-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Description
π Feature
Branches can occur in on-chain code, but it's difficult to make use of them.
Consider this Leo code in an async function
involving a mapping m
.
let x = 0field;
if cond {
x = m.get(0u32);
} else {
x = m.get(1u32);
}
We could try to compile this to .aleo
code using branches like this:
branch.eq r0 false to end_then_0_0;
get m[0u32] into r1;
branch.eq true true to end_otherwise_0_1;
position end_then_0_0;
get m[1u32] into r2;
position end_otherwise_0_1;
ternary r0 r1 r2 into r3;
But this doesn't work as no matter which branch we took, one of r1
and r2
will be uninitialized.
We could compile it to a ternary conditional without branching (which is what we'd do for a transition):
get m[0u32] into r1;
get m[1u32] into r2;
ternary r0 r1 r2 into r3;
But this means both get m[0u32]
and get m[1u32]
will run, defeating the point of having branches for onchain code and surprising the user who doesn't expect both branches will run.
It would be nice to have one of these:
-
allow uninitialized registers to be used, at least as long as their contents aren't examined and at least for some operations like
ternary
; or -
make some kind of fancy new ternary conditional (or maybe an operator like the phi instruction from many compiler intermediate representations) to allow us to unify values from different branches without running both branches; or
-
implement the flagged operations from this ARC. This wouldn't allow us to actually avoid either instruction, but it would at least allow us to execute them without halting.