Skip to content

Commit 92799b6

Browse files
committed
Separate Analysis and Results.
`Results` contains and `Analysis` and an `EntryStates`. The unfortunate thing about this is that the analysis needs to be mutable everywhere (`&mut Analysis`) which forces the `Results` to be mutable everywhere, even though `EntryStates` is immutable everywhere. To fix this, this commit renames `Results` as `AnalysisAndResults`, renames `EntryStates` as `Results`, and separates the analysis and results as much as possible. (`AnalysisAndResults` doesn't get much use, it's mostly there to facilitate method chaining of `iterate_to_fixpoint`.) `Results` is immutable everywhere, which: - is a bit clearer on how the data is used, - avoids an unnecessary clone of entry states in `locals_live_across_suspend_points`, and - moves the results outside the `RefCell` in Formatter. The commit also reformulates `ResultsHandle` as the generic `CowMut`, which is simpler than `ResultsHandle` because it doesn't need the `'tcx` lifetime and the trait bounds. It also which sits nicely alongside the new use of `Cow` in `ResultsCursor`.
1 parent 4ff5558 commit 92799b6

File tree

16 files changed

+188
-174
lines changed

16 files changed

+188
-174
lines changed

compiler/rustc_borrowck/src/lib.rs

+11-9
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ use rustc_mir_dataflow::impls::{
4747
use rustc_mir_dataflow::move_paths::{
4848
InitIndex, InitLocation, LookupResult, MoveData, MovePathIndex,
4949
};
50-
use rustc_mir_dataflow::{Analysis, EntryStates, Results, ResultsVisitor, visit_results};
50+
use rustc_mir_dataflow::{Analysis, Results, ResultsVisitor, visit_results};
5151
use rustc_session::lint::builtin::{TAIL_EXPR_DROP_ORDER, UNUSED_MUT};
5252
use rustc_span::{ErrorGuaranteed, Span, Symbol};
5353
use smallvec::SmallVec;
@@ -461,11 +461,13 @@ fn do_mir_borrowck<'tcx>(
461461
// Compute and report region errors, if any.
462462
mbcx.report_region_errors(nll_errors);
463463

464-
let mut flow_results = get_flow_results(tcx, body, &move_data, &borrow_set, &regioncx);
464+
let (mut flow_analysis, flow_entry_states) =
465+
get_flow_results(tcx, body, &move_data, &borrow_set, &regioncx);
465466
visit_results(
466467
body,
467468
traversal::reverse_postorder(body).map(|(bb, _)| bb),
468-
&mut flow_results,
469+
&mut flow_analysis,
470+
&flow_entry_states,
469471
&mut mbcx,
470472
);
471473

@@ -525,7 +527,7 @@ fn get_flow_results<'a, 'tcx>(
525527
move_data: &'a MoveData<'tcx>,
526528
borrow_set: &'a BorrowSet<'tcx>,
527529
regioncx: &RegionInferenceContext<'tcx>,
528-
) -> Results<'tcx, Borrowck<'a, 'tcx>> {
530+
) -> (Borrowck<'a, 'tcx>, Results<BorrowckDomain>) {
529531
// We compute these three analyses individually, but them combine them into
530532
// a single results so that `mbcx` can visit them all together.
531533
let borrows = Borrows::new(tcx, body, regioncx, borrow_set).iterate_to_fixpoint(
@@ -550,14 +552,14 @@ fn get_flow_results<'a, 'tcx>(
550552
ever_inits: ever_inits.analysis,
551553
};
552554

553-
assert_eq!(borrows.entry_states.len(), uninits.entry_states.len());
554-
assert_eq!(borrows.entry_states.len(), ever_inits.entry_states.len());
555-
let entry_states: EntryStates<'_, Borrowck<'_, '_>> =
556-
itertools::izip!(borrows.entry_states, uninits.entry_states, ever_inits.entry_states)
555+
assert_eq!(borrows.results.len(), uninits.results.len());
556+
assert_eq!(borrows.results.len(), ever_inits.results.len());
557+
let results: Results<_> =
558+
itertools::izip!(borrows.results, uninits.results, ever_inits.results)
557559
.map(|(borrows, uninits, ever_inits)| BorrowckDomain { borrows, uninits, ever_inits })
558560
.collect();
559561

560-
Results { analysis, entry_states }
562+
(analysis, results)
561563
}
562564

563565
pub(crate) struct BorrowckInferCtxt<'tcx> {

compiler/rustc_mir_dataflow/src/framework/cursor.rs

+47-31
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
//! Random access inspection of the results of a dataflow analysis.
22
3+
use std::borrow::Cow;
34
use std::cmp::Ordering;
45
use std::ops::{Deref, DerefMut};
56

@@ -9,38 +10,30 @@ use rustc_middle::mir::{self, BasicBlock, Location};
910

1011
use super::{Analysis, Direction, Effect, EffectIndex, Results};
1112

12-
/// Some `ResultsCursor`s want to own a `Results`, and some want to borrow a `Results`, either
13-
/// mutable or immutably. This type allows all of the above. It's similar to `Cow`.
14-
pub enum ResultsHandle<'a, 'tcx, A>
15-
where
16-
A: Analysis<'tcx>,
17-
{
18-
BorrowedMut(&'a mut Results<'tcx, A>),
19-
Owned(Results<'tcx, A>),
13+
/// Some `ResultsCursor`s want to own an `Analysis`, and some want to borrow an `Analysis`, either
14+
/// mutable or immutably. This type allows all of the above. It's similar to `Cow`, but `Cow`
15+
/// doesn't allow mutable borrowing.
16+
enum CowMut<'a, T> {
17+
BorrowedMut(&'a mut T),
18+
Owned(T),
2019
}
2120

22-
impl<'tcx, A> Deref for ResultsHandle<'_, 'tcx, A>
23-
where
24-
A: Analysis<'tcx>,
25-
{
26-
type Target = Results<'tcx, A>;
21+
impl<T> Deref for CowMut<'_, T> {
22+
type Target = T;
2723

28-
fn deref(&self) -> &Results<'tcx, A> {
24+
fn deref(&self) -> &T {
2925
match self {
30-
ResultsHandle::BorrowedMut(borrowed) => borrowed,
31-
ResultsHandle::Owned(owned) => owned,
26+
CowMut::BorrowedMut(borrowed) => borrowed,
27+
CowMut::Owned(owned) => owned,
3228
}
3329
}
3430
}
3531

36-
impl<'tcx, A> DerefMut for ResultsHandle<'_, 'tcx, A>
37-
where
38-
A: Analysis<'tcx>,
39-
{
40-
fn deref_mut(&mut self) -> &mut Results<'tcx, A> {
32+
impl<T> DerefMut for CowMut<'_, T> {
33+
fn deref_mut(&mut self) -> &mut T {
4134
match self {
42-
ResultsHandle::BorrowedMut(borrowed) => borrowed,
43-
ResultsHandle::Owned(owned) => owned,
35+
CowMut::BorrowedMut(borrowed) => borrowed,
36+
CowMut::Owned(owned) => owned,
4437
}
4538
}
4639
}
@@ -60,7 +53,8 @@ where
6053
A: Analysis<'tcx>,
6154
{
6255
body: &'mir mir::Body<'tcx>,
63-
results: ResultsHandle<'mir, 'tcx, A>,
56+
analysis: CowMut<'mir, A>,
57+
results: Cow<'mir, Results<A::Domain>>,
6458
state: A::Domain,
6559

6660
pos: CursorPosition,
@@ -88,11 +82,15 @@ where
8882
self.body
8983
}
9084

91-
/// Returns a new cursor that can inspect `results`.
92-
pub fn new(body: &'mir mir::Body<'tcx>, results: ResultsHandle<'mir, 'tcx, A>) -> Self {
93-
let bottom_value = results.analysis.bottom_value(body);
85+
fn new(
86+
body: &'mir mir::Body<'tcx>,
87+
analysis: CowMut<'mir, A>,
88+
results: Cow<'mir, Results<A::Domain>>,
89+
) -> Self {
90+
let bottom_value = analysis.bottom_value(body);
9491
ResultsCursor {
9592
body,
93+
analysis,
9694
results,
9795

9896
// Initialize to the `bottom_value` and set `state_needs_reset` to tell the cursor that
@@ -107,6 +105,24 @@ where
107105
}
108106
}
109107

108+
/// Returns a new cursor that takes ownership of and inspects analysis results.
109+
pub fn new_owning(
110+
body: &'mir mir::Body<'tcx>,
111+
analysis: A,
112+
results: Results<A::Domain>,
113+
) -> Self {
114+
Self::new(body, CowMut::Owned(analysis), Cow::Owned(results))
115+
}
116+
117+
/// Returns a new cursor that borrows and inspects analysis results.
118+
pub fn new_borrowing(
119+
body: &'mir mir::Body<'tcx>,
120+
analysis: &'mir mut A,
121+
results: &'mir Results<A::Domain>,
122+
) -> Self {
123+
Self::new(body, CowMut::BorrowedMut(analysis), Cow::Borrowed(results))
124+
}
125+
110126
/// Allows inspection of unreachable basic blocks even with `debug_assertions` enabled.
111127
#[cfg(test)]
112128
pub(crate) fn allow_unreachable(&mut self) {
@@ -116,7 +132,7 @@ where
116132

117133
/// Returns the `Analysis` used to generate the underlying `Results`.
118134
pub fn analysis(&self) -> &A {
119-
&self.results.analysis
135+
&self.analysis
120136
}
121137

122138
/// Resets the cursor to hold the entry set for the given basic block.
@@ -128,7 +144,7 @@ where
128144
#[cfg(debug_assertions)]
129145
assert!(self.reachable_blocks.contains(block));
130146

131-
self.state.clone_from(self.results.entry_set_for_block(block));
147+
self.state.clone_from(&self.results[block]);
132148
self.pos = CursorPosition::block_entry(block);
133149
self.state_needs_reset = false;
134150
}
@@ -220,7 +236,7 @@ where
220236
let target_effect_index = effect.at_index(target.statement_index);
221237

222238
A::Direction::apply_effects_in_range(
223-
&mut self.results.analysis,
239+
&mut *self.analysis,
224240
&mut self.state,
225241
target.block,
226242
block_data,
@@ -236,7 +252,7 @@ where
236252
/// This can be used, e.g., to apply the call return effect directly to the cursor without
237253
/// creating an extra copy of the dataflow state.
238254
pub fn apply_custom_effect(&mut self, f: impl FnOnce(&mut A, &mut A::Domain)) {
239-
f(&mut self.results.analysis, &mut self.state);
255+
f(&mut self.analysis, &mut self.state);
240256
self.state_needs_reset = true;
241257
}
242258
}

compiler/rustc_mir_dataflow/src/framework/direction.rs

+6-12
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use rustc_middle::mir::{
55
};
66

77
use super::visitor::ResultsVisitor;
8-
use super::{Analysis, Effect, EffectIndex, Results};
8+
use super::{Analysis, Effect, EffectIndex};
99

1010
pub trait Direction {
1111
const IS_FORWARD: bool;
@@ -36,13 +36,13 @@ pub trait Direction {
3636
A: Analysis<'tcx>;
3737

3838
/// Called by `ResultsVisitor` to recompute the analysis domain values for
39-
/// all locations in a basic block (starting from the entry value stored
40-
/// in `Results`) and to visit them with `vis`.
39+
/// all locations in a basic block (starting from `entry_state` and to
40+
/// visit them with `vis`.
4141
fn visit_results_in_block<'mir, 'tcx, A>(
4242
state: &mut A::Domain,
4343
block: BasicBlock,
4444
block_data: &'mir mir::BasicBlockData<'tcx>,
45-
results: &mut Results<'tcx, A>,
45+
analysis: &mut A,
4646
vis: &mut impl ResultsVisitor<'tcx, A>,
4747
) where
4848
A: Analysis<'tcx>;
@@ -211,18 +211,15 @@ impl Direction for Backward {
211211
state: &mut A::Domain,
212212
block: BasicBlock,
213213
block_data: &'mir mir::BasicBlockData<'tcx>,
214-
results: &mut Results<'tcx, A>,
214+
analysis: &mut A,
215215
vis: &mut impl ResultsVisitor<'tcx, A>,
216216
) where
217217
A: Analysis<'tcx>,
218218
{
219-
state.clone_from(results.entry_set_for_block(block));
220-
221219
vis.visit_block_end(state);
222220

223221
let loc = Location { block, statement_index: block_data.statements.len() };
224222
let term = block_data.terminator();
225-
let analysis = &mut results.analysis;
226223
analysis.apply_early_terminator_effect(state, term, loc);
227224
vis.visit_after_early_terminator_effect(analysis, state, term, loc);
228225
analysis.apply_primary_terminator_effect(state, term, loc);
@@ -394,16 +391,13 @@ impl Direction for Forward {
394391
state: &mut A::Domain,
395392
block: BasicBlock,
396393
block_data: &'mir mir::BasicBlockData<'tcx>,
397-
results: &mut Results<'tcx, A>,
394+
analysis: &mut A,
398395
vis: &mut impl ResultsVisitor<'tcx, A>,
399396
) where
400397
A: Analysis<'tcx>,
401398
{
402-
state.clone_from(results.entry_set_for_block(block));
403-
404399
vis.visit_block_start(state);
405400

406-
let analysis = &mut results.analysis;
407401
for (statement_index, stmt) in block_data.statements.iter().enumerate() {
408402
let loc = Location { block, statement_index };
409403
analysis.apply_early_statement_effect(state, stmt, loc);

compiler/rustc_mir_dataflow/src/framework/graphviz.rs

+19-13
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@ use tracing::debug;
2121
use {rustc_ast as ast, rustc_graphviz as dot};
2222

2323
use super::fmt::{DebugDiffWithAdapter, DebugWithAdapter, DebugWithContext};
24-
use super::{Analysis, CallReturnPlaces, Direction, Results, ResultsCursor, ResultsVisitor};
24+
use super::{
25+
Analysis, CallReturnPlaces, Direction, Results, ResultsCursor, ResultsVisitor, visit_results,
26+
};
2527
use crate::errors::{
2628
DuplicateValuesFor, PathMustEndInFilename, RequiresAnArgument, UnknownFormatter,
2729
};
@@ -32,7 +34,8 @@ use crate::errors::{
3234
pub(super) fn write_graphviz_results<'tcx, A>(
3335
tcx: TyCtxt<'tcx>,
3436
body: &Body<'tcx>,
35-
results: &mut Results<'tcx, A>,
37+
analysis: &mut A,
38+
results: &Results<A::Domain>,
3639
pass_name: Option<&'static str>,
3740
) -> std::io::Result<()>
3841
where
@@ -77,7 +80,7 @@ where
7780

7881
let mut buf = Vec::new();
7982

80-
let graphviz = Formatter::new(body, results, style);
83+
let graphviz = Formatter::new(body, analysis, results, style);
8184
let mut render_opts =
8285
vec![dot::RenderOption::Fontname(tcx.sess.opts.unstable_opts.graphviz_font.clone())];
8386
if tcx.sess.opts.unstable_opts.graphviz_dark_mode {
@@ -203,10 +206,11 @@ where
203206
{
204207
body: &'mir Body<'tcx>,
205208
// The `RefCell` is used because `<Formatter as Labeller>::node_label`
206-
// takes `&self`, but it needs to modify the results. This is also the
209+
// takes `&self`, but it needs to modify the analysis. This is also the
207210
// reason for the `Formatter`/`BlockFormatter` split; `BlockFormatter` has
208211
// the operations that involve the mutation, i.e. within the `borrow_mut`.
209-
results: RefCell<&'mir mut Results<'tcx, A>>,
212+
analysis: RefCell<&'mir mut A>,
213+
results: &'mir Results<A::Domain>,
210214
style: OutputStyle,
211215
reachable: DenseBitSet<BasicBlock>,
212216
}
@@ -217,11 +221,12 @@ where
217221
{
218222
fn new(
219223
body: &'mir Body<'tcx>,
220-
results: &'mir mut Results<'tcx, A>,
224+
analysis: &'mir mut A,
225+
results: &'mir Results<A::Domain>,
221226
style: OutputStyle,
222227
) -> Self {
223228
let reachable = traversal::reachable_as_bitset(body);
224-
Formatter { body, results: results.into(), style, reachable }
229+
Formatter { body, analysis: analysis.into(), results, style, reachable }
225230
}
226231
}
227232

@@ -259,12 +264,12 @@ where
259264
}
260265

261266
fn node_label(&self, block: &Self::Node) -> dot::LabelText<'_> {
262-
let mut results = self.results.borrow_mut();
267+
let analysis = &mut **self.analysis.borrow_mut();
263268

264-
let diffs = StateDiffCollector::run(self.body, *block, *results, self.style);
269+
let diffs = StateDiffCollector::run(self.body, *block, analysis, self.results, self.style);
265270

266271
let mut fmt = BlockFormatter {
267-
cursor: results.as_results_cursor(self.body),
272+
cursor: ResultsCursor::new_borrowing(self.body, analysis, self.results),
268273
style: self.style,
269274
bg: Background::Light,
270275
};
@@ -692,20 +697,21 @@ impl<D> StateDiffCollector<D> {
692697
fn run<'tcx, A>(
693698
body: &Body<'tcx>,
694699
block: BasicBlock,
695-
results: &mut Results<'tcx, A>,
700+
analysis: &mut A,
701+
results: &Results<A::Domain>,
696702
style: OutputStyle,
697703
) -> Self
698704
where
699705
A: Analysis<'tcx, Domain = D>,
700706
D: DebugWithContext<A>,
701707
{
702708
let mut collector = StateDiffCollector {
703-
prev_state: results.analysis.bottom_value(body),
709+
prev_state: analysis.bottom_value(body),
704710
after: vec![],
705711
before: (style == OutputStyle::BeforeAndAfter).then_some(vec![]),
706712
};
707713

708-
results.visit_with(body, std::iter::once(block), &mut collector);
714+
visit_results(body, std::iter::once(block), analysis, results, &mut collector);
709715
collector
710716
}
711717
}

0 commit comments

Comments
 (0)