diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index f79a212a473..3ae0252e990 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -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}; @@ -49,6 +50,7 @@ use std::fmt; use std::marker::PhantomData; use std::mem; use std::rc::Rc; +use std::iter; use syntax::abi::Abi; use hir; use util::nodemap::FxHashMap; @@ -1516,16 +1518,11 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { let self_ty = this.tcx().erase_late_bound_regions(&obligation.self_ty()); let poly_trait_ref = match self_ty.sty { ty::TyTrait(ref data) => { - match this.tcx().lang_items.to_builtin_kind(obligation.predicate.def_id()) { - Some(bound @ ty::BoundSend) | Some(bound @ ty::BoundSync) => { - if data.builtin_bounds.contains(&bound) { - debug!("assemble_candidates_from_object_ty: matched builtin bound, \ - pushing candidate"); - candidates.vec.push(BuiltinObjectCandidate); - return; - } - } - _ => {} + if data.auto_traits().any(|did| did == obligation.predicate.def_id()) { + debug!("assemble_candidates_from_object_ty: matched builtin bound, \ + pushing candidate"); + candidates.vec.push(BuiltinObjectCandidate); + return; } match data.principal() { @@ -1616,7 +1613,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // #2 (region bounds). match (data_a.principal(), data_b.principal()) { (Some(ref a), Some(ref b)) => a.def_id() == b.def_id() && - data_a.builtin_bounds.is_superset(&data_b.builtin_bounds), + data_b.auto_traits() + // All of a's auto traits need to be in b's auto traits. + .all(|b| data_a.auto_traits().any(|a| a == b)), _ => false } } @@ -2481,7 +2480,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { let new_trait = tcx.mk_trait(ty::TraitObject::new( data_a.principal(), data_b.region_bound, - data_b.builtin_bounds, + data_b.auto_traits().collect(), data_a.projection_bounds.clone(), )); let origin = TypeOrigin::Misc(obligation.cause.span); @@ -2504,10 +2503,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // T -> Trait. (_, &ty::TyTrait(ref data)) => { let mut object_dids = - data.builtin_bounds.iter().flat_map(|bound| { - tcx.lang_items.from_builtin_kind(bound).ok() - }) - .chain(data.principal().map(|ref p| p.def_id())); + data.auto_traits().chain(data.principal().map(|ref p| p.def_id())); if let Some(did) = object_dids.find(|did| { !tcx.is_object_safe(*did) }) { @@ -2527,19 +2523,21 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { push(data.principal().unwrap().with_self_ty(tcx, source).to_predicate()); // We can only make objects from sized types. - let mut builtin_bounds = data.builtin_bounds; - builtin_bounds.insert(ty::BoundSized); + let trait_refs = data.auto_traits() + .chain(iter::once( + tcx.lang_items.require(lang_items::SizedTraitLangItem) + .unwrap_or_else(|msg| tcx.sess.fatal(&msg[..])))) + .map(|did| ty::TraitRef { + def_id: did, + substs: tcx.mk_substs_trait(source, &[]), + }); // Create additional obligations for all the various builtin // bounds attached to the object cast. (In other words, if the // object type is Foo+Send, this would create an obligation // for the Send check.) - for bound in &builtin_bounds { - if let Ok(tr) = tcx.trait_ref_for_builtin_bound(bound, source) { - push(tr.to_predicate()); - } else { - return Err(Unimplemented); - } + for tr in trait_refs { + push(tr.to_predicate()); } // Create obligations for the projection predicates. diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs index a70cfabac87..569791a0776 100644 --- a/src/librustc/ty/relate.rs +++ b/src/librustc/ty/relate.rs @@ -428,7 +428,11 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R, |relation| relation.relate_with_variance(ty::Contravariant, &a_obj.region_bound, &b_obj.region_bound))?; - let nb = relation.relate(&a_obj.builtin_bounds, &b_obj.builtin_bounds)?; + let nb = if !a_obj.auto_traits().eq(b_obj.auto_traits()) { + return Err(TypeError::Sorts(expected_found(relation, &a, &b))); + } else { + a_obj.auto_traits().collect() + }; let pb = relation.relate(&a_obj.projection_bounds, &b_obj.projection_bounds)?; Ok(tcx.mk_trait(ty::TraitObject::new(principal, r, nb, pb))) } diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 883f43258d8..3064e337039 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -432,7 +432,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::TraitObject<'tcx> { ty::TraitObject::new( self.principal().map(|p| p.fold_with(folder)), self.region_bound.fold_with(folder), - self.builtin_bounds, + self.auto_traits().collect(), self.projection_bounds.fold_with(folder), ) } diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 454dedd937b..22a7423b177 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -279,18 +279,18 @@ impl<'a, 'gcx, 'acx, 'tcx> ClosureSubsts<'tcx> { pub struct TraitObject<'tcx> { principal: Option<PolyExistentialTraitRef<'tcx>>, pub region_bound: &'tcx ty::Region, - pub builtin_bounds: BuiltinBounds, + auto_traits: Vec<DefId>, pub projection_bounds: Vec<PolyExistentialProjection<'tcx>>, } impl<'tcx> TraitObject<'tcx> { pub fn new(principal: Option<PolyExistentialTraitRef<'tcx>>, region_bound: &'tcx ty::Region, - builtin_bounds: BuiltinBounds, projection_bounds: Vec<PolyExistentialProjection<'tcx>>) + auto_traits: Vec<DefId>, projection_bounds: Vec<PolyExistentialProjection<'tcx>>) -> Self { TraitObject { principal: principal, region_bound: region_bound, - builtin_bounds: builtin_bounds, + auto_traits: auto_traits, projection_bounds: projection_bounds, } } @@ -298,6 +298,10 @@ impl<'tcx> TraitObject<'tcx> { pub fn principal(&self) -> Option<PolyExistentialTraitRef<'tcx>> { self.principal } + + pub fn auto_traits<'a>(&'a self) -> impl Iterator<Item=DefId> + 'a { + self.auto_traits.iter().cloned() + } } /// A complete reference to a trait. These take numerous guises in syntax, @@ -833,18 +837,22 @@ impl CLike for BuiltinBound { impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn try_add_builtin_trait(self, - trait_def_id: DefId, - builtin_bounds: &mut EnumSet<BuiltinBound>) + id: DefId, + auto_traits: &mut Vec<DefId>) -> bool { - //! Checks whether `trait_ref` refers to one of the builtin - //! traits, like `Send`, and adds the corresponding - //! bound to the set `builtin_bounds` if so. Returns true if `trait_ref` - //! is a builtin trait. + //! 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. - match self.lang_items.to_builtin_kind(trait_def_id) { - Some(bound) => { builtin_bounds.insert(bound); true } - None => false + 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 } } } diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index bd7d72d3ef3..7253b88981f 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -535,7 +535,9 @@ impl<'a, 'gcx, 'tcx, H: Hasher> TypeVisitor<'tcx> for TypeIdHasher<'a, 'gcx, 'tc if let Some(ref p) = data.principal() { self.def_id(p.def_id()); } - self.hash(data.builtin_bounds); + for d in data.auto_traits() { + self.def_id(d); + } } TyTuple(tys) => { self.hash(tys.len()); diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs index 25015557ad4..b31046abf86 100644 --- a/src/librustc/ty/wf.rs +++ b/src/librustc/ty/wf.rs @@ -298,7 +298,6 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { /// is WF. Returns false if `ty0` is an unresolved type variable, /// in which case we are not able to simplify at all. fn compute(&mut self, ty0: Ty<'tcx>) -> bool { - let tcx = self.infcx.tcx; let mut subtys = ty0.walk(); while let Some(ty) = subtys.next() { match ty.sty { @@ -391,15 +390,12 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { let cause = self.cause(traits::MiscObligation); let component_traits = - data.builtin_bounds.iter().flat_map(|bound| { - tcx.lang_items.from_builtin_kind(bound).ok() - }) - .chain(data.principal().map(|ref p| p.def_id())); + data.auto_traits().chain(data.principal().map(|ref p| p.def_id())); self.out.extend( - component_traits.map(|did| { traits::Obligation::new( + component_traits.map(|did| traits::Obligation::new( cause.clone(), ty::Predicate::ObjectSafe(did) - )}) + )) ); } @@ -493,7 +489,7 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { let implicit_bounds = object_region_bounds(self.infcx.tcx, data.principal().unwrap(), - data.builtin_bounds); + data.auto_traits()); let explicit_bound = data.region_bound; @@ -512,18 +508,25 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { /// they declare `trait SomeTrait : 'static`, for example, then /// `'static` would appear in the list. The hard work is done by /// `ty::required_region_bounds`, see that for more information. -pub fn object_region_bounds<'a, 'gcx, 'tcx>( +pub fn object_region_bounds<'a, 'gcx, 'tcx, I>( tcx: TyCtxt<'a, 'gcx, 'tcx>, principal: ty::PolyExistentialTraitRef<'tcx>, - others: ty::BuiltinBounds) + others: I) -> Vec<&'tcx ty::Region> + where I: Iterator<Item=DefId> { // Since we don't actually *know* the self type for an object, // this "open(err)" serves as a kind of dummy standin -- basically // a skolemized type. let open_ty = tcx.mk_infer(ty::FreshTy(0)); - let mut predicates = others.to_predicates(tcx, open_ty); + let mut predicates = others.map(|d| { + let trait_ref = ty::TraitRef { + def_id: d, + substs: tcx.mk_substs_trait(open_ty, &[]) + }; + trait_ref.to_predicate() + }).collect::<Vec<_>>(); predicates.push(principal.with_self_ty(tcx, open_ty).to_predicate()); tcx.required_region_bounds(open_ty, predicates) diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index c87f3ba0a59..a3fa805699c 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -349,13 +349,15 @@ impl<'tcx> fmt::Display for ty::TraitObject<'tcx> { }).collect(); let tap = ty::Binder(TraitAndProjections(principal, projections)); - in_binder(f, tcx, &ty::Binder(""), Some(tap)) - })?; + in_binder(f, tcx, &ty::Binder(""), Some(tap))?; - // Builtin bounds. - for bound in &self.builtin_bounds { - write!(f, " + {:?}", bound)?; - } + // Builtin bounds. + for did in self.auto_traits() { + write!(f, " + {}", tcx.item_path_str(did))?; + } + + Ok(()) + })?; // FIXME: It'd be nice to compute from context when this bound // is implied, but that's non-trivial -- we'd perhaps have to @@ -474,10 +476,14 @@ impl<'tcx> fmt::Debug for ty::TraitObject<'tcx> { write!(f, "{}", region_str)?; } - for bound in &self.builtin_bounds { - maybe_continue(f)?; - write!(f, "{:?}", bound)?; - } + ty::tls::with(|tcx| { + for did in self.auto_traits() { + maybe_continue(f)?; + write!(f, " + {}", tcx.item_path_str(did))?; + } + + Ok(()) + })?; for projection_bound in &self.projection_bounds { maybe_continue(f)?; diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 9cf6f555744..bffd85c57f7 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -1043,7 +1043,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { trait_segment, &mut projection_bounds); - let PartitionedBounds { builtin_bounds, + let PartitionedBounds { auto_traits, trait_bounds, region_bounds } = partitioned_bounds; @@ -1076,7 +1076,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { self.compute_object_lifetime_bound(span, ®ion_bounds, existential_principal, - builtin_bounds); + &auto_traits); let region_bound = match region_bound { Some(r) => r, @@ -1138,7 +1138,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { let ty = tcx.mk_trait(ty::TraitObject::new( Some(existential_principal), region_bound, - builtin_bounds, + auto_traits, existential_projections )); debug!("trait_object_type: {:?}", ty); @@ -1923,16 +1923,16 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { span: Span, explicit_region_bounds: &[&hir::Lifetime], principal_trait_ref: ty::PolyExistentialTraitRef<'tcx>, - builtin_bounds: ty::BuiltinBounds) + auto_traits: &[DefId]) -> 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={:?})", + principal_trait_ref={:?}, auto_traits={:?})", explicit_region_bounds, principal_trait_ref, - builtin_bounds); + auto_traits); if explicit_region_bounds.len() > 1 { span_err!(tcx.sess, explicit_region_bounds[1].span, E0226, @@ -1953,7 +1953,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { // 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, principal_trait_ref, auto_traits.into_iter().cloned()); // If there are no derived region bounds, then report back that we // can find no region bound. The caller will use the default. @@ -1980,7 +1980,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { } pub struct PartitionedBounds<'a> { - pub builtin_bounds: ty::BuiltinBounds, + pub auto_traits: Vec<DefId>, pub trait_bounds: Vec<&'a hir::PolyTraitRef>, pub region_bounds: Vec<&'a hir::Lifetime>, } @@ -1992,7 +1992,7 @@ pub fn partition_bounds<'a, 'b, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, ast_bounds: &'b [hir::TyParamBound]) -> PartitionedBounds<'b> { - let mut builtin_bounds = ty::BuiltinBounds::empty(); + let mut auto_traits = Vec::new(); let mut region_bounds = Vec::new(); let mut trait_bounds = Vec::new(); for ast_bound in ast_bounds { @@ -2000,8 +2000,7 @@ 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 builtin_bounds) { + if tcx.try_add_builtin_trait(trait_did, &mut auto_traits) { let segments = &b.trait_ref.path.segments; let parameters = &segments[segments.len() - 1].parameters; if !parameters.types().is_empty() { @@ -2030,7 +2029,7 @@ pub fn partition_bounds<'a, 'b, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, } PartitionedBounds { - builtin_bounds: builtin_bounds, + auto_traits: auto_traits, trait_bounds: trait_bounds, region_bounds: region_bounds, } @@ -2105,7 +2104,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 auto_traits: Vec<DefId>, pub trait_bounds: Vec<ty::PolyTraitRef<'tcx>>, pub projection_bounds: Vec<ty::PolyProjectionPredicate<'tcx>>, } @@ -2116,11 +2115,12 @@ 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) => { } - } + 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()); } for ®ion_bound in &self.region_bounds { diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 0dcc0bcc316..0f8fe32c898 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1586,7 +1586,7 @@ fn convert_foreign_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, // 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, + bounds: &mut Vec<DefId>, ast_bounds: &[hir::TyParamBound], span: Span) { @@ -1908,13 +1908,13 @@ pub fn compute_bounds<'gcx: 'tcx, 'tcx>(astconv: &AstConv<'gcx, 'tcx>, { let tcx = astconv.tcx(); let PartitionedBounds { - mut builtin_bounds, + mut auto_traits, 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); + add_unsized_bound(astconv, &mut auto_traits, ast_bounds, span); } let mut projection_bounds = vec![]; @@ -1935,7 +1935,7 @@ pub fn compute_bounds<'gcx: 'tcx, 'tcx>(astconv: &AstConv<'gcx, 'tcx>, Bounds { region_bounds: region_bounds, - builtin_bounds: builtin_bounds, + auto_traits: auto_traits, trait_bounds: trait_bounds, projection_bounds: projection_bounds, } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index f32ee29c0a0..6b0f0ae1297 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1883,8 +1883,28 @@ impl<'tcx> Clean<Type> for ty::Ty<'tcx> { 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)); + 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(), + 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![];