From e033a231abf1b8933a51e4c93dc8aeb39b30020d Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 16 Feb 2015 15:48:31 -0500 Subject: [PATCH 01/10] Change collect to implement `AstConv` on a `ItemCtxt` rather than a global context. Have this `ItemCtxt` carry a (currently unused) pointer to the in-scope generics. --- src/librustc_typeck/collect.rs | 305 +++++++++++++++++++-------------- 1 file changed, 180 insertions(+), 125 deletions(-) diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index bc0c61ad7ad52..3ca12959246d0 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -121,7 +121,7 @@ use syntax::visit; // Main entry point pub fn collect_item_types(tcx: &ty::ctxt) { - let ccx = &CollectCtxt { tcx: tcx }; + let ccx = &CrateCtxt { tcx: tcx }; match ccx.tcx.lang_items.ty_desc() { Some(id) => { collect_intrinsic_type(ccx, id); } @@ -141,17 +141,22 @@ pub fn collect_item_types(tcx: &ty::ctxt) { /////////////////////////////////////////////////////////////////////////// -struct CollectCtxt<'a,'tcx:'a> { +struct CrateCtxt<'a,'tcx:'a> { tcx: &'a ty::ctxt<'tcx>, } +#[allow(dead_code)] // just temporary, for generics +struct ItemCtxt<'a,'tcx:'a> { + ccx: &'a CrateCtxt<'a,'tcx>, + generics: &'a ty::Generics<'tcx>, +} + /////////////////////////////////////////////////////////////////////////// // Zeroth phase: collect types of intrinsics -fn collect_intrinsic_type(ccx: &CollectCtxt, +fn collect_intrinsic_type(ccx: &CrateCtxt, lang_item: ast::DefId) { - let ty::TypeScheme { ty, .. } = - ccx.get_item_type_scheme(lang_item); + let ty::TypeScheme { ty, .. } = type_scheme_of_def_id(ccx, lang_item); ccx.tcx.intrinsic_defs.borrow_mut().insert(lang_item, ty); } @@ -161,7 +166,7 @@ fn collect_intrinsic_type(ccx: &CollectCtxt, // know later when parsing field defs. struct CollectTraitDefVisitor<'a, 'tcx: 'a> { - ccx: &'a CollectCtxt<'a, 'tcx> + ccx: &'a CrateCtxt<'a, 'tcx> } impl<'a, 'tcx, 'v> visit::Visitor<'v> for CollectTraitDefVisitor<'a, 'tcx> { @@ -182,7 +187,7 @@ impl<'a, 'tcx, 'v> visit::Visitor<'v> for CollectTraitDefVisitor<'a, 'tcx> { // Second phase: collection proper. struct CollectItemTypesVisitor<'a, 'tcx: 'a> { - ccx: &'a CollectCtxt<'a, 'tcx> + ccx: &'a CrateCtxt<'a, 'tcx> } impl<'a, 'tcx, 'v> visit::Visitor<'v> for CollectItemTypesVisitor<'a, 'tcx> { @@ -199,42 +204,41 @@ impl<'a, 'tcx, 'v> visit::Visitor<'v> for CollectItemTypesVisitor<'a, 'tcx> { /////////////////////////////////////////////////////////////////////////// // Utility types and common code for the above passes. +impl<'a,'tcx> CrateCtxt<'a,'tcx> { + fn icx(&'a self, generics: &'a ty::Generics<'tcx>) -> ItemCtxt<'a,'tcx> { + ItemCtxt { ccx: self, generics: generics } + } + + fn method_ty(&self, method_id: ast::NodeId) -> Rc> { + let def_id = local_def(method_id); + match self.tcx.impl_or_trait_items.borrow()[def_id] { + ty::MethodTraitItem(ref mty) => mty.clone(), + ty::TypeTraitItem(..) => { + self.tcx.sess.bug(&format!("method with id {} has the wrong type", method_id)); + } + } + } +} + pub trait ToTy<'tcx> { fn to_ty(&self, rs: &RS, ast_ty: &ast::Ty) -> Ty<'tcx>; } -impl<'a,'tcx> ToTy<'tcx> for CollectCtxt<'a,'tcx> { +impl<'a,'tcx> ToTy<'tcx> for ItemCtxt<'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> AstConv<'tcx> for CollectCtxt<'a, 'tcx> { - fn tcx(&self) -> &ty::ctxt<'tcx> { self.tcx } +impl<'a, 'tcx> AstConv<'tcx> for ItemCtxt<'a, 'tcx> { + fn tcx(&self) -> &ty::ctxt<'tcx> { self.ccx.tcx } fn get_item_type_scheme(&self, id: ast::DefId) -> ty::TypeScheme<'tcx> { - if id.krate != ast::LOCAL_CRATE { - return ty::lookup_item_type(self.tcx, id); - } - - match self.tcx.map.find(id.node) { - Some(ast_map::NodeItem(item)) => { - type_scheme_of_item(self, &*item) - } - Some(ast_map::NodeForeignItem(foreign_item)) => { - let abi = self.tcx.map.get_foreign_abi(id.node); - type_scheme_of_foreign_item(self, &*foreign_item, abi) - } - x => { - self.tcx.sess.bug(&format!("unexpected sort of node \ - in get_item_type_scheme(): {:?}", - x)); - } - } + type_scheme_of_def_id(self.ccx, id) } fn get_trait_def(&self, id: ast::DefId) -> Rc> { - get_trait_def(self, id) + get_trait_def(self.ccx, id) } fn ty_infer(&self, span: Span) -> Ty<'tcx> { @@ -253,11 +257,12 @@ impl<'a, 'tcx> AstConv<'tcx> for CollectCtxt<'a, 'tcx> { } } -fn get_enum_variant_types<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, +fn get_enum_variant_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, enum_scheme: ty::TypeScheme<'tcx>, enum_predicates: ty::GenericPredicates<'tcx>, variants: &[P]) { let tcx = ccx.tcx; + let icx = ccx.icx(&enum_scheme.generics); // Create a set of parameter types shared among all the variants. for variant in variants { @@ -268,8 +273,8 @@ fn get_enum_variant_types<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, let result_ty = match variant.node.kind { ast::TupleVariantKind(ref args) if args.len() > 0 => { let rs = ExplicitRscope; - let input_tys: Vec<_> = args.iter().map(|va| ccx.to_ty(&rs, &*va.ty)).collect(); - ty::mk_ctor_fn(tcx, variant_def_id, &input_tys[..], enum_scheme.ty) + let input_tys: Vec<_> = args.iter().map(|va| icx.to_ty(&rs, &*va.ty)).collect(); + ty::mk_ctor_fn(tcx, variant_def_id, &input_tys, enum_scheme.ty) } ast::TupleVariantKind(_) => { @@ -294,7 +299,7 @@ fn get_enum_variant_types<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, } } -fn collect_trait_methods<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, +fn collect_trait_methods<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, trait_id: ast::NodeId, trait_def: &ty::TraitDef<'tcx>, trait_predicates: &ty::GenericPredicates<'tcx>) { @@ -393,7 +398,7 @@ fn collect_trait_methods<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, } } - fn make_method_ty<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, m: &ty::Method<'tcx>) { + fn make_method_ty<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, m: &ty::Method<'tcx>) { ccx.tcx.tcache.borrow_mut().insert( m.def_id, TypeScheme { @@ -405,7 +410,7 @@ fn collect_trait_methods<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, m.predicates.clone()); } - fn ty_method_of_trait_method<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, + fn ty_method_of_trait_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, trait_id: ast::NodeId, trait_generics: &ty::Generics<'tcx>, trait_bounds: &ty::GenericPredicates<'tcx>, @@ -417,7 +422,8 @@ fn collect_trait_methods<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, m_generics: &ast::Generics, m_unsafety: &ast::Unsafety, m_decl: &ast::FnDecl) - -> ty::Method<'tcx> { + -> ty::Method<'tcx> + { let ty_generics = ty_generics_for_fn_or_method(ccx, m_generics, @@ -431,7 +437,7 @@ fn collect_trait_methods<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, let (fty, explicit_self_category) = { let trait_self_ty = ty::mk_self_type(ccx.tcx); - astconv::ty_of_method(ccx, + astconv::ty_of_method(&ccx.icx(&ty_generics), *m_unsafety, trait_self_ty, m_explicit_self, @@ -454,12 +460,14 @@ fn collect_trait_methods<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, } } -fn convert_field<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, - struct_generics: &ty::Generics<'tcx>, - struct_predicates: &ty::GenericPredicates<'tcx>, - v: &ast::StructField, - origin: ast::DefId) -> ty::field_ty { - let tt = ccx.to_ty(&ExplicitRscope, &*v.node.ty); +fn convert_field<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, + struct_generics: &ty::Generics<'tcx>, + struct_predicates: &ty::GenericPredicates<'tcx>, + v: &ast::StructField, + origin: ast::DefId) + -> ty::field_ty +{ + let tt = ccx.icx(struct_generics).to_ty(&ExplicitRscope, &*v.node.ty); write_ty_to_tcx(ccx.tcx, v.node.id, tt); /* add the field to the tcache */ @@ -491,7 +499,7 @@ fn convert_field<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, } } -fn convert_associated_type<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, +fn convert_associated_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, trait_def: &ty::TraitDef<'tcx>, associated_type: &ast::AssociatedType) { @@ -504,11 +512,10 @@ fn convert_associated_type<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, ccx.tcx .impl_or_trait_items .borrow_mut() - .insert(associated_type.def_id, - ty::TypeTraitItem(associated_type)); + .insert(associated_type.def_id, ty::TypeTraitItem(associated_type)); } -fn convert_methods<'a,'tcx,'i,I>(ccx: &CollectCtxt<'a, 'tcx>, +fn convert_methods<'a,'tcx,'i,I>(ccx: &CrateCtxt<'a, 'tcx>, container: ImplOrTraitItemContainer, ms: I, untransformed_rcvr_ty: Ty<'tcx>, @@ -559,7 +566,7 @@ fn convert_methods<'a,'tcx,'i,I>(ccx: &CollectCtxt<'a, 'tcx>, .insert(mty.def_id, ty::MethodTraitItem(mty)); } - fn ty_of_method<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, + fn ty_of_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, container: ImplOrTraitItemContainer, m: &ast::Method, untransformed_rcvr_ty: Ty<'tcx>, @@ -578,7 +585,7 @@ fn convert_methods<'a,'tcx,'i,I>(ccx: &CollectCtxt<'a, 'tcx>, &m_ty_generics, rcvr_ty_predicates.clone()); - let (fty, explicit_self_category) = astconv::ty_of_method(ccx, + let (fty, explicit_self_category) = astconv::ty_of_method(&ccx.icx(&m_ty_generics), m.pe_unsafety(), untransformed_rcvr_ty, m.pe_explicit_self(), @@ -603,7 +610,7 @@ fn convert_methods<'a,'tcx,'i,I>(ccx: &CollectCtxt<'a, 'tcx>, } } -fn ensure_no_ty_param_bounds(ccx: &CollectCtxt, +fn ensure_no_ty_param_bounds(ccx: &CrateCtxt, span: Span, generics: &ast::Generics, thing: &'static str) { @@ -632,7 +639,7 @@ fn ensure_no_ty_param_bounds(ccx: &CollectCtxt, } } -fn convert_item(ccx: &CollectCtxt, it: &ast::Item) { +fn convert_item(ccx: &CrateCtxt, it: &ast::Item) { let tcx = ccx.tcx; debug!("convert: item {} with id {}", token::get_ident(it.ident), it.id); match it.node { @@ -671,7 +678,7 @@ fn convert_item(ccx: &CollectCtxt, it: &ast::Item) { debug!("convert: impl_bounds={:?}", ty_predicates); - let selfty = ccx.to_ty(&ExplicitRscope, &**selfty); + let selfty = ccx.icx(&ty_generics).to_ty(&ExplicitRscope, &**selfty); write_ty_to_tcx(tcx, it.id, selfty); tcx.tcache.borrow_mut().insert(local_def(it.id), @@ -695,12 +702,6 @@ fn convert_item(ccx: &CollectCtxt, it: &ast::Item) { for impl_item in impl_items { match *impl_item { ast::MethodImplItem(ref method) => { - let body_id = method.pe_body().id; - check_method_self_type(ccx, - &BindingRscope::new(), - selfty, - method.pe_explicit_self(), - body_id); methods.push(&**method); } ast::TypeImplItem(ref typedef) => { @@ -709,7 +710,7 @@ fn convert_item(ccx: &CollectCtxt, it: &ast::Item) { "associated items are not allowed in inherent impls"); } - let typ = ccx.to_ty(&ExplicitRscope, &*typedef.typ); + let typ = ccx.icx(&ty_generics).to_ty(&ExplicitRscope, &*typedef.typ); tcx.tcache.borrow_mut().insert(local_def(typedef.id), TypeScheme { generics: ty::Generics::empty(), @@ -741,8 +742,23 @@ fn convert_item(ccx: &CollectCtxt, it: &ast::Item) { &ty_predicates, parent_visibility); + for impl_item in impl_items { + match *impl_item { + ast::MethodImplItem(ref method) => { + let body_id = method.pe_body().id; + check_method_self_type(ccx, + &BindingRscope::new(), + ccx.method_ty(method.id), + selfty, + method.pe_explicit_self(), + body_id); + } + ast::TypeImplItem(..) => { } + } + } + if let Some(ref trait_ref) = *opt_trait_ref { - astconv::instantiate_trait_ref(ccx, + astconv::instantiate_trait_ref(&ccx.icx(&ty_generics), &ExplicitRscope, trait_ref, Some(it.id), @@ -754,20 +770,42 @@ fn convert_item(ccx: &CollectCtxt, it: &ast::Item) { generics, local_def(it.id)); }, - ast::ItemTrait(_, _, _, ref trait_methods) => { + ast::ItemTrait(_, _, _, ref trait_items) => { let trait_def = trait_def_of_item(ccx, it); convert_trait_predicates(ccx, it); let trait_predicates = ty::lookup_predicates(ccx.tcx, local_def(it.id)); debug!("convert: trait_bounds={:?}", trait_predicates); - for trait_method in trait_methods { + // Run convert_methods on the provided methods. + let untransformed_rcvr_ty = ty::mk_self_type(tcx); + convert_methods(ccx, + TraitContainer(local_def(it.id)), + trait_items.iter().filter_map(|m| match *m { + ast::RequiredMethod(_) => None, + ast::ProvidedMethod(ref m) => Some(&**m), + ast::TypeTraitItem(_) => None, + }), + untransformed_rcvr_ty, + &trait_def.generics, + &trait_predicates, + it.vis); + + // We need to do this *after* converting methods, since + // convert_methods produces a tcache entry that is wrong for + // static trait methods. This is somewhat unfortunate. + collect_trait_methods(ccx, it.id, &*trait_def, &trait_predicates); + + // This must be done after `collect_trait_methods` so that + // we have a method type stored for every method. + for trait_item in trait_items { let self_type = ty::mk_self_type(tcx); - match *trait_method { + match *trait_item { ast::RequiredMethod(ref type_method) => { let rscope = BindingRscope::new(); check_method_self_type(ccx, &rscope, + ccx.method_ty(type_method.id), self_type, &type_method.explicit_self, it.id) @@ -775,6 +813,7 @@ fn convert_item(ccx: &CollectCtxt, it: &ast::Item) { ast::ProvidedMethod(ref method) => { check_method_self_type(ccx, &BindingRscope::new(), + ccx.method_ty(method.id), self_type, method.pe_explicit_self(), it.id) @@ -786,25 +825,6 @@ fn convert_item(ccx: &CollectCtxt, it: &ast::Item) { } } } - - // Run convert_methods on the provided methods. - let untransformed_rcvr_ty = ty::mk_self_type(tcx); - convert_methods(ccx, - TraitContainer(local_def(it.id)), - trait_methods.iter().filter_map(|m| match *m { - ast::RequiredMethod(_) => None, - ast::ProvidedMethod(ref m) => Some(&**m), - ast::TypeTraitItem(_) => None, - }), - untransformed_rcvr_ty, - &trait_def.generics, - &trait_predicates, - it.vis); - - // We need to do this *after* converting methods, since - // convert_methods produces a tcache entry that is wrong for - // static trait methods. This is somewhat unfortunate. - collect_trait_methods(ccx, it.id, &*trait_def, &trait_predicates); }, ast::ItemStruct(ref struct_def, _) => { // Write the class type. @@ -827,7 +847,7 @@ fn convert_item(ccx: &CollectCtxt, it: &ast::Item) { } } -fn convert_struct<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, +fn convert_struct<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, struct_def: &ast::StructDef, scheme: ty::TypeScheme<'tcx>, predicates: ty::GenericPredicates<'tcx>, @@ -897,7 +917,7 @@ fn convert_struct<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, } } -fn get_trait_def<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, +fn get_trait_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, trait_id: ast::DefId) -> Rc> { let tcx = ccx.tcx; @@ -915,7 +935,7 @@ fn get_trait_def<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, } } -fn trait_def_of_item<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, +fn trait_def_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, it: &ast::Item) -> Rc> { @@ -959,6 +979,7 @@ fn trait_def_of_item<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, // supertraits: let bounds = compute_bounds(ccx, + &ty_generics, self_param_ty, bounds, SizedByDefault::No, @@ -992,7 +1013,7 @@ fn trait_def_of_item<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, return trait_def; - fn mk_trait_substs<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, + fn mk_trait_substs<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, generics: &ast::Generics) -> subst::Substs<'tcx> { @@ -1025,7 +1046,7 @@ fn trait_def_of_item<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, } } -fn convert_trait_predicates<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, it: &ast::Item) { +fn convert_trait_predicates<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, it: &ast::Item) { let tcx = ccx.tcx; let trait_def = trait_def_of_item(ccx, it); @@ -1044,7 +1065,8 @@ fn convert_trait_predicates<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, it: &ast::Ite let super_predicates = ty::predicates(ccx.tcx, self_param_ty, &trait_def.bounds); - let assoc_predicates = predicates_for_associated_types(ccx, &trait_def.trait_ref, items); + let assoc_predicates = predicates_for_associated_types(ccx, &trait_def.generics, + &trait_def.trait_ref, items); // `ty_generic_bounds` below will consider the bounds on the type // parameters (including `Self`) and the explicit where-clauses, @@ -1075,7 +1097,8 @@ fn convert_trait_predicates<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, it: &ast::Ite return; - fn predicates_for_associated_types<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, + fn predicates_for_associated_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, + generics: &ty::Generics<'tcx>, self_trait_ref: &Rc>, trait_items: &[ast::TraitItem]) -> Vec> @@ -1095,6 +1118,7 @@ fn convert_trait_predicates<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, it: &ast::Ite assoc_type_def.ident.name); let bounds = compute_bounds(ccx, + generics, assoc_ty, &*assoc_type_def.bounds, SizedByDefault::Yes, @@ -1106,7 +1130,31 @@ fn convert_trait_predicates<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, it: &ast::Ite } } -fn type_scheme_of_item<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>, +fn type_scheme_of_def_id<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, + def_id: ast::DefId) + -> ty::TypeScheme<'tcx> +{ + if def_id.krate != ast::LOCAL_CRATE { + return ty::lookup_item_type(ccx.tcx, def_id); + } + + match ccx.tcx.map.find(def_id.node) { + Some(ast_map::NodeItem(item)) => { + type_scheme_of_item(ccx, &*item) + } + Some(ast_map::NodeForeignItem(foreign_item)) => { + let abi = ccx.tcx.map.get_foreign_abi(def_id.node); + type_scheme_of_foreign_item(ccx, &*foreign_item, abi) + } + x => { + ccx.tcx.sess.bug(&format!("unexpected sort of node \ + in get_item_type_scheme(): {:?}", + x)); + } + } +} + +fn type_scheme_of_item<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &ast::Item) -> ty::TypeScheme<'tcx> { @@ -1116,27 +1164,27 @@ fn type_scheme_of_item<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>, } -fn compute_type_scheme_of_item<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>, - it: &ast::Item) - -> ty::TypeScheme<'tcx> +fn compute_type_scheme_of_item<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, + it: &ast::Item) + -> ty::TypeScheme<'tcx> { let tcx = ccx.tcx; match it.node { ast::ItemStatic(ref t, _, _) | ast::ItemConst(ref t, _) => { - let ty = ccx.to_ty(&ExplicitRscope, &**t); + let ty = ccx.icx(&ty::Generics::empty()).to_ty(&ExplicitRscope, &**t); ty::TypeScheme { ty: ty, generics: ty::Generics::empty() } } ast::ItemFn(ref decl, unsafety, abi, ref generics, _) => { 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 tofd = astconv::ty_of_bare_fn(&ccx.icx(&ty_generics), unsafety, abi, &**decl); let ty = ty::mk_bare_fn(tcx, Some(local_def(it.id)), tcx.mk_bare_fn(tofd)); ty::TypeScheme { ty: ty, generics: ty_generics } } ast::ItemTy(ref t, ref generics) => { - let ty = ccx.to_ty(&ExplicitRscope, &**t); let ty_generics = ty_generics_for_type_or_impl(ccx, generics); + let ty = ccx.icx(&ty_generics).to_ty(&ExplicitRscope, &**t); ty::TypeScheme { ty: ty, generics: ty_generics } } ast::ItemEnum(_, ref generics) => { @@ -1168,7 +1216,7 @@ fn compute_type_scheme_of_item<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>, } } -fn convert_typed_item<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, +fn convert_typed_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, it: &ast::Item) -> (ty::TypeScheme<'tcx>, ty::GenericPredicates<'tcx>) { @@ -1234,18 +1282,18 @@ fn convert_typed_item<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, } fn type_scheme_of_foreign_item<'a, 'tcx>( - ccx: &CollectCtxt<'a, 'tcx>, + ccx: &CrateCtxt<'a, 'tcx>, it: &ast::ForeignItem, abi: abi::Abi) -> ty::TypeScheme<'tcx> { - memoized(&ccx.tcx().tcache, + memoized(&ccx.tcx.tcache, local_def(it.id), |_| compute_type_scheme_of_foreign_item(ccx, it, abi)) } fn compute_type_scheme_of_foreign_item<'a, 'tcx>( - ccx: &CollectCtxt<'a, 'tcx>, + ccx: &CrateCtxt<'a, 'tcx>, it: &ast::ForeignItem, abi: abi::Abi) -> ty::TypeScheme<'tcx> @@ -1257,13 +1305,13 @@ fn compute_type_scheme_of_foreign_item<'a, 'tcx>( ast::ForeignItemStatic(ref t, _) => { ty::TypeScheme { generics: ty::Generics::empty(), - ty: ast_ty_to_ty(ccx, &ExplicitRscope, t) + ty: ast_ty_to_ty(&ccx.icx(&ty::Generics::empty()), &ExplicitRscope, t) } } } } -fn convert_foreign_item<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, +fn convert_foreign_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, it: &ast::ForeignItem) { // For reasons I cannot fully articulate, I do so hate the AST @@ -1292,7 +1340,7 @@ fn convert_foreign_item<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, assert!(prev_predicates.is_none()); } -fn ty_generics_for_type_or_impl<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, +fn ty_generics_for_type_or_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, generics: &ast::Generics) -> ty::Generics<'tcx> { ty_generics(ccx, @@ -1303,7 +1351,7 @@ fn ty_generics_for_type_or_impl<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, ty::Generics::empty()) } -fn ty_generic_bounds_for_type_or_impl<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>, +fn ty_generic_bounds_for_type_or_impl<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, ty_generics: &ty::Generics<'tcx>, generics: &ast::Generics) -> ty::GenericPredicates<'tcx> @@ -1315,7 +1363,7 @@ fn ty_generic_bounds_for_type_or_impl<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>, &generics.where_clause) } -fn ty_generics_for_trait<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, +fn ty_generics_for_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, trait_id: ast::NodeId, substs: &'tcx subst::Substs<'tcx>, ast_generics: &ast::Generics) @@ -1364,7 +1412,7 @@ fn ty_generics_for_trait<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, return generics; } -fn ty_generics_for_fn_or_method<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>, +fn ty_generics_for_fn_or_method<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, generics: &ast::Generics, base_generics: ty::Generics<'tcx>) -> ty::Generics<'tcx> @@ -1378,7 +1426,7 @@ fn ty_generics_for_fn_or_method<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>, base_generics) } -fn ty_generic_bounds_for_fn_or_method<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>, +fn ty_generic_bounds_for_fn_or_method<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, generics: &ast::Generics, ty_generics: &ty::Generics<'tcx>, base: ty::GenericPredicates<'tcx>) @@ -1392,7 +1440,7 @@ fn ty_generic_bounds_for_fn_or_method<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>, } // Add the Sized bound, unless the type parameter is marked as `?Sized`. -fn add_unsized_bound<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>, +fn add_unsized_bound<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, bounds: &mut ty::BuiltinBounds, ast_bounds: &[ast::TyParamBound], span: Span) @@ -1438,7 +1486,7 @@ fn add_unsized_bound<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>, } } -fn ty_generic_bounds<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>, +fn ty_generic_bounds<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, space: subst::ParamSpace, generics: &ty::Generics<'tcx>, base: ty::GenericPredicates<'tcx>, @@ -1465,7 +1513,9 @@ fn ty_generic_bounds<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>, for predicate in &where_clause.predicates { match predicate { &ast::WherePredicate::BoundPredicate(ref bound_pred) => { - let ty = ast_ty_to_ty(ccx, &ExplicitRscope, &*bound_pred.bounded_ty); + let ty = ast_ty_to_ty(&ccx.icx(generics), + &ExplicitRscope, + &*bound_pred.bounded_ty); for bound in &*bound_pred.bounds { match bound { @@ -1473,7 +1523,7 @@ fn ty_generic_bounds<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>, let mut projections = Vec::new(); let trait_ref = astconv::instantiate_poly_trait_ref( - ccx, + &ccx.icx(generics), &ExplicitRscope, poly_trait_ref, Some(ty), @@ -1517,7 +1567,7 @@ fn ty_generic_bounds<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>, return result; } -fn ty_generics<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>, +fn ty_generics<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, space: subst::ParamSpace, lifetime_defs: &[ast::LifetimeDef], types: &[ast::TyParam], @@ -1554,7 +1604,7 @@ fn ty_generics<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>, result } -fn get_or_create_type_parameter_def<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>, +fn get_or_create_type_parameter_def<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, space: subst::ParamSpace, param: &ast::TyParam, index: u32, @@ -1569,6 +1619,7 @@ fn get_or_create_type_parameter_def<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>, let param_ty = ty::ParamTy::new(space, index, param.ident.name); let bounds = compute_bounds(ccx, + &ty::Generics::empty(), param_ty.to_ty(ccx.tcx), ¶m.bounds, SizedByDefault::Yes, @@ -1576,7 +1627,7 @@ fn get_or_create_type_parameter_def<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>, let default = match param.default { None => None, Some(ref path) => { - let ty = ast_ty_to_ty(ccx, &ExplicitRscope, &**path); + let ty = ast_ty_to_ty(&ccx.icx(&ty::Generics::empty()), &ExplicitRscope, &**path); let cur_idx = index; ty::walk_ty(ty, |t| { @@ -1705,7 +1756,8 @@ enum SizedByDefault { Yes, No } /// Translate the AST's notion of ty param bounds (which are an enum consisting of a newtyped Ty or /// a region) to ty's notion of ty param bounds, which can either be user-defined traits, or the /// built-in trait (formerly known as kind): Send. -fn compute_bounds<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>, +fn compute_bounds<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, + generics: &ty::Generics<'tcx>, param_ty: ty::Ty<'tcx>, ast_bounds: &[ast::TyParamBound], sized_by_default: SizedByDefault, @@ -1713,6 +1765,7 @@ fn compute_bounds<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>, -> ty::ParamBounds<'tcx> { let mut param_bounds = conv_param_bounds(ccx, + generics, span, param_ty, ast_bounds); @@ -1734,7 +1787,7 @@ fn compute_bounds<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>, param_bounds } -fn check_bounds_compatible<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>, +fn check_bounds_compatible<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, param_ty: Ty<'tcx>, param_bounds: &ty::ParamBounds<'tcx>, span: Span) { @@ -1743,7 +1796,7 @@ fn check_bounds_compatible<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>, ccx.tcx, ¶m_bounds.trait_bounds, |trait_ref| { - let trait_def = ccx.get_trait_def(trait_ref.def_id()); + let trait_def = get_trait_def(ccx, trait_ref.def_id()); if trait_def.bounds.builtin_bounds.contains(&ty::BoundSized) { span_err!(ccx.tcx.sess, span, E0129, "incompatible bounds on `{}`, \ @@ -1756,7 +1809,8 @@ fn check_bounds_compatible<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>, } } -fn conv_param_bounds<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>, +fn conv_param_bounds<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, + generics: &ty::Generics<'tcx>, span: Span, param_ty: ty::Ty<'tcx>, ast_bounds: &[ast::TyParamBound]) @@ -1774,7 +1828,7 @@ fn conv_param_bounds<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>, let trait_bounds: Vec = trait_bounds.into_iter() .map(|bound| { - astconv::instantiate_poly_trait_ref(ccx, + astconv::instantiate_poly_trait_ref(&ccx.icx(generics), &ExplicitRscope, bound, Some(param_ty), @@ -1796,7 +1850,7 @@ fn conv_param_bounds<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>, } fn compute_type_scheme_of_foreign_fn_decl<'a, 'tcx>( - ccx: &CollectCtxt<'a, 'tcx>, + ccx: &CrateCtxt<'a, 'tcx>, decl: &ast::FnDecl, ast_generics: &ast::Generics, abi: abi::Abi) @@ -1818,12 +1872,12 @@ fn compute_type_scheme_of_foreign_fn_decl<'a, 'tcx>( let rb = BindingRscope::new(); let input_tys = decl.inputs .iter() - .map(|a| ty_of_arg(ccx, &rb, a, None)) + .map(|a| ty_of_arg(&ccx.icx(&ty_generics), &rb, a, None)) .collect(); let output = match decl.output { ast::Return(ref ty) => - ty::FnConverging(ast_ty_to_ty(ccx, &rb, &**ty)), + ty::FnConverging(ast_ty_to_ty(&ccx.icx(&ty_generics), &rb, &**ty)), ast::DefaultReturn(..) => ty::FnConverging(ty::mk_nil(ccx.tcx)), ast::NoReturn(..) => @@ -1847,7 +1901,7 @@ fn compute_type_scheme_of_foreign_fn_decl<'a, 'tcx>( } } -fn mk_item_substs<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, +fn mk_item_substs<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, ty_generics: &ty::Generics<'tcx>) -> subst::Substs<'tcx> { @@ -1869,15 +1923,16 @@ fn mk_item_substs<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, /// comes back to check after the fact that explicit type the user /// wrote actually matches what the pre-defined option said. fn check_method_self_type<'a, 'tcx, RS:RegionScope>( - ccx: &CollectCtxt<'a, 'tcx>, + ccx: &CrateCtxt<'a, 'tcx>, rs: &RS, + method_type: Rc>, required_type: Ty<'tcx>, explicit_self: &ast::ExplicitSelf, body_id: ast::NodeId) { let tcx = ccx.tcx; if let ast::SelfExplicit(ref ast_type, _) = explicit_self.node { - let typ = ccx.to_ty(rs, &**ast_type); + let typ = ccx.icx(&method_type.generics).to_ty(rs, &**ast_type); let base_type = match typ.sty { ty::ty_ptr(tm) | ty::ty_rptr(_, tm) => tm.ty, ty::ty_uniq(typ) => typ, From 15ef2c2e6b94e8430d718a13c9845e33989a50d6 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 17 Feb 2015 11:04:25 -0500 Subject: [PATCH 02/10] Convert `astconv` to request bounds through the `AstConv` interface rather than poking through the `TypeParameterDef` directly. --- src/librustc/middle/ty.rs | 9 ++++++++- src/librustc_typeck/astconv.rs | 8 ++++++-- src/librustc_typeck/check/mod.rs | 26 +++++++++++++++++++++++++- src/librustc_typeck/collect.rs | 19 ++++++++++++++++--- 4 files changed, 55 insertions(+), 7 deletions(-) diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 9131363339710..275007bf79740 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -55,7 +55,7 @@ use middle::region; use middle::resolve_lifetime; use middle::infer; use middle::stability; -use middle::subst::{self, Subst, Substs, VecPerParamSpace}; +use middle::subst::{self, ParamSpace, Subst, Substs, VecPerParamSpace}; use middle::traits; use middle::ty; use middle::ty_fold::{self, TypeFoldable, TypeFolder}; @@ -2996,6 +2996,13 @@ impl<'tcx> TyS<'tcx> { _ => None, } } + + pub fn is_param(&self, space: ParamSpace, index: u32) -> bool { + match self.sty { + ty::ty_param(ref data) => data.space == space && data.idx == index, + _ => false, + } + } } pub fn walk_ty<'tcx, F>(ty_root: Ty<'tcx>, mut f: F) diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 9e50fdb4c4815..d0e194e15d202 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -53,7 +53,7 @@ use middle::const_eval; use middle::def; use middle::resolve_lifetime as rl; use middle::privacy::{AllPublic, LastMod}; -use middle::subst::{FnSpace, TypeSpace, SelfSpace, Subst, Substs}; +use middle::subst::{FnSpace, ParamSpace, TypeSpace, SelfSpace, Subst, Substs}; use middle::traits; use middle::ty::{self, RegionEscape, ToPolyTraitRef, Ty}; use rscope::{self, UnelidableRscope, RegionScope, ElidableRscope, @@ -77,6 +77,8 @@ pub trait AstConv<'tcx> { fn get_trait_def(&self, id: ast::DefId) -> Rc>; + fn get_type_parameter_bounds(&self, space: ParamSpace, index: u32) -> Vec>; + /// Return an (optional) substitution to convert bound type parameters that /// are in scope into free ones. This function should only return Some /// within a fn body. @@ -1011,7 +1013,9 @@ fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>, // FIXME(#20300) -- search where clauses, not bounds suitable_bounds = - traits::transitive_bounds(tcx, &ty_param_def.bounds.trait_bounds) + traits::transitive_bounds(tcx, + &this.get_type_parameter_bounds(ty_param_def.space, + ty_param_def.index)) .filter(|b| trait_defines_associated_type_named(this, b.def_id(), assoc_name)) .collect(); } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index d7a11b8a5152f..968d67aca9dde 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -97,7 +97,7 @@ use middle::subst::{self, Subst, Substs, VecPerParamSpace, ParamSpace, TypeSpace use middle::traits; use middle::ty::{FnSig, GenericPredicates, VariantInfo, TypeScheme}; use middle::ty::{Disr, ParamTy, ParameterEnvironment}; -use middle::ty::{self, HasProjectionTypes, RegionEscape, Ty}; +use middle::ty::{self, HasProjectionTypes, RegionEscape, ToPolyTraitRef, Ty}; use middle::ty::liberate_late_bound_regions; use middle::ty::{MethodCall, MethodCallee, MethodMap, ObjectCastMap}; use middle::ty_fold::{TypeFolder, TypeFoldable}; @@ -1218,6 +1218,30 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> { Some(&self.inh.param_env.free_substs) } + fn get_type_parameter_bounds(&self, + space: ParamSpace, + index: u32) + -> Vec> + { + self.inh.param_env.caller_bounds + .iter() + .filter_map(|predicate| { + match *predicate { + ty::Predicate::Trait(ref data) => { + if data.0.self_ty().is_param(space, index) { + Some(data.to_poly_trait_ref()) + } else { + None + } + } + _ => { + None + } + } + }) + .collect() + } + fn ty_infer(&self, _span: Span) -> Ty<'tcx> { self.infcx().next_ty_var() } diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 3ca12959246d0..6d65d05bf6f3b 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -145,7 +145,6 @@ struct CrateCtxt<'a,'tcx:'a> { tcx: &'a ty::ctxt<'tcx>, } -#[allow(dead_code)] // just temporary, for generics struct ItemCtxt<'a,'tcx:'a> { ccx: &'a CrateCtxt<'a,'tcx>, generics: &'a ty::Generics<'tcx>, @@ -241,6 +240,19 @@ impl<'a, 'tcx> AstConv<'tcx> for ItemCtxt<'a, 'tcx> { get_trait_def(self.ccx, id) } + fn get_type_parameter_bounds(&self, + param: subst::ParamSpace, + index: u32) + -> Vec> + { + // TODO out of range indices can occur when you have something + // like fn foo() { } + match self.generics.types.opt_get(param, index as usize) { + Some(def) => def.bounds.trait_bounds.clone(), + None => Vec::new(), + } + } + fn ty_infer(&self, span: Span) -> Ty<'tcx> { span_err!(self.tcx().sess, span, E0121, "the type placeholder `_` is not allowed within types on item signatures"); @@ -1596,7 +1608,7 @@ fn ty_generics<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, // Now create the real type parameters. for (i, param) in types.iter().enumerate() { - let def = get_or_create_type_parameter_def(ccx, space, param, i as u32, where_clause); + let def = get_or_create_type_parameter_def(ccx, &result, space, param, i as u32); debug!("ty_generics: def for type param: {:?}, {:?}", def, space); result.types.push(space, def); } @@ -1605,6 +1617,7 @@ fn ty_generics<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, } fn get_or_create_type_parameter_def<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, + generics_so_far: &ty::Generics<'tcx>, space: subst::ParamSpace, param: &ast::TyParam, index: u32, @@ -1619,7 +1632,7 @@ fn get_or_create_type_parameter_def<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, let param_ty = ty::ParamTy::new(space, index, param.ident.name); let bounds = compute_bounds(ccx, - &ty::Generics::empty(), + generics_so_far, param_ty.to_ty(ccx.tcx), ¶m.bounds, SizedByDefault::Yes, From 0d9e473be9e07885d49a7e5699eebd53ccfcc2fb Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 17 Feb 2015 17:11:01 -0500 Subject: [PATCH 03/10] Comprehence cycle detection in `collect`. In some cases, the cycles we report are not *necessary* cycles, but we'll work on refactoring them over time. This overlaps with the cycle detection that astconv already does: I left that code in because it gives a more targeted error message, though perhaps less helpful in that it doesn't give the full details of the cycle. --- src/librustc/middle/ty.rs | 7 + src/librustc_typeck/astconv.rs | 66 ++++---- src/librustc_typeck/check/mod.rs | 54 ++++--- src/librustc_typeck/collect.rs | 142 ++++++++++++++++-- src/test/compile-fail/cycle-generic-bound.rs | 19 +++ .../cycle-trait-supertrait-direct.rs | 17 +++ .../cycle-trait-supertrait-indirect.rs | 22 +++ .../compile-fail/cycle-trait-type-trait.rs | 23 +++ 8 files changed, 282 insertions(+), 68 deletions(-) create mode 100644 src/test/compile-fail/cycle-generic-bound.rs create mode 100644 src/test/compile-fail/cycle-trait-supertrait-direct.rs create mode 100644 src/test/compile-fail/cycle-trait-supertrait-indirect.rs create mode 100644 src/test/compile-fail/cycle-trait-type-trait.rs diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 275007bf79740..20a0c35d8e021 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -2546,6 +2546,13 @@ impl<'tcx> ctxt<'tcx> { { self.closure_tys.borrow()[def_id].subst(self, substs) } + + pub fn type_parameter_def(&self, + node_id: ast::NodeId) + -> TypeParameterDef<'tcx> + { + self.ty_param_defs.borrow()[node_id].clone() + } } // Interns a type/name combination, stores the resulting box in cx.interner, diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index d0e194e15d202..48928516a6022 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -53,7 +53,7 @@ use middle::const_eval; use middle::def; use middle::resolve_lifetime as rl; use middle::privacy::{AllPublic, LastMod}; -use middle::subst::{FnSpace, ParamSpace, TypeSpace, SelfSpace, Subst, Substs}; +use middle::subst::{FnSpace, TypeSpace, SelfSpace, Subst, Substs}; use middle::traits; use middle::ty::{self, RegionEscape, ToPolyTraitRef, Ty}; use rscope::{self, UnelidableRscope, RegionScope, ElidableRscope, @@ -73,11 +73,14 @@ use syntax::print::pprust; pub trait AstConv<'tcx> { fn tcx<'a>(&'a self) -> &'a ty::ctxt<'tcx>; - fn get_item_type_scheme(&self, id: ast::DefId) -> ty::TypeScheme<'tcx>; + fn get_item_type_scheme(&self, span: Span, id: ast::DefId) + -> Result, ErrorReported>; - fn get_trait_def(&self, id: ast::DefId) -> Rc>; + fn get_trait_def(&self, span: Span, id: ast::DefId) + -> Result>, ErrorReported>; - fn get_type_parameter_bounds(&self, space: ParamSpace, index: u32) -> Vec>; + fn get_type_parameter_bounds(&self, span: Span, def_id: ast::NodeId) + -> Result>, ErrorReported>; /// Return an (optional) substitution to convert bound type parameters that /// are in scope into free ones. This function should only return Some @@ -685,7 +688,14 @@ fn ast_path_to_trait_ref<'a,'tcx>( -> Rc> { debug!("ast_path_to_trait_ref {:?}", trait_segment); - let trait_def = this.get_trait_def(trait_def_id); + let trait_def = match this.get_trait_def(path.span, trait_def_id) { + Ok(trait_def) => trait_def, + Err(ErrorReported) => { + // No convenient way to recover from a cycle here. Just bail. Sorry! + this.tcx().sess.abort_if_errors(); + this.tcx().sess.bug("ErrorReported returned, but no errors reports?") + } + }; let (regions, types, assoc_bindings) = match trait_segment.parameters { ast::AngleBracketedParameters(ref data) => { @@ -862,14 +872,17 @@ fn ast_path_to_ty<'tcx>( item_segment: &ast::PathSegment) -> Ty<'tcx> { - let ty::TypeScheme { - generics, - ty: decl_ty - } = this.get_item_type_scheme(did); - - let substs = ast_path_substs_for_ty(this, rscope, - span, param_mode, - &generics, item_segment); + let tcx = this.tcx(); + let substs = match this.get_item_type_scheme(path.span, did) { + Ok(ty::TypeScheme { generics, ty: decl_ty }) => { + ast_path_substs_for_ty(this, rscope, + span, param_mode, + &generics, item_segment) + } + Err(ErrorReported) => { + return TypeAndSubsts { substs: Substs::empty(), ty: tcx.types.err }; + } + }; // FIXME(#12938): This is a hack until we have full support for DST. if Some(did) == this.tcx().lang_items.owned_box() { @@ -1003,22 +1016,17 @@ fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>, return (tcx.types.err, ty_path_def); }; - 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_node_id]; - ty_param_name = ty_param_def.name; - - - // FIXME(#20300) -- search where clauses, not bounds - suitable_bounds = - traits::transitive_bounds(tcx, - &this.get_type_parameter_bounds(ty_param_def.space, - ty_param_def.index)) - .filter(|b| trait_defines_associated_type_named(this, b.def_id(), assoc_name)) - .collect(); - } + let ty_param_name = tcx.ty_param_defs.borrow()[ty_param_node_id].name; + + // FIXME(#20300) -- search where clauses, not bounds + let bounds = + this.get_type_parameter_bounds(ast_ty.span, ty_param_ndoe_id) + .unwrap_or(Vec::new()); + + let mut suitable_bounds: Vec<_> = + traits::transitive_bounds(tcx, &bounds) + .filter(|b| trait_defines_associated_type_named(this, b.def_id(), assoc_name)) + .collect(); if suitable_bounds.len() == 0 { span_err!(tcx.sess, span, E0220, diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 968d67aca9dde..43edb4f09cc12 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -106,7 +106,7 @@ use session::Session; use {CrateCtxt, lookup_full_def, require_same_types}; use TypeAndSubsts; use lint; -use util::common::{block_query, indenter, loop_query}; +use util::common::{block_query, ErrorReported, indenter, loop_query}; use util::ppaux::{self, Repr}; use util::nodemap::{DefIdMap, FnvHashMap, NodeMap}; use util::lev_distance::lev_distance; @@ -1206,12 +1206,16 @@ fn check_cast<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> { fn tcx(&self) -> &ty::ctxt<'tcx> { self.ccx.tcx } - fn get_item_type_scheme(&self, id: ast::DefId) -> ty::TypeScheme<'tcx> { - ty::lookup_item_type(self.tcx(), id) + fn get_item_type_scheme(&self, _: Span, id: ast::DefId) + -> Result, ErrorReported> + { + Ok(ty::lookup_item_type(self.tcx(), id)) } - fn get_trait_def(&self, id: ast::DefId) -> Rc> { - ty::lookup_trait_def(self.tcx(), id) + fn get_trait_def(&self, _: Span, id: ast::DefId) + -> Result>, ErrorReported> + { + Ok(ty::lookup_trait_def(self.tcx(), id)) } fn get_free_substs(&self) -> Option<&Substs<'tcx>> { @@ -1219,27 +1223,29 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> { } fn get_type_parameter_bounds(&self, - space: ParamSpace, - index: u32) - -> Vec> + _: Span, + node_id: ast::NodeId) + -> Result>, ErrorReported> { - self.inh.param_env.caller_bounds - .iter() - .filter_map(|predicate| { - match *predicate { - ty::Predicate::Trait(ref data) => { - if data.0.self_ty().is_param(space, index) { - Some(data.to_poly_trait_ref()) - } else { - None + let def = self.tcx().type_parameter_def(node_id); + let r = self.inh.param_env.caller_bounds + .iter() + .filter_map(|predicate| { + match *predicate { + ty::Predicate::Trait(ref data) => { + if data.0.self_ty().is_param(def.space, def.index) { + Some(data.to_poly_trait_ref()) + } else { + None + } + } + _ => { + None + } } - } - _ => { - None - } - } - }) - .collect() + }) + .collect(); + Ok(r) } fn ty_infer(&self, _span: Span) -> Ty<'tcx> { diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 6d65d05bf6f3b..cef7f83840b4a 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -98,12 +98,13 @@ use middle::ty::{self, RegionEscape, Ty, TypeScheme}; use middle::ty_fold::{self, TypeFolder, TypeFoldable}; use middle::infer; use rscope::*; -use util::common::memoized; +use util::common::{ErrorReported, memoized}; use util::nodemap::{FnvHashMap, FnvHashSet}; use util::ppaux; use util::ppaux::{Repr,UserString}; use write_ty_to_tcx; +use std::cell::RefCell; use std::collections::HashSet; use std::rc::Rc; @@ -121,7 +122,7 @@ use syntax::visit; // Main entry point pub fn collect_item_types(tcx: &ty::ctxt) { - let ccx = &CrateCtxt { tcx: tcx }; + let ccx = &CrateCtxt { tcx: tcx, stack: RefCell::new(Vec::new()) }; match ccx.tcx.lang_items.ty_desc() { Some(id) => { collect_intrinsic_type(ccx, id); } @@ -143,6 +144,10 @@ pub fn collect_item_types(tcx: &ty::ctxt) { struct CrateCtxt<'a,'tcx:'a> { tcx: &'a ty::ctxt<'tcx>, + + // This stack is used to identify cycles in the user's source. + // Note that these cycles can cross multiple items. + stack: RefCell>, } struct ItemCtxt<'a,'tcx:'a> { @@ -150,6 +155,13 @@ struct ItemCtxt<'a,'tcx:'a> { generics: &'a ty::Generics<'tcx>, } +#[derive(Copy, PartialEq, Eq)] +enum AstConvRequest { + GetItemTypeScheme(ast::DefId), + GetTraitDef(ast::DefId), + GetTypeParameterBounds(ast::NodeId), +} + /////////////////////////////////////////////////////////////////////////// // Zeroth phase: collect types of intrinsics @@ -217,6 +229,94 @@ impl<'a,'tcx> CrateCtxt<'a,'tcx> { } } } + + fn cycle_check(&self, + span: Span, + request: AstConvRequest, + code: F) + -> Result + where F: FnOnce() -> R + { + { + let mut stack = self.stack.borrow_mut(); + match stack.iter().enumerate().rev().find(|&(_, r)| *r == request) { + None => { } + Some((i, _)) => { + let cycle = &stack[i..]; + self.report_cycle(span, cycle); + return Err(ErrorReported); + } + } + stack.push(request); + } + + let result = code(); + + self.stack.borrow_mut().pop(); + Ok(result) + } + + fn report_cycle(&self, + span: Span, + cycle: &[AstConvRequest]) + { + assert!(!cycle.is_empty()); + let tcx = self.tcx; + + tcx.sess.span_err( + span, + &format!("unsupported cyclic reference between types/traits detected")); + + match cycle[0] { + AstConvRequest::GetItemTypeScheme(def_id) | + AstConvRequest::GetTraitDef(def_id) => { + tcx.sess.note( + &format!("the cycle begins when processing `{}`...", + ty::item_path_str(tcx, def_id))); + } + AstConvRequest::GetTypeParameterBounds(id) => { + let def = tcx.type_parameter_def(id); + tcx.sess.note( + &format!("the cycle begins when computing the bounds \ + for type parameter `{}`...", + def.name.user_string(tcx))); + } + } + + for request in cycle[1..].iter() { + match *request { + AstConvRequest::GetItemTypeScheme(def_id) | + AstConvRequest::GetTraitDef(def_id) => { + tcx.sess.note( + &format!("...which then requires processing `{}`...", + ty::item_path_str(tcx, def_id))); + } + AstConvRequest::GetTypeParameterBounds(id) => { + let def = tcx.type_parameter_def(id); + tcx.sess.note( + &format!("...which then requires computing the bounds \ + for type parameter `{}`...", + def.name.user_string(tcx))); + } + } + } + + match cycle[0] { + AstConvRequest::GetItemTypeScheme(def_id) | + AstConvRequest::GetTraitDef(def_id) => { + tcx.sess.note( + &format!("...which then again requires processing `{}`, completing the cycle.", + ty::item_path_str(tcx, def_id))); + } + AstConvRequest::GetTypeParameterBounds(id) => { + let def = tcx.type_parameter_def(id); + tcx.sess.note( + &format!("...which then again requires computing the bounds \ + for type parameter `{}`, completing the cycle.", + def.name.user_string(tcx))); + } + } + } } pub trait ToTy<'tcx> { @@ -232,25 +332,37 @@ impl<'a,'tcx> ToTy<'tcx> for ItemCtxt<'a,'tcx> { impl<'a, 'tcx> AstConv<'tcx> for ItemCtxt<'a, 'tcx> { fn tcx(&self) -> &ty::ctxt<'tcx> { self.ccx.tcx } - fn get_item_type_scheme(&self, id: ast::DefId) -> ty::TypeScheme<'tcx> { - type_scheme_of_def_id(self.ccx, id) + fn get_item_type_scheme(&self, span: Span, id: ast::DefId) + -> Result, ErrorReported> + { + self.ccx.cycle_check(span, AstConvRequest::GetItemTypeScheme(id), || { + type_scheme_of_def_id(self.ccx, id) + }) } - fn get_trait_def(&self, id: ast::DefId) -> Rc> { - get_trait_def(self.ccx, id) + fn get_trait_def(&self, span: Span, id: ast::DefId) + -> Result>, ErrorReported> + { + self.ccx.cycle_check(span, AstConvRequest::GetTraitDef(id), || { + get_trait_def(self.ccx, id) + }) } fn get_type_parameter_bounds(&self, - param: subst::ParamSpace, - index: u32) - -> Vec> + span: Span, + node_id: ast::NodeId) + -> Result>, ErrorReported> { - // TODO out of range indices can occur when you have something - // like fn foo() { } - match self.generics.types.opt_get(param, index as usize) { - Some(def) => def.bounds.trait_bounds.clone(), - None => Vec::new(), - } + self.ccx.cycle_check(span, AstConvRequest::GetTypeParameterBounds(node_id), || { + let def = self.tcx().type_parameter_def(node_id); + + // TODO out of range indices can occur when you have something + // like fn foo() { } + match self.generics.types.opt_get(def.space, def.index as usize) { + Some(def) => def.bounds.trait_bounds.clone(), + None => Vec::new(), + } + }) } fn ty_infer(&self, span: Span) -> Ty<'tcx> { diff --git a/src/test/compile-fail/cycle-generic-bound.rs b/src/test/compile-fail/cycle-generic-bound.rs new file mode 100644 index 0000000000000..51fee683a81c9 --- /dev/null +++ b/src/test/compile-fail/cycle-generic-bound.rs @@ -0,0 +1,19 @@ +// Copyright 2015 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. + +// Regression test for #15477. This test should pass, vs reporting an +// error as it does now, but at least this test shows it doesn't +// segfault. + +trait Chromosome { + //~^ ERROR cyclic reference detected +} + +fn main() { } diff --git a/src/test/compile-fail/cycle-trait-supertrait-direct.rs b/src/test/compile-fail/cycle-trait-supertrait-direct.rs new file mode 100644 index 0000000000000..836b581d2bfb3 --- /dev/null +++ b/src/test/compile-fail/cycle-trait-supertrait-direct.rs @@ -0,0 +1,17 @@ +// Copyright 2015 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 a supertrait cycle where a trait extends itself. + +trait Chromosome: Chromosome { + //~^ ERROR cyclic reference detected +} + +fn main() { } diff --git a/src/test/compile-fail/cycle-trait-supertrait-indirect.rs b/src/test/compile-fail/cycle-trait-supertrait-indirect.rs new file mode 100644 index 0000000000000..68553462036f2 --- /dev/null +++ b/src/test/compile-fail/cycle-trait-supertrait-indirect.rs @@ -0,0 +1,22 @@ +// Copyright 2015 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 a supertrait cycle where the first trait we find (`A`) is not +// a direct participant in the cycle. + +trait A: B { +} + +trait B: C { } + //~^ ERROR cyclic reference detected + +trait C: B { } + +fn main() { } diff --git a/src/test/compile-fail/cycle-trait-type-trait.rs b/src/test/compile-fail/cycle-trait-type-trait.rs new file mode 100644 index 0000000000000..912961120c21a --- /dev/null +++ b/src/test/compile-fail/cycle-trait-type-trait.rs @@ -0,0 +1,23 @@ +// Copyright 2015 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 a supertrait cycle where a trait extends itself. + +trait Chromosome: Get { + //~^ ERROR cyclic reference detected +} + +trait Get { + fn get(&self) -> A; +} + +struct Struct { c: C } + +fn main() { } From 3c782b742bb09d15ccc7bf52bf86091150ba4e5d Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 17 Feb 2015 20:46:26 -0500 Subject: [PATCH 04/10] Rework the `get_type_parameter_bounds` impl to use a trait object and act more generically. --- src/librustc_typeck/collect.rs | 110 +++++++++++++++++++++++---------- 1 file changed, 79 insertions(+), 31 deletions(-) diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index cef7f83840b4a..db5770e4a2528 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -150,9 +150,16 @@ struct CrateCtxt<'a,'tcx:'a> { stack: RefCell>, } +/// Context specific to some particular item. This is what implements +/// AstConv. It has information about the predicates that are defined +/// on the trait. Unfortunately, this predicate information is +/// available in various different forms at various points in the +/// process. So we can't just store a pointer to e.g. the AST or the +/// parsed ty form, we have to wind up keeping both (and making both +/// optional) and extracting what we need from what's available. struct ItemCtxt<'a,'tcx:'a> { ccx: &'a CrateCtxt<'a,'tcx>, - generics: &'a ty::Generics<'tcx>, + param_bounds: &'a (GetTypeParameterBounds<'tcx>+'a), } #[derive(Copy, PartialEq, Eq)] @@ -216,8 +223,8 @@ impl<'a, 'tcx, 'v> visit::Visitor<'v> for CollectItemTypesVisitor<'a, 'tcx> { // Utility types and common code for the above passes. impl<'a,'tcx> CrateCtxt<'a,'tcx> { - fn icx(&'a self, generics: &'a ty::Generics<'tcx>) -> ItemCtxt<'a,'tcx> { - ItemCtxt { ccx: self, generics: generics } + fn icx(&'a self, param_bounds: &'a GetTypeParameterBounds<'tcx>) -> ItemCtxt<'a,'tcx> { + ItemCtxt { ccx: self, param_bounds: param_bounds } } fn method_ty(&self, method_id: ast::NodeId) -> Rc> { @@ -319,11 +326,7 @@ impl<'a,'tcx> CrateCtxt<'a,'tcx> { } } -pub trait ToTy<'tcx> { - fn to_ty(&self, rs: &RS, ast_ty: &ast::Ty) -> Ty<'tcx>; -} - -impl<'a,'tcx> ToTy<'tcx> for ItemCtxt<'a,'tcx> { +impl<'a,'tcx> ItemCtxt<'a,'tcx> { fn to_ty(&self, rs: &RS, ast_ty: &ast::Ty) -> Ty<'tcx> { ast_ty_to_ty(self, rs, ast_ty) } @@ -354,14 +357,7 @@ impl<'a, 'tcx> AstConv<'tcx> for ItemCtxt<'a, 'tcx> { -> Result>, ErrorReported> { self.ccx.cycle_check(span, AstConvRequest::GetTypeParameterBounds(node_id), || { - let def = self.tcx().type_parameter_def(node_id); - - // TODO out of range indices can occur when you have something - // like fn foo() { } - match self.generics.types.opt_get(def.space, def.index as usize) { - Some(def) => def.bounds.trait_bounds.clone(), - None => Vec::new(), - } + self.param_bounds.get_type_parameter_bounds(self, span, node_id) }) } @@ -381,6 +377,32 @@ impl<'a, 'tcx> AstConv<'tcx> for ItemCtxt<'a, 'tcx> { } } + +trait GetTypeParameterBounds<'tcx> { + fn get_type_parameter_bounds(&self, + astconv: &AstConv<'tcx>, + span: Span, + node_id: ast::NodeId) + -> Vec>; +} +impl<'tcx> GetTypeParameterBounds<'tcx> for ty::Generics<'tcx> { + fn get_type_parameter_bounds(&self, + astconv: &AstConv<'tcx>, + _span: Span, + node_id: ast::NodeId) + -> Vec> + { + let def = astconv.tcx().type_parameter_def(node_id); + + // TODO out of range indices can occur when you have something + // like fn foo() { } + match self.types.opt_get(def.space, def.index as usize) { + Some(def) => def.bounds.trait_bounds.clone(), + None => Vec::new(), + } + } +} + fn get_enum_variant_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, enum_scheme: ty::TypeScheme<'tcx>, enum_predicates: ty::GenericPredicates<'tcx>, @@ -1646,13 +1668,10 @@ fn ty_generic_bounds<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, &ast::TyParamBound::TraitTyParamBound(ref poly_trait_ref, _) => { let mut projections = Vec::new(); - let trait_ref = astconv::instantiate_poly_trait_ref( - &ccx.icx(generics), - &ExplicitRscope, - poly_trait_ref, - Some(ty), - &mut projections, - ); + let trait_ref = conv_poly_trait_ref(&ccx.icx(generics), + ty, + poly_trait_ref, + &mut projections); result.predicates.push(space, trait_ref.as_predicate()); @@ -1934,6 +1953,38 @@ fn check_bounds_compatible<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, } } +/// Converts a specific TyParamBound from the AST into the +/// appropriate poly-trait-reference. +fn poly_trait_ref_from_bound<'tcx>(astconv: &AstConv<'tcx>, + param_ty: Ty<'tcx>, + bound: &ast::TyParamBound, + projections: &mut Vec>) + -> Option> +{ + match *bound { + ast::TraitTyParamBound(ref tr, ast::TraitBoundModifier::None) => { + Some(conv_poly_trait_ref(astconv, param_ty, tr, projections)) + } + ast::TraitTyParamBound(_, ast::TraitBoundModifier::Maybe) | + ast::RegionTyParamBound(_) => { + None + } + } +} + +fn conv_poly_trait_ref<'tcx>(astconv: &AstConv<'tcx>, + param_ty: Ty<'tcx>, + trait_ref: &ast::PolyTraitRef, + projections: &mut Vec>) + -> ty::PolyTraitRef<'tcx> +{ + astconv::instantiate_poly_trait_ref(astconv, + &ExplicitRscope, + trait_ref, + Some(param_ty), + projections) +} + fn conv_param_bounds<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, generics: &ty::Generics<'tcx>, span: Span, @@ -1952,14 +2003,11 @@ fn conv_param_bounds<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, let trait_bounds: Vec = trait_bounds.into_iter() - .map(|bound| { - astconv::instantiate_poly_trait_ref(&ccx.icx(generics), - &ExplicitRscope, - bound, - Some(param_ty), - &mut projection_bounds) - }) - .collect(); + .map(|bound| conv_poly_trait_ref(&ccx.icx(generics), + param_ty, + bound, + &mut projection_bounds)) + .collect(); let region_bounds: Vec = region_bounds.into_iter() From 36d04711b774dd97d8341881d26786733a5a6561 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 18 Feb 2015 11:50:51 -0500 Subject: [PATCH 05/10] Remove bounds struct from TypeParameterDef. Bounds information is now exclusively stored in the where clauses. --- src/librustc/metadata/tydecode.rs | 43 ++++++++++++++----------------- src/librustc/metadata/tyencode.rs | 17 ++++++++---- src/librustc/middle/ty.rs | 1 - src/librustc/middle/ty_fold.rs | 1 - src/librustc_typeck/collect.rs | 26 +++---------------- src/librustdoc/clean/mod.rs | 7 ++--- 6 files changed, 38 insertions(+), 57 deletions(-) diff --git a/src/librustc/metadata/tydecode.rs b/src/librustc/metadata/tydecode.rs index 4a45b7fbfdcc7..e96d1b57cc767 100644 --- a/src/librustc/metadata/tydecode.rs +++ b/src/librustc/metadata/tydecode.rs @@ -822,7 +822,6 @@ fn parse_type_param_def_<'a, 'tcx, F>(st: &mut PState<'a, 'tcx>, conv: &mut F) assert_eq!(next(st), '|'); let index = parse_u32(st); assert_eq!(next(st), '|'); - let bounds = parse_bounds_(st, conv); let default = parse_opt(st, |st| parse_ty_(st, conv)); let object_lifetime_default = parse_object_lifetime_default(st, conv); @@ -831,28 +830,11 @@ fn parse_type_param_def_<'a, 'tcx, F>(st: &mut PState<'a, 'tcx>, conv: &mut F) def_id: def_id, space: space, index: index, - bounds: bounds, default: default, object_lifetime_default: object_lifetime_default, } } -fn parse_object_lifetime_default<'a,'tcx, F>(st: &mut PState<'a,'tcx>, - conv: &mut F) - -> Option - where F: FnMut(DefIdSource, ast::DefId) -> ast::DefId, -{ - match next(st) { - 'n' => None, - 'a' => Some(ty::ObjectLifetimeDefault::Ambiguous), - 's' => { - let region = parse_region_(st, conv); - Some(ty::ObjectLifetimeDefault::Specific(region)) - } - _ => panic!("parse_object_lifetime_default: bad input") - } -} - fn parse_existential_bounds<'a,'tcx, F>(st: &mut PState<'a,'tcx>, mut conv: F) -> ty::ExistentialBounds<'tcx> where @@ -924,18 +906,18 @@ fn parse_bounds_<'a, 'tcx, F>(st: &mut PState<'a, 'tcx>, conv: &mut F) { let builtin_bounds = parse_builtin_bounds_(st, conv); + let region_bounds = parse_region_bounds_(st, conv); + let mut param_bounds = ty::ParamBounds { - region_bounds: Vec::new(), + region_bounds: region_bounds, builtin_bounds: builtin_bounds, trait_bounds: Vec::new(), projection_bounds: Vec::new(), }; + + loop { match next(st) { - 'R' => { - param_bounds.region_bounds.push( - parse_region_(st, conv)); - } 'I' => { param_bounds.trait_bounds.push( ty::Binder(parse_trait_ref_(st, conv))); @@ -953,3 +935,18 @@ fn parse_bounds_<'a, 'tcx, F>(st: &mut PState<'a, 'tcx>, conv: &mut F) } } } + +fn parse_region_bounds_<'a, 'tcx, F>(st: &mut PState<'a, 'tcx>, conv: &mut F) + -> Vec where + F: FnMut(DefIdSource, ast::DefId) -> ast::DefId, +{ + let mut region_bounds = Vec::new(); + loop { + match next(st) { + 'R' => { region_bounds.push(parse_region_(st, conv)); } + '.' => { return region_bounds; } + c => { panic!("parse_bounds: bad bounds ('{}')", c); } + } + } +} + diff --git a/src/librustc/metadata/tyencode.rs b/src/librustc/metadata/tyencode.rs index 11609ebe675ef..76a365259aa57 100644 --- a/src/librustc/metadata/tyencode.rs +++ b/src/librustc/metadata/tyencode.rs @@ -386,10 +386,7 @@ pub fn enc_bounds<'a, 'tcx>(w: &mut SeekableMemWriter, cx: &ctxt<'a, 'tcx>, bs: &ty::ParamBounds<'tcx>) { enc_builtin_bounds(w, cx, &bs.builtin_bounds); - for &r in &bs.region_bounds { - mywrite!(w, "R"); - enc_region(w, cx, r); - } + enc_region_bounds(w, cx, &bs.region_bounds); for tp in &bs.trait_bounds { mywrite!(w, "I"); @@ -404,12 +401,22 @@ pub fn enc_bounds<'a, 'tcx>(w: &mut SeekableMemWriter, cx: &ctxt<'a, 'tcx>, mywrite!(w, "."); } +pub fn enc_region_bounds<'a, 'tcx>(w: &mut SeekableMemWriter, + cx: &ctxt<'a, 'tcx>, + rs: &[ty::Region]) { + for &r in rs { + mywrite!(w, "R"); + enc_region(w, cx, r); + } + + mywrite!(w, "."); +} + pub fn enc_type_param_def<'a, 'tcx>(w: &mut SeekableMemWriter, cx: &ctxt<'a, 'tcx>, v: &ty::TypeParameterDef<'tcx>) { mywrite!(w, "{}:{}|{}|{}|", token::get_name(v.name), (cx.ds)(v.def_id), v.space.to_uint(), v.index); - enc_bounds(w, cx, &v.bounds); enc_opt(w, v.default, |w, t| enc_ty(w, cx, t)); enc_object_lifetime_default(w, cx, v.object_lifetime_default); } diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 20a0c35d8e021..78b8d4f7b1e28 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -1750,7 +1750,6 @@ pub struct TypeParameterDef<'tcx> { pub def_id: ast::DefId, pub space: subst::ParamSpace, pub index: u32, - pub bounds: ParamBounds<'tcx>, pub default: Option>, pub object_lifetime_default: Option, } diff --git a/src/librustc/middle/ty_fold.rs b/src/librustc/middle/ty_fold.rs index d2469c052ac51..4bf47c3a75f80 100644 --- a/src/librustc/middle/ty_fold.rs +++ b/src/librustc/middle/ty_fold.rs @@ -377,7 +377,6 @@ impl<'tcx> TypeFoldable<'tcx> for ty::TypeParameterDef<'tcx> { def_id: self.def_id, space: self.space, index: self.index, - bounds: self.bounds.fold_with(folder), default: self.default.fold_with(folder), object_lifetime_default: self.object_lifetime_default.fold_with(folder), } diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index db5770e4a2528..cd2e80d97e10f 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1225,10 +1225,10 @@ fn convert_trait_predicates<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, it: &ast::Item) }; base_predicates.predicates.extend(subst::TypeSpace, assoc_predicates.into_iter()); - let self_bounds = &trait_def.generics.types.get_self().unwrap().bounds; - base_predicates.predicates.extend( - subst::SelfSpace, - ty::predicates(ccx.tcx, self_param_ty, self_bounds).into_iter()); + // Add in a predicate that `Self:Trait` (where `Trait` is the + // current trait). This is needed for builtin bounds. + let self_predicate = trait_def.trait_ref.to_poly_trait_ref().as_predicate(); + base_predicates.predicates.push(SelfSpace, self_predicate); // add in the explicit where-clauses let trait_predicates = @@ -1532,21 +1532,11 @@ fn ty_generics_for_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, // the node id for the Self type parameter. let param_id = trait_id; - let self_trait_ref = - Rc::new(ty::TraitRef { def_id: local_def(trait_id), - substs: substs }); - let def = ty::TypeParameterDef { space: subst::SelfSpace, index: 0, name: special_idents::type_self.name, def_id: local_def(param_id), - bounds: ty::ParamBounds { - region_bounds: vec!(), - builtin_bounds: ty::empty_builtin_bounds(), - trait_bounds: vec!(ty::Binder(self_trait_ref.clone())), - projection_bounds: vec!(), - }, default: None, object_lifetime_default: None, }; @@ -1761,13 +1751,6 @@ fn get_or_create_type_parameter_def<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, None => { } } - let param_ty = ty::ParamTy::new(space, index, param.ident.name); - let bounds = compute_bounds(ccx, - generics_so_far, - param_ty.to_ty(ccx.tcx), - ¶m.bounds, - SizedByDefault::Yes, - param.span); let default = match param.default { None => None, Some(ref path) => { @@ -1797,7 +1780,6 @@ fn get_or_create_type_parameter_def<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, index: index, name: param.ident.name, def_id: local_def(param.id), - bounds: bounds, default: default, object_lifetime_default: object_lifetime_default, }; diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index b88620d577f37..36d39fa58ba7e 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -479,11 +479,10 @@ impl<'tcx> Clean for ty::TypeParameterDef<'tcx> { fn clean(&self, cx: &DocContext) -> TyParam { cx.external_typarams.borrow_mut().as_mut().unwrap() .insert(self.def_id, self.name.clean(cx)); - let bounds = self.bounds.clean(cx); TyParam { name: self.name.clean(cx), did: self.def_id, - bounds: bounds, + bounds: vec![], // these are filled in from the where-clauses default: self.default.clean(cx), } } @@ -892,9 +891,7 @@ impl<'a, 'tcx> Clean for (&'a ty::Generics<'tcx>, // Bounds in the type_params and lifetimes fields are repeated in the predicates // field (see rustc_typeck::collect::ty_generics), so remove them. let stripped_typarams = gens.types.get_slice(space).iter().map(|tp| { - let mut stp = tp.clone(); - stp.bounds = ty::ParamBounds::empty(); - stp.clean(cx) + tp.clean(cx) }).collect::>(); let stripped_lifetimes = gens.regions.get_slice(space).iter().map(|rp| { let mut srp = rp.clone(); From cf73e36ab01f48c883808cf58af5baed8d697538 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 18 Feb 2015 10:39:39 -0500 Subject: [PATCH 06/10] Rework trait-bound-conversion so be based on the AST and rework collect to pass in the appropriate ast::generics etc --- src/librustc/metadata/tydecode.rs | 16 + src/librustc_typeck/collect.rs | 590 ++++++++++-------- ...on-ambig-between-bound-and-where-clause.rs | 52 ++ .../cycle-projection-based-on-where-clause.rs | 34 + .../cycle-trait-supertrait-direct.rs | 2 +- .../cycle-trait-supertrait-indirect.rs | 2 +- ...om-type-param-via-bound-in-where-clause.rs | 107 ++++ .../cycle-generic-bound.rs | 9 +- .../cycle-trait-type-trait.rs | 6 +- 9 files changed, 552 insertions(+), 266 deletions(-) create mode 100644 src/test/compile-fail/associated-type-projection-ambig-between-bound-and-where-clause.rs create mode 100644 src/test/compile-fail/cycle-projection-based-on-where-clause.rs create mode 100644 src/test/run-pass/associated-types-project-from-type-param-via-bound-in-where-clause.rs rename src/test/{compile-fail => run-pass}/cycle-generic-bound.rs (68%) rename src/test/{compile-fail => run-pass}/cycle-trait-type-trait.rs (77%) diff --git a/src/librustc/metadata/tydecode.rs b/src/librustc/metadata/tydecode.rs index e96d1b57cc767..baecfb7eb22c5 100644 --- a/src/librustc/metadata/tydecode.rs +++ b/src/librustc/metadata/tydecode.rs @@ -835,6 +835,22 @@ fn parse_type_param_def_<'a, 'tcx, F>(st: &mut PState<'a, 'tcx>, conv: &mut F) } } +fn parse_object_lifetime_default<'a,'tcx, F>(st: &mut PState<'a,'tcx>, + conv: &mut F) + -> Option + where F: FnMut(DefIdSource, ast::DefId) -> ast::DefId, +{ + match next(st) { + 'n' => None, + 'a' => Some(ty::ObjectLifetimeDefault::Ambiguous), + 's' => { + let region = parse_region_(st, conv); + Some(ty::ObjectLifetimeDefault::Specific(region)) + } + _ => panic!("parse_object_lifetime_default: bad input") + } +} + fn parse_existential_bounds<'a,'tcx, F>(st: &mut PState<'a,'tcx>, mut conv: F) -> ty::ExistentialBounds<'tcx> where diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index cd2e80d97e10f..2899d8868cca0 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -91,10 +91,9 @@ use constrained_type_params::identify_constrained_type_params; use middle::lang_items::SizedTraitLangItem; use middle::region; use middle::resolve_lifetime; -use middle::subst; -use middle::subst::{Substs, SelfSpace, TypeSpace, VecPerParamSpace}; +use middle::subst::{Substs, FnSpace, ParamSpace, SelfSpace, TypeSpace, VecPerParamSpace}; use middle::ty::{AsPredicate, ImplContainer, ImplOrTraitItemContainer, TraitContainer}; -use middle::ty::{self, RegionEscape, Ty, TypeScheme}; +use middle::ty::{self, RegionEscape, ToPolyTraitRef, Ty, TypeScheme}; use middle::ty_fold::{self, TypeFolder, TypeFoldable}; use middle::infer; use rscope::*; @@ -155,8 +154,12 @@ struct CrateCtxt<'a,'tcx:'a> { /// on the trait. Unfortunately, this predicate information is /// available in various different forms at various points in the /// process. So we can't just store a pointer to e.g. the AST or the -/// parsed ty form, we have to wind up keeping both (and making both -/// optional) and extracting what we need from what's available. +/// parsed ty form, we have to be more flexible. To this end, the +/// `ItemCtxt` is parameterized by a `GetTypeParameterBounds` object +/// that it uses to satisfy `get_type_parameter_bounds` requests. +/// This object might draw the information from the AST +/// (`ast::Generics`) or it might draw from a `ty::GenericPredicates` +/// or both (a tuple). struct ItemCtxt<'a,'tcx:'a> { ccx: &'a CrateCtxt<'a,'tcx>, param_bounds: &'a (GetTypeParameterBounds<'tcx>+'a), @@ -377,7 +380,8 @@ impl<'a, 'tcx> AstConv<'tcx> for ItemCtxt<'a, 'tcx> { } } - +/// Interface used to find the bounds on a type parameter from within +/// an `ItemCtxt`. This allows us to use multiple kinds of sources. trait GetTypeParameterBounds<'tcx> { fn get_type_parameter_bounds(&self, astconv: &AstConv<'tcx>, @@ -385,7 +389,39 @@ trait GetTypeParameterBounds<'tcx> { node_id: ast::NodeId) -> Vec>; } -impl<'tcx> GetTypeParameterBounds<'tcx> for ty::Generics<'tcx> { + +/// Find bounds from both elements of the tuple. +impl<'a,'b,'tcx,A,B> GetTypeParameterBounds<'tcx> for (&'a A,&'b B) + where A : GetTypeParameterBounds<'tcx>, B : GetTypeParameterBounds<'tcx> +{ + fn get_type_parameter_bounds(&self, + astconv: &AstConv<'tcx>, + span: Span, + node_id: ast::NodeId) + -> Vec> + { + let mut v = self.0.get_type_parameter_bounds(astconv, span, node_id); + v.extend(self.1.get_type_parameter_bounds(astconv, span, node_id).into_iter()); + v + } +} + +/// Empty set of bounds. +impl<'tcx> GetTypeParameterBounds<'tcx> for () { + fn get_type_parameter_bounds(&self, + _astconv: &AstConv<'tcx>, + _span: Span, + _node_id: ast::NodeId) + -> Vec> + { + Vec::new() + } +} + +/// Find bounds from the parsed and converted predicates. This is +/// used when converting methods, because by that time the predicates +/// from the trait/impl have been fully converted. +impl<'tcx> GetTypeParameterBounds<'tcx> for ty::GenericPredicates<'tcx> { fn get_type_parameter_bounds(&self, astconv: &AstConv<'tcx>, _span: Span, @@ -394,12 +430,88 @@ impl<'tcx> GetTypeParameterBounds<'tcx> for ty::Generics<'tcx> { { let def = astconv.tcx().type_parameter_def(node_id); - // TODO out of range indices can occur when you have something - // like fn foo() { } - match self.types.opt_get(def.space, def.index as usize) { - Some(def) => def.bounds.trait_bounds.clone(), - None => Vec::new(), + self.predicates + .iter() + .filter_map(|predicate| { + match *predicate { + ty::Predicate::Trait(ref data) => { + if data.0.self_ty().is_param(def.space, def.index) { + Some(data.to_poly_trait_ref()) + } else { + None + } + } + ty::Predicate::Equate(..) | + ty::Predicate::RegionOutlives(..) | + ty::Predicate::TypeOutlives(..) | + ty::Predicate::Projection(..) => { + None + } + } + }) + .collect() + } +} + +/// Find bounds from ast::Generics. This requires scanning through the +/// AST. We do this to avoid having to convert *all* the bounds, which +/// would create artificial cycles. Instead we can only convert the +/// bounds for those a type parameter `X` if `X::Foo` is used. +impl<'tcx> GetTypeParameterBounds<'tcx> for ast::Generics { + fn get_type_parameter_bounds(&self, + astconv: &AstConv<'tcx>, + _: Span, + node_id: ast::NodeId) + -> Vec> + { + // In the AST, bounds can derive from two places. Either + // written inline like `` or in a where clause like + // `where T:Foo`. + + let def = astconv.tcx().type_parameter_def(node_id); + let ty = ty::mk_param_from_def(astconv.tcx(), &def); + + let from_ty_params = + self.ty_params + .iter() + .filter(|p| p.id == node_id) + .flat_map(|p| p.bounds.iter()) + .filter_map(|b| poly_trait_ref_from_bound(astconv, ty, b, &mut Vec::new())); + + let from_where_clauses = + self.where_clause + .predicates + .iter() + .filter_map(|wp| match *wp { + ast::WherePredicate::BoundPredicate(ref bp) => Some(bp), + _ => None + }) + .filter(|bp| is_param(astconv.tcx(), &bp.bounded_ty, node_id)) + .flat_map(|bp| bp.bounds.iter()) + .filter_map(|b| poly_trait_ref_from_bound(astconv, ty, b, &mut Vec::new())); + + from_ty_params.chain(from_where_clauses).collect() + } +} + +/// Tests whether this is the AST for a reference to the type +/// parameter with id `param_id`. We use this so as to avoid running +/// `ast_ty_to_ty`, because we want to avoid triggering an all-out +/// conversion of the type to avoid inducing unnecessary cycles. +fn is_param<'tcx>(tcx: &ty::ctxt<'tcx>, + ast_ty: &ast::Ty, + param_id: ast::NodeId) + -> bool +{ + if let ast::TyPath(None, _) = ast_ty.node { + let path_res = ccx.tcx.def_map.borrow()[ast_ty.id]; + if let def::DefTyParam(_, _, def_id, _) = path_res.base_def { + path_res.depth == 0 && def_id == local_def(param_id) + } else { + false } + } else { + false } } @@ -408,7 +520,7 @@ fn get_enum_variant_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, enum_predicates: ty::GenericPredicates<'tcx>, variants: &[P]) { let tcx = ccx.tcx; - let icx = ccx.icx(&enum_scheme.generics); + let icx = ccx.icx(&enum_predicates); // Create a set of parameter types shared among all the variants. for variant in variants { @@ -571,19 +683,14 @@ fn collect_trait_methods<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, -> ty::Method<'tcx> { let ty_generics = - ty_generics_for_fn_or_method(ccx, - m_generics, - trait_generics.clone()); + ty_generics_for_fn(ccx, m_generics, trait_generics); - let ty_bounds = - ty_generic_bounds_for_fn_or_method(ccx, - m_generics, - &ty_generics, - trait_bounds.clone()); + let ty_generic_predicates = + ty_generic_predicates_for_fn(ccx, m_generics, trait_bounds); let (fty, explicit_self_category) = { let trait_self_ty = ty::mk_self_type(ccx.tcx); - astconv::ty_of_method(&ccx.icx(&ty_generics), + astconv::ty_of_method(&ccx.icx(&(trait_bounds, m_generics)), *m_unsafety, trait_self_ty, m_explicit_self, @@ -594,7 +701,7 @@ fn collect_trait_methods<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, ty::Method::new( *m_name, ty_generics, - ty_bounds, + ty_generic_predicates, fty, explicit_self_category, // assume public, because this is only invoked on trait methods @@ -613,7 +720,7 @@ fn convert_field<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, origin: ast::DefId) -> ty::field_ty { - let tt = ccx.icx(struct_generics).to_ty(&ExplicitRscope, &*v.node.ty); + let tt = ccx.icx(struct_predicates).to_ty(&ExplicitRscope, &*v.node.ty); write_ty_to_tcx(ccx.tcx, v.node.id, tt); /* add the field to the tcache */ @@ -668,7 +775,8 @@ fn convert_methods<'a,'tcx,'i,I>(ccx: &CrateCtxt<'a, 'tcx>, rcvr_ty_generics: &ty::Generics<'tcx>, rcvr_ty_predicates: &ty::GenericPredicates<'tcx>, rcvr_visibility: ast::Visibility) - where I: Iterator { + where I: Iterator +{ debug!("convert_methods(untransformed_rcvr_ty={}, rcvr_ty_generics={})", untransformed_rcvr_ty.repr(ccx.tcx), rcvr_ty_generics.repr(ccx.tcx)); @@ -719,24 +827,21 @@ fn convert_methods<'a,'tcx,'i,I>(ccx: &CrateCtxt<'a, 'tcx>, rcvr_ty_generics: &ty::Generics<'tcx>, rcvr_ty_predicates: &ty::GenericPredicates<'tcx>, rcvr_visibility: ast::Visibility) - -> ty::Method<'tcx> { + -> ty::Method<'tcx> + { let m_ty_generics = - ty_generics_for_fn_or_method(ccx, - m.pe_generics(), - rcvr_ty_generics.clone()); - - let m_ty_bounds = - ty_generic_bounds_for_fn_or_method(ccx, - m.pe_generics(), - &m_ty_generics, - rcvr_ty_predicates.clone()); - - let (fty, explicit_self_category) = astconv::ty_of_method(&ccx.icx(&m_ty_generics), - m.pe_unsafety(), - untransformed_rcvr_ty, - m.pe_explicit_self(), - &*m.pe_fn_decl(), - m.pe_abi()); + ty_generics_for_fn(ccx, m.pe_generics(), rcvr_ty_generics); + + let m_ty_generic_predicates = + ty_generic_predicates_for_fn(ccx, m.pe_generics(), rcvr_ty_predicates); + + let (fty, explicit_self_category) = + astconv::ty_of_method(&ccx.icx(&(rcvr_ty_predicates, m.pe_generics())), + 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 @@ -746,7 +851,7 @@ fn convert_methods<'a,'tcx,'i,I>(ccx: &CrateCtxt<'a, 'tcx>, ty::Method::new(m.pe_ident().name, m_ty_generics, - m_ty_bounds, + m_ty_generic_predicates, fty, explicit_self_category, method_vis, @@ -820,11 +925,11 @@ fn convert_item(ccx: &CrateCtxt, it: &ast::Item) { debug!("convert: ast_generics={:?}", generics); let ty_generics = ty_generics_for_type_or_impl(ccx, generics); - let ty_predicates = ty_generic_bounds_for_type_or_impl(ccx, &ty_generics, generics); + let ty_predicates = ty_generic_predicates_for_type_or_impl(ccx, generics); debug!("convert: impl_bounds={:?}", ty_predicates); - let selfty = ccx.icx(&ty_generics).to_ty(&ExplicitRscope, &**selfty); + let selfty = ccx.icx(&ty_predicates).to_ty(&ExplicitRscope, &**selfty); write_ty_to_tcx(tcx, it.id, selfty); tcx.tcache.borrow_mut().insert(local_def(it.id), @@ -856,7 +961,7 @@ fn convert_item(ccx: &CrateCtxt, it: &ast::Item) { "associated items are not allowed in inherent impls"); } - let typ = ccx.icx(&ty_generics).to_ty(&ExplicitRscope, &*typedef.typ); + let typ = ccx.icx(&ty_predicates).to_ty(&ExplicitRscope, &*typedef.typ); tcx.tcache.borrow_mut().insert(local_def(typedef.id), TypeScheme { generics: ty::Generics::empty(), @@ -904,7 +1009,7 @@ fn convert_item(ccx: &CrateCtxt, it: &ast::Item) { } if let Some(ref trait_ref) = *opt_trait_ref { - astconv::instantiate_trait_ref(&ccx.icx(&ty_generics), + astconv::instantiate_trait_ref(&ccx.icx(&ty_predicates), &ExplicitRscope, trait_ref, Some(it.id), @@ -1124,8 +1229,7 @@ fn trait_def_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let self_param_ty = ty::ParamTy::for_self().to_ty(ccx.tcx); // supertraits: - let bounds = compute_bounds(ccx, - &ty_generics, + let bounds = compute_bounds(&ccx.icx(generics), self_param_ty, bounds, SizedByDefault::No, @@ -1161,7 +1265,7 @@ fn trait_def_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, fn mk_trait_substs<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, generics: &ast::Generics) - -> subst::Substs<'tcx> + -> Substs<'tcx> { let tcx = ccx.tcx; @@ -1171,7 +1275,7 @@ fn trait_def_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, .iter() .enumerate() .map(|(i, def)| ty::ReEarlyBound(def.lifetime.id, - subst::TypeSpace, + TypeSpace, i as u32, def.lifetime.name)) .collect(); @@ -1181,14 +1285,14 @@ fn trait_def_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, generics.ty_params .iter() .enumerate() - .map(|(i, def)| ty::mk_param(tcx, subst::TypeSpace, + .map(|(i, def)| ty::mk_param(tcx, TypeSpace, i as u32, def.ident.name)) .collect(); // ...and also create the `Self` parameter. let self_ty = ty::mk_self_type(tcx); - subst::Substs::new_trait(types, regions, self_ty) + Substs::new_trait(types, regions, self_ty) } } @@ -1211,10 +1315,7 @@ fn convert_trait_predicates<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, it: &ast::Item) let super_predicates = ty::predicates(ccx.tcx, self_param_ty, &trait_def.bounds); - let assoc_predicates = predicates_for_associated_types(ccx, &trait_def.generics, - &trait_def.trait_ref, items); - - // `ty_generic_bounds` below will consider the bounds on the type + // `ty_generic_predicates` below will consider the bounds on the type // parameters (including `Self`) and the explicit where-clauses, // but to get the full set of predicates on a trait we need to add // in the supertrait bounds and anything declared on the @@ -1223,7 +1324,6 @@ fn convert_trait_predicates<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, it: &ast::Item) ty::GenericPredicates { predicates: VecPerParamSpace::new(super_predicates, vec![], vec![]) }; - base_predicates.predicates.extend(subst::TypeSpace, assoc_predicates.into_iter()); // Add in a predicate that `Self:Trait` (where `Trait` is the // current trait). This is needed for builtin bounds. @@ -1231,12 +1331,15 @@ fn convert_trait_predicates<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, it: &ast::Item) base_predicates.predicates.push(SelfSpace, self_predicate); // add in the explicit where-clauses - let trait_predicates = - ty_generic_bounds(ccx, - subst::TypeSpace, - &trait_def.generics, - base_predicates, - &generics.where_clause); + let mut trait_predicates = + ty_generic_predicates(ccx, TypeSpace, generics, &base_predicates); + + let assoc_predicates = predicates_for_associated_types(ccx, + generics, + &trait_predicates, + &trait_def.trait_ref, + items); + trait_predicates.predicates.extend(TypeSpace, assoc_predicates.into_iter()); let prev_predicates = tcx.predicates.borrow_mut().insert(def_id, trait_predicates); assert!(prev_predicates.is_none()); @@ -1244,7 +1347,8 @@ fn convert_trait_predicates<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, it: &ast::Item) return; fn predicates_for_associated_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, - generics: &ty::Generics<'tcx>, + ast_generics: &ast::Generics, + trait_predicates: &ty::GenericPredicates<'tcx>, self_trait_ref: &Rc>, trait_items: &[ast::TraitItem]) -> Vec> @@ -1263,8 +1367,7 @@ fn convert_trait_predicates<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, it: &ast::Item) self_trait_ref.clone(), assoc_type_def.ident.name); - let bounds = compute_bounds(ccx, - generics, + let bounds = compute_bounds(&ccx.icx(&(ast_generics, trait_predicates)), assoc_ty, &*assoc_type_def.bounds, SizedByDefault::Yes, @@ -1309,7 +1412,6 @@ fn type_scheme_of_item<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, |_| compute_type_scheme_of_item(ccx, it)) } - fn compute_type_scheme_of_item<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &ast::Item) -> ty::TypeScheme<'tcx> @@ -1317,20 +1419,18 @@ fn compute_type_scheme_of_item<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, let tcx = ccx.tcx; match it.node { ast::ItemStatic(ref t, _, _) | ast::ItemConst(ref t, _) => { - let ty = ccx.icx(&ty::Generics::empty()).to_ty(&ExplicitRscope, &**t); + let ty = ccx.icx(&()).to_ty(&ExplicitRscope, &**t); ty::TypeScheme { ty: ty, generics: ty::Generics::empty() } } ast::ItemFn(ref decl, unsafety, abi, ref generics, _) => { - let ty_generics = ty_generics_for_fn_or_method(ccx, - generics, - ty::Generics::empty()); - let tofd = astconv::ty_of_bare_fn(&ccx.icx(&ty_generics), unsafety, abi, &**decl); + let ty_generics = ty_generics_for_fn(ccx, generics, &ty::Generics::empty()); + let tofd = astconv::ty_of_bare_fn(&ccx.icx(generics), unsafety, abi, &**decl); let ty = ty::mk_bare_fn(tcx, Some(local_def(it.id)), tcx.mk_bare_fn(tofd)); ty::TypeScheme { ty: ty, generics: ty_generics } } ast::ItemTy(ref t, ref generics) => { let ty_generics = ty_generics_for_type_or_impl(ccx, generics); - let ty = ccx.icx(&ty_generics).to_ty(&ExplicitRscope, &**t); + let ty = ccx.icx(generics).to_ty(&ExplicitRscope, &**t); ty::TypeScheme { ty: ty, generics: ty_generics } } ast::ItemEnum(_, ref generics) => { @@ -1375,19 +1475,16 @@ fn convert_typed_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, ty::GenericPredicates::empty() } ast::ItemFn(_, _, _, ref ast_generics, _) => { - ty_generic_bounds_for_fn_or_method(ccx, - ast_generics, - &scheme.generics, - ty::GenericPredicates::empty()) + ty_generic_predicates_for_fn(ccx, ast_generics, &ty::GenericPredicates::empty()) } ast::ItemTy(_, ref generics) => { - ty_generic_bounds_for_type_or_impl(ccx, &scheme.generics, generics) + ty_generic_predicates_for_type_or_impl(ccx, generics) } ast::ItemEnum(_, ref generics) => { - ty_generic_bounds_for_type_or_impl(ccx, &scheme.generics, generics) + ty_generic_predicates_for_type_or_impl(ccx, generics) } ast::ItemStruct(_, ref generics) => { - ty_generic_bounds_for_type_or_impl(ccx, &scheme.generics, generics) + ty_generic_predicates_for_type_or_impl(ccx, generics) } ast::ItemDefaultImpl(..) | ast::ItemTrait(..) | @@ -1399,8 +1496,8 @@ fn convert_typed_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, ast::ItemMac(..) => { tcx.sess.span_bug( it.span, - format!("compute_type_scheme_of_item: unexpected item type: {:?}", - it.node).as_slice()); + &format!("compute_type_scheme_of_item: unexpected item type: {:?}", + it.node)); } }; @@ -1416,7 +1513,7 @@ fn convert_typed_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, Some(ty::ObjectLifetimeDefault::Specific(r)) => r.user_string(tcx), d => - d.repr(ccx.tcx()), + d.repr(ccx.tcx), }) .collect::>() .connect(","); @@ -1451,7 +1548,7 @@ fn compute_type_scheme_of_foreign_item<'a, 'tcx>( ast::ForeignItemStatic(ref t, _) => { ty::TypeScheme { generics: ty::Generics::empty(), - ty: ast_ty_to_ty(&ccx.icx(&ty::Generics::empty()), &ExplicitRscope, t) + ty: ast_ty_to_ty(&ccx.icx(&()), &ExplicitRscope, t) } } } @@ -1472,10 +1569,7 @@ fn convert_foreign_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let predicates = match it.node { ast::ForeignItemFn(_, ref generics) => { - ty_generic_bounds_for_fn_or_method(ccx, - generics, - &scheme.generics, - ty::GenericPredicates::empty()) + ty_generic_predicates_for_fn(ccx, generics, &ty::GenericPredicates::empty()) } ast::ForeignItemStatic(..) => { ty::GenericPredicates::empty() @@ -1489,42 +1583,26 @@ fn convert_foreign_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, fn ty_generics_for_type_or_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, generics: &ast::Generics) -> ty::Generics<'tcx> { - ty_generics(ccx, - subst::TypeSpace, - &generics.lifetimes, - &generics.ty_params, - &generics.where_clause, - ty::Generics::empty()) + ty_generics(ccx, TypeSpace, generics, &ty::Generics::empty()) } -fn ty_generic_bounds_for_type_or_impl<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, - ty_generics: &ty::Generics<'tcx>, - generics: &ast::Generics) - -> ty::GenericPredicates<'tcx> +fn ty_generic_predicates_for_type_or_impl<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, + generics: &ast::Generics) + -> ty::GenericPredicates<'tcx> { - ty_generic_bounds(ccx, - subst::TypeSpace, - ty_generics, - ty::GenericPredicates::empty(), - &generics.where_clause) + ty_generic_predicates(ccx, TypeSpace, generics, &ty::GenericPredicates::empty()) } fn ty_generics_for_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, trait_id: ast::NodeId, - substs: &'tcx subst::Substs<'tcx>, + substs: &'tcx Substs<'tcx>, ast_generics: &ast::Generics) -> ty::Generics<'tcx> { debug!("ty_generics_for_trait(trait_id={}, substs={})", local_def(trait_id).repr(ccx.tcx), substs.repr(ccx.tcx)); - let mut generics = - ty_generics(ccx, - subst::TypeSpace, - &ast_generics.lifetimes, - &ast_generics.ty_params, - &ast_generics.where_clause, - ty::Generics::empty()); + let mut generics = ty_generics_for_type_or_impl(ccx, ast_generics); // Add in the self type parameter. // @@ -1533,7 +1611,7 @@ fn ty_generics_for_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let param_id = trait_id; let def = ty::TypeParameterDef { - space: subst::SelfSpace, + space: SelfSpace, index: 0, name: special_idents::type_self.name, def_id: local_def(param_id), @@ -1543,44 +1621,35 @@ fn ty_generics_for_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, ccx.tcx.ty_param_defs.borrow_mut().insert(param_id, def.clone()); - generics.types.push(subst::SelfSpace, def); + generics.types.push(SelfSpace, def); return generics; } -fn ty_generics_for_fn_or_method<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, - generics: &ast::Generics, - base_generics: ty::Generics<'tcx>) - -> ty::Generics<'tcx> +fn ty_generics_for_fn<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, + generics: &ast::Generics, + base_generics: &ty::Generics<'tcx>) + -> ty::Generics<'tcx> { - let early_lifetimes = resolve_lifetime::early_bound_lifetimes(generics); - ty_generics(ccx, - subst::FnSpace, - &early_lifetimes[..], - &generics.ty_params, - &generics.where_clause, - base_generics) + ty_generics(ccx, FnSpace, generics, base_generics) } -fn ty_generic_bounds_for_fn_or_method<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, - generics: &ast::Generics, - ty_generics: &ty::Generics<'tcx>, - base: ty::GenericPredicates<'tcx>) - -> ty::GenericPredicates<'tcx> +fn ty_generic_predicates_for_fn<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, + generics: &ast::Generics, + base_predicates: &ty::GenericPredicates<'tcx>) + -> ty::GenericPredicates<'tcx> { - ty_generic_bounds(ccx, - subst::FnSpace, - ty_generics, - base, - &generics.where_clause) + ty_generic_predicates(ccx, FnSpace, generics, base_predicates) } // Add the Sized bound, unless the type parameter is marked as `?Sized`. -fn add_unsized_bound<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, - bounds: &mut ty::BuiltinBounds, - ast_bounds: &[ast::TyParamBound], - span: Span) +fn add_unsized_bound<'tcx>(astconv: &AstConv<'tcx>, + bounds: &mut ty::BuiltinBounds, + ast_bounds: &[ast::TyParamBound], + span: Span) { + let tcx = astconv.tcx(); + // Try to find an unbound in bounds. let mut unbound = None; for ab in ast_bounds { @@ -1589,67 +1658,95 @@ fn add_unsized_bound<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, assert!(ptr.bound_lifetimes.is_empty()); unbound = Some(ptr.trait_ref.clone()); } else { - span_err!(ccx.tcx.sess, span, E0203, + span_err!(tcx.sess, span, E0203, "type parameter has more than one relaxed default \ bound, only one is supported"); } } } - let kind_id = ccx.tcx.lang_items.require(SizedTraitLangItem); + let kind_id = tcx.lang_items.require(SizedTraitLangItem); match unbound { Some(ref tpb) => { // FIXME(#8559) currently requires the unbound to be built-in. - let trait_def_id = ty::trait_ref_to_def_id(ccx.tcx, tpb); + let trait_def_id = ty::trait_ref_to_def_id(tcx, tpb); match kind_id { Ok(kind_id) if trait_def_id != kind_id => { - ccx.tcx.sess.span_warn(span, - "default bound relaxed for a type parameter, but \ - this does nothing because the given bound is not \ - a default. Only `?Sized` is supported"); - ty::try_add_builtin_trait(ccx.tcx, - kind_id, - bounds); + tcx.sess.span_warn(span, + "default bound relaxed for a type parameter, but \ + this does nothing because the given bound is not \ + a default. Only `?Sized` is supported"); + ty::try_add_builtin_trait(tcx, kind_id, bounds); } _ => {} } } _ if kind_id.is_ok() => { - ty::try_add_builtin_trait(ccx.tcx, kind_id.unwrap(), bounds); + ty::try_add_builtin_trait(tcx, kind_id.unwrap(), bounds); } // No lang item for Sized, so we can't add it as a bound. None => {} } } -fn ty_generic_bounds<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, - space: subst::ParamSpace, - generics: &ty::Generics<'tcx>, - base: ty::GenericPredicates<'tcx>, - where_clause: &ast::WhereClause) - -> ty::GenericPredicates<'tcx> +/// Returns the early-bound lifetimes declared in this generics +/// listing. For anything other than fns/methods, this is just all +/// the lifetimes that are declared. For fns or methods, we have to +/// screen out those that do not appear in any where-clauses etc using +/// `resolve_lifetime::early_bound_lifetimes`. +fn early_bound_lifetimes_from_generics(space: ParamSpace, + ast_generics: &ast::Generics) + -> Vec +{ + match space { + SelfSpace | TypeSpace => ast_generics.lifetimes.to_vec(), + FnSpace => resolve_lifetime::early_bound_lifetimes(ast_generics), + } +} + +fn ty_generic_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, + space: ParamSpace, + ast_generics: &ast::Generics, + base_predicates: &ty::GenericPredicates<'tcx>) + -> ty::GenericPredicates<'tcx> { let tcx = ccx.tcx; - let mut result = base; - - // For now, scrape the bounds out of parameters from Generics. This is not great. - for def in generics.regions.get_slice(space) { - let r_a = def.to_early_bound_region(); - for &r_b in &def.bounds { - let outlives = ty::Binder(ty::OutlivesPredicate(r_a, r_b)); - result.predicates.push(def.space, ty::Predicate::RegionOutlives(outlives)); - } + let mut result = base_predicates.clone(); + + // Collect the predicates that were written inline by the user on each + // type parameter (e.g., ``). + for (index, param) in ast_generics.ty_params.iter().enumerate() { + let index = index as u32; + let param_ty = ty::ParamTy::new(space, index, param.ident.name).to_ty(ccx.tcx); + let bounds = compute_bounds(&ccx.icx(&(base_predicates, ast_generics)), + param_ty, + ¶m.bounds[], + SizedByDefault::Yes, + param.span); + let predicates = ty::predicates(ccx.tcx, param_ty, &bounds); + result.predicates.extend(space, predicates.into_iter()); } - for def in generics.types.get_slice(space) { - let t = ty::mk_param_from_def(ccx.tcx, def); - result.predicates.extend(def.space, ty::predicates(ccx.tcx, t, &def.bounds).into_iter()); + + // Collect the region predicates that were declared inline as + // well. In the case of parameters declared on a fn or method, we + // have to be careful to only iterate over early-bound regions. + let early_lifetimes = early_bound_lifetimes_from_generics(space, ast_generics); + for (index, param) in early_lifetimes.iter().enumerate() { + let index = index as u32; + let region = ty::ReEarlyBound(param.lifetime.id, space, index, param.lifetime.name); + for bound in ¶m.bounds { + let bound_region = ast_region_to_region(ccx.tcx, bound); + let outlives = ty::Binder(ty::OutlivesPredicate(region, bound_region)); + result.predicates.push(space, outlives.as_predicate()); + } } - // Add the bounds not associated with a type parameter + // Add in the bounds that appear in the where-clause + let where_clause = &ast_generics.where_clause; for predicate in &where_clause.predicates { match predicate { &ast::WherePredicate::BoundPredicate(ref bound_pred) => { - let ty = ast_ty_to_ty(&ccx.icx(generics), + let ty = ast_ty_to_ty(&ccx.icx(&(base_predicates, ast_generics)), &ExplicitRscope, &*bound_pred.bounded_ty); @@ -1658,10 +1755,11 @@ fn ty_generic_bounds<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, &ast::TyParamBound::TraitTyParamBound(ref poly_trait_ref, _) => { let mut projections = Vec::new(); - let trait_ref = conv_poly_trait_ref(&ccx.icx(generics), - ty, - poly_trait_ref, - &mut projections); + let trait_ref = + conv_poly_trait_ref(&ccx.icx(&(base_predicates, ast_generics)), + ty, + poly_trait_ref, + &mut projections); result.predicates.push(space, trait_ref.as_predicate()); @@ -1701,17 +1799,16 @@ fn ty_generic_bounds<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, } fn ty_generics<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, - space: subst::ParamSpace, - lifetime_defs: &[ast::LifetimeDef], - types: &[ast::TyParam], - where_clause: &ast::WhereClause, - base_generics: ty::Generics<'tcx>) + space: ParamSpace, + ast_generics: &ast::Generics, + base_generics: &ty::Generics<'tcx>) -> ty::Generics<'tcx> { let tcx = ccx.tcx; - let mut result = base_generics; + let mut result = base_generics.clone(); - for (i, l) in lifetime_defs.iter().enumerate() { + let early_lifetimes = early_bound_lifetimes_from_generics(space, ast_generics); + for (i, l) in early_lifetimes.iter().enumerate() { let bounds = l.bounds.iter() .map(|l| ast_region_to_region(tcx, l)) .collect(); @@ -1720,16 +1817,14 @@ fn ty_generics<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, index: i as u32, def_id: local_def(l.lifetime.id), bounds: bounds }; - // debug!("ty_generics: def for region param: {:?}", - // def.repr(tcx)); result.regions.push(space, def); } assert!(result.types.is_empty_in(space)); // Now create the real type parameters. - for (i, param) in types.iter().enumerate() { - let def = get_or_create_type_parameter_def(ccx, &result, space, param, i as u32); + for i in 0..ast_generics.ty_params.len() { + let def = get_or_create_type_parameter_def(ccx, ast_generics, space, i as u32); debug!("ty_generics: def for type param: {:?}, {:?}", def, space); result.types.push(space, def); } @@ -1738,13 +1833,13 @@ fn ty_generics<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, } fn get_or_create_type_parameter_def<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, - generics_so_far: &ty::Generics<'tcx>, - space: subst::ParamSpace, - param: &ast::TyParam, - index: u32, - where_clause: &ast::WhereClause) + ast_generics: &ast::Generics, + space: ParamSpace, + index: u32) -> ty::TypeParameterDef<'tcx> { + let param = &ast_generics.ty_params[index as usize]; + let tcx = ccx.tcx; match tcx.ty_param_defs.borrow().get(¶m.id) { Some(d) => { return d.clone(); } @@ -1754,7 +1849,7 @@ fn get_or_create_type_parameter_def<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, let default = match param.default { None => None, Some(ref path) => { - let ty = ast_ty_to_ty(&ccx.icx(&ty::Generics::empty()), &ExplicitRscope, &**path); + let ty = ast_ty_to_ty(&ccx.icx(&()), &ExplicitRscope, &**path); let cur_idx = index; ty::walk_ty(ty, |t| { @@ -1773,7 +1868,8 @@ fn get_or_create_type_parameter_def<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, }; let object_lifetime_default = - compute_object_lifetime_default(ccx, space, index, ¶m.bounds, where_clause); + compute_object_lifetime_default(ccx, param.id, + ¶m.bounds, &ast_generics.where_clause); let def = ty::TypeParameterDef { space: space, @@ -1795,15 +1891,14 @@ fn get_or_create_type_parameter_def<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, /// intentionally avoid just asking astconv to convert all the where /// clauses into a `ty::Predicate`. This is because that could induce /// artificial cycles. -fn compute_object_lifetime_default<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>, - space: subst::ParamSpace, - index: u32, +fn compute_object_lifetime_default<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, + param_id: ast::NodeId, param_bounds: &[ast::TyParamBound], where_clause: &ast::WhereClause) -> Option { let inline_bounds = from_bounds(ccx, param_bounds); - let where_bounds = from_predicates(ccx, space, index, &where_clause.predicates); + let where_bounds = from_predicates(ccx, param_id, &where_clause.predicates); let all_bounds: HashSet<_> = inline_bounds.into_iter() .chain(where_bounds.into_iter()) .collect(); @@ -1815,7 +1910,7 @@ fn compute_object_lifetime_default<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>, .map(ty::ObjectLifetimeDefault::Specific) }; - fn from_bounds<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>, + fn from_bounds<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, bounds: &[ast::TyParamBound]) -> Vec { @@ -1825,15 +1920,14 @@ fn compute_object_lifetime_default<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>, ast::TraitTyParamBound(..) => None, ast::RegionTyParamBound(ref lifetime) => - Some(astconv::ast_region_to_region(ccx.tcx(), lifetime)), + Some(astconv::ast_region_to_region(ccx.tcx, lifetime)), } }) .collect() } - fn from_predicates<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>, - space: subst::ParamSpace, - index: u32, + fn from_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, + param_id: ast::NodeId, predicates: &[ast::WherePredicate]) -> Vec { @@ -1842,7 +1936,7 @@ fn compute_object_lifetime_default<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>, match *predicate { ast::WherePredicate::BoundPredicate(ref data) => { if data.bound_lifetimes.len() == 0 && - is_param(ccx, &data.bounded_ty, space, index) + is_param(ccx.tcx, &data.bounded_ty, param_id) { from_bounds(ccx, &data.bounds).into_iter() } else { @@ -1857,24 +1951,6 @@ fn compute_object_lifetime_default<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>, }) .collect() } - - fn is_param(ccx: &CollectCtxt, - ast_ty: &ast::Ty, - space: subst::ParamSpace, - index: u32) - -> bool - { - if let ast::TyPath(None, _) = ast_ty.node { - let path_res = ccx.tcx.def_map.borrow()[ast_ty.id]; - if let def::DefTyParam(s, i, _, _) = path_res.base_def { - path_res.depth == 0 && space == s && index == i - } else { - false - } - } else { - false - } - } } enum SizedByDefault { Yes, No } @@ -1882,27 +1958,25 @@ enum SizedByDefault { Yes, No } /// Translate the AST's notion of ty param bounds (which are an enum consisting of a newtyped Ty or /// a region) to ty's notion of ty param bounds, which can either be user-defined traits, or the /// built-in trait (formerly known as kind): Send. -fn compute_bounds<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, - generics: &ty::Generics<'tcx>, - param_ty: ty::Ty<'tcx>, - ast_bounds: &[ast::TyParamBound], - sized_by_default: SizedByDefault, - span: Span) - -> ty::ParamBounds<'tcx> +fn compute_bounds<'tcx>(astconv: &AstConv<'tcx>, + param_ty: ty::Ty<'tcx>, + ast_bounds: &[ast::TyParamBound], + sized_by_default: SizedByDefault, + span: Span) + -> ty::ParamBounds<'tcx> { - let mut param_bounds = conv_param_bounds(ccx, - generics, + let mut param_bounds = conv_param_bounds(astconv, span, param_ty, ast_bounds); if let SizedByDefault::Yes = sized_by_default { - add_unsized_bound(ccx, + add_unsized_bound(astconv, &mut param_bounds.builtin_bounds, ast_bounds, span); - check_bounds_compatible(ccx, + check_bounds_compatible(astconv, param_ty, ¶m_bounds, span); @@ -1913,22 +1987,27 @@ fn compute_bounds<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, param_bounds } -fn check_bounds_compatible<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, - param_ty: Ty<'tcx>, - param_bounds: &ty::ParamBounds<'tcx>, - span: Span) { +fn check_bounds_compatible<'tcx>(astconv: &AstConv<'tcx>, + param_ty: Ty<'tcx>, + param_bounds: &ty::ParamBounds<'tcx>, + span: Span) { + let tcx = astconv.tcx(); if !param_bounds.builtin_bounds.contains(&ty::BoundSized) { ty::each_bound_trait_and_supertraits( - ccx.tcx, + tcx, ¶m_bounds.trait_bounds, |trait_ref| { - let trait_def = get_trait_def(ccx, trait_ref.def_id()); - if trait_def.bounds.builtin_bounds.contains(&ty::BoundSized) { - span_err!(ccx.tcx.sess, span, E0129, - "incompatible bounds on `{}`, \ - bound `{}` does not allow unsized type", - param_ty.user_string(ccx.tcx), - trait_ref.user_string(ccx.tcx)); + match astconv.get_trait_def(span, trait_ref.def_id()) { + Ok(trait_def) => { + if trait_def.bounds.builtin_bounds.contains(&ty::BoundSized) { + span_err!(tcx.sess, span, E0129, + "incompatible bounds on `{}`, \ + bound `{}` does not allow unsized type", + param_ty.user_string(tcx), + trait_ref.user_string(tcx)); + } + } + Err(ErrorReported) => { } } true }); @@ -1967,14 +2046,13 @@ fn conv_poly_trait_ref<'tcx>(astconv: &AstConv<'tcx>, projections) } -fn conv_param_bounds<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, - generics: &ty::Generics<'tcx>, +fn conv_param_bounds<'a,'tcx>(astconv: &AstConv<'tcx>, span: Span, param_ty: ty::Ty<'tcx>, ast_bounds: &[ast::TyParamBound]) -> ty::ParamBounds<'tcx> { - let tcx = ccx.tcx; + let tcx = astconv.tcx(); let astconv::PartitionedBounds { builtin_bounds, trait_bounds, @@ -1984,16 +2062,16 @@ fn conv_param_bounds<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, let mut projection_bounds = Vec::new(); let trait_bounds: Vec = - trait_bounds.into_iter() - .map(|bound| conv_poly_trait_ref(&ccx.icx(generics), + trait_bounds.iter() + .map(|bound| conv_poly_trait_ref(astconv, param_ty, - bound, + *bound, &mut projection_bounds)) .collect(); let region_bounds: Vec = region_bounds.into_iter() - .map(|r| ast_region_to_region(ccx.tcx, r)) + .map(|r| ast_region_to_region(tcx, r)) .collect(); ty::ParamBounds { @@ -2022,17 +2100,17 @@ fn compute_type_scheme_of_foreign_fn_decl<'a, 'tcx>( } } - let ty_generics = ty_generics_for_fn_or_method(ccx, ast_generics, ty::Generics::empty()); + let ty_generics = ty_generics_for_fn(ccx, ast_generics, &ty::Generics::empty()); let rb = BindingRscope::new(); let input_tys = decl.inputs .iter() - .map(|a| ty_of_arg(&ccx.icx(&ty_generics), &rb, a, None)) + .map(|a| ty_of_arg(&ccx.icx(ast_generics), &rb, a, None)) .collect(); let output = match decl.output { ast::Return(ref ty) => - ty::FnConverging(ast_ty_to_ty(&ccx.icx(&ty_generics), &rb, &**ty)), + ty::FnConverging(ast_ty_to_ty(&ccx.icx(ast_generics), &rb, &**ty)), ast::DefaultReturn(..) => ty::FnConverging(ty::mk_nil(ccx.tcx)), ast::NoReturn(..) => @@ -2058,7 +2136,7 @@ fn compute_type_scheme_of_foreign_fn_decl<'a, 'tcx>( fn mk_item_substs<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, ty_generics: &ty::Generics<'tcx>) - -> subst::Substs<'tcx> + -> Substs<'tcx> { let types = ty_generics.types.map( @@ -2068,7 +2146,7 @@ fn mk_item_substs<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, ty_generics.regions.map( |def| def.to_early_bound_region()); - subst::Substs::new(types, regions) + Substs::new(types, regions) } /// Verifies that the explicit self type of a method matches the impl @@ -2087,7 +2165,7 @@ fn check_method_self_type<'a, 'tcx, RS:RegionScope>( { let tcx = ccx.tcx; if let ast::SelfExplicit(ref ast_type, _) = explicit_self.node { - let typ = ccx.icx(&method_type.generics).to_ty(rs, &**ast_type); + let typ = ccx.icx(&method_type.predicates).to_ty(rs, &**ast_type); let base_type = match typ.sty { ty::ty_ptr(tm) | ty::ty_rptr(_, tm) => tm.ty, ty::ty_uniq(typ) => typ, diff --git a/src/test/compile-fail/associated-type-projection-ambig-between-bound-and-where-clause.rs b/src/test/compile-fail/associated-type-projection-ambig-between-bound-and-where-clause.rs new file mode 100644 index 0000000000000..ce97019a2b266 --- /dev/null +++ b/src/test/compile-fail/associated-type-projection-ambig-between-bound-and-where-clause.rs @@ -0,0 +1,52 @@ +// 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 in a where clause where the type being +// equated appears in a supertrait. + +pub trait Vehicle { + type Color; + + fn go(&self) { } +} + +pub trait Box { + type Color; + + fn mail(&self) { } +} + +fn a(_: C::Color) { + //~^ ERROR ambiguous associated type `Color` in bounds of `C` +} + +fn b(_: C::Color) where C : Vehicle+Box { + //~^ ERROR ambiguous associated type `Color` in bounds of `C` +} + +fn c(_: C::Color) where C : Vehicle, C : Box { + //~^ ERROR ambiguous associated type `Color` in bounds of `C` +} + +struct D; +impl D where X : Vehicle { + fn d(&self, _: X::Color) where X : Box { } + //~^ ERROR ambiguous associated type `Color` in bounds of `X` +} + +trait E { + fn e(&self, _: X::Color) where X : Box; + //~^ ERROR ambiguous associated type `Color` in bounds of `X` + + fn f(&self, _: X::Color) where X : Box { } + //~^ ERROR ambiguous associated type `Color` in bounds of `X` +} + +pub fn main() { } diff --git a/src/test/compile-fail/cycle-projection-based-on-where-clause.rs b/src/test/compile-fail/cycle-projection-based-on-where-clause.rs new file mode 100644 index 0000000000000..abcbf567d4436 --- /dev/null +++ b/src/test/compile-fail/cycle-projection-based-on-where-clause.rs @@ -0,0 +1,34 @@ +// Copyright 2015 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. + +// Example cycle where a bound on `T` uses a shorthand for `T`. This +// creates a cycle because we have to know the bounds on `T` to figure +// out what trait defines `Item`, but we can't know the bounds on `T` +// without knowing how to handle `T::Item`. +// +// Note that in the future cases like this could perhaps become legal, +// if we got more fine-grained about our cycle detection or changed +// how we handle `T::Item` resolution. + +use std::ops::Add; + +// Preamble. +trait Trait { type Item; } + +struct A + where T : Trait, + T : Add + //~^ ERROR illegal recursive type +{ + data: T +} + +fn main() { +} diff --git a/src/test/compile-fail/cycle-trait-supertrait-direct.rs b/src/test/compile-fail/cycle-trait-supertrait-direct.rs index 836b581d2bfb3..ef3fead18f6aa 100644 --- a/src/test/compile-fail/cycle-trait-supertrait-direct.rs +++ b/src/test/compile-fail/cycle-trait-supertrait-direct.rs @@ -11,7 +11,7 @@ // Test a supertrait cycle where a trait extends itself. trait Chromosome: Chromosome { - //~^ ERROR cyclic reference detected + //~^ ERROR unsupported cyclic reference } fn main() { } diff --git a/src/test/compile-fail/cycle-trait-supertrait-indirect.rs b/src/test/compile-fail/cycle-trait-supertrait-indirect.rs index 68553462036f2..6ebd9a1bcb6e2 100644 --- a/src/test/compile-fail/cycle-trait-supertrait-indirect.rs +++ b/src/test/compile-fail/cycle-trait-supertrait-indirect.rs @@ -15,8 +15,8 @@ trait A: B { } trait B: C { } - //~^ ERROR cyclic reference detected trait C: B { } + //~^ ERROR unsupported cyclic reference fn main() { } diff --git a/src/test/run-pass/associated-types-project-from-type-param-via-bound-in-where-clause.rs b/src/test/run-pass/associated-types-project-from-type-param-via-bound-in-where-clause.rs new file mode 100644 index 0000000000000..2243e00ffa160 --- /dev/null +++ b/src/test/run-pass/associated-types-project-from-type-param-via-bound-in-where-clause.rs @@ -0,0 +1,107 @@ +// Copyright 2015 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. + +// Various uses of `T::Item` syntax where the bound that supplies +// `Item` originates in a where-clause, not the declaration of +// `T`. Issue #20300. + +use std::marker::{MarkerTrait, PhantomData}; +use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT}; +use std::sync::atomic::Ordering::SeqCst; + +static COUNTER: AtomicUsize = ATOMIC_USIZE_INIT; + +// Preamble. +trait Trait : MarkerTrait { type Item; } +struct Struct; +impl Trait for Struct { + type Item = u32; +} + +// Where-clause attached on the method which declares `T`. +struct A; +impl A { + fn foo(_x: T::Item) where T: Trait { + COUNTER.fetch_add(1, SeqCst); + } +} + +// Where-clause attached on the method to a parameter from the struct. +struct B(PhantomData); +impl B { + fn foo(_x: T::Item) where T: Trait { + COUNTER.fetch_add(10, SeqCst); + } +} + +// Where-clause attached to free fn. +fn c(_: T::Item) where T : Trait { + COUNTER.fetch_add(100, SeqCst); +} + +// Where-clause attached to defaulted and non-defaulted trait method. +trait AnotherTrait { + fn method(&self, _: T::Item) where T: Trait; + fn default_method(&self, _: T::Item) where T: Trait { + COUNTER.fetch_add(1000, SeqCst); + } +} +struct D; +impl AnotherTrait for D { + fn method(&self, _: T::Item) where T: Trait { + COUNTER.fetch_add(10000, SeqCst); + } +} + +// Where-clause attached to trait and impl containing the method. +trait YetAnotherTrait + where T : Trait +{ + fn method(&self, _: T::Item); + fn default_method(&self, _: T::Item) { + COUNTER.fetch_add(100000, SeqCst); + } +} +struct E(PhantomData); +impl YetAnotherTrait for E + where T : Trait +{ + fn method(&self, _: T::Item) { + COUNTER.fetch_add(1000000, SeqCst); + } +} + +// Where-clause attached to inherent impl containing the method. +struct F(PhantomData); +impl F where T : Trait { + fn method(&self, _: T::Item) { + COUNTER.fetch_add(10000000, SeqCst); + } +} + +// Where-clause attached to struct. +#[allow(dead_code)] +struct G where T : Trait { + data: T::Item, + phantom: PhantomData, +} + +fn main() { + A::foo::(22); + B::::foo(22); + c::(22); + D.method::(22); + D.default_method::(22); + E(PhantomData::).method(22); + E(PhantomData::).default_method(22); + F(PhantomData::).method(22); + G:: { data: 22, phantom: PhantomData }; + assert_eq!(COUNTER.load(SeqCst), 11111111); +} diff --git a/src/test/compile-fail/cycle-generic-bound.rs b/src/test/run-pass/cycle-generic-bound.rs similarity index 68% rename from src/test/compile-fail/cycle-generic-bound.rs rename to src/test/run-pass/cycle-generic-bound.rs index 51fee683a81c9..2388a567f3043 100644 --- a/src/test/compile-fail/cycle-generic-bound.rs +++ b/src/test/run-pass/cycle-generic-bound.rs @@ -8,12 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// Regression test for #15477. This test should pass, vs reporting an -// error as it does now, but at least this test shows it doesn't -// segfault. +// Regression test for #15477. This test just needs to compile. -trait Chromosome { - //~^ ERROR cyclic reference detected +use std::marker::PhantomFn; + +trait Chromosome> : PhantomFn<(Self,X)> { } fn main() { } diff --git a/src/test/compile-fail/cycle-trait-type-trait.rs b/src/test/run-pass/cycle-trait-type-trait.rs similarity index 77% rename from src/test/compile-fail/cycle-trait-type-trait.rs rename to src/test/run-pass/cycle-trait-type-trait.rs index 912961120c21a..6e16e68610603 100644 --- a/src/test/compile-fail/cycle-trait-type-trait.rs +++ b/src/test/run-pass/cycle-trait-type-trait.rs @@ -8,10 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// Test a supertrait cycle where a trait extends itself. +// Test a case where a supertrait references a type that references +// the original trait. This poses no problem at the moment. -trait Chromosome: Get { - //~^ ERROR cyclic reference detected +trait Chromosome: Get> { } trait Get { From 31e09f740a376a6ffd1b137e665a69f9b9436e1f Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 18 Feb 2015 11:02:06 -0500 Subject: [PATCH 07/10] Add handy switch `-Z treat-err-as-bug` -- it often happens that I am compiling something I expect to succeed, and this lets me get stacktraces and also abort compilation faster. --- src/librustc/session/config.rs | 6 ++++++ src/librustc/session/mod.rs | 9 +++++++++ 2 files changed, 15 insertions(+) diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index efc12d00b10c6..efcde8b2fa1ac 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -99,6 +99,7 @@ pub struct Options { pub test: bool, pub parse_only: bool, pub no_trans: bool, + pub treat_err_as_bug: bool, pub no_analysis: bool, pub debugging_opts: DebuggingOptions, /// Whether to write dependency files. It's (enabled, optional filename). @@ -223,6 +224,7 @@ pub fn basic_options() -> Options { test: false, parse_only: false, no_trans: false, + treat_err_as_bug: false, no_analysis: false, debugging_opts: basic_debugging_options(), write_dependency_info: (false, None), @@ -573,6 +575,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "Parse only; do not compile, assemble, or link"), no_trans: bool = (false, parse_bool, "Run all passes except translation; no output"), + treat_err_as_bug: bool = (false, parse_bool, + "Treat all errors that occur as bugs"), no_analysis: bool = (false, parse_bool, "Parse and expand the source, but run no analysis"), extra_plugins: Vec = (Vec::new(), parse_list, @@ -843,6 +847,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { let parse_only = debugging_opts.parse_only; let no_trans = debugging_opts.no_trans; + let treat_err_as_bug = debugging_opts.treat_err_as_bug; let no_analysis = debugging_opts.no_analysis; if debugging_opts.debug_llvm { @@ -1030,6 +1035,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { test: test, parse_only: parse_only, no_trans: no_trans, + treat_err_as_bug: treat_err_as_bug, no_analysis: no_analysis, debugging_opts: debugging_opts, write_dependency_info: write_dependency_info, diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index b690cc7f7d06b..324ce1d66d007 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -74,18 +74,27 @@ impl Session { self.diagnostic().handler().fatal(msg) } pub fn span_err(&self, sp: Span, msg: &str) { + if self.opts.treat_err_as_bug { + self.span_bug(sp, msg); + } match split_msg_into_multilines(msg) { Some(msg) => self.diagnostic().span_err(sp, &msg[..]), None => self.diagnostic().span_err(sp, msg) } } pub fn span_err_with_code(&self, sp: Span, msg: &str, code: &str) { + if self.opts.treat_err_as_bug { + self.span_bug(sp, msg); + } match split_msg_into_multilines(msg) { Some(msg) => self.diagnostic().span_err_with_code(sp, &msg[..], code), None => self.diagnostic().span_err_with_code(sp, msg, code) } } pub fn err(&self, msg: &str) { + if self.opts.treat_err_as_bug { + self.bug(msg); + } self.diagnostic().handler().err(msg) } pub fn err_count(&self) -> uint { From eb77fe9e06994b0a541680450c287b10452ba91a Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 24 Feb 2015 11:49:50 -0500 Subject: [PATCH 08/10] Merge conflict: port default impls code --- src/librustc_typeck/collect.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 2899d8868cca0..585e7cedc4779 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -907,7 +907,7 @@ fn convert_item(ccx: &CrateCtxt, it: &ast::Item) { &enum_definition.variants); }, ast::ItemDefaultImpl(_, ref ast_trait_ref) => { - let trait_ref = astconv::instantiate_trait_ref(ccx, + let trait_ref = astconv::instantiate_trait_ref(&ccx.icx(&()), &ExplicitRscope, ast_trait_ref, Some(it.id), From abdb42ba6402e5c16c10ec19643a4da1f855d653 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 24 Feb 2015 11:50:07 -0500 Subject: [PATCH 09/10] Remove two uses of old `[]` notation --- src/librustc_typeck/coherence/overlap.rs | 2 +- src/librustc_typeck/collect.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustc_typeck/coherence/overlap.rs b/src/librustc_typeck/coherence/overlap.rs index 366e934b4ddce..a6ecafb624131 100644 --- a/src/librustc_typeck/coherence/overlap.rs +++ b/src/librustc_typeck/coherence/overlap.rs @@ -147,7 +147,7 @@ impl<'cx, 'tcx,'v> visit::Visitor<'v> for OverlapChecker<'cx, 'tcx> { None => { self.tcx.sess.bug( &format!("no default implementation recorded for `{:?}`", - item)[]); + item)); } } } diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 585e7cedc4779..737d20676848d 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1720,7 +1720,7 @@ fn ty_generic_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, let param_ty = ty::ParamTy::new(space, index, param.ident.name).to_ty(ccx.tcx); let bounds = compute_bounds(&ccx.icx(&(base_predicates, ast_generics)), param_ty, - ¶m.bounds[], + ¶m.bounds, SizedByDefault::Yes, param.span); let predicates = ty::predicates(ccx.tcx, param_ty, &bounds); From 1ef3598ed9da3222467d373bc02973e8ecffbaad Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 24 Feb 2015 16:27:02 -0500 Subject: [PATCH 10/10] Merge conflicts due to eddyb's UFCS branch --- src/librustc_typeck/astconv.rs | 16 +++++++++------- src/librustc_typeck/check/mod.rs | 2 +- src/librustc_typeck/collect.rs | 2 +- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 48928516a6022..844635117b5e9 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -688,7 +688,7 @@ fn ast_path_to_trait_ref<'a,'tcx>( -> Rc> { debug!("ast_path_to_trait_ref {:?}", trait_segment); - let trait_def = match this.get_trait_def(path.span, trait_def_id) { + let trait_def = match this.get_trait_def(span, trait_def_id) { Ok(trait_def) => trait_def, Err(ErrorReported) => { // No convenient way to recover from a cycle here. Just bail. Sorry! @@ -873,17 +873,19 @@ fn ast_path_to_ty<'tcx>( -> Ty<'tcx> { let tcx = this.tcx(); - let substs = match this.get_item_type_scheme(path.span, did) { + let (generics, decl_ty) = match this.get_item_type_scheme(span, did) { Ok(ty::TypeScheme { generics, ty: decl_ty }) => { - ast_path_substs_for_ty(this, rscope, - span, param_mode, - &generics, item_segment) + (generics, decl_ty) } Err(ErrorReported) => { - return TypeAndSubsts { substs: Substs::empty(), ty: tcx.types.err }; + return tcx.types.err; } }; + let substs = ast_path_substs_for_ty(this, rscope, + span, param_mode, + &generics, item_segment); + // FIXME(#12938): This is a hack until we have full support for DST. if Some(did) == this.tcx().lang_items.owned_box() { assert_eq!(substs.types.len(TypeSpace), 1); @@ -1020,7 +1022,7 @@ fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>, // FIXME(#20300) -- search where clauses, not bounds let bounds = - this.get_type_parameter_bounds(ast_ty.span, ty_param_ndoe_id) + this.get_type_parameter_bounds(span, ty_param_node_id) .unwrap_or(Vec::new()); let mut suitable_bounds: Vec<_> = diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 43edb4f09cc12..fd6ba79ec21bb 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -3637,7 +3637,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, } } else { tcx.sess.span_bug(expr.span, - &format!("unbound path {}", expr.repr(tcx))[]) + &format!("unbound path {}", expr.repr(tcx))) }; let mut def = path_res.base_def; diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 737d20676848d..74fed6cbf3937 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -504,7 +504,7 @@ fn is_param<'tcx>(tcx: &ty::ctxt<'tcx>, -> bool { if let ast::TyPath(None, _) = ast_ty.node { - let path_res = ccx.tcx.def_map.borrow()[ast_ty.id]; + let path_res = tcx.def_map.borrow()[ast_ty.id]; if let def::DefTyParam(_, _, def_id, _) = path_res.base_def { path_res.depth == 0 && def_id == local_def(param_id) } else {