From a962d47ef8a93ad125571a5628a883d0b50a97e7 Mon Sep 17 00:00:00 2001 From: Flavio Percoco Date: Sat, 24 Jan 2015 14:17:24 +0100 Subject: [PATCH] look for default trait candidates --- src/librustc/metadata/csearch.rs | 4 ++++ src/librustc/metadata/decoder.rs | 9 ++++++++ src/librustc/middle/traits/mod.rs | 11 ++++++--- src/librustc/middle/traits/project.rs | 1 + src/librustc/middle/traits/select.rs | 16 ++++++++++++-- src/librustc/middle/traits/util.rs | 3 +++ src/librustc/middle/ty.rs | 32 ++++++++++++++++++++++++--- src/librustc/middle/ty_fold.rs | 1 + src/librustc_trans/trans/meth.rs | 3 +++ src/librustc_typeck/collect.rs | 3 +++ 10 files changed, 75 insertions(+), 8 deletions(-) diff --git a/src/librustc/metadata/csearch.rs b/src/librustc/metadata/csearch.rs index 7eeb0589118f..db7e0f4d60f9 100644 --- a/src/librustc/metadata/csearch.rs +++ b/src/librustc/metadata/csearch.rs @@ -410,3 +410,7 @@ pub fn is_associated_type(cstore: &cstore::CStore, def: ast::DefId) -> bool { decoder::is_associated_type(&*cdata, def.node) } +pub fn is_default_trait(cstore: &cstore::CStore, def: ast::DefId) -> bool { + let cdata = cstore.get_crate_data(def.krate); + decoder::is_default_trait(&*cdata, def.node) +} diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index d4512f51980e..065d78879f1b 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -1563,3 +1563,12 @@ pub fn is_associated_type(cdata: Cmd, id: ast::NodeId) -> bool { Some(item) => item_sort(item) == 't', } } + + +pub fn is_default_trait<'tcx>(cdata: Cmd, id: ast::NodeId) -> bool { + let item_doc = lookup_item(id, cdata.data()); + match item_family(item_doc) { + Family::DefTrait => true, + _ => false + } +} diff --git a/src/librustc/middle/traits/mod.rs b/src/librustc/middle/traits/mod.rs index a63dcfc24a10..9c71650c7be3 100644 --- a/src/librustc/middle/traits/mod.rs +++ b/src/librustc/middle/traits/mod.rs @@ -221,6 +221,9 @@ pub enum Vtable<'tcx, N> { /// Vtable identifying a particular impl. VtableImpl(VtableImplData<'tcx, N>), + /// Vtable for default trait implementations + VtableDefaultTrait(ast::DefId), + /// Successful resolution to an obligation provided by the caller /// for some type parameter. The `Vec` represents the /// obligations incurred from normalizing the where-clause (if @@ -513,17 +516,18 @@ impl<'tcx, N> Vtable<'tcx, N> { pub fn iter_nested(&self) -> Iter { match *self { VtableImpl(ref i) => i.iter_nested(), - VtableFnPointer(..) => (&[]).iter(), - VtableClosure(..) => (&[]).iter(), VtableParam(ref n) => n.iter(), - VtableObject(_) => (&[]).iter(), VtableBuiltin(ref i) => i.iter_nested(), + VtableObject(_) | + VtableDefaultTrait(..) | VtableFnPointer(..) | + VtableClosure(..) => (&[]).iter(), } } pub fn map_nested(&self, op: F) -> Vtable<'tcx, M> where F: FnMut(&N) -> M { match *self { VtableImpl(ref i) => VtableImpl(i.map_nested(op)), + VtableDefaultTrait(t) => VtableDefaultTrait(t), VtableFnPointer(ref sig) => VtableFnPointer((*sig).clone()), VtableClosure(d, ref s) => VtableClosure(d, s.clone()), VtableParam(ref n) => VtableParam(n.iter().map(op).collect()), @@ -539,6 +543,7 @@ impl<'tcx, N> Vtable<'tcx, N> { VtableImpl(i) => VtableImpl(i.map_move_nested(op)), VtableFnPointer(sig) => VtableFnPointer(sig), VtableClosure(d, s) => VtableClosure(d, s), + VtableDefaultTrait(t) => VtableDefaultTrait(t), VtableParam(n) => VtableParam(n.into_iter().map(op).collect()), VtableObject(p) => VtableObject(p), VtableBuiltin(no) => VtableBuiltin(no.map_move_nested(op)), diff --git a/src/librustc/middle/traits/project.rs b/src/librustc/middle/traits/project.rs index 13f309e129ac..ecfd02b69fc5 100644 --- a/src/librustc/middle/traits/project.rs +++ b/src/librustc/middle/traits/project.rs @@ -709,6 +709,7 @@ fn assemble_candidates_from_impls<'cx,'tcx>( // projection. And the projection where clause is handled // in `assemble_candidates_from_param_env`. } + super::VtableDefaultTrait(..) | super::VtableBuiltin(..) => { // These traits have no associated types. selcx.tcx().sess.span_bug( diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs index 0e2989208417..15a1e3ad34b2 100644 --- a/src/librustc/middle/traits/select.rs +++ b/src/librustc/middle/traits/select.rs @@ -26,7 +26,7 @@ use super::{SelectionError, Unimplemented, Overflow, OutputTypeParameterMismatch use super::{Selection}; use super::{SelectionResult}; use super::{VtableBuiltin, VtableImpl, VtableParam, VtableClosure, - VtableFnPointer, VtableObject}; + VtableFnPointer, VtableObject, VtableDefaultTrait}; use super::{VtableImplData, VtableObjectData, VtableBuiltinData}; use super::object_safety; use super::{util}; @@ -136,6 +136,7 @@ enum SelectionCandidate<'tcx> { BuiltinCandidate(ty::BuiltinBound), ParamCandidate(ty::PolyTraitRef<'tcx>), ImplCandidate(ast::DefId), + DefaultTraitCandidate(ast::DefId), /// This is a trait matching with a projected type as `Self`, and /// we found an applicable bound in the trait definition. @@ -1130,7 +1131,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let self_ty = self.infcx.shallow_resolve(obligation.self_ty()); debug!("assemble_candidates_from_impls(self_ty={})", self_ty.repr(self.tcx())); - let all_impls = self.all_impls(obligation.predicate.def_id()); + let def_id = obligation.predicate.def_id(); + let all_impls = self.all_impls(def_id); for &impl_def_id in &all_impls { self.infcx.probe(|snapshot| { let (skol_obligation_trait_pred, skol_map) = @@ -1144,6 +1146,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } }); } + + if self.tcx().default_trait_impls.borrow().contains(&def_id) { + candidates.vec.push(DefaultTraitCandidate(def_id.clone())) + } + Ok(()) } @@ -1646,6 +1653,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { Ok(VtableParam(obligations)) } + DefaultTraitCandidate(trait_def_id) => { + Ok(VtableDefaultTrait(trait_def_id)) + } + ImplCandidate(impl_def_id) => { let vtable_impl = try!(self.confirm_impl_candidate(obligation, impl_def_id)); @@ -2308,6 +2319,7 @@ impl<'tcx> Repr<'tcx> for SelectionCandidate<'tcx> { BuiltinCandidate(b) => format!("BuiltinCandidate({:?})", b), ParamCandidate(ref a) => format!("ParamCandidate({})", a.repr(tcx)), ImplCandidate(a) => format!("ImplCandidate({})", a.repr(tcx)), + DefaultTraitCandidate(t) => format!("DefaultTraitCandidate({:?})", t), ProjectionCandidate => format!("ProjectionCandidate"), FnPointerCandidate => format!("FnPointerCandidate"), ObjectCandidate => { diff --git a/src/librustc/middle/traits/util.rs b/src/librustc/middle/traits/util.rs index 6c54da1c134f..a0affcff2cea 100644 --- a/src/librustc/middle/traits/util.rs +++ b/src/librustc/middle/traits/util.rs @@ -444,6 +444,9 @@ impl<'tcx, N:Repr<'tcx>> Repr<'tcx> for super::Vtable<'tcx, N> { super::VtableImpl(ref v) => v.repr(tcx), + super::VtableDefaultTrait(ref t) => + format!("VtableDefaultTrait({:?})", t), + super::VtableClosure(ref d, ref s) => format!("VtableClosure({},{})", d.repr(tcx), diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index e9908397f970..5652f23a16d3 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -757,6 +757,9 @@ pub struct ctxt<'tcx> { /// Maps a trait onto a list of impls of that trait. pub trait_impls: RefCell>>>>, + /// Maps a trait onto a list of *default* trait implementations + pub default_trait_impls: RefCell, + /// Maps a DefId of a type to a list of its inherent impls. /// Contains implementations of methods that are inherent to a type. /// Methods in these implementations don't need to be exported. @@ -2493,6 +2496,7 @@ pub fn mk_ctxt<'tcx>(s: Session, destructor_for_type: RefCell::new(DefIdMap()), destructors: RefCell::new(DefIdSet()), trait_impls: RefCell::new(DefIdMap()), + default_trait_impls: RefCell::new(DefIdSet()), inherent_impls: RefCell::new(DefIdMap()), impl_items: RefCell::new(DefIdMap()), used_unsafe: RefCell::new(NodeSet()), @@ -5992,6 +5996,18 @@ pub fn item_variances(tcx: &ctxt, item_id: ast::DefId) -> Rc { || Rc::new(csearch::get_item_variances(&tcx.sess.cstore, item_id))) } +/// Records a trait-to-implementation mapping. +pub fn record_default_trait_implementation(tcx: &ctxt, trait_def_id: DefId) { + + //assert!(did.krate != ast::LOCAL_CRATE); + if tcx.default_trait_impls.borrow().contains(&trait_def_id) { + return; + } + + tcx.default_trait_impls.borrow_mut().insert(trait_def_id); +} + + /// Records a trait-to-implementation mapping. pub fn record_trait_implementation(tcx: &ctxt, trait_def_id: DefId, @@ -6074,11 +6090,21 @@ pub fn populate_implementations_for_trait_if_necessary( } csearch::each_implementation_for_trait(&tcx.sess.cstore, trait_id, - |implementation_def_id| { + |implementation_def_id|{ let impl_items = csearch::get_impl_items(&tcx.sess.cstore, implementation_def_id); - // Record the trait->implementation mapping. - record_trait_implementation(tcx, trait_id, implementation_def_id); + if csearch::is_default_trait(&tcx.sess.cstore, implementation_def_id) { + record_default_trait_implementation(tcx, trait_id); + tcx.populated_external_traits.borrow_mut().insert(trait_id); + + // Nothing else to do for default trait implementations since + // they are not allowed to have type parameters, methods, or any + // other item that could be associated to a trait implementation. + return; + } else { + // Record the trait->implementation mapping. + record_trait_implementation(tcx, trait_id, implementation_def_id); + } // For any methods that use a default implementation, add them to // the map. This is a bit unfortunate. diff --git a/src/librustc/middle/ty_fold.rs b/src/librustc/middle/ty_fold.rs index 5e46ce08e4f7..3f11655e16ec 100644 --- a/src/librustc/middle/ty_fold.rs +++ b/src/librustc/middle/ty_fold.rs @@ -519,6 +519,7 @@ impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::Vtable<'tcx, N> fn fold_with>(&self, folder: &mut F) -> traits::Vtable<'tcx, N> { match *self { traits::VtableImpl(ref v) => traits::VtableImpl(v.fold_with(folder)), + traits::VtableDefaultTrait(t) => traits::VtableDefaultTrait(t), traits::VtableClosure(d, ref s) => { traits::VtableClosure(d, s.fold_with(folder)) } diff --git a/src/librustc_trans/trans/meth.rs b/src/librustc_trans/trans/meth.rs index 1d5d24a64036..1f90e4ae023b 100644 --- a/src/librustc_trans/trans/meth.rs +++ b/src/librustc_trans/trans/meth.rs @@ -390,6 +390,7 @@ fn trans_monomorphized_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, Callee { bcx: bcx, data: Fn(llfn) } } traits::VtableBuiltin(..) | + traits::VtableDefaultTrait(..) | traits::VtableParam(..) => { bcx.sess().bug( &format!("resolved vtable bad vtable {} in trans", @@ -714,6 +715,8 @@ pub fn get_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, let methods = traits::supertraits(tcx, trait_ref.clone()).flat_map(|trait_ref| { let vtable = fulfill_obligation(ccx, DUMMY_SP, trait_ref.clone()); match vtable { + // Should default trait error here? + traits::VtableDefaultTrait(_) | traits::VtableBuiltin(_) => { Vec::new().into_iter() } diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 6fa019a29145..a20fa54f8226 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -649,7 +649,10 @@ fn convert_item(ccx: &CollectCtxt, it: &ast::Item) { &enum_definition.variants); }, ast::ItemDefTrait(_, ref ast_trait_ref) => { + let trait_ref = astconv::instantiate_trait_ref(ccx, &ExplicitRscope, + ast_trait_ref, None, None); + ty::record_default_trait_implementation(tcx, trait_ref.def_id) } ast::ItemImpl(_, _, ref generics,