mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-29 06:44:46 +00:00
implement inc and dec for lists
This commit is contained in:
parent
4a937b5cc2
commit
f15a50d3fa
4 changed files with 199 additions and 111 deletions
|
@ -19,7 +19,7 @@ use roc_collections::all::ImMap;
|
||||||
use roc_module::low_level::LowLevel;
|
use roc_module::low_level::LowLevel;
|
||||||
use roc_module::symbol::{Interns, Symbol};
|
use roc_module::symbol::{Interns, Symbol};
|
||||||
use roc_mono::expr::{Expr, Proc};
|
use roc_mono::expr::{Expr, Proc};
|
||||||
use roc_mono::layout::{Builtin, Layout};
|
use roc_mono::layout::{Builtin, Layout, Ownership};
|
||||||
use target_lexicon::CallingConvention;
|
use target_lexicon::CallingConvention;
|
||||||
|
|
||||||
/// This is for Inkwell's FunctionValue::verify - we want to know the verification
|
/// This is for Inkwell's FunctionValue::verify - we want to know the verification
|
||||||
|
@ -388,72 +388,9 @@ pub fn build_expr<'a, 'ctx, 'env>(
|
||||||
BasicValueEnum::PointerValue(ptr)
|
BasicValueEnum::PointerValue(ptr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
EmptyArray => {
|
EmptyArray => empty_polymorphic_list(env),
|
||||||
let struct_type = collection(env.context, env.ptr_bytes);
|
|
||||||
|
|
||||||
// The pointer should be null (aka zero) and the length should be zero,
|
|
||||||
// so the whole struct should be a const_zero
|
|
||||||
BasicValueEnum::StructValue(struct_type.const_zero())
|
|
||||||
}
|
|
||||||
Array { elem_layout, elems } => {
|
Array { elem_layout, elems } => {
|
||||||
let ctx = env.context;
|
list_literal(env, layout_ids, scope, parent, elem_layout, elems)
|
||||||
let builder = env.builder;
|
|
||||||
|
|
||||||
if elems.is_empty() {
|
|
||||||
empty_list(env)
|
|
||||||
} else {
|
|
||||||
let len_u64 = elems.len() as u64;
|
|
||||||
let elem_bytes = elem_layout.stack_size(env.ptr_bytes) as u64;
|
|
||||||
|
|
||||||
let ptr = {
|
|
||||||
let bytes_len = elem_bytes * len_u64;
|
|
||||||
let len_type = env.ptr_int();
|
|
||||||
let len = len_type.const_int(bytes_len, false);
|
|
||||||
|
|
||||||
allocate_list(env, elem_layout, len)
|
|
||||||
|
|
||||||
// TODO check if malloc returned null; if so, runtime error for OOM!
|
|
||||||
};
|
|
||||||
|
|
||||||
// Copy the elements from the list literal into the array
|
|
||||||
for (index, elem) in elems.iter().enumerate() {
|
|
||||||
let index_val = ctx.i64_type().const_int(index as u64, false);
|
|
||||||
let elem_ptr =
|
|
||||||
unsafe { builder.build_in_bounds_gep(ptr, &[index_val], "index") };
|
|
||||||
let val = build_expr(env, layout_ids, &scope, parent, &elem);
|
|
||||||
|
|
||||||
builder.build_store(elem_ptr, val);
|
|
||||||
}
|
|
||||||
|
|
||||||
let ptr_bytes = env.ptr_bytes;
|
|
||||||
let int_type = ptr_int(ctx, ptr_bytes);
|
|
||||||
let ptr_as_int = builder.build_ptr_to_int(ptr, int_type, "list_cast_ptr");
|
|
||||||
let struct_type = collection(ctx, ptr_bytes);
|
|
||||||
let len = BasicValueEnum::IntValue(env.ptr_int().const_int(len_u64, false));
|
|
||||||
let mut struct_val;
|
|
||||||
|
|
||||||
// Store the pointer
|
|
||||||
struct_val = builder
|
|
||||||
.build_insert_value(
|
|
||||||
struct_type.get_undef(),
|
|
||||||
ptr_as_int,
|
|
||||||
Builtin::WRAPPER_PTR,
|
|
||||||
"insert_ptr",
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
// Store the length
|
|
||||||
struct_val = builder
|
|
||||||
.build_insert_value(struct_val, len, Builtin::WRAPPER_LEN, "insert_len")
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
// Bitcast to an array of raw bytes
|
|
||||||
builder.build_bitcast(
|
|
||||||
struct_val.into_struct_value(),
|
|
||||||
collection(ctx, ptr_bytes),
|
|
||||||
"cast_collection",
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Struct(sorted_fields) => {
|
Struct(sorted_fields) => {
|
||||||
|
@ -722,7 +659,7 @@ pub fn build_expr<'a, 'ctx, 'env>(
|
||||||
None => panic!("There was no entry for {:?} in scope {:?}", symbol, scope),
|
None => panic!("There was no entry for {:?} in scope {:?}", symbol, scope),
|
||||||
Some((layout, ptr)) => {
|
Some((layout, ptr)) => {
|
||||||
match layout {
|
match layout {
|
||||||
Layout::Builtin(Builtin::List(_, elem_layout)) if false => {
|
Layout::Builtin(Builtin::List(Ownership::Owned, _elem_layout)) => {
|
||||||
// first run the body
|
// first run the body
|
||||||
let body = build_expr(env, layout_ids, scope, parent, expr);
|
let body = build_expr(env, layout_ids, scope, parent, expr);
|
||||||
|
|
||||||
|
@ -774,19 +711,28 @@ fn list_get_refcount_ptr<'a, 'ctx, 'env>(
|
||||||
let builder = env.builder;
|
let builder = env.builder;
|
||||||
let ctx = env.context;
|
let ctx = env.context;
|
||||||
|
|
||||||
// basic_type_from_layout(env.arena, ctx, elem_layout, env.ptr_bytes);
|
// pointer to usize
|
||||||
let elem_type = ctx.i64_type().into();
|
let ptr_bytes = env.ptr_bytes;
|
||||||
let ptr_type = get_ptr_type(&elem_type, AddressSpace::Generic);
|
let int_type = ptr_int(ctx, ptr_bytes);
|
||||||
// Load the pointer to the array data
|
|
||||||
let array_data_ptr = load_list_ptr(builder, list_wrapper, ptr_type);
|
|
||||||
|
|
||||||
// get the refcount
|
// fetch the pointer to the array data, as an integer
|
||||||
let zero_index = ctx.i64_type().const_zero();
|
let ptr_as_int = builder
|
||||||
unsafe {
|
.build_extract_value(list_wrapper, Builtin::WRAPPER_PTR, "read_list_ptr")
|
||||||
// SAFETY
|
.unwrap()
|
||||||
// index 0 is always defined for lists.
|
.into_int_value();
|
||||||
builder.build_in_bounds_gep(array_data_ptr, &[zero_index], "refcount_index")
|
|
||||||
}
|
// subtract ptr_size, to access the refcount
|
||||||
|
let refcount_ptr = builder.build_int_sub(
|
||||||
|
ptr_as_int,
|
||||||
|
ctx.i64_type().const_int(env.ptr_bytes as u64, false),
|
||||||
|
"refcount_ptr",
|
||||||
|
);
|
||||||
|
|
||||||
|
builder.build_int_to_ptr(
|
||||||
|
refcount_ptr,
|
||||||
|
int_type.ptr_type(AddressSpace::Generic),
|
||||||
|
"make ptr",
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn increment_refcount_list<'a, 'ctx, 'env>(
|
fn increment_refcount_list<'a, 'ctx, 'env>(
|
||||||
|
@ -808,7 +754,7 @@ fn increment_refcount_list<'a, 'ctx, 'env>(
|
||||||
let decremented = env.builder.build_int_sub(
|
let decremented = env.builder.build_int_sub(
|
||||||
refcount,
|
refcount,
|
||||||
ctx.i64_type().const_int(1 as u64, false),
|
ctx.i64_type().const_int(1 as u64, false),
|
||||||
"new_refcount",
|
"incremented_refcount",
|
||||||
);
|
);
|
||||||
|
|
||||||
// Mutate the new array in-place to change the element.
|
// Mutate the new array in-place to change the element.
|
||||||
|
@ -841,7 +787,7 @@ fn decrement_refcount_list<'a, 'ctx, 'env>(
|
||||||
let decremented = env.builder.build_int_add(
|
let decremented = env.builder.build_int_add(
|
||||||
ctx.i64_type().const_int(1 as u64, false),
|
ctx.i64_type().const_int(1 as u64, false),
|
||||||
refcount,
|
refcount,
|
||||||
"new_refcount",
|
"decremented_refcount",
|
||||||
);
|
);
|
||||||
|
|
||||||
// Mutate the new array in-place to change the element.
|
// Mutate the new array in-place to change the element.
|
||||||
|
@ -852,12 +798,7 @@ fn decrement_refcount_list<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
// refcount is one, and will be decremented. This list can be freed
|
// refcount is one, and will be decremented. This list can be freed
|
||||||
let build_else = || {
|
let build_else = || {
|
||||||
let array_data_ptr = load_list_ptr(
|
let free = builder.build_free(refcount_ptr);
|
||||||
builder,
|
|
||||||
original_wrapper,
|
|
||||||
ctx.i64_type().ptr_type(AddressSpace::Generic),
|
|
||||||
);
|
|
||||||
let free = builder.build_free(array_data_ptr);
|
|
||||||
|
|
||||||
builder.insert_instruction(&free, None);
|
builder.insert_instruction(&free, None);
|
||||||
|
|
||||||
|
@ -875,7 +816,7 @@ fn load_symbol<'a, 'ctx, 'env>(
|
||||||
) -> BasicValueEnum<'ctx> {
|
) -> BasicValueEnum<'ctx> {
|
||||||
match scope.get(symbol) {
|
match scope.get(symbol) {
|
||||||
Some((layout, ptr)) => match layout {
|
Some((layout, ptr)) => match layout {
|
||||||
Layout::Builtin(Builtin::List(_, _)) if false => {
|
Layout::Builtin(Builtin::List(Ownership::Owned, _)) => {
|
||||||
let load = env
|
let load = env
|
||||||
.builder
|
.builder
|
||||||
.build_load(*ptr, symbol.ident_string(&env.interns));
|
.build_load(*ptr, symbol.ident_string(&env.interns));
|
||||||
|
@ -1237,11 +1178,14 @@ pub fn allocate_list<'a, 'ctx, 'env>(
|
||||||
let bytes_len = len_type.const_int(elem_bytes, false);
|
let bytes_len = len_type.const_int(elem_bytes, false);
|
||||||
|
|
||||||
let len = builder.build_int_mul(bytes_len, length, "data_length");
|
let len = builder.build_int_mul(bytes_len, length, "data_length");
|
||||||
// TODO 8 assume 64-bit pointer/refcount
|
let len = builder.build_int_add(
|
||||||
let len = builder.build_int_add(len, len_type.const_int(8, false), "add_refcount_space");
|
len,
|
||||||
|
len_type.const_int(env.ptr_bytes as u64, false),
|
||||||
|
"add_refcount_space",
|
||||||
|
);
|
||||||
|
|
||||||
env.builder
|
env.builder
|
||||||
.build_array_malloc(elem_type, len, "create_list_ptr")
|
.build_array_malloc(ctx.i8_type(), len, "create_list_ptr")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
|
||||||
// TODO check if malloc returned null; if so, runtime error for OOM!
|
// TODO check if malloc returned null; if so, runtime error for OOM!
|
||||||
|
@ -1448,7 +1392,7 @@ fn list_repeat<'a, 'ctx, 'env>(
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
let build_else = || empty_list(env);
|
let build_else = || empty_polymorphic_list(env);
|
||||||
|
|
||||||
let struct_type = collection(ctx, env.ptr_bytes);
|
let struct_type = collection(ctx, env.ptr_bytes);
|
||||||
|
|
||||||
|
@ -1640,7 +1584,7 @@ enum InPlace {
|
||||||
Clone,
|
Clone,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn empty_list<'a, 'ctx, 'env>(env: &Env<'a, 'ctx, 'env>) -> BasicValueEnum<'ctx> {
|
fn empty_polymorphic_list<'a, 'ctx, 'env>(env: &Env<'a, 'ctx, 'env>) -> BasicValueEnum<'ctx> {
|
||||||
let ctx = env.context;
|
let ctx = env.context;
|
||||||
|
|
||||||
let struct_type = collection(ctx, env.ptr_bytes);
|
let struct_type = collection(ctx, env.ptr_bytes);
|
||||||
|
@ -1650,6 +1594,69 @@ fn empty_list<'a, 'ctx, 'env>(env: &Env<'a, 'ctx, 'env>) -> BasicValueEnum<'ctx>
|
||||||
BasicValueEnum::StructValue(struct_type.const_zero())
|
BasicValueEnum::StructValue(struct_type.const_zero())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn list_literal<'a, 'ctx, 'env>(
|
||||||
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
layout_ids: &mut LayoutIds<'a>,
|
||||||
|
scope: &Scope<'a, 'ctx>,
|
||||||
|
parent: FunctionValue<'ctx>,
|
||||||
|
elem_layout: &Layout<'a>,
|
||||||
|
elems: &&[roc_mono::expr::Expr<'a>],
|
||||||
|
) -> BasicValueEnum<'ctx> {
|
||||||
|
let ctx = env.context;
|
||||||
|
let builder = env.builder;
|
||||||
|
|
||||||
|
let len_u64 = elems.len() as u64;
|
||||||
|
let elem_bytes = elem_layout.stack_size(env.ptr_bytes) as u64;
|
||||||
|
|
||||||
|
let ptr = {
|
||||||
|
let bytes_len = elem_bytes * len_u64;
|
||||||
|
let len_type = env.ptr_int();
|
||||||
|
let len = len_type.const_int(bytes_len, false);
|
||||||
|
|
||||||
|
allocate_list(env, elem_layout, len)
|
||||||
|
|
||||||
|
// TODO check if malloc returned null; if so, runtime error for OOM!
|
||||||
|
};
|
||||||
|
|
||||||
|
// Copy the elements from the list literal into the array
|
||||||
|
for (index, elem) in elems.iter().enumerate() {
|
||||||
|
let index_val = ctx.i64_type().const_int(index as u64, false);
|
||||||
|
let elem_ptr = unsafe { builder.build_in_bounds_gep(ptr, &[index_val], "index") };
|
||||||
|
let val = build_expr(env, layout_ids, &scope, parent, &elem);
|
||||||
|
|
||||||
|
builder.build_store(elem_ptr, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
let ptr_bytes = env.ptr_bytes;
|
||||||
|
let int_type = ptr_int(ctx, ptr_bytes);
|
||||||
|
let ptr_as_int = builder.build_ptr_to_int(ptr, int_type, "list_cast_ptr");
|
||||||
|
let struct_type = collection(ctx, ptr_bytes);
|
||||||
|
let len = BasicValueEnum::IntValue(env.ptr_int().const_int(len_u64, false));
|
||||||
|
let mut struct_val;
|
||||||
|
|
||||||
|
// Store the pointer
|
||||||
|
struct_val = builder
|
||||||
|
.build_insert_value(
|
||||||
|
struct_type.get_undef(),
|
||||||
|
ptr_as_int,
|
||||||
|
Builtin::WRAPPER_PTR,
|
||||||
|
"insert_ptr",
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// Store the length
|
||||||
|
struct_val = builder
|
||||||
|
.build_insert_value(struct_val, len, Builtin::WRAPPER_LEN, "insert_len")
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// Bitcast to an array of raw bytes
|
||||||
|
builder.build_bitcast(
|
||||||
|
struct_val.into_struct_value(),
|
||||||
|
collection(ctx, ptr_bytes),
|
||||||
|
"cast_collection",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
fn bounds_check_comparison<'ctx>(
|
fn bounds_check_comparison<'ctx>(
|
||||||
builder: &Builder<'ctx>,
|
builder: &Builder<'ctx>,
|
||||||
elem_index: IntValue<'ctx>,
|
elem_index: IntValue<'ctx>,
|
||||||
|
@ -2009,7 +2016,7 @@ fn run_low_level<'a, 'ctx, 'env>(
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
let build_else = || empty_list(env);
|
let build_else = || empty_polymorphic_list(env);
|
||||||
|
|
||||||
let struct_type = collection(ctx, env.ptr_bytes);
|
let struct_type = collection(ctx, env.ptr_bytes);
|
||||||
|
|
||||||
|
@ -2022,7 +2029,7 @@ fn run_low_level<'a, 'ctx, 'env>(
|
||||||
BasicTypeEnum::StructType(struct_type),
|
BasicTypeEnum::StructType(struct_type),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Layout::Builtin(Builtin::EmptyList) => empty_list(env),
|
Layout::Builtin(Builtin::EmptyList) => empty_polymorphic_list(env),
|
||||||
_ => {
|
_ => {
|
||||||
unreachable!("Invalid List layout for List.reverse {:?}", list_layout);
|
unreachable!("Invalid List layout for List.reverse {:?}", list_layout);
|
||||||
}
|
}
|
||||||
|
@ -2330,7 +2337,7 @@ fn list_append<'a, 'ctx, 'env>(
|
||||||
match first_list_layout {
|
match first_list_layout {
|
||||||
Layout::Builtin(Builtin::EmptyList) => {
|
Layout::Builtin(Builtin::EmptyList) => {
|
||||||
match second_list_layout {
|
match second_list_layout {
|
||||||
Layout::Builtin(Builtin::EmptyList) => empty_list(env),
|
Layout::Builtin(Builtin::EmptyList) => empty_polymorphic_list(env),
|
||||||
Layout::Builtin(Builtin::List(_, elem_layout)) => {
|
Layout::Builtin(Builtin::List(_, elem_layout)) => {
|
||||||
// THIS IS A COPY AND PASTE
|
// THIS IS A COPY AND PASTE
|
||||||
// All the code under the Layout::Builtin(Builtin::List()) match branch
|
// All the code under the Layout::Builtin(Builtin::List()) match branch
|
||||||
|
@ -2358,7 +2365,7 @@ fn list_append<'a, 'ctx, 'env>(
|
||||||
BasicValueEnum::StructValue(new_wrapper)
|
BasicValueEnum::StructValue(new_wrapper)
|
||||||
};
|
};
|
||||||
|
|
||||||
let build_second_list_else = || empty_list(env);
|
let build_second_list_else = || empty_polymorphic_list(env);
|
||||||
|
|
||||||
build_basic_phi2(
|
build_basic_phi2(
|
||||||
env,
|
env,
|
||||||
|
@ -2646,7 +2653,7 @@ fn list_append<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
let if_first_list_is_empty = || {
|
let if_first_list_is_empty = || {
|
||||||
match second_list_layout {
|
match second_list_layout {
|
||||||
Layout::Builtin(Builtin::EmptyList) => empty_list(env),
|
Layout::Builtin(Builtin::EmptyList) => empty_polymorphic_list(env),
|
||||||
Layout::Builtin(Builtin::List(_, elem_layout)) => {
|
Layout::Builtin(Builtin::List(_, elem_layout)) => {
|
||||||
// second_list_len > 0
|
// second_list_len > 0
|
||||||
// We do this check to avoid allocating memory. If the second input
|
// We do this check to avoid allocating memory. If the second input
|
||||||
|
@ -2669,7 +2676,7 @@ fn list_append<'a, 'ctx, 'env>(
|
||||||
BasicValueEnum::StructValue(new_wrapper)
|
BasicValueEnum::StructValue(new_wrapper)
|
||||||
};
|
};
|
||||||
|
|
||||||
let build_second_list_else = || empty_list(env);
|
let build_second_list_else = || empty_polymorphic_list(env);
|
||||||
|
|
||||||
build_basic_phi2(
|
build_basic_phi2(
|
||||||
env,
|
env,
|
||||||
|
|
|
@ -616,17 +616,54 @@ mod gen_list {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn gen_list_increment_decrement() {
|
fn empty_list_increment_decrement() {
|
||||||
assert_evals_to!(
|
assert_evals_to!(
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
x = [ 1,2,3 ]
|
x : List Int
|
||||||
|
x = []
|
||||||
|
|
||||||
List.len x
|
List.len x + List.len x
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
3,
|
0,
|
||||||
i64
|
i64
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn list_literal_increment_decrement() {
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
x : List Int
|
||||||
|
x = [1,2,3]
|
||||||
|
|
||||||
|
List.len x + List.len x
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
6,
|
||||||
|
i64
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn list_pass_to_function() {
|
||||||
|
// yes
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
x : List Int
|
||||||
|
x = [1,2,3]
|
||||||
|
|
||||||
|
id : List Int -> List Int
|
||||||
|
id = \y -> y
|
||||||
|
|
||||||
|
id x
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
&[1, 2, 3],
|
||||||
|
&'static [i64]
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -563,7 +563,21 @@ impl<'a> Expr<'a> {
|
||||||
alloc.intersperse(it, alloc.space())
|
alloc.intersperse(it, alloc.space())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CallByName { name, .. } => alloc.text("*magic*"),
|
CallByName { name, args, .. } => {
|
||||||
|
let doc_name = alloc.text(format!("Call {}", name));
|
||||||
|
let doc_args = args.iter().map(|(expr, _)| expr.to_doc(alloc, true));
|
||||||
|
|
||||||
|
let it = std::iter::once(doc_name).chain(doc_args);
|
||||||
|
|
||||||
|
if parens {
|
||||||
|
alloc
|
||||||
|
.text("(")
|
||||||
|
.append(alloc.intersperse(it, alloc.space()))
|
||||||
|
.append(alloc.text(")"))
|
||||||
|
} else {
|
||||||
|
alloc.intersperse(it, alloc.space())
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => todo!("not yet implemented: {:?}", self),
|
_ => todo!("not yet implemented: {:?}", self),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ mod test_mono {
|
||||||
use roc_mono::expr::Expr::{self, *};
|
use roc_mono::expr::Expr::{self, *};
|
||||||
use roc_mono::expr::{InProgressProc, Procs};
|
use roc_mono::expr::{InProgressProc, Procs};
|
||||||
use roc_mono::layout;
|
use roc_mono::layout;
|
||||||
|
use roc_mono::layout::Ownership::Owned;
|
||||||
use roc_mono::layout::{Builtin, Layout, LayoutCache};
|
use roc_mono::layout::{Builtin, Layout, LayoutCache};
|
||||||
use roc_types::subs::Subs;
|
use roc_types::subs::Subs;
|
||||||
|
|
||||||
|
@ -632,7 +633,10 @@ mod test_mono {
|
||||||
CallByName {
|
CallByName {
|
||||||
name: Symbol::LIST_GET,
|
name: Symbol::LIST_GET,
|
||||||
layout: Layout::FunctionPointer(
|
layout: Layout::FunctionPointer(
|
||||||
&[Layout::Builtin(Builtin::List(&I64_LAYOUT)), I64_LAYOUT],
|
&[
|
||||||
|
Layout::Builtin(Builtin::List(Owned, &I64_LAYOUT)),
|
||||||
|
I64_LAYOUT,
|
||||||
|
],
|
||||||
&Layout::Union(&[&[I64_LAYOUT], &[I64_LAYOUT, I64_LAYOUT]]),
|
&Layout::Union(&[&[I64_LAYOUT], &[I64_LAYOUT, I64_LAYOUT]]),
|
||||||
),
|
),
|
||||||
args: &vec![
|
args: &vec![
|
||||||
|
@ -641,11 +645,11 @@ mod test_mono {
|
||||||
name: Symbol::LIST_SET,
|
name: Symbol::LIST_SET,
|
||||||
layout: Layout::FunctionPointer(
|
layout: Layout::FunctionPointer(
|
||||||
&[
|
&[
|
||||||
Layout::Builtin(Builtin::List(&I64_LAYOUT)),
|
Layout::Builtin(Builtin::List(Owned, &I64_LAYOUT)),
|
||||||
I64_LAYOUT,
|
I64_LAYOUT,
|
||||||
I64_LAYOUT,
|
I64_LAYOUT,
|
||||||
],
|
],
|
||||||
&Layout::Builtin(Builtin::List(&I64_LAYOUT)),
|
&Layout::Builtin(Builtin::List(Owned, &I64_LAYOUT)),
|
||||||
),
|
),
|
||||||
args: &vec![
|
args: &vec![
|
||||||
(
|
(
|
||||||
|
@ -653,13 +657,13 @@ mod test_mono {
|
||||||
elem_layout: I64_LAYOUT,
|
elem_layout: I64_LAYOUT,
|
||||||
elems: &vec![Int(12), Int(9), Int(7), Int(3)],
|
elems: &vec![Int(12), Int(9), Int(7), Int(3)],
|
||||||
},
|
},
|
||||||
Layout::Builtin(Builtin::List(&I64_LAYOUT)),
|
Layout::Builtin(Builtin::List(Owned, &I64_LAYOUT)),
|
||||||
),
|
),
|
||||||
(Int(1), I64_LAYOUT),
|
(Int(1), I64_LAYOUT),
|
||||||
(Int(42), I64_LAYOUT),
|
(Int(42), I64_LAYOUT),
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
Layout::Builtin(Builtin::List(&I64_LAYOUT)),
|
Layout::Builtin(Builtin::List(Owned, &I64_LAYOUT)),
|
||||||
),
|
),
|
||||||
(Int(1), I64_LAYOUT),
|
(Int(1), I64_LAYOUT),
|
||||||
],
|
],
|
||||||
|
@ -976,4 +980,30 @@ mod test_mono {
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn pass_list_to_function() {
|
||||||
|
compiles_to_string(
|
||||||
|
r#"
|
||||||
|
x : List Int
|
||||||
|
x = [1,2,3]
|
||||||
|
|
||||||
|
id : a -> a
|
||||||
|
id = \y -> y
|
||||||
|
|
||||||
|
id x
|
||||||
|
"#,
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
procedure Test.1 (Test.3):
|
||||||
|
Load Test.3
|
||||||
|
Dec Test.3
|
||||||
|
|
||||||
|
Store Test.0: [ 1i64, 2i64, 3i64 ]
|
||||||
|
Call Test.1 (Load Test.0)
|
||||||
|
Dec Test.0
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue