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