mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-01 15:51:12 +00:00
fix issue with wrong alias being used for instantiation
This commit is contained in:
parent
cde4bd3ce0
commit
3ec3976781
1 changed files with 42 additions and 18 deletions
|
@ -1717,15 +1717,7 @@ 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);
|
||||||
|
|
||||||
// It is important that we instantiate with the aliases as they occur in the source.
|
let (symbols_introduced, mut aliases) = original_aliases.unzip();
|
||||||
// We must not instantiate A into B, then use the updated B to instantiate into C
|
|
||||||
//
|
|
||||||
// That is because B could be used different places. We don't want one place
|
|
||||||
// to mess with another.
|
|
||||||
let (symbols_introduced, uninstantiated_aliases) = original_aliases.unzip();
|
|
||||||
|
|
||||||
// the aliases that we will instantiate into
|
|
||||||
let mut aliases = uninstantiated_aliases.clone();
|
|
||||||
|
|
||||||
for (index, alias) in aliases.iter().enumerate() {
|
for (index, alias) in aliases.iter().enumerate() {
|
||||||
for referenced in alias.typ.symbols() {
|
for referenced in alias.typ.symbols() {
|
||||||
|
@ -1739,8 +1731,17 @@ fn correct_mutual_recursive_type_alias<'a>(
|
||||||
let mut solved_aliases_bitvec = bitvec::vec::BitVec::<usize>::repeat(false, capacity);
|
let mut solved_aliases_bitvec = bitvec::vec::BitVec::<usize>::repeat(false, capacity);
|
||||||
|
|
||||||
let group: Vec<_> = (0u32..capacity as u32).collect();
|
let group: Vec<_> = (0u32..capacity as u32).collect();
|
||||||
|
let sccs = matrix.strongly_connected_components(&group);
|
||||||
|
|
||||||
for cycle in matrix.strongly_connected_components(&group).groups() {
|
// sometimes we need to temporarily move some aliases somewhere
|
||||||
|
let scratchpad_capacity = sccs
|
||||||
|
.groups()
|
||||||
|
.map(|r| r.count_ones())
|
||||||
|
.max()
|
||||||
|
.unwrap_or_default();
|
||||||
|
let mut scratchpad = Vec::with_capacity(scratchpad_capacity);
|
||||||
|
|
||||||
|
for cycle in sccs.groups() {
|
||||||
debug_assert!(cycle.count_ones() > 0);
|
debug_assert!(cycle.count_ones() > 0);
|
||||||
|
|
||||||
// We need to instantiate the alias with any symbols in the currrent module it
|
// We need to instantiate the alias with any symbols in the currrent module it
|
||||||
|
@ -1761,21 +1762,34 @@ fn correct_mutual_recursive_type_alias<'a>(
|
||||||
// Don't try to instantiate the alias itself in its definition.
|
// Don't try to instantiate the alias itself in its definition.
|
||||||
to_instantiate_bitvec.set(index, false);
|
to_instantiate_bitvec.set(index, false);
|
||||||
|
|
||||||
|
// Within a recursive group, we must instantiate all aliases like how they came to the
|
||||||
|
// loop. So we cannot instantiate A into B, then the updated B into C in the same
|
||||||
|
// iteration. Hence, if we have more than one alias we sadly must clone and store
|
||||||
|
// the alias off to the side somewhere. After processing the group, we put the
|
||||||
|
// updated alias into the main `aliases` vector again, because for future groups
|
||||||
|
// we do need to use the instantiated version.
|
||||||
|
let alias = if cycle.count_ones() > 1 {
|
||||||
|
scratchpad.push((index, aliases[index].clone()));
|
||||||
|
|
||||||
|
&mut scratchpad.last_mut().unwrap().1
|
||||||
|
} else {
|
||||||
|
&mut aliases[index]
|
||||||
|
};
|
||||||
|
|
||||||
// we run into a problem here where we want to modify an element in the aliases array,
|
// we run into a problem here where we want to modify an element in the aliases array,
|
||||||
// but also reference the other elements. The borrow checker, correctly, says no to that.
|
// but also reference the other elements. The borrow checker, correctly, says no to that.
|
||||||
//
|
//
|
||||||
// So we get creative: we swap out the element we want to modify with a dummy. We can
|
// So we get creative: we swap out the element we want to modify with a dummy. We can
|
||||||
// then freely modify the type we moved out, and the `to_instantiate_bitvec` mask
|
// then freely modify the type we moved out, and the `to_instantiate_bitvec` mask
|
||||||
// prevents our dummy from being used.
|
// prevents our dummy from being used.
|
||||||
let alias_region = aliases[index].region;
|
|
||||||
|
let alias_region = alias.region;
|
||||||
let mut alias_type = Type::EmptyRec;
|
let mut alias_type = Type::EmptyRec;
|
||||||
|
|
||||||
std::mem::swap(&mut alias_type, &mut aliases[index].typ);
|
std::mem::swap(&mut alias_type, &mut alias.typ);
|
||||||
|
|
||||||
let can_instantiate_symbol = |s| match symbols_introduced.iter().position(|i| *i == s) {
|
let can_instantiate_symbol = |s| match symbols_introduced.iter().position(|i| *i == s) {
|
||||||
Some(s_index) if to_instantiate_bitvec[s_index] => {
|
Some(s_index) if to_instantiate_bitvec[s_index] => aliases.get(s_index),
|
||||||
uninstantiated_aliases.get(s_index)
|
|
||||||
}
|
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1787,14 +1801,20 @@ fn correct_mutual_recursive_type_alias<'a>(
|
||||||
&mut new_lambda_sets,
|
&mut new_lambda_sets,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let alias = if cycle.count_ones() > 1 {
|
||||||
|
&mut scratchpad.last_mut().unwrap().1
|
||||||
|
} else {
|
||||||
|
&mut aliases[index]
|
||||||
|
};
|
||||||
|
|
||||||
// swap the type back
|
// swap the type back
|
||||||
std::mem::swap(&mut alias_type, &mut aliases[index].typ);
|
std::mem::swap(&mut alias_type, &mut alias.typ);
|
||||||
|
|
||||||
// We can instantiate this alias in future iterations
|
// We can instantiate this alias in future iterations
|
||||||
to_instantiate_bitvec.set(index, true);
|
to_instantiate_bitvec.set(index, true);
|
||||||
|
|
||||||
// add any lambda sets that the instantiation created to the current alias
|
// add any lambda sets that the instantiation created to the current alias
|
||||||
aliases[index].lambda_set_variables.extend(
|
alias.lambda_set_variables.extend(
|
||||||
new_lambda_sets
|
new_lambda_sets
|
||||||
.iter()
|
.iter()
|
||||||
.map(|var| LambdaSet(Type::Variable(*var))),
|
.map(|var| LambdaSet(Type::Variable(*var))),
|
||||||
|
@ -1809,7 +1829,7 @@ fn correct_mutual_recursive_type_alias<'a>(
|
||||||
let _made_recursive = make_tag_union_of_alias_recursive(
|
let _made_recursive = make_tag_union_of_alias_recursive(
|
||||||
env,
|
env,
|
||||||
rec,
|
rec,
|
||||||
&mut aliases[index],
|
alias,
|
||||||
vec![],
|
vec![],
|
||||||
var_store,
|
var_store,
|
||||||
&mut can_still_report_error,
|
&mut can_still_report_error,
|
||||||
|
@ -1817,6 +1837,10 @@ fn correct_mutual_recursive_type_alias<'a>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (index, alias) in scratchpad.drain(..) {
|
||||||
|
aliases[index] = alias;
|
||||||
|
}
|
||||||
|
|
||||||
// The cycle we just instantiated and marked recursive may still be an illegal cycle, if
|
// The cycle we just instantiated and marked recursive may still be an illegal cycle, if
|
||||||
// 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.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue