Add a notion of "openness" tag extensions suitable only for size-polymorphism

This commit is contained in:
Ayaz Hafiz 2023-01-12 17:17:53 -06:00
parent 5f5d6a42d1
commit 1c93727822
No known key found for this signature in database
GPG key ID: 0E2A37416A25EF58
18 changed files with 302 additions and 233 deletions

View file

@ -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)
}

View file

@ -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(

View file

@ -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;

View file

@ -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,

View file

@ -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)

View file

@ -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),
)),
);
(

View file

@ -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))
})?;

View file

@ -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))
})?;

View file

@ -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 {

View file

@ -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)?,

View file

@ -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)))
}
};

View file

@ -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)*) => {{

View file

@ -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),

View file

@ -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 => {}
},

View file

@ -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)| {

View file

@ -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)
}

View file

@ -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;
}

View file

@ -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();