Skip to content

Commit 47c1921

Browse files
committed
move some parts of liveness to happen during type checking
This allows us to re-use the `normalize` method on `TypeCheck`, which is important since normalization may create fresh region variables. This is not an ideal solution, though, since the current representation of "liveness constraints" (a vector of (region, point) pairs) is rather inefficient. Could do somewhat better by converting to indices, but it'd still be less good than the older code. Unclear how important this is.
1 parent 4a940b3 commit 47c1921

File tree

7 files changed

+351
-199
lines changed

7 files changed

+351
-199
lines changed

src/librustc_mir/borrow_check/nll/constraint_generation.rs

Lines changed: 2 additions & 171 deletions
Original file line numberDiff line numberDiff line change
@@ -12,41 +12,25 @@ use rustc::hir;
1212
use rustc::mir::{BasicBlock, BasicBlockData, Location, Place, Mir, Rvalue};
1313
use rustc::mir::visit::Visitor;
1414
use rustc::mir::Place::Projection;
15-
use rustc::mir::{Local, PlaceProjection, ProjectionElem};
15+
use rustc::mir::{PlaceProjection, ProjectionElem};
1616
use rustc::mir::visit::TyContext;
1717
use rustc::infer::InferCtxt;
18-
use rustc::traits::{self, ObligationCause};
19-
use rustc::ty::{self, ClosureSubsts, Ty};
18+
use rustc::ty::{self, ClosureSubsts};
2019
use rustc::ty::subst::Substs;
2120
use rustc::ty::fold::TypeFoldable;
22-
use rustc::util::common::ErrorReported;
23-
use rustc_data_structures::fx::FxHashSet;
24-
use syntax::codemap::DUMMY_SP;
25-
use dataflow::{FlowAtLocation, FlowsAtLocation};
26-
use dataflow::MaybeInitializedLvals;
27-
use dataflow::move_paths::{HasMoveData, MoveData};
2821

29-
use super::LivenessResults;
3022
use super::ToRegionVid;
3123
use super::region_infer::RegionInferenceContext;
3224

3325
pub(super) fn generate_constraints<'cx, 'gcx, 'tcx>(
3426
infcx: &InferCtxt<'cx, 'gcx, 'tcx>,
3527
regioncx: &mut RegionInferenceContext<'tcx>,
3628
mir: &Mir<'tcx>,
37-
param_env: ty::ParamEnv<'tcx>,
38-
liveness: &LivenessResults,
39-
flow_inits: &mut FlowAtLocation<MaybeInitializedLvals<'cx, 'gcx, 'tcx>>,
40-
move_data: &MoveData<'tcx>,
4129
) {
4230
let mut cg = ConstraintGeneration {
4331
infcx,
4432
regioncx,
4533
mir,
46-
liveness,
47-
param_env,
48-
flow_inits,
49-
move_data,
5034
};
5135

5236
for (bb, data) in mir.basic_blocks().iter_enumerated() {
@@ -59,16 +43,10 @@ struct ConstraintGeneration<'cg, 'cx: 'cg, 'gcx: 'tcx, 'tcx: 'cx> {
5943
infcx: &'cg InferCtxt<'cx, 'gcx, 'tcx>,
6044
regioncx: &'cg mut RegionInferenceContext<'tcx>,
6145
mir: &'cg Mir<'tcx>,
62-
liveness: &'cg LivenessResults,
63-
param_env: ty::ParamEnv<'tcx>,
64-
flow_inits: &'cg mut FlowAtLocation<MaybeInitializedLvals<'cx, 'gcx, 'tcx>>,
65-
move_data: &'cg MoveData<'tcx>,
6646
}
6747

68-
6948
impl<'cg, 'cx, 'gcx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cg, 'cx, 'gcx, 'tcx> {
7049
fn visit_basic_block_data(&mut self, bb: BasicBlock, data: &BasicBlockData<'tcx>) {
71-
self.add_liveness_constraints(bb);
7250
self.super_basic_block_data(bb, data);
7351
}
7452

@@ -130,84 +108,6 @@ impl<'cg, 'cx, 'gcx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cg, 'cx, 'gcx
130108
}
131109

132110
impl<'cx, 'cg, 'gcx, 'tcx> ConstraintGeneration<'cx, 'cg, 'gcx, 'tcx> {
133-
/// Liveness constraints:
134-
///
135-
/// > If a variable V is live at point P, then all regions R in the type of V
136-
/// > must include the point P.
137-
fn add_liveness_constraints(&mut self, bb: BasicBlock) {
138-
debug!("add_liveness_constraints(bb={:?})", bb);
139-
140-
self.liveness
141-
.regular
142-
.simulate_block(self.mir, bb, |location, live_locals| {
143-
for live_local in live_locals.iter() {
144-
let live_local_ty = self.mir.local_decls[live_local].ty;
145-
self.add_regular_live_constraint(live_local_ty, location);
146-
}
147-
});
148-
149-
let mut all_live_locals: Vec<(Location, Vec<Local>)> = vec![];
150-
self.liveness
151-
.drop
152-
.simulate_block(self.mir, bb, |location, live_locals| {
153-
all_live_locals.push((location, live_locals.iter().collect()));
154-
});
155-
debug!(
156-
"add_liveness_constraints: all_live_locals={:#?}",
157-
all_live_locals
158-
);
159-
160-
let terminator_index = self.mir.basic_blocks()[bb].statements.len();
161-
self.flow_inits.reset_to_entry_of(bb);
162-
while let Some((location, live_locals)) = all_live_locals.pop() {
163-
for live_local in live_locals {
164-
debug!(
165-
"add_liveness_constraints: location={:?} live_local={:?}",
166-
location,
167-
live_local
168-
);
169-
170-
self.flow_inits.each_state_bit(|mpi_init| {
171-
debug!(
172-
"add_liveness_constraints: location={:?} initialized={:?}",
173-
location,
174-
&self.flow_inits
175-
.operator()
176-
.move_data()
177-
.move_paths[mpi_init]
178-
);
179-
});
180-
181-
let mpi = self.move_data.rev_lookup.find_local(live_local);
182-
if let Some(initialized_child) = self.flow_inits.has_any_child_of(mpi) {
183-
debug!(
184-
"add_liveness_constraints: mpi={:?} has initialized child {:?}",
185-
self.move_data.move_paths[mpi],
186-
self.move_data.move_paths[initialized_child]
187-
);
188-
189-
let live_local_ty = self.mir.local_decls[live_local].ty;
190-
self.add_drop_live_constraint(live_local_ty, location);
191-
}
192-
}
193-
194-
if location.statement_index == terminator_index {
195-
debug!(
196-
"add_liveness_constraints: reconstruct_terminator_effect from {:#?}",
197-
location
198-
);
199-
self.flow_inits.reconstruct_terminator_effect(location);
200-
} else {
201-
debug!(
202-
"add_liveness_constraints: reconstruct_statement_effect from {:#?}",
203-
location
204-
);
205-
self.flow_inits.reconstruct_statement_effect(location);
206-
}
207-
self.flow_inits.apply_local_effect(location);
208-
}
209-
}
210-
211111
/// Some variable with type `live_ty` is "regular live" at
212112
/// `location` -- i.e., it may be used later. This means that all
213113
/// regions appearing in the type `live_ty` must be live at
@@ -230,75 +130,6 @@ impl<'cx, 'cg, 'gcx, 'tcx> ConstraintGeneration<'cx, 'cg, 'gcx, 'tcx> {
230130
});
231131
}
232132

233-
/// Some variable with type `live_ty` is "drop live" at `location`
234-
/// -- i.e., it may be dropped later. This means that *some* of
235-
/// the regions in its type must be live at `location`. The
236-
/// precise set will depend on the dropck constraints, and in
237-
/// particular this takes `#[may_dangle]` into account.
238-
fn add_drop_live_constraint(&mut self, dropped_ty: Ty<'tcx>, location: Location) {
239-
debug!(
240-
"add_drop_live_constraint(dropped_ty={:?}, location={:?})",
241-
dropped_ty,
242-
location
243-
);
244-
245-
let tcx = self.infcx.tcx;
246-
let mut types = vec![(dropped_ty, 0)];
247-
let mut known = FxHashSet();
248-
while let Some((ty, depth)) = types.pop() {
249-
let span = DUMMY_SP; // FIXME
250-
let result = match tcx.dtorck_constraint_for_ty(span, dropped_ty, depth, ty) {
251-
Ok(result) => result,
252-
Err(ErrorReported) => {
253-
continue;
254-
}
255-
};
256-
257-
let ty::DtorckConstraint {
258-
outlives,
259-
dtorck_types,
260-
} = result;
261-
262-
// All things in the `outlives` array may be touched by
263-
// the destructor and must be live at this point.
264-
for outlive in outlives {
265-
self.add_regular_live_constraint(outlive, location);
266-
}
267-
268-
// However, there may also be some types that
269-
// `dtorck_constraint_for_ty` could not resolve (e.g.,
270-
// associated types and parameters). We need to normalize
271-
// associated types here and possibly recursively process.
272-
for ty in dtorck_types {
273-
let cause = ObligationCause::dummy();
274-
// We know that our original `dropped_ty` is well-formed,
275-
// so region obligations resulting from this normalization
276-
// should always hold.
277-
//
278-
// Therefore we ignore them instead of trying to match
279-
// them up with a location.
280-
let fulfillcx = traits::FulfillmentContext::new_ignoring_regions();
281-
match traits::fully_normalize_with_fulfillcx(
282-
self.infcx, fulfillcx, cause, self.param_env, &ty
283-
) {
284-
Ok(ty) => match ty.sty {
285-
ty::TyParam(..) | ty::TyProjection(..) | ty::TyAnon(..) => {
286-
self.add_regular_live_constraint(ty, location);
287-
}
288-
289-
_ => if known.insert(ty) {
290-
types.push((ty, depth + 1));
291-
},
292-
},
293-
294-
Err(errors) => {
295-
self.infcx.report_fulfillment_errors(&errors, None);
296-
}
297-
}
298-
}
299-
}
300-
}
301-
302133
fn add_reborrow_constraint(
303134
&mut self,
304135
location: Location,

src/librustc_mir/borrow_check/nll/mod.rs

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -77,27 +77,26 @@ pub(in borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>(
7777
) {
7878
// Run the MIR type-checker.
7979
let mir_node_id = infcx.tcx.hir.as_local_node_id(def_id).unwrap();
80-
let constraint_sets = &type_check::type_check(infcx, mir_node_id, param_env, mir);
80+
let liveness = &LivenessResults::compute(mir);
81+
let constraint_sets = &type_check::type_check(
82+
infcx,
83+
mir_node_id,
84+
param_env,
85+
mir,
86+
&liveness,
87+
flow_inits,
88+
move_data,
89+
);
8190

8291
// Create the region inference context, taking ownership of the region inference
8392
// data that was contained in `infcx`.
8493
let var_origins = infcx.take_region_var_origins();
8594
let mut regioncx = RegionInferenceContext::new(var_origins, universal_regions, mir);
8695
subtype_constraint_generation::generate(&mut regioncx, mir, constraint_sets);
8796

88-
// Compute what is live where.
89-
let liveness = &LivenessResults::compute(mir);
9097

9198
// Generate non-subtyping constraints.
92-
constraint_generation::generate_constraints(
93-
infcx,
94-
&mut regioncx,
95-
&mir,
96-
param_env,
97-
liveness,
98-
flow_inits,
99-
move_data,
100-
);
99+
constraint_generation::generate_constraints(infcx, &mut regioncx, &mir);
101100

102101
// Solve the region constraints.
103102
let closure_region_requirements = regioncx.solve(infcx, &mir, def_id);

src/librustc_mir/borrow_check/nll/region_infer/mod.rs

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -425,11 +425,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
425425
/// therefore add `end('a)` into the region for `'b` -- but we
426426
/// have no evidence that `'b` outlives `'a`, so we want to report
427427
/// an error.
428-
fn check_type_tests(
429-
&self,
430-
infcx: &InferCtxt<'_, '_, 'tcx>,
431-
mir: &Mir<'tcx>,
432-
) {
428+
fn check_type_tests(&self, infcx: &InferCtxt<'_, '_, 'tcx>, mir: &Mir<'tcx>) {
433429
for type_test in &self.type_tests {
434430
debug!("check_type_test: {:?}", type_test);
435431

@@ -473,13 +469,13 @@ impl<'tcx> RegionInferenceContext<'tcx> {
473469
.iter()
474470
.any(|&r| self.eval_outlives(mir, r, lower_bound, point)),
475471

476-
RegionTest::Any(tests) => tests
477-
.iter()
478-
.any(|test| self.eval_region_test(mir, point, lower_bound, test)),
472+
RegionTest::Any(tests) => tests.iter().any(|test| {
473+
self.eval_region_test(mir, point, lower_bound, test)
474+
}),
479475

480-
RegionTest::All(tests) => tests
481-
.iter()
482-
.all(|test| self.eval_region_test(mir, point, lower_bound, test)),
476+
RegionTest::All(tests) => tests.iter().all(|test| {
477+
self.eval_region_test(mir, point, lower_bound, test)
478+
}),
483479
}
484480
}
485481

0 commit comments

Comments
 (0)