1
Fork 0

Auto merge of #23026 - nikomatsakis:issue-20220-supertrait, r=nikomatsakis

The main gist of this PR is commit 1077efb which removes the list of supertraits from the `TraitDef` and pulls them into a separate table, which is accessed via `lookup_super_predicates`. This is analogous to `lookup_predicates`, which gets the complete where clause. This allows us to create the `TraitDef`, which contains the list generics and so forth, without fully knowing the list of supertraits. This in turn allows the *supertrait listing* to contain references to associated types like `<Self as Foo>::Item`, which were previously impossible because conversion required having the `TraitDef` for `Foo`.

We do not yet support `Self::Item` in a supertrait listing. This doesn't work because to convert that, it attempts to expand out the full set of supertraits, which are in the process of being created. This could potentially be worked out by having the expansion of supertraits proceed in a lazy fashion, but we'd have to define shadowing rules for associated types which we don't currently have.

Along the way (in 9de9ec5) I also removed the restriction against duplicate bounds and generalized the code so that it can handle having the same supertrait multiple times with different arguments, e.g. `Foo : Bar<i32> + Bar<u32>`. This restriction was serving no particular purpose, since the same trait could be extended multiple times indirectly, and in the era of multidispatch it is actively harmful.

This is technically a [breaking-change] because it affects the definition of a super-trait. Anything in a where clause that looks like `where Self : Foo` is now considered a supertrait. Because cycles are disallowed in supertraits, that could lead to some errors. This has not been observed in any existing code.

r? @nrc
This commit is contained in:
bors 2015-03-05 17:52:21 +00:00
commit f0c74f85f3
32 changed files with 821 additions and 574 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

@ -280,7 +280,11 @@ pub struct VtableBuiltinData<N> {
/// for the object type `Foo`. /// for the object type `Foo`.
#[derive(PartialEq,Eq,Clone)] #[derive(PartialEq,Eq,Clone)]
pub struct VtableObjectData<'tcx> { pub struct VtableObjectData<'tcx> {
/// the object type `Foo`.
pub object_ty: Ty<'tcx>, 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. /// Creates predicate obligations from the generic bounds.

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

@ -1260,19 +1260,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
poly_trait_ref.repr(self.tcx())); poly_trait_ref.repr(self.tcx()));
// see whether the object trait can be upcast to the trait we are looking for // 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_refs = self.upcast(poly_trait_ref, obligation);
let upcast_trait_ref = match util::upcast(self.tcx(), poly_trait_ref, obligation_def_id) { if upcast_trait_refs.len() > 1 {
Some(r) => r, // can be upcast in many ways; need more type information
None => { return; } candidates.ambiguous = true;
}; } else if upcast_trait_refs.len() == 1 {
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");
candidates.vec.push(ObjectCandidate); candidates.vec.push(ObjectCandidate);
} }
} }
@ -1455,9 +1447,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()))
} }
} }
@ -2063,20 +2055,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
} }
}; };
let obligation_def_id = obligation.predicate.def_id(); // Upcast the object type to the obligation type. There must
let upcast_trait_ref = match util::upcast(self.tcx(), // be exactly one applicable trait-reference; if this were not
poly_trait_ref.clone(), // the case, we would have reported an ambiguity error rather
obligation_def_id) { // than successfully selecting one of the candidates.
Some(r) => r, let upcast_trait_refs = self.upcast(poly_trait_ref.clone(), obligation);
None => { assert_eq!(upcast_trait_refs.len(), 1);
self.tcx().sess.span_bug(obligation.cause.span, let upcast_trait_ref = upcast_trait_refs.into_iter().next().unwrap();
&format!("unable to upcast from {} to {}",
poly_trait_ref.repr(self.tcx()),
obligation_def_id.repr(self.tcx())));
}
};
match self.match_poly_trait_ref(obligation, upcast_trait_ref) { match self.match_poly_trait_ref(obligation, upcast_trait_ref.clone()) {
Ok(()) => { } Ok(()) => { }
Err(()) => { Err(()) => {
self.tcx().sess.span_bug(obligation.cause.span, 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, fn confirm_fn_pointer_candidate(&mut self,
@ -2501,6 +2489,32 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
obligation.cause.clone() 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<ty::PolyTraitRef<'tcx>>
{
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<i32>`, but `Foo` is
// declared as `trait Foo : Bar<u32>`.
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> { impl<'tcx> Repr<'tcx> for SelectionCandidate<'tcx> {

View file

@ -76,15 +76,10 @@ impl<'a,'tcx> PredicateSet<'a,'tcx> {
/// 'static`. /// 'static`.
pub struct Elaborator<'cx, 'tcx:'cx> { pub struct Elaborator<'cx, 'tcx:'cx> {
tcx: &'cx ty::ctxt<'tcx>, tcx: &'cx ty::ctxt<'tcx>,
stack: Vec<StackEntry<'tcx>>, stack: Vec<ty::Predicate<'tcx>>,
visited: PredicateSet<'cx,'tcx>, visited: PredicateSet<'cx,'tcx>,
} }
struct StackEntry<'tcx> {
position: uint,
predicates: Vec<ty::Predicate<'tcx>>,
}
pub fn elaborate_trait_ref<'cx, 'tcx>( pub fn elaborate_trait_ref<'cx, 'tcx>(
tcx: &'cx ty::ctxt<'tcx>, tcx: &'cx ty::ctxt<'tcx>,
trait_ref: ty::PolyTraitRef<'tcx>) trait_ref: ty::PolyTraitRef<'tcx>)
@ -111,21 +106,28 @@ pub fn elaborate_predicates<'cx, 'tcx>(
{ {
let mut visited = PredicateSet::new(tcx); let mut visited = PredicateSet::new(tcx);
predicates.retain(|pred| visited.insert(pred)); predicates.retain(|pred| visited.insert(pred));
let entry = StackEntry { position: 0, predicates: predicates }; Elaborator { tcx: tcx, stack: predicates, visited: visited }
Elaborator { tcx: tcx, stack: vec![entry], visited: visited }
} }
impl<'cx, 'tcx> Elaborator<'cx, 'tcx> { impl<'cx, 'tcx> Elaborator<'cx, 'tcx> {
pub fn filter_to_traits(self) -> Supertraits<'cx, 'tcx> { pub fn filter_to_traits(self) -> FilterToTraits<Elaborator<'cx, 'tcx>> {
Supertraits { elaborator: self } FilterToTraits::new(self)
} }
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
@ -134,8 +136,7 @@ impl<'cx, 'tcx> Elaborator<'cx, 'tcx> {
// Sized { }`. // Sized { }`.
predicates.retain(|r| self.visited.insert(r)); predicates.retain(|r| self.visited.insert(r));
self.stack.push(StackEntry { position: 0, self.stack.extend(predicates.into_iter());
predicates: predicates });
} }
ty::Predicate::Equate(..) => { ty::Predicate::Equate(..) => {
// Currently, we do not "elaborate" predicates like // Currently, we do not "elaborate" predicates like
@ -175,41 +176,16 @@ impl<'cx, 'tcx> Iterator for Elaborator<'cx, 'tcx> {
type Item = ty::Predicate<'tcx>; type Item = ty::Predicate<'tcx>;
fn next(&mut self) -> Option<ty::Predicate<'tcx>> { fn next(&mut self) -> Option<ty::Predicate<'tcx>> {
loop { // Extract next item from top-most stack frame, if any.
// Extract next item from top-most stack frame, if any. let next_predicate = match self.stack.pop() {
let next_predicate = match self.stack.last_mut() { Some(predicate) => predicate,
None => { None => {
// No more stack frames. Done. // No more stack frames. Done.
return None; 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();
}
} }
} };
self.push(&next_predicate);
return Some(next_predicate);
} }
} }
@ -217,11 +193,7 @@ impl<'cx, 'tcx> Iterator for Elaborator<'cx, 'tcx> {
// Supertrait iterator // Supertrait iterator
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
/// A filter around the `Elaborator` that just yields up supertrait references, pub type Supertraits<'cx, 'tcx> = FilterToTraits<Elaborator<'cx, 'tcx>>;
/// not other kinds of predicates.
pub struct Supertraits<'cx, 'tcx:'cx> {
elaborator: Elaborator<'cx, 'tcx>,
}
pub fn supertraits<'cx, 'tcx>(tcx: &'cx ty::ctxt<'tcx>, pub fn supertraits<'cx, 'tcx>(tcx: &'cx ty::ctxt<'tcx>,
trait_ref: ty::PolyTraitRef<'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() 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<I> {
base_iterator: I
}
impl<I> FilterToTraits<I> {
fn new(base: I) -> FilterToTraits<I> {
FilterToTraits { base_iterator: base }
}
}
impl<'tcx,I:Iterator<Item=ty::Predicate<'tcx>>> Iterator for FilterToTraits<I> {
type Item = ty::PolyTraitRef<'tcx>; type Item = ty::PolyTraitRef<'tcx>;
fn next(&mut self) -> Option<ty::PolyTraitRef<'tcx>> { fn next(&mut self) -> Option<ty::PolyTraitRef<'tcx>> {
loop { loop {
match self.elaborator.next() { match self.base_iterator.next() {
None => { None => {
return None; return None;
} }
@ -256,6 +244,7 @@ impl<'cx, 'tcx> Iterator for Supertraits<'cx, 'tcx> {
} }
} }
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
// Other // Other
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
@ -370,19 +359,15 @@ pub fn predicate_for_builtin_bound<'tcx>(
pub fn upcast<'tcx>(tcx: &ty::ctxt<'tcx>, pub fn upcast<'tcx>(tcx: &ty::ctxt<'tcx>,
source_trait_ref: ty::PolyTraitRef<'tcx>, source_trait_ref: ty::PolyTraitRef<'tcx>,
target_trait_def_id: ast::DefId) target_trait_def_id: ast::DefId)
-> Option<ty::PolyTraitRef<'tcx>> -> Vec<ty::PolyTraitRef<'tcx>>
{ {
if source_trait_ref.def_id() == target_trait_def_id { if source_trait_ref.def_id() == target_trait_def_id {
return Some(source_trait_ref); // shorcut the most common case return vec![source_trait_ref]; // shorcut the most common case
} }
for super_trait_ref in supertraits(tcx, source_trait_ref) { supertraits(tcx, source_trait_ref)
if super_trait_ref.def_id() == target_trait_def_id { .filter(|r| r.def_id() == target_trait_def_id)
return Some(super_trait_ref); .collect()
}
}
None
} }
/// Given an object of type `object_trait_ref`, returns the index of /// Given an object of type `object_trait_ref`, returns the index of

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;
/// - 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)] #[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

@ -544,7 +544,8 @@ impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::Vtable<'tcx, N>
impl<'tcx> TypeFoldable<'tcx> for traits::VtableObjectData<'tcx> { impl<'tcx> TypeFoldable<'tcx> for traits::VtableObjectData<'tcx> {
fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> traits::VtableObjectData<'tcx> { fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> traits::VtableObjectData<'tcx> {
traits::VtableObjectData { 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),
} }
} }
} }

View file

@ -65,12 +65,21 @@ pub struct Session {
impl Session { impl Session {
pub fn span_fatal(&self, sp: Span, msg: &str) -> ! { 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) self.diagnostic().span_fatal(sp, msg)
} }
pub fn span_fatal_with_code(&self, sp: Span, msg: &str, code: &str) -> ! { 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) self.diagnostic().span_fatal_with_code(sp, msg, code)
} }
pub fn fatal(&self, msg: &str) -> ! { pub fn fatal(&self, msg: &str) -> ! {
if self.opts.treat_err_as_bug {
self.bug(msg);
}
self.diagnostic().handler().fatal(msg) self.diagnostic().handler().fatal(msg)
} }
pub fn span_err(&self, sp: Span, msg: &str) { pub fn span_err(&self, sp: Span, msg: &str) {

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

@ -300,7 +300,10 @@ pub fn trans_static_method_callee<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
.position(|item| item.def_id() == method_id) .position(|item| item.def_id() == method_id)
.unwrap(); .unwrap();
let (llfn, ty) = 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) immediate_rvalue(llfn, ty)
} }
_ => { _ => {
@ -386,7 +389,10 @@ fn trans_monomorphized_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
Callee { bcx: bcx, data: Fn(llfn) } Callee { bcx: bcx, data: Fn(llfn) }
} }
traits::VtableObject(ref data) => { 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) } Callee { bcx: bcx, data: Fn(llfn) }
} }
traits::VtableBuiltin(..) | 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>( pub fn trans_object_shim<'a, 'tcx>(
ccx: &'a CrateContext<'a, 'tcx>, ccx: &'a CrateContext<'a, 'tcx>,
object_ty: Ty<'tcx>, object_ty: Ty<'tcx>,
trait_id: ast::DefId, upcast_trait_ref: ty::PolyTraitRef<'tcx>,
method_offset_in_trait: uint) method_offset_in_trait: uint)
-> (ValueRef, Ty<'tcx>) -> (ValueRef, Ty<'tcx>)
{ {
let _icx = push_ctxt("trans_object_shim"); let _icx = push_ctxt("trans_object_shim");
let tcx = ccx.tcx(); 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), object_ty.repr(tcx),
trait_id.repr(tcx), upcast_trait_ref.repr(tcx),
method_offset_in_trait); method_offset_in_trait);
let object_trait_ref = 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. // 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 upcast_trait_ref = ty::erase_late_bound_regions(tcx, &upcast_trait_ref);
let object_substs = upcast_trait_ref.substs.clone().erase_regions(); let object_substs = upcast_trait_ref.substs.clone().erase_regions();
debug!("trans_object_shim: object_substs={}", object_substs.repr(tcx)); debug!("trans_object_shim: object_substs={}", object_substs.repr(tcx));

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,33 @@ 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)
-> bool;
/// Return an (optional) substitution to convert bound type parameters that /// Return an (optional) substitution to convert bound type parameters that
/// are in scope into free ones. This function should only return Some /// are in scope into free ones. This function should only return Some
/// within a fn body. /// within a fn body.
@ -783,7 +800,7 @@ fn ast_type_binding_to_projection_predicate<'tcx>(
// We want to produce `<B as SuperTrait<int>>::T == foo`. // We want to produce `<B as SuperTrait<int>>::T == foo`.
// Simple case: X is defined in the current trait. // 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 { return Ok(ty::ProjectionPredicate {
projection_ty: ty::ProjectionTy { projection_ty: ty::ProjectionTy {
trait_ref: trait_ref, trait_ref: trait_ref,
@ -810,9 +827,11 @@ 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| 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(); .collect();
// If converting for an object type, then remove the dummy-ty from `Self` now. // 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; 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)
.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(); .collect();
if suitable_bounds.len() == 0 { 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)) (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>, fn qpath_to_ty<'tcx>(this: &AstConv<'tcx>,
rscope: &RegionScope, rscope: &RegionScope,
span: Span, span: Span,
@ -1275,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) => {
@ -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; return typ;
} }
@ -1838,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 =
@ -1923,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

@ -634,16 +634,21 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
target_trait_def_id: ast::DefId) target_trait_def_id: ast::DefId)
-> ty::PolyTraitRef<'tcx> -> ty::PolyTraitRef<'tcx>
{ {
match traits::upcast(self.tcx(), source_trait_ref.clone(), target_trait_def_id) { let upcast_trait_refs = traits::upcast(self.tcx(),
Some(super_trait_ref) => super_trait_ref, source_trait_ref.clone(),
None => { target_trait_def_id);
self.tcx().sess.span_bug(
self.span, // must be exactly one trait ref or we'd get an ambig error etc
&format!("cannot upcast `{}` to `{}`", if upcast_trait_refs.len() != 1 {
source_trait_ref.repr(self.tcx()), self.tcx().sess.span_bug(
target_trait_def_id.repr(self.tcx()))); 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<T>(&self, value: &ty::Binder<T>) -> T fn replace_late_bound_regions_with_fresh_var<T>(&self, value: &ty::Binder<T>) -> T

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)
} }
@ -1248,6 +1253,15 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
Ok(r) 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> { fn ty_infer(&self, _span: Span) -> Ty<'tcx> {
self.infcx().next_ty_var() self.infcx().next_ty_var()
} }

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,20 +381,49 @@ 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)
}) })
} }
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> { fn ty_infer(&self, span: Span) -> Ty<'tcx> {
span_err!(self.tcx().sess, span, E0121, span_err!(self.tcx().sess, span, E0121,
"the type placeholder `_` is not allowed within types on item signatures"); "the type placeholder `_` is not allowed within types on item signatures");
@ -387,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.
@ -398,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());
@ -412,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()
} }
@ -426,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 { ty::Predicate::TypeOutlives(ref data) => {
None 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()
} }
} }
@ -462,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
@ -476,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
@ -488,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()
} }
@ -505,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
@ -777,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();
@ -1023,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));
@ -1168,22 +1235,89 @@ 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 {
// 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();
} }
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>,
@ -1197,18 +1331,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");
@ -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 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| {
@ -1254,7 +1370,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,
}); });
@ -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) { fn convert_trait_predicates<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, it: &ast::Item) {
let tcx = ccx.tcx; let tcx = ccx.tcx;
let trait_def = trait_def_of_item(ccx, it); 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::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.
@ -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 /// 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
@ -1975,11 +2109,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()));
@ -1987,48 +2116,32 @@ fn compute_bounds<'tcx>(astconv: &AstConv<'tcx>,
param_bounds param_bounds
} }
fn check_bounds_compatible<'tcx>(astconv: &AstConv<'tcx>, /// Converts a specific TyParamBound from the AST into a set of
param_ty: Ty<'tcx>, /// predicates that apply to the self-type. A vector is returned
param_bounds: &ty::ParamBounds<'tcx>, /// because this can be anywhere from 0 predicates (`T:?Sized` adds no
span: Span) { /// predicates) to 1 (`T:Foo`) to many (`T:Bar<X=i32>` adds `T:Bar`
let tcx = astconv.tcx(); /// and `<T as Bar>::X == i32`).
if !param_bounds.builtin_bounds.contains(&ty::BoundSized) { fn predicates_from_bound<'tcx>(astconv: &AstConv<'tcx>,
ty::each_bound_trait_and_supertraits( param_ty: Ty<'tcx>,
tcx, bound: &ast::TyParamBound)
&param_bounds.trait_bounds, -> Vec<ty::Predicate<'tcx>>
|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<ty::PolyProjectionPredicate<'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,12 +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.
// 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 {} trait Foo<X = Box<Foo>> {
fn f<Y: ?Sized + T>() { //~^ ERROR unsupported cyclic reference
//~^ERROR incompatible bounds on `Y`, bound `T` does not allow unsized type
} }
pub 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

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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");
}
}

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,19 @@
// 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 case where an associated type is referenced from within the
// supertrait definition, and the impl makes the wrong
// associations. Issue #20220.
fn foo<T: Foo + Foo>() {} //~ ERROR `Foo` already appears in the list of bounds use std::vec::IntoIter;
fn main() {} pub trait Foo: Iterator<Item=<Self as Foo>::Key> {
type Key;
}
impl Foo for IntoIter<i32> { //~ ERROR type mismatch
type Key = u32;
}
fn main() {
}

View file

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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<T> {
fn same_as(&self, t: T) -> bool;
}
trait CompareToInts : CompareTo<i64> + CompareTo<u64> {
}
impl CompareTo<i64> for i64 {
fn same_as(&self, t: i64) -> bool { *self == t }
}
impl CompareTo<u64> 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<i32>` is not implemented
}
fn with_trait<C:CompareToInts>(c: &C) -> bool {
c.same_as(22) //~ ERROR `CompareTo<i32>` is not implemented
}
fn with_ufcs1<C:CompareToInts>(c: &C) -> bool {
CompareToInts::same_as(c, 22) //~ ERROR `CompareTo<i32>` is not implemented
}
fn with_ufcs2<C:CompareToInts>(c: &C) -> bool {
CompareTo::same_as(c, 22) //~ ERROR `CompareTo<i32>` is not implemented
}
fn main() {
assert_eq!(22_i64.same_as(22), true); //~ ERROR `CompareTo<i32>` is not implemented
}

View file

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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<Item=<Self as Foo>::Key> {
type Key;
}
impl Foo for IntoIter<i32> {
type Key = i32;
}
fn sum_foo<F:Foo<Key=i32>>(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);
}

View file

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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<T> {
fn same_as(&self, t: T) -> bool;
}
trait CompareToInts : CompareTo<i64> + CompareTo<u64> {
}
impl CompareTo<i64> for i64 {
fn same_as(&self, t: i64) -> bool { *self == t }
}
impl CompareTo<u64> 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:CompareToInts>(c: &C) -> bool {
c.same_as(22_i64) && c.same_as(22_u64)
}
fn with_ufcs1<C:CompareToInts>(c: &C) -> bool {
CompareToInts::same_as(c, 22_i64) && CompareToInts::same_as(c, 22_u64)
}
fn with_ufcs2<C:CompareToInts>(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);
}