mirror of
https://github.com/roc-lang/roc.git
synced 2024-09-22 08:17:40 +03:00
Merge pull request #415 from rtfeldman/usage-analysis-improvements
Usage analysis improvements
This commit is contained in:
commit
ecd24932bc
@ -78,6 +78,28 @@ where
|
||||
answer
|
||||
}
|
||||
|
||||
/// Like intersection_with, except for MutMap and specialized to return
|
||||
/// a tuple. Also, only clones the values that will be actually returned,
|
||||
/// rather than cloning everything.
|
||||
pub fn get_shared<K, V>(map1: &MutMap<K, V>, map2: &MutMap<K, V>) -> MutMap<K, (V, V)>
|
||||
where
|
||||
K: Clone + Eq + Hash,
|
||||
V: Clone,
|
||||
{
|
||||
let mut answer = MutMap::default();
|
||||
|
||||
for (key, right_value) in map2 {
|
||||
match std::collections::HashMap::get(map1, &key) {
|
||||
None => (),
|
||||
Some(left_value) => {
|
||||
answer.insert(key.clone(), (left_value.clone(), right_value.clone()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
answer
|
||||
}
|
||||
|
||||
/// Like im's union, but for MutMap.
|
||||
pub fn union<K, V>(mut map: MutMap<K, V>, other: &MutMap<K, V>) -> MutMap<K, V>
|
||||
where
|
||||
|
@ -16,7 +16,7 @@ use roc_types::types::AnnotationSource::{self, *};
|
||||
use roc_types::types::Type::{self, *};
|
||||
use roc_types::types::{Alias, Category, PReason, Reason};
|
||||
use roc_uniq::builtins::{attr_type, empty_list_type, list_type, str_type};
|
||||
use roc_uniq::sharing::{self, Container, FieldAccess, Mark, Usage, VarUsage};
|
||||
use roc_uniq::sharing::{self, FieldAccess, Mark, Usage, VarUsage};
|
||||
|
||||
pub struct Env {
|
||||
/// Whenever we encounter a user-defined type variable (a "rigid" var for short),
|
||||
@ -1434,11 +1434,14 @@ fn constrain_var(
|
||||
]),
|
||||
)
|
||||
}
|
||||
Some(Simple(Unique)) => {
|
||||
Some(Simple(Unique)) | Some(Simple(Seen)) => {
|
||||
// no additional constraints, keep uniqueness unbound
|
||||
Lookup(symbol_for_lookup, expected, region)
|
||||
}
|
||||
Some(Usage::Access(_, _, _)) | Some(Usage::Update(_, _, _)) => {
|
||||
Some(Usage::RecordAccess(_, _))
|
||||
| Some(Usage::RecordUpdate(_, _))
|
||||
| Some(Usage::ApplyAccess(_, _))
|
||||
| Some(Usage::ApplyUpdate(_, _)) => {
|
||||
applied_usage_constraint.insert(symbol_for_lookup);
|
||||
|
||||
let mut variables = Vec::new();
|
||||
@ -1457,8 +1460,6 @@ fn constrain_var(
|
||||
]),
|
||||
)
|
||||
}
|
||||
|
||||
Some(other) => panic!("some other rc value: {:?}", other),
|
||||
}
|
||||
}
|
||||
|
||||
@ -1486,12 +1487,12 @@ fn constrain_by_usage(
|
||||
|
||||
(Bool::container(uvar, vec![]), Type::Variable(var))
|
||||
}
|
||||
Usage::Access(Container::Record, mark, fields) => {
|
||||
Usage::RecordAccess(mark, fields) => {
|
||||
let (record_bool, ext_type) = constrain_by_usage(&Simple(*mark), var_store, introduced);
|
||||
|
||||
constrain_by_usage_record(fields, record_bool, ext_type, introduced, var_store)
|
||||
}
|
||||
Usage::Update(Container::Record, _, fields) => {
|
||||
Usage::RecordUpdate(_, fields) => {
|
||||
let record_uvar = var_store.fresh();
|
||||
introduced.push(record_uvar);
|
||||
|
||||
@ -1503,12 +1504,11 @@ fn constrain_by_usage(
|
||||
|
||||
constrain_by_usage_record(fields, record_bool, ext_type, introduced, var_store)
|
||||
}
|
||||
Usage::Access(Container::List, mark, fields) => {
|
||||
Usage::ApplyAccess(mark, fields) => {
|
||||
let (list_bool, _ext_type) = constrain_by_usage(&Simple(*mark), var_store, introduced);
|
||||
|
||||
let field_usage = fields
|
||||
.get(&sharing::LIST_ELEM.into())
|
||||
.expect("no LIST_ELEM key");
|
||||
// TODO reconsier this for multi-value applies
|
||||
let field_usage = fields.get(0).expect("no LIST_ELEM key");
|
||||
|
||||
let (elem_bool, elem_type) = constrain_by_usage(field_usage, var_store, introduced);
|
||||
|
||||
@ -1543,13 +1543,12 @@ fn constrain_by_usage(
|
||||
}
|
||||
}
|
||||
|
||||
Usage::Update(Container::List, _, fields) => {
|
||||
Usage::ApplyUpdate(_, fields) => {
|
||||
let list_uvar = var_store.fresh();
|
||||
introduced.push(list_uvar);
|
||||
|
||||
let field_usage = fields
|
||||
.get(&sharing::LIST_ELEM.into())
|
||||
.expect("no LIST_ELEM key");
|
||||
// TODO reconsier this for multi-value applies
|
||||
let field_usage = fields.get(0).expect("no LIST_ELEM key");
|
||||
|
||||
let (elem_bool, elem_type) = constrain_by_usage(field_usage, var_store, introduced);
|
||||
|
||||
|
@ -221,12 +221,12 @@ mod test_uniq_load {
|
||||
expect_types(
|
||||
loaded_module,
|
||||
hashmap! {
|
||||
"findPath" => "Attr * (Attr * { costFunction : (Attr Shared (Attr Shared position, Attr Shared position -> Attr Shared Float)), end : (Attr Shared position), moveFunction : (Attr Shared (Attr Shared position -> Attr * (Set (Attr * position)))), start : (Attr Shared position) } -> Attr * (Result (Attr * (List (Attr Shared position))) (Attr * [ KeyNotFound ]*)))",
|
||||
"findPath" => "Attr * (Attr * { costFunction : (Attr Shared (Attr Shared position, Attr Shared position -> Attr * Float)), end : (Attr Shared position), moveFunction : (Attr Shared (Attr Shared position -> Attr * (Set (Attr * position)))), start : (Attr Shared position) } -> Attr * (Result (Attr * (List (Attr Shared position))) (Attr * [ KeyNotFound ]*)))",
|
||||
"initialModel" => "Attr * (Attr Shared position -> Attr * (Model (Attr Shared position)))",
|
||||
"reconstructPath" => "Attr Shared (Attr Shared (Map (Attr * position) (Attr Shared position)), Attr Shared position -> Attr * (List (Attr Shared position)))",
|
||||
"updateCost" => "Attr * (Attr Shared position, Attr Shared position, Attr Shared (Model (Attr Shared position)) -> Attr Shared (Model (Attr Shared position)))",
|
||||
"cheapestOpen" => "Attr * (Attr * (Attr Shared position -> Attr Shared Float), Attr (* | a | b) (Model (Attr Shared position)) -> Attr * (Result (Attr Shared position) (Attr * [ KeyNotFound ]*)))",
|
||||
"astar" => "Attr Shared (Attr Shared (Attr Shared position, Attr Shared position -> Attr Shared Float), Attr Shared (Attr Shared position -> Attr * (Set (Attr * position))), Attr Shared position, Attr Shared (Model (Attr Shared position)) -> Attr * [ Err (Attr * [ KeyNotFound ]*), Ok (Attr * (List (Attr Shared position))) ]*)",
|
||||
"cheapestOpen" => "Attr * (Attr * (Attr Shared position -> Attr * Float), Attr (* | a | b | c) (Model (Attr Shared position)) -> Attr * (Result (Attr Shared position) (Attr * [ KeyNotFound ]*)))",
|
||||
"astar" => "Attr Shared (Attr Shared (Attr Shared position, Attr Shared position -> Attr * Float), Attr Shared (Attr Shared position -> Attr * (Set (Attr * position))), Attr Shared position, Attr Shared (Model (Attr Shared position)) -> Attr * [ Err (Attr * [ KeyNotFound ]*), Ok (Attr * (List (Attr Shared position))) ]*)",
|
||||
},
|
||||
);
|
||||
});
|
||||
@ -242,7 +242,7 @@ mod test_uniq_load {
|
||||
expect_types(
|
||||
loaded_module,
|
||||
hashmap! {
|
||||
"swap" => "Attr * (Attr Shared Int, Attr Shared Int, Attr * (List (Attr Shared a)) -> Attr * (List (Attr Shared a)))",
|
||||
"swap" => "Attr * (Attr * Int, Attr * Int, Attr * (List (Attr Shared a)) -> Attr * (List (Attr Shared a)))",
|
||||
"partition" => "Attr * (Attr Shared Int, Attr Shared Int, Attr b (List (Attr Shared (Num (Attr Shared a)))) -> Attr * [ Pair (Attr * Int) (Attr b (List (Attr Shared (Num (Attr Shared a))))) ])",
|
||||
"quicksort" => "Attr Shared (Attr b (List (Attr Shared (Num (Attr Shared a)))), Attr Shared Int, Attr Shared Int -> Attr b (List (Attr Shared (Num (Attr Shared a)))))",
|
||||
},
|
||||
|
@ -1418,7 +1418,7 @@ mod solve_uniq_expr {
|
||||
swap
|
||||
"#
|
||||
),
|
||||
"Attr * (Attr Shared Int, Attr Shared Int, Attr * (List (Attr Shared a)) -> Attr * (List (Attr Shared a)))"
|
||||
"Attr * (Attr * Int, Attr * Int, Attr * (List (Attr Shared a)) -> Attr * (List (Attr Shared a)))"
|
||||
);
|
||||
}
|
||||
|
||||
@ -2789,7 +2789,7 @@ mod solve_uniq_expr {
|
||||
cheapestOpen
|
||||
"#
|
||||
),
|
||||
"Attr * (Attr * (Attr Shared position -> Attr Shared Float), Attr (* | * | *) (Model (Attr Shared position)) -> Attr * (Result (Attr Shared position) (Attr * [ KeyNotFound ]*)))"
|
||||
"Attr * (Attr * (Attr Shared position -> Attr * Float), Attr (* | * | * | *) (Model (Attr Shared position)) -> Attr * (Result (Attr Shared position) (Attr * [ KeyNotFound ]*)))"
|
||||
)
|
||||
});
|
||||
}
|
||||
@ -2956,7 +2956,7 @@ mod solve_uniq_expr {
|
||||
findPath
|
||||
"#
|
||||
),
|
||||
"Attr * (Attr * { costFunction : (Attr Shared (Attr Shared position, Attr Shared position -> Attr Shared Float)), end : (Attr Shared position), moveFunction : (Attr Shared (Attr Shared position -> Attr * (Set (Attr * position)))), start : (Attr Shared position) } -> Attr * (Result (Attr * (List (Attr Shared position))) (Attr * [ KeyNotFound ]*)))"
|
||||
"Attr * (Attr * { costFunction : (Attr Shared (Attr Shared position, Attr Shared position -> Attr * Float)), end : (Attr Shared position), moveFunction : (Attr Shared (Attr Shared position -> Attr * (Set (Attr * position)))), start : (Attr Shared position) } -> Attr * (Result (Attr * (List (Attr Shared position))) (Attr * [ KeyNotFound ]*)))"
|
||||
)
|
||||
});
|
||||
}
|
||||
|
@ -1,11 +1,10 @@
|
||||
use roc_collections::all::{relative_complement, union, MutMap, SendSet};
|
||||
use roc_collections::all::{get_shared, relative_complement, union, MutMap, SendSet};
|
||||
use roc_module::ident::{Lowercase, TagName};
|
||||
use roc_module::symbol::Symbol;
|
||||
use roc_types::boolean_algebra::Bool;
|
||||
use roc_types::subs::Content::{self, *};
|
||||
use roc_types::subs::{Descriptor, FlatType, Mark, OptVariable, Subs, Variable};
|
||||
use roc_types::types::{gather_fields, ErrorType, Mismatch, RecordStructure};
|
||||
use std::hash::Hash;
|
||||
|
||||
macro_rules! mismatch {
|
||||
() => {{
|
||||
@ -223,28 +222,6 @@ fn unify_structure(
|
||||
}
|
||||
}
|
||||
|
||||
/// Like intersection_with, except for MutMap and specialized to return
|
||||
/// a tuple. Also, only clones the values that will be actually returned,
|
||||
/// rather than cloning everything.
|
||||
fn get_shared<K, V>(map1: &MutMap<K, V>, map2: &MutMap<K, V>) -> MutMap<K, (V, V)>
|
||||
where
|
||||
K: Clone + Eq + Hash,
|
||||
V: Clone,
|
||||
{
|
||||
let mut answer = MutMap::default();
|
||||
|
||||
for (key, right_value) in map2 {
|
||||
match std::collections::HashMap::get(map1, &key) {
|
||||
None => (),
|
||||
Some(left_value) => {
|
||||
answer.insert(key.clone(), (left_value.clone(), right_value.clone()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
answer
|
||||
}
|
||||
|
||||
fn unify_record(
|
||||
subs: &mut Subs,
|
||||
pool: &mut Pool,
|
||||
|
@ -2,8 +2,6 @@ use roc_can::expr::Expr;
|
||||
use roc_collections::all::{ImMap, ImSet};
|
||||
use roc_module::ident::Lowercase;
|
||||
use roc_module::symbol::Symbol;
|
||||
use roc_region::all::Located;
|
||||
use roc_types::subs::Variable;
|
||||
|
||||
// fake field names for container elements
|
||||
// e.g. for lists, internally it's a record with a `list_elem` field
|
||||
@ -33,8 +31,14 @@ impl IntoIterator for FieldAccess {
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum Usage {
|
||||
Simple(Mark),
|
||||
Access(Container, Mark, FieldAccess),
|
||||
Update(Container, ImSet<Lowercase>, FieldAccess),
|
||||
|
||||
// Lists, Sets, ADTs
|
||||
ApplyAccess(Mark, Vec<Usage>),
|
||||
ApplyUpdate(ImSet<usize>, Vec<Usage>),
|
||||
|
||||
// Records
|
||||
RecordAccess(Mark, FieldAccess),
|
||||
RecordUpdate(ImSet<Lowercase>, FieldAccess),
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||
@ -92,6 +96,58 @@ impl Composable for FieldAccess {
|
||||
}
|
||||
}
|
||||
|
||||
impl Composable for Vec<Usage> {
|
||||
fn sequential(&mut self, other: &Self) {
|
||||
// NOTE we don't know they have the same length
|
||||
|
||||
let mut it_other = other.iter();
|
||||
{
|
||||
for (self_usage, other_usage) in self.iter_mut().zip(&mut it_other) {
|
||||
self_usage.sequential(&other_usage);
|
||||
|
||||
if *self_usage != Usage::Simple(Mark::Seen) {
|
||||
// e.g. we access `rec.foo` and `rec.foo.bar`.
|
||||
// Since a reference to `rec.foo` exists, there are at least two references to `foo.bar`
|
||||
// (`foo.bar` itself and `.bar rec.foo`)
|
||||
// Therefore fields of the subtrees must be shared!
|
||||
|
||||
// TODO make this work? Seems to function well without it
|
||||
// self_nested.or_subtree(&Usage::Shared);
|
||||
// other_nested.or_subtree(&Usage::Shared);
|
||||
//
|
||||
// member function on FieldAccess
|
||||
// fn or_subtree(&mut self, constraint: &Usage) {
|
||||
// for field_usage in self.fields.iter_mut() {
|
||||
// field_usage.parallel(constraint);
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if there are remaining elements in other, push them onto self
|
||||
for other_usage in it_other {
|
||||
self.push(other_usage.clone());
|
||||
}
|
||||
}
|
||||
|
||||
fn parallel(&mut self, other: &Self) {
|
||||
// NOTE we don't know they have the same length
|
||||
|
||||
let mut it_other = other.iter();
|
||||
{
|
||||
for (self_usage, other_usage) in self.iter_mut().zip(&mut it_other) {
|
||||
self_usage.parallel(&other_usage);
|
||||
}
|
||||
}
|
||||
|
||||
// if there are remaining elements in other, push them onto self
|
||||
for other_usage in it_other {
|
||||
self.push(other_usage.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Composable for Usage {
|
||||
fn sequential(&mut self, other: &Self) {
|
||||
use Mark::*;
|
||||
@ -103,79 +159,161 @@ impl Composable for Usage {
|
||||
*self = Simple(Shared);
|
||||
}
|
||||
|
||||
(Update(c1, _, _), Update(c2, _, _)) | (Update(c1, _, _), Access(c2, _, _)) => {
|
||||
debug_assert_eq!(c1, c2);
|
||||
// Record Update
|
||||
(RecordUpdate(_, _), RecordUpdate(_, _)) | (RecordUpdate(_, _), RecordAccess(_, _)) => {
|
||||
*self = Simple(Shared);
|
||||
}
|
||||
|
||||
(Update(_, _, _), Simple(Unique)) | (Simple(Unique), Update(_, _, _)) => {
|
||||
(RecordUpdate(_, _), Simple(Unique)) | (Simple(Unique), RecordUpdate(_, _)) => {
|
||||
*self = Simple(Shared);
|
||||
}
|
||||
|
||||
(Access(c1, m1, fields1), Update(c2, overwritten, fields2)) => {
|
||||
debug_assert_eq!(c1, c2);
|
||||
*self = correct_overwritten(*c1, *m1, fields1, Seen, fields2, overwritten);
|
||||
(RecordAccess(m1, fields1), RecordUpdate(overwritten, fields2)) => {
|
||||
*self = correct_overwritten(*m1, fields1, Seen, fields2, overwritten);
|
||||
}
|
||||
|
||||
(Simple(Seen), Update(c1, overwritten, fa)) => {
|
||||
*self = Update(*c1, overwritten.clone(), fa.clone());
|
||||
(Simple(Seen), RecordUpdate(overwritten, fa)) => {
|
||||
*self = RecordUpdate(overwritten.clone(), fa.clone());
|
||||
}
|
||||
(Update(c1, overwritten, fa), Simple(Seen)) => {
|
||||
*self = Update(*c1, overwritten.clone(), fa.clone());
|
||||
(RecordUpdate(overwritten, fa), Simple(Seen)) => {
|
||||
*self = RecordUpdate(overwritten.clone(), fa.clone());
|
||||
}
|
||||
|
||||
// Access
|
||||
(Access(c1, m1, fa1), Access(c2, m2, fa2)) => {
|
||||
debug_assert_eq!(c1, c2);
|
||||
// RecordAccess
|
||||
(RecordAccess(m1, fa1), RecordAccess(m2, fa2)) => {
|
||||
let mut fa = fa1.clone();
|
||||
fa.sequential(fa2);
|
||||
|
||||
let mut m = *m1;
|
||||
m.sequential(m2);
|
||||
|
||||
*self = Access(*c1, m, fa);
|
||||
*self = RecordAccess(m, fa);
|
||||
}
|
||||
(Access(c1, m, fa1), Simple(Unique)) => {
|
||||
let mut copy = Access(*c1, *m, fa1.clone());
|
||||
(RecordAccess(m, fa1), Simple(Unique)) => {
|
||||
let mut copy = RecordAccess(*m, fa1.clone());
|
||||
make_subtree_shared(&mut copy);
|
||||
|
||||
// correct the mark of the top-level access
|
||||
*self = if let Access(c, _, fa) = copy {
|
||||
*self = if let RecordAccess(_, fa) = copy {
|
||||
let mut m = *m;
|
||||
m.sequential(&Unique);
|
||||
|
||||
Access(c, m, fa)
|
||||
RecordAccess(m, fa)
|
||||
} else {
|
||||
unreachable!()
|
||||
};
|
||||
}
|
||||
(Simple(Unique), Access(c, m, fa)) => {
|
||||
let mut copy = Access(*c, *m, fa.clone());
|
||||
(Simple(Unique), RecordAccess(m, fa)) => {
|
||||
let mut copy = RecordAccess(*m, fa.clone());
|
||||
make_subtree_shared(&mut copy);
|
||||
|
||||
// correct the mark of the top-level access
|
||||
*self = if let Access(c, _, fa) = copy {
|
||||
*self = if let RecordAccess(_, fa) = copy {
|
||||
let mut m = *m;
|
||||
m.sequential(&Unique);
|
||||
|
||||
Access(c, m, fa)
|
||||
RecordAccess(m, fa)
|
||||
} else {
|
||||
unreachable!()
|
||||
};
|
||||
}
|
||||
|
||||
(Simple(m1 @ Seen), Access(c1, m2, fa)) => {
|
||||
(Simple(m1 @ Seen), RecordAccess(m2, fa)) => {
|
||||
let mut m = *m1;
|
||||
m.sequential(m2);
|
||||
*self = Access(*c1, m, fa.clone())
|
||||
*self = RecordAccess(m, fa.clone())
|
||||
}
|
||||
|
||||
(Access(c1, m1, fa), Simple(m2 @ Seen)) => {
|
||||
(RecordAccess(m1, fa), Simple(m2 @ Seen)) => {
|
||||
let mut m = *m1;
|
||||
m.sequential(m2);
|
||||
*self = Access(*c1, m, fa.clone());
|
||||
*self = RecordAccess(m, fa.clone());
|
||||
}
|
||||
|
||||
// Apply Update
|
||||
(ApplyUpdate(_, _), ApplyUpdate(_, _)) | (ApplyUpdate(_, _), ApplyAccess(_, _)) => {
|
||||
*self = Simple(Shared);
|
||||
}
|
||||
|
||||
(ApplyUpdate(_, _), Simple(Unique)) | (Simple(Unique), ApplyUpdate(_, _)) => {
|
||||
*self = Simple(Shared);
|
||||
}
|
||||
|
||||
(ApplyAccess(m1, fields1), ApplyUpdate(overwritten, fields2)) => {
|
||||
*self = correct_overwritten_apply(*m1, fields1, Seen, fields2, overwritten);
|
||||
}
|
||||
|
||||
(Simple(Seen), ApplyUpdate(overwritten, fa)) => {
|
||||
*self = ApplyUpdate(overwritten.clone(), fa.clone());
|
||||
}
|
||||
(ApplyUpdate(overwritten, fa), Simple(Seen)) => {
|
||||
*self = ApplyUpdate(overwritten.clone(), fa.clone());
|
||||
}
|
||||
|
||||
// RecordAccess
|
||||
(ApplyAccess(m1, fa1), ApplyAccess(m2, fa2)) => {
|
||||
let mut fa = fa1.clone();
|
||||
fa.sequential(fa2);
|
||||
|
||||
let mut m = *m1;
|
||||
m.sequential(m2);
|
||||
|
||||
*self = ApplyAccess(m, fa);
|
||||
}
|
||||
(ApplyAccess(m, fa1), Simple(Unique)) => {
|
||||
let mut copy = ApplyAccess(*m, fa1.clone());
|
||||
make_subtree_shared(&mut copy);
|
||||
|
||||
// correct the mark of the top-level access
|
||||
*self = if let ApplyAccess(_, fa) = copy {
|
||||
let mut m = *m;
|
||||
m.sequential(&Unique);
|
||||
|
||||
ApplyAccess(m, fa)
|
||||
} else {
|
||||
unreachable!()
|
||||
};
|
||||
}
|
||||
(Simple(Unique), ApplyAccess(m, fa)) => {
|
||||
let mut copy = ApplyAccess(*m, fa.clone());
|
||||
make_subtree_shared(&mut copy);
|
||||
|
||||
// correct the mark of the top-level access
|
||||
*self = if let ApplyAccess(_, fa) = copy {
|
||||
let mut m = *m;
|
||||
m.sequential(&Unique);
|
||||
|
||||
ApplyAccess(m, fa)
|
||||
} else {
|
||||
unreachable!()
|
||||
};
|
||||
}
|
||||
|
||||
(Simple(m1 @ Seen), ApplyAccess(m2, fa)) => {
|
||||
let mut m = *m1;
|
||||
m.sequential(m2);
|
||||
*self = ApplyAccess(m, fa.clone())
|
||||
}
|
||||
|
||||
(ApplyAccess(m1, fa), Simple(m2 @ Seen)) => {
|
||||
let mut m = *m1;
|
||||
m.sequential(m2);
|
||||
*self = ApplyAccess(m, fa.clone());
|
||||
}
|
||||
|
||||
// Things cannot change type
|
||||
(ApplyAccess(_, _), RecordAccess(_, _))
|
||||
| (ApplyAccess(_, _), RecordUpdate(_, _))
|
||||
| (ApplyUpdate(_, _), RecordAccess(_, _))
|
||||
| (ApplyUpdate(_, _), RecordUpdate(_, _))
|
||||
| (RecordAccess(_, _), ApplyAccess(_, _))
|
||||
| (RecordUpdate(_, _), ApplyAccess(_, _))
|
||||
| (RecordAccess(_, _), ApplyUpdate(_, _))
|
||||
| (RecordUpdate(_, _), ApplyUpdate(_, _)) => {
|
||||
unreachable!("applies cannot turn into records or vice versa!")
|
||||
}
|
||||
|
||||
// Simple
|
||||
(Simple(s1), Simple(s2)) => {
|
||||
let mut s = *s1;
|
||||
s.sequential(s2);
|
||||
@ -199,58 +337,120 @@ impl Composable for Usage {
|
||||
(Simple(Shared), _) | (_, Simple(Shared)) => {
|
||||
*self = Simple(Shared);
|
||||
}
|
||||
|
||||
(Update(c1, w1, fa1), Update(c2, w2, fa2)) => {
|
||||
debug_assert_eq!(c1, c2);
|
||||
// Record update
|
||||
(RecordUpdate(w1, fa1), RecordUpdate(w2, fa2)) => {
|
||||
let mut fa = fa1.clone();
|
||||
fa.parallel(fa2);
|
||||
|
||||
let w = w1.clone().intersection(w2.clone());
|
||||
|
||||
*self = Update(*c1, w, fa);
|
||||
*self = RecordUpdate(w, fa);
|
||||
}
|
||||
|
||||
(Update(_, _, _), Simple(Unique)) | (Update(_, _, _), Simple(Seen)) => {
|
||||
//*self = Update(*c1, w.clone(), fa.clone());
|
||||
(RecordUpdate(_, _), Simple(Unique)) | (RecordUpdate(_, _), Simple(Seen)) => {
|
||||
//*self = RecordUpdate( w.clone(), fa.clone());
|
||||
}
|
||||
(Simple(Unique), Update(c1, w, fa)) | (Simple(Seen), Update(c1, w, fa)) => {
|
||||
*self = Update(*c1, w.clone(), fa.clone());
|
||||
(Simple(Unique), RecordUpdate(w, fa)) | (Simple(Seen), RecordUpdate(w, fa)) => {
|
||||
*self = RecordUpdate(w.clone(), fa.clone());
|
||||
}
|
||||
|
||||
(Update(c1, w, fa1), Access(c2, _, fa2)) => {
|
||||
debug_assert_eq!(c1, c2);
|
||||
(RecordUpdate(w, fa1), RecordAccess(_, fa2)) => {
|
||||
let mut fa = fa1.clone();
|
||||
fa.parallel(&fa2.clone());
|
||||
*self = Update(*c1, w.clone(), fa);
|
||||
*self = RecordUpdate(w.clone(), fa);
|
||||
}
|
||||
(Access(c1, _, fa1), Update(c2, w, fa2)) => {
|
||||
debug_assert_eq!(c1, c2);
|
||||
(RecordAccess(_, fa1), RecordUpdate(w, fa2)) => {
|
||||
let mut fa = fa1.clone();
|
||||
fa.parallel(&fa2.clone());
|
||||
*self = Update(*c1, w.clone(), fa);
|
||||
*self = RecordUpdate(w.clone(), fa);
|
||||
}
|
||||
|
||||
(Access(c1, m1, fa1), Access(c2, m2, fa2)) => {
|
||||
debug_assert_eq!(c1, c2);
|
||||
// Record Access
|
||||
(RecordAccess(m1, fa1), RecordAccess(m2, fa2)) => {
|
||||
let mut m = *m1;
|
||||
m.parallel(m2);
|
||||
|
||||
let mut fa = fa1.clone();
|
||||
fa.parallel(fa2);
|
||||
*self = Access(*c1, m, fa)
|
||||
*self = RecordAccess(m, fa)
|
||||
}
|
||||
(Access(c, m, fa), Simple(Unique)) => {
|
||||
(RecordAccess(m, fa), Simple(Unique)) => {
|
||||
let mut m = *m;
|
||||
m.parallel(&Unique);
|
||||
*self = Access(*c, m, fa.clone());
|
||||
*self = RecordAccess(m, fa.clone());
|
||||
}
|
||||
(Access(_, _, _), Simple(Seen)) => {
|
||||
// *self = Access(*c1, *m, fa.clone());
|
||||
(RecordAccess(_, _), Simple(Seen)) => {
|
||||
// *self = RecordAccess( *m, fa.clone());
|
||||
}
|
||||
(Simple(m1 @ Unique), Access(c1, m2, fa)) | (Simple(m1 @ Seen), Access(c1, m2, fa)) => {
|
||||
(Simple(m1 @ Unique), RecordAccess(m2, fa))
|
||||
| (Simple(m1 @ Seen), RecordAccess(m2, fa)) => {
|
||||
let mut m = *m1;
|
||||
m.sequential(m2);
|
||||
*self = Access(*c1, m, fa.clone());
|
||||
*self = RecordAccess(m, fa.clone());
|
||||
}
|
||||
|
||||
// Apply Update
|
||||
(ApplyUpdate(w1, fa1), ApplyUpdate(w2, fa2)) => {
|
||||
let mut fa = fa1.clone();
|
||||
fa.parallel(fa2);
|
||||
|
||||
let w = w1.clone().intersection(w2.clone());
|
||||
|
||||
*self = ApplyUpdate(w, fa);
|
||||
}
|
||||
|
||||
(ApplyUpdate(_, _), Simple(Unique)) | (ApplyUpdate(_, _), Simple(Seen)) => {
|
||||
//*self = ApplyUpdate( w.clone(), fa.clone());
|
||||
}
|
||||
(Simple(Unique), ApplyUpdate(w, fa)) | (Simple(Seen), ApplyUpdate(w, fa)) => {
|
||||
*self = ApplyUpdate(w.clone(), fa.clone());
|
||||
}
|
||||
|
||||
(ApplyUpdate(w, fa1), ApplyAccess(_, fa2)) => {
|
||||
let mut fa = fa1.clone();
|
||||
fa.parallel(&fa2.clone());
|
||||
*self = ApplyUpdate(w.clone(), fa);
|
||||
}
|
||||
(ApplyAccess(_, fa1), ApplyUpdate(w, fa2)) => {
|
||||
let mut fa = fa1.clone();
|
||||
fa.parallel(&fa2.clone());
|
||||
*self = ApplyUpdate(w.clone(), fa);
|
||||
}
|
||||
|
||||
// Apply Access
|
||||
(ApplyAccess(m1, fa1), ApplyAccess(m2, fa2)) => {
|
||||
let mut m = *m1;
|
||||
m.parallel(m2);
|
||||
|
||||
let mut fa = fa1.clone();
|
||||
fa.parallel(fa2);
|
||||
*self = ApplyAccess(m, fa)
|
||||
}
|
||||
(ApplyAccess(m, fa), Simple(Unique)) => {
|
||||
let mut m = *m;
|
||||
m.parallel(&Unique);
|
||||
*self = ApplyAccess(m, fa.clone());
|
||||
}
|
||||
(ApplyAccess(_, _), Simple(Seen)) => {
|
||||
// *self = ApplyAccess( *m, fa.clone());
|
||||
}
|
||||
(Simple(m1 @ Unique), ApplyAccess(m2, fa))
|
||||
| (Simple(m1 @ Seen), ApplyAccess(m2, fa)) => {
|
||||
let mut m = *m1;
|
||||
m.sequential(m2);
|
||||
*self = ApplyAccess(m, fa.clone());
|
||||
}
|
||||
|
||||
// Things cannot change type
|
||||
(ApplyAccess(_, _), RecordAccess(_, _))
|
||||
| (ApplyAccess(_, _), RecordUpdate(_, _))
|
||||
| (ApplyUpdate(_, _), RecordAccess(_, _))
|
||||
| (ApplyUpdate(_, _), RecordUpdate(_, _))
|
||||
| (RecordAccess(_, _), ApplyAccess(_, _))
|
||||
| (RecordUpdate(_, _), ApplyAccess(_, _))
|
||||
| (RecordAccess(_, _), ApplyUpdate(_, _))
|
||||
| (RecordUpdate(_, _), ApplyUpdate(_, _)) => {
|
||||
unreachable!("applies cannot turn into records or vice versa!")
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -293,7 +493,6 @@ impl Composable for Mark {
|
||||
}
|
||||
|
||||
fn correct_overwritten(
|
||||
c: Container,
|
||||
mut mark1: Mark,
|
||||
fa1: &FieldAccess,
|
||||
mark2: Mark,
|
||||
@ -314,7 +513,34 @@ fn correct_overwritten(
|
||||
}
|
||||
}
|
||||
|
||||
Update(c, overwritten.clone(), fa1)
|
||||
RecordUpdate(overwritten.clone(), fa1)
|
||||
}
|
||||
|
||||
fn correct_overwritten_apply(
|
||||
mut mark1: Mark,
|
||||
fa1: &[Usage],
|
||||
mark2: Mark,
|
||||
fa2: &[Usage],
|
||||
overwritten: &ImSet<usize>,
|
||||
) -> Usage {
|
||||
use Usage::*;
|
||||
|
||||
let mut fa1 = fa1.to_owned();
|
||||
// TODO fix this cloning
|
||||
// tricky because Composable is defined on Vec, not &[]
|
||||
let fa2 = fa2.to_owned();
|
||||
|
||||
mark1.sequential(&mark2);
|
||||
fa1.sequential(&fa2);
|
||||
|
||||
// fields that are accessed, but not overwritten in the update, must be shared!
|
||||
for (index, usage) in fa1.iter_mut().enumerate() {
|
||||
if !overwritten.contains(&index) {
|
||||
make_subtree_shared(usage);
|
||||
}
|
||||
}
|
||||
|
||||
ApplyUpdate(overwritten.clone(), fa1)
|
||||
}
|
||||
|
||||
fn make_subtree_shared(usage: &mut Usage) {
|
||||
@ -328,12 +554,12 @@ fn make_subtree_shared(usage: &mut Usage) {
|
||||
*usage = Simple(Shared);
|
||||
}
|
||||
|
||||
Update(_, _, fa) => {
|
||||
RecordUpdate(_, fa) => {
|
||||
for nested in fa.fields.iter_mut() {
|
||||
make_subtree_shared(nested);
|
||||
}
|
||||
}
|
||||
Access(_, m, fa) => {
|
||||
RecordAccess(m, fa) => {
|
||||
for nested in fa.fields.iter_mut() {
|
||||
make_subtree_shared(nested);
|
||||
}
|
||||
@ -342,28 +568,61 @@ fn make_subtree_shared(usage: &mut Usage) {
|
||||
_ => Shared,
|
||||
};
|
||||
}
|
||||
ApplyUpdate(_, fa) => {
|
||||
for nested in fa.iter_mut() {
|
||||
make_subtree_shared(nested);
|
||||
}
|
||||
}
|
||||
|
||||
ApplyAccess(m, fa) => {
|
||||
for nested in fa.iter_mut() {
|
||||
make_subtree_shared(nested);
|
||||
}
|
||||
*m = match &m {
|
||||
Seen => Seen,
|
||||
_ => Shared,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct VarUsage {
|
||||
usage: ImMap<Symbol, Usage>,
|
||||
}
|
||||
|
||||
impl IntoIterator for VarUsage {
|
||||
type Item = (Symbol, Usage);
|
||||
type IntoIter = im_rc::hashmap::ConsumingIter<(Symbol, Usage)>;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.usage.into_iter()
|
||||
}
|
||||
pub usage: ImMap<Symbol, Usage>,
|
||||
pub closure_usage_signatures: ImMap<Symbol, Vec<Usage>>,
|
||||
}
|
||||
|
||||
impl VarUsage {
|
||||
pub fn default() -> VarUsage {
|
||||
let empty: ImMap<Symbol, Usage> = ImMap::default();
|
||||
let mut closure_signatures = ImMap::default();
|
||||
|
||||
VarUsage { usage: empty }
|
||||
closure_signatures.insert(
|
||||
Symbol::NUM_ADD,
|
||||
vec![Usage::Simple(Mark::Seen), Usage::Simple(Mark::Seen)],
|
||||
);
|
||||
closure_signatures.insert(
|
||||
Symbol::LIST_GET,
|
||||
vec![
|
||||
Usage::ApplyAccess(Mark::Seen, vec![Usage::Simple(Mark::Unique)]),
|
||||
Usage::Simple(Mark::Seen),
|
||||
],
|
||||
);
|
||||
|
||||
closure_signatures.insert(Symbol::LIST_IS_EMPTY, vec![Usage::Simple(Mark::Seen)]);
|
||||
|
||||
closure_signatures.insert(
|
||||
Symbol::LIST_SET,
|
||||
vec![
|
||||
Usage::ApplyUpdate(ImSet::default(), vec![Usage::Simple(Mark::Seen)]),
|
||||
Usage::Simple(Mark::Seen),
|
||||
Usage::Simple(Mark::Unique),
|
||||
],
|
||||
);
|
||||
|
||||
VarUsage {
|
||||
usage: ImMap::default(),
|
||||
closure_usage_signatures: closure_signatures,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn register_with(&mut self, symbol: Symbol, rc: &Usage) {
|
||||
@ -389,6 +648,11 @@ impl VarUsage {
|
||||
self.register_with(symbol, &Simple(Mark::Unique));
|
||||
}
|
||||
|
||||
pub fn register_seen(&mut self, symbol: Symbol) {
|
||||
use self::Usage::*;
|
||||
self.register_with(symbol, &Simple(Mark::Seen));
|
||||
}
|
||||
|
||||
pub fn unregister(&mut self, symbol: Symbol) {
|
||||
self.usage.remove(&symbol);
|
||||
}
|
||||
@ -450,7 +714,7 @@ impl Usage {
|
||||
for field in access_chain.into_iter().rev() {
|
||||
let mut fa = FieldAccess::default();
|
||||
fa.fields.insert(field, accum);
|
||||
accum = Usage::Access(Container::Record, Mark::Seen, fa);
|
||||
accum = Usage::RecordAccess(Mark::Seen, fa);
|
||||
}
|
||||
|
||||
accum
|
||||
@ -619,17 +883,34 @@ pub fn annotate_usage(expr: &Expr, usage: &mut VarUsage) {
|
||||
annotate_usage(&loc_expr.value, usage);
|
||||
}
|
||||
Call(fun, loc_args, _) => {
|
||||
annotate_usage(&fun.1.value, usage);
|
||||
if let Var(symbol) = fun.1.value {
|
||||
// call by name
|
||||
special_case_builtins(usage, symbol, loc_args);
|
||||
} else {
|
||||
// unknown call
|
||||
annotate_usage(&fun.1.value, usage);
|
||||
|
||||
for (_, arg) in loc_args {
|
||||
annotate_usage(&arg.value, usage);
|
||||
// fetch the signature
|
||||
let opt_signature = match usage.closure_usage_signatures.get(&symbol) {
|
||||
Some(v) => Some(v.clone()),
|
||||
None => None,
|
||||
};
|
||||
|
||||
if let Some(signature) = opt_signature {
|
||||
// we know the usage signature of this function
|
||||
for ((_, arg), annotated) in loc_args.iter().zip(signature.iter()) {
|
||||
if let Var(arg_symbol) = arg.value {
|
||||
usage.register_with(arg_symbol, &annotated);
|
||||
} else {
|
||||
annotate_usage(&arg.value, usage);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// unknown call
|
||||
for (_, arg) in loc_args {
|
||||
annotate_usage(&arg.value, usage);
|
||||
}
|
||||
}
|
||||
Closure(_, _, _, _, body) => {
|
||||
annotate_usage(&body.0.value, usage);
|
||||
@ -657,7 +938,7 @@ pub fn annotate_usage(expr: &Expr, usage: &mut VarUsage) {
|
||||
|
||||
usage.register_with(
|
||||
*symbol,
|
||||
&Usage::Update(Container::Record, labels, FieldAccess::default()),
|
||||
&Usage::RecordUpdate(labels, FieldAccess::default()),
|
||||
);
|
||||
}
|
||||
Expr::Access {
|
||||
@ -693,77 +974,3 @@ fn get_access_chain<'a>(expr: &'a Expr, chain: &mut Vec<Lowercase>) -> Option<&'
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn special_case_builtins(
|
||||
usage: &mut VarUsage,
|
||||
symbol: Symbol,
|
||||
loc_args: &[(Variable, Located<Expr>)],
|
||||
) {
|
||||
use Expr::Var;
|
||||
use Mark::*;
|
||||
use Usage::*;
|
||||
match symbol {
|
||||
Symbol::LIST_GET => {
|
||||
debug_assert!(loc_args.len() == 2);
|
||||
|
||||
let loc_list = &loc_args[0].1;
|
||||
let loc_index = &loc_args[1].1;
|
||||
|
||||
if let Var(list_var) = loc_list.value {
|
||||
usage.register_with(
|
||||
list_var,
|
||||
&Access(Container::List, Seen, FieldAccess::list_access()),
|
||||
);
|
||||
} else {
|
||||
annotate_usage(&loc_list.value, usage);
|
||||
}
|
||||
annotate_usage(&loc_index.value, usage);
|
||||
}
|
||||
|
||||
Symbol::LIST_SET => {
|
||||
debug_assert_eq!(loc_args.len(), 3);
|
||||
|
||||
let loc_list = &loc_args[0].1;
|
||||
let loc_index = &loc_args[1].1;
|
||||
let loc_value = &loc_args[2].1;
|
||||
|
||||
if let Var(list_var) = loc_list.value {
|
||||
usage.register_with(
|
||||
list_var,
|
||||
&Update(
|
||||
Container::List,
|
||||
ImSet::default(),
|
||||
FieldAccess::list_update(),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
annotate_usage(&loc_list.value, usage);
|
||||
}
|
||||
annotate_usage(&loc_index.value, usage);
|
||||
annotate_usage(&loc_value.value, usage);
|
||||
}
|
||||
|
||||
Symbol::LIST_IS_EMPTY | Symbol::LIST_LEN => {
|
||||
debug_assert!(loc_args.len() == 1);
|
||||
|
||||
let loc_list = &loc_args[0].1;
|
||||
|
||||
if let Var(list_var) = loc_list.value {
|
||||
usage.register_with(
|
||||
list_var,
|
||||
&Access(Container::List, Seen, FieldAccess::list_seen()),
|
||||
);
|
||||
} else {
|
||||
annotate_usage(&loc_list.value, usage);
|
||||
}
|
||||
}
|
||||
|
||||
_ => {
|
||||
usage.register_unique(symbol);
|
||||
|
||||
for (_, arg) in loc_args {
|
||||
annotate_usage(&arg.value, usage);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -18,10 +18,9 @@ mod test_usage_analysis {
|
||||
use roc_collections::all::{ImMap, ImSet};
|
||||
use roc_module::ident::Lowercase;
|
||||
use roc_module::symbol::{Interns, Symbol};
|
||||
use roc_uniq::sharing::{self, Container, FieldAccess, Mark, Usage, VarUsage};
|
||||
use roc_uniq::sharing::{FieldAccess, Mark, Usage, VarUsage};
|
||||
use std::collections::HashMap;
|
||||
|
||||
use Container::*;
|
||||
use Mark::*;
|
||||
use Usage::*;
|
||||
|
||||
@ -37,7 +36,7 @@ mod test_usage_analysis {
|
||||
}
|
||||
|
||||
match usage {
|
||||
Usage::Access(_, _, fields) => {
|
||||
Usage::RecordAccess(_, fields) => {
|
||||
let mut actual: HashMap<Lowercase, Usage> = HashMap::default();
|
||||
for (k, v) in fields.into_iter() {
|
||||
actual.insert(k, v);
|
||||
@ -66,7 +65,7 @@ mod test_usage_analysis {
|
||||
}
|
||||
|
||||
match usage {
|
||||
Usage::Access(_, _, fields) => {
|
||||
Usage::RecordAccess(_, fields) => {
|
||||
let mut actual: HashMap<Lowercase, Usage> = HashMap::default();
|
||||
for (k, v) in fields.into_iter() {
|
||||
actual.insert(k, v);
|
||||
@ -135,14 +134,14 @@ mod test_usage_analysis {
|
||||
field_access_seq(
|
||||
vec![vec!["foo", "bar"], vec!["foo"]],
|
||||
hashmap![
|
||||
"foo" => Access(Record, Unique, field_access(hashmap![ "bar" => Simple(Shared) ]))
|
||||
"foo" => RecordAccess( Unique, field_access(hashmap![ "bar" => Simple(Shared) ]))
|
||||
],
|
||||
);
|
||||
|
||||
field_access_seq(
|
||||
vec![vec!["foo"], vec!["foo", "bar"]],
|
||||
hashmap![
|
||||
"foo" => Access(Record, Unique, field_access(hashmap![ "bar" => Simple(Shared) ]))
|
||||
"foo" => RecordAccess( Unique, field_access(hashmap![ "bar" => Simple(Shared) ]))
|
||||
],
|
||||
);
|
||||
}
|
||||
@ -151,13 +150,13 @@ mod test_usage_analysis {
|
||||
field_access_par(
|
||||
vec![vec!["foo", "bar"], vec!["foo"]],
|
||||
hashmap![
|
||||
"foo" => Access(Record, Unique, field_access(hashmap![ "bar" => Simple(Unique) ]))
|
||||
"foo" => RecordAccess( Unique, field_access(hashmap![ "bar" => Simple(Unique) ]))
|
||||
],
|
||||
);
|
||||
field_access_par(
|
||||
vec![vec!["foo"], vec!["foo", "bar"]],
|
||||
hashmap![
|
||||
"foo" => Access(Record, Unique, field_access(hashmap![ "bar" => Simple(Unique) ]))
|
||||
"foo" => RecordAccess( Unique, field_access(hashmap![ "bar" => Simple(Unique) ]))
|
||||
],
|
||||
);
|
||||
}
|
||||
@ -167,13 +166,13 @@ mod test_usage_analysis {
|
||||
field_access_seq(
|
||||
vec![vec!["foo", "bar", "baz"], vec!["foo", "bar"]],
|
||||
hashmap![
|
||||
"foo" => Access(Record, Seen, field_access(hashmap![ "bar" => Access(Record, Unique, field_access(hashmap![ "baz" => Simple(Shared) ]))]))
|
||||
"foo" => RecordAccess( Seen, field_access(hashmap![ "bar" => RecordAccess( Unique, field_access(hashmap![ "baz" => Simple(Shared) ]))]))
|
||||
],
|
||||
);
|
||||
field_access_seq(
|
||||
vec![vec!["foo", "bar"], vec!["foo", "bar", "baz"]],
|
||||
hashmap![
|
||||
"foo" => Access(Record, Seen, field_access(hashmap![ "bar" => Access(Record, Unique, field_access(hashmap![ "baz" => Simple(Shared) ]))]))
|
||||
"foo" => RecordAccess( Seen, field_access(hashmap![ "bar" => RecordAccess( Unique, field_access(hashmap![ "baz" => Simple(Shared) ]))]))
|
||||
],
|
||||
);
|
||||
}
|
||||
@ -235,11 +234,7 @@ mod test_usage_analysis {
|
||||
|
||||
usage.register_with(
|
||||
interns.symbol(home, "rec".into()),
|
||||
&Access(
|
||||
Record,
|
||||
Seen,
|
||||
field_access(hashmap![ "foo" => Simple(Unique) ]),
|
||||
),
|
||||
&RecordAccess(Seen, field_access(hashmap![ "foo" => Simple(Unique) ])),
|
||||
);
|
||||
|
||||
usage
|
||||
@ -263,8 +258,7 @@ mod test_usage_analysis {
|
||||
let overwritten = hashset!["foo".into()].into();
|
||||
usage.register_with(
|
||||
interns.symbol(home, "rec".into()),
|
||||
&Update(
|
||||
Record,
|
||||
&RecordUpdate(
|
||||
overwritten,
|
||||
field_access(hashmap![ "foo" => Simple(Unique) ]),
|
||||
),
|
||||
@ -313,11 +307,7 @@ mod test_usage_analysis {
|
||||
|
||||
usage.register_with(
|
||||
interns.symbol(home, "rec".into()),
|
||||
&Access(
|
||||
Record,
|
||||
Unique,
|
||||
field_access(hashmap![ "foo" => Simple(Shared) ]),
|
||||
),
|
||||
&RecordAccess(Unique, field_access(hashmap![ "foo" => Simple(Shared) ])),
|
||||
);
|
||||
|
||||
usage
|
||||
@ -351,10 +341,7 @@ mod test_usage_analysis {
|
||||
]);
|
||||
|
||||
usage.register_unique(interns.symbol(home, "p".into()));
|
||||
usage.register_with(
|
||||
interns.symbol(home, "r".into()),
|
||||
&Access(Record, Unique, fa),
|
||||
);
|
||||
usage.register_with(interns.symbol(home, "r".into()), &RecordAccess(Unique, fa));
|
||||
|
||||
usage
|
||||
},
|
||||
@ -379,16 +366,13 @@ mod test_usage_analysis {
|
||||
|
||||
let fa = field_access(hashmap![
|
||||
"foo" =>
|
||||
Access(Record, Seen, field_access(hashmap![
|
||||
RecordAccess( Seen, field_access(hashmap![
|
||||
"bar" => Simple(Shared),
|
||||
"baz" => Simple(Shared),
|
||||
]))
|
||||
]);
|
||||
|
||||
usage.register_with(
|
||||
interns.symbol(home, "r".into()),
|
||||
&Access(Record, Unique, fa),
|
||||
);
|
||||
usage.register_with(interns.symbol(home, "r".into()), &RecordAccess(Unique, fa));
|
||||
|
||||
usage
|
||||
},
|
||||
@ -421,14 +405,14 @@ mod test_usage_analysis {
|
||||
"x" => Simple(Shared),
|
||||
]);
|
||||
|
||||
usage.register_with(r, &Update(Record, overwritten, fa));
|
||||
usage.register_with(r, &RecordUpdate(overwritten, fa));
|
||||
|
||||
let fa = field_access(hashmap![
|
||||
"x" => Simple(Unique),
|
||||
"y" => Simple(Unique),
|
||||
]);
|
||||
|
||||
usage.register_with(s, &Access(Record, Seen, fa));
|
||||
usage.register_with(s, &RecordAccess(Seen, fa));
|
||||
usage
|
||||
},
|
||||
);
|
||||
@ -460,14 +444,14 @@ mod test_usage_analysis {
|
||||
"x" => Simple(Unique),
|
||||
]);
|
||||
|
||||
usage.register_with(r, &Update(Record, overwritten, fa));
|
||||
usage.register_with(r, &RecordUpdate(overwritten, fa));
|
||||
|
||||
let fa = field_access(hashmap![
|
||||
"x" => Simple(Unique),
|
||||
"y" => Simple(Unique),
|
||||
]);
|
||||
|
||||
usage.register_with(s, &Access(Record, Seen, fa));
|
||||
usage.register_with(s, &RecordAccess(Seen, fa));
|
||||
|
||||
usage
|
||||
},
|
||||
@ -496,7 +480,7 @@ mod test_usage_analysis {
|
||||
"y" => Simple(Unique),
|
||||
]);
|
||||
|
||||
usage.register_with(r, &Access(Record, Seen, fa));
|
||||
usage.register_with(r, &RecordAccess(Seen, fa));
|
||||
|
||||
usage
|
||||
},
|
||||
@ -525,7 +509,7 @@ mod test_usage_analysis {
|
||||
|
||||
let overwritten = hashset!["y".into()].into();
|
||||
|
||||
usage.register_with(r, &Update(Record, overwritten, fa));
|
||||
usage.register_with(r, &RecordUpdate(overwritten, fa));
|
||||
|
||||
usage
|
||||
},
|
||||
@ -546,8 +530,7 @@ mod test_usage_analysis {
|
||||
let home = test_home();
|
||||
let mut usage = VarUsage::default();
|
||||
|
||||
let access = Access(
|
||||
Record,
|
||||
let access = RecordAccess(
|
||||
Seen,
|
||||
field_access(hashmap![
|
||||
"x" => Simple(Unique),
|
||||
@ -599,16 +582,8 @@ mod test_usage_analysis {
|
||||
let mut usage = VarUsage::default();
|
||||
let home = test_home();
|
||||
|
||||
let access_r = Access(
|
||||
Record,
|
||||
Seen,
|
||||
field_access(hashmap![ "y" => Simple(Unique) ]),
|
||||
);
|
||||
let access_s = Access(
|
||||
Record,
|
||||
Seen,
|
||||
field_access(hashmap![ "x" => Simple(Shared) ]),
|
||||
);
|
||||
let access_r = RecordAccess(Seen, field_access(hashmap![ "y" => Simple(Unique) ]));
|
||||
let access_s = RecordAccess(Seen, field_access(hashmap![ "x" => Simple(Shared) ]));
|
||||
|
||||
let r = interns.symbol(home, "r".into());
|
||||
let s = interns.symbol(home, "s".into());
|
||||
@ -640,16 +615,8 @@ mod test_usage_analysis {
|
||||
let mut usage = VarUsage::default();
|
||||
let home = test_home();
|
||||
|
||||
let access_r = Access(
|
||||
Record,
|
||||
Seen,
|
||||
field_access(hashmap![ "x" => Simple(Unique) ]),
|
||||
);
|
||||
let access_s = Access(
|
||||
Record,
|
||||
Seen,
|
||||
field_access(hashmap![ "x" => Simple(Shared) ]),
|
||||
);
|
||||
let access_r = RecordAccess(Seen, field_access(hashmap![ "x" => Simple(Unique) ]));
|
||||
let access_s = RecordAccess(Seen, field_access(hashmap![ "x" => Simple(Shared) ]));
|
||||
|
||||
let r = interns.symbol(home, "r".into());
|
||||
let s = interns.symbol(home, "s".into());
|
||||
@ -681,14 +648,10 @@ mod test_usage_analysis {
|
||||
let home = test_home();
|
||||
|
||||
let overwritten = hashset!["y".into()].into();
|
||||
let access_r = Update(
|
||||
Record,
|
||||
overwritten,
|
||||
field_access(hashmap![ "x" => Simple(Shared) ]),
|
||||
);
|
||||
let access_r =
|
||||
RecordUpdate(overwritten, field_access(hashmap![ "x" => Simple(Shared) ]));
|
||||
|
||||
let access_s = Access(
|
||||
Record,
|
||||
let access_s = RecordAccess(
|
||||
Unique,
|
||||
field_access(hashmap![
|
||||
"x" => Simple(Shared),
|
||||
@ -722,18 +685,14 @@ mod test_usage_analysis {
|
||||
let mut usage = VarUsage::default();
|
||||
let home = test_home();
|
||||
|
||||
let access = Access(
|
||||
List,
|
||||
Unique,
|
||||
field_access(hashmap![
|
||||
sharing::LIST_ELEM => Simple(Shared),
|
||||
]),
|
||||
);
|
||||
let access = ApplyAccess(Unique, vec![Simple(Shared)]);
|
||||
|
||||
let r = interns.symbol(home, "r".into());
|
||||
|
||||
usage.register_with(r, &access);
|
||||
|
||||
usage.register_shared(Symbol::LIST_GET);
|
||||
|
||||
usage
|
||||
},
|
||||
);
|
||||
@ -758,22 +717,19 @@ mod test_usage_analysis {
|
||||
let mut usage = VarUsage::default();
|
||||
let home = test_home();
|
||||
|
||||
let access = Update(
|
||||
List,
|
||||
ImSet::default(),
|
||||
field_access(hashmap![
|
||||
sharing::LIST_ELEM => Simple(Shared),
|
||||
]),
|
||||
);
|
||||
let access = ApplyUpdate(ImSet::default(), vec![Simple(Shared)]);
|
||||
|
||||
let r = interns.symbol(home, "list".into());
|
||||
let v = interns.symbol(home, "v".into());
|
||||
|
||||
usage.register_with(r, &access);
|
||||
|
||||
usage.register_unique(v);
|
||||
usage.register_seen(v);
|
||||
usage.register_unique(Symbol::NUM_ADD);
|
||||
|
||||
usage.register_unique(Symbol::LIST_SET);
|
||||
usage.register_unique(Symbol::LIST_GET);
|
||||
|
||||
usage
|
||||
},
|
||||
);
|
||||
@ -796,18 +752,15 @@ mod test_usage_analysis {
|
||||
let mut usage = VarUsage::default();
|
||||
let home = test_home();
|
||||
|
||||
let access = Update(
|
||||
List,
|
||||
ImSet::default(),
|
||||
field_access(hashmap![
|
||||
sharing::LIST_ELEM => Simple(Seen),
|
||||
]),
|
||||
);
|
||||
let access = ApplyUpdate(ImSet::default(), vec![Simple(Seen)]);
|
||||
|
||||
let r = interns.symbol(home, "list".into());
|
||||
|
||||
usage.register_with(r, &access);
|
||||
|
||||
usage.register_unique(Symbol::LIST_SET);
|
||||
usage.register_unique(Symbol::LIST_IS_EMPTY);
|
||||
|
||||
usage
|
||||
},
|
||||
);
|
||||
|
Loading…
Reference in New Issue
Block a user