diff --git a/src/librustc/metadata/common.rs b/src/librustc/metadata/common.rs index b3c1d6cd15fee..b28106a72e048 100644 --- a/src/librustc/metadata/common.rs +++ b/src/librustc/metadata/common.rs @@ -84,7 +84,6 @@ pub const tag_mod_impl: uint = 0x38; pub const tag_item_trait_item: uint = 0x39; pub const tag_item_trait_ref: uint = 0x3a; -pub const tag_item_super_trait_ref: uint = 0x3b; // discriminator value for variants pub const tag_disr_val: uint = 0x3c; @@ -221,8 +220,6 @@ pub const tag_struct_field_id: uint = 0x8b; pub const tag_attribute_is_sugared_doc: uint = 0x8c; -pub const tag_trait_def_bounds: uint = 0x8d; - pub const tag_items_data_region: uint = 0x8e; pub const tag_region_param_def: uint = 0x8f; @@ -255,3 +252,5 @@ pub const tag_paren_sugar: uint = 0xa0; pub const tag_codemap: uint = 0xa1; pub const tag_codemap_filemap: uint = 0xa2; + +pub const tag_item_super_predicates: uint = 0xa3; diff --git a/src/librustc/metadata/csearch.rs b/src/librustc/metadata/csearch.rs index f5c4cce065955..c7785ff4c8772 100644 --- a/src/librustc/metadata/csearch.rs +++ b/src/librustc/metadata/csearch.rs @@ -175,14 +175,6 @@ pub fn get_provided_trait_methods<'tcx>(tcx: &ty::ctxt<'tcx>, decoder::get_provided_trait_methods(cstore.intr.clone(), &*cdata, def.node, tcx) } -pub fn get_supertraits<'tcx>(tcx: &ty::ctxt<'tcx>, - def: ast::DefId) - -> Vec>> { - let cstore = &tcx.sess.cstore; - let cdata = cstore.get_crate_data(def.krate); - decoder::get_supertraits(&*cdata, def.node, tcx) -} - pub fn get_type_name_if_impl(cstore: &cstore::CStore, def: ast::DefId) -> Option { let cdata = cstore.get_crate_data(def.krate); @@ -238,6 +230,14 @@ pub fn get_predicates<'tcx>(tcx: &ty::ctxt<'tcx>, def: ast::DefId) decoder::get_predicates(&*cdata, def.node, tcx) } +pub fn get_super_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_super_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 90046398c59f4..f5f9bd41c8b8e 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -22,9 +22,8 @@ use metadata::csearch::MethodInfo; use metadata::csearch; use metadata::cstore; use metadata::tydecode::{parse_ty_data, parse_region_data, parse_def_id, - parse_type_param_def_data, parse_bounds_data, - parse_bare_fn_ty_data, parse_trait_ref_data, - parse_predicate_data}; + parse_type_param_def_data, parse_bare_fn_ty_data, + parse_trait_ref_data, parse_predicate_data}; use middle::def; use middle::lang_items; use middle::subst; @@ -260,18 +259,6 @@ fn item_trait_ref<'tcx>(doc: rbml::Doc, tcx: &ty::ctxt<'tcx>, cdata: Cmd) doc_trait_ref(tp, tcx, cdata) } -fn doc_bounds<'tcx>(doc: rbml::Doc, tcx: &ty::ctxt<'tcx>, cdata: Cmd) - -> ty::ParamBounds<'tcx> { - parse_bounds_data(doc.data, cdata.cnum, doc.start, tcx, - |_, did| translate_def_id(cdata, did)) -} - -fn trait_def_bounds<'tcx>(doc: rbml::Doc, tcx: &ty::ctxt<'tcx>, cdata: Cmd) - -> ty::ParamBounds<'tcx> { - let d = reader::get_doc(doc, tag_trait_def_bounds); - doc_bounds(d, tcx, cdata) -} - fn enum_variant_ids(item: rbml::Doc, cdata: Cmd) -> Vec { let mut ids: Vec = Vec::new(); let v = tag_items_data_item_variant; @@ -406,7 +393,6 @@ pub fn get_trait_def<'tcx>(cdata: Cmd, { let item_doc = lookup_item(item_id, cdata.data()); let generics = doc_generics(item_doc, tcx, cdata, tag_item_generics); - let bounds = trait_def_bounds(item_doc, tcx, cdata); let unsafety = parse_unsafety(item_doc); let associated_type_names = parse_associated_type_names(item_doc); let paren_sugar = parse_paren_sugar(item_doc); @@ -415,7 +401,6 @@ pub fn get_trait_def<'tcx>(cdata: Cmd, paren_sugar: paren_sugar, unsafety: unsafety, generics: generics, - bounds: bounds, trait_ref: item_trait_ref(item_doc, tcx, cdata), associated_type_names: associated_type_names, } @@ -430,6 +415,15 @@ pub fn get_predicates<'tcx>(cdata: Cmd, doc_predicates(item_doc, tcx, cdata, tag_item_generics) } +pub fn get_super_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_super_predicates) +} + pub fn get_type<'tcx>(cdata: Cmd, id: ast::NodeId, tcx: &ty::ctxt<'tcx>) -> ty::TypeScheme<'tcx> { @@ -971,24 +965,6 @@ pub fn get_provided_trait_methods<'tcx>(intr: Rc, return result; } -/// Returns the supertraits of the given trait. -pub fn get_supertraits<'tcx>(cdata: Cmd, id: ast::NodeId, tcx: &ty::ctxt<'tcx>) - -> Vec>> { - let mut results = Vec::new(); - let item_doc = lookup_item(id, cdata.data()); - reader::tagged_docs(item_doc, tag_item_super_trait_ref, |trait_doc| { - // NB. Only reads the ones that *aren't* builtin-bounds. See also - // get_trait_def() for collecting the builtin bounds. - // FIXME(#8559): The builtin bounds shouldn't be encoded in the first place. - let trait_ref = doc_trait_ref(trait_doc, tcx, cdata); - if tcx.lang_items.to_builtin_kind(trait_ref.def_id).is_none() { - results.push(trait_ref); - } - true - }); - return results; -} - pub fn get_type_name_if_impl(cdata: Cmd, node_id: ast::NodeId) -> Option { let item = lookup_item(node_id, cdata.data()); diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index b9e0e452c8374..c4ba2373b9f57 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -206,21 +206,6 @@ pub fn write_region(ecx: &EncodeContext, tyencode::enc_region(rbml_w, ty_str_ctxt, r); } -fn encode_bounds<'a, 'tcx>(rbml_w: &mut Encoder, - ecx: &EncodeContext<'a, 'tcx>, - bounds: &ty::ParamBounds<'tcx>, - tag: uint) { - rbml_w.start_tag(tag); - - let ty_str_ctxt = &tyencode::ctxt { diag: ecx.diag, - ds: def_to_string, - tcx: ecx.tcx, - abbrevs: &ecx.type_abbrevs }; - tyencode::enc_bounds(rbml_w, ty_str_ctxt, bounds); - - rbml_w.end_tag(); -} - fn encode_type<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, rbml_w: &mut Encoder, typ: Ty<'tcx>) { @@ -728,6 +713,7 @@ fn encode_generics<'a, 'tcx>(rbml_w: &mut Encoder, tcx: ecx.tcx, abbrevs: &ecx.type_abbrevs }; + for param in generics.types.iter() { rbml_w.start_tag(tag_type_param_def); tyencode::enc_type_param_def(rbml_w, ty_str_ctxt, param); @@ -758,6 +744,22 @@ fn encode_generics<'a, 'tcx>(rbml_w: &mut Encoder, rbml_w.end_tag(); } + encode_predicates_in_current_doc(rbml_w, ecx, predicates); + + rbml_w.end_tag(); +} + +fn encode_predicates_in_current_doc<'a,'tcx>(rbml_w: &mut Encoder, + ecx: &EncodeContext<'a,'tcx>, + predicates: &ty::GenericPredicates<'tcx>) +{ + let ty_str_ctxt = &tyencode::ctxt { + diag: ecx.diag, + ds: def_to_string, + tcx: ecx.tcx, + abbrevs: &ecx.type_abbrevs + }; + for (space, _, predicate) in predicates.predicates.iter_enumerated() { rbml_w.start_tag(tag_predicate); @@ -769,7 +771,15 @@ fn encode_generics<'a, 'tcx>(rbml_w: &mut Encoder, rbml_w.end_tag(); } +} +fn encode_predicates<'a,'tcx>(rbml_w: &mut Encoder, + ecx: &EncodeContext<'a,'tcx>, + predicates: &ty::GenericPredicates<'tcx>, + tag: uint) +{ + rbml_w.start_tag(tag); + encode_predicates_in_current_doc(rbml_w, ecx, predicates); rbml_w.end_tag(); } @@ -1280,6 +1290,8 @@ fn encode_info_for_item(ecx: &EncodeContext, 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, &trait_predicates, tag_item_generics); + encode_predicates(rbml_w, ecx, &ty::lookup_super_predicates(tcx, def_id), + tag_item_super_predicates); 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); @@ -1304,8 +1316,6 @@ fn encode_info_for_item(ecx: &EncodeContext, } encode_path(rbml_w, path.clone()); - encode_bounds(rbml_w, ecx, &trait_def.bounds, tag_trait_def_bounds); - // Encode the implementations of this trait. encode_extension_implementations(ecx, rbml_w, def_id); diff --git a/src/librustc/middle/traits/mod.rs b/src/librustc/middle/traits/mod.rs index 5a5639c701291..f46cac308287b 100644 --- a/src/librustc/middle/traits/mod.rs +++ b/src/librustc/middle/traits/mod.rs @@ -280,7 +280,11 @@ pub struct VtableBuiltinData { /// for the object type `Foo`. #[derive(PartialEq,Eq,Clone)] pub struct VtableObjectData<'tcx> { + /// the object type `Foo`. pub object_ty: Ty<'tcx>, + + /// `Foo` upcast to the obligation trait. This will be some supertrait of `Foo`. + pub upcast_trait_ref: ty::PolyTraitRef<'tcx>, } /// Creates predicate obligations from the generic bounds. diff --git a/src/librustc/middle/traits/object_safety.rs b/src/librustc/middle/traits/object_safety.rs index 64835a666faef..881487a2dad11 100644 --- a/src/librustc/middle/traits/object_safety.rs +++ b/src/librustc/middle/traits/object_safety.rs @@ -22,7 +22,7 @@ use super::elaborate_predicates; use middle::subst::{self, SelfSpace, TypeSpace}; use middle::traits; -use middle::ty::{self, Ty}; +use middle::ty::{self, ToPolyTraitRef, Ty}; use std::rc::Rc; use syntax::ast; use util::ppaux::Repr; @@ -128,9 +128,12 @@ fn supertraits_reference_self<'tcx>(tcx: &ty::ctxt<'tcx>, { let trait_def = ty::lookup_trait_def(tcx, trait_def_id); let trait_ref = trait_def.trait_ref.clone(); - let predicates = ty::predicates_for_trait_ref(tcx, &ty::Binder(trait_ref)); + let trait_ref = trait_ref.to_poly_trait_ref(); + let predicates = ty::lookup_super_predicates(tcx, trait_def_id); predicates + .predicates .into_iter() + .map(|predicate| predicate.subst_supertrait(tcx, &trait_ref)) .any(|predicate| { match predicate { ty::Predicate::Trait(ref data) => { diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs index 470315c78f81d..e57c16b5a0fb8 100644 --- a/src/librustc/middle/traits/select.rs +++ b/src/librustc/middle/traits/select.rs @@ -1260,19 +1260,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { poly_trait_ref.repr(self.tcx())); // see whether the object trait can be upcast to the trait we are looking for - let obligation_def_id = obligation.predicate.def_id(); - let upcast_trait_ref = match util::upcast(self.tcx(), poly_trait_ref, obligation_def_id) { - Some(r) => r, - None => { return; } - }; - - debug!("assemble_candidates_from_object_ty: upcast_trait_ref={}", - upcast_trait_ref.repr(self.tcx())); - - // check whether the upcast version of the trait-ref matches what we are looking for - if let Ok(()) = self.infcx.probe(|_| self.match_poly_trait_ref(obligation, - upcast_trait_ref.clone())) { - debug!("assemble_candidates_from_object_ty: matched, pushing candidate"); + let upcast_trait_refs = self.upcast(poly_trait_ref, obligation); + if upcast_trait_refs.len() > 1 { + // can be upcast in many ways; need more type information + candidates.ambiguous = true; + } else if upcast_trait_refs.len() == 1 { candidates.vec.push(ObjectCandidate); } } @@ -1455,9 +1447,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let principal = data.principal_trait_ref_with_self_ty(self.tcx(), self.tcx().types.err); + let desired_def_id = obligation.predicate.def_id(); for tr in util::supertraits(self.tcx(), principal) { - let td = ty::lookup_trait_def(self.tcx(), tr.def_id()); - if td.bounds.builtin_bounds.contains(&bound) { + if tr.def_id() == desired_def_id { return Ok(If(Vec::new())) } } @@ -2063,20 +2055,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } }; - let obligation_def_id = obligation.predicate.def_id(); - let upcast_trait_ref = match util::upcast(self.tcx(), - poly_trait_ref.clone(), - obligation_def_id) { - Some(r) => r, - None => { - self.tcx().sess.span_bug(obligation.cause.span, - &format!("unable to upcast from {} to {}", - poly_trait_ref.repr(self.tcx()), - obligation_def_id.repr(self.tcx()))); - } - }; + // Upcast the object type to the obligation type. There must + // be exactly one applicable trait-reference; if this were not + // the case, we would have reported an ambiguity error rather + // than successfully selecting one of the candidates. + let upcast_trait_refs = self.upcast(poly_trait_ref.clone(), obligation); + assert_eq!(upcast_trait_refs.len(), 1); + let upcast_trait_ref = upcast_trait_refs.into_iter().next().unwrap(); - match self.match_poly_trait_ref(obligation, upcast_trait_ref) { + match self.match_poly_trait_ref(obligation, upcast_trait_ref.clone()) { Ok(()) => { } Err(()) => { self.tcx().sess.span_bug(obligation.cause.span, @@ -2084,7 +2071,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } - VtableObjectData { object_ty: self_ty } + VtableObjectData { object_ty: self_ty, + upcast_trait_ref: upcast_trait_ref } } fn confirm_fn_pointer_candidate(&mut self, @@ -2501,6 +2489,32 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation.cause.clone() } } + + /// Upcasts an object trait-reference into those that match the obligation. + fn upcast(&mut self, obj_trait_ref: ty::PolyTraitRef<'tcx>, obligation: &TraitObligation<'tcx>) + -> Vec> + { + debug!("upcast(obj_trait_ref={}, obligation={})", + obj_trait_ref.repr(self.tcx()), + obligation.repr(self.tcx())); + + let obligation_def_id = obligation.predicate.def_id(); + let mut upcast_trait_refs = util::upcast(self.tcx(), obj_trait_ref, obligation_def_id); + + // Retain only those upcast versions that match the trait-ref + // we are looking for. In particular, we know that all of + // `upcast_trait_refs` apply to the correct trait, but + // possibly with incorrect type parameters. For example, we + // may be trying to upcast `Foo` to `Bar`, but `Foo` is + // declared as `trait Foo : Bar`. + upcast_trait_refs.retain(|upcast_trait_ref| { + let upcast_trait_ref = upcast_trait_ref.clone(); + self.infcx.probe(|_| self.match_poly_trait_ref(obligation, upcast_trait_ref)).is_ok() + }); + + debug!("upcast: upcast_trait_refs={}", upcast_trait_refs.repr(self.tcx())); + upcast_trait_refs + } } impl<'tcx> Repr<'tcx> for SelectionCandidate<'tcx> { diff --git a/src/librustc/middle/traits/util.rs b/src/librustc/middle/traits/util.rs index 7bef5f32475d3..4527985302aed 100644 --- a/src/librustc/middle/traits/util.rs +++ b/src/librustc/middle/traits/util.rs @@ -76,15 +76,10 @@ impl<'a,'tcx> PredicateSet<'a,'tcx> { /// 'static`. pub struct Elaborator<'cx, 'tcx:'cx> { tcx: &'cx ty::ctxt<'tcx>, - stack: Vec>, + stack: Vec>, visited: PredicateSet<'cx,'tcx>, } -struct StackEntry<'tcx> { - position: uint, - predicates: Vec>, -} - pub fn elaborate_trait_ref<'cx, 'tcx>( tcx: &'cx ty::ctxt<'tcx>, trait_ref: ty::PolyTraitRef<'tcx>) @@ -111,21 +106,28 @@ pub fn elaborate_predicates<'cx, 'tcx>( { let mut visited = PredicateSet::new(tcx); predicates.retain(|pred| visited.insert(pred)); - let entry = StackEntry { position: 0, predicates: predicates }; - Elaborator { tcx: tcx, stack: vec![entry], visited: visited } + Elaborator { tcx: tcx, stack: predicates, visited: visited } } impl<'cx, 'tcx> Elaborator<'cx, 'tcx> { - pub fn filter_to_traits(self) -> Supertraits<'cx, 'tcx> { - Supertraits { elaborator: self } + pub fn filter_to_traits(self) -> FilterToTraits> { + FilterToTraits::new(self) } fn push(&mut self, predicate: &ty::Predicate<'tcx>) { match *predicate { ty::Predicate::Trait(ref data) => { - let mut predicates = - ty::predicates_for_trait_ref(self.tcx, - &data.to_poly_trait_ref()); + // Predicates declared on the trait. + let predicates = ty::lookup_super_predicates(self.tcx, data.def_id()); + + let mut predicates: Vec<_> = + predicates.predicates + .iter() + .map(|p| p.subst_supertrait(self.tcx, &data.to_poly_trait_ref())) + .collect(); + + debug!("super_predicates: data={} predicates={}", + data.repr(self.tcx), predicates.repr(self.tcx)); // Only keep those bounds that we haven't already // seen. This is necessary to prevent infinite @@ -134,8 +136,7 @@ impl<'cx, 'tcx> Elaborator<'cx, 'tcx> { // Sized { }`. predicates.retain(|r| self.visited.insert(r)); - self.stack.push(StackEntry { position: 0, - predicates: predicates }); + self.stack.extend(predicates.into_iter()); } ty::Predicate::Equate(..) => { // Currently, we do not "elaborate" predicates like @@ -175,41 +176,16 @@ impl<'cx, 'tcx> Iterator for Elaborator<'cx, 'tcx> { type Item = ty::Predicate<'tcx>; fn next(&mut self) -> Option> { - loop { - // Extract next item from top-most stack frame, if any. - let next_predicate = match self.stack.last_mut() { - None => { - // No more stack frames. Done. - return None; - } - Some(entry) => { - let p = entry.position; - if p < entry.predicates.len() { - // Still more predicates left in the top stack frame. - entry.position += 1; - - let next_predicate = - entry.predicates[p].clone(); - - Some(next_predicate) - } else { - None - } - } - }; - - match next_predicate { - Some(next_predicate) => { - self.push(&next_predicate); - return Some(next_predicate); - } - - None => { - // Top stack frame is exhausted, pop it. - self.stack.pop(); - } + // Extract next item from top-most stack frame, if any. + let next_predicate = match self.stack.pop() { + Some(predicate) => predicate, + None => { + // No more stack frames. Done. + return None; } - } + }; + self.push(&next_predicate); + return Some(next_predicate); } } @@ -217,11 +193,7 @@ impl<'cx, 'tcx> Iterator for Elaborator<'cx, 'tcx> { // Supertrait iterator /////////////////////////////////////////////////////////////////////////// -/// A filter around the `Elaborator` that just yields up supertrait references, -/// not other kinds of predicates. -pub struct Supertraits<'cx, 'tcx:'cx> { - elaborator: Elaborator<'cx, 'tcx>, -} +pub type Supertraits<'cx, 'tcx> = FilterToTraits>; pub fn supertraits<'cx, 'tcx>(tcx: &'cx ty::ctxt<'tcx>, trait_ref: ty::PolyTraitRef<'tcx>) @@ -237,12 +209,28 @@ pub fn transitive_bounds<'cx, 'tcx>(tcx: &'cx ty::ctxt<'tcx>, elaborate_trait_refs(tcx, bounds).filter_to_traits() } -impl<'cx, 'tcx> Iterator for Supertraits<'cx, 'tcx> { +/////////////////////////////////////////////////////////////////////////// +// Other +/////////////////////////////////////////////////////////////////////////// + +/// A filter around an iterator of predicates that makes it yield up +/// just trait references. +pub struct FilterToTraits { + base_iterator: I +} + +impl FilterToTraits { + fn new(base: I) -> FilterToTraits { + FilterToTraits { base_iterator: base } + } +} + +impl<'tcx,I:Iterator>> Iterator for FilterToTraits { type Item = ty::PolyTraitRef<'tcx>; fn next(&mut self) -> Option> { loop { - match self.elaborator.next() { + match self.base_iterator.next() { None => { return None; } @@ -256,6 +244,7 @@ impl<'cx, 'tcx> Iterator for Supertraits<'cx, 'tcx> { } } + /////////////////////////////////////////////////////////////////////////// // Other /////////////////////////////////////////////////////////////////////////// @@ -370,19 +359,15 @@ pub fn predicate_for_builtin_bound<'tcx>( pub fn upcast<'tcx>(tcx: &ty::ctxt<'tcx>, source_trait_ref: ty::PolyTraitRef<'tcx>, target_trait_def_id: ast::DefId) - -> Option> + -> Vec> { if source_trait_ref.def_id() == target_trait_def_id { - return Some(source_trait_ref); // shorcut the most common case - } - - for super_trait_ref in supertraits(tcx, source_trait_ref) { - if super_trait_ref.def_id() == target_trait_def_id { - return Some(super_trait_ref); - } + return vec![source_trait_ref]; // shorcut the most common case } - None + supertraits(tcx, source_trait_ref) + .filter(|r| r.def_id() == target_trait_def_id) + .collect() } /// Given an object of type `object_trait_ref`, returns the index of diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 36c42b7079547..add829074c4f0 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -17,7 +17,6 @@ pub use self::InferTy::*; pub use self::InferRegion::*; pub use self::ImplOrTraitItemId::*; pub use self::ClosureKind::*; -pub use self::ast_ty_to_ty_cache_entry::*; pub use self::Variance::*; pub use self::AutoAdjustment::*; pub use self::Representability::*; @@ -266,12 +265,6 @@ pub struct creader_cache_key { pub len: uint } -#[derive(Copy)] -pub enum ast_ty_to_ty_cache_entry<'tcx> { - atttce_unresolved, /* not resolved yet */ - atttce_resolved(Ty<'tcx>) /* resolved to a type, irrespective of region */ -} - #[derive(Clone, PartialEq, RustcDecodable, RustcEncodable)] pub struct ItemVariances { pub types: VecPerParamSpace, @@ -716,6 +709,14 @@ pub struct ctxt<'tcx> { /// associated predicates. pub predicates: RefCell>>, + /// Maps from the def-id of a trait to the list of + /// super-predicates. This is a subset of the full list of + /// predicates. We store these in a separate map because we must + /// evaluate them even during type conversion, often before the + /// full predicates are available (note that supertraits have + /// additional acyclicity requirements). + pub super_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>, @@ -727,7 +728,7 @@ pub struct ctxt<'tcx> { pub rcache: RefCell>>, pub short_names_cache: RefCell, String>>, pub tc_cache: RefCell, TypeContents>>, - pub ast_ty_to_ty_cache: RefCell>>, + pub ast_ty_to_ty_cache: RefCell>>, pub enum_var_cache: RefCell>>>>>, pub ty_param_defs: RefCell>>, pub adjustments: RefCell>>, @@ -1352,7 +1353,7 @@ pub enum sty<'tcx> { /// definition and not a concrete use of it. To get the correct `ty_enum` /// from the tcx, use the `NodeId` from the `ast::Ty` and look it up in /// the `ast_ty_to_ty_cache`. This is probably true for `ty_struct` as - /// well.` + /// well. ty_enum(DefId, &'tcx Substs<'tcx>), ty_uniq(Ty<'tcx>), ty_str, @@ -1495,6 +1496,27 @@ impl<'tcx> PolyTraitRef<'tcx> { #[derive(Clone, PartialEq, Eq, Hash, Debug)] pub struct Binder(pub T); +impl Binder { + /// Skips the binder and returns the "bound" value. This is a + /// risky thing to do because it's easy to get confused about + /// debruijn indices and the like. It is usually better to + /// discharge the binder using `no_late_bound_regions` or + /// `replace_late_bound_regions` or something like + /// that. `skip_binder` is only valid when you are either + /// extracting data that has nothing to do with bound regions, you + /// are doing some sort of test that does not involve bound + /// regions, or you are being very careful about your depth + /// accounting. + /// + /// Some examples where `skip_binder` is reasonable: + /// - extracting the def-id from a PolyTraitRef; + /// - comparing the self type of a PolyTraitRef to see if it is equal to + /// a type parameter `X`, since the type `X` does not reference any regions + pub fn skip_binder(&self) -> &T { + &self.0 + } +} + #[derive(Clone, Copy, PartialEq)] pub enum IntVarValue { IntType(ast::IntTy), @@ -1817,6 +1839,16 @@ impl<'tcx> GenericPredicates<'tcx> { predicates: self.predicates.subst(tcx, substs), } } + + pub fn instantiate_supertrait(&self, + tcx: &ty::ctxt<'tcx>, + poly_trait_ref: &ty::PolyTraitRef<'tcx>) + -> InstantiatedPredicates<'tcx> + { + InstantiatedPredicates { + predicates: self.predicates.map(|pred| pred.subst_supertrait(tcx, poly_trait_ref)) + } + } } #[derive(Clone, PartialEq, Eq, Hash, Debug)] @@ -1840,6 +1872,93 @@ pub enum Predicate<'tcx> { Projection(PolyProjectionPredicate<'tcx>), } +impl<'tcx> Predicate<'tcx> { + /// Performs a substituion suitable for going from a + /// poly-trait-ref to supertraits that must hold if that + /// poly-trait-ref holds. This is slightly different from a normal + /// substitution in terms of what happens with bound regions. See + /// lengthy comment below for details. + pub fn subst_supertrait(&self, + tcx: &ty::ctxt<'tcx>, + trait_ref: &ty::PolyTraitRef<'tcx>) + -> ty::Predicate<'tcx> + { + // The interaction between HRTB and supertraits is not entirely + // obvious. Let me walk you (and myself) through an example. + // + // Let's start with an easy case. Consider two traits: + // + // trait Foo<'a> : Bar<'a,'a> { } + // trait Bar<'b,'c> { } + // + // Now, if we have a trait reference `for<'x> T : Foo<'x>`, then + // we can deduce that `for<'x> T : Bar<'x,'x>`. Basically, if we + // knew that `Foo<'x>` (for any 'x) then we also know that + // `Bar<'x,'x>` (for any 'x). This more-or-less falls out from + // normal substitution. + // + // In terms of why this is sound, the idea is that whenever there + // is an impl of `T:Foo<'a>`, it must show that `T:Bar<'a,'a>` + // holds. So if there is an impl of `T:Foo<'a>` that applies to + // all `'a`, then we must know that `T:Bar<'a,'a>` holds for all + // `'a`. + // + // Another example to be careful of is this: + // + // trait Foo1<'a> : for<'b> Bar1<'a,'b> { } + // trait Bar1<'b,'c> { } + // + // Here, if we have `for<'x> T : Foo1<'x>`, then what do we know? + // The answer is that we know `for<'x,'b> T : Bar1<'x,'b>`. The + // reason is similar to the previous example: any impl of + // `T:Foo1<'x>` must show that `for<'b> T : Bar1<'x, 'b>`. So + // basically we would want to collapse the bound lifetimes from + // the input (`trait_ref`) and the supertraits. + // + // To achieve this in practice is fairly straightforward. Let's + // consider the more complicated scenario: + // + // - We start out with `for<'x> T : Foo1<'x>`. In this case, `'x` + // has a De Bruijn index of 1. We want to produce `for<'x,'b> T : Bar1<'x,'b>`, + // where both `'x` and `'b` would have a DB index of 1. + // The substitution from the input trait-ref is therefore going to be + // `'a => 'x` (where `'x` has a DB index of 1). + // - The super-trait-ref is `for<'b> Bar1<'a,'b>`, where `'a` is an + // early-bound parameter and `'b' is a late-bound parameter with a + // DB index of 1. + // - If we replace `'a` with `'x` from the input, it too will have + // a DB index of 1, and thus we'll have `for<'x,'b> Bar1<'x,'b>` + // just as we wanted. + // + // There is only one catch. If we just apply the substitution `'a + // => 'x` to `for<'b> Bar1<'a,'b>`, the substitution code will + // adjust the DB index because we substituting into a binder (it + // tries to be so smart...) resulting in `for<'x> for<'b> + // Bar1<'x,'b>` (we have no syntax for this, so use your + // imagination). Basically the 'x will have DB index of 2 and 'b + // will have DB index of 1. Not quite what we want. So we apply + // the substitution to the *contents* of the trait reference, + // rather than the trait reference itself (put another way, the + // substitution code expects equal binding levels in the values + // from the substitution and the value being substituted into, and + // this trick achieves that). + + let substs = &trait_ref.0.substs; + match *self { + Predicate::Trait(ty::Binder(ref data)) => + Predicate::Trait(ty::Binder(data.subst(tcx, substs))), + Predicate::Equate(ty::Binder(ref data)) => + Predicate::Equate(ty::Binder(data.subst(tcx, substs))), + Predicate::RegionOutlives(ty::Binder(ref data)) => + Predicate::RegionOutlives(ty::Binder(data.subst(tcx, substs))), + Predicate::TypeOutlives(ty::Binder(ref data)) => + Predicate::TypeOutlives(ty::Binder(data.subst(tcx, substs))), + Predicate::Projection(ty::Binder(ref data)) => + Predicate::Projection(ty::Binder(data.subst(tcx, substs))), + } + } +} + #[derive(Clone, PartialEq, Eq, Hash, Debug)] pub struct TraitPredicate<'tcx> { pub trait_ref: Rc> @@ -2324,9 +2443,6 @@ pub struct TraitDef<'tcx> { /// implements the trait. pub generics: Generics<'tcx>, - /// The "supertrait" bounds. - pub bounds: ParamBounds<'tcx>, - pub trait_ref: Rc>, /// A list of the associated types defined in this trait. Useful @@ -2451,6 +2567,7 @@ pub fn mk_ctxt<'tcx>(s: Session, impl_trait_refs: RefCell::new(NodeMap()), trait_defs: RefCell::new(DefIdMap()), predicates: RefCell::new(DefIdMap()), + super_predicates: RefCell::new(DefIdMap()), object_cast_map: RefCell::new(NodeMap()), map: map, intrinsic_defs: RefCell::new(DefIdMap()), @@ -5432,7 +5549,7 @@ pub fn lookup_trait_def<'tcx>(cx: &ctxt<'tcx>, did: ast::DefId) }) } -/// Given the did of a trait, returns its full set of predicates. +/// Given the did of an item, returns its full set of predicates. pub fn lookup_predicates<'tcx>(cx: &ctxt<'tcx>, did: ast::DefId) -> GenericPredicates<'tcx> { @@ -5442,117 +5559,14 @@ pub fn lookup_predicates<'tcx>(cx: &ctxt<'tcx>, did: ast::DefId) }) } -/// 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 -/// those that have the form: -/// -/// Self : SuperTrait<...> -/// Self : 'region -pub fn predicates_for_trait_ref<'tcx>(tcx: &ctxt<'tcx>, - trait_ref: &PolyTraitRef<'tcx>) - -> Vec> +/// Given the did of a trait, returns its superpredicates. +pub fn lookup_super_predicates<'tcx>(cx: &ctxt<'tcx>, did: ast::DefId) + -> GenericPredicates<'tcx> { - let trait_def = lookup_trait_def(tcx, trait_ref.def_id()); - - debug!("bounds_for_trait_ref(trait_def={:?}, trait_ref={:?})", - trait_def.repr(tcx), trait_ref.repr(tcx)); - - // The interaction between HRTB and supertraits is not entirely - // obvious. Let me walk you (and myself) through an example. - // - // Let's start with an easy case. Consider two traits: - // - // trait Foo<'a> : Bar<'a,'a> { } - // trait Bar<'b,'c> { } - // - // Now, if we have a trait reference `for<'x> T : Foo<'x>`, then - // we can deduce that `for<'x> T : Bar<'x,'x>`. Basically, if we - // knew that `Foo<'x>` (for any 'x) then we also know that - // `Bar<'x,'x>` (for any 'x). This more-or-less falls out from - // normal substitution. - // - // In terms of why this is sound, the idea is that whenever there - // is an impl of `T:Foo<'a>`, it must show that `T:Bar<'a,'a>` - // holds. So if there is an impl of `T:Foo<'a>` that applies to - // all `'a`, then we must know that `T:Bar<'a,'a>` holds for all - // `'a`. - // - // Another example to be careful of is this: - // - // trait Foo1<'a> : for<'b> Bar1<'a,'b> { } - // trait Bar1<'b,'c> { } - // - // Here, if we have `for<'x> T : Foo1<'x>`, then what do we know? - // The answer is that we know `for<'x,'b> T : Bar1<'x,'b>`. The - // reason is similar to the previous example: any impl of - // `T:Foo1<'x>` must show that `for<'b> T : Bar1<'x, 'b>`. So - // basically we would want to collapse the bound lifetimes from - // the input (`trait_ref`) and the supertraits. - // - // To achieve this in practice is fairly straightforward. Let's - // consider the more complicated scenario: - // - // - We start out with `for<'x> T : Foo1<'x>`. In this case, `'x` - // has a De Bruijn index of 1. We want to produce `for<'x,'b> T : Bar1<'x,'b>`, - // where both `'x` and `'b` would have a DB index of 1. - // The substitution from the input trait-ref is therefore going to be - // `'a => 'x` (where `'x` has a DB index of 1). - // - The super-trait-ref is `for<'b> Bar1<'a,'b>`, where `'a` is an - // early-bound parameter and `'b' is a late-bound parameter with a - // DB index of 1. - // - If we replace `'a` with `'x` from the input, it too will have - // a DB index of 1, and thus we'll have `for<'x,'b> Bar1<'x,'b>` - // just as we wanted. - // - // There is only one catch. If we just apply the substitution `'a - // => 'x` to `for<'b> Bar1<'a,'b>`, the substitution code will - // adjust the DB index because we substituting into a binder (it - // tries to be so smart...) resulting in `for<'x> for<'b> - // Bar1<'x,'b>` (we have no syntax for this, so use your - // imagination). Basically the 'x will have DB index of 2 and 'b - // will have DB index of 1. Not quite what we want. So we apply - // the substitution to the *contents* of the trait reference, - // rather than the trait reference itself (put another way, the - // substitution code expects equal binding levels in the values - // from the substitution and the value being substituted into, and - // this trick achieves that). - - // Carefully avoid the binder introduced by each trait-ref by - // substituting over the substs, not the trait-refs themselves, - // thus achieving the "collapse" described in the big comment - // above. - let trait_bounds: Vec<_> = - trait_def.bounds.trait_bounds - .iter() - .map(|poly_trait_ref| ty::Binder(poly_trait_ref.0.subst(tcx, trait_ref.substs()))) - .collect(); - - let projection_bounds: Vec<_> = - trait_def.bounds.projection_bounds - .iter() - .map(|poly_proj| ty::Binder(poly_proj.0.subst(tcx, trait_ref.substs()))) - .collect(); - - debug!("bounds_for_trait_ref: trait_bounds={} projection_bounds={}", - trait_bounds.repr(tcx), - projection_bounds.repr(tcx)); - - // The region bounds and builtin bounds do not currently introduce - // binders so we can just substitute in a straightforward way here. - let region_bounds = - trait_def.bounds.region_bounds.subst(tcx, trait_ref.substs()); - let builtin_bounds = - trait_def.bounds.builtin_bounds.subst(tcx, trait_ref.substs()); - - let bounds = ty::ParamBounds { - trait_bounds: trait_bounds, - region_bounds: region_bounds, - builtin_bounds: builtin_bounds, - projection_bounds: projection_bounds, - }; - - predicates(tcx, trait_ref.self_ty(), &bounds) + memoized(&cx.super_predicates, did, |did: DefId| { + assert!(did.krate != ast::LOCAL_CRATE); + csearch::get_super_predicates(cx, did) + }) } pub fn predicates<'tcx>( diff --git a/src/librustc/middle/ty_fold.rs b/src/librustc/middle/ty_fold.rs index 1b904aacc3012..f3a7c1ee6a0c8 100644 --- a/src/librustc/middle/ty_fold.rs +++ b/src/librustc/middle/ty_fold.rs @@ -544,7 +544,8 @@ impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::Vtable<'tcx, N> impl<'tcx> TypeFoldable<'tcx> for traits::VtableObjectData<'tcx> { fn fold_with>(&self, folder: &mut F) -> traits::VtableObjectData<'tcx> { traits::VtableObjectData { - object_ty: self.object_ty.fold_with(folder) + object_ty: self.object_ty.fold_with(folder), + upcast_trait_ref: self.upcast_trait_ref.fold_with(folder), } } } diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index a478cb79796aa..8bc842671a0a9 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -65,12 +65,21 @@ pub struct Session { impl Session { pub fn span_fatal(&self, sp: Span, msg: &str) -> ! { + if self.opts.treat_err_as_bug { + self.span_bug(sp, msg); + } self.diagnostic().span_fatal(sp, msg) } pub fn span_fatal_with_code(&self, sp: Span, msg: &str, code: &str) -> ! { + if self.opts.treat_err_as_bug { + self.span_bug(sp, msg); + } self.diagnostic().span_fatal_with_code(sp, msg, code) } pub fn fatal(&self, msg: &str) -> ! { + if self.opts.treat_err_as_bug { + self.bug(msg); + } self.diagnostic().handler().fatal(msg) } pub fn span_err(&self, sp: Span, msg: &str) { diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 0eeb746022c0d..09a1225441477 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -820,9 +820,8 @@ impl<'tcx> Repr<'tcx> for ty::TraitRef<'tcx> { impl<'tcx> Repr<'tcx> for ty::TraitDef<'tcx> { fn repr(&self, tcx: &ctxt<'tcx>) -> String { - format!("TraitDef(generics={}, bounds={}, trait_ref={})", + format!("TraitDef(generics={}, trait_ref={})", self.generics.repr(tcx), - self.bounds.repr(tcx), self.trait_ref.repr(tcx)) } } diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 22311a7158378..3682fdb74b74f 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -432,8 +432,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { } def::DefTy(..) => { let tty = match self.cx.tcx.ast_ty_to_ty_cache.borrow().get(&id) { - Some(&ty::atttce_resolved(t)) => t, - _ => panic!("ast_ty_to_ty_cache was incomplete after typeck!") + Some(&t) => t, + None => panic!("ast_ty_to_ty_cache was incomplete after typeck!") }; if !ty::is_ffi_safe(self.cx.tcx, tty) { diff --git a/src/librustc_trans/trans/meth.rs b/src/librustc_trans/trans/meth.rs index c07de3a87ec27..0c82d681eed15 100644 --- a/src/librustc_trans/trans/meth.rs +++ b/src/librustc_trans/trans/meth.rs @@ -300,7 +300,10 @@ pub fn trans_static_method_callee<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, .position(|item| item.def_id() == method_id) .unwrap(); let (llfn, ty) = - trans_object_shim(ccx, data.object_ty, trait_id, method_offset_in_trait); + trans_object_shim(ccx, + data.object_ty, + data.upcast_trait_ref.clone(), + method_offset_in_trait); immediate_rvalue(llfn, ty) } _ => { @@ -386,7 +389,10 @@ fn trans_monomorphized_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, Callee { bcx: bcx, data: Fn(llfn) } } traits::VtableObject(ref data) => { - let (llfn, _) = trans_object_shim(bcx.ccx(), data.object_ty, trait_id, n_method); + let (llfn, _) = trans_object_shim(bcx.ccx(), + data.object_ty, + data.upcast_trait_ref.clone(), + n_method); Callee { bcx: bcx, data: Fn(llfn) } } traits::VtableBuiltin(..) | @@ -551,16 +557,17 @@ pub fn trans_trait_callee_from_llval<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, pub fn trans_object_shim<'a, 'tcx>( ccx: &'a CrateContext<'a, 'tcx>, object_ty: Ty<'tcx>, - trait_id: ast::DefId, + upcast_trait_ref: ty::PolyTraitRef<'tcx>, method_offset_in_trait: uint) -> (ValueRef, Ty<'tcx>) { let _icx = push_ctxt("trans_object_shim"); let tcx = ccx.tcx(); + let trait_id = upcast_trait_ref.def_id(); - debug!("trans_object_shim(object_ty={}, trait_id={}, method_offset_in_trait={})", + debug!("trans_object_shim(object_ty={}, upcast_trait_ref={}, method_offset_in_trait={})", object_ty.repr(tcx), - trait_id.repr(tcx), + upcast_trait_ref.repr(tcx), method_offset_in_trait); let object_trait_ref = @@ -575,7 +582,6 @@ pub fn trans_object_shim<'a, 'tcx>( }; // Upcast to the trait in question and extract out the substitutions. - let upcast_trait_ref = traits::upcast(ccx.tcx(), object_trait_ref.clone(), trait_id).unwrap(); let upcast_trait_ref = ty::erase_late_bound_regions(tcx, &upcast_trait_ref); let object_substs = upcast_trait_ref.substs.clone().erase_regions(); debug!("trans_object_shim: object_substs={}", object_substs.repr(tcx)); diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 1e7b90d5a1892..0da2c86066ae9 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -59,7 +59,6 @@ use middle::ty::{self, RegionEscape, ToPolyTraitRef, Ty}; use rscope::{self, UnelidableRscope, RegionScope, ElidableRscope, ObjectLifetimeDefaultRscope, ShiftedRscope, BindingRscope}; use util::common::{ErrorReported, FN_OUTPUT_NAME}; -use util::nodemap::DefIdMap; use util::ppaux::{self, Repr, UserString}; use std::iter::{repeat, AdditiveIterator}; @@ -73,15 +72,33 @@ use syntax::print::pprust; pub trait AstConv<'tcx> { fn tcx<'a>(&'a self) -> &'a ty::ctxt<'tcx>; + /// Identify the type scheme for an item with a type, like a type + /// alias, fn, or struct. This allows you to figure out the set of + /// type parameters defined on the item. fn get_item_type_scheme(&self, span: Span, id: ast::DefId) -> Result, ErrorReported>; + /// Returns the `TraitDef` for a given trait. This allows you to + /// figure out the set of type parameters defined on the trait. fn get_trait_def(&self, span: Span, id: ast::DefId) -> Result>, ErrorReported>; + /// Ensure that the super-predicates for the trait with the given + /// id are available and also for the transitive set of + /// super-predicates. + fn ensure_super_predicates(&self, span: Span, id: ast::DefId) + -> Result<(), ErrorReported>; + + /// Returns the set of bounds in scope for the type parameter with + /// the given id. fn get_type_parameter_bounds(&self, span: Span, def_id: ast::NodeId) -> Result>, ErrorReported>; + /// Returns true if the trait with id `trait_def_id` defines an + /// associated type with the name `name`. + fn trait_defines_associated_type_named(&self, trait_def_id: ast::DefId, name: ast::Name) + -> bool; + /// Return an (optional) substitution to convert bound type parameters that /// are in scope into free ones. This function should only return Some /// within a fn body. @@ -783,7 +800,7 @@ fn ast_type_binding_to_projection_predicate<'tcx>( // We want to produce `>::T == foo`. // Simple case: X is defined in the current trait. - if trait_defines_associated_type_named(this, trait_ref.def_id, binding.item_name) { + if this.trait_defines_associated_type_named(trait_ref.def_id, binding.item_name) { return Ok(ty::ProjectionPredicate { projection_ty: ty::ProjectionTy { trait_ref: trait_ref, @@ -810,9 +827,11 @@ fn ast_type_binding_to_projection_predicate<'tcx>( tcx.mk_substs(dummy_substs))); } + try!(this.ensure_super_predicates(binding.span, trait_ref.def_id)); + let mut candidates: Vec = traits::supertraits(tcx, trait_ref.to_poly_trait_ref()) - .filter(|r| trait_defines_associated_type_named(this, r.def_id(), binding.item_name)) + .filter(|r| this.trait_defines_associated_type_named(r.def_id(), binding.item_name)) .collect(); // If converting for an object type, then remove the dummy-ty from `Self` now. @@ -1029,14 +1048,19 @@ fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>, let ty_param_name = tcx.ty_param_defs.borrow()[ty_param_node_id].name; - // FIXME(#20300) -- search where clauses, not bounds - let bounds = - this.get_type_parameter_bounds(span, ty_param_node_id) - .unwrap_or(Vec::new()); + let bounds = match this.get_type_parameter_bounds(span, ty_param_node_id) { + Ok(v) => v, + Err(ErrorReported) => { return (tcx.types.err, ty_path_def); } + }; + + // ensure the super predicates and stop if we encountered an error + if bounds.iter().any(|b| this.ensure_super_predicates(span, b.def_id()).is_err()) { + return (this.tcx().types.err, ty_path_def); + } let mut suitable_bounds: Vec<_> = traits::transitive_bounds(tcx, &bounds) - .filter(|b| trait_defines_associated_type_named(this, b.def_id(), assoc_name)) + .filter(|b| this.trait_defines_associated_type_named(b.def_id(), assoc_name)) .collect(); if suitable_bounds.len() == 0 { @@ -1090,16 +1114,6 @@ fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>, (ty, def::DefAssociatedTy(trait_did, item_did)) } -fn trait_defines_associated_type_named(this: &AstConv, - trait_def_id: ast::DefId, - assoc_name: ast::Name) - -> bool -{ - let tcx = this.tcx(); - let trait_def = ty::lookup_trait_def(tcx, trait_def_id); - trait_def.associated_type_names.contains(&assoc_name) -} - fn qpath_to_ty<'tcx>(this: &AstConv<'tcx>, rscope: &RegionScope, span: Span, @@ -1275,20 +1289,9 @@ pub fn ast_ty_to_ty<'tcx>(this: &AstConv<'tcx>, let tcx = this.tcx(); - let mut ast_ty_to_ty_cache = tcx.ast_ty_to_ty_cache.borrow_mut(); - match ast_ty_to_ty_cache.get(&ast_ty.id) { - Some(&ty::atttce_resolved(ty)) => return ty, - Some(&ty::atttce_unresolved) => { - span_err!(tcx.sess, ast_ty.span, E0246, - "illegal recursive type; insert an enum \ - or struct in the cycle, if this is \ - desired"); - return this.tcx().types.err; - } - None => { /* go on */ } + if let Some(&ty) = tcx.ast_ty_to_ty_cache.borrow().get(&ast_ty.id) { + return ty; } - ast_ty_to_ty_cache.insert(ast_ty.id, ty::atttce_unresolved); - drop(ast_ty_to_ty_cache); let typ = match ast_ty.node { ast::TyVec(ref ty) => { @@ -1421,7 +1424,7 @@ pub fn ast_ty_to_ty<'tcx>(this: &AstConv<'tcx>, } }; - tcx.ast_ty_to_ty_cache.borrow_mut().insert(ast_ty.id, ty::atttce_resolved(typ)); + tcx.ast_ty_to_ty_cache.borrow_mut().insert(ast_ty.id, typ); return typ; } @@ -1838,6 +1841,10 @@ fn compute_object_lifetime_bound<'tcx>( return ast_region_to_region(tcx, r); } + if let Err(ErrorReported) = this.ensure_super_predicates(span,principal_trait_ref.def_id()) { + return ty::ReStatic; + } + // No explicit region bound specified. Therefore, examine trait // bounds and see if we can derive region bounds from those. let derived_region_bounds = @@ -1923,34 +1930,11 @@ pub fn partition_bounds<'a>(tcx: &ty::ctxt, let mut builtin_bounds = ty::empty_builtin_bounds(); let mut region_bounds = Vec::new(); let mut trait_bounds = Vec::new(); - let mut trait_def_ids = DefIdMap(); for ast_bound in ast_bounds { match *ast_bound { ast::TraitTyParamBound(ref b, ast::TraitBoundModifier::None) => { match ::lookup_full_def(tcx, b.trait_ref.path.span, b.trait_ref.ref_id) { def::DefTrait(trait_did) => { - match trait_def_ids.get(&trait_did) { - // Already seen this trait. We forbid - // duplicates in the list (for some - // reason). - Some(span) => { - span_err!( - tcx.sess, b.trait_ref.path.span, E0127, - "trait `{}` already appears in the \ - list of bounds", - b.trait_ref.path.user_string(tcx)); - tcx.sess.span_note( - *span, - "previous appearance is here"); - - continue; - } - - None => { } - } - - trait_def_ids.insert(trait_did, b.trait_ref.path.span); - if ty::try_add_builtin_trait(tcx, trait_did, &mut builtin_bounds) { diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index d7db21f3a2f76..6ef6953f707fb 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -634,16 +634,21 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { target_trait_def_id: ast::DefId) -> ty::PolyTraitRef<'tcx> { - match traits::upcast(self.tcx(), source_trait_ref.clone(), target_trait_def_id) { - Some(super_trait_ref) => super_trait_ref, - None => { - self.tcx().sess.span_bug( - self.span, - &format!("cannot upcast `{}` to `{}`", - source_trait_ref.repr(self.tcx()), - target_trait_def_id.repr(self.tcx()))); - } + let upcast_trait_refs = traits::upcast(self.tcx(), + source_trait_ref.clone(), + target_trait_def_id); + + // must be exactly one trait ref or we'd get an ambig error etc + if upcast_trait_refs.len() != 1 { + self.tcx().sess.span_bug( + self.span, + &format!("cannot uniquely upcast `{}` to `{}`: `{}`", + source_trait_ref.repr(self.tcx()), + target_trait_def_id.repr(self.tcx()), + upcast_trait_refs.repr(self.tcx()))); } + + upcast_trait_refs.into_iter().next().unwrap() } fn replace_late_bound_regions_with_fresh_var(&self, value: &ty::Binder) -> T diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index fbf002b709ee5..718804d317fb0 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -456,13 +456,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { debug!("elaborate_bounds(bounds={})", bounds.repr(self.tcx())); let tcx = self.tcx(); - let mut cache = HashSet::new(); for bound_trait_ref in traits::transitive_bounds(tcx, bounds) { - // Already visited this trait, skip it. - if !cache.insert(bound_trait_ref.def_id()) { - continue; - } - let (pos, method) = match trait_method(tcx, bound_trait_ref.def_id(), self.method_name) { @@ -1269,10 +1263,12 @@ impl<'tcx> Candidate<'tcx> { fn to_trait_data(&self) -> Option<(ast::DefId,MethodIndex)> { match self.kind { - InherentImplCandidate(..) | - ObjectCandidate(..) => { + InherentImplCandidate(..) => { None } + ObjectCandidate(trait_def_id, method_num, _) => { + Some((trait_def_id, method_num)) + } ClosureCandidate(trait_def_id, method_num) => { Some((trait_def_id, method_num)) } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index a12ff04912c49..9db98bf00cda8 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1218,6 +1218,11 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> { Ok(ty::lookup_trait_def(self.tcx(), id)) } + fn ensure_super_predicates(&self, _: Span, _: ast::DefId) -> Result<(), ErrorReported> { + // all super predicates are ensured during collect pass + Ok(()) + } + fn get_free_substs(&self) -> Option<&Substs<'tcx>> { Some(&self.inh.param_env.free_substs) } @@ -1248,6 +1253,15 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> { Ok(r) } + fn trait_defines_associated_type_named(&self, + trait_def_id: ast::DefId, + assoc_name: ast::Name) + -> bool + { + let trait_def = ty::lookup_trait_def(self.ccx.tcx, trait_def_id); + trait_def.associated_type_names.contains(&assoc_name) + } + fn ty_infer(&self, _span: Span) -> Ty<'tcx> { self.infcx().next_ty_var() } diff --git a/src/librustc_typeck/check/wf.rs b/src/librustc_typeck/check/wf.rs index e024526d0016f..fcc5eea76062d 100644 --- a/src/librustc_typeck/check/wf.rs +++ b/src/librustc_typeck/check/wf.rs @@ -281,12 +281,13 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { // Find the supertrait bounds. This will add `int:Bar`. let poly_trait_ref = ty::Binder(trait_ref); - let predicates = ty::predicates_for_trait_ref(fcx.tcx(), &poly_trait_ref); + let predicates = ty::lookup_super_predicates(fcx.tcx(), poly_trait_ref.def_id()); + let predicates = predicates.instantiate_supertrait(fcx.tcx(), &poly_trait_ref); let predicates = { let selcx = &mut traits::SelectionContext::new(fcx.infcx(), fcx); traits::normalize(selcx, cause.clone(), &predicates) }; - for predicate in predicates.value { + for predicate in predicates.value.predicates { fcx.register_predicate(traits::Obligation::new(cause.clone(), predicate)); } for obligation in predicates.obligations { diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 74fed6cbf3937..12bcf5cf5ada4 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -26,35 +26,17 @@ 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 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 -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): +The phasing of type conversion is somewhat complicated. There is no +clear set of phases we can enforce (e.g., converting traits first, +then types, or something like that) because the user can introduce +arbitrary interdependencies. So instead we generally convert things +lazilly and on demand, and include logic that checks for cycles. +Demand is driven by calls to `AstConv::get_item_type_scheme` or +`AstConv::lookup_trait_def`. + +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 @@ -64,16 +46,13 @@ 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. +for other items. There are some shortcomings in this design: -- Cycles through trait definitions (e.g. supertraits) are not currently - detected by astconv. (#12511) +- Before walking the set of supertraits for a given trait, you must + call `ensure_super_predicates` on that trait def-id. Otherwise, + `lookup_super_predicates` will result in ICEs. - 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. @@ -169,6 +148,7 @@ struct ItemCtxt<'a,'tcx:'a> { enum AstConvRequest { GetItemTypeScheme(ast::DefId), GetTraitDef(ast::DefId), + EnsureSuperPredicates(ast::DefId), GetTypeParameterBounds(ast::NodeId), } @@ -245,7 +225,7 @@ impl<'a,'tcx> CrateCtxt<'a,'tcx> { request: AstConvRequest, code: F) -> Result - where F: FnOnce() -> R + where F: FnOnce() -> Result { { let mut stack = self.stack.borrow_mut(); @@ -263,7 +243,7 @@ impl<'a,'tcx> CrateCtxt<'a,'tcx> { let result = code(); self.stack.borrow_mut().pop(); - Ok(result) + result } fn report_cycle(&self, @@ -284,6 +264,11 @@ impl<'a,'tcx> CrateCtxt<'a,'tcx> { &format!("the cycle begins when processing `{}`...", ty::item_path_str(tcx, def_id))); } + AstConvRequest::EnsureSuperPredicates(def_id) => { + tcx.sess.note( + &format!("the cycle begins when computing the supertraits of `{}`...", + ty::item_path_str(tcx, def_id))); + } AstConvRequest::GetTypeParameterBounds(id) => { let def = tcx.type_parameter_def(id); tcx.sess.note( @@ -301,6 +286,11 @@ impl<'a,'tcx> CrateCtxt<'a,'tcx> { &format!("...which then requires processing `{}`...", ty::item_path_str(tcx, def_id))); } + AstConvRequest::EnsureSuperPredicates(def_id) => { + tcx.sess.note( + &format!("...which then requires computing the supertraits of `{}`...", + ty::item_path_str(tcx, def_id))); + } AstConvRequest::GetTypeParameterBounds(id) => { let def = tcx.type_parameter_def(id); tcx.sess.note( @@ -318,6 +308,12 @@ impl<'a,'tcx> CrateCtxt<'a,'tcx> { &format!("...which then again requires processing `{}`, completing the cycle.", ty::item_path_str(tcx, def_id))); } + AstConvRequest::EnsureSuperPredicates(def_id) => { + tcx.sess.note( + &format!("...which then again requires computing the supertraits of `{}`, \ + completing the cycle.", + ty::item_path_str(tcx, def_id))); + } AstConvRequest::GetTypeParameterBounds(id) => { let def = tcx.type_parameter_def(id); tcx.sess.note( @@ -327,6 +323,41 @@ impl<'a,'tcx> CrateCtxt<'a,'tcx> { } } } + + /// Loads the trait def for a given trait, returning ErrorReported if a cycle arises. + fn get_trait_def(&self, trait_id: ast::DefId) + -> Rc> + { + let tcx = self.tcx; + + if trait_id.krate != ast::LOCAL_CRATE { + return ty::lookup_trait_def(tcx, trait_id) + } + + let item = match tcx.map.get(trait_id.node) { + ast_map::NodeItem(item) => item, + _ => tcx.sess.bug(&format!("get_trait_def({}): not an item", trait_id.repr(tcx))) + }; + + trait_def_of_item(self, &*item) + } + + /// Ensure that the (transitive) super predicates for + /// `trait_def_id` are available. This will report a cycle error + /// if a trait `X` (transitively) extends itself in some form. + fn ensure_super_predicates(&self, span: Span, trait_def_id: ast::DefId) + -> Result<(), ErrorReported> + { + self.cycle_check(span, AstConvRequest::EnsureSuperPredicates(trait_def_id), || { + let def_ids = ensure_super_predicates_step(self, trait_def_id); + + for def_id in def_ids { + try!(self.ensure_super_predicates(span, def_id)); + } + + Ok(()) + }) + } } impl<'a,'tcx> ItemCtxt<'a,'tcx> { @@ -342,7 +373,7 @@ impl<'a, 'tcx> AstConv<'tcx> for ItemCtxt<'a, 'tcx> { -> Result, ErrorReported> { self.ccx.cycle_check(span, AstConvRequest::GetItemTypeScheme(id), || { - type_scheme_of_def_id(self.ccx, id) + Ok(type_scheme_of_def_id(self.ccx, id)) }) } @@ -350,20 +381,49 @@ impl<'a, 'tcx> AstConv<'tcx> for ItemCtxt<'a, 'tcx> { -> Result>, ErrorReported> { self.ccx.cycle_check(span, AstConvRequest::GetTraitDef(id), || { - get_trait_def(self.ccx, id) + Ok(self.ccx.get_trait_def(id)) }) } + fn ensure_super_predicates(&self, + span: Span, + trait_def_id: ast::DefId) + -> Result<(), ErrorReported> + { + debug!("ensure_super_predicates(trait_def_id={})", + trait_def_id.repr(self.tcx())); + + self.ccx.ensure_super_predicates(span, trait_def_id) + } + + fn get_type_parameter_bounds(&self, span: Span, node_id: ast::NodeId) -> Result>, ErrorReported> { self.ccx.cycle_check(span, AstConvRequest::GetTypeParameterBounds(node_id), || { - self.param_bounds.get_type_parameter_bounds(self, span, node_id) + let v = self.param_bounds.get_type_parameter_bounds(self, span, node_id) + .into_iter() + .filter_map(|p| p.to_opt_poly_trait_ref()) + .collect(); + Ok(v) }) } + fn trait_defines_associated_type_named(&self, + trait_def_id: ast::DefId, + assoc_name: ast::Name) + -> bool + { + if trait_def_id.krate == ast::LOCAL_CRATE { + trait_defines_associated_type_named(self.ccx, trait_def_id.node, assoc_name) + } else { + let trait_def = ty::lookup_trait_def(self.tcx(), trait_def_id); + trait_def.associated_type_names.contains(&assoc_name) + } + } + fn ty_infer(&self, span: Span) -> Ty<'tcx> { span_err!(self.tcx().sess, span, E0121, "the type placeholder `_` is not allowed within types on item signatures"); @@ -387,7 +447,7 @@ trait GetTypeParameterBounds<'tcx> { astconv: &AstConv<'tcx>, span: Span, node_id: ast::NodeId) - -> Vec>; + -> Vec>; } /// Find bounds from both elements of the tuple. @@ -398,7 +458,7 @@ impl<'a,'b,'tcx,A,B> GetTypeParameterBounds<'tcx> for (&'a A,&'b B) astconv: &AstConv<'tcx>, span: Span, node_id: ast::NodeId) - -> Vec> + -> Vec> { let mut v = self.0.get_type_parameter_bounds(astconv, span, node_id); v.extend(self.1.get_type_parameter_bounds(astconv, span, node_id).into_iter()); @@ -412,7 +472,7 @@ impl<'tcx> GetTypeParameterBounds<'tcx> for () { _astconv: &AstConv<'tcx>, _span: Span, _node_id: ast::NodeId) - -> Vec> + -> Vec> { Vec::new() } @@ -426,29 +486,28 @@ impl<'tcx> GetTypeParameterBounds<'tcx> for ty::GenericPredicates<'tcx> { astconv: &AstConv<'tcx>, _span: Span, node_id: ast::NodeId) - -> Vec> + -> Vec> { let def = astconv.tcx().type_parameter_def(node_id); self.predicates .iter() - .filter_map(|predicate| { - match *predicate { + .filter(|predicate| { + match **predicate { ty::Predicate::Trait(ref data) => { - if data.0.self_ty().is_param(def.space, def.index) { - Some(data.to_poly_trait_ref()) - } else { - None - } + data.skip_binder().self_ty().is_param(def.space, def.index) + } + ty::Predicate::TypeOutlives(ref data) => { + data.skip_binder().0.is_param(def.space, def.index) } ty::Predicate::Equate(..) | ty::Predicate::RegionOutlives(..) | - ty::Predicate::TypeOutlives(..) | ty::Predicate::Projection(..) => { - None + false } } }) + .cloned() .collect() } } @@ -462,7 +521,7 @@ impl<'tcx> GetTypeParameterBounds<'tcx> for ast::Generics { astconv: &AstConv<'tcx>, _: Span, node_id: ast::NodeId) - -> Vec> + -> Vec> { // In the AST, bounds can derive from two places. Either // written inline like `` or in a where clause like @@ -476,7 +535,7 @@ impl<'tcx> GetTypeParameterBounds<'tcx> for ast::Generics { .iter() .filter(|p| p.id == node_id) .flat_map(|p| p.bounds.iter()) - .filter_map(|b| poly_trait_ref_from_bound(astconv, ty, b, &mut Vec::new())); + .flat_map(|b| predicates_from_bound(astconv, ty, b).into_iter()); let from_where_clauses = self.where_clause @@ -488,7 +547,7 @@ impl<'tcx> GetTypeParameterBounds<'tcx> for ast::Generics { }) .filter(|bp| is_param(astconv.tcx(), &bp.bounded_ty, node_id)) .flat_map(|bp| bp.bounds.iter()) - .filter_map(|b| poly_trait_ref_from_bound(astconv, ty, b, &mut Vec::new())); + .flat_map(|b| predicates_from_bound(astconv, ty, b).into_iter()); from_ty_params.chain(from_where_clauses).collect() } @@ -505,10 +564,15 @@ fn is_param<'tcx>(tcx: &ty::ctxt<'tcx>, { if let ast::TyPath(None, _) = ast_ty.node { let path_res = tcx.def_map.borrow()[ast_ty.id]; - if let def::DefTyParam(_, _, def_id, _) = path_res.base_def { - path_res.depth == 0 && def_id == local_def(param_id) - } else { - false + match path_res.base_def { + def::DefSelfTy(node_id) => + path_res.depth == 0 && node_id == param_id, + + def::DefTyParam(_, _, def_id, _) => + path_res.depth == 0 && def_id == local_def(param_id), + + _ => + false, } } else { false @@ -777,9 +841,10 @@ fn convert_methods<'a,'tcx,'i,I>(ccx: &CrateCtxt<'a, 'tcx>, rcvr_visibility: ast::Visibility) where I: Iterator { - debug!("convert_methods(untransformed_rcvr_ty={}, rcvr_ty_generics={})", + debug!("convert_methods(untransformed_rcvr_ty={}, rcvr_ty_generics={}, rcvr_ty_predicates={})", untransformed_rcvr_ty.repr(ccx.tcx), - rcvr_ty_generics.repr(ccx.tcx)); + rcvr_ty_generics.repr(ccx.tcx), + rcvr_ty_predicates.repr(ccx.tcx)); let tcx = ccx.tcx; let mut seen_methods = FnvHashSet(); @@ -1023,6 +1088,8 @@ fn convert_item(ccx: &CrateCtxt, it: &ast::Item) { }, ast::ItemTrait(_, _, _, ref trait_items) => { let trait_def = trait_def_of_item(ccx, it); + let _: Result<(), ErrorReported> = // any error is already reported, can ignore + ccx.ensure_super_predicates(it.span, local_def(it.id)); convert_trait_predicates(ccx, it); let trait_predicates = ty::lookup_predicates(ccx.tcx, local_def(it.id)); @@ -1168,22 +1235,89 @@ fn convert_struct<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, } } -fn get_trait_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, - trait_id: ast::DefId) - -> Rc> { +/// Ensures that the super-predicates of the trait with def-id +/// trait_def_id are converted and stored. This does NOT ensure that +/// the transitive super-predicates are converted; that is the job of +/// the `ensure_super_predicates()` method in the `AstConv` impl +/// above. Returns a list of trait def-ids that must be ensured as +/// well to guarantee that the transitive superpredicates are +/// converted. +fn ensure_super_predicates_step(ccx: &CrateCtxt, + trait_def_id: ast::DefId) + -> Vec +{ let tcx = ccx.tcx; - if trait_id.krate != ast::LOCAL_CRATE { - return ty::lookup_trait_def(tcx, trait_id) - } + debug!("ensure_super_predicates_step(trait_def_id={})", trait_def_id.repr(tcx)); - match tcx.map.get(trait_id.node) { - ast_map::NodeItem(item) => trait_def_of_item(ccx, &*item), - _ => { - tcx.sess.bug(&format!("get_trait_def({}): not an item", - trait_id.node)) - } + if trait_def_id.krate != ast::LOCAL_CRATE { + // If this trait comes from an external crate, then all of the + // supertraits it may depend on also must come from external + // crates, and hence all of them already have their + // super-predicates "converted" (and available from crate + // meta-data), so there is no need to transitively test them. + return Vec::new(); } + + let superpredicates = tcx.super_predicates.borrow().get(&trait_def_id).cloned(); + let superpredicates = superpredicates.unwrap_or_else(|| { + let trait_node_id = trait_def_id.node; + + let item = match ccx.tcx.map.get(trait_node_id) { + ast_map::NodeItem(item) => item, + _ => ccx.tcx.sess.bug(&format!("trait_node_id {} is not an item", trait_node_id)) + }; + + let (generics, bounds) = match item.node { + ast::ItemTrait(_, ref generics, ref supertraits, _) => (generics, supertraits), + _ => tcx.sess.span_bug(item.span, + "ensure_super_predicates_step invoked on non-trait"), + }; + + // In-scope when converting the superbounds for `Trait` are + // that `Self:Trait` as well as any bounds that appear on the + // generic types: + let trait_def = trait_def_of_item(ccx, item); + let self_predicate = ty::GenericPredicates { + predicates: VecPerParamSpace::new(vec![], + vec![trait_def.trait_ref.as_predicate()], + vec![]) + }; + let scope = &(generics, &self_predicate); + + // Convert the bounds that follow the colon, e.g. `Bar+Zed` in `trait Foo : Bar+Zed`. + let self_param_ty = ty::mk_self_type(tcx); + let superbounds1 = compute_bounds(&ccx.icx(scope), self_param_ty, bounds, + SizedByDefault::No, item.span); + let superbounds1 = ty::predicates(tcx, self_param_ty, &superbounds1); + + // Convert any explicit superbounds in the where clause, + // e.g. `trait Foo where Self : Bar`: + let superbounds2 = generics.get_type_parameter_bounds(&ccx.icx(scope), item.span, item.id); + + // Combine the two lists to form the complete set of superbounds: + let superbounds = superbounds1.into_iter().chain(superbounds2.into_iter()).collect(); + let superpredicates = ty::GenericPredicates { + predicates: VecPerParamSpace::new(superbounds, vec![], vec![]) + }; + debug!("superpredicates for trait {} = {}", + local_def(item.id).repr(ccx.tcx), + superpredicates.repr(ccx.tcx)); + + tcx.super_predicates.borrow_mut().insert(trait_def_id, superpredicates.clone()); + + superpredicates + }); + + let def_ids: Vec<_> = superpredicates.predicates + .iter() + .filter_map(|p| p.to_opt_poly_trait_ref()) + .map(|tr| tr.def_id()) + .collect(); + + debug!("ensure_super_predicates_step: def_ids={}", def_ids.repr(tcx)); + + def_ids } fn trait_def_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, @@ -1197,18 +1331,9 @@ fn trait_def_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, return def.clone(); } - let (unsafety, generics, bounds, items) = match it.node { - ast::ItemTrait(unsafety, - ref generics, - ref supertraits, - ref items) => { - (unsafety, generics, supertraits, items) - } - ref s => { - tcx.sess.span_bug( - it.span, - &format!("trait_def_of_item invoked on {:?}", s)); - } + let (unsafety, generics, items) = match it.node { + ast::ItemTrait(unsafety, ref generics, _, ref items) => (unsafety, generics, items), + _ => tcx.sess.span_bug(it.span, "trait_def_of_item invoked on non-trait"), }; let paren_sugar = ty::has_attr(tcx, def_id, "rustc_paren_sugar"); @@ -1226,15 +1351,6 @@ fn trait_def_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let ty_generics = ty_generics_for_trait(ccx, it.id, substs, generics); - let self_param_ty = ty::ParamTy::for_self().to_ty(ccx.tcx); - - // supertraits: - let bounds = compute_bounds(&ccx.icx(generics), - self_param_ty, - bounds, - SizedByDefault::No, - it.span); - let associated_type_names: Vec<_> = items.iter() .filter_map(|item| { @@ -1254,7 +1370,6 @@ fn trait_def_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, paren_sugar: paren_sugar, unsafety: unsafety, generics: ty_generics, - bounds: bounds, trait_ref: trait_ref, associated_type_names: associated_type_names, }); @@ -1296,6 +1411,30 @@ fn trait_def_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, } } +fn trait_defines_associated_type_named(ccx: &CrateCtxt, + trait_node_id: ast::NodeId, + assoc_name: ast::Name) + -> bool +{ + let item = match ccx.tcx.map.get(trait_node_id) { + ast_map::NodeItem(item) => item, + _ => ccx.tcx.sess.bug(&format!("trait_node_id {} is not an item", trait_node_id)) + }; + + let trait_items = match item.node { + ast::ItemTrait(_, _, _, ref trait_items) => trait_items, + _ => ccx.tcx.sess.bug(&format!("trait_node_id {} is not a trait", trait_node_id)) + }; + + trait_items.iter() + .any(|trait_item| { + match *trait_item { + ast::TypeTraitItem(ref t) => t.ty_param.ident.name == assoc_name, + ast::RequiredMethod(..) | ast::ProvidedMethod(..) => false, + } + }) +} + fn convert_trait_predicates<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, it: &ast::Item) { let tcx = ccx.tcx; let trait_def = trait_def_of_item(ccx, it); @@ -1311,19 +1450,14 @@ fn convert_trait_predicates<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, it: &ast::Item) } }; - 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 super_predicates = ty::lookup_super_predicates(ccx.tcx, def_id); // `ty_generic_predicates` below will consider the bounds on the type // parameters (including `Self`) and the explicit where-clauses, // but to get the full set of predicates on a trait we need to add // in the supertrait bounds and anything declared on the // associated types. - let mut base_predicates = - ty::GenericPredicates { - predicates: VecPerParamSpace::new(super_predicates, vec![], vec![]) - }; + let mut base_predicates = super_predicates; // Add in a predicate that `Self:Trait` (where `Trait` is the // current trait). This is needed for builtin bounds. @@ -1953,7 +2087,7 @@ fn compute_object_lifetime_default<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, } } -enum SizedByDefault { Yes, No } +enum SizedByDefault { Yes, No, } /// Translate the AST's notion of ty param bounds (which are an enum consisting of a newtyped Ty or /// a region) to ty's notion of ty param bounds, which can either be user-defined traits, or the @@ -1975,11 +2109,6 @@ fn compute_bounds<'tcx>(astconv: &AstConv<'tcx>, &mut param_bounds.builtin_bounds, ast_bounds, span); - - check_bounds_compatible(astconv, - param_ty, - ¶m_bounds, - span); } param_bounds.trait_bounds.sort_by(|a,b| a.def_id().cmp(&b.def_id())); @@ -1987,48 +2116,32 @@ fn compute_bounds<'tcx>(astconv: &AstConv<'tcx>, param_bounds } -fn check_bounds_compatible<'tcx>(astconv: &AstConv<'tcx>, - param_ty: Ty<'tcx>, - param_bounds: &ty::ParamBounds<'tcx>, - span: Span) { - let tcx = astconv.tcx(); - if !param_bounds.builtin_bounds.contains(&ty::BoundSized) { - ty::each_bound_trait_and_supertraits( - tcx, - ¶m_bounds.trait_bounds, - |trait_ref| { - match astconv.get_trait_def(span, trait_ref.def_id()) { - Ok(trait_def) => { - if trait_def.bounds.builtin_bounds.contains(&ty::BoundSized) { - span_err!(tcx.sess, span, E0129, - "incompatible bounds on `{}`, \ - bound `{}` does not allow unsized type", - param_ty.user_string(tcx), - trait_ref.user_string(tcx)); - } - } - Err(ErrorReported) => { } - } - true - }); - } -} - -/// Converts a specific TyParamBound from the AST into the -/// appropriate poly-trait-reference. -fn poly_trait_ref_from_bound<'tcx>(astconv: &AstConv<'tcx>, - param_ty: Ty<'tcx>, - bound: &ast::TyParamBound, - projections: &mut Vec>) - -> Option> +/// Converts a specific TyParamBound from the AST into a set of +/// predicates that apply to the self-type. A vector is returned +/// because this can be anywhere from 0 predicates (`T:?Sized` adds no +/// predicates) to 1 (`T:Foo`) to many (`T:Bar` adds `T:Bar` +/// and `::X == i32`). +fn predicates_from_bound<'tcx>(astconv: &AstConv<'tcx>, + param_ty: Ty<'tcx>, + bound: &ast::TyParamBound) + -> Vec> { match *bound { ast::TraitTyParamBound(ref tr, ast::TraitBoundModifier::None) => { - Some(conv_poly_trait_ref(astconv, param_ty, tr, projections)) + let mut projections = Vec::new(); + let pred = conv_poly_trait_ref(astconv, param_ty, tr, &mut projections); + projections.into_iter() + .map(|p| p.as_predicate()) + .chain(Some(pred.as_predicate()).into_iter()) + .collect() } - ast::TraitTyParamBound(_, ast::TraitBoundModifier::Maybe) | - ast::RegionTyParamBound(_) => { - None + ast::RegionTyParamBound(ref lifetime) => { + let region = ast_region_to_region(astconv.tcx(), lifetime); + let pred = ty::Binder(ty::OutlivesPredicate(param_ty, region)); + vec![ty::Predicate::TypeOutlives(pred)] + } + ast::TraitTyParamBound(_, ast::TraitBoundModifier::Maybe) => { + Vec::new() } } } diff --git a/src/librustc_typeck/variance.rs b/src/librustc_typeck/variance.rs index 1fba4a21ccd37..9b27128ce2ffd 100644 --- a/src/librustc_typeck/variance.rs +++ b/src/librustc_typeck/variance.rs @@ -644,9 +644,9 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ConstraintContext<'a, 'tcx> { ast::ItemTrait(..) => { let trait_def = ty::lookup_trait_def(tcx, did); - let predicates = ty::predicates(tcx, ty::mk_self_type(tcx), &trait_def.bounds); + let predicates = ty::lookup_super_predicates(tcx, did); self.add_constraints_from_predicates(&trait_def.generics, - &predicates, + predicates.predicates.as_slice(), self.covariant); let trait_items = ty::trait_items(tcx, did); diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 2bb4424822a47..db41bf9fee329 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -165,14 +165,12 @@ pub fn build_external_trait(cx: &DocContext, tcx: &ty::ctxt, _ => unreachable!() } }); - 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, &predicates, subst::TypeSpace).clean(cx), items: items.collect(), - bounds: bounds, + bounds: vec![], // supertraits can be found in the list of predicates } } diff --git a/src/test/compile-fail/cycle-projection-based-on-where-clause.rs b/src/test/compile-fail/cycle-projection-based-on-where-clause.rs index abcbf567d4436..5ca0700ce6eda 100644 --- a/src/test/compile-fail/cycle-projection-based-on-where-clause.rs +++ b/src/test/compile-fail/cycle-projection-based-on-where-clause.rs @@ -25,7 +25,7 @@ trait Trait { type Item; } struct A where T : Trait, T : Add - //~^ ERROR illegal recursive type + //~^ ERROR unsupported cyclic reference between types/traits detected { data: T } diff --git a/src/test/compile-fail/unsized4.rs b/src/test/compile-fail/cycle-trait-default-type-trait.rs similarity index 62% rename from src/test/compile-fail/unsized4.rs rename to src/test/compile-fail/cycle-trait-default-type-trait.rs index f8b8ad2bf2efa..e6caeb34a8c8f 100644 --- a/src/test/compile-fail/unsized4.rs +++ b/src/test/compile-fail/cycle-trait-default-type-trait.rs @@ -1,4 +1,4 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// 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. // @@ -8,12 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// Test that bounds are sized-compatible. +// Test a cycle where a type parameter on a trait has a default that +// again references the trait. -trait T : Sized {} -fn f() { -//~^ERROR incompatible bounds on `Y`, bound `T` does not allow unsized type +trait Foo> { + //~^ ERROR unsupported cyclic reference } -pub fn main() { -} +fn main() { } diff --git a/src/test/compile-fail/cycle-trait-supertrait-indirect.rs b/src/test/compile-fail/cycle-trait-supertrait-indirect.rs index 6ebd9a1bcb6e2..c9bfde3f4ed12 100644 --- a/src/test/compile-fail/cycle-trait-supertrait-indirect.rs +++ b/src/test/compile-fail/cycle-trait-supertrait-indirect.rs @@ -12,9 +12,12 @@ // a direct participant in the cycle. trait A: B { + //~^ ERROR unsupported cyclic reference } -trait B: C { } +trait B: C { + //~^ ERROR unsupported cyclic reference +} trait C: B { } //~^ ERROR unsupported cyclic reference diff --git a/src/test/compile-fail/infinite-vec-type-recursion.rs b/src/test/compile-fail/infinite-vec-type-recursion.rs index 5bcba350b2ecb..e5120840f7672 100644 --- a/src/test/compile-fail/infinite-vec-type-recursion.rs +++ b/src/test/compile-fail/infinite-vec-type-recursion.rs @@ -8,9 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern: illegal recursive type - - type x = Vec; +//~^ ERROR unsupported cyclic reference fn main() { let b: x = Vec::new(); } diff --git a/src/test/compile-fail/issue-18389.rs b/src/test/compile-fail/issue-18389.rs index 9065a5b9605b7..271c31bd37548 100644 --- a/src/test/compile-fail/issue-18389.rs +++ b/src/test/compile-fail/issue-18389.rs @@ -12,18 +12,17 @@ use std::any::Any; use std::any::TypeId; +use std::marker::MarkerTrait; -pub trait Pt {} -pub trait Rt {} +pub trait Pt : MarkerTrait {} +pub trait Rt : MarkerTrait {} trait Private { fn call(&self, p: P, r: R); } -pub trait Public: Private< +pub trait Public: Private< //~ ERROR private trait in exported type parameter bound ::P, -//~^ ERROR illegal recursive type; insert an enum or struct in the cycle, if this is desired ::R -//~^ ERROR unsupported cyclic reference between types/traits detected > { type P; type R; diff --git a/src/test/compile-fail/issue-3953.rs b/src/test/compile-fail/issue-3953.rs deleted file mode 100644 index 0f1dd2d7fd6a8..0000000000000 --- a/src/test/compile-fail/issue-3953.rs +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2012 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. - -// ignore-tidy-linelength - -use std::cmp::PartialEq; - -trait Hahaha: PartialEq + PartialEq { - //~^ ERROR trait `PartialEq` already appears in the list of bounds -} - -struct Lol(isize); - -impl Hahaha for Lol { } - -impl PartialEq for Lol { - fn eq(&self, other: &Lol) -> bool { **self != **other } - fn ne(&self, other: &Lol) -> bool { **self == **other } -} - -fn main() { - if Lol(2) == Lol(4) { - println!("2 == 4"); - } else { - println!("2 != 4"); - } -} diff --git a/src/test/compile-fail/duplicate-trait-bounds.rs b/src/test/compile-fail/traits-assoc-type-in-supertrait-bad.rs similarity index 50% rename from src/test/compile-fail/duplicate-trait-bounds.rs rename to src/test/compile-fail/traits-assoc-type-in-supertrait-bad.rs index d9aa9d9dfccc7..971869ba85bb0 100644 --- a/src/test/compile-fail/duplicate-trait-bounds.rs +++ b/src/test/compile-fail/traits-assoc-type-in-supertrait-bad.rs @@ -1,4 +1,4 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// 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. // @@ -8,8 +8,19 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -trait Foo {} +// Test case where an associated type is referenced from within the +// supertrait definition, and the impl makes the wrong +// associations. Issue #20220. -fn foo() {} //~ ERROR `Foo` already appears in the list of bounds +use std::vec::IntoIter; -fn main() {} +pub trait Foo: Iterator::Key> { + type Key; +} + +impl Foo for IntoIter { //~ ERROR type mismatch + type Key = u32; +} + +fn main() { +} diff --git a/src/test/compile-fail/traits-repeated-supertrait-ambig.rs b/src/test/compile-fail/traits-repeated-supertrait-ambig.rs new file mode 100644 index 0000000000000..d61ac6f08d99d --- /dev/null +++ b/src/test/compile-fail/traits-repeated-supertrait-ambig.rs @@ -0,0 +1,53 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test a case of a trait which extends the same supertrait twice, but +// with difference type parameters. Test then that when we don't give +// enough information to pick between these, no selection is made. In +// this particular case, the two choices are i64/u64 -- so when we use +// an integer literal, we wind up falling this literal back to i32. +// See also `run-pass/trait-repeated-supertrait.rs`. + +trait CompareTo { + fn same_as(&self, t: T) -> bool; +} + +trait CompareToInts : CompareTo + CompareTo { +} + +impl CompareTo for i64 { + fn same_as(&self, t: i64) -> bool { *self == t } +} + +impl CompareTo for i64 { + fn same_as(&self, t: u64) -> bool { *self == (t as i64) } +} + +impl CompareToInts for i64 { } + +fn with_obj(c: &CompareToInts) -> bool { + c.same_as(22) //~ ERROR `CompareTo` is not implemented +} + +fn with_trait(c: &C) -> bool { + c.same_as(22) //~ ERROR `CompareTo` is not implemented +} + +fn with_ufcs1(c: &C) -> bool { + CompareToInts::same_as(c, 22) //~ ERROR `CompareTo` is not implemented +} + +fn with_ufcs2(c: &C) -> bool { + CompareTo::same_as(c, 22) //~ ERROR `CompareTo` is not implemented +} + +fn main() { + assert_eq!(22_i64.same_as(22), true); //~ ERROR `CompareTo` is not implemented +} diff --git a/src/test/run-pass/traits-assoc-type-in-supertrait.rs b/src/test/run-pass/traits-assoc-type-in-supertrait.rs new file mode 100644 index 0000000000000..6a4a6710131e3 --- /dev/null +++ b/src/test/run-pass/traits-assoc-type-in-supertrait.rs @@ -0,0 +1,31 @@ +// 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 case where an associated type is referenced from within the +// supertrait definition. Issue #20220. + +use std::vec::IntoIter; + +pub trait Foo: Iterator::Key> { + type Key; +} + +impl Foo for IntoIter { + type Key = i32; +} + +fn sum_foo>(f: F) -> i32 { + f.fold(0, |a,b| a + b) +} + +fn main() { + let x = sum_foo(vec![11, 10, 1].into_iter()); + assert_eq!(x, 22); +} diff --git a/src/test/run-pass/traits-repeated-supertrait.rs b/src/test/run-pass/traits-repeated-supertrait.rs new file mode 100644 index 0000000000000..fdaa8d6f4d6ef --- /dev/null +++ b/src/test/run-pass/traits-repeated-supertrait.rs @@ -0,0 +1,56 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test a case of a trait which extends the same supertrait twice, but +// with difference type parameters. Test that we can invoke the +// various methods in various ways successfully. +// See also `compile-fail/trait-repeated-supertrait-ambig.rs`. + +trait CompareTo { + fn same_as(&self, t: T) -> bool; +} + +trait CompareToInts : CompareTo + CompareTo { +} + +impl CompareTo for i64 { + fn same_as(&self, t: i64) -> bool { *self == t } +} + +impl CompareTo for i64 { + fn same_as(&self, t: u64) -> bool { *self == (t as i64) } +} + +impl CompareToInts for i64 { } + +fn with_obj(c: &CompareToInts) -> bool { + c.same_as(22_i64) && c.same_as(22_u64) +} + +fn with_trait(c: &C) -> bool { + c.same_as(22_i64) && c.same_as(22_u64) +} + +fn with_ufcs1(c: &C) -> bool { + CompareToInts::same_as(c, 22_i64) && CompareToInts::same_as(c, 22_u64) +} + +fn with_ufcs2(c: &C) -> bool { + CompareTo::same_as(c, 22_i64) && CompareTo::same_as(c, 22_u64) +} + +fn main() { + assert_eq!(22_i64.same_as(22_i64), true); + assert_eq!(22_i64.same_as(22_u64), true); + assert_eq!(with_trait(&22), true); + assert_eq!(with_obj(&22), true); + assert_eq!(with_ufcs1(&22), true); + assert_eq!(with_ufcs2(&22), true); +}