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_ref: uint = 0x3a;
pub const tag_item_super_trait_ref: uint = 0x3b;
// discriminator value for variants
pub const tag_disr_val: uint = 0x3c;
@ -221,8 +220,6 @@ pub const tag_struct_field_id: uint = 0x8b;
pub const tag_attribute_is_sugared_doc: uint = 0x8c;
pub const tag_trait_def_bounds: uint = 0x8d;
pub const tag_items_data_region: uint = 0x8e;
pub const tag_region_param_def: uint = 0x8f;
@ -255,3 +252,5 @@ pub const tag_paren_sugar: uint = 0xa0;
pub const tag_codemap: uint = 0xa1;
pub const tag_codemap_filemap: uint = 0xa2;
pub const tag_item_super_predicates: uint = 0xa3;

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)
}
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)
-> Option<ast::Name> {
let cdata = cstore.get_crate_data(def.krate);
@ -238,6 +230,14 @@ pub fn get_predicates<'tcx>(tcx: &ty::ctxt<'tcx>, def: ast::DefId)
decoder::get_predicates(&*cdata, def.node, tcx)
}
pub fn get_super_predicates<'tcx>(tcx: &ty::ctxt<'tcx>, def: ast::DefId)
-> ty::GenericPredicates<'tcx>
{
let cstore = &tcx.sess.cstore;
let cdata = cstore.get_crate_data(def.krate);
decoder::get_super_predicates(&*cdata, def.node, tcx)
}
pub fn get_field_type<'tcx>(tcx: &ty::ctxt<'tcx>, class_id: ast::DefId,
def: ast::DefId) -> ty::TypeScheme<'tcx> {
let cstore = &tcx.sess.cstore;

View File

@ -22,9 +22,8 @@ use metadata::csearch::MethodInfo;
use metadata::csearch;
use metadata::cstore;
use metadata::tydecode::{parse_ty_data, parse_region_data, parse_def_id,
parse_type_param_def_data, parse_bounds_data,
parse_bare_fn_ty_data, parse_trait_ref_data,
parse_predicate_data};
parse_type_param_def_data, parse_bare_fn_ty_data,
parse_trait_ref_data, parse_predicate_data};
use middle::def;
use middle::lang_items;
use middle::subst;
@ -260,18 +259,6 @@ fn item_trait_ref<'tcx>(doc: rbml::Doc, tcx: &ty::ctxt<'tcx>, cdata: Cmd)
doc_trait_ref(tp, tcx, cdata)
}
fn doc_bounds<'tcx>(doc: rbml::Doc, tcx: &ty::ctxt<'tcx>, cdata: Cmd)
-> ty::ParamBounds<'tcx> {
parse_bounds_data(doc.data, cdata.cnum, doc.start, tcx,
|_, did| translate_def_id(cdata, did))
}
fn trait_def_bounds<'tcx>(doc: rbml::Doc, tcx: &ty::ctxt<'tcx>, cdata: Cmd)
-> ty::ParamBounds<'tcx> {
let d = reader::get_doc(doc, tag_trait_def_bounds);
doc_bounds(d, tcx, cdata)
}
fn enum_variant_ids(item: rbml::Doc, cdata: Cmd) -> Vec<ast::DefId> {
let mut ids: Vec<ast::DefId> = Vec::new();
let v = tag_items_data_item_variant;
@ -406,7 +393,6 @@ pub fn get_trait_def<'tcx>(cdata: Cmd,
{
let item_doc = lookup_item(item_id, cdata.data());
let generics = doc_generics(item_doc, tcx, cdata, tag_item_generics);
let bounds = trait_def_bounds(item_doc, tcx, cdata);
let unsafety = parse_unsafety(item_doc);
let associated_type_names = parse_associated_type_names(item_doc);
let paren_sugar = parse_paren_sugar(item_doc);
@ -415,7 +401,6 @@ pub fn get_trait_def<'tcx>(cdata: Cmd,
paren_sugar: paren_sugar,
unsafety: unsafety,
generics: generics,
bounds: bounds,
trait_ref: item_trait_ref(item_doc, tcx, cdata),
associated_type_names: associated_type_names,
}
@ -430,6 +415,15 @@ pub fn get_predicates<'tcx>(cdata: Cmd,
doc_predicates(item_doc, tcx, cdata, tag_item_generics)
}
pub fn get_super_predicates<'tcx>(cdata: Cmd,
item_id: ast::NodeId,
tcx: &ty::ctxt<'tcx>)
-> ty::GenericPredicates<'tcx>
{
let item_doc = lookup_item(item_id, cdata.data());
doc_predicates(item_doc, tcx, cdata, tag_item_super_predicates)
}
pub fn get_type<'tcx>(cdata: Cmd, id: ast::NodeId, tcx: &ty::ctxt<'tcx>)
-> ty::TypeScheme<'tcx>
{
@ -971,24 +965,6 @@ pub fn get_provided_trait_methods<'tcx>(intr: Rc<IdentInterner>,
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,
node_id: ast::NodeId) -> Option<ast::Name> {
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);
}
fn encode_bounds<'a, 'tcx>(rbml_w: &mut Encoder,
ecx: &EncodeContext<'a, 'tcx>,
bounds: &ty::ParamBounds<'tcx>,
tag: uint) {
rbml_w.start_tag(tag);
let ty_str_ctxt = &tyencode::ctxt { diag: ecx.diag,
ds: def_to_string,
tcx: ecx.tcx,
abbrevs: &ecx.type_abbrevs };
tyencode::enc_bounds(rbml_w, ty_str_ctxt, bounds);
rbml_w.end_tag();
}
fn encode_type<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
rbml_w: &mut Encoder,
typ: Ty<'tcx>) {
@ -728,6 +713,7 @@ fn encode_generics<'a, 'tcx>(rbml_w: &mut Encoder,
tcx: ecx.tcx,
abbrevs: &ecx.type_abbrevs
};
for param in generics.types.iter() {
rbml_w.start_tag(tag_type_param_def);
tyencode::enc_type_param_def(rbml_w, ty_str_ctxt, param);
@ -758,6 +744,22 @@ fn encode_generics<'a, 'tcx>(rbml_w: &mut Encoder,
rbml_w.end_tag();
}
encode_predicates_in_current_doc(rbml_w, ecx, predicates);
rbml_w.end_tag();
}
fn encode_predicates_in_current_doc<'a,'tcx>(rbml_w: &mut Encoder,
ecx: &EncodeContext<'a,'tcx>,
predicates: &ty::GenericPredicates<'tcx>)
{
let ty_str_ctxt = &tyencode::ctxt {
diag: ecx.diag,
ds: def_to_string,
tcx: ecx.tcx,
abbrevs: &ecx.type_abbrevs
};
for (space, _, predicate) in predicates.predicates.iter_enumerated() {
rbml_w.start_tag(tag_predicate);
@ -769,7 +771,15 @@ fn encode_generics<'a, 'tcx>(rbml_w: &mut Encoder,
rbml_w.end_tag();
}
}
fn encode_predicates<'a,'tcx>(rbml_w: &mut Encoder,
ecx: &EncodeContext<'a,'tcx>,
predicates: &ty::GenericPredicates<'tcx>,
tag: uint)
{
rbml_w.start_tag(tag);
encode_predicates_in_current_doc(rbml_w, ecx, predicates);
rbml_w.end_tag();
}
@ -1280,6 +1290,8 @@ fn encode_info_for_item(ecx: &EncodeContext,
encode_paren_sugar(rbml_w, trait_def.paren_sugar);
encode_associated_type_names(rbml_w, &trait_def.associated_type_names);
encode_generics(rbml_w, ecx, &trait_def.generics, &trait_predicates, tag_item_generics);
encode_predicates(rbml_w, ecx, &ty::lookup_super_predicates(tcx, def_id),
tag_item_super_predicates);
encode_trait_ref(rbml_w, ecx, &*trait_def.trait_ref, tag_item_trait_ref);
encode_name(rbml_w, item.ident.name);
encode_attributes(rbml_w, &item.attrs);
@ -1304,8 +1316,6 @@ fn encode_info_for_item(ecx: &EncodeContext,
}
encode_path(rbml_w, path.clone());
encode_bounds(rbml_w, ecx, &trait_def.bounds, tag_trait_def_bounds);
// Encode the implementations of this trait.
encode_extension_implementations(ecx, rbml_w, def_id);

View File

@ -280,7 +280,11 @@ pub struct VtableBuiltinData<N> {
/// for the object type `Foo`.
#[derive(PartialEq,Eq,Clone)]
pub struct VtableObjectData<'tcx> {
/// the object type `Foo`.
pub object_ty: Ty<'tcx>,
/// `Foo` upcast to the obligation trait. This will be some supertrait of `Foo`.
pub upcast_trait_ref: ty::PolyTraitRef<'tcx>,
}
/// Creates predicate obligations from the generic bounds.

View File

@ -22,7 +22,7 @@ use super::elaborate_predicates;
use middle::subst::{self, SelfSpace, TypeSpace};
use middle::traits;
use middle::ty::{self, Ty};
use middle::ty::{self, ToPolyTraitRef, Ty};
use std::rc::Rc;
use syntax::ast;
use util::ppaux::Repr;
@ -128,9 +128,12 @@ fn supertraits_reference_self<'tcx>(tcx: &ty::ctxt<'tcx>,
{
let trait_def = ty::lookup_trait_def(tcx, trait_def_id);
let trait_ref = trait_def.trait_ref.clone();
let predicates = ty::predicates_for_trait_ref(tcx, &ty::Binder(trait_ref));
let trait_ref = trait_ref.to_poly_trait_ref();
let predicates = ty::lookup_super_predicates(tcx, trait_def_id);
predicates
.predicates
.into_iter()
.map(|predicate| predicate.subst_supertrait(tcx, &trait_ref))
.any(|predicate| {
match predicate {
ty::Predicate::Trait(ref data) => {

View File

@ -1260,19 +1260,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
poly_trait_ref.repr(self.tcx()));
// see whether the object trait can be upcast to the trait we are looking for
let obligation_def_id = obligation.predicate.def_id();
let upcast_trait_ref = match util::upcast(self.tcx(), poly_trait_ref, obligation_def_id) {
Some(r) => r,
None => { return; }
};
debug!("assemble_candidates_from_object_ty: upcast_trait_ref={}",
upcast_trait_ref.repr(self.tcx()));
// check whether the upcast version of the trait-ref matches what we are looking for
if let Ok(()) = self.infcx.probe(|_| self.match_poly_trait_ref(obligation,
upcast_trait_ref.clone())) {
debug!("assemble_candidates_from_object_ty: matched, pushing candidate");
let upcast_trait_refs = self.upcast(poly_trait_ref, obligation);
if upcast_trait_refs.len() > 1 {
// can be upcast in many ways; need more type information
candidates.ambiguous = true;
} else if upcast_trait_refs.len() == 1 {
candidates.vec.push(ObjectCandidate);
}
}
@ -1455,9 +1447,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let principal =
data.principal_trait_ref_with_self_ty(self.tcx(),
self.tcx().types.err);
let desired_def_id = obligation.predicate.def_id();
for tr in util::supertraits(self.tcx(), principal) {
let td = ty::lookup_trait_def(self.tcx(), tr.def_id());
if td.bounds.builtin_bounds.contains(&bound) {
if tr.def_id() == desired_def_id {
return Ok(If(Vec::new()))
}
}
@ -2063,20 +2055,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}
};
let obligation_def_id = obligation.predicate.def_id();
let upcast_trait_ref = match util::upcast(self.tcx(),
poly_trait_ref.clone(),
obligation_def_id) {
Some(r) => r,
None => {
self.tcx().sess.span_bug(obligation.cause.span,
&format!("unable to upcast from {} to {}",
poly_trait_ref.repr(self.tcx()),
obligation_def_id.repr(self.tcx())));
}
};
// Upcast the object type to the obligation type. There must
// be exactly one applicable trait-reference; if this were not
// the case, we would have reported an ambiguity error rather
// than successfully selecting one of the candidates.
let upcast_trait_refs = self.upcast(poly_trait_ref.clone(), obligation);
assert_eq!(upcast_trait_refs.len(), 1);
let upcast_trait_ref = upcast_trait_refs.into_iter().next().unwrap();
match self.match_poly_trait_ref(obligation, upcast_trait_ref) {
match self.match_poly_trait_ref(obligation, upcast_trait_ref.clone()) {
Ok(()) => { }
Err(()) => {
self.tcx().sess.span_bug(obligation.cause.span,
@ -2084,7 +2071,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}
}
VtableObjectData { object_ty: self_ty }
VtableObjectData { object_ty: self_ty,
upcast_trait_ref: upcast_trait_ref }
}
fn confirm_fn_pointer_candidate(&mut self,
@ -2501,6 +2489,32 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
obligation.cause.clone()
}
}
/// Upcasts an object trait-reference into those that match the obligation.
fn upcast(&mut self, obj_trait_ref: ty::PolyTraitRef<'tcx>, obligation: &TraitObligation<'tcx>)
-> Vec<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> {

View File

@ -76,15 +76,10 @@ impl<'a,'tcx> PredicateSet<'a,'tcx> {
/// 'static`.
pub struct Elaborator<'cx, 'tcx:'cx> {
tcx: &'cx ty::ctxt<'tcx>,
stack: Vec<StackEntry<'tcx>>,
stack: Vec<ty::Predicate<'tcx>>,
visited: PredicateSet<'cx,'tcx>,
}
struct StackEntry<'tcx> {
position: uint,
predicates: Vec<ty::Predicate<'tcx>>,
}
pub fn elaborate_trait_ref<'cx, 'tcx>(
tcx: &'cx ty::ctxt<'tcx>,
trait_ref: ty::PolyTraitRef<'tcx>)
@ -111,21 +106,28 @@ pub fn elaborate_predicates<'cx, 'tcx>(
{
let mut visited = PredicateSet::new(tcx);
predicates.retain(|pred| visited.insert(pred));
let entry = StackEntry { position: 0, predicates: predicates };
Elaborator { tcx: tcx, stack: vec![entry], visited: visited }
Elaborator { tcx: tcx, stack: predicates, visited: visited }
}
impl<'cx, 'tcx> Elaborator<'cx, 'tcx> {
pub fn filter_to_traits(self) -> Supertraits<'cx, 'tcx> {
Supertraits { elaborator: self }
pub fn filter_to_traits(self) -> FilterToTraits<Elaborator<'cx, 'tcx>> {
FilterToTraits::new(self)
}
fn push(&mut self, predicate: &ty::Predicate<'tcx>) {
match *predicate {
ty::Predicate::Trait(ref data) => {
let mut predicates =
ty::predicates_for_trait_ref(self.tcx,
&data.to_poly_trait_ref());
// Predicates declared on the trait.
let predicates = ty::lookup_super_predicates(self.tcx, data.def_id());
let mut predicates: Vec<_> =
predicates.predicates
.iter()
.map(|p| p.subst_supertrait(self.tcx, &data.to_poly_trait_ref()))
.collect();
debug!("super_predicates: data={} predicates={}",
data.repr(self.tcx), predicates.repr(self.tcx));
// Only keep those bounds that we haven't already
// seen. This is necessary to prevent infinite
@ -134,8 +136,7 @@ impl<'cx, 'tcx> Elaborator<'cx, 'tcx> {
// Sized { }`.
predicates.retain(|r| self.visited.insert(r));
self.stack.push(StackEntry { position: 0,
predicates: predicates });
self.stack.extend(predicates.into_iter());
}
ty::Predicate::Equate(..) => {
// Currently, we do not "elaborate" predicates like
@ -175,41 +176,16 @@ impl<'cx, 'tcx> Iterator for Elaborator<'cx, 'tcx> {
type Item = ty::Predicate<'tcx>;
fn next(&mut self) -> Option<ty::Predicate<'tcx>> {
loop {
// Extract next item from top-most stack frame, if any.
let next_predicate = match self.stack.last_mut() {
None => {
// No more stack frames. Done.
return None;
}
Some(entry) => {
let p = entry.position;
if p < entry.predicates.len() {
// Still more predicates left in the top stack frame.
entry.position += 1;
let next_predicate =
entry.predicates[p].clone();
Some(next_predicate)
} else {
None
}
}
};
match next_predicate {
Some(next_predicate) => {
self.push(&next_predicate);
return Some(next_predicate);
}
None => {
// Top stack frame is exhausted, pop it.
self.stack.pop();
}
// Extract next item from top-most stack frame, if any.
let next_predicate = match self.stack.pop() {
Some(predicate) => predicate,
None => {
// No more stack frames. Done.
return None;
}
}
};
self.push(&next_predicate);
return Some(next_predicate);
}
}
@ -217,11 +193,7 @@ impl<'cx, 'tcx> Iterator for Elaborator<'cx, 'tcx> {
// Supertrait iterator
///////////////////////////////////////////////////////////////////////////
/// A filter around the `Elaborator` that just yields up supertrait references,
/// not other kinds of predicates.
pub struct Supertraits<'cx, 'tcx:'cx> {
elaborator: Elaborator<'cx, 'tcx>,
}
pub type Supertraits<'cx, 'tcx> = FilterToTraits<Elaborator<'cx, 'tcx>>;
pub fn supertraits<'cx, 'tcx>(tcx: &'cx ty::ctxt<'tcx>,
trait_ref: ty::PolyTraitRef<'tcx>)
@ -237,12 +209,28 @@ pub fn transitive_bounds<'cx, 'tcx>(tcx: &'cx ty::ctxt<'tcx>,
elaborate_trait_refs(tcx, bounds).filter_to_traits()
}
impl<'cx, 'tcx> Iterator for Supertraits<'cx, 'tcx> {
///////////////////////////////////////////////////////////////////////////
// Other
///////////////////////////////////////////////////////////////////////////
/// A filter around an iterator of predicates that makes it yield up
/// just trait references.
pub struct FilterToTraits<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>;
fn next(&mut self) -> Option<ty::PolyTraitRef<'tcx>> {
loop {
match self.elaborator.next() {
match self.base_iterator.next() {
None => {
return None;
}
@ -256,6 +244,7 @@ impl<'cx, 'tcx> Iterator for Supertraits<'cx, 'tcx> {
}
}
///////////////////////////////////////////////////////////////////////////
// Other
///////////////////////////////////////////////////////////////////////////
@ -370,19 +359,15 @@ pub fn predicate_for_builtin_bound<'tcx>(
pub fn upcast<'tcx>(tcx: &ty::ctxt<'tcx>,
source_trait_ref: ty::PolyTraitRef<'tcx>,
target_trait_def_id: ast::DefId)
-> Option<ty::PolyTraitRef<'tcx>>
-> Vec<ty::PolyTraitRef<'tcx>>
{
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) {
if super_trait_ref.def_id() == target_trait_def_id {
return Some(super_trait_ref);
}
}
None
supertraits(tcx, source_trait_ref)
.filter(|r| r.def_id() == target_trait_def_id)
.collect()
}
/// Given an object of type `object_trait_ref`, returns the index of

View File

@ -17,7 +17,6 @@ pub use self::InferTy::*;
pub use self::InferRegion::*;
pub use self::ImplOrTraitItemId::*;
pub use self::ClosureKind::*;
pub use self::ast_ty_to_ty_cache_entry::*;
pub use self::Variance::*;
pub use self::AutoAdjustment::*;
pub use self::Representability::*;
@ -266,12 +265,6 @@ pub struct creader_cache_key {
pub len: uint
}
#[derive(Copy)]
pub enum ast_ty_to_ty_cache_entry<'tcx> {
atttce_unresolved, /* not resolved yet */
atttce_resolved(Ty<'tcx>) /* resolved to a type, irrespective of region */
}
#[derive(Clone, PartialEq, RustcDecodable, RustcEncodable)]
pub struct ItemVariances {
pub types: VecPerParamSpace<Variance>,
@ -716,6 +709,14 @@ pub struct ctxt<'tcx> {
/// associated predicates.
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
/// Box<Trait>`) to the trait reference.
pub object_cast_map: ObjectCastMap<'tcx>,
@ -727,7 +728,7 @@ pub struct ctxt<'tcx> {
pub rcache: RefCell<FnvHashMap<creader_cache_key, Ty<'tcx>>>,
pub short_names_cache: RefCell<FnvHashMap<Ty<'tcx>, String>>,
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 ty_param_defs: RefCell<NodeMap<TypeParameterDef<'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`
/// from the tcx, use the `NodeId` from the `ast::Ty` and look it up in
/// the `ast_ty_to_ty_cache`. This is probably true for `ty_struct` as
/// well.`
/// well.
ty_enum(DefId, &'tcx Substs<'tcx>),
ty_uniq(Ty<'tcx>),
ty_str,
@ -1495,6 +1496,27 @@ impl<'tcx> PolyTraitRef<'tcx> {
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub struct Binder<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)]
pub enum IntVarValue {
IntType(ast::IntTy),
@ -1817,6 +1839,16 @@ impl<'tcx> GenericPredicates<'tcx> {
predicates: self.predicates.subst(tcx, substs),
}
}
pub fn instantiate_supertrait(&self,
tcx: &ty::ctxt<'tcx>,
poly_trait_ref: &ty::PolyTraitRef<'tcx>)
-> InstantiatedPredicates<'tcx>
{
InstantiatedPredicates {
predicates: self.predicates.map(|pred| pred.subst_supertrait(tcx, poly_trait_ref))
}
}
}
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
@ -1840,6 +1872,93 @@ pub enum Predicate<'tcx> {
Projection(PolyProjectionPredicate<'tcx>),
}
impl<'tcx> Predicate<'tcx> {
/// Performs a substituion suitable for going from a
/// poly-trait-ref to supertraits that must hold if that
/// poly-trait-ref holds. This is slightly different from a normal
/// substitution in terms of what happens with bound regions. See
/// lengthy comment below for details.
pub fn subst_supertrait(&self,
tcx: &ty::ctxt<'tcx>,
trait_ref: &ty::PolyTraitRef<'tcx>)
-> ty::Predicate<'tcx>
{
// The interaction between HRTB and supertraits is not entirely
// obvious. Let me walk you (and myself) through an example.
//
// Let's start with an easy case. Consider two traits:
//
// trait Foo<'a> : Bar<'a,'a> { }
// trait Bar<'b,'c> { }
//
// Now, if we have a trait reference `for<'x> T : Foo<'x>`, then
// we can deduce that `for<'x> T : Bar<'x,'x>`. Basically, if we
// knew that `Foo<'x>` (for any 'x) then we also know that
// `Bar<'x,'x>` (for any 'x). This more-or-less falls out from
// normal substitution.
//
// In terms of why this is sound, the idea is that whenever there
// is an impl of `T:Foo<'a>`, it must show that `T:Bar<'a,'a>`
// holds. So if there is an impl of `T:Foo<'a>` that applies to
// all `'a`, then we must know that `T:Bar<'a,'a>` holds for all
// `'a`.
//
// Another example to be careful of is this:
//
// trait Foo1<'a> : for<'b> Bar1<'a,'b> { }
// trait Bar1<'b,'c> { }
//
// Here, if we have `for<'x> T : Foo1<'x>`, then what do we know?
// The answer is that we know `for<'x,'b> T : Bar1<'x,'b>`. The
// reason is similar to the previous example: any impl of
// `T:Foo1<'x>` must show that `for<'b> T : Bar1<'x, 'b>`. So
// basically we would want to collapse the bound lifetimes from
// the input (`trait_ref`) and the supertraits.
//
// To achieve this in practice is fairly straightforward. Let's
// consider the more complicated scenario:
//
// - We start out with `for<'x> T : Foo1<'x>`. In this case, `'x`
// has a De Bruijn index of 1. We want to produce `for<'x,'b> T : Bar1<'x,'b>`,
// where both `'x` and `'b` would have a DB index of 1.
// The substitution from the input trait-ref is therefore going to be
// `'a => 'x` (where `'x` has a DB index of 1).
// - The super-trait-ref is `for<'b> Bar1<'a,'b>`, where `'a` is an
// early-bound parameter and `'b' is a late-bound parameter with a
// DB index of 1.
// - If we replace `'a` with `'x` from the input, it too will have
// a DB index of 1, and thus we'll have `for<'x,'b> Bar1<'x,'b>`
// just as we wanted.
//
// There is only one catch. If we just apply the substitution `'a
// => 'x` to `for<'b> Bar1<'a,'b>`, the substitution code will
// adjust the DB index because we substituting into a binder (it
// tries to be so smart...) resulting in `for<'x> for<'b>
// Bar1<'x,'b>` (we have no syntax for this, so use your
// imagination). Basically the 'x will have DB index of 2 and 'b
// will have DB index of 1. Not quite what we want. So we apply
// the substitution to the *contents* of the trait reference,
// rather than the trait reference itself (put another way, the
// substitution code expects equal binding levels in the values
// from the substitution and the value being substituted into, and
// this trick achieves that).
let substs = &trait_ref.0.substs;
match *self {
Predicate::Trait(ty::Binder(ref data)) =>
Predicate::Trait(ty::Binder(data.subst(tcx, substs))),
Predicate::Equate(ty::Binder(ref data)) =>
Predicate::Equate(ty::Binder(data.subst(tcx, substs))),
Predicate::RegionOutlives(ty::Binder(ref data)) =>
Predicate::RegionOutlives(ty::Binder(data.subst(tcx, substs))),
Predicate::TypeOutlives(ty::Binder(ref data)) =>
Predicate::TypeOutlives(ty::Binder(data.subst(tcx, substs))),
Predicate::Projection(ty::Binder(ref data)) =>
Predicate::Projection(ty::Binder(data.subst(tcx, substs))),
}
}
}
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub struct TraitPredicate<'tcx> {
pub trait_ref: Rc<TraitRef<'tcx>>
@ -2324,9 +2443,6 @@ pub struct TraitDef<'tcx> {
/// implements the trait.
pub generics: Generics<'tcx>,
/// The "supertrait" bounds.
pub bounds: ParamBounds<'tcx>,
pub trait_ref: Rc<ty::TraitRef<'tcx>>,
/// A list of the associated types defined in this trait. Useful
@ -2451,6 +2567,7 @@ pub fn mk_ctxt<'tcx>(s: Session,
impl_trait_refs: RefCell::new(NodeMap()),
trait_defs: RefCell::new(DefIdMap()),
predicates: RefCell::new(DefIdMap()),
super_predicates: RefCell::new(DefIdMap()),
object_cast_map: RefCell::new(NodeMap()),
map: map,
intrinsic_defs: RefCell::new(DefIdMap()),
@ -5432,7 +5549,7 @@ pub fn lookup_trait_def<'tcx>(cx: &ctxt<'tcx>, did: ast::DefId)
})
}
/// Given the did of a trait, returns its full set of predicates.
/// Given the did of an item, returns its full set of predicates.
pub fn lookup_predicates<'tcx>(cx: &ctxt<'tcx>, did: ast::DefId)
-> GenericPredicates<'tcx>
{
@ -5442,117 +5559,14 @@ pub fn lookup_predicates<'tcx>(cx: &ctxt<'tcx>, did: ast::DefId)
})
}
/// Given a reference to a trait, returns the "superbounds" declared
/// on the trait, with appropriate substitutions applied. Basically,
/// this applies a filter to the where clauses on the trait, returning
/// those that have the form:
///
/// Self : SuperTrait<...>
/// Self : 'region
pub fn predicates_for_trait_ref<'tcx>(tcx: &ctxt<'tcx>,
trait_ref: &PolyTraitRef<'tcx>)
-> Vec<ty::Predicate<'tcx>>
/// Given the did of a trait, returns its superpredicates.
pub fn lookup_super_predicates<'tcx>(cx: &ctxt<'tcx>, did: ast::DefId)
-> GenericPredicates<'tcx>
{
let trait_def = lookup_trait_def(tcx, trait_ref.def_id());
debug!("bounds_for_trait_ref(trait_def={:?}, trait_ref={:?})",
trait_def.repr(tcx), trait_ref.repr(tcx));
// The interaction between HRTB and supertraits is not entirely
// obvious. Let me walk you (and myself) through an example.
//
// Let's start with an easy case. Consider two traits:
//
// trait Foo<'a> : Bar<'a,'a> { }
// trait Bar<'b,'c> { }
//
// Now, if we have a trait reference `for<'x> T : Foo<'x>`, then
// we can deduce that `for<'x> T : Bar<'x,'x>`. Basically, if we
// knew that `Foo<'x>` (for any 'x) then we also know that
// `Bar<'x,'x>` (for any 'x). This more-or-less falls out from
// normal substitution.
//
// In terms of why this is sound, the idea is that whenever there
// is an impl of `T:Foo<'a>`, it must show that `T:Bar<'a,'a>`
// holds. So if there is an impl of `T:Foo<'a>` that applies to
// all `'a`, then we must know that `T:Bar<'a,'a>` holds for all
// `'a`.
//
// Another example to be careful of is this:
//
// trait Foo1<'a> : for<'b> Bar1<'a,'b> { }
// trait Bar1<'b,'c> { }
//
// Here, if we have `for<'x> T : Foo1<'x>`, then what do we know?
// The answer is that we know `for<'x,'b> T : Bar1<'x,'b>`. The
// reason is similar to the previous example: any impl of
// `T:Foo1<'x>` must show that `for<'b> T : Bar1<'x, 'b>`. So
// basically we would want to collapse the bound lifetimes from
// the input (`trait_ref`) and the supertraits.
//
// To achieve this in practice is fairly straightforward. Let's
// consider the more complicated scenario:
//
// - We start out with `for<'x> T : Foo1<'x>`. In this case, `'x`
// has a De Bruijn index of 1. We want to produce `for<'x,'b> T : Bar1<'x,'b>`,
// where both `'x` and `'b` would have a DB index of 1.
// The substitution from the input trait-ref is therefore going to be
// `'a => 'x` (where `'x` has a DB index of 1).
// - The super-trait-ref is `for<'b> Bar1<'a,'b>`, where `'a` is an
// early-bound parameter and `'b' is a late-bound parameter with a
// DB index of 1.
// - If we replace `'a` with `'x` from the input, it too will have
// a DB index of 1, and thus we'll have `for<'x,'b> Bar1<'x,'b>`
// just as we wanted.
//
// There is only one catch. If we just apply the substitution `'a
// => 'x` to `for<'b> Bar1<'a,'b>`, the substitution code will
// adjust the DB index because we substituting into a binder (it
// tries to be so smart...) resulting in `for<'x> for<'b>
// Bar1<'x,'b>` (we have no syntax for this, so use your
// imagination). Basically the 'x will have DB index of 2 and 'b
// will have DB index of 1. Not quite what we want. So we apply
// the substitution to the *contents* of the trait reference,
// rather than the trait reference itself (put another way, the
// substitution code expects equal binding levels in the values
// from the substitution and the value being substituted into, and
// this trick achieves that).
// Carefully avoid the binder introduced by each trait-ref by
// substituting over the substs, not the trait-refs themselves,
// thus achieving the "collapse" described in the big comment
// above.
let trait_bounds: Vec<_> =
trait_def.bounds.trait_bounds
.iter()
.map(|poly_trait_ref| ty::Binder(poly_trait_ref.0.subst(tcx, trait_ref.substs())))
.collect();
let projection_bounds: Vec<_> =
trait_def.bounds.projection_bounds
.iter()
.map(|poly_proj| ty::Binder(poly_proj.0.subst(tcx, trait_ref.substs())))
.collect();
debug!("bounds_for_trait_ref: trait_bounds={} projection_bounds={}",
trait_bounds.repr(tcx),
projection_bounds.repr(tcx));
// The region bounds and builtin bounds do not currently introduce
// binders so we can just substitute in a straightforward way here.
let region_bounds =
trait_def.bounds.region_bounds.subst(tcx, trait_ref.substs());
let builtin_bounds =
trait_def.bounds.builtin_bounds.subst(tcx, trait_ref.substs());
let bounds = ty::ParamBounds {
trait_bounds: trait_bounds,
region_bounds: region_bounds,
builtin_bounds: builtin_bounds,
projection_bounds: projection_bounds,
};
predicates(tcx, trait_ref.self_ty(), &bounds)
memoized(&cx.super_predicates, did, |did: DefId| {
assert!(did.krate != ast::LOCAL_CRATE);
csearch::get_super_predicates(cx, did)
})
}
pub fn predicates<'tcx>(

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> {
fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> traits::VtableObjectData<'tcx> {
traits::VtableObjectData {
object_ty: self.object_ty.fold_with(folder)
object_ty: self.object_ty.fold_with(folder),
upcast_trait_ref: self.upcast_trait_ref.fold_with(folder),
}
}
}

View File

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

View File

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

View File

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

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)
.unwrap();
let (llfn, ty) =
trans_object_shim(ccx, data.object_ty, trait_id, method_offset_in_trait);
trans_object_shim(ccx,
data.object_ty,
data.upcast_trait_ref.clone(),
method_offset_in_trait);
immediate_rvalue(llfn, ty)
}
_ => {
@ -386,7 +389,10 @@ fn trans_monomorphized_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
Callee { bcx: bcx, data: Fn(llfn) }
}
traits::VtableObject(ref data) => {
let (llfn, _) = trans_object_shim(bcx.ccx(), data.object_ty, trait_id, n_method);
let (llfn, _) = trans_object_shim(bcx.ccx(),
data.object_ty,
data.upcast_trait_ref.clone(),
n_method);
Callee { bcx: bcx, data: Fn(llfn) }
}
traits::VtableBuiltin(..) |
@ -551,16 +557,17 @@ pub fn trans_trait_callee_from_llval<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
pub fn trans_object_shim<'a, 'tcx>(
ccx: &'a CrateContext<'a, 'tcx>,
object_ty: Ty<'tcx>,
trait_id: ast::DefId,
upcast_trait_ref: ty::PolyTraitRef<'tcx>,
method_offset_in_trait: uint)
-> (ValueRef, Ty<'tcx>)
{
let _icx = push_ctxt("trans_object_shim");
let tcx = ccx.tcx();
let trait_id = upcast_trait_ref.def_id();
debug!("trans_object_shim(object_ty={}, trait_id={}, method_offset_in_trait={})",
debug!("trans_object_shim(object_ty={}, upcast_trait_ref={}, method_offset_in_trait={})",
object_ty.repr(tcx),
trait_id.repr(tcx),
upcast_trait_ref.repr(tcx),
method_offset_in_trait);
let object_trait_ref =
@ -575,7 +582,6 @@ pub fn trans_object_shim<'a, 'tcx>(
};
// Upcast to the trait in question and extract out the substitutions.
let upcast_trait_ref = traits::upcast(ccx.tcx(), object_trait_ref.clone(), trait_id).unwrap();
let upcast_trait_ref = ty::erase_late_bound_regions(tcx, &upcast_trait_ref);
let object_substs = upcast_trait_ref.substs.clone().erase_regions();
debug!("trans_object_shim: object_substs={}", object_substs.repr(tcx));

View File

@ -59,7 +59,6 @@ use middle::ty::{self, RegionEscape, ToPolyTraitRef, Ty};
use rscope::{self, UnelidableRscope, RegionScope, ElidableRscope,
ObjectLifetimeDefaultRscope, ShiftedRscope, BindingRscope};
use util::common::{ErrorReported, FN_OUTPUT_NAME};
use util::nodemap::DefIdMap;
use util::ppaux::{self, Repr, UserString};
use std::iter::{repeat, AdditiveIterator};
@ -73,15 +72,33 @@ use syntax::print::pprust;
pub trait AstConv<'tcx> {
fn tcx<'a>(&'a self) -> &'a ty::ctxt<'tcx>;
/// Identify the type scheme for an item with a type, like a type
/// alias, fn, or struct. This allows you to figure out the set of
/// type parameters defined on the item.
fn get_item_type_scheme(&self, span: Span, id: ast::DefId)
-> Result<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)
-> 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)
-> 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
/// are in scope into free ones. This function should only return Some
/// within a fn body.
@ -783,7 +800,7 @@ fn ast_type_binding_to_projection_predicate<'tcx>(
// We want to produce `<B as SuperTrait<int>>::T == foo`.
// Simple case: X is defined in the current trait.
if trait_defines_associated_type_named(this, trait_ref.def_id, binding.item_name) {
if this.trait_defines_associated_type_named(trait_ref.def_id, binding.item_name) {
return Ok(ty::ProjectionPredicate {
projection_ty: ty::ProjectionTy {
trait_ref: trait_ref,
@ -810,9 +827,11 @@ fn ast_type_binding_to_projection_predicate<'tcx>(
tcx.mk_substs(dummy_substs)));
}
try!(this.ensure_super_predicates(binding.span, trait_ref.def_id));
let mut candidates: Vec<ty::PolyTraitRef> =
traits::supertraits(tcx, trait_ref.to_poly_trait_ref())
.filter(|r| trait_defines_associated_type_named(this, r.def_id(), binding.item_name))
.filter(|r| this.trait_defines_associated_type_named(r.def_id(), binding.item_name))
.collect();
// If converting for an object type, then remove the dummy-ty from `Self` now.
@ -1029,14 +1048,19 @@ fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>,
let ty_param_name = tcx.ty_param_defs.borrow()[ty_param_node_id].name;
// FIXME(#20300) -- search where clauses, not bounds
let bounds =
this.get_type_parameter_bounds(span, ty_param_node_id)
.unwrap_or(Vec::new());
let bounds = match this.get_type_parameter_bounds(span, ty_param_node_id) {
Ok(v) => v,
Err(ErrorReported) => { return (tcx.types.err, ty_path_def); }
};
// ensure the super predicates and stop if we encountered an error
if bounds.iter().any(|b| this.ensure_super_predicates(span, b.def_id()).is_err()) {
return (this.tcx().types.err, ty_path_def);
}
let mut suitable_bounds: Vec<_> =
traits::transitive_bounds(tcx, &bounds)
.filter(|b| trait_defines_associated_type_named(this, b.def_id(), assoc_name))
.filter(|b| this.trait_defines_associated_type_named(b.def_id(), assoc_name))
.collect();
if suitable_bounds.len() == 0 {
@ -1090,16 +1114,6 @@ fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>,
(ty, def::DefAssociatedTy(trait_did, item_did))
}
fn trait_defines_associated_type_named(this: &AstConv,
trait_def_id: ast::DefId,
assoc_name: ast::Name)
-> bool
{
let tcx = this.tcx();
let trait_def = ty::lookup_trait_def(tcx, trait_def_id);
trait_def.associated_type_names.contains(&assoc_name)
}
fn qpath_to_ty<'tcx>(this: &AstConv<'tcx>,
rscope: &RegionScope,
span: Span,
@ -1275,20 +1289,9 @@ pub fn ast_ty_to_ty<'tcx>(this: &AstConv<'tcx>,
let tcx = this.tcx();
let mut ast_ty_to_ty_cache = tcx.ast_ty_to_ty_cache.borrow_mut();
match ast_ty_to_ty_cache.get(&ast_ty.id) {
Some(&ty::atttce_resolved(ty)) => return ty,
Some(&ty::atttce_unresolved) => {
span_err!(tcx.sess, ast_ty.span, E0246,
"illegal recursive type; insert an enum \
or struct in the cycle, if this is \
desired");
return this.tcx().types.err;
}
None => { /* go on */ }
if let Some(&ty) = tcx.ast_ty_to_ty_cache.borrow().get(&ast_ty.id) {
return ty;
}
ast_ty_to_ty_cache.insert(ast_ty.id, ty::atttce_unresolved);
drop(ast_ty_to_ty_cache);
let typ = match ast_ty.node {
ast::TyVec(ref ty) => {
@ -1421,7 +1424,7 @@ pub fn ast_ty_to_ty<'tcx>(this: &AstConv<'tcx>,
}
};
tcx.ast_ty_to_ty_cache.borrow_mut().insert(ast_ty.id, ty::atttce_resolved(typ));
tcx.ast_ty_to_ty_cache.borrow_mut().insert(ast_ty.id, typ);
return typ;
}
@ -1838,6 +1841,10 @@ fn compute_object_lifetime_bound<'tcx>(
return ast_region_to_region(tcx, r);
}
if let Err(ErrorReported) = this.ensure_super_predicates(span,principal_trait_ref.def_id()) {
return ty::ReStatic;
}
// No explicit region bound specified. Therefore, examine trait
// bounds and see if we can derive region bounds from those.
let derived_region_bounds =
@ -1923,34 +1930,11 @@ pub fn partition_bounds<'a>(tcx: &ty::ctxt,
let mut builtin_bounds = ty::empty_builtin_bounds();
let mut region_bounds = Vec::new();
let mut trait_bounds = Vec::new();
let mut trait_def_ids = DefIdMap();
for ast_bound in ast_bounds {
match *ast_bound {
ast::TraitTyParamBound(ref b, ast::TraitBoundModifier::None) => {
match ::lookup_full_def(tcx, b.trait_ref.path.span, b.trait_ref.ref_id) {
def::DefTrait(trait_did) => {
match trait_def_ids.get(&trait_did) {
// Already seen this trait. We forbid
// duplicates in the list (for some
// reason).
Some(span) => {
span_err!(
tcx.sess, b.trait_ref.path.span, E0127,
"trait `{}` already appears in the \
list of bounds",
b.trait_ref.path.user_string(tcx));
tcx.sess.span_note(
*span,
"previous appearance is here");
continue;
}
None => { }
}
trait_def_ids.insert(trait_did, b.trait_ref.path.span);
if ty::try_add_builtin_trait(tcx,
trait_did,
&mut builtin_bounds) {

View File

@ -634,16 +634,21 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
target_trait_def_id: ast::DefId)
-> ty::PolyTraitRef<'tcx>
{
match traits::upcast(self.tcx(), source_trait_ref.clone(), target_trait_def_id) {
Some(super_trait_ref) => super_trait_ref,
None => {
self.tcx().sess.span_bug(
self.span,
&format!("cannot upcast `{}` to `{}`",
source_trait_ref.repr(self.tcx()),
target_trait_def_id.repr(self.tcx())));
}
let upcast_trait_refs = traits::upcast(self.tcx(),
source_trait_ref.clone(),
target_trait_def_id);
// must be exactly one trait ref or we'd get an ambig error etc
if upcast_trait_refs.len() != 1 {
self.tcx().sess.span_bug(
self.span,
&format!("cannot uniquely upcast `{}` to `{}`: `{}`",
source_trait_ref.repr(self.tcx()),
target_trait_def_id.repr(self.tcx()),
upcast_trait_refs.repr(self.tcx())));
}
upcast_trait_refs.into_iter().next().unwrap()
}
fn replace_late_bound_regions_with_fresh_var<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()));
let tcx = self.tcx();
let mut cache = HashSet::new();
for bound_trait_ref in traits::transitive_bounds(tcx, bounds) {
// Already visited this trait, skip it.
if !cache.insert(bound_trait_ref.def_id()) {
continue;
}
let (pos, method) = match trait_method(tcx,
bound_trait_ref.def_id(),
self.method_name) {
@ -1269,10 +1263,12 @@ impl<'tcx> Candidate<'tcx> {
fn to_trait_data(&self) -> Option<(ast::DefId,MethodIndex)> {
match self.kind {
InherentImplCandidate(..) |
ObjectCandidate(..) => {
InherentImplCandidate(..) => {
None
}
ObjectCandidate(trait_def_id, method_num, _) => {
Some((trait_def_id, method_num))
}
ClosureCandidate(trait_def_id, method_num) => {
Some((trait_def_id, method_num))
}

View File

@ -1218,6 +1218,11 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
Ok(ty::lookup_trait_def(self.tcx(), id))
}
fn ensure_super_predicates(&self, _: Span, _: ast::DefId) -> Result<(), ErrorReported> {
// all super predicates are ensured during collect pass
Ok(())
}
fn get_free_substs(&self) -> Option<&Substs<'tcx>> {
Some(&self.inh.param_env.free_substs)
}
@ -1248,6 +1253,15 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
Ok(r)
}
fn trait_defines_associated_type_named(&self,
trait_def_id: ast::DefId,
assoc_name: ast::Name)
-> bool
{
let trait_def = ty::lookup_trait_def(self.ccx.tcx, trait_def_id);
trait_def.associated_type_names.contains(&assoc_name)
}
fn ty_infer(&self, _span: Span) -> Ty<'tcx> {
self.infcx().next_ty_var()
}

View File

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

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
parameters themselves are represented as `ty_param()` instances.
The phasing of type conversion is somewhat complicated. There are a
number of possible cycles that can arise.
The phasing of type conversion is somewhat complicated. There is no
clear set of phases we can enforce (e.g., converting traits first,
then types, or something like that) because the user can introduce
arbitrary interdependencies. So instead we generally convert things
lazilly and on demand, and include logic that checks for cycles.
Demand is driven by calls to `AstConv::get_item_type_scheme` or
`AstConv::lookup_trait_def`.
Converting types can require:
1. `Foo<X>` where `Foo` is a type alias, or trait requires knowing:
- number of region / type parameters
- for type parameters, `T:'a` annotations to control defaults for object lifetimes
- defaults for type parameters (which are themselves types!)
2. `Foo<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):
Currently, we "convert" types and traits in three phases (note that
conversion only affects the types of items / enum variants / methods;
it does not e.g. compute the types of individual expressions):
0. Intrinsics
1. Trait definitions
@ -64,16 +46,13 @@ Conversion itself is done by simply walking each of the items in turn
and invoking an appropriate function (e.g., `trait_def_of_item` or
`convert_item`). However, it is possible that while converting an
item, we may need to compute the *type scheme* or *trait definition*
for other items. This is a kind of shallow conversion that is
triggered on demand by calls to `AstConv::get_item_type_scheme` or
`AstConv::lookup_trait_def`. It is possible for cycles to result from
this (e.g., `type A = B; type B = A;`), in which case astconv
(currently) reports the error.
for other items.
There are some shortcomings in this design:
- Cycles through trait definitions (e.g. supertraits) are not currently
detected by astconv. (#12511)
- Before walking the set of supertraits for a given trait, you must
call `ensure_super_predicates` on that trait def-id. Otherwise,
`lookup_super_predicates` will result in ICEs.
- Because the type scheme includes defaults, cycles through type
parameter defaults are illegal even if those defaults are never
employed. This is not necessarily a bug.
@ -169,6 +148,7 @@ struct ItemCtxt<'a,'tcx:'a> {
enum AstConvRequest {
GetItemTypeScheme(ast::DefId),
GetTraitDef(ast::DefId),
EnsureSuperPredicates(ast::DefId),
GetTypeParameterBounds(ast::NodeId),
}
@ -245,7 +225,7 @@ impl<'a,'tcx> CrateCtxt<'a,'tcx> {
request: AstConvRequest,
code: F)
-> Result<R,ErrorReported>
where F: FnOnce() -> R
where F: FnOnce() -> Result<R,ErrorReported>
{
{
let mut stack = self.stack.borrow_mut();
@ -263,7 +243,7 @@ impl<'a,'tcx> CrateCtxt<'a,'tcx> {
let result = code();
self.stack.borrow_mut().pop();
Ok(result)
result
}
fn report_cycle(&self,
@ -284,6 +264,11 @@ impl<'a,'tcx> CrateCtxt<'a,'tcx> {
&format!("the cycle begins when processing `{}`...",
ty::item_path_str(tcx, def_id)));
}
AstConvRequest::EnsureSuperPredicates(def_id) => {
tcx.sess.note(
&format!("the cycle begins when computing the supertraits of `{}`...",
ty::item_path_str(tcx, def_id)));
}
AstConvRequest::GetTypeParameterBounds(id) => {
let def = tcx.type_parameter_def(id);
tcx.sess.note(
@ -301,6 +286,11 @@ impl<'a,'tcx> CrateCtxt<'a,'tcx> {
&format!("...which then requires processing `{}`...",
ty::item_path_str(tcx, def_id)));
}
AstConvRequest::EnsureSuperPredicates(def_id) => {
tcx.sess.note(
&format!("...which then requires computing the supertraits of `{}`...",
ty::item_path_str(tcx, def_id)));
}
AstConvRequest::GetTypeParameterBounds(id) => {
let def = tcx.type_parameter_def(id);
tcx.sess.note(
@ -318,6 +308,12 @@ impl<'a,'tcx> CrateCtxt<'a,'tcx> {
&format!("...which then again requires processing `{}`, completing the cycle.",
ty::item_path_str(tcx, def_id)));
}
AstConvRequest::EnsureSuperPredicates(def_id) => {
tcx.sess.note(
&format!("...which then again requires computing the supertraits of `{}`, \
completing the cycle.",
ty::item_path_str(tcx, def_id)));
}
AstConvRequest::GetTypeParameterBounds(id) => {
let def = tcx.type_parameter_def(id);
tcx.sess.note(
@ -327,6 +323,41 @@ impl<'a,'tcx> CrateCtxt<'a,'tcx> {
}
}
}
/// Loads the trait def for a given trait, returning ErrorReported if a cycle arises.
fn get_trait_def(&self, trait_id: ast::DefId)
-> Rc<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> {
@ -342,7 +373,7 @@ impl<'a, 'tcx> AstConv<'tcx> for ItemCtxt<'a, 'tcx> {
-> Result<ty::TypeScheme<'tcx>, ErrorReported>
{
self.ccx.cycle_check(span, AstConvRequest::GetItemTypeScheme(id), || {
type_scheme_of_def_id(self.ccx, id)
Ok(type_scheme_of_def_id(self.ccx, id))
})
}
@ -350,20 +381,49 @@ impl<'a, 'tcx> AstConv<'tcx> for ItemCtxt<'a, 'tcx> {
-> Result<Rc<ty::TraitDef<'tcx>>, ErrorReported>
{
self.ccx.cycle_check(span, AstConvRequest::GetTraitDef(id), || {
get_trait_def(self.ccx, id)
Ok(self.ccx.get_trait_def(id))
})
}
fn ensure_super_predicates(&self,
span: Span,
trait_def_id: ast::DefId)
-> Result<(), ErrorReported>
{
debug!("ensure_super_predicates(trait_def_id={})",
trait_def_id.repr(self.tcx()));
self.ccx.ensure_super_predicates(span, trait_def_id)
}
fn get_type_parameter_bounds(&self,
span: Span,
node_id: ast::NodeId)
-> Result<Vec<ty::PolyTraitRef<'tcx>>, ErrorReported>
{
self.ccx.cycle_check(span, AstConvRequest::GetTypeParameterBounds(node_id), || {
self.param_bounds.get_type_parameter_bounds(self, span, node_id)
let v = self.param_bounds.get_type_parameter_bounds(self, span, node_id)
.into_iter()
.filter_map(|p| p.to_opt_poly_trait_ref())
.collect();
Ok(v)
})
}
fn trait_defines_associated_type_named(&self,
trait_def_id: ast::DefId,
assoc_name: ast::Name)
-> bool
{
if trait_def_id.krate == ast::LOCAL_CRATE {
trait_defines_associated_type_named(self.ccx, trait_def_id.node, assoc_name)
} else {
let trait_def = ty::lookup_trait_def(self.tcx(), trait_def_id);
trait_def.associated_type_names.contains(&assoc_name)
}
}
fn ty_infer(&self, span: Span) -> Ty<'tcx> {
span_err!(self.tcx().sess, span, E0121,
"the type placeholder `_` is not allowed within types on item signatures");
@ -387,7 +447,7 @@ trait GetTypeParameterBounds<'tcx> {
astconv: &AstConv<'tcx>,
span: Span,
node_id: ast::NodeId)
-> Vec<ty::PolyTraitRef<'tcx>>;
-> Vec<ty::Predicate<'tcx>>;
}
/// Find bounds from both elements of the tuple.
@ -398,7 +458,7 @@ impl<'a,'b,'tcx,A,B> GetTypeParameterBounds<'tcx> for (&'a A,&'b B)
astconv: &AstConv<'tcx>,
span: Span,
node_id: ast::NodeId)
-> Vec<ty::PolyTraitRef<'tcx>>
-> Vec<ty::Predicate<'tcx>>
{
let mut v = self.0.get_type_parameter_bounds(astconv, span, node_id);
v.extend(self.1.get_type_parameter_bounds(astconv, span, node_id).into_iter());
@ -412,7 +472,7 @@ impl<'tcx> GetTypeParameterBounds<'tcx> for () {
_astconv: &AstConv<'tcx>,
_span: Span,
_node_id: ast::NodeId)
-> Vec<ty::PolyTraitRef<'tcx>>
-> Vec<ty::Predicate<'tcx>>
{
Vec::new()
}
@ -426,29 +486,28 @@ impl<'tcx> GetTypeParameterBounds<'tcx> for ty::GenericPredicates<'tcx> {
astconv: &AstConv<'tcx>,
_span: Span,
node_id: ast::NodeId)
-> Vec<ty::PolyTraitRef<'tcx>>
-> Vec<ty::Predicate<'tcx>>
{
let def = astconv.tcx().type_parameter_def(node_id);
self.predicates
.iter()
.filter_map(|predicate| {
match *predicate {
.filter(|predicate| {
match **predicate {
ty::Predicate::Trait(ref data) => {
if data.0.self_ty().is_param(def.space, def.index) {
Some(data.to_poly_trait_ref())
} else {
None
}
data.skip_binder().self_ty().is_param(def.space, def.index)
}
ty::Predicate::TypeOutlives(ref data) => {
data.skip_binder().0.is_param(def.space, def.index)
}
ty::Predicate::Equate(..) |
ty::Predicate::RegionOutlives(..) |
ty::Predicate::TypeOutlives(..) |
ty::Predicate::Projection(..) => {
None
false
}
}
})
.cloned()
.collect()
}
}
@ -462,7 +521,7 @@ impl<'tcx> GetTypeParameterBounds<'tcx> for ast::Generics {
astconv: &AstConv<'tcx>,
_: Span,
node_id: ast::NodeId)
-> Vec<ty::PolyTraitRef<'tcx>>
-> Vec<ty::Predicate<'tcx>>
{
// In the AST, bounds can derive from two places. Either
// written inline like `<T:Foo>` or in a where clause like
@ -476,7 +535,7 @@ impl<'tcx> GetTypeParameterBounds<'tcx> for ast::Generics {
.iter()
.filter(|p| p.id == node_id)
.flat_map(|p| p.bounds.iter())
.filter_map(|b| poly_trait_ref_from_bound(astconv, ty, b, &mut Vec::new()));
.flat_map(|b| predicates_from_bound(astconv, ty, b).into_iter());
let from_where_clauses =
self.where_clause
@ -488,7 +547,7 @@ impl<'tcx> GetTypeParameterBounds<'tcx> for ast::Generics {
})
.filter(|bp| is_param(astconv.tcx(), &bp.bounded_ty, node_id))
.flat_map(|bp| bp.bounds.iter())
.filter_map(|b| poly_trait_ref_from_bound(astconv, ty, b, &mut Vec::new()));
.flat_map(|b| predicates_from_bound(astconv, ty, b).into_iter());
from_ty_params.chain(from_where_clauses).collect()
}
@ -505,10 +564,15 @@ fn is_param<'tcx>(tcx: &ty::ctxt<'tcx>,
{
if let ast::TyPath(None, _) = ast_ty.node {
let path_res = tcx.def_map.borrow()[ast_ty.id];
if let def::DefTyParam(_, _, def_id, _) = path_res.base_def {
path_res.depth == 0 && def_id == local_def(param_id)
} else {
false
match path_res.base_def {
def::DefSelfTy(node_id) =>
path_res.depth == 0 && node_id == param_id,
def::DefTyParam(_, _, def_id, _) =>
path_res.depth == 0 && def_id == local_def(param_id),
_ =>
false,
}
} else {
false
@ -777,9 +841,10 @@ fn convert_methods<'a,'tcx,'i,I>(ccx: &CrateCtxt<'a, 'tcx>,
rcvr_visibility: ast::Visibility)
where I: Iterator<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),
rcvr_ty_generics.repr(ccx.tcx));
rcvr_ty_generics.repr(ccx.tcx),
rcvr_ty_predicates.repr(ccx.tcx));
let tcx = ccx.tcx;
let mut seen_methods = FnvHashSet();
@ -1023,6 +1088,8 @@ fn convert_item(ccx: &CrateCtxt, it: &ast::Item) {
},
ast::ItemTrait(_, _, _, ref trait_items) => {
let trait_def = trait_def_of_item(ccx, it);
let _: Result<(), ErrorReported> = // any error is already reported, can ignore
ccx.ensure_super_predicates(it.span, local_def(it.id));
convert_trait_predicates(ccx, it);
let trait_predicates = ty::lookup_predicates(ccx.tcx, local_def(it.id));
@ -1168,22 +1235,89 @@ fn convert_struct<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
}
}
fn get_trait_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
trait_id: ast::DefId)
-> Rc<ty::TraitDef<'tcx>> {
/// Ensures that the super-predicates of the trait with def-id
/// trait_def_id are converted and stored. This does NOT ensure that
/// the transitive super-predicates are converted; that is the job of
/// the `ensure_super_predicates()` method in the `AstConv` impl
/// above. Returns a list of trait def-ids that must be ensured as
/// well to guarantee that the transitive superpredicates are
/// converted.
fn ensure_super_predicates_step(ccx: &CrateCtxt,
trait_def_id: ast::DefId)
-> Vec<ast::DefId>
{
let tcx = ccx.tcx;
if trait_id.krate != ast::LOCAL_CRATE {
return ty::lookup_trait_def(tcx, trait_id)
debug!("ensure_super_predicates_step(trait_def_id={})", trait_def_id.repr(tcx));
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) {
ast_map::NodeItem(item) => trait_def_of_item(ccx, &*item),
_ => {
tcx.sess.bug(&format!("get_trait_def({}): not an item",
trait_id.node))
}
}
let superpredicates = tcx.super_predicates.borrow().get(&trait_def_id).cloned();
let superpredicates = superpredicates.unwrap_or_else(|| {
let trait_node_id = trait_def_id.node;
let item = match ccx.tcx.map.get(trait_node_id) {
ast_map::NodeItem(item) => item,
_ => ccx.tcx.sess.bug(&format!("trait_node_id {} is not an item", trait_node_id))
};
let (generics, bounds) = match item.node {
ast::ItemTrait(_, ref generics, ref supertraits, _) => (generics, supertraits),
_ => tcx.sess.span_bug(item.span,
"ensure_super_predicates_step invoked on non-trait"),
};
// In-scope when converting the superbounds for `Trait` are
// that `Self:Trait` as well as any bounds that appear on the
// generic types:
let trait_def = trait_def_of_item(ccx, item);
let self_predicate = ty::GenericPredicates {
predicates: VecPerParamSpace::new(vec![],
vec![trait_def.trait_ref.as_predicate()],
vec![])
};
let scope = &(generics, &self_predicate);
// Convert the bounds that follow the colon, e.g. `Bar+Zed` in `trait Foo : Bar+Zed`.
let self_param_ty = ty::mk_self_type(tcx);
let superbounds1 = compute_bounds(&ccx.icx(scope), self_param_ty, bounds,
SizedByDefault::No, item.span);
let superbounds1 = ty::predicates(tcx, self_param_ty, &superbounds1);
// Convert any explicit superbounds in the where clause,
// e.g. `trait Foo where Self : Bar`:
let superbounds2 = generics.get_type_parameter_bounds(&ccx.icx(scope), item.span, item.id);
// Combine the two lists to form the complete set of superbounds:
let superbounds = superbounds1.into_iter().chain(superbounds2.into_iter()).collect();
let superpredicates = ty::GenericPredicates {
predicates: VecPerParamSpace::new(superbounds, vec![], vec![])
};
debug!("superpredicates for trait {} = {}",
local_def(item.id).repr(ccx.tcx),
superpredicates.repr(ccx.tcx));
tcx.super_predicates.borrow_mut().insert(trait_def_id, superpredicates.clone());
superpredicates
});
let def_ids: Vec<_> = superpredicates.predicates
.iter()
.filter_map(|p| p.to_opt_poly_trait_ref())
.map(|tr| tr.def_id())
.collect();
debug!("ensure_super_predicates_step: def_ids={}", def_ids.repr(tcx));
def_ids
}
fn trait_def_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
@ -1197,18 +1331,9 @@ fn trait_def_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
return def.clone();
}
let (unsafety, generics, bounds, items) = match it.node {
ast::ItemTrait(unsafety,
ref generics,
ref supertraits,
ref items) => {
(unsafety, generics, supertraits, items)
}
ref s => {
tcx.sess.span_bug(
it.span,
&format!("trait_def_of_item invoked on {:?}", s));
}
let (unsafety, generics, items) = match it.node {
ast::ItemTrait(unsafety, ref generics, _, ref items) => (unsafety, generics, items),
_ => tcx.sess.span_bug(it.span, "trait_def_of_item invoked on non-trait"),
};
let paren_sugar = ty::has_attr(tcx, def_id, "rustc_paren_sugar");
@ -1226,15 +1351,6 @@ fn trait_def_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
let ty_generics = ty_generics_for_trait(ccx, it.id, substs, generics);
let self_param_ty = ty::ParamTy::for_self().to_ty(ccx.tcx);
// supertraits:
let bounds = compute_bounds(&ccx.icx(generics),
self_param_ty,
bounds,
SizedByDefault::No,
it.span);
let associated_type_names: Vec<_> =
items.iter()
.filter_map(|item| {
@ -1254,7 +1370,6 @@ fn trait_def_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
paren_sugar: paren_sugar,
unsafety: unsafety,
generics: ty_generics,
bounds: bounds,
trait_ref: trait_ref,
associated_type_names: associated_type_names,
});
@ -1296,6 +1411,30 @@ fn trait_def_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
}
}
fn trait_defines_associated_type_named(ccx: &CrateCtxt,
trait_node_id: ast::NodeId,
assoc_name: ast::Name)
-> bool
{
let item = match ccx.tcx.map.get(trait_node_id) {
ast_map::NodeItem(item) => item,
_ => ccx.tcx.sess.bug(&format!("trait_node_id {} is not an item", trait_node_id))
};
let trait_items = match item.node {
ast::ItemTrait(_, _, _, ref trait_items) => trait_items,
_ => ccx.tcx.sess.bug(&format!("trait_node_id {} is not a trait", trait_node_id))
};
trait_items.iter()
.any(|trait_item| {
match *trait_item {
ast::TypeTraitItem(ref t) => t.ty_param.ident.name == assoc_name,
ast::RequiredMethod(..) | ast::ProvidedMethod(..) => false,
}
})
}
fn convert_trait_predicates<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, it: &ast::Item) {
let tcx = ccx.tcx;
let trait_def = trait_def_of_item(ccx, it);
@ -1311,19 +1450,14 @@ fn convert_trait_predicates<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, it: &ast::Item)
}
};
let self_param_ty = ty::ParamTy::for_self().to_ty(ccx.tcx);
let super_predicates = ty::predicates(ccx.tcx, self_param_ty, &trait_def.bounds);
let super_predicates = ty::lookup_super_predicates(ccx.tcx, def_id);
// `ty_generic_predicates` below will consider the bounds on the type
// parameters (including `Self`) and the explicit where-clauses,
// but to get the full set of predicates on a trait we need to add
// in the supertrait bounds and anything declared on the
// associated types.
let mut base_predicates =
ty::GenericPredicates {
predicates: VecPerParamSpace::new(super_predicates, vec![], vec![])
};
let mut base_predicates = super_predicates;
// Add in a predicate that `Self:Trait` (where `Trait` is the
// current trait). This is needed for builtin bounds.
@ -1953,7 +2087,7 @@ fn compute_object_lifetime_default<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
}
}
enum SizedByDefault { Yes, No }
enum SizedByDefault { Yes, No, }
/// Translate the AST's notion of ty param bounds (which are an enum consisting of a newtyped Ty or
/// a region) to ty's notion of ty param bounds, which can either be user-defined traits, or the
@ -1975,11 +2109,6 @@ fn compute_bounds<'tcx>(astconv: &AstConv<'tcx>,
&mut param_bounds.builtin_bounds,
ast_bounds,
span);
check_bounds_compatible(astconv,
param_ty,
&param_bounds,
span);
}
param_bounds.trait_bounds.sort_by(|a,b| a.def_id().cmp(&b.def_id()));
@ -1987,48 +2116,32 @@ fn compute_bounds<'tcx>(astconv: &AstConv<'tcx>,
param_bounds
}
fn check_bounds_compatible<'tcx>(astconv: &AstConv<'tcx>,
param_ty: Ty<'tcx>,
param_bounds: &ty::ParamBounds<'tcx>,
span: Span) {
let tcx = astconv.tcx();
if !param_bounds.builtin_bounds.contains(&ty::BoundSized) {
ty::each_bound_trait_and_supertraits(
tcx,
&param_bounds.trait_bounds,
|trait_ref| {
match astconv.get_trait_def(span, trait_ref.def_id()) {
Ok(trait_def) => {
if trait_def.bounds.builtin_bounds.contains(&ty::BoundSized) {
span_err!(tcx.sess, span, E0129,
"incompatible bounds on `{}`, \
bound `{}` does not allow unsized type",
param_ty.user_string(tcx),
trait_ref.user_string(tcx));
}
}
Err(ErrorReported) => { }
}
true
});
}
}
/// Converts a specific TyParamBound from the AST into the
/// 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>>
/// Converts a specific TyParamBound from the AST into a set of
/// predicates that apply to the self-type. A vector is returned
/// because this can be anywhere from 0 predicates (`T:?Sized` adds no
/// predicates) to 1 (`T:Foo`) to many (`T:Bar<X=i32>` adds `T:Bar`
/// and `<T as Bar>::X == i32`).
fn predicates_from_bound<'tcx>(astconv: &AstConv<'tcx>,
param_ty: Ty<'tcx>,
bound: &ast::TyParamBound)
-> Vec<ty::Predicate<'tcx>>
{
match *bound {
ast::TraitTyParamBound(ref tr, ast::TraitBoundModifier::None) => {
Some(conv_poly_trait_ref(astconv, param_ty, tr, projections))
let mut projections = Vec::new();
let pred = conv_poly_trait_ref(astconv, param_ty, tr, &mut projections);
projections.into_iter()
.map(|p| p.as_predicate())
.chain(Some(pred.as_predicate()).into_iter())
.collect()
}
ast::TraitTyParamBound(_, ast::TraitBoundModifier::Maybe) |
ast::RegionTyParamBound(_) => {
None
ast::RegionTyParamBound(ref lifetime) => {
let region = ast_region_to_region(astconv.tcx(), lifetime);
let pred = ty::Binder(ty::OutlivesPredicate(param_ty, region));
vec![ty::Predicate::TypeOutlives(pred)]
}
ast::TraitTyParamBound(_, ast::TraitBoundModifier::Maybe) => {
Vec::new()
}
}
}

View File

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

View File

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

View File

@ -25,7 +25,7 @@ trait Trait { type Item; }
struct A<T>
where T : Trait,
T : Add<T::Item>
//~^ ERROR illegal recursive type
//~^ ERROR unsupported cyclic reference between types/traits detected
{
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
// http://rust-lang.org/COPYRIGHT.
//
@ -8,12 +8,11 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Test that bounds are sized-compatible.
// Test a cycle where a type parameter on a trait has a default that
// again references the trait.
trait T : Sized {}
fn f<Y: ?Sized + T>() {
//~^ERROR incompatible bounds on `Y`, bound `T` does not allow unsized type
trait Foo<X = Box<Foo>> {
//~^ ERROR unsupported cyclic reference
}
pub fn main() {
}
fn main() { }

View File

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

View File

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

View File

@ -12,18 +12,17 @@
use std::any::Any;
use std::any::TypeId;
use std::marker::MarkerTrait;
pub trait Pt {}
pub trait Rt {}
pub trait Pt : MarkerTrait {}
pub trait Rt : MarkerTrait {}
trait Private<P: Pt, R: Rt> {
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,
//~^ ERROR illegal recursive type; insert an enum or struct in the cycle, if this is desired
<Self as Public>::R
//~^ ERROR unsupported cyclic reference between types/traits detected
> {
type P;
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
// http://rust-lang.org/COPYRIGHT.
//
@ -8,8 +8,19 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
trait Foo {}
// Test case where an associated type is referenced from within the
// supertrait definition, and the impl makes the wrong
// associations. Issue #20220.
fn foo<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);
}