This commit is contained in:
Folkert 2021-11-15 20:12:48 +01:00
parent 1c6fab7043
commit db081cd84b
2 changed files with 273 additions and 4 deletions

View file

@ -1381,6 +1381,265 @@ fn instantiate_rigids_help(
var
}
fn deep_copy_var_to_help(
source: &Subs,
target: &mut Subs,
max_rank: Rank,
pools: &mut Pools,
var: Variable,
) -> Variable {
use roc_types::subs::Content::*;
use roc_types::subs::FlatType::*;
let desc = source.get_without_compacting(var);
if let Some(copy) = desc.copy.into_variable() {
return copy;
} else if desc.rank != Rank::NONE {
panic!(
"about to return a variable in source, but should only return variables from target"
);
return var;
}
let make_descriptor = |content| Descriptor {
content,
rank: max_rank,
mark: Mark::NONE,
copy: OptVariable::NONE,
};
let content = desc.content;
let copy = target.fresh(make_descriptor(content.clone()));
pools.get_mut(max_rank).push(copy);
// Link the original variable to the new variable. This lets us
// avoid making multiple copies of the variable we are instantiating.
//
// Need to do this before recursively copying to avoid looping.
source.set(
var,
Descriptor {
content: content.clone(),
rank: desc.rank,
mark: Mark::NONE,
copy: copy.into(),
},
);
// Now we recursively copy the content of the variable.
// We have already marked the variable as copied, so we
// will not repeat this work or crawl this variable again.
match content {
Structure(flat_type) => {
let new_flat_type = match flat_type {
Apply(symbol, args) => {
let mut new_arg_vars = Vec::with_capacity(args.len());
for index in args.into_iter() {
let var = source[index];
let copy_var = deep_copy_var_to_help(source, target, max_rank, pools, var);
new_arg_vars.push(copy_var);
}
let arg_vars = VariableSubsSlice::insert_into_subs(target, new_arg_vars);
Apply(symbol, arg_vars)
}
Func(arg_vars, closure_var, ret_var) => {
let new_ret_var =
deep_copy_var_to_help(source, target, max_rank, pools, ret_var);
let new_closure_var =
deep_copy_var_to_help(source, target, max_rank, pools, closure_var);
let mut new_arg_vars = Vec::with_capacity(arg_vars.len());
for index in arg_vars.into_iter() {
let var = source[index];
let copy_var = deep_copy_var_to_help(source, target, max_rank, pools, var);
new_arg_vars.push(copy_var);
}
let arg_vars = VariableSubsSlice::insert_into_subs(target, new_arg_vars);
Func(arg_vars, new_closure_var, new_ret_var)
}
same @ EmptyRecord | same @ EmptyTagUnion | same @ Erroneous(_) => same,
Record(fields, ext_var) => {
let record_fields = {
let mut new_vars = Vec::with_capacity(fields.len());
for index in fields.iter_variables() {
let var = source[index];
let copy_var =
deep_copy_var_to_help(source, target, max_rank, pools, var);
new_vars.push(copy_var);
}
let field_names_start = target.field_names.len() as u32;
let variables_start = target.variables.len() as u32;
let field_types_start = target.record_fields.len() as u32;
let mut length = 0;
for ((i1, _, i3), var) in fields.iter_all().zip(new_vars) {
let record_field = source[i3].map(|_| var);
target.field_names.push(source[i1].clone());
target.record_fields.push(record_field.map(|_| ()));
target.variables.push(*record_field.as_inner());
length += 1;
}
RecordFields {
length,
field_names_start,
variables_start,
field_types_start,
}
};
Record(
record_fields,
deep_copy_var_to_help(source, target, max_rank, pools, ext_var),
)
}
TagUnion(tags, ext_var) => {
let mut new_variable_slices = Vec::with_capacity(tags.len());
let mut new_variables = Vec::new();
for index in tags.variables() {
let slice = source[index];
for var_index in slice {
let var = source[var_index];
let new_var =
deep_copy_var_to_help(source, target, max_rank, pools, var);
new_variables.push(new_var);
}
let new_slice =
VariableSubsSlice::insert_into_subs(target, new_variables.drain(..));
new_variable_slices.push(new_slice);
}
let new_variables = {
let start = target.variable_slices.len() as u32;
let length = new_variable_slices.len() as u16;
target.variable_slices.extend(new_variable_slices);
SubsSlice::new(start, length)
};
let union_tags = UnionTags::from_slices(tags.tag_names(), new_variables);
let new_ext = deep_copy_var_to_help(source, target, max_rank, pools, ext_var);
TagUnion(union_tags, new_ext)
}
FunctionOrTagUnion(tag_name, symbol, ext_var) => FunctionOrTagUnion(
tag_name,
symbol,
deep_copy_var_to_help(source, target, max_rank, pools, ext_var),
),
RecursiveTagUnion(rec_var, tags, ext_var) => {
let mut new_variable_slices = Vec::with_capacity(tags.len());
let mut new_variables = Vec::new();
for index in tags.variables() {
let slice = source[index];
for var_index in slice {
let var = source[var_index];
let new_var =
deep_copy_var_to_help(source, target, max_rank, pools, var);
new_variables.push(new_var);
}
let new_slice =
VariableSubsSlice::insert_into_subs(target, new_variables.drain(..));
new_variable_slices.push(new_slice);
}
let new_variables = {
let start = target.variable_slices.len() as u32;
let length = new_variable_slices.len() as u16;
target.variable_slices.extend(new_variable_slices);
SubsSlice::new(start, length)
};
let union_tags = UnionTags::from_slices(tags.tag_names(), new_variables);
let new_ext = deep_copy_var_to_help(source, target, max_rank, pools, ext_var);
let new_rec_var =
deep_copy_var_to_help(source, target, max_rank, pools, rec_var);
RecursiveTagUnion(new_rec_var, union_tags, new_ext)
}
};
target.set(copy, make_descriptor(Structure(new_flat_type)));
copy
}
FlexVar(_) | Error => copy,
RecursionVar {
opt_name,
structure,
} => {
let new_structure = deep_copy_var_to_help(source, target, max_rank, pools, structure);
target.set(
copy,
make_descriptor(RecursionVar {
opt_name,
structure: new_structure,
}),
);
copy
}
RigidVar(name) => {
target.set(copy, make_descriptor(FlexVar(Some(name))));
copy
}
Alias(symbol, mut args, real_type_var) => {
let mut new_vars = Vec::with_capacity(args.variables().len());
for var_index in args.variables() {
let var = source[var_index];
let new_var = deep_copy_var_to_help(source, target, max_rank, pools, var);
new_vars.push(new_var);
}
args.replace_variables(target, new_vars);
let new_real_type_var =
deep_copy_var_to_help(source, target, max_rank, pools, real_type_var);
let new_content = Alias(symbol, args, new_real_type_var);
target.set(copy, make_descriptor(new_content));
copy
}
}
}
fn deep_copy_var(subs: &mut Subs, rank: Rank, pools: &mut Pools, var: Variable) -> Variable {
let copy = deep_copy_var_help(subs, rank, pools, var);