diff --git a/compiler/solve/src/solve.rs b/compiler/solve/src/solve.rs index 54a3c96062..aaa918c287 100644 --- a/compiler/solve/src/solve.rs +++ b/compiler/solve/src/solve.rs @@ -1259,122 +1259,100 @@ pub fn instantiate_rigids(subs: &mut Subs, var: Variable) { subs.restore(var); } -fn instantiate_rigids_help(subs: &mut Subs, max_rank: Rank, var: Variable) { - use roc_types::subs::Content::*; - use roc_types::subs::FlatType::*; +fn instantiate_rigids_help(subs: &mut Subs, max_rank: Rank, initial: Variable) { + let mut stack = vec![initial]; - let desc = subs.get_without_compacting(var); - - if desc.copy.is_some() { - return; + macro_rules! var_slice { + ($variable_subs_slice:expr) => {{ + &subs.variables[$variable_subs_slice.slice.start as usize..] + [..$variable_subs_slice.slice.length as usize] + }}; } - // 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. - subs.set( - var, - Descriptor { - content: desc.content.clone(), - rank: desc.rank, - mark: Mark::NONE, - copy: var.into(), - }, - ); + while let Some(var) = stack.pop() { + if subs.get_ref(var).copy.is_some() { + continue; + } - // 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 desc.content { - Structure(flat_type) => { - match flat_type { + subs.modify(var, |desc| { + desc.rank = Rank::NONE; + desc.mark = Mark::NONE; + desc.copy = OptVariable::from(var); + }); + + 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) => { - for var_index in args.into_iter() { - let var = subs[var_index]; - instantiate_rigids_help(subs, max_rank, var); - } + stack.extend(var_slice!(*args)); } Func(arg_vars, closure_var, ret_var) => { - instantiate_rigids_help(subs, max_rank, ret_var); - instantiate_rigids_help(subs, max_rank, closure_var); + stack.extend(var_slice!(*arg_vars)); - for index in arg_vars.into_iter() { - let var = subs[index]; - instantiate_rigids_help(subs, max_rank, var); - } + stack.push(*ret_var); + stack.push(*closure_var); } - EmptyRecord | EmptyTagUnion | Erroneous(_) => {} + EmptyRecord => (), + EmptyTagUnion => (), Record(fields, ext_var) => { - for index in fields.iter_variables() { - let var = subs[index]; - instantiate_rigids_help(subs, max_rank, var); - } + stack.extend(var_slice!(fields.variables())); - instantiate_rigids_help(subs, max_rank, ext_var); + stack.push(*ext_var); } - TagUnion(tags, ext_var) => { - for (_, index) in tags.iter_all() { - let slice = subs[index]; - for var_index in slice { - let var = subs[var_index]; - instantiate_rigids_help(subs, max_rank, var); - } + for slice_index in tags.variables() { + let slice = subs.variable_slices[slice_index.start as usize]; + stack.extend(var_slice!(slice)); } - instantiate_rigids_help(subs, max_rank, ext_var); + stack.push(*ext_var); } - - FunctionOrTagUnion(_tag_name, _symbol, ext_var) => { - instantiate_rigids_help(subs, max_rank, ext_var); + FunctionOrTagUnion(_, _, ext_var) => { + stack.push(*ext_var); } RecursiveTagUnion(rec_var, tags, ext_var) => { - instantiate_rigids_help(subs, max_rank, rec_var); - - for (_, index) in tags.iter_all() { - let slice = subs[index]; - for var_index in slice { - let var = subs[var_index]; - instantiate_rigids_help(subs, max_rank, var); - } + for slice_index in tags.variables() { + let slice = subs.variable_slices[slice_index.start as usize]; + stack.extend(var_slice!(slice)); } - 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, .. } => { - 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); + stack.push(*var); } - - instantiate_rigids_help(subs, max_rank, real_type_var); } } } diff --git a/compiler/types/src/subs.rs b/compiler/types/src/subs.rs index d8f9efcc1b..7cbb2c8e1f 100644 --- a/compiler/types/src/subs.rs +++ b/compiler/types/src/subs.rs @@ -79,7 +79,7 @@ pub struct SubsSlice { /// An index into the Vec of subs pub struct SubsIndex { - start: u32, + pub start: u32, _marker: std::marker::PhantomData, } @@ -1525,7 +1525,7 @@ pub enum Builtin { #[derive(Clone, Copy, Debug, Default)] pub struct VariableSubsSlice { - slice: SubsSlice, + pub slice: SubsSlice, } 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); VariableSubsSlice { slice }