Index: pkg/kernel/lib/frontend/accessors.dart |
diff --git a/pkg/kernel/lib/frontend/accessors.dart b/pkg/kernel/lib/frontend/accessors.dart |
index 66822127d7b9aab5eb696780e7b4f98d125e8748..449d74e8215398ae4b820127eeed4d2114242e3c 100644 |
--- a/pkg/kernel/lib/frontend/accessors.dart |
+++ b/pkg/kernel/lib/frontend/accessors.dart |
@@ -8,7 +8,25 @@ library kernel.frontend.accessors; |
import '../ast.dart'; |
+final Name indexGetName = new Name("[]"); |
+ |
+final Name indexSetName = new Name("[]="); |
+ |
+/// An [Accessor] represents a subexpression for which we can't yet build a |
+/// kernel [Expression] because we don't yet know the context in which it is |
+/// used. |
+/// |
+/// Once the context is known, an [Accessor] can be converted into an |
+/// [Expression] by calling a "build" method. |
+/// |
+/// For example, when building a kernel representation for `a[x] = b`, after |
+/// parsing `a[x]` but before parsing `= b`, we don't yet know whether to |
+/// generate an invocation of `operator[]` or `operator[]=`, so we generate an |
+/// [Accessor] object. Later, after `= b` is parsed, [buildAssignment] will be |
+/// called. |
abstract class Accessor { |
+ final int offset; |
+ |
// [builtBinary] and [builtGetter] capture the inner nodes. Used by |
// dart2js+rasta for determining how subexpressions map to legacy dart2js Ast |
// nodes. This will be removed once dart2js type analysis (aka inference) is |
@@ -16,11 +34,15 @@ abstract class Accessor { |
Expression builtBinary; |
Expression builtGetter; |
+ Accessor(this.offset); |
+ |
+ /// Builds an [Expression] representing a read from the accessor. |
Expression buildSimpleRead() { |
return _finish(_makeSimpleRead()); |
} |
- /// Returns an assignment to the accessor. |
+ /// Builds an [Expression] representing an assignment with the accessor on |
+ /// the LHS and [value] on the RHS. |
/// |
/// The returned expression evaluates to the assigned value, unless |
/// [voidContext] is true, in which case it may evaluate to anything. |
@@ -28,6 +50,13 @@ abstract class Accessor { |
return _finish(_makeSimpleWrite(value, voidContext)); |
} |
+ /// Returns an [Expression] representing a null-aware assignment (`??=`) with |
+ /// the accessor on the LHS and [value] on the RHS. |
+ /// |
+ /// The returned expression evaluates to the assigned value, unless |
+ /// [voidContext] is true, in which case it may evaluate to anything. |
+ /// |
+ /// [type] is the static type of the RHS. |
Expression buildNullAwareAssignment(Expression value, DartType type, |
{bool voidContext: false}) { |
if (voidContext) { |
@@ -41,6 +70,8 @@ abstract class Accessor { |
_makeWrite(value, false), new VariableGet(tmp), type))); |
} |
+ /// Returns an [Expression] representing a compound assignment (e.g. `+=`) |
+ /// with the accessor on the LHS and [value] on the RHS. |
Expression buildCompoundAssignment(Name binaryOperator, Expression value, |
{int offset: TreeNode.noOffset, |
bool voidContext: false, |
@@ -52,6 +83,8 @@ abstract class Accessor { |
voidContext)); |
} |
+ /// Returns an [Expression] representing a pre-increment or pre-decrement |
+ /// of the accessor. |
Expression buildPrefixIncrement(Name binaryOperator, |
{int offset: TreeNode.noOffset, |
bool voidContext: false, |
@@ -62,6 +95,8 @@ abstract class Accessor { |
interfaceTarget: interfaceTarget); |
} |
+ /// Returns an [Expression] representing a post-increment or post-decrement |
+ /// of the accessor. |
Expression buildPostfixIncrement(Name binaryOperator, |
{int offset: TreeNode.noOffset, |
bool voidContext: false, |
@@ -92,8 +127,15 @@ abstract class Accessor { |
Expression _finish(Expression body) => body; |
+ /// Returns an [Expression] representing a compile-time error. |
+ /// |
+ /// At runtime, an exception will be thrown. |
makeInvalidRead() => new InvalidExpression(); |
+ /// Returns an [Expression] representing a compile-time error wrapping |
+ /// [value]. |
+ /// |
+ /// At runtime, [value] will be evaluated before throwing an exception. |
makeInvalidWrite(Expression value) => wrapInvalid(value); |
} |
@@ -101,14 +143,15 @@ class VariableAccessor extends Accessor { |
VariableDeclaration variable; |
DartType promotedType; |
- VariableAccessor(this.variable, [this.promotedType]); |
+ VariableAccessor(this.variable, this.promotedType, int offset) |
+ : super(offset); |
- _makeRead() => new VariableGet(variable, promotedType); |
+ _makeRead() => new VariableGet(variable, promotedType)..fileOffset = offset; |
_makeWrite(Expression value, bool voidContext) { |
return variable.isFinal || variable.isConst |
? makeInvalidWrite(value) |
- : new VariableSet(variable, value); |
+ : new VariableSet(variable, value)..fileOffset = offset; |
} |
} |
@@ -119,31 +162,38 @@ class PropertyAccessor extends Accessor { |
Member getter, setter; |
static Accessor make( |
- Expression receiver, Name name, Member getter, Member setter) { |
+ Expression receiver, Name name, Member getter, Member setter, |
+ {int offset: TreeNode.noOffset}) { |
if (receiver is ThisExpression) { |
- return new ThisPropertyAccessor(name, getter, setter); |
+ return new ThisPropertyAccessor(name, getter, setter, offset); |
} else { |
- return new PropertyAccessor._internal(receiver, name, getter, setter); |
+ return new PropertyAccessor.internal( |
+ receiver, name, getter, setter, offset); |
} |
} |
- PropertyAccessor._internal( |
- this.receiver, this.name, this.getter, this.setter); |
+ PropertyAccessor.internal( |
+ this.receiver, this.name, this.getter, this.setter, int offset) |
+ : super(offset); |
+ |
+ _makeSimpleRead() => |
+ new PropertyGet(receiver, name, getter)..fileOffset = offset; |
- _makeSimpleRead() => new PropertyGet(receiver, name, getter); |
_makeSimpleWrite(Expression value, bool voidContext) { |
- return new PropertySet(receiver, name, value, setter); |
+ return new PropertySet(receiver, name, value, setter)..fileOffset = offset; |
} |
receiverAccess() { |
_receiverVariable ??= new VariableDeclaration.forValue(receiver); |
- return new VariableGet(_receiverVariable); |
+ return new VariableGet(_receiverVariable)..fileOffset = offset; |
} |
- _makeRead() => builtGetter = new PropertyGet(receiverAccess(), name, getter); |
+ _makeRead() => builtGetter = new PropertyGet(receiverAccess(), name, getter) |
+ ..fileOffset = offset; |
_makeWrite(Expression value, bool voidContext) { |
- return new PropertySet(receiverAccess(), name, value, setter); |
+ return new PropertySet(receiverAccess(), name, value, setter) |
+ ..fileOffset = offset; |
} |
_finish(Expression body) => makeLet(_receiverVariable, body); |
@@ -155,13 +205,15 @@ class ThisPropertyAccessor extends Accessor { |
Name name; |
Member getter, setter; |
- ThisPropertyAccessor(this.name, this.getter, this.setter); |
+ ThisPropertyAccessor(this.name, this.getter, this.setter, int offset) |
+ : super(offset); |
- _makeRead() => |
- builtGetter = new PropertyGet(new ThisExpression(), name, getter); |
+ _makeRead() => builtGetter = |
+ new PropertyGet(new ThisExpression(), name, getter)..fileOffset = offset; |
_makeWrite(Expression value, bool voidContext) { |
- return new PropertySet(new ThisExpression(), name, value, setter); |
+ return new PropertySet(new ThisExpression(), name, value, setter) |
+ ..fileOffset = offset; |
} |
} |
@@ -171,9 +223,10 @@ class NullAwarePropertyAccessor extends Accessor { |
Member getter, setter; |
DartType type; |
- NullAwarePropertyAccessor( |
- Expression receiver, this.name, this.getter, this.setter, this.type) |
- : this.receiver = makeOrReuseVariable(receiver); |
+ NullAwarePropertyAccessor(Expression receiver, this.name, this.getter, |
+ this.setter, this.type, int offset) |
+ : this.receiver = makeOrReuseVariable(receiver), |
+ super(offset); |
receiverAccess() => new VariableGet(receiver); |
@@ -193,18 +246,23 @@ class SuperPropertyAccessor extends Accessor { |
Name name; |
Member getter, setter; |
- SuperPropertyAccessor(this.name, this.getter, this.setter); |
+ SuperPropertyAccessor(this.name, this.getter, this.setter, int offset) |
+ : super(offset); |
- _makeRead() => builtGetter = new SuperPropertyGet(name, getter); |
+ _makeRead() { |
+ if (getter == null) return makeInvalidRead(); |
+ // TODO(ahe): Use [DirectPropertyGet] when possible. |
+ return builtGetter = new SuperPropertyGet(name, getter) |
+ ..fileOffset = offset; |
+ } |
_makeWrite(Expression value, bool voidContext) { |
- return new SuperPropertySet(name, value, setter); |
+ if (setter == null) return makeInvalidWrite(value); |
+ // TODO(ahe): Use [DirectPropertySet] when possible. |
+ return new SuperPropertySet(name, value, setter)..fileOffset = offset; |
} |
} |
-final Name _indexGet = new Name('[]'); |
-final Name _indexSet = new Name('[]='); |
- |
class IndexAccessor extends Accessor { |
Expression receiver; |
Expression index; |
@@ -212,47 +270,58 @@ class IndexAccessor extends Accessor { |
VariableDeclaration indexVariable; |
Procedure getter, setter; |
- static Accessor make(Expression receiver, Expression index, Procedure getter, |
- Procedure setter) { |
+ static Accessor make( |
+ Expression receiver, Expression index, Procedure getter, Procedure setter, |
+ {int offset: TreeNode.noOffset}) { |
if (receiver is ThisExpression) { |
- return new ThisIndexAccessor(index, getter, setter); |
+ return new ThisIndexAccessor(index, getter, setter, offset); |
} else { |
- return new IndexAccessor._internal(receiver, index, getter, setter); |
+ return new IndexAccessor.internal( |
+ receiver, index, getter, setter, offset); |
} |
} |
- IndexAccessor._internal(this.receiver, this.index, this.getter, this.setter); |
+ IndexAccessor.internal( |
+ this.receiver, this.index, this.getter, this.setter, int offset) |
+ : super(offset); |
_makeSimpleRead() => new MethodInvocation( |
- receiver, _indexGet, new Arguments(<Expression>[index]), getter); |
+ receiver, indexGetName, new Arguments(<Expression>[index]), getter) |
+ ..fileOffset = offset; |
_makeSimpleWrite(Expression value, bool voidContext) { |
if (!voidContext) return _makeWriteAndReturn(value); |
- return new MethodInvocation( |
- receiver, _indexSet, new Arguments(<Expression>[index, value]), setter); |
+ return new MethodInvocation(receiver, indexSetName, |
+ new Arguments(<Expression>[index, value]), setter)..fileOffset = offset; |
} |
receiverAccess() { |
// We cannot reuse the receiver if it is a variable since it might be |
// reassigned in the index expression. |
receiverVariable ??= new VariableDeclaration.forValue(receiver); |
- return new VariableGet(receiverVariable); |
+ return new VariableGet(receiverVariable)..fileOffset = offset; |
} |
indexAccess() { |
indexVariable ??= new VariableDeclaration.forValue(index); |
- return new VariableGet(indexVariable); |
+ return new VariableGet(indexVariable)..fileOffset = offset; |
} |
_makeRead() { |
- return builtGetter = new MethodInvocation(receiverAccess(), _indexGet, |
- new Arguments(<Expression>[indexAccess()]), getter); |
+ return builtGetter = new MethodInvocation( |
+ receiverAccess(), |
+ indexGetName, |
+ new Arguments(<Expression>[indexAccess()]), |
+ getter)..fileOffset = offset; |
} |
_makeWrite(Expression value, bool voidContext) { |
if (!voidContext) return _makeWriteAndReturn(value); |
- return new MethodInvocation(receiverAccess(), _indexSet, |
- new Arguments(<Expression>[indexAccess(), value]), setter); |
+ return new MethodInvocation( |
+ receiverAccess(), |
+ indexSetName, |
+ new Arguments(<Expression>[indexAccess(), value]), |
+ setter)..fileOffset = offset; |
} |
_makeWriteAndReturn(Expression value) { |
@@ -261,10 +330,10 @@ class IndexAccessor extends Accessor { |
var valueVariable = new VariableDeclaration.forValue(value); |
var dummy = new VariableDeclaration.forValue(new MethodInvocation( |
receiverAccess(), |
- _indexSet, |
+ indexSetName, |
new Arguments( |
<Expression>[indexAccess(), new VariableGet(valueVariable)]), |
- setter)); |
+ setter)..fileOffset = offset); |
return makeLet( |
valueVariable, makeLet(dummy, new VariableGet(valueVariable))); |
} |
@@ -281,16 +350,17 @@ class ThisIndexAccessor extends Accessor { |
VariableDeclaration indexVariable; |
Procedure getter, setter; |
- ThisIndexAccessor(this.index, this.getter, this.setter); |
+ ThisIndexAccessor(this.index, this.getter, this.setter, int offset) |
+ : super(offset); |
_makeSimpleRead() { |
- return new MethodInvocation(new ThisExpression(), _indexGet, |
+ return new MethodInvocation(new ThisExpression(), indexGetName, |
new Arguments(<Expression>[index]), getter); |
} |
_makeSimpleWrite(Expression value, bool voidContext) { |
if (!voidContext) return _makeWriteAndReturn(value); |
- return new MethodInvocation(new ThisExpression(), _indexSet, |
+ return new MethodInvocation(new ThisExpression(), indexSetName, |
new Arguments(<Expression>[index, value]), setter); |
} |
@@ -300,11 +370,11 @@ class ThisIndexAccessor extends Accessor { |
} |
_makeRead() => builtGetter = new MethodInvocation(new ThisExpression(), |
- _indexGet, new Arguments(<Expression>[indexAccess()]), getter); |
+ indexGetName, new Arguments(<Expression>[indexAccess()]), getter); |
_makeWrite(Expression value, bool voidContext) { |
if (!voidContext) return _makeWriteAndReturn(value); |
- return new MethodInvocation(new ThisExpression(), _indexSet, |
+ return new MethodInvocation(new ThisExpression(), indexSetName, |
new Arguments(<Expression>[indexAccess(), value]), setter); |
} |
@@ -312,7 +382,7 @@ class ThisIndexAccessor extends Accessor { |
var valueVariable = new VariableDeclaration.forValue(value); |
var dummy = new VariableDeclaration.forValue(new MethodInvocation( |
new ThisExpression(), |
- _indexSet, |
+ indexSetName, |
new Arguments( |
<Expression>[indexAccess(), new VariableGet(valueVariable)]), |
setter)); |
@@ -328,7 +398,8 @@ class SuperIndexAccessor extends Accessor { |
VariableDeclaration indexVariable; |
Member getter, setter; |
- SuperIndexAccessor(this.index, this.getter, this.setter); |
+ SuperIndexAccessor(this.index, this.getter, this.setter, int offset) |
+ : super(offset); |
indexAccess() { |
indexVariable ??= new VariableDeclaration.forValue(index); |
@@ -336,29 +407,29 @@ class SuperIndexAccessor extends Accessor { |
} |
_makeSimpleRead() => new SuperMethodInvocation( |
- _indexGet, new Arguments(<Expression>[index]), getter); |
+ indexGetName, new Arguments(<Expression>[index]), getter); |
_makeSimpleWrite(Expression value, bool voidContext) { |
if (!voidContext) return _makeWriteAndReturn(value); |
return new SuperMethodInvocation( |
- _indexSet, new Arguments(<Expression>[index, value]), setter); |
+ indexSetName, new Arguments(<Expression>[index, value]), setter); |
} |
_makeRead() { |
return builtGetter = new SuperMethodInvocation( |
- _indexGet, new Arguments(<Expression>[indexAccess()]), getter); |
+ indexGetName, new Arguments(<Expression>[indexAccess()]), getter); |
} |
_makeWrite(Expression value, bool voidContext) { |
if (!voidContext) return _makeWriteAndReturn(value); |
- return new SuperMethodInvocation( |
- _indexSet, new Arguments(<Expression>[indexAccess(), value]), setter); |
+ return new SuperMethodInvocation(indexSetName, |
+ new Arguments(<Expression>[indexAccess(), value]), setter); |
} |
_makeWriteAndReturn(Expression value) { |
var valueVariable = new VariableDeclaration.forValue(value); |
var dummy = new VariableDeclaration.forValue(new SuperMethodInvocation( |
- _indexSet, |
+ indexSetName, |
new Arguments( |
<Expression>[indexAccess(), new VariableGet(valueVariable)]), |
setter)); |
@@ -375,15 +446,16 @@ class StaticAccessor extends Accessor { |
Member readTarget; |
Member writeTarget; |
- StaticAccessor(this.readTarget, this.writeTarget); |
+ StaticAccessor(this.readTarget, this.writeTarget, int offset) : super(offset); |
- _makeRead() => builtGetter = |
- readTarget == null ? makeInvalidRead() : new StaticGet(readTarget); |
+ _makeRead() => builtGetter = readTarget == null |
+ ? makeInvalidRead() |
+ : new StaticGet(readTarget)..fileOffset = offset; |
_makeWrite(Expression value, bool voidContext) { |
return writeTarget == null |
? makeInvalidWrite(value) |
- : new StaticSet(writeTarget, value); |
+ : new StaticSet(writeTarget, value)..fileOffset = offset; |
} |
} |
@@ -391,7 +463,7 @@ class ReadOnlyAccessor extends Accessor { |
Expression expression; |
VariableDeclaration value; |
- ReadOnlyAccessor(this.expression); |
+ ReadOnlyAccessor(this.expression, int offset) : super(offset); |
_makeSimpleRead() => expression; |