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

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

Powered by Google App Engine
This is Rietveld 408576698