add Self: Trait<..> inside the param_env of a default impl

This commit is contained in:
Gianni Ciccarelli 2018-02-14 17:25:42 +00:00
parent 2f22a929c6
commit 220bb22e1b
8 changed files with 50 additions and 61 deletions

View File

@ -579,15 +579,15 @@ impl<'a, I, T: 'a> FusedIterator for Cloned<I>
{} {}
#[doc(hidden)] #[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 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() self.it.get_unchecked(i).clone()
} }
#[inline] #[inline]
fn may_have_side_effect() -> bool { true } default fn may_have_side_effect() -> bool { true }
} }
#[doc(hidden)] #[doc(hidden)]

View File

@ -1710,44 +1710,22 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
{ {
debug!("assemble_candidates_from_impls(obligation={:?})", obligation); debug!("assemble_candidates_from_impls(obligation={:?})", obligation);
// Check if default impls should be emitted.
// default impls are emitted if the param_env is refered to a default impl.
// The param_env should contain a Self: Trait<..> predicate in those cases
let self_trait_is_present:Vec<&ty::Predicate<'tcx>> =
obligation.param_env
.caller_bounds
.iter()
.filter(|predicate| {
match **predicate {
ty::Predicate::Trait(ref trait_predicate) => {
trait_predicate.def_id() ==
obligation.predicate.def_id() &&
obligation.predicate.0.trait_ref.self_ty() ==
trait_predicate.skip_binder().self_ty()
}
_ => false
}
}).collect::<Vec<&ty::Predicate<'tcx>>>();
self.tcx().for_each_relevant_impl( self.tcx().for_each_relevant_impl(
obligation.predicate.def_id(), obligation.predicate.def_id(),
obligation.predicate.0.trait_ref.self_ty(), obligation.predicate.0.trait_ref.self_ty(),
|impl_def_id| { |impl_def_id| {
if self_trait_is_present.len() > 0 || self.probe(|this, snapshot| { /* [1] */
!self.tcx().impl_is_default(impl_def_id) { match this.match_impl(impl_def_id, obligation, snapshot) {
self.probe(|this, snapshot| { /* [1] */ Ok(skol_map) => {
match this.match_impl(impl_def_id, obligation, snapshot) { candidates.vec.push(ImplCandidate(impl_def_id));
Ok(skol_map) => {
candidates.vec.push(ImplCandidate(impl_def_id));
// NB: we can safely drop the skol map // NB: we can safely drop the skol map
// since we are in a probe [1] // since we are in a probe [1]
mem::drop(skol_map); mem::drop(skol_map);
}
Err(_) => { }
} }
}); Err(_) => { }
} }
});
} }
); );

View File

@ -2606,31 +2606,8 @@ fn param_env<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
def_id: DefId) def_id: DefId)
-> ParamEnv<'tcx> { -> ParamEnv<'tcx> {
// Compute the bounds on Self and the type parameters. // Compute the bounds on Self and the type parameters.
let mut predicates = tcx.predicates_of(def_id);
match tcx.hir.as_local_node_id(def_id)
.and_then(|node_id| tcx.hir.find(node_id))
.and_then(|item| {
match item {
hir::map::NodeItem(..) => {
if tcx.impl_is_default(def_id) {
tcx.impl_trait_ref(def_id)
} else {
None
}
}
_ => None
}
}) {
Some(trait_ref) =>
predicates.predicates
.push(
trait_ref.to_poly_trait_ref()
.to_predicate()
),
None => {}
}
let bounds = predicates.instantiate_identity(tcx); let bounds = tcx.predicates_of(def_id).instantiate_identity(tcx);
let predicates = bounds.predicates; let predicates = bounds.predicates;
// Finally, we have to normalize the bounds in the environment, in // Finally, we have to normalize the bounds in the environment, in

View File

@ -1364,6 +1364,7 @@ fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
let node = tcx.hir.get(node_id); let node = tcx.hir.get(node_id);
let mut is_trait = None; let mut is_trait = None;
let mut is_default_impl_trait = None;
let icx = ItemCtxt::new(tcx, def_id); let icx = ItemCtxt::new(tcx, def_id);
let no_generics = hir::Generics::empty(); let no_generics = hir::Generics::empty();
@ -1373,8 +1374,13 @@ fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
NodeItem(item) => { NodeItem(item) => {
match item.node { 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, _) | ItemFn(.., ref generics, _) |
ItemImpl(_, _, _, ref generics, ..) |
ItemTy(_, ref generics) | ItemTy(_, ref generics) |
ItemEnum(_, ref generics) | ItemEnum(_, ref generics) |
ItemStruct(_, ref generics) | ItemStruct(_, ref generics) |
@ -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()); 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 // Collect the region predicates that were declared inline as
// well. In the case of parameters declared on a fn or method, we // well. In the case of parameters declared on a fn or method, we
// have to be careful to only iterate over early-bound regions. // have to be careful to only iterate over early-bound regions.

View File

@ -8,6 +8,8 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
// Tests that default impls do not have to supply all items but regular impls do.
#![feature(specialization)] #![feature(specialization)]
trait Foo { trait Foo {

View File

@ -8,6 +8,10 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // 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)] #![feature(specialization)]
trait Foo { trait Foo {

View File

@ -8,6 +8,8 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
// Tests that a default impl still has to have a WF trait ref.
#![feature(specialization)] #![feature(specialization)]
trait Foo<'a, T: Eq + 'a> { } trait Foo<'a, T: Eq + 'a> { }

View File

@ -8,18 +8,22 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
// Tests that we can combine a default impl that supplies one method with a
// full impl that supplies the other, and they can invoke one another.
#![feature(specialization)] #![feature(specialization)]
trait Foo { trait Foo {
fn foo_one(&self) -> &'static str; fn foo_one(&self) -> &'static str;
fn foo_two(&self) -> &'static str; fn foo_two(&self) -> &'static str;
fn foo_three(&self) -> &'static str;
} }
struct MyStruct; struct MyStruct;
default impl<T> Foo for T { default impl<T> Foo for T {
fn foo_one(&self) -> &'static str { fn foo_one(&self) -> &'static str {
"generic" self.foo_three()
} }
} }
@ -27,6 +31,10 @@ impl Foo for MyStruct {
fn foo_two(&self) -> &'static str { fn foo_two(&self) -> &'static str {
self.foo_one() self.foo_one()
} }
fn foo_three(&self) -> &'static str {
"generic"
}
} }
fn main() { fn main() {