Skip to content

Commit 497d67d

Browse files
authored
Auto merge of #35761 - nikomatsakis:faster-trans-fulfill-obligation, r=eddyb
Cache projections in trans This introduces a cache for the results of projection and normalization in trans. This is in addition to the existing cache that is per-inference-context. Trans is an easy place to put the cache because we are guaranteed not to have type parameters and also we don't expect any failures or inference variables, so there is no need to cache or follow-up on obligations that come along with. (As evidenced by the fact that this particular code would panic if any error occurred.) That said, I am not sure this is 100% the best place for it; I sort of wanted a cache like we have in the fulfillment context for global names; but that cache only triggers when all subsequent obligations are satisfied, and since projections don't have an entry in the obligation jungle there is no easy place to put it. I considered caching both the result and obligations globally, but haven't really tried implementing it. It might be a good next step. Regardless, this cache seems to have no real effect on bootstrap time (maybe a slight improvement), but on [the futures.rs test case I was looking at](rust-lang-deprecated/rustc-benchmarks#6), it improves performance quite a bit: | phase | before | after | | ----- | ------ | ----- | | collection | 0.79s | 0.46s | | translation | 6.8s | 3.2s | | total | 11.92s | 7.15s | r? @arielb1
2 parents 933f471 + 00d208e commit 497d67d

File tree

17 files changed

+197
-144
lines changed

17 files changed

+197
-144
lines changed

src/librustc/dep_graph/dep_node.rs

+3-4
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ pub enum DepNode<D: Clone + Debug> {
132132
// which would yield an overly conservative dep-graph.
133133
TraitItems(D),
134134
ReprHints(D),
135-
TraitSelect(D, Vec<D>),
135+
TraitSelect(Vec<D>),
136136
}
137137

138138
impl<D: Clone + Debug> DepNode<D> {
@@ -237,10 +237,9 @@ impl<D: Clone + Debug> DepNode<D> {
237237
TraitImpls(ref d) => op(d).map(TraitImpls),
238238
TraitItems(ref d) => op(d).map(TraitItems),
239239
ReprHints(ref d) => op(d).map(ReprHints),
240-
TraitSelect(ref d, ref type_ds) => {
241-
let d = try_opt!(op(d));
240+
TraitSelect(ref type_ds) => {
242241
let type_ds = try_opt!(type_ds.iter().map(|d| op(d)).collect());
243-
Some(TraitSelect(d, type_ds))
242+
Some(TraitSelect(type_ds))
244243
}
245244
}
246245
}

src/librustc/infer/mod.rs

+24-68
Original file line numberDiff line numberDiff line change
@@ -136,13 +136,6 @@ pub struct InferCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
136136
// avoid reporting the same error twice.
137137
pub reported_trait_errors: RefCell<FnvHashSet<traits::TraitErrorKey<'tcx>>>,
138138

139-
// This is a temporary field used for toggling on normalization in the inference context,
140-
// as we move towards the approach described here:
141-
// https://internals.rust-lang.org/t/flattening-the-contexts-for-fun-and-profit/2293
142-
// At a point sometime in the future normalization will be done by the typing context
143-
// directly.
144-
normalize: bool,
145-
146139
// Sadly, the behavior of projection varies a bit depending on the
147140
// stage of compilation. The specifics are given in the
148141
// documentation for `Reveal`.
@@ -458,7 +451,6 @@ pub struct InferCtxtBuilder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
458451
tables: Option<RefCell<ty::Tables<'tcx>>>,
459452
param_env: Option<ty::ParameterEnvironment<'gcx>>,
460453
projection_mode: Reveal,
461-
normalize: bool
462454
}
463455

464456
impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'gcx> {
@@ -473,19 +465,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'gcx> {
473465
tables: tables.map(RefCell::new),
474466
param_env: param_env,
475467
projection_mode: projection_mode,
476-
normalize: false
477-
}
478-
}
479-
480-
pub fn normalizing_infer_ctxt(self, projection_mode: Reveal)
481-
-> InferCtxtBuilder<'a, 'gcx, 'tcx> {
482-
InferCtxtBuilder {
483-
global_tcx: self,
484-
arenas: ty::CtxtArenas::new(),
485-
tables: None,
486-
param_env: None,
487-
projection_mode: projection_mode,
488-
normalize: false
489468
}
490469
}
491470

@@ -506,7 +485,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'gcx> {
506485
evaluation_cache: traits::EvaluationCache::new(),
507486
projection_cache: RefCell::new(traits::ProjectionCache::new()),
508487
reported_trait_errors: RefCell::new(FnvHashSet()),
509-
normalize: false,
510488
projection_mode: Reveal::NotSpecializable,
511489
tainted_by_errors_flag: Cell::new(false),
512490
err_count_on_creation: self.sess.err_count(),
@@ -525,7 +503,6 @@ impl<'a, 'gcx, 'tcx> InferCtxtBuilder<'a, 'gcx, 'tcx> {
525503
ref tables,
526504
ref mut param_env,
527505
projection_mode,
528-
normalize
529506
} = *self;
530507
let tables = if let Some(ref tables) = *tables {
531508
InferTables::Local(tables)
@@ -547,7 +524,6 @@ impl<'a, 'gcx, 'tcx> InferCtxtBuilder<'a, 'gcx, 'tcx> {
547524
selection_cache: traits::SelectionCache::new(),
548525
evaluation_cache: traits::EvaluationCache::new(),
549526
reported_trait_errors: RefCell::new(FnvHashSet()),
550-
normalize: normalize,
551527
projection_mode: projection_mode,
552528
tainted_by_errors_flag: Cell::new(false),
553529
err_count_on_creation: tcx.sess.err_count(),
@@ -683,6 +659,15 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
683659
self.drain_fulfillment_cx_or_panic(DUMMY_SP, &mut fulfill_cx, &result)
684660
}
685661

662+
/// Finishes processes any obligations that remain in the
663+
/// fulfillment context, and then returns the result with all type
664+
/// variables removed and regions erased. Because this is intended
665+
/// for use after type-check has completed, if any errors occur,
666+
/// it will panic. It is used during normalization and other cases
667+
/// where processing the obligations in `fulfill_cx` may cause
668+
/// type inference variables that appear in `result` to be
669+
/// unified, and hence we need to process those obligations to get
670+
/// the complete picture of the type.
686671
pub fn drain_fulfillment_cx_or_panic<T>(&self,
687672
span: Span,
688673
fulfill_cx: &mut traits::FulfillmentContext<'tcx>,
@@ -692,47 +677,28 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
692677
{
693678
debug!("drain_fulfillment_cx_or_panic()");
694679

695-
let when = "resolving bounds after type-checking";
696-
let v = match self.drain_fulfillment_cx(fulfill_cx, result) {
697-
Ok(v) => v,
680+
// In principle, we only need to do this so long as `result`
681+
// contains unbound type parameters. It could be a slight
682+
// optimization to stop iterating early.
683+
match fulfill_cx.select_all_or_error(self) {
684+
Ok(()) => { }
698685
Err(errors) => {
699-
span_bug!(span, "Encountered errors `{:?}` {}", errors, when);
686+
span_bug!(span, "Encountered errors `{:?}` resolving bounds after type-checking",
687+
errors);
700688
}
701-
};
689+
}
690+
691+
let result = self.resolve_type_vars_if_possible(result);
692+
let result = self.tcx.erase_regions(&result);
702693

703-
match self.tcx.lift_to_global(&v) {
704-
Some(v) => v,
694+
match self.tcx.lift_to_global(&result) {
695+
Some(result) => result,
705696
None => {
706-
span_bug!(span, "Uninferred types/regions in `{:?}` {}", v, when);
697+
span_bug!(span, "Uninferred types/regions in `{:?}`", result);
707698
}
708699
}
709700
}
710701

711-
/// Finishes processes any obligations that remain in the fulfillment
712-
/// context, and then "freshens" and returns `result`. This is
713-
/// primarily used during normalization and other cases where
714-
/// processing the obligations in `fulfill_cx` may cause type
715-
/// inference variables that appear in `result` to be unified, and
716-
/// hence we need to process those obligations to get the complete
717-
/// picture of the type.
718-
pub fn drain_fulfillment_cx<T>(&self,
719-
fulfill_cx: &mut traits::FulfillmentContext<'tcx>,
720-
result: &T)
721-
-> Result<T,Vec<traits::FulfillmentError<'tcx>>>
722-
where T : TypeFoldable<'tcx>
723-
{
724-
debug!("drain_fulfillment_cx(result={:?})",
725-
result);
726-
727-
// In principle, we only need to do this so long as `result`
728-
// contains unbound type parameters. It could be a slight
729-
// optimization to stop iterating early.
730-
fulfill_cx.select_all_or_error(self)?;
731-
732-
let result = self.resolve_type_vars_if_possible(result);
733-
Ok(self.tcx.erase_regions(&result))
734-
}
735-
736702
pub fn projection_mode(&self) -> Reveal {
737703
self.projection_mode
738704
}
@@ -1702,17 +1668,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
17021668
}
17031669

17041670
let closure_ty = self.tcx.closure_type(def_id, substs);
1705-
if self.normalize {
1706-
let closure_ty = self.tcx.erase_regions(&closure_ty);
1707-
1708-
if !closure_ty.has_projection_types() {
1709-
return closure_ty;
1710-
}
1711-
1712-
self.normalize_projections_in(&closure_ty)
1713-
} else {
1714-
closure_ty
1715-
}
1671+
closure_ty
17161672
}
17171673
}
17181674

src/librustc/traits/specialize/mod.rs

+20-17
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ pub fn specializes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
147147
.unwrap()
148148
.subst(tcx, &penv.free_substs);
149149

150-
let result = tcx.normalizing_infer_ctxt(Reveal::ExactMatch).enter(|mut infcx| {
150+
let result = tcx.infer_ctxt(None, None, Reveal::ExactMatch).enter(|mut infcx| {
151151
// Normalize the trait reference, adding any obligations
152152
// that arise into the impl1 assumptions.
153153
let Normalized { value: impl1_trait_ref, obligations: normalization_obligations } = {
@@ -207,24 +207,27 @@ fn fulfill_implication<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
207207
for oblig in obligations.into_iter() {
208208
fulfill_cx.register_predicate_obligation(&infcx, oblig);
209209
}
210+
match fulfill_cx.select_all_or_error(infcx) {
211+
Err(errors) => {
212+
// no dice!
213+
debug!("fulfill_implication: for impls on {:?} and {:?}, could not fulfill: {:?} given \
214+
{:?}",
215+
source_trait_ref,
216+
target_trait_ref,
217+
errors,
218+
infcx.parameter_environment.caller_bounds);
219+
Err(())
220+
}
210221

211-
if let Err(errors) = infcx.drain_fulfillment_cx(&mut fulfill_cx, &()) {
212-
// no dice!
213-
debug!("fulfill_implication: for impls on {:?} and {:?}, could not fulfill: {:?} given \
214-
{:?}",
215-
source_trait_ref,
216-
target_trait_ref,
217-
errors,
218-
infcx.parameter_environment.caller_bounds);
219-
Err(())
220-
} else {
221-
debug!("fulfill_implication: an impl for {:?} specializes {:?}",
222-
source_trait_ref,
223-
target_trait_ref);
222+
Ok(()) => {
223+
debug!("fulfill_implication: an impl for {:?} specializes {:?}",
224+
source_trait_ref,
225+
target_trait_ref);
224226

225-
// Now resolve the *substitution* we built for the target earlier, replacing
226-
// the inference variables inside with whatever we got from fulfillment.
227-
Ok(infcx.resolve_type_vars_if_possible(&target_substs))
227+
// Now resolve the *substitution* we built for the target earlier, replacing
228+
// the inference variables inside with whatever we got from fulfillment.
229+
Ok(infcx.resolve_type_vars_if_possible(&target_substs))
230+
}
228231
}
229232
}
230233

src/librustc/ty/mod.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -953,8 +953,9 @@ impl<'tcx> TraitPredicate<'tcx> {
953953
_ =>
954954
None
955955
})
956+
.chain(iter::once(self.def_id()))
956957
.collect();
957-
DepNode::TraitSelect(self.def_id(), def_ids)
958+
DepNode::TraitSelect(def_ids)
958959
}
959960

960961
pub fn input_types<'a>(&'a self) -> impl DoubleEndedIterator<Item=Ty<'tcx>> + 'a {

src/librustc_lint/types.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -691,7 +691,7 @@ impl LateLintPass for VariantSizeDifferences {
691691
if let hir::ItemEnum(ref enum_definition, ref gens) = it.node {
692692
if gens.ty_params.is_empty() { // sizes only make sense for non-generic types
693693
let t = cx.tcx.node_id_to_type(it.id);
694-
let layout = cx.tcx.normalizing_infer_ctxt(Reveal::All).enter(|infcx| {
694+
let layout = cx.tcx.infer_ctxt(None, None, Reveal::All).enter(|infcx| {
695695
let ty = cx.tcx.erase_regions(&t);
696696
ty.layout(&infcx).unwrap_or_else(|e| {
697697
bug!("failed to get layout for `{}`: {}", t, e)

src/librustc_trans/base.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -1128,7 +1128,7 @@ pub fn trans_instance<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, instance: Instance
11281128

11291129
let fn_ty = ccx.tcx().lookup_item_type(instance.def).ty;
11301130
let fn_ty = ccx.tcx().erase_regions(&fn_ty);
1131-
let fn_ty = monomorphize::apply_param_substs(ccx.tcx(), instance.substs, &fn_ty);
1131+
let fn_ty = monomorphize::apply_param_substs(ccx.shared(), instance.substs, &fn_ty);
11321132

11331133
let sig = ccx.tcx().erase_late_bound_regions(fn_ty.fn_sig());
11341134
let sig = ccx.tcx().normalize_associated_type(&sig);
@@ -1151,7 +1151,7 @@ pub fn trans_ctor_shim<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
11511151
attributes::set_frame_pointer_elimination(ccx, llfndecl);
11521152

11531153
let ctor_ty = ccx.tcx().lookup_item_type(def_id).ty;
1154-
let ctor_ty = monomorphize::apply_param_substs(ccx.tcx(), substs, &ctor_ty);
1154+
let ctor_ty = monomorphize::apply_param_substs(ccx.shared(), substs, &ctor_ty);
11551155

11561156
let sig = ccx.tcx().erase_late_bound_regions(&ctor_ty.fn_sig());
11571157
let sig = ccx.tcx().normalize_associated_type(&sig);
@@ -1894,7 +1894,7 @@ fn collect_and_partition_translation_items<'a, 'tcx>(scx: &SharedCrateContext<'a
18941894
};
18951895

18961896
let codegen_units = time(time_passes, "codegen unit partitioning", || {
1897-
partitioning::partition(scx.tcx(),
1897+
partitioning::partition(scx,
18981898
items.iter().cloned(),
18991899
strategy,
19001900
&inlining_map,

src/librustc_trans/callee.rs

+10-10
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ use base;
2828
use base::*;
2929
use build::*;
3030
use closure;
31-
use common::{self, Block, Result, CrateContext, FunctionContext};
31+
use common::{self, Block, Result, CrateContext, FunctionContext, SharedCrateContext};
3232
use consts;
3333
use debuginfo::DebugLoc;
3434
use declare;
@@ -37,7 +37,7 @@ use monomorphize::{self, Instance};
3737
use trans_item::TransItem;
3838
use type_of;
3939
use Disr;
40-
use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
40+
use rustc::ty::{self, Ty, TypeFoldable};
4141
use rustc::hir;
4242

4343
use syntax_pos::DUMMY_SP;
@@ -97,7 +97,7 @@ impl<'tcx> Callee<'tcx> {
9797
return Callee::trait_method(ccx, trait_id, def_id, substs);
9898
}
9999

100-
let fn_ty = def_ty(tcx, def_id, substs);
100+
let fn_ty = def_ty(ccx.shared(), def_id, substs);
101101
if let ty::TyFnDef(_, _, f) = fn_ty.sty {
102102
if f.abi == Abi::RustIntrinsic || f.abi == Abi::PlatformIntrinsic {
103103
return Callee {
@@ -155,20 +155,20 @@ impl<'tcx> Callee<'tcx> {
155155
vtable_closure.substs,
156156
trait_closure_kind);
157157

158-
let method_ty = def_ty(tcx, def_id, substs);
158+
let method_ty = def_ty(ccx.shared(), def_id, substs);
159159
Callee::ptr(llfn, method_ty)
160160
}
161161
traits::VtableFnPointer(vtable_fn_pointer) => {
162162
let trait_closure_kind = tcx.lang_items.fn_trait_kind(trait_id).unwrap();
163163
let llfn = trans_fn_pointer_shim(ccx, trait_closure_kind, vtable_fn_pointer.fn_ty);
164164

165-
let method_ty = def_ty(tcx, def_id, substs);
165+
let method_ty = def_ty(ccx.shared(), def_id, substs);
166166
Callee::ptr(llfn, method_ty)
167167
}
168168
traits::VtableObject(ref data) => {
169169
Callee {
170170
data: Virtual(tcx.get_vtable_index_of_object_method(data, def_id)),
171-
ty: def_ty(tcx, def_id, substs)
171+
ty: def_ty(ccx.shared(), def_id, substs)
172172
}
173173
}
174174
vtable => {
@@ -244,12 +244,12 @@ impl<'tcx> Callee<'tcx> {
244244
}
245245

246246
/// Given a DefId and some Substs, produces the monomorphic item type.
247-
fn def_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
247+
fn def_ty<'a, 'tcx>(shared: &SharedCrateContext<'a, 'tcx>,
248248
def_id: DefId,
249249
substs: &'tcx Substs<'tcx>)
250250
-> Ty<'tcx> {
251-
let ty = tcx.lookup_item_type(def_id).ty;
252-
monomorphize::apply_param_substs(tcx, substs, &ty)
251+
let ty = shared.tcx().lookup_item_type(def_id).ty;
252+
monomorphize::apply_param_substs(shared, substs, &ty)
253253
}
254254

255255
/// Translates an adapter that implements the `Fn` trait for a fn
@@ -407,7 +407,7 @@ fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
407407
let substs = tcx.normalize_associated_type(&substs);
408408
let instance = Instance::new(def_id, substs);
409409
let item_ty = ccx.tcx().lookup_item_type(def_id).ty;
410-
let fn_ty = monomorphize::apply_param_substs(ccx.tcx(), substs, &item_ty);
410+
let fn_ty = monomorphize::apply_param_substs(ccx.shared(), substs, &item_ty);
411411

412412
if let Some(&llfn) = ccx.instances().borrow().get(&instance) {
413413
return (llfn, fn_ty);

0 commit comments

Comments
 (0)