From 220bb22e1b621ad5a10a44080e3e1872d99f3e9f Mon Sep 17 00:00:00 2001 From: Gianni Ciccarelli Date: Wed, 14 Feb 2018 17:25:42 +0000 Subject: [PATCH] add Self: Trait<..> inside the param_env of a default impl --- src/libcore/iter/mod.rs | 6 +-- src/librustc/traits/select.rs | 42 +++++-------------- src/librustc/ty/mod.rs | 25 +---------- src/librustc_typeck/collect.rs | 20 ++++++++- ...ecialization-trait-item-not-implemented.rs | 2 + .../specialization-trait-not-implemented.rs | 4 ++ .../defaultimpl/specialization-wfcheck.rs | 2 + ...ecialization-trait-item-not-implemented.rs | 10 ++++- 8 files changed, 50 insertions(+), 61 deletions(-) diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs index bf8367d85fd..652e0027383 100644 --- a/src/libcore/iter/mod.rs +++ b/src/libcore/iter/mod.rs @@ -579,15 +579,15 @@ impl<'a, I, T: 'a> FusedIterator for Cloned {} #[doc(hidden)] -default unsafe impl<'a, I, T: 'a> TrustedRandomAccess for Cloned +unsafe impl<'a, I, T: 'a> TrustedRandomAccess for Cloned where I: TrustedRandomAccess, 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)] diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index aa43bf8ca2e..4ed25646d43 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -1710,44 +1710,22 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { { 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::>>(); - self.tcx().for_each_relevant_impl( obligation.predicate.def_id(), obligation.predicate.0.trait_ref.self_ty(), |impl_def_id| { - if self_trait_is_present.len() > 0 || - !self.tcx().impl_is_default(impl_def_id) { - self.probe(|this, snapshot| { /* [1] */ - match this.match_impl(impl_def_id, obligation, snapshot) { - Ok(skol_map) => { - candidates.vec.push(ImplCandidate(impl_def_id)); + self.probe(|this, snapshot| { /* [1] */ + match this.match_impl(impl_def_id, obligation, snapshot) { + Ok(skol_map) => { + candidates.vec.push(ImplCandidate(impl_def_id)); - // NB: we can safely drop the skol map - // since we are in a probe [1] - mem::drop(skol_map); - } - Err(_) => { } + // NB: we can safely drop the skol map + // since we are in a probe [1] + mem::drop(skol_map); } - }); - } + Err(_) => { } + } + }); } ); diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 52d33c750f8..f52f2ea0f9f 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -2606,31 +2606,8 @@ fn param_env<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> ParamEnv<'tcx> { // 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; // Finally, we have to normalize the bounds in the environment, in diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index d5328a18c22..1c8d22e4666 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -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(); @@ -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) | @@ -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. diff --git a/src/test/compile-fail/specialization/defaultimpl/specialization-trait-item-not-implemented.rs b/src/test/compile-fail/specialization/defaultimpl/specialization-trait-item-not-implemented.rs index 072507851d7..eacec2e40f0 100644 --- a/src/test/compile-fail/specialization/defaultimpl/specialization-trait-item-not-implemented.rs +++ b/src/test/compile-fail/specialization/defaultimpl/specialization-trait-item-not-implemented.rs @@ -8,6 +8,8 @@ // 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 but regular impls do. + #![feature(specialization)] trait Foo { diff --git a/src/test/compile-fail/specialization/defaultimpl/specialization-trait-not-implemented.rs b/src/test/compile-fail/specialization/defaultimpl/specialization-trait-not-implemented.rs index d020a677577..04ddf9ebb17 100644 --- a/src/test/compile-fail/specialization/defaultimpl/specialization-trait-not-implemented.rs +++ b/src/test/compile-fail/specialization/defaultimpl/specialization-trait-not-implemented.rs @@ -8,6 +8,10 @@ // 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 { diff --git a/src/test/compile-fail/specialization/defaultimpl/specialization-wfcheck.rs b/src/test/compile-fail/specialization/defaultimpl/specialization-wfcheck.rs index 34229737992..445a59a373e 100644 --- a/src/test/compile-fail/specialization/defaultimpl/specialization-wfcheck.rs +++ b/src/test/compile-fail/specialization/defaultimpl/specialization-wfcheck.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// Tests that a default impl still has to have a WF trait ref. + #![feature(specialization)] trait Foo<'a, T: Eq + 'a> { } diff --git a/src/test/run-pass/specialization/defaultimpl/specialization-trait-item-not-implemented.rs b/src/test/run-pass/specialization/defaultimpl/specialization-trait-item-not-implemented.rs index e11a3021497..fc731202005 100644 --- a/src/test/run-pass/specialization/defaultimpl/specialization-trait-item-not-implemented.rs +++ b/src/test/run-pass/specialization/defaultimpl/specialization-trait-item-not-implemented.rs @@ -8,18 +8,22 @@ // option. This file may not be copied, modified, or distributed // 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)] trait Foo { fn foo_one(&self) -> &'static str; fn foo_two(&self) -> &'static str; + fn foo_three(&self) -> &'static str; } struct MyStruct; default impl Foo for T { fn foo_one(&self) -> &'static str { - "generic" + self.foo_three() } } @@ -27,6 +31,10 @@ impl Foo for MyStruct { fn foo_two(&self) -> &'static str { self.foo_one() } + + fn foo_three(&self) -> &'static str { + "generic" + } } fn main() {