// Copyright (c) 2014, 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 deferred_load;

import 'constants/expressions.dart';
import 'constants/values.dart' show
    ConstantValue,
    ConstructedConstantValue,
    DeferredConstantValue,
    StringConstantValue;

import 'dart2jslib.dart' show
    Backend,
    Compiler,
    CompilerTask,
    invariant,
    MessageKind;

import 'dart_backend/dart_backend.dart' show
    DartBackend;

import 'js_backend/js_backend.dart' show
    JavaScriptBackend;

import 'elements/elements.dart' show
    AstElement,
    ClassElement,
    Element,
    ElementKind,
    Elements,
    FunctionElement,
    LibraryElement,
    MetadataAnnotation,
    PrefixElement,
    ScopeContainerElement,
    TypedefElement,
    VoidElement;

import 'util/util.dart' show
    Link, makeUnique;
import 'util/uri_extras.dart' as uri_extras;

import 'util/setlet.dart' show
    Setlet;

import 'tree/tree.dart' show
    Import,
    LibraryTag,
    LibraryDependency,
    LiteralDartString,
    LiteralString,
    NewExpression,
    Node;

import 'tree/tree.dart' as ast;

import 'resolution/resolution.dart' show
    AnalyzableElementX,
    TreeElements;

/// A "hunk" of the program that will be loaded whenever one of its [imports]
/// are loaded.
///
/// Elements that are only used in one deferred import, is in an OutputUnit with
/// the deferred import as single element in the [imports] set.
///
/// Whenever a deferred Element is shared between several deferred imports it is
/// in an output unit with those imports in the [imports] Set.
///
/// OutputUnits are equal if their [imports] are equal.
class OutputUnit {
  /// The deferred imports that will load this output unit when one of them is
  /// loaded.
  final Setlet<Import> imports = new Setlet<Import>();

  /// `true` if this output unit is for the main output file.
  final bool isMainOutput;

  /// A unique name representing this [OutputUnit].
  /// Based on the set of [imports].
  String name;

  OutputUnit({this.isMainOutput: false});

  String toString() => "OutputUnit($name)";

  bool operator==(OutputUnit other) {
    return imports.length == other.imports.length &&
        imports.containsAll(other.imports);
  }

  int get hashCode {
    int sum = 0;
    for (Import import in imports) {
      sum = (sum + import.hashCode) & 0x3FFFFFFF;  // Stay in 30 bit range.
    }
    return sum;
  }
}

/// For each deferred import, find elements and constants to be loaded when that
/// import is loaded. Elements that are used by several deferred imports are in
/// shared OutputUnits.
class DeferredLoadTask extends CompilerTask {
  /// The name of this task.
  String get name => 'Deferred Loading';

  /// DeferredLibrary from dart:async
  ClassElement get deferredLibraryClass => compiler.deferredLibraryClass;

  /// A synthetic [Import] representing the loading of the main
  /// program.
  final Import _fakeMainImport = new Import(null, new LiteralString(null,
      new LiteralDartString("main")), null, null, null);

  /// The OutputUnit that will be loaded when the program starts.
  final OutputUnit mainOutputUnit = new OutputUnit(isMainOutput: true);

  /// A set containing (eventually) all output units that will result from the
  /// program.
  final Set<OutputUnit> allOutputUnits = new Set<OutputUnit>();

  /// Will be `true` if the program contains deferred libraries.
  bool isProgramSplit = false;

  /// A mapping from the name of a defer import to all the output units it
  /// depends on in a list of lists to be loaded in the order they appear.
  ///
  /// For example {"lib1": [[lib1_lib2_lib3], [lib1_lib2, lib1_lib3],
  /// [lib1]]} would mean that in order to load "lib1" first the hunk
  /// lib1_lib2_lib2 should be loaded, then the hunks lib1_lib2 and lib1_lib3
  /// can be loaded in parallel. And finally lib1 can be loaded.
  final Map<String, List<OutputUnit>> hunksToLoad =
      new Map<String, List<OutputUnit>>();
  final Map<Import, String> importDeferName = new Map<Import, String>();

  /// A mapping from elements and constants to their output unit. Query this via
  /// [outputUnitForElement]
  final Map<Element, OutputUnit> _elementToOutputUnit =
      new Map<Element, OutputUnit>();

  /// A mapping from constants to their output unit. Query this via
  /// [outputUnitForConstant]
  final Map<ConstantValue, OutputUnit> _constantToOutputUnit =
      new Map<ConstantValue, OutputUnit>();

  /// All the imports with a [DeferredLibrary] annotation, mapped to the
  /// [LibraryElement] they import.
  /// The main library is included in this set for convenience.
  final Map<Import, LibraryElement> _allDeferredImports =
      new Map<Import, LibraryElement>();

  /// Because the token-stream is forgotten later in the program, we cache a
  /// description of each deferred import.
  final _deferredImportDescriptions = new Map<Import, ImportDescription>();

  // For each deferred import we want to know exactly what elements have to
  // be loaded.
  Map<Import, Set<Element>> _importedDeferredBy = null;
  Map<Import, Set<ConstantValue>> _constantsDeferredBy = null;

  Set<Element> _mainElements = new Set<Element>();

  DeferredLoadTask(Compiler compiler) : super(compiler) {
    mainOutputUnit.imports.add(_fakeMainImport);
  }

  Backend get backend => compiler.backend;

  /// Returns the [OutputUnit] where [element] belongs.
  OutputUnit outputUnitForElement(Element element) {
    if (!isProgramSplit) return mainOutputUnit;

    element = element.implementation;
    while (!_elementToOutputUnit.containsKey(element)) {
      // TODO(21051): workaround: it looks like we output annotation constants
      // for classes that we don't include in the output. This seems to happen
      // when we have reflection but can see that some classes are not needed.
      // We still add the annotation but don't run through it below (where we
      // assign every element to its output unit).
      if (element.enclosingElement == null) {
        _elementToOutputUnit[element] = mainOutputUnit;
        break;
      }
      element = element.enclosingElement.implementation;
    }
    return _elementToOutputUnit[element];
  }

  /// Returns the [OutputUnit] where [constant] belongs.
  OutputUnit outputUnitForConstant(ConstantValue constant) {
    if (!isProgramSplit) return mainOutputUnit;

    return _constantToOutputUnit[constant];
  }

  bool isDeferred(Element element) {
    return outputUnitForElement(element) != mainOutputUnit;
  }

  /// Returns true if e1 and e2 are in the same output unit.
  bool inSameOutputUnit(Element e1, Element e2) {
    return outputUnitForElement(e1) == outputUnitForElement(e2);
  }

  void registerConstantDeferredUse(DeferredConstantValue constant,
                                   PrefixElement prefix) {
    OutputUnit outputUnit = new OutputUnit();
    outputUnit.imports.add(prefix.deferredImport);
    _constantToOutputUnit[constant] = outputUnit;
  }

  /// Answers whether [element] is explicitly deferred when referred to from
  /// [library].
  bool _isExplicitlyDeferred(Element element, LibraryElement library) {
    Link<Import> imports = _getImports(element, library);
    // If the element is not imported explicitly, it is implicitly imported
    // not deferred.
    if (imports.isEmpty) return false;
    // An element could potentially be loaded by several imports. If all of them
    // is explicitly deferred, we say the element is explicitly deferred.
    // TODO(sigurdm): We might want to give a warning if the imports do not
    // agree.
    return imports.every((Import import) => import.isDeferred);
  }

  /// Returns a [Link] of every [Import] that imports [element] into [library].
  Link<Import> _getImports(Element element, LibraryElement library) {
    if (element.isClassMember) {
      element = element.enclosingClass;
    }
    if (element.isAccessor) {
      element = (element as FunctionElement).abstractField;
    }
    return library.getImportsFor(element);
  }

  /// Finds all elements and constants that [element] depends directly on.
  /// (not the transitive closure.)
  ///
  /// Adds the results to [elements] and [constants].
  void _collectAllElementsAndConstantsResolvedFrom(
      Element element,
      Set<Element> elements,
      Set<ConstantValue> constants,
      isMirrorUsage) {

    /// Recursively add the constant and its dependencies to [constants].
    void addConstants(ConstantValue constant) {
      if (constants.contains(constant)) return;
      constants.add(constant);
      if (constant is ConstructedConstantValue) {
        elements.add(constant.type.element);
      }
      constant.getDependencies().forEach(addConstants);
    }

    /// Collects all direct dependencies of [element].
    ///
    /// The collected dependent elements and constants are are added to
    /// [elements] and [constants] respectively.
    void collectDependencies(Element element) {
      // TODO(johnniwinther): Remove this when [AbstractFieldElement] has been
      // removed.
      if (element is! AstElement) return;
      AstElement astElement = element;

      // TODO(sigurdm): We want to be more specific about this - need a better
      // way to query "liveness".
      if (astElement is! TypedefElement &&
          !compiler.enqueuer.resolution.hasBeenResolved(astElement)) {
        return;
      }

      TreeElements treeElements = astElement.resolvedAst.elements;

      assert(treeElements != null);

      for (Element dependency in treeElements.allElements) {
        if (dependency.isLocal && !dependency.isFunction) continue;
        if (dependency.isErroneous) continue;
        if (dependency.isTypeVariable) continue;

        elements.add(dependency);
      }
      treeElements.forEachConstantNode((Node node, _) {
        // Explicitly depend on the backend constants.
        addConstants(
            backend.constants.getConstantForNode(node, treeElements).value);
      });
      elements.addAll(treeElements.otherDependencies);
    }

    // TODO(sigurdm): How is metadata on a patch-class handled?
    for (MetadataAnnotation metadata in element.metadata) {
      ConstantExpression constant =
          backend.constants.getConstantForMetadata(metadata);
      if (constant != null) {
        addConstants(constant.value);
      }
    }
    if (element.isClass) {
      // If we see a class, add everything its live instance members refer
      // to.  Static members are not relevant, unless we are processing
      // extra dependencies due to mirrors.
      void addLiveInstanceMember(Element element) {
        if (!compiler.enqueuer.resolution.hasBeenResolved(element)) return;
        if (!isMirrorUsage && !element.isInstanceMember) return;
        collectDependencies(element.implementation);
      }
      ClassElement cls = element.declaration;
      cls.forEachLocalMember(addLiveInstanceMember);
      if (cls.implementation != cls) {
        // TODO(ahe): Why doesn't ClassElement.forEachLocalMember do this?
        cls.implementation.forEachLocalMember(addLiveInstanceMember);
      }
      for (var type in cls.implementation.allSupertypes) {
        elements.add(type.element.implementation);
      }
      elements.add(cls.implementation);
    } else if (Elements.isStaticOrTopLevel(element) ||
               element.isConstructor) {
      collectDependencies(element);
    }
    if (element.isGenerativeConstructor) {
      // When instantiating a class, we record a reference to the
      // constructor, not the class itself.  We must add all the
      // instance members of the constructor's class.
      ClassElement implementation =
          element.enclosingClass.implementation;
      _collectAllElementsAndConstantsResolvedFrom(
          implementation, elements, constants, isMirrorUsage);
    }

    // Other elements, in particular instance members, are ignored as
    // they are processed as part of the class.
  }

  /// Returns the transitive closure of all libraries that are imported
  /// from root without DeferredLibrary annotations.
  Set<LibraryElement> _nonDeferredReachableLibraries(LibraryElement root) {
    Set<LibraryElement> result = new Set<LibraryElement>();

    void traverseLibrary(LibraryElement library) {
      if (result.contains(library)) return;
      result.add(library);

      iterateTags(LibraryElement library) {
        // TODO(sigurdm): Make helper getLibraryDependencyTags when tags is
        // changed to be a List instead of a Link.
        for (LibraryTag tag in library.tags) {
          if (tag is! LibraryDependency) continue;
          LibraryDependency libraryDependency = tag;
          if (!(libraryDependency is Import && libraryDependency.isDeferred)) {
            LibraryElement importedLibrary = library.getLibraryFromTag(tag);
            traverseLibrary(importedLibrary);
          }
        }
      }

      iterateTags(library);
      if (library.isPatched) {
        iterateTags(library.implementation);
      }
    }
    traverseLibrary(root);
    result.add(compiler.coreLibrary);
    return result;
  }

  /// Recursively traverses the graph of dependencies from [element], mapping
  /// deferred imports to each dependency it needs in the sets
  /// [_importedDeferredBy] and [_constantsDeferredBy].
  void _mapDependencies(Element element, Import import,
                        {isMirrorUsage: false}) {
    Set<Element> elements = _importedDeferredBy.putIfAbsent(import,
        () => new Set<Element>());
    Set<ConstantValue> constants = _constantsDeferredBy.putIfAbsent(import,
        () => new Set<ConstantValue>());

    // Only process elements once, unless we are doing dependencies due to
    // mirrors, which are added in additional traversals.
    if (!isMirrorUsage && elements.contains(element)) return;
    // Anything used directly by main will be loaded from the start
    // We do not need to traverse it again.
    if (import != _fakeMainImport && _mainElements.contains(element)) return;

    // Here we modify [_importedDeferredBy].
    elements.add(element);

    Set<Element> dependentElements = new Set<Element>();

    // This call can modify [_importedDeferredBy] and [_constantsDeferredBy].
    _collectAllElementsAndConstantsResolvedFrom(
        element, dependentElements, constants, isMirrorUsage);

    LibraryElement library = element.library;
    for (Element dependency in dependentElements) {
      if (_isExplicitlyDeferred(dependency, library)) {
        for (Import deferredImport in _getImports(dependency, library)) {
          _mapDependencies(dependency, deferredImport);
        };
      } else {
        _mapDependencies(dependency, import);
      }
    }
  }

  /// Adds extra dependencies coming from mirror usage.
  ///
  /// The elements are added with [_mapDependencies].
  void _addMirrorElements() {
    void mapDependenciesIfResolved(Element element, Import deferredImport) {
      // If an element is the target of a MirrorsUsed annotation but never used
      // It will not be resolved, and we should not call isNeededForReflection.
      // TODO(sigurdm): Unresolved elements should just answer false when
      // asked isNeededForReflection. Instead an internal error is triggered.
      // So we have to filter them out here.
      if (element is AnalyzableElementX && !element.hasTreeElements) return;
      if (compiler.backend.isAccessibleByReflection(element)) {
        _mapDependencies(element, deferredImport, isMirrorUsage: true);
      }
    }

    // For each deferred import we analyze all elements reachable from the
    // imported library through non-deferred imports.
    handleLibrary(LibraryElement library, Import deferredImport) {
      library.implementation.forEachLocalMember((Element element) {
        mapDependenciesIfResolved(element, deferredImport);
      });

      for (MetadataAnnotation metadata in library.metadata) {
        ConstantExpression constant =
            backend.constants.getConstantForMetadata(metadata);
        if (constant != null) {
          _mapDependencies(constant.value.getType(compiler.coreTypes).element,
              deferredImport);
        }
      }
      for (LibraryTag tag in library.tags) {
        for (MetadataAnnotation metadata in tag.metadata) {
          ConstantExpression constant =
              backend.constants.getConstantForMetadata(metadata);
          if (constant != null) {
            _mapDependencies(constant.value.getType(compiler.coreTypes).element,
                deferredImport);
          }
        }
      }
    }

    for (Import deferredImport in _allDeferredImports.keys) {
      LibraryElement deferredLibrary = _allDeferredImports[deferredImport];
      for (LibraryElement library in
          _nonDeferredReachableLibraries(deferredLibrary)) {
        handleLibrary(library, deferredImport);
      }
    }
  }

  /// Computes a unique string for the name field for each outputUnit.
  ///
  /// Also sets up the [hunksToLoad] mapping.
  void _assignNamesToOutputUnits(Set<OutputUnit> allOutputUnits) {
    Set<String> usedImportNames = new Set<String>();

    // Finds the first argument to the [DeferredLibrary] annotation
    void computeImportDeferName(Import import) {
      String result;
      if (import == _fakeMainImport) {
        result = "main";
      } else if (import.isDeferred) {
        result = import.prefix.toString();
      } else {
        Link<MetadataAnnotation> metadatas = import.metadata;
        assert(metadatas != null);
        for (MetadataAnnotation metadata in metadatas) {
          metadata.ensureResolved(compiler);
          Element element =
              metadata.constant.value.getType(compiler.coreTypes).element;
          if (element == deferredLibraryClass) {
            ConstructedConstantValue constant = metadata.constant.value;
            StringConstantValue s = constant.fields[0];
            result = s.primitiveValue.slowToString();
            break;
          }
        }
      }
      assert(result != null);
      importDeferName[import] = makeUnique(result, usedImportNames);;
    }

    int counter = 1;

    for (Import import in _allDeferredImports.keys) {
      computeImportDeferName(import);
    }

    for (OutputUnit outputUnit in allOutputUnits) {
      if (outputUnit == mainOutputUnit) {
        outputUnit.name = "main";
      } else {
        outputUnit.name = "$counter";
        ++counter;
      }
    }

    List sortedOutputUnits = new List.from(allOutputUnits);
    // Sort the output units in descending order of the number of imports they
    // include.

    // The loading of the output units mut be ordered because a superclass needs
    // to be initialized before its subclass.
    // But a class can only depend on another class in an output unit shared by
    // a strict superset of the imports:
    // By contradiction: Assume a class C in output unit shared by imports in
    // the set S1 = (lib1,.., lib_n) depends on a class D in an output unit
    // shared by S2 such that S2 not a superset of S1. Let lib_s be a library in
    // S1 not in S2. lib_s must depend on C, and then in turn on D therefore D
    // is not in the right output unit.
    sortedOutputUnits.sort((a, b) => b.imports.length - a.imports.length);

    // For each deferred import we find out which outputUnits to load.
    for (Import import in _allDeferredImports.keys) {
      if (import == _fakeMainImport) continue;
      hunksToLoad[importDeferName[import]] = new List<OutputUnit>();
      for (OutputUnit outputUnit in sortedOutputUnits) {
        if (outputUnit == mainOutputUnit) continue;
        if (outputUnit.imports.contains(import)) {
          hunksToLoad[importDeferName[import]].add(outputUnit);
        }
      }
    }
  }

  void onResolutionComplete(FunctionElement main) {
    if (!isProgramSplit) {
      allOutputUnits.add(mainOutputUnit);
      return;
    }
    if (main == null) return;
    LibraryElement mainLibrary = main.library;
    _importedDeferredBy = new Map<Import, Set<Element>>();
    _constantsDeferredBy = new Map<Import, Set<ConstantValue>>();
    _importedDeferredBy[_fakeMainImport] = _mainElements;

    measureElement(mainLibrary, () {

      // Starting from main, traverse the program and find all dependencies.
      _mapDependencies(compiler.mainFunction, _fakeMainImport);

      // Also add "global" dependencies to the main OutputUnit.  These are
      // things that the backend need but cannot associate with a particular
      // element, for example, startRootIsolate.  This set also contains
      // elements for which we lack precise information.
      for (Element element in compiler.globalDependencies.otherDependencies) {
        _mapDependencies(element, _fakeMainImport);
      }

      // Now check to see if we have to add more elements due to mirrors.
      if (compiler.mirrorsLibrary != null) {
        _addMirrorElements();
      }

      // Build the OutputUnits using these two maps.
      Map<Element, OutputUnit> elementToOutputUnitBuilder =
          new Map<Element, OutputUnit>();
      Map<ConstantValue, OutputUnit> constantToOutputUnitBuilder =
          new Map<ConstantValue, OutputUnit>();

      // Reverse the mappings. For each element record an OutputUnit collecting
      // all deferred imports mapped to this element. Same for constants.
      for (Import import in _importedDeferredBy.keys) {
        for (Element element in _importedDeferredBy[import]) {
          // Only one file should be loaded when the program starts, so make
          // sure that only one OutputUnit is created for [fakeMainImport].
          if (import == _fakeMainImport) {
            elementToOutputUnitBuilder[element] = mainOutputUnit;
          } else {
            elementToOutputUnitBuilder
                .putIfAbsent(element, () => new OutputUnit())
                .imports.add(import);
          }
        }
        for (ConstantValue constant in _constantsDeferredBy[import]) {
          // Only one file should be loaded when the program starts, so make
          // sure that only one OutputUnit is created for [fakeMainImport].
          if (import == _fakeMainImport) {
            constantToOutputUnitBuilder[constant] = mainOutputUnit;
          } else {
            constantToOutputUnitBuilder
                .putIfAbsent(constant, () => new OutputUnit())
                .imports.add(import);
          }
        }
      }

      // Release maps;
      _importedDeferredBy = null;
      _constantsDeferredBy = null;

      // Find all the output units elements/constants have been mapped to, and
      // canonicalize them.
      elementToOutputUnitBuilder.forEach(
          (Element element, OutputUnit outputUnit) {
        OutputUnit representative = allOutputUnits.lookup(outputUnit);
        if (representative == null) {
          representative = outputUnit;
          allOutputUnits.add(representative);
        }
        _elementToOutputUnit[element] = representative;
      });
      constantToOutputUnitBuilder.forEach(
          (ConstantValue constant, OutputUnit outputUnit) {
        OutputUnit representative = allOutputUnits.lookup(outputUnit);
        if (representative == null) {
          representative = outputUnit;
          allOutputUnits.add(representative);
        }
        _constantToOutputUnit[constant] = representative;
      });

      // Generate a unique name for each OutputUnit.
      _assignNamesToOutputUnits(allOutputUnits);
    });
  }

  void beforeResolution(Compiler compiler) {
    if (compiler.mainApp == null) return;
    _allDeferredImports[_fakeMainImport] = compiler.mainApp;
    var lastDeferred;
    // When detecting duplicate prefixes of deferred libraries there are 4
    // cases of duplicate prefixes:
    // 1.
    // import "lib.dart" deferred as a;
    // import "lib2.dart" deferred as a;
    // 2.
    // import "lib.dart" deferred as a;
    // import "lib2.dart" as a;
    // 3.
    // import "lib.dart" as a;
    // import "lib2.dart" deferred as a;
    // 4.
    // import "lib.dart" as a;
    // import "lib2.dart" as a;
    // We must be able to signal error for case 1, 2, 3, but accept case 4.

    // The prefixes that have been used by any imports in this library.
    Setlet<String> usedPrefixes = new Setlet<String>();
    // The last deferred import we saw with a given prefix (if any).
    Map<String, Import> prefixDeferredImport = new Map<String, Import>();
    for (LibraryElement library in compiler.libraryLoader.libraries) {
      compiler.withCurrentElement(library, () {
        prefixDeferredImport.clear();
        usedPrefixes.clear();
        // TODO(sigurdm): Make helper getLibraryImportTags when tags is a List
        // instead of a Link.
        for (LibraryTag tag in library.tags) {
          if (tag is! Import) continue;
          Import import = tag;

          /// Give an error if the old annotation-based syntax has been used.
          Link<MetadataAnnotation> metadataList = import.metadata;
          if (metadataList != null) {
            for (MetadataAnnotation metadata in metadataList) {
              metadata.ensureResolved(compiler);
              Element element =
                  metadata.constant.value.getType(compiler.coreTypes).element;
              if (element == deferredLibraryClass) {
                 compiler.reportError(
                     import, MessageKind.DEFERRED_OLD_SYNTAX);
              }
            }
          }

          String prefix = (import.prefix != null)
              ? import.prefix.toString()
              : null;
          // The last import we saw with the same prefix.
          Import previousDeferredImport = prefixDeferredImport[prefix];
          if (import.isDeferred) {
            LibraryElement importedLibrary = library.getLibraryFromTag(import);
            _allDeferredImports[import] = importedLibrary;

            if (prefix == null) {
              compiler.reportError(import,
                  MessageKind.DEFERRED_LIBRARY_WITHOUT_PREFIX);
            } else {
              prefixDeferredImport[prefix] = import;
              _deferredImportDescriptions[import] =
                  new ImportDescription(import, library, compiler);
            }
            isProgramSplit = true;
            lastDeferred = import;
          }
          if (prefix != null) {
            if (previousDeferredImport != null ||
                (import.isDeferred && usedPrefixes.contains(prefix))) {
              Import failingImport = (previousDeferredImport != null)
                  ? previousDeferredImport
                  : import;
              compiler.reportError(failingImport.prefix,
                  MessageKind.DEFERRED_LIBRARY_DUPLICATE_PREFIX);
            }
            usedPrefixes.add(prefix);
          }
        }
      });
    }
    Backend backend = compiler.backend;
    if (isProgramSplit && backend is JavaScriptBackend) {
      backend.registerCheckDeferredIsLoaded(compiler.globalDependencies);
    }
    if (isProgramSplit && backend is DartBackend) {
      // TODO(sigurdm): Implement deferred loading for dart2dart.
      compiler.reportWarning(
          lastDeferred,
          MessageKind.DEFERRED_LIBRARY_DART_2_DART);
      isProgramSplit = false;
    }
  }

  /// If [send] is a static send with a deferred element, returns the
  /// [PrefixElement] that the first prefix of the send resolves to.
  /// Otherwise returns null.
  ///
  /// Precondition: send must be static.
  ///
  /// Example:
  ///
  /// import "a.dart" deferred as a;
  ///
  /// main() {
  ///   print(a.loadLibrary.toString());
  ///   a.loadLibrary().then((_) {
  ///     a.run();
  ///     a.foo.method();
  ///   });
  /// }
  ///
  /// Returns null for a.loadLibrary() (the special
  /// function loadLibrary is not deferred). And returns the PrefixElement for
  /// a.run() and a.foo.
  /// a.loadLibrary.toString() and a.foo.method() are dynamic sends - and
  /// this functions should not be called on them.
  PrefixElement deferredPrefixElement(ast.Send send, TreeElements elements) {
    Element element = elements[send];
    // The DeferredLoaderGetter is not deferred, therefore we do not return the
    // prefix.
    if (element != null && element.isDeferredLoaderGetter) return null;

    ast.Node firstNode(ast.Node node) {
      if (node is! ast.Send) {
        return node;
      } else {
        ast.Send send = node;
        ast.Node receiver = send.receiver;
        ast.Node receiverFirst = firstNode(receiver);
        if (receiverFirst != null) {
          return receiverFirst;
        } else {
          return firstNode(send.selector);
        }
      }
    }
    ast.Node first = firstNode(send);
    ast.Node identifier = first.asIdentifier();
    if (identifier == null) return null;
    Element maybePrefix = elements[identifier];
    if (maybePrefix != null && maybePrefix.isPrefix) {
      PrefixElement prefixElement = maybePrefix;
      if (prefixElement.isDeferred) {
        return prefixElement;
      }
    }
    return null;
  }

  /// Returns a json-style map for describing what files that are loaded by a
  /// given deferred import.
  /// The mapping is structured as:
  /// library uri -> {"name": library name, "files": (prefix -> list of files)}
  /// Where
  ///
  /// - <library uri> is the relative uri of the library making a deferred
  ///   import
  /// - <library name> is the name of the libary, and "<unnamed>" if it is
  ///   unnamed.
  /// - <prefix> is the `as` prefix used for a given deferred import.
  /// - <list of files> is a list of the filenames the must be loaded when that
  ///   import is loaded.
  Map<String, Map<String, dynamic>> computeDeferredMap() {
    JavaScriptBackend backend = compiler.backend;
    Map<String, Map<String, dynamic>> mapping =
        new Map<String, Map<String, dynamic>>();
    _deferredImportDescriptions.keys.forEach((ast.Import import) {
      List<OutputUnit> outputUnits = hunksToLoad[importDeferName[import]];
      ImportDescription description = _deferredImportDescriptions[import];
      Map<String, dynamic> libraryMap =
          mapping.putIfAbsent(description.importingUri,
              () => <String, dynamic>{"name": description.importingLibraryName,
                                      "imports": <String, List<String>>{}});

      libraryMap["imports"][description.prefix] = outputUnits.map(
            (OutputUnit outputUnit) {
          return backend.deferredPartFileName(outputUnit.name);
        }).toList();
    });
    return mapping;
  }
}

class ImportDescription {
  /// Relative uri to the importing library.
  final String importingUri;
  /// The prefix this import is imported as.
  final String prefix;
  final LibraryElement _importingLibrary;

  ImportDescription(Import import,
                    LibraryElement importingLibrary,
                    Compiler compiler)
      : importingUri = uri_extras.relativize(
          compiler.mainApp.canonicalUri,
          importingLibrary.canonicalUri, false),
        prefix = import.prefix.source,
        _importingLibrary = importingLibrary;

  String get importingLibraryName {
    String libraryName = _importingLibrary.getLibraryName();
    return libraryName == ""
      ? "<unnamed>"
      : libraryName;
  }

}
