mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-28 22:34:45 +00:00
working is_empty (without RC)
This commit is contained in:
parent
167858ef06
commit
345ecd434b
2 changed files with 198 additions and 28 deletions
|
@ -966,8 +966,6 @@ pub fn build_exp_expr<'a, 'ctx, 'env>(
|
||||||
tag_name,
|
tag_name,
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
dbg!(&arguments, &fields);
|
|
||||||
panic!();
|
|
||||||
let tag_layout = Layout::Union(fields);
|
let tag_layout = Layout::Union(fields);
|
||||||
|
|
||||||
debug_assert!(*union_size > 1);
|
debug_assert!(*union_size > 1);
|
||||||
|
@ -1041,6 +1039,99 @@ pub fn build_exp_expr<'a, 'ctx, 'env>(
|
||||||
data_ptr.into()
|
data_ptr.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Tag {
|
||||||
|
arguments,
|
||||||
|
tag_layout:
|
||||||
|
Layout::NullableUnion {
|
||||||
|
nullable_id,
|
||||||
|
nullable_layout: _,
|
||||||
|
foo: fields,
|
||||||
|
},
|
||||||
|
union_size,
|
||||||
|
tag_id,
|
||||||
|
tag_name,
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
let tag_layout = Layout::Union(fields);
|
||||||
|
if *tag_id == *nullable_id as u8 {
|
||||||
|
let output_type =
|
||||||
|
basic_type_from_layout(env.arena, env.context, &tag_layout, env.ptr_bytes)
|
||||||
|
.ptr_type(AddressSpace::Generic);
|
||||||
|
|
||||||
|
return output_type.const_null().into();
|
||||||
|
}
|
||||||
|
|
||||||
|
debug_assert!(*union_size > 1);
|
||||||
|
let ptr_size = env.ptr_bytes;
|
||||||
|
|
||||||
|
let ctx = env.context;
|
||||||
|
let builder = env.builder;
|
||||||
|
|
||||||
|
// Determine types
|
||||||
|
let num_fields = arguments.len() + 1;
|
||||||
|
let mut field_types = Vec::with_capacity_in(num_fields, env.arena);
|
||||||
|
let mut field_vals = Vec::with_capacity_in(num_fields, env.arena);
|
||||||
|
|
||||||
|
let tag_field_layouts = if let TagName::Closure(_) = tag_name {
|
||||||
|
// closures ignore (and do not store) the discriminant
|
||||||
|
&fields[*tag_id as usize][1..]
|
||||||
|
} else {
|
||||||
|
&fields[*tag_id as usize]
|
||||||
|
};
|
||||||
|
|
||||||
|
for (field_symbol, tag_field_layout) in arguments.iter().zip(tag_field_layouts.iter()) {
|
||||||
|
let (val, val_layout) = load_symbol_and_layout(env, scope, field_symbol);
|
||||||
|
|
||||||
|
// Zero-sized fields have no runtime representation.
|
||||||
|
// The layout of the struct expects them to be dropped!
|
||||||
|
if !tag_field_layout.is_dropped_because_empty() {
|
||||||
|
let field_type =
|
||||||
|
basic_type_from_layout(env.arena, env.context, tag_field_layout, ptr_size);
|
||||||
|
|
||||||
|
field_types.push(field_type);
|
||||||
|
|
||||||
|
if let Layout::RecursivePointer = tag_field_layout {
|
||||||
|
debug_assert!(val.is_pointer_value());
|
||||||
|
|
||||||
|
// we store recursive pointers as `i64*`
|
||||||
|
let ptr = cast_basic_basic(
|
||||||
|
builder,
|
||||||
|
val,
|
||||||
|
ctx.i64_type().ptr_type(AddressSpace::Generic).into(),
|
||||||
|
);
|
||||||
|
|
||||||
|
field_vals.push(ptr);
|
||||||
|
} else {
|
||||||
|
// this check fails for recursive tag unions, but can be helpful while debugging
|
||||||
|
debug_assert_eq!(tag_field_layout, val_layout);
|
||||||
|
|
||||||
|
field_vals.push(val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the struct_type
|
||||||
|
let data_ptr = reserve_with_refcount(env, &tag_layout);
|
||||||
|
let struct_type = ctx.struct_type(field_types.into_bump_slice(), false);
|
||||||
|
let struct_ptr = cast_basic_basic(
|
||||||
|
builder,
|
||||||
|
data_ptr.into(),
|
||||||
|
struct_type.ptr_type(AddressSpace::Generic).into(),
|
||||||
|
)
|
||||||
|
.into_pointer_value();
|
||||||
|
|
||||||
|
// Insert field exprs into struct_val
|
||||||
|
for (index, field_val) in field_vals.into_iter().enumerate() {
|
||||||
|
let field_ptr = builder
|
||||||
|
.build_struct_gep(struct_ptr, index as u32, "struct_gep")
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
builder.build_store(field_ptr, field_val);
|
||||||
|
}
|
||||||
|
|
||||||
|
data_ptr.into()
|
||||||
|
}
|
||||||
|
|
||||||
Tag { .. } => unreachable!("tags should have a Union or RecursiveUnion layout"),
|
Tag { .. } => unreachable!("tags should have a Union or RecursiveUnion layout"),
|
||||||
|
|
||||||
Reset(_) => todo!(),
|
Reset(_) => todo!(),
|
||||||
|
@ -1127,7 +1218,7 @@ pub fn build_exp_expr<'a, 'ctx, 'env>(
|
||||||
.struct_type(field_types.into_bump_slice(), false);
|
.struct_type(field_types.into_bump_slice(), false);
|
||||||
|
|
||||||
// cast the argument bytes into the desired shape for this tag
|
// cast the argument bytes into the desired shape for this tag
|
||||||
let argument = load_symbol(env, scope, structure);
|
let (argument, structure_layout) = load_symbol_and_layout(env, scope, structure);
|
||||||
|
|
||||||
let struct_layout = Layout::Struct(field_layouts);
|
let struct_layout = Layout::Struct(field_layouts);
|
||||||
match argument {
|
match argument {
|
||||||
|
@ -1154,31 +1245,72 @@ pub fn build_exp_expr<'a, 'ctx, 'env>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PointerValue(value) => {
|
PointerValue(value) => {
|
||||||
let ptr = cast_basic_basic(
|
match structure_layout {
|
||||||
builder,
|
Layout::NullableUnion { nullable_id, .. } if *index == 0 => {
|
||||||
value.into(),
|
let ptr = value;
|
||||||
struct_type.ptr_type(AddressSpace::Generic).into(),
|
let is_null = env.builder.build_is_null(ptr, "is_null");
|
||||||
)
|
|
||||||
.into_pointer_value();
|
|
||||||
|
|
||||||
let elem_ptr = builder
|
let ctx = env.context;
|
||||||
.build_struct_gep(ptr, *index as u32, "at_index_struct_gep")
|
let then_block = ctx.append_basic_block(parent, "then");
|
||||||
.unwrap();
|
let else_block = ctx.append_basic_block(parent, "else");
|
||||||
|
let cont_block = ctx.append_basic_block(parent, "cont");
|
||||||
|
|
||||||
let result = builder.build_load(elem_ptr, "load_at_index_ptr");
|
let result = builder.build_alloca(ctx.i64_type(), "result");
|
||||||
|
|
||||||
if let Some(Layout::RecursivePointer) = field_layouts.get(*index as usize) {
|
env.builder.build_switch(
|
||||||
// a recursive field is stored as a `i64*`, to use it we must cast it to
|
is_null,
|
||||||
// a pointer to the block of memory representation
|
else_block,
|
||||||
cast_basic_basic(
|
&[(ctx.bool_type().const_int(1, false), then_block)],
|
||||||
builder,
|
);
|
||||||
result,
|
|
||||||
block_of_memory(env.context, &struct_layout, env.ptr_bytes)
|
{
|
||||||
.ptr_type(AddressSpace::Generic)
|
env.builder.position_at_end(then_block);
|
||||||
.into(),
|
let tag_id = ctx.i64_type().const_int(*nullable_id as u64, false);
|
||||||
)
|
env.builder.build_store(result, tag_id);
|
||||||
} else {
|
env.builder.build_unconditional_branch(cont_block);
|
||||||
result
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
env.builder.position_at_end(else_block);
|
||||||
|
let tag_id = extract_tag_discriminant_ptr(env, ptr);
|
||||||
|
env.builder.build_store(result, tag_id);
|
||||||
|
env.builder.build_unconditional_branch(cont_block);
|
||||||
|
}
|
||||||
|
|
||||||
|
env.builder.position_at_end(cont_block);
|
||||||
|
|
||||||
|
env.builder.build_load(result, "load_result")
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
let ptr = cast_basic_basic(
|
||||||
|
builder,
|
||||||
|
value.into(),
|
||||||
|
struct_type.ptr_type(AddressSpace::Generic).into(),
|
||||||
|
)
|
||||||
|
.into_pointer_value();
|
||||||
|
|
||||||
|
let elem_ptr = builder
|
||||||
|
.build_struct_gep(ptr, *index as u32, "at_index_struct_gep")
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let result = builder.build_load(elem_ptr, "load_at_index_ptr");
|
||||||
|
|
||||||
|
if let Some(Layout::RecursivePointer) =
|
||||||
|
field_layouts.get(*index as usize)
|
||||||
|
{
|
||||||
|
// a recursive field is stored as a `i64*`, to use it we must cast it to
|
||||||
|
// a pointer to the block of memory representation
|
||||||
|
cast_basic_basic(
|
||||||
|
builder,
|
||||||
|
result,
|
||||||
|
block_of_memory(env.context, &struct_layout, env.ptr_bytes)
|
||||||
|
.ptr_type(AddressSpace::Generic)
|
||||||
|
.into(),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
result
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => panic!("cannot look up index in {:?}", argument),
|
_ => panic!("cannot look up index in {:?}", argument),
|
||||||
|
@ -1842,7 +1974,7 @@ pub fn cast_basic_basic<'ctx>(
|
||||||
builder.build_load(to_type_pointer, "")
|
builder.build_load(to_type_pointer, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn extract_tag_discriminant<'a, 'ctx, 'env>(
|
fn extract_tag_discriminant_struct<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
from_value: StructValue<'ctx>,
|
from_value: StructValue<'ctx>,
|
||||||
) -> IntValue<'ctx> {
|
) -> IntValue<'ctx> {
|
||||||
|
@ -1858,6 +1990,23 @@ fn extract_tag_discriminant<'a, 'ctx, 'env>(
|
||||||
.into_int_value()
|
.into_int_value()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn extract_tag_discriminant_ptr<'a, 'ctx, 'env>(
|
||||||
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
from_value: PointerValue<'ctx>,
|
||||||
|
) -> IntValue<'ctx> {
|
||||||
|
let ptr = cast_basic_basic(
|
||||||
|
env.builder,
|
||||||
|
from_value.into(),
|
||||||
|
env.context
|
||||||
|
.i64_type()
|
||||||
|
.ptr_type(AddressSpace::Generic)
|
||||||
|
.into(),
|
||||||
|
)
|
||||||
|
.into_pointer_value();
|
||||||
|
|
||||||
|
env.builder.build_load(ptr, "load_tag_id").into_int_value()
|
||||||
|
}
|
||||||
|
|
||||||
struct SwitchArgsIr<'a, 'ctx> {
|
struct SwitchArgsIr<'a, 'ctx> {
|
||||||
pub cond_symbol: Symbol,
|
pub cond_symbol: Symbol,
|
||||||
pub cond_layout: Layout<'a>,
|
pub cond_layout: Layout<'a>,
|
||||||
|
@ -1933,7 +2082,7 @@ fn build_switch_ir<'a, 'ctx, 'env>(
|
||||||
cond_layout = Layout::Builtin(Builtin::Int64);
|
cond_layout = Layout::Builtin(Builtin::Int64);
|
||||||
let full_cond = load_symbol(env, scope, cond_symbol).into_struct_value();
|
let full_cond = load_symbol(env, scope, cond_symbol).into_struct_value();
|
||||||
|
|
||||||
extract_tag_discriminant(env, full_cond)
|
extract_tag_discriminant_struct(env, full_cond)
|
||||||
}
|
}
|
||||||
Layout::Builtin(_) => load_symbol(env, scope, cond_symbol).into_int_value(),
|
Layout::Builtin(_) => load_symbol(env, scope, cond_symbol).into_int_value(),
|
||||||
other => todo!("Build switch value from layout: {:?}", other),
|
other => todo!("Build switch value from layout: {:?}", other),
|
||||||
|
|
|
@ -3,10 +3,31 @@ app "hello-world"
|
||||||
imports []
|
imports []
|
||||||
provides [ main ] to base
|
provides [ main ] to base
|
||||||
|
|
||||||
|
|
||||||
|
ConsList a : [ Cons a (ConsList a), Nil ]
|
||||||
|
|
||||||
|
empty : ConsList a
|
||||||
|
empty = Nil
|
||||||
|
|
||||||
|
isEmpty : ConsList a -> Bool
|
||||||
|
isEmpty = \list ->
|
||||||
|
when list is
|
||||||
|
Cons _ _ ->
|
||||||
|
False
|
||||||
|
|
||||||
|
Nil ->
|
||||||
|
True
|
||||||
|
|
||||||
|
|
||||||
greeting =
|
greeting =
|
||||||
hi = "Hello"
|
hi = "Hello"
|
||||||
name = "World"
|
name = "World"
|
||||||
|
|
||||||
"\(hi), \(name)!!!!!!!!!!!!!"
|
"\(hi), \(name)!!!!!!!!!!!!!"
|
||||||
|
|
||||||
main = greeting
|
main =
|
||||||
|
myList : ConsList (Int *)
|
||||||
|
myList = empty
|
||||||
|
|
||||||
|
|
||||||
|
if isEmpty myList then greeting else greeting
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue