Skip to content

Interop extension type object literal constructors are not lowered without an @JS annotation on the library #54801

Closed
@srujzs

Description

@srujzs
import 'dart:js_interop';

@JS()
extension type ObjectLiteral._(JSObject _) implements JSObject {
  external ObjectLiteral({String prop});
}

void main() {
  ObjectLiteral();
}

results in:

The compiler crashed: Assertion failure: Unknown external method j:method(ObjectLiteral|constructor#)
#0      failedAt (package:compiler/src/diagnostics/invariant.dart:39:3)
#1      KernelSsaGraphBuilder._buildExternalFunctionNode (package:compiler/src/ssa/builder.dart:1819:5)
#2      KernelSsaGraphBuilder.build.<anonymous closure> (package:compiler/src/ssa/builder.dart:439:15)
#3      DiagnosticReporter.withCurrentElement (package:compiler/src/diagnostics/diagnostic_listener.dart:154:15)
#4      KernelSsaGraphBuilder.build (package:compiler/src/ssa/builder.dart:427:21)
#5      KernelSsaBuilder.build.<anonymous closure> (package:compiler/src/js_model/js_strategy.dart:525:22)
#6      CompilerTask.measure (package:compiler/src/common/tasks.dart:66:51)
#7      KernelSsaBuilder.build (package:compiler/src/js_model/js_strategy.dart:507:18)
#8      SsaBuilderTask.build (package:compiler/src/ssa/ssa.dart:365:21)
#9      SsaFunctionCompiler.compile (package:compiler/src/ssa/ssa.dart:99:28)
#10     OnDemandCodegenResults.getCodegenResults (package:compiler/src/common/codegen.dart:409:30)
#11     JsBackendStrategy.generateCode (package:compiler/src/js_model/js_strategy.dart:331:43)
#12     KernelCodegenWorkItem.run (package:compiler/src/js_model/js_strategy.dart:466:29)
#13     Compiler.emptyQueue.<anonymous closure>.<anonymous closure>.<anonymous closure>.<anonymous closure>.<anonymous closure> (package:compiler/src/compiler.dart:752:70)
#14     CompilerTask.measureSubtask (package:compiler/src/common/tasks.dart:181:35)
#15     Compiler.emptyQueue.<anonymous closure>.<anonymous closure>.<anonymous closure>.<anonymous closure> (package:compiler/src/compiler.dart:752:32)
#16     CompilerTask.measureSubtask (package:compiler/src/common/tasks.dart:181:35)
#17     Compiler.emptyQueue.<anonymous closure>.<anonymous closure>.<anonymous closure> (package:compiler/src/compiler.dart:750:28)
#18     DiagnosticReporter.withCurrentElement (package:compiler/src/diagnostics/diagnostic_listener.dart:154:15)
#19     Compiler.emptyQueue.<anonymous closure>.<anonymous closure> (package:compiler/src/compiler.dart:748:18)
#20     CodegenEnqueuer._forEach (package:compiler/src/js_backend/enqueuer.dart:266:12)
#21     CodegenEnqueuer.forEach (package:compiler/src/js_backend/enqueuer.dart:282:5)
#22     Compiler.emptyQueue.<anonymous closure> (package:compiler/src/compiler.dart:744:16)
#23     CompilerTask.measureSubtask (package:compiler/src/common/tasks.dart:181:35)
#24     Compiler.emptyQueue (package:compiler/src/compiler.dart:743:14)
#25     Compiler.processQueue.<anonymous closure> (package:compiler/src/compiler.dart:767:7)
#26     CompilerTask.measureSubtask (package:compiler/src/common/tasks.dart:181:35)
#27     Compiler.processQueue (package:compiler/src/compiler.dart:761:14)
#28     Compiler.runCodegenEnqueuer (package:compiler/src/compiler.dart:472:5)
#29     Compiler.runSequentialPhases (package:compiler/src/compiler.dart:680:27)
<asynchronous suspension>
#30     Compiler.runInternal.<anonymous closure> (package:compiler/src/compiler.dart:315:7)
<asynchronous suspension>
#31     Compiler.runInternal (package:compiler/src/compiler.dart:314:5)
<asynchronous suspension>
#32     Compiler.run.<anonymous closure> (package:compiler/src/compiler.dart:235:11)
<asynchronous suspension>
#33     compile.<anonymous closure> (package:compiler/compiler_api.dart:256:30)
<asynchronous suspension>
#34     compile.compilationDone (package:compiler/src/dart2js.dart:729:3)
<asynchronous suspension>
#35     batchMain.<anonymous closure>.<anonymous closure> (package:compiler/src/dart2js.dart:1347:13)
<asynchronous suspension>
#36     batchMain.<anonymous closure>.<anonymous closure> (package:compiler/src/dart2js.dart:1355:21)
<asynchronous suspension>

because dart2js doesn't recognize the constructor as a JS interop member.

Adding an @JS annotation onto the library tells dart2js it's meant to be an interop member e.g.

@JS()
library literal;

import 'dart:js_interop';

@JS()
extension type ObjectLiteral._(JSObject _) implements JSObject {
  external ObjectLiteral({String prop});
}

void main() {
  ObjectLiteral();
}

DDC doesn't come across this issue because it assumes all external, extension type members with named parameters are object literal constructors. We can make this same assumption in dart2js as a fix, but long-term, we should have a more robust lowering here. With extension types, we use the representation type to determine if a type is an interop type. However, this information requires indexing all the extension types and their members, which is expensive, so we don't do this in the backends. Ideally, we'd be able to construct the literal in the transformers (where we already do the indexing) before we get to the backend, but this isn't possible today as we don't have a lowering to create an arbitrary object with keys and values in JS.

Metadata

Metadata

Assignees

Labels

area-web-jsIssues related to JavaScript support for Dart Web, including DDC, dart2js, and JS interop.web-dart2jsweb-js-interopIssues that impact all js interop

Type

No type

Projects

Status

Done

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions