| 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
|
| index efd92cf2724e4eba6f5e8ac476dc0e7f5cff6d8a..49369ccf692c40b15d17d5115797cf1e32f5cc9e 100644
|
| --- a/pkg/compiler/lib/src/resolution/send_resolver.dart
|
| +++ b/pkg/compiler/lib/src/resolution/send_resolver.dart
|
| @@ -6,8 +6,6 @@ library dart2js.semantics_visitor.resolver;
|
|
|
| import '../constants/expressions.dart';
|
| import '../dart_types.dart';
|
| -import '../diagnostics/invariant.dart' show
|
| - invariant;
|
| import '../diagnostics/messages.dart' show
|
| MessageKind;
|
| import '../diagnostics/spannable.dart' show
|
| @@ -18,548 +16,15 @@ import '../tree/tree.dart';
|
| import '../universe/universe.dart';
|
|
|
| import 'access_semantics.dart';
|
| -import 'operators.dart';
|
| import 'semantic_visitor.dart';
|
| import 'send_structure.dart';
|
| import 'tree_elements.dart';
|
|
|
| -enum SendStructureKind {
|
| - GET,
|
| - SET,
|
| - INVOKE,
|
| - UNARY,
|
| - NOT,
|
| - BINARY,
|
| - EQ,
|
| - NOT_EQ,
|
| - COMPOUND,
|
| - INDEX,
|
| - INDEX_SET,
|
| - COMPOUND_INDEX_SET,
|
| - PREFIX,
|
| - POSTFIX,
|
| - INDEX_PREFIX,
|
| - INDEX_POSTFIX,
|
| -}
|
| -
|
| abstract class SendResolverMixin {
|
| TreeElements get elements;
|
|
|
| internalError(Spannable spannable, String message);
|
|
|
| - AccessSemantics handleCompoundErroneousSetterAccess(
|
| - Send node,
|
| - Element setter,
|
| - Element getter) {
|
| - assert(invariant(node, Elements.isUnresolved(setter),
|
| - message: "Unexpected erreneous compound setter: $setter."));
|
| - if (getter.isStatic) {
|
| - if (getter.isGetter) {
|
| - return new CompoundAccessSemantics(
|
| - CompoundAccessKind.UNRESOLVED_STATIC_SETTER, getter, setter);
|
| - } else if (getter.isField) {
|
| - // TODO(johnniwinther): Handle const field separately.
|
| - assert(invariant(node, getter.isFinal || getter.isConst,
|
| - message: "Field expected to be final or const."));
|
| - return new StaticAccess.finalStaticField(getter);
|
| - } else if (getter.isFunction) {
|
| - return new StaticAccess.staticMethod(getter);
|
| - } else {
|
| - return internalError(node,
|
| - "Unexpected erroneous static compound: getter=$getter");
|
| - }
|
| - } else if (getter.isTopLevel) {
|
| - if (getter.isGetter) {
|
| - return new CompoundAccessSemantics(
|
| - CompoundAccessKind.UNRESOLVED_TOPLEVEL_SETTER, getter, setter);
|
| - } else if (getter.isField) {
|
| - // TODO(johnniwinther): Handle const field separately.
|
| - assert(invariant(node, getter.isFinal || getter.isConst,
|
| - message: "Field expected to be final or const."));
|
| - return new StaticAccess.finalTopLevelField(getter);
|
| - } else if (getter.isFunction) {
|
| - return new StaticAccess.topLevelMethod(getter);
|
| - } else {
|
| - return internalError(node,
|
| - "Unexpected erroneous top level compound: getter=$getter");
|
| - }
|
| - } else if (getter.isParameter) {
|
| - assert(invariant(node, getter.isFinal,
|
| - message: "Parameter expected to be final."));
|
| - return new StaticAccess.finalParameter(getter);
|
| - } else if (getter.isLocal) {
|
| - if (getter.isVariable) {
|
| - // TODO(johnniwinther): Handle const variable separately.
|
| - assert(invariant(node, getter.isFinal || getter.isConst,
|
| - message: "Variable expected to be final or const."));
|
| - return new StaticAccess.finalLocalVariable(getter);
|
| - } else if (getter.isFunction) {
|
| - return new StaticAccess.localFunction(getter);
|
| - } else {
|
| - return internalError(node,
|
| - "Unexpected erroneous local compound: getter=$getter");
|
| - }
|
| - } else if (getter.isErroneous) {
|
| - return new StaticAccess.unresolved(getter);
|
| - } else {
|
| - return internalError(node,
|
| - "Unexpected erroneous compound: getter=$getter");
|
| - }
|
| - }
|
| -
|
| - AccessSemantics handleStaticallyResolvedAccess(
|
| - Send node,
|
| - Element element,
|
| - Element getter,
|
| - {bool isCompound}) {
|
| - if (element == null) {
|
| - assert(invariant(node, isCompound, message:
|
| - "Non-compound static access without element."));
|
| - assert(invariant(node, getter != null, message:
|
| - "Compound static access without element."));
|
| - return handleCompoundErroneousSetterAccess(node, element, getter);
|
| - }
|
| - if (element.isErroneous) {
|
| - if (isCompound) {
|
| - return handleCompoundErroneousSetterAccess(node, element, getter);
|
| - }
|
| - return new StaticAccess.unresolved(element);
|
| - } else if (element.isParameter) {
|
| - if (element.isFinal) {
|
| - return new StaticAccess.finalParameter(element);
|
| - } else {
|
| - return new StaticAccess.parameter(element);
|
| - }
|
| - } else if (element.isLocal) {
|
| - if (element.isFunction) {
|
| - return new StaticAccess.localFunction(element);
|
| - } else if (element.isFinal || element.isConst) {
|
| - return new StaticAccess.finalLocalVariable(element);
|
| - } else {
|
| - return new StaticAccess.localVariable(element);
|
| - }
|
| - } else if (element.isStatic) {
|
| - if (element.isField) {
|
| - if (element.isFinal || element.isConst) {
|
| - // TODO(johnniwinther): Handle const field separately.
|
| - return new StaticAccess.finalStaticField(element);
|
| - }
|
| - return new StaticAccess.staticField(element);
|
| - } else if (element.isGetter) {
|
| - if (isCompound) {
|
| - return new CompoundAccessSemantics(
|
| - CompoundAccessKind.UNRESOLVED_STATIC_SETTER, element, null);
|
| - }
|
| - return new StaticAccess.staticGetter(element);
|
| - } else if (element.isSetter) {
|
| - if (getter != null) {
|
| - CompoundAccessKind accessKind;
|
| - if (getter.isErroneous) {
|
| - accessKind = CompoundAccessKind.UNRESOLVED_STATIC_GETTER;
|
| - } else if (getter.isAbstractField) {
|
| - AbstractFieldElement abstractField = getter;
|
| - if (abstractField.getter == null) {
|
| - accessKind = CompoundAccessKind.UNRESOLVED_STATIC_GETTER;
|
| - } else {
|
| - // TODO(johnniwinther): This might be dead code.
|
| - getter = abstractField.getter;
|
| - accessKind = CompoundAccessKind.STATIC_GETTER_SETTER;
|
| - }
|
| - } else 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) {
|
| - if (element.isFinal || element.isConst) {
|
| - // TODO(johnniwinther): Handle const field separately.
|
| - return new StaticAccess.finalTopLevelField(element);
|
| - }
|
| - 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.isErroneous) {
|
| - accessKind = CompoundAccessKind.UNRESOLVED_TOPLEVEL_GETTER;
|
| - } else if (getter.isAbstractField) {
|
| - AbstractFieldElement abstractField = getter;
|
| - if (abstractField.getter == null) {
|
| - accessKind = CompoundAccessKind.UNRESOLVED_TOPLEVEL_GETTER;
|
| - } else {
|
| - // TODO(johnniwinther): This might be dead code.
|
| - getter = abstractField.getter;
|
| - accessKind = CompoundAccessKind.TOPLEVEL_GETTER_SETTER;
|
| - }
|
| - } else 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) {
|
| - SendStructure sendStructure = elements.getSendStructure(node);
|
| - if (sendStructure != null) {
|
| - return sendStructure;
|
| - }
|
| -
|
| - if (elements.isAssert(node)) {
|
| - return internalError(node, "Unexpected assert.");
|
| - }
|
| -
|
| - AssignmentOperator assignmentOperator;
|
| - BinaryOperator binaryOperator;
|
| - IncDecOperator incDecOperator;
|
| -
|
| - if (node.isOperator) {
|
| - String operatorText = node.selector.asOperator().source;
|
| - if (operatorText == 'is') {
|
| - return internalError(node, "Unexpected is test.");
|
| - } else if (operatorText == 'as') {
|
| - return internalError(node, "Unexpected as cast.");
|
| - } else if (operatorText == '&&') {
|
| - return internalError(node, "Unexpected logical and.");
|
| - } else if (operatorText == '||') {
|
| - return internalError(node, "Unexpected logical or.");
|
| - } else if (operatorText == '??') {
|
| - return internalError(node, "Unexpected if-null.");
|
| - }
|
| - }
|
| -
|
| - 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) {
|
| - return internalError(node, "Unexpected unary $operatorText.");
|
| - } else {
|
| - binaryOperator = BinaryOperator.parse(operatorText);
|
| - if (binaryOperator != null) {
|
| - switch (binaryOperator.kind) {
|
| - case BinaryOperatorKind.EQ:
|
| - kind = SendStructureKind.EQ;
|
| - return internalError(node, "Unexpected binary $kind.");
|
| - case BinaryOperatorKind.NOT_EQ:
|
| - kind = SendStructureKind.NOT_EQ;
|
| - return internalError(node, "Unexpected binary $kind.");
|
| - case BinaryOperatorKind.INDEX:
|
| - if (node.isPrefix) {
|
| - kind = SendStructureKind.INDEX_PREFIX;
|
| - } else if (node.isPostfix) {
|
| - kind = SendStructureKind.INDEX_POSTFIX;
|
| - } else if (node.arguments.tail.isEmpty) {
|
| - // a[b]
|
| - kind = SendStructureKind.INDEX;
|
| - return internalError(node, "Unexpected binary $kind.");
|
| - } 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;
|
| - return internalError(node, "Unexpected binary $kind.");
|
| - }
|
| - } else {
|
| - return internalError(
|
| - node, "Unexpected invalid binary $operatorText.");
|
| - }
|
| - }
|
| - }
|
| - AccessSemantics semantics = computeAccessSemantics(
|
| - node,
|
| - isSet: kind == SendStructureKind.SET,
|
| - isInvoke: kind == SendStructureKind.INVOKE,
|
| - isCompound: kind == SendStructureKind.COMPOUND ||
|
| - kind == SendStructureKind.COMPOUND_INDEX_SET ||
|
| - kind == SendStructureKind.PREFIX ||
|
| - kind == SendStructureKind.POSTFIX ||
|
| - kind == SendStructureKind.INDEX_PREFIX ||
|
| - kind == SendStructureKind.INDEX_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:
|
| - switch (semantics.kind) {
|
| - case AccessKind.STATIC_METHOD:
|
| - case AccessKind.SUPER_METHOD:
|
| - case AccessKind.TOPLEVEL_METHOD:
|
| - // TODO(johnniwinther): Should local function also be handled here?
|
| - FunctionElement function = semantics.element;
|
| - FunctionSignature signature = function.functionSignature;
|
| - if (!selector.callStructure.signatureApplies(signature)) {
|
| - return new IncompatibleInvokeStructure(semantics, selector);
|
| - }
|
| - break;
|
| - default:
|
| - break;
|
| - }
|
| - return new InvokeStructure(semantics, selector);
|
| - case SendStructureKind.UNARY:
|
| - return internalError(node, "Unexpected unary.");
|
| - case SendStructureKind.NOT:
|
| - return internalError(node, "Unexpected not.");
|
| - case SendStructureKind.BINARY:
|
| - return internalError(node, "Unexpected binary.");
|
| - case SendStructureKind.INDEX:
|
| - return internalError(node, "Unexpected index.");
|
| - case SendStructureKind.EQ:
|
| - return internalError(node, "Unexpected equals.");
|
| - case SendStructureKind.NOT_EQ:
|
| - return internalError(node, "Unexpected not equals.");
|
| - 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.INDEX_PREFIX:
|
| - Selector getterSelector =
|
| - elements.getGetterSelectorInComplexSendSet(node);
|
| - return new IndexPrefixStructure(
|
| - semantics,
|
| - incDecOperator,
|
| - getterSelector,
|
| - selector);
|
| - case SendStructureKind.INDEX_POSTFIX:
|
| - Selector getterSelector =
|
| - elements.getGetterSelectorInComplexSendSet(node);
|
| - return new IndexPostfixStructure(
|
| - semantics,
|
| - incDecOperator,
|
| - 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 isSet: 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);
|
| - // TODO(johnniwinther): Handle deferred constants. There are runtime
|
| - // but not compile-time constants and should have their own
|
| - // [DeferredConstantExpression] class.
|
| - ConstantExpression constant = elements.getConstant(
|
| - isInvoke || isSet || isCompound ? 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)) {
|
| - if (isCompound) {
|
| - if (Elements.isUnresolved(getter)) {
|
| - // TODO(johnniwinther): Ensure that [getter] is not null. This
|
| - // happens in the case of missing super getter.
|
| - return new StaticAccess.unresolvedSuper(element);
|
| - } else if (getter.isField) {
|
| - assert(invariant(node, getter.isFinal,
|
| - message: "Super field expected to be final."));
|
| - return new StaticAccess.superFinalField(getter);
|
| - } else if (getter.isFunction) {
|
| - if (node.isIndex) {
|
| - return new CompoundAccessSemantics(
|
| - CompoundAccessKind.UNRESOLVED_SUPER_SETTER, getter, element);
|
| - } else {
|
| - return new StaticAccess.superMethod(getter);
|
| - }
|
| - } else {
|
| - return new CompoundAccessSemantics(
|
| - CompoundAccessKind.UNRESOLVED_SUPER_SETTER, getter, element);
|
| - }
|
| - } else {
|
| - return new StaticAccess.unresolvedSuper(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 CompoundAccessSemantics(
|
| - CompoundAccessKind.UNRESOLVED_SUPER_GETTER, getter, element);
|
| - } 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);
|
| - } else if (element.isFinal) {
|
| - return new StaticAccess.superFinalField(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.isConditional) {
|
| - // Conditional sends (e?.x) are treated as dynamic property reads because
|
| - // they are equivalent to do ((a) => a == null ? null : a.x)(e). If `e` is
|
| - // a type `A`, this is equivalent to write `(A).x`.
|
| - return const DynamicAccess.ifNotNullProperty();
|
| - } else if (node.isOperator) {
|
| - return const DynamicAccess.dynamicProperty();
|
| - } else if (Elements.isClosureSend(node, element)) {
|
| - if (element == null) {
|
| - if (node.selector.isThis()) {
|
| - return new DynamicAccess.thisAccess();
|
| - } else {
|
| - return new DynamicAccess.expression();
|
| - }
|
| - } else if (Elements.isErroneous(element)) {
|
| - return new StaticAccess.unresolved(element);
|
| - } else {
|
| - return handleStaticallyResolvedAccess(
|
| - node, element, getter, isCompound: isCompound);
|
| - }
|
| - } else {
|
| - bool isDynamicAccess(Element e) => e == null || e.isInstanceMember;
|
| -
|
| - if (isDynamicAccess(element) &&
|
| - (!isCompound || isDynamicAccess(getter))) {
|
| - if (node.receiver == null || node.receiver.isThis()) {
|
| - return const DynamicAccess.thisProperty();
|
| - } else {
|
| - return const DynamicAccess.dynamicProperty();
|
| - }
|
| - } else if (element != null && 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, isCompound: isCompound);
|
| - }
|
| - }
|
| - }
|
| -
|
| ConstructorAccessSemantics computeConstructorAccessSemantics(
|
| ConstructorElement constructor,
|
| CallStructure callStructure,
|
|
|