Fix Js-interop factory calls which broke when eliding optional parameters.
The issue derives from the fact that `parameterStructure` has only the preserved parameters,
however the SSA was emitting values for all arguments.
I fixed this by emitting all parameters. I also noticed that the parameter order should
probably be the native-ordering here as well (it doesn't matter for the factory, but it may
matter for other static native calls, if any)
Bug: https://github.com/dart-lang/sdk/issues/35916
Change-Id: I2e93c7f8e3baf5c9285107d23786bb3bf4f3a511
Reviewed-on: https://dart-review.googlesource.com/c/92626
Commit-Queue: Sigmund Cherem <sigmund@google.com>
Reviewed-by: Stephen Adams <sra@google.com>
diff --git a/pkg/compiler/lib/src/ssa/builder_kernel.dart b/pkg/compiler/lib/src/ssa/builder_kernel.dart
index 607fbeb..6ceb352 100644
--- a/pkg/compiler/lib/src/ssa/builder_kernel.dart
+++ b/pkg/compiler/lib/src/ssa/builder_kernel.dart
@@ -3266,12 +3266,8 @@
// Visit named arguments in parameter-position order, selecting provided
// or default value.
- // TODO(sra): Ensure the stored order is canonical so we don't have to
- // sort. The old builder uses CallStructure.makeArgumentList which
- // depends on the old element model.
- var namedParameters = target.namedParameters.toList()
- ..sort((ir.VariableDeclaration a, ir.VariableDeclaration b) =>
- a.name.compareTo(b.name));
+ var namedParameters = target.namedParameters.toList();
+ namedParameters.sort(nativeOrdering);
for (ir.VariableDeclaration parameter in namedParameters) {
HInstruction value = namedValues[parameter.name];
values.add(value);
@@ -4363,12 +4359,22 @@
// Factory constructor that is syntactic sugar for creating a JavaScript
// object literal.
ConstructorEntity constructor = element;
- ParameterStructure params = constructor.parameterStructure;
int i = 0;
int positions = 0;
var filteredArguments = <HInstruction>[];
var parameterNameMap = new Map<String, js.Expression>();
- params.namedParameters.forEach((String parameterName) {
+
+ // Note: we don't use `constructor.parameterStructure` here because
+ // we don't elide parameters to js-interop external static targets
+ // (including factory constructors.)
+ // TODO(johnniwinther): can we elide those parameters? This should be
+ // consistent with what we do with instance methods.
+ ir.Procedure node = _elementMap.getMemberDefinition(constructor).node;
+ List<ir.VariableDeclaration> namedParameters =
+ node.function.namedParameters.toList();
+ namedParameters.sort(nativeOrdering);
+ for (ir.VariableDeclaration variable in namedParameters) {
+ String parameterName = variable.name;
// TODO(jacobr): consider throwing if parameter names do not match
// names of properties in the class.
HInstruction argument = arguments[i];
@@ -4378,7 +4384,7 @@
parameterNameMap[jsName] = new js.InterpolatedExpression(positions++);
}
i++;
- });
+ }
var codeTemplate =
new js.Template(null, js.objectLiteral(parameterNameMap));
diff --git a/tests/compiler/dart2js_extra/js_interop_no_elide_optional_arg_test.dart b/tests/compiler/dart2js_extra/js_interop_no_elide_optional_arg_test.dart
new file mode 100644
index 0000000..5d6d913
--- /dev/null
+++ b/tests/compiler/dart2js_extra/js_interop_no_elide_optional_arg_test.dart
@@ -0,0 +1,31 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// Test that optional arguments of js-interop factory constructors are not
+/// elided.
+/// This is a regression test for issue 35916
+@JS()
+library test;
+
+import "package:js/js.dart";
+import "package:expect/expect.dart";
+
+@JS()
+@anonymous
+class Margins {
+ external factory Margins(
+ {int top, int start, int end, int right, int bottom, int left});
+ external int get top;
+ external int get right;
+ external int get left;
+ external int get bottom;
+}
+
+main() {
+ var m = new Margins(bottom: 21, left: 88, right: 20, top: 24);
+ Expect.equals(m.top, 24);
+ Expect.equals(m.bottom, 21);
+ Expect.equals(m.left, 88);
+ Expect.equals(m.right, 20);
+}