Skip to content

Commit 55a73d9

Browse files
authored
Merge pull request #42 from lqd/opt_errors
Make DatafrogOpt produce errors
2 parents b63eb48 + c754a90 commit 55a73d9

File tree

2 files changed

+65
-29
lines changed

2 files changed

+65
-29
lines changed

src/output/datafrog_opt.rs

Lines changed: 48 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -35,25 +35,37 @@ pub(super) fn compute(dump_enabled: bool, mut all_facts: AllFacts) -> Output {
3535

3636
let mut result = Output::new(dump_enabled);
3737

38-
let borrow_live_at = {
38+
let errors = {
3939
// Create a new iteration context, ...
4040
let mut iteration = Iteration::new();
4141

42-
// .. some variables and different indices for `subset`.
42+
// static inputs
43+
let cfg_edge = iteration.variable::<(Point, Point)>("cfg_edge");
44+
let killed = all_facts.killed.into();
45+
46+
// `invalidates` facts, stored ready for joins
47+
let invalidates = iteration.variable::<((Loan, Point), ())>("invalidates");
48+
49+
// we need `region_live_at` in both variable and relation forms.
50+
// (respectively, for join and antijoin).
51+
let region_live_at_rel =
52+
Relation::from(all_facts.region_live_at.iter().map(|&(r, p)| (r, p)));
53+
let region_live_at_var = iteration.variable::<((Region, Point), ())>("region_live_at");
54+
55+
// variables, indices for the computation rules, and temporaries for the multi-way joins
4356
let subset = iteration.variable::<(Region, Region, Point)>("subset");
4457
let subset_1 = iteration.variable_indistinct("subset_1");
4558
let subset_2 = iteration.variable_indistinct("subset_2");
4659
let subset_r1p = iteration.variable_indistinct("subset_r1p");
4760
let subset_p = iteration.variable_indistinct("subset_p");
4861

49-
// temporaries as we perform a multi-way join, and more indices
5062
let requires = iteration.variable::<(Region, Loan, Point)>("requires");
5163
let requires_1 = iteration.variable_indistinct("requires_1");
5264
let requires_2 = iteration.variable_indistinct("requires_2");
5365
let requires_bp = iteration.variable_indistinct("requires_bp");
5466
let requires_rp = iteration.variable_indistinct("requires_rp");
5567

56-
let borrow_live_at = iteration.variable::<(Loan, Point)>("borrow_live_at");
68+
let borrow_live_at = iteration.variable::<((Loan, Point), ())>("borrow_live_at");
5769

5870
let live_to_dead_regions =
5971
iteration.variable::<(Region, Region, Point, Point)>("live_to_dead_regions");
@@ -78,22 +90,19 @@ pub(super) fn compute(dump_enabled: bool, mut all_facts: AllFacts) -> Output {
7890
iteration.variable::<((Region, Point, Point), Region)>("dead_can_reach_live");
7991
let dead_can_reach_live_r1pq = iteration.variable_indistinct("dead_can_reach_live_r1pq");
8092

81-
// We need both relation and variable forms of this (for join and antijoin).
82-
let region_live_at_rel =
83-
Relation::from(all_facts.region_live_at.iter().map(|&(r, p)| (r, p)));
84-
let region_live_at_var = iteration.variable::<((Region, Point), ())>("region_live_at");
85-
86-
let cfg_edge_p = iteration.variable::<(Point, Point)>("cfg_edge_p");
87-
88-
let killed = all_facts.killed.into();
93+
// output
94+
let errors = iteration.variable("errors");
8995

9096
// load initial facts.
91-
subset.insert(all_facts.outlives.into());
92-
requires.insert(all_facts.borrow_region.into());
97+
cfg_edge.insert(all_facts.cfg_edge.into());
98+
invalidates.insert(Relation::from(
99+
all_facts.invalidates.iter().map(|&(p, b)| ((b, p), ())),
100+
));
93101
region_live_at_var.insert(Relation::from(
94102
all_facts.region_live_at.iter().map(|&(r, p)| ((r, p), ())),
95103
));
96-
cfg_edge_p.insert(all_facts.cfg_edge.into());
104+
subset.insert(all_facts.outlives.into());
105+
requires.insert(all_facts.borrow_region.into());
97106

98107
// .. and then start iterating rules!
99108
while iteration.changed() {
@@ -142,9 +151,8 @@ pub(super) fn compute(dump_enabled: bool, mut all_facts: AllFacts) -> Output {
142151
// cfg_edge(P, Q),
143152
// region_live_at(R1, Q),
144153
// !region_live_at(R2, Q).
145-
live_to_dead_regions_1.from_join(&subset_p, &cfg_edge_p, |&p, &(r1, r2), &q| {
146-
((r1, q), (r2, p))
147-
});
154+
live_to_dead_regions_1
155+
.from_join(&subset_p, &cfg_edge, |&p, &(r1, r2), &q| ((r1, q), (r2, p)));
148156
live_to_dead_regions_2.from_join(
149157
&live_to_dead_regions_1,
150158
&region_live_at_var,
@@ -169,7 +177,7 @@ pub(super) fn compute(dump_enabled: bool, mut all_facts: AllFacts) -> Output {
169177
dead_region_requires_1.from_antijoin(&requires_bp, &killed, |&(b, p), &r| (p, (b, r)));
170178
dead_region_requires_2.from_join(
171179
&dead_region_requires_1,
172-
&cfg_edge_p,
180+
&cfg_edge,
173181
|&p, &(b, r), &q| ((r, q), (b, p)),
174182
);
175183
dead_region_requires.from_antijoin(
@@ -236,14 +244,14 @@ pub(super) fn compute(dump_enabled: bool, mut all_facts: AllFacts) -> Output {
236244
);
237245

238246
// subset(R1, R2, Q) :-
239-
// subset(R1, R2, P) :-
247+
// subset(R1, R2, P),
240248
// cfg_edge(P, Q),
241249
// region_live_at(R1, Q),
242250
// region_live_at(R2, Q).
243251
//
244252
// Carry `R1 <= R2` from P into Q if both `R1` and
245253
// `R2` are live in Q.
246-
subset_1.from_join(&subset_p, &cfg_edge_p, |&_p, &(r1, r2), &q| ((r1, q), r2));
254+
subset_1.from_join(&subset_p, &cfg_edge, |&_p, &(r1, r2), &q| ((r1, q), r2));
247255
subset_2.from_join(&subset_1, &region_live_at_var, |&(r1, q), &r2, &()| {
248256
((r2, q), r1)
249257
});
@@ -281,7 +289,7 @@ pub(super) fn compute(dump_enabled: bool, mut all_facts: AllFacts) -> Output {
281289
// cfg_edge(P, Q),
282290
// region_live_at(R, Q).
283291
requires_1.from_antijoin(&requires_bp, &killed, |&(b, p), &r| (p, (r, b)));
284-
requires_2.from_join(&requires_1, &cfg_edge_p, |&_p, &(r, b), &q| ((r, q), b));
292+
requires_2.from_join(&requires_1, &cfg_edge, |&_p, &(r, b), &q| ((r, q), b));
285293
requires.from_join(&requires_2, &region_live_at_var, |&(r, q), &b, &()| {
286294
(r, b, q)
287295
});
@@ -291,8 +299,11 @@ pub(super) fn compute(dump_enabled: bool, mut all_facts: AllFacts) -> Output {
291299
//
292300
// borrow_live_at(B, P) :- requires(R, B, P), region_live_at(R, P)
293301
borrow_live_at.from_join(&requires_rp, &region_live_at_var, |&(_r, p), &b, &()| {
294-
(b, p)
302+
((b, p), ())
295303
});
304+
305+
// .decl errors(B, P) :- invalidates(B, P), borrow_live_at(B, P).
306+
errors.from_join(&invalidates, &borrow_live_at, |&(b, p), &(), &()| (b, p));
296307
}
297308

298309
if dump_enabled {
@@ -326,22 +337,31 @@ pub(super) fn compute(dump_enabled: bool, mut all_facts: AllFacts) -> Output {
326337
.or_insert(BTreeSet::new())
327338
.insert(*borrow);
328339
}
340+
341+
let borrow_live_at = borrow_live_at.complete();
342+
for ((borrow, location), ()) in &borrow_live_at.elements {
343+
result
344+
.borrow_live_at
345+
.entry(*location)
346+
.or_insert(Vec::new())
347+
.push(*borrow);
348+
}
329349
}
330350

331-
borrow_live_at.complete()
351+
errors.complete()
332352
};
333353

334354
if dump_enabled {
335355
println!(
336-
"borrow_live_at is complete: {} tuples, {:?}",
337-
borrow_live_at.len(),
356+
"errors is complete: {} tuples, {:?}",
357+
errors.len(),
338358
timer.elapsed()
339359
);
340360
}
341361

342-
for (borrow, location) in &borrow_live_at.elements {
362+
for (borrow, location) in &errors.elements {
343363
result
344-
.borrow_live_at
364+
.potential_errors
345365
.entry(*location)
346366
.or_insert(Vec::new())
347367
.push(*borrow);

src/test.rs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ fn test_fn(dir_name: &str, fn_name: &str) -> Result<(), Error> {
2020
let tables = &mut intern::InternerTables::new();
2121
let all_facts = tab_delim::load_tab_delimited_facts(tables, &facts_dir)?;
2222
let naive = Output::compute(&all_facts, Algorithm::Naive, false);
23-
let opt = Output::compute(&all_facts, Algorithm::DatafrogOpt, false);
23+
let opt = Output::compute(&all_facts, Algorithm::DatafrogOpt, true);
2424
assert_eq!(naive.borrow_live_at, opt.borrow_live_at);
2525
}
2626
}
@@ -60,3 +60,19 @@ fn test_insensitive_potential_error() -> Result<(), Error> {
6060
assert_eq!(insensitive.potential_errors, expected);
6161
}
6262
}
63+
64+
#[test]
65+
fn test_sensitive_passes_issue_47680() -> Result<(), Error> {
66+
do catch {
67+
let facts_dir = Path::new(env!("CARGO_MANIFEST_DIR"))
68+
.join("inputs")
69+
.join("issue-47680")
70+
.join("nll-facts")
71+
.join("main");
72+
let tables = &mut intern::InternerTables::new();
73+
let all_facts = tab_delim::load_tab_delimited_facts(tables, &facts_dir)?;
74+
let sensitive = Output::compute(&all_facts, Algorithm::DatafrogOpt, false);
75+
76+
assert!(sensitive.potential_errors.is_empty());
77+
}
78+
}

0 commit comments

Comments
 (0)