From acd1a0090a55bcb6810b2d6eb1676cb9a5fb65b7 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 11 Feb 2015 05:59:01 -0500 Subject: [PATCH 01/12] Update metadata to reflect that predicates/schemes/trait-defs are now severed --- src/librustc/metadata/csearch.rs | 8 ++++ src/librustc/metadata/decoder.rs | 40 +++++++++++++----- src/librustc/metadata/encoder.rs | 69 +++++++++++++++++--------------- src/librustc/middle/astencode.rs | 13 +----- src/libsyntax/ast.rs | 8 ++++ 5 files changed, 82 insertions(+), 56 deletions(-) diff --git a/src/librustc/metadata/csearch.rs b/src/librustc/metadata/csearch.rs index b151856e30941..245b9ef66ad3a 100644 --- a/src/librustc/metadata/csearch.rs +++ b/src/librustc/metadata/csearch.rs @@ -233,6 +233,14 @@ pub fn get_trait_def<'tcx>(tcx: &ty::ctxt<'tcx>, def: ast::DefId) -> ty::TraitDe decoder::get_trait_def(&*cdata, def.node, tcx) } +pub fn get_predicates<'tcx>(tcx: &ty::ctxt<'tcx>, def: ast::DefId) + -> ty::GenericPredicates<'tcx> +{ + let cstore = &tcx.sess.cstore; + let cdata = cstore.get_crate_data(def.krate); + decoder::get_predicates(&*cdata, def.node, tcx) +} + pub fn get_field_type<'tcx>(tcx: &ty::ctxt<'tcx>, class_id: ast::DefId, def: ast::DefId) -> ty::TypeScheme<'tcx> { let cstore = &tcx.sess.cstore; diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index 3a70490771eba..4924ebc576742 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -417,16 +417,22 @@ pub fn get_trait_def<'tcx>(cdata: Cmd, } } -pub fn get_type<'tcx>(cdata: Cmd, id: ast::NodeId, tcx: &ty::ctxt<'tcx>) - -> ty::TypeScheme<'tcx> { - - let item = lookup_item(id, cdata.data()); +pub fn get_predicates<'tcx>(cdata: Cmd, + item_id: ast::NodeId, + tcx: &ty::ctxt<'tcx>) + -> ty::GenericPredicates<'tcx> +{ + let item_doc = lookup_item(item_id, cdata.data()); + doc_predicates(item_doc, tcx, cdata, tag_item_generics) +} - let t = item_type(ast::DefId { krate: cdata.cnum, node: id }, item, tcx, +pub fn get_type<'tcx>(cdata: Cmd, id: ast::NodeId, tcx: &ty::ctxt<'tcx>) + -> ty::TypeScheme<'tcx> +{ + let item_doc = lookup_item(id, cdata.data()); + let t = item_type(ast::DefId { krate: cdata.cnum, node: id }, item_doc, tcx, cdata); - - let generics = doc_generics(item, tcx, cdata, tag_item_generics); - + let generics = doc_generics(item_doc, tcx, cdata, tag_item_generics); ty::TypeScheme { generics: generics, ty: t @@ -882,14 +888,15 @@ pub fn get_impl_or_trait_item<'tcx>(intr: Rc, match item_sort(method_doc) { 'r' | 'p' => { - let generics = doc_generics(method_doc, tcx, cdata, - tag_method_ty_generics); + let generics = doc_generics(method_doc, tcx, cdata, tag_method_ty_generics); + let predicates = doc_predicates(method_doc, tcx, cdata, tag_method_ty_generics); let fty = doc_method_fty(method_doc, tcx, cdata); let explicit_self = get_explicit_self(method_doc); let provided_source = get_provided_source(method_doc, cdata); ty::MethodTraitItem(Rc::new(ty::Method::new(name, generics, + predicates, fty, explicit_self, vis, @@ -1520,6 +1527,17 @@ fn doc_generics<'tcx>(base_doc: rbml::Doc, true }); + ty::Generics { types: types, regions: regions } +} + +fn doc_predicates<'tcx>(base_doc: rbml::Doc, + tcx: &ty::ctxt<'tcx>, + cdata: Cmd, + tag: uint) + -> ty::GenericPredicates<'tcx> +{ + let doc = reader::get_doc(base_doc, tag); + let mut predicates = subst::VecPerParamSpace::empty(); reader::tagged_docs(doc, tag_predicate, |predicate_doc| { let space_doc = reader::get_doc(predicate_doc, tag_predicate_space); @@ -1533,7 +1551,7 @@ fn doc_generics<'tcx>(base_doc: rbml::Doc, true }); - ty::Generics { types: types, regions: regions, predicates: predicates } + ty::GenericPredicates { predicates: predicates } } pub fn is_associated_type(cdata: Cmd, id: ast::NodeId) -> bool { diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index ef0c3fbb252fa..3123fa31abdd1 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -139,11 +139,21 @@ fn encode_item_variances(rbml_w: &mut Encoder, rbml_w.end_tag(); } +fn encode_bounds_and_type_for_item<'a, 'tcx>(rbml_w: &mut Encoder, + ecx: &EncodeContext<'a, 'tcx>, + id: ast::NodeId) { + encode_bounds_and_type(rbml_w, + ecx, + &ty::lookup_item_type(ecx.tcx, local_def(id)), + &ty::lookup_predicates(ecx.tcx, local_def(id))); +} + fn encode_bounds_and_type<'a, 'tcx>(rbml_w: &mut Encoder, ecx: &EncodeContext<'a, 'tcx>, - pty: &ty::TypeScheme<'tcx>) { - encode_generics(rbml_w, ecx, &pty.generics, tag_item_generics); - encode_type(ecx, rbml_w, pty.ty); + scheme: &ty::TypeScheme<'tcx>, + predicates: &ty::GenericPredicates<'tcx>) { + encode_generics(rbml_w, ecx, &scheme.generics, &predicates, tag_item_generics); + encode_type(ecx, rbml_w, scheme.ty); } fn encode_variant_id(rbml_w: &mut Encoder, vid: DefId) { @@ -353,8 +363,7 @@ fn encode_enum_variant_info(ecx: &EncodeContext, encode_disr_val(ecx, rbml_w, (*vi)[i].disr_val); disr_val = (*vi)[i].disr_val; } - encode_bounds_and_type(rbml_w, ecx, - &lookup_item_type(ecx.tcx, def_id)); + encode_bounds_and_type_for_item(rbml_w, ecx, def_id.local_id()); ecx.tcx.map.with_path(variant.node.id, |path| encode_path(rbml_w, path)); rbml_w.end_tag(); @@ -698,8 +707,7 @@ fn encode_info_for_struct(ecx: &EncodeContext, token::get_name(nm), id); encode_struct_field_family(rbml_w, field.vis); encode_name(rbml_w, nm); - encode_bounds_and_type(rbml_w, ecx, - &lookup_item_type(ecx.tcx, local_def(id))); + encode_bounds_and_type_for_item(rbml_w, ecx, id); encode_def_id(rbml_w, local_def(id)); let stab = stability::lookup(ecx.tcx, field.id); @@ -724,8 +732,7 @@ fn encode_info_for_struct_ctor(ecx: &EncodeContext, rbml_w.start_tag(tag_items_data_item); encode_def_id(rbml_w, local_def(ctor_id)); encode_family(rbml_w, 'o'); - encode_bounds_and_type(rbml_w, ecx, - &lookup_item_type(ecx.tcx, local_def(ctor_id))); + encode_bounds_and_type_for_item(rbml_w, ecx, ctor_id); encode_name(rbml_w, name.name); ecx.tcx.map.with_path(ctor_id, |path| encode_path(rbml_w, path)); encode_parent_item(rbml_w, local_def(struct_id)); @@ -749,6 +756,7 @@ fn encode_info_for_struct_ctor(ecx: &EncodeContext, fn encode_generics<'a, 'tcx>(rbml_w: &mut Encoder, ecx: &EncodeContext<'a, 'tcx>, generics: &ty::Generics<'tcx>, + predicates: &ty::GenericPredicates<'tcx>, tag: uint) { rbml_w.start_tag(tag); @@ -790,7 +798,7 @@ fn encode_generics<'a, 'tcx>(rbml_w: &mut Encoder, rbml_w.end_tag(); } - for (space, _, predicate) in generics.predicates.iter_enumerated() { + for (space, _, predicate) in predicates.predicates.iter_enumerated() { rbml_w.start_tag(tag_predicate); rbml_w.wr_tagged_u8(tag_predicate_space, space as u8); @@ -810,7 +818,7 @@ fn encode_method_ty_fields<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, method_ty: &ty::Method<'tcx>) { encode_def_id(rbml_w, method_ty.def_id); encode_name(rbml_w, method_ty.name); - encode_generics(rbml_w, ecx, &method_ty.generics, + encode_generics(rbml_w, ecx, &method_ty.generics, &method_ty.predicates, tag_method_ty_generics); encode_method_fty(ecx, rbml_w, &method_ty.fty); encode_visibility(rbml_w, method_ty.vis); @@ -844,15 +852,15 @@ fn encode_info_for_method<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, encode_stability(rbml_w, stab); // The type for methods gets encoded twice, which is unfortunate. - let pty = lookup_item_type(ecx.tcx, m.def_id); - encode_bounds_and_type(rbml_w, ecx, &pty); + encode_bounds_and_type_for_item(rbml_w, ecx, m.def_id.local_id()); let elem = ast_map::PathName(m.name); encode_path(rbml_w, impl_path.chain(Some(elem).into_iter())); match ast_item_opt { Some(&ast::MethodImplItem(ref ast_method)) => { encode_attributes(rbml_w, &ast_method.attrs[]); - let any_types = !pty.generics.types.is_empty(); + let scheme = ty::lookup_item_type(ecx.tcx, m.def_id); + let any_types = !scheme.generics.types.is_empty(); if any_types || is_default_impl || should_inline(&ast_method.attrs[]) { encode_inlined_item(ecx, rbml_w, IIImplItemRef(local_def(parent_id), ast_item_opt.unwrap())); @@ -887,8 +895,7 @@ fn encode_info_for_associated_type(ecx: &EncodeContext, encode_parent_item(rbml_w, local_def(parent_id)); encode_item_sort(rbml_w, 't'); - let type_scheme = ty::lookup_item_type(ecx.tcx, associated_type.def_id); - encode_bounds_and_type(rbml_w, ecx, &type_scheme); + encode_bounds_and_type_for_item(rbml_w, ecx, associated_type.def_id.local_id()); let stab = stability::lookup(ecx.tcx, associated_type.def_id); encode_stability(rbml_w, stab); @@ -1027,7 +1034,7 @@ fn encode_info_for_item(ecx: &EncodeContext, } else { encode_family(rbml_w, 'c'); } - encode_bounds_and_type(rbml_w, ecx, &lookup_item_type(tcx, def_id)); + encode_bounds_and_type_for_item(rbml_w, ecx, item.id); encode_symbol(ecx, rbml_w, item.id); encode_name(rbml_w, item.ident.name); encode_path(rbml_w, path); @@ -1041,7 +1048,7 @@ fn encode_info_for_item(ecx: &EncodeContext, rbml_w.start_tag(tag_items_data_item); encode_def_id(rbml_w, def_id); encode_family(rbml_w, 'C'); - encode_bounds_and_type(rbml_w, ecx, &lookup_item_type(tcx, def_id)); + encode_bounds_and_type_for_item(rbml_w, ecx, item.id); encode_name(rbml_w, item.ident.name); encode_path(rbml_w, path); encode_attributes(rbml_w, &item.attrs); @@ -1056,7 +1063,7 @@ fn encode_info_for_item(ecx: &EncodeContext, encode_def_id(rbml_w, def_id); encode_family(rbml_w, FN_FAMILY); let tps_len = generics.ty_params.len(); - encode_bounds_and_type(rbml_w, ecx, &lookup_item_type(tcx, def_id)); + encode_bounds_and_type_for_item(rbml_w, ecx, item.id); encode_name(rbml_w, item.ident.name); encode_path(rbml_w, path); encode_attributes(rbml_w, &item.attrs[]); @@ -1105,7 +1112,7 @@ fn encode_info_for_item(ecx: &EncodeContext, rbml_w.start_tag(tag_items_data_item); encode_def_id(rbml_w, def_id); encode_family(rbml_w, 'y'); - encode_bounds_and_type(rbml_w, ecx, &lookup_item_type(tcx, def_id)); + encode_bounds_and_type_for_item(rbml_w, ecx, item.id); encode_name(rbml_w, item.ident.name); encode_path(rbml_w, path); encode_visibility(rbml_w, vis); @@ -1119,7 +1126,7 @@ fn encode_info_for_item(ecx: &EncodeContext, encode_def_id(rbml_w, def_id); encode_family(rbml_w, 't'); encode_item_variances(rbml_w, ecx, item.id); - encode_bounds_and_type(rbml_w, ecx, &lookup_item_type(tcx, def_id)); + encode_bounds_and_type_for_item(rbml_w, ecx, item.id); encode_name(rbml_w, item.ident.name); encode_attributes(rbml_w, &item.attrs[]); encode_repr_attrs(rbml_w, ecx, &item.attrs[]); @@ -1161,7 +1168,7 @@ fn encode_info_for_item(ecx: &EncodeContext, rbml_w.start_tag(tag_items_data_item); encode_def_id(rbml_w, def_id); encode_family(rbml_w, 'S'); - encode_bounds_and_type(rbml_w, ecx, &lookup_item_type(tcx, def_id)); + encode_bounds_and_type_for_item(rbml_w, ecx, item.id); encode_item_variances(rbml_w, ecx, item.id); encode_name(rbml_w, item.ident.name); @@ -1204,7 +1211,7 @@ fn encode_info_for_item(ecx: &EncodeContext, rbml_w.start_tag(tag_items_data_item); encode_def_id(rbml_w, def_id); encode_family(rbml_w, 'i'); - encode_bounds_and_type(rbml_w, ecx, &lookup_item_type(tcx, def_id)); + encode_bounds_and_type_for_item(rbml_w, ecx, item.id); encode_name(rbml_w, item.ident.name); encode_attributes(rbml_w, &item.attrs[]); encode_unsafety(rbml_w, unsafety); @@ -1305,10 +1312,11 @@ fn encode_info_for_item(ecx: &EncodeContext, encode_family(rbml_w, 'I'); encode_item_variances(rbml_w, ecx, item.id); let trait_def = ty::lookup_trait_def(tcx, def_id); + let trait_predicates = ty::lookup_predicates(tcx, def_id); encode_unsafety(rbml_w, trait_def.unsafety); encode_paren_sugar(rbml_w, trait_def.paren_sugar); encode_associated_type_names(rbml_w, &trait_def.associated_type_names); - encode_generics(rbml_w, ecx, &trait_def.generics, tag_item_generics); + encode_generics(rbml_w, ecx, &trait_def.generics, &trait_predicates, tag_item_generics); encode_trait_ref(rbml_w, ecx, &*trait_def.trait_ref, tag_item_trait_ref); encode_name(rbml_w, item.ident.name); encode_attributes(rbml_w, &item.attrs[]); @@ -1384,9 +1392,7 @@ fn encode_info_for_item(ecx: &EncodeContext, METHOD_FAMILY); } } - let pty = ty::lookup_item_type(tcx, - method_def_id); - encode_bounds_and_type(rbml_w, ecx, &pty); + encode_bounds_and_type_for_item(rbml_w, ecx, method_def_id.local_id()); is_nonstatic_method = method_ty.explicit_self != ty::StaticExplicitSelfCategory; @@ -1415,8 +1421,7 @@ fn encode_info_for_item(ecx: &EncodeContext, if is_nonstatic_method { // FIXME: I feel like there is something funny // going on. - let pty = ty::lookup_item_type(tcx, item_def_id.def_id()); - encode_bounds_and_type(rbml_w, ecx, &pty); + encode_bounds_and_type_for_item(rbml_w, ecx, item_def_id.def_id().local_id()); } }; match trait_item { @@ -1468,8 +1473,7 @@ fn encode_info_for_foreign_item(ecx: &EncodeContext, match nitem.node { ast::ForeignItemFn(ref fndecl, _) => { encode_family(rbml_w, FN_FAMILY); - encode_bounds_and_type(rbml_w, ecx, - &lookup_item_type(ecx.tcx,local_def(nitem.id))); + encode_bounds_and_type_for_item(rbml_w, ecx, nitem.id); encode_name(rbml_w, nitem.ident.name); if abi == abi::RustIntrinsic { encode_inlined_item(ecx, rbml_w, IIForeignRef(nitem)); @@ -1486,8 +1490,7 @@ fn encode_info_for_foreign_item(ecx: &EncodeContext, } else { encode_family(rbml_w, 'c'); } - encode_bounds_and_type(rbml_w, ecx, - &lookup_item_type(ecx.tcx,local_def(nitem.id))); + encode_bounds_and_type_for_item(rbml_w, ecx, nitem.id); encode_attributes(rbml_w, &*nitem.attrs); let stab = stability::lookup(ecx.tcx, ast_util::local_def(nitem.id)); encode_stability(rbml_w, stab); diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index 8e3bf0fa28d23..423032d1287d7 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -951,11 +951,6 @@ impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> { Ok(encode_vec_per_param_space( this, &type_scheme.generics.regions, |this, def| def.encode(this).unwrap())) - }); - this.emit_struct_field("predicates", 2, |this| { - Ok(encode_vec_per_param_space( - this, &type_scheme.generics.predicates, - |this, def| this.emit_predicate(ecx, def))) }) }) }); @@ -1574,7 +1569,7 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> { fn read_type_scheme<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>) -> ty::TypeScheme<'tcx> { - self.read_struct("TypeScheme", 2, |this| { + self.read_struct("TypeScheme", 3, |this| { Ok(ty::TypeScheme { generics: this.read_struct_field("generics", 0, |this| { this.read_struct("Generics", 2, |this| { @@ -1590,12 +1585,6 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> { Ok(this.read_vec_per_param_space( |this| Decodable::decode(this).unwrap())) }).unwrap(), - - predicates: - this.read_struct_field("predicates", 2, |this| { - Ok(this.read_vec_per_param_space( - |this| this.read_predicate(dcx))) - }).unwrap(), }) }) }).unwrap(), diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 5979d339e17a4..d6778be553e8b 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -366,6 +366,14 @@ pub struct DefId { pub node: NodeId, } +impl DefId { + /// Read the node id, asserting that this def-id is krate-local. + pub fn local_id(&self) -> NodeId { + assert_eq!(self.krate, LOCAL_CRATE); + self.node + } +} + /// Item definitions in the currently-compiled crate would have the CrateNum /// LOCAL_CRATE in their DefId. pub const LOCAL_CRATE: CrateNum = 0; From bea8b81225372ebbcb42fc5a2b6f468b2df402ba Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 11 Feb 2015 05:59:59 -0500 Subject: [PATCH 02/12] Make VecPerParamSpace support IntoIterator --- src/librustc/middle/subst.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/librustc/middle/subst.rs b/src/librustc/middle/subst.rs index 8cb0447e73247..e20968a9ac997 100644 --- a/src/librustc/middle/subst.rs +++ b/src/librustc/middle/subst.rs @@ -18,6 +18,7 @@ use middle::ty_fold::{self, TypeFoldable, TypeFolder}; use util::ppaux::Repr; use std::fmt; +use std::iter::IntoIterator; use std::slice::Iter; use std::vec::{Vec, IntoIter}; use syntax::codemap::{Span, DUMMY_SP}; @@ -529,6 +530,23 @@ impl<'a,T> Iterator for EnumeratedItems<'a,T> { } } +impl IntoIterator for VecPerParamSpace { + type IntoIter = IntoIter; + + fn into_iter(self) -> IntoIter { + self.into_vec().into_iter() + } +} + +impl<'a,T> IntoIterator for &'a VecPerParamSpace { + type IntoIter = Iter<'a, T>; + + fn into_iter(self) -> Iter<'a, T> { + self.as_slice().into_iter() + } +} + + /////////////////////////////////////////////////////////////////////////// // Public trait `Subst` // From d1630970deaf3fce2b0c4671acaeb8edfd07bc7e Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 11 Feb 2015 06:54:05 -0500 Subject: [PATCH 03/12] Split the predicates listing out of `TraitDef` and `TypeScheme` and into a separate map, `tcx.predicates`, that is used for both traits and other kinds of items. Also use two newtypes to distinguish instantiated predicates from the raw, unsubstituted predicates extracted from the map. --- src/librustc/middle/ty.rs | 75 ++++++++++++++++++++++++++++----------- 1 file changed, 54 insertions(+), 21 deletions(-) diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 8e94991f65691..af80ce65474f5 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -192,7 +192,8 @@ impl ImplOrTraitItemId { #[derive(Clone, Debug)] pub struct Method<'tcx> { pub name: ast::Name, - pub generics: ty::Generics<'tcx>, + pub generics: Generics<'tcx>, + pub predicates: GenericPredicates<'tcx>, pub fty: BareFnTy<'tcx>, pub explicit_self: ExplicitSelfCategory, pub vis: ast::Visibility, @@ -206,6 +207,7 @@ pub struct Method<'tcx> { impl<'tcx> Method<'tcx> { pub fn new(name: ast::Name, generics: ty::Generics<'tcx>, + predicates: GenericPredicates<'tcx>, fty: BareFnTy<'tcx>, explicit_self: ExplicitSelfCategory, vis: ast::Visibility, @@ -216,6 +218,7 @@ impl<'tcx> Method<'tcx> { Method { name: name, generics: generics, + predicates: predicates, fty: fty, explicit_self: explicit_self, vis: vis, @@ -710,6 +713,10 @@ pub struct ctxt<'tcx> { pub trait_refs: RefCell>>>, pub trait_defs: RefCell>>>, + /// Maps from the def-id of an item (trait/struct/enum/fn) to its + /// associated predicates. + pub predicates: RefCell>>, + /// Maps from node-id of a trait object cast (like `foo as /// Box`) to the trait reference. pub object_cast_map: ObjectCastMap<'tcx>, @@ -1782,7 +1789,6 @@ impl RegionParameterDef { pub struct Generics<'tcx> { pub types: VecPerParamSpace>, pub regions: VecPerParamSpace, - pub predicates: VecPerParamSpace>, } impl<'tcx> Generics<'tcx> { @@ -1790,10 +1796,13 @@ impl<'tcx> Generics<'tcx> { Generics { types: VecPerParamSpace::empty(), regions: VecPerParamSpace::empty(), - predicates: VecPerParamSpace::empty(), } } + pub fn is_empty(&self) -> bool { + self.types.is_empty() && self.regions.is_empty() + } + pub fn has_type_params(&self, space: subst::ParamSpace) -> bool { !self.types.is_empty_in(space) } @@ -1801,14 +1810,24 @@ impl<'tcx> Generics<'tcx> { pub fn has_region_params(&self, space: subst::ParamSpace) -> bool { !self.regions.is_empty_in(space) } +} - pub fn is_empty(&self) -> bool { - self.types.is_empty() && self.regions.is_empty() +/// Bounds on generics. +#[derive(Clone, Debug)] +pub struct GenericPredicates<'tcx> { + pub predicates: VecPerParamSpace>, +} + +impl<'tcx> GenericPredicates<'tcx> { + pub fn empty() -> GenericPredicates<'tcx> { + GenericPredicates { + predicates: VecPerParamSpace::empty(), + } } - pub fn to_bounds(&self, tcx: &ty::ctxt<'tcx>, substs: &Substs<'tcx>) - -> GenericBounds<'tcx> { - GenericBounds { + pub fn instantiate(&self, tcx: &ty::ctxt<'tcx>, substs: &Substs<'tcx>) + -> InstantiatedPredicates<'tcx> { + InstantiatedPredicates { predicates: self.predicates.subst(tcx, substs), } } @@ -2022,11 +2041,11 @@ impl<'tcx> Predicate<'tcx> { /// Represents the bounds declared on a particular set of type /// parameters. Should eventually be generalized into a flag list of -/// where clauses. You can obtain a `GenericBounds` list from a -/// `Generics` by using the `to_bounds` method. Note that this method -/// reflects an important semantic invariant of `GenericBounds`: while -/// the bounds in a `Generics` are expressed in terms of the bound type -/// parameters of the impl/trait/whatever, a `GenericBounds` instance +/// where clauses. You can obtain a `InstantiatedPredicates` list from a +/// `GenericPredicates` by using the `instantiate` method. Note that this method +/// reflects an important semantic invariant of `InstantiatedPredicates`: while +/// the `GenericPredicates` are expressed in terms of the bound type +/// parameters of the impl/trait/whatever, an `InstantiatedPredicates` instance /// represented a set of bounds for some particular instantiation, /// meaning that the generic parameters have been substituted with /// their values. @@ -2035,18 +2054,18 @@ impl<'tcx> Predicate<'tcx> { /// /// struct Foo> { ... } /// -/// Here, the `Generics` for `Foo` would contain a list of bounds like +/// Here, the `GenericPredicates` for `Foo` would contain a list of bounds like /// `[[], [U:Bar]]`. Now if there were some particular reference -/// like `Foo`, then the `GenericBounds` would be `[[], +/// like `Foo`, then the `InstantiatedPredicates` would be `[[], /// [uint:Bar]]`. #[derive(Clone, Debug)] -pub struct GenericBounds<'tcx> { +pub struct InstantiatedPredicates<'tcx> { pub predicates: VecPerParamSpace>, } -impl<'tcx> GenericBounds<'tcx> { - pub fn empty() -> GenericBounds<'tcx> { - GenericBounds { predicates: VecPerParamSpace::empty() } +impl<'tcx> InstantiatedPredicates<'tcx> { + pub fn empty() -> InstantiatedPredicates<'tcx> { + InstantiatedPredicates { predicates: VecPerParamSpace::empty() } } pub fn has_escaping_regions(&self) -> bool { @@ -2248,10 +2267,13 @@ impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> { /// stray references in a comment or something). We try to reserve the /// "poly" prefix to refer to higher-ranked things, as in /// `PolyTraitRef`. +/// +/// Note that each item also comes with predicates, see +/// `lookup_predicates`. #[derive(Clone, Debug)] pub struct TypeScheme<'tcx> { pub generics: Generics<'tcx>, - pub ty: Ty<'tcx> + pub ty: Ty<'tcx>, } /// As `TypeScheme` but for a trait ref. @@ -2393,6 +2415,7 @@ pub fn mk_ctxt<'tcx>(s: Session, item_substs: RefCell::new(NodeMap()), trait_refs: RefCell::new(NodeMap()), trait_defs: RefCell::new(DefIdMap()), + predicates: RefCell::new(DefIdMap()), object_cast_map: RefCell::new(NodeMap()), map: map, intrinsic_defs: RefCell::new(DefIdMap()), @@ -5378,13 +5401,23 @@ pub fn lookup_item_type<'tcx>(cx: &ctxt<'tcx>, /// Given the did of a trait, returns its canonical trait ref. pub fn lookup_trait_def<'tcx>(cx: &ctxt<'tcx>, did: ast::DefId) - -> Rc> { + -> Rc> { memoized(&cx.trait_defs, did, |did: DefId| { assert!(did.krate != ast::LOCAL_CRATE); Rc::new(csearch::get_trait_def(cx, did)) }) } +/// Given the did of a trait, returns its full set of predicates. +pub fn lookup_predicates<'tcx>(cx: &ctxt<'tcx>, did: ast::DefId) + -> GenericPredicates<'tcx> +{ + memoized(&cx.predicates, did, |did: DefId| { + assert!(did.krate != ast::LOCAL_CRATE); + csearch::get_predicates(cx, did) + }) +} + /// Given a reference to a trait, returns the "superbounds" declared /// on the trait, with appropriate substitutions applied. Basically, /// this applies a filter to the where clauses on the trait, returning From 3764699c83387df254f220b4c85121010413aeff Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 11 Feb 2015 10:25:52 -0500 Subject: [PATCH 04/12] 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 | 922 ++++++++++++++++++++------------- 1 file changed, 558 insertions(+), 364 deletions(-) diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 55fa47760bbf0..3ee3eb87b95a7 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,121 +1001,267 @@ 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(); + let trait_def = trait_def_of_item(ccx, it); + + 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)[]); + } + }; + + let self_param_ty = ty::ParamTy::for_self().to_ty(ccx.tcx); + + 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); + + // `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()); + + 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 the explicit where-clauses + let trait_predicates = + ty_generic_bounds(ccx, + subst::TypeSpace, + &trait_def.generics, + base_predicates, + &generics.where_clause); + + 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>, + trait_items: &[ast::TraitItem]) + -> Vec> + { + trait_items + .iter() + .flat_map(|trait_item| { + let assoc_type_def = match *trait_item { + ast::TypeTraitItem(ref assoc_type) => &assoc_type.ty_param, + ast::RequiredMethod(..) | ast::ProvidedMethod(..) => { + return vec!().into_iter(); + } + }; + + let assoc_ty = ty::mk_projection(ccx.tcx, + self_trait_ref.clone(), + assoc_type_def.ident.name); + + let bounds = compute_bounds(ccx, + assoc_ty, + &*assoc_type_def.bounds, + SizedByDefault::Yes, + assoc_type_def.span); + + ty::predicates(ccx.tcx, assoc_ty, &bounds).into_iter() + }) + .collect() } +} + +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 typ = ccx.to_ty(&ExplicitRscope, &**t); - let scheme = no_params(typ); - - tcx.tcache.borrow_mut().insert(local_def(it.id), scheme.clone()); - return scheme; + 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 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; + 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) => { - 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; + 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)); - 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"); + 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)); - let scheme = TypeScheme { - generics: ty_generics, - ty: t - }; - - tcx.tcache.borrow_mut().insert(local_def(it.id), scheme.clone()); - return scheme; + 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()); } - 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> +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) => { - ty_of_foreign_fn_decl(ccx, - &**fn_decl, - local_def(it.id), - generics, - abi) + 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) + 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> { @@ -1051,15 +1269,25 @@ fn ty_generics_for_type_or_impl<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, subst::TypeSpace, &generics.lifetimes[], &generics.ty_params[], - ty::Generics::empty(), - &generics.where_clause) + 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, - trait_items: &[ast::TraitItem]) + ast_generics: &ast::Generics) -> ty::Generics<'tcx> { debug!("ty_generics_for_trait(trait_id={}, substs={})", @@ -1070,8 +1298,7 @@ fn ty_generics_for_trait<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, subst::TypeSpace, &ast_generics.lifetimes[], &ast_generics.ty_params[], - ty::Generics::empty(), - &ast_generics.where_clause); + ty::Generics::empty()); // Add in the self type parameter. // @@ -1101,49 +1328,7 @@ fn ty_generics_for_trait<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, generics.types.push(subst::SelfSpace, def); - generics.predicates.push(subst::SelfSpace, self_trait_ref.as_predicate()); - - let assoc_predicates = predicates_for_associated_types(ccx, - &self_trait_ref, - trait_items); - - debug!("ty_generics_for_trait: assoc_predicates={}", assoc_predicates.repr(ccx.tcx)); - - for assoc_predicate in assoc_predicates { - generics.predicates.push(subst::TypeSpace, assoc_predicate); - } - return generics; - - fn predicates_for_associated_types<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, - self_trait_ref: &Rc>, - trait_items: &[ast::TraitItem]) - -> Vec> - { - trait_items - .iter() - .flat_map(|trait_item| { - let assoc_type_def = match *trait_item { - ast::TypeTraitItem(ref assoc_type) => &assoc_type.ty_param, - ast::RequiredMethod(..) | ast::ProvidedMethod(..) => { - return vec!().into_iter(); - } - }; - - let assoc_ty = ty::mk_projection(ccx.tcx, - self_trait_ref.clone(), - assoc_type_def.ident.name); - - let bounds = compute_bounds(ccx, - assoc_ty, - &*assoc_type_def.bounds, - SizedByDefault::Yes, - assoc_type_def.span); - - ty::predicates(ccx.tcx, assoc_ty, &bounds).into_iter() - }) - .collect() - } } fn ty_generics_for_fn_or_method<'a,'tcx>(ccx: &CollectCtxt<'a,'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; - - 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); + 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)); + } } - - 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))); - - 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, + tcx, body_scope, &ty::Binder(base_type))); + + //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 From 3e88b5bbf907bdb7d7610d66c27504be92330030 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 11 Feb 2015 10:28:52 -0500 Subject: [PATCH 05/12] Rote changes to fix fallout throughout the compiler from splitting the predicates and renaming some things. --- src/librustc/middle/traits/mod.rs | 2 +- src/librustc/middle/traits/object_safety.rs | 5 +- src/librustc/middle/traits/project.rs | 4 +- src/librustc/middle/traits/select.rs | 8 +- src/librustc/middle/traits/util.rs | 2 +- src/librustc/middle/ty.rs | 31 ++++-- src/librustc/middle/ty_fold.rs | 13 ++- src/librustc_typeck/check/_match.rs | 13 ++- src/librustc_typeck/check/compare_method.rs | 4 +- src/librustc_typeck/check/dropck.rs | 3 +- src/librustc_typeck/check/method/confirm.rs | 29 ++--- src/librustc_typeck/check/method/mod.rs | 2 +- src/librustc_typeck/check/method/probe.rs | 9 +- src/librustc_typeck/check/mod.rs | 112 +++++++++----------- src/librustc_typeck/check/regionck.rs | 4 +- src/librustc_typeck/check/wf.rs | 34 +++--- src/librustc_typeck/coherence/mod.rs | 3 + src/librustc_typeck/lib.rs | 12 --- src/librustdoc/clean/inline.rs | 20 ++-- src/librustdoc/clean/mod.rs | 19 ++-- 20 files changed, 180 insertions(+), 149 deletions(-) diff --git a/src/librustc/middle/traits/mod.rs b/src/librustc/middle/traits/mod.rs index bddbb7c02baa7..395e486059eff 100644 --- a/src/librustc/middle/traits/mod.rs +++ b/src/librustc/middle/traits/mod.rs @@ -283,7 +283,7 @@ pub fn overlapping_impls(infcx: &InferCtxt, /// Creates predicate obligations from the generic bounds. pub fn predicates_for_generics<'tcx>(tcx: &ty::ctxt<'tcx>, cause: ObligationCause<'tcx>, - generic_bounds: &ty::GenericBounds<'tcx>) + generic_bounds: &ty::InstantiatedPredicates<'tcx>) -> PredicateObligations<'tcx> { util::predicates_for_generics(tcx, cause, 0, generic_bounds) diff --git a/src/librustc/middle/traits/object_safety.rs b/src/librustc/middle/traits/object_safety.rs index c88e58266a076..b2701ae875c0c 100644 --- a/src/librustc/middle/traits/object_safety.rs +++ b/src/librustc/middle/traits/object_safety.rs @@ -130,7 +130,10 @@ fn trait_has_sized_self<'tcx>(tcx: &ty::ctxt<'tcx>, // Search for a predicate like `Self : Sized` amongst the trait bounds. let trait_def = ty::lookup_trait_def(tcx, trait_def_id); let free_substs = ty::construct_free_substs(tcx, &trait_def.generics, ast::DUMMY_NODE_ID); - let predicates = trait_def.generics.to_bounds(tcx, &free_substs).predicates.into_vec(); + + let trait_predicates = ty::lookup_predicates(tcx, trait_def_id); + let predicates = trait_predicates.instantiate(tcx, &free_substs).predicates.into_vec(); + elaborate_predicates(tcx, predicates) .any(|predicate| { match predicate { diff --git a/src/librustc/middle/traits/project.rs b/src/librustc/middle/traits/project.rs index 7d02adea1fa5c..13f309e129ac9 100644 --- a/src/librustc/middle/traits/project.rs +++ b/src/librustc/middle/traits/project.rs @@ -561,8 +561,8 @@ fn assemble_candidates_from_trait_def<'cx,'tcx>( }; // If so, extract what we know from the trait and try to come up with a good answer. - let trait_def = ty::lookup_trait_def(selcx.tcx(), trait_ref.def_id); - let bounds = trait_def.generics.to_bounds(selcx.tcx(), trait_ref.substs); + let trait_predicates = ty::lookup_predicates(selcx.tcx(), trait_ref.def_id); + let bounds = trait_predicates.instantiate(selcx.tcx(), trait_ref.substs); assemble_candidates_from_predicates(selcx, obligation, obligation_trait_ref, candidate_set, bounds.predicates.into_vec()); } diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs index 5323a32243642..5f659aa303e90 100644 --- a/src/librustc/middle/traits/select.rs +++ b/src/librustc/middle/traits/select.rs @@ -923,8 +923,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { projection_trait_ref={}", projection_trait_ref.repr(self.tcx())); - let trait_def = ty::lookup_trait_def(self.tcx(), projection_trait_ref.def_id); - let bounds = trait_def.generics.to_bounds(self.tcx(), projection_trait_ref.substs); + let trait_predicates = ty::lookup_predicates(self.tcx(), projection_trait_ref.def_id); + let bounds = trait_predicates.instantiate(self.tcx(), projection_trait_ref.substs); debug!("match_projection_obligation_against_bounds_from_trait: \ bounds={}", bounds.repr(self.tcx())); @@ -2314,8 +2314,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { snapshot: &infer::CombinedSnapshot) -> VecPerParamSpace> { - let impl_generics = ty::lookup_item_type(self.tcx(), impl_def_id).generics; - let bounds = impl_generics.to_bounds(self.tcx(), impl_substs); + let impl_bounds = ty::lookup_predicates(self.tcx(), impl_def_id); + let bounds = impl_bounds.instantiate(self.tcx(), impl_substs); let normalized_bounds = project::normalize_with_depth(self, cause.clone(), recursion_depth, &bounds); let normalized_bounds = diff --git a/src/librustc/middle/traits/util.rs b/src/librustc/middle/traits/util.rs index 573efa727569e..6c54da1c134f5 100644 --- a/src/librustc/middle/traits/util.rs +++ b/src/librustc/middle/traits/util.rs @@ -290,7 +290,7 @@ impl<'tcx> fmt::Debug for super::VtableObjectData<'tcx> { pub fn predicates_for_generics<'tcx>(tcx: &ty::ctxt<'tcx>, cause: ObligationCause<'tcx>, recursion_depth: uint, - generic_bounds: &ty::GenericBounds<'tcx>) + generic_bounds: &ty::InstantiatedPredicates<'tcx>) -> VecPerParamSpace> { debug!("predicates_for_generics(generic_bounds={})", diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index af80ce65474f5..6026359ddace0 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -2153,10 +2153,12 @@ impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> { match ty::impl_or_trait_item(cx, method_def_id) { MethodTraitItem(ref method_ty) => { let method_generics = &method_ty.generics; + let method_bounds = &method_ty.predicates; construct_parameter_environment( cx, method.span, method_generics, + method_bounds, method.pe_body().id) } TypeTraitItem(_) => { @@ -2188,10 +2190,12 @@ impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> { match ty::impl_or_trait_item(cx, method_def_id) { MethodTraitItem(ref method_ty) => { let method_generics = &method_ty.generics; + let method_bounds = &method_ty.predicates; construct_parameter_environment( cx, method.span, method_generics, + method_bounds, method.pe_body().id) } TypeTraitItem(_) => { @@ -2214,11 +2218,13 @@ impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> { ast::ItemFn(_, _, _, _, ref body) => { // We assume this is a function. let fn_def_id = ast_util::local_def(id); - let fn_pty = ty::lookup_item_type(cx, fn_def_id); + let fn_scheme = lookup_item_type(cx, fn_def_id); + let fn_predicates = lookup_predicates(cx, fn_def_id); construct_parameter_environment(cx, item.span, - &fn_pty.generics, + &fn_scheme.generics, + &fn_predicates, body.id) } ast::ItemEnum(..) | @@ -2227,8 +2233,13 @@ impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> { ast::ItemConst(..) | ast::ItemStatic(..) => { let def_id = ast_util::local_def(id); - let pty = ty::lookup_item_type(cx, def_id); - construct_parameter_environment(cx, item.span, &pty.generics, id) + let scheme = lookup_item_type(cx, def_id); + let predicates = lookup_predicates(cx, def_id); + construct_parameter_environment(cx, + item.span, + &scheme.generics, + &predicates, + id) } _ => { cx.sess.span_bug(item.span, @@ -6320,7 +6331,7 @@ pub fn empty_parameter_environment<'a,'tcx>(cx: &'a ctxt<'tcx>) -> ParameterEnvi /// parameters in the same way, this only has an effect on regions. pub fn construct_free_substs<'a,'tcx>( tcx: &'a ctxt<'tcx>, - generics: &ty::Generics<'tcx>, + generics: &Generics<'tcx>, free_id: ast::NodeId) -> Substs<'tcx> { @@ -6365,6 +6376,7 @@ pub fn construct_parameter_environment<'a,'tcx>( tcx: &'a ctxt<'tcx>, span: Span, generics: &ty::Generics<'tcx>, + generic_predicates: &ty::GenericPredicates<'tcx>, free_id: ast::NodeId) -> ParameterEnvironment<'a, 'tcx> { @@ -6379,7 +6391,7 @@ pub fn construct_parameter_environment<'a,'tcx>( // Compute the bounds on Self and the type parameters. // - let bounds = generics.to_bounds(tcx, &free_substs); + let bounds = generic_predicates.instantiate(tcx, &free_substs); let bounds = liberate_late_bound_regions(tcx, free_id_outlive, &ty::Binder(bounds)); let predicates = bounds.predicates.into_vec(); @@ -7013,8 +7025,7 @@ impl<'tcx,T:RegionEscape> RegionEscape for VecPerParamSpace { impl<'tcx> RegionEscape for TypeScheme<'tcx> { fn has_regions_escaping_depth(&self, depth: u32) -> bool { - self.ty.has_regions_escaping_depth(depth) || - self.generics.has_regions_escaping_depth(depth) + self.ty.has_regions_escaping_depth(depth) } } @@ -7024,7 +7035,7 @@ impl RegionEscape for Region { } } -impl<'tcx> RegionEscape for Generics<'tcx> { +impl<'tcx> RegionEscape for GenericPredicates<'tcx> { fn has_regions_escaping_depth(&self, depth: u32) -> bool { self.predicates.has_regions_escaping_depth(depth) } @@ -7133,7 +7144,7 @@ impl<'tcx> HasProjectionTypes for ClosureUpvar<'tcx> { } } -impl<'tcx> HasProjectionTypes for ty::GenericBounds<'tcx> { +impl<'tcx> HasProjectionTypes for ty::InstantiatedPredicates<'tcx> { fn has_projection_types(&self) -> bool { self.predicates.has_projection_types() } diff --git a/src/librustc/middle/ty_fold.rs b/src/librustc/middle/ty_fold.rs index 69d32c3f5fc33..645a7ab9440b9 100644 --- a/src/librustc/middle/ty_fold.rs +++ b/src/librustc/middle/ty_fold.rs @@ -400,6 +400,13 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Generics<'tcx> { ty::Generics { types: self.types.fold_with(folder), regions: self.regions.fold_with(folder), + } + } +} + +impl<'tcx> TypeFoldable<'tcx> for ty::GenericPredicates<'tcx> { + fn fold_with>(&self, folder: &mut F) -> ty::GenericPredicates<'tcx> { + ty::GenericPredicates { predicates: self.predicates.fold_with(folder), } } @@ -440,9 +447,9 @@ impl<'tcx> TypeFoldable<'tcx> for ty::ProjectionTy<'tcx> { } } -impl<'tcx> TypeFoldable<'tcx> for ty::GenericBounds<'tcx> { - fn fold_with>(&self, folder: &mut F) -> ty::GenericBounds<'tcx> { - ty::GenericBounds { +impl<'tcx> TypeFoldable<'tcx> for ty::InstantiatedPredicates<'tcx> { + fn fold_with>(&self, folder: &mut F) -> ty::InstantiatedPredicates<'tcx> { + ty::InstantiatedPredicates { predicates: self.predicates.fold_with(folder), } } diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 1249e0d8ce1e5..3ea2743c63e6c 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -467,8 +467,14 @@ pub fn check_pat_struct<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, pat: &'tcx ast::Pat, } }; - instantiate_path(pcx.fcx, path, ty::lookup_item_type(tcx, enum_def_id), - None, def, pat.span, pat.id); + instantiate_path(pcx.fcx, + path, + ty::lookup_item_type(tcx, enum_def_id), + &ty::lookup_predicates(tcx, enum_def_id), + None, + def, + pat.span, + pat.id); let pat_ty = fcx.node_ty(pat.id); demand::eqtype(fcx, pat.span, expected, pat_ty); @@ -499,6 +505,7 @@ pub fn check_pat_enum<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, .map_or_else(|| def.def_id(), |(enum_def, _)| enum_def); let ctor_scheme = ty::lookup_item_type(tcx, enum_def); + let ctor_predicates = ty::lookup_predicates(tcx, enum_def); let path_scheme = if ty::is_fn_ty(ctor_scheme.ty) { let fn_ret = ty::assert_no_late_bound_regions(tcx, &ty::ty_fn_ret(ctor_scheme.ty)); ty::TypeScheme { @@ -508,7 +515,7 @@ pub fn check_pat_enum<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, } else { ctor_scheme }; - instantiate_path(pcx.fcx, path, path_scheme, None, def, pat.span, pat.id); + instantiate_path(pcx.fcx, path, path_scheme, &ctor_predicates, None, def, pat.span, pat.id); let pat_ty = fcx.node_ty(pat.id); demand::eqtype(fcx, pat.span, expected, pat_ty); diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index a5b938c7600c2..1e1d7e0926038 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -205,7 +205,7 @@ pub fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>, // however, because we want to replace all late-bound regions with // region variables. let impl_bounds = - impl_m.generics.to_bounds(tcx, impl_to_skol_substs); + impl_m.predicates.instantiate(tcx, impl_to_skol_substs); let (impl_bounds, _) = infcx.replace_late_bound_regions_with_fresh_var( @@ -216,7 +216,7 @@ pub fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>, impl_bounds.repr(tcx)); // Normalize the associated types in the trait_bounds. - let trait_bounds = trait_m.generics.to_bounds(tcx, &trait_to_skol_substs); + let trait_bounds = trait_m.predicates.instantiate(tcx, &trait_to_skol_substs); // Obtain the predicate split predicate sets for each. let trait_pred = trait_bounds.predicates.split(); diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index 1be6bf05c9962..ce67369ca9dda 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -131,8 +131,9 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'tcx>( let dtor_typescheme = ty::lookup_item_type(rcx.tcx(), impl_did); let dtor_generics = dtor_typescheme.generics; + let dtor_predicates = ty::lookup_predicates(rcx.tcx(), impl_did); - let has_pred_of_interest = dtor_generics.predicates.iter().any(|pred| { + let has_pred_of_interest = dtor_predicates.predicates.iter().any(|pred| { // In `impl Drop where ...`, we automatically // assume some predicate will be meaningful and thus // represents a type through which we could reach diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index 77701af25d39a..dfbfc86c65970 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -46,7 +46,7 @@ struct InstantiatedMethodSig<'tcx> { /// Generic bounds on the method's parameters which must be added /// as pending obligations. - method_bounds: ty::GenericBounds<'tcx>, + method_predicates: ty::InstantiatedPredicates<'tcx>, } pub fn confirm<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, @@ -99,7 +99,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { // Create the final signature for the method, replacing late-bound regions. let InstantiatedMethodSig { - method_sig, all_substs, method_bounds + method_sig, all_substs, method_predicates } = self.instantiate_method_sig(&pick, all_substs); let method_self_ty = method_sig.inputs[0]; @@ -107,7 +107,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { self.unify_receivers(self_ty, method_self_ty); // Add any trait/regions obligations specified on the method's type parameters. - self.add_obligations(&pick, &all_substs, &method_bounds); + self.add_obligations(&pick, &all_substs, &method_predicates); // Create the final `MethodCallee`. let fty = ty::mk_bare_fn(self.tcx(), None, self.tcx().mk_bare_fn(ty::BareFnTy { @@ -416,18 +416,19 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { // that obligation is not necessarily satisfied. (In the // future, it would be.) But we know that the true `Self` DOES implement // the trait. So we just delete this requirement. Hack hack hack. - let mut method_bounds = pick.method_ty.generics.to_bounds(self.tcx(), &all_substs); + let mut method_predicates = pick.method_ty.predicates.instantiate(self.tcx(), &all_substs); match pick.kind { probe::ObjectPick(..) => { - assert_eq!(method_bounds.predicates.get_slice(subst::SelfSpace).len(), 1); - method_bounds.predicates.pop(subst::SelfSpace); + assert_eq!(method_predicates.predicates.get_slice(subst::SelfSpace).len(), 1); + method_predicates.predicates.pop(subst::SelfSpace); } _ => { } } - let method_bounds = self.fcx.normalize_associated_types_in(self.span, &method_bounds); + let method_predicates = self.fcx.normalize_associated_types_in(self.span, + &method_predicates); - debug!("method_bounds after subst = {}", - method_bounds.repr(self.tcx())); + debug!("method_predicates after subst = {}", + method_predicates.repr(self.tcx())); // Instantiate late-bound regions and substitute the trait // parameters into the method type to get the actual method type. @@ -446,22 +447,22 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { InstantiatedMethodSig { method_sig: method_sig, all_substs: all_substs, - method_bounds: method_bounds, + method_predicates: method_predicates, } } fn add_obligations(&mut self, pick: &probe::Pick<'tcx>, all_substs: &subst::Substs<'tcx>, - method_bounds: &ty::GenericBounds<'tcx>) { - debug!("add_obligations: pick={} all_substs={} method_bounds={}", + method_predicates: &ty::InstantiatedPredicates<'tcx>) { + debug!("add_obligations: pick={} all_substs={} method_predicates={}", pick.repr(self.tcx()), all_substs.repr(self.tcx()), - method_bounds.repr(self.tcx())); + method_predicates.repr(self.tcx())); self.fcx.add_obligations_for_parameters( traits::ObligationCause::misc(self.span, self.fcx.body_id), - method_bounds); + method_predicates); self.fcx.add_default_region_param_bounds( all_substs, diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index 88455b3385a1e..55b4dae5b9eb1 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -221,7 +221,7 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // // Note that as the method comes from a trait, it should not have // any late-bound regions appearing in its bounds. - let method_bounds = fcx.instantiate_bounds(span, trait_ref.substs, &method_ty.generics); + let method_bounds = fcx.instantiate_bounds(span, trait_ref.substs, &method_ty.predicates); assert!(!method_bounds.has_escaping_regions()); fcx.add_obligations_for_parameters( traits::ObligationCause::misc(span, fcx.body_id), diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index cfc04a9a92fb6..82bd4ae87ffae 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -666,8 +666,9 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { debug!("assemble_projection_candidates: projection_trait_ref={}", projection_trait_ref.repr(self.tcx())); - let trait_def = ty::lookup_trait_def(self.tcx(), projection_trait_ref.def_id); - let bounds = trait_def.generics.to_bounds(self.tcx(), projection_trait_ref.substs); + let trait_predicates = ty::lookup_predicates(self.tcx(), + projection_trait_ref.def_id); + let bounds = trait_predicates.instantiate(self.tcx(), projection_trait_ref.substs); let predicates = bounds.predicates.into_vec(); debug!("assemble_projection_candidates: predicates={}", predicates.repr(self.tcx())); @@ -943,8 +944,8 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { let cause = traits::ObligationCause::misc(self.span, self.fcx.body_id); // Check whether the impl imposes obligations we have to worry about. - let impl_generics = ty::lookup_item_type(self.tcx(), impl_def_id).generics; - let impl_bounds = impl_generics.to_bounds(self.tcx(), substs); + let impl_bounds = ty::lookup_predicates(self.tcx(), impl_def_id); + let impl_bounds = impl_bounds.instantiate(self.tcx(), substs); let traits::Normalized { value: impl_bounds, obligations: norm_obligations } = traits::normalize(selcx, cause.clone(), &impl_bounds); diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index d90ed7eda599e..00bc3375fdd9f 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -93,7 +93,7 @@ use middle::pat_util::{self, pat_id_map}; use middle::region::{self, CodeExtent}; use middle::subst::{self, Subst, Substs, VecPerParamSpace, ParamSpace, TypeSpace}; use middle::traits; -use middle::ty::{FnSig, VariantInfo, TypeScheme}; +use middle::ty::{FnSig, GenericPredicates, VariantInfo, TypeScheme}; use middle::ty::{Disr, ParamTy, ParameterEnvironment}; use middle::ty::{self, HasProjectionTypes, RegionEscape, Ty}; use middle::ty::liberate_late_bound_regions; @@ -101,7 +101,7 @@ use middle::ty::{MethodCall, MethodCallee, MethodMap, ObjectCastMap}; use middle::ty_fold::{TypeFolder, TypeFoldable}; use rscope::RegionScope; use session::Session; -use {CrateCtxt, lookup_def_ccx, no_params, require_same_types}; +use {CrateCtxt, lookup_def_ccx, require_same_types}; use TypeAndSubsts; use lint; use util::common::{block_query, indenter, loop_query}; @@ -1446,11 +1446,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn instantiate_bounds(&self, span: Span, substs: &Substs<'tcx>, - generics: &ty::Generics<'tcx>) - -> ty::GenericBounds<'tcx> + bounds: &ty::GenericPredicates<'tcx>) + -> ty::InstantiatedPredicates<'tcx> { - ty::GenericBounds { - predicates: self.instantiate_type_scheme(span, substs, &generics.predicates) + ty::InstantiatedPredicates { + predicates: self.instantiate_type_scheme(span, substs, &bounds.predicates) } } @@ -1561,12 +1561,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { { let type_scheme = ty::lookup_item_type(self.tcx(), def_id); + let type_predicates = + ty::lookup_predicates(self.tcx(), def_id); let substs = self.infcx().fresh_substs_for_generics( span, &type_scheme.generics); let bounds = - self.instantiate_bounds(span, &substs, &type_scheme.generics); + self.instantiate_bounds(span, &substs, &type_predicates); self.add_obligations_for_parameters( traits::ObligationCause::new( span, @@ -1594,7 +1596,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { { let tcx = self.tcx(); - let ty::TypeScheme { generics, ty: decl_ty } = ty::lookup_item_type(tcx, did); + let ty::TypeScheme { generics, ty: decl_ty } = + ty::lookup_item_type(tcx, did); let wants_params = generics.has_type_params(TypeSpace) || generics.has_region_params(TypeSpace); @@ -1843,16 +1846,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// and `T`. This routine will add a region obligation `$1:'$0` and register it locally. pub fn add_obligations_for_parameters(&self, cause: traits::ObligationCause<'tcx>, - generic_bounds: &ty::GenericBounds<'tcx>) + predicates: &ty::InstantiatedPredicates<'tcx>) { - assert!(!generic_bounds.has_escaping_regions()); + assert!(!predicates.has_escaping_regions()); - debug!("add_obligations_for_parameters(generic_bounds={})", - generic_bounds.repr(self.tcx())); + debug!("add_obligations_for_parameters(predicates={})", + predicates.repr(self.tcx())); let obligations = traits::predicates_for_generics(self.tcx(), cause, - generic_bounds); + predicates); obligations.map_move(|o| self.register_predicate(o)); } @@ -3616,8 +3619,8 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, } ast::ExprPath(ref path) => { let defn = lookup_def(fcx, path.span, id); - let pty = type_scheme_for_def(fcx, expr.span, defn); - instantiate_path(fcx, path, pty, None, defn, expr.span, expr.id); + let (scheme, predicates) = type_scheme_and_predicates_for_def(fcx, expr.span, defn); + instantiate_path(fcx, path, scheme, &predicates, None, defn, expr.span, expr.id); // We always require that the type provided as the value for // a type parameter outlives the moment of instantiation. @@ -3629,10 +3632,10 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, astconv::instantiate_trait_ref(fcx, fcx, &*qpath.trait_ref, Some(self_ty), None); let defn = lookup_def(fcx, expr.span, id); - let pty = type_scheme_for_def(fcx, expr.span, defn); + let (scheme, predicates) = type_scheme_and_predicates_for_def(fcx, expr.span, defn); let mut path = qpath.trait_ref.path.clone(); path.segments.push(qpath.item_path.clone()); - instantiate_path(fcx, &path, pty, Some(self_ty), defn, expr.span, expr.id); + instantiate_path(fcx, &path, scheme, &predicates, Some(self_ty), defn, expr.span, expr.id); // We always require that the type provided as the value for // a type parameter outlives the moment of instantiation. @@ -4048,9 +4051,9 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, }; if let Some(did) = did { - let polytype = ty::lookup_item_type(tcx, did); + let predicates = ty::lookup_predicates(tcx, did); let substs = Substs::new_type(vec![idx_type], vec![]); - let bounds = fcx.instantiate_bounds(expr.span, &substs, &polytype.generics); + let bounds = fcx.instantiate_bounds(expr.span, &substs, &predicates); fcx.add_obligations_for_parameters( traits::ObligationCause::new(expr.span, fcx.body_id, @@ -4631,46 +4634,36 @@ pub fn lookup_def(fcx: &FnCtxt, sp: Span, id: ast::NodeId) -> def::Def { } // Returns the type parameter count and the type for the given definition. -pub fn type_scheme_for_def<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, - sp: Span, - defn: def::Def) - -> TypeScheme<'tcx> { +fn type_scheme_and_predicates_for_def<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, + sp: Span, + defn: def::Def) + -> (TypeScheme<'tcx>, GenericPredicates<'tcx>) { match defn { - def::DefLocal(nid) | def::DefUpvar(nid, _) => { - let typ = fcx.local_ty(sp, nid); - return no_params(typ); - } - def::DefFn(id, _) | def::DefStaticMethod(id, _) | def::DefMethod(id, _, _) | - def::DefStatic(id, _) | def::DefVariant(_, id, _) | - def::DefStruct(id) | def::DefConst(id) => { - return ty::lookup_item_type(fcx.ccx.tcx, id); - } - def::DefTrait(_) | - def::DefTy(..) | - def::DefAssociatedTy(..) | - def::DefAssociatedPath(..) | - def::DefPrimTy(_) | - def::DefTyParam(..) => { - fcx.ccx.tcx.sess.span_bug(sp, "expected value, found type"); - } - def::DefMod(..) | def::DefForeignMod(..) => { - fcx.ccx.tcx.sess.span_bug(sp, "expected value, found module"); - } - def::DefUse(..) => { - fcx.ccx.tcx.sess.span_bug(sp, "expected value, found use"); - } - def::DefRegion(..) => { - fcx.ccx.tcx.sess.span_bug(sp, "expected value, found region"); - } - def::DefTyParamBinder(..) => { - fcx.ccx.tcx.sess.span_bug(sp, "expected value, found type parameter"); - } - def::DefLabel(..) => { - fcx.ccx.tcx.sess.span_bug(sp, "expected value, found label"); - } - def::DefSelfTy(..) => { - fcx.ccx.tcx.sess.span_bug(sp, "expected value, found self ty"); - } + def::DefLocal(nid) | def::DefUpvar(nid, _) => { + let typ = fcx.local_ty(sp, nid); + (ty::TypeScheme { generics: ty::Generics::empty(), ty: typ }, + ty::GenericPredicates::empty()) + } + def::DefFn(id, _) | def::DefStaticMethod(id, _) | def::DefMethod(id, _, _) | + def::DefStatic(id, _) | def::DefVariant(_, id, _) | + def::DefStruct(id) | def::DefConst(id) => { + (ty::lookup_item_type(fcx.tcx(), id), ty::lookup_predicates(fcx.tcx(), id)) + } + def::DefTrait(_) | + def::DefTy(..) | + def::DefAssociatedTy(..) | + def::DefAssociatedPath(..) | + def::DefPrimTy(_) | + def::DefTyParam(..) | + def::DefMod(..) | + def::DefForeignMod(..) | + def::DefUse(..) | + def::DefRegion(..) | + def::DefTyParamBinder(..) | + def::DefLabel(..) | + def::DefSelfTy(..) => { + fcx.ccx.tcx.sess.span_bug(sp, &format!("expected value, found {:?}", defn)); + } } } @@ -4679,6 +4672,7 @@ pub fn type_scheme_for_def<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, path: &ast::Path, type_scheme: TypeScheme<'tcx>, + type_predicates: &ty::GenericPredicates<'tcx>, opt_self_ty: Option>, def: def::Def, span: Span, @@ -4864,7 +4858,7 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // Add all the obligations that are required, substituting and // normalized appropriately. - let bounds = fcx.instantiate_bounds(span, &substs, &type_scheme.generics); + let bounds = fcx.instantiate_bounds(span, &substs, &type_predicates); fcx.add_obligations_for_parameters( traits::ObligationCause::new(span, fcx.body_id, traits::ItemObligation(def.def_id())), &bounds); diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index 80f6e3800f713..bcb2ba6231df3 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -1588,8 +1588,8 @@ fn projection_bounds<'a,'tcx>(rcx: &Rcx<'a, 'tcx>, // ``` // // we can thus deduce that `>::SomeType : 'a`. - let trait_def = ty::lookup_trait_def(tcx, projection_ty.trait_ref.def_id); - let predicates = trait_def.generics.predicates.as_slice().to_vec(); + let trait_predicates = ty::lookup_predicates(tcx, projection_ty.trait_ref.def_id); + let predicates = trait_predicates.predicates.as_slice().to_vec(); traits::elaborate_predicates(tcx, predicates) .filter_map(|predicate| { // we're only interesting in `T : 'a` style predicates: diff --git a/src/librustc_typeck/check/wf.rs b/src/librustc_typeck/check/wf.rs index 923614f9e8a74..94670305be755 100644 --- a/src/librustc_typeck/check/wf.rs +++ b/src/librustc_typeck/check/wf.rs @@ -107,12 +107,12 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { }); } ast::ItemTrait(..) => { - let trait_def = - ty::lookup_trait_def(ccx.tcx, local_def(item.id)); + let trait_predicates = + ty::lookup_predicates(ccx.tcx, local_def(item.id)); reject_non_type_param_bounds( ccx.tcx, item.span, - &trait_def.generics); + &trait_predicates); } _ => {} } @@ -124,11 +124,13 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { let ccx = self.ccx; let item_def_id = local_def(item.id); let type_scheme = ty::lookup_item_type(ccx.tcx, item_def_id); - reject_non_type_param_bounds(ccx.tcx, item.span, &type_scheme.generics); + let type_predicates = ty::lookup_predicates(ccx.tcx, item_def_id); + reject_non_type_param_bounds(ccx.tcx, item.span, &type_predicates); let param_env = ty::construct_parameter_environment(ccx.tcx, item.span, &type_scheme.generics, + &type_predicates, item.id); let inh = Inherited::new(ccx.tcx, param_env); let fcx = blank_fn_ctxt(ccx, &inh, ty::FnConverging(type_scheme.ty), item.id); @@ -283,9 +285,8 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { // Reject any predicates that do not involve a type parameter. fn reject_non_type_param_bounds<'tcx>(tcx: &ty::ctxt<'tcx>, span: Span, - generics: &ty::Generics<'tcx>) { - - for predicate in generics.predicates.iter() { + predicates: &ty::GenericPredicates<'tcx>) { + for predicate in predicates.predicates.iter() { match predicate { &ty::Predicate::Trait(ty::Binder(ref tr)) => { let found_param = tr.input_types().iter() @@ -367,7 +368,7 @@ impl<'ccx, 'tcx, 'v> Visitor<'v> for CheckTypeWellFormedVisitor<'ccx, 'tcx> { reject_non_type_param_bounds( self.ccx.tcx, method.span, - &ty_method.generics); + &ty_method.predicates); reject_shadowing_type_parameters( self.ccx.tcx, method.span, @@ -415,9 +416,11 @@ impl<'cx,'tcx> BoundsChecker<'cx,'tcx> { /// Note that it does not (currently, at least) check that `A : Copy` (that check is delegated /// to the point where impl `A : Trait` is implemented). pub fn check_trait_ref(&mut self, trait_ref: &ty::TraitRef<'tcx>) { - let trait_def = ty::lookup_trait_def(self.fcx.tcx(), trait_ref.def_id); + let trait_predicates = ty::lookup_predicates(self.fcx.tcx(), trait_ref.def_id); - let bounds = self.fcx.instantiate_bounds(self.span, trait_ref.substs, &trait_def.generics); + let bounds = self.fcx.instantiate_bounds(self.span, + trait_ref.substs, + &trait_predicates); self.fcx.add_obligations_for_parameters( traits::ObligationCause::new( @@ -482,8 +485,9 @@ impl<'cx,'tcx> TypeFolder<'tcx> for BoundsChecker<'cx,'tcx> { match t.sty{ ty::ty_struct(type_id, substs) | ty::ty_enum(type_id, substs) => { - let type_scheme = ty::lookup_item_type(self.fcx.tcx(), type_id); - let bounds = self.fcx.instantiate_bounds(self.span, substs, &type_scheme.generics); + let type_predicates = ty::lookup_predicates(self.fcx.tcx(), type_id); + let bounds = self.fcx.instantiate_bounds(self.span, substs, + &type_predicates); if self.binding_count == 0 { self.fcx.add_obligations_for_parameters( @@ -603,10 +607,10 @@ fn enum_variants<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, .collect() } -fn filter_to_trait_obligations<'tcx>(bounds: ty::GenericBounds<'tcx>) - -> ty::GenericBounds<'tcx> +fn filter_to_trait_obligations<'tcx>(bounds: ty::InstantiatedPredicates<'tcx>) + -> ty::InstantiatedPredicates<'tcx> { - let mut result = ty::GenericBounds::empty(); + let mut result = ty::InstantiatedPredicates::empty(); for (space, _, predicate) in bounds.predicates.iter_enumerated() { match *predicate { ty::Predicate::Trait(..) | diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index ed340b0882ca3..1542e74ff8167 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -247,6 +247,7 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { debug!("new_polytype={}", new_polytype.repr(tcx)); tcx.tcache.borrow_mut().insert(new_did, new_polytype); + tcx.predicates.borrow_mut().insert(new_did, new_method_ty.predicates.clone()); tcx.impl_or_trait_items .borrow_mut() .insert(new_did, ty::MethodTraitItem(new_method_ty)); @@ -555,6 +556,7 @@ fn subst_receiver_types_in_method_ty<'tcx>(tcx: &ty::ctxt<'tcx>, debug!("subst_receiver_types_in_method_ty: combined_substs={}", combined_substs.repr(tcx)); + let method_predicates = method.predicates.subst(tcx, &combined_substs); let mut method_generics = method.generics.subst(tcx, &combined_substs); // replace the type parameters declared on the trait with those @@ -579,6 +581,7 @@ fn subst_receiver_types_in_method_ty<'tcx>(tcx: &ty::ctxt<'tcx>, ty::Method::new( method.name, method_generics, + method_predicates, method_fty, method.explicit_self, method.vis, diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 5ad2dc2871c52..ccfadaba2440b 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -102,7 +102,6 @@ pub use rustc::util; use middle::def; use middle::infer; use middle::subst; -use middle::subst::VecPerParamSpace; use middle::ty::{self, Ty}; use session::config; use util::common::time; @@ -177,17 +176,6 @@ fn lookup_def_ccx(ccx: &CrateCtxt, sp: Span, id: ast::NodeId) lookup_def_tcx(ccx.tcx, sp, id) } -fn no_params<'tcx>(t: Ty<'tcx>) -> ty::TypeScheme<'tcx> { - ty::TypeScheme { - generics: ty::Generics { - types: VecPerParamSpace::empty(), - regions: VecPerParamSpace::empty(), - predicates: VecPerParamSpace::empty(), - }, - ty: t - } -} - fn require_same_types<'a, 'tcx, M>(tcx: &ty::ctxt<'tcx>, maybe_infcx: Option<&infer::InferCtxt<'a, 'tcx>>, t1_is_expected: bool, diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index dfa5b01270efd..d1283d6f46bd8 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -166,10 +166,11 @@ pub fn build_external_trait(cx: &DocContext, tcx: &ty::ctxt, } }); let trait_def = ty::lookup_trait_def(tcx, did); + let predicates = ty::lookup_predicates(tcx, did); let bounds = trait_def.bounds.clean(cx); clean::Trait { unsafety: def.unsafety, - generics: (&def.generics, subst::TypeSpace).clean(cx), + generics: (&def.generics, &predicates, subst::TypeSpace).clean(cx), items: items.collect(), bounds: bounds, } @@ -181,9 +182,10 @@ fn build_external_function(cx: &DocContext, tcx: &ty::ctxt, did: ast::DefId) -> ty::ty_bare_fn(_, ref f) => ((did, &f.sig).clean(cx), f.unsafety), _ => panic!("bad function"), }; + let predicates = ty::lookup_predicates(tcx, did); clean::Function { decl: decl, - generics: (&t.generics, subst::FnSpace).clean(cx), + generics: (&t.generics, &predicates, subst::FnSpace).clean(cx), unsafety: style, } } @@ -192,6 +194,7 @@ fn build_struct(cx: &DocContext, tcx: &ty::ctxt, did: ast::DefId) -> clean::Stru use syntax::parse::token::special_idents::unnamed_field; let t = ty::lookup_item_type(tcx, did); + let predicates = ty::lookup_predicates(tcx, did); let fields = ty::lookup_struct_fields(tcx, did); clean::Struct { @@ -201,7 +204,7 @@ fn build_struct(cx: &DocContext, tcx: &ty::ctxt, did: ast::DefId) -> clean::Stru [ref f, ..] if f.name == unnamed_field.name => doctree::Tuple, _ => doctree::Plain, }, - generics: (&t.generics, subst::TypeSpace).clean(cx), + generics: (&t.generics, &predicates, subst::TypeSpace).clean(cx), fields: fields.clean(cx), fields_stripped: false, } @@ -209,10 +212,11 @@ fn build_struct(cx: &DocContext, tcx: &ty::ctxt, did: ast::DefId) -> clean::Stru fn build_type(cx: &DocContext, tcx: &ty::ctxt, did: ast::DefId) -> clean::ItemEnum { let t = ty::lookup_item_type(tcx, did); + let predicates = ty::lookup_predicates(tcx, did); match t.ty.sty { ty::ty_enum(edid, _) if !csearch::is_typedef(&tcx.sess.cstore, did) => { return clean::EnumItem(clean::Enum { - generics: (&t.generics, subst::TypeSpace).clean(cx), + generics: (&t.generics, &predicates, subst::TypeSpace).clean(cx), variants_stripped: false, variants: ty::enum_variants(tcx, edid).clean(cx), }) @@ -222,7 +226,7 @@ fn build_type(cx: &DocContext, tcx: &ty::ctxt, did: ast::DefId) -> clean::ItemEn clean::TypedefItem(clean::Typedef { type_: t.ty.clean(cx), - generics: (&t.generics, subst::TypeSpace).clean(cx), + generics: (&t.generics, &predicates, subst::TypeSpace).clean(cx), }) } @@ -293,6 +297,7 @@ fn build_impl(cx: &DocContext, tcx: &ty::ctxt, let attrs = load_attrs(cx, tcx, did); let ty = ty::lookup_item_type(tcx, did); + let predicates = ty::lookup_predicates(tcx, did); let trait_items = csearch::get_impl_items(&tcx.sess.cstore, did) .iter() .filter_map(|did| { @@ -323,9 +328,10 @@ fn build_impl(cx: &DocContext, tcx: &ty::ctxt, ty::TypeTraitItem(ref assoc_ty) => { let did = assoc_ty.def_id; let type_scheme = ty::lookup_item_type(tcx, did); + let predicates = ty::lookup_predicates(tcx, did); // Not sure the choice of ParamSpace actually matters here, because an // associated type won't have generics on the LHS - let typedef = (type_scheme, subst::ParamSpace::TypeSpace).clean(cx); + let typedef = (type_scheme, predicates, subst::ParamSpace::TypeSpace).clean(cx); Some(clean::Item { name: Some(assoc_ty.name.clean(cx)), inner: clean::TypedefItem(typedef), @@ -349,7 +355,7 @@ fn build_impl(cx: &DocContext, tcx: &ty::ctxt, } }), for_: ty.ty.clean(cx), - generics: (&ty.generics, subst::TypeSpace).clean(cx), + generics: (&ty.generics, &predicates, subst::TypeSpace).clean(cx), items: trait_items, polarity: polarity.map(|p| { p.clean(cx) }), }), diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 7ab9d8c6672c4..6c3d2d8fa19d1 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -860,7 +860,9 @@ impl Clean for ast::Generics { } } -impl<'a, 'tcx> Clean for (&'a ty::Generics<'tcx>, subst::ParamSpace) { +impl<'a, 'tcx> Clean for (&'a ty::Generics<'tcx>, + &'a ty::GenericPredicates<'tcx>, + subst::ParamSpace) { fn clean(&self, cx: &DocContext) -> Generics { use std::collections::HashSet; use syntax::ast::TraitBoundModifier as TBM; @@ -885,7 +887,8 @@ impl<'a, 'tcx> Clean for (&'a ty::Generics<'tcx>, subst::ParamSpace) { false } - let (gens, space) = *self; + let (gens, preds, space) = *self; + // 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| { @@ -899,7 +902,8 @@ impl<'a, 'tcx> Clean for (&'a ty::Generics<'tcx>, subst::ParamSpace) { srp.clean(cx) }).collect::>(); - let where_predicates = gens.predicates.get_slice(space).to_vec().clean(cx); + let where_predicates = preds.predicates.get_slice(space).to_vec().clean(cx); + // Type parameters have a Sized bound by default unless removed with ?Sized. // Scan through the predicates and mark any type parameter with a Sized // bound, removing the bounds as we find them. @@ -913,6 +917,7 @@ impl<'a, 'tcx> Clean for (&'a ty::Generics<'tcx>, subst::ParamSpace) { } Some(pred) }).collect::>(); + // Finally, run through the type parameters again and insert a ?Sized unbound for // any we didn't find to be Sized. for tp in &stripped_typarams { @@ -1303,7 +1308,7 @@ impl<'tcx> Clean for ty::Method<'tcx> { source: Span::empty(), inner: TyMethodItem(TyMethod { unsafety: self.fty.unsafety, - generics: (&self.generics, subst::FnSpace).clean(cx), + generics: (&self.generics, &self.predicates, subst::FnSpace).clean(cx), self_: self_, decl: (self.def_id, &sig).clean(cx), abi: self.fty.abi @@ -2560,12 +2565,12 @@ impl Clean for ast::Typedef { } } -impl<'a> Clean for (ty::TypeScheme<'a>, ParamSpace) { +impl<'a> Clean for (ty::TypeScheme<'a>, ty::GenericPredicates<'a>, ParamSpace) { fn clean(&self, cx: &DocContext) -> Typedef { - let (ref ty_scheme, ps) = *self; + let (ref ty_scheme, ref predicates, ps) = *self; Typedef { type_: ty_scheme.ty.clean(cx), - generics: (&ty_scheme.generics, ps).clean(cx) + generics: (&ty_scheme.generics, predicates, ps).clean(cx) } } } From a6c295cb22d4c76c0b58a7f0fbca104b7dcbfdc4 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 11 Feb 2015 10:29:46 -0500 Subject: [PATCH 06/12] Modify `repr()` so that when `-Z verbose` is used, at least, it does not fetch trait definitions. This allows is to be used early in the compiler without triggering ICEs. Also make -Z verbose less horrifyingly ugly. --- src/librustc/util/ppaux.rs | 92 ++++++++++++++++++++++++-------------- 1 file changed, 58 insertions(+), 34 deletions(-) diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 397d27db3b961..0363978bada25 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -395,8 +395,8 @@ pub fn ty_to_string<'tcx>(cx: &ctxt<'tcx>, typ: &ty::TyS<'tcx>) -> String { } ty_enum(did, substs) | ty_struct(did, substs) => { let base = ty::item_path_str(cx, did); - let generics = ty::lookup_item_type(cx, did).generics; - parameterized(cx, &base, substs, &generics, did, &[]) + parameterized(cx, &base, substs, did, &[], + || ty::lookup_item_type(cx, did).generics) } ty_trait(ref data) => { data.user_string(cx) @@ -444,23 +444,40 @@ pub fn explicit_self_category_to_str(category: &ty::ExplicitSelfCategory) } } -pub fn parameterized<'tcx>(cx: &ctxt<'tcx>, - base: &str, - substs: &subst::Substs<'tcx>, - generics: &ty::Generics<'tcx>, - did: ast::DefId, - projections: &[ty::ProjectionPredicate<'tcx>]) - -> String +pub fn parameterized<'tcx,GG>(cx: &ctxt<'tcx>, + base: &str, + substs: &subst::Substs<'tcx>, + did: ast::DefId, + projections: &[ty::ProjectionPredicate<'tcx>], + get_generics: GG) + -> String + where GG : FnOnce() -> ty::Generics<'tcx> { if cx.sess.verbose() { - if substs.is_noop() { - return format!("{}", base); - } else { - return format!("{}<{},{}>", - base, - substs.regions.repr(cx), - substs.types.repr(cx)); + let mut strings = vec![]; + match substs.regions { + subst::ErasedRegions => { + strings.push(format!("..")); + } + subst::NonerasedRegions(ref regions) => { + for region in regions.iter() { + strings.push(region.repr(cx)); + } + } } + for ty in substs.types.iter() { + strings.push(ty.repr(cx)); + } + for projection in projections.iter() { + strings.push(format!("{}={}", + projection.projection_ty.item_name.user_string(cx), + projection.ty.user_string(cx))); + } + return if strings.is_empty() { + format!("{}", base) + } else { + format!("{}<{}>", base, strings.connect(",")) + }; } let mut strs = Vec::new(); @@ -484,6 +501,13 @@ pub fn parameterized<'tcx>(cx: &ctxt<'tcx>, } } + // It is important to execute this conditionally, only if -Z + // verbose is false. Otherwise, debug logs can sometimes cause + // ICEs trying to fetch the generics early in the pipeline. This + // is kind of a hacky workaround in that -Z verbose is required to + // avoid those ICEs. + let generics = get_generics(); + let tps = substs.types.get_slice(subst::TypeSpace); let ty_params = generics.types.get_slice(subst::TypeSpace); let has_defaults = ty_params.last().map_or(false, |def| def.default.is_some()); @@ -645,13 +669,12 @@ impl<'tcx> UserString<'tcx> for TraitAndProjections<'tcx> { fn user_string(&self, tcx: &ctxt<'tcx>) -> String { let &(ref trait_ref, ref projection_bounds) = self; let base = ty::item_path_str(tcx, trait_ref.def_id); - let trait_def = ty::lookup_trait_def(tcx, trait_ref.def_id); parameterized(tcx, &base, trait_ref.substs, - &trait_def.generics, trait_ref.def_id, - &projection_bounds[]) + &projection_bounds[], + || ty::lookup_trait_def(tcx, trait_ref.def_id).generics.clone()) } } @@ -687,10 +710,9 @@ impl<'tcx> UserString<'tcx> for ty::TyTrait<'tcx> { } impl<'tcx> Repr<'tcx> for ty::TypeParameterDef<'tcx> { - fn repr(&self, tcx: &ctxt<'tcx>) -> String { - format!("TypeParameterDef({:?}, {}, {:?}/{})", + fn repr(&self, _tcx: &ctxt<'tcx>) -> String { + format!("TypeParameterDef({:?}, {:?}/{})", self.def_id, - self.bounds.repr(tcx), self.space, self.index) } @@ -781,11 +803,8 @@ impl<'tcx> Repr<'tcx> for ty::TraitRef<'tcx> { // to enumerate the `for<...>` etc because the debruijn index // tells you everything you need to know. let base = ty::item_path_str(tcx, self.def_id); - let trait_def = ty::lookup_trait_def(tcx, self.def_id); - format!("TraitRef({}, {})", - self.substs.self_ty().repr(tcx), - parameterized(tcx, &base, self.substs, - &trait_def.generics, self.def_id, &[])) + parameterized(tcx, &base, self.substs, self.def_id, &[], + || ty::lookup_trait_def(tcx, self.def_id).generics.clone()) } } @@ -987,16 +1006,22 @@ impl<'tcx> Repr<'tcx> for ty::TypeScheme<'tcx> { impl<'tcx> Repr<'tcx> for ty::Generics<'tcx> { fn repr(&self, tcx: &ctxt<'tcx>) -> String { - format!("Generics(types: {}, regions: {}, predicates: {})", + format!("Generics(types: {}, regions: {})", self.types.repr(tcx), - self.regions.repr(tcx), + self.regions.repr(tcx)) + } +} + +impl<'tcx> Repr<'tcx> for ty::GenericPredicates<'tcx> { + fn repr(&self, tcx: &ctxt<'tcx>) -> String { + format!("GenericPredicates(predicates: {})", self.predicates.repr(tcx)) } } -impl<'tcx> Repr<'tcx> for ty::GenericBounds<'tcx> { +impl<'tcx> Repr<'tcx> for ty::InstantiatedPredicates<'tcx> { fn repr(&self, tcx: &ctxt<'tcx>) -> String { - format!("GenericBounds({})", + format!("InstantiatedPredicates({})", self.predicates.repr(tcx)) } } @@ -1249,9 +1274,8 @@ impl<'tcx, T> UserString<'tcx> for ty::Binder impl<'tcx> UserString<'tcx> for ty::TraitRef<'tcx> { fn user_string(&self, tcx: &ctxt<'tcx>) -> String { let path_str = ty::item_path_str(tcx, self.def_id); - let trait_def = ty::lookup_trait_def(tcx, self.def_id); - parameterized(tcx, &path_str, self.substs, - &trait_def.generics, self.def_id, &[]) + parameterized(tcx, &path_str, self.substs, self.def_id, &[], + || ty::lookup_trait_def(tcx, self.def_id).generics.clone()) } } From c87166e149c6c67d72c62667ae8cd96cb27bc090 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 11 Feb 2015 10:30:16 -0500 Subject: [PATCH 07/12] Adjust wording of astconv comment. --- src/librustc_typeck/astconv.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 0dbb53e09b7d9..1951d9946bca9 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -16,11 +16,12 @@ //! somewhat differently during the collect and check phases, //! particularly with respect to looking up the types of top-level //! items. In the collect phase, the crate context is used as the -//! `AstConv` instance; in this phase, the `get_item_type_scheme()` function -//! triggers a recursive call to `ty_of_item()` (note that -//! `ast_ty_to_ty()` will detect recursive types and report an error). -//! In the check phase, when the FnCtxt is used as the `AstConv`, -//! `get_item_type_scheme()` just looks up the item type in `tcx.tcache`. +//! `AstConv` instance; in this phase, the `get_item_type_scheme()` +//! function triggers a recursive call to `type_scheme_of_item()` +//! (note that `ast_ty_to_ty()` will detect recursive types and report +//! an error). In the check phase, when the FnCtxt is used as the +//! `AstConv`, `get_item_type_scheme()` just looks up the item type in +//! `tcx.tcache` (using `ty::lookup_item_type`). //! //! The `RegionScope` trait controls what happens when the user does //! not specify a region in some location where a region is required From 28e48f308c28be41d0aec27ced895084cdc842c1 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 11 Feb 2015 10:31:19 -0500 Subject: [PATCH 08/12] Add test for IntoIterator pattern blocked by #20220. Fixes #20220. --- .../run-pass/associated-types-issue-20220.rs | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 src/test/run-pass/associated-types-issue-20220.rs diff --git a/src/test/run-pass/associated-types-issue-20220.rs b/src/test/run-pass/associated-types-issue-20220.rs new file mode 100644 index 0000000000000..a253fbde5633f --- /dev/null +++ b/src/test/run-pass/associated-types-issue-20220.rs @@ -0,0 +1,36 @@ +// 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 references to `Self::Item` in the trait. Issue #20220. + +use std::vec; + +trait IntoIteratorX { + type Item; + type IntoIter: Iterator; + + fn into_iter_x(self) -> Self::IntoIter; +} + +impl IntoIteratorX for Vec { + type Item = T; + type IntoIter = vec::IntoIter; + + fn into_iter_x(self) -> vec::IntoIter { + self.into_iter() + } +} + +fn main() { + let vec = vec![1, 2, 3]; + for (i, e) in vec.into_iter().enumerate() { + assert_eq!(i+1, e); + } +} From 14141aca80a78dc8ec67bce463c5677ec0280264 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 11 Feb 2015 10:31:37 -0500 Subject: [PATCH 09/12] Add test for self-referencing pattern blocked by #20551. Fixes #20551. --- src/test/run-pass/associated-types-stream.rs | 47 ++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 src/test/run-pass/associated-types-stream.rs diff --git a/src/test/run-pass/associated-types-stream.rs b/src/test/run-pass/associated-types-stream.rs new file mode 100644 index 0000000000000..ef7fbe87b3047 --- /dev/null +++ b/src/test/run-pass/associated-types-stream.rs @@ -0,0 +1,47 @@ +// 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 references to the trait `Stream` in the bounds for associated +// types defined on `Stream`. Issue #20551. + +trait Stream { + type Car; + type Cdr: Stream; + + fn car(&self) -> Self::Car; + fn cdr(self) -> Self::Cdr; +} + +impl Stream for () { + type Car = (); + type Cdr = (); + fn car(&self) -> () { () } + fn cdr(self) -> () { self } +} + +impl Stream for (T, U) + where T : Clone, U : Stream +{ + type Car = T; + type Cdr = U; + fn car(&self) -> T { self.0.clone() } + fn cdr(self) -> U { self.1 } +} + +fn main() { + let p = (22, (44, (66, ()))); + assert_eq!(p.car(), 22); + + let p = p.cdr(); + assert_eq!(p.car(), 44); + + let p = p.cdr(); + assert_eq!(p.car(), 66); +} From 21fb420592bd4ee03e81efe7b2dbd7115e790e3a Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 11 Feb 2015 10:32:21 -0500 Subject: [PATCH 10/12] Add test that shows how a cycle between the where-clauses on a type and the type appearing in the trait would (previously) trigger an error message. The code is now accepted. No reported issue that I am aware of. --- .../astconv-cycle-between-trait-and-type.rs | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 src/test/run-pass/astconv-cycle-between-trait-and-type.rs diff --git a/src/test/run-pass/astconv-cycle-between-trait-and-type.rs b/src/test/run-pass/astconv-cycle-between-trait-and-type.rs new file mode 100644 index 0000000000000..0c6d91eda26af --- /dev/null +++ b/src/test/run-pass/astconv-cycle-between-trait-and-type.rs @@ -0,0 +1,36 @@ +// 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 that we are able to successfully compile a setup where a trait +// (`Trait1`) references a struct (`SomeType`) which in turn +// carries a predicate that references the trait (`u32 : Trait1`, +// substituted). + +#![allow(dead_code)] + +trait Trait1 : Trait2> { + fn dumb(&self) { } +} + +trait Trait2 { + fn dumber(&self, _: A) { } +} + +struct SomeType + where A : Trait1 +{ + a: A +} + +impl Trait1 for u32 { } + +impl Trait2> for u32 { } + +fn main() { } From eec3b431aa30ab6160dcc93b7bf7f654ba9dc6ea Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 11 Feb 2015 11:54:30 -0500 Subject: [PATCH 11/12] Pacify the mercilous tidy. --- src/librustc_typeck/check/mod.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 00bc3375fdd9f..d12b23187b80b 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -3635,7 +3635,8 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, let (scheme, predicates) = type_scheme_and_predicates_for_def(fcx, expr.span, defn); let mut path = qpath.trait_ref.path.clone(); path.segments.push(qpath.item_path.clone()); - instantiate_path(fcx, &path, scheme, &predicates, Some(self_ty), defn, expr.span, expr.id); + instantiate_path(fcx, &path, scheme, &predicates, Some(self_ty), + defn, expr.span, expr.id); // We always require that the type provided as the value for // a type parameter outlives the moment of instantiation. From a25ed227a7887454bd1717286a7ada4f8a8d9a00 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 11 Feb 2015 16:55:22 -0500 Subject: [PATCH 12/12] Pacify the merciless nrc. --- src/librustc/metadata/csearch.rs | 2 +- src/librustc/metadata/decoder.rs | 6 +++--- src/librustc_typeck/collect.rs | 14 +++++++------- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/librustc/metadata/csearch.rs b/src/librustc/metadata/csearch.rs index 245b9ef66ad3a..7eeb0589118fb 100644 --- a/src/librustc/metadata/csearch.rs +++ b/src/librustc/metadata/csearch.rs @@ -234,7 +234,7 @@ pub fn get_trait_def<'tcx>(tcx: &ty::ctxt<'tcx>, def: ast::DefId) -> ty::TraitDe } pub fn get_predicates<'tcx>(tcx: &ty::ctxt<'tcx>, def: ast::DefId) - -> ty::GenericPredicates<'tcx> + -> ty::GenericPredicates<'tcx> { let cstore = &tcx.sess.cstore; let cdata = cstore.get_crate_data(def.krate); diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index 4924ebc576742..e5576de6e8424 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -418,9 +418,9 @@ pub fn get_trait_def<'tcx>(cdata: Cmd, } pub fn get_predicates<'tcx>(cdata: Cmd, - item_id: ast::NodeId, - tcx: &ty::ctxt<'tcx>) - -> ty::GenericPredicates<'tcx> + item_id: ast::NodeId, + tcx: &ty::ctxt<'tcx>) + -> ty::GenericPredicates<'tcx> { let item_doc = lookup_item(item_id, cdata.data()); doc_predicates(item_doc, tcx, cdata, tag_item_generics) diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 3ee3eb87b95a7..8a1945c16a6aa 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -44,7 +44,7 @@ Converting types can require: 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 +trait hierarchy requires converting 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 @@ -1778,12 +1778,12 @@ fn check_method_self_type<'a, 'tcx, RS:RegionScope>( &ty::liberate_late_bound_regions( tcx, body_scope, &ty::Binder(base_type))); - //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)); + 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,