diff --git a/ast/src/solve_type.rs b/ast/src/solve_type.rs index 5d03f3a2f8..dc2e53f3a8 100644 --- a/ast/src/solve_type.rs +++ b/ast/src/solve_type.rs @@ -1390,7 +1390,7 @@ fn adjust_rank_content( Alias(_, args, real_var, _) => { let mut rank = Rank::toplevel(); - for var_index in args.variables() { + for var_index in args.all_variables() { let var = subs[var_index]; rank = rank.max(adjust_rank(subs, young_mark, visit_mark, group_rank, var)); } @@ -1548,7 +1548,7 @@ fn instantiate_rigids_help( } Alias(_, args, real_type_var, _) => { - for var_index in args.variables() { + for var_index in args.all_variables() { let var = subs[var_index]; instantiate_rigids_help(subs, max_rank, pools, var); } @@ -1798,9 +1798,9 @@ fn deep_copy_var_help( } Alias(symbol, mut args, real_type_var, kind) => { - let mut new_args = Vec::with_capacity(args.variables().len()); + let mut new_args = Vec::with_capacity(args.all_variables().len()); - for var_index in args.variables() { + for var_index in args.all_variables() { let var = subs[var_index]; let new_var = deep_copy_var_help(subs, max_rank, pools, var); new_args.push(new_var); diff --git a/compiler/mono/src/ir.rs b/compiler/mono/src/ir.rs index b53bbee924..d2199b32e3 100644 --- a/compiler/mono/src/ir.rs +++ b/compiler/mono/src/ir.rs @@ -8446,7 +8446,7 @@ pub fn num_argument_to_int_or_float( debug_assert!(args.len() == 1); // Recurse on the second argument - let var = subs[args.variables().into_iter().next().unwrap()]; + let var = subs[args.all_variables().into_iter().next().unwrap()]; num_argument_to_int_or_float(subs, target_info, var, false) } @@ -8464,7 +8464,7 @@ pub fn num_argument_to_int_or_float( debug_assert!(args.len() == 1); // Recurse on the second argument - let var = subs[args.variables().into_iter().next().unwrap()]; + let var = subs[args.all_variables().into_iter().next().unwrap()]; num_argument_to_int_or_float(subs, target_info, var, true) } diff --git a/compiler/mono/src/layout.rs b/compiler/mono/src/layout.rs index 5cee9a52a6..ab3524af7d 100644 --- a/compiler/mono/src/layout.rs +++ b/compiler/mono/src/layout.rs @@ -2670,7 +2670,7 @@ fn unwrap_num_tag<'a>( Content::Alias(Symbol::NUM_INTEGER, args, _, _) => { debug_assert!(args.len() == 1); - let precision_var = subs[args.variables().into_iter().next().unwrap()]; + let precision_var = subs[args.all_variables().into_iter().next().unwrap()]; let precision = subs.get_content_without_compacting(precision_var); @@ -2706,7 +2706,7 @@ fn unwrap_num_tag<'a>( Content::Alias(Symbol::NUM_FLOATINGPOINT, args, _, _) => { debug_assert!(args.len() == 1); - let precision_var = subs[args.variables().into_iter().next().unwrap()]; + let precision_var = subs[args.all_variables().into_iter().next().unwrap()]; let precision = subs.get_content_without_compacting(precision_var); diff --git a/compiler/solve/src/solve.rs b/compiler/solve/src/solve.rs index ab3bfdb702..f90888e8cd 100644 --- a/compiler/solve/src/solve.rs +++ b/compiler/solve/src/solve.rs @@ -78,27 +78,142 @@ pub enum TypeError { use roc_types::types::Alias; +#[derive(Debug, Clone, Copy)] +struct DelayedAliasVariables { + start: u32, + type_variables_len: u8, + lambda_set_variables_len: u8, + recursion_variables_len: u8, +} + +impl DelayedAliasVariables { + fn recursion_variables(self, variables: &mut [Variable]) -> &mut [Variable] { + let start = self.start as usize + + (self.type_variables_len + self.lambda_set_variables_len) as usize; + let length = self.recursion_variables_len as usize; + + &mut variables[start..][..length] + } + + fn lambda_set_variables(self, variables: &mut [Variable]) -> &mut [Variable] { + let start = self.start as usize + self.type_variables_len as usize; + let length = self.lambda_set_variables_len as usize; + + &mut variables[start..][..length] + } + + fn type_variables(self, variables: &mut [Variable]) -> &mut [Variable] { + let start = self.start as usize; + let length = self.type_variables_len as usize; + + &mut variables[start..][..length] + } +} + #[derive(Debug, Default)] pub struct Aliases { - aliases: MutMap, + aliases: Vec<(Symbol, Type, DelayedAliasVariables)>, + variables: Vec, } impl Aliases { - fn instantiate_alias( - &self, + pub fn insert(&mut self, symbol: Symbol, alias: Alias) { + // debug_assert!(self.get(&symbol).is_none()); + + let alias_variables = + { + let start = self.variables.len() as _; + + self.variables + .extend(alias.type_variables.iter().map(|x| x.value.1)); + + self.variables.extend(alias.lambda_set_variables.iter().map( + |x| match x.as_inner() { + Type::Variable(v) => *v, + _ => unreachable!("lambda set type is not a variable"), + }, + )); + + let recursion_variables_len = alias.recursion_variables.len() as _; + self.variables.extend(alias.recursion_variables); + + DelayedAliasVariables { + start, + type_variables_len: alias.type_variables.len() as _, + lambda_set_variables_len: alias.lambda_set_variables.len() as _, + recursion_variables_len, + } + }; + + self.aliases.push((symbol, alias.typ, alias_variables)); + } + + fn instantiate( + &mut self, subs: &mut Subs, rank: Rank, pools: &mut Pools, - arena: &bumpalo::Bump, + _arena: &bumpalo::Bump, symbol: Symbol, alias_variables: AliasVariables, ) -> Result { - match self.aliases.get(&symbol) { - None => Err(()), - Some(alias) => { - todo!() + let (typ, delayed_variables) = match self.aliases.iter_mut().find(|(s, _, _)| *s == symbol) + { + None => return Err(()), + Some((_, typ, delayed_variables)) => (typ, delayed_variables), + }; + + let mut substitutions: MutMap<_, _> = Default::default(); + + for rec_var in delayed_variables + .recursion_variables(&mut self.variables) + .iter_mut() + { + let new_var = subs.fresh_unnamed_flex_var(); + substitutions.insert(*rec_var, new_var); + *rec_var = new_var; + } + + let old_type_variables = delayed_variables.type_variables(&mut self.variables); + let new_type_variables = &subs.variables[alias_variables.type_variables().indices()]; + + for (old, new) in old_type_variables.iter_mut().zip(new_type_variables) { + substitutions.insert(*old, *new); + *old = *new; + } + + let old_lambda_set_variables = delayed_variables.lambda_set_variables(&mut self.variables); + let new_lambda_set_variables = + &subs.variables[alias_variables.lambda_set_variables().indices()]; + + for (old, new) in old_lambda_set_variables + .iter_mut() + .zip(new_lambda_set_variables) + { + substitutions.insert(*old, *new); + *old = *new; + } + + typ.substitute_variables(&substitutions); + + // assumption: an alias does not (transitively) syntactically contain itself + // (if it did it would have to be a recursive tag union) + let mut t = Type::EmptyRec; + + std::mem::swap(typ, &mut t); + + let alias_variable = type_to_var(subs, rank, pools, self, &t); + + { + match self.aliases.iter_mut().find(|(s, _, _)| *s == symbol) { + None => unreachable!(), + Some((_, typ, _)) => { + std::mem::swap(typ, &mut t); + } } } + + Ok(alias_variable) } } @@ -932,7 +1047,7 @@ fn type_to_var( subs: &mut Subs, rank: Rank, pools: &mut Pools, - aliases: &Aliases, + aliases: &mut Aliases, typ: &Type, ) -> Variable { if let Type::Variable(var) = typ { @@ -1020,7 +1135,7 @@ fn type_to_variable<'a>( rank: Rank, pools: &mut Pools, arena: &'a bumpalo::Bump, - aliases: &Aliases, + aliases: &mut Aliases, typ: &Type, ) -> Variable { use bumpalo::collections::Vec; @@ -1226,7 +1341,7 @@ fn type_to_variable<'a>( }; let instantiated = - aliases.instantiate_alias(subs, rank, pools, arena, *symbol, alias_variables); + aliases.instantiate(subs, rank, pools, arena, *symbol, alias_variables); let alias_variable = match instantiated { Err(_) => panic!("Alias {:?} is not available", symbol), @@ -1943,7 +2058,7 @@ fn adjust_rank_content( Alias(_, args, real_var, _) => { let mut rank = Rank::toplevel(); - for var_index in args.variables() { + for var_index in args.all_variables() { let var = subs[var_index]; rank = rank.max(adjust_rank(subs, young_mark, visit_mark, group_rank, var)); } @@ -2089,7 +2204,7 @@ fn instantiate_rigids_help(subs: &mut Subs, max_rank: Rank, initial: Variable) { let var = *var; let args = *args; - stack.extend(var_slice!(args.variables())); + stack.extend(var_slice!(args.all_variables())); stack.push(var); } @@ -2338,7 +2453,9 @@ fn deep_copy_var_help( Alias(symbol, arguments, real_type_var, kind) => { let new_variables = SubsSlice::reserve_into_subs(subs, arguments.all_variables_len as _); - for (target_index, var_index) in (new_variables.indices()).zip(arguments.variables()) { + for (target_index, var_index) in + (new_variables.indices()).zip(arguments.all_variables()) + { let var = subs[var_index]; let copy_var = deep_copy_var_help(subs, max_rank, pools, visited, var); subs.variables[target_index] = copy_var; diff --git a/compiler/types/src/subs.rs b/compiler/types/src/subs.rs index 1ce8a9eed9..15ab1586d1 100644 --- a/compiler/types/src/subs.rs +++ b/compiler/types/src/subs.rs @@ -427,7 +427,7 @@ fn subs_fmt_content(this: &Content, subs: &Subs, f: &mut fmt::Formatter) -> fmt: } => write!(f, "Recursion({:?}, {:?})", structure, opt_name), Content::Structure(flat_type) => subs_fmt_flat_type(flat_type, subs, f), Content::Alias(name, arguments, actual, kind) => { - let slice = subs.get_subs_slice(arguments.variables()); + let slice = subs.get_subs_slice(arguments.all_variables()); let wrap = match kind { AliasKind::Structural => "Alias", AliasKind::Opaque => "Opaque", @@ -1775,10 +1775,21 @@ pub struct AliasVariables { } impl AliasVariables { - pub const fn variables(&self) -> VariableSubsSlice { + pub const fn all_variables(&self) -> VariableSubsSlice { SubsSlice::new(self.variables_start, self.all_variables_len) } + pub const fn type_variables(&self) -> VariableSubsSlice { + SubsSlice::new(self.variables_start, self.type_variables_len) + } + + pub const fn lambda_set_variables(&self) -> VariableSubsSlice { + SubsSlice::new( + self.variables_start + self.type_variables_len as u32, + self.all_variables_len - self.type_variables_len, + ) + } + pub const fn len(&self) -> usize { self.type_variables_len as usize } @@ -1802,13 +1813,13 @@ impl AliasVariables { } pub fn named_type_arguments(&self) -> impl Iterator> { - self.variables() + self.all_variables() .into_iter() .take(self.type_variables_len as usize) } pub fn unnamed_type_arguments(&self) -> impl Iterator> { - self.variables() + self.all_variables() .into_iter() .skip(self.type_variables_len as usize) } @@ -1850,7 +1861,7 @@ impl IntoIterator for AliasVariables { type IntoIter = ::IntoIter; fn into_iter(self) -> Self::IntoIter { - self.variables().into_iter() + self.all_variables().into_iter() } } @@ -3298,7 +3309,7 @@ fn restore_help(subs: &mut Subs, initial: Variable) { Erroneous(_) => (), }, Alias(_, args, var, _) => { - stack.extend(var_slice(args.variables())); + stack.extend(var_slice(args.all_variables())); stack.push(*var); } @@ -3333,6 +3344,14 @@ impl StorageSubs { Self { subs } } + pub fn fresh_unnamed_flex_var(&mut self) -> Variable { + self.subs.fresh_unnamed_flex_var() + } + + pub fn as_inner_mut(&mut self) -> &mut Subs { + &mut self.subs + } + pub fn extend_with_variable(&mut self, source: &mut Subs, variable: Variable) -> Variable { deep_copy_var_to(source, &mut self.subs, variable) } @@ -3867,7 +3886,9 @@ fn deep_copy_var_to_help<'a>(env: &mut DeepCopyVarToEnv<'a>, var: Variable) -> V Alias(symbol, arguments, real_type_var, kind) => { let new_variables = SubsSlice::reserve_into_subs(env.target, arguments.all_variables_len as _); - for (target_index, var_index) in (new_variables.indices()).zip(arguments.variables()) { + for (target_index, var_index) in + (new_variables.indices()).zip(arguments.all_variables()) + { let var = env.source[var_index]; let copy_var = deep_copy_var_to_help(env, var); env.target.variables[target_index] = copy_var; @@ -4284,7 +4305,9 @@ fn copy_import_to_help(env: &mut CopyImportEnv<'_>, max_rank: Rank, var: Variabl Alias(symbol, arguments, real_type_var, kind) => { let new_variables = SubsSlice::reserve_into_subs(env.target, arguments.all_variables_len as _); - for (target_index, var_index) in (new_variables.indices()).zip(arguments.variables()) { + for (target_index, var_index) in + (new_variables.indices()).zip(arguments.all_variables()) + { let var = env.source[var_index]; let copy_var = copy_import_to_help(env, max_rank, var); env.target.variables[target_index] = copy_var; @@ -4389,7 +4412,7 @@ where Erroneous(_) | EmptyRecord | EmptyTagUnion => {} }, Alias(_, arguments, real_type_var, _) => { - push_var_slice!(arguments.variables()); + push_var_slice!(arguments.all_variables()); stack.push(*real_type_var); } RangedNumber(typ, vars) => { diff --git a/compiler/types/src/types.rs b/compiler/types/src/types.rs index fa39d6eaf9..76530c0ff6 100644 --- a/compiler/types/src/types.rs +++ b/compiler/types/src/types.rs @@ -160,8 +160,8 @@ impl RecordField { pub struct LambdaSet(pub Type); impl LambdaSet { - fn substitute(&mut self, substitutions: &ImMap) { - self.0.substitute(substitutions); + pub fn as_inner(&self) -> &Type { + &self.0 } fn as_inner_mut(&mut self) -> &mut Type { diff --git a/compiler/unify/src/unify.rs b/compiler/unify/src/unify.rs index 133429b94c..bfa36d4293 100644 --- a/compiler/unify/src/unify.rs +++ b/compiler/unify/src/unify.rs @@ -322,9 +322,9 @@ fn unify_alias( if args.len() == other_args.len() { let mut problems = Vec::new(); let it = args - .variables() + .all_variables() .into_iter() - .zip(other_args.variables().into_iter()); + .zip(other_args.all_variables().into_iter()); for (l, r) in it { let l_var = subs[l];