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:
Ayaz Hafiz 2022-11-15 14:21:42 -06:00
parent 2cba520839
commit 0a9a20a53c
No known key found for this signature in database
GPG key ID: 0E2A37416A25EF58

View file

@ -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();