From bb35d50cad5f452e80ff88ee957962966c28a9f6 Mon Sep 17 00:00:00 2001 From: Mark-Simulacrum Date: Wed, 16 Nov 2016 09:21:49 -0700 Subject: [PATCH] Refactor TyTrait to contain a interned ExistentialPredicate slice. Renames TyTrait to TyDynamic. --- mk/crates.mk | 2 +- src/librustc/infer/freshen.rs | 2 +- src/librustc/traits/coherence.rs | 4 +- src/librustc/traits/error_reporting.rs | 2 +- src/librustc/traits/fulfill.rs | 8 +- src/librustc/traits/mod.rs | 8 +- src/librustc/traits/project.rs | 4 +- src/librustc/traits/select.rs | 140 ++++++------- src/librustc/ty/contents.rs | 2 +- src/librustc/ty/context.rs | 74 +++++-- src/librustc/ty/error.rs | 9 +- src/librustc/ty/fast_reject.rs | 2 +- src/librustc/ty/flags.rs | 19 +- src/librustc/ty/item_path.rs | 2 +- src/librustc/ty/layout.rs | 4 +- src/librustc/ty/mod.rs | 4 +- src/librustc/ty/outlives.rs | 2 +- src/librustc/ty/relate.rs | 54 +++-- src/librustc/ty/structural_impls.rs | 40 ++-- src/librustc/ty/sty.rs | 194 +++++++++++++----- src/librustc/ty/util.rs | 8 +- src/librustc/ty/walk.rs | 21 +- src/librustc/ty/wf.rs | 37 ++-- src/librustc/util/ppaux.rs | 125 +++-------- src/librustc_lint/types.rs | 2 +- src/librustc_metadata/decoder.rs | 9 + src/librustc_trans/base.rs | 8 +- src/librustc_trans/collector.rs | 26 +-- src/librustc_trans/context.rs | 7 +- src/librustc_trans/debuginfo/metadata.rs | 6 +- src/librustc_trans/debuginfo/type_names.rs | 2 +- src/librustc_trans/glue.rs | 4 +- src/librustc_trans/meth.rs | 34 +-- src/librustc_trans/trans_item.rs | 4 +- src/librustc_trans/type_of.rs | 6 +- src/librustc_typeck/astconv.rs | 109 +++++----- src/librustc_typeck/check/_match.rs | 2 +- src/librustc_typeck/check/cast.rs | 7 +- src/librustc_typeck/check/closure.rs | 9 +- src/librustc_typeck/check/dropck.rs | 4 +- src/librustc_typeck/check/method/confirm.rs | 2 +- src/librustc_typeck/check/method/probe.rs | 8 +- src/librustc_typeck/check/method/suggest.rs | 4 +- src/librustc_typeck/check/mod.rs | 2 +- src/librustc_typeck/check/regionck.rs | 5 +- src/librustc_typeck/check/wfcheck.rs | 11 +- src/librustc_typeck/coherence/mod.rs | 4 +- src/librustc_typeck/coherence/orphan.rs | 2 +- src/librustc_typeck/coherence/overlap.rs | 11 +- src/librustc_typeck/collect.rs | 3 +- src/librustc_typeck/diagnostics.rs | 4 +- src/librustc_typeck/variance/constraints.rs | 13 +- src/librustdoc/clean/mod.rs | 27 +-- src/test/compile-fail/E0225.rs | 4 +- src/test/compile-fail/bad-sized.rs | 7 +- src/test/compile-fail/issue-22560.rs | 2 +- src/test/compile-fail/issue-32963.rs | 4 +- .../compile-fail/trait-bounds-cant-coerce.rs | 2 +- src/test/run-pass/auxiliary/issue13507.rs | 2 +- 59 files changed, 611 insertions(+), 512 deletions(-) diff --git a/mk/crates.mk b/mk/crates.mk index 7ae5846c54b..cf985a0d980 100644 --- a/mk/crates.mk +++ b/mk/crates.mk @@ -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 diff --git a/src/librustc/infer/freshen.rs b/src/librustc/infer/freshen.rs index 30e18a4c569..19183892e4b 100644 --- a/src/librustc/infer/freshen.rs +++ b/src/librustc/infer/freshen.rs @@ -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(..) | diff --git a/src/librustc/traits/coherence.rs b/src/librustc/traits/coherence.rs index d4e217fb710..58cb52e8977 100644 --- a/src/librustc/traits/coherence.rs +++ b/src/librustc/traits/coherence.rs @@ -227,7 +227,7 @@ 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) => { + ty::TyDynamic(ref data, ..) => { data.principal().map_or(false, |p| tcx.has_attr(p.def_id(), "fundamental")) } _ => false @@ -270,7 +270,7 @@ fn ty_is_local_constructor(tcx: TyCtxt, ty: Ty, infer_is_local: InferIsLocal)-> krate == Some(LOCAL_CRATE) } - ty::TyTrait(ref tt) => { + ty::TyDynamic(ref tt, ..) => { tt.principal().map_or(false, |p| p.def_id().is_local()) } diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 4ac4c31386e..2e8e45468dd 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -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), diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs index 9ff4048f73e..23c28037a3c 100644 --- a/src/librustc/traits/fulfill.rs +++ b/src/librustc/traits/fulfill.rs @@ -231,10 +231,10 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> { } pub fn register_bound(&mut self, - infcx: &InferCtxt<'a, 'gcx, 'tcx>, - ty: Ty<'tcx>, - def_id: DefId, - cause: ObligationCause<'tcx>) + infcx: &InferCtxt<'a, 'gcx, 'tcx>, + ty: Ty<'tcx>, + def_id: DefId, + cause: ObligationCause<'tcx>) { let trait_ref = ty::TraitRef { def_id: def_id, diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index bdd0ee75eb1..5c5bf130c3b 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -366,10 +366,10 @@ pub fn predicates_for_generics<'tcx>(cause: ObligationCause<'tcx>, /// conservative towards *no impl*, which is the opposite of the /// `evaluate` methods). pub fn type_known_to_meet_bound<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, - ty: Ty<'tcx>, - def_id: DefId, - span: Span) - -> bool + ty: Ty<'tcx>, + def_id: DefId, + span: Span) +-> bool { debug!("type_known_to_meet_bound(ty={:?}, bound={:?})", ty, diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs index 76bead99343..27b7adf0ef3 100644 --- a/src/librustc/traits/project.rs +++ b/src/librustc/traits/project.rs @@ -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 = { diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 11b23d699de..a23b021cd4f 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -50,7 +50,6 @@ use std::fmt; use std::marker::PhantomData; use std::mem; use std::rc::Rc; -use std::iter; use syntax::abi::Abi; use hir; use util::nodemap::FxHashMap; @@ -1094,38 +1093,30 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // and applicable impls. There is a certain set of precedence rules here. let def_id = obligation.predicate.def_id(); - match obligation.predicate.def_id() { - _ if self.tcx().lang_items.copy_trait() == Some(def_id) => { - debug!("obligation self ty is {:?}", - obligation.predicate.0.self_ty()); + if self.tcx().lang_items.copy_trait() == Some(def_id) { + debug!("obligation self ty is {:?}", + obligation.predicate.0.self_ty()); - // User-defined copy impls are permitted, but only for - // structs and enums. - self.assemble_candidates_from_impls(obligation, &mut candidates)?; + // User-defined copy impls are permitted, but only for + // structs and enums. + self.assemble_candidates_from_impls(obligation, &mut candidates)?; - // For other types, we'll use the builtin rules. - let copy_conditions = self.copy_conditions(obligation); - self.assemble_builtin_bound_candidates(copy_conditions, &mut candidates)?; - } - _ if self.tcx().lang_items.sized_trait() == Some(def_id) => { - // Sized is never implementable by end-users, it is - // always automatically computed. - let sized_conditions = self.sized_conditions(obligation); - self.assemble_builtin_bound_candidates(sized_conditions, - &mut candidates)?; - } - - _ if self.tcx().lang_items.unsize_trait() == Some(def_id) => { - self.assemble_candidates_for_unsizing(obligation, &mut candidates); - } - - // For non-builtins and Send/Sync - _ => { - self.assemble_closure_candidates(obligation, &mut candidates)?; - self.assemble_fn_pointer_candidates(obligation, &mut candidates)?; - self.assemble_candidates_from_impls(obligation, &mut candidates)?; - self.assemble_candidates_from_object_ty(obligation, &mut candidates); - } + // For other types, we'll use the builtin rules. + let copy_conditions = self.copy_conditions(obligation); + self.assemble_builtin_bound_candidates(copy_conditions, &mut candidates)?; + } else if self.tcx().lang_items.sized_trait() == Some(def_id) { + // Sized is never implementable by end-users, it is + // always automatically computed. + let sized_conditions = self.sized_conditions(obligation); + self.assemble_builtin_bound_candidates(sized_conditions, + &mut candidates)?; + } else if self.tcx().lang_items.unsize_trait() == Some(def_id) { + self.assemble_candidates_for_unsizing(obligation, &mut candidates); + } else { + self.assemble_closure_candidates(obligation, &mut candidates)?; + self.assemble_fn_pointer_candidates(obligation, &mut candidates)?; + self.assemble_candidates_from_impls(obligation, &mut candidates)?; + self.assemble_candidates_from_object_ty(obligation, &mut candidates); } self.assemble_candidates_from_projected_tys(obligation, &mut candidates); @@ -1446,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 @@ -1516,7 +1507,7 @@ 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) => { + 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"); @@ -1525,7 +1516,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { } match data.principal() { - Some(ref p) => p.with_self_ty(this.tcx(), self_ty), + Some(p) => p.with_self_ty(this.tcx(), self_ty), None => return, } } @@ -1598,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,7 +1602,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // We always upcast when we can because of reason // #2 (region bounds). match (data_a.principal(), data_b.principal()) { - (Some(ref a), Some(ref b)) => a.def_id() == b.def_id() && + (Some(a), Some(b)) => a.def_id() == b.def_id() && data_b.auto_traits() // All of a's auto traits need to be in b's auto traits. .all(|b| data_a.auto_traits().any(|a| a == b)), @@ -1620,7 +1611,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { } // T -> Trait. - (_, &ty::TyTrait(_)) => true, + (_, &ty::TyDynamic(..)) => true, // Ambiguous handling is below T -> Trait, because inference // variables can still implement Unsize and nested @@ -1772,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())) @@ -1818,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 @@ -1883,7 +1874,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { Vec::new() } - ty::TyTrait(..) | + ty::TyDynamic(..) | ty::TyParam(..) | ty::TyProjection(..) | ty::TyAnon(..) | @@ -2169,11 +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 principal = data.principal().unwrap(); let input_types = principal.input_types(); - let assoc_types = data.projection_bounds.iter() + let assoc_types = data.projection_bounds() .map(|pb| pb.skip_binder().ty); let all_types: Vec<_> = input_types.chain(assoc_types) .collect(); @@ -2305,7 +2296,7 @@ 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) => { + ty::TyDynamic(ref data, ..) => { data.principal().unwrap().with_self_ty(self.tcx(), self_ty) } _ => { @@ -2474,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::new( - data_a.principal(), - data_b.region_bound, - data_b.auto_traits().collect(), - data_a.projection_bounds.clone(), - )); + // Binders reintroduced below in call to mk_existential_predicates. + let principal = data_a.skip_binder().principal(); + let iter = principal.into_iter().map(ty::ExistentialPredicate::Trait) + .chain(data_a.skip_binder().projection_bounds() + .map(|x| ty::ExistentialPredicate::Projection(x))) + .chain(data_b.auto_traits().map(ty::ExistentialPredicate::AutoTrait)); + let new_trait = tcx.mk_dynamic( + ty::Binder(tcx.mk_existential_predicates(iter)), r_b); let InferOk { obligations, .. } = self.infcx.sub_types(false, &obligation.cause, new_trait, target) .map_err(|_| Unimplemented)?; @@ -2491,17 +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.auto_traits().chain(data.principal().map(|ref p| p.def_id())); + data.auto_traits().chain(data.principal().map(|p| p.def_id())); if let Some(did) = object_dids.find(|did| { !tcx.is_object_safe(*did) }) { @@ -2517,35 +2509,27 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { predicate)); }; - // Create the obligation for casting from T to Trait. - push(data.principal().unwrap().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 trait_refs = data.auto_traits() - .chain(iter::once( - tcx.lang_items.require(lang_items::SizedTraitLangItem) - .unwrap_or_else(|msg| tcx.sess.fatal(&msg[..])))) - .map(|did| ty::TraitRef { - def_id: did, - substs: tcx.mk_substs_trait(source, &[]), - }); - - // Create additional obligations for all the various builtin - // bounds attached to the object cast. (In other words, if the - // object type is Foo+Send, this would create an obligation - // for the Send check.) - for tr in trait_refs { - push(tr.to_predicate()); - } - - // Create obligations for the projection predicates. - for bound in &data.projection_bounds { - push(bound.with_self_ty(tcx, source).to_predicate()); - } + let tr = ty::TraitRef { + def_id: tcx.lang_items.require(lang_items::SizedTraitLangItem) + .unwrap_or_else(|msg| tcx.sess.fatal(&msg[..])), + substs: tcx.mk_substs_trait(source, &[]), + }; + push(tr.to_predicate()); // If the type is `Foo+'a`, ensures that the type // being cast to `Foo+'a` outlives `'a`: - let outlives = ty::OutlivesPredicate(source, data.region_bound); + let outlives = ty::OutlivesPredicate(source, r); push(ty::Binder(outlives).to_predicate()); } diff --git a/src/librustc/ty/contents.rs b/src/librustc/ty/contents.rs index 9f80c2487fb..8c3cb792948 100644 --- a/src/librustc/ty/contents.rs +++ b/src/librustc/ty/contents.rs @@ -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 } diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index ea81c85ba6a..c23ee489a28 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -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, stability: TypedArena, layout: TypedArena, + existential_predicates: TypedArena>, // references generics: TypedArena>, @@ -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>>, stability: RefCell>, layout: RefCell>, + existential_predicates: RefCell>>>>, } 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> { } } +impl<'a, 'tcx> Lift<'tcx> for &'a Slice> { + type Lifted = &'tcx Slice>; + fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) + -> Option<&'tcx Slice>> { + 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 for Interned<'tcx, Region> { } } +impl<'tcx: 'lcx, 'lcx> Borrow<[ExistentialPredicate<'lcx>]> + for Interned<'tcx, Slice>> { + 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,24 +1471,27 @@ 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>>, + reg: &'tcx ty::Region + ) -> Ty<'tcx> { + self.mk_ty(TyDynamic(obj, reg)) } pub fn mk_projection(self, trait_ref: TraitRef<'tcx>, item_name: Name) - -> Ty<'tcx> { - // take a copy of substs so that we own the vectors inside - let inner = ProjectionTy { trait_ref: trait_ref, item_name: item_name }; - self.mk_ty(TyProjection(inner)) - } + -> Ty<'tcx> { + // take a copy of substs so that we own the vectors inside + let inner = ProjectionTy { trait_ref: trait_ref, item_name: item_name }; + self.mk_ty(TyProjection(inner)) + } pub fn mk_closure(self, closure_id: DefId, substs: &'tcx Substs<'tcx>) - -> Ty<'tcx> { + -> Ty<'tcx> { self.mk_closure_from_closure_substs(closure_id, ClosureSubsts { substs: substs }) @@ -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> { + 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> { if ts.len() == 0 { Slice::empty() @@ -1517,6 +1561,12 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } } + pub fn mk_existential_predicates], + &'tcx Slice>>>(self, iter: I) + -> I::Output { + iter.intern_with(|xs| self.intern_existential_predicates(xs)) + } + pub fn mk_type_list], &'tcx Slice>>>(self, iter: I) -> I::Output { iter.intern_with(|xs| self.intern_type_list(xs)) diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs index 8ef13e62901..125ee0a02c8 100644 --- a/src/librustc/ty/error.rs +++ b/src/librustc/ty/error.rs @@ -49,7 +49,8 @@ pub enum TypeError<'tcx> { CyclicTy, ProjectionNameMismatched(ExpectedFound), ProjectionBoundsLength(ExpectedFound), - TyParamDefaultMismatch(ExpectedFound>) + TyParamDefaultMismatch(ExpectedFound>), + ExistentialMismatch(ExpectedFound<&'tcx ty::Slice>>), } #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Debug, Copy)] @@ -164,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)) + } } } } @@ -200,7 +205,7 @@ impl<'a, 'gcx, 'lcx, 'tcx> ty::TyS<'tcx> { } ty::TyFnDef(..) => format!("fn item"), ty::TyFnPtr(_) => "fn pointer".to_string(), - ty::TyTrait(ref inner) => { + ty::TyDynamic(ref inner, ..) => { inner.principal().map_or_else(|| "trait".to_string(), |p| format!("trait {}", tcx.item_path_str(p.def_id()))) } diff --git a/src/librustc/ty/fast_reject.rs b/src/librustc/ty/fast_reject.rs index 3eab06dc674..9791ccb1013 100644 --- a/src/librustc/ty/fast_reject.rs +++ b/src/librustc/ty/fast_reject.rs @@ -59,7 +59,7 @@ 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) => { + ty::TyDynamic(ref trait_info, ..) => { trait_info.principal().map(|p| TraitSimplifiedType(p.def_id())) } ty::TyRef(_, mt) => { diff --git a/src/librustc/ty/flags.rs b/src/librustc/ty/flags.rs index 026bf64533c..2bcbccb7d05 100644 --- a/src/librustc/ty/flags.rs +++ b/src/librustc/ty/flags.rs @@ -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().unwrap().skip_binder().substs); - for projection_bound in &obj.projection_bounds { - let mut proj_computation = FlagComputation::new(); - proj_computation.add_existential_projection(&projection_bound.0); - self.add_bound_computation(&proj_computation); + for predicate in obj.skip_binder().iter() { + match *predicate { + ty::ExistentialPredicate::Trait(tr) => computation.add_substs(tr.substs), + ty::ExistentialPredicate::Projection(p) => { + let mut proj_computation = FlagComputation::new(); + proj_computation.add_existential_projection(&p); + self.add_bound_computation(&proj_computation); + } + ty::ExistentialPredicate::AutoTrait(_) => {} + } } self.add_bound_computation(&computation); - self.add_region(obj.region_bound); + self.add_region(r); } &ty::TyBox(tt) | &ty::TyArray(tt, _) | &ty::TySlice(tt) => { diff --git a/src/librustc/ty/item_path.rs b/src/librustc/ty/item_path.rs index d1e6f5b8cd1..440a3916786 100644 --- a/src/librustc/ty/item_path.rs +++ b/src/librustc/ty/item_path.rs @@ -316,7 +316,7 @@ pub fn characteristic_def_id_of_type(ty: Ty) -> Option { match ty.sty { ty::TyAdt(adt_def, _) => Some(adt_def.did), - ty::TyTrait(ref data) => data.principal().map(|ref p| p.def_id()), + ty::TyDynamic(data, ..) => data.principal().map(|p| p.def_id()), ty::TyArray(subty, _) | ty::TySlice(subty) | diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index bc3c5d6ed4e..8646bccf1e9 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -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 } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 4544cda0ae9..86fe14ea504 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -54,7 +54,7 @@ use hir::itemlikevisit::ItemLikeVisitor; pub use self::sty::{Binder, DebruijnIndex}; pub use self::sty::{BareFnTy, FnSig, PolyFnSig}; -pub use self::sty::{ClosureTy, InferTy, ParamTy, ProjectionTy, TraitObject}; +pub use self::sty::{ClosureTy, InferTy, ParamTy, ProjectionTy, ExistentialPredicate}; pub use self::sty::{ClosureSubsts, TypeAndMut}; pub use self::sty::{TraitRef, TypeVariants, PolyTraitRef}; pub use self::sty::{ExistentialTraitRef, PolyExistentialTraitRef}; @@ -1712,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] } diff --git a/src/librustc/ty/outlives.rs b/src/librustc/ty/outlives.rs index e3d13f59395..eb384eec6a6 100644 --- a/src/librustc/ty/outlives.rs +++ b/src/librustc/ty/outlives.rs @@ -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 diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs index 02704e94fee..8cb1483107f 100644 --- a/src/librustc/ty/relate.rs +++ b/src/librustc/ty/relate.rs @@ -398,26 +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 = match (a_obj.principal(), b_obj.principal()) { - (Some(ref a_p), Some(ref b_p)) => Some(relation.relate(a_p, b_p)?), - (None, None) => None, - _ => return Err(TypeError::Sorts(expected_found(relation, &a, &b))), - }; - let r = - relation.with_cause( - Cause::ExistentialRegionBound, - |relation| relation.relate_with_variance(ty::Contravariant, - &a_obj.region_bound, - &b_obj.region_bound))?; - let nb = if !a_obj.auto_traits().eq(b_obj.auto_traits()) { - return Err(TypeError::Sorts(expected_found(relation, &a, &b))); - } else { - a_obj.auto_traits().collect() - }; - let pb = relation.relate(&a_obj.projection_bounds, &b_obj.projection_bounds)?; - Ok(tcx.mk_trait(ty::TraitObject::new(principal, r, nb, pb))) + (&ty::TyDynamic(ref a_obj, ref a_region), &ty::TyDynamic(ref b_obj, ref b_region)) => { + let region_bound = relation.with_cause(Cause::ExistentialRegionBound, + |relation| { + relation.relate_with_variance( + ty::Contravariant, + a_region, + b_region) + })?; + Ok(tcx.mk_dynamic(relation.relate(a_obj, b_obj)?, region_bound)) } (&ty::TyClosure(a_id, a_substs), @@ -513,6 +502,31 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R, } } +impl<'tcx> Relate<'tcx> for &'tcx ty::Slice> { + 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>, diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index e890d750a7b..88de3575274 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -324,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) }) } } @@ -426,20 +427,33 @@ impl<'tcx, T:TypeFoldable<'tcx>> TypeFoldable<'tcx> for ty::Binder { } } -impl<'tcx> TypeFoldable<'tcx> for ty::TraitObject<'tcx> { +impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::Slice> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { - ty::TraitObject::new( - self.principal().map(|p| p.fold_with(folder)), - self.region_bound.fold_with(folder), - self.auto_traits().collect(), - self.projection_bounds.fold_with(folder), - ) + let v = self.iter().map(|p| p.fold_with(folder)).collect::>(); + folder.tcx().intern_existential_predicates(&v) } fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.principal().map(|p| p.visit_with(visitor)).unwrap_or(true) || - self.region_bound.visit_with(visitor) || - self.projection_bounds.visit_with(visitor) + self.iter().any(|p| p.visit_with(visitor)) + } +} + +impl<'tcx> TypeFoldable<'tcx> for ty::ExistentialPredicate<'tcx> { + fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { + use ty::ExistentialPredicate::*; + match *self { + Trait(ref tr) => Trait(tr.fold_with(folder)), + Projection(ref p) => Projection(p.fold_with(folder)), + AutoTrait(did) => AutoTrait(did), + } + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + match *self { + ty::ExistentialPredicate::Trait(ref tr) => tr.visit_with(visitor), + ty::ExistentialPredicate::Projection(ref p) => p.visit_with(visitor), + ty::ExistentialPredicate::AutoTrait(_) => false, + } } } @@ -462,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, @@ -499,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) diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index e6411ca1e4f..667db5b6730 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -16,8 +16,11 @@ use middle::region; use ty::subst::Substs; use ty::{self, AdtDef, TypeFlags, Ty, TyCtxt, TypeFoldable}; use ty::{Slice, TyS}; +use ty::subst::Kind; use std::fmt; +use std::iter; +use std::cmp::Ordering; use syntax::abi; use syntax::ast::{self, Name, NodeId}; use syntax::symbol::{keywords, InternedString}; @@ -144,7 +147,7 @@ pub enum TypeVariants<'tcx> { TyFnPtr(&'tcx BareFnTy<'tcx>), /// A trait, defined with `trait`. - TyTrait(Box>), + TyDynamic(Binder<&'tcx Slice>>, &'tcx ty::Region), /// The anonymous type of a closure. Used to represent the type of /// `|a| a`. @@ -272,32 +275,103 @@ impl<'a, 'gcx, 'acx, 'tcx> ClosureSubsts<'tcx> { } } -#[derive(Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] -pub struct TraitObject<'tcx> { - principal: Option>, - pub region_bound: &'tcx ty::Region, - auto_traits: Vec, - pub projection_bounds: Vec>, +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] +pub enum ExistentialPredicate<'tcx> { + // e.g. Iterator + Trait(ExistentialTraitRef<'tcx>), + // e.g. Iterator::Item = T + Projection(ExistentialProjection<'tcx>), + // e.g. Send + AutoTrait(DefId), } -impl<'tcx> TraitObject<'tcx> { - pub fn new(principal: Option>, region_bound: &'tcx ty::Region, - auto_traits: Vec, projection_bounds: Vec>) - -> Self { - TraitObject { - principal: principal, - region_bound: region_bound, - auto_traits: auto_traits, - projection_bounds: projection_bounds, +impl<'a, 'gcx, 'tcx> ExistentialPredicate<'tcx> { + pub fn cmp(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, other: &Self) -> Ordering { + use self::ExistentialPredicate::*; + match (*self, *other) { + (Trait(_), Trait(_)) => Ordering::Equal, + (Projection(ref a), Projection(ref b)) => a.sort_key(tcx).cmp(&b.sort_key(tcx)), + (AutoTrait(ref a), AutoTrait(ref b)) => + tcx.lookup_trait_def(*a).def_path_hash.cmp(&tcx.lookup_trait_def(*b).def_path_hash), + (Trait(_), _) => Ordering::Less, + (Projection(_), Trait(_)) => Ordering::Greater, + (Projection(_), _) => Ordering::Less, + (AutoTrait(_), _) => Ordering::Greater, } } - pub fn principal(&self) -> Option> { - self.principal +} + +impl<'a, 'gcx, 'tcx> Binder> { + 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> {} + +impl<'tcx> Slice> { + pub fn principal(&self) -> Option> { + match self.get(0) { + Some(&ExistentialPredicate::Trait(tr)) => Some(tr), + _ => None + } } + #[inline] + pub fn projection_bounds<'a>(&'a self) -> + impl Iterator> + 'a { + self.iter().filter_map(|predicate| { + match *predicate { + ExistentialPredicate::Projection(p) => Some(p), + _ => None, + } + }) + } + + #[inline] pub fn auto_traits<'a>(&'a self) -> impl Iterator + 'a { - self.auto_traits.iter().cloned() + self.iter().filter_map(|predicate| { + match *predicate { + ExistentialPredicate::AutoTrait(d) => Some(d), + _ => None + } + }) + } +} + +impl<'tcx> Binder<&'tcx Slice>> { + pub fn principal(&self) -> Option> { + self.skip_binder().principal().map(Binder) + } + + #[inline] + pub fn projection_bounds<'a>(&'a self) -> + impl Iterator> + 'a { + self.skip_binder().projection_bounds().map(Binder) + } + + #[inline] + pub fn auto_traits<'a>(&'a self) -> impl Iterator + 'a { + self.skip_binder().auto_traits() + } + + pub fn iter<'a>(&'a self) + -> impl DoubleEndedIterator>> + 'tcx { + self.skip_binder().iter().cloned().map(Binder) } } @@ -362,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> + 'a { +impl<'a, 'gcx, 'tcx> ExistentialTraitRef<'tcx> { + pub fn input_types<'b>(&'b self) -> impl DoubleEndedIterator> + '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>; @@ -731,61 +821,53 @@ pub struct ExistentialProjection<'tcx> { pub type PolyExistentialProjection<'tcx> = Binder>; -impl<'a, 'tcx, 'gcx> PolyExistentialProjection<'tcx> { +impl<'a, 'tcx, 'gcx> ExistentialProjection<'tcx> { pub fn item_name(&self) -> Name { - self.0.item_name // safe to skip the binder to access a name + self.item_name // safe to skip the binder to access a name } pub fn sort_key(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> (u64, InternedString) { // We want something here that is stable across crate boundaries. // The DefId isn't but the `deterministic_hash` of the corresponding // DefPath is. - let trait_def = tcx.lookup_trait_def(self.0.trait_ref.def_id); + let trait_def = tcx.lookup_trait_def(self.trait_ref.def_id); let def_path_hash = trait_def.def_path_hash; // An `ast::Name` is also not stable (it's just an index into an // interning table), so map to the corresponding `InternedString`. - let item_name = self.0.item_name.as_str(); + let item_name = self.item_name.as_str(); (def_path_hash, item_name) } pub fn with_self_ty(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, self_ty: Ty<'tcx>) - -> ty::PolyProjectionPredicate<'tcx> + -> ty::ProjectionPredicate<'tcx> { // otherwise the escaping regions would be captured by the binders assert!(!self_ty.has_escaping_regions()); - let trait_ref = self.map_bound(|proj| proj.trait_ref); - self.map_bound(|proj| ty::ProjectionPredicate { + ty::ProjectionPredicate { projection_ty: ty::ProjectionTy { - trait_ref: trait_ref.with_self_ty(tcx, self_ty).0, - item_name: proj.item_name + trait_ref: self.trait_ref.with_self_ty(tcx, self_ty), + item_name: self.item_name }, - ty: proj.ty - }) + ty: self.ty + } } } -impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { - pub fn try_add_builtin_trait(self, - id: DefId, - auto_traits: &mut Vec) - -> bool - { - //! Checks whether `id` refers to one of the builtin - //! traits, like `Send`, and adds it to `auto_traits` if so. - //! Returns true if `idf` refers to a builtin trait. +impl<'a, 'tcx, 'gcx> PolyExistentialProjection<'tcx> { + pub fn item_name(&self) -> Name { + self.skip_binder().item_name() + } - if Some(id) == self.lang_items.send_trait() || - Some(id) == self.lang_items.sized_trait() || - Some(id) == self.lang_items.copy_trait() || - Some(id) == self.lang_items.sync_trait() { - auto_traits.push(id); - true - } else { - false - } + 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)) } } @@ -1045,7 +1127,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { pub fn is_trait(&self) -> bool { match self.sty { - TyTrait(..) => true, + TyDynamic(..) => true, _ => false } } @@ -1178,7 +1260,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { pub fn ty_to_def_id(&self) -> Option { match self.sty { - TyTrait(ref tt) => tt.principal().map(|p| p.def_id()), + TyDynamic(ref tt, ..) => tt.principal().map(|p| p.def_id()), TyAdt(def, _) => Some(def.did), TyClosure(id, _) => Some(id), _ => None @@ -1200,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().unwrap().skip_binder().substs.regions()); + TyDynamic(ref obj, region) => { + let mut v = vec![region]; + if let Some(p) = obj.principal() { + v.extend(p.skip_binder().substs.regions()); + } v } TyAdt(_, substs) | TyAnon(_, substs) => { diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 350426e7f3e..ed9a327750a 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -532,8 +532,8 @@ 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) => { - if let Some(ref p) = data.principal() { + TyDynamic(ref data, ..) => { + if let Some(p) = data.principal() { self.def_id(p.def_id()); } for d in data.auto_traits() { @@ -641,7 +641,7 @@ 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(|| { @@ -684,7 +684,7 @@ 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 diff --git a/src/librustc/ty/walk.rs b/src/librustc/ty/walk.rs index 02f55c6e340..0848dcd2c8d 100644 --- a/src/librustc/ty/walk.rs +++ b/src/librustc/ty/walk.rs @@ -92,14 +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) => { - match obj.principal() { - Some(ref p) => stack.extend(p.input_types().rev()), - None => {} - } - stack.extend(obj.projection_bounds.iter().map(|pred| { - pred.0.ty - }).rev()); + ty::TyDynamic(ref obj, ..) => { + stack.extend(obj.iter().rev().flat_map(|predicate| { + let (substs, opt_ty) = match *predicate.skip_binder() { + ty::ExistentialPredicate::Trait(tr) => (tr.substs, None), + ty::ExistentialPredicate::Projection(p) => + (p.trait_ref.substs, Some(p.ty)), + ty::ExistentialPredicate::AutoTrait(_) => + // Empty iterator + (ty::Substs::empty(), None), + }; + + substs.types().rev().chain(opt_ty) + })); } ty::TyAdt(_, substs) | ty::TyAnon(_, substs) => { stack.extend(substs.types().rev()); diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs index d0bc2f07977..87a0339fff7 100644 --- a/src/librustc/ty/wf.rs +++ b/src/librustc/ty/wf.rs @@ -374,12 +374,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 @@ -388,7 +388,7 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { let cause = self.cause(traits::MiscObligation); let component_traits = - data.auto_traits().chain(data.principal().map(|ref p| p.def_id())); + data.auto_traits().chain(data.principal().map(|p| p.def_id())); self.out.extend( component_traits.map(|did| traits::Obligation::new( cause.clone(), @@ -450,7 +450,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>>, + region: &'tcx ty::Region) { // Imagine a type like this: // // trait Foo { } @@ -485,11 +487,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().unwrap(), - data.auto_traits()); + object_region_bounds(self.infcx.tcx, data); - let explicit_bound = data.region_bound; + let explicit_bound = region; for implicit_bound in implicit_bounds { let cause = self.cause(traits::ObjectTypeBound(ty, explicit_bound)); @@ -506,26 +506,23 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { /// they declare `trait SomeTrait : 'static`, for example, then /// `'static` would appear in the list. The hard work is done by /// `ty::required_region_bounds`, see that for more information. -pub fn object_region_bounds<'a, 'gcx, 'tcx, I>( +pub fn object_region_bounds<'a, 'gcx, 'tcx>( tcx: TyCtxt<'a, 'gcx, 'tcx>, - principal: ty::PolyExistentialTraitRef<'tcx>, - others: I) + existential_predicates: ty::Binder<&'tcx ty::Slice>>) -> Vec<&'tcx ty::Region> - where I: Iterator { // Since we don't actually *know* the self type for an object, // this "open(err)" serves as a kind of dummy standin -- basically // a skolemized type. let open_ty = tcx.mk_infer(ty::FreshTy(0)); - let mut predicates = others.map(|d| { - let trait_ref = ty::TraitRef { - def_id: d, - substs: tcx.mk_substs_trait(open_ty, &[]) - }; - trait_ref.to_predicate() - }).collect::>(); - 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) } diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 242342a7f93..d839df80a12 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -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,58 +297,23 @@ 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>); - -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>(&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> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { // Generate the main trait ref, including associated types. ty::tls::with(|tcx| { // Use a type that can't appear in defaults of type parameters. let dummy_self = tcx.mk_infer(ty::FreshTy(0)); - let principal = self.principal().and_then(|ref p| tcx.lift(p)) - .expect("could not lift TraitRef for printing") - .with_self_ty(tcx, dummy_self).0; - let projections = self.projection_bounds.iter().map(|p| { - tcx.lift(p) - .expect("could not lift projection for printing") - .with_self_ty(tcx, dummy_self).0 - }).collect(); - - let tap = ty::Binder(TraitAndProjections(principal, projections)); - in_binder(f, tcx, &ty::Binder(""), Some(tap))?; + if let Some(p) = self.principal() { + let principal = tcx.lift(&p).expect("could not lift TraitRef for printing") + .with_self_ty(tcx, dummy_self); + let projections = self.projection_bounds().map(|p| { + tcx.lift(&p) + .expect("could not lift projection for printing") + .with_self_ty(tcx, dummy_self) + }).collect::>(); + parameterized(f, principal.substs, principal.def_id, &projections)?; + } // Builtin bounds. for did in self.auto_traits() { @@ -359,16 +323,6 @@ impl<'tcx> fmt::Display for ty::TraitObject<'tcx> { Ok(()) })?; - // FIXME: It'd be nice to compute from context when this bound - // is implied, but that's non-trivial -- we'd perhaps have to - // use thread-local data of some kind? There are also - // advantages to just showing the region, since it makes - // people aware that it's there. - let bound = self.region_bound.to_string(); - if !bound.is_empty() { - write!(f, " + {}", bound)?; - } - Ok(()) } } @@ -455,45 +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)?; - } - - ty::tls::with(|tcx| { - for did in self.auto_traits() { - maybe_continue(f)?; - write!(f, " + {}", tcx.item_path_str(did))?; - } - - Ok(()) - })?; - - for projection_bound in &self.projection_bounds { - maybe_continue(f)?; - write!(f, "{:?}", projection_bound)?; - } - - Ok(()) - } -} - impl<'tcx> fmt::Debug for ty::Predicate<'tcx> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { @@ -746,6 +661,12 @@ impl fmt::Debug for ty::IntVarValue { } }*/ +impl<'tcx> fmt::Display for ty::Binder<&'tcx ty::Slice>> { + 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> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { ty::tls::with(|tcx| in_binder(f, tcx, self, tcx.lift(self))) @@ -865,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| { diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index 8aa5e9e0a94..6e9467d63dd 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -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") } diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index f59f2bcc074..1e3d12c50a3 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -416,6 +416,15 @@ impl<'a, 'tcx> SpecializedDecoder> for DecodeContext<'a, 'tcx> } } +impl<'a, 'tcx> SpecializedDecoder<&'tcx ty::Slice>> + for DecodeContext<'a, 'tcx> { + fn specialized_decode(&mut self) + -> Result<&'tcx ty::Slice>, 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) diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index a79f7e1733c..f1126e6fd25 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -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().unwrap().with_self_ty(ccx.tcx(), source); - let trait_ref = ccx.tcx().erase_regions(&trait_ref); - consts::ptrcast(meth::get_vtable(ccx, trait_ref), + (_, &ty::TyDynamic(ref data, ..)) => { + consts::ptrcast(meth::get_vtable(ccx, source, data.principal()), Type::vtable_ptr(ccx)) } _ => bug!("unsized_info: invalid unsizing {:?} -> {:?}", diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index ac8793c47e7..120e1a562eb 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -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>) { assert!(!trait_ty.needs_subst() && !impl_ty.needs_subst()); - if let ty::TyTrait(ref trait_ty) = trait_ty.sty { - let poly_trait_ref = trait_ty.principal().unwrap().with_self_ty(scx.tcx(), impl_ty); - let param_substs = scx.tcx().intern_substs(&[]); - - // Walk all methods of the trait, including those of its supertraits - let methods = traits::get_vtable_methods(scx.tcx(), poly_trait_ref); - let methods = methods.filter_map(|method| method) - .filter_map(|(def_id, substs)| do_static_dispatch(scx, def_id, substs, param_substs)) - .filter(|&(def_id, _)| can_have_local_instance(scx.tcx(), def_id)) - .map(|(def_id, substs)| create_fn_trans_item(scx, def_id, substs, param_substs)); - output.extend(methods); + if let ty::TyDynamic(ref trait_ty, ..) = trait_ty.sty { + if let Some(principal) = trait_ty.principal() { + let poly_trait_ref = principal.with_self_ty(scx.tcx(), impl_ty); + let param_substs = scx.tcx().intern_substs(&[]); + // Walk all methods of the trait, including those of its supertraits + let methods = traits::get_vtable_methods(scx.tcx(), poly_trait_ref); + let methods = methods.filter_map(|method| method) + .filter_map(|(def_id, substs)| do_static_dispatch(scx, def_id, substs, + param_substs)) + .filter(|&(def_id, _)| can_have_local_instance(scx.tcx(), def_id)) + .map(|(def_id, substs)| create_fn_trans_item(scx, def_id, substs, param_substs)); + output.extend(methods); + } // Also add the destructor let dg_type = glue::get_drop_glue_type(scx.tcx(), impl_ty); output.push(TransItem::DropGlue(DropGlueKind::Ty(dg_type))); diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index 771c5ef6d9d..c0d7c64bd19 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -95,7 +95,8 @@ pub struct LocalCrateContext<'tcx> { /// Cache instances of monomorphic and polymorphic items instances: RefCell, ValueRef>>, /// Cache generated vtables - vtables: RefCell, ValueRef>>, + vtables: RefCell, + Option>), ValueRef>>, /// Cache of constant strings, const_cstr_cache: RefCell>, @@ -800,7 +801,9 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { &self.local().instances } - pub fn vtables<'a>(&'a self) -> &'a RefCell, ValueRef>> { + pub fn vtables<'a>(&'a self) + -> &'a RefCell, + Option>), ValueRef>> { &self.local().vtables } diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs index 5af1b0faebc..8bbe50af065 100644 --- a/src/librustc_trans/debuginfo/metadata.rs +++ b/src/librustc_trans/debuginfo/metadata.rs @@ -432,7 +432,7 @@ fn trait_pointer_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, // But it does not describe the trait's methods. let containing_scope = match trait_type.sty { - ty::TyTrait(ref data) => if let Some(principal) = data.principal() { + ty::TyDynamic(ref data, ..) => if let Some(principal) = data.principal() { let def_id = principal.def_id(); get_namespace_and_span_for_item(cx, def_id).0 } else { @@ -523,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) @@ -538,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) diff --git a/src/librustc_trans/debuginfo/type_names.rs b/src/librustc_trans/debuginfo/type_names.rs index 1831125e8eb..80e6bd7aa29 100644 --- a/src/librustc_trans/debuginfo/type_names.rs +++ b/src/librustc_trans/debuginfo/type_names.rs @@ -93,7 +93,7 @@ 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( &principal); diff --git a/src/librustc_trans/glue.rs b/src/librustc_trans/glue.rs index d6d4d33923f..06d0b1e1982 100644 --- a/src/librustc_trans/glue.rs +++ b/src/librustc_trans/glue.rs @@ -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. diff --git a/src/librustc_trans/meth.rs b/src/librustc_trans/meth.rs index 1e687f5ff6e..aa9b900fa46 100644 --- a/src/librustc_trans/meth.rs +++ b/src/librustc_trans/meth.rs @@ -110,42 +110,48 @@ pub fn trans_object_shim<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>, /// making an object `Foo` from a value of type `Foo`, 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>) -> ValueRef { let tcx = ccx.tcx(); let _icx = push_ctxt("meth::get_vtable"); - debug!("get_vtable(trait_ref={:?})", trait_ref); + debug!("get_vtable(ty={:?}, trait_ref={:?})", ty, trait_ref); // Check the cache. - if let Some(&val) = ccx.vtables().borrow().get(&trait_ref) { + if let Some(&val) = ccx.vtables().borrow().get(&(ty, trait_ref)) { return val; } // Not in the cache. Build it. let nullptr = C_null(Type::nil(ccx).ptr_to()); - let methods = traits::get_vtable_methods(tcx, trait_ref).map(|opt_mth| { - opt_mth.map_or(nullptr, |(def_id, substs)| { - Callee::def(ccx, def_id, substs).reify(ccx) - }) - }); - let size_ty = sizing_type_of(ccx, trait_ref.self_ty()); + let size_ty = sizing_type_of(ccx, ty); let size = machine::llsize_of_alloc(ccx, size_ty); - let align = align_of(ccx, trait_ref.self_ty()); + let align = align_of(ccx, ty); - let components: Vec<_> = [ + let mut components: Vec<_> = [ // Generate a destructor for the vtable. - glue::get_drop_glue(ccx, trait_ref.self_ty()), + glue::get_drop_glue(ccx, ty), C_uint(ccx, size), C_uint(ccx, align) - ].iter().cloned().chain(methods).collect(); + ].iter().cloned().collect(); + + if let Some(trait_ref) = trait_ref { + let trait_ref = trait_ref.with_self_ty(tcx, ty); + let methods = traits::get_vtable_methods(tcx, trait_ref).map(|opt_mth| { + opt_mth.map_or(nullptr, |(def_id, substs)| { + Callee::def(ccx, def_id, substs).reify(ccx) + }) + }); + components.extend(methods); + } let vtable_const = C_struct(ccx, &components, false); let align = machine::llalign_of_pref(ccx, val_ty(vtable_const)); let vtable = consts::addr_of(ccx, vtable_const, align, "vtable"); - ccx.vtables().borrow_mut().insert(trait_ref, vtable); + ccx.vtables().borrow_mut().insert((ty, trait_ref), vtable); vtable } diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs index c46c6e6f769..979c2206fc1 100644 --- a/src/librustc_trans/trans_item.rs +++ b/src/librustc_trans/trans_item.rs @@ -457,11 +457,11 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> { self.push_type_name(inner_type, output); output.push(']'); }, - ty::TyTrait(ref trait_data) => { + ty::TyDynamic(ref trait_data, ..) => { if let Some(principal) = trait_data.principal() { self.push_def_path(principal.def_id(), output); self.push_type_params(principal.skip_binder().substs, - &trait_data.projection_bounds, + &trait_data.projection_bounds().collect::>()[..], output); } }, diff --git a/src/librustc_trans/type_of.rs b/src/librustc_trans/type_of.rs index 16d4f97200c..22c405fe254 100644 --- a/src/librustc_trans/type_of.rs +++ b/src/librustc_trans/type_of.rs @@ -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) => { diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index bffd85c57f7..986d817a10c 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -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}; @@ -1052,8 +1054,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { 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 +1072,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { ty: b.ty } }) - }).collect(); - - let region_bound = - self.compute_object_lifetime_bound(span, - ®ion_bounds, - existential_principal, - &auto_traits); - - let region_bound = match region_bound { - Some(r) => r, - None => { - tcx.mk_region(match rscope.object_lifetime_default(span) { - Some(r) => r, - None => { - span_err!(self.tcx().sess, span, E0228, - "the lifetime bound for this object type cannot be deduced \ - from context; please supply an explicit bound"); - ty::ReStatic - } - }) - } - }; - - debug!("region_bound: {:?}", region_bound); + }); // ensure the super predicates and stop if we encountered an error if self.ensure_super_predicates(span, principal.def_id()).is_err() { @@ -1135,12 +1114,37 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { .emit(); } - let ty = tcx.mk_trait(ty::TraitObject::new( - Some(existential_principal), - region_bound, - auto_traits, - existential_projections - )); + let mut v = + iter::once(ty::ExistentialPredicate::Trait(*existential_principal.skip_binder())) + .chain(auto_traits.into_iter().map(ty::ExistentialPredicate::AutoTrait)) + .chain(existential_projections + .map(|x| ty::ExistentialPredicate::Projection(*x.skip_binder()))) + .collect::>(); + v.sort_by(|a, b| a.cmp(tcx, b)); + let existential_predicates = ty::Binder(tcx.mk_existential_predicates(v.into_iter())); + + let region_bound = self.compute_object_lifetime_bound(span, + ®ion_bounds, + existential_predicates); + + let region_bound = match region_bound { + Some(r) => r, + None => { + tcx.mk_region(match rscope.object_lifetime_default(span) { + Some(r) => r, + None => { + span_err!(self.tcx().sess, span, E0228, + "the lifetime bound for this object type cannot be deduced \ + from context; please supply an explicit bound"); + ty::ReStatic + } + }) + } + }; + + debug!("region_bound: {:?}", region_bound); + + let ty = tcx.mk_dynamic(existential_predicates, region_bound); debug!("trait_object_type: {:?}", ty); ty } @@ -1922,38 +1926,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>, - auto_traits: &[DefId]) + existential_predicates: ty::Binder<&'tcx ty::Slice>>) -> Option<&'tcx ty::Region> // if None, use the default { let tcx = self.tcx(); debug!("compute_opt_region_bound(explicit_region_bounds={:?}, \ - principal_trait_ref={:?}, auto_traits={:?})", + existential_predicates={:?})", explicit_region_bounds, - principal_trait_ref, - auto_traits); + existential_predicates); if explicit_region_bounds.len() > 1 { span_err!(tcx.sess, explicit_region_bounds[1].span, E0226, "only a single explicit lifetime bound is permitted"); } - if !explicit_region_bounds.is_empty() { + if let Some(&r) = explicit_region_bounds.get(0) { // Explicitly specified region bound. Use that. - let r = explicit_region_bounds[0]; return Some(ast_region_to_region(tcx, r)); } - if let Err(ErrorReported) = - self.ensure_super_predicates(span, principal_trait_ref.def_id()) { - return Some(tcx.mk_region(ty::ReStatic)); + if let Some(principal) = existential_predicates.principal() { + if let Err(ErrorReported) = self.ensure_super_predicates(span, principal.def_id()) { + return Some(tcx.mk_region(ty::ReStatic)); + } } // No explicit region bound specified. Therefore, examine trait // bounds and see if we can derive region bounds from those. let derived_region_bounds = - object_region_bounds(tcx, principal_trait_ref, auto_traits.into_iter().cloned()); + object_region_bounds(tcx, existential_predicates); // If there are no derived region bounds, then report back that we // can find no region bound. The caller will use the default. @@ -2000,7 +2002,11 @@ pub fn partition_bounds<'a, 'b, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, hir::TraitTyParamBound(ref b, hir::TraitBoundModifier::None) => { match b.trait_ref.path.def { Def::Trait(trait_did) => { - if tcx.try_add_builtin_trait(trait_did, &mut auto_traits) { + // Checks whether `trait_did` refers to one of the builtin + // traits, like `Send`, and adds it to `auto_traits` if so. + if Some(trait_did) == tcx.lang_items.send_trait() || + Some(trait_did) == tcx.lang_items.sync_trait() { + auto_traits.push(trait_did); let segments = &b.trait_ref.path.segments; let parameters = &segments[segments.len() - 1].parameters; if !parameters.types().is_empty() { @@ -2115,12 +2121,15 @@ impl<'a, 'gcx, 'tcx> Bounds<'tcx> { { let mut vec = Vec::new(); - for trait_did in &self.auto_traits { - let trait_ref = ty::TraitRef { - def_id: *trait_did, - substs: tcx.mk_substs_trait(param_ty, &[]), - }; - vec.push(trait_ref.to_predicate()); + // If it could be sized, and is, add the sized predicate + if self.implicitly_sized { + if let Some(sized) = tcx.lang_items.sized_trait() { + let trait_ref = ty::TraitRef { + def_id: sized, + substs: tcx.mk_substs_trait(param_ty, &[]) + }; + vec.push(trait_ref.to_predicate()); + } } for ®ion_bound in &self.region_bounds { diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 63e797a87ff..6e2b42881a7 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -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", an error. let type_str = self.ty_to_string(expected); diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index 197e7793f4b..5f904f507e2 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -65,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), Length, /// The unsize info of this projection OfProjection(&'tcx ty::ProjectionTy<'tcx>), @@ -79,7 +79,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { fn unsize_kind(&self, t: Ty<'tcx>) -> Option> { match t.sty { ty::TySlice(_) | ty::TyStr => Some(UnsizeKind::Length), - ty::TyTrait(ref tty) => Some(UnsizeKind::Vtable(tty.principal().unwrap().def_id())), + ty::TyDynamic(ref tty, ..) => + Some(UnsizeKind::Vtable(tty.principal().map(|p| p.def_id()))), ty::TyAdt(def, substs) if def.is_struct() => { // FIXME(arielb1): do some kind of normalization match def.struct_variant().fields.last() { @@ -130,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) } diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index be6d65bf511..744d99fe60d 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -111,16 +111,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().unwrap().def_id()); + let kind = object_type.principal() + .and_then(|p| self.tcx.lang_items.fn_trait_kind(p.def_id())); (sig, kind) } ty::TyInfer(ty::TyVar(vid)) => self.deduce_expectations_from_obligations(vid), diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index 8868d1e54f4..a5446b0fbaa 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -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; }, diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index 4c19ea46e5a..ff9eaa012ba 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -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) => data.principal().map(|p| closure(self, ty, p)), + ty::TyDynamic(ref data, ..) => data.principal().map(|p| closure(self, ty, p)), _ => None, } }) diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index b76d13125b4..b0787d75c9c 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -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().unwrap()); - self.assemble_inherent_impl_candidates_for_type(data.principal().unwrap().def_id()); + ty::TyDynamic(ref data, ..) => { + if let Some(p) = data.principal() { + self.assemble_inherent_candidates_from_object(self_ty, p); + self.assemble_inherent_impl_candidates_for_type(p.def_id()); + } } ty::TyAdt(def, _) => { self.assemble_inherent_impl_candidates_for_type(def.did); diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index 508b0e820ce..9443e0a3586 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -379,8 +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().map(|p| - p.def_id().is_local()).unwrap_or(false), + ty::TyDynamic(ref tr, ..) => tr.principal() + .map_or(false, |p| p.def_id().is_local()), ty::TyParam(_) => true, diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index c921936800b..bad7b4d96ca 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -269,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) diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index ca33682480c..fb35cb8181c 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -806,11 +806,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), diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 57859f9c84c..f29965ee47c 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -118,15 +118,8 @@ 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); - let sync_trait = ccx.tcx.lang_items.require(lang_items::SyncTraitLangItem) - .unwrap_or_else(|msg| ccx.tcx.sess.fatal(&msg[..])); - let send_trait = ccx.tcx.lang_items.require(lang_items::SendTraitLangItem) - .unwrap_or_else(|msg| ccx.tcx.sess.fatal(&msg[..])); - if trait_ref.def_id != sync_trait && trait_ref.def_id != send_trait { - if !ccx.tcx.trait_has_default_impl(trait_ref.def_id) { - error_192(ccx, item.span); - } + if !ccx.tcx.trait_has_default_impl(trait_ref.def_id) { + error_192(ccx, item.span); } } hir::ItemFn(.., ref body) => { diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index 0b6f2f554a1..30472f85db1 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -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) => t.principal().map(|p| p.def_id()), + TyDynamic(ref t, ..) => t.principal().map(|p| p.def_id()), TyBox(_) => self.inference_context.tcx.lang_items.owned_box(), diff --git a/src/librustc_typeck/coherence/orphan.rs b/src/librustc_typeck/coherence/orphan.rs index f949a8796c7..f04442de09c 100644 --- a/src/librustc_typeck/coherence/orphan.rs +++ b/src/librustc_typeck/coherence/orphan.rs @@ -86,7 +86,7 @@ impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> { ty::TyAdt(def, _) => { self.check_def_id(item, def.did); } - ty::TyTrait(ref data) if data.principal().is_some() => { + ty::TyDynamic(ref data, ..) if data.principal().is_some() => { self.check_def_id(item, data.principal().unwrap().def_id()); } ty::TyBox(..) => { diff --git a/src/librustc_typeck/coherence/overlap.rs b/src/librustc_typeck/coherence/overlap.rs index 5ae233f6479..815811675a5 100644 --- a/src/librustc_typeck/coherence/overlap.rs +++ b/src/librustc_typeck/coherence/overlap.rs @@ -178,16 +178,13 @@ 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 data.principal().is_none() || - !self.tcx.is_object_safe(data.principal().unwrap().def_id()) { - // This is an error, but it will be - // reported by wfcheck. Ignore it - // here. This is tested by - // `coherence-impl-trait-for-trait-object-safe.rs`. + if data.principal().map_or(true, |p| !self.tcx.is_object_safe(p.def_id())) { + // This is an error, but it will be reported by wfcheck. Ignore it here. + // This is tested by `coherence-impl-trait-for-trait-object-safe.rs`. } else { let mut supertrait_def_ids = traits::supertrait_def_ids(self.tcx, diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 0f8fe32c898..2b69ac12a2c 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1617,12 +1617,11 @@ 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); + bounds.push(kind_id.unwrap()); } // No lang item for Sized, so we can't add it as a bound. None => {} diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 04314045733..01e99a296e8 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -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: ``` diff --git a/src/librustc_typeck/variance/constraints.rs b/src/librustc_typeck/variance/constraints.rs index 076d024c1e1..f34753c227d 100644 --- a/src/librustc_typeck/variance/constraints.rs +++ b/src/librustc_typeck/variance/constraints.rs @@ -371,16 +371,17 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { variance); } - ty::TyTrait(ref data) => { + ty::TyDynamic(ref data, r) => { // The type `Foo` is contravariant w/r/t `'a`: let contra = self.contravariant(variance); - self.add_constraints_from_region(generics, data.region_bound, contra); + self.add_constraints_from_region(generics, r, contra); - let poly_trait_ref = data.principal().unwrap().with_self_ty(self.tcx(), - self.tcx().types.err); - self.add_constraints_from_trait_ref(generics, poly_trait_ref.0, variance); + if let Some(p) = data.principal() { + let poly_trait_ref = p.with_self_ty(self.tcx(), self.tcx().types.err); + self.add_constraints_from_trait_ref(generics, poly_trait_ref.0, variance); + } - for projection in &data.projection_bounds { + for projection in data.projection_bounds() { self.add_constraints_from_ty(generics, projection.0.ty, self.invariant); } } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 9d98cdd3f03..b9ba7f732a6 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -594,10 +594,10 @@ pub enum TyParamBound { impl TyParamBound { fn maybe_sized(cx: &DocContext) -> TyParamBound { - let did = cx.tcx().lang_items.require(lang_items::SizedTraitLangItem) - .unwrap_or_else(|msg| cx.tcx().sess.fatal(&msg[..])); - let empty = cx.tcx().intern_substs(&[]); - let path = external_path(cx, &cx.tcx().item_name(did).as_str(), + let did = cx.tcx.lang_items.require(lang_items::SizedTraitLangItem) + .unwrap_or_else(|msg| cx.tcx.sess.fatal(&msg[..])); + let empty = cx.tcx.intern_substs(&[]); + let path = external_path(cx, &cx.tcx.item_name(did).as_str(), Some(did), false, vec![], empty); inline::record_extern_fqn(cx, did, TypeKind::Trait); TraitBound(PolyTrait { @@ -1855,23 +1855,16 @@ impl<'tcx> Clean for ty::Ty<'tcx> { is_generic: false, } } - ty::TyTrait(ref obj) => { + ty::TyDynamic(ref obj, ref reg) => { if let Some(principal) = obj.principal() { let did = principal.def_id(); inline::record_extern_fqn(cx, did, TypeKind::Trait); let mut typarams = vec![]; - obj.region_bound.clean(cx).map(|b| typarams.push(RegionBound(b))); + reg.clean(cx).map(|b| typarams.push(RegionBound(b))); for did in obj.auto_traits() { - let tcx = match cx.tcx_opt() { - Some(tcx) => tcx, - None => { - typarams.push(RegionBound(Lifetime::statik())); - continue; - } - }; - let empty = tcx.intern_substs(&[]); - let path = external_path(cx, &tcx.item_name(did).as_str(), + let empty = cx.tcx.intern_substs(&[]); + let path = external_path(cx, &cx.tcx.item_name(did).as_str(), Some(did), false, vec![], empty); inline::record_extern_fqn(cx, did, TypeKind::Trait); let bound = TraitBound(PolyTrait { @@ -1887,14 +1880,14 @@ impl<'tcx> Clean for ty::Ty<'tcx> { } let mut bindings = vec![]; - for &ty::Binder(ref pb) in &obj.projection_bounds { + for ty::Binder(ref pb) in obj.projection_bounds() { bindings.push(TypeBinding { name: pb.item_name.clean(cx), ty: pb.ty.clean(cx) }); } - let path = external_path(cx, &cx.tcx().item_name(did).as_str(), Some(did), + let path = external_path(cx, &cx.tcx.item_name(did).as_str(), Some(did), false, bindings, principal.0.substs); ResolvedPath { path: path, diff --git a/src/test/compile-fail/E0225.rs b/src/test/compile-fail/E0225.rs index b013788ceff..8c79c15e3de 100644 --- a/src/test/compile-fail/E0225.rs +++ b/src/test/compile-fail/E0225.rs @@ -10,6 +10,6 @@ fn main() { let _: Box; - //~^ 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 } diff --git a/src/test/compile-fail/bad-sized.rs b/src/test/compile-fail/bad-sized.rs index 59a039057f3..a2e2e5caafe 100644 --- a/src/test/compile-fail/bad-sized.rs +++ b/src/test/compile-fail/bad-sized.rs @@ -12,8 +12,7 @@ trait Trait {} pub fn main() { let x: Vec = Vec::new(); - //~^ ERROR the trait bound `Trait + std::marker::Sized: std::marker::Sized` is not satisfied - //~| ERROR the trait `std::marker::Sized` cannot be made into an object - //~| ERROR the trait bound `Trait + std::marker::Sized: std::marker::Sized` is not satisfied - //~| ERROR the trait `std::marker::Sized` cannot be made into an object + //~^ ERROR only Send/Sync traits can be used as additional traits in a trait object + //~| ERROR the trait bound `Trait: std::marker::Sized` is not satisfied + //~| ERROR the trait bound `Trait: std::marker::Sized` is not satisfied } diff --git a/src/test/compile-fail/issue-22560.rs b/src/test/compile-fail/issue-22560.rs index 45b110bf563..2ad804fc8ce 100644 --- a/src/test/compile-fail/issue-22560.rs +++ b/src/test/compile-fail/issue-22560.rs @@ -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() { } diff --git a/src/test/compile-fail/issue-32963.rs b/src/test/compile-fail/issue-32963.rs index 14ab0dd5f63..f146cfbe68b 100644 --- a/src/test/compile-fail/issue-32963.rs +++ b/src/test/compile-fail/issue-32963.rs @@ -16,6 +16,6 @@ fn size_of_copy() -> usize { mem::size_of::() } fn main() { size_of_copy::(); - //~^ ERROR the trait bound `Misc + std::marker::Copy: std::marker::Copy` is not satisfied - //~| ERROR the trait `std::marker::Copy` cannot be made into an object + //~^ ERROR only Send/Sync traits can be used as additional traits in a trait object + //~| ERROR the trait bound `Misc: std::marker::Copy` is not satisfied } diff --git a/src/test/compile-fail/trait-bounds-cant-coerce.rs b/src/test/compile-fail/trait-bounds-cant-coerce.rs index 0bfa328751a..9f832c7b6e5 100644 --- a/src/test/compile-fail/trait-bounds-cant-coerce.rs +++ b/src/test/compile-fail/trait-bounds-cant-coerce.rs @@ -24,7 +24,7 @@ fn d(x: Box) { a(x); //~ ERROR mismatched types [E0308] //~| NOTE expected type `Box` //~| NOTE found type `Box` - //~| NOTE expected trait Foo, found a different trait Foo + //~| NOTE expected trait `Foo + std::marker::Send`, found trait `Foo` } fn main() { } diff --git a/src/test/run-pass/auxiliary/issue13507.rs b/src/test/run-pass/auxiliary/issue13507.rs index ca1027b11ad..ba50aed42c3 100644 --- a/src/test/run-pass/auxiliary/issue13507.rs +++ b/src/test/run-pass/auxiliary/issue13507.rs @@ -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; }