Auto merge of #37965 - Mark-Simulacrum:trait-obj-to-exis-predicate, r=eddyb

Refactor TraitObject to Slice<ExistentialPredicate>

For reference, the primary types changes in this PR are shown below. They may add in the understanding of what is discussed below, though they should not be required.

We change `TraitObject` into a list of `ExistentialPredicate`s to allow for a couple of things:
 - Principal (ExistentialPredicate::Trait) is now optional.
 - Region bounds are moved out of `TraitObject` into `TyDynamic`. This permits wrapping only the `ExistentialPredicate` list in `Binder`.
 - `BuiltinBounds` and `BuiltinBound` are removed entirely from the codebase, to permit future non-constrained auto traits. These are replaced with `ExistentialPredicate::AutoTrait`, which only requires a `DefId`. For the time being, only `Send` and `Sync` are supported; this constraint can be lifted in a future pull request.
 - Binder-related logic is extracted from `ExistentialPredicate` into the parent (`Binder<Slice<EP>>`), so `PolyX`s are inside `TraitObject` are replaced with `X`.

The code requires a sorting order for `ExistentialPredicate`s in the interned `Slice`. The sort order is asserted to be correct during interning, but the slices are not sorted at that point.

1. `ExistentialPredicate::Trait` are defined as always equal; **This may be wrong; should we be comparing them and sorting them in some way?**
1. `ExistentialPredicate::Projection`: Compared by `ExistentialProjection::sort_key`.
1. `ExistentialPredicate::AutoTrait`: Compared by `TraitDef.def_path_hash`.

Construction of `ExistentialPredicate`s is conducted through `TyCtxt::mk_existential_predicates`, which interns a passed iterator as a `Slice`. There are no convenience functions to construct from a set of separate iterators; callers must pass an iterator chain. The lack of convenience functions is primarily due to few uses and the relative difficulty in defining a nice API due to optional parts and difficulty in recognizing which argument goes where. It is also true that the current situation isn't significantly better than 4 arguments to a constructor function; but the extra work is deemed unnecessary as of this time.

```rust
// before this PR
struct TraitObject<'tcx> {
    pub principal: PolyExistentialTraitRef<'tcx>,
    pub region_bound: &'tcx ty::Region,
    pub builtin_bounds: BuiltinBounds,
    pub projection_bounds: Vec<PolyExistentialProjection<'tcx>>,
}

// after
pub enum ExistentialPredicate<'tcx> {
    // e.g. Iterator
    Trait(ExistentialTraitRef<'tcx>),
    // e.g. Iterator::Item = T
    Projection(ExistentialProjection<'tcx>),
    // e.g. Send
    AutoTrait(DefId),
}
```
This commit is contained in:
bors 2016-11-29 20:41:38 -06:00 committed by GitHub
commit 8e373b4787
71 changed files with 893 additions and 901 deletions

View File

@ -140,7 +140,7 @@ DEPS_rustc_trans := arena flate getopts graphviz libc rustc rustc_back \
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

View File

@ -165,7 +165,7 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> {
ty::TyRef(..) |
ty::TyFnDef(..) |
ty::TyFnPtr(_) |
ty::TyTrait(..) |
ty::TyDynamic(..) |
ty::TyClosure(..) |
ty::TyNever |
ty::TyTuple(..) |

View File

@ -24,6 +24,7 @@ use middle::free_region::FreeRegionMap;
use middle::mem_categorization as mc;
use middle::mem_categorization::McResult;
use middle::region::CodeExtent;
use middle::lang_items;
use mir::tcx::LvalueTy;
use ty::subst::{Kind, Subst, Substs};
use ty::adjustment;
@ -1492,11 +1493,13 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
}
}
let copy_def_id = self.tcx.require_lang_item(lang_items::CopyTraitLangItem);
// this can get called from typeck (by euv), and moves_by_default
// rightly refuses to work with inference variables, but
// moves_by_default has a cache, which we want to use in other
// cases.
!traits::type_known_to_meet_builtin_bound(self, ty, ty::BoundCopy, span)
!traits::type_known_to_meet_bound(self, ty, copy_def_id, span)
}
pub fn node_method_ty(&self, method_call: ty::MethodCall)

View File

@ -32,7 +32,6 @@
#![feature(const_fn)]
#![feature(core_intrinsics)]
#![cfg_attr(stage0, feature(dotdot_in_tuple_patterns))]
#![feature(enumset)]
#![cfg_attr(stage0, feature(item_like_imports))]
#![feature(libc)]
#![feature(nonzero)]

View File

@ -90,31 +90,6 @@ impl LanguageItems {
self.require(OwnedBoxLangItem)
}
pub fn from_builtin_kind(&self, bound: ty::BuiltinBound)
-> Result<DefId, String>
{
match bound {
ty::BoundSend => self.require(SendTraitLangItem),
ty::BoundSized => self.require(SizedTraitLangItem),
ty::BoundCopy => self.require(CopyTraitLangItem),
ty::BoundSync => self.require(SyncTraitLangItem),
}
}
pub fn to_builtin_kind(&self, id: DefId) -> Option<ty::BuiltinBound> {
if Some(id) == self.send_trait() {
Some(ty::BoundSend)
} else if Some(id) == self.sized_trait() {
Some(ty::BoundSized)
} else if Some(id) == self.copy_trait() {
Some(ty::BoundCopy)
} else if Some(id) == self.sync_trait() {
Some(ty::BoundSync)
} else {
None
}
}
pub fn fn_trait_kind(&self, id: DefId) -> Option<ty::ClosureKind> {
let def_id_kinds = [
(self.fn_trait(), ty::ClosureKind::Fn),
@ -381,3 +356,11 @@ language_item_table! {
DebugTraitLangItem, "debug_trait", debug_trait;
}
impl<'a, 'tcx, 'gcx> ty::TyCtxt<'a, 'tcx, 'gcx> {
pub fn require_lang_item(&self, lang_item: LangItem) -> DefId {
self.lang_items.require(lang_item).unwrap_or_else(|msg| {
self.sess.fatal(&msg)
})
}
}

View File

@ -225,14 +225,12 @@ fn ty_is_local(tcx: TyCtxt, ty: Ty, infer_is_local: InferIsLocal) -> bool {
fn fundamental_ty(tcx: TyCtxt, ty: Ty) -> bool {
match ty.sty {
ty::TyBox(..) | ty::TyRef(..) =>
true,
ty::TyAdt(def, _) =>
def.is_fundamental(),
ty::TyTrait(ref data) =>
tcx.has_attr(data.principal.def_id(), "fundamental"),
_ =>
false
ty::TyBox(..) | ty::TyRef(..) => true,
ty::TyAdt(def, _) => def.is_fundamental(),
ty::TyDynamic(ref data, ..) => {
data.principal().map_or(false, |p| tcx.has_attr(p.def_id(), "fundamental"))
}
_ => false
}
}
@ -272,8 +270,8 @@ fn ty_is_local_constructor(tcx: TyCtxt, ty: Ty, infer_is_local: InferIsLocal)->
krate == Some(LOCAL_CRATE)
}
ty::TyTrait(ref tt) => {
tt.principal.def_id().is_local()
ty::TyDynamic(ref tt, ..) => {
tt.principal().map_or(false, |p| p.def_id().is_local())
}
ty::TyError => {

View File

@ -156,7 +156,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
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),
@ -905,16 +905,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
ObligationCauseCode::StructInitializerSized => {
err.note("structs must have a statically known size to be initialized");
}
ObligationCauseCode::ClosureCapture(var_id, _, builtin_bound) => {
let def_id = tcx.lang_items.from_builtin_kind(builtin_bound).unwrap();
let trait_name = tcx.item_path_str(def_id);
let name = tcx.local_var_name_str(var_id);
err.note(
&format!("the closure that captures `{}` requires that all captured variables \
implement the trait `{}`",
name,
trait_name));
}
ObligationCauseCode::FieldSized => {
err.note("only the last field of a struct may have a dynamically sized type");
}

View File

@ -17,8 +17,8 @@ use rustc_data_structures::obligation_forest::{ForestObligation, ObligationProce
use std::marker::PhantomData;
use std::mem;
use syntax::ast;
use util::common::ErrorReported;
use util::nodemap::{FxHashSet, NodeMap};
use hir::def_id::DefId;
use super::CodeAmbiguity;
use super::CodeProjectionError;
@ -230,18 +230,21 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> {
normalized.value
}
pub fn register_builtin_bound(&mut self,
pub fn register_bound(&mut self,
infcx: &InferCtxt<'a, 'gcx, 'tcx>,
ty: Ty<'tcx>,
builtin_bound: ty::BuiltinBound,
def_id: DefId,
cause: ObligationCause<'tcx>)
{
match infcx.tcx.predicate_for_builtin_bound(cause, builtin_bound, 0, ty) {
Ok(predicate) => {
self.register_predicate_obligation(infcx, predicate);
}
Err(ErrorReported) => { }
}
let trait_ref = ty::TraitRef {
def_id: def_id,
substs: infcx.tcx.mk_substs_trait(ty, &[]),
};
self.register_predicate_obligation(infcx, Obligation {
cause: cause,
recursion_depth: 0,
predicate: trait_ref.to_predicate()
});
}
pub fn register_region_obligation(&mut self,

View File

@ -19,7 +19,7 @@ use hir;
use hir::def_id::DefId;
use middle::free_region::FreeRegionMap;
use ty::subst::Substs;
use ty::{self, Ty, TyCtxt, TypeFoldable};
use ty::{self, Ty, TyCtxt, TypeFoldable, ToPredicate};
use infer::InferCtxt;
use std::rc::Rc;
@ -125,10 +125,6 @@ pub enum ObligationCauseCode<'tcx> {
ReturnType, // Return type must be Sized
RepeatVec, // [T,..n] --> T must be Copy
// Captures of variable the given id by a closure (span is the
// span of the closure)
ClosureCapture(ast::NodeId, Span, ty::BuiltinBound),
// Types of fields (other than the last) in a struct must be sized.
FieldSized,
@ -369,27 +365,30 @@ pub fn predicates_for_generics<'tcx>(cause: ObligationCause<'tcx>,
/// `bound` or is not known to meet bound (note that this is
/// conservative towards *no impl*, which is the opposite of the
/// `evaluate` methods).
pub fn type_known_to_meet_builtin_bound<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
pub fn type_known_to_meet_bound<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
ty: Ty<'tcx>,
bound: ty::BuiltinBound,
def_id: DefId,
span: Span)
-> bool
{
debug!("type_known_to_meet_builtin_bound(ty={:?}, bound={:?})",
debug!("type_known_to_meet_bound(ty={:?}, bound={:?})",
ty,
bound);
infcx.tcx.item_path_str(def_id));
let cause = ObligationCause::misc(span, ast::DUMMY_NODE_ID);
let obligation =
infcx.tcx.predicate_for_builtin_bound(cause, bound, 0, ty);
let obligation = match obligation {
Ok(o) => o,
Err(..) => return false
let trait_ref = ty::TraitRef {
def_id: def_id,
substs: infcx.tcx.mk_substs_trait(ty, &[]),
};
let obligation = Obligation {
cause: ObligationCause::misc(span, ast::DUMMY_NODE_ID),
recursion_depth: 0,
predicate: trait_ref.to_predicate(),
};
let result = SelectionContext::new(infcx)
.evaluate_obligation_conservatively(&obligation);
debug!("type_known_to_meet_builtin_bound: ty={:?} bound={:?} => {:?}",
ty, bound, result);
debug!("type_known_to_meet_ty={:?} bound={} => {:?}",
ty, infcx.tcx.item_path_str(def_id), result);
if result && (ty.has_infer_types() || ty.has_closure_types()) {
// Because of inference "guessing", selection can sometimes claim
@ -404,22 +403,22 @@ pub fn type_known_to_meet_builtin_bound<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'g
// anyhow).
let cause = ObligationCause::misc(span, ast::DUMMY_NODE_ID);
fulfill_cx.register_builtin_bound(infcx, ty, bound, cause);
fulfill_cx.register_bound(infcx, ty, def_id, cause);
// Note: we only assume something is `Copy` if we can
// *definitively* show that it implements `Copy`. Otherwise,
// assume it is move; linear is always ok.
match fulfill_cx.select_all_or_error(infcx) {
Ok(()) => {
debug!("type_known_to_meet_builtin_bound: ty={:?} bound={:?} success",
debug!("type_known_to_meet_bound: ty={:?} bound={} success",
ty,
bound);
infcx.tcx.item_path_str(def_id));
true
}
Err(e) => {
debug!("type_known_to_meet_builtin_bound: ty={:?} bound={:?} errors={:?}",
debug!("type_known_to_meet_bound: ty={:?} bound={} errors={:?}",
ty,
bound,
infcx.tcx.item_path_str(def_id),
e);
false
}

View File

@ -1123,7 +1123,7 @@ fn confirm_object_candidate<'cx, 'gcx, 'tcx>(
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,
@ -1131,7 +1131,7 @@ fn confirm_object_candidate<'cx, 'gcx, 'tcx>(
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 = {

View File

@ -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};
@ -1091,8 +1092,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
// Other bounds. Consider both in-scope bounds from fn decl
// and applicable impls. There is a certain set of precedence rules here.
match self.tcx().lang_items.to_builtin_kind(obligation.predicate.def_id()) {
Some(ty::BoundCopy) => {
let def_id = obligation.predicate.def_id();
if self.tcx().lang_items.copy_trait() == Some(def_id) {
debug!("obligation self ty is {:?}",
obligation.predicate.0.self_ty());
@ -1103,29 +1104,20 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
// 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)?;
}
Some(ty::BoundSized) => {
} 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)?;
}
None if self.tcx().lang_items.unsize_trait() ==
Some(obligation.predicate.def_id()) => {
} else if self.tcx().lang_items.unsize_trait() == Some(def_id) {
self.assemble_candidates_for_unsizing(obligation, &mut candidates);
}
Some(ty::BoundSend) |
Some(ty::BoundSync) |
None => {
} 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);
self.assemble_candidates_from_caller_bounds(stack, &mut candidates)?;
@ -1445,7 +1437,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
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
@ -1515,20 +1507,18 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
// 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) => {
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) {
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");
candidates.vec.push(BuiltinObjectCandidate);
return;
}
}
_ => {}
}
data.principal.with_self_ty(this.tcx(), self_ty)
match data.principal() {
Some(p) => p.with_self_ty(this.tcx(), self_ty),
None => return,
}
}
ty::TyInfer(ty::TyVar(_)) => {
debug!("assemble_candidates_from_object_ty: ambiguous");
@ -1599,7 +1589,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
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`
@ -1611,12 +1601,17 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
//
// We always upcast when we can because of reason
// #2 (region bounds).
data_a.principal.def_id() == data_b.principal.def_id() &&
data_a.builtin_bounds.is_superset(&data_b.builtin_bounds)
match (data_a.principal(), data_b.principal()) {
(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)),
_ => false
}
}
// T -> Trait.
(_, &ty::TyTrait(_)) => true,
(_, &ty::TyDynamic(..)) => true,
// Ambiguous handling is below T -> Trait, because inference
// variables can still implement Unsize<Trait> and nested
@ -1768,7 +1763,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
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()))
@ -1814,7 +1809,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
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
@ -1879,7 +1874,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
Vec::new()
}
ty::TyTrait(..) |
ty::TyDynamic(..) |
ty::TyParam(..) |
ty::TyProjection(..) |
ty::TyAnon(..) |
@ -2165,10 +2160,11 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
// 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 input_types = data.principal.input_types();
let assoc_types = data.projection_bounds.iter()
let principal = data.principal().unwrap();
let input_types = principal.input_types();
let assoc_types = data.projection_bounds()
.map(|pb| pb.skip_binder().ty);
let all_types: Vec<_> = input_types.chain(assoc_types)
.collect();
@ -2300,8 +2296,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
// 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) => {
data.principal.with_self_ty(self.tcx(), self_ty)
ty::TyDynamic(ref data, ..) => {
data.principal().unwrap().with_self_ty(self.tcx(), self_ty)
}
_ => {
span_bug!(obligation.cause.span,
@ -2469,14 +2465,16 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
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 {
principal: data_a.principal,
region_bound: data_b.region_bound,
builtin_bounds: data_b.builtin_bounds,
projection_bounds: 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)?;
@ -2486,20 +2484,16 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
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.builtin_bounds.iter().flat_map(|bound| {
tcx.lang_items.from_builtin_kind(bound).ok()
})
.chain(Some(data.principal.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)
}) {
@ -2515,33 +2509,26 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
predicate));
};
// Create the obligation for casting from T to Trait.
push(data.principal.with_self_ty(tcx, source).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));
}
// We can only make objects from sized types.
let mut builtin_bounds = data.builtin_bounds;
builtin_bounds.insert(ty::BoundSized);
// 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) {
let tr = ty::TraitRef {
def_id: tcx.require_lang_item(lang_items::SizedTraitLangItem),
substs: tcx.mk_substs_trait(source, &[]),
};
push(tr.to_predicate());
} else {
return Err(Unimplemented);
}
}
// Create obligations for the projection predicates.
for bound in &data.projection_bounds {
push(bound.with_self_ty(tcx, source).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());
}

View File

@ -190,9 +190,6 @@ impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCauseCode<'a> {
super::VariableType(id) => Some(super::VariableType(id)),
super::ReturnType => Some(super::ReturnType),
super::RepeatVec => Some(super::RepeatVec),
super::ClosureCapture(node_id, span, bound) => {
Some(super::ClosureCapture(node_id, span, bound))
}
super::FieldSized => Some(super::FieldSized),
super::ConstSized => Some(super::ConstSized),
super::SharedStatic => Some(super::SharedStatic),
@ -507,7 +504,6 @@ impl<'tcx> TypeFoldable<'tcx> for traits::ObligationCauseCode<'tcx> {
super::VariableType(_) |
super::ReturnType |
super::RepeatVec |
super::ClosureCapture(..) |
super::FieldSized |
super::ConstSized |
super::SharedStatic |
@ -552,7 +548,6 @@ impl<'tcx> TypeFoldable<'tcx> for traits::ObligationCauseCode<'tcx> {
super::VariableType(_) |
super::ReturnType |
super::RepeatVec |
super::ClosureCapture(..) |
super::FieldSized |
super::ConstSized |
super::SharedStatic |

View File

@ -12,7 +12,6 @@ use hir::def_id::DefId;
use ty::subst::{Subst, Substs};
use ty::{self, Ty, TyCtxt, ToPredicate, ToPolyTraitRef};
use ty::outlives::Component;
use util::common::ErrorReported;
use util::nodemap::FxHashSet;
use super::{Obligation, ObligationCause, PredicateObligation, SelectionContext, Normalized};
@ -408,25 +407,6 @@ pub fn predicate_for_trait_ref<'tcx>(
}
impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
pub fn trait_ref_for_builtin_bound(self,
builtin_bound: ty::BuiltinBound,
param_ty: Ty<'tcx>)
-> Result<ty::TraitRef<'tcx>, ErrorReported>
{
match self.lang_items.from_builtin_kind(builtin_bound) {
Ok(def_id) => {
Ok(ty::TraitRef {
def_id: def_id,
substs: self.mk_substs_trait(param_ty, &[])
})
}
Err(e) => {
self.sess.err(&e);
Err(ErrorReported)
}
}
}
pub fn predicate_for_trait_def(self,
cause: ObligationCause<'tcx>,
trait_def_id: DefId,
@ -442,17 +422,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
predicate_for_trait_ref(cause, trait_ref, recursion_depth)
}
pub fn predicate_for_builtin_bound(self,
cause: ObligationCause<'tcx>,
builtin_bound: ty::BuiltinBound,
recursion_depth: usize,
param_ty: Ty<'tcx>)
-> Result<PredicateObligation<'tcx>, ErrorReported>
{
let trait_ref = self.trait_ref_for_builtin_bound(builtin_bound, param_ty)?;
Ok(predicate_for_trait_ref(cause, trait_ref, recursion_depth))
}
/// Cast a trait reference into a reference to one of its super
/// traits; returns `None` if `target_trait_def_id` is not a
/// supertrait.

View File

@ -195,7 +195,7 @@ impl<'a, 'tcx> ty::TyS<'tcx> {
tc_ty(tcx, typ, cache).owned_pointer()
}
ty::TyTrait(_) => {
ty::TyDynamic(..) => {
TC::All - TC::InteriorParam
}

View File

@ -29,7 +29,7 @@ use ty::{self, TraitRef, Ty, TypeAndMut};
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};
@ -47,6 +47,7 @@ use std::mem;
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};
@ -63,6 +64,7 @@ pub struct CtxtArenas<'tcx> {
region: TypedArena<Region>,
stability: TypedArena<attr::Stability>,
layout: TypedArena<Layout>,
existential_predicates: TypedArena<ExistentialPredicate<'tcx>>,
// references
generics: TypedArena<ty::Generics<'tcx>>,
@ -81,6 +83,7 @@ impl<'tcx> CtxtArenas<'tcx> {
region: TypedArena::new(),
stability: TypedArena::new(),
layout: TypedArena::new(),
existential_predicates: TypedArena::new(),
generics: TypedArena::new(),
trait_def: TypedArena::new(),
@ -103,6 +106,7 @@ pub struct CtxtInterners<'tcx> {
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> {
@ -115,7 +119,8 @@ 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()),
}
}
@ -958,6 +963,27 @@ impl<'a, 'tcx> Lift<'tcx> for &'a Slice<Ty<'a>> {
}
}
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>)
@ -1126,7 +1152,7 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, '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());
@ -1200,6 +1226,13 @@ impl<'tcx> Borrow<Region> for Interned<'tcx, Region> {
}
}
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,
@ -1297,6 +1330,7 @@ macro_rules! slice_interners {
}
slice_interners!(
existential_predicates: _intern_existential_predicates(ExistentialPredicate),
type_list: _intern_type_list(Ty),
substs: _intern_substs(Kind)
);
@ -1437,9 +1471,12 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
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,
@ -1501,6 +1538,13 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
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()
@ -1517,6 +1561,12 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
}
}
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))

View File

@ -45,12 +45,12 @@ pub enum TypeError<'tcx> {
IntMismatch(ExpectedFound<ty::IntVarValue>),
FloatMismatch(ExpectedFound<ast::FloatTy>),
Traits(ExpectedFound<DefId>),
BuiltinBoundsMismatch(ExpectedFound<ty::BuiltinBounds>),
VariadicMismatch(ExpectedFound<bool>),
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)]
@ -135,19 +135,6 @@ impl<'tcx> fmt::Display for TypeError<'tcx> {
format!("trait `{}`",
tcx.item_path_str(values.found)))
}),
BuiltinBoundsMismatch(values) => {
if values.expected.is_empty() {
write!(f, "expected no bounds, found `{}`",
values.found)
} else if values.found.is_empty() {
write!(f, "expected bounds `{}`, found no bounds",
values.expected)
} else {
write!(f, "expected bounds `{}`, found bounds `{}`",
values.expected,
values.found)
}
}
IntMismatch(ref values) => {
write!(f, "expected `{:?}`, found `{:?}`",
values.expected,
@ -178,6 +165,10 @@ impl<'tcx> fmt::Display for TypeError<'tcx> {
values.expected.ty,
values.found.ty)
}
ExistentialMismatch(ref values) => {
report_maybe_different(f, format!("trait `{}`", values.expected),
format!("trait `{}`", values.found))
}
}
}
}
@ -214,8 +205,9 @@ impl<'a, 'gcx, 'lcx, 'tcx> ty::TyS<'tcx> {
}
ty::TyFnDef(..) => format!("fn item"),
ty::TyFnPtr(_) => "fn pointer".to_string(),
ty::TyTrait(ref inner) => {
format!("trait {}", tcx.item_path_str(inner.principal.def_id()))
ty::TyDynamic(ref inner, ..) => {
inner.principal().map_or_else(|| "trait".to_string(),
|p| format!("trait {}", tcx.item_path_str(p.def_id())))
}
ty::TyClosure(..) => "closure".to_string(),
ty::TyTuple(_) => "tuple".to_string(),

View File

@ -11,6 +11,7 @@
use hir::def_id::DefId;
use ty::{self, Ty, TyCtxt};
use syntax::ast;
use middle::lang_items::OwnedBoxLangItem;
use self::SimplifiedType::*;
@ -59,8 +60,8 @@ pub fn simplify_type<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
ty::TyStr => Some(StrSimplifiedType),
ty::TyArray(..) | ty::TySlice(_) => Some(ArraySimplifiedType),
ty::TyRawPtr(_) => Some(PtrSimplifiedType),
ty::TyTrait(ref trait_info) => {
Some(TraitSimplifiedType(trait_info.principal.def_id()))
ty::TyDynamic(ref trait_info, ..) => {
trait_info.principal().map(|p| TraitSimplifiedType(p.def_id()))
}
ty::TyRef(_, mt) => {
// since we introduce auto-refs during method lookup, we
@ -70,10 +71,7 @@ pub fn simplify_type<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
}
ty::TyBox(_) => {
// treat like we would treat `Box`
match tcx.lang_items.require_owned_box() {
Ok(def_id) => Some(AdtSimplifiedType(def_id)),
Err(msg) => tcx.sess.fatal(&msg),
}
Some(AdtSimplifiedType(tcx.require_lang_item(OwnedBoxLangItem)))
}
ty::TyClosure(def_id, _) => {
Some(ClosureSimplifiedType(def_id))

View File

@ -121,16 +121,21 @@ impl FlagComputation {
self.add_substs(substs);
}
&ty::TyTrait(ref obj) => {
&ty::TyDynamic(ref obj, r) => {
let mut computation = FlagComputation::new();
computation.add_substs(obj.principal.skip_binder().substs);
for projection_bound in &obj.projection_bounds {
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(&projection_bound.0);
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) => {

View File

@ -316,7 +316,7 @@ pub fn characteristic_def_id_of_type(ty: Ty) -> Option<DefId> {
match ty.sty {
ty::TyAdt(adt_def, _) => Some(adt_def.did),
ty::TyTrait(ref data) => Some(data.principal.def_id()),
ty::TyDynamic(data, ..) => data.principal().map(|p| p.def_id()),
ty::TyArray(subty, _) |
ty::TySlice(subty) |

View File

@ -924,7 +924,7 @@ impl<'a, 'gcx, 'tcx> Layout {
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 }
@ -963,7 +963,7 @@ impl<'a, 'gcx, 'tcx> Layout {
non_zero: false
}
}
ty::TyTrait(_) => {
ty::TyDynamic(..) => {
let mut unit = Struct::new(dl, false);
unit.sized = false;
Univariant { variant: unit, non_zero: false }

View File

@ -53,9 +53,8 @@ use hir;
use hir::itemlikevisit::ItemLikeVisitor;
pub use self::sty::{Binder, DebruijnIndex};
pub use self::sty::{BuiltinBound, BuiltinBounds};
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};
@ -68,11 +67,6 @@ pub use self::sty::InferTy::*;
pub use self::sty::Region::*;
pub use self::sty::TypeVariants::*;
pub use self::sty::BuiltinBound::Send as BoundSend;
pub use self::sty::BuiltinBound::Sized as BoundSized;
pub use self::sty::BuiltinBound::Copy as BoundCopy;
pub use self::sty::BuiltinBound::Sync as BoundSync;
pub use self::contents::TypeContents;
pub use self::context::{TyCtxt, tls};
pub use self::context::{CtxtArenas, Lift, Tables};
@ -1718,7 +1712,7 @@ impl<'a, 'tcx> AdtDefData<'tcx, 'tcx> {
vec![]
}
TyStr | TyTrait(..) | TySlice(_) | TyError => {
TyStr | TyDynamic(..) | TySlice(_) | TyError => {
// these are never sized - return the target type
vec![ty]
}
@ -1884,18 +1878,14 @@ pub enum ClosureKind {
impl<'a, 'tcx> ClosureKind {
pub fn trait_did(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> DefId {
let result = match *self {
ClosureKind::Fn => tcx.lang_items.require(FnTraitLangItem),
match *self {
ClosureKind::Fn => tcx.require_lang_item(FnTraitLangItem),
ClosureKind::FnMut => {
tcx.lang_items.require(FnMutTraitLangItem)
tcx.require_lang_item(FnMutTraitLangItem)
}
ClosureKind::FnOnce => {
tcx.lang_items.require(FnOnceTraitLangItem)
tcx.require_lang_item(FnOnceTraitLangItem)
}
};
match result {
Ok(trait_did) => trait_did,
Err(err) => tcx.sess.fatal(&err[..]),
}
}

View File

@ -177,7 +177,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
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

View File

@ -302,23 +302,6 @@ impl<'tcx> Relate<'tcx> for Vec<ty::PolyExistentialProjection<'tcx>> {
}
}
impl<'tcx> Relate<'tcx> for ty::BuiltinBounds {
fn relate<'a, 'gcx, R>(relation: &mut R,
a: &ty::BuiltinBounds,
b: &ty::BuiltinBounds)
-> RelateResult<'tcx, ty::BuiltinBounds>
where R: TypeRelation<'a, 'gcx, 'tcx>, 'gcx: 'a+'tcx, 'tcx: 'a
{
// Two sets of builtin bounds are only relatable if they are
// precisely the same (but see the coercion code).
if a != b {
Err(TypeError::BuiltinBoundsMismatch(expected_found(relation, a, b)))
} else {
Ok(*a)
}
}
}
impl<'tcx> Relate<'tcx> for ty::TraitRef<'tcx> {
fn relate<'a, 'gcx, R>(relation: &mut R,
a: &ty::TraitRef<'tcx>,
@ -415,23 +398,15 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R,
Ok(tcx.mk_adt(a_def, substs))
}
(&ty::TyTrait(ref a_obj), &ty::TyTrait(ref b_obj)) =>
{
let principal = relation.relate(&a_obj.principal, &b_obj.principal)?;
let r =
relation.with_cause(
Cause::ExistentialRegionBound,
|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 pb = relation.relate(&a_obj.projection_bounds, &b_obj.projection_bounds)?;
Ok(tcx.mk_trait(ty::TraitObject {
principal: principal,
region_bound: r,
builtin_bounds: nb,
projection_bounds: 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),
@ -527,6 +502,31 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R,
}
}
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>,

View File

@ -315,7 +315,6 @@ impl<'a, 'tcx> Lift<'tcx> for ty::error::TypeError<'a> {
IntMismatch(x) => IntMismatch(x),
FloatMismatch(x) => FloatMismatch(x),
Traits(x) => Traits(x),
BuiltinBoundsMismatch(x) => BuiltinBoundsMismatch(x),
VariadicMismatch(x) => VariadicMismatch(x),
CyclicTy => CyclicTy,
ProjectionNameMismatched(x) => ProjectionNameMismatched(x),
@ -325,6 +324,7 @@ impl<'a, 'tcx> Lift<'tcx> for ty::error::TypeError<'a> {
TyParamDefaultMismatch(ref x) => {
return tcx.lift(x).map(TyParamDefaultMismatch)
}
ExistentialMismatch(ref x) => return tcx.lift(x).map(ExistentialMismatch)
})
}
}
@ -427,20 +427,33 @@ impl<'tcx, T:TypeFoldable<'tcx>> TypeFoldable<'tcx> for ty::Binder<T> {
}
}
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 {
principal: self.principal.fold_with(folder),
region_bound: self.region_bound.fold_with(folder),
builtin_bounds: self.builtin_bounds,
projection_bounds: 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.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 {
self.principal.visit_with(visitor) ||
self.region_bound.visit_with(visitor) ||
self.projection_bounds.visit_with(visitor)
match *self {
ty::ExistentialPredicate::Trait(ref tr) => tr.visit_with(visitor),
ty::ExistentialPredicate::Projection(ref p) => p.visit_with(visitor),
ty::ExistentialPredicate::AutoTrait(_) => false,
}
}
}
@ -463,7 +476,8 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> {
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,
@ -500,7 +514,8 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> {
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)
@ -703,16 +718,6 @@ impl<'tcx> TypeFoldable<'tcx> for ty::adjustment::AutoBorrow<'tcx> {
}
}
impl<'tcx> TypeFoldable<'tcx> for ty::BuiltinBounds {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, _folder: &mut F) -> Self {
*self
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _visitor: &mut V) -> bool {
false
}
}
impl<'tcx> TypeFoldable<'tcx> for ty::TypeParameterDef<'tcx> {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
ty::TypeParameterDef {

View File

@ -14,13 +14,13 @@ use hir::def_id::DefId;
use middle::region;
use ty::subst::Substs;
use ty::{self, AdtDef, ToPredicate, TypeFlags, Ty, TyCtxt, TypeFoldable};
use ty::{self, AdtDef, TypeFlags, Ty, TyCtxt, TypeFoldable};
use ty::{Slice, TyS};
use util::common::ErrorReported;
use ty::subst::Kind;
use collections::enum_set::{self, EnumSet, CLike};
use std::fmt;
use std::ops;
use std::iter;
use std::cmp::Ordering;
use syntax::abi;
use syntax::ast::{self, Name, NodeId};
use syntax::symbol::{keywords, InternedString};
@ -147,7 +147,7 @@ pub enum TypeVariants<'tcx> {
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`.
@ -275,12 +275,104 @@ impl<'a, 'gcx, 'acx, 'tcx> ClosureSubsts<'tcx> {
}
}
#[derive(Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
pub struct TraitObject<'tcx> {
pub principal: PolyExistentialTraitRef<'tcx>,
pub region_bound: &'tcx ty::Region,
pub builtin_bounds: BuiltinBounds,
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<'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.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.skip_binder().auto_traits()
}
pub fn iter<'a>(&'a self)
-> impl DoubleEndedIterator<Item=Binder<ExistentialPredicate<'tcx>>> + 'tcx {
self.skip_binder().iter().cloned().map(Binder)
}
}
/// A complete reference to a trait. These take numerous guises in syntax,
@ -344,14 +436,30 @@ pub struct ExistentialTraitRef<'tcx> {
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>>;
@ -713,122 +821,53 @@ pub struct ExistentialProjection<'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
})
}
}
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
pub struct BuiltinBounds(EnumSet<BuiltinBound>);
impl<'a, 'gcx, 'tcx> BuiltinBounds {
pub fn empty() -> BuiltinBounds {
BuiltinBounds(EnumSet::new())
}
pub fn iter(&self) -> enum_set::Iter<BuiltinBound> {
self.into_iter()
}
pub fn to_predicates(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>,
self_ty: Ty<'tcx>)
-> Vec<ty::Predicate<'tcx>> {
self.iter().filter_map(|builtin_bound|
match tcx.trait_ref_for_builtin_bound(builtin_bound, self_ty) {
Ok(trait_ref) => Some(trait_ref.to_predicate()),
Err(ErrorReported) => { None }
}
).collect()
}
}
impl ops::Deref for BuiltinBounds {
type Target = EnumSet<BuiltinBound>;
fn deref(&self) -> &Self::Target { &self.0 }
}
impl ops::DerefMut for BuiltinBounds {
fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 }
}
impl<'a> IntoIterator for &'a BuiltinBounds {
type Item = BuiltinBound;
type IntoIter = enum_set::Iter<BuiltinBound>;
fn into_iter(self) -> Self::IntoIter {
(**self).into_iter()
}
}
#[derive(Clone, RustcEncodable, PartialEq, Eq, RustcDecodable, Hash,
Debug, Copy)]
pub enum BuiltinBound {
Send = 0,
Sized = 1,
Copy = 2,
Sync = 3,
}
impl CLike for BuiltinBound {
fn to_usize(&self) -> usize {
*self as usize
}
fn from_usize(v: usize) -> BuiltinBound {
match v {
0 => BuiltinBound::Send,
1 => BuiltinBound::Sized,
2 => BuiltinBound::Copy,
3 => BuiltinBound::Sync,
_ => bug!("{} is not a valid BuiltinBound", v)
ty: self.ty
}
}
}
impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
pub fn try_add_builtin_trait(self,
trait_def_id: DefId,
builtin_bounds: &mut EnumSet<BuiltinBound>)
-> 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
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))
}
}
@ -1088,7 +1127,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
pub fn is_trait(&self) -> bool {
match self.sty {
TyTrait(..) => true,
TyDynamic(..) => true,
_ => false
}
}
@ -1221,7 +1260,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
pub fn ty_to_def_id(&self) -> Option<DefId> {
match self.sty {
TyTrait(ref tt) => Some(tt.principal.def_id()),
TyDynamic(ref tt, ..) => tt.principal().map(|p| p.def_id()),
TyAdt(def, _) => Some(def.did),
TyClosure(id, _) => Some(id),
_ => None
@ -1243,9 +1282,11 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
TyRef(region, _) => {
vec![region]
}
TyTrait(ref obj) => {
let mut v = vec![obj.region_bound];
v.extend(obj.principal.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) => {

View File

@ -21,6 +21,7 @@ use ty::fold::TypeVisitor;
use ty::layout::{Layout, LayoutError};
use ty::TypeVariants::*;
use util::nodemap::FxHashMap;
use middle::lang_items;
use rustc_const_math::{ConstInt, ConstIsize, ConstUsize};
@ -531,9 +532,13 @@ impl<'a, 'gcx, 'tcx, H: Hasher> TypeVisitor<'tcx> for TypeIdHasher<'a, 'gcx, 'tc
self.hash(f.sig.variadic());
self.hash(f.sig.inputs().skip_binder().len());
}
TyTrait(ref data) => {
self.def_id(data.principal.def_id());
self.hash(data.builtin_bounds);
TyDynamic(ref data, ..) => {
if let Some(p) = data.principal() {
self.def_id(p.def_id());
}
for d in data.auto_traits() {
self.def_id(d);
}
}
TyTuple(tys) => {
self.hash(tys.len());
@ -595,7 +600,7 @@ impl<'a, 'gcx, 'tcx, H: Hasher> TypeVisitor<'tcx> for TypeIdHasher<'a, 'gcx, 'tc
impl<'a, 'tcx> ty::TyS<'tcx> {
fn impls_bound(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
param_env: &ParameterEnvironment<'tcx>,
bound: ty::BuiltinBound,
def_id: DefId,
cache: &RefCell<FxHashMap<Ty<'tcx>, bool>>,
span: Span) -> bool
{
@ -607,7 +612,7 @@ impl<'a, 'tcx> ty::TyS<'tcx> {
let result =
tcx.infer_ctxt(None, Some(param_env.clone()), Reveal::ExactMatch)
.enter(|infcx| {
traits::type_known_to_meet_builtin_bound(&infcx, self, bound, span)
traits::type_known_to_meet_bound(&infcx, self, def_id, span)
});
if self.has_param_types() || self.has_self_ty() {
cache.borrow_mut().insert(self, result);
@ -636,12 +641,13 @@ impl<'a, 'tcx> ty::TyS<'tcx> {
mutbl: hir::MutMutable, ..
}) => Some(true),
TyArray(..) | TySlice(..) | TyTrait(..) | TyTuple(..) |
TyArray(..) | TySlice(..) | TyDynamic(..) | TyTuple(..) |
TyClosure(..) | TyAdt(..) | TyAnon(..) |
TyProjection(..) | TyParam(..) | TyInfer(..) | TyError => None
}.unwrap_or_else(|| {
!self.impls_bound(tcx, param_env, ty::BoundCopy, &param_env.is_copy_cache, span)
});
!self.impls_bound(tcx, param_env,
tcx.require_lang_item(lang_items::CopyTraitLangItem),
&param_env.is_copy_cache, span) });
if !self.has_param_types() && !self.has_self_ty() {
self.flags.set(self.flags.get() | if result {
@ -677,13 +683,13 @@ impl<'a, 'tcx> ty::TyS<'tcx> {
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
}.unwrap_or_else(|| {
self.impls_bound(tcx, param_env, ty::BoundSized, &param_env.is_sized_cache, span)
});
self.impls_bound(tcx, param_env, tcx.require_lang_item(lang_items::SizedTraitLangItem),
&param_env.is_sized_cache, span) });
if !self.has_param_types() && !self.has_self_ty() {
self.flags.set(self.flags.get() | if result {

View File

@ -92,11 +92,19 @@ fn push_subtypes<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent_ty: Ty<'tcx>) {
ty::TyProjection(ref data) => {
stack.extend(data.trait_ref.substs.types().rev());
}
ty::TyTrait(ref obj) => {
stack.extend(obj.principal.input_types().rev());
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());

View File

@ -17,7 +17,7 @@ use ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable};
use std::iter::once;
use syntax::ast;
use syntax_pos::Span;
use util::common::ErrorReported;
use middle::lang_items;
/// Returns the set of obligations needed to make `ty` well-formed.
/// If `ty` contains unresolved inference variables, this may include
@ -282,14 +282,11 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> {
fn require_sized(&mut self, subty: Ty<'tcx>, cause: traits::ObligationCauseCode<'tcx>) {
if !subty.has_escaping_regions() {
let cause = self.cause(cause);
match self.infcx.tcx.trait_ref_for_builtin_bound(ty::BoundSized, subty) {
Ok(trait_ref) => {
self.out.push(
traits::Obligation::new(cause,
trait_ref.to_predicate()));
}
Err(ErrorReported) => { }
}
let trait_ref = ty::TraitRef {
def_id: self.infcx.tcx.require_lang_item(lang_items::SizedTraitLangItem),
substs: self.infcx.tcx.mk_substs_trait(subty, &[]),
};
self.out.push(traits::Obligation::new(cause, trait_ref.to_predicate()));
}
}
@ -298,7 +295,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 {
@ -377,12 +373,12 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> {
// 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
@ -391,15 +387,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(Some(data.principal.def_id()));
data.auto_traits().chain(data.principal().map(|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)
)})
))
);
}
@ -456,7 +449,9 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> {
.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 { }
@ -491,11 +486,9 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> {
if !data.has_escaping_regions() {
let implicit_bounds =
object_region_bounds(self.infcx.tcx,
data.principal,
data.builtin_bounds);
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));
@ -514,8 +507,7 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> {
/// `ty::required_region_bounds`, see that for more information.
pub fn object_region_bounds<'a, 'gcx, 'tcx>(
tcx: TyCtxt<'a, 'gcx, 'tcx>,
principal: ty::PolyExistentialTraitRef<'tcx>,
others: ty::BuiltinBounds)
existential_predicates: ty::Binder<&'tcx ty::Slice<ty::ExistentialPredicate<'tcx>>>)
-> Vec<&'tcx ty::Region>
{
// Since we don't actually *know* the self type for an object,
@ -523,8 +515,13 @@ pub fn object_region_bounds<'a, 'gcx, 'tcx>(
// a skolemized type.
let open_ty = tcx.mk_infer(ty::FreshTy(0));
let mut predicates = others.to_predicates(tcx, open_ty);
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)
}

View File

@ -16,9 +16,8 @@ use ty::{TyBool, TyChar, TyAdt};
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;
@ -298,74 +297,31 @@ fn in_binder<'a, 'gcx, 'tcx, T, U>(f: &mut fmt::Formatter,
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 = tcx.lift(&self.principal)
.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)
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).0
}).collect();
let tap = ty::Binder(TraitAndProjections(principal, projections));
in_binder(f, tcx, &ty::Binder(""), Some(tap))
})?;
.with_self_ty(tcx, dummy_self)
}).collect::<Vec<_>>();
parameterized(f, principal.substs, principal.def_id, &projections)?;
}
// Builtin bounds.
for bound in &self.builtin_bounds {
write!(f, " + {:?}", bound)?;
for did in self.auto_traits() {
write!(f, " + {}", tcx.item_path_str(did))?;
}
// 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(())
})?;
Ok(())
}
@ -453,41 +409,6 @@ impl<'tcx> fmt::Debug for ty::adjustment::Adjustment<'tcx> {
}
}
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)?;
}
for bound in &self.builtin_bounds {
maybe_continue(f)?;
write!(f, "{:?}", bound)?;
}
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 {
@ -677,19 +598,6 @@ impl<'tcx> fmt::Display for ty::FnSig<'tcx> {
}
}
impl fmt::Display for ty::BuiltinBounds {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut bounds = self.iter();
if let Some(bound) = bounds.next() {
write!(f, "{:?}", bound)?;
for bound in bounds {
write!(f, " + {:?}", bound)?;
}
}
Ok(())
}
}
impl fmt::Debug for ty::TyVid {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "_#{}t", self.index)
@ -753,6 +661,12 @@ impl fmt::Debug for ty::IntVarValue {
}
}*/
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)))
@ -872,7 +786,15 @@ impl<'tcx> fmt::Display for ty::TypeVariants<'tcx> {
}
})
}
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| {

View File

@ -857,8 +857,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
let tcx = self.tcx;
let unit_temp = Lvalue::Local(self.patch.new_temp(tcx.mk_nil()));
let free_func = tcx.lang_items.require(lang_items::BoxFreeFnLangItem)
.unwrap_or_else(|e| tcx.sess.fatal(&e));
let free_func = tcx.require_lang_item(lang_items::BoxFreeFnLangItem);
let substs = tcx.mk_substs(iter::once(Kind::from(ty)));
let fty = tcx.item_type(free_func).subst(tcx, substs);

View File

@ -572,7 +572,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, '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")
}

View File

@ -416,6 +416,15 @@ impl<'a, 'tcx> SpecializedDecoder<ty::AdtDef<'tcx>> for DecodeContext<'a, 'tcx>
}
}
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)

View File

@ -783,8 +783,7 @@ fn build_free<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
data: &FreeData<'tcx>,
target: BasicBlock)
-> TerminatorKind<'tcx> {
let free_func = tcx.lang_items.require(lang_items::BoxFreeFnLangItem)
.unwrap_or_else(|e| tcx.sess.fatal(&e));
let free_func = tcx.require_lang_item(lang_items::BoxFreeFnLangItem);
let substs = tcx.intern_substs(&[Kind::from(data.item_ty)]);
TerminatorKind::Call {
func: Operand::Constant(Constant {

View File

@ -28,6 +28,7 @@ use rustc::mir::traversal::ReversePostorder;
use rustc::mir::transform::{Pass, MirPass, MirSource};
use rustc::mir::visit::{LvalueContext, Visitor};
use rustc::util::nodemap::DefIdMap;
use rustc::middle::lang_items;
use syntax::abi::Abi;
use syntax::feature_gate::UnstableFeatures;
use syntax_pos::Span;
@ -1040,7 +1041,9 @@ impl<'tcx> MirPass<'tcx> for QualifyAndPromoteConstants {
tcx.infer_ctxt(None, None, Reveal::NotSpecializable).enter(|infcx| {
let cause = traits::ObligationCause::new(mir.span, id, traits::SharedStatic);
let mut fulfillment_cx = traits::FulfillmentContext::new();
fulfillment_cx.register_builtin_bound(&infcx, ty, ty::BoundSync, cause);
fulfillment_cx.register_bound(&infcx, ty,
tcx.require_lang_item(lang_items::SyncTraitLangItem),
cause);
if let Err(err) = fulfillment_cx.select_all_or_error(&infcx) {
infcx.report_fulfillment_errors(&err);
}

View File

@ -71,7 +71,8 @@ impl<'a, 'tcx> EmbargoVisitor<'a, 'tcx> {
fn item_ty_level(&self, item_def_id: DefId) -> Option<AccessLevel> {
let ty_def_id = match self.tcx.item_type(item_def_id).sty {
ty::TyAdt(adt, _) => adt.did,
ty::TyTrait(ref obj) => obj.principal.def_id(),
ty::TyDynamic(ref obj, ..) if obj.principal().is_some() =>
obj.principal().unwrap().def_id(),
ty::TyProjection(ref proj) => proj.trait_ref.def_id,
_ => return Some(AccessLevel::Public)
};
@ -359,7 +360,7 @@ impl<'b, 'a, 'tcx> TypeVisitor<'tcx> for ReachEverythingInTheInterfaceVisitor<'b
fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool {
let ty_def_id = match ty.sty {
ty::TyAdt(adt, _) => Some(adt.did),
ty::TyTrait(ref obj) => Some(obj.principal.def_id()),
ty::TyDynamic(ref obj, ..) => obj.principal().map(|p| p.def_id()),
ty::TyProjection(ref proj) => Some(proj.trait_ref.def_id),
ty::TyFnDef(def_id, ..) |
ty::TyAnon(def_id, _) => Some(def_id),
@ -938,7 +939,7 @@ impl<'a, 'tcx: 'a> TypeVisitor<'tcx> for SearchInterfaceForPrivateItemsVisitor<'
fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool {
let ty_def_id = match ty.sty {
ty::TyAdt(adt, _) => Some(adt.did),
ty::TyTrait(ref obj) => Some(obj.principal.def_id()),
ty::TyDynamic(ref obj, ..) => obj.principal().map(|p| p.def_id()),
ty::TyProjection(ref proj) => {
if self.required_visibility == ty::Visibility::PrivateExternal {
// Conservatively approximate the whole type alias as public without

View File

@ -295,16 +295,14 @@ pub fn unsized_info<'ccx, 'tcx>(ccx: &CrateContext<'ccx, 'tcx>,
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.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 {:?} -> {:?}",

View File

@ -763,7 +763,7 @@ fn find_drop_glue_neighbors<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
ty::TyFnDef(..) |
ty::TyFnPtr(_) |
ty::TyNever |
ty::TyTrait(_) => {
ty::TyDynamic(..) => {
/* nothing to do */
}
ty::TyAdt(adt_def, substs) => {
@ -1003,18 +1003,20 @@ fn create_trans_items_for_vtable_methods<'a, 'tcx>(scx: &SharedCrateContext<'a,
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.with_self_ty(scx.tcx(), impl_ty);
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_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)));

View File

@ -95,7 +95,8 @@ pub struct LocalCrateContext<'tcx> {
/// 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>>,
@ -800,7 +801,9 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> {
&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
}

View File

@ -431,8 +431,13 @@ fn trait_pointer_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
// type is assigned the correct name, size, namespace, and source location.
// But it does not describe the trait's methods.
let def_id = match trait_type.sty {
ty::TyTrait(ref data) => data.principal.def_id(),
let containing_scope = match trait_type.sty {
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 {
NO_SCOPE_METADATA
},
_ => {
bug!("debuginfo: Unexpected trait-object type in \
trait_pointer_metadata(): {:?}",
@ -444,8 +449,6 @@ fn trait_pointer_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
let trait_type_name =
compute_debuginfo_type_name(cx, trait_object_type, false);
let (containing_scope, _) = get_namespace_and_span_for_item(cx, def_id);
let trait_llvm_type = type_of::type_of(cx, trait_object_type);
let file_metadata = unknown_file_metadata(cx);
@ -520,7 +523,7 @@ pub fn type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
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)
@ -535,7 +538,7 @@ pub fn type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
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)

View File

@ -93,11 +93,13 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
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(
&trait_data.principal);
&principal);
push_item_name(cx, principal.def_id, false, output);
push_type_params(cx, principal.substs, output);
}
},
ty::TyFnDef(.., &ty::BareFnTy{ unsafety, abi, ref sig } ) |
ty::TyFnPtr(&ty::BareFnTy{ unsafety, abi, ref sig } ) => {

View File

@ -394,7 +394,7 @@ pub fn size_and_align_of_dst<'blk, 'tcx>(bcx: &BlockAndBuilder<'blk, 'tcx>,
(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());
@ -463,7 +463,7 @@ fn make_drop_glue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
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.

View File

@ -110,42 +110,48 @@ pub fn trans_object_shim<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>,
/// 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 size_ty = sizing_type_of(ccx, ty);
let size = machine::llsize_of_alloc(ccx, size_ty);
let align = align_of(ccx, ty);
let mut components: Vec<_> = [
// Generate a destructor for the vtable.
glue::get_drop_glue(ccx, ty),
C_uint(ccx, size),
C_uint(ccx, align)
].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)
})
});
let size_ty = sizing_type_of(ccx, trait_ref.self_ty());
let size = machine::llsize_of_alloc(ccx, size_ty);
let align = align_of(ccx, trait_ref.self_ty());
let components: Vec<_> = [
// Generate a destructor for the vtable.
glue::get_drop_glue(ccx, trait_ref.self_ty()),
C_uint(ccx, size),
C_uint(ccx, align)
].iter().cloned().chain(methods).collect();
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
}

View File

@ -36,6 +36,7 @@ use glue;
use abi::{Abi, FnType};
use back::symbol_names;
use std::fmt::Write;
use std::iter;
#[derive(PartialEq, Eq, Clone, Copy, Debug, Hash)]
pub enum TransItem<'tcx> {
@ -410,7 +411,7 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> {
ty::TyFloat(ast::FloatTy::F64) => output.push_str("f64"),
ty::TyAdt(adt_def, substs) => {
self.push_def_path(adt_def.did, output);
self.push_type_params(substs, &[], output);
self.push_type_params(substs, iter::empty(), output);
},
ty::TyTuple(component_types) => {
output.push('(');
@ -457,11 +458,13 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> {
self.push_type_name(inner_type, output);
output.push(']');
},
ty::TyTrait(ref trait_data) => {
self.push_def_path(trait_data.principal.def_id(), output);
self.push_type_params(trait_data.principal.skip_binder().substs,
&trait_data.projection_bounds,
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(),
output);
}
},
ty::TyFnDef(.., &ty::BareFnTy{ unsafety, abi, ref sig } ) |
ty::TyFnPtr(&ty::BareFnTy{ unsafety, abi, ref sig } ) => {
@ -511,7 +514,7 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> {
self.push_def_path(def_id, output);
let generics = self.tcx.item_generics(self.tcx.closure_base_def_id(def_id));
let substs = closure_substs.substs.truncate_to(self.tcx, generics);
self.push_type_params(substs, &[], output);
self.push_type_params(substs, iter::empty(), output);
}
ty::TyError |
ty::TyInfer(_) |
@ -551,11 +554,14 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> {
output.pop();
}
pub fn push_type_params(&self,
fn push_type_params<I>(&self,
substs: &Substs<'tcx>,
projections: &[ty::PolyExistentialProjection<'tcx>],
output: &mut String) {
if substs.types().next().is_none() && projections.is_empty() {
projections: I,
output: &mut String)
where I: Iterator<Item=ty::PolyExistentialProjection<'tcx>>
{
let mut projections = projections.peekable();
if substs.types().next().is_none() && projections.peek().is_none() {
return;
}
@ -585,6 +591,6 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> {
instance: Instance<'tcx>,
output: &mut String) {
self.push_def_path(instance.def, output);
self.push_type_params(instance.substs, &[], output);
self.push_type_params(instance.substs, iter::empty(), output);
}
}

View File

@ -95,7 +95,7 @@ pub fn sizing_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Typ
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);
@ -148,7 +148,7 @@ fn unsized_info_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> Type
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)
}
@ -258,7 +258,7 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) ->
// 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) => {

View File

@ -49,6 +49,7 @@
//! 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;
@ -69,6 +70,7 @@ use util::common::{ErrorReported, FN_OUTPUT_NAME};
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};
@ -960,7 +962,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
ty.id,
path.segments.last().unwrap(),
span,
partition_bounds(tcx, span, bounds))
partition_bounds(bounds))
} else {
struct_span_err!(tcx.sess, ty.span, E0172,
"expected a reference to a trait")
@ -1043,17 +1045,18 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
trait_segment,
&mut projection_bounds);
let PartitionedBounds { builtin_bounds,
trait_bounds,
let PartitionedBounds { trait_bounds,
region_bounds } =
partitioned_bounds;
let (auto_traits, trait_bounds) = split_auto_traits(tcx, trait_bounds);
if !trait_bounds.is_empty() {
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();
}
@ -1070,30 +1073,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
ty: b.ty
}
})
}).collect();
let region_bound =
self.compute_object_lifetime_bound(span,
&region_bounds,
existential_principal,
builtin_bounds);
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() {
@ -1135,12 +1115,37 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
.emit();
}
let ty = tcx.mk_trait(ty::TraitObject {
principal: existential_principal,
region_bound: region_bound,
builtin_bounds: builtin_bounds,
projection_bounds: 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,
&region_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
}
@ -1439,7 +1444,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
path_id,
path.segments.last().unwrap(),
span,
partition_bounds(tcx, span, &[]))
partition_bounds(&[]))
}
Def::Enum(did) | Def::TyAlias(did) | Def::Struct(did) | Def::Union(did) => {
assert_eq!(opt_self_ty, None);
@ -1893,7 +1898,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
ast_bounds: &[hir::TyParamBound])
-> Ty<'tcx>
{
let mut partitioned_bounds = partition_bounds(self.tcx(), span, &ast_bounds[..]);
let mut partitioned_bounds = partition_bounds(ast_bounds);
let trait_bound = if !partitioned_bounds.trait_bounds.is_empty() {
partitioned_bounds.trait_bounds.remove(0)
@ -1922,38 +1927,36 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
fn compute_object_lifetime_bound(&self,
span: Span,
explicit_region_bounds: &[&hir::Lifetime],
principal_trait_ref: ty::PolyExistentialTraitRef<'tcx>,
builtin_bounds: ty::BuiltinBounds)
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={:?}, builtin_bounds={:?})",
existential_predicates={:?})",
explicit_region_bounds,
principal_trait_ref,
builtin_bounds);
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()) {
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, builtin_bounds);
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.
@ -1980,46 +1983,62 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
}
pub struct PartitionedBounds<'a> {
pub builtin_bounds: ty::BuiltinBounds,
pub trait_bounds: Vec<&'a hir::PolyTraitRef>,
pub region_bounds: Vec<&'a hir::Lifetime>,
}
/// Divides a list of bounds from the AST into three groups: builtin bounds (Copy, Sized etc),
/// general trait bounds, and region bounds.
pub fn partition_bounds<'a, 'b, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
_span: Span,
ast_bounds: &'b [hir::TyParamBound])
/// Divides a list of general trait bounds into two groups: builtin bounds (Sync/Send) and the
/// remaining general trait bounds.
fn split_auto_traits<'a, 'b, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
trait_bounds: Vec<&'b hir::PolyTraitRef>)
-> (Vec<DefId>, Vec<&'b hir::PolyTraitRef>)
{
let (auto_traits, trait_bounds): (Vec<_>, _) = trait_bounds.into_iter().partition(|bound| {
match bound.trait_ref.path.def {
Def::Trait(trait_did) => {
// 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() {
let segments = &bound.trait_ref.path.segments;
let parameters = &segments[segments.len() - 1].parameters;
if !parameters.types().is_empty() {
check_type_argument_count(tcx, bound.trait_ref.path.span,
parameters.types().len(), &[]);
}
if !parameters.lifetimes().is_empty() {
report_lifetime_number_error(tcx, bound.trait_ref.path.span,
parameters.lifetimes().len(), 0);
}
true
} else {
false
}
}
_ => false
}
});
let auto_traits = auto_traits.into_iter().map(|tr| {
if let Def::Trait(trait_did) = tr.trait_ref.path.def {
trait_did
} else {
unreachable!()
}
}).collect::<Vec<_>>();
(auto_traits, trait_bounds)
}
/// Divides a list of bounds from the AST into two groups: general trait bounds and region bounds
pub fn partition_bounds<'a, 'b, 'gcx, 'tcx>(ast_bounds: &'b [hir::TyParamBound])
-> PartitionedBounds<'b>
{
let mut builtin_bounds = ty::BuiltinBounds::empty();
let mut region_bounds = Vec::new();
let mut trait_bounds = Vec::new();
for ast_bound in ast_bounds {
match *ast_bound {
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 builtin_bounds) {
let segments = &b.trait_ref.path.segments;
let parameters = &segments[segments.len() - 1].parameters;
if !parameters.types().is_empty() {
check_type_argument_count(tcx, b.trait_ref.path.span,
parameters.types().len(), &[]);
}
if !parameters.lifetimes().is_empty() {
report_lifetime_number_error(tcx, b.trait_ref.path.span,
parameters.lifetimes().len(), 0);
}
continue; // success
}
}
_ => {
// Not a trait? that's an error, but it'll get
// reported later.
}
}
trait_bounds.push(b);
}
hir::TraitTyParamBound(_, hir::TraitBoundModifier::Maybe) => {}
@ -2030,7 +2049,6 @@ pub fn partition_bounds<'a, 'b, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
}
PartitionedBounds {
builtin_bounds: builtin_bounds,
trait_bounds: trait_bounds,
region_bounds: region_bounds,
}
@ -2105,7 +2123,7 @@ fn report_lifetime_number_error(tcx: TyCtxt, span: Span, number: usize, expected
#[derive(PartialEq, Eq, Clone, Debug)]
pub struct Bounds<'tcx> {
pub region_bounds: Vec<&'tcx ty::Region>,
pub builtin_bounds: ty::BuiltinBounds,
pub implicitly_sized: bool,
pub trait_bounds: Vec<ty::PolyTraitRef<'tcx>>,
pub projection_bounds: Vec<ty::PolyProjectionPredicate<'tcx>>,
}
@ -2116,10 +2134,14 @@ impl<'a, 'gcx, 'tcx> Bounds<'tcx> {
{
let mut vec = Vec::new();
for builtin_bound in &self.builtin_bounds {
match tcx.trait_ref_for_builtin_bound(builtin_bound, param_ty) {
Ok(trait_ref) => { vec.push(trait_ref.to_predicate()); }
Err(ErrorReported) => { }
// 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());
}
}

View File

@ -340,7 +340,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
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);

View File

@ -46,6 +46,7 @@ use rustc::hir;
use rustc::traits;
use rustc::ty::{self, Ty, TypeFoldable};
use rustc::ty::cast::{CastKind, CastTy};
use rustc::middle::lang_items;
use syntax::ast;
use syntax_pos::Span;
use util::common::ErrorReported;
@ -64,7 +65,7 @@ pub struct CastCheck<'tcx> {
/// 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>),
@ -78,7 +79,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, '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.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() {
@ -129,7 +131,7 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> {
// 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)
}
@ -543,6 +545,7 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> {
impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
fn type_is_known_to_be_sized(&self, ty: Ty<'tcx>, span: Span) -> bool {
traits::type_known_to_meet_builtin_bound(self, ty, ty::BoundSized, span)
let lang_item = self.tcx.require_lang_item(lang_items::SizedTraitLangItem);
traits::type_known_to_meet_bound(self, ty, lang_item, span)
}
}

View File

@ -112,15 +112,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
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.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),

View File

@ -515,7 +515,7 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'b, 'gcx, 'tcx>(
}
// these are always dtorck
ty::TyTrait(..) | ty::TyProjection(_) | ty::TyAnon(..) => bug!(),
ty::TyDynamic(..) | ty::TyProjection(_) | ty::TyAnon(..) => bug!(),
}
}
@ -564,7 +564,7 @@ fn has_dtor_of_interest<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
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;
},

View File

@ -255,7 +255,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
.autoderef(self.span, self_ty)
.filter_map(|(ty, _)| {
match ty.sty {
ty::TyTrait(ref data) => Some(closure(self, ty, data.principal)),
ty::TyDynamic(ref data, ..) => data.principal().map(|p| closure(self, ty, p)),
_ => None,
}
})

View File

@ -295,9 +295,11 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
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);
self.assemble_inherent_impl_candidates_for_type(data.principal.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);

View File

@ -379,7 +379,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
match ty.sty {
ty::TyAdt(def, _) => def.did.is_local(),
ty::TyTrait(ref tr) => tr.principal.def_id().is_local(),
ty::TyDynamic(ref tr, ..) => tr.principal()
.map_or(false, |p| p.def_id().is_local()),
ty::TyParam(_) => true,

View File

@ -123,6 +123,7 @@ use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
use rustc::hir::itemlikevisit::ItemLikeVisitor;
use rustc::hir::{self, PatKind};
use rustc::hir::print as pprust;
use rustc::middle::lang_items;
use rustc_back::slice;
use rustc_const_eval::eval_length;
@ -268,7 +269,7 @@ impl<'a, 'gcx, 'tcx> Expectation<'tcx> {
/// 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)
@ -1815,11 +1816,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
ty: Ty<'tcx>,
span: Span,
code: traits::ObligationCauseCode<'tcx>,
bound: ty::BuiltinBound)
def_id: DefId)
{
self.register_builtin_bound(
self.register_bound(
ty,
bound,
def_id,
traits::ObligationCause::new(span, self.body_id, code));
}
@ -1828,16 +1829,17 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
span: Span,
code: traits::ObligationCauseCode<'tcx>)
{
self.require_type_meets(ty, span, code, ty::BoundSized);
let lang_item = self.tcx.require_lang_item(lang_items::SizedTraitLangItem);
self.require_type_meets(ty, span, code, lang_item);
}
pub fn register_builtin_bound(&self,
pub fn register_bound(&self,
ty: Ty<'tcx>,
builtin_bound: ty::BuiltinBound,
def_id: DefId,
cause: traits::ObligationCause<'tcx>)
{
self.fulfillment_cx.borrow_mut()
.register_builtin_bound(self, ty, builtin_bound, cause);
.register_bound(self, ty, def_id, cause);
}
pub fn register_predicate(&self,
@ -3909,7 +3911,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
if count > 1 {
// For [foo, ..n] where n > 1, `foo` must have
// Copy type:
self.require_type_meets(t, expr.span, traits::RepeatVec, ty::BoundCopy);
let lang_item = self.tcx.require_lang_item(lang_items::CopyTraitLangItem);
self.require_type_meets(t, expr.span, traits::RepeatVec, lang_item);
}
if element_ty.references_error() {

View File

@ -812,11 +812,10 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
}
/*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),

View File

@ -18,6 +18,7 @@ use middle::region::{CodeExtent};
use rustc::traits::{self, ObligationCauseCode};
use rustc::ty::{self, Ty, TyCtxt};
use rustc::util::nodemap::{FxHashSet, FxHashMap};
use rustc::middle::lang_items;
use syntax::ast;
use syntax_pos::Span;
@ -117,16 +118,10 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> {
// 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);
match ccx.tcx.lang_items.to_builtin_kind(trait_ref.def_id) {
Some(ty::BoundSend) | Some(ty::BoundSync) => {}
Some(_) | None => {
if !ccx.tcx.trait_has_default_impl(trait_ref.def_id) {
error_192(ccx, item.span);
}
}
}
}
hir::ItemFn(.., body_id) => {
self.check_item_fn(item, body_id);
}
@ -241,9 +236,9 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> {
// For DST, all intermediate types must be sized.
let unsized_len = if all_sized || variant.fields.is_empty() { 0 } else { 1 };
for field in &variant.fields[..variant.fields.len() - unsized_len] {
fcx.register_builtin_bound(
fcx.register_bound(
field.ty,
ty::BoundSized,
fcx.tcx.require_lang_item(lang_items::SizedTraitLangItem),
traits::ObligationCause::new(field.span,
fcx.body_id,
traits::FieldSized));

View File

@ -23,7 +23,7 @@ use rustc::traits::{self, ObligationCause, Reveal};
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};
@ -68,7 +68,7 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> {
match ty.sty {
TyAdt(def, _) => Some(def.did),
TyTrait(ref t) => Some(t.principal.def_id()),
TyDynamic(ref t, ..) => t.principal().map(|p| p.def_id()),
TyBox(_) => self.inference_context.tcx.lang_items.owned_box(),

View File

@ -86,8 +86,8 @@ impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> {
ty::TyAdt(def, _) => {
self.check_def_id(item, def.did);
}
ty::TyTrait(ref data) => {
self.check_def_id(item, data.principal.def_id());
ty::TyDynamic(ref data, ..) if data.principal().is_some() => {
self.check_def_id(item, data.principal().unwrap().def_id());
}
ty::TyBox(..) => {
match self.tcx.lang_items.require_owned_box() {

View File

@ -178,18 +178,17 @@ impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for OverlapChecker<'cx, 'tcx> {
}
// 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 !self.tcx.is_object_safe(data.principal.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, data.principal.def_id());
traits::supertrait_def_ids(self.tcx,
data.principal().unwrap().def_id());
if supertrait_def_ids.any(|d| d == trait_def_id) {
span_err!(self.tcx.sess,
item.span,

View File

@ -1639,11 +1639,10 @@ fn convert_foreign_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
assert!(prev_predicates.is_none());
}
// Add the Sized bound, unless the type parameter is marked as `?Sized`.
fn add_unsized_bound<'gcx: 'tcx, 'tcx>(astconv: &AstConv<'gcx, 'tcx>,
bounds: &mut ty::BuiltinBounds,
// Is it marked with ?Sized
fn is_unsized<'gcx: 'tcx, 'tcx>(astconv: &AstConv<'gcx, 'tcx>,
ast_bounds: &[hir::TyParamBound],
span: Span)
span: Span) -> bool
{
let tcx = astconv.tcx();
@ -1672,16 +1671,17 @@ fn add_unsized_bound<'gcx: 'tcx, 'tcx>(astconv: &AstConv<'gcx, '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);
return false;
}
// No lang item for Sized, so we can't add it as a bound.
None => {}
}
true
}
/// Returns the early-bound lifetimes declared in this generics
@ -1963,14 +1963,9 @@ pub fn compute_bounds<'gcx: 'tcx, 'tcx>(astconv: &AstConv<'gcx, 'tcx>,
{
let tcx = astconv.tcx();
let PartitionedBounds {
mut builtin_bounds,
trait_bounds,
region_bounds
} = partition_bounds(tcx, span, &ast_bounds);
if let SizedByDefault::Yes = sized_by_default {
add_unsized_bound(astconv, &mut builtin_bounds, ast_bounds, span);
}
} = partition_bounds(&ast_bounds);
let mut projection_bounds = vec![];
@ -1988,9 +1983,15 @@ pub fn compute_bounds<'gcx: 'tcx, 'tcx>(astconv: &AstConv<'gcx, 'tcx>,
trait_bounds.sort_by(|a,b| a.def_id().cmp(&b.def_id()));
let implicitly_sized = if let SizedByDefault::Yes = sized_by_default {
!is_unsized(astconv, ast_bounds, span)
} else {
false
};
Bounds {
region_bounds: region_bounds,
builtin_bounds: builtin_bounds,
implicitly_sized: implicitly_sized,
trait_bounds: trait_bounds,
projection_bounds: projection_bounds,
}

View File

@ -2778,8 +2778,8 @@ fn main() {
}
```
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:
```

View File

@ -371,15 +371,17 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
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.with_self_ty(self.tcx(), self.tcx().types.err);
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);
}
}

View File

@ -30,6 +30,7 @@ use syntax_pos::{self, DUMMY_SP, Pos};
use rustc_trans::back::link;
use rustc::middle::privacy::AccessLevels;
use rustc::middle::resolve_lifetime::DefRegion::*;
use rustc::middle::lang_items;
use rustc::hir::def::{Def, CtorKind};
use rustc::hir::def_id::{self, DefId, DefIndex, CRATE_DEF_INDEX};
use rustc::hir::print as pprust;
@ -593,12 +594,20 @@ pub enum TyParamBound {
impl TyParamBound {
fn maybe_sized(cx: &DocContext) -> TyParamBound {
use rustc::hir::TraitBoundModifier as TBM;
let mut sized_bound = ty::BoundSized.clean(cx);
if let TyParamBound::TraitBound(_, ref mut tbm) = sized_bound {
*tbm = TBM::Maybe
};
sized_bound
let did = cx.tcx.require_lang_item(lang_items::SizedTraitLangItem);
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 {
trait_: ResolvedPath {
path: path,
typarams: None,
did: did,
is_generic: false,
},
lifetimes: vec![]
}, hir::TraitBoundModifier::Maybe)
}
fn is_sized_bound(&self, cx: &DocContext) -> bool {
@ -675,37 +684,6 @@ fn external_path(cx: &DocContext, name: &str, trait_did: Option<DefId>, has_self
}
}
impl Clean<TyParamBound> for ty::BuiltinBound {
fn clean(&self, cx: &DocContext) -> TyParamBound {
let tcx = cx.tcx;
let empty = tcx.intern_substs(&[]);
let (did, path) = match *self {
ty::BoundSend =>
(tcx.lang_items.send_trait().unwrap(),
external_path(cx, "Send", None, false, vec![], empty)),
ty::BoundSized =>
(tcx.lang_items.sized_trait().unwrap(),
external_path(cx, "Sized", None, false, vec![], empty)),
ty::BoundCopy =>
(tcx.lang_items.copy_trait().unwrap(),
external_path(cx, "Copy", None, false, vec![], empty)),
ty::BoundSync =>
(tcx.lang_items.sync_trait().unwrap(),
external_path(cx, "Sync", None, false, vec![], empty)),
};
inline::record_extern_fqn(cx, did, TypeKind::Trait);
TraitBound(PolyTrait {
trait_: ResolvedPath {
path: path,
typarams: None,
did: did,
is_generic: false,
},
lifetimes: vec![]
}, hir::TraitBoundModifier::None)
}
}
impl<'tcx> Clean<TyParamBound> for ty::TraitRef<'tcx> {
fn clean(&self, cx: &DocContext) -> TyParamBound {
inline::record_extern_fqn(cx, self.def_id, TypeKind::Trait);
@ -1876,32 +1854,49 @@ impl<'tcx> Clean<Type> for ty::Ty<'tcx> {
is_generic: false,
}
}
ty::TyTrait(ref obj) => {
let did = obj.principal.def_id();
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)));
for bb in &obj.builtin_bounds {
typarams.push(bb.clean(cx));
reg.clean(cx).map(|b| typarams.push(RegionBound(b)));
for did in obj.auto_traits() {
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 {
trait_: ResolvedPath {
path: path,
typarams: None,
did: did,
is_generic: false,
},
lifetimes: vec![]
}, hir::TraitBoundModifier::None);
typarams.push(bound);
}
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), false, bindings, obj.principal.0.substs);
let path = external_path(cx, &cx.tcx.item_name(did).as_str(), Some(did),
false, bindings, principal.0.substs);
ResolvedPath {
path: path,
typarams: Some(typarams),
did: did,
is_generic: false,
}
} else {
Never
}
}
ty::TyTuple(ref t) => Tuple(t.clean(cx)),

View File

@ -10,6 +10,6 @@
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
}

View File

@ -12,8 +12,7 @@ trait Trait {}
pub fn main() {
let x: Vec<Trait + Sized> = Vec::new();
//~^ ERROR `Trait + Sized: std::marker::Sized` is not satisfied
//~| ERROR the trait `std::marker::Sized` cannot be made into an object
//~| ERROR `Trait + 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
}

View File

@ -11,8 +11,8 @@
use std::fmt::Debug;
const CONST_0: Debug+Sync = *(&0 as &(Debug+Sync));
//~^ ERROR `std::fmt::Debug + Sync + 'static: std::marker::Sized` is not satisfied
//~| NOTE the trait `std::marker::Sized` is not implemented for `std::fmt::Debug + Sync + 'static`
//~^ ERROR `std::fmt::Debug + std::marker::Sync + 'static: std::marker::Sized` is not satisfied
//~| NOTE the trait `std::marker::Sized` is not implemented for `std::fmt::Debug + std::marker::Syn
//~| NOTE does not have a constant size known at compile-time
//~| NOTE constant expressions must have a statically known size
@ -23,8 +23,8 @@ const CONST_FOO: str = *"foo";
//~| NOTE constant expressions must have a statically known size
static STATIC_1: Debug+Sync = *(&1 as &(Debug+Sync));
//~^ ERROR `std::fmt::Debug + Sync + 'static: std::marker::Sized` is not satisfied
//~| NOTE the trait `std::marker::Sized` is not implemented for `std::fmt::Debug + Sync + 'static`
//~^ ERROR `std::fmt::Debug + std::marker::Sync + 'static: std::marker::Sized` is not satisfied
//~| NOTE the trait `std::marker::Sized` is not implemented for `std::fmt::Debug + std::marker::Syn
//~| NOTE does not have a constant size known at compile-time
//~| NOTE constant expressions must have a statically known size

View File

@ -8,7 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// error-pattern:type annotations required
// error-pattern:type annotations or generic parameter binding required
fn main() {
panic!(
std::default::Default::default()

View File

@ -20,6 +20,6 @@ type Test = Add +
//~| NOTE missing associated type `Output` value
Sub;
//~^ ERROR E0225
//~| NOTE non-builtin trait used as bounds
//~| NOTE non-Send/Sync additional trait
fn main() { }

View File

@ -16,6 +16,6 @@ fn size_of_copy<T: Copy+?Sized>() -> usize { mem::size_of::<T>() }
fn main() {
size_of_copy::<Misc+Copy>();
//~^ ERROR `Misc + 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
}

View File

@ -21,10 +21,10 @@ fn c(x: Box<Foo+Sync+Send>) {
}
fn d(x: Box<Foo>) {
a(x); //~ ERROR mismatched types
//~| expected type `Box<Foo + Send + 'static>`
//~| found type `Box<Foo + 'static>`
//~| expected bounds `Send`, found no bounds
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 + std::marker::Send`, found trait `Foo`
}
fn main() { }

View File

@ -15,7 +15,7 @@ trait Foo {
// This should emit the less confusing error, not the more confusing one.
fn foo(_x: Foo + Send) {
//~^ ERROR `Foo + Send + 'static: std::marker::Sized` is not satisfied
//~^ ERROR the trait bound `Foo + std::marker::Send + 'static: std::marker::Sized` is not
}
fn main() { }

View File

@ -70,7 +70,7 @@ pub mod testtypes {
// Tests TyFnPtr
pub type FooFnPtr = fn(u8) -> bool;
// Tests TyTrait
// Tests TyDynamic
pub trait FooTrait {
fn foo_method(&self) -> usize;
}