alignment in multi tag pattern match

This commit is contained in:
Folkert 2020-11-24 23:15:32 +01:00
parent 69734e837e
commit 0f1baef160
3 changed files with 130 additions and 14 deletions

View file

@ -481,7 +481,7 @@ mod gen_tags {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r#"
wrapper = \{} -> wrapper = \{} ->
when 2 is when 2 is
2 if False -> 0 2 if False -> 0
_ -> 42 _ -> 42
@ -499,7 +499,7 @@ mod gen_tags {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r#"
wrapper = \{} -> wrapper = \{} ->
when 2 is when 2 is
2 if True -> 42 2 if True -> 42
_ -> 0 _ -> 0
@ -517,7 +517,7 @@ mod gen_tags {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r#"
wrapper = \{} -> wrapper = \{} ->
when 2 is when 2 is
_ if False -> 0 _ if False -> 0
_ -> 42 _ -> 42
@ -637,7 +637,7 @@ mod gen_tags {
x : Maybe (Maybe Int) x : Maybe (Maybe Int)
x = Just (Just 41) x = Just (Just 41)
main = main =
x x
"# "#
), ),
@ -701,11 +701,11 @@ mod gen_tags {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r#"
wrapper = \{} -> wrapper = \{} ->
x : [ Red, White, Blue ] x : [ Red, White, Blue ]
x = Blue x = Blue
y = y =
when x is when x is
Red -> 1 Red -> 1
White -> 2 White -> 2
@ -726,8 +726,8 @@ mod gen_tags {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r#"
wrapper = \{} -> wrapper = \{} ->
y = y =
when 1 + 2 is when 1 + 2 is
3 -> 3 3 -> 3
1 -> 1 1 -> 1
@ -745,7 +745,7 @@ mod gen_tags {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r#"
y = y =
if 1 + 2 > 0 then if 1 + 2 > 0 then
3 3
else else
@ -778,7 +778,7 @@ mod gen_tags {
x = Three (1 == 1) 32 x = Three (1 == 1) 32
when x is when x is
Three bool int -> Three bool int ->
{ bool, int } { bool, int }
#" #"
), ),
@ -792,7 +792,7 @@ mod gen_tags {
x = Three (1 == 1) (if True then Red else if True then Green else Blue) 32 x = Three (1 == 1) (if True then Red else if True then Green else Blue) 32
when x is when x is
Three bool color int -> Three bool color int ->
{ bool, color, int } { bool, color, int }
#" #"
), ),
@ -800,4 +800,72 @@ mod gen_tags {
(i64, bool, u8) (i64, bool, u8)
); );
} }
#[test]
fn alignment_in_multi_tag_construction() {
assert_evals_to!(
indoc!(
r"#
x : [ Three Bool Int, Empty ]
x = Three (1 == 1) 32
x
#"
),
(1, 32i64, true),
(i64, i64, bool)
);
assert_evals_to!(
indoc!(
r"#
x : [ Three Bool [ Red, Green, Blue ] Int, Empty ]
x = Three (1 == 1) (if True then Red else if True then Green else Blue) 32
x
#"
),
(1, 32i64, true, 2u8),
(i64, i64, bool, u8)
);
}
#[test]
fn alignment_in_multi_tag_pattern_match() {
assert_evals_to!(
indoc!(
r"#
x : [ Three Bool Int, Empty ]
x = Three (1 == 1) 32
when x is
Three bool int ->
{ bool, int }
Empty ->
{ bool: False, int: 0 }
#"
),
(32i64, true),
(i64, bool)
);
assert_evals_to!(
indoc!(
r"#
x : [ Three Bool [ Red, Green, Blue ] Int, Empty ]
x = Three (1 == 1) (if True then Red else if True then Green else Blue) 32
when x is
Three bool color int ->
{ bool, color, int }
Empty ->
{ bool: False, color: Red, int: 0 }
#"
),
(32i64, true, 2u8),
(i64, bool, u8)
);
}
} }

View file

@ -2472,12 +2472,33 @@ pub fn with_hole<'a>(
.find(|(_, (key, _))| key == &tag_name) .find(|(_, (key, _))| key == &tag_name)
.expect("tag must be in its own type"); .expect("tag must be in its own type");
let mut field_symbols_temp = Vec::with_capacity_in(args.len(), env.arena);
for (var, arg) in args.drain(..) {
// Layout will unpack this unwrapped tack if it only has one (non-zero-sized) field
let layout = layout_cache
.from_var(env.arena, var, env.subs)
.unwrap_or_else(|err| {
panic!("TODO turn fn_var into a RuntimeError {:?}", err)
});
let alignment = layout.alignment_bytes(8);
let symbol = possible_reuse_symbol(env, procs, &arg.value);
field_symbols_temp.push((
alignment,
symbol,
((var, arg), &*env.arena.alloc(symbol)),
));
}
field_symbols_temp.sort_by(|a, b| b.0.cmp(&a.0));
let mut field_symbols: Vec<Symbol> = Vec::with_capacity_in(args.len(), arena); let mut field_symbols: Vec<Symbol> = Vec::with_capacity_in(args.len(), arena);
let tag_id_symbol = env.unique_symbol(); let tag_id_symbol = env.unique_symbol();
field_symbols.push(tag_id_symbol); field_symbols.push(tag_id_symbol);
for (_, arg) in args.iter() { for (_, symbol, _) in field_symbols_temp.iter() {
field_symbols.push(possible_reuse_symbol(env, procs, &arg.value)); field_symbols.push(*symbol);
} }
let mut layouts: Vec<&'a [Layout<'a>]> = let mut layouts: Vec<&'a [Layout<'a>]> =
@ -2498,7 +2519,11 @@ pub fn with_hole<'a>(
}; };
let mut stmt = Stmt::Let(assigned, tag, layout, hole); let mut stmt = Stmt::Let(assigned, tag, layout, hole);
let iter = args.into_iter().rev().zip(field_symbols.iter().rev()); let iter = field_symbols_temp
.drain(..)
.map(|x| x.2 .0)
.rev()
.zip(field_symbols.iter().rev());
stmt = assign_to_symbols(env, procs, layout_cache, iter, stmt); stmt = assign_to_symbols(env, procs, layout_cache, iter, stmt);
@ -5370,6 +5395,20 @@ pub fn from_can_pattern<'a>(
let mut mono_args = Vec::with_capacity_in(arguments.len(), env.arena); let mut mono_args = Vec::with_capacity_in(arguments.len(), env.arena);
// disregard the tag discriminant layout // disregard the tag discriminant layout
let mut arguments = arguments.clone();
arguments.sort_by(|arg1, arg2| {
let ptr_bytes = 8;
let layout1 = layout_cache.from_var(env.arena, arg1.0, env.subs).unwrap();
let layout2 = layout_cache.from_var(env.arena, arg2.0, env.subs).unwrap();
let size1 = layout1.alignment_bytes(ptr_bytes);
let size2 = layout2.alignment_bytes(ptr_bytes);
size2.cmp(&size1)
});
// TODO make this assert pass, it currently does not because // TODO make this assert pass, it currently does not because
// 0-sized values are dropped out // 0-sized values are dropped out
// debug_assert_eq!(arguments.len(), argument_layouts[1..].len()); // debug_assert_eq!(arguments.len(), argument_layouts[1..].len());

View file

@ -1099,6 +1099,15 @@ pub fn union_sorted_tags_help<'a>(
} }
} }
arg_layouts.sort_by(|layout1, layout2| {
let ptr_bytes = 8;
let size1 = layout1.alignment_bytes(ptr_bytes);
let size2 = layout2.alignment_bytes(ptr_bytes);
size2.cmp(&size1)
});
answer.push((tag_name, arg_layouts.into_bump_slice())); answer.push((tag_name, arg_layouts.into_bump_slice()));
} }