| 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 #library('elements'); | |
| 6 | |
| 7 #import('../tree/tree.dart'); | |
| 8 #import('../scanner/scannerlib.dart'); | |
| 9 #import('../leg.dart'); // TODO(karlklose): we only need type. | |
| 10 #import('../util/util.dart'); | |
| 11 | |
| 12 class ElementCategory { | |
| 13 /** | |
| 14 * Represents things that we don't expect to find when looking in a | |
| 15 * scope. | |
| 16 */ | |
| 17 static final int NONE = 0; | |
| 18 | |
| 19 /** Field, parameter, or variable. */ | |
| 20 static final int VARIABLE = 1; | |
| 21 | |
| 22 /** Function, method, or foreign function. */ | |
| 23 static final int FUNCTION = 2; | |
| 24 | |
| 25 static final int CLASS = 4; | |
| 26 | |
| 27 static final int PREFIX = 8; | |
| 28 | |
| 29 /** Constructor or factory. */ | |
| 30 static final int FACTORY = 16; | |
| 31 | |
| 32 static final int ALIAS = 32; | |
| 33 | |
| 34 static final int SUPER = 64; | |
| 35 | |
| 36 /** Type variable */ | |
| 37 static final int TYPE_VARIABLE = 128; | |
| 38 | |
| 39 static final int IMPLIES_TYPE = CLASS | ALIAS | TYPE_VARIABLE; | |
| 40 | |
| 41 static final int IS_EXTENDABLE = CLASS | ALIAS; | |
| 42 } | |
| 43 | |
| 44 class ElementKind { | |
| 45 final String id; | |
| 46 final int category; | |
| 47 | |
| 48 const ElementKind(String this.id, this.category); | |
| 49 | |
| 50 static final ElementKind VARIABLE = | |
| 51 const ElementKind('variable', ElementCategory.VARIABLE); | |
| 52 static final ElementKind PARAMETER = | |
| 53 const ElementKind('parameter', ElementCategory.VARIABLE); | |
| 54 // Parameters in constructors that directly initialize fields. For example: | |
| 55 // [:A(this.field):]. | |
| 56 static final ElementKind FIELD_PARAMETER = | |
| 57 const ElementKind('field_parameter', ElementCategory.VARIABLE); | |
| 58 static final ElementKind FUNCTION = | |
| 59 const ElementKind('function', ElementCategory.FUNCTION); | |
| 60 static final ElementKind CLASS = | |
| 61 const ElementKind('class', ElementCategory.CLASS); | |
| 62 static final ElementKind FOREIGN = | |
| 63 const ElementKind('foreign', ElementCategory.FUNCTION); | |
| 64 static final ElementKind GENERATIVE_CONSTRUCTOR = | |
| 65 const ElementKind('generative_constructor', ElementCategory.FACTORY); | |
| 66 static final ElementKind FIELD = | |
| 67 const ElementKind('field', ElementCategory.VARIABLE); | |
| 68 static final ElementKind VARIABLE_LIST = | |
| 69 const ElementKind('variable_list', ElementCategory.NONE); | |
| 70 static final ElementKind FIELD_LIST = | |
| 71 const ElementKind('field_list', ElementCategory.NONE); | |
| 72 static final ElementKind GENERATIVE_CONSTRUCTOR_BODY = | |
| 73 const ElementKind('generative_constructor_body', ElementCategory.NONE); | |
| 74 static final ElementKind COMPILATION_UNIT = | |
| 75 const ElementKind('compilation_unit', ElementCategory.NONE); | |
| 76 static final ElementKind GETTER = | |
| 77 const ElementKind('getter', ElementCategory.NONE); | |
| 78 static final ElementKind SETTER = | |
| 79 const ElementKind('setter', ElementCategory.NONE); | |
| 80 static final ElementKind TYPE_VARIABLE = | |
| 81 const ElementKind('type_variable', ElementCategory.TYPE_VARIABLE); | |
| 82 static final ElementKind ABSTRACT_FIELD = | |
| 83 const ElementKind('abstract_field', ElementCategory.VARIABLE); | |
| 84 static final ElementKind LIBRARY = | |
| 85 const ElementKind('library', ElementCategory.NONE); | |
| 86 static final ElementKind PREFIX = | |
| 87 const ElementKind('prefix', ElementCategory.PREFIX); | |
| 88 static final ElementKind TYPEDEF = | |
| 89 const ElementKind('typedef', ElementCategory.ALIAS); | |
| 90 | |
| 91 static final ElementKind STATEMENT = | |
| 92 const ElementKind('statement', ElementCategory.NONE); | |
| 93 static final ElementKind LABEL = | |
| 94 const ElementKind('label', ElementCategory.NONE); | |
| 95 | |
| 96 toString() => id; | |
| 97 } | |
| 98 | |
| 99 class Element implements Hashable { | |
| 100 final SourceString name; | |
| 101 final ElementKind kind; | |
| 102 final Element enclosingElement; | |
| 103 Modifiers get modifiers() => null; | |
| 104 | |
| 105 Node parseNode(DiagnosticListener listener) { | |
| 106 listener.cancel("Internal Error: $this.parseNode", token: position()); | |
| 107 } | |
| 108 | |
| 109 Type computeType(Compiler compiler) { | |
| 110 compiler.internalError("$this.computeType.", token: position()); | |
| 111 } | |
| 112 | |
| 113 bool isFunction() => kind === ElementKind.FUNCTION; | |
| 114 bool isMember() => | |
| 115 enclosingElement !== null && enclosingElement.kind === ElementKind.CLASS; | |
| 116 bool isInstanceMember() => false; | |
| 117 bool isFactoryConstructor() => modifiers !== null && modifiers.isFactory(); | |
| 118 bool isGenerativeConstructor() => kind === ElementKind.GENERATIVE_CONSTRUCTOR; | |
| 119 bool isCompilationUnit() { | |
| 120 return kind === ElementKind.COMPILATION_UNIT || | |
| 121 kind === ElementKind.LIBRARY; | |
| 122 } | |
| 123 bool isClass() => kind === ElementKind.CLASS; | |
| 124 bool isVariable() => kind === ElementKind.VARIABLE; | |
| 125 bool isParameter() => kind === ElementKind.PARAMETER; | |
| 126 bool isStatement() => kind === ElementKind.STATEMENT; | |
| 127 bool isTypedef() => kind === ElementKind.TYPEDEF; | |
| 128 bool isTypeVariable() => kind === ElementKind.TYPE_VARIABLE; | |
| 129 bool isGetter() => kind === ElementKind.GETTER; | |
| 130 bool isSetter() => kind === ElementKind.SETTER; | |
| 131 bool impliesType() => (kind.category & ElementCategory.IMPLIES_TYPE) != 0; | |
| 132 bool isExtendable() => (kind.category & ElementCategory.IS_EXTENDABLE) != 0; | |
| 133 | |
| 134 bool isAssignable() { | |
| 135 if (modifiers != null && modifiers.isFinal()) return false; | |
| 136 if (isFunction() || isGenerativeConstructor()) return false; | |
| 137 return true; | |
| 138 } | |
| 139 | |
| 140 Token position() => null; | |
| 141 | |
| 142 Token findMyName(Token token) { | |
| 143 for (Token t = token; t !== EOF_TOKEN; t = t.next) { | |
| 144 if (t.value == name) return t; | |
| 145 } | |
| 146 return token; | |
| 147 } | |
| 148 | |
| 149 Element(this.name, this.kind, this.enclosingElement) { | |
| 150 assert(getLibrary() !== null); | |
| 151 } | |
| 152 | |
| 153 // TODO(kasperl): This is a very bad hash code for the element and | |
| 154 // there's no reason why two elements with the same name should have | |
| 155 // the same hash code. Replace this with a simple id in the element? | |
| 156 int hashCode() => name.hashCode(); | |
| 157 | |
| 158 CompilationUnitElement getCompilationUnit() { | |
| 159 Element element = this; | |
| 160 while (element !== null && !element.isCompilationUnit()) { | |
| 161 element = element.enclosingElement; | |
| 162 } | |
| 163 return element; | |
| 164 } | |
| 165 | |
| 166 LibraryElement getLibrary() { | |
| 167 Element element = this; | |
| 168 while (element.kind !== ElementKind.LIBRARY) { | |
| 169 element = element.enclosingElement; | |
| 170 } | |
| 171 return element; | |
| 172 } | |
| 173 | |
| 174 ClassElement getEnclosingClass() { | |
| 175 for (Element e = this; e !== null; e = e.enclosingElement) { | |
| 176 if (e.kind === ElementKind.CLASS) return e; | |
| 177 } | |
| 178 return null; | |
| 179 } | |
| 180 | |
| 181 toString() => '$kind(${name.slowToString()})'; | |
| 182 | |
| 183 bool _isNative = false; | |
| 184 void setNative() => _isNative = true; | |
| 185 bool isNative() => _isNative; | |
| 186 } | |
| 187 | |
| 188 class ContainerElement extends Element { | |
| 189 ContainerElement(name, kind, enclosingElement) : | |
| 190 super(name, kind, enclosingElement); | |
| 191 | |
| 192 abstract void addMember(Element element, DiagnosticListener listener); | |
| 193 | |
| 194 void addGetterOrSetter(Element element, | |
| 195 Element existing, | |
| 196 DiagnosticListener listener) { | |
| 197 void reportError(Element other) { | |
| 198 listener.cancel('duplicate definition of ${element.name.slowToString()}', | |
| 199 element: element); | |
| 200 listener.cancel('existing definition', element: other); | |
| 201 } | |
| 202 | |
| 203 if (existing != null) { | |
| 204 if (existing.kind !== ElementKind.ABSTRACT_FIELD) { | |
| 205 reportError(existing); | |
| 206 } else { | |
| 207 AbstractFieldElement field = existing; | |
| 208 if (element.kind == ElementKind.GETTER) { | |
| 209 if (field.getter != null && field.getter != element) { | |
| 210 reportError(field.getter); | |
| 211 } | |
| 212 field.getter = element; | |
| 213 } else { | |
| 214 if (field.setter != null && field.setter != element) { | |
| 215 reportError(field.setter); | |
| 216 } | |
| 217 field.setter = element; | |
| 218 } | |
| 219 } | |
| 220 } else { | |
| 221 AbstractFieldElement field = new AbstractFieldElement(element.name, this); | |
| 222 addMember(field, listener); | |
| 223 if (element.kind == ElementKind.GETTER) { | |
| 224 field.getter = element; | |
| 225 } else { | |
| 226 field.setter = element; | |
| 227 } | |
| 228 } | |
| 229 } | |
| 230 } | |
| 231 | |
| 232 class CompilationUnitElement extends ContainerElement { | |
| 233 final Script script; | |
| 234 Link<Element> topLevelElements = const EmptyLink<Element>(); | |
| 235 | |
| 236 CompilationUnitElement(Script script, Element enclosing) | |
| 237 : this.script = script, | |
| 238 super(new SourceString(script.name), | |
| 239 ElementKind.COMPILATION_UNIT, | |
| 240 enclosing); | |
| 241 | |
| 242 CompilationUnitElement.library(Script script) | |
| 243 : this.script = script, | |
| 244 super(new SourceString(script.name), ElementKind.LIBRARY, null); | |
| 245 | |
| 246 void addMember(Element element, DiagnosticListener listener) { | |
| 247 LibraryElement library = enclosingElement; | |
| 248 library.addMember(element, listener); | |
| 249 topLevelElements = topLevelElements.prepend(element); | |
| 250 } | |
| 251 | |
| 252 void define(Element element, DiagnosticListener listener) { | |
| 253 LibraryElement library = enclosingElement; | |
| 254 library.define(element, listener); | |
| 255 } | |
| 256 | |
| 257 void addTag(ScriptTag tag, DiagnosticListener listener) { | |
| 258 listener.cancel("script tags not allowed here", node: tag); | |
| 259 } | |
| 260 } | |
| 261 | |
| 262 class LibraryElement extends CompilationUnitElement { | |
| 263 // TODO(ahe): Library element should not be a subclass of | |
| 264 // CompilationUnitElement. | |
| 265 | |
| 266 Link<CompilationUnitElement> compilationUnits = | |
| 267 const EmptyLink<CompilationUnitElement>(); | |
| 268 Link<ScriptTag> tags = const EmptyLink<ScriptTag>(); | |
| 269 ScriptTag libraryTag; | |
| 270 Map<SourceString, Element> elements; | |
| 271 bool canUseNative = false; | |
| 272 | |
| 273 LibraryElement(Script script) | |
| 274 : elements = new Map<SourceString, Element>(), | |
| 275 super.library(script); | |
| 276 | |
| 277 void addCompilationUnit(CompilationUnitElement element) { | |
| 278 compilationUnits = compilationUnits.prepend(element); | |
| 279 } | |
| 280 | |
| 281 void addTag(ScriptTag tag, DiagnosticListener listener) { | |
| 282 tags = tags.prepend(tag); | |
| 283 } | |
| 284 | |
| 285 void addMember(Element element, DiagnosticListener listener) { | |
| 286 topLevelElements = topLevelElements.prepend(element); | |
| 287 define(element, listener); | |
| 288 } | |
| 289 | |
| 290 void define(Element element, DiagnosticListener listener) { | |
| 291 if (element.kind == ElementKind.GETTER | |
| 292 || element.kind == ElementKind.SETTER) { | |
| 293 addGetterOrSetter(element, elements[element.name], listener); | |
| 294 } else { | |
| 295 Element existing = elements.putIfAbsent(element.name, () => element); | |
| 296 if (existing !== element) { | |
| 297 listener.cancel('duplicate definition', token: element.position()); | |
| 298 listener.cancel('existing definition', token: existing.position()); | |
| 299 } | |
| 300 } | |
| 301 } | |
| 302 | |
| 303 Element find(SourceString elementName) { | |
| 304 return elements[elementName]; | |
| 305 } | |
| 306 | |
| 307 void forEachExport(f(Element element)) { | |
| 308 elements.forEach((SourceString _, Element e) { | |
| 309 if (this === e.getLibrary() | |
| 310 && e.kind !== ElementKind.PREFIX | |
| 311 && e.kind !== ElementKind.FOREIGN) { | |
| 312 if (!e.name.isPrivate()) f(e); | |
| 313 } | |
| 314 }); | |
| 315 } | |
| 316 | |
| 317 bool hasLibraryName() => libraryTag !== null; | |
| 318 } | |
| 319 | |
| 320 class PrefixElement extends Element { | |
| 321 Map<SourceString, Element> imported; | |
| 322 Token firstPosition; | |
| 323 | |
| 324 PrefixElement(SourceString prefix, Element enclosing, this.firstPosition) | |
| 325 : imported = new Map<SourceString, Element>(), | |
| 326 super(prefix, ElementKind.PREFIX, enclosing); | |
| 327 | |
| 328 lookupLocalMember(SourceString memberName) => imported[memberName]; | |
| 329 | |
| 330 Type computeType(Compiler compiler) => compiler.types.dynamicType; | |
| 331 | |
| 332 Token position() => firstPosition; | |
| 333 } | |
| 334 | |
| 335 class TypedefElement extends Element { | |
| 336 Token token; | |
| 337 TypedefElement(SourceString name, Element enclosing, this.token) | |
| 338 : super(name, ElementKind.TYPEDEF, enclosing); | |
| 339 | |
| 340 position() => findMyName(token); | |
| 341 } | |
| 342 | |
| 343 class VariableElement extends Element { | |
| 344 final VariableListElement variables; | |
| 345 Expression cachedNode; // The send or the identifier in the variables list. | |
| 346 | |
| 347 Modifiers get modifiers() => variables.modifiers; | |
| 348 | |
| 349 VariableElement(SourceString name, | |
| 350 VariableListElement this.variables, | |
| 351 ElementKind kind, | |
| 352 Element enclosing, | |
| 353 [Node node]) | |
| 354 : super(name, kind, enclosing), cachedNode = node; | |
| 355 | |
| 356 Node parseNode(DiagnosticListener listener) { | |
| 357 if (cachedNode !== null) return cachedNode; | |
| 358 VariableDefinitions definitions = variables.parseNode(listener); | |
| 359 for (Link<Node> link = definitions.definitions.nodes; | |
| 360 !link.isEmpty(); link = link.tail) { | |
| 361 Expression initializedIdentifier = link.head; | |
| 362 Identifier identifier = initializedIdentifier.asIdentifier(); | |
| 363 if (identifier === null) { | |
| 364 identifier = initializedIdentifier.asSendSet().selector.asIdentifier(); | |
| 365 } | |
| 366 if (name === identifier.source) { | |
| 367 cachedNode = initializedIdentifier; | |
| 368 return cachedNode; | |
| 369 } | |
| 370 } | |
| 371 listener.cancel('internal error: could not find $name', node: variables); | |
| 372 } | |
| 373 | |
| 374 Type computeType(Compiler compiler) { | |
| 375 return variables.computeType(compiler); | |
| 376 } | |
| 377 | |
| 378 Type get type() => variables.type; | |
| 379 | |
| 380 bool isInstanceMember() { | |
| 381 return isMember() && !modifiers.isStatic(); | |
| 382 } | |
| 383 | |
| 384 // Note: cachedNode.getBeginToken() will not be correct in all | |
| 385 // cases, for example, for function typed parameters. | |
| 386 Token position() => findMyName(variables.position()); | |
| 387 } | |
| 388 | |
| 389 /** | |
| 390 * Parameters in constructors that directly initialize fields. For example: | |
| 391 * [:A(this.field):]. | |
| 392 */ | |
| 393 class FieldParameterElement extends VariableElement { | |
| 394 VariableElement fieldElement; | |
| 395 | |
| 396 FieldParameterElement(SourceString name, | |
| 397 this.fieldElement, | |
| 398 VariableListElement variables, | |
| 399 Element enclosing, | |
| 400 Node node) | |
| 401 : super(name, variables, ElementKind.FIELD_PARAMETER, enclosing, node); | |
| 402 } | |
| 403 | |
| 404 // This element represents a list of variable or field declaration. | |
| 405 // It contains the node, and the type. A [VariableElement] always | |
| 406 // references its [VariableListElement]. It forwards its | |
| 407 // [computeType] and [parseNode] methods to this element. | |
| 408 class VariableListElement extends Element { | |
| 409 VariableDefinitions cachedNode; | |
| 410 Type type; | |
| 411 final Modifiers modifiers; | |
| 412 | |
| 413 VariableListElement(ElementKind kind, | |
| 414 Modifiers this.modifiers, | |
| 415 Element enclosing) | |
| 416 : super(null, kind, enclosing); | |
| 417 | |
| 418 VariableListElement.node(VariableDefinitions node, | |
| 419 ElementKind kind, | |
| 420 Element enclosing) | |
| 421 : super(null, kind, enclosing), | |
| 422 this.cachedNode = node, | |
| 423 this.modifiers = node.modifiers; | |
| 424 | |
| 425 VariableDefinitions parseNode(DiagnosticListener listener) { | |
| 426 return cachedNode; | |
| 427 } | |
| 428 | |
| 429 Type computeType(Compiler compiler) { | |
| 430 if (type != null) return type; | |
| 431 type = getType(parseNode(compiler).type, compiler, getLibrary()); | |
| 432 return type; | |
| 433 } | |
| 434 | |
| 435 Token position() => cachedNode.getBeginToken(); | |
| 436 } | |
| 437 | |
| 438 class ForeignElement extends Element { | |
| 439 ForeignElement(SourceString name, ContainerElement enclosingElement) | |
| 440 : super(name, ElementKind.FOREIGN, enclosingElement); | |
| 441 | |
| 442 Type computeType(Compiler compiler) { | |
| 443 return compiler.types.dynamicType; | |
| 444 } | |
| 445 | |
| 446 parseNode(DiagnosticListener listener) { | |
| 447 throw "internal error: ForeignElement has no node"; | |
| 448 } | |
| 449 } | |
| 450 | |
| 451 class AbstractFieldElement extends Element { | |
| 452 FunctionElement getter; | |
| 453 FunctionElement setter; | |
| 454 Modifiers modifiers; | |
| 455 | |
| 456 AbstractFieldElement(SourceString name, Element enclosing) | |
| 457 : super(name, ElementKind.ABSTRACT_FIELD, enclosing), | |
| 458 modifiers = new Modifiers.empty(); | |
| 459 | |
| 460 Type computeType(Compiler compiler) { | |
| 461 throw "internal error: AbstractFieldElement has no type"; | |
| 462 } | |
| 463 | |
| 464 Node parseNode(DiagnosticListener listener) { | |
| 465 throw "internal error: AbstractFieldElement has no node"; | |
| 466 } | |
| 467 | |
| 468 position() { | |
| 469 // The getter and setter may be defined in two different | |
| 470 // compilation units. However, we know that one of them is | |
| 471 // non-null and defined in the same compilation unit as the | |
| 472 // abstract element. | |
| 473 // | |
| 474 // We need to make sure that the position returned is relative to | |
| 475 // the compilation unit of the abstract element. | |
| 476 if (getter !== null && getter.enclosingElement === enclosingElement) { | |
| 477 return getter.position(); | |
| 478 } else if (setter != null) { | |
| 479 // TODO(ahe): checking for null should not be necessary. | |
| 480 return setter.position(); | |
| 481 } | |
| 482 } | |
| 483 } | |
| 484 | |
| 485 /** DEPRECATED. */ | |
| 486 Type getType(TypeAnnotation typeAnnotation, | |
| 487 Compiler compiler, | |
| 488 LibraryElement library) { | |
| 489 // TODO(karlklose,ngeoffray): This method should be removed and the | |
| 490 // information should be computed by the resolver. | |
| 491 | |
| 492 if (typeAnnotation == null || typeAnnotation.typeName == null) { | |
| 493 return compiler.types.dynamicType; | |
| 494 } | |
| 495 Identifier identifier = typeAnnotation.typeName.asIdentifier(); | |
| 496 if (identifier === null) { | |
| 497 compiler.reportWarning(typeAnnotation.typeName, | |
| 498 'library prefixes not handled'); | |
| 499 return compiler.types.dynamicType; | |
| 500 } | |
| 501 SourceString name = identifier.source; | |
| 502 Element element = library.find(name); | |
| 503 if (element !== null) { | |
| 504 if (element.isTypedef()) { | |
| 505 // TODO(ngeoffray): This is a hack to help us get support for the | |
| 506 // DOM library. | |
| 507 // TODO(ngeoffray): The list of types for the argument is wrong. | |
| 508 return new FunctionType(compiler.types.dynamicType, | |
| 509 const EmptyLink<Type>(), | |
| 510 element); | |
| 511 } | |
| 512 if (element.isClass()) { | |
| 513 // TODO(karlklose): substitute type parameters. | |
| 514 return element.computeType(compiler); | |
| 515 } | |
| 516 } | |
| 517 Type type = compiler.types.lookup(name); | |
| 518 if (type === null) { | |
| 519 type = compiler.types.dynamicType; | |
| 520 } | |
| 521 return type; | |
| 522 } | |
| 523 | |
| 524 class FunctionParameters { | |
| 525 Link<Element> requiredParameters; | |
| 526 Link<Element> optionalParameters; | |
| 527 int requiredParameterCount; | |
| 528 int optionalParameterCount; | |
| 529 FunctionParameters(this.requiredParameters, | |
| 530 this.optionalParameters, | |
| 531 this.requiredParameterCount, | |
| 532 this.optionalParameterCount); | |
| 533 | |
| 534 void forEachParameter(void function(Element parameter)) { | |
| 535 for (Link<Element> link = requiredParameters; | |
| 536 !link.isEmpty(); | |
| 537 link = link.tail) { | |
| 538 function(link.head); | |
| 539 } | |
| 540 for (Link<Element> link = optionalParameters; | |
| 541 !link.isEmpty(); | |
| 542 link = link.tail) { | |
| 543 function(link.head); | |
| 544 } | |
| 545 } | |
| 546 | |
| 547 int get parameterCount() => requiredParameterCount + optionalParameterCount; | |
| 548 } | |
| 549 | |
| 550 class FunctionElement extends Element { | |
| 551 FunctionExpression cachedNode; | |
| 552 Type type; | |
| 553 final Modifiers modifiers; | |
| 554 | |
| 555 FunctionParameters functionParameters; | |
| 556 | |
| 557 /** | |
| 558 * If this is an interface constructor, [defaultImplementation] will | |
| 559 * changed by the resolver to point to the default | |
| 560 * implementation. Otherwise, [:defaultImplementation === this:]. | |
| 561 */ | |
| 562 FunctionElement defaultImplementation; | |
| 563 | |
| 564 FunctionElement(SourceString name, | |
| 565 ElementKind kind, | |
| 566 Modifiers modifiers, | |
| 567 Element enclosing) | |
| 568 : this.tooMuchOverloading(name, null, kind, modifiers, enclosing, null); | |
| 569 | |
| 570 FunctionElement.node(SourceString name, | |
| 571 FunctionExpression node, | |
| 572 ElementKind kind, | |
| 573 Modifiers modifiers, | |
| 574 Element enclosing) | |
| 575 : this.tooMuchOverloading(name, node, kind, modifiers, enclosing, null); | |
| 576 | |
| 577 FunctionElement.from(SourceString name, | |
| 578 FunctionElement other, | |
| 579 Element enclosing) | |
| 580 : this.tooMuchOverloading(name, other.cachedNode, other.kind, | |
| 581 other.modifiers, enclosing, | |
| 582 other.functionParameters); | |
| 583 | |
| 584 FunctionElement.tooMuchOverloading(SourceString name, | |
| 585 FunctionExpression this.cachedNode, | |
| 586 ElementKind kind, | |
| 587 Modifiers this.modifiers, | |
| 588 Element enclosing, | |
| 589 FunctionParameters this.functionParameters) | |
| 590 : super(name, kind, enclosing) | |
| 591 { | |
| 592 defaultImplementation = this; | |
| 593 } | |
| 594 | |
| 595 bool isInstanceMember() { | |
| 596 return isMember() | |
| 597 && kind != ElementKind.GENERATIVE_CONSTRUCTOR | |
| 598 && !modifiers.isFactory() | |
| 599 && !modifiers.isStatic(); | |
| 600 } | |
| 601 | |
| 602 FunctionParameters computeParameters(Compiler compiler) { | |
| 603 if (functionParameters !== null) return functionParameters; | |
| 604 functionParameters = compiler.resolveSignature(this); | |
| 605 return functionParameters; | |
| 606 } | |
| 607 | |
| 608 int requiredParameterCount(Compiler compiler) { | |
| 609 return computeParameters(compiler).requiredParameterCount; | |
| 610 } | |
| 611 | |
| 612 int optionalParameterCount(Compiler compiler) { | |
| 613 return computeParameters(compiler).optionalParameterCount; | |
| 614 } | |
| 615 | |
| 616 int parameterCount(Compiler compiler) { | |
| 617 return computeParameters(compiler).parameterCount; | |
| 618 } | |
| 619 | |
| 620 FunctionType computeType(Compiler compiler) { | |
| 621 if (type != null) return type; | |
| 622 FunctionParameters parameters = computeParameters(compiler); | |
| 623 Types types = compiler.types; | |
| 624 FunctionExpression node = | |
| 625 compiler.parser.measure(() => parseNode(compiler)); | |
| 626 Type returnType = getType(node.returnType, compiler, getLibrary()); | |
| 627 if (returnType === null) returnType = types.dynamicType; | |
| 628 | |
| 629 LinkBuilder<Type> parameterTypes = new LinkBuilder<Type>(); | |
| 630 for (Link<Element> link = parameters.requiredParameters; | |
| 631 !link.isEmpty(); | |
| 632 link = link.tail) { | |
| 633 parameterTypes.addLast(link.head.computeType(compiler)); | |
| 634 } | |
| 635 type = new FunctionType(returnType, parameterTypes.toLink(), this); | |
| 636 return type; | |
| 637 } | |
| 638 | |
| 639 Node parseNode(DiagnosticListener listener) => cachedNode; | |
| 640 | |
| 641 Token position() => cachedNode.getBeginToken(); | |
| 642 } | |
| 643 | |
| 644 class ConstructorBodyElement extends FunctionElement { | |
| 645 FunctionElement constructor; | |
| 646 | |
| 647 ConstructorBodyElement(FunctionElement constructor) | |
| 648 : this.constructor = constructor, | |
| 649 super(constructor.name, | |
| 650 ElementKind.GENERATIVE_CONSTRUCTOR_BODY, | |
| 651 null, | |
| 652 constructor.enclosingElement) { | |
| 653 functionParameters = constructor.functionParameters; | |
| 654 } | |
| 655 | |
| 656 bool isInstanceMember() => true; | |
| 657 | |
| 658 FunctionType computeType(Compiler compiler) { unreachable(); } | |
| 659 | |
| 660 Node parseNode(DiagnosticListener listener) { | |
| 661 if (cachedNode !== null) return cachedNode; | |
| 662 cachedNode = constructor.parseNode(listener); | |
| 663 assert(cachedNode !== null); | |
| 664 return cachedNode; | |
| 665 } | |
| 666 | |
| 667 Token position() => constructor.position(); | |
| 668 } | |
| 669 | |
| 670 class SynthesizedConstructorElement extends FunctionElement { | |
| 671 SynthesizedConstructorElement(Element enclosing) | |
| 672 : super(enclosing.name, ElementKind.GENERATIVE_CONSTRUCTOR, | |
| 673 null, enclosing); | |
| 674 | |
| 675 Token position() => enclosingElement.position(); | |
| 676 } | |
| 677 | |
| 678 class ClassElement extends ContainerElement { | |
| 679 Type type; | |
| 680 Type supertype; | |
| 681 Type defaultClass; | |
| 682 Link<Element> members = const EmptyLink<Element>(); | |
| 683 Map<SourceString, Element> localMembers; | |
| 684 Map<SourceString, Element> constructors; | |
| 685 Link<Type> interfaces = const EmptyLink<Type>(); | |
| 686 Map<SourceString, TypeVariableElement> typeParameters; | |
| 687 bool isResolved = false; | |
| 688 bool isBeingResolved = false; | |
| 689 // backendMembers are members that have been added by the backend to simplify | |
| 690 // compilation. They don't have any user-side counter-part. | |
| 691 Link<Element> backendMembers = const EmptyLink<Element>(); | |
| 692 | |
| 693 Link<Type> allSupertypes; | |
| 694 | |
| 695 ClassElement(SourceString name, CompilationUnitElement enclosing) | |
| 696 : localMembers = new Map<SourceString, Element>(), | |
| 697 constructors = new Map<SourceString, Element>(), | |
| 698 typeParameters = new Map<SourceString, TypeVariableElement>(), | |
| 699 super(name, ElementKind.CLASS, enclosing); | |
| 700 | |
| 701 void addMember(Element element, DiagnosticListener listener) { | |
| 702 members = members.prepend(element); | |
| 703 if (element.kind == ElementKind.GENERATIVE_CONSTRUCTOR || | |
| 704 element.modifiers.isFactory()) { | |
| 705 constructors[element.name] = element; | |
| 706 } else if (element.kind == ElementKind.GETTER | |
| 707 || element.kind == ElementKind.SETTER) { | |
| 708 addGetterOrSetter(element, localMembers[element.name], listener); | |
| 709 } else { | |
| 710 localMembers[element.name] = element; | |
| 711 } | |
| 712 } | |
| 713 | |
| 714 Type computeType(compiler) { | |
| 715 if (type === null) { | |
| 716 type = new SimpleType(name, this); | |
| 717 } | |
| 718 return type; | |
| 719 } | |
| 720 | |
| 721 ClassElement ensureResolved(Compiler compiler) { | |
| 722 if (!isResolved && !isBeingResolved) { | |
| 723 isBeingResolved = true; | |
| 724 compiler.resolveType(this); | |
| 725 isBeingResolved = false; | |
| 726 isResolved = true; | |
| 727 } | |
| 728 return this; | |
| 729 } | |
| 730 | |
| 731 Element lookupTypeParameter(SourceString parameterName) { | |
| 732 Element result = typeParameters[parameterName]; | |
| 733 return result; | |
| 734 } | |
| 735 | |
| 736 Element lookupLocalMember(SourceString memberName) { | |
| 737 return localMembers[memberName]; | |
| 738 } | |
| 739 | |
| 740 Element lookupSuperMember(SourceString memberName) { | |
| 741 for (ClassElement s = superclass; s != null; s = s.superclass) { | |
| 742 Element e = s.lookupLocalMember(memberName); | |
| 743 if (e !== null) { | |
| 744 if (!memberName.isPrivate() || getLibrary() === e.getLibrary()) { | |
| 745 return e; | |
| 746 } | |
| 747 } | |
| 748 } | |
| 749 return null; | |
| 750 } | |
| 751 | |
| 752 Element lookupConstructor(SourceString className, | |
| 753 [SourceString constructorName = | |
| 754 const SourceString(''), | |
| 755 Element noMatch(Element)]) { | |
| 756 // TODO(karlklose): have a map from class names to a map of constructors | |
| 757 // instead of creating the name here? | |
| 758 SourceString normalizedName; | |
| 759 if (constructorName !== const SourceString('')) { | |
| 760 normalizedName = Elements.constructConstructorName(className, | |
| 761 constructorName); | |
| 762 } else { | |
| 763 normalizedName = className; | |
| 764 } | |
| 765 Element result = constructors[normalizedName]; | |
| 766 if (result === null && noMatch !== null) { | |
| 767 result = noMatch(lookupLocalMember(constructorName)); | |
| 768 } | |
| 769 return result; | |
| 770 } | |
| 771 | |
| 772 /** | |
| 773 * Returns the super class, if any. | |
| 774 * | |
| 775 * The returned element may not be resolved yet. | |
| 776 */ | |
| 777 ClassElement get superclass() { | |
| 778 assert(isResolved); | |
| 779 return supertype === null ? null : supertype.element; | |
| 780 } | |
| 781 | |
| 782 bool isInterface() => false; | |
| 783 bool isNative() => nativeName != null; | |
| 784 SourceString nativeName; | |
| 785 } | |
| 786 | |
| 787 class Elements { | |
| 788 static bool isLocal(Element element) { | |
| 789 return ((element !== null) | |
| 790 && !element.isInstanceMember() | |
| 791 && !isStaticOrTopLevelField(element) | |
| 792 && !isStaticOrTopLevelFunction(element) | |
| 793 && (element.kind === ElementKind.VARIABLE || | |
| 794 element.kind === ElementKind.PARAMETER || | |
| 795 element.kind === ElementKind.FUNCTION)); | |
| 796 } | |
| 797 | |
| 798 static bool isInstanceField(Element element) { | |
| 799 return (element !== null) | |
| 800 && element.isInstanceMember() | |
| 801 && (element.kind === ElementKind.FIELD | |
| 802 || element.kind === ElementKind.GETTER | |
| 803 || element.kind === ElementKind.SETTER); | |
| 804 } | |
| 805 | |
| 806 static bool isStaticOrTopLevel(Element element) { | |
| 807 return (element != null) | |
| 808 && !element.isInstanceMember() | |
| 809 && element.enclosingElement !== null | |
| 810 && (element.enclosingElement.kind == ElementKind.CLASS || | |
| 811 element.enclosingElement.kind == ElementKind.COMPILATION_UNIT || | |
| 812 element.enclosingElement.kind == ElementKind.LIBRARY); | |
| 813 } | |
| 814 | |
| 815 static bool isStaticOrTopLevelField(Element element) { | |
| 816 return isStaticOrTopLevel(element) | |
| 817 && (element.kind === ElementKind.FIELD | |
| 818 || element.kind === ElementKind.GETTER | |
| 819 || element.kind === ElementKind.SETTER); | |
| 820 } | |
| 821 | |
| 822 static bool isStaticOrTopLevelFunction(Element element) { | |
| 823 return isStaticOrTopLevel(element) | |
| 824 && (element.kind === ElementKind.FUNCTION); | |
| 825 } | |
| 826 | |
| 827 static bool isInstanceMethod(Element element) { | |
| 828 return (element != null) | |
| 829 && element.isInstanceMember() | |
| 830 && (element.kind === ElementKind.FUNCTION); | |
| 831 } | |
| 832 | |
| 833 static bool isInstanceSend(Send send, TreeElements elements) { | |
| 834 Element element = elements[send]; | |
| 835 if (element === null) return !isClosureSend(send, elements); | |
| 836 return isInstanceMethod(element) || isInstanceField(element); | |
| 837 } | |
| 838 | |
| 839 static bool isClosureSend(Send send, TreeElements elements) { | |
| 840 if (send.isPropertyAccess) return false; | |
| 841 if (send.receiver !== null) return false; | |
| 842 Element element = elements[send]; | |
| 843 // (o)() or foo()(). | |
| 844 if (element === null && send.selector.asIdentifier() === null) return true; | |
| 845 if (element === null) return false; | |
| 846 // foo() with foo a local or a parameter. | |
| 847 return isLocal(element); | |
| 848 } | |
| 849 | |
| 850 static SourceString constructConstructorName(SourceString receiver, | |
| 851 SourceString selector) { | |
| 852 String r = receiver.slowToString(); | |
| 853 String s = selector.slowToString(); | |
| 854 return new SourceString('$r\$$s'); | |
| 855 } | |
| 856 | |
| 857 static SourceString constructOperatorName(SourceString receiver, | |
| 858 SourceString selector, | |
| 859 [bool isPrefix = false]) { | |
| 860 String str = selector.stringValue; | |
| 861 if (str === '==' || str === '!=') return Namer.OPERATOR_EQUALS; | |
| 862 | |
| 863 if (str === '~') str = 'not'; | |
| 864 else if (str === 'negate' || (str === '-' && isPrefix)) str = 'negate'; | |
| 865 else if (str === '[]') str = 'index'; | |
| 866 else if (str === '[]=') str = 'indexSet'; | |
| 867 else if (str === '*' || str === '*=') str = 'mul'; | |
| 868 else if (str === '/' || str === '/=') str = 'div'; | |
| 869 else if (str === '%' || str === '%=') str = 'mod'; | |
| 870 else if (str === '~/' || str === '~/=') str = 'tdiv'; | |
| 871 else if (str === '+' || str === '+=') str = 'add'; | |
| 872 else if (str === '-' || str === '-=') str = 'sub'; | |
| 873 else if (str === '<<' || str === '<<=') str = 'shl'; | |
| 874 else if (str === '>>' || str === '>>=') str = 'shr'; | |
| 875 else if (str === '>=') str = 'ge'; | |
| 876 else if (str === '>') str = 'gt'; | |
| 877 else if (str === '<=') str = 'le'; | |
| 878 else if (str === '<') str = 'lt'; | |
| 879 else if (str === '&' || str === '&=') str = 'and'; | |
| 880 else if (str === '^' || str === '^=') str = 'xor'; | |
| 881 else if (str === '|' || str === '|=') str = 'or'; | |
| 882 else { | |
| 883 throw new Exception('Unhandled selector: ${selector.slowToString()}'); | |
| 884 } | |
| 885 return new SourceString('$receiver\$$str'); | |
| 886 } | |
| 887 | |
| 888 static bool isStringSupertype(Element element, Compiler compiler) { | |
| 889 LibraryElement coreLibrary = compiler.coreLibrary; | |
| 890 return (element == coreLibrary.find(const SourceString('Comparable'))) | |
| 891 || (element == coreLibrary.find(const SourceString('Hashable'))) | |
| 892 || (element == coreLibrary.find(const SourceString('Pattern'))); | |
| 893 } | |
| 894 | |
| 895 static bool isListSupertype(Element element, Compiler compiler) { | |
| 896 LibraryElement coreLibrary = compiler.coreLibrary; | |
| 897 return (element == coreLibrary.find(const SourceString('Collection'))) | |
| 898 || (element == coreLibrary.find(const SourceString('Iterable'))); | |
| 899 } | |
| 900 } | |
| 901 | |
| 902 | |
| 903 class LabelElement extends Element { | |
| 904 final Identifier label; | |
| 905 final String labelName; | |
| 906 final TargetElement target; | |
| 907 bool isBreakTarget = false; | |
| 908 bool isContinueTarget = false; | |
| 909 LabelElement(Identifier label, this.labelName, this.target, | |
| 910 Element enclosingElement) | |
| 911 : this.label = label, | |
| 912 super(label.source, ElementKind.LABEL, enclosingElement); | |
| 913 | |
| 914 void setBreakTarget() { | |
| 915 isBreakTarget = true; | |
| 916 target.isBreakTarget = true; | |
| 917 } | |
| 918 void setContinueTarget() { | |
| 919 isContinueTarget = true; | |
| 920 target.isContinueTarget = true; | |
| 921 } | |
| 922 | |
| 923 bool get isTarget() => isBreakTarget || isContinueTarget; | |
| 924 Node parseNode(DiagnosticListener l) => label; | |
| 925 | |
| 926 Token position() => label.token; | |
| 927 String toString() => "${labelName}:"; | |
| 928 } | |
| 929 | |
| 930 // Represents a reference to a statement, either a label or the | |
| 931 // default target of a break or continue. | |
| 932 class TargetElement extends Element { | |
| 933 // TODO(lrn): StatementElement is not just referencing statements anymore. | |
| 934 final Node statement; | |
| 935 final int nestingLevel; | |
| 936 Link<LabelElement> labels = const EmptyLink<LabelElement>(); | |
| 937 bool isBreakTarget = false; | |
| 938 bool isContinueTarget = false; | |
| 939 | |
| 940 TargetElement(this.statement, this.nestingLevel, Element enclosingElement) | |
| 941 : super(const SourceString(""), ElementKind.STATEMENT, enclosingElement); | |
| 942 bool get isTarget() => isBreakTarget || isContinueTarget; | |
| 943 | |
| 944 LabelElement addLabel(Identifier label, String labelName) { | |
| 945 LabelElement result = new LabelElement(label, labelName, this, | |
| 946 enclosingElement); | |
| 947 labels = labels.prepend(result); | |
| 948 return result; | |
| 949 } | |
| 950 | |
| 951 Node parseNode(DiagnosticListener l) => statement; | |
| 952 | |
| 953 bool get isSwitch() => statement is SwitchStatement; | |
| 954 | |
| 955 Token position() => statement.getBeginToken(); | |
| 956 String toString() => statement.toString(); | |
| 957 } | |
| 958 | |
| 959 class TypeVariableElement extends Element { | |
| 960 final Node node; | |
| 961 Type bound; | |
| 962 Type type; | |
| 963 TypeVariableElement(name, Element enclosing, this.node, this.type, | |
| 964 [this.bound]) | |
| 965 : super(name, ElementKind.TYPE_VARIABLE, enclosing); | |
| 966 Type computeType(compiler) => type; | |
| 967 Node parseNode(compiler) => node; | |
| 968 toString() => "${enclosingElement.toString()}.${name.slowToString()}"; | |
| 969 } | |
| OLD | NEW |