[cfe,dartdevc,dart2js] Use InstanceGetterInvocation for getter/field invocation
The web compilers don't support getter/field invocation encoded as a
FunctionInvocation on an InstanceGet because it doesn't work for
getter/field invocation of js-interop properties, since the InstanceGet
wouldn't result in a Dart function but just JavaScript function.
To support this in the new method invocation encoding, a special
expression, InstanceGetterInvocation, is used to encode getter/field
invocations in dart2js and ddc.
Change-Id: I21da8e8686f66ae4ce4d44245073b9e424f975b9
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/192181
Reviewed-by: Dmitry Stefantsov <dmitryas@google.com>
Commit-Queue: Johnni Winther <johnniwinther@google.com>
diff --git a/pkg/compiler/lib/src/ir/static_type.dart b/pkg/compiler/lib/src/ir/static_type.dart
index cb063b6..fd85772 100644
--- a/pkg/compiler/lib/src/ir/static_type.dart
+++ b/pkg/compiler/lib/src/ir/static_type.dart
@@ -1012,16 +1012,9 @@
// effectively final variable types and type promotion.
ir.DartType functionType = _computeInstanceInvocationType(
receiverType, interfaceTarget, node.arguments, argumentTypes);
- if (functionType != node.functionType) {
+ if (functionType is ir.FunctionType && functionType != node.functionType) {
node.functionType = functionType;
- // TODO(johnniwinther): To provide the static guarantee that arguments
- // of a statically typed call have been checked against the parameter
- // types we need to call [_updateMethodInvocationTarget]. This can create
- // uses of type variables are not registered with the closure model so
- // we skip it for now. Note that this invariant is not currently used
- // in later phases since it wasn't provided for function invocations in
- // the old method invocation encoding.
- //_updateMethodInvocationTarget(node, argumentTypes, functionType);
+ _updateMethodInvocationTarget(node, argumentTypes, functionType);
}
ir.DartType returnType = _getFunctionReturnType(functionType);
receiverType = _narrowInstanceReceiver(node.interfaceTarget, receiverType);
@@ -1046,10 +1039,14 @@
(interfaceTarget is ir.Procedure && interfaceTarget.isGetter)) {
// This should actually be a function invocation of an instance get but
// this doesn't work for invocation of js-interop properties. We
- // therefore use [ir.MethodInvocation] instead.
- // TODO(johnniwinther): Use [ir.InstanceGetterInvocation] instead.
- replacement = ir.MethodInvocation(
- node.receiver, node.name, node.arguments, interfaceTarget)
+ // therefore use [ir.InstanceGetterInvocation] instead.
+ replacement = ir.InstanceGetterInvocation(
+ ir.InstanceAccessKind.Instance,
+ node.receiver,
+ node.name,
+ node.arguments,
+ interfaceTarget: interfaceTarget,
+ functionType: functionType is ir.FunctionType ? functionType : null)
..fileOffset = node.fileOffset;
} else {
replacement = ir.InstanceInvocation(ir.InstanceAccessKind.Instance,
diff --git a/pkg/dev_compiler/lib/src/kernel/nullable_inference.dart b/pkg/dev_compiler/lib/src/kernel/nullable_inference.dart
index b930366..07fa7d4 100644
--- a/pkg/dev_compiler/lib/src/kernel/nullable_inference.dart
+++ b/pkg/dev_compiler/lib/src/kernel/nullable_inference.dart
@@ -145,6 +145,11 @@
node.interfaceTarget, node.name.text, node, node.receiver);
@override
+ bool visitInstanceGetterInvocation(InstanceGetterInvocation node) =>
+ _invocationIsNullable(
+ node.interfaceTarget, node.name.text, node, node.receiver);
+
+ @override
bool visitDynamicInvocation(DynamicInvocation node) =>
_invocationIsNullable(null, node.name.text, node, node.receiver);
diff --git a/pkg/dev_compiler/lib/src/kernel/target.dart b/pkg/dev_compiler/lib/src/kernel/target.dart
index ffc64a4..1f8d5f6 100644
--- a/pkg/dev_compiler/lib/src/kernel/target.dart
+++ b/pkg/dev_compiler/lib/src/kernel/target.dart
@@ -440,6 +440,12 @@
}
@override
+ void visitInstanceGetterInvocation(InstanceGetterInvocation node) {
+ _checkTarget(node.receiver, node.interfaceTarget);
+ super.visitInstanceGetterInvocation(node);
+ }
+
+ @override
void visitInstanceTearOff(InstanceTearOff node) {
_checkTearoff(node.interfaceTarget);
super.visitInstanceTearOff(node);
diff --git a/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart b/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
index d754099..c8fbea5e 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
@@ -3330,24 +3330,38 @@
..fileOffset = nullAwareAction.fileOffset);
} else if (nullAwareAction is InstanceInvocation &&
nullAwareAction.receiver == originalPropertyGet) {
+ // TODO(johnniwinther): Remove this when [MethodInvocation] is no longer
+ // used and [originalPropertyGet] can be an [InstanceGet].
+ InstanceGet instanceGet = originalPropertyGet;
invocationResult = new ExpressionInferenceResult(
invocationResult.inferredType,
- new MethodInvocation(originalReceiver, originalName,
- nullAwareAction.arguments, originalTarget)
+ new InstanceGetterInvocation(instanceGet.kind, originalReceiver,
+ originalName, nullAwareAction.arguments,
+ interfaceTarget: originalTarget,
+ functionType: nullAwareAction.functionType)
..fileOffset = nullAwareAction.fileOffset);
} else if (nullAwareAction is DynamicInvocation &&
nullAwareAction.receiver == originalPropertyGet) {
+ // TODO(johnniwinther): Remove this when [MethodInvocation] is no longer
+ // used and [originalPropertyGet] can be an [InstanceGet].
+ InstanceGet instanceGet = originalPropertyGet;
invocationResult = new ExpressionInferenceResult(
invocationResult.inferredType,
- new MethodInvocation(originalReceiver, originalName,
- nullAwareAction.arguments, originalTarget)
+ new InstanceGetterInvocation(instanceGet.kind, originalReceiver,
+ originalName, nullAwareAction.arguments,
+ interfaceTarget: originalTarget, functionType: null)
..fileOffset = nullAwareAction.fileOffset);
} else if (nullAwareAction is FunctionInvocation &&
nullAwareAction.receiver == originalPropertyGet) {
+ // TODO(johnniwinther): Remove this when [MethodInvocation] is no longer
+ // used and [originalPropertyGet] can be an [InstanceGet].
+ InstanceGet instanceGet = originalPropertyGet;
invocationResult = new ExpressionInferenceResult(
invocationResult.inferredType,
- new MethodInvocation(originalReceiver, originalName,
- nullAwareAction.arguments, originalTarget)
+ new InstanceGetterInvocation(instanceGet.kind, originalReceiver,
+ originalName, nullAwareAction.arguments,
+ interfaceTarget: originalTarget,
+ functionType: nullAwareAction.functionType)
..fileOffset = nullAwareAction.fileOffset);
}
}
diff --git a/pkg/front_end/test/spell_checking_list_code.txt b/pkg/front_end/test/spell_checking_list_code.txt
index 0863ec7..dfcff07 100644
--- a/pkg/front_end/test/spell_checking_list_code.txt
+++ b/pkg/front_end/test/spell_checking_list_code.txt
@@ -353,6 +353,7 @@
dst
dummy
dupdate
+dyn
e
easy
ecma
diff --git a/pkg/front_end/testcases/dart2js/instance_getter_invocation.dart b/pkg/front_end/testcases/dart2js/instance_getter_invocation.dart
new file mode 100644
index 0000000..1ef505e
--- /dev/null
+++ b/pkg/front_end/testcases/dart2js/instance_getter_invocation.dart
@@ -0,0 +1,17 @@
+// Copyright (c) 2021, 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.
+
+T id<T>(T t) => t;
+
+class Class {
+ S Function<S>(S) get idFunction => id;
+ dynamic get dynFunction => id;
+}
+
+main() {
+ Class c = new Class();
+ c.idFunction(0);
+ c.idFunction<int>(0);
+ c.dynFunction(0);
+}
diff --git a/pkg/front_end/testcases/dart2js/instance_getter_invocation.dart.strong.expect b/pkg/front_end/testcases/dart2js/instance_getter_invocation.dart.strong.expect
new file mode 100644
index 0000000..e29a84e
--- /dev/null
+++ b/pkg/front_end/testcases/dart2js/instance_getter_invocation.dart.strong.expect
@@ -0,0 +1,25 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+class Class extends core::Object {
+ synthetic constructor •() → self::Class
+ : super core::Object::•()
+ ;
+ get idFunction() → <S extends core::Object? = dynamic>(S%) → S%
+ return #C1;
+ get dynFunction() → dynamic
+ return #C1;
+}
+static method id<T extends core::Object? = dynamic>(self::id::T% t) → self::id::T%
+ return t;
+static method main() → dynamic {
+ self::Class c = new self::Class::•();
+ let final self::Class #t1 = c in let final core::int #t2 = 0 in #t1.{self::Class::idFunction}<core::int>(#t2){(core::int) → core::int};
+ let final self::Class #t3 = c in let final core::int #t4 = 0 in #t3.{self::Class::idFunction}<core::int>(#t4){(core::int) → core::int};
+ let final self::Class #t5 = c in let final core::int #t6 = 0 in #t5.{self::Class::dynFunction}(#t6);
+}
+
+constants {
+ #C1 = tearoff self::id
+}
diff --git a/pkg/front_end/testcases/dart2js/instance_getter_invocation.dart.strong.transformed.expect b/pkg/front_end/testcases/dart2js/instance_getter_invocation.dart.strong.transformed.expect
new file mode 100644
index 0000000..6a431a4
--- /dev/null
+++ b/pkg/front_end/testcases/dart2js/instance_getter_invocation.dart.strong.transformed.expect
@@ -0,0 +1,31 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+class Class extends core::Object {
+ synthetic constructor •() → self::Class
+ : super core::Object::•()
+ ;
+ get idFunction() → <S extends core::Object? = dynamic>(S%) → S%
+ return #C1;
+ get dynFunction() → dynamic
+ return #C1;
+}
+static method id<T extends core::Object? = dynamic>(self::id::T% t) → self::id::T%
+ return t;
+static method main() → dynamic {
+ self::Class c = new self::Class::•();
+ let final self::Class #t1 = c in let final core::int #t2 = 0 in #t1.{self::Class::idFunction}<core::int>(#t2){(core::int) → core::int};
+ let final self::Class #t3 = c in let final core::int #t4 = 0 in #t3.{self::Class::idFunction}<core::int>(#t4){(core::int) → core::int};
+ let final self::Class #t5 = c in let final core::int #t6 = 0 in #t5.{self::Class::dynFunction}(#t6);
+}
+
+constants {
+ #C1 = tearoff self::id
+}
+
+Extra constant evaluation status:
+Evaluated: VariableGet @ org-dartlang-testcase:///instance_getter_invocation.dart:14:16 -> DoubleConstant(0.0)
+Evaluated: VariableGet @ org-dartlang-testcase:///instance_getter_invocation.dart:15:21 -> DoubleConstant(0.0)
+Evaluated: VariableGet @ org-dartlang-testcase:///instance_getter_invocation.dart:16:17 -> DoubleConstant(0.0)
+Extra constant evaluation: evaluated: 20, effectively constant: 3
diff --git a/pkg/front_end/testcases/dart2js/instance_getter_invocation.dart.textual_outline.expect b/pkg/front_end/testcases/dart2js/instance_getter_invocation.dart.textual_outline.expect
new file mode 100644
index 0000000..9cd1271
--- /dev/null
+++ b/pkg/front_end/testcases/dart2js/instance_getter_invocation.dart.textual_outline.expect
@@ -0,0 +1,8 @@
+T id<T>(T t) => t;
+
+class Class {
+ S Function<S>(S) get idFunction => id;
+ dynamic get dynFunction => id;
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/dart2js/instance_getter_invocation.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/dart2js/instance_getter_invocation.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..9cd1271
--- /dev/null
+++ b/pkg/front_end/testcases/dart2js/instance_getter_invocation.dart.textual_outline_modelled.expect
@@ -0,0 +1,8 @@
+T id<T>(T t) => t;
+
+class Class {
+ S Function<S>(S) get idFunction => id;
+ dynamic get dynFunction => id;
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/dart2js/instance_getter_invocation.dart.weak.expect b/pkg/front_end/testcases/dart2js/instance_getter_invocation.dart.weak.expect
new file mode 100644
index 0000000..e29a84e
--- /dev/null
+++ b/pkg/front_end/testcases/dart2js/instance_getter_invocation.dart.weak.expect
@@ -0,0 +1,25 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+class Class extends core::Object {
+ synthetic constructor •() → self::Class
+ : super core::Object::•()
+ ;
+ get idFunction() → <S extends core::Object? = dynamic>(S%) → S%
+ return #C1;
+ get dynFunction() → dynamic
+ return #C1;
+}
+static method id<T extends core::Object? = dynamic>(self::id::T% t) → self::id::T%
+ return t;
+static method main() → dynamic {
+ self::Class c = new self::Class::•();
+ let final self::Class #t1 = c in let final core::int #t2 = 0 in #t1.{self::Class::idFunction}<core::int>(#t2){(core::int) → core::int};
+ let final self::Class #t3 = c in let final core::int #t4 = 0 in #t3.{self::Class::idFunction}<core::int>(#t4){(core::int) → core::int};
+ let final self::Class #t5 = c in let final core::int #t6 = 0 in #t5.{self::Class::dynFunction}(#t6);
+}
+
+constants {
+ #C1 = tearoff self::id
+}
diff --git a/pkg/front_end/testcases/dart2js/instance_getter_invocation.dart.weak.outline.expect b/pkg/front_end/testcases/dart2js/instance_getter_invocation.dart.weak.outline.expect
new file mode 100644
index 0000000..85f75fa
--- /dev/null
+++ b/pkg/front_end/testcases/dart2js/instance_getter_invocation.dart.weak.outline.expect
@@ -0,0 +1,16 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+class Class extends core::Object {
+ synthetic constructor •() → self::Class
+ ;
+ get idFunction() → <S extends core::Object? = dynamic>(S%) → S%
+ ;
+ get dynFunction() → dynamic
+ ;
+}
+static method id<T extends core::Object? = dynamic>(self::id::T% t) → self::id::T%
+ ;
+static method main() → dynamic
+ ;
diff --git a/pkg/front_end/testcases/dart2js/instance_getter_invocation.dart.weak.transformed.expect b/pkg/front_end/testcases/dart2js/instance_getter_invocation.dart.weak.transformed.expect
new file mode 100644
index 0000000..6a431a4
--- /dev/null
+++ b/pkg/front_end/testcases/dart2js/instance_getter_invocation.dart.weak.transformed.expect
@@ -0,0 +1,31 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+class Class extends core::Object {
+ synthetic constructor •() → self::Class
+ : super core::Object::•()
+ ;
+ get idFunction() → <S extends core::Object? = dynamic>(S%) → S%
+ return #C1;
+ get dynFunction() → dynamic
+ return #C1;
+}
+static method id<T extends core::Object? = dynamic>(self::id::T% t) → self::id::T%
+ return t;
+static method main() → dynamic {
+ self::Class c = new self::Class::•();
+ let final self::Class #t1 = c in let final core::int #t2 = 0 in #t1.{self::Class::idFunction}<core::int>(#t2){(core::int) → core::int};
+ let final self::Class #t3 = c in let final core::int #t4 = 0 in #t3.{self::Class::idFunction}<core::int>(#t4){(core::int) → core::int};
+ let final self::Class #t5 = c in let final core::int #t6 = 0 in #t5.{self::Class::dynFunction}(#t6);
+}
+
+constants {
+ #C1 = tearoff self::id
+}
+
+Extra constant evaluation status:
+Evaluated: VariableGet @ org-dartlang-testcase:///instance_getter_invocation.dart:14:16 -> DoubleConstant(0.0)
+Evaluated: VariableGet @ org-dartlang-testcase:///instance_getter_invocation.dart:15:21 -> DoubleConstant(0.0)
+Evaluated: VariableGet @ org-dartlang-testcase:///instance_getter_invocation.dart:16:17 -> DoubleConstant(0.0)
+Extra constant evaluation: evaluated: 20, effectively constant: 3
diff --git a/pkg/front_end/testcases/dartdevc/instance_getter_invocation.dart b/pkg/front_end/testcases/dartdevc/instance_getter_invocation.dart
new file mode 100644
index 0000000..1ef505e
--- /dev/null
+++ b/pkg/front_end/testcases/dartdevc/instance_getter_invocation.dart
@@ -0,0 +1,17 @@
+// Copyright (c) 2021, 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.
+
+T id<T>(T t) => t;
+
+class Class {
+ S Function<S>(S) get idFunction => id;
+ dynamic get dynFunction => id;
+}
+
+main() {
+ Class c = new Class();
+ c.idFunction(0);
+ c.idFunction<int>(0);
+ c.dynFunction(0);
+}
diff --git a/pkg/front_end/testcases/dartdevc/instance_getter_invocation.dart.strong.expect b/pkg/front_end/testcases/dartdevc/instance_getter_invocation.dart.strong.expect
new file mode 100644
index 0000000..e29a84e
--- /dev/null
+++ b/pkg/front_end/testcases/dartdevc/instance_getter_invocation.dart.strong.expect
@@ -0,0 +1,25 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+class Class extends core::Object {
+ synthetic constructor •() → self::Class
+ : super core::Object::•()
+ ;
+ get idFunction() → <S extends core::Object? = dynamic>(S%) → S%
+ return #C1;
+ get dynFunction() → dynamic
+ return #C1;
+}
+static method id<T extends core::Object? = dynamic>(self::id::T% t) → self::id::T%
+ return t;
+static method main() → dynamic {
+ self::Class c = new self::Class::•();
+ let final self::Class #t1 = c in let final core::int #t2 = 0 in #t1.{self::Class::idFunction}<core::int>(#t2){(core::int) → core::int};
+ let final self::Class #t3 = c in let final core::int #t4 = 0 in #t3.{self::Class::idFunction}<core::int>(#t4){(core::int) → core::int};
+ let final self::Class #t5 = c in let final core::int #t6 = 0 in #t5.{self::Class::dynFunction}(#t6);
+}
+
+constants {
+ #C1 = tearoff self::id
+}
diff --git a/pkg/front_end/testcases/dartdevc/instance_getter_invocation.dart.strong.transformed.expect b/pkg/front_end/testcases/dartdevc/instance_getter_invocation.dart.strong.transformed.expect
new file mode 100644
index 0000000..6a431a4
--- /dev/null
+++ b/pkg/front_end/testcases/dartdevc/instance_getter_invocation.dart.strong.transformed.expect
@@ -0,0 +1,31 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+class Class extends core::Object {
+ synthetic constructor •() → self::Class
+ : super core::Object::•()
+ ;
+ get idFunction() → <S extends core::Object? = dynamic>(S%) → S%
+ return #C1;
+ get dynFunction() → dynamic
+ return #C1;
+}
+static method id<T extends core::Object? = dynamic>(self::id::T% t) → self::id::T%
+ return t;
+static method main() → dynamic {
+ self::Class c = new self::Class::•();
+ let final self::Class #t1 = c in let final core::int #t2 = 0 in #t1.{self::Class::idFunction}<core::int>(#t2){(core::int) → core::int};
+ let final self::Class #t3 = c in let final core::int #t4 = 0 in #t3.{self::Class::idFunction}<core::int>(#t4){(core::int) → core::int};
+ let final self::Class #t5 = c in let final core::int #t6 = 0 in #t5.{self::Class::dynFunction}(#t6);
+}
+
+constants {
+ #C1 = tearoff self::id
+}
+
+Extra constant evaluation status:
+Evaluated: VariableGet @ org-dartlang-testcase:///instance_getter_invocation.dart:14:16 -> DoubleConstant(0.0)
+Evaluated: VariableGet @ org-dartlang-testcase:///instance_getter_invocation.dart:15:21 -> DoubleConstant(0.0)
+Evaluated: VariableGet @ org-dartlang-testcase:///instance_getter_invocation.dart:16:17 -> DoubleConstant(0.0)
+Extra constant evaluation: evaluated: 20, effectively constant: 3
diff --git a/pkg/front_end/testcases/dartdevc/instance_getter_invocation.dart.textual_outline.expect b/pkg/front_end/testcases/dartdevc/instance_getter_invocation.dart.textual_outline.expect
new file mode 100644
index 0000000..9cd1271
--- /dev/null
+++ b/pkg/front_end/testcases/dartdevc/instance_getter_invocation.dart.textual_outline.expect
@@ -0,0 +1,8 @@
+T id<T>(T t) => t;
+
+class Class {
+ S Function<S>(S) get idFunction => id;
+ dynamic get dynFunction => id;
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/dartdevc/instance_getter_invocation.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/dartdevc/instance_getter_invocation.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..9cd1271
--- /dev/null
+++ b/pkg/front_end/testcases/dartdevc/instance_getter_invocation.dart.textual_outline_modelled.expect
@@ -0,0 +1,8 @@
+T id<T>(T t) => t;
+
+class Class {
+ S Function<S>(S) get idFunction => id;
+ dynamic get dynFunction => id;
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/dartdevc/instance_getter_invocation.dart.weak.expect b/pkg/front_end/testcases/dartdevc/instance_getter_invocation.dart.weak.expect
new file mode 100644
index 0000000..e29a84e
--- /dev/null
+++ b/pkg/front_end/testcases/dartdevc/instance_getter_invocation.dart.weak.expect
@@ -0,0 +1,25 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+class Class extends core::Object {
+ synthetic constructor •() → self::Class
+ : super core::Object::•()
+ ;
+ get idFunction() → <S extends core::Object? = dynamic>(S%) → S%
+ return #C1;
+ get dynFunction() → dynamic
+ return #C1;
+}
+static method id<T extends core::Object? = dynamic>(self::id::T% t) → self::id::T%
+ return t;
+static method main() → dynamic {
+ self::Class c = new self::Class::•();
+ let final self::Class #t1 = c in let final core::int #t2 = 0 in #t1.{self::Class::idFunction}<core::int>(#t2){(core::int) → core::int};
+ let final self::Class #t3 = c in let final core::int #t4 = 0 in #t3.{self::Class::idFunction}<core::int>(#t4){(core::int) → core::int};
+ let final self::Class #t5 = c in let final core::int #t6 = 0 in #t5.{self::Class::dynFunction}(#t6);
+}
+
+constants {
+ #C1 = tearoff self::id
+}
diff --git a/pkg/front_end/testcases/dartdevc/instance_getter_invocation.dart.weak.outline.expect b/pkg/front_end/testcases/dartdevc/instance_getter_invocation.dart.weak.outline.expect
new file mode 100644
index 0000000..85f75fa
--- /dev/null
+++ b/pkg/front_end/testcases/dartdevc/instance_getter_invocation.dart.weak.outline.expect
@@ -0,0 +1,16 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+class Class extends core::Object {
+ synthetic constructor •() → self::Class
+ ;
+ get idFunction() → <S extends core::Object? = dynamic>(S%) → S%
+ ;
+ get dynFunction() → dynamic
+ ;
+}
+static method id<T extends core::Object? = dynamic>(self::id::T% t) → self::id::T%
+ ;
+static method main() → dynamic
+ ;
diff --git a/pkg/front_end/testcases/dartdevc/instance_getter_invocation.dart.weak.transformed.expect b/pkg/front_end/testcases/dartdevc/instance_getter_invocation.dart.weak.transformed.expect
new file mode 100644
index 0000000..6a431a4
--- /dev/null
+++ b/pkg/front_end/testcases/dartdevc/instance_getter_invocation.dart.weak.transformed.expect
@@ -0,0 +1,31 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+class Class extends core::Object {
+ synthetic constructor •() → self::Class
+ : super core::Object::•()
+ ;
+ get idFunction() → <S extends core::Object? = dynamic>(S%) → S%
+ return #C1;
+ get dynFunction() → dynamic
+ return #C1;
+}
+static method id<T extends core::Object? = dynamic>(self::id::T% t) → self::id::T%
+ return t;
+static method main() → dynamic {
+ self::Class c = new self::Class::•();
+ let final self::Class #t1 = c in let final core::int #t2 = 0 in #t1.{self::Class::idFunction}<core::int>(#t2){(core::int) → core::int};
+ let final self::Class #t3 = c in let final core::int #t4 = 0 in #t3.{self::Class::idFunction}<core::int>(#t4){(core::int) → core::int};
+ let final self::Class #t5 = c in let final core::int #t6 = 0 in #t5.{self::Class::dynFunction}(#t6);
+}
+
+constants {
+ #C1 = tearoff self::id
+}
+
+Extra constant evaluation status:
+Evaluated: VariableGet @ org-dartlang-testcase:///instance_getter_invocation.dart:14:16 -> DoubleConstant(0.0)
+Evaluated: VariableGet @ org-dartlang-testcase:///instance_getter_invocation.dart:15:21 -> DoubleConstant(0.0)
+Evaluated: VariableGet @ org-dartlang-testcase:///instance_getter_invocation.dart:16:17 -> DoubleConstant(0.0)
+Extra constant evaluation: evaluated: 20, effectively constant: 3
diff --git a/pkg/front_end/testcases/implicit_getter_calls/getter_call.dart.weak.expect b/pkg/front_end/testcases/implicit_getter_calls/getter_call.dart.weak.expect
index ce47bb9..2b4c9cc 100644
--- a/pkg/front_end/testcases/implicit_getter_calls/getter_call.dart.weak.expect
+++ b/pkg/front_end/testcases/implicit_getter_calls/getter_call.dart.weak.expect
@@ -153,21 +153,21 @@
}
static method callGetter(self::Class* c) → dynamic {
self::expect(0, c.{self::Class::getter1a}());
- self::expect(0, c.{self::Class::getter1b}());
- self::expect(42.{core::int::unary-}(){() →* core::int*}, let final self::Class* #t31 = c in let final core::int* #t32 = self::read(42) in #t31.{self::Class::getter2}(#t32));
- self::expect(11.{core::int::unary-}(){() →* core::int*}, let final self::Class* #t33 = c in let final core::int* #t34 = self::read(12) in let final core::int* #t35 = self::read(23) in #t33.{self::Class::getter3}(#t34, #t35));
- self::expect(12, let final self::Class* #t36 = c in let final core::int* #t37 = self::read(12) in #t36.{self::Class::getter4}(#t37));
- self::expect(11.{core::int::unary-}(){() →* core::int*}, let final self::Class* #t38 = c in let final core::int* #t39 = self::read(12) in let final core::int* #t40 = self::read(23) in #t38.{self::Class::getter4}(#t39, #t40));
- self::expect(0, c.{self::Class::getter5}());
- self::expect(12, let final self::Class* #t41 = c in let final core::int* #t42 = self::read(12) in #t41.{self::Class::getter5}(#t42));
- self::expect(11.{core::int::unary-}(){() →* core::int*}, let final self::Class* #t43 = c in let final core::int* #t44 = self::read(12) in let final core::int* #t45 = self::read(23) in #t43.{self::Class::getter5}(#t44, #t45));
- self::expect(12, let final self::Class* #t46 = c in let final core::int* #t47 = self::read(12) in #t46.{self::Class::getter6}(#t47));
- self::expect(11.{core::int::unary-}(){() →* core::int*}, let final self::Class* #t48 = c in let final core::int* #t49 = self::read(12) in let final core::int* #t50 = self::read(23) in #t48.{self::Class::getter6}(#t49, b: #t50));
- self::expect(0, c.{self::Class::getter7}());
- self::expect(12, let final self::Class* #t51 = c in let final core::int* #t52 = self::read(12) in #t51.{self::Class::getter7}(a: #t52));
- self::expect(23.{core::int::unary-}(){() →* core::int*}, let final self::Class* #t53 = c in let final core::int* #t54 = self::read(23) in #t53.{self::Class::getter7}(b: #t54));
- self::expect(11.{core::int::unary-}(){() →* core::int*}, let final self::Class* #t55 = c in let final core::int* #t56 = self::read(12) in let final core::int* #t57 = self::read(23) in #t55.{self::Class::getter7}(a: #t56, b: #t57));
- self::expect(11.{core::int::unary-}(){() →* core::int*}, let final self::Class* #t58 = c in let final core::int* #t59 = self::read(23) in let final core::int* #t60 = self::read(12) in #t58.{self::Class::getter7}(b: #t59, a: #t60));
+ self::expect(0, c.{self::Class::getter1b}(){() →* core::int*});
+ self::expect(42.{core::int::unary-}(){() →* core::int*}, let final self::Class* #t31 = c in let final core::int* #t32 = self::read(42) in #t31.{self::Class::getter2}(#t32){(core::int*) →* core::int*});
+ self::expect(11.{core::int::unary-}(){() →* core::int*}, let final self::Class* #t33 = c in let final core::int* #t34 = self::read(12) in let final core::int* #t35 = self::read(23) in #t33.{self::Class::getter3}(#t34, #t35){(core::int*, core::int*) →* core::int*});
+ self::expect(12, let final self::Class* #t36 = c in let final core::int* #t37 = self::read(12) in #t36.{self::Class::getter4}(#t37){(core::int*, [core::int*]) →* core::int*});
+ self::expect(11.{core::int::unary-}(){() →* core::int*}, let final self::Class* #t38 = c in let final core::int* #t39 = self::read(12) in let final core::int* #t40 = self::read(23) in #t38.{self::Class::getter4}(#t39, #t40){(core::int*, [core::int*]) →* core::int*});
+ self::expect(0, c.{self::Class::getter5}(){([core::int*, core::int*]) →* core::int*});
+ self::expect(12, let final self::Class* #t41 = c in let final core::int* #t42 = self::read(12) in #t41.{self::Class::getter5}(#t42){([core::int*, core::int*]) →* core::int*});
+ self::expect(11.{core::int::unary-}(){() →* core::int*}, let final self::Class* #t43 = c in let final core::int* #t44 = self::read(12) in let final core::int* #t45 = self::read(23) in #t43.{self::Class::getter5}(#t44, #t45){([core::int*, core::int*]) →* core::int*});
+ self::expect(12, let final self::Class* #t46 = c in let final core::int* #t47 = self::read(12) in #t46.{self::Class::getter6}(#t47){(core::int*, {b: core::int*}) →* core::int*});
+ self::expect(11.{core::int::unary-}(){() →* core::int*}, let final self::Class* #t48 = c in let final core::int* #t49 = self::read(12) in let final core::int* #t50 = self::read(23) in #t48.{self::Class::getter6}(#t49, b: #t50){(core::int*, {b: core::int*}) →* core::int*});
+ self::expect(0, c.{self::Class::getter7}(){({a: core::int*, b: core::int*}) →* core::int*});
+ self::expect(12, let final self::Class* #t51 = c in let final core::int* #t52 = self::read(12) in #t51.{self::Class::getter7}(a: #t52){({a: core::int*, b: core::int*}) →* core::int*});
+ self::expect(23.{core::int::unary-}(){() →* core::int*}, let final self::Class* #t53 = c in let final core::int* #t54 = self::read(23) in #t53.{self::Class::getter7}(b: #t54){({a: core::int*, b: core::int*}) →* core::int*});
+ self::expect(11.{core::int::unary-}(){() →* core::int*}, let final self::Class* #t55 = c in let final core::int* #t56 = self::read(12) in let final core::int* #t57 = self::read(23) in #t55.{self::Class::getter7}(a: #t56, b: #t57){({a: core::int*, b: core::int*}) →* core::int*});
+ self::expect(11.{core::int::unary-}(){() →* core::int*}, let final self::Class* #t58 = c in let final core::int* #t59 = self::read(23) in let final core::int* #t60 = self::read(12) in #t58.{self::Class::getter7}(b: #t59, a: #t60){({a: core::int*, b: core::int*}) →* core::int*});
}
static method expect(dynamic expected, dynamic actual) → dynamic {
self::enableRead = true;
diff --git a/pkg/front_end/testcases/implicit_getter_calls/getter_call.dart.weak.transformed.expect b/pkg/front_end/testcases/implicit_getter_calls/getter_call.dart.weak.transformed.expect
index 25ceba5..3c6b74a 100644
--- a/pkg/front_end/testcases/implicit_getter_calls/getter_call.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/implicit_getter_calls/getter_call.dart.weak.transformed.expect
@@ -153,21 +153,21 @@
}
static method callGetter(self::Class* c) → dynamic {
self::expect(0, c.{self::Class::getter1a}());
- self::expect(0, c.{self::Class::getter1b}());
- self::expect(42.{core::int::unary-}(){() →* core::int*}, let final self::Class* #t31 = c in let final core::int* #t32 = self::read(42) in #t31.{self::Class::getter2}(#t32));
- self::expect(11.{core::int::unary-}(){() →* core::int*}, let final self::Class* #t33 = c in let final core::int* #t34 = self::read(12) in let final core::int* #t35 = self::read(23) in #t33.{self::Class::getter3}(#t34, #t35));
- self::expect(12, let final self::Class* #t36 = c in let final core::int* #t37 = self::read(12) in #t36.{self::Class::getter4}(#t37));
- self::expect(11.{core::int::unary-}(){() →* core::int*}, let final self::Class* #t38 = c in let final core::int* #t39 = self::read(12) in let final core::int* #t40 = self::read(23) in #t38.{self::Class::getter4}(#t39, #t40));
- self::expect(0, c.{self::Class::getter5}());
- self::expect(12, let final self::Class* #t41 = c in let final core::int* #t42 = self::read(12) in #t41.{self::Class::getter5}(#t42));
- self::expect(11.{core::int::unary-}(){() →* core::int*}, let final self::Class* #t43 = c in let final core::int* #t44 = self::read(12) in let final core::int* #t45 = self::read(23) in #t43.{self::Class::getter5}(#t44, #t45));
- self::expect(12, let final self::Class* #t46 = c in let final core::int* #t47 = self::read(12) in #t46.{self::Class::getter6}(#t47));
- self::expect(11.{core::int::unary-}(){() →* core::int*}, let final self::Class* #t48 = c in let final core::int* #t49 = self::read(12) in let final core::int* #t50 = self::read(23) in #t48.{self::Class::getter6}(#t49, b: #t50));
- self::expect(0, c.{self::Class::getter7}());
- self::expect(12, let final self::Class* #t51 = c in let final core::int* #t52 = self::read(12) in #t51.{self::Class::getter7}(a: #t52));
- self::expect(23.{core::int::unary-}(){() →* core::int*}, let final self::Class* #t53 = c in let final core::int* #t54 = self::read(23) in #t53.{self::Class::getter7}(b: #t54));
- self::expect(11.{core::int::unary-}(){() →* core::int*}, let final self::Class* #t55 = c in let final core::int* #t56 = self::read(12) in let final core::int* #t57 = self::read(23) in #t55.{self::Class::getter7}(a: #t56, b: #t57));
- self::expect(11.{core::int::unary-}(){() →* core::int*}, let final self::Class* #t58 = c in let final core::int* #t59 = self::read(23) in let final core::int* #t60 = self::read(12) in #t58.{self::Class::getter7}(b: #t59, a: #t60));
+ self::expect(0, c.{self::Class::getter1b}(){() →* core::int*});
+ self::expect(42.{core::int::unary-}(){() →* core::int*}, let final self::Class* #t31 = c in let final core::int* #t32 = self::read(42) in #t31.{self::Class::getter2}(#t32){(core::int*) →* core::int*});
+ self::expect(11.{core::int::unary-}(){() →* core::int*}, let final self::Class* #t33 = c in let final core::int* #t34 = self::read(12) in let final core::int* #t35 = self::read(23) in #t33.{self::Class::getter3}(#t34, #t35){(core::int*, core::int*) →* core::int*});
+ self::expect(12, let final self::Class* #t36 = c in let final core::int* #t37 = self::read(12) in #t36.{self::Class::getter4}(#t37){(core::int*, [core::int*]) →* core::int*});
+ self::expect(11.{core::int::unary-}(){() →* core::int*}, let final self::Class* #t38 = c in let final core::int* #t39 = self::read(12) in let final core::int* #t40 = self::read(23) in #t38.{self::Class::getter4}(#t39, #t40){(core::int*, [core::int*]) →* core::int*});
+ self::expect(0, c.{self::Class::getter5}(){([core::int*, core::int*]) →* core::int*});
+ self::expect(12, let final self::Class* #t41 = c in let final core::int* #t42 = self::read(12) in #t41.{self::Class::getter5}(#t42){([core::int*, core::int*]) →* core::int*});
+ self::expect(11.{core::int::unary-}(){() →* core::int*}, let final self::Class* #t43 = c in let final core::int* #t44 = self::read(12) in let final core::int* #t45 = self::read(23) in #t43.{self::Class::getter5}(#t44, #t45){([core::int*, core::int*]) →* core::int*});
+ self::expect(12, let final self::Class* #t46 = c in let final core::int* #t47 = self::read(12) in #t46.{self::Class::getter6}(#t47){(core::int*, {b: core::int*}) →* core::int*});
+ self::expect(11.{core::int::unary-}(){() →* core::int*}, let final self::Class* #t48 = c in let final core::int* #t49 = self::read(12) in let final core::int* #t50 = self::read(23) in #t48.{self::Class::getter6}(#t49, b: #t50){(core::int*, {b: core::int*}) →* core::int*});
+ self::expect(0, c.{self::Class::getter7}(){({a: core::int*, b: core::int*}) →* core::int*});
+ self::expect(12, let final self::Class* #t51 = c in let final core::int* #t52 = self::read(12) in #t51.{self::Class::getter7}(a: #t52){({a: core::int*, b: core::int*}) →* core::int*});
+ self::expect(23.{core::int::unary-}(){() →* core::int*}, let final self::Class* #t53 = c in let final core::int* #t54 = self::read(23) in #t53.{self::Class::getter7}(b: #t54){({a: core::int*, b: core::int*}) →* core::int*});
+ self::expect(11.{core::int::unary-}(){() →* core::int*}, let final self::Class* #t55 = c in let final core::int* #t56 = self::read(12) in let final core::int* #t57 = self::read(23) in #t55.{self::Class::getter7}(a: #t56, b: #t57){({a: core::int*, b: core::int*}) →* core::int*});
+ self::expect(11.{core::int::unary-}(){() →* core::int*}, let final self::Class* #t58 = c in let final core::int* #t59 = self::read(23) in let final core::int* #t60 = self::read(12) in #t58.{self::Class::getter7}(b: #t59, a: #t60){({a: core::int*, b: core::int*}) →* core::int*});
}
static method expect(dynamic expected, dynamic actual) → dynamic {
self::enableRead = true;
diff --git a/pkg/kernel/lib/ast.dart b/pkg/kernel/lib/ast.dart
index 0b0de7e..3298c90 100644
--- a/pkg/kernel/lib/ast.dart
+++ b/pkg/kernel/lib/ast.dart
@@ -5253,7 +5253,7 @@
int flags = 0;
- /// The static type of the invocation.
+ /// The static type of the invocation, or `dynamic` is of the type is unknown.
///
/// This includes substituted type parameters from the static receiver type
/// and generic type arguments.
@@ -5261,19 +5261,21 @@
/// For instance
///
/// class A<T> {
- /// Map<T, S> map<S>(S s) { ... }
+ /// Map<T, S> Function<S>(S) get map => ...
+ /// dynamic get dyn => ...
/// }
/// m(A<String> a) {
/// a.map(0); // The function type is `Map<String, int> Function(int)`.
+ /// a.dyn(0); // The function type is `null`.
/// }
///
- FunctionType functionType;
+ FunctionType? functionType;
Reference interfaceTargetReference;
InstanceGetterInvocation(InstanceAccessKind kind, Expression receiver,
Name name, Arguments arguments,
- {required Procedure interfaceTarget, required FunctionType functionType})
+ {required Member interfaceTarget, required FunctionType? functionType})
: this.byReference(kind, receiver, name, arguments,
interfaceTargetReference:
getNonNullableMemberReferenceGetter(interfaceTarget),
@@ -5284,14 +5286,12 @@
{required this.interfaceTargetReference, required this.functionType})
// ignore: unnecessary_null_comparison
: assert(interfaceTargetReference != null),
- // ignore: unnecessary_null_comparison
- assert(functionType != null),
- assert(functionType.typeParameters.isEmpty) {
+ assert(functionType == null || functionType.typeParameters.isEmpty) {
receiver.parent = this;
arguments.parent = this;
}
- Member get interfaceTarget => interfaceTargetReference.asProcedure;
+ Member get interfaceTarget => interfaceTargetReference.asMember;
void set interfaceTarget(Member target) {
interfaceTargetReference = getNonNullableMemberReferenceGetter(target);
@@ -5334,7 +5334,7 @@
@override
DartType getStaticTypeInternal(StaticTypeContext context) =>
- functionType.returnType;
+ functionType?.returnType ?? const DynamicType();
@override
R accept<R>(ExpressionVisitor<R> v) => v.visitInstanceGetterInvocation(this);
diff --git a/pkg/kernel/lib/binary/ast_from_binary.dart b/pkg/kernel/lib/binary/ast_from_binary.dart
index 15ebc86..2172314 100644
--- a/pkg/kernel/lib/binary/ast_from_binary.dart
+++ b/pkg/kernel/lib/binary/ast_from_binary.dart
@@ -2132,10 +2132,18 @@
InstanceAccessKind kind = InstanceAccessKind.values[readByte()];
int flags = readByte();
int offset = readOffset();
+ Expression receiver = readExpression();
+ Name name = readName();
+ Arguments arguments = readArguments();
+ DartType functionType = readDartType();
+ // `const DynamicType()` is used to encode a missing function type.
+ assert(functionType is FunctionType || functionType is DynamicType,
+ "Unexpected function type $functionType for InstanceGetterInvocation");
+ Reference interfaceTargetReference = readNonNullInstanceMemberReference();
return new InstanceGetterInvocation.byReference(
- kind, readExpression(), readName(), readArguments(),
- functionType: readDartType() as FunctionType,
- interfaceTargetReference: readNonNullInstanceMemberReference())
+ kind, receiver, name, arguments,
+ functionType: functionType is FunctionType ? functionType : null,
+ interfaceTargetReference: interfaceTargetReference)
..fileOffset = offset
..flags = flags;
}
diff --git a/pkg/kernel/lib/binary/ast_to_binary.dart b/pkg/kernel/lib/binary/ast_to_binary.dart
index 5b2eec7..c8c332e 100644
--- a/pkg/kernel/lib/binary/ast_to_binary.dart
+++ b/pkg/kernel/lib/binary/ast_to_binary.dart
@@ -1653,7 +1653,8 @@
writeNode(node.receiver);
writeName(node.name);
writeArgumentsNode(node.arguments);
- writeDartType(node.functionType);
+ // `const DynamicType()` is used to encode a missing function type.
+ writeDartType(node.functionType ?? const DynamicType());
writeNonNullInstanceMemberReference(node.interfaceTargetReference);
}
diff --git a/pkg/kernel/lib/clone.dart b/pkg/kernel/lib/clone.dart
index 930ff79..3f09922 100644
--- a/pkg/kernel/lib/clone.dart
+++ b/pkg/kernel/lib/clone.dart
@@ -695,7 +695,7 @@
TreeNode visitInstanceGetterInvocation(InstanceGetterInvocation node) {
return new InstanceGetterInvocation.byReference(
node.kind, clone(node.receiver), node.name, clone(node.arguments),
- functionType: visitType(node.functionType) as FunctionType,
+ functionType: visitOptionalType(node.functionType) as FunctionType,
interfaceTargetReference: node.interfaceTargetReference);
}
diff --git a/pkg/kernel/lib/text/ast_to_text.dart b/pkg/kernel/lib/text/ast_to_text.dart
index 9482f51..0718f76 100644
--- a/pkg/kernel/lib/text/ast_to_text.dart
+++ b/pkg/kernel/lib/text/ast_to_text.dart
@@ -1498,6 +1498,19 @@
writeSymbol('}');
}
+ visitInstanceGetterInvocation(InstanceGetterInvocation node) {
+ writeExpression(node.receiver, Precedence.PRIMARY);
+ writeSymbol('.');
+ writeInterfaceTarget(node.name, node.interfaceTargetReference);
+ _writeInstanceAccessKind(node.kind);
+ writeNode(node.arguments);
+ if (node.functionType != null) {
+ writeSymbol('{');
+ writeType(node.functionType!);
+ writeSymbol('}');
+ }
+ }
+
visitEqualsCall(EqualsCall node) {
int precedence = Precedence.EQUALITY;
writeExpression(node.left, precedence);
diff --git a/pkg/kernel/lib/text/text_serializer.dart b/pkg/kernel/lib/text/text_serializer.dart
index 0f936bf..86e8127 100644
--- a/pkg/kernel/lib/text/text_serializer.dart
+++ b/pkg/kernel/lib/text/text_serializer.dart
@@ -84,6 +84,8 @@
String visitSuperPropertySet(SuperPropertySet _) => "set-super";
String visitMethodInvocation(MethodInvocation _) => "invoke-method";
String visitInstanceInvocation(InstanceInvocation _) => "invoke-instance";
+ String visitInstanceGetterInvocation(InstanceGetterInvocation _) =>
+ "invoke-instance-getter";
String visitDynamicInvocation(DynamicInvocation _) => "invoke-dynamic";
String visitFunctionInvocation(FunctionInvocation _) => "invoke-function";
String visitLocalFunctionInvocation(LocalFunctionInvocation _) =>
@@ -656,6 +658,43 @@
functionType: tuple.sixth as FunctionType);
}
+TextSerializer<
+ InstanceGetterInvocation> instanceGetterInvocationSerializer = new Wrapped<
+ Tuple6<InstanceAccessKind, Expression, Name, Arguments, CanonicalName,
+ DartType?>,
+ InstanceGetterInvocation>(
+ unwrapInstanceGetterInvocation,
+ wrapInstanceGetterInvocation,
+ new Tuple6Serializer(
+ instanceAccessKindSerializer,
+ expressionSerializer,
+ nameSerializer,
+ argumentsSerializer,
+ const CanonicalNameSerializer(),
+ Optional(dartTypeSerializer)));
+
+Tuple6<InstanceAccessKind, Expression, Name, Arguments, CanonicalName,
+ DartType?>
+ unwrapInstanceGetterInvocation(InstanceGetterInvocation expression) {
+ return new Tuple6(
+ expression.kind,
+ expression.receiver,
+ expression.name,
+ expression.arguments,
+ expression.interfaceTargetReference.canonicalName!,
+ expression.functionType);
+}
+
+InstanceGetterInvocation wrapInstanceGetterInvocation(
+ Tuple6<InstanceAccessKind, Expression, Name, Arguments, CanonicalName,
+ DartType?>
+ tuple) {
+ return new InstanceGetterInvocation.byReference(
+ tuple.first, tuple.second, tuple.third, tuple.fourth,
+ interfaceTargetReference: tuple.fifth.reference,
+ functionType: tuple.sixth as FunctionType?);
+}
+
const Map<DynamicAccessKind, String> dynamicAccessKindToName = const {
DynamicAccessKind.Dynamic: "dynamic",
DynamicAccessKind.Never: "never",
@@ -2513,6 +2552,7 @@
"set-super": superPropertySetSerializer,
"invoke-method": methodInvocationSerializer,
"invoke-instance": instanceInvocationSerializer,
+ "invoke-instance-getter": instanceGetterInvocationSerializer,
"invoke-dynamic": dynamicInvocationSerializer,
"invoke-function": functionInvocationSerializer,
"invoke-local-function": localFunctionInvocationSerializer,