Skip to content

Commit d476147

Browse files
committed
cache the dropck_outlives computation per variable
1 parent 780f6c5 commit d476147

File tree

1 file changed

+57
-51
lines changed
  • src/librustc_mir/borrow_check/nll/type_check

1 file changed

+57
-51
lines changed

src/librustc_mir/borrow_check/nll/type_check/liveness.rs

Lines changed: 57 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,14 @@ use borrow_check::nll::type_check::AtLocation;
1313
use dataflow::move_paths::{HasMoveData, MoveData};
1414
use dataflow::MaybeInitializedPlaces;
1515
use dataflow::{FlowAtLocation, FlowsAtLocation};
16-
use rustc::infer::InferOk;
16+
use rustc::infer::region_constraints::RegionConstraintData;
1717
use rustc::mir::Local;
1818
use rustc::mir::{BasicBlock, Location, Mir};
19-
use rustc::ty::{Ty, TyCtxt, TypeFoldable};
19+
use rustc::ty::subst::Kind;
20+
use rustc::ty::{Ty, TypeFoldable};
21+
use rustc_data_structures::fx::FxHashMap;
22+
use std::rc::Rc;
23+
use syntax::codemap::DUMMY_SP;
2024
use util::liveness::LivenessResults;
2125

2226
use super::TypeChecker;
@@ -36,14 +40,13 @@ pub(super) fn generate<'gcx, 'tcx>(
3640
flow_inits: &mut FlowAtLocation<MaybeInitializedPlaces<'_, 'gcx, 'tcx>>,
3741
move_data: &MoveData<'tcx>,
3842
) {
39-
let tcx = cx.tcx();
4043
let mut generator = TypeLivenessGenerator {
4144
cx,
42-
tcx,
4345
mir,
4446
liveness,
4547
flow_inits,
4648
move_data,
49+
drop_data: FxHashMap(),
4750
};
4851

4952
for bb in mir.basic_blocks().indices() {
@@ -59,11 +62,16 @@ where
5962
'gcx: 'tcx,
6063
{
6164
cx: &'gen mut TypeChecker<'typeck, 'gcx, 'tcx>,
62-
tcx: TyCtxt<'typeck, 'gcx, 'tcx>,
6365
mir: &'gen Mir<'tcx>,
6466
liveness: &'gen LivenessResults,
6567
flow_inits: &'gen mut FlowAtLocation<MaybeInitializedPlaces<'flow, 'gcx, 'tcx>>,
6668
move_data: &'gen MoveData<'tcx>,
69+
drop_data: FxHashMap<Local, DropData<'tcx>>,
70+
}
71+
72+
struct DropData<'tcx> {
73+
dropped_kinds: Vec<Kind<'tcx>>,
74+
region_constraint_data: Option<Rc<RegionConstraintData<'tcx>>>,
6775
}
6876

6977
impl<'gen, 'typeck, 'flow, 'gcx, 'tcx> TypeLivenessGenerator<'gen, 'typeck, 'flow, 'gcx, 'tcx> {
@@ -80,7 +88,7 @@ impl<'gen, 'typeck, 'flow, 'gcx, 'tcx> TypeLivenessGenerator<'gen, 'typeck, 'flo
8088
for live_local in live_locals.iter() {
8189
let live_local_ty = self.mir.local_decls[live_local].ty;
8290
let cause = Cause::LiveVar(live_local, location);
83-
self.push_type_live_constraint(live_local_ty, location, cause);
91+
Self::push_type_live_constraint(&mut self.cx, live_local_ty, location, cause);
8492
}
8593
});
8694

@@ -148,17 +156,21 @@ impl<'gen, 'typeck, 'flow, 'gcx, 'tcx> TypeLivenessGenerator<'gen, 'typeck, 'flo
148156
/// `location` -- i.e., it may be used later. This means that all
149157
/// regions appearing in the type `live_ty` must be live at
150158
/// `location`.
151-
fn push_type_live_constraint<T>(&mut self, value: T, location: Location, cause: Cause)
152-
where
159+
fn push_type_live_constraint<T>(
160+
cx: &mut TypeChecker<'_, 'gcx, 'tcx>,
161+
value: T,
162+
location: Location,
163+
cause: Cause,
164+
) where
153165
T: TypeFoldable<'tcx>,
154166
{
155167
debug!(
156168
"push_type_live_constraint(live_ty={:?}, location={:?})",
157169
value, location
158170
);
159171

160-
self.tcx.for_each_free_region(&value, |live_region| {
161-
self.cx
172+
cx.tcx().for_each_free_region(&value, |live_region| {
173+
cx
162174
.constraints
163175
.liveness_set
164176
.push((live_region, location, cause.clone()));
@@ -182,53 +194,47 @@ impl<'gen, 'typeck, 'flow, 'gcx, 'tcx> TypeLivenessGenerator<'gen, 'typeck, 'flo
182194
dropped_local, dropped_ty, location
183195
);
184196

185-
// If we end visiting the same type twice (usually due to a cycle involving
186-
// associated types), we need to ensure that its region types match up with the type
187-
// we added to the 'known' map the first time around. For this reason, we need
188-
// our infcx to hold onto its calculated region constraints after each call
189-
// to dtorck_constraint_for_ty. Otherwise, normalizing the corresponding associated
190-
// type will end up instantiating the type with a new set of inference variables
191-
// Since this new type will never be in 'known', we end up looping forever.
192-
//
193-
// For this reason, we avoid calling TypeChecker.normalize, instead doing all normalization
194-
// ourselves in one large 'fully_perform_op' callback.
195-
let kind_constraints = self
196-
.cx
197-
.fully_perform_op(
198-
location.at_self(),
199-
|| format!("add_drop_live_constraint(dropped_ty={:?})", dropped_ty),
200-
|cx| {
201-
let span = cx.last_span;
197+
let drop_data = self.drop_data.entry(dropped_local).or_insert_with({
198+
let cx = &mut self.cx;
199+
move || Self::compute_drop_data(cx, dropped_ty)
200+
});
202201

203-
let mut final_obligations = Vec::new();
204-
let mut kind_constraints = Vec::new();
202+
if let Some(data) = &drop_data.region_constraint_data {
203+
self.cx
204+
.push_region_constraints(location.at_self(), data.clone());
205+
}
205206

206-
let InferOk {
207-
value: kinds,
208-
obligations,
209-
} = cx
207+
// All things in the `outlives` array may be touched by
208+
// the destructor and must be live at this point.
209+
let cause = Cause::DropVar(dropped_local, location);
210+
for &kind in &drop_data.dropped_kinds {
211+
Self::push_type_live_constraint(&mut self.cx, kind, location, cause);
212+
}
213+
}
214+
215+
#[inline(never)]
216+
fn compute_drop_data(
217+
cx: &mut TypeChecker<'_, 'gcx, 'tcx>,
218+
dropped_ty: Ty<'tcx>,
219+
) -> DropData<'tcx> {
220+
debug!("compute_drop_data(dropped_ty={:?})", dropped_ty,);
221+
222+
let (dropped_kinds, region_constraint_data) =
223+
cx.fully_perform_op_and_get_region_constraint_data(
224+
|| format!("compute_drop_data(dropped_ty={:?})", dropped_ty),
225+
|cx| {
226+
// crappy span, but I don't think it really matters
227+
let span = DUMMY_SP;
228+
Ok(cx
210229
.infcx
211230
.at(&cx.misc(span), cx.param_env)
212-
.dropck_outlives(dropped_ty);
213-
for kind in kinds {
214-
// All things in the `outlives` array may be touched by
215-
// the destructor and must be live at this point.
216-
let cause = Cause::DropVar(dropped_local, location);
217-
kind_constraints.push((kind, location, cause));
218-
}
219-
220-
final_obligations.extend(obligations);
221-
222-
Ok(InferOk {
223-
value: kind_constraints,
224-
obligations: final_obligations,
225-
})
231+
.dropck_outlives(dropped_ty))
226232
},
227-
)
228-
.unwrap();
233+
).unwrap();
229234

230-
for (kind, location, cause) in kind_constraints {
231-
self.push_type_live_constraint(kind, location, cause);
235+
DropData {
236+
dropped_kinds,
237+
region_constraint_data,
232238
}
233239
}
234240
}

0 commit comments

Comments
 (0)