mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-27 22:09:09 +00:00
Merge branch 'trunk' into store-bool-closure-as-unit
This commit is contained in:
commit
bb7726b0e0
10 changed files with 315 additions and 342 deletions
|
@ -733,6 +733,30 @@ pub fn listAppend(list: RocList, alignment: u32, element: Opaque, element_width:
|
||||||
return output;
|
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(
|
pub fn listSwap(
|
||||||
list: RocList,
|
list: RocList,
|
||||||
alignment: u32,
|
alignment: u32,
|
||||||
|
|
|
@ -33,6 +33,7 @@ comptime {
|
||||||
exportListFn(list.listContains, "contains");
|
exportListFn(list.listContains, "contains");
|
||||||
exportListFn(list.listRepeat, "repeat");
|
exportListFn(list.listRepeat, "repeat");
|
||||||
exportListFn(list.listAppend, "append");
|
exportListFn(list.listAppend, "append");
|
||||||
|
exportListFn(list.listPrepend, "prepend");
|
||||||
exportListFn(list.listSingle, "single");
|
exportListFn(list.listSingle, "single");
|
||||||
exportListFn(list.listJoin, "join");
|
exportListFn(list.listJoin, "join");
|
||||||
exportListFn(list.listRange, "range");
|
exportListFn(list.listRange, "range");
|
||||||
|
|
|
@ -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_CONTAINS: &str = "roc_builtins.list.contains";
|
||||||
pub const LIST_REPEAT: &str = "roc_builtins.list.repeat";
|
pub const LIST_REPEAT: &str = "roc_builtins.list.repeat";
|
||||||
pub const LIST_APPEND: &str = "roc_builtins.list.append";
|
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_DROP: &str = "roc_builtins.list.drop";
|
||||||
pub const LIST_SWAP: &str = "roc_builtins.list.swap";
|
pub const LIST_SWAP: &str = "roc_builtins.list.swap";
|
||||||
pub const LIST_SINGLE: &str = "roc_builtins.list.single";
|
pub const LIST_SINGLE: &str = "roc_builtins.list.single";
|
||||||
|
|
|
@ -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
|
/// List.join : List (List elem) -> List elem
|
||||||
pub fn list_join<'a, 'ctx, 'env>(
|
pub fn list_join<'a, 'ctx, 'env>(
|
||||||
env: &Env<'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
|
/// List.swap : List elem, Nat, Nat -> List elem
|
||||||
pub fn list_swap<'a, 'ctx, 'env>(
|
pub fn list_swap<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
|
|
@ -829,7 +829,7 @@ impl<'a> Layout<'a> {
|
||||||
/// But if we're careful when to invalidate certain keys, we still get some benefit
|
/// But if we're careful when to invalidate certain keys, we still get some benefit
|
||||||
#[derive(Default, Debug)]
|
#[derive(Default, Debug)]
|
||||||
pub struct LayoutCache<'a> {
|
pub struct LayoutCache<'a> {
|
||||||
layouts: ven_ena::unify::UnificationTable<ven_ena::unify::InPlace<CachedVariable<'a>>>,
|
_marker: std::marker::PhantomData<&'a u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
@ -839,38 +839,7 @@ pub enum CachedLayout<'a> {
|
||||||
Problem(LayoutProblem),
|
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> {
|
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(
|
pub fn from_var(
|
||||||
&mut self,
|
&mut self,
|
||||||
arena: &'a Bump,
|
arena: &'a Bump,
|
||||||
|
@ -880,39 +849,13 @@ impl<'a> LayoutCache<'a> {
|
||||||
// Store things according to the root Variable, to avoid duplicate work.
|
// Store things according to the root Variable, to avoid duplicate work.
|
||||||
let var = subs.get_root_key_without_compacting(var);
|
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 {
|
let mut env = Env {
|
||||||
arena,
|
arena,
|
||||||
subs,
|
subs,
|
||||||
seen: Vec::new_in(arena),
|
seen: Vec::new_in(arena),
|
||||||
};
|
};
|
||||||
|
|
||||||
let result = Layout::from_var(&mut env, var);
|
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn raw_from_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.
|
// Store things according to the root Variable, to avoid duplicate work.
|
||||||
let var = subs.get_root_key_without_compacting(var);
|
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 {
|
let mut env = Env {
|
||||||
arena,
|
arena,
|
||||||
subs,
|
subs,
|
||||||
|
@ -943,36 +878,17 @@ impl<'a> LayoutCache<'a> {
|
||||||
other => RawFunctionLayout::ZeroArgumentThunk(other),
|
other => RawFunctionLayout::ZeroArgumentThunk(other),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
pub fn snapshot(&mut self) -> SnapshotKeyPlaceholder {
|
||||||
|
SnapshotKeyPlaceholder
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expand_to_fit(&mut self, var: CachedVariable<'a>) {
|
pub fn rollback_to(&mut self, _snapshot: SnapshotKeyPlaceholder) {}
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// placeholder for the type ven_ena::unify::Snapshot<ven_ena::unify::InPlace<CachedVariable<'a>>>
|
||||||
|
pub struct SnapshotKeyPlaceholder;
|
||||||
|
|
||||||
impl<'a> Builtin<'a> {
|
impl<'a> Builtin<'a> {
|
||||||
const I128_SIZE: u32 = std::mem::size_of::<i128>() as u32;
|
const I128_SIZE: u32 = std::mem::size_of::<i128>() as u32;
|
||||||
const I64_SIZE: u32 = std::mem::size_of::<i64>() as u32;
|
const I64_SIZE: u32 = std::mem::size_of::<i64>() as u32;
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
use roc_can::constraint::Constraint::{self, *};
|
use roc_can::constraint::Constraint::{self, *};
|
||||||
use roc_can::expected::{Expected, PExpected};
|
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_module::symbol::Symbol;
|
||||||
use roc_region::all::{Located, Region};
|
use roc_region::all::{Located, Region};
|
||||||
use roc_types::solved_types::Solved;
|
use roc_types::solved_types::Solved;
|
||||||
use roc_types::subs::{
|
use roc_types::subs::{
|
||||||
AliasVariables, Content, Descriptor, FlatType, Mark, OptVariable, Rank, RecordFields, 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::Type::{self, *};
|
||||||
use roc_types::types::{gather_fields_unsorted_iter, Alias, Category, ErrorType, PatternCategory};
|
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)
|
register(subs, rank, pools, content)
|
||||||
}
|
}
|
||||||
TagUnion(tags, ext) => {
|
TagUnion(tags, ext) => {
|
||||||
let mut tag_vars = MutMap::with_capacity_and_hasher(tags.len(), default_hasher());
|
let (union_tags, ext) = type_to_union_tags(subs, rank, pools, cached, tags, ext);
|
||||||
|
let content = Content::Structure(FlatType::TagUnion(union_tags, ext));
|
||||||
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));
|
|
||||||
|
|
||||||
register(subs, rank, pools, content)
|
register(subs, rank, pools, content)
|
||||||
}
|
}
|
||||||
|
@ -758,36 +735,9 @@ fn type_to_variable(
|
||||||
register(subs, rank, pools, content)
|
register(subs, rank, pools, content)
|
||||||
}
|
}
|
||||||
RecursiveTagUnion(rec_var, tags, ext) => {
|
RecursiveTagUnion(rec_var, tags, ext) => {
|
||||||
let mut tag_vars = MutMap::with_capacity_and_hasher(tags.len(), default_hasher());
|
let (union_tags, ext) = type_to_union_tags(subs, rank, pools, cached, tags, ext);
|
||||||
|
let content =
|
||||||
for (tag, tag_argument_types) in tags {
|
Content::Structure(FlatType::RecursiveTagUnion(*rec_var, union_tags, ext));
|
||||||
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 tag_union_var = register(subs, rank, pools, content);
|
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(
|
fn check_for_infinite_type(
|
||||||
subs: &mut Subs,
|
subs: &mut Subs,
|
||||||
problems: &mut Vec<TypeError>,
|
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() {
|
for (name_index, slice_index) in tags.iter_all() {
|
||||||
let slice = subs[slice_index];
|
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_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 new_ext_var = subs.explicit_substitute(recursive, rec_var, ext_var);
|
||||||
|
|
||||||
let flat_type =
|
let new_tags = UnionTags::insert_into_subs(subs, new_tags);
|
||||||
roc_unify::unify::from_mutmap_rec(subs, rec_var, new_tags, new_ext_var);
|
|
||||||
|
let flat_type = FlatType::RecursiveTagUnion(rec_var, new_tags, new_ext_var);
|
||||||
|
|
||||||
subs.set_content(recursive, Content::Structure(flat_type));
|
subs.set_content(recursive, Content::Structure(flat_type));
|
||||||
}
|
}
|
||||||
|
@ -1509,23 +1513,35 @@ fn deep_copy_var_help(
|
||||||
}
|
}
|
||||||
|
|
||||||
TagUnion(tags, ext_var) => {
|
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 mut new_variables = Vec::new();
|
||||||
let tag = subs[tag_index].clone();
|
for index in tags.variables() {
|
||||||
let slice = subs[index];
|
let slice = subs[index];
|
||||||
let mut new_vars = Vec::new();
|
|
||||||
for var_index in slice {
|
for var_index in slice {
|
||||||
let var = subs[var_index];
|
let var = subs[var_index];
|
||||||
let new_var = deep_copy_var_help(subs, max_rank, pools, var);
|
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);
|
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(
|
FunctionOrTagUnion(tag_name, symbol, ext_var) => FunctionOrTagUnion(
|
||||||
|
@ -1535,25 +1551,37 @@ fn deep_copy_var_help(
|
||||||
),
|
),
|
||||||
|
|
||||||
RecursiveTagUnion(rec_var, tags, ext_var) => {
|
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);
|
let mut new_variables = Vec::new();
|
||||||
|
for index in tags.variables() {
|
||||||
for (tag_index, index) in tags.iter_all() {
|
|
||||||
let tag = subs[tag_index].clone();
|
|
||||||
let slice = subs[index];
|
let slice = subs[index];
|
||||||
let mut new_vars = Vec::new();
|
|
||||||
for var_index in slice {
|
for var_index in slice {
|
||||||
let var = subs[var_index];
|
let var = subs[var_index];
|
||||||
let new_var = deep_copy_var_help(subs, max_rank, pools, var);
|
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);
|
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)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -276,6 +276,20 @@ fn list_prepend() {
|
||||||
RocList::from_slice(&[6, 4]),
|
RocList::from_slice(&[6, 4]),
|
||||||
RocList<i64>
|
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]
|
#[test]
|
||||||
|
|
|
@ -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());
|
debug_assert_eq!(tag_names.len(), variables.len());
|
||||||
|
|
||||||
Self {
|
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
|
pub fn insert_slices_into_subs<I>(subs: &mut Subs, input: I) -> Self
|
||||||
where
|
where
|
||||||
I: IntoIterator<Item = (TagName, VariableSubsSlice)>,
|
I: IntoIterator<Item = (TagName, VariableSubsSlice)>,
|
||||||
|
|
|
@ -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::ident::{Lowercase, TagName};
|
||||||
use roc_module::symbol::Symbol;
|
use roc_module::symbol::Symbol;
|
||||||
use roc_types::subs::Content::{self, *};
|
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)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
fn unify_function_or_tag_union_and_func(
|
fn unify_function_or_tag_union_and_func(
|
||||||
subs: &mut Subs,
|
subs: &mut Subs,
|
||||||
|
@ -1285,15 +1255,8 @@ fn unify_function_or_tag_union_and_func(
|
||||||
) -> Outcome {
|
) -> Outcome {
|
||||||
let tag_name = subs[*tag_name_index].clone();
|
let tag_name = subs[*tag_name_index].clone();
|
||||||
|
|
||||||
let mut new_tags = MutMap::with_capacity_and_hasher(1, default_hasher());
|
let union_tags = UnionTags::insert_slices_into_subs(subs, [(tag_name, function_arguments)]);
|
||||||
|
let content = Content::Structure(FlatType::TagUnion(union_tags, tag_ext));
|
||||||
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 new_tag_union_var = fresh(subs, pool, ctx, content);
|
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 lambda_set_ext = subs.fresh_unnamed_flex_var();
|
||||||
|
let lambda_set_content = Structure(FlatType::TagUnion(union_tags, lambda_set_ext));
|
||||||
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 tag_lambda_set = register(
|
let tag_lambda_set = register(
|
||||||
subs,
|
subs,
|
||||||
|
|
|
@ -1,17 +1,18 @@
|
||||||
#![allow(clippy::all)]
|
#![allow(clippy::all)]
|
||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
use crate::lang::constrain::Constraint::{self, *};
|
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 crate::lang::types::Type2;
|
||||||
use bumpalo::Bump;
|
use bumpalo::Bump;
|
||||||
use roc_can::expected::{Expected, PExpected};
|
use roc_can::expected::{Expected, PExpected};
|
||||||
use roc_collections::all::{BumpMap, BumpMapDefault, MutMap};
|
use roc_collections::all::{BumpMap, BumpMapDefault, MutMap};
|
||||||
|
use roc_module::ident::TagName;
|
||||||
use roc_module::symbol::Symbol;
|
use roc_module::symbol::Symbol;
|
||||||
use roc_region::all::{Located, Region};
|
use roc_region::all::{Located, Region};
|
||||||
use roc_types::solved_types::Solved;
|
use roc_types::solved_types::Solved;
|
||||||
use roc_types::subs::{
|
use roc_types::subs::{
|
||||||
AliasVariables, Content, Descriptor, FlatType, Mark, OptVariable, Rank, RecordFields, Subs,
|
AliasVariables, Content, Descriptor, FlatType, Mark, OptVariable, Rank, RecordFields, Subs,
|
||||||
Variable, VariableSubsSlice,
|
SubsSlice, UnionTags, Variable, VariableSubsSlice,
|
||||||
};
|
};
|
||||||
use roc_types::types::{
|
use roc_types::types::{
|
||||||
gather_fields_unsorted_iter, Alias, Category, ErrorType, PatternCategory, RecordField,
|
gather_fields_unsorted_iter, Alias, Category, ErrorType, PatternCategory, RecordField,
|
||||||
|
@ -831,35 +832,11 @@ fn type_to_variable<'a>(
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
TagUnion(tags, ext_id) => {
|
TagUnion(tags, ext_id) => {
|
||||||
let mut tag_vars = MutMap::default();
|
|
||||||
let ext = mempool.get(*ext_id);
|
let ext = mempool.get(*ext_id);
|
||||||
|
|
||||||
for (tag_name, tag_argument_types) in tags.iter(mempool) {
|
let (union_tags, ext) =
|
||||||
let mut tag_argument_vars = Vec::with_capacity(tag_argument_types.len());
|
type_to_union_tags(arena, mempool, subs, rank, pools, cached, tags, ext);
|
||||||
|
let content = Content::Structure(FlatType::TagUnion(union_tags, ext));
|
||||||
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));
|
|
||||||
|
|
||||||
register(subs, rank, pools, content)
|
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(
|
fn check_for_infinite_type(
|
||||||
subs: &mut Subs,
|
subs: &mut Subs,
|
||||||
problems: &mut Vec<TypeError>,
|
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() {
|
for (name_index, slice_index) in tags.iter_all() {
|
||||||
let slice = subs[slice_index];
|
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_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 new_ext_var = subs.explicit_substitute(recursive, rec_var, ext_var);
|
||||||
|
|
||||||
let flat_type =
|
let new_tags = UnionTags::insert_into_subs(subs, new_tags);
|
||||||
roc_unify::unify::from_mutmap_rec(subs, rec_var, new_tags, new_ext_var);
|
|
||||||
|
let flat_type = FlatType::RecursiveTagUnion(rec_var, new_tags, new_ext_var);
|
||||||
|
|
||||||
subs.set_content(recursive, Content::Structure(flat_type));
|
subs.set_content(recursive, Content::Structure(flat_type));
|
||||||
}
|
}
|
||||||
|
@ -1581,23 +1616,35 @@ fn deep_copy_var_help(
|
||||||
}
|
}
|
||||||
|
|
||||||
TagUnion(tags, ext_var) => {
|
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 mut new_variables = Vec::new();
|
||||||
let tag = subs[tag_index].clone();
|
for index in tags.variables() {
|
||||||
let slice = subs[index];
|
let slice = subs[index];
|
||||||
let mut new_vars = Vec::new();
|
|
||||||
for var_index in slice {
|
for var_index in slice {
|
||||||
let var = subs[var_index];
|
let var = subs[var_index];
|
||||||
let new_var = deep_copy_var_help(subs, max_rank, pools, var);
|
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);
|
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(
|
FunctionOrTagUnion(tag_name, symbol, ext_var) => FunctionOrTagUnion(
|
||||||
|
@ -1607,25 +1654,36 @@ fn deep_copy_var_help(
|
||||||
),
|
),
|
||||||
|
|
||||||
RecursiveTagUnion(rec_var, tags, ext_var) => {
|
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);
|
let mut new_variables = Vec::new();
|
||||||
|
for index in tags.variables() {
|
||||||
for (tag_index, index) in tags.iter_all() {
|
|
||||||
let tag = subs[tag_index].clone();
|
|
||||||
let slice = subs[index];
|
let slice = subs[index];
|
||||||
let mut new_vars = Vec::new();
|
|
||||||
for var_index in slice {
|
for var_index in slice {
|
||||||
let var = subs[var_index];
|
let var = subs[var_index];
|
||||||
let new_var = deep_copy_var_help(subs, max_rank, pools, var);
|
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);
|
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)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue