| 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 abstract class TreeElements { | |
| 6 Element operator[](Node node); | |
| 7 Selector getSelector(Send send); | |
| 8 DartType getType(TypeAnnotation annotation); | |
| 9 bool isParameterChecked(Element element); | |
| 10 } | |
| 11 | |
| 12 class TreeElementMapping implements TreeElements { | |
| 13 final Element currentElement; | |
| 14 final Map<Node, Element> map; | |
| 15 final Map<Node, Selector> selectors; | |
| 16 final Map<TypeAnnotation, DartType> types; | |
| 17 final Set<Element> checkedParameters; | |
| 18 | |
| 19 TreeElementMapping([Element this.currentElement]) | |
| 20 : map = new LinkedHashMap<Node, Element>(), | |
| 21 selectors = new LinkedHashMap<Node, Selector>(), | |
| 22 types = new LinkedHashMap<TypeAnnotation, DartType>(), | |
| 23 checkedParameters = new Set<Element>(); | |
| 24 | |
| 25 operator []=(Node node, Element element) { | |
| 26 assert(invariant(node, () { | |
| 27 if (node is FunctionExpression) { | |
| 28 return !node.modifiers.isExternal(); | |
| 29 } | |
| 30 return true; | |
| 31 })); | |
| 32 // TODO(johnniwinther): Simplify this invariant to use only declarations in | |
| 33 // [TreeElements]. | |
| 34 assert(invariant(node, () { | |
| 35 if (!element.isErroneous() && currentElement != null && element.isPatch) { | |
| 36 return currentElement.getImplementationLibrary().isPatch; | |
| 37 } | |
| 38 return true; | |
| 39 })); | |
| 40 | |
| 41 map[node] = element; | |
| 42 } | |
| 43 operator [](Node node) => map[node]; | |
| 44 void remove(Node node) { map.remove(node); } | |
| 45 | |
| 46 void setType(TypeAnnotation annotation, DartType type) { | |
| 47 types[annotation] = type; | |
| 48 } | |
| 49 | |
| 50 DartType getType(TypeAnnotation annotation) => types[annotation]; | |
| 51 | |
| 52 void setSelector(Node node, Selector selector) { | |
| 53 selectors[node] = selector; | |
| 54 } | |
| 55 | |
| 56 Selector getSelector(Node node) => selectors[node]; | |
| 57 | |
| 58 bool isParameterChecked(Element element) { | |
| 59 return checkedParameters.contains(element); | |
| 60 } | |
| 61 } | |
| 62 | |
| 63 class ResolverTask extends CompilerTask { | |
| 64 ResolverTask(Compiler compiler) : super(compiler); | |
| 65 | |
| 66 String get name => 'Resolver'; | |
| 67 | |
| 68 TreeElements resolve(Element element) { | |
| 69 return measure(() { | |
| 70 ElementKind kind = element.kind; | |
| 71 if (identical(kind, ElementKind.GENERATIVE_CONSTRUCTOR) || | |
| 72 identical(kind, ElementKind.FUNCTION) || | |
| 73 identical(kind, ElementKind.GETTER) || | |
| 74 identical(kind, ElementKind.SETTER)) { | |
| 75 return resolveMethodElement(element); | |
| 76 } | |
| 77 | |
| 78 if (identical(kind, ElementKind.FIELD)) return resolveField(element); | |
| 79 | |
| 80 if (identical(kind, ElementKind.PARAMETER) || | |
| 81 identical(kind, ElementKind.FIELD_PARAMETER)) { | |
| 82 return resolveParameter(element); | |
| 83 } | |
| 84 | |
| 85 compiler.unimplemented("resolve($element)", | |
| 86 node: element.parseNode(compiler)); | |
| 87 }); | |
| 88 } | |
| 89 | |
| 90 bool isNamedConstructor(Send node) => node.receiver != null; | |
| 91 | |
| 92 SourceString getConstructorName(Send node) { | |
| 93 return node.selector.asIdentifier().source; | |
| 94 } | |
| 95 | |
| 96 String constructorNameForDiagnostics(SourceString className, | |
| 97 SourceString constructorName) { | |
| 98 String classNameString = className.slowToString(); | |
| 99 String constructorNameString = constructorName.slowToString(); | |
| 100 return (identical(constructorName, const SourceString(''))) | |
| 101 ? classNameString | |
| 102 : "$classNameString.$constructorNameString"; | |
| 103 } | |
| 104 | |
| 105 FunctionElement resolveConstructorRedirection(InitializerResolver resolver, | |
| 106 FunctionElement constructor) { | |
| 107 if (constructor.isPatched) { | |
| 108 checkMatchingPatchSignatures(constructor, constructor.patch); | |
| 109 constructor = constructor.patch; | |
| 110 } | |
| 111 FunctionExpression node = constructor.parseNode(compiler); | |
| 112 | |
| 113 // A synthetic constructor does not have a node. | |
| 114 if (node == null) return null; | |
| 115 if (node.initializers == null) return null; | |
| 116 Link<Node> initializers = node.initializers.nodes; | |
| 117 if (!initializers.isEmpty() && | |
| 118 Initializers.isConstructorRedirect(initializers.head)) { | |
| 119 final ClassElement classElement = constructor.getEnclosingClass(); | |
| 120 Selector selector; | |
| 121 if (isNamedConstructor(initializers.head)) { | |
| 122 SourceString constructorName = getConstructorName(initializers.head); | |
| 123 selector = new Selector.callConstructor( | |
| 124 constructorName, | |
| 125 resolver.visitor.enclosingElement.getLibrary()); | |
| 126 } else { | |
| 127 selector = new Selector.callDefaultConstructor( | |
| 128 resolver.visitor.enclosingElement.getLibrary()); | |
| 129 } | |
| 130 return classElement.lookupConstructor(selector); | |
| 131 } | |
| 132 return null; | |
| 133 } | |
| 134 | |
| 135 void resolveRedirectingConstructor(InitializerResolver resolver, | |
| 136 Node node, | |
| 137 FunctionElement constructor, | |
| 138 FunctionElement redirection) { | |
| 139 Set<FunctionElement> seen = new Set<FunctionElement>(); | |
| 140 seen.add(constructor); | |
| 141 while (redirection != null) { | |
| 142 if (seen.contains(redirection)) { | |
| 143 resolver.visitor.error(node, MessageKind.REDIRECTING_CONSTRUCTOR_CYCLE); | |
| 144 return; | |
| 145 } | |
| 146 seen.add(redirection); | |
| 147 redirection = resolveConstructorRedirection(resolver, redirection); | |
| 148 } | |
| 149 } | |
| 150 | |
| 151 void checkMatchingPatchParameters(FunctionElement origin, | |
| 152 Link<Element> originParameters, | |
| 153 Link<Element> patchParameters) { | |
| 154 while (!originParameters.isEmpty()) { | |
| 155 Element originParameter = originParameters.head; | |
| 156 Element patchParameter = patchParameters.head; | |
| 157 // Hack: Use unparser to test parameter equality. This only works because | |
| 158 // we are restricting patch uses and the approach cannot be used | |
| 159 // elsewhere. | |
| 160 String originParameterText = | |
| 161 originParameter.parseNode(compiler).toString(); | |
| 162 String patchParameterText = | |
| 163 patchParameter.parseNode(compiler).toString(); | |
| 164 if (originParameterText != patchParameterText) { | |
| 165 error(originParameter.parseNode(compiler), | |
| 166 MessageKind.PATCH_PARAMETER_MISMATCH, | |
| 167 [origin.name, originParameterText, patchParameterText]); | |
| 168 } | |
| 169 | |
| 170 originParameters = originParameters.tail; | |
| 171 patchParameters = patchParameters.tail; | |
| 172 } | |
| 173 } | |
| 174 | |
| 175 void checkMatchingPatchSignatures(FunctionElement origin, | |
| 176 FunctionElement patch) { | |
| 177 // TODO(johnniwinther): Show both origin and patch locations on errors. | |
| 178 FunctionExpression originTree = compiler.withCurrentElement(origin, () { | |
| 179 return origin.parseNode(compiler); | |
| 180 }); | |
| 181 FunctionSignature originSignature = compiler.withCurrentElement(origin, () { | |
| 182 return origin.computeSignature(compiler); | |
| 183 }); | |
| 184 FunctionExpression patchTree = compiler.withCurrentElement(patch, () { | |
| 185 return patch.parseNode(compiler); | |
| 186 }); | |
| 187 FunctionSignature patchSignature = compiler.withCurrentElement(patch, () { | |
| 188 return patch.computeSignature(compiler); | |
| 189 }); | |
| 190 | |
| 191 if (originSignature.returnType != patchSignature.returnType) { | |
| 192 compiler.withCurrentElement(patch, () { | |
| 193 Node errorNode = | |
| 194 patchTree.returnType != null ? patchTree.returnType : patchTree; | |
| 195 error(errorNode, MessageKind.PATCH_RETURN_TYPE_MISMATCH, [origin.name, | |
| 196 originSignature.returnType, patchSignature.returnType]); | |
| 197 }); | |
| 198 } | |
| 199 if (originSignature.requiredParameterCount != | |
| 200 patchSignature.requiredParameterCount) { | |
| 201 compiler.withCurrentElement(patch, () { | |
| 202 error(patchTree, | |
| 203 MessageKind.PATCH_REQUIRED_PARAMETER_COUNT_MISMATCH, | |
| 204 [origin.name, originSignature.requiredParameterCount, | |
| 205 patchSignature.requiredParameterCount]); | |
| 206 }); | |
| 207 } else { | |
| 208 checkMatchingPatchParameters(origin, | |
| 209 originSignature.requiredParameters, | |
| 210 patchSignature.requiredParameters); | |
| 211 } | |
| 212 if (originSignature.optionalParameterCount != 0 && | |
| 213 patchSignature.optionalParameterCount != 0) { | |
| 214 if (originSignature.optionalParametersAreNamed != | |
| 215 patchSignature.optionalParametersAreNamed) { | |
| 216 compiler.withCurrentElement(patch, () { | |
| 217 error(patchTree, | |
| 218 MessageKind.PATCH_OPTIONAL_PARAMETER_NAMED_MISMATCH, | |
| 219 [origin.name]); | |
| 220 }); | |
| 221 } | |
| 222 } | |
| 223 if (originSignature.optionalParameterCount != | |
| 224 patchSignature.optionalParameterCount) { | |
| 225 compiler.withCurrentElement(patch, () { | |
| 226 error(patchTree, | |
| 227 MessageKind.PATCH_OPTIONAL_PARAMETER_COUNT_MISMATCH, | |
| 228 [origin.name, originSignature.optionalParameterCount, | |
| 229 patchSignature.optionalParameterCount]); | |
| 230 }); | |
| 231 } else { | |
| 232 checkMatchingPatchParameters(origin, | |
| 233 originSignature.optionalParameters, | |
| 234 patchSignature.optionalParameters); | |
| 235 } | |
| 236 } | |
| 237 | |
| 238 TreeElements resolveMethodElement(FunctionElement element) { | |
| 239 assert(invariant(element, element.isDeclaration)); | |
| 240 return compiler.withCurrentElement(element, () { | |
| 241 bool isConstructor = | |
| 242 identical(element.kind, ElementKind.GENERATIVE_CONSTRUCTOR); | |
| 243 TreeElements elements = | |
| 244 compiler.enqueuer.resolution.getCachedElements(element); | |
| 245 if (elements != null) { | |
| 246 assert(isConstructor); | |
| 247 return elements; | |
| 248 } | |
| 249 if (element.isPatched) { | |
| 250 checkMatchingPatchSignatures(element, element.patch); | |
| 251 element = element.patch; | |
| 252 } | |
| 253 return compiler.withCurrentElement(element, () { | |
| 254 FunctionExpression tree = element.parseNode(compiler); | |
| 255 if (isConstructor) { | |
| 256 if (tree.returnType != null) { | |
| 257 error(tree, MessageKind.CONSTRUCTOR_WITH_RETURN_TYPE); | |
| 258 } | |
| 259 resolveConstructorImplementation(element, tree); | |
| 260 } | |
| 261 ResolverVisitor visitor = new ResolverVisitor(compiler, element); | |
| 262 visitor.useElement(tree, element); | |
| 263 visitor.setupFunction(tree, element); | |
| 264 | |
| 265 if (isConstructor) { | |
| 266 // Even if there is no initializer list we still have to do the | |
| 267 // resolution in case there is an implicit super constructor call. | |
| 268 InitializerResolver resolver = new InitializerResolver(visitor); | |
| 269 FunctionElement redirection = | |
| 270 resolver.resolveInitializers(element, tree); | |
| 271 if (redirection != null) { | |
| 272 resolveRedirectingConstructor(resolver, tree, element, redirection); | |
| 273 } | |
| 274 } else if (tree.initializers != null) { | |
| 275 error(tree, MessageKind.FUNCTION_WITH_INITIALIZER); | |
| 276 } | |
| 277 visitBody(visitor, tree.body); | |
| 278 | |
| 279 return visitor.mapping; | |
| 280 }); | |
| 281 }); | |
| 282 } | |
| 283 | |
| 284 void visitBody(ResolverVisitor visitor, Statement body) { | |
| 285 visitor.visit(body); | |
| 286 } | |
| 287 | |
| 288 void resolveConstructorImplementation(FunctionElement constructor, | |
| 289 FunctionExpression node) { | |
| 290 if (!identical(constructor.defaultImplementation, constructor)) return; | |
| 291 ClassElement intrface = constructor.getEnclosingClass(); | |
| 292 if (!intrface.isInterface()) return; | |
| 293 DartType defaultType = intrface.defaultClass; | |
| 294 if (defaultType == null) { | |
| 295 error(node, MessageKind.NO_DEFAULT_CLASS, [intrface.name]); | |
| 296 } | |
| 297 ClassElement defaultClass = defaultType.element; | |
| 298 defaultClass.ensureResolved(compiler); | |
| 299 assert(defaultClass.resolutionState == STATE_DONE); | |
| 300 assert(defaultClass.supertypeLoadState == STATE_DONE); | |
| 301 if (defaultClass.isInterface()) { | |
| 302 error(node, MessageKind.CANNOT_INSTANTIATE_INTERFACE, | |
| 303 [defaultClass.name]); | |
| 304 } | |
| 305 // We have now established the following: | |
| 306 // [intrface] is an interface, let's say "MyInterface". | |
| 307 // [defaultClass] is a class, let's say "MyClass". | |
| 308 | |
| 309 Selector selector; | |
| 310 // If the default class implements the interface then we must use the | |
| 311 // default class' name. Otherwise we look for a factory with the name | |
| 312 // of the interface. | |
| 313 if (defaultClass.implementsInterface(intrface)) { | |
| 314 var constructorNameString = constructor.name.slowToString(); | |
| 315 // Create selector based on constructor.name but where interface | |
| 316 // is replaced with default class name. | |
| 317 // TODO(ahe): Don't use string manipulations here. | |
| 318 int classNameSeparatorIndex = constructorNameString.indexOf('\$'); | |
| 319 if (classNameSeparatorIndex < 0) { | |
| 320 selector = new Selector.callDefaultConstructor( | |
| 321 defaultClass.getLibrary()); | |
| 322 } else { | |
| 323 selector = new Selector.callConstructor( | |
| 324 new SourceString( | |
| 325 constructorNameString.substring(classNameSeparatorIndex + 1)), | |
| 326 defaultClass.getLibrary()); | |
| 327 } | |
| 328 constructor.defaultImplementation = | |
| 329 defaultClass.lookupConstructor(selector); | |
| 330 } else { | |
| 331 selector = | |
| 332 new Selector.callConstructor(constructor.name, | |
| 333 defaultClass.getLibrary()); | |
| 334 constructor.defaultImplementation = | |
| 335 defaultClass.lookupFactoryConstructor(selector); | |
| 336 } | |
| 337 if (constructor.defaultImplementation == null) { | |
| 338 // We failed to find a constructor named either | |
| 339 // "MyInterface.name" or "MyClass.name". | |
| 340 // TODO(aprelev@gmail.com): Use constructorNameForDiagnostics in | |
| 341 // the error message below. | |
| 342 error(node, | |
| 343 MessageKind.CANNOT_FIND_CONSTRUCTOR2, | |
| 344 [selector.name, defaultClass.name]); | |
| 345 } | |
| 346 } | |
| 347 | |
| 348 TreeElements resolveField(VariableElement element) { | |
| 349 Node tree = element.parseNode(compiler); | |
| 350 if(element.modifiers.isStatic() && element.variables.isTopLevel()) { | |
| 351 error(element.modifiers.getStatic(), MessageKind.TOP_LEVEL_VARIABLE_DECLAR
ED_STATIC); | |
| 352 } | |
| 353 ResolverVisitor visitor = new ResolverVisitor(compiler, element); | |
| 354 initializerDo(tree, visitor.visit); | |
| 355 return visitor.mapping; | |
| 356 } | |
| 357 | |
| 358 TreeElements resolveParameter(Element element) { | |
| 359 Node tree = element.parseNode(compiler); | |
| 360 ResolverVisitor visitor = | |
| 361 new ResolverVisitor(compiler, element.enclosingElement); | |
| 362 initializerDo(tree, visitor.visit); | |
| 363 return visitor.mapping; | |
| 364 } | |
| 365 | |
| 366 DartType resolveTypeAnnotation(Element element, TypeAnnotation annotation) { | |
| 367 DartType type = resolveReturnType(element, annotation); | |
| 368 if (type == compiler.types.voidType) { | |
| 369 error(annotation, MessageKind.VOID_NOT_ALLOWED); | |
| 370 } | |
| 371 return type; | |
| 372 } | |
| 373 | |
| 374 DartType resolveReturnType(Element element, TypeAnnotation annotation) { | |
| 375 if (annotation == null) return compiler.types.dynamicType; | |
| 376 ResolverVisitor visitor = new ResolverVisitor(compiler, element); | |
| 377 DartType result = visitor.resolveTypeAnnotation(annotation); | |
| 378 if (result == null) { | |
| 379 // TODO(karklose): warning. | |
| 380 return compiler.types.dynamicType; | |
| 381 } | |
| 382 return result; | |
| 383 } | |
| 384 | |
| 385 /** | |
| 386 * Load and resolve the supertypes of [cls]. | |
| 387 * | |
| 388 * Warning: do not call this method directly. It should only be | |
| 389 * called by [resolveClass] and [ClassSupertypeResolver]. | |
| 390 */ | |
| 391 void loadSupertypes(ClassElement cls, Node from) { | |
| 392 compiler.withCurrentElement(cls, () => measure(() { | |
| 393 if (cls.supertypeLoadState == STATE_DONE) return; | |
| 394 if (cls.supertypeLoadState == STATE_STARTED) { | |
| 395 compiler.reportMessage( | |
| 396 compiler.spanFromNode(from), | |
| 397 MessageKind.CYCLIC_CLASS_HIERARCHY.error([cls.name]), | |
| 398 api.Diagnostic.ERROR); | |
| 399 cls.supertypeLoadState = STATE_DONE; | |
| 400 cls.allSupertypes = const Link<DartType>().prepend( | |
| 401 compiler.objectClass.computeType(compiler)); | |
| 402 // TODO(ahe): We should also set cls.supertype here to avoid | |
| 403 // creating a malformed class hierarchy. | |
| 404 return; | |
| 405 } | |
| 406 cls.supertypeLoadState = STATE_STARTED; | |
| 407 compiler.withCurrentElement(cls, () { | |
| 408 // TODO(ahe): Cache the node in cls. | |
| 409 cls.parseNode(compiler).accept(new ClassSupertypeResolver(compiler, | |
| 410 cls)); | |
| 411 if (cls.supertypeLoadState != STATE_DONE) { | |
| 412 cls.supertypeLoadState = STATE_DONE; | |
| 413 } | |
| 414 }); | |
| 415 })); | |
| 416 } | |
| 417 | |
| 418 /** | |
| 419 * Resolve the class [element]. | |
| 420 * | |
| 421 * Before calling this method, [element] was constructed by the | |
| 422 * scanner and most fields are null or empty. This method fills in | |
| 423 * these fields and also ensure that the supertypes of [element] are | |
| 424 * resolved. | |
| 425 * | |
| 426 * Warning: Do not call this method directly. Instead use | |
| 427 * [:element.ensureResolved(compiler):]. | |
| 428 */ | |
| 429 void resolveClass(ClassElement element) { | |
| 430 if (!element.isPatch) { | |
| 431 compiler.withCurrentElement(element, () => measure(() { | |
| 432 assert(element.resolutionState == STATE_NOT_STARTED); | |
| 433 element.resolutionState = STATE_STARTED; | |
| 434 ClassNode tree = element.parseNode(compiler); | |
| 435 loadSupertypes(element, tree); | |
| 436 | |
| 437 ClassResolverVisitor visitor = | |
| 438 new ClassResolverVisitor(compiler, element); | |
| 439 visitor.visit(tree); | |
| 440 element.resolutionState = STATE_DONE; | |
| 441 })); | |
| 442 if (element.isPatched) { | |
| 443 // Ensure handling patch after origin. | |
| 444 element.patch.ensureResolved(compiler); | |
| 445 } | |
| 446 } else { // Handle patch classes: | |
| 447 element.resolutionState = STATE_STARTED; | |
| 448 // Ensure handling origin before patch. | |
| 449 element.origin.ensureResolved(compiler); | |
| 450 // Ensure that the type is computed. | |
| 451 element.computeType(compiler); | |
| 452 // Copy class hiearchy from origin. | |
| 453 element.supertype = element.origin.supertype; | |
| 454 element.defaultClass = element.origin.defaultClass; | |
| 455 element.interfaces = element.origin.interfaces; | |
| 456 element.allSupertypes = element.origin.allSupertypes; | |
| 457 // Stepwise assignment to ensure invariant. | |
| 458 element.supertypeLoadState = STATE_STARTED; | |
| 459 element.supertypeLoadState = STATE_DONE; | |
| 460 element.resolutionState = STATE_DONE; | |
| 461 // TODO(johnniwinther): Check matching type variables and | |
| 462 // empty extends/implements clauses. | |
| 463 } | |
| 464 } | |
| 465 | |
| 466 void checkMembers(ClassElement cls) { | |
| 467 assert(invariant(cls, cls.isDeclaration)); | |
| 468 if (cls.isObject(compiler)) return; | |
| 469 // TODO(johnniwinther): Should this be done on the implementation element as | |
| 470 // well? | |
| 471 cls.forEachMember((holder, member) { | |
| 472 // Perform various checks as side effect of "computing" the type. | |
| 473 member.computeType(compiler); | |
| 474 | |
| 475 // Check modifiers. | |
| 476 if (member.isFunction() && member.modifiers.isFinal()) { | |
| 477 compiler.reportMessage( | |
| 478 compiler.spanFromElement(member), | |
| 479 MessageKind.ILLEGAL_FINAL_METHOD_MODIFIER.error(), | |
| 480 api.Diagnostic.ERROR); | |
| 481 } | |
| 482 if (member.isConstructor()) { | |
| 483 final mismatchedFlagsBits = | |
| 484 member.modifiers.flags & | |
| 485 (Modifiers.FLAG_STATIC | Modifiers.FLAG_ABSTRACT); | |
| 486 if (mismatchedFlagsBits != 0) { | |
| 487 final mismatchedFlags = | |
| 488 new Modifiers.withFlags(null, mismatchedFlagsBits); | |
| 489 compiler.reportMessage( | |
| 490 compiler.spanFromElement(member), | |
| 491 MessageKind.ILLEGAL_CONSTRUCTOR_MODIFIERS.error([mismatchedFlags]), | |
| 492 api.Diagnostic.ERROR); | |
| 493 } | |
| 494 } | |
| 495 checkAbstractField(member); | |
| 496 checkValidOverride(member, cls.lookupSuperMember(member.name)); | |
| 497 }); | |
| 498 } | |
| 499 | |
| 500 void checkAbstractField(Element member) { | |
| 501 // Only check for getters. The test can only fail if there is both a setter | |
| 502 // and a getter with the same name, and we only need to check each abstract | |
| 503 // field once, so we just ignore setters. | |
| 504 if (!member.isGetter()) return; | |
| 505 | |
| 506 // Find the associated abstract field. | |
| 507 ClassElement classElement = member.getEnclosingClass(); | |
| 508 Element lookupElement = classElement.lookupLocalMember(member.name); | |
| 509 if (lookupElement == null) { | |
| 510 compiler.internalErrorOnElement(member, | |
| 511 "No abstract field for accessor"); | |
| 512 } else if (!identical(lookupElement.kind, ElementKind.ABSTRACT_FIELD)) { | |
| 513 compiler.internalErrorOnElement( | |
| 514 member, "Inaccessible abstract field for accessor"); | |
| 515 } | |
| 516 AbstractFieldElement field = lookupElement; | |
| 517 | |
| 518 if (field.getter == null) return; | |
| 519 if (field.setter == null) return; | |
| 520 int getterFlags = field.getter.modifiers.flags | Modifiers.FLAG_ABSTRACT; | |
| 521 int setterFlags = field.setter.modifiers.flags | Modifiers.FLAG_ABSTRACT; | |
| 522 if (!identical(getterFlags, setterFlags)) { | |
| 523 final mismatchedFlags = | |
| 524 new Modifiers.withFlags(null, getterFlags ^ setterFlags); | |
| 525 compiler.reportMessage( | |
| 526 compiler.spanFromElement(field.getter), | |
| 527 MessageKind.GETTER_MISMATCH.error([mismatchedFlags]), | |
| 528 api.Diagnostic.ERROR); | |
| 529 compiler.reportMessage( | |
| 530 compiler.spanFromElement(field.setter), | |
| 531 MessageKind.SETTER_MISMATCH.error([mismatchedFlags]), | |
| 532 api.Diagnostic.ERROR); | |
| 533 } | |
| 534 } | |
| 535 | |
| 536 reportErrorWithContext(Element errorneousElement, | |
| 537 MessageKind errorMessage, | |
| 538 Element contextElement, | |
| 539 MessageKind contextMessage) { | |
| 540 compiler.reportMessage( | |
| 541 compiler.spanFromElement(errorneousElement), | |
| 542 errorMessage.error([contextElement.name, | |
| 543 contextElement.getEnclosingClass().name]), | |
| 544 api.Diagnostic.ERROR); | |
| 545 compiler.reportMessage( | |
| 546 compiler.spanFromElement(contextElement), | |
| 547 contextMessage.error(), | |
| 548 api.Diagnostic.INFO); | |
| 549 } | |
| 550 | |
| 551 void checkValidOverride(Element member, Element superMember) { | |
| 552 if (superMember == null) return; | |
| 553 if (member.modifiers.isStatic()) { | |
| 554 reportErrorWithContext( | |
| 555 member, MessageKind.NO_STATIC_OVERRIDE, | |
| 556 superMember, MessageKind.NO_STATIC_OVERRIDE_CONT); | |
| 557 } else { | |
| 558 FunctionElement superFunction = superMember.asFunctionElement(); | |
| 559 FunctionElement function = member.asFunctionElement(); | |
| 560 if (superFunction == null || superFunction.isAccessor()) { | |
| 561 // Field or accessor in super. | |
| 562 if (function != null && !function.isAccessor()) { | |
| 563 // But a plain method in this class. | |
| 564 reportErrorWithContext( | |
| 565 member, MessageKind.CANNOT_OVERRIDE_FIELD_WITH_METHOD, | |
| 566 superMember, MessageKind.CANNOT_OVERRIDE_FIELD_WITH_METHOD_CONT); | |
| 567 } | |
| 568 } else { | |
| 569 // Instance method in super. | |
| 570 if (function == null || function.isAccessor()) { | |
| 571 // But a field (or accessor) in this class. | |
| 572 reportErrorWithContext( | |
| 573 member, MessageKind.CANNOT_OVERRIDE_METHOD_WITH_FIELD, | |
| 574 superMember, MessageKind.CANNOT_OVERRIDE_METHOD_WITH_FIELD_CONT); | |
| 575 } else { | |
| 576 // Both are plain instance methods. | |
| 577 if (superFunction.requiredParameterCount(compiler) != | |
| 578 function.requiredParameterCount(compiler)) { | |
| 579 reportErrorWithContext( | |
| 580 member, | |
| 581 MessageKind.BAD_ARITY_OVERRIDE, | |
| 582 superMember, | |
| 583 MessageKind.BAD_ARITY_OVERRIDE_CONT); | |
| 584 } | |
| 585 // TODO(ahe): Check optional parameters. | |
| 586 } | |
| 587 } | |
| 588 } | |
| 589 } | |
| 590 | |
| 591 FunctionSignature resolveSignature(FunctionElement element) { | |
| 592 return compiler.withCurrentElement(element, () { | |
| 593 FunctionExpression node = | |
| 594 compiler.parser.measure(() => element.parseNode(compiler)); | |
| 595 return measure(() => SignatureResolver.analyze( | |
| 596 compiler, node.parameters, node.returnType, element)); | |
| 597 }); | |
| 598 } | |
| 599 | |
| 600 FunctionSignature resolveFunctionExpression(Element element, | |
| 601 FunctionExpression node) { | |
| 602 return measure(() => SignatureResolver.analyze( | |
| 603 compiler, node.parameters, node.returnType, element)); | |
| 604 } | |
| 605 | |
| 606 void resolveTypedef(TypedefElement element) { | |
| 607 if (element.isResolved || element.isBeingResolved) return; | |
| 608 element.isBeingResolved = true; | |
| 609 return compiler.withCurrentElement(element, () { | |
| 610 measure(() { | |
| 611 Typedef node = | |
| 612 compiler.parser.measure(() => element.parseNode(compiler)); | |
| 613 TypedefResolverVisitor visitor = | |
| 614 new TypedefResolverVisitor(compiler, element); | |
| 615 visitor.visit(node); | |
| 616 | |
| 617 element.isBeingResolved = false; | |
| 618 element.isResolved = true; | |
| 619 }); | |
| 620 }); | |
| 621 } | |
| 622 | |
| 623 FunctionType computeFunctionType(Element element, | |
| 624 FunctionSignature signature) { | |
| 625 LinkBuilder<DartType> parameterTypes = new LinkBuilder<DartType>(); | |
| 626 for (Link<Element> link = signature.requiredParameters; | |
| 627 !link.isEmpty(); | |
| 628 link = link.tail) { | |
| 629 parameterTypes.addLast(link.head.computeType(compiler)); | |
| 630 // TODO(karlklose): optional parameters. | |
| 631 } | |
| 632 return new FunctionType(signature.returnType, | |
| 633 parameterTypes.toLink(), | |
| 634 element); | |
| 635 } | |
| 636 | |
| 637 void resolveMetadataAnnotation(PartialMetadataAnnotation annotation) { | |
| 638 compiler.withCurrentElement(annotation.annotatedElement, () => measure(() { | |
| 639 assert(annotation.resolutionState == STATE_NOT_STARTED); | |
| 640 annotation.resolutionState = STATE_STARTED; | |
| 641 | |
| 642 Node node = annotation.parseNode(compiler); | |
| 643 ResolverVisitor visitor = new ResolverVisitor( | |
| 644 compiler, annotation.annotatedElement.enclosingElement); | |
| 645 node.accept(visitor); | |
| 646 annotation.value = compiler.constantHandler.compileNodeWithDefinitions( | |
| 647 node, visitor.mapping); | |
| 648 | |
| 649 annotation.resolutionState = STATE_DONE; | |
| 650 })); | |
| 651 } | |
| 652 | |
| 653 error(Node node, MessageKind kind, [arguments = const []]) { | |
| 654 ResolutionError message = new ResolutionError(kind, arguments); | |
| 655 compiler.reportError(node, message); | |
| 656 } | |
| 657 } | |
| 658 | |
| 659 class InitializerResolver { | |
| 660 final ResolverVisitor visitor; | |
| 661 final Map<SourceString, Node> initialized; | |
| 662 Link<Node> initializers; | |
| 663 bool hasSuper; | |
| 664 | |
| 665 InitializerResolver(this.visitor) | |
| 666 : initialized = new Map<SourceString, Node>(), hasSuper = false; | |
| 667 | |
| 668 error(Node node, MessageKind kind, [arguments = const []]) { | |
| 669 visitor.error(node, kind, arguments); | |
| 670 } | |
| 671 | |
| 672 warning(Node node, MessageKind kind, [arguments = const []]) { | |
| 673 visitor.warning(node, kind, arguments); | |
| 674 } | |
| 675 | |
| 676 bool isFieldInitializer(SendSet node) { | |
| 677 if (node.selector.asIdentifier() == null) return false; | |
| 678 if (node.receiver == null) return true; | |
| 679 if (node.receiver.asIdentifier() == null) return false; | |
| 680 return node.receiver.asIdentifier().isThis(); | |
| 681 } | |
| 682 | |
| 683 void checkForDuplicateInitializers(SourceString name, Node init) { | |
| 684 if (initialized.containsKey(name)) { | |
| 685 error(init, MessageKind.DUPLICATE_INITIALIZER, [name]); | |
| 686 warning(initialized[name], MessageKind.ALREADY_INITIALIZED, [name]); | |
| 687 } | |
| 688 initialized[name] = init; | |
| 689 } | |
| 690 | |
| 691 void resolveFieldInitializer(FunctionElement constructor, SendSet init) { | |
| 692 // init is of the form [this.]field = value. | |
| 693 final Node selector = init.selector; | |
| 694 final SourceString name = selector.asIdentifier().source; | |
| 695 // Lookup target field. | |
| 696 Element target; | |
| 697 if (isFieldInitializer(init)) { | |
| 698 Scope localScope = constructor.getEnclosingClass().buildLocalScope(); | |
| 699 target = localScope.lookup(name); | |
| 700 if (target == null) { | |
| 701 error(selector, MessageKind.CANNOT_RESOLVE, [name]); | |
| 702 } else if (target.kind != ElementKind.FIELD) { | |
| 703 error(selector, MessageKind.NOT_A_FIELD, [name]); | |
| 704 } else if (!target.isInstanceMember()) { | |
| 705 error(selector, MessageKind.INIT_STATIC_FIELD, [name]); | |
| 706 } | |
| 707 } else { | |
| 708 error(init, MessageKind.INVALID_RECEIVER_IN_INITIALIZER); | |
| 709 } | |
| 710 visitor.useElement(init, target); | |
| 711 visitor.world.registerStaticUse(target); | |
| 712 checkForDuplicateInitializers(name, init); | |
| 713 // Resolve initializing value. | |
| 714 visitor.visitInStaticContext(init.arguments.head); | |
| 715 } | |
| 716 | |
| 717 ClassElement getSuperOrThisLookupTarget(FunctionElement constructor, | |
| 718 bool isSuperCall, | |
| 719 Node diagnosticNode) { | |
| 720 ClassElement lookupTarget = constructor.getEnclosingClass(); | |
| 721 if (isSuperCall) { | |
| 722 // Calculate correct lookup target and constructor name. | |
| 723 if (identical(lookupTarget, visitor.compiler.objectClass)) { | |
| 724 error(diagnosticNode, MessageKind.SUPER_INITIALIZER_IN_OBJECT); | |
| 725 } else { | |
| 726 return lookupTarget.supertype.element; | |
| 727 } | |
| 728 } | |
| 729 return lookupTarget; | |
| 730 } | |
| 731 | |
| 732 Element resolveSuperOrThisForSend(FunctionElement constructor, | |
| 733 FunctionExpression functionNode, | |
| 734 Send call) { | |
| 735 // Resolve the selector and the arguments. | |
| 736 ResolverTask resolver = visitor.compiler.resolver; | |
| 737 visitor.inStaticContext(() { | |
| 738 visitor.resolveSelector(call); | |
| 739 visitor.resolveArguments(call.argumentsNode); | |
| 740 }); | |
| 741 Selector selector = visitor.mapping.getSelector(call); | |
| 742 bool isSuperCall = Initializers.isSuperConstructorCall(call); | |
| 743 | |
| 744 ClassElement lookupTarget = getSuperOrThisLookupTarget(constructor, | |
| 745 isSuperCall, | |
| 746 call); | |
| 747 final SourceString className = lookupTarget.name; | |
| 748 | |
| 749 SourceString constructorName; | |
| 750 Selector lookupSelector; | |
| 751 if (resolver.isNamedConstructor(call)) { | |
| 752 constructorName = resolver.getConstructorName(call); | |
| 753 lookupSelector = new Selector.callConstructor( | |
| 754 constructorName, | |
| 755 visitor.enclosingElement.getLibrary()); | |
| 756 } else { | |
| 757 constructorName = const SourceString(''); | |
| 758 lookupSelector = new Selector.callDefaultConstructor( | |
| 759 visitor.enclosingElement.getLibrary()); | |
| 760 } | |
| 761 | |
| 762 FunctionElement lookedupConstructor = | |
| 763 lookupTarget.lookupConstructor(lookupSelector); | |
| 764 | |
| 765 final bool isImplicitSuperCall = false; | |
| 766 verifyThatConstructorMatchesCall(lookedupConstructor, | |
| 767 selector, | |
| 768 isImplicitSuperCall, | |
| 769 call, | |
| 770 constructorName, | |
| 771 className); | |
| 772 | |
| 773 visitor.useElement(call, lookedupConstructor); | |
| 774 visitor.world.registerStaticUse(lookedupConstructor); | |
| 775 return lookedupConstructor; | |
| 776 } | |
| 777 | |
| 778 void resolveImplicitSuperConstructorSend(FunctionElement constructor, | |
| 779 FunctionExpression functionNode) { | |
| 780 // If the class has a super resolve the implicit super call. | |
| 781 ClassElement classElement = constructor.getEnclosingClass(); | |
| 782 ClassElement superClass = classElement.superclass; | |
| 783 if (classElement != visitor.compiler.objectClass) { | |
| 784 assert(superClass != null); | |
| 785 assert(superClass.resolutionState == STATE_DONE); | |
| 786 SourceString constructorName = const SourceString(''); | |
| 787 Selector callToMatch = new Selector.call( | |
| 788 constructorName, | |
| 789 classElement.getLibrary(), | |
| 790 0); | |
| 791 | |
| 792 final bool isSuperCall = true; | |
| 793 ClassElement lookupTarget = getSuperOrThisLookupTarget(constructor, | |
| 794 isSuperCall, | |
| 795 functionNode); | |
| 796 final SourceString className = lookupTarget.name; | |
| 797 Element calledConstructor = lookupTarget.lookupConstructor( | |
| 798 new Selector.callDefaultConstructor( | |
| 799 visitor.enclosingElement.getLibrary())); | |
| 800 | |
| 801 final bool isImplicitSuperCall = true; | |
| 802 verifyThatConstructorMatchesCall(calledConstructor, | |
| 803 callToMatch, | |
| 804 isImplicitSuperCall, | |
| 805 functionNode, | |
| 806 className, | |
| 807 const SourceString('')); | |
| 808 | |
| 809 visitor.world.registerStaticUse(calledConstructor); | |
| 810 } | |
| 811 } | |
| 812 | |
| 813 void verifyThatConstructorMatchesCall( | |
| 814 FunctionElement lookedupConstructor, | |
| 815 Selector call, | |
| 816 bool isImplicitSuperCall, | |
| 817 Node diagnosticNode, | |
| 818 SourceString className, | |
| 819 SourceString constructorName) { | |
| 820 if (lookedupConstructor == null | |
| 821 || !lookedupConstructor.isGenerativeConstructor()) { | |
| 822 var fullConstructorName = | |
| 823 visitor.compiler.resolver.constructorNameForDiagnostics(className, | |
| 824 constructorName); | |
| 825 MessageKind kind = isImplicitSuperCall | |
| 826 ? MessageKind.CANNOT_RESOLVE_CONSTRUCTOR_FOR_IMPLICIT | |
| 827 : MessageKind.CANNOT_RESOLVE_CONSTRUCTOR; | |
| 828 error(diagnosticNode, kind, [fullConstructorName]); | |
| 829 } else { | |
| 830 if (!call.applies(lookedupConstructor, visitor.compiler)) { | |
| 831 MessageKind kind = isImplicitSuperCall | |
| 832 ? MessageKind.NO_MATCHING_CONSTRUCTOR_FOR_IMPLICIT | |
| 833 : MessageKind.NO_MATCHING_CONSTRUCTOR; | |
| 834 error(diagnosticNode, kind); | |
| 835 } | |
| 836 } | |
| 837 } | |
| 838 | |
| 839 FunctionElement resolveRedirection(FunctionElement constructor, | |
| 840 FunctionExpression functionNode) { | |
| 841 if (functionNode.initializers == null) return null; | |
| 842 Link<Node> link = functionNode.initializers.nodes; | |
| 843 if (!link.isEmpty() && Initializers.isConstructorRedirect(link.head)) { | |
| 844 return resolveSuperOrThisForSend(constructor, functionNode, link.head); | |
| 845 } | |
| 846 return null; | |
| 847 } | |
| 848 | |
| 849 /** | |
| 850 * Resolve all initializers of this constructor. In the case of a redirecting | |
| 851 * constructor, the resolved constructor's function element is returned. | |
| 852 */ | |
| 853 FunctionElement resolveInitializers(FunctionElement constructor, | |
| 854 FunctionExpression functionNode) { | |
| 855 // Keep track of all "this.param" parameters specified for constructor so | |
| 856 // that we can ensure that fields are initialized only once. | |
| 857 FunctionSignature functionParameters = | |
| 858 constructor.computeSignature(visitor.compiler); | |
| 859 functionParameters.forEachParameter((Element element) { | |
| 860 if (identical(element.kind, ElementKind.FIELD_PARAMETER)) { | |
| 861 checkForDuplicateInitializers(element.name, | |
| 862 element.parseNode(visitor.compiler)); | |
| 863 } | |
| 864 }); | |
| 865 | |
| 866 if (functionNode.initializers == null) { | |
| 867 initializers = const Link<Node>(); | |
| 868 } else { | |
| 869 initializers = functionNode.initializers.nodes; | |
| 870 } | |
| 871 FunctionElement result; | |
| 872 bool resolvedSuper = false; | |
| 873 for (Link<Node> link = initializers; | |
| 874 !link.isEmpty(); | |
| 875 link = link.tail) { | |
| 876 if (link.head.asSendSet() != null) { | |
| 877 final SendSet init = link.head.asSendSet(); | |
| 878 resolveFieldInitializer(constructor, init); | |
| 879 } else if (link.head.asSend() != null) { | |
| 880 final Send call = link.head.asSend(); | |
| 881 if (Initializers.isSuperConstructorCall(call)) { | |
| 882 if (resolvedSuper) { | |
| 883 error(call, MessageKind.DUPLICATE_SUPER_INITIALIZER); | |
| 884 } | |
| 885 resolveSuperOrThisForSend(constructor, functionNode, call); | |
| 886 resolvedSuper = true; | |
| 887 } else if (Initializers.isConstructorRedirect(call)) { | |
| 888 // Check that there is no body (Language specification 7.5.1). | |
| 889 if (functionNode.hasBody()) { | |
| 890 error(functionNode, MessageKind.REDIRECTING_CONSTRUCTOR_HAS_BODY); | |
| 891 } | |
| 892 // Check that there are no other initializers. | |
| 893 if (!initializers.tail.isEmpty()) { | |
| 894 error(call, MessageKind.REDIRECTING_CONSTRUCTOR_HAS_INITIALIZER); | |
| 895 } | |
| 896 return resolveSuperOrThisForSend(constructor, functionNode, call); | |
| 897 } else { | |
| 898 visitor.error(call, MessageKind.CONSTRUCTOR_CALL_EXPECTED); | |
| 899 return null; | |
| 900 } | |
| 901 } else { | |
| 902 error(link.head, MessageKind.INVALID_INITIALIZER); | |
| 903 } | |
| 904 } | |
| 905 if (!resolvedSuper) { | |
| 906 resolveImplicitSuperConstructorSend(constructor, functionNode); | |
| 907 } | |
| 908 return null; // If there was no redirection always return null. | |
| 909 } | |
| 910 } | |
| 911 | |
| 912 class CommonResolverVisitor<R> extends Visitor<R> { | |
| 913 final Compiler compiler; | |
| 914 | |
| 915 CommonResolverVisitor(Compiler this.compiler); | |
| 916 | |
| 917 R visitNode(Node node) { | |
| 918 cancel(node, | |
| 919 'internal error: Unhandled node: ${node.getObjectDescription()}'); | |
| 920 } | |
| 921 | |
| 922 R visitEmptyStatement(Node node) => null; | |
| 923 | |
| 924 /** Convenience method for visiting nodes that may be null. */ | |
| 925 R visit(Node node) => (node == null) ? null : node.accept(this); | |
| 926 | |
| 927 void error(Node node, MessageKind kind, [arguments = const []]) { | |
| 928 ResolutionError message = new ResolutionError(kind, arguments); | |
| 929 compiler.reportError(node, message); | |
| 930 } | |
| 931 | |
| 932 void warning(Node node, MessageKind kind, [arguments = const []]) { | |
| 933 ResolutionWarning message = new ResolutionWarning(kind, arguments); | |
| 934 compiler.reportWarning(node, message); | |
| 935 } | |
| 936 | |
| 937 void cancel(Node node, String message) { | |
| 938 compiler.cancel(message, node: node); | |
| 939 } | |
| 940 | |
| 941 void internalError(Node node, String message) { | |
| 942 compiler.internalError(message, node: node); | |
| 943 } | |
| 944 | |
| 945 void unimplemented(Node node, String message) { | |
| 946 compiler.unimplemented(message, node: node); | |
| 947 } | |
| 948 } | |
| 949 | |
| 950 abstract class LabelScope { | |
| 951 LabelScope get outer; | |
| 952 LabelElement lookup(String label); | |
| 953 } | |
| 954 | |
| 955 class LabeledStatementLabelScope implements LabelScope { | |
| 956 final LabelScope outer; | |
| 957 final Map<String, LabelElement> labels; | |
| 958 LabeledStatementLabelScope(this.outer, this.labels); | |
| 959 LabelElement lookup(String labelName) { | |
| 960 LabelElement label = labels[labelName]; | |
| 961 if (label != null) return label; | |
| 962 return outer.lookup(labelName); | |
| 963 } | |
| 964 } | |
| 965 | |
| 966 class SwitchLabelScope implements LabelScope { | |
| 967 final LabelScope outer; | |
| 968 final Map<String, LabelElement> caseLabels; | |
| 969 | |
| 970 SwitchLabelScope(this.outer, this.caseLabels); | |
| 971 | |
| 972 LabelElement lookup(String labelName) { | |
| 973 LabelElement result = caseLabels[labelName]; | |
| 974 if (result != null) return result; | |
| 975 return outer.lookup(labelName); | |
| 976 } | |
| 977 } | |
| 978 | |
| 979 class EmptyLabelScope implements LabelScope { | |
| 980 const EmptyLabelScope(); | |
| 981 LabelElement lookup(String label) => null; | |
| 982 LabelScope get outer { | |
| 983 throw 'internal error: empty label scope has no outer'; | |
| 984 } | |
| 985 } | |
| 986 | |
| 987 class StatementScope { | |
| 988 LabelScope labels; | |
| 989 Link<TargetElement> breakTargetStack; | |
| 990 Link<TargetElement> continueTargetStack; | |
| 991 // Used to provide different numbers to statements if one is inside the other. | |
| 992 // Can be used to make otherwise duplicate labels unique. | |
| 993 int nestingLevel = 0; | |
| 994 | |
| 995 StatementScope() | |
| 996 : labels = const EmptyLabelScope(), | |
| 997 breakTargetStack = const Link<TargetElement>(), | |
| 998 continueTargetStack = const Link<TargetElement>(); | |
| 999 | |
| 1000 LabelElement lookupLabel(String label) { | |
| 1001 return labels.lookup(label); | |
| 1002 } | |
| 1003 | |
| 1004 TargetElement currentBreakTarget() => | |
| 1005 breakTargetStack.isEmpty() ? null : breakTargetStack.head; | |
| 1006 | |
| 1007 TargetElement currentContinueTarget() => | |
| 1008 continueTargetStack.isEmpty() ? null : continueTargetStack.head; | |
| 1009 | |
| 1010 void enterLabelScope(Map<String, LabelElement> elements) { | |
| 1011 labels = new LabeledStatementLabelScope(labels, elements); | |
| 1012 nestingLevel++; | |
| 1013 } | |
| 1014 | |
| 1015 void exitLabelScope() { | |
| 1016 nestingLevel--; | |
| 1017 labels = labels.outer; | |
| 1018 } | |
| 1019 | |
| 1020 void enterLoop(TargetElement element) { | |
| 1021 breakTargetStack = breakTargetStack.prepend(element); | |
| 1022 continueTargetStack = continueTargetStack.prepend(element); | |
| 1023 nestingLevel++; | |
| 1024 } | |
| 1025 | |
| 1026 void exitLoop() { | |
| 1027 nestingLevel--; | |
| 1028 breakTargetStack = breakTargetStack.tail; | |
| 1029 continueTargetStack = continueTargetStack.tail; | |
| 1030 } | |
| 1031 | |
| 1032 void enterSwitch(TargetElement breakElement, | |
| 1033 Map<String, LabelElement> continueElements) { | |
| 1034 breakTargetStack = breakTargetStack.prepend(breakElement); | |
| 1035 labels = new SwitchLabelScope(labels, continueElements); | |
| 1036 nestingLevel++; | |
| 1037 } | |
| 1038 | |
| 1039 void exitSwitch() { | |
| 1040 nestingLevel--; | |
| 1041 breakTargetStack = breakTargetStack.tail; | |
| 1042 labels = labels.outer; | |
| 1043 } | |
| 1044 } | |
| 1045 | |
| 1046 class TypeResolver { | |
| 1047 final Compiler compiler; | |
| 1048 | |
| 1049 TypeResolver(this.compiler); | |
| 1050 | |
| 1051 Element resolveTypeName(Scope scope, TypeAnnotation node) { | |
| 1052 Identifier typeName = node.typeName.asIdentifier(); | |
| 1053 Send send = node.typeName.asSend(); | |
| 1054 return resolveTypeNameInternal(scope, typeName, send); | |
| 1055 } | |
| 1056 | |
| 1057 Element resolveTypeNameInternal(Scope scope, Identifier typeName, Send send) { | |
| 1058 if (send != null) { | |
| 1059 typeName = send.selector; | |
| 1060 } | |
| 1061 if (identical(typeName.source.stringValue, 'void')) { | |
| 1062 return compiler.types.voidType.element; | |
| 1063 } else if ( | |
| 1064 // TODO(aprelev@gmail.com): Remove deprecated Dynamic keyword support. | |
| 1065 identical(typeName.source.stringValue, 'Dynamic') | |
| 1066 || identical(typeName.source.stringValue, 'dynamic')) { | |
| 1067 return compiler.dynamicClass; | |
| 1068 } else if (send != null) { | |
| 1069 Element e = scope.lookup(send.receiver.asIdentifier().source); | |
| 1070 if (e != null && identical(e.kind, ElementKind.PREFIX)) { | |
| 1071 // The receiver is a prefix. Lookup in the imported members. | |
| 1072 PrefixElement prefix = e; | |
| 1073 return prefix.lookupLocalMember(typeName.source); | |
| 1074 } else if (e != null && identical(e.kind, ElementKind.CLASS)) { | |
| 1075 // The receiver is the class part of a named constructor. | |
| 1076 return e; | |
| 1077 } else { | |
| 1078 return null; | |
| 1079 } | |
| 1080 } else { | |
| 1081 return scope.lookup(typeName.source); | |
| 1082 } | |
| 1083 } | |
| 1084 | |
| 1085 // TODO(johnniwinther): Change [onFailure] and [whenResolved] to use boolean | |
| 1086 // flags instead of closures. | |
| 1087 // TODO(johnniwinther): Should never return [null] but instead an erroneous | |
| 1088 // type. | |
| 1089 DartType resolveTypeAnnotation(TypeAnnotation node, | |
| 1090 {Scope inScope, ClassElement inClass, | |
| 1091 onFailure(Node, MessageKind, [List arguments]), | |
| 1092 whenResolved(Node, Type)}) { | |
| 1093 if (onFailure == null) { | |
| 1094 onFailure = (n, k, [arguments]) {}; | |
| 1095 } | |
| 1096 if (whenResolved == null) { | |
| 1097 whenResolved = (n, t) {}; | |
| 1098 } | |
| 1099 if (inClass != null) { | |
| 1100 inScope = inClass.buildScope(); | |
| 1101 } | |
| 1102 if (inScope == null) { | |
| 1103 compiler.internalError('resolveTypeAnnotation: no scope specified'); | |
| 1104 } | |
| 1105 return resolveTypeAnnotationInContext(inScope, node, onFailure, | |
| 1106 whenResolved); | |
| 1107 } | |
| 1108 | |
| 1109 DartType resolveTypeAnnotationInContext(Scope scope, TypeAnnotation node, | |
| 1110 onFailure, whenResolved) { | |
| 1111 Element element = resolveTypeName(scope, node); | |
| 1112 DartType type; | |
| 1113 if (element == null) { | |
| 1114 onFailure(node, MessageKind.CANNOT_RESOLVE_TYPE, [node.typeName]); | |
| 1115 } else if (element.isErroneous()) { | |
| 1116 ErroneousElement error = element; | |
| 1117 onFailure(node, error.messageKind, error.messageArguments); | |
| 1118 } else if (!element.impliesType()) { | |
| 1119 onFailure(node, MessageKind.NOT_A_TYPE, [node.typeName]); | |
| 1120 } else { | |
| 1121 if (identical(element, compiler.types.voidType.element) || | |
| 1122 identical(element, compiler.types.dynamicType.element)) { | |
| 1123 type = element.computeType(compiler); | |
| 1124 } else if (element.isClass()) { | |
| 1125 ClassElement cls = element; | |
| 1126 cls.ensureResolved(compiler); | |
| 1127 Link<DartType> arguments = | |
| 1128 resolveTypeArguments(node, cls.typeVariables, scope, | |
| 1129 onFailure, whenResolved); | |
| 1130 if (cls.typeVariables.isEmpty() && arguments.isEmpty()) { | |
| 1131 // Use the canonical type if it has no type parameters. | |
| 1132 type = cls.computeType(compiler); | |
| 1133 } else { | |
| 1134 type = new InterfaceType(cls, arguments); | |
| 1135 } | |
| 1136 } else if (element.isTypedef()) { | |
| 1137 TypedefElement typdef = element; | |
| 1138 // TODO(ahe): Should be [ensureResolved]. | |
| 1139 compiler.resolveTypedef(typdef); | |
| 1140 typdef.computeType(compiler); | |
| 1141 Link<DartType> arguments = resolveTypeArguments( | |
| 1142 node, typdef.typeVariables, | |
| 1143 scope, onFailure, whenResolved); | |
| 1144 if (typdef.typeVariables.isEmpty() && arguments.isEmpty()) { | |
| 1145 // Return the canonical type if it has no type parameters. | |
| 1146 type = typdef.computeType(compiler); | |
| 1147 } else { | |
| 1148 type = new TypedefType(typdef, arguments); | |
| 1149 } | |
| 1150 } else if (element.isTypeVariable()) { | |
| 1151 type = element.computeType(compiler); | |
| 1152 } else { | |
| 1153 compiler.cancel("unexpected element kind ${element.kind}", | |
| 1154 node: node); | |
| 1155 } | |
| 1156 } | |
| 1157 whenResolved(node, type); | |
| 1158 return type; | |
| 1159 } | |
| 1160 | |
| 1161 Link<DartType> resolveTypeArguments(TypeAnnotation node, | |
| 1162 Link<DartType> typeVariables, | |
| 1163 Scope scope, onFailure, whenResolved) { | |
| 1164 if (node.typeArguments == null) { | |
| 1165 return const Link<DartType>(); | |
| 1166 } | |
| 1167 var arguments = new LinkBuilder<DartType>(); | |
| 1168 for (Link<Node> typeArguments = node.typeArguments.nodes; | |
| 1169 !typeArguments.isEmpty(); | |
| 1170 typeArguments = typeArguments.tail) { | |
| 1171 if (typeVariables.isEmpty()) { | |
| 1172 onFailure(typeArguments.head, MessageKind.ADDITIONAL_TYPE_ARGUMENT); | |
| 1173 } | |
| 1174 DartType argType = resolveTypeAnnotationInContext(scope, | |
| 1175 typeArguments.head, | |
| 1176 onFailure, | |
| 1177 whenResolved); | |
| 1178 arguments.addLast(argType); | |
| 1179 if (!typeVariables.isEmpty()) { | |
| 1180 typeVariables = typeVariables.tail; | |
| 1181 } | |
| 1182 } | |
| 1183 if (!typeVariables.isEmpty()) { | |
| 1184 onFailure(node.typeArguments, MessageKind.MISSING_TYPE_ARGUMENT); | |
| 1185 } | |
| 1186 return arguments.toLink(); | |
| 1187 } | |
| 1188 } | |
| 1189 | |
| 1190 class ResolverVisitor extends CommonResolverVisitor<Element> { | |
| 1191 final TreeElementMapping mapping; | |
| 1192 Element enclosingElement; | |
| 1193 final TypeResolver typeResolver; | |
| 1194 bool inInstanceContext; | |
| 1195 bool inCheckContext; | |
| 1196 bool inCatchBlock; | |
| 1197 Scope scope; | |
| 1198 ClassElement currentClass; | |
| 1199 ExpressionStatement currentExpressionStatement; | |
| 1200 bool typeRequired = false; | |
| 1201 StatementScope statementScope; | |
| 1202 int allowedCategory = ElementCategory.VARIABLE | ElementCategory.FUNCTION; | |
| 1203 | |
| 1204 ResolverVisitor(Compiler compiler, Element element) | |
| 1205 : this.mapping = new TreeElementMapping(element), | |
| 1206 this.enclosingElement = element, | |
| 1207 // When the element is a field, we are actually resolving its | |
| 1208 // initial value, which should not have access to instance | |
| 1209 // fields. | |
| 1210 inInstanceContext = (element.isInstanceMember() && !element.isField()) | |
| 1211 || element.isGenerativeConstructor(), | |
| 1212 this.currentClass = element.isMember() ? element.getEnclosingClass() | |
| 1213 : null, | |
| 1214 this.statementScope = new StatementScope(), | |
| 1215 typeResolver = new TypeResolver(compiler), | |
| 1216 scope = element.buildScope(), | |
| 1217 inCheckContext = compiler.enableTypeAssertions, | |
| 1218 inCatchBlock = false, | |
| 1219 super(compiler); | |
| 1220 | |
| 1221 Enqueuer get world => compiler.enqueuer.resolution; | |
| 1222 | |
| 1223 Element lookup(Node node, SourceString name) { | |
| 1224 Element result = scope.lookup(name); | |
| 1225 if (!inInstanceContext && result != null && result.isInstanceMember()) { | |
| 1226 error(node, MessageKind.NO_INSTANCE_AVAILABLE, [node]); | |
| 1227 } | |
| 1228 return result; | |
| 1229 } | |
| 1230 | |
| 1231 // Create, or reuse an already created, statement element for a statement. | |
| 1232 TargetElement getOrCreateTargetElement(Node statement) { | |
| 1233 TargetElement element = mapping[statement]; | |
| 1234 if (element == null) { | |
| 1235 element = new TargetElement(statement, | |
| 1236 statementScope.nestingLevel, | |
| 1237 enclosingElement); | |
| 1238 mapping[statement] = element; | |
| 1239 } | |
| 1240 return element; | |
| 1241 } | |
| 1242 | |
| 1243 doInCheckContext(action()) { | |
| 1244 bool wasInCheckContext = inCheckContext; | |
| 1245 inCheckContext = true; | |
| 1246 var result = action(); | |
| 1247 inCheckContext = wasInCheckContext; | |
| 1248 return result; | |
| 1249 } | |
| 1250 | |
| 1251 inStaticContext(action()) { | |
| 1252 bool wasInstanceContext = inInstanceContext; | |
| 1253 inInstanceContext = false; | |
| 1254 var result = action(); | |
| 1255 inInstanceContext = wasInstanceContext; | |
| 1256 return result; | |
| 1257 } | |
| 1258 | |
| 1259 visitInStaticContext(Node node) { | |
| 1260 inStaticContext(() => visit(node)); | |
| 1261 } | |
| 1262 | |
| 1263 ErroneousElement warnAndCreateErroneousElement(Node node, | |
| 1264 SourceString name, | |
| 1265 MessageKind kind, | |
| 1266 List<Node> arguments) { | |
| 1267 return warnOnErroneousElement(node, | |
| 1268 new ErroneousElement(kind, arguments, name, enclosingElement)); | |
| 1269 } | |
| 1270 | |
| 1271 ErroneousElement warnOnErroneousElement(Node node, | |
| 1272 ErroneousElement erroneousElement) { | |
| 1273 ResolutionWarning warning = | |
| 1274 new ResolutionWarning(erroneousElement.messageKind, | |
| 1275 erroneousElement.messageArguments); | |
| 1276 compiler.reportWarning(node, warning); | |
| 1277 return erroneousElement; | |
| 1278 } | |
| 1279 | |
| 1280 Element visitIdentifier(Identifier node) { | |
| 1281 if (node.isThis()) { | |
| 1282 if (!inInstanceContext) { | |
| 1283 error(node, MessageKind.NO_INSTANCE_AVAILABLE, [node]); | |
| 1284 } | |
| 1285 return null; | |
| 1286 } else if (node.isSuper()) { | |
| 1287 if (!inInstanceContext) error(node, MessageKind.NO_SUPER_IN_STATIC); | |
| 1288 if ((ElementCategory.SUPER & allowedCategory) == 0) { | |
| 1289 error(node, MessageKind.INVALID_USE_OF_SUPER); | |
| 1290 } | |
| 1291 return null; | |
| 1292 } else { | |
| 1293 Element element = lookup(node, node.source); | |
| 1294 if (element == null) { | |
| 1295 if (!inInstanceContext) { | |
| 1296 element = warnAndCreateErroneousElement(node, node.source, | |
| 1297 MessageKind.CANNOT_RESOLVE, | |
| 1298 [node]); | |
| 1299 } | |
| 1300 } else if (element.isErroneous()) { | |
| 1301 element = warnOnErroneousElement(node, element); | |
| 1302 } else { | |
| 1303 if ((element.kind.category & allowedCategory) == 0) { | |
| 1304 // TODO(ahe): Improve error message. Need UX input. | |
| 1305 error(node, MessageKind.GENERIC, ["is not an expression $element"]); | |
| 1306 } | |
| 1307 } | |
| 1308 return useElement(node, element); | |
| 1309 } | |
| 1310 } | |
| 1311 | |
| 1312 Element visitTypeAnnotation(TypeAnnotation node) { | |
| 1313 DartType type = resolveTypeAnnotation(node); | |
| 1314 if (type != null) { | |
| 1315 if (inCheckContext) { | |
| 1316 compiler.enqueuer.resolution.registerIsCheck(type); | |
| 1317 } | |
| 1318 return type.element; | |
| 1319 } | |
| 1320 return null; | |
| 1321 } | |
| 1322 | |
| 1323 Element defineElement(Node node, Element element, | |
| 1324 {bool doAddToScope: true}) { | |
| 1325 compiler.ensure(element != null); | |
| 1326 mapping[node] = element; | |
| 1327 if (doAddToScope) { | |
| 1328 Element existing = scope.add(element); | |
| 1329 if (existing != element) { | |
| 1330 error(node, MessageKind.DUPLICATE_DEFINITION, [node]); | |
| 1331 } | |
| 1332 } | |
| 1333 return element; | |
| 1334 } | |
| 1335 | |
| 1336 Element useElement(Node node, Element element) { | |
| 1337 if (element == null) return null; | |
| 1338 return mapping[node] = element; | |
| 1339 } | |
| 1340 | |
| 1341 DartType useType(TypeAnnotation annotation, DartType type) { | |
| 1342 if (type != null) { | |
| 1343 mapping.setType(annotation, type); | |
| 1344 useElement(annotation, type.element); | |
| 1345 } | |
| 1346 return type; | |
| 1347 } | |
| 1348 | |
| 1349 void setupFunction(FunctionExpression node, FunctionElement function) { | |
| 1350 // If [function] is the [enclosingElement], the [scope] has | |
| 1351 // already been set in the constructor of [ResolverVisitor]. | |
| 1352 if (function != enclosingElement) scope = new MethodScope(scope, function); | |
| 1353 | |
| 1354 // Put the parameters in scope. | |
| 1355 FunctionSignature functionParameters = | |
| 1356 function.computeSignature(compiler); | |
| 1357 Link<Node> parameterNodes = (node.parameters == null) | |
| 1358 ? const Link<Node>() : node.parameters.nodes; | |
| 1359 functionParameters.forEachParameter((Element element) { | |
| 1360 if (element == functionParameters.optionalParameters.head) { | |
| 1361 NodeList nodes = parameterNodes.head; | |
| 1362 parameterNodes = nodes.nodes; | |
| 1363 } | |
| 1364 VariableDefinitions variableDefinitions = parameterNodes.head; | |
| 1365 Node parameterNode = variableDefinitions.definitions.nodes.head; | |
| 1366 initializerDo(parameterNode, (n) => n.accept(this)); | |
| 1367 // Field parameters (this.x) are not visible inside the constructor. The | |
| 1368 // fields they reference are visible, but must be resolved independently. | |
| 1369 if (element.kind == ElementKind.FIELD_PARAMETER) { | |
| 1370 useElement(parameterNode, element); | |
| 1371 } else { | |
| 1372 defineElement(variableDefinitions.definitions.nodes.head, element); | |
| 1373 } | |
| 1374 parameterNodes = parameterNodes.tail; | |
| 1375 }); | |
| 1376 } | |
| 1377 | |
| 1378 visitCascade(Cascade node) { | |
| 1379 visit(node.expression); | |
| 1380 } | |
| 1381 | |
| 1382 visitCascadeReceiver(CascadeReceiver node) { | |
| 1383 visit(node.expression); | |
| 1384 } | |
| 1385 | |
| 1386 Element visitClassNode(ClassNode node) { | |
| 1387 cancel(node, "shouldn't be called"); | |
| 1388 } | |
| 1389 | |
| 1390 visitIn(Node node, Scope nestedScope) { | |
| 1391 scope = nestedScope; | |
| 1392 Element element = visit(node); | |
| 1393 scope = scope.parent; | |
| 1394 return element; | |
| 1395 } | |
| 1396 | |
| 1397 /** | |
| 1398 * Introduces new default targets for break and continue | |
| 1399 * before visiting the body of the loop | |
| 1400 */ | |
| 1401 visitLoopBodyIn(Node loop, Node body, Scope bodyScope) { | |
| 1402 TargetElement element = getOrCreateTargetElement(loop); | |
| 1403 statementScope.enterLoop(element); | |
| 1404 visitIn(body, bodyScope); | |
| 1405 statementScope.exitLoop(); | |
| 1406 if (!element.isTarget) { | |
| 1407 mapping.remove(loop); | |
| 1408 } | |
| 1409 } | |
| 1410 | |
| 1411 visitBlock(Block node) { | |
| 1412 visitIn(node.statements, new BlockScope(scope)); | |
| 1413 } | |
| 1414 | |
| 1415 visitDoWhile(DoWhile node) { | |
| 1416 visitLoopBodyIn(node, node.body, new BlockScope(scope)); | |
| 1417 visit(node.condition); | |
| 1418 } | |
| 1419 | |
| 1420 visitEmptyStatement(EmptyStatement node) { } | |
| 1421 | |
| 1422 visitExpressionStatement(ExpressionStatement node) { | |
| 1423 ExpressionStatement oldExpressionStatement = currentExpressionStatement; | |
| 1424 currentExpressionStatement = node; | |
| 1425 visit(node.expression); | |
| 1426 currentExpressionStatement = oldExpressionStatement; | |
| 1427 } | |
| 1428 | |
| 1429 visitFor(For node) { | |
| 1430 Scope blockScope = new BlockScope(scope); | |
| 1431 visitIn(node.initializer, blockScope); | |
| 1432 visitIn(node.condition, blockScope); | |
| 1433 visitIn(node.update, blockScope); | |
| 1434 visitLoopBodyIn(node, node.body, blockScope); | |
| 1435 } | |
| 1436 | |
| 1437 visitFunctionDeclaration(FunctionDeclaration node) { | |
| 1438 assert(node.function.name != null); | |
| 1439 visit(node.function); | |
| 1440 FunctionElement functionElement = mapping[node.function]; | |
| 1441 // TODO(floitsch): this might lead to two errors complaining about | |
| 1442 // shadowing. | |
| 1443 defineElement(node, functionElement); | |
| 1444 } | |
| 1445 | |
| 1446 visitFunctionExpression(FunctionExpression node) { | |
| 1447 visit(node.returnType); | |
| 1448 SourceString name; | |
| 1449 if (node.name == null) { | |
| 1450 name = const SourceString(""); | |
| 1451 } else { | |
| 1452 name = node.name.asIdentifier().source; | |
| 1453 } | |
| 1454 | |
| 1455 FunctionElement function = new FunctionElement.node( | |
| 1456 name, node, ElementKind.FUNCTION, Modifiers.EMPTY, | |
| 1457 enclosingElement); | |
| 1458 setupFunction(node, function); | |
| 1459 defineElement(node, function, doAddToScope: node.name !== null); | |
| 1460 | |
| 1461 Element previousEnclosingElement = enclosingElement; | |
| 1462 enclosingElement = function; | |
| 1463 // Run the body in a fresh statement scope. | |
| 1464 StatementScope oldScope = statementScope; | |
| 1465 statementScope = new StatementScope(); | |
| 1466 visit(node.body); | |
| 1467 statementScope = oldScope; | |
| 1468 | |
| 1469 scope = scope.parent; | |
| 1470 enclosingElement = previousEnclosingElement; | |
| 1471 } | |
| 1472 | |
| 1473 visitIf(If node) { | |
| 1474 visit(node.condition); | |
| 1475 visit(node.thenPart); | |
| 1476 visit(node.elsePart); | |
| 1477 } | |
| 1478 | |
| 1479 static bool isLogicalOperator(Identifier op) { | |
| 1480 String str = op.source.stringValue; | |
| 1481 return (identical(str, '&&') || str == '||' || str == '!'); | |
| 1482 } | |
| 1483 | |
| 1484 Element resolveSend(Send node) { | |
| 1485 Selector selector = resolveSelector(node); | |
| 1486 | |
| 1487 if (node.receiver == null) { | |
| 1488 // If this send is of the form "assert(expr);", then | |
| 1489 // this is an assertion. | |
| 1490 if (selector.isAssert()) { | |
| 1491 if (selector.argumentCount != 1) { | |
| 1492 error(node.selector, | |
| 1493 MessageKind.WRONG_NUMBER_OF_ARGUMENTS_FOR_ASSERT, | |
| 1494 [selector.argumentCount]); | |
| 1495 } else if (selector.namedArgumentCount != 0) { | |
| 1496 error(node.selector, | |
| 1497 MessageKind.ASSERT_IS_GIVEN_NAMED_ARGUMENTS, | |
| 1498 [selector.namedArgumentCount]); | |
| 1499 } | |
| 1500 return compiler.assertMethod; | |
| 1501 } | |
| 1502 return node.selector.accept(this); | |
| 1503 } | |
| 1504 | |
| 1505 var oldCategory = allowedCategory; | |
| 1506 allowedCategory |= | |
| 1507 ElementCategory.CLASS | ElementCategory.PREFIX | ElementCategory.SUPER; | |
| 1508 Element resolvedReceiver = visit(node.receiver); | |
| 1509 allowedCategory = oldCategory; | |
| 1510 | |
| 1511 Element target; | |
| 1512 SourceString name = node.selector.asIdentifier().source; | |
| 1513 if (identical(name.stringValue, 'this')) { | |
| 1514 error(node.selector, MessageKind.GENERIC, ["expected an identifier"]); | |
| 1515 } else if (node.isSuperCall) { | |
| 1516 if (node.isOperator) { | |
| 1517 if (isUserDefinableOperator(name.stringValue)) { | |
| 1518 name = selector.name; | |
| 1519 } else { | |
| 1520 error(node.selector, MessageKind.ILLEGAL_SUPER_SEND, [name]); | |
| 1521 } | |
| 1522 } | |
| 1523 if (!inInstanceContext) { | |
| 1524 error(node.receiver, MessageKind.NO_INSTANCE_AVAILABLE, [name]); | |
| 1525 return null; | |
| 1526 } | |
| 1527 if (currentClass.supertype == null) { | |
| 1528 // This is just to guard against internal errors, so no need | |
| 1529 // for a real error message. | |
| 1530 error(node.receiver, MessageKind.GENERIC, ["Object has no superclass"]); | |
| 1531 } | |
| 1532 // TODO(johnniwinther): Ensure correct behavior if currentClass is a | |
| 1533 // patch. | |
| 1534 target = currentClass.lookupSuperMember(name); | |
| 1535 // [target] may be null which means invoking noSuchMethod on | |
| 1536 // super. | |
| 1537 } else if (Elements.isUnresolved(resolvedReceiver)) { | |
| 1538 return null; | |
| 1539 } else if (identical(resolvedReceiver.kind, ElementKind.CLASS)) { | |
| 1540 ClassElement receiverClass = resolvedReceiver; | |
| 1541 receiverClass.ensureResolved(compiler); | |
| 1542 target = receiverClass.buildLocalScope().lookup(name); | |
| 1543 if (target == null) { | |
| 1544 // TODO(johnniwinther): With the simplified [TreeElements] invariant, | |
| 1545 // try to resolve injected elements if [currentClass] is in the patch | |
| 1546 // library of [receiverClass]. | |
| 1547 | |
| 1548 // TODO(karlklose): this should be reported by the caller of | |
| 1549 // [resolveSend] to select better warning messages for getters and | |
| 1550 // setters. | |
| 1551 return warnAndCreateErroneousElement(node, name, | |
| 1552 MessageKind.METHOD_NOT_FOUND, | |
| 1553 [receiverClass.name, name]); | |
| 1554 } else if (target.isInstanceMember()) { | |
| 1555 error(node, MessageKind.MEMBER_NOT_STATIC, [receiverClass.name, name]); | |
| 1556 } | |
| 1557 } else if (identical(resolvedReceiver.kind, ElementKind.PREFIX)) { | |
| 1558 PrefixElement prefix = resolvedReceiver; | |
| 1559 target = prefix.lookupLocalMember(name); | |
| 1560 if (target == null) { | |
| 1561 error(node, MessageKind.NO_SUCH_LIBRARY_MEMBER, [prefix.name, name]); | |
| 1562 } | |
| 1563 } | |
| 1564 return target; | |
| 1565 } | |
| 1566 | |
| 1567 DartType resolveTypeTest(Node argument) { | |
| 1568 TypeAnnotation node = argument.asTypeAnnotation(); | |
| 1569 if (node == null) { | |
| 1570 // node is of the form !Type. | |
| 1571 node = argument.asSend().receiver.asTypeAnnotation(); | |
| 1572 if (node == null) compiler.cancel("malformed send"); | |
| 1573 } | |
| 1574 return resolveTypeRequired(node); | |
| 1575 } | |
| 1576 | |
| 1577 static Selector computeSendSelector(Send node, LibraryElement library) { | |
| 1578 // First determine if this is part of an assignment. | |
| 1579 bool isSet = node.asSendSet() != null; | |
| 1580 | |
| 1581 if (node.isIndex) { | |
| 1582 return isSet ? new Selector.indexSet() : new Selector.index(); | |
| 1583 } | |
| 1584 | |
| 1585 if (node.isOperator) { | |
| 1586 SourceString source = node.selector.asOperator().source; | |
| 1587 String string = source.stringValue; | |
| 1588 if (identical(string, '!') || identical(string, '&&') || string == '||'
|| | |
| 1589 identical(string, 'is') || identical(string, 'as') || | |
| 1590 identical(string, '===') || identical(string, '!==') || | |
| 1591 identical(string, '>>>')) { | |
| 1592 return null; | |
| 1593 } | |
| 1594 return node.arguments.isEmpty() | |
| 1595 ? new Selector.unaryOperator(source) | |
| 1596 : new Selector.binaryOperator(source); | |
| 1597 } | |
| 1598 | |
| 1599 Identifier identifier = node.selector.asIdentifier(); | |
| 1600 if (node.isPropertyAccess) { | |
| 1601 assert(!isSet); | |
| 1602 return new Selector.getter(identifier.source, library); | |
| 1603 } else if (isSet) { | |
| 1604 return new Selector.setter(identifier.source, library); | |
| 1605 } | |
| 1606 | |
| 1607 // Compute the arity and the list of named arguments. | |
| 1608 int arity = 0; | |
| 1609 List<SourceString> named = <SourceString>[]; | |
| 1610 for (Link<Node> link = node.argumentsNode.nodes; | |
| 1611 !link.isEmpty(); | |
| 1612 link = link.tail) { | |
| 1613 Expression argument = link.head; | |
| 1614 NamedArgument namedArgument = argument.asNamedArgument(); | |
| 1615 if (namedArgument != null) { | |
| 1616 named.add(namedArgument.name.source); | |
| 1617 } | |
| 1618 arity++; | |
| 1619 } | |
| 1620 | |
| 1621 // If we're invoking a closure, we do not have an identifier. | |
| 1622 return (identifier == null) | |
| 1623 ? new Selector.callClosure(arity, named) | |
| 1624 : new Selector.call(identifier.source, library, arity, named); | |
| 1625 } | |
| 1626 | |
| 1627 Selector resolveSelector(Send node) { | |
| 1628 LibraryElement library = enclosingElement.getLibrary(); | |
| 1629 Selector selector = computeSendSelector(node, library); | |
| 1630 if (selector != null) mapping.setSelector(node, selector); | |
| 1631 return selector; | |
| 1632 } | |
| 1633 | |
| 1634 void resolveArguments(NodeList list) { | |
| 1635 if (list == null) return; | |
| 1636 bool seenNamedArgument = false; | |
| 1637 for (Link<Node> link = list.nodes; !link.isEmpty(); link = link.tail) { | |
| 1638 Expression argument = link.head; | |
| 1639 visit(argument); | |
| 1640 if (argument.asNamedArgument() != null) { | |
| 1641 seenNamedArgument = true; | |
| 1642 } else if (seenNamedArgument) { | |
| 1643 error(argument, MessageKind.INVALID_ARGUMENT_AFTER_NAMED); | |
| 1644 } | |
| 1645 } | |
| 1646 } | |
| 1647 | |
| 1648 visitSend(Send node) { | |
| 1649 Element target = resolveSend(node); | |
| 1650 if (!Elements.isUnresolved(target) | |
| 1651 && target.kind == ElementKind.ABSTRACT_FIELD) { | |
| 1652 AbstractFieldElement field = target; | |
| 1653 target = field.getter; | |
| 1654 if (target == null && !inInstanceContext) { | |
| 1655 target = | |
| 1656 warnAndCreateErroneousElement(node.selector, field.name, | |
| 1657 MessageKind.CANNOT_RESOLVE_GETTER, | |
| 1658 [node.selector]); | |
| 1659 } | |
| 1660 } | |
| 1661 | |
| 1662 bool resolvedArguments = false; | |
| 1663 if (node.isOperator) { | |
| 1664 String operatorString = node.selector.asOperator().source.stringValue; | |
| 1665 if (identical(operatorString, 'is') || identical(operatorString, 'as')) { | |
| 1666 assert(node.arguments.tail.isEmpty()); | |
| 1667 DartType type = resolveTypeTest(node.arguments.head); | |
| 1668 if (type != null) { | |
| 1669 compiler.enqueuer.resolution.registerIsCheck(type); | |
| 1670 } | |
| 1671 resolvedArguments = true; | |
| 1672 } else if (identical(operatorString, '?')) { | |
| 1673 Element parameter = mapping[node.receiver]; | |
| 1674 if (parameter == null | |
| 1675 || !identical(parameter.kind, ElementKind.PARAMETER)) { | |
| 1676 error(node.receiver, MessageKind.PARAMETER_NAME_EXPECTED); | |
| 1677 } else { | |
| 1678 mapping.checkedParameters.add(parameter); | |
| 1679 } | |
| 1680 } | |
| 1681 } | |
| 1682 | |
| 1683 if (!resolvedArguments) { | |
| 1684 resolveArguments(node.argumentsNode); | |
| 1685 } | |
| 1686 | |
| 1687 // If the selector is null, it means that we will not be generating | |
| 1688 // code for this as a send. | |
| 1689 Selector selector = mapping.getSelector(node); | |
| 1690 if (selector == null) return; | |
| 1691 | |
| 1692 // If we don't know what we're calling or if we are calling a getter, | |
| 1693 // we need to register that fact that we may be calling a closure | |
| 1694 // with the same arguments. | |
| 1695 if (node.isCall && | |
| 1696 (Elements.isUnresolved(target) || | |
| 1697 target.isGetter() || | |
| 1698 Elements.isClosureSend(node, target))) { | |
| 1699 Selector call = new Selector.callClosureFrom(selector); | |
| 1700 world.registerDynamicInvocation(call.name, call); | |
| 1701 } | |
| 1702 | |
| 1703 // TODO(ngeoffray): Warn if target is null and the send is | |
| 1704 // unqualified. | |
| 1705 useElement(node, target); | |
| 1706 registerSend(selector, target); | |
| 1707 return node.isPropertyAccess ? target : null; | |
| 1708 } | |
| 1709 | |
| 1710 visitSendSet(SendSet node) { | |
| 1711 Element target = resolveSend(node); | |
| 1712 Element setter = target; | |
| 1713 Element getter = target; | |
| 1714 SourceString operatorName = node.assignmentOperator.source; | |
| 1715 String source = operatorName.stringValue; | |
| 1716 bool isComplex = !identical(source, '='); | |
| 1717 if (!Elements.isUnresolved(target) | |
| 1718 && target.kind == ElementKind.ABSTRACT_FIELD) { | |
| 1719 AbstractFieldElement field = target; | |
| 1720 setter = field.setter; | |
| 1721 getter = field.getter; | |
| 1722 if (setter == null && !inInstanceContext) { | |
| 1723 setter = | |
| 1724 warnAndCreateErroneousElement(node.selector, field.name, | |
| 1725 MessageKind.CANNOT_RESOLVE_SETTER, | |
| 1726 [node.selector]); | |
| 1727 } | |
| 1728 if (isComplex && getter == null && !inInstanceContext) { | |
| 1729 getter = | |
| 1730 warnAndCreateErroneousElement(node.selector, field.name, | |
| 1731 MessageKind.CANNOT_RESOLVE_GETTER, | |
| 1732 [node.selector]); | |
| 1733 } | |
| 1734 } | |
| 1735 | |
| 1736 visit(node.argumentsNode); | |
| 1737 | |
| 1738 // TODO(ngeoffray): Check if the target can be assigned. | |
| 1739 // TODO(ngeoffray): Warn if target is null and the send is | |
| 1740 // unqualified. | |
| 1741 | |
| 1742 Selector selector = mapping.getSelector(node); | |
| 1743 if (isComplex) { | |
| 1744 if (selector.isSetter()) { | |
| 1745 // TODO(kasperl): We're registering the getter selector for | |
| 1746 // compound assignments on the AST selector node. In the code | |
| 1747 // generator, we then fetch it from there when generating the | |
| 1748 // getter for a SendSet node. | |
| 1749 Selector getterSelector = new Selector.getterFrom(selector); | |
| 1750 registerSend(getterSelector, getter); | |
| 1751 mapping.setSelector(node.selector, getterSelector); | |
| 1752 useElement(node.selector, getter); | |
| 1753 } else { | |
| 1754 // TODO(kasperl): If [getter] is resolved, it will actually | |
| 1755 // refer to the []= operator which isn't the one we want to | |
| 1756 // register here. We should consider using some notion of | |
| 1757 // abstract indexable element that we can resolve to so we can | |
| 1758 // distinguish the two. | |
| 1759 assert(selector.isIndexSet()); | |
| 1760 registerSend(new Selector.index(), null); | |
| 1761 } | |
| 1762 | |
| 1763 // Make sure we include the + and - operators if we are using | |
| 1764 // the ++ and -- ones. Also, if op= form is used, include op itself. | |
| 1765 void registerBinaryOperator(SourceString name) { | |
| 1766 Selector binop = new Selector.binaryOperator(name); | |
| 1767 world.registerDynamicInvocation(binop.name, binop); | |
| 1768 } | |
| 1769 if (identical(source, '++')) registerBinaryOperator(const SourceString('+'
)); | |
| 1770 if (identical(source, '--')) registerBinaryOperator(const SourceString('-'
)); | |
| 1771 if (source.endsWith('=')) { | |
| 1772 registerBinaryOperator(Elements.mapToUserOperator(operatorName)); | |
| 1773 } | |
| 1774 } | |
| 1775 | |
| 1776 registerSend(selector, setter); | |
| 1777 return useElement(node, setter); | |
| 1778 } | |
| 1779 | |
| 1780 void registerSend(Selector selector, Element target) { | |
| 1781 if (target == null || target.isInstanceMember()) { | |
| 1782 if (selector.isGetter()) { | |
| 1783 world.registerDynamicGetter(selector.name, selector); | |
| 1784 } else if (selector.isSetter()) { | |
| 1785 world.registerDynamicSetter(selector.name, selector); | |
| 1786 } else { | |
| 1787 world.registerDynamicInvocation(selector.name, selector); | |
| 1788 } | |
| 1789 } else if (Elements.isStaticOrTopLevel(target)) { | |
| 1790 // TODO(kasperl): It seems like we're not supposed to register | |
| 1791 // the use of classes. Wouldn't it be simpler if we just did? | |
| 1792 if (!target.isClass()) { | |
| 1793 // [target] might be the implementation element and only declaration | |
| 1794 // elements may be registered. | |
| 1795 world.registerStaticUse(target.declaration); | |
| 1796 } | |
| 1797 } | |
| 1798 if (target == null) { | |
| 1799 // If we haven't found an element for this send, it might be a | |
| 1800 // dynamic send on a primitive value. Register the selector with | |
| 1801 // the world to add an interceptor, if necessary. | |
| 1802 world.registerUsedSelector(selector); | |
| 1803 } | |
| 1804 } | |
| 1805 | |
| 1806 visitLiteralInt(LiteralInt node) { | |
| 1807 } | |
| 1808 | |
| 1809 visitLiteralDouble(LiteralDouble node) { | |
| 1810 } | |
| 1811 | |
| 1812 visitLiteralBool(LiteralBool node) { | |
| 1813 } | |
| 1814 | |
| 1815 visitLiteralString(LiteralString node) { | |
| 1816 } | |
| 1817 | |
| 1818 visitLiteralNull(LiteralNull node) { | |
| 1819 } | |
| 1820 | |
| 1821 visitStringJuxtaposition(StringJuxtaposition node) { | |
| 1822 node.visitChildren(this); | |
| 1823 } | |
| 1824 | |
| 1825 visitNodeList(NodeList node) { | |
| 1826 for (Link<Node> link = node.nodes; !link.isEmpty(); link = link.tail) { | |
| 1827 visit(link.head); | |
| 1828 } | |
| 1829 } | |
| 1830 | |
| 1831 visitOperator(Operator node) { | |
| 1832 unimplemented(node, 'operator'); | |
| 1833 } | |
| 1834 | |
| 1835 visitReturn(Return node) { | |
| 1836 if (node.isRedirectingConstructorBody) { | |
| 1837 unimplemented(node, 'redirecting constructors'); | |
| 1838 } | |
| 1839 visit(node.expression); | |
| 1840 } | |
| 1841 | |
| 1842 visitThrow(Throw node) { | |
| 1843 if (!inCatchBlock && node.expression == null) { | |
| 1844 error(node, MessageKind.THROW_WITHOUT_EXPRESSION); | |
| 1845 } | |
| 1846 visit(node.expression); | |
| 1847 } | |
| 1848 | |
| 1849 visitVariableDefinitions(VariableDefinitions node) { | |
| 1850 visit(node.type); | |
| 1851 VariableDefinitionsVisitor visitor = | |
| 1852 new VariableDefinitionsVisitor(compiler, node, this, | |
| 1853 ElementKind.VARIABLE); | |
| 1854 visitor.visit(node.definitions); | |
| 1855 } | |
| 1856 | |
| 1857 visitWhile(While node) { | |
| 1858 visit(node.condition); | |
| 1859 visitLoopBodyIn(node, node.body, new BlockScope(scope)); | |
| 1860 } | |
| 1861 | |
| 1862 visitParenthesizedExpression(ParenthesizedExpression node) { | |
| 1863 visit(node.expression); | |
| 1864 } | |
| 1865 | |
| 1866 visitNewExpression(NewExpression node) { | |
| 1867 Node selector = node.send.selector; | |
| 1868 FunctionElement constructor = resolveConstructor(node); | |
| 1869 resolveSelector(node.send); | |
| 1870 resolveArguments(node.send.argumentsNode); | |
| 1871 useElement(node.send, constructor); | |
| 1872 if (Elements.isUnresolved(constructor)) return constructor; | |
| 1873 // TODO(karlklose): handle optional arguments. | |
| 1874 if (node.send.argumentCount() != constructor.parameterCount(compiler)) { | |
| 1875 // TODO(ngeoffray): resolution error with wrong number of | |
| 1876 // parameters. We cannot do this rigth now because of the | |
| 1877 // List constructor. | |
| 1878 } | |
| 1879 // [constructor] might be the implementation element and only declaration | |
| 1880 // elements may be registered. | |
| 1881 world.registerStaticUse(constructor.declaration); | |
| 1882 compiler.withCurrentElement(constructor, () { | |
| 1883 FunctionExpression tree = constructor.parseNode(compiler); | |
| 1884 compiler.resolver.resolveConstructorImplementation(constructor, tree); | |
| 1885 }); | |
| 1886 // [constructor.defaultImplementation] might be the implementation element | |
| 1887 // and only declaration elements may be registered. | |
| 1888 world.registerStaticUse(constructor.defaultImplementation.declaration); | |
| 1889 ClassElement cls = constructor.defaultImplementation.getEnclosingClass(); | |
| 1890 // [cls] might be the implementation element and only declaration elements | |
| 1891 // may be registered. | |
| 1892 world.registerInstantiatedClass(cls.declaration); | |
| 1893 // [cls] might be the declaration element and we want to include injected | |
| 1894 // members. | |
| 1895 cls.implementation.forEachInstanceField( | |
| 1896 (ClassElement enclosingClass, Element member) { | |
| 1897 world.addToWorkList(member); | |
| 1898 }, | |
| 1899 includeBackendMembers: false, | |
| 1900 includeSuperMembers: true); | |
| 1901 return null; | |
| 1902 } | |
| 1903 | |
| 1904 /** | |
| 1905 * Try to resolve the constructor that is referred to by [node]. | |
| 1906 * Note: this function may return an ErroneousFunctionElement instead of | |
| 1907 * [null], if there is no corresponding constructor, class or library. | |
| 1908 */ | |
| 1909 FunctionElement resolveConstructor(NewExpression node) { | |
| 1910 // Resolve the constructor that [node] refers to. | |
| 1911 ConstructorResolver visitor = | |
| 1912 new ConstructorResolver(compiler, this, node.isConst()); | |
| 1913 FunctionElement constructor = node.accept(visitor); | |
| 1914 // Try to resolve the type that the new-expression constructs. | |
| 1915 TypeAnnotation annotation = node.send.getTypeAnnotation(); | |
| 1916 if (Elements.isUnresolved(constructor)) { | |
| 1917 // Resolve the type arguments. We cannot create a type and check the | |
| 1918 // number of type arguments for this annotation, because we do not know | |
| 1919 // the element. | |
| 1920 Link arguments = const Link<Node>(); | |
| 1921 if (annotation.typeArguments != null) { | |
| 1922 arguments = annotation.typeArguments.nodes; | |
| 1923 } | |
| 1924 for (Node argument in arguments) { | |
| 1925 resolveTypeRequired(argument); | |
| 1926 } | |
| 1927 } else { | |
| 1928 // Resolve and store the type this annotation resolves to. The type | |
| 1929 // is used in the backend, e.g., for creating runtime type information. | |
| 1930 // TODO(karlklose): This will resolve the class element again. Refactor | |
| 1931 // so we can use the TypeResolver. | |
| 1932 resolveTypeRequired(annotation); | |
| 1933 } | |
| 1934 return constructor; | |
| 1935 } | |
| 1936 | |
| 1937 DartType resolveTypeRequired(TypeAnnotation node) { | |
| 1938 bool old = typeRequired; | |
| 1939 typeRequired = true; | |
| 1940 DartType result = resolveTypeAnnotation(node); | |
| 1941 typeRequired = old; | |
| 1942 return result; | |
| 1943 } | |
| 1944 | |
| 1945 void analyzeTypeArgument(DartType annotation, DartType argument) { | |
| 1946 if (argument == null) return; | |
| 1947 if (argument.element.isTypeVariable()) { | |
| 1948 // Register a dependency between the class where the type | |
| 1949 // variable is, and the annotation. If the annotation requires | |
| 1950 // runtime type information, then the class of the type variable | |
| 1951 // does too. | |
| 1952 compiler.world.registerRtiDependency( | |
| 1953 annotation.element, | |
| 1954 argument.element.enclosingElement); | |
| 1955 } else if (argument is InterfaceType) { | |
| 1956 InterfaceType type = argument; | |
| 1957 type.arguments.forEach((DartType argument) { | |
| 1958 analyzeTypeArgument(type, argument); | |
| 1959 }); | |
| 1960 } | |
| 1961 } | |
| 1962 | |
| 1963 DartType resolveTypeAnnotation(TypeAnnotation node) { | |
| 1964 Function report = typeRequired ? error : warning; | |
| 1965 DartType type = typeResolver.resolveTypeAnnotation(node, inScope: scope, | |
| 1966 onFailure: report, | |
| 1967 whenResolved: useType); | |
| 1968 if (type == null) return null; | |
| 1969 if (inCheckContext) { | |
| 1970 compiler.enqueuer.resolution.registerIsCheck(type); | |
| 1971 } | |
| 1972 if (typeRequired || inCheckContext) { | |
| 1973 if (type is InterfaceType) { | |
| 1974 InterfaceType itf = type; | |
| 1975 itf.arguments.forEach((DartType argument) { | |
| 1976 analyzeTypeArgument(type, argument); | |
| 1977 }); | |
| 1978 } | |
| 1979 // TODO(ngeoffray): Also handle cases like: | |
| 1980 // 1) a is T | |
| 1981 // 2) T a (in checked mode). | |
| 1982 } | |
| 1983 return type; | |
| 1984 } | |
| 1985 | |
| 1986 visitModifiers(Modifiers node) { | |
| 1987 // TODO(ngeoffray): Implement this. | |
| 1988 unimplemented(node, 'modifiers'); | |
| 1989 } | |
| 1990 | |
| 1991 visitLiteralList(LiteralList node) { | |
| 1992 NodeList arguments = node.typeArguments; | |
| 1993 if (arguments != null) { | |
| 1994 Link<Node> nodes = arguments.nodes; | |
| 1995 if (nodes.isEmpty()) { | |
| 1996 error(arguments, MessageKind.MISSING_TYPE_ARGUMENT, []); | |
| 1997 } else { | |
| 1998 resolveTypeRequired(nodes.head); | |
| 1999 for (nodes = nodes.tail; !nodes.isEmpty(); nodes = nodes.tail) { | |
| 2000 error(nodes.head, MessageKind.ADDITIONAL_TYPE_ARGUMENT, []); | |
| 2001 resolveTypeRequired(nodes.head); | |
| 2002 } | |
| 2003 } | |
| 2004 } | |
| 2005 visit(node.elements); | |
| 2006 } | |
| 2007 | |
| 2008 visitConditional(Conditional node) { | |
| 2009 node.visitChildren(this); | |
| 2010 } | |
| 2011 | |
| 2012 visitStringInterpolation(StringInterpolation node) { | |
| 2013 node.visitChildren(this); | |
| 2014 } | |
| 2015 | |
| 2016 visitStringInterpolationPart(StringInterpolationPart node) { | |
| 2017 registerImplicitInvocation(const SourceString('toString'), 0); | |
| 2018 node.visitChildren(this); | |
| 2019 } | |
| 2020 | |
| 2021 visitBreakStatement(BreakStatement node) { | |
| 2022 TargetElement target; | |
| 2023 if (node.target == null) { | |
| 2024 target = statementScope.currentBreakTarget(); | |
| 2025 if (target == null) { | |
| 2026 error(node, MessageKind.NO_BREAK_TARGET); | |
| 2027 return; | |
| 2028 } | |
| 2029 target.isBreakTarget = true; | |
| 2030 } else { | |
| 2031 String labelName = node.target.source.slowToString(); | |
| 2032 LabelElement label = statementScope.lookupLabel(labelName); | |
| 2033 if (label == null) { | |
| 2034 error(node.target, MessageKind.UNBOUND_LABEL, [labelName]); | |
| 2035 return; | |
| 2036 } | |
| 2037 target = label.target; | |
| 2038 if (!target.statement.isValidBreakTarget()) { | |
| 2039 error(node.target, MessageKind.INVALID_BREAK, [labelName]); | |
| 2040 return; | |
| 2041 } | |
| 2042 label.setBreakTarget(); | |
| 2043 mapping[node.target] = label; | |
| 2044 } | |
| 2045 mapping[node] = target; | |
| 2046 } | |
| 2047 | |
| 2048 visitContinueStatement(ContinueStatement node) { | |
| 2049 TargetElement target; | |
| 2050 if (node.target == null) { | |
| 2051 target = statementScope.currentContinueTarget(); | |
| 2052 if (target == null) { | |
| 2053 error(node, MessageKind.NO_CONTINUE_TARGET); | |
| 2054 return; | |
| 2055 } | |
| 2056 target.isContinueTarget = true; | |
| 2057 } else { | |
| 2058 String labelName = node.target.source.slowToString(); | |
| 2059 LabelElement label = statementScope.lookupLabel(labelName); | |
| 2060 if (label == null) { | |
| 2061 error(node.target, MessageKind.UNBOUND_LABEL, [labelName]); | |
| 2062 return; | |
| 2063 } | |
| 2064 target = label.target; | |
| 2065 if (!target.statement.isValidContinueTarget()) { | |
| 2066 error(node.target, MessageKind.INVALID_CONTINUE, [labelName]); | |
| 2067 } | |
| 2068 // TODO(lrn): Handle continues to switch cases. | |
| 2069 if (target.statement is SwitchCase) { | |
| 2070 unimplemented(node, "continue to switch case"); | |
| 2071 } | |
| 2072 label.setContinueTarget(); | |
| 2073 mapping[node.target] = label; | |
| 2074 } | |
| 2075 mapping[node] = target; | |
| 2076 } | |
| 2077 | |
| 2078 registerImplicitInvocation(SourceString name, int arity) { | |
| 2079 Selector selector = new Selector.call(name, null, arity); | |
| 2080 world.registerDynamicInvocation(name, selector); | |
| 2081 } | |
| 2082 | |
| 2083 visitForIn(ForIn node) { | |
| 2084 for (final name in const [ | |
| 2085 const SourceString('iterator'), | |
| 2086 const SourceString('next'), | |
| 2087 const SourceString('hasNext')]) { | |
| 2088 registerImplicitInvocation(name, 0); | |
| 2089 } | |
| 2090 visit(node.expression); | |
| 2091 Scope blockScope = new BlockScope(scope); | |
| 2092 Node declaration = node.declaredIdentifier; | |
| 2093 visitIn(declaration, blockScope); | |
| 2094 visitLoopBodyIn(node, node.body, blockScope); | |
| 2095 | |
| 2096 // TODO(lrn): Also allow a single identifier. | |
| 2097 if ((declaration is !Send || declaration.asSend().selector is !Identifier | |
| 2098 || declaration.asSend().receiver != null) | |
| 2099 && (declaration is !VariableDefinitions || | |
| 2100 !declaration.asVariableDefinitions().definitions.nodes.tail.isEmpty())) | |
| 2101 { | |
| 2102 // The variable declaration is either not an identifier, not a | |
| 2103 // declaration, or it's declaring more than one variable. | |
| 2104 error(node.declaredIdentifier, MessageKind.INVALID_FOR_IN, []); | |
| 2105 } | |
| 2106 } | |
| 2107 | |
| 2108 visitLabel(Label node) { | |
| 2109 // Labels are handled by their containing statements/cases. | |
| 2110 } | |
| 2111 | |
| 2112 visitLabeledStatement(LabeledStatement node) { | |
| 2113 Statement body = node.statement; | |
| 2114 TargetElement targetElement = getOrCreateTargetElement(body); | |
| 2115 Map<String, LabelElement> labelElements = <String, LabelElement>{}; | |
| 2116 for (Label label in node.labels) { | |
| 2117 String labelName = label.slowToString(); | |
| 2118 if (labelElements.containsKey(labelName)) continue; | |
| 2119 LabelElement element = targetElement.addLabel(label, labelName); | |
| 2120 labelElements[labelName] = element; | |
| 2121 } | |
| 2122 statementScope.enterLabelScope(labelElements); | |
| 2123 visit(node.statement); | |
| 2124 statementScope.exitLabelScope(); | |
| 2125 labelElements.forEach((String labelName, LabelElement element) { | |
| 2126 if (element.isTarget) { | |
| 2127 mapping[element.label] = element; | |
| 2128 } else { | |
| 2129 warning(element.label, MessageKind.UNUSED_LABEL, [labelName]); | |
| 2130 } | |
| 2131 }); | |
| 2132 if (!targetElement.isTarget && identical(mapping[body], targetElement)) { | |
| 2133 // If the body is itself a break or continue for another target, it | |
| 2134 // might have updated its mapping to the target it actually does target. | |
| 2135 mapping.remove(body); | |
| 2136 } | |
| 2137 } | |
| 2138 | |
| 2139 visitLiteralMap(LiteralMap node) { | |
| 2140 node.visitChildren(this); | |
| 2141 } | |
| 2142 | |
| 2143 visitLiteralMapEntry(LiteralMapEntry node) { | |
| 2144 node.visitChildren(this); | |
| 2145 } | |
| 2146 | |
| 2147 visitNamedArgument(NamedArgument node) { | |
| 2148 visit(node.expression); | |
| 2149 } | |
| 2150 | |
| 2151 visitSwitchStatement(SwitchStatement node) { | |
| 2152 node.expression.accept(this); | |
| 2153 | |
| 2154 TargetElement breakElement = getOrCreateTargetElement(node); | |
| 2155 Map<String, LabelElement> continueLabels = <String, LabelElement>{}; | |
| 2156 Link<Node> cases = node.cases.nodes; | |
| 2157 while (!cases.isEmpty()) { | |
| 2158 SwitchCase switchCase = cases.head; | |
| 2159 for (Node labelOrCase in switchCase.labelsAndCases) { | |
| 2160 if (labelOrCase is! Label) continue; | |
| 2161 Label label = labelOrCase; | |
| 2162 String labelName = label.slowToString(); | |
| 2163 | |
| 2164 LabelElement existingElement = continueLabels[labelName]; | |
| 2165 if (existingElement != null) { | |
| 2166 // It's an error if the same label occurs twice in the same switch. | |
| 2167 warning(label, MessageKind.DUPLICATE_LABEL, [labelName]); | |
| 2168 error(existingElement.label, MessageKind.EXISTING_LABEL, [labelName]); | |
| 2169 } else { | |
| 2170 // It's only a warning if it shadows another label. | |
| 2171 existingElement = statementScope.lookupLabel(labelName); | |
| 2172 if (existingElement != null) { | |
| 2173 warning(label, MessageKind.DUPLICATE_LABEL, [labelName]); | |
| 2174 warning(existingElement.label, | |
| 2175 MessageKind.EXISTING_LABEL, [labelName]); | |
| 2176 } | |
| 2177 } | |
| 2178 | |
| 2179 TargetElement targetElement = | |
| 2180 new TargetElement(switchCase, | |
| 2181 statementScope.nestingLevel, | |
| 2182 enclosingElement); | |
| 2183 mapping[switchCase] = targetElement; | |
| 2184 | |
| 2185 LabelElement labelElement = | |
| 2186 new LabelElement(label, labelName, | |
| 2187 targetElement, enclosingElement); | |
| 2188 mapping[label] = labelElement; | |
| 2189 continueLabels[labelName] = labelElement; | |
| 2190 } | |
| 2191 cases = cases.tail; | |
| 2192 // Test that only the last case, if any, is a default case. | |
| 2193 if (switchCase.defaultKeyword != null && !cases.isEmpty()) { | |
| 2194 error(switchCase, MessageKind.INVALID_CASE_DEFAULT); | |
| 2195 } | |
| 2196 } | |
| 2197 | |
| 2198 statementScope.enterSwitch(breakElement, continueLabels); | |
| 2199 node.cases.accept(this); | |
| 2200 statementScope.exitSwitch(); | |
| 2201 | |
| 2202 // Clean-up unused labels. | |
| 2203 continueLabels.forEach((String key, LabelElement label) { | |
| 2204 if (!label.isContinueTarget) { | |
| 2205 TargetElement targetElement = label.target; | |
| 2206 SwitchCase switchCase = targetElement.statement; | |
| 2207 mapping.remove(switchCase); | |
| 2208 mapping.remove(label.label); | |
| 2209 } | |
| 2210 }); | |
| 2211 } | |
| 2212 | |
| 2213 visitSwitchCase(SwitchCase node) { | |
| 2214 node.labelsAndCases.accept(this); | |
| 2215 visitIn(node.statements, new BlockScope(scope)); | |
| 2216 } | |
| 2217 | |
| 2218 visitCaseMatch(CaseMatch node) { | |
| 2219 visit(node.expression); | |
| 2220 } | |
| 2221 | |
| 2222 visitTryStatement(TryStatement node) { | |
| 2223 visit(node.tryBlock); | |
| 2224 if (node.catchBlocks.isEmpty() && node.finallyBlock == null) { | |
| 2225 // TODO(ngeoffray): The precise location is | |
| 2226 // node.getEndtoken.next. Adjust when issue #1581 is fixed. | |
| 2227 error(node, MessageKind.NO_CATCH_NOR_FINALLY); | |
| 2228 } | |
| 2229 visit(node.catchBlocks); | |
| 2230 visit(node.finallyBlock); | |
| 2231 } | |
| 2232 | |
| 2233 visitCatchBlock(CatchBlock node) { | |
| 2234 // Check that if catch part is present, then | |
| 2235 // it has one or two formal parameters. | |
| 2236 if (node.formals != null) { | |
| 2237 if (node.formals.isEmpty()) { | |
| 2238 error(node, MessageKind.EMPTY_CATCH_DECLARATION); | |
| 2239 } | |
| 2240 if (!node.formals.nodes.tail.isEmpty() && | |
| 2241 !node.formals.nodes.tail.tail.isEmpty()) { | |
| 2242 for (Node extra in node.formals.nodes.tail.tail) { | |
| 2243 error(extra, MessageKind.EXTRA_CATCH_DECLARATION); | |
| 2244 } | |
| 2245 } | |
| 2246 | |
| 2247 // Check that the formals aren't optional and that they have no | |
| 2248 // modifiers or type. | |
| 2249 for (Link<Node> link = node.formals.nodes; | |
| 2250 !link.isEmpty(); | |
| 2251 link = link.tail) { | |
| 2252 // If the formal parameter is a node list, it means that it is a | |
| 2253 // sequence of optional parameters. | |
| 2254 NodeList nodeList = link.head.asNodeList(); | |
| 2255 if (nodeList != null) { | |
| 2256 error(nodeList, MessageKind.OPTIONAL_PARAMETER_IN_CATCH); | |
| 2257 } else { | |
| 2258 VariableDefinitions declaration = link.head; | |
| 2259 for (Node modifier in declaration.modifiers.nodes) { | |
| 2260 error(modifier, MessageKind.PARAMETER_WITH_MODIFIER_IN_CATCH); | |
| 2261 } | |
| 2262 TypeAnnotation type = declaration.type; | |
| 2263 if (type != null) { | |
| 2264 error(type, MessageKind.PARAMETER_WITH_TYPE_IN_CATCH); | |
| 2265 } | |
| 2266 } | |
| 2267 } | |
| 2268 } | |
| 2269 | |
| 2270 Scope blockScope = new BlockScope(scope); | |
| 2271 var wasTypeRequired = typeRequired; | |
| 2272 typeRequired = true; | |
| 2273 doInCheckContext(() => visitIn(node.type, blockScope)); | |
| 2274 typeRequired = wasTypeRequired; | |
| 2275 visitIn(node.formals, blockScope); | |
| 2276 var oldInCatchBlock = inCatchBlock; | |
| 2277 inCatchBlock = true; | |
| 2278 visitIn(node.block, blockScope); | |
| 2279 inCatchBlock = oldInCatchBlock; | |
| 2280 } | |
| 2281 | |
| 2282 visitTypedef(Typedef node) { | |
| 2283 unimplemented(node, 'typedef'); | |
| 2284 } | |
| 2285 } | |
| 2286 | |
| 2287 class TypeDefinitionVisitor extends CommonResolverVisitor<DartType> { | |
| 2288 Scope scope; | |
| 2289 TypeDeclarationElement element; | |
| 2290 TypeResolver typeResolver; | |
| 2291 | |
| 2292 TypeDefinitionVisitor(Compiler compiler, TypeDeclarationElement element) | |
| 2293 : this.element = element, | |
| 2294 scope = element.buildEnclosingScope(), | |
| 2295 typeResolver = new TypeResolver(compiler), | |
| 2296 super(compiler); | |
| 2297 | |
| 2298 void resolveTypeVariableBounds(NodeList node) { | |
| 2299 if (node == null) return; | |
| 2300 | |
| 2301 var nameSet = new Set<SourceString>(); | |
| 2302 // Resolve the bounds of type variables. | |
| 2303 Link<DartType> typeLink = element.typeVariables; | |
| 2304 Link<Node> nodeLink = node.nodes; | |
| 2305 while (!nodeLink.isEmpty()) { | |
| 2306 TypeVariableType typeVariable = typeLink.head; | |
| 2307 SourceString typeName = typeVariable.name; | |
| 2308 TypeVariable typeNode = nodeLink.head; | |
| 2309 if (nameSet.contains(typeName)) { | |
| 2310 error(typeNode, MessageKind.DUPLICATE_TYPE_VARIABLE_NAME, [typeName]); | |
| 2311 } | |
| 2312 nameSet.add(typeName); | |
| 2313 | |
| 2314 TypeVariableElement variableElement = typeVariable.element; | |
| 2315 if (typeNode.bound != null) { | |
| 2316 DartType boundType = typeResolver.resolveTypeAnnotation( | |
| 2317 typeNode.bound, inScope: scope, onFailure: warning); | |
| 2318 if (boundType != null && boundType.element == variableElement) { | |
| 2319 // TODO(johnniwinther): Check for more general cycles, like | |
| 2320 // [: <A extends B, B extends C, C extends B> :]. | |
| 2321 warning(node, MessageKind.CYCLIC_TYPE_VARIABLE, | |
| 2322 [variableElement.name]); | |
| 2323 } else if (boundType != null) { | |
| 2324 variableElement.bound = boundType; | |
| 2325 } else { | |
| 2326 // TODO(johnniwinther): Should be an erroneous type. | |
| 2327 variableElement.bound = compiler.objectClass.computeType(compiler); | |
| 2328 } | |
| 2329 } else { | |
| 2330 variableElement.bound = compiler.objectClass.computeType(compiler); | |
| 2331 } | |
| 2332 nodeLink = nodeLink.tail; | |
| 2333 typeLink = typeLink.tail; | |
| 2334 } | |
| 2335 assert(typeLink.isEmpty()); | |
| 2336 } | |
| 2337 } | |
| 2338 | |
| 2339 class TypedefResolverVisitor extends TypeDefinitionVisitor { | |
| 2340 TypedefElement get element => super.element; | |
| 2341 | |
| 2342 TypedefResolverVisitor(Compiler compiler, TypedefElement typedefElement) | |
| 2343 : super(compiler, typedefElement); | |
| 2344 | |
| 2345 visitTypedef(Typedef node) { | |
| 2346 TypedefType type = element.computeType(compiler); | |
| 2347 scope = new TypeDeclarationScope(scope, element); | |
| 2348 resolveTypeVariableBounds(node.typeParameters); | |
| 2349 | |
| 2350 element.functionSignature = SignatureResolver.analyze( | |
| 2351 compiler, node.formals, node.returnType, element); | |
| 2352 | |
| 2353 element.alias = compiler.computeFunctionType( | |
| 2354 element, element.functionSignature); | |
| 2355 | |
| 2356 // TODO(johnniwinther): Check for cyclic references in the typedef alias. | |
| 2357 } | |
| 2358 } | |
| 2359 | |
| 2360 /** | |
| 2361 * The implementation of [ResolverTask.resolveClass]. | |
| 2362 * | |
| 2363 * This visitor has to be extra careful as it is building the basic | |
| 2364 * element information, and cannot safely look at other elements as | |
| 2365 * this may lead to cycles. | |
| 2366 * | |
| 2367 * This visitor can assume that the supertypes have already been | |
| 2368 * resolved, but it cannot call [ResolverTask.resolveClass] directly | |
| 2369 * or indirectly (through [ClassElement.ensureResolved]) for any other | |
| 2370 * types. | |
| 2371 */ | |
| 2372 class ClassResolverVisitor extends TypeDefinitionVisitor { | |
| 2373 ClassElement get element => super.element; | |
| 2374 | |
| 2375 ClassResolverVisitor(Compiler compiler, ClassElement classElement) | |
| 2376 : super(compiler, classElement); | |
| 2377 | |
| 2378 DartType visitClassNode(ClassNode node) { | |
| 2379 compiler.ensure(element != null); | |
| 2380 compiler.ensure(element.resolutionState == STATE_STARTED); | |
| 2381 | |
| 2382 InterfaceType type = element.computeType(compiler); | |
| 2383 scope = new TypeDeclarationScope(scope, element); | |
| 2384 // TODO(ahe): It is not safe to call resolveTypeVariableBounds yet. | |
| 2385 // As a side-effect, this may get us back here trying to | |
| 2386 // resolve this class again. | |
| 2387 resolveTypeVariableBounds(node.typeParameters); | |
| 2388 | |
| 2389 // Find super type. | |
| 2390 DartType supertype = visit(node.superclass); | |
| 2391 if (supertype != null && supertype.element.isExtendable()) { | |
| 2392 element.supertype = supertype; | |
| 2393 if (isBlackListed(supertype)) { | |
| 2394 error(node.superclass, MessageKind.CANNOT_EXTEND, [supertype]); | |
| 2395 } | |
| 2396 } else if (supertype != null) { | |
| 2397 error(node.superclass, MessageKind.TYPE_NAME_EXPECTED); | |
| 2398 } | |
| 2399 final objectElement = compiler.objectClass; | |
| 2400 if (!identical(element, objectElement) && element.supertype == null) { | |
| 2401 if (objectElement == null) { | |
| 2402 compiler.internalError("Internal error: cannot resolve Object", | |
| 2403 node: node); | |
| 2404 } else { | |
| 2405 objectElement.ensureResolved(compiler); | |
| 2406 } | |
| 2407 // TODO(ahe): This should be objectElement.computeType(...). | |
| 2408 element.supertype = new InterfaceType(objectElement); | |
| 2409 } | |
| 2410 assert(element.interfaces == null); | |
| 2411 Link<DartType> interfaces = const Link<DartType>(); | |
| 2412 for (Link<Node> link = node.interfaces.nodes; | |
| 2413 !link.isEmpty(); | |
| 2414 link = link.tail) { | |
| 2415 DartType interfaceType = visit(link.head); | |
| 2416 if (interfaceType != null && interfaceType.element.isExtendable()) { | |
| 2417 interfaces = interfaces.prepend(interfaceType); | |
| 2418 if (isBlackListed(interfaceType)) { | |
| 2419 error(link.head, MessageKind.CANNOT_IMPLEMENT, [interfaceType]); | |
| 2420 } | |
| 2421 } else { | |
| 2422 error(link.head, MessageKind.TYPE_NAME_EXPECTED); | |
| 2423 } | |
| 2424 } | |
| 2425 element.interfaces = interfaces; | |
| 2426 calculateAllSupertypes(element); | |
| 2427 | |
| 2428 if (node.defaultClause != null) { | |
| 2429 element.defaultClass = visit(node.defaultClause); | |
| 2430 } | |
| 2431 addDefaultConstructorIfNeeded(element); | |
| 2432 return element.computeType(compiler); | |
| 2433 } | |
| 2434 | |
| 2435 DartType visitTypeAnnotation(TypeAnnotation node) { | |
| 2436 return visit(node.typeName); | |
| 2437 } | |
| 2438 | |
| 2439 DartType visitIdentifier(Identifier node) { | |
| 2440 Element element = scope.lookup(node.source); | |
| 2441 if (element == null) { | |
| 2442 error(node, MessageKind.CANNOT_RESOLVE_TYPE, [node]); | |
| 2443 return null; | |
| 2444 } else if (!element.impliesType() && !element.isTypeVariable()) { | |
| 2445 error(node, MessageKind.NOT_A_TYPE, [node]); | |
| 2446 return null; | |
| 2447 } else { | |
| 2448 if (element.isTypeVariable()) { | |
| 2449 TypeVariableElement variableElement = element; | |
| 2450 return variableElement.type; | |
| 2451 } else if (element.isTypedef()) { | |
| 2452 compiler.unimplemented('visitIdentifier for typedefs', node: node); | |
| 2453 } else { | |
| 2454 // TODO(ngeoffray): Use type variables. | |
| 2455 return element.computeType(compiler); | |
| 2456 } | |
| 2457 } | |
| 2458 return null; | |
| 2459 } | |
| 2460 | |
| 2461 DartType visitSend(Send node) { | |
| 2462 Identifier prefix = node.receiver.asIdentifier(); | |
| 2463 if (prefix == null) { | |
| 2464 error(node.receiver, MessageKind.NOT_A_PREFIX, [node.receiver]); | |
| 2465 return null; | |
| 2466 } | |
| 2467 Element element = scope.lookup(prefix.source); | |
| 2468 if (element == null || !identical(element.kind, ElementKind.PREFIX)) { | |
| 2469 error(node.receiver, MessageKind.NOT_A_PREFIX, [node.receiver]); | |
| 2470 return null; | |
| 2471 } | |
| 2472 PrefixElement prefixElement = element; | |
| 2473 Identifier selector = node.selector.asIdentifier(); | |
| 2474 var e = prefixElement.lookupLocalMember(selector.source); | |
| 2475 if (e == null || !e.impliesType()) { | |
| 2476 error(node.selector, MessageKind.CANNOT_RESOLVE_TYPE, [node.selector]); | |
| 2477 return null; | |
| 2478 } | |
| 2479 return e.computeType(compiler); | |
| 2480 } | |
| 2481 | |
| 2482 void calculateAllSupertypes(ClassElement cls) { | |
| 2483 // TODO(karlklose): substitute type variables. | |
| 2484 // TODO(karlklose): check if type arguments match, if a classelement occurs | |
| 2485 // more than once in the supertypes. | |
| 2486 if (cls.allSupertypes != null) return; | |
| 2487 final DartType supertype = cls.supertype; | |
| 2488 if (supertype != null) { | |
| 2489 ClassElement superElement = supertype.element; | |
| 2490 Link<DartType> superSupertypes = superElement.allSupertypes; | |
| 2491 assert(superSupertypes != null); | |
| 2492 Link<DartType> supertypes = superSupertypes.prepend(supertype); | |
| 2493 for (Link<DartType> interfaces = cls.interfaces; | |
| 2494 !interfaces.isEmpty(); | |
| 2495 interfaces = interfaces.tail) { | |
| 2496 ClassElement element = interfaces.head.element; | |
| 2497 Link<DartType> interfaceSupertypes = element.allSupertypes; | |
| 2498 assert(interfaceSupertypes != null); | |
| 2499 supertypes = supertypes.reversePrependAll(interfaceSupertypes); | |
| 2500 supertypes = supertypes.prepend(interfaces.head); | |
| 2501 } | |
| 2502 cls.allSupertypes = supertypes; | |
| 2503 } else { | |
| 2504 assert(identical(cls, compiler.objectClass)); | |
| 2505 cls.allSupertypes = const Link<DartType>(); | |
| 2506 } | |
| 2507 } | |
| 2508 | |
| 2509 /** | |
| 2510 * Add a synthetic nullary constructor if there are no other | |
| 2511 * constructors. | |
| 2512 */ | |
| 2513 void addDefaultConstructorIfNeeded(ClassElement element) { | |
| 2514 if (element.hasConstructor) return; | |
| 2515 SynthesizedConstructorElement constructor = | |
| 2516 new SynthesizedConstructorElement(element); | |
| 2517 element.addToScope(constructor, compiler); | |
| 2518 DartType returnType = compiler.types.voidType; | |
| 2519 constructor.type = new FunctionType(returnType, const Link<DartType>(), | |
| 2520 constructor); | |
| 2521 constructor.cachedNode = | |
| 2522 new FunctionExpression(new Identifier(element.position()), | |
| 2523 new NodeList.empty(), | |
| 2524 new Block(new NodeList.empty()), | |
| 2525 null, Modifiers.EMPTY, null, null); | |
| 2526 } | |
| 2527 | |
| 2528 isBlackListed(DartType type) { | |
| 2529 LibraryElement lib = element.getLibrary(); | |
| 2530 return | |
| 2531 !identical(lib, compiler.coreLibrary) && | |
| 2532 !identical(lib, compiler.coreImplLibrary) && | |
| 2533 !identical(lib, compiler.jsHelperLibrary) && | |
| 2534 (identical(type.element, compiler.dynamicClass) || | |
| 2535 identical(type.element, compiler.boolClass) || | |
| 2536 identical(type.element, compiler.numClass) || | |
| 2537 identical(type.element, compiler.intClass) || | |
| 2538 identical(type.element, compiler.doubleClass) || | |
| 2539 identical(type.element, compiler.stringClass) || | |
| 2540 identical(type.element, compiler.nullClass) || | |
| 2541 identical(type.element, compiler.functionClass)); | |
| 2542 } | |
| 2543 } | |
| 2544 | |
| 2545 class ClassSupertypeResolver extends CommonResolverVisitor { | |
| 2546 Scope context; | |
| 2547 ClassElement classElement; | |
| 2548 | |
| 2549 ClassSupertypeResolver(Compiler compiler, ClassElement cls) | |
| 2550 : context = cls.buildEnclosingScope(), | |
| 2551 this.classElement = cls, | |
| 2552 super(compiler); | |
| 2553 | |
| 2554 void loadSupertype(ClassElement element, Node from) { | |
| 2555 compiler.resolver.loadSupertypes(element, from); | |
| 2556 element.ensureResolved(compiler); | |
| 2557 } | |
| 2558 | |
| 2559 void visitClassNode(ClassNode node) { | |
| 2560 if (node.superclass == null) { | |
| 2561 if (!identical(classElement, compiler.objectClass)) { | |
| 2562 loadSupertype(compiler.objectClass, node); | |
| 2563 } | |
| 2564 } else { | |
| 2565 node.superclass.accept(this); | |
| 2566 } | |
| 2567 for (Link<Node> link = node.interfaces.nodes; | |
| 2568 !link.isEmpty(); | |
| 2569 link = link.tail) { | |
| 2570 link.head.accept(this); | |
| 2571 } | |
| 2572 } | |
| 2573 | |
| 2574 void visitTypeAnnotation(TypeAnnotation node) { | |
| 2575 node.typeName.accept(this); | |
| 2576 } | |
| 2577 | |
| 2578 void visitIdentifier(Identifier node) { | |
| 2579 Element element = context.lookup(node.source); | |
| 2580 if (element == null) { | |
| 2581 error(node, MessageKind.CANNOT_RESOLVE_TYPE, [node]); | |
| 2582 } else if (!element.impliesType()) { | |
| 2583 error(node, MessageKind.NOT_A_TYPE, [node]); | |
| 2584 } else { | |
| 2585 if (element.isClass()) { | |
| 2586 loadSupertype(element, node); | |
| 2587 } else { | |
| 2588 compiler.reportMessage( | |
| 2589 compiler.spanFromNode(node), | |
| 2590 MessageKind.TYPE_NAME_EXPECTED.error([]), | |
| 2591 api.Diagnostic.ERROR); | |
| 2592 } | |
| 2593 } | |
| 2594 } | |
| 2595 | |
| 2596 void visitSend(Send node) { | |
| 2597 Identifier prefix = node.receiver.asIdentifier(); | |
| 2598 if (prefix == null) { | |
| 2599 error(node.receiver, MessageKind.NOT_A_PREFIX, [node.receiver]); | |
| 2600 return; | |
| 2601 } | |
| 2602 Element element = context.lookup(prefix.source); | |
| 2603 if (element == null || !identical(element.kind, ElementKind.PREFIX)) { | |
| 2604 error(node.receiver, MessageKind.NOT_A_PREFIX, [node.receiver]); | |
| 2605 return; | |
| 2606 } | |
| 2607 PrefixElement prefixElement = element; | |
| 2608 Identifier selector = node.selector.asIdentifier(); | |
| 2609 var e = prefixElement.lookupLocalMember(selector.source); | |
| 2610 if (e == null || !e.impliesType()) { | |
| 2611 error(node.selector, MessageKind.CANNOT_RESOLVE_TYPE, [node.selector]); | |
| 2612 return; | |
| 2613 } | |
| 2614 loadSupertype(e, node); | |
| 2615 } | |
| 2616 } | |
| 2617 | |
| 2618 class VariableDefinitionsVisitor extends CommonResolverVisitor<SourceString> { | |
| 2619 VariableDefinitions definitions; | |
| 2620 ResolverVisitor resolver; | |
| 2621 ElementKind kind; | |
| 2622 VariableListElement variables; | |
| 2623 | |
| 2624 VariableDefinitionsVisitor(Compiler compiler, | |
| 2625 this.definitions, this.resolver, this.kind) | |
| 2626 : super(compiler) { | |
| 2627 variables = new VariableListElement.node( | |
| 2628 definitions, ElementKind.VARIABLE_LIST, resolver.scope.element); | |
| 2629 } | |
| 2630 | |
| 2631 SourceString visitSendSet(SendSet node) { | |
| 2632 assert(node.arguments.tail.isEmpty()); // Sanity check | |
| 2633 resolver.visit(node.arguments.head); | |
| 2634 return visit(node.selector); | |
| 2635 } | |
| 2636 | |
| 2637 SourceString visitIdentifier(Identifier node) => node.source; | |
| 2638 | |
| 2639 visitNodeList(NodeList node) { | |
| 2640 for (Link<Node> link = node.nodes; !link.isEmpty(); link = link.tail) { | |
| 2641 SourceString name = visit(link.head); | |
| 2642 VariableElement element = | |
| 2643 new VariableElement(name, variables, kind, link.head); | |
| 2644 resolver.defineElement(link.head, element); | |
| 2645 } | |
| 2646 } | |
| 2647 } | |
| 2648 | |
| 2649 /** | |
| 2650 * [SignatureResolver] resolves function signatures. | |
| 2651 */ | |
| 2652 class SignatureResolver extends CommonResolverVisitor<Element> { | |
| 2653 final Element enclosingElement; | |
| 2654 Link<Element> optionalParameters = const Link<Element>(); | |
| 2655 int optionalParameterCount = 0; | |
| 2656 bool optionalParametersAreNamed = false; | |
| 2657 VariableDefinitions currentDefinitions; | |
| 2658 | |
| 2659 SignatureResolver(Compiler compiler, this.enclosingElement) : super(compiler); | |
| 2660 | |
| 2661 Element visitNodeList(NodeList node) { | |
| 2662 // This must be a list of optional arguments. | |
| 2663 String value = node.beginToken.stringValue; | |
| 2664 if ((!identical(value, '[')) && (!identical(value, '{'))) { | |
| 2665 internalError(node, "expected optional parameters"); | |
| 2666 } | |
| 2667 optionalParametersAreNamed = (identical(value, '{')); | |
| 2668 LinkBuilder<Element> elements = analyzeNodes(node.nodes); | |
| 2669 optionalParameterCount = elements.length; | |
| 2670 optionalParameters = elements.toLink(); | |
| 2671 return null; | |
| 2672 } | |
| 2673 | |
| 2674 Element visitVariableDefinitions(VariableDefinitions node) { | |
| 2675 Link<Node> definitions = node.definitions.nodes; | |
| 2676 if (definitions.isEmpty()) { | |
| 2677 cancel(node, 'internal error: no parameter definition'); | |
| 2678 return null; | |
| 2679 } | |
| 2680 if (!definitions.tail.isEmpty()) { | |
| 2681 cancel(definitions.tail.head, 'internal error: extra definition'); | |
| 2682 return null; | |
| 2683 } | |
| 2684 Node definition = definitions.head; | |
| 2685 if (definition is NodeList) { | |
| 2686 cancel(node, 'optional parameters are not implemented'); | |
| 2687 } | |
| 2688 | |
| 2689 if (currentDefinitions != null) { | |
| 2690 cancel(node, 'function type parameters not supported'); | |
| 2691 } | |
| 2692 currentDefinitions = node; | |
| 2693 Element element = definition.accept(this); | |
| 2694 currentDefinitions = null; | |
| 2695 return element; | |
| 2696 } | |
| 2697 | |
| 2698 Element visitIdentifier(Identifier node) { | |
| 2699 Element variables = new VariableListElement.node(currentDefinitions, | |
| 2700 ElementKind.VARIABLE_LIST, enclosingElement); | |
| 2701 // Ensure a parameter is not typed 'void'. | |
| 2702 variables.computeType(compiler); | |
| 2703 return new VariableElement(node.source, variables, | |
| 2704 ElementKind.PARAMETER, node); | |
| 2705 } | |
| 2706 | |
| 2707 SourceString getParameterName(Send node) { | |
| 2708 var identifier = node.selector.asIdentifier(); | |
| 2709 if (identifier != null) { | |
| 2710 // Normal parameter: [:Type name:]. | |
| 2711 return identifier.source; | |
| 2712 } else { | |
| 2713 // Function type parameter: [:void name(DartType arg):]. | |
| 2714 var functionExpression = node.selector.asFunctionExpression(); | |
| 2715 if (functionExpression != null && | |
| 2716 functionExpression.name.asIdentifier() != null) { | |
| 2717 return functionExpression.name.asIdentifier().source; | |
| 2718 } else { | |
| 2719 cancel(node, | |
| 2720 'internal error: unimplemented receiver on parameter send'); | |
| 2721 } | |
| 2722 } | |
| 2723 } | |
| 2724 | |
| 2725 // The only valid [Send] can be in constructors and must be of the form | |
| 2726 // [:this.x:] (where [:x:] represents an instance field). | |
| 2727 FieldParameterElement visitSend(Send node) { | |
| 2728 FieldParameterElement element; | |
| 2729 if (node.receiver.asIdentifier() == null || | |
| 2730 !node.receiver.asIdentifier().isThis()) { | |
| 2731 error(node, MessageKind.INVALID_PARAMETER, []); | |
| 2732 } else if (!identical(enclosingElement.kind, ElementKind.GENERATIVE_CONSTRUC
TOR)) { | |
| 2733 error(node, MessageKind.FIELD_PARAMETER_NOT_ALLOWED, []); | |
| 2734 } else { | |
| 2735 SourceString name = getParameterName(node); | |
| 2736 Element fieldElement = currentClass.lookupLocalMember(name); | |
| 2737 if (fieldElement == null || !identical(fieldElement.kind, ElementKind.FIEL
D)) { | |
| 2738 error(node, MessageKind.NOT_A_FIELD, [name]); | |
| 2739 } else if (!fieldElement.isInstanceMember()) { | |
| 2740 error(node, MessageKind.NOT_INSTANCE_FIELD, [name]); | |
| 2741 } | |
| 2742 Element variables = new VariableListElement.node(currentDefinitions, | |
| 2743 ElementKind.VARIABLE_LIST, enclosingElement); | |
| 2744 element = new FieldParameterElement(name, fieldElement, variables, node); | |
| 2745 } | |
| 2746 return element; | |
| 2747 } | |
| 2748 | |
| 2749 Element visitSendSet(SendSet node) { | |
| 2750 Element element; | |
| 2751 if (node.receiver != null) { | |
| 2752 element = visitSend(node); | |
| 2753 } else if (node.selector.asIdentifier() != null) { | |
| 2754 Element variables = new VariableListElement.node(currentDefinitions, | |
| 2755 ElementKind.VARIABLE_LIST, enclosingElement); | |
| 2756 element = new VariableElement(node.selector.asIdentifier().source, | |
| 2757 variables, ElementKind.PARAMETER, node); | |
| 2758 } | |
| 2759 // Visit the value. The compile time constant handler will | |
| 2760 // make sure it's a compile time constant. | |
| 2761 resolveExpression(node.arguments.head); | |
| 2762 return element; | |
| 2763 } | |
| 2764 | |
| 2765 Element visitFunctionExpression(FunctionExpression node) { | |
| 2766 // This is a function typed parameter. | |
| 2767 // TODO(ahe): Resolve the function type. | |
| 2768 return visit(node.name); | |
| 2769 } | |
| 2770 | |
| 2771 LinkBuilder<Element> analyzeNodes(Link<Node> link) { | |
| 2772 LinkBuilder<Element> elements = new LinkBuilder<Element>(); | |
| 2773 for (; !link.isEmpty(); link = link.tail) { | |
| 2774 Element element = link.head.accept(this); | |
| 2775 if (element != null) { | |
| 2776 elements.addLast(element); | |
| 2777 } else { | |
| 2778 // If parameter is null, the current node should be the last, | |
| 2779 // and a list of optional named parameters. | |
| 2780 if (!link.tail.isEmpty() || (link.head is !NodeList)) { | |
| 2781 internalError(link.head, "expected optional parameters"); | |
| 2782 } | |
| 2783 } | |
| 2784 } | |
| 2785 return elements; | |
| 2786 } | |
| 2787 | |
| 2788 /** | |
| 2789 * Resolves formal parameters and return type to a [FunctionSignature]. | |
| 2790 */ | |
| 2791 static FunctionSignature analyze(Compiler compiler, | |
| 2792 NodeList formalParameters, | |
| 2793 Node returnNode, | |
| 2794 Element element) { | |
| 2795 SignatureResolver visitor = new SignatureResolver(compiler, element); | |
| 2796 Link<Element> parameters = const Link<Element>(); | |
| 2797 int requiredParameterCount = 0; | |
| 2798 if (formalParameters == null) { | |
| 2799 if (!element.isGetter()) { | |
| 2800 compiler.reportMessage(compiler.spanFromElement(element), | |
| 2801 MessageKind.MISSING_FORMALS.error([]), | |
| 2802 api.Diagnostic.ERROR); | |
| 2803 } | |
| 2804 } else { | |
| 2805 if (element.isGetter()) { | |
| 2806 if (!element.getLibrary().isPlatformLibrary) { | |
| 2807 // TODO(ahe): Remove the isPlatformLibrary check. | |
| 2808 if (!identical(formalParameters.getEndToken().next.stringValue, 'nativ
e')) { | |
| 2809 // TODO(ahe): Remove the check for native keyword. | |
| 2810 compiler.reportMessage(compiler.spanFromNode(formalParameters), | |
| 2811 MessageKind.EXTRA_FORMALS.error([]), | |
| 2812 api.Diagnostic.WARNING); | |
| 2813 } | |
| 2814 } | |
| 2815 } | |
| 2816 LinkBuilder<Element> parametersBuilder = | |
| 2817 visitor.analyzeNodes(formalParameters.nodes); | |
| 2818 requiredParameterCount = parametersBuilder.length; | |
| 2819 parameters = parametersBuilder.toLink(); | |
| 2820 } | |
| 2821 DartType returnType = compiler.resolveReturnType(element, returnNode); | |
| 2822 return new FunctionSignature(parameters, | |
| 2823 visitor.optionalParameters, | |
| 2824 requiredParameterCount, | |
| 2825 visitor.optionalParameterCount, | |
| 2826 visitor.optionalParametersAreNamed, | |
| 2827 returnType); | |
| 2828 } | |
| 2829 | |
| 2830 // TODO(ahe): This is temporary. | |
| 2831 void resolveExpression(Node node) { | |
| 2832 if (node == null) return; | |
| 2833 node.accept(new ResolverVisitor(compiler, enclosingElement)); | |
| 2834 } | |
| 2835 | |
| 2836 // TODO(ahe): This is temporary. | |
| 2837 ClassElement get currentClass { | |
| 2838 return enclosingElement.isMember() | |
| 2839 ? enclosingElement.getEnclosingClass() : null; | |
| 2840 } | |
| 2841 } | |
| 2842 | |
| 2843 class ConstructorResolver extends CommonResolverVisitor<Element> { | |
| 2844 final ResolverVisitor resolver; | |
| 2845 // TODO(ngeoffray): have this context at the call site. | |
| 2846 final bool inConstContext; | |
| 2847 | |
| 2848 ConstructorResolver(Compiler compiler, | |
| 2849 this.resolver, | |
| 2850 this.inConstContext) | |
| 2851 : super(compiler); | |
| 2852 | |
| 2853 visitNode(Node node) { | |
| 2854 throw 'not supported'; | |
| 2855 } | |
| 2856 | |
| 2857 failOrReturnErroneousElement(Element enclosing, Node diagnosticNode, | |
| 2858 SourceString targetName, MessageKind kind, | |
| 2859 List arguments) { | |
| 2860 if (inConstContext) { | |
| 2861 error(diagnosticNode, kind, arguments); | |
| 2862 } else { | |
| 2863 ResolutionWarning warning = new ResolutionWarning(kind, arguments); | |
| 2864 compiler.reportWarning(diagnosticNode, warning); | |
| 2865 return new ErroneousFunctionElement(kind, arguments, targetName, | |
| 2866 enclosing); | |
| 2867 } | |
| 2868 } | |
| 2869 | |
| 2870 Selector createConstructorSelector(SourceString constructorName) { | |
| 2871 return constructorName == const SourceString('') | |
| 2872 ? new Selector.callDefaultConstructor( | |
| 2873 resolver.enclosingElement.getLibrary()) | |
| 2874 : new Selector.callConstructor( | |
| 2875 constructorName, | |
| 2876 resolver.enclosingElement.getLibrary()); | |
| 2877 } | |
| 2878 | |
| 2879 // TODO(ngeoffray): method named lookup should not report errors. | |
| 2880 FunctionElement lookupConstructor(ClassElement cls, | |
| 2881 Node diagnosticNode, | |
| 2882 SourceString constructorName) { | |
| 2883 cls.ensureResolved(compiler); | |
| 2884 Selector selector = createConstructorSelector(constructorName); | |
| 2885 Element result = cls.lookupConstructor(selector); | |
| 2886 if (result == null) { | |
| 2887 String fullConstructorName = | |
| 2888 resolver.compiler.resolver.constructorNameForDiagnostics( | |
| 2889 cls.name, | |
| 2890 constructorName); | |
| 2891 return failOrReturnErroneousElement( | |
| 2892 cls, | |
| 2893 diagnosticNode, | |
| 2894 new SourceString(fullConstructorName), | |
| 2895 MessageKind.CANNOT_FIND_CONSTRUCTOR, | |
| 2896 [fullConstructorName]); | |
| 2897 } else if (inConstContext && !result.modifiers.isConst()) { | |
| 2898 error(diagnosticNode, MessageKind.CONSTRUCTOR_IS_NOT_CONST); | |
| 2899 } | |
| 2900 return result; | |
| 2901 } | |
| 2902 | |
| 2903 visitNewExpression(NewExpression node) { | |
| 2904 Node selector = node.send.selector; | |
| 2905 Element e = visit(selector); | |
| 2906 if (!Elements.isUnresolved(e) && identical(e.kind, ElementKind.CLASS)) { | |
| 2907 ClassElement cls = e; | |
| 2908 cls.ensureResolved(compiler); | |
| 2909 if (cls.isInterface() && (cls.defaultClass == null)) { | |
| 2910 error(selector, MessageKind.CANNOT_INSTANTIATE_INTERFACE, [cls.name]); | |
| 2911 } | |
| 2912 e = lookupConstructor(cls, selector, const SourceString('')); | |
| 2913 } | |
| 2914 return e; | |
| 2915 } | |
| 2916 | |
| 2917 visitTypeAnnotation(TypeAnnotation node) { | |
| 2918 return visit(node.typeName); | |
| 2919 } | |
| 2920 | |
| 2921 visitSend(Send node) { | |
| 2922 Element e = visit(node.receiver); | |
| 2923 if (Elements.isUnresolved(e)) return e; | |
| 2924 Identifier name = node.selector.asIdentifier(); | |
| 2925 if (name == null) internalError(node.selector, 'unexpected node'); | |
| 2926 | |
| 2927 if (identical(e.kind, ElementKind.CLASS)) { | |
| 2928 ClassElement cls = e; | |
| 2929 cls.ensureResolved(compiler); | |
| 2930 if (cls.isInterface() && (cls.defaultClass == null)) { | |
| 2931 error(node.receiver, MessageKind.CANNOT_INSTANTIATE_INTERFACE, | |
| 2932 [cls.name]); | |
| 2933 } | |
| 2934 return lookupConstructor(cls, name, name.source); | |
| 2935 } else if (identical(e.kind, ElementKind.PREFIX)) { | |
| 2936 PrefixElement prefix = e; | |
| 2937 e = prefix.lookupLocalMember(name.source); | |
| 2938 if (e == null) { | |
| 2939 return failOrReturnErroneousElement(resolver.enclosingElement, name, | |
| 2940 name.source, | |
| 2941 MessageKind.CANNOT_RESOLVE, | |
| 2942 [name]); | |
| 2943 } else if (!identical(e.kind, ElementKind.CLASS)) { | |
| 2944 error(node, MessageKind.NOT_A_TYPE, [name]); | |
| 2945 } | |
| 2946 } else { | |
| 2947 internalError(node.receiver, 'unexpected element $e'); | |
| 2948 } | |
| 2949 return e; | |
| 2950 } | |
| 2951 | |
| 2952 Element visitIdentifier(Identifier node) { | |
| 2953 SourceString name = node.source; | |
| 2954 Element e = resolver.lookup(node, name); | |
| 2955 if (e == null) { | |
| 2956 return failOrReturnErroneousElement(resolver.enclosingElement, node, name, | |
| 2957 MessageKind.CANNOT_RESOLVE, [name]); | |
| 2958 } else if (identical(e.kind, ElementKind.TYPEDEF)) { | |
| 2959 error(node, MessageKind.CANNOT_INSTANTIATE_TYPEDEF, [name]); | |
| 2960 } else if (!identical(e.kind, ElementKind.CLASS) | |
| 2961 && !identical(e.kind, ElementKind.PREFIX)) { | |
| 2962 error(node, MessageKind.NOT_A_TYPE, [name]); | |
| 2963 } | |
| 2964 return e; | |
| 2965 } | |
| 2966 } | |
| 2967 | |
| 2968 abstract class Scope { | |
| 2969 final Element element; | |
| 2970 final Scope parent; | |
| 2971 | |
| 2972 Scope(this.parent, this.element); | |
| 2973 abstract Element add(Element element); | |
| 2974 | |
| 2975 Element lookup(SourceString name) { | |
| 2976 Element result = localLookup(name); | |
| 2977 if (result != null) return result; | |
| 2978 return parent.lookup(name); | |
| 2979 } | |
| 2980 | |
| 2981 Element lexicalLookup(SourceString name) { | |
| 2982 Element result = localLookup(name); | |
| 2983 if (result != null) return result; | |
| 2984 return parent.lexicalLookup(name); | |
| 2985 } | |
| 2986 | |
| 2987 abstract Element localLookup(SourceString name); | |
| 2988 } | |
| 2989 | |
| 2990 class VariableScope extends Scope { | |
| 2991 VariableScope(parent, element) : super(parent, element); | |
| 2992 | |
| 2993 Element add(Element newElement) { | |
| 2994 throw "Cannot add element to VariableScope"; | |
| 2995 } | |
| 2996 | |
| 2997 Element localLookup(SourceString name) => null; | |
| 2998 | |
| 2999 String toString() => '$element > $parent'; | |
| 3000 } | |
| 3001 | |
| 3002 /** | |
| 3003 * [TypeDeclarationScope] defines the outer scope of a type declaration in | |
| 3004 * which the declared type variables and the entities in the enclosing scope are | |
| 3005 * available but where declared and inherited members are not available. This | |
| 3006 * scope is only used for class/interface declarations during resolution of the | |
| 3007 * class hierarchy. In all other cases [ClassScope] is used. | |
| 3008 */ | |
| 3009 class TypeDeclarationScope extends Scope { | |
| 3010 TypeDeclarationElement get element => super.element; | |
| 3011 | |
| 3012 TypeDeclarationScope(parent, TypeDeclarationElement element) | |
| 3013 : super(parent, element) { | |
| 3014 assert(parent != null); | |
| 3015 } | |
| 3016 | |
| 3017 Element add(Element newElement) { | |
| 3018 throw "Cannot add element to TypeDeclarationScope"; | |
| 3019 } | |
| 3020 | |
| 3021 Element localLookup(SourceString name) { | |
| 3022 Link<DartType> typeVariableLink = element.typeVariables; | |
| 3023 while (!typeVariableLink.isEmpty()) { | |
| 3024 TypeVariableType typeVariable = typeVariableLink.head; | |
| 3025 if (typeVariable.name == name) { | |
| 3026 return typeVariable.element; | |
| 3027 } | |
| 3028 typeVariableLink = typeVariableLink.tail; | |
| 3029 } | |
| 3030 return null; | |
| 3031 } | |
| 3032 | |
| 3033 String toString() => | |
| 3034 'TypeDeclarationScope($element)'; | |
| 3035 } | |
| 3036 | |
| 3037 class MethodScope extends Scope { | |
| 3038 final Map<SourceString, Element> elements; | |
| 3039 | |
| 3040 MethodScope(Scope parent, Element element) | |
| 3041 : super(parent, element), | |
| 3042 this.elements = new Map<SourceString, Element>() { | |
| 3043 assert(parent != null); | |
| 3044 } | |
| 3045 | |
| 3046 Element localLookup(SourceString name) => elements[name]; | |
| 3047 | |
| 3048 Element add(Element newElement) { | |
| 3049 if (elements.containsKey(newElement.name)) { | |
| 3050 return elements[newElement.name]; | |
| 3051 } | |
| 3052 elements[newElement.name] = newElement; | |
| 3053 return newElement; | |
| 3054 } | |
| 3055 | |
| 3056 String toString() => '$element${elements.getKeys()}'; | |
| 3057 } | |
| 3058 | |
| 3059 class BlockScope extends MethodScope { | |
| 3060 BlockScope(Scope parent) : super(parent, parent.element); | |
| 3061 | |
| 3062 String toString() => 'block${elements.getKeys()}'; | |
| 3063 } | |
| 3064 | |
| 3065 /** | |
| 3066 * [ClassScope] defines the inner scope of a class/interface declaration in | |
| 3067 * which declared members, declared type variables, entities in the enclosing | |
| 3068 * scope and inherited members are available, in the given order. | |
| 3069 */ | |
| 3070 class ClassScope extends TypeDeclarationScope { | |
| 3071 bool inStaticContext = false; | |
| 3072 | |
| 3073 ClassScope(Scope parentScope, ClassElement element) | |
| 3074 : super(parentScope, element) { | |
| 3075 assert(parent != null); | |
| 3076 } | |
| 3077 | |
| 3078 Element localLookup(SourceString name) { | |
| 3079 ClassElement cls = element; | |
| 3080 Element result = cls.lookupLocalMember(name); | |
| 3081 if (result != null) return result; | |
| 3082 if (!inStaticContext) { | |
| 3083 // If not in a static context, we can lookup in the | |
| 3084 // TypeDeclaration scope, which contains the type variables of | |
| 3085 // the class. | |
| 3086 result = super.localLookup(name); | |
| 3087 } | |
| 3088 return result; | |
| 3089 } | |
| 3090 | |
| 3091 Element lookup(SourceString name) { | |
| 3092 Element result = localLookup(name); | |
| 3093 if (result != null) return result; | |
| 3094 result = parent.lookup(name); | |
| 3095 if (result != null) return result; | |
| 3096 ClassElement cls = element; | |
| 3097 return cls.lookupSuperMember(name); | |
| 3098 } | |
| 3099 | |
| 3100 Element add(Element newElement) { | |
| 3101 throw "Cannot add an element in a class scope"; | |
| 3102 } | |
| 3103 | |
| 3104 String toString() => 'ClassScope($element)'; | |
| 3105 } | |
| 3106 | |
| 3107 // TODO(johnniwinther): Refactor scopes to avoid class explosion. | |
| 3108 class PatchClassScope extends TypeDeclarationScope { | |
| 3109 bool inStaticContext = false; | |
| 3110 ClassElement get origin => element; | |
| 3111 final ClassElement patch; | |
| 3112 | |
| 3113 PatchClassScope(Scope parentScope, | |
| 3114 ClassElement origin, ClassElement this.patch) | |
| 3115 : super(parentScope, origin) { | |
| 3116 assert(parent != null); | |
| 3117 } | |
| 3118 | |
| 3119 Element localLookup(SourceString name) { | |
| 3120 Element result = patch.lookupLocalMember(name); | |
| 3121 if (result != null) return result; | |
| 3122 result = origin.lookupLocalMember(name); | |
| 3123 if (result != null) return result; | |
| 3124 if (!inStaticContext) { | |
| 3125 // If not in a static context, we can lookup in the | |
| 3126 // TypeDeclaration scope, which contains the type variables of | |
| 3127 // the class. | |
| 3128 result = super.localLookup(name); | |
| 3129 if (result != null) return result; | |
| 3130 } | |
| 3131 result = parent.lookup(name); | |
| 3132 if (result != null) return result; | |
| 3133 return result; | |
| 3134 } | |
| 3135 | |
| 3136 Element lookup(SourceString name) { | |
| 3137 Element result = localLookup(name); | |
| 3138 if (result != null) return result; | |
| 3139 // TODO(johnniwinther): Should we support patch lookup on supertypes? | |
| 3140 return origin.lookupSuperMember(name); | |
| 3141 } | |
| 3142 | |
| 3143 Element add(Element newElement) { | |
| 3144 throw "Cannot add an element in a class scope"; | |
| 3145 } | |
| 3146 | |
| 3147 String toString() => 'PatchClassScope($origin,$patch)'; | |
| 3148 } | |
| 3149 | |
| 3150 class LocalClassScope extends Scope { | |
| 3151 LocalClassScope(ClassElement element) | |
| 3152 : super(null, element); | |
| 3153 | |
| 3154 Element lookup(SourceString name) => localLookup(name); | |
| 3155 | |
| 3156 Element localLookup(SourceString name) { | |
| 3157 ClassElement cls = element; | |
| 3158 return cls.lookupLocalMember(name); | |
| 3159 } | |
| 3160 | |
| 3161 Element add(Element newElement) { | |
| 3162 throw "Cannot add an element in a class scope"; | |
| 3163 } | |
| 3164 | |
| 3165 String toString() => 'LocalClassScope($element)'; | |
| 3166 } | |
| 3167 | |
| 3168 class LocalPatchClassScope extends Scope { | |
| 3169 ClassElement get origin => element; | |
| 3170 final ClassElement patch; | |
| 3171 | |
| 3172 LocalPatchClassScope(ClassElement origin, ClassElement this.patch) | |
| 3173 : super(null, origin); | |
| 3174 | |
| 3175 Element lookup(SourceString name) => localLookup(name); | |
| 3176 | |
| 3177 Element localLookup(SourceString name) { | |
| 3178 Element result = patch.lookupLocalMember(name); | |
| 3179 if (result != null) return result; | |
| 3180 return origin.lookupLocalMember(name); | |
| 3181 } | |
| 3182 | |
| 3183 | |
| 3184 Element add(Element newElement) { | |
| 3185 throw "Cannot add an element in a class scope"; | |
| 3186 } | |
| 3187 | |
| 3188 String toString() => 'LocalPatchClassScope($origin,$patch)'; | |
| 3189 } | |
| 3190 | |
| 3191 class TopScope extends Scope { | |
| 3192 LibraryElement get library => element; | |
| 3193 | |
| 3194 TopScope(LibraryElement library) : super(null, library); | |
| 3195 | |
| 3196 Element localLookup(SourceString name) => library.find(name); | |
| 3197 Element lookup(SourceString name) => localLookup(name); | |
| 3198 Element lexicalLookup(SourceString name) => localLookup(name); | |
| 3199 | |
| 3200 Element add(Element newElement) { | |
| 3201 throw "Cannot add an element in the top scope"; | |
| 3202 } | |
| 3203 String toString() => 'LibraryScope($element)'; | |
| 3204 } | |
| 3205 | |
| 3206 class PatchLibraryScope extends Scope { | |
| 3207 LibraryElement get origin => element; | |
| 3208 final LibraryElement patch; | |
| 3209 | |
| 3210 PatchLibraryScope(LibraryElement origin, LibraryElement this.patch) | |
| 3211 : super(null, origin); | |
| 3212 | |
| 3213 Element localLookup(SourceString name) { | |
| 3214 Element result = patch.find(name); | |
| 3215 if (result != null) { | |
| 3216 return result; | |
| 3217 } | |
| 3218 result = origin.find(name); | |
| 3219 if (result != null) { | |
| 3220 return result; | |
| 3221 } | |
| 3222 return result; | |
| 3223 } | |
| 3224 Element lookup(SourceString name) => localLookup(name); | |
| 3225 Element lexicalLookup(SourceString name) => localLookup(name); | |
| 3226 | |
| 3227 Element add(Element newElement) { | |
| 3228 throw "Cannot add an element in a patch library scope"; | |
| 3229 } | |
| 3230 String toString() => 'PatchLibraryScope($origin,$patch)'; | |
| 3231 } | |
| OLD | NEW |