about summary refs log tree commit diff
diff options
context:
space:
mode:
authorNiko Matsakis <niko@alum.mit.edu>2014-12-30 14:49:13 -0500
committerNiko Matsakis <niko@alum.mit.edu>2014-12-31 11:16:28 -0500
commit0aa7ba9f5e9882c63a8f4bf4397ba8cd558b33ab (patch)
treefa57b8490e8d9a7d82789abb1e284c823dbd369c
parent90252b8ddb439a538765ef85532f4caa029b5e8e (diff)
downloadrust-0aa7ba9f5e9882c63a8f4bf4397ba8cd558b33ab.tar.gz
rust-0aa7ba9f5e9882c63a8f4bf4397ba8cd558b33ab.zip
Normalize bounds also in the UFCS cases (and get more systematic about it)
-rw-r--r--src/librustc/middle/traits/project.rs2
-rw-r--r--src/librustc/middle/ty.rs47
-rw-r--r--src/librustc_typeck/check/method/mod.rs2
-rw-r--r--src/librustc_typeck/check/method/probe.rs1
-rw-r--r--src/librustc_typeck/check/mod.rs43
-rw-r--r--src/librustc_typeck/check/wf.rs13
-rw-r--r--src/test/run-pass/associated-types-normalize-in-bounds-ufcs.rs41
7 files changed, 123 insertions, 26 deletions
diff --git a/src/librustc/middle/traits/project.rs b/src/librustc/middle/traits/project.rs
index ab90f567ea2..0fa171523f4 100644
--- a/src/librustc/middle/traits/project.rs
+++ b/src/librustc/middle/traits/project.rs
@@ -363,6 +363,8 @@ fn confirm_candidate<'cx,'tcx>(
                 break;
             }
 
+            // TODO we need the impl_vtable items here
+
             match impl_ty {
                 Some(ty) => ty,
                 None => {
diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs
index ab39c761a38..351485d74e8 100644
--- a/src/librustc/middle/ty.rs
+++ b/src/librustc/middle/ty.rs
@@ -6385,7 +6385,7 @@ pub fn construct_parameter_environment<'tcx>(
     }
 
     fn push_types_from_defs<'tcx>(tcx: &ty::ctxt<'tcx>,
-                                  types: &mut subst::VecPerParamSpace<Ty<'tcx>>,
+                                  types: &mut VecPerParamSpace<Ty<'tcx>>,
                                   defs: &[TypeParameterDef<'tcx>]) {
         for def in defs.iter() {
             debug!("construct_parameter_environment(): push_types_from_defs: def={}",
@@ -6915,12 +6915,49 @@ impl<'tcx> RegionEscape for Ty<'tcx> {
     }
 }
 
+impl<'tcx,T:RegionEscape> RegionEscape for VecPerParamSpace<T> {
+    fn has_regions_escaping_depth(&self, depth: u32) -> bool {
+        self.iter_enumerated().any(|(space, _, t)| {
+            if space == subst::FnSpace {
+                t.has_regions_escaping_depth(depth+1)
+            } else {
+                t.has_regions_escaping_depth(depth)
+            }
+        })
+    }
+}
+
+impl<'tcx> RegionEscape for TypeScheme<'tcx> {
+    fn has_regions_escaping_depth(&self, depth: u32) -> bool {
+        self.ty.has_regions_escaping_depth(depth) ||
+            self.generics.has_regions_escaping_depth(depth)
+    }
+}
+
 impl RegionEscape for Region {
     fn has_regions_escaping_depth(&self, depth: u32) -> bool {
         self.escapes_depth(depth)
     }
 }
 
+impl<'tcx> RegionEscape for Generics<'tcx> {
+    fn has_regions_escaping_depth(&self, depth: u32) -> bool {
+        self.predicates.has_regions_escaping_depth(depth)
+    }
+}
+
+impl<'tcx> RegionEscape for Predicate<'tcx> {
+    fn has_regions_escaping_depth(&self, depth: u32) -> bool {
+        match *self {
+            Predicate::Trait(ref data) => data.has_regions_escaping_depth(depth),
+            Predicate::Equate(ref data) => data.has_regions_escaping_depth(depth),
+            Predicate::RegionOutlives(ref data) => data.has_regions_escaping_depth(depth),
+            Predicate::TypeOutlives(ref data) => data.has_regions_escaping_depth(depth),
+            Predicate::Projection(ref data) => data.has_regions_escaping_depth(depth),
+        }
+    }
+}
+
 impl<'tcx> RegionEscape for TraitRef<'tcx> {
     fn has_regions_escaping_depth(&self, depth: u32) -> bool {
         self.substs.types.iter().any(|t| t.has_regions_escaping_depth(depth)) ||
@@ -6988,9 +7025,15 @@ pub trait HasProjectionTypes {
     fn has_projection_types(&self) -> bool;
 }
 
+impl<'tcx,T:HasProjectionTypes> HasProjectionTypes for VecPerParamSpace<T> {
+    fn has_projection_types(&self) -> bool {
+        self.iter().any(|p| p.has_projection_types())
+    }
+}
+
 impl<'tcx> HasProjectionTypes for ty::GenericBounds<'tcx> {
     fn has_projection_types(&self) -> bool {
-        self.predicates.iter().any(|p| p.has_projection_types())
+        self.predicates.has_projection_types()
     }
 }
 
diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs
index 1971be11760..4e6593deddd 100644
--- a/src/librustc_typeck/check/method/mod.rs
+++ b/src/librustc_typeck/check/method/mod.rs
@@ -216,7 +216,7 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &'a FnCtxt<'a, 'tcx>,
     //
     // Note that as the method comes from a trait, it should not have
     // any late-bound regions appearing in its bounds.
-    let method_bounds = method_ty.generics.to_bounds(fcx.tcx(), trait_ref.substs);
+    let method_bounds = fcx.instantiate_bounds(span, trait_ref.substs, &method_ty.generics);
     assert!(!method_bounds.has_escaping_regions());
     fcx.add_obligations_for_parameters(
         traits::ObligationCause::misc(span, fcx.body_id),
diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs
index 1a9e124521e..610a5c0b246 100644
--- a/src/librustc_typeck/check/method/probe.rs
+++ b/src/librustc_typeck/check/method/probe.rs
@@ -768,6 +768,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
                     // Check whether the impl imposes obligations we have to worry about.
                     let impl_generics = ty::lookup_item_type(self.tcx(), impl_def_id).generics;
                     let impl_bounds = impl_generics.to_bounds(self.tcx(), substs);
+                    // TODO assoc type normalization here?
 
                     // Erase any late-bound regions bound in the impl
                     // which appear in the bounds.
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 8069d00dda8..e2691a778ac 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -93,7 +93,7 @@ use middle::subst::{mod, Subst, Substs, VecPerParamSpace, ParamSpace};
 use middle::traits;
 use middle::ty::{FnSig, VariantInfo, TypeScheme};
 use middle::ty::{Disr, ParamTy, ParameterEnvironment};
-use middle::ty::{mod, HasProjectionTypes, Ty};
+use middle::ty::{mod, HasProjectionTypes, RegionEscape, Ty};
 use middle::ty::liberate_late_bound_regions;
 use middle::ty::{MethodCall, MethodCallee, MethodMap, ObjectCastMap};
 use middle::ty_fold::{TypeFolder, TypeFoldable};
@@ -1741,6 +1741,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         result
     }
 
+    /// As `instantiate_type_scheme`, but for the bounds found in a
+    /// generic type scheme.
+    fn instantiate_bounds(&self,
+                          span: Span,
+                          substs: &Substs<'tcx>,
+                          generics: &ty::Generics<'tcx>)
+                          -> ty::GenericBounds<'tcx>
+    {
+        ty::GenericBounds {
+            predicates: self.instantiate_type_scheme(span, substs, &generics.predicates)
+        }
+    }
+
+
     fn normalize_associated_types_in<T>(&self, span: Span, value: &T) -> T
         where T : TypeFoldable<'tcx> + Clone + HasProjectionTypes
     {
@@ -1852,7 +1866,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 span,
                 &type_scheme.generics);
         let bounds =
-            type_scheme.generics.to_bounds(self.tcx(), &substs);
+            self.instantiate_bounds(span, &substs, &type_scheme.generics);
         self.add_obligations_for_parameters(
             traits::ObligationCause::new(
                 span,
@@ -4455,7 +4469,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
                 if let Some(did) = did {
                     let polytype = ty::lookup_item_type(tcx, did);
                     let substs = Substs::new_type(vec![idx_type], vec![]);
-                    let bounds = polytype.generics.to_bounds(tcx, &substs);
+                    let bounds = fcx.instantiate_bounds(expr.span, &substs, &polytype.generics);
                     fcx.add_obligations_for_parameters(
                         traits::ObligationCause::new(expr.span,
                                                      fcx.body_id,
@@ -5270,31 +5284,20 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
     }
 
     // The things we are substituting into the type should not contain
-    // escaping late-bound regions.
+    // escaping late-bound regions, and nor should the base type scheme.
     assert!(!substs.has_regions_escaping_depth(0));
+    assert!(!type_scheme.has_escaping_regions());
 
-    // In the case of static items taken from impls, there may be
-    // late-bound regions associated with the impl (not declared on
-    // the fn itself). Those should be replaced with fresh variables
-    // now. These can appear either on the type being referenced, or
-    // on the associated bounds.
-    let bounds = type_scheme.generics.to_bounds(fcx.tcx(), &substs);
-    let (ty_late_bound, bounds) =
-        fcx.infcx().replace_late_bound_regions_with_fresh_var(
-            span,
-            infer::FnCall,
-            &ty::Binder((type_scheme.ty, bounds))).0;
-
-    debug!("after late-bounds have been replaced: ty_late_bound={}", ty_late_bound.repr(fcx.tcx()));
-    debug!("after late-bounds have been replaced: bounds={}", bounds.repr(fcx.tcx()));
-
+    // Add all the obligations that are required, substituting and
+    // normalized appropriately.
+    let bounds = fcx.instantiate_bounds(span, &substs, &type_scheme.generics);
     fcx.add_obligations_for_parameters(
         traits::ObligationCause::new(span, fcx.body_id, traits::ItemObligation(def.def_id())),
         &bounds);
 
     // Substitute the values for the type parameters into the type of
     // the referenced item.
-    let ty_substituted = fcx.instantiate_type_scheme(span, &substs, &ty_late_bound);
+    let ty_substituted = fcx.instantiate_type_scheme(span, &substs, &type_scheme.ty);
 
     fcx.write_ty(node_id, ty_substituted);
     fcx.write_substs(node_id, ty::ItemSubsts { substs: substs });
diff --git a/src/librustc_typeck/check/wf.rs b/src/librustc_typeck/check/wf.rs
index 2a3f528809c..2d9b243e00e 100644
--- a/src/librustc_typeck/check/wf.rs
+++ b/src/librustc_typeck/check/wf.rs
@@ -269,7 +269,14 @@ impl<'cx,'tcx> BoundsChecker<'cx,'tcx> {
     pub fn check_trait_ref(&mut self, trait_ref: &ty::TraitRef<'tcx>) {
         let trait_def = ty::lookup_trait_def(self.fcx.tcx(), trait_ref.def_id);
 
-        let bounds = trait_def.generics.to_bounds(self.tcx(), trait_ref.substs);
+        // TODO uncommented this line causes failures because the impl
+        // obligations are not registered when we do a projection, and
+        // in this case it's those obligations that make the link
+        // between the normalized type ($1) and the result
+        //
+        // let bounds = self.fcx.instantiate_bounds(self.span, trait_ref.substs, &trait_def.generics);
+
+        let bounds = trait_def.generics.to_bounds(self.fcx.tcx(), trait_ref.substs);
         self.fcx.add_obligations_for_parameters(
             traits::ObligationCause::new(
                 self.span,
@@ -319,13 +326,14 @@ impl<'cx,'tcx> TypeFolder<'tcx> for BoundsChecker<'cx,'tcx> {
             ty::ty_struct(type_id, substs) |
             ty::ty_enum(type_id, substs) => {
                 let type_scheme = ty::lookup_item_type(self.fcx.tcx(), type_id);
+                let bounds = self.fcx.instantiate_bounds(self.span, substs, &type_scheme.generics);
 
                 if self.binding_count == 0 {
                     self.fcx.add_obligations_for_parameters(
                         traits::ObligationCause::new(self.span,
                                                      self.fcx.body_id,
                                                      traits::ItemObligation(type_id)),
-                        &type_scheme.generics.to_bounds(self.tcx(), substs));
+                        &bounds);
                 } else {
                     // There are two circumstances in which we ignore
                     // region obligations.
@@ -349,7 +357,6 @@ impl<'cx,'tcx> TypeFolder<'tcx> for BoundsChecker<'cx,'tcx> {
                     //
                     // (I believe we should do the same for traits, but
                     // that will require an RFC. -nmatsakis)
-                    let bounds = type_scheme.generics.to_bounds(self.tcx(), substs);
                     let bounds = filter_to_trait_obligations(bounds);
                     self.fcx.add_obligations_for_parameters(
                         traits::ObligationCause::new(self.span,
diff --git a/src/test/run-pass/associated-types-normalize-in-bounds-ufcs.rs b/src/test/run-pass/associated-types-normalize-in-bounds-ufcs.rs
new file mode 100644
index 00000000000..0fd47720421
--- /dev/null
+++ b/src/test/run-pass/associated-types-normalize-in-bounds-ufcs.rs
@@ -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 {
+        SliceExt2::split2(self, pred);
+        loop {}
+    }
+}
+
+fn main() { }