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.09k stars 1.56k forks source link

Pattern matching inside collection literal can cause crash in release builds #56756

Open Yegair opened 5 hours ago

Yegair commented 5 hours ago

When using an if(someValue case final Type typedValue) guard within collection literals, there can be runtime errors that I think are caused by an incorrect compilation. They only happen in release builds (dart compile exe) and don't happen in development builds (dart run).

I encountered this issue with Dart 3.5.3, but I did not test if it is present in other Dart versions also.

Reproduction

import 'dart:math';

class RandomValue {
  final bool shouldReturnValue;

  const RandomValue(this.shouldReturnValue);

  String? get valueOrNull {
    return shouldReturnValue ? "${Random().nextInt(42)}" : null;
  }
}

void main() {
  final values = [
    RandomValue(true),
    RandomValue(true),
    RandomValue(false),
    RandomValue(true),
  ];

  final nonNullValues = [
    for (final value in values)
      if (value.valueOrNull case final String aString) aString,
  ];

  print(nonNullValues);
}

When running the code above with dart run, it will correctly print out 3 random values, such as [10, 32, 29].

However, when compiling it to an executable and then running it, it will throw an error like

Unhandled exception:
type 'Null' is not a subtype of type 'String' in type cast
#0 ...

And the stack-trace pointing to the line with the statement

  print(nonNullValues);

I assume the line

      if (value.valueOrNull case final String aString) aString,

somehow gets erased by the compiler, which then causes the null value to end up in the nonNullValues list.

Also some observations I have made:

dart-github-bot commented 5 hours ago

Summary: The issue occurs when using pattern matching inside a collection literal with a nullable type. In release builds, the pattern matching guard appears to be removed during compilation, leading to null values being included in the collection, resulting in a runtime error when accessing those values. This issue is specific to release builds and does not occur in development builds.