Skip to content

Commit 39fd958

Browse files
committed
Auto merge of #44967 - wesleywiser:trans_fulfill_obligation, r=nikomatsakis
Turn `trans_fulfill_obligation` into a query Part of #44891
2 parents d274114 + 31f4b57 commit 39fd958

File tree

10 files changed

+226
-82
lines changed

10 files changed

+226
-82
lines changed

src/librustc/dep_graph/dep_node.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ use hir::map::DefPathHash;
6565
use hir::{HirId, ItemLocalId};
6666

6767
use ich::Fingerprint;
68-
use ty::{TyCtxt, Instance, InstanceDef, ParamEnvAnd, Ty};
68+
use ty::{TyCtxt, Instance, InstanceDef, ParamEnv, ParamEnvAnd, PolyTraitRef, Ty};
6969
use ty::subst::Substs;
7070
use rustc_data_structures::stable_hasher::{StableHasher, HashStable};
7171
use ich::StableHashingContext;
@@ -505,6 +505,7 @@ define_dep_nodes!( <'tcx>
505505
[] InstanceSymbolName { instance: Instance<'tcx> },
506506
[] SpecializationGraph(DefId),
507507
[] ObjectSafety(DefId),
508+
[] FulfillObligation { param_env: ParamEnv<'tcx>, trait_ref: PolyTraitRef<'tcx> },
508509

509510
[] IsCopy { param_env: ParamEnvAnd<'tcx, Ty<'tcx>> },
510511
[] IsSized { param_env: ParamEnvAnd<'tcx, Ty<'tcx>> },

src/librustc/ich/impls_ty.rs

+126
Original file line numberDiff line numberDiff line change
@@ -841,3 +841,129 @@ impl_stable_hash_for!(struct ::util::common::ErrorReported {});
841841
impl_stable_hash_for!(tuple_struct ::middle::reachable::ReachableSet {
842842
reachable_set
843843
});
844+
845+
impl<'gcx, N> HashStable<StableHashingContext<'gcx>>
846+
for traits::Vtable<'gcx, N> where N: HashStable<StableHashingContext<'gcx>> {
847+
fn hash_stable<W: StableHasherResult>(&self,
848+
hcx: &mut StableHashingContext<'gcx>,
849+
hasher: &mut StableHasher<W>) {
850+
use traits::Vtable::*;
851+
852+
mem::discriminant(self).hash_stable(hcx, hasher);
853+
854+
match self {
855+
&VtableImpl(ref table_impl) => table_impl.hash_stable(hcx, hasher),
856+
&VtableDefaultImpl(ref table_def_impl) => table_def_impl.hash_stable(hcx, hasher),
857+
&VtableParam(ref table_param) => table_param.hash_stable(hcx, hasher),
858+
&VtableObject(ref table_obj) => table_obj.hash_stable(hcx, hasher),
859+
&VtableBuiltin(ref table_builtin) => table_builtin.hash_stable(hcx, hasher),
860+
&VtableClosure(ref table_closure) => table_closure.hash_stable(hcx, hasher),
861+
&VtableFnPointer(ref table_fn_pointer) => table_fn_pointer.hash_stable(hcx, hasher),
862+
&VtableGenerator(ref table_generator) => table_generator.hash_stable(hcx, hasher),
863+
}
864+
}
865+
}
866+
867+
impl<'gcx, N> HashStable<StableHashingContext<'gcx>>
868+
for traits::VtableImplData<'gcx, N> where N: HashStable<StableHashingContext<'gcx>> {
869+
fn hash_stable<W: StableHasherResult>(&self,
870+
hcx: &mut StableHashingContext<'gcx>,
871+
hasher: &mut StableHasher<W>) {
872+
let traits::VtableImplData {
873+
impl_def_id,
874+
substs,
875+
ref nested,
876+
} = *self;
877+
impl_def_id.hash_stable(hcx, hasher);
878+
substs.hash_stable(hcx, hasher);
879+
nested.hash_stable(hcx, hasher);
880+
}
881+
}
882+
883+
impl<'gcx, N> HashStable<StableHashingContext<'gcx>>
884+
for traits::VtableDefaultImplData<N> where N: HashStable<StableHashingContext<'gcx>> {
885+
fn hash_stable<W: StableHasherResult>(&self,
886+
hcx: &mut StableHashingContext<'gcx>,
887+
hasher: &mut StableHasher<W>) {
888+
let traits::VtableDefaultImplData {
889+
trait_def_id,
890+
ref nested,
891+
} = *self;
892+
trait_def_id.hash_stable(hcx, hasher);
893+
nested.hash_stable(hcx, hasher);
894+
}
895+
}
896+
897+
impl<'gcx, N> HashStable<StableHashingContext<'gcx>>
898+
for traits::VtableObjectData<'gcx, N> where N: HashStable<StableHashingContext<'gcx>> {
899+
fn hash_stable<W: StableHasherResult>(&self,
900+
hcx: &mut StableHashingContext<'gcx>,
901+
hasher: &mut StableHasher<W>) {
902+
let traits::VtableObjectData {
903+
upcast_trait_ref,
904+
vtable_base,
905+
ref nested,
906+
} = *self;
907+
upcast_trait_ref.hash_stable(hcx, hasher);
908+
vtable_base.hash_stable(hcx, hasher);
909+
nested.hash_stable(hcx, hasher);
910+
}
911+
}
912+
913+
impl<'gcx, N> HashStable<StableHashingContext<'gcx>>
914+
for traits::VtableBuiltinData<N> where N: HashStable<StableHashingContext<'gcx>> {
915+
fn hash_stable<W: StableHasherResult>(&self,
916+
hcx: &mut StableHashingContext<'gcx>,
917+
hasher: &mut StableHasher<W>) {
918+
let traits::VtableBuiltinData {
919+
ref nested,
920+
} = *self;
921+
nested.hash_stable(hcx, hasher);
922+
}
923+
}
924+
925+
impl<'gcx, N> HashStable<StableHashingContext<'gcx>>
926+
for traits::VtableClosureData<'gcx, N> where N: HashStable<StableHashingContext<'gcx>> {
927+
fn hash_stable<W: StableHasherResult>(&self,
928+
hcx: &mut StableHashingContext<'gcx>,
929+
hasher: &mut StableHasher<W>) {
930+
let traits::VtableClosureData {
931+
closure_def_id,
932+
substs,
933+
ref nested,
934+
} = *self;
935+
closure_def_id.hash_stable(hcx, hasher);
936+
substs.hash_stable(hcx, hasher);
937+
nested.hash_stable(hcx, hasher);
938+
}
939+
}
940+
941+
impl<'gcx, N> HashStable<StableHashingContext<'gcx>>
942+
for traits::VtableFnPointerData<'gcx, N> where N: HashStable<StableHashingContext<'gcx>> {
943+
fn hash_stable<W: StableHasherResult>(&self,
944+
hcx: &mut StableHashingContext<'gcx>,
945+
hasher: &mut StableHasher<W>) {
946+
let traits::VtableFnPointerData {
947+
fn_ty,
948+
ref nested,
949+
} = *self;
950+
fn_ty.hash_stable(hcx, hasher);
951+
nested.hash_stable(hcx, hasher);
952+
}
953+
}
954+
955+
impl<'gcx, N> HashStable<StableHashingContext<'gcx>>
956+
for traits::VtableGeneratorData<'gcx, N> where N: HashStable<StableHashingContext<'gcx>> {
957+
fn hash_stable<W: StableHasherResult>(&self,
958+
hcx: &mut StableHashingContext<'gcx>,
959+
hasher: &mut StableHasher<W>) {
960+
let traits::VtableGeneratorData {
961+
closure_def_id,
962+
substs,
963+
ref nested,
964+
} = *self;
965+
closure_def_id.hash_stable(hcx, hasher);
966+
substs.hash_stable(hcx, hasher);
967+
nested.hash_stable(hcx, hasher);
968+
}
969+
}

src/librustc/traits/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -835,6 +835,7 @@ pub fn provide(providers: &mut ty::maps::Providers) {
835835
is_object_safe: object_safety::is_object_safe_provider,
836836
specialization_graph_of: specialize::specialization_graph_provider,
837837
specializes: specialize::specializes,
838+
trans_fulfill_obligation: trans::trans_fulfill_obligation,
838839
..*providers
839840
};
840841
}
@@ -844,6 +845,7 @@ pub fn provide_extern(providers: &mut ty::maps::Providers) {
844845
is_object_safe: object_safety::is_object_safe_provider,
845846
specialization_graph_of: specialize::specialization_graph_provider,
846847
specializes: specialize::specializes,
848+
trans_fulfill_obligation: trans::trans_fulfill_obligation,
847849
..*providers
848850
};
849851
}

src/librustc/traits/trans/mod.rs

+64-74
Original file line numberDiff line numberDiff line change
@@ -17,85 +17,77 @@ use dep_graph::{DepGraph, DepKind, DepTrackingMap, DepTrackingMapConfig};
1717
use infer::TransNormalize;
1818
use std::cell::RefCell;
1919
use std::marker::PhantomData;
20-
use syntax::ast;
21-
use syntax_pos::Span;
20+
use syntax_pos::DUMMY_SP;
2221
use traits::{FulfillmentContext, Obligation, ObligationCause, SelectionContext, Vtable};
2322
use ty::{self, Ty, TyCtxt};
2423
use ty::subst::{Subst, Substs};
2524
use ty::fold::{TypeFoldable, TypeFolder};
2625
use util::common::MemoizationMap;
2726

28-
impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
29-
/// Attempts to resolve an obligation to a vtable.. The result is
30-
/// a shallow vtable resolution -- meaning that we do not
31-
/// (necessarily) resolve all nested obligations on the impl. Note
32-
/// that type check should guarantee to us that all nested
33-
/// obligations *could be* resolved if we wanted to.
34-
/// Assumes that this is run after the entire crate has been successfully type-checked.
35-
pub fn trans_fulfill_obligation(self,
36-
span: Span,
37-
param_env: ty::ParamEnv<'tcx>,
38-
trait_ref: ty::PolyTraitRef<'tcx>)
39-
-> Vtable<'tcx, ()>
40-
{
41-
// Remove any references to regions; this helps improve caching.
42-
let trait_ref = self.erase_regions(&trait_ref);
43-
44-
self.trans_trait_caches.trait_cache.memoize((param_env, trait_ref), || {
45-
debug!("trans::fulfill_obligation(trait_ref={:?}, def_id={:?})",
46-
(param_env, trait_ref), trait_ref.def_id());
47-
48-
// Do the initial selection for the obligation. This yields the
49-
// shallow result we are looking for -- that is, what specific impl.
50-
self.infer_ctxt().enter(|infcx| {
51-
let mut selcx = SelectionContext::new(&infcx);
52-
53-
let obligation_cause = ObligationCause::misc(span,
54-
ast::DUMMY_NODE_ID);
55-
let obligation = Obligation::new(obligation_cause,
56-
param_env,
57-
trait_ref.to_poly_trait_predicate());
58-
59-
let selection = match selcx.select(&obligation) {
60-
Ok(Some(selection)) => selection,
61-
Ok(None) => {
62-
// Ambiguity can happen when monomorphizing during trans
63-
// expands to some humongo type that never occurred
64-
// statically -- this humongo type can then overflow,
65-
// leading to an ambiguous result. So report this as an
66-
// overflow bug, since I believe this is the only case
67-
// where ambiguity can result.
68-
debug!("Encountered ambiguity selecting `{:?}` during trans, \
69-
presuming due to overflow",
70-
trait_ref);
71-
self.sess.span_fatal(span,
72-
"reached the recursion limit during monomorphization \
73-
(selection ambiguity)");
74-
}
75-
Err(e) => {
76-
span_bug!(span, "Encountered error `{:?}` selecting `{:?}` during trans",
77-
e, trait_ref)
78-
}
79-
};
80-
81-
debug!("fulfill_obligation: selection={:?}", selection);
82-
83-
// Currently, we use a fulfillment context to completely resolve
84-
// all nested obligations. This is because they can inform the
85-
// inference of the impl's type parameters.
86-
let mut fulfill_cx = FulfillmentContext::new();
87-
let vtable = selection.map(|predicate| {
88-
debug!("fulfill_obligation: register_predicate_obligation {:?}", predicate);
89-
fulfill_cx.register_predicate_obligation(&infcx, predicate);
90-
});
91-
let vtable = infcx.drain_fulfillment_cx_or_panic(span, &mut fulfill_cx, &vtable);
92-
93-
info!("Cache miss: {:?} => {:?}", trait_ref, vtable);
94-
vtable
95-
})
96-
})
97-
}
27+
/// Attempts to resolve an obligation to a vtable.. The result is
28+
/// a shallow vtable resolution -- meaning that we do not
29+
/// (necessarily) resolve all nested obligations on the impl. Note
30+
/// that type check should guarantee to us that all nested
31+
/// obligations *could be* resolved if we wanted to.
32+
/// Assumes that this is run after the entire crate has been successfully type-checked.
33+
pub fn trans_fulfill_obligation<'a, 'tcx>(ty: TyCtxt<'a, 'tcx, 'tcx>,
34+
(param_env, trait_ref):
35+
(ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>))
36+
-> Vtable<'tcx, ()>
37+
{
38+
// Remove any references to regions; this helps improve caching.
39+
let trait_ref = ty.erase_regions(&trait_ref);
40+
41+
debug!("trans::fulfill_obligation(trait_ref={:?}, def_id={:?})",
42+
(param_env, trait_ref), trait_ref.def_id());
43+
44+
// Do the initial selection for the obligation. This yields the
45+
// shallow result we are looking for -- that is, what specific impl.
46+
ty.infer_ctxt().enter(|infcx| {
47+
let mut selcx = SelectionContext::new(&infcx);
48+
49+
let obligation_cause = ObligationCause::dummy();
50+
let obligation = Obligation::new(obligation_cause,
51+
param_env,
52+
trait_ref.to_poly_trait_predicate());
53+
54+
let selection = match selcx.select(&obligation) {
55+
Ok(Some(selection)) => selection,
56+
Ok(None) => {
57+
// Ambiguity can happen when monomorphizing during trans
58+
// expands to some humongo type that never occurred
59+
// statically -- this humongo type can then overflow,
60+
// leading to an ambiguous result. So report this as an
61+
// overflow bug, since I believe this is the only case
62+
// where ambiguity can result.
63+
bug!("Encountered ambiguity selecting `{:?}` during trans, \
64+
presuming due to overflow",
65+
trait_ref)
66+
}
67+
Err(e) => {
68+
bug!("Encountered error `{:?}` selecting `{:?}` during trans",
69+
e, trait_ref)
70+
}
71+
};
72+
73+
debug!("fulfill_obligation: selection={:?}", selection);
74+
75+
// Currently, we use a fulfillment context to completely resolve
76+
// all nested obligations. This is because they can inform the
77+
// inference of the impl's type parameters.
78+
let mut fulfill_cx = FulfillmentContext::new();
79+
let vtable = selection.map(|predicate| {
80+
debug!("fulfill_obligation: register_predicate_obligation {:?}", predicate);
81+
fulfill_cx.register_predicate_obligation(&infcx, predicate);
82+
});
83+
let vtable = infcx.drain_fulfillment_cx_or_panic(DUMMY_SP, &mut fulfill_cx, &vtable);
84+
85+
info!("Cache miss: {:?} => {:?}", trait_ref, vtable);
86+
vtable
87+
})
88+
}
9889

90+
impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
9991
/// Monomorphizes a type from the AST by first applying the in-scope
10092
/// substitutions and then normalizing any associated types.
10193
pub fn trans_apply_param_substs<T>(self,
@@ -149,14 +141,12 @@ impl<'a, 'gcx> TypeFolder<'gcx, 'gcx> for AssociatedTypeNormalizer<'a, 'gcx> {
149141
/// Specializes caches used in trans -- in particular, they assume all
150142
/// types are fully monomorphized and that free regions can be erased.
151143
pub struct TransTraitCaches<'tcx> {
152-
trait_cache: RefCell<DepTrackingMap<TraitSelectionCache<'tcx>>>,
153144
project_cache: RefCell<DepTrackingMap<ProjectionCache<'tcx>>>,
154145
}
155146

156147
impl<'tcx> TransTraitCaches<'tcx> {
157148
pub fn new(graph: DepGraph) -> Self {
158149
TransTraitCaches {
159-
trait_cache: RefCell::new(DepTrackingMap::new(graph.clone())),
160150
project_cache: RefCell::new(DepTrackingMap::new(graph)),
161151
}
162152
}

src/librustc/ty/instance.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ use ty::{self, Ty, TypeFoldable, Substs, TyCtxt};
1313
use ty::subst::{Kind, Subst};
1414
use traits;
1515
use syntax::abi::Abi;
16-
use syntax::codemap::DUMMY_SP;
1716
use util::ppaux;
1817

1918
use std::fmt;
@@ -212,7 +211,7 @@ fn resolve_associated_item<'a, 'tcx>(
212211
def_id, trait_id, rcvr_substs);
213212

214213
let trait_ref = ty::TraitRef::from_method(tcx, trait_id, rcvr_substs);
215-
let vtbl = tcx.trans_fulfill_obligation(DUMMY_SP, param_env, ty::Binder(trait_ref));
214+
let vtbl = tcx.trans_fulfill_obligation((param_env, ty::Binder(trait_ref)));
216215

217216
// Now that we know which impl is being used, we can dispatch to
218217
// the actual function:

src/librustc/ty/maps/config.rs

+6
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,12 @@ impl<'tcx> QueryDescription for queries::is_mir_available<'tcx> {
221221
}
222222
}
223223

224+
impl<'tcx> QueryDescription for queries::trans_fulfill_obligation<'tcx> {
225+
fn describe(tcx: TyCtxt, key: (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>)) -> String {
226+
format!("checking if `{}` fulfills its obligations", tcx.item_path_str(key.1.def_id()))
227+
}
228+
}
229+
224230
impl<'tcx> QueryDescription for queries::trait_impls_of<'tcx> {
225231
fn describe(tcx: TyCtxt, def_id: DefId) -> String {
226232
format!("trait impls of `{}`", tcx.item_path_str(def_id))

src/librustc/ty/maps/keys.rs

+9
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,15 @@ impl Key for (MirSuite, MirPassIndex, DefId) {
134134
}
135135
}
136136

137+
impl<'tcx> Key for (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>) {
138+
fn map_crate(&self) -> CrateNum {
139+
self.1.def_id().krate
140+
}
141+
fn default_span(&self, tcx: TyCtxt) -> Span {
142+
tcx.def_span(self.1.def_id())
143+
}
144+
}
145+
137146
impl<'tcx> Key for Ty<'tcx> {
138147
fn map_crate(&self) -> CrateNum {
139148
LOCAL_CRATE

0 commit comments

Comments
 (0)