From e55aebe247611b8c1b85cda87421b6c113768c6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Re=CC=81my=20Rakic?= Date: Tue, 17 Sep 2019 23:11:44 +0200 Subject: [PATCH] The Great Renaming of 2019 (TM) Renames `MovePath`s to `Path`s, instances of `borrow` or `B` to `loans`, uses words instead of single-letter variables, etc. --- polonius-engine/src/facts.rs | 58 +-- polonius-engine/src/output/datafrog_opt.rs | 444 ++++++++++-------- polonius-engine/src/output/initialization.rs | 100 ++-- polonius-engine/src/output/liveness.rs | 135 +++--- .../src/output/location_insensitive.rs | 81 ++-- polonius-engine/src/output/mod.rs | 2 +- polonius-engine/src/output/naive.rs | 168 ++++--- src/dump.rs | 132 +++--- src/facts.rs | 4 +- src/intern.rs | 6 +- src/program.rs | 36 +- src/test.rs | 10 +- 12 files changed, 634 insertions(+), 542 deletions(-) diff --git a/polonius-engine/src/facts.rs b/polonius-engine/src/facts.rs index c9c67e64297..60355d3637d 100644 --- a/polonius-engine/src/facts.rs +++ b/polonius-engine/src/facts.rs @@ -4,64 +4,64 @@ use std::hash::Hash; /// The "facts" which are the basis of the NLL borrow analysis. #[derive(Clone, Debug)] pub struct AllFacts { - /// `borrow_region(O, L, P)` -- the origin `O` may refer to data - /// from loan `L` starting at the point `P` (this is usually the + /// `borrow_region(origin, loan, point)` -- the `origin` may refer to data + /// from `loan` starting at `point` (this is usually the /// point *after* a borrow rvalue) pub borrow_region: Vec<(T::Origin, T::Loan, T::Point)>, - /// `universal_region(O)` -- this is a "free region" within fn body + /// `universal_region(origin)` -- this is a "free region" within fn body pub universal_region: Vec, - /// `cfg_edge(P, Q)` for each edge `P -> Q` in the control flow + /// `cfg_edge(point1, point2)` for each edge `point1 -> point2` in the control flow pub cfg_edge: Vec<(T::Point, T::Point)>, - /// `killed(L, P)` when some prefix of the path borrowed at `L` is assigned at point `P` + /// `killed(loan, point)` when some prefix of the path borrowed at `loan` is assigned at `point` pub killed: Vec<(T::Loan, T::Point)>, - /// `outlives(O1, P2, P)` when we require `O1@P: O2@P` + /// `outlives(origin1, origin2, point)` when we require `origin1@point: origin2@point` pub outlives: Vec<(T::Origin, T::Origin, T::Point)>, - /// `invalidates(P, L)` when the loan `L` is invalidated at point `P` + /// `invalidates(point, loan)` when the `loan` is invalidated at `point` pub invalidates: Vec<(T::Point, T::Loan)>, - /// `var_used(V, P)` when the variable `V` is used for anything but a drop at point `P` + /// `var_used(var, point)` when the variable `var` is used for anything but a drop at `point` pub var_used: Vec<(T::Variable, T::Point)>, - /// `var_defined(V, P)` when the variable `V` is overwritten by the point `P` + /// `var_defined(var, point)` when the variable `var` is overwritten at `point` pub var_defined: Vec<(T::Variable, T::Point)>, - /// `var_used(V, P)` when the variable `V` is used in a drop at point `P` + /// `var_used(var, point)` when the variable `var` is used in a drop at `point` pub var_drop_used: Vec<(T::Variable, T::Point)>, - /// `var_uses_region(V, O)` when the type of `V` includes the origin `O` + /// `var_uses_region(var, origin)` when the type of `var` includes the `origin` pub var_uses_region: Vec<(T::Variable, T::Origin)>, - /// `var_drops_region(V, O)` when the type of `V` includes the origin `O` and uses + /// `var_drops_region(var, origin)` when the type of `var` includes the `origin` and uses /// it when dropping pub var_drops_region: Vec<(T::Variable, T::Origin)>, - /// `child(M1, M2)` when the move path `M1` is the direct or transitive child - /// of `M2`, e.g. `child(x.y, x)`, `child(x.y.z, x.y)`, `child(x.y.z, x)` + /// `child(path1, path2)` when the path `path1` is the direct or transitive child + /// of `path2`, e.g. `child(x.y, x)`, `child(x.y.z, x.y)`, `child(x.y.z, x)` /// would all be true if there was a path like `x.y.z`. - pub child: Vec<(T::MovePath, T::MovePath)>, + pub child: Vec<(T::Path, T::Path)>, - /// `path_belongs_to_var(M, V)` the root path `M` starting in variable `V`. - pub path_belongs_to_var: Vec<(T::MovePath, T::Variable)>, + /// `path_belongs_to_var(path, var)` the root path `path` starting in variable `var`. + pub path_belongs_to_var: Vec<(T::Path, T::Variable)>, - /// `initialized_at(M, P)` when the move path `M` was initialized at point - /// `P`. This fact is only emitted for a prefix `M`, and not for the - /// implicit initialization of all of `M`'s children. E.g. a statement like - /// `x.y = 3` at point `P` would give the fact `initialized_at(x.y, P)` (but - /// neither `initialized_at(x.y.z, P)` nor `initialized_at(x, P)`). - pub initialized_at: Vec<(T::MovePath, T::Point)>, + /// `initialized_at(path, point)` when the `path` was initialized at point + /// `point`. This fact is only emitted for a prefix `path`, and not for the + /// implicit initialization of all of `path`'s children. E.g. a statement like + /// `x.y = 3` at `point` would give the fact `initialized_at(x.y, point)` (but + /// neither `initialized_at(x.y.z, point)` nor `initialized_at(x, point)`). + pub initialized_at: Vec<(T::Path, T::Point)>, - /// `moved_out_at(M, P)` when the move path `M` was moved at point `P`. The + /// `moved_out_at(path, point)` when the `path` was moved at `point`. The /// same logic is applied as for `initialized_at` above. - pub moved_out_at: Vec<(T::MovePath, T::Point)>, + pub moved_out_at: Vec<(T::Path, T::Point)>, - /// `path_accessed_at(M, P)` when the move path `M` was accessed at point - /// `P`. The same logic as for `initialized_at` and `moved_out_at` applies. - pub path_accessed_at: Vec<(T::MovePath, T::Point)>, + /// `path_accessed_at(path, point)` when the `path` was accessed at point + /// `point`. The same logic as for `initialized_at` and `moved_out_at` applies. + pub path_accessed_at: Vec<(T::Path, T::Point)>, } impl Default for AllFacts { @@ -98,5 +98,5 @@ pub trait FactTypes: Copy + Clone + Debug { type Loan: Atom; type Point: Atom; type Variable: Atom; - type MovePath: Atom; + type Path: Atom; } diff --git a/polonius-engine/src/output/datafrog_opt.rs b/polonius-engine/src/output/datafrog_opt.rs index a15f2828a3c..b0fc9f02854 100644 --- a/polonius-engine/src/output/datafrog_opt.rs +++ b/polonius-engine/src/output/datafrog_opt.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::collections::{BTreeMap, BTreeSet}; use std::time::Instant; use crate::output::initialization; @@ -50,305 +49,346 @@ pub(super) fn compute(dump_enabled: bool, all_facts: AllFacts) let mut iteration = Iteration::new(); // static inputs - let cfg_edge_rel = Relation::from_iter(all_facts.cfg_edge.iter().map(|&(p, q)| (p, q))); + let cfg_edge_rel = Relation::from_iter( + all_facts + .cfg_edge + .iter() + .map(|&(point1, point2)| (point1, point2)), + ); let killed_rel: Relation<(T::Loan, T::Point)> = all_facts.killed.into(); // `invalidates` facts, stored ready for joins let invalidates = iteration.variable::<((T::Loan, T::Point), ())>("invalidates"); - // we need `region_live_at` in both variable and relation forms. + // we need `region_live_at` in both variable and relation forms, // (respectively, for join and antijoin). let region_live_at_rel: Relation<(T::Origin, T::Point)> = region_live_at.into(); let region_live_at_var = iteration.variable::<((T::Origin, T::Point), ())>("region_live_at"); // `borrow_region` input but organized for join - let borrow_region_rp = - iteration.variable::<((T::Origin, T::Point), T::Loan)>("borrow_region_rp"); + let borrow_region_op = + iteration.variable::<((T::Origin, T::Point), T::Loan)>("borrow_region_op"); - // .decl subset(R1, R2, P) + // .decl subset(origin1, origin2, point) // - // Indicates that `R1: R2` at the point `P`. - let subset_r1p = iteration.variable::<((T::Origin, T::Point), T::Origin)>("subset_r1p"); + // Indicates that `origin1: origin2` at `point`. + let subset_o1p = iteration.variable::<((T::Origin, T::Point), T::Origin)>("subset_o1p"); - // .decl requires(R, B, P) + // .decl requires(origin, loan, point) // - // At the point, things with origin R may depend on data from - // borrow B - let requires_rp = iteration.variable::<((T::Origin, T::Point), T::Loan)>("requires_rp"); + // At `point`, things with `origin` may depend on data from `loan`. + let requires_op = iteration.variable::<((T::Origin, T::Point), T::Loan)>("requires_op"); - // .decl borrow_live_at(B, P) -- true if the restrictions of the borrow B - // need to be enforced at the point P + // .decl borrow_live_at(loan, point) + // + // True if the restrictions of the `loan` need to be enforced at `point`. let borrow_live_at = iteration.variable::<((T::Loan, T::Point), ())>("borrow_live_at"); - // .decl live_to_dying_regions(R1, R2, P, Q) + // .decl live_to_dying_regions(origin1, origin2, point1, point2) // - // The regions `R1` and `R2` are "live to dead" - // on the edge `P -> Q` if: + // The origins `origin1` and `origin2` are "live to dead" + // on the edge `point1 -> point2` if: // - // - In P, `R1` <= `R2` - // - In Q, `R1` is live but `R2` is dead. + // - In `point1`, `origin1` <= `origin2` + // - In `point2`, `origin1` is live but `origin2` is dead. // - // In that case, `Q` would like to add all the - // live things reachable from `R2` to `R1`. + // In that case, `point2` would like to add all the + // live things reachable from `origin2` to `origin1`. // - let live_to_dying_regions_r2pq = iteration - .variable::<((T::Origin, T::Point, T::Point), T::Origin)>("live_to_dying_regions_r2pq"); + let live_to_dying_regions_o2pq = iteration + .variable::<((T::Origin, T::Point, T::Point), T::Origin)>("live_to_dying_regions_o2pq"); - // .decl dying_region_requires((R, P, Q), B) + // .decl dying_region_requires((origin, point1, point2), loan) // - // The origin `R` requires the borrow `B`, but the - // origin `R` goes dead along the edge `P -> Q` + // The `origin` requires `loan`, but the `origin` goes dead + // along the edge `point1 -> point2`. let dying_region_requires = iteration .variable::<((T::Origin, T::Point, T::Point), T::Loan)>("dying_region_requires"); - // .decl dying_can_reach_origins(R, P, Q) + // .decl dying_can_reach_origins(origin, point1, point2) // - // Contains dead regions where we are interested + // Contains dead origins where we are interested // in computing the transitive closure of things they // can reach. + // + // FIXME: this relation was named before renaming the `regions` atoms to `origins`, and + // will need to be renamed to change "_origins" to "_ascendants", "_roots", etc. let dying_can_reach_origins = iteration.variable::<((T::Origin, T::Point), T::Point)>("dying_can_reach_origins"); - // .decl dying_can_reach(R1, R2, P, Q) + // .decl dying_can_reach(origin1, origin2, point1, point2) // - // Indicates that the origin `R1`, which is dead - // in `Q`, can reach the origin `R2` in P. + // Indicates that `origin1`, which is dead + // in `point2`, can reach `origin2` in `point1`. // // This is effectively the transitive subset - // relation, but we try to limit it to regions - // that are dying on the edge P -> Q. - let dying_can_reach_r2q = + // relation, but we try to limit it to origins + // that are dying on the edge `point1 -> point2`. + let dying_can_reach_o2q = iteration.variable::<((T::Origin, T::Point), (T::Origin, T::Point))>("dying_can_reach"); let dying_can_reach_1 = iteration.variable_indistinct("dying_can_reach_1"); - // .decl dying_can_reach_live(R1, R2, P, Q) + // .decl dying_can_reach_live(origin1, origin2, point1, point2) // - // Indicates that, along the edge `P -> Q`, the dead (in Q) - // origin R1 can reach the live (in Q) origin R2 via a subset + // Indicates that, along the edge `point1 -> point2`, the dead (in `point2`) + // `origin1` can reach the live (in `point2`) `origin2` via a subset // relation. This is a subset of the full `dying_can_reach` - // relation where we filter down to those cases where R2 is - // live in Q. + // relation where we filter down to those cases where `origin2` is + // live in `point2`. let dying_can_reach_live = iteration .variable::<((T::Origin, T::Point, T::Point), T::Origin)>("dying_can_reach_live"); - // .decl dead_borrow_region_can_reach_root((R, P), B) + // .decl dead_borrow_region_can_reach_root((origin, point), loan) // - // Indicates a "borrow region" R at P which is not live on - // entry to P. + // Indicates a "borrow region" `origin` at `point` which is not live on + // entry to `point`. let dead_borrow_region_can_reach_root = iteration .variable::<((T::Origin, T::Point), T::Loan)>("dead_borrow_region_can_reach_root"); - // .decl dead_borrow_region_can_reach_dead((R2, P), B) + // .decl dead_borrow_region_can_reach_dead((origin2, point), loan) let dead_borrow_region_can_reach_dead = iteration .variable::<((T::Origin, T::Point), T::Loan)>("dead_borrow_region_can_reach_dead"); let dead_borrow_region_can_reach_dead_1 = iteration.variable_indistinct("dead_borrow_region_can_reach_dead_1"); - // .decl errors(B, P) + // .decl errors(loan, point) let errors = iteration.variable("errors"); // Make "variable" versions of the relations, needed for joins. - borrow_region_rp.extend(all_facts.borrow_region.iter().map(|&(r, b, p)| ((r, p), b))); - invalidates.extend(all_facts.invalidates.iter().map(|&(p, b)| ((b, p), ()))); - region_live_at_var.extend(region_live_at_rel.iter().map(|&(r, p)| ((r, p), ()))); + borrow_region_op.extend( + all_facts + .borrow_region + .iter() + .map(|&(origin, loan, point)| ((origin, point), loan)), + ); + invalidates.extend( + all_facts + .invalidates + .iter() + .map(|&(point, loan)| ((loan, point), ())), + ); + region_live_at_var.extend( + region_live_at_rel + .iter() + .map(|&(origin, point)| ((origin, point), ())), + ); - // subset(R1, R2, P) :- outlives(R1, R2, P). - subset_r1p.extend(all_facts.outlives.iter().map(|&(r1, r2, p)| ((r1, p), r2))); + // subset(origin1, origin2, point) :- outlives(origin1, origin2, point). + subset_o1p.extend( + all_facts + .outlives + .iter() + .map(|&(origin1, origin2, point)| ((origin1, point), origin2)), + ); - // requires(R, B, P) :- borrow_region(R, B, P). - requires_rp.extend(all_facts.borrow_region.iter().map(|&(r, b, p)| ((r, p), b))); + // requires(origin, loan, point) :- borrow_region(origin, loan, point). + requires_op.extend( + all_facts + .borrow_region + .iter() + .map(|&(origin, loan, point)| ((origin, point), loan)), + ); // .. and then start iterating rules! while iteration.changed() { // Cleanup step: remove symmetries - // - remove regions which are `subset`s of themselves + // - remove origins which are `subset`s of themselves // // FIXME: investigate whether is there a better way to do that without complicating // the rules too much, because it would also require temporary variables and // impact performance. Until then, the big reduction in tuples improves performance // a lot, even if we're potentially adding a small number of tuples // per round just to remove them in the next round. - subset_r1p + subset_o1p .recent .borrow_mut() .elements - .retain(|&((r1, _), r2)| r1 != r2); - - // live_to_dying_regions(R1, R2, P, Q) :- - // subset(R1, R2, P), - // cfg_edge(P, Q), - // region_live_at(R1, Q), - // !region_live_at(R2, Q). - live_to_dying_regions_r2pq.from_leapjoin( - &subset_r1p, + .retain(|&((origin1, _), origin2)| origin1 != origin2); + + // live_to_dying_regions(origin1, origin2, point1, point2) :- + // subset(origin1, origin2, point1), + // cfg_edge(point1, point2), + // region_live_at(origin1, point2), + // !region_live_at(origin2, point2). + live_to_dying_regions_o2pq.from_leapjoin( + &subset_o1p, ( - cfg_edge_rel.extend_with(|&((_, p), _)| p), - region_live_at_rel.extend_with(|&((r1, _), _)| r1), - region_live_at_rel.extend_anti(|&((_, _), r2)| r2), + cfg_edge_rel.extend_with(|&((_, point1), _)| point1), + region_live_at_rel.extend_with(|&((origin1, _), _)| origin1), + region_live_at_rel.extend_anti(|&((_, _), origin2)| origin2), ), - |&((r1, p), r2), &q| ((r2, p, q), r1), + |&((origin1, point1), origin2), &point2| ((origin2, point1, point2), origin1), ); - // dying_region_requires((R, P, Q), B) :- - // requires(R, B, P), - // !killed(B, P), - // cfg_edge(P, Q), - // !region_live_at(R, Q). + // dying_region_requires((origin, point1, point2), loan) :- + // requires(origin, loan, point1), + // !killed(loan, point1), + // cfg_edge(point1, point2), + // !region_live_at(origin, point2). dying_region_requires.from_leapjoin( - &requires_rp, + &requires_op, ( - killed_rel.filter_anti(|&((_, p), b)| (b, p)), - cfg_edge_rel.extend_with(|&((_, p), _)| p), - region_live_at_rel.extend_anti(|&((r, _), _)| r), + killed_rel.filter_anti(|&((_, point1), loan)| (loan, point1)), + cfg_edge_rel.extend_with(|&((_, point1), _)| point1), + region_live_at_rel.extend_anti(|&((origin, _), _)| origin), ), - |&((r, p), b), &q| ((r, p, q), b), + |&((origin, point1), loan), &point2| ((origin, point1, point2), loan), ); - // dying_can_reach_origins(R2, P, Q) :- - // live_to_dying_regions(_, R2, P, Q). - dying_can_reach_origins.from_map(&live_to_dying_regions_r2pq, |&((r2, p, q), _r1)| { - ((r2, p), q) - }); + // dying_can_reach_origins(origin2, point1, point2) :- + // live_to_dying_regions(_, origin2, point1, point2). + dying_can_reach_origins.from_map( + &live_to_dying_regions_o2pq, + |&((origin2, point1, point2), _origin1)| ((origin2, point1), point2), + ); - // dying_can_reach_origins(R, P, Q) :- - // dying_region_requires(R, P, Q, _B). - dying_can_reach_origins - .from_map(&dying_region_requires, |&((r, p, q), _b)| ((r, p), q)); + // dying_can_reach_origins(origin, point1, point2) :- + // dying_region_requires(origin, point1, point2, _loan). + dying_can_reach_origins.from_map( + &dying_region_requires, + |&((origin, point1, point2), _loan)| ((origin, point1), point2), + ); - // dying_can_reach(R1, R2, P, Q) :- - // dying_can_reach_origins(R1, P, Q), - // subset(R1, R2, P). - dying_can_reach_r2q.from_join( + // dying_can_reach(origin1, origin2, point1, point2) :- + // dying_can_reach_origins(origin1, point1, point2), + // subset(origin1, origin2, point1). + dying_can_reach_o2q.from_join( &dying_can_reach_origins, - &subset_r1p, - |&(r1, p), &q, &r2| ((r2, q), (r1, p)), + &subset_o1p, + |&(origin1, point1), &point2, &origin2| ((origin2, point2), (origin1, point1)), ); - // dying_can_reach(R1, R3, P, Q) :- - // dying_can_reach(R1, R2, P, Q), - // !region_live_at(R2, Q), - // subset(R2, R3, P). + // dying_can_reach(origin1, origin3, point1, point2) :- + // dying_can_reach(origin1, origin2, point1, point2), + // !region_live_at(origin2, point2), + // subset(origin2, origin3, point1). // // This is the "transitive closure" rule, but // note that we only apply it with the - // "intermediate" origin R2 is dead at Q. + // "intermediate" `origin2` is dead at `point2`. dying_can_reach_1.from_antijoin( - &dying_can_reach_r2q, + &dying_can_reach_o2q, ®ion_live_at_rel, - |&(r2, q), &(r1, p)| ((r2, p), (r1, q)), + |&(origin2, point2), &(origin1, point1)| ((origin2, point1), (origin1, point2)), ); - dying_can_reach_r2q.from_join( + dying_can_reach_o2q.from_join( &dying_can_reach_1, - &subset_r1p, - |&(_r2, p), &(r1, q), &r3| ((r3, q), (r1, p)), + &subset_o1p, + |&(_origin2, point1), &(origin1, point2), &origin3| { + ((origin3, point2), (origin1, point1)) + }, ); - // dying_can_reach_live(R1, R2, P, Q) :- - // dying_can_reach(R1, R2, P, Q), - // region_live_at(R2, Q). + // dying_can_reach_live(origin1, origin2, point1, point2) :- + // dying_can_reach(origin1, origin2, point1, point2), + // region_live_at(origin2, point2). dying_can_reach_live.from_join( - &dying_can_reach_r2q, + &dying_can_reach_o2q, ®ion_live_at_var, - |&(r2, q), &(r1, p), &()| ((r1, p, q), r2), + |&(origin2, point2), &(origin1, point1), _| ((origin1, point1, point2), origin2), ); - // subset(R1, R2, Q) :- - // subset(R1, R2, P), - // cfg_edge(P, Q), - // region_live_at(R1, Q), - // region_live_at(R2, Q). + // subset(origin1, origin2, point2) :- + // subset(origin1, origin2, point1), + // cfg_edge(point1, point2), + // region_live_at(origin1, point2), + // region_live_at(origin2, point2). // - // Carry `R1 <= R2` from P into Q if both `R1` and - // `R2` are live in Q. - subset_r1p.from_leapjoin( - &subset_r1p, + // Carry `origin1 <= origin2` from `point1` into `point2` if both `origin1` and + // `origin2` are live in `point2`. + subset_o1p.from_leapjoin( + &subset_o1p, ( - cfg_edge_rel.extend_with(|&((_, p), _)| p), - region_live_at_rel.extend_with(|&((r1, _), _)| r1), - region_live_at_rel.extend_with(|&((_, _), r2)| r2), + cfg_edge_rel.extend_with(|&((_, point1), _)| point1), + region_live_at_rel.extend_with(|&((origin1, _), _)| origin1), + region_live_at_rel.extend_with(|&((_, _), origin2)| origin2), ), - |&((r1, _p), r2), &q| ((r1, q), r2), + |&((origin1, _point1), origin2), &point2| ((origin1, point2), origin2), ); - // subset(R1, R3, Q) :- - // live_to_dying_regions(R1, R2, P, Q), - // dying_can_reach_live(R2, R3, P, Q). - subset_r1p.from_join( - &live_to_dying_regions_r2pq, + // subset(origin1, origin3, point2) :- + // live_to_dying_regions(origin1, origin2, point1, point2), + // dying_can_reach_live(origin2, origin3, point1, point2). + subset_o1p.from_join( + &live_to_dying_regions_o2pq, &dying_can_reach_live, - |&(_r2, _p, q), &r1, &r3| ((r1, q), r3), + |&(_origin2, _point1, point2), &origin1, &origin3| ((origin1, point2), origin3), ); - // requires(R2, B, Q) :- - // dying_region_requires(R1, B, P, Q), - // dying_can_reach_live(R1, R2, P, Q). + // requires(origin2, loan, point2) :- + // dying_region_requires(origin1, loan, point1, point2), + // dying_can_reach_live(origin1, origin2, point1, point2). // - // Communicate a `R1 requires B` relation across - // an edge `P -> Q` where `R1` is dead in Q; in - // that case, for each origin `R2` live in `Q` - // where `R1 <= R2` in P, we add `R2 requires B` - // to `Q`. - requires_rp.from_join( + // Communicate a `origin1 requires loan` relation across + // an edge `point1 -> point2` where `origin1` is dead in `point2`; in + // that case, for each origin `origin2` live in `point2` + // where `origin1 <= origin2` in `point1`, we add `origin2 requires loan` + // to `point2`. + requires_op.from_join( &dying_region_requires, &dying_can_reach_live, - |&(_r1, _p, q), &b, &r2| ((r2, q), b), + |&(_origin1, _point1, point2), &loan, &origin2| ((origin2, point2), loan), ); - // requires(R, B, Q) :- - // requires(R, B, P), - // !killed(B, P), - // cfg_edge(P, Q), - // region_live_at(R, Q). - requires_rp.from_leapjoin( - &requires_rp, + // requires(origin, loan, point2) :- + // requires(origin, loan, point1), + // !killed(loan, point1), + // cfg_edge(point1, point2), + // region_live_at(origin, point2). + requires_op.from_leapjoin( + &requires_op, ( - killed_rel.filter_anti(|&((_, p), b)| (b, p)), - cfg_edge_rel.extend_with(|&((_, p), _)| p), - region_live_at_rel.extend_with(|&((r, _), _)| r), + killed_rel.filter_anti(|&((_, point1), loan)| (loan, point1)), + cfg_edge_rel.extend_with(|&((_, point1), _)| point1), + region_live_at_rel.extend_with(|&((origin, _), _)| origin), ), - |&((r, _), b), &q| ((r, q), b), + |&((origin, _), loan), &point2| ((origin, point2), loan), ); - // dead_borrow_region_can_reach_root((R, P), B) :- - // borrow_region(R, B, P), - // !region_live_at(R, P). + // dead_borrow_region_can_reach_root((origin, point), loan) :- + // borrow_region(origin, loan, point), + // !region_live_at(origin, point). dead_borrow_region_can_reach_root.from_antijoin( - &borrow_region_rp, + &borrow_region_op, ®ion_live_at_rel, - |&(r, p), &b| ((r, p), b), + |&(origin, point), &loan| ((origin, point), loan), ); - // dead_borrow_region_can_reach_dead((R, P), B) :- - // dead_borrow_region_can_reach_root((R, P), B). + // dead_borrow_region_can_reach_dead((origin, point), loan) :- + // dead_borrow_region_can_reach_root((origin, point), loan). dead_borrow_region_can_reach_dead .from_map(&dead_borrow_region_can_reach_root, |&tuple| tuple); - // dead_borrow_region_can_reach_dead((R2, P), B) :- - // dead_borrow_region_can_reach_dead(R1, B, P), - // subset(R1, R2, P), - // !region_live_at(R2, P). + // dead_borrow_region_can_reach_dead((origin2, point), loan) :- + // dead_borrow_region_can_reach_dead(origin1, loan, point), + // subset(origin1, origin2, point), + // !region_live_at(origin2, point). dead_borrow_region_can_reach_dead_1.from_join( &dead_borrow_region_can_reach_dead, - &subset_r1p, - |&(_r1, p), &b, &r2| ((r2, p), b), + &subset_o1p, + |&(_origin1, point), &loan, &origin2| ((origin2, point), loan), ); dead_borrow_region_can_reach_dead.from_antijoin( &dead_borrow_region_can_reach_dead_1, ®ion_live_at_rel, - |&(r2, p), &b| ((r2, p), b), + |&(origin2, point), &loan| ((origin2, point), loan), ); - // borrow_live_at(B, P) :- requires(R, B, P), region_live_at(R, P) - borrow_live_at.from_join(&requires_rp, ®ion_live_at_var, |&(_r, p), &b, &()| { - ((b, p), ()) - }); + // borrow_live_at(loan, point) :- + // requires(origin, loan, point), + // region_live_at(origin, point). + borrow_live_at.from_join( + &requires_op, + ®ion_live_at_var, + |&(_origin, point), &loan, _| ((loan, point), ()), + ); - // borrow_live_at(B, P) :- - // dead_borrow_region_can_reach_dead(R1, B, P), - // subset(R1, R2, P), - // region_live_at(R2, P). + // borrow_live_at(loan, point) :- + // dead_borrow_region_can_reach_dead(origin1, loan, point), + // subset(origin1, origin2, point), + // region_live_at(origin2, point). // // NB: the datafrog code below uses // `dead_borrow_region_can_reach_dead_1`, which is equal @@ -357,55 +397,63 @@ pub(super) fn compute(dump_enabled: bool, all_facts: AllFacts) borrow_live_at.from_join( &dead_borrow_region_can_reach_dead_1, ®ion_live_at_var, - |&(_r2, p), &b, &()| ((b, p), ()), + |&(_origin2, point), &loan, _| ((loan, point), ()), ); - // errors(B, P) :- invalidates(B, P), borrow_live_at(B, P). - errors.from_join(&invalidates, &borrow_live_at, |&(b, p), &(), &()| (b, p)); + // errors(loan, point) :- + // invalidates(loan, point), + // borrow_live_at(loan, point). + errors.from_join(&invalidates, &borrow_live_at, |&(loan, point), _, _| { + (loan, point) + }); } if dump_enabled { - for (origin, location) in ®ion_live_at_rel.elements { + for &(origin, location) in region_live_at_rel.iter() { result .region_live_at - .entry(*location) - .or_insert(vec![]) - .push(*origin); + .entry(location) + .or_default() + .push(origin); } - let subset_r1p = subset_r1p.complete(); + let subset_o1p = subset_o1p.complete(); assert!( - subset_r1p.iter().filter(|&((r1, _), r2)| r1 == r2).count() == 0, + subset_o1p + .iter() + .filter(|&((origin1, _), origin2)| origin1 == origin2) + .count() + == 0, "unwanted subset symmetries" ); - for ((r1, location), r2) in &subset_r1p.elements { + for &((origin1, location), origin2) in subset_o1p.iter() { result .subset - .entry(*location) - .or_insert(BTreeMap::new()) - .entry(*r1) - .or_insert(BTreeSet::new()) - .insert(*r2); + .entry(location) + .or_default() + .entry(origin1) + .or_default() + .insert(origin2); } - let requires_rp = requires_rp.complete(); - for ((origin, location), borrow) in &requires_rp.elements { + let requires_op = requires_op.complete(); + for &((origin, location), loan) in requires_op.iter() { result .restricts - .entry(*location) - .or_insert(BTreeMap::new()) - .entry(*origin) - .or_insert(BTreeSet::new()) - .insert(*borrow); + .entry(location) + .or_default() + .entry(origin) + .or_default() + .insert(loan); } let borrow_live_at = borrow_live_at.complete(); - for ((borrow, location), ()) in &borrow_live_at.elements { + for &((loan, location), _) in borrow_live_at.iter() { result .borrow_live_at - .entry(*location) - .or_insert(Vec::new()) - .push(*borrow); + .entry(location) + .or_default() + .push(loan); } } @@ -420,12 +468,8 @@ pub(super) fn compute(dump_enabled: bool, all_facts: AllFacts) ); } - for (borrow, location) in &errors.elements { - result - .errors - .entry(*location) - .or_insert(Vec::new()) - .push(*borrow); + for &(loan, location) in errors.iter() { + result.errors.entry(location).or_default().push(loan); } result diff --git a/polonius-engine/src/output/initialization.rs b/polonius-engine/src/output/initialization.rs index 3f12f5765cf..ca711ee516e 100644 --- a/polonius-engine/src/output/initialization.rs +++ b/polonius-engine/src/output/initialization.rs @@ -6,133 +6,131 @@ use facts::FactTypes; use datafrog::{Iteration, Relation, RelationLeaper}; pub(super) fn init_var_maybe_initialized_on_exit( - child: Vec<(T::MovePath, T::MovePath)>, - path_belongs_to_var: Vec<(T::MovePath, T::Variable)>, - initialized_at: Vec<(T::MovePath, T::Point)>, - moved_out_at: Vec<(T::MovePath, T::Point)>, - path_accessed_at: Vec<(T::MovePath, T::Point)>, + child: Vec<(T::Path, T::Path)>, + path_belongs_to_var: Vec<(T::Path, T::Variable)>, + initialized_at: Vec<(T::Path, T::Point)>, + moved_out_at: Vec<(T::Path, T::Point)>, + path_accessed_at: Vec<(T::Path, T::Point)>, cfg_edge: &[(T::Point, T::Point)], output: &mut Output, ) -> Vec<(T::Variable, T::Point)> { - debug!("compute_initialization()"); let computation_start = Instant::now(); let mut iteration = Iteration::new(); // Relations - //let parent: Relation<(T::MovePath, T::MovePath)> = child.iter().map(|&(c, p)| (p, c)).collect(); - let child: Relation<(T::MovePath, T::MovePath)> = child.into(); - let path_belongs_to_var: Relation<(T::MovePath, T::Variable)> = path_belongs_to_var.into(); - let initialized_at: Relation<(T::MovePath, T::Point)> = initialized_at.into(); - let moved_out_at: Relation<(T::MovePath, T::Point)> = moved_out_at.into(); + //let parent: Relation<(Path, Path)> = child.iter().map(|&(child_path, parent_path)| (parent_path, child_path)).collect(); + let child: Relation<(T::Path, T::Path)> = child.into(); + let path_belongs_to_var: Relation<(T::Path, T::Variable)> = path_belongs_to_var.into(); + let initialized_at: Relation<(T::Path, T::Point)> = initialized_at.into(); + let moved_out_at: Relation<(T::Path, T::Point)> = moved_out_at.into(); let cfg_edge: Relation<(T::Point, T::Point)> = cfg_edge.iter().cloned().collect(); - let _path_accessed_at: Relation<(T::MovePath, T::Point)> = path_accessed_at.into(); + let _path_accessed_at: Relation<(T::Path, T::Point)> = path_accessed_at.into(); // Variables - // var_maybe_initialized_on_exit(V, P): Upon leaving `P`, at least one part of the - // variable `V` might be initialized for some path through the CFG. + // var_maybe_initialized_on_exit(var, point): Upon leaving `point`, at least one part of the + // variable `var` might be initialized for some path through the CFG. let var_maybe_initialized_on_exit = iteration.variable::<(T::Variable, T::Point)>("var_maybe_initialized_on_exit"); - // path_maybe_initialized_on_exit(M, P): Upon leaving `P`, the move path `M` + // path_maybe_initialized_on_exit(path, point): Upon leaving `point`, the move path `path` // might be *partially* initialized for some path through the CFG. let path_maybe_initialized_on_exit = - iteration.variable::<(T::MovePath, T::Point)>("path_maybe_initialized_on_exit"); + iteration.variable::<(T::Path, T::Point)>("path_maybe_initialized_on_exit"); // Initial propagation of static relations - // path_maybe_initialized_on_exit(Path, Point) :- initialized_at(Path, - // Point). + // path_maybe_initialized_on_exit(path, point) :- initialized_at(path, point). path_maybe_initialized_on_exit.insert(initialized_at); while iteration.changed() { - // path_maybe_initialized_on_exit(M, Q) :- - // path_maybe_initialized_on_exit(M, P), - // cfg_edge(P, Q), - // !moved_out_at(M, Q). + // path_maybe_initialized_on_exit(path, point2) :- + // path_maybe_initialized_on_exit(path, point1), + // cfg_edge(point1, point2), + // !moved_out_at(path, point2). path_maybe_initialized_on_exit.from_leapjoin( &path_maybe_initialized_on_exit, ( - cfg_edge.extend_with(|&(_m, p)| p), - moved_out_at.extend_anti(|&(m, _p)| m), + cfg_edge.extend_with(|&(_path, point1)| point1), + moved_out_at.extend_anti(|&(path, _point1)| path), ), - |&(m, _p), &q| (m, q), + |&(path, _point1), &point2| (path, point2), ); - // path_maybe_initialized_on_exit(Mother, P) :- - // path_maybe_initialized_on_exit(Daughter, P), + // path_maybe_initialized_on_exit(Mother, point) :- + // path_maybe_initialized_on_exit(Daughter, point), // child(Daughter, Mother). path_maybe_initialized_on_exit.from_leapjoin( &path_maybe_initialized_on_exit, - child.extend_with(|&(daughter, _p)| daughter), - |&(_daughter, p), &mother| (mother, p), + child.extend_with(|&(daughter, _point)| daughter), + |&(_daughter, point), &mother| (mother, point), ); // TODO: the following lines contain things left to implement for move // tracking: - // path_accessed :- path_accessed(M, P). + // path_accessed :- path_accessed(path, point). // // -- transitive access of all children - // path_accessed(Child, P) :- - // path_accessed(Mother, P), + // path_accessed(Child, point) :- + // path_accessed(Mother, point), // parent(Mother, Child). // Propagate across CFG edges: - // path_maybe_uninit(M, Q) :- - // path_maybe_uninit(M, P), - // cfg_edge_(P, Q) - // !initialized_at(P, Q). + // path_maybe_uninit(path, point2) :- + // path_maybe_uninit(path, point1), + // cfg_edge_(point1, point2) + // !initialized_at(point1, point2). // Initial value (static). - // path_maybe_uninit(M, P) :- moved_out_at(M, P). + // path_maybe_uninit(path, point) :- moved_out_at(path, point). // NOTE: Double join! - // errors(M, P) :- - // path_maybe_uninit(M, P), - // path_accessed(M, P). + // errors(path, point) :- + // path_maybe_uninit(path, point), + // path_accessed(path, point). // END TODO - // var_maybe_initialized_on_exit(V, P) :- - // path_belongs_to_var(M, V), - // path_maybe_initialized_at(M, P). + // var_maybe_initialized_on_exit(var, point) :- + // path_belongs_to_var(path, var), + // path_maybe_initialized_at(path, point). var_maybe_initialized_on_exit.from_leapjoin( &path_maybe_initialized_on_exit, - path_belongs_to_var.extend_with(|&(m, _p)| m), - |&(_m, p), &v| (v, p), + path_belongs_to_var.extend_with(|&(path, _point)| path), + |&(_path, point), &var| (var, point), ); } let var_maybe_initialized_on_exit = var_maybe_initialized_on_exit.complete(); info!( - "compute_initialization() completed: {} tuples, {:?}", + "init_var_maybe_initialized_on_exit() completed: {} tuples, {:?}", var_maybe_initialized_on_exit.len(), computation_start.elapsed() ); if output.dump_enabled { let path_maybe_initialized_on_exit = path_maybe_initialized_on_exit.complete(); - for &(path, location) in &path_maybe_initialized_on_exit.elements { + for &(path, location) in path_maybe_initialized_on_exit.iter() { output .path_maybe_initialized_at .entry(location) - .or_insert_with(Vec::new) + .or_default() .push(path); } - for &(var, location) in &var_maybe_initialized_on_exit.elements { + for &(var, location) in var_maybe_initialized_on_exit.iter() { output .var_maybe_initialized_on_exit .entry(location) - .or_insert_with(Vec::new) + .or_default() .push(var); } } var_maybe_initialized_on_exit .iter() - .map(|&(v, p)| (v, p)) + .map(|&(var, point)| (var, point)) .collect() } diff --git a/polonius-engine/src/output/liveness.rs b/polonius-engine/src/output/liveness.rs index 3a3ba8b0c35..c28a8a65c1a 100644 --- a/polonius-engine/src/output/liveness.rs +++ b/polonius-engine/src/output/liveness.rs @@ -28,132 +28,137 @@ pub(super) fn compute_live_regions( var_maybe_initialized_on_exit: Vec<(T::Variable, T::Point)>, output: &mut Output, ) -> Vec<(T::Origin, T::Point)> { - debug!("compute_liveness()"); let computation_start = Instant::now(); let mut iteration = Iteration::new(); // Relations let var_defined_rel: Relation<(T::Variable, T::Point)> = var_defined.into(); - let cfg_edge_rel: Relation<(T::Point, T::Point)> = - cfg_edge.iter().map(|(p, q)| (*p, *q)).collect(); - let cfg_edge_reverse_rel: Relation<(T::Point, T::Point)> = - cfg_edge.iter().map(|(p, q)| (*q, *p)).collect(); + let cfg_edge_rel: Relation<(T::Point, T::Point)> = cfg_edge + .iter() + .map(|&(point1, point2)| (point1, point2)) + .collect(); + let cfg_edge_reverse_rel: Relation<(T::Point, T::Point)> = cfg_edge + .iter() + .map(|&(point1, point2)| (point2, point1)) + .collect(); let var_uses_region_rel: Relation<(T::Variable, T::Origin)> = var_uses_region.into(); let var_drops_region_rel: Relation<(T::Variable, T::Origin)> = var_drops_region.into(); let var_maybe_initialized_on_exit_rel: Relation<(T::Variable, T::Point)> = var_maybe_initialized_on_exit.into(); let var_drop_used_rel: Relation<((T::Variable, T::Point), ())> = var_drop_used .into_iter() - .map(|(v, p)| ((v, p), ())) + .map(|(var, point)| ((var, point), ())) .collect(); - // T::Variables + // Variables - // `var_live`: variable V is live upon entry in point P + // `var_live`: variable `var` is live upon entry at `point` let var_live_var = iteration.variable::<(T::Variable, T::Point)>("var_live_at"); - // `var_drop_live`: variable V is drop-live (will be used for a drop) upon entry in point P + // `var_drop_live`: variable `var` is drop-live (will be used for a drop) upon entry in `point` let var_drop_live_var = iteration.variable::<(T::Variable, T::Point)>("var_drop_live_at"); // This is what we are actually calculating: let region_live_at_var = iteration.variable::<((T::Origin, T::Point), ())>("region_live_at"); - // This propagates the relation `var_live(V, P) :- var_used(V, P)`: + // This propagates the relation `var_live(var, point) :- var_used(var, point)`: var_live_var.insert(var_used.into()); - // var_maybe_initialized_on_entry(V, Q) :- - // var_maybe_initialized_on_exit(V, P), - // cfg_edge(P, Q). + // var_maybe_initialized_on_entry(var, point2) :- + // var_maybe_initialized_on_exit(var, point1), + // cfg_edge(point1, point2). let var_maybe_initialized_on_entry = Relation::from_leapjoin( &var_maybe_initialized_on_exit_rel, - cfg_edge_rel.extend_with(|&(_v, p)| p), - |&(v, _p), &q| ((v, q), ()), + cfg_edge_rel.extend_with(|&(_var, point1)| point1), + |&(var, _point1), &point2| ((var, point2), ()), ); - // var_drop_live(V, P) :- - // var_drop_used(V, P), - // var_maybe_initialzed_on_entry(V, P). + // var_drop_live(var, point) :- + // var_drop_used(var, point), + // var_maybe_initialzed_on_entry(var, point). var_drop_live_var.insert(Relation::from_join( &var_drop_used_rel, &var_maybe_initialized_on_entry, - |&(v, p), &(), &()| (v, p), + |&(var, point), _, _| (var, point), )); while iteration.changed() { - // region_live_at(R, P) :- - // var_drop_live(V, P), - // var_drops_region(V, R). - region_live_at_var.from_join(&var_drop_live_var, &var_drops_region_rel, |_v, &p, &r| { - ((r, p), ()) - }); - - // region_live_at(R, P) :- - // var_live(V, P), - // var_uses_region(V, R). - region_live_at_var.from_join(&var_live_var, &var_uses_region_rel, |_v, &p, &r| { - ((r, p), ()) - }); - - // var_live(V, P) :- - // var_live(V, Q), - // cfg_edge(P, Q), - // !var_defined(V, P). + // region_live_at(origin, point) :- + // var_drop_live(var, point), + // var_drops_region(var, origin). + region_live_at_var.from_join( + &var_drop_live_var, + &var_drops_region_rel, + |_var, &point, &origin| ((origin, point), ()), + ); + + // region_live_at(origin, point) :- + // var_live(var, point), + // var_uses_region(var, origin). + region_live_at_var.from_join( + &var_live_var, + &var_uses_region_rel, + |_var, &point, &origin| ((origin, point), ()), + ); + + // var_live(var, point1) :- + // var_live(var, point2), + // cfg_edge(point1, point2), + // !var_defined(var, point1). var_live_var.from_leapjoin( &var_live_var, ( - var_defined_rel.extend_anti(|&(v, _q)| v), - cfg_edge_reverse_rel.extend_with(|&(_v, q)| q), + var_defined_rel.extend_anti(|&(var, _point2)| var), + cfg_edge_reverse_rel.extend_with(|&(_var, point2)| point2), ), - |&(v, _q), &p| (v, p), + |&(var, _point2), &point1| (var, point1), ); - // var_drop_live(V, P) :- - // var_drop_live(V, Q), - // cfg_edge(P, Q), - // !var_defined(V, P) - // var_maybe_initialized_on_exit(V, P). - // extend p with v:s from q such that v is not in q, there is an edge from p to q + // var_drop_live(var, point1) :- + // var_drop_live(var, point2), + // cfg_edge(point1, point2), + // !var_defined(var, point1) + // var_maybe_initialized_on_exit(var, point1). + // + // Extend `point1` with `var:s` from `point2` such that `var` is not in `point2`, + // there is an edge from `point1` to `point2` var_drop_live_var.from_leapjoin( &var_drop_live_var, ( - var_defined_rel.extend_anti(|&(v, _q)| v), - cfg_edge_reverse_rel.extend_with(|&(_v, q)| q), - var_maybe_initialized_on_exit_rel.extend_with(|&(v, _q)| v), + var_defined_rel.extend_anti(|&(var, _point2)| var), + cfg_edge_reverse_rel.extend_with(|&(_var, point2)| point2), + var_maybe_initialized_on_exit_rel.extend_with(|&(var, _point2)| var), ), - |&(v, _q), &p| (v, p), + |&(var, _point2), &point1| (var, point1), ); } let region_live_at_rel = region_live_at_var.complete(); info!( - "compute_liveness() completed: {} tuples, {:?}", + "compute_live_regions() completed: {} tuples, {:?}", region_live_at_rel.len(), computation_start.elapsed() ); if output.dump_enabled { let var_drop_live_at = var_drop_live_var.complete(); - for &(var, location) in &var_drop_live_at.elements { + for &(var, location) in var_drop_live_at.iter() { output .var_drop_live_at .entry(location) - .or_insert_with(Vec::new) + .or_default() .push(var); } let var_live_at = var_live_var.complete(); - for &(var, location) in &var_live_at.elements { - output - .var_live_at - .entry(location) - .or_insert_with(Vec::new) - .push(var); + for &(var, location) in var_live_at.iter() { + output.var_live_at.entry(location).or_default().push(var); } } region_live_at_rel .iter() - .map(|&((r, p), _)| (r, p)) + .map(|&((origin, point), _)| (origin, point)) .collect() } @@ -166,14 +171,14 @@ pub(super) fn make_universal_region_live( let all_points: BTreeSet = cfg_edge .iter() - .map(|&(p, _)| p) - .chain(cfg_edge.iter().map(|&(_, q)| q)) + .map(|&(point1, _)| point1) + .chain(cfg_edge.iter().map(|&(_, point2)| point2)) .collect(); region_live_at.reserve(universal_region.len() * all_points.len()); - for &r in &universal_region { - for &p in &all_points { - region_live_at.push((r, p)); + for &origin in &universal_region { + for &point in &all_points { + region_live_at.push((origin, point)); } } } diff --git a/polonius-engine/src/output/location_insensitive.rs b/polonius-engine/src/output/location_insensitive.rs index de55ec5c321..80cc5b482dd 100644 --- a/polonius-engine/src/output/location_insensitive.rs +++ b/polonius-engine/src/output/location_insensitive.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::collections::BTreeSet; use std::time::Instant; use crate::output::initialization; @@ -49,7 +48,12 @@ pub(super) fn compute(dump_enabled: bool, all_facts: &AllFacts) // static inputs let region_live_at: Relation<(T::Origin, T::Point)> = region_live_at.into(); - let invalidates = Relation::from_iter(all_facts.invalidates.iter().map(|&(b, p)| (p, b))); + let invalidates = Relation::from_iter( + all_facts + .invalidates + .iter() + .map(|&(loan, point)| (point, loan)), + ); // .. some variables, .. let subset = iteration.variable::<(T::Origin, T::Origin)>("subset"); @@ -59,22 +63,41 @@ pub(super) fn compute(dump_enabled: bool, all_facts: &AllFacts) // load initial facts. - // subset(R1, R2) :- outlives(R1, R2, _P) - subset.extend(all_facts.outlives.iter().map(|&(r1, r2, _p)| (r1, r2))); + // subset(origin1, origin2) :- outlives(origin1, origin2, _point) + subset.extend( + all_facts + .outlives + .iter() + .map(|&(origin1, origin2, _point)| (origin1, origin2)), + ); - // requires(R, B) :- borrow_region(R, B, _P). - requires.extend(all_facts.borrow_region.iter().map(|&(r, b, _p)| (r, b))); + // requires(origin, loan) :- borrow_region(origin, loan, _point). + requires.extend( + all_facts + .borrow_region + .iter() + .map(|&(origin, loan, _point)| (origin, loan)), + ); // .. and then start iterating rules! while iteration.changed() { - // requires(R2, B) :- requires(R1, B), subset(R1, R2). + // requires(origin2, loan) :- + // requires(origin1, loan), + // subset(origin1, origin2). // // Note: Since `subset` is effectively a static input, this join can be ported to // a leapjoin. Doing so, however, was 7% slower on `clap`. - requires.from_join(&requires, &subset, |&_r1, &b, &r2| (r2, b)); + requires.from_join(&requires, &subset, |&_origin1, &loan, &origin2| { + (origin2, loan) + }); - // borrow_live_at(B, P) :- requires(R, B), region_live_at(R, P) - // potential_errors(B, P) :- invalidates(B, P), borrow_live_at(B, P). + // borrow_live_at(loan, point) :- + // requires(origin, loan), + // region_live_at(origin, point) + // + // potential_errors(loan, point) :- + // invalidates(loan, point), + // borrow_live_at(loan, point). // // Note: we don't need to materialize `borrow_live_at` here // so we can inline it in the `potential_errors` relation. @@ -82,38 +105,38 @@ pub(super) fn compute(dump_enabled: bool, all_facts: &AllFacts) potential_errors.from_leapjoin( &requires, ( - region_live_at.extend_with(|&(r, _b)| r), - invalidates.extend_with(|&(_r, b)| b), + region_live_at.extend_with(|&(origin, _loan)| origin), + invalidates.extend_with(|&(_origin, loan)| loan), ), - |&(_r, b), &p| (b, p), + |&(_origin, loan), &point| (loan, point), ); } if dump_enabled { let subset = subset.complete(); - for (r1, r2) in &subset.elements { + for &(origin1, origin2) in subset.iter() { result .subset_anywhere - .entry(*r1) - .or_insert(BTreeSet::new()) - .insert(*r2); + .entry(origin1) + .or_default() + .insert(origin2); } let requires = requires.complete(); - for (origin, borrow) in &requires.elements { + for &(origin, loan) in requires.iter() { result .restricts_anywhere - .entry(*origin) - .or_insert(BTreeSet::new()) - .insert(*borrow); + .entry(origin) + .or_default() + .insert(loan); } - for (origin, location) in ®ion_live_at.elements { + for &(origin, location) in region_live_at.iter() { result .region_live_at - .entry(*location) - .or_insert(vec![]) - .push(*origin); + .entry(location) + .or_default() + .push(origin); } } @@ -128,12 +151,8 @@ pub(super) fn compute(dump_enabled: bool, all_facts: &AllFacts) ); } - for (borrow, location) in &potential_errors.elements { - result - .errors - .entry(*location) - .or_insert(Vec::new()) - .push(*borrow); + for &(loan, location) in potential_errors.iter() { + result.errors.entry(location).or_default().push(loan); } result diff --git a/polonius-engine/src/output/mod.rs b/polonius-engine/src/output/mod.rs index 88e8955eab7..8351512fde0 100644 --- a/polonius-engine/src/output/mod.rs +++ b/polonius-engine/src/output/mod.rs @@ -77,7 +77,7 @@ pub struct Output { pub subset_anywhere: FxHashMap>, pub var_live_at: FxHashMap>, pub var_drop_live_at: FxHashMap>, - pub path_maybe_initialized_at: FxHashMap>, + pub path_maybe_initialized_at: FxHashMap>, pub var_maybe_initialized_on_exit: FxHashMap>, } diff --git a/polonius-engine/src/output/naive.rs b/polonius-engine/src/output/naive.rs index 4da6047ab30..73922109625 100644 --- a/polonius-engine/src/output/naive.rs +++ b/polonius-engine/src/output/naive.rs @@ -10,7 +10,6 @@ //! A version of the Naive datalog analysis using Datafrog. -use std::collections::{BTreeMap, BTreeSet}; use std::time::Instant; use crate::output::initialization; @@ -65,11 +64,11 @@ pub(super) fn compute(dump_enabled: bool, all_facts: AllFacts) let invalidates = iteration.variable::<((T::Loan, T::Point), ())>("invalidates"); // different indices for `subset`. - let subset_r1p = iteration.variable_indistinct("subset_r1p"); - let subset_r2p = iteration.variable_indistinct("subset_r2p"); + let subset_o1p = iteration.variable_indistinct("subset_o1p"); + let subset_o2p = iteration.variable_indistinct("subset_o2p"); // different index for `requires`. - let requires_rp = iteration.variable_indistinct("requires_rp"); + let requires_op = iteration.variable_indistinct("requires_op"); // we need `region_live_at` in both variable and relation forms. // (respectively, for the regular join and the leapjoin). @@ -82,8 +81,17 @@ pub(super) fn compute(dump_enabled: bool, all_facts: AllFacts) // load initial facts. subset.insert(all_facts.outlives.into()); requires.insert(all_facts.borrow_region.into()); - invalidates.extend(all_facts.invalidates.iter().map(|&(p, b)| ((b, p), ()))); - region_live_at_var.extend(region_live_at_rel.iter().map(|&(r, p)| ((r, p), ()))); + invalidates.extend( + all_facts + .invalidates + .iter() + .map(|&(point, loan)| ((loan, point), ())), + ); + region_live_at_var.extend( + region_live_at_rel + .iter() + .map(|&(origin, point)| ((origin, point), ())), + ); // .. and then start iterating rules! while iteration.changed() { @@ -99,112 +107,134 @@ pub(super) fn compute(dump_enabled: bool, all_facts: AllFacts) .recent .borrow_mut() .elements - .retain(|&(r1, r2, _)| r1 != r2); + .retain(|&(origin1, origin2, _)| origin1 != origin2); // remap fields to re-index by keys. - subset_r1p.from_map(&subset, |&(r1, r2, p)| ((r1, p), r2)); - subset_r2p.from_map(&subset, |&(r1, r2, p)| ((r2, p), r1)); + subset_o1p.from_map(&subset, |&(origin1, origin2, point)| { + ((origin1, point), origin2) + }); + subset_o2p.from_map(&subset, |&(origin1, origin2, point)| { + ((origin2, point), origin1) + }); - requires_rp.from_map(&requires, |&(r, b, p)| ((r, p), b)); + requires_op.from_map(&requires, |&(origin, loan, point)| ((origin, point), loan)); - // subset(R1, R2, P) :- outlives(R1, R2, P). + // subset(origin1, origin2, point) :- outlives(origin1, origin2, point). // Already loaded; outlives is static. - // subset(R1, R3, P) :- - // subset(R1, R2, P), - // subset(R2, R3, P). - subset.from_join(&subset_r2p, &subset_r1p, |&(_r2, p), &r1, &r3| (r1, r3, p)); + // subset(origin1, origin3, point) :- + // subset(origin1, origin2, point), + // subset(origin2, origin3, point). + subset.from_join( + &subset_o2p, + &subset_o1p, + |&(_origin2, point), &origin1, &origin3| (origin1, origin3, point), + ); - // subset(R1, R2, Q) :- - // subset(R1, R2, P), - // cfg_edge(P, Q), - // region_live_at(R1, Q), - // region_live_at(R2, Q). + // subset(origin1, origin2, point2) :- + // subset(origin1, origin2, point1), + // cfg_edge(point1, point2), + // region_live_at(origin1, point2), + // region_live_at(origin2, point2). subset.from_leapjoin( &subset, ( - cfg_edge_rel.extend_with(|&(_r1, _r2, p)| p), - region_live_at_rel.extend_with(|&(r1, _r2, _p)| r1), - region_live_at_rel.extend_with(|&(_r1, r2, _p)| r2), + cfg_edge_rel.extend_with(|&(_origin1, _origin2, point1)| point1), + region_live_at_rel.extend_with(|&(origin1, _origin2, _point1)| origin1), + region_live_at_rel.extend_with(|&(_origin1, origin2, _point1)| origin2), ), - |&(r1, r2, _p), &q| (r1, r2, q), + |&(origin1, origin2, _point1), &point2| (origin1, origin2, point2), ); - // requires(R, B, P) :- borrow_region(R, B, P). + // requires(origin, loan, point) :- borrow_region(origin, loan, point). // Already loaded; borrow_region is static. - // requires(R2, B, P) :- - // requires(R1, B, P), - // subset(R1, R2, P). - requires.from_join(&requires_rp, &subset_r1p, |&(_r1, p), &b, &r2| (r2, b, p)); + // requires(origin2, loan, point) :- + // requires(origin1, loan, point), + // subset(origin1, origin2, point). + requires.from_join( + &requires_op, + &subset_o1p, + |&(_origin1, point), &loan, &origin2| (origin2, loan, point), + ); - // requires(R, B, Q) :- - // requires(R, B, P), - // !killed(B, P), - // cfg_edge(P, Q), - // region_live_at(R, Q). + // requires(origin, loan, point2) :- + // requires(origin, loan, point1), + // !killed(loan, point1), + // cfg_edge(point1, point2), + // region_live_at(origin, point2). requires.from_leapjoin( &requires, ( - killed_rel.filter_anti(|&(_r, b, p)| (b, p)), - cfg_edge_rel.extend_with(|&(_r, _b, p)| p), - region_live_at_rel.extend_with(|&(r, _b, _p)| r), + killed_rel.filter_anti(|&(_origin, loan, point1)| (loan, point1)), + cfg_edge_rel.extend_with(|&(_origin, _loan, point1)| point1), + region_live_at_rel.extend_with(|&(origin, _loan, _point1)| origin), ), - |&(r, b, _p), &q| (r, b, q), + |&(origin, loan, _point1), &point2| (origin, loan, point2), ); - // borrow_live_at(B, P) :- - // requires(R, B, P), - // region_live_at(R, P). - borrow_live_at.from_join(&requires_rp, ®ion_live_at_var, |&(_r, p), &b, &()| { - ((b, p), ()) - }); + // borrow_live_at(loan, point) :- + // requires(origin, loan, point), + // region_live_at(origin, point). + borrow_live_at.from_join( + &requires_op, + ®ion_live_at_var, + |&(_origin, point), &loan, _| ((loan, point), ()), + ); - // .decl errors(B, P) :- invalidates(B, P), borrow_live_at(B, P). - errors.from_join(&invalidates, &borrow_live_at, |&(b, p), &(), &()| (b, p)); + // errors(loan, point) :- + // invalidates(loan, point), + // borrow_live_at(loan, point). + errors.from_join(&invalidates, &borrow_live_at, |&(loan, point), _, _| { + (loan, point) + }); } if dump_enabled { let subset = subset.complete(); assert!( - subset.iter().filter(|&(r1, r2, _)| r1 == r2).count() == 0, + subset + .iter() + .filter(|&(origin1, origin2, _)| origin1 == origin2) + .count() + == 0, "unwanted subset symmetries" ); - for (r1, r2, location) in &subset.elements { + for &(origin1, origin2, location) in subset.iter() { result .subset - .entry(*location) - .or_insert_with(BTreeMap::new) - .entry(*r1) - .or_insert_with(BTreeSet::new) - .insert(*r2); + .entry(location) + .or_default() + .entry(origin1) + .or_default() + .insert(origin2); } let requires = requires.complete(); - for (origin, borrow, location) in &requires.elements { + for &(origin, loan, location) in requires.iter() { result .restricts - .entry(*location) - .or_insert_with(BTreeMap::new) - .entry(*origin) - .or_insert_with(BTreeSet::new) - .insert(*borrow); + .entry(location) + .or_default() + .entry(origin) + .or_default() + .insert(loan); } - for (origin, location) in ®ion_live_at_rel.elements { + for &(origin, location) in region_live_at_rel.iter() { result .region_live_at - .entry(*location) - .or_insert_with(Vec::new) - .push(*origin); + .entry(location) + .or_default() + .push(origin); } let borrow_live_at = borrow_live_at.complete(); - for &((loan, location), ()) in &borrow_live_at.elements { + for &((loan, location), _) in borrow_live_at.iter() { result .borrow_live_at .entry(location) - .or_insert_with(Vec::new) + .or_default() .push(loan); } } @@ -220,12 +250,8 @@ pub(super) fn compute(dump_enabled: bool, all_facts: AllFacts) ); } - for (borrow, location) in &errors.elements { - result - .errors - .entry(*location) - .or_insert_with(Vec::new) - .push(*borrow); + for &(loan, location) in errors.iter() { + result.errors.entry(location).or_default().push(loan); } result diff --git a/src/dump.rs b/src/dump.rs index d6b14fa73d0..214ed6bad73 100644 --- a/src/dump.rs +++ b/src/dump.rs @@ -311,9 +311,9 @@ impl Atom for Variable { } } -impl Atom for MovePath { +impl Atom for Path { fn table(intern: &InternerTables) -> &Interner { - &intern.move_paths + &intern.paths } } @@ -326,12 +326,12 @@ fn facts_by_point( ) -> HashMap { let mut by_point: HashMap> = HashMap::new(); for f in facts { - let (p, o) = point(f); - by_point.entry(p).or_insert_with(Vec::new).push(o); + let (point, o) = point(f); + by_point.entry(point).or_insert_with(Vec::new).push(o); } by_point .into_iter() - .map(|(p, o)| { + .map(|(point, o)| { let mut rows: Vec> = Vec::new(); OutputDump::push_all(&o, intern, &mut vec![], &mut rows); let s = rows @@ -354,7 +354,7 @@ fn facts_by_point( .join("\\l") + "\\l"; // in graphviz, \l is a \n that left-aligns - (p, s) + (point, s) }) .collect() } @@ -366,70 +366,70 @@ fn build_inputs_by_point_for_visualization( vec![ facts_by_point( all_facts.borrow_region.iter().cloned(), - |(a, b, p)| (p, (a, b)), + |(origin, loan, point)| (point, (origin, loan)), "borrow_region".to_string(), 2, intern, ), facts_by_point( all_facts.killed.iter().cloned(), - |(l, p)| (p, (l,)), + |(loan, point)| (point, (loan,)), "killed".to_string(), 1, intern, ), facts_by_point( all_facts.outlives.iter().cloned(), - |(r1, r2, p)| (p, (r1, r2)), + |(origin1, origin2, point)| (point, (origin1, origin2)), "outlives".to_string(), 2, intern, ), facts_by_point( all_facts.invalidates.iter().cloned(), - |(p, l)| (p, (l,)), + |(point, loan)| (point, (loan,)), "invalidates".to_string(), 0, intern, ), facts_by_point( all_facts.var_used.iter().cloned(), - |(v, p)| (p, (v,)), + |(var, point)| (point, (var,)), "var_used".to_string(), 1, intern, ), facts_by_point( all_facts.var_defined.iter().cloned(), - |(v, p)| (p, (v,)), + |(var, point)| (point, (var,)), "var_defined".to_string(), 1, intern, ), facts_by_point( all_facts.var_drop_used.iter().cloned(), - |(v, p)| (p, (v,)), + |(var, point)| (point, (var,)), "var_drop_used".to_string(), 1, intern, ), facts_by_point( all_facts.initialized_at.iter().cloned(), - |(v, p)| (p, (v,)), + |(var, point)| (point, (var,)), "initialized_at".to_string(), 1, intern, ), facts_by_point( all_facts.moved_out_at.iter().cloned(), - |(v, p)| (p, (v,)), + |(var, point)| (point, (var,)), "moved_out_at".to_string(), 1, intern, ), facts_by_point( all_facts.path_accessed_at.iter().cloned(), - |(v, p)| (p, (v,)), + |(var, point)| (point, (var,)), "path_accessed_at".to_string(), 1, intern, @@ -444,56 +444,56 @@ fn build_outputs_by_point_for_visualization( vec![ facts_by_point( output.borrow_live_at.iter(), - |(pt, loans)| (*pt, loans.clone()), + |(point, loans)| (*point, loans.clone()), "borrow_live_at".to_string(), 0, intern, ), facts_by_point( output.restricts.iter(), - |(pt, region_to_loans)| (*pt, region_to_loans.clone()), + |(point, origin_to_loans)| (*point, origin_to_loans.clone()), "restricts".to_string(), 0, intern, ), facts_by_point( output.invalidates.iter(), - |(pt, loans)| (*pt, loans.clone()), + |(point, loans)| (*point, loans.clone()), "invalidates".to_string(), 0, intern, ), facts_by_point( output.subset.iter(), - |(pt, region_to_regions)| (*pt, region_to_regions.clone()), + |(point, origin_to_origins)| (*point, origin_to_origins.clone()), "subset".to_string(), 0, intern, ), facts_by_point( output.var_live_at.iter(), - |(p, v)| (*p, v.clone()), + |(point, var)| (*point, var.clone()), "var_live_at".to_string(), 1, intern, ), facts_by_point( output.var_drop_live_at.iter(), - |(p, v)| (*p, v.clone()), + |(point, var)| (*point, var.clone()), "var_drop_live_at".to_string(), 1, intern, ), facts_by_point( output.region_live_at.iter(), - |(pt, origin)| (*pt, origin.clone()), + |(point, origin)| (*point, origin.clone()), "region_live_at".to_string(), 1, intern, ), facts_by_point( output.var_maybe_initialized_on_exit.iter(), - |(p, v)| (*p, v.clone()), + |(point, var)| (*point, var.clone()), "var_maybe_initialized_on_exit".to_string(), 1, intern, @@ -522,10 +522,10 @@ pub(crate) fn graphviz( let outputs_by_point = build_outputs_by_point_for_visualization(output, intern); output_fragments.push("digraph g {\n graph [\n rankdir = \"TD\"\n];\n".to_string()); - for (idx, &(p1, p2)) in all_facts.cfg_edge.iter().enumerate() { + for (idx, &(point1, point2)) in all_facts.cfg_edge.iter().enumerate() { let graphviz_code = graphviz_for_edge( - p1, - p2, + point1, + point2, idx, &mut seen_nodes, &inputs_by_point, @@ -542,8 +542,8 @@ pub(crate) fn graphviz( } fn graphviz_for_edge( - p1: Point, - p2: Point, + point1: Point, + point2: Point, edge_index: usize, seen_points: &mut BTreeSet, inputs_by_point: &[HashMap], @@ -552,7 +552,7 @@ fn graphviz_for_edge( ) -> Vec { let mut ret = Vec::new(); maybe_render_point( - p1, + point1, seen_points, inputs_by_point, outputs_by_point, @@ -560,7 +560,7 @@ fn graphviz_for_edge( intern, ); maybe_render_point( - p2, + point2, seen_points, inputs_by_point, outputs_by_point, @@ -569,41 +569,41 @@ fn graphviz_for_edge( ); ret.push(format!( "\"node{0}\" -> \"node{1}\":f0 [\n id = {2}\n];\n", - p1.index(), - p2.index(), + point1.index(), + point2.index(), edge_index )); ret } fn maybe_render_point( - pt: Point, + point: Point, seen_points: &mut BTreeSet, inputs_by_point: &[HashMap], outputs_by_point: &[HashMap], render_vec: &mut Vec, intern: &InternerTables, ) { - if seen_points.contains(&pt.index()) { + if seen_points.contains(&point.index()) { return; } - seen_points.insert(pt.index()); + seen_points.insert(point.index()); let input_tuples = inputs_by_point .iter() - .filter_map(|inp| inp.get(&pt).map(std::string::ToString::to_string)) + .filter_map(|inp| inp.get(&point).map(ToString::to_string)) .collect::>() .join(" | "); let output_tuples = outputs_by_point .iter() - .filter_map(|outp| outp.get(&pt).map(std::string::ToString::to_string)) + .filter_map(|outp| outp.get(&point).map(ToString::to_string)) .collect::>() .join(" | "); render_vec.push(format!("\"node{0}\" [\n label = \"{{ {1} | INPUTS | {2} | OUTPUTS | {3} }}\"\n shape = \"record\"\n];\n", - pt.index(), - escape_for_graphviz(Point::table(intern).untern(pt)), + point.index(), + escape_for_graphviz(Point::table(intern).untern(point)), &input_tuples, &output_tuples)); } @@ -652,45 +652,45 @@ impl Liveness { self.point_facts.extend(other.point_facts); } - fn from_polonius_data(output: &Output, all_facts: &AllFacts, point: Point) -> Self { + fn from_polonius_data(output: &Output, all_facts: &AllFacts, location: Point) -> Self { let mut point_facts = Vec::default(); point_facts.extend( all_facts .var_defined .iter() - .filter(|&(_v, p)| *p == point) - .map(|&(v, p)| ("☠".to_string(), v, p)), + .filter(|&(_var, point)| *point == location) + .map(|&(var, point)| ("☠".to_string(), var, point)), ); point_facts.extend( all_facts .var_drop_used .iter() - .filter(|&(_v, p)| *p == point) - .map(|&(v, p)| ("💧".to_string(), v, p)), + .filter(|&(_var, point)| *point == location) + .map(|&(var, point)| ("💧".to_string(), var, point)), ); point_facts.extend( all_facts .var_used .iter() - .filter(|&(_v, p)| *p == point) - .map(|&(v, p)| ("🔧".to_string(), v, p)), + .filter(|&(_var, point)| *point == location) + .map(|&(var, point)| ("🔧".to_string(), var, point)), ); Self { point_facts, use_live_vars: output .var_live_at - .get(&point) + .get(&location) .map_or(HashSet::default(), |live| live.iter().cloned().collect()), drop_live_vars: output .var_drop_live_at - .get(&point) + .get(&location) .map_or(HashSet::default(), |live| live.iter().cloned().collect()), - cfg_points: vec![point], + cfg_points: vec![location], } } } @@ -702,7 +702,7 @@ fn render_cfg_label(node: &Liveness, intern: &InternerTables) -> String { let mut fragments = vec![if cfg_points.len() <= 3 { node.cfg_points .iter() - .map(|p| intern.points.untern(*p).replace("\"", "")) + .map(|point| intern.points.untern(*point).replace("\"", "")) .collect::>() .join(", ") } else { @@ -721,12 +721,12 @@ fn render_cfg_label(node: &Liveness, intern: &InternerTables) -> String { fragments[0].push_str("\\l"); - fragments.extend(node.point_facts.iter().map(|(label, var, pt)| { + fragments.extend(node.point_facts.iter().map(|(label, var, point)| { format!( "{}({}, {}).", label, intern.variables.untern(*var).replace("\"", ""), - intern.points.untern(*pt).replace("\"", ""), + intern.points.untern(*point).replace("\"", ""), ) })); @@ -745,16 +745,16 @@ pub(crate) fn liveness_graph( let mut cfg = StableGraph::::new(); let mut point_to_node = HashMap::new(); - for &(p1, p2) in all_facts.cfg_edge.iter() { - let n1 = *point_to_node - .entry(p1) - .or_insert_with(|| cfg.add_node(Liveness::from_polonius_data(output, all_facts, p1))); + for &(point1, point2) in all_facts.cfg_edge.iter() { + let node1 = *point_to_node.entry(point1).or_insert_with(|| { + cfg.add_node(Liveness::from_polonius_data(output, all_facts, point1)) + }); - let n2 = *point_to_node - .entry(p2) - .or_insert_with(|| cfg.add_node(Liveness::from_polonius_data(output, all_facts, p2))); + let node2 = *point_to_node.entry(point2).or_insert_with(|| { + cfg.add_node(Liveness::from_polonius_data(output, all_facts, point2)) + }); - cfg.add_edge(n1, n2, ()); + cfg.add_edge(node1, node2, ()); } info!("Reducing the liveness graph..."); @@ -829,14 +829,14 @@ pub(crate) fn liveness_graph( for edge in cfg.edge_references() { let edge_live_vars = edge_live_vars(&cfg[edge.source()], &cfg[edge.target()]); - for &v in edge_live_vars.iter() { + for &var in edge_live_vars.iter() { let liveness_status = vec![ - if cfg[edge.source()].use_live_vars.contains(&v) { + if cfg[edge.source()].use_live_vars.contains(&var) { "U" } else { "" }, - if cfg[edge.source()].drop_live_vars.contains(&v) { + if cfg[edge.source()].drop_live_vars.contains(&var) { "D" } else { "" @@ -848,9 +848,9 @@ pub(crate) fn liveness_graph( "{} -> {} [label=\" {} {}\", color=\"{}\", penwidth = 2 arrowhead = none]", cfg.to_index(edge.target()), cfg.to_index(edge.source()), - intern.variables.untern(v).replace("\"", ""), + intern.variables.untern(var).replace("\"", ""), liveness_status, - colour_palette[v.index() % colour_palette.len()], + colour_palette[var.index() % colour_palette.len()], )); } diff --git a/src/facts.rs b/src/facts.rs index 11e7a39bdb7..74f57ff6cb1 100644 --- a/src/facts.rs +++ b/src/facts.rs @@ -38,12 +38,12 @@ index_type!(Origin); index_type!(Loan); index_type!(Point); index_type!(Variable); -index_type!(MovePath); +index_type!(Path); impl FactTypes for LocalFacts { type Origin = Origin; type Loan = Loan; type Point = Point; type Variable = Variable; - type MovePath = MovePath; + type Path = Path; } diff --git a/src/intern.rs b/src/intern.rs index ceb51e4691c..419e2415176 100644 --- a/src/intern.rs +++ b/src/intern.rs @@ -46,7 +46,7 @@ pub(crate) struct InternerTables { pub(crate) loans: Interner, pub(crate) points: Interner, pub(crate) variables: Interner, - pub(crate) move_paths: Interner, + pub(crate) paths: Interner, } impl InternerTables { @@ -56,7 +56,7 @@ impl InternerTables { loans: Interner::new(), points: Interner::new(), variables: Interner::new(), - move_paths: Interner::new(), + paths: Interner::new(), } } } @@ -79,7 +79,7 @@ intern_impl!(Origin, origins); intern_impl!(Loan, loans); intern_impl!(Point, points); intern_impl!(Variable, variables); -intern_impl!(MovePath, move_paths); +intern_impl!(Path, paths); impl InternTo<(A, B)> for (FromA, FromB) where diff --git a/src/program.rs b/src/program.rs index 311ee927e6a..d11cb481eba 100644 --- a/src/program.rs +++ b/src/program.rs @@ -7,7 +7,7 @@ use polonius_parser::{ parse_input, }; -use crate::facts::{AllFacts, Loan, MovePath, Origin, Point, Variable}; +use crate::facts::{AllFacts, Loan, Origin, Path, Point, Variable}; use crate::intern::InternerTables; /// A structure to hold and deduplicate facts @@ -24,11 +24,11 @@ struct Facts { var_drop_used: BTreeSet<(Variable, Point)>, var_uses_region: BTreeSet<(Variable, Origin)>, var_drops_region: BTreeSet<(Variable, Origin)>, - child: BTreeSet<(MovePath, MovePath)>, - path_belongs_to_var: BTreeSet<(MovePath, Variable)>, - initialized_at: BTreeSet<(MovePath, Point)>, - moved_out_at: BTreeSet<(MovePath, Point)>, - path_accessed_at: BTreeSet<(MovePath, Point)>, + child: BTreeSet<(Path, Path)>, + path_belongs_to_var: BTreeSet<(Path, Variable)>, + initialized_at: BTreeSet<(Path, Point)>, + moved_out_at: BTreeSet<(Path, Point)>, + path_accessed_at: BTreeSet<(Path, Point)>, } impl From for AllFacts { @@ -184,10 +184,10 @@ fn emit_fact(facts: &mut Facts, fact: &Fact, point: Point, tables: &mut Interner // facts: outlives(Origin, Origin, Point) Fact::Outlives { ref a, ref b } => { // outlives: a `outlives` occurs on Mid points - let region_a = tables.origins.intern(a); - let region_b = tables.origins.intern(b); + let origin_a = tables.origins.intern(a); + let origin_b = tables.origins.intern(b); - facts.outlives.insert((region_a, region_b, point)); + facts.outlives.insert((origin_a, origin_b, point)); } // facts: killed(Loan, Point) @@ -204,14 +204,14 @@ fn emit_fact(facts: &mut Facts, fact: &Fact, point: Point, tables: &mut Interner facts.invalidates.insert((point, loan)); } - // facts: var_defined(V, P) + // facts: var_defined(Variable, Point) Fact::DefineVariable { ref variable } => { // var_defined: a variable is overwritten here let variable = tables.variables.intern(variable); facts.var_defined.insert((variable, point)); } - // facts: var_used(V, P) + // facts: var_used(Variable, Point) Fact::UseVariable { ref variable } => { // var_used: a variable is used here let variable = tables.variables.intern(variable); @@ -262,7 +262,7 @@ mod tests { let universal_regions: Vec<_> = facts .universal_region .iter() - .map(|r| tables.origins.untern(*r).to_string()) + .map(|origin| tables.origins.untern(*origin).to_string()) .collect(); assert_eq!(universal_regions, ["'a", "'b", "'c"]); @@ -288,12 +288,12 @@ mod tests { assert_eq!(facts.outlives.len(), 1); { - let region_a = tables.origins.untern(facts.outlives[0].0); - let region_b = tables.origins.untern(facts.outlives[0].1); + let origin_a = tables.origins.untern(facts.outlives[0].0); + let origin_b = tables.origins.untern(facts.outlives[0].1); let point = tables.points.untern(facts.outlives[0].2); - assert_eq!(region_a, "'a"); - assert_eq!(region_b, "'b"); + assert_eq!(origin_a, "'a"); + assert_eq!(origin_b, "'b"); assert_eq!(point, "\"Mid(B1[0])\""); } @@ -321,8 +321,8 @@ mod tests { let points: BTreeSet = facts .cfg_edge .iter() - .map(|&(p, _)| p) - .chain(facts.cfg_edge.iter().map(|&(_, q)| q)) + .map(|&(point1, _)| point1) + .chain(facts.cfg_edge.iter().map(|&(_, point2)| point2)) .collect(); assert_eq!(points.len(), 6); assert_eq!(facts.cfg_edge.len(), 5); diff --git a/src/test.rs b/src/test.rs index cbae1782aff..1975e307790 100644 --- a/src/test.rs +++ b/src/test.rs @@ -136,8 +136,8 @@ fn no_subset_symmetries_exist() -> Result<(), Box> { let subset_symmetries_exist = |output: &Output| { for (_, subsets) in &output.subset { - for (r1, rs) in subsets { - if rs.contains(&r1) { + for (origin, origins) in subsets { + if origins.contains(&origin) { return true; } } @@ -321,7 +321,7 @@ fn smoke_test_success_2() { } #[test] -// V used in P => V live upon entry into P +// `var` used in `point` => `var` live upon entry into `point` fn var_live_in_single_block() { let program = r" universal_regions { } @@ -345,7 +345,7 @@ fn var_live_in_single_block() { } #[test] -// P GOTO Q, V used in Q => V live in P +// `point1` GOTO `point2`, `var` used in `point2` => `var` live in `point1` fn var_live_in_successor_propagates_to_predecessor() { let program = r" universal_regions { } @@ -381,7 +381,7 @@ fn var_live_in_successor_propagates_to_predecessor() { } #[test] -// P GOTO Q, V used in Q, V defined in P => V not live in P +// `point1` GOTO `point2`, `var` used in `point2`, `var` defined in `point1` => `var` not live in `point1` fn var_live_in_successor_killed_by_reassignment() { let program = r" universal_regions { }