| 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 a380cc4faefff46f5e70de01b3ec881f85a3540c..63cf51c34f02a9b47cf6590698db3c8f63631fa8 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
|
| @@ -3,10 +3,8 @@
|
| // BSD-style license that can be found in the LICENSE.md file.
|
|
|
| import 'package:front_end/src/base/instrumentation.dart';
|
| -import 'package:front_end/src/fasta/errors.dart';
|
| import 'package:front_end/src/fasta/kernel/kernel_shadow_ast.dart';
|
| -import 'package:front_end/src/fasta/names.dart'
|
| - show callName, indexGetName, indexSetName;
|
| +import 'package:front_end/src/fasta/names.dart' show callName;
|
| import 'package:front_end/src/fasta/type_inference/type_inference_engine.dart';
|
| import 'package:front_end/src/fasta/type_inference/type_inference_listener.dart';
|
| import 'package:front_end/src/fasta/type_inference/type_promotion.dart';
|
| @@ -26,7 +24,6 @@ import 'package:kernel/ast.dart'
|
| FunctionType,
|
| Initializer,
|
| InterfaceType,
|
| - Let,
|
| Member,
|
| MethodInvocation,
|
| Name,
|
| @@ -34,8 +31,6 @@ import 'package:kernel/ast.dart'
|
| ProcedureKind,
|
| Statement,
|
| TypeParameterType,
|
| - VariableDeclaration,
|
| - VariableGet,
|
| VoidType;
|
| import 'package:kernel/class_hierarchy.dart';
|
| import 'package:kernel/core_types.dart';
|
| @@ -450,172 +445,6 @@ abstract class TypeInferrerImpl extends TypeInferrer {
|
| closureContext = null;
|
| }
|
|
|
| - /// Performs type inference for a (possibly compound) assignment whose LHS is
|
| - /// an index expression.
|
| - DartType inferIndexAssign(
|
| - Expression expression, DartType typeContext, bool typeNeeded) {
|
| - typeNeeded =
|
| - listener.indexAssignEnter(expression, typeContext) || typeNeeded;
|
| -
|
| - // Decompose an expression like `a[b] += c` into subexpressions and record
|
| - // the variables holding those subexpressions (if any):
|
| - // receiver: a
|
| - // index: b
|
| - // read: a[b]
|
| - // rhs: c
|
| - // value: a[b] + c
|
| - // write: a[b] = a[b] + c
|
| - Expression receiver;
|
| - VariableDeclaration receiverVariable;
|
| - Expression index;
|
| - VariableDeclaration indexVariable;
|
| - Expression read;
|
| - VariableDeclaration readVariable;
|
| - Expression rhs;
|
| - VariableDeclaration rhsVariable;
|
| - Expression value;
|
| - VariableDeclaration valueVariable;
|
| - MethodInvocation write;
|
| - KernelConditionalExpression nullAwareCombiner;
|
| - MethodInvocation combiner;
|
| - List<VariableDeclaration> syntheticVariables = [];
|
| - VariableGet finalValue;
|
| - bool isPostIncDec = false;
|
| -
|
| - // Dig in to the tree to find the expression with the main effect.
|
| - Expression e = expression;
|
| - while (true) {
|
| - if (e is Let) {
|
| - Let let = e;
|
| - var variable = let.variable;
|
| - syntheticVariables.add(variable);
|
| - if (KernelVariableDeclaration.isDiscarding(variable)) {
|
| - // This happens when we are dealing with a desugared expression for
|
| - // something like `var x = a[b] = c;`, which desugars to:
|
| - //
|
| - // var x =
|
| - // let v1 = a in
|
| - // let v2 = b in
|
| - // let v3 = c in
|
| - // let v4 = v1.[]=(v2, v3) in
|
| - // v3
|
| - //
|
| - // In this case `e` is `let v4 = v1.[]=(v2, v3) in v3`, so the
|
| - // expression with the main effect is found in the initializer.
|
| - //
|
| - // We know that the "let" body is always a VariableGet, since the only
|
| - // circumstance in which this sort of desugaring occurs is when the
|
| - // final value of the expression was computed in a previous "let".
|
| - assert(let.body is VariableGet);
|
| - finalValue = let.body;
|
| - e = variable.initializer;
|
| - } else {
|
| - e = let.body;
|
| - }
|
| - } else if (e is KernelConditionalExpression &&
|
| - KernelConditionalExpression.isNullAwareCombiner(e)) {
|
| - KernelConditionalExpression conditional = e;
|
| - nullAwareCombiner = conditional;
|
| - e = conditional.then;
|
| - } else {
|
| - break;
|
| - }
|
| - }
|
| -
|
| - Expression deref(Expression e, void callback(VariableDeclaration v)) {
|
| - if (e is VariableGet) {
|
| - var variable = e.variable;
|
| - if (syntheticVariables.contains(variable)) {
|
| - callback(variable);
|
| - return variable.initializer;
|
| - }
|
| - }
|
| - return e;
|
| - }
|
| -
|
| - if (e is KernelMethodInvocation && identical(e.name.name, '[]=')) {
|
| - write = e;
|
| - receiver = deref(e.receiver, (v) => receiverVariable = v);
|
| - index = deref(e.arguments.positional[0], (v) => indexVariable = v);
|
| - value = deref(e.arguments.positional[1], (v) => valueVariable = v);
|
| - if (value is KernelMethodInvocation &&
|
| - KernelMethodInvocation.isCombiner(value)) {
|
| - combiner = value;
|
| - read = deref(value.receiver, (v) => readVariable = v);
|
| - rhs = deref(value.arguments.positional[0], (v) => rhsVariable = v);
|
| - isPostIncDec =
|
| - finalValue is VariableGet && finalValue.variable == readVariable;
|
| - } else {
|
| - rhs = value;
|
| - if (nullAwareCombiner != null) {
|
| - MethodInvocation equalsNullCheck = nullAwareCombiner.condition;
|
| - read = deref(equalsNullCheck.receiver, (v) => readVariable = v);
|
| - }
|
| - }
|
| - } else {
|
| - internalError('Unexpected expression type: $e');
|
| - }
|
| -
|
| - var receiverType = inferExpression(receiver, null, true);
|
| - receiverVariable?.type = receiverType;
|
| - if (read != null) {
|
| - var readMember =
|
| - findMethodInvocationMember(receiverType, read, silent: true);
|
| - if (readVariable != null) {
|
| - var calleeType = getCalleeType(readMember, receiverType, indexGetName);
|
| - if (calleeType is FunctionType) {
|
| - readVariable.type = calleeType.returnType;
|
| - }
|
| - }
|
| - }
|
| - var writeMember = findMethodInvocationMember(receiverType, write);
|
| - // To replicate analyzer behavior, we base type inference on the write
|
| - // member. TODO(paulberry): would it be better to use the read member
|
| - // when doing compound assignment?
|
| - var calleeType = getCalleeType(writeMember, receiverType, indexSetName);
|
| - DartType indexContext;
|
| - DartType rhsContext;
|
| - DartType inferredType;
|
| - if (calleeType is FunctionType &&
|
| - calleeType.positionalParameters.length >= 2) {
|
| - // TODO(paulberry): we ought to get a context for the index expression
|
| - // from the index formal parameter, but analyzer doesn't so for now we
|
| - // replicate its behavior.
|
| - indexContext = null;
|
| - rhsContext = calleeType.positionalParameters[1];
|
| - if (combiner != null) {
|
| - var combinerMember =
|
| - findMethodInvocationMember(rhsContext, combiner, silent: true);
|
| - if (isPostIncDec) {
|
| - inferredType = rhsContext;
|
| - } else {
|
| - inferredType = getCalleeFunctionType(
|
| - combinerMember, rhsContext, combiner.name, false)
|
| - .returnType;
|
| - }
|
| - // Analyzer uses a null context for the RHS here.
|
| - // TODO(paulberry): improve on this.
|
| - rhsContext = null;
|
| - } else {
|
| - inferredType = rhsContext;
|
| - }
|
| - } else {
|
| - inferredType = const DynamicType();
|
| - }
|
| - var indexType = inferExpression(index, indexContext, true);
|
| - indexVariable?.type = indexType;
|
| - var rhsType = inferExpression(rhs, rhsContext, true);
|
| - rhsVariable?.type = rhsType;
|
| - valueVariable?.type = rhsContext ?? const DynamicType();
|
| - if (nullAwareCombiner != null) {
|
| - MethodInvocation equalsInvocation = nullAwareCombiner.condition;
|
| - findMethodInvocationMember(rhsContext, equalsInvocation);
|
| - nullAwareCombiner.staticType = inferredType;
|
| - }
|
| - listener.indexAssignExit(expression, inferredType);
|
| - return inferredType;
|
| - }
|
| -
|
| /// Performs the type inference steps that are shared by all kinds of
|
| /// invocations (constructors, instance methods, and static methods).
|
| DartType inferInvocation(DartType typeContext, bool typeNeeded, int offset,
|
|
|