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 66de118a5f1f852fbd1541c1c8b157df5e5d7cba..5faf37545711d5ed2cb9da440701048008975739 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 |
@@ -44,6 +44,34 @@ import 'package:kernel/class_hierarchy.dart'; |
import 'package:kernel/core_types.dart'; |
import 'package:kernel/type_algebra.dart'; |
+bool isOverloadableArithmeticOperator(String name) { |
+ return identical(name, '+') || |
+ identical(name, '-') || |
+ identical(name, '*') || |
+ identical(name, '%'); |
+} |
+ |
+bool _isUserDefinableOperator(String name) { |
+ return identical(name, '<') || |
+ identical(name, '>') || |
+ identical(name, '<=') || |
+ identical(name, '>=') || |
+ identical(name, '==') || |
+ identical(name, '-') || |
+ identical(name, '+') || |
+ identical(name, '/') || |
+ identical(name, '~/') || |
+ identical(name, '*') || |
+ identical(name, '%') || |
+ identical(name, '|') || |
+ identical(name, '^') || |
+ identical(name, '&') || |
+ identical(name, '<<') || |
+ identical(name, '>>') || |
+ identical(name, '[]=') || |
+ identical(name, '~'); |
+} |
+ |
/// Keeps track of information about the innermost function or closure being |
/// inferred. |
class ClosureContext { |
@@ -621,6 +649,55 @@ abstract class TypeInferrerImpl extends TypeInferrer { |
return inferredType; |
} |
+ /// Performs the core type inference algorithm for method invocations (this |
+ /// handles both null-aware and non-null-aware method invocations). |
+ DartType inferMethodInvocation( |
+ Expression expression, |
+ Expression receiver, |
+ int fileOffset, |
+ MethodInvocation desugaredInvocation, |
+ bool isImplicitCall, |
+ DartType typeContext, |
+ bool typeNeeded, |
+ {VariableDeclaration receiverVariable}) { |
+ typeNeeded = |
+ listener.methodInvocationEnter(expression, typeContext) || typeNeeded; |
+ // First infer the receiver so we can look up the method that was invoked. |
+ var receiverType = inferExpression(receiver, null, true); |
+ receiverVariable?.type = receiverType; |
+ bool isOverloadedArithmeticOperator = false; |
+ Member interfaceMember = |
+ findMethodInvocationMember(receiverType, desugaredInvocation); |
+ if (interfaceMember is Procedure) { |
+ isOverloadedArithmeticOperator = typeSchemaEnvironment |
+ .isOverloadedArithmeticOperatorAndType(interfaceMember, receiverType); |
+ } |
+ var calleeType = getCalleeFunctionType(interfaceMember, receiverType, |
+ desugaredInvocation.name, !isImplicitCall); |
+ bool forceArgumentInference = false; |
+ if (isDryRun) { |
+ if (_isUserDefinableOperator(desugaredInvocation.name.name)) { |
+ // If this is an overloadable arithmetic operator, then type inference |
+ // might depend on the RHS, so conservatively assume it does. |
+ forceArgumentInference = |
+ isOverloadableArithmeticOperator(desugaredInvocation.name.name); |
+ } else { |
+ // If no type arguments were given, then type inference might depend on |
+ // the arguments (because the called method might be generic), so |
+ // conservatively assume it does. |
+ forceArgumentInference = |
+ getExplicitTypeArguments(desugaredInvocation.arguments) == null; |
+ } |
+ } |
+ var inferredType = inferInvocation(typeContext, typeNeeded, fileOffset, |
+ calleeType, calleeType.returnType, desugaredInvocation.arguments, |
+ isOverloadedArithmeticOperator: isOverloadedArithmeticOperator, |
+ receiverType: receiverType, |
+ forceArgumentInference: forceArgumentInference); |
+ listener.methodInvocationExit(expression, inferredType); |
+ return inferredType; |
+ } |
+ |
@override |
void inferParameterInitializer( |
Expression initializer, DartType declaredType) { |