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.26k stars 1.58k forks source link

Dart2JS crash in assert of extension type const constructor. #56803

Closed lrhn closed 1 month ago

lrhn commented 1 month ago

Given the following code:

const String? maybes = bool.fromEnvironment("not there") ? "string" : null;
extension type const Ext._(String _) implements String {
  const Ext() 
     : assert(maybes != null, "Must not be null"),
       _ = "OK";
}
void main() {
  var c= const Ext();
  print(c);
}

Dart2JS (on Windows 10) crashes with the error message included below.

It does not seem to happen if converting Ext to a class. It does not seem to happen if maybes is a literal null.

Error:

d2jscrash.dart:
Internal Error: The compiler crashed when compiling this element.

The compiler is broken.

When compiling the above element, the compiler crashed. It is not
possible to tell if this is caused by a problem in your program or
not. Regardless, the compiler should not crash.

The Dart team would greatly appreciate if you would take a moment to
report this problem at http://dartbug.com/new.

Please include the following information:

* the name and version of your operating system,

* the Dart SDK build number (3.6.0-277.0.dev), and

* the entire message you see here (including the full stack trace
  below as well as the source location above).

The compiler crashed: Crash when compiling:
Null check operator used on a null value

#0      ConstantEvaluator.checkAssert (package:front_end/src/kernel/constant_evaluator.dart:3392:22)
#1      StatementConstantEvaluator.visitAssertStatement (package:front_end/src/kernel/constant_evaluator.dart:5304:42)
#2      AssertStatement.accept (package:kernel/ast.dart:9342:43)
#3      StatementConstantEvaluator.visitBlock.<anonymous closure> (package:front_end/src/kernel/constant_evaluator.dart:5313:50)
#4      ConstantEvaluator.withNewEnvironment (package:front_end/src/kernel/constant_evaluator.dart:5155:18)
#5      StatementConstantEvaluator.visitBlock (package:front_end/src/kernel/constant_evaluator.dart:5311:26)
#6      Block.accept (package:kernel/ast.dart:9203:43)
#7      ConstantEvaluator.executeBody (package:front_end/src/kernel/constant_evaluator.dart:2519:40)
#8      ConstantEvaluator._handleFunctionInvocation.executeFunction (package:front_end/src/kernel/constant_evaluator.dart:4592:31)
#9      ConstantEvaluator.withNewEnvironment (package:front_end/src/kernel/constant_evaluator.dart:5155:18)
#10     ConstantEvaluator._handleFunctionInvocation (package:front_end/src/kernel/constant_evaluator.dart:4609:12)
#11     ConstantEvaluator.visitStaticInvocation (package:front_end/src/kernel/constant_evaluator.dart:4543:27)
#12     StaticInvocation.accept (package:kernel/ast.dart:6604:44)
#13     ConstantEvaluator._evaluateSubexpression (package:front_end/src/kernel/constant_evaluator.dart:2704:41)
#14     ConstantEvaluator._evaluate (package:front_end/src/kernel/constant_evaluator.dart:2437:23)
#15     ConstantEvaluator.evaluate (package:front_end/src/kernel/constant_evaluator.dart:2429:23)
#16     ConstantsTransformer.evaluateWithContext (package:front_end/src/kernel/constant_evaluator.dart:2184:32)
#17     ConstantsTransformer.evaluateAndTransformWithContext (package:front_end/src/kernel/constant_evaluator.dart:2179:35)
#18     ConstantsTransformer.visitStaticInvocation (package:front_end/src/kernel/constant_evaluator.dart:2149:14)
#19     StaticInvocation.accept1 (package:kernel/ast.dart:6608:9)
#20     RemovingTransformer.transform (package:kernel/visitor.dart:1881:17)
#21     ConstantsTransformer.visitVariableDeclaration (package:front_end/src/kernel/constant_evaluator.dart:443:28)
#22     VariableDeclaration.accept1 (package:kernel/ast.dart:10779:9)
#23     RemovingTransformer.transformOrRemove (package:kernel/visitor.dart:1917:21)
#24     ConstantsTransformer.visitBlock (package:front_end/src/kernel/constant_evaluator.dart:587:27)
#25     Block.accept1 (package:kernel/ast.dart:9206:58)
#26     RemovingTransformer.transform (package:kernel/visitor.dart:1881:17)
#27     ConstantsTransformer.visitFunctionNode (package:front_end/src/kernel/constant_evaluator.dart:402:19)
#28     FunctionNode.accept1 (package:kernel/ast.dart:3898:9)
#29     RemovingTransformer.transform (package:kernel/visitor.dart:1881:17)
#30     ConstantsTransformer.visitProcedure.<anonymous closure> (package:front_end/src/kernel/constant_evaluator.dart:308:23)
#31     ConstantEvaluator.withNewEnvironment (package:front_end/src/kernel/constant_evaluator.dart:5155:18)
#32     ConstantsTransformer.visitProcedure (package:front_end/src/kernel/constant_evaluator.dart:306:23)
#33     Procedure.accept1 (package:kernel/ast.dart:3253:55)
#34     RemovingTransformer.transformOrRemove (package:kernel/visitor.dart:1917:21)
#35     RemovingTransformer.transformList (package:kernel/visitor.dart:2141:19)
#36     RemovingTransformer.transformProcedureList (package:kernel/visitor.dart:2033:5)
#37     ConstantsTransformer.convertLibrary (package:front_end/src/kernel/constant_evaluator.dart:209:5)
#38     transformLibraries (package:front_end/src/kernel/constant_evaluator.dart:82:26)
#39     KernelTarget.runBuildTransformations (package:front_end/src/kernel/kernel_target.dart:1692:19)
#40     KernelTarget.buildComponent.<anonymous closure> (package:front_end/src/kernel/kernel_target.dart:795:7)
<asynchronous suspension>
#41     withCrashReporting (package:front_end/src/base/crash.dart:138:12)
<asynchronous suspension>
#42     KernelTarget.buildComponent (package:front_end/src/kernel/kernel_target.dart:724:12)
<asynchronous suspension>
#43     _buildInternal (package:front_end/src/kernel_generator_impl.dart:241:19)
<asynchronous suspension>
#44     withCrashReporting (package:front_end/src/base/crash.dart:138:12)
<asynchronous suspension>
#45     compile.<anonymous closure> (package:front_end/src/api_unstable/dart2js.dart:166:37)
<asynchronous suspension>
#46     CompilerContext.clear (package:front_end/src/base/compiler_context.dart:79:3)
<asynchronous suspension>
#47     compile (package:front_end/src/api_unstable/dart2js.dart:164:36)
<asynchronous suspension>
#48     _loadFromSource (package:compiler/src/phase/load_kernel.dart:317:29)
<asynchronous suspension>
#49     run (package:compiler/src/phase/load_kernel.dart:411:36)
<asynchronous suspension>
#50     Compiler.loadKernel (package:compiler/src/compiler.dart:392:9)
<asynchronous suspension>
#51     Compiler.produceKernel (package:compiler/src/compiler.dart:399:36)
<asynchronous suspension>
#52     Compiler.runSequentialPhases (package:compiler/src/compiler.dart:633:20)
<asynchronous suspension>
#53     Compiler.runInternal.<anonymous closure> (package:compiler/src/compiler.dart:316:7)
<asynchronous suspension>
#54     Compiler.runInternal (package:compiler/src/compiler.dart:315:5)
<asynchronous suspension>
#55     Compiler.run.<anonymous closure> (package:compiler/src/compiler.dart:236:11)
<asynchronous suspension>
#56     compile.<anonymous closure> (package:compiler/compiler_api.dart:256:30)
<asynchronous suspension>
#57     compile.compilationDone (package:compiler/src/dart2js.dart:723:3)
<asynchronous suspension>
#58     main (package:compiler/src/dart2js.dart:1226:3)
<asynchronous suspension>
rakudrama commented 1 month ago

The VM emits a diagnostic

../../play1/56803.dart:8:16: Error: Constant evaluation error:
  var c= const Ext();
               ^
../../play1/56803.dart:4:22: Context: This assertion failed with message: Must not be null
     : assert(maybes != null, "Must not be null"),
                     ^

For dart2js, it seems like the evaluation of the constant is being deferred, possibly because dart2js (IIRC) resolves const bool.fromEnvironment later if it is not defined.

  AbortConstant? checkAssert(AssertStatement statement) {
    if (!enableAsserts) return null;
    final Constant condition = _evaluateSubexpression(statement.condition);
    if (condition is AbortConstant) return condition;

    if (shouldBeUnevaluated) {
      // Coverage-ignore-block(suite): Not run.
      Expression? message = null;
      if (statement.message != null) {
        enterLazy();
        Constant constant = _evaluateSubexpression(statement.message!);
        if (constant is AbortConstant) return constant;
        message = _wrap(constant);
        leaveLazy();
      }
      //             v  this is the crash
      instanceBuilder!.asserts.add(new AssertStatement(_wrap(condition),
          message: message,
          conditionStartOffset: statement.conditionStartOffset,
          conditionEndOffset: statement.conditionEndOffset));
    } else if (condition is BoolConstant) {
      // VM takes this path?

/cc @johnniwinther, @fishythefish

I'm not sure why we don't have an instanceBuilder. There seems to be an assumption that a constant-folded assert must be in the initializers of a regular constructor.

Has the extension type constructor been lowered to a static method?

johnniwinther commented 1 month ago

The extension type constructor has been lowered and checkAssert hasn't been updated accordingly. I'll look into it.