Description
Extracted from the test language/exception/throw2_test
:
import "package:expect/expect.dart";
abstract class TestException {
String getMessage();
}
class MyException implements TestException {
const MyException([String message = ""]) : message_ = message;
@override
String getMessage() {
return message_;
}
final String message_;
}
class MyException2 implements TestException {
const MyException2([String message = ""]) : message_ = message;
@override
String getMessage() {
return message_;
}
final String message_;
}
class MyException3 implements TestException {
const MyException3([String message = ""]) : message_ = message;
@override
String getMessage() {
return message_;
}
final String message_;
}
class Helper {
static int f1(int i) {
try {
int j;
j = func();
} on MyException3 catch (exception) {
i = 100;
print(exception.getMessage());
} on MyException2 catch (exception) {
try {
i = func2();
i = 200;
} on TestException catch (exception) {
i = 50;
}
print(exception.getMessage());
} on MyException catch (exception) {
i = func2();
print(exception.getMessage());
} finally {
i = i + 800;
}
return i;
}
static int func() {
int i = 0;
while (i < 10) {
i++;
}
if (i > 0) {
throw new MyException2("Test for exception being thrown");
}
return i;
}
static int func2() {
int i = 0;
while (i < 10) {
i++;
}
if (i > 0) {
throw new MyException2("Test for exception being thrown");
}
return i;
}
}
void main() {
Expect.equals(850, Helper.f1(1));
}
Here MyException3
is never allocated, but TFA doesn't drop the catch
block for it. Relevant parts of the kernel:
[@vm.unboxing-info.metadata=(i)->i] static method f1([@vm.inferred-arg-type.metadata=dart.core::_Smi (value: 1)] core::int i) → core::int {
try
try {
core::int j;
j = test::Helper::func();
}
on test::MyException3 catch(final test::MyException3 exception) {
i = 100;
block {
[@vm.inferred-type.metadata=! (skip check)] exception.{test::MyException3::getMessage}(){() → core::String};
} =>throw "Attempt to execute code removed by Dart AOT compiler (TFA)";
}
As a result the class also can't be dropped, though TFA turns it into an abstract class with the getMessage
also turned into an abstract method:
abstract class MyException3 extends core::Object implements test::TestException /*hasConstConstructor*/ {
[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasNonThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:6,getterSelectorId:7] abstract method getMessage() → core::String;
}
I suspect, the use of MyException3
in on MyException3 catch ...
is treated the same way as e.g. List<MyException3> list = []
, however unlike in the list type, the type on MyException3 ...
does not need a runtime representation of the type MyException3
to exist, if it doesn't already exist it means the on ...
can just be dropped. Similar to x is MyException3
, which should be compiled to false
(instead of making MyException3
available in runtime).