| OLD | NEW | 
|---|
|  | (Empty) | 
| 1 // Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file |  | 
| 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. |  | 
| 4 |  | 
| 5 part of resolution; |  | 
| 6 |  | 
| 7 abstract class TreeElements { |  | 
| 8   AnalyzableElement get analyzedElement; |  | 
| 9   Iterable<Node> get superUses; |  | 
| 10 |  | 
| 11   /// Iterables of the dependencies that this [TreeElement] records of |  | 
| 12   /// [analyzedElement]. |  | 
| 13   Iterable<Element> get allElements; |  | 
| 14   void forEachConstantNode(f(Node n, ConstantExpression c)); |  | 
| 15 |  | 
| 16   /// A set of additional dependencies.  See [registerDependency] below. |  | 
| 17   Iterable<Element> get otherDependencies; |  | 
| 18 |  | 
| 19   Element operator[](Node node); |  | 
| 20 |  | 
| 21   // TODO(johnniwinther): Investigate whether [Node] could be a [Send]. |  | 
| 22   Selector getSelector(Node node); |  | 
| 23   Selector getGetterSelectorInComplexSendSet(SendSet node); |  | 
| 24   Selector getOperatorSelectorInComplexSendSet(SendSet node); |  | 
| 25   DartType getType(Node node); |  | 
| 26   void setSelector(Node node, Selector selector); |  | 
| 27   void setGetterSelectorInComplexSendSet(SendSet node, Selector selector); |  | 
| 28   void setOperatorSelectorInComplexSendSet(SendSet node, Selector selector); |  | 
| 29 |  | 
| 30   /// Returns the for-in loop variable for [node]. |  | 
| 31   Element getForInVariable(ForIn node); |  | 
| 32   Selector getIteratorSelector(ForIn node); |  | 
| 33   Selector getMoveNextSelector(ForIn node); |  | 
| 34   Selector getCurrentSelector(ForIn node); |  | 
| 35   void setIteratorSelector(ForIn node, Selector selector); |  | 
| 36   void setMoveNextSelector(ForIn node, Selector selector); |  | 
| 37   void setCurrentSelector(ForIn node, Selector selector); |  | 
| 38   void setConstant(Node node, ConstantExpression constant); |  | 
| 39   ConstantExpression getConstant(Node node); |  | 
| 40   bool isAssert(Send send); |  | 
| 41 |  | 
| 42   /// Returns the [FunctionElement] defined by [node]. |  | 
| 43   FunctionElement getFunctionDefinition(FunctionExpression node); |  | 
| 44 |  | 
| 45   /// Returns target constructor for the redirecting factory body [node]. |  | 
| 46   ConstructorElement getRedirectingTargetConstructor( |  | 
| 47       RedirectingFactoryBody node); |  | 
| 48 |  | 
| 49   /** |  | 
| 50    * Returns [:true:] if [node] is a type literal. |  | 
| 51    * |  | 
| 52    * Resolution marks this by setting the type on the node to be the |  | 
| 53    * type that the literal refers to. |  | 
| 54    */ |  | 
| 55   bool isTypeLiteral(Send node); |  | 
| 56 |  | 
| 57   /// Returns the type that the type literal [node] refers to. |  | 
| 58   DartType getTypeLiteralType(Send node); |  | 
| 59 |  | 
| 60   /// Register additional dependencies required by [analyzedElement]. |  | 
| 61   /// For example, elements that are used by a backend. |  | 
| 62   void registerDependency(Element element); |  | 
| 63 |  | 
| 64   /// Returns a list of nodes that potentially mutate [element] anywhere in its |  | 
| 65   /// scope. |  | 
| 66   List<Node> getPotentialMutations(VariableElement element); |  | 
| 67 |  | 
| 68   /// Returns a list of nodes that potentially mutate [element] in [node]. |  | 
| 69   List<Node> getPotentialMutationsIn(Node node, VariableElement element); |  | 
| 70 |  | 
| 71   /// Returns a list of nodes that potentially mutate [element] in a closure. |  | 
| 72   List<Node> getPotentialMutationsInClosure(VariableElement element); |  | 
| 73 |  | 
| 74   /// Returns a list of nodes that access [element] within a closure in [node]. |  | 
| 75   List<Node> getAccessesByClosureIn(Node node, VariableElement element); |  | 
| 76 |  | 
| 77   /// Returns the jump target defined by [node]. |  | 
| 78   JumpTarget getTargetDefinition(Node node); |  | 
| 79 |  | 
| 80   /// Returns the jump target of the [node]. |  | 
| 81   JumpTarget getTargetOf(GotoStatement node); |  | 
| 82 |  | 
| 83   /// Returns the label defined by [node]. |  | 
| 84   LabelDefinition getLabelDefinition(Label node); |  | 
| 85 |  | 
| 86   /// Returns the label that [node] targets. |  | 
| 87   LabelDefinition getTargetLabel(GotoStatement node); |  | 
| 88 } |  | 
| 89 |  | 
| 90 class TreeElementMapping implements TreeElements { |  | 
| 91   final AnalyzableElement analyzedElement; |  | 
| 92   Map<Spannable, Selector> _selectors; |  | 
| 93   Map<Node, DartType> _types; |  | 
| 94   Setlet<Node> _superUses; |  | 
| 95   Setlet<Element> _otherDependencies; |  | 
| 96   Map<Node, ConstantExpression> _constants; |  | 
| 97   Map<VariableElement, List<Node>> _potentiallyMutated; |  | 
| 98   Map<Node, Map<VariableElement, List<Node>>> _potentiallyMutatedIn; |  | 
| 99   Map<VariableElement, List<Node>> _potentiallyMutatedInClosure; |  | 
| 100   Map<Node, Map<VariableElement, List<Node>>> _accessedByClosureIn; |  | 
| 101   Setlet<Element> _elements; |  | 
| 102   Setlet<Send> _asserts; |  | 
| 103 |  | 
| 104   /// Map from nodes to the targets they define. |  | 
| 105   Map<Node, JumpTarget> _definedTargets; |  | 
| 106 |  | 
| 107   /// Map from goto statements to their targets. |  | 
| 108   Map<GotoStatement, JumpTarget> _usedTargets; |  | 
| 109 |  | 
| 110   /// Map from labels to their label definition. |  | 
| 111   Map<Label, LabelDefinition> _definedLabels; |  | 
| 112 |  | 
| 113   /// Map from labeled goto statements to the labels they target. |  | 
| 114   Map<GotoStatement, LabelDefinition> _targetLabels; |  | 
| 115 |  | 
| 116   final int hashCode = ++_hashCodeCounter; |  | 
| 117   static int _hashCodeCounter = 0; |  | 
| 118 |  | 
| 119   TreeElementMapping(this.analyzedElement); |  | 
| 120 |  | 
| 121   operator []=(Node node, Element element) { |  | 
| 122     assert(invariant(node, () { |  | 
| 123       FunctionExpression functionExpression = node.asFunctionExpression(); |  | 
| 124       if (functionExpression != null) { |  | 
| 125         return !functionExpression.modifiers.isExternal; |  | 
| 126       } |  | 
| 127       return true; |  | 
| 128     })); |  | 
| 129     // TODO(johnniwinther): Simplify this invariant to use only declarations in |  | 
| 130     // [TreeElements]. |  | 
| 131     assert(invariant(node, () { |  | 
| 132       if (!element.isErroneous && analyzedElement != null && element.isPatch) { |  | 
| 133         return analyzedElement.implementationLibrary.isPatch; |  | 
| 134       } |  | 
| 135       return true; |  | 
| 136     })); |  | 
| 137     // TODO(ahe): Investigate why the invariant below doesn't hold. |  | 
| 138     // assert(invariant(node, |  | 
| 139     //                  getTreeElement(node) == element || |  | 
| 140     //                  getTreeElement(node) == null, |  | 
| 141     //                  message: '${getTreeElement(node)}; $element')); |  | 
| 142 |  | 
| 143     if (_elements == null) { |  | 
| 144       _elements = new Setlet<Element>(); |  | 
| 145     } |  | 
| 146     _elements.add(element); |  | 
| 147     setTreeElement(node, element); |  | 
| 148   } |  | 
| 149 |  | 
| 150   operator [](Node node) => getTreeElement(node); |  | 
| 151 |  | 
| 152   void setType(Node node, DartType type) { |  | 
| 153     if (_types == null) { |  | 
| 154       _types = new Maplet<Node, DartType>(); |  | 
| 155     } |  | 
| 156     _types[node] = type; |  | 
| 157   } |  | 
| 158 |  | 
| 159   DartType getType(Node node) => _types != null ? _types[node] : null; |  | 
| 160 |  | 
| 161   Iterable<Node> get superUses { |  | 
| 162     return _superUses != null ? _superUses : const <Node>[]; |  | 
| 163   } |  | 
| 164 |  | 
| 165   void addSuperUse(Node node) { |  | 
| 166     if (_superUses == null) { |  | 
| 167       _superUses = new Setlet<Node>(); |  | 
| 168     } |  | 
| 169     _superUses.add(node); |  | 
| 170   } |  | 
| 171 |  | 
| 172   Selector _getSelector(Spannable node) { |  | 
| 173     return _selectors != null ? _selectors[node] : null; |  | 
| 174   } |  | 
| 175 |  | 
| 176   void _setSelector(Spannable node, Selector selector) { |  | 
| 177     if (_selectors == null) { |  | 
| 178       _selectors = new Maplet<Spannable, Selector>(); |  | 
| 179     } |  | 
| 180     _selectors[node] = selector; |  | 
| 181   } |  | 
| 182 |  | 
| 183   void setSelector(Node node, Selector selector) { |  | 
| 184     _setSelector(node, selector); |  | 
| 185   } |  | 
| 186 |  | 
| 187   Selector getSelector(Node node) => _getSelector(node); |  | 
| 188 |  | 
| 189   int getSelectorCount() => _selectors == null ? 0 : _selectors.length; |  | 
| 190 |  | 
| 191   void setGetterSelectorInComplexSendSet(SendSet node, Selector selector) { |  | 
| 192     _setSelector(node.selector, selector); |  | 
| 193   } |  | 
| 194 |  | 
| 195   Selector getGetterSelectorInComplexSendSet(SendSet node) { |  | 
| 196     return _getSelector(node.selector); |  | 
| 197   } |  | 
| 198 |  | 
| 199   void setOperatorSelectorInComplexSendSet(SendSet node, Selector selector) { |  | 
| 200     _setSelector(node.assignmentOperator, selector); |  | 
| 201   } |  | 
| 202 |  | 
| 203   Selector getOperatorSelectorInComplexSendSet(SendSet node) { |  | 
| 204     return _getSelector(node.assignmentOperator); |  | 
| 205   } |  | 
| 206 |  | 
| 207   // The following methods set selectors on the "for in" node. Since |  | 
| 208   // we're using three selectors, we need to use children of the node, |  | 
| 209   // and we arbitrarily choose which ones. |  | 
| 210 |  | 
| 211   void setIteratorSelector(ForIn node, Selector selector) { |  | 
| 212     _setSelector(node, selector); |  | 
| 213   } |  | 
| 214 |  | 
| 215   Selector getIteratorSelector(ForIn node) { |  | 
| 216     return _getSelector(node); |  | 
| 217   } |  | 
| 218 |  | 
| 219   void setMoveNextSelector(ForIn node, Selector selector) { |  | 
| 220     _setSelector(node.forToken, selector); |  | 
| 221   } |  | 
| 222 |  | 
| 223   Selector getMoveNextSelector(ForIn node) { |  | 
| 224     return _getSelector(node.forToken); |  | 
| 225   } |  | 
| 226 |  | 
| 227   void setCurrentSelector(ForIn node, Selector selector) { |  | 
| 228     _setSelector(node.inToken, selector); |  | 
| 229   } |  | 
| 230 |  | 
| 231   Selector getCurrentSelector(ForIn node) { |  | 
| 232     return _getSelector(node.inToken); |  | 
| 233   } |  | 
| 234 |  | 
| 235   Element getForInVariable(ForIn node) { |  | 
| 236     return this[node]; |  | 
| 237   } |  | 
| 238 |  | 
| 239   void setConstant(Node node, ConstantExpression constant) { |  | 
| 240     if (_constants == null) { |  | 
| 241       _constants = new Maplet<Node, ConstantExpression>(); |  | 
| 242     } |  | 
| 243     _constants[node] = constant; |  | 
| 244   } |  | 
| 245 |  | 
| 246   ConstantExpression getConstant(Node node) { |  | 
| 247     return _constants != null ? _constants[node] : null; |  | 
| 248   } |  | 
| 249 |  | 
| 250   bool isTypeLiteral(Send node) { |  | 
| 251     return getType(node) != null; |  | 
| 252   } |  | 
| 253 |  | 
| 254   DartType getTypeLiteralType(Send node) { |  | 
| 255     return getType(node); |  | 
| 256   } |  | 
| 257 |  | 
| 258   void registerDependency(Element element) { |  | 
| 259     if (element == null) return; |  | 
| 260     if (_otherDependencies == null) { |  | 
| 261       _otherDependencies = new Setlet<Element>(); |  | 
| 262     } |  | 
| 263     _otherDependencies.add(element.implementation); |  | 
| 264   } |  | 
| 265 |  | 
| 266   Iterable<Element> get otherDependencies { |  | 
| 267     return _otherDependencies != null ? _otherDependencies : const <Element>[]; |  | 
| 268   } |  | 
| 269 |  | 
| 270   List<Node> getPotentialMutations(VariableElement element) { |  | 
| 271     if (_potentiallyMutated == null) return const <Node>[]; |  | 
| 272     List<Node> mutations = _potentiallyMutated[element]; |  | 
| 273     if (mutations == null) return const <Node>[]; |  | 
| 274     return mutations; |  | 
| 275   } |  | 
| 276 |  | 
| 277   void registerPotentialMutation(VariableElement element, Node mutationNode) { |  | 
| 278     if (_potentiallyMutated == null) { |  | 
| 279       _potentiallyMutated = new Maplet<VariableElement, List<Node>>(); |  | 
| 280     } |  | 
| 281     _potentiallyMutated.putIfAbsent(element, () => <Node>[]).add(mutationNode); |  | 
| 282   } |  | 
| 283 |  | 
| 284   List<Node> getPotentialMutationsIn(Node node, VariableElement element) { |  | 
| 285     if (_potentiallyMutatedIn == null) return const <Node>[]; |  | 
| 286     Map<VariableElement, List<Node>> mutationsIn = _potentiallyMutatedIn[node]; |  | 
| 287     if (mutationsIn == null) return const <Node>[]; |  | 
| 288     List<Node> mutations = mutationsIn[element]; |  | 
| 289     if (mutations == null) return const <Node>[]; |  | 
| 290     return mutations; |  | 
| 291   } |  | 
| 292 |  | 
| 293   void registerPotentialMutationIn(Node contextNode, VariableElement element, |  | 
| 294                                     Node mutationNode) { |  | 
| 295     if (_potentiallyMutatedIn == null) { |  | 
| 296       _potentiallyMutatedIn = |  | 
| 297           new Maplet<Node, Map<VariableElement, List<Node>>>(); |  | 
| 298     } |  | 
| 299     Map<VariableElement, List<Node>> mutationMap = |  | 
| 300         _potentiallyMutatedIn.putIfAbsent(contextNode, |  | 
| 301           () => new Maplet<VariableElement, List<Node>>()); |  | 
| 302     mutationMap.putIfAbsent(element, () => <Node>[]).add(mutationNode); |  | 
| 303   } |  | 
| 304 |  | 
| 305   List<Node> getPotentialMutationsInClosure(VariableElement element) { |  | 
| 306     if (_potentiallyMutatedInClosure == null) return const <Node>[]; |  | 
| 307     List<Node> mutations = _potentiallyMutatedInClosure[element]; |  | 
| 308     if (mutations == null) return const <Node>[]; |  | 
| 309     return mutations; |  | 
| 310   } |  | 
| 311 |  | 
| 312   void registerPotentialMutationInClosure(VariableElement element, |  | 
| 313                                           Node mutationNode) { |  | 
| 314     if (_potentiallyMutatedInClosure == null) { |  | 
| 315       _potentiallyMutatedInClosure = new Maplet<VariableElement, List<Node>>(); |  | 
| 316     } |  | 
| 317     _potentiallyMutatedInClosure.putIfAbsent( |  | 
| 318         element, () => <Node>[]).add(mutationNode); |  | 
| 319   } |  | 
| 320 |  | 
| 321   List<Node> getAccessesByClosureIn(Node node, VariableElement element) { |  | 
| 322     if (_accessedByClosureIn == null) return const <Node>[]; |  | 
| 323     Map<VariableElement, List<Node>> accessesIn = _accessedByClosureIn[node]; |  | 
| 324     if (accessesIn == null) return const <Node>[]; |  | 
| 325     List<Node> accesses = accessesIn[element]; |  | 
| 326     if (accesses == null) return const <Node>[]; |  | 
| 327     return accesses; |  | 
| 328   } |  | 
| 329 |  | 
| 330   void setAccessedByClosureIn(Node contextNode, VariableElement element, |  | 
| 331                               Node accessNode) { |  | 
| 332     if (_accessedByClosureIn == null) { |  | 
| 333       _accessedByClosureIn = new Map<Node, Map<VariableElement, List<Node>>>(); |  | 
| 334     } |  | 
| 335     Map<VariableElement, List<Node>> accessMap = |  | 
| 336         _accessedByClosureIn.putIfAbsent(contextNode, |  | 
| 337           () => new Maplet<VariableElement, List<Node>>()); |  | 
| 338     accessMap.putIfAbsent(element, () => <Node>[]).add(accessNode); |  | 
| 339   } |  | 
| 340 |  | 
| 341   String toString() => 'TreeElementMapping($analyzedElement)'; |  | 
| 342 |  | 
| 343   Iterable<Element> get allElements { |  | 
| 344     return _elements != null ? _elements : const <Element>[]; |  | 
| 345   } |  | 
| 346 |  | 
| 347   void forEachConstantNode(f(Node n, ConstantExpression c)) { |  | 
| 348     if (_constants != null) { |  | 
| 349       _constants.forEach(f); |  | 
| 350     } |  | 
| 351   } |  | 
| 352 |  | 
| 353   void setAssert(Send node) { |  | 
| 354     if (_asserts == null) { |  | 
| 355       _asserts = new Setlet<Send>(); |  | 
| 356     } |  | 
| 357     _asserts.add(node); |  | 
| 358   } |  | 
| 359 |  | 
| 360   bool isAssert(Send node) { |  | 
| 361     return _asserts != null && _asserts.contains(node); |  | 
| 362   } |  | 
| 363 |  | 
| 364   FunctionElement getFunctionDefinition(FunctionExpression node) { |  | 
| 365     return this[node]; |  | 
| 366   } |  | 
| 367 |  | 
| 368   ConstructorElement getRedirectingTargetConstructor( |  | 
| 369       RedirectingFactoryBody node) { |  | 
| 370     return this[node]; |  | 
| 371   } |  | 
| 372 |  | 
| 373   void defineTarget(Node node, JumpTarget target) { |  | 
| 374     if (_definedTargets == null) { |  | 
| 375       _definedTargets = new Maplet<Node, JumpTarget>(); |  | 
| 376     } |  | 
| 377     _definedTargets[node] = target; |  | 
| 378   } |  | 
| 379 |  | 
| 380   void undefineTarget(Node node) { |  | 
| 381     if (_definedTargets != null) { |  | 
| 382       _definedTargets.remove(node); |  | 
| 383       if (_definedTargets.isEmpty) { |  | 
| 384         _definedTargets = null; |  | 
| 385       } |  | 
| 386     } |  | 
| 387   } |  | 
| 388 |  | 
| 389   JumpTarget getTargetDefinition(Node node) { |  | 
| 390     return _definedTargets != null ? _definedTargets[node] : null; |  | 
| 391   } |  | 
| 392 |  | 
| 393   void registerTargetOf(GotoStatement node, JumpTarget target) { |  | 
| 394     if (_usedTargets == null) { |  | 
| 395       _usedTargets = new Maplet<GotoStatement, JumpTarget>(); |  | 
| 396     } |  | 
| 397     _usedTargets[node] = target; |  | 
| 398   } |  | 
| 399 |  | 
| 400   JumpTarget getTargetOf(GotoStatement node) { |  | 
| 401     return _usedTargets != null ? _usedTargets[node] : null; |  | 
| 402   } |  | 
| 403 |  | 
| 404   void defineLabel(Label label, LabelDefinition target) { |  | 
| 405     if (_definedLabels == null) { |  | 
| 406       _definedLabels = new Maplet<Label, LabelDefinition>(); |  | 
| 407     } |  | 
| 408     _definedLabels[label] = target; |  | 
| 409   } |  | 
| 410 |  | 
| 411   void undefineLabel(Label label) { |  | 
| 412     if (_definedLabels != null) { |  | 
| 413       _definedLabels.remove(label); |  | 
| 414       if (_definedLabels.isEmpty) { |  | 
| 415         _definedLabels = null; |  | 
| 416       } |  | 
| 417     } |  | 
| 418   } |  | 
| 419 |  | 
| 420   LabelDefinition getLabelDefinition(Label label) { |  | 
| 421     return _definedLabels != null ? _definedLabels[label] : null; |  | 
| 422   } |  | 
| 423 |  | 
| 424   void registerTargetLabel(GotoStatement node, LabelDefinition label) { |  | 
| 425     assert(node.target != null); |  | 
| 426     if (_targetLabels == null) { |  | 
| 427       _targetLabels = new Maplet<GotoStatement, LabelDefinition>(); |  | 
| 428     } |  | 
| 429     _targetLabels[node] = label; |  | 
| 430   } |  | 
| 431 |  | 
| 432   LabelDefinition getTargetLabel(GotoStatement node) { |  | 
| 433     assert(node.target != null); |  | 
| 434     return _targetLabels != null ? _targetLabels[node] : null; |  | 
| 435   } |  | 
| 436 } |  | 
| 437 |  | 
| 438 class ResolverTask extends CompilerTask { |  | 
| 439   final ConstantCompiler constantCompiler; |  | 
| 440 |  | 
| 441   ResolverTask(Compiler compiler, this.constantCompiler) : super(compiler); |  | 
| 442 |  | 
| 443   String get name => 'Resolver'; |  | 
| 444 |  | 
| 445   TreeElements resolve(Element element) { |  | 
| 446     return measure(() { |  | 
| 447       if (Elements.isErroneousElement(element)) return null; |  | 
| 448 |  | 
| 449       processMetadata([result]) { |  | 
| 450         for (MetadataAnnotation metadata in element.metadata) { |  | 
| 451           metadata.ensureResolved(compiler); |  | 
| 452         } |  | 
| 453         return result; |  | 
| 454       } |  | 
| 455 |  | 
| 456       ElementKind kind = element.kind; |  | 
| 457       if (identical(kind, ElementKind.GENERATIVE_CONSTRUCTOR) || |  | 
| 458           identical(kind, ElementKind.FUNCTION) || |  | 
| 459           identical(kind, ElementKind.GETTER) || |  | 
| 460           identical(kind, ElementKind.SETTER)) { |  | 
| 461         return processMetadata(resolveMethodElement(element)); |  | 
| 462       } |  | 
| 463 |  | 
| 464       if (identical(kind, ElementKind.FIELD)) { |  | 
| 465         return processMetadata(resolveField(element)); |  | 
| 466       } |  | 
| 467       if (element.isClass) { |  | 
| 468         ClassElement cls = element; |  | 
| 469         cls.ensureResolved(compiler); |  | 
| 470         return processMetadata(); |  | 
| 471       } else if (element.isTypedef) { |  | 
| 472         TypedefElement typdef = element; |  | 
| 473         return processMetadata(resolveTypedef(typdef)); |  | 
| 474       } |  | 
| 475 |  | 
| 476       compiler.unimplemented(element, "resolve($element)"); |  | 
| 477     }); |  | 
| 478   } |  | 
| 479 |  | 
| 480   void resolveRedirectingConstructor(InitializerResolver resolver, |  | 
| 481                                      Node node, |  | 
| 482                                      FunctionElement constructor, |  | 
| 483                                      FunctionElement redirection) { |  | 
| 484     assert(invariant(node, constructor.isImplementation, |  | 
| 485         message: 'Redirecting constructors must be resolved on implementation ' |  | 
| 486                  'elements.')); |  | 
| 487     Setlet<FunctionElement> seen = new Setlet<FunctionElement>(); |  | 
| 488     seen.add(constructor); |  | 
| 489     while (redirection != null) { |  | 
| 490       // Ensure that we follow redirections through implementation elements. |  | 
| 491       redirection = redirection.implementation; |  | 
| 492       if (seen.contains(redirection)) { |  | 
| 493         resolver.visitor.error(node, MessageKind.REDIRECTING_CONSTRUCTOR_CYCLE); |  | 
| 494         return; |  | 
| 495       } |  | 
| 496       seen.add(redirection); |  | 
| 497       redirection = resolver.visitor.resolveConstructorRedirection(redirection); |  | 
| 498     } |  | 
| 499   } |  | 
| 500 |  | 
| 501   void checkMatchingPatchParameters(FunctionElement origin, |  | 
| 502                                     Link<Element> originParameters, |  | 
| 503                                     Link<Element> patchParameters) { |  | 
| 504     while (!originParameters.isEmpty) { |  | 
| 505       ParameterElementX originParameter = originParameters.head; |  | 
| 506       ParameterElementX patchParameter = patchParameters.head; |  | 
| 507       // TODO(johnniwinther): Remove the conditional patching when we never |  | 
| 508       // resolve the same method twice. |  | 
| 509       if (!originParameter.isPatched) { |  | 
| 510         originParameter.applyPatch(patchParameter); |  | 
| 511       } else { |  | 
| 512         assert(invariant(origin, originParameter.patch == patchParameter, |  | 
| 513                message: "Inconsistent repatch of $originParameter.")); |  | 
| 514       } |  | 
| 515       DartType originParameterType = originParameter.computeType(compiler); |  | 
| 516       DartType patchParameterType = patchParameter.computeType(compiler); |  | 
| 517       if (originParameterType != patchParameterType) { |  | 
| 518         compiler.reportError( |  | 
| 519             originParameter.parseNode(compiler), |  | 
| 520             MessageKind.PATCH_PARAMETER_TYPE_MISMATCH, |  | 
| 521             {'methodName': origin.name, |  | 
| 522              'parameterName': originParameter.name, |  | 
| 523              'originParameterType': originParameterType, |  | 
| 524              'patchParameterType': patchParameterType}); |  | 
| 525         compiler.reportInfo(patchParameter, |  | 
| 526             MessageKind.PATCH_POINT_TO_PARAMETER, |  | 
| 527             {'parameterName': patchParameter.name}); |  | 
| 528       } else { |  | 
| 529         // Hack: Use unparser to test parameter equality. This only works |  | 
| 530         // because we are restricting patch uses and the approach cannot be used |  | 
| 531         // elsewhere. |  | 
| 532 |  | 
| 533         // The node contains the type, so there is a potential overlap. |  | 
| 534         // Therefore we only check the text if the types are identical. |  | 
| 535         String originParameterText = |  | 
| 536             originParameter.parseNode(compiler).toString(); |  | 
| 537         String patchParameterText = |  | 
| 538             patchParameter.parseNode(compiler).toString(); |  | 
| 539         if (originParameterText != patchParameterText |  | 
| 540             // We special case the list constructor because of the |  | 
| 541             // optional parameter. |  | 
| 542             && origin != compiler.unnamedListConstructor) { |  | 
| 543           compiler.reportError( |  | 
| 544               originParameter.parseNode(compiler), |  | 
| 545               MessageKind.PATCH_PARAMETER_MISMATCH, |  | 
| 546               {'methodName': origin.name, |  | 
| 547                'originParameter': originParameterText, |  | 
| 548                'patchParameter': patchParameterText}); |  | 
| 549           compiler.reportInfo(patchParameter, |  | 
| 550               MessageKind.PATCH_POINT_TO_PARAMETER, |  | 
| 551               {'parameterName': patchParameter.name}); |  | 
| 552         } |  | 
| 553       } |  | 
| 554 |  | 
| 555       originParameters = originParameters.tail; |  | 
| 556       patchParameters = patchParameters.tail; |  | 
| 557     } |  | 
| 558   } |  | 
| 559 |  | 
| 560   void checkMatchingPatchSignatures(FunctionElement origin, |  | 
| 561                                     FunctionElement patch) { |  | 
| 562     // TODO(johnniwinther): Show both origin and patch locations on errors. |  | 
| 563     FunctionExpression originTree = origin.node; |  | 
| 564     FunctionSignature originSignature = origin.functionSignature; |  | 
| 565     FunctionExpression patchTree = patch.node; |  | 
| 566     FunctionSignature patchSignature = patch.functionSignature; |  | 
| 567 |  | 
| 568     if (originSignature.type.returnType != patchSignature.type.returnType) { |  | 
| 569       compiler.withCurrentElement(patch, () { |  | 
| 570         Node errorNode = |  | 
| 571             patchTree.returnType != null ? patchTree.returnType : patchTree; |  | 
| 572         error(errorNode, MessageKind.PATCH_RETURN_TYPE_MISMATCH, |  | 
| 573               {'methodName': origin.name, |  | 
| 574                'originReturnType': originSignature.type.returnType, |  | 
| 575                'patchReturnType': patchSignature.type.returnType}); |  | 
| 576       }); |  | 
| 577     } |  | 
| 578     if (originSignature.requiredParameterCount != |  | 
| 579         patchSignature.requiredParameterCount) { |  | 
| 580       compiler.withCurrentElement(patch, () { |  | 
| 581         error(patchTree, |  | 
| 582               MessageKind.PATCH_REQUIRED_PARAMETER_COUNT_MISMATCH, |  | 
| 583               {'methodName': origin.name, |  | 
| 584                'originParameterCount': originSignature.requiredParameterCount, |  | 
| 585                'patchParameterCount': patchSignature.requiredParameterCount}); |  | 
| 586       }); |  | 
| 587     } else { |  | 
| 588       checkMatchingPatchParameters(origin, |  | 
| 589                                    originSignature.requiredParameters, |  | 
| 590                                    patchSignature.requiredParameters); |  | 
| 591     } |  | 
| 592     if (originSignature.optionalParameterCount != 0 && |  | 
| 593         patchSignature.optionalParameterCount != 0) { |  | 
| 594       if (originSignature.optionalParametersAreNamed != |  | 
| 595           patchSignature.optionalParametersAreNamed) { |  | 
| 596         compiler.withCurrentElement(patch, () { |  | 
| 597           error(patchTree, |  | 
| 598                 MessageKind.PATCH_OPTIONAL_PARAMETER_NAMED_MISMATCH, |  | 
| 599                 {'methodName': origin.name}); |  | 
| 600         }); |  | 
| 601       } |  | 
| 602     } |  | 
| 603     if (originSignature.optionalParameterCount != |  | 
| 604         patchSignature.optionalParameterCount) { |  | 
| 605       compiler.withCurrentElement(patch, () { |  | 
| 606         error(patchTree, |  | 
| 607               MessageKind.PATCH_OPTIONAL_PARAMETER_COUNT_MISMATCH, |  | 
| 608               {'methodName': origin.name, |  | 
| 609                'originParameterCount': originSignature.optionalParameterCount, |  | 
| 610                'patchParameterCount': patchSignature.optionalParameterCount}); |  | 
| 611       }); |  | 
| 612     } else { |  | 
| 613       checkMatchingPatchParameters(origin, |  | 
| 614                                    originSignature.optionalParameters, |  | 
| 615                                    patchSignature.optionalParameters); |  | 
| 616     } |  | 
| 617   } |  | 
| 618 |  | 
| 619   TreeElements resolveMethodElement(FunctionElementX element) { |  | 
| 620     assert(invariant(element, element.isDeclaration)); |  | 
| 621     return compiler.withCurrentElement(element, () { |  | 
| 622       bool isConstructor = |  | 
| 623           identical(element.kind, ElementKind.GENERATIVE_CONSTRUCTOR); |  | 
| 624       if (compiler.enqueuer.resolution.hasBeenResolved(element)) { |  | 
| 625         // TODO(karlklose): Remove the check for [isConstructor]. [elememts] |  | 
| 626         // should never be non-null, not even for constructors. |  | 
| 627         assert(invariant(element, element.isConstructor, |  | 
| 628             message: 'Non-constructor element $element ' |  | 
| 629                      'has already been analyzed.')); |  | 
| 630         return element.resolvedAst.elements; |  | 
| 631       } |  | 
| 632       if (element.isSynthesized) { |  | 
| 633         if (isConstructor) { |  | 
| 634           ResolutionRegistry registry = |  | 
| 635               new ResolutionRegistry(compiler, element); |  | 
| 636           ConstructorElement constructor = element.asFunctionElement(); |  | 
| 637           ConstructorElement target = constructor.definingConstructor; |  | 
| 638           // Ensure the signature of the synthesized element is |  | 
| 639           // resolved. This is the only place where the resolver is |  | 
| 640           // seeing this element. |  | 
| 641           element.computeSignature(compiler); |  | 
| 642           if (!target.isErroneous) { |  | 
| 643             registry.registerStaticUse(target); |  | 
| 644             registry.registerImplicitSuperCall(target); |  | 
| 645           } |  | 
| 646           return registry.mapping; |  | 
| 647         } else { |  | 
| 648           assert(element.isDeferredLoaderGetter); |  | 
| 649           return _ensureTreeElements(element); |  | 
| 650         } |  | 
| 651       } |  | 
| 652       element.parseNode(compiler); |  | 
| 653       element.computeType(compiler); |  | 
| 654       if (element.isPatched) { |  | 
| 655         FunctionElementX patch = element.patch; |  | 
| 656         compiler.withCurrentElement(patch, () { |  | 
| 657           patch.parseNode(compiler); |  | 
| 658           patch.computeType(compiler); |  | 
| 659         }); |  | 
| 660         checkMatchingPatchSignatures(element, patch); |  | 
| 661         element = patch; |  | 
| 662       } |  | 
| 663       return compiler.withCurrentElement(element, () { |  | 
| 664         FunctionExpression tree = element.node; |  | 
| 665         if (tree.modifiers.isExternal) { |  | 
| 666           error(tree, MessageKind.PATCH_EXTERNAL_WITHOUT_IMPLEMENTATION); |  | 
| 667           return null; |  | 
| 668         } |  | 
| 669         if (isConstructor || element.isFactoryConstructor) { |  | 
| 670           if (tree.returnType != null) { |  | 
| 671             error(tree, MessageKind.CONSTRUCTOR_WITH_RETURN_TYPE); |  | 
| 672           } |  | 
| 673           if (element.modifiers.isConst && |  | 
| 674               tree.hasBody() && |  | 
| 675               !tree.isRedirectingFactory) { |  | 
| 676             compiler.reportError(tree, MessageKind.CONST_CONSTRUCTOR_HAS_BODY); |  | 
| 677           } |  | 
| 678         } |  | 
| 679 |  | 
| 680         ResolverVisitor visitor = visitorFor(element); |  | 
| 681         ResolutionRegistry registry = visitor.registry; |  | 
| 682         registry.defineFunction(tree, element); |  | 
| 683         visitor.setupFunction(tree, element); |  | 
| 684 |  | 
| 685         if (isConstructor && !element.isForwardingConstructor) { |  | 
| 686           // Even if there is no initializer list we still have to do the |  | 
| 687           // resolution in case there is an implicit super constructor call. |  | 
| 688           InitializerResolver resolver = new InitializerResolver(visitor); |  | 
| 689           FunctionElement redirection = |  | 
| 690               resolver.resolveInitializers(element, tree); |  | 
| 691           if (redirection != null) { |  | 
| 692             resolveRedirectingConstructor(resolver, tree, element, redirection); |  | 
| 693           } |  | 
| 694         } else if (element.isForwardingConstructor) { |  | 
| 695           // Initializers will be checked on the original constructor. |  | 
| 696         } else if (tree.initializers != null) { |  | 
| 697           error(tree, MessageKind.FUNCTION_WITH_INITIALIZER); |  | 
| 698         } |  | 
| 699 |  | 
| 700         if (!compiler.analyzeSignaturesOnly || tree.isRedirectingFactory) { |  | 
| 701           // We need to analyze the redirecting factory bodies to ensure that |  | 
| 702           // we can analyze compile-time constants. |  | 
| 703           visitor.visit(tree.body); |  | 
| 704         } |  | 
| 705 |  | 
| 706         // Get the resolution tree and check that the resolved |  | 
| 707         // function doesn't use 'super' if it is mixed into another |  | 
| 708         // class. This is the part of the 'super' mixin check that |  | 
| 709         // happens when a function is resolved after the mixin |  | 
| 710         // application has been performed. |  | 
| 711         TreeElements resolutionTree = registry.mapping; |  | 
| 712         ClassElement enclosingClass = element.enclosingClass; |  | 
| 713         if (enclosingClass != null) { |  | 
| 714           // TODO(johnniwinther): Find another way to obtain mixin uses. |  | 
| 715           Iterable<MixinApplicationElement> mixinUses = |  | 
| 716               compiler.world.allMixinUsesOf(enclosingClass); |  | 
| 717           ClassElement mixin = enclosingClass; |  | 
| 718           for (MixinApplicationElement mixinApplication in mixinUses) { |  | 
| 719             checkMixinSuperUses(resolutionTree, mixinApplication, mixin); |  | 
| 720           } |  | 
| 721         } |  | 
| 722         return resolutionTree; |  | 
| 723       }); |  | 
| 724     }); |  | 
| 725   } |  | 
| 726 |  | 
| 727   /// Creates a [ResolverVisitor] for resolving an AST in context of [element]. |  | 
| 728   /// If [useEnclosingScope] is `true` then the initial scope of the visitor |  | 
| 729   /// does not include inner scope of [element]. |  | 
| 730   /// |  | 
| 731   /// This method should only be used by this library (or tests of |  | 
| 732   /// this library). |  | 
| 733   ResolverVisitor visitorFor(Element element, {bool useEnclosingScope: false}) { |  | 
| 734     return new ResolverVisitor(compiler, element, |  | 
| 735         new ResolutionRegistry(compiler, element), |  | 
| 736         useEnclosingScope: useEnclosingScope); |  | 
| 737   } |  | 
| 738 |  | 
| 739   TreeElements resolveField(FieldElementX element) { |  | 
| 740     VariableDefinitions tree = element.parseNode(compiler); |  | 
| 741     if(element.modifiers.isStatic && element.isTopLevel) { |  | 
| 742       error(element.modifiers.getStatic(), |  | 
| 743             MessageKind.TOP_LEVEL_VARIABLE_DECLARED_STATIC); |  | 
| 744     } |  | 
| 745     ResolverVisitor visitor = visitorFor(element); |  | 
| 746     ResolutionRegistry registry = visitor.registry; |  | 
| 747     // TODO(johnniwinther): Maybe remove this when placeholderCollector migrates |  | 
| 748     // to the backend ast. |  | 
| 749     registry.defineElement(tree.definitions.nodes.head, element); |  | 
| 750     // TODO(johnniwinther): Share the resolved type between all variables |  | 
| 751     // declared in the same declaration. |  | 
| 752     if (tree.type != null) { |  | 
| 753       element.variables.type = visitor.resolveTypeAnnotation(tree.type); |  | 
| 754     } else { |  | 
| 755       element.variables.type = const DynamicType(); |  | 
| 756     } |  | 
| 757 |  | 
| 758     Expression initializer = element.initializer; |  | 
| 759     Modifiers modifiers = element.modifiers; |  | 
| 760     if (initializer != null) { |  | 
| 761       // TODO(johnniwinther): Avoid analyzing initializers if |  | 
| 762       // [Compiler.analyzeSignaturesOnly] is set. |  | 
| 763       visitor.visit(initializer); |  | 
| 764     } else if (modifiers.isConst) { |  | 
| 765       compiler.reportError(element, MessageKind.CONST_WITHOUT_INITIALIZER); |  | 
| 766     } else if (modifiers.isFinal && !element.isInstanceMember) { |  | 
| 767       compiler.reportError(element, MessageKind.FINAL_WITHOUT_INITIALIZER); |  | 
| 768     } else { |  | 
| 769       registry.registerInstantiatedClass(compiler.nullClass); |  | 
| 770     } |  | 
| 771 |  | 
| 772     if (Elements.isStaticOrTopLevelField(element)) { |  | 
| 773       visitor.addDeferredAction(element, () { |  | 
| 774         if (element.modifiers.isConst) { |  | 
| 775           constantCompiler.compileConstant(element); |  | 
| 776         } else { |  | 
| 777           constantCompiler.compileVariable(element); |  | 
| 778         } |  | 
| 779       }); |  | 
| 780       if (initializer != null) { |  | 
| 781         if (!element.modifiers.isConst) { |  | 
| 782           // TODO(johnniwinther): Determine the const-ness eagerly to avoid |  | 
| 783           // unnecessary registrations. |  | 
| 784           registry.registerLazyField(); |  | 
| 785         } |  | 
| 786       } |  | 
| 787     } |  | 
| 788 |  | 
| 789     // Perform various checks as side effect of "computing" the type. |  | 
| 790     element.computeType(compiler); |  | 
| 791 |  | 
| 792     return registry.mapping; |  | 
| 793   } |  | 
| 794 |  | 
| 795   DartType resolveTypeAnnotation(Element element, TypeAnnotation annotation) { |  | 
| 796     DartType type = resolveReturnType(element, annotation); |  | 
| 797     if (type.isVoid) { |  | 
| 798       error(annotation, MessageKind.VOID_NOT_ALLOWED); |  | 
| 799     } |  | 
| 800     return type; |  | 
| 801   } |  | 
| 802 |  | 
| 803   DartType resolveReturnType(Element element, TypeAnnotation annotation) { |  | 
| 804     if (annotation == null) return const DynamicType(); |  | 
| 805     DartType result = visitorFor(element).resolveTypeAnnotation(annotation); |  | 
| 806     if (result == null) { |  | 
| 807       // TODO(karklose): warning. |  | 
| 808       return const DynamicType(); |  | 
| 809     } |  | 
| 810     return result; |  | 
| 811   } |  | 
| 812 |  | 
| 813   void resolveRedirectionChain(ConstructorElementX constructor, |  | 
| 814                                Spannable node) { |  | 
| 815     ConstructorElementX target = constructor; |  | 
| 816     InterfaceType targetType; |  | 
| 817     List<Element> seen = new List<Element>(); |  | 
| 818     // Follow the chain of redirections and check for cycles. |  | 
| 819     while (target.isRedirectingFactory) { |  | 
| 820       if (target.internalEffectiveTarget != null) { |  | 
| 821         // We found a constructor that already has been processed. |  | 
| 822         targetType = target.effectiveTargetType; |  | 
| 823         assert(invariant(target, targetType != null, |  | 
| 824             message: 'Redirection target type has not been computed for ' |  | 
| 825                      '$target')); |  | 
| 826         target = target.internalEffectiveTarget; |  | 
| 827         break; |  | 
| 828       } |  | 
| 829 |  | 
| 830       Element nextTarget = target.immediateRedirectionTarget; |  | 
| 831       if (seen.contains(nextTarget)) { |  | 
| 832         error(node, MessageKind.CYCLIC_REDIRECTING_FACTORY); |  | 
| 833         break; |  | 
| 834       } |  | 
| 835       seen.add(target); |  | 
| 836       target = nextTarget; |  | 
| 837     } |  | 
| 838 |  | 
| 839     if (targetType == null) { |  | 
| 840       assert(!target.isRedirectingFactory); |  | 
| 841       targetType = target.enclosingClass.thisType; |  | 
| 842     } |  | 
| 843 |  | 
| 844     // [target] is now the actual target of the redirections.  Run through |  | 
| 845     // the constructors again and set their [redirectionTarget], so that we |  | 
| 846     // do not have to run the loop for these constructors again. Furthermore, |  | 
| 847     // compute [redirectionTargetType] for each factory by computing the |  | 
| 848     // substitution of the target type with respect to the factory type. |  | 
| 849     while (!seen.isEmpty) { |  | 
| 850       ConstructorElementX factory = seen.removeLast(); |  | 
| 851 |  | 
| 852       // [factory] must already be analyzed but the [TreeElements] might not |  | 
| 853       // have been stored in the enqueuer cache yet. |  | 
| 854       // TODO(johnniwinther): Store [TreeElements] in the cache before |  | 
| 855       // resolution of the element. |  | 
| 856       TreeElements treeElements = factory.treeElements; |  | 
| 857       assert(invariant(node, treeElements != null, |  | 
| 858           message: 'No TreeElements cached for $factory.')); |  | 
| 859       FunctionExpression functionNode = factory.parseNode(compiler); |  | 
| 860       RedirectingFactoryBody redirectionNode = functionNode.body; |  | 
| 861       InterfaceType factoryType = treeElements.getType(redirectionNode); |  | 
| 862 |  | 
| 863       targetType = targetType.substByContext(factoryType); |  | 
| 864       factory.effectiveTarget = target; |  | 
| 865       factory.effectiveTargetType = targetType; |  | 
| 866     } |  | 
| 867   } |  | 
| 868 |  | 
| 869   /** |  | 
| 870    * Load and resolve the supertypes of [cls]. |  | 
| 871    * |  | 
| 872    * Warning: do not call this method directly. It should only be |  | 
| 873    * called by [resolveClass] and [ClassSupertypeResolver]. |  | 
| 874    */ |  | 
| 875   void loadSupertypes(BaseClassElementX cls, Spannable from) { |  | 
| 876     compiler.withCurrentElement(cls, () => measure(() { |  | 
| 877       if (cls.supertypeLoadState == STATE_DONE) return; |  | 
| 878       if (cls.supertypeLoadState == STATE_STARTED) { |  | 
| 879         compiler.reportError(from, MessageKind.CYCLIC_CLASS_HIERARCHY, |  | 
| 880                                  {'className': cls.name}); |  | 
| 881         cls.supertypeLoadState = STATE_DONE; |  | 
| 882         cls.hasIncompleteHierarchy = true; |  | 
| 883         cls.allSupertypesAndSelf = |  | 
| 884             compiler.objectClass.allSupertypesAndSelf.extendClass( |  | 
| 885                 cls.computeType(compiler)); |  | 
| 886         cls.supertype = cls.allSupertypes.head; |  | 
| 887         assert(invariant(from, cls.supertype != null, |  | 
| 888             message: 'Missing supertype on cyclic class $cls.')); |  | 
| 889         cls.interfaces = const Link<DartType>(); |  | 
| 890         return; |  | 
| 891       } |  | 
| 892       cls.supertypeLoadState = STATE_STARTED; |  | 
| 893       compiler.withCurrentElement(cls, () { |  | 
| 894         // TODO(ahe): Cache the node in cls. |  | 
| 895         cls.parseNode(compiler).accept( |  | 
| 896             new ClassSupertypeResolver(compiler, cls)); |  | 
| 897         if (cls.supertypeLoadState != STATE_DONE) { |  | 
| 898           cls.supertypeLoadState = STATE_DONE; |  | 
| 899         } |  | 
| 900       }); |  | 
| 901     })); |  | 
| 902   } |  | 
| 903 |  | 
| 904   // TODO(johnniwinther): Remove this queue when resolution has been split into |  | 
| 905   // syntax and semantic resolution. |  | 
| 906   TypeDeclarationElement currentlyResolvedTypeDeclaration; |  | 
| 907   Queue<ClassElement> pendingClassesToBeResolved = new Queue<ClassElement>(); |  | 
| 908   Queue<ClassElement> pendingClassesToBePostProcessed = |  | 
| 909       new Queue<ClassElement>(); |  | 
| 910 |  | 
| 911   /// Resolve [element] using [resolveTypeDeclaration]. |  | 
| 912   /// |  | 
| 913   /// This methods ensure that class declarations encountered through type |  | 
| 914   /// annotations during the resolution of [element] are resolved after |  | 
| 915   /// [element] has been resolved. |  | 
| 916   // TODO(johnniwinther): Encapsulate this functionality in a |  | 
| 917   // 'TypeDeclarationResolver'. |  | 
| 918   _resolveTypeDeclaration(TypeDeclarationElement element, |  | 
| 919                           resolveTypeDeclaration()) { |  | 
| 920     return compiler.withCurrentElement(element, () { |  | 
| 921       return measure(() { |  | 
| 922         TypeDeclarationElement previousResolvedTypeDeclaration = |  | 
| 923             currentlyResolvedTypeDeclaration; |  | 
| 924         currentlyResolvedTypeDeclaration = element; |  | 
| 925         var result = resolveTypeDeclaration(); |  | 
| 926         if (previousResolvedTypeDeclaration == null) { |  | 
| 927           do { |  | 
| 928             while (!pendingClassesToBeResolved.isEmpty) { |  | 
| 929               pendingClassesToBeResolved.removeFirst().ensureResolved(compiler); |  | 
| 930             } |  | 
| 931             while (!pendingClassesToBePostProcessed.isEmpty) { |  | 
| 932               _postProcessClassElement( |  | 
| 933                   pendingClassesToBePostProcessed.removeFirst()); |  | 
| 934             } |  | 
| 935           } while (!pendingClassesToBeResolved.isEmpty); |  | 
| 936           assert(pendingClassesToBeResolved.isEmpty); |  | 
| 937           assert(pendingClassesToBePostProcessed.isEmpty); |  | 
| 938         } |  | 
| 939         currentlyResolvedTypeDeclaration = previousResolvedTypeDeclaration; |  | 
| 940         return result; |  | 
| 941       }); |  | 
| 942     }); |  | 
| 943   } |  | 
| 944 |  | 
| 945   /** |  | 
| 946    * Resolve the class [element]. |  | 
| 947    * |  | 
| 948    * Before calling this method, [element] was constructed by the |  | 
| 949    * scanner and most fields are null or empty. This method fills in |  | 
| 950    * these fields and also ensure that the supertypes of [element] are |  | 
| 951    * resolved. |  | 
| 952    * |  | 
| 953    * Warning: Do not call this method directly. Instead use |  | 
| 954    * [:element.ensureResolved(compiler):]. |  | 
| 955    */ |  | 
| 956   TreeElements resolveClass(BaseClassElementX element) { |  | 
| 957     return _resolveTypeDeclaration(element, () { |  | 
| 958       // TODO(johnniwinther): Store the mapping in the resolution enqueuer. |  | 
| 959       ResolutionRegistry registry = new ResolutionRegistry(compiler, element); |  | 
| 960       resolveClassInternal(element, registry); |  | 
| 961       return element.treeElements; |  | 
| 962     }); |  | 
| 963   } |  | 
| 964 |  | 
| 965   void _ensureClassWillBeResolved(ClassElement element) { |  | 
| 966     if (currentlyResolvedTypeDeclaration == null) { |  | 
| 967       element.ensureResolved(compiler); |  | 
| 968     } else { |  | 
| 969       pendingClassesToBeResolved.add(element); |  | 
| 970     } |  | 
| 971   } |  | 
| 972 |  | 
| 973   void resolveClassInternal(BaseClassElementX element, |  | 
| 974                             ResolutionRegistry registry) { |  | 
| 975     if (!element.isPatch) { |  | 
| 976       compiler.withCurrentElement(element, () => measure(() { |  | 
| 977         assert(element.resolutionState == STATE_NOT_STARTED); |  | 
| 978         element.resolutionState = STATE_STARTED; |  | 
| 979         Node tree = element.parseNode(compiler); |  | 
| 980         loadSupertypes(element, tree); |  | 
| 981 |  | 
| 982         ClassResolverVisitor visitor = |  | 
| 983             new ClassResolverVisitor(compiler, element, registry); |  | 
| 984         visitor.visit(tree); |  | 
| 985         element.resolutionState = STATE_DONE; |  | 
| 986         compiler.onClassResolved(element); |  | 
| 987         pendingClassesToBePostProcessed.add(element); |  | 
| 988       })); |  | 
| 989       if (element.isPatched) { |  | 
| 990         // Ensure handling patch after origin. |  | 
| 991         element.patch.ensureResolved(compiler); |  | 
| 992       } |  | 
| 993     } else { // Handle patch classes: |  | 
| 994       element.resolutionState = STATE_STARTED; |  | 
| 995       // Ensure handling origin before patch. |  | 
| 996       element.origin.ensureResolved(compiler); |  | 
| 997       // Ensure that the type is computed. |  | 
| 998       element.computeType(compiler); |  | 
| 999       // Copy class hierarchy from origin. |  | 
| 1000       element.supertype = element.origin.supertype; |  | 
| 1001       element.interfaces = element.origin.interfaces; |  | 
| 1002       element.allSupertypesAndSelf = element.origin.allSupertypesAndSelf; |  | 
| 1003       // Stepwise assignment to ensure invariant. |  | 
| 1004       element.supertypeLoadState = STATE_STARTED; |  | 
| 1005       element.supertypeLoadState = STATE_DONE; |  | 
| 1006       element.resolutionState = STATE_DONE; |  | 
| 1007       // TODO(johnniwinther): Check matching type variables and |  | 
| 1008       // empty extends/implements clauses. |  | 
| 1009     } |  | 
| 1010   } |  | 
| 1011 |  | 
| 1012   void _postProcessClassElement(BaseClassElementX element) { |  | 
| 1013     for (MetadataAnnotation metadata in element.metadata) { |  | 
| 1014       metadata.ensureResolved(compiler); |  | 
| 1015       if (!element.isProxy && |  | 
| 1016           metadata.constant.value == compiler.proxyConstant) { |  | 
| 1017         element.isProxy = true; |  | 
| 1018       } |  | 
| 1019     } |  | 
| 1020 |  | 
| 1021     // Force resolution of metadata on non-instance members since they may be |  | 
| 1022     // inspected by the backend while emitting. Metadata on instance members is |  | 
| 1023     // handled as a result of processing instantiated class members in the |  | 
| 1024     // enqueuer. |  | 
| 1025     // TODO(ahe): Avoid this eager resolution. |  | 
| 1026     element.forEachMember((_, Element member) { |  | 
| 1027       if (!member.isInstanceMember) { |  | 
| 1028         compiler.withCurrentElement(member, () { |  | 
| 1029           for (MetadataAnnotation metadata in member.metadata) { |  | 
| 1030             metadata.ensureResolved(compiler); |  | 
| 1031           } |  | 
| 1032         }); |  | 
| 1033       } |  | 
| 1034     }); |  | 
| 1035 |  | 
| 1036     computeClassMember(element, Compiler.CALL_OPERATOR_NAME); |  | 
| 1037   } |  | 
| 1038 |  | 
| 1039   void computeClassMembers(ClassElement element) { |  | 
| 1040     MembersCreator.computeAllClassMembers(compiler, element); |  | 
| 1041   } |  | 
| 1042 |  | 
| 1043   void computeClassMember(ClassElement element, String name) { |  | 
| 1044     MembersCreator.computeClassMembersByName(compiler, element, name); |  | 
| 1045   } |  | 
| 1046 |  | 
| 1047   void checkClass(ClassElement element) { |  | 
| 1048     computeClassMembers(element); |  | 
| 1049     if (element.isMixinApplication) { |  | 
| 1050       checkMixinApplication(element); |  | 
| 1051     } else { |  | 
| 1052       checkClassMembers(element); |  | 
| 1053     } |  | 
| 1054   } |  | 
| 1055 |  | 
| 1056   void checkMixinApplication(MixinApplicationElementX mixinApplication) { |  | 
| 1057     Modifiers modifiers = mixinApplication.modifiers; |  | 
| 1058     int illegalFlags = modifiers.flags & ~Modifiers.FLAG_ABSTRACT; |  | 
| 1059     if (illegalFlags != 0) { |  | 
| 1060       Modifiers illegalModifiers = new Modifiers.withFlags(null, illegalFlags); |  | 
| 1061       compiler.reportError( |  | 
| 1062           modifiers, |  | 
| 1063           MessageKind.ILLEGAL_MIXIN_APPLICATION_MODIFIERS, |  | 
| 1064           {'modifiers': illegalModifiers}); |  | 
| 1065     } |  | 
| 1066 |  | 
| 1067     // In case of cyclic mixin applications, the mixin chain will have |  | 
| 1068     // been cut. If so, we have already reported the error to the |  | 
| 1069     // user so we just return from here. |  | 
| 1070     ClassElement mixin = mixinApplication.mixin; |  | 
| 1071     if (mixin == null) return; |  | 
| 1072 |  | 
| 1073     // Check that we're not trying to use Object as a mixin. |  | 
| 1074     if (mixin.superclass == null) { |  | 
| 1075       compiler.reportError(mixinApplication, |  | 
| 1076                                MessageKind.ILLEGAL_MIXIN_OBJECT); |  | 
| 1077       // Avoid reporting additional errors for the Object class. |  | 
| 1078       return; |  | 
| 1079     } |  | 
| 1080 |  | 
| 1081     // Check that the mixed in class has Object as its superclass. |  | 
| 1082     if (!mixin.superclass.isObject) { |  | 
| 1083       compiler.reportError(mixin, MessageKind.ILLEGAL_MIXIN_SUPERCLASS); |  | 
| 1084     } |  | 
| 1085 |  | 
| 1086     // Check that the mixed in class doesn't have any constructors and |  | 
| 1087     // make sure we aren't mixing in methods that use 'super'. |  | 
| 1088     mixin.forEachLocalMember((AstElement member) { |  | 
| 1089       if (member.isGenerativeConstructor && !member.isSynthesized) { |  | 
| 1090         compiler.reportError(member, MessageKind.ILLEGAL_MIXIN_CONSTRUCTOR); |  | 
| 1091       } else { |  | 
| 1092         // Get the resolution tree and check that the resolved member |  | 
| 1093         // doesn't use 'super'. This is the part of the 'super' mixin |  | 
| 1094         // check that happens when a function is resolved before the |  | 
| 1095         // mixin application has been performed. |  | 
| 1096         // TODO(johnniwinther): Obtain the [TreeElements] for [member] |  | 
| 1097         // differently. |  | 
| 1098         if (compiler.enqueuer.resolution.hasBeenResolved(member)) { |  | 
| 1099           checkMixinSuperUses( |  | 
| 1100               member.resolvedAst.elements, |  | 
| 1101               mixinApplication, |  | 
| 1102               mixin); |  | 
| 1103         } |  | 
| 1104       } |  | 
| 1105     }); |  | 
| 1106   } |  | 
| 1107 |  | 
| 1108   void checkMixinSuperUses(TreeElements resolutionTree, |  | 
| 1109                            MixinApplicationElement mixinApplication, |  | 
| 1110                            ClassElement mixin) { |  | 
| 1111     // TODO(johnniwinther): Avoid the use of [TreeElements] here. |  | 
| 1112     if (resolutionTree == null) return; |  | 
| 1113     Iterable<Node> superUses = resolutionTree.superUses; |  | 
| 1114     if (superUses.isEmpty) return; |  | 
| 1115     compiler.reportError(mixinApplication, |  | 
| 1116                          MessageKind.ILLEGAL_MIXIN_WITH_SUPER, |  | 
| 1117                          {'className': mixin.name}); |  | 
| 1118     // Show the user the problematic uses of 'super' in the mixin. |  | 
| 1119     for (Node use in superUses) { |  | 
| 1120       compiler.reportInfo( |  | 
| 1121           use, |  | 
| 1122           MessageKind.ILLEGAL_MIXIN_SUPER_USE); |  | 
| 1123     } |  | 
| 1124   } |  | 
| 1125 |  | 
| 1126   void checkClassMembers(ClassElement cls) { |  | 
| 1127     assert(invariant(cls, cls.isDeclaration)); |  | 
| 1128     if (cls.isObject) return; |  | 
| 1129     // TODO(johnniwinther): Should this be done on the implementation element as |  | 
| 1130     // well? |  | 
| 1131     List<Element> constConstructors = <Element>[]; |  | 
| 1132     List<Element> nonFinalInstanceFields = <Element>[]; |  | 
| 1133     cls.forEachMember((holder, member) { |  | 
| 1134       compiler.withCurrentElement(member, () { |  | 
| 1135         // Perform various checks as side effect of "computing" the type. |  | 
| 1136         member.computeType(compiler); |  | 
| 1137 |  | 
| 1138         // Check modifiers. |  | 
| 1139         if (member.isFunction && member.modifiers.isFinal) { |  | 
| 1140           compiler.reportError( |  | 
| 1141               member, MessageKind.ILLEGAL_FINAL_METHOD_MODIFIER); |  | 
| 1142         } |  | 
| 1143         if (member.isConstructor) { |  | 
| 1144           final mismatchedFlagsBits = |  | 
| 1145               member.modifiers.flags & |  | 
| 1146               (Modifiers.FLAG_STATIC | Modifiers.FLAG_ABSTRACT); |  | 
| 1147           if (mismatchedFlagsBits != 0) { |  | 
| 1148             final mismatchedFlags = |  | 
| 1149                 new Modifiers.withFlags(null, mismatchedFlagsBits); |  | 
| 1150             compiler.reportError( |  | 
| 1151                 member, |  | 
| 1152                 MessageKind.ILLEGAL_CONSTRUCTOR_MODIFIERS, |  | 
| 1153                 {'modifiers': mismatchedFlags}); |  | 
| 1154           } |  | 
| 1155           if (member.modifiers.isConst) { |  | 
| 1156             constConstructors.add(member); |  | 
| 1157           } |  | 
| 1158         } |  | 
| 1159         if (member.isField) { |  | 
| 1160           if (member.modifiers.isConst && !member.modifiers.isStatic) { |  | 
| 1161             compiler.reportError( |  | 
| 1162                 member, MessageKind.ILLEGAL_CONST_FIELD_MODIFIER); |  | 
| 1163           } |  | 
| 1164           if (!member.modifiers.isStatic && !member.modifiers.isFinal) { |  | 
| 1165             nonFinalInstanceFields.add(member); |  | 
| 1166           } |  | 
| 1167         } |  | 
| 1168         checkAbstractField(member); |  | 
| 1169         checkUserDefinableOperator(member); |  | 
| 1170       }); |  | 
| 1171     }); |  | 
| 1172     if (!constConstructors.isEmpty && !nonFinalInstanceFields.isEmpty) { |  | 
| 1173       Spannable span = constConstructors.length > 1 |  | 
| 1174           ? cls : constConstructors[0]; |  | 
| 1175       compiler.reportError(span, |  | 
| 1176           MessageKind.CONST_CONSTRUCTOR_WITH_NONFINAL_FIELDS, |  | 
| 1177           {'className': cls.name}); |  | 
| 1178       if (constConstructors.length > 1) { |  | 
| 1179         for (Element constructor in constConstructors) { |  | 
| 1180           compiler.reportInfo(constructor, |  | 
| 1181               MessageKind.CONST_CONSTRUCTOR_WITH_NONFINAL_FIELDS_CONSTRUCTOR); |  | 
| 1182         } |  | 
| 1183       } |  | 
| 1184       for (Element field in nonFinalInstanceFields) { |  | 
| 1185         compiler.reportInfo(field, |  | 
| 1186             MessageKind.CONST_CONSTRUCTOR_WITH_NONFINAL_FIELDS_FIELD); |  | 
| 1187       } |  | 
| 1188     } |  | 
| 1189   } |  | 
| 1190 |  | 
| 1191   void checkAbstractField(Element member) { |  | 
| 1192     // Only check for getters. The test can only fail if there is both a setter |  | 
| 1193     // and a getter with the same name, and we only need to check each abstract |  | 
| 1194     // field once, so we just ignore setters. |  | 
| 1195     if (!member.isGetter) return; |  | 
| 1196 |  | 
| 1197     // Find the associated abstract field. |  | 
| 1198     ClassElement classElement = member.enclosingClass; |  | 
| 1199     Element lookupElement = classElement.lookupLocalMember(member.name); |  | 
| 1200     if (lookupElement == null) { |  | 
| 1201       compiler.internalError(member, |  | 
| 1202           "No abstract field for accessor"); |  | 
| 1203     } else if (!identical(lookupElement.kind, ElementKind.ABSTRACT_FIELD)) { |  | 
| 1204       compiler.internalError(member, |  | 
| 1205           "Inaccessible abstract field for accessor"); |  | 
| 1206     } |  | 
| 1207     AbstractFieldElement field = lookupElement; |  | 
| 1208 |  | 
| 1209     FunctionElementX getter = field.getter; |  | 
| 1210     if (getter == null) return; |  | 
| 1211     FunctionElementX setter = field.setter; |  | 
| 1212     if (setter == null) return; |  | 
| 1213     int getterFlags = getter.modifiers.flags | Modifiers.FLAG_ABSTRACT; |  | 
| 1214     int setterFlags = setter.modifiers.flags | Modifiers.FLAG_ABSTRACT; |  | 
| 1215     if (!identical(getterFlags, setterFlags)) { |  | 
| 1216       final mismatchedFlags = |  | 
| 1217         new Modifiers.withFlags(null, getterFlags ^ setterFlags); |  | 
| 1218       compiler.reportError( |  | 
| 1219           field.getter, |  | 
| 1220           MessageKind.GETTER_MISMATCH, |  | 
| 1221           {'modifiers': mismatchedFlags}); |  | 
| 1222       compiler.reportError( |  | 
| 1223           field.setter, |  | 
| 1224           MessageKind.SETTER_MISMATCH, |  | 
| 1225           {'modifiers': mismatchedFlags}); |  | 
| 1226     } |  | 
| 1227   } |  | 
| 1228 |  | 
| 1229   void checkUserDefinableOperator(Element member) { |  | 
| 1230     FunctionElement function = member.asFunctionElement(); |  | 
| 1231     if (function == null) return; |  | 
| 1232     String value = member.name; |  | 
| 1233     if (value == null) return; |  | 
| 1234     if (!(isUserDefinableOperator(value) || identical(value, 'unary-'))) return; |  | 
| 1235 |  | 
| 1236     bool isMinus = false; |  | 
| 1237     int requiredParameterCount; |  | 
| 1238     MessageKind messageKind; |  | 
| 1239     if (identical(value, 'unary-')) { |  | 
| 1240       isMinus = true; |  | 
| 1241       messageKind = MessageKind.MINUS_OPERATOR_BAD_ARITY; |  | 
| 1242       requiredParameterCount = 0; |  | 
| 1243     } else if (isMinusOperator(value)) { |  | 
| 1244       isMinus = true; |  | 
| 1245       messageKind = MessageKind.MINUS_OPERATOR_BAD_ARITY; |  | 
| 1246       requiredParameterCount = 1; |  | 
| 1247     } else if (isUnaryOperator(value)) { |  | 
| 1248       messageKind = MessageKind.UNARY_OPERATOR_BAD_ARITY; |  | 
| 1249       requiredParameterCount = 0; |  | 
| 1250     } else if (isBinaryOperator(value)) { |  | 
| 1251       messageKind = MessageKind.BINARY_OPERATOR_BAD_ARITY; |  | 
| 1252       requiredParameterCount = 1; |  | 
| 1253       if (identical(value, '==')) checkOverrideHashCode(member); |  | 
| 1254     } else if (isTernaryOperator(value)) { |  | 
| 1255       messageKind = MessageKind.TERNARY_OPERATOR_BAD_ARITY; |  | 
| 1256       requiredParameterCount = 2; |  | 
| 1257     } else { |  | 
| 1258       compiler.internalError(function, |  | 
| 1259           'Unexpected user defined operator $value'); |  | 
| 1260     } |  | 
| 1261     checkArity(function, requiredParameterCount, messageKind, isMinus); |  | 
| 1262   } |  | 
| 1263 |  | 
| 1264   void checkOverrideHashCode(FunctionElement operatorEquals) { |  | 
| 1265     if (operatorEquals.isAbstract) return; |  | 
| 1266     ClassElement cls = operatorEquals.enclosingClass; |  | 
| 1267     Element hashCodeImplementation = |  | 
| 1268         cls.lookupLocalMember('hashCode'); |  | 
| 1269     if (hashCodeImplementation != null) return; |  | 
| 1270     compiler.reportHint( |  | 
| 1271         operatorEquals, MessageKind.OVERRIDE_EQUALS_NOT_HASH_CODE, |  | 
| 1272         {'class': cls.name}); |  | 
| 1273   } |  | 
| 1274 |  | 
| 1275   void checkArity(FunctionElement function, |  | 
| 1276                   int requiredParameterCount, MessageKind messageKind, |  | 
| 1277                   bool isMinus) { |  | 
| 1278     FunctionExpression node = function.node; |  | 
| 1279     FunctionSignature signature = function.functionSignature; |  | 
| 1280     if (signature.requiredParameterCount != requiredParameterCount) { |  | 
| 1281       Node errorNode = node; |  | 
| 1282       if (node.parameters != null) { |  | 
| 1283         if (isMinus || |  | 
| 1284             signature.requiredParameterCount < requiredParameterCount) { |  | 
| 1285           // If there are too few parameters, point to the whole parameter list. |  | 
| 1286           // For instance |  | 
| 1287           // |  | 
| 1288           //     int operator +() {} |  | 
| 1289           //                   ^^ |  | 
| 1290           // |  | 
| 1291           //     int operator []=(value) {} |  | 
| 1292           //                     ^^^^^^^ |  | 
| 1293           // |  | 
| 1294           // For operator -, always point the whole parameter list, like |  | 
| 1295           // |  | 
| 1296           //     int operator -(a, b) {} |  | 
| 1297           //                   ^^^^^^ |  | 
| 1298           // |  | 
| 1299           // instead of |  | 
| 1300           // |  | 
| 1301           //     int operator -(a, b) {} |  | 
| 1302           //                       ^ |  | 
| 1303           // |  | 
| 1304           // since the correction might not be to remove 'b' but instead to |  | 
| 1305           // remove 'a, b'. |  | 
| 1306           errorNode = node.parameters; |  | 
| 1307         } else { |  | 
| 1308           errorNode = node.parameters.nodes.skip(requiredParameterCount).head; |  | 
| 1309         } |  | 
| 1310       } |  | 
| 1311       compiler.reportError( |  | 
| 1312           errorNode, messageKind, {'operatorName': function.name}); |  | 
| 1313     } |  | 
| 1314     if (signature.optionalParameterCount != 0) { |  | 
| 1315       Node errorNode = |  | 
| 1316           node.parameters.nodes.skip(signature.requiredParameterCount).head; |  | 
| 1317       if (signature.optionalParametersAreNamed) { |  | 
| 1318         compiler.reportError( |  | 
| 1319             errorNode, |  | 
| 1320             MessageKind.OPERATOR_NAMED_PARAMETERS, |  | 
| 1321             {'operatorName': function.name}); |  | 
| 1322       } else { |  | 
| 1323         compiler.reportError( |  | 
| 1324             errorNode, |  | 
| 1325             MessageKind.OPERATOR_OPTIONAL_PARAMETERS, |  | 
| 1326             {'operatorName': function.name}); |  | 
| 1327       } |  | 
| 1328     } |  | 
| 1329   } |  | 
| 1330 |  | 
| 1331   reportErrorWithContext(Element errorneousElement, |  | 
| 1332                          MessageKind errorMessage, |  | 
| 1333                          Element contextElement, |  | 
| 1334                          MessageKind contextMessage) { |  | 
| 1335     compiler.reportError( |  | 
| 1336         errorneousElement, |  | 
| 1337         errorMessage, |  | 
| 1338         {'memberName': contextElement.name, |  | 
| 1339          'className': contextElement.enclosingClass.name}); |  | 
| 1340     compiler.reportInfo(contextElement, contextMessage); |  | 
| 1341   } |  | 
| 1342 |  | 
| 1343 |  | 
| 1344   FunctionSignature resolveSignature(FunctionElementX element) { |  | 
| 1345     MessageKind defaultValuesError = null; |  | 
| 1346     if (element.isFactoryConstructor) { |  | 
| 1347       FunctionExpression body = element.parseNode(compiler); |  | 
| 1348       if (body.isRedirectingFactory) { |  | 
| 1349         defaultValuesError = MessageKind.REDIRECTING_FACTORY_WITH_DEFAULT; |  | 
| 1350       } |  | 
| 1351     } |  | 
| 1352     return compiler.withCurrentElement(element, () { |  | 
| 1353       FunctionExpression node = |  | 
| 1354           compiler.parser.measure(() => element.parseNode(compiler)); |  | 
| 1355       return measure(() => SignatureResolver.analyze( |  | 
| 1356           compiler, node.parameters, node.returnType, element, |  | 
| 1357           new ResolutionRegistry(compiler, element), |  | 
| 1358           defaultValuesError: defaultValuesError, |  | 
| 1359           createRealParameters: true)); |  | 
| 1360     }); |  | 
| 1361   } |  | 
| 1362 |  | 
| 1363   TreeElements resolveTypedef(TypedefElementX element) { |  | 
| 1364     if (element.isResolved) return element.treeElements; |  | 
| 1365     compiler.world.allTypedefs.add(element); |  | 
| 1366     return _resolveTypeDeclaration(element, () { |  | 
| 1367       ResolutionRegistry registry = new ResolutionRegistry(compiler, element); |  | 
| 1368       return compiler.withCurrentElement(element, () { |  | 
| 1369         return measure(() { |  | 
| 1370           assert(element.resolutionState == STATE_NOT_STARTED); |  | 
| 1371           element.resolutionState = STATE_STARTED; |  | 
| 1372           Typedef node = |  | 
| 1373             compiler.parser.measure(() => element.parseNode(compiler)); |  | 
| 1374           TypedefResolverVisitor visitor = |  | 
| 1375             new TypedefResolverVisitor(compiler, element, registry); |  | 
| 1376           visitor.visit(node); |  | 
| 1377           element.resolutionState = STATE_DONE; |  | 
| 1378           return registry.mapping; |  | 
| 1379         }); |  | 
| 1380       }); |  | 
| 1381     }); |  | 
| 1382   } |  | 
| 1383 |  | 
| 1384   void resolveMetadataAnnotation(MetadataAnnotationX annotation) { |  | 
| 1385     compiler.withCurrentElement(annotation.annotatedElement, () => measure(() { |  | 
| 1386       assert(annotation.resolutionState == STATE_NOT_STARTED); |  | 
| 1387       annotation.resolutionState = STATE_STARTED; |  | 
| 1388 |  | 
| 1389       Node node = annotation.parseNode(compiler); |  | 
| 1390       Element annotatedElement = annotation.annotatedElement; |  | 
| 1391       AnalyzableElement context = annotatedElement.analyzableElement; |  | 
| 1392       ClassElement classElement = annotatedElement.enclosingClass; |  | 
| 1393       if (classElement != null) { |  | 
| 1394         // The annotation is resolved in the scope of [classElement]. |  | 
| 1395         classElement.ensureResolved(compiler); |  | 
| 1396       } |  | 
| 1397       assert(invariant(node, context != null, |  | 
| 1398           message: "No context found for metadata annotation " |  | 
| 1399                    "on $annotatedElement.")); |  | 
| 1400       ResolverVisitor visitor = visitorFor(context, useEnclosingScope: true); |  | 
| 1401       ResolutionRegistry registry = visitor.registry; |  | 
| 1402       node.accept(visitor); |  | 
| 1403       // TODO(johnniwinther): Avoid passing the [TreeElements] to |  | 
| 1404       // [compileMetadata]. |  | 
| 1405       annotation.constant = |  | 
| 1406           constantCompiler.compileMetadata(annotation, node, registry.mapping); |  | 
| 1407       // TODO(johnniwinther): Register the relation between the annotation |  | 
| 1408       // and the annotated element instead. This will allow the backend to |  | 
| 1409       // retrieve the backend constant and only register metadata on the |  | 
| 1410       // elements for which it is needed. (Issue 17732). |  | 
| 1411       registry.registerMetadataConstant(annotation, annotatedElement); |  | 
| 1412       annotation.resolutionState = STATE_DONE; |  | 
| 1413     })); |  | 
| 1414   } |  | 
| 1415 |  | 
| 1416   error(Spannable node, MessageKind kind, [arguments = const {}]) { |  | 
| 1417     // TODO(ahe): Make non-fatal. |  | 
| 1418     compiler.reportFatalError(node, kind, arguments); |  | 
| 1419   } |  | 
| 1420 |  | 
| 1421   Link<MetadataAnnotation> resolveMetadata(Element element, |  | 
| 1422                                            VariableDefinitions node) { |  | 
| 1423     LinkBuilder<MetadataAnnotation> metadata = |  | 
| 1424         new LinkBuilder<MetadataAnnotation>(); |  | 
| 1425     for (Metadata annotation in node.metadata.nodes) { |  | 
| 1426       ParameterMetadataAnnotation metadataAnnotation = |  | 
| 1427           new ParameterMetadataAnnotation(annotation); |  | 
| 1428       metadataAnnotation.annotatedElement = element; |  | 
| 1429       metadata.addLast(metadataAnnotation.ensureResolved(compiler)); |  | 
| 1430     } |  | 
| 1431     return metadata.toLink(); |  | 
| 1432   } |  | 
| 1433 } |  | 
| 1434 |  | 
| 1435 class InitializerResolver { |  | 
| 1436   final ResolverVisitor visitor; |  | 
| 1437   final Map<Element, Node> initialized; |  | 
| 1438   Link<Node> initializers; |  | 
| 1439   bool hasSuper; |  | 
| 1440 |  | 
| 1441   InitializerResolver(this.visitor) |  | 
| 1442     : initialized = new Map<Element, Node>(), hasSuper = false; |  | 
| 1443 |  | 
| 1444   ResolutionRegistry get registry => visitor.registry; |  | 
| 1445 |  | 
| 1446   error(Node node, MessageKind kind, [arguments = const {}]) { |  | 
| 1447     visitor.error(node, kind, arguments); |  | 
| 1448   } |  | 
| 1449 |  | 
| 1450   warning(Node node, MessageKind kind, [arguments = const {}]) { |  | 
| 1451     visitor.warning(node, kind, arguments); |  | 
| 1452   } |  | 
| 1453 |  | 
| 1454   bool isFieldInitializer(SendSet node) { |  | 
| 1455     if (node.selector.asIdentifier() == null) return false; |  | 
| 1456     if (node.receiver == null) return true; |  | 
| 1457     if (node.receiver.asIdentifier() == null) return false; |  | 
| 1458     return node.receiver.asIdentifier().isThis(); |  | 
| 1459   } |  | 
| 1460 |  | 
| 1461   reportDuplicateInitializerError(Element field, Node init, Node existing) { |  | 
| 1462     visitor.compiler.reportError( |  | 
| 1463         init, |  | 
| 1464         MessageKind.DUPLICATE_INITIALIZER, {'fieldName': field.name}); |  | 
| 1465     visitor.compiler.reportInfo( |  | 
| 1466         existing, |  | 
| 1467         MessageKind.ALREADY_INITIALIZED, {'fieldName': field.name}); |  | 
| 1468   } |  | 
| 1469 |  | 
| 1470   void checkForDuplicateInitializers(FieldElementX field, Node init) { |  | 
| 1471     // [field] can be null if it could not be resolved. |  | 
| 1472     if (field == null) return; |  | 
| 1473     String name = field.name; |  | 
| 1474     if (initialized.containsKey(field)) { |  | 
| 1475       reportDuplicateInitializerError(field, init, initialized[field]); |  | 
| 1476     } else if (field.isFinal) { |  | 
| 1477       field.parseNode(visitor.compiler); |  | 
| 1478       Expression initializer = field.initializer; |  | 
| 1479       if (initializer != null) { |  | 
| 1480         reportDuplicateInitializerError(field, init, initializer); |  | 
| 1481       } |  | 
| 1482     } |  | 
| 1483     initialized[field] = init; |  | 
| 1484   } |  | 
| 1485 |  | 
| 1486   void resolveFieldInitializer(FunctionElement constructor, SendSet init) { |  | 
| 1487     // init is of the form [this.]field = value. |  | 
| 1488     final Node selector = init.selector; |  | 
| 1489     final String name = selector.asIdentifier().source; |  | 
| 1490     // Lookup target field. |  | 
| 1491     Element target; |  | 
| 1492     if (isFieldInitializer(init)) { |  | 
| 1493       target = constructor.enclosingClass.lookupLocalMember(name); |  | 
| 1494       if (target == null) { |  | 
| 1495         error(selector, MessageKind.CANNOT_RESOLVE, {'name': name}); |  | 
| 1496       } else if (target.kind != ElementKind.FIELD) { |  | 
| 1497         error(selector, MessageKind.NOT_A_FIELD, {'fieldName': name}); |  | 
| 1498       } else if (!target.isInstanceMember) { |  | 
| 1499         error(selector, MessageKind.INIT_STATIC_FIELD, {'fieldName': name}); |  | 
| 1500       } |  | 
| 1501     } else { |  | 
| 1502       error(init, MessageKind.INVALID_RECEIVER_IN_INITIALIZER); |  | 
| 1503     } |  | 
| 1504     registry.useElement(init, target); |  | 
| 1505     registry.registerStaticUse(target); |  | 
| 1506     checkForDuplicateInitializers(target, init); |  | 
| 1507     // Resolve initializing value. |  | 
| 1508     visitor.visitInStaticContext(init.arguments.head); |  | 
| 1509   } |  | 
| 1510 |  | 
| 1511   ClassElement getSuperOrThisLookupTarget(FunctionElement constructor, |  | 
| 1512                                           bool isSuperCall, |  | 
| 1513                                           Node diagnosticNode) { |  | 
| 1514     ClassElement lookupTarget = constructor.enclosingClass; |  | 
| 1515     if (isSuperCall) { |  | 
| 1516       // Calculate correct lookup target and constructor name. |  | 
| 1517       if (identical(lookupTarget, visitor.compiler.objectClass)) { |  | 
| 1518         error(diagnosticNode, MessageKind.SUPER_INITIALIZER_IN_OBJECT); |  | 
| 1519       } else { |  | 
| 1520         return lookupTarget.supertype.element; |  | 
| 1521       } |  | 
| 1522     } |  | 
| 1523     return lookupTarget; |  | 
| 1524   } |  | 
| 1525 |  | 
| 1526   Element resolveSuperOrThisForSend(FunctionElement constructor, |  | 
| 1527                                     FunctionExpression functionNode, |  | 
| 1528                                     Send call) { |  | 
| 1529     // Resolve the selector and the arguments. |  | 
| 1530     ResolverTask resolver = visitor.compiler.resolver; |  | 
| 1531     visitor.inStaticContext(() { |  | 
| 1532       visitor.resolveSelector(call, null); |  | 
| 1533       visitor.resolveArguments(call.argumentsNode); |  | 
| 1534     }); |  | 
| 1535     Selector selector = registry.getSelector(call); |  | 
| 1536     bool isSuperCall = Initializers.isSuperConstructorCall(call); |  | 
| 1537 |  | 
| 1538     ClassElement lookupTarget = getSuperOrThisLookupTarget(constructor, |  | 
| 1539                                                            isSuperCall, |  | 
| 1540                                                            call); |  | 
| 1541     Selector constructorSelector = |  | 
| 1542         visitor.getRedirectingThisOrSuperConstructorSelector(call); |  | 
| 1543     FunctionElement calledConstructor = |  | 
| 1544         lookupTarget.lookupConstructor(constructorSelector); |  | 
| 1545 |  | 
| 1546     final bool isImplicitSuperCall = false; |  | 
| 1547     final String className = lookupTarget.name; |  | 
| 1548     verifyThatConstructorMatchesCall(constructor, |  | 
| 1549                                      calledConstructor, |  | 
| 1550                                      selector, |  | 
| 1551                                      isImplicitSuperCall, |  | 
| 1552                                      call, |  | 
| 1553                                      className, |  | 
| 1554                                      constructorSelector); |  | 
| 1555 |  | 
| 1556     registry.useElement(call, calledConstructor); |  | 
| 1557     registry.registerStaticUse(calledConstructor); |  | 
| 1558     return calledConstructor; |  | 
| 1559   } |  | 
| 1560 |  | 
| 1561   void resolveImplicitSuperConstructorSend(FunctionElement constructor, |  | 
| 1562                                            FunctionExpression functionNode) { |  | 
| 1563     // If the class has a super resolve the implicit super call. |  | 
| 1564     ClassElement classElement = constructor.enclosingClass; |  | 
| 1565     ClassElement superClass = classElement.superclass; |  | 
| 1566     if (classElement != visitor.compiler.objectClass) { |  | 
| 1567       assert(superClass != null); |  | 
| 1568       assert(superClass.resolutionState == STATE_DONE); |  | 
| 1569       String constructorName = ''; |  | 
| 1570       Selector callToMatch = new Selector.call( |  | 
| 1571           constructorName, |  | 
| 1572           classElement.library, |  | 
| 1573           0); |  | 
| 1574 |  | 
| 1575       final bool isSuperCall = true; |  | 
| 1576       ClassElement lookupTarget = getSuperOrThisLookupTarget(constructor, |  | 
| 1577                                                              isSuperCall, |  | 
| 1578                                                              functionNode); |  | 
| 1579       Selector constructorSelector = new Selector.callDefaultConstructor( |  | 
| 1580           visitor.enclosingElement.library); |  | 
| 1581       Element calledConstructor = lookupTarget.lookupConstructor( |  | 
| 1582           constructorSelector); |  | 
| 1583 |  | 
| 1584       final String className = lookupTarget.name; |  | 
| 1585       final bool isImplicitSuperCall = true; |  | 
| 1586       verifyThatConstructorMatchesCall(constructor, |  | 
| 1587                                        calledConstructor, |  | 
| 1588                                        callToMatch, |  | 
| 1589                                        isImplicitSuperCall, |  | 
| 1590                                        functionNode, |  | 
| 1591                                        className, |  | 
| 1592                                        constructorSelector); |  | 
| 1593       registry.registerImplicitSuperCall(calledConstructor); |  | 
| 1594       registry.registerStaticUse(calledConstructor); |  | 
| 1595     } |  | 
| 1596   } |  | 
| 1597 |  | 
| 1598   void verifyThatConstructorMatchesCall( |  | 
| 1599       FunctionElement caller, |  | 
| 1600       FunctionElement lookedupConstructor, |  | 
| 1601       Selector call, |  | 
| 1602       bool isImplicitSuperCall, |  | 
| 1603       Node diagnosticNode, |  | 
| 1604       String className, |  | 
| 1605       Selector constructorSelector) { |  | 
| 1606     if (lookedupConstructor == null |  | 
| 1607         || !lookedupConstructor.isGenerativeConstructor) { |  | 
| 1608       String fullConstructorName = Elements.constructorNameForDiagnostics( |  | 
| 1609               className, |  | 
| 1610               constructorSelector.name); |  | 
| 1611       MessageKind kind = isImplicitSuperCall |  | 
| 1612           ? MessageKind.CANNOT_RESOLVE_CONSTRUCTOR_FOR_IMPLICIT |  | 
| 1613           : MessageKind.CANNOT_RESOLVE_CONSTRUCTOR; |  | 
| 1614       visitor.compiler.reportError( |  | 
| 1615           diagnosticNode, kind, {'constructorName': fullConstructorName}); |  | 
| 1616     } else { |  | 
| 1617       lookedupConstructor.computeSignature(visitor.compiler); |  | 
| 1618       if (!call.applies(lookedupConstructor, visitor.compiler.world)) { |  | 
| 1619         MessageKind kind = isImplicitSuperCall |  | 
| 1620                            ? MessageKind.NO_MATCHING_CONSTRUCTOR_FOR_IMPLICIT |  | 
| 1621                            : MessageKind.NO_MATCHING_CONSTRUCTOR; |  | 
| 1622         visitor.compiler.reportError(diagnosticNode, kind); |  | 
| 1623       } else if (caller.isConst |  | 
| 1624                  && !lookedupConstructor.isConst) { |  | 
| 1625         visitor.compiler.reportError( |  | 
| 1626             diagnosticNode, MessageKind.CONST_CALLS_NON_CONST); |  | 
| 1627       } |  | 
| 1628     } |  | 
| 1629   } |  | 
| 1630 |  | 
| 1631   /** |  | 
| 1632    * Resolve all initializers of this constructor. In the case of a redirecting |  | 
| 1633    * constructor, the resolved constructor's function element is returned. |  | 
| 1634    */ |  | 
| 1635   FunctionElement resolveInitializers(FunctionElement constructor, |  | 
| 1636                                       FunctionExpression functionNode) { |  | 
| 1637     // Keep track of all "this.param" parameters specified for constructor so |  | 
| 1638     // that we can ensure that fields are initialized only once. |  | 
| 1639     FunctionSignature functionParameters = constructor.functionSignature; |  | 
| 1640     functionParameters.forEachParameter((ParameterElement element) { |  | 
| 1641       if (element.isInitializingFormal) { |  | 
| 1642         InitializingFormalElement initializingFormal = element; |  | 
| 1643         checkForDuplicateInitializers(initializingFormal.fieldElement, |  | 
| 1644                                       element.initializer); |  | 
| 1645       } |  | 
| 1646     }); |  | 
| 1647 |  | 
| 1648     if (functionNode.initializers == null) { |  | 
| 1649       initializers = const Link<Node>(); |  | 
| 1650     } else { |  | 
| 1651       initializers = functionNode.initializers.nodes; |  | 
| 1652     } |  | 
| 1653     FunctionElement result; |  | 
| 1654     bool resolvedSuper = false; |  | 
| 1655     for (Link<Node> link = initializers; !link.isEmpty; link = link.tail) { |  | 
| 1656       if (link.head.asSendSet() != null) { |  | 
| 1657         final SendSet init = link.head.asSendSet(); |  | 
| 1658         resolveFieldInitializer(constructor, init); |  | 
| 1659       } else if (link.head.asSend() != null) { |  | 
| 1660         final Send call = link.head.asSend(); |  | 
| 1661         if (call.argumentsNode == null) { |  | 
| 1662           error(link.head, MessageKind.INVALID_INITIALIZER); |  | 
| 1663           continue; |  | 
| 1664         } |  | 
| 1665         if (Initializers.isSuperConstructorCall(call)) { |  | 
| 1666           if (resolvedSuper) { |  | 
| 1667             error(call, MessageKind.DUPLICATE_SUPER_INITIALIZER); |  | 
| 1668           } |  | 
| 1669           resolveSuperOrThisForSend(constructor, functionNode, call); |  | 
| 1670           resolvedSuper = true; |  | 
| 1671         } else if (Initializers.isConstructorRedirect(call)) { |  | 
| 1672           // Check that there is no body (Language specification 7.5.1).  If the |  | 
| 1673           // constructor is also const, we already reported an error in |  | 
| 1674           // [resolveMethodElement]. |  | 
| 1675           if (functionNode.hasBody() && !constructor.isConst) { |  | 
| 1676             error(functionNode, MessageKind.REDIRECTING_CONSTRUCTOR_HAS_BODY); |  | 
| 1677           } |  | 
| 1678           // Check that there are no other initializers. |  | 
| 1679           if (!initializers.tail.isEmpty) { |  | 
| 1680             error(call, MessageKind.REDIRECTING_CONSTRUCTOR_HAS_INITIALIZER); |  | 
| 1681           } |  | 
| 1682           // Check that there are no field initializing parameters. |  | 
| 1683           Compiler compiler = visitor.compiler; |  | 
| 1684           FunctionSignature signature = constructor.functionSignature; |  | 
| 1685           signature.forEachParameter((ParameterElement parameter) { |  | 
| 1686             if (parameter.isInitializingFormal) { |  | 
| 1687               Node node = parameter.node; |  | 
| 1688               error(node, MessageKind.INITIALIZING_FORMAL_NOT_ALLOWED); |  | 
| 1689             } |  | 
| 1690           }); |  | 
| 1691           return resolveSuperOrThisForSend(constructor, functionNode, call); |  | 
| 1692         } else { |  | 
| 1693           visitor.error(call, MessageKind.CONSTRUCTOR_CALL_EXPECTED); |  | 
| 1694           return null; |  | 
| 1695         } |  | 
| 1696       } else { |  | 
| 1697         error(link.head, MessageKind.INVALID_INITIALIZER); |  | 
| 1698       } |  | 
| 1699     } |  | 
| 1700     if (!resolvedSuper) { |  | 
| 1701       resolveImplicitSuperConstructorSend(constructor, functionNode); |  | 
| 1702     } |  | 
| 1703     return null;  // If there was no redirection always return null. |  | 
| 1704   } |  | 
| 1705 } |  | 
| 1706 |  | 
| 1707 class CommonResolverVisitor<R> extends Visitor<R> { |  | 
| 1708   final Compiler compiler; |  | 
| 1709 |  | 
| 1710   CommonResolverVisitor(Compiler this.compiler); |  | 
| 1711 |  | 
| 1712   R visitNode(Node node) { |  | 
| 1713     internalError(node, |  | 
| 1714         'internal error: Unhandled node: ${node.getObjectDescription()}'); |  | 
| 1715     return null; |  | 
| 1716   } |  | 
| 1717 |  | 
| 1718   R visitEmptyStatement(Node node) => null; |  | 
| 1719 |  | 
| 1720   /** Convenience method for visiting nodes that may be null. */ |  | 
| 1721   R visit(Node node) => (node == null) ? null : node.accept(this); |  | 
| 1722 |  | 
| 1723   void error(Spannable node, MessageKind kind, [Map arguments = const {}]) { |  | 
| 1724     compiler.reportFatalError(node, kind, arguments); |  | 
| 1725   } |  | 
| 1726 |  | 
| 1727   void warning(Spannable node, MessageKind kind, [Map arguments = const {}]) { |  | 
| 1728     compiler.reportWarning(node, kind, arguments); |  | 
| 1729   } |  | 
| 1730 |  | 
| 1731   void internalError(Spannable node, message) { |  | 
| 1732     compiler.internalError(node, message); |  | 
| 1733   } |  | 
| 1734 |  | 
| 1735   void addDeferredAction(Element element, DeferredAction action) { |  | 
| 1736     compiler.enqueuer.resolution.addDeferredAction(element, action); |  | 
| 1737   } |  | 
| 1738 } |  | 
| 1739 |  | 
| 1740 abstract class LabelScope { |  | 
| 1741   LabelScope get outer; |  | 
| 1742   LabelDefinition lookup(String label); |  | 
| 1743 } |  | 
| 1744 |  | 
| 1745 class LabeledStatementLabelScope implements LabelScope { |  | 
| 1746   final LabelScope outer; |  | 
| 1747   final Map<String, LabelDefinition> labels; |  | 
| 1748   LabeledStatementLabelScope(this.outer, this.labels); |  | 
| 1749   LabelDefinition lookup(String labelName) { |  | 
| 1750     LabelDefinition label = labels[labelName]; |  | 
| 1751     if (label != null) return label; |  | 
| 1752     return outer.lookup(labelName); |  | 
| 1753   } |  | 
| 1754 } |  | 
| 1755 |  | 
| 1756 class SwitchLabelScope implements LabelScope { |  | 
| 1757   final LabelScope outer; |  | 
| 1758   final Map<String, LabelDefinition> caseLabels; |  | 
| 1759 |  | 
| 1760   SwitchLabelScope(this.outer, this.caseLabels); |  | 
| 1761 |  | 
| 1762   LabelDefinition lookup(String labelName) { |  | 
| 1763     LabelDefinition result = caseLabels[labelName]; |  | 
| 1764     if (result != null) return result; |  | 
| 1765     return outer.lookup(labelName); |  | 
| 1766   } |  | 
| 1767 } |  | 
| 1768 |  | 
| 1769 class EmptyLabelScope implements LabelScope { |  | 
| 1770   const EmptyLabelScope(); |  | 
| 1771   LabelDefinition lookup(String label) => null; |  | 
| 1772   LabelScope get outer { |  | 
| 1773     throw 'internal error: empty label scope has no outer'; |  | 
| 1774   } |  | 
| 1775 } |  | 
| 1776 |  | 
| 1777 class StatementScope { |  | 
| 1778   LabelScope labels; |  | 
| 1779   Link<JumpTarget> breakTargetStack; |  | 
| 1780   Link<JumpTarget> continueTargetStack; |  | 
| 1781   // Used to provide different numbers to statements if one is inside the other. |  | 
| 1782   // Can be used to make otherwise duplicate labels unique. |  | 
| 1783   int nestingLevel = 0; |  | 
| 1784 |  | 
| 1785   StatementScope() |  | 
| 1786       : labels = const EmptyLabelScope(), |  | 
| 1787         breakTargetStack = const Link<JumpTarget>(), |  | 
| 1788         continueTargetStack = const Link<JumpTarget>(); |  | 
| 1789 |  | 
| 1790   LabelDefinition lookupLabel(String label) { |  | 
| 1791     return labels.lookup(label); |  | 
| 1792   } |  | 
| 1793 |  | 
| 1794   JumpTarget currentBreakTarget() => |  | 
| 1795     breakTargetStack.isEmpty ? null : breakTargetStack.head; |  | 
| 1796 |  | 
| 1797   JumpTarget currentContinueTarget() => |  | 
| 1798     continueTargetStack.isEmpty ? null : continueTargetStack.head; |  | 
| 1799 |  | 
| 1800   void enterLabelScope(Map<String, LabelDefinition> elements) { |  | 
| 1801     labels = new LabeledStatementLabelScope(labels, elements); |  | 
| 1802     nestingLevel++; |  | 
| 1803   } |  | 
| 1804 |  | 
| 1805   void exitLabelScope() { |  | 
| 1806     nestingLevel--; |  | 
| 1807     labels = labels.outer; |  | 
| 1808   } |  | 
| 1809 |  | 
| 1810   void enterLoop(JumpTarget element) { |  | 
| 1811     breakTargetStack = breakTargetStack.prepend(element); |  | 
| 1812     continueTargetStack = continueTargetStack.prepend(element); |  | 
| 1813     nestingLevel++; |  | 
| 1814   } |  | 
| 1815 |  | 
| 1816   void exitLoop() { |  | 
| 1817     nestingLevel--; |  | 
| 1818     breakTargetStack = breakTargetStack.tail; |  | 
| 1819     continueTargetStack = continueTargetStack.tail; |  | 
| 1820   } |  | 
| 1821 |  | 
| 1822   void enterSwitch(JumpTarget breakElement, |  | 
| 1823                    Map<String, LabelDefinition> continueElements) { |  | 
| 1824     breakTargetStack = breakTargetStack.prepend(breakElement); |  | 
| 1825     labels = new SwitchLabelScope(labels, continueElements); |  | 
| 1826     nestingLevel++; |  | 
| 1827   } |  | 
| 1828 |  | 
| 1829   void exitSwitch() { |  | 
| 1830     nestingLevel--; |  | 
| 1831     breakTargetStack = breakTargetStack.tail; |  | 
| 1832     labels = labels.outer; |  | 
| 1833   } |  | 
| 1834 } |  | 
| 1835 |  | 
| 1836 class TypeResolver { |  | 
| 1837   final Compiler compiler; |  | 
| 1838 |  | 
| 1839   TypeResolver(this.compiler); |  | 
| 1840 |  | 
| 1841   /// Tries to resolve the type name as an element. |  | 
| 1842   Element resolveTypeName(Identifier prefixName, |  | 
| 1843                           Identifier typeName, |  | 
| 1844                           Scope scope, |  | 
| 1845                           {bool deferredIsMalformed: true}) { |  | 
| 1846     Element element; |  | 
| 1847     bool deferredTypeAnnotation = false; |  | 
| 1848     if (prefixName != null) { |  | 
| 1849       Element prefixElement = |  | 
| 1850           lookupInScope(compiler, prefixName, scope, prefixName.source); |  | 
| 1851       if (prefixElement != null && prefixElement.isPrefix) { |  | 
| 1852         // The receiver is a prefix. Lookup in the imported members. |  | 
| 1853         PrefixElement prefix = prefixElement; |  | 
| 1854         element = prefix.lookupLocalMember(typeName.source); |  | 
| 1855         // TODO(17260, sigurdm): The test for DartBackend is there because |  | 
| 1856         // dart2dart outputs malformed types with prefix. |  | 
| 1857         if (element != null && |  | 
| 1858             prefix.isDeferred && |  | 
| 1859             deferredIsMalformed && |  | 
| 1860             compiler.backend is! DartBackend) { |  | 
| 1861           element = new ErroneousElementX(MessageKind.DEFERRED_TYPE_ANNOTATION, |  | 
| 1862                                           {'node': typeName}, |  | 
| 1863                                           element.name, |  | 
| 1864                                           element); |  | 
| 1865         } |  | 
| 1866       } else { |  | 
| 1867         // The caller of this method will create the ErroneousElement for |  | 
| 1868         // the MalformedType. |  | 
| 1869         element = null; |  | 
| 1870       } |  | 
| 1871     } else { |  | 
| 1872       String stringValue = typeName.source; |  | 
| 1873       element = lookupInScope(compiler, typeName, scope, typeName.source); |  | 
| 1874     } |  | 
| 1875     return element; |  | 
| 1876   } |  | 
| 1877 |  | 
| 1878   DartType resolveTypeAnnotation(MappingVisitor visitor, TypeAnnotation node, |  | 
| 1879                                  {bool malformedIsError: false, |  | 
| 1880                                   bool deferredIsMalformed: true}) { |  | 
| 1881     ResolutionRegistry registry = visitor.registry; |  | 
| 1882 |  | 
| 1883     Identifier typeName; |  | 
| 1884     DartType type; |  | 
| 1885 |  | 
| 1886     DartType checkNoTypeArguments(DartType type) { |  | 
| 1887       List<DartType> arguments = new List<DartType>(); |  | 
| 1888       bool hasTypeArgumentMismatch = resolveTypeArguments( |  | 
| 1889           visitor, node, const <DartType>[], arguments); |  | 
| 1890       if (hasTypeArgumentMismatch) { |  | 
| 1891         return new MalformedType( |  | 
| 1892             new ErroneousElementX(MessageKind.TYPE_ARGUMENT_COUNT_MISMATCH, |  | 
| 1893                 {'type': node}, typeName.source, visitor.enclosingElement), |  | 
| 1894                 type, arguments); |  | 
| 1895       } |  | 
| 1896       return type; |  | 
| 1897     } |  | 
| 1898 |  | 
| 1899     Identifier prefixName; |  | 
| 1900     Send send = node.typeName.asSend(); |  | 
| 1901     if (send != null) { |  | 
| 1902       // The type name is of the form [: prefix . identifier :]. |  | 
| 1903       prefixName = send.receiver.asIdentifier(); |  | 
| 1904       typeName = send.selector.asIdentifier(); |  | 
| 1905     } else { |  | 
| 1906       typeName = node.typeName.asIdentifier(); |  | 
| 1907       if (identical(typeName.source, 'void')) { |  | 
| 1908         type = const VoidType(); |  | 
| 1909         checkNoTypeArguments(type); |  | 
| 1910         registry.useType(node, type); |  | 
| 1911         return type; |  | 
| 1912       } else if (identical(typeName.source, 'dynamic')) { |  | 
| 1913         type = const DynamicType(); |  | 
| 1914         checkNoTypeArguments(type); |  | 
| 1915         registry.useType(node, type); |  | 
| 1916         return type; |  | 
| 1917       } |  | 
| 1918     } |  | 
| 1919 |  | 
| 1920     Element element = resolveTypeName(prefixName, typeName, visitor.scope, |  | 
| 1921                                       deferredIsMalformed: deferredIsMalformed); |  | 
| 1922 |  | 
| 1923     DartType reportFailureAndCreateType(MessageKind messageKind, |  | 
| 1924                                         Map messageArguments, |  | 
| 1925                                         {DartType userProvidedBadType, |  | 
| 1926                                          Element erroneousElement}) { |  | 
| 1927       if (malformedIsError) { |  | 
| 1928         visitor.error(node, messageKind, messageArguments); |  | 
| 1929       } else { |  | 
| 1930         registry.registerThrowRuntimeError(); |  | 
| 1931         visitor.warning(node, messageKind, messageArguments); |  | 
| 1932       } |  | 
| 1933       if (erroneousElement == null) { |  | 
| 1934          erroneousElement = new ErroneousElementX( |  | 
| 1935             messageKind, messageArguments, typeName.source, |  | 
| 1936             visitor.enclosingElement); |  | 
| 1937       } |  | 
| 1938       List<DartType> arguments = <DartType>[]; |  | 
| 1939       resolveTypeArguments(visitor, node, const <DartType>[], arguments); |  | 
| 1940       return new MalformedType(erroneousElement, |  | 
| 1941               userProvidedBadType, arguments); |  | 
| 1942     } |  | 
| 1943 |  | 
| 1944     // Try to construct the type from the element. |  | 
| 1945     if (element == null) { |  | 
| 1946       type = reportFailureAndCreateType( |  | 
| 1947           MessageKind.CANNOT_RESOLVE_TYPE, {'typeName': node.typeName}); |  | 
| 1948     } else if (element.isAmbiguous) { |  | 
| 1949       AmbiguousElement ambiguous = element; |  | 
| 1950       type = reportFailureAndCreateType( |  | 
| 1951           ambiguous.messageKind, ambiguous.messageArguments); |  | 
| 1952       ambiguous.diagnose(registry.mapping.analyzedElement, compiler); |  | 
| 1953     } else if (element.isErroneous) { |  | 
| 1954       ErroneousElement erroneousElement = element; |  | 
| 1955       type = reportFailureAndCreateType( |  | 
| 1956           erroneousElement.messageKind, erroneousElement.messageArguments, |  | 
| 1957           erroneousElement: erroneousElement); |  | 
| 1958     } else if (!element.impliesType) { |  | 
| 1959       type = reportFailureAndCreateType( |  | 
| 1960           MessageKind.NOT_A_TYPE, {'node': node.typeName}); |  | 
| 1961     } else { |  | 
| 1962       bool addTypeVariableBoundsCheck = false; |  | 
| 1963       if (element.isClass) { |  | 
| 1964         ClassElement cls = element; |  | 
| 1965         // TODO(johnniwinther): [_ensureClassWillBeResolved] should imply |  | 
| 1966         // [computeType]. |  | 
| 1967         compiler.resolver._ensureClassWillBeResolved(cls); |  | 
| 1968         element.computeType(compiler); |  | 
| 1969         List<DartType> arguments = <DartType>[]; |  | 
| 1970         bool hasTypeArgumentMismatch = resolveTypeArguments( |  | 
| 1971             visitor, node, cls.typeVariables, arguments); |  | 
| 1972         if (hasTypeArgumentMismatch) { |  | 
| 1973           type = new BadInterfaceType(cls.declaration, |  | 
| 1974               new InterfaceType.forUserProvidedBadType(cls.declaration, |  | 
| 1975                                                        arguments)); |  | 
| 1976         } else { |  | 
| 1977           if (arguments.isEmpty) { |  | 
| 1978             type = cls.rawType; |  | 
| 1979           } else { |  | 
| 1980             type = new InterfaceType(cls.declaration, arguments.toList(growable:
       false)); |  | 
| 1981             addTypeVariableBoundsCheck = true; |  | 
| 1982           } |  | 
| 1983         } |  | 
| 1984       } else if (element.isTypedef) { |  | 
| 1985         TypedefElement typdef = element; |  | 
| 1986         // TODO(johnniwinther): [ensureResolved] should imply [computeType]. |  | 
| 1987         typdef.ensureResolved(compiler); |  | 
| 1988         element.computeType(compiler); |  | 
| 1989         List<DartType> arguments = <DartType>[]; |  | 
| 1990         bool hasTypeArgumentMismatch = resolveTypeArguments( |  | 
| 1991             visitor, node, typdef.typeVariables, arguments); |  | 
| 1992         if (hasTypeArgumentMismatch) { |  | 
| 1993           type = new BadTypedefType(typdef, |  | 
| 1994               new TypedefType.forUserProvidedBadType(typdef, arguments)); |  | 
| 1995         } else { |  | 
| 1996           if (arguments.isEmpty) { |  | 
| 1997             type = typdef.rawType; |  | 
| 1998           } else { |  | 
| 1999             type = new TypedefType(typdef, arguments.toList(growable: false)); |  | 
| 2000             addTypeVariableBoundsCheck = true; |  | 
| 2001           } |  | 
| 2002         } |  | 
| 2003       } else if (element.isTypeVariable) { |  | 
| 2004         Element outer = |  | 
| 2005             visitor.enclosingElement.outermostEnclosingMemberOrTopLevel; |  | 
| 2006         bool isInFactoryConstructor = |  | 
| 2007             outer != null && outer.isFactoryConstructor; |  | 
| 2008         if (!outer.isClass && |  | 
| 2009             !outer.isTypedef && |  | 
| 2010             !isInFactoryConstructor && |  | 
| 2011             Elements.isInStaticContext(visitor.enclosingElement)) { |  | 
| 2012           registry.registerThrowRuntimeError(); |  | 
| 2013           type = reportFailureAndCreateType( |  | 
| 2014               MessageKind.TYPE_VARIABLE_WITHIN_STATIC_MEMBER, |  | 
| 2015               {'typeVariableName': node}, |  | 
| 2016               userProvidedBadType: element.computeType(compiler)); |  | 
| 2017         } else { |  | 
| 2018           type = element.computeType(compiler); |  | 
| 2019         } |  | 
| 2020         type = checkNoTypeArguments(type); |  | 
| 2021       } else { |  | 
| 2022         compiler.internalError(node, |  | 
| 2023             "Unexpected element kind ${element.kind}."); |  | 
| 2024       } |  | 
| 2025       if (addTypeVariableBoundsCheck) { |  | 
| 2026         registry.registerTypeVariableBoundCheck(); |  | 
| 2027         visitor.addDeferredAction( |  | 
| 2028             visitor.enclosingElement, |  | 
| 2029             () => checkTypeVariableBounds(node, type)); |  | 
| 2030       } |  | 
| 2031     } |  | 
| 2032     registry.useType(node, type); |  | 
| 2033     return type; |  | 
| 2034   } |  | 
| 2035 |  | 
| 2036   /// Checks the type arguments of [type] against the type variable bounds. |  | 
| 2037   void checkTypeVariableBounds(TypeAnnotation node, GenericType type) { |  | 
| 2038     void checkTypeVariableBound(_, DartType typeArgument, |  | 
| 2039                                    TypeVariableType typeVariable, |  | 
| 2040                                    DartType bound) { |  | 
| 2041       if (!compiler.types.isSubtype(typeArgument, bound)) { |  | 
| 2042         compiler.reportWarning(node, |  | 
| 2043             MessageKind.INVALID_TYPE_VARIABLE_BOUND, |  | 
| 2044             {'typeVariable': typeVariable, |  | 
| 2045              'bound': bound, |  | 
| 2046              'typeArgument': typeArgument, |  | 
| 2047              'thisType': type.element.thisType}); |  | 
| 2048       } |  | 
| 2049     }; |  | 
| 2050 |  | 
| 2051     compiler.types.checkTypeVariableBounds(type, checkTypeVariableBound); |  | 
| 2052   } |  | 
| 2053 |  | 
| 2054   /** |  | 
| 2055    * Resolves the type arguments of [node] and adds these to [arguments]. |  | 
| 2056    * |  | 
| 2057    * Returns [: true :] if the number of type arguments did not match the |  | 
| 2058    * number of type variables. |  | 
| 2059    */ |  | 
| 2060   bool resolveTypeArguments(MappingVisitor visitor, |  | 
| 2061                             TypeAnnotation node, |  | 
| 2062                             List<DartType> typeVariables, |  | 
| 2063                             List<DartType> arguments) { |  | 
| 2064     if (node.typeArguments == null) { |  | 
| 2065       return false; |  | 
| 2066     } |  | 
| 2067     int expectedVariables = typeVariables.length; |  | 
| 2068     int index = 0; |  | 
| 2069     bool typeArgumentCountMismatch = false; |  | 
| 2070     for (Link<Node> typeArguments = node.typeArguments.nodes; |  | 
| 2071          !typeArguments.isEmpty; |  | 
| 2072          typeArguments = typeArguments.tail, index++) { |  | 
| 2073       if (index > expectedVariables - 1) { |  | 
| 2074         visitor.warning( |  | 
| 2075             typeArguments.head, MessageKind.ADDITIONAL_TYPE_ARGUMENT); |  | 
| 2076         typeArgumentCountMismatch = true; |  | 
| 2077       } |  | 
| 2078       DartType argType = resolveTypeAnnotation(visitor, typeArguments.head); |  | 
| 2079       // TODO(karlklose): rewrite to not modify [arguments]. |  | 
| 2080       arguments.add(argType); |  | 
| 2081     } |  | 
| 2082     if (index < expectedVariables) { |  | 
| 2083       visitor.warning(node.typeArguments, |  | 
| 2084                       MessageKind.MISSING_TYPE_ARGUMENT); |  | 
| 2085       typeArgumentCountMismatch = true; |  | 
| 2086     } |  | 
| 2087     return typeArgumentCountMismatch; |  | 
| 2088   } |  | 
| 2089 } |  | 
| 2090 |  | 
| 2091 /** |  | 
| 2092  * Common supertype for resolver visitors that record resolutions in a |  | 
| 2093  * [ResolutionRegistry]. |  | 
| 2094  */ |  | 
| 2095 abstract class MappingVisitor<T> extends CommonResolverVisitor<T> { |  | 
| 2096   final ResolutionRegistry registry; |  | 
| 2097   final TypeResolver typeResolver; |  | 
| 2098   /// The current enclosing element for the visited AST nodes. |  | 
| 2099   Element get enclosingElement; |  | 
| 2100   /// The current scope of the visitor. |  | 
| 2101   Scope get scope; |  | 
| 2102 |  | 
| 2103   MappingVisitor(Compiler compiler, ResolutionRegistry this.registry) |  | 
| 2104       : typeResolver = new TypeResolver(compiler), |  | 
| 2105         super(compiler); |  | 
| 2106 |  | 
| 2107   /// Add [element] to the current scope and check for duplicate definitions. |  | 
| 2108   void addToScope(Element element) { |  | 
| 2109     Element existing = scope.add(element); |  | 
| 2110     if (existing != element) { |  | 
| 2111       reportDuplicateDefinition(element.name, element, existing); |  | 
| 2112     } |  | 
| 2113   } |  | 
| 2114 |  | 
| 2115   /// Register [node] as the definition of [element]. |  | 
| 2116   void defineLocalVariable(Node node, LocalVariableElement element) { |  | 
| 2117     invariant(node, element != null); |  | 
| 2118     registry.defineElement(node, element); |  | 
| 2119   } |  | 
| 2120 |  | 
| 2121   void reportDuplicateDefinition(String name, |  | 
| 2122                                  Spannable definition, |  | 
| 2123                                  Spannable existing) { |  | 
| 2124     compiler.reportError(definition, |  | 
| 2125         MessageKind.DUPLICATE_DEFINITION, {'name': name}); |  | 
| 2126     compiler.reportInfo(existing, |  | 
| 2127         MessageKind.EXISTING_DEFINITION, {'name': name}); |  | 
| 2128   } |  | 
| 2129 } |  | 
| 2130 |  | 
| 2131 /** |  | 
| 2132  * Core implementation of resolution. |  | 
| 2133  * |  | 
| 2134  * Do not subclass or instantiate this class outside this library |  | 
| 2135  * except for testing. |  | 
| 2136  */ |  | 
| 2137 class ResolverVisitor extends MappingVisitor<ResolutionResult> { |  | 
| 2138   /** |  | 
| 2139    * The current enclosing element for the visited AST nodes. |  | 
| 2140    * |  | 
| 2141    * This field is updated when nested closures are visited. |  | 
| 2142    */ |  | 
| 2143   Element enclosingElement; |  | 
| 2144   bool inInstanceContext; |  | 
| 2145   bool inCheckContext; |  | 
| 2146   bool inCatchBlock; |  | 
| 2147 |  | 
| 2148   Scope scope; |  | 
| 2149   ClassElement currentClass; |  | 
| 2150   ExpressionStatement currentExpressionStatement; |  | 
| 2151   bool sendIsMemberAccess = false; |  | 
| 2152   StatementScope statementScope; |  | 
| 2153   int allowedCategory = ElementCategory.VARIABLE | ElementCategory.FUNCTION |  | 
| 2154       | ElementCategory.IMPLIES_TYPE; |  | 
| 2155 |  | 
| 2156   /** |  | 
| 2157    * Record of argument nodes to JS_INTERCEPTOR_CONSTANT for deferred |  | 
| 2158    * processing. |  | 
| 2159    */ |  | 
| 2160   Set<Node> argumentsToJsInterceptorConstant = null; |  | 
| 2161 |  | 
| 2162   /// When visiting the type declaration of the variable in a [ForIn] loop, |  | 
| 2163   /// the initializer of the variable is implicit and we should not emit an |  | 
| 2164   /// error when verifying that all final variables are initialized. |  | 
| 2165   bool allowFinalWithoutInitializer = false; |  | 
| 2166 |  | 
| 2167   /// The nodes for which variable access and mutation must be registered in |  | 
| 2168   /// order to determine when the static type of variables types is promoted. |  | 
| 2169   Link<Node> promotionScope = const Link<Node>(); |  | 
| 2170 |  | 
| 2171   bool isPotentiallyMutableTarget(Element target) { |  | 
| 2172     if (target == null) return false; |  | 
| 2173     return (target.isVariable || target.isParameter) && |  | 
| 2174       !(target.isFinal || target.isConst); |  | 
| 2175   } |  | 
| 2176 |  | 
| 2177   // TODO(ahe): Find a way to share this with runtime implementation. |  | 
| 2178   static final RegExp symbolValidationPattern = |  | 
| 2179       new RegExp(r'^(?:[a-zA-Z$][a-zA-Z$0-9_]*\.)*(?:[a-zA-Z$][a-zA-Z$0-9_]*=?|' |  | 
| 2180                  r'-|' |  | 
| 2181                  r'unary-|' |  | 
| 2182                  r'\[\]=|' |  | 
| 2183                  r'~|' |  | 
| 2184                  r'==|' |  | 
| 2185                  r'\[\]|' |  | 
| 2186                  r'\*|' |  | 
| 2187                  r'/|' |  | 
| 2188                  r'%|' |  | 
| 2189                  r'~/|' |  | 
| 2190                  r'\+|' |  | 
| 2191                  r'<<|' |  | 
| 2192                  r'>>|' |  | 
| 2193                  r'>=|' |  | 
| 2194                  r'>|' |  | 
| 2195                  r'<=|' |  | 
| 2196                  r'<|' |  | 
| 2197                  r'&|' |  | 
| 2198                  r'\^|' |  | 
| 2199                  r'\|' |  | 
| 2200                  r')$'); |  | 
| 2201 |  | 
| 2202   ResolverVisitor(Compiler compiler, |  | 
| 2203                   Element element, |  | 
| 2204                   ResolutionRegistry registry, |  | 
| 2205                   {bool useEnclosingScope: false}) |  | 
| 2206     : this.enclosingElement = element, |  | 
| 2207       // When the element is a field, we are actually resolving its |  | 
| 2208       // initial value, which should not have access to instance |  | 
| 2209       // fields. |  | 
| 2210       inInstanceContext = (element.isInstanceMember && !element.isField) |  | 
| 2211           || element.isGenerativeConstructor, |  | 
| 2212       this.currentClass = element.isClassMember ? element.enclosingClass |  | 
| 2213                                              : null, |  | 
| 2214       this.statementScope = new StatementScope(), |  | 
| 2215       scope = useEnclosingScope |  | 
| 2216           ? Scope.buildEnclosingScope(element) : element.buildScope(), |  | 
| 2217       // The type annotations on a typedef do not imply type checks. |  | 
| 2218       // TODO(karlklose): clean this up (dartbug.com/8870). |  | 
| 2219       inCheckContext = compiler.enableTypeAssertions && |  | 
| 2220           !element.isLibrary && |  | 
| 2221           !element.isTypedef && |  | 
| 2222           !element.enclosingElement.isTypedef, |  | 
| 2223       inCatchBlock = false, |  | 
| 2224       super(compiler, registry); |  | 
| 2225 |  | 
| 2226   Element reportLookupErrorIfAny(Element result, Node node, String name) { |  | 
| 2227     if (!Elements.isUnresolved(result)) { |  | 
| 2228       if (!inInstanceContext && result.isInstanceMember) { |  | 
| 2229         compiler.reportError( |  | 
| 2230             node, MessageKind.NO_INSTANCE_AVAILABLE, {'name': name}); |  | 
| 2231         return new ErroneousElementX(MessageKind.NO_INSTANCE_AVAILABLE, |  | 
| 2232                                      {'name': name}, |  | 
| 2233                                      name, enclosingElement); |  | 
| 2234       } else if (result.isAmbiguous) { |  | 
| 2235         AmbiguousElement ambiguous = result; |  | 
| 2236         compiler.reportError( |  | 
| 2237             node, ambiguous.messageKind, ambiguous.messageArguments); |  | 
| 2238         ambiguous.diagnose(enclosingElement, compiler); |  | 
| 2239         return new ErroneousElementX(ambiguous.messageKind, |  | 
| 2240                                      ambiguous.messageArguments, |  | 
| 2241                                      name, enclosingElement); |  | 
| 2242       } |  | 
| 2243     } |  | 
| 2244     return result; |  | 
| 2245   } |  | 
| 2246 |  | 
| 2247   // Create, or reuse an already created, target element for a statement. |  | 
| 2248   JumpTarget getOrDefineTarget(Node statement) { |  | 
| 2249     JumpTarget element = registry.getTargetDefinition(statement); |  | 
| 2250     if (element == null) { |  | 
| 2251       element = new JumpTargetX(statement, |  | 
| 2252                                    statementScope.nestingLevel, |  | 
| 2253                                    enclosingElement); |  | 
| 2254       registry.defineTarget(statement, element); |  | 
| 2255     } |  | 
| 2256     return element; |  | 
| 2257   } |  | 
| 2258 |  | 
| 2259   doInCheckContext(action()) { |  | 
| 2260     bool wasInCheckContext = inCheckContext; |  | 
| 2261     inCheckContext = true; |  | 
| 2262     var result = action(); |  | 
| 2263     inCheckContext = wasInCheckContext; |  | 
| 2264     return result; |  | 
| 2265   } |  | 
| 2266 |  | 
| 2267   inStaticContext(action()) { |  | 
| 2268     bool wasInstanceContext = inInstanceContext; |  | 
| 2269     inInstanceContext = false; |  | 
| 2270     var result = action(); |  | 
| 2271     inInstanceContext = wasInstanceContext; |  | 
| 2272     return result; |  | 
| 2273   } |  | 
| 2274 |  | 
| 2275   doInPromotionScope(Node node, action()) { |  | 
| 2276     promotionScope = promotionScope.prepend(node); |  | 
| 2277     var result = action(); |  | 
| 2278     promotionScope = promotionScope.tail; |  | 
| 2279     return result; |  | 
| 2280   } |  | 
| 2281 |  | 
| 2282   visitInStaticContext(Node node) { |  | 
| 2283     inStaticContext(() => visit(node)); |  | 
| 2284   } |  | 
| 2285 |  | 
| 2286   ErroneousElement warnAndCreateErroneousElement(Node node, |  | 
| 2287                                                  String name, |  | 
| 2288                                                  MessageKind kind, |  | 
| 2289                                                  [Map arguments = const {}]) { |  | 
| 2290     compiler.reportWarning(node, kind, arguments); |  | 
| 2291     return new ErroneousElementX(kind, arguments, name, enclosingElement); |  | 
| 2292   } |  | 
| 2293 |  | 
| 2294   ResolutionResult visitIdentifier(Identifier node) { |  | 
| 2295     if (node.isThis()) { |  | 
| 2296       if (!inInstanceContext) { |  | 
| 2297         error(node, MessageKind.NO_INSTANCE_AVAILABLE, {'name': node}); |  | 
| 2298       } |  | 
| 2299       return null; |  | 
| 2300     } else if (node.isSuper()) { |  | 
| 2301       if (!inInstanceContext) error(node, MessageKind.NO_SUPER_IN_STATIC); |  | 
| 2302       if ((ElementCategory.SUPER & allowedCategory) == 0) { |  | 
| 2303         error(node, MessageKind.INVALID_USE_OF_SUPER); |  | 
| 2304       } |  | 
| 2305       return null; |  | 
| 2306     } else { |  | 
| 2307       String name = node.source; |  | 
| 2308       Element element = lookupInScope(compiler, node, scope, name); |  | 
| 2309       if (Elements.isUnresolved(element) && name == 'dynamic') { |  | 
| 2310         // TODO(johnniwinther): Remove this hack when we can return more complex |  | 
| 2311         // objects than [Element] from this method. |  | 
| 2312         element = compiler.typeClass; |  | 
| 2313         // Set the type to be `dynamic` to mark that this is a type literal. |  | 
| 2314         registry.setType(node, const DynamicType()); |  | 
| 2315       } |  | 
| 2316       element = reportLookupErrorIfAny(element, node, node.source); |  | 
| 2317       if (element == null) { |  | 
| 2318         if (!inInstanceContext) { |  | 
| 2319           element = warnAndCreateErroneousElement( |  | 
| 2320               node, node.source, MessageKind.CANNOT_RESOLVE, |  | 
| 2321               {'name': node}); |  | 
| 2322           registry.registerThrowNoSuchMethod(); |  | 
| 2323         } |  | 
| 2324       } else if (element.isErroneous) { |  | 
| 2325         // Use the erroneous element. |  | 
| 2326       } else { |  | 
| 2327         if ((element.kind.category & allowedCategory) == 0) { |  | 
| 2328           // TODO(ahe): Improve error message. Need UX input. |  | 
| 2329           error(node, MessageKind.GENERIC, |  | 
| 2330                 {'text': "is not an expression $element"}); |  | 
| 2331         } |  | 
| 2332       } |  | 
| 2333       if (!Elements.isUnresolved(element) && element.isClass) { |  | 
| 2334         ClassElement classElement = element; |  | 
| 2335         classElement.ensureResolved(compiler); |  | 
| 2336       } |  | 
| 2337       return new ElementResult(registry.useElement(node, element)); |  | 
| 2338     } |  | 
| 2339   } |  | 
| 2340 |  | 
| 2341   ResolutionResult visitTypeAnnotation(TypeAnnotation node) { |  | 
| 2342     DartType type = resolveTypeAnnotation(node); |  | 
| 2343     if (inCheckContext) { |  | 
| 2344       registry.registerIsCheck(type); |  | 
| 2345     } |  | 
| 2346     return new TypeResult(type); |  | 
| 2347   } |  | 
| 2348 |  | 
| 2349   bool isNamedConstructor(Send node) => node.receiver != null; |  | 
| 2350 |  | 
| 2351   Selector getRedirectingThisOrSuperConstructorSelector(Send node) { |  | 
| 2352     if (isNamedConstructor(node)) { |  | 
| 2353       String constructorName = node.selector.asIdentifier().source; |  | 
| 2354       return new Selector.callConstructor( |  | 
| 2355           constructorName, |  | 
| 2356           enclosingElement.library); |  | 
| 2357     } else { |  | 
| 2358       return new Selector.callDefaultConstructor( |  | 
| 2359           enclosingElement.library); |  | 
| 2360     } |  | 
| 2361   } |  | 
| 2362 |  | 
| 2363   FunctionElement resolveConstructorRedirection(FunctionElementX constructor) { |  | 
| 2364     FunctionExpression node = constructor.parseNode(compiler); |  | 
| 2365 |  | 
| 2366     // A synthetic constructor does not have a node. |  | 
| 2367     if (node == null) return null; |  | 
| 2368     if (node.initializers == null) return null; |  | 
| 2369     Link<Node> initializers = node.initializers.nodes; |  | 
| 2370     if (!initializers.isEmpty && |  | 
| 2371         Initializers.isConstructorRedirect(initializers.head)) { |  | 
| 2372       Selector selector = |  | 
| 2373           getRedirectingThisOrSuperConstructorSelector(initializers.head); |  | 
| 2374       final ClassElement classElement = constructor.enclosingClass; |  | 
| 2375       return classElement.lookupConstructor(selector); |  | 
| 2376     } |  | 
| 2377     return null; |  | 
| 2378   } |  | 
| 2379 |  | 
| 2380   void setupFunction(FunctionExpression node, FunctionElement function) { |  | 
| 2381     Element enclosingElement = function.enclosingElement; |  | 
| 2382     if (node.modifiers.isStatic && |  | 
| 2383         enclosingElement.kind != ElementKind.CLASS) { |  | 
| 2384       compiler.reportError(node, MessageKind.ILLEGAL_STATIC); |  | 
| 2385     } |  | 
| 2386 |  | 
| 2387     scope = new MethodScope(scope, function); |  | 
| 2388     // Put the parameters in scope. |  | 
| 2389     FunctionSignature functionParameters = function.functionSignature; |  | 
| 2390     Link<Node> parameterNodes = (node.parameters == null) |  | 
| 2391         ? const Link<Node>() : node.parameters.nodes; |  | 
| 2392     functionParameters.forEachParameter((ParameterElement element) { |  | 
| 2393       // TODO(karlklose): should be a list of [FormalElement]s, but the actual |  | 
| 2394       // implementation uses [Element]. |  | 
| 2395       Link<Element> optionals = functionParameters.optionalParameters; |  | 
| 2396       if (!optionals.isEmpty && element == optionals.head) { |  | 
| 2397         NodeList nodes = parameterNodes.head; |  | 
| 2398         parameterNodes = nodes.nodes; |  | 
| 2399       } |  | 
| 2400       visit(element.initializer); |  | 
| 2401       VariableDefinitions variableDefinitions = parameterNodes.head; |  | 
| 2402       Node parameterNode = variableDefinitions.definitions.nodes.head; |  | 
| 2403       // Field parameters (this.x) are not visible inside the constructor. The |  | 
| 2404       // fields they reference are visible, but must be resolved independently. |  | 
| 2405       if (element.isInitializingFormal) { |  | 
| 2406         registry.useElement(parameterNode, element); |  | 
| 2407       } else { |  | 
| 2408         LocalParameterElement parameterElement = element; |  | 
| 2409         defineLocalVariable(parameterNode, parameterElement); |  | 
| 2410         addToScope(parameterElement); |  | 
| 2411       } |  | 
| 2412       parameterNodes = parameterNodes.tail; |  | 
| 2413     }); |  | 
| 2414     addDeferredAction(enclosingElement, () { |  | 
| 2415       functionParameters.forEachOptionalParameter((Element parameter) { |  | 
| 2416         compiler.resolver.constantCompiler.compileConstant(parameter); |  | 
| 2417       }); |  | 
| 2418     }); |  | 
| 2419     if (inCheckContext) { |  | 
| 2420       functionParameters.forEachParameter((ParameterElement element) { |  | 
| 2421         registry.registerIsCheck(element.type); |  | 
| 2422       }); |  | 
| 2423     } |  | 
| 2424   } |  | 
| 2425 |  | 
| 2426   visitCascade(Cascade node) { |  | 
| 2427     visit(node.expression); |  | 
| 2428   } |  | 
| 2429 |  | 
| 2430   visitCascadeReceiver(CascadeReceiver node) { |  | 
| 2431     visit(node.expression); |  | 
| 2432   } |  | 
| 2433 |  | 
| 2434   visitClassNode(ClassNode node) { |  | 
| 2435     internalError(node, "shouldn't be called"); |  | 
| 2436   } |  | 
| 2437 |  | 
| 2438   visitIn(Node node, Scope nestedScope) { |  | 
| 2439     Scope oldScope = scope; |  | 
| 2440     scope = nestedScope; |  | 
| 2441     ResolutionResult result = visit(node); |  | 
| 2442     scope = oldScope; |  | 
| 2443     return result; |  | 
| 2444   } |  | 
| 2445 |  | 
| 2446   /** |  | 
| 2447    * Introduces new default targets for break and continue |  | 
| 2448    * before visiting the body of the loop |  | 
| 2449    */ |  | 
| 2450   visitLoopBodyIn(Loop loop, Node body, Scope bodyScope) { |  | 
| 2451     JumpTarget element = getOrDefineTarget(loop); |  | 
| 2452     statementScope.enterLoop(element); |  | 
| 2453     visitIn(body, bodyScope); |  | 
| 2454     statementScope.exitLoop(); |  | 
| 2455     if (!element.isTarget) { |  | 
| 2456       registry.undefineTarget(loop); |  | 
| 2457     } |  | 
| 2458   } |  | 
| 2459 |  | 
| 2460   visitBlock(Block node) { |  | 
| 2461     visitIn(node.statements, new BlockScope(scope)); |  | 
| 2462   } |  | 
| 2463 |  | 
| 2464   visitDoWhile(DoWhile node) { |  | 
| 2465     visitLoopBodyIn(node, node.body, new BlockScope(scope)); |  | 
| 2466     visit(node.condition); |  | 
| 2467   } |  | 
| 2468 |  | 
| 2469   visitEmptyStatement(EmptyStatement node) { } |  | 
| 2470 |  | 
| 2471   visitExpressionStatement(ExpressionStatement node) { |  | 
| 2472     ExpressionStatement oldExpressionStatement = currentExpressionStatement; |  | 
| 2473     currentExpressionStatement = node; |  | 
| 2474     visit(node.expression); |  | 
| 2475     currentExpressionStatement = oldExpressionStatement; |  | 
| 2476   } |  | 
| 2477 |  | 
| 2478   visitFor(For node) { |  | 
| 2479     Scope blockScope = new BlockScope(scope); |  | 
| 2480     visitIn(node.initializer, blockScope); |  | 
| 2481     visitIn(node.condition, blockScope); |  | 
| 2482     visitIn(node.update, blockScope); |  | 
| 2483     visitLoopBodyIn(node, node.body, blockScope); |  | 
| 2484   } |  | 
| 2485 |  | 
| 2486   visitFunctionDeclaration(FunctionDeclaration node) { |  | 
| 2487     assert(node.function.name != null); |  | 
| 2488     visitFunctionExpression(node.function, inFunctionDeclaration: true); |  | 
| 2489   } |  | 
| 2490 |  | 
| 2491 |  | 
| 2492   /// Process a local function declaration or an anonymous function expression. |  | 
| 2493   /// |  | 
| 2494   /// [inFunctionDeclaration] is `true` when the current node is the immediate |  | 
| 2495   /// child of a function declaration. |  | 
| 2496   /// |  | 
| 2497   /// This is used to distinguish local function declarations from anonymous |  | 
| 2498   /// function expressions. |  | 
| 2499   visitFunctionExpression(FunctionExpression node, |  | 
| 2500                           {bool inFunctionDeclaration: false}) { |  | 
| 2501     bool doAddToScope = inFunctionDeclaration; |  | 
| 2502     if (!inFunctionDeclaration && node.name != null) { |  | 
| 2503       compiler.reportError( |  | 
| 2504           node.name, |  | 
| 2505           MessageKind.NAMED_FUNCTION_EXPRESSION, |  | 
| 2506           {'name': node.name}); |  | 
| 2507     } |  | 
| 2508     visit(node.returnType); |  | 
| 2509     String name; |  | 
| 2510     if (node.name == null) { |  | 
| 2511       name = ""; |  | 
| 2512     } else { |  | 
| 2513       name = node.name.asIdentifier().source; |  | 
| 2514     } |  | 
| 2515     LocalFunctionElementX function = new LocalFunctionElementX( |  | 
| 2516         name, node, ElementKind.FUNCTION, Modifiers.EMPTY, |  | 
| 2517         enclosingElement); |  | 
| 2518     function.functionSignatureCache = |  | 
| 2519         SignatureResolver.analyze(compiler, node.parameters, node.returnType, |  | 
| 2520             function, registry, createRealParameters: true); |  | 
| 2521     registry.defineFunction(node, function); |  | 
| 2522     if (doAddToScope) { |  | 
| 2523       addToScope(function); |  | 
| 2524     } |  | 
| 2525     Scope oldScope = scope; // The scope is modified by [setupFunction]. |  | 
| 2526     setupFunction(node, function); |  | 
| 2527 |  | 
| 2528     Element previousEnclosingElement = enclosingElement; |  | 
| 2529     enclosingElement = function; |  | 
| 2530     // Run the body in a fresh statement scope. |  | 
| 2531     StatementScope oldStatementScope = statementScope; |  | 
| 2532     statementScope = new StatementScope(); |  | 
| 2533     visit(node.body); |  | 
| 2534     statementScope = oldStatementScope; |  | 
| 2535 |  | 
| 2536     scope = oldScope; |  | 
| 2537     enclosingElement = previousEnclosingElement; |  | 
| 2538 |  | 
| 2539     registry.registerClosure(function); |  | 
| 2540     registry.registerInstantiatedClass(compiler.functionClass); |  | 
| 2541   } |  | 
| 2542 |  | 
| 2543   visitIf(If node) { |  | 
| 2544     doInPromotionScope(node.condition.expression, () => visit(node.condition)); |  | 
| 2545     doInPromotionScope(node.thenPart, |  | 
| 2546         () => visitIn(node.thenPart, new BlockScope(scope))); |  | 
| 2547     visitIn(node.elsePart, new BlockScope(scope)); |  | 
| 2548   } |  | 
| 2549 |  | 
| 2550   ResolutionResult resolveSend(Send node) { |  | 
| 2551     Selector selector = resolveSelector(node, null); |  | 
| 2552     if (node.isSuperCall) registry.registerSuperUse(node); |  | 
| 2553 |  | 
| 2554     if (node.receiver == null) { |  | 
| 2555       // If this send is of the form "assert(expr);", then |  | 
| 2556       // this is an assertion. |  | 
| 2557       if (selector.isAssert) { |  | 
| 2558         if (selector.argumentCount != 1) { |  | 
| 2559           error(node.selector, |  | 
| 2560                 MessageKind.WRONG_NUMBER_OF_ARGUMENTS_FOR_ASSERT, |  | 
| 2561                 {'argumentCount': selector.argumentCount}); |  | 
| 2562         } else if (selector.namedArgumentCount != 0) { |  | 
| 2563           error(node.selector, |  | 
| 2564                 MessageKind.ASSERT_IS_GIVEN_NAMED_ARGUMENTS, |  | 
| 2565                 {'argumentCount': selector.namedArgumentCount}); |  | 
| 2566         } |  | 
| 2567         registry.registerAssert(node); |  | 
| 2568         return const AssertResult(); |  | 
| 2569       } |  | 
| 2570 |  | 
| 2571       return node.selector.accept(this); |  | 
| 2572     } |  | 
| 2573 |  | 
| 2574     var oldCategory = allowedCategory; |  | 
| 2575     allowedCategory |= ElementCategory.PREFIX | ElementCategory.SUPER; |  | 
| 2576     ResolutionResult resolvedReceiver = visit(node.receiver); |  | 
| 2577     allowedCategory = oldCategory; |  | 
| 2578 |  | 
| 2579     Element target; |  | 
| 2580     String name = node.selector.asIdentifier().source; |  | 
| 2581     if (identical(name, 'this')) { |  | 
| 2582       // TODO(ahe): Why is this using GENERIC? |  | 
| 2583       error(node.selector, MessageKind.GENERIC, |  | 
| 2584             {'text': "expected an identifier"}); |  | 
| 2585     } else if (node.isSuperCall) { |  | 
| 2586       if (node.isOperator) { |  | 
| 2587         if (isUserDefinableOperator(name)) { |  | 
| 2588           name = selector.name; |  | 
| 2589         } else { |  | 
| 2590           error(node.selector, MessageKind.ILLEGAL_SUPER_SEND, {'name': name}); |  | 
| 2591         } |  | 
| 2592       } |  | 
| 2593       if (!inInstanceContext) { |  | 
| 2594         error(node.receiver, MessageKind.NO_INSTANCE_AVAILABLE, {'name': name}); |  | 
| 2595         return null; |  | 
| 2596       } |  | 
| 2597       if (currentClass.supertype == null) { |  | 
| 2598         // This is just to guard against internal errors, so no need |  | 
| 2599         // for a real error message. |  | 
| 2600         error(node.receiver, MessageKind.GENERIC, |  | 
| 2601               {'text': "Object has no superclass"}); |  | 
| 2602       } |  | 
| 2603       // TODO(johnniwinther): Ensure correct behavior if currentClass is a |  | 
| 2604       // patch. |  | 
| 2605       target = currentClass.lookupSuperSelector(selector); |  | 
| 2606       // [target] may be null which means invoking noSuchMethod on |  | 
| 2607       // super. |  | 
| 2608       if (target == null) { |  | 
| 2609         target = warnAndCreateErroneousElement( |  | 
| 2610             node, name, MessageKind.NO_SUCH_SUPER_MEMBER, |  | 
| 2611             {'className': currentClass, 'memberName': name}); |  | 
| 2612         // We still need to register the invocation, because we might |  | 
| 2613         // call [:super.noSuchMethod:] which calls |  | 
| 2614         // [JSInvocationMirror._invokeOn]. |  | 
| 2615         registry.registerDynamicInvocation(selector); |  | 
| 2616         registry.registerSuperNoSuchMethod(); |  | 
| 2617       } |  | 
| 2618     } else if (resolvedReceiver == null || |  | 
| 2619                Elements.isUnresolved(resolvedReceiver.element)) { |  | 
| 2620       return null; |  | 
| 2621     } else if (resolvedReceiver.element.isClass) { |  | 
| 2622       ClassElement receiverClass = resolvedReceiver.element; |  | 
| 2623       receiverClass.ensureResolved(compiler); |  | 
| 2624       if (node.isOperator) { |  | 
| 2625         // When the resolved receiver is a class, we can have two cases: |  | 
| 2626         //  1) a static send: C.foo, or |  | 
| 2627         //  2) an operator send, where the receiver is a class literal: 'C + 1'. |  | 
| 2628         // The following code that looks up the selector on the resolved |  | 
| 2629         // receiver will treat the second as the invocation of a static operator |  | 
| 2630         // if the resolved receiver is not null. |  | 
| 2631         return null; |  | 
| 2632       } |  | 
| 2633       MembersCreator.computeClassMembersByName( |  | 
| 2634           compiler, receiverClass.declaration, name); |  | 
| 2635       target = receiverClass.lookupLocalMember(name); |  | 
| 2636       if (target == null || target.isInstanceMember) { |  | 
| 2637         registry.registerThrowNoSuchMethod(); |  | 
| 2638         // TODO(johnniwinther): With the simplified [TreeElements] invariant, |  | 
| 2639         // try to resolve injected elements if [currentClass] is in the patch |  | 
| 2640         // library of [receiverClass]. |  | 
| 2641 |  | 
| 2642         // TODO(karlklose): this should be reported by the caller of |  | 
| 2643         // [resolveSend] to select better warning messages for getters and |  | 
| 2644         // setters. |  | 
| 2645         MessageKind kind = (target == null) |  | 
| 2646             ? MessageKind.MEMBER_NOT_FOUND |  | 
| 2647             : MessageKind.MEMBER_NOT_STATIC; |  | 
| 2648         return new ElementResult(warnAndCreateErroneousElement( |  | 
| 2649             node, name, kind, |  | 
| 2650             {'className': receiverClass.name, 'memberName': name})); |  | 
| 2651       } else if (isPrivateName(name) && |  | 
| 2652                  target.library != enclosingElement.library) { |  | 
| 2653         registry.registerThrowNoSuchMethod(); |  | 
| 2654         return new ElementResult(warnAndCreateErroneousElement( |  | 
| 2655             node, name, MessageKind.PRIVATE_ACCESS, |  | 
| 2656             {'libraryName': target.library.getLibraryOrScriptName(), |  | 
| 2657              'name': name})); |  | 
| 2658       } |  | 
| 2659     } else if (resolvedReceiver.element.isPrefix) { |  | 
| 2660       PrefixElement prefix = resolvedReceiver.element; |  | 
| 2661       target = prefix.lookupLocalMember(name); |  | 
| 2662       if (Elements.isUnresolved(target)) { |  | 
| 2663         registry.registerThrowNoSuchMethod(); |  | 
| 2664         return new ElementResult(warnAndCreateErroneousElement( |  | 
| 2665             node, name, MessageKind.NO_SUCH_LIBRARY_MEMBER, |  | 
| 2666             {'libraryName': prefix.name, 'memberName': name})); |  | 
| 2667       } else if (target.isAmbiguous) { |  | 
| 2668         registry.registerThrowNoSuchMethod(); |  | 
| 2669         AmbiguousElement ambiguous = target; |  | 
| 2670         target = warnAndCreateErroneousElement(node, name, |  | 
| 2671                                                ambiguous.messageKind, |  | 
| 2672                                                ambiguous.messageArguments); |  | 
| 2673         ambiguous.diagnose(enclosingElement, compiler); |  | 
| 2674         return new ElementResult(target); |  | 
| 2675       } else if (target.kind == ElementKind.CLASS) { |  | 
| 2676         ClassElement classElement = target; |  | 
| 2677         classElement.ensureResolved(compiler); |  | 
| 2678       } |  | 
| 2679     } |  | 
| 2680     return new ElementResult(target); |  | 
| 2681   } |  | 
| 2682 |  | 
| 2683   static Selector computeSendSelector(Send node, |  | 
| 2684                                       LibraryElement library, |  | 
| 2685                                       Element element) { |  | 
| 2686     // First determine if this is part of an assignment. |  | 
| 2687     bool isSet = node.asSendSet() != null; |  | 
| 2688 |  | 
| 2689     if (node.isIndex) { |  | 
| 2690       return isSet ? new Selector.indexSet() : new Selector.index(); |  | 
| 2691     } |  | 
| 2692 |  | 
| 2693     if (node.isOperator) { |  | 
| 2694       String source = node.selector.asOperator().source; |  | 
| 2695       String string = source; |  | 
| 2696       if (identical(string, '!') || |  | 
| 2697           identical(string, '&&') || identical(string, '||') || |  | 
| 2698           identical(string, 'is') || identical(string, 'as') || |  | 
| 2699           identical(string, '?') || |  | 
| 2700           identical(string, '>>>')) { |  | 
| 2701         return null; |  | 
| 2702       } |  | 
| 2703       String op = source; |  | 
| 2704       if (!isUserDefinableOperator(source)) { |  | 
| 2705         op = Elements.mapToUserOperatorOrNull(source); |  | 
| 2706       } |  | 
| 2707       if (op == null) { |  | 
| 2708         // Unsupported operator. An error has been reported during parsing. |  | 
| 2709         return new Selector.call( |  | 
| 2710             source, library, node.argumentsNode.slowLength(), []); |  | 
| 2711       } |  | 
| 2712       return node.arguments.isEmpty |  | 
| 2713           ? new Selector.unaryOperator(op) |  | 
| 2714           : new Selector.binaryOperator(op); |  | 
| 2715     } |  | 
| 2716 |  | 
| 2717     Identifier identifier = node.selector.asIdentifier(); |  | 
| 2718     if (node.isPropertyAccess) { |  | 
| 2719       assert(!isSet); |  | 
| 2720       return new Selector.getter(identifier.source, library); |  | 
| 2721     } else if (isSet) { |  | 
| 2722       return new Selector.setter(identifier.source, library); |  | 
| 2723     } |  | 
| 2724 |  | 
| 2725     // Compute the arity and the list of named arguments. |  | 
| 2726     int arity = 0; |  | 
| 2727     List<String> named = <String>[]; |  | 
| 2728     for (Link<Node> link = node.argumentsNode.nodes; |  | 
| 2729         !link.isEmpty; |  | 
| 2730         link = link.tail) { |  | 
| 2731       Expression argument = link.head; |  | 
| 2732       NamedArgument namedArgument = argument.asNamedArgument(); |  | 
| 2733       if (namedArgument != null) { |  | 
| 2734         named.add(namedArgument.name.source); |  | 
| 2735       } |  | 
| 2736       arity++; |  | 
| 2737     } |  | 
| 2738 |  | 
| 2739     if (element != null && element.isConstructor) { |  | 
| 2740       return new Selector.callConstructor( |  | 
| 2741           element.name, library, arity, named); |  | 
| 2742     } |  | 
| 2743 |  | 
| 2744     // If we're invoking a closure, we do not have an identifier. |  | 
| 2745     return (identifier == null) |  | 
| 2746         ? new Selector.callClosure(arity, named) |  | 
| 2747         : new Selector.call(identifier.source, library, arity, named); |  | 
| 2748   } |  | 
| 2749 |  | 
| 2750   Selector resolveSelector(Send node, Element element) { |  | 
| 2751     LibraryElement library = enclosingElement.library; |  | 
| 2752     Selector selector = computeSendSelector(node, library, element); |  | 
| 2753     if (selector != null) registry.setSelector(node, selector); |  | 
| 2754     return selector; |  | 
| 2755   } |  | 
| 2756 |  | 
| 2757   void resolveArguments(NodeList list) { |  | 
| 2758     if (list == null) return; |  | 
| 2759     bool oldSendIsMemberAccess = sendIsMemberAccess; |  | 
| 2760     sendIsMemberAccess = false; |  | 
| 2761     Map<String, Node> seenNamedArguments = new Map<String, Node>(); |  | 
| 2762     for (Link<Node> link = list.nodes; !link.isEmpty; link = link.tail) { |  | 
| 2763       Expression argument = link.head; |  | 
| 2764       visit(argument); |  | 
| 2765       NamedArgument namedArgument = argument.asNamedArgument(); |  | 
| 2766       if (namedArgument != null) { |  | 
| 2767         String source = namedArgument.name.source; |  | 
| 2768         if (seenNamedArguments.containsKey(source)) { |  | 
| 2769           reportDuplicateDefinition( |  | 
| 2770               source, |  | 
| 2771               argument, |  | 
| 2772               seenNamedArguments[source]); |  | 
| 2773         } else { |  | 
| 2774           seenNamedArguments[source] = namedArgument; |  | 
| 2775         } |  | 
| 2776       } else if (!seenNamedArguments.isEmpty) { |  | 
| 2777         error(argument, MessageKind.INVALID_ARGUMENT_AFTER_NAMED); |  | 
| 2778       } |  | 
| 2779     } |  | 
| 2780     sendIsMemberAccess = oldSendIsMemberAccess; |  | 
| 2781   } |  | 
| 2782 |  | 
| 2783   ResolutionResult visitSend(Send node) { |  | 
| 2784     bool oldSendIsMemberAccess = sendIsMemberAccess; |  | 
| 2785     sendIsMemberAccess = node.isPropertyAccess || node.isCall; |  | 
| 2786     ResolutionResult result; |  | 
| 2787     if (node.isLogicalAnd) { |  | 
| 2788       result = doInPromotionScope(node.receiver, () => resolveSend(node)); |  | 
| 2789     } else { |  | 
| 2790       result = resolveSend(node); |  | 
| 2791     } |  | 
| 2792     sendIsMemberAccess = oldSendIsMemberAccess; |  | 
| 2793 |  | 
| 2794     Element target = result != null ? result.element : null; |  | 
| 2795 |  | 
| 2796     if (target != null |  | 
| 2797         && target == compiler.mirrorSystemGetNameFunction |  | 
| 2798         && !compiler.mirrorUsageAnalyzerTask.hasMirrorUsage(enclosingElement)) { |  | 
| 2799       compiler.reportHint( |  | 
| 2800           node.selector, MessageKind.STATIC_FUNCTION_BLOAT, |  | 
| 2801           {'class': compiler.mirrorSystemClass.name, |  | 
| 2802            'name': compiler.mirrorSystemGetNameFunction.name}); |  | 
| 2803     } |  | 
| 2804 |  | 
| 2805     if (!Elements.isUnresolved(target)) { |  | 
| 2806       if (target.isAbstractField) { |  | 
| 2807         AbstractFieldElement field = target; |  | 
| 2808         target = field.getter; |  | 
| 2809         if (target == null && !inInstanceContext) { |  | 
| 2810           registry.registerThrowNoSuchMethod(); |  | 
| 2811           target = |  | 
| 2812               warnAndCreateErroneousElement(node.selector, field.name, |  | 
| 2813                                             MessageKind.CANNOT_RESOLVE_GETTER); |  | 
| 2814         } |  | 
| 2815       } else if (target.isTypeVariable) { |  | 
| 2816         ClassElement cls = target.enclosingClass; |  | 
| 2817         assert(enclosingElement.enclosingClass == cls); |  | 
| 2818         registry.registerClassUsingVariableExpression(cls); |  | 
| 2819         registry.registerTypeVariableExpression(); |  | 
| 2820         // Set the type of the node to [Type] to mark this send as a |  | 
| 2821         // type variable expression. |  | 
| 2822         registry.registerTypeLiteral(node, target.computeType(compiler)); |  | 
| 2823       } else if (target.impliesType && (!sendIsMemberAccess || node.isCall)) { |  | 
| 2824         // Set the type of the node to [Type] to mark this send as a |  | 
| 2825         // type literal. |  | 
| 2826         DartType type; |  | 
| 2827 |  | 
| 2828         // TODO(johnniwinther): Remove this hack when we can pass more complex |  | 
| 2829         // information between methods than resolved elements. |  | 
| 2830         if (target == compiler.typeClass && node.receiver == null) { |  | 
| 2831           // Potentially a 'dynamic' type literal. |  | 
| 2832           type = registry.getType(node.selector); |  | 
| 2833         } |  | 
| 2834         if (type == null) { |  | 
| 2835           type = target.computeType(compiler); |  | 
| 2836         } |  | 
| 2837         registry.registerTypeLiteral(node, type); |  | 
| 2838 |  | 
| 2839         // Don't try to make constants of calls to type literals. |  | 
| 2840         if (!node.isCall) { |  | 
| 2841           analyzeConstant(node); |  | 
| 2842         } else { |  | 
| 2843           // The node itself is not a constant but we register the selector (the |  | 
| 2844           // identifier that refers to the class/typedef) as a constant. |  | 
| 2845           analyzeConstant(node.selector); |  | 
| 2846         } |  | 
| 2847       } |  | 
| 2848       if (isPotentiallyMutableTarget(target)) { |  | 
| 2849         if (enclosingElement != target.enclosingElement) { |  | 
| 2850           for (Node scope in promotionScope) { |  | 
| 2851             registry.setAccessedByClosureIn(scope, target, node); |  | 
| 2852           } |  | 
| 2853         } |  | 
| 2854       } |  | 
| 2855     } |  | 
| 2856 |  | 
| 2857     bool resolvedArguments = false; |  | 
| 2858     if (node.isOperator) { |  | 
| 2859       String operatorString = node.selector.asOperator().source; |  | 
| 2860       if (identical(operatorString, 'is')) { |  | 
| 2861         // TODO(johnniwinther): Use seen type tests to avoid registration of |  | 
| 2862         // mutation/access to unpromoted variables. |  | 
| 2863         DartType type = |  | 
| 2864             resolveTypeAnnotation(node.typeAnnotationFromIsCheckOrCast); |  | 
| 2865         if (type != null) { |  | 
| 2866           registry.registerIsCheck(type); |  | 
| 2867         } |  | 
| 2868         resolvedArguments = true; |  | 
| 2869       } else if (identical(operatorString, 'as')) { |  | 
| 2870         DartType type = resolveTypeAnnotation(node.arguments.head); |  | 
| 2871         if (type != null) { |  | 
| 2872           registry.registerAsCheck(type); |  | 
| 2873         } |  | 
| 2874         resolvedArguments = true; |  | 
| 2875       } else if (identical(operatorString, '&&')) { |  | 
| 2876         doInPromotionScope(node.arguments.head, |  | 
| 2877             () => resolveArguments(node.argumentsNode)); |  | 
| 2878         resolvedArguments = true; |  | 
| 2879       } |  | 
| 2880     } |  | 
| 2881 |  | 
| 2882     if (!resolvedArguments) { |  | 
| 2883       resolveArguments(node.argumentsNode); |  | 
| 2884     } |  | 
| 2885 |  | 
| 2886     // If the selector is null, it means that we will not be generating |  | 
| 2887     // code for this as a send. |  | 
| 2888     Selector selector = registry.getSelector(node); |  | 
| 2889     if (selector == null) return null; |  | 
| 2890 |  | 
| 2891     if (node.isCall) { |  | 
| 2892       if (Elements.isUnresolved(target) || |  | 
| 2893           target.isGetter || |  | 
| 2894           target.isField || |  | 
| 2895           Elements.isClosureSend(node, target)) { |  | 
| 2896         // If we don't know what we're calling or if we are calling a getter, |  | 
| 2897         // we need to register that fact that we may be calling a closure |  | 
| 2898         // with the same arguments. |  | 
| 2899         Selector call = new Selector.callClosureFrom(selector); |  | 
| 2900         registry.registerDynamicInvocation(call); |  | 
| 2901       } else if (target.impliesType) { |  | 
| 2902         // We call 'call()' on a Type instance returned from the reference to a |  | 
| 2903         // class or typedef literal. We do not need to register this call as a |  | 
| 2904         // dynamic invocation, because we statically know what the target is. |  | 
| 2905       } else { |  | 
| 2906         if (target is FunctionElement) { |  | 
| 2907           FunctionElement function = target; |  | 
| 2908           function.computeSignature(compiler); |  | 
| 2909         } |  | 
| 2910         if (!selector.applies(target, compiler.world)) { |  | 
| 2911           registry.registerThrowNoSuchMethod(); |  | 
| 2912           if (node.isSuperCall) { |  | 
| 2913             // Similar to what we do when we can't find super via selector |  | 
| 2914             // in [resolveSend] above, we still need to register the invocation, |  | 
| 2915             // because we might call [:super.noSuchMethod:] which calls |  | 
| 2916             // [JSInvocationMirror._invokeOn]. |  | 
| 2917             registry.registerDynamicInvocation(selector); |  | 
| 2918             registry.registerSuperNoSuchMethod(); |  | 
| 2919           } |  | 
| 2920         } |  | 
| 2921       } |  | 
| 2922 |  | 
| 2923       if (target != null && target.isForeign(compiler.backend)) { |  | 
| 2924         if (selector.name == 'JS') { |  | 
| 2925           registry.registerJsCall(node, this); |  | 
| 2926         } else if (selector.name == 'JS_EMBEDDED_GLOBAL') { |  | 
| 2927           registry.registerJsEmbeddedGlobalCall(node, this); |  | 
| 2928         } else if (selector.name == 'JS_INTERCEPTOR_CONSTANT') { |  | 
| 2929           if (!node.argumentsNode.isEmpty) { |  | 
| 2930             Node argument = node.argumentsNode.nodes.head; |  | 
| 2931             if (argumentsToJsInterceptorConstant == null) { |  | 
| 2932               argumentsToJsInterceptorConstant = new Set<Node>(); |  | 
| 2933             } |  | 
| 2934             argumentsToJsInterceptorConstant.add(argument); |  | 
| 2935           } |  | 
| 2936         } |  | 
| 2937       } |  | 
| 2938     } |  | 
| 2939 |  | 
| 2940     registry.useElement(node, target); |  | 
| 2941     registerSend(selector, target); |  | 
| 2942     if (node.isPropertyAccess && Elements.isStaticOrTopLevelFunction(target)) { |  | 
| 2943       registry.registerGetOfStaticFunction(target.declaration); |  | 
| 2944     } |  | 
| 2945     return node.isPropertyAccess ? new ElementResult(target) : null; |  | 
| 2946   } |  | 
| 2947 |  | 
| 2948   /// Callback for native enqueuer to parse a type.  Returns [:null:] on error. |  | 
| 2949   DartType resolveTypeFromString(Node node, String typeName) { |  | 
| 2950     Element element = lookupInScope(compiler, node, |  | 
| 2951                                     scope, typeName); |  | 
| 2952     if (element == null) return null; |  | 
| 2953     if (element is! ClassElement) return null; |  | 
| 2954     ClassElement cls = element; |  | 
| 2955     cls.ensureResolved(compiler); |  | 
| 2956     return cls.computeType(compiler); |  | 
| 2957   } |  | 
| 2958 |  | 
| 2959   ResolutionResult visitSendSet(SendSet node) { |  | 
| 2960     bool oldSendIsMemberAccess = sendIsMemberAccess; |  | 
| 2961     sendIsMemberAccess = node.isPropertyAccess || node.isCall; |  | 
| 2962     ResolutionResult result = resolveSend(node); |  | 
| 2963     sendIsMemberAccess = oldSendIsMemberAccess; |  | 
| 2964     Element target = result != null ? result.element : null; |  | 
| 2965     Element setter = target; |  | 
| 2966     Element getter = target; |  | 
| 2967     String operatorName = node.assignmentOperator.source; |  | 
| 2968     String source = operatorName; |  | 
| 2969     bool isComplex = !identical(source, '='); |  | 
| 2970     if (!(result is AssertResult || Elements.isUnresolved(target))) { |  | 
| 2971       if (target.isAbstractField) { |  | 
| 2972         AbstractFieldElement field = target; |  | 
| 2973         setter = field.setter; |  | 
| 2974         getter = field.getter; |  | 
| 2975         if (setter == null && !inInstanceContext) { |  | 
| 2976           setter = warnAndCreateErroneousElement( |  | 
| 2977               node.selector, field.name, MessageKind.CANNOT_RESOLVE_SETTER); |  | 
| 2978           registry.registerThrowNoSuchMethod(); |  | 
| 2979         } |  | 
| 2980         if (isComplex && getter == null && !inInstanceContext) { |  | 
| 2981           getter = warnAndCreateErroneousElement( |  | 
| 2982               node.selector, field.name, MessageKind.CANNOT_RESOLVE_GETTER); |  | 
| 2983           registry.registerThrowNoSuchMethod(); |  | 
| 2984         } |  | 
| 2985       } else if (target.impliesType) { |  | 
| 2986         setter = warnAndCreateErroneousElement( |  | 
| 2987             node.selector, target.name, MessageKind.ASSIGNING_TYPE); |  | 
| 2988         registry.registerThrowNoSuchMethod(); |  | 
| 2989       } else if (target.isFinal || |  | 
| 2990                  target.isConst || |  | 
| 2991                  (target.isFunction && |  | 
| 2992                   Elements.isStaticOrTopLevelFunction(target) && |  | 
| 2993                   !target.isSetter)) { |  | 
| 2994         if (target.isFunction) { |  | 
| 2995           setter = warnAndCreateErroneousElement( |  | 
| 2996               node.selector, target.name, MessageKind.ASSIGNING_METHOD); |  | 
| 2997         } else { |  | 
| 2998           setter = warnAndCreateErroneousElement( |  | 
| 2999               node.selector, target.name, MessageKind.CANNOT_RESOLVE_SETTER); |  | 
| 3000         } |  | 
| 3001         registry.registerThrowNoSuchMethod(); |  | 
| 3002       } |  | 
| 3003       if (isPotentiallyMutableTarget(target)) { |  | 
| 3004         registry.registerPotentialMutation(target, node); |  | 
| 3005         if (enclosingElement != target.enclosingElement) { |  | 
| 3006           registry.registerPotentialMutationInClosure(target, node); |  | 
| 3007         } |  | 
| 3008         for (Node scope in promotionScope) { |  | 
| 3009           registry.registerPotentialMutationIn(scope, target, node); |  | 
| 3010         } |  | 
| 3011       } |  | 
| 3012     } |  | 
| 3013 |  | 
| 3014     resolveArguments(node.argumentsNode); |  | 
| 3015 |  | 
| 3016     Selector selector = registry.getSelector(node); |  | 
| 3017     if (isComplex) { |  | 
| 3018       Selector getterSelector; |  | 
| 3019       if (selector.isSetter) { |  | 
| 3020         getterSelector = new Selector.getterFrom(selector); |  | 
| 3021       } else { |  | 
| 3022         assert(selector.isIndexSet); |  | 
| 3023         getterSelector = new Selector.index(); |  | 
| 3024       } |  | 
| 3025       registerSend(getterSelector, getter); |  | 
| 3026       registry.setGetterSelectorInComplexSendSet(node, getterSelector); |  | 
| 3027       if (node.isSuperCall) { |  | 
| 3028         getter = currentClass.lookupSuperSelector(getterSelector); |  | 
| 3029         if (getter == null) { |  | 
| 3030           target = warnAndCreateErroneousElement( |  | 
| 3031               node, selector.name, MessageKind.NO_SUCH_SUPER_MEMBER, |  | 
| 3032               {'className': currentClass, 'memberName': selector.name}); |  | 
| 3033           registry.registerSuperNoSuchMethod(); |  | 
| 3034         } |  | 
| 3035       } |  | 
| 3036       registry.useElement(node.selector, getter); |  | 
| 3037 |  | 
| 3038       // Make sure we include the + and - operators if we are using |  | 
| 3039       // the ++ and -- ones.  Also, if op= form is used, include op itself. |  | 
| 3040       void registerBinaryOperator(String name) { |  | 
| 3041         Selector binop = new Selector.binaryOperator(name); |  | 
| 3042         registry.registerDynamicInvocation(binop); |  | 
| 3043         registry.setOperatorSelectorInComplexSendSet(node, binop); |  | 
| 3044       } |  | 
| 3045       if (identical(source, '++')) { |  | 
| 3046         registerBinaryOperator('+'); |  | 
| 3047         registry.registerInstantiatedClass(compiler.intClass); |  | 
| 3048       } else if (identical(source, '--')) { |  | 
| 3049         registerBinaryOperator('-'); |  | 
| 3050         registry.registerInstantiatedClass(compiler.intClass); |  | 
| 3051       } else if (source.endsWith('=')) { |  | 
| 3052         registerBinaryOperator(Elements.mapToUserOperator(operatorName)); |  | 
| 3053       } |  | 
| 3054     } |  | 
| 3055 |  | 
| 3056     registerSend(selector, setter); |  | 
| 3057     return new ElementResult(registry.useElement(node, setter)); |  | 
| 3058   } |  | 
| 3059 |  | 
| 3060   void registerSend(Selector selector, Element target) { |  | 
| 3061     if (target == null || target.isInstanceMember) { |  | 
| 3062       if (selector.isGetter) { |  | 
| 3063         registry.registerDynamicGetter(selector); |  | 
| 3064       } else if (selector.isSetter) { |  | 
| 3065         registry.registerDynamicSetter(selector); |  | 
| 3066       } else { |  | 
| 3067         registry.registerDynamicInvocation(selector); |  | 
| 3068       } |  | 
| 3069     } else if (Elements.isStaticOrTopLevel(target)) { |  | 
| 3070       // Avoid registration of type variables since they are not analyzable but |  | 
| 3071       // instead resolved through their enclosing type declaration. |  | 
| 3072       if (!target.isTypeVariable) { |  | 
| 3073         // [target] might be the implementation element and only declaration |  | 
| 3074         // elements may be registered. |  | 
| 3075         registry.registerStaticUse(target.declaration); |  | 
| 3076       } |  | 
| 3077     } |  | 
| 3078   } |  | 
| 3079 |  | 
| 3080   visitLiteralInt(LiteralInt node) { |  | 
| 3081     registry.registerInstantiatedClass(compiler.intClass); |  | 
| 3082   } |  | 
| 3083 |  | 
| 3084   visitLiteralDouble(LiteralDouble node) { |  | 
| 3085     registry.registerInstantiatedClass(compiler.doubleClass); |  | 
| 3086   } |  | 
| 3087 |  | 
| 3088   visitLiteralBool(LiteralBool node) { |  | 
| 3089     registry.registerInstantiatedClass(compiler.boolClass); |  | 
| 3090   } |  | 
| 3091 |  | 
| 3092   visitLiteralString(LiteralString node) { |  | 
| 3093     registry.registerInstantiatedClass(compiler.stringClass); |  | 
| 3094   } |  | 
| 3095 |  | 
| 3096   visitLiteralNull(LiteralNull node) { |  | 
| 3097     registry.registerInstantiatedClass(compiler.nullClass); |  | 
| 3098   } |  | 
| 3099 |  | 
| 3100   visitLiteralSymbol(LiteralSymbol node) { |  | 
| 3101     registry.registerInstantiatedClass(compiler.symbolClass); |  | 
| 3102     registry.registerStaticUse(compiler.symbolConstructor.declaration); |  | 
| 3103     registry.registerConstSymbol(node.slowNameString); |  | 
| 3104     if (!validateSymbol(node, node.slowNameString, reportError: false)) { |  | 
| 3105       compiler.reportError(node, |  | 
| 3106           MessageKind.UNSUPPORTED_LITERAL_SYMBOL, |  | 
| 3107           {'value': node.slowNameString}); |  | 
| 3108     } |  | 
| 3109     analyzeConstant(node); |  | 
| 3110   } |  | 
| 3111 |  | 
| 3112   visitStringJuxtaposition(StringJuxtaposition node) { |  | 
| 3113     registry.registerInstantiatedClass(compiler.stringClass); |  | 
| 3114     node.visitChildren(this); |  | 
| 3115   } |  | 
| 3116 |  | 
| 3117   visitNodeList(NodeList node) { |  | 
| 3118     for (Link<Node> link = node.nodes; !link.isEmpty; link = link.tail) { |  | 
| 3119       visit(link.head); |  | 
| 3120     } |  | 
| 3121   } |  | 
| 3122 |  | 
| 3123   visitOperator(Operator node) { |  | 
| 3124     internalError(node, 'operator'); |  | 
| 3125   } |  | 
| 3126 |  | 
| 3127   visitRethrow(Rethrow node) { |  | 
| 3128     if (!inCatchBlock) { |  | 
| 3129       error(node, MessageKind.THROW_WITHOUT_EXPRESSION); |  | 
| 3130     } |  | 
| 3131   } |  | 
| 3132 |  | 
| 3133   visitReturn(Return node) { |  | 
| 3134     Node expression = node.expression; |  | 
| 3135     if (expression != null && |  | 
| 3136         enclosingElement.isGenerativeConstructor) { |  | 
| 3137       // It is a compile-time error if a return statement of the form |  | 
| 3138       // `return e;` appears in a generative constructor.  (Dart Language |  | 
| 3139       // Specification 13.12.) |  | 
| 3140       compiler.reportError(expression, |  | 
| 3141                            MessageKind.CANNOT_RETURN_FROM_CONSTRUCTOR); |  | 
| 3142     } |  | 
| 3143     visit(node.expression); |  | 
| 3144   } |  | 
| 3145 |  | 
| 3146   visitRedirectingFactoryBody(RedirectingFactoryBody node) { |  | 
| 3147     final isSymbolConstructor = enclosingElement == compiler.symbolConstructor; |  | 
| 3148     if (!enclosingElement.isFactoryConstructor) { |  | 
| 3149       compiler.reportError( |  | 
| 3150           node, MessageKind.FACTORY_REDIRECTION_IN_NON_FACTORY); |  | 
| 3151       compiler.reportHint( |  | 
| 3152           enclosingElement, MessageKind.MISSING_FACTORY_KEYWORD); |  | 
| 3153     } |  | 
| 3154     ConstructorElementX constructor = enclosingElement; |  | 
| 3155     bool isConstConstructor = constructor.isConst; |  | 
| 3156     ConstructorElement redirectionTarget = resolveRedirectingFactory( |  | 
| 3157         node, inConstContext: isConstConstructor); |  | 
| 3158     constructor.immediateRedirectionTarget = redirectionTarget; |  | 
| 3159     registry.setRedirectingTargetConstructor(node, redirectionTarget); |  | 
| 3160     if (Elements.isUnresolved(redirectionTarget)) { |  | 
| 3161       registry.registerThrowNoSuchMethod(); |  | 
| 3162       return; |  | 
| 3163     } else { |  | 
| 3164       if (isConstConstructor && |  | 
| 3165           !redirectionTarget.isConst) { |  | 
| 3166         compiler.reportError(node, MessageKind.CONSTRUCTOR_IS_NOT_CONST); |  | 
| 3167       } |  | 
| 3168       if (redirectionTarget == constructor) { |  | 
| 3169         compiler.reportError(node, MessageKind.CYCLIC_REDIRECTING_FACTORY); |  | 
| 3170         return; |  | 
| 3171       } |  | 
| 3172     } |  | 
| 3173 |  | 
| 3174     // Check that the target constructor is type compatible with the |  | 
| 3175     // redirecting constructor. |  | 
| 3176     ClassElement targetClass = redirectionTarget.enclosingClass; |  | 
| 3177     InterfaceType type = registry.getType(node); |  | 
| 3178     FunctionType targetType = redirectionTarget.computeType(compiler) |  | 
| 3179         .subst(type.typeArguments, targetClass.typeVariables); |  | 
| 3180     FunctionType constructorType = constructor.computeType(compiler); |  | 
| 3181     bool isSubtype = compiler.types.isSubtype(targetType, constructorType); |  | 
| 3182     if (!isSubtype) { |  | 
| 3183       warning(node, MessageKind.NOT_ASSIGNABLE, |  | 
| 3184               {'fromType': targetType, 'toType': constructorType}); |  | 
| 3185     } |  | 
| 3186 |  | 
| 3187     FunctionSignature targetSignature = |  | 
| 3188         redirectionTarget.computeSignature(compiler); |  | 
| 3189     FunctionSignature constructorSignature = |  | 
| 3190         constructor.computeSignature(compiler); |  | 
| 3191     if (!targetSignature.isCompatibleWith(constructorSignature)) { |  | 
| 3192       assert(!isSubtype); |  | 
| 3193       registry.registerThrowNoSuchMethod(); |  | 
| 3194     } |  | 
| 3195 |  | 
| 3196     // Register a post process to check for cycles in the redirection chain and |  | 
| 3197     // set the actual generative constructor at the end of the chain. |  | 
| 3198     addDeferredAction(constructor, () { |  | 
| 3199       compiler.resolver.resolveRedirectionChain(constructor, node); |  | 
| 3200     }); |  | 
| 3201 |  | 
| 3202     registry.registerStaticUse(redirectionTarget); |  | 
| 3203     // TODO(johnniwinther): Register the effective target type instead. |  | 
| 3204     registry.registerInstantiatedClass( |  | 
| 3205         redirectionTarget.enclosingClass.declaration); |  | 
| 3206     if (isSymbolConstructor) { |  | 
| 3207       registry.registerSymbolConstructor(); |  | 
| 3208     } |  | 
| 3209   } |  | 
| 3210 |  | 
| 3211   visitThrow(Throw node) { |  | 
| 3212     registry.registerThrowExpression(); |  | 
| 3213     visit(node.expression); |  | 
| 3214   } |  | 
| 3215 |  | 
| 3216   visitVariableDefinitions(VariableDefinitions node) { |  | 
| 3217     DartType type; |  | 
| 3218     if (node.type != null) { |  | 
| 3219       type = resolveTypeAnnotation(node.type); |  | 
| 3220     } else { |  | 
| 3221       type = const DynamicType(); |  | 
| 3222     } |  | 
| 3223     VariableList variables = new VariableList.node(node, type); |  | 
| 3224     VariableDefinitionsVisitor visitor = |  | 
| 3225         new VariableDefinitionsVisitor(compiler, node, this, variables); |  | 
| 3226 |  | 
| 3227     Modifiers modifiers = node.modifiers; |  | 
| 3228     void reportExtraModifier(String modifier) { |  | 
| 3229       Node modifierNode; |  | 
| 3230       for (Link<Node> nodes = modifiers.nodes.nodes; |  | 
| 3231            !nodes.isEmpty; |  | 
| 3232            nodes = nodes.tail) { |  | 
| 3233         if (modifier == nodes.head.asIdentifier().source) { |  | 
| 3234           modifierNode = nodes.head; |  | 
| 3235           break; |  | 
| 3236         } |  | 
| 3237       } |  | 
| 3238       assert(modifierNode != null); |  | 
| 3239       compiler.reportError(modifierNode, MessageKind.EXTRANEOUS_MODIFIER, |  | 
| 3240           {'modifier': modifier}); |  | 
| 3241     } |  | 
| 3242     if (modifiers.isFinal && (modifiers.isConst || modifiers.isVar)) { |  | 
| 3243       reportExtraModifier('final'); |  | 
| 3244     } |  | 
| 3245     if (modifiers.isVar && (modifiers.isConst || node.type != null)) { |  | 
| 3246       reportExtraModifier('var'); |  | 
| 3247     } |  | 
| 3248     if (enclosingElement.isFunction) { |  | 
| 3249       if (modifiers.isAbstract) { |  | 
| 3250         reportExtraModifier('abstract'); |  | 
| 3251       } |  | 
| 3252       if (modifiers.isStatic) { |  | 
| 3253         reportExtraModifier('static'); |  | 
| 3254       } |  | 
| 3255     } |  | 
| 3256     if (node.metadata != null) { |  | 
| 3257       variables.metadata = |  | 
| 3258           compiler.resolver.resolveMetadata(enclosingElement, node); |  | 
| 3259     } |  | 
| 3260     visitor.visit(node.definitions); |  | 
| 3261   } |  | 
| 3262 |  | 
| 3263   visitWhile(While node) { |  | 
| 3264     visit(node.condition); |  | 
| 3265     visitLoopBodyIn(node, node.body, new BlockScope(scope)); |  | 
| 3266   } |  | 
| 3267 |  | 
| 3268   visitParenthesizedExpression(ParenthesizedExpression node) { |  | 
| 3269     bool oldSendIsMemberAccess = sendIsMemberAccess; |  | 
| 3270     sendIsMemberAccess = false; |  | 
| 3271     visit(node.expression); |  | 
| 3272     sendIsMemberAccess = oldSendIsMemberAccess; |  | 
| 3273   } |  | 
| 3274 |  | 
| 3275   ResolutionResult visitNewExpression(NewExpression node) { |  | 
| 3276     Node selector = node.send.selector; |  | 
| 3277     FunctionElement constructor = resolveConstructor(node); |  | 
| 3278     final bool isSymbolConstructor = constructor == compiler.symbolConstructor; |  | 
| 3279     final bool isMirrorsUsedConstant = |  | 
| 3280         node.isConst && (constructor == compiler.mirrorsUsedConstructor); |  | 
| 3281     Selector callSelector = resolveSelector(node.send, constructor); |  | 
| 3282     resolveArguments(node.send.argumentsNode); |  | 
| 3283     registry.useElement(node.send, constructor); |  | 
| 3284     if (Elements.isUnresolved(constructor)) { |  | 
| 3285       return new ElementResult(constructor); |  | 
| 3286     } |  | 
| 3287     constructor.computeSignature(compiler); |  | 
| 3288     if (!callSelector.applies(constructor, compiler.world)) { |  | 
| 3289       registry.registerThrowNoSuchMethod(); |  | 
| 3290     } |  | 
| 3291 |  | 
| 3292     // [constructor] might be the implementation element |  | 
| 3293     // and only declaration elements may be registered. |  | 
| 3294     registry.registerStaticUse(constructor.declaration); |  | 
| 3295     ClassElement cls = constructor.enclosingClass; |  | 
| 3296     InterfaceType type = registry.getType(node); |  | 
| 3297     if (node.isConst && type.containsTypeVariables) { |  | 
| 3298       compiler.reportError(node.send.selector, |  | 
| 3299                            MessageKind.TYPE_VARIABLE_IN_CONSTANT); |  | 
| 3300     } |  | 
| 3301     // TODO(johniwinther): Avoid registration of `type` in face of redirecting |  | 
| 3302     // factory constructors. |  | 
| 3303     registry.registerInstantiatedType(type); |  | 
| 3304     if (constructor.isFactoryConstructor && !type.typeArguments.isEmpty) { |  | 
| 3305       registry.registerFactoryWithTypeArguments(); |  | 
| 3306     } |  | 
| 3307     if (constructor.isGenerativeConstructor && cls.isAbstract) { |  | 
| 3308       warning(node, MessageKind.ABSTRACT_CLASS_INSTANTIATION); |  | 
| 3309       registry.registerAbstractClassInstantiation(); |  | 
| 3310     } |  | 
| 3311 |  | 
| 3312     if (isSymbolConstructor) { |  | 
| 3313       if (node.isConst) { |  | 
| 3314         Node argumentNode = node.send.arguments.head; |  | 
| 3315         ConstantExpression constant = |  | 
| 3316             compiler.resolver.constantCompiler.compileNode( |  | 
| 3317                 argumentNode, registry.mapping); |  | 
| 3318         ConstantValue name = constant.value; |  | 
| 3319         if (!name.isString) { |  | 
| 3320           DartType type = name.computeType(compiler); |  | 
| 3321           compiler.reportError(argumentNode, MessageKind.STRING_EXPECTED, |  | 
| 3322                                    {'type': type}); |  | 
| 3323         } else { |  | 
| 3324           StringConstantValue stringConstant = name; |  | 
| 3325           String nameString = stringConstant.toDartString().slowToString(); |  | 
| 3326           if (validateSymbol(argumentNode, nameString)) { |  | 
| 3327             registry.registerConstSymbol(nameString); |  | 
| 3328           } |  | 
| 3329         } |  | 
| 3330       } else { |  | 
| 3331         if (!compiler.mirrorUsageAnalyzerTask.hasMirrorUsage( |  | 
| 3332                 enclosingElement)) { |  | 
| 3333           compiler.reportHint( |  | 
| 3334               node.newToken, MessageKind.NON_CONST_BLOAT, |  | 
| 3335               {'name': compiler.symbolClass.name}); |  | 
| 3336         } |  | 
| 3337         registry.registerNewSymbol(); |  | 
| 3338       } |  | 
| 3339     } else if (isMirrorsUsedConstant) { |  | 
| 3340       compiler.mirrorUsageAnalyzerTask.validate(node, registry.mapping); |  | 
| 3341     } |  | 
| 3342     if (node.isConst) { |  | 
| 3343       analyzeConstant(node); |  | 
| 3344     } |  | 
| 3345 |  | 
| 3346     return null; |  | 
| 3347   } |  | 
| 3348 |  | 
| 3349   void checkConstMapKeysDontOverrideEquals(Spannable spannable, |  | 
| 3350                                            MapConstantValue map) { |  | 
| 3351     for (ConstantValue key in map.keys) { |  | 
| 3352       if (!key.isObject) continue; |  | 
| 3353       ObjectConstantValue objectConstant = key; |  | 
| 3354       DartType keyType = objectConstant.type; |  | 
| 3355       ClassElement cls = keyType.element; |  | 
| 3356       if (cls == compiler.stringClass) continue; |  | 
| 3357       Element equals = cls.lookupMember('=='); |  | 
| 3358       if (equals.enclosingClass != compiler.objectClass) { |  | 
| 3359         compiler.reportError(spannable, |  | 
| 3360                              MessageKind.CONST_MAP_KEY_OVERRIDES_EQUALS, |  | 
| 3361                              {'type': keyType}); |  | 
| 3362       } |  | 
| 3363     } |  | 
| 3364   } |  | 
| 3365 |  | 
| 3366   void analyzeConstant(Node node) { |  | 
| 3367     addDeferredAction(enclosingElement, () { |  | 
| 3368       ConstantExpression constant = |  | 
| 3369           compiler.resolver.constantCompiler.compileNode( |  | 
| 3370               node, registry.mapping); |  | 
| 3371 |  | 
| 3372       ConstantValue value = constant.value; |  | 
| 3373       if (value.isMap) { |  | 
| 3374         checkConstMapKeysDontOverrideEquals(node, value); |  | 
| 3375       } |  | 
| 3376 |  | 
| 3377       // The type constant that is an argument to JS_INTERCEPTOR_CONSTANT names |  | 
| 3378       // a class that will be instantiated outside the program by attaching a |  | 
| 3379       // native class dispatch record referencing the interceptor. |  | 
| 3380       if (argumentsToJsInterceptorConstant != null && |  | 
| 3381           argumentsToJsInterceptorConstant.contains(node)) { |  | 
| 3382         if (value.isType) { |  | 
| 3383           TypeConstantValue typeConstant = value; |  | 
| 3384           if (typeConstant.representedType is InterfaceType) { |  | 
| 3385             registry.registerInstantiatedType(typeConstant.representedType); |  | 
| 3386           } else { |  | 
| 3387             compiler.reportError(node, |  | 
| 3388                 MessageKind.WRONG_ARGUMENT_FOR_JS_INTERCEPTOR_CONSTANT); |  | 
| 3389           } |  | 
| 3390         } else { |  | 
| 3391           compiler.reportError(node, |  | 
| 3392               MessageKind.WRONG_ARGUMENT_FOR_JS_INTERCEPTOR_CONSTANT); |  | 
| 3393         } |  | 
| 3394       } |  | 
| 3395     }); |  | 
| 3396   } |  | 
| 3397 |  | 
| 3398   bool validateSymbol(Node node, String name, {bool reportError: true}) { |  | 
| 3399     if (name.isEmpty) return true; |  | 
| 3400     if (name.startsWith('_')) { |  | 
| 3401       if (reportError) { |  | 
| 3402         compiler.reportError(node, MessageKind.PRIVATE_IDENTIFIER, |  | 
| 3403                              {'value': name}); |  | 
| 3404       } |  | 
| 3405       return false; |  | 
| 3406     } |  | 
| 3407     if (!symbolValidationPattern.hasMatch(name)) { |  | 
| 3408       if (reportError) { |  | 
| 3409         compiler.reportError(node, MessageKind.INVALID_SYMBOL, |  | 
| 3410                              {'value': name}); |  | 
| 3411       } |  | 
| 3412       return false; |  | 
| 3413     } |  | 
| 3414     return true; |  | 
| 3415   } |  | 
| 3416 |  | 
| 3417   /** |  | 
| 3418    * Try to resolve the constructor that is referred to by [node]. |  | 
| 3419    * Note: this function may return an ErroneousFunctionElement instead of |  | 
| 3420    * [:null:], if there is no corresponding constructor, class or library. |  | 
| 3421    */ |  | 
| 3422   ConstructorElement resolveConstructor(NewExpression node) { |  | 
| 3423     return node.accept(new ConstructorResolver(compiler, this)); |  | 
| 3424   } |  | 
| 3425 |  | 
| 3426   ConstructorElement resolveRedirectingFactory(RedirectingFactoryBody node, |  | 
| 3427                                                {bool inConstContext: false}) { |  | 
| 3428     return node.accept(new ConstructorResolver(compiler, this, |  | 
| 3429                                                inConstContext: inConstContext)); |  | 
| 3430   } |  | 
| 3431 |  | 
| 3432   DartType resolveTypeAnnotation(TypeAnnotation node, |  | 
| 3433                                  {bool malformedIsError: false, |  | 
| 3434                                   bool deferredIsMalformed: true}) { |  | 
| 3435     DartType type = typeResolver.resolveTypeAnnotation( |  | 
| 3436         this, node, malformedIsError: malformedIsError, |  | 
| 3437         deferredIsMalformed: deferredIsMalformed); |  | 
| 3438     if (inCheckContext) { |  | 
| 3439       registry.registerIsCheck(type); |  | 
| 3440       registry.registerRequiredType(type, enclosingElement); |  | 
| 3441     } |  | 
| 3442     return type; |  | 
| 3443   } |  | 
| 3444 |  | 
| 3445   visitModifiers(Modifiers node) { |  | 
| 3446     internalError(node, 'modifiers'); |  | 
| 3447   } |  | 
| 3448 |  | 
| 3449   visitLiteralList(LiteralList node) { |  | 
| 3450     bool oldSendIsMemberAccess = sendIsMemberAccess; |  | 
| 3451     sendIsMemberAccess = false; |  | 
| 3452 |  | 
| 3453     NodeList arguments = node.typeArguments; |  | 
| 3454     DartType typeArgument; |  | 
| 3455     if (arguments != null) { |  | 
| 3456       Link<Node> nodes = arguments.nodes; |  | 
| 3457       if (nodes.isEmpty) { |  | 
| 3458         // The syntax [: <>[] :] is not allowed. |  | 
| 3459         error(arguments, MessageKind.MISSING_TYPE_ARGUMENT); |  | 
| 3460       } else { |  | 
| 3461         typeArgument = resolveTypeAnnotation(nodes.head); |  | 
| 3462         for (nodes = nodes.tail; !nodes.isEmpty; nodes = nodes.tail) { |  | 
| 3463           warning(nodes.head, MessageKind.ADDITIONAL_TYPE_ARGUMENT); |  | 
| 3464           resolveTypeAnnotation(nodes.head); |  | 
| 3465         } |  | 
| 3466       } |  | 
| 3467     } |  | 
| 3468     DartType listType; |  | 
| 3469     if (typeArgument != null) { |  | 
| 3470       if (node.isConst && typeArgument.containsTypeVariables) { |  | 
| 3471         compiler.reportError(arguments.nodes.head, |  | 
| 3472             MessageKind.TYPE_VARIABLE_IN_CONSTANT); |  | 
| 3473       } |  | 
| 3474       listType = new InterfaceType(compiler.listClass, [typeArgument]); |  | 
| 3475     } else { |  | 
| 3476       compiler.listClass.computeType(compiler); |  | 
| 3477       listType = compiler.listClass.rawType; |  | 
| 3478     } |  | 
| 3479     registry.setType(node, listType); |  | 
| 3480     registry.registerInstantiatedType(listType); |  | 
| 3481     registry.registerRequiredType(listType, enclosingElement); |  | 
| 3482     visit(node.elements); |  | 
| 3483     if (node.isConst) { |  | 
| 3484       analyzeConstant(node); |  | 
| 3485     } |  | 
| 3486 |  | 
| 3487     sendIsMemberAccess = false; |  | 
| 3488   } |  | 
| 3489 |  | 
| 3490   visitConditional(Conditional node) { |  | 
| 3491     doInPromotionScope(node.condition, () => visit(node.condition)); |  | 
| 3492     doInPromotionScope(node.thenExpression, () => visit(node.thenExpression)); |  | 
| 3493     visit(node.elseExpression); |  | 
| 3494   } |  | 
| 3495 |  | 
| 3496   visitStringInterpolation(StringInterpolation node) { |  | 
| 3497     registry.registerInstantiatedClass(compiler.stringClass); |  | 
| 3498     registry.registerStringInterpolation(); |  | 
| 3499     node.visitChildren(this); |  | 
| 3500   } |  | 
| 3501 |  | 
| 3502   visitStringInterpolationPart(StringInterpolationPart node) { |  | 
| 3503     registerImplicitInvocation('toString', 0); |  | 
| 3504     node.visitChildren(this); |  | 
| 3505   } |  | 
| 3506 |  | 
| 3507   visitBreakStatement(BreakStatement node) { |  | 
| 3508     JumpTarget target; |  | 
| 3509     if (node.target == null) { |  | 
| 3510       target = statementScope.currentBreakTarget(); |  | 
| 3511       if (target == null) { |  | 
| 3512         error(node, MessageKind.NO_BREAK_TARGET); |  | 
| 3513         return; |  | 
| 3514       } |  | 
| 3515       target.isBreakTarget = true; |  | 
| 3516     } else { |  | 
| 3517       String labelName = node.target.source; |  | 
| 3518       LabelDefinition label = statementScope.lookupLabel(labelName); |  | 
| 3519       if (label == null) { |  | 
| 3520         error(node.target, MessageKind.UNBOUND_LABEL, {'labelName': labelName}); |  | 
| 3521         return; |  | 
| 3522       } |  | 
| 3523       target = label.target; |  | 
| 3524       if (!target.statement.isValidBreakTarget()) { |  | 
| 3525         error(node.target, MessageKind.INVALID_BREAK); |  | 
| 3526         return; |  | 
| 3527       } |  | 
| 3528       label.setBreakTarget(); |  | 
| 3529       registry.useLabel(node, label); |  | 
| 3530     } |  | 
| 3531     registry.registerTargetOf(node, target); |  | 
| 3532   } |  | 
| 3533 |  | 
| 3534   visitContinueStatement(ContinueStatement node) { |  | 
| 3535     JumpTarget target; |  | 
| 3536     if (node.target == null) { |  | 
| 3537       target = statementScope.currentContinueTarget(); |  | 
| 3538       if (target == null) { |  | 
| 3539         error(node, MessageKind.NO_CONTINUE_TARGET); |  | 
| 3540         return; |  | 
| 3541       } |  | 
| 3542       target.isContinueTarget = true; |  | 
| 3543     } else { |  | 
| 3544       String labelName = node.target.source; |  | 
| 3545       LabelDefinition label = statementScope.lookupLabel(labelName); |  | 
| 3546       if (label == null) { |  | 
| 3547         error(node.target, MessageKind.UNBOUND_LABEL, {'labelName': labelName}); |  | 
| 3548         return; |  | 
| 3549       } |  | 
| 3550       target = label.target; |  | 
| 3551       if (!target.statement.isValidContinueTarget()) { |  | 
| 3552         error(node.target, MessageKind.INVALID_CONTINUE); |  | 
| 3553       } |  | 
| 3554       label.setContinueTarget(); |  | 
| 3555       registry.useLabel(node, label); |  | 
| 3556     } |  | 
| 3557     registry.registerTargetOf(node, target); |  | 
| 3558   } |  | 
| 3559 |  | 
| 3560   registerImplicitInvocation(String name, int arity) { |  | 
| 3561     Selector selector = new Selector.call(name, null, arity); |  | 
| 3562     registry.registerDynamicInvocation(selector); |  | 
| 3563   } |  | 
| 3564 |  | 
| 3565   visitForIn(ForIn node) { |  | 
| 3566     LibraryElement library = enclosingElement.library; |  | 
| 3567     registry.setIteratorSelector(node, compiler.iteratorSelector); |  | 
| 3568     registry.registerDynamicGetter(compiler.iteratorSelector); |  | 
| 3569     registry.setCurrentSelector(node, compiler.currentSelector); |  | 
| 3570     registry.registerDynamicGetter(compiler.currentSelector); |  | 
| 3571     registry.setMoveNextSelector(node, compiler.moveNextSelector); |  | 
| 3572     registry.registerDynamicInvocation(compiler.moveNextSelector); |  | 
| 3573 |  | 
| 3574     visit(node.expression); |  | 
| 3575     Scope blockScope = new BlockScope(scope); |  | 
| 3576     Node declaration = node.declaredIdentifier; |  | 
| 3577 |  | 
| 3578     bool oldAllowFinalWithoutInitializer = allowFinalWithoutInitializer; |  | 
| 3579     allowFinalWithoutInitializer = true; |  | 
| 3580     visitIn(declaration, blockScope); |  | 
| 3581     allowFinalWithoutInitializer = oldAllowFinalWithoutInitializer; |  | 
| 3582 |  | 
| 3583     Send send = declaration.asSend(); |  | 
| 3584     VariableDefinitions variableDefinitions = |  | 
| 3585         declaration.asVariableDefinitions(); |  | 
| 3586     Element loopVariable; |  | 
| 3587     Selector loopVariableSelector; |  | 
| 3588     if (send != null) { |  | 
| 3589       loopVariable = registry.getDefinition(send); |  | 
| 3590       Identifier identifier = send.selector.asIdentifier(); |  | 
| 3591       if (identifier == null) { |  | 
| 3592         compiler.reportError(send.selector, MessageKind.INVALID_FOR_IN); |  | 
| 3593       } else { |  | 
| 3594         loopVariableSelector = new Selector.setter(identifier.source, library); |  | 
| 3595       } |  | 
| 3596       if (send.receiver != null) { |  | 
| 3597         compiler.reportError(send.receiver, MessageKind.INVALID_FOR_IN); |  | 
| 3598       } |  | 
| 3599     } else if (variableDefinitions != null) { |  | 
| 3600       Link<Node> nodes = variableDefinitions.definitions.nodes; |  | 
| 3601       if (!nodes.tail.isEmpty) { |  | 
| 3602         compiler.reportError(nodes.tail.head, MessageKind.INVALID_FOR_IN); |  | 
| 3603       } |  | 
| 3604       Node first = nodes.head; |  | 
| 3605       Identifier identifier = first.asIdentifier(); |  | 
| 3606       if (identifier == null) { |  | 
| 3607         compiler.reportError(first, MessageKind.INVALID_FOR_IN); |  | 
| 3608       } else { |  | 
| 3609         loopVariableSelector = new Selector.setter(identifier.source, library); |  | 
| 3610         loopVariable = registry.getDefinition(identifier); |  | 
| 3611       } |  | 
| 3612     } else { |  | 
| 3613       compiler.reportError(declaration, MessageKind.INVALID_FOR_IN); |  | 
| 3614     } |  | 
| 3615     if (loopVariableSelector != null) { |  | 
| 3616       registry.setSelector(declaration, loopVariableSelector); |  | 
| 3617       registerSend(loopVariableSelector, loopVariable); |  | 
| 3618     } else { |  | 
| 3619       // The selector may only be null if we reported an error. |  | 
| 3620       assert(invariant(declaration, compiler.compilationFailed)); |  | 
| 3621     } |  | 
| 3622     if (loopVariable != null) { |  | 
| 3623       // loopVariable may be null if it could not be resolved. |  | 
| 3624       registry.setForInVariable(node, loopVariable); |  | 
| 3625     } |  | 
| 3626     visitLoopBodyIn(node, node.body, blockScope); |  | 
| 3627   } |  | 
| 3628 |  | 
| 3629   visitLabel(Label node) { |  | 
| 3630     // Labels are handled by their containing statements/cases. |  | 
| 3631   } |  | 
| 3632 |  | 
| 3633   visitLabeledStatement(LabeledStatement node) { |  | 
| 3634     Statement body = node.statement; |  | 
| 3635     JumpTarget targetElement = getOrDefineTarget(body); |  | 
| 3636     Map<String, LabelDefinition> labelElements = <String, LabelDefinition>{}; |  | 
| 3637     for (Label label in node.labels) { |  | 
| 3638       String labelName = label.labelName; |  | 
| 3639       if (labelElements.containsKey(labelName)) continue; |  | 
| 3640       LabelDefinition element = targetElement.addLabel(label, labelName); |  | 
| 3641       labelElements[labelName] = element; |  | 
| 3642     } |  | 
| 3643     statementScope.enterLabelScope(labelElements); |  | 
| 3644     visit(node.statement); |  | 
| 3645     statementScope.exitLabelScope(); |  | 
| 3646     labelElements.forEach((String labelName, LabelDefinition element) { |  | 
| 3647       if (element.isTarget) { |  | 
| 3648         registry.defineLabel(element.label, element); |  | 
| 3649       } else { |  | 
| 3650         warning(element.label, MessageKind.UNUSED_LABEL, |  | 
| 3651                 {'labelName': labelName}); |  | 
| 3652       } |  | 
| 3653     }); |  | 
| 3654     if (!targetElement.isTarget) { |  | 
| 3655       registry.undefineTarget(body); |  | 
| 3656     } |  | 
| 3657   } |  | 
| 3658 |  | 
| 3659   visitLiteralMap(LiteralMap node) { |  | 
| 3660     bool oldSendIsMemberAccess = sendIsMemberAccess; |  | 
| 3661     sendIsMemberAccess = false; |  | 
| 3662 |  | 
| 3663     NodeList arguments = node.typeArguments; |  | 
| 3664     DartType keyTypeArgument; |  | 
| 3665     DartType valueTypeArgument; |  | 
| 3666     if (arguments != null) { |  | 
| 3667       Link<Node> nodes = arguments.nodes; |  | 
| 3668       if (nodes.isEmpty) { |  | 
| 3669         // The syntax [: <>{} :] is not allowed. |  | 
| 3670         error(arguments, MessageKind.MISSING_TYPE_ARGUMENT); |  | 
| 3671       } else { |  | 
| 3672         keyTypeArgument = resolveTypeAnnotation(nodes.head); |  | 
| 3673         nodes = nodes.tail; |  | 
| 3674         if (nodes.isEmpty) { |  | 
| 3675           warning(arguments, MessageKind.MISSING_TYPE_ARGUMENT); |  | 
| 3676         } else { |  | 
| 3677           valueTypeArgument = resolveTypeAnnotation(nodes.head); |  | 
| 3678           for (nodes = nodes.tail; !nodes.isEmpty; nodes = nodes.tail) { |  | 
| 3679             warning(nodes.head, MessageKind.ADDITIONAL_TYPE_ARGUMENT); |  | 
| 3680             resolveTypeAnnotation(nodes.head); |  | 
| 3681           } |  | 
| 3682         } |  | 
| 3683       } |  | 
| 3684     } |  | 
| 3685     DartType mapType; |  | 
| 3686     if (valueTypeArgument != null) { |  | 
| 3687       mapType = new InterfaceType(compiler.mapClass, |  | 
| 3688           [keyTypeArgument, valueTypeArgument]); |  | 
| 3689     } else { |  | 
| 3690       compiler.mapClass.computeType(compiler); |  | 
| 3691       mapType = compiler.mapClass.rawType; |  | 
| 3692     } |  | 
| 3693     if (node.isConst && mapType.containsTypeVariables) { |  | 
| 3694       compiler.reportError(arguments, |  | 
| 3695           MessageKind.TYPE_VARIABLE_IN_CONSTANT); |  | 
| 3696     } |  | 
| 3697     registry.setType(node, mapType); |  | 
| 3698     registry.registerInstantiatedType(mapType); |  | 
| 3699     if (node.isConst) { |  | 
| 3700       registry.registerConstantMap(); |  | 
| 3701     } |  | 
| 3702     registry.registerRequiredType(mapType, enclosingElement); |  | 
| 3703     node.visitChildren(this); |  | 
| 3704     if (node.isConst) { |  | 
| 3705       analyzeConstant(node); |  | 
| 3706     } |  | 
| 3707 |  | 
| 3708     sendIsMemberAccess = false; |  | 
| 3709   } |  | 
| 3710 |  | 
| 3711   visitLiteralMapEntry(LiteralMapEntry node) { |  | 
| 3712     node.visitChildren(this); |  | 
| 3713   } |  | 
| 3714 |  | 
| 3715   visitNamedArgument(NamedArgument node) { |  | 
| 3716     visit(node.expression); |  | 
| 3717   } |  | 
| 3718 |  | 
| 3719   DartType typeOfConstant(ConstantValue constant) { |  | 
| 3720     if (constant.isInt) return compiler.intClass.rawType; |  | 
| 3721     if (constant.isBool) return compiler.boolClass.rawType; |  | 
| 3722     if (constant.isDouble) return compiler.doubleClass.rawType; |  | 
| 3723     if (constant.isString) return compiler.stringClass.rawType; |  | 
| 3724     if (constant.isNull) return compiler.nullClass.rawType; |  | 
| 3725     if (constant.isFunction) return compiler.functionClass.rawType; |  | 
| 3726     assert(constant.isObject); |  | 
| 3727     ObjectConstantValue objectConstant = constant; |  | 
| 3728     return objectConstant.type; |  | 
| 3729   } |  | 
| 3730 |  | 
| 3731   bool overridesEquals(DartType type) { |  | 
| 3732     ClassElement cls = type.element; |  | 
| 3733     Element equals = cls.lookupMember('=='); |  | 
| 3734     return equals.enclosingClass != compiler.objectClass; |  | 
| 3735   } |  | 
| 3736 |  | 
| 3737   void checkCaseExpressions(SwitchStatement node) { |  | 
| 3738     JumpTarget breakElement = getOrDefineTarget(node); |  | 
| 3739     Map<String, LabelDefinition> continueLabels = <String, LabelDefinition>{}; |  | 
| 3740 |  | 
| 3741     Link<Node> cases = node.cases.nodes; |  | 
| 3742     CaseMatch firstCase = null; |  | 
| 3743     DartType firstCaseType = null; |  | 
| 3744     bool hasReportedProblem = false; |  | 
| 3745 |  | 
| 3746     for (Link<Node> cases = node.cases.nodes; |  | 
| 3747          !cases.isEmpty; |  | 
| 3748          cases = cases.tail) { |  | 
| 3749       SwitchCase switchCase = cases.head; |  | 
| 3750 |  | 
| 3751       for (Node labelOrCase in switchCase.labelsAndCases) { |  | 
| 3752         CaseMatch caseMatch = labelOrCase.asCaseMatch(); |  | 
| 3753         if (caseMatch == null) continue; |  | 
| 3754 |  | 
| 3755         // Analyze the constant. |  | 
| 3756         ConstantExpression constant = |  | 
| 3757             registry.getConstant(caseMatch.expression); |  | 
| 3758         assert(invariant(node, constant != null, |  | 
| 3759             message: 'No constant computed for $node')); |  | 
| 3760 |  | 
| 3761         DartType caseType = typeOfConstant(constant.value); |  | 
| 3762 |  | 
| 3763         if (firstCaseType == null) { |  | 
| 3764           firstCase = caseMatch; |  | 
| 3765           firstCaseType = caseType; |  | 
| 3766 |  | 
| 3767           // We only report the bad type on the first class element. All others |  | 
| 3768           // get a "type differs" error. |  | 
| 3769           if (caseType.element == compiler.doubleClass) { |  | 
| 3770             compiler.reportError(node, |  | 
| 3771                                  MessageKind.SWITCH_CASE_VALUE_OVERRIDES_EQUALS, |  | 
| 3772                                  {'type': "double"}); |  | 
| 3773           } else if (caseType.element == compiler.functionClass) { |  | 
| 3774             compiler.reportError(node, MessageKind.SWITCH_CASE_FORBIDDEN, |  | 
| 3775                                  {'type': "Function"}); |  | 
| 3776           } else if (constant.value.isObject && overridesEquals(caseType)) { |  | 
| 3777             compiler.reportError(firstCase.expression, |  | 
| 3778                 MessageKind.SWITCH_CASE_VALUE_OVERRIDES_EQUALS, |  | 
| 3779                 {'type': caseType}); |  | 
| 3780           } |  | 
| 3781         } else { |  | 
| 3782           if (caseType != firstCaseType) { |  | 
| 3783             if (!hasReportedProblem) { |  | 
| 3784               compiler.reportError( |  | 
| 3785                   node, |  | 
| 3786                   MessageKind.SWITCH_CASE_TYPES_NOT_EQUAL, |  | 
| 3787                   {'type': firstCaseType}); |  | 
| 3788               compiler.reportInfo( |  | 
| 3789                   firstCase.expression, |  | 
| 3790                   MessageKind.SWITCH_CASE_TYPES_NOT_EQUAL_CASE, |  | 
| 3791                   {'type': firstCaseType}); |  | 
| 3792               hasReportedProblem = true; |  | 
| 3793             } |  | 
| 3794             compiler.reportInfo( |  | 
| 3795                 caseMatch.expression, |  | 
| 3796                 MessageKind.SWITCH_CASE_TYPES_NOT_EQUAL_CASE, |  | 
| 3797                 {'type': caseType}); |  | 
| 3798           } |  | 
| 3799         } |  | 
| 3800       } |  | 
| 3801     } |  | 
| 3802   } |  | 
| 3803 |  | 
| 3804   visitSwitchStatement(SwitchStatement node) { |  | 
| 3805     node.expression.accept(this); |  | 
| 3806 |  | 
| 3807     JumpTarget breakElement = getOrDefineTarget(node); |  | 
| 3808     Map<String, LabelDefinition> continueLabels = <String, LabelDefinition>{}; |  | 
| 3809     Link<Node> cases = node.cases.nodes; |  | 
| 3810     while (!cases.isEmpty) { |  | 
| 3811       SwitchCase switchCase = cases.head; |  | 
| 3812       for (Node labelOrCase in switchCase.labelsAndCases) { |  | 
| 3813         CaseMatch caseMatch = labelOrCase.asCaseMatch(); |  | 
| 3814         if (caseMatch != null) { |  | 
| 3815           analyzeConstant(caseMatch.expression); |  | 
| 3816           continue; |  | 
| 3817         } |  | 
| 3818         Label label = labelOrCase; |  | 
| 3819         String labelName = label.labelName; |  | 
| 3820 |  | 
| 3821         LabelDefinition existingElement = continueLabels[labelName]; |  | 
| 3822         if (existingElement != null) { |  | 
| 3823           // It's an error if the same label occurs twice in the same switch. |  | 
| 3824           compiler.reportError( |  | 
| 3825               label, |  | 
| 3826               MessageKind.DUPLICATE_LABEL, {'labelName': labelName}); |  | 
| 3827           compiler.reportInfo( |  | 
| 3828               existingElement.label, |  | 
| 3829               MessageKind.EXISTING_LABEL, {'labelName': labelName}); |  | 
| 3830         } else { |  | 
| 3831           // It's only a warning if it shadows another label. |  | 
| 3832           existingElement = statementScope.lookupLabel(labelName); |  | 
| 3833           if (existingElement != null) { |  | 
| 3834             compiler.reportWarning( |  | 
| 3835                 label, |  | 
| 3836                 MessageKind.DUPLICATE_LABEL, {'labelName': labelName}); |  | 
| 3837             compiler.reportInfo( |  | 
| 3838                 existingElement.label, |  | 
| 3839                 MessageKind.EXISTING_LABEL, {'labelName': labelName}); |  | 
| 3840           } |  | 
| 3841         } |  | 
| 3842 |  | 
| 3843         JumpTarget targetElement = getOrDefineTarget(switchCase); |  | 
| 3844         LabelDefinition labelElement = targetElement.addLabel(label, labelName); |  | 
| 3845         registry.defineLabel(label, labelElement); |  | 
| 3846         continueLabels[labelName] = labelElement; |  | 
| 3847       } |  | 
| 3848       cases = cases.tail; |  | 
| 3849       // Test that only the last case, if any, is a default case. |  | 
| 3850       if (switchCase.defaultKeyword != null && !cases.isEmpty) { |  | 
| 3851         error(switchCase, MessageKind.INVALID_CASE_DEFAULT); |  | 
| 3852       } |  | 
| 3853     } |  | 
| 3854 |  | 
| 3855     addDeferredAction(enclosingElement, () { |  | 
| 3856       checkCaseExpressions(node); |  | 
| 3857     }); |  | 
| 3858 |  | 
| 3859     statementScope.enterSwitch(breakElement, continueLabels); |  | 
| 3860     node.cases.accept(this); |  | 
| 3861     statementScope.exitSwitch(); |  | 
| 3862 |  | 
| 3863     // Clean-up unused labels. |  | 
| 3864     continueLabels.forEach((String key, LabelDefinition label) { |  | 
| 3865       if (!label.isContinueTarget) { |  | 
| 3866         JumpTarget targetElement = label.target; |  | 
| 3867         SwitchCase switchCase = targetElement.statement; |  | 
| 3868         registry.undefineTarget(switchCase); |  | 
| 3869         registry.undefineLabel(label.label); |  | 
| 3870       } |  | 
| 3871     }); |  | 
| 3872     // TODO(15575): We should warn if we can detect a fall through |  | 
| 3873     // error. |  | 
| 3874     registry.registerFallThroughError(); |  | 
| 3875   } |  | 
| 3876 |  | 
| 3877   visitSwitchCase(SwitchCase node) { |  | 
| 3878     node.labelsAndCases.accept(this); |  | 
| 3879     visitIn(node.statements, new BlockScope(scope)); |  | 
| 3880   } |  | 
| 3881 |  | 
| 3882   visitCaseMatch(CaseMatch node) { |  | 
| 3883     visit(node.expression); |  | 
| 3884   } |  | 
| 3885 |  | 
| 3886   visitTryStatement(TryStatement node) { |  | 
| 3887     visit(node.tryBlock); |  | 
| 3888     if (node.catchBlocks.isEmpty && node.finallyBlock == null) { |  | 
| 3889       error(node.getEndToken().next, MessageKind.NO_CATCH_NOR_FINALLY); |  | 
| 3890     } |  | 
| 3891     visit(node.catchBlocks); |  | 
| 3892     visit(node.finallyBlock); |  | 
| 3893   } |  | 
| 3894 |  | 
| 3895   visitCatchBlock(CatchBlock node) { |  | 
| 3896     registry.registerCatchStatement(); |  | 
| 3897     // Check that if catch part is present, then |  | 
| 3898     // it has one or two formal parameters. |  | 
| 3899     VariableDefinitions exceptionDefinition; |  | 
| 3900     VariableDefinitions stackTraceDefinition; |  | 
| 3901     if (node.formals != null) { |  | 
| 3902       Link<Node> formalsToProcess = node.formals.nodes; |  | 
| 3903       if (formalsToProcess.isEmpty) { |  | 
| 3904         error(node, MessageKind.EMPTY_CATCH_DECLARATION); |  | 
| 3905       } else { |  | 
| 3906         exceptionDefinition = formalsToProcess.head.asVariableDefinitions(); |  | 
| 3907         formalsToProcess = formalsToProcess.tail; |  | 
| 3908         if (!formalsToProcess.isEmpty) { |  | 
| 3909           stackTraceDefinition = formalsToProcess.head.asVariableDefinitions(); |  | 
| 3910           formalsToProcess = formalsToProcess.tail; |  | 
| 3911           if (!formalsToProcess.isEmpty) { |  | 
| 3912             for (Node extra in formalsToProcess) { |  | 
| 3913               error(extra, MessageKind.EXTRA_CATCH_DECLARATION); |  | 
| 3914             } |  | 
| 3915           } |  | 
| 3916           registry.registerStackTraceInCatch(); |  | 
| 3917         } |  | 
| 3918       } |  | 
| 3919 |  | 
| 3920       // Check that the formals aren't optional and that they have no |  | 
| 3921       // modifiers or type. |  | 
| 3922       for (Link<Node> link = node.formals.nodes; |  | 
| 3923            !link.isEmpty; |  | 
| 3924            link = link.tail) { |  | 
| 3925         // If the formal parameter is a node list, it means that it is a |  | 
| 3926         // sequence of optional parameters. |  | 
| 3927         NodeList nodeList = link.head.asNodeList(); |  | 
| 3928         if (nodeList != null) { |  | 
| 3929           error(nodeList, MessageKind.OPTIONAL_PARAMETER_IN_CATCH); |  | 
| 3930         } else { |  | 
| 3931           VariableDefinitions declaration = link.head; |  | 
| 3932           for (Node modifier in declaration.modifiers.nodes) { |  | 
| 3933             error(modifier, MessageKind.PARAMETER_WITH_MODIFIER_IN_CATCH); |  | 
| 3934           } |  | 
| 3935           TypeAnnotation type = declaration.type; |  | 
| 3936           if (type != null) { |  | 
| 3937             error(type, MessageKind.PARAMETER_WITH_TYPE_IN_CATCH); |  | 
| 3938           } |  | 
| 3939         } |  | 
| 3940       } |  | 
| 3941     } |  | 
| 3942 |  | 
| 3943     Scope blockScope = new BlockScope(scope); |  | 
| 3944     doInCheckContext(() => visitIn(node.type, blockScope)); |  | 
| 3945     visitIn(node.formals, blockScope); |  | 
| 3946     var oldInCatchBlock = inCatchBlock; |  | 
| 3947     inCatchBlock = true; |  | 
| 3948     visitIn(node.block, blockScope); |  | 
| 3949     inCatchBlock = oldInCatchBlock; |  | 
| 3950 |  | 
| 3951     if (node.type != null && exceptionDefinition != null) { |  | 
| 3952       DartType exceptionType = registry.getType(node.type); |  | 
| 3953       Node exceptionVariable = exceptionDefinition.definitions.nodes.head; |  | 
| 3954       VariableElementX exceptionElement = |  | 
| 3955           registry.getDefinition(exceptionVariable); |  | 
| 3956       exceptionElement.variables.type = exceptionType; |  | 
| 3957     } |  | 
| 3958     if (stackTraceDefinition != null) { |  | 
| 3959       Node stackTraceVariable = stackTraceDefinition.definitions.nodes.head; |  | 
| 3960       VariableElementX stackTraceElement = |  | 
| 3961           registry.getDefinition(stackTraceVariable); |  | 
| 3962       registry.registerInstantiatedClass(compiler.stackTraceClass); |  | 
| 3963       stackTraceElement.variables.type = compiler.stackTraceClass.rawType; |  | 
| 3964     } |  | 
| 3965   } |  | 
| 3966 |  | 
| 3967   visitTypedef(Typedef node) { |  | 
| 3968     internalError(node, 'typedef'); |  | 
| 3969   } |  | 
| 3970 } |  | 
| 3971 |  | 
| 3972 class TypeDefinitionVisitor extends MappingVisitor<DartType> { |  | 
| 3973   Scope scope; |  | 
| 3974   final TypeDeclarationElement enclosingElement; |  | 
| 3975   TypeDeclarationElement get element => enclosingElement; |  | 
| 3976 |  | 
| 3977   TypeDefinitionVisitor(Compiler compiler, |  | 
| 3978                         TypeDeclarationElement element, |  | 
| 3979                         ResolutionRegistry registry) |  | 
| 3980       : this.enclosingElement = element, |  | 
| 3981         scope = Scope.buildEnclosingScope(element), |  | 
| 3982         super(compiler, registry); |  | 
| 3983 |  | 
| 3984   DartType get objectType => compiler.objectClass.rawType; |  | 
| 3985 |  | 
| 3986   void resolveTypeVariableBounds(NodeList node) { |  | 
| 3987     if (node == null) return; |  | 
| 3988 |  | 
| 3989     Setlet<String> nameSet = new Setlet<String>(); |  | 
| 3990     // Resolve the bounds of type variables. |  | 
| 3991     Iterator<DartType> types = element.typeVariables.iterator; |  | 
| 3992     Link<Node> nodeLink = node.nodes; |  | 
| 3993     while (!nodeLink.isEmpty) { |  | 
| 3994       types.moveNext(); |  | 
| 3995       TypeVariableType typeVariable = types.current; |  | 
| 3996       String typeName = typeVariable.name; |  | 
| 3997       TypeVariable typeNode = nodeLink.head; |  | 
| 3998       registry.useType(typeNode, typeVariable); |  | 
| 3999       if (nameSet.contains(typeName)) { |  | 
| 4000         error(typeNode, MessageKind.DUPLICATE_TYPE_VARIABLE_NAME, |  | 
| 4001               {'typeVariableName': typeName}); |  | 
| 4002       } |  | 
| 4003       nameSet.add(typeName); |  | 
| 4004 |  | 
| 4005       TypeVariableElementX variableElement = typeVariable.element; |  | 
| 4006       if (typeNode.bound != null) { |  | 
| 4007         DartType boundType = typeResolver.resolveTypeAnnotation( |  | 
| 4008             this, typeNode.bound); |  | 
| 4009         variableElement.boundCache = boundType; |  | 
| 4010 |  | 
| 4011         void checkTypeVariableBound() { |  | 
| 4012           Link<TypeVariableElement> seenTypeVariables = |  | 
| 4013               const Link<TypeVariableElement>(); |  | 
| 4014           seenTypeVariables = seenTypeVariables.prepend(variableElement); |  | 
| 4015           DartType bound = boundType; |  | 
| 4016           while (bound.isTypeVariable) { |  | 
| 4017             TypeVariableElement element = bound.element; |  | 
| 4018             if (seenTypeVariables.contains(element)) { |  | 
| 4019               if (identical(element, variableElement)) { |  | 
| 4020                 // Only report an error on the checked type variable to avoid |  | 
| 4021                 // generating multiple errors for the same cyclicity. |  | 
| 4022                 warning(typeNode.name, MessageKind.CYCLIC_TYPE_VARIABLE, |  | 
| 4023                     {'typeVariableName': variableElement.name}); |  | 
| 4024               } |  | 
| 4025               break; |  | 
| 4026             } |  | 
| 4027             seenTypeVariables = seenTypeVariables.prepend(element); |  | 
| 4028             bound = element.bound; |  | 
| 4029           } |  | 
| 4030         } |  | 
| 4031         addDeferredAction(element, checkTypeVariableBound); |  | 
| 4032       } else { |  | 
| 4033         variableElement.boundCache = objectType; |  | 
| 4034       } |  | 
| 4035       nodeLink = nodeLink.tail; |  | 
| 4036     } |  | 
| 4037     assert(!types.moveNext()); |  | 
| 4038   } |  | 
| 4039 } |  | 
| 4040 |  | 
| 4041 class TypedefResolverVisitor extends TypeDefinitionVisitor { |  | 
| 4042   TypedefElementX get element => enclosingElement; |  | 
| 4043 |  | 
| 4044   TypedefResolverVisitor(Compiler compiler, |  | 
| 4045                          TypedefElement typedefElement, |  | 
| 4046                          ResolutionRegistry registry) |  | 
| 4047       : super(compiler, typedefElement, registry); |  | 
| 4048 |  | 
| 4049   visitTypedef(Typedef node) { |  | 
| 4050     TypedefType type = element.computeType(compiler); |  | 
| 4051     scope = new TypeDeclarationScope(scope, element); |  | 
| 4052     resolveTypeVariableBounds(node.typeParameters); |  | 
| 4053 |  | 
| 4054     FunctionSignature signature = SignatureResolver.analyze( |  | 
| 4055         compiler, node.formals, node.returnType, element, registry, |  | 
| 4056         defaultValuesError: MessageKind.TYPEDEF_FORMAL_WITH_DEFAULT); |  | 
| 4057     element.functionSignature = signature; |  | 
| 4058 |  | 
| 4059     scope = new MethodScope(scope, element); |  | 
| 4060     signature.forEachParameter(addToScope); |  | 
| 4061 |  | 
| 4062     element.alias = signature.type; |  | 
| 4063 |  | 
| 4064     void checkCyclicReference() { |  | 
| 4065       element.checkCyclicReference(compiler); |  | 
| 4066     } |  | 
| 4067     addDeferredAction(element, checkCyclicReference); |  | 
| 4068   } |  | 
| 4069 } |  | 
| 4070 |  | 
| 4071 // TODO(johnniwinther): Replace with a traversal on the AST when the type |  | 
| 4072 // annotations in typedef alias are stored in a [TreeElements] mapping. |  | 
| 4073 class TypedefCyclicVisitor extends DartTypeVisitor { |  | 
| 4074   final Compiler compiler; |  | 
| 4075   final TypedefElementX element; |  | 
| 4076   bool hasCyclicReference = false; |  | 
| 4077 |  | 
| 4078   Link<TypedefElement> seenTypedefs = const Link<TypedefElement>(); |  | 
| 4079 |  | 
| 4080   int seenTypedefsCount = 0; |  | 
| 4081 |  | 
| 4082   Link<TypeVariableElement> seenTypeVariables = |  | 
| 4083       const Link<TypeVariableElement>(); |  | 
| 4084 |  | 
| 4085   TypedefCyclicVisitor(Compiler this.compiler, TypedefElement this.element); |  | 
| 4086 |  | 
| 4087   visitType(DartType type, _) { |  | 
| 4088     // Do nothing. |  | 
| 4089   } |  | 
| 4090 |  | 
| 4091   visitTypedefType(TypedefType type, _) { |  | 
| 4092     TypedefElementX typedefElement = type.element; |  | 
| 4093     if (seenTypedefs.contains(typedefElement)) { |  | 
| 4094       if (!hasCyclicReference && identical(element, typedefElement)) { |  | 
| 4095         // Only report an error on the checked typedef to avoid generating |  | 
| 4096         // multiple errors for the same cyclicity. |  | 
| 4097         hasCyclicReference = true; |  | 
| 4098         if (seenTypedefsCount == 1) { |  | 
| 4099           // Direct cyclicity. |  | 
| 4100           compiler.reportError(element, |  | 
| 4101               MessageKind.CYCLIC_TYPEDEF, |  | 
| 4102               {'typedefName': element.name}); |  | 
| 4103         } else if (seenTypedefsCount == 2) { |  | 
| 4104           // Cyclicity through one other typedef. |  | 
| 4105           compiler.reportError(element, |  | 
| 4106               MessageKind.CYCLIC_TYPEDEF_ONE, |  | 
| 4107               {'typedefName': element.name, |  | 
| 4108                'otherTypedefName': seenTypedefs.head.name}); |  | 
| 4109         } else { |  | 
| 4110           // Cyclicity through more than one other typedef. |  | 
| 4111           for (TypedefElement cycle in seenTypedefs) { |  | 
| 4112             if (!identical(typedefElement, cycle)) { |  | 
| 4113               compiler.reportError(element, |  | 
| 4114                   MessageKind.CYCLIC_TYPEDEF_ONE, |  | 
| 4115                   {'typedefName': element.name, |  | 
| 4116                    'otherTypedefName': cycle.name}); |  | 
| 4117             } |  | 
| 4118           } |  | 
| 4119         } |  | 
| 4120         ErroneousElementX erroneousElement = new ErroneousElementX( |  | 
| 4121               MessageKind.CYCLIC_TYPEDEF, |  | 
| 4122               {'typedefName': element.name}, |  | 
| 4123               element.name, element); |  | 
| 4124         element.alias = |  | 
| 4125             new MalformedType(erroneousElement, typedefElement.alias); |  | 
| 4126         element.hasBeenCheckedForCycles = true; |  | 
| 4127       } |  | 
| 4128     } else { |  | 
| 4129       seenTypedefs = seenTypedefs.prepend(typedefElement); |  | 
| 4130       seenTypedefsCount++; |  | 
| 4131       type.visitChildren(this, null); |  | 
| 4132       typedefElement.alias.accept(this, null); |  | 
| 4133       seenTypedefs = seenTypedefs.tail; |  | 
| 4134       seenTypedefsCount--; |  | 
| 4135     } |  | 
| 4136   } |  | 
| 4137 |  | 
| 4138   visitFunctionType(FunctionType type, _) { |  | 
| 4139     type.visitChildren(this, null); |  | 
| 4140   } |  | 
| 4141 |  | 
| 4142   visitInterfaceType(InterfaceType type, _) { |  | 
| 4143     type.visitChildren(this, null); |  | 
| 4144   } |  | 
| 4145 |  | 
| 4146   visitTypeVariableType(TypeVariableType type, _) { |  | 
| 4147     TypeVariableElement typeVariableElement = type.element; |  | 
| 4148     if (seenTypeVariables.contains(typeVariableElement)) { |  | 
| 4149       // Avoid running in cycles on cyclic type variable bounds. |  | 
| 4150       // Cyclicity is reported elsewhere. |  | 
| 4151       return; |  | 
| 4152     } |  | 
| 4153     seenTypeVariables = seenTypeVariables.prepend(typeVariableElement); |  | 
| 4154     typeVariableElement.bound.accept(this, null); |  | 
| 4155     seenTypeVariables = seenTypeVariables.tail; |  | 
| 4156   } |  | 
| 4157 } |  | 
| 4158 |  | 
| 4159 /** |  | 
| 4160  * The implementation of [ResolverTask.resolveClass]. |  | 
| 4161  * |  | 
| 4162  * This visitor has to be extra careful as it is building the basic |  | 
| 4163  * element information, and cannot safely look at other elements as |  | 
| 4164  * this may lead to cycles. |  | 
| 4165  * |  | 
| 4166  * This visitor can assume that the supertypes have already been |  | 
| 4167  * resolved, but it cannot call [ResolverTask.resolveClass] directly |  | 
| 4168  * or indirectly (through [ClassElement.ensureResolved]) for any other |  | 
| 4169  * types. |  | 
| 4170  */ |  | 
| 4171 class ClassResolverVisitor extends TypeDefinitionVisitor { |  | 
| 4172   BaseClassElementX get element => enclosingElement; |  | 
| 4173 |  | 
| 4174   ClassResolverVisitor(Compiler compiler, |  | 
| 4175                        ClassElement classElement, |  | 
| 4176                        ResolutionRegistry registry) |  | 
| 4177     : super(compiler, classElement, registry); |  | 
| 4178 |  | 
| 4179   DartType visitClassNode(ClassNode node) { |  | 
| 4180     invariant(node, element != null); |  | 
| 4181     invariant(element, element.resolutionState == STATE_STARTED, |  | 
| 4182         message: () => 'cyclic resolution of class $element'); |  | 
| 4183 |  | 
| 4184     InterfaceType type = element.computeType(compiler); |  | 
| 4185     scope = new TypeDeclarationScope(scope, element); |  | 
| 4186     // TODO(ahe): It is not safe to call resolveTypeVariableBounds yet. |  | 
| 4187     // As a side-effect, this may get us back here trying to |  | 
| 4188     // resolve this class again. |  | 
| 4189     resolveTypeVariableBounds(node.typeParameters); |  | 
| 4190 |  | 
| 4191     // Setup the supertype for the element (if there is a cycle in the |  | 
| 4192     // class hierarchy, it has already been set to Object). |  | 
| 4193     if (element.supertype == null && node.superclass != null) { |  | 
| 4194       MixinApplication superMixin = node.superclass.asMixinApplication(); |  | 
| 4195       if (superMixin != null) { |  | 
| 4196         DartType supertype = resolveSupertype(element, superMixin.superclass); |  | 
| 4197         Link<Node> link = superMixin.mixins.nodes; |  | 
| 4198         while (!link.isEmpty) { |  | 
| 4199           supertype = applyMixin(supertype, |  | 
| 4200                                  checkMixinType(link.head), link.head); |  | 
| 4201           link = link.tail; |  | 
| 4202         } |  | 
| 4203         element.supertype = supertype; |  | 
| 4204       } else { |  | 
| 4205         element.supertype = resolveSupertype(element, node.superclass); |  | 
| 4206       } |  | 
| 4207     } |  | 
| 4208     // If the super type isn't specified, we provide a default.  The language |  | 
| 4209     // specifies [Object] but the backend can pick a specific 'implementation' |  | 
| 4210     // of Object - the JavaScript backend chooses between Object and |  | 
| 4211     // Interceptor. |  | 
| 4212     if (element.supertype == null) { |  | 
| 4213       ClassElement superElement = registry.defaultSuperclass(element); |  | 
| 4214       // Avoid making the superclass (usually Object) extend itself. |  | 
| 4215       if (element != superElement) { |  | 
| 4216         if (superElement == null) { |  | 
| 4217           compiler.internalError(node, |  | 
| 4218               "Cannot resolve default superclass for $element."); |  | 
| 4219         } else { |  | 
| 4220           superElement.ensureResolved(compiler); |  | 
| 4221         } |  | 
| 4222         element.supertype = superElement.computeType(compiler); |  | 
| 4223       } |  | 
| 4224     } |  | 
| 4225 |  | 
| 4226     if (element.interfaces == null) { |  | 
| 4227       element.interfaces = resolveInterfaces(node.interfaces, node.superclass); |  | 
| 4228     } else { |  | 
| 4229       assert(invariant(element, element.hasIncompleteHierarchy)); |  | 
| 4230     } |  | 
| 4231     calculateAllSupertypes(element); |  | 
| 4232 |  | 
| 4233     if (!element.hasConstructor) { |  | 
| 4234       Element superMember = element.superclass.localLookup(''); |  | 
| 4235       if (superMember == null || !superMember.isGenerativeConstructor) { |  | 
| 4236         MessageKind kind = MessageKind.CANNOT_FIND_CONSTRUCTOR; |  | 
| 4237         Map arguments = {'constructorName': ''}; |  | 
| 4238         // TODO(ahe): Why is this a compile-time error? Or if it is an error, |  | 
| 4239         // why do we bother to registerThrowNoSuchMethod below? |  | 
| 4240         compiler.reportError(node, kind, arguments); |  | 
| 4241         superMember = new ErroneousElementX( |  | 
| 4242             kind, arguments, '', element); |  | 
| 4243         registry.registerThrowNoSuchMethod(); |  | 
| 4244       } else { |  | 
| 4245         ConstructorElement superConstructor = superMember; |  | 
| 4246         Selector callToMatch = new Selector.call("", element.library, 0); |  | 
| 4247         superConstructor.computeSignature(compiler); |  | 
| 4248         if (!callToMatch.applies(superConstructor, compiler.world)) { |  | 
| 4249           MessageKind kind = MessageKind.NO_MATCHING_CONSTRUCTOR_FOR_IMPLICIT; |  | 
| 4250           compiler.reportError(node, kind); |  | 
| 4251           superMember = new ErroneousElementX(kind, {}, '', element); |  | 
| 4252         } |  | 
| 4253       } |  | 
| 4254       FunctionElement constructor = |  | 
| 4255           new SynthesizedConstructorElementX.forDefault(superMember, element); |  | 
| 4256       element.setDefaultConstructor(constructor, compiler); |  | 
| 4257     } |  | 
| 4258     return element.computeType(compiler); |  | 
| 4259   } |  | 
| 4260 |  | 
| 4261   /// Resolves the mixed type for [mixinNode] and checks that the the mixin type |  | 
| 4262   /// is a valid, non-blacklisted interface type. The mixin type is returned. |  | 
| 4263   DartType checkMixinType(TypeAnnotation mixinNode) { |  | 
| 4264     DartType mixinType = resolveType(mixinNode); |  | 
| 4265     if (isBlackListed(mixinType)) { |  | 
| 4266       compiler.reportError(mixinNode, |  | 
| 4267           MessageKind.CANNOT_MIXIN, {'type': mixinType}); |  | 
| 4268     } else if (mixinType.isTypeVariable) { |  | 
| 4269       compiler.reportError(mixinNode, MessageKind.CLASS_NAME_EXPECTED); |  | 
| 4270     } else if (mixinType.isMalformed) { |  | 
| 4271       compiler.reportError(mixinNode, MessageKind.CANNOT_MIXIN_MALFORMED, |  | 
| 4272           {'className': element.name, 'malformedType': mixinType}); |  | 
| 4273     } |  | 
| 4274     return mixinType; |  | 
| 4275   } |  | 
| 4276 |  | 
| 4277   DartType visitNamedMixinApplication(NamedMixinApplication node) { |  | 
| 4278     invariant(node, element != null); |  | 
| 4279     invariant(element, element.resolutionState == STATE_STARTED, |  | 
| 4280         message: () => 'cyclic resolution of class $element'); |  | 
| 4281 |  | 
| 4282     if (identical(node.classKeyword.stringValue, 'typedef')) { |  | 
| 4283       // TODO(aprelev@gmail.com): Remove this deprecation diagnostic |  | 
| 4284       // together with corresponding TODO in parser.dart. |  | 
| 4285       compiler.reportWarning(node.classKeyword, |  | 
| 4286           MessageKind.DEPRECATED_TYPEDEF_MIXIN_SYNTAX); |  | 
| 4287     } |  | 
| 4288 |  | 
| 4289     InterfaceType type = element.computeType(compiler); |  | 
| 4290     scope = new TypeDeclarationScope(scope, element); |  | 
| 4291     resolveTypeVariableBounds(node.typeParameters); |  | 
| 4292 |  | 
| 4293     // Generate anonymous mixin application elements for the |  | 
| 4294     // intermediate mixin applications (excluding the last). |  | 
| 4295     DartType supertype = resolveSupertype(element, node.superclass); |  | 
| 4296     Link<Node> link = node.mixins.nodes; |  | 
| 4297     while (!link.tail.isEmpty) { |  | 
| 4298       supertype = applyMixin(supertype, checkMixinType(link.head), link.head); |  | 
| 4299       link = link.tail; |  | 
| 4300     } |  | 
| 4301     doApplyMixinTo(element, supertype, checkMixinType(link.head)); |  | 
| 4302     return element.computeType(compiler); |  | 
| 4303   } |  | 
| 4304 |  | 
| 4305   DartType applyMixin(DartType supertype, DartType mixinType, Node node) { |  | 
| 4306     String superName = supertype.name; |  | 
| 4307     String mixinName = mixinType.name; |  | 
| 4308     MixinApplicationElementX mixinApplication = new MixinApplicationElementX( |  | 
| 4309         "${superName}+${mixinName}", |  | 
| 4310         element.compilationUnit, |  | 
| 4311         compiler.getNextFreeClassId(), |  | 
| 4312         node, |  | 
| 4313         new Modifiers.withFlags(new NodeList.empty(), Modifiers.FLAG_ABSTRACT)); |  | 
| 4314     // Create synthetic type variables for the mixin application. |  | 
| 4315     List<DartType> typeVariables = <DartType>[]; |  | 
| 4316     element.typeVariables.forEach((TypeVariableType type) { |  | 
| 4317       TypeVariableElementX typeVariableElement = new TypeVariableElementX( |  | 
| 4318           type.name, mixinApplication, type.element.node); |  | 
| 4319       TypeVariableType typeVariable = new TypeVariableType(typeVariableElement); |  | 
| 4320       typeVariables.add(typeVariable); |  | 
| 4321     }); |  | 
| 4322     // Setup bounds on the synthetic type variables. |  | 
| 4323     List<DartType> link = typeVariables; |  | 
| 4324     int index = 0; |  | 
| 4325     element.typeVariables.forEach((TypeVariableType type) { |  | 
| 4326       TypeVariableType typeVariable = typeVariables[index++]; |  | 
| 4327       TypeVariableElementX typeVariableElement = typeVariable.element; |  | 
| 4328       typeVariableElement.typeCache = typeVariable; |  | 
| 4329       typeVariableElement.boundCache = |  | 
| 4330           type.element.bound.subst(typeVariables, element.typeVariables); |  | 
| 4331     }); |  | 
| 4332     // Setup this and raw type for the mixin application. |  | 
| 4333     mixinApplication.computeThisAndRawType(compiler, typeVariables); |  | 
| 4334     // Substitute in synthetic type variables in super and mixin types. |  | 
| 4335     supertype = supertype.subst(typeVariables, element.typeVariables); |  | 
| 4336     mixinType = mixinType.subst(typeVariables, element.typeVariables); |  | 
| 4337 |  | 
| 4338     doApplyMixinTo(mixinApplication, supertype, mixinType); |  | 
| 4339     mixinApplication.resolutionState = STATE_DONE; |  | 
| 4340     mixinApplication.supertypeLoadState = STATE_DONE; |  | 
| 4341     // Replace the synthetic type variables by the original type variables in |  | 
| 4342     // the returned type (which should be the type actually extended). |  | 
| 4343     InterfaceType mixinThisType = mixinApplication.computeType(compiler); |  | 
| 4344     return mixinThisType.subst(element.typeVariables, |  | 
| 4345                                mixinThisType.typeArguments); |  | 
| 4346   } |  | 
| 4347 |  | 
| 4348   bool isDefaultConstructor(FunctionElement constructor) { |  | 
| 4349     return constructor.name == '' && |  | 
| 4350         constructor.computeSignature(compiler).parameterCount == 0; |  | 
| 4351   } |  | 
| 4352 |  | 
| 4353   FunctionElement createForwardingConstructor(ConstructorElement target, |  | 
| 4354                                               ClassElement enclosing) { |  | 
| 4355     return new SynthesizedConstructorElementX( |  | 
| 4356         target.name, target, enclosing, false); |  | 
| 4357   } |  | 
| 4358 |  | 
| 4359   void doApplyMixinTo(MixinApplicationElementX mixinApplication, |  | 
| 4360                       DartType supertype, |  | 
| 4361                       DartType mixinType) { |  | 
| 4362     Node node = mixinApplication.parseNode(compiler); |  | 
| 4363 |  | 
| 4364     if (mixinApplication.supertype != null) { |  | 
| 4365       // [supertype] is not null if there was a cycle. |  | 
| 4366       assert(invariant(node, compiler.compilationFailed)); |  | 
| 4367       supertype = mixinApplication.supertype; |  | 
| 4368       assert(invariant(node, supertype.element == compiler.objectClass)); |  | 
| 4369     } else { |  | 
| 4370       mixinApplication.supertype = supertype; |  | 
| 4371     } |  | 
| 4372 |  | 
| 4373     // Named mixin application may have an 'implements' clause. |  | 
| 4374     NamedMixinApplication namedMixinApplication = |  | 
| 4375         node.asNamedMixinApplication(); |  | 
| 4376     Link<DartType> interfaces = (namedMixinApplication != null) |  | 
| 4377         ? resolveInterfaces(namedMixinApplication.interfaces, |  | 
| 4378                             namedMixinApplication.superclass) |  | 
| 4379         : const Link<DartType>(); |  | 
| 4380 |  | 
| 4381     // The class that is the result of a mixin application implements |  | 
| 4382     // the interface of the class that was mixed in so always prepend |  | 
| 4383     // that to the interface list. |  | 
| 4384     if (mixinApplication.interfaces == null) { |  | 
| 4385       if (mixinType.isInterfaceType) { |  | 
| 4386         // Avoid malformed types in the interfaces. |  | 
| 4387         interfaces = interfaces.prepend(mixinType); |  | 
| 4388       } |  | 
| 4389       mixinApplication.interfaces = interfaces; |  | 
| 4390     } else { |  | 
| 4391       assert(invariant(mixinApplication, |  | 
| 4392           mixinApplication.hasIncompleteHierarchy)); |  | 
| 4393     } |  | 
| 4394 |  | 
| 4395     ClassElement superclass = supertype.element; |  | 
| 4396     if (mixinType.kind != TypeKind.INTERFACE) { |  | 
| 4397       mixinApplication.hasIncompleteHierarchy = true; |  | 
| 4398       mixinApplication.allSupertypesAndSelf = superclass.allSupertypesAndSelf; |  | 
| 4399       return; |  | 
| 4400     } |  | 
| 4401 |  | 
| 4402     assert(mixinApplication.mixinType == null); |  | 
| 4403     mixinApplication.mixinType = resolveMixinFor(mixinApplication, mixinType); |  | 
| 4404 |  | 
| 4405     // Create forwarding constructors for constructor defined in the superclass |  | 
| 4406     // because they are now hidden by the mixin application. |  | 
| 4407     superclass.forEachLocalMember((Element member) { |  | 
| 4408       if (!member.isGenerativeConstructor) return; |  | 
| 4409       FunctionElement forwarder = |  | 
| 4410           createForwardingConstructor(member, mixinApplication); |  | 
| 4411       if (isPrivateName(member.name) && |  | 
| 4412           mixinApplication.library != superclass.library) { |  | 
| 4413         // Do not create a forwarder to the super constructor, because the mixin |  | 
| 4414         // application is in a different library than the constructor in the |  | 
| 4415         // super class and it is not possible to call that constructor from the |  | 
| 4416         // library using the mixin application. |  | 
| 4417         return; |  | 
| 4418       } |  | 
| 4419       mixinApplication.addConstructor(forwarder); |  | 
| 4420     }); |  | 
| 4421     calculateAllSupertypes(mixinApplication); |  | 
| 4422   } |  | 
| 4423 |  | 
| 4424   InterfaceType resolveMixinFor(MixinApplicationElement mixinApplication, |  | 
| 4425                                 DartType mixinType) { |  | 
| 4426     ClassElement mixin = mixinType.element; |  | 
| 4427     mixin.ensureResolved(compiler); |  | 
| 4428 |  | 
| 4429     // Check for cycles in the mixin chain. |  | 
| 4430     ClassElement previous = mixinApplication;  // For better error messages. |  | 
| 4431     ClassElement current = mixin; |  | 
| 4432     while (current != null && current.isMixinApplication) { |  | 
| 4433       MixinApplicationElement currentMixinApplication = current; |  | 
| 4434       if (currentMixinApplication == mixinApplication) { |  | 
| 4435         compiler.reportError( |  | 
| 4436             mixinApplication, MessageKind.ILLEGAL_MIXIN_CYCLE, |  | 
| 4437             {'mixinName1': current.name, 'mixinName2': previous.name}); |  | 
| 4438         // We have found a cycle in the mixin chain. Return null as |  | 
| 4439         // the mixin for this application to avoid getting into |  | 
| 4440         // infinite recursion when traversing members. |  | 
| 4441         return null; |  | 
| 4442       } |  | 
| 4443       previous = current; |  | 
| 4444       current = currentMixinApplication.mixin; |  | 
| 4445     } |  | 
| 4446     registry.registerMixinUse(mixinApplication, mixin); |  | 
| 4447     return mixinType; |  | 
| 4448   } |  | 
| 4449 |  | 
| 4450   DartType resolveType(TypeAnnotation node) { |  | 
| 4451     return typeResolver.resolveTypeAnnotation(this, node); |  | 
| 4452   } |  | 
| 4453 |  | 
| 4454   DartType resolveSupertype(ClassElement cls, TypeAnnotation superclass) { |  | 
| 4455     DartType supertype = resolveType(superclass); |  | 
| 4456     if (supertype != null) { |  | 
| 4457       if (identical(supertype.kind, TypeKind.MALFORMED_TYPE)) { |  | 
| 4458         compiler.reportError(superclass, MessageKind.CANNOT_EXTEND_MALFORMED, |  | 
| 4459             {'className': element.name, 'malformedType': supertype}); |  | 
| 4460         return objectType; |  | 
| 4461       } else if (!identical(supertype.kind, TypeKind.INTERFACE)) { |  | 
| 4462         compiler.reportError(superclass.typeName, |  | 
| 4463             MessageKind.CLASS_NAME_EXPECTED); |  | 
| 4464         return objectType; |  | 
| 4465       } else if (isBlackListed(supertype)) { |  | 
| 4466         compiler.reportError(superclass, MessageKind.CANNOT_EXTEND, |  | 
| 4467             {'type': supertype}); |  | 
| 4468         return objectType; |  | 
| 4469       } |  | 
| 4470     } |  | 
| 4471     return supertype; |  | 
| 4472   } |  | 
| 4473 |  | 
| 4474   Link<DartType> resolveInterfaces(NodeList interfaces, Node superclass) { |  | 
| 4475     Link<DartType> result = const Link<DartType>(); |  | 
| 4476     if (interfaces == null) return result; |  | 
| 4477     for (Link<Node> link = interfaces.nodes; !link.isEmpty; link = link.tail) { |  | 
| 4478       DartType interfaceType = resolveType(link.head); |  | 
| 4479       if (interfaceType != null) { |  | 
| 4480         if (identical(interfaceType.kind, TypeKind.MALFORMED_TYPE)) { |  | 
| 4481           compiler.reportError(superclass, |  | 
| 4482               MessageKind.CANNOT_IMPLEMENT_MALFORMED, |  | 
| 4483               {'className': element.name, 'malformedType': interfaceType}); |  | 
| 4484         } else if (!identical(interfaceType.kind, TypeKind.INTERFACE)) { |  | 
| 4485           // TODO(johnniwinther): Handle dynamic. |  | 
| 4486           TypeAnnotation typeAnnotation = link.head; |  | 
| 4487           error(typeAnnotation.typeName, MessageKind.CLASS_NAME_EXPECTED); |  | 
| 4488         } else { |  | 
| 4489           if (interfaceType == element.supertype) { |  | 
| 4490             compiler.reportError( |  | 
| 4491                 superclass, |  | 
| 4492                 MessageKind.DUPLICATE_EXTENDS_IMPLEMENTS, |  | 
| 4493                 {'type': interfaceType}); |  | 
| 4494             compiler.reportError( |  | 
| 4495                 link.head, |  | 
| 4496                 MessageKind.DUPLICATE_EXTENDS_IMPLEMENTS, |  | 
| 4497                 {'type': interfaceType}); |  | 
| 4498           } |  | 
| 4499           if (result.contains(interfaceType)) { |  | 
| 4500             compiler.reportError( |  | 
| 4501                 link.head, |  | 
| 4502                 MessageKind.DUPLICATE_IMPLEMENTS, |  | 
| 4503                 {'type': interfaceType}); |  | 
| 4504           } |  | 
| 4505           result = result.prepend(interfaceType); |  | 
| 4506           if (isBlackListed(interfaceType)) { |  | 
| 4507             error(link.head, MessageKind.CANNOT_IMPLEMENT, |  | 
| 4508                   {'type': interfaceType}); |  | 
| 4509           } |  | 
| 4510         } |  | 
| 4511       } |  | 
| 4512     } |  | 
| 4513     return result; |  | 
| 4514   } |  | 
| 4515 |  | 
| 4516   /** |  | 
| 4517    * Compute the list of all supertypes. |  | 
| 4518    * |  | 
| 4519    * The elements of this list are ordered as follows: first the supertype that |  | 
| 4520    * the class extends, then the implemented interfaces, and then the supertypes |  | 
| 4521    * of these.  The class [Object] appears only once, at the end of the list. |  | 
| 4522    * |  | 
| 4523    * For example, for a class `class C extends S implements I1, I2`, we compute |  | 
| 4524    *   supertypes(C) = [S, I1, I2] ++ supertypes(S) ++ supertypes(I1) |  | 
| 4525    *                   ++ supertypes(I2), |  | 
| 4526    * where ++ stands for list concatenation. |  | 
| 4527    * |  | 
| 4528    * This order makes sure that if a class implements an interface twice with |  | 
| 4529    * different type arguments, the type used in the most specific class comes |  | 
| 4530    * first. |  | 
| 4531    */ |  | 
| 4532   void calculateAllSupertypes(BaseClassElementX cls) { |  | 
| 4533     if (cls.allSupertypesAndSelf != null) return; |  | 
| 4534     final DartType supertype = cls.supertype; |  | 
| 4535     if (supertype != null) { |  | 
| 4536       OrderedTypeSetBuilder allSupertypes = new OrderedTypeSetBuilder(cls); |  | 
| 4537       // TODO(15296): Collapse these iterations to one when the order is not |  | 
| 4538       // needed. |  | 
| 4539       allSupertypes.add(compiler, supertype); |  | 
| 4540       for (Link<DartType> interfaces = cls.interfaces; |  | 
| 4541            !interfaces.isEmpty; |  | 
| 4542            interfaces = interfaces.tail) { |  | 
| 4543         allSupertypes.add(compiler, interfaces.head); |  | 
| 4544       } |  | 
| 4545 |  | 
| 4546       addAllSupertypes(allSupertypes, supertype); |  | 
| 4547       for (Link<DartType> interfaces = cls.interfaces; |  | 
| 4548            !interfaces.isEmpty; |  | 
| 4549            interfaces = interfaces.tail) { |  | 
| 4550         addAllSupertypes(allSupertypes, interfaces.head); |  | 
| 4551       } |  | 
| 4552       allSupertypes.add(compiler, cls.computeType(compiler)); |  | 
| 4553       cls.allSupertypesAndSelf = allSupertypes.toTypeSet(); |  | 
| 4554     } else { |  | 
| 4555       assert(identical(cls, compiler.objectClass)); |  | 
| 4556       cls.allSupertypesAndSelf = |  | 
| 4557           new OrderedTypeSet.singleton(cls.computeType(compiler)); |  | 
| 4558     } |  | 
| 4559   } |  | 
| 4560 |  | 
| 4561   /** |  | 
| 4562    * Adds [type] and all supertypes of [type] to [allSupertypes] while |  | 
| 4563    * substituting type variables. |  | 
| 4564    */ |  | 
| 4565   void addAllSupertypes(OrderedTypeSetBuilder allSupertypes, |  | 
| 4566                         InterfaceType type) { |  | 
| 4567     ClassElement classElement = type.element; |  | 
| 4568     Link<DartType> supertypes = classElement.allSupertypes; |  | 
| 4569     assert(invariant(element, supertypes != null, |  | 
| 4570         message: "Supertypes not computed on $classElement " |  | 
| 4571                  "during resolution of $element")); |  | 
| 4572     while (!supertypes.isEmpty) { |  | 
| 4573       DartType supertype = supertypes.head; |  | 
| 4574       allSupertypes.add(compiler, supertype.substByContext(type)); |  | 
| 4575       supertypes = supertypes.tail; |  | 
| 4576     } |  | 
| 4577   } |  | 
| 4578 |  | 
| 4579   isBlackListed(DartType type) { |  | 
| 4580     LibraryElement lib = element.library; |  | 
| 4581     return |  | 
| 4582       !identical(lib, compiler.coreLibrary) && |  | 
| 4583       !compiler.backend.isBackendLibrary(lib) && |  | 
| 4584       (type.isDynamic || |  | 
| 4585        identical(type.element, compiler.boolClass) || |  | 
| 4586        identical(type.element, compiler.numClass) || |  | 
| 4587        identical(type.element, compiler.intClass) || |  | 
| 4588        identical(type.element, compiler.doubleClass) || |  | 
| 4589        identical(type.element, compiler.stringClass) || |  | 
| 4590        identical(type.element, compiler.nullClass)); |  | 
| 4591   } |  | 
| 4592 } |  | 
| 4593 |  | 
| 4594 class ClassSupertypeResolver extends CommonResolverVisitor { |  | 
| 4595   Scope context; |  | 
| 4596   ClassElement classElement; |  | 
| 4597 |  | 
| 4598   ClassSupertypeResolver(Compiler compiler, ClassElement cls) |  | 
| 4599     : context = Scope.buildEnclosingScope(cls), |  | 
| 4600       this.classElement = cls, |  | 
| 4601       super(compiler); |  | 
| 4602 |  | 
| 4603   void loadSupertype(ClassElement element, Node from) { |  | 
| 4604     compiler.resolver.loadSupertypes(element, from); |  | 
| 4605     element.ensureResolved(compiler); |  | 
| 4606   } |  | 
| 4607 |  | 
| 4608   void visitNodeList(NodeList node) { |  | 
| 4609     if (node != null) { |  | 
| 4610       for (Link<Node> link = node.nodes; !link.isEmpty; link = link.tail) { |  | 
| 4611         link.head.accept(this); |  | 
| 4612       } |  | 
| 4613     } |  | 
| 4614   } |  | 
| 4615 |  | 
| 4616   void visitClassNode(ClassNode node) { |  | 
| 4617     if (node.superclass == null) { |  | 
| 4618       if (!identical(classElement, compiler.objectClass)) { |  | 
| 4619         loadSupertype(compiler.objectClass, node); |  | 
| 4620       } |  | 
| 4621     } else { |  | 
| 4622       node.superclass.accept(this); |  | 
| 4623     } |  | 
| 4624     visitNodeList(node.interfaces); |  | 
| 4625   } |  | 
| 4626 |  | 
| 4627   void visitMixinApplication(MixinApplication node) { |  | 
| 4628     node.superclass.accept(this); |  | 
| 4629     visitNodeList(node.mixins); |  | 
| 4630   } |  | 
| 4631 |  | 
| 4632   void visitNamedMixinApplication(NamedMixinApplication node) { |  | 
| 4633     node.superclass.accept(this); |  | 
| 4634     visitNodeList(node.mixins); |  | 
| 4635     visitNodeList(node.interfaces); |  | 
| 4636   } |  | 
| 4637 |  | 
| 4638   void visitTypeAnnotation(TypeAnnotation node) { |  | 
| 4639     node.typeName.accept(this); |  | 
| 4640   } |  | 
| 4641 |  | 
| 4642   void visitIdentifier(Identifier node) { |  | 
| 4643     Element element = lookupInScope(compiler, node, context, node.source); |  | 
| 4644     if (element != null && element.isClass) { |  | 
| 4645       loadSupertype(element, node); |  | 
| 4646     } |  | 
| 4647   } |  | 
| 4648 |  | 
| 4649   void visitSend(Send node) { |  | 
| 4650     Identifier prefix = node.receiver.asIdentifier(); |  | 
| 4651     if (prefix == null) { |  | 
| 4652       error(node.receiver, MessageKind.NOT_A_PREFIX, {'node': node.receiver}); |  | 
| 4653       return; |  | 
| 4654     } |  | 
| 4655     Element element = lookupInScope(compiler, prefix, context, prefix.source); |  | 
| 4656     if (element == null || !identical(element.kind, ElementKind.PREFIX)) { |  | 
| 4657       error(node.receiver, MessageKind.NOT_A_PREFIX, {'node': node.receiver}); |  | 
| 4658       return; |  | 
| 4659     } |  | 
| 4660     PrefixElement prefixElement = element; |  | 
| 4661     Identifier selector = node.selector.asIdentifier(); |  | 
| 4662     var e = prefixElement.lookupLocalMember(selector.source); |  | 
| 4663     if (e == null || !e.impliesType) { |  | 
| 4664       error(node.selector, MessageKind.CANNOT_RESOLVE_TYPE, |  | 
| 4665             {'typeName': node.selector}); |  | 
| 4666       return; |  | 
| 4667     } |  | 
| 4668     loadSupertype(e, node); |  | 
| 4669   } |  | 
| 4670 } |  | 
| 4671 |  | 
| 4672 class VariableDefinitionsVisitor extends CommonResolverVisitor<Identifier> { |  | 
| 4673   VariableDefinitions definitions; |  | 
| 4674   ResolverVisitor resolver; |  | 
| 4675   VariableList variables; |  | 
| 4676 |  | 
| 4677   VariableDefinitionsVisitor(Compiler compiler, |  | 
| 4678                              this.definitions, |  | 
| 4679                              this.resolver, |  | 
| 4680                              this.variables) |  | 
| 4681       : super(compiler) { |  | 
| 4682   } |  | 
| 4683 |  | 
| 4684   ResolutionRegistry get registry => resolver.registry; |  | 
| 4685 |  | 
| 4686   Identifier visitSendSet(SendSet node) { |  | 
| 4687     assert(node.arguments.tail.isEmpty); // Sanity check |  | 
| 4688     Identifier identifier = node.selector; |  | 
| 4689     String name = identifier.source; |  | 
| 4690     VariableDefinitionScope scope = |  | 
| 4691         new VariableDefinitionScope(resolver.scope, name); |  | 
| 4692     resolver.visitIn(node.arguments.head, scope); |  | 
| 4693     if (scope.variableReferencedInInitializer) { |  | 
| 4694       compiler.reportError( |  | 
| 4695           identifier, MessageKind.REFERENCE_IN_INITIALIZATION, |  | 
| 4696           {'variableName': name}); |  | 
| 4697     } |  | 
| 4698     return identifier; |  | 
| 4699   } |  | 
| 4700 |  | 
| 4701   Identifier visitIdentifier(Identifier node) { |  | 
| 4702     // The variable is initialized to null. |  | 
| 4703     registry.registerInstantiatedClass(compiler.nullClass); |  | 
| 4704     if (definitions.modifiers.isConst) { |  | 
| 4705       compiler.reportError(node, MessageKind.CONST_WITHOUT_INITIALIZER); |  | 
| 4706     } |  | 
| 4707     if (definitions.modifiers.isFinal && |  | 
| 4708         !resolver.allowFinalWithoutInitializer) { |  | 
| 4709       compiler.reportError(node, MessageKind.FINAL_WITHOUT_INITIALIZER); |  | 
| 4710     } |  | 
| 4711     return node; |  | 
| 4712   } |  | 
| 4713 |  | 
| 4714   visitNodeList(NodeList node) { |  | 
| 4715     for (Link<Node> link = node.nodes; !link.isEmpty; link = link.tail) { |  | 
| 4716       Identifier name = visit(link.head); |  | 
| 4717       LocalVariableElement element = new LocalVariableElementX( |  | 
| 4718           name.source, resolver.enclosingElement, |  | 
| 4719           variables, name.token); |  | 
| 4720       resolver.defineLocalVariable(link.head, element); |  | 
| 4721       resolver.addToScope(element); |  | 
| 4722       if (definitions.modifiers.isConst) { |  | 
| 4723         compiler.enqueuer.resolution.addDeferredAction(element, () { |  | 
| 4724           compiler.resolver.constantCompiler.compileConstant(element); |  | 
| 4725         }); |  | 
| 4726       } |  | 
| 4727     } |  | 
| 4728   } |  | 
| 4729 } |  | 
| 4730 |  | 
| 4731 class ConstructorResolver extends CommonResolverVisitor<Element> { |  | 
| 4732   final ResolverVisitor resolver; |  | 
| 4733   bool inConstContext; |  | 
| 4734   DartType type; |  | 
| 4735 |  | 
| 4736   ConstructorResolver(Compiler compiler, this.resolver, |  | 
| 4737                       {bool this.inConstContext: false}) |  | 
| 4738       : super(compiler); |  | 
| 4739 |  | 
| 4740   ResolutionRegistry get registry => resolver.registry; |  | 
| 4741 |  | 
| 4742   visitNode(Node node) { |  | 
| 4743     throw 'not supported'; |  | 
| 4744   } |  | 
| 4745 |  | 
| 4746   failOrReturnErroneousElement(Element enclosing, Node diagnosticNode, |  | 
| 4747                                String targetName, MessageKind kind, |  | 
| 4748                                Map arguments) { |  | 
| 4749     if (kind == MessageKind.CANNOT_FIND_CONSTRUCTOR) { |  | 
| 4750       registry.registerThrowNoSuchMethod(); |  | 
| 4751     } else { |  | 
| 4752       registry.registerThrowRuntimeError(); |  | 
| 4753     } |  | 
| 4754     if (inConstContext) { |  | 
| 4755       compiler.reportError(diagnosticNode, kind, arguments); |  | 
| 4756     } else { |  | 
| 4757       compiler.reportWarning(diagnosticNode, kind, arguments); |  | 
| 4758     } |  | 
| 4759     return new ErroneousElementX(kind, arguments, targetName, enclosing); |  | 
| 4760   } |  | 
| 4761 |  | 
| 4762   Selector createConstructorSelector(String constructorName) { |  | 
| 4763     return constructorName == '' |  | 
| 4764         ? new Selector.callDefaultConstructor( |  | 
| 4765             resolver.enclosingElement.library) |  | 
| 4766         : new Selector.callConstructor( |  | 
| 4767             constructorName, |  | 
| 4768             resolver.enclosingElement.library); |  | 
| 4769   } |  | 
| 4770 |  | 
| 4771   FunctionElement resolveConstructor(ClassElement cls, |  | 
| 4772                                      Node diagnosticNode, |  | 
| 4773                                      String constructorName) { |  | 
| 4774     cls.ensureResolved(compiler); |  | 
| 4775     Selector selector = createConstructorSelector(constructorName); |  | 
| 4776     Element result = cls.lookupConstructor(selector); |  | 
| 4777     if (result == null) { |  | 
| 4778       String fullConstructorName = Elements.constructorNameForDiagnostics( |  | 
| 4779               cls.name, |  | 
| 4780               constructorName); |  | 
| 4781       return failOrReturnErroneousElement( |  | 
| 4782           cls, |  | 
| 4783           diagnosticNode, |  | 
| 4784           fullConstructorName, |  | 
| 4785           MessageKind.CANNOT_FIND_CONSTRUCTOR, |  | 
| 4786           {'constructorName': fullConstructorName}); |  | 
| 4787     } else if (inConstContext && !result.isConst) { |  | 
| 4788       error(diagnosticNode, MessageKind.CONSTRUCTOR_IS_NOT_CONST); |  | 
| 4789     } |  | 
| 4790     return result; |  | 
| 4791   } |  | 
| 4792 |  | 
| 4793   Element visitNewExpression(NewExpression node) { |  | 
| 4794     inConstContext = node.isConst; |  | 
| 4795     Node selector = node.send.selector; |  | 
| 4796     Element element = visit(selector); |  | 
| 4797     assert(invariant(selector, element != null, |  | 
| 4798         message: 'No element return for $selector.')); |  | 
| 4799     return finishConstructorReference(element, node.send.selector, node); |  | 
| 4800   } |  | 
| 4801 |  | 
| 4802   /// Finishes resolution of a constructor reference and records the |  | 
| 4803   /// type of the constructed instance on [expression]. |  | 
| 4804   FunctionElement finishConstructorReference(Element element, |  | 
| 4805                                              Node diagnosticNode, |  | 
| 4806                                              Node expression) { |  | 
| 4807     assert(invariant(diagnosticNode, element != null, |  | 
| 4808         message: 'No element return for $diagnosticNode.')); |  | 
| 4809     // Find the unnamed constructor if the reference resolved to a |  | 
| 4810     // class. |  | 
| 4811     if (!Elements.isUnresolved(element) && !element.isConstructor) { |  | 
| 4812       if (element.isClass) { |  | 
| 4813         ClassElement cls = element; |  | 
| 4814         cls.ensureResolved(compiler); |  | 
| 4815         // The unnamed constructor may not exist, so [e] may become unresolved. |  | 
| 4816         element = resolveConstructor(cls, diagnosticNode, ''); |  | 
| 4817       } else { |  | 
| 4818         element = failOrReturnErroneousElement( |  | 
| 4819             element, diagnosticNode, element.name, MessageKind.NOT_A_TYPE, |  | 
| 4820             {'node': diagnosticNode}); |  | 
| 4821       } |  | 
| 4822     } |  | 
| 4823     if (type == null) { |  | 
| 4824       if (Elements.isUnresolved(element)) { |  | 
| 4825         type = const DynamicType(); |  | 
| 4826       } else { |  | 
| 4827         type = element.enclosingClass.rawType; |  | 
| 4828       } |  | 
| 4829     } |  | 
| 4830     resolver.registry.setType(expression, type); |  | 
| 4831     return element; |  | 
| 4832   } |  | 
| 4833 |  | 
| 4834   Element visitTypeAnnotation(TypeAnnotation node) { |  | 
| 4835     assert(invariant(node, type == null)); |  | 
| 4836     // This is not really resolving a type-annotation, but the name of the |  | 
| 4837     // constructor. Therefore we allow deferred types. |  | 
| 4838     type = resolver.resolveTypeAnnotation(node, |  | 
| 4839                                           malformedIsError: inConstContext, |  | 
| 4840                                           deferredIsMalformed: false); |  | 
| 4841     registry.registerRequiredType(type, resolver.enclosingElement); |  | 
| 4842     return type.element; |  | 
| 4843   } |  | 
| 4844 |  | 
| 4845   Element visitSend(Send node) { |  | 
| 4846     Element element = visit(node.receiver); |  | 
| 4847     assert(invariant(node.receiver, element != null, |  | 
| 4848         message: 'No element return for $node.receiver.')); |  | 
| 4849     if (Elements.isUnresolved(element)) return element; |  | 
| 4850     Identifier name = node.selector.asIdentifier(); |  | 
| 4851     if (name == null) internalError(node.selector, 'unexpected node'); |  | 
| 4852 |  | 
| 4853     if (element.isClass) { |  | 
| 4854       ClassElement cls = element; |  | 
| 4855       cls.ensureResolved(compiler); |  | 
| 4856       return resolveConstructor(cls, name, name.source); |  | 
| 4857     } else if (element.isPrefix) { |  | 
| 4858       PrefixElement prefix = element; |  | 
| 4859       element = prefix.lookupLocalMember(name.source); |  | 
| 4860       element = Elements.unwrap(element, compiler, node); |  | 
| 4861       if (element == null) { |  | 
| 4862         return failOrReturnErroneousElement( |  | 
| 4863             resolver.enclosingElement, name, |  | 
| 4864             name.source, |  | 
| 4865             MessageKind.CANNOT_RESOLVE, |  | 
| 4866             {'name': name}); |  | 
| 4867       } else if (!element.isClass) { |  | 
| 4868         error(node, MessageKind.NOT_A_TYPE, {'node': name}); |  | 
| 4869       } |  | 
| 4870     } else { |  | 
| 4871       internalError(node.receiver, 'unexpected element $element'); |  | 
| 4872     } |  | 
| 4873     return element; |  | 
| 4874   } |  | 
| 4875 |  | 
| 4876   Element visitIdentifier(Identifier node) { |  | 
| 4877     String name = node.source; |  | 
| 4878     Element element = resolver.reportLookupErrorIfAny( |  | 
| 4879         lookupInScope(compiler, node, resolver.scope, name), node, name); |  | 
| 4880     registry.useElement(node, element); |  | 
| 4881     // TODO(johnniwinther): Change errors to warnings, cf. 11.11.1. |  | 
| 4882     if (element == null) { |  | 
| 4883       return failOrReturnErroneousElement(resolver.enclosingElement, node, name, |  | 
| 4884                                           MessageKind.CANNOT_RESOLVE, |  | 
| 4885                                           {'name': name}); |  | 
| 4886     } else if (element.isErroneous) { |  | 
| 4887       return element; |  | 
| 4888     } else if (element.isTypedef) { |  | 
| 4889       error(node, MessageKind.CANNOT_INSTANTIATE_TYPEDEF, |  | 
| 4890             {'typedefName': name}); |  | 
| 4891     } else if (element.isTypeVariable) { |  | 
| 4892       error(node, MessageKind.CANNOT_INSTANTIATE_TYPE_VARIABLE, |  | 
| 4893             {'typeVariableName': name}); |  | 
| 4894     } else if (!element.isClass && !element.isPrefix) { |  | 
| 4895       error(node, MessageKind.NOT_A_TYPE, {'node': name}); |  | 
| 4896     } |  | 
| 4897     return element; |  | 
| 4898   } |  | 
| 4899 |  | 
| 4900   /// Assumed to be called by [resolveRedirectingFactory]. |  | 
| 4901   Element visitRedirectingFactoryBody(RedirectingFactoryBody node) { |  | 
| 4902     Node constructorReference = node.constructorReference; |  | 
| 4903     return finishConstructorReference(visit(constructorReference), |  | 
| 4904         constructorReference, node); |  | 
| 4905   } |  | 
| 4906 } |  | 
| 4907 |  | 
| 4908 /// Looks up [name] in [scope] and unwraps the result. |  | 
| 4909 Element lookupInScope(Compiler compiler, Node node, |  | 
| 4910                       Scope scope, String name) { |  | 
| 4911   return Elements.unwrap(scope.lookup(name), compiler, node); |  | 
| 4912 } |  | 
| 4913 |  | 
| 4914 TreeElements _ensureTreeElements(AnalyzableElementX element) { |  | 
| 4915   if (element._treeElements == null) { |  | 
| 4916     element._treeElements = new TreeElementMapping(element); |  | 
| 4917   } |  | 
| 4918   return element._treeElements; |  | 
| 4919 } |  | 
| 4920 |  | 
| 4921 abstract class AnalyzableElementX implements AnalyzableElement { |  | 
| 4922   TreeElements _treeElements; |  | 
| 4923 |  | 
| 4924   bool get hasTreeElements => _treeElements != null; |  | 
| 4925 |  | 
| 4926   TreeElements get treeElements { |  | 
| 4927     assert(invariant(this, _treeElements !=null, |  | 
| 4928         message: "TreeElements have not been computed for $this.")); |  | 
| 4929     return _treeElements; |  | 
| 4930   } |  | 
| 4931 |  | 
| 4932   void reuseElement() { |  | 
| 4933     _treeElements = null; |  | 
| 4934   } |  | 
| 4935 } |  | 
| 4936 |  | 
| 4937 /// The result of resolving a node. |  | 
| 4938 abstract class ResolutionResult { |  | 
| 4939   Element get element; |  | 
| 4940 } |  | 
| 4941 |  | 
| 4942 /// The result for the resolution of a node that points to an [Element]. |  | 
| 4943 class ElementResult implements ResolutionResult { |  | 
| 4944   final Element element; |  | 
| 4945 |  | 
| 4946   // TODO(johnniwinther): Remove this factory constructor when `null` is never |  | 
| 4947   // passed as an element result. |  | 
| 4948   factory ElementResult(Element element) { |  | 
| 4949     return element != null ? new ElementResult.internal(element) : null; |  | 
| 4950   } |  | 
| 4951 |  | 
| 4952   ElementResult.internal(this.element); |  | 
| 4953 |  | 
| 4954   String toString() => 'ElementResult($element)'; |  | 
| 4955 } |  | 
| 4956 |  | 
| 4957 /// The result for the resolution of a node that points to an [DartType]. |  | 
| 4958 class TypeResult implements ResolutionResult { |  | 
| 4959   final DartType type; |  | 
| 4960 |  | 
| 4961   TypeResult(this.type) { |  | 
| 4962     assert(type != null); |  | 
| 4963   } |  | 
| 4964 |  | 
| 4965   Element get element => type.element; |  | 
| 4966 |  | 
| 4967   String toString() => 'TypeResult($type)'; |  | 
| 4968 } |  | 
| 4969 |  | 
| 4970 /// The result for the resolution of the `assert` method. |  | 
| 4971 class AssertResult implements ResolutionResult { |  | 
| 4972   const AssertResult(); |  | 
| 4973 |  | 
| 4974   Element get element => null; |  | 
| 4975 |  | 
| 4976   String toString() => 'AssertResult()'; |  | 
| 4977 } |  | 
| OLD | NEW | 
|---|