diff --git a/CHANGELOG.md b/CHANGELOG.md index 4bd72c79f6d..59b4b9f25bb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/pkg/_js_interop_checks/lib/src/transformations/static_interop_class_eraser.dart b/pkg/_js_interop_checks/lib/src/transformations/static_interop_class_eraser.dart index e6a891a7679..cf5babd9400 100644 --- a/pkg/_js_interop_checks/lib/src/transformations/static_interop_class_eraser.dart +++ b/pkg/_js_interop_checks/lib/src/transformations/static_interop_class_eraser.dart @@ -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'; } diff --git a/pkg/compiler/test/impact/data/jsinterop.dart b/pkg/compiler/test/impact/data/jsinterop.dart index 7a0f3f35757..b862598bddb 100644 --- a/pkg/compiler/test/impact/data/jsinterop.dart +++ b/pkg/compiler/test/impact/data/jsinterop.dart @@ -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, diff --git a/pkg/compiler/test/impact/data/jsinterop_setter1.dart b/pkg/compiler/test/impact/data/jsinterop_setter1.dart index 8c61da59a57..a9f4b62bab9 100644 --- a/pkg/compiler/test/impact/data/jsinterop_setter1.dart +++ b/pkg/compiler/test/impact/data/jsinterop_setter1.dart @@ -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, diff --git a/pkg/compiler/test/impact/data/jsinterop_setter2.dart b/pkg/compiler/test/impact/data/jsinterop_setter2.dart index 742bc0f2a14..4d6831879be 100644 --- a/pkg/compiler/test/impact/data/jsinterop_setter2.dart +++ b/pkg/compiler/test/impact/data/jsinterop_setter2.dart @@ -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, diff --git a/sdk/lib/_internal/js_shared/lib/js_types.dart b/sdk/lib/_internal/js_shared/lib/js_types.dart index 0787748233b..ffd4a60ebaa 100644 --- a/sdk/lib/_internal/js_shared/lib/js_types.dart +++ b/sdk/lib/_internal/js_shared/lib/js_types.dart @@ -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. diff --git a/sdk/lib/_internal/wasm/lib/js_types.dart b/sdk/lib/_internal/wasm/lib/js_types.dart index 1483dab7035..e510ab72d19 100644 --- a/sdk/lib/_internal/wasm/lib/js_types.dart +++ b/sdk/lib/_internal/wasm/lib/js_types.dart @@ -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. diff --git a/sdk/lib/js_interop/js_interop.dart b/sdk/lib/js_interop/js_interop.dart index 36e4d5f844f..9413d88f843 100644 --- a/sdk/lib/js_interop/js_interop.dart +++ b/sdk/lib/js_interop/js_interop.dart @@ -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; diff --git a/tests/lib/js/static_interop_test/js_types_test.dart b/tests/lib/js/static_interop_test/js_types_test.dart index c527246c0ac..cd57492e7d7 100644 --- a/tests/lib/js/static_interop_test/js_types_test.dart +++ b/tests/lib/js/static_interop_test/js_types_test.dart @@ -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.