mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-02 16:21:11 +00:00
Collect tags from extension variables during monomorphization
Fixes #2365
This commit is contained in:
parent
2b3f347eec
commit
b2f2fcd6a8
5 changed files with 194 additions and 85 deletions
|
@ -5118,41 +5118,42 @@ fn register_capturing_closure<'a>(
|
||||||
|
|
||||||
let is_self_recursive = !matches!(recursive, roc_can::expr::Recursive::NotRecursive);
|
let is_self_recursive = !matches!(recursive, roc_can::expr::Recursive::NotRecursive);
|
||||||
|
|
||||||
// does this function capture any local values?
|
let captured_symbols = match *env.subs.get_content_without_compacting(function_type) {
|
||||||
let function_layout = layout_cache.raw_from_var(env.arena, function_type, env.subs);
|
Content::Structure(FlatType::Func(_, closure_var, _)) => {
|
||||||
|
match LambdaSet::from_var(env.arena, env.subs, closure_var, env.ptr_bytes) {
|
||||||
let captured_symbols = match function_layout {
|
Ok(lambda_set) => {
|
||||||
Ok(RawFunctionLayout::Function(_, lambda_set, _)) => {
|
if let Layout::Struct(&[]) = lambda_set.runtime_representation() {
|
||||||
if let Layout::Struct(&[]) = lambda_set.runtime_representation() {
|
CapturedSymbols::None
|
||||||
CapturedSymbols::None
|
} else {
|
||||||
} else {
|
let mut temp = Vec::from_iter_in(captured_symbols, env.arena);
|
||||||
let mut temp = Vec::from_iter_in(captured_symbols, env.arena);
|
temp.sort();
|
||||||
temp.sort();
|
CapturedSymbols::Captured(temp.into_bump_slice())
|
||||||
CapturedSymbols::Captured(temp.into_bump_slice())
|
}
|
||||||
|
}
|
||||||
|
Err(_) => {
|
||||||
|
// just allow this. see https://github.com/rtfeldman/roc/issues/1585
|
||||||
|
if captured_symbols.is_empty() {
|
||||||
|
CapturedSymbols::None
|
||||||
|
} else {
|
||||||
|
let mut temp = Vec::from_iter_in(captured_symbols, env.arena);
|
||||||
|
temp.sort();
|
||||||
|
CapturedSymbols::Captured(temp.into_bump_slice())
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(RawFunctionLayout::ZeroArgumentThunk(_)) => {
|
_ => {
|
||||||
// top-level thunks cannot capture any variables
|
// This is a value (zero-argument thunk); it cannot capture any variables.
|
||||||
debug_assert!(
|
debug_assert!(
|
||||||
captured_symbols.is_empty(),
|
captured_symbols.is_empty(),
|
||||||
"{:?} with layout {:?} {:?} {:?}",
|
"{:?} with layout {:?} {:?} {:?}",
|
||||||
&captured_symbols,
|
&captured_symbols,
|
||||||
function_layout,
|
layout_cache.raw_from_var(env.arena, function_type, env.subs),
|
||||||
env.subs,
|
env.subs,
|
||||||
(function_type, closure_type, closure_ext_var),
|
(function_type, closure_type, closure_ext_var),
|
||||||
);
|
);
|
||||||
CapturedSymbols::None
|
CapturedSymbols::None
|
||||||
}
|
}
|
||||||
Err(_) => {
|
|
||||||
// just allow this. see https://github.com/rtfeldman/roc/issues/1585
|
|
||||||
if captured_symbols.is_empty() {
|
|
||||||
CapturedSymbols::None
|
|
||||||
} else {
|
|
||||||
let mut temp = Vec::from_iter_in(captured_symbols, env.arena);
|
|
||||||
temp.sort();
|
|
||||||
CapturedSymbols::Captured(temp.into_bump_slice())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let partial_proc = PartialProc::from_named_function(
|
let partial_proc = PartialProc::from_named_function(
|
||||||
|
|
|
@ -7,7 +7,7 @@ use roc_module::ident::{Lowercase, TagName};
|
||||||
use roc_module::symbol::{Interns, Symbol};
|
use roc_module::symbol::{Interns, Symbol};
|
||||||
use roc_problem::can::RuntimeError;
|
use roc_problem::can::RuntimeError;
|
||||||
use roc_types::subs::{
|
use roc_types::subs::{
|
||||||
Content, FlatType, RecordFields, Subs, UnionTags, Variable, VariableSubsSlice,
|
Content, FlatType, RecordFields, Subs, UnionTags, UnsortedUnionTags, Variable,
|
||||||
};
|
};
|
||||||
use roc_types::types::{gather_fields_unsorted_iter, RecordField};
|
use roc_types::types::{gather_fields_unsorted_iter, RecordField};
|
||||||
use std::collections::hash_map::Entry;
|
use std::collections::hash_map::Entry;
|
||||||
|
@ -1571,18 +1571,26 @@ fn layout_from_flat_type<'a>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TagUnion(tags, ext_var) => {
|
TagUnion(tags, ext_var) => {
|
||||||
|
let (tags, ext_var) = tags.unsorted_tags_and_ext(subs, ext_var);
|
||||||
|
|
||||||
debug_assert!(ext_var_is_empty_tag_union(subs, ext_var));
|
debug_assert!(ext_var_is_empty_tag_union(subs, ext_var));
|
||||||
|
|
||||||
Ok(layout_from_tag_union(arena, tags, subs, env.ptr_bytes))
|
Ok(layout_from_tag_union(arena, &tags, subs, env.ptr_bytes))
|
||||||
}
|
}
|
||||||
FunctionOrTagUnion(tag_name, _, ext_var) => {
|
FunctionOrTagUnion(tag_name, _, ext_var) => {
|
||||||
debug_assert!(ext_var_is_empty_tag_union(subs, ext_var));
|
debug_assert!(
|
||||||
|
ext_var_is_empty_tag_union(subs, ext_var),
|
||||||
|
"If ext_var wasn't empty, this wouldn't be a FunctionOrTagUnion!"
|
||||||
|
);
|
||||||
|
|
||||||
let tags = UnionTags::from_tag_name_index(tag_name);
|
let union_tags = UnionTags::from_tag_name_index(tag_name);
|
||||||
|
let (tags, _) = union_tags.unsorted_tags_and_ext(subs, ext_var);
|
||||||
|
|
||||||
Ok(layout_from_tag_union(arena, tags, subs, env.ptr_bytes))
|
Ok(layout_from_tag_union(arena, &tags, subs, env.ptr_bytes))
|
||||||
}
|
}
|
||||||
RecursiveTagUnion(rec_var, tags, ext_var) => {
|
RecursiveTagUnion(rec_var, tags, ext_var) => {
|
||||||
|
let (tags, ext_var) = tags.unsorted_tags_and_ext(subs, ext_var);
|
||||||
|
|
||||||
debug_assert!(ext_var_is_empty_tag_union(subs, ext_var));
|
debug_assert!(ext_var_is_empty_tag_union(subs, ext_var));
|
||||||
|
|
||||||
// some observations
|
// some observations
|
||||||
|
@ -1594,9 +1602,9 @@ fn layout_from_flat_type<'a>(
|
||||||
// That means none of the optimizations for enums or single tag tag unions apply
|
// That means none of the optimizations for enums or single tag tag unions apply
|
||||||
|
|
||||||
let rec_var = subs.get_root_key_without_compacting(rec_var);
|
let rec_var = subs.get_root_key_without_compacting(rec_var);
|
||||||
let mut tag_layouts = Vec::with_capacity_in(tags.len(), arena);
|
let mut tag_layouts = Vec::with_capacity_in(tags.tags.len(), arena);
|
||||||
|
|
||||||
let tags_vec = cheap_sort_tags(arena, tags, subs);
|
let tags_vec = cheap_sort_tags(&tags);
|
||||||
|
|
||||||
let mut nullable = None;
|
let mut nullable = None;
|
||||||
|
|
||||||
|
@ -1610,7 +1618,7 @@ fn layout_from_flat_type<'a>(
|
||||||
}
|
}
|
||||||
|
|
||||||
env.insert_seen(rec_var);
|
env.insert_seen(rec_var);
|
||||||
for (index, (_name, variables)) in tags_vec.into_iter().enumerate() {
|
for (index, &(_name, variables)) in tags_vec.iter().enumerate() {
|
||||||
if matches!(nullable, Some(i) if i == index as TagIdIntType) {
|
if matches!(nullable, Some(i) if i == index as TagIdIntType) {
|
||||||
// don't add the nullable case
|
// don't add the nullable case
|
||||||
continue;
|
continue;
|
||||||
|
@ -1618,8 +1626,7 @@ fn layout_from_flat_type<'a>(
|
||||||
|
|
||||||
let mut tag_layout = Vec::with_capacity_in(variables.len() + 1, arena);
|
let mut tag_layout = Vec::with_capacity_in(variables.len() + 1, arena);
|
||||||
|
|
||||||
for var_index in variables {
|
for &var in variables {
|
||||||
let var = subs[var_index];
|
|
||||||
// TODO does this cause problems with mutually recursive unions?
|
// TODO does this cause problems with mutually recursive unions?
|
||||||
if rec_var == subs.get_root_key_without_compacting(var) {
|
if rec_var == subs.get_root_key_without_compacting(var) {
|
||||||
tag_layout.push(Layout::RecursivePointer);
|
tag_layout.push(Layout::RecursivePointer);
|
||||||
|
@ -1902,13 +1909,14 @@ fn is_recursive_tag_union(layout: &Layout) -> bool {
|
||||||
|
|
||||||
fn union_sorted_tags_help_new<'a>(
|
fn union_sorted_tags_help_new<'a>(
|
||||||
arena: &'a Bump,
|
arena: &'a Bump,
|
||||||
mut tags_vec: Vec<(&'_ TagName, VariableSubsSlice)>,
|
tags_list: &[(&'_ TagName, &[Variable])],
|
||||||
opt_rec_var: Option<Variable>,
|
opt_rec_var: Option<Variable>,
|
||||||
subs: &Subs,
|
subs: &Subs,
|
||||||
ptr_bytes: u32,
|
ptr_bytes: u32,
|
||||||
) -> UnionVariant<'a> {
|
) -> UnionVariant<'a> {
|
||||||
// sort up front; make sure the ordering stays intact!
|
// sort up front; make sure the ordering stays intact!
|
||||||
tags_vec.sort_unstable_by(|(a, _), (b, _)| a.cmp(b));
|
let mut tags_list = Vec::from_iter_in(tags_list.iter(), arena);
|
||||||
|
tags_list.sort_unstable_by(|(a, _), (b, _)| a.cmp(b));
|
||||||
|
|
||||||
let mut env = Env {
|
let mut env = Env {
|
||||||
arena,
|
arena,
|
||||||
|
@ -1917,27 +1925,26 @@ fn union_sorted_tags_help_new<'a>(
|
||||||
ptr_bytes,
|
ptr_bytes,
|
||||||
};
|
};
|
||||||
|
|
||||||
match tags_vec.len() {
|
match tags_list.len() {
|
||||||
0 => {
|
0 => {
|
||||||
// trying to instantiate a type with no values
|
// trying to instantiate a type with no values
|
||||||
UnionVariant::Never
|
UnionVariant::Never
|
||||||
}
|
}
|
||||||
1 => {
|
1 => {
|
||||||
let (tag_name, arguments) = tags_vec.remove(0);
|
let &(tag_name, arguments) = tags_list.remove(0);
|
||||||
let tag_name = tag_name.clone();
|
let tag_name = tag_name.clone();
|
||||||
|
|
||||||
// just one tag in the union (but with arguments) can be a struct
|
// just one tag in the union (but with arguments) can be a struct
|
||||||
let mut layouts = Vec::with_capacity_in(tags_vec.len(), arena);
|
let mut layouts = Vec::with_capacity_in(tags_list.len(), arena);
|
||||||
|
|
||||||
// special-case NUM_AT_NUM: if its argument is a FlexVar, make it Int
|
// special-case NUM_AT_NUM: if its argument is a FlexVar, make it Int
|
||||||
match tag_name {
|
match tag_name {
|
||||||
TagName::Private(Symbol::NUM_AT_NUM) => {
|
TagName::Private(Symbol::NUM_AT_NUM) => {
|
||||||
let var = subs[arguments.into_iter().next().unwrap()];
|
let var = arguments[0];
|
||||||
layouts.push(unwrap_num_tag(subs, var, ptr_bytes).expect("invalid num layout"));
|
layouts.push(unwrap_num_tag(subs, var, ptr_bytes).expect("invalid num layout"));
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
for var_index in arguments {
|
for &var in arguments {
|
||||||
let var = subs[var_index];
|
|
||||||
match Layout::from_var(&mut env, var) {
|
match Layout::from_var(&mut env, var) {
|
||||||
Ok(layout) => {
|
Ok(layout) => {
|
||||||
layouts.push(layout);
|
layouts.push(layout);
|
||||||
|
@ -1980,7 +1987,7 @@ fn union_sorted_tags_help_new<'a>(
|
||||||
}
|
}
|
||||||
num_tags => {
|
num_tags => {
|
||||||
// default path
|
// default path
|
||||||
let mut answer = Vec::with_capacity_in(tags_vec.len(), arena);
|
let mut answer = Vec::with_capacity_in(tags_list.len(), arena);
|
||||||
let mut has_any_arguments = false;
|
let mut has_any_arguments = false;
|
||||||
|
|
||||||
let mut nullable: Option<(TagIdIntType, TagName)> = None;
|
let mut nullable: Option<(TagIdIntType, TagName)> = None;
|
||||||
|
@ -1988,7 +1995,7 @@ fn union_sorted_tags_help_new<'a>(
|
||||||
// only recursive tag unions can be nullable
|
// only recursive tag unions can be nullable
|
||||||
let is_recursive = opt_rec_var.is_some();
|
let is_recursive = opt_rec_var.is_some();
|
||||||
if is_recursive && GENERATE_NULLABLE {
|
if is_recursive && GENERATE_NULLABLE {
|
||||||
for (index, (name, variables)) in tags_vec.iter().enumerate() {
|
for (index, (name, variables)) in tags_list.iter().enumerate() {
|
||||||
if variables.is_empty() {
|
if variables.is_empty() {
|
||||||
nullable = Some((index as TagIdIntType, (*name).clone()));
|
nullable = Some((index as TagIdIntType, (*name).clone()));
|
||||||
break;
|
break;
|
||||||
|
@ -1996,7 +2003,7 @@ fn union_sorted_tags_help_new<'a>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (index, (tag_name, arguments)) in tags_vec.into_iter().enumerate() {
|
for (index, &(tag_name, arguments)) in tags_list.into_iter().enumerate() {
|
||||||
// reserve space for the tag discriminant
|
// reserve space for the tag discriminant
|
||||||
if matches!(nullable, Some((i, _)) if i as usize == index) {
|
if matches!(nullable, Some((i, _)) if i as usize == index) {
|
||||||
debug_assert!(arguments.is_empty());
|
debug_assert!(arguments.is_empty());
|
||||||
|
@ -2005,8 +2012,7 @@ fn union_sorted_tags_help_new<'a>(
|
||||||
|
|
||||||
let mut arg_layouts = Vec::with_capacity_in(arguments.len() + 1, arena);
|
let mut arg_layouts = Vec::with_capacity_in(arguments.len() + 1, arena);
|
||||||
|
|
||||||
for var_index in arguments {
|
for &var in arguments {
|
||||||
let var = subs[var_index];
|
|
||||||
match Layout::from_var(&mut env, var) {
|
match Layout::from_var(&mut env, var) {
|
||||||
Ok(layout) => {
|
Ok(layout) => {
|
||||||
has_any_arguments = true;
|
has_any_arguments = true;
|
||||||
|
@ -2317,38 +2323,19 @@ pub fn union_sorted_tags_help<'a>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cheap_sort_tags<'a, 'b>(
|
fn cheap_sort_tags<'a>(tags: &'a UnsortedUnionTags) -> &'a [(&'a TagName, &'a [Variable])] {
|
||||||
arena: &'a Bump,
|
&tags.tags
|
||||||
tags: UnionTags,
|
|
||||||
subs: &'b Subs,
|
|
||||||
) -> Vec<'a, (&'b TagName, VariableSubsSlice)> {
|
|
||||||
let mut tags_vec = Vec::with_capacity_in(tags.len(), arena);
|
|
||||||
|
|
||||||
for (tag_index, index) in tags.iter_all() {
|
|
||||||
let tag = &subs[tag_index];
|
|
||||||
let slice = subs[index];
|
|
||||||
|
|
||||||
tags_vec.push((tag, slice));
|
|
||||||
}
|
|
||||||
|
|
||||||
tags_vec
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn layout_from_newtype<'a>(
|
fn layout_from_newtype<'a>(
|
||||||
arena: &'a Bump,
|
arena: &'a Bump,
|
||||||
tags: UnionTags,
|
tags: &UnsortedUnionTags,
|
||||||
subs: &Subs,
|
subs: &Subs,
|
||||||
ptr_bytes: u32,
|
ptr_bytes: u32,
|
||||||
) -> Layout<'a> {
|
) -> Layout<'a> {
|
||||||
debug_assert!(tags.is_newtype_wrapper(subs));
|
debug_assert!(tags.is_newtype_wrapper(subs));
|
||||||
|
|
||||||
let slice_index = tags.variables().into_iter().next().unwrap();
|
let (tag_name, var) = tags.get_newtype(subs);
|
||||||
let slice = subs[slice_index];
|
|
||||||
let var_index = slice.into_iter().next().unwrap();
|
|
||||||
let var = subs[var_index];
|
|
||||||
|
|
||||||
let tag_name_index = tags.tag_names().into_iter().next().unwrap();
|
|
||||||
let tag_name = &subs[tag_name_index];
|
|
||||||
|
|
||||||
if tag_name == &TagName::Private(Symbol::NUM_AT_NUM) {
|
if tag_name == &TagName::Private(Symbol::NUM_AT_NUM) {
|
||||||
unwrap_num_tag(subs, var, ptr_bytes).expect("invalid Num argument")
|
unwrap_num_tag(subs, var, ptr_bytes).expect("invalid Num argument")
|
||||||
|
@ -2379,7 +2366,7 @@ fn layout_from_newtype<'a>(
|
||||||
|
|
||||||
fn layout_from_tag_union<'a>(
|
fn layout_from_tag_union<'a>(
|
||||||
arena: &'a Bump,
|
arena: &'a Bump,
|
||||||
tags: UnionTags,
|
tags: &UnsortedUnionTags,
|
||||||
subs: &Subs,
|
subs: &Subs,
|
||||||
ptr_bytes: u32,
|
ptr_bytes: u32,
|
||||||
) -> Layout<'a> {
|
) -> Layout<'a> {
|
||||||
|
@ -2389,14 +2376,13 @@ fn layout_from_tag_union<'a>(
|
||||||
return layout_from_newtype(arena, tags, subs, ptr_bytes);
|
return layout_from_newtype(arena, tags, subs, ptr_bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
let tags_vec = cheap_sort_tags(arena, tags, subs);
|
let tags_vec = cheap_sort_tags(tags);
|
||||||
|
|
||||||
match tags_vec.get(0) {
|
match tags_vec.get(0) {
|
||||||
Some((tag_name, arguments)) if *tag_name == &TagName::Private(Symbol::NUM_AT_NUM) => {
|
Some((tag_name, arguments)) if *tag_name == &TagName::Private(Symbol::NUM_AT_NUM) => {
|
||||||
debug_assert_eq!(arguments.len(), 1);
|
debug_assert_eq!(arguments.len(), 1);
|
||||||
|
|
||||||
let var_index = arguments.into_iter().next().unwrap();
|
let &var = arguments.iter().next().unwrap();
|
||||||
let var = subs[var_index];
|
|
||||||
|
|
||||||
unwrap_num_tag(subs, var, ptr_bytes).expect("invalid Num argument")
|
unwrap_num_tag(subs, var, ptr_bytes).expect("invalid Num argument")
|
||||||
}
|
}
|
||||||
|
|
|
@ -1367,3 +1367,85 @@ fn monomorphized_tag_with_polymorphic_arg_and_monomorphic_arg() {
|
||||||
u8
|
u8
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||||
|
fn issue_2365_monomorphize_tag_with_non_empty_ext_var() {
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
app "test" provides [main] to "./platform"
|
||||||
|
|
||||||
|
Single a : [A, B, C]a
|
||||||
|
Compound a : Single [D, E, F]a
|
||||||
|
|
||||||
|
single : {} -> Single *
|
||||||
|
single = \{} -> C
|
||||||
|
|
||||||
|
compound : {} -> Compound *
|
||||||
|
compound = \{} -> single {}
|
||||||
|
|
||||||
|
main = compound {}
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
2, // C
|
||||||
|
u8
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||||
|
fn issue_2365_monomorphize_tag_with_non_empty_ext_var_wrapped() {
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
app "test" provides [main] to "./platform"
|
||||||
|
|
||||||
|
Single a : [A, B, C]a
|
||||||
|
Compound a : Single [D, E, F]a
|
||||||
|
|
||||||
|
single : {} -> Result Str (Single *)
|
||||||
|
single = \{} -> Err C
|
||||||
|
|
||||||
|
compound : {} -> Result Str (Compound *)
|
||||||
|
compound = \{} ->
|
||||||
|
when single {} is
|
||||||
|
Ok s -> Ok s
|
||||||
|
Err e -> Err e
|
||||||
|
|
||||||
|
main = compound {}
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
2, // C
|
||||||
|
u8
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||||
|
fn issue_2365_monomorphize_tag_with_non_empty_ext_var_wrapped_nested() {
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
app "test" provides [main] to "./platform"
|
||||||
|
|
||||||
|
Single a : [A, B, C]a
|
||||||
|
Compound a : Single [D, E, F]a
|
||||||
|
|
||||||
|
main =
|
||||||
|
single : {} -> Result Str (Single *)
|
||||||
|
single = \{} -> Err C
|
||||||
|
|
||||||
|
compound : {} -> Result Str (Compound *)
|
||||||
|
compound = \{} ->
|
||||||
|
when single {} is
|
||||||
|
Ok s -> Ok s
|
||||||
|
Err e -> Err e
|
||||||
|
|
||||||
|
compound {}
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
2, // C
|
||||||
|
u8
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
|
@ -406,8 +406,8 @@ fn write_sorted_tags2<'a>(
|
||||||
ext_var: Variable,
|
ext_var: Variable,
|
||||||
) -> ExtContent<'a> {
|
) -> ExtContent<'a> {
|
||||||
// Sort the fields so they always end up in the same order.
|
// Sort the fields so they always end up in the same order.
|
||||||
let (it, new_ext_var) = tags.unsorted_iterator_and_ext(subs, ext_var);
|
let (tags, new_ext_var) = tags.unsorted_tags_and_ext(subs, ext_var);
|
||||||
let mut sorted_fields: Vec<_> = it.collect();
|
let mut sorted_fields = tags.tags;
|
||||||
|
|
||||||
let interns = &env.interns;
|
let interns = &env.interns;
|
||||||
let home = env.home;
|
let home = env.home;
|
||||||
|
|
|
@ -830,7 +830,10 @@ fn integer_type(
|
||||||
) {
|
) {
|
||||||
// define the type Signed64 (which is an alias for [ @Signed64 ])
|
// define the type Signed64 (which is an alias for [ @Signed64 ])
|
||||||
{
|
{
|
||||||
let tags = UnionTags::insert_into_subs(subs, [(TagName::Private(num_at_signed64), [])]);
|
let tags = UnionTags::insert_into_subs::<Variable, _, _>(
|
||||||
|
subs,
|
||||||
|
[(TagName::Private(num_at_signed64), [])],
|
||||||
|
);
|
||||||
|
|
||||||
subs.set_content(at_signed64, {
|
subs.set_content(at_signed64, {
|
||||||
Content::Structure(FlatType::TagUnion(tags, Variable::EMPTY_TAG_UNION))
|
Content::Structure(FlatType::TagUnion(tags, Variable::EMPTY_TAG_UNION))
|
||||||
|
@ -1082,7 +1085,7 @@ impl Subs {
|
||||||
Content::Structure(FlatType::EmptyTagUnion),
|
Content::Structure(FlatType::EmptyTagUnion),
|
||||||
);
|
);
|
||||||
|
|
||||||
let bool_union_tags = UnionTags::insert_into_subs(
|
let bool_union_tags = UnionTags::insert_into_subs::<Variable, _, _>(
|
||||||
&mut subs,
|
&mut subs,
|
||||||
[
|
[
|
||||||
(TagName::Global("False".into()), []),
|
(TagName::Global("False".into()), []),
|
||||||
|
@ -1724,10 +1727,11 @@ impl UnionTags {
|
||||||
pub fn compare<T>(x: &(TagName, T), y: &(TagName, T)) -> std::cmp::Ordering {
|
pub fn compare<T>(x: &(TagName, T), y: &(TagName, T)) -> std::cmp::Ordering {
|
||||||
first(x, y)
|
first(x, y)
|
||||||
}
|
}
|
||||||
pub fn insert_into_subs<I, I2>(subs: &mut Subs, input: I) -> Self
|
pub fn insert_into_subs<V, I, I2>(subs: &mut Subs, input: I) -> Self
|
||||||
where
|
where
|
||||||
|
V: Into<Variable>,
|
||||||
I: IntoIterator<Item = (TagName, I2)>,
|
I: IntoIterator<Item = (TagName, I2)>,
|
||||||
I2: IntoIterator<Item = Variable>,
|
I2: IntoIterator<Item = V>,
|
||||||
{
|
{
|
||||||
let tag_names_start = subs.tag_names.len() as u32;
|
let tag_names_start = subs.tag_names.len() as u32;
|
||||||
let variables_start = subs.variable_slices.len() as u32;
|
let variables_start = subs.variable_slices.len() as u32;
|
||||||
|
@ -1740,7 +1744,8 @@ impl UnionTags {
|
||||||
|
|
||||||
let mut length = 0;
|
let mut length = 0;
|
||||||
for (k, v) in it {
|
for (k, v) in it {
|
||||||
let variables = VariableSubsSlice::insert_into_subs(subs, v.into_iter());
|
let variables =
|
||||||
|
VariableSubsSlice::insert_into_subs(subs, v.into_iter().map(|v| v.into()));
|
||||||
|
|
||||||
subs.tag_names.push(k);
|
subs.tag_names.push(k);
|
||||||
subs.variable_slices.push(variables);
|
subs.variable_slices.push(variables);
|
||||||
|
@ -1813,16 +1818,17 @@ impl UnionTags {
|
||||||
it.map(f)
|
it.map(f)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn unsorted_iterator_and_ext<'a>(
|
#[inline(always)]
|
||||||
|
pub fn unsorted_tags_and_ext<'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
subs: &'a Subs,
|
subs: &'a Subs,
|
||||||
ext: Variable,
|
ext: Variable,
|
||||||
) -> (impl Iterator<Item = (&TagName, &[Variable])> + 'a, Variable) {
|
) -> (UnsortedUnionTags<'a>, Variable) {
|
||||||
let (it, ext) = crate::types::gather_tags_unsorted_iter(subs, *self, ext);
|
let (it, ext) = crate::types::gather_tags_unsorted_iter(subs, *self, ext);
|
||||||
|
|
||||||
let f = move |(label, slice): (_, SubsSlice<Variable>)| (label, subs.get_subs_slice(slice));
|
let f = move |(label, slice): (_, SubsSlice<Variable>)| (label, subs.get_subs_slice(slice));
|
||||||
|
let it = it.map(f);
|
||||||
|
|
||||||
(it.map(f), ext)
|
(UnsortedUnionTags { tags: it.collect() }, ext)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
@ -1877,6 +1883,25 @@ impl UnionTags {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct UnsortedUnionTags<'a> {
|
||||||
|
pub tags: Vec<(&'a TagName, &'a [Variable])>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> UnsortedUnionTags<'a> {
|
||||||
|
pub fn is_newtype_wrapper(&self, _subs: &Subs) -> bool {
|
||||||
|
if self.tags.len() != 1 {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
self.tags[0].1.len() == 1
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_newtype(&self, _subs: &Subs) -> (&TagName, Variable) {
|
||||||
|
let (tag_name, vars) = self.tags[0];
|
||||||
|
(tag_name, vars[0])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub type SortedTagsIterator<'a> = Box<dyn Iterator<Item = (TagName, &'a [Variable])> + 'a>;
|
pub type SortedTagsIterator<'a> = Box<dyn Iterator<Item = (TagName, &'a [Variable])> + 'a>;
|
||||||
pub type SortedTagsSlicesIterator<'a> = Box<dyn Iterator<Item = (TagName, VariableSubsSlice)> + 'a>;
|
pub type SortedTagsSlicesIterator<'a> = Box<dyn Iterator<Item = (TagName, VariableSubsSlice)> + 'a>;
|
||||||
|
|
||||||
|
@ -2025,6 +2050,21 @@ impl RecordFields {
|
||||||
it
|
it
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn unsorted_iterator_and_ext<'a>(
|
||||||
|
&'a self,
|
||||||
|
subs: &'a Subs,
|
||||||
|
ext: Variable,
|
||||||
|
) -> (
|
||||||
|
impl Iterator<Item = (&Lowercase, RecordField<Variable>)> + 'a,
|
||||||
|
Variable,
|
||||||
|
) {
|
||||||
|
let (it, ext) = crate::types::gather_fields_unsorted_iter(subs, *self, ext)
|
||||||
|
.expect("Something weird ended up in a record type");
|
||||||
|
|
||||||
|
(it, ext)
|
||||||
|
}
|
||||||
|
|
||||||
/// Get a sorted iterator over the fields of this record type
|
/// Get a sorted iterator over the fields of this record type
|
||||||
///
|
///
|
||||||
/// Implementation: When the record has an `ext` variable that is the empty record, then
|
/// Implementation: When the record has an `ext` variable that is the empty record, then
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue