Skip to content

Commit efda9ba

Browse files
committed
Auto merge of #45404 - giannicic:defaultimpl2, r=nikomatsakis
#37653 support `default impl` for specialization this commit implements the second part of the `default impl` feature: > - a `default impl` need not include all items from the trait > - a `default impl` alone does not mean that a type implements the trait The first point allows rustc to compile and run something like this: ``` trait Foo { fn foo_one(&self) -> &'static str; fn foo_two(&self) -> &'static str; } default impl<T> Foo for T { fn foo_one(&self) -> &'static str { "generic" } } struct MyStruct; fn main() { assert!(MyStruct.foo_one() == "generic"); } ``` but it shows a proper error if trying to call `MyStruct.foo_two()` The second point allows a `default impl` to be considered as not implementing the `Trait` if it doesn't implement all the trait items. The tests provided (in the compile-fail section) should cover all the possible trait resolutions. Let me know if some tests is missed. See [referenced ](#37653) issue for further info r? @nikomatsakis
2 parents 1670a53 + 220bb22 commit efda9ba

17 files changed

+117
-703
lines changed

Diff for: src/libcore/iter/mod.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -595,15 +595,15 @@ impl<'a, I, T: 'a> FusedIterator for Cloned<I>
595595
{}
596596

597597
#[doc(hidden)]
598-
default unsafe impl<'a, I, T: 'a> TrustedRandomAccess for Cloned<I>
598+
unsafe impl<'a, I, T: 'a> TrustedRandomAccess for Cloned<I>
599599
where I: TrustedRandomAccess<Item=&'a T>, T: Clone
600600
{
601-
unsafe fn get_unchecked(&mut self, i: usize) -> Self::Item {
601+
default unsafe fn get_unchecked(&mut self, i: usize) -> Self::Item {
602602
self.it.get_unchecked(i).clone()
603603
}
604604

605605
#[inline]
606-
fn may_have_side_effect() -> bool { true }
606+
default fn may_have_side_effect() -> bool { true }
607607
}
608608

609609
#[doc(hidden)]

Diff for: src/librustc_typeck/check/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1395,7 +1395,7 @@ fn check_impl_items_against_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
13951395
.map(|node_item| !node_item.node.is_from_trait())
13961396
.unwrap_or(false);
13971397

1398-
if !is_implemented {
1398+
if !is_implemented && !tcx.impl_is_default(impl_id) {
13991399
if !trait_item.defaultness.has_value() {
14001400
missing_items.push(trait_item);
14011401
} else if associated_type_overridden {

Diff for: src/librustc_typeck/collect.rs

+19-1
Original file line numberDiff line numberDiff line change
@@ -1364,6 +1364,7 @@ fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
13641364
let node = tcx.hir.get(node_id);
13651365

13661366
let mut is_trait = None;
1367+
let mut is_default_impl_trait = None;
13671368

13681369
let icx = ItemCtxt::new(tcx, def_id);
13691370
let no_generics = hir::Generics::empty();
@@ -1373,8 +1374,13 @@ fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
13731374

13741375
NodeItem(item) => {
13751376
match item.node {
1377+
ItemImpl(_, _, defaultness, ref generics, ..) => {
1378+
if defaultness.is_default() {
1379+
is_default_impl_trait = tcx.impl_trait_ref(def_id);
1380+
}
1381+
generics
1382+
}
13761383
ItemFn(.., ref generics, _) |
1377-
ItemImpl(_, _, _, ref generics, ..) |
13781384
ItemTy(_, ref generics) |
13791385
ItemEnum(_, ref generics) |
13801386
ItemStruct(_, ref generics) |
@@ -1446,6 +1452,18 @@ fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
14461452
predicates.push(trait_ref.to_poly_trait_ref().to_predicate());
14471453
}
14481454

1455+
// In default impls, we can assume that the self type implements
1456+
// the trait. So in:
1457+
//
1458+
// default impl Foo for Bar { .. }
1459+
//
1460+
// we add a default where clause `Foo: Bar`. We do a similar thing for traits
1461+
// (see below). Recall that a default impl is not itself an impl, but rather a
1462+
// set of defaults that can be incorporated into another impl.
1463+
if let Some(trait_ref) = is_default_impl_trait {
1464+
predicates.push(trait_ref.to_poly_trait_ref().to_predicate());
1465+
}
1466+
14491467
// Collect the region predicates that were declared inline as
14501468
// well. In the case of parameters declared on a fn or method, we
14511469
// have to be careful to only iterate over early-bound regions.

Diff for: src/test/compile-fail/specialization/defaultimpl/specialization-default-projection.rs

-46
This file was deleted.

Diff for: src/test/compile-fail/specialization/defaultimpl/specialization-default-types.rs

-45
This file was deleted.

Diff for: src/test/run-pass/specialization/defaultimpl/assoc-fns.rs renamed to src/test/compile-fail/specialization/defaultimpl/specialization-trait-item-not-implemented.rs

+11-15
Original file line numberDiff line numberDiff line change
@@ -8,30 +8,26 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
// Test that non-method associated functions can be specialized
11+
// Tests that default impls do not have to supply all items but regular impls do.
1212

1313
#![feature(specialization)]
1414

1515
trait Foo {
16-
fn mk() -> Self;
16+
fn foo_one(&self) -> &'static str;
17+
fn foo_two(&self) -> &'static str;
1718
}
1819

19-
default impl<T: Default> Foo for T {
20-
fn mk() -> T {
21-
T::default()
22-
}
23-
}
20+
struct MyStruct;
2421

25-
impl Foo for Vec<u8> {
26-
fn mk() -> Vec<u8> {
27-
vec![0]
22+
default impl<T> Foo for T {
23+
fn foo_one(&self) -> &'static str {
24+
"generic"
2825
}
2926
}
3027

31-
fn main() {
32-
let v1: Vec<i32> = Foo::mk();
33-
let v2: Vec<u8> = Foo::mk();
28+
impl Foo for MyStruct {}
29+
//~^ ERROR not all trait items implemented, missing: `foo_two` [E0046]
3430

35-
assert!(v1.len() == 0);
36-
assert!(v2.len() == 1);
31+
fn main() {
32+
println!("{}", MyStruct.foo_one());
3733
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// Tests that:
12+
// - default impls do not have to supply all items and
13+
// - a default impl does not count as an impl (in this case, an incomplete default impl).
14+
15+
#![feature(specialization)]
16+
17+
trait Foo {
18+
fn foo_one(&self) -> &'static str;
19+
fn foo_two(&self) -> &'static str;
20+
}
21+
22+
struct MyStruct;
23+
24+
default impl<T> Foo for T {
25+
fn foo_one(&self) -> &'static str {
26+
"generic"
27+
}
28+
}
29+
30+
31+
fn main() {
32+
println!("{}", MyStruct.foo_one());
33+
//~^ ERROR no method named `foo_one` found for type `MyStruct` in the current scope
34+
}
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
22
// file at the top-level directory of this distribution and at
33
// http://rust-lang.org/COPYRIGHT.
44
//
@@ -8,25 +8,13 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
#![feature(specialization)]
12-
13-
// Regression test for ICE when combining specialized associated types and type
14-
// aliases
15-
16-
trait Id_ {
17-
type Out;
18-
}
11+
// Tests that a default impl still has to have a WF trait ref.
1912

20-
type Id<T> = <T as Id_>::Out;
21-
22-
default impl<T> Id_ for T {
23-
type Out = T;
24-
}
13+
#![feature(specialization)]
2514

26-
fn test_proection() {
27-
let x: Id<bool> = panic!();
28-
}
15+
trait Foo<'a, T: Eq + 'a> { }
2916

30-
fn main() {
17+
default impl<U> Foo<'static, U> for () {}
18+
//~^ ERROR the trait bound `U: std::cmp::Eq` is not satisfied
3119

32-
}
20+
fn main(){}

Diff for: src/test/run-pass/specialization/defaultimpl/auxiliary/cross_crate.rs

-82
This file was deleted.

0 commit comments

Comments
 (0)