-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Description
Consider the following null-aware expression (taken from pkg/front_end/testcases/nnbd/null_shorting.dart):
n1?.nonNullable1Method()?.nonNullable1Method();Where n1 has type Class1? and Class1.nonNullable1Method has return type Class1. Note that the second ?. is not necessary (because, thanks to null shorting, it only executes when n1 != null); therefore it should, in principle, be possible to optimize it to . during compilation.
The kernel generated for this expression is (line breaks added for clarity):
let final self::Class1? #t80 = n1
in #t80 == null
?{self::Class1?} null
: let final self::Class1? #t81 =
#t80{self::Class1}.{self::Class1::nonNullable1Method}
(){() → self::Class1}
in #t81 == null
?{self::Class1?} null
: #t81{self::Class1}.{self::Class1::nonNullable1Method}
(){() → self::Class1};
Although this has correct runtime semantics, the type of #t81 is unnecessarily broad. It could be self::Class1 instead of self::Class1?, since the initializer expression is the value returned by nonNullable1Method, which has return type Class1.
I suspect that if the type of #t81 were corrected, it would improve the chances of back-ends detecting that the null check #t81 == null is unnecessary (and thus performing the correct optimization).