| OLD | NEW | 
|     1 // Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file |     1 // Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file | 
|     2 // for details. All rights reserved. Use of this source code is governed by a |     2 // for details. All rights reserved. Use of this source code is governed by a | 
|     3 // BSD-style license that can be found in the LICENSE file. |     3 // BSD-style license that can be found in the LICENSE file. | 
|     4  |     4  | 
|     5 library dart2js.semantics_visitor.resolver; |     5 library dart2js.semantics_visitor.resolver; | 
|     6  |     6  | 
|     7 import '../constants/expressions.dart'; |     7 import '../constants/expressions.dart'; | 
|     8 import '../dart_types.dart'; |     8 import '../dart_types.dart'; | 
|     9 import '../diagnostics/invariant.dart' show |  | 
|    10     invariant; |  | 
|    11 import '../diagnostics/messages.dart' show |     9 import '../diagnostics/messages.dart' show | 
|    12     MessageKind; |    10     MessageKind; | 
|    13 import '../diagnostics/spannable.dart' show |    11 import '../diagnostics/spannable.dart' show | 
|    14     Spannable, |    12     Spannable, | 
|    15     SpannableAssertionFailure; |    13     SpannableAssertionFailure; | 
|    16 import '../elements/elements.dart'; |    14 import '../elements/elements.dart'; | 
|    17 import '../tree/tree.dart'; |    15 import '../tree/tree.dart'; | 
|    18 import '../universe/universe.dart'; |    16 import '../universe/universe.dart'; | 
|    19  |    17  | 
|    20 import 'access_semantics.dart'; |    18 import 'access_semantics.dart'; | 
|    21 import 'operators.dart'; |  | 
|    22 import 'semantic_visitor.dart'; |    19 import 'semantic_visitor.dart'; | 
|    23 import 'send_structure.dart'; |    20 import 'send_structure.dart'; | 
|    24 import 'tree_elements.dart'; |    21 import 'tree_elements.dart'; | 
|    25  |    22  | 
|    26 enum SendStructureKind { |  | 
|    27   GET, |  | 
|    28   SET, |  | 
|    29   INVOKE, |  | 
|    30   UNARY, |  | 
|    31   NOT, |  | 
|    32   BINARY, |  | 
|    33   EQ, |  | 
|    34   NOT_EQ, |  | 
|    35   COMPOUND, |  | 
|    36   INDEX, |  | 
|    37   INDEX_SET, |  | 
|    38   COMPOUND_INDEX_SET, |  | 
|    39   PREFIX, |  | 
|    40   POSTFIX, |  | 
|    41   INDEX_PREFIX, |  | 
|    42   INDEX_POSTFIX, |  | 
|    43 } |  | 
|    44  |  | 
|    45 abstract class SendResolverMixin { |    23 abstract class SendResolverMixin { | 
|    46   TreeElements get elements; |    24   TreeElements get elements; | 
|    47  |    25  | 
|    48   internalError(Spannable spannable, String message); |    26   internalError(Spannable spannable, String message); | 
|    49  |    27  | 
|    50   AccessSemantics handleCompoundErroneousSetterAccess( |  | 
|    51       Send node, |  | 
|    52       Element setter, |  | 
|    53       Element getter) { |  | 
|    54     assert(invariant(node, Elements.isUnresolved(setter), |  | 
|    55         message: "Unexpected erreneous compound setter: $setter.")); |  | 
|    56     if (getter.isStatic) { |  | 
|    57       if (getter.isGetter) { |  | 
|    58         return new CompoundAccessSemantics( |  | 
|    59             CompoundAccessKind.UNRESOLVED_STATIC_SETTER, getter, setter); |  | 
|    60       } else if (getter.isField) { |  | 
|    61         // TODO(johnniwinther): Handle const field separately. |  | 
|    62         assert(invariant(node, getter.isFinal || getter.isConst, |  | 
|    63             message: "Field expected to be final or const.")); |  | 
|    64         return new StaticAccess.finalStaticField(getter); |  | 
|    65       } else if (getter.isFunction) { |  | 
|    66         return new StaticAccess.staticMethod(getter); |  | 
|    67       } else { |  | 
|    68         return internalError(node, |  | 
|    69             "Unexpected erroneous static compound: getter=$getter"); |  | 
|    70       } |  | 
|    71     } else if (getter.isTopLevel) { |  | 
|    72       if (getter.isGetter) { |  | 
|    73         return new CompoundAccessSemantics( |  | 
|    74             CompoundAccessKind.UNRESOLVED_TOPLEVEL_SETTER, getter, setter); |  | 
|    75       } else if (getter.isField) { |  | 
|    76         // TODO(johnniwinther): Handle const field separately. |  | 
|    77         assert(invariant(node, getter.isFinal || getter.isConst, |  | 
|    78             message: "Field expected to be final or const.")); |  | 
|    79         return new StaticAccess.finalTopLevelField(getter); |  | 
|    80       } else if (getter.isFunction) { |  | 
|    81         return new StaticAccess.topLevelMethod(getter); |  | 
|    82       } else { |  | 
|    83         return internalError(node, |  | 
|    84             "Unexpected erroneous top level compound: getter=$getter"); |  | 
|    85       } |  | 
|    86     } else if (getter.isParameter) { |  | 
|    87       assert(invariant(node, getter.isFinal, |  | 
|    88           message: "Parameter expected to be final.")); |  | 
|    89       return new StaticAccess.finalParameter(getter); |  | 
|    90     } else if (getter.isLocal) { |  | 
|    91       if (getter.isVariable) { |  | 
|    92         // TODO(johnniwinther): Handle const variable separately. |  | 
|    93         assert(invariant(node, getter.isFinal || getter.isConst, |  | 
|    94             message: "Variable expected to be final or const.")); |  | 
|    95         return new StaticAccess.finalLocalVariable(getter); |  | 
|    96       } else if (getter.isFunction) { |  | 
|    97         return new StaticAccess.localFunction(getter); |  | 
|    98       } else { |  | 
|    99         return internalError(node, |  | 
|   100             "Unexpected erroneous local compound: getter=$getter"); |  | 
|   101       } |  | 
|   102     } else if (getter.isErroneous) { |  | 
|   103       return new StaticAccess.unresolved(getter); |  | 
|   104     } else { |  | 
|   105       return internalError(node, |  | 
|   106           "Unexpected erroneous compound: getter=$getter"); |  | 
|   107     } |  | 
|   108   } |  | 
|   109  |  | 
|   110   AccessSemantics handleStaticallyResolvedAccess( |  | 
|   111       Send node, |  | 
|   112       Element element, |  | 
|   113       Element getter, |  | 
|   114       {bool isCompound}) { |  | 
|   115     if (element == null) { |  | 
|   116       assert(invariant(node, isCompound, message: |  | 
|   117         "Non-compound static access without element.")); |  | 
|   118       assert(invariant(node, getter != null, message: |  | 
|   119         "Compound static access without element.")); |  | 
|   120       return handleCompoundErroneousSetterAccess(node, element, getter); |  | 
|   121     } |  | 
|   122     if (element.isErroneous) { |  | 
|   123       if (isCompound) { |  | 
|   124         return handleCompoundErroneousSetterAccess(node, element, getter); |  | 
|   125       } |  | 
|   126       return new StaticAccess.unresolved(element); |  | 
|   127     } else if (element.isParameter) { |  | 
|   128       if (element.isFinal) { |  | 
|   129         return new StaticAccess.finalParameter(element); |  | 
|   130       } else { |  | 
|   131         return new StaticAccess.parameter(element); |  | 
|   132       } |  | 
|   133     } else if (element.isLocal) { |  | 
|   134       if (element.isFunction) { |  | 
|   135         return new StaticAccess.localFunction(element); |  | 
|   136       } else if (element.isFinal || element.isConst) { |  | 
|   137         return new StaticAccess.finalLocalVariable(element); |  | 
|   138       } else { |  | 
|   139         return new StaticAccess.localVariable(element); |  | 
|   140       } |  | 
|   141     } else if (element.isStatic) { |  | 
|   142       if (element.isField) { |  | 
|   143         if (element.isFinal || element.isConst) { |  | 
|   144           // TODO(johnniwinther): Handle const field separately. |  | 
|   145           return new StaticAccess.finalStaticField(element); |  | 
|   146         } |  | 
|   147         return new StaticAccess.staticField(element); |  | 
|   148       } else if (element.isGetter) { |  | 
|   149         if (isCompound) { |  | 
|   150           return new CompoundAccessSemantics( |  | 
|   151               CompoundAccessKind.UNRESOLVED_STATIC_SETTER, element, null); |  | 
|   152         } |  | 
|   153         return new StaticAccess.staticGetter(element); |  | 
|   154       } else if (element.isSetter) { |  | 
|   155         if (getter != null) { |  | 
|   156           CompoundAccessKind accessKind; |  | 
|   157           if (getter.isErroneous) { |  | 
|   158             accessKind = CompoundAccessKind.UNRESOLVED_STATIC_GETTER; |  | 
|   159           } else if (getter.isAbstractField) { |  | 
|   160             AbstractFieldElement abstractField = getter; |  | 
|   161             if (abstractField.getter == null) { |  | 
|   162               accessKind = CompoundAccessKind.UNRESOLVED_STATIC_GETTER; |  | 
|   163             } else { |  | 
|   164               // TODO(johnniwinther): This might be dead code. |  | 
|   165               getter = abstractField.getter; |  | 
|   166               accessKind = CompoundAccessKind.STATIC_GETTER_SETTER; |  | 
|   167             } |  | 
|   168           } else if (getter.isGetter) { |  | 
|   169             accessKind = CompoundAccessKind.STATIC_GETTER_SETTER; |  | 
|   170           } else { |  | 
|   171             accessKind = CompoundAccessKind.STATIC_METHOD_SETTER; |  | 
|   172           } |  | 
|   173           return new CompoundAccessSemantics( |  | 
|   174               accessKind, getter, element); |  | 
|   175         } else { |  | 
|   176           return new StaticAccess.staticSetter(element); |  | 
|   177         } |  | 
|   178       } else { |  | 
|   179         return new StaticAccess.staticMethod(element); |  | 
|   180       } |  | 
|   181     } else if (element.isTopLevel) { |  | 
|   182       if (element.isField) { |  | 
|   183         if (element.isFinal || element.isConst) { |  | 
|   184           // TODO(johnniwinther): Handle const field separately. |  | 
|   185           return new StaticAccess.finalTopLevelField(element); |  | 
|   186         } |  | 
|   187         return new StaticAccess.topLevelField(element); |  | 
|   188       } else if (element.isGetter) { |  | 
|   189         return new StaticAccess.topLevelGetter(element); |  | 
|   190       } else if (element.isSetter) { |  | 
|   191         if (getter != null) { |  | 
|   192           CompoundAccessKind accessKind; |  | 
|   193           if (getter.isErroneous) { |  | 
|   194             accessKind = CompoundAccessKind.UNRESOLVED_TOPLEVEL_GETTER; |  | 
|   195           } else if (getter.isAbstractField) { |  | 
|   196             AbstractFieldElement abstractField = getter; |  | 
|   197             if (abstractField.getter == null) { |  | 
|   198               accessKind = CompoundAccessKind.UNRESOLVED_TOPLEVEL_GETTER; |  | 
|   199             } else { |  | 
|   200               // TODO(johnniwinther): This might be dead code. |  | 
|   201               getter = abstractField.getter; |  | 
|   202               accessKind = CompoundAccessKind.TOPLEVEL_GETTER_SETTER; |  | 
|   203             } |  | 
|   204           } else if (getter.isGetter) { |  | 
|   205             accessKind = CompoundAccessKind.TOPLEVEL_GETTER_SETTER; |  | 
|   206           } else { |  | 
|   207             accessKind = CompoundAccessKind.TOPLEVEL_METHOD_SETTER; |  | 
|   208           } |  | 
|   209           return new CompoundAccessSemantics( |  | 
|   210               accessKind, getter, element); |  | 
|   211         } else { |  | 
|   212           return new StaticAccess.topLevelSetter(element); |  | 
|   213         } |  | 
|   214       } else { |  | 
|   215         return new StaticAccess.topLevelMethod(element); |  | 
|   216       } |  | 
|   217     } else { |  | 
|   218       return internalError( |  | 
|   219           node, "Unhandled resolved property access: $element"); |  | 
|   220     } |  | 
|   221   } |  | 
|   222  |  | 
|   223   SendStructure computeSendStructure(Send node) { |  | 
|   224     SendStructure sendStructure = elements.getSendStructure(node); |  | 
|   225     if (sendStructure != null) { |  | 
|   226       return sendStructure; |  | 
|   227     } |  | 
|   228  |  | 
|   229     if (elements.isAssert(node)) { |  | 
|   230       return internalError(node, "Unexpected assert."); |  | 
|   231     } |  | 
|   232  |  | 
|   233     AssignmentOperator assignmentOperator; |  | 
|   234     BinaryOperator binaryOperator; |  | 
|   235     IncDecOperator incDecOperator; |  | 
|   236  |  | 
|   237     if (node.isOperator) { |  | 
|   238       String operatorText = node.selector.asOperator().source; |  | 
|   239       if (operatorText == 'is') { |  | 
|   240         return internalError(node, "Unexpected is test."); |  | 
|   241       } else if (operatorText == 'as') { |  | 
|   242         return internalError(node, "Unexpected as cast."); |  | 
|   243       } else if (operatorText == '&&') { |  | 
|   244         return internalError(node, "Unexpected logical and."); |  | 
|   245       } else if (operatorText == '||') { |  | 
|   246         return internalError(node, "Unexpected logical or."); |  | 
|   247       } else if (operatorText == '??') { |  | 
|   248         return internalError(node, "Unexpected if-null."); |  | 
|   249       } |  | 
|   250     } |  | 
|   251  |  | 
|   252     SendStructureKind kind; |  | 
|   253  |  | 
|   254     if (node.asSendSet() != null) { |  | 
|   255       SendSet sendSet = node.asSendSet(); |  | 
|   256       String operatorText = sendSet.assignmentOperator.source; |  | 
|   257       if (sendSet.isPrefix || sendSet.isPostfix) { |  | 
|   258         kind = sendSet.isPrefix |  | 
|   259             ? SendStructureKind.PREFIX |  | 
|   260             : SendStructureKind.POSTFIX; |  | 
|   261         incDecOperator = IncDecOperator.parse(operatorText); |  | 
|   262         if (incDecOperator == null) { |  | 
|   263           return internalError( |  | 
|   264               node, "No inc/dec operator for '$operatorText'."); |  | 
|   265         } |  | 
|   266       } else { |  | 
|   267         assignmentOperator = AssignmentOperator.parse(operatorText); |  | 
|   268         if (assignmentOperator != null) { |  | 
|   269           switch (assignmentOperator.kind) { |  | 
|   270             case AssignmentOperatorKind.ASSIGN: |  | 
|   271               kind = SendStructureKind.SET; |  | 
|   272               break; |  | 
|   273             default: |  | 
|   274               kind = SendStructureKind.COMPOUND; |  | 
|   275           } |  | 
|   276         } else { |  | 
|   277           return internalError( |  | 
|   278               node, "No assignment operator for '$operatorText'."); |  | 
|   279         } |  | 
|   280       } |  | 
|   281     } else if (!node.isPropertyAccess) { |  | 
|   282       kind = SendStructureKind.INVOKE; |  | 
|   283     } else { |  | 
|   284       kind = SendStructureKind.GET; |  | 
|   285     } |  | 
|   286  |  | 
|   287     if (node.isOperator) { |  | 
|   288       String operatorText = node.selector.asOperator().source; |  | 
|   289       if (node.arguments.isEmpty) { |  | 
|   290         return internalError(node, "Unexpected unary $operatorText."); |  | 
|   291       } else { |  | 
|   292         binaryOperator = BinaryOperator.parse(operatorText); |  | 
|   293         if (binaryOperator != null) { |  | 
|   294           switch (binaryOperator.kind) { |  | 
|   295             case BinaryOperatorKind.EQ: |  | 
|   296               kind = SendStructureKind.EQ; |  | 
|   297               return internalError(node, "Unexpected binary $kind."); |  | 
|   298             case BinaryOperatorKind.NOT_EQ: |  | 
|   299               kind = SendStructureKind.NOT_EQ; |  | 
|   300               return internalError(node, "Unexpected binary $kind."); |  | 
|   301             case BinaryOperatorKind.INDEX: |  | 
|   302               if (node.isPrefix) { |  | 
|   303                 kind = SendStructureKind.INDEX_PREFIX; |  | 
|   304               } else if (node.isPostfix) { |  | 
|   305                 kind = SendStructureKind.INDEX_POSTFIX; |  | 
|   306               } else if (node.arguments.tail.isEmpty) { |  | 
|   307                 // a[b] |  | 
|   308                 kind = SendStructureKind.INDEX; |  | 
|   309                 return internalError(node, "Unexpected binary $kind."); |  | 
|   310               } else { |  | 
|   311                 if (kind == SendStructureKind.COMPOUND) { |  | 
|   312                   // a[b] += c |  | 
|   313                   kind = SendStructureKind.COMPOUND_INDEX_SET; |  | 
|   314                 } else { |  | 
|   315                   // a[b] = c |  | 
|   316                   kind = SendStructureKind.INDEX_SET; |  | 
|   317                 } |  | 
|   318               } |  | 
|   319               break; |  | 
|   320             default: |  | 
|   321               kind = SendStructureKind.BINARY; |  | 
|   322               return internalError(node, "Unexpected binary $kind."); |  | 
|   323           } |  | 
|   324         } else { |  | 
|   325           return internalError( |  | 
|   326               node, "Unexpected invalid binary $operatorText."); |  | 
|   327         } |  | 
|   328       } |  | 
|   329     } |  | 
|   330     AccessSemantics semantics = computeAccessSemantics( |  | 
|   331         node, |  | 
|   332         isSet: kind == SendStructureKind.SET, |  | 
|   333         isInvoke: kind == SendStructureKind.INVOKE, |  | 
|   334         isCompound: kind == SendStructureKind.COMPOUND || |  | 
|   335                     kind == SendStructureKind.COMPOUND_INDEX_SET || |  | 
|   336                     kind == SendStructureKind.PREFIX || |  | 
|   337                     kind == SendStructureKind.POSTFIX || |  | 
|   338                     kind == SendStructureKind.INDEX_PREFIX || |  | 
|   339                     kind == SendStructureKind.INDEX_POSTFIX); |  | 
|   340     if (semantics == null) { |  | 
|   341       return internalError(node, 'No semantics for $node'); |  | 
|   342     } |  | 
|   343     Selector selector = elements.getSelector(node); |  | 
|   344     switch (kind) { |  | 
|   345       case SendStructureKind.GET: |  | 
|   346         return new GetStructure(semantics, selector); |  | 
|   347       case SendStructureKind.SET: |  | 
|   348         return new SetStructure(semantics, selector); |  | 
|   349       case SendStructureKind.INVOKE: |  | 
|   350         switch (semantics.kind) { |  | 
|   351           case AccessKind.STATIC_METHOD: |  | 
|   352           case AccessKind.SUPER_METHOD: |  | 
|   353           case AccessKind.TOPLEVEL_METHOD: |  | 
|   354             // TODO(johnniwinther): Should local function also be handled here? |  | 
|   355             FunctionElement function = semantics.element; |  | 
|   356             FunctionSignature signature = function.functionSignature; |  | 
|   357             if (!selector.callStructure.signatureApplies(signature)) { |  | 
|   358               return new IncompatibleInvokeStructure(semantics, selector); |  | 
|   359             } |  | 
|   360             break; |  | 
|   361           default: |  | 
|   362             break; |  | 
|   363         } |  | 
|   364         return new InvokeStructure(semantics, selector); |  | 
|   365       case SendStructureKind.UNARY: |  | 
|   366         return internalError(node, "Unexpected unary."); |  | 
|   367       case SendStructureKind.NOT: |  | 
|   368         return internalError(node, "Unexpected not."); |  | 
|   369       case SendStructureKind.BINARY: |  | 
|   370         return internalError(node, "Unexpected binary."); |  | 
|   371       case SendStructureKind.INDEX: |  | 
|   372         return internalError(node, "Unexpected index."); |  | 
|   373       case SendStructureKind.EQ: |  | 
|   374         return internalError(node, "Unexpected equals."); |  | 
|   375       case SendStructureKind.NOT_EQ: |  | 
|   376         return internalError(node, "Unexpected not equals."); |  | 
|   377       case SendStructureKind.COMPOUND: |  | 
|   378         Selector getterSelector = |  | 
|   379             elements.getGetterSelectorInComplexSendSet(node); |  | 
|   380         return new CompoundStructure( |  | 
|   381             semantics, |  | 
|   382             assignmentOperator, |  | 
|   383             getterSelector, |  | 
|   384             selector); |  | 
|   385       case SendStructureKind.INDEX_SET: |  | 
|   386         return new IndexSetStructure(semantics, selector); |  | 
|   387       case SendStructureKind.COMPOUND_INDEX_SET: |  | 
|   388         Selector getterSelector = |  | 
|   389             elements.getGetterSelectorInComplexSendSet(node); |  | 
|   390         return new CompoundIndexSetStructure( |  | 
|   391             semantics, |  | 
|   392             assignmentOperator, |  | 
|   393             getterSelector, |  | 
|   394             selector); |  | 
|   395       case SendStructureKind.INDEX_PREFIX: |  | 
|   396         Selector getterSelector = |  | 
|   397             elements.getGetterSelectorInComplexSendSet(node); |  | 
|   398         return new IndexPrefixStructure( |  | 
|   399             semantics, |  | 
|   400             incDecOperator, |  | 
|   401             getterSelector, |  | 
|   402             selector); |  | 
|   403       case SendStructureKind.INDEX_POSTFIX: |  | 
|   404         Selector getterSelector = |  | 
|   405             elements.getGetterSelectorInComplexSendSet(node); |  | 
|   406         return new IndexPostfixStructure( |  | 
|   407             semantics, |  | 
|   408             incDecOperator, |  | 
|   409             getterSelector, |  | 
|   410             selector); |  | 
|   411       case SendStructureKind.PREFIX: |  | 
|   412         Selector getterSelector = |  | 
|   413             elements.getGetterSelectorInComplexSendSet(node); |  | 
|   414         return new PrefixStructure( |  | 
|   415             semantics, |  | 
|   416             incDecOperator, |  | 
|   417             getterSelector, |  | 
|   418             selector); |  | 
|   419       case SendStructureKind.POSTFIX: |  | 
|   420         Selector getterSelector = |  | 
|   421             elements.getGetterSelectorInComplexSendSet(node); |  | 
|   422         return new PostfixStructure( |  | 
|   423             semantics, |  | 
|   424             incDecOperator, |  | 
|   425             getterSelector, |  | 
|   426             selector); |  | 
|   427     } |  | 
|   428   } |  | 
|   429  |  | 
|   430   AccessSemantics computeAccessSemantics(Send node, |  | 
|   431                                          {bool isSet: false, |  | 
|   432                                           bool isInvoke: false, |  | 
|   433                                           bool isCompound: false}) { |  | 
|   434     Element element = elements[node]; |  | 
|   435     Element getter = isCompound ? elements[node.selector] : null; |  | 
|   436     if (elements.isTypeLiteral(node)) { |  | 
|   437       DartType dartType = elements.getTypeLiteralType(node); |  | 
|   438       // TODO(johnniwinther): Handle deferred constants. There are runtime |  | 
|   439       // but not compile-time constants and should have their own |  | 
|   440       // [DeferredConstantExpression] class. |  | 
|   441       ConstantExpression constant = elements.getConstant( |  | 
|   442           isInvoke || isSet || isCompound ? node.selector : node); |  | 
|   443       switch (dartType.kind) { |  | 
|   444         case TypeKind.INTERFACE: |  | 
|   445           return new ConstantAccess.classTypeLiteral(constant); |  | 
|   446         case TypeKind.TYPEDEF: |  | 
|   447           return new ConstantAccess.typedefTypeLiteral(constant); |  | 
|   448         case TypeKind.TYPE_VARIABLE: |  | 
|   449           return new StaticAccess.typeParameterTypeLiteral(dartType.element); |  | 
|   450         case TypeKind.DYNAMIC: |  | 
|   451           return new ConstantAccess.dynamicTypeLiteral(constant); |  | 
|   452         default: |  | 
|   453           return internalError(node, "Unexpected type literal type: $dartType"); |  | 
|   454       } |  | 
|   455     } else if (node.isSuperCall) { |  | 
|   456       if (Elements.isUnresolved(element)) { |  | 
|   457         if (isCompound) { |  | 
|   458           if (Elements.isUnresolved(getter)) { |  | 
|   459             // TODO(johnniwinther): Ensure that [getter] is not null. This |  | 
|   460             // happens in the case of missing super getter. |  | 
|   461             return new StaticAccess.unresolvedSuper(element); |  | 
|   462           } else if (getter.isField) { |  | 
|   463             assert(invariant(node, getter.isFinal, |  | 
|   464                 message: "Super field expected to be final.")); |  | 
|   465             return new StaticAccess.superFinalField(getter); |  | 
|   466           } else if (getter.isFunction) { |  | 
|   467             if (node.isIndex) { |  | 
|   468               return new CompoundAccessSemantics( |  | 
|   469                   CompoundAccessKind.UNRESOLVED_SUPER_SETTER, getter, element); |  | 
|   470             } else { |  | 
|   471               return new StaticAccess.superMethod(getter); |  | 
|   472             } |  | 
|   473           } else { |  | 
|   474             return new CompoundAccessSemantics( |  | 
|   475                 CompoundAccessKind.UNRESOLVED_SUPER_SETTER, getter, element); |  | 
|   476           } |  | 
|   477         } else { |  | 
|   478           return new StaticAccess.unresolvedSuper(element); |  | 
|   479         } |  | 
|   480       } else if (isCompound && Elements.isUnresolved(getter)) { |  | 
|   481         // TODO(johnniwinther): Ensure that [getter] is not null. This happens |  | 
|   482         // in the case of missing super getter. |  | 
|   483         return new CompoundAccessSemantics( |  | 
|   484             CompoundAccessKind.UNRESOLVED_SUPER_GETTER, getter, element); |  | 
|   485       } else if (element.isField) { |  | 
|   486         if (getter != null && getter != element) { |  | 
|   487           CompoundAccessKind accessKind; |  | 
|   488           if (getter.isField) { |  | 
|   489             accessKind = CompoundAccessKind.SUPER_FIELD_FIELD; |  | 
|   490           } else if (getter.isGetter) { |  | 
|   491             accessKind = CompoundAccessKind.SUPER_GETTER_FIELD; |  | 
|   492           } else { |  | 
|   493             return internalError(node, |  | 
|   494                "Unsupported super call: $node : $element/$getter."); |  | 
|   495           } |  | 
|   496           return new CompoundAccessSemantics(accessKind, getter, element); |  | 
|   497         } else if (element.isFinal) { |  | 
|   498           return new StaticAccess.superFinalField(element); |  | 
|   499         } |  | 
|   500         return new StaticAccess.superField(element); |  | 
|   501       } else if (element.isGetter) { |  | 
|   502         return new StaticAccess.superGetter(element); |  | 
|   503       } else if (element.isSetter) { |  | 
|   504         if (getter != null) { |  | 
|   505           CompoundAccessKind accessKind; |  | 
|   506           if (getter.isField) { |  | 
|   507             accessKind = CompoundAccessKind.SUPER_FIELD_SETTER; |  | 
|   508           } else if (getter.isGetter) { |  | 
|   509             accessKind = CompoundAccessKind.SUPER_GETTER_SETTER; |  | 
|   510           } else { |  | 
|   511             accessKind = CompoundAccessKind.SUPER_METHOD_SETTER; |  | 
|   512           } |  | 
|   513           return new CompoundAccessSemantics(accessKind, getter, element); |  | 
|   514         } |  | 
|   515         return new StaticAccess.superSetter(element); |  | 
|   516       } else if (isCompound) { |  | 
|   517         return new CompoundAccessSemantics( |  | 
|   518             CompoundAccessKind.SUPER_GETTER_SETTER, getter, element); |  | 
|   519       } else { |  | 
|   520         return new StaticAccess.superMethod(element); |  | 
|   521       } |  | 
|   522     } else if (node.isConditional) { |  | 
|   523       // Conditional sends (e?.x) are treated as dynamic property reads because |  | 
|   524       // they are equivalent to do ((a) => a == null ? null : a.x)(e). If `e` is |  | 
|   525       // a type `A`, this is equivalent to write `(A).x`. |  | 
|   526       return const DynamicAccess.ifNotNullProperty(); |  | 
|   527     } else if (node.isOperator) { |  | 
|   528       return const DynamicAccess.dynamicProperty(); |  | 
|   529     } else if (Elements.isClosureSend(node, element)) { |  | 
|   530       if (element == null) { |  | 
|   531         if (node.selector.isThis()) { |  | 
|   532           return new DynamicAccess.thisAccess(); |  | 
|   533         } else { |  | 
|   534           return new DynamicAccess.expression(); |  | 
|   535         } |  | 
|   536       } else if (Elements.isErroneous(element)) { |  | 
|   537         return new StaticAccess.unresolved(element); |  | 
|   538       } else { |  | 
|   539         return handleStaticallyResolvedAccess( |  | 
|   540             node, element, getter, isCompound: isCompound); |  | 
|   541       } |  | 
|   542     } else { |  | 
|   543       bool isDynamicAccess(Element e) => e == null || e.isInstanceMember; |  | 
|   544  |  | 
|   545       if (isDynamicAccess(element) && |  | 
|   546            (!isCompound || isDynamicAccess(getter))) { |  | 
|   547         if (node.receiver == null || node.receiver.isThis()) { |  | 
|   548           return const DynamicAccess.thisProperty(); |  | 
|   549         } else { |  | 
|   550           return const DynamicAccess.dynamicProperty(); |  | 
|   551         } |  | 
|   552       } else if (element != null && element.impliesType) { |  | 
|   553         // TODO(johnniwinther): Provide an [ErroneousElement]. |  | 
|   554         // This happens for code like `C.this`. |  | 
|   555         return new StaticAccess.unresolved(null); |  | 
|   556       } else { |  | 
|   557         return handleStaticallyResolvedAccess( |  | 
|   558             node, element, getter, isCompound: isCompound); |  | 
|   559       } |  | 
|   560     } |  | 
|   561   } |  | 
|   562  |  | 
|   563   ConstructorAccessSemantics computeConstructorAccessSemantics( |    28   ConstructorAccessSemantics computeConstructorAccessSemantics( | 
|   564         ConstructorElement constructor, |    29         ConstructorElement constructor, | 
|   565         CallStructure callStructure, |    30         CallStructure callStructure, | 
|   566         DartType type, |    31         DartType type, | 
|   567         {bool mustBeConstant: false}) { |    32         {bool mustBeConstant: false}) { | 
|   568     if (mustBeConstant && !constructor.isConst) { |    33     if (mustBeConstant && !constructor.isConst) { | 
|   569       return new ConstructorAccessSemantics( |    34       return new ConstructorAccessSemantics( | 
|   570           ConstructorAccessKind.NON_CONSTANT_CONSTRUCTOR, constructor, type); |    35           ConstructorAccessKind.NON_CONSTANT_CONSTRUCTOR, constructor, type); | 
|   571     } |    36     } | 
|   572     if (constructor.isErroneous) { |    37     if (constructor.isErroneous) { | 
| (...skipping 431 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  1004       return internalError(node, "Unexpected variable $element."); |   469       return internalError(node, "Unexpected variable $element."); | 
|  1005     } |   470     } | 
|  1006     if (element.isConst) { |   471     if (element.isConst) { | 
|  1007       ConstantExpression constant = elements.getConstant(element.initializer); |   472       ConstantExpression constant = elements.getConstant(element.initializer); | 
|  1008       return new ConstantVariableStructure(kind, node, element, constant); |   473       return new ConstantVariableStructure(kind, node, element, constant); | 
|  1009     } else { |   474     } else { | 
|  1010       return new NonConstantVariableStructure(kind, node, element); |   475       return new NonConstantVariableStructure(kind, node, element); | 
|  1011     } |   476     } | 
|  1012   } |   477   } | 
|  1013 } |   478 } | 
| OLD | NEW |