Skip to content

Commit

Permalink
Refactor BuiltinBounds to Vec<DefId> on TraitObject.
Browse files Browse the repository at this point in the history
  • Loading branch information
Mark-Simulacrum committed Nov 28, 2016
1 parent 46c7a11 commit 607af72
Show file tree
Hide file tree
Showing 10 changed files with 126 additions and 85 deletions.
46 changes: 22 additions & 24 deletions src/librustc/traits/select.rs
Expand Up @@ -41,6 +41,7 @@ use ty::{self, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable};
use traits;
use ty::fast_reject;
use ty::relate::TypeRelation;
use middle::lang_items;

use rustc_data_structures::bitvec::BitVector;
use rustc_data_structures::snapshot_vec::{SnapshotVecDelegate, SnapshotVec};
Expand All @@ -49,6 +50,7 @@ use std::fmt;
use std::marker::PhantomData;
use std::mem;
use std::rc::Rc;
use std::iter;
use syntax::abi::Abi;
use hir;
use util::nodemap::FxHashMap;
Expand Down Expand Up @@ -1516,16 +1518,11 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
let self_ty = this.tcx().erase_late_bound_regions(&obligation.self_ty());
let poly_trait_ref = match self_ty.sty {
ty::TyTrait(ref data) => {
match this.tcx().lang_items.to_builtin_kind(obligation.predicate.def_id()) {
Some(bound @ ty::BoundSend) | Some(bound @ ty::BoundSync) => {
if data.builtin_bounds.contains(&bound) {
debug!("assemble_candidates_from_object_ty: matched builtin bound, \
pushing candidate");
candidates.vec.push(BuiltinObjectCandidate);
return;
}
}
_ => {}
if data.auto_traits().any(|did| did == obligation.predicate.def_id()) {
debug!("assemble_candidates_from_object_ty: matched builtin bound, \
pushing candidate");
candidates.vec.push(BuiltinObjectCandidate);
return;
}

match data.principal() {
Expand Down Expand Up @@ -1616,7 +1613,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
// #2 (region bounds).
match (data_a.principal(), data_b.principal()) {
(Some(ref a), Some(ref b)) => a.def_id() == b.def_id() &&
data_a.builtin_bounds.is_superset(&data_b.builtin_bounds),
data_b.auto_traits()
// All of a's auto traits need to be in b's auto traits.
.all(|b| data_a.auto_traits().any(|a| a == b)),
_ => false
}
}
Expand Down Expand Up @@ -2481,7 +2480,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
let new_trait = tcx.mk_trait(ty::TraitObject::new(
data_a.principal(),
data_b.region_bound,
data_b.builtin_bounds,
data_b.auto_traits().collect(),
data_a.projection_bounds.clone(),
));
let origin = TypeOrigin::Misc(obligation.cause.span);
Expand All @@ -2504,10 +2503,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
// T -> Trait.
(_, &ty::TyTrait(ref data)) => {
let mut object_dids =
data.builtin_bounds.iter().flat_map(|bound| {
tcx.lang_items.from_builtin_kind(bound).ok()
})
.chain(data.principal().map(|ref p| p.def_id()));
data.auto_traits().chain(data.principal().map(|ref p| p.def_id()));
if let Some(did) = object_dids.find(|did| {
!tcx.is_object_safe(*did)
}) {
Expand All @@ -2527,19 +2523,21 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
push(data.principal().unwrap().with_self_ty(tcx, source).to_predicate());

// We can only make objects from sized types.
let mut builtin_bounds = data.builtin_bounds;
builtin_bounds.insert(ty::BoundSized);
let trait_refs = data.auto_traits()
.chain(iter::once(
tcx.lang_items.require(lang_items::SizedTraitLangItem)
.unwrap_or_else(|msg| tcx.sess.fatal(&msg[..]))))
.map(|did| ty::TraitRef {
def_id: did,
substs: tcx.mk_substs_trait(source, &[]),
});

// Create additional obligations for all the various builtin
// bounds attached to the object cast. (In other words, if the
// object type is Foo+Send, this would create an obligation
// for the Send check.)
for bound in &builtin_bounds {
if let Ok(tr) = tcx.trait_ref_for_builtin_bound(bound, source) {
push(tr.to_predicate());
} else {
return Err(Unimplemented);
}
for tr in trait_refs {
push(tr.to_predicate());
}

// Create obligations for the projection predicates.
Expand Down
6 changes: 5 additions & 1 deletion src/librustc/ty/relate.rs
Expand Up @@ -428,7 +428,11 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R,
|relation| relation.relate_with_variance(ty::Contravariant,
&a_obj.region_bound,
&b_obj.region_bound))?;
let nb = relation.relate(&a_obj.builtin_bounds, &b_obj.builtin_bounds)?;
let nb = if !a_obj.auto_traits().eq(b_obj.auto_traits()) {
return Err(TypeError::Sorts(expected_found(relation, &a, &b)));
} else {
a_obj.auto_traits().collect()
};
let pb = relation.relate(&a_obj.projection_bounds, &b_obj.projection_bounds)?;
Ok(tcx.mk_trait(ty::TraitObject::new(principal, r, nb, pb)))
}
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/ty/structural_impls.rs
Expand Up @@ -432,7 +432,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::TraitObject<'tcx> {
ty::TraitObject::new(
self.principal().map(|p| p.fold_with(folder)),
self.region_bound.fold_with(folder),
self.builtin_bounds,
self.auto_traits().collect(),
self.projection_bounds.fold_with(folder),
)
}
Expand Down
34 changes: 21 additions & 13 deletions src/librustc/ty/sty.rs
Expand Up @@ -279,25 +279,29 @@ impl<'a, 'gcx, 'acx, 'tcx> ClosureSubsts<'tcx> {
pub struct TraitObject<'tcx> {
principal: Option<PolyExistentialTraitRef<'tcx>>,
pub region_bound: &'tcx ty::Region,
pub builtin_bounds: BuiltinBounds,
auto_traits: Vec<DefId>,
pub projection_bounds: Vec<PolyExistentialProjection<'tcx>>,
}

impl<'tcx> TraitObject<'tcx> {
pub fn new(principal: Option<PolyExistentialTraitRef<'tcx>>, region_bound: &'tcx ty::Region,
builtin_bounds: BuiltinBounds, projection_bounds: Vec<PolyExistentialProjection<'tcx>>)
auto_traits: Vec<DefId>, projection_bounds: Vec<PolyExistentialProjection<'tcx>>)
-> Self {
TraitObject {
principal: principal,
region_bound: region_bound,
builtin_bounds: builtin_bounds,
auto_traits: auto_traits,
projection_bounds: projection_bounds,
}
}

pub fn principal(&self) -> Option<PolyExistentialTraitRef<'tcx>> {
self.principal
}

pub fn auto_traits<'a>(&'a self) -> impl Iterator<Item=DefId> + 'a {
self.auto_traits.iter().cloned()
}
}

/// A complete reference to a trait. These take numerous guises in syntax,
Expand Down Expand Up @@ -833,18 +837,22 @@ impl CLike for BuiltinBound {

impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
pub fn try_add_builtin_trait(self,
trait_def_id: DefId,
builtin_bounds: &mut EnumSet<BuiltinBound>)
id: DefId,
auto_traits: &mut Vec<DefId>)
-> bool
{
//! Checks whether `trait_ref` refers to one of the builtin
//! traits, like `Send`, and adds the corresponding
//! bound to the set `builtin_bounds` if so. Returns true if `trait_ref`
//! is a builtin trait.

match self.lang_items.to_builtin_kind(trait_def_id) {
Some(bound) => { builtin_bounds.insert(bound); true }
None => false
//! Checks whether `id` refers to one of the builtin
//! traits, like `Send`, and adds it to `auto_traits` if so.
//! Returns true if `idf` refers to a builtin trait.

if Some(id) == self.lang_items.send_trait() ||
Some(id) == self.lang_items.sized_trait() ||
Some(id) == self.lang_items.copy_trait() ||
Some(id) == self.lang_items.sync_trait() {
auto_traits.push(id);
true
} else {
false
}
}
}
Expand Down
4 changes: 3 additions & 1 deletion src/librustc/ty/util.rs
Expand Up @@ -535,7 +535,9 @@ impl<'a, 'gcx, 'tcx, H: Hasher> TypeVisitor<'tcx> for TypeIdHasher<'a, 'gcx, 'tc
if let Some(ref p) = data.principal() {
self.def_id(p.def_id());
}
self.hash(data.builtin_bounds);
for d in data.auto_traits() {
self.def_id(d);
}
}
TyTuple(tys) => {
self.hash(tys.len());
Expand Down
25 changes: 14 additions & 11 deletions src/librustc/ty/wf.rs
Expand Up @@ -298,7 +298,6 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> {
/// is WF. Returns false if `ty0` is an unresolved type variable,
/// in which case we are not able to simplify at all.
fn compute(&mut self, ty0: Ty<'tcx>) -> bool {
let tcx = self.infcx.tcx;
let mut subtys = ty0.walk();
while let Some(ty) = subtys.next() {
match ty.sty {
Expand Down Expand Up @@ -391,15 +390,12 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> {
let cause = self.cause(traits::MiscObligation);

let component_traits =
data.builtin_bounds.iter().flat_map(|bound| {
tcx.lang_items.from_builtin_kind(bound).ok()
})
.chain(data.principal().map(|ref p| p.def_id()));
data.auto_traits().chain(data.principal().map(|ref p| p.def_id()));
self.out.extend(
component_traits.map(|did| { traits::Obligation::new(
component_traits.map(|did| traits::Obligation::new(
cause.clone(),
ty::Predicate::ObjectSafe(did)
)})
))
);
}

Expand Down Expand Up @@ -493,7 +489,7 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> {
let implicit_bounds =
object_region_bounds(self.infcx.tcx,
data.principal().unwrap(),
data.builtin_bounds);
data.auto_traits());

let explicit_bound = data.region_bound;

Expand All @@ -512,18 +508,25 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> {
/// they declare `trait SomeTrait : 'static`, for example, then
/// `'static` would appear in the list. The hard work is done by
/// `ty::required_region_bounds`, see that for more information.
pub fn object_region_bounds<'a, 'gcx, 'tcx>(
pub fn object_region_bounds<'a, 'gcx, 'tcx, I>(
tcx: TyCtxt<'a, 'gcx, 'tcx>,
principal: ty::PolyExistentialTraitRef<'tcx>,
others: ty::BuiltinBounds)
others: I)
-> Vec<&'tcx ty::Region>
where I: Iterator<Item=DefId>
{
// Since we don't actually *know* the self type for an object,
// this "open(err)" serves as a kind of dummy standin -- basically
// a skolemized type.
let open_ty = tcx.mk_infer(ty::FreshTy(0));

let mut predicates = others.to_predicates(tcx, open_ty);
let mut predicates = others.map(|d| {
let trait_ref = ty::TraitRef {
def_id: d,
substs: tcx.mk_substs_trait(open_ty, &[])
};
trait_ref.to_predicate()
}).collect::<Vec<_>>();
predicates.push(principal.with_self_ty(tcx, open_ty).to_predicate());

tcx.required_region_bounds(open_ty, predicates)
Expand Down
26 changes: 16 additions & 10 deletions src/librustc/util/ppaux.rs
Expand Up @@ -349,13 +349,15 @@ impl<'tcx> fmt::Display for ty::TraitObject<'tcx> {
}).collect();

let tap = ty::Binder(TraitAndProjections(principal, projections));
in_binder(f, tcx, &ty::Binder(""), Some(tap))
})?;
in_binder(f, tcx, &ty::Binder(""), Some(tap))?;

// Builtin bounds.
for bound in &self.builtin_bounds {
write!(f, " + {:?}", bound)?;
}
// Builtin bounds.
for did in self.auto_traits() {
write!(f, " + {}", tcx.item_path_str(did))?;
}

Ok(())
})?;

// FIXME: It'd be nice to compute from context when this bound
// is implied, but that's non-trivial -- we'd perhaps have to
Expand Down Expand Up @@ -474,10 +476,14 @@ impl<'tcx> fmt::Debug for ty::TraitObject<'tcx> {
write!(f, "{}", region_str)?;
}

for bound in &self.builtin_bounds {
maybe_continue(f)?;
write!(f, "{:?}", bound)?;
}
ty::tls::with(|tcx| {
for did in self.auto_traits() {
maybe_continue(f)?;
write!(f, " + {}", tcx.item_path_str(did))?;
}

Ok(())
})?;

for projection_bound in &self.projection_bounds {
maybe_continue(f)?;
Expand Down

0 comments on commit 607af72

Please sign in to comment.