]> git.lizzy.rs Git - rust.git/commitdiff
add Self: Trait<..> inside the param_env of a default impl
authorGianni Ciccarelli <gianni.ciccarelli@gmail.com>
Wed, 14 Feb 2018 17:25:42 +0000 (17:25 +0000)
committerGianni Ciccarelli <gianni.ciccarelli@gmail.com>
Thu, 15 Feb 2018 15:31:05 +0000 (15:31 +0000)
src/libcore/iter/mod.rs
src/librustc/traits/select.rs
src/librustc/ty/mod.rs
src/librustc_typeck/collect.rs
src/test/compile-fail/specialization/defaultimpl/specialization-trait-item-not-implemented.rs
src/test/compile-fail/specialization/defaultimpl/specialization-trait-not-implemented.rs
src/test/compile-fail/specialization/defaultimpl/specialization-wfcheck.rs
src/test/run-pass/specialization/defaultimpl/specialization-trait-item-not-implemented.rs

index bf8367d85fd1085ad6d42bb05eceae760a95496a..652e0027383c1c5b320b0e620ce7dfac7b197c60 100644 (file)
@@ -579,15 +579,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)]
index aa43bf8ca2eff1495d0dd2327c4a16b1347a3a05..4ed25646d436d03671852d1d3a0fcd0f625e9c85 100644 (file)
@@ -1710,44 +1710,22 @@ fn assemble_candidates_from_impls(&mut self,
     {
         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(
             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));
-
-                                // NB: we can safely drop the skol map
-                                // since we are in a probe [1]
-                                mem::drop(skol_map);
-                            }
-                            Err(_) => { }
+                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(_) => { }
+                    }
+                });
             }
         );
 
index 52d33c750f864e1478d91ae98007ee495f7d44bf..f52f2ea0f9fc8258b9d93964c6694a1da0cb9e9a 100644 (file)
@@ -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
index d5328a18c22400f52c5f5fb9b7e0ecede732a13b..1c8d22e4666a6dd4b9884e2bbfe4878f9028838d 100644 (file)
@@ -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.
index 072507851d795c1deadafeb70c963c9cf31b669e..eacec2e40f073e44ff875e2b2d88fbda6424f92f 100644 (file)
@@ -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 {
index d020a6775772d67c4ca0a26717e1fd70529e3b97..04ddf9ebb17717be054945af5c3f45b9fe962a79 100644 (file)
@@ -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 {
index 3422973799282fd499b3714805ddfc9386a541c1..445a59a373e56f1ee962c5f90dacc4ce37e0c461 100644 (file)
@@ -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> { }
index e11a30214974e07984e1f22f6c3cfa178e705ff3..fc7312020053ebd9714beab7a8edbb3c26650ea8 100644 (file)
@@ -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<T> 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() {