Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(278)

Unified Diff: pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart

Issue 2927013004: Rework type inference of assignments to index expressions. (Closed)
Patch Set: Created 3 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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,

Powered by Google App Engine
This is Rietveld 408576698