1 // Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 //! Code for projecting associated types out of trait references.
13 use super::elaborate_predicates;
14 use super::Obligation;
15 use super::ObligationCause;
17 use super::PredicateObligation;
18 use super::SelectionContext;
19 use super::SelectionError;
20 use super::VtableImplData;
23 use middle::subst::Subst;
24 use middle::ty::{self, AsPredicate, ReferencesError, RegionEscape,
25 HasProjectionTypes, ToPolyTraitRef, Ty};
26 use middle::ty_fold::{self, TypeFoldable, TypeFolder};
28 use util::ppaux::Repr;
30 pub type PolyProjectionObligation<'tcx> =
31 Obligation<'tcx, ty::PolyProjectionPredicate<'tcx>>;
33 pub type ProjectionObligation<'tcx> =
34 Obligation<'tcx, ty::ProjectionPredicate<'tcx>>;
36 pub type ProjectionTyObligation<'tcx> =
37 Obligation<'tcx, ty::ProjectionTy<'tcx>>;
39 /// When attempting to resolve `<T as TraitRef>::Name` ...
40 pub enum ProjectionTyError<'tcx> {
41 /// ...we found multiple sources of information and couldn't resolve the ambiguity.
44 /// ...an error occurred matching `T : TraitRef`
45 TraitSelectionError(SelectionError<'tcx>),
49 pub struct MismatchedProjectionTypes<'tcx> {
50 pub err: ty::type_err<'tcx>
53 enum ProjectionTyCandidate<'tcx> {
54 ParamEnv(ty::PolyProjectionPredicate<'tcx>),
55 Impl(VtableImplData<'tcx, PredicateObligation<'tcx>>),
58 struct ProjectionTyCandidateSet<'tcx> {
59 vec: Vec<ProjectionTyCandidate<'tcx>>,
63 pub fn poly_project_and_unify_type<'cx,'tcx>(
64 selcx: &mut SelectionContext<'cx,'tcx>,
65 obligation: &PolyProjectionObligation<'tcx>)
66 -> Result<Option<Vec<PredicateObligation<'tcx>>>, MismatchedProjectionTypes<'tcx>>
68 debug!("poly_project(obligation={})",
69 obligation.repr(selcx.tcx()));
71 let infcx = selcx.infcx();
72 let result = infcx.try(|snapshot| {
73 let (skol_predicate, skol_map) =
74 infcx.skolemize_late_bound_regions(&obligation.predicate, snapshot);
76 let skol_obligation = obligation.with(skol_predicate);
77 match project_and_unify_type(selcx, &skol_obligation) {
78 Ok(Some(obligations)) => {
79 match infcx.leak_check(&skol_map, snapshot) {
80 Ok(()) => Ok(infcx.plug_leaks(skol_map, snapshot, &obligations)),
81 Err(e) => Err(Some(MismatchedProjectionTypes { err: e })),
85 // Signal ambiguity using Err just so that infcx.try()
86 // rolls back the snapshot. We adapt below.
95 // Above, we use Err(None) to signal ambiguity so that the
96 // snapshot will be rolled back. But here, we want to translate to
97 // Ok(None). Kind of weird.
99 Ok(obligations) => Ok(Some(obligations)),
100 Err(None) => Ok(None),
101 Err(Some(e)) => Err(e),
105 /// Compute result of projecting an associated type and unify it with
106 /// `obligation.predicate.ty` (if we can).
107 fn project_and_unify_type<'cx,'tcx>(
108 selcx: &mut SelectionContext<'cx,'tcx>,
109 obligation: &ProjectionObligation<'tcx>)
110 -> Result<Option<Vec<PredicateObligation<'tcx>>>, MismatchedProjectionTypes<'tcx>>
112 debug!("project_and_unify(obligation={})",
113 obligation.repr(selcx.tcx()));
115 let Normalized { value: normalized_ty, obligations } =
116 match opt_normalize_projection_type(selcx,
117 obligation.predicate.projection_ty.clone(),
118 obligation.cause.clone(),
119 obligation.recursion_depth) {
121 None => { return Ok(None); }
124 debug!("project_and_unify_type: normalized_ty={} obligations={}",
125 normalized_ty.repr(selcx.tcx()),
126 obligations.repr(selcx.tcx()));
128 let infcx = selcx.infcx();
129 let origin = infer::RelateOutputImplTypes(obligation.cause.span);
130 match infer::mk_eqty(infcx, true, origin, normalized_ty, obligation.predicate.ty) {
131 Ok(()) => Ok(Some(obligations)),
132 Err(err) => Err(MismatchedProjectionTypes { err: err }),
136 pub fn normalize<'a,'b,'tcx,T>(selcx: &'a mut SelectionContext<'b,'tcx>,
137 cause: ObligationCause<'tcx>,
139 -> Normalized<'tcx, T>
140 where T : TypeFoldable<'tcx> + HasProjectionTypes + Clone + Repr<'tcx>
142 normalize_with_depth(selcx, cause, 0, value)
145 pub fn normalize_with_depth<'a,'b,'tcx,T>(selcx: &'a mut SelectionContext<'b,'tcx>,
146 cause: ObligationCause<'tcx>,
149 -> Normalized<'tcx, T>
150 where T : TypeFoldable<'tcx> + HasProjectionTypes + Clone + Repr<'tcx>
152 let mut normalizer = AssociatedTypeNormalizer::new(selcx, cause, depth);
153 let result = normalizer.fold(value);
156 obligations: normalizer.obligations,
160 struct AssociatedTypeNormalizer<'a,'b:'a,'tcx:'b> {
161 selcx: &'a mut SelectionContext<'b,'tcx>,
162 cause: ObligationCause<'tcx>,
163 obligations: Vec<PredicateObligation<'tcx>>,
167 impl<'a,'b,'tcx> AssociatedTypeNormalizer<'a,'b,'tcx> {
168 fn new(selcx: &'a mut SelectionContext<'b,'tcx>,
169 cause: ObligationCause<'tcx>,
171 -> AssociatedTypeNormalizer<'a,'b,'tcx>
173 AssociatedTypeNormalizer {
181 fn fold<T:TypeFoldable<'tcx> + HasProjectionTypes + Clone>(&mut self, value: &T) -> T {
182 let value = self.selcx.infcx().resolve_type_vars_if_possible(value);
184 if !value.has_projection_types() {
187 value.fold_with(self)
192 impl<'a,'b,'tcx> TypeFolder<'tcx> for AssociatedTypeNormalizer<'a,'b,'tcx> {
193 fn tcx(&self) -> &ty::ctxt<'tcx> {
197 fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
198 // We don't want to normalize associated types that occur inside of region
199 // binders, because they may contain bound regions, and we can't cope with that.
203 // for<'a> fn(<T as Foo<&'a>>::A)
205 // Instead of normalizing `<T as Foo<&'a>>::A` here, we'll
206 // normalize it when we instantiate those bound regions (which
207 // should occur eventually).
210 ty::ty_projection(ref data) if !data.has_escaping_regions() => { // (*)
212 // (*) This is kind of hacky -- we need to be able to
213 // handle normalization within binders because
214 // otherwise we wind up a need to normalize when doing
215 // trait matching (since you can have a trait
216 // obligation like `for<'a> T::B : Fn(&'a int)`), but
217 // we can't normalize with bound regions in scope. So
218 // far now we just ignore binders but only normalize
219 // if all bound regions are gone (and then we still
220 // have to renormalize whenever we instantiate a
221 // binder). It would be better to normalize in a
222 // binding-aware fashion.
224 let Normalized { value: ty, obligations } =
225 normalize_projection_type(self.selcx,
229 self.obligations.extend(obligations.into_iter());
233 ty_fold::super_fold_ty(self, ty)
239 pub struct Normalized<'tcx,T> {
241 pub obligations: Vec<PredicateObligation<'tcx>>,
244 pub type NormalizedTy<'tcx> = Normalized<'tcx, Ty<'tcx>>;
246 pub fn normalize_projection_type<'a,'b,'tcx>(
247 selcx: &'a mut SelectionContext<'b,'tcx>,
248 projection_ty: ty::ProjectionTy<'tcx>,
249 cause: ObligationCause<'tcx>,
251 -> NormalizedTy<'tcx>
253 opt_normalize_projection_type(selcx, projection_ty.clone(), cause.clone(), depth)
254 .unwrap_or_else(move || {
255 // if we bottom out in ambiguity, create a type variable
256 // and a deferred predicate to resolve this when more type
257 // information is available.
259 let ty_var = selcx.infcx().next_ty_var();
260 let projection = ty::Binder(ty::ProjectionPredicate {
261 projection_ty: projection_ty,
264 let obligation = Obligation::with_depth(cause, depth+1, projection.as_predicate());
267 obligations: vec!(obligation)
272 fn opt_normalize_projection_type<'a,'b,'tcx>(
273 selcx: &'a mut SelectionContext<'b,'tcx>,
274 projection_ty: ty::ProjectionTy<'tcx>,
275 cause: ObligationCause<'tcx>,
277 -> Option<NormalizedTy<'tcx>>
279 debug!("normalize_projection_type(\
282 projection_ty.repr(selcx.tcx()),
285 let obligation = Obligation::with_depth(cause.clone(), depth, projection_ty.clone());
286 match project_type(selcx, &obligation) {
287 Ok(ProjectedTy::Progress(projected_ty, mut obligations)) => {
288 // if projection succeeded, then what we get out of this
289 // is also non-normalized (consider: it was derived from
290 // an impl, where-clause etc) and hence we must
293 debug!("normalize_projection_type: projected_ty={} depth={} obligations={}",
294 projected_ty.repr(selcx.tcx()),
296 obligations.repr(selcx.tcx()));
298 if ty::type_has_projection(projected_ty) {
299 let tcx = selcx.tcx();
300 let mut normalizer = AssociatedTypeNormalizer::new(selcx, cause, depth);
301 let normalized_ty = normalizer.fold(&projected_ty);
303 debug!("normalize_projection_type: normalized_ty={} depth={}",
304 normalized_ty.repr(tcx),
307 obligations.extend(normalizer.obligations.into_iter());
309 value: normalized_ty,
310 obligations: obligations,
315 obligations: obligations,
319 Ok(ProjectedTy::NoProgress(projected_ty)) => {
325 Err(ProjectionTyError::TooManyCandidates) => {
328 Err(ProjectionTyError::TraitSelectionError(_)) => {
329 // if we got an error processing the `T as Trait` part,
330 // just return `ty::err` but add the obligation `T :
331 // Trait`, which when processed will cause the error to be
334 Some(normalize_to_error(selcx, projection_ty, cause, depth))
339 /// in various error cases, we just set ty_err and return an obligation
340 /// that, when fulfilled, will lead to an error
341 fn normalize_to_error<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>,
342 projection_ty: ty::ProjectionTy<'tcx>,
343 cause: ObligationCause<'tcx>,
345 -> NormalizedTy<'tcx>
347 let trait_ref = projection_ty.trait_ref.to_poly_trait_ref();
348 let trait_obligation = Obligation { cause: cause,
349 recursion_depth: depth,
350 predicate: trait_ref.as_predicate() };
352 value: selcx.tcx().types.err,
353 obligations: vec!(trait_obligation)
357 enum ProjectedTy<'tcx> {
358 Progress(Ty<'tcx>, Vec<PredicateObligation<'tcx>>),
359 NoProgress(Ty<'tcx>),
362 /// Compute the result of a projection type (if we can).
363 fn project_type<'cx,'tcx>(
364 selcx: &mut SelectionContext<'cx,'tcx>,
365 obligation: &ProjectionTyObligation<'tcx>)
366 -> Result<ProjectedTy<'tcx>, ProjectionTyError<'tcx>>
368 debug!("project(obligation={})",
369 obligation.repr(selcx.tcx()));
371 let recursion_limit = selcx.tcx().sess.recursion_limit.get();
372 if obligation.recursion_depth >= recursion_limit {
373 debug!("project: overflow!");
374 return Err(ProjectionTyError::TraitSelectionError(Overflow));
377 let obligation_trait_ref =
378 selcx.infcx().resolve_type_vars_if_possible(&obligation.predicate.trait_ref);
380 debug!("project: obligation_trait_ref={}", obligation_trait_ref.repr(selcx.tcx()));
382 if obligation_trait_ref.references_error() {
383 return Ok(ProjectedTy::Progress(selcx.tcx().types.err, vec!()));
386 let mut candidates = ProjectionTyCandidateSet {
391 assemble_candidates_from_param_env(selcx,
393 &obligation_trait_ref,
396 if let Err(e) = assemble_candidates_from_impls(selcx,
398 &obligation_trait_ref,
400 return Err(ProjectionTyError::TraitSelectionError(e));
403 debug!("{} candidates, ambiguous={}",
404 candidates.vec.len(),
405 candidates.ambiguous);
407 // We probably need some winnowing logic similar to select here.
409 if candidates.ambiguous || candidates.vec.len() > 1 {
410 return Err(ProjectionTyError::TooManyCandidates);
413 match candidates.vec.pop() {
415 let (ty, obligations) = confirm_candidate(selcx, obligation, candidate);
416 Ok(ProjectedTy::Progress(ty, obligations))
419 Ok(ProjectedTy::NoProgress(ty::mk_projection(selcx.tcx(),
420 obligation.predicate.trait_ref.clone(),
421 obligation.predicate.item_name)))
426 /// The first thing we have to do is scan through the parameter
427 /// environment to see whether there are any projection predicates
428 /// there that can answer this question.
429 fn assemble_candidates_from_param_env<'cx,'tcx>(
430 selcx: &mut SelectionContext<'cx,'tcx>,
431 obligation: &ProjectionTyObligation<'tcx>,
432 obligation_trait_ref: &Rc<ty::TraitRef<'tcx>>,
433 candidate_set: &mut ProjectionTyCandidateSet<'tcx>)
435 let env_predicates = selcx.param_env().caller_bounds.predicates.clone();
436 let env_predicates = env_predicates.iter().cloned().collect();
437 assemble_candidates_from_predicates(selcx, obligation, obligation_trait_ref,
438 candidate_set, env_predicates);
441 fn assemble_candidates_from_predicates<'cx,'tcx>(
442 selcx: &mut SelectionContext<'cx,'tcx>,
443 obligation: &ProjectionTyObligation<'tcx>,
444 obligation_trait_ref: &Rc<ty::TraitRef<'tcx>>,
445 candidate_set: &mut ProjectionTyCandidateSet<'tcx>,
446 env_predicates: Vec<ty::Predicate<'tcx>>)
448 debug!("assemble_candidates_from_predicates(obligation={}, env_predicates={})",
449 obligation.repr(selcx.tcx()),
450 env_predicates.repr(selcx.tcx()));
451 let infcx = selcx.infcx();
452 for predicate in elaborate_predicates(selcx.tcx(), env_predicates) {
454 ty::Predicate::Projection(ref data) => {
455 let is_match = infcx.probe(|_| {
456 let origin = infer::Misc(obligation.cause.span);
457 let obligation_poly_trait_ref =
458 obligation_trait_ref.to_poly_trait_ref();
459 let data_poly_trait_ref =
460 data.to_poly_trait_ref();
461 infcx.sub_poly_trait_refs(false,
463 obligation_poly_trait_ref,
464 data_poly_trait_ref).is_ok()
468 candidate_set.vec.push(
469 ProjectionTyCandidate::ParamEnv(data.clone()));
477 fn assemble_candidates_from_object_type<'cx,'tcx>(
478 selcx: &mut SelectionContext<'cx,'tcx>,
479 obligation: &ProjectionTyObligation<'tcx>,
480 obligation_trait_ref: &Rc<ty::TraitRef<'tcx>>,
481 candidate_set: &mut ProjectionTyCandidateSet<'tcx>,
484 let infcx = selcx.infcx();
485 debug!("assemble_candidates_from_object_type(object_ty={})",
486 object_ty.repr(infcx.tcx));
487 let data = match object_ty.sty {
488 ty::ty_trait(ref data) => data,
490 selcx.tcx().sess.span_bug(
491 obligation.cause.span,
492 format!("assemble_candidates_from_object_type called with non-object: {}",
493 object_ty.repr(selcx.tcx())).as_slice());
496 let projection_bounds = data.projection_bounds_with_self_ty(selcx.tcx(), object_ty);
497 let env_predicates = projection_bounds.iter()
498 .map(|p| p.as_predicate())
500 assemble_candidates_from_predicates(selcx, obligation, obligation_trait_ref,
501 candidate_set, env_predicates)
504 fn assemble_candidates_from_impls<'cx,'tcx>(
505 selcx: &mut SelectionContext<'cx,'tcx>,
506 obligation: &ProjectionTyObligation<'tcx>,
507 obligation_trait_ref: &Rc<ty::TraitRef<'tcx>>,
508 candidate_set: &mut ProjectionTyCandidateSet<'tcx>)
509 -> Result<(), SelectionError<'tcx>>
511 // If we are resolving `<T as TraitRef<...>>::Item == Type`,
512 // start out by selecting the predicate `T as TraitRef<...>`:
513 let poly_trait_ref = obligation_trait_ref.to_poly_trait_ref();
514 let trait_obligation = obligation.with(poly_trait_ref.to_poly_trait_predicate());
515 let vtable = match selcx.select(&trait_obligation) {
516 Ok(Some(vtable)) => vtable,
518 candidate_set.ambiguous = true;
522 debug!("assemble_candidates_from_impls: selection error {}",
523 e.repr(selcx.tcx()));
529 super::VtableImpl(data) => {
530 candidate_set.vec.push(
531 ProjectionTyCandidate::Impl(data));
533 super::VtableObject(data) => {
534 assemble_candidates_from_object_type(
535 selcx, obligation, obligation_trait_ref, candidate_set,
538 super::VtableParam(..) => {
539 // This case tell us nothing about the value of an
540 // associated type. Consider:
543 // trait SomeTrait { type Foo; }
544 // fn foo<T:SomeTrait>(...) { }
547 // If the user writes `<T as SomeTrait>::Foo`, then the `T
548 // : SomeTrait` binding does not help us decide what the
549 // type `Foo` is (at least, not more specifically than
550 // what we already knew).
552 // But wait, you say! What about an example like this:
555 // fn bar<T:SomeTrait<Foo=uint>>(...) { ... }
558 // Doesn't the `T : Sometrait<Foo=uint>` predicate help
559 // resolve `T::Foo`? And of course it does, but in fact
560 // that single predicate is desugared into two predicates
561 // in the compiler: a trait predicate (`T : SomeTrait`) and a
562 // projection. And the projection where clause is handled
563 // in `assemble_candidates_from_param_env`.
565 super::VtableBuiltin(..) |
566 super::VtableUnboxedClosure(..) |
567 super::VtableFnPointer(..) => {
568 // These traits have no associated types.
569 selcx.tcx().sess.span_bug(
570 obligation.cause.span,
571 format!("Cannot project an associated type from `{}`",
572 vtable.repr(selcx.tcx())).as_slice());
579 fn confirm_candidate<'cx,'tcx>(
580 selcx: &mut SelectionContext<'cx,'tcx>,
581 obligation: &ProjectionTyObligation<'tcx>,
582 candidate: ProjectionTyCandidate<'tcx>)
583 -> (Ty<'tcx>, Vec<PredicateObligation<'tcx>>)
585 let infcx = selcx.infcx();
587 debug!("confirm_candidate(candidate={}, obligation={})",
588 candidate.repr(infcx.tcx),
589 obligation.repr(infcx.tcx));
592 ProjectionTyCandidate::ParamEnv(poly_projection) => {
594 infcx.replace_late_bound_regions_with_fresh_var(
595 obligation.cause.span,
596 infer::LateBoundRegionConversionTime::HigherRankedType,
599 assert_eq!(projection.projection_ty.item_name,
600 obligation.predicate.item_name);
602 let origin = infer::RelateOutputImplTypes(obligation.cause.span);
603 match infcx.sub_trait_refs(false,
605 obligation.predicate.trait_ref.clone(),
606 projection.projection_ty.trait_ref.clone()) {
609 selcx.tcx().sess.span_bug(
610 obligation.cause.span,
611 format!("Failed to unify `{}` and `{}` in projection: {}",
612 obligation.repr(selcx.tcx()),
613 projection.repr(selcx.tcx()),
614 ty::type_err_to_str(selcx.tcx(), &e)).as_slice());
618 (projection.ty, vec!())
621 ProjectionTyCandidate::Impl(impl_vtable) => {
622 // there don't seem to be nicer accessors to these:
623 let impl_items_map = selcx.tcx().impl_items.borrow();
624 let impl_or_trait_items_map = selcx.tcx().impl_or_trait_items.borrow();
626 let impl_items = &impl_items_map[impl_vtable.impl_def_id];
627 let mut impl_ty = None;
628 for impl_item in impl_items.iter() {
629 let assoc_type = match impl_or_trait_items_map[impl_item.def_id()] {
630 ty::TypeTraitItem(ref assoc_type) => assoc_type.clone(),
631 ty::MethodTraitItem(..) => { continue; }
634 if assoc_type.name != obligation.predicate.item_name {
638 let impl_poly_ty = ty::lookup_item_type(selcx.tcx(), assoc_type.def_id);
639 impl_ty = Some(impl_poly_ty.ty.subst(selcx.tcx(), &impl_vtable.substs));
644 Some(ty) => (ty, impl_vtable.nested.to_vec()),
646 // This means that the impl is missing a
647 // definition for the associated type. This error
648 // ought to be reported by the type checker method
649 // `check_impl_items_against_trait`, so here we
650 // just return ty_err.
651 (selcx.tcx().types.err, vec!())
658 impl<'tcx> Repr<'tcx> for ProjectionTyError<'tcx> {
659 fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
661 ProjectionTyError::TooManyCandidates =>
662 format!("NoCandidate"),
663 ProjectionTyError::TraitSelectionError(ref e) =>
664 format!("TraitSelectionError({})", e.repr(tcx)),
669 impl<'tcx> Repr<'tcx> for ProjectionTyCandidate<'tcx> {
670 fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
672 ProjectionTyCandidate::ParamEnv(ref data) =>
673 format!("ParamEnv({})", data.repr(tcx)),
674 ProjectionTyCandidate::Impl(ref data) =>
675 format!("Impl({})", data.repr(tcx))
680 impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Normalized<'tcx, T> {
681 fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Normalized<'tcx, T> {
683 value: self.value.fold_with(folder),
684 obligations: self.obligations.fold_with(folder),
689 impl<'tcx, T:Repr<'tcx>> Repr<'tcx> for Normalized<'tcx, T> {
690 fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
691 format!("Normalized({},{})",
692 self.value.repr(tcx),
693 self.obligations.repr(tcx))