dart-lang / sdk

The Dart SDK, including the VM, JS and Wasm compilers, analysis, core libraries, and more.
https://dart.dev
BSD 3-Clause "New" or "Revised" License
10.28k stars 1.59k forks source link

Field promotion doesn't support late fields on DDC and dart2wasm #53462

Open stereotype441 opened 1 year ago

stereotype441 commented 1 year ago

The following code is allowed on dart2js and the VM, but fails on DDC and dart2wasm:

class C {
  late final int? _finalWithInitializer = 0;
  late final int? _finalWithoutInitializer;

  C() {
    _finalWithoutInitializer = 0;
  }

  void test() {
    if (_finalWithInitializer != null) {
      print(_finalWithInitializer + 1);
    }
    if (_finalWithoutInitializer != null) {
      print(_finalWithoutInitializer + 1);
    }
  }
}

What's happening is that DDC and dart2wasm lower late final fields to a synthetic getter. The logic in the CFE for deciding whether a property access is promotable needs to understand that a synthetic getter that came from a late final field is still ok to promote.

I'm working on a fix.

biggs0125 commented 3 months ago

An issue was opened in the flutter repo demonstrating this bug still exists in some cases.

I've confirmed locally that I can repro the same behavior. Here's my minimal repro:

typedef Callback = void Function();

class Foo {
  late final Callback? _koCallback;
  final Callback? _okCallback;

  Foo({
    Callback? okCallback,
    Callback? koCallback,
  }) : _okCallback = okCallback {
    _koCallback = koCallback;
  }

  void thisWorks() {
    _okCallback == null ? null : (value) => _okCallback();
  }

  void thisDoesNot() {
    _koCallback == null ? null : (value) => _koCallback();
  }
}

void main() {}

Running $DART_SDK/out/ReleaseX64/dart $DART_SDK/pkg/dev_compiler/tool/ddb --debug -r chrome <file>.dart locally gives me:

org-dartlang-app:/test.dart:19:56: Error: Can't use an expression of type 'void Function()?' as a function because it's potentially null.
Try calling using ?.call instead.
    _koCallback == null ? null : (value) => _koCallback();

Running with the VM or dart2js compiles/executes as expected.

This is also reproducible in dartpad with the above example since it uses DDC.

a-siva commented 1 month ago

The Flutter issue referred above is marked as a P2 so bumping the priority of this issue accordingly.