Separate supertrait collection from processing a TraitDef. This allows

us to construct trait-references and do other things without forcing a
full evaluation of the supertraits. One downside of this scheme is that
we must invoke `ensure_super_predicates` before using any construct that
might require knowing about the super-predicates.
This commit is contained in:
Niko Matsakis 2015-02-24 09:24:42 -05:00
parent 4ee002a17c
commit bc9ae36dba
23 changed files with 486 additions and 416 deletions

View File

@ -84,7 +84,6 @@ pub const tag_mod_impl: uint = 0x38;
pub const tag_item_trait_item: uint = 0x39; pub const tag_item_trait_item: uint = 0x39;
pub const tag_item_trait_ref: uint = 0x3a; pub const tag_item_trait_ref: uint = 0x3a;
pub const tag_item_super_trait_ref: uint = 0x3b;
// discriminator value for variants // discriminator value for variants
pub const tag_disr_val: uint = 0x3c; 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_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_items_data_region: uint = 0x8e;
pub const tag_region_param_def: uint = 0x8f; 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: uint = 0xa1;
pub const tag_codemap_filemap: uint = 0xa2; pub const tag_codemap_filemap: uint = 0xa2;
pub const tag_item_super_predicates: uint = 0xa3;

View File

@ -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) 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<Rc<ty::TraitRef<'tcx>>> {
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) pub fn get_type_name_if_impl(cstore: &cstore::CStore, def: ast::DefId)
-> Option<ast::Name> { -> Option<ast::Name> {
let cdata = cstore.get_crate_data(def.krate); 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) 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, pub fn get_field_type<'tcx>(tcx: &ty::ctxt<'tcx>, class_id: ast::DefId,
def: ast::DefId) -> ty::TypeScheme<'tcx> { def: ast::DefId) -> ty::TypeScheme<'tcx> {
let cstore = &tcx.sess.cstore; let cstore = &tcx.sess.cstore;

View File

@ -22,9 +22,8 @@ use metadata::csearch::MethodInfo;
use metadata::csearch; use metadata::csearch;
use metadata::cstore; use metadata::cstore;
use metadata::tydecode::{parse_ty_data, parse_region_data, parse_def_id, use metadata::tydecode::{parse_ty_data, parse_region_data, parse_def_id,
parse_type_param_def_data, parse_bounds_data, parse_type_param_def_data, parse_bare_fn_ty_data,
parse_bare_fn_ty_data, parse_trait_ref_data, parse_trait_ref_data, parse_predicate_data};
parse_predicate_data};
use middle::def; use middle::def;
use middle::lang_items; use middle::lang_items;
use middle::subst; 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) 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<ast::DefId> { fn enum_variant_ids(item: rbml::Doc, cdata: Cmd) -> Vec<ast::DefId> {
let mut ids: Vec<ast::DefId> = Vec::new(); let mut ids: Vec<ast::DefId> = Vec::new();
let v = tag_items_data_item_variant; 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 item_doc = lookup_item(item_id, cdata.data());
let generics = doc_generics(item_doc, tcx, cdata, tag_item_generics); 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 unsafety = parse_unsafety(item_doc);
let associated_type_names = parse_associated_type_names(item_doc); let associated_type_names = parse_associated_type_names(item_doc);
let paren_sugar = parse_paren_sugar(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, paren_sugar: paren_sugar,
unsafety: unsafety, unsafety: unsafety,
generics: generics, generics: generics,
bounds: bounds,
trait_ref: item_trait_ref(item_doc, tcx, cdata), trait_ref: item_trait_ref(item_doc, tcx, cdata),
associated_type_names: associated_type_names, 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) 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>) pub fn get_type<'tcx>(cdata: Cmd, id: ast::NodeId, tcx: &ty::ctxt<'tcx>)
-> ty::TypeScheme<'tcx> -> ty::TypeScheme<'tcx>
{ {
@ -971,24 +965,6 @@ pub fn get_provided_trait_methods<'tcx>(intr: Rc<IdentInterner>,
return result; return result;
} }
/// Returns the supertraits of the given trait.
pub fn get_supertraits<'tcx>(cdata: Cmd, id: ast::NodeId, tcx: &ty::ctxt<'tcx>)
-> Vec<Rc<ty::TraitRef<'tcx>>> {
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, pub fn get_type_name_if_impl(cdata: Cmd,
node_id: ast::NodeId) -> Option<ast::Name> { node_id: ast::NodeId) -> Option<ast::Name> {
let item = lookup_item(node_id, cdata.data()); let item = lookup_item(node_id, cdata.data());

View File

@ -206,21 +206,6 @@ pub fn write_region(ecx: &EncodeContext,
tyencode::enc_region(rbml_w, ty_str_ctxt, r); 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>, fn encode_type<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
rbml_w: &mut Encoder, rbml_w: &mut Encoder,
typ: Ty<'tcx>) { typ: Ty<'tcx>) {
@ -728,6 +713,7 @@ fn encode_generics<'a, 'tcx>(rbml_w: &mut Encoder,
tcx: ecx.tcx, tcx: ecx.tcx,
abbrevs: &ecx.type_abbrevs abbrevs: &ecx.type_abbrevs
}; };
for param in generics.types.iter() { for param in generics.types.iter() {
rbml_w.start_tag(tag_type_param_def); rbml_w.start_tag(tag_type_param_def);
tyencode::enc_type_param_def(rbml_w, ty_str_ctxt, param); 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(); 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() { for (space, _, predicate) in predicates.predicates.iter_enumerated() {
rbml_w.start_tag(tag_predicate); rbml_w.start_tag(tag_predicate);
@ -769,7 +771,15 @@ fn encode_generics<'a, 'tcx>(rbml_w: &mut Encoder,
rbml_w.end_tag(); 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(); 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_paren_sugar(rbml_w, trait_def.paren_sugar);
encode_associated_type_names(rbml_w, &trait_def.associated_type_names); 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_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_trait_ref(rbml_w, ecx, &*trait_def.trait_ref, tag_item_trait_ref);
encode_name(rbml_w, item.ident.name); encode_name(rbml_w, item.ident.name);
encode_attributes(rbml_w, &item.attrs); encode_attributes(rbml_w, &item.attrs);
@ -1304,8 +1316,6 @@ fn encode_info_for_item(ecx: &EncodeContext,
} }
encode_path(rbml_w, path.clone()); 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 the implementations of this trait.
encode_extension_implementations(ecx, rbml_w, def_id); encode_extension_implementations(ecx, rbml_w, def_id);

View File

@ -22,7 +22,7 @@ use super::elaborate_predicates;
use middle::subst::{self, SelfSpace, TypeSpace}; use middle::subst::{self, SelfSpace, TypeSpace};
use middle::traits; use middle::traits;
use middle::ty::{self, Ty}; use middle::ty::{self, ToPolyTraitRef, Ty};
use std::rc::Rc; use std::rc::Rc;
use syntax::ast; use syntax::ast;
use util::ppaux::Repr; 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_def = ty::lookup_trait_def(tcx, trait_def_id);
let trait_ref = trait_def.trait_ref.clone(); 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
.predicates
.into_iter() .into_iter()
.map(|predicate| predicate.subst_supertrait(tcx, &trait_ref))
.any(|predicate| { .any(|predicate| {
match predicate { match predicate {
ty::Predicate::Trait(ref data) => { ty::Predicate::Trait(ref data) => {

View File

@ -1455,9 +1455,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let principal = let principal =
data.principal_trait_ref_with_self_ty(self.tcx(), data.principal_trait_ref_with_self_ty(self.tcx(),
self.tcx().types.err); self.tcx().types.err);
let desired_def_id = obligation.predicate.def_id();
for tr in util::supertraits(self.tcx(), principal) { for tr in util::supertraits(self.tcx(), principal) {
let td = ty::lookup_trait_def(self.tcx(), tr.def_id()); if tr.def_id() == desired_def_id {
if td.bounds.builtin_bounds.contains(&bound) {
return Ok(If(Vec::new())) return Ok(If(Vec::new()))
} }
} }

View File

@ -117,9 +117,17 @@ impl<'cx, 'tcx> Elaborator<'cx, 'tcx> {
fn push(&mut self, predicate: &ty::Predicate<'tcx>) { fn push(&mut self, predicate: &ty::Predicate<'tcx>) {
match *predicate { match *predicate {
ty::Predicate::Trait(ref data) => { ty::Predicate::Trait(ref data) => {
let mut predicates = // Predicates declared on the trait.
ty::predicates_for_trait_ref(self.tcx, let predicates = ty::lookup_super_predicates(self.tcx, data.def_id());
&data.to_poly_trait_ref());
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 // Only keep those bounds that we haven't already
// seen. This is necessary to prevent infinite // seen. This is necessary to prevent infinite

View File

@ -17,7 +17,6 @@ pub use self::InferTy::*;
pub use self::InferRegion::*; pub use self::InferRegion::*;
pub use self::ImplOrTraitItemId::*; pub use self::ImplOrTraitItemId::*;
pub use self::ClosureKind::*; pub use self::ClosureKind::*;
pub use self::ast_ty_to_ty_cache_entry::*;
pub use self::Variance::*; pub use self::Variance::*;
pub use self::AutoAdjustment::*; pub use self::AutoAdjustment::*;
pub use self::Representability::*; pub use self::Representability::*;
@ -266,12 +265,6 @@ pub struct creader_cache_key {
pub len: uint 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)] #[derive(Clone, PartialEq, RustcDecodable, RustcEncodable)]
pub struct ItemVariances { pub struct ItemVariances {
pub types: VecPerParamSpace<Variance>, pub types: VecPerParamSpace<Variance>,
@ -716,6 +709,14 @@ pub struct ctxt<'tcx> {
/// associated predicates. /// associated predicates.
pub predicates: RefCell<DefIdMap<GenericPredicates<'tcx>>>, pub predicates: RefCell<DefIdMap<GenericPredicates<'tcx>>>,
/// 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<DefIdMap<GenericPredicates<'tcx>>>,
/// Maps from node-id of a trait object cast (like `foo as /// Maps from node-id of a trait object cast (like `foo as
/// Box<Trait>`) to the trait reference. /// Box<Trait>`) to the trait reference.
pub object_cast_map: ObjectCastMap<'tcx>, pub object_cast_map: ObjectCastMap<'tcx>,
@ -727,7 +728,7 @@ pub struct ctxt<'tcx> {
pub rcache: RefCell<FnvHashMap<creader_cache_key, Ty<'tcx>>>, pub rcache: RefCell<FnvHashMap<creader_cache_key, Ty<'tcx>>>,
pub short_names_cache: RefCell<FnvHashMap<Ty<'tcx>, String>>, pub short_names_cache: RefCell<FnvHashMap<Ty<'tcx>, String>>,
pub tc_cache: RefCell<FnvHashMap<Ty<'tcx>, TypeContents>>, pub tc_cache: RefCell<FnvHashMap<Ty<'tcx>, TypeContents>>,
pub ast_ty_to_ty_cache: RefCell<NodeMap<ast_ty_to_ty_cache_entry<'tcx>>>, pub ast_ty_to_ty_cache: RefCell<NodeMap<Ty<'tcx>>>,
pub enum_var_cache: RefCell<DefIdMap<Rc<Vec<Rc<VariantInfo<'tcx>>>>>>, pub enum_var_cache: RefCell<DefIdMap<Rc<Vec<Rc<VariantInfo<'tcx>>>>>>,
pub ty_param_defs: RefCell<NodeMap<TypeParameterDef<'tcx>>>, pub ty_param_defs: RefCell<NodeMap<TypeParameterDef<'tcx>>>,
pub adjustments: RefCell<NodeMap<AutoAdjustment<'tcx>>>, pub adjustments: RefCell<NodeMap<AutoAdjustment<'tcx>>>,
@ -1352,7 +1353,7 @@ pub enum sty<'tcx> {
/// definition and not a concrete use of it. To get the correct `ty_enum` /// 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 /// 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 /// the `ast_ty_to_ty_cache`. This is probably true for `ty_struct` as
/// well.` /// well.
ty_enum(DefId, &'tcx Substs<'tcx>), ty_enum(DefId, &'tcx Substs<'tcx>),
ty_uniq(Ty<'tcx>), ty_uniq(Ty<'tcx>),
ty_str, ty_str,
@ -1495,6 +1496,27 @@ impl<'tcx> PolyTraitRef<'tcx> {
#[derive(Clone, PartialEq, Eq, Hash, Debug)] #[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub struct Binder<T>(pub T); pub struct Binder<T>(pub T);
impl<T> Binder<T> {
/// 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;
/// - compariing 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)] #[derive(Clone, Copy, PartialEq)]
pub enum IntVarValue { pub enum IntVarValue {
IntType(ast::IntTy), IntType(ast::IntTy),
@ -1817,6 +1839,16 @@ impl<'tcx> GenericPredicates<'tcx> {
predicates: self.predicates.subst(tcx, substs), 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)] #[derive(Clone, PartialEq, Eq, Hash, Debug)]
@ -1840,6 +1872,93 @@ pub enum Predicate<'tcx> {
Projection(PolyProjectionPredicate<'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)] #[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub struct TraitPredicate<'tcx> { pub struct TraitPredicate<'tcx> {
pub trait_ref: Rc<TraitRef<'tcx>> pub trait_ref: Rc<TraitRef<'tcx>>
@ -2324,9 +2443,6 @@ pub struct TraitDef<'tcx> {
/// implements the trait. /// implements the trait.
pub generics: Generics<'tcx>, pub generics: Generics<'tcx>,
/// The "supertrait" bounds.
pub bounds: ParamBounds<'tcx>,
pub trait_ref: Rc<ty::TraitRef<'tcx>>, pub trait_ref: Rc<ty::TraitRef<'tcx>>,
/// A list of the associated types defined in this trait. Useful /// 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()), impl_trait_refs: RefCell::new(NodeMap()),
trait_defs: RefCell::new(DefIdMap()), trait_defs: RefCell::new(DefIdMap()),
predicates: RefCell::new(DefIdMap()), predicates: RefCell::new(DefIdMap()),
super_predicates: RefCell::new(DefIdMap()),
object_cast_map: RefCell::new(NodeMap()), object_cast_map: RefCell::new(NodeMap()),
map: map, map: map,
intrinsic_defs: RefCell::new(DefIdMap()), 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) pub fn lookup_predicates<'tcx>(cx: &ctxt<'tcx>, did: ast::DefId)
-> GenericPredicates<'tcx> -> 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 /// Given the did of a trait, returns its superpredicates.
/// on the trait, with appropriate substitutions applied. Basically, pub fn lookup_super_predicates<'tcx>(cx: &ctxt<'tcx>, did: ast::DefId)
/// this applies a filter to the where clauses on the trait, returning -> GenericPredicates<'tcx>
/// those that have the form:
///
/// Self : SuperTrait<...>
/// Self : 'region
pub fn predicates_for_trait_ref<'tcx>(tcx: &ctxt<'tcx>,
trait_ref: &PolyTraitRef<'tcx>)
-> Vec<ty::Predicate<'tcx>>
{ {
let trait_def = lookup_trait_def(tcx, trait_ref.def_id()); memoized(&cx.super_predicates, did, |did: DefId| {
assert!(did.krate != ast::LOCAL_CRATE);
debug!("bounds_for_trait_ref(trait_def={:?}, trait_ref={:?})", csearch::get_super_predicates(cx, did)
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)
} }
pub fn predicates<'tcx>( pub fn predicates<'tcx>(

View File

@ -820,9 +820,8 @@ impl<'tcx> Repr<'tcx> for ty::TraitRef<'tcx> {
impl<'tcx> Repr<'tcx> for ty::TraitDef<'tcx> { impl<'tcx> Repr<'tcx> for ty::TraitDef<'tcx> {
fn repr(&self, tcx: &ctxt<'tcx>) -> String { fn repr(&self, tcx: &ctxt<'tcx>) -> String {
format!("TraitDef(generics={}, bounds={}, trait_ref={})", format!("TraitDef(generics={}, trait_ref={})",
self.generics.repr(tcx), self.generics.repr(tcx),
self.bounds.repr(tcx),
self.trait_ref.repr(tcx)) self.trait_ref.repr(tcx))
} }
} }

View File

@ -432,8 +432,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
} }
def::DefTy(..) => { def::DefTy(..) => {
let tty = match self.cx.tcx.ast_ty_to_ty_cache.borrow().get(&id) { let tty = match self.cx.tcx.ast_ty_to_ty_cache.borrow().get(&id) {
Some(&ty::atttce_resolved(t)) => t, Some(&t) => t,
_ => panic!("ast_ty_to_ty_cache was incomplete after typeck!") None => panic!("ast_ty_to_ty_cache was incomplete after typeck!")
}; };
if !ty::is_ffi_safe(self.cx.tcx, tty) { if !ty::is_ffi_safe(self.cx.tcx, tty) {

View File

@ -59,7 +59,6 @@ use middle::ty::{self, RegionEscape, ToPolyTraitRef, Ty};
use rscope::{self, UnelidableRscope, RegionScope, ElidableRscope, use rscope::{self, UnelidableRscope, RegionScope, ElidableRscope,
ObjectLifetimeDefaultRscope, ShiftedRscope, BindingRscope}; ObjectLifetimeDefaultRscope, ShiftedRscope, BindingRscope};
use util::common::{ErrorReported, FN_OUTPUT_NAME}; use util::common::{ErrorReported, FN_OUTPUT_NAME};
use util::nodemap::DefIdMap;
use util::ppaux::{self, Repr, UserString}; use util::ppaux::{self, Repr, UserString};
use std::iter::{repeat, AdditiveIterator}; use std::iter::{repeat, AdditiveIterator};
@ -73,15 +72,30 @@ use syntax::print::pprust;
pub trait AstConv<'tcx> { pub trait AstConv<'tcx> {
fn tcx<'a>(&'a self) -> &'a ty::ctxt<'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) fn get_item_type_scheme(&self, span: Span, id: ast::DefId)
-> Result<ty::TypeScheme<'tcx>, ErrorReported>; -> Result<ty::TypeScheme<'tcx>, 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) fn get_trait_def(&self, span: Span, id: ast::DefId)
-> Result<Rc<ty::TraitDef<'tcx>>, ErrorReported>; -> Result<Rc<ty::TraitDef<'tcx>>, 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) fn get_type_parameter_bounds(&self, span: Span, def_id: ast::NodeId)
-> Result<Vec<ty::PolyTraitRef<'tcx>>, ErrorReported>; -> Result<Vec<ty::PolyTraitRef<'tcx>>, 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) fn trait_defines_associated_type_named(&self, trait_def_id: ast::DefId, name: ast::Name)
-> bool; -> bool;
@ -813,6 +827,8 @@ fn ast_type_binding_to_projection_predicate<'tcx>(
tcx.mk_substs(dummy_substs))); tcx.mk_substs(dummy_substs)));
} }
try!(this.ensure_super_predicates(binding.span, trait_ref.def_id));
let mut candidates: Vec<ty::PolyTraitRef> = let mut candidates: Vec<ty::PolyTraitRef> =
traits::supertraits(tcx, trait_ref.to_poly_trait_ref()) traits::supertraits(tcx, trait_ref.to_poly_trait_ref())
.filter(|r| this.trait_defines_associated_type_named(r.def_id(), binding.item_name)) .filter(|r| this.trait_defines_associated_type_named(r.def_id(), binding.item_name))
@ -1032,10 +1048,15 @@ fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>,
let ty_param_name = tcx.ty_param_defs.borrow()[ty_param_node_id].name; let ty_param_name = tcx.ty_param_defs.borrow()[ty_param_node_id].name;
// FIXME(#20300) -- search where clauses, not bounds let bounds = match this.get_type_parameter_bounds(span, ty_param_node_id) {
let bounds = Ok(v) => v,
this.get_type_parameter_bounds(span, ty_param_node_id) Err(ErrorReported) => { return (tcx.types.err, ty_path_def); }
.unwrap_or(Vec::new()); };
// 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<_> = let mut suitable_bounds: Vec<_> =
traits::transitive_bounds(tcx, &bounds) traits::transitive_bounds(tcx, &bounds)
@ -1268,20 +1289,9 @@ pub fn ast_ty_to_ty<'tcx>(this: &AstConv<'tcx>,
let tcx = this.tcx(); let tcx = this.tcx();
let mut ast_ty_to_ty_cache = tcx.ast_ty_to_ty_cache.borrow_mut(); if let Some(&ty) = tcx.ast_ty_to_ty_cache.borrow().get(&ast_ty.id) {
match ast_ty_to_ty_cache.get(&ast_ty.id) { return ty;
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 */ }
}
ast_ty_to_ty_cache.insert(ast_ty.id, ty::atttce_unresolved);
drop(ast_ty_to_ty_cache);
let typ = match ast_ty.node { let typ = match ast_ty.node {
ast::TyVec(ref ty) => { ast::TyVec(ref ty) => {
@ -1414,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; return typ;
} }
@ -1831,6 +1841,10 @@ fn compute_object_lifetime_bound<'tcx>(
return ast_region_to_region(tcx, r); 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 // No explicit region bound specified. Therefore, examine trait
// bounds and see if we can derive region bounds from those. // bounds and see if we can derive region bounds from those.
let derived_region_bounds = let derived_region_bounds =
@ -1916,34 +1930,11 @@ pub fn partition_bounds<'a>(tcx: &ty::ctxt,
let mut builtin_bounds = ty::empty_builtin_bounds(); let mut builtin_bounds = ty::empty_builtin_bounds();
let mut region_bounds = Vec::new(); let mut region_bounds = Vec::new();
let mut trait_bounds = Vec::new(); let mut trait_bounds = Vec::new();
let mut trait_def_ids = DefIdMap();
for ast_bound in ast_bounds { for ast_bound in ast_bounds {
match *ast_bound { match *ast_bound {
ast::TraitTyParamBound(ref b, ast::TraitBoundModifier::None) => { ast::TraitTyParamBound(ref b, ast::TraitBoundModifier::None) => {
match ::lookup_full_def(tcx, b.trait_ref.path.span, b.trait_ref.ref_id) { match ::lookup_full_def(tcx, b.trait_ref.path.span, b.trait_ref.ref_id) {
def::DefTrait(trait_did) => { 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, if ty::try_add_builtin_trait(tcx,
trait_did, trait_did,
&mut builtin_bounds) { &mut builtin_bounds) {

View File

@ -456,13 +456,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
debug!("elaborate_bounds(bounds={})", bounds.repr(self.tcx())); debug!("elaborate_bounds(bounds={})", bounds.repr(self.tcx()));
let tcx = self.tcx(); let tcx = self.tcx();
let mut cache = HashSet::new();
for bound_trait_ref in traits::transitive_bounds(tcx, bounds) { 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, let (pos, method) = match trait_method(tcx,
bound_trait_ref.def_id(), bound_trait_ref.def_id(),
self.method_name) { self.method_name) {
@ -1269,10 +1263,12 @@ impl<'tcx> Candidate<'tcx> {
fn to_trait_data(&self) -> Option<(ast::DefId,MethodIndex)> { fn to_trait_data(&self) -> Option<(ast::DefId,MethodIndex)> {
match self.kind { match self.kind {
InherentImplCandidate(..) | InherentImplCandidate(..) => {
ObjectCandidate(..) => {
None None
} }
ObjectCandidate(trait_def_id, method_num, _) => {
Some((trait_def_id, method_num))
}
ClosureCandidate(trait_def_id, method_num) => { ClosureCandidate(trait_def_id, method_num) => {
Some((trait_def_id, method_num)) Some((trait_def_id, method_num))
} }

View File

@ -1218,6 +1218,11 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
Ok(ty::lookup_trait_def(self.tcx(), id)) 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>> { fn get_free_substs(&self) -> Option<&Substs<'tcx>> {
Some(&self.inh.param_env.free_substs) Some(&self.inh.param_env.free_substs)
} }

View File

@ -281,12 +281,13 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
// Find the supertrait bounds. This will add `int:Bar`. // Find the supertrait bounds. This will add `int:Bar`.
let poly_trait_ref = ty::Binder(trait_ref); 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 predicates = {
let selcx = &mut traits::SelectionContext::new(fcx.infcx(), fcx); let selcx = &mut traits::SelectionContext::new(fcx.infcx(), fcx);
traits::normalize(selcx, cause.clone(), &predicates) 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)); fcx.register_predicate(traits::Obligation::new(cause.clone(), predicate));
} }
for obligation in predicates.obligations { for obligation in predicates.obligations {

View File

@ -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 core type along with a list of the bounds for each parameter. Type
parameters themselves are represented as `ty_param()` instances. parameters themselves are represented as `ty_param()` instances.
The phasing of type conversion is somewhat complicated. There are a The phasing of type conversion is somewhat complicated. There is no
number of possible cycles that can arise. 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`.
Converting types can require: Currently, we "convert" types and traits in three phases (note that
conversion only affects the types of items / enum variants / methods;
1. `Foo<X>` where `Foo` is a type alias, or trait requires knowing: it does not e.g. compute the types of individual expressions):
- 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<X>` 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 `<T as Trait>::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):
0. Intrinsics 0. Intrinsics
1. Trait definitions 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 and invoking an appropriate function (e.g., `trait_def_of_item` or
`convert_item`). However, it is possible that while converting an `convert_item`). However, it is possible that while converting an
item, we may need to compute the *type scheme* or *trait definition* item, we may need to compute the *type scheme* or *trait definition*
for other items. This is a kind of shallow conversion that is for other items.
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: There are some shortcomings in this design:
- Cycles through trait definitions (e.g. supertraits) are not currently - Before walking the set of supertraits for a given trait, you must
detected by astconv. (#12511) 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 - Because the type scheme includes defaults, cycles through type
parameter defaults are illegal even if those defaults are never parameter defaults are illegal even if those defaults are never
employed. This is not necessarily a bug. employed. This is not necessarily a bug.
@ -169,6 +148,7 @@ struct ItemCtxt<'a,'tcx:'a> {
enum AstConvRequest { enum AstConvRequest {
GetItemTypeScheme(ast::DefId), GetItemTypeScheme(ast::DefId),
GetTraitDef(ast::DefId), GetTraitDef(ast::DefId),
EnsureSuperPredicates(ast::DefId),
GetTypeParameterBounds(ast::NodeId), GetTypeParameterBounds(ast::NodeId),
} }
@ -245,7 +225,7 @@ impl<'a,'tcx> CrateCtxt<'a,'tcx> {
request: AstConvRequest, request: AstConvRequest,
code: F) code: F)
-> Result<R,ErrorReported> -> Result<R,ErrorReported>
where F: FnOnce() -> R where F: FnOnce() -> Result<R,ErrorReported>
{ {
{ {
let mut stack = self.stack.borrow_mut(); let mut stack = self.stack.borrow_mut();
@ -263,7 +243,7 @@ impl<'a,'tcx> CrateCtxt<'a,'tcx> {
let result = code(); let result = code();
self.stack.borrow_mut().pop(); self.stack.borrow_mut().pop();
Ok(result) result
} }
fn report_cycle(&self, fn report_cycle(&self,
@ -284,6 +264,11 @@ impl<'a,'tcx> CrateCtxt<'a,'tcx> {
&format!("the cycle begins when processing `{}`...", &format!("the cycle begins when processing `{}`...",
ty::item_path_str(tcx, def_id))); 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) => { AstConvRequest::GetTypeParameterBounds(id) => {
let def = tcx.type_parameter_def(id); let def = tcx.type_parameter_def(id);
tcx.sess.note( tcx.sess.note(
@ -301,6 +286,11 @@ impl<'a,'tcx> CrateCtxt<'a,'tcx> {
&format!("...which then requires processing `{}`...", &format!("...which then requires processing `{}`...",
ty::item_path_str(tcx, def_id))); 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) => { AstConvRequest::GetTypeParameterBounds(id) => {
let def = tcx.type_parameter_def(id); let def = tcx.type_parameter_def(id);
tcx.sess.note( tcx.sess.note(
@ -318,6 +308,12 @@ impl<'a,'tcx> CrateCtxt<'a,'tcx> {
&format!("...which then again requires processing `{}`, completing the cycle.", &format!("...which then again requires processing `{}`, completing the cycle.",
ty::item_path_str(tcx, def_id))); 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) => { AstConvRequest::GetTypeParameterBounds(id) => {
let def = tcx.type_parameter_def(id); let def = tcx.type_parameter_def(id);
tcx.sess.note( 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<ty::TraitDef<'tcx>>
{
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> { impl<'a,'tcx> ItemCtxt<'a,'tcx> {
@ -342,7 +373,7 @@ impl<'a, 'tcx> AstConv<'tcx> for ItemCtxt<'a, 'tcx> {
-> Result<ty::TypeScheme<'tcx>, ErrorReported> -> Result<ty::TypeScheme<'tcx>, ErrorReported>
{ {
self.ccx.cycle_check(span, AstConvRequest::GetItemTypeScheme(id), || { 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,17 +381,33 @@ impl<'a, 'tcx> AstConv<'tcx> for ItemCtxt<'a, 'tcx> {
-> Result<Rc<ty::TraitDef<'tcx>>, ErrorReported> -> Result<Rc<ty::TraitDef<'tcx>>, ErrorReported>
{ {
self.ccx.cycle_check(span, AstConvRequest::GetTraitDef(id), || { 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, fn get_type_parameter_bounds(&self,
span: Span, span: Span,
node_id: ast::NodeId) node_id: ast::NodeId)
-> Result<Vec<ty::PolyTraitRef<'tcx>>, ErrorReported> -> Result<Vec<ty::PolyTraitRef<'tcx>>, ErrorReported>
{ {
self.ccx.cycle_check(span, AstConvRequest::GetTypeParameterBounds(node_id), || { 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)
}) })
} }
@ -400,7 +447,7 @@ trait GetTypeParameterBounds<'tcx> {
astconv: &AstConv<'tcx>, astconv: &AstConv<'tcx>,
span: Span, span: Span,
node_id: ast::NodeId) node_id: ast::NodeId)
-> Vec<ty::PolyTraitRef<'tcx>>; -> Vec<ty::Predicate<'tcx>>;
} }
/// Find bounds from both elements of the tuple. /// Find bounds from both elements of the tuple.
@ -411,7 +458,7 @@ impl<'a,'b,'tcx,A,B> GetTypeParameterBounds<'tcx> for (&'a A,&'b B)
astconv: &AstConv<'tcx>, astconv: &AstConv<'tcx>,
span: Span, span: Span,
node_id: ast::NodeId) node_id: ast::NodeId)
-> Vec<ty::PolyTraitRef<'tcx>> -> Vec<ty::Predicate<'tcx>>
{ {
let mut v = self.0.get_type_parameter_bounds(astconv, span, node_id); let mut v = self.0.get_type_parameter_bounds(astconv, span, node_id);
v.extend(self.1.get_type_parameter_bounds(astconv, span, node_id).into_iter()); v.extend(self.1.get_type_parameter_bounds(astconv, span, node_id).into_iter());
@ -425,7 +472,7 @@ impl<'tcx> GetTypeParameterBounds<'tcx> for () {
_astconv: &AstConv<'tcx>, _astconv: &AstConv<'tcx>,
_span: Span, _span: Span,
_node_id: ast::NodeId) _node_id: ast::NodeId)
-> Vec<ty::PolyTraitRef<'tcx>> -> Vec<ty::Predicate<'tcx>>
{ {
Vec::new() Vec::new()
} }
@ -439,29 +486,28 @@ impl<'tcx> GetTypeParameterBounds<'tcx> for ty::GenericPredicates<'tcx> {
astconv: &AstConv<'tcx>, astconv: &AstConv<'tcx>,
_span: Span, _span: Span,
node_id: ast::NodeId) node_id: ast::NodeId)
-> Vec<ty::PolyTraitRef<'tcx>> -> Vec<ty::Predicate<'tcx>>
{ {
let def = astconv.tcx().type_parameter_def(node_id); let def = astconv.tcx().type_parameter_def(node_id);
self.predicates self.predicates
.iter() .iter()
.filter_map(|predicate| { .filter(|predicate| {
match *predicate { match **predicate {
ty::Predicate::Trait(ref data) => { ty::Predicate::Trait(ref data) => {
if data.0.self_ty().is_param(def.space, def.index) { data.skip_binder().self_ty().is_param(def.space, def.index)
Some(data.to_poly_trait_ref())
} else {
None
} }
ty::Predicate::TypeOutlives(ref data) => {
data.skip_binder().0.is_param(def.space, def.index)
} }
ty::Predicate::Equate(..) | ty::Predicate::Equate(..) |
ty::Predicate::RegionOutlives(..) | ty::Predicate::RegionOutlives(..) |
ty::Predicate::TypeOutlives(..) |
ty::Predicate::Projection(..) => { ty::Predicate::Projection(..) => {
None false
} }
} }
}) })
.cloned()
.collect() .collect()
} }
} }
@ -475,7 +521,7 @@ impl<'tcx> GetTypeParameterBounds<'tcx> for ast::Generics {
astconv: &AstConv<'tcx>, astconv: &AstConv<'tcx>,
_: Span, _: Span,
node_id: ast::NodeId) node_id: ast::NodeId)
-> Vec<ty::PolyTraitRef<'tcx>> -> Vec<ty::Predicate<'tcx>>
{ {
// In the AST, bounds can derive from two places. Either // In the AST, bounds can derive from two places. Either
// written inline like `<T:Foo>` or in a where clause like // written inline like `<T:Foo>` or in a where clause like
@ -489,7 +535,7 @@ impl<'tcx> GetTypeParameterBounds<'tcx> for ast::Generics {
.iter() .iter()
.filter(|p| p.id == node_id) .filter(|p| p.id == node_id)
.flat_map(|p| p.bounds.iter()) .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 = let from_where_clauses =
self.where_clause self.where_clause
@ -501,7 +547,7 @@ impl<'tcx> GetTypeParameterBounds<'tcx> for ast::Generics {
}) })
.filter(|bp| is_param(astconv.tcx(), &bp.bounded_ty, node_id)) .filter(|bp| is_param(astconv.tcx(), &bp.bounded_ty, node_id))
.flat_map(|bp| bp.bounds.iter()) .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() from_ty_params.chain(from_where_clauses).collect()
} }
@ -518,10 +564,15 @@ fn is_param<'tcx>(tcx: &ty::ctxt<'tcx>,
{ {
if let ast::TyPath(None, _) = ast_ty.node { if let ast::TyPath(None, _) = ast_ty.node {
let path_res = tcx.def_map.borrow()[ast_ty.id]; let path_res = tcx.def_map.borrow()[ast_ty.id];
if let def::DefTyParam(_, _, def_id, _) = path_res.base_def { match path_res.base_def {
path_res.depth == 0 && def_id == local_def(param_id) def::DefSelfTy(node_id) =>
} else { path_res.depth == 0 && node_id == param_id,
false
def::DefTyParam(_, _, def_id, _) =>
path_res.depth == 0 && def_id == local_def(param_id),
_ =>
false,
} }
} else { } else {
false false
@ -790,9 +841,10 @@ fn convert_methods<'a,'tcx,'i,I>(ccx: &CrateCtxt<'a, 'tcx>,
rcvr_visibility: ast::Visibility) rcvr_visibility: ast::Visibility)
where I: Iterator<Item=&'i ast::Method> where I: Iterator<Item=&'i ast::Method>
{ {
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), 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 tcx = ccx.tcx;
let mut seen_methods = FnvHashSet(); let mut seen_methods = FnvHashSet();
@ -1036,6 +1088,8 @@ fn convert_item(ccx: &CrateCtxt, it: &ast::Item) {
}, },
ast::ItemTrait(_, _, _, ref trait_items) => { ast::ItemTrait(_, _, _, ref trait_items) => {
let trait_def = trait_def_of_item(ccx, it); 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); convert_trait_predicates(ccx, it);
let trait_predicates = ty::lookup_predicates(ccx.tcx, local_def(it.id)); let trait_predicates = ty::lookup_predicates(ccx.tcx, local_def(it.id));
@ -1181,22 +1235,84 @@ fn convert_struct<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
} }
} }
fn get_trait_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, /// Ensures that the super-predicates of the trait with def-id
trait_id: ast::DefId) /// trait_def_id are converted and stored. This does NOT ensure that
-> Rc<ty::TraitDef<'tcx>> { /// 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<ast::DefId>
{
let tcx = ccx.tcx; let tcx = ccx.tcx;
if trait_id.krate != ast::LOCAL_CRATE { debug!("ensure_super_predicates_step(trait_def_id={})", trait_def_id.repr(tcx));
return ty::lookup_trait_def(tcx, trait_id)
if trait_def_id.krate != ast::LOCAL_CRATE {
return Vec::new();
} }
match tcx.map.get(trait_id.node) { let superpredicates = tcx.super_predicates.borrow().get(&trait_def_id).cloned();
ast_map::NodeItem(item) => trait_def_of_item(ccx, &*item), let superpredicates = superpredicates.unwrap_or_else(|| {
_ => { let trait_node_id = trait_def_id.node;
tcx.sess.bug(&format!("get_trait_def({}): not an item",
trait_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>, fn trait_def_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
@ -1210,18 +1326,9 @@ fn trait_def_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
return def.clone(); return def.clone();
} }
let (unsafety, generics, bounds, items) = match it.node { let (unsafety, generics, items) = match it.node {
ast::ItemTrait(unsafety, ast::ItemTrait(unsafety, ref generics, _, ref items) => (unsafety, generics, items),
ref generics, _ => tcx.sess.span_bug(it.span, "trait_def_of_item invoked on non-trait"),
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 paren_sugar = ty::has_attr(tcx, def_id, "rustc_paren_sugar"); let paren_sugar = ty::has_attr(tcx, def_id, "rustc_paren_sugar");
@ -1239,15 +1346,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 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<_> = let associated_type_names: Vec<_> =
items.iter() items.iter()
.filter_map(|item| { .filter_map(|item| {
@ -1267,7 +1365,6 @@ fn trait_def_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
paren_sugar: paren_sugar, paren_sugar: paren_sugar,
unsafety: unsafety, unsafety: unsafety,
generics: ty_generics, generics: ty_generics,
bounds: bounds,
trait_ref: trait_ref, trait_ref: trait_ref,
associated_type_names: associated_type_names, associated_type_names: associated_type_names,
}); });
@ -1348,19 +1445,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::lookup_super_predicates(ccx.tcx, def_id);
let super_predicates = ty::predicates(ccx.tcx, self_param_ty, &trait_def.bounds);
// `ty_generic_predicates` below will consider the bounds on the type // `ty_generic_predicates` below will consider the bounds on the type
// parameters (including `Self`) and the explicit where-clauses, // parameters (including `Self`) and the explicit where-clauses,
// but to get the full set of predicates on a trait we need to add // but to get the full set of predicates on a trait we need to add
// in the supertrait bounds and anything declared on the // in the supertrait bounds and anything declared on the
// associated types. // associated types.
let mut base_predicates = let mut base_predicates = super_predicates;
ty::GenericPredicates {
predicates: VecPerParamSpace::new(super_predicates, vec![], vec![])
};
// Add in a predicate that `Self:Trait` (where `Trait` is the // Add in a predicate that `Self:Trait` (where `Trait` is the
// current trait). This is needed for builtin bounds. // current trait). This is needed for builtin bounds.
@ -1990,7 +2082,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 /// 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 /// a region) to ty's notion of ty param bounds, which can either be user-defined traits, or the
@ -2012,11 +2104,6 @@ fn compute_bounds<'tcx>(astconv: &AstConv<'tcx>,
&mut param_bounds.builtin_bounds, &mut param_bounds.builtin_bounds,
ast_bounds, ast_bounds,
span); span);
check_bounds_compatible(astconv,
param_ty,
&param_bounds,
span);
} }
param_bounds.trait_bounds.sort_by(|a,b| a.def_id().cmp(&b.def_id())); param_bounds.trait_bounds.sort_by(|a,b| a.def_id().cmp(&b.def_id()));
@ -2024,48 +2111,29 @@ fn compute_bounds<'tcx>(astconv: &AstConv<'tcx>,
param_bounds 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,
&param_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 /// Converts a specific TyParamBound from the AST into the
/// appropriate poly-trait-reference. /// appropriate poly-trait-reference.
fn poly_trait_ref_from_bound<'tcx>(astconv: &AstConv<'tcx>, fn predicates_from_bound<'tcx>(astconv: &AstConv<'tcx>,
param_ty: Ty<'tcx>, param_ty: Ty<'tcx>,
bound: &ast::TyParamBound, bound: &ast::TyParamBound)
projections: &mut Vec<ty::PolyProjectionPredicate<'tcx>>) -> Vec<ty::Predicate<'tcx>>
-> Option<ty::PolyTraitRef<'tcx>>
{ {
match *bound { match *bound {
ast::TraitTyParamBound(ref tr, ast::TraitBoundModifier::None) => { 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(ref lifetime) => {
ast::RegionTyParamBound(_) => { let region = ast_region_to_region(astconv.tcx(), lifetime);
None let pred = ty::Binder(ty::OutlivesPredicate(param_ty, region));
vec![ty::Predicate::TypeOutlives(pred)]
}
ast::TraitTyParamBound(_, ast::TraitBoundModifier::Maybe) => {
Vec::new()
} }
} }
} }

View File

@ -644,9 +644,9 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ConstraintContext<'a, 'tcx> {
ast::ItemTrait(..) => { ast::ItemTrait(..) => {
let trait_def = ty::lookup_trait_def(tcx, did); 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, self.add_constraints_from_predicates(&trait_def.generics,
&predicates, predicates.predicates.as_slice(),
self.covariant); self.covariant);
let trait_items = ty::trait_items(tcx, did); let trait_items = ty::trait_items(tcx, did);

View File

@ -165,14 +165,12 @@ pub fn build_external_trait(cx: &DocContext, tcx: &ty::ctxt,
_ => unreachable!() _ => unreachable!()
} }
}); });
let trait_def = ty::lookup_trait_def(tcx, did);
let predicates = ty::lookup_predicates(tcx, did); let predicates = ty::lookup_predicates(tcx, did);
let bounds = trait_def.bounds.clean(cx);
clean::Trait { clean::Trait {
unsafety: def.unsafety, unsafety: def.unsafety,
generics: (&def.generics, &predicates, subst::TypeSpace).clean(cx), generics: (&def.generics, &predicates, subst::TypeSpace).clean(cx),
items: items.collect(), items: items.collect(),
bounds: bounds, bounds: vec![], // supertraits can be found in the list of predicates
} }
} }

View File

@ -25,7 +25,7 @@ trait Trait { type Item; }
struct A<T> struct A<T>
where T : Trait, where T : Trait,
T : Add<T::Item> T : Add<T::Item>
//~^ ERROR illegal recursive type //~^ ERROR unsupported cyclic reference between types/traits detected
{ {
data: T data: T
} }

View File

@ -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 // file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT. // http://rust-lang.org/COPYRIGHT.
// //
@ -8,8 +8,11 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
trait Foo {} // Test a cycle where a type parameter on a trait has a default that
// again references the trait.
fn foo<T: Foo + Foo>() {} //~ ERROR `Foo` already appears in the list of bounds trait Foo<X = Box<Foo>> {
//~^ ERROR unsupported cyclic reference
}
fn main() {} fn main() { }

View File

@ -12,9 +12,12 @@
// a direct participant in the cycle. // a direct participant in the cycle.
trait A: B { trait A: B {
//~^ ERROR unsupported cyclic reference
} }
trait B: C { } trait B: C {
//~^ ERROR unsupported cyclic reference
}
trait C: B { } trait C: B { }
//~^ ERROR unsupported cyclic reference //~^ ERROR unsupported cyclic reference

View File

@ -8,9 +8,7 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
// error-pattern: illegal recursive type
type x = Vec<x>; type x = Vec<x>;
//~^ ERROR unsupported cyclic reference
fn main() { let b: x = Vec::new(); } fn main() { let b: x = Vec::new(); }

View File

@ -12,18 +12,17 @@
use std::any::Any; use std::any::Any;
use std::any::TypeId; use std::any::TypeId;
use std::marker::MarkerTrait;
pub trait Pt {} pub trait Pt : MarkerTrait {}
pub trait Rt {} pub trait Rt : MarkerTrait {}
trait Private<P: Pt, R: Rt> { trait Private<P: Pt, R: Rt> {
fn call(&self, p: P, r: R); fn call(&self, p: P, r: R);
} }
pub trait Public: Private< pub trait Public: Private< //~ ERROR private trait in exported type parameter bound
<Self as Public>::P, <Self as Public>::P,
//~^ ERROR illegal recursive type; insert an enum or struct in the cycle, if this is desired
<Self as Public>::R <Self as Public>::R
//~^ ERROR unsupported cyclic reference between types/traits detected
> { > {
type P; type P;
type R; type R;

View File

@ -13,7 +13,6 @@
use std::cmp::PartialEq; use std::cmp::PartialEq;
trait Hahaha: PartialEq + PartialEq { trait Hahaha: PartialEq + PartialEq {
//~^ ERROR trait `PartialEq` already appears in the list of bounds
} }
struct Lol(isize); struct Lol(isize);
@ -21,8 +20,8 @@ struct Lol(isize);
impl Hahaha for Lol { } impl Hahaha for Lol { }
impl PartialEq for Lol { impl PartialEq for Lol {
fn eq(&self, other: &Lol) -> bool { **self != **other } fn eq(&self, other: &Lol) -> bool { loop { } }
fn ne(&self, other: &Lol) -> bool { **self == **other } fn ne(&self, other: &Lol) -> bool { loop { } }
} }
fn main() { fn main() {