Skip to content

Refactor supertrait handling #23026

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Mar 5, 2015
5 changes: 2 additions & 3 deletions src/librustc/metadata/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
16 changes: 8 additions & 8 deletions src/librustc/metadata/csearch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand Down
46 changes: 11 additions & 35 deletions src/librustc/metadata/decoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand All @@ -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,
}
Expand All @@ -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>
{
Expand Down Expand Up @@ -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());
Expand Down
44 changes: 27 additions & 17 deletions src/librustc/metadata/encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>) {
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);

Expand All @@ -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();
}

Expand Down Expand Up @@ -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);
Expand All @@ -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);

Expand Down
4 changes: 4 additions & 0 deletions src/librustc/middle/traits/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
7 changes: 5 additions & 2 deletions src/librustc/middle/traits/object_safety.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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) => {
Expand Down
72 changes: 43 additions & 29 deletions src/librustc/middle/traits/select.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
Expand Down Expand Up @@ -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()))
}
}
Expand Down Expand Up @@ -2063,28 +2055,24 @@ 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,
"failed to match trait refs");
}
}

VtableObjectData { object_ty: self_ty }
VtableObjectData { object_ty: self_ty,
upcast_trait_ref: upcast_trait_ref }
}

fn confirm_fn_pointer_candidate(&mut self,
Expand Down Expand Up @@ -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> {
Expand Down
Loading