]> git.lizzy.rs Git - rust.git/commitdiff
Don't normalize associated types when in region binders, wait until we instantiate
authorNiko Matsakis <niko@alum.mit.edu>
Sun, 28 Dec 2014 15:07:21 +0000 (10:07 -0500)
committerNiko Matsakis <niko@alum.mit.edu>
Tue, 30 Dec 2014 14:36:22 +0000 (09:36 -0500)
them. Also fix some assertions and handling of builtin bounds.

src/librustc/middle/traits/fulfill.rs
src/librustc/middle/traits/select.rs
src/librustc/middle/ty.rs
src/librustc_typeck/check/assoc.rs
src/librustc_typeck/check/closure.rs
src/librustc_typeck/check/method/confirm.rs
src/librustc_typeck/check/method/mod.rs
src/librustc_typeck/check/mod.rs
src/librustc_typeck/check/regionmanip.rs
src/librustc_typeck/check/wf.rs
src/libsyntax/visit.rs

index 0d2023ead4fcc5aadbaad6b62a8c70b2ed983575..e72d5b405c4e4dae1117e1773ec4990955071d6c 100644 (file)
@@ -109,6 +109,10 @@ pub fn normalize_associated_type<'a>(&mut self,
                                          cause: ObligationCause<'tcx>)
                                          -> Ty<'tcx>
     {
+        debug!("normalize_associated_type(trait_ref={}, item_name={})",
+               trait_ref.repr(infcx.tcx),
+               item_name.repr(infcx.tcx));
+
         assert!(!trait_ref.has_escaping_regions());
 
         let ty_var = infcx.next_ty_var();
@@ -120,6 +124,9 @@ pub fn normalize_associated_type<'a>(&mut self,
             });
         let obligation = Obligation::new(cause, projection.as_predicate());
         self.register_predicate(infcx, obligation);
+
+        debug!("normalize_associated_type: result={}", ty_var.repr(infcx.tcx));
+
         ty_var
     }
 
index 2e4bdadb8c231644662649895204e7a69b03999b..9301531e84d5e1b2e22bbede4b3806c0a01d3057 100644 (file)
@@ -1141,7 +1141,11 @@ fn builtin_bound(&mut self,
                      obligation: &TraitObligation<'tcx>)
                      -> Result<BuiltinBoundConditions<'tcx>,SelectionError<'tcx>>
     {
-        // TODO seems like we ought to skolemize here, oder?
+        // Note: these tests operate on types that may contain bound
+        // regions. To be proper, we ought to skolemize here, but we
+        // forego the skolemization and defer it until the
+        // confirmation step.
+
         let self_ty = self.infcx.shallow_resolve(obligation.predicate.0.self_ty());
         return match self_ty.sty {
             ty::ty_infer(ty::IntVar(_)) |
@@ -1627,13 +1631,31 @@ fn vtable_builtin_data(&mut self,
                            -> VtableBuiltinData<PredicateObligation<'tcx>>
     {
         let derived_cause = self.derived_cause(obligation, BuiltinDerivedObligation);
-        let obligations = nested.iter().map(|&t| {
-            util::predicate_for_builtin_bound(
-                self.tcx(),
-                derived_cause.clone(),
-                bound,
-                obligation.recursion_depth + 1,
-                t)
+        let obligations = nested.iter().map(|&bound_ty| {
+            // the obligation might be higher-ranked, e.g. for<'a> &'a
+            // int : Copy. In that case, we will wind up with
+            // late-bound regions in the `nested` vector. So for each
+            // one we instantiate to a skolemized region, do our work
+            // to produce something like `&'0 int : Copy`, and then
+            // re-bind it. This is a bit of busy-work but preserves
+            // the invariant that we only manipulate free regions, not
+            // bound ones.
+            self.infcx.try(|snapshot| {
+                let (skol_ty, skol_map) =
+                    self.infcx().skolemize_late_bound_regions(&ty::Binder(bound_ty), snapshot);
+                let skol_predicate =
+                    util::predicate_for_builtin_bound(
+                        self.tcx(),
+                        derived_cause.clone(),
+                        bound,
+                        obligation.recursion_depth + 1,
+                        skol_ty);
+                match skol_predicate {
+                    Ok(skol_predicate) => Ok(self.infcx().plug_leaks(skol_map, snapshot,
+                                                                     &skol_predicate)),
+                    Err(ErrorReported) => Err(ErrorReported)
+                }
+            })
         }).collect::<Result<_, _>>();
         let mut obligations = match obligations {
             Ok(o) => o,
index 6225a0f3fba18607ce877559b25f347ab1010fa9..583d2ce3b67c238d30477587087525125d5f7bab 100644 (file)
@@ -6903,8 +6903,19 @@ fn has_regions_escaping_depth(&self, depth: u32) -> bool {
 
 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)) &&
-            self.substs.regions().iter().any(|t| t.has_regions_escaping_depth(depth))
+        self.substs.types.iter().any(|t| t.has_regions_escaping_depth(depth)) ||
+            self.substs.regions.has_regions_escaping_depth(depth)
+    }
+}
+
+impl<'tcx> RegionEscape for subst::RegionSubsts {
+    fn has_regions_escaping_depth(&self, depth: u32) -> bool {
+        match *self {
+            subst::ErasedRegions => false,
+            subst::NonerasedRegions(ref r) => {
+                r.iter().any(|t| t.has_regions_escaping_depth(depth))
+            }
+        }
     }
 }
 
@@ -6921,7 +6932,7 @@ fn has_regions_escaping_depth(&self, depth: u32) -> bool {
 }
 
 impl<'tcx> RegionEscape for TraitPredicate<'tcx> {
-    fn has_regions_escaping_depth(&self, depth: uint) -> bool {
+    fn has_regions_escaping_depth(&self, depth: u32) -> bool {
         self.trait_ref.has_regions_escaping_depth(depth)
     }
 }
@@ -6933,14 +6944,14 @@ fn has_regions_escaping_depth(&self, depth: u32) -> bool {
 }
 
 impl<'tcx> RegionEscape for ProjectionPredicate<'tcx> {
-    fn has_regions_escaping_depth(&self, depth: uint) -> bool {
+    fn has_regions_escaping_depth(&self, depth: u32) -> bool {
         self.projection_ty.has_regions_escaping_depth(depth) ||
             self.ty.has_regions_escaping_depth(depth)
     }
 }
 
 impl<'tcx> RegionEscape for ProjectionTy<'tcx> {
-    fn has_regions_escaping_depth(&self, depth: uint) -> bool {
+    fn has_regions_escaping_depth(&self, depth: u32) -> bool {
         self.trait_ref.has_regions_escaping_depth(depth)
     }
 }
index e737bb1b237fb87dd48a7c6b3ab99ab5b0eb9579..b59f9291e4fc66dc8f2095aea8057f2fbad0b6a9 100644 (file)
@@ -33,7 +33,8 @@ 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 };
+                                                    fulfillment_cx: fulfillment_cx,
+                                                    region_binders: 0 };
     value.fold_with(&mut normalizer)
 }
 
@@ -42,6 +43,7 @@ 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> {
@@ -49,9 +51,29 @@ 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.
+        //
+        // Example:
+        //
+        //     for<'a> fn(<T as Foo<&'a>>::A)
+        //
+        // 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) => {
+            ty::ty_projection(ref data) if no_region_binders => {
                 let cause =
                     ObligationCause::new(
                         self.span,
index 19108ca710bc1a3153f3877794cfe81329aa1140..340cc9b355c0252043b9c8bfb859c0e8c2d92ad6 100644 (file)
@@ -14,6 +14,7 @@
 
 use astconv;
 use middle::infer;
+use middle::region::CodeExtent;
 use middle::subst;
 use middle::ty::{mod, ToPolyTraitRef, Ty};
 use rscope::RegionScope;
@@ -132,10 +133,13 @@ fn check_unboxed_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
 
     fcx.write_ty(expr.id, closure_type);
 
+    let fn_sig =
+        ty::liberate_late_bound_regions(fcx.tcx(), CodeExtent::from_node_id(body.id), &fn_ty.sig);
+
     check_fn(fcx.ccx,
              ast::Unsafety::Normal,
              expr.id,
-             &fn_ty.sig,
+             &fn_sig,
              decl,
              expr.id,
              &*body,
@@ -310,7 +314,7 @@ fn check_boxed_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
                                        decl,
                                        abi::Rust,
                                        expected_sig);
-    let fty_sig = fn_ty.sig.clone();
+    let fn_sig = fn_ty.sig.clone();
     let fty = ty::mk_closure(tcx, fn_ty);
     debug!("check_expr_fn fty={}", fcx.infcx().ty_to_string(fty));
 
@@ -325,10 +329,13 @@ fn check_boxed_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
         ty::UniqTraitStore => (ast::Unsafety::Normal, expr.id)
     };
 
+    let fn_sig =
+        ty::liberate_late_bound_regions(tcx, CodeExtent::from_node_id(body.id), &fn_sig);
+
     check_fn(fcx.ccx,
              inherited_style,
              inherited_style_id,
-             &fty_sig,
+             &fn_sig,
              &*decl,
              expr.id,
              &*body,
index de6824fa5ddd1e822a5dede46b6fc8ba7c58c0dd..1aa9adaf9ec4d4422fe3ae65601375fbdf602a50 100644 (file)
@@ -424,17 +424,18 @@ fn instantiate_method_sig(&mut self,
         debug!("method_bounds after subst = {}",
                method_bounds.repr(self.tcx()));
 
-        // Substitute the type/early-bound-regions into the method
-        // signature. In addition, the method signature may bind
-        // late-bound regions, so instantiate those.
-        let method_sig = self.fcx.instantiate_type_scheme(self.span,
-                                                          &all_substs,
-                                                          &pick.method_ty.fty.sig);
-        debug!("late-bound lifetimes from method substituted, method_sig={}",
+        // Instantiate late-bound regions and substitute the trait
+        // parameters into the method type to get the actual method type.
+        //
+        // NB: Instantiate late-bound regions first so that
+        // `instantiate_type_scheme` can normalize associated types that
+        // may reference those regions.
+        let method_sig = self.replace_late_bound_regions_with_fresh_var(&pick.method_ty.fty.sig);
+        debug!("late-bound lifetimes from method instantiated, method_sig={}",
                method_sig.repr(self.tcx()));
 
-        let method_sig = self.replace_late_bound_regions_with_fresh_var(&method_sig);
-        debug!("late-bound lifetimes from method instantiated, method_sig={}",
+        let method_sig = self.fcx.instantiate_type_scheme(self.span, &all_substs, &method_sig);
+        debug!("type scheme substituted, method_sig={}",
                method_sig.repr(self.tcx()));
 
         InstantiatedMethodSig {
index cb71fbce8ac4cf22b179d514981e098da5130503..5b6acdbf3ada5fff99b347b0ea71aa77bd852b5e 100644 (file)
@@ -190,19 +190,21 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &'a FnCtxt<'a, 'tcx>,
     debug!("lookup_in_trait_adjusted: method_num={} method_ty={}",
            method_num, method_ty.repr(fcx.tcx()));
 
-    // Substitute the trait parameters into the method type and
-    // instantiate late-bound regions to get the actual method type.
-    let bare_fn_ty = fcx.instantiate_type_scheme(span,
-                                                 &trait_ref.substs,
-                                                 &method_ty.fty);
+    // Instantiate late-bound regions and substitute the trait
+    // parameters into the method type to get the actual method type.
+    //
+    // NB: Instantiate late-bound regions first so that
+    // `instantiate_type_scheme` can normalize associated types that
+    // may reference those regions.
     let fn_sig = fcx.infcx().replace_late_bound_regions_with_fresh_var(span,
                                                                        infer::FnCall,
-                                                                       &bare_fn_ty.sig).0;
+                                                                       &method_ty.fty.sig).0;
+    let fn_sig = fcx.instantiate_type_scheme(span, &trait_ref.substs, &fn_sig);
     let transformed_self_ty = fn_sig.inputs[0];
     let fty = ty::mk_bare_fn(tcx, None, tcx.mk_bare_fn(ty::BareFnTy {
         sig: ty::Binder(fn_sig),
-        unsafety: bare_fn_ty.unsafety,
-        abi: bare_fn_ty.abi.clone(),
+        unsafety: method_ty.fty.unsafety,
+        abi: method_ty.fty.abi.clone(),
     }));
 
     debug!("lookup_in_trait_adjusted: matched method fty={} obligation={}",
index 139ef010d212424b9ddaa4a7d53ff53669090c97..e485e49148fe4831a0ed9416a582e1eab9dc4875 100644 (file)
@@ -432,13 +432,15 @@ fn check_bare_fn<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
         ty::ty_bare_fn(_, ref fn_ty) => {
             let inh = Inherited::new(ccx.tcx, param_env);
 
-            // Compute the fty from point of view of inside fn
-            // (replace any type-scheme with a type, and normalize
-            // associated types appearing in the fn signature).
-            let fn_ty = fn_ty.subst(ccx.tcx, &inh.param_env.free_substs);
-            let fn_ty = inh.normalize_associated_types_in(body.span, body.id, &fn_ty);
-
-            let fcx = check_fn(ccx, fn_ty.unsafety, id, &fn_ty.sig,
+            // Compute the fty from point of view of inside fn.
+            let fn_sig =
+                fn_ty.sig.subst(ccx.tcx, &inh.param_env.free_substs);
+            let fn_sig =
+                liberate_late_bound_regions(ccx.tcx, CodeExtent::from_node_id(body.id), &fn_sig);
+            let fn_sig =
+                inh.normalize_associated_types_in(body.span, body.id, &fn_sig);
+
+            let fcx = check_fn(ccx, fn_ty.unsafety, id, &fn_sig,
                                decl, id, body, &inh);
 
             vtable::select_all_fcx_obligations_or_error(&fcx);
@@ -542,7 +544,7 @@ fn visit_item(&mut self, _: &ast::Item) { }
 fn check_fn<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>,
                       unsafety: ast::Unsafety,
                       unsafety_id: ast::NodeId,
-                      fn_sig: &ty::PolyFnSig<'tcx>,
+                      fn_sig: &ty::FnSig<'tcx>,
                       decl: &ast::FnDecl,
                       fn_id: ast::NodeId,
                       body: &ast::Block,
@@ -552,10 +554,6 @@ fn check_fn<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>,
     let tcx = ccx.tcx;
     let err_count_on_creation = tcx.sess.err_count();
 
-    // First, we have to replace any bound regions in the fn type with free ones.
-    // The free region references will be bound the node_id of the body block.
-    let fn_sig = liberate_late_bound_regions(tcx, CodeExtent::from_node_id(body.id), fn_sig);
-
     let arg_tys = fn_sig.inputs[];
     let ret_ty = fn_sig.output;
 
@@ -1161,39 +1159,80 @@ fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>,
         }
     }
 
+    // We now need to check that the signature of the impl method is
+    // compatible with that of the trait method. We do this by
+    // checking that `impl_fty <: trait_fty`.
+    //
+    // FIXME. Unfortunately, this doesn't quite work right now because
+    // associated type normalization is not integrated into subtype
+    // checks. For the comparison to be valid, we need to
+    // normalize the associated types in the impl/trait methods
+    // first. However, because function types bind regions, just
+    // calling `normalize_associated_types_in` would have no effect on
+    // any associated types appearing in the fn arguments or return
+    // type.
+
+
     // Compute skolemized form of impl and trait method tys.
     let impl_fty = ty::mk_bare_fn(tcx, None, tcx.mk_bare_fn(impl_m.fty.clone()));
     let impl_fty = impl_fty.subst(tcx, impl_to_skol_substs);
     let trait_fty = ty::mk_bare_fn(tcx, None, tcx.mk_bare_fn(trait_m.fty.clone()));
     let trait_fty = trait_fty.subst(tcx, &trait_to_skol_substs);
-    let trait_fty =
-        assoc::normalize_associated_types_in(&infcx,
-                                             &mut fulfillment_cx,
-                                             impl_m_span,
-                                             impl_m_body_id,
-                                             &trait_fty);
-
-    // Check the impl method type IM is a subtype of the trait method
-    // type TM. To see why this makes sense, think of a vtable. The
-    // expected type of the function pointers in the vtable is the
-    // type TM of the trait method.  The actual type will be the type
-    // IM of the impl method. Because we know that IM <: TM, that
-    // means that anywhere a TM is expected, a IM will do instead. In
-    // other words, anyone expecting to call a method with the type
-    // from the trait, can safely call a method with the type from the
-    // impl instead.
-    debug!("checking trait method for compatibility: impl ty {}, trait ty {}",
-           impl_fty.repr(tcx),
-           trait_fty.repr(tcx));
-    match infer::mk_subty(&infcx, false, infer::MethodCompatCheck(impl_m_span),
-                          impl_fty, trait_fty) {
-        Ok(()) => {}
-        Err(ref terr) => {
+
+    let err = infcx.try(|snapshot| {
+        let origin = infer::MethodCompatCheck(impl_m_span);
+
+        let (impl_sig, _) =
+            infcx.replace_late_bound_regions_with_fresh_var(impl_m_span,
+                                                            infer::HigherRankedType,
+                                                            &impl_m.fty.sig);
+        let impl_sig =
+            impl_sig.subst(tcx, impl_to_skol_substs);
+        let impl_sig =
+            assoc::normalize_associated_types_in(&infcx,
+                                                 &mut fulfillment_cx,
+                                                 impl_m_span,
+                                                 impl_m_body_id,
+                                                 &impl_sig);
+        let impl_fty = ty::mk_bare_fn(tcx, None, ty::BareFnTy { unsafety: impl_m.fty.unsafety,
+                                                                abi: impl_m.fty.abi,
+                                                                sig: ty::Binder(impl_sig) });
+        debug!("compare_impl_method: impl_fty={}",
+               impl_fty.repr(tcx));
+
+        let (trait_sig, skol_map) =
+            infcx.skolemize_late_bound_regions(&trait_m.fty.sig, snapshot);
+        let trait_sig =
+            trait_sig.subst(tcx, &trait_to_skol_substs);
+        let trait_sig =
+            assoc::normalize_associated_types_in(&infcx,
+                                                 &mut fulfillment_cx,
+                                                 impl_m_span,
+                                                 impl_m_body_id,
+                                                 &trait_sig);
+        let trait_fty = ty::mk_bare_fn(tcx, None, ty::BareFnTy { unsafety: trait_m.fty.unsafety,
+                                                                 abi: trait_m.fty.abi,
+                                                                 sig: ty::Binder(trait_sig) });
+
+        debug!("compare_impl_method: trait_fty={}",
+               trait_fty.repr(tcx));
+
+        try!(infer::mk_subty(&infcx, false, origin, impl_fty, trait_fty));
+
+        infcx.leak_check(&skol_map, snapshot)
+    });
+
+    match err {
+        Ok(()) => { }
+        Err(terr) => {
+            debug!("checking trait method for compatibility: impl ty {}, trait ty {}",
+                   impl_fty.repr(tcx),
+                   trait_fty.repr(tcx));
             span_err!(tcx.sess, impl_m_span, E0053,
-                "method `{}` has an incompatible type for trait: {}",
-                token::get_name(trait_m.name),
-                ty::type_err_to_str(tcx, terr));
-            ty::note_and_explain_type_err(tcx, terr);
+                      "method `{}` has an incompatible type for trait: {}",
+                      token::get_name(trait_m.name),
+                      ty::type_err_to_str(tcx, &terr));
+            return;
         }
     }
 
@@ -1791,7 +1830,7 @@ fn register_unsize_obligations(&self,
     /// Also returns the substitution from the type parameters on `def_id` to the fresh variables.
     /// Registers any trait obligations specified on `def_id` at the same time.
     ///
-    /// Note that function is only intended to be used with types (notably, not impls). This is
+    /// Note that function is only intended to be used with types (notably, not fns). This is
     /// because it doesn't do any instantiation of late-bound regions.
     pub fn instantiate_type(&self,
                             span: Span,
@@ -3061,12 +3100,18 @@ fn check_call(fcx: &FnCtxt,
             }
         };
 
-        // Replace any bound regions that appear in the function
-        // signature with region variables
+        // Replace any late-bound regions that appear in the function
+        // signature with region variables. We also have to
+        // renormalize the associated types at this point, since they
+        // previously appeared within a `Binder<>` and hence would not
+        // have been normalized before.
         let fn_sig =
             fcx.infcx().replace_late_bound_regions_with_fresh_var(call_expr.span,
                                                                   infer::FnCall,
                                                                   fn_sig).0;
+        let fn_sig =
+            fcx.normalize_associated_types_in(call_expr.span,
+                                              &fn_sig);
 
         // Call the generic checker.
         check_argument_types(fcx,
index 14405b9a92b59c0d199406e3120fde12a3e1a300..c0b281450a2c0bb2956c95ff918fbb1ab09b410e 100644 (file)
@@ -104,7 +104,8 @@ fn accumulate_from_ty(&mut self, ty: Ty<'tcx>) {
 
             ty::ty_enum(def_id, substs) |
             ty::ty_struct(def_id, substs) => {
-                self.accumulate_from_adt(ty, def_id, substs)
+                let item_scheme = ty::lookup_item_type(self.tcx, def_id);
+                self.accumulate_from_adt(ty, def_id, &item_scheme.generics, substs)
             }
 
             ty::ty_vec(t, _) |
@@ -127,7 +128,9 @@ fn accumulate_from_ty(&mut self, ty: Ty<'tcx>) {
                 // TODO What region constraints are necessary here, if any??
 
                 // this seems like a minimal requirement:
-                self.accumulate_from_ty(data.trait_ref.self_ty());
+                let trait_def = ty::lookup_trait_def(self.tcx, data.trait_ref.def_id);
+                self.accumulate_from_adt(ty, data.trait_ref.def_id,
+                                         &trait_def.generics, &data.trait_ref.substs)
             }
 
             ty::ty_tup(ref tuptys) => {
@@ -222,14 +225,12 @@ fn push_param_constraint(&mut self,
     fn accumulate_from_adt(&mut self,
                            ty: Ty<'tcx>,
                            def_id: ast::DefId,
+                           generics: &ty::Generics<'tcx>,
                            substs: &Substs<'tcx>)
     {
         // The generic declarations from the type, appropriately
         // substituted for the actual substitutions.
-        let generics =
-            ty::lookup_item_type(self.tcx, def_id)
-            .generics
-            .subst(self.tcx, substs);
+        let generics = generics.subst(self.tcx, substs);
 
         // Variance of each type/region parameter.
         let variances = ty::item_variances(self.tcx, def_id);
index 21c81c7be9bfac65c5706f1b852ae76be4cd0120..2a3f528809cfd883776e85f39b997dfe95a5ce3f 100644 (file)
@@ -349,8 +349,7 @@ fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'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 = 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,
index 1cd21ccac7a0ef41b7d757b3ee2cb51b65333c0f..40ca6354ca6d14d114378799746d40b2de55527c 100644 (file)
@@ -133,6 +133,9 @@ fn visit_path_segment(&mut self, path_span: Span, path_segment: &'v PathSegment)
     fn visit_path_parameters(&mut self, path_span: Span, path_parameters: &'v PathParameters) {
         walk_path_parameters(self, path_span, path_parameters)
     }
+    fn visit_assoc_type_binding(&mut self, type_binding: &'v TypeBinding) {
+        walk_assoc_type_binding(self, type_binding)
+    }
     fn visit_attribute(&mut self, _attr: &'v Attribute) {}
 }
 
@@ -467,6 +470,9 @@ pub fn walk_path_parameters<'v, V: Visitor<'v>>(visitor: &mut V,
             for lifetime in data.lifetimes.iter() {
                 visitor.visit_lifetime_ref(lifetime);
             }
+            for binding in data.bindings.iter() {
+                visitor.visit_assoc_type_binding(&**binding);
+            }
         }
         ast::ParenthesizedParameters(ref data) => {
             for typ in data.inputs.iter() {
@@ -479,6 +485,12 @@ pub fn walk_path_parameters<'v, V: Visitor<'v>>(visitor: &mut V,
     }
 }
 
+pub fn walk_assoc_type_binding<'v, V: Visitor<'v>>(visitor: &mut V,
+                                                   type_binding: &'v TypeBinding) {
+    visitor.visit_ident(type_binding.span, type_binding.ident);
+    visitor.visit_ty(&*type_binding.ty);
+}
+
 pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat) {
     match pattern.node {
         PatEnum(ref path, ref children) => {