Chromium Code Reviews| Index: pkg/front_end/lib/src/fasta/kernel/kernel_shadow_ast.dart |
| diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_shadow_ast.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_shadow_ast.dart |
| index b710245161a05ca95e924aae65464d626e015126..b97f7fb8f26a3439db248b2769de1f9d6088fa26 100644 |
| --- a/pkg/front_end/lib/src/fasta/kernel/kernel_shadow_ast.dart |
| +++ b/pkg/front_end/lib/src/fasta/kernel/kernel_shadow_ast.dart |
| @@ -232,13 +232,37 @@ class KernelCascadeExpression extends Let implements KernelExpression { |
| } |
| } |
| +/// Concrete shadow object representing a complex assignment in kernel form. |
|
ahe
2017/06/08 14:16:33
What is a complex assignment?
Paul Berry
2017/06/08 16:17:04
I'm still figuring out exactly where to draw the l
|
| +class KernelComplexAssign extends Let implements KernelExpression { |
| + KernelComplexAssign(VariableDeclaration variable, Expression body) |
| + : super(variable, body); |
| + |
| + @override |
| + void _collectDependencies(KernelDependencyCollector collector) { |
| + // Assignment expressions are not immediately evident expressions. |
| + collector.recordNotImmediatelyEvident(fileOffset); |
| + } |
| + |
| + @override |
| + DartType _inferExpression( |
| + KernelTypeInferrer inferrer, DartType typeContext, bool typeNeeded) { |
| + return inferrer.inferIndexAssign(this, typeContext, typeNeeded); |
| + } |
| +} |
| + |
| /// Concrete shadow object representing a conditional expression in kernel form. |
| /// Shadow object for [ConditionalExpression]. |
| class KernelConditionalExpression extends ConditionalExpression |
| implements KernelExpression { |
| + /// Indicates whether this conditional expression is associated with a `??=` |
| + /// in a null-aware compound assignment. |
| + final bool _isNullAwareCombiner; |
| + |
| KernelConditionalExpression( |
| - Expression condition, Expression then, Expression otherwise) |
| - : super(condition, then, otherwise, const DynamicType()); |
| + Expression condition, Expression then, Expression otherwise, |
| + {bool isNullAwareCombiner: false}) |
| + : _isNullAwareCombiner = isNullAwareCombiner, |
| + super(condition, then, otherwise, const DynamicType()); |
| @override |
| void _collectDependencies(KernelDependencyCollector collector) { |
| @@ -268,6 +292,11 @@ class KernelConditionalExpression extends ConditionalExpression |
| inferrer.listener.conditionalExpressionExit(this, inferredType); |
| return inferredType; |
| } |
| + |
| + /// Helper method allowing [_isNullAwareCombiner] to be checked from outside |
| + /// this library without adding a public member to the class. |
| + static bool isNullAwareCombiner(KernelConditionalExpression e) => |
| + e._isNullAwareCombiner; |
| } |
| /// Shadow object for [ConstructorInvocation]. |
| @@ -1038,9 +1067,16 @@ class KernelMethodInvocation extends MethodInvocation |
| /// resulting from the invocation of a function expression. |
| final bool _isImplicitCall; |
| + /// Indicates whether this method invocation invokes the operator that |
| + /// combines old and new values in a compound assignment. |
| + final bool _isCombiner; |
| + |
| KernelMethodInvocation(Expression receiver, Name name, Arguments arguments, |
| - {bool isImplicitCall: false, Procedure interfaceTarget}) |
| + {bool isImplicitCall: false, |
| + Procedure interfaceTarget, |
| + bool isCombiner: false}) |
| : _isImplicitCall = isImplicitCall, |
| + _isCombiner = isCombiner, |
| super(receiver, name, arguments, interfaceTarget); |
| @override |
| @@ -1053,34 +1089,19 @@ class KernelMethodInvocation extends MethodInvocation |
| @override |
| DartType _inferExpression( |
| KernelTypeInferrer inferrer, DartType typeContext, bool typeNeeded) { |
| + if (identical(name.name, '[]=')) { |
| + return inferrer.inferIndexAssign(this, typeContext, typeNeeded); |
| + } |
| typeNeeded = inferrer.listener.methodInvocationEnter(this, typeContext) || |
| typeNeeded; |
| // First infer the receiver so we can look up the method that was invoked. |
| var receiverType = inferrer.inferExpression(receiver, null, true); |
| bool isOverloadedArithmeticOperator = false; |
| - Member interfaceMember; |
| - if (receiverType is InterfaceType) { |
| - interfaceMember = inferrer.classHierarchy |
| - .getInterfaceMember(receiverType.classNode, name); |
| - // Our non-strong golden files currently don't include interface |
| - // targets, so we can't store the interface target without causing tests |
| - // to fail. TODO(paulberry): fix this. |
| - if (inferrer.strongMode) { |
| - if (interfaceMember != null) { |
| - inferrer.instrumentation?.record(Uri.parse(inferrer.uri), fileOffset, |
| - 'target', new InstrumentationValueForMember(interfaceMember)); |
| - } |
| - // interfaceTarget is currently required to be a procedure, so we skip |
| - // if it's anything else. TODO(paulberry): fix this - see |
| - // https://codereview.chromium.org/2923653003/. |
| - if (interfaceMember is Procedure) { |
| - interfaceTarget = interfaceMember; |
| - } |
| - } |
| - if (interfaceMember is Procedure) { |
| - isOverloadedArithmeticOperator = inferrer.typeSchemaEnvironment |
| - .isOverloadedArithmeticOperator(interfaceMember); |
| - } |
| + Member interfaceMember = |
| + inferrer.findMethodInvocationMember(receiverType, this); |
| + if (interfaceMember is Procedure) { |
| + isOverloadedArithmeticOperator = inferrer.typeSchemaEnvironment |
| + .isOverloadedArithmeticOperator(interfaceMember); |
| } |
| var calleeType = inferrer.getCalleeFunctionType( |
| interfaceMember, receiverType, name, !_isImplicitCall); |
| @@ -1091,6 +1112,10 @@ class KernelMethodInvocation extends MethodInvocation |
| inferrer.listener.methodInvocationExit(this, inferredType); |
| return inferredType; |
| } |
| + |
| + /// Helper method allowing [_isCombiner] to be checked from outside this |
| + /// library without adding a public member to the class. |
| + static bool isCombiner(KernelMethodInvocation e) => e._isCombiner; |
| } |
| /// Shadow object for [Not]. |
| @@ -1163,27 +1188,17 @@ class KernelPropertyGet extends PropertyGet implements KernelExpression { |
| inferrer.listener.propertyGetEnter(this, typeContext) || typeNeeded; |
| // First infer the receiver so we can look up the getter that was invoked. |
| var receiverType = inferrer.inferExpression(receiver, null, true); |
| - Member interfaceMember; |
| - if (receiverType is InterfaceType) { |
| - interfaceMember = inferrer.classHierarchy |
| - .getInterfaceMember(receiverType.classNode, name); |
| - if (inferrer.isTopLevel && |
| - ((interfaceMember is Procedure && |
| - interfaceMember.kind == ProcedureKind.Getter) || |
| - interfaceMember is Field)) { |
| - // References to fields and getters can't be relied upon for top level |
| - // inference. |
| - inferrer.recordNotImmediatelyEvident(fileOffset); |
| - } |
| - // Our non-strong golden files currently don't include interface targets, |
| - // so we can't store the interface target without causing tests to fail. |
| - // TODO(paulberry): fix this. |
| - if (inferrer.strongMode) { |
| - inferrer.instrumentation?.record(Uri.parse(inferrer.uri), fileOffset, |
| - 'target', new InstrumentationValueForMember(interfaceMember)); |
| - interfaceTarget = interfaceMember; |
| - } |
| + Member interfaceMember = |
| + inferrer.findInterfaceMember(receiverType, name, fileOffset); |
| + if (inferrer.isTopLevel && |
| + ((interfaceMember is Procedure && |
| + interfaceMember.kind == ProcedureKind.Getter) || |
| + interfaceMember is Field)) { |
| + // References to fields and getters can't be relied upon for top level |
| + // inference. |
| + inferrer.recordNotImmediatelyEvident(fileOffset); |
| } |
| + interfaceTarget = interfaceMember; |
| var inferredType = |
| inferrer.getCalleeType(interfaceMember, receiverType, name); |
| // TODO(paulberry): Infer tear-off type arguments if appropriate. |
| @@ -1215,19 +1230,9 @@ class KernelPropertySet extends PropertySet implements KernelExpression { |
| inferrer.listener.propertySetEnter(this, typeContext) || typeNeeded; |
| // First infer the receiver so we can look up the setter that was invoked. |
| var receiverType = inferrer.inferExpression(receiver, null, true); |
| - Member interfaceMember; |
| - if (receiverType is InterfaceType) { |
| - interfaceMember = inferrer.classHierarchy |
| - .getInterfaceMember(receiverType.classNode, name, setter: true); |
| - // Our non-strong golden files currently don't include interface targets, |
| - // so we can't store the interface target without causing tests to fail. |
| - // TODO(paulberry): fix this. |
| - if (inferrer.strongMode) { |
| - inferrer.instrumentation?.record(Uri.parse(inferrer.uri), fileOffset, |
| - 'target', new InstrumentationValueForMember(interfaceMember)); |
| - interfaceTarget = interfaceMember; |
| - } |
| - } |
| + Member interfaceMember = inferrer |
| + .findInterfaceMember(receiverType, name, fileOffset, setter: true); |
| + interfaceTarget = interfaceMember; |
| var setterType = inferrer.getSetterType(interfaceMember, receiverType); |
| var inferredType = inferrer.inferExpression(value, setterType, typeNeeded); |
| inferrer.listener.propertySetExit(this, inferredType); |
| @@ -1797,6 +1802,10 @@ class KernelVariableDeclaration extends VariableDeclaration |
| final bool _isLocalFunction; |
| + /// Indicates whether this variable declaration exists for the sole purpose of |
| + /// discarding a return value in a complex desugared expression. |
| + final bool _isDiscarding; |
|
ahe
2017/06/08 14:16:33
It would be easier for for me to understand the me
Paul Berry
2017/06/08 16:17:04
I'm open to changing this, but I think "voidContex
|
| + |
| KernelVariableDeclaration(String name, this._functionNestingLevel, |
| {Expression initializer, |
| DartType type, |
| @@ -1805,6 +1814,7 @@ class KernelVariableDeclaration extends VariableDeclaration |
| bool isLocalFunction: false}) |
| : _implicitlyTyped = type == null, |
| _isLocalFunction = isLocalFunction, |
| + _isDiscarding = false, |
| super(name, |
| initializer: initializer, |
| type: type ?? const DynamicType(), |
| @@ -1812,9 +1822,11 @@ class KernelVariableDeclaration extends VariableDeclaration |
| isConst: isConst); |
| KernelVariableDeclaration.forValue( |
| - Expression initializer, this._functionNestingLevel) |
| + Expression initializer, this._functionNestingLevel, |
| + {bool isDiscarding: false}) |
| : _implicitlyTyped = true, |
| _isLocalFunction = false, |
| + _isDiscarding = isDiscarding, |
| super.forValue(initializer); |
| @override |
| @@ -1833,6 +1845,11 @@ class KernelVariableDeclaration extends VariableDeclaration |
| inferrer.listener.variableDeclarationExit(this); |
| } |
| + /// Helper method allowing [_isDiscarding] to be checked from outside this |
| + /// library without adding a public member to the class. |
| + static bool isDiscarding(VariableDeclaration v) => |
| + v is KernelVariableDeclaration && v._isDiscarding; |
| + |
| /// Determine whether the given [KernelVariableDeclaration] had an implicit |
| /// type. |
| /// |