diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index a286ce8c7cb19..a1dd2caf786c2 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -187,7 +187,7 @@ for ty::OutlivesPredicate } impl_stable_hash_for!(struct ty::ProjectionPredicate<'tcx> { projection_ty, ty }); -impl_stable_hash_for!(struct ty::ProjectionTy<'tcx> { trait_ref, item_def_id }); +impl_stable_hash_for!(struct ty::ProjectionTy<'tcx> { substs, item_def_id }); impl<'a, 'gcx, 'tcx> HashStable> for ty::Predicate<'tcx> { @@ -599,8 +599,8 @@ impl_stable_hash_for!(struct ty::ExistentialTraitRef<'tcx> { }); impl_stable_hash_for!(struct ty::ExistentialProjection<'tcx> { - trait_ref, - item_name, + item_def_id, + substs, ty }); diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 228481e853021..7154ce9e38f5e 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -274,7 +274,7 @@ pub enum LateBoundRegionConversionTime { HigherRankedType, /// when projecting an associated type - AssocTypeProjection(ast::Name), + AssocTypeProjection(ast::Name), // FIXME(tschottdorf): should contain DefId, not Name } /// Reasons to create a region inference variable @@ -1277,14 +1277,13 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { match_b: ty::TraitRef<'tcx>) -> InferResult<'tcx, HrMatchResult>> { + let match_pair = match_a.map_bound(|p| (p.projection_ty.trait_ref(self.tcx), p.ty)); let span = cause.span; - let match_trait_ref = match_a.skip_binder().projection_ty.trait_ref; let trace = TypeTrace { cause, - values: TraitRefs(ExpectedFound::new(true, match_trait_ref, match_b)) + values: TraitRefs(ExpectedFound::new(true, match_pair.skip_binder().0, match_b)) }; - let match_pair = match_a.map_bound(|p| (p.projection_ty.trait_ref, p.ty)); let mut combine = self.combine_fields(trace, param_env); let result = combine.higher_ranked_match(span, &match_pair, &match_b, true)?; Ok(InferOk { value: result, obligations: combine.obligations }) diff --git a/src/librustc/infer/region_inference/mod.rs b/src/librustc/infer/region_inference/mod.rs index 4f8168982496e..57f2f748b246e 100644 --- a/src/librustc/infer/region_inference/mod.rs +++ b/src/librustc/infer/region_inference/mod.rs @@ -1550,8 +1550,7 @@ impl<'a, 'gcx, 'tcx> GenericKind<'tcx> { pub fn to_ty(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx> { match *self { GenericKind::Param(ref p) => p.to_ty(tcx), - GenericKind::Projection(ref p) => tcx.mk_projection( - p.trait_ref.clone(), p.item_name(tcx)), + GenericKind::Projection(ref p) => tcx.mk_projection(p.item_def_id, p.substs), } } } diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs index 826d4a2815838..4f1eb6169209b 100644 --- a/src/librustc/traits/fulfill.rs +++ b/src/librustc/traits/fulfill.rs @@ -470,8 +470,9 @@ fn process_predicate<'a, 'gcx, 'tcx>( let project_obligation = obligation.with(data.clone()); match project::poly_project_and_unify_type(selcx, &project_obligation) { Ok(None) => { + let tcx = selcx.tcx(); pending_obligation.stalled_on = - trait_ref_type_vars(selcx, data.to_poly_trait_ref()); + trait_ref_type_vars(selcx, data.to_poly_trait_ref(tcx)); Ok(None) } Ok(v) => Ok(v), diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs index c6c052fa4b1bc..9c04c013c4b1a 100644 --- a/src/librustc/traits/object_safety.rs +++ b/src/librustc/traits/object_safety.rs @@ -354,7 +354,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { // direct equality here because all of these types // are part of the formal parameter listing, and // hence there should be no inference variables. - let projection_trait_ref = ty::Binder(data.trait_ref.clone()); + let projection_trait_ref = ty::Binder(data.trait_ref(self)); let is_supertrait_of_current_trait = supertraits.as_ref().unwrap().contains(&projection_trait_ref); diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs index 14b6d4605e89f..b5284852747f9 100644 --- a/src/librustc/traits/project.rs +++ b/src/librustc/traits/project.rs @@ -365,9 +365,7 @@ pub fn normalize_projection_type<'a, 'b, 'gcx, 'tcx>( // information is available. let tcx = selcx.infcx().tcx; - let def_id = tcx.associated_items(projection_ty.trait_ref.def_id).find(|i| - i.name == projection_ty.item_name(tcx) && i.kind == ty::AssociatedKind::Type - ).map(|i| i.def_id).unwrap(); + let def_id = projection_ty.item_def_id; let ty_var = selcx.infcx().next_ty_var( TypeVariableOrigin::NormalizeProjectionType(tcx.def_span(def_id))); let projection = ty::Binder(ty::ProjectionPredicate { @@ -447,8 +445,8 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>( // normalization. In that case, I think we will want this code: // // ``` - // let ty = selcx.tcx().mk_projection(projection_ty.trait_ref, - // projection_ty.item_name(tcx); + // let ty = selcx.tcx().mk_projection(projection_ty.item_def_id, + // projection_ty.substs; // return Some(NormalizedTy { value: v, obligations: vec![] }); // ``` @@ -585,15 +583,13 @@ fn normalize_to_error<'a, 'gcx, 'tcx>(selcx: &mut SelectionContext<'a, 'gcx, 'tc depth: usize) -> NormalizedTy<'tcx> { - let trait_ref = projection_ty.trait_ref.to_poly_trait_ref(); + let trait_ref = projection_ty.trait_ref(selcx.tcx()).to_poly_trait_ref(); let trait_obligation = Obligation { cause, recursion_depth: depth, param_env, predicate: trait_ref.to_predicate() }; let tcx = selcx.infcx().tcx; - let def_id = tcx.associated_items(projection_ty.trait_ref.def_id).find(|i| - i.name == projection_ty.item_name(tcx) && i.kind == ty::AssociatedKind::Type - ).map(|i| i.def_id).unwrap(); + let def_id = projection_ty.item_def_id; let new_value = selcx.infcx().next_ty_var( TypeVariableOrigin::NormalizeProjectionType(tcx.def_span(def_id))); Normalized { @@ -654,7 +650,7 @@ fn project_type<'cx, 'gcx, 'tcx>( selcx.infcx().report_overflow_error(&obligation, true); } - let obligation_trait_ref = &obligation.predicate.trait_ref; + let obligation_trait_ref = &obligation.predicate.trait_ref(selcx.tcx()); debug!("project: obligation_trait_ref={:?}", obligation_trait_ref); @@ -743,12 +739,10 @@ fn project_type<'cx, 'gcx, 'tcx>( &obligation_trait_ref, candidate))) } - None => { - Ok(ProjectedTy::NoProgress( - selcx.tcx().mk_projection( - obligation.predicate.trait_ref.clone(), - obligation.predicate.item_name(selcx.tcx())))) - } + None => Ok(ProjectedTy::NoProgress( + selcx.tcx().mk_projection( + obligation.predicate.item_def_id, + obligation.predicate.substs))) } } @@ -788,10 +782,11 @@ fn assemble_candidates_from_trait_def<'cx, 'gcx, 'tcx>( { debug!("assemble_candidates_from_trait_def(..)"); + let tcx = selcx.tcx(); // Check whether the self-type is itself a projection. let (def_id, substs) = match obligation_trait_ref.self_ty().sty { ty::TyProjection(ref data) => { - (data.trait_ref.def_id, data.trait_ref.substs) + (data.trait_ref(tcx).def_id, data.substs) } ty::TyAnon(def_id, substs) => (def_id, substs), ty::TyInfer(ty::TyVar(_)) => { @@ -804,9 +799,9 @@ fn assemble_candidates_from_trait_def<'cx, 'gcx, 'tcx>( }; // If so, extract what we know from the trait and try to come up with a good answer. - let trait_predicates = selcx.tcx().predicates_of(def_id); - let bounds = trait_predicates.instantiate(selcx.tcx(), substs); - let bounds = elaborate_predicates(selcx.tcx(), bounds.predicates); + let trait_predicates = tcx.predicates_of(def_id); + let bounds = trait_predicates.instantiate(tcx, substs); + let bounds = elaborate_predicates(tcx, bounds.predicates); assemble_candidates_from_predicates(selcx, obligation, obligation_trait_ref, @@ -832,12 +827,12 @@ fn assemble_candidates_from_predicates<'cx, 'gcx, 'tcx, I>( predicate); match predicate { ty::Predicate::Projection(ref data) => { - let tcx = selcx.tcx(); - let same_name = data.item_name(tcx) == obligation.predicate.item_name(tcx); + let same_def_id = + data.0.projection_ty.item_def_id == obligation.predicate.item_def_id; - let is_match = same_name && infcx.probe(|_| { + let is_match = same_def_id && infcx.probe(|_| { let data_poly_trait_ref = - data.to_poly_trait_ref(); + data.to_poly_trait_ref(infcx.tcx); let obligation_poly_trait_ref = obligation_trait_ref.to_poly_trait_ref(); infcx.at(&obligation.cause, obligation.param_env) @@ -850,8 +845,8 @@ fn assemble_candidates_from_predicates<'cx, 'gcx, 'tcx, I>( }); debug!("assemble_candidates_from_predicates: candidate={:?} \ - is_match={} same_name={}", - data, is_match, same_name); + is_match={} same_def_id={}", + data, is_match, same_def_id); if is_match { candidate_set.vec.push(ctor(data.clone())); @@ -916,9 +911,10 @@ fn assemble_candidates_from_impls<'cx, 'gcx, 'tcx>( // In either case, we handle this by not adding a // candidate for an impl if it contains a `default` // type. + let item_name = selcx.tcx().associated_item(obligation.predicate.item_def_id).name; let node_item = assoc_ty_def(selcx, impl_data.impl_def_id, - obligation.predicate.item_name(selcx.tcx())); + item_name); let is_default = if node_item.node.is_from_trait() { // If true, the impl inherited a `type Foo = Bar` @@ -1091,10 +1087,9 @@ fn confirm_object_candidate<'cx, 'gcx, 'tcx>( // select only those projections that are actually projecting an // item with the correct name - let tcx = selcx.tcx(); let env_predicates = env_predicates.filter_map(|p| match p { ty::Predicate::Projection(data) => - if data.item_name(tcx) == obligation.predicate.item_name(tcx) { + if data.0.projection_ty.item_def_id == obligation.predicate.item_def_id { Some(data) } else { None @@ -1104,7 +1099,7 @@ fn confirm_object_candidate<'cx, 'gcx, 'tcx>( // select those with a relevant trait-ref let mut env_predicates = env_predicates.filter(|data| { - let data_poly_trait_ref = data.to_poly_trait_ref(); + let data_poly_trait_ref = data.to_poly_trait_ref(selcx.tcx()); let obligation_poly_trait_ref = obligation_trait_ref.to_poly_trait_ref(); selcx.infcx().probe(|_| { selcx.infcx().at(&obligation.cause, obligation.param_env) @@ -1202,7 +1197,7 @@ fn confirm_callable_candidate<'cx, 'gcx, 'tcx>( // Note: we unwrap the binder here but re-create it below (1) let ty::Binder((trait_ref, ret_type)) = tcx.closure_trait_ref_and_return_type(fn_once_def_id, - obligation.predicate.trait_ref.self_ty(), + obligation.predicate.self_ty(), fn_sig, flag); @@ -1227,7 +1222,7 @@ fn confirm_param_env_candidate<'cx, 'gcx, 'tcx>( let infcx = selcx.infcx(); let cause = obligation.cause.clone(); let param_env = obligation.param_env; - let trait_ref = obligation.predicate.trait_ref; + let trait_ref = obligation.predicate.trait_ref(infcx.tcx); match infcx.match_poly_projection_predicate(cause, param_env, poly_projection, trait_ref) { Ok(InferOk { value: ty_match, obligations }) => { Progress { @@ -1258,7 +1253,8 @@ fn confirm_impl_candidate<'cx, 'gcx, 'tcx>( let tcx = selcx.tcx(); let param_env = obligation.param_env; - let assoc_ty = assoc_ty_def(selcx, impl_def_id, obligation.predicate.item_name(tcx)); + let assoc_ty = assoc_ty_def(selcx, impl_def_id, + tcx.associated_item(obligation.predicate.item_def_id).name); let ty = if !assoc_ty.item.defaultness.has_value() { // This means that the impl is missing a definition for the @@ -1267,7 +1263,7 @@ fn confirm_impl_candidate<'cx, 'gcx, 'tcx>( // just return TyError. debug!("confirm_impl_candidate: no associated type {:?} for {:?}", assoc_ty.item.name, - obligation.predicate.trait_ref); + obligation.predicate); tcx.types.err } else { tcx.type_of(assoc_ty.item.def_id) diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 452ad43cd699f..79da04df1df08 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -1335,7 +1335,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { skol_map); let (def_id, substs) = match skol_trait_predicate.trait_ref.self_ty().sty { - ty::TyProjection(ref data) => (data.trait_ref.def_id, data.trait_ref.substs), + ty::TyProjection(ref data) => + (data.trait_ref(self.tcx()).def_id, data.substs), ty::TyAnon(def_id, substs) => (def_id, substs), _ => { span_bug!( diff --git a/src/librustc/traits/trans/mod.rs b/src/librustc/traits/trans/mod.rs index 40bd88d731d3d..9c6047b28b5b0 100644 --- a/src/librustc/traits/trans/mod.rs +++ b/src/librustc/traits/trans/mod.rs @@ -203,9 +203,9 @@ impl<'gcx> DepTrackingMapConfig for ProjectionCache<'gcx> { let def_ids: Vec = key.walk() .filter_map(|t| match t.sty { - ty::TyAdt(adt_def, _) => Some(adt_def.did), - ty::TyProjection(ref proj) => Some(proj.trait_ref.def_id), - _ => None, + ty::TyAdt(adt_def, _) => Some(adt_def.did), + ty::TyProjection(ref proj) => Some(proj.item_def_id), + _ => None, }) .collect(); diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 1f20993f96cfd..c234f43e38779 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -28,7 +28,7 @@ use mir::transform::Passes; use ty::subst::{Kind, Substs}; use ty::ReprOptions; use traits; -use ty::{self, TraitRef, Ty, TypeAndMut}; +use ty::{self, Ty, TypeAndMut}; use ty::{TyS, TypeVariants, Slice}; use ty::{AdtKind, AdtDef, ClosureSubsts, Region}; use hir::FreevarMap; @@ -1387,12 +1387,13 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } pub fn mk_projection(self, - trait_ref: TraitRef<'tcx>, - item_name: Name) + item_def_id: DefId, + substs: &'tcx Substs<'tcx>) -> Ty<'tcx> { - // take a copy of substs so that we own the vectors inside - let inner = ProjectionTy::from_ref_and_name(self, trait_ref, item_name); - self.mk_ty(TyProjection(inner)) + self.mk_ty(TyProjection(ProjectionTy { + item_def_id: item_def_id, + substs: substs, + })) } pub fn mk_closure(self, diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs index d6804976e84c5..3442cf0ef698a 100644 --- a/src/librustc/ty/error.rs +++ b/src/librustc/ty/error.rs @@ -14,7 +14,7 @@ use ty::{self, BoundRegion, DefIdTree, Region, Ty, TyCtxt}; use std::fmt; use syntax::abi; -use syntax::ast::{self, Name}; +use syntax::ast; use errors::DiagnosticBuilder; use syntax_pos::Span; @@ -47,7 +47,7 @@ pub enum TypeError<'tcx> { Traits(ExpectedFound), VariadicMismatch(ExpectedFound), CyclicTy, - ProjectionNameMismatched(ExpectedFound), + ProjectionMismatched(ExpectedFound), ProjectionBoundsLength(ExpectedFound), TyParamDefaultMismatch(ExpectedFound>), ExistentialMismatch(ExpectedFound<&'tcx ty::Slice>>), @@ -154,11 +154,11 @@ impl<'tcx> fmt::Display for TypeError<'tcx> { if values.expected { "variadic" } else { "non-variadic" }, if values.found { "variadic" } else { "non-variadic" }) } - ProjectionNameMismatched(ref values) => { + ProjectionMismatched(ref values) => ty::tls::with(|tcx| { write!(f, "expected {}, found {}", - values.expected, - values.found) - } + tcx.item_path_str(values.expected), + tcx.item_path_str(values.found)) + }), ProjectionBoundsLength(ref values) => { write!(f, "expected {} associated type bindings, found {}", values.expected, diff --git a/src/librustc/ty/flags.rs b/src/librustc/ty/flags.rs index d5aa9f55ff0c4..ce2bb23660ce0 100644 --- a/src/librustc/ty/flags.rs +++ b/src/librustc/ty/flags.rs @@ -193,12 +193,12 @@ impl FlagComputation { } fn add_existential_projection(&mut self, projection: &ty::ExistentialProjection) { - self.add_substs(projection.trait_ref.substs); + self.add_substs(projection.substs); self.add_ty(projection.ty); } fn add_projection_ty(&mut self, projection_ty: &ty::ProjectionTy) { - self.add_substs(projection_ty.trait_ref.substs); + self.add_substs(projection_ty.substs); } fn add_substs(&mut self, substs: &Substs) { diff --git a/src/librustc/ty/fold.rs b/src/librustc/ty/fold.rs index 66868040925e1..a1cd92c760915 100644 --- a/src/librustc/ty/fold.rs +++ b/src/librustc/ty/fold.rs @@ -150,10 +150,6 @@ pub trait TypeVisitor<'tcx> : Sized { t.super_visit_with(self) } - fn visit_trait_ref(&mut self, trait_ref: ty::TraitRef<'tcx>) -> bool { - trait_ref.super_visit_with(self) - } - fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool { r.super_visit_with(self) } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 0ce91b33c510d..3f1302e72e974 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -1030,8 +1030,13 @@ pub struct ProjectionPredicate<'tcx> { pub type PolyProjectionPredicate<'tcx> = Binder>; impl<'tcx> PolyProjectionPredicate<'tcx> { - pub fn item_name(&self, tcx: TyCtxt) -> Name { - self.0.projection_ty.item_name(tcx) // safe to skip the binder to access a name + pub fn to_poly_trait_ref(&self, tcx: TyCtxt) -> PolyTraitRef<'tcx> { + // Note: unlike with TraitRef::to_poly_trait_ref(), + // self.0.trait_ref is permitted to have escaping regions. + // This is because here `self` has a `Binder` and so does our + // return value, so we are preserving the number of binding + // levels. + ty::Binder(self.0.projection_ty.trait_ref(tcx)) } } @@ -1052,17 +1057,6 @@ impl<'tcx> ToPolyTraitRef<'tcx> for PolyTraitPredicate<'tcx> { } } -impl<'tcx> ToPolyTraitRef<'tcx> for PolyProjectionPredicate<'tcx> { - fn to_poly_trait_ref(&self) -> PolyTraitRef<'tcx> { - // Note: unlike with TraitRef::to_poly_trait_ref(), - // self.0.trait_ref is permitted to have escaping regions. - // This is because here `self` has a `Binder` and so does our - // return value, so we are preserving the number of binding - // levels. - ty::Binder(self.0.projection_ty.trait_ref) - } -} - pub trait ToPredicate<'tcx> { fn to_predicate(&self) -> Predicate<'tcx>; } @@ -1132,8 +1126,7 @@ impl<'tcx> Predicate<'tcx> { vec![] } ty::Predicate::Projection(ref data) => { - let trait_inputs = data.0.projection_ty.trait_ref.input_types(); - trait_inputs.chain(Some(data.0.ty)).collect() + data.0.projection_ty.substs.types().chain(Some(data.0.ty)).collect() } ty::Predicate::WellFormed(data) => { vec![data] diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs index 7710cc965c8f0..0d9ef8196c794 100644 --- a/src/librustc/ty/relate.rs +++ b/src/librustc/ty/relate.rs @@ -225,13 +225,15 @@ impl<'tcx> Relate<'tcx> for ty::ProjectionTy<'tcx> { -> RelateResult<'tcx, ty::ProjectionTy<'tcx>> where R: TypeRelation<'a, 'gcx, 'tcx>, 'gcx: 'a+'tcx, 'tcx: 'a { - let tcx = relation.tcx(); - if a.item_name(tcx) != b.item_name(tcx) { - Err(TypeError::ProjectionNameMismatched( - expected_found(relation, &a.item_name(tcx), &b.item_name(tcx)))) + if a.item_def_id != b.item_def_id { + Err(TypeError::ProjectionMismatched( + expected_found(relation, &a.item_def_id, &b.item_def_id))) } else { - let trait_ref = relation.relate(&a.trait_ref, &b.trait_ref)?; - Ok(ty::ProjectionTy::from_ref_and_name(tcx, trait_ref, a.item_name(tcx))) + let substs = relation.relate(&a.substs, &b.substs)?; + Ok(ty::ProjectionTy { + item_def_id: a.item_def_id, + substs: &substs, + }) } } } @@ -243,15 +245,15 @@ impl<'tcx> Relate<'tcx> for ty::ExistentialProjection<'tcx> { -> RelateResult<'tcx, ty::ExistentialProjection<'tcx>> where R: TypeRelation<'a, 'gcx, 'tcx>, 'gcx: 'a+'tcx, 'tcx: 'a { - if a.item_name != b.item_name { - Err(TypeError::ProjectionNameMismatched( - expected_found(relation, &a.item_name, &b.item_name))) + if a.item_def_id != b.item_def_id { + Err(TypeError::ProjectionMismatched( + expected_found(relation, &a.item_def_id, &b.item_def_id))) } else { - let trait_ref = relation.relate(&a.trait_ref, &b.trait_ref)?; let ty = relation.relate(&a.ty, &b.ty)?; + let substs = relation.relate(&a.substs, &b.substs)?; Ok(ty::ExistentialProjection { - trait_ref, - item_name: a.item_name, + item_def_id: a.item_def_id, + substs: substs, ty, }) } @@ -456,7 +458,7 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R, (&ty::TyProjection(ref a_data), &ty::TyProjection(ref b_data)) => { let projection_ty = relation.relate(a_data, b_data)?; - Ok(tcx.mk_projection(projection_ty.trait_ref, projection_ty.item_name(tcx))) + Ok(tcx.mk_projection(projection_ty.item_def_id, projection_ty.substs)) } (&ty::TyAnon(a_def_id, a_substs), &ty::TyAnon(b_def_id, b_substs)) diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index c9b3d038c0774..b81bd595e25b0 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -134,8 +134,11 @@ impl<'a, 'tcx> Lift<'tcx> for ty::ProjectionTy<'a> { type Lifted = ty::ProjectionTy<'tcx>; fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option> { - tcx.lift(&self.trait_ref).map(|trait_ref| { - ty::ProjectionTy::from_ref_and_name(tcx, trait_ref, self.item_name(tcx)) + tcx.lift(&self.substs).map(|substs| { + ty::ProjectionTy { + item_def_id: self.item_def_id, + substs: substs, + } }) } } @@ -156,11 +159,11 @@ impl<'a, 'tcx> Lift<'tcx> for ty::ProjectionPredicate<'a> { impl<'a, 'tcx> Lift<'tcx> for ty::ExistentialProjection<'a> { type Lifted = ty::ExistentialProjection<'tcx>; fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option { - tcx.lift(&(self.trait_ref, self.ty)).map(|(trait_ref, ty)| { + tcx.lift(&self.substs).map(|substs| { ty::ExistentialProjection { - trait_ref, - item_name: self.item_name, - ty, + substs, + ty: tcx.lift(&self.ty).expect("type must lift when substs do"), + item_def_id: self.item_def_id, } }) } @@ -356,7 +359,7 @@ impl<'a, 'tcx> Lift<'tcx> for ty::error::TypeError<'a> { Traits(x) => Traits(x), VariadicMismatch(x) => VariadicMismatch(x), CyclicTy => CyclicTy, - ProjectionNameMismatched(x) => ProjectionNameMismatched(x), + ProjectionMismatched(x) => ProjectionMismatched(x), ProjectionBoundsLength(x) => ProjectionBoundsLength(x), Sorts(ref x) => return tcx.lift(x).map(Sorts), @@ -621,10 +624,6 @@ impl<'tcx> TypeFoldable<'tcx> for ty::TraitRef<'tcx> { fn super_visit_with>(&self, visitor: &mut V) -> bool { self.substs.visit_with(visitor) } - - fn visit_with>(&self, visitor: &mut V) -> bool { - visitor.visit_trait_ref(*self) - } } impl<'tcx> TypeFoldable<'tcx> for ty::ExistentialTraitRef<'tcx> { @@ -847,27 +846,27 @@ impl<'tcx> TypeFoldable<'tcx> for ty::ProjectionPredicate<'tcx> { impl<'tcx> TypeFoldable<'tcx> for ty::ExistentialProjection<'tcx> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { ty::ExistentialProjection { - trait_ref: self.trait_ref.fold_with(folder), - item_name: self.item_name, ty: self.ty.fold_with(folder), + substs: self.substs.fold_with(folder), + item_def_id: self.item_def_id, } } fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.trait_ref.visit_with(visitor) || self.ty.visit_with(visitor) + self.substs.visit_with(visitor) || self.ty.visit_with(visitor) } } impl<'tcx> TypeFoldable<'tcx> for ty::ProjectionTy<'tcx> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { ty::ProjectionTy { - trait_ref: self.trait_ref.fold_with(folder), + substs: self.substs.fold_with(folder), item_def_id: self.item_def_id, } } fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.trait_ref.visit_with(visitor) + self.substs.visit_with(visitor) } } @@ -1018,7 +1017,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::error::TypeError<'tcx> { Traits(x) => Traits(x), VariadicMismatch(x) => VariadicMismatch(x), CyclicTy => CyclicTy, - ProjectionNameMismatched(x) => ProjectionNameMismatched(x), + ProjectionMismatched(x) => ProjectionMismatched(x), ProjectionBoundsLength(x) => ProjectionBoundsLength(x), Sorts(x) => Sorts(x.fold_with(folder)), TyParamDefaultMismatch(ref x) => TyParamDefaultMismatch(x.fold_with(folder)), @@ -1054,7 +1053,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::error::TypeError<'tcx> { Traits(_) | VariadicMismatch(_) | CyclicTy | - ProjectionNameMismatched(_) | + ProjectionMismatched(_) | ProjectionBoundsLength(_) => false, } } diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index ee6c7576aa276..5f89714b33fda 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -11,7 +11,6 @@ //! This module contains TypeVariants and its major components use hir::def_id::DefId; -use hir::map::DefPathHash; use middle::region; use ty::subst::{Substs, Subst}; @@ -24,7 +23,7 @@ use std::iter; use std::cmp::Ordering; use syntax::abi; use syntax::ast::{self, Name}; -use syntax::symbol::{keywords, InternedString}; +use syntax::symbol::keywords; use util::nodemap::FxHashMap; use serialize; @@ -291,7 +290,8 @@ impl<'a, 'gcx, 'tcx> ExistentialPredicate<'tcx> { use self::ExistentialPredicate::*; match (*self, *other) { (Trait(_), Trait(_)) => Ordering::Equal, - (Projection(ref a), Projection(ref b)) => a.sort_key(tcx).cmp(&b.sort_key(tcx)), + (Projection(ref a), Projection(ref b)) => + tcx.def_path_hash(a.item_def_id).cmp(&tcx.def_path_hash(b.item_def_id)), (AutoTrait(ref a), AutoTrait(ref b)) => tcx.trait_def(*a).def_path_hash.cmp(&tcx.trait_def(*b).def_path_hash), (Trait(_), _) => Ordering::Less, @@ -551,8 +551,8 @@ impl fmt::Debug for TypeFlags { /// form this would be written `>::N`. #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] pub struct ProjectionTy<'tcx> { - /// The trait reference `T as Trait<..>`. - pub trait_ref: ty::TraitRef<'tcx>, + /// The parameters of the associated item. + pub substs: &'tcx Substs<'tcx>, /// The DefId of the TraitItem for the associated type N. /// @@ -568,16 +568,28 @@ impl<'a, 'tcx> ProjectionTy<'tcx> { tcx: TyCtxt, trait_ref: ty::TraitRef<'tcx>, item_name: Name ) -> ProjectionTy<'tcx> { let item_def_id = tcx.associated_items(trait_ref.def_id).find( - |item| item.name == item_name).unwrap().def_id; + |item| item.name == item_name && item.kind == ty::AssociatedKind::Type + ).unwrap().def_id; ProjectionTy { - trait_ref, + substs: trait_ref.substs, item_def_id, } } - pub fn item_name(self, tcx: TyCtxt) -> Name { - tcx.associated_item(self.item_def_id).name + /// Extracts the underlying trait reference from this projection. + /// For example, if this is a projection of `::Item`, + /// then this function would return a `T: Iterator` trait reference. + pub fn trait_ref(&self, tcx: TyCtxt) -> ty::TraitRef<'tcx> { + let def_id = tcx.associated_item(self.item_def_id).container.id(); + ty::TraitRef { + def_id: def_id, + substs: self.substs, + } + } + + pub fn self_ty(&self) -> Ty<'tcx> { + self.substs.type_at(0) } } @@ -861,29 +873,24 @@ pub enum InferTy { /// A `ProjectionPredicate` for an `ExistentialTraitRef`. #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] pub struct ExistentialProjection<'tcx> { - pub trait_ref: ExistentialTraitRef<'tcx>, - pub item_name: Name, + pub item_def_id: DefId, + pub substs: &'tcx Substs<'tcx>, pub ty: Ty<'tcx>, } pub type PolyExistentialProjection<'tcx> = Binder>; impl<'a, 'tcx, 'gcx> ExistentialProjection<'tcx> { - pub fn item_name(&self) -> Name { - self.item_name // safe to skip the binder to access a name - } - - pub fn sort_key(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> (DefPathHash, InternedString) { - // We want something here that is stable across crate boundaries. - // The DefId isn't but the `deterministic_hash` of the corresponding - // DefPath is. - let trait_def = tcx.trait_def(self.trait_ref.def_id); - let def_path_hash = trait_def.def_path_hash; - - // An `ast::Name` is also not stable (it's just an index into an - // interning table), so map to the corresponding `InternedString`. - let item_name = self.item_name.as_str(); - (def_path_hash, item_name) + /// Extracts the underlying existential trait reference from this projection. + /// For example, if this is a projection of `exists T. ::Item == X`, + /// then this function would return a `exists T. T: Iterator` existential trait + /// reference. + pub fn trait_ref(&self, tcx: TyCtxt) -> ty::ExistentialTraitRef<'tcx> { + let def_id = tcx.associated_item(self.item_def_id).container.id(); + ty::ExistentialTraitRef{ + def_id: def_id, + substs: self.substs, + } } pub fn with_self_ty(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, @@ -894,24 +901,17 @@ impl<'a, 'tcx, 'gcx> ExistentialProjection<'tcx> { assert!(!self_ty.has_escaping_regions()); ty::ProjectionPredicate { - projection_ty: ty::ProjectionTy::from_ref_and_name( - tcx, - self.trait_ref.with_self_ty(tcx, self_ty), - self.item_name), + projection_ty: ty::ProjectionTy { + item_def_id: self.item_def_id, + substs: tcx.mk_substs( + iter::once(Kind::from(self_ty)).chain(self.substs.iter().cloned())), + }, ty: self.ty, } } } impl<'a, 'tcx, 'gcx> PolyExistentialProjection<'tcx> { - pub fn item_name(&self) -> Name { - self.skip_binder().item_name() - } - - pub fn sort_key(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> (DefPathHash, InternedString) { - self.skip_binder().sort_key(tcx) - } - pub fn with_self_ty(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, self_ty: Ty<'tcx>) -> ty::PolyProjectionPredicate<'tcx> { self.map_bound(|p| p.with_self_ty(tcx, self_ty)) @@ -1397,7 +1397,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { substs.substs.regions().collect() } TyProjection(ref data) => { - data.trait_ref.substs.regions().collect() + data.substs.regions().collect() } TyFnDef(..) | TyFnPtr(_) | diff --git a/src/librustc/ty/walk.rs b/src/librustc/ty/walk.rs index 71844abfe534c..a7f0bafe9b67d 100644 --- a/src/librustc/ty/walk.rs +++ b/src/librustc/ty/walk.rs @@ -90,14 +90,14 @@ fn push_subtypes<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent_ty: Ty<'tcx>) { stack.push(mt.ty); } ty::TyProjection(ref data) => { - stack.extend(data.trait_ref.substs.types().rev()); + stack.extend(data.substs.types().rev()); } ty::TyDynamic(ref obj, ..) => { stack.extend(obj.iter().rev().flat_map(|predicate| { let (substs, opt_ty) = match *predicate.skip_binder() { ty::ExistentialPredicate::Trait(tr) => (tr.substs, None), ty::ExistentialPredicate::Projection(p) => - (p.trait_ref.substs, Some(p.ty)), + (p.substs, Some(p.ty)), ty::ExistentialPredicate::AutoTrait(_) => // Empty iterator (ty::Substs::empty(), None), diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs index 91bc56155969a..c24c583ad1e19 100644 --- a/src/librustc/ty/wf.rs +++ b/src/librustc/ty/wf.rs @@ -155,11 +155,11 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { // A projection is well-formed if (a) the trait ref itself is // WF and (b) the trait-ref holds. (It may also be // normalizable and be WF that way.) - - self.compute_trait_ref(&data.trait_ref); + let trait_ref = data.trait_ref(self.infcx.tcx); + self.compute_trait_ref(&trait_ref); if !data.has_escaping_regions() { - let predicate = data.trait_ref.to_predicate(); + let predicate = trait_ref.to_predicate(); let cause = self.cause(traits::ProjectionWf(data)); self.out.push(traits::Obligation::new(cause, self.param_env, predicate)); } diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index eb6bffc29c561..d9c99ccd50843 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -224,7 +224,7 @@ pub fn parameterized(f: &mut fmt::Formatter, start_or_continue(f, "<", ", ")?; ty::tls::with(|tcx| write!(f, "{}={}", - projection.projection_ty.item_name(tcx), + tcx.associated_item(projection.projection_ty.item_def_id).name, projection.ty) )?; } @@ -958,9 +958,14 @@ impl<'tcx> fmt::Display for ty::ProjectionPredicate<'tcx> { impl<'tcx> fmt::Display for ty::ProjectionTy<'tcx> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let item_name = ty::tls::with(|tcx| self.item_name(tcx)); + // FIXME(tschottdorf): use something like + // parameterized(f, self.substs, self.item_def_id, &[]) + // (which currently ICEs). + let (trait_ref, item_name) = ty::tls::with(|tcx| + (self.trait_ref(tcx), tcx.associated_item(self.item_def_id).name) + ); write!(f, "{:?}::{}", - self.trait_ref, + trait_ref, item_name) } } diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index 4a74a9e524d0c..64af24d92eecb 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -89,7 +89,7 @@ impl<'a, 'tcx> EmbargoVisitor<'a, 'tcx> { ty::TyAdt(adt, _) => adt.did, ty::TyDynamic(ref obj, ..) if obj.principal().is_some() => obj.principal().unwrap().def_id(), - ty::TyProjection(ref proj) => proj.trait_ref.def_id, + ty::TyProjection(ref proj) => proj.trait_ref(self.tcx).def_id, _ => return Some(AccessLevel::Public) }; if let Some(node_id) = self.tcx.hir.as_local_node_id(ty_def_id) { @@ -395,7 +395,22 @@ impl<'b, 'a, 'tcx> ReachEverythingInTheInterfaceVisitor<'b, 'a, 'tcx> { } fn predicates(&mut self) -> &mut Self { - self.ev.tcx.predicates_of(self.item_def_id).visit_with(self); + let predicates = self.ev.tcx.predicates_of(self.item_def_id); + for predicate in &predicates.predicates { + predicate.visit_with(self); + match predicate { + &ty::Predicate::Trait(poly_predicate) => { + self.check_trait_ref(poly_predicate.skip_binder().trait_ref); + }, + &ty::Predicate::Projection(poly_predicate) => { + let tcx = self.ev.tcx; + self.check_trait_ref( + poly_predicate.skip_binder().projection_ty.trait_ref(tcx) + ); + }, + _ => (), + }; + } self } @@ -411,9 +426,19 @@ impl<'b, 'a, 'tcx> ReachEverythingInTheInterfaceVisitor<'b, 'a, 'tcx> { } fn impl_trait_ref(&mut self) -> &mut Self { - self.ev.tcx.impl_trait_ref(self.item_def_id).visit_with(self); + if let Some(impl_trait_ref) = self.ev.tcx.impl_trait_ref(self.item_def_id) { + self.check_trait_ref(impl_trait_ref); + impl_trait_ref.super_visit_with(self); + } self } + + fn check_trait_ref(&mut self, trait_ref: ty::TraitRef<'tcx>) { + if let Some(node_id) = self.ev.tcx.hir.as_local_node_id(trait_ref.def_id) { + let item = self.ev.tcx.hir.expect_item(node_id); + self.ev.update(item.id, Some(AccessLevel::Reachable)); + } + } } impl<'b, 'a, 'tcx> TypeVisitor<'tcx> for ReachEverythingInTheInterfaceVisitor<'b, 'a, 'tcx> { @@ -421,7 +446,7 @@ impl<'b, 'a, 'tcx> TypeVisitor<'tcx> for ReachEverythingInTheInterfaceVisitor<'b let ty_def_id = match ty.sty { ty::TyAdt(adt, _) => Some(adt.did), ty::TyDynamic(ref obj, ..) => obj.principal().map(|p| p.def_id()), - ty::TyProjection(ref proj) => Some(proj.trait_ref.def_id), + ty::TyProjection(ref proj) => Some(proj.item_def_id), ty::TyFnDef(def_id, ..) | ty::TyAnon(def_id, _) => Some(def_id), _ => None @@ -435,15 +460,6 @@ impl<'b, 'a, 'tcx> TypeVisitor<'tcx> for ReachEverythingInTheInterfaceVisitor<'b ty.super_visit_with(self) } - - fn visit_trait_ref(&mut self, trait_ref: ty::TraitRef<'tcx>) -> bool { - if let Some(node_id) = self.ev.tcx.hir.as_local_node_id(trait_ref.def_id) { - let item = self.ev.tcx.hir.expect_item(node_id); - self.ev.update(item.id, Some(AccessLevel::Reachable)); - } - - trait_ref.super_visit_with(self) - } } ////////////////////////////////////////////////////////////////////////////////////// @@ -633,14 +649,42 @@ impl<'a, 'tcx> TypePrivacyVisitor<'a, 'tcx> { } fn predicates(&mut self) -> &mut Self { - self.tcx.predicates_of(self.current_item).visit_with(self); + let predicates = self.tcx.predicates_of(self.current_item); + for predicate in &predicates.predicates { + predicate.visit_with(self); + match predicate { + &ty::Predicate::Trait(poly_predicate) => { + self.check_trait_ref(poly_predicate.skip_binder().trait_ref); + }, + &ty::Predicate::Projection(poly_predicate) => { + let tcx = self.tcx; + self.check_trait_ref( + poly_predicate.skip_binder().projection_ty.trait_ref(tcx) + ); + }, + _ => (), + }; + } self } fn impl_trait_ref(&mut self) -> &mut Self { - self.tcx.impl_trait_ref(self.current_item).visit_with(self); + if let Some(impl_trait_ref) = self.tcx.impl_trait_ref(self.current_item) { + self.check_trait_ref(impl_trait_ref); + } + self.tcx.predicates_of(self.current_item).visit_with(self); self } + + fn check_trait_ref(&mut self, trait_ref: ty::TraitRef<'tcx>) -> bool { + if !self.item_is_accessible(trait_ref.def_id) { + let msg = format!("trait `{}` is private", trait_ref); + self.tcx.sess.span_err(self.span, &msg); + return true; + } + + trait_ref.super_visit_with(self) + } } impl<'a, 'tcx> Visitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> { @@ -817,7 +861,8 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> { let is_private = predicates.skip_binder().iter().any(|predicate| { let def_id = match *predicate { ty::ExistentialPredicate::Trait(trait_ref) => trait_ref.def_id, - ty::ExistentialPredicate::Projection(proj) => proj.trait_ref.def_id, + ty::ExistentialPredicate::Projection(proj) => + proj.trait_ref(self.tcx).def_id, ty::ExistentialPredicate::AutoTrait(def_id) => def_id, }; !self.item_is_accessible(def_id) @@ -828,6 +873,12 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> { return true; } } + ty::TyProjection(ref proj) => { + let tcx = self.tcx; + if self.check_trait_ref(proj.trait_ref(tcx)) { + return true; + } + } ty::TyAnon(def_id, ..) => { for predicate in &self.tcx.predicates_of(def_id).predicates { let trait_ref = match *predicate { @@ -838,7 +889,8 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> { if poly_projection_predicate.skip_binder().ty.visit_with(self) { return true; } - Some(poly_projection_predicate.skip_binder().projection_ty.trait_ref) + Some(poly_projection_predicate.skip_binder() + .projection_ty.trait_ref(self.tcx)) } ty::Predicate::TypeOutlives(..) => None, _ => bug!("unexpected predicate: {:?}", predicate), @@ -863,16 +915,6 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> { ty.super_visit_with(self) } - - fn visit_trait_ref(&mut self, trait_ref: ty::TraitRef<'tcx>) -> bool { - if !self.item_is_accessible(trait_ref.def_id) { - let msg = format!("trait `{}` is private", trait_ref); - self.tcx.sess.span_err(self.span, &msg); - return true; - } - - trait_ref.super_visit_with(self) - } } /////////////////////////////////////////////////////////////////////////////// @@ -1249,7 +1291,22 @@ impl<'a, 'tcx: 'a> SearchInterfaceForPrivateItemsVisitor<'a, 'tcx> { } fn predicates(&mut self) -> &mut Self { - self.tcx.predicates_of(self.item_def_id).visit_with(self); + let predicates = self.tcx.predicates_of(self.item_def_id); + for predicate in &predicates.predicates { + predicate.visit_with(self); + match predicate { + &ty::Predicate::Trait(poly_predicate) => { + self.check_trait_ref(poly_predicate.skip_binder().trait_ref); + }, + &ty::Predicate::Projection(poly_predicate) => { + let tcx = self.tcx; + self.check_trait_ref( + poly_predicate.skip_binder().projection_ty.trait_ref(tcx) + ); + }, + _ => (), + }; + } self } @@ -1265,9 +1322,38 @@ impl<'a, 'tcx: 'a> SearchInterfaceForPrivateItemsVisitor<'a, 'tcx> { } fn impl_trait_ref(&mut self) -> &mut Self { - self.tcx.impl_trait_ref(self.item_def_id).visit_with(self); + if let Some(impl_trait_ref) = self.tcx.impl_trait_ref(self.item_def_id) { + self.check_trait_ref(impl_trait_ref); + impl_trait_ref.super_visit_with(self); + } self } + + fn check_trait_ref(&mut self, trait_ref: ty::TraitRef<'tcx>) { + // Non-local means public (private items can't leave their crate, modulo bugs) + if let Some(node_id) = self.tcx.hir.as_local_node_id(trait_ref.def_id) { + let item = self.tcx.hir.expect_item(node_id); + let vis = ty::Visibility::from_hir(&item.vis, node_id, self.tcx); + if !vis.is_at_least(self.min_visibility, self.tcx) { + self.min_visibility = vis; + } + if !vis.is_at_least(self.required_visibility, self.tcx) { + if self.has_pub_restricted || self.has_old_errors { + struct_span_err!(self.tcx.sess, self.span, E0445, + "private trait `{}` in public interface", trait_ref) + .span_label(self.span, format!( + "private trait can't be public")) + .emit(); + } else { + self.tcx.sess.add_lint(lint::builtin::PRIVATE_IN_PUBLIC, + node_id, + self.span, + format!("private trait `{}` in public \ + interface (error E0445)", trait_ref)); + } + } + } + } } impl<'a, 'tcx: 'a> TypeVisitor<'tcx> for SearchInterfaceForPrivateItemsVisitor<'a, 'tcx> { @@ -1285,8 +1371,8 @@ impl<'a, 'tcx: 'a> TypeVisitor<'tcx> for SearchInterfaceForPrivateItemsVisitor<' // free type aliases, but this isn't done yet. return false; } - - Some(proj.trait_ref.def_id) + let trait_ref = proj.trait_ref(self.tcx); + Some(trait_ref.def_id) } _ => None }; @@ -1317,42 +1403,7 @@ impl<'a, 'tcx: 'a> TypeVisitor<'tcx> for SearchInterfaceForPrivateItemsVisitor<' } } - if let ty::TyProjection(ref proj) = ty.sty { - // Avoid calling `visit_trait_ref` below on the trait, - // as we have already checked the trait itself above. - proj.trait_ref.super_visit_with(self) - } else { - ty.super_visit_with(self) - } - } - - fn visit_trait_ref(&mut self, trait_ref: ty::TraitRef<'tcx>) -> bool { - // Non-local means public (private items can't leave their crate, modulo bugs) - if let Some(node_id) = self.tcx.hir.as_local_node_id(trait_ref.def_id) { - let item = self.tcx.hir.expect_item(node_id); - let vis = ty::Visibility::from_hir(&item.vis, node_id, self.tcx); - - if !vis.is_at_least(self.min_visibility, self.tcx) { - self.min_visibility = vis; - } - if !vis.is_at_least(self.required_visibility, self.tcx) { - if self.has_pub_restricted || self.has_old_errors { - struct_span_err!(self.tcx.sess, self.span, E0445, - "private trait `{}` in public interface", trait_ref) - .span_label(self.span, format!( - "private trait can't be public")) - .emit(); - } else { - self.tcx.sess.add_lint(lint::builtin::PRIVATE_IN_PUBLIC, - node_id, - self.span, - format!("private trait `{}` in public \ - interface (error E0445)", trait_ref)); - } - } - } - - trait_ref.super_visit_with(self) + ty.super_visit_with(self) } } diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index f54973e08975c..ac2baa9e8b1d2 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -608,13 +608,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { hir::QPath::TypeRelative(..) => { let ty = hir_ty_to_ty(self.tcx, ty); if let ty::TyProjection(proj) = ty.sty { - for item in self.tcx.associated_items(proj.trait_ref.def_id) { - if item.kind == ty::AssociatedKind::Type { - if item.name == proj.item_name(self.tcx) { - return HirDef::AssociatedTy(item.def_id); - } - } - } + return HirDef::AssociatedTy(proj.item_def_id); } HirDef::Err } diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs index 200f6dee334ad..8a77b26580999 100644 --- a/src/librustc_trans/trans_item.rs +++ b/src/librustc_trans/trans_item.rs @@ -558,7 +558,7 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> { for projection in projections { let projection = projection.skip_binder(); - let name = &projection.item_name.as_str(); + let name = &self.tcx.associated_item(projection.item_def_id).name.as_str(); output.push_str(name); output.push_str("="); self.push_type_name(projection.ty, output); diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 212461a6d70e2..bb6e478738aa2 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -66,8 +66,8 @@ pub trait AstConv<'gcx, 'tcx> { /// late-bound regions. fn projected_ty_from_poly_trait_ref(&self, span: Span, - poly_trait_ref: ty::PolyTraitRef<'tcx>, - item_name: ast::Name) + item_def_id: DefId, + poly_trait_ref: ty::PolyTraitRef<'tcx>) -> Ty<'tcx>; /// Normalize an associated type coming from the user. @@ -651,11 +651,11 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { }); let existential_projections = projection_bounds.iter().map(|bound| { bound.map_bound(|b| { - let p = b.projection_ty; + let trait_ref = self.trait_ref_to_existential(b.projection_ty.trait_ref(tcx)); ty::ExistentialProjection { - trait_ref: self.trait_ref_to_existential(p.trait_ref), - item_name: p.item_name(tcx), - ty: b.ty + ty: b.ty, + item_def_id: b.projection_ty.item_def_id, + substs: trait_ref.substs, } }) }); @@ -676,22 +676,22 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { for tr in traits::supertraits(tcx, principal) { associated_types.extend(tcx.associated_items(tr.def_id()) .filter(|item| item.kind == ty::AssociatedKind::Type) - .map(|item| (tr.def_id(), item.name))); + .map(|item| item.def_id)); } for projection_bound in &projection_bounds { - let pair = (projection_bound.0.projection_ty.trait_ref.def_id, - projection_bound.0.projection_ty.item_name(tcx)); - associated_types.remove(&pair); + associated_types.remove(&projection_bound.0.projection_ty.item_def_id); } - for (trait_def_id, name) in associated_types { + for item_def_id in associated_types { + let assoc_item = tcx.associated_item(item_def_id); + let trait_def_id = assoc_item.container.id(); struct_span_err!(tcx.sess, span, E0191, "the value of the associated type `{}` (from the trait `{}`) must be specified", - name, + assoc_item.name, tcx.item_path_str(trait_def_id)) .span_label(span, format!( - "missing associated type `{}` value", name)) + "missing associated type `{}` value", assoc_item.name)) .emit(); } @@ -896,11 +896,12 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { }; let trait_did = bound.0.def_id; - let ty = self.projected_ty_from_poly_trait_ref(span, bound, assoc_name); - let ty = self.normalize_ty(span, ty); - let item = tcx.associated_items(trait_did).find(|i| i.name == assoc_name) .expect("missing associated type"); + + let ty = self.projected_ty_from_poly_trait_ref(span, item.def_id, bound); + let ty = self.normalize_ty(span, ty); + let def = Def::AssociatedTy(item.def_id); let def_scope = tcx.adjust(assoc_name, item.container.id(), ref_id).1; if !item.vis.is_accessible_from(def_scope, tcx) { @@ -915,12 +916,13 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { fn qpath_to_ty(&self, span: Span, opt_self_ty: Option>, - trait_def_id: DefId, + item_def_id: DefId, trait_segment: &hir::PathSegment, item_segment: &hir::PathSegment) -> Ty<'tcx> { let tcx = self.tcx(); + let trait_def_id = tcx.parent_def_id(item_def_id).unwrap(); self.prohibit_type_params(slice::ref_slice(item_segment)); @@ -944,7 +946,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { debug!("qpath_to_ty: trait_ref={:?}", trait_ref); - self.normalize_ty(span, tcx.mk_projection(trait_ref, item_segment.name)) + self.normalize_ty(span, tcx.mk_projection(item_def_id, trait_ref.substs)) } pub fn prohibit_type_params(&self, segments: &[hir::PathSegment]) { @@ -1050,10 +1052,9 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { } Def::AssociatedTy(def_id) => { self.prohibit_type_params(&path.segments[..path.segments.len()-2]); - let trait_did = tcx.parent_def_id(def_id).unwrap(); self.qpath_to_ty(span, opt_self_ty, - trait_did, + def_id, &path.segments[path.segments.len()-2], path.segments.last().unwrap()) } diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index f041db43e16d7..802eee91efcf3 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -156,7 +156,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Given a Projection predicate, we can potentially infer // the complete signature. ty::Predicate::Projection(ref proj_predicate) => { - let trait_ref = proj_predicate.to_poly_trait_ref(); + let trait_ref = proj_predicate.to_poly_trait_ref(self.tcx); self.self_type_matches_expected_vid(trait_ref, expected_vid) .and_then(|_| self.deduce_sig_from_projection(proj_predicate)) } @@ -174,7 +174,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { .map(|obligation| &obligation.obligation) .filter_map(|obligation| { let opt_trait_ref = match obligation.predicate { - ty::Predicate::Projection(ref data) => Some(data.to_poly_trait_ref()), + ty::Predicate::Projection(ref data) => Some(data.to_poly_trait_ref(self.tcx)), ty::Predicate::Trait(ref data) => Some(data.to_poly_trait_ref()), ty::Predicate::Equate(..) => None, ty::Predicate::Subtype(..) => None, @@ -211,7 +211,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { debug!("deduce_sig_from_projection({:?})", projection); - let trait_ref = projection.to_poly_trait_ref(); + let trait_ref = projection.to_poly_trait_ref(tcx); if tcx.lang_items.fn_trait_kind(trait_ref.def_id()).is_none() { return None; diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index ee9a347ae9511..dfc5cd00b6eab 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -861,7 +861,10 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { debug!("assemble_projection_candidates: step={:?}", step); let (def_id, substs) = match step.self_ty.sty { - ty::TyProjection(ref data) => (data.trait_ref.def_id, data.trait_ref.substs), + ty::TyProjection(ref data) => { + let trait_ref = data.trait_ref(self.tcx); + (trait_ref.def_id, trait_ref.substs) + }, ty::TyAnon(def_id, substs) => (def_id, substs), _ => continue, }; diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 2634e8fcc006d..6e2c36c86a328 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1620,17 +1620,18 @@ impl<'a, 'gcx, 'tcx> AstConv<'gcx, 'tcx> for FnCtxt<'a, 'gcx, 'tcx> { fn projected_ty_from_poly_trait_ref(&self, span: Span, - poly_trait_ref: ty::PolyTraitRef<'tcx>, - item_name: ast::Name) + item_def_id: DefId, + poly_trait_ref: ty::PolyTraitRef<'tcx>) -> Ty<'tcx> { + let item = self.tcx().associated_item(item_def_id); let (trait_ref, _) = self.replace_late_bound_regions_with_fresh_var( span, - infer::LateBoundRegionConversionTime::AssocTypeProjection(item_name), + infer::LateBoundRegionConversionTime::AssocTypeProjection(item.name), &poly_trait_ref); - self.tcx().mk_projection(trait_ref, item_name) + self.tcx().mk_projection(item_def_id, trait_ref.substs) } fn normalize_ty(&self, span: Span, ty: Ty<'tcx>) -> Ty<'tcx> { diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index 5e79237da69d4..82207428efc4f 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -1595,15 +1595,15 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { // the problem is to add `T: 'r`, which isn't true. So, if there are no // inference variables, we use a verify constraint instead of adding // edges, which winds up enforcing the same condition. - let needs_infer = projection_ty.trait_ref.needs_infer(); + let needs_infer = projection_ty.needs_infer(); if env_bounds.is_empty() && needs_infer { debug!("projection_must_outlive: no declared bounds"); - for component_ty in projection_ty.trait_ref.substs.types() { + for component_ty in projection_ty.substs.types() { self.type_must_outlive(origin.clone(), component_ty, region); } - for r in projection_ty.trait_ref.substs.regions() { + for r in projection_ty.substs.regions() { self.sub_regions(origin.clone(), region, r); } @@ -1621,7 +1621,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { if !env_bounds.is_empty() && env_bounds[1..].iter().all(|b| *b == env_bounds[0]) { let unique_bound = env_bounds[0]; debug!("projection_must_outlive: unique declared bound = {:?}", unique_bound); - if projection_ty.trait_ref.substs.regions().any(|r| env_bounds.contains(&r)) { + if projection_ty.substs.regions().any(|r| env_bounds.contains(&r)) { debug!("projection_must_outlive: unique declared bound appears in trait ref"); self.sub_regions(origin.clone(), region, unique_bound); return; @@ -1691,8 +1691,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { declared_bounds, projection_ty); // see the extensive comment in projection_must_outlive - let item_name = projection_ty.item_name(self.tcx); - let ty = self.tcx.mk_projection(projection_ty.trait_ref, item_name); + let ty = self.tcx.mk_projection(projection_ty.item_def_id, projection_ty.substs); let recursive_bound = self.recursive_type_bound(span, ty); VerifyBound::AnyRegion(declared_bounds).or(recursive_bound) @@ -1758,9 +1757,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { { debug!("projection_bounds(projection_ty={:?})", projection_ty); - let item_name = projection_ty.item_name(self.tcx); - let ty = self.tcx.mk_projection(projection_ty.trait_ref.clone(), - item_name); + let ty = self.tcx.mk_projection(projection_ty.item_def_id, projection_ty.substs); // Say we have a projection `>::SomeType`. We are interested // in looking for a trait definition like: @@ -1772,7 +1769,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { // ``` // // we can thus deduce that `>::SomeType : 'a`. - let trait_predicates = self.tcx.predicates_of(projection_ty.trait_ref.def_id); + let trait_predicates = self.tcx.predicates_of(projection_ty.trait_ref(self.tcx).def_id); assert_eq!(trait_predicates.parent, None); let predicates = trait_predicates.predicates.as_slice().to_vec(); traits::elaborate_predicates(self.tcx, predicates) @@ -1788,7 +1785,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { // apply the substitutions (and normalize any projected types) let outlives = self.instantiate_type_scheme(span, - projection_ty.trait_ref.substs, + projection_ty.substs, &outlives); debug!("projection_bounds: outlives={:?} (2)", @@ -1798,7 +1795,8 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { let (outlives, _) = self.replace_late_bound_regions_with_fresh_var( span, - infer::AssocTypeProjection(projection_ty.item_name(self.tcx)), + infer::AssocTypeProjection( + self.tcx.associated_item(projection_ty.item_def_id).name), &outlives); debug!("projection_bounds: outlives={:?} (3)", diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index cbda1227742ca..69cd141462875 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -508,7 +508,8 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> { .map(|(index, _)| Parameter(index as u32)) .collect(); - identify_constrained_type_params(ty_predicates.predicates.as_slice(), + identify_constrained_type_params(self.tcx, + ty_predicates.predicates.as_slice(), None, &mut constrained_parameters); diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index fd6dda5ccf4a7..002a148c459a3 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -225,12 +225,12 @@ impl<'a, 'tcx> AstConv<'tcx, 'tcx> for ItemCtxt<'a, 'tcx> { fn projected_ty_from_poly_trait_ref(&self, span: Span, - poly_trait_ref: ty::PolyTraitRef<'tcx>, - item_name: ast::Name) + item_def_id: DefId, + poly_trait_ref: ty::PolyTraitRef<'tcx>) -> Ty<'tcx> { if let Some(trait_ref) = self.tcx().no_late_bound_regions(&poly_trait_ref) { - self.tcx().mk_projection(trait_ref, item_name) + self.tcx().mk_projection(item_def_id, trait_ref.substs) } else { // no late-bound regions, we can just ignore the binder span_err!(self.tcx().sess, span, E0212, @@ -1438,7 +1438,10 @@ fn predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } }; - let assoc_ty = tcx.mk_projection(self_trait_ref, trait_item.name); + let assoc_ty = tcx.mk_projection( + tcx.hir.local_def_id(trait_item.id), + self_trait_ref.substs, + ); let bounds = compute_bounds(&ItemCtxt::new(tcx, def_id), assoc_ty, @@ -1458,7 +1461,8 @@ fn predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, if let NodeItem(&Item { node: ItemImpl(..), .. }) = node { let self_ty = tcx.type_of(def_id); let trait_ref = tcx.impl_trait_ref(def_id); - ctp::setup_constraining_predicates(&mut predicates, + ctp::setup_constraining_predicates(tcx, + &mut predicates, trait_ref, &mut ctp::parameters_for_impl(self_ty, trait_ref)); } diff --git a/src/librustc_typeck/constrained_type_params.rs b/src/librustc_typeck/constrained_type_params.rs index ee11b774cf261..7742194dfe6e0 100644 --- a/src/librustc_typeck/constrained_type_params.rs +++ b/src/librustc_typeck/constrained_type_params.rs @@ -86,12 +86,13 @@ impl<'tcx> TypeVisitor<'tcx> for ParameterCollector { } } -pub fn identify_constrained_type_params<'tcx>(predicates: &[ty::Predicate<'tcx>], +pub fn identify_constrained_type_params<'tcx>(tcx: ty::TyCtxt, + predicates: &[ty::Predicate<'tcx>], impl_trait_ref: Option>, input_parameters: &mut FxHashSet) { let mut predicates = predicates.to_owned(); - setup_constraining_predicates(&mut predicates, impl_trait_ref, input_parameters); + setup_constraining_predicates(tcx, &mut predicates, impl_trait_ref, input_parameters); } @@ -135,7 +136,8 @@ pub fn identify_constrained_type_params<'tcx>(predicates: &[ty::Predicate<'tcx>] /// which is determined by 1, which requires `U`, that is determined /// by 0. I should probably pick a less tangled example, but I can't /// think of any. -pub fn setup_constraining_predicates<'tcx>(predicates: &mut [ty::Predicate<'tcx>], +pub fn setup_constraining_predicates<'tcx>(tcx: ty::TyCtxt, + predicates: &mut [ty::Predicate<'tcx>], impl_trait_ref: Option>, input_parameters: &mut FxHashSet) { @@ -175,7 +177,7 @@ pub fn setup_constraining_predicates<'tcx>(predicates: &mut [ty::Predicate<'tcx> // Special case: watch out for some kind of sneaky attempt // to project out an associated type defined by this very // trait. - let unbound_trait_ref = &projection.projection_ty.trait_ref; + let unbound_trait_ref = projection.projection_ty.trait_ref(tcx); if Some(unbound_trait_ref.clone()) == impl_trait_ref { continue; } @@ -185,8 +187,7 @@ pub fn setup_constraining_predicates<'tcx>(predicates: &mut [ty::Predicate<'tcx> // `<::Baz as Iterator>::Output = ::Output` // Then the projection only applies if `T` is known, but it still // does not determine `U`. - - let inputs = parameters_for(&projection.projection_ty.trait_ref, true); + let inputs = parameters_for(&projection.projection_ty.trait_ref(tcx), true); let relies_only_on_inputs = inputs.iter().all(|p| input_parameters.contains(&p)); if !relies_only_on_inputs { continue; diff --git a/src/librustc_typeck/impl_wf_check.rs b/src/librustc_typeck/impl_wf_check.rs index 6b4f08d3d4c8d..14e48b9302964 100644 --- a/src/librustc_typeck/impl_wf_check.rs +++ b/src/librustc_typeck/impl_wf_check.rs @@ -102,7 +102,7 @@ fn enforce_impl_params_are_constrained<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let mut input_parameters = ctp::parameters_for_impl(impl_self_ty, impl_trait_ref); ctp::identify_constrained_type_params( - &impl_predicates.predicates.as_slice(), impl_trait_ref, &mut input_parameters); + tcx, &impl_predicates.predicates.as_slice(), impl_trait_ref, &mut input_parameters); // Disallow ANY unconstrained type parameters. for (ty_param, param) in impl_generics.types.iter().zip(&impl_hir_generics.ty_params) { diff --git a/src/librustc_typeck/variance/constraints.rs b/src/librustc_typeck/variance/constraints.rs index f4963619370e4..284c9c5cfc398 100644 --- a/src/librustc_typeck/variance/constraints.rs +++ b/src/librustc_typeck/variance/constraints.rs @@ -324,7 +324,8 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { } ty::TyProjection(ref data) => { - self.add_constraints_from_trait_ref(current, data.trait_ref, variance); + let tcx = self.tcx(); + self.add_constraints_from_trait_ref(current, data.trait_ref(tcx), variance); } ty::TyAnon(_, substs) => { diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 478e2fc5085d1..9d0b5b41a913f 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -952,15 +952,15 @@ impl<'tcx> Clean for ty::ProjectionPredicate<'tcx> { impl<'tcx> Clean for ty::ProjectionTy<'tcx> { fn clean(&self, cx: &DocContext) -> Type { - let trait_ = match self.trait_ref.clean(cx) { + let trait_ = match self.trait_ref(cx.tcx).clean(cx) { TyParamBound::TraitBound(t, _) => t.trait_, TyParamBound::RegionBound(_) => { panic!("cleaning a trait got a region") } }; Type::QPath { - name: self.item_name(cx.tcx).clean(cx), - self_type: box self.trait_ref.self_ty().clean(cx), + name: cx.tcx.associated_item(self.item_def_id).name.clean(cx), + self_type: box self.self_ty().clean(cx), trait_: box trait_ } } @@ -1784,7 +1784,7 @@ impl Clean for hir::Ty { let mut def = Def::Err; let ty = hir_ty_to_ty(cx.tcx, self); if let ty::TyProjection(proj) = ty.sty { - def = Def::Trait(proj.trait_ref.def_id); + def = Def::Trait(proj.trait_ref(cx.tcx).def_id); } let trait_path = hir::Path { span: self.span, @@ -1901,7 +1901,7 @@ impl<'tcx> Clean for ty::Ty<'tcx> { let mut bindings = vec![]; for ty::Binder(ref pb) in obj.projection_bounds() { bindings.push(TypeBinding { - name: pb.item_name.clean(cx), + name: cx.tcx.associated_item(pb.item_def_id).name.clean(cx), ty: pb.ty.clean(cx) }); }