mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-27 13:59:08 +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;
|
||||
}
|
||||
|
||||
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,
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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>,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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)>,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
};
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue