diff --git a/compiler/mono/src/layout.rs b/compiler/mono/src/layout.rs index 71ddbd8f89..5e3ef0a89a 100644 --- a/compiler/mono/src/layout.rs +++ b/compiler/mono/src/layout.rs @@ -1299,8 +1299,22 @@ fn layout_from_flat_type<'a>( let rec_var = subs.get_root_key_without_compacting(rec_var); let mut tag_layouts = Vec::with_capacity_in(tags.len(), arena); + let mut new_tags = MutMap::default(); + + for (tag_index, index) in tags.iter_all() { + let tag = subs[tag_index].clone(); + let slice = subs[index]; + let mut new_vars = std::vec::Vec::new(); + for var_index in slice { + let var = subs[var_index]; + new_vars.push(var); + } + + new_tags.insert(tag, new_vars); + } + // VERY IMPORTANT: sort the tags - let mut tags_vec: std::vec::Vec<_> = tags.into_iter().collect(); + let mut tags_vec: std::vec::Vec<_> = new_tags.into_iter().collect(); tags_vec.sort(); let mut nullable = None; diff --git a/compiler/solve/src/solve.rs b/compiler/solve/src/solve.rs index ec3250e745..bda12e1885 100644 --- a/compiler/solve/src/solve.rs +++ b/compiler/solve/src/solve.rs @@ -780,8 +780,12 @@ fn type_to_variable( }; tag_vars.extend(ext_tag_vec.into_iter()); - let content = - Content::Structure(FlatType::RecursiveTagUnion(*rec_var, tag_vars, new_ext_var)); + let content = Content::Structure(roc_unify::unify::from_mutmap_rec( + subs, + *rec_var, + tag_vars, + new_ext_var, + )); let tag_union_var = register(subs, rank, pools, content); @@ -896,7 +900,8 @@ fn check_for_infinite_type( let new_ext_var = subs.explicit_substitute(recursive, rec_var, ext_var); - let flat_type = FlatType::RecursiveTagUnion(rec_var, new_tags, new_ext_var); + let flat_type = + roc_unify::unify::from_mutmap_rec(subs, rec_var, new_tags, new_ext_var); subs.set_content(recursive, Content::Structure(flat_type)); } @@ -1124,9 +1129,13 @@ fn adjust_rank_content( RecursiveTagUnion(rec_var, tags, ext_var) => { let mut rank = adjust_rank(subs, young_mark, visit_mark, group_rank, *ext_var); - for var in tags.values().flatten() { - rank = - rank.max(adjust_rank(subs, young_mark, visit_mark, group_rank, *var)); + for (_, index) in tags.iter_all() { + let slice = subs[index]; + for var_index in slice { + let var = subs[var_index]; + rank = rank + .max(adjust_rank(subs, young_mark, visit_mark, group_rank, var)); + } } // THEORY: the recursion var has the same rank as the tag union itself @@ -1275,8 +1284,10 @@ fn instantiate_rigids_help( RecursiveTagUnion(rec_var, tags, ext_var) => { instantiate_rigids_help(subs, max_rank, pools, rec_var); - for (_, vars) in tags { - for var in vars.into_iter() { + 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, pools, var); } } @@ -1466,19 +1477,21 @@ fn deep_copy_var_help( let new_rec_var = deep_copy_var_help(subs, max_rank, pools, rec_var); - for (tag, vars) in tags { - let new_vars: Vec = vars - .into_iter() - .map(|var| deep_copy_var_help(subs, max_rank, pools, var)) - .collect(); + for (tag_index, index) in tags.iter_all() { + let tag = subs[tag_index].clone(); + let slice = subs[index]; + let mut new_vars = Vec::new(); + for var_index in slice { + let var = subs[var_index]; + let new_var = deep_copy_var_help(subs, max_rank, pools, var); + new_vars.push(new_var); + } + new_tags.insert(tag, new_vars); } - RecursiveTagUnion( - new_rec_var, - new_tags, - deep_copy_var_help(subs, max_rank, pools, ext_var), - ) + let new_ext = deep_copy_var_help(subs, max_rank, pools, ext_var); + roc_unify::unify::from_mutmap_rec(subs, new_rec_var, new_tags, new_ext) } }; diff --git a/compiler/types/src/pretty_print.rs b/compiler/types/src/pretty_print.rs index 8291e788ba..1fa406de8e 100644 --- a/compiler/types/src/pretty_print.rs +++ b/compiler/types/src/pretty_print.rs @@ -82,6 +82,8 @@ fn find_names_needed( match content { Content::Structure(FlatType::TagUnion(tags, ext_var)) => { + let ext_var = *ext_var; + let mut new_tags = MutMap::default(); for (name_index, slice_index) in tags.iter_all() { @@ -96,7 +98,12 @@ fn find_names_needed( new_tags.insert(subs[name_index].clone(), new_vars); } - let flat_type = FlatType::RecursiveTagUnion(rec_var, new_tags, *ext_var); + let mut x: Vec<_> = new_tags.into_iter().collect(); + x.sort(); + + let union_tags = UnionTags::insert_into_subs(subs, x); + + let flat_type = FlatType::RecursiveTagUnion(rec_var, union_tags, ext_var); subs.set_content(recursive, Content::Structure(flat_type)); } _ => panic!( @@ -178,11 +185,12 @@ fn find_names_needed( find_names_needed(*ext_var, subs, roots, root_appearances, names_taken); } Structure(RecursiveTagUnion(rec_var, tags, ext_var)) => { - let mut sorted_tags: Vec<_> = tags.iter().collect(); - sorted_tags.sort(); - - for var in sorted_tags.into_iter().map(|(_, v)| v).flatten() { - find_names_needed(*var, subs, roots, root_appearances, names_taken); + for slice_index in tags.variables { + let slice = subs[slice_index]; + for var_index in slice { + let var = subs[var_index]; + find_names_needed(var, subs, roots, root_appearances, names_taken); + } } find_names_needed(*ext_var, subs, roots, root_appearances, names_taken); @@ -587,7 +595,7 @@ fn write_flat_type(env: &Env, flat_type: &FlatType, subs: &Subs, buf: &mut Strin RecursiveTagUnion(rec_var, tags, ext_var) => { buf.push_str("[ "); - let ext_content = write_sorted_tags(env, subs, buf, tags, *ext_var); + let ext_content = write_sorted_tags2(env, subs, buf, tags, *ext_var); buf.push_str(" ]"); @@ -629,8 +637,12 @@ pub fn chase_ext_tag_union<'a>( } Content::Structure(RecursiveTagUnion(_, tags, ext_var)) => { - for (label, vars) in tags { - fields.push((label.clone(), vars.to_vec())); + for (name_index, slice_index) in tags.iter_all() { + let subs_slice = subs[slice_index]; + let slice = subs.get_subs_slice(*subs_slice.as_subs_slice()); + let tag_name = subs[name_index].clone(); + + fields.push((tag_name, slice.to_vec())); } chase_ext_tag_union(subs, *ext_var, fields) diff --git a/compiler/types/src/solved_types.rs b/compiler/types/src/solved_types.rs index a36712d193..4960ff812f 100644 --- a/compiler/types/src/solved_types.rs +++ b/compiler/types/src/solved_types.rs @@ -447,13 +447,16 @@ impl SolvedType { let mut new_tags = Vec::with_capacity(tags.len()); - for (tag_name, args) in tags { - let mut new_args = Vec::with_capacity(args.len()); + for (name_index, slice_index) in tags.iter_all() { + let slice = subs[slice_index]; - for var in args { - new_args.push(Self::from_var_help(subs, recursion_vars, *var)); + let mut new_args = Vec::with_capacity(slice.len()); + + for var_index in slice { + let var = subs[var_index]; + new_args.push(Self::from_var_help(subs, recursion_vars, var)); } - + let tag_name = subs[name_index].clone(); new_tags.push((tag_name.clone(), new_args)); } diff --git a/compiler/types/src/subs.rs b/compiler/types/src/subs.rs index 39ae422a24..11dbcb05ee 100644 --- a/compiler/types/src/subs.rs +++ b/compiler/types/src/subs.rs @@ -1,5 +1,5 @@ use crate::types::{name_type_var, ErrorType, Problem, RecordField, TypeExt}; -use roc_collections::all::{ImMap, ImSet, MutMap, MutSet, SendMap}; +use roc_collections::all::{ImMap, ImSet, MutSet, SendMap}; use roc_module::ident::{Lowercase, TagName}; use roc_module::symbol::Symbol; use std::fmt; @@ -9,9 +9,9 @@ use ven_ena::unify::{InPlace, Snapshot, UnificationTable, UnifyKey}; // if your changes cause this number to go down, great! // please change it to the lower number. // if it went up, maybe check that the change is really required -static_assertions::assert_eq_size!([u8; 72], Descriptor); -static_assertions::assert_eq_size!([u8; 56], Content); -static_assertions::assert_eq_size!([u8; 48], FlatType); +static_assertions::assert_eq_size!([u8; 64], Descriptor); +static_assertions::assert_eq_size!([u8; 48], Content); +static_assertions::assert_eq_size!([u8; 40], FlatType); static_assertions::assert_eq_size!([u8; 48], Problem); #[derive(Clone, Copy, Hash, PartialEq, Eq)] @@ -884,7 +884,7 @@ pub enum FlatType { Record(RecordFields, Variable), TagUnion(UnionTags, Variable), FunctionOrTagUnion(SubsIndex, Symbol, Variable), - RecursiveTagUnion(Variable, MutMap>, Variable), + RecursiveTagUnion(Variable, UnionTags, Variable), Erroneous(Box), EmptyRecord, EmptyTagUnion, @@ -1376,8 +1376,15 @@ fn occurs( } RecursiveTagUnion(_rec_var, tags, ext_var) => { // TODO rec_var is excluded here, verify that this is correct - let it = once(ext_var).chain(tags.values().flatten()); - short_circuit(subs, root_var, &new_seen, it) + for slice_index in tags.variables { + let slice = subs[slice_index]; + for var_index in slice { + let var = subs[var_index]; + short_circuit_help(subs, root_var, &new_seen, var)?; + } + } + + short_circuit_help(subs, root_var, &new_seen, *ext_var) } EmptyRecord | EmptyTagUnion | Erroneous(_) => Ok(()), } @@ -1481,7 +1488,6 @@ fn explicit_substitute( let var = subs[var_index]; let new_var = explicit_substitute(subs, from, to, var, seen); new_variables.push(new_var); - // subs[var_index] = new_var; } let start = subs.variables.len() as u32; @@ -1509,17 +1515,40 @@ fn explicit_substitute( Structure(FunctionOrTagUnion(tag_name, symbol, new_ext_var)), ); } - RecursiveTagUnion(rec_var, mut tags, ext_var) => { + RecursiveTagUnion(rec_var, tags, ext_var) => { // NOTE rec_var is not substituted, verify that this is correct! let new_ext_var = explicit_substitute(subs, from, to, ext_var, seen); - for (_, variables) in tags.iter_mut() { - for var in variables.iter_mut() { - *var = explicit_substitute(subs, from, to, *var, seen); + + let mut new_slices = Vec::new(); + for slice_index in tags.variables { + let slice = subs[slice_index]; + + let mut new_variables = Vec::new(); + for var_index in slice { + let var = subs[var_index]; + let new_var = explicit_substitute(subs, from, to, var, seen); + new_variables.push(new_var); } + + let start = subs.variables.len() as u32; + let length = new_variables.len() as u16; + + subs.variables.extend(new_variables); + + new_slices.push(VariableSubsSlice::new(start, length)); } + + let start = subs.variable_slices.len() as u32; + let length = new_slices.len() as u16; + + subs.variable_slices.extend(new_slices); + + let mut union_tags = tags; + union_tags.variables = SubsSlice::new(start, length); + subs.set_content( in_var, - Structure(RecursiveTagUnion(rec_var, tags, new_ext_var)), + Structure(RecursiveTagUnion(rec_var, union_tags, new_ext_var)), ); } Record(vars_by_field, ext_var) => { @@ -1657,9 +1686,11 @@ fn get_var_names( let taken_names = get_var_names(subs, ext_var, taken_names); let mut taken_names = get_var_names(subs, rec_var, taken_names); - for vars in tags.values() { - for arg_var in vars { - taken_names = get_var_names(subs, *arg_var, taken_names) + for slice_index in tags.variables { + let slice = subs[slice_index]; + for var_index in slice { + let arg_var = subs[var_index]; + taken_names = get_var_names(subs, arg_var, taken_names) } } @@ -1947,13 +1978,16 @@ fn flat_type_to_err_type( RecursiveTagUnion(rec_var, tags, ext_var) => { let mut err_tags = SendMap::default(); - for (tag, vars) in tags.into_iter() { - let mut err_vars = Vec::with_capacity(vars.len()); + for (name_index, slice_index) in tags.iter_all() { + let mut err_vars = Vec::with_capacity(tags.len()); - for var in vars { + let slice = subs[slice_index]; + for var_index in slice { + let var = subs[var_index]; err_vars.push(var_to_err_type(subs, state, var)); } + let tag = subs[name_index].clone(); err_tags.insert(tag, err_vars); } @@ -2049,8 +2083,12 @@ fn restore_content(subs: &mut Subs, content: &Content) { } RecursiveTagUnion(rec_var, tags, ext_var) => { - for var in tags.values().flatten() { - subs.restore(*var); + for slice_index in tags.variables { + let slice = subs[slice_index]; + for var_index in slice { + let var = subs[var_index]; + subs.restore(var); + } } subs.restore(*ext_var); diff --git a/compiler/unify/src/unify.rs b/compiler/unify/src/unify.rs index a96ee936ec..5fdefee871 100644 --- a/compiler/unify/src/unify.rs +++ b/compiler/unify/src/unify.rs @@ -902,18 +902,7 @@ fn unify_shared_tags_merge_new( ) -> Outcome { let flat_type = if let Some(rec) = recursion_var { debug_assert!(is_recursion_var(subs, rec)); - - let mut tags = MutMap::default(); - - for (name_index, slice_index) in new_tags.iter_all() { - let subs_slice = subs[slice_index]; - let slice = subs.get_subs_slice(*subs_slice.as_subs_slice()); - let tag = subs[name_index].clone(); - - tags.insert(tag, slice.to_vec()); - } - - FlatType::RecursiveTagUnion(rec, tags, new_ext_var) + FlatType::RecursiveTagUnion(rec, new_tags, new_ext_var) } else { FlatType::TagUnion(new_tags, new_ext_var) }; @@ -1296,7 +1285,7 @@ fn unify_shared_tags_recursive_not_recursive( let mut new_tags = union(matching_tags, &other_tags); new_tags.extend(fields.into_iter()); - let flat_type = FlatType::RecursiveTagUnion(recursion_var, new_tags, new_ext_var); + let flat_type = from_mutmap_rec(subs, recursion_var, new_tags, new_ext_var); merge(subs, ctx, Structure(flat_type)) } else { @@ -1408,7 +1397,7 @@ fn unify_shared_tags_merge( ) -> Outcome { let flat_type = if let Some(rec) = recursion_var { debug_assert!(is_recursion_var(subs, rec)); - FlatType::RecursiveTagUnion(rec, new_tags, new_ext_var) + from_mutmap_rec(subs, rec, new_tags, new_ext_var) } else { from_mutmap(subs, new_tags, new_ext_var) }; @@ -1458,7 +1447,7 @@ fn unify_flat_type( (RecursiveTagUnion(recursion_var, tags1, ext1), TagUnion(tags2, ext2)) => { debug_assert!(is_recursion_var(subs, *recursion_var)); // this never happens in type-correct programs, but may happen if there is a type error - let union1 = gather_tags(subs, tags1.clone(), *ext1); + let union1 = gather_tags_new(subs, *tags1, *ext1); let union2 = gather_tags_new(subs, *tags2, *ext2); unify_tag_union( @@ -1474,7 +1463,7 @@ fn unify_flat_type( (TagUnion(tags1, ext1), RecursiveTagUnion(recursion_var, tags2, ext2)) => { debug_assert!(is_recursion_var(subs, *recursion_var)); let union1 = gather_tags_new(subs, *tags1, *ext1); - let union2 = gather_tags(subs, tags2.clone(), *ext2); + let union2 = gather_tags_new(subs, *tags2, *ext2); unify_tag_union_not_recursive_recursive(subs, pool, ctx, union1, union2, *recursion_var) } @@ -1482,8 +1471,8 @@ fn unify_flat_type( (RecursiveTagUnion(rec1, tags1, ext1), RecursiveTagUnion(rec2, tags2, ext2)) => { debug_assert!(is_recursion_var(subs, *rec1)); debug_assert!(is_recursion_var(subs, *rec2)); - let union1 = gather_tags(subs, tags1.clone(), *ext1); - let union2 = gather_tags(subs, tags2.clone(), *ext2); + let union1 = gather_tags_new(subs, *tags1, *ext1); + let union2 = gather_tags_new(subs, *tags2, *ext2); let mut problems = unify_tag_union(subs, pool, ctx, union1, union2, (Some(*rec1), Some(*rec2))); @@ -1602,7 +1591,7 @@ fn unify_flat_type( let mut tags2 = MutMap::default(); tags2.insert(tag_name, vec![]); - let union1 = gather_tags(subs, tags1.clone(), *ext1); + let union1 = gather_tags_new(subs, *tags1, *ext1); let union2 = gather_tags(subs, tags2, *ext2); unify_tag_union( @@ -1624,7 +1613,7 @@ fn unify_flat_type( tags1.insert(tag_name, vec![]); let union1 = gather_tags(subs, tags1, *ext1); - let union2 = gather_tags(subs, tags2.clone(), *ext2); + let union2 = gather_tags_new(subs, *tags2, *ext2); unify_tag_union_not_recursive_recursive(subs, pool, ctx, union1, union2, *recursion_var) } @@ -1894,6 +1883,21 @@ pub fn from_mutmap( FlatType::TagUnion(union_tags, ext) } +pub fn from_mutmap_rec( + subs: &mut Subs, + rec: Variable, + tags: MutMap>, + ext: Variable, +) -> FlatType { + let mut vec: Vec<_> = tags.into_iter().collect(); + + vec.sort(); + + let union_tags = UnionTags::insert_into_subs(subs, vec); + + FlatType::RecursiveTagUnion(rec, union_tags, ext) +} + #[allow(clippy::too_many_arguments)] fn unify_function_or_tag_union_and_func( subs: &mut Subs, diff --git a/editor/src/lang/solve.rs b/editor/src/lang/solve.rs index 60ff3f0098..8e5edf65c5 100644 --- a/editor/src/lang/solve.rs +++ b/editor/src/lang/solve.rs @@ -1013,7 +1013,8 @@ fn check_for_infinite_type( let new_ext_var = subs.explicit_substitute(recursive, rec_var, ext_var); - let flat_type = FlatType::RecursiveTagUnion(rec_var, new_tags, new_ext_var); + let flat_type = + roc_unify::unify::from_mutmap_rec(subs, rec_var, new_tags, new_ext_var); subs.set_content(recursive, Content::Structure(flat_type)); } @@ -1252,9 +1253,13 @@ fn adjust_rank_content( RecursiveTagUnion(rec_var, tags, ext_var) => { let mut rank = adjust_rank(subs, young_mark, visit_mark, group_rank, *ext_var); - for var in tags.values().flatten() { - rank = - rank.max(adjust_rank(subs, young_mark, visit_mark, group_rank, *var)); + for (_, index) in tags.iter_all() { + let slice = subs[index]; + for var_index in slice { + let var = subs[var_index]; + rank = rank + .max(adjust_rank(subs, young_mark, visit_mark, group_rank, var)); + } } // THEORY: the recursion var has the same rank as the tag union itself @@ -1403,8 +1408,10 @@ fn instantiate_rigids_help( RecursiveTagUnion(rec_var, tags, ext_var) => { instantiate_rigids_help(subs, max_rank, pools, rec_var); - for (_, vars) in tags { - for var in vars.into_iter() { + 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, pools, var); } } @@ -1594,19 +1601,21 @@ fn deep_copy_var_help( let new_rec_var = deep_copy_var_help(subs, max_rank, pools, rec_var); - for (tag, vars) in tags { - let new_vars: Vec = vars - .into_iter() - .map(|var| deep_copy_var_help(subs, max_rank, pools, var)) - .collect(); + for (tag_index, index) in tags.iter_all() { + let tag = subs[tag_index].clone(); + let slice = subs[index]; + let mut new_vars = Vec::new(); + for var_index in slice { + let var = subs[var_index]; + let new_var = deep_copy_var_help(subs, max_rank, pools, var); + new_vars.push(new_var); + } + new_tags.insert(tag, new_vars); } - RecursiveTagUnion( - new_rec_var, - new_tags, - deep_copy_var_help(subs, max_rank, pools, ext_var), - ) + let new_ext = deep_copy_var_help(subs, max_rank, pools, ext_var); + roc_unify::unify::from_mutmap_rec(subs, new_rec_var, new_tags, new_ext) } };