Skip to content

[dart2wasm] Null assertion in code generator on using extension type type parameter in success function in a Promise #54192

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
srujzs opened this issue Nov 30, 2023 · 5 comments
Labels
area-dart2wasm Issues for the dart2wasm compiler. web-js-interop Issues that impact all js interop

Comments

@srujzs
Copy link
Contributor

srujzs commented Nov 30, 2023

Dart SDK version: Dart SDK version: 3.3.0-edge.2960e60e24056266f3661bfdb11163a98b3050b1 (main) (Wed Nov 29 13:13:43 2023 -0800) on "macos_x64"
Browser: d8

// SharedOptions=--enable-experiment=inline-class

import 'dart:async';
import 'dart:js_interop';

extension type MyJSPromise<T extends JSAny?>(JSObject s) {
  external void then(JSFunction success, JSFunction error);

  Future<T> get toDart {
    final completer = Completer<T>();
    final success = (T r) {
      completer.complete(r);
    }.toJS;
    final error = (JSAny? e) {}.toJS;
    then(success, error);
    return completer.future;
  }
}

void main() {}

outputs:

stdout:
Exception in TypeLiteral at null

stderr:
Unhandled exception:
Null check operator used on a null value
#0      CodeGenerator.instantiateTypeParameter (package:dart2wasm/code_generator.dart:3052)
#1      Types.makeType (package:dart2wasm/types.dart:572)
#2      CodeGenerator.visitTypeLiteral (package:dart2wasm/code_generator.dart:2985)
#3      TypeLiteral.accept1 (package:kernel/ast.dart:7990)
#4      CodeGenerator.wrap (package:dart2wasm/code_generator.dart:878)
#5      CodeGenerator.makeListFromExpressions.<anonymous closure> (package:dart2wasm/code_generator.dart:2927)
#6      Translator.makeList (package:dart2wasm/translator.dart:1004)
#7      CodeGenerator.makeList (package:dart2wasm/code_generator.dart:2918)
#8      CodeGenerator.makeListFromExpressions (package:dart2wasm/code_generator.dart:2926)
#9      Types._makeTypeList (package:dart2wasm/types.dart:411)
#10     Types._makeFunctionType (package:dart2wasm/types.dart:514)
#11     Types.makeType (package:dart2wasm/types.dart:595)
#12     Types.emitTypeCheck (package:dart2wasm/types.dart:658)
#13     CodeGenerator.visitAsExpression (package:dart2wasm/code_generator.dart:3008)
#14     AsExpression.accept1 (package:kernel/ast.dart:7643)
#15     CodeGenerator.wrap (package:dart2wasm/code_generator.dart:878)
#16     CodeGenerator.visitFunctionInvocation (package:dart2wasm/code_generator.dart:2622)
#17     FunctionInvocation.accept1 (package:kernel/ast.dart:6071)
#18     CodeGenerator.wrap (package:dart2wasm/code_generator.dart:878)
#19     CodeGenerator.visitArgumentsLists (package:dart2wasm/code_generator.dart:2770)
#20     CodeGenerator._visitArguments (package:dart2wasm/code_generator.dart:2804)
#21     CodeGenerator.visitStaticInvocation (package:dart2wasm/code_generator.dart:1755)
#22     StaticInvocation.accept1 (package:kernel/ast.dart:6584)
#23     CodeGenerator.wrap (package:dart2wasm/code_generator.dart:878)
#24     CodeGenerator.visitReturnStatement (package:dart2wasm/code_generator.dart:1523)
#25     ReturnStatement.accept (package:kernel/ast.dart:10163)
#26     CodeGenerator.visitStatement (package:dart2wasm/code_generator.dart:889)
#27     CodeGenerator.visitBlock (package:dart2wasm/code_generator.dart:1011)
#28     Block.accept (package:kernel/ast.dart:9199)
#29     CodeGenerator.visitStatement (package:dart2wasm/code_generator.dart:889)
#30     CodeGenerator.generateBody (package:dart2wasm/code_generator.dart:578)
#31     CodeGenerator.generate (package:dart2wasm/code_generator.dart:234)
#32     Translator.translate (package:dart2wasm/translator.dart:349)
#33     compileToModule (package:dart2wasm/compile.dart:151)
<asynchronous suspension>
#34     main (package:dart2wasm/dart2wasm.dart:144)
<asynchronous suspension>
#35     main (file:///Users/srujzs/dart-sdk/sdk/pkg/dart2wasm/bin/dart2wasm.dart:7)
<asynchronous suspension>

I tried to workaround this by using a Completer<JSAny?> in a few different ways but the cast to T later fails e.g. undefined:0: [object WebAssembly.Exception] or RuntimeError: illegal cast, so I'm guessing that might be a consequence of the codegen not handling this type parameter correctly.

@srujzs srujzs added the area-dart2wasm Issues for the dart2wasm compiler. label Nov 30, 2023
@sigmundch
Copy link
Member

Mmm, it appears this happens because of the .toJS call to convert the closure. This program also produces a similar crash:

import 'dart:js_interop';

void m<T>() {
  final f = (T x) {};
  f.toJS;
}

void main() { }

Note that if we use a static tearoff instead of a closure, we'd get a static error because we don't allow calling .toJS on a function that takes generics:

import 'dart:js_interop';
void m3<T extends JSAny?>(T t) {}
void main() { m3.toJS; }

This produces the error:

example.dart:3:18: Error: Type 'T' is not a valid type for external `dart:js_interop` APIs. The only valid types are: @staticInterop types, JS types from `dart:js_interop`, void, bool, num, double, int, String, and any extension type that erases to one of these types.
Use one of the valid types instead.

@srujzs
Copy link
Contributor Author

srujzs commented Dec 1, 2023

I think you discovered two others bugs in our error checker that needs to be fixed :)

  1. We should be checking local functions for type parameter types. I believe the error checker assumes we don't need to do this because it's checked elsewhere, but that's only for top-level procedures, not locals. Note that the first snippet's T is not bound to anything, so there should be an error.
  2. That second code snippet should be invalid only because it declares type parameters. T is bound to a static interop type whose subtypes' can only be other static interop types, so the usage of that T shouldn't be invalid.

That being said, it does look like .toJS is the culprit there, so I'll need to debug further.

@srujzs
Copy link
Contributor Author

srujzs commented Dec 1, 2023

Oh, I'm silly. I already filed a similar bug on this: #53968.

@osa1
Copy link
Member

osa1 commented Dec 4, 2023

Since this isn't a dart2wasm bug, what would be the right label for it?

@srujzs srujzs added the web-js-interop Issues that impact all js interop label Dec 4, 2023
@srujzs
Copy link
Contributor Author

srujzs commented Dec 4, 2023

Let's label this as a JS interop bug for now (but only affects dart2wasm, so I'll keep that label too).

copybara-service bot pushed a commit that referenced this issue Dec 11, 2023
Addresses some comments in #54192

- With the addition of `nonTypeVariableBound`, we no longer need a
recursive checker.
- We also should account for `StructuralParameterTypes`.
- The current checks did not check type parameters for functions
converted via `toJS`, so that is handled as well.
- Functions that declare type parameters cannot be called in JS
correctly, so an error is added when users try to convert them.
- Some errors are reworded/modified.

Change-Id: Ic05220883ec4ad8653963acd901d339426cba6c6
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/339346
Reviewed-by: Sigmund Cherem <[email protected]>
Commit-Queue: Srujan Gaddam <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-dart2wasm Issues for the dart2wasm compiler. web-js-interop Issues that impact all js interop
Projects
None yet
Development

No branches or pull requests

3 participants