[dart2wasm] Fix invocation forwarder named argument adjustment

Invocation forwarders currently cannot distinguish a named parameter not
passed from passed as `null`.

Refactor `getNamedParameter` to return nullable index. When the index is
not null it means that the named parameter is present, and its value may
be `null`.

This doesn't fix any of the existing tests so I added a regression test.

(Bug originally discovered and fixed in
https://dart-review.googlesource.com/c/sdk/+/278505)

Change-Id: I960c674073b3d25c37e79f9836647882acaff08b
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/278745
Reviewed-by: Aske Simon Christensen <askesc@google.com>
Commit-Queue: Ömer Ağacan <omersa@google.com>
Reviewed-by: Joshua Litt <joshualitt@google.com>
This commit is contained in:
Ömer Sinan Ağacan 2023-01-10 13:37:33 +00:00 committed by Commit Queue
parent 6a4a6a167d
commit 8db3be7557
4 changed files with 53 additions and 16 deletions

View file

@ -334,8 +334,8 @@ class Forwarder {
translator, function, targetMemberParamInfo.named.length);
b.local_set(adjustedNamedArgsLocal);
final namedParameterValueLocal =
function.addLocal(translator.topInfo.nullableType);
final namedParameterIdxLocal = function.addLocal(
translator.classInfo[translator.boxedIntClass]!.nullableType);
final remainingNamedArgsLocal = numArgsLocal;
b.local_get(namedArgsLocal);
@ -371,9 +371,9 @@ class Forwarder {
translator.classInfo[translator.symbolClass]!.nonNullableType);
b.call(translator.functions
.getFunction(translator.getNamedParameter.reference));
.getFunction(translator.getNamedParameterIndex.reference));
b.local_tee(namedParameterIdxLocal);
b.local_tee(namedParameterValueLocal);
b.ref_is_null();
b.i32_eqz();
b.if_();
@ -383,14 +383,20 @@ class Forwarder {
b.local_set(remainingNamedArgsLocal);
b.end();
b.local_get(namedParameterValueLocal);
b.local_get(namedParameterIdxLocal);
b.ref_is_null();
if (functionNodeDefaultValue == null &&
paramInfoDefaultValue == null) {
// Required
b.br_if(topBlock);
b.local_get(adjustedNamedArgsLocal);
b.local_get(namedParameterValueLocal);
b.local_get(namedArgsLocal);
translator.indexList(b, (b) {
b.local_get(namedParameterIdxLocal);
translator.convertType(
function, namedParameterIdxLocal.type, w.NumType.i64);
b.i32_wrap_i64();
});
b.call(translator.functions
.getFunction(translator.growableListAdd.reference));
} else {
@ -398,6 +404,8 @@ class Forwarder {
// the member
b.if_();
b.local_get(adjustedNamedArgsLocal);
if (functionNodeDefaultValue != null) {
// Used by the member, has a default value
translator.constants.instantiateConstant(
@ -414,13 +422,24 @@ class Forwarder {
translator.topInfo.nullableType,
);
}
b.local_set(namedParameterValueLocal);
b.end();
b.local_get(adjustedNamedArgsLocal);
b.local_get(namedParameterValueLocal);
b.call(translator.functions
.getFunction(translator.growableListAdd.reference));
b.else_();
b.local_get(adjustedNamedArgsLocal);
b.local_get(namedArgsLocal);
translator.indexList(b, (b) {
b.local_get(namedParameterIdxLocal);
translator.convertType(
function, namedParameterIdxLocal.type, w.NumType.i64);
b.i32_wrap_i64();
});
b.call(translator.functions
.getFunction(translator.growableListAdd.reference));
b.end();
}
}

View file

@ -196,8 +196,8 @@ mixin KernelNodes {
"dart:core", "_TypeUniverse", "substituteFunctionTypeArgument");
// dart:core dynamic invocation helper procedures
late final Procedure getNamedParameter =
index.getTopLevelProcedure("dart:core", "_getNamedParameter");
late final Procedure getNamedParameterIndex =
index.getTopLevelProcedure("dart:core", "_getNamedParameterIndex");
late final Procedure namedParameterListToMap =
index.getTopLevelProcedure("dart:core", "_namedParameterListToMap");

View file

@ -5,13 +5,13 @@
part of "core_patch.dart";
/// Finds a named parameter in a named parameter list passed to a dynamic
/// forwarder and returns the value of that named parameter. Returns `null` if
/// the name is not in the list.
/// forwarder and returns the index of the value of that named parameter.
/// Returns `null` if the name is not in the list.
@pragma("wasm:entry-point")
Object? _getNamedParameter(List<Object?> namedArguments, Symbol paramName) {
int? _getNamedParameterIndex(List<Object?> namedArguments, Symbol paramName) {
for (int i = 0; i < namedArguments.length; i += 2) {
if (identical(namedArguments[i], paramName)) {
return namedArguments[i + 1];
return i + 1;
}
}
return null;

View file

@ -0,0 +1,18 @@
// Copyright (c) 2023, 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.
import 'package:expect/expect.dart';
class A {
int? test({int? a = 123}) {
return a;
}
}
void main() {
dynamic x = A();
Expect.equals(null, x.test(a: null));
Expect.equals(123, x.test());
Expect.equals(456, x.test(a: 456));
}