Skip to content

Commit

Permalink
Auto merge of #45404 - giannicic:defaultimpl2, r=nikomatsakis
Browse files Browse the repository at this point in the history
#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
  • Loading branch information
bors committed Feb 16, 2018
2 parents 1670a53 + 220bb22 commit efda9ba
Show file tree
Hide file tree
Showing 17 changed files with 117 additions and 703 deletions.
6 changes: 3 additions & 3 deletions src/libcore/iter/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -595,15 +595,15 @@ impl<'a, I, T: 'a> FusedIterator for Cloned<I>
{}

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

#[inline]
fn may_have_side_effect() -> bool { true }
default fn may_have_side_effect() -> bool { true }
}

#[doc(hidden)]
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_typeck/check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1395,7 +1395,7 @@ fn check_impl_items_against_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
.map(|node_item| !node_item.node.is_from_trait())
.unwrap_or(false);

if !is_implemented {
if !is_implemented && !tcx.impl_is_default(impl_id) {
if !trait_item.defaultness.has_value() {
missing_items.push(trait_item);
} else if associated_type_overridden {
Expand Down
20 changes: 19 additions & 1 deletion src/librustc_typeck/collect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1364,6 +1364,7 @@ fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
let node = tcx.hir.get(node_id);

let mut is_trait = None;
let mut is_default_impl_trait = None;

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

NodeItem(item) => {
match item.node {
ItemImpl(_, _, defaultness, ref generics, ..) => {
if defaultness.is_default() {
is_default_impl_trait = tcx.impl_trait_ref(def_id);
}
generics
}
ItemFn(.., ref generics, _) |
ItemImpl(_, _, _, ref generics, ..) |
ItemTy(_, ref generics) |
ItemEnum(_, ref generics) |
ItemStruct(_, ref generics) |
Expand Down Expand Up @@ -1446,6 +1452,18 @@ fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
predicates.push(trait_ref.to_poly_trait_ref().to_predicate());
}

// In default impls, we can assume that the self type implements
// the trait. So in:
//
// default impl Foo for Bar { .. }
//
// we add a default where clause `Foo: Bar`. We do a similar thing for traits
// (see below). Recall that a default impl is not itself an impl, but rather a
// set of defaults that can be incorporated into another impl.
if let Some(trait_ref) = is_default_impl_trait {
predicates.push(trait_ref.to_poly_trait_ref().to_predicate());
}

// Collect the region predicates that were declared inline as
// well. In the case of parameters declared on a fn or method, we
// have to be careful to only iterate over early-bound regions.
Expand Down

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -8,30 +8,26 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

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

#![feature(specialization)]

trait Foo {
fn mk() -> Self;
fn foo_one(&self) -> &'static str;
fn foo_two(&self) -> &'static str;
}

default impl<T: Default> Foo for T {
fn mk() -> T {
T::default()
}
}
struct MyStruct;

impl Foo for Vec<u8> {
fn mk() -> Vec<u8> {
vec![0]
default impl<T> Foo for T {
fn foo_one(&self) -> &'static str {
"generic"
}
}

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

assert!(v1.len() == 0);
assert!(v2.len() == 1);
fn main() {
println!("{}", MyStruct.foo_one());
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// Tests that:
// - default impls do not have to supply all items and
// - a default impl does not count as an impl (in this case, an incomplete default impl).

#![feature(specialization)]

trait Foo {
fn foo_one(&self) -> &'static str;
fn foo_two(&self) -> &'static str;
}

struct MyStruct;

default impl<T> Foo for T {
fn foo_one(&self) -> &'static str {
"generic"
}
}


fn main() {
println!("{}", MyStruct.foo_one());
//~^ ERROR no method named `foo_one` found for type `MyStruct` in the current scope
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
Expand All @@ -8,25 +8,13 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![feature(specialization)]

// Regression test for ICE when combining specialized associated types and type
// aliases

trait Id_ {
type Out;
}
// Tests that a default impl still has to have a WF trait ref.

type Id<T> = <T as Id_>::Out;

default impl<T> Id_ for T {
type Out = T;
}
#![feature(specialization)]

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

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

}
fn main(){}

This file was deleted.

Loading

0 comments on commit efda9ba

Please sign in to comment.