Skip to content

Commit f0c74f8

Browse files
committed
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
2 parents 68740b4 + 9b332ff commit f0c74f8

32 files changed

+822
-575
lines changed

src/librustc/metadata/common.rs

+2-3
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,6 @@ pub const tag_mod_impl: uint = 0x38;
8484
pub const tag_item_trait_item: uint = 0x39;
8585

8686
pub const tag_item_trait_ref: uint = 0x3a;
87-
pub const tag_item_super_trait_ref: uint = 0x3b;
8887

8988
// discriminator value for variants
9089
pub const tag_disr_val: uint = 0x3c;
@@ -221,8 +220,6 @@ pub const tag_struct_field_id: uint = 0x8b;
221220

222221
pub const tag_attribute_is_sugared_doc: uint = 0x8c;
223222

224-
pub const tag_trait_def_bounds: uint = 0x8d;
225-
226223
pub const tag_items_data_region: uint = 0x8e;
227224

228225
pub const tag_region_param_def: uint = 0x8f;
@@ -255,3 +252,5 @@ pub const tag_paren_sugar: uint = 0xa0;
255252

256253
pub const tag_codemap: uint = 0xa1;
257254
pub const tag_codemap_filemap: uint = 0xa2;
255+
256+
pub const tag_item_super_predicates: uint = 0xa3;

src/librustc/metadata/csearch.rs

+8-8
Original file line numberDiff line numberDiff line change
@@ -175,14 +175,6 @@ pub fn get_provided_trait_methods<'tcx>(tcx: &ty::ctxt<'tcx>,
175175
decoder::get_provided_trait_methods(cstore.intr.clone(), &*cdata, def.node, tcx)
176176
}
177177

178-
pub fn get_supertraits<'tcx>(tcx: &ty::ctxt<'tcx>,
179-
def: ast::DefId)
180-
-> Vec<Rc<ty::TraitRef<'tcx>>> {
181-
let cstore = &tcx.sess.cstore;
182-
let cdata = cstore.get_crate_data(def.krate);
183-
decoder::get_supertraits(&*cdata, def.node, tcx)
184-
}
185-
186178
pub fn get_type_name_if_impl(cstore: &cstore::CStore, def: ast::DefId)
187179
-> Option<ast::Name> {
188180
let cdata = cstore.get_crate_data(def.krate);
@@ -238,6 +230,14 @@ pub fn get_predicates<'tcx>(tcx: &ty::ctxt<'tcx>, def: ast::DefId)
238230
decoder::get_predicates(&*cdata, def.node, tcx)
239231
}
240232

233+
pub fn get_super_predicates<'tcx>(tcx: &ty::ctxt<'tcx>, def: ast::DefId)
234+
-> ty::GenericPredicates<'tcx>
235+
{
236+
let cstore = &tcx.sess.cstore;
237+
let cdata = cstore.get_crate_data(def.krate);
238+
decoder::get_super_predicates(&*cdata, def.node, tcx)
239+
}
240+
241241
pub fn get_field_type<'tcx>(tcx: &ty::ctxt<'tcx>, class_id: ast::DefId,
242242
def: ast::DefId) -> ty::TypeScheme<'tcx> {
243243
let cstore = &tcx.sess.cstore;

src/librustc/metadata/decoder.rs

+11-35
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,8 @@ use metadata::csearch::MethodInfo;
2222
use metadata::csearch;
2323
use metadata::cstore;
2424
use metadata::tydecode::{parse_ty_data, parse_region_data, parse_def_id,
25-
parse_type_param_def_data, parse_bounds_data,
26-
parse_bare_fn_ty_data, parse_trait_ref_data,
27-
parse_predicate_data};
25+
parse_type_param_def_data, parse_bare_fn_ty_data,
26+
parse_trait_ref_data, parse_predicate_data};
2827
use middle::def;
2928
use middle::lang_items;
3029
use middle::subst;
@@ -260,18 +259,6 @@ fn item_trait_ref<'tcx>(doc: rbml::Doc, tcx: &ty::ctxt<'tcx>, cdata: Cmd)
260259
doc_trait_ref(tp, tcx, cdata)
261260
}
262261

263-
fn doc_bounds<'tcx>(doc: rbml::Doc, tcx: &ty::ctxt<'tcx>, cdata: Cmd)
264-
-> ty::ParamBounds<'tcx> {
265-
parse_bounds_data(doc.data, cdata.cnum, doc.start, tcx,
266-
|_, did| translate_def_id(cdata, did))
267-
}
268-
269-
fn trait_def_bounds<'tcx>(doc: rbml::Doc, tcx: &ty::ctxt<'tcx>, cdata: Cmd)
270-
-> ty::ParamBounds<'tcx> {
271-
let d = reader::get_doc(doc, tag_trait_def_bounds);
272-
doc_bounds(d, tcx, cdata)
273-
}
274-
275262
fn enum_variant_ids(item: rbml::Doc, cdata: Cmd) -> Vec<ast::DefId> {
276263
let mut ids: Vec<ast::DefId> = Vec::new();
277264
let v = tag_items_data_item_variant;
@@ -406,7 +393,6 @@ pub fn get_trait_def<'tcx>(cdata: Cmd,
406393
{
407394
let item_doc = lookup_item(item_id, cdata.data());
408395
let generics = doc_generics(item_doc, tcx, cdata, tag_item_generics);
409-
let bounds = trait_def_bounds(item_doc, tcx, cdata);
410396
let unsafety = parse_unsafety(item_doc);
411397
let associated_type_names = parse_associated_type_names(item_doc);
412398
let paren_sugar = parse_paren_sugar(item_doc);
@@ -415,7 +401,6 @@ pub fn get_trait_def<'tcx>(cdata: Cmd,
415401
paren_sugar: paren_sugar,
416402
unsafety: unsafety,
417403
generics: generics,
418-
bounds: bounds,
419404
trait_ref: item_trait_ref(item_doc, tcx, cdata),
420405
associated_type_names: associated_type_names,
421406
}
@@ -430,6 +415,15 @@ pub fn get_predicates<'tcx>(cdata: Cmd,
430415
doc_predicates(item_doc, tcx, cdata, tag_item_generics)
431416
}
432417

418+
pub fn get_super_predicates<'tcx>(cdata: Cmd,
419+
item_id: ast::NodeId,
420+
tcx: &ty::ctxt<'tcx>)
421+
-> ty::GenericPredicates<'tcx>
422+
{
423+
let item_doc = lookup_item(item_id, cdata.data());
424+
doc_predicates(item_doc, tcx, cdata, tag_item_super_predicates)
425+
}
426+
433427
pub fn get_type<'tcx>(cdata: Cmd, id: ast::NodeId, tcx: &ty::ctxt<'tcx>)
434428
-> ty::TypeScheme<'tcx>
435429
{
@@ -971,24 +965,6 @@ pub fn get_provided_trait_methods<'tcx>(intr: Rc<IdentInterner>,
971965
return result;
972966
}
973967

974-
/// Returns the supertraits of the given trait.
975-
pub fn get_supertraits<'tcx>(cdata: Cmd, id: ast::NodeId, tcx: &ty::ctxt<'tcx>)
976-
-> Vec<Rc<ty::TraitRef<'tcx>>> {
977-
let mut results = Vec::new();
978-
let item_doc = lookup_item(id, cdata.data());
979-
reader::tagged_docs(item_doc, tag_item_super_trait_ref, |trait_doc| {
980-
// NB. Only reads the ones that *aren't* builtin-bounds. See also
981-
// get_trait_def() for collecting the builtin bounds.
982-
// FIXME(#8559): The builtin bounds shouldn't be encoded in the first place.
983-
let trait_ref = doc_trait_ref(trait_doc, tcx, cdata);
984-
if tcx.lang_items.to_builtin_kind(trait_ref.def_id).is_none() {
985-
results.push(trait_ref);
986-
}
987-
true
988-
});
989-
return results;
990-
}
991-
992968
pub fn get_type_name_if_impl(cdata: Cmd,
993969
node_id: ast::NodeId) -> Option<ast::Name> {
994970
let item = lookup_item(node_id, cdata.data());

src/librustc/metadata/encoder.rs

+27-17
Original file line numberDiff line numberDiff line change
@@ -206,21 +206,6 @@ pub fn write_region(ecx: &EncodeContext,
206206
tyencode::enc_region(rbml_w, ty_str_ctxt, r);
207207
}
208208

209-
fn encode_bounds<'a, 'tcx>(rbml_w: &mut Encoder,
210-
ecx: &EncodeContext<'a, 'tcx>,
211-
bounds: &ty::ParamBounds<'tcx>,
212-
tag: uint) {
213-
rbml_w.start_tag(tag);
214-
215-
let ty_str_ctxt = &tyencode::ctxt { diag: ecx.diag,
216-
ds: def_to_string,
217-
tcx: ecx.tcx,
218-
abbrevs: &ecx.type_abbrevs };
219-
tyencode::enc_bounds(rbml_w, ty_str_ctxt, bounds);
220-
221-
rbml_w.end_tag();
222-
}
223-
224209
fn encode_type<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
225210
rbml_w: &mut Encoder,
226211
typ: Ty<'tcx>) {
@@ -728,6 +713,7 @@ fn encode_generics<'a, 'tcx>(rbml_w: &mut Encoder,
728713
tcx: ecx.tcx,
729714
abbrevs: &ecx.type_abbrevs
730715
};
716+
731717
for param in generics.types.iter() {
732718
rbml_w.start_tag(tag_type_param_def);
733719
tyencode::enc_type_param_def(rbml_w, ty_str_ctxt, param);
@@ -758,6 +744,22 @@ fn encode_generics<'a, 'tcx>(rbml_w: &mut Encoder,
758744
rbml_w.end_tag();
759745
}
760746

747+
encode_predicates_in_current_doc(rbml_w, ecx, predicates);
748+
749+
rbml_w.end_tag();
750+
}
751+
752+
fn encode_predicates_in_current_doc<'a,'tcx>(rbml_w: &mut Encoder,
753+
ecx: &EncodeContext<'a,'tcx>,
754+
predicates: &ty::GenericPredicates<'tcx>)
755+
{
756+
let ty_str_ctxt = &tyencode::ctxt {
757+
diag: ecx.diag,
758+
ds: def_to_string,
759+
tcx: ecx.tcx,
760+
abbrevs: &ecx.type_abbrevs
761+
};
762+
761763
for (space, _, predicate) in predicates.predicates.iter_enumerated() {
762764
rbml_w.start_tag(tag_predicate);
763765

@@ -769,7 +771,15 @@ fn encode_generics<'a, 'tcx>(rbml_w: &mut Encoder,
769771

770772
rbml_w.end_tag();
771773
}
774+
}
772775

776+
fn encode_predicates<'a,'tcx>(rbml_w: &mut Encoder,
777+
ecx: &EncodeContext<'a,'tcx>,
778+
predicates: &ty::GenericPredicates<'tcx>,
779+
tag: uint)
780+
{
781+
rbml_w.start_tag(tag);
782+
encode_predicates_in_current_doc(rbml_w, ecx, predicates);
773783
rbml_w.end_tag();
774784
}
775785

@@ -1280,6 +1290,8 @@ fn encode_info_for_item(ecx: &EncodeContext,
12801290
encode_paren_sugar(rbml_w, trait_def.paren_sugar);
12811291
encode_associated_type_names(rbml_w, &trait_def.associated_type_names);
12821292
encode_generics(rbml_w, ecx, &trait_def.generics, &trait_predicates, tag_item_generics);
1293+
encode_predicates(rbml_w, ecx, &ty::lookup_super_predicates(tcx, def_id),
1294+
tag_item_super_predicates);
12831295
encode_trait_ref(rbml_w, ecx, &*trait_def.trait_ref, tag_item_trait_ref);
12841296
encode_name(rbml_w, item.ident.name);
12851297
encode_attributes(rbml_w, &item.attrs);
@@ -1304,8 +1316,6 @@ fn encode_info_for_item(ecx: &EncodeContext,
13041316
}
13051317
encode_path(rbml_w, path.clone());
13061318

1307-
encode_bounds(rbml_w, ecx, &trait_def.bounds, tag_trait_def_bounds);
1308-
13091319
// Encode the implementations of this trait.
13101320
encode_extension_implementations(ecx, rbml_w, def_id);
13111321

src/librustc/middle/traits/mod.rs

+4
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,11 @@ pub struct VtableBuiltinData<N> {
280280
/// for the object type `Foo`.
281281
#[derive(PartialEq,Eq,Clone)]
282282
pub struct VtableObjectData<'tcx> {
283+
/// the object type `Foo`.
283284
pub object_ty: Ty<'tcx>,
285+
286+
/// `Foo` upcast to the obligation trait. This will be some supertrait of `Foo`.
287+
pub upcast_trait_ref: ty::PolyTraitRef<'tcx>,
284288
}
285289

286290
/// Creates predicate obligations from the generic bounds.

src/librustc/middle/traits/object_safety.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ use super::elaborate_predicates;
2222

2323
use middle::subst::{self, SelfSpace, TypeSpace};
2424
use middle::traits;
25-
use middle::ty::{self, Ty};
25+
use middle::ty::{self, ToPolyTraitRef, Ty};
2626
use std::rc::Rc;
2727
use syntax::ast;
2828
use util::ppaux::Repr;
@@ -128,9 +128,12 @@ fn supertraits_reference_self<'tcx>(tcx: &ty::ctxt<'tcx>,
128128
{
129129
let trait_def = ty::lookup_trait_def(tcx, trait_def_id);
130130
let trait_ref = trait_def.trait_ref.clone();
131-
let predicates = ty::predicates_for_trait_ref(tcx, &ty::Binder(trait_ref));
131+
let trait_ref = trait_ref.to_poly_trait_ref();
132+
let predicates = ty::lookup_super_predicates(tcx, trait_def_id);
132133
predicates
134+
.predicates
133135
.into_iter()
136+
.map(|predicate| predicate.subst_supertrait(tcx, &trait_ref))
134137
.any(|predicate| {
135138
match predicate {
136139
ty::Predicate::Trait(ref data) => {

src/librustc/middle/traits/select.rs

+43-29
Original file line numberDiff line numberDiff line change
@@ -1260,19 +1260,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
12601260
poly_trait_ref.repr(self.tcx()));
12611261

12621262
// see whether the object trait can be upcast to the trait we are looking for
1263-
let obligation_def_id = obligation.predicate.def_id();
1264-
let upcast_trait_ref = match util::upcast(self.tcx(), poly_trait_ref, obligation_def_id) {
1265-
Some(r) => r,
1266-
None => { return; }
1267-
};
1268-
1269-
debug!("assemble_candidates_from_object_ty: upcast_trait_ref={}",
1270-
upcast_trait_ref.repr(self.tcx()));
1271-
1272-
// check whether the upcast version of the trait-ref matches what we are looking for
1273-
if let Ok(()) = self.infcx.probe(|_| self.match_poly_trait_ref(obligation,
1274-
upcast_trait_ref.clone())) {
1275-
debug!("assemble_candidates_from_object_ty: matched, pushing candidate");
1263+
let upcast_trait_refs = self.upcast(poly_trait_ref, obligation);
1264+
if upcast_trait_refs.len() > 1 {
1265+
// can be upcast in many ways; need more type information
1266+
candidates.ambiguous = true;
1267+
} else if upcast_trait_refs.len() == 1 {
12761268
candidates.vec.push(ObjectCandidate);
12771269
}
12781270
}
@@ -1455,9 +1447,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
14551447
let principal =
14561448
data.principal_trait_ref_with_self_ty(self.tcx(),
14571449
self.tcx().types.err);
1450+
let desired_def_id = obligation.predicate.def_id();
14581451
for tr in util::supertraits(self.tcx(), principal) {
1459-
let td = ty::lookup_trait_def(self.tcx(), tr.def_id());
1460-
if td.bounds.builtin_bounds.contains(&bound) {
1452+
if tr.def_id() == desired_def_id {
14611453
return Ok(If(Vec::new()))
14621454
}
14631455
}
@@ -2063,28 +2055,24 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
20632055
}
20642056
};
20652057

2066-
let obligation_def_id = obligation.predicate.def_id();
2067-
let upcast_trait_ref = match util::upcast(self.tcx(),
2068-
poly_trait_ref.clone(),
2069-
obligation_def_id) {
2070-
Some(r) => r,
2071-
None => {
2072-
self.tcx().sess.span_bug(obligation.cause.span,
2073-
&format!("unable to upcast from {} to {}",
2074-
poly_trait_ref.repr(self.tcx()),
2075-
obligation_def_id.repr(self.tcx())));
2076-
}
2077-
};
2058+
// Upcast the object type to the obligation type. There must
2059+
// be exactly one applicable trait-reference; if this were not
2060+
// the case, we would have reported an ambiguity error rather
2061+
// than successfully selecting one of the candidates.
2062+
let upcast_trait_refs = self.upcast(poly_trait_ref.clone(), obligation);
2063+
assert_eq!(upcast_trait_refs.len(), 1);
2064+
let upcast_trait_ref = upcast_trait_refs.into_iter().next().unwrap();
20782065

2079-
match self.match_poly_trait_ref(obligation, upcast_trait_ref) {
2066+
match self.match_poly_trait_ref(obligation, upcast_trait_ref.clone()) {
20802067
Ok(()) => { }
20812068
Err(()) => {
20822069
self.tcx().sess.span_bug(obligation.cause.span,
20832070
"failed to match trait refs");
20842071
}
20852072
}
20862073

2087-
VtableObjectData { object_ty: self_ty }
2074+
VtableObjectData { object_ty: self_ty,
2075+
upcast_trait_ref: upcast_trait_ref }
20882076
}
20892077

20902078
fn confirm_fn_pointer_candidate(&mut self,
@@ -2501,6 +2489,32 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
25012489
obligation.cause.clone()
25022490
}
25032491
}
2492+
2493+
/// Upcasts an object trait-reference into those that match the obligation.
2494+
fn upcast(&mut self, obj_trait_ref: ty::PolyTraitRef<'tcx>, obligation: &TraitObligation<'tcx>)
2495+
-> Vec<ty::PolyTraitRef<'tcx>>
2496+
{
2497+
debug!("upcast(obj_trait_ref={}, obligation={})",
2498+
obj_trait_ref.repr(self.tcx()),
2499+
obligation.repr(self.tcx()));
2500+
2501+
let obligation_def_id = obligation.predicate.def_id();
2502+
let mut upcast_trait_refs = util::upcast(self.tcx(), obj_trait_ref, obligation_def_id);
2503+
2504+
// Retain only those upcast versions that match the trait-ref
2505+
// we are looking for. In particular, we know that all of
2506+
// `upcast_trait_refs` apply to the correct trait, but
2507+
// possibly with incorrect type parameters. For example, we
2508+
// may be trying to upcast `Foo` to `Bar<i32>`, but `Foo` is
2509+
// declared as `trait Foo : Bar<u32>`.
2510+
upcast_trait_refs.retain(|upcast_trait_ref| {
2511+
let upcast_trait_ref = upcast_trait_ref.clone();
2512+
self.infcx.probe(|_| self.match_poly_trait_ref(obligation, upcast_trait_ref)).is_ok()
2513+
});
2514+
2515+
debug!("upcast: upcast_trait_refs={}", upcast_trait_refs.repr(self.tcx()));
2516+
upcast_trait_refs
2517+
}
25042518
}
25052519

25062520
impl<'tcx> Repr<'tcx> for SelectionCandidate<'tcx> {

0 commit comments

Comments
 (0)