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

Side by Side Diff: pkg/compiler/lib/src/scanner/token_map.dart

Issue 1284593003: Remove dart2jslib.dart (Closed) Base URL: https://github.com/dart-lang/sdk.git@master
Patch Set: Created 5 years, 4 months 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
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 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. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 part of dart2js; 5 library dart2js.tokens.token_map;
6 6
7 /** 7 import 'scannerlib.dart' show
8 * If true, print a warning for each method that was resolved, but not 8 Token;
9 * compiled.
10 */
11 const bool REPORT_EXCESS_RESOLUTION = false;
12
13 /**
14 * Contains backend-specific data that is used throughout the compilation of
15 * one work item.
16 */
17 class ItemCompilationContext {
18 }
19
20 abstract class WorkItem {
21 final ItemCompilationContext compilationContext;
22 /**
23 * Documentation wanted -- johnniwinther
24 *
25 * Invariant: [element] must be a declaration element.
26 */
27 final AstElement element;
28
29 WorkItem(this.element, this.compilationContext) {
30 assert(invariant(element, element.isDeclaration));
31 }
32
33 WorldImpact run(Compiler compiler, Enqueuer world);
34 }
35
36 /// [WorkItem] used exclusively by the [ResolutionEnqueuer].
37 class ResolutionWorkItem extends WorkItem {
38 bool _isAnalyzed = false;
39
40 ResolutionWorkItem(AstElement element,
41 ItemCompilationContext compilationContext)
42 : super(element, compilationContext);
43
44 WorldImpact run(Compiler compiler, ResolutionEnqueuer world) {
45 WorldImpact impact = compiler.analyze(this, world);
46 _isAnalyzed = true;
47 return impact;
48 }
49
50 bool get isAnalyzed => _isAnalyzed;
51 }
52
53 // TODO(johnniwinther): Split this class into interface and implementation.
54 // TODO(johnniwinther): Move this implementation to the JS backend.
55 class CodegenRegistry extends Registry {
56 final Compiler compiler;
57 final TreeElements treeElements;
58
59 CodegenRegistry(this.compiler, this.treeElements);
60
61 bool get isForResolution => false;
62
63 Element get currentElement => treeElements.analyzedElement;
64
65 // TODO(johnniwinther): Remove this getter when [Registry] creates a
66 // dependency node.
67 Setlet<Element> get otherDependencies => treeElements.otherDependencies;
68
69 CodegenEnqueuer get world => compiler.enqueuer.codegen;
70 js_backend.JavaScriptBackend get backend => compiler.backend;
71
72 void registerDependency(Element element) {
73 treeElements.registerDependency(element);
74 }
75
76 void registerInlining(Element inlinedElement, Element context) {
77 if (compiler.dumpInfo) {
78 compiler.dumpInfoTask.registerInlined(inlinedElement, context);
79 }
80 }
81
82 void registerInstantiatedClass(ClassElement element) {
83 world.registerInstantiatedType(element.rawType, this);
84 }
85
86 void registerInstantiatedType(InterfaceType type) {
87 world.registerInstantiatedType(type, this);
88 }
89
90 void registerStaticUse(Element element) {
91 world.registerStaticUse(element);
92 }
93
94 void registerDynamicInvocation(UniverseSelector selector) {
95 world.registerDynamicInvocation(selector);
96 compiler.dumpInfoTask.elementUsesSelector(currentElement, selector);
97 }
98
99 void registerDynamicSetter(UniverseSelector selector) {
100 world.registerDynamicSetter(selector);
101 compiler.dumpInfoTask.elementUsesSelector(currentElement, selector);
102 }
103
104 void registerDynamicGetter(UniverseSelector selector) {
105 world.registerDynamicGetter(selector);
106 compiler.dumpInfoTask.elementUsesSelector(currentElement, selector);
107 }
108
109 void registerGetterForSuperMethod(Element element) {
110 world.registerGetterForSuperMethod(element);
111 }
112
113 void registerFieldGetter(Element element) {
114 world.registerFieldGetter(element);
115 }
116
117 void registerFieldSetter(Element element) {
118 world.registerFieldSetter(element);
119 }
120
121 void registerIsCheck(DartType type) {
122 world.registerIsCheck(type);
123 backend.registerIsCheckForCodegen(type, world, this);
124 }
125
126 void registerCompileTimeConstant(ConstantValue constant) {
127 backend.registerCompileTimeConstant(constant, this);
128 backend.constants.addCompileTimeConstantForEmission(constant);
129 }
130
131 void registerTypeVariableBoundsSubtypeCheck(DartType subtype,
132 DartType supertype) {
133 backend.registerTypeVariableBoundsSubtypeCheck(subtype, supertype);
134 }
135
136 void registerInstantiatedClosure(LocalFunctionElement element) {
137 backend.registerInstantiatedClosure(element, this);
138 }
139
140 void registerGetOfStaticFunction(FunctionElement element) {
141 world.registerGetOfStaticFunction(element);
142 }
143
144 void registerSelectorUse(Selector selector) {
145 world.registerSelectorUse(new UniverseSelector(selector, null));
146 }
147
148 void registerConstSymbol(String name) {
149 backend.registerConstSymbol(name, this);
150 }
151
152 void registerSpecializedGetInterceptor(Set<ClassElement> classes) {
153 backend.registerSpecializedGetInterceptor(classes);
154 }
155
156 void registerUseInterceptor() {
157 backend.registerUseInterceptor(world);
158 }
159
160 void registerTypeConstant(ClassElement element) {
161 backend.customElementsAnalysis.registerTypeConstant(element, world);
162 }
163
164 void registerStaticInvocation(Element element) {
165 world.registerStaticUse(element);
166 }
167
168 void registerSuperInvocation(Element element) {
169 world.registerStaticUse(element);
170 }
171
172 void registerDirectInvocation(Element element) {
173 world.registerStaticUse(element);
174 }
175
176 void registerInstantiation(InterfaceType type) {
177 world.registerInstantiatedType(type, this);
178 }
179
180 void registerAsyncMarker(FunctionElement element) {
181 backend.registerAsyncMarker(element, world, this);
182 }
183
184 }
185
186 /// [WorkItem] used exclusively by the [CodegenEnqueuer].
187 class CodegenWorkItem extends WorkItem {
188 CodegenRegistry registry;
189
190 factory CodegenWorkItem(
191 Compiler compiler,
192 AstElement element,
193 ItemCompilationContext compilationContext) {
194 // If this assertion fails, the resolution callbacks of the backend may be
195 // missing call of form registry.registerXXX. Alternatively, the code
196 // generation could spuriously be adding dependencies on things we know we
197 // don't need.
198 assert(invariant(element,
199 compiler.enqueuer.resolution.hasBeenResolved(element),
200 message: "$element has not been resolved."));
201 assert(invariant(element, element.resolvedAst.elements != null,
202 message: 'Resolution tree is null for $element in codegen work item'));
203 return new CodegenWorkItem.internal(element, compilationContext);
204 }
205
206 CodegenWorkItem.internal(
207 AstElement element,
208 ItemCompilationContext compilationContext)
209 : super(element, compilationContext);
210
211 TreeElements get resolutionTree => element.resolvedAst.elements;
212
213 WorldImpact run(Compiler compiler, CodegenEnqueuer world) {
214 if (world.isProcessed(element)) return const WorldImpact();
215
216 registry = new CodegenRegistry(compiler, resolutionTree);
217 return compiler.codegen(this, world);
218 }
219 }
220
221 typedef void DeferredAction();
222
223 class DeferredTask {
224 final Element element;
225 final DeferredAction action;
226
227 DeferredTask(this.element, this.action);
228 }
229
230 /// Interface for registration of element dependencies.
231 abstract class Registry {
232 // TODO(johnniwinther): Remove this getter when [Registry] creates a
233 // dependency node.
234 Iterable<Element> get otherDependencies;
235
236 void registerDependency(Element element);
237
238 bool get isForResolution;
239
240 void registerDynamicInvocation(UniverseSelector selector);
241
242 void registerDynamicGetter(UniverseSelector selector);
243
244 void registerDynamicSetter(UniverseSelector selector);
245
246 void registerStaticInvocation(Element element);
247
248 void registerInstantiation(InterfaceType type);
249
250 void registerGetOfStaticFunction(FunctionElement element);
251 }
252
253 abstract class Backend {
254 final Compiler compiler;
255
256 Backend(this.compiler);
257
258 /// Returns true if the backend supports reflection.
259 bool get supportsReflection;
260
261 /// The [ConstantSystem] used to interpret compile-time constants for this
262 /// backend.
263 ConstantSystem get constantSystem;
264
265 /// The constant environment for the backend interpretation of compile-time
266 /// constants.
267 BackendConstantEnvironment get constants;
268
269 /// The compiler task responsible for the compilation of constants for both
270 /// the frontend and the backend.
271 ConstantCompilerTask get constantCompilerTask;
272
273 /// Backend callback methods for the resolution phase.
274 ResolutionCallbacks get resolutionCallbacks;
275
276 /// The strategy used for collecting and emitting source information.
277 SourceInformationStrategy get sourceInformationStrategy {
278 return const SourceInformationStrategy();
279 }
280
281 // TODO(johnniwinther): Move this to the JavaScriptBackend.
282 String get patchVersion => null;
283
284 /// Set of classes that need to be considered for reflection although not
285 /// otherwise visible during resolution.
286 Iterable<ClassElement> classesRequiredForReflection = const [];
287
288 // Given a [FunctionElement], return a buffer with the code generated for it
289 // or null if no code was generated.
290 CodeBuffer codeOf(Element element) => null;
291
292 void initializeHelperClasses() {}
293
294 void enqueueHelpers(ResolutionEnqueuer world, Registry registry);
295 WorldImpact codegen(CodegenWorkItem work);
296
297 // The backend determines the native resolution enqueuer, with a no-op
298 // default, so tools like dart2dart can ignore the native classes.
299 native.NativeEnqueuer nativeResolutionEnqueuer(world) {
300 return new native.NativeEnqueuer();
301 }
302 native.NativeEnqueuer nativeCodegenEnqueuer(world) {
303 return new native.NativeEnqueuer();
304 }
305
306 /// Generates the output and returns the total size of the generated code.
307 int assembleProgram();
308
309 List<CompilerTask> get tasks;
310
311 void onResolutionComplete() {}
312 void onTypeInferenceComplete() {}
313
314 ItemCompilationContext createItemCompilationContext() {
315 return new ItemCompilationContext();
316 }
317
318 bool classNeedsRti(ClassElement cls);
319 bool methodNeedsRti(FunctionElement function);
320
321 /// Enable compilation of code with compile time errors. Returns `true` if
322 /// supported by the backend.
323 bool enableCodegenWithErrorsIfSupported(Spannable node);
324
325 /// Enable deferred loading. Returns `true` if the backend supports deferred
326 /// loading.
327 bool enableDeferredLoadingIfSupported(Spannable node, Registry registry);
328
329 /// Called during codegen when [constant] has been used.
330 void registerCompileTimeConstant(ConstantValue constant, Registry registry) {}
331
332 /// Called during resolution when a constant value for [metadata] on
333 /// [annotatedElement] has been evaluated.
334 void registerMetadataConstant(MetadataAnnotation metadata,
335 Element annotatedElement,
336 Registry registry) {}
337
338 /// Called to notify to the backend that a class is being instantiated.
339 // TODO(johnniwinther): Remove this. It's only called once for each [cls] and
340 // only with [Compiler.globalDependencies] as [registry].
341 void registerInstantiatedClass(ClassElement cls,
342 Enqueuer enqueuer,
343 Registry registry) {}
344
345 /// Called to notify to the backend that an interface type has been
346 /// instantiated.
347 void registerInstantiatedType(InterfaceType type, Registry registry) {}
348
349 /// Register an is check to the backend.
350 void registerIsCheckForCodegen(DartType type,
351 Enqueuer enqueuer,
352 Registry registry) {}
353
354 /// Register a runtime type variable bound tests between [typeArgument] and
355 /// [bound].
356 void registerTypeVariableBoundsSubtypeCheck(DartType typeArgument,
357 DartType bound) {}
358
359 /// Returns `true` if [element] represent the assert function.
360 bool isAssertMethod(Element element) => false;
361
362 /**
363 * Call this to register that an instantiated generic class has a call
364 * method.
365 */
366 void registerCallMethodWithFreeTypeVariables(
367 Element callMethod,
368 Enqueuer enqueuer,
369 Registry registry) {}
370
371 /**
372 * Call this to register that a getter exists for a function on an
373 * instantiated generic class.
374 */
375 void registerClosureWithFreeTypeVariables(
376 Element closure,
377 Enqueuer enqueuer,
378 Registry registry) {}
379
380 /// Call this to register that a member has been closurized.
381 void registerBoundClosure(Enqueuer enqueuer) {}
382
383 /// Call this to register that a static function has been closurized.
384 void registerGetOfStaticFunction(Enqueuer enqueuer) {}
385
386 /**
387 * Call this to register that the [:runtimeType:] property has been accessed.
388 */
389 void registerRuntimeType(Enqueuer enqueuer, Registry registry) {}
390
391 /// Call this to register a `noSuchMethod` implementation.
392 void registerNoSuchMethod(FunctionElement noSuchMethodElement) {}
393
394 /// Call this method to enable support for `noSuchMethod`.
395 void enableNoSuchMethod(Enqueuer enqueuer) {}
396
397 /// Returns whether or not `noSuchMethod` support has been enabled.
398 bool get enabledNoSuchMethod => false;
399
400 /// Call this method to enable support for isolates.
401 void enableIsolateSupport(Enqueuer enqueuer) {}
402
403 void registerRequiredType(DartType type, Element enclosingElement) {}
404 void registerClassUsingVariableExpression(ClassElement cls) {}
405
406 void registerConstSymbol(String name, Registry registry) {}
407 void registerNewSymbol(Registry registry) {}
408
409 bool isNullImplementation(ClassElement cls) {
410 return cls == compiler.nullClass;
411 }
412
413 ClassElement get intImplementation => compiler.intClass;
414 ClassElement get doubleImplementation => compiler.doubleClass;
415 ClassElement get numImplementation => compiler.numClass;
416 ClassElement get stringImplementation => compiler.stringClass;
417 ClassElement get listImplementation => compiler.listClass;
418 ClassElement get growableListImplementation => compiler.listClass;
419 ClassElement get fixedListImplementation => compiler.listClass;
420 ClassElement get constListImplementation => compiler.listClass;
421 ClassElement get mapImplementation => compiler.mapClass;
422 ClassElement get constMapImplementation => compiler.mapClass;
423 ClassElement get functionImplementation => compiler.functionClass;
424 ClassElement get typeImplementation => compiler.typeClass;
425 ClassElement get boolImplementation => compiler.boolClass;
426 ClassElement get nullImplementation => compiler.nullClass;
427 ClassElement get uint32Implementation => compiler.intClass;
428 ClassElement get uint31Implementation => compiler.intClass;
429 ClassElement get positiveIntImplementation => compiler.intClass;
430
431 ClassElement defaultSuperclass(ClassElement element) => compiler.objectClass;
432
433 bool isInterceptorClass(ClassElement element) => false;
434
435 /// Returns `true` if [element] is a foreign element, that is, that the
436 /// backend has specialized handling for the element.
437 bool isForeign(Element element) => false;
438
439 /// Processes [element] for resolution and returns the [FunctionElement] that
440 /// defines the implementation of [element].
441 FunctionElement resolveExternalFunction(FunctionElement element) => element;
442
443 /// Returns `true` if [library] is a backend specific library whose members
444 /// have special treatment, such as being allowed to extends blacklisted
445 /// classes or member being eagerly resolved.
446 bool isBackendLibrary(LibraryElement library) {
447 // TODO(johnniwinther): Remove this when patching is only done by the
448 // JavaScript backend.
449 Uri canonicalUri = library.canonicalUri;
450 if (canonicalUri == js_backend.JavaScriptBackend.DART_JS_HELPER ||
451 canonicalUri == js_backend.JavaScriptBackend.DART_INTERCEPTORS) {
452 return true;
453 }
454 return false;
455 }
456
457 void registerStaticUse(Element element, Enqueuer enqueuer) {}
458
459 /// This method is called immediately after the [LibraryElement] [library] has
460 /// been created.
461 void onLibraryCreated(LibraryElement library) {}
462
463 /// This method is called immediately after the [library] and its parts have
464 /// been scanned.
465 Future onLibraryScanned(LibraryElement library, LibraryLoader loader) {
466 if (library.canUseNative) {
467 library.forEachLocalMember((Element element) {
468 if (element.isClass) {
469 checkNativeAnnotation(compiler, element);
470 }
471 });
472 }
473 return new Future.value();
474 }
475
476 /// This method is called when all new libraries loaded through
477 /// [LibraryLoader.loadLibrary] has been loaded and their imports/exports
478 /// have been computed.
479 Future onLibrariesLoaded(LoadedLibraries loadedLibraries) {
480 return new Future.value();
481 }
482
483 /// Called by [MirrorUsageAnalyzerTask] after it has merged all @MirrorsUsed
484 /// annotations. The arguments corresponds to the unions of the corresponding
485 /// fields of the annotations.
486 void registerMirrorUsage(Set<String> symbols,
487 Set<Element> targets,
488 Set<Element> metaTargets) {}
489
490 /// Returns true if this element needs reflection information at runtime.
491 bool isAccessibleByReflection(Element element) => true;
492
493 /// Returns true if this element is covered by a mirrorsUsed annotation.
494 ///
495 /// Note that it might still be ok to tree shake the element away if no
496 /// reflection is used in the program (and thus [isTreeShakingDisabled] is
497 /// still false). Therefore _do not_ use this predicate to decide inclusion
498 /// in the tree, use [requiredByMirrorSystem] instead.
499 bool referencedFromMirrorSystem(Element element, [recursive]) => false;
500
501 /// Returns true if this element has to be enqueued due to
502 /// mirror usage. Might be a subset of [referencedFromMirrorSystem] if
503 /// normal tree shaking is still active ([isTreeShakingDisabled] is false).
504 bool requiredByMirrorSystem(Element element) => false;
505
506 /// Returns true if global optimizations such as type inferencing
507 /// can apply to this element. One category of elements that do not
508 /// apply is runtime helpers that the backend calls, but the
509 /// optimizations don't see those calls.
510 bool canBeUsedForGlobalOptimizations(Element element) => true;
511
512 /// Called when [enqueuer]'s queue is empty, but before it is closed.
513 /// This is used, for example, by the JS backend to enqueue additional
514 /// elements needed for reflection. [recentClasses] is a collection of
515 /// all classes seen for the first time by the [enqueuer] since the last call
516 /// to [onQueueEmpty].
517 ///
518 /// A return value of [:true:] indicates that [recentClasses] has been
519 /// processed and its elements do not need to be seen in the next round. When
520 /// [:false:] is returned, [onQueueEmpty] will be called again once the
521 /// resolution queue has drained and [recentClasses] will be a superset of the
522 /// current value.
523 ///
524 /// There is no guarantee that a class is only present once in
525 /// [recentClasses], but every class seen by the [enqueuer] will be present in
526 /// [recentClasses] at least once.
527 bool onQueueEmpty(Enqueuer enqueuer, Iterable<ClassElement> recentClasses) {
528 return true;
529 }
530
531 /// Called after [element] has been resolved.
532 // TODO(johnniwinther): Change [TreeElements] to [Registry] or a dependency
533 // node. [elements] is currently unused by the implementation.
534 void onElementResolved(Element element, TreeElements elements) {}
535
536 // Does this element belong in the output
537 bool shouldOutput(Element element) => true;
538
539 FunctionElement helperForBadMain() => null;
540
541 FunctionElement helperForMissingMain() => null;
542
543 FunctionElement helperForMainArity() => null;
544
545 void forgetElement(Element element) {}
546
547 void registerMainHasArguments(Enqueuer enqueuer) {}
548
549 void registerAsyncMarker(FunctionElement element,
550 Enqueuer enqueuer,
551 Registry registry) {}
552 }
553
554 /// Backend callbacks function specific to the resolution phase.
555 class ResolutionCallbacks {
556 /// Register that [node] is a call to `assert`.
557 void onAssert(Send node, Registry registry) {}
558
559 /// Register that an 'await for' has been seen.
560 void onAsyncForIn(AsyncForIn node, Registry registry) {}
561
562 /// Called during resolution to notify to the backend that the
563 /// program uses string interpolation.
564 void onStringInterpolation(Registry registry) {}
565
566 /// Called during resolution to notify to the backend that the
567 /// program has a catch statement.
568 void onCatchStatement(Registry registry) {}
569
570 /// Called during resolution to notify to the backend that the
571 /// program explicitly throws an exception.
572 void onThrowExpression(Registry registry) {}
573
574 /// Called during resolution to notify to the backend that the
575 /// program has a global variable with a lazy initializer.
576 void onLazyField(Registry registry) {}
577
578 /// Called during resolution to notify to the backend that the
579 /// program uses a type variable as an expression.
580 void onTypeVariableExpression(Registry registry) {}
581
582 /// Called during resolution to notify to the backend that the
583 /// program uses a type literal.
584 void onTypeLiteral(DartType type, Registry registry) {}
585
586 /// Called during resolution to notify to the backend that the
587 /// program has a catch statement with a stack trace.
588 void onStackTraceInCatch(Registry registry) {}
589
590 /// Register an is check to the backend.
591 void onIsCheck(DartType type, Registry registry) {}
592
593 /// Called during resolution to notify to the backend that the
594 /// program has a for-in loop.
595 void onSyncForIn(Registry registry) {}
596
597 /// Register an as check to the backend.
598 void onAsCheck(DartType type, Registry registry) {}
599
600 /// Registers that a type variable bounds check might occur at runtime.
601 void onTypeVariableBoundCheck(Registry registry) {}
602
603 /// Register that the application may throw a [NoSuchMethodError].
604 void onThrowNoSuchMethod(Registry registry) {}
605
606 /// Register that the application may throw a [RuntimeError].
607 void onThrowRuntimeError(Registry registry) {}
608
609 /// Register that the application may throw an
610 /// [AbstractClassInstantiationError].
611 void onAbstractClassInstantiation(Registry registry) {}
612
613 /// Register that the application may throw a [FallThroughError].
614 void onFallThroughError(Registry registry) {}
615
616 /// Register that a super call will end up calling
617 /// [: super.noSuchMethod :].
618 void onSuperNoSuchMethod(Registry registry) {}
619
620 /// Register that the application creates a constant map.
621 void onMapLiteral(Registry registry, DartType type, bool isConstant) {}
622
623 /// Called when resolving the `Symbol` constructor.
624 void onSymbolConstructor(Registry registry) {}
625 }
626 9
627 /** 10 /**
628 * Key class used in [TokenMap] in which the hash code for a token is based 11 * Key class used in [TokenMap] in which the hash code for a token is based
629 * on the [charOffset]. 12 * on the [charOffset].
630 */ 13 */
631 class TokenKey { 14 class TokenKey {
632 final Token token; 15 final Token token;
633 TokenKey(this.token); 16 TokenKey(this.token);
634 int get hashCode => token.charOffset; 17 int get hashCode => token.charOffset;
635 operator==(other) => other is TokenKey && token == other.token; 18 operator==(other) => other is TokenKey && token == other.token;
(...skipping 19 matching lines...) Expand all
655 Token operator[] (Token key) { 38 Token operator[] (Token key) {
656 if (key == null) return null; 39 if (key == null) return null;
657 return comments[new TokenKey(key)]; 40 return comments[new TokenKey(key)];
658 } 41 }
659 42
660 void operator[]= (Token key, Token value) { 43 void operator[]= (Token key, Token value) {
661 if (key == null) return; 44 if (key == null) return;
662 comments[new TokenKey(key)] = value; 45 comments[new TokenKey(key)] = value;
663 } 46 }
664 } 47 }
665
666 abstract class Compiler implements DiagnosticListener {
667 static final Uri DART_CORE = new Uri(scheme: 'dart', path: 'core');
668 static final Uri DART_MIRRORS = new Uri(scheme: 'dart', path: 'mirrors');
669 static final Uri DART_NATIVE_TYPED_DATA =
670 new Uri(scheme: 'dart', path: '_native_typed_data');
671 static final Uri DART_INTERNAL = new Uri(scheme: 'dart', path: '_internal');
672 static final Uri DART_ASYNC = new Uri(scheme: 'dart', path: 'async');
673
674 final Stopwatch totalCompileTime = new Stopwatch();
675 int nextFreeClassId = 0;
676 World world;
677 Types types;
678 _CompilerCoreTypes _coreTypes;
679
680 final CacheStrategy cacheStrategy;
681
682 /**
683 * Map from token to the first preceding comment token.
684 */
685 final TokenMap commentMap = new TokenMap();
686
687 /**
688 * Records global dependencies, that is, dependencies that don't
689 * correspond to a particular element.
690 *
691 * We should get rid of this and ensure that all dependencies are
692 * associated with a particular element.
693 */
694 Registry globalDependencies;
695
696 /**
697 * Dependencies that are only included due to mirrors.
698 *
699 * We should get rid of this and ensure that all dependencies are
700 * associated with a particular element.
701 */
702 // TODO(johnniwinther): This should not be a [ResolutionRegistry].
703 final Registry mirrorDependencies =
704 new ResolutionRegistry.internal(null, new TreeElementMapping(null));
705
706 final bool enableMinification;
707
708 final bool useFrequencyNamer;
709
710 /// When `true` emits URIs in the reflection metadata.
711 final bool preserveUris;
712
713 final bool enableTypeAssertions;
714 final bool enableUserAssertions;
715 final bool trustTypeAnnotations;
716 final bool trustPrimitives;
717 final bool enableConcreteTypeInference;
718 final bool disableTypeInferenceFlag;
719 final Uri deferredMapUri;
720 final bool dumpInfo;
721 final bool useContentSecurityPolicy;
722 final bool enableExperimentalMirrors;
723
724 /**
725 * The maximum size of a concrete type before it widens to dynamic during
726 * concrete type inference.
727 */
728 final int maxConcreteTypeSize;
729 final bool analyzeAllFlag;
730 final bool analyzeOnly;
731
732 /// If true, disable tree-shaking for the main script.
733 final bool analyzeMain;
734
735 /**
736 * If true, skip analysis of method bodies and field initializers. Implies
737 * [analyzeOnly].
738 */
739 final bool analyzeSignaturesOnly;
740 final bool enableNativeLiveTypeAnalysis;
741
742 /**
743 * If true, stop compilation after type inference is complete. Used for
744 * debugging and testing purposes only.
745 */
746 bool stopAfterTypeInference = false;
747
748 /**
749 * If [:true:], comment tokens are collected in [commentMap] during scanning.
750 */
751 final bool preserveComments;
752
753 /// Use the new CPS based backend end. This flag works for both the Dart and
754 /// JavaScript backend.
755 final bool useCpsIr;
756
757 /**
758 * Is the compiler in verbose mode.
759 */
760 final bool verbose;
761
762 /**
763 * URI of the main source map if the compiler is generating source
764 * maps.
765 */
766 final Uri sourceMapUri;
767
768 /**
769 * URI of the main output if the compiler is generating source maps.
770 */
771 final Uri outputUri;
772
773 /// Emit terse diagnostics without howToFix.
774 final bool terseDiagnostics;
775
776 /// If `true`, warnings and hints not from user code are reported.
777 final bool showPackageWarnings;
778
779 /// `true` if the last diagnostic was filtered, in which case the
780 /// accompanying info message should be filtered as well.
781 bool lastDiagnosticWasFiltered = false;
782
783 /// Map containing information about the warnings and hints that have been
784 /// suppressed for each library.
785 Map<Uri, SuppressionInfo> suppressedWarnings = <Uri, SuppressionInfo>{};
786
787 final bool suppressWarnings;
788 final bool fatalWarnings;
789
790 /// If `true`, some values are cached for reuse in incremental compilation.
791 /// Incremental compilation is basically calling [run] more than once.
792 final bool hasIncrementalSupport;
793
794 /// If `true` native extension syntax is supported by the frontend.
795 final bool allowNativeExtensions;
796
797 /// Output provider from user of Compiler API.
798 api.CompilerOutput userOutputProvider;
799
800 /// Generate output even when there are compile-time errors.
801 final bool generateCodeWithCompileTimeErrors;
802
803 /// The compiler is run from the build bot.
804 final bool testMode;
805
806 bool disableInlining = false;
807
808 List<Uri> librariesToAnalyzeWhenRun;
809
810 Tracer tracer;
811
812 CompilerTask measuredTask;
813 Element _currentElement;
814 LibraryElement coreLibrary;
815 LibraryElement asyncLibrary;
816
817 LibraryElement mainApp;
818 FunctionElement mainFunction;
819
820 /// Initialized when dart:mirrors is loaded.
821 LibraryElement mirrorsLibrary;
822
823 /// Initialized when dart:typed_data is loaded.
824 LibraryElement typedDataLibrary;
825
826 ClassElement get objectClass => _coreTypes.objectClass;
827 ClassElement get boolClass => _coreTypes.boolClass;
828 ClassElement get numClass => _coreTypes.numClass;
829 ClassElement get intClass => _coreTypes.intClass;
830 ClassElement get doubleClass => _coreTypes.doubleClass;
831 ClassElement get stringClass => _coreTypes.stringClass;
832 ClassElement get functionClass => _coreTypes.functionClass;
833 ClassElement get nullClass => _coreTypes.nullClass;
834 ClassElement get listClass => _coreTypes.listClass;
835 ClassElement get typeClass => _coreTypes.typeClass;
836 ClassElement get mapClass => _coreTypes.mapClass;
837 ClassElement get symbolClass => _coreTypes.symbolClass;
838 ClassElement get stackTraceClass => _coreTypes.stackTraceClass;
839 ClassElement get futureClass => _coreTypes.futureClass;
840 ClassElement get iterableClass => _coreTypes.iterableClass;
841 ClassElement get streamClass => _coreTypes.streamClass;
842
843 CoreTypes get coreTypes => _coreTypes;
844
845 ClassElement typedDataClass;
846
847 /// The constant for the [proxy] variable defined in dart:core.
848 ConstantValue proxyConstant;
849
850 // TODO(johnniwinther): Move this to the JavaScriptBackend.
851 /// The class for patch annotation defined in dart:_js_helper.
852 ClassElement patchAnnotationClass;
853
854 // TODO(johnniwinther): Move this to the JavaScriptBackend.
855 ClassElement nativeAnnotationClass;
856
857 // Initialized after symbolClass has been resolved.
858 FunctionElement symbolConstructor;
859
860 // Initialized when dart:mirrors is loaded.
861 ClassElement mirrorSystemClass;
862
863 // Initialized when dart:mirrors is loaded.
864 ClassElement mirrorsUsedClass;
865
866 // Initialized after mirrorSystemClass has been resolved.
867 FunctionElement mirrorSystemGetNameFunction;
868
869 // Initialized when dart:_internal is loaded.
870 ClassElement symbolImplementationClass;
871
872 // Initialized when symbolImplementationClass has been resolved.
873 FunctionElement symbolValidatedConstructor;
874
875 // Initialized when mirrorsUsedClass has been resolved.
876 FunctionElement mirrorsUsedConstructor;
877
878 // Initialized when dart:mirrors is loaded.
879 ClassElement deferredLibraryClass;
880
881 /// Document class from dart:mirrors.
882 ClassElement documentClass;
883 Element identicalFunction;
884 Element loadLibraryFunction;
885 Element functionApplyMethod;
886
887 /// The [int.fromEnvironment] constructor.
888 ConstructorElement intEnvironment;
889
890 /// The [bool.fromEnvironment] constructor.
891 ConstructorElement boolEnvironment;
892
893 /// The [String.fromEnvironment] constructor.
894 ConstructorElement stringEnvironment;
895
896 /// Tracks elements with compile-time errors.
897 final Set<Element> elementsWithCompileTimeErrors = new Set<Element>();
898
899 fromEnvironment(String name) => null;
900
901 Element get currentElement => _currentElement;
902
903 String tryToString(object) {
904 try {
905 return object.toString();
906 } catch (_) {
907 return '<exception in toString()>';
908 }
909 }
910
911 /**
912 * Perform an operation, [f], returning the return value from [f]. If an
913 * error occurs then report it as having occurred during compilation of
914 * [element]. Can be nested.
915 */
916 withCurrentElement(Element element, f()) {
917 Element old = currentElement;
918 _currentElement = element;
919 try {
920 return f();
921 } on SpannableAssertionFailure catch (ex) {
922 if (!hasCrashed) {
923 reportAssertionFailure(ex);
924 pleaseReportCrash();
925 }
926 hasCrashed = true;
927 rethrow;
928 } on StackOverflowError {
929 // We cannot report anything useful in this case, because we
930 // do not have enough stack space.
931 rethrow;
932 } catch (ex) {
933 if (hasCrashed) rethrow;
934 try {
935 unhandledExceptionOnElement(element);
936 } catch (doubleFault) {
937 // Ignoring exceptions in exception handling.
938 }
939 rethrow;
940 } finally {
941 _currentElement = old;
942 }
943 }
944
945 List<CompilerTask> tasks;
946 ScannerTask scanner;
947 DietParserTask dietParser;
948 ParserTask parser;
949 PatchParserTask patchParser;
950 LibraryLoaderTask libraryLoader;
951 SerializationTask serialization;
952 ResolverTask resolver;
953 closureMapping.ClosureTask closureToClassMapper;
954 TypeCheckerTask checker;
955 IrBuilderTask irBuilder;
956 ti.TypesTask typesTask;
957 Backend backend;
958
959 GenericTask reuseLibraryTask;
960
961 /// The constant environment for the frontend interpretation of compile-time
962 /// constants.
963 ConstantEnvironment constants;
964
965 EnqueueTask enqueuer;
966 DeferredLoadTask deferredLoadTask;
967 MirrorUsageAnalyzerTask mirrorUsageAnalyzerTask;
968 DumpInfoTask dumpInfoTask;
969 String buildId;
970
971 /// A customizable filter that is applied to enqueued work items.
972 QueueFilter enqueuerFilter = new QueueFilter();
973
974 static const String MAIN = 'main';
975 static const String CALL_OPERATOR_NAME = 'call';
976 static const String NO_SUCH_METHOD = 'noSuchMethod';
977 static const int NO_SUCH_METHOD_ARG_COUNT = 1;
978 static const String CREATE_INVOCATION_MIRROR =
979 'createInvocationMirror';
980 static const String FROM_ENVIRONMENT = 'fromEnvironment';
981
982 static const String RUNTIME_TYPE = 'runtimeType';
983
984 static const String UNDETERMINED_BUILD_ID =
985 "build number could not be determined";
986
987 final Selector iteratorSelector =
988 new Selector.getter('iterator', null);
989 final Selector currentSelector =
990 new Selector.getter('current', null);
991 final Selector moveNextSelector =
992 new Selector.call('moveNext', null, 0);
993 final Selector noSuchMethodSelector = new Selector.call(
994 Compiler.NO_SUCH_METHOD, null, Compiler.NO_SUCH_METHOD_ARG_COUNT);
995 final Selector symbolValidatedConstructorSelector = new Selector.call(
996 'validated', null, 1);
997
998 bool enabledRuntimeType = false;
999 bool enabledFunctionApply = false;
1000 bool enabledInvokeOn = false;
1001 bool hasIsolateSupport = false;
1002
1003 Stopwatch progress;
1004
1005 bool get shouldPrintProgress {
1006 return verbose && progress.elapsedMilliseconds > 500;
1007 }
1008
1009 static const int PHASE_SCANNING = 0;
1010 static const int PHASE_RESOLVING = 1;
1011 static const int PHASE_DONE_RESOLVING = 2;
1012 static const int PHASE_COMPILING = 3;
1013 int phase;
1014
1015 bool compilationFailedInternal = false;
1016
1017 bool get compilationFailed => compilationFailedInternal;
1018
1019 void set compilationFailed(bool value) {
1020 if (value) {
1021 elementsWithCompileTimeErrors.add(currentElement);
1022 }
1023 compilationFailedInternal = value;
1024 }
1025
1026 bool hasCrashed = false;
1027
1028 /// Set by the backend if real reflection is detected in use of dart:mirrors.
1029 bool disableTypeInferenceForMirrors = false;
1030
1031 Compiler({this.enableTypeAssertions: false,
1032 this.enableUserAssertions: false,
1033 this.trustTypeAnnotations: false,
1034 this.trustPrimitives: false,
1035 this.enableConcreteTypeInference: false,
1036 bool disableTypeInferenceFlag: false,
1037 this.maxConcreteTypeSize: 5,
1038 this.enableMinification: false,
1039 this.preserveUris: false,
1040 this.enableNativeLiveTypeAnalysis: false,
1041 bool emitJavaScript: true,
1042 bool dart2dartMultiFile: false,
1043 bool generateSourceMap: true,
1044 bool analyzeAllFlag: false,
1045 bool analyzeOnly: false,
1046 this.analyzeMain: false,
1047 bool analyzeSignaturesOnly: false,
1048 this.preserveComments: false,
1049 this.useCpsIr: false,
1050 this.useFrequencyNamer: false,
1051 this.verbose: false,
1052 this.sourceMapUri: null,
1053 this.outputUri: null,
1054 this.buildId: UNDETERMINED_BUILD_ID,
1055 this.terseDiagnostics: false,
1056 this.deferredMapUri: null,
1057 this.dumpInfo: false,
1058 this.showPackageWarnings: false,
1059 bool useStartupEmitter: false,
1060 this.useContentSecurityPolicy: false,
1061 this.suppressWarnings: false,
1062 this.fatalWarnings: false,
1063 bool hasIncrementalSupport: false,
1064 this.enableExperimentalMirrors: false,
1065 this.allowNativeExtensions: false,
1066 this.generateCodeWithCompileTimeErrors: false,
1067 this.testMode: false,
1068 api.CompilerOutput outputProvider,
1069 List<String> strips: const []})
1070 : this.disableTypeInferenceFlag =
1071 disableTypeInferenceFlag || !emitJavaScript,
1072 this.analyzeOnly =
1073 analyzeOnly || analyzeSignaturesOnly || analyzeAllFlag,
1074 this.analyzeSignaturesOnly = analyzeSignaturesOnly,
1075 this.analyzeAllFlag = analyzeAllFlag,
1076 this.hasIncrementalSupport = hasIncrementalSupport,
1077 cacheStrategy = new CacheStrategy(hasIncrementalSupport),
1078 this.userOutputProvider = outputProvider == null
1079 ? const NullCompilerOutput() : outputProvider {
1080 if (hasIncrementalSupport) {
1081 // TODO(ahe): This is too much. Any method from platform and package
1082 // libraries can be inlined.
1083 disableInlining = true;
1084 }
1085 world = new World(this);
1086 // TODO(johnniwinther): Initialize core types in [initializeCoreClasses] and
1087 // make its field final.
1088 _coreTypes = new _CompilerCoreTypes(this);
1089 types = new Types(this);
1090 tracer = new Tracer(this, this.outputProvider);
1091
1092 if (verbose) {
1093 progress = new Stopwatch()..start();
1094 }
1095
1096 // TODO(johnniwinther): Separate the dependency tracking from the enqueuing
1097 // for global dependencies.
1098 globalDependencies =
1099 new CodegenRegistry(this, new TreeElementMapping(null));
1100
1101 if (emitJavaScript) {
1102 js_backend.JavaScriptBackend jsBackend =
1103 new js_backend.JavaScriptBackend(
1104 this, generateSourceMap: generateSourceMap,
1105 useStartupEmitter: useStartupEmitter);
1106 backend = jsBackend;
1107 } else {
1108 backend = new dart_backend.DartBackend(this, strips,
1109 multiFile: dart2dartMultiFile);
1110 if (dumpInfo) {
1111 throw new ArgumentError('--dump-info is not supported for dart2dart.');
1112 }
1113 }
1114
1115 tasks = [
1116 libraryLoader = new LibraryLoaderTask(this),
1117 serialization = new SerializationTask(this),
1118 scanner = new ScannerTask(this),
1119 dietParser = new DietParserTask(this),
1120 parser = new ParserTask(this),
1121 patchParser = new PatchParserTask(this),
1122 resolver = new ResolverTask(this, backend.constantCompilerTask),
1123 closureToClassMapper = new closureMapping.ClosureTask(this),
1124 checker = new TypeCheckerTask(this),
1125 irBuilder = new IrBuilderTask(this, backend.sourceInformationStrategy),
1126 typesTask = new ti.TypesTask(this),
1127 constants = backend.constantCompilerTask,
1128 deferredLoadTask = new DeferredLoadTask(this),
1129 mirrorUsageAnalyzerTask = new MirrorUsageAnalyzerTask(this),
1130 enqueuer = new EnqueueTask(this),
1131 dumpInfoTask = new DumpInfoTask(this),
1132 reuseLibraryTask = new GenericTask('Reuse library', this),
1133 ];
1134
1135 tasks.addAll(backend.tasks);
1136 }
1137
1138 Universe get resolverWorld => enqueuer.resolution.universe;
1139 Universe get codegenWorld => enqueuer.codegen.universe;
1140
1141 bool get hasBuildId => buildId != UNDETERMINED_BUILD_ID;
1142
1143 bool get analyzeAll => analyzeAllFlag || compileAll;
1144
1145 bool get compileAll => false;
1146
1147 bool get disableTypeInference {
1148 return disableTypeInferenceFlag || compilationFailed;
1149 }
1150
1151 int getNextFreeClassId() => nextFreeClassId++;
1152
1153 void unimplemented(Spannable spannable, String methodName) {
1154 internalError(spannable, "$methodName not implemented.");
1155 }
1156
1157 void internalError(Spannable node, reason) {
1158 String message = tryToString(reason);
1159 reportDiagnosticInternal(
1160 node, MessageKind.GENERIC, {'text': message}, api.Diagnostic.CRASH);
1161 throw 'Internal Error: $message';
1162 }
1163
1164 void unhandledExceptionOnElement(Element element) {
1165 if (hasCrashed) return;
1166 hasCrashed = true;
1167 reportDiagnostic(
1168 element,
1169 MessageTemplate.TEMPLATES[MessageKind.COMPILER_CRASHED].message(),
1170 api.Diagnostic.CRASH);
1171 pleaseReportCrash();
1172 }
1173
1174 void pleaseReportCrash() {
1175 print(
1176 MessageTemplate.TEMPLATES[MessageKind.PLEASE_REPORT_THE_CRASH]
1177 .message({'buildId': buildId}));
1178 }
1179
1180 SourceSpan spanFromSpannable(Spannable node) {
1181 // TODO(johnniwinther): Disallow `node == null` ?
1182 if (node == null) return null;
1183 if (node == CURRENT_ELEMENT_SPANNABLE) {
1184 node = currentElement;
1185 } else if (node == NO_LOCATION_SPANNABLE) {
1186 if (currentElement == null) return null;
1187 node = currentElement;
1188 }
1189 if (node is SourceSpan) {
1190 return node;
1191 } else if (node is Node) {
1192 return spanFromNode(node);
1193 } else if (node is TokenPair) {
1194 return spanFromTokens(node.begin, node.end);
1195 } else if (node is Token) {
1196 return spanFromTokens(node, node);
1197 } else if (node is HInstruction) {
1198 return spanFromHInstruction(node);
1199 } else if (node is Element) {
1200 return spanFromElement(node);
1201 } else if (node is MetadataAnnotation) {
1202 Uri uri = node.annotatedElement.compilationUnit.script.resourceUri;
1203 return spanFromTokens(node.beginToken, node.endToken, uri);
1204 } else if (node is Local) {
1205 Local local = node;
1206 return spanFromElement(local.executableContext);
1207 } else {
1208 throw 'No error location.';
1209 }
1210 }
1211
1212 Element _elementFromHInstruction(HInstruction instruction) {
1213 return instruction.sourceElement is Element
1214 ? instruction.sourceElement : null;
1215 }
1216
1217 /// Finds the approximate [Element] for [node]. [currentElement] is used as
1218 /// the default value.
1219 Element elementFromSpannable(Spannable node) {
1220 Element element;
1221 if (node is Element) {
1222 element = node;
1223 } else if (node is HInstruction) {
1224 element = _elementFromHInstruction(node);
1225 } else if (node is MetadataAnnotation) {
1226 element = node.annotatedElement;
1227 }
1228 return element != null ? element : currentElement;
1229 }
1230
1231 void log(message) {
1232 reportDiagnostic(null,
1233 MessageTemplate.TEMPLATES[MessageKind.GENERIC]
1234 .message({'text': '$message'}),
1235 api.Diagnostic.VERBOSE_INFO);
1236 }
1237
1238 Future<bool> run(Uri uri) {
1239 totalCompileTime.start();
1240
1241 return new Future.sync(() => runCompiler(uri)).catchError((error) {
1242 try {
1243 if (!hasCrashed) {
1244 hasCrashed = true;
1245 if (error is SpannableAssertionFailure) {
1246 reportAssertionFailure(error);
1247 } else {
1248 reportDiagnostic(
1249 new SourceSpan(uri, 0, 0),
1250 MessageTemplate.TEMPLATES[MessageKind.COMPILER_CRASHED]
1251 .message(),
1252 api.Diagnostic.CRASH);
1253 }
1254 pleaseReportCrash();
1255 }
1256 } catch (doubleFault) {
1257 // Ignoring exceptions in exception handling.
1258 }
1259 throw error;
1260 }).whenComplete(() {
1261 tracer.close();
1262 totalCompileTime.stop();
1263 }).then((_) {
1264 return !compilationFailed;
1265 });
1266 }
1267
1268 /// This method is called immediately after the [LibraryElement] [library] has
1269 /// been created.
1270 ///
1271 /// Use this callback method to store references to specific libraries.
1272 /// Note that [library] has not been scanned yet, nor has its imports/exports
1273 /// been resolved.
1274 void onLibraryCreated(LibraryElement library) {
1275 Uri uri = library.canonicalUri;
1276 if (uri == DART_CORE) {
1277 coreLibrary = library;
1278 } else if (uri == DART_NATIVE_TYPED_DATA) {
1279 typedDataLibrary = library;
1280 } else if (uri == DART_MIRRORS) {
1281 mirrorsLibrary = library;
1282 }
1283 backend.onLibraryCreated(library);
1284 }
1285
1286 /// This method is called immediately after the [library] and its parts have
1287 /// been scanned.
1288 ///
1289 /// Use this callback method to store references to specific member declared
1290 /// in certain libraries. Note that [library] has not been patched yet, nor
1291 /// has its imports/exports been resolved.
1292 ///
1293 /// Use [loader] to register the creation and scanning of a patch library
1294 /// for [library].
1295 Future onLibraryScanned(LibraryElement library, LibraryLoader loader) {
1296 Uri uri = library.canonicalUri;
1297 if (uri == DART_CORE) {
1298 initializeCoreClasses();
1299 identicalFunction = coreLibrary.find('identical');
1300 } else if (uri == DART_INTERNAL) {
1301 symbolImplementationClass = findRequiredElement(library, 'Symbol');
1302 } else if (uri == DART_MIRRORS) {
1303 mirrorSystemClass = findRequiredElement(library, 'MirrorSystem');
1304 mirrorsUsedClass = findRequiredElement(library, 'MirrorsUsed');
1305 } else if (uri == DART_ASYNC) {
1306 asyncLibrary = library;
1307 deferredLibraryClass = findRequiredElement(library, 'DeferredLibrary');
1308 _coreTypes.futureClass = findRequiredElement(library, 'Future');
1309 _coreTypes.streamClass = findRequiredElement(library, 'Stream');
1310 } else if (uri == DART_NATIVE_TYPED_DATA) {
1311 typedDataClass = findRequiredElement(library, 'NativeTypedData');
1312 } else if (uri == js_backend.JavaScriptBackend.DART_JS_HELPER) {
1313 patchAnnotationClass = findRequiredElement(library, '_Patch');
1314 nativeAnnotationClass = findRequiredElement(library, 'Native');
1315 }
1316 return backend.onLibraryScanned(library, loader);
1317 }
1318
1319 /// This method is called when all new libraries loaded through
1320 /// [LibraryLoader.loadLibrary] has been loaded and their imports/exports
1321 /// have been computed.
1322 ///
1323 /// [loadedLibraries] contains the newly loaded libraries.
1324 ///
1325 /// The method returns a [Future] allowing for the loading of additional
1326 /// libraries.
1327 Future onLibrariesLoaded(LoadedLibraries loadedLibraries) {
1328 return new Future.sync(() {
1329 if (!loadedLibraries.containsLibrary(DART_CORE)) {
1330 return null;
1331 }
1332 if (!enableExperimentalMirrors &&
1333 loadedLibraries.containsLibrary(DART_MIRRORS)) {
1334 // TODO(johnniwinther): Move computation of dependencies to the library
1335 // loader.
1336 Uri rootUri = loadedLibraries.rootUri;
1337 Set<String> importChains = new Set<String>();
1338 // The maximum number of full imports chains to process.
1339 final int chainLimit = 10000;
1340 // The maximum number of imports chains to show.
1341 final int compactChainLimit = verbose ? 20 : 10;
1342 int chainCount = 0;
1343 loadedLibraries.forEachImportChain(DART_MIRRORS,
1344 callback: (Link<Uri> importChainReversed) {
1345 Link<CodeLocation> compactImportChain = const Link<CodeLocation>();
1346 CodeLocation currentCodeLocation =
1347 new UriLocation(importChainReversed.head);
1348 compactImportChain = compactImportChain.prepend(currentCodeLocation);
1349 for (Link<Uri> link = importChainReversed.tail;
1350 !link.isEmpty;
1351 link = link.tail) {
1352 Uri uri = link.head;
1353 if (!currentCodeLocation.inSameLocation(uri)) {
1354 currentCodeLocation =
1355 verbose ? new UriLocation(uri) : new CodeLocation(uri);
1356 compactImportChain =
1357 compactImportChain.prepend(currentCodeLocation);
1358 }
1359 }
1360 String importChain =
1361 compactImportChain.map((CodeLocation codeLocation) {
1362 return codeLocation.relativize(rootUri);
1363 }).join(' => ');
1364
1365 if (!importChains.contains(importChain)) {
1366 if (importChains.length > compactChainLimit) {
1367 importChains.add('...');
1368 return false;
1369 } else {
1370 importChains.add(importChain);
1371 }
1372 }
1373
1374 chainCount++;
1375 if (chainCount > chainLimit) {
1376 // Assume there are more import chains.
1377 importChains.add('...');
1378 return false;
1379 }
1380 return true;
1381 });
1382
1383 if (!backend.supportsReflection) {
1384 reportError(NO_LOCATION_SPANNABLE,
1385 MessageKind.MIRRORS_LIBRARY_NOT_SUPPORT_BY_BACKEND);
1386 } else {
1387 reportWarning(NO_LOCATION_SPANNABLE,
1388 MessageKind.IMPORT_EXPERIMENTAL_MIRRORS,
1389 {'importChain': importChains.join(
1390 MessageTemplate.IMPORT_EXPERIMENTAL_MIRRORS_PADDING)});
1391 }
1392 }
1393
1394 functionClass.ensureResolved(this);
1395 functionApplyMethod = functionClass.lookupLocalMember('apply');
1396
1397 proxyConstant =
1398 constants.getConstantValue(
1399 resolver.constantCompiler.compileConstant(
1400 coreLibrary.find('proxy')));
1401
1402 if (preserveComments) {
1403 return libraryLoader.loadLibrary(DART_MIRRORS)
1404 .then((LibraryElement libraryElement) {
1405 documentClass = libraryElement.find('Comment');
1406 });
1407 }
1408 }).then((_) => backend.onLibrariesLoaded(loadedLibraries));
1409 }
1410
1411 Element findRequiredElement(LibraryElement library, String name) {
1412 var element = library.find(name);
1413 if (element == null) {
1414 internalError(library,
1415 "The library '${library.canonicalUri}' does not contain required "
1416 "element: '$name'.");
1417 }
1418 return element;
1419 }
1420
1421 // TODO(johnniwinther): Move this to [PatchParser] when it is moved to the
1422 // [JavaScriptBackend]. Currently needed for testing.
1423 String get patchVersion => backend.patchVersion;
1424
1425 void onClassResolved(ClassElement cls) {
1426 if (mirrorSystemClass == cls) {
1427 mirrorSystemGetNameFunction =
1428 cls.lookupLocalMember('getName');
1429 } else if (symbolClass == cls) {
1430 symbolConstructor = cls.constructors.head;
1431 } else if (symbolImplementationClass == cls) {
1432 symbolValidatedConstructor = symbolImplementationClass.lookupConstructor(
1433 symbolValidatedConstructorSelector.name);
1434 } else if (mirrorsUsedClass == cls) {
1435 mirrorsUsedConstructor = cls.constructors.head;
1436 } else if (intClass == cls) {
1437 intEnvironment = intClass.lookupConstructor(FROM_ENVIRONMENT);
1438 } else if (stringClass == cls) {
1439 stringEnvironment =
1440 stringClass.lookupConstructor(FROM_ENVIRONMENT);
1441 } else if (boolClass == cls) {
1442 boolEnvironment =
1443 boolClass.lookupConstructor(FROM_ENVIRONMENT);
1444 }
1445 }
1446
1447 void initializeCoreClasses() {
1448 final List missingCoreClasses = [];
1449 ClassElement lookupCoreClass(String name) {
1450 ClassElement result = coreLibrary.find(name);
1451 if (result == null) {
1452 missingCoreClasses.add(name);
1453 }
1454 return result;
1455 }
1456 _coreTypes.objectClass = lookupCoreClass('Object');
1457 _coreTypes.boolClass = lookupCoreClass('bool');
1458 _coreTypes.numClass = lookupCoreClass('num');
1459 _coreTypes.intClass = lookupCoreClass('int');
1460 _coreTypes.doubleClass = lookupCoreClass('double');
1461 _coreTypes.stringClass = lookupCoreClass('String');
1462 _coreTypes.functionClass = lookupCoreClass('Function');
1463 _coreTypes.listClass = lookupCoreClass('List');
1464 _coreTypes.typeClass = lookupCoreClass('Type');
1465 _coreTypes.mapClass = lookupCoreClass('Map');
1466 _coreTypes.nullClass = lookupCoreClass('Null');
1467 _coreTypes.stackTraceClass = lookupCoreClass('StackTrace');
1468 _coreTypes.iterableClass = lookupCoreClass('Iterable');
1469 _coreTypes.symbolClass = lookupCoreClass('Symbol');
1470 if (!missingCoreClasses.isEmpty) {
1471 internalError(
1472 coreLibrary,
1473 'dart:core library does not contain required classes: '
1474 '$missingCoreClasses');
1475 }
1476 }
1477
1478 Element _unnamedListConstructor;
1479 Element get unnamedListConstructor {
1480 if (_unnamedListConstructor != null) return _unnamedListConstructor;
1481 return _unnamedListConstructor = listClass.lookupDefaultConstructor();
1482 }
1483
1484 Element _filledListConstructor;
1485 Element get filledListConstructor {
1486 if (_filledListConstructor != null) return _filledListConstructor;
1487 return _filledListConstructor = listClass.lookupConstructor("filled");
1488 }
1489
1490 /**
1491 * Get an [Uri] pointing to a patch for the dart: library with
1492 * the given path. Returns null if there is no patch.
1493 */
1494 Uri resolvePatchUri(String dartLibraryPath);
1495
1496 Future runCompiler(Uri uri) {
1497 // TODO(ahe): This prevents memory leaks when invoking the compiler
1498 // multiple times. Implement a better mechanism where we can store
1499 // such caches in the compiler and get access to them through a
1500 // suitably maintained static reference to the current compiler.
1501 StringToken.canonicalizedSubstrings.clear();
1502 Selector.canonicalizedValues.clear();
1503
1504 assert(uri != null || analyzeOnly || hasIncrementalSupport);
1505 return new Future.sync(() {
1506 if (librariesToAnalyzeWhenRun != null) {
1507 return Future.forEach(librariesToAnalyzeWhenRun, (libraryUri) {
1508 log('Analyzing $libraryUri ($buildId)');
1509 return libraryLoader.loadLibrary(libraryUri);
1510 });
1511 }
1512 }).then((_) {
1513 if (uri != null) {
1514 if (analyzeOnly) {
1515 log('Analyzing $uri ($buildId)');
1516 } else {
1517 log('Compiling $uri ($buildId)');
1518 }
1519 return libraryLoader.loadLibrary(uri).then((LibraryElement library) {
1520 mainApp = library;
1521 });
1522 }
1523 }).then((_) {
1524 compileLoadedLibraries();
1525 });
1526 }
1527
1528 void computeMain() {
1529 if (mainApp == null) return;
1530
1531 Element main = mainApp.findExported(MAIN);
1532 ErroneousElement errorElement = null;
1533 if (main == null) {
1534 if (analyzeOnly) {
1535 if (!analyzeAll) {
1536 errorElement = new ErroneousElementX(
1537 MessageKind.CONSIDER_ANALYZE_ALL, {'main': MAIN}, MAIN, mainApp);
1538 }
1539 } else {
1540 // Compilation requires a main method.
1541 errorElement = new ErroneousElementX(
1542 MessageKind.MISSING_MAIN, {'main': MAIN}, MAIN, mainApp);
1543 }
1544 mainFunction = backend.helperForMissingMain();
1545 } else if (main.isErroneous && main.isSynthesized) {
1546 if (main is ErroneousElement) {
1547 errorElement = main;
1548 } else {
1549 internalError(main, 'Problem with $MAIN.');
1550 }
1551 mainFunction = backend.helperForBadMain();
1552 } else if (!main.isFunction) {
1553 errorElement = new ErroneousElementX(
1554 MessageKind.MAIN_NOT_A_FUNCTION, {'main': MAIN}, MAIN, main);
1555 mainFunction = backend.helperForBadMain();
1556 } else {
1557 mainFunction = main;
1558 mainFunction.computeType(this);
1559 FunctionSignature parameters = mainFunction.functionSignature;
1560 if (parameters.requiredParameterCount > 2) {
1561 int index = 0;
1562 parameters.orderedForEachParameter((Element parameter) {
1563 if (index++ < 2) return;
1564 errorElement = new ErroneousElementX(
1565 MessageKind.MAIN_WITH_EXTRA_PARAMETER, {'main': MAIN}, MAIN,
1566 parameter);
1567 mainFunction = backend.helperForMainArity();
1568 // Don't warn about main not being used:
1569 enqueuer.resolution.registerStaticUse(main);
1570 });
1571 }
1572 }
1573 if (mainFunction == null) {
1574 if (errorElement == null && !analyzeOnly && !analyzeAll) {
1575 internalError(mainApp, "Problem with '$MAIN'.");
1576 } else {
1577 mainFunction = errorElement;
1578 }
1579 }
1580 if (errorElement != null &&
1581 errorElement.isSynthesized &&
1582 !mainApp.isSynthesized) {
1583 reportWarning(
1584 errorElement, errorElement.messageKind,
1585 errorElement.messageArguments);
1586 }
1587 }
1588
1589 /// Performs the compilation when all libraries have been loaded.
1590 void compileLoadedLibraries() {
1591 computeMain();
1592
1593 mirrorUsageAnalyzerTask.analyzeUsage(mainApp);
1594
1595 // In order to see if a library is deferred, we must compute the
1596 // compile-time constants that are metadata. This means adding
1597 // something to the resolution queue. So we cannot wait with
1598 // this until after the resolution queue is processed.
1599 deferredLoadTask.beforeResolution(this);
1600
1601 phase = PHASE_RESOLVING;
1602 if (analyzeAll) {
1603 libraryLoader.libraries.forEach((LibraryElement library) {
1604 log('Enqueuing ${library.canonicalUri}');
1605 fullyEnqueueLibrary(library, enqueuer.resolution);
1606 });
1607 } else if (analyzeMain && mainApp != null) {
1608 fullyEnqueueLibrary(mainApp, enqueuer.resolution);
1609 }
1610 // Elements required by enqueueHelpers are global dependencies
1611 // that are not pulled in by a particular element.
1612 backend.enqueueHelpers(enqueuer.resolution, globalDependencies);
1613 resolveLibraryMetadata();
1614 log('Resolving...');
1615 processQueue(enqueuer.resolution, mainFunction);
1616 enqueuer.resolution.logSummary(log);
1617
1618 if (!showPackageWarnings && !suppressWarnings) {
1619 suppressedWarnings.forEach((Uri uri, SuppressionInfo info) {
1620 MessageKind kind = MessageKind.HIDDEN_WARNINGS_HINTS;
1621 if (info.warnings == 0) {
1622 kind = MessageKind.HIDDEN_HINTS;
1623 } else if (info.hints == 0) {
1624 kind = MessageKind.HIDDEN_WARNINGS;
1625 }
1626 MessageTemplate template = MessageTemplate.TEMPLATES[kind];
1627 reportDiagnostic(null,
1628 template.message(
1629 {'warnings': info.warnings,
1630 'hints': info.hints,
1631 'uri': uri},
1632 terseDiagnostics),
1633 api.Diagnostic.HINT);
1634 });
1635 }
1636
1637 if (compilationFailed){
1638 if (!generateCodeWithCompileTimeErrors) return;
1639 if (!backend.enableCodegenWithErrorsIfSupported(NO_LOCATION_SPANNABLE)) {
1640 return;
1641 }
1642 }
1643
1644 if (analyzeOnly) {
1645 if (!analyzeAll && !compilationFailed) {
1646 // No point in reporting unused code when [analyzeAll] is true: all
1647 // code is artificially used.
1648 // If compilation failed, it is possible that the error prevents the
1649 // compiler from analyzing all the code.
1650 reportUnusedCode();
1651 }
1652 return;
1653 }
1654 assert(mainFunction != null);
1655 phase = PHASE_DONE_RESOLVING;
1656
1657 world.populate();
1658 // Compute whole-program-knowledge that the backend needs. (This might
1659 // require the information computed in [world.populate].)
1660 backend.onResolutionComplete();
1661
1662 deferredLoadTask.onResolutionComplete(mainFunction);
1663
1664 log('Inferring types...');
1665 typesTask.onResolutionComplete(mainFunction);
1666
1667 if (stopAfterTypeInference) return;
1668
1669 backend.onTypeInferenceComplete();
1670
1671 log('Compiling...');
1672 phase = PHASE_COMPILING;
1673 // TODO(johnniwinther): Move these to [CodegenEnqueuer].
1674 if (hasIsolateSupport) {
1675 backend.enableIsolateSupport(enqueuer.codegen);
1676 }
1677 if (compileAll) {
1678 libraryLoader.libraries.forEach((LibraryElement library) {
1679 fullyEnqueueLibrary(library, enqueuer.codegen);
1680 });
1681 }
1682 processQueue(enqueuer.codegen, mainFunction);
1683 enqueuer.codegen.logSummary(log);
1684
1685 int programSize = backend.assembleProgram();
1686
1687 if (dumpInfo) {
1688 dumpInfoTask.reportSize(programSize);
1689 dumpInfoTask.dumpInfo();
1690 }
1691
1692 checkQueues();
1693 }
1694
1695 void fullyEnqueueLibrary(LibraryElement library, Enqueuer world) {
1696 void enqueueAll(Element element) {
1697 fullyEnqueueTopLevelElement(element, world);
1698 }
1699 library.implementation.forEachLocalMember(enqueueAll);
1700 }
1701
1702 void fullyEnqueueTopLevelElement(Element element, Enqueuer world) {
1703 if (element.isClass) {
1704 ClassElement cls = element;
1705 cls.ensureResolved(this);
1706 cls.forEachLocalMember(enqueuer.resolution.addToWorkList);
1707 world.registerInstantiatedType(cls.rawType, globalDependencies);
1708 } else {
1709 world.addToWorkList(element);
1710 }
1711 }
1712
1713 // Resolves metadata on library elements. This is necessary in order to
1714 // resolve metadata classes referenced only from metadata on library tags.
1715 // TODO(ahe): Figure out how to do this lazily.
1716 void resolveLibraryMetadata() {
1717 for (LibraryElement library in libraryLoader.libraries) {
1718 if (library.metadata != null) {
1719 for (MetadataAnnotation metadata in library.metadata) {
1720 metadata.ensureResolved(this);
1721 }
1722 }
1723 }
1724 }
1725
1726 void processQueue(Enqueuer world, Element main) {
1727 world.nativeEnqueuer.processNativeClasses(libraryLoader.libraries);
1728 if (main != null && !main.isErroneous) {
1729 FunctionElement mainMethod = main;
1730 mainMethod.computeType(this);
1731 if (mainMethod.functionSignature.parameterCount != 0) {
1732 // The first argument could be a list of strings.
1733 backend.listImplementation.ensureResolved(this);
1734 world.registerInstantiatedType(
1735 backend.listImplementation.rawType, globalDependencies);
1736 backend.stringImplementation.ensureResolved(this);
1737 world.registerInstantiatedType(
1738 backend.stringImplementation.rawType, globalDependencies);
1739
1740 backend.registerMainHasArguments(world);
1741 }
1742 world.addToWorkList(main);
1743 }
1744 if (verbose) {
1745 progress.reset();
1746 }
1747 world.forEach((WorkItem work) {
1748 withCurrentElement(work.element, () {
1749 world.applyImpact(work.element, work.run(this, world));
1750 });
1751 });
1752 world.queueIsClosed = true;
1753 assert(compilationFailed || world.checkNoEnqueuedInvokedInstanceMethods());
1754 }
1755
1756 /**
1757 * Perform various checks of the queues. This includes checking that
1758 * the queues are empty (nothing was added after we stopped
1759 * processing the queues). Also compute the number of methods that
1760 * were resolved, but not compiled (aka excess resolution).
1761 */
1762 checkQueues() {
1763 for (Enqueuer world in [enqueuer.resolution, enqueuer.codegen]) {
1764 world.forEach((WorkItem work) {
1765 internalError(work.element, "Work list is not empty.");
1766 });
1767 }
1768 if (!REPORT_EXCESS_RESOLUTION) return;
1769 var resolved = new Set.from(enqueuer.resolution.resolvedElements);
1770 for (Element e in enqueuer.codegen.generatedCode.keys) {
1771 resolved.remove(e);
1772 }
1773 for (Element e in new Set.from(resolved)) {
1774 if (e.isClass ||
1775 e.isField ||
1776 e.isTypeVariable ||
1777 e.isTypedef ||
1778 identical(e.kind, ElementKind.ABSTRACT_FIELD)) {
1779 resolved.remove(e);
1780 }
1781 if (identical(e.kind, ElementKind.GENERATIVE_CONSTRUCTOR)) {
1782 resolved.remove(e);
1783 }
1784 if (backend.isBackendLibrary(e.library)) {
1785 resolved.remove(e);
1786 }
1787 }
1788 log('Excess resolution work: ${resolved.length}.');
1789 for (Element e in resolved) {
1790 reportWarning(e,
1791 MessageKind.GENERIC,
1792 {'text': 'Warning: $e resolved but not compiled.'});
1793 }
1794 }
1795
1796 WorldImpact analyzeElement(Element element) {
1797 assert(invariant(element,
1798 element.impliesType ||
1799 element.isField ||
1800 element.isFunction ||
1801 element.isGenerativeConstructor ||
1802 element.isGetter ||
1803 element.isSetter,
1804 message: 'Unexpected element kind: ${element.kind}'));
1805 assert(invariant(element, element is AnalyzableElement,
1806 message: 'Element $element is not analyzable.'));
1807 assert(invariant(element, element.isDeclaration));
1808 ResolutionEnqueuer world = enqueuer.resolution;
1809 if (world.hasBeenResolved(element)) {
1810 return const WorldImpact();
1811 }
1812 assert(parser != null);
1813 Node tree = parser.parse(element);
1814 assert(invariant(element, !element.isSynthesized || tree == null));
1815 WorldImpact worldImpact = resolver.resolve(element);
1816 if (tree != null && !analyzeSignaturesOnly && !suppressWarnings) {
1817 // Only analyze nodes with a corresponding [TreeElements].
1818 checker.check(element);
1819 }
1820 world.registerResolvedElement(element);
1821 return worldImpact;
1822 }
1823
1824 WorldImpact analyze(ResolutionWorkItem work, ResolutionEnqueuer world) {
1825 assert(invariant(work.element, identical(world, enqueuer.resolution)));
1826 assert(invariant(work.element, !work.isAnalyzed,
1827 message: 'Element ${work.element} has already been analyzed'));
1828 if (shouldPrintProgress) {
1829 // TODO(ahe): Add structured diagnostics to the compiler API and
1830 // use it to separate this from the --verbose option.
1831 if (phase == PHASE_RESOLVING) {
1832 log('Resolved ${enqueuer.resolution.resolvedElements.length} '
1833 'elements.');
1834 progress.reset();
1835 }
1836 }
1837 AstElement element = work.element;
1838 if (world.hasBeenResolved(element)) {
1839 return const WorldImpact();
1840 }
1841 WorldImpact worldImpact = analyzeElement(element);
1842 backend.onElementResolved(element, element.resolvedAst.elements);
1843 return worldImpact;
1844 }
1845
1846 WorldImpact codegen(CodegenWorkItem work, CodegenEnqueuer world) {
1847 assert(invariant(work.element, identical(world, enqueuer.codegen)));
1848 if (shouldPrintProgress) {
1849 // TODO(ahe): Add structured diagnostics to the compiler API and
1850 // use it to separate this from the --verbose option.
1851 log('Compiled ${enqueuer.codegen.generatedCode.length} methods.');
1852 progress.reset();
1853 }
1854 return backend.codegen(work);
1855 }
1856
1857 void reportError(Spannable node,
1858 MessageKind messageKind,
1859 [Map arguments = const {}]) {
1860 reportDiagnosticInternal(
1861 node, messageKind, arguments, api.Diagnostic.ERROR);
1862 }
1863
1864 void reportWarning(Spannable node, MessageKind messageKind,
1865 [Map arguments = const {}]) {
1866 reportDiagnosticInternal(
1867 node, messageKind, arguments, api.Diagnostic.WARNING);
1868 }
1869
1870 void reportInfo(Spannable node, MessageKind messageKind,
1871 [Map arguments = const {}]) {
1872 reportDiagnosticInternal(node, messageKind, arguments, api.Diagnostic.INFO);
1873 }
1874
1875 void reportHint(Spannable node, MessageKind messageKind,
1876 [Map arguments = const {}]) {
1877 reportDiagnosticInternal(node, messageKind, arguments, api.Diagnostic.HINT);
1878 }
1879
1880 void reportDiagnosticInternal(Spannable node,
1881 MessageKind messageKind,
1882 Map arguments,
1883 api.Diagnostic kind) {
1884 if (!showPackageWarnings && node != NO_LOCATION_SPANNABLE) {
1885 switch (kind) {
1886 case api.Diagnostic.WARNING:
1887 case api.Diagnostic.HINT:
1888 Element element = elementFromSpannable(node);
1889 if (!inUserCode(element, assumeInUserCode: true)) {
1890 Uri uri = getCanonicalUri(element);
1891 SuppressionInfo info =
1892 suppressedWarnings.putIfAbsent(uri, () => new SuppressionInfo());
1893 if (kind == api.Diagnostic.WARNING) {
1894 info.warnings++;
1895 } else {
1896 info.hints++;
1897 }
1898 lastDiagnosticWasFiltered = true;
1899 return;
1900 }
1901 break;
1902 case api.Diagnostic.INFO:
1903 if (lastDiagnosticWasFiltered) {
1904 return;
1905 }
1906 break;
1907 }
1908 }
1909 lastDiagnosticWasFiltered = false;
1910 MessageTemplate template = MessageTemplate.TEMPLATES[messageKind];
1911 reportDiagnostic(
1912 node,
1913 template.message(arguments, terseDiagnostics),
1914 kind);
1915 }
1916
1917 void reportDiagnostic(Spannable span,
1918 Message message,
1919 api.Diagnostic kind);
1920
1921 void reportAssertionFailure(SpannableAssertionFailure ex) {
1922 String message = (ex.message != null) ? tryToString(ex.message)
1923 : tryToString(ex);
1924 reportDiagnosticInternal(
1925 ex.node, MessageKind.GENERIC, {'text': message}, api.Diagnostic.CRASH);
1926 }
1927
1928 SourceSpan spanFromTokens(Token begin, Token end, [Uri uri]) {
1929 if (begin == null || end == null) {
1930 // TODO(ahe): We can almost always do better. Often it is only
1931 // end that is null. Otherwise, we probably know the current
1932 // URI.
1933 throw 'Cannot find tokens to produce error message.';
1934 }
1935 if (uri == null && currentElement != null) {
1936 uri = currentElement.compilationUnit.script.resourceUri;
1937 }
1938 return SourceSpan.withCharacterOffsets(begin, end,
1939 (beginOffset, endOffset) => new SourceSpan(uri, beginOffset, endOffset));
1940 }
1941
1942 SourceSpan spanFromNode(Node node) {
1943 return spanFromTokens(node.getBeginToken(), node.getEndToken());
1944 }
1945
1946 SourceSpan spanFromElement(Element element) {
1947 if (element != null && element.sourcePosition != null) {
1948 return element.sourcePosition;
1949 }
1950 while (element != null && element.isSynthesized) {
1951 element = element.enclosingElement;
1952 }
1953 if (element != null &&
1954 element.sourcePosition == null &&
1955 !element.isLibrary &&
1956 !element.isCompilationUnit) {
1957 // Sometimes, the backend fakes up elements that have no
1958 // position. So we use the enclosing element instead. It is
1959 // not a good error location, but cancel really is "internal
1960 // error" or "not implemented yet", so the vicinity is good
1961 // enough for now.
1962 element = element.enclosingElement;
1963 // TODO(ahe): I plan to overhaul this infrastructure anyways.
1964 }
1965 if (element == null) {
1966 element = currentElement;
1967 }
1968 if (element == null) {
1969 return null;
1970 }
1971
1972 if (element.sourcePosition != null) {
1973 return element.sourcePosition;
1974 }
1975 Token position = element.position;
1976 Uri uri = element.compilationUnit.script.resourceUri;
1977 return (position == null)
1978 ? new SourceSpan(uri, 0, 0)
1979 : spanFromTokens(position, position, uri);
1980 }
1981
1982 SourceSpan spanFromHInstruction(HInstruction instruction) {
1983 Element element = _elementFromHInstruction(instruction);
1984 if (element == null) element = currentElement;
1985 SourceInformation position = instruction.sourceInformation;
1986 if (position == null) return spanFromElement(element);
1987 return position.sourceSpan;
1988 }
1989
1990 /**
1991 * Translates the [resolvedUri] into a readable URI.
1992 *
1993 * The [importingLibrary] holds the library importing [resolvedUri] or
1994 * [:null:] if [resolvedUri] is loaded as the main library. The
1995 * [importingLibrary] is used to grant access to internal libraries from
1996 * platform libraries and patch libraries.
1997 *
1998 * If the [resolvedUri] is not accessible from [importingLibrary], this method
1999 * is responsible for reporting errors.
2000 *
2001 * See [LibraryLoader] for terminology on URIs.
2002 */
2003 Uri translateResolvedUri(LibraryElement importingLibrary,
2004 Uri resolvedUri, Node node) {
2005 unimplemented(importingLibrary, 'Compiler.translateResolvedUri');
2006 return null;
2007 }
2008
2009 /**
2010 * Reads the script specified by the [readableUri].
2011 *
2012 * See [LibraryLoader] for terminology on URIs.
2013 */
2014 Future<Script> readScript(Spannable node, Uri readableUri) {
2015 unimplemented(node, 'Compiler.readScript');
2016 return null;
2017 }
2018
2019 /// Compatible with [readScript] and used by [LibraryLoader] to create
2020 /// synthetic scripts to recover from read errors and bad URIs.
2021 Future<Script> synthesizeScript(Spannable node, Uri readableUri) {
2022 unimplemented(node, 'Compiler.synthesizeScript');
2023 return null;
2024 }
2025
2026 Element lookupElementIn(ScopeContainerElement container, String name) {
2027 Element element = container.localLookup(name);
2028 if (element == null) {
2029 throw 'Could not find $name in $container';
2030 }
2031 return element;
2032 }
2033
2034 bool get isMockCompilation => false;
2035
2036 Token processAndStripComments(Token currentToken) {
2037 Token firstToken = currentToken;
2038 Token prevToken;
2039 while (currentToken.kind != EOF_TOKEN) {
2040 if (identical(currentToken.kind, COMMENT_TOKEN)) {
2041 Token firstCommentToken = currentToken;
2042 while (identical(currentToken.kind, COMMENT_TOKEN)) {
2043 currentToken = currentToken.next;
2044 }
2045 commentMap[currentToken] = firstCommentToken;
2046 if (prevToken == null) {
2047 firstToken = currentToken;
2048 } else {
2049 prevToken.next = currentToken;
2050 }
2051 }
2052 prevToken = currentToken;
2053 currentToken = currentToken.next;
2054 }
2055 return firstToken;
2056 }
2057
2058 void reportUnusedCode() {
2059 void checkLive(member) {
2060 if (member.isErroneous) return;
2061 if (member.isFunction) {
2062 if (!enqueuer.resolution.hasBeenResolved(member)) {
2063 reportHint(member, MessageKind.UNUSED_METHOD,
2064 {'name': member.name});
2065 }
2066 } else if (member.isClass) {
2067 if (!member.isResolved) {
2068 reportHint(member, MessageKind.UNUSED_CLASS,
2069 {'name': member.name});
2070 } else {
2071 member.forEachLocalMember(checkLive);
2072 }
2073 } else if (member.isTypedef) {
2074 if (!member.isResolved) {
2075 reportHint(member, MessageKind.UNUSED_TYPEDEF,
2076 {'name': member.name});
2077 }
2078 }
2079 }
2080 libraryLoader.libraries.forEach((LibraryElement library) {
2081 // TODO(ahe): Implement better heuristics to discover entry points of
2082 // packages and use that to discover unused implementation details in
2083 // packages.
2084 if (library.isPlatformLibrary || library.isPackageLibrary) return;
2085 library.compilationUnits.forEach((unit) {
2086 unit.forEachLocalMember(checkLive);
2087 });
2088 });
2089 }
2090
2091 /// Helper for determining whether the current element is declared within
2092 /// 'user code'.
2093 ///
2094 /// See [inUserCode] for what defines 'user code'.
2095 bool currentlyInUserCode() {
2096 return inUserCode(currentElement);
2097 }
2098
2099 /// Helper for determining whether [element] is declared within 'user code'.
2100 ///
2101 /// What constitutes 'user code' is defined by the URI(s) provided by the
2102 /// entry point(s) of compilation or analysis:
2103 ///
2104 /// If an entrypoint URI uses the 'package' scheme then every library from
2105 /// that same package is considered to be in user code. For instance, if
2106 /// an entry point URI is 'package:foo/bar.dart' then every library whose
2107 /// canonical URI starts with 'package:foo/' is in user code.
2108 ///
2109 /// If an entrypoint URI uses another scheme than 'package' then every library
2110 /// with that scheme is in user code. For instance, an entry point URI is
2111 /// 'file:///foo.dart' then every library whose canonical URI scheme is
2112 /// 'file' is in user code.
2113 ///
2114 /// If [assumeInUserCode] is `true`, [element] is assumed to be in user code
2115 /// if no entrypoints have been set.
2116 bool inUserCode(Element element, {bool assumeInUserCode: false}) {
2117 if (element == null) return false;
2118 Iterable<CodeLocation> userCodeLocations =
2119 computeUserCodeLocations(assumeInUserCode: assumeInUserCode);
2120 Uri libraryUri = element.library.canonicalUri;
2121 return userCodeLocations.any(
2122 (CodeLocation codeLocation) => codeLocation.inSameLocation(libraryUri));
2123 }
2124
2125 Iterable<CodeLocation> computeUserCodeLocations(
2126 {bool assumeInUserCode: false}) {
2127 List<CodeLocation> userCodeLocations = <CodeLocation>[];
2128 if (mainApp != null) {
2129 userCodeLocations.add(new CodeLocation(mainApp.canonicalUri));
2130 }
2131 if (librariesToAnalyzeWhenRun != null) {
2132 userCodeLocations.addAll(librariesToAnalyzeWhenRun.map(
2133 (Uri uri) => new CodeLocation(uri)));
2134 }
2135 if (userCodeLocations.isEmpty && assumeInUserCode) {
2136 // Assume in user code since [mainApp] has not been set yet.
2137 userCodeLocations.add(const AnyLocation());
2138 }
2139 return userCodeLocations;
2140 }
2141
2142 /// Return a canonical URI for the source of [element].
2143 ///
2144 /// For a package library with canonical URI 'package:foo/bar/baz.dart' the
2145 /// return URI is 'package:foo'. For non-package libraries the returned URI is
2146 /// the canonical URI of the library itself.
2147 Uri getCanonicalUri(Element element) {
2148 if (element == null) return null;
2149 Uri libraryUri = element.library.canonicalUri;
2150 if (libraryUri.scheme == 'package') {
2151 int slashPos = libraryUri.path.indexOf('/');
2152 if (slashPos != -1) {
2153 String packageName = libraryUri.path.substring(0, slashPos);
2154 return new Uri(scheme: 'package', path: packageName);
2155 }
2156 }
2157 return libraryUri;
2158 }
2159
2160 void diagnoseCrashInUserCode(String message, exception, stackTrace) {
2161 // Overridden by Compiler in apiimpl.dart.
2162 }
2163
2164 void forgetElement(Element element) {
2165 enqueuer.forgetElement(element);
2166 if (element is MemberElement) {
2167 for (Element closure in element.nestedClosures) {
2168 // TODO(ahe): It would be nice to reuse names of nested closures.
2169 closureToClassMapper.forgetElement(closure);
2170 }
2171 }
2172 backend.forgetElement(element);
2173 }
2174
2175 bool elementHasCompileTimeError(Element element) {
2176 return elementsWithCompileTimeErrors.contains(element);
2177 }
2178
2179 EventSink<String> outputProvider(String name, String extension) {
2180 if (compilationFailed) {
2181 if (!generateCodeWithCompileTimeErrors || testMode) {
2182 // Disable output in test mode: The build bot currently uses the time
2183 // stamp of the generated file to determine whether the output is
2184 // up-to-date.
2185 return new NullSink('$name.$extension');
2186 }
2187 }
2188 return userOutputProvider.createEventSink(name, extension);
2189 }
2190 }
2191
2192 class CompilerTask {
2193 final Compiler compiler;
2194 final Stopwatch watch;
2195 UserTag profilerTag;
2196
2197 CompilerTask(Compiler compiler)
2198 : this.compiler = compiler,
2199 watch = (compiler.verbose) ? new Stopwatch() : null;
2200
2201 String get name => "Unknown task '${this.runtimeType}'";
2202 int get timing => (watch != null) ? watch.elapsedMilliseconds : 0;
2203
2204 int get timingMicroseconds => (watch != null) ? watch.elapsedMicroseconds : 0;
2205
2206 UserTag getProfilerTag() {
2207 if (profilerTag == null) profilerTag = new UserTag(name);
2208 return profilerTag;
2209 }
2210
2211 measure(action()) {
2212 // In verbose mode when watch != null.
2213 if (watch == null) return action();
2214 CompilerTask previous = compiler.measuredTask;
2215 if (identical(this, previous)) return action();
2216 compiler.measuredTask = this;
2217 if (previous != null) previous.watch.stop();
2218 watch.start();
2219 UserTag oldTag = getProfilerTag().makeCurrent();
2220 try {
2221 return action();
2222 } finally {
2223 watch.stop();
2224 oldTag.makeCurrent();
2225 if (previous != null) previous.watch.start();
2226 compiler.measuredTask = previous;
2227 }
2228 }
2229
2230 measureElement(Element element, action()) {
2231 compiler.withCurrentElement(element, () => measure(action));
2232 }
2233 }
2234
2235 class SourceSpan implements Spannable {
2236 final Uri uri;
2237 final int begin;
2238 final int end;
2239
2240 const SourceSpan(this.uri, this.begin, this.end);
2241
2242 static withCharacterOffsets(Token begin, Token end,
2243 f(int beginOffset, int endOffset)) {
2244 final beginOffset = begin.charOffset;
2245 final endOffset = end.charOffset + end.charCount;
2246
2247 // [begin] and [end] might be the same for the same empty token. This
2248 // happens for instance when scanning '$$'.
2249 assert(endOffset >= beginOffset);
2250 return f(beginOffset, endOffset);
2251 }
2252
2253 int get hashCode {
2254 return 13 * uri.hashCode +
2255 17 * begin.hashCode +
2256 19 * end.hashCode;
2257 }
2258
2259 bool operator ==(other) {
2260 if (identical(this, other)) return true;
2261 if (other is! SourceSpan) return false;
2262 return uri == other.uri &&
2263 begin == other.begin &&
2264 end == other.end;
2265 }
2266
2267 String toString() => 'SourceSpan($uri, $begin, $end)';
2268 }
2269
2270 /// Flag that can be used in assertions to assert that a code path is only
2271 /// executed as part of development.
2272 ///
2273 /// This flag is automatically set to true if helper methods like, [debugPrint],
2274 /// [debugWrapPrint], [trace], and [reportHere] are called.
2275 bool DEBUG_MODE = false;
2276
2277 /// Assert that [DEBUG_MODE] is `true` and provide [message] as part of the
2278 /// error message.
2279 assertDebugMode(String message) {
2280 assert(invariant(NO_LOCATION_SPANNABLE, DEBUG_MODE,
2281 message: 'Debug mode is not enabled: $message'));
2282 }
2283
2284 /**
2285 * Throws a [SpannableAssertionFailure] if [condition] is
2286 * [:false:]. [condition] must be either a [:bool:] or a no-arg
2287 * function returning a [:bool:].
2288 *
2289 * Use this method to provide better information for assertion by calling
2290 * [invariant] as the argument to an [:assert:] statement:
2291 *
2292 * assert(invariant(position, isValid));
2293 *
2294 * [spannable] must be non-null and will be used to provide positional
2295 * information in the generated error message.
2296 */
2297 bool invariant(Spannable spannable, var condition, {var message: null}) {
2298 // TODO(johnniwinther): Use [spannable] and [message] to provide better
2299 // information on assertion errors.
2300 if (spannable == null) {
2301 throw new SpannableAssertionFailure(CURRENT_ELEMENT_SPANNABLE,
2302 "Spannable was null for invariant. Use CURRENT_ELEMENT_SPANNABLE.");
2303 }
2304 if (condition is Function){
2305 condition = condition();
2306 }
2307 if (!condition) {
2308 if (message is Function) {
2309 message = message();
2310 }
2311 throw new SpannableAssertionFailure(spannable, message);
2312 }
2313 return true;
2314 }
2315
2316 /// Returns `true` when [s] is private if used as an identifier.
2317 bool isPrivateName(String s) => !s.isEmpty && s.codeUnitAt(0) == $_;
2318
2319 /// Returns `true` when [s] is public if used as an identifier.
2320 bool isPublicName(String s) => !isPrivateName(s);
2321
2322 /// Information about suppressed warnings and hints for a given library.
2323 class SuppressionInfo {
2324 int warnings = 0;
2325 int hints = 0;
2326 }
2327
2328 class GenericTask extends CompilerTask {
2329 final String name;
2330
2331 GenericTask(this.name, Compiler compiler)
2332 : super(compiler);
2333 }
2334
2335 /// [CodeLocation] divides uris into different classes.
2336 ///
2337 /// These are used to group uris from user code, platform libraries and
2338 /// packages.
2339 abstract class CodeLocation {
2340 /// Returns `true` if [uri] is in this code location.
2341 bool inSameLocation(Uri uri);
2342
2343 /// Returns the uri of this location relative to [baseUri].
2344 String relativize(Uri baseUri);
2345
2346 factory CodeLocation(Uri uri) {
2347 if (uri.scheme == 'package') {
2348 int slashPos = uri.path.indexOf('/');
2349 if (slashPos != -1) {
2350 String packageName = uri.path.substring(0, slashPos);
2351 return new PackageLocation(packageName);
2352 } else {
2353 return new UriLocation(uri);
2354 }
2355 } else {
2356 return new SchemeLocation(uri);
2357 }
2358 }
2359 }
2360
2361 /// A code location defined by the scheme of the uri.
2362 ///
2363 /// Used for non-package uris, such as 'dart', 'file', and 'http'.
2364 class SchemeLocation implements CodeLocation {
2365 final Uri uri;
2366
2367 SchemeLocation(this.uri);
2368
2369 bool inSameLocation(Uri uri) {
2370 return this.uri.scheme == uri.scheme;
2371 }
2372
2373 String relativize(Uri baseUri) {
2374 return uri_extras.relativize(baseUri, uri, false);
2375 }
2376 }
2377
2378 /// A code location defined by the package name.
2379 ///
2380 /// Used for package uris, separated by their `package names`, that is, the
2381 /// 'foo' of 'package:foo/bar.dart'.
2382 class PackageLocation implements CodeLocation {
2383 final String packageName;
2384
2385 PackageLocation(this.packageName);
2386
2387 bool inSameLocation(Uri uri) {
2388 return uri.scheme == 'package' && uri.path.startsWith('$packageName/');
2389 }
2390
2391 String relativize(Uri baseUri) => 'package:$packageName';
2392 }
2393
2394 /// A code location defined by the whole uri.
2395 ///
2396 /// Used for package uris with no package name. For instance 'package:foo.dart'.
2397 class UriLocation implements CodeLocation {
2398 final Uri uri;
2399
2400 UriLocation(this.uri);
2401
2402 bool inSameLocation(Uri uri) => this.uri == uri;
2403
2404 String relativize(Uri baseUri) {
2405 return uri_extras.relativize(baseUri, uri, false);
2406 }
2407 }
2408
2409 /// A code location that contains any uri.
2410 class AnyLocation implements CodeLocation {
2411 const AnyLocation();
2412
2413 bool inSameLocation(Uri uri) => true;
2414
2415 String relativize(Uri baseUri) => '$baseUri';
2416 }
2417
2418 class _CompilerCoreTypes implements CoreTypes {
2419 final Compiler compiler;
2420
2421 ClassElement objectClass;
2422 ClassElement boolClass;
2423 ClassElement numClass;
2424 ClassElement intClass;
2425 ClassElement doubleClass;
2426 ClassElement stringClass;
2427 ClassElement functionClass;
2428 ClassElement nullClass;
2429 ClassElement listClass;
2430 ClassElement typeClass;
2431 ClassElement mapClass;
2432 ClassElement symbolClass;
2433 ClassElement stackTraceClass;
2434 ClassElement futureClass;
2435 ClassElement iterableClass;
2436 ClassElement streamClass;
2437
2438 _CompilerCoreTypes(this.compiler);
2439
2440 @override
2441 InterfaceType get objectType => objectClass.computeType(compiler);
2442
2443 @override
2444 InterfaceType get boolType => boolClass.computeType(compiler);
2445
2446 @override
2447 InterfaceType get doubleType => doubleClass.computeType(compiler);
2448
2449 @override
2450 InterfaceType get functionType => functionClass.computeType(compiler);
2451
2452 @override
2453 InterfaceType get intType => intClass.computeType(compiler);
2454
2455 @override
2456 InterfaceType listType([DartType elementType]) {
2457 InterfaceType type = listClass.computeType(compiler);
2458 if (elementType == null) {
2459 return listClass.rawType;
2460 }
2461 return type.createInstantiation([elementType]);
2462 }
2463
2464 @override
2465 InterfaceType mapType([DartType keyType,
2466 DartType valueType]) {
2467 InterfaceType type = mapClass.computeType(compiler);
2468 if (keyType == null && valueType == null) {
2469 return mapClass.rawType;
2470 } else if (keyType == null) {
2471 keyType = const DynamicType();
2472 } else if (valueType == null) {
2473 valueType = const DynamicType();
2474 }
2475 return type.createInstantiation([keyType, valueType]);
2476 }
2477
2478 @override
2479 InterfaceType get nullType => nullClass.computeType(compiler);
2480
2481 @override
2482 InterfaceType get numType => numClass.computeType(compiler);
2483
2484 @override
2485 InterfaceType get stringType => stringClass.computeType(compiler);
2486
2487 @override
2488 InterfaceType get symbolType => symbolClass.computeType(compiler);
2489
2490 @override
2491 InterfaceType get typeType => typeClass.computeType(compiler);
2492
2493 @override
2494 InterfaceType iterableType([DartType elementType]) {
2495 InterfaceType type = iterableClass.computeType(compiler);
2496 if (elementType == null) {
2497 return iterableClass.rawType;
2498 }
2499 return type.createInstantiation([elementType]);
2500 }
2501
2502 @override
2503 InterfaceType futureType([DartType elementType]) {
2504 InterfaceType type = futureClass.computeType(compiler);
2505 if (elementType == null) {
2506 return futureClass.rawType;
2507 }
2508 return type.createInstantiation([elementType]);
2509 }
2510
2511 @override
2512 InterfaceType streamType([DartType elementType]) {
2513 InterfaceType type = streamClass.computeType(compiler);
2514 if (elementType == null) {
2515 return streamClass.rawType;
2516 }
2517 return type.createInstantiation([elementType]);
2518 }
2519 }
2520
2521 typedef void InternalErrorFunction(Spannable location, String message);
OLDNEW
« no previous file with comments | « pkg/compiler/lib/src/scanner/scannerlib.dart ('k') | pkg/compiler/lib/src/serialization/element_serialization.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698