Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(71)

Side by Side Diff: sdk/lib/_internal/compiler/implementation/elements/modelx.dart

Issue 692513002: Remove old dart2js code. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2013, 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.modelx;
6
7 import 'elements.dart';
8 import '../constants/expressions.dart';
9 import '../helpers/helpers.dart'; // Included for debug helpers.
10 import '../tree/tree.dart';
11 import '../util/util.dart';
12 import '../resolution/resolution.dart';
13 import '../resolution/class_members.dart' show ClassMemberMixin;
14
15 import '../dart2jslib.dart' show invariant,
16 InterfaceType,
17 DartType,
18 TypeVariableType,
19 TypedefType,
20 DualKind,
21 MessageKind,
22 DiagnosticListener,
23 Script,
24 FunctionType,
25 Selector,
26 Constant,
27 Compiler,
28 Backend,
29 isPrivateName;
30
31 import '../dart_types.dart';
32
33 import '../scanner/scannerlib.dart' show
34 EOF_TOKEN,
35 ErrorToken,
36 Token;
37
38 import '../ordered_typeset.dart' show OrderedTypeSet;
39
40 import 'visitor.dart' show ElementVisitor;
41
42 abstract class DeclarationSite {
43 }
44
45 abstract class ElementX extends Element {
46 static int elementHashCode = 0;
47
48 final String name;
49 final ElementKind kind;
50 final Element enclosingElement;
51 final int hashCode = ++elementHashCode;
52 Link<MetadataAnnotation> metadata = const Link<MetadataAnnotation>();
53
54 ElementX(this.name, this.kind, this.enclosingElement) {
55 assert(isErroneous || implementationLibrary != null);
56 }
57
58 Modifiers get modifiers => Modifiers.EMPTY;
59
60 Node parseNode(DiagnosticListener listener) {
61 listener.internalError(this,
62 'parseNode not implemented on $this.');
63 return null;
64 }
65
66 DartType computeType(Compiler compiler) {
67 compiler.internalError(this,
68 "computeType not implemented on $this.");
69 return null;
70 }
71
72 void addMetadata(MetadataAnnotationX annotation) {
73 assert(annotation.annotatedElement == null);
74 annotation.annotatedElement = this;
75 addMetadataInternal(annotation);
76 }
77
78 void addMetadataInternal(MetadataAnnotation annotation) {
79 metadata = metadata.prepend(annotation);
80 }
81
82 bool get isClosure => false;
83 bool get isClassMember {
84 // Check that this element is defined in the scope of a Class.
85 return enclosingElement != null && enclosingElement.isClass;
86 }
87 bool get isInstanceMember => false;
88 bool get isDeferredLoaderGetter => false;
89
90 bool get isFactoryConstructor => modifiers.isFactory;
91 bool get isConst => modifiers.isConst;
92 bool get isFinal => modifiers.isFinal;
93 bool get isStatic => modifiers.isStatic;
94 bool get isOperator => Elements.isOperatorName(name);
95 bool get impliesType => (kind.category & ElementCategory.IMPLIES_TYPE) != 0;
96
97 bool get isPatched => false;
98
99 bool get isPatch => false;
100
101 bool get isImplementation => true;
102
103 bool get isDeclaration => true;
104
105 bool get isInjected => !isPatch && implementationLibrary.isPatch;
106
107 Element get implementation => this;
108
109 Element get declaration => this;
110
111 Element get patch {
112 throw new UnsupportedError('patch is not supported on $this');
113 }
114
115 Element get origin {
116 throw new UnsupportedError('origin is not supported on $this');
117 }
118
119 bool get isSynthesized => false;
120
121 bool get isForwardingConstructor => false;
122
123 bool get isMixinApplication => false;
124
125 bool get isLocal => false;
126
127 // TODO(johnniwinther): This breaks for libraries (for which enclosing
128 // elements are null) and is invalid for top level variable declarations for
129 // which the enclosing element is a VariableDeclarations and not a compilation
130 // unit.
131 bool get isTopLevel {
132 return enclosingElement != null && enclosingElement.isCompilationUnit;
133 }
134
135 bool get isAssignable {
136 if (isFinal || isConst) return false;
137 if (isFunction || isGenerativeConstructor) return false;
138 return true;
139 }
140
141 Token get position => null;
142
143 Token findMyName(Token token) {
144 return findNameToken(token, isConstructor, name, enclosingElement.name);
145 }
146
147 static Token findNameToken(Token token, bool isConstructor, String name,
148 String enclosingClassName) {
149 // We search for the token that has the name of this element.
150 // For constructors, that doesn't work because they may have
151 // named formed out of multiple tokens (named constructors) so
152 // for those we search for the class name instead.
153 String needle = isConstructor ? enclosingClassName : name;
154 // The unary '-' operator has a special element name (specified).
155 if (needle == 'unary-') needle = '-';
156 for (Token t = token; EOF_TOKEN != t.kind; t = t.next) {
157 if (t is !ErrorToken && needle == t.value) return t;
158 }
159 return token;
160 }
161
162 CompilationUnitElement get compilationUnit {
163 Element element = this;
164 while (!element.isCompilationUnit) {
165 element = element.enclosingElement;
166 }
167 return element;
168 }
169
170 LibraryElement get library => enclosingElement.library;
171
172 LibraryElement get implementationLibrary {
173 Element element = this;
174 while (!identical(element.kind, ElementKind.LIBRARY)) {
175 element = element.enclosingElement;
176 }
177 return element;
178 }
179
180 ClassElement get enclosingClass {
181 for (Element e = this; e != null; e = e.enclosingElement) {
182 if (e.isClass) return e;
183 }
184 return null;
185 }
186
187 Element get enclosingClassOrCompilationUnit {
188 for (Element e = this; e != null; e = e.enclosingElement) {
189 if (e.isClass || e.isCompilationUnit) return e;
190 }
191 return null;
192 }
193
194 Element get outermostEnclosingMemberOrTopLevel {
195 // TODO(lrn): Why is this called "Outermost"?
196 // TODO(johnniwinther): Clean up this method: This method does not return
197 // the outermost for elements in closure classses, but some call-sites rely
198 // on that behavior.
199 for (Element e = this; e != null; e = e.enclosingElement) {
200 if (e.isClassMember || e.isTopLevel) {
201 return e;
202 }
203 }
204 return null;
205 }
206
207 ClassElement get contextClass {
208 ClassElement cls;
209 for (Element e = this; e != null; e = e.enclosingElement) {
210 if (e.isClass) {
211 // Record [e] instead of returning it directly. We need the last class
212 // in the chain since the first classes might be closure classes.
213 cls = e.declaration;
214 }
215 }
216 return cls;
217 }
218
219 /**
220 * Creates the scope for this element.
221 */
222 Scope buildScope() => enclosingElement.buildScope();
223
224 String toString() {
225 // TODO(johnniwinther): Test for nullness of name, or make non-nullness an
226 // invariant for all element types?
227 var nameText = name != null ? name : '?';
228 if (enclosingElement != null && !isTopLevel) {
229 String holderName = enclosingElement.name != null
230 ? enclosingElement.name
231 : '${enclosingElement.kind}?';
232 return '$kind($holderName#${nameText})';
233 } else {
234 return '$kind(${nameText})';
235 }
236 }
237
238 String _fixedBackendName = null;
239 bool _isNative = false;
240 bool get isNative => _isNative;
241 bool get hasFixedBackendName => _fixedBackendName != null;
242 String get fixedBackendName => _fixedBackendName;
243 // Marks this element as a native element.
244 void setNative(String name) {
245 _isNative = true;
246 _fixedBackendName = name;
247 }
248 void setFixedBackendName(String name) {
249 _fixedBackendName = name;
250 }
251
252 FunctionElement asFunctionElement() => null;
253
254 bool get isAbstract => modifiers.isAbstract;
255 bool isForeign(Backend backend) => backend.isForeign(this);
256
257 void diagnose(Element context, DiagnosticListener listener) {}
258
259 bool get hasTreeElements => analyzableElement.hasTreeElements;
260
261 TreeElements get treeElements => analyzableElement.treeElements;
262
263 AnalyzableElement get analyzableElement {
264 Element element = outermostEnclosingMemberOrTopLevel;
265 if (element.isAbstractField || element.isPrefix) return element.library;
266 return element;
267 }
268
269 DeclarationSite get declarationSite => null;
270 }
271
272 class ErroneousElementX extends ElementX implements ErroneousElement {
273 final MessageKind messageKind;
274 final Map messageArguments;
275
276 ErroneousElementX(this.messageKind, this.messageArguments,
277 String name, Element enclosing)
278 : super(name, ElementKind.ERROR, enclosing);
279
280 bool get isTopLevel => false;
281
282 bool get isSynthesized => true;
283
284 AbstractFieldElement abstractField;
285
286 unsupported() {
287 throw 'unsupported operation on erroneous element';
288 }
289
290 Link<MetadataAnnotation> get metadata => unsupported();
291 bool get hasNode => false;
292 get node => unsupported();
293 get hasResolvedAst => false;
294 get resolvedAst => unsupported();
295 get type => unsupported();
296 get cachedNode => unsupported();
297 get functionSignature => unsupported();
298 get patch => null;
299 get origin => this;
300 get immediateRedirectionTarget => unsupported();
301 get nestedClosures => unsupported();
302 get memberContext => unsupported();
303 get executableContext => unsupported();
304
305 bool get isRedirectingFactory => unsupported();
306
307 computeSignature(compiler) => unsupported();
308
309 bool get hasFunctionSignature => false;
310
311 get effectiveTarget => this;
312
313 computeEffectiveTargetType(InterfaceType newType) => unsupported();
314
315 get definingConstructor => null;
316
317 FunctionElement asFunctionElement() => this;
318
319 String get message => '${messageKind.message(messageArguments)}';
320
321 String toString() => '<$name: $message>';
322
323 accept(ElementVisitor visitor) => visitor.visitErroneousElement(this);
324 }
325
326 /// A message attached to a [WarnOnUseElementX].
327 class WrappedMessage {
328 /// The message position. If [:null:] the position of the reference to the
329 /// [WarnOnUseElementX] is used.
330 final Spannable spannable;
331
332 /**
333 * The message to report on resolving a wrapped element.
334 */
335 final MessageKind messageKind;
336
337 /**
338 * The message arguments to report on resolving a wrapped element.
339 */
340 final Map messageArguments;
341
342 WrappedMessage(this.spannable, this.messageKind, this.messageArguments);
343 }
344
345 class WarnOnUseElementX extends ElementX implements WarnOnUseElement {
346 /// Warning to report on resolving this element.
347 final WrappedMessage warning;
348
349 /// Info to report on resolving this element.
350 final WrappedMessage info;
351
352 /// The element whose usage cause a warning.
353 final Element wrappedElement;
354
355 WarnOnUseElementX(WrappedMessage this.warning, WrappedMessage this.info,
356 Element enclosingElement, Element wrappedElement)
357 : this.wrappedElement = wrappedElement,
358 super(wrappedElement.name, ElementKind.WARN_ON_USE, enclosingElement);
359
360 Element unwrap(DiagnosticListener listener, Spannable usageSpannable) {
361 var unwrapped = wrappedElement;
362 if (warning != null) {
363 Spannable spannable = warning.spannable;
364 if (spannable == null) spannable = usageSpannable;
365 listener.reportWarning(
366 spannable, warning.messageKind, warning.messageArguments);
367 }
368 if (info != null) {
369 Spannable spannable = info.spannable;
370 if (spannable == null) spannable = usageSpannable;
371 listener.reportInfo(
372 spannable, info.messageKind, info.messageArguments);
373 }
374 if (unwrapped.isWarnOnUse) {
375 unwrapped = unwrapped.unwrap(listener, usageSpannable);
376 }
377 return unwrapped;
378 }
379
380 accept(ElementVisitor visitor) => visitor.visitWarnOnUseElement(this);
381 }
382
383 class AmbiguousElementX extends ElementX implements AmbiguousElement {
384 /**
385 * The message to report on resolving this element.
386 */
387 final MessageKind messageKind;
388
389 /**
390 * The message arguments to report on resolving this element.
391 */
392 final Map messageArguments;
393
394 /**
395 * The first element that this ambiguous element might refer to.
396 */
397 final Element existingElement;
398
399 /**
400 * The second element that this ambiguous element might refer to.
401 */
402 final Element newElement;
403
404 AmbiguousElementX(this.messageKind, this.messageArguments,
405 Element enclosingElement, Element existingElement, Element newElement)
406 : this.existingElement = existingElement,
407 this.newElement = newElement,
408 super(existingElement.name, ElementKind.AMBIGUOUS, enclosingElement);
409
410 Setlet flatten() {
411 Element element = this;
412 var set = new Setlet();
413 while (element.isAmbiguous) {
414 AmbiguousElement ambiguous = element;
415 set.add(ambiguous.newElement);
416 element = ambiguous.existingElement;
417 }
418 set.add(element);
419 return set;
420 }
421
422 void diagnose(Element context, DiagnosticListener listener) {
423 Setlet ambiguousElements = flatten();
424 MessageKind code = (ambiguousElements.length == 1)
425 ? MessageKind.AMBIGUOUS_REEXPORT : MessageKind.AMBIGUOUS_LOCATION;
426 LibraryElementX importer = context.library;
427 for (Element element in ambiguousElements) {
428 var arguments = {'name': element.name};
429 listener.reportInfo(element, code, arguments);
430 Link<Import> importers = importer.importers.getImports(element);
431 listener.withCurrentElement(importer, () {
432 for (; !importers.isEmpty; importers = importers.tail) {
433 listener.reportInfo(
434 importers.head, MessageKind.IMPORTED_HERE, arguments);
435 }
436 });
437 }
438 }
439
440 accept(ElementVisitor visitor) => visitor.visitAmbiguousElement(this);
441
442 bool get isTopLevel => false;
443 }
444
445 class ScopeX {
446 final Map<String, Element> contents = new Map<String, Element>();
447
448 bool get isEmpty => contents.isEmpty;
449 Iterable<Element> get values => contents.values;
450
451 Element lookup(String name) {
452 return contents[name];
453 }
454
455 void add(Element element, DiagnosticListener listener) {
456 String name = element.name;
457 if (element.isAccessor) {
458 addAccessor(element, contents[name], listener);
459 } else {
460 Element existing = contents.putIfAbsent(name, () => element);
461 if (!identical(existing, element)) {
462 listener.reportError(
463 element, MessageKind.DUPLICATE_DEFINITION, {'name': name});
464 listener.reportInfo(existing,
465 MessageKind.EXISTING_DEFINITION, {'name': name});
466 }
467 }
468 }
469
470 /**
471 * Adds a definition for an [accessor] (getter or setter) to a scope.
472 * The definition binds to an abstract field that can hold both a getter
473 * and a setter.
474 *
475 * The abstract field is added once, for the first getter or setter, and
476 * reused if the other one is also added.
477 * The abstract field should not be treated as a proper member of the
478 * container, it's simply a way to return two results for one lookup.
479 * That is, the getter or setter does not have the abstract field as enclosing
480 * element, they are enclosed by the class or compilation unit, as is the
481 * abstract field.
482 */
483 void addAccessor(FunctionElementX accessor,
484 Element existing,
485 DiagnosticListener listener) {
486 void reportError(Element other) {
487 listener.reportError(accessor,
488 MessageKind.DUPLICATE_DEFINITION,
489 {'name': accessor.name});
490 // TODO(johnniwinther): Make this an info instead of a fatal error.
491 listener.reportFatalError(other,
492 MessageKind.EXISTING_DEFINITION,
493 {'name': accessor.name});
494 }
495
496 if (existing != null) {
497 if (!identical(existing.kind, ElementKind.ABSTRACT_FIELD)) {
498 reportError(existing);
499 } else {
500 AbstractFieldElementX field = existing;
501 accessor.abstractField = field;
502 if (accessor.isGetter) {
503 if (field.getter != null && field.getter != accessor) {
504 reportError(field.getter);
505 }
506 field.getter = accessor;
507 } else {
508 assert(accessor.isSetter);
509 if (field.setter != null && field.setter != accessor) {
510 reportError(field.setter);
511 }
512 field.setter = accessor;
513 }
514 }
515 } else {
516 Element container = accessor.enclosingClassOrCompilationUnit;
517 AbstractFieldElementX field =
518 new AbstractFieldElementX(accessor.name, container);
519 accessor.abstractField = field;
520 if (accessor.isGetter) {
521 field.getter = accessor;
522 } else {
523 field.setter = accessor;
524 }
525 add(field, listener);
526 }
527 }
528 }
529
530 class CompilationUnitElementX extends ElementX
531 implements CompilationUnitElement {
532 final Script script;
533 PartOf partTag;
534 Link<Element> localMembers = const Link<Element>();
535
536 CompilationUnitElementX(Script script, LibraryElement library)
537 : this.script = script,
538 super(script.name,
539 ElementKind.COMPILATION_UNIT,
540 library) {
541 library.addCompilationUnit(this);
542 }
543
544 void forEachLocalMember(f(Element element)) {
545 localMembers.forEach(f);
546 }
547
548 void addMember(Element element, DiagnosticListener listener) {
549 // Keep a list of top level members.
550 localMembers = localMembers.prepend(element);
551 // Provide the member to the library to build scope.
552 if (enclosingElement.isPatch) {
553 implementationLibrary.addMember(element, listener);
554 } else {
555 library.addMember(element, listener);
556 }
557 }
558
559 void setPartOf(PartOf tag, DiagnosticListener listener) {
560 LibraryElementX library = enclosingElement;
561 if (library.entryCompilationUnit == this) {
562 listener.reportError(tag, MessageKind.ILLEGAL_DIRECTIVE);
563 return;
564 }
565 if (!localMembers.isEmpty) {
566 listener.reportError(tag, MessageKind.BEFORE_TOP_LEVEL);
567 return;
568 }
569 if (partTag != null) {
570 listener.reportWarning(tag, MessageKind.DUPLICATED_PART_OF);
571 return;
572 }
573 partTag = tag;
574 LibraryName libraryTag = library.libraryTag;
575 String actualName = tag.name.toString();
576 if (libraryTag != null) {
577 String expectedName = libraryTag.name.toString();
578 if (expectedName != actualName) {
579 listener.reportWarning(tag.name,
580 MessageKind.LIBRARY_NAME_MISMATCH,
581 {'libraryName': expectedName});
582 }
583 } else {
584 listener.reportWarning(library,
585 MessageKind.MISSING_LIBRARY_NAME,
586 {'libraryName': actualName});
587 listener.reportInfo(tag.name,
588 MessageKind.THIS_IS_THE_PART_OF_TAG);
589 }
590 }
591
592 bool get hasMembers => !localMembers.isEmpty;
593
594 int compareTo(CompilationUnitElement other) {
595 if (this == other) return 0;
596 return '${script.readableUri}'.compareTo('${other.script.readableUri}');
597 }
598
599 Element get analyzableElement => library;
600
601 accept(ElementVisitor visitor) => visitor.visitCompilationUnitElement(this);
602 }
603
604 class Importers {
605 Map<Element, Link<Import>> importers = new Map<Element, Link<Import>>();
606
607 Link<Import> getImports(Element element) {
608 Link<Import> imports = importers[element];
609 return imports != null ? imports : const Link<Import>();
610 }
611
612 Import getImport(Element element) => getImports(element).head;
613
614 void registerImport(Element element, Import import) {
615 if (import == null) return;
616
617 importers[element] =
618 importers.putIfAbsent(element, () => const Link<Import>())
619 .prepend(import);
620 }
621 }
622
623 class ImportScope {
624 /**
625 * Map for elements imported through import declarations.
626 *
627 * Addition to the map is performed by [addImport]. Lookup is done trough
628 * [find].
629 */
630 final Map<String, Element> importScope =
631 new Map<String, Element>();
632
633 /**
634 * Adds [element] to the import scope of this library.
635 *
636 * If an element by the same name is already in the imported scope, an
637 * [ErroneousElement] will be put in the imported scope, allowing for
638 * detection of ambiguous uses of imported names.
639 */
640 void addImport(Element enclosingElement,
641 Element element,
642 Import import,
643 DiagnosticListener listener) {
644 LibraryElementX library = enclosingElement.library;
645 Importers importers = library.importers;
646
647 String name = element.name;
648
649 // The loadLibrary function always shadows existing bindings to that name.
650 if (element.isDeferredLoaderGetter) {
651 importScope.remove(name);
652 // TODO(sigurdm): Print a hint.
653 }
654 Element existing = importScope.putIfAbsent(name, () => element);
655 importers.registerImport(element, import);
656
657 void registerWarnOnUseElement(Import import,
658 MessageKind messageKind,
659 Element hidingElement,
660 Element hiddenElement) {
661 Uri hiddenUri = hiddenElement.library.canonicalUri;
662 Uri hidingUri = hidingElement.library.canonicalUri;
663 Element element = new WarnOnUseElementX(
664 new WrappedMessage(
665 null, // Report on reference to [hidingElement].
666 messageKind,
667 {'name': name, 'hiddenUri': hiddenUri, 'hidingUri': hidingUri}),
668 new WrappedMessage(
669 listener.spanFromSpannable(import),
670 MessageKind.IMPORTED_HERE,
671 {'name': name}),
672 enclosingElement, hidingElement);
673 importScope[name] = element;
674 importers.registerImport(element, import);
675 }
676
677 if (existing != element) {
678 Import existingImport = importers.getImport(existing);
679 Element newElement;
680 if (existing.library.isPlatformLibrary &&
681 !element.library.isPlatformLibrary) {
682 // [existing] is implicitly hidden.
683 registerWarnOnUseElement(
684 import, MessageKind.HIDDEN_IMPORT, element, existing);
685 } else if (!existing.library.isPlatformLibrary &&
686 element.library.isPlatformLibrary) {
687 // [element] is implicitly hidden.
688 if (import == null) {
689 // [element] is imported implicitly (probably through dart:core).
690 registerWarnOnUseElement(
691 existingImport, MessageKind.HIDDEN_IMPLICIT_IMPORT,
692 existing, element);
693 } else {
694 registerWarnOnUseElement(
695 import, MessageKind.HIDDEN_IMPORT, existing, element);
696 }
697 } else {
698 Element ambiguousElement = new AmbiguousElementX(
699 MessageKind.DUPLICATE_IMPORT, {'name': name},
700 enclosingElement, existing, element);
701 importScope[name] = ambiguousElement;
702 importers.registerImport(ambiguousElement, import);
703 importers.registerImport(ambiguousElement, existingImport);
704 }
705 }
706 }
707
708 Element operator [](String name) => importScope[name];
709 }
710
711 class LibraryElementX
712 extends ElementX with AnalyzableElementX, PatchMixin<LibraryElementX>
713 implements LibraryElement {
714 final Uri canonicalUri;
715 CompilationUnitElement entryCompilationUnit;
716 Link<CompilationUnitElement> compilationUnits =
717 const Link<CompilationUnitElement>();
718 LinkBuilder<LibraryTag> tagsBuilder = new LinkBuilder<LibraryTag>();
719 List<LibraryTag> tagsCache;
720 LibraryName libraryTag;
721 bool canUseNative = false;
722 Link<Element> localMembers = const Link<Element>();
723 final ScopeX localScope = new ScopeX();
724 final ImportScope importScope = new ImportScope();
725
726 /// A mapping from an imported element to the "import" tag.
727 final Importers importers = new Importers();
728
729 /**
730 * Link for elements exported either through export declarations or through
731 * declaration. This field should not be accessed directly but instead through
732 * the [exports] getter.
733 *
734 * [LibraryDependencyHandler] sets this field through [setExports] when the
735 * library is loaded.
736 */
737 Link<Element> slotForExports;
738
739 final Map<LibraryDependency, LibraryElement> tagMapping =
740 new Map<LibraryDependency, LibraryElement>();
741
742 LibraryElementX(Script script,
743 [Uri canonicalUri, LibraryElementX origin])
744 : this.canonicalUri =
745 ((canonicalUri == null) ? script.readableUri : canonicalUri),
746 super(script.name, ElementKind.LIBRARY, null) {
747 entryCompilationUnit = new CompilationUnitElementX(script, this);
748 if (origin != null) {
749 origin.applyPatch(this);
750 }
751 }
752
753 bool get isDartCore => canonicalUri == Compiler.DART_CORE;
754
755 Link<MetadataAnnotation> get metadata {
756 return (libraryTag == null) ? super.metadata : libraryTag.metadata;
757 }
758
759 set metadata(value) {
760 // The metadata is stored on [libraryTag].
761 throw new SpannableAssertionFailure(this, 'Cannot set metadata on Library');
762 }
763
764 CompilationUnitElement get compilationUnit => entryCompilationUnit;
765
766 Element get analyzableElement => this;
767
768 void addCompilationUnit(CompilationUnitElement element) {
769 compilationUnits = compilationUnits.prepend(element);
770 }
771
772 void addTag(LibraryTag tag, DiagnosticListener listener) {
773 if (tagsCache != null) {
774 listener.internalError(tag,
775 "Library tags for $this have already been computed.");
776 }
777 tagsBuilder.addLast(tag);
778 }
779
780 Iterable<LibraryTag> get tags {
781 if (tagsCache == null) {
782 tagsCache = tagsBuilder.toList();
783 tagsBuilder = null;
784 }
785 return tagsCache;
786 }
787
788 void recordResolvedTag(LibraryDependency tag, LibraryElement library) {
789 assert(tagMapping[tag] == null);
790 tagMapping[tag] = library;
791 }
792
793 LibraryElement getLibraryFromTag(LibraryDependency tag) => tagMapping[tag];
794
795 /**
796 * Adds [element] to the import scope of this library.
797 *
798 * If an element by the same name is already in the imported scope, an
799 * [ErroneousElement] will be put in the imported scope, allowing for
800 * detection of ambiguous uses of imported names.
801 */
802 void addImport(Element element, Import import, DiagnosticListener listener) {
803 importScope.addImport(this, element, import, listener);
804 }
805
806 void addMember(Element element, DiagnosticListener listener) {
807 localMembers = localMembers.prepend(element);
808 addToScope(element, listener);
809 }
810
811 void addToScope(Element element, DiagnosticListener listener) {
812 localScope.add(element, listener);
813 }
814
815 Element localLookup(String elementName) {
816 Element result = localScope.lookup(elementName);
817 if (result == null && isPatch) {
818 result = origin.localLookup(elementName);
819 }
820 return result;
821 }
822
823 /**
824 * Returns [:true:] if the export scope has already been computed for this
825 * library.
826 */
827 bool get exportsHandled => slotForExports != null;
828
829 Link<Element> get exports {
830 assert(invariant(this, exportsHandled,
831 message: 'Exports not handled on $this'));
832 return slotForExports;
833 }
834
835 /**
836 * Sets the export scope of this library. This method can only be called once.
837 */
838 void setExports(Iterable<Element> exportedElements) {
839 assert(invariant(this, !exportsHandled,
840 message: 'Exports already set to $slotForExports on $this'));
841 assert(invariant(this, exportedElements != null));
842 var builder = new LinkBuilder<Element>();
843 for (Element export in exportedElements) {
844 builder.addLast(export);
845 }
846 slotForExports = builder.toLink();
847 }
848
849 LibraryElement get library => isPatch ? origin : this;
850
851 /**
852 * Look up a top-level element in this library. The element could
853 * potentially have been imported from another library. Returns
854 * null if no such element exist and an [ErroneousElement] if multiple
855 * elements have been imported.
856 */
857 Element find(String elementName) {
858 Element result = localScope.lookup(elementName);
859 if (result != null) return result;
860 if (origin != null) {
861 result = origin.localScope.lookup(elementName);
862 if (result != null) return result;
863 }
864 result = importScope[elementName];
865 if (result != null) return result;
866 if (origin != null) {
867 result = origin.importScope[elementName];
868 if (result != null) return result;
869 }
870 return null;
871 }
872
873 /** Look up a top-level element in this library, but only look for
874 * non-imported elements. Returns null if no such element exist. */
875 Element findLocal(String elementName) {
876 // TODO(johnniwinther): How to handle injected elements in the patch
877 // library?
878 Element result = localScope.lookup(elementName);
879 if (result == null || result.library != this) return null;
880 return result;
881 }
882
883 Element findExported(String elementName) {
884 for (Link link = exports; !link.isEmpty; link = link.tail) {
885 Element element = link.head;
886 if (element.name == elementName) return element;
887 }
888 return null;
889 }
890
891 void forEachExport(f(Element element)) {
892 exports.forEach((Element e) => f(e));
893 }
894
895 Link<Import> getImportsFor(Element element) => importers.getImports(element);
896
897 void forEachLocalMember(f(Element element)) {
898 if (isPatch) {
899 // Patch libraries traverse both origin and injected members.
900 origin.localMembers.forEach(f);
901
902 void filterPatch(Element element) {
903 if (!element.isPatch) {
904 // Do not traverse the patch members.
905 f(element);
906 }
907 }
908 localMembers.forEach(filterPatch);
909 } else {
910 localMembers.forEach(f);
911 }
912 }
913
914 Iterable<Element> getNonPrivateElementsInScope() {
915 return localScope.values.where((Element element) {
916 // At this point [localScope] only contains members so we don't need
917 // to check for foreign or prefix elements.
918 return !isPrivateName(element.name);
919 });
920 }
921
922 bool hasLibraryName() => libraryTag != null;
923
924 /**
925 * Returns the library name, which is either the name given in the library tag
926 * or the empty string if there is no library tag.
927 */
928 String getLibraryName() {
929 if (libraryTag == null) return '';
930 return libraryTag.name.toString();
931 }
932
933 /**
934 * Returns the library name (as defined by the library tag) or for script
935 * (which have no library tag) the script file name. The latter case is used
936 * to private 'library name' for scripts to use for instance in dartdoc.
937 *
938 * Note: the returned filename will still be escaped ("a%20b.dart" instead of
939 * "a b.dart").
940 */
941 String getLibraryOrScriptName() {
942 if (libraryTag != null) {
943 return libraryTag.name.toString();
944 } else {
945 // Use the file name as script name.
946 String path = canonicalUri.path;
947 return path.substring(path.lastIndexOf('/') + 1);
948 }
949 }
950
951 Scope buildScope() => new LibraryScope(this);
952
953 bool get isPlatformLibrary => canonicalUri.scheme == 'dart';
954
955 bool get isPackageLibrary => canonicalUri.scheme == 'package';
956
957 bool get isInternalLibrary =>
958 isPlatformLibrary && canonicalUri.path.startsWith('_');
959
960 String toString() {
961 if (origin != null) {
962 return 'patch library(${canonicalUri})';
963 } else if (patch != null) {
964 return 'origin library(${canonicalUri})';
965 } else {
966 return 'library(${canonicalUri})';
967 }
968 }
969
970 int compareTo(LibraryElement other) {
971 if (this == other) return 0;
972 return getLibraryOrScriptName().compareTo(other.getLibraryOrScriptName());
973 }
974
975 accept(ElementVisitor visitor) => visitor.visitLibraryElement(this);
976
977 // TODO(johnniwinther): Remove these when issue 18630 is fixed.
978 LibraryElementX get patch => super.patch;
979 LibraryElementX get origin => super.origin;
980 }
981
982 class PrefixElementX extends ElementX implements PrefixElement {
983 Token firstPosition;
984
985 final ImportScope importScope = new ImportScope();
986
987 bool get isDeferred => _deferredImport != null;
988
989 // Only needed for deferred imports.
990 Import _deferredImport;
991 Import get deferredImport => _deferredImport;
992
993 PrefixElementX(String prefix, Element enclosing, this.firstPosition)
994 : super(prefix, ElementKind.PREFIX, enclosing);
995
996 bool get isTopLevel => false;
997
998 Element lookupLocalMember(String memberName) => importScope[memberName];
999
1000 DartType computeType(Compiler compiler) => const DynamicType();
1001
1002 Token get position => firstPosition;
1003
1004 void addImport(Element element, Import import, DiagnosticListener listener) {
1005 importScope.addImport(this, element, import, listener);
1006 }
1007
1008 accept(ElementVisitor visitor) => visitor.visitPrefixElement(this);
1009
1010 void markAsDeferred(Import deferredImport) {
1011 _deferredImport = deferredImport;
1012 }
1013 }
1014
1015 class TypedefElementX extends ElementX
1016 with AstElementMixin,
1017 AnalyzableElementX,
1018 TypeDeclarationElementX<TypedefType>
1019 implements TypedefElement {
1020 Typedef cachedNode;
1021
1022 /**
1023 * The type annotation which defines this typedef.
1024 */
1025 DartType alias;
1026
1027 /// [:true:] if the typedef has been checked for cyclic reference.
1028 bool hasBeenCheckedForCycles = false;
1029
1030 int resolutionState = STATE_NOT_STARTED;
1031
1032 TypedefElementX(String name, Element enclosing)
1033 : super(name, ElementKind.TYPEDEF, enclosing);
1034
1035 bool get hasNode => cachedNode != null;
1036
1037 Typedef get node {
1038 assert(invariant(this, cachedNode != null,
1039 message: "Node has not been computed for $this."));
1040 return cachedNode;
1041 }
1042
1043 /**
1044 * Function signature for a typedef of a function type. The signature is
1045 * kept to provide full information about parameter names through the mirror
1046 * system.
1047 *
1048 * The [functionSignature] is not available until the typedef element has been
1049 * resolved.
1050 */
1051 FunctionSignature functionSignature;
1052
1053 TypedefType computeType(Compiler compiler) {
1054 if (thisTypeCache != null) return thisTypeCache;
1055 Typedef node = parseNode(compiler);
1056 setThisAndRawTypes(compiler, createTypeVariables(node.typeParameters));
1057 ensureResolved(compiler);
1058 return thisTypeCache;
1059 }
1060
1061 void ensureResolved(Compiler compiler) {
1062 if (resolutionState == STATE_NOT_STARTED) {
1063 compiler.resolver.resolve(this);
1064 }
1065 }
1066
1067 TypedefType createType(List<DartType> typeArguments) {
1068 return new TypedefType(this, typeArguments);
1069 }
1070
1071 Scope buildScope() {
1072 return new TypeDeclarationScope(enclosingElement.buildScope(), this);
1073 }
1074
1075 void checkCyclicReference(Compiler compiler) {
1076 if (hasBeenCheckedForCycles) return;
1077 var visitor = new TypedefCyclicVisitor(compiler, this);
1078 computeType(compiler).accept(visitor, null);
1079 hasBeenCheckedForCycles = true;
1080 }
1081
1082 accept(ElementVisitor visitor) => visitor.visitTypedefElement(this);
1083
1084 // A typedef cannot be patched therefore defines itself.
1085 AstElement get definingElement => this;
1086 }
1087
1088 // This class holds common information for a list of variable or field
1089 // declarations. It contains the node, and the type. A [VariableElementX]
1090 // forwards its [computeType] and [parseNode] methods to this class.
1091 class VariableList implements DeclarationSite {
1092 VariableDefinitions definitions;
1093 DartType type;
1094 final Modifiers modifiers;
1095 Link<MetadataAnnotation> metadata = const Link<MetadataAnnotation>();
1096
1097 VariableList(Modifiers this.modifiers);
1098
1099 VariableList.node(VariableDefinitions node, this.type)
1100 : this.definitions = node,
1101 this.modifiers = node.modifiers {
1102 assert(modifiers != null);
1103 }
1104
1105 VariableDefinitions parseNode(Element element, DiagnosticListener listener) {
1106 return definitions;
1107 }
1108
1109 DartType computeType(Element element, Compiler compiler) => type;
1110 }
1111
1112 abstract class VariableElementX extends ElementX with AstElementMixin
1113 implements VariableElement {
1114 final Token token;
1115 final VariableList variables;
1116 VariableDefinitions definitionsCache;
1117 Expression initializerCache;
1118
1119 Modifiers get modifiers => variables.modifiers;
1120
1121 VariableElementX(String name,
1122 ElementKind kind,
1123 Element enclosingElement,
1124 VariableList variables,
1125 this.token)
1126 : this.variables = variables,
1127 super(name, kind, enclosingElement);
1128
1129 // TODO(johnniwinther): Ensure that the [TreeElements] for this variable hold
1130 // the mappings for all its metadata.
1131 Link<MetadataAnnotation> get metadata => variables.metadata;
1132
1133 void addMetadataInternal(MetadataAnnotation annotation) {
1134 variables.metadata = variables.metadata.prepend(annotation);
1135 }
1136
1137 // A variable cannot be patched therefore defines itself.
1138 AstElement get definingElement => this;
1139
1140 bool get hasNode => definitionsCache != null;
1141
1142 VariableDefinitions get node {
1143 assert(invariant(this, definitionsCache != null,
1144 message: "Node has not been computed for $this."));
1145 return definitionsCache;
1146 }
1147
1148 Expression get initializer {
1149 assert(invariant(this, definitionsCache != null,
1150 message: "Initializer has not been computed for $this."));
1151 return initializerCache;
1152 }
1153
1154 Node parseNode(DiagnosticListener listener) {
1155 if (definitionsCache != null) return definitionsCache;
1156
1157 VariableDefinitions definitions = variables.parseNode(this, listener);
1158 createDefinitions(definitions);
1159 return definitionsCache;
1160 }
1161
1162 void createDefinitions(VariableDefinitions definitions) {
1163 assert(invariant(this, definitionsCache == null,
1164 message: "VariableDefinitions has already been computed for $this."));
1165 Expression node;
1166 int count = 0;
1167 for (Link<Node> link = definitions.definitions.nodes;
1168 !link.isEmpty; link = link.tail) {
1169 Expression initializedIdentifier = link.head;
1170 Identifier identifier = initializedIdentifier.asIdentifier();
1171 if (identifier == null) {
1172 SendSet sendSet = initializedIdentifier.asSendSet();
1173 identifier = sendSet.selector.asIdentifier();
1174 if (identical(name, identifier.source)) {
1175 node = initializedIdentifier;
1176 initializerCache = sendSet.arguments.first;
1177 }
1178 } else if (identical(name, identifier.source)) {
1179 node = initializedIdentifier;
1180 }
1181 count++;
1182 }
1183 invariant(definitions, node != null, message: "Could not find '$name'.");
1184 if (count == 1) {
1185 definitionsCache = definitions;
1186 } else {
1187 // Create a [VariableDefinitions] node for the single definition of
1188 // [node].
1189 definitionsCache = new VariableDefinitions(definitions.type,
1190 definitions.modifiers, new NodeList(
1191 definitions.definitions.beginToken,
1192 const Link<Node>().prepend(node),
1193 definitions.definitions.endToken));
1194 }
1195 }
1196
1197 DartType computeType(Compiler compiler) {
1198 if (variables.type != null) return variables.type;
1199 // Call [parseNode] to ensure that [definitionsCache] and [initializerCache]
1200 // are set as a consequence of calling [computeType].
1201 return compiler.withCurrentElement(this, () {
1202 parseNode(compiler);
1203 return variables.computeType(this, compiler);
1204 });
1205 }
1206
1207 DartType get type {
1208 assert(invariant(this, variables.type != null,
1209 message: "Type has not been computed for $this."));
1210 return variables.type;
1211 }
1212
1213 bool get isInstanceMember => isClassMember && !isStatic;
1214
1215 // Note: cachedNode.beginToken will not be correct in all
1216 // cases, for example, for function typed parameters.
1217 Token get position => token;
1218
1219 accept(ElementVisitor visitor) => visitor.visitVariableElement(this);
1220
1221 DeclarationSite get declarationSite => variables;
1222 }
1223
1224 class LocalVariableElementX extends VariableElementX
1225 implements LocalVariableElement {
1226 LocalVariableElementX(String name,
1227 ExecutableElement enclosingElement,
1228 VariableList variables,
1229 Token token)
1230 : super(name, ElementKind.VARIABLE, enclosingElement, variables, token) {
1231 createDefinitions(variables.definitions);
1232 }
1233
1234 // TODO(johnniwinther): Remove this when the dart `backend_ast` does not need
1235 // [Element] for entities.
1236 LocalVariableElementX.synthetic(String name,
1237 ExecutableElement enclosingElement,
1238 VariableList variables)
1239 : super(name, ElementKind.VARIABLE, enclosingElement, variables, null);
1240
1241 ExecutableElement get executableContext => enclosingElement;
1242
1243 ExecutableElement get memberContext => executableContext.memberContext;
1244
1245 bool get isLocal => true;
1246 }
1247
1248 class FieldElementX extends VariableElementX
1249 with AnalyzableElementX implements FieldElement {
1250 List<FunctionElement> nestedClosures = new List<FunctionElement>();
1251
1252 FieldElementX(Identifier name,
1253 Element enclosingElement,
1254 VariableList variables)
1255 : super(name.source, ElementKind.FIELD, enclosingElement,
1256 variables, name.token);
1257
1258 accept(ElementVisitor visitor) => visitor.visitFieldElement(this);
1259
1260 MemberElement get memberContext => this;
1261
1262 void reuseElement() {
1263 super.reuseElement();
1264 nestedClosures.clear();
1265 }
1266 }
1267
1268 /// [Element] for a parameter-like element.
1269 class FormalElementX extends ElementX
1270 with AstElementMixin
1271 implements FormalElement {
1272 final VariableDefinitions definitions;
1273 final Identifier identifier;
1274 DartType typeCache;
1275
1276 /**
1277 * Function signature for a variable with a function type. The signature is
1278 * kept to provide full information about parameter names through the mirror
1279 * system.
1280 */
1281 FunctionSignature functionSignatureCache;
1282
1283 FormalElementX(ElementKind elementKind,
1284 FunctionTypedElement enclosingElement,
1285 this.definitions,
1286 Identifier identifier)
1287 : this.identifier = identifier,
1288 super(identifier.source, elementKind, enclosingElement);
1289
1290 FunctionTypedElement get functionDeclaration => enclosingElement;
1291
1292 Modifiers get modifiers => definitions.modifiers;
1293
1294 Token get position => identifier.getBeginToken();
1295
1296 Node parseNode(DiagnosticListener listener) => definitions;
1297
1298 DartType computeType(Compiler compiler) {
1299 assert(invariant(this, type != null,
1300 message: "Parameter type has not been set for $this."));
1301 return type;
1302 }
1303
1304 DartType get type {
1305 assert(invariant(this, typeCache != null,
1306 message: "Parameter type has not been set for $this."));
1307 return typeCache;
1308 }
1309
1310 FunctionSignature get functionSignature {
1311 assert(invariant(this, typeCache != null,
1312 message: "Parameter signature has not been set for $this."));
1313 return functionSignatureCache;
1314 }
1315
1316 bool get hasNode => true;
1317
1318 VariableDefinitions get node => definitions;
1319
1320 FunctionType get functionType => type;
1321
1322 accept(ElementVisitor visitor) => visitor.visitFormalElement(this);
1323
1324 // A parameter is defined by the declaration element.
1325 AstElement get definingElement => declaration;
1326 }
1327
1328 /// [Element] for a formal parameter.
1329 ///
1330 /// A [ParameterElementX] can be patched. A parameter of an external method is
1331 /// patched with the corresponding parameter of the patch method. This is done
1332 /// to ensure that default values on parameters are computed once (on the
1333 /// origin parameter) but can be found through both the origin and the patch.
1334 abstract class ParameterElementX extends FormalElementX
1335 with PatchMixin<ParameterElement> implements ParameterElement {
1336 final Expression initializer;
1337
1338 ParameterElementX(ElementKind elementKind,
1339 FunctionElement functionDeclaration,
1340 VariableDefinitions definitions,
1341 Identifier identifier,
1342 this.initializer)
1343 : super(elementKind, functionDeclaration, definitions, identifier);
1344
1345 FunctionElement get functionDeclaration => enclosingElement;
1346
1347 ExecutableElement get executableContext => enclosingElement;
1348
1349 MemberElement get memberContext => executableContext.memberContext;
1350
1351 accept(ElementVisitor visitor) => visitor.visitParameterElement(this);
1352
1353 bool get isLocal => true;
1354 }
1355
1356 class LocalParameterElementX extends ParameterElementX
1357 implements LocalParameterElement {
1358 LocalParameterElementX(FunctionElement functionDeclaration,
1359 VariableDefinitions definitions,
1360 Identifier identifier,
1361 Expression initializer)
1362 : super(ElementKind.PARAMETER, functionDeclaration,
1363 definitions, identifier, initializer);
1364 }
1365
1366 /// Parameters in constructors that directly initialize fields. For example:
1367 /// `A(this.field)`.
1368 class InitializingFormalElementX extends ParameterElementX
1369 implements InitializingFormalElement {
1370 FieldElement fieldElement;
1371
1372 InitializingFormalElementX(ConstructorElement constructorDeclaration,
1373 VariableDefinitions variables,
1374 Identifier identifier,
1375 Expression initializer,
1376 this.fieldElement)
1377 : super(ElementKind.INITIALIZING_FORMAL, constructorDeclaration,
1378 variables, identifier, initializer);
1379
1380 accept(ElementVisitor visitor) => visitor.visitFieldParameterElement(this);
1381
1382 MemberElement get memberContext => enclosingElement;
1383
1384 bool get isLocal => false;
1385 }
1386
1387
1388 class AbstractFieldElementX extends ElementX implements AbstractFieldElement {
1389 FunctionElementX getter;
1390 FunctionElementX setter;
1391
1392 AbstractFieldElementX(String name, Element enclosing)
1393 : super(name, ElementKind.ABSTRACT_FIELD, enclosing);
1394
1395 DartType computeType(Compiler compiler) {
1396 throw "internal error: AbstractFieldElement has no type";
1397 }
1398
1399 Node parseNode(DiagnosticListener listener) {
1400 throw "internal error: AbstractFieldElement has no node";
1401 }
1402
1403 Token get position {
1404 // The getter and setter may be defined in two different
1405 // compilation units. However, we know that one of them is
1406 // non-null and defined in the same compilation unit as the
1407 // abstract element.
1408 // TODO(lrn): No we don't know that if the element from the same
1409 // compilation unit is patched.
1410 //
1411 // We need to make sure that the position returned is relative to
1412 // the compilation unit of the abstract element.
1413 if (getter != null
1414 && identical(getter.compilationUnit, compilationUnit)) {
1415 return getter.position;
1416 } else {
1417 return setter.position;
1418 }
1419 }
1420
1421 Modifiers get modifiers {
1422 // The resolver ensures that the flags match (ignoring abstract).
1423 if (getter != null) {
1424 return new Modifiers.withFlags(
1425 getter.modifiers.nodes,
1426 getter.modifiers.flags | Modifiers.FLAG_ABSTRACT);
1427 } else {
1428 return new Modifiers.withFlags(
1429 setter.modifiers.nodes,
1430 setter.modifiers.flags | Modifiers.FLAG_ABSTRACT);
1431 }
1432 }
1433
1434 bool get isInstanceMember {
1435 return isClassMember && !isStatic;
1436 }
1437
1438 accept(ElementVisitor visitor) => visitor.visitAbstractFieldElement(this);
1439
1440 bool get isAbstract {
1441 return getter != null && getter.isAbstract
1442 || setter != null && setter.isAbstract;
1443 }
1444 }
1445
1446 // TODO(johnniwinther): [FunctionSignature] should be merged with
1447 // [FunctionType].
1448 // TODO(karlklose): all these lists should have element type [FormalElement].
1449 class FunctionSignatureX implements FunctionSignature {
1450 final Link<Element> requiredParameters;
1451 final Link<Element> optionalParameters;
1452 final int requiredParameterCount;
1453 final int optionalParameterCount;
1454 final bool optionalParametersAreNamed;
1455 final List<Element> orderedOptionalParameters;
1456 final FunctionType type;
1457 final bool hasOptionalParameters;
1458
1459 FunctionSignatureX(this.requiredParameters,
1460 Link<Element> optionalParameters,
1461 this.requiredParameterCount,
1462 this.optionalParameterCount,
1463 this.optionalParametersAreNamed,
1464 this.orderedOptionalParameters,
1465 this.type)
1466 : optionalParameters = optionalParameters,
1467 hasOptionalParameters = !optionalParameters.isEmpty;
1468
1469 void forEachRequiredParameter(void function(Element parameter)) {
1470 for (Link<Element> link = requiredParameters;
1471 !link.isEmpty;
1472 link = link.tail) {
1473 function(link.head);
1474 }
1475 }
1476
1477 void forEachOptionalParameter(void function(Element parameter)) {
1478 for (Link<Element> link = optionalParameters;
1479 !link.isEmpty;
1480 link = link.tail) {
1481 function(link.head);
1482 }
1483 }
1484
1485 Element get firstOptionalParameter => optionalParameters.head;
1486
1487 void forEachParameter(void function(Element parameter)) {
1488 forEachRequiredParameter(function);
1489 forEachOptionalParameter(function);
1490 }
1491
1492 void orderedForEachParameter(void function(Element parameter)) {
1493 forEachRequiredParameter(function);
1494 orderedOptionalParameters.forEach(function);
1495 }
1496
1497 int get parameterCount => requiredParameterCount + optionalParameterCount;
1498
1499 /**
1500 * Check whether a function with this signature can be used instead of a
1501 * function with signature [signature] without causing a `noSuchMethod`
1502 * exception/call.
1503 */
1504 bool isCompatibleWith(FunctionSignature signature) {
1505 if (optionalParametersAreNamed) {
1506 if (!signature.optionalParametersAreNamed) {
1507 return requiredParameterCount == signature.parameterCount;
1508 }
1509 // If both signatures have named parameters, then they must have
1510 // the same number of required parameters, and the names in
1511 // [signature] must all be in [:this:].
1512 if (requiredParameterCount != signature.requiredParameterCount) {
1513 return false;
1514 }
1515 Set<String> names = optionalParameters.mapToSet(
1516 (Element element) => element.name);
1517 for (Element namedParameter in signature.optionalParameters) {
1518 if (!names.contains(namedParameter.name)) {
1519 return false;
1520 }
1521 }
1522 } else {
1523 if (signature.optionalParametersAreNamed) return false;
1524 // There must be at least as many arguments as in the other signature, but
1525 // this signature must not have more required parameters. Having more
1526 // optional parameters is not a problem, they simply are never provided
1527 // by call sites of a call to a method with the other signature.
1528 int otherTotalCount = signature.parameterCount;
1529 return requiredParameterCount <= otherTotalCount
1530 && parameterCount >= otherTotalCount;
1531 }
1532 return true;
1533 }
1534 }
1535
1536 abstract class BaseFunctionElementX
1537 extends ElementX with PatchMixin<FunctionElement>, AstElementMixin
1538 implements FunctionElement {
1539 DartType typeCache;
1540 final Modifiers modifiers;
1541
1542 List<FunctionElement> nestedClosures = new List<FunctionElement>();
1543
1544 FunctionSignature functionSignatureCache;
1545
1546 final bool _hasNoBody;
1547
1548 AbstractFieldElement abstractField;
1549
1550 BaseFunctionElementX(String name,
1551 ElementKind kind,
1552 Modifiers this.modifiers,
1553 Element enclosing,
1554 bool hasNoBody)
1555 : super(name, kind, enclosing),
1556 _hasNoBody = hasNoBody {
1557 assert(modifiers != null);
1558 }
1559
1560 bool get isInstanceMember {
1561 return isClassMember
1562 && !isConstructor
1563 && !isStatic;
1564 }
1565
1566 bool get hasFunctionSignature => functionSignatureCache != null;
1567
1568 FunctionSignature computeSignature(Compiler compiler) {
1569 if (functionSignatureCache != null) return functionSignatureCache;
1570 compiler.withCurrentElement(this, () {
1571 functionSignatureCache = compiler.resolver.resolveSignature(this);
1572 });
1573 return functionSignatureCache;
1574 }
1575
1576 FunctionSignature get functionSignature {
1577 assert(invariant(this, functionSignatureCache != null,
1578 message: "Function signature has not been computed for $this."));
1579 return functionSignatureCache;
1580 }
1581
1582 FunctionType computeType(Compiler compiler) {
1583 if (typeCache != null) return typeCache;
1584 typeCache = computeSignature(compiler).type;
1585 return typeCache;
1586 }
1587
1588 FunctionType get type {
1589 assert(invariant(this, typeCache != null,
1590 message: "Type has not been computed for $this."));
1591 return typeCache;
1592 }
1593
1594 FunctionElement asFunctionElement() => this;
1595
1596 String toString() {
1597 if (isPatch) {
1598 return 'patch ${super.toString()}';
1599 } else if (isPatched) {
1600 return 'origin ${super.toString()}';
1601 } else {
1602 return super.toString();
1603 }
1604 }
1605
1606 bool get isAbstract {
1607 return !modifiers.isExternal &&
1608 (isFunction || isAccessor) &&
1609 _hasNoBody;
1610 }
1611
1612 accept(ElementVisitor visitor) => visitor.visitFunctionElement(this);
1613
1614 // A function is defined by the implementation element.
1615 AstElement get definingElement => implementation;
1616 }
1617
1618 abstract class FunctionElementX extends BaseFunctionElementX
1619 with AnalyzableElementX implements MemberElement {
1620 FunctionElementX(String name,
1621 ElementKind kind,
1622 Modifiers modifiers,
1623 Element enclosing,
1624 bool hasNoBody)
1625 : super(name, kind, modifiers, enclosing, hasNoBody);
1626
1627 MemberElement get memberContext => this;
1628
1629 void reuseElement() {
1630 super.reuseElement();
1631 nestedClosures.clear();
1632 functionSignatureCache = null;
1633 typeCache = null;
1634 }
1635 }
1636
1637 class LocalFunctionElementX extends BaseFunctionElementX
1638 implements LocalFunctionElement {
1639 final FunctionExpression node;
1640
1641 LocalFunctionElementX(String name,
1642 FunctionExpression this.node,
1643 ElementKind kind,
1644 Modifiers modifiers,
1645 ExecutableElement enclosing)
1646 : super(name, kind, modifiers, enclosing, false);
1647
1648 ExecutableElement get executableContext => enclosingElement;
1649
1650 MemberElement get memberContext => executableContext.memberContext;
1651
1652 bool get hasNode => true;
1653
1654 FunctionExpression parseNode(DiagnosticListener listener) => node;
1655
1656 Token get position {
1657 // Use the name as position if this is not an unnamed closure.
1658 if (node.name != null) {
1659 return node.name.getBeginToken();
1660 } else {
1661 return node.getBeginToken();
1662 }
1663 }
1664
1665 bool get isLocal => true;
1666 }
1667
1668 abstract class ConstructorElementX extends FunctionElementX
1669 implements ConstructorElement {
1670
1671 ConstructorElementX(String name,
1672 ElementKind kind,
1673 Modifiers modifiers,
1674 Element enclosing)
1675 : super(name, kind, modifiers, enclosing, false);
1676
1677 FunctionElement immediateRedirectionTarget;
1678
1679 bool get isRedirectingFactory => immediateRedirectionTarget != null;
1680
1681 /// This field is set by the post process queue when checking for cycles.
1682 ConstructorElement internalEffectiveTarget;
1683 DartType effectiveTargetType;
1684
1685 void set effectiveTarget(ConstructorElement constructor) {
1686 assert(constructor != null && internalEffectiveTarget == null);
1687 internalEffectiveTarget = constructor;
1688 }
1689
1690 ConstructorElement get effectiveTarget {
1691 if (Elements.isErroneousElement(immediateRedirectionTarget)) {
1692 return immediateRedirectionTarget;
1693 }
1694 assert(!isRedirectingFactory || internalEffectiveTarget != null);
1695 return isRedirectingFactory ? internalEffectiveTarget : this;
1696 }
1697
1698 InterfaceType computeEffectiveTargetType(InterfaceType newType) {
1699 if (!isRedirectingFactory) return newType;
1700 assert(invariant(this, effectiveTargetType != null,
1701 message: 'Redirection target type has not yet been computed for '
1702 '$this.'));
1703 return effectiveTargetType.substByContext(newType);
1704 }
1705
1706 ConstructorElement get definingConstructor => null;
1707
1708 ClassElement get enclosingClass => enclosingElement;
1709 }
1710
1711 class DeferredLoaderGetterElementX extends FunctionElementX {
1712 final PrefixElement prefix;
1713
1714 DeferredLoaderGetterElementX(PrefixElement prefix)
1715 : this.prefix = prefix,
1716 super("loadLibrary",
1717 ElementKind.FUNCTION,
1718 Modifiers.EMPTY,
1719 prefix, true);
1720
1721 FunctionSignature computeSignature(Compiler compiler) {
1722 if (functionSignatureCache != null) return functionSignature;
1723 compiler.withCurrentElement(this, () {
1724 DartType inner = new FunctionType(this);
1725 functionSignatureCache = new FunctionSignatureX(const Link(),
1726 const Link(), 0, 0, false, [], inner);
1727 });
1728 return functionSignatureCache;
1729 }
1730
1731 bool get isClassMember => false;
1732
1733 bool isForeign(Backend backend) => true;
1734
1735 bool get isSynthesized => true;
1736
1737 bool get isFunction => false;
1738
1739 bool get isDeferredLoaderGetter => true;
1740
1741 bool get isGetter => true;
1742
1743 bool get isTopLevel => true;
1744 // By having position null, the enclosing elements location is printed in
1745 // error messages.
1746 Token get position => null;
1747
1748 FunctionExpression parseNode(DiagnosticListener listener) => null;
1749
1750 bool get hasNode => false;
1751
1752 FunctionExpression get node => null;
1753 }
1754
1755 class ConstructorBodyElementX extends BaseFunctionElementX
1756 implements ConstructorBodyElement {
1757 ConstructorElement constructor;
1758
1759 ConstructorBodyElementX(FunctionElement constructor)
1760 : this.constructor = constructor,
1761 super(constructor.name,
1762 ElementKind.GENERATIVE_CONSTRUCTOR_BODY,
1763 Modifiers.EMPTY,
1764 constructor.enclosingElement, false) {
1765 functionSignatureCache = constructor.functionSignature;
1766 }
1767
1768 bool get hasNode => constructor.hasNode;
1769
1770 FunctionExpression get node => constructor.node;
1771
1772 bool get isInstanceMember => true;
1773
1774 FunctionType computeType(Compiler compiler) {
1775 compiler.internalError(this, '$this.computeType.');
1776 return null;
1777 }
1778
1779 Token get position => constructor.position;
1780
1781 Element get outermostEnclosingMemberOrTopLevel => constructor;
1782
1783 Element get analyzableElement => constructor.analyzableElement;
1784
1785 accept(ElementVisitor visitor) => visitor.visitConstructorBodyElement(this);
1786
1787 MemberElement get memberContext => constructor;
1788 }
1789
1790 /**
1791 * A constructor that is not defined in the source code but rather implied by
1792 * the language semantics.
1793 *
1794 * This class is used to represent default constructors and forwarding
1795 * constructors for mixin applications.
1796 */
1797 class SynthesizedConstructorElementX extends ConstructorElementX {
1798 final ConstructorElement definingConstructor;
1799 final bool isDefaultConstructor;
1800
1801 SynthesizedConstructorElementX(String name,
1802 this.definingConstructor,
1803 Element enclosing,
1804 this.isDefaultConstructor)
1805 : super(name,
1806 ElementKind.GENERATIVE_CONSTRUCTOR,
1807 Modifiers.EMPTY,
1808 enclosing);
1809
1810 SynthesizedConstructorElementX.forDefault(superMember, Element enclosing)
1811 : this('', superMember, enclosing, true);
1812
1813 FunctionExpression parseNode(DiagnosticListener listener) => null;
1814
1815 bool get hasNode => false;
1816
1817 FunctionExpression get node => null;
1818
1819 Token get position => enclosingElement.position;
1820
1821 bool get isSynthesized => true;
1822
1823 FunctionSignature computeSignature(compiler) {
1824 if (functionSignatureCache != null) return functionSignatureCache;
1825 if (isDefaultConstructor) {
1826 return functionSignatureCache = new FunctionSignatureX(
1827 const Link<Element>(), const Link<Element>(), 0, 0, false,
1828 const <Element>[],
1829 new FunctionType(this, enclosingClass.thisType));
1830 }
1831 if (definingConstructor.isErroneous) {
1832 return functionSignatureCache =
1833 compiler.objectClass.localLookup('').computeSignature(compiler);
1834 }
1835 // TODO(johnniwinther): Ensure that the function signature (and with it the
1836 // function type) substitutes type variables correctly.
1837 return functionSignatureCache =
1838 definingConstructor.computeSignature(compiler);
1839 }
1840
1841 accept(ElementVisitor visitor) {
1842 return visitor.visitFunctionElement(this);
1843 }
1844 }
1845
1846 abstract class TypeDeclarationElementX<T extends GenericType>
1847 implements TypeDeclarationElement {
1848 /**
1849 * The `this type` for this type declaration.
1850 *
1851 * The type of [:this:] is the generic type based on this element in which
1852 * the type arguments are the declared type variables. For instance,
1853 * [:List<E>:] for [:List:] and [:Map<K,V>:] for [:Map:].
1854 *
1855 * For a class declaration this is the type of [:this:].
1856 *
1857 * This type is computed in [computeType].
1858 */
1859 T thisTypeCache;
1860
1861 /**
1862 * The raw type for this type declaration.
1863 *
1864 * The raw type is the generic type base on this element in which the type
1865 * arguments are all [dynamic]. For instance [:List<dynamic>:] for [:List:]
1866 * and [:Map<dynamic,dynamic>:] for [:Map:]. For non-generic classes [rawType]
1867 * is the same as [thisType].
1868 *
1869 * The [rawType] field is a canonicalization of the raw type and should be
1870 * used to distinguish explicit and implicit uses of the [dynamic]
1871 * type arguments. For instance should [:List:] be the [rawType] of the
1872 * [:List:] class element whereas [:List<dynamic>:] should be its own
1873 * instantiation of [InterfaceType] with [:dynamic:] as type argument. Using
1874 * this distinction, we can print the raw type with type arguments only when
1875 * the input source has used explicit type arguments.
1876 *
1877 * This type is computed together with [thisType] in [computeType].
1878 */
1879 T rawTypeCache;
1880
1881 T get thisType {
1882 assert(invariant(this, thisTypeCache != null,
1883 message: 'This type has not been computed for $this'));
1884 return thisTypeCache;
1885 }
1886
1887 T get rawType {
1888 assert(invariant(this, rawTypeCache != null,
1889 message: 'Raw type has not been computed for $this'));
1890 return rawTypeCache;
1891 }
1892
1893 T createType(List<DartType> typeArguments);
1894
1895 void setThisAndRawTypes(Compiler compiler, List<DartType> typeParameters) {
1896 assert(invariant(this, thisTypeCache == null,
1897 message: "This type has already been set on $this."));
1898 assert(invariant(this, rawTypeCache == null,
1899 message: "Raw type has already been set on $this."));
1900 thisTypeCache = createType(typeParameters);
1901 if (typeParameters.isEmpty) {
1902 rawTypeCache = thisTypeCache;
1903 } else {
1904 List<DartType> dynamicParameters =
1905 new List.filled(typeParameters.length, const DynamicType());
1906 rawTypeCache = createType(dynamicParameters);
1907 }
1908 }
1909
1910 List<DartType> get typeVariables => thisType.typeArguments;
1911
1912 /**
1913 * Creates the type variables, their type and corresponding element, for the
1914 * type variables declared in [parameter] on [element]. The bounds of the type
1915 * variables are not set until [element] has been resolved.
1916 */
1917 List<DartType> createTypeVariables(NodeList parameters) {
1918 if (parameters == null) return const <DartType>[];
1919
1920 // Create types and elements for type variable.
1921 Link<Node> nodes = parameters.nodes;
1922 List<DartType> arguments =
1923 new List.generate(nodes.slowLength(), (_) {
1924 TypeVariable node = nodes.head;
1925 String variableName = node.name.source;
1926 nodes = nodes.tail;
1927 TypeVariableElementX variableElement =
1928 new TypeVariableElementX(variableName, this, node);
1929 TypeVariableType variableType = new TypeVariableType(variableElement);
1930 variableElement.typeCache = variableType;
1931 return variableType;
1932 }, growable: false);
1933 return arguments;
1934 }
1935
1936 bool get isResolved => resolutionState == STATE_DONE;
1937 }
1938
1939 abstract class BaseClassElementX extends ElementX
1940 with AstElementMixin,
1941 AnalyzableElementX,
1942 TypeDeclarationElementX<InterfaceType>,
1943 PatchMixin<ClassElement>,
1944 ClassMemberMixin
1945 implements ClassElement {
1946 final int id;
1947
1948 DartType supertype;
1949 Link<DartType> interfaces;
1950 String nativeTagInfo;
1951 int supertypeLoadState;
1952 int resolutionState;
1953 bool isProxy = false;
1954 bool hasIncompleteHierarchy = false;
1955
1956 // backendMembers are members that have been added by the backend to simplify
1957 // compilation. They don't have any user-side counter-part.
1958 Link<Element> backendMembers = const Link<Element>();
1959
1960 OrderedTypeSet allSupertypesAndSelf;
1961
1962 Link<DartType> get allSupertypes => allSupertypesAndSelf.supertypes;
1963
1964 int get hierarchyDepth => allSupertypesAndSelf.maxDepth;
1965
1966 BaseClassElementX(String name,
1967 Element enclosing,
1968 this.id,
1969 int initialState)
1970 : supertypeLoadState = initialState,
1971 resolutionState = initialState,
1972 super(name, ElementKind.CLASS, enclosing);
1973
1974 int get hashCode => id;
1975
1976 bool get hasBackendMembers => !backendMembers.isEmpty;
1977
1978 bool get isUnnamedMixinApplication => false;
1979
1980 InterfaceType computeType(Compiler compiler) {
1981 if (thisTypeCache == null) {
1982 computeThisAndRawType(compiler, computeTypeParameters(compiler));
1983 }
1984 return thisTypeCache;
1985 }
1986
1987 void computeThisAndRawType(Compiler compiler, List<DartType> typeVariables) {
1988 if (thisTypeCache == null) {
1989 if (origin == null) {
1990 setThisAndRawTypes(compiler, typeVariables);
1991 } else {
1992 thisTypeCache = origin.computeType(compiler);
1993 rawTypeCache = origin.rawType;
1994 }
1995 }
1996 }
1997
1998 InterfaceType createType(List<DartType> typeArguments) {
1999 return new InterfaceType(this, typeArguments);
2000 }
2001
2002 List<DartType> computeTypeParameters(Compiler compiler);
2003
2004 InterfaceType asInstanceOf(ClassElement cls) {
2005 if (cls == this) return thisType;
2006 return allSupertypesAndSelf.asInstanceOf(cls);
2007 }
2008
2009 bool get isObject {
2010 assert(invariant(this, isResolved,
2011 message: "isObject has not been computed for $this."));
2012 return supertype == null;
2013 }
2014
2015 void ensureResolved(Compiler compiler) {
2016 if (resolutionState == STATE_NOT_STARTED) {
2017 compiler.resolver.resolveClass(this);
2018 }
2019 }
2020
2021 void setDefaultConstructor(FunctionElement constructor, Compiler compiler);
2022
2023 void addBackendMember(Element member) {
2024 // TODO(ngeoffray): Deprecate this method.
2025 assert(member.isGenerativeConstructorBody);
2026 backendMembers = backendMembers.prepend(member);
2027 }
2028
2029 void reverseBackendMembers() {
2030 backendMembers = backendMembers.reverse();
2031 }
2032
2033 /**
2034 * Lookup local members in the class. This will ignore constructors.
2035 */
2036 Element lookupLocalMember(String memberName) {
2037 var result = localLookup(memberName);
2038 if (result != null && result.isConstructor) return null;
2039 return result;
2040 }
2041
2042 /// Lookup a synthetic element created by the backend.
2043 Element lookupBackendMember(String memberName) {
2044 for (Element element in backendMembers) {
2045 if (element.name == memberName) {
2046 return element;
2047 }
2048 }
2049 return null;
2050 }
2051 /**
2052 * Lookup super members for the class. This will ignore constructors.
2053 */
2054 Element lookupSuperMember(String memberName) {
2055 return lookupSuperMemberInLibrary(memberName, library);
2056 }
2057
2058 /**
2059 * Lookup super members for the class that is accessible in [library].
2060 * This will ignore constructors.
2061 */
2062 Element lookupSuperMemberInLibrary(String memberName,
2063 LibraryElement library) {
2064 bool isPrivate = isPrivateName(memberName);
2065 for (ClassElement s = superclass; s != null; s = s.superclass) {
2066 // Private members from a different library are not visible.
2067 if (isPrivate && !identical(library, s.library)) continue;
2068 Element e = s.lookupLocalMember(memberName);
2069 if (e == null) continue;
2070 // Static members are not inherited.
2071 if (e.isStatic) continue;
2072 return e;
2073 }
2074 return null;
2075 }
2076
2077 /**
2078 * Find the first member in the class chain with the given [selector].
2079 *
2080 * This method is NOT to be used for resolving
2081 * unqualified sends because it does not implement the scoping
2082 * rules, where library scope comes before superclass scope.
2083 *
2084 * When called on the implementation element both members declared in the
2085 * origin and the patch class are returned.
2086 */
2087 Element lookupSelector(Selector selector) {
2088 return internalLookupSelector(selector, false);
2089 }
2090
2091 Element lookupSuperSelector(Selector selector) {
2092 return internalLookupSelector(selector, true);
2093 }
2094
2095 Element internalLookupSelector(Selector selector,
2096 bool isSuperLookup) {
2097 String name = selector.name;
2098 bool isPrivate = isPrivateName(name);
2099 LibraryElement library = selector.library;
2100 for (ClassElement current = isSuperLookup ? superclass : this;
2101 current != null;
2102 current = current.superclass) {
2103 Element member = current.lookupLocalMember(name);
2104 if (member == null && current.isPatched) {
2105 // Doing lookups on selectors is done after resolution, so it
2106 // is safe to look in the patch class.
2107 member = current.patch.lookupLocalMember(name);
2108 }
2109 if (member == null) continue;
2110 // Private members from a different library are not visible.
2111 if (isPrivate && !identical(library, member.library)) continue;
2112 // Static members are not inherited.
2113 if (member.isStatic && !identical(this, current)) continue;
2114 // If we find an abstract field we have to make sure that it has
2115 // the getter or setter part we're actually looking
2116 // for. Otherwise, we continue up the superclass chain.
2117 if (member.isAbstractField) {
2118 AbstractFieldElement field = member;
2119 FunctionElement getter = field.getter;
2120 FunctionElement setter = field.setter;
2121 if (selector.isSetter) {
2122 // Abstract members can be defined in a super class.
2123 if (setter != null && !setter.isAbstract) return setter;
2124 } else {
2125 assert(selector.isGetter || selector.isCall);
2126 if (getter != null && !getter.isAbstract) return getter;
2127 }
2128 // Abstract members can be defined in a super class.
2129 } else if (!member.isAbstract) {
2130 return member;
2131 }
2132 }
2133 return null;
2134 }
2135
2136 /**
2137 * Find the first member in the class chain with the given
2138 * [memberName]. This method is NOT to be used for resolving
2139 * unqualified sends because it does not implement the scoping
2140 * rules, where library scope comes before superclass scope.
2141 */
2142 Element lookupMember(String memberName) {
2143 Element localMember = lookupLocalMember(memberName);
2144 return localMember == null ? lookupSuperMember(memberName) : localMember;
2145 }
2146
2147 /**
2148 * Returns true if the [fieldMember] shadows another field. The given
2149 * [fieldMember] must be a member of this class, i.e. if there is a field of
2150 * the same name in the superclass chain.
2151 *
2152 * This method also works if the [fieldMember] is private.
2153 */
2154 bool hasFieldShadowedBy(Element fieldMember) {
2155 assert(fieldMember.isField);
2156 String fieldName = fieldMember.name;
2157 bool isPrivate = isPrivateName(fieldName);
2158 LibraryElement memberLibrary = fieldMember.library;
2159 ClassElement lookupClass = this.superclass;
2160 while (lookupClass != null) {
2161 Element foundMember = lookupClass.lookupLocalMember(fieldName);
2162 if (foundMember != null) {
2163 if (foundMember.isField) {
2164 if (!isPrivate || memberLibrary == foundMember.library) {
2165 // Private fields can only be shadowed by a field declared in the
2166 // same library.
2167 return true;
2168 }
2169 }
2170 }
2171 lookupClass = lookupClass.superclass;
2172 }
2173 return false;
2174 }
2175
2176 Element validateConstructorLookupResults(Selector selector,
2177 Element result,
2178 Element noMatch(Element)) {
2179 if (result == null
2180 || !result.isConstructor
2181 || (isPrivateName(selector.name)
2182 && result.library != selector.library)) {
2183 result = noMatch != null ? noMatch(result) : null;
2184 }
2185 return result;
2186 }
2187
2188 // TODO(aprelev@gmail.com): Peter believes that it would be great to
2189 // make noMatch a required argument. Peter's suspicion is that most
2190 // callers of this method would benefit from using the noMatch method.
2191 Element lookupConstructor(Selector selector, [Element noMatch(Element)]) {
2192 Element result = localLookup(selector.name);
2193 return validateConstructorLookupResults(selector, result, noMatch);
2194 }
2195
2196 Link<Element> get constructors {
2197 // TODO(ajohnsen): See if we can avoid this method at some point.
2198 Link<Element> result = const Link<Element>();
2199 // TODO(johnniwinther): Should we include injected constructors?
2200 forEachMember((_, Element member) {
2201 if (member.isConstructor) result = result.prepend(member);
2202 });
2203 return result;
2204 }
2205
2206 /**
2207 * Returns the super class, if any.
2208 *
2209 * The returned element may not be resolved yet.
2210 */
2211 ClassElement get superclass {
2212 assert(supertypeLoadState == STATE_DONE);
2213 return supertype == null ? null : supertype.element;
2214 }
2215
2216 /**
2217 * Runs through all members of this class.
2218 *
2219 * The enclosing class is passed to the callback. This is useful when
2220 * [includeSuperAndInjectedMembers] is [:true:].
2221 *
2222 * When called on an implementation element both the members in the origin
2223 * and patch class are included.
2224 */
2225 // TODO(johnniwinther): Clean up lookup to get rid of the include predicates.
2226 void forEachMember(void f(ClassElement enclosingClass, Element member),
2227 {includeBackendMembers: false,
2228 includeSuperAndInjectedMembers: false}) {
2229 bool includeInjectedMembers = includeSuperAndInjectedMembers || isPatch;
2230 ClassElement classElement = declaration;
2231 do {
2232 // Iterate through the members in textual order, which requires
2233 // to reverse the data structure [localMembers] we created.
2234 // Textual order may be important for certain operations, for
2235 // example when emitting the initializers of fields.
2236 classElement.forEachLocalMember((e) => f(classElement, e));
2237 if (includeBackendMembers) {
2238 classElement.forEachBackendMember((e) => f(classElement, e));
2239 }
2240 if (includeInjectedMembers) {
2241 if (classElement.patch != null) {
2242 classElement.patch.forEachLocalMember((e) {
2243 if (!e.isPatch) f(classElement, e);
2244 });
2245 }
2246 }
2247 classElement = includeSuperAndInjectedMembers
2248 ? classElement.superclass
2249 : null;
2250 } while (classElement != null);
2251 }
2252
2253 /**
2254 * Runs through all instance-field members of this class.
2255 *
2256 * The enclosing class is passed to the callback. This is useful when
2257 * [includeSuperAndInjectedMembers] is [:true:].
2258 *
2259 * When called on the implementation element both the fields declared in the
2260 * origin and in the patch are included.
2261 */
2262 void forEachInstanceField(void f(ClassElement enclosingClass,
2263 FieldElement field),
2264 {bool includeSuperAndInjectedMembers: false}) {
2265 // Filters so that [f] is only invoked with instance fields.
2266 void fieldFilter(ClassElement enclosingClass, Element member) {
2267 if (member.isInstanceMember && member.kind == ElementKind.FIELD) {
2268 f(enclosingClass, member);
2269 }
2270 }
2271
2272 forEachMember(fieldFilter,
2273 includeSuperAndInjectedMembers: includeSuperAndInjectedMembers);
2274 }
2275
2276 /// Similar to [forEachInstanceField] but visits static fields.
2277 void forEachStaticField(void f(ClassElement enclosingClass, Element field)) {
2278 // Filters so that [f] is only invoked with static fields.
2279 void fieldFilter(ClassElement enclosingClass, Element member) {
2280 if (!member.isInstanceMember && member.kind == ElementKind.FIELD) {
2281 f(enclosingClass, member);
2282 }
2283 }
2284
2285 forEachMember(fieldFilter);
2286 }
2287
2288 void forEachBackendMember(void f(Element member)) {
2289 backendMembers.forEach(f);
2290 }
2291
2292 bool implementsInterface(ClassElement intrface) {
2293 for (DartType implementedInterfaceType in allSupertypes) {
2294 ClassElement implementedInterface = implementedInterfaceType.element;
2295 if (identical(implementedInterface, intrface)) {
2296 return true;
2297 }
2298 }
2299 return false;
2300 }
2301
2302 /**
2303 * Returns true if [this] is a subclass of [cls].
2304 *
2305 * This method is not to be used for checking type hierarchy and
2306 * assignments, because it does not take parameterized types into
2307 * account.
2308 */
2309 bool isSubclassOf(ClassElement cls) {
2310 // Use [declaration] for both [this] and [cls], because
2311 // declaration classes hold the superclass hierarchy.
2312 cls = cls.declaration;
2313 for (ClassElement s = declaration; s != null; s = s.superclass) {
2314 if (identical(s, cls)) return true;
2315 }
2316 return false;
2317 }
2318
2319 bool get isNative => nativeTagInfo != null;
2320
2321 void setNative(String name) {
2322 // TODO(johnniwinther): Assert that this is only called once. The memory
2323 // compiler copies pre-processed elements into a new compiler through
2324 // [Compiler.onLibraryScanned] and thereby causes multiple calls to this
2325 // method.
2326 assert(invariant(this, nativeTagInfo == null || nativeTagInfo == name,
2327 message: "Native tag info set inconsistently on $this: "
2328 "Existing name '$nativeTagInfo', new name '$name'."));
2329 nativeTagInfo = name;
2330 }
2331
2332 FunctionType get callType {
2333 MemberSignature member =
2334 lookupInterfaceMember(const PublicName(Compiler.CALL_OPERATOR_NAME));
2335 return member != null && member.isMethod ? member.type : null;
2336 }
2337
2338 // TODO(johnniwinther): Remove these when issue 18630 is fixed.
2339 ClassElement get patch => super.patch;
2340 ClassElement get origin => super.origin;
2341
2342 // A class declaration is defined by the declaration element.
2343 AstElement get definingElement => declaration;
2344 }
2345
2346 abstract class ClassElementX extends BaseClassElementX {
2347 Link<Element> localMembersReversed = const Link<Element>();
2348 final ScopeX localScope = new ScopeX();
2349
2350 Link<Element> localMembersCache;
2351
2352 Link<Element> get localMembers {
2353 if (localMembersCache == null) {
2354 localMembersCache = localMembersReversed.reverse();
2355 }
2356 return localMembersCache;
2357 }
2358
2359 ClassElementX(String name, Element enclosing, int id, int initialState)
2360 : super(name, enclosing, id, initialState);
2361
2362 ClassNode parseNode(Compiler compiler);
2363
2364 bool get isMixinApplication => false;
2365 bool get hasLocalScopeMembers => !localScope.isEmpty;
2366
2367 void addMember(Element element, DiagnosticListener listener) {
2368 localMembersCache = null;
2369 localMembersReversed = localMembersReversed.prepend(element);
2370 addToScope(element, listener);
2371 }
2372
2373 void addToScope(Element element, DiagnosticListener listener) {
2374 if (element.isField && element.name == name) {
2375 listener.reportError(element, MessageKind.MEMBER_USES_CLASS_NAME);
2376 }
2377 localScope.add(element, listener);
2378 }
2379
2380 Element localLookup(String elementName) {
2381 Element result = localScope.lookup(elementName);
2382 if (result == null && isPatch) {
2383 result = origin.localLookup(elementName);
2384 }
2385 return result;
2386 }
2387
2388 void forEachLocalMember(void f(Element member)) {
2389 localMembers.forEach(f);
2390 }
2391
2392 bool get hasConstructor {
2393 // Search in scope to be sure we search patched constructors.
2394 for (var element in localScope.values) {
2395 if (element.isConstructor) return true;
2396 }
2397 return false;
2398 }
2399
2400 void setDefaultConstructor(FunctionElement constructor, Compiler compiler) {
2401 // The default constructor, although synthetic, is part of a class' API.
2402 addMember(constructor, compiler);
2403 }
2404
2405 List<DartType> computeTypeParameters(Compiler compiler) {
2406 ClassNode node = parseNode(compiler);
2407 return createTypeVariables(node.typeParameters);
2408 }
2409
2410 Scope buildScope() => new ClassScope(enclosingElement.buildScope(), this);
2411
2412 String toString() {
2413 if (origin != null) {
2414 return 'patch ${super.toString()}';
2415 } else if (patch != null) {
2416 return 'origin ${super.toString()}';
2417 } else {
2418 return super.toString();
2419 }
2420 }
2421 }
2422
2423 class MixinApplicationElementX extends BaseClassElementX
2424 implements MixinApplicationElement {
2425 final Node node;
2426 final Modifiers modifiers;
2427
2428 Link<FunctionElement> constructors = new Link<FunctionElement>();
2429
2430 InterfaceType mixinType;
2431
2432 MixinApplicationElementX(String name, Element enclosing, int id,
2433 this.node, this.modifiers)
2434 : super(name, enclosing, id, STATE_NOT_STARTED);
2435
2436 ClassElement get mixin => mixinType != null ? mixinType.element : null;
2437
2438 bool get isMixinApplication => true;
2439 bool get isUnnamedMixinApplication => node is! NamedMixinApplication;
2440 bool get hasConstructor => !constructors.isEmpty;
2441 bool get hasLocalScopeMembers => !constructors.isEmpty;
2442
2443 get patch => null;
2444 get origin => null;
2445
2446 bool get hasNode => true;
2447
2448 Token get position => node.getBeginToken();
2449
2450 Node parseNode(DiagnosticListener listener) => node;
2451
2452 FunctionElement lookupLocalConstructor(String name) {
2453 for (Link<Element> link = constructors;
2454 !link.isEmpty;
2455 link = link.tail) {
2456 if (link.head.name == name) return link.head;
2457 }
2458 return null;
2459 }
2460
2461 Element localLookup(String name) {
2462 Element constructor = lookupLocalConstructor(name);
2463 if (constructor != null) return constructor;
2464 if (mixin == null) return null;
2465 Element mixedInElement = mixin.localLookup(name);
2466 if (mixedInElement == null) return null;
2467 return mixedInElement.isInstanceMember ? mixedInElement : null;
2468 }
2469
2470 void forEachLocalMember(void f(Element member)) {
2471 constructors.forEach(f);
2472 if (mixin != null) mixin.forEachLocalMember((Element mixedInElement) {
2473 if (mixedInElement.isInstanceMember) f(mixedInElement);
2474 });
2475 }
2476
2477 void addMember(Element element, DiagnosticListener listener) {
2478 throw new UnsupportedError("Cannot add member to $this.");
2479 }
2480
2481 void addToScope(Element element, DiagnosticListener listener) {
2482 listener.internalError(this, 'Cannot add to scope of $this.');
2483 }
2484
2485 void addConstructor(FunctionElement constructor) {
2486 constructors = constructors.prepend(constructor);
2487 }
2488
2489 void setDefaultConstructor(FunctionElement constructor, Compiler compiler) {
2490 assert(!hasConstructor);
2491 addConstructor(constructor);
2492 }
2493
2494 List<DartType> computeTypeParameters(Compiler compiler) {
2495 NamedMixinApplication named = node.asNamedMixinApplication();
2496 if (named == null) {
2497 throw new SpannableAssertionFailure(node,
2498 "Type variables on unnamed mixin applications must be set on "
2499 "creation.");
2500 }
2501 return createTypeVariables(named.typeParameters);
2502 }
2503
2504 accept(ElementVisitor visitor) => visitor.visitMixinApplicationElement(this);
2505 }
2506
2507 class LabelDefinitionX implements LabelDefinition {
2508 final Label label;
2509 final String labelName;
2510 final JumpTarget target;
2511 bool isBreakTarget = false;
2512 bool isContinueTarget = false;
2513
2514 LabelDefinitionX(Label label, String labelName, this.target)
2515 : this.label = label,
2516 this.labelName = labelName;
2517
2518 // In case of a synthetic label, just use [labelName] for identifying the
2519 // label.
2520 String get name => label == null ? labelName : label.identifier.source;
2521
2522 void setBreakTarget() {
2523 isBreakTarget = true;
2524 target.isBreakTarget = true;
2525 }
2526
2527 void setContinueTarget() {
2528 isContinueTarget = true;
2529 target.isContinueTarget = true;
2530 }
2531
2532 bool get isTarget => isBreakTarget || isContinueTarget;
2533
2534 String toString() => 'Label:${name}';
2535 }
2536
2537 class JumpTargetX implements JumpTarget {
2538 final ExecutableElement executableContext;
2539 final Node statement;
2540 final int nestingLevel;
2541 Link<LabelDefinition> labels = const Link<LabelDefinition>();
2542 bool isBreakTarget = false;
2543 bool isContinueTarget = false;
2544
2545 JumpTargetX(this.statement, this.nestingLevel, this.executableContext);
2546
2547 String get name => "target";
2548
2549 bool get isTarget => isBreakTarget || isContinueTarget;
2550
2551 LabelDefinition addLabel(Label label, String labelName) {
2552 LabelDefinition result = new LabelDefinitionX(label, labelName, this);
2553 labels = labels.prepend(result);
2554 return result;
2555 }
2556
2557 bool get isSwitch => statement is SwitchStatement;
2558
2559 String toString() => 'Target:$statement';
2560 }
2561
2562 class TypeVariableElementX extends ElementX with AstElementMixin
2563 implements TypeVariableElement {
2564 final Node node;
2565 TypeVariableType typeCache;
2566 DartType boundCache;
2567
2568 TypeVariableElementX(String name, TypeDeclarationElement enclosing, this.node)
2569 : super(name, ElementKind.TYPE_VARIABLE, enclosing);
2570
2571 TypeDeclarationElement get typeDeclaration => enclosingElement;
2572
2573 TypeVariableType computeType(compiler) => type;
2574
2575 TypeVariableType get type {
2576 assert(invariant(this, typeCache != null,
2577 message: "Type has not been set on $this."));
2578 return typeCache;
2579 }
2580
2581 DartType get bound {
2582 assert(invariant(this, boundCache != null,
2583 message: "Bound has not been set on $this."));
2584 return boundCache;
2585 }
2586
2587 bool get hasNode => true;
2588
2589 Node parseNode(compiler) => node;
2590
2591 String toString() => "${enclosingElement.toString()}.${name}";
2592
2593 Token get position => node.getBeginToken();
2594
2595 accept(ElementVisitor visitor) => visitor.visitTypeVariableElement(this);
2596
2597 // A type variable cannot be patched therefore defines itself.
2598 AstElement get definingElement => this;
2599 }
2600
2601 /**
2602 * A single metadata annotation.
2603 *
2604 * For example, consider:
2605 *
2606 * class Data {
2607 * const Data();
2608 * }
2609 *
2610 * const data = const Data();
2611 *
2612 * @data
2613 * class Foo {}
2614 *
2615 * @data @data
2616 * class Bar {}
2617 *
2618 * In this example, there are three instances of [MetadataAnnotation]
2619 * and they correspond each to a location in the source code where
2620 * there is an at-sign, '@'. The [constant] of each of these instances
2621 * are the same compile-time constant, [: const Data() :].
2622 *
2623 * The mirror system does not have a concept matching this class.
2624 */
2625 abstract class MetadataAnnotationX implements MetadataAnnotation {
2626 /**
2627 * The compile-time constant which this annotation resolves to.
2628 * In the mirror system, this would be an object mirror.
2629 */
2630 ConstantExpression constant;
2631 Element annotatedElement;
2632 int resolutionState;
2633
2634 /**
2635 * The beginning token of this annotation, or [:null:] if it is synthetic.
2636 */
2637 Token get beginToken;
2638
2639 MetadataAnnotationX([this.resolutionState = STATE_NOT_STARTED]);
2640
2641 MetadataAnnotation ensureResolved(Compiler compiler) {
2642 if (annotatedElement.isClass || annotatedElement.isTypedef) {
2643 TypeDeclarationElement typeDeclaration = annotatedElement;
2644 typeDeclaration.ensureResolved(compiler);
2645 }
2646 if (resolutionState == STATE_NOT_STARTED) {
2647 compiler.resolver.resolveMetadataAnnotation(this);
2648 }
2649 return this;
2650 }
2651
2652 Node parseNode(DiagnosticListener listener);
2653
2654 String toString() => 'MetadataAnnotation($constant, $resolutionState)';
2655 }
2656
2657 /// Metadata annotation on a parameter.
2658 class ParameterMetadataAnnotation extends MetadataAnnotationX {
2659 final Metadata metadata;
2660
2661 ParameterMetadataAnnotation(Metadata this.metadata);
2662
2663 Node parseNode(DiagnosticListener listener) => metadata.expression;
2664
2665 Token get beginToken => metadata.getBeginToken();
2666
2667 Token get endToken => metadata.getEndToken();
2668
2669 bool get hasNode => true;
2670
2671 Metadata get node => metadata;
2672 }
2673
2674 /// Mixin for the implementation of patched elements.
2675 ///
2676 /// See [:patch_parser.dart:] for a description of the terminology.
2677 abstract class PatchMixin<E extends Element> implements Element {
2678 // TODO(johnniwinther): Use type variables when issue 18630 is fixed.
2679 Element/*E*/ patch = null;
2680 Element/*E*/ origin = null;
2681
2682 bool get isPatch => origin != null;
2683 bool get isPatched => patch != null;
2684
2685 bool get isImplementation => !isPatched;
2686 bool get isDeclaration => !isPatch;
2687
2688 Element/*E*/ get implementation => isPatched ? patch : this;
2689 Element/*E*/ get declaration => isPatch ? origin : this;
2690
2691 /// Applies a patch to this element. This method must be called at most once.
2692 void applyPatch(PatchMixin<E> patch) {
2693 assert(invariant(this, this.patch == null,
2694 message: "Element is patched twice."));
2695 assert(invariant(this, this.origin == null,
2696 message: "Origin element is a patch."));
2697 assert(invariant(patch, patch.origin == null,
2698 message: "Element is patched twice."));
2699 assert(invariant(patch, patch.patch == null,
2700 message: "Patch element is patched."));
2701 this.patch = patch;
2702 patch.origin = this;
2703 }
2704 }
2705
2706 /// Abstract implementation of the [AstElement] interface.
2707 abstract class AstElementMixin implements AstElement {
2708 /// The element whose node defines this element.
2709 ///
2710 /// For patched functions the defining element is the patch element found
2711 /// through [implementation] since its node define the implementation of the
2712 /// function. For patched classes the defining element is the origin element
2713 /// found through [declaration] since its node define the inheritance relation
2714 /// for the class. For unpatched elements the defining element is the element
2715 /// itself.
2716 AstElement get definingElement;
2717
2718 bool get hasResolvedAst => definingElement.hasTreeElements;
2719
2720 ResolvedAst get resolvedAst {
2721 return new ResolvedAst(declaration,
2722 definingElement.node, definingElement.treeElements);
2723 }
2724
2725 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698