make instantiate_rigids_help use a loop/stack

This commit is contained in:
Folkert 2021-11-20 00:24:46 +01:00
parent 991420731d
commit 497bc2db02
2 changed files with 69 additions and 91 deletions

View file

@ -1259,122 +1259,100 @@ pub fn instantiate_rigids(subs: &mut Subs, var: Variable) {
subs.restore(var); subs.restore(var);
} }
fn instantiate_rigids_help(subs: &mut Subs, max_rank: Rank, var: Variable) { fn instantiate_rigids_help(subs: &mut Subs, max_rank: Rank, initial: Variable) {
use roc_types::subs::Content::*; let mut stack = vec![initial];
use roc_types::subs::FlatType::*;
let desc = subs.get_without_compacting(var); macro_rules! var_slice {
($variable_subs_slice:expr) => {{
if desc.copy.is_some() { &subs.variables[$variable_subs_slice.slice.start as usize..]
return; [..$variable_subs_slice.slice.length as usize]
}};
} }
// Link the original variable to the new variable. This lets us while let Some(var) = stack.pop() {
// avoid making multiple copies of the variable we are instantiating. if subs.get_ref(var).copy.is_some() {
// continue;
// Need to do this before recursively copying to avoid looping. }
subs.set(
var,
Descriptor {
content: desc.content.clone(),
rank: desc.rank,
mark: Mark::NONE,
copy: var.into(),
},
);
// Now we recursively copy the content of the variable. subs.modify(var, |desc| {
// We have already marked the variable as copied, so we desc.rank = Rank::NONE;
// will not repeat this work or crawl this variable again. desc.mark = Mark::NONE;
match desc.content { desc.copy = OptVariable::from(var);
Structure(flat_type) => { });
match flat_type {
use Content::*;
use FlatType::*;
let desc = subs.get_ref(var);
match &desc.content {
RigidVar(name) => {
// what it's all about: convert the rigid var into a flex var
let name = name.clone();
subs.set(
var,
Descriptor {
content: FlexVar(Some(name)),
rank: max_rank,
mark: Mark::NONE,
copy: OptVariable::NONE,
},
);
}
FlexVar(_) | Error => (),
RecursionVar { structure, .. } => {
stack.push(*structure);
}
Structure(flat_type) => match flat_type {
Apply(_, args) => { Apply(_, args) => {
for var_index in args.into_iter() { stack.extend(var_slice!(*args));
let var = subs[var_index];
instantiate_rigids_help(subs, max_rank, var);
}
} }
Func(arg_vars, closure_var, ret_var) => { Func(arg_vars, closure_var, ret_var) => {
instantiate_rigids_help(subs, max_rank, ret_var); stack.extend(var_slice!(*arg_vars));
instantiate_rigids_help(subs, max_rank, closure_var);
for index in arg_vars.into_iter() { stack.push(*ret_var);
let var = subs[index]; stack.push(*closure_var);
instantiate_rigids_help(subs, max_rank, var);
}
} }
EmptyRecord | EmptyTagUnion | Erroneous(_) => {} EmptyRecord => (),
EmptyTagUnion => (),
Record(fields, ext_var) => { Record(fields, ext_var) => {
for index in fields.iter_variables() { stack.extend(var_slice!(fields.variables()));
let var = subs[index];
instantiate_rigids_help(subs, max_rank, var);
}
instantiate_rigids_help(subs, max_rank, ext_var); stack.push(*ext_var);
} }
TagUnion(tags, ext_var) => { TagUnion(tags, ext_var) => {
for (_, index) in tags.iter_all() { for slice_index in tags.variables() {
let slice = subs[index]; let slice = subs.variable_slices[slice_index.start as usize];
for var_index in slice { stack.extend(var_slice!(slice));
let var = subs[var_index];
instantiate_rigids_help(subs, max_rank, var);
}
} }
instantiate_rigids_help(subs, max_rank, ext_var); stack.push(*ext_var);
} }
FunctionOrTagUnion(_, _, ext_var) => {
FunctionOrTagUnion(_tag_name, _symbol, ext_var) => { stack.push(*ext_var);
instantiate_rigids_help(subs, max_rank, ext_var);
} }
RecursiveTagUnion(rec_var, tags, ext_var) => { RecursiveTagUnion(rec_var, tags, ext_var) => {
instantiate_rigids_help(subs, max_rank, rec_var); for slice_index in tags.variables() {
let slice = subs.variable_slices[slice_index.start as usize];
for (_, index) in tags.iter_all() { stack.extend(var_slice!(slice));
let slice = subs[index];
for var_index in slice {
let var = subs[var_index];
instantiate_rigids_help(subs, max_rank, var);
}
} }
instantiate_rigids_help(subs, max_rank, ext_var); stack.push(*ext_var);
stack.push(*rec_var);
} }
};
}
FlexVar(_) | Error => {} Erroneous(_) => (),
},
Alias(_, args, var) => {
stack.extend(var_slice!(args.variables()));
RecursionVar { structure, .. } => { stack.push(*var);
instantiate_rigids_help(subs, max_rank, structure);
}
RigidVar(name) => {
// what it's all about: convert the rigid var into a flex var
subs.set(
var,
Descriptor {
content: FlexVar(Some(name)),
rank: max_rank,
mark: Mark::NONE,
copy: OptVariable::NONE,
},
);
}
Alias(_symbol, args, real_type_var) => {
for var_index in args.variables().into_iter() {
let var = subs[var_index];
instantiate_rigids_help(subs, max_rank, var);
} }
instantiate_rigids_help(subs, max_rank, real_type_var);
} }
} }
} }

View file

@ -79,7 +79,7 @@ pub struct SubsSlice<T> {
/// An index into the Vec<T> of subs /// An index into the Vec<T> of subs
pub struct SubsIndex<T> { pub struct SubsIndex<T> {
start: u32, pub start: u32,
_marker: std::marker::PhantomData<T>, _marker: std::marker::PhantomData<T>,
} }
@ -1525,7 +1525,7 @@ pub enum Builtin {
#[derive(Clone, Copy, Debug, Default)] #[derive(Clone, Copy, Debug, Default)]
pub struct VariableSubsSlice { pub struct VariableSubsSlice {
slice: SubsSlice<Variable>, pub slice: SubsSlice<Variable>,
} }
impl VariableSubsSlice { impl VariableSubsSlice {
@ -1849,7 +1849,7 @@ impl RecordFields {
} }
} }
fn variables(&self) -> VariableSubsSlice { pub const fn variables(&self) -> VariableSubsSlice {
let slice = SubsSlice::new(self.variables_start, self.length); let slice = SubsSlice::new(self.variables_start, self.length);
VariableSubsSlice { slice } VariableSubsSlice { slice }