rustc_trans: simplify vtable and symbol handling.
This commit is contained in:
parent
521d3ea193
commit
ade79d7609
8 changed files with 198 additions and 354 deletions
|
|
@ -40,7 +40,7 @@ pub use self::select::{EvaluationCache, SelectionContext, SelectionCache};
|
|||
pub use self::select::{MethodMatchResult, MethodMatched, MethodAmbiguous, MethodDidNotMatch};
|
||||
pub use self::select::{MethodMatchedData}; // intentionally don't export variants
|
||||
pub use self::specialize::{OverlapError, specialization_graph, specializes, translate_substs};
|
||||
pub use self::specialize::{SpecializesCache};
|
||||
pub use self::specialize::{SpecializesCache, find_method};
|
||||
pub use self::util::elaborate_predicates;
|
||||
pub use self::util::supertraits;
|
||||
pub use self::util::Supertraits;
|
||||
|
|
@ -527,6 +527,88 @@ pub fn fully_normalize<'a, 'gcx, 'tcx, T>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
|
|||
Ok(resolved_value)
|
||||
}
|
||||
|
||||
/// Normalizes the predicates and checks whether they hold. If this
|
||||
/// returns false, then either normalize encountered an error or one
|
||||
/// of the predicates did not hold. Used when creating vtables to
|
||||
/// check for unsatisfiable methods.
|
||||
pub fn normalize_and_test_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
predicates: Vec<ty::Predicate<'tcx>>)
|
||||
-> bool
|
||||
{
|
||||
debug!("normalize_and_test_predicates(predicates={:?})",
|
||||
predicates);
|
||||
|
||||
tcx.infer_ctxt(None, None, Reveal::All).enter(|infcx| {
|
||||
let mut selcx = SelectionContext::new(&infcx);
|
||||
let mut fulfill_cx = FulfillmentContext::new();
|
||||
let cause = ObligationCause::dummy();
|
||||
let Normalized { value: predicates, obligations } =
|
||||
normalize(&mut selcx, cause.clone(), &predicates);
|
||||
for obligation in obligations {
|
||||
fulfill_cx.register_predicate_obligation(&infcx, obligation);
|
||||
}
|
||||
for predicate in predicates {
|
||||
let obligation = Obligation::new(cause.clone(), predicate);
|
||||
fulfill_cx.register_predicate_obligation(&infcx, obligation);
|
||||
}
|
||||
|
||||
fulfill_cx.select_all_or_error(&infcx).is_ok()
|
||||
})
|
||||
}
|
||||
|
||||
/// Given a trait `trait_ref`, iterates the vtable entries
|
||||
/// that come from `trait_ref`, including its supertraits.
|
||||
#[inline] // FIXME(#35870) Avoid closures being unexported due to impl Trait.
|
||||
pub fn get_vtable_methods<'a, 'tcx>(
|
||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
trait_ref: ty::PolyTraitRef<'tcx>)
|
||||
-> impl Iterator<Item=Option<(DefId, &'tcx Substs<'tcx>)>> + 'a
|
||||
{
|
||||
debug!("get_vtable_methods({:?})", trait_ref);
|
||||
|
||||
supertraits(tcx, trait_ref).flat_map(move |trait_ref| {
|
||||
tcx.populate_implementations_for_trait_if_necessary(trait_ref.def_id());
|
||||
|
||||
let trait_item_def_ids = tcx.impl_or_trait_items(trait_ref.def_id());
|
||||
let trait_methods = (0..trait_item_def_ids.len()).filter_map(move |i| {
|
||||
match tcx.impl_or_trait_item(trait_item_def_ids[i]) {
|
||||
ty::MethodTraitItem(m) => Some(m),
|
||||
_ => None
|
||||
}
|
||||
});
|
||||
|
||||
// Now list each method's DefId and Substs (for within its trait).
|
||||
// If the method can never be called from this object, produce None.
|
||||
trait_methods.map(move |trait_method| {
|
||||
debug!("get_vtable_methods: trait_method={:?}", trait_method);
|
||||
|
||||
// Some methods cannot be called on an object; skip those.
|
||||
if !tcx.is_vtable_safe_method(trait_ref.def_id(), &trait_method) {
|
||||
debug!("get_vtable_methods: not vtable safe");
|
||||
return None;
|
||||
}
|
||||
|
||||
// the method may have some early-bound lifetimes, add
|
||||
// regions for those
|
||||
let substs = Substs::for_item(tcx, trait_method.def_id,
|
||||
|_, _| tcx.mk_region(ty::ReErased),
|
||||
|def, _| trait_ref.substs().type_for_def(def));
|
||||
|
||||
// It's possible that the method relies on where clauses that
|
||||
// do not hold for this particular set of type parameters.
|
||||
// Note that this method could then never be called, so we
|
||||
// do not want to try and trans it, in that case (see #23435).
|
||||
let predicates = trait_method.predicates.instantiate_own(tcx, substs);
|
||||
if !normalize_and_test_predicates(tcx, predicates.predicates) {
|
||||
debug!("get_vtable_methods: predicates do not hold");
|
||||
return None;
|
||||
}
|
||||
|
||||
Some((trait_method.def_id, substs))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
impl<'tcx,O> Obligation<'tcx,O> {
|
||||
pub fn new(cause: ObligationCause<'tcx>,
|
||||
trait_ref: O)
|
||||
|
|
|
|||
|
|
@ -26,9 +26,11 @@ use infer::{InferCtxt, TypeOrigin};
|
|||
use middle::region;
|
||||
use ty::subst::{Subst, Substs};
|
||||
use traits::{self, Reveal, ObligationCause, Normalized};
|
||||
use ty::{self, TyCtxt};
|
||||
use ty::{self, TyCtxt, TypeFoldable};
|
||||
use syntax_pos::DUMMY_SP;
|
||||
|
||||
use syntax::ast;
|
||||
|
||||
pub mod specialization_graph;
|
||||
|
||||
/// Information pertinent to an overlapping impl error.
|
||||
|
|
@ -103,6 +105,41 @@ pub fn translate_substs<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
|
|||
source_substs.rebase_onto(infcx.tcx, source_impl, target_substs)
|
||||
}
|
||||
|
||||
/// Given a selected impl described by `impl_data`, returns the
|
||||
/// definition and substitions for the method with the name `name`,
|
||||
/// and trait method substitutions `substs`, in that impl, a less
|
||||
/// specialized impl, or the trait default, whichever applies.
|
||||
pub fn find_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
name: ast::Name,
|
||||
substs: &'tcx Substs<'tcx>,
|
||||
impl_data: &super::VtableImplData<'tcx, ()>)
|
||||
-> (DefId, &'tcx Substs<'tcx>)
|
||||
{
|
||||
assert!(!substs.needs_infer());
|
||||
|
||||
let trait_def_id = tcx.trait_id_of_impl(impl_data.impl_def_id).unwrap();
|
||||
let trait_def = tcx.lookup_trait_def(trait_def_id);
|
||||
|
||||
match trait_def.ancestors(impl_data.impl_def_id).fn_defs(tcx, name).next() {
|
||||
Some(node_item) => {
|
||||
let substs = tcx.infer_ctxt(None, None, Reveal::All).enter(|infcx| {
|
||||
let substs = substs.rebase_onto(tcx, trait_def_id, impl_data.substs);
|
||||
let substs = translate_substs(&infcx, impl_data.impl_def_id,
|
||||
substs, node_item.node);
|
||||
tcx.lift(&substs).unwrap_or_else(|| {
|
||||
bug!("find_method: translate_substs \
|
||||
returned {:?} which contains inference types/regions",
|
||||
substs);
|
||||
})
|
||||
});
|
||||
(node_item.item.def_id, substs)
|
||||
}
|
||||
None => {
|
||||
bug!("method {:?} not found in {:?}", name, impl_data.impl_def_id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Is impl1 a specialization of impl2?
|
||||
///
|
||||
/// Specialization is determined by the sets of types to which the impls apply;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue