mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-28 22:34:45 +00:00
bitvec all the things
This commit is contained in:
parent
b0ceaf0372
commit
452447232f
3 changed files with 88 additions and 67 deletions
|
@ -467,6 +467,7 @@ pub(crate) fn canonicalize_defs<'a>(
|
||||||
// Now that we know the alias dependency graph, we can try to insert recursion variables
|
// Now that we know the alias dependency graph, we can try to insert recursion variables
|
||||||
// where aliases are recursive tag unions, or detect illegal recursions.
|
// where aliases are recursive tag unions, or detect illegal recursions.
|
||||||
let mut aliases = correct_mutual_recursive_type_alias(env, aliases, var_store);
|
let mut aliases = correct_mutual_recursive_type_alias(env, aliases, var_store);
|
||||||
|
|
||||||
for (symbol, alias) in aliases.iter() {
|
for (symbol, alias) in aliases.iter() {
|
||||||
scope.add_alias(
|
scope.add_alias(
|
||||||
*symbol,
|
*symbol,
|
||||||
|
@ -1908,19 +1909,10 @@ fn correct_mutual_recursive_type_alias<'a>(
|
||||||
let capacity = original_aliases.len();
|
let capacity = original_aliases.len();
|
||||||
let mut matrix = ReferenceMatrix::new(capacity);
|
let mut matrix = ReferenceMatrix::new(capacity);
|
||||||
|
|
||||||
let (symbols_introduced, mut aliases): (Vec<_>, Vec<_>) = original_aliases
|
let (symbols_introduced, mut aliases): (Vec<_>, Vec<_>) = original_aliases.into_iter().unzip();
|
||||||
.into_iter()
|
|
||||||
.map(|(k, v)| (k, Some(v)))
|
|
||||||
.unzip();
|
|
||||||
|
|
||||||
for (index, alias) in aliases.iter().enumerate() {
|
for (index, alias) in aliases.iter().enumerate() {
|
||||||
let it = alias
|
for referenced in alias.typ.symbols() {
|
||||||
.as_ref()
|
|
||||||
.map(|a| a.typ.symbols().into_iter())
|
|
||||||
.into_iter()
|
|
||||||
.flatten();
|
|
||||||
|
|
||||||
for referenced in it {
|
|
||||||
match symbols_introduced.iter().position(|k| referenced == *k) {
|
match symbols_introduced.iter().position(|k| referenced == *k) {
|
||||||
None => { /* ignore */ }
|
None => { /* ignore */ }
|
||||||
Some(ref_id) => matrix.set_row_col(index, ref_id, true),
|
Some(ref_id) => matrix.set_row_col(index, ref_id, true),
|
||||||
|
@ -1928,7 +1920,8 @@ fn correct_mutual_recursive_type_alias<'a>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut solved_aliases = ImMap::default();
|
let mut solved_aliases_bitvec = bitvec::vec::BitVec::<usize>::repeat(false, capacity);
|
||||||
|
let mut pending_aliases_bitvec = bitvec::vec::BitVec::repeat(false, capacity);
|
||||||
|
|
||||||
let group: Vec<_> = (0u32..capacity as u32).collect();
|
let group: Vec<_> = (0u32..capacity as u32).collect();
|
||||||
|
|
||||||
|
@ -1937,15 +1930,12 @@ fn correct_mutual_recursive_type_alias<'a>(
|
||||||
for cycle in cycles {
|
for cycle in cycles {
|
||||||
debug_assert!(!cycle.is_empty());
|
debug_assert!(!cycle.is_empty());
|
||||||
|
|
||||||
let mut pending_aliases: ImMap<_, _> = cycle
|
// zero out all the bits
|
||||||
.iter()
|
pending_aliases_bitvec.set_elements(0);
|
||||||
.map(|index| {
|
|
||||||
(
|
for index in cycle.iter() {
|
||||||
symbols_introduced[*index as usize],
|
pending_aliases_bitvec.set(*index as usize, true);
|
||||||
aliases[*index as usize].take().unwrap(),
|
}
|
||||||
)
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
// Make sure we report only one error for the cycle, not an error for every
|
// Make sure we report only one error for the cycle, not an error for every
|
||||||
// alias in the cycle.
|
// alias in the cycle.
|
||||||
|
@ -1955,23 +1945,43 @@ fn correct_mutual_recursive_type_alias<'a>(
|
||||||
// depends on.
|
// depends on.
|
||||||
// We only need to worry about symbols in this SCC or any prior one, since the SCCs
|
// We only need to worry about symbols in this SCC or any prior one, since the SCCs
|
||||||
// were sorted topologically, and we've already instantiated aliases coming from other
|
// were sorted topologically, and we've already instantiated aliases coming from other
|
||||||
// modules.
|
let mut to_instantiate_bitvec = solved_aliases_bitvec | &pending_aliases_bitvec;
|
||||||
// NB: ImMap::clone is O(1): https://docs.rs/im/latest/src/im/hash/map.rs.html#1527-1544
|
|
||||||
let mut to_instantiate = solved_aliases.clone().union(pending_aliases.clone());
|
|
||||||
|
|
||||||
for index in cycle.iter() {
|
for index in cycle.iter() {
|
||||||
let rec = symbols_introduced[*index as usize];
|
let index = *index as usize;
|
||||||
|
|
||||||
let alias = pending_aliases.get_mut(&rec).unwrap();
|
|
||||||
// Don't try to instantiate the alias itself in its definition.
|
// Don't try to instantiate the alias itself in its definition.
|
||||||
let original_alias_def = to_instantiate.remove(&rec).unwrap();
|
to_instantiate_bitvec.set(index, false);
|
||||||
|
|
||||||
let helper = |s| to_instantiate.get(&s);
|
// now we do something sneaky. In `can_instantiate_symbol` we want to be able to
|
||||||
|
// take a reference to an `Alias` in the `aliases` vec. That would not work if
|
||||||
|
// we also had a mutable reference to an alias in that vec. So we swap out the
|
||||||
|
// type.
|
||||||
|
let alias_region = aliases[index].region;
|
||||||
|
let mut alias_type = Type::EmptyRec;
|
||||||
|
|
||||||
|
std::mem::swap(&mut alias_type, &mut aliases[index].typ);
|
||||||
|
|
||||||
|
let can_instantiate_symbol = |s| match symbols_introduced.iter().position(|i| *i == s) {
|
||||||
|
Some(s_index) if to_instantiate_bitvec[s_index] => aliases.get(s_index),
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
|
||||||
let mut new_lambda_sets = ImSet::default();
|
let mut new_lambda_sets = ImSet::default();
|
||||||
alias
|
alias_type.instantiate_aliases(
|
||||||
.typ
|
alias_region,
|
||||||
.instantiate_aliases(alias.region, &helper, var_store, &mut new_lambda_sets);
|
&can_instantiate_symbol,
|
||||||
|
var_store,
|
||||||
|
&mut new_lambda_sets,
|
||||||
|
);
|
||||||
|
|
||||||
|
// swap the type back
|
||||||
|
std::mem::swap(&mut alias_type, &mut aliases[index].typ);
|
||||||
|
|
||||||
|
// We can instantiate this alias in future iterations
|
||||||
|
to_instantiate_bitvec.set(index, true);
|
||||||
|
|
||||||
|
let alias = &mut aliases[index];
|
||||||
|
|
||||||
for lambda_set_var in new_lambda_sets {
|
for lambda_set_var in new_lambda_sets {
|
||||||
alias
|
alias
|
||||||
|
@ -1979,10 +1989,9 @@ fn correct_mutual_recursive_type_alias<'a>(
|
||||||
.push(LambdaSet(Type::Variable(lambda_set_var)));
|
.push(LambdaSet(Type::Variable(lambda_set_var)));
|
||||||
}
|
}
|
||||||
|
|
||||||
to_instantiate.insert(rec, original_alias_def);
|
|
||||||
|
|
||||||
// Now mark the alias recursive, if it needs to be.
|
// Now mark the alias recursive, if it needs to be.
|
||||||
let is_self_recursive = alias.typ.contains_symbol(rec);
|
let rec = symbols_introduced[index];
|
||||||
|
let is_self_recursive = cycle.len() == 1 && matrix.get_row_col(index, index);
|
||||||
let is_mutually_recursive = cycle.len() > 1;
|
let is_mutually_recursive = cycle.len() > 1;
|
||||||
|
|
||||||
if is_self_recursive || is_mutually_recursive {
|
if is_self_recursive || is_mutually_recursive {
|
||||||
|
@ -2001,20 +2010,24 @@ fn correct_mutual_recursive_type_alias<'a>(
|
||||||
// all the types in the cycle are narrow newtypes. We can't figure this out until now,
|
// all the types in the cycle are narrow newtypes. We can't figure this out until now,
|
||||||
// because we need all the types to be deeply instantiated.
|
// because we need all the types to be deeply instantiated.
|
||||||
let all_are_narrow = cycle.iter().all(|index| {
|
let all_are_narrow = cycle.iter().all(|index| {
|
||||||
let sym = &symbols_introduced[*index as usize];
|
let index = *index as usize;
|
||||||
let typ = &pending_aliases.get(sym).unwrap().typ;
|
let typ = &aliases[index].typ;
|
||||||
matches!(typ, Type::RecursiveTagUnion(..)) && typ.is_narrow()
|
matches!(typ, Type::RecursiveTagUnion(..)) && typ.is_narrow()
|
||||||
});
|
});
|
||||||
|
|
||||||
if all_are_narrow {
|
if all_are_narrow {
|
||||||
// This cycle is illegal!
|
// This cycle is illegal!
|
||||||
let mut rest: Vec<Symbol> = cycle
|
|
||||||
|
let mut cycle = cycle;
|
||||||
|
let first_index = cycle.pop().unwrap() as usize;
|
||||||
|
|
||||||
|
let rest: Vec<Symbol> = cycle
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|i| symbols_introduced[i as usize])
|
.map(|i| symbols_introduced[i as usize])
|
||||||
.collect();
|
.collect();
|
||||||
let alias_name = rest.pop().unwrap();
|
|
||||||
|
|
||||||
let alias = pending_aliases.get_mut(&alias_name).unwrap();
|
let alias_name = symbols_introduced[first_index];
|
||||||
|
let alias = aliases.get_mut(first_index).unwrap();
|
||||||
|
|
||||||
mark_cyclic_alias(
|
mark_cyclic_alias(
|
||||||
env,
|
env,
|
||||||
|
@ -2026,11 +2039,14 @@ fn correct_mutual_recursive_type_alias<'a>(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now, promote all resolved aliases in this cycle as solved.
|
// We've instantiated all we could, so all instantiatable aliases are solved now
|
||||||
solved_aliases.extend(pending_aliases);
|
solved_aliases_bitvec = to_instantiate_bitvec;
|
||||||
}
|
}
|
||||||
|
|
||||||
solved_aliases
|
symbols_introduced
|
||||||
|
.into_iter()
|
||||||
|
.zip(aliases.into_iter())
|
||||||
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_tag_union_of_alias_recursive<'a>(
|
fn make_tag_union_of_alias_recursive<'a>(
|
||||||
|
|
|
@ -40,6 +40,11 @@ impl ReferenceMatrix {
|
||||||
self.bitvec[index]
|
self.bitvec[index]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn get_row_col(&self, row: usize, col: usize) -> bool {
|
||||||
|
self.bitvec[row * self.length + col]
|
||||||
|
}
|
||||||
|
|
||||||
pub fn is_recursive(&self, index: usize) -> bool {
|
pub fn is_recursive(&self, index: usize) -> bool {
|
||||||
let mut scheduled = self.row_slice(index).to_bitvec();
|
let mut scheduled = self.row_slice(index).to_bitvec();
|
||||||
let mut visited = self.row_slice(index).to_bitvec();
|
let mut visited = self.row_slice(index).to_bitvec();
|
||||||
|
|
|
@ -3646,8 +3646,8 @@ mod test_reporting {
|
||||||
This `ACons` global tag application has the type:
|
This `ACons` global tag application has the type:
|
||||||
|
|
||||||
[ ACons (Num (Integer Signed64)) [
|
[ ACons (Num (Integer Signed64)) [
|
||||||
BCons (Num (Integer Signed64)) [ ACons Str [ BCons I64 a, BNil ],
|
BCons (Num (Integer Signed64)) [ ACons Str [
|
||||||
ANil ], BNil ], ANil ]
|
BCons I64 (AList I64 I64), BNil ] as a, ANil ], BNil ], ANil ]
|
||||||
|
|
||||||
But the type annotation on `x` says it should be:
|
But the type annotation on `x` says it should be:
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue