pattern match on single-tag tag unions

in LLVM and crane
This commit is contained in:
Folkert 2020-03-17 19:44:59 +01:00
parent b5abed5f54
commit 6253d2d1af
4 changed files with 60 additions and 7 deletions

View file

@ -11,7 +11,7 @@ use inkwell::{AddressSpace, FloatPredicate, IntPredicate};
use crate::llvm::convert::{ use crate::llvm::convert::{
basic_type_from_layout, collection_wrapper, get_array_type, get_fn_type, basic_type_from_layout, collection_wrapper, get_array_type, get_fn_type,
}; };
use roc_collections::all::{ImMap, MutMap}; use roc_collections::all::ImMap;
use roc_module::symbol::{Interns, Symbol}; use roc_module::symbol::{Interns, Symbol};
use roc_mono::expr::{Expr, Proc, Procs}; use roc_mono::expr::{Expr, Proc, Procs};
use roc_mono::layout::{Builtin, Layout}; use roc_mono::layout::{Builtin, Layout};
@ -316,11 +316,10 @@ pub fn build_expr<'a, 'ctx, 'env>(
BasicValueEnum::StructValue(struct_val.into_struct_value()) BasicValueEnum::StructValue(struct_val.into_struct_value())
} }
Tag { Tag {
tag_id, union_size,
arguments, arguments,
tag_layout,
.. ..
} => { } if *union_size == 1 => {
/* /*
// put the discriminant in the first slot // put the discriminant in the first slot
let discriminant = ( let discriminant = (
@ -393,6 +392,16 @@ pub fn build_expr<'a, 'ctx, 'env>(
.build_extract_value(struct_val, index, "field_access") .build_extract_value(struct_val, index, "field_access")
.unwrap() .unwrap()
} }
AccessAtIndex { index, expr, .. } => {
let builder = env.builder;
// Get Struct val
let struct_val = build_expr(env, &scope, parent, expr, procs).into_struct_value();
builder
.build_extract_value(struct_val, *index as u32, "tag_field_access")
.unwrap()
}
_ => { _ => {
panic!("I don't yet know how to LLVM build {:?}", expr); panic!("I don't yet know how to LLVM build {:?}", expr);
} }

View file

@ -69,7 +69,7 @@ pub fn basic_type_from_layout<'ctx>(
.as_basic_type_enum() .as_basic_type_enum()
} }
Union(tags) if tags.len() == 1 => { Union(tags) if tags.len() == 1 => {
let (_, layouts) = tags.into_iter().next().unwrap(); let (_, layouts) = tags.iter().next().unwrap();
// Determine types // Determine types
let mut field_types = Vec::with_capacity_in(layouts.len(), arena); let mut field_types = Vec::with_capacity_in(layouts.len(), arena);
@ -82,7 +82,7 @@ pub fn basic_type_from_layout<'ctx>(
.struct_type(field_types.into_bump_slice(), false) .struct_type(field_types.into_bump_slice(), false)
.as_basic_type_enum() .as_basic_type_enum()
} }
Union(tags) => { Union(_) => {
// TODO make this dynamic // TODO make this dynamic
let ptr_size = std::mem::size_of::<i64>(); let ptr_size = std::mem::size_of::<i64>();
let union_size = layout.stack_size(ptr_size as u32); let union_size = layout.stack_size(ptr_size as u32);

View file

@ -708,6 +708,38 @@ mod test_gen {
); );
} }
#[test]
fn when_one_element_tag() {
assert_evals_to!(
indoc!(
r#"
x : [ Pair Int Int ]
x = Pair 0x2 0x3
when x is
Pair l r -> l + r
"#
),
5,
i64
);
}
#[test]
fn twice_record_access() {
assert_evals_to!(
indoc!(
r#"
x = {a: 0x2, b: 0x3 }
x.a + x.b
"#
),
5,
i64
);
}
#[test] #[test]
fn gen_when_one_branch() { fn gen_when_one_branch() {
assert_evals_to!( assert_evals_to!(
@ -1312,5 +1344,17 @@ mod test_gen {
19, 19,
i64 i64
); );
assert_evals_to!(
indoc!(
r#"
rec = { x: 15, y: 17, z: 19 }
rec.z + rec.x
"#
),
34,
i64
);
} }
} }

View file

@ -910,7 +910,7 @@ fn store_pattern2<'a>(
match argument { match argument {
Identifier(symbol) => { Identifier(symbol) => {
// store immediately in the given symbol // store immediately in the given symbol
stored.push((*symbol, layout.clone(), load)); stored.push((*symbol, arg_layout.clone(), load));
} }
Underscore => { Underscore => {
// ignore // ignore