[dart:js_interop] Add JS types for Symbol/BigInt

Adds JSSymbol and JSBigInt and erases to either their respective
interceptor types in the JS backends or JSValue in dart2wasm.

CoreLibraryReviewExempt: Backend-specific library.
Change-Id: Ib2c70d22a70c6308733cd170b91eafa8ec3b3aeb
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/321749
Reviewed-by: Sigmund Cherem <sigmund@google.com>
This commit is contained in:
Srujan Gaddam 2023-08-21 21:54:15 +00:00 committed by Commit Queue
parent c738fe1d7b
commit a38fb595cf
9 changed files with 76 additions and 2 deletions

View file

@ -90,7 +90,9 @@
interceptor and should not be used with `package:js` classes. These types were
being intercepted with the assumption that they are a subtype of JavaScript's
`Object`, but this is incorrect. This lead to erroneous behavior when using
these types as Dart `Object`s. See [#53106][] for more details.
these types as Dart `Object`s. See [#53106][] for more details. Use
`dart:js_interop`'s `JSSymbol` and `JSBigInt` with extension types to interop
with these types.
#### Dart2js
@ -99,7 +101,9 @@
interceptor and should not be used with `package:js` classes. These types were
being intercepted with the assumption that they are a subtype of JavaScript's
`Object`, but this is incorrect. This lead to erroneous behavior when using
these types as Dart `Object`s. See [#53106][] for more details.
these types as Dart `Object`s. See [#53106][] for more details. Use
`dart:js_interop`'s `JSSymbol` and `JSBigInt` with extension types to interop
with these types.
[#53106]: https://github.com/dart-lang/sdk/issues/53106

View file

@ -101,6 +101,14 @@ InterfaceType eraseStaticInteropTypesForJSCompilers(
erasedClass =
coreTypes.index.getClass('dart:_interceptors', 'JSObject');
break;
case 'JSSymbol':
erasedClass =
coreTypes.index.getClass('dart:_interceptors', 'JavaScriptSymbol');
break;
case 'JSBigInt':
erasedClass =
coreTypes.index.getClass('dart:_interceptors', 'JavaScriptBigInt');
break;
default:
throw 'Unimplemented `dart:_js_types`: $className';
}

View file

@ -35,6 +35,7 @@ class JsInteropClass {
native:JSAny,
native:JSArray,
native:JSArrayBuffer,
native:JSBigInt,
native:JSBoolean,
native:JSBoxedDartObject,
native:JSDataView,
@ -49,6 +50,7 @@ class JsInteropClass {
native:JSObject,
native:JSPromise,
native:JSString,
native:JSSymbol,
native:JSTypedArray,
native:JSUint16Array,
native:JSUint32Array,

View file

@ -58,6 +58,7 @@ import 'package:js/js.dart';
native:JSAny,
native:JSArray,
native:JSArrayBuffer,
native:JSBigInt,
native:JSBoolean,
native:JSBoxedDartObject,
native:JSDataView,
@ -72,6 +73,7 @@ import 'package:js/js.dart';
native:JSObject,
native:JSPromise,
native:JSString,
native:JSSymbol,
native:JSTypedArray,
native:JSUint16Array,
native:JSUint32Array,

View file

@ -65,6 +65,7 @@ import 'package:js/js.dart';
native:JSAny,
native:JSArray,
native:JSArrayBuffer,
native:JSBigInt,
native:JSBoolean,
native:JSBoxedDartObject,
native:JSDataView,
@ -79,6 +80,7 @@ import 'package:js/js.dart';
native:JSObject,
native:JSPromise,
native:JSString,
native:JSSymbol,
native:JSTypedArray,
native:JSUint16Array,
native:JSUint32Array,

View file

@ -51,6 +51,7 @@ class JSExportedDartFunction implements JSFunction {}
@staticInterop
class JSArray implements JSObject {
external factory JSArray();
// TODO(srujzs): Should we make this an `int`?
external factory JSArray.withLength(JSNumber length);
}
@ -118,6 +119,14 @@ class JSBoolean implements JSAny {}
@staticInterop
class JSString implements JSAny {}
@JS()
@staticInterop
class JSSymbol implements JSAny {}
@JS()
@staticInterop
class JSBigInt implements JSAny {}
/// [JSVoid] is just a typedef for [void]. While we could just use
/// `JSUndefined`, in the future we may be able to use this to elide `return`s
/// in JS trampolines.

View file

@ -99,6 +99,7 @@ class JSPromise implements JSObject {}
@staticInterop
class JSArray implements JSObject {
external factory JSArray();
// TODO(srujzs): Should we make this an `int`?
external factory JSArray.withLength(JSNumber length);
}
@ -166,6 +167,14 @@ class JSBoolean implements JSAny {}
@staticInterop
class JSString implements JSAny {}
@JS()
@staticInterop
class JSSymbol implements JSAny {}
@JS()
@staticInterop
class JSBigInt implements JSAny {}
/// [JSVoid] is just a typedef for [void]. While we could just use
/// `JSUndefined`, in the future we may be able to use this to elide `return`s
/// in JS trampolines.

View file

@ -136,6 +136,12 @@ typedef JSBoolean = js_types.JSBoolean;
/// The type of JS strings, [JSString] <: [JSAny].
typedef JSString = js_types.JSString;
/// The type of JS Symbols, [JSSymbol] <: [JSAny].
typedef JSSymbol = js_types.JSSymbol;
/// The type of JS BigInts, [JSBigInt] <: [JSAny].
typedef JSBigInt = js_types.JSBigInt;
/// A getter to retrieve the global context that is used in static interop
/// lowering.
external JSObject get globalContext;

View file

@ -88,6 +88,28 @@ external JSBoolean boo;
@JS()
external JSString str;
@JS()
external JSSymbol symbol;
@JS('Symbol')
external JSSymbol createSymbol(String value);
extension on JSSymbol {
@JS('toString')
external String toStringExternal();
}
@JS()
external JSBigInt bigInt;
@JS('BigInt')
external JSBigInt createBigInt(String value);
extension on JSBigInt {
@JS('toString')
external String toStringExternal();
}
@JS()
external JSAny? nullAny;
@ -240,6 +262,16 @@ void syncTests() {
String dartStr = str.toDart;
expect(dartStr, 'foo');
// [JSSymbol]
symbol = createSymbol('foo');
expect(symbol is JSSymbol, true);
expect(symbol.toStringExternal(), 'Symbol(foo)');
// [JSBigInt]
bigInt = createBigInt('9876543210000000000000123456789');
expect(bigInt is JSBigInt, true);
expect(bigInt.toStringExternal(), '9876543210000000000000123456789');
// null and undefined can flow into `JSAny?`.
// TODO(joshualitt): Fix tests when `JSNull` and `JSUndefined` are no longer
// conflated.