Merge branch 'trunk' into store-bool-closure-as-unit

This commit is contained in:
Richard Feldman 2021-08-14 16:47:42 -04:00 committed by GitHub
commit bb7726b0e0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 315 additions and 342 deletions

View file

@ -733,6 +733,30 @@ pub fn listAppend(list: RocList, alignment: u32, element: Opaque, element_width:
return output;
}
pub fn listPrepend(list: RocList, alignment: u32, element: Opaque, element_width: usize) callconv(.C) RocList {
const old_length = list.len();
var output = list.reallocate(alignment, old_length + 1, element_width);
// can't use one memcpy here because source and target overlap
if (output.bytes) |target| {
var i: usize = old_length;
while (i > 0) {
i -= 1;
// move the ith element to the (i + 1)th position
@memcpy(target + (i + 1) * element_width, target + i * element_width, element_width);
}
// finally copy in the new first element
if (element) |source| {
@memcpy(target, source, element_width);
}
}
return output;
}
pub fn listSwap(
list: RocList,
alignment: u32,

View file

@ -33,6 +33,7 @@ comptime {
exportListFn(list.listContains, "contains");
exportListFn(list.listRepeat, "repeat");
exportListFn(list.listAppend, "append");
exportListFn(list.listPrepend, "prepend");
exportListFn(list.listSingle, "single");
exportListFn(list.listJoin, "join");
exportListFn(list.listRange, "range");

View file

@ -57,6 +57,7 @@ pub const LIST_WALK_BACKWARDS: &str = "roc_builtins.list.walk_backwards";
pub const LIST_CONTAINS: &str = "roc_builtins.list.contains";
pub const LIST_REPEAT: &str = "roc_builtins.list.repeat";
pub const LIST_APPEND: &str = "roc_builtins.list.append";
pub const LIST_PREPEND: &str = "roc_builtins.list.prepend";
pub const LIST_DROP: &str = "roc_builtins.list.drop";
pub const LIST_SWAP: &str = "roc_builtins.list.swap";
pub const LIST_SINGLE: &str = "roc_builtins.list.single";

View file

@ -121,69 +121,6 @@ pub fn list_repeat<'a, 'ctx, 'env>(
)
}
/// List.prepend : List elem, elem -> List elem
pub fn list_prepend<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
original_wrapper: StructValue<'ctx>,
elem: BasicValueEnum<'ctx>,
elem_layout: &Layout<'a>,
) -> BasicValueEnum<'ctx> {
let builder = env.builder;
// Load the usize length from the wrapper.
let len = list_len(builder, original_wrapper);
let elem_type = basic_type_from_layout(env, elem_layout);
let ptr_type = elem_type.ptr_type(AddressSpace::Generic);
let list_ptr = load_list_ptr(builder, original_wrapper, ptr_type);
// The output list length, which is the old list length + 1
let new_list_len = env.builder.build_int_add(
env.ptr_int().const_int(1_u64, false),
len,
"new_list_length",
);
// Allocate space for the new array that we'll copy into.
let clone_ptr = allocate_list(env, elem_layout, new_list_len);
builder.build_store(clone_ptr, elem);
let index_1_ptr = unsafe {
builder.build_in_bounds_gep(
clone_ptr,
&[env.ptr_int().const_int(1_u64, false)],
"load_index",
)
};
// Calculate the number of bytes we'll need to allocate.
let elem_bytes = env
.ptr_int()
.const_int(elem_layout.stack_size(env.ptr_bytes) as u64, false);
// This is the size of the list coming in, before we have added an element
// to the beginning.
let list_size = env
.builder
.build_int_mul(elem_bytes, len, "mul_old_len_by_elem_bytes");
let ptr_bytes = env.ptr_bytes;
if elem_layout.safe_to_memcpy() {
// Copy the bytes from the original array into the new
// one we just allocated
//
// TODO how do we decide when to do the small memcpy vs the normal one?
builder
.build_memcpy(index_1_ptr, ptr_bytes, list_ptr, ptr_bytes, list_size)
.unwrap();
} else {
panic!("TODO Cranelift currently only knows how to clone list elements that are Copy.");
}
store_list(env, clone_ptr, new_list_len)
}
/// List.join : List (List elem) -> List elem
pub fn list_join<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
@ -299,6 +236,25 @@ pub fn list_append<'a, 'ctx, 'env>(
)
}
/// List.prepend : List elem, elem -> List elem
pub fn list_prepend<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
original_wrapper: StructValue<'ctx>,
element: BasicValueEnum<'ctx>,
element_layout: &Layout<'a>,
) -> BasicValueEnum<'ctx> {
call_bitcode_fn_returns_list(
env,
&[
pass_list_as_i128(env, original_wrapper.into()),
env.alignment_intvalue(element_layout),
pass_element_as_opaque(env, element),
layout_width(env, element_layout),
],
bitcode::LIST_PREPEND,
)
}
/// List.swap : List elem, Nat, Nat -> List elem
pub fn list_swap<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,

View file

@ -829,7 +829,7 @@ impl<'a> Layout<'a> {
/// But if we're careful when to invalidate certain keys, we still get some benefit
#[derive(Default, Debug)]
pub struct LayoutCache<'a> {
layouts: ven_ena::unify::UnificationTable<ven_ena::unify::InPlace<CachedVariable<'a>>>,
_marker: std::marker::PhantomData<&'a u8>,
}
#[derive(Debug, Clone)]
@ -839,38 +839,7 @@ pub enum CachedLayout<'a> {
Problem(LayoutProblem),
}
/// Must wrap so we can define a specific UnifyKey instance
/// PhantomData so we can store the 'a lifetime, which is needed to implement the UnifyKey trait,
/// specifically so we can use `type Value = CachedLayout<'a>`
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct CachedVariable<'a>(Variable, std::marker::PhantomData<&'a ()>);
impl<'a> CachedVariable<'a> {
fn new(var: Variable) -> Self {
CachedVariable(var, std::marker::PhantomData)
}
}
impl<'a> ven_ena::unify::UnifyKey for CachedVariable<'a> {
type Value = CachedLayout<'a>;
fn index(&self) -> u32 {
self.0.index()
}
fn from_index(index: u32) -> Self {
CachedVariable(Variable::from_index(index), std::marker::PhantomData)
}
fn tag() -> &'static str {
"CachedVariable"
}
}
impl<'a> LayoutCache<'a> {
/// Returns Err(()) if given an error, or Ok(Layout) if given a non-erroneous Structure.
/// Panics if given a FlexVar or RigidVar, since those should have been
/// monomorphized away already!
pub fn from_var(
&mut self,
arena: &'a Bump,
@ -880,39 +849,13 @@ impl<'a> LayoutCache<'a> {
// Store things according to the root Variable, to avoid duplicate work.
let var = subs.get_root_key_without_compacting(var);
let cached_var = CachedVariable::new(var);
self.expand_to_fit(cached_var);
use CachedLayout::*;
match self.layouts.probe_value(cached_var) {
Cached(result) => Ok(result),
Problem(problem) => Err(problem),
NotCached => {
let mut env = Env {
arena,
subs,
seen: Vec::new_in(arena),
};
let result = Layout::from_var(&mut env, var);
// Don't actually cache. The layout cache is very hard to get right in the presence
// of specialization, it's turned of for now so an invalid cache is never the cause
// of a problem
if false {
let cached_layout = match &result {
Ok(layout) => Cached(*layout),
Err(problem) => Problem(problem.clone()),
};
self.layouts
.update_value(cached_var, |existing| existing.value = cached_layout);
}
result
}
}
Layout::from_var(&mut env, var)
}
pub fn raw_from_var(
@ -924,14 +867,6 @@ impl<'a> LayoutCache<'a> {
// Store things according to the root Variable, to avoid duplicate work.
let var = subs.get_root_key_without_compacting(var);
let cached_var = CachedVariable::new(var);
self.expand_to_fit(cached_var);
use CachedLayout::*;
match self.layouts.probe_value(cached_var) {
Problem(problem) => Err(problem),
Cached(_) | NotCached => {
let mut env = Env {
arena,
subs,
@ -943,36 +878,17 @@ impl<'a> LayoutCache<'a> {
other => RawFunctionLayout::ZeroArgumentThunk(other),
})
}
}
pub fn snapshot(&mut self) -> SnapshotKeyPlaceholder {
SnapshotKeyPlaceholder
}
fn expand_to_fit(&mut self, var: CachedVariable<'a>) {
use ven_ena::unify::UnifyKey;
let required = (var.index() as isize) - (self.layouts.len() as isize) + 1;
if required > 0 {
self.layouts.reserve(required as usize);
for _ in 0..required {
self.layouts.new_key(CachedLayout::NotCached);
}
}
}
pub fn snapshot(
&mut self,
) -> ven_ena::unify::Snapshot<ven_ena::unify::InPlace<CachedVariable<'a>>> {
self.layouts.snapshot()
}
pub fn rollback_to(
&mut self,
snapshot: ven_ena::unify::Snapshot<ven_ena::unify::InPlace<CachedVariable<'a>>>,
) {
self.layouts.rollback_to(snapshot)
}
pub fn rollback_to(&mut self, _snapshot: SnapshotKeyPlaceholder) {}
}
// placeholder for the type ven_ena::unify::Snapshot<ven_ena::unify::InPlace<CachedVariable<'a>>>
pub struct SnapshotKeyPlaceholder;
impl<'a> Builtin<'a> {
const I128_SIZE: u32 = std::mem::size_of::<i128>() as u32;
const I64_SIZE: u32 = std::mem::size_of::<i64>() as u32;

View file

@ -1,12 +1,13 @@
use roc_can::constraint::Constraint::{self, *};
use roc_can::expected::{Expected, PExpected};
use roc_collections::all::{default_hasher, MutMap};
use roc_collections::all::MutMap;
use roc_module::ident::TagName;
use roc_module::symbol::Symbol;
use roc_region::all::{Located, Region};
use roc_types::solved_types::Solved;
use roc_types::subs::{
AliasVariables, Content, Descriptor, FlatType, Mark, OptVariable, Rank, RecordFields, Subs,
SubsIndex, Variable, VariableSubsSlice,
SubsIndex, SubsSlice, UnionTags, Variable, VariableSubsSlice,
};
use roc_types::types::Type::{self, *};
use roc_types::types::{gather_fields_unsorted_iter, Alias, Category, ErrorType, PatternCategory};
@ -706,32 +707,8 @@ fn type_to_variable(
register(subs, rank, pools, content)
}
TagUnion(tags, ext) => {
let mut tag_vars = MutMap::with_capacity_and_hasher(tags.len(), default_hasher());
for (tag, tag_argument_types) in tags {
let mut tag_argument_vars = Vec::with_capacity(tag_argument_types.len());
for arg_type in tag_argument_types {
tag_argument_vars.push(type_to_variable(subs, rank, pools, cached, arg_type));
}
tag_vars.insert(tag.clone(), tag_argument_vars);
}
let temp_ext_var = type_to_variable(subs, rank, pools, cached, ext);
let mut ext_tag_vec = Vec::new();
let new_ext_var = match roc_types::pretty_print::chase_ext_tag_union(
subs,
temp_ext_var,
&mut ext_tag_vec,
) {
Ok(()) => Variable::EMPTY_TAG_UNION,
Err((new, _)) => new,
};
tag_vars.extend(ext_tag_vec.into_iter());
let content =
Content::Structure(roc_unify::unify::from_mutmap(subs, tag_vars, new_ext_var));
let (union_tags, ext) = type_to_union_tags(subs, rank, pools, cached, tags, ext);
let content = Content::Structure(FlatType::TagUnion(union_tags, ext));
register(subs, rank, pools, content)
}
@ -758,36 +735,9 @@ fn type_to_variable(
register(subs, rank, pools, content)
}
RecursiveTagUnion(rec_var, tags, ext) => {
let mut tag_vars = MutMap::with_capacity_and_hasher(tags.len(), default_hasher());
for (tag, tag_argument_types) in tags {
let mut tag_argument_vars = Vec::with_capacity(tag_argument_types.len());
for arg_type in tag_argument_types {
tag_argument_vars.push(type_to_variable(subs, rank, pools, cached, arg_type));
}
tag_vars.insert(tag.clone(), tag_argument_vars);
}
let temp_ext_var = type_to_variable(subs, rank, pools, cached, ext);
let mut ext_tag_vec = Vec::new();
let new_ext_var = match roc_types::pretty_print::chase_ext_tag_union(
subs,
temp_ext_var,
&mut ext_tag_vec,
) {
Ok(()) => Variable::EMPTY_TAG_UNION,
Err((new, _)) => new,
};
tag_vars.extend(ext_tag_vec.into_iter());
let content = Content::Structure(roc_unify::unify::from_mutmap_rec(
subs,
*rec_var,
tag_vars,
new_ext_var,
));
let (union_tags, ext) = type_to_union_tags(subs, rank, pools, cached, tags, ext);
let content =
Content::Structure(FlatType::RecursiveTagUnion(*rec_var, union_tags, ext));
let tag_union_var = register(subs, rank, pools, content);
@ -903,6 +853,59 @@ fn type_to_variable(
}
}
fn type_to_union_tags(
subs: &mut Subs,
rank: Rank,
pools: &mut Pools,
cached: &mut MutMap<Symbol, Variable>,
tags: &[(TagName, Vec<Type>)],
ext: &Type,
) -> (UnionTags, Variable) {
let mut tag_vars = Vec::with_capacity(tags.len());
let mut tag_argument_vars = Vec::new();
for (tag, tag_argument_types) in tags {
for arg_type in tag_argument_types {
let new_var = type_to_variable(subs, rank, pools, cached, arg_type);
tag_argument_vars.push(new_var);
}
let new_slice = VariableSubsSlice::insert_into_subs(subs, tag_argument_vars.drain(..));
tag_vars.push((tag.clone(), new_slice));
}
let temp_ext_var = type_to_variable(subs, rank, pools, cached, ext);
let ext = {
let (it, ext) =
roc_types::types::gather_tags_unsorted_iter(subs, UnionTags::default(), temp_ext_var);
tag_vars.extend(it.map(|(n, v)| (n.clone(), v)));
tag_vars.sort_unstable_by(|(a, _), (b, _)| a.cmp(b));
// deduplicate, keeping the right-most occurrence of a tag name
let mut i = 0;
while i < tag_vars.len() {
match (tag_vars.get(i), tag_vars.get(i + 1)) {
(Some((t1, _)), Some((t2, _))) => {
if t1 == t2 {
tag_vars.remove(i);
} else {
i += 1;
}
}
_ => break,
}
}
ext
};
(UnionTags::insert_slices_into_subs(subs, tag_vars), ext)
}
fn check_for_infinite_type(
subs: &mut Subs,
problems: &mut Vec<TypeError>,
@ -928,7 +931,7 @@ fn check_for_infinite_type(
},
);
let mut new_tags = MutMap::default();
let mut new_tags = Vec::with_capacity(tags.len());
for (name_index, slice_index) in tags.iter_all() {
let slice = subs[slice_index];
@ -939,13 +942,14 @@ fn check_for_infinite_type(
new_vars.push(subs.explicit_substitute(recursive, rec_var, var));
}
new_tags.insert(subs[name_index].clone(), new_vars);
new_tags.push((subs[name_index].clone(), new_vars));
}
let new_ext_var = subs.explicit_substitute(recursive, rec_var, ext_var);
let flat_type =
roc_unify::unify::from_mutmap_rec(subs, rec_var, new_tags, new_ext_var);
let new_tags = UnionTags::insert_into_subs(subs, new_tags);
let flat_type = FlatType::RecursiveTagUnion(rec_var, new_tags, new_ext_var);
subs.set_content(recursive, Content::Structure(flat_type));
}
@ -1509,23 +1513,35 @@ fn deep_copy_var_help(
}
TagUnion(tags, ext_var) => {
let mut new_tags = MutMap::default();
let mut new_variable_slices = Vec::with_capacity(tags.len());
for (tag_index, index) in tags.iter_all() {
let tag = subs[tag_index].clone();
let mut new_variables = Vec::new();
for index in tags.variables() {
let slice = subs[index];
let mut new_vars = Vec::new();
for var_index in slice {
let var = subs[var_index];
let new_var = deep_copy_var_help(subs, max_rank, pools, var);
new_vars.push(new_var);
new_variables.push(new_var);
}
new_tags.insert(tag, new_vars);
let new_slice =
VariableSubsSlice::insert_into_subs(subs, new_variables.drain(..));
new_variable_slices.push(new_slice);
}
let new_variables = {
let start = subs.variable_slices.len() as u32;
let length = new_variable_slices.len() as u16;
subs.variable_slices.extend(new_variable_slices);
SubsSlice::new(start, length)
};
let union_tags = UnionTags::from_slices(tags.tag_names(), new_variables);
let new_ext = deep_copy_var_help(subs, max_rank, pools, ext_var);
roc_unify::unify::from_mutmap(subs, new_tags, new_ext)
TagUnion(union_tags, new_ext)
}
FunctionOrTagUnion(tag_name, symbol, ext_var) => FunctionOrTagUnion(
@ -1535,25 +1551,37 @@ fn deep_copy_var_help(
),
RecursiveTagUnion(rec_var, tags, ext_var) => {
let mut new_tags = MutMap::default();
let mut new_variable_slices = Vec::with_capacity(tags.len());
let new_rec_var = deep_copy_var_help(subs, max_rank, pools, rec_var);
for (tag_index, index) in tags.iter_all() {
let tag = subs[tag_index].clone();
let mut new_variables = Vec::new();
for index in tags.variables() {
let slice = subs[index];
let mut new_vars = Vec::new();
for var_index in slice {
let var = subs[var_index];
let new_var = deep_copy_var_help(subs, max_rank, pools, var);
new_vars.push(new_var);
new_variables.push(new_var);
}
new_tags.insert(tag, new_vars);
let new_slice =
VariableSubsSlice::insert_into_subs(subs, new_variables.drain(..));
new_variable_slices.push(new_slice);
}
let new_variables = {
let start = subs.variable_slices.len() as u32;
let length = new_variable_slices.len() as u16;
subs.variable_slices.extend(new_variable_slices);
SubsSlice::new(start, length)
};
let union_tags = UnionTags::from_slices(tags.tag_names(), new_variables);
let new_ext = deep_copy_var_help(subs, max_rank, pools, ext_var);
roc_unify::unify::from_mutmap_rec(subs, new_rec_var, new_tags, new_ext)
let new_rec_var = deep_copy_var_help(subs, max_rank, pools, rec_var);
RecursiveTagUnion(new_rec_var, union_tags, new_ext)
}
};

View file

@ -276,6 +276,20 @@ fn list_prepend() {
RocList::from_slice(&[6, 4]),
RocList<i64>
);
assert_evals_to!(
indoc!(
r#"
init : List Str
init =
["foo"]
List.prepend init "bar"
"#
),
RocList::from_slice(&[RocStr::from_slice(b"bar"), RocStr::from_slice(b"foo"),]),
RocList<RocStr>
);
}
#[test]

View file

@ -1519,7 +1519,10 @@ impl UnionTags {
)
}
fn from_slices(tag_names: SubsSlice<TagName>, variables: SubsSlice<VariableSubsSlice>) -> Self {
pub fn from_slices(
tag_names: SubsSlice<TagName>,
variables: SubsSlice<VariableSubsSlice>,
) -> Self {
debug_assert_eq!(tag_names.len(), variables.len());
Self {
@ -1578,6 +1581,16 @@ impl UnionTags {
)
}
pub fn tag_without_arguments(subs: &mut Subs, tag_name: TagName) -> Self {
subs.tag_names.push(tag_name);
Self {
length: 1,
tag_names_start: (subs.tag_names.len() - 1) as u32,
variables_start: 0,
}
}
pub fn insert_slices_into_subs<I>(subs: &mut Subs, input: I) -> Self
where
I: IntoIterator<Item = (TagName, VariableSubsSlice)>,

View file

@ -1,4 +1,4 @@
use roc_collections::all::{default_hasher, MutMap};
use roc_collections::all::MutMap;
use roc_module::ident::{Lowercase, TagName};
use roc_module::symbol::Symbol;
use roc_types::subs::Content::{self, *};
@ -1240,36 +1240,6 @@ fn is_recursion_var(subs: &Subs, var: Variable) -> bool {
)
}
// TODO remove when all tags use SOA
pub fn from_mutmap(
subs: &mut Subs,
tags: MutMap<TagName, Vec<Variable>>,
ext: Variable,
) -> FlatType {
let mut vec: Vec<_> = tags.into_iter().collect();
vec.sort();
let union_tags = UnionTags::insert_into_subs(subs, vec);
FlatType::TagUnion(union_tags, ext)
}
pub fn from_mutmap_rec(
subs: &mut Subs,
rec: Variable,
tags: MutMap<TagName, Vec<Variable>>,
ext: Variable,
) -> FlatType {
let mut vec: Vec<_> = tags.into_iter().collect();
vec.sort();
let union_tags = UnionTags::insert_into_subs(subs, vec);
FlatType::RecursiveTagUnion(rec, union_tags, ext)
}
#[allow(clippy::too_many_arguments)]
fn unify_function_or_tag_union_and_func(
subs: &mut Subs,
@ -1285,15 +1255,8 @@ fn unify_function_or_tag_union_and_func(
) -> Outcome {
let tag_name = subs[*tag_name_index].clone();
let mut new_tags = MutMap::with_capacity_and_hasher(1, default_hasher());
new_tags.insert(
tag_name,
subs.get_subs_slice(*function_arguments.as_subs_slice())
.to_owned(),
);
let content = Content::Structure(from_mutmap(subs, new_tags, tag_ext));
let union_tags = UnionTags::insert_slices_into_subs(subs, [(tag_name, function_arguments)]);
let content = Content::Structure(FlatType::TagUnion(union_tags, tag_ext));
let new_tag_union_var = fresh(subs, pool, ctx, content);
@ -1304,12 +1267,11 @@ fn unify_function_or_tag_union_and_func(
};
{
let tag_name = TagName::Closure(tag_symbol);
let union_tags = UnionTags::tag_without_arguments(subs, tag_name);
let lambda_set_ext = subs.fresh_unnamed_flex_var();
let mut closure_tags = MutMap::with_capacity_and_hasher(1, default_hasher());
closure_tags.insert(TagName::Closure(tag_symbol), vec![]);
let lambda_set_content = Structure(from_mutmap(subs, closure_tags, lambda_set_ext));
let lambda_set_content = Structure(FlatType::TagUnion(union_tags, lambda_set_ext));
let tag_lambda_set = register(
subs,

View file

@ -1,17 +1,18 @@
#![allow(clippy::all)]
#![allow(dead_code)]
use crate::lang::constrain::Constraint::{self, *};
use crate::lang::pool::{Pool, ShallowClone};
use crate::lang::pool::{Pool, PoolVec, ShallowClone};
use crate::lang::types::Type2;
use bumpalo::Bump;
use roc_can::expected::{Expected, PExpected};
use roc_collections::all::{BumpMap, BumpMapDefault, MutMap};
use roc_module::ident::TagName;
use roc_module::symbol::Symbol;
use roc_region::all::{Located, Region};
use roc_types::solved_types::Solved;
use roc_types::subs::{
AliasVariables, Content, Descriptor, FlatType, Mark, OptVariable, Rank, RecordFields, Subs,
Variable, VariableSubsSlice,
SubsSlice, UnionTags, Variable, VariableSubsSlice,
};
use roc_types::types::{
gather_fields_unsorted_iter, Alias, Category, ErrorType, PatternCategory, RecordField,
@ -831,35 +832,11 @@ fn type_to_variable<'a>(
result
}
TagUnion(tags, ext_id) => {
let mut tag_vars = MutMap::default();
let ext = mempool.get(*ext_id);
for (tag_name, tag_argument_types) in tags.iter(mempool) {
let mut tag_argument_vars = Vec::with_capacity(tag_argument_types.len());
for arg_type in tag_argument_types.iter(mempool) {
tag_argument_vars.push(type_to_variable(
arena, mempool, subs, rank, pools, cached, arg_type,
));
}
tag_vars.insert(tag_name.clone(), tag_argument_vars);
}
let temp_ext_var = type_to_variable(arena, mempool, subs, rank, pools, cached, ext);
let mut ext_tag_vec = Vec::new();
let new_ext_var = match roc_types::pretty_print::chase_ext_tag_union(
subs,
temp_ext_var,
&mut ext_tag_vec,
) {
Ok(()) => roc_types::subs::Variable::EMPTY_TAG_UNION,
Err((new, _)) => new,
};
tag_vars.extend(ext_tag_vec.into_iter());
let content =
Content::Structure(roc_unify::unify::from_mutmap(subs, tag_vars, new_ext_var));
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));
register(subs, rank, pools, content)
}
@ -974,6 +951,63 @@ fn type_to_variable<'a>(
}
}
fn type_to_union_tags<'a>(
arena: &'a Bump,
mempool: &Pool,
subs: &mut Subs,
rank: Rank,
pools: &mut Pools,
cached: &mut MutMap<Symbol, Variable>,
tags: &PoolVec<(TagName, PoolVec<Type2>)>,
ext: &Type2,
) -> (UnionTags, Variable) {
let mut tag_vars = Vec::with_capacity(tags.len());
let mut tag_argument_vars = Vec::new();
for id in tags.iter_node_ids() {
let (tag, tag_argument_types) = mempool.get(id);
for arg_id in tag_argument_types.iter_node_ids() {
let arg_type = mempool.get(arg_id);
let new_var = type_to_variable(arena, mempool, subs, rank, pools, cached, arg_type);
tag_argument_vars.push(new_var);
}
let new_slice = VariableSubsSlice::insert_into_subs(subs, tag_argument_vars.drain(..));
tag_vars.push((tag.clone(), new_slice));
}
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);
tag_vars.extend(it.map(|(n, v)| (n.clone(), v)));
tag_vars.sort_unstable_by(|(a, _), (b, _)| a.cmp(b));
// deduplicate, keeping the right-most occurrence of a tag name
let mut i = 0;
while i < tag_vars.len() {
match (tag_vars.get(i), tag_vars.get(i + 1)) {
(Some((t1, _)), Some((t2, _))) => {
if t1 == t2 {
tag_vars.remove(i);
} else {
i += 1;
}
}
_ => break,
}
}
ext
};
(UnionTags::insert_slices_into_subs(subs, tag_vars), ext)
}
fn check_for_infinite_type(
subs: &mut Subs,
problems: &mut Vec<TypeError>,
@ -999,7 +1033,7 @@ fn check_for_infinite_type(
},
);
let mut new_tags = MutMap::default();
let mut new_tags = Vec::with_capacity(tags.len());
for (name_index, slice_index) in tags.iter_all() {
let slice = subs[slice_index];
@ -1010,13 +1044,14 @@ fn check_for_infinite_type(
new_vars.push(subs.explicit_substitute(recursive, rec_var, var));
}
new_tags.insert(subs[name_index].clone(), new_vars);
new_tags.push((subs[name_index].clone(), new_vars));
}
let new_ext_var = subs.explicit_substitute(recursive, rec_var, ext_var);
let flat_type =
roc_unify::unify::from_mutmap_rec(subs, rec_var, new_tags, new_ext_var);
let new_tags = UnionTags::insert_into_subs(subs, new_tags);
let flat_type = FlatType::RecursiveTagUnion(rec_var, new_tags, new_ext_var);
subs.set_content(recursive, Content::Structure(flat_type));
}
@ -1581,23 +1616,35 @@ fn deep_copy_var_help(
}
TagUnion(tags, ext_var) => {
let mut new_tags = MutMap::default();
let mut new_variable_slices = Vec::with_capacity(tags.len());
for (tag_index, index) in tags.iter_all() {
let tag = subs[tag_index].clone();
let mut new_variables = Vec::new();
for index in tags.variables() {
let slice = subs[index];
let mut new_vars = Vec::new();
for var_index in slice {
let var = subs[var_index];
let new_var = deep_copy_var_help(subs, max_rank, pools, var);
new_vars.push(new_var);
new_variables.push(new_var);
}
new_tags.insert(tag, new_vars);
let new_slice =
VariableSubsSlice::insert_into_subs(subs, new_variables.drain(..));
new_variable_slices.push(new_slice);
}
let new_variables = {
let start = subs.variable_slices.len() as u32;
let length = new_variable_slices.len() as u16;
subs.variable_slices.extend(new_variable_slices);
SubsSlice::new(start, length)
};
let union_tags = UnionTags::from_slices(tags.tag_names(), new_variables);
let new_ext = deep_copy_var_help(subs, max_rank, pools, ext_var);
roc_unify::unify::from_mutmap(subs, new_tags, new_ext)
TagUnion(union_tags, new_ext)
}
FunctionOrTagUnion(tag_name, symbol, ext_var) => FunctionOrTagUnion(
@ -1607,25 +1654,36 @@ fn deep_copy_var_help(
),
RecursiveTagUnion(rec_var, tags, ext_var) => {
let mut new_tags = MutMap::default();
let mut new_variable_slices = Vec::with_capacity(tags.len());
let new_rec_var = deep_copy_var_help(subs, max_rank, pools, rec_var);
for (tag_index, index) in tags.iter_all() {
let tag = subs[tag_index].clone();
let mut new_variables = Vec::new();
for index in tags.variables() {
let slice = subs[index];
let mut new_vars = Vec::new();
for var_index in slice {
let var = subs[var_index];
let new_var = deep_copy_var_help(subs, max_rank, pools, var);
new_vars.push(new_var);
new_variables.push(new_var);
}
new_tags.insert(tag, new_vars);
let new_slice =
VariableSubsSlice::insert_into_subs(subs, new_variables.drain(..));
new_variable_slices.push(new_slice);
}
let new_variables = {
let start = subs.variable_slices.len() as u32;
let length = new_variable_slices.len() as u16;
subs.variable_slices.extend(new_variable_slices);
SubsSlice::new(start, length)
};
let union_tags = UnionTags::from_slices(tags.tag_names(), new_variables);
let new_ext = deep_copy_var_help(subs, max_rank, pools, ext_var);
roc_unify::unify::from_mutmap_rec(subs, new_rec_var, new_tags, new_ext)
let new_rec_var = deep_copy_var_help(subs, max_rank, pools, rec_var);
FlatType::RecursiveTagUnion(new_rec_var, union_tags, new_ext)
}
};