diff --git a/src/librustc/metadata/common.rs b/src/librustc/metadata/common.rs index 03e436e98df..2a58da8cb3b 100644 --- a/src/librustc/metadata/common.rs +++ b/src/librustc/metadata/common.rs @@ -256,3 +256,6 @@ pub const tag_predicate_space: uint = 0xa9; pub const tag_predicate_data: uint = 0xb0; pub const tag_unsafety: uint = 0xb1; + +pub const tag_associated_type_names: uint = 0xb2; +pub const tag_associated_type_name: uint = 0xb3; diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index ce04a902992..fe0a2beb9ab 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -369,6 +369,17 @@ fn parse_unsafety(item_doc: rbml::Doc) -> ast::Unsafety { } } +fn parse_associated_type_names(item_doc: rbml::Doc) -> Vec { + let names_doc = reader::get_doc(item_doc, tag_associated_type_names); + let mut names = Vec::new(); + reader::tagged_docs(names_doc, tag_associated_type_name, |name_doc| { + let name = token::intern(name_doc.as_str_slice()); + names.push(name); + true + }); + names +} + pub fn get_trait_def<'tcx>(cdata: Cmd, item_id: ast::NodeId, tcx: &ty::ctxt<'tcx>) -> ty::TraitDef<'tcx> @@ -377,12 +388,14 @@ pub fn get_trait_def<'tcx>(cdata: Cmd, let generics = doc_generics(item_doc, tcx, cdata, tag_item_generics); let bounds = trait_def_bounds(item_doc, tcx, cdata); let unsafety = parse_unsafety(item_doc); + let associated_type_names = parse_associated_type_names(item_doc); ty::TraitDef { unsafety: unsafety, generics: generics, bounds: bounds, - trait_ref: Rc::new(item_trait_ref(item_doc, tcx, cdata)) + trait_ref: Rc::new(item_trait_ref(item_doc, tcx, cdata)), + associated_type_names: associated_type_names, } } diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index 6d79419b386..e541768b357 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -1316,6 +1316,7 @@ fn encode_info_for_item(ecx: &EncodeContext, encode_item_variances(rbml_w, ecx, item.id); let trait_def = ty::lookup_trait_def(tcx, def_id); encode_unsafety(rbml_w, trait_def.unsafety); + encode_associated_type_names(rbml_w, trait_def.associated_type_names.as_slice()); encode_generics(rbml_w, ecx, &trait_def.generics, tag_item_generics); encode_trait_ref(rbml_w, ecx, &*trait_def.trait_ref, tag_item_trait_ref); encode_name(rbml_w, item.ident.name); @@ -1689,6 +1690,14 @@ fn encode_unsafety(rbml_w: &mut Encoder, unsafety: ast::Unsafety) { rbml_w.wr_tagged_u8(tag_unsafety, byte); } +fn encode_associated_type_names(rbml_w: &mut Encoder, names: &[ast::Name]) { + rbml_w.start_tag(tag_associated_type_names); + for &name in names.iter() { + rbml_w.wr_tagged_str(tag_associated_type_name, token::get_name(name).get()); + } + rbml_w.end_tag(); +} + fn encode_crate_deps(rbml_w: &mut Encoder, cstore: &cstore::CStore) { fn get_ordered_deps(cstore: &cstore::CStore) -> Vec { // Pull the cnums and name,vers,hash out of cstore diff --git a/src/librustc/metadata/tydecode.rs b/src/librustc/metadata/tydecode.rs index 01cde5138c5..7daef30e253 100644 --- a/src/librustc/metadata/tydecode.rs +++ b/src/librustc/metadata/tydecode.rs @@ -504,6 +504,12 @@ fn parse_ty<'a, 'tcx>(st: &mut PState<'a, 'tcx>, conv: conv_did) -> Ty<'tcx> { return ty::mk_unboxed_closure(st.tcx, did, st.tcx.mk_region(region), st.tcx.mk_substs(substs)); } + 'P' => { + assert_eq!(next(st), '['); + let trait_ref = parse_trait_ref(st, |x,y| conv(x,y)); + let name = token::str_to_ident(parse_str(st, ']').as_slice()).name; + return ty::mk_projection(tcx, trait_ref, name); + } 'e' => { return tcx.types.err; } @@ -683,17 +689,32 @@ pub fn parse_predicate<'a,'tcx>(st: &mut PState<'a, 'tcx>, -> ty::Predicate<'tcx> { match next(st) { - 't' => Rc::new(ty::Binder(parse_trait_ref(st, conv))).as_predicate(), + 't' => ty::Binder(Rc::new(parse_trait_ref(st, conv))).as_predicate(), 'e' => ty::Binder(ty::EquatePredicate(parse_ty(st, |x,y| conv(x,y)), parse_ty(st, |x,y| conv(x,y)))).as_predicate(), 'r' => ty::Binder(ty::OutlivesPredicate(parse_region(st, |x,y| conv(x,y)), parse_region(st, |x,y| conv(x,y)))).as_predicate(), 'o' => ty::Binder(ty::OutlivesPredicate(parse_ty(st, |x,y| conv(x,y)), parse_region(st, |x,y| conv(x,y)))).as_predicate(), + 'p' => ty::Binder(parse_projection_predicate(st, conv)).as_predicate(), c => panic!("Encountered invalid character in metadata: {}", c) } } +fn parse_projection_predicate<'a,'tcx>( + st: &mut PState<'a, 'tcx>, + conv: conv_did) + -> ty::ProjectionPredicate<'tcx> +{ + ty::ProjectionPredicate { + projection_ty: ty::ProjectionTy { + trait_ref: Rc::new(parse_trait_ref(st, |x,y| conv(x,y))), + item_name: token::str_to_ident(parse_str(st, '|').as_slice()).name, + }, + ty: parse_ty(st, |x,y| conv(x,y)), + } +} + pub fn parse_type_param_def_data<'tcx>(data: &[u8], start: uint, crate_num: ast::CrateNum, tcx: &ty::ctxt<'tcx>, conv: conv_did) -> ty::TypeParameterDef<'tcx> @@ -710,10 +731,6 @@ fn parse_type_param_def<'a, 'tcx>(st: &mut PState<'a, 'tcx>, conv: conv_did) assert_eq!(next(st), '|'); let index = parse_u32(st); assert_eq!(next(st), '|'); - let associated_with = parse_opt(st, |st| { - parse_def(st, NominalType, |x,y| conv(x,y)) - }); - assert_eq!(next(st), '|'); let bounds = parse_bounds(st, |x,y| conv(x,y)); let default = parse_opt(st, |st| parse_ty(st, |x,y| conv(x,y))); @@ -722,7 +739,6 @@ fn parse_type_param_def<'a, 'tcx>(st: &mut PState<'a, 'tcx>, conv: conv_did) def_id: def_id, space: space, index: index, - associated_with: associated_with, bounds: bounds, default: default } @@ -768,7 +784,8 @@ fn parse_bounds<'a, 'tcx>(st: &mut PState<'a, 'tcx>, conv: conv_did) let mut param_bounds = ty::ParamBounds { region_bounds: Vec::new(), builtin_bounds: builtin_bounds, - trait_bounds: Vec::new() + trait_bounds: Vec::new(), + projection_bounds: Vec::new(), }; loop { match next(st) { @@ -778,7 +795,11 @@ fn parse_bounds<'a, 'tcx>(st: &mut PState<'a, 'tcx>, conv: conv_did) } 'I' => { param_bounds.trait_bounds.push( - Rc::new(ty::Binder(parse_trait_ref(st, |x,y| conv(x,y))))); + ty::Binder(Rc::new(parse_trait_ref(st, |x,y| conv(x,y))))); + } + 'P' => { + param_bounds.projection_bounds.push( + ty::Binder(parse_projection_predicate(st, |x,y| conv(x,y)))); } '.' => { return param_bounds; diff --git a/src/librustc/metadata/tyencode.rs b/src/librustc/metadata/tyencode.rs index 3e9eaf7eea2..6d2b7e0ba93 100644 --- a/src/librustc/metadata/tyencode.rs +++ b/src/librustc/metadata/tyencode.rs @@ -149,6 +149,11 @@ pub fn enc_ty<'a, 'tcx>(w: &mut SeekableMemWriter, cx: &ctxt<'a, 'tcx>, t: Ty<'t enc_substs(w, cx, substs); mywrite!(w, "]"); } + ty::ty_projection(ref data) => { + mywrite!(w, "P["); + enc_trait_ref(w, cx, &data.trait_ref); + mywrite!(w, "{}]", token::get_name(data.item_name)); + } ty::ty_err => { mywrite!(w, "e"); } @@ -403,7 +408,12 @@ pub fn enc_bounds<'a, 'tcx>(w: &mut SeekableMemWriter, cx: &ctxt<'a, 'tcx>, for tp in bs.trait_bounds.iter() { mywrite!(w, "I"); - enc_trait_ref(w, cx, &tp.0); + enc_trait_ref(w, cx, &*tp.0); + } + + for tp in bs.projection_bounds.iter() { + mywrite!(w, "P"); + enc_projection_predicate(w, cx, &tp.0); } mywrite!(w, "."); @@ -414,8 +424,6 @@ pub fn enc_type_param_def<'a, 'tcx>(w: &mut SeekableMemWriter, cx: &ctxt<'a, 'tc mywrite!(w, "{}:{}|{}|{}|", token::get_name(v.name), (cx.ds)(v.def_id), v.space.to_uint(), v.index); - enc_opt(w, v.associated_with, |w, did| mywrite!(w, "{}", (cx.ds)(did))); - mywrite!(w, "|"); enc_bounds(w, cx, &v.bounds); enc_opt(w, v.default, |w, t| enc_ty(w, cx, t)); } @@ -427,7 +435,7 @@ pub fn enc_predicate<'a, 'tcx>(w: &mut SeekableMemWriter, match *p { ty::Predicate::Trait(ref trait_ref) => { mywrite!(w, "t"); - enc_trait_ref(w, cx, &trait_ref.0); + enc_trait_ref(w, cx, &*trait_ref.0.trait_ref); } ty::Predicate::Equate(ty::Binder(ty::EquatePredicate(a, b))) => { mywrite!(w, "e"); @@ -444,5 +452,17 @@ pub fn enc_predicate<'a, 'tcx>(w: &mut SeekableMemWriter, enc_ty(w, cx, a); enc_region(w, cx, b); } + ty::Predicate::Projection(ty::Binder(ref data)) => { + mywrite!(w, "p"); + enc_projection_predicate(w, cx, data) + } } } + +fn enc_projection_predicate<'a, 'tcx>(w: &mut SeekableMemWriter, + cx: &ctxt<'a, 'tcx>, + data: &ty::ProjectionPredicate<'tcx>) { + enc_trait_ref(w, cx, &*data.projection_ty.trait_ref); + mywrite!(w, "{}|", token::get_name(data.projection_ty.item_name)); + enc_ty(w, cx, data.ty); +} diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index a135701a9c4..57dac607fa6 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -1284,7 +1284,7 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext, rbml_w.tag(c::tag_table_object_cast_map, |rbml_w| { rbml_w.id(id); rbml_w.tag(c::tag_table_val, |rbml_w| { - rbml_w.emit_trait_ref(ecx, &trait_ref.0); + rbml_w.emit_trait_ref(ecx, &*trait_ref.0); }) }) } @@ -1364,7 +1364,7 @@ trait rbml_decoder_decoder_helpers<'tcx> { fn read_trait_ref<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) -> Rc>; fn read_poly_trait_ref<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) - -> Rc>; + -> ty::PolyTraitRef<'tcx>; fn read_type_param_def<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) -> ty::TypeParameterDef<'tcx>; fn read_predicate<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) @@ -1558,8 +1558,8 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> { } fn read_poly_trait_ref<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>) - -> Rc> { - Rc::new(ty::Binder(self.read_opaque(|this, doc| { + -> ty::PolyTraitRef<'tcx> { + ty::Binder(Rc::new(self.read_opaque(|this, doc| { let ty = tydecode::parse_trait_ref_data( doc.data, dcx.cdata.cnum, @@ -1786,7 +1786,7 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> { Ok(this.read_poly_trait_ref(dcx)) })); Ok(ty::TyTrait { - principal: (*principal).clone(), + principal: ty::Binder((*principal.0).clone()), bounds: try!(this.read_struct_field("bounds", 1, |this| { Ok(this.read_existential_bounds(dcx)) })), diff --git a/src/librustc/middle/fast_reject.rs b/src/librustc/middle/fast_reject.rs index 62cf47da687..dcbd94b8482 100644 --- a/src/librustc/middle/fast_reject.rs +++ b/src/librustc/middle/fast_reject.rs @@ -58,7 +58,7 @@ pub fn simplify_type(tcx: &ty::ctxt, ty::ty_vec(..) => Some(VecSimplifiedType), ty::ty_ptr(_) => Some(PtrSimplifiedType), ty::ty_trait(ref trait_info) => { - Some(TraitSimplifiedType(trait_info.principal.def_id())) + Some(TraitSimplifiedType(trait_info.principal_def_id())) } ty::ty_struct(def_id, _) => { Some(StructSimplifiedType(def_id)) @@ -86,6 +86,9 @@ pub fn simplify_type(tcx: &ty::ctxt, ty::ty_bare_fn(_, ref f) => { Some(FunctionSimplifiedType(f.sig.0.inputs.len())) } + ty::ty_projection(_) => { + None + } ty::ty_param(_) => { if can_simplify_params { Some(ParameterSimplifiedType) diff --git a/src/librustc/middle/infer/combine.rs b/src/librustc/middle/infer/combine.rs index 9f5eca142c3..8ff2d0ba1f0 100644 --- a/src/librustc/middle/infer/combine.rs +++ b/src/librustc/middle/infer/combine.rs @@ -51,6 +51,7 @@ use middle::ty_fold; use middle::ty_fold::{TypeFoldable}; use util::ppaux::Repr; +use std::rc::Rc; use syntax::ast::{Onceness, Unsafety}; use syntax::ast; use syntax::abi; @@ -358,6 +359,18 @@ pub trait Combineable<'tcx> : Repr<'tcx> + TypeFoldable<'tcx> { fn combine>(combiner: &C, a: &Self, b: &Self) -> cres<'tcx, Self>; } +impl<'tcx,T> Combineable<'tcx> for Rc + where T : Combineable<'tcx> +{ + fn combine>(combiner: &C, + a: &Rc, + b: &Rc) + -> cres<'tcx, Rc> + { + Ok(Rc::new(try!(Combineable::combine(combiner, &**a, &**b)))) + } +} + impl<'tcx> Combineable<'tcx> for ty::TraitRef<'tcx> { fn combine>(combiner: &C, a: &ty::TraitRef<'tcx>, @@ -581,6 +594,15 @@ pub fn super_tys<'tcx, C: Combine<'tcx>>(this: &C, }) } + (&ty::ty_projection(ref a_data), &ty::ty_projection(ref b_data)) => { + if a_data.item_name == b_data.item_name { + let trait_ref = try!(this.trait_refs(&a_data.trait_ref, &b_data.trait_ref)); + Ok(ty::mk_projection(tcx, trait_ref, a_data.item_name)) + } else { + Err(ty::terr_sorts(expected_found(this, a, b))) + } + } + _ => Err(ty::terr_sorts(expected_found(this, a, b))) }; diff --git a/src/librustc/middle/infer/error_reporting.rs b/src/librustc/middle/infer/error_reporting.rs index 3d3eac7b6ed..e38b721ce2d 100644 --- a/src/librustc/middle/infer/error_reporting.rs +++ b/src/librustc/middle/infer/error_reporting.rs @@ -1437,6 +1437,11 @@ impl<'a, 'tcx> ErrorReportingHelpers<'tcx> for InferCtxt<'a, 'tcx> { format!(" for {}in generic type", bound_region_to_string(self.tcx, "lifetime parameter ", true, br)) } + infer::LateBoundRegion(_, br, infer::AssocTypeProjection(type_name)) => { + format!(" for {}in trait containing associated type `{}`", + bound_region_to_string(self.tcx, "lifetime parameter ", true, br), + token::get_name(type_name)) + } infer::EarlyBoundRegion(_, name) => { format!(" for lifetime parameter `{}`", token::get_name(name).get()) @@ -1661,13 +1666,16 @@ impl<'tcx> Resolvable<'tcx> for Rc> { } } -impl<'tcx> Resolvable<'tcx> for Rc> { - fn resolve<'a>(&self, infcx: &InferCtxt<'a, 'tcx>) - -> Rc> { - Rc::new(infcx.resolve_type_vars_if_possible(&**self)) +impl<'tcx> Resolvable<'tcx> for ty::PolyTraitRef<'tcx> { + fn resolve<'a>(&self, + infcx: &InferCtxt<'a, 'tcx>) + -> ty::PolyTraitRef<'tcx> + { + infcx.resolve_type_vars_if_possible(self) } + fn contains_error(&self) -> bool { - ty::trait_ref_contains_error(&self.0) + ty::trait_ref_contains_error(&*self.0) } } diff --git a/src/librustc/middle/infer/freshen.rs b/src/librustc/middle/infer/freshen.rs index d8455b8db71..33174409f89 100644 --- a/src/librustc/middle/infer/freshen.rs +++ b/src/librustc/middle/infer/freshen.rs @@ -157,6 +157,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> { ty::ty_struct(..) | ty::ty_unboxed_closure(..) | ty::ty_tup(..) | + ty::ty_projection(..) | ty::ty_param(..) => { ty_fold::super_fold_ty(self, t) } diff --git a/src/librustc/middle/infer/mod.rs b/src/librustc/middle/infer/mod.rs index 2231c0088e7..cf9520ecfbb 100644 --- a/src/librustc/middle/infer/mod.rs +++ b/src/librustc/middle/infer/mod.rs @@ -139,7 +139,7 @@ pub enum TypeOrigin { pub enum ValuePairs<'tcx> { Types(ty::expected_found>), TraitRefs(ty::expected_found>>), - PolyTraitRefs(ty::expected_found>>), + PolyTraitRefs(ty::expected_found>), } /// The trace designates the path through inference that we took to @@ -231,6 +231,9 @@ pub enum LateBoundRegionConversionTime { /// when two higher-ranked types are compared HigherRankedType, + + /// when projecting an associated type + AssocTypeProjection(ast::Name), } /// Reasons to create a region inference variable @@ -407,8 +410,8 @@ pub fn mk_eqty<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, pub fn mk_sub_poly_trait_refs<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, a_is_expected: bool, origin: TypeOrigin, - a: Rc>, - b: Rc>) + a: ty::PolyTraitRef<'tcx>, + b: ty::PolyTraitRef<'tcx>) -> ures<'tcx> { debug!("mk_sub_trait_refs({} <: {})", @@ -703,8 +706,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { pub fn sub_poly_trait_refs(&self, a_is_expected: bool, origin: TypeOrigin, - a: Rc>, - b: Rc>) + a: ty::PolyTraitRef<'tcx>, + b: ty::PolyTraitRef<'tcx>) -> ures<'tcx> { debug!("sub_poly_trait_refs({} <: {})", @@ -715,7 +718,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { origin: origin, values: PolyTraitRefs(expected_found(a_is_expected, a.clone(), b.clone())) }; - self.sub(a_is_expected, trace).binders(&*a, &*b).to_ures() + self.sub(a_is_expected, trace).binders(&a, &b).to_ures() }) } @@ -750,7 +753,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { -> T where T : TypeFoldable<'tcx> + Repr<'tcx> { - /*! See `higher_ranked::leak_check` */ + /*! See `higher_ranked::plug_leaks` */ higher_ranked::plug_leaks(self, skol_map, snapshot, value) } diff --git a/src/librustc/middle/traits/coherence.rs b/src/librustc/middle/traits/coherence.rs index d48685ce27d..d8b39d92c69 100644 --- a/src/librustc/middle/traits/coherence.rs +++ b/src/librustc/middle/traits/coherence.rs @@ -45,7 +45,9 @@ pub fn impl_can_satisfy(infcx: &InferCtxt, let param_env = ty::empty_parameter_environment(); let mut selcx = SelectionContext::intercrate(infcx, ¶m_env, infcx.tcx); let obligation = Obligation::new(ObligationCause::dummy(), - Rc::new(ty::Binder(impl1_trait_ref))); + ty::Binder(ty::TraitPredicate { + trait_ref: Rc::new(impl1_trait_ref), + })); debug!("impl_can_satisfy(obligation={})", obligation.repr(infcx.tcx)); selcx.evaluate_impl(impl2_def_id, &obligation) } @@ -140,7 +142,7 @@ pub fn ty_is_local<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool { } ty::ty_trait(ref tt) => { - tt.principal.def_id().krate == ast::LOCAL_CRATE + tt.principal_def_id().krate == ast::LOCAL_CRATE } // Type parameters may be bound to types that are not local to @@ -149,6 +151,11 @@ pub fn ty_is_local<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool { false } + // Associated types could be anything, I guess. + ty::ty_projection(..) => { + false + } + ty::ty_infer(..) | ty::ty_open(..) | ty::ty_err => { diff --git a/src/librustc/middle/traits/error_reporting.rs b/src/librustc/middle/traits/error_reporting.rs index 462857de1d4..a3d92c698a2 100644 --- a/src/librustc/middle/traits/error_reporting.rs +++ b/src/librustc/middle/traits/error_reporting.rs @@ -8,12 +8,18 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use super::{FulfillmentError, FulfillmentErrorCode, - ObligationCauseCode, SelectionError, - PredicateObligation, OutputTypeParameterMismatch}; +use super::{ + FulfillmentError, + FulfillmentErrorCode, + MismatchedProjectionTypes, + ObligationCauseCode, + OutputTypeParameterMismatch, + PredicateObligation, + SelectionError, +}; use middle::infer::InferCtxt; -use middle::ty::{mod}; +use middle::ty::{mod, AsPredicate, ReferencesError, ToPolyTraitRef}; use syntax::codemap::Span; use util::ppaux::{Repr, UserString}; @@ -30,12 +36,32 @@ fn report_fulfillment_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, FulfillmentErrorCode::CodeSelectionError(ref e) => { report_selection_error(infcx, &error.obligation, e); } + FulfillmentErrorCode::CodeProjectionError(ref e) => { + report_projection_error(infcx, &error.obligation, e); + } FulfillmentErrorCode::CodeAmbiguity => { maybe_report_ambiguity(infcx, &error.obligation); } } } +pub fn report_projection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, + obligation: &PredicateObligation<'tcx>, + error: &MismatchedProjectionTypes<'tcx>) +{ + let predicate = + infcx.resolve_type_vars_if_possible(&obligation.predicate); + if !predicate.references_error() { + infcx.tcx.sess.span_err( + obligation.cause.span, + format!( + "type mismatch resolving `{}`: {}", + predicate.user_string(infcx.tcx), + ty::type_err_to_str(infcx.tcx, &error.err)).as_slice()); + note_obligation_cause(infcx, obligation); + } +} + pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, obligation: &PredicateObligation<'tcx>, error: &SelectionError<'tcx>) @@ -43,38 +69,13 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, match *error { SelectionError::Overflow => { // We could track the stack here more precisely if we wanted, I imagine. - match obligation.trait_ref { - ty::Predicate::Trait(ref trait_ref) => { - let trait_ref = - infcx.resolve_type_vars_if_possible(&**trait_ref); - infcx.tcx.sess.span_err( - obligation.cause.span, - format!( - "overflow evaluating the trait `{}` for the type `{}`", - trait_ref.user_string(infcx.tcx), - trait_ref.self_ty().user_string(infcx.tcx))[]); - } - - ty::Predicate::Equate(ref predicate) => { - let predicate = infcx.resolve_type_vars_if_possible(predicate); - let err = infcx.equality_predicate(obligation.cause.span, - &predicate).unwrap_err(); - - infcx.tcx.sess.span_err( - obligation.cause.span, - format!( - "the requirement `{}` is not satisfied (`{}`)", - predicate.user_string(infcx.tcx), - ty::type_err_to_str(infcx.tcx, &err)).as_slice()); - } - - ty::Predicate::TypeOutlives(..) | - ty::Predicate::RegionOutlives(..) => { - infcx.tcx.sess.span_err( - obligation.cause.span, - format!("overflow evaluating lifetime predicate").as_slice()); - } - } + let predicate = + infcx.resolve_type_vars_if_possible(&obligation.predicate); + infcx.tcx.sess.span_err( + obligation.cause.span, + format!( + "overflow evaluating the requirement `{}`", + predicate.user_string(infcx.tcx)).as_slice()); let current_limit = infcx.tcx.sess.recursion_limit.get(); let suggested_limit = current_limit * 2; @@ -87,27 +88,25 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, note_obligation_cause(infcx, obligation); } SelectionError::Unimplemented => { - match obligation.trait_ref { - ty::Predicate::Trait(ref trait_ref) => { - let trait_ref = - infcx.resolve_type_vars_if_possible( - &**trait_ref); - if !ty::type_is_error(trait_ref.self_ty()) { + match obligation.predicate { + ty::Predicate::Trait(ref trait_predicate) => { + let trait_predicate = + infcx.resolve_type_vars_if_possible(trait_predicate); + if !trait_predicate.references_error() { + let trait_ref = trait_predicate.to_poly_trait_ref(); infcx.tcx.sess.span_err( obligation.cause.span, format!( "the trait `{}` is not implemented for the type `{}`", trait_ref.user_string(infcx.tcx), trait_ref.self_ty().user_string(infcx.tcx)).as_slice()); - note_obligation_cause(infcx, obligation); } } ty::Predicate::Equate(ref predicate) => { let predicate = infcx.resolve_type_vars_if_possible(predicate); let err = infcx.equality_predicate(obligation.cause.span, - &predicate).unwrap_err(); - + &predicate).unwrap_err(); infcx.tcx.sess.span_err( obligation.cause.span, format!( @@ -116,9 +115,22 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, ty::type_err_to_str(infcx.tcx, &err)).as_slice()); } - ty::Predicate::TypeOutlives(..) | - ty::Predicate::RegionOutlives(..) => { - let predicate = infcx.resolve_type_vars_if_possible(&obligation.trait_ref); + ty::Predicate::RegionOutlives(ref predicate) => { + let predicate = infcx.resolve_type_vars_if_possible(predicate); + let err = infcx.region_outlives_predicate(obligation.cause.span, + &predicate).unwrap_err(); + infcx.tcx.sess.span_err( + obligation.cause.span, + format!( + "the requirement `{}` is not satisfied (`{}`)", + predicate.user_string(infcx.tcx), + ty::type_err_to_str(infcx.tcx, &err)).as_slice()); + } + + ty::Predicate::Projection(..) | + ty::Predicate::TypeOutlives(..) => { + let predicate = + infcx.resolve_type_vars_if_possible(&obligation.predicate); infcx.tcx.sess.span_err( obligation.cause.span, format!( @@ -128,12 +140,8 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, } } OutputTypeParameterMismatch(ref expected_trait_ref, ref actual_trait_ref, ref e) => { - let expected_trait_ref = - infcx.resolve_type_vars_if_possible( - &**expected_trait_ref); - let actual_trait_ref = - infcx.resolve_type_vars_if_possible( - &**actual_trait_ref); + let expected_trait_ref = infcx.resolve_type_vars_if_possible(&*expected_trait_ref); + let actual_trait_ref = infcx.resolve_type_vars_if_possible(&*actual_trait_ref); if !ty::type_is_error(actual_trait_ref.self_ty()) { infcx.tcx.sess.span_err( obligation.cause.span, @@ -150,24 +158,26 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, } } -fn maybe_report_ambiguity<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, - obligation: &PredicateObligation<'tcx>) { +pub fn maybe_report_ambiguity<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, + obligation: &PredicateObligation<'tcx>) { // Unable to successfully determine, probably means // insufficient type information, but could mean // ambiguous impls. The latter *ought* to be a // coherence violation, so we don't report it here. - let trait_ref = match obligation.trait_ref { - ty::Predicate::Trait(ref trait_ref) => { - infcx.resolve_type_vars_if_possible(&**trait_ref) + let trait_ref = match obligation.predicate { + ty::Predicate::Trait(ref trait_predicate) => { + infcx.resolve_type_vars_if_possible( + &trait_predicate.to_poly_trait_ref()) } _ => { infcx.tcx.sess.span_bug( obligation.cause.span, format!("ambiguity from something other than a trait: {}", - obligation.trait_ref.repr(infcx.tcx)).as_slice()); + obligation.predicate.repr(infcx.tcx)).as_slice()); } }; + let self_ty = trait_ref.self_ty(); debug!("maybe_report_ambiguity(trait_ref={}, self_ty={}, obligation={})", @@ -208,7 +218,7 @@ fn maybe_report_ambiguity<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, locate the impl of the trait `{}` for \ the type `{}`; type annotations required", trait_ref.user_string(infcx.tcx), - self_ty.user_string(infcx.tcx))[]); + self_ty.user_string(infcx.tcx)).as_slice()); note_obligation_cause(infcx, obligation); } } @@ -221,56 +231,38 @@ fn maybe_report_ambiguity<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, cannot locate the impl of the trait `{}` for \ the type `{}`", trait_ref.user_string(infcx.tcx), - self_ty.user_string(infcx.tcx))[]); + self_ty.user_string(infcx.tcx)).as_slice()); } } fn note_obligation_cause<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, obligation: &PredicateObligation<'tcx>) { - let trait_ref = match obligation.trait_ref { - ty::Predicate::Trait(ref trait_ref) => { - infcx.resolve_type_vars_if_possible(&**trait_ref) - } - _ => { - infcx.tcx.sess.span_bug( - obligation.cause.span, - format!("ambiguity from something other than a trait: {}", - obligation.trait_ref.repr(infcx.tcx)).as_slice()); - } - }; - note_obligation_cause_code(infcx, - &trait_ref, + &obligation.predicate, obligation.cause.span, - &obligation.cause.code) + &obligation.cause.code); } fn note_obligation_cause_code<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, - trait_ref: &ty::PolyTraitRef<'tcx>, + _predicate: &ty::Predicate<'tcx>, cause_span: Span, cause_code: &ObligationCauseCode<'tcx>) { let tcx = infcx.tcx; - let trait_name = ty::item_path_str(tcx, trait_ref.def_id()); match *cause_code { ObligationCauseCode::MiscObligation => { } ObligationCauseCode::ItemObligation(item_def_id) => { let item_name = ty::item_path_str(tcx, item_def_id); tcx.sess.span_note( cause_span, - format!( - "the trait `{}` must be implemented because it is required by `{}`", - trait_name, - item_name).as_slice()); + format!("required by `{}`", item_name).as_slice()); } ObligationCauseCode::ObjectCastObligation(object_ty) => { tcx.sess.span_note( cause_span, format!( - "the trait `{}` must be implemented for the cast \ - to the object type `{}`", - trait_name, + "required for the cast to the object type `{}`", infcx.ty_to_string(object_ty)).as_slice()); } ObligationCauseCode::RepeatVec => { @@ -323,27 +315,23 @@ fn note_obligation_cause_code<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, span_note!(tcx.sess, cause_span, "shared static variables must have a type that implements `Sync`"); } - ObligationCauseCode::BuiltinDerivedObligation(ref root_trait_ref, ref root_cause_code) => { - let root_trait_ref = - infcx.resolve_type_vars_if_possible(&**root_trait_ref); + ObligationCauseCode::BuiltinDerivedObligation(ref data) => { + let parent_trait_ref = infcx.resolve_type_vars_if_possible(&data.parent_trait_ref); span_note!(tcx.sess, cause_span, - "the type `{}` must implement `{}` because it appears within the type `{}`", - trait_ref.self_ty().user_string(infcx.tcx), - trait_ref.user_string(infcx.tcx), - root_trait_ref.self_ty().user_string(infcx.tcx)); - note_obligation_cause_code(infcx, &root_trait_ref, cause_span, &**root_cause_code); + "required because it appears within the type `{}`", + parent_trait_ref.0.self_ty().user_string(infcx.tcx)); + let parent_predicate = parent_trait_ref.as_predicate(); + note_obligation_cause_code(infcx, &parent_predicate, cause_span, &*data.parent_code); } - ObligationCauseCode::ImplDerivedObligation(ref root_trait_ref, ref root_cause_code) => { - let root_trait_ref = - infcx.resolve_type_vars_if_possible(&**root_trait_ref); + ObligationCauseCode::ImplDerivedObligation(ref data) => { + let parent_trait_ref = infcx.resolve_type_vars_if_possible(&data.parent_trait_ref); span_note!(tcx.sess, cause_span, - "the type `{}` must implement `{}` due to the requirements \ - on the impl of `{}` for the type `{}`", - trait_ref.self_ty().user_string(infcx.tcx), - trait_ref.user_string(infcx.tcx), - root_trait_ref.user_string(infcx.tcx), - root_trait_ref.self_ty().user_string(infcx.tcx)); - note_obligation_cause_code(infcx, &root_trait_ref, cause_span, &**root_cause_code); + "required because of the requirements on the impl of `{}` for `{}`", + parent_trait_ref.user_string(infcx.tcx), + parent_trait_ref.0.self_ty().user_string(infcx.tcx)); + let parent_predicate = parent_trait_ref.as_predicate(); + note_obligation_cause_code(infcx, &parent_predicate, cause_span, &*data.parent_code); } } } + diff --git a/src/librustc/middle/traits/fulfill.rs b/src/librustc/middle/traits/fulfill.rs index 6c80a22536a..e5024e000df 100644 --- a/src/librustc/middle/traits/fulfill.rs +++ b/src/librustc/middle/traits/fulfill.rs @@ -8,9 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use middle::infer::InferCtxt; +use middle::infer::{mod, InferCtxt}; use middle::mem_categorization::Typer; -use middle::ty::{mod, Ty}; +use middle::ty::{mod, AsPredicate, RegionEscape, Ty, ToPolyTraitRef}; use std::collections::HashSet; use std::collections::hash_map::Entry::{Occupied, Vacant}; use std::default::Default; @@ -21,15 +21,16 @@ use util::ppaux::Repr; use util::nodemap::NodeMap; use super::CodeAmbiguity; +use super::CodeProjectionError; use super::CodeSelectionError; use super::FulfillmentError; use super::Obligation; use super::ObligationCause; use super::PredicateObligation; -use super::Selection; +use super::project; use super::select::SelectionContext; -use super::poly_trait_ref_for_builtin_bound; use super::Unimplemented; +use super::util::predicate_for_builtin_bound; /// The fulfillment context is used to drive trait resolution. It /// consists of a list of obligations that must be (eventually) @@ -101,35 +102,41 @@ impl<'tcx> FulfillmentContext<'tcx> { } } + pub fn normalize_associated_type<'a>(&mut self, + infcx: &InferCtxt<'a,'tcx>, + trait_ref: Rc>, + item_name: ast::Name, + cause: ObligationCause<'tcx>) + -> Ty<'tcx> + { + assert!(!trait_ref.has_escaping_regions()); + + 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 }, + ty: ty_var + }); + let obligation = Obligation::new(cause, projection.as_predicate()); + self.register_predicate(infcx.tcx, obligation); + ty_var + } + pub fn register_builtin_bound(&mut self, tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>, builtin_bound: ty::BuiltinBound, cause: ObligationCause<'tcx>) { - match poly_trait_ref_for_builtin_bound(tcx, builtin_bound, ty) { - Ok(trait_ref) => { - self.register_trait_ref(tcx, trait_ref, cause); + match predicate_for_builtin_bound(tcx, cause, builtin_bound, 0, ty) { + Ok(predicate) => { + self.register_predicate(tcx, predicate); } Err(ErrorReported) => { } } } - pub fn register_trait_ref<'a>(&mut self, - tcx: &ty::ctxt<'tcx>, - trait_ref: Rc>, - cause: ObligationCause<'tcx>) - { - /*! - * A convenience function for registering trait obligations. - */ - - let trait_obligation = Obligation { cause: cause, - recursion_depth: 0, - predicate: ty::Predicate::Trait(trait_ref) }; - self.register_predicate(tcx, trait_obligation) - } - pub fn register_region_obligation(&mut self, tcx: &ty::ctxt<'tcx>, t_a: Ty<'tcx>, @@ -232,7 +239,7 @@ impl<'tcx> FulfillmentContext<'tcx> { debug!("select_where_possible({} obligations) iteration", count); - let mut selections = Vec::new(); + let mut new_obligations = Vec::new(); // If we are only attempting obligations we haven't seen yet, // then set `skip` to the number of obligations we've already @@ -253,7 +260,7 @@ impl<'tcx> FulfillmentContext<'tcx> { let processed = if skip == 0 { process_predicate(selcx, predicate, - &mut selections, &mut errors, region_obligations) + &mut new_obligations, &mut errors, region_obligations) } else { skip -= 1; false @@ -271,8 +278,8 @@ impl<'tcx> FulfillmentContext<'tcx> { // Now go through all the successful ones, // registering any nested obligations for the future. - for selection in selections.into_iter() { - selection.map_move_nested(|p| self.register_predicate(tcx, p)); + for new_obligation in new_obligations.into_iter() { + self.register_predicate(tcx, new_obligation); } } @@ -290,7 +297,7 @@ impl<'tcx> FulfillmentContext<'tcx> { fn process_predicate<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>, obligation: &PredicateObligation<'tcx>, - selections: &mut Vec>, + new_obligations: &mut Vec>, errors: &mut Vec>, region_obligations: &mut NodeMap>>) -> bool @@ -304,14 +311,14 @@ fn process_predicate<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>, let tcx = selcx.tcx(); match obligation.predicate { - ty::Predicate::Trait(ref trait_ref) => { - let trait_obligation = obligation.with(trait_ref.clone()); + ty::Predicate::Trait(ref data) => { + let trait_obligation = obligation.with(data.clone()); match selcx.select(&trait_obligation) { Ok(None) => { false } Ok(Some(s)) => { - selections.push(s); + s.map_move_nested(|p| new_obligations.push(p)); true } Err(selection_err) => { @@ -372,6 +379,111 @@ fn process_predicate<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>, } true } + + ty::Predicate::Projection(ref data) => { + let project_obligation = obligation.with(data.clone()); + let result = project::poly_project_and_unify_type(selcx, &project_obligation); + debug!("poly_project_and_unify_type({}) = {}", + project_obligation.repr(tcx), + result.repr(tcx)); + match result { + Ok(()) => { + true + } + Err(project::ProjectionError::TooManyCandidates) => { + // Without more type information, we can't say much. + false + } + Err(project::ProjectionError::NoCandidate) => { + // This means that we have a type like `::name = U` but we couldn't find any more + // information. This could just be that we're in a + // function like: + // + // fn foo(...) + // + // in which case this is not an error. But it + // might also mean we're in a situation where we + // don't actually know that `T : Trait` holds, + // which would be weird (e.g., if `T` was not a + // parameter type but a normal type, like `int`). + // + // So what we do is to (1) add a requirement that + // `T : Trait` (just in case) and (2) try to unify + // `U` with `::name`. + + if !ty::binds_late_bound_regions(selcx.tcx(), data) { + // Check that `T : Trait` holds. + let trait_ref = data.to_poly_trait_ref(); + new_obligations.push(obligation.with(trait_ref.as_predicate())); + + // Fallback to `::name`. If this + // fails, then the output must be at least + // somewhat constrained, and we cannot verify + // that constraint, so yield an error. + let ty_projection = ty::mk_projection(tcx, + (*trait_ref.0).clone(), + data.0.projection_ty.item_name); + + debug!("process_predicate: falling back to projection {}", + ty_projection.repr(selcx.tcx())); + + match infer::mk_eqty(selcx.infcx(), + true, + infer::EquatePredicate(obligation.cause.span), + ty_projection, + data.0.ty) { + Ok(()) => { } + Err(_) => { + debug!("process_predicate: fallback failed to unify; error"); + errors.push( + FulfillmentError::new( + obligation.clone(), + CodeSelectionError(Unimplemented))); + } + } + + true + } else { + // If we have something like + // + // for<'a> as Trait>::name == &'a int + // + // there is no "canonical form" for us to + // make, so just report the lack of candidates + // as an error. + + debug!("process_predicate: can't fallback, higher-ranked"); + errors.push( + FulfillmentError::new( + obligation.clone(), + CodeSelectionError(Unimplemented))); + + true + } + } + Err(project::ProjectionError::MismatchedTypes(e)) => { + errors.push( + FulfillmentError::new( + obligation.clone(), + CodeProjectionError(e))); + true + } + Err(project::ProjectionError::TraitSelectionError(e)) => { + // Extract just the `T : Trait` from `::Name == U`, so that when we report an + // error to the user, it says something like "`T : + // Trait` not satisfied".5D + let trait_predicate = data.to_poly_trait_ref(); + let trait_obligation = obligation.with(trait_predicate.as_predicate()); + errors.push( + FulfillmentError::new( + trait_obligation, + CodeSelectionError(e))); + true + } + } + } } } diff --git a/src/librustc/middle/traits/mod.rs b/src/librustc/middle/traits/mod.rs index 41c55abc9ae..b7e2304849a 100644 --- a/src/librustc/middle/traits/mod.rs +++ b/src/librustc/middle/traits/mod.rs @@ -18,28 +18,32 @@ pub use self::ObligationCauseCode::*; use middle::subst; use middle::ty::{mod, Ty}; use middle::infer::InferCtxt; -use std::rc::Rc; use std::slice::Iter; +use std::rc::Rc; use syntax::ast; use syntax::codemap::{Span, DUMMY_SP}; use util::ppaux::Repr; pub use self::error_reporting::report_fulfillment_errors; pub use self::fulfill::{FulfillmentContext, RegionObligation}; +pub use self::project::MismatchedProjectionTypes; +pub use self::project::project_type; +pub use self::project::ProjectionResult; pub use self::select::SelectionContext; pub use self::select::SelectionCache; pub use self::select::{MethodMatchResult, MethodMatched, MethodAmbiguous, MethodDidNotMatch}; pub use self::select::{MethodMatchedData}; // intentionally don't export variants pub use self::util::elaborate_predicates; +pub use self::util::trait_ref_for_builtin_bound; pub use self::util::supertraits; pub use self::util::Supertraits; pub use self::util::search_trait_and_supertraits_from_bound; pub use self::util::transitive_bounds; -pub use self::util::poly_trait_ref_for_builtin_bound; mod coherence; mod error_reporting; mod fulfill; +mod project; mod select; mod util; @@ -57,7 +61,7 @@ pub struct Obligation<'tcx, T> { } pub type PredicateObligation<'tcx> = Obligation<'tcx, ty::Predicate<'tcx>>; -pub type TraitObligation<'tcx> = Obligation<'tcx, Rc>>; +pub type TraitObligation<'tcx> = Obligation<'tcx, ty::PolyTraitPredicate<'tcx>>; /// Why did we incur this obligation? Used for error reporting. #[deriving(Clone)] @@ -107,9 +111,18 @@ pub enum ObligationCauseCode<'tcx> { // static items must have `Sync` type SharedStatic, - BuiltinDerivedObligation(Rc>, Rc>), + BuiltinDerivedObligation(DerivedObligationCause<'tcx>), - ImplDerivedObligation(Rc>, Rc>), + ImplDerivedObligation(DerivedObligationCause<'tcx>), +} + +#[deriving(Clone)] +pub struct DerivedObligationCause<'tcx> { + /// Resolving this trait led to the current obligation + parent_trait_ref: ty::PolyTraitRef<'tcx>, + + /// The parent trait had this cause + parent_code: Rc> } pub type Obligations<'tcx, O> = subst::VecPerParamSpace>; @@ -122,8 +135,8 @@ pub type Selection<'tcx> = Vtable<'tcx, PredicateObligation<'tcx>>; pub enum SelectionError<'tcx> { Unimplemented, Overflow, - OutputTypeParameterMismatch(Rc>, - Rc>, + OutputTypeParameterMismatch(ty::PolyTraitRef<'tcx>, + ty::PolyTraitRef<'tcx>, ty::type_err<'tcx>), } @@ -135,6 +148,7 @@ pub struct FulfillmentError<'tcx> { #[deriving(Clone)] pub enum FulfillmentErrorCode<'tcx> { CodeSelectionError(SelectionError<'tcx>), + CodeProjectionError(MismatchedProjectionTypes<'tcx>), CodeAmbiguity, } @@ -235,7 +249,7 @@ pub struct VtableBuiltinData { #[deriving(PartialEq,Eq,Clone)] pub struct VtableParamData<'tcx> { // In the above example, this would `Eq` - pub bound: Rc>, + pub bound: ty::PolyTraitRef<'tcx>, } /// True if neither the trait nor self type is local. Note that `impl_def_id` must refer to an impl @@ -324,12 +338,6 @@ impl<'tcx,O> Obligation<'tcx,O> { } } -impl<'tcx> TraitObligation<'tcx> { - pub fn self_ty(&self) -> Ty<'tcx> { - self.predicate.self_ty() - } -} - impl<'tcx> ObligationCause<'tcx> { pub fn new(span: Span, body_id: ast::NodeId, @@ -441,6 +449,13 @@ impl<'tcx> FulfillmentError<'tcx> { CodeAmbiguity => false, CodeSelectionError(Overflow) => true, CodeSelectionError(_) => false, + CodeProjectionError(_) => false, } } } + +impl<'tcx> TraitObligation<'tcx> { + fn self_ty(&self) -> Ty<'tcx> { + self.predicate.0.self_ty() + } +} diff --git a/src/librustc/middle/traits/project.rs b/src/librustc/middle/traits/project.rs new file mode 100644 index 00000000000..083227d02bd --- /dev/null +++ b/src/librustc/middle/traits/project.rs @@ -0,0 +1,374 @@ +// 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. + +//! Code for projecting associated types out of trait references. + +use super::elaborate_predicates; +use super::Obligation; +use super::PredicateObligation; +use super::SelectionContext; +use super::SelectionError; +use super::VtableImplData; + +use middle::infer; +use middle::subst::Subst; +use middle::ty::{mod, ToPolyTraitRef, Ty}; +use std::fmt; +use util::ppaux::Repr; + +pub type PolyProjectionObligation<'tcx> = + Obligation<'tcx, ty::PolyProjectionPredicate<'tcx>>; + +pub type ProjectionObligation<'tcx> = + Obligation<'tcx, ty::ProjectionPredicate<'tcx>>; + +pub type ProjectionTyObligation<'tcx> = + Obligation<'tcx, ty::ProjectionTy<'tcx>>; + +/// When attempting to resolve `::Name == U`... +pub enum ProjectionError<'tcx> { + NoCandidate, + TooManyCandidates, + + /// + MismatchedTypes(MismatchedProjectionTypes<'tcx>), + + /// ...an error occurred matching `T : TraitRef` + TraitSelectionError(SelectionError<'tcx>), +} + +#[deriving(Clone)] +pub struct MismatchedProjectionTypes<'tcx> { + pub err: ty::type_err<'tcx> // TODO expected/actual/etc +} + +pub type ProjectionResult<'tcx, T> = Result>; + +enum ProjectionTyCandidate<'tcx> { + ParamEnv(ty::PolyProjectionPredicate<'tcx>), + Impl(VtableImplData<'tcx, PredicateObligation<'tcx>>), +} + +struct ProjectionTyCandidateSet<'tcx> { + vec: Vec>, + ambiguous: bool +} + +pub fn poly_project_and_unify_type<'cx,'tcx>( + selcx: &mut SelectionContext<'cx,'tcx>, + obligation: &PolyProjectionObligation<'tcx>) + -> ProjectionResult<'tcx, ()> +{ + debug!("poly_project(obligation={})", + obligation.repr(selcx.tcx())); + + let infcx = selcx.infcx(); + + infcx.try(|snapshot| { + let (skol_predicate, skol_map) = + infcx.skolemize_late_bound_regions(&obligation.predicate, snapshot); + + let skol_obligation = obligation.with(skol_predicate); + let () = try!(project_and_unify_type(selcx, &skol_obligation)); + match infcx.leak_check(&skol_map, snapshot) { + Ok(()) => Ok(()), + Err(e) => Err(ProjectionError::MismatchedTypes(MismatchedProjectionTypes{err: e})), + } + }) +} + +/// Compute result of projecting an associated type and unify it with +/// `obligation.predicate.ty` (if we can). +pub fn project_and_unify_type<'cx,'tcx>( + selcx: &mut SelectionContext<'cx,'tcx>, + obligation: &ProjectionObligation<'tcx>) + -> ProjectionResult<'tcx, ()> +{ + debug!("project_and_unify(obligation={})", + obligation.repr(selcx.tcx())); + + let ty_obligation = obligation.with(obligation.predicate.projection_ty.clone()); + let projected_ty = try!(project_type(selcx, &ty_obligation)); + let infcx = selcx.infcx(); + let origin = infer::RelateOutputImplTypes(obligation.cause.span); + debug!("project_and_unify_type: projected_ty = {}", projected_ty.repr(selcx.tcx())); + match infer::mk_eqty(infcx, true, origin, projected_ty, obligation.predicate.ty) { + Ok(()) => Ok(()), + Err(e) => Err(ProjectionError::MismatchedTypes(MismatchedProjectionTypes{err: e})), + } +} + +/// Compute the result of a projection type (if we can). +pub fn project_type<'cx,'tcx>( + selcx: &mut SelectionContext<'cx,'tcx>, + obligation: &ProjectionTyObligation<'tcx>) + -> ProjectionResult<'tcx, Ty<'tcx>> +{ + debug!("project(obligation={})", + obligation.repr(selcx.tcx())); + + let mut candidates = ProjectionTyCandidateSet { + vec: Vec::new(), + ambiguous: false, + }; + + let () = assemble_candidates_from_param_env(selcx, + obligation, + &mut candidates); + + let () = try!(assemble_candidates_from_impls(selcx, + obligation, + &mut candidates)); + + debug!("{} candidates, ambiguous={}", + candidates.vec.len(), + candidates.ambiguous); + + // We probably need some winnowing logic similar to select here. + + if candidates.ambiguous || candidates.vec.len() > 1 { + return Err(ProjectionError::TooManyCandidates); + } + + match candidates.vec.pop() { + Some(candidate) => { + Ok(try!(confirm_candidate(selcx, obligation, candidate))) + } + None => { + Err(ProjectionError::NoCandidate) + } + } +} + +/// The first thing we have to do is scan through the parameter +/// environment to see whether there are any projection predicates +/// there that can answer this question. +fn assemble_candidates_from_param_env<'cx,'tcx>( + selcx: &mut SelectionContext<'cx,'tcx>, + obligation: &ProjectionTyObligation<'tcx>, + candidate_set: &mut ProjectionTyCandidateSet<'tcx>) +{ + let infcx = selcx.infcx(); + let env_predicates = selcx.param_env().caller_bounds.predicates.clone(); + let env_predicates = env_predicates.iter().cloned().collect(); + for predicate in elaborate_predicates(selcx.tcx(), env_predicates) { + match predicate { + ty::Predicate::Projection(ref data) => { + let is_match = infcx.probe(|_| { + let origin = infer::Misc(obligation.cause.span); + let obligation_poly_trait_ref = + obligation.predicate.trait_ref.to_poly_trait_ref(); + let data_poly_trait_ref = + data.to_poly_trait_ref(); + infcx.sub_poly_trait_refs(false, + origin, + obligation_poly_trait_ref, + data_poly_trait_ref).is_ok() + }); + + if is_match { + candidate_set.vec.push( + ProjectionTyCandidate::ParamEnv(data.clone())); + } + } + _ => { } + } + } +} + +fn assemble_candidates_from_impls<'cx,'tcx>( + selcx: &mut SelectionContext<'cx,'tcx>, + obligation: &ProjectionTyObligation<'tcx>, + candidate_set: &mut ProjectionTyCandidateSet<'tcx>) + -> ProjectionResult<'tcx, ()> +{ + // If we are resolving `>::Item == Type`, + // start out by selecting the predicate `T as TraitRef<...>`: + let trait_ref = + obligation.predicate.trait_ref.to_poly_trait_ref(); + let trait_obligation = + obligation.with(trait_ref.to_poly_trait_predicate()); + let vtable = match selcx.select(&trait_obligation) { + Ok(Some(vtable)) => vtable, + Ok(None) => { + candidate_set.ambiguous = true; + return Ok(()); + } + Err(e) => { + debug!("assemble_candidates_from_impls: selection error {}", + e.repr(selcx.tcx())); + return Err(ProjectionError::TraitSelectionError(e)); + } + }; + + match vtable { + super::VtableImpl(data) => { + candidate_set.vec.push( + ProjectionTyCandidate::Impl(data)); + } + super::VtableParam(..) => { + // This case tell us nothing about the value of an + // associated type. Consider: + // + // ``` + // trait SomeTrait { type Foo; } + // fn foo(...) { } + // ``` + // + // If the user writes `::Foo`, then the `T + // : SomeTrait` binding does not help us decide what the + // type `Foo` is (at least, not more specifically than + // what we already knew). + // + // But wait, you say! What about an example like this: + // + // ``` + // fn bar>(...) { ... } + // ``` + // + // Doesn't the `T : Sometrait` predicate help + // resolve `T::Foo`? And of course it does, but in fact + // that single predicate is desugared into two predicates + // in the compiler: a trait predicate (`T : SomeTrait`) and a + // projection. And the projection where clause is handled + // in `assemble_candidates_from_param_env`. + } + super::VtableBuiltin(..) | + super::VtableUnboxedClosure(..) | + super::VtableFnPointer(..) => { + // These traits have no associated types. + selcx.tcx().sess.span_bug( + obligation.cause.span, + format!("Cannot project an associated type from `{}`", + vtable.repr(selcx.tcx())).as_slice()); + } + } + + Ok(()) +} + +fn confirm_candidate<'cx,'tcx>( + selcx: &mut SelectionContext<'cx,'tcx>, + obligation: &ProjectionTyObligation<'tcx>, + candidate: ProjectionTyCandidate<'tcx>) + -> ProjectionResult<'tcx, Ty<'tcx>> +{ + let infcx = selcx.infcx(); + + debug!("confirm_candidate(candidate={}, obligation={})", + candidate.repr(infcx.tcx), + obligation.repr(infcx.tcx)); + + let projected_ty = match candidate { + ProjectionTyCandidate::ParamEnv(poly_projection) => { + let projection = + infcx.replace_late_bound_regions_with_fresh_var( + obligation.cause.span, + infer::LateBoundRegionConversionTime::HigherRankedType, + &poly_projection).0; + + assert_eq!(projection.projection_ty.item_name, + obligation.predicate.item_name); + + let origin = infer::RelateOutputImplTypes(obligation.cause.span); + match infcx.sub_trait_refs(false, + origin, + obligation.predicate.trait_ref.clone(), + projection.projection_ty.trait_ref.clone()) { + Ok(()) => { } + Err(e) => { + selcx.tcx().sess.span_bug( + obligation.cause.span, + format!("Failed to unify `{}` and `{}` in projection: {}", + obligation.repr(selcx.tcx()), + projection.repr(selcx.tcx()), + ty::type_err_to_str(selcx.tcx(), &e)).as_slice()); + } + } + + projection.ty + } + + ProjectionTyCandidate::Impl(impl_vtable) => { + // there don't seem to be nicer accessors to these: + let impl_items_map = selcx.tcx().impl_items.borrow(); + let impl_or_trait_items_map = selcx.tcx().impl_or_trait_items.borrow(); + + let impl_items = &impl_items_map[impl_vtable.impl_def_id]; + let mut impl_ty = None; + for impl_item in impl_items.iter() { + let assoc_type = match impl_or_trait_items_map[impl_item.def_id()] { + ty::TypeTraitItem(ref assoc_type) => assoc_type.clone(), + ty::MethodTraitItem(..) => { continue; } + }; + + if assoc_type.name != obligation.predicate.item_name { + continue; + } + + let impl_poly_ty = ty::lookup_item_type(selcx.tcx(), assoc_type.def_id); + impl_ty = Some(impl_poly_ty.ty.subst(selcx.tcx(), &impl_vtable.substs)); + break; + } + + match impl_ty { + Some(ty) => ty, + None => { + selcx.tcx().sess.span_bug( + obligation.cause.span, + format!("impl `{}` did not contain projection for `{}`", + impl_vtable.repr(selcx.tcx()), + obligation.repr(selcx.tcx())).as_slice()); + } + } + } + }; + + 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 { + ProjectionError::NoCandidate => + format!("NoCandidate"), + ProjectionError::TooManyCandidates => + format!("NoCandidate"), + ProjectionError::MismatchedTypes(ref m) => + format!("MismatchedTypes({})", m.repr(tcx)), + ProjectionError::TraitSelectionError(ref e) => + format!("TraitSelectionError({})", e.repr(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 { + ProjectionTyCandidate::ParamEnv(ref data) => + format!("ParamEnv({})", data.repr(tcx)), + ProjectionTyCandidate::Impl(ref data) => + format!("Impl({})", data.repr(tcx)) + } + } +} + diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs index a22a602ddff..2a3bb3c80c8 100644 --- a/src/librustc/middle/traits/select.rs +++ b/src/librustc/middle/traits/select.rs @@ -13,10 +13,11 @@ pub use self::MethodMatchResult::*; pub use self::MethodMatchedData::*; -use self::Candidate::*; +use self::SelectionCandidate::*; use self::BuiltinBoundConditions::*; use self::EvaluationResult::*; +use super::{DerivedObligationCause}; use super::{PredicateObligation, Obligation, TraitObligation, ObligationCause}; use super::{ObligationCauseCode, BuiltinDerivedObligation}; use super::{SelectionError, Unimplemented, Overflow, OutputTypeParameterMismatch}; @@ -29,7 +30,7 @@ use super::{util}; use middle::fast_reject; use middle::mem_categorization::Typer; use middle::subst::{Subst, Substs, VecPerParamSpace}; -use middle::ty::{mod, AsPredicate, RegionEscape, Ty}; +use middle::ty::{mod, AsPredicate, RegionEscape, ToPolyTraitRef, Ty}; use middle::infer; use middle::infer::{InferCtxt, TypeFreshener}; use middle::ty_fold::TypeFoldable; @@ -75,15 +76,15 @@ struct TraitObligationStack<'prev, 'tcx: 'prev> { /// Trait ref from `obligation` but skolemized with the /// selection-context's freshener. Used to check for recursion. - fresh_trait_ref: Rc>, + fresh_trait_ref: ty::PolyTraitRef<'tcx>, previous: Option<&'prev TraitObligationStack<'prev, 'tcx>> } #[deriving(Clone)] pub struct SelectionCache<'tcx> { - hashmap: RefCell>, - SelectionResult<'tcx, Candidate<'tcx>>>>, + hashmap: RefCell>, + SelectionResult<'tcx, SelectionCandidate<'tcx>>>>, } pub enum MethodMatchResult { @@ -128,7 +129,7 @@ pub enum MethodMatchedData { /// clauses can give additional information (like, the types of output /// parameters) that would have to be inferred from the impl. #[deriving(PartialEq,Eq,Show,Clone)] -enum Candidate<'tcx> { +enum SelectionCandidate<'tcx> { BuiltinCandidate(ty::BuiltinBound), ParamCandidate(VtableParamData<'tcx>), ImplCandidate(ast::DefId), @@ -144,8 +145,8 @@ enum Candidate<'tcx> { ErrorCandidate, } -struct CandidateSet<'tcx> { - vec: Vec>, +struct SelectionCandidateSet<'tcx> { + vec: Vec>, ambiguous: bool } @@ -193,6 +194,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.infcx } + pub fn param_env(&self) -> &'cx ty::ParameterEnvironment<'tcx> { + self.param_env + } + pub fn tcx(&self) -> &'cx ty::ctxt<'tcx> { self.infcx.tcx } @@ -302,6 +307,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // evaluating trait matches EvaluatedToOk } + + ty::Predicate::Projection(..) => { + // FIXME(#20296) -- we should be able to give a more precise answer here + EvaluatedToAmbig + } } } @@ -411,9 +421,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.infcx.probe(|snapshot| { let (skol_obligation_trait_ref, skol_map) = - self.infcx().skolemize_late_bound_regions(&*obligation.predicate, snapshot); + self.infcx().skolemize_late_bound_regions(&obligation.predicate, snapshot); match self.match_impl(impl_def_id, obligation, snapshot, - &skol_map, Rc::new(skol_obligation_trait_ref)) { + &skol_map, skol_obligation_trait_ref.trait_ref.clone()) { Ok(substs) => { let vtable_impl = self.vtable_impl(impl_def_id, substs, @@ -439,7 +449,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { fn candidate_from_obligation<'o>(&mut self, stack: &TraitObligationStack<'o, 'tcx>) - -> SelectionResult<'tcx, Candidate<'tcx>> + -> SelectionResult<'tcx, SelectionCandidate<'tcx>> { // Watch out for overflow. This intentionally bypasses (and does // not update) the cache. @@ -455,17 +465,17 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // separately rather than using `stack.fresh_trait_ref` -- this // is because we want the unbound variables to be replaced // with fresh skolemized types starting from index 0. - let cache_fresh_trait_ref = + let cache_fresh_trait_pred = self.infcx.freshen(stack.obligation.predicate.clone()); - debug!("candidate_from_obligation(cache_fresh_trait_ref={}, obligation={})", - cache_fresh_trait_ref.repr(self.tcx()), + debug!("candidate_from_obligation(cache_fresh_trait_pred={}, obligation={})", + cache_fresh_trait_pred.repr(self.tcx()), stack.repr(self.tcx())); assert!(!stack.obligation.predicate.has_escaping_regions()); - match self.check_candidate_cache(cache_fresh_trait_ref.clone()) { + match self.check_candidate_cache(&cache_fresh_trait_pred) { Some(c) => { - debug!("CACHE HIT: cache_fresh_trait_ref={}, candidate={}", - cache_fresh_trait_ref.repr(self.tcx()), + debug!("CACHE HIT: cache_fresh_trait_pred={}, candidate={}", + cache_fresh_trait_pred.repr(self.tcx()), c.repr(self.tcx())); return c; } @@ -474,17 +484,17 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // If no match, compute result and insert into cache. let candidate = self.candidate_from_obligation_no_cache(stack); - debug!("CACHE MISS: cache_fresh_trait_ref={}, candidate={}", - cache_fresh_trait_ref.repr(self.tcx()), candidate.repr(self.tcx())); - self.insert_candidate_cache(cache_fresh_trait_ref, candidate.clone()); + debug!("CACHE MISS: cache_fresh_trait_pred={}, candidate={}", + cache_fresh_trait_pred.repr(self.tcx()), candidate.repr(self.tcx())); + self.insert_candidate_cache(cache_fresh_trait_pred, candidate.clone()); candidate } fn candidate_from_obligation_no_cache<'o>(&mut self, stack: &TraitObligationStack<'o, 'tcx>) - -> SelectionResult<'tcx, Candidate<'tcx>> + -> SelectionResult<'tcx, SelectionCandidate<'tcx>> { - if ty::type_is_error(stack.obligation.self_ty()) { + if ty::type_is_error(stack.obligation.predicate.0.self_ty()) { return Ok(Some(ErrorCandidate)); } @@ -576,7 +586,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } fn pick_candidate_cache(&self, - cache_fresh_trait_ref: &Rc>) + cache_fresh_trait_pred: &ty::PolyTraitPredicate<'tcx>) -> &SelectionCache<'tcx> { // High-level idea: we have to decide whether to consult the @@ -598,7 +608,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // If the trait refers to any parameters in scope, then use // the cache of the param-environment. if - cache_fresh_trait_ref.0.input_types().iter().any( + cache_fresh_trait_pred.0.input_types().iter().any( |&t| ty::type_has_self(t) || ty::type_has_params(t)) { return &self.param_env.selection_cache; @@ -611,7 +621,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // See the discussion in doc.rs for more details. if !self.param_env.caller_bounds.is_empty() && - cache_fresh_trait_ref.0.input_types().iter().any( + cache_fresh_trait_pred.0.input_types().iter().any( |&t| ty::type_has_ty_infer(t)) { return &self.param_env.selection_cache; @@ -622,32 +632,32 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } fn check_candidate_cache(&mut self, - cache_fresh_trait_ref: Rc>) - -> Option>> + cache_fresh_trait_pred: &ty::PolyTraitPredicate<'tcx>) + -> Option>> { - let cache = self.pick_candidate_cache(&cache_fresh_trait_ref); + let cache = self.pick_candidate_cache(cache_fresh_trait_pred); let hashmap = cache.hashmap.borrow(); - hashmap.get(&cache_fresh_trait_ref).map(|c| (*c).clone()) + hashmap.get(&cache_fresh_trait_pred.0.trait_ref).map(|c| (*c).clone()) } fn insert_candidate_cache(&mut self, - cache_fresh_trait_ref: Rc>, - candidate: SelectionResult<'tcx, Candidate<'tcx>>) + cache_fresh_trait_pred: ty::PolyTraitPredicate<'tcx>, + candidate: SelectionResult<'tcx, SelectionCandidate<'tcx>>) { - let cache = self.pick_candidate_cache(&cache_fresh_trait_ref); + let cache = self.pick_candidate_cache(&cache_fresh_trait_pred); let mut hashmap = cache.hashmap.borrow_mut(); - hashmap.insert(cache_fresh_trait_ref, candidate); + hashmap.insert(cache_fresh_trait_pred.0.trait_ref.clone(), candidate); } fn assemble_candidates<'o>(&mut self, stack: &TraitObligationStack<'o, 'tcx>) - -> Result, SelectionError<'tcx>> + -> Result, SelectionError<'tcx>> { // Check for overflow. let TraitObligationStack { obligation, .. } = *stack; - let mut candidates = CandidateSet { + let mut candidates = SelectionCandidateSet { vec: Vec::new(), ambiguous: false }; @@ -658,7 +668,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { match self.tcx().lang_items.to_builtin_kind(obligation.predicate.def_id()) { Some(ty::BoundCopy) => { debug!("obligation self ty is {}", - obligation.self_ty().repr(self.tcx())); + obligation.predicate.0.self_ty().repr(self.tcx())); // If the user has asked for the older, compatibility // behavior, ignore user-defined impls here. This will @@ -707,7 +717,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { /// Never affects inference environment. fn assemble_candidates_from_caller_bounds(&mut self, obligation: &TraitObligation<'tcx>, - candidates: &mut CandidateSet<'tcx>) + candidates: &mut SelectionCandidateSet<'tcx>) -> Result<(),SelectionError<'tcx>> { debug!("assemble_candidates_from_caller_bounds({})", @@ -715,7 +725,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let caller_trait_refs: Vec<_> = self.param_env.caller_bounds.predicates.iter() - .filter_map(|o| o.to_trait()) + .filter_map(|o| o.to_opt_poly_trait_ref()) .collect(); let all_bounds = @@ -744,10 +754,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { /// unified during the confirmation step. fn assemble_unboxed_closure_candidates(&mut self, obligation: &TraitObligation<'tcx>, - candidates: &mut CandidateSet<'tcx>) + candidates: &mut SelectionCandidateSet<'tcx>) -> Result<(),SelectionError<'tcx>> { - let kind = match self.fn_family_trait_kind(obligation.predicate.def_id()) { + let kind = match self.fn_family_trait_kind(obligation.predicate.0.def_id()) { Some(k) => k, None => { return Ok(()); } }; @@ -789,7 +799,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { /// Implement one of the `Fn()` family for a fn pointer. fn assemble_fn_pointer_candidates(&mut self, obligation: &TraitObligation<'tcx>, - candidates: &mut CandidateSet<'tcx>) + candidates: &mut SelectionCandidateSet<'tcx>) -> Result<(),SelectionError<'tcx>> { // We provide a `Fn` impl for fn pointers. There is no need to provide @@ -827,16 +837,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { /// Search for impls that might apply to `obligation`. fn assemble_candidates_from_impls(&mut self, obligation: &TraitObligation<'tcx>, - candidate_vec: &mut Vec>) + candidate_vec: &mut Vec>) -> Result<(), SelectionError<'tcx>> { let all_impls = self.all_impls(obligation.predicate.def_id()); for &impl_def_id in all_impls.iter() { self.infcx.probe(|snapshot| { - let (skol_obligation_trait_ref, skol_map) = - self.infcx().skolemize_late_bound_regions(&*obligation.predicate, snapshot); + let (skol_obligation_trait_pred, skol_map) = + self.infcx().skolemize_late_bound_regions(&obligation.predicate, snapshot); match self.match_impl(impl_def_id, obligation, snapshot, - &skol_map, Rc::new(skol_obligation_trait_ref)) { + &skol_map, skol_obligation_trait_pred.trait_ref.clone()) { Ok(_) => { candidate_vec.push(ImplCandidate(impl_def_id)); } @@ -861,7 +871,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { /// scrutiny. fn winnow_candidate<'o>(&mut self, stack: &TraitObligationStack<'o, 'tcx>, - candidate: &Candidate<'tcx>) + candidate: &SelectionCandidate<'tcx>) -> EvaluationResult<'tcx> { debug!("winnow_candidate: candidate={}", candidate.repr(self.tcx())); @@ -918,8 +928,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { /// a case where doing the opposite caused us harm. fn candidate_should_be_dropped_in_favor_of<'o>(&mut self, stack: &TraitObligationStack<'o, 'tcx>, - candidate_i: &Candidate<'tcx>, - candidate_j: &Candidate<'tcx>) + candidate_i: &SelectionCandidate<'tcx>, + candidate_j: &SelectionCandidate<'tcx>) -> bool { match (candidate_i, candidate_j) { @@ -931,16 +941,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.infcx.probe(|snapshot| { let (skol_obligation_trait_ref, skol_map) = self.infcx().skolemize_late_bound_regions( - &*stack.obligation.predicate, snapshot); + &stack.obligation.predicate, snapshot); let impl_substs = self.rematch_impl(impl_def_id, stack.obligation, snapshot, - &skol_map, Rc::new(skol_obligation_trait_ref)); + &skol_map, skol_obligation_trait_ref.trait_ref.clone()); let impl_trait_ref = ty::impl_trait_ref(self.tcx(), impl_def_id).unwrap(); let impl_trait_ref = impl_trait_ref.subst(self.tcx(), &impl_substs); let poly_impl_trait_ref = - Rc::new(ty::Binder((*impl_trait_ref).clone())); + ty::Binder(impl_trait_ref); let origin = infer::RelateOutputImplTypes(stack.obligation.cause.span); self.infcx @@ -966,7 +976,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { fn assemble_builtin_bound_candidates<'o>(&mut self, bound: ty::BuiltinBound, stack: &TraitObligationStack<'o, 'tcx>, - candidates: &mut CandidateSet<'tcx>) + candidates: &mut SelectionCandidateSet<'tcx>) -> Result<(),SelectionError<'tcx>> { match self.builtin_bound(bound, stack.obligation) { @@ -987,7 +997,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation: &TraitObligation<'tcx>) -> Result,SelectionError<'tcx>> { - let self_ty = self.infcx.shallow_resolve(obligation.predicate.self_ty()); + // TODO seems like we ought to skolemize here, oder? + let self_ty = self.infcx.shallow_resolve(obligation.predicate.0.self_ty()); return match self_ty.sty { ty::ty_infer(ty::IntVar(_)) | ty::ty_infer(ty::FloatVar(_)) | @@ -1269,6 +1280,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { nominal(self, bound, def_id, types) } + ty::ty_projection(_) | ty::ty_param(_) => { // Note: A type parameter is only considered to meet a // particular bound if there is a where clause telling @@ -1360,7 +1372,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { fn confirm_candidate(&mut self, obligation: &TraitObligation<'tcx>, - candidate: Candidate<'tcx>) + candidate: SelectionCandidate<'tcx>) -> Result,SelectionError<'tcx>> { debug!("confirm_candidate({}, {})", @@ -1416,7 +1428,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // trait-ref. Repeat that unification now without any // transactional boundary; it should not fail. match self.confirm_poly_trait_refs(obligation.cause.clone(), - obligation.predicate.clone(), + obligation.predicate.to_poly_trait_ref(), param.bound.clone()) { Ok(()) => Ok(param), Err(_) => { @@ -1501,9 +1513,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // this time not in a probe. self.infcx.try(|snapshot| { let (skol_obligation_trait_ref, skol_map) = - self.infcx().skolemize_late_bound_regions(&*obligation.predicate, snapshot); - let substs = self.rematch_impl(impl_def_id, obligation, - snapshot, &skol_map, Rc::new(skol_obligation_trait_ref)); + self.infcx().skolemize_late_bound_regions(&obligation.predicate, snapshot); + let substs = + self.rematch_impl(impl_def_id, obligation, + snapshot, &skol_map, skol_obligation_trait_ref.trait_ref); debug!("confirm_impl_candidate substs={}", substs); Ok(self.vtable_impl(impl_def_id, substs, obligation.cause.clone(), obligation.recursion_depth + 1, skol_map, snapshot)) @@ -1574,13 +1587,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { vec![], vec![], self_ty); - let trait_ref = Rc::new(ty::Binder(ty::TraitRef { + let trait_ref = ty::Binder(Rc::new(ty::TraitRef { def_id: obligation.predicate.def_id(), substs: self.tcx().mk_substs(substs), })); try!(self.confirm_poly_trait_refs(obligation.cause.clone(), - obligation.predicate.clone(), + obligation.predicate.to_poly_trait_ref(), trait_ref)); Ok(self_ty) } @@ -1615,7 +1628,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { vec![], vec![], obligation.self_ty()); - let trait_ref = Rc::new(ty::Binder(ty::TraitRef { + let trait_ref = ty::Binder(Rc::new(ty::TraitRef { def_id: obligation.predicate.def_id(), substs: self.tcx().mk_substs(substs), })); @@ -1625,7 +1638,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { trait_ref.repr(self.tcx())); self.confirm_poly_trait_refs(obligation.cause.clone(), - obligation.predicate.clone(), + obligation.predicate.to_poly_trait_ref(), trait_ref) } @@ -1656,8 +1669,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { /// report an error to the user. fn confirm_poly_trait_refs(&mut self, obligation_cause: ObligationCause, - obligation_trait_ref: Rc>, - expected_trait_ref: Rc>) + obligation_trait_ref: ty::PolyTraitRef<'tcx>, + expected_trait_ref: ty::PolyTraitRef<'tcx>) -> Result<(), SelectionError<'tcx>> { let origin = infer::RelateOutputImplTypes(obligation_cause.span); @@ -1770,7 +1783,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // substitution if we find that any of the input types, when // simplified, do not match. - obligation.predicate.input_types().iter() + obligation.predicate.0.input_types().iter() .zip(impl_trait_ref.input_types().iter()) .any(|(&obligation_ty, &impl_ty)| { let simplified_obligation_ty = @@ -1786,7 +1799,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { fn match_where_clause(&mut self, obligation: &TraitObligation<'tcx>, - where_clause_trait_ref: Rc>) + where_clause_trait_ref: ty::PolyTraitRef<'tcx>) -> Result<(),()> { debug!("match_where_clause: obligation={} where_clause_trait_ref={}", @@ -1797,7 +1810,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { match self.infcx.sub_poly_trait_refs(false, origin, where_clause_trait_ref, - obligation.predicate.clone()) { + obligation.predicate.to_poly_trait_ref()) { Ok(()) => Ok(()), Err(_) => Err(()), } @@ -1879,7 +1892,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation: &'o TraitObligation<'tcx>) -> TraitObligationStack<'o, 'tcx> { - let fresh_trait_ref = obligation.predicate.fold_with(&mut self.freshener); + let fresh_trait_ref = + obligation.predicate.to_poly_trait_ref().fold_with(&mut self.freshener); TraitObligationStack { obligation: obligation, @@ -1932,9 +1946,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { #[allow(unused_comparisons)] fn derived_cause(&self, obligation: &TraitObligation<'tcx>, - variant: fn(Rc>>, - Rc>) - -> ObligationCauseCode<'tcx>) + variant: fn(DerivedObligationCause<'tcx>) -> ObligationCauseCode<'tcx>) -> ObligationCause<'tcx> { /*! @@ -1951,17 +1963,20 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // chain. Ideally, we should have a way to configure this either // by using -Z verbose or just a CLI argument. if obligation.recursion_depth >= 0 { + let derived_cause = DerivedObligationCause { + parent_trait_ref: obligation.predicate.to_poly_trait_ref(), + parent_code: Rc::new(obligation.cause.code.clone()), + }; ObligationCause::new(obligation.cause.span, - obligation.trait_ref.def_id().node, - variant(obligation.trait_ref.clone(), - Rc::new(obligation.cause.code.clone()))) + obligation.cause.body_id, + variant(derived_cause)) } else { obligation.cause.clone() } } } -impl<'tcx> Repr<'tcx> for Candidate<'tcx> { +impl<'tcx> Repr<'tcx> for SelectionCandidate<'tcx> { fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String { match *self { ErrorCandidate => format!("ErrorCandidate"), @@ -2021,8 +2036,7 @@ impl<'tcx> EvaluationResult<'tcx> { EvaluatedToOk | EvaluatedToAmbig | EvaluatedToErr(Overflow) | - EvaluatedToErr(OutputTypeParameterMismatch(..)) | - EvaluatedToErr(ProjectionMismatch(..)) => { + EvaluatedToErr(OutputTypeParameterMismatch(..)) => { true } EvaluatedToErr(Unimplemented) => { diff --git a/src/librustc/middle/traits/util.rs b/src/librustc/middle/traits/util.rs index 6b95e983e88..00995e1ee43 100644 --- a/src/librustc/middle/traits/util.rs +++ b/src/librustc/middle/traits/util.rs @@ -10,7 +10,7 @@ use middle::subst::{Subst, Substs, VecPerParamSpace}; use middle::infer::InferCtxt; -use middle::ty::{mod, Ty}; +use middle::ty::{mod, Ty, AsPredicate, ToPolyTraitRef}; use std::collections::HashSet; use std::fmt; use std::rc::Rc; @@ -46,19 +46,19 @@ struct StackEntry<'tcx> { pub fn elaborate_trait_ref<'cx, 'tcx>( tcx: &'cx ty::ctxt<'tcx>, - trait_ref: Rc>) + trait_ref: ty::PolyTraitRef<'tcx>) -> Elaborator<'cx, 'tcx> { - elaborate_predicates(tcx, vec![ty::Predicate::Trait(trait_ref)]) + elaborate_predicates(tcx, vec![trait_ref.as_predicate()]) } pub fn elaborate_trait_refs<'cx, 'tcx>( tcx: &'cx ty::ctxt<'tcx>, - trait_refs: &[Rc>]) + trait_refs: &[ty::PolyTraitRef<'tcx>]) -> Elaborator<'cx, 'tcx> { let predicates = trait_refs.iter() - .map(|trait_ref| ty::Predicate::Trait((*trait_ref).clone())) + .map(|trait_ref| trait_ref.as_predicate()) .collect(); elaborate_predicates(tcx, predicates) } @@ -80,21 +80,28 @@ pub fn elaborate_predicates<'cx, 'tcx>( impl<'cx, 'tcx> Elaborator<'cx, 'tcx> { fn push(&mut self, predicate: &ty::Predicate<'tcx>) { match *predicate { - ty::Predicate::Trait(ref trait_ref) => { + ty::Predicate::Trait(ref data) => { let mut predicates = - ty::predicates_for_trait_ref(self.tcx, &**trait_ref); + ty::predicates_for_trait_ref(self.tcx, + &data.to_poly_trait_ref()); // Only keep those bounds that we haven't already // seen. This is necessary to prevent infinite // recursion in some cases. One common case is when // people define `trait Sized { }` rather than `trait // Sized for Sized? { }`. - predicates.retain(|r| self.visited.insert((*r).clone())); + predicates.retain(|r| self.visited.insert(r.clone())); self.stack.push(StackEntry { position: 0, predicates: predicates }); } ty::Predicate::Equate(..) => { + // Currently, we do not "elaborate" predicates like + // `X == Y`, though conceivably we might. For example, + // `&X == &Y` implies that `X == Y`. + } + ty::Predicate::Projection(..) => { + // Nothing to elaborate in a projection predicate. } ty::Predicate::RegionOutlives(..) | ty::Predicate::TypeOutlives(..) => { @@ -173,7 +180,7 @@ pub struct Supertraits<'cx, 'tcx:'cx> { } pub fn supertraits<'cx, 'tcx>(tcx: &'cx ty::ctxt<'tcx>, - trait_ref: Rc>) + trait_ref: ty::PolyTraitRef<'tcx>) -> Supertraits<'cx, 'tcx> { let elaborator = elaborate_trait_ref(tcx, trait_ref); @@ -181,26 +188,24 @@ pub fn supertraits<'cx, 'tcx>(tcx: &'cx ty::ctxt<'tcx>, } pub fn transitive_bounds<'cx, 'tcx>(tcx: &'cx ty::ctxt<'tcx>, - bounds: &[Rc>]) + bounds: &[ty::PolyTraitRef<'tcx>]) -> Supertraits<'cx, 'tcx> { let elaborator = elaborate_trait_refs(tcx, bounds); Supertraits { elaborator: elaborator } } -impl<'cx, 'tcx> Iterator>> for Supertraits<'cx, 'tcx> { - fn next(&mut self) -> Option>> { +impl<'cx, 'tcx> Iterator> for Supertraits<'cx, 'tcx> { + fn next(&mut self) -> Option> { loop { match self.elaborator.next() { None => { return None; } - Some(ty::Predicate::Trait(trait_ref)) => { - return Some(trait_ref); + Some(ty::Predicate::Trait(data)) => { + return Some(data.to_poly_trait_ref()); } - Some(ty::Predicate::Equate(..)) | - Some(ty::Predicate::RegionOutlives(..)) | - Some(ty::Predicate::TypeOutlives(..)) => { + Some(_) => { } } } @@ -265,18 +270,18 @@ pub fn predicates_for_generics<'tcx>(tcx: &ty::ctxt<'tcx>, }) } -pub fn poly_trait_ref_for_builtin_bound<'tcx>( +pub fn trait_ref_for_builtin_bound<'tcx>( tcx: &ty::ctxt<'tcx>, builtin_bound: ty::BuiltinBound, param_ty: Ty<'tcx>) - -> Result>, ErrorReported> + -> Result>, ErrorReported> { match tcx.lang_items.from_builtin_kind(builtin_bound) { Ok(def_id) => { - Ok(Rc::new(ty::Binder(ty::TraitRef { + Ok(Rc::new(ty::TraitRef { def_id: def_id, substs: tcx.mk_substs(Substs::empty().with_self_ty(param_ty)) - }))) + })) } Err(e) => { tcx.sess.err(e.as_slice()); @@ -293,11 +298,11 @@ pub fn predicate_for_builtin_bound<'tcx>( param_ty: Ty<'tcx>) -> Result, ErrorReported> { - let trait_ref = try!(poly_trait_ref_for_builtin_bound(tcx, builtin_bound, param_ty)); + let trait_ref = try!(trait_ref_for_builtin_bound(tcx, builtin_bound, param_ty)); Ok(Obligation { cause: cause, recursion_depth: recursion_depth, - predicate: ty::Predicate::Trait(trait_ref), + predicate: trait_ref.as_predicate(), }) } @@ -306,7 +311,7 @@ pub fn predicate_for_builtin_bound<'tcx>( /// true, where `d` is the def-id of the trait/supertrait. If any is found, return `Some(p)` where /// `p` is the path to that trait/supertrait. Else `None`. pub fn search_trait_and_supertraits_from_bound<'tcx,F>(tcx: &ty::ctxt<'tcx>, - caller_bound: Rc>, + caller_bound: ty::PolyTraitRef<'tcx>, mut test: F) -> Option> where F: FnMut(ast::DefId) -> bool, @@ -390,12 +395,6 @@ impl<'tcx> Repr<'tcx> for super::SelectionError<'tcx> { a.repr(tcx), b.repr(tcx), c.repr(tcx)), - - super::ProjectionMismatch(ref a, ref b, ref c) => - format!("PrjectionMismatch({},{},{})", - a.repr(tcx), - b.repr(tcx), - c.repr(tcx)), } } } @@ -412,6 +411,7 @@ impl<'tcx> Repr<'tcx> for super::FulfillmentErrorCode<'tcx> { fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String { match *self { super::CodeSelectionError(ref o) => o.repr(tcx), + super::CodeProjectionError(ref o) => o.repr(tcx), super::CodeAmbiguity => format!("Ambiguity") } } @@ -421,6 +421,7 @@ impl<'tcx> fmt::Show for super::FulfillmentErrorCode<'tcx> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { super::CodeSelectionError(ref e) => write!(f, "{}", e), + super::CodeProjectionError(ref e) => write!(f, "{}", e), super::CodeAmbiguity => write!(f, "Ambiguity") } } @@ -431,3 +432,4 @@ impl<'tcx> Repr<'tcx> for ty::type_err<'tcx> { ty::type_err_to_str(tcx, self) } } + diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 8a0e5ea0bb3..da65feb8fd3 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -587,7 +587,7 @@ pub enum vtable_origin<'tcx> { // For every explicit cast into an object type, maps from the cast // expr to the associated trait ref. -pub type ObjectCastMap<'tcx> = RefCell>>>; +pub type ObjectCastMap<'tcx> = RefCell>>; /// A restriction that certain types must be the same size. The use of /// `transmute` gives rise to these restrictions. These generally @@ -843,6 +843,7 @@ bitflags! { const HAS_RE_LATE_BOUND = 0b10000, const HAS_REGIONS = 0b100000, const HAS_TY_ERR = 0b1000000, + const HAS_PROJECTION = 0b10000000, const NEEDS_SUBST = HAS_PARAMS.bits | HAS_SELF.bits | HAS_REGIONS.bits, } } @@ -989,6 +990,9 @@ pub fn type_has_ty_infer(ty: Ty) -> bool { pub fn type_needs_infer(ty: Ty) -> bool { ty.flags.intersects(HAS_TY_INFER | HAS_RE_INFER) } +pub fn type_has_projection(ty: Ty) -> bool { + ty.flags.intersects(HAS_PROJECTION) +} pub fn type_has_late_bound_regions(ty: Ty) -> bool { ty.flags.intersects(HAS_RE_LATE_BOUND) @@ -1354,7 +1358,9 @@ pub enum sty<'tcx> { ty_tup(Vec>), + ty_projection(Box>), ty_param(ParamTy), // type parameter + ty_open(Ty<'tcx>), // A deref'ed fat pointer, i.e., a dynamically sized value // and its size. Only ever used in trans. It is not necessary // earlier since we don't need to distinguish a DST with its @@ -1370,22 +1376,30 @@ pub enum sty<'tcx> { #[deriving(Clone, PartialEq, Eq, Hash, Show)] pub struct TyTrait<'tcx> { // Principal trait reference. - pub principal: PolyTraitRef<'tcx>, + pub principal: ty::Binder>, pub bounds: ExistentialBounds } impl<'tcx> TyTrait<'tcx> { + pub fn principal_def_id(&self) -> ast::DefId { + self.principal.0.def_id + } + /// Object types don't have a self-type specified. Therefore, when /// we convert the principal trait-ref into a normal trait-ref, /// you must give *some* self-type. A common choice is `mk_err()` /// or some skolemized type. pub fn principal_trait_ref_with_self_ty(&self, - tcx: &ctxt<'tcx>, self_ty: Ty<'tcx>) - -> Rc> + tcx: &ctxt<'tcx>, + self_ty: Ty<'tcx>) + -> ty::PolyTraitRef<'tcx> { - Rc::new(ty::Binder(ty::TraitRef { - def_id: self.principal.def_id(), - substs: tcx.mk_substs(self.principal.substs().with_self_ty(self_ty)), + // otherwise the escaping regions would be captured by the binder + assert!(!self_ty.has_escaping_regions()); + + ty::Binder(Rc::new(ty::TraitRef { + def_id: self.principal.0.def_id, + substs: tcx.mk_substs(self.principal.0.substs.with_self_ty(self_ty)), })) } } @@ -1411,7 +1425,7 @@ pub struct TraitRef<'tcx> { pub substs: &'tcx Substs<'tcx>, } -pub type PolyTraitRef<'tcx> = Binder>; +pub type PolyTraitRef<'tcx> = Binder>>; impl<'tcx> PolyTraitRef<'tcx> { pub fn self_ty(&self) -> Ty<'tcx> { @@ -1429,6 +1443,17 @@ impl<'tcx> PolyTraitRef<'tcx> { pub fn input_types(&self) -> &[Ty<'tcx>] { self.0.input_types() } + + pub fn to_poly_trait_predicate(&self) -> PolyTraitPredicate<'tcx> { + // Note that we preserve binding levels + Binder(TraitPredicate { trait_ref: self.0.clone() }) + } + + pub fn remove_rc(&self) -> ty::Binder> { + // Annoyingly, we can't easily put a `Rc` into a `sty` structure, + // and hence we have to remove the rc to put this into a `TyTrait`. + ty::Binder((*self.0).clone()) + } } /// Binder is a binder for higher-ranked lifetimes. It is part of the @@ -1501,7 +1526,8 @@ pub enum type_err<'tcx> { pub struct ParamBounds<'tcx> { pub region_bounds: Vec, pub builtin_bounds: BuiltinBounds, - pub trait_bounds: Vec>> + pub trait_bounds: Vec>, + pub projection_bounds: Vec>, } /// Bounds suitable for an existentially quantified type parameter @@ -1672,7 +1698,6 @@ pub struct TypeParameterDef<'tcx> { pub def_id: ast::DefId, pub space: subst::ParamSpace, pub index: u32, - pub associated_with: Option, pub bounds: ParamBounds<'tcx>, pub default: Option>, } @@ -1731,7 +1756,7 @@ pub enum Predicate<'tcx> { /// Corresponds to `where Foo : Bar`. `Foo` here would be /// the `Self` type of the trait reference and `A`, `B`, and `C` /// would be the parameters in the `TypeSpace`. - Trait(Rc>), + Trait(PolyTraitPredicate<'tcx>), /// where `T1 == T2`. Equate(PolyEquatePredicate<'tcx>), @@ -1741,6 +1766,35 @@ pub enum Predicate<'tcx> { /// where T : 'a TypeOutlives(PolyTypeOutlivesPredicate<'tcx>), + + /// + Projection(PolyProjectionPredicate<'tcx>), +} + +#[deriving(Clone, PartialEq, Eq, Hash, Show)] +pub struct TraitPredicate<'tcx> { + pub trait_ref: Rc> +} +pub type PolyTraitPredicate<'tcx> = ty::Binder>; + +impl<'tcx> TraitPredicate<'tcx> { + pub fn def_id(&self) -> ast::DefId { + self.trait_ref.def_id + } + + pub fn input_types(&self) -> &[Ty<'tcx>] { + self.trait_ref.substs.types.as_slice() + } + + pub fn self_ty(&self) -> Ty<'tcx> { + self.trait_ref.self_ty() + } +} + +impl<'tcx> PolyTraitPredicate<'tcx> { + pub fn def_id(&self) -> ast::DefId { + self.0.def_id() + } } #[deriving(Clone, PartialEq, Eq, Hash, Show)] @@ -1753,13 +1807,90 @@ pub type PolyOutlivesPredicate = ty::Binder>; pub type PolyRegionOutlivesPredicate = PolyOutlivesPredicate; pub type PolyTypeOutlivesPredicate<'tcx> = PolyOutlivesPredicate, ty::Region>; +/// This kind of predicate has no *direct* correspondent in the +/// syntax, but it roughly corresponds to the syntactic forms: +/// +/// 1. `T : TraitRef<..., Item=Type>` +/// 2. `>::Item == Type` (NYI) +/// +/// In particular, form #1 is "desugared" to the combination of a +/// normal trait predicate (`T : TraitRef<...>`) and one of these +/// predicates. Form #2 is a broader form in that it also permits +/// equality between arbitrary types. Processing an instance of Form +/// #2 eventually yields one of these `ProjectionPredicate` +/// instances to normalize the LHS. +#[deriving(Clone, PartialEq, Eq, Hash, Show)] +pub struct ProjectionPredicate<'tcx> { + pub projection_ty: ProjectionTy<'tcx>, + pub ty: Ty<'tcx>, +} + +pub type PolyProjectionPredicate<'tcx> = Binder>; + +#[deriving(Clone, PartialEq, Eq, Hash, Show)] +pub struct ProjectionTy<'tcx> { + pub trait_ref: Rc>, + pub item_name: ast::Name, +} + +// Annoying: a version of `ProjectionTy` that avoids the `Rc`, because +// it is difficult to place an `Rc` in the `sty` struct. Eventually +// these two types ought to be unified. +#[deriving(Clone, PartialEq, Eq, Hash, Show)] +pub struct TyProjection<'tcx> { + pub trait_ref: ty::TraitRef<'tcx>, + pub item_name: ast::Name, +} + +pub trait ToPolyTraitRef<'tcx> { + fn to_poly_trait_ref(&self) -> PolyTraitRef<'tcx>; +} + +impl<'tcx> ToPolyTraitRef<'tcx> for Rc> { + fn to_poly_trait_ref(&self) -> PolyTraitRef<'tcx> { + assert!(!self.has_escaping_regions()); + ty::Binder(self.clone()) + } +} + +impl<'tcx> ToPolyTraitRef<'tcx> for PolyTraitPredicate<'tcx> { + fn to_poly_trait_ref(&self) -> PolyTraitRef<'tcx> { + // We are just preserving the binder levels here + ty::Binder(self.0.trait_ref.clone()) + } +} + +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.clone()) + } +} + pub trait AsPredicate<'tcx> { fn as_predicate(&self) -> Predicate<'tcx>; } -impl<'tcx> AsPredicate<'tcx> for Rc> { +impl<'tcx> AsPredicate<'tcx> for Rc> { fn as_predicate(&self) -> Predicate<'tcx> { - Predicate::Trait(self.clone()) + // we're about to add a binder, so let's check that we don't + // accidentally capture anything, or else that might be some + // weird debruijn accounting. + assert!(!self.has_escaping_regions()); + + ty::Predicate::Trait(ty::Binder(ty::TraitPredicate { + trait_ref: self.clone() + })) + } +} + +impl<'tcx> AsPredicate<'tcx> for PolyTraitRef<'tcx> { + fn as_predicate(&self) -> Predicate<'tcx> { + ty::Predicate::Trait(self.to_poly_trait_predicate()) } } @@ -1781,6 +1912,12 @@ impl<'tcx> AsPredicate<'tcx> for PolyTypeOutlivesPredicate<'tcx> { } } +impl<'tcx> AsPredicate<'tcx> for PolyProjectionPredicate<'tcx> { + fn as_predicate(&self) -> Predicate<'tcx> { + Predicate::Projection(self.clone()) + } +} + impl<'tcx> Predicate<'tcx> { pub fn has_escaping_regions(&self) -> bool { match *self { @@ -1788,14 +1925,16 @@ impl<'tcx> Predicate<'tcx> { Predicate::Equate(ref p) => p.has_escaping_regions(), Predicate::RegionOutlives(ref p) => p.has_escaping_regions(), Predicate::TypeOutlives(ref p) => p.has_escaping_regions(), + Predicate::Projection(ref p) => p.has_escaping_regions(), } } - pub fn to_trait(&self) -> Option>> { + pub fn to_opt_poly_trait_ref(&self) -> Option> { match *self { Predicate::Trait(ref t) => { - Some(t.clone()) + Some(t.to_poly_trait_ref()) } + Predicate::Projection(..) | Predicate::Equate(..) | Predicate::RegionOutlives(..) | Predicate::TypeOutlives(..) => { @@ -2032,7 +2171,12 @@ pub struct TraitDef<'tcx> { /// The "supertrait" bounds. pub bounds: ParamBounds<'tcx>, + pub trait_ref: Rc>, + + /// A list of the associated types defined in this trait. Useful + /// for resolving `X::Foo` type markers. + pub associated_type_names: Vec, } /// Records the substitutions used to translate the polytype for an @@ -2330,9 +2474,14 @@ impl FlagComputation { self.add_substs(substs); } + &ty_projection(ref data) => { + self.add_flags(HAS_PROJECTION); + self.add_substs(&data.trait_ref.substs); + } + &ty_trait(box TyTrait { ref principal, ref bounds }) => { let mut computation = FlagComputation::new(); - computation.add_substs(principal.substs()); + computation.add_substs(&principal.0.substs); self.add_bound_computation(&computation); self.add_bounds(bounds); @@ -2540,9 +2689,8 @@ pub fn mk_ctor_fn<'tcx>(cx: &ctxt<'tcx>, })) } - pub fn mk_trait<'tcx>(cx: &ctxt<'tcx>, - principal: ty::PolyTraitRef<'tcx>, + principal: ty::Binder>, bounds: ExistentialBounds) -> Ty<'tcx> { // take a copy of substs so that we own the vectors inside @@ -2553,6 +2701,15 @@ pub fn mk_trait<'tcx>(cx: &ctxt<'tcx>, mk_t(cx, ty_trait(inner)) } +pub fn mk_projection<'tcx>(cx: &ctxt<'tcx>, + trait_ref: ty::TraitRef<'tcx>, + item_name: ast::Name) + -> Ty<'tcx> { + // take a copy of substs so that we own the vectors inside + let inner = box TyProjection { trait_ref: trait_ref, item_name: item_name }; + mk_t(cx, ty_projection(inner)) +} + pub fn mk_struct<'tcx>(cx: &ctxt<'tcx>, struct_id: ast::DefId, substs: &'tcx Substs<'tcx>) -> Ty<'tcx> { // take a copy of substs so that we own the vectors inside @@ -2615,7 +2772,12 @@ pub fn maybe_walk_ty<'tcx>(ty: Ty<'tcx>, f: |Ty<'tcx>| -> bool) { maybe_walk_ty(tm.ty, f); } ty_trait(box TyTrait { ref principal, .. }) => { - for subty in principal.substs().types.iter() { + for subty in principal.0.substs.types.iter() { + maybe_walk_ty(*subty, |x| f(x)); + } + } + ty_projection(box TyProjection { ref trait_ref, .. }) => { + for subty in trait_ref.substs.types.iter() { maybe_walk_ty(*subty, |x| f(x)); } } @@ -2693,6 +2855,7 @@ impl<'tcx> ParamBounds<'tcx> { builtin_bounds: empty_builtin_bounds(), trait_bounds: Vec::new(), region_bounds: Vec::new(), + projection_bounds: Vec::new(), } } } @@ -3191,6 +3354,7 @@ pub fn type_contents<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> TypeContents { apply_lang_items(cx, did, res) } + ty_projection(..) | ty_param(_) => { TC::All } @@ -3372,6 +3536,7 @@ pub fn is_instantiable<'tcx>(cx: &ctxt<'tcx>, r_ty: Ty<'tcx>) -> bool { ty_infer(_) | ty_err | ty_param(_) | + ty_projection(_) | ty_vec(_, None) => { false } @@ -4448,7 +4613,7 @@ pub fn ty_sort_string<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> String { ty_bare_fn(None, _) => "fn pointer".to_string(), ty_closure(_) => "fn".to_string(), ty_trait(ref inner) => { - format!("trait {}", item_path_str(cx, inner.principal.def_id())) + format!("trait {}", item_path_str(cx, inner.principal_def_id())) } ty_struct(id, _) => { format!("struct {}", item_path_str(cx, id)) @@ -4460,6 +4625,7 @@ pub fn ty_sort_string<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> String { ty_infer(FloatVar(_)) => "floating-point variable".to_string(), ty_infer(FreshTy(_)) => "skolemized type".to_string(), ty_infer(FreshIntTy(_)) => "skolemized integral type".to_string(), + ty_projection(_) => "associated type".to_string(), ty_param(ref p) => { if p.space == subst::SelfSpace { "Self".to_string() @@ -4871,7 +5037,7 @@ pub fn try_add_builtin_trait( pub fn ty_to_def_id(ty: Ty) -> Option { match ty.sty { ty_trait(ref tt) => - Some(tt.principal.def_id()), + Some(tt.principal_def_id()), ty_struct(id, _) | ty_enum(id, _) | ty_unboxed_closure(id, _, _) => @@ -5128,7 +5294,12 @@ pub fn lookup_trait_def<'tcx>(cx: &ctxt<'tcx>, did: ast::DefId) } /// Given a reference to a trait, returns the "superbounds" declared -/// on the trait, with appropriate substitutions applied. +/// on the trait, with appropriate substitutions applied. Basically, +/// this applies a filter to the where clauses on the trait, returning +/// those that have the form: +/// +/// Self : SuperTrait<...> +/// Self : 'region pub fn predicates_for_trait_ref<'tcx>(tcx: &ctxt<'tcx>, trait_ref: &PolyTraitRef<'tcx>) -> Vec> @@ -5205,13 +5376,7 @@ pub fn predicates_for_trait_ref<'tcx>(tcx: &ctxt<'tcx>, let trait_bounds: Vec<_> = trait_def.bounds.trait_bounds .iter() - .map(|bound_trait_ref| { - let substs = tcx.mk_substs(bound_trait_ref.substs().subst(tcx, trait_ref.substs())); - ty::Binder( - ty::TraitRef::new(bound_trait_ref.def_id(), - substs)) - }) - .map(|bound_trait_ref| Rc::new(bound_trait_ref)) + .map(|poly_trait_ref| ty::Binder(poly_trait_ref.0.subst(tcx, trait_ref.substs()))) .collect(); debug!("bounds_for_trait_ref: trait_bounds={}", @@ -5228,6 +5393,11 @@ pub fn predicates_for_trait_ref<'tcx>(tcx: &ctxt<'tcx>, trait_bounds: trait_bounds, region_bounds: region_bounds, builtin_bounds: builtin_bounds, + + // FIXME(#19451) -- if a trait has a bound like `trait Foo : + // Bar`, we should probably be returning that, but this + // code here will just ignore it. + projection_bounds: Vec::new(), }; predicates(tcx, trait_ref.self_ty(), &bounds) @@ -5242,7 +5412,7 @@ pub fn predicates<'tcx>( let mut vec = Vec::new(); for builtin_bound in bounds.builtin_bounds.iter() { - match traits::poly_trait_ref_for_builtin_bound(tcx, builtin_bound, param_ty) { + match traits::trait_ref_for_builtin_bound(tcx, builtin_bound, param_ty) { Ok(trait_ref) => { vec.push(trait_ref.as_predicate()); } Err(ErrorReported) => { } } @@ -5259,6 +5429,10 @@ pub fn predicates<'tcx>( vec.push(bound_trait_ref.as_predicate()); } + for projection in bounds.projection_bounds.iter() { + vec.push(projection.as_predicate()); + } + vec } @@ -5594,10 +5768,10 @@ pub fn eval_repeat_count(tcx: &ctxt, count_expr: &ast::Expr) -> uint { // relation on the supertraits from each bounded trait's constraint // list. pub fn each_bound_trait_and_supertraits<'tcx, F>(tcx: &ctxt<'tcx>, - bounds: &[Rc>], + bounds: &[PolyTraitRef<'tcx>], mut f: F) -> bool where - F: FnMut(Rc>) -> bool, + F: FnMut(PolyTraitRef<'tcx>) -> bool, { for bound_trait_ref in traits::transitive_bounds(tcx, bounds) { if !f(bound_trait_ref) { @@ -5607,10 +5781,11 @@ pub fn each_bound_trait_and_supertraits<'tcx, F>(tcx: &ctxt<'tcx>, return true; } -pub fn object_region_bounds<'tcx>(tcx: &ctxt<'tcx>, - opt_principal: Option<&PolyTraitRef<'tcx>>, // None for closures - others: BuiltinBounds) - -> Vec +pub fn object_region_bounds<'tcx>( + tcx: &ctxt<'tcx>, + opt_principal: Option<&Binder>>, // None for closures + others: BuiltinBounds) + -> Vec { // Since we don't actually *know* the self type for an object, // this "open(err)" serves as a kind of dummy standin -- basically @@ -5618,14 +5793,17 @@ pub fn object_region_bounds<'tcx>(tcx: &ctxt<'tcx>, let open_ty = ty::mk_infer(tcx, FreshTy(0)); let opt_trait_ref = opt_principal.map_or(Vec::new(), |principal| { - let substs = principal.substs().with_self_ty(open_ty); - vec!(Rc::new(ty::Binder(ty::TraitRef::new(principal.def_id(), tcx.mk_substs(substs))))) + // Note that we preserve the overall binding levels here. + assert!(!open_ty.has_escaping_regions()); + let substs = tcx.mk_substs(principal.0.substs.with_self_ty(open_ty)); + vec!(ty::Binder(Rc::new(ty::TraitRef::new(principal.0.def_id, substs)))) }); let param_bounds = ty::ParamBounds { region_bounds: Vec::new(), builtin_bounds: others, trait_bounds: opt_trait_ref, + projection_bounds: Vec::new(), // not relevant to computing region bounds }; let predicates = ty::predicates(tcx, open_ty, ¶m_bounds); @@ -5656,6 +5834,7 @@ pub fn required_region_bounds<'tcx>(tcx: &ctxt<'tcx>, traits::elaborate_predicates(tcx, predicates) .filter_map(|predicate| { match predicate { + ty::Predicate::Projection(..) | ty::Predicate::Trait(..) | ty::Predicate::Equate(..) | ty::Predicate::RegionOutlives(..) => { @@ -6007,12 +6186,12 @@ pub fn hash_crate_independent<'tcx>(tcx: &ctxt<'tcx>, ty: Ty<'tcx>, svh: &Svh) - return false; } - ty_trait(box TyTrait { ref principal, bounds }) => { + ty_trait(ref data) => { byte!(17); - did(state, principal.def_id()); - hash!(bounds); + did(state, data.principal_def_id()); + hash!(data.bounds); - let principal = anonymize_late_bound_regions(tcx, principal); + let principal = anonymize_late_bound_regions(tcx, &data.principal); for subty in principal.substs.types.iter() { helper(tcx, *subty, svh, state); } @@ -6040,6 +6219,11 @@ pub fn hash_crate_independent<'tcx>(tcx: &ctxt<'tcx>, ty: Ty<'tcx>, svh: &Svh) - did(state, d); region(state, *r); } + ty_projection(ref data) => { + byte!(25); + did(state, data.trait_ref.def_id); + hash!(token::get_name(data.item_name)); + } } true }); @@ -6156,7 +6340,10 @@ pub fn construct_parameter_environment<'tcx>( for predicate in bounds.predicates.iter() { match *predicate { - Predicate::Trait(..) | Predicate::Equate(..) | Predicate::TypeOutlives(..) => { + Predicate::Projection(..) | + Predicate::Trait(..) | + Predicate::Equate(..) | + Predicate::TypeOutlives(..) => { // No region bounds here } Predicate::RegionOutlives(ty::Binder(ty::OutlivesPredicate(r_a, r_b))) => { @@ -6283,7 +6470,7 @@ pub fn accumulate_lifetimes_in_type(accumulator: &mut Vec, accumulator.push(*region) } ty_trait(ref t) => { - accumulator.push_all(t.principal.substs().regions().as_slice()); + accumulator.push_all(t.principal.0.substs.regions().as_slice()); } ty_enum(_, substs) | ty_struct(_, substs) => { @@ -6310,6 +6497,7 @@ pub fn accumulate_lifetimes_in_type(accumulator: &mut Vec, ty_ptr(_) | ty_bare_fn(..) | ty_tup(_) | + ty_projection(_) | ty_param(_) | ty_infer(_) | ty_open(_) | @@ -6400,6 +6588,15 @@ pub fn count_late_bound_regions<'tcx, T>( skol_map.len() } +pub fn binds_late_bound_regions<'tcx, T>( + tcx: &ty::ctxt<'tcx>, + value: &Binder) + -> bool + where T : TypeFoldable<'tcx> + Repr<'tcx> +{ + count_late_bound_regions(tcx, value) > 0 +} + /// Replace any late-bound regions bound in `value` with `'static`. Useful in trans but also /// method lookup and a few other places where precise region relationships are not required. pub fn erase_late_bound_regions<'tcx, T>( @@ -6540,9 +6737,10 @@ impl<'tcx> Repr<'tcx> for ty::Predicate<'tcx> { fn repr(&self, tcx: &ctxt<'tcx>) -> String { match *self { Predicate::Trait(ref a) => a.repr(tcx), - Predicate::Equate(ref pair) => format!("Equate({})", pair.repr(tcx)), - Predicate::RegionOutlives(ref pair) => format!("Outlives({})", pair.repr(tcx)), - Predicate::TypeOutlives(ref pair) => format!("Outlives({})", pair.repr(tcx)), + Predicate::Equate(ref pair) => pair.repr(tcx), + Predicate::RegionOutlives(ref pair) => pair.repr(tcx), + Predicate::TypeOutlives(ref pair) => pair.repr(tcx), + Predicate::Projection(ref pair) => pair.repr(tcx), } } } @@ -6638,6 +6836,11 @@ pub fn can_type_implement_copy<'tcx>(tcx: &ctxt<'tcx>, Ok(()) } +// TODO -- all of these types basically walk various structures to +// test whether types/regions are reachable with various +// properties. It should be possible to express them in terms of one +// common "walker" trait or something. + pub trait RegionEscape { fn has_escaping_regions(&self) -> bool { self.has_regions_escaping_depth(0) @@ -6677,8 +6880,193 @@ impl<'tcx> RegionEscape for EquatePredicate<'tcx> { } } +impl<'tcx> RegionEscape for TraitPredicate<'tcx> { + fn has_regions_escaping_depth(&self, depth: uint) -> bool { + self.trait_ref.has_regions_escaping_depth(depth) + } +} + impl RegionEscape for OutlivesPredicate { fn has_regions_escaping_depth(&self, depth: u32) -> bool { self.0.has_regions_escaping_depth(depth) || self.1.has_regions_escaping_depth(depth) } } + +impl<'tcx> RegionEscape for ProjectionPredicate<'tcx> { + fn has_regions_escaping_depth(&self, depth: uint) -> bool { + self.projection_ty.has_regions_escaping_depth(depth) || + self.ty.has_regions_escaping_depth(depth) + } +} + +impl<'tcx> RegionEscape for ProjectionTy<'tcx> { + fn has_regions_escaping_depth(&self, depth: uint) -> bool { + self.trait_ref.has_regions_escaping_depth(depth) + } +} + +impl<'tcx> Repr<'tcx> for ty::ProjectionPredicate<'tcx> { + fn repr(&self, tcx: &ctxt<'tcx>) -> String { + format!("ProjectionPredicate({}, {})", + self.projection_ty.repr(tcx), + self.ty.repr(tcx)) + } +} + +impl<'tcx> Repr<'tcx> for ty::TyProjection<'tcx> { + fn repr(&self, tcx: &ctxt<'tcx>) -> String { + format!("TyProjection({}, {})", + self.trait_ref.repr(tcx), + self.item_name.repr(tcx)) + } +} + +pub trait HasProjectionTypes { + fn has_projection_types(&self) -> bool; +} + +impl<'tcx> HasProjectionTypes for Ty<'tcx> { + fn has_projection_types(&self) -> bool { + ty::type_has_projection(*self) + } +} + +impl<'tcx> HasProjectionTypes for ty::TraitRef<'tcx> { + fn has_projection_types(&self) -> bool { + self.substs.has_projection_types() + } +} + +impl<'tcx> HasProjectionTypes for subst::Substs<'tcx> { + fn has_projection_types(&self) -> bool { + self.types.iter().any(|t| t.has_projection_types()) + } +} + +impl<'tcx,T> HasProjectionTypes for Option + where T : HasProjectionTypes +{ + fn has_projection_types(&self) -> bool { + self.iter().any(|t| t.has_projection_types()) + } +} + +impl<'tcx,T> HasProjectionTypes for Rc + where T : HasProjectionTypes +{ + fn has_projection_types(&self) -> bool { + (**self).has_projection_types() + } +} + +impl<'tcx,T> HasProjectionTypes for Box + where T : HasProjectionTypes +{ + fn has_projection_types(&self) -> bool { + (**self).has_projection_types() + } +} + +impl HasProjectionTypes for ty::Binder + where T : HasProjectionTypes +{ + fn has_projection_types(&self) -> bool { + self.0.has_projection_types() + } +} + +impl<'tcx> HasProjectionTypes for ty::FnOutput<'tcx> { + fn has_projection_types(&self) -> bool { + match *self { + ty::FnConverging(t) => t.has_projection_types(), + ty::FnDiverging => false, + } + } +} + +impl<'tcx> HasProjectionTypes for ty::FnSig<'tcx> { + fn has_projection_types(&self) -> bool { + self.inputs.iter().any(|t| t.has_projection_types()) || + self.output.has_projection_types() + } +} + +impl<'tcx> HasProjectionTypes for ty::BareFnTy<'tcx> { + fn has_projection_types(&self) -> bool { + self.sig.has_projection_types() + } +} + +pub trait ReferencesError { + fn references_error(&self) -> bool; +} + +impl ReferencesError for ty::Binder { + fn references_error(&self) -> bool { + self.0.references_error() + } +} + +impl ReferencesError for Rc { + fn references_error(&self) -> bool { + (&*self).references_error() + } +} + +impl<'tcx> ReferencesError for ty::TraitPredicate<'tcx> { + fn references_error(&self) -> bool { + self.trait_ref.references_error() + } +} + +impl<'tcx> ReferencesError for ty::ProjectionPredicate<'tcx> { + fn references_error(&self) -> bool { + self.projection_ty.trait_ref.references_error() || self.ty.references_error() + } +} + +impl<'tcx> ReferencesError for ty::TraitRef<'tcx> { + fn references_error(&self) -> bool { + self.input_types().iter().any(|t| t.references_error()) + } +} + +impl<'tcx> ReferencesError for ty::Ty<'tcx> { + fn references_error(&self) -> bool { + ty::type_is_error(*self) + } +} + +impl<'tcx> ReferencesError for ty::Predicate<'tcx> { + fn references_error(&self) -> bool { + match *self { + ty::Predicate::Trait(ref data) => data.references_error(), + ty::Predicate::Equate(ref data) => data.references_error(), + ty::Predicate::RegionOutlives(ref data) => data.references_error(), + ty::Predicate::TypeOutlives(ref data) => data.references_error(), + ty::Predicate::Projection(ref data) => data.references_error(), + } + } +} + +impl ReferencesError for ty::OutlivesPredicate + where A : ReferencesError, B : ReferencesError +{ + fn references_error(&self) -> bool { + self.0.references_error() || self.1.references_error() + } +} + +impl<'tcx> ReferencesError for ty::EquatePredicate<'tcx> +{ + fn references_error(&self) -> bool { + self.0.references_error() || self.1.references_error() + } +} + +impl ReferencesError for ty::Region +{ + fn references_error(&self) -> bool { + false + } +} diff --git a/src/librustc/middle/ty_fold.rs b/src/librustc/middle/ty_fold.rs index 11a130f0c54..036fbfec280 100644 --- a/src/librustc/middle/ty_fold.rs +++ b/src/librustc/middle/ty_fold.rs @@ -170,6 +170,13 @@ impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Rc { } } +impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Box { + fn fold_with>(&self, folder: &mut F) -> Box { + let content: T = (**self).fold_with(folder); + box content + } +} + impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Vec { fn fold_with>(&self, folder: &mut F) -> Vec { self.iter().map(|t| t.fold_with(folder)).collect() @@ -354,6 +361,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::ParamBounds<'tcx> { region_bounds: self.region_bounds.fold_with(folder), builtin_bounds: self.builtin_bounds.fold_with(folder), trait_bounds: self.trait_bounds.fold_with(folder), + projection_bounds: self.projection_bounds.fold_with(folder), } } } @@ -365,7 +373,6 @@ impl<'tcx> TypeFoldable<'tcx> for ty::TypeParameterDef<'tcx> { def_id: self.def_id, space: self.space, index: self.index, - associated_with: self.associated_with, bounds: self.bounds.fold_with(folder), default: self.default.fold_with(folder), } @@ -405,6 +412,35 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> { ty::Predicate::RegionOutlives(binder.fold_with(folder)), ty::Predicate::TypeOutlives(ref binder) => ty::Predicate::TypeOutlives(binder.fold_with(folder)), + ty::Predicate::Projection(ref binder) => + ty::Predicate::Projection(binder.fold_with(folder)), + } + } +} + +impl<'tcx> TypeFoldable<'tcx> for ty::ProjectionPredicate<'tcx> { + fn fold_with>(&self, folder: &mut F) -> ty::ProjectionPredicate<'tcx> { + ty::ProjectionPredicate { + projection_ty: self.projection_ty.fold_with(folder), + ty: self.ty.fold_with(folder), + } + } +} + +impl<'tcx> TypeFoldable<'tcx> for ty::ProjectionTy<'tcx> { + fn fold_with>(&self, folder: &mut F) -> ty::ProjectionTy<'tcx> { + ty::ProjectionTy { + trait_ref: self.trait_ref.fold_with(folder), + item_name: self.item_name, + } + } +} + +impl<'tcx> TypeFoldable<'tcx> for ty::TyProjection<'tcx> { + fn fold_with>(&self, folder: &mut F) -> ty::TyProjection<'tcx> { + ty::TyProjection { + trait_ref: self.trait_ref.fold_with(folder), + item_name: self.item_name, } } } @@ -495,6 +531,14 @@ impl<'tcx> TypeFoldable<'tcx> for ty::EquatePredicate<'tcx> { } } +impl<'tcx> TypeFoldable<'tcx> for ty::TraitPredicate<'tcx> { + fn fold_with>(&self, folder: &mut F) -> ty::TraitPredicate<'tcx> { + ty::TraitPredicate { + trait_ref: self.trait_ref.fold_with(folder) + } + } +} + impl<'tcx,T,U> TypeFoldable<'tcx> for ty::OutlivesPredicate where T : TypeFoldable<'tcx>, U : TypeFoldable<'tcx>, @@ -544,7 +588,7 @@ pub fn super_fold_ty<'tcx, T: TypeFolder<'tcx>>(this: &mut T, ty::ty_bare_fn(opt_def_id, this.tcx().mk_bare_fn(bfn)) } ty::ty_closure(ref f) => { - ty::ty_closure(box f.fold_with(this)) + ty::ty_closure(f.fold_with(this)) } ty::ty_rptr(r, ref tm) => { let r = r.fold_with(this); @@ -559,6 +603,9 @@ pub fn super_fold_ty<'tcx, T: TypeFolder<'tcx>>(this: &mut T, let s = substs.fold_with(this); ty::ty_unboxed_closure(did, this.tcx().mk_region(r), this.tcx().mk_substs(s)) } + ty::ty_projection(ref data) => { + ty::ty_projection(data.fold_with(this)) + } ty::ty_bool | ty::ty_char | ty::ty_str | ty::ty_int(_) | ty::ty_uint(_) | ty::ty_float(_) | ty::ty_err | ty::ty_infer(_) | diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index ae8324d9a4f..134a4722507 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -448,6 +448,12 @@ pub fn ty_to_string<'tcx>(cx: &ctxt<'tcx>, typ: &ty::TyS<'tcx>) -> String { bound_sep, bound_str) } + ty::ty_projection(ref data) => { + format!("<{} as {}>::{}", + data.trait_ref.self_ty().user_string(cx), + data.trait_ref.user_string(cx), + data.item_name.user_string(cx)) + } ty_str => "str".to_string(), ty_unboxed_closure(ref did, _, substs) => { let unboxed_closures = cx.unboxed_closures.borrow(); @@ -1408,17 +1414,55 @@ impl<'tcx> UserString<'tcx> for ty::EquatePredicate<'tcx> { } } +impl<'tcx> Repr<'tcx> for ty::TraitPredicate<'tcx> { + fn repr(&self, tcx: &ctxt<'tcx>) -> String { + format!("TraitPredicate({})", + self.trait_ref.repr(tcx)) + } +} + +impl<'tcx> UserString<'tcx> for ty::TraitPredicate<'tcx> { + fn user_string(&self, tcx: &ctxt<'tcx>) -> String { + format!("{} : {}", + self.trait_ref.self_ty().user_string(tcx), + self.trait_ref.user_string(tcx)) + } +} + +impl<'tcx> UserString<'tcx> for ty::ProjectionPredicate<'tcx> { + fn user_string(&self, tcx: &ctxt<'tcx>) -> String { + format!("{} == {}", + self.projection_ty.user_string(tcx), + self.ty.user_string(tcx)) + } +} + +impl<'tcx> Repr<'tcx> for ty::ProjectionTy<'tcx> { + fn repr(&self, tcx: &ctxt<'tcx>) -> String { + format!("<{} as {}>::{}", + self.trait_ref.self_ty().repr(tcx), + self.trait_ref.repr(tcx), + self.item_name.repr(tcx)) + } +} + +impl<'tcx> UserString<'tcx> for ty::ProjectionTy<'tcx> { + fn user_string(&self, tcx: &ctxt<'tcx>) -> String { + format!("<{} as {}>::{}", + self.trait_ref.self_ty().user_string(tcx), + self.trait_ref.user_string(tcx), + self.item_name.user_string(tcx)) + } +} + impl<'tcx> UserString<'tcx> for ty::Predicate<'tcx> { fn user_string(&self, tcx: &ctxt<'tcx>) -> String { match *self { - ty::Predicate::Trait(ref trait_ref) => { - format!("{} : {}", - trait_ref.self_ty().user_string(tcx), - trait_ref.user_string(tcx)) - } + ty::Predicate::Trait(ref data) => data.user_string(tcx), ty::Predicate::Equate(ref predicate) => predicate.user_string(tcx), ty::Predicate::RegionOutlives(ref predicate) => predicate.user_string(tcx), ty::Predicate::TypeOutlives(ref predicate) => predicate.user_string(tcx), + ty::Predicate::Projection(ref predicate) => predicate.user_string(tcx), } } } diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index e0a717d8073..c5d3ad805d9 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -281,6 +281,8 @@ pub fn kind_for_unboxed_closure(ccx: &CrateContext, closure_id: ast::DefId) pub fn decl_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_ty: Ty<'tcx>, name: &str) -> ValueRef { + let fn_ty = monomorphize::normalize_associated_type(ccx.tcx(), &fn_ty); + let (inputs, output, abi, env) = match fn_ty.sty { ty::ty_bare_fn(_, ref f) => { (f.sig.0.inputs.clone(), f.sig.0.output, f.abi, None) @@ -1453,7 +1455,8 @@ pub fn new_fn_ctxt<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>, let uses_outptr = match output_type { ty::FnConverging(output_type) => { - let substd_output_type = output_type.subst(ccx.tcx(), param_substs); + let substd_output_type = + monomorphize::apply_param_substs(ccx.tcx(), param_substs, &output_type); type_of::return_uses_outptr(ccx, substd_output_type) } ty::FnDiverging => false @@ -1512,7 +1515,7 @@ pub fn init_function<'a, 'tcx>(fcx: &'a FunctionContext<'a, 'tcx>, if let ty::FnConverging(output_type) = output { // This shouldn't need to recompute the return type, // as new_fn_ctxt did it already. - let substd_output_type = output_type.subst(fcx.ccx.tcx(), fcx.param_substs); + let substd_output_type = fcx.monomorphize(&output_type); if !return_type_is_void(fcx.ccx, substd_output_type) { // If the function returns nil/bot, there is no real return // value, so do not set `llretslotptr`. @@ -1732,7 +1735,7 @@ pub fn finish_fn<'blk, 'tcx>(fcx: &'blk FunctionContext<'blk, 'tcx>, // This shouldn't need to recompute the return type, // as new_fn_ctxt did it already. - let substd_retty = retty.subst(fcx.ccx.tcx(), fcx.param_substs); + let substd_retty = fcx.monomorphize(&retty); build_return_block(fcx, ret_cx, substd_retty); debuginfo::clear_source_location(fcx); @@ -2074,7 +2077,7 @@ fn trans_enum_variant_or_tuple_like_struct<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx param_substs: &Substs<'tcx>, llfndecl: ValueRef) { let ctor_ty = ty::node_id_to_type(ccx.tcx(), ctor_id); - let ctor_ty = ctor_ty.subst(ccx.tcx(), param_substs); + let ctor_ty = monomorphize::apply_param_substs(ccx.tcx(), param_substs, &ctor_ty); let result_ty = match ctor_ty.sty { ty::ty_bare_fn(_, ref bft) => bft.sig.0.output, @@ -2764,6 +2767,7 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef { } let item = ccx.tcx().map.get(id); + debug!("get_item_val: id={} item={}", id, item); let val = match item { ast_map::NodeItem(i) => { let ty = ty::node_id_to_type(ccx.tcx(), i.id); diff --git a/src/librustc_trans/trans/callee.rs b/src/librustc_trans/trans/callee.rs index c0697c2a238..169e52bcfe5 100644 --- a/src/librustc_trans/trans/callee.rs +++ b/src/librustc_trans/trans/callee.rs @@ -516,6 +516,7 @@ pub fn trans_fn_ref_with_substs<'blk, 'tcx>( // Type scheme of the function item (may have type params) let fn_type_scheme = ty::lookup_item_type(tcx, def_id); + let fn_type = monomorphize::normalize_associated_type(tcx, &fn_type_scheme.ty); // Find the actual function pointer. let mut val = { @@ -524,7 +525,7 @@ pub fn trans_fn_ref_with_substs<'blk, 'tcx>( get_item_val(ccx, def_id.node) } else { // External reference. - trans_external_path(ccx, def_id, fn_type_scheme.ty) + trans_external_path(ccx, def_id, fn_type) } }; @@ -551,7 +552,7 @@ pub fn trans_fn_ref_with_substs<'blk, 'tcx>( // This can occur on either a crate-local or crate-external // reference. It also occurs when testing libcore and in some // other weird situations. Annoying. - let llty = type_of::type_of_fn_from_ty(ccx, fn_type_scheme.ty); + let llty = type_of::type_of_fn_from_ty(ccx, fn_type); let llptrty = llty.ptr_to(); if val_ty(val) != llptrty { debug!("trans_fn_ref_with_vtables(): casting pointer!"); diff --git a/src/librustc_trans/trans/common.rs b/src/librustc_trans/trans/common.rs index f052a20bc89..694fbf251dd 100644 --- a/src/librustc_trans/trans/common.rs +++ b/src/librustc_trans/trans/common.rs @@ -24,20 +24,20 @@ use middle::infer; use middle::lang_items::LangItem; use middle::mem_categorization as mc; use middle::region; -use middle::subst; -use middle::subst::{Subst, Substs}; +use middle::subst::{mod, Subst, Substs}; use trans::base; use trans::build; use trans::cleanup; use trans::datum; use trans::debuginfo; use trans::machine; +use trans::monomorphize; use trans::type_::Type; use trans::type_of; use middle::traits; -use middle::ty::{mod, Ty}; +use middle::ty::{mod, HasProjectionTypes, Ty}; use middle::ty_fold; -use middle::ty_fold::TypeFoldable; +use middle::ty_fold::{TypeFolder, TypeFoldable}; use util::ppaux::Repr; use util::nodemap::{DefIdMap, FnvHashMap, NodeMap}; @@ -45,7 +45,6 @@ use arena::TypedArena; use libc::{c_uint, c_char}; use std::c_str::ToCStr; use std::cell::{Cell, RefCell}; -use std::rc::Rc; use std::vec::Vec; use syntax::ast::Ident; use syntax::ast; @@ -137,7 +136,7 @@ pub fn type_needs_unwind_cleanup<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty< ty::ty_enum(did, substs) => ty::enum_variants(tcx, did).iter().any(|v| - v.args.iter().any(|aty| { + v.args.iter().any(|&aty| { let t = aty.subst(tcx, substs); type_needs_unwind_cleanup_(tcx, t, tycache) }) @@ -465,6 +464,14 @@ impl<'a, 'tcx> FunctionContext<'a, 'tcx> { } return out; } + + pub fn monomorphize(&self, value: &T) -> T + where T : TypeFoldable<'tcx> + Repr<'tcx> + HasProjectionTypes + Clone + { + monomorphize::apply_param_substs(self.ccx.tcx(), + self.param_substs, + value) + } } // Basic block context. We create a block context for each basic block @@ -557,6 +564,14 @@ impl<'blk, 'tcx> BlockS<'blk, 'tcx> { pub fn to_str(&self) -> String { format!("[block {:p}]", self) } + + pub fn monomorphize(&self, value: &T) -> T + where T : TypeFoldable<'tcx> + Repr<'tcx> + HasProjectionTypes + Clone + { + monomorphize::apply_param_substs(self.tcx(), + self.fcx.param_substs, + value) + } } impl<'blk, 'tcx> mc::Typer<'tcx> for BlockS<'blk, 'tcx> { @@ -859,7 +874,7 @@ pub fn is_null(val: ValueRef) -> bool { } pub fn monomorphize_type<'blk, 'tcx>(bcx: &BlockS<'blk, 'tcx>, t: Ty<'tcx>) -> Ty<'tcx> { - t.subst(bcx.tcx(), bcx.fcx.param_substs) + bcx.fcx.monomorphize(&t) } pub fn node_id_type<'blk, 'tcx>(bcx: &BlockS<'blk, 'tcx>, id: ast::NodeId) -> Ty<'tcx> { @@ -881,7 +896,7 @@ pub fn expr_ty_adjusted<'blk, 'tcx>(bcx: &BlockS<'blk, 'tcx>, ex: &ast::Expr) -> /// guarantee to us that all nested obligations *could be* resolved if we wanted to. pub fn fulfill_obligation<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, span: Span, - trait_ref: Rc>) + trait_ref: ty::PolyTraitRef<'tcx>) -> traits::Vtable<'tcx, ()> { let tcx = ccx.tcx(); @@ -911,7 +926,7 @@ pub fn fulfill_obligation<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, // shallow result we are looking for -- that is, what specific impl. let mut selcx = traits::SelectionContext::new(&infcx, ¶m_env, tcx); let obligation = traits::Obligation::new(traits::ObligationCause::dummy(), - trait_ref.clone()); + trait_ref.to_poly_trait_predicate()); let selection = match selcx.select(&obligation) { Ok(Some(selection)) => selection, Ok(None) => { @@ -991,7 +1006,8 @@ pub enum ExprOrMethodCall { pub fn node_id_substs<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, node: ExprOrMethodCall) - -> subst::Substs<'tcx> { + -> subst::Substs<'tcx> +{ let tcx = bcx.tcx(); let substs = match node { @@ -1012,7 +1028,7 @@ pub fn node_id_substs<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, } let substs = substs.erase_regions(); - substs.subst(tcx, bcx.fcx.param_substs) + bcx.monomorphize(&substs) } pub fn langcall(bcx: Block, diff --git a/src/librustc_trans/trans/context.rs b/src/librustc_trans/trans/context.rs index 02eaef88548..9ceb0c63990 100644 --- a/src/librustc_trans/trans/context.rs +++ b/src/librustc_trans/trans/context.rs @@ -100,7 +100,7 @@ pub struct LocalCrateContext<'tcx> { monomorphized: RefCell, ValueRef>>, monomorphizing: RefCell>, /// Cache generated vtables - vtables: RefCell, Rc>), ValueRef>>, + vtables: RefCell, ty::PolyTraitRef<'tcx>), ValueRef>>, /// Cache of constant strings, const_cstr_cache: RefCell>, @@ -151,7 +151,7 @@ pub struct LocalCrateContext<'tcx> { /// contexts around the same size. n_llvm_insns: Cell, - trait_cache: RefCell>, + trait_cache: RefCell, traits::Vtable<'tcx, ()>>>, } @@ -607,7 +607,7 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { &self.local.monomorphizing } - pub fn vtables<'a>(&'a self) -> &'a RefCell, Rc>), + pub fn vtables<'a>(&'a self) -> &'a RefCell, ty::PolyTraitRef<'tcx>), ValueRef>> { &self.local.vtables } @@ -705,7 +705,7 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { self.local.n_llvm_insns.set(self.local.n_llvm_insns.get() + 1); } - pub fn trait_cache(&self) -> &RefCell>, + pub fn trait_cache(&self) -> &RefCell, traits::Vtable<'tcx, ()>>> { &self.local.trait_cache } diff --git a/src/librustc_trans/trans/debuginfo.rs b/src/librustc_trans/trans/debuginfo.rs index 98f87b27385..e94ce55e704 100644 --- a/src/librustc_trans/trans/debuginfo.rs +++ b/src/librustc_trans/trans/debuginfo.rs @@ -198,6 +198,7 @@ use middle::subst::{mod, Subst, Substs}; use trans::{mod, adt, machine, type_of}; use trans::common::*; use trans::_match::{BindingInfo, TrByCopy, TrByMove, TrByRef}; +use trans::monomorphize; use trans::type_::Type; use middle::ty::{mod, Ty}; use middle::pat_util; @@ -426,8 +427,8 @@ impl<'tcx> TypeMap<'tcx> { from_def_id_and_substs(self, cx, - trait_data.principal.def_id(), - trait_data.principal.substs(), + trait_data.principal_def_id(), + &trait_data.principal.0.substs, &mut unique_type_id); }, ty::ty_bare_fn(_, &ty::BareFnTy{ unsafety, abi, ref sig } ) => { @@ -1438,7 +1439,9 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, assert_type_for_node_id(cx, fn_ast_id, error_reporting_span); let return_type = ty::node_id_to_type(cx.tcx(), fn_ast_id); - let return_type = return_type.subst(cx.tcx(), param_substs); + let return_type = monomorphize::apply_param_substs(cx.tcx(), + param_substs, + &return_type); signature.push(type_metadata(cx, return_type, codemap::DUMMY_SP)); } } @@ -1447,7 +1450,9 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, for arg in fn_decl.inputs.iter() { assert_type_for_node_id(cx, arg.pat.id, arg.pat.span); let arg_type = ty::node_id_to_type(cx.tcx(), arg.pat.id); - let arg_type = arg_type.subst(cx.tcx(), param_substs); + let arg_type = monomorphize::apply_param_substs(cx.tcx(), + param_substs, + &arg_type); signature.push(type_metadata(cx, arg_type, codemap::DUMMY_SP)); } @@ -1459,8 +1464,10 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, param_substs: &Substs<'tcx>, file_metadata: DIFile, name_to_append_suffix_to: &mut String) - -> DIArray { + -> DIArray + { let self_type = param_substs.self_ty(); + let self_type = monomorphize::normalize_associated_type(cx.tcx(), &self_type); // Only true for static default methods: let has_self_type = self_type.is_some(); @@ -2878,7 +2885,7 @@ fn trait_pointer_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, // But it does not describe the trait's methods. let def_id = match trait_type.sty { - ty::ty_trait(box ty::TyTrait { ref principal, .. }) => principal.def_id(), + ty::ty_trait(ref data) => data.principal_def_id(), _ => { let pp_type_name = ppaux::ty_to_string(cx.tcx(), trait_type); cx.sess().bug(format!("debuginfo: Unexpected trait-object type in \ @@ -3811,8 +3818,8 @@ fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, output.push(']'); }, ty::ty_trait(ref trait_data) => { - push_item_name(cx, trait_data.principal.def_id(), false, output); - push_type_params(cx, trait_data.principal.substs(), output); + push_item_name(cx, trait_data.principal_def_id(), false, output); + push_type_params(cx, &trait_data.principal.0.substs, output); }, ty::ty_bare_fn(_, &ty::BareFnTy{ unsafety, abi, ref sig } ) => { if unsafety == ast::Unsafety::Unsafe { @@ -3920,9 +3927,10 @@ fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, ty::ty_unboxed_closure(..) => { output.push_str("closure"); } - ty::ty_err | + ty::ty_err | ty::ty_infer(_) | ty::ty_open(_) | + ty::ty_projection(..) | ty::ty_param(_) => { cx.sess().bug(format!("debuginfo: Trying to create type name for \ unexpected type: {}", ppaux::ty_to_string(cx.tcx(), t))[]); diff --git a/src/librustc_trans/trans/expr.rs b/src/librustc_trans/trans/expr.rs index fc2e6c7b7fd..5a7131cf68e 100644 --- a/src/librustc_trans/trans/expr.rs +++ b/src/librustc_trans/trans/expr.rs @@ -39,7 +39,7 @@ use back::abi; use llvm::{mod, ValueRef}; use middle::def; use middle::mem_categorization::Typer; -use middle::subst::{mod, Subst, Substs}; +use middle::subst::{mod, Substs}; use trans::{_match, adt, asm, base, callee, closure, consts, controlflow}; use trans::base::*; use trans::build::*; @@ -319,11 +319,13 @@ fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, bcx.ty_to_string(unadjusted_ty))[]) }, &ty::UnsizeVtable(ty::TyTrait { ref principal, .. }, _) => { - let substs = principal.substs().with_self_ty(unadjusted_ty).erase_regions(); + // Note that we preserve binding levels here: + let substs = principal.0.substs.with_self_ty(unadjusted_ty).erase_regions(); + let substs = tcx.tcx().mk_substs(substs); let trait_ref = - Rc::new(ty::Binder(ty::TraitRef { def_id: principal.def_id(), - substs: bcx.tcx().mk_substs(substs) })); - let trait_ref = trait_ref.subst(bcx.tcx(), bcx.fcx.param_substs); + ty::Binder(Rc::new(ty::TraitRef { def_id: principal.def_id(), + substs: substs })); + let trait_ref = bcx.monomorphize(&trait_ref); let box_ty = mk_ty(unadjusted_ty); PointerCast(bcx, meth::get_vtable(bcx, box_ty, trait_ref), @@ -1204,7 +1206,7 @@ fn trans_rvalue_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, .get(&expr.id) .map(|t| (*t).clone()) .unwrap(); - let trait_ref = trait_ref.subst(bcx.tcx(), bcx.fcx.param_substs); + let trait_ref = bcx.monomorphize(&trait_ref); let datum = unpack_datum!(bcx, trans(bcx, &**val)); meth::trans_trait_cast(bcx, datum, expr.id, trait_ref, dest) diff --git a/src/librustc_trans/trans/foreign.rs b/src/librustc_trans/trans/foreign.rs index 1bad476863f..e234d77914b 100644 --- a/src/librustc_trans/trans/foreign.rs +++ b/src/librustc_trans/trans/foreign.rs @@ -19,11 +19,12 @@ use trans::build::*; use trans::cabi; use trans::common::*; use trans::machine; +use trans::monomorphize; use trans::type_::Type; use trans::type_of::*; use trans::type_of; use middle::ty::{mod, Ty}; -use middle::subst::{Subst, Substs}; +use middle::subst::{Substs}; use std::cmp; use libc::c_uint; use syntax::abi::{Cdecl, Aapcs, C, Win64, Abi}; @@ -525,7 +526,7 @@ pub fn trans_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, let _icx = push_ctxt("foreign::build_foreign_fn"); let fnty = ty::node_id_to_type(ccx.tcx(), id); - let mty = fnty.subst(ccx.tcx(), param_substs); + let mty = monomorphize::apply_param_substs(ccx.tcx(), param_substs, &fnty); let tys = foreign_types_for_fn_ty(ccx, mty); unsafe { // unsafe because we call LLVM operations @@ -543,10 +544,12 @@ pub fn trans_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, attrs: &[ast::Attribute], id: ast::NodeId, hash: Option<&str>) - -> ValueRef { + -> ValueRef + { let _icx = push_ctxt("foreign::foreign::build_rust_fn"); let tcx = ccx.tcx(); - let t = ty::node_id_to_type(tcx, id).subst(ccx.tcx(), param_substs); + let t = ty::node_id_to_type(tcx, id); + let t = monomorphize::apply_param_substs(tcx, param_substs, &t); let ps = ccx.tcx().map.with_path(id, |path| { let abi = Some(ast_map::PathName(special_idents::clownshoe_abi.name)); diff --git a/src/librustc_trans/trans/meth.rs b/src/librustc_trans/trans/meth.rs index a937f989b3a..00b17ca00df 100644 --- a/src/librustc_trans/trans/meth.rs +++ b/src/librustc_trans/trans/meth.rs @@ -13,7 +13,7 @@ use back::abi; use llvm; use llvm::ValueRef; use metadata::csearch; -use middle::subst::{Subst,Substs}; +use middle::subst::{Substs}; use middle::subst::VecPerParamSpace; use middle::subst; use middle::traits; @@ -132,8 +132,7 @@ pub fn trans_method_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, ref trait_ref, method_num }) => { - let trait_ref = - Rc::new(ty::Binder((**trait_ref).subst(bcx.tcx(), bcx.fcx.param_substs))); + let trait_ref = ty::Binder(bcx.monomorphize(trait_ref)); let span = bcx.tcx().map.span(method_call.expr_id); debug!("method_call={} trait_ref={}", method_call, @@ -142,8 +141,11 @@ pub fn trans_method_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, span, trait_ref.clone()); debug!("origin = {}", origin.repr(bcx.tcx())); - trans_monomorphized_callee(bcx, method_call, trait_ref.def_id(), - method_num, origin) + trans_monomorphized_callee(bcx, + method_call, + trait_ref.def_id(), + method_num, + origin) } ty::MethodTraitObject(ref mt) => { @@ -238,9 +240,10 @@ pub fn trans_static_method_callee(bcx: Block, rcvr_self, rcvr_assoc, Vec::new())); + let trait_substs = bcx.tcx().mk_substs(trait_substs); debug!("trait_substs={}", trait_substs.repr(bcx.tcx())); - let trait_ref = Rc::new(ty::Binder(ty::TraitRef { def_id: trait_id, - substs: bcx.tcx().mk_substs(trait_substs) })); + let trait_ref = ty::Binder(Rc::new(ty::TraitRef { def_id: trait_id, + substs: trait_substs })); let vtbl = fulfill_obligation(bcx.ccx(), DUMMY_SP, trait_ref); @@ -515,7 +518,7 @@ pub fn trans_trait_callee_from_llval<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, /// This will hopefully change now that DST is underway. pub fn get_vtable<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, box_ty: Ty<'tcx>, - trait_ref: Rc>) + trait_ref: ty::PolyTraitRef<'tcx>) -> ValueRef { debug!("get_vtable(box_ty={}, trait_ref={})", @@ -671,7 +674,7 @@ fn emit_vtable_methods<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, pub fn trans_trait_cast<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, datum: Datum<'tcx, Expr>, id: ast::NodeId, - trait_ref: Rc>, + trait_ref: ty::PolyTraitRef<'tcx>, dest: expr::Dest) -> Block<'blk, 'tcx> { let mut bcx = bcx; diff --git a/src/librustc_trans/trans/monomorphize.rs b/src/librustc_trans/trans/monomorphize.rs index 2a6aff56513..dcfe5f40ece 100644 --- a/src/librustc_trans/trans/monomorphize.rs +++ b/src/librustc_trans/trans/monomorphize.rs @@ -12,15 +12,18 @@ use back::link::exported_name; use session; use llvm::ValueRef; use llvm; +use middle::infer; use middle::subst; -use middle::subst::Subst; +use middle::subst::{Subst, Substs}; +use middle::traits; +use middle::ty_fold::{mod, TypeFolder, TypeFoldable}; use trans::base::{set_llvm_fn_attrs, set_inline_hint}; use trans::base::{trans_enum_variant, push_ctxt, get_item_val}; use trans::base::{trans_fn, decl_internal_rust_fn}; use trans::base; use trans::common::*; use trans::foreign; -use middle::ty::{mod, Ty}; +use middle::ty::{mod, HasProjectionTypes, Ty}; use util::ppaux::Repr; use syntax::abi; @@ -29,6 +32,7 @@ use syntax::ast_map; use syntax::ast_util::{local_def, PostExpansionMethod}; use syntax::attr; use std::hash::{sip, Hash}; +use std::rc::Rc; pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_id: ast::DefId, @@ -92,7 +96,12 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, } debug!("monomorphic_fn about to subst into {}", llitem_ty.repr(ccx.tcx())); + let mono_ty = llitem_ty.subst(ccx.tcx(), psubsts); + debug!("mono_ty = {} (post-substitution)", mono_ty.repr(ccx.tcx())); + + let mono_ty = normalize_associated_type(ccx.tcx(), &mono_ty); + debug!("mono_ty = {} (post-normalization)", mono_ty.repr(ccx.tcx())); ccx.stats().n_monos.set(ccx.stats().n_monos.get() + 1); @@ -282,3 +291,84 @@ pub struct MonoId<'tcx> { pub def: ast::DefId, pub params: subst::VecPerParamSpace> } + +/// Monomorphizes a type from the AST by first applying the in-scope +/// substitutions and then normalizing any associated types. +pub fn apply_param_substs<'tcx,T>(tcx: &ty::ctxt<'tcx>, + param_substs: &Substs<'tcx>, + value: &T) + -> T + where T : TypeFoldable<'tcx> + Repr<'tcx> + HasProjectionTypes + Clone +{ + assert!(param_substs.regions.is_erased()); + + let substituted = value.subst(tcx, param_substs); + normalize_associated_type(tcx, &substituted) +} + +/// Removes associated types, if any. Since this during +/// monomorphization, we know that only concrete types are involved, +/// and hence we can be sure that all associated types will be +/// completely normalized away. +pub fn normalize_associated_type<'tcx,T>(tcx: &ty::ctxt<'tcx>, t: &T) -> T + where T : TypeFoldable<'tcx> + Repr<'tcx> + HasProjectionTypes + Clone +{ + debug!("normalize_associated_type(t={})", t.repr(tcx)); + + if !t.has_projection_types() { + return t.clone(); + } + + // TODO cache + + let infcx = infer::new_infer_ctxt(tcx); + let param_env = ty::empty_parameter_environment(); + let mut selcx = traits::SelectionContext::new(&infcx, ¶m_env, tcx); + let mut normalizer = AssociatedTypeNormalizer { selcx: &mut selcx }; + let result = t.fold_with(&mut normalizer); + + debug!("normalize_associated_type: t={} result={}", + t.repr(tcx), + result.repr(tcx)); + + result +} + +struct AssociatedTypeNormalizer<'a,'tcx:'a> { + selcx: &'a mut traits::SelectionContext<'a,'tcx>, +} + +impl<'a,'tcx> TypeFolder<'tcx> for AssociatedTypeNormalizer<'a,'tcx> { + fn tcx(&self) -> &ty::ctxt<'tcx> { self.selcx.tcx() } + + fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { + match ty.sty { + ty::ty_projection(ref data) => { + debug!("ty_projection({})", data.repr(self.tcx())); + + let tcx = self.selcx.tcx(); + let substs = data.trait_ref.substs.clone().erase_regions(); + assert!(substs.types.iter().all(|&t| (!ty::type_has_params(t) && + !ty::type_has_self(t)))); + let trait_ref = Rc::new(ty::TraitRef::new(data.trait_ref.def_id, substs)); + let projection_ty = ty::ProjectionTy { trait_ref: trait_ref.clone(), + item_name: data.item_name }; + let obligation = traits::Obligation::new(traits::ObligationCause::dummy(), + projection_ty); + match traits::project_type(self.selcx, &obligation) { + Ok(ty) => ty, + Err(errors) => { + tcx.sess.bug( + format!("Encountered error(s) `{}` selecting `{}` during trans", + errors.repr(tcx), + trait_ref.repr(tcx)).as_slice()); + } + } + } + + _ => { + ty_fold::super_fold_ty(self, ty) + } + } + } +} diff --git a/src/librustc_trans/trans/type_of.rs b/src/librustc_trans/trans/type_of.rs index aaec82bb177..0bc35390cd7 100644 --- a/src/librustc_trans/trans/type_of.rs +++ b/src/librustc_trans/trans/type_of.rs @@ -241,7 +241,7 @@ pub fn sizing_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Typ Type::struct_(cx, &[Type::i8p(cx), Type::i8p(cx)], false) } - ty::ty_infer(..) | ty::ty_param(..) | ty::ty_err(..) => { + ty::ty_projection(..) | ty::ty_infer(..) | ty::ty_param(..) | ty::ty_err(..) => { cx.sess().bug(format!("fictitious type {} in sizing_type_of()", ppaux::ty_to_string(cx.tcx(), t))[]) } @@ -414,6 +414,7 @@ pub fn type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Type { }, ty::ty_infer(..) => cx.sess().bug("type_of with ty_infer"), + ty::ty_projection(..) => cx.sess().bug("type_of with ty_projection"), ty::ty_param(..) => cx.sess().bug("type_of with ty_param"), ty::ty_err(..) => cx.sess().bug("type_of with ty_err"), }; diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 0ba528ad030..00d3478e6a5 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -51,7 +51,7 @@ use middle::astconv_util::{ast_ty_to_prim_ty, check_path_args, NO_TPS, NO_REGION use middle::const_eval; use middle::def; use middle::resolve_lifetime as rl; -use middle::subst::{FnSpace, TypeSpace, AssocSpace, SelfSpace, Subst, Substs}; +use middle::subst::{FnSpace, TypeSpace, SelfSpace, Subst, Substs}; use middle::subst::{VecPerParamSpace}; use middle::ty::{mod, RegionEscape, Ty}; use rscope::{mod, UnelidableRscope, RegionScope, SpecificRscope, @@ -84,25 +84,45 @@ pub trait AstConv<'tcx> { /// What type should we use when a type is omitted? fn ty_infer(&self, span: Span) -> Ty<'tcx>; - /// Returns true if associated types from the given trait and type are - /// allowed to be used here and false otherwise. - fn associated_types_of_trait_are_valid(&self, - ty: Ty<'tcx>, - trait_id: ast::DefId) - -> bool; + /// Projecting an associated type from a (potentially) + /// higher-ranked trait reference is more complicated, because of + /// the possibility of late-bound regions appearing in the + /// associated type binding. This is not legal in function + /// signatures for that reason. In a function body, we can always + /// handle it because we can use inference variables to remove the + /// late-bound regions. + fn projected_ty_from_poly_trait_ref(&self, + span: Span, + poly_trait_ref: ty::PolyTraitRef<'tcx>, + item_name: ast::Name) + -> Ty<'tcx> + { + if ty::binds_late_bound_regions(self.tcx(), &poly_trait_ref) { + self.tcx().sess.span_err( + span, + "cannot extract an associated type from a higher-ranked trait bound \ + in this context"); + self.tcx().types.err + } else { + // no late-bound regions, we can just ignore the binder + self.projected_ty(span, poly_trait_ref.0.clone(), item_name) + } + } - /// Returns the concrete type bound to the given associated type (indicated - /// by associated_type_id) in the current context. For example, - /// in `trait Foo { type A; }` looking up `A` will give a type variable; - /// in `impl Foo for ... { type A = int; ... }` looking up `A` will give `int`. - fn associated_type_binding(&self, - span: Span, - self_ty: Option>, - // DefId for the declaration of the trait - // in which the associated type is declared. - trait_id: ast::DefId, - associated_type_id: ast::DefId) - -> Option>; + /// Project an associated type from a non-higher-ranked trait reference. + /// This is fairly straightforward and can be accommodated in any context. + fn projected_ty(&self, + span: Span, + _trait_ref: Rc>, + _item_name: ast::Name) + -> Ty<'tcx> + { + self.tcx().sess.span_err( + span, + "associated types are not accepted in this context"); + + self.tcx().types.err + } } pub fn ast_region_to_region(tcx: &ty::ctxt, lifetime: &ast::Lifetime) @@ -255,6 +275,8 @@ fn ast_path_substs_for_ty<'tcx,AC,RS>( } }; + prohibit_projections(this.tcx(), assoc_bindings.as_slice()); + create_substs_for_ast_path(this, rscope, path.span, @@ -262,21 +284,19 @@ fn ast_path_substs_for_ty<'tcx,AC,RS>( decl_generics, None, types, - regions, - assoc_bindings) + regions) } fn create_substs_for_ast_path<'tcx,AC,RS>( this: &AC, rscope: &RS, span: Span, - decl_def_id: ast::DefId, + _decl_def_id: ast::DefId, decl_generics: &ty::Generics<'tcx>, self_ty: Option>, types: Vec>, - regions: Vec, - assoc_bindings: Vec<(ast::Ident, Ty<'tcx>)>) - -> Substs<'tcx> + regions: Vec) + -> Substs<'tcx> where AC: AstConv<'tcx>, RS: RegionScope { let tcx = this.tcx(); @@ -382,52 +402,21 @@ fn create_substs_for_ast_path<'tcx,AC,RS>( } } - for formal_assoc in decl_generics.types.get_slice(AssocSpace).iter() { - let mut found = false; - for &(ident, ty) in assoc_bindings.iter() { - if formal_assoc.name.ident() == ident { - substs.types.push(AssocSpace, ty); - found = true; - break; - } - } - if !found { - match this.associated_type_binding(span, - self_ty, - decl_def_id, - formal_assoc.def_id) { - Some(ty) => { - substs.types.push(AssocSpace, ty); - } - None => { - substs.types.push(AssocSpace, ty::mk_err()); - span_err!(this.tcx().sess, span, E0171, - "missing type for associated type `{}`", - token::get_ident(formal_assoc.name.ident())); - } - } - } - } - - for &(ident, _) in assoc_bindings.iter() { - let mut formal_idents = decl_generics.types.get_slice(AssocSpace) - .iter().map(|t| t.name.ident()); - if !formal_idents.any(|i| i == ident) { - span_err!(this.tcx().sess, span, E0177, - "associated type `{}` does not exist", - token::get_ident(ident)); - } - } - return substs; } +struct ConvertedBinding<'tcx> { + item_name: ast::Name, + ty: Ty<'tcx>, + span: Span, +} + fn convert_angle_bracketed_parameters<'tcx, AC, RS>(this: &AC, rscope: &RS, data: &ast::AngleBracketedParameterData) -> (Vec, Vec>, - Vec<(ast::Ident, Ty<'tcx>)>) + Vec>) where AC: AstConv<'tcx>, RS: RegionScope { let regions: Vec<_> = @@ -442,7 +431,9 @@ fn convert_angle_bracketed_parameters<'tcx, AC, RS>(this: &AC, let assoc_bindings: Vec<_> = data.bindings.iter() - .map(|b| (b.ident, ast_ty_to_ty(this, rscope, &*b.ty))) + .map(|b| ConvertedBinding { item_name: b.ident.name, + ty: ast_ty_to_ty(this, rscope, &*b.ty), + span: b.span }) .collect(); (regions, types, assoc_bindings) @@ -534,38 +525,47 @@ pub fn instantiate_poly_trait_ref<'tcx,AC,RS>( rscope: &RS, ast_trait_ref: &ast::PolyTraitRef, self_ty: Option>, - allow_eq: AllowEqConstraints) - -> Rc> + poly_projections: &mut Vec>) + -> ty::PolyTraitRef<'tcx> where AC: AstConv<'tcx>, RS: RegionScope { + let mut projections = Vec::new(); + let trait_ref = - instantiate_trait_ref(this, rscope, &ast_trait_ref.trait_ref, self_ty, allow_eq); - let trait_ref = (*trait_ref).clone(); - Rc::new(ty::Binder(trait_ref)) // Ugh. + instantiate_trait_ref(this, rscope, &ast_trait_ref.trait_ref, + self_ty, Some(&mut projections)); + + for projection in projections.into_iter() { + poly_projections.push(ty::Binder(projection)); + } + + ty::Binder(trait_ref) } /// Instantiates the path for the given trait reference, assuming that it's /// bound to a valid trait type. Returns the def_id for the defining trait. /// Fails if the type is a type other than a trait type. -pub fn instantiate_trait_ref<'tcx,AC,RS>(this: &AC, - rscope: &RS, - ast_trait_ref: &ast::TraitRef, - self_ty: Option>, - allow_eq: AllowEqConstraints) - -> Rc> - where AC: AstConv<'tcx>, - RS: RegionScope +/// +/// If the `projections` argument is `None`, then assoc type bindings like `Foo` +/// are disallowed. Otherwise, they are pushed onto the vector given. +pub fn instantiate_trait_ref<'tcx,AC,RS>( + this: &AC, + rscope: &RS, + ast_trait_ref: &ast::TraitRef, + self_ty: Option>, + projections: Option<&mut Vec>>) + -> Rc> + where AC: AstConv<'tcx>, RS: RegionScope { match ::lookup_def_tcx(this.tcx(), ast_trait_ref.path.span, ast_trait_ref.ref_id) { def::DefTrait(trait_def_id) => { - let trait_ref = Rc::new(ast_path_to_trait_ref(this, - rscope, - trait_def_id, - self_ty, - &ast_trait_ref.path, - allow_eq)); - this.tcx().trait_refs.borrow_mut().insert(ast_trait_ref.ref_id, - trait_ref.clone()); + let trait_ref = ast_path_to_trait_ref(this, + rscope, + trait_def_id, + self_ty, + &ast_trait_ref.path, + projections); + this.tcx().trait_refs.borrow_mut().insert(ast_trait_ref.ref_id, trait_ref.clone()); trait_ref } _ => { @@ -576,20 +576,14 @@ pub fn instantiate_trait_ref<'tcx,AC,RS>(this: &AC, } } -#[deriving(PartialEq,Show)] -pub enum AllowEqConstraints { - Allow, - DontAllow -} - -fn ast_path_to_trait_ref<'tcx,AC,RS>( +fn ast_path_to_trait_ref<'a,'tcx,AC,RS>( this: &AC, rscope: &RS, trait_def_id: ast::DefId, self_ty: Option>, path: &ast::Path, - allow_eq: AllowEqConstraints) - -> ty::TraitRef<'tcx> + mut projections: Option<&mut Vec>>) + -> Rc> where AC: AstConv<'tcx>, RS: RegionScope { debug!("ast_path_to_trait_ref {}", path); @@ -624,11 +618,6 @@ fn ast_path_to_trait_ref<'tcx,AC,RS>( } }; - if allow_eq == AllowEqConstraints::DontAllow && assoc_bindings.len() > 0 { - span_err!(this.tcx().sess, path.span, E0173, - "equality constraints are not allowed in this position"); - } - let substs = create_substs_for_ast_path(this, &shifted_rscope, path.span, @@ -636,10 +625,69 @@ fn ast_path_to_trait_ref<'tcx,AC,RS>( &trait_def.generics, self_ty, types, - regions, - assoc_bindings); + regions); + let substs = this.tcx().mk_substs(substs); - ty::TraitRef::new(trait_def_id, this.tcx().mk_substs(substs)) + let trait_ref = Rc::new(ty::TraitRef::new(trait_def_id, substs)); + + match projections { + None => { + prohibit_projections(this.tcx(), assoc_bindings.as_slice()); + } + Some(ref mut v) => { + for binding in assoc_bindings.iter() { + match ast_type_binding_to_projection_predicate(this, trait_ref.clone(), binding) { + Ok(pp) => { v.push(pp); } + Err(ErrorReported) => { } + } + } + } + } + + trait_ref +} + +pub fn ast_type_binding_to_projection_predicate<'tcx,AC>( + this: &AC, + trait_ref: Rc>, + binding: &ConvertedBinding<'tcx>) + -> Result, ErrorReported> + where AC : AstConv<'tcx> +{ + // Given something like `U : SomeTrait`, we want to produce a + // predicate like `::T = X`. This is somewhat + // subtle in the event that `T` is defined in a supertrait of + // `SomeTrait`, because in that case we need to upcast. + // + // That is, consider this case: + // + // ``` + // trait SubTrait : SuperTrait { } + // trait SuperTrait { type T; } + // + // ... B : SubTrait ... + // ``` + // + // We want to produce `>::T == foo`. + + // FIXME(#19541): supertrait upcasting not actually impl'd :) + + if !trait_defines_associated_type_named(this, trait_ref.def_id, binding.item_name) { + this.tcx().sess.span_err( + binding.span, + format!("no associated type `{}` defined in `{}`", + token::get_name(binding.item_name), + trait_ref.user_string(this.tcx())).as_slice()); + return Err(ErrorReported); + } + + Ok(ty::ProjectionPredicate { + projection_ty: ty::ProjectionTy { + trait_ref: trait_ref, + item_name: binding.item_name, + }, + ty: binding.ty, + }) } pub fn ast_path_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>( @@ -784,12 +832,14 @@ fn ast_ty_to_trait_ref<'tcx,AC,RS>(this: &AC, ast::TyPath(ref path, id) => { match this.tcx().def_map.borrow().get(&id) { Some(&def::DefTrait(trait_def_id)) => { - return Ok(ty::Binder(ast_path_to_trait_ref(this, - rscope, - trait_def_id, - None, - path, - AllowEqConstraints::Allow))); + // TODO do something with this + let mut projections = Vec::new(); + Ok(ty::Binder(ast_path_to_trait_ref(this, + rscope, + trait_def_id, + None, + path, + Some(&mut projections)))) } _ => { span_err!(this.tcx().sess, ty.span, E0172, "expected a reference to a trait"); @@ -831,7 +881,7 @@ fn ast_ty_to_trait_ref<'tcx,AC,RS>(this: &AC, fn trait_ref_to_object_type<'tcx,AC,RS>(this: &AC, rscope: &RS, span: Span, - trait_ref: ty::PolyTraitRef<'tcx>, + trait_ref: ty::Binder>, bounds: &[ast::TyParamBound]) -> Ty<'tcx> where AC : AstConv<'tcx>, RS : RegionScope @@ -849,6 +899,68 @@ fn trait_ref_to_object_type<'tcx,AC,RS>(this: &AC, result } +fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>, + ast_ty: &ast::Ty, + provenance: def::TyParamProvenance, + assoc_name: ast::Name) + -> Ty<'tcx> +{ + let tcx = this.tcx(); + let ty_param_def_id = provenance.def_id(); + let mut suitable_bounds: Vec<_>; + let ty_param_name: ast::Name; + { // contain scope of refcell: + let ty_param_defs = tcx.ty_param_defs.borrow(); + let ty_param_def = &ty_param_defs[ty_param_def_id.node]; + ty_param_name = ty_param_def.name; + + // FIXME(#19541): we should consider associated types in + // super-traits. Probably by elaborating the bounds. + + suitable_bounds = + ty_param_def.bounds.trait_bounds // TODO trait_bounds, no good + .iter() + .cloned() + .filter(|b| trait_defines_associated_type_named(this, b.def_id(), assoc_name)) + .collect(); + } + + if suitable_bounds.len() == 0 { + tcx.sess.span_err(ast_ty.span, + format!("associated type `{}` not found for type parameter `{}`", + token::get_name(assoc_name), + token::get_name(ty_param_name)).as_slice()); + return this.tcx().types.err; + } + + if suitable_bounds.len() > 1 { + tcx.sess.span_err(ast_ty.span, + format!("ambiguous associated type `{}` in bounds of `{}`", + token::get_name(assoc_name), + token::get_name(ty_param_name)).as_slice()); + + for suitable_bound in suitable_bounds.iter() { + span_note!(this.tcx().sess, ast_ty.span, + "associated type `{}` could derive from `{}`", + token::get_name(ty_param_name), + suitable_bound.user_string(this.tcx())); + } + } + + let suitable_bound = suitable_bounds.pop().unwrap().clone(); + return this.projected_ty_from_poly_trait_ref(ast_ty.span, suitable_bound, assoc_name); +} + +fn trait_defines_associated_type_named(this: &AstConv, + trait_def_id: ast::DefId, + assoc_name: ast::Name) + -> bool +{ + let tcx = this.tcx(); + let trait_def = ty::lookup_trait_def(tcx, trait_def_id); + trait_def.associated_type_names.contains(&assoc_name) +} + fn qpath_to_ty<'tcx,AC,RS>(this: &AC, rscope: &RS, ast_ty: &ast::Ty, // the TyQPath @@ -867,33 +979,13 @@ fn qpath_to_ty<'tcx,AC,RS>(this: &AC, rscope, &*qpath.trait_ref, Some(self_type), - AllowEqConstraints::DontAllow); + None); debug!("qpath_to_ty: trait_ref={}", trait_ref.repr(this.tcx())); - if let Some(ty) = find_assoc_ty(this, &*trait_ref, qpath.item_name) { - return ty; - } - - this.tcx().sess.span_bug(ast_ty.span, - "this associated type didn't get added \ - as a parameter for some reason") -} - -fn find_assoc_ty<'tcx, AC>(this: &AC, - trait_ref: &ty::TraitRef<'tcx>, - type_name: ast::Ident) - -> Option> -where AC: AstConv<'tcx> { - let trait_def = this.get_trait_def(trait_ref.def_id); - - for ty_param_def in trait_def.generics.types.get_slice(AssocSpace).iter() { - if ty_param_def.name == type_name.name { - return Some(trait_ref.substs.type_for_def(ty_param_def)); - } - } - - None + return this.projected_ty(ast_ty.span, + trait_ref, + qpath.item_name.name); // TODO change qpath to use name } // Parses the programmer's textual representation of a type into our @@ -928,6 +1020,7 @@ pub fn ast_ty_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>( ast::TyObjectSum(ref ty, ref bounds) => { match ast_ty_to_trait_ref(this, rscope, &**ty, bounds[]) { Ok(trait_ref) => { + let trait_ref = trait_ref.remove_rc(); trait_ref_to_object_type(this, rscope, ast_ty.span, trait_ref, bounds[]) } @@ -1000,13 +1093,16 @@ pub fn ast_ty_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>( def::DefTrait(trait_def_id) => { // N.B. this case overlaps somewhat with // TyObjectSum, see that fn for details - let result = ty::Binder(ast_path_to_trait_ref(this, - rscope, - trait_def_id, - None, - path, - AllowEqConstraints::Allow)); - trait_ref_to_object_type(this, rscope, path.span, result, &[]) + let mut projections = Vec::new(); // TODO + let trait_ref = ast_path_to_trait_ref(this, + rscope, + trait_def_id, + None, + path, + Some(&mut projections)); + let trait_ref = (*trait_ref).clone(); + let trait_ref = ty::Binder(trait_ref); + trait_ref_to_object_type(this, rscope, path.span, trait_ref, &[]) } def::DefTy(did, _) | def::DefStruct(did) => { ast_path_to_ty(this, rscope, did, path).ty @@ -1048,44 +1144,9 @@ pub fn ast_ty_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>( .get())[]); this.tcx().types.err } - def::DefAssociatedPath(typ, assoc_ident) => { - // FIXME(#19541): in both branches we should consider - // associated types in super-traits. - let (assoc_tys, tp_name): (Vec<_>, _) = match typ { - def::TyParamProvenance::FromParam(did) | - def::TyParamProvenance::FromSelf(did) => { - let ty_param_defs = tcx.ty_param_defs.borrow(); - let tp_def = &(*ty_param_defs)[did.node]; - let assoc_tys = tp_def.bounds.trait_bounds.iter() - .filter_map(|b| find_assoc_ty(this, &b.0, assoc_ident)) - .collect(); - (assoc_tys, token::get_name(tp_def.name).to_string()) - } - }; - - if assoc_tys.len() == 0 { - tcx.sess.span_err(ast_ty.span, - format!("associated type `{}` not \ - found for type parameter `{}`", - token::get_ident(assoc_ident), - tp_name).as_slice()); - return ty::mk_err() - } - - if assoc_tys.len() > 1 { - tcx.sess.span_err(ast_ty.span, - format!("ambiguous associated type \ - `{}` in bounds of `{}`", - token::get_ident(assoc_ident), - tp_name).as_slice()); - } - - let mut result_ty = assoc_tys[0]; - if let Some(substs) = this.get_free_substs() { - result_ty = result_ty.subst(tcx, substs); - } - - result_ty + def::DefAssociatedPath(provenance, assoc_ident) => { + // TODO update DefAssociatedPath to use name + associated_path_def_to_ty(this, ast_ty, provenance, assoc_ident.name) } _ => { tcx.sess.span_fatal(ast_ty.span, @@ -1440,7 +1501,7 @@ pub fn conv_existential_bounds<'tcx, AC: AstConv<'tcx>, RS:RegionScope>( this: &AC, rscope: &RS, span: Span, - principal_trait_ref: Option<&ty::PolyTraitRef<'tcx>>, // None for boxed closures + principal_trait_ref: Option<&ty::Binder>>, // None for boxed closures ast_bounds: &[ast::TyParamBound]) -> ty::ExistentialBounds { @@ -1461,13 +1522,15 @@ fn conv_ty_poly_trait_ref<'tcx, AC, RS>( { let mut partitioned_bounds = partition_bounds(this.tcx(), span, ast_bounds[]); + let mut projections = Vec::new(); let main_trait_bound = match partitioned_bounds.trait_bounds.remove(0) { Some(trait_bound) => { - Some(instantiate_poly_trait_ref(this, - rscope, - trait_bound, - None, - AllowEqConstraints::Allow)) + let ptr = instantiate_poly_trait_ref(this, + rscope, + trait_bound, + None, + &mut projections); + Some(ptr.remove_rc()) } None => { this.tcx().sess.span_err( @@ -1477,11 +1540,13 @@ fn conv_ty_poly_trait_ref<'tcx, AC, RS>( } }; + // TODO use projections somewhere + let bounds = conv_existential_bounds_from_partitioned_bounds(this, rscope, span, - main_trait_bound.as_ref().map(|tr| &**tr), + main_trait_bound.as_ref(), partitioned_bounds); match main_trait_bound { @@ -1494,7 +1559,7 @@ pub fn conv_existential_bounds_from_partitioned_bounds<'tcx, AC, RS>( this: &AC, rscope: &RS, span: Span, - principal_trait_ref: Option<&ty::PolyTraitRef<'tcx>>, // None for boxed closures + principal_trait_ref: Option<&ty::Binder>>, // None for boxed closures partitioned_bounds: PartitionedBounds) -> ty::ExistentialBounds where AC: AstConv<'tcx>, RS:RegionScope @@ -1532,7 +1597,7 @@ pub fn conv_existential_bounds_from_partitioned_bounds<'tcx, AC, RS>( fn compute_opt_region_bound<'tcx>(tcx: &ty::ctxt<'tcx>, span: Span, explicit_region_bounds: &[&ast::Lifetime], - principal_trait_ref: Option<&ty::PolyTraitRef<'tcx>>, + principal_trait_ref: Option<&ty::Binder>>, builtin_bounds: ty::BuiltinBounds) -> Option { @@ -1592,7 +1657,7 @@ fn compute_region_bound<'tcx, AC: AstConv<'tcx>, RS:RegionScope>( rscope: &RS, span: Span, region_bounds: &[&ast::Lifetime], - principal_trait_ref: Option<&ty::PolyTraitRef<'tcx>>, // None for closures + principal_trait_ref: Option<&ty::Binder>>, // None for closures builtin_bounds: ty::BuiltinBounds) -> ty::Region { @@ -1660,6 +1725,7 @@ pub fn partition_bounds<'a>(tcx: &ty::ctxt, if ty::try_add_builtin_trait(tcx, trait_did, &mut builtin_bounds) { + // TODO Copy? continue; // success } } @@ -1683,3 +1749,13 @@ pub fn partition_bounds<'a>(tcx: &ty::ctxt, region_bounds: region_bounds, } } + +fn prohibit_projections<'tcx>(tcx: &ty::ctxt<'tcx>, + bindings: &[ConvertedBinding<'tcx>]) +{ + for binding in bindings.iter().take(1) { + tcx.sess.span_err( + binding.span, + "associated type bindings are not allowed here"); + } +} diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index dc77a1e782b..0e8b5b373f1 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -11,7 +11,7 @@ use middle::def; use middle::infer; use middle::pat_util::{PatIdMap, pat_id_map, pat_is_binding, pat_is_const}; -use middle::subst::{Subst, Substs}; +use middle::subst::{Substs}; use middle::ty::{mod, Ty}; use check::{check_expr, check_expr_has_type, check_expr_with_expectation}; use check::{check_expr_coercable_to_type, demand, FnCtxt, Expectation}; @@ -410,17 +410,24 @@ pub fn check_pat_enum<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, pat: &ast::Pat, demand::eqtype(fcx, pat.span, expected, pat_ty); let real_path_ty = fcx.node_ty(pat.id); - let (arg_tys, kind_name) = match real_path_ty.sty { + let (arg_tys, kind_name): (Vec<_>, &'static str) = match real_path_ty.sty { ty::ty_enum(enum_def_id, expected_substs) - if def == def::DefVariant(enum_def_id, def.def_id(), false) => { + if def == def::DefVariant(enum_def_id, def.def_id(), false) => + { let variant = ty::enum_variant_with_id(tcx, enum_def_id, def.def_id()); - (variant.args.iter().map(|t| t.subst(tcx, expected_substs)).collect::>(), - "variant") + (variant.args.iter() + .map(|t| fcx.instantiate_type_scheme(pat.span, expected_substs, t)) + .collect(), + "variant") } ty::ty_struct(struct_def_id, expected_substs) => { let struct_fields = ty::struct_fields(tcx, struct_def_id, expected_substs); - (struct_fields.iter().map(|field| field.mt.ty).collect::>(), - "struct") + (struct_fields.iter() + .map(|field| fcx.instantiate_type_scheme(pat.span, + expected_substs, + &field.mt.ty)) + .collect(), + "struct") } _ => { let name = pprust::path_to_string(path); diff --git a/src/librustc_typeck/check/assoc.rs b/src/librustc_typeck/check/assoc.rs new file mode 100644 index 00000000000..65ade452fa1 --- /dev/null +++ b/src/librustc_typeck/check/assoc.rs @@ -0,0 +1,73 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// 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. + +use middle::infer::InferCtxt; +use middle::traits::{ObligationCause, ObligationCauseCode, FulfillmentContext}; +use middle::ty::{mod, HasProjectionTypes, Ty}; +use middle::ty_fold::{mod, TypeFoldable, TypeFolder}; +use syntax::ast; +use syntax::codemap::Span; +use std::rc::Rc; + +pub fn normalize_associated_types_in<'a,'tcx,T>(infcx: &InferCtxt<'a,'tcx>, + fulfillment_cx: &mut FulfillmentContext<'tcx>, + span: Span, + body_id: ast::NodeId, + value: &T) + -> T + where T : TypeFoldable<'tcx> + HasProjectionTypes + Clone +{ + let value = infcx.resolve_type_vars_if_possible(value); + + if !value.has_projection_types() { + return value.clone(); + } + + let mut normalizer = AssociatedTypeNormalizer { span: span, + body_id: body_id, + infcx: infcx, + fulfillment_cx: fulfillment_cx }; + value.fold_with(&mut normalizer) +} + +struct AssociatedTypeNormalizer<'a,'tcx:'a> { + infcx: &'a InferCtxt<'a, 'tcx>, + fulfillment_cx: &'a mut FulfillmentContext<'tcx>, + span: Span, + body_id: ast::NodeId, +} + +impl<'a,'tcx> TypeFolder<'tcx> for AssociatedTypeNormalizer<'a,'tcx> { + fn tcx(&self) -> &ty::ctxt<'tcx> { + self.infcx.tcx + } + + fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { + match ty.sty { + ty::ty_projection(ref data) => { + let cause = + ObligationCause::new( + self.span, + self.body_id, + ObligationCauseCode::MiscObligation); + let trait_ref = Rc::new(data.trait_ref.clone()); + self.fulfillment_cx + .normalize_associated_type(self.infcx, + trait_ref, + data.item_name, + cause) + } + _ => { + ty_fold::super_fold_ty(self, ty) + } + } + } +} diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index c8a8a0ff559..ec964ab638f 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -15,7 +15,7 @@ use super::{check_fn, Expectation, FnCtxt}; use astconv; use middle::infer; use middle::subst; -use middle::ty::{mod, Ty}; +use middle::ty::{mod, ToPolyTraitRef, Ty}; use rscope::RegionScope; use syntax::abi; use syntax::ast; @@ -168,7 +168,8 @@ fn deduce_unboxed_closure_expectations_from_expected_type<'a,'tcx>( { match expected_ty.sty { ty::ty_trait(ref object_type) => { - deduce_unboxed_closure_expectations_from_trait_ref(fcx, &object_type.principal) + let trait_ref = object_type.principal_trait_ref_with_self_ty(fcx.tcx().types.err); + deduce_unboxed_closure_expectations_from_trait_ref(fcx, &trait_ref) } ty::ty_infer(ty::TyVar(vid)) => { deduce_unboxed_closure_expectations_from_obligations(fcx, vid) @@ -227,23 +228,21 @@ fn deduce_unboxed_closure_expectations_from_obligations<'a,'tcx>( { // Here `expected_ty` is known to be a type inference variable. for obligation in fcx.inh.fulfillment_cx.borrow().pending_obligations().iter() { - match obligation.trait_ref { - ty::Predicate::Trait(ref trait_ref) => { + match obligation.predicate { + ty::Predicate::Trait(ref trait_predicate) => { + let trait_ref = trait_predicate.to_poly_trait_ref(); let self_ty = fcx.infcx().shallow_resolve(trait_ref.self_ty()); match self_ty.sty { ty::ty_infer(ty::TyVar(v)) if expected_vid == v => { } _ => { continue; } } - match deduce_unboxed_closure_expectations_from_trait_ref(fcx, &**trait_ref) { + match deduce_unboxed_closure_expectations_from_trait_ref(fcx, &trait_ref) { Some(e) => { return Some(e); } None => { } } } - ty::Predicate::Equate(..) | - ty::Predicate::RegionOutlives(..) | - ty::Predicate::TypeOutlives(..) => { - } + _ => { } } } diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index 791ebc5d0ea..de6824fa5dd 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -11,7 +11,7 @@ use super::probe; use check::{mod, FnCtxt, NoPreference, PreferMutLvalue, callee}; -use middle::subst::{mod, Subst}; +use middle::subst::{mod}; use middle::traits; use middle::ty::{mod, Ty}; use middle::ty::{MethodCall, MethodCallee, MethodObject, MethodOrigin, @@ -227,14 +227,14 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { let upcast_poly_trait_ref = this.upcast(original_poly_trait_ref.clone(), trait_def_id); let upcast_trait_ref = - this.replace_late_bound_regions_with_fresh_var(&*upcast_poly_trait_ref); + this.replace_late_bound_regions_with_fresh_var(&upcast_poly_trait_ref); debug!("original_poly_trait_ref={} upcast_trait_ref={} target_trait={}", original_poly_trait_ref.repr(this.tcx()), upcast_trait_ref.repr(this.tcx()), trait_def_id.repr(this.tcx())); let substs = upcast_trait_ref.substs.clone(); let origin = MethodTraitObject(MethodObject { - trait_ref: Rc::new(upcast_trait_ref), + trait_ref: upcast_trait_ref, object_trait_id: trait_def_id, method_num: method_num, real_index: real_index, @@ -254,9 +254,11 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { // parameters from the trait ([$A,$B]), not those from // the impl ([$A,$B,$C]) not the receiver type ([$C]). let impl_polytype = check::impl_self_ty(self.fcx, self.span, impl_def_id); - let impl_trait_ref = ty::impl_trait_ref(self.tcx(), impl_def_id) - .unwrap() - .subst(self.tcx(), &impl_polytype.substs); + let impl_trait_ref = + self.fcx.instantiate_type_scheme( + self.span, + &impl_polytype.substs, + &ty::impl_trait_ref(self.tcx(), impl_def_id).unwrap()); let origin = MethodTypeParam(MethodParam { trait_ref: impl_trait_ref.clone(), method_num: method_num }); (impl_trait_ref.substs.clone(), origin) @@ -284,9 +286,9 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { probe::WhereClausePick(ref poly_trait_ref, method_num) => { // Where clauses can have bound regions in them. We need to instantiate // those to convert from a poly-trait-ref to a trait-ref. - let trait_ref = self.replace_late_bound_regions_with_fresh_var(&**poly_trait_ref); + let trait_ref = self.replace_late_bound_regions_with_fresh_var(&*poly_trait_ref); let substs = trait_ref.substs.clone(); - let origin = MethodTypeParam(MethodParam { trait_ref: Rc::new(trait_ref), + let origin = MethodTypeParam(MethodParam { trait_ref: trait_ref, method_num: method_num }); (substs, origin) } @@ -425,9 +427,13 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { // Substitute the type/early-bound-regions into the method // signature. In addition, the method signature may bind // late-bound regions, so instantiate those. - let method_sig = pick.method_ty.fty.sig.subst(self.tcx(), &all_substs); - let method_sig = self.replace_late_bound_regions_with_fresh_var(&method_sig); + let method_sig = self.fcx.instantiate_type_scheme(self.span, + &all_substs, + &pick.method_ty.fty.sig); + debug!("late-bound lifetimes from method substituted, method_sig={}", + method_sig.repr(self.tcx())); + let method_sig = self.replace_late_bound_regions_with_fresh_var(&method_sig); debug!("late-bound lifetimes from method instantiated, method_sig={}", method_sig.repr(self.tcx())); @@ -626,9 +632,9 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { } fn upcast(&mut self, - source_trait_ref: Rc>, + source_trait_ref: ty::PolyTraitRef<'tcx>, target_trait_def_id: ast::DefId) - -> Rc> + -> ty::PolyTraitRef<'tcx> { for super_trait_ref in traits::supertraits(self.tcx(), source_trait_ref.clone()) { if super_trait_ref.def_id() == target_trait_def_id { diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index 0c094823a75..cb71fbce8ac 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -16,7 +16,6 @@ use check::{impl_self_ty}; use check::vtable; use check::vtable::select_new_fcx_obligations; use middle::subst; -use middle::subst::{Subst}; use middle::traits; use middle::ty::*; use middle::ty; @@ -167,7 +166,7 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &'a FnCtxt<'a, 'tcx>, let trait_ref = Rc::new(ty::TraitRef::new(trait_def_id, fcx.tcx().mk_substs(substs))); // Construct an obligation - let poly_trait_ref = Rc::new(ty::Binder((*trait_ref).clone())); + let poly_trait_ref = trait_ref.to_poly_trait_ref(); let obligation = traits::Obligation::misc(span, fcx.body_id, poly_trait_ref.as_predicate()); @@ -193,11 +192,12 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &'a FnCtxt<'a, 'tcx>, // Substitute the trait parameters into the method type and // instantiate late-bound regions to get the actual method type. - let ref bare_fn_ty = method_ty.fty; - let fn_sig = bare_fn_ty.sig.subst(tcx, trait_ref.substs); + let bare_fn_ty = fcx.instantiate_type_scheme(span, + &trait_ref.substs, + &method_ty.fty); let fn_sig = fcx.infcx().replace_late_bound_regions_with_fresh_var(span, infer::FnCall, - &fn_sig).0; + &bare_fn_ty.sig).0; let transformed_self_ty = fn_sig.inputs[0]; let fty = ty::mk_bare_fn(tcx, None, tcx.mk_bare_fn(ty::BareFnTy { sig: ty::Binder(fn_sig), diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 3ecd2007ff1..1a9e124521e 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -18,7 +18,7 @@ use middle::fast_reject; use middle::subst; use middle::subst::Subst; use middle::traits; -use middle::ty::{mod, Ty}; +use middle::ty::{mod, Ty, ToPolyTraitRef}; use middle::ty_fold::TypeFoldable; use middle::infer; use middle::infer::InferCtxt; @@ -61,7 +61,7 @@ enum CandidateKind<'tcx> { ExtensionImplCandidate(/* Impl */ ast::DefId, Rc>, subst::Substs<'tcx>, MethodIndex), UnboxedClosureCandidate(/* Trait */ ast::DefId, MethodIndex), - WhereClauseCandidate(Rc>, MethodIndex), + WhereClauseCandidate(ty::PolyTraitRef<'tcx>, MethodIndex), } pub struct Pick<'tcx> { @@ -76,7 +76,7 @@ pub enum PickKind<'tcx> { ObjectPick(/* Trait */ ast::DefId, /* method_num */ uint, /* real_index */ uint), ExtensionImplPick(/* Impl */ ast::DefId, MethodIndex), TraitPick(/* Trait */ ast::DefId, MethodIndex), - WhereClausePick(/* Trait */ Rc>, MethodIndex), + WhereClausePick(/* Trait */ ty::PolyTraitRef<'tcx>, MethodIndex), } pub type PickResult<'tcx> = Result, MethodError>; @@ -235,7 +235,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { match self_ty.sty { ty::ty_trait(box ref data) => { self.assemble_inherent_candidates_from_object(self_ty, data); - self.assemble_inherent_impl_candidates_for_type(data.principal.def_id()); + self.assemble_inherent_impl_candidates_for_type(data.principal_def_id()); } ty::ty_enum(did, _) | ty::ty_struct(did, _) | @@ -308,7 +308,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { let trait_ref = data.principal_trait_ref_with_self_ty(self.tcx(), self_ty); self.elaborate_bounds(&[trait_ref.clone()], false, |this, new_trait_ref, m, method_num| { let vtable_index = - get_method_index(tcx, &*new_trait_ref, trait_ref.clone(), method_num); + get_method_index(tcx, &new_trait_ref, trait_ref.clone(), method_num); let xform_self_ty = this.xform_self_ty(&m, new_trait_ref.substs()); @@ -330,13 +330,16 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { .iter() .filter_map(|predicate| { match *predicate { - ty::Predicate::Trait(ref trait_ref) => { - match trait_ref.self_ty().sty { - ty::ty_param(ref p) if *p == param_ty => Some(trait_ref.clone()), + ty::Predicate::Trait(ref trait_predicate) => { + match trait_predicate.0.trait_ref.self_ty().sty { + ty::ty_param(ref p) if *p == param_ty => { + Some(trait_predicate.to_poly_trait_ref()) + } _ => None } } ty::Predicate::Equate(..) | + ty::Predicate::Projection(..) | ty::Predicate::RegionOutlives(..) | ty::Predicate::TypeOutlives(..) => { None @@ -381,10 +384,10 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { // create the candidates. fn elaborate_bounds( &mut self, - bounds: &[Rc>], + bounds: &[ty::PolyTraitRef<'tcx>], num_includes_types: bool, mk_cand: for<'b> |this: &mut ProbeContext<'b, 'tcx>, - tr: Rc>, + tr: ty::PolyTraitRef<'tcx>, m: Rc>, method_num: uint|) { @@ -996,7 +999,7 @@ fn trait_method<'tcx>(tcx: &ty::ctxt<'tcx>, // to a trait and its supertraits. fn get_method_index<'tcx>(tcx: &ty::ctxt<'tcx>, trait_ref: &ty::PolyTraitRef<'tcx>, - subtrait: Rc>, + subtrait: ty::PolyTraitRef<'tcx>, n_method: uint) -> uint { // We need to figure the "real index" of the method in a // listing of all the methods of an object. We do this by diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 7a6b2d54dc1..be8fa21cf0e 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -93,10 +93,10 @@ 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, Ty}; +use middle::ty::{mod, HasProjectionTypes, Ty}; use middle::ty::liberate_late_bound_regions; use middle::ty::{MethodCall, MethodCallee, MethodMap, ObjectCastMap}; -use middle::ty_fold::TypeFolder; +use middle::ty_fold::{TypeFolder, TypeFoldable}; use rscope::RegionScope; use session::Session; use {CrateCtxt, lookup_def_ccx, no_params, require_same_types}; @@ -120,6 +120,7 @@ use syntax::print::pprust; use syntax::ptr::P; use syntax::visit::{mod, Visitor}; +mod assoc; pub mod _match; pub mod vtable; pub mod writeback; @@ -348,6 +349,17 @@ impl<'a, 'tcx> Inherited<'a, 'tcx> { fulfillment_cx: RefCell::new(traits::FulfillmentContext::new()), } } + + fn normalize_associated_types_in(&self, span: Span, body_id: ast::NodeId, value: &T) -> T + where T : TypeFoldable<'tcx> + Clone + HasProjectionTypes + { + let mut fulfillment_cx = self.fulfillment_cx.borrow_mut(); + assoc::normalize_associated_types_in(&self.infcx, + &mut *fulfillment_cx, span, + body_id, + value) + } + } // Used by check_const and check_enum_variants @@ -414,15 +426,18 @@ fn check_bare_fn<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, decl: &ast::FnDecl, body: &ast::Block, id: ast::NodeId, - fty: Ty<'tcx>, + raw_fty: Ty<'tcx>, param_env: ty::ParameterEnvironment<'tcx>) { - // Compute the fty from point of view of inside fn - // (replace any type-scheme with a type) - let fty = fty.subst(ccx.tcx, ¶m_env.free_substs); - - match fty.sty { + match raw_fty.sty { ty::ty_bare_fn(_, ref fn_ty) => { let inh = Inherited::new(ccx.tcx, param_env); + + // Compute the fty from point of view of inside fn + // (replace any type-scheme with a type, and normalize + // associated types appearing in the fn signature). + let fn_ty = fn_ty.subst(ccx.tcx, &inh.param_env.free_substs); + let fn_ty = inh.normalize_associated_types_in(body.span, body.id, &fn_ty); + let fcx = check_fn(ccx, fn_ty.unsafety, id, &fn_ty.sig, decl, id, body, &inh); @@ -532,7 +547,8 @@ fn check_fn<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>, fn_id: ast::NodeId, body: &ast::Block, inherited: &'a Inherited<'a, 'tcx>) - -> FnCtxt<'a, 'tcx> { + -> FnCtxt<'a, 'tcx> +{ let tcx = ccx.tcx; let err_count_on_creation = tcx.sess.err_count(); @@ -771,9 +787,7 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, // corresponding method definition in the trait. let opt_trait_method_ty = trait_items.iter() - .find(|ti| { - ti.name() == impl_item_ty.name() - }); + .find(|ti| ti.name() == impl_item_ty.name()); match opt_trait_method_ty { Some(trait_method_ty) => { match (trait_method_ty, &impl_item_ty) { @@ -917,6 +931,7 @@ fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>, impl_trait_ref.repr(tcx)); let infcx = infer::new_infer_ctxt(tcx); + let mut fulfillment_cx = traits::FulfillmentContext::new(); let trait_to_impl_substs = &impl_trait_ref.substs; @@ -1034,21 +1049,15 @@ fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>, // this kind of equivalency just fine. // Create mapping from impl to skolemized. - let skol_tps = - impl_m.generics.types.map( - |d| ty::mk_param_from_def(tcx, d)); - let skol_regions = - impl_m.generics.regions.map( - |l| ty::free_region_from_def(impl_m_body_id, l)); - let impl_to_skol_substs = - subst::Substs::new(skol_tps.clone(), skol_regions.clone()); + let impl_param_env = ty::construct_parameter_environment(tcx, &impl_m.generics, impl_m_body_id); + let impl_to_skol_substs = &impl_param_env.free_substs; // Create mapping from trait to skolemized. let trait_to_skol_substs = trait_to_impl_substs - .subst(tcx, &impl_to_skol_substs) - .with_method(skol_tps.get_slice(subst::FnSpace).to_vec(), - skol_regions.get_slice(subst::FnSpace).to_vec()); + .subst(tcx, impl_to_skol_substs) + .with_method(impl_to_skol_substs.types.get_slice(subst::FnSpace).to_vec(), + impl_to_skol_substs.regions().get_slice(subst::FnSpace).to_vec()); // Check region bounds. if !check_region_bounds_on_impl_method(tcx, @@ -1057,7 +1066,7 @@ fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>, &trait_m.generics, &impl_m.generics, &trait_to_skol_substs, - &impl_to_skol_substs) { + impl_to_skol_substs) { return; } @@ -1120,7 +1129,7 @@ fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>, for impl_trait_bound in impl_param_bounds.trait_bounds.iter() { debug!("compare_impl_method(): impl-trait-bound subst"); let impl_trait_bound = - impl_trait_bound.subst(tcx, &impl_to_skol_substs); + impl_trait_bound.subst(tcx, impl_to_skol_substs); // There may be late-bound regions from the impl in the // impl's bound, so "liberate" those. Note that the @@ -1134,7 +1143,6 @@ fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>, debug!("compare_impl_method(): trait-bound subst"); let trait_bound = trait_bound.subst(tcx, &trait_to_skol_substs); - let infcx = infer::new_infer_ctxt(tcx); infer::mk_sub_poly_trait_refs(&infcx, true, infer::Misc(impl_m_span), @@ -1155,9 +1163,15 @@ fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>, // Compute skolemized form of impl and trait method tys. let impl_fty = ty::mk_bare_fn(tcx, None, tcx.mk_bare_fn(impl_m.fty.clone())); - let impl_fty = impl_fty.subst(tcx, &impl_to_skol_substs); + let impl_fty = impl_fty.subst(tcx, impl_to_skol_substs); let trait_fty = ty::mk_bare_fn(tcx, None, tcx.mk_bare_fn(trait_m.fty.clone())); let trait_fty = trait_fty.subst(tcx, &trait_to_skol_substs); + let trait_fty = + assoc::normalize_associated_types_in(&infcx, + &mut fulfillment_cx, + impl_m_span, + impl_m_body_id, + &trait_fty); // Check the impl method type IM is a subtype of the trait method // type TM. To see why this makes sense, think of a vtable. The @@ -1183,6 +1197,15 @@ fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>, } } + // Run the fulfillment context to completion to accommodate any + // associated type normalizations that may have occurred. + match fulfillment_cx.select_all_or_error(&infcx, &impl_param_env, tcx) { + Ok(()) => { } + Err(errors) => { + traits::report_fulfillment_errors(&infcx, &errors); + } + } + // Finally, resolve all regions. This catches wily misuses of lifetime // parameters. infcx.resolve_regions_and_report_errors(impl_m_body_id); @@ -1526,19 +1549,28 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> { self.infcx().next_ty_var() } - fn associated_types_of_trait_are_valid(&self, _: Ty, _: ast::DefId) - -> bool { - false + fn projected_ty_from_poly_trait_ref(&self, + span: Span, + poly_trait_ref: ty::PolyTraitRef<'tcx>, + item_name: ast::Name) + -> Ty<'tcx> + { + let (trait_ref, _) = + self.infcx().replace_late_bound_regions_with_fresh_var( + span, + infer::LateBoundRegionConversionTime::AssocTypeProjection(item_name), + &poly_trait_ref); + + self.normalize_associated_type(span, trait_ref, item_name) } - fn associated_type_binding(&self, - span: Span, - _: Option>, - _: ast::DefId, - _: ast::DefId) - -> Option> { - self.tcx().sess.span_err(span, "unsupported associated type binding"); - Some(ty::mk_err()) + fn projected_ty(&self, + span: Span, + trait_ref: Rc>, + item_name: ast::Name) + -> Ty<'tcx> + { + self.normalize_associated_type(span, trait_ref, item_name) } } @@ -1560,22 +1592,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn err_count_since_creation(&self) -> uint { self.ccx.tcx.sess.err_count() - self.err_count_on_creation } -} -impl<'a, 'tcx> RegionScope for infer::InferCtxt<'a, 'tcx> { - fn default_region_bound(&self, span: Span) -> Option { - Some(self.next_region_var(infer::MiscVariable(span))) - } - - fn anon_regions(&self, span: Span, count: uint) - -> Result, Option>> { - Ok(Vec::from_fn(count, |_| { - self.next_region_var(infer::MiscVariable(span)) - })) - } -} - -impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn tag(&self) -> String { format!("{}", self as *const FnCtxt) } @@ -1609,7 +1626,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn write_object_cast(&self, key: ast::NodeId, - trait_ref: Rc>) { + trait_ref: ty::PolyTraitRef<'tcx>) { debug!("write_object_cast key={} trait_ref={}", key, trait_ref.repr(self.tcx())); self.inh.object_cast_map.borrow_mut().insert(key, trait_ref); @@ -1660,6 +1677,48 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.inh.adjustments.borrow_mut().insert(node_id, adj); } + /// Basically whenever we are converting from a type scheme into + /// the fn body space, we always want to normalize associated + /// types as well. This function combines the two. + fn instantiate_type_scheme(&self, + span: Span, + substs: &Substs<'tcx>, + value: &T) + -> T + where T : TypeFoldable<'tcx> + Clone + HasProjectionTypes + Repr<'tcx> + { + let value = value.subst(self.tcx(), substs); + let result = self.normalize_associated_types_in(span, &value); + debug!("instantiate_type_scheme(value={}, substs={}) = {}", + value.repr(self.tcx()), + substs.repr(self.tcx()), + result.repr(self.tcx())); + result + } + + fn normalize_associated_types_in(&self, span: Span, value: &T) -> T + where T : TypeFoldable<'tcx> + Clone + HasProjectionTypes + { + self.inh.normalize_associated_types_in(span, self.body_id, value) + } + + fn normalize_associated_type(&self, + span: Span, + trait_ref: Rc>, + item_name: ast::Name) + -> Ty<'tcx> + { + let cause = traits::ObligationCause::new(span, + self.body_id, + traits::ObligationCauseCode::MiscObligation); + self.inh.fulfillment_cx + .borrow_mut() + .normalize_associated_type(self.infcx(), + trait_ref, + item_name, + cause) + } + fn register_adjustment_obligations(&self, span: Span, adj: &ty::AutoAdjustment<'tcx>) { @@ -1754,7 +1813,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { traits::ItemObligation(def_id)), &bounds); let monotype = - type_scheme.ty.subst(self.tcx(), &substs); + self.instantiate_type_scheme(span, &substs, &type_scheme.ty); TypeAndSubsts { ty: monotype, @@ -2017,7 +2076,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } -#[deriving(Copy, Show,PartialEq,Eq)] +//impl<'a, 'tcx> RegionScope for infer::InferCtxt<'a, 'tcx> { +// fn default_region_bound(&self, span: Span) -> Option { +// Some(self.next_region_var(infer::MiscVariable(span))) +// } +// +// fn anon_regions(&self, span: Span, count: uint) +// -> Result, Option>> { +// Ok(Vec::from_fn(count, |_| { +// self.next_region_var(infer::MiscVariable(span)) +// })) +// } +//} + +#[deriving(Copy, Show, PartialEq, Eq)] pub enum LvaluePreference { PreferMutLvalue, NoPreference @@ -2879,7 +2951,7 @@ pub fn impl_self_ty<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, let rps = fcx.inh.infcx.region_vars_for_defs(span, rps); let tps = fcx.inh.infcx.next_ty_vars(n_tps); let substs = subst::Substs::new_type(tps, rps); - let substd_ty = raw_ty.subst(tcx, &substs); + let substd_ty = fcx.instantiate_type_scheme(span, &substs, &raw_ty); TypeAndSubsts { substs: substs, ty: substd_ty } } @@ -5219,9 +5291,7 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // Substitute the values for the type parameters into the type of // the referenced item. - let ty_substituted = ty_late_bound.subst(fcx.tcx(), &substs); - - debug!("ty_substituted: ty_substituted={}", ty_substituted.repr(fcx.tcx())); + let ty_substituted = fcx.instantiate_type_scheme(span, &substs, &ty_late_bound); fcx.write_ty(node_id, ty_substituted); fcx.write_substs(node_id, ty::ItemSubsts { substs: substs }); diff --git a/src/librustc_typeck/check/regionmanip.rs b/src/librustc_typeck/check/regionmanip.rs index ea70b9d9e2e..14405b9a92b 100644 --- a/src/librustc_typeck/check/regionmanip.rs +++ b/src/librustc_typeck/check/regionmanip.rs @@ -121,6 +121,15 @@ impl<'a, 'tcx> Wf<'a, 'tcx> { self.push_param_constraint_from_top(p); } + ty::ty_projection(ref data) => { + // `>::Name` + + // TODO What region constraints are necessary here, if any?? + + // this seems like a minimal requirement: + self.accumulate_from_ty(data.trait_ref.self_ty()); + } + ty::ty_tup(ref tuptys) => { for &tupty in tuptys.iter() { self.accumulate_from_ty(tupty); diff --git a/src/librustc_typeck/check/vtable.rs b/src/librustc_typeck/check/vtable.rs index 626845613b4..98badf9c049 100644 --- a/src/librustc_typeck/check/vtable.rs +++ b/src/librustc_typeck/check/vtable.rs @@ -13,7 +13,7 @@ use middle::subst::{FnSpace}; use middle::traits; use middle::traits::{Obligation, ObligationCause}; use middle::traits::report_fulfillment_errors; -use middle::ty::{mod, Ty}; +use middle::ty::{mod, Ty, AsPredicate, ToPolyTraitRef}; use middle::infer; use std::rc::Rc; use syntax::ast; @@ -136,7 +136,7 @@ pub fn check_object_safety<'tcx>(tcx: &ty::ctxt<'tcx>, let object_trait_ref = object_trait.principal_trait_ref_with_self_ty(tcx, tcx.types.err); for tr in traits::supertraits(tcx, object_trait_ref) { - check_object_safety_inner(tcx, &*tr, span); + check_object_safety_inner(tcx, &tr, span); } } @@ -231,7 +231,7 @@ pub fn register_object_cast_obligations<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, span: Span, object_trait: &ty::TyTrait<'tcx>, referent_ty: Ty<'tcx>) - -> Rc> + -> ty::PolyTraitRef<'tcx> { // We can only make objects from sized types. fcx.register_builtin_bound( @@ -258,7 +258,7 @@ pub fn register_object_cast_obligations<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, ObligationCause::new(span, fcx.body_id, traits::ObjectCastObligation(object_trait_ty)), - ty::Predicate::Trait(object_trait_ref.clone())); + object_trait_ref.as_predicate()); fcx.register_predicate(object_obligation); // Create additional obligations for all the various builtin @@ -314,3 +314,4 @@ pub fn select_new_fcx_obligations(fcx: &FnCtxt) { Err(errors) => { report_fulfillment_errors(fcx.infcx(), &errors); } } } + diff --git a/src/librustc_typeck/check/wf.rs b/src/librustc_typeck/check/wf.rs index 3ddc81d40a5..21c81c7be9b 100644 --- a/src/librustc_typeck/check/wf.rs +++ b/src/librustc_typeck/check/wf.rs @@ -13,7 +13,6 @@ use check::{FnCtxt, Inherited, blank_fn_ctxt, vtable, regionck}; use CrateCtxt; use middle::region; use middle::subst; -use middle::subst::{Subst}; use middle::traits; use middle::ty::{mod, Ty}; use middle::ty::liberate_late_bound_regions; @@ -148,7 +147,9 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { region::CodeExtent::from_node_id(item.id), Some(&mut this.cache)); let type_scheme = ty::lookup_item_type(fcx.tcx(), local_def(item.id)); - let item_ty = type_scheme.ty.subst(fcx.tcx(), &fcx.inh.param_env.free_substs); + let item_ty = fcx.instantiate_type_scheme(item.span, + &fcx.inh.param_env.free_substs, + &type_scheme.ty); bounds_checker.check_traits_in_ty(item_ty); }); } @@ -168,7 +169,9 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { // that is, with all type parameters converted from bound // to free. let self_ty = ty::node_id_to_type(fcx.tcx(), item.id); - let self_ty = self_ty.subst(fcx.tcx(), &fcx.inh.param_env.free_substs); + let self_ty = fcx.instantiate_type_scheme(item.span, + &fcx.inh.param_env.free_substs, + &self_ty); bounds_checker.check_traits_in_ty(self_ty); @@ -178,7 +181,9 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { None => { return; } Some(t) => { t } }; - let trait_ref = (*trait_ref).subst(fcx.tcx(), &fcx.inh.param_env.free_substs); + let trait_ref = fcx.instantiate_type_scheme(item.span, + &fcx.inh.param_env.free_substs, + &trait_ref); // There are special rules that apply to drop. if @@ -209,7 +214,7 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { // trait reference. Instead, this is done at the impl site. // Arguably this is wrong and we should treat the trait-reference // the same way as we treat the self-type. - bounds_checker.check_trait_ref(&trait_ref); + bounds_checker.check_trait_ref(&*trait_ref); let cause = traits::ObligationCause::new( @@ -344,7 +349,8 @@ 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 = 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, @@ -397,7 +403,9 @@ fn struct_variant<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, .iter() .map(|field| { let field_ty = ty::node_id_to_type(fcx.tcx(), field.node.id); - let field_ty = field_ty.subst(fcx.tcx(), &fcx.inh.param_env.free_substs); + let field_ty = fcx.instantiate_type_scheme(field.span, + &fcx.inh.param_env.free_substs, + &field_ty); AdtField { ty: field_ty, span: field.span } }) .collect(); @@ -416,7 +424,10 @@ fn enum_variants<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, AdtVariant { fields: args.iter().enumerate().map(|(index, arg)| { let arg_ty = arg_tys[index]; - let arg_ty = arg_ty.subst(fcx.tcx(), &fcx.inh.param_env.free_substs); + let arg_ty = + fcx.instantiate_type_scheme(variant.span, + &fcx.inh.param_env.free_substs, + &arg_ty); AdtField { ty: arg_ty, span: arg.ty.span @@ -443,7 +454,8 @@ fn filter_to_trait_obligations<'tcx>(bounds: ty::GenericBounds<'tcx>) let mut result = ty::GenericBounds::empty(); for (space, _, predicate) in bounds.predicates.iter_enumerated() { match *predicate { - ty::Predicate::Trait(..) => { + ty::Predicate::Trait(..) | + ty::Predicate::Projection(..) => { result.predicates.push(space, predicate.clone()) } ty::Predicate::Equate(..) | diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index 30039f2ecc1..79e1efa618f 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -27,6 +27,7 @@ use middle::ty::{ty_param, TypeScheme, ty_ptr}; use middle::ty::{ty_rptr, ty_struct, ty_trait, ty_tup}; use middle::ty::{ty_str, ty_vec, ty_float, ty_infer, ty_int, ty_open}; use middle::ty::{ty_uint, ty_unboxed_closure, ty_uniq, ty_bare_fn}; +use middle::ty::{ty_projection}; use middle::ty; use CrateCtxt; use middle::infer::combine::Combine; @@ -64,13 +65,13 @@ fn get_base_type_def_id<'a, 'tcx>(inference_context: &InferCtxt<'a, 'tcx>, } ty_trait(ref t) => { - Some(t.principal.def_id()) + Some(t.principal_def_id()) } ty_bool | ty_char | ty_int(..) | ty_uint(..) | ty_float(..) | ty_str(..) | ty_vec(..) | ty_bare_fn(..) | ty_closure(..) | ty_tup(..) | ty_param(..) | ty_err | ty_open(..) | ty_uniq(_) | - ty_ptr(_) | ty_rptr(_, _) => { + ty_ptr(_) | ty_rptr(_, _) | ty_projection(..) => { None } diff --git a/src/librustc_typeck/coherence/orphan.rs b/src/librustc_typeck/coherence/orphan.rs index bb8efd29910..79443200ddf 100644 --- a/src/librustc_typeck/coherence/orphan.rs +++ b/src/librustc_typeck/coherence/orphan.rs @@ -54,8 +54,8 @@ impl<'cx, 'tcx,'v> visit::Visitor<'v> for OrphanChecker<'cx, 'tcx> { ty::ty_struct(def_id, _) => { self.check_def_id(item.span, def_id); } - ty::ty_trait(box ty::TyTrait{ ref principal, ..}) => { - self.check_def_id(item.span, principal.def_id()); + ty::ty_trait(ref data) => { + self.check_def_id(item.span, data.principal_def_id()); } _ => { span_err!(self.tcx.sess, item.span, E0118, diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 6bbf4644414..35599a989c1 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -29,14 +29,8 @@ bounds for each parameter. Type parameters themselves are represented as `ty_param()` instances. */ -use self::ConvertMethodContext::*; -use self::CreateTypeParametersForAssociatedTypesFlag::*; - -use astconv::{AstConv, ty_of_arg, AllowEqConstraints}; -use astconv::{ast_ty_to_ty, ast_region_to_region}; -use astconv; +use astconv::{mod, AstConv, ty_of_arg, ast_ty_to_ty, ast_region_to_region}; use metadata::csearch; -use middle::def; use middle::lang_items::SizedTraitLangItem; use middle::region; use middle::resolve_lifetime; @@ -47,7 +41,7 @@ use middle::ty::{mod, RegionEscape, Ty, TypeScheme}; use middle::ty_fold::{mod, TypeFolder, TypeFoldable}; use middle::infer; use rscope::*; -use {CrateCtxt, lookup_def_tcx, no_params, write_ty_to_tcx}; +use {CrateCtxt, no_params, write_ty_to_tcx}; use util::nodemap::{FnvHashMap, FnvHashSet}; use util::ppaux; use util::ppaux::{Repr,UserString}; @@ -139,12 +133,6 @@ pub trait ToTy<'tcx> { fn to_ty(&self, rs: &RS, ast_ty: &ast::Ty) -> Ty<'tcx>; } -impl<'a,'tcx> ToTy<'tcx> for ImplCtxt<'a,'tcx> { - fn to_ty(&self, rs: &RS, ast_ty: &ast::Ty) -> Ty<'tcx> { - ast_ty_to_ty(self, rs, ast_ty) - } -} - impl<'a,'tcx> ToTy<'tcx> for CrateCtxt<'a,'tcx> { fn to_ty(&self, rs: &RS, ast_ty: &ast::Ty) -> Ty<'tcx> { ast_ty_to_ty(self, rs, ast_ty) @@ -165,9 +153,6 @@ impl<'a, 'tcx> AstConv<'tcx> for CrateCtxt<'a, 'tcx> { let abi = self.tcx.map.get_foreign_abi(id.node); ty_of_foreign_item(self, &*foreign_item, abi) } - Some(ast_map::NodeTraitItem(trait_item)) => { - ty_of_trait_item(self, &*trait_item) - } x => { self.tcx.sess.bug(format!("unexpected sort of node \ in get_item_type_scheme(): {}", @@ -186,20 +171,13 @@ impl<'a, 'tcx> AstConv<'tcx> for CrateCtxt<'a, 'tcx> { self.tcx().types.err } - fn associated_types_of_trait_are_valid(&self, _: Ty<'tcx>, _: ast::DefId) - -> bool { - false - } - - fn associated_type_binding(&self, - span: Span, - _: Option>, - _: ast::DefId, - _: ast::DefId) - -> Option> { - self.tcx().sess.span_err(span, "associated types may not be \ - referenced here"); - Some(ty::mk_err()) + fn projected_ty(&self, + _span: Span, + trait_ref: Rc>, + item_name: ast::Name) + -> Ty<'tcx> + { + ty::mk_projection(self.tcx, (*trait_ref).clone(), item_name) } } @@ -228,10 +206,7 @@ pub fn get_enum_variant_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, ast::StructVariantKind(ref struct_def) => { let scheme = TypeScheme { - generics: ty_generics_for_type_or_impl( - ccx, - generics, - DontCreateTypeParametersForAssociatedTypes), + generics: ty_generics_for_type_or_impl(ccx, generics), ty: enum_ty }; @@ -241,10 +216,7 @@ pub fn get_enum_variant_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, }; let scheme = TypeScheme { - generics: ty_generics_for_type_or_impl( - ccx, - generics, - DontCreateTypeParametersForAssociatedTypes), + generics: ty_generics_for_type_or_impl(ccx, generics), ty: result_ty }; @@ -361,7 +333,7 @@ fn collect_trait_methods<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, fn ty_method_of_trait_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, trait_id: ast::NodeId, trait_generics: &ty::Generics<'tcx>, - trait_items: &[ast::TraitItem], + _trait_items: &[ast::TraitItem], m_id: &ast::NodeId, m_name: &ast::Name, m_explicit_self: &ast::ExplicitSelf, @@ -374,19 +346,11 @@ fn collect_trait_methods<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, ty_generics_for_fn_or_method( ccx, m_generics, - (*trait_generics).clone(), - DontCreateTypeParametersForAssociatedTypes); + (*trait_generics).clone()); let (fty, explicit_self_category) = { - let tmcx = TraitMethodCtxt { - ccx: ccx, - trait_id: local_def(trait_id), - trait_items: trait_items[], - method_generics: &ty_generics, - }; - let trait_self_ty = ty::mk_self_type(tmcx.tcx(), - local_def(trait_id)); - astconv::ty_of_method(&tmcx, + let trait_self_ty = ty::mk_self_type(ccx.tcx, local_def(trait_id)); + astconv::ty_of_method(ccx, *m_unsafety, trait_self_ty, m_explicit_self, @@ -444,36 +408,7 @@ pub fn convert_field<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, fn convert_associated_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, trait_def: &ty::TraitDef<'tcx>, associated_type: &ast::AssociatedType) - -> ty::Polytype<'tcx> { - // Find the type parameter ID corresponding to this - // associated type. - let type_parameter_def = trait_def.generics - .types - .get_slice(subst::AssocSpace) - .iter() - .find(|def| { - def.def_id == local_def(associated_type.ty_param.id) - }); - let type_parameter_def = match type_parameter_def { - Some(type_parameter_def) => type_parameter_def, - None => { - ccx.tcx().sess.span_bug(associated_type.ty_param.span, - "`convert_associated_type()` didn't find \ - a type parameter ID corresponding to \ - this type") - } - }; - let param_type = ty::mk_param(ccx.tcx, - type_parameter_def.space, - type_parameter_def.index, - local_def(associated_type.ty_param.id)); - ccx.tcx.tcache.borrow_mut().insert(local_def(associated_type.ty_param.id), - Polytype { - generics: ty::Generics::empty(), - ty: param_type, - }); - write_ty_to_tcx(ccx.tcx, associated_type.ty_param.id, param_type); - +{ let associated_type = Rc::new(ty::AssociatedType { name: associated_type.ty_param.ident.name, vis: ast::Public, @@ -485,32 +420,16 @@ fn convert_associated_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, .borrow_mut() .insert(associated_type.def_id, ty::TypeTraitItem(associated_type)); - - Polytype { - generics: ty::Generics::empty(), - ty: param_type, - } -} - -#[deriving(Copy)] -enum ConvertMethodContext<'a> { - /// Used when converting implementation methods. - ImplConvertMethodContext, - /// Used when converting method signatures. The def ID is the def ID of - /// the trait we're translating. - TraitConvertMethodContext(ast::DefId, &'a [ast::TraitItem]), } fn convert_methods<'a,'tcx,'i,I>(ccx: &CrateCtxt<'a, 'tcx>, - convert_method_context: ConvertMethodContext, container: ImplOrTraitItemContainer, mut ms: I, untransformed_rcvr_ty: Ty<'tcx>, rcvr_ty_generics: &ty::Generics<'tcx>, rcvr_visibility: ast::Visibility) where I: Iterator<&'i ast::Method> { - debug!("convert_methods(untransformed_rcvr_ty={}, \ - rcvr_ty_generics={})", + debug!("convert_methods(untransformed_rcvr_ty={}, rcvr_ty_generics={})", untransformed_rcvr_ty.repr(ccx.tcx), rcvr_ty_generics.repr(ccx.tcx)); @@ -523,7 +442,6 @@ fn convert_methods<'a,'tcx,'i,I>(ccx: &CrateCtxt<'a, 'tcx>, let m_def_id = local_def(m.id); let mty = Rc::new(ty_of_method(ccx, - convert_method_context, container, m, untransformed_rcvr_ty, @@ -552,7 +470,6 @@ fn convert_methods<'a,'tcx,'i,I>(ccx: &CrateCtxt<'a, 'tcx>, } fn ty_of_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, - convert_method_context: ConvertMethodContext, container: ImplOrTraitItemContainer, m: &ast::Method, untransformed_rcvr_ty: Ty<'tcx>, @@ -563,37 +480,14 @@ fn convert_methods<'a,'tcx,'i,I>(ccx: &CrateCtxt<'a, 'tcx>, ty_generics_for_fn_or_method( ccx, m.pe_generics(), - (*rcvr_ty_generics).clone(), - CreateTypeParametersForAssociatedTypes); + (*rcvr_ty_generics).clone()); - let (fty, explicit_self_category) = match convert_method_context { - ImplConvertMethodContext => { - let imcx = ImplMethodCtxt { - ccx: ccx, - method_generics: &m_ty_generics, - }; - astconv::ty_of_method(&imcx, - m.pe_unsafety(), - untransformed_rcvr_ty, - m.pe_explicit_self(), - &*m.pe_fn_decl(), - m.pe_abi()) - } - TraitConvertMethodContext(trait_id, trait_items) => { - let tmcx = TraitMethodCtxt { - ccx: ccx, - trait_id: trait_id, - trait_items: trait_items, - method_generics: &m_ty_generics, - }; - astconv::ty_of_method(&tmcx, - m.pe_unsafety(), - untransformed_rcvr_ty, - m.pe_explicit_self(), - &*m.pe_fn_decl(), - m.pe_abi()) - } - }; + let (fty, explicit_self_category) = astconv::ty_of_method(ccx, + m.pe_unsafety(), + untransformed_rcvr_ty, + m.pe_explicit_self(), + &*m.pe_fn_decl(), + m.pe_abi()); // if the method specifies a visibility, use that, otherwise // inherit the visibility from the impl (so `foo` in `pub impl @@ -641,392 +535,6 @@ pub fn ensure_no_ty_param_bounds(ccx: &CrateCtxt, } } -fn is_associated_type_valid_for_param(ty: Ty, - trait_id: ast::DefId, - generics: &ty::Generics) - -> bool { - if let ty::ty_param(param_ty) = ty.sty { - let type_parameter = generics.types.get(param_ty.space, param_ty.idx as uint); - for trait_bound in type_parameter.bounds.trait_bounds.iter() { - if trait_bound.def_id() == trait_id { - return true - } - } - } - - false -} - -fn find_associated_type_in_generics<'tcx>(tcx: &ty::ctxt<'tcx>, - span: Span, - self_ty: Option>, - associated_type_id: ast::DefId, - generics: &ty::Generics<'tcx>) - -> Option> -{ - debug!("find_associated_type_in_generics(ty={}, associated_type_id={}, generics={}", - self_ty.repr(tcx), associated_type_id.repr(tcx), generics.repr(tcx)); - - let self_ty = match self_ty { - None => { - return None; - } - Some(ty) => ty, - }; - - match self_ty.sty { - ty::ty_param(ref param_ty) => { - let param_id = param_ty.def_id; - for type_parameter in generics.types.iter() { - if type_parameter.def_id == associated_type_id - && type_parameter.associated_with == Some(param_id) { - return Some(ty::mk_param_from_def(tcx, type_parameter)); - } - } - - tcx.sess.span_err( - span, - format!("no suitable bound on `{}`", - self_ty.user_string(tcx))[]); - Some(ty::mk_err()) - } - _ => { - tcx.sess.span_err( - span, - "it is currently unsupported to access associated types except \ - through a type parameter; this restriction will be lifted in time"); - Some(ty::mk_err()) - } - } -} - -fn type_is_self(ty: Ty) -> bool { - match ty.sty { - ty::ty_param(ref param_ty) if param_ty.is_self() => true, - _ => false, - } -} - -struct ImplCtxt<'a,'tcx:'a> { - ccx: &'a CrateCtxt<'a,'tcx>, - opt_trait_ref_id: Option, - impl_items: &'a [ast::ImplItem], - impl_generics: &'a ty::Generics<'tcx>, -} - -impl<'a,'tcx> AstConv<'tcx> for ImplCtxt<'a,'tcx> { - fn tcx(&self) -> &ty::ctxt<'tcx> { - self.ccx.tcx - } - - fn get_item_ty(&self, id: ast::DefId) -> ty::Polytype<'tcx> { - self.ccx.get_item_ty(id) - } - - fn get_trait_def(&self, id: ast::DefId) -> Rc> { - self.ccx.get_trait_def(id) - } - - fn ty_infer(&self, span: Span) -> Ty<'tcx> { - self.ccx.ty_infer(span) - } - - fn associated_types_of_trait_are_valid(&self, - ty: Ty<'tcx>, - trait_id: ast::DefId) - -> bool { - // OK if the trait with the associated type is the trait we're - // implementing. - match self.opt_trait_ref_id { - Some(trait_ref_id) if trait_ref_id == trait_id => { - if type_is_self(ty) { - return true - } - } - Some(_) | None => {} - } - - // OK if the trait with the associated type is one of the traits in - // our bounds. - is_associated_type_valid_for_param(ty, trait_id, self.impl_generics) - } - - fn associated_type_binding(&self, - span: Span, - self_ty: Option>, - trait_id: ast::DefId, - associated_type_id: ast::DefId) - -> Option> - { - match self.opt_trait_ref_id { - // It's an associated type on the trait that we're - // implementing. - Some(trait_ref_id) if trait_ref_id == trait_id => { - let trait_def = ty::lookup_trait_def(self.tcx(), trait_id); - assert!(trait_def.generics.types - .get_slice(subst::AssocSpace) - .iter() - .any(|type_param_def| type_param_def.def_id == associated_type_id)); - let associated_type = ty::impl_or_trait_item(self.ccx.tcx, associated_type_id); - for impl_item in self.impl_items.iter() { - match *impl_item { - ast::MethodImplItem(_) => {} - ast::TypeImplItem(ref typedef) => { - if associated_type.name() == typedef.ident.name { - return Some(self.ccx.to_ty(&ExplicitRscope, &*typedef.typ)) - } - } - } - } - self.ccx - .tcx - .sess - .span_bug(span, - "ImplCtxt::associated_type_binding(): didn't \ - find associated type") - } - Some(_) | None => {} - } - - // OK then, it should be an associated type on one of the traits in - // our bounds. - find_associated_type_in_generics(self.ccx.tcx, - span, - self_ty, - associated_type_id, - self.impl_generics) - } -} - -struct FnCtxt<'a,'tcx:'a> { - ccx: &'a CrateCtxt<'a,'tcx>, - generics: &'a ty::Generics<'tcx>, -} - -impl<'a,'tcx> AstConv<'tcx> for FnCtxt<'a,'tcx> { - fn tcx(&self) -> &ty::ctxt<'tcx> { - self.ccx.tcx - } - - fn get_item_ty(&self, id: ast::DefId) -> ty::Polytype<'tcx> { - self.ccx.get_item_ty(id) - } - - fn get_trait_def(&self, id: ast::DefId) -> Rc> { - self.ccx.get_trait_def(id) - } - - fn ty_infer(&self, span: Span) -> Ty<'tcx> { - self.ccx.ty_infer(span) - } - - fn associated_types_of_trait_are_valid(&self, - ty: Ty<'tcx>, - trait_id: ast::DefId) - -> bool { - // OK if the trait with the associated type is one of the traits in - // our bounds. - is_associated_type_valid_for_param(ty, trait_id, self.generics) - } - - fn associated_type_binding(&self, - span: Span, - self_ty: Option>, - _: ast::DefId, - associated_type_id: ast::DefId) - -> Option> { - debug!("collect::FnCtxt::associated_type_binding()"); - - // The ID should map to an associated type on one of the traits in - // our bounds. - find_associated_type_in_generics(self.ccx.tcx, - span, - self_ty, - associated_type_id, - self.generics) - } -} - -struct ImplMethodCtxt<'a,'tcx:'a> { - ccx: &'a CrateCtxt<'a,'tcx>, - method_generics: &'a ty::Generics<'tcx>, -} - -impl<'a,'tcx> AstConv<'tcx> for ImplMethodCtxt<'a,'tcx> { - fn tcx(&self) -> &ty::ctxt<'tcx> { - self.ccx.tcx - } - - fn get_item_ty(&self, id: ast::DefId) -> ty::Polytype<'tcx> { - self.ccx.get_item_ty(id) - } - - fn get_trait_def(&self, id: ast::DefId) -> Rc> { - self.ccx.get_trait_def(id) - } - - fn ty_infer(&self, span: Span) -> Ty<'tcx> { - self.ccx.ty_infer(span) - } - - fn associated_types_of_trait_are_valid(&self, - ty: Ty<'tcx>, - trait_id: ast::DefId) - -> bool { - is_associated_type_valid_for_param(ty, trait_id, self.method_generics) - } - - fn associated_type_binding(&self, - span: Span, - self_ty: Option>, - _: ast::DefId, - associated_type_id: ast::DefId) - -> Option> { - debug!("collect::ImplMethodCtxt::associated_type_binding()"); - - // The ID should map to an associated type on one of the traits in - // our bounds. - find_associated_type_in_generics(self.ccx.tcx, - span, - self_ty, - associated_type_id, - self.method_generics) - } -} - -struct TraitMethodCtxt<'a,'tcx:'a> { - ccx: &'a CrateCtxt<'a,'tcx>, - trait_id: ast::DefId, - trait_items: &'a [ast::TraitItem], - method_generics: &'a ty::Generics<'tcx>, -} - -impl<'a,'tcx> AstConv<'tcx> for TraitMethodCtxt<'a,'tcx> { - fn tcx(&self) -> &ty::ctxt<'tcx> { - self.ccx.tcx - } - - fn get_item_ty(&self, id: ast::DefId) -> ty::Polytype<'tcx> { - self.ccx.get_item_ty(id) - } - - fn get_trait_def(&self, id: ast::DefId) -> Rc> { - self.ccx.get_trait_def(id) - } - - fn ty_infer(&self, span: Span) -> Ty<'tcx> { - self.ccx.ty_infer(span) - } - - fn associated_types_of_trait_are_valid(&self, - ty: Ty<'tcx>, - trait_id: ast::DefId) - -> bool { - // OK if the trait with the associated type is this trait. - if self.trait_id == trait_id && type_is_self(ty) { - return true - } - - // OK if the trait with the associated type is one of the traits in - // our bounds. - is_associated_type_valid_for_param(ty, trait_id, self.method_generics) - } - - fn associated_type_binding(&self, - span: Span, - self_ty: Option>, - trait_id: ast::DefId, - associated_type_id: ast::DefId) - -> Option> { - debug!("collect::TraitMethodCtxt::associated_type_binding()"); - - // If this is one of our own associated types, return it. - if trait_id == self.trait_id { - let mut index = 0; - for item in self.trait_items.iter() { - match *item { - ast::RequiredMethod(_) | ast::ProvidedMethod(_) => {} - ast::TypeTraitItem(ref item) => { - if local_def(item.ty_param.id) == associated_type_id { - return Some(ty::mk_param(self.tcx(), - subst::AssocSpace, - index, - associated_type_id)) - } - index += 1; - } - } - } - self.ccx - .tcx - .sess - .span_bug(span, - "TraitMethodCtxt::associated_type_binding(): \ - didn't find associated type anywhere in the item \ - list") - } - - // The ID should map to an associated type on one of the traits in - // our bounds. - find_associated_type_in_generics(self.ccx.tcx, - span, - self_ty, - associated_type_id, - self.method_generics) - } -} - -struct GenericsCtxt<'a,'tcx:'a,AC:'a> { - chain: &'a AC, - associated_types_generics: &'a ty::Generics<'tcx>, -} - -impl<'a,'tcx,AC:AstConv<'tcx>> AstConv<'tcx> for GenericsCtxt<'a,'tcx,AC> { - fn tcx(&self) -> &ty::ctxt<'tcx> { - self.chain.tcx() - } - - fn get_item_ty(&self, id: ast::DefId) -> ty::Polytype<'tcx> { - self.chain.get_item_ty(id) - } - - fn get_trait_def(&self, id: ast::DefId) -> Rc> { - self.chain.get_trait_def(id) - } - - fn ty_infer(&self, span: Span) -> Ty<'tcx> { - self.chain.ty_infer(span) - } - - fn associated_types_of_trait_are_valid(&self, - ty: Ty<'tcx>, - trait_id: ast::DefId) - -> bool { - // OK if the trait with the associated type is one of the traits in - // our bounds. - is_associated_type_valid_for_param(ty, - trait_id, - self.associated_types_generics) - } - - fn associated_type_binding(&self, - span: Span, - self_ty: Option>, - _: ast::DefId, - associated_type_id: ast::DefId) - -> Option> { - debug!("collect::GenericsCtxt::associated_type_binding()"); - - // The ID should map to an associated type on one of the traits in - // our bounds. - find_associated_type_in_generics(self.chain.tcx(), - span, - self_ty, - associated_type_id, - self.associated_types_generics) - } -} - pub fn convert(ccx: &CrateCtxt, it: &ast::Item) { let tcx = ccx.tcx; debug!("convert: item {} with id {}", token::get_ident(it.ident), it.id); @@ -1047,10 +555,7 @@ pub fn convert(ccx: &CrateCtxt, it: &ast::Item) { ref selfty, ref impl_items) => { // Create generics from the generics specified in the impl head. - let ty_generics = ty_generics_for_type_or_impl( - ccx, - generics, - CreateTypeParametersForAssociatedTypes); + let ty_generics = ty_generics_for_type_or_impl(ccx, generics); let selfty = ccx.to_ty(&ExplicitRscope, &**selfty); write_ty_to_tcx(tcx, it.id, selfty); @@ -1074,20 +579,6 @@ pub fn convert(ccx: &CrateCtxt, it: &ast::Item) { it.vis }; - let icx = ImplCtxt { - ccx: ccx, - opt_trait_ref_id: match *opt_trait_ref { - None => None, - Some(ref ast_trait_ref) => { - Some(lookup_def_tcx(tcx, - ast_trait_ref.path.span, - ast_trait_ref.ref_id).def_id()) - } - }, - impl_items: impl_items[], - impl_generics: &ty_generics, - }; - let mut methods = Vec::new(); for impl_item in impl_items.iter() { match *impl_item { @@ -1101,7 +592,7 @@ pub fn convert(ccx: &CrateCtxt, it: &ast::Item) { methods.push(&**method); } ast::TypeImplItem(ref typedef) => { - let typ = icx.to_ty(&ExplicitRscope, &*typedef.typ); + let typ = ccx.to_ty(&ExplicitRscope, &*typedef.typ); tcx.tcache .borrow_mut() .insert(local_def(typedef.id), @@ -1126,7 +617,6 @@ pub fn convert(ccx: &CrateCtxt, it: &ast::Item) { } convert_methods(ccx, - ImplConvertMethodContext, ImplContainer(local_def(it.id)), methods.into_iter(), selfty, @@ -1134,11 +624,11 @@ pub fn convert(ccx: &CrateCtxt, it: &ast::Item) { parent_visibility); for trait_ref in opt_trait_ref.iter() { - astconv::instantiate_trait_ref(&icx, + astconv::instantiate_trait_ref(ccx, &ExplicitRscope, trait_ref, Some(selfty), - AllowEqConstraints::DontAllow); + None); } }, ast::ItemTrait(_, _, _, ref trait_methods) => { @@ -1180,11 +670,7 @@ pub fn convert(ccx: &CrateCtxt, it: &ast::Item) { // Run convert_methods on the provided methods. let untransformed_rcvr_ty = ty::mk_self_type(tcx, local_def(it.id)); - let convert_method_context = - TraitConvertMethodContext(local_def(it.id), - trait_methods[]); convert_methods(ccx, - convert_method_context, TraitContainer(local_def(it.id)), trait_methods.iter().filter_map(|m| match *m { ast::RequiredMethod(_) => None, @@ -1326,7 +812,8 @@ fn get_trait_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, pub fn trait_def_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, it: &ast::Item) - -> Rc> { + -> Rc> +{ let def_id = local_def(it.id); let tcx = ccx.tcx; if let Some(def) = tcx.trait_defs.borrow().get(&def_id) { @@ -1347,7 +834,7 @@ pub fn trait_def_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, } }; - let substs = ccx.tcx.mk_substs(mk_trait_substs(ccx, it.id, generics, items)); + let substs = ccx.tcx.mk_substs(mk_trait_substs(ccx, it.id, generics)); let ty_generics = ty_generics_for_trait(ccx, it.id, @@ -1363,15 +850,27 @@ pub fn trait_def_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, bounds.as_slice(), it.span); - let substs = mk_item_substs(ccx, &ty_generics); + let substs = ccx.tcx.mk_substs(mk_item_substs(ccx, &ty_generics)); + + let associated_type_names: Vec<_> = + items.iter() + .filter_map(|item| { + match *item { + ast::RequiredMethod(_) | ast::ProvidedMethod(_) => None, + ast::TypeTraitItem(ref data) => Some(data.ty_param.ident.name), + } + }) + .collect(); + let trait_def = Rc::new(ty::TraitDef { unsafety: unsafety, generics: ty_generics, bounds: bounds, trait_ref: Rc::new(ty::TraitRef { def_id: def_id, - substs: ccx.tcx.mk_substs(substs) - }) + substs: substs + }), + associated_type_names: associated_type_names, }); tcx.trait_defs.borrow_mut().insert(def_id, trait_def.clone()); @@ -1379,8 +878,7 @@ pub fn trait_def_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, fn mk_trait_substs<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, trait_id: ast::NodeId, - generics: &ast::Generics, - items: &[ast::TraitItem]) + generics: &ast::Generics) -> subst::Substs<'tcx> { // Creates a no-op substitution for the trait's type parameters. @@ -1403,28 +901,11 @@ pub fn trait_def_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, i as u32, local_def(def.id))) .collect(); - // ...and also create generics synthesized from the associated types. - let mut index = 0; - let assoc_types: Vec<_> = - items.iter() - .flat_map(|item| match *item { - ast::TypeTraitItem(ref trait_item) => { - index += 1; - Some(ty::mk_param(ccx.tcx, - subst::AssocSpace, - index - 1, - local_def(trait_item.ty_param.id))).into_iter() - } - ast::RequiredMethod(_) | ast::ProvidedMethod(_) => { - None.into_iter() - } - }) - .collect(); - + // ...and also create the `Self` parameter. let self_ty = ty::mk_param(ccx.tcx, subst::SelfSpace, 0, local_def(trait_id)); - subst::Substs::new_trait(types, regions, assoc_types, self_ty) + subst::Substs::new_trait(types, regions, Vec::new(), self_ty) } } @@ -1444,18 +925,10 @@ pub fn ty_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, it: &ast::Item) return scheme; } ast::ItemFn(ref decl, unsafety, abi, ref generics, _) => { - let ty_generics = ty_generics_for_fn_or_method( - ccx, - generics, - ty::Generics::empty(), - CreateTypeParametersForAssociatedTypes); - let tofd = { - let fcx = FnCtxt { - ccx: ccx, - generics: &ty_generics, - }; - astconv::ty_of_bare_fn(&fcx, unsafety, abi, &**decl) - }; + let ty_generics = ty_generics_for_fn_or_method(ccx, + generics, + ty::Generics::empty()); + let tofd = astconv::ty_of_bare_fn(ccx, unsafety, abi, &**decl); let scheme = TypeScheme { generics: ty_generics, ty: ty::mk_bare_fn(ccx.tcx, Some(local_def(it.id)), ccx.tcx.mk_bare_fn(tofd)) @@ -1477,10 +950,7 @@ pub fn ty_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, it: &ast::Item) let scheme = { let ty = ccx.to_ty(&ExplicitRscope, &**t); TypeScheme { - generics: ty_generics_for_type_or_impl( - ccx, - generics, - DontCreateTypeParametersForAssociatedTypes), + generics: ty_generics_for_type_or_impl(ccx, generics), ty: ty } }; @@ -1490,10 +960,7 @@ pub fn ty_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, it: &ast::Item) } ast::ItemEnum(_, ref generics) => { // Create a new generic polytype. - let ty_generics = ty_generics_for_type_or_impl( - ccx, - generics, - DontCreateTypeParametersForAssociatedTypes); + let ty_generics = ty_generics_for_type_or_impl(ccx, generics); let substs = mk_item_substs(ccx, &ty_generics); let t = ty::mk_enum(tcx, local_def(it.id), tcx.mk_substs(substs)); let scheme = TypeScheme { @@ -1508,10 +975,7 @@ pub fn ty_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, it: &ast::Item) tcx.sess.span_bug(it.span, "invoked ty_of_item on trait"); } ast::ItemStruct(_, ref generics) => { - let ty_generics = ty_generics_for_type_or_impl( - ccx, - generics, - DontCreateTypeParametersForAssociatedTypes); + let ty_generics = ty_generics_for_type_or_impl(ccx, generics); let substs = mk_item_substs(ccx, &ty_generics); let t = ty::mk_struct(tcx, local_def(it.id), tcx.mk_substs(substs)); let scheme = TypeScheme { @@ -1548,52 +1012,22 @@ pub fn ty_of_foreign_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, } } -fn ty_of_trait_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, - trait_item: &ast::TraitItem) - -> ty::Polytype<'tcx> { - match *trait_item { - ast::RequiredMethod(ref m) => { - ccx.tcx.sess.span_bug(m.span, - "ty_of_trait_item() on required method") - } - ast::ProvidedMethod(ref m) => { - ccx.tcx.sess.span_bug(m.span, - "ty_of_trait_item() on provided method") - } - ast::TypeTraitItem(ref associated_type) => { - let parent = ccx.tcx.map.get_parent(associated_type.ty_param.id); - let trait_def = match ccx.tcx.map.get(parent) { - ast_map::NodeItem(item) => trait_def_of_item(ccx, &*item), - _ => { - ccx.tcx.sess.span_bug(associated_type.ty_param.span, - "associated type's parent wasn't \ - an item?!") - } - }; - convert_associated_type(ccx, &*trait_def, &**associated_type) - } - } -} - fn ty_generics_for_type_or_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, - generics: &ast::Generics, - create_type_parameters_for_associated_types: - CreateTypeParametersForAssociatedTypesFlag) + generics: &ast::Generics) -> ty::Generics<'tcx> { ty_generics(ccx, subst::TypeSpace, generics.lifetimes[], generics.ty_params[], ty::Generics::empty(), - &generics.where_clause, - create_type_parameters_for_associated_types) + &generics.where_clause) } fn ty_generics_for_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, trait_id: ast::NodeId, substs: &'tcx subst::Substs<'tcx>, ast_generics: &ast::Generics, - items: &[ast::TraitItem]) + _items: &[ast::TraitItem]) -> ty::Generics<'tcx> { let mut generics = @@ -1602,27 +1036,7 @@ fn ty_generics_for_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, ast_generics.lifetimes[], ast_generics.ty_params[], ty::Generics::empty(), - &ast_generics.where_clause, - DontCreateTypeParametersForAssociatedTypes); - - // Add in type parameters for any associated types. - for item in items.iter() { - match *item { - ast::TypeTraitItem(ref associated_type) => { - let def = - get_or_create_type_parameter_def( - ccx, - subst::AssocSpace, - &associated_type.ty_param, - generics.types.len(subst::AssocSpace) as u32, - Some(local_def(trait_id))); - ccx.tcx.ty_param_defs.borrow_mut().insert(associated_type.ty_param.id, - def.clone()); - generics.types.push(subst::AssocSpace, def); - } - ast::ProvidedMethod(_) | ast::RequiredMethod(_) => {} - } - } + &ast_generics.where_clause); // Add in the self type parameter. // @@ -1631,7 +1045,7 @@ fn ty_generics_for_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let param_id = trait_id; let self_trait_ref = - Rc::new(ty::Binder(ty::TraitRef { def_id: local_def(trait_id), + ty::Binder(Rc::new(ty::TraitRef { def_id: local_def(trait_id), substs: substs })); let def = ty::TypeParameterDef { @@ -1643,8 +1057,8 @@ fn ty_generics_for_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, region_bounds: vec!(), builtin_bounds: ty::empty_builtin_bounds(), trait_bounds: vec!(self_trait_ref.clone()), + projection_bounds: vec!(), }, - associated_with: None, default: None }; @@ -1652,8 +1066,7 @@ fn ty_generics_for_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, generics.types.push(subst::SelfSpace, def); - generics.predicates.push(subst::SelfSpace, - ty::Predicate::Trait(self_trait_ref)); + generics.predicates.push(subst::SelfSpace, self_trait_ref.as_predicate()); generics } @@ -1661,9 +1074,7 @@ fn ty_generics_for_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, fn ty_generics_for_fn_or_method<'tcx,AC>( this: &AC, generics: &ast::Generics, - base_generics: ty::Generics<'tcx>, - create_type_parameters_for_associated_types: - CreateTypeParametersForAssociatedTypesFlag) + base_generics: ty::Generics<'tcx>) -> ty::Generics<'tcx> where AC: AstConv<'tcx> { let early_lifetimes = resolve_lifetime::early_bound_lifetimes(generics); @@ -1672,8 +1083,7 @@ fn ty_generics_for_fn_or_method<'tcx,AC>( early_lifetimes[], generics.ty_params[], base_generics, - &generics.where_clause, - create_type_parameters_for_associated_types) + &generics.where_clause) } // Add the Sized bound, unless the type parameter is marked as `?Sized`. @@ -1722,20 +1132,12 @@ fn add_unsized_bound<'tcx,AC>(this: &AC, } } -#[deriving(Clone, PartialEq, Eq)] -enum CreateTypeParametersForAssociatedTypesFlag { - DontCreateTypeParametersForAssociatedTypes, - CreateTypeParametersForAssociatedTypes, -} - fn ty_generics<'tcx,AC>(this: &AC, space: subst::ParamSpace, lifetime_defs: &[ast::LifetimeDef], types: &[ast::TyParam], base_generics: ty::Generics<'tcx>, - where_clause: &ast::WhereClause, - create_type_parameters_for_associated_types_flag: - CreateTypeParametersForAssociatedTypesFlag) + where_clause: &ast::WhereClause) -> ty::Generics<'tcx> where AC: AstConv<'tcx> { @@ -1756,46 +1158,18 @@ fn ty_generics<'tcx,AC>(this: &AC, assert!(result.types.is_empty_in(space)); - // First, create the virtual type parameters for associated types if - // necessary. - let mut associated_types_generics = ty::Generics::empty(); - match create_type_parameters_for_associated_types_flag { - DontCreateTypeParametersForAssociatedTypes => {} - CreateTypeParametersForAssociatedTypes => { - create_type_parameters_for_associated_types(this, space, types, - &mut associated_types_generics); - } - } - // Now create the real type parameters. - let gcx = GenericsCtxt { - chain: this, - associated_types_generics: &associated_types_generics, - }; for (i, param) in types.iter().enumerate() { - let def = get_or_create_type_parameter_def(&gcx, + let def = get_or_create_type_parameter_def(this, space, param, - i as u32, - None); + i as u32); debug!("ty_generics: def for type param: {}, {}", def.repr(this.tcx()), space); result.types.push(space, def); } - // Append the associated types to the result. - for associated_type_param in associated_types_generics.types - .get_slice(space) - .iter() { - assert!(result.types.get_slice(space).len() == - associated_type_param.index as uint); - debug!("ty_generics: def for associated type: {}, {}", - associated_type_param.repr(this.tcx()), - space); - result.types.push(space, (*associated_type_param).clone()); - } - // Just for fun, also push the bounds from the type parameters // into the predicates list. This is currently kind of non-DRY. create_predicates(this.tcx(), &mut result, space); @@ -1809,16 +1183,21 @@ fn ty_generics<'tcx,AC>(this: &AC, for bound in bound_pred.bounds.iter() { match bound { &ast::TyParamBound::TraitTyParamBound(ref poly_trait_ref, _) => { + let mut projections = Vec::new(); + let trait_ref = astconv::instantiate_poly_trait_ref( this, &ExplicitRscope, - //@jroesch: for now trait_ref, poly_trait_ref? poly_trait_ref, Some(ty), - AllowEqConstraints::Allow + &mut projections, ); - result.predicates.push(space, ty::Predicate::Trait(trait_ref)); + result.predicates.push(space, trait_ref.as_predicate()); + + for projection in projections.iter() { + result.predicates.push(space, projection.as_predicate()); + } } &ast::TyParamBound::RegionTyParamBound(ref lifetime) => { @@ -1850,91 +1229,6 @@ fn ty_generics<'tcx,AC>(this: &AC, return result; - fn create_type_parameters_for_associated_types<'tcx, AC>( - this: &AC, - space: subst::ParamSpace, - types: &[ast::TyParam], - associated_types_generics: &mut ty::Generics<'tcx>) - where AC: AstConv<'tcx> - { - // The idea here is roughly as follows. We start with - // an item that is paramerized by various type parameters - // with bounds: - // - // fn foo(t: T) { ... } - // - // The traits in those bounds declare associated types: - // - // trait Iterator { type Elem; ... } - // - // And we rewrite the original function so that every associated - // type is bound to some fresh type parameter: - // - // fn foo>(t: T) { ... } - - // Number of synthetic type parameters created thus far - let mut index = 0; - - // Iterate over the each type parameter `T` (from the example) - for param in types.iter() { - // Iterate over the bound `Iterator` - for bound in param.bounds.iter() { - // In the above example, `ast_trait_ref` is `Iterator`. - let ast_trait_ref = match *bound { - ast::TraitTyParamBound(ref r, _) => r, - ast::RegionTyParamBound(..) => { continue; } - }; - - let trait_def_id = - match lookup_def_tcx(this.tcx(), - ast_trait_ref.trait_ref.path.span, - ast_trait_ref.trait_ref.ref_id) { - def::DefTrait(trait_def_id) => trait_def_id, - _ => { - this.tcx().sess.span_bug(ast_trait_ref.trait_ref.path.span, - "not a trait?!") - } - }; - - // trait_def_id is def-id of `Iterator` - let trait_def = ty::lookup_trait_def(this.tcx(), trait_def_id); - let associated_type_defs = trait_def.generics.types.get_slice(subst::AssocSpace); - - // Find any associated type bindings in the bound. - let ref segments = ast_trait_ref.trait_ref.path.segments; - let bindings = segments[segments.len() -1].parameters.bindings(); - - // Iterate over each associated type `Elem` - for associated_type_def in associated_type_defs.iter() { - if bindings.iter().any(|b| associated_type_def.name.ident() == b.ident) { - // Don't add a variable for a bound associated type. - continue; - } - - // Create the fresh type parameter `A` - let def = ty::TypeParameterDef { - name: associated_type_def.name, - def_id: associated_type_def.def_id, - space: space, - index: types.len() as u32 + index, - bounds: ty::ParamBounds { - builtin_bounds: associated_type_def.bounds.builtin_bounds, - - // FIXME(#18178) -- we should add the other bounds, but - // that requires subst and more logic - trait_bounds: Vec::new(), - region_bounds: Vec::new(), - }, - associated_with: Some(local_def(param.id)), - default: None, - }; - associated_types_generics.types.push(space, def); - index += 1; - } - } - } - } - fn create_predicates<'tcx>( tcx: &ty::ctxt<'tcx>, result: &mut ty::Generics<'tcx>, @@ -1964,8 +1258,7 @@ fn ty_generics<'tcx,AC>(this: &AC, fn get_or_create_type_parameter_def<'tcx,AC>(this: &AC, space: subst::ParamSpace, param: &ast::TyParam, - index: u32, - associated_with: Option) + index: u32) -> ty::TypeParameterDef<'tcx> where AC: AstConv<'tcx> { @@ -2006,7 +1299,6 @@ fn get_or_create_type_parameter_def<'tcx,AC>(this: &AC, index: index, name: param.ident.name, def_id: local_def(param.id), - associated_with: associated_with, bounds: bounds, default: default }; @@ -2081,14 +1373,17 @@ fn conv_param_bounds<'tcx,AC>(this: &AC, trait_bounds, region_bounds } = astconv::partition_bounds(this.tcx(), span, ast_bounds.as_slice()); - let trait_bounds: Vec> = + + let mut projection_bounds = Vec::new(); + + let trait_bounds: Vec = trait_bounds.into_iter() .map(|bound| { astconv::instantiate_poly_trait_ref(this, &ExplicitRscope, bound, Some(param_ty.to_ty(this.tcx())), - AllowEqConstraints::Allow) + &mut projection_bounds) }) .collect(); let region_bounds: Vec = @@ -2099,6 +1394,7 @@ fn conv_param_bounds<'tcx,AC>(this: &AC, region_bounds: region_bounds, builtin_bounds: builtin_bounds, trait_bounds: trait_bounds, + projection_bounds: projection_bounds, } } @@ -2119,11 +1415,9 @@ pub fn ty_of_foreign_fn_decl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, } } - let ty_generics_for_fn_or_method = ty_generics_for_fn_or_method( - ccx, - ast_generics, - ty::Generics::empty(), - DontCreateTypeParametersForAssociatedTypes); + let ty_generics_for_fn_or_method = ty_generics_for_fn_or_method(ccx, + ast_generics, + ty::Generics::empty()); let rb = BindingRscope::new(); let input_tys = decl.inputs .iter() diff --git a/src/librustc_typeck/variance.rs b/src/librustc_typeck/variance.rs index 30869186ba5..c3a3993b66b 100644 --- a/src/librustc_typeck/variance.rs +++ b/src/librustc_typeck/variance.rs @@ -770,33 +770,38 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { variance); } - ty::ty_trait(box ty::TyTrait { ref principal, bounds }) => { - let trait_def = ty::lookup_trait_def(self.tcx(), principal.def_id()); + ty::ty_projection(ref data) => { + let trait_ref = &data.trait_ref; + let trait_def = ty::lookup_trait_def(self.tcx(), trait_ref.def_id); + let generics = &trait_def.generics; + self.add_constraints_from_substs( + trait_ref.def_id, + generics.types.as_slice(), + generics.regions.as_slice(), + &trait_ref.substs, + variance); + } + + ty::ty_trait(ref data) => { + let trait_ref = data.principal_trait_ref_with_self_ty(self.tcx().types.err); + let trait_def = ty::lookup_trait_def(self.tcx(), trait_ref.def_id()); let generics = &trait_def.generics; - // Traits DO have a Self type parameter, but it is - // erased from object types. - assert!(!generics.types.is_empty_in(subst::SelfSpace) && - principal.substs().types.is_empty_in(subst::SelfSpace)); - // Traits never declare region parameters in the self - // space. + // space nor anything in the fn space. assert!(generics.regions.is_empty_in(subst::SelfSpace)); - - // Traits never declare type/region parameters in the - // fn space. assert!(generics.types.is_empty_in(subst::FnSpace)); assert!(generics.regions.is_empty_in(subst::FnSpace)); // The type `Foo` is contravariant w/r/t `'a`: let contra = self.contravariant(variance); - self.add_constraints_from_region(bounds.region_bound, contra); + self.add_constraints_from_region(data.bounds.region_bound, contra); self.add_constraints_from_substs( - principal.def_id(), + trait_ref.def_id(), generics.types.get_slice(subst::TypeSpace), generics.regions.get_slice(subst::TypeSpace), - principal.substs(), + trait_ref.substs(), variance); } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index b7845f23be2..d5ffce8db78 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1466,6 +1466,18 @@ impl<'tcx> Clean for ty::Ty<'tcx> { } ty::ty_tup(ref t) => Tuple(t.clean(cx)), + ty::ty_projection(ref data) => { + let trait_ref = match data.trait_ref.clean(cx) { + TyParamBound::TraitBound(t) => t, + TyParamBound::RegionBound(_) => panic!("cleaning a trait got a region??"), + }; + Type::QPath { + name: data.item_name.clean(cx), + self_type: box data.trait_ref.self_ty().clean(cx), + trait_: box trait_ref, + } + } + ty::ty_param(ref p) => { if p.space == subst::SelfSpace { Self(p.def_id) diff --git a/src/test/compile-fail/assoc-eq-1.rs b/src/test/compile-fail/associated-types-eq-1.rs similarity index 100% rename from src/test/compile-fail/assoc-eq-1.rs rename to src/test/compile-fail/associated-types-eq-1.rs diff --git a/src/test/compile-fail/assoc-eq-2.rs b/src/test/compile-fail/associated-types-eq-2.rs similarity index 100% rename from src/test/compile-fail/assoc-eq-2.rs rename to src/test/compile-fail/associated-types-eq-2.rs diff --git a/src/test/compile-fail/assoc-eq-3.rs b/src/test/compile-fail/associated-types-eq-3.rs similarity index 100% rename from src/test/compile-fail/assoc-eq-3.rs rename to src/test/compile-fail/associated-types-eq-3.rs diff --git a/src/test/compile-fail/assoc-eq-expr-path.rs b/src/test/compile-fail/associated-types-eq-expr-path.rs similarity index 100% rename from src/test/compile-fail/assoc-eq-expr-path.rs rename to src/test/compile-fail/associated-types-eq-expr-path.rs diff --git a/src/test/compile-fail/associated-types-for-unimpl-trait.rs b/src/test/compile-fail/associated-types-for-unimpl-trait.rs new file mode 100644 index 00000000000..2c6ee502fca --- /dev/null +++ b/src/test/compile-fail/associated-types-for-unimpl-trait.rs @@ -0,0 +1,25 @@ +// 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. + +#![feature(associated_types)] + +trait Get { + type Value; + fn get(&self) -> ::Value; +} + +trait Other { + fn uhoh(&self, foo: U, bar: ::Value) {} + //~^ ERROR the trait `Get` is not implemented for the type `Self` +} + +fn main() { +} + diff --git a/src/test/compile-fail/associated-types-in-wrong-context.rs b/src/test/compile-fail/associated-types-in-wrong-context.rs index 8cab2759ad5..28a4ad01e23 100644 --- a/src/test/compile-fail/associated-types-in-wrong-context.rs +++ b/src/test/compile-fail/associated-types-in-wrong-context.rs @@ -15,9 +15,6 @@ trait Get { fn get(&self) -> ::Value; } -fn get(x: int) -> ::Value {} -//~^ ERROR unsupported - struct Struct { x: int, } diff --git a/src/test/compile-fail/assoc-path-1.rs b/src/test/compile-fail/associated-types-path-1.rs similarity index 100% rename from src/test/compile-fail/assoc-path-1.rs rename to src/test/compile-fail/associated-types-path-1.rs diff --git a/src/test/compile-fail/assoc-path-2.rs b/src/test/compile-fail/associated-types-path-2.rs similarity index 100% rename from src/test/compile-fail/assoc-path-2.rs rename to src/test/compile-fail/associated-types-path-2.rs diff --git a/src/test/run-pass/associated-types-basic.rs b/src/test/run-pass/associated-types-basic.rs new file mode 100644 index 00000000000..fcfcce3ff1b --- /dev/null +++ b/src/test/run-pass/associated-types-basic.rs @@ -0,0 +1,26 @@ +// 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. + +#![feature(associated_types)] + +trait Foo { + type T; +} + +impl Foo for i32 { + type T = int; +} + +fn main() { + let x: ::T = 22; + let y: int = 44; + assert_eq!(x * 2, y); +} + diff --git a/src/test/run-pass/associated-types-binding-in-where-clause.rs b/src/test/run-pass/associated-types-binding-in-where-clause.rs new file mode 100644 index 00000000000..c3300c52935 --- /dev/null +++ b/src/test/run-pass/associated-types-binding-in-where-clause.rs @@ -0,0 +1,47 @@ +// 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 equality constraints on associated types in a where clause. + +#![feature(associated_types)] + +pub trait Foo { + type A; + fn boo(&self) -> ::A; +} + +#[deriving(PartialEq)] +struct Bar; + +impl Foo for int { + type A = uint; + fn boo(&self) -> uint { 42 } +} + +impl Foo for char { + type A = Bar; + fn boo(&self) -> Bar { Bar } +} + +fn foo_bar>(x: I) -> Bar { + x.boo() +} + +fn foo_uint>(x: I) -> uint { + x.boo() +} + +pub fn main() { + let a = 42i; + foo_uint(a); + + let a = 'a'; + foo_bar(a); +} diff --git a/src/test/run-pass/associated-types-constant-type.rs b/src/test/run-pass/associated-types-constant-type.rs new file mode 100644 index 00000000000..ea2cf84b757 --- /dev/null +++ b/src/test/run-pass/associated-types-constant-type.rs @@ -0,0 +1,42 @@ +// 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. + +#![feature(associated_types)] + +trait SignedUnsigned { + type Opposite; + fn convert(self) -> Self::Opposite; +} + +impl SignedUnsigned for int { + type Opposite = uint; + + fn convert(self) -> uint { + self as uint + } +} + +impl SignedUnsigned for uint { + type Opposite = int; + + fn convert(self) -> int { + self as int + } +} + +fn get(x: int) -> ::Opposite { + x.convert() +} + +fn main() { + let x = get(22); + assert_eq!(22u, x); +} + diff --git a/src/test/run-pass/associated-types-eq-obj.rs b/src/test/run-pass/associated-types-eq-obj.rs new file mode 100644 index 00000000000..f0343a743cb --- /dev/null +++ b/src/test/run-pass/associated-types-eq-obj.rs @@ -0,0 +1,34 @@ +// 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 equality constraints on associated types inside of an object type + +#![feature(associated_types)] + +pub trait Foo { + type A; + fn boo(&self) -> ::A; +} + +struct Bar; + +impl Foo for char { + type A = Bar; + fn boo(&self) -> Bar { Bar } +} + +fn baz(x: &Foo) -> Bar { + x.boo() +} + +pub fn main() { + let a = 'a'; + baz(&a); +} diff --git a/src/test/run-pass/assoc-eq.rs b/src/test/run-pass/associated-types-return.rs similarity index 89% rename from src/test/run-pass/assoc-eq.rs rename to src/test/run-pass/associated-types-return.rs index f1ba382b42d..d8e277510ed 100644 --- a/src/test/run-pass/assoc-eq.rs +++ b/src/test/run-pass/associated-types-return.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// Test equality constraints on associated types. +// Test equality constraints on associated types in a where clause. #![feature(associated_types)] @@ -17,16 +17,19 @@ pub trait Foo { fn boo(&self) -> ::A; } +#[deriving(PartialEq)] struct Bar; impl Foo for int { type A = uint; fn boo(&self) -> uint { 42 } } + impl Foo for Bar { type A = int; fn boo(&self) -> int { 43 } } + impl Foo for char { type A = Bar; fn boo(&self) -> Bar { Bar } @@ -35,12 +38,10 @@ impl Foo for char { fn foo1>(x: I) -> Bar { x.boo() } + fn foo2(x: I) -> ::A { x.boo() } -fn baz(x: &Foo) -> Bar { - x.boo() -} pub fn main() { let a = 42i; @@ -51,5 +52,5 @@ pub fn main() { let a = 'a'; foo1(a); - baz(&a); + assert!(foo2(a) == Bar); } diff --git a/src/test/run-pass/assoc-sugar-path.rs b/src/test/run-pass/associated-types-sugar-path.rs similarity index 100% rename from src/test/run-pass/assoc-sugar-path.rs rename to src/test/run-pass/associated-types-sugar-path.rs