//> using options -Xasync
import OptionAwait._
object Test {
def main(args: Array[String]): Unit = {
assert(Some(22) == iSw(11))
}
private def iSw(i: Int) = optionally {
i match {
case 11 if value(Some(430)) > 42 => 22
case p => p
}
}
}
The ASTs are, before async:
(x1: Int) match {
case 11 => if (unbox(OptionAwait.value(new Some(scala.Int.box(430)))).>(42))
scala.Int.box(22)
else
scala.Int.box(default3())
case _ => default3(){
scala.Int.box(x1)
}
Erasure adds scala.Int.box(default3()) around the label jump, which is wrong / dead code, but wihtout async it's just skipped when emitting bytecode, so it works.
After async:
override def apply(tr$async: Option): Unit = while$(){
try {
stateMachine$async.this.state() match {
case 0 => {
case <synthetic> val x1: Int = i;
stateMachine$async.this.match$1 = null;
(x1: Int) match {
case 11 => {
val awaitable$async: Some = new Some(scala.Int.box(430));
tr$async = stateMachine$async.this.getCompleted(awaitable$async);
stateMachine$async.this.state_=(1);
if (null.!=(tr$async))
while$()
else
{
stateMachine$async.this.onComplete(awaitable$async);
return ()
}
}
case _ => {
stateMachine$async.this.match$1 = default3(){
scala.Int.box(x1)
}
}
};
stateMachine$async.this.state_=(2);
while$()
}
case 1 => {
<synthetic> val await$1: Object = {
val tryGetResult$async: Object = stateMachine$async.this.tryGet(tr$async);
if (stateMachine$async.this.eq(tryGetResult$async))
return ()
else
tryGetResult$async.$asInstanceOf[Object]()
};
if (unbox(await$1).>(42))
stateMachine$async.this.match$1 = scala.Int.box(22)
else
stateMachine$async.this.match$1 = scala.Int.box(default3());
stateMachine$async.this.state_=(2);
while$()
}
case 2 => {
stateMachine$async.this.completeSuccess(stateMachine$async.this.match$1);
return ()
}
case _ => throw new IllegalStateException(java.lang.String.valueOf(stateMachine$async.this.state()))
}
} catch {
case (throwable$async @ (_: Throwable)) => {
stateMachine$async.this.completeFailure(throwable$async);
return ()
}
};
while$()
}
The the jump to default3() is now wrong, we don't want to jump from case 1 into case 0 of the state machine.
Also match$1 = default3(){ scala.Int.box(x1) } is strange; but that's the label def, doesn't change emitted code.
But mainly stateMachine$async.this.match$1 = scala.Int.box(default3()); is not right, default3() is a jump, not a call that returns a result that can be assigned to match$1.
Running the example gives
Exception in thread "main" java.lang.VerifyError: Bad local variable type
Exception Details:
Location:
Test$stateMachine$async$1.apply(Lscala/Option;)V @99: iload_2
Reason:
Type top (current frame, locals[2]) is not assignable to integer
The ASTs are, before async:
The label is added in
SwitchMaker.collapseGuardedCases
to translate switches with guards.Erasure adds
scala.Int.box(default3())
around the label jump, which is wrong / dead code, but wihtout async it's just skipped when emitting bytecode, so it works.After async:
The the jump to
default3()
is now wrong, we don't want to jump fromcase 1
intocase 0
of the state machine.Also
match$1 = default3(){ scala.Int.box(x1) }
is strange; but that's the label def, doesn't change emitted code.But mainly
stateMachine$async.this.match$1 = scala.Int.box(default3());
is not right,default3()
is a jump, not a call that returns a result that can be assigned tomatch$1
.Running the example gives