diff --git a/src/librustc/middle/traits/mod.rs b/src/librustc/middle/traits/mod.rs index 24b201c960f1..ffc11efe7c71 100644 --- a/src/librustc/middle/traits/mod.rs +++ b/src/librustc/middle/traits/mod.rs @@ -48,6 +48,8 @@ pub use self::util::get_vtable_index_of_object_method; pub use self::util::trait_ref_for_builtin_bound; pub use self::util::supertraits; pub use self::util::Supertraits; +pub use self::util::supertrait_def_ids; +pub use self::util::SupertraitDefIds; pub use self::util::transitive_bounds; pub use self::util::upcast; @@ -640,7 +642,7 @@ impl<'tcx> FulfillmentError<'tcx> { } impl<'tcx> TraitObligation<'tcx> { - fn self_ty(&self) -> Ty<'tcx> { - self.predicate.0.self_ty() + fn self_ty(&self) -> ty::Binder> { + ty::Binder(self.predicate.skip_binder().self_ty()) } } diff --git a/src/librustc/middle/traits/object_safety.rs b/src/librustc/middle/traits/object_safety.rs index 881487a2dad1..9dccadc932bb 100644 --- a/src/librustc/middle/traits/object_safety.rs +++ b/src/librustc/middle/traits/object_safety.rs @@ -53,36 +53,36 @@ pub enum MethodViolationCode { } pub fn is_object_safe<'tcx>(tcx: &ty::ctxt<'tcx>, - trait_ref: ty::PolyTraitRef<'tcx>) + trait_def_id: ast::DefId) -> bool { // Because we query yes/no results frequently, we keep a cache: let cached_result = - tcx.object_safety_cache.borrow().get(&trait_ref.def_id()).cloned(); + tcx.object_safety_cache.borrow().get(&trait_def_id).cloned(); let result = cached_result.unwrap_or_else(|| { - let result = object_safety_violations(tcx, trait_ref.clone()).is_empty(); + let result = object_safety_violations(tcx, trait_def_id).is_empty(); // Record just a yes/no result in the cache; this is what is // queried most frequently. Note that this may overwrite a // previous result, but always with the same thing. - tcx.object_safety_cache.borrow_mut().insert(trait_ref.def_id(), result); + tcx.object_safety_cache.borrow_mut().insert(trait_def_id, result); result }); - debug!("is_object_safe({}) = {}", trait_ref.repr(tcx), result); + debug!("is_object_safe({}) = {}", trait_def_id.repr(tcx), result); result } pub fn object_safety_violations<'tcx>(tcx: &ty::ctxt<'tcx>, - sub_trait_ref: ty::PolyTraitRef<'tcx>) + trait_def_id: ast::DefId) -> Vec> { - supertraits(tcx, sub_trait_ref) - .flat_map(|tr| object_safety_violations_for_trait(tcx, tr.def_id()).into_iter()) + traits::supertrait_def_ids(tcx, trait_def_id) + .flat_map(|def_id| object_safety_violations_for_trait(tcx, def_id).into_iter()) .collect() } diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs index 6121a4419923..7e89534026ff 100644 --- a/src/librustc/middle/traits/select.rs +++ b/src/librustc/middle/traits/select.rs @@ -1237,7 +1237,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // self-type from one of the other inputs. Without this check, // these cases wind up being considered ambiguous due to a // (spurious) ambiguity introduced here. - if !object_safety::is_object_safe(self.tcx(), obligation.predicate.to_poly_trait_ref()) { + let predicate_trait_ref = obligation.predicate.to_poly_trait_ref(); + if !object_safety::is_object_safe(self.tcx(), predicate_trait_ref.def_id()) { return; } diff --git a/src/librustc/middle/traits/util.rs b/src/librustc/middle/traits/util.rs index 965aaf12044e..06b687bd92b9 100644 --- a/src/librustc/middle/traits/util.rs +++ b/src/librustc/middle/traits/util.rs @@ -209,6 +209,47 @@ pub fn transitive_bounds<'cx, 'tcx>(tcx: &'cx ty::ctxt<'tcx>, elaborate_trait_refs(tcx, bounds).filter_to_traits() } +/////////////////////////////////////////////////////////////////////////// +// Iterator over def-ids of supertraits + +pub struct SupertraitDefIds<'cx, 'tcx:'cx> { + tcx: &'cx ty::ctxt<'tcx>, + stack: Vec, + visited: FnvHashSet, +} + +pub fn supertrait_def_ids<'cx, 'tcx>(tcx: &'cx ty::ctxt<'tcx>, + trait_def_id: ast::DefId) + -> SupertraitDefIds<'cx, 'tcx> +{ + SupertraitDefIds { + tcx: tcx, + stack: vec![trait_def_id], + visited: Some(trait_def_id).into_iter().collect(), + } +} + +impl<'cx, 'tcx> Iterator for SupertraitDefIds<'cx, 'tcx> { + type Item = ast::DefId; + + fn next(&mut self) -> Option { + let def_id = match self.stack.pop() { + Some(def_id) => def_id, + None => { return None; } + }; + + let predicates = ty::lookup_super_predicates(self.tcx, def_id); + let visited = &mut self.visited; + self.stack.extend( + predicates.predicates + .iter() + .filter_map(|p| p.to_opt_poly_trait_ref()) + .map(|t| t.def_id()) + .filter(|&super_def_id| visited.insert(super_def_id))); + Some(def_id) + } +} + /////////////////////////////////////////////////////////////////////////// // Other /////////////////////////////////////////////////////////////////////////// diff --git a/src/librustc_typeck/check/vtable.rs b/src/librustc_typeck/check/vtable.rs index 2858dc9b569f..67461ff561bb 100644 --- a/src/librustc_typeck/check/vtable.rs +++ b/src/librustc_typeck/check/vtable.rs @@ -28,18 +28,17 @@ pub fn check_object_safety<'tcx>(tcx: &ty::ctxt<'tcx>, object_trait: &ty::TyTrait<'tcx>, span: Span) { - let object_trait_ref = - object_trait.principal_trait_ref_with_self_ty(tcx, tcx.types.err); + let trait_def_id = object_trait.principal_def_id(); - if traits::is_object_safe(tcx, object_trait_ref.clone()) { + if traits::is_object_safe(tcx, trait_def_id) { return; } span_err!(tcx.sess, span, E0038, "cannot convert to a trait object because trait `{}` is not object-safe", - ty::item_path_str(tcx, object_trait_ref.def_id())); + ty::item_path_str(tcx, trait_def_id)); - let violations = traits::object_safety_violations(tcx, object_trait_ref.clone()); + let violations = traits::object_safety_violations(tcx, trait_def_id); for violation in violations { match violation { ObjectSafetyViolation::SizedSelf => {