| 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;
|
|
|
|
|