| Index: pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
|
| 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 ad1dc41bf01b76302e11d9ede58eb08958bfef3a..4e7db482776d8a7cc4fe9680529eb45e1f4414ed 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
|
| @@ -39,6 +39,7 @@ import 'package:kernel/ast.dart'
|
| SuperMethodInvocation,
|
| SuperPropertyGet,
|
| SuperPropertySet,
|
| + ThisExpression,
|
| TypeParameter,
|
| TypeParameterType,
|
| VariableDeclaration,
|
| @@ -869,24 +870,49 @@ abstract class TypeInferrerImpl extends TypeInferrer {
|
| if (interfaceMember is Procedure) {
|
| isOverloadedArithmeticOperator = typeSchemaEnvironment
|
| .isOverloadedArithmeticOperatorAndType(interfaceMember, receiverType);
|
| - if (instrumentation != null) {
|
| + }
|
| + if (instrumentation != null) {
|
| + int offset = arguments.fileOffset == -1
|
| + ? expression.fileOffset
|
| + : arguments.fileOffset;
|
| + if (receiver is ThisExpression) {
|
| + // Calls to `this` are always typed.
|
| + } else if (interfaceMember == null &&
|
| + !(receiverType is FunctionType && methodName.name == 'call')) {
|
| + // Dynamic invocation
|
| + instrumentation.record(Uri.parse(uri), offset, 'checkCall',
|
| + new InstrumentationValueLiteral('dynamic'));
|
| + } else {
|
| var semiTypedArguments = <String>[];
|
| - var function = interfaceMember.function;
|
| - var positionalParameters = function.positionalParameters;
|
| - for (int i = 0; i < positionalParameters.length; i++) {
|
| - if (_isFormalSemiSafe(positionalParameters[i])) {
|
| - semiTypedArguments.add(i.toString());
|
| + var function = interfaceMember?.function;
|
| + int i = 0;
|
| + _forEachArgument(arguments, (name, expression) {
|
| + bool isSemiTyped;
|
| + if (function == null) {
|
| + // Invocation of a function-typed object; everything is semi-typed.
|
| + isSemiTyped = true;
|
| + } else {
|
| + var formal = name != null
|
| + ? _getNamedFormal(function, name)
|
| + : _getPositionalFormal(function, i);
|
| + if (formal != null) {
|
| + isSemiTyped = _isFormalSemiSafe(formal);
|
| + } else {
|
| + // No matching formal parameter. An error should have already been
|
| + // reported, so the code won't compile. Thus, it doesn't really
|
| + // matter how we annotate the parameter.
|
| + isSemiTyped = false;
|
| + }
|
| }
|
| - }
|
| - for (var formal in function.namedParameters) {
|
| - if (_isFormalSemiSafe(formal)) {
|
| - semiTypedArguments.add(formal.name);
|
| + if (isSemiTyped) {
|
| + semiTypedArguments.add(name ?? i.toString());
|
| }
|
| - }
|
| + if (name == null) i++;
|
| + });
|
| if (semiTypedArguments.isNotEmpty) {
|
| instrumentation.record(
|
| Uri.parse(uri),
|
| - arguments.fileOffset,
|
| + offset,
|
| 'checkCall',
|
| new InstrumentationValueLiteral(
|
| 'interface(semiTyped:${semiTypedArguments.join(',')})'));
|
| @@ -1083,6 +1109,25 @@ abstract class TypeInferrerImpl extends TypeInferrer {
|
| }
|
| }
|
|
|
| + /// Given a [FunctionNode], gets the named parameter identified by [name], or
|
| + /// `null` if there is no parameter with the given name.
|
| + VariableDeclaration _getNamedFormal(FunctionNode function, String name) {
|
| + for (var formal in function.namedParameters) {
|
| + if (formal.name == name) return formal;
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + /// Given a [FunctionNode], gets the [i]th positional formal parameter, or
|
| + /// `null` if there is no parameter with that index.
|
| + VariableDeclaration _getPositionalFormal(FunctionNode function, int i) {
|
| + if (i < function.positionalParameters.length) {
|
| + return function.positionalParameters[i];
|
| + } else {
|
| + return null;
|
| + }
|
| + }
|
| +
|
| /// Determines if the given formal parameter is semi-safe.
|
| ///
|
| /// Eventually this information will be stored in the kernel representation,
|
|
|