Renames TyTrait to TyDynamic.
DEPS_rustc_incremental := rustc syntax_pos serialize rustc_data_structures
DEPS_rustc_save_analysis := rustc log syntax syntax_pos serialize
DEPS_rustc_typeck := rustc syntax syntax_pos rustc_platform_intrinsics rustc_const_math \
- rustc_const_eval rustc_errors
+ rustc_const_eval rustc_errors rustc_data_structures
DEPS_rustdoc := rustc rustc_driver native:hoedown serialize getopts test \
rustc_lint rustc_const_eval syntax_pos rustc_data_structures
ty::TyRef(..) |
ty::TyFnDef(..) |
ty::TyFnPtr(_) |
- ty::TyTrait(..) |
+ ty::TyDynamic(..) |
ty::TyClosure(..) |
ty::TyNever |
ty::TyTuple(..) |
match ty.sty {
ty::TyBox(..) | ty::TyRef(..) => true,
ty::TyAdt(def, _) => def.is_fundamental(),
- ty::TyTrait(ref data) => {
+ ty::TyDynamic(ref data, ..) => {
data.principal().map_or(false, |p| tcx.has_attr(p.def_id(), "fundamental"))
}
_ => false
krate == Some(LOCAL_CRATE)
}
- ty::TyTrait(ref tt) => {
+ ty::TyDynamic(ref tt, ..) => {
tt.principal().map_or(false, |p| p.def_id().is_local())
}
ty::TyBox(..) | ty::TyRef(..) | ty::TyRawPtr(..) => Some(5),
ty::TyArray(..) | ty::TySlice(..) => Some(6),
ty::TyFnDef(..) | ty::TyFnPtr(..) => Some(7),
- ty::TyTrait(..) => Some(8),
+ ty::TyDynamic(..) => Some(8),
ty::TyClosure(..) => Some(9),
ty::TyTuple(..) => Some(10),
ty::TyProjection(..) => Some(11),
}
pub fn register_bound(&mut self,
- infcx: &InferCtxt<'a, 'gcx, 'tcx>,
- ty: Ty<'tcx>,
- def_id: DefId,
- cause: ObligationCause<'tcx>)
+ infcx: &InferCtxt<'a, 'gcx, 'tcx>,
+ ty: Ty<'tcx>,
+ def_id: DefId,
+ cause: ObligationCause<'tcx>)
{
let trait_ref = ty::TraitRef {
def_id: def_id,
/// conservative towards *no impl*, which is the opposite of the
/// `evaluate` methods).
pub fn type_known_to_meet_bound<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
- ty: Ty<'tcx>,
- def_id: DefId,
- span: Span)
- -> bool
+ ty: Ty<'tcx>,
+ def_id: DefId,
+ span: Span)
+-> bool
{
debug!("type_known_to_meet_bound(ty={:?}, bound={:?})",
ty,
debug!("confirm_object_candidate(object_ty={:?})",
object_ty);
let data = match object_ty.sty {
- ty::TyTrait(ref data) => data,
+ ty::TyDynamic(ref data, ..) => data,
_ => {
span_bug!(
obligation.cause.span,
object_ty)
}
};
- let env_predicates = data.projection_bounds.iter().map(|p| {
+ let env_predicates = data.projection_bounds().map(|p| {
p.with_self_ty(selcx.tcx(), object_ty).to_predicate()
}).collect();
let env_predicate = {
use std::marker::PhantomData;
use std::mem;
use std::rc::Rc;
-use std::iter;
use syntax::abi::Abi;
use hir;
use util::nodemap::FxHashMap;
// and applicable impls. There is a certain set of precedence rules here.
let def_id = obligation.predicate.def_id();
- match obligation.predicate.def_id() {
- _ if self.tcx().lang_items.copy_trait() == Some(def_id) => {
- debug!("obligation self ty is {:?}",
- obligation.predicate.0.self_ty());
-
- // User-defined copy impls are permitted, but only for
- // structs and enums.
- self.assemble_candidates_from_impls(obligation, &mut candidates)?;
-
- // For other types, we'll use the builtin rules.
- let copy_conditions = self.copy_conditions(obligation);
- self.assemble_builtin_bound_candidates(copy_conditions, &mut candidates)?;
- }
- _ if self.tcx().lang_items.sized_trait() == Some(def_id) => {
- // Sized is never implementable by end-users, it is
- // always automatically computed.
- let sized_conditions = self.sized_conditions(obligation);
- self.assemble_builtin_bound_candidates(sized_conditions,
- &mut candidates)?;
- }
-
- _ if self.tcx().lang_items.unsize_trait() == Some(def_id) => {
- self.assemble_candidates_for_unsizing(obligation, &mut candidates);
- }
-
- // For non-builtins and Send/Sync
- _ => {
- self.assemble_closure_candidates(obligation, &mut candidates)?;
- self.assemble_fn_pointer_candidates(obligation, &mut candidates)?;
- self.assemble_candidates_from_impls(obligation, &mut candidates)?;
- self.assemble_candidates_from_object_ty(obligation, &mut candidates);
- }
+ if self.tcx().lang_items.copy_trait() == Some(def_id) {
+ debug!("obligation self ty is {:?}",
+ obligation.predicate.0.self_ty());
+
+ // User-defined copy impls are permitted, but only for
+ // structs and enums.
+ self.assemble_candidates_from_impls(obligation, &mut candidates)?;
+
+ // For other types, we'll use the builtin rules.
+ let copy_conditions = self.copy_conditions(obligation);
+ self.assemble_builtin_bound_candidates(copy_conditions, &mut candidates)?;
+ } else if self.tcx().lang_items.sized_trait() == Some(def_id) {
+ // Sized is never implementable by end-users, it is
+ // always automatically computed.
+ let sized_conditions = self.sized_conditions(obligation);
+ self.assemble_builtin_bound_candidates(sized_conditions,
+ &mut candidates)?;
+ } else if self.tcx().lang_items.unsize_trait() == Some(def_id) {
+ self.assemble_candidates_for_unsizing(obligation, &mut candidates);
+ } else {
+ self.assemble_closure_candidates(obligation, &mut candidates)?;
+ self.assemble_fn_pointer_candidates(obligation, &mut candidates)?;
+ self.assemble_candidates_from_impls(obligation, &mut candidates)?;
+ self.assemble_candidates_from_object_ty(obligation, &mut candidates);
}
self.assemble_candidates_from_projected_tys(obligation, &mut candidates);
if self.tcx().trait_has_default_impl(def_id) {
match self_ty.sty {
- ty::TyTrait(..) => {
+ ty::TyDynamic(..) => {
// For object types, we don't know what the closed
// over types are. For most traits, this means we
// conservatively say nothing; a candidate may be
// any LBR.
let self_ty = this.tcx().erase_late_bound_regions(&obligation.self_ty());
let poly_trait_ref = match self_ty.sty {
- ty::TyTrait(ref data) => {
+ ty::TyDynamic(ref data, ..) => {
if data.auto_traits().any(|did| did == obligation.predicate.def_id()) {
debug!("assemble_candidates_from_object_ty: matched builtin bound, \
pushing candidate");
}
match data.principal() {
- Some(ref p) => p.with_self_ty(this.tcx(), self_ty),
+ Some(p) => p.with_self_ty(this.tcx(), self_ty),
None => return,
}
}
let may_apply = match (&source.sty, &target.sty) {
// Trait+Kx+'a -> Trait+Ky+'b (upcasts).
- (&ty::TyTrait(ref data_a), &ty::TyTrait(ref data_b)) => {
+ (&ty::TyDynamic(ref data_a, ..), &ty::TyDynamic(ref data_b, ..)) => {
// Upcasts permit two things:
//
// 1. Dropping builtin bounds, e.g. `Foo+Send` to `Foo`
// We always upcast when we can because of reason
// #2 (region bounds).
match (data_a.principal(), data_b.principal()) {
- (Some(ref a), Some(ref b)) => a.def_id() == b.def_id() &&
+ (Some(a), Some(b)) => a.def_id() == b.def_id() &&
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)),
}
// T -> Trait.
- (_, &ty::TyTrait(_)) => true,
+ (_, &ty::TyDynamic(..)) => true,
// Ambiguous handling is below T -> Trait, because inference
// variables can still implement Unsize<Trait> and nested
Where(ty::Binder(Vec::new()))
}
- ty::TyStr | ty::TySlice(_) | ty::TyTrait(..) => Never,
+ ty::TyStr | ty::TySlice(_) | ty::TyDynamic(..) => Never,
ty::TyTuple(tys) => {
Where(ty::Binder(tys.last().into_iter().cloned().collect()))
Where(ty::Binder(Vec::new()))
}
- ty::TyBox(_) | ty::TyTrait(..) | ty::TyStr | ty::TySlice(..) |
+ ty::TyBox(_) | ty::TyDynamic(..) | ty::TyStr | ty::TySlice(..) |
ty::TyClosure(..) |
ty::TyRef(_, ty::TypeAndMut { ty: _, mutbl: hir::MutMutable }) => {
Never
Vec::new()
}
- ty::TyTrait(..) |
+ ty::TyDynamic(..) |
ty::TyParam(..) |
ty::TyProjection(..) |
ty::TyAnon(..) |
// OK to skip binder, it is reintroduced below
let self_ty = self.infcx.shallow_resolve(obligation.predicate.skip_binder().self_ty());
match self_ty.sty {
- ty::TyTrait(ref data) => {
+ ty::TyDynamic(ref data, ..) => {
// OK to skip the binder, it is reintroduced below
let principal = data.principal().unwrap();
let input_types = principal.input_types();
- let assoc_types = data.projection_bounds.iter()
+ let assoc_types = data.projection_bounds()
.map(|pb| pb.skip_binder().ty);
let all_types: Vec<_> = input_types.chain(assoc_types)
.collect();
// case that results. -nmatsakis
let self_ty = self.infcx.shallow_resolve(*obligation.self_ty().skip_binder());
let poly_trait_ref = match self_ty.sty {
- ty::TyTrait(ref data) => {
+ ty::TyDynamic(ref data, ..) => {
data.principal().unwrap().with_self_ty(self.tcx(), self_ty)
}
_ => {
let mut nested = vec![];
match (&source.sty, &target.sty) {
// Trait+Kx+'a -> Trait+Ky+'b (upcasts).
- (&ty::TyTrait(ref data_a), &ty::TyTrait(ref data_b)) => {
+ (&ty::TyDynamic(ref data_a, r_a), &ty::TyDynamic(ref data_b, r_b)) => {
// See assemble_candidates_for_unsizing for more info.
- let new_trait = tcx.mk_trait(ty::TraitObject::new(
- data_a.principal(),
- data_b.region_bound,
- data_b.auto_traits().collect(),
- data_a.projection_bounds.clone(),
- ));
+ // Binders reintroduced below in call to mk_existential_predicates.
+ let principal = data_a.skip_binder().principal();
+ let iter = principal.into_iter().map(ty::ExistentialPredicate::Trait)
+ .chain(data_a.skip_binder().projection_bounds()
+ .map(|x| ty::ExistentialPredicate::Projection(x)))
+ .chain(data_b.auto_traits().map(ty::ExistentialPredicate::AutoTrait));
+ let new_trait = tcx.mk_dynamic(
+ ty::Binder(tcx.mk_existential_predicates(iter)), r_b);
let InferOk { obligations, .. } =
self.infcx.sub_types(false, &obligation.cause, new_trait, target)
.map_err(|_| Unimplemented)?;
let cause = ObligationCause::new(obligation.cause.span,
obligation.cause.body_id,
ObjectCastObligation(target));
- let outlives = ty::OutlivesPredicate(data_a.region_bound,
- data_b.region_bound);
+ let outlives = ty::OutlivesPredicate(r_a, r_b);
nested.push(Obligation::with_depth(cause,
obligation.recursion_depth + 1,
ty::Binder(outlives).to_predicate()));
}
// T -> Trait.
- (_, &ty::TyTrait(ref data)) => {
+ (_, &ty::TyDynamic(ref data, r)) => {
let mut object_dids =
- data.auto_traits().chain(data.principal().map(|ref p| p.def_id()));
+ data.auto_traits().chain(data.principal().map(|p| p.def_id()));
if let Some(did) = object_dids.find(|did| {
!tcx.is_object_safe(*did)
}) {
predicate));
};
- // Create the obligation for casting from T to Trait.
- push(data.principal().unwrap().with_self_ty(tcx, source).to_predicate());
-
- // We can only make objects from sized types.
- 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 tr in trait_refs {
- push(tr.to_predicate());
+ // Create obligations:
+ // - Casting T to Trait
+ // - 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.)
+ // - Projection predicates
+ for predicate in data.iter() {
+ push(predicate.with_self_ty(tcx, source));
}
- // Create obligations for the projection predicates.
- for bound in &data.projection_bounds {
- push(bound.with_self_ty(tcx, source).to_predicate());
- }
+ // We can only make objects from sized types.
+ let tr = ty::TraitRef {
+ def_id: tcx.lang_items.require(lang_items::SizedTraitLangItem)
+ .unwrap_or_else(|msg| tcx.sess.fatal(&msg[..])),
+ substs: tcx.mk_substs_trait(source, &[]),
+ };
+ push(tr.to_predicate());
// If the type is `Foo+'a`, ensures that the type
// being cast to `Foo+'a` outlives `'a`:
- let outlives = ty::OutlivesPredicate(source, data.region_bound);
+ let outlives = ty::OutlivesPredicate(source, r);
push(ty::Binder(outlives).to_predicate());
}
tc_ty(tcx, typ, cache).owned_pointer()
}
- ty::TyTrait(_) => {
+ ty::TyDynamic(..) => {
TC::All - TC::InteriorParam
}
use ty::{TyS, TypeVariants, Slice};
use ty::{AdtKind, AdtDef, ClosureSubsts, Region};
use hir::FreevarMap;
-use ty::{BareFnTy, InferTy, ParamTy, ProjectionTy, TraitObject};
+use ty::{BareFnTy, InferTy, ParamTy, ProjectionTy, ExistentialPredicate};
use ty::{TyVar, TyVid, IntVar, IntVid, FloatVar, FloatVid};
use ty::TypeVariants::*;
use ty::layout::{Layout, TargetDataLayout};
use std::ops::Deref;
use std::rc::Rc;
use std::iter;
+use std::cmp::Ordering;
use syntax::ast::{self, Name, NodeId};
use syntax::attr;
use syntax::symbol::{Symbol, keywords};
region: TypedArena<Region>,
stability: TypedArena<attr::Stability>,
layout: TypedArena<Layout>,
+ existential_predicates: TypedArena<ExistentialPredicate<'tcx>>,
// references
generics: TypedArena<ty::Generics<'tcx>>,
region: TypedArena::new(),
stability: TypedArena::new(),
layout: TypedArena::new(),
+ existential_predicates: TypedArena::new(),
generics: TypedArena::new(),
trait_def: TypedArena::new(),
region: RefCell<FxHashSet<Interned<'tcx, Region>>>,
stability: RefCell<FxHashSet<&'tcx attr::Stability>>,
layout: RefCell<FxHashSet<&'tcx Layout>>,
+ existential_predicates: RefCell<FxHashSet<Interned<'tcx, Slice<ExistentialPredicate<'tcx>>>>>,
}
impl<'gcx: 'tcx, 'tcx> CtxtInterners<'tcx> {
bare_fn: RefCell::new(FxHashSet()),
region: RefCell::new(FxHashSet()),
stability: RefCell::new(FxHashSet()),
- layout: RefCell::new(FxHashSet())
+ layout: RefCell::new(FxHashSet()),
+ existential_predicates: RefCell::new(FxHashSet()),
}
}
}
}
+impl<'a, 'tcx> Lift<'tcx> for &'a Slice<ExistentialPredicate<'a>> {
+ type Lifted = &'tcx Slice<ExistentialPredicate<'tcx>>;
+ fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>)
+ -> Option<&'tcx Slice<ExistentialPredicate<'tcx>>> {
+ if self.is_empty() {
+ return Some(Slice::empty());
+ }
+ if let Some(&Interned(eps)) = tcx.interners.existential_predicates.borrow().get(&self[..]) {
+ if *self as *const _ == eps as *const _ {
+ return Some(eps);
+ }
+ }
+ // Also try in the global tcx if we're not that.
+ if !tcx.is_global() {
+ self.lift_to_tcx(tcx.global_tcx())
+ } else {
+ None
+ }
+ }
+}
+
impl<'a, 'tcx> Lift<'tcx> for &'a BareFnTy<'a> {
type Lifted = &'tcx BareFnTy<'tcx>;
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>)
sty_debug_print!(
self,
TyAdt, TyBox, TyArray, TySlice, TyRawPtr, TyRef, TyFnDef, TyFnPtr,
- TyTrait, TyClosure, TyTuple, TyParam, TyInfer, TyProjection, TyAnon);
+ TyDynamic, TyClosure, TyTuple, TyParam, TyInfer, TyProjection, TyAnon);
println!("Substs interner: #{}", self.interners.substs.borrow().len());
println!("BareFnTy interner: #{}", self.interners.bare_fn.borrow().len());
}
}
+impl<'tcx: 'lcx, 'lcx> Borrow<[ExistentialPredicate<'lcx>]>
+ for Interned<'tcx, Slice<ExistentialPredicate<'tcx>>> {
+ fn borrow<'a>(&'a self) -> &'a [ExistentialPredicate<'lcx>] {
+ &self.0[..]
+ }
+}
+
macro_rules! intern_method {
($lt_tcx:tt, $name:ident: $method:ident($alloc:ty,
$alloc_method:ident,
}
slice_interners!(
+ existential_predicates: _intern_existential_predicates(ExistentialPredicate),
type_list: _intern_type_list(Ty),
substs: _intern_substs(Kind)
);
self.mk_ty(TyFnPtr(fty))
}
- pub fn mk_trait(self, mut obj: TraitObject<'tcx>) -> Ty<'tcx> {
- obj.projection_bounds.sort_by_key(|b| b.sort_key(self));
- self.mk_ty(TyTrait(box obj))
+ pub fn mk_dynamic(
+ self,
+ obj: ty::Binder<&'tcx Slice<ExistentialPredicate<'tcx>>>,
+ reg: &'tcx ty::Region
+ ) -> Ty<'tcx> {
+ self.mk_ty(TyDynamic(obj, reg))
}
pub fn mk_projection(self,
trait_ref: TraitRef<'tcx>,
item_name: Name)
- -> Ty<'tcx> {
- // take a copy of substs so that we own the vectors inside
- let inner = ProjectionTy { trait_ref: trait_ref, item_name: item_name };
- self.mk_ty(TyProjection(inner))
- }
+ -> Ty<'tcx> {
+ // take a copy of substs so that we own the vectors inside
+ let inner = ProjectionTy { trait_ref: trait_ref, item_name: item_name };
+ self.mk_ty(TyProjection(inner))
+ }
pub fn mk_closure(self,
closure_id: DefId,
substs: &'tcx Substs<'tcx>)
- -> Ty<'tcx> {
+ -> Ty<'tcx> {
self.mk_closure_from_closure_substs(closure_id, ClosureSubsts {
substs: substs
})
self.mk_ty(TyAnon(def_id, substs))
}
+ pub fn intern_existential_predicates(self, eps: &[ExistentialPredicate<'tcx>])
+ -> &'tcx Slice<ExistentialPredicate<'tcx>> {
+ assert!(!eps.is_empty());
+ assert!(eps.windows(2).all(|w| w[0].cmp(self, &w[1]) != Ordering::Greater));
+ self._intern_existential_predicates(eps)
+ }
+
pub fn intern_type_list(self, ts: &[Ty<'tcx>]) -> &'tcx Slice<Ty<'tcx>> {
if ts.len() == 0 {
Slice::empty()
}
}
+ pub fn mk_existential_predicates<I: InternAs<[ExistentialPredicate<'tcx>],
+ &'tcx Slice<ExistentialPredicate<'tcx>>>>(self, iter: I)
+ -> I::Output {
+ iter.intern_with(|xs| self.intern_existential_predicates(xs))
+ }
+
pub fn mk_type_list<I: InternAs<[Ty<'tcx>],
&'tcx Slice<Ty<'tcx>>>>(self, iter: I) -> I::Output {
iter.intern_with(|xs| self.intern_type_list(xs))
CyclicTy,
ProjectionNameMismatched(ExpectedFound<Name>),
ProjectionBoundsLength(ExpectedFound<usize>),
- TyParamDefaultMismatch(ExpectedFound<type_variable::Default<'tcx>>)
+ TyParamDefaultMismatch(ExpectedFound<type_variable::Default<'tcx>>),
+ ExistentialMismatch(ExpectedFound<&'tcx ty::Slice<ty::ExistentialPredicate<'tcx>>>),
}
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Debug, Copy)]
values.expected.ty,
values.found.ty)
}
+ ExistentialMismatch(ref values) => {
+ report_maybe_different(f, format!("trait `{}`", values.expected),
+ format!("trait `{}`", values.found))
+ }
}
}
}
}
ty::TyFnDef(..) => format!("fn item"),
ty::TyFnPtr(_) => "fn pointer".to_string(),
- ty::TyTrait(ref inner) => {
+ ty::TyDynamic(ref inner, ..) => {
inner.principal().map_or_else(|| "trait".to_string(),
|p| format!("trait {}", tcx.item_path_str(p.def_id())))
}
ty::TyStr => Some(StrSimplifiedType),
ty::TyArray(..) | ty::TySlice(_) => Some(ArraySimplifiedType),
ty::TyRawPtr(_) => Some(PtrSimplifiedType),
- ty::TyTrait(ref trait_info) => {
+ ty::TyDynamic(ref trait_info, ..) => {
trait_info.principal().map(|p| TraitSimplifiedType(p.def_id()))
}
ty::TyRef(_, mt) => {
self.add_substs(substs);
}
- &ty::TyTrait(ref obj) => {
+ &ty::TyDynamic(ref obj, r) => {
let mut computation = FlagComputation::new();
- computation.add_substs(obj.principal().unwrap().skip_binder().substs);
- for projection_bound in &obj.projection_bounds {
- let mut proj_computation = FlagComputation::new();
- proj_computation.add_existential_projection(&projection_bound.0);
- self.add_bound_computation(&proj_computation);
+ for predicate in obj.skip_binder().iter() {
+ match *predicate {
+ ty::ExistentialPredicate::Trait(tr) => computation.add_substs(tr.substs),
+ ty::ExistentialPredicate::Projection(p) => {
+ let mut proj_computation = FlagComputation::new();
+ proj_computation.add_existential_projection(&p);
+ self.add_bound_computation(&proj_computation);
+ }
+ ty::ExistentialPredicate::AutoTrait(_) => {}
+ }
}
self.add_bound_computation(&computation);
- self.add_region(obj.region_bound);
+ self.add_region(r);
}
&ty::TyBox(tt) | &ty::TyArray(tt, _) | &ty::TySlice(tt) => {
match ty.sty {
ty::TyAdt(adt_def, _) => Some(adt_def.did),
- ty::TyTrait(ref data) => data.principal().map(|ref p| p.def_id()),
+ ty::TyDynamic(data, ..) => data.principal().map(|p| p.def_id()),
ty::TyArray(subty, _) |
ty::TySlice(subty) |
ty::TySlice(_) | ty::TyStr => {
Int(dl.ptr_sized_integer())
}
- ty::TyTrait(_) => Pointer,
+ ty::TyDynamic(..) => Pointer,
_ => return Err(LayoutError::Unknown(unsized_part))
};
FatPointer { metadata: meta, non_zero: non_zero }
non_zero: false
}
}
- ty::TyTrait(_) => {
+ ty::TyDynamic(..) => {
let mut unit = Struct::new(dl, false);
unit.sized = false;
Univariant { variant: unit, non_zero: false }
pub use self::sty::{Binder, DebruijnIndex};
pub use self::sty::{BareFnTy, FnSig, PolyFnSig};
-pub use self::sty::{ClosureTy, InferTy, ParamTy, ProjectionTy, TraitObject};
+pub use self::sty::{ClosureTy, InferTy, ParamTy, ProjectionTy, ExistentialPredicate};
pub use self::sty::{ClosureSubsts, TypeAndMut};
pub use self::sty::{TraitRef, TypeVariants, PolyTraitRef};
pub use self::sty::{ExistentialTraitRef, PolyExistentialTraitRef};
vec![]
}
- TyStr | TyTrait(..) | TySlice(_) | TyError => {
+ TyStr | TyDynamic(..) | TySlice(_) | TyError => {
// these are never sized - return the target type
vec![ty]
}
ty::TyTuple(..) | // ...
ty::TyFnDef(..) | // OutlivesFunction (*)
ty::TyFnPtr(_) | // OutlivesFunction (*)
- ty::TyTrait(..) | // OutlivesObject, OutlivesFragment (*)
+ ty::TyDynamic(..) | // OutlivesObject, OutlivesFragment (*)
ty::TyError => {
// (*) Bare functions and traits are both binders. In the
// RFC, this means we would add the bound regions to the
Ok(tcx.mk_adt(a_def, substs))
}
- (&ty::TyTrait(ref a_obj), &ty::TyTrait(ref b_obj)) =>
- {
- let principal = match (a_obj.principal(), b_obj.principal()) {
- (Some(ref a_p), Some(ref b_p)) => Some(relation.relate(a_p, b_p)?),
- (None, None) => None,
- _ => return Err(TypeError::Sorts(expected_found(relation, &a, &b))),
- };
- let r =
- relation.with_cause(
- Cause::ExistentialRegionBound,
- |relation| relation.relate_with_variance(ty::Contravariant,
- &a_obj.region_bound,
- &b_obj.region_bound))?;
- 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)))
+ (&ty::TyDynamic(ref a_obj, ref a_region), &ty::TyDynamic(ref b_obj, ref b_region)) => {
+ let region_bound = relation.with_cause(Cause::ExistentialRegionBound,
+ |relation| {
+ relation.relate_with_variance(
+ ty::Contravariant,
+ a_region,
+ b_region)
+ })?;
+ Ok(tcx.mk_dynamic(relation.relate(a_obj, b_obj)?, region_bound))
}
(&ty::TyClosure(a_id, a_substs),
}
}
+impl<'tcx> Relate<'tcx> for &'tcx ty::Slice<ty::ExistentialPredicate<'tcx>> {
+ fn relate<'a, 'gcx, R>(relation: &mut R,
+ a: &Self,
+ b: &Self)
+ -> RelateResult<'tcx, Self>
+ where R: TypeRelation<'a, 'gcx, 'tcx>, 'gcx: 'a+'tcx, 'tcx: 'a {
+
+ if a.len() != b.len() {
+ return Err(TypeError::ExistentialMismatch(expected_found(relation, a, b)));
+ }
+
+ let tcx = relation.tcx();
+ let v = a.iter().zip(b.iter()).map(|(ep_a, ep_b)| {
+ use ty::ExistentialPredicate::*;
+ match (*ep_a, *ep_b) {
+ (Trait(ref a), Trait(ref b)) => Ok(Trait(relation.relate(a, b)?)),
+ (Projection(ref a), Projection(ref b)) => Ok(Projection(relation.relate(a, b)?)),
+ (AutoTrait(ref a), AutoTrait(ref b)) if a == b => Ok(AutoTrait(*a)),
+ _ => Err(TypeError::ExistentialMismatch(expected_found(relation, a, b)))
+ }
+ });
+ Ok(tcx.mk_existential_predicates(v)?)
+ }
+}
+
impl<'tcx> Relate<'tcx> for ty::ClosureSubsts<'tcx> {
fn relate<'a, 'gcx, R>(relation: &mut R,
a: &ty::ClosureSubsts<'tcx>,
TyParamDefaultMismatch(ref x) => {
return tcx.lift(x).map(TyParamDefaultMismatch)
}
+ ExistentialMismatch(ref x) => return tcx.lift(x).map(ExistentialMismatch)
})
}
}
}
}
-impl<'tcx> TypeFoldable<'tcx> for ty::TraitObject<'tcx> {
+impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::Slice<ty::ExistentialPredicate<'tcx>> {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
- ty::TraitObject::new(
- self.principal().map(|p| p.fold_with(folder)),
- self.region_bound.fold_with(folder),
- self.auto_traits().collect(),
- self.projection_bounds.fold_with(folder),
- )
+ let v = self.iter().map(|p| p.fold_with(folder)).collect::<AccumulateVec<[_; 8]>>();
+ folder.tcx().intern_existential_predicates(&v)
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
- self.principal().map(|p| p.visit_with(visitor)).unwrap_or(true) ||
- self.region_bound.visit_with(visitor) ||
- self.projection_bounds.visit_with(visitor)
+ self.iter().any(|p| p.visit_with(visitor))
+ }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for ty::ExistentialPredicate<'tcx> {
+ fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
+ use ty::ExistentialPredicate::*;
+ match *self {
+ Trait(ref tr) => Trait(tr.fold_with(folder)),
+ Projection(ref p) => Projection(p.fold_with(folder)),
+ AutoTrait(did) => AutoTrait(did),
+ }
+ }
+
+ fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+ match *self {
+ ty::ExistentialPredicate::Trait(ref tr) => tr.visit_with(visitor),
+ ty::ExistentialPredicate::Projection(ref p) => p.visit_with(visitor),
+ ty::ExistentialPredicate::AutoTrait(_) => false,
+ }
}
}
ty::TyArray(typ, sz) => ty::TyArray(typ.fold_with(folder), sz),
ty::TySlice(typ) => ty::TySlice(typ.fold_with(folder)),
ty::TyAdt(tid, substs) => ty::TyAdt(tid, substs.fold_with(folder)),
- ty::TyTrait(ref trait_ty) => ty::TyTrait(trait_ty.fold_with(folder)),
+ ty::TyDynamic(ref trait_ty, ref region) =>
+ ty::TyDynamic(trait_ty.fold_with(folder), region.fold_with(folder)),
ty::TyTuple(ts) => ty::TyTuple(ts.fold_with(folder)),
ty::TyFnDef(def_id, substs, f) => {
ty::TyFnDef(def_id,
ty::TyArray(typ, _sz) => typ.visit_with(visitor),
ty::TySlice(typ) => typ.visit_with(visitor),
ty::TyAdt(_, substs) => substs.visit_with(visitor),
- ty::TyTrait(ref trait_ty) => trait_ty.visit_with(visitor),
+ ty::TyDynamic(ref trait_ty, ref reg) =>
+ trait_ty.visit_with(visitor) || reg.visit_with(visitor),
ty::TyTuple(ts) => ts.visit_with(visitor),
ty::TyFnDef(_, substs, ref f) => {
substs.visit_with(visitor) || f.visit_with(visitor)
use ty::subst::Substs;
use ty::{self, AdtDef, TypeFlags, Ty, TyCtxt, TypeFoldable};
use ty::{Slice, TyS};
+use ty::subst::Kind;
use std::fmt;
+use std::iter;
+use std::cmp::Ordering;
use syntax::abi;
use syntax::ast::{self, Name, NodeId};
use syntax::symbol::{keywords, InternedString};
TyFnPtr(&'tcx BareFnTy<'tcx>),
/// A trait, defined with `trait`.
- TyTrait(Box<TraitObject<'tcx>>),
+ TyDynamic(Binder<&'tcx Slice<ExistentialPredicate<'tcx>>>, &'tcx ty::Region),
/// The anonymous type of a closure. Used to represent the type of
/// `|a| a`.
}
}
-#[derive(Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
-pub struct TraitObject<'tcx> {
- principal: Option<PolyExistentialTraitRef<'tcx>>,
- pub region_bound: &'tcx ty::Region,
- auto_traits: Vec<DefId>,
- pub projection_bounds: Vec<PolyExistentialProjection<'tcx>>,
+#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
+pub enum ExistentialPredicate<'tcx> {
+ // e.g. Iterator
+ Trait(ExistentialTraitRef<'tcx>),
+ // e.g. Iterator::Item = T
+ Projection(ExistentialProjection<'tcx>),
+ // e.g. Send
+ AutoTrait(DefId),
}
-impl<'tcx> TraitObject<'tcx> {
- pub fn new(principal: Option<PolyExistentialTraitRef<'tcx>>, region_bound: &'tcx ty::Region,
- auto_traits: Vec<DefId>, projection_bounds: Vec<PolyExistentialProjection<'tcx>>)
- -> Self {
- TraitObject {
- principal: principal,
- region_bound: region_bound,
- auto_traits: auto_traits,
- projection_bounds: projection_bounds,
+impl<'a, 'gcx, 'tcx> ExistentialPredicate<'tcx> {
+ pub fn cmp(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, other: &Self) -> Ordering {
+ use self::ExistentialPredicate::*;
+ match (*self, *other) {
+ (Trait(_), Trait(_)) => Ordering::Equal,
+ (Projection(ref a), Projection(ref b)) => a.sort_key(tcx).cmp(&b.sort_key(tcx)),
+ (AutoTrait(ref a), AutoTrait(ref b)) =>
+ tcx.lookup_trait_def(*a).def_path_hash.cmp(&tcx.lookup_trait_def(*b).def_path_hash),
+ (Trait(_), _) => Ordering::Less,
+ (Projection(_), Trait(_)) => Ordering::Greater,
+ (Projection(_), _) => Ordering::Less,
+ (AutoTrait(_), _) => Ordering::Greater,
+ }
+ }
+
+}
+
+impl<'a, 'gcx, 'tcx> Binder<ExistentialPredicate<'tcx>> {
+ pub fn with_self_ty(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, self_ty: Ty<'tcx>)
+ -> ty::Predicate<'tcx> {
+ use ty::ToPredicate;
+ match *self.skip_binder() {
+ ExistentialPredicate::Trait(tr) => Binder(tr).with_self_ty(tcx, self_ty).to_predicate(),
+ ExistentialPredicate::Projection(p) =>
+ ty::Predicate::Projection(Binder(p.with_self_ty(tcx, self_ty))),
+ ExistentialPredicate::AutoTrait(did) => {
+ let trait_ref = Binder(ty::TraitRef {
+ def_id: did,
+ substs: tcx.mk_substs_trait(self_ty, &[]),
+ });
+ trait_ref.to_predicate()
+ }
+ }
+ }
+}
+
+impl<'tcx> serialize::UseSpecializedDecodable for &'tcx Slice<ExistentialPredicate<'tcx>> {}
+
+impl<'tcx> Slice<ExistentialPredicate<'tcx>> {
+ pub fn principal(&self) -> Option<ExistentialTraitRef<'tcx>> {
+ match self.get(0) {
+ Some(&ExistentialPredicate::Trait(tr)) => Some(tr),
+ _ => None
}
}
+ #[inline]
+ pub fn projection_bounds<'a>(&'a self) ->
+ impl Iterator<Item=ExistentialProjection<'tcx>> + 'a {
+ self.iter().filter_map(|predicate| {
+ match *predicate {
+ ExistentialPredicate::Projection(p) => Some(p),
+ _ => None,
+ }
+ })
+ }
+
+ #[inline]
+ pub fn auto_traits<'a>(&'a self) -> impl Iterator<Item=DefId> + 'a {
+ self.iter().filter_map(|predicate| {
+ match *predicate {
+ ExistentialPredicate::AutoTrait(d) => Some(d),
+ _ => None
+ }
+ })
+ }
+}
+
+impl<'tcx> Binder<&'tcx Slice<ExistentialPredicate<'tcx>>> {
pub fn principal(&self) -> Option<PolyExistentialTraitRef<'tcx>> {
- self.principal
+ self.skip_binder().principal().map(Binder)
+ }
+
+ #[inline]
+ pub fn projection_bounds<'a>(&'a self) ->
+ impl Iterator<Item=PolyExistentialProjection<'tcx>> + 'a {
+ self.skip_binder().projection_bounds().map(Binder)
}
+ #[inline]
pub fn auto_traits<'a>(&'a self) -> impl Iterator<Item=DefId> + 'a {
- self.auto_traits.iter().cloned()
+ self.skip_binder().auto_traits()
+ }
+
+ pub fn iter<'a>(&'a self)
+ -> impl DoubleEndedIterator<Item=Binder<ExistentialPredicate<'tcx>>> + 'tcx {
+ self.skip_binder().iter().cloned().map(Binder)
}
}
pub substs: &'tcx Substs<'tcx>,
}
-impl<'tcx> ExistentialTraitRef<'tcx> {
- pub fn input_types<'a>(&'a self) -> impl DoubleEndedIterator<Item=Ty<'tcx>> + 'a {
+impl<'a, 'gcx, 'tcx> ExistentialTraitRef<'tcx> {
+ pub fn input_types<'b>(&'b self) -> impl DoubleEndedIterator<Item=Ty<'tcx>> + 'b {
// Select only the "input types" from a trait-reference. For
// now this is all the types that appear in the
// trait-reference, but it should eventually exclude
// associated types.
self.substs.types()
}
+
+ /// Object types don't have a self-type specified. Therefore, when
+ /// we convert the principal trait-ref into a normal trait-ref,
+ /// you must give *some* self-type. A common choice is `mk_err()`
+ /// or some skolemized type.
+ pub fn with_self_ty(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, self_ty: Ty<'tcx>)
+ -> ty::TraitRef<'tcx> {
+ // otherwise the escaping regions would be captured by the binder
+ assert!(!self_ty.has_escaping_regions());
+
+ ty::TraitRef {
+ def_id: self.def_id,
+ substs: tcx.mk_substs(
+ iter::once(Kind::from(self_ty)).chain(self.substs.iter().cloned()))
+ }
+ }
}
pub type PolyExistentialTraitRef<'tcx> = Binder<ExistentialTraitRef<'tcx>>;
pub type PolyExistentialProjection<'tcx> = Binder<ExistentialProjection<'tcx>>;
-impl<'a, 'tcx, 'gcx> PolyExistentialProjection<'tcx> {
+impl<'a, 'tcx, 'gcx> ExistentialProjection<'tcx> {
pub fn item_name(&self) -> Name {
- self.0.item_name // safe to skip the binder to access a name
+ self.item_name // safe to skip the binder to access a name
}
pub fn sort_key(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> (u64, InternedString) {
// We want something here that is stable across crate boundaries.
// The DefId isn't but the `deterministic_hash` of the corresponding
// DefPath is.
- let trait_def = tcx.lookup_trait_def(self.0.trait_ref.def_id);
+ let trait_def = tcx.lookup_trait_def(self.trait_ref.def_id);
let def_path_hash = trait_def.def_path_hash;
// An `ast::Name` is also not stable (it's just an index into an
// interning table), so map to the corresponding `InternedString`.
- let item_name = self.0.item_name.as_str();
+ let item_name = self.item_name.as_str();
(def_path_hash, item_name)
}
pub fn with_self_ty(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>,
self_ty: Ty<'tcx>)
- -> ty::PolyProjectionPredicate<'tcx>
+ -> ty::ProjectionPredicate<'tcx>
{
// otherwise the escaping regions would be captured by the binders
assert!(!self_ty.has_escaping_regions());
- let trait_ref = self.map_bound(|proj| proj.trait_ref);
- self.map_bound(|proj| ty::ProjectionPredicate {
+ ty::ProjectionPredicate {
projection_ty: ty::ProjectionTy {
- trait_ref: trait_ref.with_self_ty(tcx, self_ty).0,
- item_name: proj.item_name
+ trait_ref: self.trait_ref.with_self_ty(tcx, self_ty),
+ item_name: self.item_name
},
- ty: proj.ty
- })
+ ty: self.ty
+ }
}
}
-impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
- pub fn try_add_builtin_trait(self,
- id: DefId,
- auto_traits: &mut Vec<DefId>)
- -> bool
- {
- //! 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
- }
+impl<'a, 'tcx, 'gcx> PolyExistentialProjection<'tcx> {
+ pub fn item_name(&self) -> Name {
+ self.skip_binder().item_name()
+ }
+
+ pub fn sort_key(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> (u64, InternedString) {
+ self.skip_binder().sort_key(tcx)
+ }
+
+ pub fn with_self_ty(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, self_ty: Ty<'tcx>)
+ -> ty::PolyProjectionPredicate<'tcx> {
+ self.map_bound(|p| p.with_self_ty(tcx, self_ty))
}
}
pub fn is_trait(&self) -> bool {
match self.sty {
- TyTrait(..) => true,
+ TyDynamic(..) => true,
_ => false
}
}
pub fn ty_to_def_id(&self) -> Option<DefId> {
match self.sty {
- TyTrait(ref tt) => tt.principal().map(|p| p.def_id()),
+ TyDynamic(ref tt, ..) => tt.principal().map(|p| p.def_id()),
TyAdt(def, _) => Some(def.did),
TyClosure(id, _) => Some(id),
_ => None
TyRef(region, _) => {
vec![region]
}
- TyTrait(ref obj) => {
- let mut v = vec![obj.region_bound];
- v.extend(obj.principal().unwrap().skip_binder().substs.regions());
+ TyDynamic(ref obj, region) => {
+ let mut v = vec![region];
+ if let Some(p) = obj.principal() {
+ v.extend(p.skip_binder().substs.regions());
+ }
v
}
TyAdt(_, substs) | TyAnon(_, substs) => {
self.hash(f.sig.variadic());
self.hash(f.sig.inputs().skip_binder().len());
}
- TyTrait(ref data) => {
- if let Some(ref p) = data.principal() {
+ TyDynamic(ref data, ..) => {
+ if let Some(p) = data.principal() {
self.def_id(p.def_id());
}
for d in data.auto_traits() {
mutbl: hir::MutMutable, ..
}) => Some(true),
- TyArray(..) | TySlice(..) | TyTrait(..) | TyTuple(..) |
+ TyArray(..) | TySlice(..) | TyDynamic(..) | TyTuple(..) |
TyClosure(..) | TyAdt(..) | TyAnon(..) |
TyProjection(..) | TyParam(..) | TyInfer(..) | TyError => None
}.unwrap_or_else(|| {
TyBox(..) | TyRawPtr(..) | TyRef(..) | TyFnDef(..) | TyFnPtr(_) |
TyArray(..) | TyTuple(..) | TyClosure(..) | TyNever => Some(true),
- TyStr | TyTrait(..) | TySlice(_) => Some(false),
+ TyStr | TyDynamic(..) | TySlice(_) => Some(false),
TyAdt(..) | TyProjection(..) | TyParam(..) |
TyInfer(..) | TyAnon(..) | TyError => None
ty::TyProjection(ref data) => {
stack.extend(data.trait_ref.substs.types().rev());
}
- ty::TyTrait(ref obj) => {
- match obj.principal() {
- Some(ref p) => stack.extend(p.input_types().rev()),
- None => {}
- }
- stack.extend(obj.projection_bounds.iter().map(|pred| {
- pred.0.ty
- }).rev());
+ ty::TyDynamic(ref obj, ..) => {
+ stack.extend(obj.iter().rev().flat_map(|predicate| {
+ let (substs, opt_ty) = match *predicate.skip_binder() {
+ ty::ExistentialPredicate::Trait(tr) => (tr.substs, None),
+ ty::ExistentialPredicate::Projection(p) =>
+ (p.trait_ref.substs, Some(p.ty)),
+ ty::ExistentialPredicate::AutoTrait(_) =>
+ // Empty iterator
+ (ty::Substs::empty(), None),
+ };
+
+ substs.types().rev().chain(opt_ty)
+ }));
}
ty::TyAdt(_, substs) | ty::TyAnon(_, substs) => {
stack.extend(substs.types().rev());
// of whatever returned this exact `impl Trait`.
}
- ty::TyTrait(ref data) => {
+ ty::TyDynamic(data, r) => {
// WfObject
//
// Here, we defer WF checking due to higher-ranked
// regions. This is perhaps not ideal.
- self.from_object_ty(ty, data);
+ self.from_object_ty(ty, data, r);
// FIXME(#27579) RFC also considers adding trait
// obligations that don't refer to Self and
let cause = self.cause(traits::MiscObligation);
let component_traits =
- data.auto_traits().chain(data.principal().map(|ref p| p.def_id()));
+ data.auto_traits().chain(data.principal().map(|p| p.def_id()));
self.out.extend(
component_traits.map(|did| traits::Obligation::new(
cause.clone(),
.collect()
}
- fn from_object_ty(&mut self, ty: Ty<'tcx>, data: &ty::TraitObject<'tcx>) {
+ fn from_object_ty(&mut self, ty: Ty<'tcx>,
+ data: ty::Binder<&'tcx ty::Slice<ty::ExistentialPredicate<'tcx>>>,
+ region: &'tcx ty::Region) {
// Imagine a type like this:
//
// trait Foo { }
if !data.has_escaping_regions() {
let implicit_bounds =
- object_region_bounds(self.infcx.tcx,
- data.principal().unwrap(),
- data.auto_traits());
+ object_region_bounds(self.infcx.tcx, data);
- let explicit_bound = data.region_bound;
+ let explicit_bound = region;
for implicit_bound in implicit_bounds {
let cause = self.cause(traits::ObjectTypeBound(ty, explicit_bound));
/// 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, I>(
+pub fn object_region_bounds<'a, 'gcx, 'tcx>(
tcx: TyCtxt<'a, 'gcx, 'tcx>,
- principal: ty::PolyExistentialTraitRef<'tcx>,
- others: I)
+ existential_predicates: ty::Binder<&'tcx ty::Slice<ty::ExistentialPredicate<'tcx>>>)
-> 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.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());
+ let predicates = existential_predicates.iter().filter_map(|predicate| {
+ if let ty::ExistentialPredicate::Projection(_) = *predicate.skip_binder() {
+ None
+ } else {
+ Some(predicate.with_self_ty(tcx, open_ty))
+ }
+ }).collect();
tcx.required_region_bounds(open_ty, predicates)
}
use ty::{TyError, TyStr, TyArray, TySlice, TyFloat, TyFnDef, TyFnPtr};
use ty::{TyParam, TyRawPtr, TyRef, TyNever, TyTuple};
use ty::{TyClosure, TyProjection, TyAnon};
-use ty::{TyBox, TyTrait, TyInt, TyUint, TyInfer};
+use ty::{TyBox, TyDynamic, TyInt, TyUint, TyInfer};
use ty::{self, Ty, TyCtxt, TypeFoldable};
-use ty::fold::{TypeFolder, TypeVisitor};
use std::cell::Cell;
use std::fmt;
write!(f, "{}", new_value)
}
-/// This curious type is here to help pretty-print trait objects. In
-/// a trait object, the projections are stored separately from the
-/// main trait bound, but in fact we want to package them together
-/// when printing out; they also have separate binders, but we want
-/// them to share a binder when we print them out. (And the binder
-/// pretty-printing logic is kind of clever and we don't want to
-/// reproduce it.) So we just repackage up the structure somewhat.
-///
-/// Right now there is only one trait in an object that can have
-/// projection bounds, so we just stuff them altogether. But in
-/// reality we should eventually sort things out better.
-#[derive(Clone, Debug)]
-struct TraitAndProjections<'tcx>(ty::TraitRef<'tcx>,
- Vec<ty::ProjectionPredicate<'tcx>>);
-
-impl<'tcx> TypeFoldable<'tcx> for TraitAndProjections<'tcx> {
- fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
- TraitAndProjections(self.0.fold_with(folder), self.1.fold_with(folder))
- }
-
- fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
- self.0.visit_with(visitor) || self.1.visit_with(visitor)
- }
-}
-
-impl<'tcx> fmt::Display for TraitAndProjections<'tcx> {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- let TraitAndProjections(ref trait_ref, ref projection_bounds) = *self;
- parameterized(f, trait_ref.substs,
- trait_ref.def_id,
- projection_bounds)
- }
-}
-
-impl<'tcx> fmt::Display for ty::TraitObject<'tcx> {
+impl<'tcx> fmt::Display for &'tcx ty::Slice<ty::ExistentialPredicate<'tcx>> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
// Generate the main trait ref, including associated types.
ty::tls::with(|tcx| {
// Use a type that can't appear in defaults of type parameters.
let dummy_self = tcx.mk_infer(ty::FreshTy(0));
- let principal = self.principal().and_then(|ref p| tcx.lift(p))
- .expect("could not lift TraitRef for printing")
- .with_self_ty(tcx, dummy_self).0;
- let projections = self.projection_bounds.iter().map(|p| {
- tcx.lift(p)
- .expect("could not lift projection for printing")
- .with_self_ty(tcx, dummy_self).0
- }).collect();
-
- let tap = ty::Binder(TraitAndProjections(principal, projections));
- in_binder(f, tcx, &ty::Binder(""), Some(tap))?;
+ if let Some(p) = self.principal() {
+ let principal = tcx.lift(&p).expect("could not lift TraitRef for printing")
+ .with_self_ty(tcx, dummy_self);
+ let projections = self.projection_bounds().map(|p| {
+ tcx.lift(&p)
+ .expect("could not lift projection for printing")
+ .with_self_ty(tcx, dummy_self)
+ }).collect::<Vec<_>>();
+ parameterized(f, principal.substs, principal.def_id, &projections)?;
+ }
// Builtin bounds.
for did in self.auto_traits() {
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
- // use thread-local data of some kind? There are also
- // advantages to just showing the region, since it makes
- // people aware that it's there.
- let bound = self.region_bound.to_string();
- if !bound.is_empty() {
- write!(f, " + {}", bound)?;
- }
-
Ok(())
}
}
}
}
-impl<'tcx> fmt::Debug for ty::TraitObject<'tcx> {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- let mut empty = true;
- let mut maybe_continue = |f: &mut fmt::Formatter| {
- if empty {
- empty = false;
- Ok(())
- } else {
- write!(f, " + ")
- }
- };
-
- maybe_continue(f)?;
- write!(f, "{:?}", self.principal())?;
-
- let region_str = format!("{:?}", self.region_bound);
- if !region_str.is_empty() {
- maybe_continue(f)?;
- write!(f, "{}", region_str)?;
- }
-
- 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)?;
- write!(f, "{:?}", projection_bound)?;
- }
-
- Ok(())
- }
-}
-
impl<'tcx> fmt::Debug for ty::Predicate<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
}
}*/
+impl<'tcx> fmt::Display for ty::Binder<&'tcx ty::Slice<ty::ExistentialPredicate<'tcx>>> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ ty::tls::with(|tcx| in_binder(f, tcx, self, tcx.lift(self)))
+ }
+}
+
impl<'tcx> fmt::Display for ty::Binder<ty::TraitRef<'tcx>> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
ty::tls::with(|tcx| in_binder(f, tcx, self, tcx.lift(self)))
}
})
}
- TyTrait(ref data) => write!(f, "{}", data),
+ TyDynamic(data, r) => {
+ write!(f, "{}", data)?;
+ let r = r.to_string();
+ if !r.is_empty() {
+ write!(f, " + {}", r)
+ } else {
+ Ok(())
+ }
+ }
TyProjection(ref data) => write!(f, "{}", data),
TyAnon(def_id, substs) => {
ty::tls::with(|tcx| {
consider using a raw pointer instead")
}
- ty::TyTrait(..) => {
+ ty::TyDynamic(..) => {
FfiUnsafe("found Rust trait type in foreign module, \
consider using a raw pointer instead")
}
}
}
+impl<'a, 'tcx> SpecializedDecoder<&'tcx ty::Slice<ty::ExistentialPredicate<'tcx>>>
+ for DecodeContext<'a, 'tcx> {
+ fn specialized_decode(&mut self)
+ -> Result<&'tcx ty::Slice<ty::ExistentialPredicate<'tcx>>, Self::Error> {
+ Ok(self.tcx().mk_existential_predicates((0..self.read_usize()?)
+ .map(|_| Decodable::decode(self)))?)
+ }
+}
+
impl<'a, 'tcx> MetadataBlob {
pub fn is_compatible(&self) -> bool {
self.raw_bytes().starts_with(METADATA_HEADER)
let (source, target) = ccx.tcx().struct_lockstep_tails(source, target);
match (&source.sty, &target.sty) {
(&ty::TyArray(_, len), &ty::TySlice(_)) => C_uint(ccx, len),
- (&ty::TyTrait(_), &ty::TyTrait(_)) => {
+ (&ty::TyDynamic(..), &ty::TyDynamic(..)) => {
// For now, upcasts are limited to changes in marker
// traits, and hence never actually require an actual
// change to the vtable.
old_info.expect("unsized_info: missing old info for trait upcast")
}
- (_, &ty::TyTrait(ref data)) => {
- let trait_ref = data.principal().unwrap().with_self_ty(ccx.tcx(), source);
- let trait_ref = ccx.tcx().erase_regions(&trait_ref);
- consts::ptrcast(meth::get_vtable(ccx, trait_ref),
+ (_, &ty::TyDynamic(ref data, ..)) => {
+ consts::ptrcast(meth::get_vtable(ccx, source, data.principal()),
Type::vtable_ptr(ccx))
}
_ => bug!("unsized_info: invalid unsizing {:?} -> {:?}",
ty::TyFnDef(..) |
ty::TyFnPtr(_) |
ty::TyNever |
- ty::TyTrait(_) => {
+ ty::TyDynamic(..) => {
/* nothing to do */
}
ty::TyAdt(adt_def, substs) => {
output: &mut Vec<TransItem<'tcx>>) {
assert!(!trait_ty.needs_subst() && !impl_ty.needs_subst());
- if let ty::TyTrait(ref trait_ty) = trait_ty.sty {
- let poly_trait_ref = trait_ty.principal().unwrap().with_self_ty(scx.tcx(), impl_ty);
- let param_substs = scx.tcx().intern_substs(&[]);
-
- // Walk all methods of the trait, including those of its supertraits
- let methods = traits::get_vtable_methods(scx.tcx(), poly_trait_ref);
- let methods = methods.filter_map(|method| method)
- .filter_map(|(def_id, substs)| do_static_dispatch(scx, def_id, substs, param_substs))
- .filter(|&(def_id, _)| can_have_local_instance(scx.tcx(), def_id))
- .map(|(def_id, substs)| create_fn_trans_item(scx, def_id, substs, param_substs));
- output.extend(methods);
-
+ if let ty::TyDynamic(ref trait_ty, ..) = trait_ty.sty {
+ if let Some(principal) = trait_ty.principal() {
+ let poly_trait_ref = principal.with_self_ty(scx.tcx(), impl_ty);
+ let param_substs = scx.tcx().intern_substs(&[]);
+
+ // Walk all methods of the trait, including those of its supertraits
+ let methods = traits::get_vtable_methods(scx.tcx(), poly_trait_ref);
+ let methods = methods.filter_map(|method| method)
+ .filter_map(|(def_id, substs)| do_static_dispatch(scx, def_id, substs,
+ param_substs))
+ .filter(|&(def_id, _)| can_have_local_instance(scx.tcx(), def_id))
+ .map(|(def_id, substs)| create_fn_trans_item(scx, def_id, substs, param_substs));
+ output.extend(methods);
+ }
// Also add the destructor
let dg_type = glue::get_drop_glue_type(scx.tcx(), impl_ty);
output.push(TransItem::DropGlue(DropGlueKind::Ty(dg_type)));
/// Cache instances of monomorphic and polymorphic items
instances: RefCell<FxHashMap<Instance<'tcx>, ValueRef>>,
/// Cache generated vtables
- vtables: RefCell<FxHashMap<ty::PolyTraitRef<'tcx>, ValueRef>>,
+ vtables: RefCell<FxHashMap<(ty::Ty<'tcx>,
+ Option<ty::PolyExistentialTraitRef<'tcx>>), ValueRef>>,
/// Cache of constant strings,
const_cstr_cache: RefCell<FxHashMap<InternedString, ValueRef>>,
&self.local().instances
}
- pub fn vtables<'a>(&'a self) -> &'a RefCell<FxHashMap<ty::PolyTraitRef<'tcx>, ValueRef>> {
+ pub fn vtables<'a>(&'a self)
+ -> &'a RefCell<FxHashMap<(ty::Ty<'tcx>,
+ Option<ty::PolyExistentialTraitRef<'tcx>>), ValueRef>> {
&self.local().vtables
}
// But it does not describe the trait's methods.
let containing_scope = match trait_type.sty {
- ty::TyTrait(ref data) => if let Some(principal) = data.principal() {
+ ty::TyDynamic(ref data, ..) => if let Some(principal) = data.principal() {
let def_id = principal.def_id();
get_namespace_and_span_for_item(cx, def_id).0
} else {
ty::TyStr => {
fixed_vec_metadata(cx, unique_type_id, cx.tcx().types.i8, None, usage_site_span)
}
- ty::TyTrait(..) => {
+ ty::TyDynamic(..) => {
MetadataCreationResult::new(
trait_pointer_metadata(cx, t, None, unique_type_id),
false)
ty::TyStr => {
vec_slice_metadata(cx, t, cx.tcx().types.u8, unique_type_id, usage_site_span)
}
- ty::TyTrait(..) => {
+ ty::TyDynamic(..) => {
MetadataCreationResult::new(
trait_pointer_metadata(cx, ty, Some(t), unique_type_id),
false)
push_debuginfo_type_name(cx, inner_type, true, output);
output.push(']');
},
- ty::TyTrait(ref trait_data) => {
+ ty::TyDynamic(ref trait_data, ..) => {
if let Some(principal) = trait_data.principal() {
let principal = cx.tcx().erase_late_bound_regions_and_normalize(
&principal);
(size, align)
}
- ty::TyTrait(..) => {
+ ty::TyDynamic(..) => {
// info points to the vtable and the second entry in the vtable is the
// dynamic size of the object.
let info = bcx.pointercast(info, Type::int(bcx.ccx()).ptr_to());
trans_exchange_free_ty(bcx, llbox, content_ty, DebugLoc::None)
}
}
- ty::TyTrait(..) => {
+ ty::TyDynamic(..) => {
// No support in vtable for distinguishing destroying with
// versus without calling Drop::drop. Assert caller is
// okay with always calling the Drop impl, if any.
/// making an object `Foo<Trait>` from a value of type `Foo<T>`, then
/// `trait_ref` would map `T:Trait`.
pub fn get_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
- trait_ref: ty::PolyTraitRef<'tcx>)
+ ty: ty::Ty<'tcx>,
+ trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>)
-> ValueRef
{
let tcx = ccx.tcx();
let _icx = push_ctxt("meth::get_vtable");
- debug!("get_vtable(trait_ref={:?})", trait_ref);
+ debug!("get_vtable(ty={:?}, trait_ref={:?})", ty, trait_ref);
// Check the cache.
- if let Some(&val) = ccx.vtables().borrow().get(&trait_ref) {
+ if let Some(&val) = ccx.vtables().borrow().get(&(ty, trait_ref)) {
return val;
}
// Not in the cache. Build it.
let nullptr = C_null(Type::nil(ccx).ptr_to());
- let methods = traits::get_vtable_methods(tcx, trait_ref).map(|opt_mth| {
- opt_mth.map_or(nullptr, |(def_id, substs)| {
- Callee::def(ccx, def_id, substs).reify(ccx)
- })
- });
- let size_ty = sizing_type_of(ccx, trait_ref.self_ty());
+ let size_ty = sizing_type_of(ccx, ty);
let size = machine::llsize_of_alloc(ccx, size_ty);
- let align = align_of(ccx, trait_ref.self_ty());
+ let align = align_of(ccx, ty);
- let components: Vec<_> = [
+ let mut components: Vec<_> = [
// Generate a destructor for the vtable.
- glue::get_drop_glue(ccx, trait_ref.self_ty()),
+ glue::get_drop_glue(ccx, ty),
C_uint(ccx, size),
C_uint(ccx, align)
- ].iter().cloned().chain(methods).collect();
+ ].iter().cloned().collect();
+
+ if let Some(trait_ref) = trait_ref {
+ let trait_ref = trait_ref.with_self_ty(tcx, ty);
+ let methods = traits::get_vtable_methods(tcx, trait_ref).map(|opt_mth| {
+ opt_mth.map_or(nullptr, |(def_id, substs)| {
+ Callee::def(ccx, def_id, substs).reify(ccx)
+ })
+ });
+ components.extend(methods);
+ }
let vtable_const = C_struct(ccx, &components, false);
let align = machine::llalign_of_pref(ccx, val_ty(vtable_const));
let vtable = consts::addr_of(ccx, vtable_const, align, "vtable");
- ccx.vtables().borrow_mut().insert(trait_ref, vtable);
+ ccx.vtables().borrow_mut().insert((ty, trait_ref), vtable);
vtable
}
self.push_type_name(inner_type, output);
output.push(']');
},
- ty::TyTrait(ref trait_data) => {
+ ty::TyDynamic(ref trait_data, ..) => {
if let Some(principal) = trait_data.principal() {
self.push_def_path(principal.def_id(), output);
self.push_type_params(principal.skip_binder().substs,
- &trait_data.projection_bounds,
+ &trait_data.projection_bounds().collect::<Vec<_>>()[..],
output);
}
},
ty::TyAnon(..) | ty::TyError => {
bug!("fictitious type {:?} in sizing_type_of()", t)
}
- ty::TySlice(_) | ty::TyTrait(..) | ty::TyStr => bug!()
+ ty::TySlice(_) | ty::TyDynamic(..) | ty::TyStr => bug!()
};
debug!("--> mapped t={:?} to llsizingty={:?}", t, llsizingty);
ty::TyStr | ty::TyArray(..) | ty::TySlice(_) => {
Type::uint_from_ty(ccx, ast::UintTy::Us)
}
- ty::TyTrait(_) => Type::vtable_ptr(ccx),
+ ty::TyDynamic(..) => Type::vtable_ptr(ccx),
_ => bug!("Unexpected tail in unsized_info_ty: {:?} for ty={:?}",
unsized_part, ty)
}
// fat pointers is of the right type (e.g. for array accesses), even
// when taking the address of an unsized field in a struct.
ty::TySlice(ty) => in_memory_type_of(cx, ty),
- ty::TyStr | ty::TyTrait(..) => Type::i8(cx),
+ ty::TyStr | ty::TyDynamic(..) => Type::i8(cx),
ty::TyFnDef(..) => Type::nil(cx),
ty::TyFnPtr(f) => {
//! an rptr (`&r.T`) use the region `r` that appears in the rptr.
use rustc_const_eval::eval_length;
+use rustc_data_structures::accumulate_vec::AccumulateVec;
use hir::{self, SelfKind};
use hir::def::Def;
use hir::def_id::DefId;
use util::nodemap::{NodeMap, FxHashSet};
use std::cell::RefCell;
+use std::iter;
use syntax::{abi, ast};
use syntax::feature_gate::{GateIssue, emit_feature_err};
use syntax::symbol::{Symbol, keywords};
let b = &trait_bounds[0];
let span = b.trait_ref.path.span;
struct_span_err!(self.tcx().sess, span, E0225,
- "only the builtin traits can be used as closure or object bounds")
- .span_label(span, &format!("non-builtin trait used as bounds"))
+ "only Send/Sync traits can be used as additional traits in a trait object")
+ .span_label(span, &format!("non-Send/Sync additional trait"))
.emit();
}
ty: b.ty
}
})
- }).collect();
-
- let region_bound =
- self.compute_object_lifetime_bound(span,
- ®ion_bounds,
- existential_principal,
- &auto_traits);
-
- let region_bound = match region_bound {
- Some(r) => r,
- None => {
- tcx.mk_region(match rscope.object_lifetime_default(span) {
- Some(r) => r,
- None => {
- span_err!(self.tcx().sess, span, E0228,
- "the lifetime bound for this object type cannot be deduced \
- from context; please supply an explicit bound");
- ty::ReStatic
- }
- })
- }
- };
-
- debug!("region_bound: {:?}", region_bound);
+ });
// ensure the super predicates and stop if we encountered an error
if self.ensure_super_predicates(span, principal.def_id()).is_err() {
.emit();
}
- let ty = tcx.mk_trait(ty::TraitObject::new(
- Some(existential_principal),
- region_bound,
- auto_traits,
- existential_projections
- ));
+ let mut v =
+ iter::once(ty::ExistentialPredicate::Trait(*existential_principal.skip_binder()))
+ .chain(auto_traits.into_iter().map(ty::ExistentialPredicate::AutoTrait))
+ .chain(existential_projections
+ .map(|x| ty::ExistentialPredicate::Projection(*x.skip_binder())))
+ .collect::<AccumulateVec<[_; 8]>>();
+ v.sort_by(|a, b| a.cmp(tcx, b));
+ let existential_predicates = ty::Binder(tcx.mk_existential_predicates(v.into_iter()));
+
+ let region_bound = self.compute_object_lifetime_bound(span,
+ ®ion_bounds,
+ existential_predicates);
+
+ let region_bound = match region_bound {
+ Some(r) => r,
+ None => {
+ tcx.mk_region(match rscope.object_lifetime_default(span) {
+ Some(r) => r,
+ None => {
+ span_err!(self.tcx().sess, span, E0228,
+ "the lifetime bound for this object type cannot be deduced \
+ from context; please supply an explicit bound");
+ ty::ReStatic
+ }
+ })
+ }
+ };
+
+ debug!("region_bound: {:?}", region_bound);
+
+ let ty = tcx.mk_dynamic(existential_predicates, region_bound);
debug!("trait_object_type: {:?}", ty);
ty
}
fn compute_object_lifetime_bound(&self,
span: Span,
explicit_region_bounds: &[&hir::Lifetime],
- principal_trait_ref: ty::PolyExistentialTraitRef<'tcx>,
- auto_traits: &[DefId])
+ existential_predicates: ty::Binder<&'tcx ty::Slice<ty::ExistentialPredicate<'tcx>>>)
-> Option<&'tcx ty::Region> // if None, use the default
{
let tcx = self.tcx();
debug!("compute_opt_region_bound(explicit_region_bounds={:?}, \
- principal_trait_ref={:?}, auto_traits={:?})",
+ existential_predicates={:?})",
explicit_region_bounds,
- principal_trait_ref,
- auto_traits);
+ existential_predicates);
if explicit_region_bounds.len() > 1 {
span_err!(tcx.sess, explicit_region_bounds[1].span, E0226,
"only a single explicit lifetime bound is permitted");
}
- if !explicit_region_bounds.is_empty() {
+ if let Some(&r) = explicit_region_bounds.get(0) {
// Explicitly specified region bound. Use that.
- let r = explicit_region_bounds[0];
return Some(ast_region_to_region(tcx, r));
}
- if let Err(ErrorReported) =
- self.ensure_super_predicates(span, principal_trait_ref.def_id()) {
- return Some(tcx.mk_region(ty::ReStatic));
+ if let Some(principal) = existential_predicates.principal() {
+ if let Err(ErrorReported) = self.ensure_super_predicates(span, principal.def_id()) {
+ return Some(tcx.mk_region(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 =
- object_region_bounds(tcx, principal_trait_ref, auto_traits.into_iter().cloned());
+ object_region_bounds(tcx, existential_predicates);
// If there are no derived region bounds, then report back that we
// can find no region bound. The caller will use the default.
hir::TraitTyParamBound(ref b, hir::TraitBoundModifier::None) => {
match b.trait_ref.path.def {
Def::Trait(trait_did) => {
- if tcx.try_add_builtin_trait(trait_did, &mut auto_traits) {
+ // Checks whether `trait_did` refers to one of the builtin
+ // traits, like `Send`, and adds it to `auto_traits` if so.
+ if Some(trait_did) == tcx.lang_items.send_trait() ||
+ Some(trait_did) == tcx.lang_items.sync_trait() {
+ auto_traits.push(trait_did);
let segments = &b.trait_ref.path.segments;
let parameters = &segments[segments.len() - 1].parameters;
if !parameters.types().is_empty() {
{
let mut vec = Vec::new();
- for trait_did in &self.auto_traits {
- let trait_ref = ty::TraitRef {
- def_id: *trait_did,
- substs: tcx.mk_substs_trait(param_ty, &[]),
- };
- vec.push(trait_ref.to_predicate());
+ // If it could be sized, and is, add the sized predicate
+ if self.implicitly_sized {
+ if let Some(sized) = tcx.lang_items.sized_trait() {
+ let trait_ref = ty::TraitRef {
+ def_id: sized,
+ substs: tcx.mk_substs_trait(param_ty, &[])
+ };
+ vec.push(trait_ref.to_predicate());
+ }
}
for ®ion_bound in &self.region_bounds {
pub fn check_dereferencable(&self, span: Span, expected: Ty<'tcx>, inner: &hir::Pat) -> bool {
if let PatKind::Binding(..) = inner.node {
if let Some(mt) = self.shallow_resolve(expected).builtin_deref(true, ty::NoPreference) {
- if let ty::TyTrait(..) = mt.ty.sty {
+ if let ty::TyDynamic(..) = mt.ty.sty {
// This is "x = SomeTrait" being reduced from
// "let &x = &SomeTrait" or "let box x = Box<SomeTrait>", an error.
let type_str = self.ty_to_string(expected);
/// fat pointers if their unsize-infos have the same kind.
#[derive(Copy, Clone, PartialEq, Eq)]
enum UnsizeKind<'tcx> {
- Vtable(DefId),
+ Vtable(Option<DefId>),
Length,
/// The unsize info of this projection
OfProjection(&'tcx ty::ProjectionTy<'tcx>),
fn unsize_kind(&self, t: Ty<'tcx>) -> Option<UnsizeKind<'tcx>> {
match t.sty {
ty::TySlice(_) | ty::TyStr => Some(UnsizeKind::Length),
- ty::TyTrait(ref tty) => Some(UnsizeKind::Vtable(tty.principal().unwrap().def_id())),
+ ty::TyDynamic(ref tty, ..) =>
+ Some(UnsizeKind::Vtable(tty.principal().map(|p| p.def_id()))),
ty::TyAdt(def, substs) if def.is_struct() => {
// FIXME(arielb1): do some kind of normalization
match def.struct_variant().fields.last() {
// cases now. We do a more thorough check at the end, once
// inference is more completely known.
match cast_ty.sty {
- ty::TyTrait(..) | ty::TySlice(..) => {
+ ty::TyDynamic(..) | ty::TySlice(..) => {
check.report_cast_to_unsized_type(fcx);
Err(ErrorReported)
}
expected_ty);
match expected_ty.sty {
- ty::TyTrait(ref object_type) => {
- let sig = object_type.projection_bounds
- .iter()
+ ty::TyDynamic(ref object_type, ..) => {
+ let sig = object_type.projection_bounds()
.filter_map(|pb| {
let pb = pb.with_self_ty(self.tcx, self.tcx.types.err);
self.deduce_sig_from_projection(&pb)
})
.next();
- let kind =
- self.tcx.lang_items.fn_trait_kind(object_type.principal().unwrap().def_id());
+ let kind = object_type.principal()
+ .and_then(|p| self.tcx.lang_items.fn_trait_kind(p.def_id()));
(sig, kind)
}
ty::TyInfer(ty::TyVar(vid)) => self.deduce_expectations_from_obligations(vid),
}
// these are always dtorck
- ty::TyTrait(..) | ty::TyProjection(_) | ty::TyAnon(..) => bug!(),
+ ty::TyDynamic(..) | ty::TyProjection(_) | ty::TyAnon(..) => bug!(),
}
}
let revised_ty = revise_self_ty(tcx, adt_def, impl_def_id, substs);
return DropckKind::RevisedSelf(revised_ty);
}
- ty::TyTrait(..) | ty::TyProjection(..) | ty::TyAnon(..) => {
+ ty::TyDynamic(..) | ty::TyProjection(..) | ty::TyAnon(..) => {
debug!("ty: {:?} isn't known, and therefore is a dropck type", ty);
return DropckKind::BorrowedDataMustStrictlyOutliveSelf;
},
.autoderef(self.span, self_ty)
.filter_map(|(ty, _)| {
match ty.sty {
- ty::TyTrait(ref data) => data.principal().map(|p| closure(self, ty, p)),
+ ty::TyDynamic(ref data, ..) => data.principal().map(|p| closure(self, ty, p)),
_ => None,
}
})
debug!("assemble_probe: self_ty={:?}", self_ty);
match self_ty.sty {
- ty::TyTrait(box ref data) => {
- self.assemble_inherent_candidates_from_object(self_ty, data.principal().unwrap());
- self.assemble_inherent_impl_candidates_for_type(data.principal().unwrap().def_id());
+ ty::TyDynamic(ref data, ..) => {
+ if let Some(p) = data.principal() {
+ self.assemble_inherent_candidates_from_object(self_ty, p);
+ self.assemble_inherent_impl_candidates_for_type(p.def_id());
+ }
}
ty::TyAdt(def, _) => {
self.assemble_inherent_impl_candidates_for_type(def.did);
match ty.sty {
ty::TyAdt(def, _) => def.did.is_local(),
- ty::TyTrait(ref tr) => tr.principal().map(|p|
- p.def_id().is_local()).unwrap_or(false),
+ ty::TyDynamic(ref tr, ..) => tr.principal()
+ .map_or(false, |p| p.def_id().is_local()),
ty::TyParam(_) => true,
/// for examples of where this comes up,.
fn rvalue_hint(fcx: &FnCtxt<'a, 'gcx, 'tcx>, ty: Ty<'tcx>) -> Expectation<'tcx> {
match fcx.tcx.struct_tail(ty).sty {
- ty::TySlice(_) | ty::TyStr | ty::TyTrait(..) => {
+ ty::TySlice(_) | ty::TyStr | ty::TyDynamic(..) => {
ExpectRvalueLikeUnsized(ty)
}
_ => ExpectHasType(ty)
}
/*From:*/ (_,
- /*To: */ &ty::TyTrait(ref obj)) => {
+ /*To: */ &ty::TyDynamic(.., r)) => {
// When T is existentially quantified as a trait
// `Foo+'to`, it must outlive the region bound `'to`.
- self.type_must_outlive(infer::RelateObjectBound(cast_expr.span),
- from_ty, obj.region_bound);
+ self.type_must_outlive(infer::RelateObjectBound(cast_expr.span), from_ty, r);
}
/*From:*/ (&ty::TyBox(from_referent_ty),
// FIXME(#27579) what amount of WF checking do we need for neg impls?
let trait_ref = ccx.tcx.impl_trait_ref(ccx.tcx.map.local_def_id(item.id)).unwrap();
- ccx.tcx.populate_implementations_for_trait_if_necessary(trait_ref.def_id);
- let sync_trait = ccx.tcx.lang_items.require(lang_items::SyncTraitLangItem)
- .unwrap_or_else(|msg| ccx.tcx.sess.fatal(&msg[..]));
- let send_trait = ccx.tcx.lang_items.require(lang_items::SendTraitLangItem)
- .unwrap_or_else(|msg| ccx.tcx.sess.fatal(&msg[..]));
- if trait_ref.def_id != sync_trait && trait_ref.def_id != send_trait {
- if !ccx.tcx.trait_has_default_impl(trait_ref.def_id) {
- error_192(ccx, item.span);
- }
+ if !ccx.tcx.trait_has_default_impl(trait_ref.def_id) {
+ error_192(ccx, item.span);
}
}
hir::ItemFn(.., ref body) => {
use rustc::ty::ParameterEnvironment;
use rustc::ty::{Ty, TyBool, TyChar, TyError};
use rustc::ty::{TyParam, TyRawPtr};
-use rustc::ty::{TyRef, TyAdt, TyTrait, TyNever, TyTuple};
+use rustc::ty::{TyRef, TyAdt, TyDynamic, TyNever, TyTuple};
use rustc::ty::{TyStr, TyArray, TySlice, TyFloat, TyInfer, TyInt};
use rustc::ty::{TyUint, TyClosure, TyBox, TyFnDef, TyFnPtr};
use rustc::ty::{TyProjection, TyAnon};
match ty.sty {
TyAdt(def, _) => Some(def.did),
- TyTrait(ref t) => t.principal().map(|p| p.def_id()),
+ TyDynamic(ref t, ..) => t.principal().map(|p| p.def_id()),
TyBox(_) => self.inference_context.tcx.lang_items.owned_box(),
ty::TyAdt(def, _) => {
self.check_def_id(item, def.did);
}
- ty::TyTrait(ref data) if data.principal().is_some() => {
+ ty::TyDynamic(ref data, ..) if data.principal().is_some() => {
self.check_def_id(item, data.principal().unwrap().def_id());
}
ty::TyBox(..) => {
}
// check for overlap with the automatic `impl Trait for Trait`
- if let ty::TyTrait(ref data) = trait_ref.self_ty().sty {
+ if let ty::TyDynamic(ref data, ..) = trait_ref.self_ty().sty {
// This is something like impl Trait1 for Trait2. Illegal
// if Trait1 is a supertrait of Trait2 or Trait2 is not object safe.
- if data.principal().is_none() ||
- !self.tcx.is_object_safe(data.principal().unwrap().def_id()) {
- // This is an error, but it will be
- // reported by wfcheck. Ignore it
- // here. This is tested by
- // `coherence-impl-trait-for-trait-object-safe.rs`.
+ if data.principal().map_or(true, |p| !self.tcx.is_object_safe(p.def_id())) {
+ // This is an error, but it will be reported by wfcheck. Ignore it here.
+ // This is tested by `coherence-impl-trait-for-trait-object-safe.rs`.
} else {
let mut supertrait_def_ids =
traits::supertrait_def_ids(self.tcx,
"default bound relaxed for a type parameter, but \
this does nothing because the given bound is not \
a default. Only `?Sized` is supported");
- tcx.try_add_builtin_trait(kind_id, bounds);
}
}
}
_ if kind_id.is_ok() => {
- tcx.try_add_builtin_trait(kind_id.unwrap(), bounds);
+ bounds.push(kind_id.unwrap());
}
// No lang item for Sized, so we can't add it as a bound.
None => {}
}
```
-Builtin traits are an exception to this rule: it's possible to have bounds of
-one non-builtin type, plus any number of builtin types. For example, the
+Send and Sync are an exception to this rule: it's possible to have bounds of
+one non-builtin trait, plus either or both of Send and Sync. For example, the
following compiles correctly:
```
variance);
}
- ty::TyTrait(ref data) => {
+ ty::TyDynamic(ref data, r) => {
// The type `Foo<T+'a>` is contravariant w/r/t `'a`:
let contra = self.contravariant(variance);
- self.add_constraints_from_region(generics, data.region_bound, contra);
+ self.add_constraints_from_region(generics, r, contra);
- let poly_trait_ref = data.principal().unwrap().with_self_ty(self.tcx(),
- self.tcx().types.err);
- self.add_constraints_from_trait_ref(generics, poly_trait_ref.0, variance);
+ if let Some(p) = data.principal() {
+ let poly_trait_ref = p.with_self_ty(self.tcx(), self.tcx().types.err);
+ self.add_constraints_from_trait_ref(generics, poly_trait_ref.0, variance);
+ }
- for projection in &data.projection_bounds {
+ for projection in data.projection_bounds() {
self.add_constraints_from_ty(generics, projection.0.ty, self.invariant);
}
}
impl TyParamBound {
fn maybe_sized(cx: &DocContext) -> TyParamBound {
- let did = cx.tcx().lang_items.require(lang_items::SizedTraitLangItem)
- .unwrap_or_else(|msg| cx.tcx().sess.fatal(&msg[..]));
- let empty = cx.tcx().intern_substs(&[]);
- let path = external_path(cx, &cx.tcx().item_name(did).as_str(),
+ let did = cx.tcx.lang_items.require(lang_items::SizedTraitLangItem)
+ .unwrap_or_else(|msg| cx.tcx.sess.fatal(&msg[..]));
+ let empty = cx.tcx.intern_substs(&[]);
+ let path = external_path(cx, &cx.tcx.item_name(did).as_str(),
Some(did), false, vec![], empty);
inline::record_extern_fqn(cx, did, TypeKind::Trait);
TraitBound(PolyTrait {
is_generic: false,
}
}
- ty::TyTrait(ref obj) => {
+ ty::TyDynamic(ref obj, ref reg) => {
if let Some(principal) = obj.principal() {
let did = principal.def_id();
inline::record_extern_fqn(cx, did, TypeKind::Trait);
let mut typarams = vec![];
- obj.region_bound.clean(cx).map(|b| typarams.push(RegionBound(b)));
+ reg.clean(cx).map(|b| typarams.push(RegionBound(b)));
for did in obj.auto_traits() {
- let tcx = match cx.tcx_opt() {
- Some(tcx) => tcx,
- None => {
- typarams.push(RegionBound(Lifetime::statik()));
- continue;
- }
- };
- let empty = tcx.intern_substs(&[]);
- let path = external_path(cx, &tcx.item_name(did).as_str(),
+ let empty = cx.tcx.intern_substs(&[]);
+ let path = external_path(cx, &cx.tcx.item_name(did).as_str(),
Some(did), false, vec![], empty);
inline::record_extern_fqn(cx, did, TypeKind::Trait);
let bound = TraitBound(PolyTrait {
}
let mut bindings = vec![];
- for &ty::Binder(ref pb) in &obj.projection_bounds {
+ for ty::Binder(ref pb) in obj.projection_bounds() {
bindings.push(TypeBinding {
name: pb.item_name.clean(cx),
ty: pb.ty.clean(cx)
});
}
- let path = external_path(cx, &cx.tcx().item_name(did).as_str(), Some(did),
+ let path = external_path(cx, &cx.tcx.item_name(did).as_str(), Some(did),
false, bindings, principal.0.substs);
ResolvedPath {
path: path,
fn main() {
let _: Box<std::io::Read + std::io::Write>;
- //~^ ERROR only the builtin traits can be used as closure or object bounds [E0225]
- //~| NOTE non-builtin trait used as bounds
+ //~^ ERROR only Send/Sync traits can be used as additional traits in a trait object [E0225]
+ //~| NOTE non-Send/Sync additional trait
}
pub fn main() {
let x: Vec<Trait + Sized> = Vec::new();
- //~^ ERROR the trait bound `Trait + std::marker::Sized: std::marker::Sized` is not satisfied
- //~| ERROR the trait `std::marker::Sized` cannot be made into an object
- //~| ERROR the trait bound `Trait + std::marker::Sized: std::marker::Sized` is not satisfied
- //~| ERROR the trait `std::marker::Sized` cannot be made into an object
+ //~^ ERROR only Send/Sync traits can be used as additional traits in a trait object
+ //~| ERROR the trait bound `Trait: std::marker::Sized` is not satisfied
+ //~| ERROR the trait bound `Trait: std::marker::Sized` is not satisfied
}
//~| NOTE missing associated type `Output` value
Sub;
//~^ ERROR E0225
- //~| NOTE non-builtin trait used as bounds
+ //~| NOTE non-Send/Sync additional trait
fn main() { }
fn main() {
size_of_copy::<Misc+Copy>();
- //~^ ERROR the trait bound `Misc + std::marker::Copy: std::marker::Copy` is not satisfied
- //~| ERROR the trait `std::marker::Copy` cannot be made into an object
+ //~^ ERROR only Send/Sync traits can be used as additional traits in a trait object
+ //~| ERROR the trait bound `Misc: std::marker::Copy` is not satisfied
}
a(x); //~ ERROR mismatched types [E0308]
//~| NOTE expected type `Box<Foo + std::marker::Send + 'static>`
//~| NOTE found type `Box<Foo + 'static>`
- //~| NOTE expected trait Foo, found a different trait Foo
+ //~| NOTE expected trait `Foo + std::marker::Send`, found trait `Foo`
}
fn main() { }
// Tests TyFnPtr
pub type FooFnPtr = fn(u8) -> bool;
- // Tests TyTrait
+ // Tests TyDynamic
pub trait FooTrait {
fn foo_method(&self) -> usize;
}