Skip to content

Commit 566aa54

Browse files
trans: Make common::fulfill_obligation only depend on SharedCrateContext.
Plus make it produce a nicer dependency graph via DepTrackingMap::memoize().
1 parent d24ead0 commit 566aa54

File tree

7 files changed

+70
-77
lines changed

7 files changed

+70
-77
lines changed

src/librustc_trans/base.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -678,7 +678,7 @@ pub fn custom_coerce_unsize_info<'ccx, 'tcx>(ccx: &CrateContext<'ccx, 'tcx>,
678678
substs: ccx.tcx().mk_substs(trait_substs)
679679
});
680680

681-
match fulfill_obligation(ccx, DUMMY_SP, trait_ref) {
681+
match fulfill_obligation(ccx.shared(), DUMMY_SP, trait_ref) {
682682
traits::VtableImpl(traits::VtableImplData { impl_def_id, .. }) => {
683683
ccx.tcx().custom_coerce_unsized_kind(impl_def_id)
684684
}

src/librustc_trans/callee.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ impl<'tcx> Callee<'tcx> {
156156
let trait_id = method_item.container().id();
157157
let trait_ref = ty::Binder(substs.to_trait_ref(tcx, trait_id));
158158
let trait_ref = infer::normalize_associated_type(tcx, &trait_ref);
159-
match common::fulfill_obligation(ccx, DUMMY_SP, trait_ref) {
159+
match common::fulfill_obligation(ccx.shared(), DUMMY_SP, trait_ref) {
160160
traits::VtableImpl(vtable_impl) => {
161161
let impl_did = vtable_impl.impl_def_id;
162162
let mname = tcx.item_name(def_id);

src/librustc_trans/collector.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -701,7 +701,7 @@ fn find_drop_glue_neighbors<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
701701
substs: self_type_substs,
702702
}.to_poly_trait_ref();
703703

704-
let substs = match fulfill_obligation(ccx, DUMMY_SP, trait_ref) {
704+
let substs = match fulfill_obligation(ccx.shared(), DUMMY_SP, trait_ref) {
705705
traits::VtableImpl(data) => data.substs,
706706
_ => bug!()
707707
};
@@ -844,7 +844,7 @@ fn do_static_trait_method_dispatch<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
844844
callee_substs);
845845

846846
let trait_ref = ty::Binder(rcvr_substs.to_trait_ref(tcx, trait_id));
847-
let vtbl = fulfill_obligation(ccx, DUMMY_SP, trait_ref);
847+
let vtbl = fulfill_obligation(ccx.shared(), DUMMY_SP, trait_ref);
848848

849849
// Now that we know which impl is being used, we can dispatch to
850850
// the actual function:
@@ -999,7 +999,7 @@ fn create_trans_items_for_vtable_methods<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
999999

10001000
// Walk all methods of the trait, including those of its supertraits
10011001
for trait_ref in traits::supertraits(ccx.tcx(), poly_trait_ref) {
1002-
let vtable = fulfill_obligation(ccx, DUMMY_SP, trait_ref);
1002+
let vtable = fulfill_obligation(ccx.shared(), DUMMY_SP, trait_ref);
10031003
match vtable {
10041004
traits::VtableImpl(
10051005
traits::VtableImplData {

src/librustc_trans/common.rs

Lines changed: 57 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ use rustc::cfg;
2020
use rustc::hir::def::Def;
2121
use rustc::hir::def_id::DefId;
2222
use rustc::infer;
23+
use rustc::util::common::MemoizationMap;
2324
use middle::lang_items::LangItem;
2425
use rustc::ty::subst::Substs;
2526
use abi::{Abi, FnType};
@@ -54,7 +55,7 @@ use syntax::codemap::{DUMMY_SP, Span};
5455
use syntax::parse::token::InternedString;
5556
use syntax::parse::token;
5657

57-
pub use context::CrateContext;
58+
pub use context::{CrateContext, SharedCrateContext};
5859

5960
/// Is the type's representation size known at compile time?
6061
pub fn type_is_sized<'tcx>(tcx: &TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool {
@@ -1051,7 +1052,7 @@ pub fn expr_ty_adjusted<'blk, 'tcx>(bcx: &BlockS<'blk, 'tcx>, ex: &hir::Expr) ->
10511052
/// Attempts to resolve an obligation. The result is a shallow vtable resolution -- meaning that we
10521053
/// do not (necessarily) resolve all nested obligations on the impl. Note that type check should
10531054
/// guarantee to us that all nested obligations *could be* resolved if we wanted to.
1054-
pub fn fulfill_obligation<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
1055+
pub fn fulfill_obligation<'a, 'tcx>(ccx: &SharedCrateContext<'a, 'tcx>,
10551056
span: Span,
10561057
trait_ref: ty::PolyTraitRef<'tcx>)
10571058
-> traits::Vtable<'tcx, ()>
@@ -1061,68 +1062,63 @@ pub fn fulfill_obligation<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
10611062
// Remove any references to regions; this helps improve caching.
10621063
let trait_ref = tcx.erase_regions(&trait_ref);
10631064

1064-
// First check the cache.
1065-
match ccx.trait_cache().borrow().get(&trait_ref) {
1066-
Some(vtable) => {
1067-
info!("Cache hit: {:?}", trait_ref);
1068-
return (*vtable).clone();
1069-
}
1070-
None => { }
1071-
}
1072-
1073-
debug!("trans fulfill_obligation: trait_ref={:?} def_id={:?}",
1074-
trait_ref, trait_ref.def_id());
1075-
1076-
1077-
// Do the initial selection for the obligation. This yields the
1078-
// shallow result we are looking for -- that is, what specific impl.
1079-
let infcx = infer::normalizing_infer_ctxt(tcx, &tcx.tables, ProjectionMode::Any);
1080-
let mut selcx = SelectionContext::new(&infcx);
1081-
1082-
let obligation =
1083-
traits::Obligation::new(traits::ObligationCause::misc(span, ast::DUMMY_NODE_ID),
1084-
trait_ref.to_poly_trait_predicate());
1085-
let selection = match selcx.select(&obligation) {
1086-
Ok(Some(selection)) => selection,
1087-
Ok(None) => {
1088-
// Ambiguity can happen when monomorphizing during trans
1089-
// expands to some humongo type that never occurred
1090-
// statically -- this humongo type can then overflow,
1091-
// leading to an ambiguous result. So report this as an
1092-
// overflow bug, since I believe this is the only case
1093-
// where ambiguity can result.
1094-
debug!("Encountered ambiguity selecting `{:?}` during trans, \
1095-
presuming due to overflow",
1096-
trait_ref);
1097-
ccx.sess().span_fatal(
1098-
span,
1099-
"reached the recursion limit during monomorphization (selection ambiguity)");
1100-
}
1101-
Err(e) => {
1102-
span_bug!(
1103-
span,
1104-
"Encountered error `{:?}` selecting `{:?}` during trans",
1105-
e,
1106-
trait_ref)
1107-
}
1108-
};
1109-
1110-
// Currently, we use a fulfillment context to completely resolve
1111-
// all nested obligations. This is because they can inform the
1112-
// inference of the impl's type parameters.
1113-
let mut fulfill_cx = traits::FulfillmentContext::new();
1114-
let vtable = selection.map(|predicate| {
1115-
fulfill_cx.register_predicate_obligation(&infcx, predicate);
1116-
});
1117-
let vtable = infer::drain_fulfillment_cx_or_panic(
1118-
span, &infcx, &mut fulfill_cx, &vtable
1119-
);
1065+
ccx.trait_cache().memoize(trait_ref, || {
1066+
debug!("trans fulfill_obligation: trait_ref={:?} def_id={:?}",
1067+
trait_ref, trait_ref.def_id());
1068+
1069+
// Do the initial selection for the obligation. This yields the
1070+
// shallow result we are looking for -- that is, what specific impl.
1071+
let infcx = infer::normalizing_infer_ctxt(tcx,
1072+
&tcx.tables,
1073+
ProjectionMode::Any);
1074+
let mut selcx = SelectionContext::new(&infcx);
1075+
1076+
let obligation_cause = traits::ObligationCause::misc(span,
1077+
ast::DUMMY_NODE_ID);
1078+
let obligation = traits::Obligation::new(obligation_cause,
1079+
trait_ref.to_poly_trait_predicate());
1080+
1081+
let selection = match selcx.select(&obligation) {
1082+
Ok(Some(selection)) => selection,
1083+
Ok(None) => {
1084+
// Ambiguity can happen when monomorphizing during trans
1085+
// expands to some humongo type that never occurred
1086+
// statically -- this humongo type can then overflow,
1087+
// leading to an ambiguous result. So report this as an
1088+
// overflow bug, since I believe this is the only case
1089+
// where ambiguity can result.
1090+
debug!("Encountered ambiguity selecting `{:?}` during trans, \
1091+
presuming due to overflow",
1092+
trait_ref);
1093+
ccx.sess().span_fatal(
1094+
span,
1095+
"reached the recursion limit during monomorphization \
1096+
(selection ambiguity)");
1097+
}
1098+
Err(e) => {
1099+
span_bug!(
1100+
span,
1101+
"Encountered error `{:?}` selecting `{:?}` during trans",
1102+
e,
1103+
trait_ref)
1104+
}
1105+
};
11201106

1121-
info!("Cache miss: {:?} => {:?}", trait_ref, vtable);
1107+
// Currently, we use a fulfillment context to completely resolve
1108+
// all nested obligations. This is because they can inform the
1109+
// inference of the impl's type parameters.
1110+
let mut fulfill_cx = traits::FulfillmentContext::new();
1111+
let vtable = selection.map(|predicate| {
1112+
fulfill_cx.register_predicate_obligation(&infcx, predicate);
1113+
});
1114+
let vtable = infer::drain_fulfillment_cx_or_panic(
1115+
span, &infcx, &mut fulfill_cx, &vtable
1116+
);
11221117

1123-
ccx.trait_cache().borrow_mut().insert(trait_ref, vtable.clone());
1118+
info!("Cache miss: {:?} => {:?}", trait_ref, vtable);
11241119

1125-
vtable
1120+
vtable
1121+
})
11261122
}
11271123

11281124
/// Normalizes the predicates and checks whether they hold. If this

src/librustc_trans/context.rs

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ pub struct SharedCrateContext<'a, 'tcx: 'a> {
8484
use_dll_storage_attrs: bool,
8585

8686
translation_items: RefCell<FnvHashMap<TransItem<'tcx>, TransItemState>>,
87+
trait_cache: RefCell<DepTrackingMap<TraitSelectionCache<'tcx>>>,
8788
}
8889

8990
/// The local portion of a `CrateContext`. There is one `LocalCrateContext`
@@ -169,8 +170,6 @@ pub struct LocalCrateContext<'tcx> {
169170

170171
/// Depth of the current type-of computation - used to bail out
171172
type_of_depth: Cell<usize>,
172-
173-
trait_cache: RefCell<DepTrackingMap<TraitSelectionCache<'tcx>>>,
174173
}
175174

176175
// Implement DepTrackingMapConfig for `trait_cache`
@@ -423,6 +422,7 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> {
423422
available_drop_glues: RefCell::new(FnvHashMap()),
424423
use_dll_storage_attrs: use_dll_storage_attrs,
425424
translation_items: RefCell::new(FnvHashMap()),
425+
trait_cache: RefCell::new(DepTrackingMap::new(tcx.dep_graph.clone())),
426426
}
427427
}
428428

@@ -446,6 +446,10 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> {
446446
&self.item_symbols
447447
}
448448

449+
pub fn trait_cache(&self) -> &RefCell<DepTrackingMap<TraitSelectionCache<'tcx>>> {
450+
&self.trait_cache
451+
}
452+
449453
pub fn link_meta<'a>(&'a self) -> &'a LinkMeta {
450454
&self.link_meta
451455
}
@@ -516,9 +520,6 @@ impl<'tcx> LocalCrateContext<'tcx> {
516520
intrinsics: RefCell::new(FnvHashMap()),
517521
n_llvm_insns: Cell::new(0),
518522
type_of_depth: Cell::new(0),
519-
trait_cache: RefCell::new(DepTrackingMap::new(shared.tcx
520-
.dep_graph
521-
.clone())),
522523
};
523524

524525
let (int_type, opaque_vec_type, str_slice_ty, mut local_ccx) = {
@@ -805,10 +806,6 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> {
805806
self.local().n_llvm_insns.set(self.local().n_llvm_insns.get() + 1);
806807
}
807808

808-
pub fn trait_cache(&self) -> &RefCell<DepTrackingMap<TraitSelectionCache<'tcx>>> {
809-
&self.local().trait_cache
810-
}
811-
812809
pub fn obj_size_bound(&self) -> u64 {
813810
self.tcx().data_layout.obj_size_bound()
814811
}

src/librustc_trans/glue.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -364,7 +364,7 @@ fn trans_struct_drop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
364364
def_id: tcx.lang_items.drop_trait().unwrap(),
365365
substs: tcx.mk_substs(Substs::empty().with_self_ty(t))
366366
});
367-
let vtbl = match fulfill_obligation(bcx.ccx(), DUMMY_SP, trait_ref) {
367+
let vtbl = match fulfill_obligation(bcx.ccx().shared(), DUMMY_SP, trait_ref) {
368368
traits::VtableImpl(data) => data,
369369
_ => bug!("dtor for {:?} is not an impl???", t)
370370
};

src/librustc_trans/meth.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ pub fn get_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
144144

145145
// Not in the cache. Build it.
146146
let methods = traits::supertraits(tcx, trait_ref.clone()).flat_map(|trait_ref| {
147-
let vtable = fulfill_obligation(ccx, DUMMY_SP, trait_ref.clone());
147+
let vtable = fulfill_obligation(ccx.shared(), DUMMY_SP, trait_ref.clone());
148148
match vtable {
149149
// Should default trait error here?
150150
traits::VtableDefaultImpl(_) |

0 commit comments

Comments
 (0)