// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

library dart2js.compiler_base;

import 'dart:async' show Future;

import '../compiler_new.dart' as api;
import 'backend_strategy.dart';
import 'common/names.dart' show Selectors;
import 'common/names.dart' show Uris;
import 'common/resolution.dart'
    show
        ParsingContext,
        Resolution,
        ResolutionWorkItem,
        ResolutionImpact,
        Target;
import 'common/tasks.dart' show CompilerTask, GenericTask, Measurer;
import 'common/work.dart' show WorkItem;
import 'common.dart';
import 'compile_time_constants.dart';
import 'constants/values.dart';
import 'common_elements.dart' show CommonElements, ElementEnvironment;
import 'deferred_load.dart' show DeferredLoadTask, OutputUnitData;
import 'diagnostics/code_location.dart';
import 'diagnostics/diagnostic_listener.dart' show DiagnosticReporter;
import 'diagnostics/invariant.dart' show REPORT_EXCESS_RESOLUTION;
import 'diagnostics/messages.dart' show Message, MessageTemplate;
import 'dump_info.dart' show DumpInfoTask;
import 'elements/elements.dart';
import 'elements/entities.dart';
import 'elements/resolution_types.dart' show ResolutionDartType, Types;
import 'enqueue.dart' show Enqueuer, EnqueueTask, ResolutionEnqueuer;
import 'environment.dart';
import 'frontend_strategy.dart';
import 'id_generator.dart';
import 'io/source_information.dart' show SourceInformation;
import 'io/source_file.dart' show Binary;
import 'js_backend/backend.dart' show JavaScriptBackend;
import 'kernel/kernel_backend_strategy.dart';
import 'kernel/kernel_strategy.dart';
import 'library_loader.dart'
    show
        ElementScanner,
        LibraryLoader,
        LibraryLoaderTask,
        LoadedLibraries,
        ScriptLoader;
import 'mirrors_used.dart' show MirrorUsageAnalyzerTask;
import 'null_compiler_output.dart' show NullCompilerOutput, NullSink;
import 'options.dart' show CompilerOptions, DiagnosticOptions;
import 'parser/diet_parser_task.dart' show DietParserTask;
import 'parser/parser_task.dart' show ParserTask;
import 'patch_parser.dart' show PatchParserTask;
import 'resolution/resolution.dart' show ResolverTask;
import 'resolution/resolution_strategy.dart';
import 'resolved_uri_translator.dart';
import 'scanner/scanner_task.dart' show ScannerTask;
import 'script.dart' show Script;
import 'ssa/nodes.dart' show HInstruction;
import 'package:front_end/src/fasta/scanner.dart' show StringToken, Token;
import 'tree/tree.dart' show Node, TypeAnnotation;
import 'typechecker.dart' show TypeCheckerTask;
import 'types/types.dart' show GlobalTypeInferenceTask;
import 'universe/selector.dart' show Selector;
import 'universe/world_builder.dart'
    show ResolutionWorldBuilder, CodegenWorldBuilder;
import 'universe/use.dart' show StaticUse, TypeUse;
import 'universe/world_impact.dart'
    show ImpactStrategy, WorldImpact, WorldImpactBuilderImpl;
import 'util/util.dart' show Link;
import 'world.dart' show ClosedWorld, ClosedWorldRefiner;

typedef CompilerDiagnosticReporter MakeReporterFunction(
    Compiler compiler, CompilerOptions options);

abstract class Compiler {
  Measurer get measurer;

  api.CompilerInput get provider;

  final IdGenerator idGenerator = new IdGenerator();
  FrontendStrategy frontendStrategy;
  BackendStrategy backendStrategy;
  CompilerDiagnosticReporter _reporter;
  CompilerResolution _resolution;
  Map<Entity, WorldImpact> _impactCache;
  ImpactCacheDeleter _impactCacheDeleter;
  ParsingContext _parsingContext;

  ImpactStrategy impactStrategy = const ImpactStrategy();

  /// Options provided from command-line arguments.
  final CompilerOptions options;

  /**
   * If true, stop compilation after type inference is complete. Used for
   * debugging and testing purposes only.
   */
  bool stopAfterTypeInference = false;

  /// Output provider from user of Compiler API.
  api.CompilerOutput _outputProvider;

  api.CompilerOutput get outputProvider => _outputProvider;

  List<Uri> librariesToAnalyzeWhenRun;

  ResolvedUriTranslator get resolvedUriTranslator;

  Uri mainLibraryUri;

  ClosedWorld backendClosedWorldForTesting;

  DiagnosticReporter get reporter => _reporter;
  Resolution get resolution => _resolution;
  Map<Entity, WorldImpact> get impactCache => _impactCache;
  ImpactCacheDeleter get impactCacheDeleter => _impactCacheDeleter;
  ParsingContext get parsingContext => _parsingContext;

  // TODO(zarah): Remove this map and incorporate compile-time errors
  // in the model.
  /// Tracks elements with compile-time errors.
  final Map<Entity, List<DiagnosticMessage>> elementsWithCompileTimeErrors =
      new Map<Entity, List<DiagnosticMessage>>();

  final Environment environment;
  // TODO(sigmund): delete once we migrate the rest of the compiler to use
  // `environment` directly.
  @deprecated
  fromEnvironment(String name) => environment.valueOf(name);

  Entity get currentElement => _reporter.currentElement;

  List<CompilerTask> tasks;
  ScannerTask scanner;
  DietParserTask dietParser;
  ParserTask parser;
  PatchParserTask patchParser;
  LibraryLoaderTask libraryLoader;
  ResolverTask resolver;
  TypeCheckerTask checker;
  GlobalTypeInferenceTask globalInference;
  JavaScriptBackend backend;
  CodegenWorldBuilder _codegenWorldBuilder;

  GenericTask selfTask;

  /// The constant environment for the frontend interpretation of compile-time
  /// constants.
  ConstantEnvironment constants;

  EnqueueTask enqueuer;
  DeferredLoadTask deferredLoadTask;
  MirrorUsageAnalyzerTask mirrorUsageAnalyzerTask;
  DumpInfoTask dumpInfoTask;

  bool get hasCrashed => _reporter.hasCrashed;

  Progress progress = const Progress();

  static const int PHASE_SCANNING = 0;
  static const int PHASE_RESOLVING = 1;
  static const int PHASE_DONE_RESOLVING = 2;
  static const int PHASE_COMPILING = 3;
  int phase;

  bool compilationFailed = false;

  // Callback function used for testing resolution enqueuing.
  void Function() onResolutionQueueEmptyForTesting;

  // Callback function used for testing codegen enqueuing.
  void Function() onCodegenQueueEmptyForTesting;

  Compiler(
      {CompilerOptions options,
      api.CompilerOutput outputProvider,
      this.environment: const _EmptyEnvironment(),
      MakeReporterFunction makeReporter})
      : this.options = options {
    options.deriveOptions();
    options.validate();
    CompilerTask kernelFrontEndTask;
    selfTask = new GenericTask('self', measurer);
    _outputProvider = new _CompilerOutput(this, outputProvider);
    if (makeReporter != null) {
      _reporter = makeReporter(this, options);
    } else {
      _reporter = new CompilerDiagnosticReporter(this, options);
    }
    kernelFrontEndTask = new GenericTask('Front end', measurer);
    frontendStrategy = new KernelFrontEndStrategy(kernelFrontEndTask, options,
        reporter, environment, options.kernelInitializedCompilerState);
    backendStrategy = new KernelBackendStrategy(this);
    _impactCache = <Entity, WorldImpact>{};
    _impactCacheDeleter = new _MapImpactCacheDeleter(_impactCache);

    if (options.verbose) {
      progress = new ProgressImpl(_reporter);
    }

    backend = createBackend();
    enqueuer = backend.makeEnqueuer();

    tasks = [
      dietParser = new DietParserTask(idGenerator, backend, reporter, measurer),
      scanner = createScannerTask(),
      patchParser = new PatchParserTask(this),
      libraryLoader = frontendStrategy.createLibraryLoader(
          resolvedUriTranslator,
          new _ScriptLoader(this),
          provider,
          new _ElementScanner(scanner),
          resolvePatchUri,
          patchParser,
          environment,
          reporter,
          measurer),
      parser = new ParserTask(this),
      resolver = createResolverTask(),
      checker = new TypeCheckerTask(this),
      globalInference = new GlobalTypeInferenceTask(this),
      constants = backend.constantCompilerTask,
      deferredLoadTask = frontendStrategy.createDeferredLoadTask(this),
      mirrorUsageAnalyzerTask = new MirrorUsageAnalyzerTask(this),
      // [enqueuer] is created earlier because it contains the resolution world
      // objects needed by other tasks.
      enqueuer,
      dumpInfoTask = new DumpInfoTask(this),
      selfTask,
    ];
    tasks.add(kernelFrontEndTask);

    _parsingContext =
        new ParsingContext(reporter, parser, scanner, patchParser, backend);

    tasks.addAll(backend.tasks);
  }

  /// Creates the backend.
  ///
  /// Override this to mock the backend for testing.
  JavaScriptBackend createBackend() {
    return new JavaScriptBackend(this,
        generateSourceMap: options.generateSourceMap,
        useStartupEmitter: options.useStartupEmitter,
        useMultiSourceInfo: options.useMultiSourceInfo,
        useNewSourceInfo: options.useNewSourceInfo);
  }

  /// Creates the scanner task.
  ///
  /// Override this to mock the scanner for testing.
  ScannerTask createScannerTask() =>
      new ScannerTask(dietParser, reporter, measurer);

  /// Creates the resolution object.
  ///
  /// Override this to mock resolution for testing.
  Resolution createResolution() => new CompilerResolution(this);

  /// Creates the resolver task.
  ///
  /// Override this to mock the resolver for testing.
  ResolverTask createResolverTask() {
    return new ResolverTask(resolution, backend.constantCompilerTask, measurer);
  }

  ResolutionWorldBuilder get resolutionWorldBuilder =>
      enqueuer.resolution.worldBuilder;
  CodegenWorldBuilder get codegenWorldBuilder {
    assert(
        _codegenWorldBuilder != null,
        failedAt(NO_LOCATION_SPANNABLE,
            "CodegenWorldBuilder has not been created yet."));
    return _codegenWorldBuilder;
  }

  bool get analyzeAll => options.analyzeAll || compileAll;

  bool get compileAll => false;

  bool get disableTypeInference =>
      options.disableTypeInference || compilationFailed;

  // Compiles the dart script at [uri].
  //
  // The resulting future will complete with true if the compilation
  // succeeded.
  Future<bool> run(Uri uri) => selfTask.measureSubtask("Compiler.run", () {
        measurer.startWallClock();

        return new Future.sync(() => runInternal(uri))
            .catchError((error) => _reporter.onError(uri, error))
            .whenComplete(() {
          measurer.stopWallClock();
        }).then((_) {
          return !compilationFailed;
        });
      });

  /// Compute the set of distinct import chains to the library at [uri] within
  /// [loadedLibraries].
  ///
  /// The chains are strings of the form
  ///
  ///       <main-uri> => <intermediate-uri1> => <intermediate-uri2> => <uri>
  ///
  Set<String> computeImportChainsFor(LoadedLibraries loadedLibraries, Uri uri) {
    // TODO(johnniwinther): Move computation of dependencies to the library
    // loader.
    Set<String> importChains = new Set<String>();
    // The maximum number of full imports chains to process.
    final int chainLimit = 10000;
    // The maximum number of imports chains to show.
    final int compactChainLimit = options.verbose ? 20 : 10;
    int chainCount = 0;
    loadedLibraries.forEachImportChain(uri,
        callback: (Link<Uri> importChainReversed) {
      Link<CodeLocation> compactImportChain = const Link<CodeLocation>();
      CodeLocation currentCodeLocation =
          new UriLocation(importChainReversed.head);
      compactImportChain = compactImportChain.prepend(currentCodeLocation);
      for (Link<Uri> link = importChainReversed.tail;
          !link.isEmpty;
          link = link.tail) {
        Uri uri = link.head;
        if (!currentCodeLocation.inSameLocation(uri)) {
          currentCodeLocation =
              options.verbose ? new UriLocation(uri) : new CodeLocation(uri);
          compactImportChain = compactImportChain.prepend(currentCodeLocation);
        }
      }
      String importChain = compactImportChain.map((CodeLocation codeLocation) {
        return codeLocation.relativize(
            (loadedLibraries.rootLibrary as LibraryElement).canonicalUri);
      }).join(' => ');

      if (!importChains.contains(importChain)) {
        if (importChains.length > compactChainLimit) {
          importChains.add('...');
          return false;
        } else {
          importChains.add(importChain);
        }
      }

      chainCount++;
      if (chainCount > chainLimit) {
        // Assume there are more import chains.
        importChains.add('...');
        return false;
      }
      return true;
    });
    return importChains;
  }

  /// This method is called when all new libraries loaded through
  /// [LibraryLoader.loadLibrary] has been loaded and their imports/exports
  /// have been computed.
  ///
  /// [loadedLibraries] contains the newly loaded libraries.
  ///
  /// The method returns a [Future] allowing for the loading of additional
  /// libraries.
  LoadedLibraries processLoadedLibraries(LoadedLibraries loadedLibraries) {
    loadedLibraries.forEachLibrary((LibraryEntity library) {
      backend.setAnnotations(library);
    });

    // TODO(efortuna, sigmund): These validation steps should be done in the
    // front end for the Kernel path since Kernel doesn't have the notion of
    // imports (everything has already been resolved). (See
    // https://github.com/dart-lang/sdk/issues/29368)
    if (loadedLibraries.containsLibrary(Uris.dart_mirrors)) {
      reporter.reportWarningMessage(NO_LOCATION_SPANNABLE,
          MessageKind.MIRRORS_LIBRARY_NOT_SUPPORT_WITH_CFE);
    }
    backend.onLibrariesLoaded(frontendStrategy.commonElements, loadedLibraries);
    return loadedLibraries;
  }

  /**
   * Get an [Uri] pointing to a patch for the dart: library with
   * the given path. Returns null if there is no patch.
   */
  Uri resolvePatchUri(String dartLibraryPath);

  Future runInternal(Uri uri) async {
    mainLibraryUri = uri;
    // TODO(ahe): This prevents memory leaks when invoking the compiler
    // multiple times. Implement a better mechanism where we can store
    // such caches in the compiler and get access to them through a
    // suitably maintained static reference to the current compiler.
    StringToken.canonicalizer.clear();
    Selector.canonicalizedValues.clear();

    // The selector objects held in static fields must remain canonical.
    for (Selector selector in Selectors.ALL) {
      Selector.canonicalizedValues
          .putIfAbsent(selector.hashCode, () => <Selector>[])
          .add(selector);
    }

    assert(uri != null || options.analyzeOnly);
    // As far as I can tell, this branch is only used by test code.
    if (librariesToAnalyzeWhenRun != null) {
      await Future.forEach(librariesToAnalyzeWhenRun, (libraryUri) async {
        reporter.log('Analyzing $libraryUri (${options.buildId})');
        LoadedLibraries loadedLibraries =
            await libraryLoader.loadLibrary(libraryUri);
        processLoadedLibraries(loadedLibraries);
      });
    }
    LibraryEntity mainApp;
    if (uri != null) {
      if (options.analyzeOnly) {
        reporter.log('Analyzing $uri (${options.buildId})');
      } else {
        reporter.log('Compiling $uri (${options.buildId})');
      }
      LoadedLibraries libraries = await libraryLoader.loadLibrary(uri);
      // Note: libraries may be null because of errors trying to find files or
      // parse-time errors (when using `package:front_end` as a loader).
      if (libraries == null) return;
      processLoadedLibraries(libraries);
      mainApp = libraries.rootLibrary;
    }
    compileLoadedLibraries(mainApp);
  }

  /// Analyze all members of the library in [libraryUri].
  ///
  /// If [skipLibraryWithPartOfTag] is `true`, member analysis is skipped if the
  /// library has a `part of` tag, assuming it is a part and not a library.
  ///
  /// This operation assumes an unclosed resolution queue and is only supported
  /// when the '--analyze-main' option is used.
  Future<LibraryElement> analyzeUri(Uri libraryUri,
      {bool skipLibraryWithPartOfTag: true}) async {
    phase = PHASE_RESOLVING;
    assert(options.analyzeMain);
    reporter.log('Analyzing $libraryUri (${options.buildId})');
    LoadedLibraries loadedLibraries = await libraryLoader
        .loadLibrary(libraryUri, skipFileWithPartOfTag: true);
    if (loadedLibraries == null) return null;
    processLoadedLibraries(loadedLibraries);
    LibraryElement library = loadedLibraries.rootLibrary;
    ResolutionEnqueuer resolutionEnqueuer = startResolution();
    resolutionEnqueuer.applyImpact(computeImpactForLibrary(library));
    emptyQueue(resolutionEnqueuer, onProgress: showResolutionProgress);
    resolutionEnqueuer.logSummary(reporter.log);
    return library;
  }

  /// Starts the resolution phase, creating the [ResolutionEnqueuer] if not
  /// already created.
  ///
  /// During normal compilation resolution only started once, but through
  /// [analyzeUri] resolution is started repeatedly.
  ResolutionEnqueuer startResolution() {
    ResolutionEnqueuer resolutionEnqueuer;
    if (enqueuer.hasResolution) {
      resolutionEnqueuer = enqueuer.resolution;
    } else {
      resolutionEnqueuer = enqueuer.createResolutionEnqueuer();
      backend.onResolutionStart();
    }
    resolutionEnqueuer.addDeferredActions(libraryLoader.pullDeferredActions());
    return resolutionEnqueuer;
  }

  /// Performs the compilation when all libraries have been loaded.
  void compileLoadedLibraries(LibraryEntity rootLibrary) =>
      selfTask.measureSubtask("Compiler.compileLoadedLibraries", () {
        ResolutionEnqueuer resolutionEnqueuer = startResolution();
        WorldImpactBuilderImpl mainImpact = new WorldImpactBuilderImpl();
        FunctionEntity mainFunction =
            frontendStrategy.computeMain(rootLibrary, mainImpact);

        // In order to see if a library is deferred, we must compute the
        // compile-time constants that are metadata.  This means adding
        // something to the resolution queue.  So we cannot wait with
        // this until after the resolution queue is processed.
        deferredLoadTask.beforeResolution(rootLibrary);
        impactStrategy = backend.createImpactStrategy(
            supportDeferredLoad: deferredLoadTask.isProgramSplit,
            supportDumpInfo: options.dumpInfo);

        phase = PHASE_RESOLVING;
        resolutionEnqueuer.applyImpact(mainImpact);
        if (analyzeAll) {
          libraryLoader.libraries.forEach((LibraryEntity library) {
            reporter.log('Enqueuing ${library.canonicalUri}');
            resolutionEnqueuer.applyImpact(computeImpactForLibrary(library));
          });
        } else if (options.analyzeMain) {
          if (rootLibrary != null) {
            resolutionEnqueuer
                .applyImpact(computeImpactForLibrary(rootLibrary));
          }
          if (librariesToAnalyzeWhenRun != null) {
            for (Uri libraryUri in librariesToAnalyzeWhenRun) {
              resolutionEnqueuer.applyImpact(computeImpactForLibrary(
                  libraryLoader.lookupLibrary(libraryUri)));
            }
          }
        }
        reporter.log('Resolving...');

        processQueue(frontendStrategy.elementEnvironment, resolutionEnqueuer,
            mainFunction, libraryLoader.libraries,
            onProgress: showResolutionProgress);
        backend.onResolutionEnd();
        resolutionEnqueuer.logSummary(reporter.log);

        _reporter.reportSuppressedMessagesSummary();

        if (compilationFailed) {
          if (!options.generateCodeWithCompileTimeErrors) {
            return;
          }
          if (mainFunction == null) return;
          if (!backend
              .enableCodegenWithErrorsIfSupported(NO_LOCATION_SPANNABLE)) {
            return;
          }
        }

        if (options.analyzeOnly) return;
        assert(mainFunction != null);

        ClosedWorldRefiner closedWorldRefiner = closeResolution(mainFunction);
        ClosedWorld closedWorld = closedWorldRefiner.closedWorld;
        backendClosedWorldForTesting = closedWorld;
        mainFunction = closedWorld.elementEnvironment.mainFunction;

        reporter.log('Inferring types...');
        globalInference.runGlobalTypeInference(
            mainFunction, closedWorld, closedWorldRefiner);
        closedWorldRefiner.computeSideEffects();

        if (stopAfterTypeInference) return;

        reporter.log('Compiling...');
        phase = PHASE_COMPILING;

        Enqueuer codegenEnqueuer = startCodegen(closedWorld);
        if (compileAll) {
          libraryLoader.libraries.forEach((LibraryEntity library) {
            codegenEnqueuer.applyImpact(computeImpactForLibrary(library));
          });
        }
        processQueue(closedWorld.elementEnvironment, codegenEnqueuer,
            mainFunction, libraryLoader.libraries,
            onProgress: showCodegenProgress);
        codegenEnqueuer.logSummary(reporter.log);

        int programSize = backend.assembleProgram(closedWorld);

        if (options.dumpInfo) {
          dumpInfoTask.reportSize(programSize);
          dumpInfoTask.dumpInfo(closedWorld);
        }

        backend.onCodegenEnd();

        checkQueues(resolutionEnqueuer, codegenEnqueuer);
      });

  Enqueuer startCodegen(ClosedWorld closedWorld) {
    Enqueuer codegenEnqueuer = enqueuer.createCodegenEnqueuer(closedWorld);
    _codegenWorldBuilder = codegenEnqueuer.worldBuilder;
    codegenEnqueuer.applyImpact(backend.onCodegenStart(
        closedWorld, _codegenWorldBuilder, backendStrategy.sorter));
    return codegenEnqueuer;
  }

  /// Perform the steps needed to fully end the resolution phase.
  ClosedWorldRefiner closeResolution(FunctionEntity mainFunction) {
    phase = PHASE_DONE_RESOLVING;

    ClosedWorld closedWorld = resolutionWorldBuilder.closeWorld();
    ClosedWorldRefiner closedWorldRefiner =
        backendStrategy.createClosedWorldRefiner(closedWorld);
    // Compute whole-program-knowledge that the backend needs. (This might
    // require the information computed in [world.closeWorld].)
    backend.onResolutionClosedWorld(closedWorld, closedWorldRefiner);

    OutputUnitData result = deferredLoadTask.run(mainFunction, closedWorld);
    backend.onDeferredLoadComplete(result);

    // TODO(johnniwinther): Move this after rti computation but before
    // reflection members computation, and (re-)close the world afterwards.
    backendStrategy.closureDataLookup.convertClosures(
        enqueuer.resolution.processedEntities, closedWorldRefiner);
    return closedWorldRefiner;
  }

  /// Compute the [WorldImpact] for accessing all elements in [library].
  WorldImpact computeImpactForLibrary(LibraryEntity library) {
    WorldImpactBuilderImpl impactBuilder = new WorldImpactBuilderImpl();

    void registerStaticUse(MemberEntity element) {
      impactBuilder.registerStaticUse(new StaticUse.directUse(element));
    }

    void registerStaticElementUse(Element element) {
      MemberElement member = element;
      impactBuilder.registerStaticUse(new StaticUse.directUse(member));
    }

    void registerElement(Element element) {
      if (element.isClass) {
        ClassElement cls = element;
        cls.ensureResolved(resolution);
        cls.forEachLocalMember(registerStaticElementUse);
        impactBuilder.registerTypeUse(new TypeUse.instantiation(cls.rawType));
      } else if (element.isTypedef) {
        TypedefElement typedef = element;
        typedef.ensureResolved(resolution);
      } else {
        registerStaticElementUse(element);
      }
    }

    if (library is LibraryElement) {
      library.implementation.forEachLocalMember(registerElement);

      library.imports.forEach((ImportElement import) {
        if (import.isDeferred) {
          // `import.prefix` and `loadLibrary` may be `null` when the deferred
          // import has compile-time errors.
          GetterElement loadLibrary = import.prefix?.loadLibrary;
          if (loadLibrary != null) {
            registerStaticUse(loadLibrary);
          }
        }
      });
    } else {
      ElementEnvironment elementEnvironment =
          frontendStrategy.elementEnvironment;

      elementEnvironment.forEachLibraryMember(library, registerStaticUse);
      elementEnvironment.forEachClass(library, (ClassEntity cls) {
        impactBuilder.registerTypeUse(
            new TypeUse.instantiation(elementEnvironment.getRawType(cls)));
        elementEnvironment.forEachLocalClassMember(cls, registerStaticUse);
      });
    }
    return impactBuilder;
  }

  // Resolves metadata on library elements.  This is necessary in order to
  // resolve metadata classes referenced only from metadata on library tags.
  // TODO(ahe): Figure out how to do this lazily.
  void resolveLibraryMetadata() {
    assert(frontendStrategy.commonElements.mirrorsLibrary != null);
    for (LibraryElement library in libraryLoader.libraries) {
      if (library.metadata != null) {
        for (MetadataAnnotation metadata in library.metadata) {
          metadata.ensureResolved(resolution);
        }
      }
    }
  }

  /**
   * Empty the [enqueuer] queue.
   */
  void emptyQueue(Enqueuer enqueuer, {void onProgress(Enqueuer enqueuer)}) {
    selfTask.measureSubtask("Compiler.emptyQueue", () {
      enqueuer.forEach((WorkItem work) {
        if (onProgress != null) {
          onProgress(enqueuer);
        }
        reporter.withCurrentElement(
            work.element,
            () => selfTask.measureSubtask("world.applyImpact", () {
                  enqueuer.applyImpact(
                      selfTask.measureSubtask("work.run", () => work.run()),
                      impactSource: work.element);
                }));
      });
    });
  }

  void processQueue(ElementEnvironment elementEnvironment, Enqueuer enqueuer,
      FunctionEntity mainMethod, Iterable<LibraryEntity> libraries,
      {void onProgress(Enqueuer enqueuer)}) {
    selfTask.measureSubtask("Compiler.processQueue", () {
      enqueuer.open(impactStrategy, mainMethod, libraries);
      progress.startPhase();
      emptyQueue(enqueuer, onProgress: onProgress);
      enqueuer.queueIsClosed = true;
      enqueuer.close();
      // Notify the impact strategy impacts are no longer needed for this
      // enqueuer.
      impactStrategy.onImpactUsed(enqueuer.impactUse);
      assert(compilationFailed ||
          enqueuer.checkNoEnqueuedInvokedInstanceMethods(elementEnvironment));
    });
  }

  /**
   * Perform various checks of the queues. This includes checking that
   * the queues are empty (nothing was added after we stopped
   * processing the queues). Also compute the number of methods that
   * were resolved, but not compiled (aka excess resolution).
   */
  checkQueues(Enqueuer resolutionEnqueuer, Enqueuer codegenEnqueuer) {
    for (Enqueuer enqueuer in [resolutionEnqueuer, codegenEnqueuer]) {
      enqueuer.checkQueueIsEmpty();
    }
    if (!REPORT_EXCESS_RESOLUTION) return;
    var resolved = new Set.from(resolutionEnqueuer.processedEntities);
    for (MemberEntity e in codegenEnqueuer.processedEntities) {
      resolved.remove(e);
    }
    for (MemberEntity e in new Set.from(resolved)) {
      if (e.isField) {
        resolved.remove(e);
      }
      if (e.isConstructor && (e as ConstructorEntity).isGenerativeConstructor) {
        resolved.remove(e);
      }
      if (backend.isTargetSpecificLibrary(e.library)) {
        resolved.remove(e);
      }
    }
    reporter.log('Excess resolution work: ${resolved.length}.');
    for (MemberEntity e in resolved) {
      reporter.reportWarningMessage(e, MessageKind.GENERIC,
          {'text': 'Warning: $e resolved but not compiled.'});
    }
  }

  void showResolutionProgress(Enqueuer enqueuer) {
    assert(phase == PHASE_RESOLVING, 'Unexpected phase: $phase');
    progress.showProgress(
        'Resolved ', enqueuer.processedEntities.length, ' elements.');
  }

  void showCodegenProgress(Enqueuer enqueuer) {
    progress.showProgress(
        'Compiled ', enqueuer.processedEntities.length, ' methods.');
  }

  void reportDiagnostic(DiagnosticMessage message,
      List<DiagnosticMessage> infos, api.Diagnostic kind);

  void reportCrashInUserCode(String message, exception, stackTrace) {
    reporter.onCrashInUserCode(message, exception, stackTrace);
  }

  /// Messages for which compile-time errors are reported but compilation
  /// continues regardless.
  static const List<MessageKind> BENIGN_ERRORS = const <MessageKind>[
    MessageKind.INVALID_METADATA,
    MessageKind.INVALID_METADATA_GENERIC,
  ];

  bool markCompilationAsFailed(DiagnosticMessage message, api.Diagnostic kind) {
    if (options.testMode) {
      // When in test mode, i.e. on the build-bot, we always stop compilation.
      return true;
    }
    if (reporter.options.fatalWarnings) {
      return true;
    }
    return !BENIGN_ERRORS.contains(message.message.kind);
  }

  void fatalDiagnosticReported(DiagnosticMessage message,
      List<DiagnosticMessage> infos, api.Diagnostic kind) {
    if (markCompilationAsFailed(message, kind)) {
      compilationFailed = true;
    }
    registerCompileTimeError(currentElement, message);
  }

  /**
   * Reads the script specified by the [readableUri].
   *
   * See [LibraryLoader] for terminology on URIs.
   */
  Future<Script> readScript(Uri readableUri, [Spannable node]) {
    throw failedAt(node, 'Compiler.readScript not implemented.');
  }

  Future<Binary> readBinary(Uri readableUri, [Spannable node]) {
    throw failedAt(node, 'Compiler.readBinary not implemented.');
  }

  Element lookupElementIn(ScopeContainerElement container, String name) {
    Element element = container.localLookup(name);
    if (element == null) {
      throw 'Could not find $name in $container';
    }
    return element;
  }

  bool get isMockCompilation => false;

  /// Helper for determining whether the current element is declared within
  /// 'user code'.
  ///
  /// See [inUserCode] for what defines 'user code'.
  bool currentlyInUserCode() {
    return inUserCode(currentElement);
  }

  /// Helper for determining whether [element] is declared within 'user code'.
  ///
  /// What constitutes 'user code' is defined by the URI(s) provided by the
  /// entry point(s) of compilation or analysis:
  ///
  /// If an entrypoint URI uses the 'package' scheme then every library from
  /// that same package is considered to be in user code. For instance, if
  /// an entry point URI is 'package:foo/bar.dart' then every library whose
  /// canonical URI starts with 'package:foo/' is in user code.
  ///
  /// If an entrypoint URI uses another scheme than 'package' then every library
  /// with that scheme is in user code. For instance, an entry point URI is
  /// 'file:///foo.dart' then every library whose canonical URI scheme is
  /// 'file' is in user code.
  ///
  /// If [assumeInUserCode] is `true`, [element] is assumed to be in user code
  /// if no entrypoints have been set.
  bool inUserCode(Entity element, {bool assumeInUserCode: false}) {
    if (element == null) return assumeInUserCode;
    Uri libraryUri = _uriFromElement(element);
    if (libraryUri == null) return false;
    Iterable<CodeLocation> userCodeLocations =
        computeUserCodeLocations(assumeInUserCode: assumeInUserCode);
    return userCodeLocations.any(
        (CodeLocation codeLocation) => codeLocation.inSameLocation(libraryUri));
  }

  Iterable<CodeLocation> computeUserCodeLocations(
      {bool assumeInUserCode: false}) {
    List<CodeLocation> userCodeLocations = <CodeLocation>[];
    if (mainLibraryUri != null) {
      userCodeLocations.add(new CodeLocation(mainLibraryUri));
    }
    if (librariesToAnalyzeWhenRun != null) {
      userCodeLocations.addAll(
          librariesToAnalyzeWhenRun.map((Uri uri) => new CodeLocation(uri)));
    }
    if (userCodeLocations.isEmpty && assumeInUserCode) {
      // Assume in user code since [mainApp] has not been set yet.
      userCodeLocations.add(const AnyLocation());
    }
    return userCodeLocations;
  }

  /// Return a canonical URI for the source of [element].
  ///
  /// For a package library with canonical URI 'package:foo/bar/baz.dart' the
  /// return URI is 'package:foo'. For non-package libraries the returned URI is
  /// the canonical URI of the library itself.
  Uri getCanonicalUri(Entity element) {
    Uri libraryUri = _uriFromElement(element);
    if (libraryUri == null) return null;
    if (libraryUri.scheme == 'package') {
      int slashPos = libraryUri.path.indexOf('/');
      if (slashPos != -1) {
        String packageName = libraryUri.path.substring(0, slashPos);
        return new Uri(scheme: 'package', path: packageName);
      }
    }
    return libraryUri;
  }

  Uri _uriFromElement(Entity element) {
    if (element is LibraryEntity) {
      return element.canonicalUri;
    } else if (element is ClassEntity) {
      return element.library.canonicalUri;
    } else if (element is MemberEntity) {
      return element.library.canonicalUri;
    } else if (element is Element) {
      return element.library.canonicalUri;
    }
    return null;
  }

  /// Returns [true] if a compile-time error has been reported for element.
  bool elementHasCompileTimeError(Entity element) {
    return elementsWithCompileTimeErrors.containsKey(element);
  }

  /// Associate [element] with a compile-time error [message].
  void registerCompileTimeError(Entity element, DiagnosticMessage message) {
    // The information is only needed if [generateCodeWithCompileTimeErrors].
    if (options.generateCodeWithCompileTimeErrors) {
      if (element == null) {
        // Record as global error.
        // TODO(zarah): Extend element model to represent compile-time
        // errors instead of using a map.
        element = frontendStrategy.elementEnvironment.mainFunction;
      }
      elementsWithCompileTimeErrors
          .putIfAbsent(element, () => <DiagnosticMessage>[])
          .add(message);
    }
  }
}

class _CompilerOutput implements api.CompilerOutput {
  final Compiler _compiler;
  final api.CompilerOutput _userOutput;

  _CompilerOutput(this._compiler, api.CompilerOutput output)
      : this._userOutput = output ?? const NullCompilerOutput();

  @override
  api.OutputSink createOutputSink(
      String name, String extension, api.OutputType type) {
    if (_compiler.compilationFailed) {
      if (!_compiler.options.generateCodeWithCompileTimeErrors ||
          _compiler.options.testMode) {
        // Disable output in test mode: The build bot currently uses the time
        // stamp of the generated file to determine whether the output is
        // up-to-date.
        return NullSink.outputProvider(name, extension, type);
      }
    }
    return _userOutput.createOutputSink(name, extension, type);
  }
}

/// Information about suppressed warnings and hints for a given library.
class SuppressionInfo {
  int warnings = 0;
  int hints = 0;
}

class CompilerDiagnosticReporter extends DiagnosticReporter {
  final Compiler compiler;
  final DiagnosticOptions options;

  Entity _currentElement;
  bool hasCrashed = false;

  /// `true` if the last diagnostic was filtered, in which case the
  /// accompanying info message should be filtered as well.
  bool lastDiagnosticWasFiltered = false;

  /// Map containing information about the warnings and hints that have been
  /// suppressed for each library.
  Map<Uri, SuppressionInfo> suppressedWarnings = <Uri, SuppressionInfo>{};

  CompilerDiagnosticReporter(this.compiler, this.options);

  Entity get currentElement => _currentElement;

  DiagnosticMessage createMessage(Spannable spannable, MessageKind messageKind,
      [Map arguments = const {}]) {
    SourceSpan span = spanFromSpannable(spannable);
    MessageTemplate template = MessageTemplate.TEMPLATES[messageKind];
    Message message = template.message(arguments, options.terseDiagnostics);
    return new DiagnosticMessage(span, spannable, message);
  }

  void reportError(DiagnosticMessage message,
      [List<DiagnosticMessage> infos = const <DiagnosticMessage>[]]) {
    reportDiagnosticInternal(message, infos, api.Diagnostic.ERROR);
  }

  void reportWarning(DiagnosticMessage message,
      [List<DiagnosticMessage> infos = const <DiagnosticMessage>[]]) {
    reportDiagnosticInternal(message, infos, api.Diagnostic.WARNING);
  }

  void reportHint(DiagnosticMessage message,
      [List<DiagnosticMessage> infos = const <DiagnosticMessage>[]]) {
    reportDiagnosticInternal(message, infos, api.Diagnostic.HINT);
  }

  @deprecated
  void reportInfo(Spannable node, MessageKind messageKind,
      [Map arguments = const {}]) {
    reportDiagnosticInternal(createMessage(node, messageKind, arguments),
        const <DiagnosticMessage>[], api.Diagnostic.INFO);
  }

  void reportDiagnosticInternal(DiagnosticMessage message,
      List<DiagnosticMessage> infos, api.Diagnostic kind) {
    if (!options.showAllPackageWarnings &&
        message.spannable != NO_LOCATION_SPANNABLE) {
      switch (kind) {
        case api.Diagnostic.WARNING:
        case api.Diagnostic.HINT:
          Entity element = elementFromSpannable(message.spannable);
          if (!compiler.inUserCode(element, assumeInUserCode: true)) {
            Uri uri = compiler.getCanonicalUri(element);
            if (options.showPackageWarningsFor(uri)) {
              reportDiagnostic(message, infos, kind);
              return;
            }
            SuppressionInfo info = suppressedWarnings.putIfAbsent(
                uri, () => new SuppressionInfo());
            if (kind == api.Diagnostic.WARNING) {
              info.warnings++;
            } else {
              info.hints++;
            }
            lastDiagnosticWasFiltered = true;
            return;
          }
          break;
        case api.Diagnostic.INFO:
          if (lastDiagnosticWasFiltered) {
            return;
          }
          break;
      }
    }
    lastDiagnosticWasFiltered = false;
    reportDiagnostic(message, infos, kind);
  }

  void reportDiagnostic(DiagnosticMessage message,
      List<DiagnosticMessage> infos, api.Diagnostic kind) {
    compiler.reportDiagnostic(message, infos, kind);
    if (kind == api.Diagnostic.ERROR ||
        kind == api.Diagnostic.CRASH ||
        (options.fatalWarnings && kind == api.Diagnostic.WARNING)) {
      Entity errorElement;
      if (message.spannable is Entity) {
        errorElement = message.spannable;
      } else {
        errorElement = currentElement;
      }
      compiler.registerCompileTimeError(errorElement, message);
      compiler.fatalDiagnosticReported(message, infos, kind);
    }
  }

  @override
  bool get hasReportedError => compiler.compilationFailed;

  /**
   * Perform an operation, [f], returning the return value from [f].  If an
   * error occurs then report it as having occurred during compilation of
   * [element].  Can be nested.
   */
  withCurrentElement(Entity element, f()) {
    Entity old = currentElement;
    _currentElement = element;
    try {
      return f();
    } on SpannableAssertionFailure catch (ex) {
      if (!hasCrashed) {
        reportAssertionFailure(ex);
        pleaseReportCrash();
      }
      hasCrashed = true;
      rethrow;
    } on StackOverflowError {
      // We cannot report anything useful in this case, because we
      // do not have enough stack space.
      rethrow;
    } catch (ex) {
      if (hasCrashed) rethrow;
      try {
        unhandledExceptionOnElement(element);
      } catch (doubleFault) {
        // Ignoring exceptions in exception handling.
      }
      rethrow;
    } finally {
      _currentElement = old;
    }
  }

  void reportAssertionFailure(SpannableAssertionFailure ex) {
    String message =
        (ex.message != null) ? tryToString(ex.message) : tryToString(ex);
    reportDiagnosticInternal(
        createMessage(ex.node, MessageKind.GENERIC, {'text': message}),
        const <DiagnosticMessage>[],
        api.Diagnostic.CRASH);
  }

  /// Using [frontendStrategy] to compute a [SourceSpan] from spannable using
  /// the [currentElement] as context.
  SourceSpan _spanFromStrategy(Spannable spannable) {
    SourceSpan span;
    if (compiler.phase == Compiler.PHASE_COMPILING) {
      span =
          compiler.backendStrategy.spanFromSpannable(spannable, currentElement);
    } else {
      span = compiler.frontendStrategy
          .spanFromSpannable(spannable, currentElement);
    }
    if (span != null) return span;
    throw 'No error location.';
  }

  SourceSpan spanFromSpannable(Spannable spannable) {
    if (spannable == CURRENT_ELEMENT_SPANNABLE) {
      spannable = currentElement;
    } else if (spannable == NO_LOCATION_SPANNABLE) {
      if (currentElement == null) return null;
      spannable = currentElement;
    }
    if (spannable is SourceSpan) {
      return spannable;
    } else if (spannable is HInstruction) {
      Entity element = spannable.sourceElement;
      if (element == null) element = currentElement;
      SourceInformation position = spannable.sourceInformation;
      if (position != null) return position.sourceSpan;
      return _spanFromStrategy(element);
    } else {
      return _spanFromStrategy(spannable);
    }
  }

  // TODO(johnniwinther): Move this to the parser listeners.
  @override
  SourceSpan spanFromToken(Token token) {
    if (compiler.frontendStrategy is ResolutionFrontEndStrategy) {
      ResolutionFrontEndStrategy strategy = compiler.frontendStrategy;
      return strategy.spanFromToken(currentElement, token);
    }
    throw 'No error location.';
  }

  Element _elementFromHInstruction(HInstruction instruction) {
    return instruction.sourceElement is Element
        ? instruction.sourceElement
        : null;
  }

  internalError(Spannable spannable, reason) {
    String message = tryToString(reason);
    reportDiagnosticInternal(
        createMessage(spannable, MessageKind.GENERIC, {'text': message}),
        const <DiagnosticMessage>[],
        api.Diagnostic.CRASH);
    throw 'Internal Error: $message';
  }

  void unhandledExceptionOnElement(Entity element) {
    if (hasCrashed) return;
    hasCrashed = true;
    reportDiagnostic(createMessage(element, MessageKind.COMPILER_CRASHED),
        const <DiagnosticMessage>[], api.Diagnostic.CRASH);
    pleaseReportCrash();
  }

  void pleaseReportCrash() {
    print(MessageTemplate.TEMPLATES[MessageKind.PLEASE_REPORT_THE_CRASH]
        .message({'buildId': compiler.options.buildId}));
  }

  /// Finds the approximate [Element] for [node]. [currentElement] is used as
  /// the default value.
  Entity elementFromSpannable(Spannable node) {
    Entity element;
    if (node is Entity) {
      element = node;
    } else if (node is HInstruction) {
      element = _elementFromHInstruction(node);
    } else if (node is MetadataAnnotation) {
      element = node.annotatedElement;
    }
    return element != null ? element : currentElement;
  }

  void log(message) {
    Message msg = MessageTemplate.TEMPLATES[MessageKind.GENERIC]
        .message({'text': '$message'});
    reportDiagnostic(new DiagnosticMessage(null, null, msg),
        const <DiagnosticMessage>[], api.Diagnostic.VERBOSE_INFO);
  }

  String tryToString(object) {
    try {
      return object.toString();
    } catch (_) {
      return '<exception in toString()>';
    }
  }

  onError(Uri uri, error) {
    try {
      if (!hasCrashed) {
        hasCrashed = true;
        if (error is SpannableAssertionFailure) {
          reportAssertionFailure(error);
        } else {
          reportDiagnostic(
              createMessage(
                  new SourceSpan(uri, 0, 0), MessageKind.COMPILER_CRASHED),
              const <DiagnosticMessage>[],
              api.Diagnostic.CRASH);
        }
        pleaseReportCrash();
      }
    } catch (doubleFault) {
      // Ignoring exceptions in exception handling.
    }
    throw error;
  }

  @override
  void onCrashInUserCode(String message, exception, stackTrace) {
    hasCrashed = true;
    print('$message: ${tryToString(exception)}');
    print(tryToString(stackTrace));
  }

  void reportSuppressedMessagesSummary() {
    if (!options.showAllPackageWarnings && !options.suppressWarnings) {
      suppressedWarnings.forEach((Uri uri, SuppressionInfo info) {
        MessageKind kind = MessageKind.HIDDEN_WARNINGS_HINTS;
        if (info.warnings == 0) {
          kind = MessageKind.HIDDEN_HINTS;
        } else if (info.hints == 0) {
          kind = MessageKind.HIDDEN_WARNINGS;
        }
        MessageTemplate template = MessageTemplate.TEMPLATES[kind];
        Message message = template.message(
            {'warnings': info.warnings, 'hints': info.hints, 'uri': uri},
            options.terseDiagnostics);
        reportDiagnostic(new DiagnosticMessage(null, null, message),
            const <DiagnosticMessage>[], api.Diagnostic.HINT);
      });
    }
  }
}

// TODO(johnniwinther): Move [ResolverTask] here.
class CompilerResolution implements Resolution, ImpactCacheDeleter {
  final Compiler _compiler;
  final Map<Element, ResolutionImpact> _resolutionImpactCache =
      <Element, ResolutionImpact>{};
  final Map<Entity, WorldImpact> _worldImpactCache = <Entity, WorldImpact>{};
  bool retainCachesForTesting = false;
  Types _types;

  CompilerResolution(this._compiler) {
    _types = new Types(this);
  }

  @override
  DiagnosticReporter get reporter => _compiler.reporter;

  @override
  ParsingContext get parsingContext => _compiler.parsingContext;

  @override
  ElementEnvironment get elementEnvironment =>
      _compiler.frontendStrategy.elementEnvironment;

  @override
  CommonElements get commonElements =>
      _compiler.frontendStrategy.commonElements;

  @override
  Types get types => _types;

  @override
  Target get target => _compiler.backend.target;

  @override
  ResolverTask get resolver => _compiler.resolver;

  @override
  ResolutionEnqueuer get enqueuer => _compiler.enqueuer.resolution;

  @override
  CompilerOptions get options => _compiler.options;

  @override
  IdGenerator get idGenerator => _compiler.idGenerator;

  @override
  ConstantEnvironment get constants => _compiler.constants;

  @override
  MirrorUsageAnalyzerTask get mirrorUsageAnalyzerTask =>
      _compiler.mirrorUsageAnalyzerTask;

  LibraryElement get coreLibrary =>
      _compiler.frontendStrategy.commonElements.coreLibrary;

  @override
  bool get wasProxyConstantComputedTestingOnly => _proxyConstant != null;

  @override
  void resolveClass(ClassElement cls) {
    _compiler.resolver.resolveClass(cls);
  }

  @override
  void resolveTypedef(TypedefElement typdef) {
    _compiler.resolver.resolve(typdef);
  }

  @override
  void resolveMetadataAnnotation(MetadataAnnotation metadataAnnotation) {
    _compiler.resolver.resolveMetadataAnnotation(metadataAnnotation);
  }

  @override
  FunctionSignature resolveSignature(FunctionElement function) {
    return _compiler.resolver.resolveSignature(function);
  }

  @override
  ResolutionDartType resolveTypeAnnotation(
      Element element, TypeAnnotation node) {
    return _compiler.resolver.resolveTypeAnnotation(element, node);
  }

  @override
  void ensureResolved(Element element) {
    computeWorldImpact(element);
  }

  @override
  void ensureClassMembers(ClassElement element) {
    _compiler.resolver.checkClass(element);
  }

  @override
  void registerCompileTimeError(Element element, DiagnosticMessage message) =>
      _compiler.registerCompileTimeError(element, message);

  @override
  bool hasResolvedAst(ExecutableElement element) {
    assert(element.isDeclaration,
        failedAt(element, "Element $element must be the declaration."));
    return hasBeenResolved(element.memberContext.declaration) &&
        element.hasResolvedAst;
  }

  @override
  ResolvedAst getResolvedAst(ExecutableElement element) {
    assert(element.isDeclaration,
        failedAt(element, "Element $element must be the declaration."));
    assert(hasResolvedAst(element),
        failedAt(element, "ResolvedAst not available for $element."));
    return element.resolvedAst;
  }

  @override
  ResolvedAst computeResolvedAst(Element element) {
    ensureResolved(element);
    return getResolvedAst(element);
  }

  @override
  bool hasResolutionImpact(Element element) {
    assert(element.isDeclaration,
        failedAt(element, "Element $element must be the declaration."));
    return _resolutionImpactCache.containsKey(element);
  }

  @override
  ResolutionImpact getResolutionImpact(Element element) {
    assert(element.isDeclaration,
        failedAt(element, "Element $element must be the declaration."));
    ResolutionImpact resolutionImpact = _resolutionImpactCache[element];
    assert(resolutionImpact != null,
        failedAt(element, "ResolutionImpact not available for $element."));
    return resolutionImpact;
  }

  @override
  WorldImpact getWorldImpact(Element element) {
    assert(element.isDeclaration,
        failedAt(element, "Element $element must be the declaration."));
    WorldImpact worldImpact = _worldImpactCache[element];
    assert(worldImpact != null,
        failedAt(element, "WorldImpact not computed for $element."));
    return worldImpact;
  }

  @override
  WorldImpact computeWorldImpact(Element element) {
    return _compiler.selfTask.measureSubtask("Resolution.computeWorldImpact",
        () {
      assert(
          element.impliesType ||
              element.isField ||
              element.isFunction ||
              element.isConstructor ||
              element.isGetter ||
              element.isSetter,
          failedAt(element, 'Unexpected element kind: ${element.kind}'));
      // `true ==` prevents analyzer type inference from strengthening element
      // to AnalyzableElement which incompatible with some down-cast to ElementX
      // uses.
      // TODO(29712): Can this be made to work as we expect?
      assert(true == element is AnalyzableElement,
          failedAt(element, 'Element $element is not analyzable.'));
      assert(element.isDeclaration,
          failedAt(element, "Element $element must be the declaration."));
      return _worldImpactCache.putIfAbsent(element, () {
        assert(_compiler.parser != null);
        Node tree = _compiler.parser.parse(element);
        assert(!element.isSynthesized || tree == null, failedAt(element));
        ResolutionImpact resolutionImpact = _compiler.resolver.resolve(element);

        if (retainCachesForTesting) {
          // [ResolutionImpact] is currently only used by serialization. The
          // enqueuer uses the [WorldImpact] which is always cached.
          // TODO(johnniwinther): Align these use cases better; maybe only
          // cache [ResolutionImpact] and let the enqueuer transform it into
          // a [WorldImpact].
          _resolutionImpactCache[element] = resolutionImpact;
        }
        if (tree != null && !_compiler.options.analyzeSignaturesOnly) {
          // TODO(het): don't do this if suppressWarnings is on, currently we
          // have to do it because the typechecker also sets types
          // Only analyze nodes with a corresponding [TreeElements].
          _compiler.checker.check(element);
        }
        return transformResolutionImpact(element, resolutionImpact);
      });
    });
  }

  @override
  WorldImpact transformResolutionImpact(
      Element element, ResolutionImpact resolutionImpact) {
    WorldImpact worldImpact = _compiler.backend.impactTransformer
        .transformResolutionImpact(resolutionImpact);
    _worldImpactCache[element] = worldImpact;
    return worldImpact;
  }

  @override
  void uncacheWorldImpact(covariant Element element) {
    assert(element.isDeclaration,
        failedAt(element, "Element $element must be the declaration."));
    if (retainCachesForTesting) return;
    assert(_worldImpactCache[element] != null,
        failedAt(element, "WorldImpact not computed for $element."));
    _worldImpactCache[element] = const WorldImpact();
    _resolutionImpactCache.remove(element);
  }

  @override
  void emptyCache() {
    if (retainCachesForTesting) return;
    for (Element element in _worldImpactCache.keys) {
      _worldImpactCache[element] = const WorldImpact();
    }
    _resolutionImpactCache.clear();
  }

  @override
  bool hasBeenResolved(Element element) {
    return _worldImpactCache.containsKey(element);
  }

  @override
  ResolutionWorkItem createWorkItem(MemberElement element) {
    return new ResolutionWorkItem(this, element);
  }

  ConstantValue _proxyConstant;

  @override
  bool isProxyConstant(ConstantValue value) {
    FieldElement field = coreLibrary.find('proxy');
    if (field == null) return false;
    if (!hasBeenResolved(field)) return false;
    if (_proxyConstant == null) {
      _proxyConstant = constants
          .getConstantValue(resolver.constantCompiler.compileConstant(field));
    }
    return _proxyConstant == value;
  }

  @override
  void registerClass(ClassEntity cls) {
    enqueuer.worldBuilder.registerClass(cls);
  }
}

class _MapImpactCacheDeleter implements ImpactCacheDeleter {
  final Map<Entity, WorldImpact> _impactCache;
  _MapImpactCacheDeleter(this._impactCache);

  bool retainCachesForTesting = false;

  void uncacheWorldImpact(Entity element) {
    if (retainCachesForTesting) return;
    _impactCache.remove(element);
  }

  void emptyCache() {
    if (retainCachesForTesting) return;
    _impactCache.clear();
  }
}

class _ScriptLoader implements ScriptLoader {
  Compiler compiler;
  _ScriptLoader(this.compiler);

  Future<Script> readScript(Uri uri, [Spannable spannable]) =>
      compiler.readScript(uri, spannable);

  Future<Binary> readBinary(Uri uri, [Spannable spannable]) =>
      compiler.readBinary(uri, spannable);
}

class _ElementScanner implements ElementScanner {
  ScannerTask scanner;
  _ElementScanner(this.scanner);
  void scanLibrary(LibraryElement library) => scanner.scanLibrary(library);
  void scanUnit(CompilationUnitElement unit) => scanner.scan(unit);
}

class _EmptyEnvironment implements Environment {
  const _EmptyEnvironment();

  String valueOf(String key) => null;
}

/// Interface for showing progress during compilation.
class Progress {
  const Progress();

  /// Starts a new phase for which to show progress.
  void startPhase() {}

  /// Shows progress of the current phase if needed. The shown message is
  /// computed as '$prefix$count$suffix'.
  void showProgress(String prefix, int count, String suffix) {}
}

/// Progress implementations that prints progress to the [DiagnosticReporter]
/// with 500ms intervals.
class ProgressImpl implements Progress {
  final DiagnosticReporter _reporter;
  final Stopwatch _stopwatch = new Stopwatch()..start();

  ProgressImpl(this._reporter);

  void showProgress(String prefix, int count, String suffix) {
    if (_stopwatch.elapsedMilliseconds > 500) {
      _reporter.log('$prefix$count$suffix');
      _stopwatch.reset();
    }
  }

  void startPhase() {
    _stopwatch.reset();
  }
}
