mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-27 05:49:08 +00:00
parent
a997280dc9
commit
ca57cce93c
2 changed files with 56 additions and 9 deletions
|
@ -265,6 +265,8 @@ fn get_tags_vars_and_variant<'a>(
|
||||||
(vars_of_tag, union_variant)
|
(vars_of_tag, union_variant)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const FAKE_EXPR: &'static Loc<Expr> = &Loc::at_zero(Expr::Crash);
|
||||||
|
|
||||||
fn expr_of_tag<'a, M: ReplAppMemory>(
|
fn expr_of_tag<'a, M: ReplAppMemory>(
|
||||||
env: &mut Env<'a, '_>,
|
env: &mut Env<'a, '_>,
|
||||||
mem: &'a M,
|
mem: &'a M,
|
||||||
|
@ -279,9 +281,35 @@ fn expr_of_tag<'a, M: ReplAppMemory>(
|
||||||
|
|
||||||
debug_assert_eq!(arg_layouts.len(), arg_vars.len());
|
debug_assert_eq!(arg_layouts.len(), arg_vars.len());
|
||||||
|
|
||||||
// NOTE assumes the data bytes are the first bytes
|
// The type checker stores payloads in definition order, but the memory representation sorts
|
||||||
let it = arg_vars.iter().copied().zip(arg_layouts.iter());
|
// first by size (and tie-breaks by definition order).
|
||||||
let output = sequence_of_expr(env, mem, data_addr, it, when_recursive);
|
let mut layouts: Vec<_> = arg_vars
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.map(|(i, v)| {
|
||||||
|
let layout = env.layout_cache.from_var(env.arena, *v, env.subs).unwrap();
|
||||||
|
(i, *v, layout)
|
||||||
|
})
|
||||||
|
.collect_in(env.arena);
|
||||||
|
|
||||||
|
layouts.sort_by(|(i1, _, lay1), (i2, _, lay2)| {
|
||||||
|
cmp_fields(&env.layout_cache.interner, i1, *lay1, i2, *lay2)
|
||||||
|
});
|
||||||
|
|
||||||
|
let mut output: Vec<&Loc<Expr>> =
|
||||||
|
Vec::from_iter_in(std::iter::repeat(FAKE_EXPR).take(layouts.len()), env.arena);
|
||||||
|
let mut field_addr = data_addr;
|
||||||
|
for (i, var, lay) in layouts {
|
||||||
|
let repr = env.layout_cache.interner.get_repr(lay);
|
||||||
|
let expr = addr_to_ast(env, mem, field_addr, repr, when_recursive, var);
|
||||||
|
let loc_expr = Loc::at_zero(expr);
|
||||||
|
|
||||||
|
output[i] = &*env.arena.alloc(loc_expr);
|
||||||
|
|
||||||
|
// Advance the field pointer to the next field.
|
||||||
|
field_addr += env.layout_cache.interner.stack_size(lay) as usize;
|
||||||
|
}
|
||||||
|
|
||||||
let output = output.into_bump_slice();
|
let output = output.into_bump_slice();
|
||||||
|
|
||||||
Expr::Apply(loc_tag_expr, output, CalledVia::Space)
|
Expr::Apply(loc_tag_expr, output, CalledVia::Space)
|
||||||
|
@ -962,11 +990,14 @@ fn single_tag_union_to_ast<'a, M: ReplAppMemory>(
|
||||||
let loc_tag_expr = &*arena.alloc(Loc::at_zero(tag_expr));
|
let loc_tag_expr = &*arena.alloc(Loc::at_zero(tag_expr));
|
||||||
|
|
||||||
let output = if field_layouts.len() == payload_vars.len() {
|
let output = if field_layouts.len() == payload_vars.len() {
|
||||||
let it = payload_vars.iter().copied().zip(field_layouts);
|
let it = payload_vars
|
||||||
|
.iter()
|
||||||
|
.copied()
|
||||||
|
.zip(field_layouts.iter().copied());
|
||||||
sequence_of_expr(env, mem, addr, it, WhenRecursive::Unreachable).into_bump_slice()
|
sequence_of_expr(env, mem, addr, it, WhenRecursive::Unreachable).into_bump_slice()
|
||||||
} else if field_layouts.is_empty() && !payload_vars.is_empty() {
|
} else if field_layouts.is_empty() && !payload_vars.is_empty() {
|
||||||
// happens for e.g. `Foo Bar` where unit structures are nested and the inner one is dropped
|
// happens for e.g. `Foo Bar` where unit structures are nested and the inner one is dropped
|
||||||
let it = payload_vars.iter().copied().zip([&Layout::UNIT]);
|
let it = payload_vars.iter().copied().zip([Layout::UNIT]);
|
||||||
sequence_of_expr(env, mem, addr, it, WhenRecursive::Unreachable).into_bump_slice()
|
sequence_of_expr(env, mem, addr, it, WhenRecursive::Unreachable).into_bump_slice()
|
||||||
} else {
|
} else {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
|
@ -983,8 +1014,7 @@ fn sequence_of_expr<'a, 'env, I, M: ReplAppMemory>(
|
||||||
when_recursive: WhenRecursive<'a>,
|
when_recursive: WhenRecursive<'a>,
|
||||||
) -> Vec<'a, &'a Loc<Expr<'a>>>
|
) -> Vec<'a, &'a Loc<Expr<'a>>>
|
||||||
where
|
where
|
||||||
I: Iterator<Item = (Variable, &'a InLayout<'a>)>,
|
I: ExactSizeIterator<Item = (Variable, InLayout<'a>)>,
|
||||||
I: ExactSizeIterator<Item = (Variable, &'a InLayout<'a>)>,
|
|
||||||
{
|
{
|
||||||
let arena = env.arena;
|
let arena = env.arena;
|
||||||
let mut output = Vec::with_capacity_in(sequence.len(), arena);
|
let mut output = Vec::with_capacity_in(sequence.len(), arena);
|
||||||
|
@ -997,7 +1027,7 @@ where
|
||||||
env,
|
env,
|
||||||
mem,
|
mem,
|
||||||
field_addr,
|
field_addr,
|
||||||
env.layout_cache.get_repr(*layout),
|
env.layout_cache.get_repr(layout),
|
||||||
when_recursive,
|
when_recursive,
|
||||||
var,
|
var,
|
||||||
);
|
);
|
||||||
|
@ -1006,7 +1036,7 @@ where
|
||||||
output.push(&*arena.alloc(loc_expr));
|
output.push(&*arena.alloc(loc_expr));
|
||||||
|
|
||||||
// Advance the field pointer to the next field.
|
// Advance the field pointer to the next field.
|
||||||
field_addr += env.layout_cache.interner.stack_size(*layout) as usize;
|
field_addr += env.layout_cache.interner.stack_size(layout) as usize;
|
||||||
}
|
}
|
||||||
|
|
||||||
output
|
output
|
||||||
|
|
|
@ -1304,3 +1304,20 @@ fn nested_tuple() {
|
||||||
r#"("a", (2, 3)) : ( Str, ( U32, U32 )a )a"#,
|
r#"("a", (2, 3)) : ( Str, ( U32, U32 )a )a"#,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn ordered_tag_union_memory_layout() {
|
||||||
|
expect_success(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
Loc : { line: U32, column: U32 }
|
||||||
|
|
||||||
|
Node : [ A Loc, Height U8 Loc ]
|
||||||
|
|
||||||
|
x : Node
|
||||||
|
x = Height 1 { line: 2, column: 3 }
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
r#""#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue