| Index: pkg/compiler/lib/src/resolution/send_resolver.dart
|
| diff --git a/pkg/compiler/lib/src/resolution/send_resolver.dart b/pkg/compiler/lib/src/resolution/send_resolver.dart
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..c6c4fca179277cfd05fd183975955a027d7131bb
|
| --- /dev/null
|
| +++ b/pkg/compiler/lib/src/resolution/send_resolver.dart
|
| @@ -0,0 +1,374 @@
|
| +// 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.
|
| +
|
| +part of dart2js.semantics_visitor;
|
| +
|
| +enum SendStructureKind {
|
| + GET,
|
| + SET,
|
| + INVOKE,
|
| + UNARY,
|
| + NOT,
|
| + BINARY,
|
| + EQ,
|
| + NOT_EQ,
|
| + COMPOUND,
|
| + INDEX_SET,
|
| + COMPOUND_INDEX_SET,
|
| + PREFIX,
|
| + POSTFIX,
|
| +}
|
| +
|
| +abstract class SendResolverMixin {
|
| + TreeElements get elements;
|
| +
|
| + internalError(Spannable spannable, String message);
|
| +
|
| + AccessSemantics handleStaticallyResolvedAccess(Send node,
|
| + Element element,
|
| + Element getter) {
|
| + if (element.isErroneous) {
|
| + return new StaticAccess.unresolved(element);
|
| + } else if (element.isParameter) {
|
| + return new StaticAccess.parameter(element);
|
| + } else if (element.isLocal) {
|
| + if (element.isFunction) {
|
| + return new StaticAccess.localFunction(element);
|
| + } else {
|
| + return new StaticAccess.localVariable(element);
|
| + }
|
| + } else if (element.isStatic) {
|
| + if (element.isField) {
|
| + return new StaticAccess.staticField(element);
|
| + } else if (element.isGetter) {
|
| + return new StaticAccess.staticGetter(element);
|
| + } else if (element.isSetter) {
|
| + if (getter != null) {
|
| + CompoundAccessKind accessKind;
|
| + if (getter.isGetter) {
|
| + accessKind = CompoundAccessKind.STATIC_GETTER_SETTER;
|
| + } else {
|
| + accessKind = CompoundAccessKind.STATIC_METHOD_SETTER;
|
| + }
|
| + return new CompoundAccessSemantics(
|
| + accessKind, getter, element);
|
| + } else {
|
| + return new StaticAccess.staticSetter(element);
|
| + }
|
| + } else {
|
| + return new StaticAccess.staticMethod(element);
|
| + }
|
| + } else if (element.isTopLevel) {
|
| + if (element.isField) {
|
| + return new StaticAccess.topLevelField(element);
|
| + } else if (element.isGetter) {
|
| + return new StaticAccess.topLevelGetter(element);
|
| + } else if (element.isSetter) {
|
| + if (getter != null) {
|
| + CompoundAccessKind accessKind;
|
| + if (getter.isGetter) {
|
| + accessKind = CompoundAccessKind.TOPLEVEL_GETTER_SETTER;
|
| + } else {
|
| + accessKind = CompoundAccessKind.TOPLEVEL_METHOD_SETTER;
|
| + }
|
| + return new CompoundAccessSemantics(
|
| + accessKind, getter, element);
|
| + } else {
|
| + return new StaticAccess.topLevelSetter(element);
|
| + }
|
| + } else {
|
| + return new StaticAccess.topLevelMethod(element);
|
| + }
|
| + } else {
|
| + return internalError(
|
| + node, "Unhandled resolved property access: $element");
|
| + }
|
| + }
|
| +
|
| + SendStructure computeSendStructure(Send node) {
|
| + if (elements.isAssert(node)) {
|
| + if (!node.arguments.isEmpty && node.arguments.tail.isEmpty) {
|
| + return const AssertStructure();
|
| + } else {
|
| + return const InvalidAssertStructure();
|
| + }
|
| + }
|
| +
|
| + AssignmentOperator assignmentOperator;
|
| + UnaryOperator unaryOperator;
|
| + BinaryOperator binaryOperator;
|
| + IncDecOperator incDecOperator;
|
| +
|
| + if (node.isOperator) {
|
| + String operatorText = node.selector.asOperator().source;
|
| + if (operatorText == 'is') {
|
| + if (node.isIsNotCheck) {
|
| + return new IsNotStructure(
|
| + elements.getType(node.arguments.single.asSend().receiver));
|
| + } else {
|
| + return new IsStructure(elements.getType(node.arguments.single));
|
| + }
|
| + } else if (operatorText == 'as') {
|
| + return new AsStructure(elements.getType(node.arguments.single));
|
| + } else if (operatorText == '&&') {
|
| + return const LogicalAndStructure();
|
| + } else if (operatorText == '||') {
|
| + return const LogicalOrStructure();
|
| + }
|
| + }
|
| +
|
| + SendStructureKind kind;
|
| +
|
| + if (node.asSendSet() != null) {
|
| + SendSet sendSet = node.asSendSet();
|
| + String operatorText = sendSet.assignmentOperator.source;
|
| + if (sendSet.isPrefix || sendSet.isPostfix) {
|
| + kind = sendSet.isPrefix
|
| + ? SendStructureKind.PREFIX
|
| + : SendStructureKind.POSTFIX;
|
| + incDecOperator = IncDecOperator.parse(operatorText);
|
| + if (incDecOperator == null) {
|
| + return internalError(
|
| + node, "No inc/dec operator for '$operatorText'.");
|
| + }
|
| + } else {
|
| + assignmentOperator = AssignmentOperator.parse(operatorText);
|
| + if (assignmentOperator != null) {
|
| + switch (assignmentOperator.kind) {
|
| + case AssignmentOperatorKind.ASSIGN:
|
| + kind = SendStructureKind.SET;
|
| + break;
|
| + default:
|
| + kind = SendStructureKind.COMPOUND;
|
| + }
|
| + } else {
|
| + return internalError(
|
| + node, "No assignment operator for '$operatorText'.");
|
| + }
|
| + }
|
| + } else if (!node.isPropertyAccess) {
|
| + kind = SendStructureKind.INVOKE;
|
| + } else {
|
| + kind = SendStructureKind.GET;
|
| + }
|
| +
|
| + if (node.isOperator) {
|
| + String operatorText = node.selector.asOperator().source;
|
| + if (node.arguments.isEmpty) {
|
| + unaryOperator = UnaryOperator.parse(operatorText);
|
| + if (unaryOperator != null) {
|
| + switch (unaryOperator.kind) {
|
| + case UnaryOperatorKind.NOT:
|
| + kind = SendStructureKind.NOT;
|
| + break;
|
| + default:
|
| + kind = SendStructureKind.UNARY;
|
| + break;
|
| + }
|
| + } else {
|
| + return const InvalidUnaryStructure();
|
| + }
|
| + } else {
|
| + binaryOperator = BinaryOperator.parse(operatorText);
|
| + if (binaryOperator != null) {
|
| + switch (binaryOperator.kind) {
|
| + case BinaryOperatorKind.EQ:
|
| + kind = SendStructureKind.EQ;
|
| + break;
|
| + case BinaryOperatorKind.NOT_EQ:
|
| + if (node.isSuperCall) {
|
| + // `super != foo` is a compile-time error.
|
| + return const InvalidBinaryStructure();
|
| + }
|
| + kind = SendStructureKind.NOT_EQ;
|
| + break;
|
| + case BinaryOperatorKind.INDEX:
|
| + if (node.arguments.tail.isEmpty) {
|
| + // a[b]
|
| + kind = SendStructureKind.BINARY;
|
| + } else {
|
| + if (kind == SendStructureKind.COMPOUND) {
|
| + // a[b] += c
|
| + kind = SendStructureKind.COMPOUND_INDEX_SET;
|
| + } else {
|
| + // a[b] = c
|
| + kind = SendStructureKind.INDEX_SET;
|
| + }
|
| + }
|
| + break;
|
| + default:
|
| + kind = SendStructureKind.BINARY;
|
| + break;
|
| + }
|
| + } else {
|
| + return const InvalidBinaryStructure();
|
| + }
|
| + }
|
| + }
|
| + AccessSemantics semantics = computeAccessSemantics(
|
| + node,
|
| + isGetOrSet: kind == SendStructureKind.GET ||
|
| + kind == SendStructureKind.SET,
|
| + isInvoke: kind == SendStructureKind.INVOKE,
|
| + isCompound: kind == SendStructureKind.COMPOUND ||
|
| + kind == SendStructureKind.COMPOUND_INDEX_SET ||
|
| + kind == SendStructureKind.PREFIX ||
|
| + kind == SendStructureKind.POSTFIX);
|
| + if (semantics == null) {
|
| + return internalError(node, 'No semantics for $node');
|
| + }
|
| + Selector selector = elements.getSelector(node);
|
| + switch (kind) {
|
| + case SendStructureKind.GET:
|
| + return new GetStructure(semantics, selector);
|
| + case SendStructureKind.SET:
|
| + return new SetStructure(semantics, selector);
|
| + case SendStructureKind.INVOKE:
|
| + return new InvokeStructure(semantics, selector);
|
| + case SendStructureKind.UNARY:
|
| + return new UnaryStructure(semantics, unaryOperator, selector);
|
| + case SendStructureKind.NOT:
|
| + assert(selector == null);
|
| + return new NotStructure(semantics, selector);
|
| + case SendStructureKind.BINARY:
|
| + return new BinaryStructure(semantics, binaryOperator, selector);
|
| + case SendStructureKind.EQ:
|
| + return new EqualsStructure(semantics, selector);
|
| + case SendStructureKind.NOT_EQ:
|
| + return new NotEqualsStructure(semantics, selector);
|
| + case SendStructureKind.COMPOUND:
|
| + Selector getterSelector =
|
| + elements.getGetterSelectorInComplexSendSet(node);
|
| + return new CompoundStructure(
|
| + semantics,
|
| + assignmentOperator,
|
| + getterSelector,
|
| + selector);
|
| + case SendStructureKind.INDEX_SET:
|
| + return new IndexSetStructure(semantics, selector);
|
| + case SendStructureKind.COMPOUND_INDEX_SET:
|
| + Selector getterSelector =
|
| + elements.getGetterSelectorInComplexSendSet(node);
|
| + return new CompoundIndexSetStructure(
|
| + semantics,
|
| + assignmentOperator,
|
| + getterSelector,
|
| + selector);
|
| + case SendStructureKind.PREFIX:
|
| + Selector getterSelector =
|
| + elements.getGetterSelectorInComplexSendSet(node);
|
| + return new PrefixStructure(
|
| + semantics,
|
| + incDecOperator,
|
| + getterSelector,
|
| + selector);
|
| + case SendStructureKind.POSTFIX:
|
| + Selector getterSelector =
|
| + elements.getGetterSelectorInComplexSendSet(node);
|
| + return new PostfixStructure(
|
| + semantics,
|
| + incDecOperator,
|
| + getterSelector,
|
| + selector);
|
| + }
|
| + }
|
| +
|
| + AccessSemantics computeAccessSemantics(Send node,
|
| + {bool isGetOrSet: false,
|
| + bool isInvoke: false,
|
| + bool isCompound: false}) {
|
| + Element element = elements[node];
|
| + Element getter = isCompound ? elements[node.selector] : null;
|
| + if (elements.isTypeLiteral(node)) {
|
| + DartType dartType = elements.getTypeLiteralType(node);
|
| + TypeConstantExpression constant = elements.getConstant(
|
| + isInvoke ? node.selector : node);
|
| + switch (dartType.kind) {
|
| + case TypeKind.INTERFACE:
|
| + return new ConstantAccess.classTypeLiteral(constant);
|
| + case TypeKind.TYPEDEF:
|
| + return new ConstantAccess.typedefTypeLiteral(constant);
|
| + case TypeKind.TYPE_VARIABLE:
|
| + return new StaticAccess.typeParameterTypeLiteral(dartType.element);
|
| + case TypeKind.DYNAMIC:
|
| + return new ConstantAccess.dynamicTypeLiteral(constant);
|
| + default:
|
| + return internalError(node, "Unexpected type literal type: $dartType");
|
| + }
|
| + } else if (node.isSuperCall) {
|
| + if (Elements.isUnresolved(element)) {
|
| + return new StaticAccess.unresolved(element);
|
| + } else if (isCompound && Elements.isUnresolved(getter)) {
|
| + // TODO(johnniwinther): Ensure that [getter] is not null. This happens
|
| + // in the case of missing super getter.
|
| + return new StaticAccess.unresolved(getter);
|
| + } else if (element.isField) {
|
| + if (getter != null && getter != element) {
|
| + CompoundAccessKind accessKind;
|
| + if (getter.isField) {
|
| + accessKind = CompoundAccessKind.SUPER_FIELD_FIELD;
|
| + } else if (getter.isGetter) {
|
| + accessKind = CompoundAccessKind.SUPER_GETTER_FIELD;
|
| + } else {
|
| + return internalError(node,
|
| + "Unsupported super call: $node : $element/$getter.");
|
| + }
|
| + return new CompoundAccessSemantics(accessKind, getter, element);
|
| + }
|
| + return new StaticAccess.superField(element);
|
| + } else if (element.isGetter) {
|
| + return new StaticAccess.superGetter(element);
|
| + } else if (element.isSetter) {
|
| + if (getter != null) {
|
| + CompoundAccessKind accessKind;
|
| + if (getter.isField) {
|
| + accessKind = CompoundAccessKind.SUPER_FIELD_SETTER;
|
| + } else if (getter.isGetter) {
|
| + accessKind = CompoundAccessKind.SUPER_GETTER_SETTER;
|
| + } else {
|
| + accessKind = CompoundAccessKind.SUPER_METHOD_SETTER;
|
| + }
|
| + return new CompoundAccessSemantics(accessKind, getter, element);
|
| + }
|
| + return new StaticAccess.superSetter(element);
|
| + } else if (isCompound) {
|
| + return new CompoundAccessSemantics(
|
| + CompoundAccessKind.SUPER_GETTER_SETTER, getter, element);
|
| + } else {
|
| + return new StaticAccess.superMethod(element);
|
| + }
|
| + } else if (node.isOperator) {
|
| + return new DynamicAccess.dynamicProperty(node.receiver);
|
| + } else if (Elements.isClosureSend(node, element)) {
|
| + if (element == null) {
|
| + if (node.selector.isThis()) {
|
| + return new AccessSemantics.thisAccess();
|
| + } else {
|
| + return new AccessSemantics.expression();
|
| + }
|
| + } else if (Elements.isErroneous(element)) {
|
| + return new StaticAccess.unresolved(element);
|
| + } else {
|
| + return handleStaticallyResolvedAccess(node, element, getter);
|
| + }
|
| + } else {
|
| + if (Elements.isErroneous(element)) {
|
| + return new StaticAccess.unresolved(element);
|
| + } else if (element == null || element.isInstanceMember) {
|
| + if (node.receiver == null || node.receiver.isThis()) {
|
| + return new AccessSemantics.thisProperty();
|
| + } else {
|
| + return new DynamicAccess.dynamicProperty(node.receiver);
|
| + }
|
| + } else if (element.impliesType) {
|
| + // TODO(johnniwinther): Provide an [ErroneousElement].
|
| + // This happens for code like `C.this`.
|
| + return new StaticAccess.unresolved(null);
|
| + } else {
|
| + return handleStaticallyResolvedAccess(node, element, getter);
|
| + }
|
| + }
|
| + }
|
| +}
|
| +
|
|
|