Skip to content

Commit d580ea4

Browse files
committed
Remove use of AllFacts everywhere and divide it into type-safe step-dedicated contexts
1 parent 61d763e commit d580ea4

File tree

6 files changed

+114
-120
lines changed

6 files changed

+114
-120
lines changed

polonius-engine/src/output/datafrog_opt.rs

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,10 @@ pub(super) fn compute<T: FactTypes>(
2121
let timer = Instant::now();
2222

2323
let errors = {
24-
let all_facts = &ctx.all_facts;
25-
2624
// Static inputs
25+
let region_live_at_rel = &ctx.region_live_at;
2726
let cfg_edge_rel = &ctx.cfg_edge;
2827
let killed_rel = &ctx.killed;
29-
let region_live_at_rel = &ctx.region_live_at;
3028

3129
// Create a new iteration context, ...
3230
let mut iteration = Iteration::new();
@@ -130,16 +128,14 @@ pub(super) fn compute<T: FactTypes>(
130128

131129
// Make "variable" versions of the relations, needed for joins.
132130
borrow_region_op.extend(
133-
all_facts
134-
.borrow_region
131+
ctx.borrow_region
135132
.iter()
136133
.map(|&(origin, loan, point)| ((origin, point), loan)),
137134
);
138135
invalidates.extend(
139-
all_facts
140-
.invalidates
136+
ctx.invalidates
141137
.iter()
142-
.map(|&(point, loan)| ((loan, point), ())),
138+
.map(|&(loan, point)| ((loan, point), ())),
143139
);
144140
region_live_at_var.extend(
145141
region_live_at_rel
@@ -149,16 +145,14 @@ pub(super) fn compute<T: FactTypes>(
149145

150146
// subset(origin1, origin2, point) :- outlives(origin1, origin2, point).
151147
subset_o1p.extend(
152-
all_facts
153-
.outlives
148+
ctx.outlives
154149
.iter()
155150
.map(|&(origin1, origin2, point)| ((origin1, point), origin2)),
156151
);
157152

158153
// requires(origin, loan, point) :- borrow_region(origin, loan, point).
159154
requires_op.extend(
160-
all_facts
161-
.borrow_region
155+
ctx.borrow_region
162156
.iter()
163157
.map(|&(origin, loan, point)| ((origin, point), loan)),
164158
);

polonius-engine/src/output/initialization.rs

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,12 @@
11
use std::time::Instant;
22

3-
use crate::output::Output;
4-
use facts::FactTypes;
3+
use crate::facts::FactTypes;
4+
use crate::output::{InitializationContext, Output};
55

66
use datafrog::{Iteration, Relation, RelationLeaper};
77

88
pub(super) fn init_var_maybe_initialized_on_exit<T: FactTypes>(
9-
child: Vec<(T::Path, T::Path)>,
10-
path_belongs_to_var: Vec<(T::Path, T::Variable)>,
11-
initialized_at: Vec<(T::Path, T::Point)>,
12-
moved_out_at: Vec<(T::Path, T::Point)>,
13-
path_accessed_at: Vec<(T::Path, T::Point)>,
9+
ctx: InitializationContext<T>,
1410
cfg_edge: &Relation<(T::Point, T::Point)>,
1511
output: &mut Output<T>,
1612
) -> Relation<(T::Variable, T::Point)> {
@@ -19,11 +15,11 @@ pub(super) fn init_var_maybe_initialized_on_exit<T: FactTypes>(
1915

2016
// Relations
2117
//let parent: Relation<(Path, Path)> = child.iter().map(|&(child_path, parent_path)| (parent_path, child_path)).collect();
22-
let child: Relation<(T::Path, T::Path)> = child.into();
23-
let path_belongs_to_var: Relation<(T::Path, T::Variable)> = path_belongs_to_var.into();
24-
let initialized_at: Relation<(T::Path, T::Point)> = initialized_at.into();
25-
let moved_out_at: Relation<(T::Path, T::Point)> = moved_out_at.into();
26-
let _path_accessed_at: Relation<(T::Path, T::Point)> = path_accessed_at.into();
18+
let child: Relation<(T::Path, T::Path)> = ctx.child.into();
19+
let path_belongs_to_var: Relation<(T::Path, T::Variable)> = ctx.path_belongs_to_var.into();
20+
let initialized_at: Relation<(T::Path, T::Point)> = ctx.initialized_at.into();
21+
let moved_out_at: Relation<(T::Path, T::Point)> = ctx.moved_out_at.into();
22+
let _path_accessed_at: Relation<(T::Path, T::Point)> = ctx.path_accessed_at.into();
2723

2824
// Variables
2925

polonius-engine/src/output/liveness.rs

Lines changed: 9 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,13 @@
1313
use std::collections::BTreeSet;
1414
use std::time::Instant;
1515

16-
use crate::output::Output;
17-
use facts::FactTypes;
16+
use crate::facts::FactTypes;
17+
use crate::output::{LivenessContext, Output};
1818

1919
use datafrog::{Iteration, Relation, RelationLeaper};
2020

2121
pub(super) fn compute_live_regions<T: FactTypes>(
22-
var_used: Vec<(T::Variable, T::Point)>,
23-
var_drop_used: Vec<(T::Variable, T::Point)>,
24-
var_defined: Vec<(T::Variable, T::Point)>,
25-
var_uses_region: Vec<(T::Variable, T::Origin)>,
26-
var_drops_region: Vec<(T::Variable, T::Origin)>,
22+
ctx: LivenessContext<T>,
2723
cfg_edge_rel: &Relation<(T::Point, T::Point)>,
2824
var_maybe_initialized_on_exit_rel: Relation<(T::Variable, T::Point)>,
2925
output: &mut Output<T>,
@@ -32,14 +28,15 @@ pub(super) fn compute_live_regions<T: FactTypes>(
3228
let mut iteration = Iteration::new();
3329

3430
// Relations
35-
let var_defined_rel: Relation<(T::Variable, T::Point)> = var_defined.into();
31+
let var_defined_rel: Relation<(T::Variable, T::Point)> = ctx.var_defined.into();
3632
let cfg_edge_reverse_rel: Relation<(T::Point, T::Point)> = cfg_edge_rel
3733
.iter()
3834
.map(|&(point1, point2)| (point2, point1))
3935
.collect();
40-
let var_uses_region_rel: Relation<(T::Variable, T::Origin)> = var_uses_region.into();
41-
let var_drops_region_rel: Relation<(T::Variable, T::Origin)> = var_drops_region.into();
42-
let var_drop_used_rel: Relation<((T::Variable, T::Point), ())> = var_drop_used
36+
let var_uses_region_rel: Relation<(T::Variable, T::Origin)> = ctx.var_uses_region.into();
37+
let var_drops_region_rel: Relation<(T::Variable, T::Origin)> = ctx.var_drops_region.into();
38+
let var_drop_used_rel: Relation<((T::Variable, T::Point), ())> = ctx
39+
.var_drop_used
4340
.into_iter()
4441
.map(|(var, point)| ((var, point), ()))
4542
.collect();
@@ -55,7 +52,7 @@ pub(super) fn compute_live_regions<T: FactTypes>(
5552
let region_live_at_var = iteration.variable::<(T::Origin, T::Point)>("region_live_at");
5653

5754
// This propagates the relation `var_live(var, point) :- var_used(var, point)`:
58-
var_live_var.insert(var_used.into());
55+
var_live_var.insert(ctx.var_used.into());
5956

6057
// var_maybe_initialized_on_entry(var, point2) :-
6158
// var_maybe_initialized_on_exit(var, point1),
@@ -173,31 +170,3 @@ pub(super) fn make_universal_regions_live<T: FactTypes>(
173170
}
174171
}
175172
}
176-
177-
pub(super) fn init_region_live_at<T: FactTypes>(
178-
var_used: Vec<(T::Variable, T::Point)>,
179-
var_drop_used: Vec<(T::Variable, T::Point)>,
180-
var_defined: Vec<(T::Variable, T::Point)>,
181-
var_uses_region: Vec<(T::Variable, T::Origin)>,
182-
var_drops_region: Vec<(T::Variable, T::Origin)>,
183-
var_maybe_initialized_on_exit: Relation<(T::Variable, T::Point)>,
184-
cfg_edge: &Relation<(T::Point, T::Point)>,
185-
universal_regions: Vec<T::Origin>,
186-
output: &mut Output<T>,
187-
) -> Vec<(T::Origin, T::Point)> {
188-
debug!("init_region_live_at()");
189-
let mut region_live_at = compute_live_regions(
190-
var_used,
191-
var_drop_used,
192-
var_defined,
193-
var_uses_region,
194-
var_drops_region,
195-
cfg_edge,
196-
var_maybe_initialized_on_exit,
197-
output,
198-
);
199-
200-
make_universal_regions_live::<T>(&mut region_live_at, cfg_edge, universal_regions);
201-
202-
region_live_at
203-
}

polonius-engine/src/output/location_insensitive.rs

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,6 @@ pub(super) fn compute<T: FactTypes>(
2121
let timer = Instant::now();
2222

2323
let potential_errors = {
24-
let all_facts = &ctx.all_facts;
25-
2624
// Static inputs
2725
let region_live_at = &ctx.region_live_at;
2826
let invalidates = &ctx.invalidates;
@@ -40,16 +38,14 @@ pub(super) fn compute<T: FactTypes>(
4038

4139
// subset(origin1, origin2) :- outlives(origin1, origin2, _point)
4240
subset.extend(
43-
all_facts
44-
.outlives
41+
ctx.outlives
4542
.iter()
4643
.map(|&(origin1, origin2, _point)| (origin1, origin2)),
4744
);
4845

4946
// requires(origin, loan) :- borrow_region(origin, loan, _point).
5047
requires.extend(
51-
all_facts
52-
.borrow_region
48+
ctx.borrow_region
5349
.iter()
5450
.map(|&(origin, loan, _point)| (origin, loan)),
5551
);

polonius-engine/src/output/mod.rs

Lines changed: 85 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ use datafrog::Relation;
1212
use rustc_hash::{FxHashMap, FxHashSet};
1313
use std::borrow::Cow;
1414
use std::collections::{BTreeMap, BTreeSet};
15-
use std::mem;
1615

1716
use crate::facts::{AllFacts, Atom, FactTypes};
1817

@@ -94,61 +93,102 @@ pub struct Output<T: FactTypes> {
9493
pub var_maybe_initialized_on_exit: FxHashMap<T::Point, Vec<T::Variable>>,
9594
}
9695

97-
struct Context<T: FactTypes> {
98-
all_facts: AllFacts<T>,
96+
/// Subset of `AllFacts` dedicated to initialization
97+
struct InitializationContext<T: FactTypes> {
98+
child: Vec<(T::Path, T::Path)>,
99+
path_belongs_to_var: Vec<(T::Path, T::Variable)>,
100+
initialized_at: Vec<(T::Path, T::Point)>,
101+
moved_out_at: Vec<(T::Path, T::Point)>,
102+
path_accessed_at: Vec<(T::Path, T::Point)>,
103+
}
104+
105+
/// Subset of `AllFacts` dedicated to liveness
106+
struct LivenessContext<T: FactTypes> {
107+
var_used: Vec<(T::Variable, T::Point)>,
108+
var_defined: Vec<(T::Variable, T::Point)>,
109+
var_drop_used: Vec<(T::Variable, T::Point)>,
110+
var_uses_region: Vec<(T::Variable, T::Origin)>,
111+
var_drops_region: Vec<(T::Variable, T::Origin)>,
112+
}
99113

100-
// `Relation`s used by multiple variants as static inputs
114+
/// Subset of `AllFacts` dedicated to borrow checking, and data ready to use by the variants
115+
struct Context<'ctx, T: FactTypes> {
116+
// `Relation`s used as static inputs, by all variants
101117
region_live_at: Relation<(T::Origin, T::Point)>,
102118
invalidates: Relation<(T::Loan, T::Point)>,
103-
cfg_edge: Relation<(T::Point, T::Point)>,
119+
120+
// static inputs used via `Variable`s, by all variants
121+
outlives: &'ctx Vec<(T::Origin, T::Origin, T::Point)>,
122+
borrow_region: &'ctx Vec<(T::Origin, T::Loan, T::Point)>,
123+
124+
// static inputs used by variants other than `LocationInsensitive`
104125
killed: Relation<(T::Loan, T::Point)>,
105126

127+
// while this static input is unused by `LocationInsensitive`, it's depended on by initialization
128+
// and liveness, so already computed by the time we get to borrowcking.
129+
cfg_edge: Relation<(T::Point, T::Point)>,
130+
106131
// Partial results possibly used by other variants as input
107-
potential_errors: FxHashSet<T::Loan>,
132+
potential_errors: Option<FxHashSet<T::Loan>>,
108133
}
109134

110135
impl<T: FactTypes> Output<T> {
136+
/// All variants require the same initial preparations, done in multiple
137+
/// successive steps:
138+
/// - compute initialization data
139+
/// - compute liveness
140+
/// - prepare static inputs as shared `Relation`s
141+
/// - in cases where `LocationInsensitive` variant is ran as a filtering pre-pass,
142+
/// partial results can also be stored in the context, so that the following
143+
/// variant can use it to prune its own input data
111144
pub fn compute(all_facts: &AllFacts<T>, algorithm: Algorithm, dump_enabled: bool) -> Self {
112-
// All variants require the same initial preparations, done in multiple
113-
// successive steps:
114-
// - compute initialization data
115-
// - compute liveness
116-
// - prepare static inputs as shared `Relation`s
117-
// - in cases where `LocationInsensitive` variant is ran as a filtering pre-pass,
118-
// partial results can also be stored in the context, so that the following
119-
// variant can use it to prune its own input data
120-
121-
// TODO: remove the need for this clone in concert here and in rustc
122-
let mut all_facts = all_facts.clone();
123-
124145
let mut result = Output::new(dump_enabled);
125146

126-
let cfg_edge = mem::replace(&mut all_facts.cfg_edge, Vec::new()).into();
147+
// TODO: remove all the cloning thereafter, but that needs to be done in concert with rustc
148+
149+
let cfg_edge = all_facts.cfg_edge.clone().into();
150+
151+
// 1) Initialization
152+
let initialization_ctx = InitializationContext {
153+
child: all_facts.child.clone(),
154+
path_belongs_to_var: all_facts.path_belongs_to_var.clone(),
155+
initialized_at: all_facts.initialized_at.clone(),
156+
moved_out_at: all_facts.moved_out_at.clone(),
157+
path_accessed_at: all_facts.path_accessed_at.clone(),
158+
};
127159

128-
// Initialization
129160
let var_maybe_initialized_on_exit = initialization::init_var_maybe_initialized_on_exit(
130-
mem::replace(&mut all_facts.child, Vec::new()),
131-
mem::replace(&mut all_facts.path_belongs_to_var, Vec::new()),
132-
mem::replace(&mut all_facts.initialized_at, Vec::new()),
133-
mem::replace(&mut all_facts.moved_out_at, Vec::new()),
134-
mem::replace(&mut all_facts.path_accessed_at, Vec::new()),
161+
initialization_ctx,
135162
&cfg_edge,
136163
&mut result,
137164
);
138165

139-
// Liveness
140-
let region_live_at = liveness::init_region_live_at(
141-
mem::replace(&mut all_facts.var_used, Vec::new()),
142-
mem::replace(&mut all_facts.var_drop_used, Vec::new()),
143-
mem::replace(&mut all_facts.var_defined, Vec::new()),
144-
mem::replace(&mut all_facts.var_uses_region, Vec::new()),
145-
mem::replace(&mut all_facts.var_drops_region, Vec::new()),
146-
var_maybe_initialized_on_exit,
166+
// 2) Liveness
167+
let universal_regions = all_facts.universal_region.clone();
168+
169+
let liveness_ctx = LivenessContext {
170+
var_used: all_facts.var_used.clone(),
171+
var_defined: all_facts.var_defined.clone(),
172+
var_drop_used: all_facts.var_drop_used.clone(),
173+
var_uses_region: all_facts.var_uses_region.clone(),
174+
var_drops_region: all_facts.var_drops_region.clone(),
175+
};
176+
177+
let mut region_live_at = liveness::compute_live_regions(
178+
liveness_ctx,
147179
&cfg_edge,
148-
mem::replace(&mut all_facts.universal_region, Vec::new()),
180+
var_maybe_initialized_on_exit,
149181
&mut result,
150182
);
151183

184+
liveness::make_universal_regions_live::<T>(
185+
&mut region_live_at,
186+
&cfg_edge,
187+
universal_regions,
188+
);
189+
190+
// 3) Borrow checking
191+
152192
// Prepare data as datafrog relations, ready to join.
153193
//
154194
// Note: if rustc and polonius had more interaction, we could also delay or avoid
@@ -160,26 +200,28 @@ impl<T: FactTypes> Output<T> {
160200
// be recorded in separate MIR walks, we might also avoid generating those facts.
161201

162202
let region_live_at = region_live_at.into();
163-
let killed = mem::replace(&mut all_facts.killed, Vec::new()).into();
164203

165-
// TODO: flip the order of this relation's arguments in rustc
166-
// from `invalidates(loan, point)` to `invalidates(point, loan)`.
204+
// TODO: also flip the order of this relation's arguments in rustc
205+
// from `invalidates(point, loan)` to `invalidates(loan, point)`.
167206
// to avoid this allocation.
168207
let invalidates = Relation::from_iter(
169208
all_facts
170209
.invalidates
171210
.iter()
172-
.map(|&(loan, point)| (point, loan)),
211+
.map(|&(point, loan)| (loan, point)),
173212
);
174213

214+
let killed = all_facts.killed.clone().into();
215+
175216
// Ask the variants to compute errors in their own way
176217
let mut ctx = Context {
177-
all_facts,
178218
region_live_at,
179-
cfg_edge,
180219
invalidates,
220+
cfg_edge,
221+
outlives: &all_facts.outlives,
222+
borrow_region: &all_facts.borrow_region,
181223
killed,
182-
potential_errors: FxHashSet::default(),
224+
potential_errors: None,
183225
};
184226

185227
let errors = match algorithm {
@@ -196,8 +238,8 @@ impl<T: FactTypes> Output<T> {
196238
} else {
197239
// Record these potential errors as they can be used to limit the next
198240
// variant's work to only these loans.
199-
ctx.potential_errors
200-
.extend(potential_errors.iter().map(|&(loan, _)| loan));
241+
ctx.potential_errors =
242+
Some(potential_errors.iter().map(|&(loan, _)| loan).collect());
201243

202244
datafrog_opt::compute(&ctx, &mut result)
203245
}

0 commit comments

Comments
 (0)