Skip to content

Kernel output contains an overly broad type when lowering an expression that's unnecessarily null-aware due to null shorting #59636

@stereotype441

Description

@stereotype441

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).

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions