[pkg:js] Lower external @staticInterop and extension members using invocation-level semantics

We've changed the semantics for these members using dart:js_interop
so that not passing in optionals on the Dart side is equivalent to
not passing in optionals on the JS side. This CL makes that consistent
with package:js as well.

Modifies CHANGELOG to announce breaking change.

Change-Id: Ic5c33c9c797983a72edec9bc59f60fc1f29240b4
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/300400
Reviewed-by: Joshua Litt <joshualitt@google.com>
Commit-Queue: Srujan Gaddam <srujzs@google.com>
This commit is contained in:
Srujan Gaddam 2023-05-09 23:12:58 +00:00 committed by Commit Queue
parent 8cbd946338
commit 29e814357c
4 changed files with 13 additions and 38 deletions

View file

@ -20,6 +20,14 @@
`external` `@staticInterop` members and `external` extension members can no
longer be used as tear-offs. Declare a closure or a non-`external` method that
calls these members, and use that instead.
- **Breaking change to `@staticInterop` and `external` extension members**:
`external` `@staticInterop` members and `external` extension members will
generate slightly different JS code for methods that have optional parameters.
Whereas before, the JS code passed in the default value for missing optionals,
it will now pass in only the provided members. This aligns with how JS
parameters work, where omitted parameters are actually omitted. For example,
calling `external void foo([int a, int b])` as `foo(0)` will now result in
`foo(0)`, and not `foo(0, null)`.
### Tools

View file

@ -930,31 +930,20 @@ class InlineExtensionIndex {
/// member but rather lower directly to the interop procedure at the
/// call-site. This is needed in order to support cases where omitted
/// optional parameters shouldn't be passed.
///
/// **Note that we only do this for users using `dart:js_interop`'s `@JS`
/// annotation. This means `@staticInterop` will behave slightly differently
/// depending on the import. This is to avoid a breaking change in the
/// existing semantics of `@staticInterop`.**
bool canBeInvocationLevelLowered(Procedure node) {
if (hasDartJSInteropAnnotation(node) ||
hasDartJSInteropAnnotation(node.enclosingLibrary) ||
if (hasJSInteropAnnotation(node) ||
hasJSInteropAnnotation(node.enclosingLibrary) ||
(node.enclosingClass != null &&
hasDartJSInteropAnnotation(node.enclosingClass!))) {
hasJSInteropAnnotation(node.enclosingClass!))) {
return true;
}
if (node.isExtensionMember) {
final annotatable = getExtensionAnnotatable(node);
if (annotatable != null) {
return hasDartJSInteropAnnotation(annotatable);
}
return getExtensionAnnotatable(node) != null;
}
if (node.isInlineClassMember) {
final cls = getInlineClass(node);
if (cls != null) {
return hasDartJSInteropAnnotation(cls);
}
return getInlineClass(node) != null;
}
return false;

View file

@ -133,17 +133,6 @@ void main() {
expect(foo.otherSumFn(10, 5), equals(15));
});
// TODO(41375): Remove if JS interop default value arguments are disallowed.
test('optional arguments', () {
var foo = Foo(42);
expect(foo.field, equals(42));
foo.setField10();
expect(foo.field, equals(10));
foo.setField10(6);
expect(foo.field, equals(6));
});
test('module class', () {
var bar = Bar(5);
expect(js_util.getProperty(bar, 'fieldAnnotation'), equals(5));

View file

@ -115,17 +115,6 @@ void main() {
expect(foo.otherSumFn(10, 5), equals(15));
});
// TODO(41375): Remove if JS interop default value arguments are disallowed.
test('optional arguments', () {
var foo = Foo(42);
expect(foo.getField(), equals(42));
foo.setField10();
expect(foo.getField(), equals(10));
foo.setField10(6);
expect(foo.getField(), equals(6));
});
test('module class', () {
var bar = Bar(5);
expect(js_util.getProperty(bar, 'fieldAnnotation'), equals(5));