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

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

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

Powered by Google App Engine
This is Rietveld 408576698