mirror of
https://github.com/roc-lang/roc.git
synced 2025-08-02 11:22:19 +00:00
Correct emplace variables in type indices during translation
Prior to this commit, we emplace type variables into `Index<TypeTag>` only for translated top-level types. However, we need to be careful to do this emplacement for nested types as well! This patch ensures we do, but immediately emplacing the destination variable of a type when we allocate a variable for it.
This commit is contained in:
parent
2cba520839
commit
0a9a20a53c
1 changed files with 46 additions and 25 deletions
|
@ -2232,10 +2232,14 @@ fn either_type_index_to_var(
|
||||||
aliases,
|
aliases,
|
||||||
type_index,
|
type_index,
|
||||||
);
|
);
|
||||||
unsafe {
|
|
||||||
types.emplace_variable(type_index, var);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
debug_assert!(
|
||||||
|
matches!(types[type_index], TypeTag::Variable(v) if v == var)
|
||||||
|
|| matches!(
|
||||||
|
types[type_index],
|
||||||
|
TypeTag::EmptyRecord | TypeTag::EmptyTagUnion
|
||||||
|
)
|
||||||
|
);
|
||||||
var
|
var
|
||||||
}
|
}
|
||||||
Err(var_index) => {
|
Err(var_index) => {
|
||||||
|
@ -2311,14 +2315,18 @@ impl RegisterVariable {
|
||||||
| TypeTag::HostExposedAlias { shared, .. } => {
|
| TypeTag::HostExposedAlias { shared, .. } => {
|
||||||
let AliasShared { symbol, .. } = types[shared];
|
let AliasShared { symbol, .. } = types[shared];
|
||||||
if let Some(reserved) = Variable::get_reserved(symbol) {
|
if let Some(reserved) = Variable::get_reserved(symbol) {
|
||||||
if rank.is_none() {
|
let direct_var = if rank.is_none() {
|
||||||
// reserved variables are stored with rank NONE
|
// reserved variables are stored with rank NONE
|
||||||
return Direct(reserved);
|
reserved
|
||||||
} else {
|
} else {
|
||||||
// for any other rank, we need to copy; it takes care of adjusting the rank
|
// for any other rank, we need to copy; it takes care of adjusting the rank
|
||||||
let copied = deep_copy_var_in(subs, rank, pools, reserved, arena);
|
let copied = deep_copy_var_in(subs, rank, pools, reserved, arena);
|
||||||
return Direct(copied);
|
copied
|
||||||
}
|
};
|
||||||
|
// Safety: the `destination` will become the source-of-truth for the type index, since it
|
||||||
|
// was not already transformed before (if it was, we'd be in the Variable branch!)
|
||||||
|
let _old_typ = unsafe { types.emplace_variable(typ, direct_var) };
|
||||||
|
return Direct(direct_var);
|
||||||
}
|
}
|
||||||
|
|
||||||
Deferred
|
Deferred
|
||||||
|
@ -2334,15 +2342,19 @@ impl RegisterVariable {
|
||||||
pools: &mut Pools,
|
pools: &mut Pools,
|
||||||
arena: &'_ bumpalo::Bump,
|
arena: &'_ bumpalo::Bump,
|
||||||
types: &mut Types,
|
types: &mut Types,
|
||||||
typ: Index<TypeTag>,
|
typ_index: Index<TypeTag>,
|
||||||
stack: &mut bumpalo::collections::Vec<'_, TypeToVar>,
|
stack: &mut bumpalo::collections::Vec<'_, TypeToVar>,
|
||||||
) -> Variable {
|
) -> Variable {
|
||||||
match Self::from_type(subs, rank, pools, arena, types, typ) {
|
match Self::from_type(subs, rank, pools, arena, types, typ_index) {
|
||||||
Self::Direct(var) => var,
|
Self::Direct(var) => var,
|
||||||
Self::Deferred => {
|
Self::Deferred => {
|
||||||
let var = subs.fresh_unnamed_flex_var();
|
let var = subs.fresh_unnamed_flex_var();
|
||||||
|
// Safety: the `destination` will become the source-of-truth for the type index, since it
|
||||||
|
// was not already transformed before (if it was, it wouldn't be deferred!)
|
||||||
|
let typ = unsafe { types.emplace_variable(typ_index, var) };
|
||||||
stack.push(TypeToVar::Defer {
|
stack.push(TypeToVar::Defer {
|
||||||
typ,
|
typ,
|
||||||
|
typ_index,
|
||||||
destination: var,
|
destination: var,
|
||||||
ambient_function: AmbientFunctionPolicy::NoFunction,
|
ambient_function: AmbientFunctionPolicy::NoFunction,
|
||||||
});
|
});
|
||||||
|
@ -2405,7 +2417,8 @@ impl AmbientFunctionPolicy {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
enum TypeToVar {
|
enum TypeToVar {
|
||||||
Defer {
|
Defer {
|
||||||
typ: Index<TypeTag>,
|
typ: TypeTag,
|
||||||
|
typ_index: Index<TypeTag>,
|
||||||
destination: Variable,
|
destination: Variable,
|
||||||
ambient_function: AmbientFunctionPolicy,
|
ambient_function: AmbientFunctionPolicy,
|
||||||
},
|
},
|
||||||
|
@ -2443,11 +2456,18 @@ fn type_to_variable<'a>(
|
||||||
}
|
}
|
||||||
RegisterVariable::Deferred => {
|
RegisterVariable::Deferred => {
|
||||||
let var = subs.fresh_unnamed_flex_var();
|
let var = subs.fresh_unnamed_flex_var();
|
||||||
|
|
||||||
|
// Safety: the `destination` will become the source-of-truth for the type index, since it
|
||||||
|
// was not already transformed before (if it was, it wouldn't be deferred!)
|
||||||
|
let typ = unsafe { types.emplace_variable($typ, var) };
|
||||||
|
|
||||||
stack.push(TypeToVar::Defer {
|
stack.push(TypeToVar::Defer {
|
||||||
typ: $typ,
|
typ: typ,
|
||||||
|
typ_index: $typ,
|
||||||
destination: var,
|
destination: var,
|
||||||
ambient_function: $ambient_function_policy,
|
ambient_function: $ambient_function_policy,
|
||||||
});
|
});
|
||||||
|
|
||||||
var
|
var
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2460,15 +2480,16 @@ fn type_to_variable<'a>(
|
||||||
let result = helper!(typ);
|
let result = helper!(typ);
|
||||||
|
|
||||||
while let Some(TypeToVar::Defer {
|
while let Some(TypeToVar::Defer {
|
||||||
|
typ_index,
|
||||||
typ,
|
typ,
|
||||||
destination,
|
destination,
|
||||||
ambient_function,
|
ambient_function,
|
||||||
}) = stack.pop()
|
}) = stack.pop()
|
||||||
{
|
{
|
||||||
use TypeTag::*;
|
use TypeTag::*;
|
||||||
match types[typ] {
|
match typ {
|
||||||
Variable(_) | EmptyRecord | EmptyTagUnion => {
|
Variable(_) | EmptyRecord | EmptyTagUnion => {
|
||||||
unreachable!("This variant should never be deferred!")
|
unreachable!("This variant should never be deferred!",)
|
||||||
}
|
}
|
||||||
RangedNumber(range) => {
|
RangedNumber(range) => {
|
||||||
let content = Content::RangedNumber(range);
|
let content = Content::RangedNumber(range);
|
||||||
|
@ -2480,7 +2501,7 @@ fn type_to_variable<'a>(
|
||||||
type_argument_regions: _,
|
type_argument_regions: _,
|
||||||
region: _,
|
region: _,
|
||||||
} => {
|
} => {
|
||||||
let arguments = types.get_type_arguments(typ);
|
let arguments = types.get_type_arguments(typ_index);
|
||||||
let new_arguments = VariableSubsSlice::reserve_into_subs(subs, arguments.len());
|
let new_arguments = VariableSubsSlice::reserve_into_subs(subs, arguments.len());
|
||||||
for (target_index, var_index) in
|
for (target_index, var_index) in
|
||||||
(new_arguments.indices()).zip(arguments.into_iter())
|
(new_arguments.indices()).zip(arguments.into_iter())
|
||||||
|
@ -2499,7 +2520,7 @@ fn type_to_variable<'a>(
|
||||||
name,
|
name,
|
||||||
ambient_function,
|
ambient_function,
|
||||||
} => {
|
} => {
|
||||||
let captures = types.get_type_arguments(typ);
|
let captures = types.get_type_arguments(typ_index);
|
||||||
let union_lambdas = create_union_lambda(
|
let union_lambdas = create_union_lambda(
|
||||||
subs, rank, pools, arena, types, name, captures, &mut stack,
|
subs, rank, pools, arena, types, name, captures, &mut stack,
|
||||||
);
|
);
|
||||||
|
@ -2546,7 +2567,7 @@ fn type_to_variable<'a>(
|
||||||
}
|
}
|
||||||
// This case is important for the rank of boolean variables
|
// This case is important for the rank of boolean variables
|
||||||
Function(closure_type, ret_type) => {
|
Function(closure_type, ret_type) => {
|
||||||
let arguments = types.get_type_arguments(typ);
|
let arguments = types.get_type_arguments(typ_index);
|
||||||
let new_arguments = VariableSubsSlice::reserve_into_subs(subs, arguments.len());
|
let new_arguments = VariableSubsSlice::reserve_into_subs(subs, arguments.len());
|
||||||
for (target_index, var_index) in
|
for (target_index, var_index) in
|
||||||
(new_arguments.indices()).zip(arguments.into_iter())
|
(new_arguments.indices()).zip(arguments.into_iter())
|
||||||
|
@ -2564,7 +2585,7 @@ fn type_to_variable<'a>(
|
||||||
register_with_known_var(subs, destination, rank, pools, content)
|
register_with_known_var(subs, destination, rank, pools, content)
|
||||||
}
|
}
|
||||||
Record(fields) => {
|
Record(fields) => {
|
||||||
let ext_slice = types.get_type_arguments(typ);
|
let ext_slice = types.get_type_arguments(typ_index);
|
||||||
|
|
||||||
// An empty fields is inefficient (but would be correct)
|
// An empty fields is inefficient (but would be correct)
|
||||||
// If hit, try to turn the value into an EmptyRecord in canonicalization
|
// If hit, try to turn the value into an EmptyRecord in canonicalization
|
||||||
|
@ -2611,7 +2632,7 @@ fn type_to_variable<'a>(
|
||||||
}
|
}
|
||||||
|
|
||||||
TagUnion(tags) => {
|
TagUnion(tags) => {
|
||||||
let ext_slice = types.get_type_arguments(typ);
|
let ext_slice = types.get_type_arguments(typ_index);
|
||||||
|
|
||||||
// An empty tags is inefficient (but would be correct)
|
// An empty tags is inefficient (but would be correct)
|
||||||
// If hit, try to turn the value into an EmptyTagUnion in canonicalization
|
// If hit, try to turn the value into an EmptyTagUnion in canonicalization
|
||||||
|
@ -2625,8 +2646,8 @@ fn type_to_variable<'a>(
|
||||||
register_with_known_var(subs, destination, rank, pools, content)
|
register_with_known_var(subs, destination, rank, pools, content)
|
||||||
}
|
}
|
||||||
FunctionOrTagUnion(symbol) => {
|
FunctionOrTagUnion(symbol) => {
|
||||||
let ext_slice = types.get_type_arguments(typ);
|
let ext_slice = types.get_type_arguments(typ_index);
|
||||||
let tag_name = types.get_tag_name(&typ).clone();
|
let tag_name = types.get_tag_name(&typ_index).clone();
|
||||||
|
|
||||||
debug_assert!(ext_slice.len() <= 1);
|
debug_assert!(ext_slice.len() <= 1);
|
||||||
let temp_ext_var = match ext_slice.into_iter().next() {
|
let temp_ext_var = match ext_slice.into_iter().next() {
|
||||||
|
@ -2654,7 +2675,7 @@ fn type_to_variable<'a>(
|
||||||
register_with_known_var(subs, destination, rank, pools, content)
|
register_with_known_var(subs, destination, rank, pools, content)
|
||||||
}
|
}
|
||||||
RecursiveTagUnion(rec_var, tags) => {
|
RecursiveTagUnion(rec_var, tags) => {
|
||||||
let ext_slice = types.get_type_arguments(typ);
|
let ext_slice = types.get_type_arguments(typ_index);
|
||||||
|
|
||||||
// An empty tags is inefficient (but would be correct)
|
// An empty tags is inefficient (but would be correct)
|
||||||
// If hit, try to turn the value into an EmptyTagUnion in canonicalization
|
// If hit, try to turn the value into an EmptyTagUnion in canonicalization
|
||||||
|
@ -2692,7 +2713,7 @@ fn type_to_variable<'a>(
|
||||||
infer_ext_in_output_variables,
|
infer_ext_in_output_variables,
|
||||||
} = types[shared];
|
} = types[shared];
|
||||||
|
|
||||||
let type_arguments = types.get_type_arguments(typ);
|
let type_arguments = types.get_type_arguments(typ_index);
|
||||||
|
|
||||||
let alias_variables = {
|
let alias_variables = {
|
||||||
let all_vars_length = type_arguments.len()
|
let all_vars_length = type_arguments.len()
|
||||||
|
@ -2773,7 +2794,7 @@ fn type_to_variable<'a>(
|
||||||
}
|
}
|
||||||
|
|
||||||
StructuralAlias { shared, actual } | OpaqueAlias { shared, actual } => {
|
StructuralAlias { shared, actual } | OpaqueAlias { shared, actual } => {
|
||||||
let kind = match types[typ] {
|
let kind = match typ {
|
||||||
StructuralAlias { .. } => AliasKind::Structural,
|
StructuralAlias { .. } => AliasKind::Structural,
|
||||||
OpaqueAlias { .. } => AliasKind::Opaque,
|
OpaqueAlias { .. } => AliasKind::Opaque,
|
||||||
_ => internal_error!(),
|
_ => internal_error!(),
|
||||||
|
@ -2789,7 +2810,7 @@ fn type_to_variable<'a>(
|
||||||
|
|
||||||
debug_assert!(roc_types::subs::Variable::get_reserved(symbol).is_none());
|
debug_assert!(roc_types::subs::Variable::get_reserved(symbol).is_none());
|
||||||
|
|
||||||
let type_arguments = types.get_type_arguments(typ);
|
let type_arguments = types.get_type_arguments(typ_index);
|
||||||
|
|
||||||
let alias_variables = {
|
let alias_variables = {
|
||||||
let all_vars_length = type_arguments.len()
|
let all_vars_length = type_arguments.len()
|
||||||
|
@ -2860,7 +2881,7 @@ fn type_to_variable<'a>(
|
||||||
infer_ext_in_output_variables: _, // TODO
|
infer_ext_in_output_variables: _, // TODO
|
||||||
} = types[shared];
|
} = types[shared];
|
||||||
|
|
||||||
let type_arguments = types.get_type_arguments(typ);
|
let type_arguments = types.get_type_arguments(typ_index);
|
||||||
|
|
||||||
let alias_variables = {
|
let alias_variables = {
|
||||||
let length = type_arguments.len() + lambda_set_variables.len();
|
let length = type_arguments.len() + lambda_set_variables.len();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue