]> git.lizzy.rs Git - rust.git/commitdiff
Normalize associated types in bounds too. Also, make the workaround
authorNiko Matsakis <niko@alum.mit.edu>
Tue, 30 Dec 2014 11:29:59 +0000 (06:29 -0500)
committerNiko Matsakis <niko@alum.mit.edu>
Tue, 30 Dec 2014 14:36:23 +0000 (09:36 -0500)
for lack of impl-trait-for-trait just a bit more targeted (don't
substitute err, just drop the troublesome bound for now) -- otherwise
substituting false types leads us into trouble when we normalize etc.

src/librustc/middle/ty.rs
src/librustc_typeck/check/assoc.rs
src/librustc_typeck/check/method/confirm.rs
src/librustc_typeck/collect.rs
src/test/run-pass/associated-types-normalize-in-bounds.rs [new file with mode: 0644]

index caec56800c63a14149dc63a0056e34ba49eaf752..d6ab0201d190a22b0cbc00feef3f0668bbe03000 100644 (file)
@@ -6970,13 +6970,67 @@ pub trait HasProjectionTypes {
     fn has_projection_types(&self) -> bool;
 }
 
+impl<'tcx> HasProjectionTypes for ty::GenericBounds<'tcx> {
+    fn has_projection_types(&self) -> bool {
+        self.predicates.iter().any(|p| p.has_projection_types())
+    }
+}
+
+impl<'tcx> HasProjectionTypes for Predicate<'tcx> {
+    fn has_projection_types(&self) -> bool {
+        match *self {
+            Predicate::Trait(ref data) => data.has_projection_types(),
+            Predicate::Equate(ref data) => data.has_projection_types(),
+            Predicate::RegionOutlives(ref data) => data.has_projection_types(),
+            Predicate::TypeOutlives(ref data) => data.has_projection_types(),
+            Predicate::Projection(ref data) => data.has_projection_types(),
+        }
+    }
+}
+
+impl<'tcx> HasProjectionTypes for TraitPredicate<'tcx> {
+    fn has_projection_types(&self) -> bool {
+        self.trait_ref.has_projection_types()
+    }
+}
+
+impl<'tcx> HasProjectionTypes for EquatePredicate<'tcx> {
+    fn has_projection_types(&self) -> bool {
+        self.0.has_projection_types() || self.1.has_projection_types()
+    }
+}
+
+impl HasProjectionTypes for Region {
+    fn has_projection_types(&self) -> bool {
+        false
+    }
+}
+
+impl<T:HasProjectionTypes,U:HasProjectionTypes> HasProjectionTypes for OutlivesPredicate<T,U> {
+    fn has_projection_types(&self) -> bool {
+        self.0.has_projection_types() || self.1.has_projection_types()
+    }
+}
+
+impl<'tcx> HasProjectionTypes for ProjectionPredicate<'tcx> {
+    fn has_projection_types(&self) -> bool {
+        self.projection_ty.has_projection_types() || self.ty.has_projection_types()
+    }
+}
+
+impl<'tcx> HasProjectionTypes for ProjectionTy<'tcx> {
+    fn has_projection_types(&self) -> bool {
+        self.trait_ref.has_projection_types()
+    }
+}
+
 impl<'tcx> HasProjectionTypes for Ty<'tcx> {
     fn has_projection_types(&self) -> bool {
         ty::type_has_projection(*self)
     }
 }
 
-impl<'tcx> HasProjectionTypes for ty::TraitRef<'tcx> {
+impl<'tcx> HasProjectionTypes for TraitRef<'tcx> {
     fn has_projection_types(&self) -> bool {
         self.substs.has_projection_types()
     }
@@ -7012,7 +7066,7 @@ fn has_projection_types(&self) -> bool {
     }
 }
 
-impl<T> HasProjectionTypes for ty::Binder<T>
+impl<T> HasProjectionTypes for Binder<T>
     where T : HasProjectionTypes
 {
     fn has_projection_types(&self) -> bool {
@@ -7020,23 +7074,23 @@ fn has_projection_types(&self) -> bool {
     }
 }
 
-impl<'tcx> HasProjectionTypes for ty::FnOutput<'tcx> {
+impl<'tcx> HasProjectionTypes for FnOutput<'tcx> {
     fn has_projection_types(&self) -> bool {
         match *self {
-            ty::FnConverging(t) => t.has_projection_types(),
-            ty::FnDiverging => false,
+            FnConverging(t) => t.has_projection_types(),
+            FnDiverging => false,
         }
     }
 }
 
-impl<'tcx> HasProjectionTypes for ty::FnSig<'tcx> {
+impl<'tcx> HasProjectionTypes for FnSig<'tcx> {
     fn has_projection_types(&self) -> bool {
         self.inputs.iter().any(|t| t.has_projection_types()) ||
             self.output.has_projection_types()
     }
 }
 
-impl<'tcx> HasProjectionTypes for ty::BareFnTy<'tcx> {
+impl<'tcx> HasProjectionTypes for BareFnTy<'tcx> {
     fn has_projection_types(&self) -> bool {
         self.sig.has_projection_types()
     }
@@ -7046,7 +7100,7 @@ pub trait ReferencesError {
     fn references_error(&self) -> bool;
 }
 
-impl<T:ReferencesError> ReferencesError for ty::Binder<T> {
+impl<T:ReferencesError> ReferencesError for Binder<T> {
     fn references_error(&self) -> bool {
         self.0.references_error()
     }
@@ -7058,43 +7112,43 @@ fn references_error(&self) -> bool {
     }
 }
 
-impl<'tcx> ReferencesError for ty::TraitPredicate<'tcx> {
+impl<'tcx> ReferencesError for TraitPredicate<'tcx> {
     fn references_error(&self) -> bool {
         self.trait_ref.references_error()
     }
 }
 
-impl<'tcx> ReferencesError for ty::ProjectionPredicate<'tcx> {
+impl<'tcx> ReferencesError for ProjectionPredicate<'tcx> {
     fn references_error(&self) -> bool {
         self.projection_ty.trait_ref.references_error() || self.ty.references_error()
     }
 }
 
-impl<'tcx> ReferencesError for ty::TraitRef<'tcx> {
+impl<'tcx> ReferencesError for TraitRef<'tcx> {
     fn references_error(&self) -> bool {
         self.input_types().iter().any(|t| t.references_error())
     }
 }
 
-impl<'tcx> ReferencesError for ty::Ty<'tcx> {
+impl<'tcx> ReferencesError for Ty<'tcx> {
     fn references_error(&self) -> bool {
-        ty::type_is_error(*self)
+        type_is_error(*self)
     }
 }
 
-impl<'tcx> ReferencesError for ty::Predicate<'tcx> {
+impl<'tcx> ReferencesError for Predicate<'tcx> {
     fn references_error(&self) -> bool {
         match *self {
-            ty::Predicate::Trait(ref data) => data.references_error(),
-            ty::Predicate::Equate(ref data) => data.references_error(),
-            ty::Predicate::RegionOutlives(ref data) => data.references_error(),
-            ty::Predicate::TypeOutlives(ref data) => data.references_error(),
-            ty::Predicate::Projection(ref data) => data.references_error(),
+            Predicate::Trait(ref data) => data.references_error(),
+            Predicate::Equate(ref data) => data.references_error(),
+            Predicate::RegionOutlives(ref data) => data.references_error(),
+            Predicate::TypeOutlives(ref data) => data.references_error(),
+            Predicate::Projection(ref data) => data.references_error(),
         }
     }
 }
 
-impl<A,B> ReferencesError for ty::OutlivesPredicate<A,B>
+impl<A,B> ReferencesError for OutlivesPredicate<A,B>
     where A : ReferencesError, B : ReferencesError
 {
     fn references_error(&self) -> bool {
@@ -7102,14 +7156,14 @@ fn references_error(&self) -> bool {
     }
 }
 
-impl<'tcx> ReferencesError for ty::EquatePredicate<'tcx>
+impl<'tcx> ReferencesError for EquatePredicate<'tcx>
 {
     fn references_error(&self) -> bool {
         self.0.references_error() || self.1.references_error()
     }
 }
 
-impl ReferencesError for ty::Region
+impl ReferencesError for Region
 {
     fn references_error(&self) -> bool {
         false
index c20dd5aebaddbef0a5b315b1ea7e8ae33a83880e..0d7ce2f871a6fd6d21d62ef7c96058e08c9469aa 100644 (file)
@@ -10,7 +10,7 @@
 
 use middle::infer::InferCtxt;
 use middle::traits::{ObligationCause, ObligationCauseCode, FulfillmentContext};
-use middle::ty::{mod, HasProjectionTypes, Ty};
+use middle::ty::{mod, RegionEscape, HasProjectionTypes, Ty};
 use middle::ty_fold::{mod, TypeFoldable, TypeFolder};
 use syntax::ast;
 use syntax::codemap::Span;
@@ -32,8 +32,7 @@ pub fn normalize_associated_types_in<'a,'tcx,T>(infcx: &InferCtxt<'a,'tcx>,
     let mut normalizer = AssociatedTypeNormalizer { span: span,
                                                     body_id: body_id,
                                                     infcx: infcx,
-                                                    fulfillment_cx: fulfillment_cx,
-                                                    region_binders: 0 };
+                                                    fulfillment_cx: fulfillment_cx };
     value.fold_with(&mut normalizer)
 }
 
@@ -42,7 +41,6 @@ struct AssociatedTypeNormalizer<'a,'tcx:'a> {
     fulfillment_cx: &'a mut FulfillmentContext<'tcx>,
     span: Span,
     body_id: ast::NodeId,
-    region_binders: uint,
 }
 
 impl<'a,'tcx> TypeFolder<'tcx> for AssociatedTypeNormalizer<'a,'tcx> {
@@ -50,14 +48,6 @@ fn tcx(&self) -> &ty::ctxt<'tcx> {
         self.infcx.tcx
     }
 
-    fn enter_region_binder(&mut self) {
-        self.region_binders += 1;
-    }
-
-    fn exit_region_binder(&mut self) {
-        self.region_binders -= 1;
-    }
-
     fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
         // We don't want to normalize associated types that occur inside of region
         // binders, because they may contain bound regions, and we can't cope with that.
@@ -69,10 +59,22 @@ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
         // Instead of normalizing `<T as Foo<&'a>>::A` here, we'll
         // normalize it when we instantiate those bound regions (which
         // should occur eventually).
-        let no_region_binders = self.region_binders == 0;
 
         match ty.sty {
-            ty::ty_projection(ref data) if no_region_binders => {
+            ty::ty_projection(ref data) if !data.has_escaping_regions() => { // (*)
+
+                // (*) This is kind of hacky -- we need to be able to
+                // handle normalization within binders because
+                // otherwise we wind up a need to normalize when doing
+                // trait matching (since you can have a trait
+                // obligation like `for<'a> T::B : Fn(&'a int)`), but
+                // we can't normalize with bound regions in scope. So
+                // far now we just ignore binders but only normalize
+                // if all bound regions are gone (and then we still
+                // have to renormalize whenever we instantiate a
+                // binder). It would be better to normalize in a
+                // binding-aware fashion.
+
                 let cause =
                     ObligationCause::new(
                         self.span,
index 9704439c468b2cf542702c59174326f94f0b2e3c..a189f780b0c270e2956f256acac4f2f84970752f 100644 (file)
@@ -42,12 +42,6 @@ struct InstantiatedMethodSig<'tcx> {
     /// the method.
     all_substs: subst::Substs<'tcx>,
 
-    /// Substitution to use when adding obligations from the method
-    /// bounds. Normally equal to `all_substs` except for object
-    /// receivers. See FIXME in instantiate_method_sig() for
-    /// explanation.
-    method_bounds_substs: subst::Substs<'tcx>,
-
     /// Generic bounds on the method's parameters which must be added
     /// as pending obligations.
     method_bounds: ty::GenericBounds<'tcx>,
@@ -103,7 +97,7 @@ fn confirm(&mut self,
 
         // Create the final signature for the method, replacing late-bound regions.
         let InstantiatedMethodSig {
-            method_sig, all_substs, method_bounds_substs, method_bounds
+            method_sig, all_substs, method_bounds
         } = self.instantiate_method_sig(&pick, all_substs);
         let method_self_ty = method_sig.inputs[0];
 
@@ -111,7 +105,7 @@ fn confirm(&mut self,
         self.unify_receivers(self_ty, method_self_ty);
 
         // Add any trait/regions obligations specified on the method's type parameters.
-        self.add_obligations(&pick, &method_bounds_substs, &method_bounds);
+        self.add_obligations(&pick, &all_substs, &method_bounds);
 
         // Create the final `MethodCallee`.
         let fty = ty::mk_bare_fn(self.tcx(), None, self.tcx().mk_bare_fn(ty::BareFnTy {
@@ -403,24 +397,17 @@ fn instantiate_method_sig(&mut self,
         // type `Trait`, this leads to an obligation
         // `Trait:Trait`. Until such time we DST is fully implemented,
         // that obligation is not necessarily satisfied. (In the
-        // future, it would be.)
-        //
-        // To sidestep this, we overwrite the binding for `Self` with
-        // `err` (just for trait objects) when we generate the
-        // obligations.  This causes us to generate the obligation
-        // `err:Trait`, and the error type is considered to implement
-        // all traits, so we're all good. Hack hack hack.
-        let method_bounds_substs = match pick.kind {
+        // future, it would be.) But we know that the true `Self` DOES implement
+        // the trait. So we just delete this requirement. Hack hack hack.
+        let mut method_bounds = pick.method_ty.generics.to_bounds(self.tcx(), &all_substs);
+        match pick.kind {
             probe::ObjectPick(..) => {
-                let mut temp_substs = all_substs.clone();
-                temp_substs.types.get_mut_slice(subst::SelfSpace)[0] = self.tcx().types.err;
-                temp_substs
+                assert_eq!(method_bounds.predicates.get_slice(subst::SelfSpace).len(), 1);
+                method_bounds.predicates.pop(subst::SelfSpace);
             }
-            _ => {
-                all_substs.clone()
-            }
-        };
-        let method_bounds = pick.method_ty.generics.to_bounds(self.tcx(), &method_bounds_substs);
+            _ => { }
+        }
+        let method_bounds = self.fcx.normalize_associated_types_in(self.span, &method_bounds);
 
         debug!("method_bounds after subst = {}",
                method_bounds.repr(self.tcx()));
@@ -442,18 +429,17 @@ fn instantiate_method_sig(&mut self,
         InstantiatedMethodSig {
             method_sig: method_sig,
             all_substs: all_substs,
-            method_bounds_substs: method_bounds_substs,
             method_bounds: method_bounds,
         }
     }
 
     fn add_obligations(&mut self,
                        pick: &probe::Pick<'tcx>,
-                       method_bounds_substs: &subst::Substs<'tcx>,
+                       all_substs: &subst::Substs<'tcx>,
                        method_bounds: &ty::GenericBounds<'tcx>) {
-        debug!("add_obligations: pick={} method_bounds_substs={} method_bounds={}",
+        debug!("add_obligations: pick={} all_substs={} method_bounds={}",
                pick.repr(self.tcx()),
-               method_bounds_substs.repr(self.tcx()),
+               all_substs.repr(self.tcx()),
                method_bounds.repr(self.tcx()));
 
         self.fcx.add_obligations_for_parameters(
@@ -461,7 +447,7 @@ fn add_obligations(&mut self,
             method_bounds);
 
         self.fcx.add_default_region_param_bounds(
-            method_bounds_substs,
+            all_substs,
             self.call_expr);
     }
 
index 8f70966dd14c433145a8428557fc94fa65c1ac8d..47473564254e13af2f0717a2e302a159ad451a42 100644 (file)
@@ -1071,7 +1071,7 @@ fn ty_generics_for_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
     debug!("ty_generics_for_trait: assoc_predicates={}", assoc_predicates.repr(ccx.tcx));
 
     for assoc_predicate in assoc_predicates.into_iter() {
-        generics.predicates.push(subst::SelfSpace, assoc_predicate);
+        generics.predicates.push(subst::TypeSpace, assoc_predicate);
     }
 
     return generics;
diff --git a/src/test/run-pass/associated-types-normalize-in-bounds.rs b/src/test/run-pass/associated-types-normalize-in-bounds.rs
new file mode 100644 (file)
index 0000000..f09c270
--- /dev/null
@@ -0,0 +1,41 @@
+// Copyright 2014 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.
+
+// Test that we normalize associated types that appear in bounds; if
+// we didn't, the call to `self.split2()` fails to type check.
+
+#![feature(associated_types)]
+
+struct Splits<'a, T, P>;
+struct SplitsN<I>;
+
+trait SliceExt2 for Sized? {
+    type Item;
+
+    fn split2<'a, P>(&'a self, pred: P) -> Splits<'a, Self::Item, P>
+        where P: FnMut(&Self::Item) -> bool;
+    fn splitn2<'a, P>(&'a self, n: uint, pred: P) -> SplitsN<Splits<'a, Self::Item, P>>
+        where P: FnMut(&Self::Item) -> bool;
+}
+
+impl<T> SliceExt2 for [T] {
+    type Item = T;
+
+    fn split2<P>(&self, pred: P) -> Splits<T, P> where P: FnMut(&T) -> bool {
+        loop {}
+    }
+
+    fn splitn2<P>(&self, n: uint, pred: P) -> SplitsN<Splits<T, P>> where P: FnMut(&T) -> bool {
+        self.split2(pred);
+        loop {}
+    }
+}
+
+fn main() { }