Auto merge of #44967 - wesleywiser:trans_fulfill_obligation, r=nikomatsakis
Turn `trans_fulfill_obligation` into a query Part of #44891
This commit is contained in:
commit
39fd958520
@ -65,7 +65,7 @@ use hir::map::DefPathHash;
|
||||
use hir::{HirId, ItemLocalId};
|
||||
|
||||
use ich::Fingerprint;
|
||||
use ty::{TyCtxt, Instance, InstanceDef, ParamEnvAnd, Ty};
|
||||
use ty::{TyCtxt, Instance, InstanceDef, ParamEnv, ParamEnvAnd, PolyTraitRef, Ty};
|
||||
use ty::subst::Substs;
|
||||
use rustc_data_structures::stable_hasher::{StableHasher, HashStable};
|
||||
use ich::StableHashingContext;
|
||||
@ -505,6 +505,7 @@ define_dep_nodes!( <'tcx>
|
||||
[] InstanceSymbolName { instance: Instance<'tcx> },
|
||||
[] SpecializationGraph(DefId),
|
||||
[] ObjectSafety(DefId),
|
||||
[] FulfillObligation { param_env: ParamEnv<'tcx>, trait_ref: PolyTraitRef<'tcx> },
|
||||
|
||||
[] IsCopy { param_env: ParamEnvAnd<'tcx, Ty<'tcx>> },
|
||||
[] IsSized { param_env: ParamEnvAnd<'tcx, Ty<'tcx>> },
|
||||
|
@ -841,3 +841,129 @@ impl_stable_hash_for!(struct ::util::common::ErrorReported {});
|
||||
impl_stable_hash_for!(tuple_struct ::middle::reachable::ReachableSet {
|
||||
reachable_set
|
||||
});
|
||||
|
||||
impl<'gcx, N> HashStable<StableHashingContext<'gcx>>
|
||||
for traits::Vtable<'gcx, N> where N: HashStable<StableHashingContext<'gcx>> {
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
use traits::Vtable::*;
|
||||
|
||||
mem::discriminant(self).hash_stable(hcx, hasher);
|
||||
|
||||
match self {
|
||||
&VtableImpl(ref table_impl) => table_impl.hash_stable(hcx, hasher),
|
||||
&VtableDefaultImpl(ref table_def_impl) => table_def_impl.hash_stable(hcx, hasher),
|
||||
&VtableParam(ref table_param) => table_param.hash_stable(hcx, hasher),
|
||||
&VtableObject(ref table_obj) => table_obj.hash_stable(hcx, hasher),
|
||||
&VtableBuiltin(ref table_builtin) => table_builtin.hash_stable(hcx, hasher),
|
||||
&VtableClosure(ref table_closure) => table_closure.hash_stable(hcx, hasher),
|
||||
&VtableFnPointer(ref table_fn_pointer) => table_fn_pointer.hash_stable(hcx, hasher),
|
||||
&VtableGenerator(ref table_generator) => table_generator.hash_stable(hcx, hasher),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'gcx, N> HashStable<StableHashingContext<'gcx>>
|
||||
for traits::VtableImplData<'gcx, N> where N: HashStable<StableHashingContext<'gcx>> {
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
let traits::VtableImplData {
|
||||
impl_def_id,
|
||||
substs,
|
||||
ref nested,
|
||||
} = *self;
|
||||
impl_def_id.hash_stable(hcx, hasher);
|
||||
substs.hash_stable(hcx, hasher);
|
||||
nested.hash_stable(hcx, hasher);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'gcx, N> HashStable<StableHashingContext<'gcx>>
|
||||
for traits::VtableDefaultImplData<N> where N: HashStable<StableHashingContext<'gcx>> {
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
let traits::VtableDefaultImplData {
|
||||
trait_def_id,
|
||||
ref nested,
|
||||
} = *self;
|
||||
trait_def_id.hash_stable(hcx, hasher);
|
||||
nested.hash_stable(hcx, hasher);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'gcx, N> HashStable<StableHashingContext<'gcx>>
|
||||
for traits::VtableObjectData<'gcx, N> where N: HashStable<StableHashingContext<'gcx>> {
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
let traits::VtableObjectData {
|
||||
upcast_trait_ref,
|
||||
vtable_base,
|
||||
ref nested,
|
||||
} = *self;
|
||||
upcast_trait_ref.hash_stable(hcx, hasher);
|
||||
vtable_base.hash_stable(hcx, hasher);
|
||||
nested.hash_stable(hcx, hasher);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'gcx, N> HashStable<StableHashingContext<'gcx>>
|
||||
for traits::VtableBuiltinData<N> where N: HashStable<StableHashingContext<'gcx>> {
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
let traits::VtableBuiltinData {
|
||||
ref nested,
|
||||
} = *self;
|
||||
nested.hash_stable(hcx, hasher);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'gcx, N> HashStable<StableHashingContext<'gcx>>
|
||||
for traits::VtableClosureData<'gcx, N> where N: HashStable<StableHashingContext<'gcx>> {
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
let traits::VtableClosureData {
|
||||
closure_def_id,
|
||||
substs,
|
||||
ref nested,
|
||||
} = *self;
|
||||
closure_def_id.hash_stable(hcx, hasher);
|
||||
substs.hash_stable(hcx, hasher);
|
||||
nested.hash_stable(hcx, hasher);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'gcx, N> HashStable<StableHashingContext<'gcx>>
|
||||
for traits::VtableFnPointerData<'gcx, N> where N: HashStable<StableHashingContext<'gcx>> {
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
let traits::VtableFnPointerData {
|
||||
fn_ty,
|
||||
ref nested,
|
||||
} = *self;
|
||||
fn_ty.hash_stable(hcx, hasher);
|
||||
nested.hash_stable(hcx, hasher);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'gcx, N> HashStable<StableHashingContext<'gcx>>
|
||||
for traits::VtableGeneratorData<'gcx, N> where N: HashStable<StableHashingContext<'gcx>> {
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
let traits::VtableGeneratorData {
|
||||
closure_def_id,
|
||||
substs,
|
||||
ref nested,
|
||||
} = *self;
|
||||
closure_def_id.hash_stable(hcx, hasher);
|
||||
substs.hash_stable(hcx, hasher);
|
||||
nested.hash_stable(hcx, hasher);
|
||||
}
|
||||
}
|
||||
|
@ -835,6 +835,7 @@ pub fn provide(providers: &mut ty::maps::Providers) {
|
||||
is_object_safe: object_safety::is_object_safe_provider,
|
||||
specialization_graph_of: specialize::specialization_graph_provider,
|
||||
specializes: specialize::specializes,
|
||||
trans_fulfill_obligation: trans::trans_fulfill_obligation,
|
||||
..*providers
|
||||
};
|
||||
}
|
||||
@ -844,6 +845,7 @@ pub fn provide_extern(providers: &mut ty::maps::Providers) {
|
||||
is_object_safe: object_safety::is_object_safe_provider,
|
||||
specialization_graph_of: specialize::specialization_graph_provider,
|
||||
specializes: specialize::specializes,
|
||||
trans_fulfill_obligation: trans::trans_fulfill_obligation,
|
||||
..*providers
|
||||
};
|
||||
}
|
||||
|
@ -17,85 +17,77 @@ use dep_graph::{DepGraph, DepKind, DepTrackingMap, DepTrackingMapConfig};
|
||||
use infer::TransNormalize;
|
||||
use std::cell::RefCell;
|
||||
use std::marker::PhantomData;
|
||||
use syntax::ast;
|
||||
use syntax_pos::Span;
|
||||
use syntax_pos::DUMMY_SP;
|
||||
use traits::{FulfillmentContext, Obligation, ObligationCause, SelectionContext, Vtable};
|
||||
use ty::{self, Ty, TyCtxt};
|
||||
use ty::subst::{Subst, Substs};
|
||||
use ty::fold::{TypeFoldable, TypeFolder};
|
||||
use util::common::MemoizationMap;
|
||||
|
||||
/// Attempts to resolve an obligation to a vtable.. The result is
|
||||
/// a shallow vtable resolution -- meaning that we do not
|
||||
/// (necessarily) resolve all nested obligations on the impl. Note
|
||||
/// that type check should guarantee to us that all nested
|
||||
/// obligations *could be* resolved if we wanted to.
|
||||
/// Assumes that this is run after the entire crate has been successfully type-checked.
|
||||
pub fn trans_fulfill_obligation<'a, 'tcx>(ty: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
(param_env, trait_ref):
|
||||
(ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>))
|
||||
-> Vtable<'tcx, ()>
|
||||
{
|
||||
// Remove any references to regions; this helps improve caching.
|
||||
let trait_ref = ty.erase_regions(&trait_ref);
|
||||
|
||||
debug!("trans::fulfill_obligation(trait_ref={:?}, def_id={:?})",
|
||||
(param_env, trait_ref), trait_ref.def_id());
|
||||
|
||||
// Do the initial selection for the obligation. This yields the
|
||||
// shallow result we are looking for -- that is, what specific impl.
|
||||
ty.infer_ctxt().enter(|infcx| {
|
||||
let mut selcx = SelectionContext::new(&infcx);
|
||||
|
||||
let obligation_cause = ObligationCause::dummy();
|
||||
let obligation = Obligation::new(obligation_cause,
|
||||
param_env,
|
||||
trait_ref.to_poly_trait_predicate());
|
||||
|
||||
let selection = match selcx.select(&obligation) {
|
||||
Ok(Some(selection)) => selection,
|
||||
Ok(None) => {
|
||||
// Ambiguity can happen when monomorphizing during trans
|
||||
// expands to some humongo type that never occurred
|
||||
// statically -- this humongo type can then overflow,
|
||||
// leading to an ambiguous result. So report this as an
|
||||
// overflow bug, since I believe this is the only case
|
||||
// where ambiguity can result.
|
||||
bug!("Encountered ambiguity selecting `{:?}` during trans, \
|
||||
presuming due to overflow",
|
||||
trait_ref)
|
||||
}
|
||||
Err(e) => {
|
||||
bug!("Encountered error `{:?}` selecting `{:?}` during trans",
|
||||
e, trait_ref)
|
||||
}
|
||||
};
|
||||
|
||||
debug!("fulfill_obligation: selection={:?}", selection);
|
||||
|
||||
// Currently, we use a fulfillment context to completely resolve
|
||||
// all nested obligations. This is because they can inform the
|
||||
// inference of the impl's type parameters.
|
||||
let mut fulfill_cx = FulfillmentContext::new();
|
||||
let vtable = selection.map(|predicate| {
|
||||
debug!("fulfill_obligation: register_predicate_obligation {:?}", predicate);
|
||||
fulfill_cx.register_predicate_obligation(&infcx, predicate);
|
||||
});
|
||||
let vtable = infcx.drain_fulfillment_cx_or_panic(DUMMY_SP, &mut fulfill_cx, &vtable);
|
||||
|
||||
info!("Cache miss: {:?} => {:?}", trait_ref, vtable);
|
||||
vtable
|
||||
})
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
|
||||
/// Attempts to resolve an obligation to a vtable.. The result is
|
||||
/// a shallow vtable resolution -- meaning that we do not
|
||||
/// (necessarily) resolve all nested obligations on the impl. Note
|
||||
/// that type check should guarantee to us that all nested
|
||||
/// obligations *could be* resolved if we wanted to.
|
||||
/// Assumes that this is run after the entire crate has been successfully type-checked.
|
||||
pub fn trans_fulfill_obligation(self,
|
||||
span: Span,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
trait_ref: ty::PolyTraitRef<'tcx>)
|
||||
-> Vtable<'tcx, ()>
|
||||
{
|
||||
// Remove any references to regions; this helps improve caching.
|
||||
let trait_ref = self.erase_regions(&trait_ref);
|
||||
|
||||
self.trans_trait_caches.trait_cache.memoize((param_env, trait_ref), || {
|
||||
debug!("trans::fulfill_obligation(trait_ref={:?}, def_id={:?})",
|
||||
(param_env, trait_ref), trait_ref.def_id());
|
||||
|
||||
// Do the initial selection for the obligation. This yields the
|
||||
// shallow result we are looking for -- that is, what specific impl.
|
||||
self.infer_ctxt().enter(|infcx| {
|
||||
let mut selcx = SelectionContext::new(&infcx);
|
||||
|
||||
let obligation_cause = ObligationCause::misc(span,
|
||||
ast::DUMMY_NODE_ID);
|
||||
let obligation = Obligation::new(obligation_cause,
|
||||
param_env,
|
||||
trait_ref.to_poly_trait_predicate());
|
||||
|
||||
let selection = match selcx.select(&obligation) {
|
||||
Ok(Some(selection)) => selection,
|
||||
Ok(None) => {
|
||||
// Ambiguity can happen when monomorphizing during trans
|
||||
// expands to some humongo type that never occurred
|
||||
// statically -- this humongo type can then overflow,
|
||||
// leading to an ambiguous result. So report this as an
|
||||
// overflow bug, since I believe this is the only case
|
||||
// where ambiguity can result.
|
||||
debug!("Encountered ambiguity selecting `{:?}` during trans, \
|
||||
presuming due to overflow",
|
||||
trait_ref);
|
||||
self.sess.span_fatal(span,
|
||||
"reached the recursion limit during monomorphization \
|
||||
(selection ambiguity)");
|
||||
}
|
||||
Err(e) => {
|
||||
span_bug!(span, "Encountered error `{:?}` selecting `{:?}` during trans",
|
||||
e, trait_ref)
|
||||
}
|
||||
};
|
||||
|
||||
debug!("fulfill_obligation: selection={:?}", selection);
|
||||
|
||||
// Currently, we use a fulfillment context to completely resolve
|
||||
// all nested obligations. This is because they can inform the
|
||||
// inference of the impl's type parameters.
|
||||
let mut fulfill_cx = FulfillmentContext::new();
|
||||
let vtable = selection.map(|predicate| {
|
||||
debug!("fulfill_obligation: register_predicate_obligation {:?}", predicate);
|
||||
fulfill_cx.register_predicate_obligation(&infcx, predicate);
|
||||
});
|
||||
let vtable = infcx.drain_fulfillment_cx_or_panic(span, &mut fulfill_cx, &vtable);
|
||||
|
||||
info!("Cache miss: {:?} => {:?}", trait_ref, vtable);
|
||||
vtable
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/// Monomorphizes a type from the AST by first applying the in-scope
|
||||
/// substitutions and then normalizing any associated types.
|
||||
pub fn trans_apply_param_substs<T>(self,
|
||||
@ -149,14 +141,12 @@ impl<'a, 'gcx> TypeFolder<'gcx, 'gcx> for AssociatedTypeNormalizer<'a, 'gcx> {
|
||||
/// Specializes caches used in trans -- in particular, they assume all
|
||||
/// types are fully monomorphized and that free regions can be erased.
|
||||
pub struct TransTraitCaches<'tcx> {
|
||||
trait_cache: RefCell<DepTrackingMap<TraitSelectionCache<'tcx>>>,
|
||||
project_cache: RefCell<DepTrackingMap<ProjectionCache<'tcx>>>,
|
||||
}
|
||||
|
||||
impl<'tcx> TransTraitCaches<'tcx> {
|
||||
pub fn new(graph: DepGraph) -> Self {
|
||||
TransTraitCaches {
|
||||
trait_cache: RefCell::new(DepTrackingMap::new(graph.clone())),
|
||||
project_cache: RefCell::new(DepTrackingMap::new(graph)),
|
||||
}
|
||||
}
|
||||
|
@ -13,7 +13,6 @@ use ty::{self, Ty, TypeFoldable, Substs, TyCtxt};
|
||||
use ty::subst::{Kind, Subst};
|
||||
use traits;
|
||||
use syntax::abi::Abi;
|
||||
use syntax::codemap::DUMMY_SP;
|
||||
use util::ppaux;
|
||||
|
||||
use std::fmt;
|
||||
@ -212,7 +211,7 @@ fn resolve_associated_item<'a, 'tcx>(
|
||||
def_id, trait_id, rcvr_substs);
|
||||
|
||||
let trait_ref = ty::TraitRef::from_method(tcx, trait_id, rcvr_substs);
|
||||
let vtbl = tcx.trans_fulfill_obligation(DUMMY_SP, param_env, ty::Binder(trait_ref));
|
||||
let vtbl = tcx.trans_fulfill_obligation((param_env, ty::Binder(trait_ref)));
|
||||
|
||||
// Now that we know which impl is being used, we can dispatch to
|
||||
// the actual function:
|
||||
|
@ -221,6 +221,12 @@ impl<'tcx> QueryDescription for queries::is_mir_available<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> QueryDescription for queries::trans_fulfill_obligation<'tcx> {
|
||||
fn describe(tcx: TyCtxt, key: (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>)) -> String {
|
||||
format!("checking if `{}` fulfills its obligations", tcx.item_path_str(key.1.def_id()))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> QueryDescription for queries::trait_impls_of<'tcx> {
|
||||
fn describe(tcx: TyCtxt, def_id: DefId) -> String {
|
||||
format!("trait impls of `{}`", tcx.item_path_str(def_id))
|
||||
|
@ -134,6 +134,15 @@ impl Key for (MirSuite, MirPassIndex, DefId) {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Key for (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>) {
|
||||
fn map_crate(&self) -> CrateNum {
|
||||
self.1.def_id().krate
|
||||
}
|
||||
fn default_span(&self, tcx: TyCtxt) -> Span {
|
||||
tcx.def_span(self.1.def_id())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Key for Ty<'tcx> {
|
||||
fn map_crate(&self) -> CrateNum {
|
||||
LOCAL_CRATE
|
||||
|
@ -30,6 +30,7 @@ use middle::trans::{CodegenUnit, Stats};
|
||||
use mir;
|
||||
use session::CompileResult;
|
||||
use session::config::OutputFilenames;
|
||||
use traits::Vtable;
|
||||
use traits::specialization_graph;
|
||||
use ty::{self, CrateInherentImpls, Ty, TyCtxt};
|
||||
use ty::layout::{Layout, LayoutError};
|
||||
@ -228,6 +229,8 @@ define_maps! { <'tcx>
|
||||
[] fn const_is_rvalue_promotable_to_static: ConstIsRvaluePromotableToStatic(DefId) -> bool,
|
||||
[] fn is_mir_available: IsMirAvailable(DefId) -> bool,
|
||||
|
||||
[] fn trans_fulfill_obligation: fulfill_obligation_dep_node(
|
||||
(ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>)) -> Vtable<'tcx, ()>,
|
||||
[] fn trait_impls_of: TraitImpls(DefId) -> Rc<ty::trait_def::TraitImpls>,
|
||||
[] fn specialization_graph_of: SpecializationGraph(DefId) -> Rc<specialization_graph::Graph>,
|
||||
[] fn is_object_safe: ObjectSafety(DefId) -> bool,
|
||||
@ -347,6 +350,14 @@ fn type_param_predicates<'tcx>((item_id, param_id): (DefId, DefId)) -> DepConstr
|
||||
}
|
||||
}
|
||||
|
||||
fn fulfill_obligation_dep_node<'tcx>((param_env, trait_ref):
|
||||
(ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>)) -> DepConstructor<'tcx> {
|
||||
DepConstructor::FulfillObligation {
|
||||
param_env,
|
||||
trait_ref
|
||||
}
|
||||
}
|
||||
|
||||
fn coherent_trait_dep_node<'tcx>((_, def_id): (CrateNum, DefId)) -> DepConstructor<'tcx> {
|
||||
DepConstructor::CoherenceCheckTrait(def_id)
|
||||
}
|
||||
|
@ -748,6 +748,7 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>,
|
||||
DepKind::TypeParamPredicates |
|
||||
DepKind::CodegenUnit |
|
||||
DepKind::CompileCodegenUnit |
|
||||
DepKind::FulfillObligation |
|
||||
|
||||
// These are just odd
|
||||
DepKind::Null |
|
||||
|
@ -15,8 +15,6 @@ use rustc::ty::adjustment::CustomCoerceUnsized;
|
||||
use rustc::ty::subst::{Kind, Subst, Substs};
|
||||
use rustc::ty::{self, Ty, TyCtxt};
|
||||
|
||||
use syntax::codemap::DUMMY_SP;
|
||||
|
||||
pub use rustc::ty::Instance;
|
||||
|
||||
fn fn_once_adapter_instance<'a, 'tcx>(
|
||||
@ -110,13 +108,14 @@ pub fn custom_coerce_unsize_info<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
source_ty: Ty<'tcx>,
|
||||
target_ty: Ty<'tcx>)
|
||||
-> CustomCoerceUnsized {
|
||||
let def_id = tcx.lang_items().coerce_unsized_trait().unwrap();
|
||||
|
||||
let trait_ref = ty::Binder(ty::TraitRef {
|
||||
def_id: tcx.lang_items().coerce_unsized_trait().unwrap(),
|
||||
def_id: def_id,
|
||||
substs: tcx.mk_substs_trait(source_ty, &[target_ty])
|
||||
});
|
||||
|
||||
match tcx.trans_fulfill_obligation(
|
||||
DUMMY_SP, ty::ParamEnv::empty(traits::Reveal::All), trait_ref) {
|
||||
match tcx.trans_fulfill_obligation( (ty::ParamEnv::empty(traits::Reveal::All), trait_ref)) {
|
||||
traits::VtableImpl(traits::VtableImplData { impl_def_id, .. }) => {
|
||||
tcx.coerce_unsized_info(impl_def_id).custom_kind.unwrap()
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user