Have FunctionOrTagUnion include multiple possible tags

This commit is contained in:
Ayaz Hafiz 2022-10-03 11:01:16 -05:00
parent 797763b5fa
commit 61cf8e53e6
No known key found for this signature in database
GPG key ID: 0E2A37416A25EF58
9 changed files with 155 additions and 85 deletions

View file

@ -60,8 +60,6 @@ trait CopyEnv {
fn clone_name(&mut self, name: SubsIndex<Lowercase>) -> SubsIndex<Lowercase>;
fn clone_tag_name(&mut self, tag_name: SubsIndex<TagName>) -> SubsIndex<TagName>;
fn clone_field_names(&mut self, field_names: SubsSlice<Lowercase>) -> SubsSlice<Lowercase>;
fn clone_tag_names(&mut self, tag_names: SubsSlice<TagName>) -> SubsSlice<TagName>;
@ -95,11 +93,6 @@ impl CopyEnv for Subs {
name
}
#[inline(always)]
fn clone_tag_name(&mut self, tag_name: SubsIndex<TagName>) -> SubsIndex<TagName> {
tag_name
}
#[inline(always)]
fn clone_field_names(&mut self, field_names: SubsSlice<Lowercase>) -> SubsSlice<Lowercase> {
field_names
@ -150,11 +143,6 @@ impl<'a> CopyEnv for AcrossSubs<'a> {
SubsIndex::push_new(&mut self.target.field_names, self.source[name].clone())
}
#[inline(always)]
fn clone_tag_name(&mut self, tag_name: SubsIndex<TagName>) -> SubsIndex<TagName> {
SubsIndex::push_new(&mut self.target.tag_names, self.source[tag_name].clone())
}
#[inline(always)]
fn clone_field_names(&mut self, field_names: SubsSlice<Lowercase>) -> SubsSlice<Lowercase> {
SubsSlice::extend_new(
@ -935,12 +923,13 @@ fn deep_copy_type_vars<C: CopyEnv>(
Structure(RecursiveTagUnion(new_rec_var, new_union_tags, new_ext_var))
})
}
FunctionOrTagUnion(tag_name, symbol, ext_var) => {
FunctionOrTagUnion(tag_names, symbols, ext_var) => {
let new_ext_var = descend_var!(ext_var);
let new_tag_name = env.clone_tag_name(tag_name);
let new_tag_names = env.clone_tag_names(tag_names);
let new_symbols = env.clone_lambda_names(symbols);
perform_clone!(Structure(FunctionOrTagUnion(
new_tag_name,
symbol,
new_tag_names,
new_symbols,
new_ext_var
)))
}

View file

@ -2,7 +2,7 @@ use roc_module::{
ident::{Lowercase, TagName},
symbol::Symbol,
};
use roc_types::subs::{Content, FlatType, Subs, Variable};
use roc_types::subs::{Content, FlatType, GetSubsSlice, Subs, Variable};
use crate::{
util::{check_derivable_ext_var, debug_name_record},
@ -107,9 +107,14 @@ impl FlatEncodable {
Ok(Key(FlatEncodableKey::TagUnion(tag_names_and_payload_sizes)))
}
FlatType::FunctionOrTagUnion(name_index, _, _) => Ok(Key(
FlatEncodableKey::TagUnion(vec![(subs[name_index].clone(), 0)]),
)),
FlatType::FunctionOrTagUnion(names_index, _, _) => {
Ok(Key(FlatEncodableKey::TagUnion(
subs.get_subs_slice(names_index)
.iter()
.map(|t| (t.clone(), 0))
.collect(),
)))
}
FlatType::EmptyRecord => Ok(Key(FlatEncodableKey::Record(vec![]))),
FlatType::EmptyTagUnion => Ok(Key(FlatEncodableKey::TagUnion(vec![]))),
//

View file

@ -12,7 +12,7 @@ use roc_problem::can::RuntimeError;
use roc_target::{PtrWidth, TargetInfo};
use roc_types::num::NumericRange;
use roc_types::subs::{
self, Content, FlatType, GetSubsSlice, Label, OptVariable, RecordFields, Subs, UnionTags,
self, Content, FlatType, GetSubsSlice, Label, OptVariable, RecordFields, Subs,
UnsortedUnionLabels, Variable,
};
use roc_types::types::{gather_fields_unsorted_iter, RecordField, RecordFieldsError};
@ -3152,16 +3152,18 @@ fn layout_from_flat_type<'a>(
layout_from_non_recursive_union(env, &tags).map(Ok)
}
FunctionOrTagUnion(tag_name, _, ext_var) => {
FunctionOrTagUnion(tag_names, _, ext_var) => {
debug_assert!(
ext_var_is_empty_tag_union(subs, ext_var),
"If ext_var wasn't empty, this wouldn't be a FunctionOrTagUnion!"
);
let union_tags = UnionTags::from_tag_name_index(tag_name);
let (tags, _) = union_tags.unsorted_tags_and_ext(subs, ext_var);
let tag_names = subs.get_subs_slice(tag_names);
let unsorted_tags = UnsortedUnionLabels {
tags: tag_names.iter().map(|t| (t, &[] as &[Variable])).collect(),
};
layout_from_non_recursive_union(env, &tags).map(Ok)
layout_from_non_recursive_union(env, &unsorted_tags).map(Ok)
}
RecursiveTagUnion(rec_var, tags, ext_var) => {
let (tags, ext_var) = tags.unsorted_tags_and_ext(subs, ext_var);

View file

@ -2299,10 +2299,11 @@ fn type_to_variable<'a>(
unreachable!("we assert that the ext var is empty; otherwise we'd already know it was a tag union!");
}
let slice = SubsIndex::new(subs.tag_names.len() as u32);
subs.tag_names.push(tag_name.clone());
let tag_names = SubsSlice::extend_new(&mut subs.tag_names, [tag_name.clone()]);
let symbols = SubsSlice::extend_new(&mut subs.closure_names, [*symbol]);
let content = Content::Structure(FlatType::FunctionOrTagUnion(slice, *symbol, ext));
let content =
Content::Structure(FlatType::FunctionOrTagUnion(tag_names, symbols, ext));
register_with_known_var(subs, destination, rank, pools, content)
}

View file

@ -1156,11 +1156,15 @@ fn write_flat_type<'a>(
)
}
FunctionOrTagUnion(tag_name, _, ext_var) => {
FunctionOrTagUnion(tag_names, _, ext_var) => {
buf.push('[');
let mut tags: MutMap<TagName, _> = MutMap::default();
tags.insert(subs[*tag_name].clone(), vec![]);
tags.extend(
subs.get_subs_slice(*tag_names)
.iter()
.map(|t| (t.clone(), vec![])),
);
let ext_content = write_sorted_tags(env, ctx, subs, buf, &tags, *ext_var);
buf.push(']');
@ -1241,8 +1245,12 @@ pub fn chase_ext_tag_union(
push_union(subs, tags, fields);
chase_ext_tag_union(subs, *ext_var, fields)
}
Content::Structure(FunctionOrTagUnion(tag_name, _, ext_var)) => {
fields.push((subs[*tag_name].clone(), vec![]));
Content::Structure(FunctionOrTagUnion(tag_names, _, ext_var)) => {
fields.extend(
subs.get_subs_slice(*tag_names)
.iter()
.map(|t| (t.clone(), vec![])),
);
chase_ext_tag_union(subs, *ext_var, fields)
}

View file

@ -962,13 +962,13 @@ fn subs_fmt_flat_type(this: &FlatType, subs: &Subs, f: &mut fmt::Formatter) -> f
write!(f, "]<{:?}>", new_ext)
}
FlatType::FunctionOrTagUnion(tagname_index, symbol, ext) => {
let tagname: &TagName = &subs[*tagname_index];
FlatType::FunctionOrTagUnion(tagnames, symbol, ext) => {
let tagnames: &[TagName] = &subs.get_subs_slice(*tagnames);
write!(
f,
"FunctionOrTagUnion({:?}, {:?}, {:?})",
tagname, symbol, ext
tagnames, symbol, ext
)
}
FlatType::RecursiveTagUnion(rec, tags, ext) => {
@ -2424,7 +2424,12 @@ pub enum FlatType {
Func(VariableSubsSlice, Variable, Variable),
Record(RecordFields, Variable),
TagUnion(UnionTags, Variable),
FunctionOrTagUnion(SubsIndex<TagName>, Symbol, Variable),
/// `A` might either be a function
/// x -> A x : a -> [A a, B a, C a]
/// or a tag `[A, B, C]`
FunctionOrTagUnion(SubsSlice<TagName>, SubsSlice<Symbol>, Variable),
RecursiveTagUnion(Variable, UnionTags, Variable),
Erroneous(SubsIndex<Problem>),
EmptyRecord,
@ -3881,12 +3886,12 @@ fn flat_type_to_err_type(
}
}
FunctionOrTagUnion(tag_name, _, ext_var) => {
let tag_name = subs[tag_name].clone();
FunctionOrTagUnion(tag_names, _, ext_var) => {
let tag_names = subs.get_subs_slice(tag_names);
let mut err_tags = SendMap::default();
let mut err_tags: SendMap<TagName, Vec<_>> = SendMap::default();
err_tags.insert(tag_name, vec![]);
err_tags.extend(tag_names.into_iter().map(|t| (t.clone(), vec![])));
match var_to_err_type(subs, state, ext_var).unwrap_structural_alias() {
ErrorType::TagUnion(sub_tags, sub_ext) => {
@ -4202,8 +4207,8 @@ impl StorageSubs {
Self::offset_tag_union(offsets, *union_tags),
Self::offset_variable(offsets, *ext),
),
FlatType::FunctionOrTagUnion(tag_name, symbol, ext) => FlatType::FunctionOrTagUnion(
Self::offset_tag_name_index(offsets, *tag_name),
FlatType::FunctionOrTagUnion(tag_names, symbol, ext) => FlatType::FunctionOrTagUnion(
Self::offset_tag_name_slice(offsets, *tag_names),
*symbol,
Self::offset_variable(offsets, *ext),
),
@ -4295,13 +4300,13 @@ impl StorageSubs {
record_fields
}
fn offset_tag_name_index(
fn offset_tag_name_slice(
offsets: &StorageSubsOffsets,
mut tag_name: SubsIndex<TagName>,
) -> SubsIndex<TagName> {
tag_name.index += offsets.tag_names;
mut tag_names: SubsSlice<TagName>,
) -> SubsSlice<TagName> {
tag_names.start += offsets.tag_names;
tag_name
tag_names
}
fn offset_variable(offsets: &StorageSubsOffsets, variable: Variable) -> Variable {
@ -4542,12 +4547,22 @@ fn storage_copy_var_to_help(env: &mut StorageCopyVarToEnv<'_>, var: Variable) ->
TagUnion(union_tags, new_ext)
}
FunctionOrTagUnion(tag_name, symbol, ext_var) => {
let new_tag_name = SubsIndex::new(env.target.tag_names.len() as u32);
FunctionOrTagUnion(tag_names, symbols, ext_var) => {
let new_tag_names = SubsSlice::extend_new(
&mut env.target.tag_names,
env.source.get_subs_slice(tag_names).iter().cloned(),
);
env.target.tag_names.push(env.source[tag_name].clone());
let new_symbols = SubsSlice::extend_new(
&mut env.target.closure_names,
env.source.get_subs_slice(symbols).iter().cloned(),
);
FunctionOrTagUnion(new_tag_name, symbol, storage_copy_var_to_help(env, ext_var))
FunctionOrTagUnion(
new_tag_names,
new_symbols,
storage_copy_var_to_help(env, ext_var),
)
}
RecursiveTagUnion(rec_var, tags, ext_var) => {
@ -4981,14 +4996,20 @@ fn copy_import_to_help(env: &mut CopyImportEnv<'_>, max_rank: Rank, var: Variabl
TagUnion(union_tags, new_ext)
}
FunctionOrTagUnion(tag_name, symbol, ext_var) => {
let new_tag_name = SubsIndex::new(env.target.tag_names.len() as u32);
FunctionOrTagUnion(tag_names, symbols, ext_var) => {
let new_tag_names = SubsSlice::extend_new(
&mut env.target.tag_names,
env.source.get_subs_slice(tag_names).iter().cloned(),
);
env.target.tag_names.push(env.source[tag_name].clone());
let new_symbols = SubsSlice::extend_new(
&mut env.target.closure_names,
env.source.get_subs_slice(symbols).iter().cloned(),
);
FunctionOrTagUnion(
new_tag_name,
symbol,
new_tag_names,
new_symbols,
copy_import_to_help(env, max_rank, ext_var),
)
}

View file

@ -2657,13 +2657,13 @@ fn unify_flat_type<M: MetaCollector>(
outcome
}
(FunctionOrTagUnion(tag_name, tag_symbol, ext), Func(args, closure, ret)) => {
(FunctionOrTagUnion(tag_names, tag_symbols, ext), Func(args, closure, ret)) => {
unify_function_or_tag_union_and_func(
env,
pool,
ctx,
tag_name,
*tag_symbol,
*tag_names,
*tag_symbols,
*ext,
*args,
*ret,
@ -2671,13 +2671,13 @@ fn unify_flat_type<M: MetaCollector>(
true,
)
}
(Func(args, closure, ret), FunctionOrTagUnion(tag_name, tag_symbol, ext)) => {
(Func(args, closure, ret), FunctionOrTagUnion(tag_names, tag_symbols, ext)) => {
unify_function_or_tag_union_and_func(
env,
pool,
ctx,
tag_name,
*tag_symbol,
*tag_names,
*tag_symbols,
*ext,
*args,
*ret,
@ -2685,9 +2685,9 @@ fn unify_flat_type<M: MetaCollector>(
false,
)
}
(FunctionOrTagUnion(tag_name_1, _, ext1), FunctionOrTagUnion(tag_name_2, _, ext2)) => {
let tag_name_1_ref = &env.subs[*tag_name_1];
let tag_name_2_ref = &env.subs[*tag_name_2];
(FunctionOrTagUnion(tag_names_1, _, ext1), FunctionOrTagUnion(tag_names_2, _, ext2)) => {
let tag_name_1_ref = &env.subs.get_subs_slice(*tag_names_1);
let tag_name_2_ref = &env.subs.get_subs_slice(*tag_names_2);
if tag_name_1_ref == tag_name_2_ref {
let outcome = unify_pool(env, pool, *ext1, *ext2, ctx.mode);
@ -2698,37 +2698,62 @@ fn unify_flat_type<M: MetaCollector>(
outcome
}
} else {
let tags1 = UnionTags::from_tag_name_index(*tag_name_1);
let tags2 = UnionTags::from_tag_name_index(*tag_name_2);
let empty_tag_var_slices_1 = SubsSlice::extend_new(
&mut env.subs.variable_slices,
std::iter::repeat(Default::default()).take(tag_names_1.len()),
);
let tags1 = UnionTags::from_slices(*tag_names_1, empty_tag_var_slices_1);
let empty_tag_var_slices_2 = SubsSlice::extend_new(
&mut env.subs.variable_slices,
std::iter::repeat(Default::default()).take(tag_names_2.len()),
);
let tags2 = UnionTags::from_slices(*tag_names_2, empty_tag_var_slices_2);
unify_tag_unions(env, pool, ctx, tags1, *ext1, tags2, *ext2, Rec::None)
}
}
(TagUnion(tags1, ext1), FunctionOrTagUnion(tag_name, _, ext2)) => {
let tags2 = UnionTags::from_tag_name_index(*tag_name);
(TagUnion(tags1, ext1), FunctionOrTagUnion(tag_names, _, ext2)) => {
let empty_tag_var_slices = SubsSlice::extend_new(
&mut env.subs.variable_slices,
std::iter::repeat(Default::default()).take(tag_names.len()),
);
let tags2 = UnionTags::from_slices(*tag_names, empty_tag_var_slices);
unify_tag_unions(env, pool, ctx, *tags1, *ext1, tags2, *ext2, Rec::None)
}
(FunctionOrTagUnion(tag_name, _, ext1), TagUnion(tags2, ext2)) => {
let tags1 = UnionTags::from_tag_name_index(*tag_name);
(FunctionOrTagUnion(tag_names, _, ext1), TagUnion(tags2, ext2)) => {
let empty_tag_var_slices = SubsSlice::extend_new(
&mut env.subs.variable_slices,
std::iter::repeat(Default::default()).take(tag_names.len()),
);
let tags1 = UnionTags::from_slices(*tag_names, empty_tag_var_slices);
unify_tag_unions(env, pool, ctx, tags1, *ext1, *tags2, *ext2, Rec::None)
}
(RecursiveTagUnion(recursion_var, tags1, ext1), FunctionOrTagUnion(tag_name, _, ext2)) => {
(RecursiveTagUnion(recursion_var, tags1, ext1), FunctionOrTagUnion(tag_names, _, ext2)) => {
// this never happens in type-correct programs, but may happen if there is a type error
debug_assert!(is_recursion_var(env.subs, *recursion_var));
let tags2 = UnionTags::from_tag_name_index(*tag_name);
let empty_tag_var_slices = SubsSlice::extend_new(
&mut env.subs.variable_slices,
std::iter::repeat(Default::default()).take(tag_names.len()),
);
let tags2 = UnionTags::from_slices(*tag_names, empty_tag_var_slices);
let rec = Rec::Left(*recursion_var);
unify_tag_unions(env, pool, ctx, *tags1, *ext1, tags2, *ext2, rec)
}
(FunctionOrTagUnion(tag_name, _, ext1), RecursiveTagUnion(recursion_var, tags2, ext2)) => {
(FunctionOrTagUnion(tag_names, _, ext1), RecursiveTagUnion(recursion_var, tags2, ext2)) => {
debug_assert!(is_recursion_var(env.subs, *recursion_var));
let tags1 = UnionTags::from_tag_name_index(*tag_name);
let empty_tag_var_slices = SubsSlice::extend_new(
&mut env.subs.variable_slices,
std::iter::repeat(Default::default()).take(tag_names.len()),
);
let tags1 = UnionTags::from_slices(*tag_names, empty_tag_var_slices);
let rec = Rec::Right(*recursion_var);
unify_tag_unions(env, pool, ctx, tags1, *ext1, *tags2, *ext2, rec)
@ -3133,17 +3158,20 @@ fn unify_function_or_tag_union_and_func<M: MetaCollector>(
env: &mut Env,
pool: &mut Pool,
ctx: &Context,
tag_name_index: &SubsIndex<TagName>,
tag_symbol: Symbol,
tag_names_slice: SubsSlice<TagName>,
tag_fn_lambdas: SubsSlice<Symbol>,
tag_ext: Variable,
function_arguments: VariableSubsSlice,
function_return: Variable,
function_lambda_set: Variable,
left: bool,
) -> Outcome<M> {
let tag_name = env.subs[*tag_name_index].clone();
let tag_names = env.subs.get_subs_slice(tag_names_slice).to_vec();
let union_tags = UnionTags::insert_slices_into_subs(env.subs, [(tag_name, function_arguments)]);
let union_tags = UnionTags::insert_slices_into_subs(
env.subs,
tag_names.into_iter().map(|tag| (tag, function_arguments)),
);
let content = Content::Structure(FlatType::TagUnion(union_tags, tag_ext));
let new_tag_union_var = fresh(env, pool, ctx, content);
@ -3155,7 +3183,14 @@ fn unify_function_or_tag_union_and_func<M: MetaCollector>(
};
{
let union_tags = UnionLambdas::tag_without_arguments(env.subs, tag_symbol);
let lambda_names = env.subs.get_subs_slice(tag_fn_lambdas).to_vec();
let new_lambda_names = SubsSlice::extend_new(&mut env.subs.closure_names, lambda_names);
let empty_captures_slices = SubsSlice::extend_new(
&mut env.subs.variable_slices,
std::iter::repeat(Default::default()).take(new_lambda_names.len()),
);
let union_tags = UnionLambdas::from_slices(new_lambda_names, empty_captures_slices);
let ambient_function_var = if left { ctx.first } else { ctx.second };
let lambda_set_content = LambdaSet(self::LambdaSet {
solved: union_tags,