mirror of
https://github.com/roc-lang/roc.git
synced 2025-08-04 12:18:19 +00:00
Add a notion of "openness" tag extensions suitable only for size-polymorphism
This commit is contained in:
parent
5f5d6a42d1
commit
1c93727822
18 changed files with 302 additions and 233 deletions
|
@ -10,7 +10,7 @@ use roc_region::all::{Loc, Region};
|
|||
use roc_solve::module::Solved;
|
||||
use roc_types::subs::{
|
||||
self, AliasVariables, Content, Descriptor, FlatType, Mark, OptVariable, Rank, RecordFields,
|
||||
Subs, SubsSlice, UnionLambdas, UnionTags, Variable, VariableSubsSlice,
|
||||
Subs, SubsSlice, TagExt, UnionLambdas, UnionTags, Variable, VariableSubsSlice,
|
||||
};
|
||||
use roc_types::types::{
|
||||
gather_fields_unsorted_iter, Alias, AliasKind, Category, ErrorType, PatternCategory, Polarity,
|
||||
|
@ -683,7 +683,7 @@ fn solve<'a>(
|
|||
let mut new_desc = subs.get(actual);
|
||||
match new_desc.content {
|
||||
Content::Structure(FlatType::TagUnion(tags, _)) => {
|
||||
let new_ext = subs.fresh_unnamed_flex_var();
|
||||
let new_ext = TagExt::Any(subs.fresh_unnamed_flex_var());
|
||||
let new_union = Content::Structure(FlatType::TagUnion(tags, new_ext));
|
||||
new_desc.content = new_union;
|
||||
subs.set(actual, new_desc);
|
||||
|
@ -953,7 +953,7 @@ fn type_to_variable<'a>(
|
|||
|
||||
let (union_tags, ext) =
|
||||
type_to_union_tags(arena, mempool, subs, rank, pools, cached, tags, ext);
|
||||
let content = Content::Structure(FlatType::TagUnion(union_tags, ext));
|
||||
let content = Content::Structure(FlatType::TagUnion(union_tags, TagExt::Any(ext)));
|
||||
|
||||
register(subs, rank, pools, content)
|
||||
}
|
||||
|
@ -1097,9 +1097,12 @@ fn type_to_union_tags<'a>(
|
|||
let temp_ext_var = type_to_variable(arena, mempool, subs, rank, pools, cached, ext);
|
||||
|
||||
let ext = {
|
||||
let (it, ext) =
|
||||
roc_types::types::gather_tags_unsorted_iter(subs, UnionTags::default(), temp_ext_var)
|
||||
.expect("not a tag union");
|
||||
let (it, ext) = roc_types::types::gather_tags_unsorted_iter(
|
||||
subs,
|
||||
UnionTags::default(),
|
||||
TagExt::Any(temp_ext_var),
|
||||
)
|
||||
.expect("not a tag union");
|
||||
|
||||
tag_vars.extend(it.map(|(n, v)| (n.clone(), v)));
|
||||
tag_vars.sort_unstable_by(|(a, _), (b, _)| a.cmp(b));
|
||||
|
@ -1123,7 +1126,10 @@ fn type_to_union_tags<'a>(
|
|||
ext
|
||||
};
|
||||
|
||||
(UnionTags::insert_slices_into_subs(subs, tag_vars), ext)
|
||||
(
|
||||
UnionTags::insert_slices_into_subs(subs, tag_vars),
|
||||
ext.var(),
|
||||
)
|
||||
}
|
||||
|
||||
fn check_for_infinite_type(
|
||||
|
@ -1165,7 +1171,7 @@ fn check_for_infinite_type(
|
|||
new_tags.push((subs[name_index].clone(), new_vars));
|
||||
}
|
||||
|
||||
let new_ext_var = subs.explicit_substitute(recursive, rec_var, ext_var);
|
||||
let new_ext_var = ext_var.map(|v| subs.explicit_substitute(recursive, rec_var, v));
|
||||
|
||||
let new_tags = UnionTags::insert_into_subs(subs, new_tags);
|
||||
|
||||
|
@ -1387,7 +1393,8 @@ fn adjust_rank_content(
|
|||
}
|
||||
|
||||
TagUnion(tags, ext_var) => {
|
||||
let mut rank = adjust_rank(subs, young_mark, visit_mark, group_rank, *ext_var);
|
||||
let mut rank =
|
||||
adjust_rank(subs, young_mark, visit_mark, group_rank, ext_var.var());
|
||||
|
||||
for (_, index) in tags.iter_all() {
|
||||
let slice = subs[index];
|
||||
|
@ -1402,11 +1409,12 @@ fn adjust_rank_content(
|
|||
}
|
||||
|
||||
FunctionOrTagUnion(_, _, ext_var) => {
|
||||
adjust_rank(subs, young_mark, visit_mark, group_rank, *ext_var)
|
||||
adjust_rank(subs, young_mark, visit_mark, group_rank, ext_var.var())
|
||||
}
|
||||
|
||||
RecursiveTagUnion(rec_var, tags, ext_var) => {
|
||||
let mut rank = adjust_rank(subs, young_mark, visit_mark, group_rank, *ext_var);
|
||||
let mut rank =
|
||||
adjust_rank(subs, young_mark, visit_mark, group_rank, ext_var.var());
|
||||
|
||||
for (_, index) in tags.iter_all() {
|
||||
let slice = subs[index];
|
||||
|
@ -1584,11 +1592,11 @@ fn instantiate_rigids_help(
|
|||
}
|
||||
}
|
||||
|
||||
instantiate_rigids_help(subs, max_rank, pools, ext_var);
|
||||
instantiate_rigids_help(subs, max_rank, pools, ext_var.var());
|
||||
}
|
||||
|
||||
FunctionOrTagUnion(_tag_name, _symbol, ext_var) => {
|
||||
instantiate_rigids_help(subs, max_rank, pools, ext_var);
|
||||
instantiate_rigids_help(subs, max_rank, pools, ext_var.var());
|
||||
}
|
||||
|
||||
RecursiveTagUnion(rec_var, tags, ext_var) => {
|
||||
|
@ -1602,7 +1610,7 @@ fn instantiate_rigids_help(
|
|||
}
|
||||
}
|
||||
|
||||
instantiate_rigids_help(subs, max_rank, pools, ext_var);
|
||||
instantiate_rigids_help(subs, max_rank, pools, ext_var.var());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -1815,14 +1823,14 @@ fn deep_copy_var_help(
|
|||
|
||||
let union_tags = UnionTags::from_slices(tags.labels(), new_variables);
|
||||
|
||||
let new_ext = deep_copy_var_help(subs, max_rank, pools, ext_var);
|
||||
let new_ext = ext_var.map(|v| deep_copy_var_help(subs, max_rank, pools, v));
|
||||
TagUnion(union_tags, new_ext)
|
||||
}
|
||||
|
||||
FunctionOrTagUnion(tag_name, symbol, ext_var) => FunctionOrTagUnion(
|
||||
tag_name,
|
||||
symbol,
|
||||
deep_copy_var_help(subs, max_rank, pools, ext_var),
|
||||
ext_var.map(|v| deep_copy_var_help(subs, max_rank, pools, v)),
|
||||
),
|
||||
|
||||
RecursiveTagUnion(rec_var, tags, ext_var) => {
|
||||
|
@ -1853,7 +1861,7 @@ fn deep_copy_var_help(
|
|||
|
||||
let union_tags = UnionTags::from_slices(tags.labels(), new_variables);
|
||||
|
||||
let new_ext = deep_copy_var_help(subs, max_rank, pools, ext_var);
|
||||
let new_ext = ext_var.map(|v| deep_copy_var_help(subs, max_rank, pools, v));
|
||||
let new_rec_var = deep_copy_var_help(subs, max_rank, pools, rec_var);
|
||||
FlatType::RecursiveTagUnion(new_rec_var, union_tags, new_ext)
|
||||
}
|
||||
|
|
|
@ -904,7 +904,7 @@ fn deep_copy_type_vars<C: CopyEnv>(
|
|||
})
|
||||
}
|
||||
TagUnion(tags, ext_var) => {
|
||||
let new_ext_var = descend_var!(ext_var);
|
||||
let new_ext_var = ext_var.map(|v| descend_var!(v));
|
||||
|
||||
for variables_slice_index in tags.variables() {
|
||||
let variables_slice = env.source()[variables_slice_index];
|
||||
|
@ -929,7 +929,7 @@ fn deep_copy_type_vars<C: CopyEnv>(
|
|||
})
|
||||
}
|
||||
RecursiveTagUnion(rec_var, tags, ext_var) => {
|
||||
let new_ext_var = descend_var!(ext_var);
|
||||
let new_ext_var = ext_var.map(|v| descend_var!(v));
|
||||
let new_rec_var = descend_var!(rec_var);
|
||||
|
||||
for variables_slice_index in tags.variables() {
|
||||
|
@ -956,7 +956,7 @@ fn deep_copy_type_vars<C: CopyEnv>(
|
|||
})
|
||||
}
|
||||
FunctionOrTagUnion(tag_names, symbols, ext_var) => {
|
||||
let new_ext_var = descend_var!(ext_var);
|
||||
let new_ext_var = ext_var.map(|v| descend_var!(v));
|
||||
let new_tag_names = env.clone_tag_names(tag_names);
|
||||
let new_symbols = env.clone_lambda_names(symbols);
|
||||
perform_clone!(Structure(FunctionOrTagUnion(
|
||||
|
|
|
@ -613,7 +613,7 @@ fn convert_tag(subs: &Subs, whole_var: Variable, this_tag: &TagName) -> (Union,
|
|||
|
||||
// DEVIATION: model openness by attaching a #Open constructor, that can never
|
||||
// be matched unless there's an `Anything` pattern.
|
||||
let opt_openness_tag = match subs.get_content_without_compacting(ext) {
|
||||
let opt_openness_tag = match subs.get_content_without_compacting(ext.var()) {
|
||||
FlexVar(_) | RigidVar(_) => {
|
||||
let openness_tag = TagName(NONEXHAUSIVE_CTOR.into());
|
||||
num_tags += 1;
|
||||
|
|
|
@ -13,7 +13,7 @@ use roc_module::symbol::Symbol;
|
|||
use roc_region::all::{Loc, Region};
|
||||
use roc_types::subs::{
|
||||
Content, ExhaustiveMark, FlatType, GetSubsSlice, LambdaSet, OptVariable, RecordFields,
|
||||
RedundantMark, SubsSlice, UnionLambdas, UnionTags, Variable,
|
||||
RedundantMark, SubsSlice, TagExt, UnionLambdas, UnionTags, Variable,
|
||||
};
|
||||
use roc_types::types::{AliasKind, RecordField};
|
||||
|
||||
|
@ -210,7 +210,7 @@ fn decoder_record_step_field(
|
|||
("Skip".into(), Default::default()),
|
||||
],
|
||||
),
|
||||
Variable::EMPTY_TAG_UNION,
|
||||
TagExt::Any(Variable::EMPTY_TAG_UNION),
|
||||
);
|
||||
|
||||
synth_var(env.subs, Content::Structure(flat_type))
|
||||
|
@ -257,7 +257,7 @@ fn decoder_record_step_field(
|
|||
let rec_dot_result = {
|
||||
let tag_union = FlatType::TagUnion(
|
||||
UnionTags::for_result(env.subs, field_var, decode_err_var),
|
||||
Variable::EMPTY_TAG_UNION,
|
||||
TagExt::Any(Variable::EMPTY_TAG_UNION),
|
||||
);
|
||||
|
||||
synth_var(env.subs, Content::Structure(tag_union))
|
||||
|
@ -300,7 +300,7 @@ fn decoder_record_step_field(
|
|||
let when_expr_var = {
|
||||
let flat_type = FlatType::TagUnion(
|
||||
UnionTags::for_result(env.subs, state_record_var, decode_err_var),
|
||||
Variable::EMPTY_TAG_UNION,
|
||||
TagExt::Any(Variable::EMPTY_TAG_UNION),
|
||||
);
|
||||
|
||||
synth_var(env.subs, Content::Structure(flat_type))
|
||||
|
@ -759,7 +759,7 @@ fn decoder_record_finalizer(
|
|||
let decode_err_var = {
|
||||
let flat_type = FlatType::TagUnion(
|
||||
UnionTags::tag_without_arguments(env.subs, "TooShort".into()),
|
||||
Variable::EMPTY_TAG_UNION,
|
||||
TagExt::Any(Variable::EMPTY_TAG_UNION),
|
||||
);
|
||||
|
||||
synth_var(env.subs, Content::Structure(flat_type))
|
||||
|
@ -802,7 +802,7 @@ fn decoder_record_finalizer(
|
|||
return_type_var = {
|
||||
let flat_type = FlatType::TagUnion(
|
||||
UnionTags::for_result(subs, done_record_var, decode_err_var),
|
||||
Variable::EMPTY_TAG_UNION,
|
||||
TagExt::Any(Variable::EMPTY_TAG_UNION),
|
||||
);
|
||||
|
||||
synth_var(subs, Content::Structure(flat_type))
|
||||
|
@ -946,7 +946,10 @@ fn decoder_record_initial_state(
|
|||
let union_tags = UnionTags::tag_without_arguments(subs, no_field_label.into());
|
||||
let no_field_var = synth_var(
|
||||
subs,
|
||||
Content::Structure(FlatType::TagUnion(union_tags, Variable::EMPTY_TAG_UNION)),
|
||||
Content::Structure(FlatType::TagUnion(
|
||||
union_tags,
|
||||
TagExt::Any(Variable::EMPTY_TAG_UNION),
|
||||
)),
|
||||
);
|
||||
let no_field = Expr::Tag {
|
||||
tag_union_var: no_field_var,
|
||||
|
@ -958,7 +961,10 @@ fn decoder_record_initial_state(
|
|||
let union_tags = UnionTags::for_result(subs, field_var, no_field_var);
|
||||
let result_var = synth_var(
|
||||
subs,
|
||||
Content::Structure(FlatType::TagUnion(union_tags, Variable::EMPTY_TAG_UNION)),
|
||||
Content::Structure(FlatType::TagUnion(
|
||||
union_tags,
|
||||
TagExt::Any(Variable::EMPTY_TAG_UNION),
|
||||
)),
|
||||
);
|
||||
let field_expr = Expr::Tag {
|
||||
tag_union_var: result_var,
|
||||
|
|
|
@ -14,7 +14,7 @@ use roc_module::symbol::Symbol;
|
|||
use roc_region::all::{Loc, Region};
|
||||
use roc_types::subs::{
|
||||
Content, ExhaustiveMark, FlatType, GetSubsSlice, LambdaSet, OptVariable, RecordFields,
|
||||
RedundantMark, SubsSlice, UnionLambdas, UnionTags, Variable, VariableSubsSlice,
|
||||
RedundantMark, SubsSlice, TagExt, UnionLambdas, UnionTags, Variable, VariableSubsSlice,
|
||||
};
|
||||
use roc_types::types::RecordField;
|
||||
|
||||
|
@ -67,7 +67,10 @@ pub(crate) fn derive_to_encoder(
|
|||
let union_tags = UnionTags::insert_slices_into_subs(env.subs, flex_tag_labels);
|
||||
let tag_union_var = synth_var(
|
||||
env.subs,
|
||||
Content::Structure(FlatType::TagUnion(union_tags, Variable::EMPTY_TAG_UNION)),
|
||||
Content::Structure(FlatType::TagUnion(
|
||||
union_tags,
|
||||
TagExt::Any(Variable::EMPTY_TAG_UNION),
|
||||
)),
|
||||
);
|
||||
|
||||
to_encoder_tag_union(env, tag_union_var, union_tags, def_symbol)
|
||||
|
|
|
@ -19,7 +19,7 @@ use roc_types::{
|
|||
num::int_lit_width_to_variable,
|
||||
subs::{
|
||||
Content, ExhaustiveMark, FlatType, GetSubsSlice, LambdaSet, OptVariable, RecordFields,
|
||||
RedundantMark, Subs, SubsIndex, SubsSlice, UnionLambdas, UnionTags, Variable,
|
||||
RedundantMark, Subs, SubsIndex, SubsSlice, TagExt, UnionLambdas, UnionTags, Variable,
|
||||
VariableSubsSlice,
|
||||
},
|
||||
types::RecordField,
|
||||
|
@ -146,7 +146,10 @@ fn hash_tag_union(
|
|||
let union_tags = UnionTags::insert_slices_into_subs(env.subs, flex_tag_labels);
|
||||
let tag_union_var = synth_var(
|
||||
env.subs,
|
||||
Content::Structure(FlatType::TagUnion(union_tags, Variable::EMPTY_TAG_UNION)),
|
||||
Content::Structure(FlatType::TagUnion(
|
||||
union_tags,
|
||||
TagExt::Any(Variable::EMPTY_TAG_UNION),
|
||||
)),
|
||||
);
|
||||
|
||||
(tag_union_var, union_tags)
|
||||
|
@ -305,7 +308,10 @@ fn hash_newtype_tag_union(
|
|||
let union_tags = UnionTags::from_slices(tag_name_index.as_slice(), variables_slices_slice);
|
||||
let tag_union_var = synth_var(
|
||||
env.subs,
|
||||
Content::Structure(FlatType::TagUnion(union_tags, Variable::EMPTY_TAG_UNION)),
|
||||
Content::Structure(FlatType::TagUnion(
|
||||
union_tags,
|
||||
TagExt::Any(Variable::EMPTY_TAG_UNION),
|
||||
)),
|
||||
);
|
||||
|
||||
(
|
||||
|
|
|
@ -78,7 +78,7 @@ impl FlatEncodable {
|
|||
// `t`-prefixed payload types.
|
||||
let (tags_iter, ext) = tags.unsorted_tags_and_ext(subs, ext);
|
||||
|
||||
check_derivable_ext_var(subs, ext, |ext| {
|
||||
check_derivable_ext_var(subs, ext.var(), |ext| {
|
||||
matches!(ext, Content::Structure(FlatType::EmptyTagUnion))
|
||||
})?;
|
||||
|
||||
|
|
|
@ -77,7 +77,7 @@ impl FlatHash {
|
|||
// `t`-prefixed payload types.
|
||||
let (tags_iter, ext) = tags.unsorted_tags_and_ext(subs, ext);
|
||||
|
||||
check_derivable_ext_var(subs, ext, |ext| {
|
||||
check_derivable_ext_var(subs, ext.var(), |ext| {
|
||||
matches!(ext, Content::Structure(FlatType::EmptyTagUnion))
|
||||
})?;
|
||||
|
||||
|
|
|
@ -11,7 +11,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,
|
||||
self, Content, FlatType, GetSubsSlice, Label, OptVariable, RecordFields, Subs, TagExt,
|
||||
UnsortedUnionLabels, Variable,
|
||||
};
|
||||
use roc_types::types::{gather_fields_unsorted_iter, RecordField, RecordFieldsError};
|
||||
|
@ -2061,7 +2061,7 @@ fn lambda_set_size(subs: &Subs, var: Variable) -> (usize, usize, usize) {
|
|||
stack.push((*ext, depth_any + 1, depth_lset));
|
||||
}
|
||||
FlatType::FunctionOrTagUnion(_, _, ext) => {
|
||||
stack.push((*ext, depth_any + 1, depth_lset));
|
||||
stack.push((ext.var(), depth_any + 1, depth_lset));
|
||||
}
|
||||
FlatType::TagUnion(tags, ext) => {
|
||||
for (_, payloads) in tags.iter_from_subs(subs) {
|
||||
|
@ -2069,7 +2069,7 @@ fn lambda_set_size(subs: &Subs, var: Variable) -> (usize, usize, usize) {
|
|||
stack.push((*payload, depth_any + 1, depth_lset));
|
||||
}
|
||||
}
|
||||
stack.push((*ext, depth_any + 1, depth_lset));
|
||||
stack.push((ext.var(), depth_any + 1, depth_lset));
|
||||
}
|
||||
FlatType::RecursiveTagUnion(rec_var, tags, ext) => {
|
||||
seen_rec_vars.insert(*rec_var);
|
||||
|
@ -2078,7 +2078,7 @@ fn lambda_set_size(subs: &Subs, var: Variable) -> (usize, usize, usize) {
|
|||
stack.push((*payload, depth_any + 1, depth_lset));
|
||||
}
|
||||
}
|
||||
stack.push((*ext, depth_any + 1, depth_lset));
|
||||
stack.push((ext.var(), depth_any + 1, depth_lset));
|
||||
}
|
||||
FlatType::EmptyRecord | FlatType::EmptyTagUnion => {}
|
||||
},
|
||||
|
@ -4110,13 +4110,13 @@ pub fn ext_var_is_empty_record(_subs: &Subs, _ext_var: Variable) -> bool {
|
|||
}
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
pub fn ext_var_is_empty_tag_union(subs: &Subs, ext_var: Variable) -> bool {
|
||||
pub fn ext_var_is_empty_tag_union(subs: &Subs, tag_ext: TagExt) -> bool {
|
||||
use roc_types::pretty_print::ChasedExt;
|
||||
use Content::*;
|
||||
|
||||
// the ext_var is empty
|
||||
let mut ext_fields = std::vec::Vec::new();
|
||||
match roc_types::pretty_print::chase_ext_tag_union(subs, ext_var, &mut ext_fields) {
|
||||
match roc_types::pretty_print::chase_ext_tag_union(subs, tag_ext.var(), &mut ext_fields) {
|
||||
ChasedExt::Empty => ext_fields.is_empty(),
|
||||
ChasedExt::NonEmpty { content, .. } => {
|
||||
match content {
|
||||
|
|
|
@ -708,13 +708,13 @@ trait DerivableVisitor {
|
|||
for i in tags.variables() {
|
||||
push_var_slice!(subs[i]);
|
||||
}
|
||||
stack.push(ext);
|
||||
stack.push(ext.var());
|
||||
}
|
||||
}
|
||||
FunctionOrTagUnion(_tag_name, _fn_name, ext) => {
|
||||
let descend = Self::visit_function_or_tag_union(var)?;
|
||||
if descend.0 {
|
||||
stack.push(ext);
|
||||
stack.push(ext.var());
|
||||
}
|
||||
}
|
||||
RecursiveTagUnion(rec, tags, ext) => {
|
||||
|
@ -724,7 +724,7 @@ trait DerivableVisitor {
|
|||
for i in tags.variables() {
|
||||
push_var_slice!(subs[i]);
|
||||
}
|
||||
stack.push(ext);
|
||||
stack.push(ext.var());
|
||||
}
|
||||
}
|
||||
EmptyRecord => Self::visit_empty_record(var)?,
|
||||
|
|
|
@ -29,7 +29,7 @@ use roc_region::all::Loc;
|
|||
use roc_solve_problem::TypeError;
|
||||
use roc_types::subs::{
|
||||
self, AliasVariables, Content, Descriptor, FlatType, GetSubsSlice, LambdaSet, Mark,
|
||||
OptVariable, Rank, RecordFields, Subs, SubsSlice, UlsOfVar, UnionLabels, UnionLambdas,
|
||||
OptVariable, Rank, RecordFields, Subs, SubsSlice, TagExt, UlsOfVar, UnionLabels, UnionLambdas,
|
||||
UnionTags, Variable, VariableSubsSlice,
|
||||
};
|
||||
use roc_types::types::{
|
||||
|
@ -217,7 +217,7 @@ impl Aliases {
|
|||
SubsSlice::extend_new(&mut subs.variable_slices, [err_slice, ok_slice]);
|
||||
|
||||
let union_tags = UnionTags::from_slices(tag_names_slice, variable_slices);
|
||||
let ext_var = Variable::EMPTY_TAG_UNION;
|
||||
let ext_var = TagExt::Any(Variable::EMPTY_TAG_UNION);
|
||||
let flat_type = FlatType::TagUnion(union_tags, ext_var);
|
||||
let content = Content::Structure(flat_type);
|
||||
|
||||
|
@ -1829,9 +1829,9 @@ fn open_tag_union(subs: &mut Subs, var: Variable) {
|
|||
let desc = subs.get(var);
|
||||
match desc.content {
|
||||
Structure(TagUnion(tags, ext)) => {
|
||||
if let Structure(EmptyTagUnion) = subs.get_content_without_compacting(ext) {
|
||||
let new_ext = subs.fresh_unnamed_flex_var();
|
||||
subs.set_rank(new_ext, desc.rank);
|
||||
if let Structure(EmptyTagUnion) = subs.get_content_without_compacting(ext.var()) {
|
||||
let new_ext = TagExt::Any(subs.fresh_unnamed_flex_var());
|
||||
subs.set_rank(new_ext.var(), desc.rank);
|
||||
let new_union = Structure(TagUnion(tags, new_ext));
|
||||
subs.set_content(var, new_union);
|
||||
}
|
||||
|
@ -1880,12 +1880,15 @@ fn close_pattern_matched_tag_unions(subs: &mut Subs, var: Variable) {
|
|||
Structure(TagUnion(tags, mut ext)) => {
|
||||
// Close the extension, chasing it as far as it goes.
|
||||
loop {
|
||||
match subs.get_content_without_compacting(ext) {
|
||||
match subs.get_content_without_compacting(ext.var()) {
|
||||
Structure(FlatType::EmptyTagUnion) => {
|
||||
break;
|
||||
}
|
||||
FlexVar(..) | FlexAbleVar(..) => {
|
||||
subs.set_content_unchecked(ext, Structure(FlatType::EmptyTagUnion));
|
||||
subs.set_content_unchecked(
|
||||
ext.var(),
|
||||
Structure(FlatType::EmptyTagUnion),
|
||||
);
|
||||
break;
|
||||
}
|
||||
RigidVar(..) | RigidAbleVar(..) => {
|
||||
|
@ -2682,7 +2685,7 @@ fn type_to_variable<'a>(
|
|||
let (it, ext) = roc_types::types::gather_tags_unsorted_iter(
|
||||
subs,
|
||||
UnionTags::default(),
|
||||
temp_ext_var,
|
||||
TagExt::Any(temp_ext_var),
|
||||
)
|
||||
.expect("extension var could not be seen as a tag union");
|
||||
|
||||
|
@ -3112,7 +3115,7 @@ fn roc_result_to_var(
|
|||
subs.variable_slices.push(ok_slice);
|
||||
|
||||
let union_tags = UnionTags::from_slices(Subs::RESULT_TAG_NAMES, variables);
|
||||
let ext = Variable::EMPTY_TAG_UNION;
|
||||
let ext = TagExt::Any(Variable::EMPTY_TAG_UNION);
|
||||
|
||||
let content = Content::Structure(FlatType::TagUnion(union_tags, ext));
|
||||
|
||||
|
@ -3383,7 +3386,7 @@ fn type_to_union_tags(
|
|||
union_tags: UnionTags,
|
||||
opt_ext_slice: Slice<TypeTag>,
|
||||
stack: &mut bumpalo::collections::Vec<'_, TypeToVar>,
|
||||
) -> (UnionTags, Variable) {
|
||||
) -> (UnionTags, TagExt) {
|
||||
use bumpalo::collections::Vec;
|
||||
|
||||
let (tags, _) = types.union_tag_slices(union_tags);
|
||||
|
@ -3403,7 +3406,7 @@ fn type_to_union_tags(
|
|||
insert_tags_slow_path(subs, rank, pools, arena, types, union_tags, tag_vars, stack)
|
||||
};
|
||||
|
||||
(union_tags, ext)
|
||||
(union_tags, TagExt::Any(ext))
|
||||
}
|
||||
Some(ext) => {
|
||||
let mut tag_vars = Vec::with_capacity_in(tags.len(), arena);
|
||||
|
@ -3413,7 +3416,7 @@ fn type_to_union_tags(
|
|||
let (it, ext) = roc_types::types::gather_tags_unsorted_iter(
|
||||
subs,
|
||||
UnionTags::default(),
|
||||
temp_ext_var,
|
||||
TagExt::Any(temp_ext_var),
|
||||
)
|
||||
.expect("extension var could not be seen as tag union");
|
||||
|
||||
|
@ -3745,7 +3748,8 @@ fn adjust_rank_content(
|
|||
}
|
||||
|
||||
TagUnion(tags, ext_var) => {
|
||||
let mut rank = adjust_rank(subs, young_mark, visit_mark, group_rank, *ext_var);
|
||||
let mut rank =
|
||||
adjust_rank(subs, young_mark, visit_mark, group_rank, ext_var.var());
|
||||
// For performance reasons, we only keep one representation of empty tag unions
|
||||
// in subs. That representation exists at rank 0, which we don't always want to
|
||||
// reflect the whole tag union as, because doing so may over-generalize free
|
||||
|
@ -3761,7 +3765,7 @@ fn adjust_rank_content(
|
|||
// we'll wind up with [Z, S a]{}, but it will be at rank 0, and "a" will get
|
||||
// over-generalized. Really, the empty tag union should be introduced at
|
||||
// whatever current group rank we're at, and so that's how we encode it here.
|
||||
if *ext_var == Variable::EMPTY_TAG_UNION && rank.is_generalized() {
|
||||
if ext_var.var() == Variable::EMPTY_TAG_UNION && rank.is_generalized() {
|
||||
rank = group_rank;
|
||||
}
|
||||
|
||||
|
@ -3778,11 +3782,12 @@ fn adjust_rank_content(
|
|||
}
|
||||
|
||||
FunctionOrTagUnion(_, _, ext_var) => {
|
||||
adjust_rank(subs, young_mark, visit_mark, group_rank, *ext_var)
|
||||
adjust_rank(subs, young_mark, visit_mark, group_rank, ext_var.var())
|
||||
}
|
||||
|
||||
RecursiveTagUnion(rec_var, tags, ext_var) => {
|
||||
let mut rank = adjust_rank(subs, young_mark, visit_mark, group_rank, *ext_var);
|
||||
let mut rank =
|
||||
adjust_rank(subs, young_mark, visit_mark, group_rank, ext_var.var());
|
||||
|
||||
for (_, index) in tags.iter_all() {
|
||||
let slice = subs[index];
|
||||
|
@ -4136,17 +4141,17 @@ fn deep_copy_var_help(
|
|||
TagUnion(tags, ext_var) => {
|
||||
let union_tags = copy_union!(tags);
|
||||
|
||||
TagUnion(union_tags, work!(ext_var))
|
||||
TagUnion(union_tags, ext_var.map(|v| work!(v)))
|
||||
}
|
||||
|
||||
FunctionOrTagUnion(tag_name, symbol, ext_var) => {
|
||||
FunctionOrTagUnion(tag_name, symbol, work!(ext_var))
|
||||
FunctionOrTagUnion(tag_name, symbol, ext_var.map(|v| work!(v)))
|
||||
}
|
||||
|
||||
RecursiveTagUnion(rec_var, tags, ext_var) => {
|
||||
let union_tags = copy_union!(tags);
|
||||
|
||||
RecursiveTagUnion(work!(rec_var), union_tags, work!(ext_var))
|
||||
RecursiveTagUnion(work!(rec_var), union_tags, ext_var.map(|v| work!(v)))
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -90,7 +90,7 @@ macro_rules! v {
|
|||
}
|
||||
}};
|
||||
([ $($tag:ident $($payload:expr)*),* ] as $rec_var:ident) => {{
|
||||
use roc_types::subs::{Subs, SubsIndex, Variable, Content, FlatType, UnionTags};
|
||||
use roc_types::subs::{Subs, SubsIndex, Variable, Content, FlatType, TagExt, UnionTags};
|
||||
use roc_module::ident::TagName;
|
||||
|subs: &mut Subs| {
|
||||
let $rec_var = subs.fresh_unnamed_flex_var();
|
||||
|
@ -101,7 +101,7 @@ macro_rules! v {
|
|||
let $tag = vec![ $( $payload(subs), )* ];
|
||||
)*
|
||||
let tags = UnionTags::insert_into_subs::<_, Vec<Variable>>(subs, vec![ $( (TagName(stringify!($tag).into()), $tag) ,)* ]);
|
||||
let tag_union_var = roc_derive::synth_var(subs, Content::Structure(FlatType::RecursiveTagUnion($rec_var, tags, Variable::EMPTY_TAG_UNION)));
|
||||
let tag_union_var = roc_derive::synth_var(subs, Content::Structure(FlatType::RecursiveTagUnion($rec_var, tags, TagExt::Any(Variable::EMPTY_TAG_UNION))));
|
||||
|
||||
subs.set_content(
|
||||
$rec_var,
|
||||
|
@ -115,7 +115,7 @@ macro_rules! v {
|
|||
}};
|
||||
([ $($tag:ident $($payload:expr)*),* ]$( $($ext:tt)+ )?) => {{
|
||||
#[allow(unused)]
|
||||
use roc_types::subs::{Subs, UnionTags, Content, FlatType, Variable};
|
||||
use roc_types::subs::{Subs, UnionTags, Content, FlatType, TagExt, Variable};
|
||||
#[allow(unused)]
|
||||
use roc_module::ident::TagName;
|
||||
|subs: &mut Subs| {
|
||||
|
@ -128,7 +128,7 @@ macro_rules! v {
|
|||
let mut ext = Variable::EMPTY_TAG_UNION;
|
||||
$( ext = $crate::v!($($ext)+)(subs); )?
|
||||
|
||||
roc_derive::synth_var(subs, Content::Structure(FlatType::TagUnion(tags, ext)))
|
||||
roc_derive::synth_var(subs, Content::Structure(FlatType::TagUnion(tags, TagExt::Any(ext))))
|
||||
}
|
||||
}};
|
||||
(Symbol::$sym:ident $($arg:expr)*) => {{
|
||||
|
|
|
@ -242,7 +242,7 @@ fn find_names_needed(
|
|||
}
|
||||
|
||||
find_names_needed(
|
||||
*ext_var,
|
||||
ext_var.var(),
|
||||
subs,
|
||||
roots,
|
||||
root_appearances,
|
||||
|
@ -252,7 +252,7 @@ fn find_names_needed(
|
|||
}
|
||||
Structure(FunctionOrTagUnion(_, _, ext_var)) => {
|
||||
find_names_needed(
|
||||
*ext_var,
|
||||
ext_var.var(),
|
||||
subs,
|
||||
roots,
|
||||
root_appearances,
|
||||
|
@ -277,7 +277,7 @@ fn find_names_needed(
|
|||
}
|
||||
|
||||
find_names_needed(
|
||||
*ext_var,
|
||||
ext_var.var(),
|
||||
subs,
|
||||
roots,
|
||||
root_appearances,
|
||||
|
@ -1209,7 +1209,7 @@ fn write_flat_type<'a>(
|
|||
ctx,
|
||||
subs,
|
||||
buf,
|
||||
ExtContent::for_tag(subs, new_ext_var, pol, &env.debug),
|
||||
ExtContent::for_tag(subs, new_ext_var.var(), pol, &env.debug),
|
||||
parens,
|
||||
pol,
|
||||
)
|
||||
|
@ -1224,7 +1224,7 @@ fn write_flat_type<'a>(
|
|||
.iter()
|
||||
.map(|t| (t.clone(), vec![])),
|
||||
);
|
||||
let ext_content = write_sorted_tags(env, ctx, subs, buf, &tags, *ext_var, pol);
|
||||
let ext_content = write_sorted_tags(env, ctx, subs, buf, &tags, ext_var.var(), pol);
|
||||
|
||||
buf.push(']');
|
||||
|
||||
|
@ -1253,7 +1253,7 @@ fn write_flat_type<'a>(
|
|||
ctx,
|
||||
subs,
|
||||
buf,
|
||||
ExtContent::for_tag(subs, new_ext_var, pol, &env.debug),
|
||||
ExtContent::for_tag(subs, new_ext_var.var(), pol, &env.debug),
|
||||
parens,
|
||||
pol,
|
||||
);
|
||||
|
@ -1306,12 +1306,12 @@ pub fn chase_ext_tag_union(
|
|||
Content::Structure(EmptyTagUnion) => ChasedExt::Empty,
|
||||
Content::Structure(TagUnion(tags, ext_var)) => {
|
||||
push_union(subs, tags, fields);
|
||||
chase_ext_tag_union(subs, *ext_var, fields)
|
||||
chase_ext_tag_union(subs, ext_var.var(), fields)
|
||||
}
|
||||
|
||||
Content::Structure(RecursiveTagUnion(_, tags, ext_var)) => {
|
||||
push_union(subs, tags, fields);
|
||||
chase_ext_tag_union(subs, *ext_var, fields)
|
||||
chase_ext_tag_union(subs, ext_var.var(), fields)
|
||||
}
|
||||
Content::Structure(FunctionOrTagUnion(tag_names, _, ext_var)) => {
|
||||
fields.extend(
|
||||
|
@ -1320,7 +1320,7 @@ pub fn chase_ext_tag_union(
|
|||
.map(|t| (t.clone(), vec![])),
|
||||
);
|
||||
|
||||
chase_ext_tag_union(subs, *ext_var, fields)
|
||||
chase_ext_tag_union(subs, ext_var.var(), fields)
|
||||
}
|
||||
|
||||
Content::Alias(_, _, var, _) => chase_ext_tag_union(subs, *var, fields),
|
||||
|
|
|
@ -17,7 +17,7 @@ use crate::unification_table::{self, UnificationTable};
|
|||
// please change it to the lower number.
|
||||
// if it went up, maybe check that the change is really required
|
||||
roc_error_macros::assert_sizeof_all!(Descriptor, 5 * 8 + 4);
|
||||
roc_error_macros::assert_sizeof_all!(FlatType, 3 * 8);
|
||||
roc_error_macros::assert_sizeof_all!(FlatType, 3 * 8 + 4);
|
||||
roc_error_macros::assert_sizeof_all!(UnionTags, 12);
|
||||
roc_error_macros::assert_sizeof_all!(RecordFields, 2 * 8);
|
||||
|
||||
|
@ -1007,17 +1007,17 @@ impl Default for VarStore {
|
|||
|
||||
impl VarStore {
|
||||
#[inline(always)]
|
||||
pub fn new(next_var: Variable) -> Self {
|
||||
debug_assert!(next_var.0 >= Variable::FIRST_USER_SPACE_VAR.0);
|
||||
pub fn new(next: Variable) -> Self {
|
||||
debug_assert!(next.0 >= Variable::FIRST_USER_SPACE_VAR.0);
|
||||
|
||||
VarStore { next: next_var.0 }
|
||||
VarStore { next: next.0 }
|
||||
}
|
||||
|
||||
pub fn new_from_subs(subs: &Subs) -> Self {
|
||||
let next_var = (subs.utable.len()) as u32;
|
||||
debug_assert!(next_var >= Variable::FIRST_USER_SPACE_VAR.0);
|
||||
let next = (subs.utable.len()) as u32;
|
||||
debug_assert!(next >= Variable::FIRST_USER_SPACE_VAR.0);
|
||||
|
||||
VarStore { next: next_var }
|
||||
VarStore { next: next }
|
||||
}
|
||||
|
||||
pub fn peek(&mut self) -> u32 {
|
||||
|
@ -1745,7 +1745,7 @@ impl Subs {
|
|||
subs.set_content(Variable::BOOL_ENUM, {
|
||||
Content::Structure(FlatType::TagUnion(
|
||||
bool_union_tags,
|
||||
Variable::EMPTY_TAG_UNION,
|
||||
TagExt::Any(Variable::EMPTY_TAG_UNION),
|
||||
))
|
||||
});
|
||||
|
||||
|
@ -1965,16 +1965,11 @@ impl Subs {
|
|||
result
|
||||
}
|
||||
|
||||
pub fn mark_tag_union_recursive(
|
||||
&mut self,
|
||||
recursive: Variable,
|
||||
tags: UnionTags,
|
||||
ext_var: Variable,
|
||||
) {
|
||||
pub fn mark_tag_union_recursive(&mut self, recursive: Variable, tags: UnionTags, ext: TagExt) {
|
||||
let (rec_var, new_tags) = self.mark_union_recursive_help(recursive, tags);
|
||||
|
||||
let new_ext_var = self.explicit_substitute(recursive, rec_var, ext_var);
|
||||
let flat_type = FlatType::RecursiveTagUnion(rec_var, new_tags, new_ext_var);
|
||||
let new_ext = ext.map(|v| self.explicit_substitute(recursive, rec_var, v));
|
||||
let flat_type = FlatType::RecursiveTagUnion(rec_var, new_tags, new_ext);
|
||||
|
||||
self.set_content(recursive, Content::Structure(flat_type));
|
||||
}
|
||||
|
@ -2281,7 +2276,7 @@ impl From<Content> for Descriptor {
|
|||
roc_error_macros::assert_sizeof_all!(Content, 4 * 8);
|
||||
roc_error_macros::assert_sizeof_all!((Symbol, AliasVariables, Variable), 8 + 12 + 4);
|
||||
roc_error_macros::assert_sizeof_all!(AliasVariables, 12);
|
||||
roc_error_macros::assert_sizeof_all!(FlatType, 3 * 8);
|
||||
roc_error_macros::assert_sizeof_all!(FlatType, 3 * 8 + 4);
|
||||
roc_error_macros::assert_sizeof_all!(LambdaSet, 3 * 8 + 4);
|
||||
|
||||
roc_error_macros::assert_sizeof_aarch64!((Variable, Option<Lowercase>), 4 * 8);
|
||||
|
@ -2514,19 +2509,61 @@ impl Content {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub enum TagExt {
|
||||
/// This tag extension variable measures polymorphism in the openness of the tag,
|
||||
/// or the lack thereof. It can only be unified with
|
||||
/// - an empty tag union, or
|
||||
/// - a rigid extension variable
|
||||
///
|
||||
/// Openness extensions are used when tag annotations are introduced, since tag union
|
||||
/// annotations may contain hidden extension variables which we want to reflect openness,
|
||||
/// but not growth in the monomorphic size of the tag. For example, openness extensions enable
|
||||
/// catching
|
||||
///
|
||||
/// ```ignore
|
||||
/// f : [A]
|
||||
/// f = if Bool.true then A else B
|
||||
/// ```
|
||||
///
|
||||
/// as an error rather than resolving as [A][B].
|
||||
Openness(Variable),
|
||||
/// This tag extension can grow unboundedly.
|
||||
Any(Variable),
|
||||
}
|
||||
|
||||
impl TagExt {
|
||||
pub fn var(&self) -> Variable {
|
||||
match self {
|
||||
TagExt::Openness(v) | TagExt::Any(v) => *v,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn map(&self, f: impl FnOnce(Variable) -> Variable) -> Self {
|
||||
match self {
|
||||
Self::Openness(v) => Self::Openness(f(*v)),
|
||||
Self::Any(v) => Self::Any(f(*v)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_any(&self) -> bool {
|
||||
matches!(self, Self::Any(..))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub enum FlatType {
|
||||
Apply(Symbol, VariableSubsSlice),
|
||||
Func(VariableSubsSlice, Variable, Variable),
|
||||
Record(RecordFields, Variable),
|
||||
TagUnion(UnionTags, Variable),
|
||||
TagUnion(UnionTags, TagExt),
|
||||
|
||||
/// `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),
|
||||
FunctionOrTagUnion(SubsSlice<TagName>, SubsSlice<Symbol>, TagExt),
|
||||
|
||||
RecursiveTagUnion(Variable, UnionTags, Variable),
|
||||
RecursiveTagUnion(Variable, UnionTags, TagExt),
|
||||
EmptyRecord,
|
||||
EmptyTagUnion,
|
||||
}
|
||||
|
@ -2864,7 +2901,7 @@ impl UnionTags {
|
|||
pub fn unsorted_iterator<'a>(
|
||||
&'a self,
|
||||
subs: &'a Subs,
|
||||
ext: Variable,
|
||||
ext: TagExt,
|
||||
) -> impl Iterator<Item = (&TagName, &[Variable])> + 'a {
|
||||
let (it, _) =
|
||||
crate::types::gather_tags_unsorted_iter(subs, *self, ext).expect("not a tag union");
|
||||
|
@ -2878,8 +2915,8 @@ impl UnionTags {
|
|||
pub fn unsorted_tags_and_ext<'a>(
|
||||
&'a self,
|
||||
subs: &'a Subs,
|
||||
ext: Variable,
|
||||
) -> (UnsortedUnionLabels<'a, TagName>, Variable) {
|
||||
ext: TagExt,
|
||||
) -> (UnsortedUnionLabels<'a, TagName>, TagExt) {
|
||||
let (it, ext) =
|
||||
crate::types::gather_tags_unsorted_iter(subs, *self, ext).expect("not a tag union");
|
||||
let f = move |(label, slice): (_, SubsSlice<Variable>)| (label, subs.get_subs_slice(slice));
|
||||
|
@ -2892,9 +2929,9 @@ impl UnionTags {
|
|||
pub fn sorted_iterator_and_ext<'a>(
|
||||
&'_ self,
|
||||
subs: &'a Subs,
|
||||
ext: Variable,
|
||||
) -> (SortedTagsIterator<'a>, Variable) {
|
||||
if is_empty_tag_union(subs, ext) {
|
||||
ext: TagExt,
|
||||
) -> (SortedTagsIterator<'a>, TagExt) {
|
||||
if is_empty_tag_union(subs, ext.var()) {
|
||||
(
|
||||
Box::new(self.iter_all().map(move |(i1, i2)| {
|
||||
let tag_name: &TagName = &subs[i1];
|
||||
|
@ -2921,9 +2958,9 @@ impl UnionTags {
|
|||
pub fn sorted_slices_iterator_and_ext<'a>(
|
||||
&'_ self,
|
||||
subs: &'a Subs,
|
||||
ext: Variable,
|
||||
) -> (SortedTagsSlicesIterator<'a>, Variable) {
|
||||
if is_empty_tag_union(subs, ext) {
|
||||
ext: TagExt,
|
||||
) -> (SortedTagsSlicesIterator<'a>, TagExt) {
|
||||
if is_empty_tag_union(subs, ext.var()) {
|
||||
(
|
||||
Box::new(self.iter_all().map(move |(i1, i2)| {
|
||||
let tag_name: &TagName = &subs[i1];
|
||||
|
@ -2990,14 +3027,14 @@ pub fn is_empty_tag_union(subs: &Subs, mut var: Variable) -> bool {
|
|||
return false;
|
||||
}
|
||||
|
||||
var = *sub_ext;
|
||||
var = sub_ext.var();
|
||||
}
|
||||
Structure(RecursiveTagUnion(_, sub_fields, sub_ext)) => {
|
||||
if !sub_fields.is_empty() {
|
||||
return false;
|
||||
}
|
||||
|
||||
var = *sub_ext;
|
||||
var = sub_ext.var();
|
||||
}
|
||||
|
||||
Alias(_, _, actual_var, _) => {
|
||||
|
@ -3274,24 +3311,23 @@ fn occurs(
|
|||
.chain(subs.get_subs_slice(*arg_vars).iter());
|
||||
short_circuit(subs, root_var, seen, it)
|
||||
}
|
||||
Record(vars_by_field, ext_var) => {
|
||||
Record(vars_by_field, ext) => {
|
||||
let slice = SubsSlice::new(vars_by_field.variables_start, vars_by_field.length);
|
||||
let it = once(ext_var).chain(subs.get_subs_slice(slice).iter());
|
||||
let it = once(ext).chain(subs.get_subs_slice(slice).iter());
|
||||
short_circuit(subs, root_var, seen, it)
|
||||
}
|
||||
TagUnion(tags, ext_var) => {
|
||||
TagUnion(tags, ext) => {
|
||||
occurs_union(subs, root_var, seen, tags)?;
|
||||
|
||||
short_circuit_help(subs, root_var, seen, *ext_var)
|
||||
short_circuit_help(subs, root_var, seen, ext.var())
|
||||
}
|
||||
FunctionOrTagUnion(_, _, ext_var) => {
|
||||
let it = once(ext_var);
|
||||
short_circuit(subs, root_var, seen, it)
|
||||
FunctionOrTagUnion(_, _, ext) => {
|
||||
short_circuit(subs, root_var, seen, once(&ext.var()))
|
||||
}
|
||||
RecursiveTagUnion(_, tags, ext_var) => {
|
||||
RecursiveTagUnion(_, tags, ext) => {
|
||||
occurs_union(subs, root_var, seen, tags)?;
|
||||
|
||||
short_circuit_help(subs, root_var, seen, *ext_var)
|
||||
short_circuit_help(subs, root_var, seen, ext.var())
|
||||
}
|
||||
EmptyRecord | EmptyTagUnion => Ok(()),
|
||||
},
|
||||
|
@ -3426,33 +3462,33 @@ fn explicit_substitute(
|
|||
Structure(Func(arg_vars, new_closure_var, new_ret_var)),
|
||||
);
|
||||
}
|
||||
TagUnion(tags, ext_var) => {
|
||||
let new_ext_var = explicit_substitute(subs, from, to, ext_var, seen);
|
||||
TagUnion(tags, ext) => {
|
||||
let new_ext = ext.map(|v| explicit_substitute(subs, from, to, v, seen));
|
||||
|
||||
let union_tags = explicit_substitute_union(subs, from, to, tags, seen);
|
||||
|
||||
subs.set_content(in_var, Structure(TagUnion(union_tags, new_ext_var)));
|
||||
subs.set_content(in_var, Structure(TagUnion(union_tags, new_ext)));
|
||||
}
|
||||
FunctionOrTagUnion(tag_name, symbol, ext_var) => {
|
||||
let new_ext_var = explicit_substitute(subs, from, to, ext_var, seen);
|
||||
FunctionOrTagUnion(tag_name, symbol, ext) => {
|
||||
let new_ext = ext.map(|v| explicit_substitute(subs, from, to, v, seen));
|
||||
subs.set_content(
|
||||
in_var,
|
||||
Structure(FunctionOrTagUnion(tag_name, symbol, new_ext_var)),
|
||||
Structure(FunctionOrTagUnion(tag_name, symbol, new_ext)),
|
||||
);
|
||||
}
|
||||
RecursiveTagUnion(rec_var, tags, ext_var) => {
|
||||
RecursiveTagUnion(rec_var, tags, ext) => {
|
||||
// NOTE rec_var is not substituted, verify that this is correct!
|
||||
let new_ext_var = explicit_substitute(subs, from, to, ext_var, seen);
|
||||
let new_ext = ext.map(|v| explicit_substitute(subs, from, to, v, seen));
|
||||
|
||||
let union_tags = explicit_substitute_union(subs, from, to, tags, seen);
|
||||
|
||||
subs.set_content(
|
||||
in_var,
|
||||
Structure(RecursiveTagUnion(rec_var, union_tags, new_ext_var)),
|
||||
Structure(RecursiveTagUnion(rec_var, union_tags, new_ext)),
|
||||
);
|
||||
}
|
||||
Record(vars_by_field, ext_var) => {
|
||||
let new_ext_var = explicit_substitute(subs, from, to, ext_var, seen);
|
||||
Record(vars_by_field, ext) => {
|
||||
let new_ext = explicit_substitute(subs, from, to, ext, seen);
|
||||
|
||||
for index in vars_by_field.iter_variables() {
|
||||
let var = subs[index];
|
||||
|
@ -3460,7 +3496,7 @@ fn explicit_substitute(
|
|||
subs[index] = new_var;
|
||||
}
|
||||
|
||||
subs.set_content(in_var, Structure(Record(vars_by_field, new_ext_var)));
|
||||
subs.set_content(in_var, Structure(Record(vars_by_field, new_ext)));
|
||||
}
|
||||
|
||||
EmptyRecord | EmptyTagUnion => {}
|
||||
|
@ -3648,8 +3684,8 @@ fn get_var_names(
|
|||
|
||||
FlatType::EmptyRecord | FlatType::EmptyTagUnion => taken_names,
|
||||
|
||||
FlatType::Record(vars_by_field, ext_var) => {
|
||||
let mut accum = get_var_names(subs, ext_var, taken_names);
|
||||
FlatType::Record(vars_by_field, ext) => {
|
||||
let mut accum = get_var_names(subs, ext, taken_names);
|
||||
|
||||
for var_index in vars_by_field.iter_variables() {
|
||||
let arg_var = subs[var_index];
|
||||
|
@ -3659,17 +3695,17 @@ fn get_var_names(
|
|||
|
||||
accum
|
||||
}
|
||||
FlatType::TagUnion(tags, ext_var) => {
|
||||
let taken_names = get_var_names(subs, ext_var, taken_names);
|
||||
FlatType::TagUnion(tags, ext) => {
|
||||
let taken_names = get_var_names(subs, ext.var(), taken_names);
|
||||
get_var_names_union(subs, tags, taken_names)
|
||||
}
|
||||
|
||||
FlatType::FunctionOrTagUnion(_, _, ext_var) => {
|
||||
get_var_names(subs, ext_var, taken_names)
|
||||
FlatType::FunctionOrTagUnion(_, _, ext) => {
|
||||
get_var_names(subs, ext.var(), taken_names)
|
||||
}
|
||||
|
||||
FlatType::RecursiveTagUnion(rec_var, tags, ext_var) => {
|
||||
let taken_names = get_var_names(subs, ext_var, taken_names);
|
||||
FlatType::RecursiveTagUnion(rec_var, tags, ext) => {
|
||||
let taken_names = get_var_names(subs, ext.var(), taken_names);
|
||||
let taken_names = get_var_names(subs, rec_var, taken_names);
|
||||
get_var_names_union(subs, tags, taken_names)
|
||||
}
|
||||
|
@ -3934,7 +3970,7 @@ fn flat_type_to_err_type(
|
|||
EmptyRecord => ErrorType::Record(SendMap::default(), TypeExt::Closed),
|
||||
EmptyTagUnion => ErrorType::TagUnion(SendMap::default(), TypeExt::Closed, pol),
|
||||
|
||||
Record(vars_by_field, ext_var) => {
|
||||
Record(vars_by_field, ext) => {
|
||||
let mut err_fields = SendMap::default();
|
||||
|
||||
for (i1, i2, i3) in vars_by_field.iter_all() {
|
||||
|
@ -3956,7 +3992,7 @@ fn flat_type_to_err_type(
|
|||
err_fields.insert(label, err_record_field);
|
||||
}
|
||||
|
||||
match var_to_err_type(subs, state, ext_var, pol).unwrap_structural_alias() {
|
||||
match var_to_err_type(subs, state, ext, pol).unwrap_structural_alias() {
|
||||
ErrorType::Record(sub_fields, sub_ext) => {
|
||||
ErrorType::Record(sub_fields.union(err_fields), sub_ext)
|
||||
}
|
||||
|
@ -3976,10 +4012,10 @@ fn flat_type_to_err_type(
|
|||
}
|
||||
}
|
||||
|
||||
TagUnion(tags, ext_var) => {
|
||||
TagUnion(tags, ext) => {
|
||||
let err_tags = union_tags_to_err_tags(subs, state, tags, pol);
|
||||
|
||||
match var_to_err_type(subs, state, ext_var, pol).unwrap_structural_alias() {
|
||||
match var_to_err_type(subs, state, ext.var(), pol).unwrap_structural_alias() {
|
||||
ErrorType::TagUnion(sub_tags, sub_ext, pol) => {
|
||||
ErrorType::TagUnion(sub_tags.union(err_tags), sub_ext, pol)
|
||||
}
|
||||
|
@ -4002,14 +4038,14 @@ fn flat_type_to_err_type(
|
|||
}
|
||||
}
|
||||
|
||||
FunctionOrTagUnion(tag_names, _, ext_var) => {
|
||||
FunctionOrTagUnion(tag_names, _, ext) => {
|
||||
let tag_names = subs.get_subs_slice(tag_names);
|
||||
|
||||
let mut err_tags: SendMap<TagName, Vec<_>> = SendMap::default();
|
||||
|
||||
err_tags.extend(tag_names.iter().map(|t| (t.clone(), vec![])));
|
||||
|
||||
match var_to_err_type(subs, state, ext_var, pol).unwrap_structural_alias() {
|
||||
match var_to_err_type(subs, state, ext.var(), pol).unwrap_structural_alias() {
|
||||
ErrorType::TagUnion(sub_tags, sub_ext, pol) => {
|
||||
ErrorType::TagUnion(sub_tags.union(err_tags), sub_ext, pol)
|
||||
}
|
||||
|
@ -4032,14 +4068,14 @@ fn flat_type_to_err_type(
|
|||
}
|
||||
}
|
||||
|
||||
RecursiveTagUnion(rec_var, tags, ext_var) => {
|
||||
RecursiveTagUnion(rec_var, tags, ext) => {
|
||||
state.recursive_tag_unions_seen.push(rec_var);
|
||||
|
||||
let err_tags = union_tags_to_err_tags(subs, state, tags, pol);
|
||||
|
||||
let rec_error_type = Box::new(var_to_err_type(subs, state, rec_var, pol));
|
||||
|
||||
match var_to_err_type(subs, state, ext_var, pol).unwrap_structural_alias() {
|
||||
match var_to_err_type(subs, state, ext.var(), pol).unwrap_structural_alias() {
|
||||
ErrorType::RecursiveTagUnion(rec_var, sub_tags, sub_ext, pol) => {
|
||||
debug_assert!(rec_var == rec_error_type);
|
||||
ErrorType::RecursiveTagUnion(rec_error_type, sub_tags.union(err_tags), sub_ext, pol)
|
||||
|
@ -4328,17 +4364,17 @@ impl StorageSubs {
|
|||
),
|
||||
FlatType::TagUnion(union_tags, ext) => FlatType::TagUnion(
|
||||
Self::offset_tag_union(offsets, *union_tags),
|
||||
Self::offset_variable(offsets, *ext),
|
||||
ext.map(|v| Self::offset_variable(offsets, v)),
|
||||
),
|
||||
FlatType::FunctionOrTagUnion(tag_names, symbol, ext) => FlatType::FunctionOrTagUnion(
|
||||
Self::offset_tag_name_slice(offsets, *tag_names),
|
||||
*symbol,
|
||||
Self::offset_variable(offsets, *ext),
|
||||
ext.map(|v| Self::offset_variable(offsets, v)),
|
||||
),
|
||||
FlatType::RecursiveTagUnion(rec, union_tags, ext) => FlatType::RecursiveTagUnion(
|
||||
Self::offset_variable(offsets, *rec),
|
||||
Self::offset_tag_union(offsets, *union_tags),
|
||||
Self::offset_variable(offsets, *ext),
|
||||
ext.map(|v| Self::offset_variable(offsets, v)),
|
||||
),
|
||||
FlatType::EmptyRecord => FlatType::EmptyRecord,
|
||||
FlatType::EmptyTagUnion => FlatType::EmptyTagUnion,
|
||||
|
@ -4629,7 +4665,7 @@ fn storage_copy_var_to_help(env: &mut StorageCopyVarToEnv<'_>, var: Variable) ->
|
|||
|
||||
same @ EmptyRecord | same @ EmptyTagUnion => same,
|
||||
|
||||
Record(fields, ext_var) => {
|
||||
Record(fields, ext) => {
|
||||
let record_fields = {
|
||||
let new_variables =
|
||||
VariableSubsSlice::reserve_into_subs(env.target, fields.len());
|
||||
|
@ -4661,17 +4697,17 @@ fn storage_copy_var_to_help(env: &mut StorageCopyVarToEnv<'_>, var: Variable) ->
|
|||
}
|
||||
};
|
||||
|
||||
Record(record_fields, storage_copy_var_to_help(env, ext_var))
|
||||
Record(record_fields, storage_copy_var_to_help(env, ext))
|
||||
}
|
||||
|
||||
TagUnion(tags, ext_var) => {
|
||||
let new_ext = storage_copy_var_to_help(env, ext_var);
|
||||
TagUnion(tags, ext) => {
|
||||
let new_ext = ext.map(|v| storage_copy_var_to_help(env, v));
|
||||
let union_tags = storage_copy_union(env, tags);
|
||||
|
||||
TagUnion(union_tags, new_ext)
|
||||
}
|
||||
|
||||
FunctionOrTagUnion(tag_names, symbols, ext_var) => {
|
||||
FunctionOrTagUnion(tag_names, symbols, ext) => {
|
||||
let new_tag_names = SubsSlice::extend_new(
|
||||
&mut env.target.tag_names,
|
||||
env.source.get_subs_slice(tag_names).iter().cloned(),
|
||||
|
@ -4685,14 +4721,14 @@ fn storage_copy_var_to_help(env: &mut StorageCopyVarToEnv<'_>, var: Variable) ->
|
|||
FunctionOrTagUnion(
|
||||
new_tag_names,
|
||||
new_symbols,
|
||||
storage_copy_var_to_help(env, ext_var),
|
||||
ext.map(|v| storage_copy_var_to_help(env, v)),
|
||||
)
|
||||
}
|
||||
|
||||
RecursiveTagUnion(rec_var, tags, ext_var) => {
|
||||
RecursiveTagUnion(rec_var, tags, ext) => {
|
||||
let union_tags = storage_copy_union(env, tags);
|
||||
|
||||
let new_ext = storage_copy_var_to_help(env, ext_var);
|
||||
let new_ext = ext.map(|v| storage_copy_var_to_help(env, v));
|
||||
let new_rec_var = storage_copy_var_to_help(env, rec_var);
|
||||
|
||||
RecursiveTagUnion(new_rec_var, union_tags, new_ext)
|
||||
|
@ -5077,7 +5113,7 @@ fn copy_import_to_help(env: &mut CopyImportEnv<'_>, max_rank: Rank, var: Variabl
|
|||
|
||||
same @ EmptyRecord | same @ EmptyTagUnion => same,
|
||||
|
||||
Record(fields, ext_var) => {
|
||||
Record(fields, ext) => {
|
||||
let record_fields = {
|
||||
let new_variables =
|
||||
VariableSubsSlice::reserve_into_subs(env.target, fields.len());
|
||||
|
@ -5109,18 +5145,18 @@ fn copy_import_to_help(env: &mut CopyImportEnv<'_>, max_rank: Rank, var: Variabl
|
|||
}
|
||||
};
|
||||
|
||||
Record(record_fields, copy_import_to_help(env, max_rank, ext_var))
|
||||
Record(record_fields, copy_import_to_help(env, max_rank, ext))
|
||||
}
|
||||
|
||||
TagUnion(tags, ext_var) => {
|
||||
let new_ext = copy_import_to_help(env, max_rank, ext_var);
|
||||
TagUnion(tags, ext) => {
|
||||
let new_ext = ext.map(|v| copy_import_to_help(env, max_rank, v));
|
||||
|
||||
let union_tags = copy_union(env, max_rank, tags);
|
||||
|
||||
TagUnion(union_tags, new_ext)
|
||||
}
|
||||
|
||||
FunctionOrTagUnion(tag_names, symbols, ext_var) => {
|
||||
FunctionOrTagUnion(tag_names, symbols, ext) => {
|
||||
let new_tag_names = SubsSlice::extend_new(
|
||||
&mut env.target.tag_names,
|
||||
env.source.get_subs_slice(tag_names).iter().cloned(),
|
||||
|
@ -5131,17 +5167,15 @@ fn copy_import_to_help(env: &mut CopyImportEnv<'_>, max_rank: Rank, var: Variabl
|
|||
env.source.get_subs_slice(symbols).iter().cloned(),
|
||||
);
|
||||
|
||||
FunctionOrTagUnion(
|
||||
new_tag_names,
|
||||
new_symbols,
|
||||
copy_import_to_help(env, max_rank, ext_var),
|
||||
)
|
||||
let new_ext = ext.map(|v| copy_import_to_help(env, max_rank, v));
|
||||
|
||||
FunctionOrTagUnion(new_tag_names, new_symbols, new_ext)
|
||||
}
|
||||
|
||||
RecursiveTagUnion(rec_var, tags, ext_var) => {
|
||||
RecursiveTagUnion(rec_var, tags, ext) => {
|
||||
let union_tags = copy_union(env, max_rank, tags);
|
||||
|
||||
let new_ext = copy_import_to_help(env, max_rank, ext_var);
|
||||
let new_ext = ext.map(|v| copy_import_to_help(env, max_rank, v));
|
||||
let new_rec_var = copy_import_to_help(env, max_rank, rec_var);
|
||||
|
||||
RecursiveTagUnion(new_rec_var, union_tags, new_ext)
|
||||
|
@ -5412,31 +5446,31 @@ fn instantiate_rigids_help(subs: &mut Subs, max_rank: Rank, initial: Variable) {
|
|||
EmptyRecord => (),
|
||||
EmptyTagUnion => (),
|
||||
|
||||
Record(fields, ext_var) => {
|
||||
Record(fields, ext) => {
|
||||
let fields = *fields;
|
||||
let ext_var = *ext_var;
|
||||
let ext = *ext;
|
||||
stack.extend(var_slice!(fields.variables()));
|
||||
|
||||
stack.push(ext_var);
|
||||
stack.push(ext);
|
||||
}
|
||||
TagUnion(tags, ext_var) => {
|
||||
TagUnion(tags, ext) => {
|
||||
let tags = *tags;
|
||||
let ext_var = *ext_var;
|
||||
let ext = *ext;
|
||||
|
||||
for slice_index in tags.variables() {
|
||||
let slice = subs.variable_slices[slice_index.index as usize];
|
||||
stack.extend(var_slice!(slice));
|
||||
}
|
||||
|
||||
stack.push(ext_var);
|
||||
stack.push(ext.var());
|
||||
}
|
||||
FunctionOrTagUnion(_, _, ext_var) => {
|
||||
stack.push(*ext_var);
|
||||
FunctionOrTagUnion(_, _, ext) => {
|
||||
stack.push(ext.var());
|
||||
}
|
||||
|
||||
RecursiveTagUnion(rec_var, tags, ext_var) => {
|
||||
RecursiveTagUnion(rec_var, tags, ext) => {
|
||||
let tags = *tags;
|
||||
let ext_var = *ext_var;
|
||||
let ext = *ext;
|
||||
let rec_var = *rec_var;
|
||||
|
||||
for slice_index in tags.variables() {
|
||||
|
@ -5444,7 +5478,7 @@ fn instantiate_rigids_help(subs: &mut Subs, max_rank: Rank, initial: Variable) {
|
|||
stack.extend(var_slice!(slice));
|
||||
}
|
||||
|
||||
stack.push(ext_var);
|
||||
stack.push(ext.var());
|
||||
stack.push(rec_var);
|
||||
}
|
||||
},
|
||||
|
@ -5535,10 +5569,10 @@ pub fn get_member_lambda_sets_at_region(subs: &Subs, var: Variable, target_regio
|
|||
.iter()
|
||||
.flat_map(|slice| subs.get_subs_slice(*slice)),
|
||||
);
|
||||
stack.push(*ext);
|
||||
stack.push(ext.var());
|
||||
}
|
||||
FlatType::FunctionOrTagUnion(_, _, ext) => {
|
||||
stack.push(*ext);
|
||||
stack.push(ext.var());
|
||||
}
|
||||
FlatType::RecursiveTagUnion(rec, tags, ext) => {
|
||||
stack.push(*rec);
|
||||
|
@ -5547,7 +5581,7 @@ pub fn get_member_lambda_sets_at_region(subs: &Subs, var: Variable, target_regio
|
|||
.iter()
|
||||
.flat_map(|slice| subs.get_subs_slice(*slice)),
|
||||
);
|
||||
stack.push(*ext);
|
||||
stack.push(ext.var());
|
||||
}
|
||||
FlatType::EmptyRecord | FlatType::EmptyTagUnion => {}
|
||||
},
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use crate::num::NumericRange;
|
||||
use crate::pretty_print::Parens;
|
||||
use crate::subs::{
|
||||
GetSubsSlice, RecordFields, Subs, UnionTags, VarStore, Variable, VariableSubsSlice,
|
||||
GetSubsSlice, RecordFields, Subs, TagExt, UnionTags, VarStore, Variable, VariableSubsSlice,
|
||||
};
|
||||
use roc_collections::all::{HumanIndex, ImMap, ImSet, MutMap, MutSet, SendMap};
|
||||
use roc_collections::soa::{Index, Slice};
|
||||
|
@ -3385,7 +3385,7 @@ pub struct RecordStructure {
|
|||
pub struct TagUnionStructure<'a> {
|
||||
/// Invariant: these should be sorted!
|
||||
pub fields: Vec<(TagName, &'a [Variable])>,
|
||||
pub ext: Variable,
|
||||
pub ext: TagExt,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
|
@ -4250,11 +4250,11 @@ pub enum GatherTagsError {
|
|||
pub fn gather_tags_unsorted_iter(
|
||||
subs: &Subs,
|
||||
other_fields: UnionTags,
|
||||
mut var: Variable,
|
||||
mut ext: TagExt,
|
||||
) -> Result<
|
||||
(
|
||||
impl Iterator<Item = (&TagName, VariableSubsSlice)> + '_,
|
||||
Variable,
|
||||
TagExt,
|
||||
),
|
||||
GatherTagsError,
|
||||
> {
|
||||
|
@ -4267,7 +4267,7 @@ pub fn gather_tags_unsorted_iter(
|
|||
let mut seen_head_union = false;
|
||||
|
||||
loop {
|
||||
match subs.get_content_without_compacting(var) {
|
||||
match subs.get_content_without_compacting(ext.var()) {
|
||||
Structure(TagUnion(sub_fields, sub_ext)) => {
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
|
@ -4277,7 +4277,7 @@ pub fn gather_tags_unsorted_iter(
|
|||
|
||||
stack.push(*sub_fields);
|
||||
|
||||
var = *sub_ext;
|
||||
ext = *sub_ext;
|
||||
}
|
||||
|
||||
Structure(FunctionOrTagUnion(_tag_name_index, _, _sub_ext)) => {
|
||||
|
@ -4296,7 +4296,8 @@ pub fn gather_tags_unsorted_iter(
|
|||
}
|
||||
|
||||
Alias(_, _, actual_var, _) => {
|
||||
var = *actual_var;
|
||||
debug_assert!(matches!(ext, TagExt::Any(..)));
|
||||
ext = TagExt::Any(*actual_var);
|
||||
}
|
||||
|
||||
Structure(EmptyTagUnion) => break,
|
||||
|
@ -4307,7 +4308,7 @@ pub fn gather_tags_unsorted_iter(
|
|||
|
||||
Error => break,
|
||||
|
||||
_ => return Err(GatherTagsError::NotATagUnion(var)),
|
||||
_ => return Err(GatherTagsError::NotATagUnion(ext.var())),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4321,15 +4322,15 @@ pub fn gather_tags_unsorted_iter(
|
|||
(tag_name, subs_slice)
|
||||
});
|
||||
|
||||
Ok((it, var))
|
||||
Ok((it, ext))
|
||||
}
|
||||
|
||||
pub fn gather_tags_slices(
|
||||
subs: &Subs,
|
||||
other_fields: UnionTags,
|
||||
var: Variable,
|
||||
) -> Result<(Vec<(TagName, VariableSubsSlice)>, Variable), GatherTagsError> {
|
||||
let (it, ext) = gather_tags_unsorted_iter(subs, other_fields, var)?;
|
||||
ext: TagExt,
|
||||
) -> Result<(Vec<(TagName, VariableSubsSlice)>, TagExt), GatherTagsError> {
|
||||
let (it, ext) = gather_tags_unsorted_iter(subs, other_fields, ext)?;
|
||||
|
||||
let mut result: Vec<_> = it
|
||||
.map(|(ref_label, field): (_, VariableSubsSlice)| (ref_label.clone(), field))
|
||||
|
@ -4343,9 +4344,9 @@ pub fn gather_tags_slices(
|
|||
pub fn gather_tags(
|
||||
subs: &Subs,
|
||||
other_fields: UnionTags,
|
||||
var: Variable,
|
||||
ext: TagExt,
|
||||
) -> Result<TagUnionStructure, GatherTagsError> {
|
||||
let (it, ext) = gather_tags_unsorted_iter(subs, other_fields, var)?;
|
||||
let (it, ext) = gather_tags_unsorted_iter(subs, other_fields, ext)?;
|
||||
|
||||
let mut result: Vec<_> = it
|
||||
.map(|(ref_label, field): (_, VariableSubsSlice)| {
|
||||
|
|
|
@ -268,7 +268,7 @@ fn find_chain(subs: &Subs, left: Variable, right: Variable) -> impl Iterator<Ite
|
|||
subs.get_subs_slice(*left_sym),
|
||||
subs.get_subs_slice(*right_sym)
|
||||
);
|
||||
let mut chain = help(subs, needle, *left_var, *right_var)?;
|
||||
let mut chain = help(subs, needle, left_var.var(), right_var.var())?;
|
||||
chain.push((left, right));
|
||||
Ok(chain)
|
||||
}
|
||||
|
|
|
@ -10,8 +10,8 @@ use roc_types::num::{FloatWidth, IntLitWidth, NumericRange};
|
|||
use roc_types::subs::Content::{self, *};
|
||||
use roc_types::subs::{
|
||||
AliasVariables, Descriptor, ErrorTypeContext, FlatType, GetSubsSlice, LambdaSet, Mark,
|
||||
OptVariable, RecordFields, Subs, SubsIndex, SubsSlice, UlsOfVar, UnionLabels, UnionLambdas,
|
||||
UnionTags, Variable, VariableSubsSlice,
|
||||
OptVariable, RecordFields, Subs, SubsIndex, SubsSlice, TagExt, UlsOfVar, UnionLabels,
|
||||
UnionLambdas, UnionTags, Variable, VariableSubsSlice,
|
||||
};
|
||||
use roc_types::types::{
|
||||
AliasKind, DoesNotImplementAbility, ErrorType, Mismatch, Polarity, RecordField, Uls,
|
||||
|
@ -2335,10 +2335,10 @@ where
|
|||
fn separate_union_tags(
|
||||
subs: &Subs,
|
||||
fields1: UnionTags,
|
||||
ext1: Variable,
|
||||
ext1: TagExt,
|
||||
fields2: UnionTags,
|
||||
ext2: Variable,
|
||||
) -> (Separate<TagName, VariableSubsSlice>, Variable, Variable) {
|
||||
ext2: TagExt,
|
||||
) -> (Separate<TagName, VariableSubsSlice>, TagExt, TagExt) {
|
||||
let (it1, new_ext1) = fields1.sorted_slices_iterator_and_ext(subs, ext1);
|
||||
let (it2, new_ext2) = fields2.sorted_slices_iterator_and_ext(subs, ext2);
|
||||
|
||||
|
@ -2375,11 +2375,11 @@ enum Rec {
|
|||
/// of the variables under unification
|
||||
fn should_extend_ext_with_uninhabited_type(
|
||||
subs: &Subs,
|
||||
ext1: Variable,
|
||||
ext1: TagExt,
|
||||
candidate_type: Variable,
|
||||
) -> bool {
|
||||
matches!(
|
||||
subs.get_content_without_compacting(ext1),
|
||||
subs.get_content_without_compacting(ext1.var()),
|
||||
Content::Structure(FlatType::EmptyTagUnion)
|
||||
) && !subs.is_inhabited(candidate_type)
|
||||
}
|
||||
|
@ -2398,7 +2398,7 @@ fn close_uninhabited_extended_union(subs: &mut Subs, mut var: Variable) {
|
|||
}
|
||||
Structure(FlatType::TagUnion(_, ext))
|
||||
| Structure(FlatType::RecursiveTagUnion(_, _, ext)) => {
|
||||
var = *ext;
|
||||
var = ext.var();
|
||||
}
|
||||
_ => internal_error!("not a tag union"),
|
||||
}
|
||||
|
@ -2412,9 +2412,9 @@ fn unify_tag_unions<M: MetaCollector>(
|
|||
pool: &mut Pool,
|
||||
ctx: &Context,
|
||||
tags1: UnionTags,
|
||||
initial_ext1: Variable,
|
||||
initial_ext1: TagExt,
|
||||
tags2: UnionTags,
|
||||
initial_ext2: Variable,
|
||||
initial_ext2: TagExt,
|
||||
recursion_var: Rec,
|
||||
) -> Outcome<M> {
|
||||
let (separate, mut ext1, mut ext2) =
|
||||
|
@ -2423,7 +2423,7 @@ fn unify_tag_unions<M: MetaCollector>(
|
|||
let shared_tags = separate.in_both;
|
||||
|
||||
if let (true, Content::Structure(FlatType::EmptyTagUnion)) =
|
||||
(ctx.mode.is_present(), env.subs.get(ext1).content)
|
||||
(ctx.mode.is_present(), env.subs.get(ext1.var()).content)
|
||||
{
|
||||
if !separate.only_in_2.is_empty() {
|
||||
// Create a new extension variable that we'll fill in with the
|
||||
|
@ -2440,7 +2440,8 @@ fn unify_tag_unions<M: MetaCollector>(
|
|||
// [A M, B] += [A N]
|
||||
// the nested tag `A` **will** grow, but we don't need to modify
|
||||
// the top level extension variable for that!
|
||||
let new_ext = fresh(env, pool, ctx, Content::FlexVar(None));
|
||||
debug_assert!(ext1.is_any());
|
||||
let new_ext = TagExt::Any(fresh(env, pool, ctx, Content::FlexVar(None)));
|
||||
let new_union = Structure(FlatType::TagUnion(tags1, new_ext));
|
||||
let mut new_desc = ctx.first_desc;
|
||||
new_desc.content = new_union;
|
||||
|
@ -2453,7 +2454,8 @@ fn unify_tag_unions<M: MetaCollector>(
|
|||
if separate.only_in_1.is_empty() {
|
||||
if separate.only_in_2.is_empty() {
|
||||
let ext_outcome = if ctx.mode.is_eq() {
|
||||
unify_pool(env, pool, ext1, ext2, ctx.mode)
|
||||
// TODO(openness)
|
||||
unify_pool(env, pool, ext1.var(), ext2.var(), ctx.mode)
|
||||
} else {
|
||||
// In a presence context, we don't care about ext2 being equal to ext1
|
||||
Outcome::default()
|
||||
|
@ -2488,7 +2490,8 @@ fn unify_tag_unions<M: MetaCollector>(
|
|||
let extend_ext_with_uninhabited =
|
||||
should_extend_ext_with_uninhabited_type(env.subs, ext1, extra_tags_in_2);
|
||||
if extend_ext_with_uninhabited {
|
||||
let new_ext = fresh(env, pool, ctx, Content::FlexVar(None));
|
||||
debug_assert!(ext1.is_any());
|
||||
let new_ext = TagExt::Any(fresh(env, pool, ctx, Content::FlexVar(None)));
|
||||
let new_union = Structure(FlatType::TagUnion(tags1, new_ext));
|
||||
let mut new_desc = ctx.first_desc;
|
||||
new_desc.content = new_union;
|
||||
|
@ -2497,7 +2500,7 @@ fn unify_tag_unions<M: MetaCollector>(
|
|||
ext1 = new_ext;
|
||||
}
|
||||
|
||||
let ext_outcome = unify_pool(env, pool, ext1, extra_tags_in_2, ctx.mode);
|
||||
let ext_outcome = unify_pool(env, pool, ext1.var(), extra_tags_in_2, ctx.mode);
|
||||
|
||||
if !ext_outcome.mismatches.is_empty() {
|
||||
return ext_outcome;
|
||||
|
@ -2509,7 +2512,7 @@ fn unify_tag_unions<M: MetaCollector>(
|
|||
ctx,
|
||||
shared_tags,
|
||||
OtherTags2::Empty,
|
||||
extra_tags_in_2,
|
||||
ext1.map(|_| extra_tags_in_2),
|
||||
recursion_var,
|
||||
);
|
||||
|
||||
|
@ -2537,7 +2540,8 @@ fn unify_tag_unions<M: MetaCollector>(
|
|||
let extend_ext_with_uninhabited =
|
||||
should_extend_ext_with_uninhabited_type(env.subs, ext2, extra_tags_in_1);
|
||||
if extend_ext_with_uninhabited {
|
||||
let new_ext = fresh(env, pool, ctx, Content::FlexVar(None));
|
||||
debug_assert!(ext2.is_any());
|
||||
let new_ext = TagExt::Any(fresh(env, pool, ctx, Content::FlexVar(None)));
|
||||
let new_union = Structure(FlatType::TagUnion(tags2, new_ext));
|
||||
let mut new_desc = ctx.second_desc;
|
||||
new_desc.content = new_union;
|
||||
|
@ -2546,7 +2550,7 @@ fn unify_tag_unions<M: MetaCollector>(
|
|||
ext2 = new_ext;
|
||||
}
|
||||
|
||||
let ext_outcome = unify_pool(env, pool, extra_tags_in_1, ext2, ctx.mode);
|
||||
let ext_outcome = unify_pool(env, pool, extra_tags_in_1, ext2.var(), ctx.mode);
|
||||
|
||||
if !ext_outcome.mismatches.is_empty() {
|
||||
return ext_outcome;
|
||||
|
@ -2564,7 +2568,7 @@ fn unify_tag_unions<M: MetaCollector>(
|
|||
ctx,
|
||||
shared_tags,
|
||||
OtherTags2::Empty,
|
||||
extra_tags_in_1,
|
||||
ext2.map(|_| extra_tags_in_1),
|
||||
recursion_var,
|
||||
);
|
||||
total_outcome.union(shared_tags_outcome);
|
||||
|
@ -2585,7 +2589,7 @@ fn unify_tag_unions<M: MetaCollector>(
|
|||
} else {
|
||||
Content::FlexVar(None)
|
||||
};
|
||||
let ext = fresh(env, pool, ctx, ext_content);
|
||||
let ext = TagExt::Any(fresh(env, pool, ctx, ext_content));
|
||||
let flat_type1 = FlatType::TagUnion(unique_tags1, ext);
|
||||
let flat_type2 = FlatType::TagUnion(unique_tags2, ext);
|
||||
|
||||
|
@ -2609,7 +2613,7 @@ fn unify_tag_unions<M: MetaCollector>(
|
|||
let mut total_outcome = Outcome::default();
|
||||
let snapshot = env.subs.snapshot();
|
||||
|
||||
let ext1_outcome = unify_pool(env, pool, ext1, sub2, ctx.mode);
|
||||
let ext1_outcome = unify_pool(env, pool, ext1.var(), sub2, ctx.mode);
|
||||
if !ext1_outcome.mismatches.is_empty() {
|
||||
env.subs.rollback_to(snapshot);
|
||||
return ext1_outcome;
|
||||
|
@ -2617,7 +2621,7 @@ fn unify_tag_unions<M: MetaCollector>(
|
|||
total_outcome.union(ext1_outcome);
|
||||
|
||||
if ctx.mode.is_eq() {
|
||||
let ext2_outcome = unify_pool(env, pool, sub1, ext2, ctx.mode);
|
||||
let ext2_outcome = unify_pool(env, pool, sub1, ext2.var(), ctx.mode);
|
||||
if !ext2_outcome.mismatches.is_empty() {
|
||||
env.subs.rollback_to(snapshot);
|
||||
return ext2_outcome;
|
||||
|
@ -2746,7 +2750,7 @@ fn unify_shared_tags<M: MetaCollector>(
|
|||
ctx: &Context,
|
||||
shared_tags: Vec<(TagName, (VariableSubsSlice, VariableSubsSlice))>,
|
||||
other_tags: OtherTags2,
|
||||
ext: Variable,
|
||||
ext: TagExt,
|
||||
recursion_var: Rec,
|
||||
) -> Outcome<M> {
|
||||
let mut matching_tags = Vec::default();
|
||||
|
@ -2874,7 +2878,7 @@ fn unify_shared_tags_merge<M: MetaCollector>(
|
|||
env: &mut Env,
|
||||
ctx: &Context,
|
||||
new_tags: UnionTags,
|
||||
new_ext_var: Variable,
|
||||
new_ext: TagExt,
|
||||
recursion_var: Rec,
|
||||
) -> Outcome<M> {
|
||||
if env.was_fixed(ctx.first) && env.was_fixed(ctx.second) {
|
||||
|
@ -2888,10 +2892,10 @@ fn unify_shared_tags_merge<M: MetaCollector>(
|
|||
}
|
||||
|
||||
let flat_type = match recursion_var {
|
||||
Rec::None => FlatType::TagUnion(new_tags, new_ext_var),
|
||||
Rec::None => FlatType::TagUnion(new_tags, new_ext),
|
||||
Rec::Left(rec) | Rec::Right(rec) | Rec::Both(rec, _) => {
|
||||
debug_assert!(is_recursion_var(env.subs, rec), "{:?}", env.subs.dbg(rec));
|
||||
FlatType::RecursiveTagUnion(rec, new_tags, new_ext_var)
|
||||
FlatType::RecursiveTagUnion(rec, new_tags, new_ext)
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -2927,11 +2931,11 @@ fn unify_flat_type<M: MetaCollector>(
|
|||
(EmptyTagUnion, EmptyTagUnion) => merge(env, ctx, Structure(*left)),
|
||||
|
||||
(TagUnion(tags, ext), EmptyTagUnion) if tags.is_empty() => {
|
||||
unify_pool(env, pool, *ext, ctx.second, ctx.mode)
|
||||
unify_pool(env, pool, ext.var(), ctx.second, ctx.mode)
|
||||
}
|
||||
|
||||
(EmptyTagUnion, TagUnion(tags, ext)) if tags.is_empty() => {
|
||||
unify_pool(env, pool, ctx.first, *ext, ctx.mode)
|
||||
unify_pool(env, pool, ctx.first, ext.var(), ctx.mode)
|
||||
}
|
||||
|
||||
(TagUnion(tags1, ext1), TagUnion(tags2, ext2)) => {
|
||||
|
@ -3599,7 +3603,7 @@ fn unify_function_or_tag_union_and_func<M: MetaCollector>(
|
|||
ctx: &Context,
|
||||
tag_names_slice: SubsSlice<TagName>,
|
||||
tag_fn_lambdas: SubsSlice<Symbol>,
|
||||
tag_ext: Variable,
|
||||
tag_ext: TagExt,
|
||||
function_arguments: VariableSubsSlice,
|
||||
function_return: Variable,
|
||||
function_lambda_set: Variable,
|
||||
|
@ -3678,10 +3682,10 @@ fn unify_two_function_or_tag_unions<M: MetaCollector>(
|
|||
ctx: &Context,
|
||||
tag_names_1: SubsSlice<TagName>,
|
||||
tag_symbols_1: SubsSlice<Symbol>,
|
||||
ext1: Variable,
|
||||
ext1: TagExt,
|
||||
tag_names_2: SubsSlice<TagName>,
|
||||
tag_symbols_2: SubsSlice<Symbol>,
|
||||
ext2: Variable,
|
||||
ext2: TagExt,
|
||||
) -> Outcome<M> {
|
||||
let merged_tags = {
|
||||
let mut all_tags: Vec<_> = (env.subs.get_subs_slice(tag_names_1).iter())
|
||||
|
@ -3702,7 +3706,7 @@ fn unify_two_function_or_tag_unions<M: MetaCollector>(
|
|||
SubsSlice::extend_new(&mut env.subs.symbol_names, all_lambdas)
|
||||
};
|
||||
|
||||
let mut outcome = unify_pool(env, pool, ext1, ext2, ctx.mode);
|
||||
let mut outcome = unify_pool(env, pool, ext1.var(), ext2.var(), ctx.mode);
|
||||
if !outcome.mismatches.is_empty() {
|
||||
return outcome;
|
||||
}
|
||||
|
|
|
@ -17,7 +17,9 @@ use roc_parse::ast::{AssignedField, Collection, Expr, Pattern, StrLiteral};
|
|||
use roc_region::all::{Loc, Region};
|
||||
use roc_std::RocDec;
|
||||
use roc_target::TargetInfo;
|
||||
use roc_types::subs::{Content, FlatType, GetSubsSlice, RecordFields, Subs, UnionTags, Variable};
|
||||
use roc_types::subs::{
|
||||
Content, FlatType, GetSubsSlice, RecordFields, Subs, TagExt, UnionTags, Variable,
|
||||
};
|
||||
|
||||
use crate::{ReplApp, ReplAppMemory};
|
||||
|
||||
|
@ -116,7 +118,7 @@ fn get_newtype_tag_and_var(
|
|||
};
|
||||
|
||||
let vars = tags
|
||||
.unsorted_iterator(env.subs, Variable::EMPTY_TAG_UNION)
|
||||
.unsorted_iterator(env.subs, TagExt::Any(Variable::EMPTY_TAG_UNION))
|
||||
.find(|(tag, _)| **tag == tag_name)
|
||||
.unwrap()
|
||||
.1;
|
||||
|
@ -244,7 +246,7 @@ fn get_tags_vars_and_variant<'a>(
|
|||
opt_rec_var: Option<Variable>,
|
||||
) -> (MutMap<TagName, std::vec::Vec<Variable>>, UnionVariant<'a>) {
|
||||
let tags_vec: std::vec::Vec<(TagName, std::vec::Vec<Variable>)> = tags
|
||||
.unsorted_iterator(env.subs, Variable::EMPTY_TAG_UNION)
|
||||
.unsorted_iterator(env.subs, TagExt::Any(Variable::EMPTY_TAG_UNION))
|
||||
.map(|(a, b)| (a.clone(), b.to_vec()))
|
||||
.collect();
|
||||
|
||||
|
@ -1286,7 +1288,7 @@ fn byte_to_ast<'a>(env: &mut Env<'a, '_>, value: u8, content: &Content) -> Expr<
|
|||
debug_assert!(tags.len() > 2);
|
||||
|
||||
let tags_vec: std::vec::Vec<(TagName, std::vec::Vec<Variable>)> = tags
|
||||
.unsorted_iterator(env.subs, Variable::EMPTY_TAG_UNION)
|
||||
.unsorted_iterator(env.subs, TagExt::Any(Variable::EMPTY_TAG_UNION))
|
||||
.map(|(a, b)| (a.clone(), b.to_vec()))
|
||||
.collect();
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue