Handle case where only other tag of nullable unwrapped needs no refcount

It's possible to have a nullable unwrapped code where the only material
payload does not need refcounting operations. In this case the
refcounting function is the trivial one.
This commit is contained in:
Ayaz Hafiz 2023-02-16 09:36:56 -06:00
parent b5fe932c22
commit 94c2c47da4
No known key found for this signature in database
GPG key ID: 0E2A37416A25EF58
2 changed files with 49 additions and 4 deletions

View file

@ -1345,11 +1345,16 @@ fn build_rec_union_recursive_decrement<'a, 'ctx, 'env>(
union_layout,
UnionLayout::NullableUnwrapped { .. } | UnionLayout::NonNullableUnwrapped { .. }
) {
debug_assert_eq!(cases.len(), 1);
debug_assert!(cases.len() <= 1, "{cases:?}");
// in this case, don't switch, because the `else` branch below would try to read the (nonexistent) tag id
let (_, only_branch) = cases.pop().unwrap();
env.builder.build_unconditional_branch(only_branch);
if cases.is_empty() {
// The only other layout doesn't need refcounting. Pass through.
builder.build_return(None);
} else {
// in this case, don't switch, because the `else` branch below would try to read the (nonexistent) tag id
let (_, only_branch) = cases.pop().unwrap();
env.builder.build_unconditional_branch(only_branch);
}
} else {
let default_block = env.context.append_basic_block(parent, "switch_default");
@ -1372,6 +1377,7 @@ fn build_rec_union_recursive_decrement<'a, 'ctx, 'env>(
}
}
#[derive(Debug)]
struct UnionLayoutTags<'a> {
nullable_id: Option<u16>,
tags: &'a [&'a [InLayout<'a>]],

View file

@ -2196,3 +2196,42 @@ fn nullable_wrapped_with_nullable_not_last_index() {
RocStr
);
}
#[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
fn refcount_nullable_unwrapped_needing_no_refcount_issue_5027() {
assert_evals_to!(
indoc!(
r#"
app "test" provides [main] to "./platform"
Effect : {} -> Str
after = \effect, buildNext ->
\{} ->
when buildNext (effect {}) is
thunk -> thunk {}
line : Effect
line = \{} -> "done"
await : Effect, (Str -> Effect) -> Effect
await = \fx, cont ->
after
fx
cont
succeed : {} -> Effect
succeed = \{} -> (\{} -> "success")
test =
await line \s ->
if s == "done" then succeed {} else test
main = test {}
"#
),
RocStr::from("success"),
RocStr
);
}