Skip to content

Commit

Permalink
[dart:js_interop] Make ExternalDartReference generic
Browse files Browse the repository at this point in the history
Closes #55342
Closes #55536
Closes #56015

- Adds a type parameter T that extends Object? to
ExternalDartReference to capture the type of the value
that was externalized.
-- In the JS compilers, the representation type of
ExternalDartReference is now T.
-- In dart2wasm, the representation type is now JSValue?.
- ExternalDartReference no longer implements Object.
- Return type of toDartObject is now T.
- ObjectToExternalDartReference and
ExternalDartReferenceToObject both now are on a T that is
bound to Object?.
- Internal patches for WeakReference and Finalizer are
updated.

Change-Id: Ic2dc834b17ec6a4eb2122cba3c495a6e0a1eae6e
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/370663
Commit-Queue: Srujan Gaddam <srujzs@google.com>
Reviewed-by: Martin Kustermann <kustermann@google.com>
Reviewed-by: Sigmund Cherem <sigmund@google.com>
Reviewed-by: Lasse Nielsen <lrn@google.com>
  • Loading branch information
srujzs authored and Commit Queue committed Jun 26, 2024
1 parent 2653075 commit b8402f5
Show file tree
Hide file tree
Showing 11 changed files with 303 additions and 137 deletions.
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,18 @@
of a `String` to support other JS values as well, like `TrustedScriptURL`s.
- **Breaking Change** [#55267][]: `isTruthy` and `not` now return `JSBoolean`
instead of `bool` to be consistent with the other operators.
- **Breaking Change** `ExternalDartReference` no longer implements `Object`.
`ExternalDartReference` now accepts a type parameter `T` with a bound of
`Object?` to capture the type of the Dart object that is externalized.
`ExternalDartReferenceToObject.toDartObject` now returns a `T`.
`ExternalDartReferenceToObject` and `ObjectToExternalDartReference` are now
extensions on `T` and `ExternalDartReference<T>`, respectively, where `T
extends Object?`. See [#55342][] and [#55536][] for more details.

[#55508]: https://github.com/dart-lang/sdk/issues/55508
[#55267]: https://github.com/dart-lang/sdk/issues/55267
[#55342]: https://github.com/dart-lang/sdk/issues/55342
[#55536]: https://github.com/dart-lang/sdk/issues/55536

### Tools

Expand Down
2 changes: 1 addition & 1 deletion pkg/dart2wasm/lib/js/callback_specializer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ class CallbackSpecializer {
VariableGet v = VariableGet(positionalParameters[i]);
if (_util.isJSValueType(callbackParameterType) && boxExternRef) {
expression = _createJSValue(v);
if (!callbackParameterType.isPotentiallyNullable) {
if (!callbackParameterType.extensionTypeErasure.isPotentiallyNullable) {
expression = NullCheck(expression);
}
} else {
Expand Down
4 changes: 2 additions & 2 deletions pkg/dart2wasm/lib/js/util.dart
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ class CoreTypesUtil {
Procedure jsifyTarget(DartType type) =>
isJSValueType(type) ? jsValueUnboxTarget : jsifyRawTarget;

/// Return whether [type] erases to a `JSValue`.
/// Whether [type] erases to a `JSValue` or `JSValue?`.
bool isJSValueType(DartType type) =>
_extensionIndex.isStaticInteropType(type) ||
_extensionIndex.isExternalDartReferenceType(type);
Expand Down Expand Up @@ -112,7 +112,7 @@ class CoreTypesUtil {
// there are static interop types that are not boxed as JSValue, we
// might need a proper cast then.
expression = invokeOneArg(jsValueBoxTarget, invocation);
if (returnType.isPotentiallyNonNullable) {
if (returnType.extensionTypeErasure.isPotentiallyNonNullable) {
expression = NullCheck(expression);
}
} else {
Expand Down
84 changes: 52 additions & 32 deletions sdk/lib/_internal/js_shared/lib/js_interop_patch.dart
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ JSObjectRepType _createObjectLiteral() =>
@pragma('dart2js:prefer-inline')
JSObject get globalContext => staticInteropGlobalContext as JSObject;

/// Helper for working with the [JSAny?] top type in a backend agnostic way.
// Helper for working with the JSAny? top type in a backend agnostic way.
@patch
extension NullableUndefineableJSAnyExtension on JSAny? {
@patch
Expand Down Expand Up @@ -53,15 +53,16 @@ extension JSAnyUtilityExtension on JSAny? {
Object? dartify() => js_util.dartify(this);
}

/// Utility extensions for [Object?].
// Utility extensions for Object?.
@patch
extension NullableObjectUtilExtension on Object? {
@patch
@pragma('dart2js:prefer-inline')
JSAny? jsify() => js_util.jsify(this);
}

/// [JSExportedDartFunction] <-> [Function]
// -----------------------------------------------------------------------------
// JSExportedDartFunction <-> Function
@patch
extension JSExportedDartFunctionToFunction on JSExportedDartFunction {
// TODO(srujzs): We should unwrap rather than allow arbitrary JS functions
Expand All @@ -79,15 +80,16 @@ extension FunctionToJSExportedDartFunction on Function {
js_util.allowInterop(this) as JSExportedDartFunction;
}

/// Embedded global property for wrapped Dart objects passed via JS interop.
///
/// This is a Symbol so that different Dart applications don't share Dart
/// objects from different Dart runtimes. We expect all [JSBoxedDartObject]s to
/// have this Symbol.
// Embedded global property for wrapped Dart objects passed via JS interop.
//
// This is a Symbol so that different Dart applications don't share Dart
// objects from different Dart runtimes. We expect all JSBoxedDartObjects to
// have this Symbol.
final Object _jsBoxedDartObjectProperty =
foreign_helper.JS('', 'Symbol("jsBoxedDartObjectProperty")');

/// [JSBoxedDartObject] <-> [Object]
// -----------------------------------------------------------------------------
// JSBoxedDartObject <-> Object
@patch
extension JSBoxedDartObjectToObject on JSBoxedDartObject {
@patch
Expand Down Expand Up @@ -118,31 +120,34 @@ extension ObjectToJSBoxedDartObject on Object {
}
}

/// [ExternalDartReference] <-> [Object]
// -----------------------------------------------------------------------------
// ExternalDartReference <-> T
@patch
extension ExternalDartReferenceToObject on ExternalDartReference {
extension ExternalDartReferenceToObject<T extends Object?>
on ExternalDartReference<T> {
@patch
@pragma('dart2js:prefer-inline')
Object get toDartObject => this;
T get toDartObject => _externalDartReference;
}

@patch
extension ObjectToExternalDartReference on Object {
extension ObjectToExternalDartReference<T extends Object?> on T {
@patch
@pragma('dart2js:prefer-inline')
ExternalDartReference get toExternalReference =>
ExternalDartReference._(this);
ExternalDartReference<T> get toExternalReference =>
ExternalDartReference<T>._(this);
}

/// [JSPromise] -> [Future].
// JSPromise -> Future
@patch
extension JSPromiseToFuture<T extends JSAny?> on JSPromise<T> {
@patch
@pragma('dart2js:prefer-inline')
Future<T> get toDart => js_util.promiseToFuture<T>(this);
}

/// [JSArrayBuffer] <-> [ByteBuffer]
// -----------------------------------------------------------------------------
// JSArrayBuffer <-> ByteBuffer
@patch
extension JSArrayBufferToByteBuffer on JSArrayBuffer {
@patch
Expand All @@ -157,7 +162,8 @@ extension ByteBufferToJSArrayBuffer on ByteBuffer {
JSArrayBuffer get toJS => this as JSArrayBuffer;
}

/// [JSDataView] <-> [ByteData]
// -----------------------------------------------------------------------------
// JSDataView <-> ByteData
@patch
extension JSDataViewToByteData on JSDataView {
@patch
Expand All @@ -172,7 +178,8 @@ extension ByteDataToJSDataView on ByteData {
JSDataView get toJS => this as JSDataView;
}

/// [JSInt8Array] <-> [Int8List]
// -----------------------------------------------------------------------------
// JSInt8Array <-> Int8List
@patch
extension JSInt8ArrayToInt8List on JSInt8Array {
@patch
Expand All @@ -187,7 +194,8 @@ extension Int8ListToJSInt8Array on Int8List {
JSInt8Array get toJS => this as JSInt8Array;
}

/// [JSUint8Array] <-> [Uint8List]
// -----------------------------------------------------------------------------
// JSUint8Array <-> Uint8List
@patch
extension JSUint8ArrayToUint8List on JSUint8Array {
@patch
Expand All @@ -202,7 +210,8 @@ extension Uint8ListToJSUint8Array on Uint8List {
JSUint8Array get toJS => this as JSUint8Array;
}

/// [JSUint8ClampedArray] <-> [Uint8ClampedList]
// -----------------------------------------------------------------------------
// JSUint8ClampedArray <-> Uint8ClampedList
@patch
extension JSUint8ClampedArrayToUint8ClampedList on JSUint8ClampedArray {
@patch
Expand All @@ -217,7 +226,8 @@ extension Uint8ClampedListToJSUint8ClampedArray on Uint8ClampedList {
JSUint8ClampedArray get toJS => this as JSUint8ClampedArray;
}

/// [JSInt16Array] <-> [Int16List]
// -----------------------------------------------------------------------------
// JSInt16Array <-> Int16List
@patch
extension JSInt16ArrayToInt16List on JSInt16Array {
@patch
Expand All @@ -232,7 +242,8 @@ extension Int16ListToJSInt16Array on Int16List {
JSInt16Array get toJS => this as JSInt16Array;
}

/// [JSUint16Array] <-> [Uint16List]
// -----------------------------------------------------------------------------
// JSUint16Array <-> Uint16List
@patch
extension JSUint16ArrayToInt16List on JSUint16Array {
@patch
Expand All @@ -247,7 +258,8 @@ extension Uint16ListToJSInt16Array on Uint16List {
JSUint16Array get toJS => this as JSUint16Array;
}

/// [JSInt32Array] <-> [Int32List]
// -----------------------------------------------------------------------------
// JSInt32Array <-> Int32List
@patch
extension JSInt32ArrayToInt32List on JSInt32Array {
@patch
Expand All @@ -262,7 +274,8 @@ extension Int32ListToJSInt32Array on Int32List {
JSInt32Array get toJS => this as JSInt32Array;
}

/// [JSUint32Array] <-> [Uint32List]
// -----------------------------------------------------------------------------
// JSUint32Array <-> Uint32List
@patch
extension JSUint32ArrayToUint32List on JSUint32Array {
@patch
Expand All @@ -277,7 +290,8 @@ extension Uint32ListToJSUint32Array on Uint32List {
JSUint32Array get toJS => this as JSUint32Array;
}

/// [JSFloat32Array] <-> [Float32List]
// -----------------------------------------------------------------------------
// JSFloat32Array <-> Float32List
@patch
extension JSFloat32ArrayToFloat32List on JSFloat32Array {
@patch
Expand All @@ -292,7 +306,8 @@ extension Float32ListToJSFloat32Array on Float32List {
JSFloat32Array get toJS => this as JSFloat32Array;
}

/// [JSFloat64Array] <-> [Float64List]
// -----------------------------------------------------------------------------
// JSFloat64Array <-> Float64List
@patch
extension JSFloat64ArrayToFloat64List on JSFloat64Array {
@patch
Expand All @@ -307,7 +322,8 @@ extension Float64ListToJSFloat64Array on Float64List {
JSFloat64Array get toJS => this as JSFloat64Array;
}

/// [JSArray] <-> [List]
// -----------------------------------------------------------------------------
// JSArray <-> List
@patch
extension JSArrayToList<T extends JSAny?> on JSArray<T> {
@patch
Expand Down Expand Up @@ -339,7 +355,8 @@ extension ListToJSArray<T extends JSAny?> on List<T> {
JSArray<T> get toJSProxyOrRef => this as JSArray<T>;
}

/// [JSNumber] -> [double] or [int].
// -----------------------------------------------------------------------------
// JSNumber -> double or int
@patch
extension JSNumberToNumber on JSNumber {
@patch
Expand All @@ -351,15 +368,17 @@ extension JSNumberToNumber on JSNumber {
int get toDartInt => this as int;
}

/// [double] -> [JSNumber].
// -----------------------------------------------------------------------------
// double -> JSNumber
@patch
extension DoubleToJSNumber on double {
@patch
@pragma('dart2js:prefer-inline')
JSNumber get toJS => JSNumber._(this);
}

/// [JSBoolean] <-> [bool]
// -----------------------------------------------------------------------------
// JSBoolean <-> bool
@patch
extension JSBooleanToBool on JSBoolean {
@patch
Expand All @@ -374,7 +393,8 @@ extension BoolToJSBoolean on bool {
JSBoolean get toJS => JSBoolean._(this);
}

/// [JSString] <-> [String]
// -----------------------------------------------------------------------------
// JSString <-> String
@patch
extension JSStringToString on JSString {
@patch
Expand Down
2 changes: 1 addition & 1 deletion sdk/lib/_internal/js_shared/lib/js_types.dart
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ typedef JSBigIntRepType = interceptors.JavaScriptBigInt;

// While this type is not a JS type, it is here for convenience so we don't need
// to create a new shared library.
typedef ExternalDartReferenceRepType = Object;
typedef ExternalDartReferenceRepType<T> = T;

// JSVoid is just a typedef for void.
typedef JSVoidRepType = void;
Loading

0 comments on commit b8402f5

Please sign in to comment.