From 3764699c83387df254f220b4c85121010413aeff Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 11 Feb 2015 10:25:52 -0500 Subject: [PATCH] Refactor collect to separate out the computation of the type scheme and predicates. Try to document how things work. More cleanup is needed here but I had to draw the line somewhere gosh darn it. --- src/librustc_typeck/collect.rs | 1018 +++++++++++++++++++------------- 1 file changed, 606 insertions(+), 412 deletions(-) diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 55fa47760bb..3ee3eb87b95 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -20,28 +20,83 @@ current crate: we assume that after the collect phase, the types of all local items will be present in the table. Unlike most of the types that are present in Rust, the types computed -for each item are in fact polytypes. In "layman's terms", this means -that they are generic types that may have type parameters (more -mathematically phrased, they are universally quantified over a set of -type parameters). TypeSchemes are represented by an instance of -`ty::TypeScheme`. This combines the core type along with a list of the -bounds for each parameter. Type parameters themselves are represented -as `ty_param()` instances. +for each item are in fact type schemes. This means that they are +generic types that may have type parameters. TypeSchemes are +represented by an instance of `ty::TypeScheme`. This combines the +core type along with a list of the bounds for each parameter. Type +parameters themselves are represented as `ty_param()` instances. + +The phasing of type conversion is somewhat complicated. There are a +number of possible cycles that can arise. + +Converting types can require: + +1. `Foo` where `Foo` is a type alias, or trait requires knowing: + - number of region / type parameters + - for type parameters, `T:'a` annotations to control defaults for object lifetimes + - defaults for type parameters (which are themselves types!) +2. `Foo` where `Foo` is a type alias requires knowing what `Foo` expands to +3. Translating `SomeTrait` with no explicit lifetime bound requires knowing + - supertraits of `SomeTrait` +4. Translating `T::X` (vs `::X`) requires knowing + - bounds on `T` + - supertraits of those bounds + +So as you can see, in general translating types requires knowing the +trait hierarchy. But this gets a bit tricky because translating the +trait hierarchy requires convering the types that appear in trait +references. One potential saving grace is that in general knowing the +trait hierarchy is only necessary for shorthands like `T::X` or +handling omitted lifetime bounds on object types. Therefore, if we are +lazy about expanding out the trait hierachy, users can sever cycles if +necessary. Lazy expansion is also needed for type aliases. + +This system is not perfect yet. Currently, we "convert" types and +traits in three phases (note that conversion only affects the types of +items / enum variants / methods; it does not e.g. compute the types of +individual expressions): + +0. Intrinsics +1. Trait definitions +2. Type definitions + +Conversion itself is done by simply walking each of the items in turn +and invoking an appropriate function (e.g., `trait_def_of_item` or +`convert_item`). However, it is possible that while converting an +item, we may need to compute the *type scheme* or *trait definition* +for other items. This is a kind of shallow conversion that is +triggered on demand by calls to `AstConv::get_item_type_scheme` or +`AstConv::lookup_trait_def`. It is possible for cycles to result from +this (e.g., `type A = B; type B = A;`), in which case astconv +(currently) reports the error. + +There are some shortcomings in this design: + +- Cycles through trait definitions (e.g. supertraits) are not currently + detected by astconv. (#12511) +- Because the type scheme includes defaults, cycles through type + parameter defaults are illegal even if those defaults are never + employed. This is not necessarily a bug. +- The phasing of trait definitions before type definitions does not + seem to be necessary, sufficient, or particularly helpful, given that + processing a trait definition can trigger processing a type def and + vice versa. However, if I remove it, I get ICEs, so some more work is + needed in that area. -nmatsakis */ + use astconv::{self, AstConv, ty_of_arg, ast_ty_to_ty, ast_region_to_region}; -use metadata::csearch; use middle::lang_items::SizedTraitLangItem; use middle::region; use middle::resolve_lifetime; use middle::subst; -use middle::subst::{Substs, TypeSpace}; +use middle::subst::{Substs, SelfSpace, TypeSpace, VecPerParamSpace}; use middle::ty::{AsPredicate, ImplContainer, ImplOrTraitItemContainer, TraitContainer}; use middle::ty::{self, RegionEscape, Ty, TypeScheme}; use middle::ty_fold::{self, TypeFolder, TypeFoldable}; use middle::infer; -use no_params; use rscope::*; +use util::common::memoized; use util::nodemap::{FnvHashMap, FnvHashSet}; use util::ppaux; use util::ppaux::{Repr,UserString}; @@ -130,11 +185,11 @@ struct CollectItemTypesVisitor<'a, 'tcx: 'a> { impl<'a, 'tcx, 'v> visit::Visitor<'v> for CollectItemTypesVisitor<'a, 'tcx> { fn visit_item(&mut self, i: &ast::Item) { - convert(self.ccx, i); + convert_item(self.ccx, i); visit::walk_item(self, i); } fn visit_foreign_item(&mut self, i: &ast::ForeignItem) { - convert_foreign(self.ccx, i); + convert_foreign_item(self.ccx, i); visit::walk_foreign_item(self, i); } } @@ -157,16 +212,16 @@ impl<'a, 'tcx> AstConv<'tcx> for CollectCtxt<'a, 'tcx> { fn get_item_type_scheme(&self, id: ast::DefId) -> ty::TypeScheme<'tcx> { if id.krate != ast::LOCAL_CRATE { - return csearch::get_type(self.tcx, id) + return ty::lookup_item_type(self.tcx, id); } match self.tcx.map.find(id.node) { Some(ast_map::NodeItem(item)) => { - ty_of_item(self, &*item) + type_scheme_of_item(self, &*item) } Some(ast_map::NodeForeignItem(foreign_item)) => { let abi = self.tcx.map.get_foreign_abi(id.node); - ty_of_foreign_item(self, &*foreign_item, abi) + type_scheme_of_foreign_item(self, &*foreign_item, abi) } x => { self.tcx.sess.bug(&format!("unexpected sort of node \ @@ -181,7 +236,7 @@ impl<'a, 'tcx> AstConv<'tcx> for CollectCtxt<'a, 'tcx> { } fn ty_infer(&self, span: Span) -> Ty<'tcx> { - span_err!(self.tcx.sess, span, E0121, + span_err!(self.tcx().sess, span, E0121, "the type placeholder `_` is not allowed within types on item signatures"); self.tcx().types.err } @@ -192,14 +247,14 @@ impl<'a, 'tcx> AstConv<'tcx> for CollectCtxt<'a, 'tcx> { item_name: ast::Name) -> Ty<'tcx> { - ty::mk_projection(self.tcx, trait_ref, item_name) + ty::mk_projection(self.tcx(), trait_ref, item_name) } } fn get_enum_variant_types<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, - enum_ty: Ty<'tcx>, - variants: &[P], - generics: &ast::Generics) { + enum_scheme: ty::TypeScheme<'tcx>, + enum_predicates: ty::GenericPredicates<'tcx>, + variants: &[P]) { let tcx = ccx.tcx; // Create a set of parameter types shared among all the variants. @@ -212,38 +267,35 @@ fn get_enum_variant_types<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, 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_ty) + ty::mk_ctor_fn(tcx, variant_def_id, &input_tys[], enum_scheme.ty) } ast::TupleVariantKind(_) => { - enum_ty + enum_scheme.ty } ast::StructVariantKind(ref struct_def) => { - let scheme = TypeScheme { - generics: ty_generics_for_type_or_impl(ccx, generics), - ty: enum_ty - }; - - convert_struct(ccx, &**struct_def, scheme, variant.node.id); - enum_ty + convert_struct(ccx, &**struct_def, enum_scheme.clone(), + enum_predicates.clone(), variant.node.id); + enum_scheme.ty } }; - let scheme = TypeScheme { - generics: ty_generics_for_type_or_impl(ccx, generics), + let variant_scheme = TypeScheme { + generics: enum_scheme.generics.clone(), ty: result_ty }; - tcx.tcache.borrow_mut().insert(variant_def_id, scheme); - + tcx.tcache.borrow_mut().insert(variant_def_id, variant_scheme.clone()); + tcx.predicates.borrow_mut().insert(variant_def_id, enum_predicates.clone()); write_ty_to_tcx(tcx, variant.node.id, result_ty); } } fn collect_trait_methods<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, trait_id: ast::NodeId, - trait_def: &ty::TraitDef<'tcx>) { + trait_def: &ty::TraitDef<'tcx>, + trait_predicates: &ty::GenericPredicates<'tcx>) { let tcx = ccx.tcx; if let ast_map::NodeItem(item) = tcx.map.get(trait_id) { if let ast::ItemTrait(_, _, _, ref trait_items) = item.node { @@ -259,6 +311,7 @@ fn collect_trait_methods<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, ccx, trait_id, &trait_def.generics, + &trait_predicates, &trait_items[], &m.id, &m.ident.name, @@ -273,6 +326,7 @@ fn collect_trait_methods<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, ccx, trait_id, &trait_def.generics, + &trait_predicates, &trait_items[], &m.id, &m.pe_ident().name, @@ -342,12 +396,17 @@ fn collect_trait_methods<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, m.def_id, TypeScheme { generics: m.generics.clone(), - ty: ty::mk_bare_fn(ccx.tcx, Some(m.def_id), ccx.tcx.mk_bare_fn(m.fty.clone())) }); + ty: ty::mk_bare_fn(ccx.tcx, Some(m.def_id), ccx.tcx.mk_bare_fn(m.fty.clone())) + }); + ccx.tcx.predicates.borrow_mut().insert( + m.def_id, + m.predicates.clone()); } fn ty_method_of_trait_method<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, trait_id: ast::NodeId, trait_generics: &ty::Generics<'tcx>, + trait_bounds: &ty::GenericPredicates<'tcx>, _trait_items: &[ast::TraitItem], m_id: &ast::NodeId, m_name: &ast::Name, @@ -358,10 +417,15 @@ fn collect_trait_methods<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, m_decl: &ast::FnDecl) -> ty::Method<'tcx> { let ty_generics = - ty_generics_for_fn_or_method( - ccx, - m_generics, - (*trait_generics).clone()); + ty_generics_for_fn_or_method(ccx, + m_generics, + trait_generics.clone()); + + let ty_bounds = + ty_generic_bounds_for_fn_or_method(ccx, + m_generics, + &ty_generics, + trait_bounds.clone()); let (fty, explicit_self_category) = { let trait_self_ty = ty::mk_self_type(ccx.tcx); @@ -376,6 +440,7 @@ fn collect_trait_methods<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, ty::Method::new( *m_name, ty_generics, + ty_bounds, fty, explicit_self_category, // assume public, because this is only invoked on trait methods @@ -389,16 +454,20 @@ 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); write_ty_to_tcx(ccx.tcx, v.node.id, tt); + /* add the field to the tcache */ ccx.tcx.tcache.borrow_mut().insert(local_def(v.node.id), ty::TypeScheme { generics: struct_generics.clone(), ty: tt }); + ccx.tcx.predicates.borrow_mut().insert(local_def(v.node.id), + struct_predicates.clone()); match v.node.kind { ast::NamedField(ident, visibility) => { @@ -442,6 +511,7 @@ fn convert_methods<'a,'tcx,'i,I>(ccx: &CollectCtxt<'a, 'tcx>, ms: I, untransformed_rcvr_ty: Ty<'tcx>, rcvr_ty_generics: &ty::Generics<'tcx>, + rcvr_ty_predicates: &ty::GenericPredicates<'tcx>, rcvr_visibility: ast::Visibility) where I: Iterator { debug!("convert_methods(untransformed_rcvr_ty={}, rcvr_ty_generics={})", @@ -456,11 +526,13 @@ fn convert_methods<'a,'tcx,'i,I>(ccx: &CollectCtxt<'a, 'tcx>, } let m_def_id = local_def(m.id); + let mty = Rc::new(ty_of_method(ccx, container, m, untransformed_rcvr_ty, rcvr_ty_generics, + rcvr_ty_predicates, rcvr_visibility)); let fty = ty::mk_bare_fn(tcx, Some(m_def_id), tcx.mk_bare_fn(mty.fty.clone())); debug!("method {} (id {}) has type {}", @@ -473,6 +545,7 @@ fn convert_methods<'a,'tcx,'i,I>(ccx: &CollectCtxt<'a, 'tcx>, generics: mty.generics.clone(), ty: fty }); + tcx.predicates.borrow_mut().insert(m_def_id, mty.predicates.clone()); write_ty_to_tcx(tcx, m.id, fty); @@ -489,13 +562,19 @@ fn convert_methods<'a,'tcx,'i,I>(ccx: &CollectCtxt<'a, 'tcx>, m: &ast::Method, untransformed_rcvr_ty: Ty<'tcx>, rcvr_ty_generics: &ty::Generics<'tcx>, + rcvr_ty_predicates: &ty::GenericPredicates<'tcx>, rcvr_visibility: ast::Visibility) -> ty::Method<'tcx> { let m_ty_generics = - ty_generics_for_fn_or_method( - ccx, - m.pe_generics(), - (*rcvr_ty_generics).clone()); + 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, m.pe_unsafety(), @@ -512,6 +591,7 @@ fn convert_methods<'a,'tcx,'i,I>(ccx: &CollectCtxt<'a, 'tcx>, ty::Method::new(m.pe_ident().name, m_ty_generics, + m_ty_bounds, fty, explicit_self_category, method_vis, @@ -550,20 +630,21 @@ fn ensure_no_ty_param_bounds(ccx: &CollectCtxt, } } -fn convert(ccx: &CollectCtxt, it: &ast::Item) { +fn convert_item(ccx: &CollectCtxt, it: &ast::Item) { let tcx = ccx.tcx; debug!("convert: item {} with id {}", token::get_ident(it.ident), it.id); match it.node { // These don't define types. ast::ItemExternCrate(_) | ast::ItemUse(_) | - ast::ItemForeignMod(_) | ast::ItemMod(_) | ast::ItemMac(_) => {} - ast::ItemEnum(ref enum_definition, ref generics) => { - let scheme = ty_of_item(ccx, it); + ast::ItemForeignMod(_) | ast::ItemMod(_) | ast::ItemMac(_) => { + } + ast::ItemEnum(ref enum_definition, _) => { + let (scheme, predicates) = convert_typed_item(ccx, it); write_ty_to_tcx(tcx, it.id, scheme.ty); get_enum_variant_types(ccx, - scheme.ty, - &enum_definition.variants, - generics); + scheme, + predicates, + &enum_definition.variants); }, ast::ItemImpl(_, _, ref generics, @@ -571,18 +652,21 @@ fn convert(ccx: &CollectCtxt, it: &ast::Item) { ref selfty, ref impl_items) => { // Create generics from the generics specified in the impl head. + + 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); + + debug!("convert: impl_bounds={:?}", ty_predicates); let selfty = ccx.to_ty(&ExplicitRscope, &**selfty); write_ty_to_tcx(tcx, it.id, selfty); - tcx.tcache - .borrow_mut() - .insert(local_def(it.id), - TypeScheme { - generics: ty_generics.clone(), - ty: selfty, - }); + tcx.tcache.borrow_mut().insert(local_def(it.id), + TypeScheme { generics: ty_generics.clone(), + ty: selfty }); + tcx.predicates.borrow_mut().insert(local_def(it.id), + ty_predicates.clone()); // If there is a trait reference, treat the methods as always public. // This is to work around some incorrect behavior in privacy checking: @@ -614,14 +698,14 @@ fn convert(ccx: &CollectCtxt, it: &ast::Item) { } let typ = ccx.to_ty(&ExplicitRscope, &*typedef.typ); - tcx.tcache - .borrow_mut() - .insert(local_def(typedef.id), - TypeScheme { - generics: ty::Generics::empty(), - ty: typ, - }); - write_ty_to_tcx(ccx.tcx, typedef.id, typ); + tcx.tcache.borrow_mut().insert(local_def(typedef.id), + TypeScheme { + generics: ty::Generics::empty(), + ty: typ, + }); + tcx.predicates.borrow_mut().insert(local_def(typedef.id), + ty::GenericPredicates::empty()); + write_ty_to_tcx(tcx, typedef.id, typ); let associated_type = Rc::new(ty::AssociatedType { name: typedef.ident.name, @@ -642,6 +726,7 @@ fn convert(ccx: &CollectCtxt, it: &ast::Item) { methods.into_iter(), selfty, &ty_generics, + &ty_predicates, parent_visibility); if let Some(ref trait_ref) = *opt_trait_ref { @@ -652,16 +737,16 @@ fn convert(ccx: &CollectCtxt, it: &ast::Item) { None); } - enforce_impl_ty_params_are_constrained(ccx.tcx, + enforce_impl_ty_params_are_constrained(tcx, generics, local_def(it.id)); }, ast::ItemTrait(_, _, _, ref trait_methods) => { 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!("trait_def: ident={} trait_def={}", - it.ident.repr(ccx.tcx), - trait_def.repr(ccx.tcx)); + debug!("convert: trait_bounds={:?}", trait_predicates); for trait_method in trait_methods { let self_type = ty::mk_self_type(tcx); @@ -700,47 +785,46 @@ fn convert(ccx: &CollectCtxt, it: &ast::Item) { }), 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); + collect_trait_methods(ccx, it.id, &*trait_def, &trait_predicates); }, ast::ItemStruct(ref struct_def, _) => { // Write the class type. - let scheme = ty_of_item(ccx, it); + let (scheme, predicates) = convert_typed_item(ccx, it); write_ty_to_tcx(tcx, it.id, scheme.ty); - - tcx.tcache.borrow_mut().insert(local_def(it.id), scheme.clone()); - - convert_struct(ccx, &**struct_def, scheme, it.id); + convert_struct(ccx, &**struct_def, scheme, predicates, it.id); }, ast::ItemTy(_, ref generics) => { ensure_no_ty_param_bounds(ccx, it.span, generics, "type"); - let tpt = ty_of_item(ccx, it); - write_ty_to_tcx(tcx, it.id, tpt.ty); + let (scheme, _) = convert_typed_item(ccx, it); + write_ty_to_tcx(tcx, it.id, scheme.ty); }, _ => { // This call populates the type cache with the converted type // of the item in passing. All we have to do here is to write // it into the node type table. - let scheme = ty_of_item(ccx, it); + let (scheme, _) = convert_typed_item(ccx, it); write_ty_to_tcx(tcx, it.id, scheme.ty); }, } } fn convert_struct<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, - struct_def: &ast::StructDef, - scheme: ty::TypeScheme<'tcx>, - id: ast::NodeId) { + struct_def: &ast::StructDef, + scheme: ty::TypeScheme<'tcx>, + predicates: ty::GenericPredicates<'tcx>, + id: ast::NodeId) { let tcx = ccx.tcx; // Write the type of each of the members and check for duplicate fields. let mut seen_fields: FnvHashMap = FnvHashMap(); let field_tys = struct_def.fields.iter().map(|f| { - let result = convert_field(ccx, &scheme.generics, f, local_def(id)); + let result = convert_field(ccx, &scheme.generics, &predicates, f, local_def(id)); if result.name != special_idents::unnamed_field.name { let dup = match seen_fields.get(&result.name) { @@ -778,6 +862,7 @@ fn convert_struct<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, write_ty_to_tcx(tcx, ctor_id, selfty); tcx.tcache.borrow_mut().insert(local_def(ctor_id), scheme); + tcx.predicates.borrow_mut().insert(local_def(ctor_id), predicates); } else if struct_def.fields[0].node.kind.is_unnamed() { // Tuple-like. let inputs: Vec<_> = struct_def.fields.iter().map( @@ -789,44 +874,30 @@ fn convert_struct<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, selfty); write_ty_to_tcx(tcx, ctor_id, ctor_fn_ty); tcx.tcache.borrow_mut().insert(local_def(ctor_id), - TypeScheme { - generics: scheme.generics, - ty: ctor_fn_ty - }); + TypeScheme { + generics: scheme.generics, + ty: ctor_fn_ty + }); + tcx.predicates.borrow_mut().insert(local_def(ctor_id), predicates); } } } } -fn convert_foreign(ccx: &CollectCtxt, i: &ast::ForeignItem) { - // As above, this call populates the type table with the converted - // type of the foreign item. We simply write it into the node type - // table. - - // For reasons I cannot fully articulate, I do so hate the AST - // map, and I regard each time that I use it as a personal and - // moral failing, but at the moment it seems like the only - // convenient way to extract the ABI. - ndm - let abi = ccx.tcx.map.get_foreign_abi(i.id); - - let scheme = ty_of_foreign_item(ccx, i, abi); - write_ty_to_tcx(ccx.tcx, i.id, scheme.ty); - - ccx.tcx.tcache.borrow_mut().insert(local_def(i.id), scheme); -} - fn get_trait_def<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, trait_id: ast::DefId) -> Rc> { + let tcx = ccx.tcx; + if trait_id.krate != ast::LOCAL_CRATE { - return ty::lookup_trait_def(ccx.tcx, trait_id) + return ty::lookup_trait_def(tcx, trait_id) } - match ccx.tcx.map.get(trait_id.node) { + match tcx.map.get(trait_id.node) { ast_map::NodeItem(item) => trait_def_of_item(ccx, &*item), _ => { - ccx.tcx.sess.bug(&format!("get_trait_def({}): not an item", - trait_id.node)[]) + tcx.sess.bug(&format!("get_trait_def({}): not an item", + trait_id.node)[]) } } } @@ -837,6 +908,7 @@ fn trait_def_of_item<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, { let def_id = local_def(it.id); let tcx = ccx.tcx; + if let Some(def) = tcx.trait_defs.borrow().get(&def_id) { return def.clone(); } @@ -868,16 +940,13 @@ fn trait_def_of_item<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, let substs = ccx.tcx.mk_substs(mk_trait_substs(ccx, generics)); - let ty_generics = ty_generics_for_trait(ccx, - it.id, - substs, - generics, - items); + let ty_generics = ty_generics_for_trait(ccx, it.id, substs, generics); - let self_param_ty = ty::ParamTy::for_self(); + let self_param_ty = ty::ParamTy::for_self().to_ty(ccx.tcx); + // supertraits: let bounds = compute_bounds(ccx, - self_param_ty.to_ty(ccx.tcx), + self_param_ty, bounds, SizedByDefault::No, it.span); @@ -890,11 +959,11 @@ fn trait_def_of_item<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, ast::TypeTraitItem(ref data) => Some(data.ty_param.ident.name), } }) - .collect(); + .collect(); let trait_ref = Rc::new(ty::TraitRef { def_id: def_id, - substs: substs + substs: substs, }); let trait_def = Rc::new(ty::TraitDef { @@ -905,6 +974,7 @@ fn trait_def_of_item<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, trait_ref: trait_ref, associated_type_names: associated_type_names, }); + tcx.trait_defs.borrow_mut().insert(def_id, trait_def.clone()); return trait_def; @@ -913,6 +983,8 @@ fn trait_def_of_item<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, generics: &ast::Generics) -> subst::Substs<'tcx> { + let tcx = ccx.tcx; + // Creates a no-op substitution for the trait's type parameters. let regions = generics.lifetimes @@ -929,191 +1001,66 @@ fn trait_def_of_item<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, generics.ty_params .iter() .enumerate() - .map(|(i, def)| ty::mk_param(ccx.tcx, subst::TypeSpace, + .map(|(i, def)| ty::mk_param(tcx, subst::TypeSpace, i as u32, def.ident.name)) .collect(); // ...and also create the `Self` parameter. - let self_ty = ty::mk_self_type(ccx.tcx); + let self_ty = ty::mk_self_type(tcx); subst::Substs::new_trait(types, regions, self_ty) } } -fn ty_of_item<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, it: &ast::Item) - -> ty::TypeScheme<'tcx> { - let def_id = local_def(it.id); +fn convert_trait_predicates<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, it: &ast::Item) { let tcx = ccx.tcx; - if let Some(scheme) = tcx.tcache.borrow().get(&def_id) { - return scheme.clone(); - } - match it.node { - ast::ItemStatic(ref t, _, _) | ast::ItemConst(ref t, _) => { - let typ = ccx.to_ty(&ExplicitRscope, &**t); - let scheme = no_params(typ); + let trait_def = trait_def_of_item(ccx, it); - tcx.tcache.borrow_mut().insert(local_def(it.id), scheme.clone()); - return scheme; + let def_id = local_def(it.id); + + let (generics, items) = match it.node { + ast::ItemTrait(_, ref generics, _, ref items) => (generics, items), + ref s => { + tcx.sess.span_bug( + it.span, + &format!("trait_def_of_item invoked on {:?}", s)[]); } - 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 scheme = TypeScheme { - generics: ty_generics, - ty: ty::mk_bare_fn(ccx.tcx, Some(local_def(it.id)), ccx.tcx.mk_bare_fn(tofd)) - }; - debug!("type of {} (id {}) is {}", - token::get_ident(it.ident), - it.id, - scheme.repr(tcx)); - - ccx.tcx.tcache.borrow_mut().insert(local_def(it.id), scheme.clone()); - return scheme; - } - ast::ItemTy(ref t, ref generics) => { - match tcx.tcache.borrow_mut().get(&local_def(it.id)) { - Some(scheme) => return scheme.clone(), - None => { } - } - - let scheme = { - let ty = ccx.to_ty(&ExplicitRscope, &**t); - TypeScheme { - generics: ty_generics_for_type_or_impl(ccx, generics), - ty: ty - } - }; - - tcx.tcache.borrow_mut().insert(local_def(it.id), scheme.clone()); - return scheme; - } - ast::ItemEnum(_, ref generics) => { - // Create a new generic polytype. - let ty_generics = ty_generics_for_type_or_impl(ccx, generics); - let substs = mk_item_substs(ccx, &ty_generics); - let t = ty::mk_enum(tcx, local_def(it.id), tcx.mk_substs(substs)); - let scheme = TypeScheme { - generics: ty_generics, - ty: t - }; - - tcx.tcache.borrow_mut().insert(local_def(it.id), scheme.clone()); - return scheme; - } - ast::ItemTrait(..) => { - tcx.sess.span_bug(it.span, "invoked ty_of_item on trait"); - } - ast::ItemStruct(_, ref generics) => { - let ty_generics = ty_generics_for_type_or_impl(ccx, generics); - let substs = mk_item_substs(ccx, &ty_generics); - let t = ty::mk_struct(tcx, local_def(it.id), tcx.mk_substs(substs)); - let scheme = TypeScheme { - generics: ty_generics, - ty: t - }; - - tcx.tcache.borrow_mut().insert(local_def(it.id), scheme.clone()); - return scheme; - } - ast::ItemExternCrate(_) | ast::ItemUse(_) | - ast::ItemImpl(..) | ast::ItemMod(_) | - ast::ItemForeignMod(_) | ast::ItemMac(_) => panic!(), - } -} - -fn ty_of_foreign_item<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, - it: &ast::ForeignItem, - abi: abi::Abi) -> ty::TypeScheme<'tcx> -{ - match it.node { - ast::ForeignItemFn(ref fn_decl, ref generics) => { - ty_of_foreign_fn_decl(ccx, - &**fn_decl, - local_def(it.id), - generics, - abi) - } - ast::ForeignItemStatic(ref t, _) => { - ty::TypeScheme { - generics: ty::Generics::empty(), - ty: ast_ty_to_ty(ccx, &ExplicitRscope, &**t) - } - } - } -} - -fn ty_generics_for_type_or_impl<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, - generics: &ast::Generics) - -> ty::Generics<'tcx> { - ty_generics(ccx, - subst::TypeSpace, - &generics.lifetimes[], - &generics.ty_params[], - ty::Generics::empty(), - &generics.where_clause) -} - -fn ty_generics_for_trait<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, - trait_id: ast::NodeId, - substs: &'tcx subst::Substs<'tcx>, - ast_generics: &ast::Generics, - trait_items: &[ast::TraitItem]) - -> 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[], - ty::Generics::empty(), - &ast_generics.where_clause); - - // Add in the self type parameter. - // - // Something of a hack: use the node id for the trait, also as - // 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 }; - ccx.tcx.ty_param_defs.borrow_mut().insert(param_id, def.clone()); + let self_param_ty = ty::ParamTy::for_self().to_ty(ccx.tcx); - generics.types.push(subst::SelfSpace, def); + let super_predicates = ty::predicates(ccx.tcx, self_param_ty, &trait_def.bounds); - generics.predicates.push(subst::SelfSpace, self_trait_ref.as_predicate()); + let assoc_predicates = predicates_for_associated_types(ccx, &trait_def.trait_ref, items); - let assoc_predicates = predicates_for_associated_types(ccx, - &self_trait_ref, - trait_items); + // `ty_generic_bounds` 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 + // associated types. + let mut base_predicates = + ty::GenericPredicates { + predicates: VecPerParamSpace::new(super_predicates, vec![], vec![]) + }; + base_predicates.predicates.extend(subst::TypeSpace, assoc_predicates.into_iter()); - debug!("ty_generics_for_trait: assoc_predicates={}", assoc_predicates.repr(ccx.tcx)); + 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()); - for assoc_predicate in assoc_predicates { - generics.predicates.push(subst::TypeSpace, assoc_predicate); - } + // add in the explicit where-clauses + let trait_predicates = + ty_generic_bounds(ccx, + subst::TypeSpace, + &trait_def.generics, + base_predicates, + &generics.where_clause); - return generics; + let prev_predicates = tcx.predicates.borrow_mut().insert(def_id, trait_predicates); + assert!(prev_predicates.is_none()); + + return; fn predicates_for_associated_types<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, self_trait_ref: &Rc>, @@ -1146,6 +1093,244 @@ fn ty_generics_for_trait<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, } } +fn type_scheme_of_item<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>, + it: &ast::Item) + -> ty::TypeScheme<'tcx> +{ + memoized(&ccx.tcx.tcache, + local_def(it.id), + |_| compute_type_scheme_of_item(ccx, it)) +} + + +fn compute_type_scheme_of_item<'a,'tcx>(ccx: &CollectCtxt<'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); + 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 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); + ty::TypeScheme { ty: ty, generics: ty_generics } + } + ast::ItemEnum(_, ref generics) => { + // Create a new generic polytype. + let ty_generics = ty_generics_for_type_or_impl(ccx, generics); + let substs = mk_item_substs(ccx, &ty_generics); + let t = ty::mk_enum(tcx, local_def(it.id), tcx.mk_substs(substs)); + ty::TypeScheme { ty: t, generics: ty_generics } + } + ast::ItemStruct(_, ref generics) => { + let ty_generics = ty_generics_for_type_or_impl(ccx, generics); + let substs = mk_item_substs(ccx, &ty_generics); + let t = ty::mk_struct(tcx, local_def(it.id), tcx.mk_substs(substs)); + ty::TypeScheme { ty: t, generics: ty_generics } + } + ast::ItemTrait(..) | + ast::ItemImpl(..) | + ast::ItemMod(..) | + ast::ItemForeignMod(..) | + ast::ItemExternCrate(..) | + ast::ItemUse(..) | + ast::ItemMac(..) => { + tcx.sess.span_bug( + it.span, + format!("compute_type_scheme_of_item: unexpected item type: {:?}", + it.node).as_slice()); + } + } +} + +fn convert_typed_item<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, + it: &ast::Item) + -> (ty::TypeScheme<'tcx>, ty::GenericPredicates<'tcx>) +{ + let tcx = ccx.tcx; + + let tag = type_scheme_of_item(ccx, it); + let scheme = TypeScheme { generics: tag.generics, ty: tag.ty }; + let predicates = match it.node { + ast::ItemStatic(..) | ast::ItemConst(..) => { + ty::GenericPredicates::empty() + } + ast::ItemFn(_, _, _, ref ast_generics, _) => { + ty_generic_bounds_for_fn_or_method(ccx, + ast_generics, + &scheme.generics, + ty::GenericPredicates::empty()) + } + ast::ItemTy(_, ref generics) => { + ty_generic_bounds_for_type_or_impl(ccx, &scheme.generics, generics) + } + ast::ItemEnum(_, ref generics) => { + ty_generic_bounds_for_type_or_impl(ccx, &scheme.generics, generics) + } + ast::ItemStruct(_, ref generics) => { + ty_generic_bounds_for_type_or_impl(ccx, &scheme.generics, generics) + } + ast::ItemTrait(..) | + ast::ItemExternCrate(..) | + ast::ItemUse(..) | + ast::ItemImpl(..) | + ast::ItemMod(..) | + ast::ItemForeignMod(..) | + ast::ItemMac(..) => { + tcx.sess.span_bug( + it.span, + format!("compute_type_scheme_of_item: unexpected item type: {:?}", + it.node).as_slice()); + } + }; + + let prev_predicates = tcx.predicates.borrow_mut().insert(local_def(it.id), + predicates.clone()); + assert!(prev_predicates.is_none()); + + return (scheme, predicates); + +} + +fn type_scheme_of_foreign_item<'a, 'tcx>( + ccx: &CollectCtxt<'a, 'tcx>, + it: &ast::ForeignItem, + abi: abi::Abi) + -> ty::TypeScheme<'tcx> +{ + 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>, + it: &ast::ForeignItem, + abi: abi::Abi) + -> ty::TypeScheme<'tcx> +{ + match it.node { + ast::ForeignItemFn(ref fn_decl, ref generics) => { + compute_type_scheme_of_foreign_fn_decl(ccx, fn_decl, generics, abi) + } + ast::ForeignItemStatic(ref t, _) => { + ty::TypeScheme { + generics: ty::Generics::empty(), + ty: ast_ty_to_ty(ccx, &ExplicitRscope, t) + } + } + } +} + +fn convert_foreign_item<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, + it: &ast::ForeignItem) +{ + // For reasons I cannot fully articulate, I do so hate the AST + // map, and I regard each time that I use it as a personal and + // moral failing, but at the moment it seems like the only + // convenient way to extract the ABI. - ndm + let tcx = ccx.tcx; + let abi = tcx.map.get_foreign_abi(it.id); + + let scheme = type_scheme_of_foreign_item(ccx, it, abi); + write_ty_to_tcx(ccx.tcx, it.id, scheme.ty); + + let predicates = match it.node { + ast::ForeignItemFn(_, ref generics) => { + ty_generic_bounds_for_fn_or_method(ccx, + generics, + &scheme.generics, + ty::GenericPredicates::empty()) + } + ast::ForeignItemStatic(..) => { + ty::GenericPredicates::empty() + } + }; + + let prev_predicates = tcx.predicates.borrow_mut().insert(local_def(it.id), predicates); + assert!(prev_predicates.is_none()); +} + +fn ty_generics_for_type_or_impl<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, + generics: &ast::Generics) + -> ty::Generics<'tcx> { + ty_generics(ccx, + subst::TypeSpace, + &generics.lifetimes[], + &generics.ty_params[], + ty::Generics::empty()) +} + +fn ty_generic_bounds_for_type_or_impl<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>, + ty_generics: &ty::Generics<'tcx>, + generics: &ast::Generics) + -> ty::GenericPredicates<'tcx> +{ + ty_generic_bounds(ccx, + subst::TypeSpace, + ty_generics, + ty::GenericPredicates::empty(), + &generics.where_clause) +} + +fn ty_generics_for_trait<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, + trait_id: ast::NodeId, + substs: &'tcx subst::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[], + ty::Generics::empty()); + + // Add in the self type parameter. + // + // Something of a hack: use the node id for the trait, also as + // 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 + }; + + ccx.tcx.ty_param_defs.borrow_mut().insert(param_id, def.clone()); + + generics.types.push(subst::SelfSpace, def); + + return generics; +} + fn ty_generics_for_fn_or_method<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>, generics: &ast::Generics, base_generics: ty::Generics<'tcx>) @@ -1156,8 +1341,20 @@ fn ty_generics_for_fn_or_method<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>, subst::FnSpace, &early_lifetimes[], &generics.ty_params[], - base_generics, - &generics.where_clause) + base_generics) +} + +fn ty_generic_bounds_for_fn_or_method<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>, + generics: &ast::Generics, + ty_generics: &ty::Generics<'tcx>, + base: ty::GenericPredicates<'tcx>) + -> ty::GenericPredicates<'tcx> +{ + ty_generic_bounds(ccx, + subst::FnSpace, + ty_generics, + base, + &generics.where_clause) } // Add the Sized bound, unless the type parameter is marked as `?Sized`. @@ -1207,47 +1404,29 @@ fn add_unsized_bound<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>, } } -fn ty_generics<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>, - space: subst::ParamSpace, - lifetime_defs: &[ast::LifetimeDef], - types: &[ast::TyParam], - base_generics: ty::Generics<'tcx>, - where_clause: &ast::WhereClause) - -> ty::Generics<'tcx> +fn ty_generic_bounds<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>, + space: subst::ParamSpace, + generics: &ty::Generics<'tcx>, + base: ty::GenericPredicates<'tcx>, + where_clause: &ast::WhereClause) + -> ty::GenericPredicates<'tcx> { - let mut result = base_generics; + let tcx = ccx.tcx; + let mut result = base; - for (i, l) in lifetime_defs.iter().enumerate() { - let bounds = l.bounds.iter() - .map(|l| ast_region_to_region(ccx.tcx, l)) - .collect(); - let def = ty::RegionParameterDef { name: l.lifetime.name, - space: space, - index: i as u32, - def_id: local_def(l.lifetime.id), - bounds: bounds }; - debug!("ty_generics: def for region param: {:?}", def); - result.regions.push(space, def); + // 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)); + } } - - 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, - space, - param, - i as u32); - debug!("ty_generics: def for type param: {}, {:?}", - def.repr(ccx.tcx), - space); - result.types.push(space, def); + 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()); } - // Just for fun, also push the bounds from the type parameters - // into the predicates list. This is currently kind of non-DRY. - create_predicates(ccx.tcx, &mut result, space); - // Add the bounds not associated with a type parameter for predicate in &where_clause.predicates { match predicate { @@ -1275,7 +1454,7 @@ fn ty_generics<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>, } &ast::TyParamBound::RegionTyParamBound(ref lifetime) => { - let region = ast_region_to_region(ccx.tcx, lifetime); + let region = ast_region_to_region(tcx, lifetime); let pred = ty::Binder(ty::OutlivesPredicate(ty, region)); result.predicates.push(space, ty::Predicate::TypeOutlives(pred)) } @@ -1284,9 +1463,9 @@ fn ty_generics<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>, } &ast::WherePredicate::RegionPredicate(ref region_pred) => { - let r1 = ast_region_to_region(ccx.tcx, ®ion_pred.lifetime); + let r1 = ast_region_to_region(tcx, ®ion_pred.lifetime); for bound in ®ion_pred.bounds { - let r2 = ast_region_to_region(ccx.tcx, bound); + let r2 = ast_region_to_region(tcx, bound); let pred = ty::Binder(ty::OutlivesPredicate(r1, r2)); result.predicates.push(space, ty::Predicate::RegionOutlives(pred)) } @@ -1294,39 +1473,50 @@ fn ty_generics<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>, &ast::WherePredicate::EqPredicate(ref eq_pred) => { // FIXME(#20041) - ccx.tcx.sess.span_bug(eq_pred.span, - "Equality constraints are not yet \ - implemented (#20041)") + tcx.sess.span_bug(eq_pred.span, + "Equality constraints are not yet \ + implemented (#20041)") } } } return result; +} - fn create_predicates<'tcx>( - tcx: &ty::ctxt<'tcx>, - result: &mut ty::Generics<'tcx>, - space: subst::ParamSpace) - { - for type_param_def in result.types.get_slice(space) { - let param_ty = ty::mk_param_from_def(tcx, type_param_def); - for predicate in ty::predicates(tcx, param_ty, &type_param_def.bounds) { - result.predicates.push(space, predicate); - } - } +fn ty_generics<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>, + space: subst::ParamSpace, + lifetime_defs: &[ast::LifetimeDef], + types: &[ast::TyParam], + base_generics: ty::Generics<'tcx>) + -> ty::Generics<'tcx> +{ + let tcx = ccx.tcx; + let mut result = base_generics; - for region_param_def in result.regions.get_slice(space) { - let region = region_param_def.to_early_bound_region(); - for &bound_region in ®ion_param_def.bounds { - // account for new binder introduced in the predicate below; no need - // to shift `region` because it is never a late-bound region - let bound_region = ty_fold::shift_region(bound_region, 1); - result.predicates.push( - space, - ty::Binder(ty::OutlivesPredicate(region, bound_region)).as_predicate()); - } - } + for (i, l) in lifetime_defs.iter().enumerate() { + let bounds = l.bounds.iter() + .map(|l| ast_region_to_region(tcx, l)) + .collect(); + let def = ty::RegionParameterDef { name: l.lifetime.name, + space: space, + 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, space, param, i as u32); + debug!("ty_generics: def for type param: {:?}, {:?}", def, space); + result.types.push(space, def); + } + + result } fn get_or_create_type_parameter_def<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>, @@ -1335,8 +1525,9 @@ fn get_or_create_type_parameter_def<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>, index: u32) -> ty::TypeParameterDef<'tcx> { - match ccx.tcx.ty_param_defs.borrow().get(¶m.id) { - Some(d) => { return (*d).clone(); } + let tcx = ccx.tcx; + match tcx.ty_param_defs.borrow().get(¶m.id) { + Some(d) => { return d.clone(); } None => { } } @@ -1355,9 +1546,9 @@ fn get_or_create_type_parameter_def<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>, ty::walk_ty(ty, |t| { match t.sty { ty::ty_param(p) => if p.idx > cur_idx { - span_err!(ccx.tcx.sess, path.span, E0128, + span_err!(tcx.sess, path.span, E0128, "type parameters with a default cannot use \ - forward declared identifiers"); + forward declared identifiers"); }, _ => {} } @@ -1376,7 +1567,7 @@ fn get_or_create_type_parameter_def<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>, default: default }; - ccx.tcx.ty_param_defs.borrow_mut().insert(param.id, def.clone()); + tcx.ty_param_defs.borrow_mut().insert(param.id, def.clone()); def } @@ -1404,7 +1595,7 @@ fn compute_bounds<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>, ast_bounds, span); - check_bounds_compatible(ccx.tcx, + check_bounds_compatible(ccx, param_ty, ¶m_bounds, span); @@ -1415,24 +1606,22 @@ fn compute_bounds<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>, param_bounds } -fn check_bounds_compatible<'tcx>(tcx: &ty::ctxt<'tcx>, - param_ty: Ty<'tcx>, - param_bounds: &ty::ParamBounds<'tcx>, - span: Span) { - // Currently the only bound which is incompatible with other bounds is - // Sized/Unsized. +fn check_bounds_compatible<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>, + param_ty: Ty<'tcx>, + param_bounds: &ty::ParamBounds<'tcx>, + span: Span) { if !param_bounds.builtin_bounds.contains(&ty::BoundSized) { ty::each_bound_trait_and_supertraits( - tcx, + ccx.tcx, ¶m_bounds.trait_bounds[], |trait_ref| { - let trait_def = ty::lookup_trait_def(tcx, trait_ref.def_id()); + let trait_def = ccx.get_trait_def(trait_ref.def_id()); if trait_def.bounds.builtin_bounds.contains(&ty::BoundSized) { - span_err!(tcx.sess, span, E0129, + span_err!(ccx.tcx.sess, span, E0129, "incompatible bounds on `{}`, \ bound `{}` does not allow unsized type", - param_ty.user_string(tcx), - trait_ref.user_string(tcx)); + param_ty.user_string(ccx.tcx), + trait_ref.user_string(ccx.tcx)); } true }); @@ -1445,10 +1634,12 @@ fn conv_param_bounds<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>, ast_bounds: &[ast::TyParamBound]) -> ty::ParamBounds<'tcx> { - let astconv::PartitionedBounds { builtin_bounds, - trait_bounds, - region_bounds } = - astconv::partition_bounds(ccx.tcx, span, ast_bounds); + let tcx = ccx.tcx; + let astconv::PartitionedBounds { + builtin_bounds, + trait_bounds, + region_bounds + } = astconv::partition_bounds(tcx, span, ast_bounds.as_slice()); let mut projection_bounds = Vec::new(); @@ -1461,11 +1652,13 @@ fn conv_param_bounds<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>, Some(param_ty), &mut projection_bounds) }) - .collect(); + .collect(); + let region_bounds: Vec = region_bounds.into_iter() - .map(|r| ast_region_to_region(ccx.tcx, r)) - .collect(); + .map(|r| ast_region_to_region(ccx.tcx, r)) + .collect(); + ty::ParamBounds { region_bounds: region_bounds, builtin_bounds: builtin_bounds, @@ -1474,13 +1667,14 @@ fn conv_param_bounds<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>, } } -fn ty_of_foreign_fn_decl<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, - decl: &ast::FnDecl, - def_id: ast::DefId, - ast_generics: &ast::Generics, - abi: abi::Abi) - -> ty::TypeScheme<'tcx> { - for i in &decl.inputs { +fn compute_type_scheme_of_foreign_fn_decl<'a, 'tcx>( + ccx: &CollectCtxt<'a, 'tcx>, + decl: &ast::FnDecl, + ast_generics: &ast::Generics, + abi: abi::Abi) + -> ty::TypeScheme<'tcx> +{ + for i in decl.inputs.iter() { match (*i).pat.node { ast::PatIdent(_, _, _) => (), ast::PatWild(ast::PatWildSingle) => (), @@ -1491,9 +1685,8 @@ fn ty_of_foreign_fn_decl<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, } } - let ty_generics_for_fn_or_method = ty_generics_for_fn_or_method(ccx, - ast_generics, - ty::Generics::empty()); + let ty_generics = ty_generics_for_fn_or_method(ccx, ast_generics, ty::Generics::empty()); + let rb = BindingRscope::new(); let input_tys = decl.inputs .iter() @@ -1519,13 +1712,11 @@ fn ty_of_foreign_fn_decl<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, output: output, variadic: decl.variadic}), })); - let scheme = TypeScheme { - generics: ty_generics_for_fn_or_method, - ty: t_fn - }; - ccx.tcx.tcache.borrow_mut().insert(def_id, scheme.clone()); - return scheme; + ty::TypeScheme { + generics: ty_generics, + ty: t_fn + } } fn mk_item_substs<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, @@ -1556,6 +1747,7 @@ fn check_method_self_type<'a, 'tcx, RS:RegionScope>( 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 base_type = match typ.sty { @@ -1573,27 +1765,28 @@ fn check_method_self_type<'a, 'tcx, RS:RegionScope>( assert!(!base_type.has_regions_escaping_depth(1)); let required_type_free = liberate_early_bound_regions( - ccx.tcx, body_scope, + tcx, body_scope, &ty::liberate_late_bound_regions( - ccx.tcx, body_scope, &ty::Binder(required_type))); + tcx, body_scope, &ty::Binder(required_type))); // The "base type" comes from the impl. It too may have late-bound // regions from the method. assert!(!base_type.has_regions_escaping_depth(1)); let base_type_free = liberate_early_bound_regions( - ccx.tcx, body_scope, + tcx, body_scope, &ty::liberate_late_bound_regions( - ccx.tcx, body_scope, &ty::Binder(base_type))); + tcx, body_scope, &ty::Binder(base_type))); - debug!("required_type={} required_type_free={} \ - base_type={} base_type_free={}", - required_type.repr(ccx.tcx), - required_type_free.repr(ccx.tcx), - base_type.repr(ccx.tcx), - base_type_free.repr(ccx.tcx)); - let infcx = infer::new_infer_ctxt(ccx.tcx); - drop(::require_same_types(ccx.tcx, + //debug!("required_type={} required_type_free={} \ + //base_type={} base_type_free={}", + //required_type.repr(tcx), + //required_type_free.repr(tcx), + //base_type.repr(tcx), + //base_type_free.repr(tcx)); + + let infcx = infer::new_infer_ctxt(tcx); + drop(::require_same_types(tcx, Some(&infcx), false, explicit_self.span, @@ -1601,7 +1794,7 @@ fn check_method_self_type<'a, 'tcx, RS:RegionScope>( required_type_free, || { format!("mismatched self type: expected `{}`", - ppaux::ty_to_string(ccx.tcx, required_type)) + ppaux::ty_to_string(tcx, required_type)) })); infcx.resolve_regions_and_report_errors(body_id); } @@ -1639,6 +1832,7 @@ fn enforce_impl_ty_params_are_constrained<'tcx>(tcx: &ty::ctxt<'tcx>, impl_def_id: ast::DefId) { let impl_scheme = ty::lookup_item_type(tcx, impl_def_id); + let impl_predicates = ty::lookup_predicates(tcx, impl_def_id); let impl_trait_ref = ty::impl_trait_ref(tcx, impl_def_id); // The trait reference is an input, so find all type parameters @@ -1656,18 +1850,18 @@ fn enforce_impl_ty_params_are_constrained<'tcx>(tcx: &ty::ctxt<'tcx>, let num_inputs = input_parameters.len(); let projection_predicates = - impl_scheme.generics.predicates - .iter() - .filter_map(|predicate| { - match *predicate { - // Ignore higher-ranked binders. For the purposes - // of this check, they don't matter because they - // only affect named regions, and we're just - // concerned about type parameters here. - ty::Predicate::Projection(ref data) => Some(data.0.clone()), - _ => None, - } - }); + impl_predicates.predicates + .iter() + .filter_map(|predicate| { + match *predicate { + // Ignore higher-ranked binders. For the purposes + // of this check, they don't matter because they + // only affect named regions, and we're just + // concerned about type parameters here. + ty::Predicate::Projection(ref data) => Some(data.0.clone()), + _ => None, + } + }); for projection in projection_predicates { // Special case: watch out for some kind of sneaky attempt