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>, + types: &mut VecPerParamSpace>, 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 { + 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 { + 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(&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 or the MIT license +// , 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; + +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> + where P: FnMut(&Self::Item) -> bool; +} + +impl SliceExt2 for [T] { + type Item = T; + + fn split2

(&self, pred: P) -> Splits where P: FnMut(&T) -> bool { + loop {} + } + + fn splitn2

(&self, n: uint, pred: P) -> SplitsN> where P: FnMut(&T) -> bool { + SliceExt2::split2(self, pred); + loop {} + } +} + +fn main() { }