about summary refs log tree commit diff
diff options
context:
space:
mode:
authorGianni Ciccarelli <gianni.ciccarelli@gmail.com>2018-02-14 17:25:42 +0000
committerGianni Ciccarelli <gianni.ciccarelli@gmail.com>2018-02-15 15:31:05 +0000
commit220bb22e1b621ad5a10a44080e3e1872d99f3e9f (patch)
treef19e7517b4bacdf53509ee0dd5ccc668a02f3228
parent2f22a929c6d231d9a9d872ac40b5c9e36daabe38 (diff)
downloadrust-220bb22e1b621ad5a10a44080e3e1872d99f3e9f.tar.gz
rust-220bb22e1b621ad5a10a44080e3e1872d99f3e9f.zip
add Self: Trait<..> inside the param_env of a default impl
-rw-r--r--src/libcore/iter/mod.rs6
-rw-r--r--src/librustc/traits/select.rs44
-rw-r--r--src/librustc/ty/mod.rs25
-rw-r--r--src/librustc_typeck/collect.rs20
-rw-r--r--src/test/compile-fail/specialization/defaultimpl/specialization-trait-item-not-implemented.rs2
-rw-r--r--src/test/compile-fail/specialization/defaultimpl/specialization-trait-not-implemented.rs4
-rw-r--r--src/test/compile-fail/specialization/defaultimpl/specialization-wfcheck.rs2
-rw-r--r--src/test/run-pass/specialization/defaultimpl/specialization-trait-item-not-implemented.rs10
8 files changed, 51 insertions, 62 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<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)]
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::<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(_) => { }
+                    }
+                });
             }
         );
 
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<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() {