Index: pkg/front_end/lib/src/fasta/kernel/frontend_accessors.dart |
diff --git a/pkg/front_end/lib/src/fasta/kernel/frontend_accessors.dart b/pkg/front_end/lib/src/fasta/kernel/frontend_accessors.dart |
index a0bfd3aa2919139f66b16d4c9abfe965b0c12d10..5c93f1db71adb6eb86b15ea45a634d680075cab0 100644 |
--- a/pkg/front_end/lib/src/fasta/kernel/frontend_accessors.dart |
+++ b/pkg/front_end/lib/src/fasta/kernel/frontend_accessors.dart |
@@ -8,7 +8,7 @@ |
import 'package:front_end/src/fasta/kernel/kernel_shadow_ast.dart' |
show |
KernelArguments, |
- KernelComplexAssign, |
+ KernelComplexAssignment, |
KernelConditionalExpression, |
KernelMethodInvocation, |
KernelPropertyGet, |
@@ -50,7 +50,7 @@ abstract class Accessor { |
/// Builds an [Expression] representing a read from the accessor. |
Expression buildSimpleRead() { |
- return _finish(_makeSimpleRead()); |
+ return _finish(_makeSimpleRead(), null); |
} |
/// Builds an [Expression] representing an assignment with the accessor on |
@@ -59,7 +59,9 @@ abstract class Accessor { |
/// The returned expression evaluates to the assigned value, unless |
/// [voidContext] is true, in which case it may evaluate to anything. |
Expression buildAssignment(Expression value, {bool voidContext: false}) { |
- return _finish(_makeSimpleWrite(value, voidContext)); |
+ var complexAssignment = startComplexAssignment(value); |
+ return _finish(_makeSimpleWrite(value, voidContext, complexAssignment), |
+ complexAssignment); |
} |
/// Returns an [Expression] representing a null-aware assignment (`??=`) with |
@@ -71,17 +73,22 @@ abstract class Accessor { |
/// [type] is the static type of the RHS. |
Expression buildNullAwareAssignment(Expression value, DartType type, |
{bool voidContext: false}) { |
+ var complexAssignment = startComplexAssignment(value); |
if (voidContext) { |
- return _finish(new KernelConditionalExpression( |
- buildIsNull(_makeRead()), _makeWrite(value, false), new NullLiteral(), |
- isNullAwareCombiner: true)); |
+ var nullAwareCombiner = new KernelConditionalExpression( |
+ buildIsNull(_makeRead(complexAssignment)), |
+ _makeWrite(value, false, complexAssignment), |
+ new NullLiteral()); |
+ complexAssignment?.nullAwareCombiner = nullAwareCombiner; |
+ return _finish(nullAwareCombiner, complexAssignment); |
} |
- var tmp = new VariableDeclaration.forValue(_makeRead()); |
- return _finish(makeLet( |
- tmp, |
- new KernelConditionalExpression(buildIsNull(new VariableGet(tmp)), |
- _makeWrite(value, false), new VariableGet(tmp), |
- isNullAwareCombiner: true))); |
+ var tmp = new VariableDeclaration.forValue(_makeRead(complexAssignment)); |
+ var nullAwareCombiner = new KernelConditionalExpression( |
+ buildIsNull(new VariableGet(tmp)), |
+ _makeWrite(value, false, complexAssignment), |
+ new VariableGet(tmp)); |
+ complexAssignment?.nullAwareCombiner = nullAwareCombiner; |
+ return _finish(makeLet(tmp, nullAwareCombiner), complexAssignment); |
} |
/// Returns an [Expression] representing a compound assignment (e.g. `+=`) |
@@ -90,10 +97,13 @@ abstract class Accessor { |
{int offset: TreeNode.noOffset, |
bool voidContext: false, |
Procedure interfaceTarget}) { |
- return _finish(_makeWrite( |
- makeBinary(_makeRead(), binaryOperator, interfaceTarget, value, |
- offset: offset, isCombiner: true), |
- voidContext)); |
+ var complexAssignment = startComplexAssignment(value); |
+ var combiner = makeBinary( |
+ _makeRead(complexAssignment), binaryOperator, interfaceTarget, value, |
+ offset: offset); |
+ complexAssignment?.combiner = combiner; |
+ return _finish(_makeWrite(combiner, voidContext, complexAssignment), |
+ complexAssignment); |
} |
/// Returns an [Expression] representing a pre-increment or pre-decrement |
@@ -118,30 +128,37 @@ abstract class Accessor { |
return buildPrefixIncrement(binaryOperator, |
offset: offset, voidContext: true, interfaceTarget: interfaceTarget); |
} |
- var value = new VariableDeclaration.forValue(_makeRead()); |
+ var rhs = new IntLiteral(1); |
+ var complexAssignment = startComplexAssignment(rhs); |
+ var value = new VariableDeclaration.forValue(_makeRead(complexAssignment)); |
valueAccess() => new VariableGet(value); |
+ var combiner = makeBinary( |
+ valueAccess(), binaryOperator, interfaceTarget, rhs, |
+ offset: offset); |
+ complexAssignment?.combiner = combiner; |
+ complexAssignment?.isPostIncDec = true; |
var dummy = new KernelVariableDeclaration.forValue( |
- _makeWrite( |
- makeBinary(valueAccess(), binaryOperator, interfaceTarget, |
- new IntLiteral(1), |
- offset: offset, isCombiner: true), |
- true), |
- helper.functionNestingLevel, |
- isDiscarding: true); |
- return _finish(makeLet(value, makeLet(dummy, valueAccess()))); |
+ _makeWrite(combiner, true, complexAssignment), |
+ helper.functionNestingLevel); |
+ return _finish( |
+ makeLet(value, makeLet(dummy, valueAccess())), complexAssignment); |
} |
- Expression _makeSimpleRead() => _makeRead(); |
+ Expression _makeSimpleRead() => _makeRead(null); |
- Expression _makeSimpleWrite(Expression value, bool voidContext) { |
- return _makeWrite(value, voidContext); |
+ Expression _makeSimpleWrite(Expression value, bool voidContext, |
+ KernelComplexAssignment complexAssignment) { |
+ return _makeWrite(value, voidContext, complexAssignment); |
} |
- Expression _makeRead(); |
+ Expression _makeRead(KernelComplexAssignment complexAssignment); |
- Expression _makeWrite(Expression value, bool voidContext); |
+ Expression _makeWrite(Expression value, bool voidContext, |
+ KernelComplexAssignment complexAssignment); |
- Expression _finish(Expression body) => body; |
+ Expression _finish( |
+ Expression body, KernelComplexAssignment complexAssignment) => |
+ body; |
/// Returns an [Expression] representing a compile-time error. |
/// |
@@ -159,6 +176,11 @@ abstract class Accessor { |
return internalError( |
"Unhandled compile-time error.", null, offsetForToken(token)); |
} |
+ |
+ /// Creates a data structure for tracking the desugaring of a complex |
+ /// assignment expression whose right hand side is [rhs], if necessary, or |
+ /// returns `null` if not necessary. |
+ KernelComplexAssignment startComplexAssignment(Expression rhs) => null; |
} |
abstract class VariableAccessor extends Accessor { |
@@ -169,7 +191,7 @@ abstract class VariableAccessor extends Accessor { |
BuilderHelper helper, this.variable, this.promotedType, Token token) |
: super(helper, token); |
- Expression _makeRead() { |
+ Expression _makeRead(KernelComplexAssignment complexAssignment) { |
var fact = helper.typePromoter |
.getFactForAccess(variable, helper.functionNestingLevel); |
var scope = helper.typePromoter.currentScope; |
@@ -177,7 +199,8 @@ abstract class VariableAccessor extends Accessor { |
..fileOffset = offsetForToken(token); |
} |
- Expression _makeWrite(Expression value, bool voidContext) { |
+ Expression _makeWrite(Expression value, bool voidContext, |
+ KernelComplexAssignment complexAssignment) { |
helper.typePromoter.mutateVariable(variable, helper.functionNestingLevel); |
return variable.isFinal || variable.isConst |
? makeInvalidWrite(value) |
@@ -210,7 +233,8 @@ class PropertyAccessor extends Accessor { |
Expression _makeSimpleRead() => new KernelPropertyGet(receiver, name, getter) |
..fileOffset = offsetForToken(token); |
- Expression _makeSimpleWrite(Expression value, bool voidContext) { |
+ Expression _makeSimpleWrite(Expression value, bool voidContext, |
+ KernelComplexAssignment complexAssignment) { |
return new KernelPropertySet(receiver, name, value, setter) |
..fileOffset = offsetForToken(token); |
} |
@@ -221,16 +245,19 @@ class PropertyAccessor extends Accessor { |
..fileOffset = offsetForToken(token); |
} |
- Expression _makeRead() => |
+ Expression _makeRead(KernelComplexAssignment complexAssignment) => |
new KernelPropertyGet(receiverAccess(), name, getter) |
..fileOffset = offsetForToken(token); |
- Expression _makeWrite(Expression value, bool voidContext) { |
+ Expression _makeWrite(Expression value, bool voidContext, |
+ KernelComplexAssignment complexAssignment) { |
return new KernelPropertySet(receiverAccess(), name, value, setter) |
..fileOffset = offsetForToken(token); |
} |
- Expression _finish(Expression body) => makeLet(_receiverVariable, body); |
+ Expression _finish( |
+ Expression body, KernelComplexAssignment complexAssignment) => |
+ makeLet(_receiverVariable, body); |
} |
/// Special case of [PropertyAccessor] to avoid creating an indirect access to |
@@ -243,11 +270,12 @@ class ThisPropertyAccessor extends Accessor { |
BuilderHelper helper, this.name, this.getter, this.setter, Token token) |
: super(helper, token); |
- Expression _makeRead() => |
+ Expression _makeRead(KernelComplexAssignment complexAssignment) => |
new KernelPropertyGet(new ThisExpression(), name, getter) |
..fileOffset = offsetForToken(token); |
- Expression _makeWrite(Expression value, bool voidContext) { |
+ Expression _makeWrite(Expression value, bool voidContext, |
+ KernelComplexAssignment complexAssignment) { |
return new KernelPropertySet(new ThisExpression(), name, value, setter) |
..fileOffset = offsetForToken(token); |
} |
@@ -266,17 +294,20 @@ class NullAwarePropertyAccessor extends Accessor { |
receiverAccess() => new VariableGet(receiver); |
- Expression _makeRead() => |
+ Expression _makeRead(KernelComplexAssignment complexAssignment) => |
new KernelPropertyGet(receiverAccess(), name, getter); |
- Expression _makeWrite(Expression value, bool voidContext) { |
+ Expression _makeWrite(Expression value, bool voidContext, |
+ KernelComplexAssignment complexAssignment) { |
return new KernelPropertySet(receiverAccess(), name, value, setter); |
} |
- Expression _finish(Expression body) => makeLet( |
- receiver, |
- new KernelConditionalExpression( |
- buildIsNull(receiverAccess()), new NullLiteral(), body)); |
+ Expression _finish( |
+ Expression body, KernelComplexAssignment complexAssignment) => |
+ makeLet( |
+ receiver, |
+ new KernelConditionalExpression( |
+ buildIsNull(receiverAccess()), new NullLiteral(), body)); |
} |
class SuperPropertyAccessor extends Accessor { |
@@ -287,14 +318,15 @@ class SuperPropertyAccessor extends Accessor { |
BuilderHelper helper, this.name, this.getter, this.setter, Token token) |
: super(helper, token); |
- Expression _makeRead() { |
+ Expression _makeRead(KernelComplexAssignment complexAssignment) { |
if (getter == null) return makeInvalidRead(); |
// TODO(ahe): Use [DirectPropertyGet] when possible. |
return new SuperPropertyGet(name, getter) |
..fileOffset = offsetForToken(token); |
} |
- Expression _makeWrite(Expression value, bool voidContext) { |
+ Expression _makeWrite(Expression value, bool voidContext, |
+ KernelComplexAssignment complexAssignment) { |
if (setter == null) return makeInvalidWrite(value); |
// TODO(ahe): Use [DirectPropertySet] when possible. |
return new SuperPropertySet(name, value, setter) |
@@ -324,17 +356,23 @@ class IndexAccessor extends Accessor { |
this.getter, this.setter, Token token) |
: super(helper, token); |
- Expression _makeSimpleRead() => new KernelMethodInvocation( |
- receiver, indexGetName, new KernelArguments(<Expression>[index]), |
- interfaceTarget: getter) |
- ..fileOffset = offsetForToken(token); |
+ Expression _makeSimpleRead() { |
+ var read = new KernelMethodInvocation( |
+ receiver, indexGetName, new KernelArguments(<Expression>[index]), |
+ interfaceTarget: getter) |
+ ..fileOffset = offsetForToken(token); |
+ return read; |
+ } |
- Expression _makeSimpleWrite(Expression value, bool voidContext) { |
- if (!voidContext) return _makeWriteAndReturn(value); |
- return new KernelMethodInvocation( |
+ Expression _makeSimpleWrite(Expression value, bool voidContext, |
+ KernelComplexAssignment complexAssignment) { |
+ if (!voidContext) return _makeWriteAndReturn(value, complexAssignment); |
+ var write = new KernelMethodInvocation( |
receiver, indexSetName, new KernelArguments(<Expression>[index, value]), |
interfaceTarget: setter) |
..fileOffset = offsetForToken(token); |
+ complexAssignment?.write = write; |
+ return write; |
} |
receiverAccess() { |
@@ -350,48 +388,56 @@ class IndexAccessor extends Accessor { |
return new VariableGet(indexVariable)..fileOffset = offsetForToken(token); |
} |
- Expression _makeRead() { |
- return new KernelMethodInvocation(receiverAccess(), indexGetName, |
+ Expression _makeRead(KernelComplexAssignment complexAssignment) { |
+ var read = new KernelMethodInvocation(receiverAccess(), indexGetName, |
new KernelArguments(<Expression>[indexAccess()]), |
interfaceTarget: getter) |
..fileOffset = offsetForToken(token); |
+ complexAssignment?.read = read; |
+ return read; |
} |
- Expression _makeWrite(Expression value, bool voidContext) { |
- if (!voidContext) return _makeWriteAndReturn(value); |
- return new KernelMethodInvocation(receiverAccess(), indexSetName, |
+ Expression _makeWrite(Expression value, bool voidContext, |
+ KernelComplexAssignment complexAssignment) { |
+ if (!voidContext) return _makeWriteAndReturn(value, complexAssignment); |
+ var write = new KernelMethodInvocation(receiverAccess(), indexSetName, |
new KernelArguments(<Expression>[indexAccess(), value]), |
interfaceTarget: setter) |
..fileOffset = offsetForToken(token); |
+ complexAssignment?.write = write; |
+ return write; |
} |
// TODO(dmitryas): remove this method after the "[]=" operator of the Context |
// class is made to return a value. |
- _makeWriteAndReturn(Expression value) { |
+ _makeWriteAndReturn( |
+ Expression value, KernelComplexAssignment complexAssignment) { |
// The call to []= does not return the value like direct-style assignments |
// do. We need to bind the value in a let. |
var valueVariable = new VariableDeclaration.forValue(value); |
+ var write = new KernelMethodInvocation( |
+ receiverAccess(), |
+ indexSetName, |
+ new KernelArguments( |
+ <Expression>[indexAccess(), new VariableGet(valueVariable)]), |
+ interfaceTarget: setter) |
+ ..fileOffset = offsetForToken(token); |
+ complexAssignment?.write = write; |
var dummy = new KernelVariableDeclaration.forValue( |
- new KernelMethodInvocation( |
- receiverAccess(), |
- indexSetName, |
- new KernelArguments( |
- <Expression>[indexAccess(), new VariableGet(valueVariable)]), |
- interfaceTarget: setter) |
- ..fileOffset = offsetForToken(token), |
- helper.functionNestingLevel, |
- isDiscarding: true); |
+ write, helper.functionNestingLevel); |
return makeLet( |
valueVariable, makeLet(dummy, new VariableGet(valueVariable))); |
} |
- Expression _finish(Expression body) { |
- if (receiverVariable == null) { |
- assert(indexVariable == null); |
- return body; |
+ Expression _finish( |
+ Expression body, KernelComplexAssignment complexAssignment) { |
+ Expression desugared = |
+ makeLet(receiverVariable, makeLet(indexVariable, body)); |
+ if (complexAssignment != null) { |
+ complexAssignment.desugared = desugared; |
+ return complexAssignment; |
} else { |
- return new KernelComplexAssign( |
- receiverVariable, makeLet(indexVariable, body)); |
+ return desugared; |
} |
} |
} |
@@ -413,7 +459,8 @@ class ThisIndexAccessor extends Accessor { |
interfaceTarget: getter); |
} |
- Expression _makeSimpleWrite(Expression value, bool voidContext) { |
+ Expression _makeSimpleWrite(Expression value, bool voidContext, |
+ KernelComplexAssignment complexAssignment) { |
if (!voidContext) return _makeWriteAndReturn(value); |
return new KernelMethodInvocation(new ThisExpression(), indexSetName, |
new KernelArguments(<Expression>[index, value]), |
@@ -425,11 +472,13 @@ class ThisIndexAccessor extends Accessor { |
return new VariableGet(indexVariable); |
} |
- Expression _makeRead() => new KernelMethodInvocation(new ThisExpression(), |
- indexGetName, new KernelArguments(<Expression>[indexAccess()]), |
- interfaceTarget: getter); |
+ Expression _makeRead(KernelComplexAssignment complexAssignment) => |
+ new KernelMethodInvocation(new ThisExpression(), indexGetName, |
+ new KernelArguments(<Expression>[indexAccess()]), |
+ interfaceTarget: getter); |
- Expression _makeWrite(Expression value, bool voidContext) { |
+ Expression _makeWrite(Expression value, bool voidContext, |
+ KernelComplexAssignment complexAssignment) { |
if (!voidContext) return _makeWriteAndReturn(value); |
return new KernelMethodInvocation(new ThisExpression(), indexSetName, |
new KernelArguments(<Expression>[indexAccess(), value]), |
@@ -448,7 +497,9 @@ class ThisIndexAccessor extends Accessor { |
valueVariable, makeLet(dummy, new VariableGet(valueVariable))); |
} |
- Expression _finish(Expression body) => makeLet(indexVariable, body); |
+ Expression _finish( |
+ Expression body, KernelComplexAssignment complexAssignment) => |
+ makeLet(indexVariable, body); |
} |
class SuperIndexAccessor extends Accessor { |
@@ -468,18 +519,20 @@ class SuperIndexAccessor extends Accessor { |
Expression _makeSimpleRead() => new SuperMethodInvocation( |
indexGetName, new KernelArguments(<Expression>[index]), getter); |
- Expression _makeSimpleWrite(Expression value, bool voidContext) { |
+ Expression _makeSimpleWrite(Expression value, bool voidContext, |
+ KernelComplexAssignment complexAssignment) { |
if (!voidContext) return _makeWriteAndReturn(value); |
return new SuperMethodInvocation( |
indexSetName, new KernelArguments(<Expression>[index, value]), setter); |
} |
- Expression _makeRead() { |
+ Expression _makeRead(KernelComplexAssignment complexAssignment) { |
return new SuperMethodInvocation( |
indexGetName, new KernelArguments(<Expression>[indexAccess()]), getter); |
} |
- Expression _makeWrite(Expression value, bool voidContext) { |
+ Expression _makeWrite(Expression value, bool voidContext, |
+ KernelComplexAssignment complexAssignment) { |
if (!voidContext) return _makeWriteAndReturn(value); |
return new SuperMethodInvocation(indexSetName, |
new KernelArguments(<Expression>[indexAccess(), value]), setter); |
@@ -496,7 +549,8 @@ class SuperIndexAccessor extends Accessor { |
valueVariable, makeLet(dummy, new VariableGet(valueVariable))); |
} |
- Expression _finish(Expression body) { |
+ Expression _finish( |
+ Expression body, KernelComplexAssignment complexAssignment) { |
return makeLet(indexVariable, body); |
} |
} |
@@ -509,11 +563,13 @@ class StaticAccessor extends Accessor { |
BuilderHelper helper, this.readTarget, this.writeTarget, Token token) |
: super(helper, token); |
- Expression _makeRead() => readTarget == null |
- ? makeInvalidRead() |
- : helper.makeStaticGet(readTarget, token); |
+ Expression _makeRead(KernelComplexAssignment complexAssignment) => |
+ readTarget == null |
+ ? makeInvalidRead() |
+ : helper.makeStaticGet(readTarget, token); |
- Expression _makeWrite(Expression value, bool voidContext) { |
+ Expression _makeWrite(Expression value, bool voidContext, |
+ KernelComplexAssignment complexAssignment) { |
return writeTarget == null |
? makeInvalidWrite(value) |
: new StaticSet(writeTarget, value) |
@@ -530,15 +586,18 @@ class ReadOnlyAccessor extends Accessor { |
Expression _makeSimpleRead() => expression; |
- Expression _makeRead() { |
+ Expression _makeRead(KernelComplexAssignment complexAssignment) { |
value ??= new VariableDeclaration.forValue(expression); |
return new VariableGet(value); |
} |
- Expression _makeWrite(Expression value, bool voidContext) => |
+ Expression _makeWrite(Expression value, bool voidContext, |
+ KernelComplexAssignment complexAssignment) => |
makeInvalidWrite(value); |
- Expression _finish(Expression body) => makeLet(value, body); |
+ Expression _finish( |
+ Expression body, KernelComplexAssignment complexAssignment) => |
+ makeLet(value, body); |
} |
Expression makeLet(VariableDeclaration variable, Expression body) { |
@@ -548,10 +607,10 @@ Expression makeLet(VariableDeclaration variable, Expression body) { |
Expression makeBinary( |
Expression left, Name operator, Procedure interfaceTarget, Expression right, |
- {int offset: TreeNode.noOffset, bool isCombiner: false}) { |
+ {int offset: TreeNode.noOffset}) { |
return new KernelMethodInvocation( |
left, operator, new KernelArguments(<Expression>[right]), |
- interfaceTarget: interfaceTarget, isCombiner: isCombiner) |
+ interfaceTarget: interfaceTarget) |
..fileOffset = offset; |
} |