blob: 799b0a2ca240c9f3f78dfd7d96a23a7ddcd41048 [file] [log] [blame]
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
library dart2js.resolution.send_structure;
import '../common.dart';
import '../constants/expressions.dart';
import '../elements/resolution_types.dart';
import '../elements/elements.dart';
import '../resolution/tree_elements.dart' show TreeElements;
import '../tree/tree.dart';
import '../universe/call_structure.dart' show CallStructure;
import '../universe/selector.dart' show Selector;
import 'access_semantics.dart';
import 'operators.dart';
import 'semantic_visitor.dart';
/// Interface for the structure of the semantics of a [Send] or [NewExpression]
/// node.
abstract class SemanticSendStructure<R, A> {
/// Calls the matching visit method on [visitor] with [node] and [arg].
R dispatch(SemanticSendVisitor<R, A> visitor, Node node, A arg);
}
enum SendStructureKind {
IF_NULL,
LOGICAL_AND,
LOGICAL_OR,
IS,
IS_NOT,
AS,
INVOKE,
INCOMPATIBLE_INVOKE,
GET,
SET,
NOT,
UNARY,
INVALID_UNARY,
INDEX,
EQUALS,
NOT_EQUALS,
BINARY,
INVALID_BINARY,
INDEX_SET,
INDEX_PREFIX,
INDEX_POSTFIX,
COMPOUND,
SET_IF_NULL,
COMPOUND_INDEX_SET,
INDEX_SET_IF_NULL,
PREFIX,
POSTFIX,
DEFERRED_PREFIX,
}
/// Interface for the structure of the semantics of a [Send] node.
///
/// Subclasses handle each of the [Send] variations; `assert(e)`, `a && b`,
/// `a.b`, `a.b(c)`, etc.
abstract class SendStructure<R, A> extends SemanticSendStructure<R, A> {
/// Calls the matching visit method on [visitor] with [send] and [arg].
R dispatch(SemanticSendVisitor<R, A> visitor, Send send, A arg);
SendStructureKind get kind;
}
/// The structure for a [Send] of the form `a ?? b`.
class IfNullStructure<R, A> implements SendStructure<R, A> {
const IfNullStructure();
R dispatch(SemanticSendVisitor<R, A> visitor, Send node, A arg) {
return visitor.visitIfNull(node, node.receiver, node.arguments.single, arg);
}
@override
SendStructureKind get kind => SendStructureKind.IF_NULL;
String toString() => '??';
}
/// The structure for a [Send] of the form `a && b`.
class LogicalAndStructure<R, A> implements SendStructure<R, A> {
const LogicalAndStructure();
R dispatch(SemanticSendVisitor<R, A> visitor, Send node, A arg) {
return visitor.visitLogicalAnd(
node, node.receiver, node.arguments.single, arg);
}
@override
SendStructureKind get kind => SendStructureKind.LOGICAL_AND;
String toString() => '&&';
}
/// The structure for a [Send] of the form `a || b`.
class LogicalOrStructure<R, A> implements SendStructure<R, A> {
const LogicalOrStructure();
R dispatch(SemanticSendVisitor<R, A> visitor, Send node, A arg) {
return visitor.visitLogicalOr(
node, node.receiver, node.arguments.single, arg);
}
@override
SendStructureKind get kind => SendStructureKind.LOGICAL_OR;
String toString() => '||';
}
/// The structure for a [Send] of the form `a is T`.
class IsStructure<R, A> implements SendStructure<R, A> {
/// The type that the expression is tested against.
final ResolutionDartType type;
IsStructure(this.type);
R dispatch(SemanticSendVisitor<R, A> visitor, Send node, A arg) {
return visitor.visitIs(node, node.receiver, type, arg);
}
@override
SendStructureKind get kind => SendStructureKind.IS;
String toString() => 'is $type';
}
/// The structure for a [Send] of the form `a is! T`.
class IsNotStructure<R, A> implements SendStructure<R, A> {
/// The type that the expression is tested against.
final ResolutionDartType type;
IsNotStructure(this.type);
R dispatch(SemanticSendVisitor<R, A> visitor, Send node, A arg) {
return visitor.visitIsNot(node, node.receiver, type, arg);
}
@override
SendStructureKind get kind => SendStructureKind.IS_NOT;
String toString() => 'is! $type';
}
/// The structure for a [Send] of the form `a as T`.
class AsStructure<R, A> implements SendStructure<R, A> {
/// The type that the expression is cast to.
final ResolutionDartType type;
AsStructure(this.type);
R dispatch(SemanticSendVisitor<R, A> visitor, Send node, A arg) {
return visitor.visitAs(node, node.receiver, type, arg);
}
@override
SendStructureKind get kind => SendStructureKind.AS;
String toString() => 'as $type';
}
/// The structure for a [Send] that is an invocation.
class InvokeStructure<R, A> implements SendStructure<R, A> {
/// The target of the invocation.
final AccessSemantics semantics;
/// The [Selector] for the invocation.
// TODO(johnniwinther): Store this only for dynamic invocations.
final Selector selector;
/// The [CallStructure] of the invocation.
// TODO(johnniwinther): Store this directly for static invocations.
CallStructure get callStructure => selector.callStructure;
InvokeStructure(this.semantics, this.selector);
@override
SendStructureKind get kind => SendStructureKind.INVOKE;
R dispatch(SemanticSendVisitor<R, A> visitor, Send node, A arg) {
switch (semantics.kind) {
case AccessKind.CONDITIONAL_DYNAMIC_PROPERTY:
return visitor.visitIfNotNullDynamicPropertyInvoke(
node, node.receiver, node.argumentsNode, selector, arg);
case AccessKind.DYNAMIC_PROPERTY:
return visitor.visitDynamicPropertyInvoke(
node, node.receiver, node.argumentsNode, selector, arg);
case AccessKind.LOCAL_FUNCTION:
return visitor.visitLocalFunctionInvoke(
node,
semantics.element,
node.argumentsNode,
// TODO(johnniwinther): Store the call selector instead of the
// selector using the name of the function.
callStructure,
arg);
case AccessKind.LOCAL_VARIABLE:
case AccessKind.FINAL_LOCAL_VARIABLE:
return visitor.visitLocalVariableInvoke(
node,
semantics.element,
node.argumentsNode,
// TODO(johnniwinther): Store the call selector instead of the
// selector using the name of the variable.
callStructure,
arg);
case AccessKind.PARAMETER:
case AccessKind.FINAL_PARAMETER:
return visitor.visitParameterInvoke(
node,
semantics.element,
node.argumentsNode,
// TODO(johnniwinther): Store the call selector instead of the
// selector using the name of the parameter.
callStructure,
arg);
case AccessKind.STATIC_FIELD:
case AccessKind.FINAL_STATIC_FIELD:
return visitor.visitStaticFieldInvoke(
node, semantics.element, node.argumentsNode, callStructure, arg);
case AccessKind.STATIC_METHOD:
return visitor.visitStaticFunctionInvoke(
node, semantics.element, node.argumentsNode, callStructure, arg);
case AccessKind.STATIC_GETTER:
return visitor.visitStaticGetterInvoke(
node, semantics.element, node.argumentsNode, callStructure, arg);
case AccessKind.STATIC_SETTER:
return visitor.visitStaticSetterInvoke(
node, semantics.element, node.argumentsNode, callStructure, arg);
case AccessKind.TOPLEVEL_FIELD:
case AccessKind.FINAL_TOPLEVEL_FIELD:
return visitor.visitTopLevelFieldInvoke(
node, semantics.element, node.argumentsNode, callStructure, arg);
case AccessKind.TOPLEVEL_METHOD:
return visitor.visitTopLevelFunctionInvoke(
node, semantics.element, node.argumentsNode, callStructure, arg);
case AccessKind.TOPLEVEL_GETTER:
return visitor.visitTopLevelGetterInvoke(
node, semantics.element, node.argumentsNode, callStructure, arg);
case AccessKind.TOPLEVEL_SETTER:
return visitor.visitTopLevelSetterInvoke(
node, semantics.element, node.argumentsNode, callStructure, arg);
case AccessKind.CLASS_TYPE_LITERAL:
return visitor.visitClassTypeLiteralInvoke(
node, semantics.constant, node.argumentsNode, callStructure, arg);
case AccessKind.TYPEDEF_TYPE_LITERAL:
return visitor.visitTypedefTypeLiteralInvoke(
node, semantics.constant, node.argumentsNode, callStructure, arg);
case AccessKind.DYNAMIC_TYPE_LITERAL:
return visitor.visitDynamicTypeLiteralInvoke(
node, semantics.constant, node.argumentsNode, callStructure, arg);
case AccessKind.TYPE_PARAMETER_TYPE_LITERAL:
return visitor.visitTypeVariableTypeLiteralInvoke(
node, semantics.element, node.argumentsNode, callStructure, arg);
case AccessKind.EXPRESSION:
return visitor.visitExpressionInvoke(
node, node.selector, node.argumentsNode, callStructure, arg);
case AccessKind.THIS:
return visitor.visitThisInvoke(
node, node.argumentsNode, callStructure, arg);
case AccessKind.THIS_PROPERTY:
return visitor.visitThisPropertyInvoke(
node, node.argumentsNode, selector, arg);
case AccessKind.SUPER_FIELD:
case AccessKind.SUPER_FINAL_FIELD:
return visitor.visitSuperFieldInvoke(
node, semantics.element, node.argumentsNode, callStructure, arg);
case AccessKind.SUPER_METHOD:
return visitor.visitSuperMethodInvoke(
node, semantics.element, node.argumentsNode, callStructure, arg);
case AccessKind.SUPER_GETTER:
return visitor.visitSuperGetterInvoke(
node, semantics.element, node.argumentsNode, callStructure, arg);
case AccessKind.SUPER_SETTER:
return visitor.visitSuperSetterInvoke(
node, semantics.element, node.argumentsNode, callStructure, arg);
case AccessKind.CONSTANT:
return visitor.visitConstantInvoke(
node, semantics.constant, node.argumentsNode, callStructure, arg);
case AccessKind.UNRESOLVED:
return visitor.visitUnresolvedInvoke(
node, semantics.element, node.argumentsNode, selector, arg);
case AccessKind.UNRESOLVED_SUPER:
return visitor.visitUnresolvedSuperInvoke(
node, semantics.element, node.argumentsNode, selector, arg);
case AccessKind.INVALID:
return visitor.errorInvalidInvoke(
node, semantics.element, node.argumentsNode, selector, arg);
case AccessKind.COMPOUND:
// This is not a valid case.
break;
}
throw new SpannableAssertionFailure(node, "Invalid invoke: ${semantics}");
}
String toString() => 'invoke($selector, $semantics)';
}
/// The structure for a [Send] that is an incompatible invocation, i.e. an
/// invocation of a known target where the call structure does not match.
class IncompatibleInvokeStructure<R, A> implements SendStructure<R, A> {
/// The target of the invocation.
final AccessSemantics semantics;
/// The [Selector] for the invocation.
// TODO(johnniwinther): Store this only for dynamic invocations.
final Selector selector;
/// The [CallStructure] of the invocation.
// TODO(johnniwinther): Store this directly for static invocations.
CallStructure get callStructure => selector.callStructure;
IncompatibleInvokeStructure(this.semantics, this.selector);
@override
SendStructureKind get kind => SendStructureKind.INCOMPATIBLE_INVOKE;
R dispatch(SemanticSendVisitor<R, A> visitor, Send node, A arg) {
switch (semantics.kind) {
case AccessKind.STATIC_METHOD:
return visitor.visitStaticFunctionIncompatibleInvoke(
node, semantics.element, node.argumentsNode, callStructure, arg);
case AccessKind.SUPER_METHOD:
return visitor.visitSuperMethodIncompatibleInvoke(
node, semantics.element, node.argumentsNode, callStructure, arg);
case AccessKind.TOPLEVEL_METHOD:
return visitor.visitTopLevelFunctionIncompatibleInvoke(
node, semantics.element, node.argumentsNode, callStructure, arg);
case AccessKind.LOCAL_FUNCTION:
return visitor.visitLocalFunctionIncompatibleInvoke(
node, semantics.element, node.argumentsNode, callStructure, arg);
default:
// TODO(johnniwinther): Support more variants of this invoke structure.
break;
}
throw new SpannableAssertionFailure(
node, "Invalid incompatible invoke: ${semantics}");
}
String toString() => 'incompatible-invoke($selector, $semantics)';
}
/// The structure for a [Send] that is a read access.
class GetStructure<R, A> implements SendStructure<R, A> {
/// The target of the read access.
final AccessSemantics semantics;
GetStructure(this.semantics);
@override
SendStructureKind get kind => SendStructureKind.GET;
R dispatch(SemanticSendVisitor<R, A> visitor, Send node, A arg) {
switch (semantics.kind) {
case AccessKind.CONDITIONAL_DYNAMIC_PROPERTY:
return visitor.visitIfNotNullDynamicPropertyGet(
node, node.receiver, semantics.name, arg);
case AccessKind.DYNAMIC_PROPERTY:
return visitor.visitDynamicPropertyGet(
node, node.receiver, semantics.name, arg);
case AccessKind.LOCAL_FUNCTION:
return visitor.visitLocalFunctionGet(node, semantics.element, arg);
case AccessKind.LOCAL_VARIABLE:
case AccessKind.FINAL_LOCAL_VARIABLE:
return visitor.visitLocalVariableGet(node, semantics.element, arg);
case AccessKind.PARAMETER:
case AccessKind.FINAL_PARAMETER:
return visitor.visitParameterGet(node, semantics.element, arg);
case AccessKind.STATIC_FIELD:
case AccessKind.FINAL_STATIC_FIELD:
return visitor.visitStaticFieldGet(node, semantics.element, arg);
case AccessKind.STATIC_METHOD:
return visitor.visitStaticFunctionGet(node, semantics.element, arg);
case AccessKind.STATIC_GETTER:
return visitor.visitStaticGetterGet(node, semantics.element, arg);
case AccessKind.STATIC_SETTER:
return visitor.visitStaticSetterGet(node, semantics.element, arg);
case AccessKind.TOPLEVEL_FIELD:
case AccessKind.FINAL_TOPLEVEL_FIELD:
return visitor.visitTopLevelFieldGet(node, semantics.element, arg);
case AccessKind.TOPLEVEL_METHOD:
return visitor.visitTopLevelFunctionGet(node, semantics.element, arg);
case AccessKind.TOPLEVEL_GETTER:
return visitor.visitTopLevelGetterGet(node, semantics.element, arg);
case AccessKind.TOPLEVEL_SETTER:
return visitor.visitTopLevelSetterGet(node, semantics.element, arg);
case AccessKind.CLASS_TYPE_LITERAL:
return visitor.visitClassTypeLiteralGet(node, semantics.constant, arg);
case AccessKind.TYPEDEF_TYPE_LITERAL:
return visitor.visitTypedefTypeLiteralGet(
node, semantics.constant, arg);
case AccessKind.DYNAMIC_TYPE_LITERAL:
return visitor.visitDynamicTypeLiteralGet(
node, semantics.constant, arg);
case AccessKind.TYPE_PARAMETER_TYPE_LITERAL:
return visitor.visitTypeVariableTypeLiteralGet(
node, semantics.element, arg);
case AccessKind.EXPRESSION:
// This is not a valid case.
break;
case AccessKind.THIS:
// TODO(johnniwinther): Handle this when `this` is a [Send].
break;
case AccessKind.THIS_PROPERTY:
return visitor.visitThisPropertyGet(node, semantics.name, arg);
case AccessKind.SUPER_FIELD:
case AccessKind.SUPER_FINAL_FIELD:
return visitor.visitSuperFieldGet(node, semantics.element, arg);
case AccessKind.SUPER_METHOD:
return visitor.visitSuperMethodGet(node, semantics.element, arg);
case AccessKind.SUPER_GETTER:
return visitor.visitSuperGetterGet(node, semantics.element, arg);
case AccessKind.SUPER_SETTER:
return visitor.visitSuperSetterGet(node, semantics.element, arg);
case AccessKind.CONSTANT:
return visitor.visitConstantGet(node, semantics.constant, arg);
case AccessKind.UNRESOLVED:
return visitor.visitUnresolvedGet(node, semantics.element, arg);
case AccessKind.UNRESOLVED_SUPER:
return visitor.visitUnresolvedSuperGet(node, semantics.element, arg);
case AccessKind.INVALID:
return visitor.errorInvalidGet(node, semantics.element, arg);
case AccessKind.COMPOUND:
// This is not a valid case.
break;
}
throw new SpannableAssertionFailure(node, "Invalid getter: ${semantics}");
}
String toString() => 'get($semantics)';
}
/// The structure for a [Send] that is an assignment.
class SetStructure<R, A> implements SendStructure<R, A> {
/// The target of the assignment.
final AccessSemantics semantics;
SetStructure(this.semantics);
@override
SendStructureKind get kind => SendStructureKind.SET;
R dispatch(SemanticSendVisitor<R, A> visitor, Send node, A arg) {
switch (semantics.kind) {
case AccessKind.CONDITIONAL_DYNAMIC_PROPERTY:
return visitor.visitIfNotNullDynamicPropertySet(
node, node.receiver, semantics.name, node.arguments.single, arg);
case AccessKind.DYNAMIC_PROPERTY:
return visitor.visitDynamicPropertySet(
node, node.receiver, semantics.name, node.arguments.single, arg);
case AccessKind.LOCAL_FUNCTION:
return visitor.visitLocalFunctionSet(
node, semantics.element, node.arguments.single, arg);
case AccessKind.LOCAL_VARIABLE:
return visitor.visitLocalVariableSet(
node, semantics.element, node.arguments.single, arg);
case AccessKind.FINAL_LOCAL_VARIABLE:
return visitor.visitFinalLocalVariableSet(
node, semantics.element, node.arguments.single, arg);
case AccessKind.PARAMETER:
return visitor.visitParameterSet(
node, semantics.element, node.arguments.single, arg);
case AccessKind.FINAL_PARAMETER:
return visitor.visitFinalParameterSet(
node, semantics.element, node.arguments.single, arg);
case AccessKind.STATIC_FIELD:
return visitor.visitStaticFieldSet(
node, semantics.element, node.arguments.single, arg);
case AccessKind.FINAL_STATIC_FIELD:
return visitor.visitFinalStaticFieldSet(
node, semantics.element, node.arguments.single, arg);
case AccessKind.STATIC_METHOD:
return visitor.visitStaticFunctionSet(
node, semantics.element, node.arguments.single, arg);
case AccessKind.STATIC_GETTER:
return visitor.visitStaticGetterSet(
node, semantics.element, node.arguments.single, arg);
case AccessKind.STATIC_SETTER:
return visitor.visitStaticSetterSet(
node, semantics.element, node.arguments.single, arg);
case AccessKind.TOPLEVEL_FIELD:
return visitor.visitTopLevelFieldSet(
node, semantics.element, node.arguments.single, arg);
case AccessKind.FINAL_TOPLEVEL_FIELD:
return visitor.visitFinalTopLevelFieldSet(
node, semantics.element, node.arguments.single, arg);
case AccessKind.TOPLEVEL_METHOD:
return visitor.visitTopLevelFunctionSet(
node, semantics.element, node.arguments.single, arg);
case AccessKind.TOPLEVEL_GETTER:
return visitor.visitTopLevelGetterSet(
node, semantics.element, node.arguments.single, arg);
case AccessKind.TOPLEVEL_SETTER:
return visitor.visitTopLevelSetterSet(
node, semantics.element, node.arguments.single, arg);
case AccessKind.CLASS_TYPE_LITERAL:
return visitor.visitClassTypeLiteralSet(
node, semantics.constant, node.arguments.single, arg);
case AccessKind.TYPEDEF_TYPE_LITERAL:
return visitor.visitTypedefTypeLiteralSet(
node, semantics.constant, node.arguments.single, arg);
case AccessKind.DYNAMIC_TYPE_LITERAL:
return visitor.visitDynamicTypeLiteralSet(
node, semantics.constant, node.arguments.single, arg);
case AccessKind.TYPE_PARAMETER_TYPE_LITERAL:
return visitor.visitTypeVariableTypeLiteralSet(
node, semantics.element, node.arguments.single, arg);
case AccessKind.EXPRESSION:
// This is not a valid case.
break;
case AccessKind.THIS:
// This is not a valid case.
break;
case AccessKind.THIS_PROPERTY:
return visitor.visitThisPropertySet(
node, semantics.name, node.arguments.single, arg);
case AccessKind.SUPER_FIELD:
return visitor.visitSuperFieldSet(
node, semantics.element, node.arguments.single, arg);
case AccessKind.SUPER_FINAL_FIELD:
return visitor.visitFinalSuperFieldSet(
node, semantics.element, node.arguments.single, arg);
case AccessKind.SUPER_METHOD:
return visitor.visitSuperMethodSet(
node, semantics.element, node.arguments.single, arg);
case AccessKind.SUPER_GETTER:
return visitor.visitSuperGetterSet(
node, semantics.element, node.arguments.single, arg);
case AccessKind.SUPER_SETTER:
return visitor.visitSuperSetterSet(
node, semantics.element, node.arguments.single, arg);
case AccessKind.CONSTANT:
// TODO(johnniwinther): Should this be a valid case?
break;
case AccessKind.UNRESOLVED_SUPER:
return visitor.visitUnresolvedSuperSet(
node, semantics.element, node.arguments.single, arg);
case AccessKind.UNRESOLVED:
return visitor.visitUnresolvedSet(
node, semantics.element, node.arguments.single, arg);
case AccessKind.INVALID:
return visitor.errorInvalidSet(
node, semantics.element, node.arguments.single, arg);
case AccessKind.COMPOUND:
// This is not a valid case.
break;
}
throw new SpannableAssertionFailure(node, "Invalid setter: ${semantics}");
}
String toString() => 'set($semantics)';
}
/// The structure for a [Send] that is a negation, i.e. of the form `!e`.
class NotStructure<R, A> implements SendStructure<R, A> {
const NotStructure();
R dispatch(SemanticSendVisitor<R, A> visitor, Send node, A arg) {
return visitor.visitNot(node, node.receiver, arg);
}
@override
SendStructureKind get kind => SendStructureKind.NOT;
String toString() => 'not()';
}
/// The structure for a [Send] that is an invocation of a user definable unary
/// operator.
class UnaryStructure<R, A> implements SendStructure<R, A> {
/// The target of the unary operation.
final AccessSemantics semantics;
/// The user definable unary operator.
final UnaryOperator operator;
UnaryStructure(this.semantics, this.operator);
@override
SendStructureKind get kind => SendStructureKind.UNARY;
R dispatch(SemanticSendVisitor<R, A> visitor, Send node, A arg) {
switch (semantics.kind) {
case AccessKind.EXPRESSION:
return visitor.visitUnary(node, operator, node.receiver, arg);
case AccessKind.SUPER_METHOD:
return visitor.visitSuperUnary(node, operator, semantics.element, arg);
case AccessKind.UNRESOLVED_SUPER:
return visitor.visitUnresolvedSuperUnary(
node, operator, semantics.element, arg);
case AccessKind.INVALID:
return visitor.errorInvalidUnary(
node, operator, semantics.element, arg);
default:
// This is not a valid case.
break;
}
throw new SpannableAssertionFailure(node, "Invalid setter: ${semantics}");
}
String toString() => 'unary($operator,$semantics)';
}
/// The structure for a [Send] that is an invocation of a undefined unary
/// operator.
class InvalidUnaryStructure<R, A> implements SendStructure<R, A> {
const InvalidUnaryStructure();
@override
R dispatch(SemanticSendVisitor<R, A> visitor, Send node, A arg) {
return visitor.errorUndefinedUnaryExpression(
node, node.selector, node.receiver, arg);
}
@override
SendStructureKind get kind => SendStructureKind.INVALID_UNARY;
String toString() => 'invalid unary';
}
/// The structure for a [Send] that is an index expression, i.e. of the form
/// `a[b]`.
class IndexStructure<R, A> implements SendStructure<R, A> {
/// The target of the left operand.
final AccessSemantics semantics;
IndexStructure(this.semantics);
@override
SendStructureKind get kind => SendStructureKind.INDEX;
R dispatch(SemanticSendVisitor<R, A> visitor, Send node, A arg) {
switch (semantics.kind) {
case AccessKind.EXPRESSION:
return visitor.visitIndex(
node, node.receiver, node.arguments.single, arg);
case AccessKind.SUPER_METHOD:
return visitor.visitSuperIndex(
node, semantics.element, node.arguments.single, arg);
case AccessKind.UNRESOLVED_SUPER:
return visitor.visitUnresolvedSuperIndex(
node, semantics.element, node.arguments.single, arg);
case AccessKind.INVALID:
return visitor.errorInvalidIndex(
node, semantics.element, node.arguments.single, arg);
default:
// This is not a valid case.
break;
}
throw new SpannableAssertionFailure(node, "Invalid index: ${semantics}");
}
}
/// The structure for a [Send] that is an equals test, i.e. of the form
/// `a == b`.
class EqualsStructure<R, A> implements SendStructure<R, A> {
/// The target of the left operand.
final AccessSemantics semantics;
EqualsStructure(this.semantics);
@override
SendStructureKind get kind => SendStructureKind.EQUALS;
R dispatch(SemanticSendVisitor<R, A> visitor, Send node, A arg) {
switch (semantics.kind) {
case AccessKind.EXPRESSION:
return visitor.visitEquals(
node, node.receiver, node.arguments.single, arg);
case AccessKind.SUPER_METHOD:
return visitor.visitSuperEquals(
node, semantics.element, node.arguments.single, arg);
case AccessKind.INVALID:
return visitor.errorInvalidEquals(
node, semantics.element, node.arguments.single, arg);
default:
// This is not a valid case.
break;
}
throw new SpannableAssertionFailure(node, "Invalid equals: ${semantics}");
}
String toString() => '==($semantics)';
}
/// The structure for a [Send] that is a not-equals test, i.e. of the form
/// `a != b`.
class NotEqualsStructure<R, A> implements SendStructure<R, A> {
/// The target of the left operand.
final AccessSemantics semantics;
NotEqualsStructure(this.semantics);
@override
SendStructureKind get kind => SendStructureKind.NOT_EQUALS;
R dispatch(SemanticSendVisitor<R, A> visitor, Send node, A arg) {
switch (semantics.kind) {
case AccessKind.EXPRESSION:
return visitor.visitNotEquals(
node, node.receiver, node.arguments.single, arg);
case AccessKind.SUPER_METHOD:
return visitor.visitSuperNotEquals(
node, semantics.element, node.arguments.single, arg);
case AccessKind.INVALID:
return visitor.errorInvalidNotEquals(
node, semantics.element, node.arguments.single, arg);
default:
// This is not a valid case.
break;
}
throw new SpannableAssertionFailure(
node, "Invalid not equals: ${semantics}");
}
String toString() => '!=($semantics)';
}
/// The structure for a [Send] that is an invocation of a user-definable binary
/// operator.
class BinaryStructure<R, A> implements SendStructure<R, A> {
/// The target of the left operand.
final AccessSemantics semantics;
/// The user definable binary operator.
final BinaryOperator operator;
BinaryStructure(this.semantics, this.operator);
@override
SendStructureKind get kind => SendStructureKind.BINARY;
R dispatch(SemanticSendVisitor<R, A> visitor, Send node, A arg) {
switch (semantics.kind) {
case AccessKind.EXPRESSION:
return visitor.visitBinary(
node, node.receiver, operator, node.arguments.single, arg);
case AccessKind.SUPER_METHOD:
return visitor.visitSuperBinary(
node, semantics.element, operator, node.arguments.single, arg);
case AccessKind.UNRESOLVED_SUPER:
return visitor.visitUnresolvedSuperBinary(
node, semantics.element, operator, node.arguments.single, arg);
case AccessKind.INVALID:
return visitor.errorInvalidBinary(
node, semantics.element, operator, node.arguments.single, arg);
default:
// This is not a valid case.
break;
}
throw new SpannableAssertionFailure(node, "Invalid binary: ${semantics}");
}
String toString() => 'binary($operator,$semantics)';
}
/// The structure for a [Send] that is an invocation of a undefined binary
/// operator.
class InvalidBinaryStructure<R, A> implements SendStructure<R, A> {
const InvalidBinaryStructure();
@override
R dispatch(SemanticSendVisitor<R, A> visitor, Send node, A arg) {
return visitor.errorUndefinedBinaryExpression(
node, node.receiver, node.selector, node.arguments.single, arg);
}
@override
SendStructureKind get kind => SendStructureKind.INVALID_BINARY;
String toString() => 'invalid binary';
}
/// The structure for a [Send] that is of the form `a[b] = c`.
class IndexSetStructure<R, A> implements SendStructure<R, A> {
/// The target of the index set operation.
final AccessSemantics semantics;
IndexSetStructure(this.semantics);
@override
SendStructureKind get kind => SendStructureKind.INDEX_SET;
R dispatch(SemanticSendVisitor<R, A> visitor, Send node, A arg) {
switch (semantics.kind) {
case AccessKind.EXPRESSION:
return visitor.visitIndexSet(node, node.receiver, node.arguments.first,
node.arguments.tail.head, arg);
case AccessKind.SUPER_METHOD:
return visitor.visitSuperIndexSet(node, semantics.element,
node.arguments.first, node.arguments.tail.head, arg);
case AccessKind.UNRESOLVED_SUPER:
case AccessKind.UNRESOLVED:
return visitor.visitUnresolvedSuperIndexSet(node, semantics.element,
node.arguments.first, node.arguments.tail.head, arg);
case AccessKind.INVALID:
return visitor.errorInvalidIndexSet(node, semantics.element,
node.arguments.first, node.arguments.tail.head, arg);
default:
// This is not a valid case.
break;
}
throw new SpannableAssertionFailure(
node, "Invalid index set: ${semantics}");
}
String toString() => '[]=($semantics)';
}
/// The structure for a [Send] that is an prefix operation on an index
/// expression, i.e. of the form `--a[b]`.
class IndexPrefixStructure<R, A> implements SendStructure<R, A> {
/// The target of the left operand.
final AccessSemantics semantics;
/// The `++` or `--` operator used in the operation.
final IncDecOperator operator;
IndexPrefixStructure(this.semantics, this.operator);
@override
SendStructureKind get kind => SendStructureKind.INDEX_PREFIX;
R dispatch(SemanticSendVisitor<R, A> visitor, Send node, A arg) {
switch (semantics.kind) {
case AccessKind.EXPRESSION:
return visitor.visitIndexPrefix(
node, node.receiver, node.arguments.single, operator, arg);
case AccessKind.UNRESOLVED_SUPER:
return visitor.visitUnresolvedSuperIndexPrefix(
node, semantics.element, node.arguments.single, operator, arg);
case AccessKind.INVALID:
return visitor.errorInvalidIndexPrefix(
node, semantics.element, node.arguments.single, operator, arg);
case AccessKind.COMPOUND:
CompoundAccessSemantics compoundSemantics = semantics;
switch (compoundSemantics.compoundAccessKind) {
case CompoundAccessKind.SUPER_GETTER_SETTER:
return visitor.visitSuperIndexPrefix(node, compoundSemantics.getter,
compoundSemantics.setter, node.arguments.single, operator, arg);
case CompoundAccessKind.UNRESOLVED_SUPER_GETTER:
return visitor.visitUnresolvedSuperGetterIndexPrefix(
node,
compoundSemantics.getter,
compoundSemantics.setter,
node.arguments.single,
operator,
arg);
case CompoundAccessKind.UNRESOLVED_SUPER_SETTER:
return visitor.visitUnresolvedSuperSetterIndexPrefix(
node,
compoundSemantics.getter,
compoundSemantics.setter,
node.arguments.single,
operator,
arg);
default:
// This is not a valid case.
break;
}
break;
default:
// This is not a valid case.
break;
}
throw new SpannableAssertionFailure(
node, "Invalid index prefix: ${semantics}");
}
}
/// The structure for a [Send] that is an postfix operation on an index
/// expression, i.e. of the form `a[b]++`.
class IndexPostfixStructure<R, A> implements SendStructure<R, A> {
/// The target of the left operand.
final AccessSemantics semantics;
/// The `++` or `--` operator used in the operation.
final IncDecOperator operator;
IndexPostfixStructure(this.semantics, this.operator);
@override
SendStructureKind get kind => SendStructureKind.INDEX_POSTFIX;
R dispatch(SemanticSendVisitor<R, A> visitor, Send node, A arg) {
switch (semantics.kind) {
case AccessKind.EXPRESSION:
return visitor.visitIndexPostfix(
node, node.receiver, node.arguments.single, operator, arg);
case AccessKind.UNRESOLVED_SUPER:
return visitor.visitUnresolvedSuperIndexPostfix(
node, semantics.element, node.arguments.single, operator, arg);
case AccessKind.INVALID:
return visitor.errorInvalidIndexPostfix(
node, semantics.element, node.arguments.single, operator, arg);
case AccessKind.COMPOUND:
CompoundAccessSemantics compoundSemantics = semantics;
switch (compoundSemantics.compoundAccessKind) {
case CompoundAccessKind.SUPER_GETTER_SETTER:
return visitor.visitSuperIndexPostfix(
node,
compoundSemantics.getter,
compoundSemantics.setter,
node.arguments.single,
operator,
arg);
case CompoundAccessKind.UNRESOLVED_SUPER_GETTER:
return visitor.visitUnresolvedSuperGetterIndexPostfix(
node,
compoundSemantics.getter,
compoundSemantics.setter,
node.arguments.single,
operator,
arg);
case CompoundAccessKind.UNRESOLVED_SUPER_SETTER:
return visitor.visitUnresolvedSuperSetterIndexPostfix(
node,
compoundSemantics.getter,
compoundSemantics.setter,
node.arguments.single,
operator,
arg);
default:
// This is not a valid case.
break;
}
break;
default:
// This is not a valid case.
break;
}
throw new SpannableAssertionFailure(
node, "Invalid index postfix: ${semantics}");
}
}
/// The structure for a [Send] that is a compound assignment. For instance
/// `a += b`.
class CompoundStructure<R, A> implements SendStructure<R, A> {
/// The target of the compound assignment, i.e. the left-hand side.
final AccessSemantics semantics;
/// The assignment operator used in the compound assignment.
final AssignmentOperator operator;
CompoundStructure(this.semantics, this.operator);
@override
SendStructureKind get kind => SendStructureKind.COMPOUND;
R dispatch(SemanticSendVisitor<R, A> visitor, Send node, A arg) {
switch (semantics.kind) {
case AccessKind.CONDITIONAL_DYNAMIC_PROPERTY:
return visitor.visitIfNotNullDynamicPropertyCompound(
node,
node.receiver,
semantics.name,
operator,
node.arguments.single,
arg);
case AccessKind.DYNAMIC_PROPERTY:
return visitor.visitDynamicPropertyCompound(node, node.receiver,
semantics.name, operator, node.arguments.single, arg);
case AccessKind.LOCAL_FUNCTION:
return visitor.visitLocalFunctionCompound(
node, semantics.element, operator, node.arguments.single, arg);
case AccessKind.LOCAL_VARIABLE:
return visitor.visitLocalVariableCompound(
node, semantics.element, operator, node.arguments.single, arg);
case AccessKind.FINAL_LOCAL_VARIABLE:
return visitor.visitFinalLocalVariableCompound(
node, semantics.element, operator, node.arguments.single, arg);
case AccessKind.PARAMETER:
return visitor.visitParameterCompound(
node, semantics.element, operator, node.arguments.single, arg);
case AccessKind.FINAL_PARAMETER:
return visitor.visitFinalParameterCompound(
node, semantics.element, operator, node.arguments.single, arg);
case AccessKind.STATIC_FIELD:
return visitor.visitStaticFieldCompound(
node, semantics.element, operator, node.arguments.single, arg);
case AccessKind.FINAL_STATIC_FIELD:
return visitor.visitFinalStaticFieldCompound(
node, semantics.element, operator, node.arguments.single, arg);
case AccessKind.STATIC_METHOD:
return visitor.visitStaticMethodCompound(
node, semantics.element, operator, node.arguments.single, arg);
case AccessKind.STATIC_GETTER:
// This is not a valid case.
break;
case AccessKind.STATIC_SETTER:
// This is not a valid case.
break;
case AccessKind.TOPLEVEL_FIELD:
return visitor.visitTopLevelFieldCompound(
node, semantics.element, operator, node.arguments.single, arg);
case AccessKind.FINAL_TOPLEVEL_FIELD:
return visitor.visitFinalTopLevelFieldCompound(
node, semantics.element, operator, node.arguments.single, arg);
case AccessKind.TOPLEVEL_METHOD:
return visitor.visitTopLevelMethodCompound(
node, semantics.element, operator, node.arguments.single, arg);
case AccessKind.TOPLEVEL_GETTER:
// This is not a valid case.
break;
case AccessKind.TOPLEVEL_SETTER:
// This is not a valid case.
break;
case AccessKind.CLASS_TYPE_LITERAL:
return visitor.visitClassTypeLiteralCompound(
node, semantics.constant, operator, node.arguments.single, arg);
case AccessKind.TYPEDEF_TYPE_LITERAL:
return visitor.visitTypedefTypeLiteralCompound(
node, semantics.constant, operator, node.arguments.single, arg);
case AccessKind.DYNAMIC_TYPE_LITERAL:
return visitor.visitDynamicTypeLiteralCompound(
node, semantics.constant, operator, node.arguments.single, arg);
case AccessKind.TYPE_PARAMETER_TYPE_LITERAL:
return visitor.visitTypeVariableTypeLiteralCompound(
node, semantics.element, operator, node.arguments.single, arg);
case AccessKind.EXPRESSION:
// This is not a valid case.
break;
case AccessKind.THIS:
// This is not a valid case.
break;
case AccessKind.THIS_PROPERTY:
return visitor.visitThisPropertyCompound(
node, semantics.name, operator, node.arguments.single, arg);
case AccessKind.SUPER_FIELD:
return visitor.visitSuperFieldCompound(
node, semantics.element, operator, node.arguments.single, arg);
case AccessKind.SUPER_FINAL_FIELD:
return visitor.visitFinalSuperFieldCompound(
node, semantics.element, operator, node.arguments.single, arg);
case AccessKind.SUPER_METHOD:
return visitor.visitSuperMethodCompound(
node, semantics.element, operator, node.arguments.single, arg);
case AccessKind.SUPER_GETTER:
// This is not a valid case.
break;
case AccessKind.SUPER_SETTER:
// This is not a valid case.
break;
case AccessKind.CONSTANT:
// TODO(johnniwinther): Should this be a valid case?
break;
case AccessKind.UNRESOLVED_SUPER:
return visitor.visitUnresolvedSuperCompound(
node, semantics.element, operator, node.arguments.single, arg);
case AccessKind.UNRESOLVED:
return visitor.visitUnresolvedCompound(
node, semantics.element, operator, node.arguments.single, arg);
case AccessKind.INVALID:
return visitor.errorInvalidCompound(
node, semantics.element, operator, node.arguments.single, arg);
case AccessKind.COMPOUND:
CompoundAccessSemantics compoundSemantics = semantics;
switch (compoundSemantics.compoundAccessKind) {
case CompoundAccessKind.STATIC_GETTER_SETTER:
return visitor.visitStaticGetterSetterCompound(
node,
compoundSemantics.getter,
compoundSemantics.setter,
operator,
node.arguments.single,
arg);
case CompoundAccessKind.STATIC_METHOD_SETTER:
return visitor.visitStaticMethodSetterCompound(
node,
compoundSemantics.getter,
compoundSemantics.setter,
operator,
node.arguments.single,
arg);
case CompoundAccessKind.UNRESOLVED_STATIC_GETTER:
return visitor.visitUnresolvedStaticGetterCompound(
node,
compoundSemantics.getter,
compoundSemantics.setter,
operator,
node.arguments.single,
arg);
case CompoundAccessKind.UNRESOLVED_STATIC_SETTER:
return visitor.visitUnresolvedStaticSetterCompound(
node,
compoundSemantics.getter,
compoundSemantics.setter,
operator,
node.arguments.single,
arg);
case CompoundAccessKind.TOPLEVEL_GETTER_SETTER:
return visitor.visitTopLevelGetterSetterCompound(
node,
compoundSemantics.getter,
compoundSemantics.setter,
operator,
node.arguments.single,
arg);
case CompoundAccessKind.TOPLEVEL_METHOD_SETTER:
return visitor.visitTopLevelMethodSetterCompound(
node,
compoundSemantics.getter,
compoundSemantics.setter,
operator,
node.arguments.single,
arg);
case CompoundAccessKind.UNRESOLVED_TOPLEVEL_GETTER:
return visitor.visitUnresolvedTopLevelGetterCompound(
node,
compoundSemantics.getter,
compoundSemantics.setter,
operator,
node.arguments.single,
arg);
case CompoundAccessKind.UNRESOLVED_TOPLEVEL_SETTER:
return visitor.visitUnresolvedTopLevelSetterCompound(
node,
compoundSemantics.getter,
compoundSemantics.setter,
operator,
node.arguments.single,
arg);
case CompoundAccessKind.SUPER_FIELD_FIELD:
return visitor.visitSuperFieldFieldCompound(
node,
compoundSemantics.getter,
compoundSemantics.setter,
operator,
node.arguments.single,
arg);
case CompoundAccessKind.SUPER_GETTER_SETTER:
return visitor.visitSuperGetterSetterCompound(
node,
compoundSemantics.getter,
compoundSemantics.setter,
operator,
node.arguments.single,
arg);
case CompoundAccessKind.SUPER_GETTER_FIELD:
return visitor.visitSuperGetterFieldCompound(
node,
compoundSemantics.getter,
compoundSemantics.setter,
operator,
node.arguments.single,
arg);
case CompoundAccessKind.SUPER_METHOD_SETTER:
return visitor.visitSuperMethodSetterCompound(
node,
compoundSemantics.getter,
compoundSemantics.setter,
operator,
node.arguments.single,
arg);
case CompoundAccessKind.SUPER_FIELD_SETTER:
return visitor.visitSuperFieldSetterCompound(
node,
compoundSemantics.getter,
compoundSemantics.setter,
operator,
node.arguments.single,
arg);
case CompoundAccessKind.UNRESOLVED_SUPER_GETTER:
return visitor.visitUnresolvedSuperGetterCompound(
node,
compoundSemantics.getter,
compoundSemantics.setter,
operator,
node.arguments.single,
arg);
case CompoundAccessKind.UNRESOLVED_SUPER_SETTER:
return visitor.visitUnresolvedSuperSetterCompound(
node,
compoundSemantics.getter,
compoundSemantics.setter,
operator,
node.arguments.single,
arg);
}
break;
}
throw new SpannableAssertionFailure(
node, "Invalid compound assigment: ${semantics}");
}
String toString() => 'compound($operator,$semantics)';
}
/// The structure for a [Send] that is an if-null assignment. For instance
/// `a ??= b`.
class SetIfNullStructure<R, A> implements SendStructure<R, A> {
/// The target of the if-null assignment, i.e. the left-hand side.
final AccessSemantics semantics;
SetIfNullStructure(this.semantics);
@override
SendStructureKind get kind => SendStructureKind.SET_IF_NULL;
R dispatch(SemanticSendVisitor<R, A> visitor, Send node, A arg) {
switch (semantics.kind) {
case AccessKind.CONDITIONAL_DYNAMIC_PROPERTY:
return visitor.visitIfNotNullDynamicPropertySetIfNull(
node, node.receiver, semantics.name, node.arguments.single, arg);
case AccessKind.DYNAMIC_PROPERTY:
return visitor.visitDynamicPropertySetIfNull(
node, node.receiver, semantics.name, node.arguments.single, arg);
case AccessKind.LOCAL_FUNCTION:
return visitor.visitLocalFunctionSetIfNull(
node, semantics.element, node.arguments.single, arg);
case AccessKind.LOCAL_VARIABLE:
return visitor.visitLocalVariableSetIfNull(
node, semantics.element, node.arguments.single, arg);
case AccessKind.FINAL_LOCAL_VARIABLE:
return visitor.visitFinalLocalVariableSetIfNull(
node, semantics.element, node.arguments.single, arg);
case AccessKind.PARAMETER:
return visitor.visitParameterSetIfNull(
node, semantics.element, node.arguments.single, arg);
case AccessKind.FINAL_PARAMETER:
return visitor.visitFinalParameterSetIfNull(
node, semantics.element, node.arguments.single, arg);
case AccessKind.STATIC_FIELD:
return visitor.visitStaticFieldSetIfNull(
node, semantics.element, node.arguments.single, arg);
case AccessKind.FINAL_STATIC_FIELD:
return visitor.visitFinalStaticFieldSetIfNull(
node, semantics.element, node.arguments.single, arg);
case AccessKind.STATIC_METHOD:
return visitor.visitStaticMethodSetIfNull(
node, semantics.element, node.arguments.single, arg);
case AccessKind.STATIC_GETTER:
// This is not a valid case.
break;
case AccessKind.STATIC_SETTER:
// This is not a valid case.
break;
case AccessKind.TOPLEVEL_FIELD:
return visitor.visitTopLevelFieldSetIfNull(
node, semantics.element, node.arguments.single, arg);
case AccessKind.FINAL_TOPLEVEL_FIELD:
return visitor.visitFinalTopLevelFieldSetIfNull(
node, semantics.element, node.arguments.single, arg);
case AccessKind.TOPLEVEL_METHOD:
return visitor.visitTopLevelMethodSetIfNull(
node, semantics.element, node.arguments.single, arg);
case AccessKind.TOPLEVEL_GETTER:
// This is not a valid case.
break;
case AccessKind.TOPLEVEL_SETTER:
// This is not a valid case.
break;
case AccessKind.CLASS_TYPE_LITERAL:
return visitor.visitClassTypeLiteralSetIfNull(
node, semantics.constant, node.arguments.single, arg);
case AccessKind.TYPEDEF_TYPE_LITERAL:
return visitor.visitTypedefTypeLiteralSetIfNull(
node, semantics.constant, node.arguments.single, arg);
case AccessKind.DYNAMIC_TYPE_LITERAL:
return visitor.visitDynamicTypeLiteralSetIfNull(
node, semantics.constant, node.arguments.single, arg);
case AccessKind.TYPE_PARAMETER_TYPE_LITERAL:
return visitor.visitTypeVariableTypeLiteralSetIfNull(
node, semantics.element, node.arguments.single, arg);
case AccessKind.EXPRESSION:
// This is not a valid case.
break;
case AccessKind.THIS:
// This is not a valid case.
break;
case AccessKind.THIS_PROPERTY:
return visitor.visitThisPropertySetIfNull(
node, semantics.name, node.arguments.single, arg);
case AccessKind.SUPER_FIELD:
return visitor.visitSuperFieldSetIfNull(
node, semantics.element, node.arguments.single, arg);
case AccessKind.SUPER_FINAL_FIELD:
return visitor.visitFinalSuperFieldSetIfNull(
node, semantics.element, node.arguments.single, arg);
case AccessKind.SUPER_METHOD:
return visitor.visitSuperMethodSetIfNull(
node, semantics.element, node.arguments.single, arg);
case AccessKind.SUPER_GETTER:
// This is not a valid case.
break;
case AccessKind.SUPER_SETTER:
// This is not a valid case.
break;
case AccessKind.CONSTANT:
// TODO(johnniwinther): Should this be a valid case?
break;
case AccessKind.UNRESOLVED_SUPER:
return visitor.visitUnresolvedSuperSetIfNull(
node, semantics.element, node.arguments.single, arg);
case AccessKind.UNRESOLVED:
return visitor.visitUnresolvedSetIfNull(
node, semantics.element, node.arguments.single, arg);
case AccessKind.INVALID:
return visitor.errorInvalidSetIfNull(
node, semantics.element, node.arguments.single, arg);
case AccessKind.COMPOUND:
CompoundAccessSemantics compoundSemantics = semantics;
switch (compoundSemantics.compoundAccessKind) {
case CompoundAccessKind.STATIC_GETTER_SETTER:
return visitor.visitStaticGetterSetterSetIfNull(
node,
compoundSemantics.getter,
compoundSemantics.setter,
node.arguments.single,
arg);
case CompoundAccessKind.STATIC_METHOD_SETTER:
return visitor.visitStaticMethodSetterSetIfNull(
node,
compoundSemantics.getter,
compoundSemantics.setter,
node.arguments.single,
arg);
case CompoundAccessKind.UNRESOLVED_STATIC_GETTER:
return visitor.visitUnresolvedStaticGetterSetIfNull(
node,
compoundSemantics.getter,
compoundSemantics.setter,
node.arguments.single,
arg);
case CompoundAccessKind.UNRESOLVED_STATIC_SETTER:
return visitor.visitUnresolvedStaticSetterSetIfNull(
node,
compoundSemantics.getter,
compoundSemantics.setter,
node.arguments.single,
arg);
case CompoundAccessKind.TOPLEVEL_GETTER_SETTER:
return visitor.visitTopLevelGetterSetterSetIfNull(
node,
compoundSemantics.getter,
compoundSemantics.setter,
node.arguments.single,
arg);
case CompoundAccessKind.TOPLEVEL_METHOD_SETTER:
return visitor.visitTopLevelMethodSetterSetIfNull(
node,
compoundSemantics.getter,
compoundSemantics.setter,
node.arguments.single,
arg);
case CompoundAccessKind.UNRESOLVED_TOPLEVEL_GETTER:
return visitor.visitUnresolvedTopLevelGetterSetIfNull(
node,
compoundSemantics.getter,
compoundSemantics.setter,
node.arguments.single,
arg);
case CompoundAccessKind.UNRESOLVED_TOPLEVEL_SETTER:
return visitor.visitUnresolvedTopLevelSetterSetIfNull(
node,
compoundSemantics.getter,
compoundSemantics.setter,
node.arguments.single,
arg);
case CompoundAccessKind.SUPER_FIELD_FIELD:
return visitor.visitSuperFieldFieldSetIfNull(
node,
compoundSemantics.getter,
compoundSemantics.setter,
node.arguments.single,
arg);
case CompoundAccessKind.SUPER_GETTER_SETTER:
return visitor.visitSuperGetterSetterSetIfNull(
node,
compoundSemantics.getter,
compoundSemantics.setter,
node.arguments.single,
arg);
case CompoundAccessKind.SUPER_GETTER_FIELD:
return visitor.visitSuperGetterFieldSetIfNull(
node,
compoundSemantics.getter,
compoundSemantics.setter,
node.arguments.single,
arg);
case CompoundAccessKind.SUPER_METHOD_SETTER:
return visitor.visitSuperMethodSetterSetIfNull(
node,
compoundSemantics.getter,
compoundSemantics.setter,
node.arguments.single,
arg);
case CompoundAccessKind.SUPER_FIELD_SETTER:
return visitor.visitSuperFieldSetterSetIfNull(
node,
compoundSemantics.getter,
compoundSemantics.setter,
node.arguments.single,
arg);
case CompoundAccessKind.UNRESOLVED_SUPER_GETTER:
return visitor.visitUnresolvedSuperGetterSetIfNull(
node,
compoundSemantics.getter,
compoundSemantics.setter,
node.arguments.single,
arg);
case CompoundAccessKind.UNRESOLVED_SUPER_SETTER:
return visitor.visitUnresolvedSuperSetterSetIfNull(
node,
compoundSemantics.getter,
compoundSemantics.setter,
node.arguments.single,
arg);
}
break;
}
throw new SpannableAssertionFailure(
node, "Invalid if-null assigment: ${semantics}");
}
String toString() => 'ifNull($semantics)';
}
/// The structure for a [Send] that is a compound assignment on the index
/// operator. For instance `a[b] += c`.
class CompoundIndexSetStructure<R, A> implements SendStructure<R, A> {
/// The target of the index operations.
final AccessSemantics semantics;
/// The assignment operator used in the compound assignment.
final AssignmentOperator operator;
CompoundIndexSetStructure(this.semantics, this.operator);
@override
SendStructureKind get kind => SendStructureKind.COMPOUND_INDEX_SET;
R dispatch(SemanticSendVisitor<R, A> visitor, Send node, A arg) {
switch (semantics.kind) {
case AccessKind.EXPRESSION:
return visitor.visitCompoundIndexSet(node, node.receiver,
node.arguments.first, operator, node.arguments.tail.head, arg);
case AccessKind.UNRESOLVED_SUPER:
return visitor.visitUnresolvedSuperCompoundIndexSet(
node,
semantics.element,
node.arguments.first,
operator,
node.arguments.tail.head,
arg);
case AccessKind.INVALID:
return visitor.errorInvalidCompoundIndexSet(node, semantics.element,
node.arguments.first, operator, node.arguments.tail.head, arg);
case AccessKind.COMPOUND:
CompoundAccessSemantics compoundSemantics = semantics;
switch (compoundSemantics.compoundAccessKind) {
case CompoundAccessKind.SUPER_GETTER_SETTER:
return visitor.visitSuperCompoundIndexSet(
node,
compoundSemantics.getter,
compoundSemantics.setter,
node.arguments.first,
operator,
node.arguments.tail.head,
arg);
case CompoundAccessKind.UNRESOLVED_SUPER_GETTER:
return visitor.visitUnresolvedSuperGetterCompoundIndexSet(
node,
compoundSemantics.getter,
compoundSemantics.setter,
node.arguments.first,
operator,
node.arguments.tail.head,
arg);
case CompoundAccessKind.UNRESOLVED_SUPER_SETTER:
return visitor.visitUnresolvedSuperSetterCompoundIndexSet(
node,
compoundSemantics.getter,
compoundSemantics.setter,
node.arguments.first,
operator,
node.arguments.tail.head,
arg);
default:
// This is not a valid case.
break;
}
break;
default:
// This is not a valid case.
break;
}
throw new SpannableAssertionFailure(
node, "Invalid compound index set: ${semantics}");
}
String toString() => 'compound []=($operator,$semantics)';
}
/// The structure for a [Send] that is a if-null assignment on the index
/// operator. For instance `a[b] ??= c`.
class IndexSetIfNullStructure<R, A> implements SendStructure<R, A> {
/// The target of the index operations.
final AccessSemantics semantics;
IndexSetIfNullStructure(this.semantics);
@override
SendStructureKind get kind => SendStructureKind.INDEX_SET_IF_NULL;
R dispatch(SemanticSendVisitor<R, A> visitor, Send node, A arg) {
switch (semantics.kind) {
case AccessKind.EXPRESSION:
return visitor.visitIndexSetIfNull(node, node.receiver,
node.arguments.first, node.arguments.tail.head, arg);
case AccessKind.UNRESOLVED_SUPER:
return visitor.visitUnresolvedSuperIndexSetIfNull(
node,
semantics.element,
node.arguments.first,
node.arguments.tail.head,
arg);
case AccessKind.INVALID:
return visitor.errorInvalidIndexSetIfNull(node, semantics.element,
node.arguments.first, node.arguments.tail.head, arg);
case AccessKind.COMPOUND:
CompoundAccessSemantics compoundSemantics = semantics;
switch (compoundSemantics.compoundAccessKind) {
case CompoundAccessKind.SUPER_GETTER_SETTER:
return visitor.visitSuperIndexSetIfNull(
node,
compoundSemantics.getter,
compoundSemantics.setter,
node.arguments.first,
node.arguments.tail.head,
arg);
case CompoundAccessKind.UNRESOLVED_SUPER_GETTER:
return visitor.visitUnresolvedSuperGetterIndexSetIfNull(
node,
compoundSemantics.getter,
compoundSemantics.setter,
node.arguments.first,
node.arguments.tail.head,
arg);
case CompoundAccessKind.UNRESOLVED_SUPER_SETTER:
return visitor.visitUnresolvedSuperSetterIndexSetIfNull(
node,
compoundSemantics.getter,
compoundSemantics.setter,
node.arguments.first,
node.arguments.tail.head,
arg);
default:
// This is not a valid case.
break;
}
break;
default:
// This is not a valid case.
break;
}
throw new SpannableAssertionFailure(
node, "Invalid index set if-null: ${semantics}");
}
String toString() => 'index set if-null []??=($semantics)';
}
/// The structure for a [Send] that is a prefix operations. For instance
/// `++a`.
class PrefixStructure<R, A> implements SendStructure<R, A> {
/// The target of the prefix operation.
final AccessSemantics semantics;
/// The `++` or `--` operator used in the operation.
final IncDecOperator operator;
PrefixStructure(this.semantics, this.operator);
@override
SendStructureKind get kind => SendStructureKind.PREFIX;
R dispatch(SemanticSendVisitor<R, A> visitor, Send node, A arg) {
switch (semantics.kind) {
case AccessKind.CONDITIONAL_DYNAMIC_PROPERTY:
return visitor.visitIfNotNullDynamicPropertyPrefix(
node, node.receiver, semantics.name, operator, arg);
case AccessKind.DYNAMIC_PROPERTY:
return visitor.visitDynamicPropertyPrefix(
node, node.receiver, semantics.name, operator, arg);
case AccessKind.LOCAL_FUNCTION:
return visitor.visitLocalFunctionPrefix(
node, semantics.element, operator, arg);
case AccessKind.LOCAL_VARIABLE:
return visitor.visitLocalVariablePrefix(
node, semantics.element, operator, arg);
case AccessKind.FINAL_LOCAL_VARIABLE:
return visitor.visitFinalLocalVariablePrefix(
node, semantics.element, operator, arg);
case AccessKind.PARAMETER:
return visitor.visitParameterPrefix(
node, semantics.element, operator, arg);
case AccessKind.FINAL_PARAMETER:
return visitor.visitFinalParameterPrefix(
node, semantics.element, operator, arg);
case AccessKind.STATIC_FIELD:
return visitor.visitStaticFieldPrefix(
node, semantics.element, operator, arg);
case AccessKind.FINAL_STATIC_FIELD:
return visitor.visitFinalStaticFieldPrefix(
node, semantics.element, operator, arg);
case AccessKind.STATIC_METHOD:
return visitor.visitStaticMethodPrefix(
node, semantics.element, operator, arg);
case AccessKind.STATIC_GETTER:
// This is not a valid case.
break;
case AccessKind.STATIC_SETTER:
// This is not a valid case.
break;
case AccessKind.TOPLEVEL_FIELD:
return visitor.visitTopLevelFieldPrefix(
node, semantics.element, operator, arg);
case AccessKind.FINAL_TOPLEVEL_FIELD:
return visitor.visitFinalTopLevelFieldPrefix(
node, semantics.element, operator, arg);
case AccessKind.TOPLEVEL_METHOD:
return visitor.visitTopLevelMethodPrefix(
node, semantics.element, operator, arg);
case AccessKind.TOPLEVEL_GETTER:
// This is not a valid case.
break;
case AccessKind.TOPLEVEL_SETTER:
// This is not a valid case.
break;
case AccessKind.CLASS_TYPE_LITERAL:
return visitor.visitClassTypeLiteralPrefix(
node, semantics.constant, operator, arg);
case AccessKind.TYPEDEF_TYPE_LITERAL:
return visitor.visitTypedefTypeLiteralPrefix(
node, semantics.constant, operator, arg);
case AccessKind.DYNAMIC_TYPE_LITERAL:
return visitor.visitDynamicTypeLiteralPrefix(
node, semantics.constant, operator, arg);
case AccessKind.TYPE_PARAMETER_TYPE_LITERAL:
return visitor.visitTypeVariableTypeLiteralPrefix(
node, semantics.element, operator, arg);
case AccessKind.EXPRESSION:
// This is not a valid case.
break;
case AccessKind.THIS:
// This is not a valid case.
break;
case AccessKind.THIS_PROPERTY:
return visitor.visitThisPropertyPrefix(
node, semantics.name, operator, arg);
case AccessKind.SUPER_FIELD:
return visitor.visitSuperFieldPrefix(
node, semantics.element, operator, arg);
case AccessKind.SUPER_FINAL_FIELD:
return visitor.visitFinalSuperFieldPrefix(
node, semantics.element, operator, arg);
case AccessKind.SUPER_METHOD:
return visitor.visitSuperMethodPrefix(
node, semantics.element, operator, arg);
case AccessKind.SUPER_GETTER:
// This is not a valid case.
break;
case AccessKind.SUPER_SETTER:
// This is not a valid case.
break;
case AccessKind.CONSTANT:
// TODO(johnniwinther): Should this be a valid case?
break;
case AccessKind.UNRESOLVED_SUPER:
return visitor.visitUnresolvedSuperPrefix(
node, semantics.element, operator, arg);
case AccessKind.UNRESOLVED:
return visitor.visitUnresolvedPrefix(
node, semantics.element, operator, arg);
case AccessKind.INVALID:
return visitor.errorInvalidPrefix(
node, semantics.element, operator, arg);
case AccessKind.COMPOUND:
CompoundAccessSemantics compoundSemantics = semantics;
switch (compoundSemantics.compoundAccessKind) {
case CompoundAccessKind.STATIC_GETTER_SETTER:
return visitor.visitStaticGetterSetterPrefix(
node,
compoundSemantics.getter,
compoundSemantics.setter,
operator,
arg);
case CompoundAccessKind.STATIC_METHOD_SETTER:
return visitor.visitStaticMethodSetterPrefix(
node,
compoundSemantics.getter,
compoundSemantics.setter,
operator,
arg);
case CompoundAccessKind.UNRESOLVED_STATIC_GETTER:
return visitor.visitUnresolvedStaticGetterPrefix(
node,
compoundSemantics.getter,
compoundSemantics.setter,
operator,
arg);
case CompoundAccessKind.UNRESOLVED_STATIC_SETTER:
return visitor.visitUnresolvedStaticSetterPrefix(
node,
compoundSemantics.getter,
compoundSemantics.setter,
operator,
arg);
case CompoundAccessKind.STATIC_METHOD_SETTER:
return visitor.visitStaticMethodSetterPrefix(
node,
compoundSemantics.getter,
compoundSemantics.setter,
operator,
arg);
case CompoundAccessKind.TOPLEVEL_GETTER_SETTER:
return visitor.visitTopLevelGetterSetterPrefix(
node,
compoundSemantics.getter,
compoundSemantics.setter,
operator,
arg);
case CompoundAccessKind.TOPLEVEL_METHOD_SETTER:
return visitor.visitTopLevelMethodSetterPrefix(
node,
compoundSemantics.getter,
compoundSemantics.setter,
operator,
arg);
case CompoundAccessKind.UNRESOLVED_TOPLEVEL_GETTER:
return visitor.visitUnresolvedTopLevelGetterPrefix(
node,
compoundSemantics.getter,
compoundSemantics.setter,
operator,
arg);
case CompoundAccessKind.UNRESOLVED_TOPLEVEL_SETTER:
return visitor.visitUnresolvedTopLevelSetterPrefix(
node,
compoundSemantics.getter,
compoundSemantics.setter,
operator,
arg);
case CompoundAccessKind.SUPER_FIELD_FIELD:
return visitor.visitSuperFieldFieldPrefix(
node,
compoundSemantics.getter,
compoundSemantics.setter,
operator,
arg);
case CompoundAccessKind.SUPER_GETTER_SETTER:
return visitor.visitSuperGetterSetterPrefix(
node,
compoundSemantics.getter,
compoundSemantics.setter,
operator,
arg);
case CompoundAccessKind.SUPER_GETTER_FIELD:
return visitor.visitSuperGetterFieldPrefix(
node,
compoundSemantics.getter,
compoundSemantics.setter,
operator,
arg);
case CompoundAccessKind.SUPER_METHOD_SETTER:
return visitor.visitSuperMethodSetterPrefix(
node,
compoundSemantics.getter,
compoundSemantics.setter,
operator,
arg);
case CompoundAccessKind.SUPER_FIELD_SETTER:
return visitor.visitSuperFieldSetterPrefix(
node,
compoundSemantics.getter,
compoundSemantics.setter,
operator,
arg);
case CompoundAccessKind.UNRESOLVED_SUPER_GETTER:
return visitor.visitUnresolvedSuperGetterPrefix(
node,
compoundSemantics.getter,
compoundSemantics.setter,
operator,
arg);
case CompoundAccessKind.UNRESOLVED_SUPER_SETTER:
return visitor.visitUnresolvedSuperSetterPrefix(
node,
compoundSemantics.getter,
compoundSemantics.setter,
operator,
arg);
}
}
throw new SpannableAssertionFailure(
node, "Invalid compound assigment: ${semantics}");
}
String toString() => 'prefix($operator,$semantics)';
}
/// The structure for a [Send] that is a postfix operations. For instance
/// `a++`.
class PostfixStructure<R, A> implements SendStructure<R, A> {
/// The target of the postfix operation.
final AccessSemantics semantics;
/// The `++` or `--` operator used in the operation.
final IncDecOperator operator;
PostfixStructure(this.semantics, this.operator);
@override
SendStructureKind get kind => SendStructureKind.POSTFIX;
R dispatch(SemanticSendVisitor<R, A> visitor, Send node, A arg) {
switch (semantics.kind) {
case AccessKind.CONDITIONAL_DYNAMIC_PROPERTY:
return visitor.visitIfNotNullDynamicPropertyPostfix(
node, node.receiver, semantics.name, operator, arg);
case AccessKind.DYNAMIC_PROPERTY:
return visitor.visitDynamicPropertyPostfix(
node, node.receiver, semantics.name, operator, arg);
case AccessKind.LOCAL_FUNCTION:
return visitor.visitLocalFunctionPostfix(
node, semantics.element, operator, arg);
case AccessKind.LOCAL_VARIABLE:
return visitor.visitLocalVariablePostfix(
node, semantics.element, operator, arg);
case AccessKind.FINAL_LOCAL_VARIABLE:
return visitor.visitFinalLocalVariablePostfix(
node, semantics.element, operator, arg);
case AccessKind.PARAMETER:
return visitor.visitParameterPostfix(
node, semantics.element, operator, arg);
case AccessKind.FINAL_PARAMETER:
return visitor.visitFinalParameterPostfix(
node, semantics.element, operator, arg);
case AccessKind.STATIC_FIELD:
return visitor.visitStaticFieldPostfix(
node, semantics.element, operator, arg);
case AccessKind.FINAL_STATIC_FIELD:
return visitor.visitFinalStaticFieldPostfix(
node, semantics.element, operator, arg);
case AccessKind.STATIC_METHOD:
return visitor.visitStaticMethodPostfix(
node, semantics.element, operator, arg);
case AccessKind.STATIC_GETTER:
// This is not a valid case.
break;
case AccessKind.STATIC_SETTER:
// This is not a valid case.
break;
case AccessKind.TOPLEVEL_FIELD:
return visitor.visitTopLevelFieldPostfix(
node, semantics.element, operator, arg);
case AccessKind.FINAL_TOPLEVEL_FIELD:
return visitor.visitFinalTopLevelFieldPostfix(
node, semantics.element, operator, arg);
case AccessKind.TOPLEVEL_METHOD:
return visitor.visitTopLevelMethodPostfix(
node, semantics.element, operator, arg);
case AccessKind.TOPLEVEL_GETTER:
// This is not a valid case.
break;
case AccessKind.TOPLEVEL_SETTER:
// This is not a valid case.
break;
case AccessKind.CLASS_TYPE_LITERAL:
return visitor.visitClassTypeLiteralPostfix(
node, semantics.constant, operator, arg);
case AccessKind.TYPEDEF_TYPE_LITERAL:
return visitor.visitTypedefTypeLiteralPostfix(
node, semantics.constant, operator, arg);
case AccessKind.DYNAMIC_TYPE_LITERAL:
return visitor.visitDynamicTypeLiteralPostfix(
node, semantics.constant, operator, arg);
case AccessKind.TYPE_PARAMETER_TYPE_LITERAL:
return visitor.visitTypeVariableTypeLiteralPostfix(
node, semantics.element, operator, arg);
case AccessKind.EXPRESSION:
// This is not a valid case.
break;
case AccessKind.THIS:
// This is not a valid case.
break;
case AccessKind.THIS_PROPERTY:
return visitor.visitThisPropertyPostfix(
node, semantics.name, operator, arg);
case AccessKind.SUPER_FIELD:
return visitor.visitSuperFieldPostfix(
node, semantics.element, operator, arg);
case AccessKind.SUPER_FINAL_FIELD:
return visitor.visitFinalSuperFieldPostfix(
node, semantics.element, operator, arg);
case AccessKind.SUPER_METHOD:
return visitor.visitSuperMethodPostfix(
node, semantics.element, operator, arg);
case AccessKind.SUPER_GETTER:
// This is not a valid case.
break;
case AccessKind.SUPER_SETTER:
// This is not a valid case.
break;
case AccessKind.CONSTANT:
// TODO(johnniwinther): Should this be a valid case?
break;
case AccessKind.UNRESOLVED_SUPER:
return visitor.visitUnresolvedSuperPostfix(
node, semantics.element, operator, arg);
case AccessKind.UNRESOLVED:
return visitor.visitUnresolvedPostfix(
node, semantics.element, operator, arg);
case AccessKind.INVALID:
return visitor.errorInvalidPostfix(
node, semantics.element, operator, arg);
case AccessKind.COMPOUND:
CompoundAccessSemantics compoundSemantics = semantics;
switch (compoundSemantics.compoundAccessKind) {
case CompoundAccessKind.STATIC_GETTER_SETTER:
return visitor.visitStaticGetterSetterPostfix(
node,
compoundSemantics.getter,
compoundSemantics.setter,
operator,
arg);
case CompoundAccessKind.UNRESOLVED_STATIC_GETTER:
return visitor.visitUnresolvedStaticGetterPostfix(
node,
compoundSemantics.getter,
compoundSemantics.setter,
operator,
arg);
case CompoundAccessKind.UNRESOLVED_STATIC_SETTER:
return visitor.visitUnresolvedStaticSetterPostfix(
node,
compoundSemantics.getter,
compoundSemantics.setter,
operator,
arg);
case CompoundAccessKind.STATIC_METHOD_SETTER:
return visitor.visitStaticMethodSetterPostfix(
node,
compoundSemantics.getter,
compoundSemantics.setter,
operator,
arg);
case CompoundAccessKind.TOPLEVEL_GETTER_SETTER:
return visitor.visitTopLevelGetterSetterPostfix(
node,
compoundSemantics.getter,
compoundSemantics.setter,
operator,
arg);
case CompoundAccessKind.TOPLEVEL_METHOD_SETTER:
return visitor.visitTopLevelMethodSetterPostfix(
node,
compoundSemantics.getter,
compoundSemantics.setter,
operator,
arg);
case CompoundAccessKind.UNRESOLVED_TOPLEVEL_GETTER:
return visitor.visitUnresolvedTopLevelGetterPostfix(
node,
compoundSemantics.getter,
compoundSemantics.setter,
operator,
arg);
case CompoundAccessKind.UNRESOLVED_TOPLEVEL_SETTER:
return visitor.visitUnresolvedTopLevelSetterPostfix(
node,
compoundSemantics.getter,
compoundSemantics.setter,
operator,
arg);
case CompoundAccessKind.SUPER_FIELD_FIELD:
return visitor.visitSuperFieldFieldPostfix(
node,
compoundSemantics.getter,
compoundSemantics.setter,
operator,
arg);
case CompoundAccessKind.SUPER_GETTER_SETTER:
return visitor.visitSuperGetterSetterPostfix(
node,
compoundSemantics.getter,
compoundSemantics.setter,
operator,
arg);
case CompoundAccessKind.SUPER_GETTER_FIELD:
return visitor.visitSuperGetterFieldPostfix(
node,
compoundSemantics.getter,
compoundSemantics.setter,
operator,
arg);
case CompoundAccessKind.SUPER_METHOD_SETTER:
return visitor.visitSuperMethodSetterPostfix(
node,
compoundSemantics.getter,
compoundSemantics.setter,
operator,
arg);
case CompoundAccessKind.SUPER_FIELD_SETTER:
return visitor.visitSuperFieldSetterPostfix(
node,
compoundSemantics.getter,
compoundSemantics.setter,
operator,
arg);
case CompoundAccessKind.UNRESOLVED_SUPER_GETTER:
return visitor.visitUnresolvedSuperGetterPostfix(
node,
compoundSemantics.getter,
compoundSemantics.setter,
operator,
arg);
case CompoundAccessKind.UNRESOLVED_SUPER_SETTER:
return visitor.visitUnresolvedSuperSetterPostfix(
node,
compoundSemantics.getter,
compoundSemantics.setter,
operator,
arg);
}
}
throw new SpannableAssertionFailure(
node, "Invalid compound assigment: ${semantics}");
}
String toString() => 'postfix($operator,$semantics)';
}
/// The structure for a [Send] whose prefix is a prefix for a deferred library.
/// For instance `deferred.a` where `deferred` is a deferred prefix.
class DeferredPrefixStructure<R, A> implements SendStructure<R, A> {
/// The deferred prefix element.
final PrefixElement prefix;
/// The send structure for the whole [Send] node. For instance a
/// [GetStructure] for `deferred.a` where `a` is a top level member of the
/// deferred library.
final SendStructure sendStructure;
DeferredPrefixStructure(this.prefix, this.sendStructure) {
assert(sendStructure != null);
}
@override
SendStructureKind get kind => SendStructureKind.DEFERRED_PREFIX;
@override
R dispatch(SemanticSendVisitor<R, A> visitor, Send send, A arg) {
visitor.previsitDeferredAccess(send, prefix, arg);
return sendStructure.dispatch(visitor, send, arg);
}
}
enum NewStructureKind {
NEW_INVOKE,
CONST_INVOKE,
LATE_CONST,
}
/// The structure for a [NewExpression] of a new invocation.
abstract class NewStructure<R, A> implements SemanticSendStructure<R, A> {
/// Calls the matching visit method on [visitor] with [node] and [arg].
R dispatch(SemanticSendVisitor<R, A> visitor, NewExpression node, A arg);
NewStructureKind get kind;
}
/// The structure for a [NewExpression] of a new invocation. For instance
/// `new C()`.
class NewInvokeStructure<R, A> extends NewStructure<R, A> {
final ConstructorAccessSemantics semantics;
final Selector selector;
NewInvokeStructure(this.semantics, this.selector);
@override
NewStructureKind get kind => NewStructureKind.NEW_INVOKE;
CallStructure get callStructure => selector.callStructure;
R dispatch(SemanticSendVisitor<R, A> visitor, NewExpression node, A arg) {
switch (semantics.kind) {
case ConstructorAccessKind.GENERATIVE:
ConstructorElement constructor = semantics.element;
if (constructor.isRedirectingGenerative) {
return visitor.visitRedirectingGenerativeConstructorInvoke(
node,
constructor,
semantics.type,
node.send.argumentsNode,
callStructure,
arg);
}
return visitor.visitGenerativeConstructorInvoke(node, constructor,
semantics.type, node.send.argumentsNode, callStructure, arg);
case ConstructorAccessKind.FACTORY:
ConstructorElement constructor = semantics.element;
if (constructor.isRedirectingFactory) {
if (constructor.isEffectiveTargetMalformed) {
return visitor.visitUnresolvedRedirectingFactoryConstructorInvoke(
node,
semantics.element,
semantics.type,
node.send.argumentsNode,
callStructure,
arg);
}
ConstructorElement effectiveTarget = constructor.effectiveTarget;
ResolutionInterfaceType effectiveTargetType =
constructor.computeEffectiveTargetType(semantics.type);
if (callStructure.signatureApplies(effectiveTarget.type)) {
return visitor.visitRedirectingFactoryConstructorInvoke(
node,
semantics.element,
semantics.type,
effectiveTarget,
effectiveTargetType,
node.send.argumentsNode,
callStructure,
arg);
} else {
return visitor.visitUnresolvedRedirectingFactoryConstructorInvoke(
node,
semantics.element,
semantics.type,
node.send.argumentsNode,
callStructure,
arg);
}
}
if (callStructure.signatureApplies(constructor.type)) {
return visitor.visitFactoryConstructorInvoke(node, constructor,
semantics.type, node.send.argumentsNode, callStructure, arg);
}
return visitor.visitConstructorIncompatibleInvoke(node, constructor,
semantics.type, node.send.argumentsNode, callStructure, arg);
case ConstructorAccessKind.ABSTRACT:
return visitor.visitAbstractClassConstructorInvoke(
node,
semantics.element,
semantics.type,
node.send.argumentsNode,
callStructure,
arg);
case ConstructorAccessKind.UNRESOLVED_CONSTRUCTOR:
return visitor.visitUnresolvedConstructorInvoke(node, semantics.element,
semantics.type, node.send.argumentsNode, selector, arg);
case ConstructorAccessKind.UNRESOLVED_TYPE:
return visitor.visitUnresolvedClassConstructorInvoke(
node,
semantics.element,
semantics.type,
node.send.argumentsNode,
selector,
arg);
case ConstructorAccessKind.NON_CONSTANT_CONSTRUCTOR:
return visitor.errorNonConstantConstructorInvoke(
node,
semantics.element,
semantics.type,
node.send.argumentsNode,
callStructure,
arg);
case ConstructorAccessKind.INCOMPATIBLE:
return visitor.visitConstructorIncompatibleInvoke(
node,
semantics.element,
semantics.type,
node.send.argumentsNode,
callStructure,
arg);
}
throw new SpannableAssertionFailure(
node, "Unhandled constructor invocation kind: ${semantics.kind}");
}
String toString() => 'new($semantics,$selector)';
}
enum ConstantInvokeKind {
CONSTRUCTED,
BOOL_FROM_ENVIRONMENT,
INT_FROM_ENVIRONMENT,
STRING_FROM_ENVIRONMENT,
}
/// The structure for a [NewExpression] of a constant invocation. For instance
/// `const C()`.
class ConstInvokeStructure<R, A> extends NewStructure<R, A> {
final ConstantInvokeKind constantInvokeKind;
final ConstantExpression constant;
ConstInvokeStructure(this.constantInvokeKind, this.constant);
@override
NewStructureKind get kind => NewStructureKind.CONST_INVOKE;
R dispatch(SemanticSendVisitor<R, A> visitor, NewExpression node, A arg) {
switch (constantInvokeKind) {
case ConstantInvokeKind.CONSTRUCTED:
return visitor.visitConstConstructorInvoke(node, constant, arg);
case ConstantInvokeKind.BOOL_FROM_ENVIRONMENT:
return visitor.visitBoolFromEnvironmentConstructorInvoke(
node, constant, arg);
case ConstantInvokeKind.INT_FROM_ENVIRONMENT:
return visitor.visitIntFromEnvironmentConstructorInvoke(
node, constant, arg);
case ConstantInvokeKind.STRING_FROM_ENVIRONMENT:
return visitor.visitStringFromEnvironmentConstructorInvoke(
node, constant, arg);
}
}
}
/// A constant constructor invocation that couldn't be determined fully during
/// resolution.
// TODO(johnniwinther): Remove this when all constants are computed during
// resolution.
class LateConstInvokeStructure<R, A> extends NewStructure<R, A> {
final TreeElements elements;
LateConstInvokeStructure(this.elements);
@override
NewStructureKind get kind => NewStructureKind.LATE_CONST;
/// Convert this new structure into a regular new structure using the data
/// available in [elements].
NewStructure resolve(NewExpression node) {
Element element = elements[node.send];
Selector selector = elements.getSelector(node.send);
ResolutionDartType type = elements.getType(node);
ConstantExpression constant = elements.getConstant(node);
if (element.isMalformed ||
constant == null ||
constant.kind == ConstantExpressionKind.ERRONEOUS) {
// This is a non-constant constant constructor invocation, like
// `const Const(method())`.
return new NewInvokeStructure(
new ConstructorAccessSemantics(
ConstructorAccessKind.NON_CONSTANT_CONSTRUCTOR, element, type),
selector);
} else {
ConstantInvokeKind kind;
switch (constant.kind) {
case ConstantExpressionKind.CONSTRUCTED:
kind = ConstantInvokeKind.CONSTRUCTED;
break;
case ConstantExpressionKind.BOOL_FROM_ENVIRONMENT:
kind = ConstantInvokeKind.BOOL_FROM_ENVIRONMENT;
break;
case ConstantExpressionKind.INT_FROM_ENVIRONMENT:
kind = ConstantInvokeKind.INT_FROM_ENVIRONMENT;
break;
case ConstantExpressionKind.STRING_FROM_ENVIRONMENT:
kind = ConstantInvokeKind.STRING_FROM_ENVIRONMENT;
break;
default:
throw new SpannableAssertionFailure(
node, "Unexpected constant kind $kind: ${constant.toDartText()}");
}
return new ConstInvokeStructure(kind, constant);
}
}
R dispatch(SemanticSendVisitor<R, A> visitor, NewExpression node, A arg) {
Element element = elements[node.send];
Selector selector = elements.getSelector(node.send);
ResolutionDartType type = elements.getType(node);
ConstantExpression constant = elements.getConstant(node);
if (element.isMalformed ||
constant == null ||
constant.kind == ConstantExpressionKind.ERRONEOUS) {
// This is a non-constant constant constructor invocation, like
// `const Const(method())`.
return visitor.errorNonConstantConstructorInvoke(node, element, type,
node.send.argumentsNode, selector.callStructure, arg);
} else {
ConstantInvokeKind kind;
switch (constant.kind) {
case ConstantExpressionKind.CONSTRUCTED:
return visitor.visitConstConstructorInvoke(node, constant, arg);
case ConstantExpressionKind.BOOL_FROM_ENVIRONMENT:
return visitor.visitBoolFromEnvironmentConstructorInvoke(
node, constant, arg);
case ConstantExpressionKind.INT_FROM_ENVIRONMENT:
return visitor.visitIntFromEnvironmentConstructorInvoke(
node, constant, arg);
case ConstantExpressionKind.STRING_FROM_ENVIRONMENT:
return visitor.visitStringFromEnvironmentConstructorInvoke(
node, constant, arg);
default:
throw new SpannableAssertionFailure(
node, "Unexpected constant kind $kind: ${constant.toDartText()}");
}
}
}
}
/// The structure of a parameter declaration.
abstract class ParameterStructure<R, A> {
final VariableDefinitions definitions;
final Node node;
final ParameterElement parameter;
ParameterStructure(this.definitions, this.node, this.parameter);
/// Calls the matching visit method on [visitor] with [definitions] and [arg].
R dispatch(SemanticDeclarationVisitor<R, A> visitor, A arg);
}
/// The structure of a required parameter declaration.
class RequiredParameterStructure<R, A> extends ParameterStructure<R, A> {
final int index;
RequiredParameterStructure(VariableDefinitions definitions, Node node,
ParameterElement parameter, this.index)
: super(definitions, node, parameter);
@override
R dispatch(SemanticDeclarationVisitor<R, A> visitor, A arg) {
if (parameter.isInitializingFormal) {
return visitor.visitInitializingFormalDeclaration(
definitions, node, parameter, index, arg);
} else {
return visitor.visitParameterDeclaration(
definitions, node, parameter, index, arg);
}
}
}
/// The structure of a optional positional parameter declaration.
class OptionalParameterStructure<R, A> extends ParameterStructure<R, A> {
final ConstantExpression defaultValue;
final int index;
OptionalParameterStructure(VariableDefinitions definitions, Node node,
ParameterElement parameter, this.defaultValue, this.index)
: super(definitions, node, parameter);
@override
R dispatch(SemanticDeclarationVisitor<R, A> visitor, A arg) {
if (parameter.isInitializingFormal) {
return visitor.visitOptionalInitializingFormalDeclaration(
definitions, node, parameter, defaultValue, index, arg);
} else {
return visitor.visitOptionalParameterDeclaration(
definitions, node, parameter, defaultValue, index, arg);
}
}
}
/// The structure of a optional named parameter declaration.
class NamedParameterStructure<R, A> extends ParameterStructure<R, A> {
final ConstantExpression defaultValue;
NamedParameterStructure(VariableDefinitions definitions, Node node,
ParameterElement parameter, this.defaultValue)
: super(definitions, node, parameter);
@override
R dispatch(SemanticDeclarationVisitor<R, A> visitor, A arg) {
if (parameter.isInitializingFormal) {
return visitor.visitNamedInitializingFormalDeclaration(
definitions, node, parameter, defaultValue, arg);
} else {
return visitor.visitNamedParameterDeclaration(
definitions, node, parameter, defaultValue, arg);
}
}
}
enum VariableKind {
TOP_LEVEL_FIELD,
STATIC_FIELD,
INSTANCE_FIELD,
LOCAL_VARIABLE,
}
abstract class VariableStructure<R, A> {
final VariableKind kind;
final Node node;
final VariableElement variable;
VariableStructure(this.kind, this.node, this.variable);
R dispatch(SemanticDeclarationVisitor<R, A> visitor,
VariableDefinitions definitions, A arg);
}
class NonConstantVariableStructure<R, A> extends VariableStructure<R, A> {
NonConstantVariableStructure(
VariableKind kind, Node node, VariableElement variable)
: super(kind, node, variable);
R dispatch(SemanticDeclarationVisitor<R, A> visitor,
VariableDefinitions definitions, A arg) {
switch (kind) {
case VariableKind.TOP_LEVEL_FIELD:
return visitor.visitTopLevelFieldDeclaration(
definitions, node, variable, variable.initializer, arg);
case VariableKind.STATIC_FIELD:
return visitor.visitStaticFieldDeclaration(
definitions, node, variable, variable.initializer, arg);
case VariableKind.INSTANCE_FIELD:
return visitor.visitInstanceFieldDeclaration(
definitions, node, variable, variable.initializer, arg);
case VariableKind.LOCAL_VARIABLE:
return visitor.visitLocalVariableDeclaration(
definitions, node, variable, variable.initializer, arg);
}
}
}
class ConstantVariableStructure<R, A> extends VariableStructure<R, A> {
final ConstantExpression constant;
ConstantVariableStructure(
VariableKind kind, Node node, VariableElement variable, this.constant)
: super(kind, node, variable);
R dispatch(SemanticDeclarationVisitor<R, A> visitor,
VariableDefinitions definitions, A arg) {
switch (kind) {
case VariableKind.TOP_LEVEL_FIELD:
return visitor.visitTopLevelConstantDeclaration(
definitions, node, variable, constant, arg);
case VariableKind.STATIC_FIELD:
return visitor.visitStaticConstantDeclaration(
definitions, node, variable, constant, arg);
case VariableKind.LOCAL_VARIABLE:
return visitor.visitLocalConstantDeclaration(
definitions, node, variable, constant, arg);
default:
}
throw new SpannableAssertionFailure(
node, "Invalid constant variable: $variable");
}
}
class InitializersStructure<R, A> {
final List<InitializerStructure<R, A>> initializers;
InitializersStructure(this.initializers);
}
abstract class InitializerStructure<R, A> {
R dispatch(SemanticDeclarationVisitor<R, A> visitor, A arg);
bool get isConstructorInvoke => false;
}
class FieldInitializerStructure<R, A> extends InitializerStructure<R, A> {
final Send node;
final FieldElement field;
FieldInitializerStructure(this.node, this.field);
R dispatch(SemanticDeclarationVisitor<R, A> visitor, A arg) {
return visitor.visitFieldInitializer(
node, field, node.arguments.single, arg);
}
}
class SuperConstructorInvokeStructure<R, A> extends InitializerStructure<R, A> {
final Send node;
final ConstructorElement constructor;
final ResolutionInterfaceType type;
final CallStructure callStructure;
SuperConstructorInvokeStructure(
this.node, this.constructor, this.type, this.callStructure);
R dispatch(SemanticDeclarationVisitor<R, A> visitor, A arg) {
return visitor.visitSuperConstructorInvoke(
node, constructor, type, node.argumentsNode, callStructure, arg);
}
bool get isConstructorInvoke => true;
}
class ImplicitSuperConstructorInvokeStructure<R, A>
extends InitializerStructure<R, A> {
final FunctionExpression node;
final ConstructorElement constructor;
final ResolutionInterfaceType type;
ImplicitSuperConstructorInvokeStructure(
this.node, this.constructor, this.type);
R dispatch(SemanticDeclarationVisitor<R, A> visitor, A arg) {
return visitor.visitImplicitSuperConstructorInvoke(
node, constructor, type, arg);
}
bool get isConstructorInvoke => true;
}
class ThisConstructorInvokeStructure<R, A> extends InitializerStructure<R, A> {
final Send node;
final ConstructorElement constructor;
final CallStructure callStructure;
ThisConstructorInvokeStructure(
this.node, this.constructor, this.callStructure);
R dispatch(SemanticDeclarationVisitor<R, A> visitor, A arg) {
return visitor.visitThisConstructorInvoke(
node, constructor, node.argumentsNode, callStructure, arg);
}
bool get isConstructorInvoke => true;
}