diff --git a/src/librustc/middle/traits/fulfill.rs b/src/librustc/middle/traits/fulfill.rs index b55504da237..7ec221fcfa9 100644 --- a/src/librustc/middle/traits/fulfill.rs +++ b/src/librustc/middle/traits/fulfill.rs @@ -14,7 +14,6 @@ use middle::ty::{mod, AsPredicate, RegionEscape, Ty, ToPolyTraitRef}; use std::collections::HashSet; use std::collections::hash_map::Entry::{Occupied, Vacant}; use std::default::Default; -use std::rc::Rc; use syntax::ast; use util::common::ErrorReported; use util::ppaux::Repr; @@ -102,26 +101,30 @@ impl<'tcx> FulfillmentContext<'tcx> { } } - pub fn normalize_associated_type<'a>(&mut self, + /// "Normalize" a projection type `::X` by + /// creating a fresh type variable `$0` as well as a projection + /// predicate `::X == $0`. When the + /// inference engine runs, it will attempt to find an impl of + /// `SomeTrait` or a where clause that lets us unify `$0` with + /// something concrete. If this fails, we'll unify `$0` with + /// `projection_ty` again. + pub fn normalize_projection_type<'a>(&mut self, infcx: &InferCtxt<'a,'tcx>, - trait_ref: Rc>, - item_name: ast::Name, + projection_ty: ty::ProjectionTy<'tcx>, cause: ObligationCause<'tcx>) -> Ty<'tcx> { - debug!("normalize_associated_type(trait_ref={}, item_name={})", - trait_ref.repr(infcx.tcx), - item_name.repr(infcx.tcx)); + debug!("normalize_associated_type(projection_ty={})", + projection_ty.repr(infcx.tcx)); - assert!(!trait_ref.has_escaping_regions()); + assert!(!projection_ty.has_escaping_regions()); // FIXME(#20304) -- cache let ty_var = infcx.next_ty_var(); let projection = ty::Binder(ty::ProjectionPredicate { - projection_ty: ty::ProjectionTy { trait_ref: trait_ref, - item_name: item_name }, + projection_ty: projection_ty, ty: ty_var }); let obligation = Obligation::new(cause, projection.as_predicate()); diff --git a/src/librustc/middle/traits/mod.rs b/src/librustc/middle/traits/mod.rs index d7febea8909..d4fa0c98ad5 100644 --- a/src/librustc/middle/traits/mod.rs +++ b/src/librustc/middle/traits/mod.rs @@ -117,7 +117,10 @@ pub enum ObligationCauseCode<'tcx> { #[deriving(Clone)] pub struct DerivedObligationCause<'tcx> { - /// Resolving this trait led to the current obligation + /// The trait reference of the parent obligation that led to the + /// current obligation. Note that only trait obligations lead to + /// derived obligations, so we just store the trait reference here + /// directly. parent_trait_ref: ty::PolyTraitRef<'tcx>, /// The parent trait had this cause diff --git a/src/librustc/middle/traits/project.rs b/src/librustc/middle/traits/project.rs index d319e441415..435babf168e 100644 --- a/src/librustc/middle/traits/project.rs +++ b/src/librustc/middle/traits/project.rs @@ -20,7 +20,6 @@ use super::VtableImplData; use middle::infer; use middle::subst::Subst; use middle::ty::{mod, AsPredicate, ToPolyTraitRef, Ty}; -use std::fmt; use util::ppaux::Repr; pub type PolyProjectionObligation<'tcx> = @@ -34,10 +33,17 @@ pub type ProjectionTyObligation<'tcx> = /// When attempting to resolve `::Name == U`... pub enum ProjectionError<'tcx> { + /// ...we could not find any helpful information on what `Name` + /// might be. This could occur, for example, if there is a where + /// clause `T : TraitRef` but not `T : TraitRef`. When + /// normalizing, this case is where we opt to normalize back to + /// the projection type `::Name`. NoCandidate, + + /// ...we found multiple sources of information and couldn't resolve the ambiguity. TooManyCandidates, - /// + /// ...`` ws resolved to some type `V` that failed to unify with `U` MismatchedTypes(MismatchedProjectionTypes<'tcx>), /// ...an error occurred matching `T : TraitRef` @@ -380,12 +386,6 @@ fn confirm_candidate<'cx,'tcx>( Ok(projected_ty) } -impl<'tcx> Repr<'tcx> for super::MismatchedProjectionTypes<'tcx> { - fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String { - self.err.repr(tcx) - } -} - impl<'tcx> Repr<'tcx> for ProjectionError<'tcx> { fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String { match *self { @@ -401,12 +401,6 @@ impl<'tcx> Repr<'tcx> for ProjectionError<'tcx> { } } -impl<'tcx> fmt::Show for super::MismatchedProjectionTypes<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "MismatchedProjectionTypes(..)") - } -} - impl<'tcx> Repr<'tcx> for ProjectionTyCandidate<'tcx> { fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String { match *self { diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs index 755e50f1327..ce5337a58e1 100644 --- a/src/librustc/middle/traits/select.rs +++ b/src/librustc/middle/traits/select.rs @@ -150,8 +150,15 @@ enum SelectionCandidate<'tcx> { } struct SelectionCandidateSet<'tcx> { + // a list of candidates that definitely apply to the current + // obligation (meaning: types unify). vec: Vec>, - ambiguous: bool + + // if this is true, then there were candidates that might or might + // not have applied, but we couldn't tell. This occurs when some + // of the input types are type variables, in which case there are + // various "builtin" rules that might or might not trigger. + ambiguous: bool, } enum BuiltinBoundConditions<'tcx> { diff --git a/src/librustc/middle/traits/util.rs b/src/librustc/middle/traits/util.rs index ddf2c9d87fe..109810fc7ee 100644 --- a/src/librustc/middle/traits/util.rs +++ b/src/librustc/middle/traits/util.rs @@ -385,9 +385,16 @@ impl<'tcx> fmt::Show for super::FulfillmentErrorCode<'tcx> { } } -impl<'tcx> Repr<'tcx> for ty::type_err<'tcx> { +impl<'tcx> Repr<'tcx> for super::MismatchedProjectionTypes<'tcx> { fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String { - ty::type_err_to_str(tcx, self) + self.err.repr(tcx) } } +impl<'tcx> fmt::Show for super::MismatchedProjectionTypes<'tcx> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "MismatchedProjectionTypes(..)") + } +} + + diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index d6ab0201d19..ab39c761a38 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -1791,7 +1791,8 @@ pub enum Predicate<'tcx> { /// where T : 'a TypeOutlives(PolyTypeOutlivesPredicate<'tcx>), - /// + /// where ::Name == X, approximately. + /// See `ProjectionPredicate` struct for details. Projection(PolyProjectionPredicate<'tcx>), } @@ -1857,9 +1858,14 @@ impl<'tcx> PolyProjectionPredicate<'tcx> { } } +/// Represents the projection of an associated type. In explicit UFCS +/// form this would be written `>::N`. #[deriving(Clone, PartialEq, Eq, Hash, Show)] pub struct ProjectionTy<'tcx> { + /// The trait reference `T as Trait<..>`. pub trait_ref: Rc>, + + /// The name `N` of the associated type. pub item_name: ast::Name, } @@ -2179,6 +2185,12 @@ impl<'tcx> ParameterEnvironment<'tcx> { /// - `generics`: the set of type parameters and their bounds /// - `ty`: the base types, which may reference the parameters defined /// in `generics` +/// +/// Note that TypeSchemes are also sometimes called "polytypes" (and +/// in fact this struct used to carry that name, so you may find some +/// stray references in a comment or something). We try to reserve the +/// "poly" prefix to refer to higher-ranked things, as in +/// `PolyTraitRef`. #[deriving(Clone, Show)] pub struct TypeScheme<'tcx> { pub generics: Generics<'tcx>, @@ -4680,6 +4692,12 @@ pub fn ty_sort_string<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> String { } } +impl<'tcx> Repr<'tcx> for ty::type_err<'tcx> { + fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String { + ty::type_err_to_str(tcx, self) + } +} + /// Explains the source of a type err in a short, human readable way. This is meant to be placed /// in parentheses after some larger message. You should also invoke `note_and_explain_type_err()` /// afterwards to present additional details, particularly when it comes to lifetime-related diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 82a02320209..587a85cfcba 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -244,7 +244,6 @@ pub fn opt_ast_region_to_region<'tcx, AC: AstConv<'tcx>, RS: RegionScope>( fn ast_path_substs_for_ty<'tcx,AC,RS>( this: &AC, rscope: &RS, - decl_def_id: ast::DefId, decl_generics: &ty::Generics<'tcx>, path: &ast::Path) -> Substs<'tcx> @@ -280,7 +279,6 @@ fn ast_path_substs_for_ty<'tcx,AC,RS>( create_substs_for_ast_path(this, rscope, path.span, - decl_def_id, decl_generics, None, types, @@ -291,7 +289,6 @@ fn create_substs_for_ast_path<'tcx,AC,RS>( this: &AC, rscope: &RS, span: Span, - _decl_def_id: ast::DefId, decl_generics: &ty::Generics<'tcx>, self_ty: Option>, types: Vec>, @@ -621,7 +618,6 @@ fn ast_path_to_trait_ref<'a,'tcx,AC,RS>( let substs = create_substs_for_ast_path(this, &shifted_rscope, path.span, - trait_def_id, &trait_def.generics, self_ty, types, @@ -705,7 +701,6 @@ pub fn ast_path_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>( let substs = ast_path_substs_for_ty(this, rscope, - did, &generics, path); let ty = decl_ty.subst(tcx, &substs); @@ -747,7 +742,7 @@ pub fn ast_path_to_ty_relaxed<'tcx,AC,RS>( Substs::new(VecPerParamSpace::params_from_type(type_params), VecPerParamSpace::params_from_type(region_params)) } else { - ast_path_substs_for_ty(this, rscope, did, &generics, path) + ast_path_substs_for_ty(this, rscope, &generics, path) }; let ty = decl_ty.subst(tcx, &substs); diff --git a/src/librustc_typeck/check/assoc.rs b/src/librustc_typeck/check/assoc.rs index 0d7ce2f871a..081959a4efa 100644 --- a/src/librustc_typeck/check/assoc.rs +++ b/src/librustc_typeck/check/assoc.rs @@ -80,11 +80,9 @@ impl<'a,'tcx> TypeFolder<'tcx> for AssociatedTypeNormalizer<'a,'tcx> { self.span, self.body_id, ObligationCauseCode::MiscObligation); - let trait_ref = data.trait_ref.clone(); self.fulfillment_cx - .normalize_associated_type(self.infcx, - trait_ref, - data.item_name, + .normalize_projection_type(self.infcx, + data.clone(), cause) } _ => { diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 7929a005af2..12ecfe6c298 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1758,9 +1758,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { traits::ObligationCauseCode::MiscObligation); self.inh.fulfillment_cx .borrow_mut() - .normalize_associated_type(self.infcx(), - trait_ref, - item_name, + .normalize_projection_type(self.infcx(), + ty::ProjectionTy { + trait_ref: trait_ref, + item_name: item_name, + }, cause) } diff --git a/src/test/auxiliary/issue-18048-lib.rs b/src/test/auxiliary/associated-types-cc-lib.rs similarity index 88% rename from src/test/auxiliary/issue-18048-lib.rs rename to src/test/auxiliary/associated-types-cc-lib.rs index 52cc216657b..17b2a0751fe 100644 --- a/src/test/auxiliary/issue-18048-lib.rs +++ b/src/test/auxiliary/associated-types-cc-lib.rs @@ -8,6 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// Helper for test issue-18048, which tests associated types in a +// cross-crate scenario. + #![crate_type="lib"] #![feature(associated_types)] diff --git a/src/test/run-pass/issue-18048.rs b/src/test/run-pass/associated-types-cc.rs similarity index 89% rename from src/test/run-pass/issue-18048.rs rename to src/test/run-pass/associated-types-cc.rs index 7cd6e5eb0d5..c0cf917aa41 100644 --- a/src/test/run-pass/issue-18048.rs +++ b/src/test/run-pass/associated-types-cc.rs @@ -8,14 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// aux-build:issue-18048-lib.rs +// aux-build:associated-types-cc-lib.rs // Test that we are able to reference cross-crate traits that employ // associated types. #![feature(associated_types)] -extern crate "issue-18048-lib" as bar; +extern crate "associated-types-cc-lib" as bar; use bar::Bar; diff --git a/src/test/run-pass/issue-19081.rs b/src/test/run-pass/issue-19081.rs index aeb14087477..57724ba91b0 100644 --- a/src/test/run-pass/issue-19081.rs +++ b/src/test/run-pass/issue-19081.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty -- currently pretty prints as `Hash<