| Index: pkg/front_end/lib/src/base/processed_options.dart
|
| diff --git a/pkg/front_end/lib/src/base/processed_options.dart b/pkg/front_end/lib/src/base/processed_options.dart
|
| index b2e93ab6008cb4553aec0ad17fb6d3d515a3733e..a42d2b54caa8c554bb705ee450a79a3a61a8ab64 100644
|
| --- a/pkg/front_end/lib/src/base/processed_options.dart
|
| +++ b/pkg/front_end/lib/src/base/processed_options.dart
|
| @@ -4,27 +4,17 @@
|
|
|
| import 'dart:async';
|
|
|
| -import 'package:front_end/compilation_error.dart';
|
| import 'package:front_end/compiler_options.dart';
|
| import 'package:front_end/file_system.dart';
|
| -import 'package:front_end/src/base/performace_logger.dart';
|
| -import 'package:front_end/src/fasta/ticker.dart';
|
| import 'package:front_end/src/fasta/translate_uri.dart';
|
| +import 'package:front_end/src/base/performace_logger.dart';
|
| import 'package:front_end/src/incremental/byte_store.dart';
|
| -import 'package:kernel/kernel.dart'
|
| - show Program, loadProgramFromBytes, CanonicalName;
|
| -import 'package:kernel/target/targets.dart';
|
| -import 'package:kernel/target/vm_fasta.dart';
|
| +import 'package:front_end/src/simple_error.dart';
|
| import 'package:package_config/packages_file.dart' as package_config;
|
| -import 'package:source_span/source_span.dart' show SourceSpan;
|
| +import 'package:kernel/kernel.dart' show Program, loadProgramFromBytes;
|
|
|
| -/// All options needed for the front end implementation.
|
| -///
|
| -/// This includes: all of [CompilerOptions] in a form useful to the
|
| -/// implementation, default values for options that were not provided,
|
| -/// and information derived from how the compiler was invoked (like the
|
| -/// entry-points given to the compiler and whether a modular or whole-program
|
| -/// API was used).
|
| +/// Wrapper around [CompilerOptions] which exposes the options in a form useful
|
| +/// to the front end implementation.
|
| ///
|
| /// The intent is that the front end should immediately wrap any incoming
|
| /// [CompilerOptions] object in this class before doing further processing, and
|
| @@ -44,58 +34,19 @@ class ProcessedOptions {
|
| TranslateUri _uriTranslator;
|
|
|
| /// The SDK summary, or `null` if it has not been read yet.
|
| - ///
|
| - /// A summary, also referred to as "outline" internally, is a [Program] where
|
| - /// all method bodies are left out. In essence, it contains just API
|
| - /// signatures and constants. When strong-mode is enabled, the summary already
|
| - /// includes inferred types.
|
| Program _sdkSummaryProgram;
|
|
|
| /// The summary for each uri in `options.inputSummaries`.
|
| - ///
|
| - /// A summary, also referred to as "outline" internally, is a [Program] where
|
| - /// all method bodies are left out. In essence, it contains just API
|
| - /// signatures and constants. When strong-mode is enabled, the summary already
|
| - /// includes inferred types.
|
| List<Program> _inputSummariesPrograms;
|
|
|
| - /// Other programs that are meant to be linked and compiled with the input
|
| - /// sources.
|
| - List<Program> _linkedDependencies;
|
| -
|
| /// The location of the SDK, or `null` if the location hasn't been determined
|
| /// yet.
|
| Uri _sdkRoot;
|
| - Uri get sdkRoot => _sdkRoot ??= _normalizeSdkRoot();
|
| -
|
| - Uri _sdkSummary;
|
| - Uri get sdkSummary => _sdkSummary ??= _computeSdkSummaryUri();
|
|
|
| - Ticker ticker;
|
| -
|
| - bool get verbose => _raw.verbose;
|
| -
|
| - bool get verify => _raw.verify;
|
| -
|
| - bool get debugDump => _raw.debugDump;
|
| -
|
| - /// Like [CompilerOptions.chaseDependencies] but with the appropriate default
|
| - /// value filled in.
|
| - bool get chaseDependencies => _raw.chaseDependencies ?? !_modularApi;
|
| -
|
| - /// Whether the compiler was invoked with a modular API.
|
| - ///
|
| - /// Used to determine the default behavior for [chaseDependencies].
|
| - final bool _modularApi;
|
| -
|
| - /// The entry-points provided to the compiler.
|
| - final List<Uri> inputs;
|
| + Uri get sdkRoot => _sdkRoot ??= _normalizeSdkRoot();
|
|
|
| /// Initializes a [ProcessedOptions] object wrapping the given [rawOptions].
|
| - ProcessedOptions(CompilerOptions rawOptions,
|
| - [this._modularApi = false, this.inputs = const []])
|
| - : this._raw = rawOptions,
|
| - ticker = new Ticker(isVerbose: rawOptions.verbose);
|
| + ProcessedOptions(CompilerOptions rawOptions) : this._raw = rawOptions;
|
|
|
| /// The logger to report compilation progress.
|
| PerformanceLog get logger {
|
| @@ -107,40 +58,28 @@ class ProcessedOptions {
|
| return _raw.byteStore;
|
| }
|
|
|
| - // TODO(sigmund): delete. We should use messages with error codes directly
|
| - // instead.
|
| - void reportError(String message) {
|
| - _raw.onError(new _CompilationError(message));
|
| - }
|
| -
|
| /// Runs various validations checks on the input options. For instance,
|
| /// if an option is a path to a file, it checks that the file exists.
|
| Future<bool> validateOptions() async {
|
| - for (var source in inputs) {
|
| - if (source.scheme == 'file' &&
|
| - !await fileSystem.entityForUri(source).exists()) {
|
| - reportError("Entry-point file not found: $source");
|
| - return false;
|
| - }
|
| - }
|
| + var fs = _raw.fileSystem;
|
| + var root = _raw.sdkRoot;
|
|
|
| - if (_raw.sdkRoot != null &&
|
| - !await fileSystem.entityForUri(sdkRoot).exists()) {
|
| - reportError("SDK root directory not found: ${sdkRoot}");
|
| + bool _report(String msg) {
|
| + _raw.onError(new SimpleError(msg));
|
| return false;
|
| }
|
|
|
| - var summary = sdkSummary;
|
| - if (summary != null && !await fileSystem.entityForUri(summary).exists()) {
|
| - reportError("SDK summary not found: ${summary}");
|
| - return false;
|
| + if (root != null && !await fs.entityForUri(root).exists()) {
|
| + return _report("SDK root directory not found: ${_raw.sdkRoot}");
|
| }
|
|
|
| - if (compileSdk && summary != null) {
|
| - reportError(
|
| - "The compileSdk and sdkSummary options are mutually exclusive");
|
| - return false;
|
| + var summary = _raw.sdkSummary;
|
| + if (summary != null && !await fs.entityForUri(summary).exists()) {
|
| + return _report("SDK summary not found: ${_raw.sdkSummary}");
|
| }
|
| +
|
| + // TODO(sigmund): add checks for options that are meant to be disjoint (like
|
| + // sdkRoot and sdkSummary).
|
| return true;
|
| }
|
|
|
| @@ -148,67 +87,43 @@ class ProcessedOptions {
|
| /// whole-program.
|
| bool get compileSdk => _raw.compileSdk;
|
|
|
| - FileSystem _fileSystem;
|
| -
|
| /// Get the [FileSystem] which should be used by the front end to access
|
| /// files.
|
| ///
|
| /// If the client supplied roots using [CompilerOptions.multiRoots], the
|
| /// returned [FileSystem] will automatically perform the appropriate mapping.
|
| - FileSystem get fileSystem => _fileSystem ??= _createFileSystem();
|
| + FileSystem get fileSystem {
|
| + // TODO(paulberry): support multiRoots.
|
| + assert(_raw.multiRoots.isEmpty);
|
| + return _raw.fileSystem;
|
| + }
|
|
|
| /// Whether to interpret Dart sources in strong-mode.
|
| bool get strongMode => _raw.strongMode;
|
|
|
| - Target _target;
|
| - Target get target => _target ??=
|
| - _raw.target ?? new VmFastaTarget(new TargetFlags(strongMode: strongMode));
|
| -
|
| - /// Get an outline program that summarizes the SDK, if any.
|
| - // TODO(sigmund): move, this doesn't feel like an "option".
|
| - Future<Program> loadSdkSummary(CanonicalName nameRoot) async {
|
| + /// Get an outline program that summarizes the SDK.
|
| + Future<Program> get sdkSummaryProgram async {
|
| if (_sdkSummaryProgram == null) {
|
| - if (sdkSummary == null) return null;
|
| - var bytes = await fileSystem.entityForUri(sdkSummary).readAsBytes();
|
| - _sdkSummaryProgram = loadProgram(bytes, nameRoot);
|
| + if (_raw.sdkSummary == null) return null;
|
| + _sdkSummaryProgram = await _loadProgram(_raw.sdkSummary);
|
| }
|
| return _sdkSummaryProgram;
|
| }
|
|
|
| /// Get the summary programs for each of the underlying `inputSummaries`
|
| /// provided via [CompilerOptions].
|
| - // TODO(sigmund): move, this doesn't feel like an "option".
|
| - Future<List<Program>> loadInputSummaries(CanonicalName nameRoot) async {
|
| + Future<List<Program>> get inputSummariesPrograms async {
|
| if (_inputSummariesPrograms == null) {
|
| var uris = _raw.inputSummaries;
|
| if (uris == null || uris.isEmpty) return const <Program>[];
|
| - // TODO(sigmund): throttle # of concurrent opreations.
|
| - var allBytes = await Future
|
| - .wait(uris.map((uri) => fileSystem.entityForUri(uri).readAsBytes()));
|
| - _inputSummariesPrograms =
|
| - allBytes.map((bytes) => loadProgram(bytes, nameRoot)).toList();
|
| + _inputSummariesPrograms = await Future.wait(uris.map(_loadProgram));
|
| }
|
| return _inputSummariesPrograms;
|
| }
|
|
|
| - /// Load each of the [CompilerOptions.linkedDependencies] programs.
|
| - // TODO(sigmund): move, this doesn't feel like an "option".
|
| - Future<List<Program>> loadLinkDependencies(CanonicalName nameRoot) async {
|
| - if (_linkedDependencies == null) {
|
| - var uris = _raw.linkedDependencies;
|
| - if (uris == null || uris.isEmpty) return const <Program>[];
|
| - // TODO(sigmund): throttle # of concurrent opreations.
|
| - var allBytes = await Future
|
| - .wait(uris.map((uri) => fileSystem.entityForUri(uri).readAsBytes()));
|
| - _linkedDependencies =
|
| - allBytes.map((bytes) => loadProgram(bytes, nameRoot)).toList();
|
| - }
|
| - return _linkedDependencies;
|
| - }
|
| -
|
| - /// Helper to load a .dill file from [uri] using the existing [nameRoot].
|
| - Program loadProgram(List<int> bytes, CanonicalName nameRoot) {
|
| - return loadProgramFromBytes(bytes, new Program(nameRoot: nameRoot));
|
| + Future<Program> _loadProgram(Uri uri) async {
|
| + var bytes = await fileSystem.entityForUri(uri).readAsBytes();
|
| + return loadProgramFromBytes(bytes)..unbindCanonicalNames();
|
| }
|
|
|
| /// Get the [TranslateUri] which resolves "package:" and "dart:" URIs.
|
| @@ -220,19 +135,13 @@ class ProcessedOptions {
|
| await _getPackages();
|
| // TODO(scheglov) Load SDK libraries from whatever format we decide.
|
| // TODO(scheglov) Remove the field "_raw.dartLibraries".
|
| - var libraries = _raw.dartLibraries ?? await _parseLibraries();
|
| - _uriTranslator =
|
| - new TranslateUri(_packages, libraries, const <String, List<Uri>>{});
|
| - ticker.logMs("Read packages file");
|
| + _uriTranslator = new TranslateUri(
|
| + _packages, _raw.dartLibraries, const <String, List<Uri>>{});
|
| + _uriTranslator.dartLibraries.addAll(_raw.dartLibraries);
|
| }
|
| return _uriTranslator;
|
| }
|
|
|
| - Future<Map<String, Uri>> _parseLibraries() async {
|
| - Uri librariesJson = _raw.sdkRoot?.resolve("lib/libraries.json");
|
| - return await computeLibraries(fileSystem, librariesJson);
|
| - }
|
| -
|
| /// Get the package map which maps package names to URIs.
|
| ///
|
| /// This is an asynchronous getter since file system operations may be
|
| @@ -240,8 +149,7 @@ class ProcessedOptions {
|
| Future<Map<String, Uri>> _getPackages() async {
|
| if (_packages == null) {
|
| if (_raw.packagesFileUri == null) {
|
| - // TODO(sigmund,paulberry): implement
|
| - throw new UnimplementedError('search for .packages');
|
| + throw new UnimplementedError(); // TODO(paulberry): search for .packages
|
| } else if (_raw.packagesFileUri.path.isEmpty) {
|
| _packages = {};
|
| } else {
|
| @@ -254,6 +162,9 @@ class ProcessedOptions {
|
| }
|
|
|
| /// Get the location of the SDK.
|
| + ///
|
| + /// This is an asynchronous getter since file system operations may be
|
| + /// required to locate the SDK.
|
| Uri _normalizeSdkRoot() {
|
| // If an SDK summary location was provided, the SDK itself should not be
|
| // needed.
|
| @@ -261,89 +172,12 @@ class ProcessedOptions {
|
| if (_raw.sdkRoot == null) {
|
| // TODO(paulberry): implement the algorithm for finding the SDK
|
| // automagically.
|
| - throw new UnimplementedError('infer the default sdk location');
|
| + throw new UnimplementedError();
|
| }
|
| var root = _raw.sdkRoot;
|
| if (!root.path.endsWith('/')) {
|
| - root = root.replace(path: root.path + '/');
|
| + root = root.replace(path: _sdkRoot.path + '/');
|
| }
|
| return root;
|
| }
|
| -
|
| - /// Get or infer the location of the SDK summary.
|
| - Uri _computeSdkSummaryUri() {
|
| - if (_raw.sdkSummary != null) return _raw.sdkSummary;
|
| -
|
| - // Infer based on the sdkRoot, but only when `compileSdk` is false,
|
| - // otherwise the default intent was to compile the sdk from sources and not
|
| - // to load an sdk summary file.
|
| - if (_raw.compileSdk) return null;
|
| - return sdkRoot.resolve('outline.dill');
|
| - }
|
| -
|
| - /// Create a [FileSystem] specific to the current options.
|
| - ///
|
| - /// If [chaseDependencies] is false, the resulting file system will be
|
| - /// hermetic.
|
| - FileSystem _createFileSystem() {
|
| - var result = _raw.fileSystem;
|
| - if (!chaseDependencies) {
|
| - var allInputs = inputs.toSet();
|
| - allInputs.addAll(_raw.inputSummaries);
|
| - allInputs.addAll(_raw.linkedDependencies);
|
| -
|
| - if (sdkSummary != null) allInputs.add(sdkSummary);
|
| -
|
| - if (_raw.sdkRoot != null) {
|
| - // TODO(sigmund): refine this, we should be more explicit about when
|
| - // sdkRoot and libraries.json are allowed to be used.
|
| - allInputs.add(sdkRoot);
|
| - allInputs.add(sdkRoot.resolve("lib/libraries.json"));
|
| - }
|
| -
|
| - /// Note: Searching the file-system for the package-config is not
|
| - /// supported in hermetic builds.
|
| - if (_raw.packagesFileUri != null) allInputs.add(_raw.packagesFileUri);
|
| - result = new HermeticFileSystem(allInputs, result);
|
| - }
|
| - // TODO(paulberry): support multiRoots.
|
| - assert(_raw.multiRoots.isEmpty);
|
| - return result;
|
| - }
|
| -}
|
| -
|
| -/// A [FileSystem] that only allows access to files that have been explicitly
|
| -/// whitelisted.
|
| -class HermeticFileSystem implements FileSystem {
|
| - final Set<Uri> includedFiles;
|
| - final FileSystem _realFileSystem;
|
| -
|
| - HermeticFileSystem(this.includedFiles, this._realFileSystem);
|
| -
|
| - FileSystemEntity entityForUri(Uri uri) {
|
| - if (includedFiles.contains(uri)) return _realFileSystem.entityForUri(uri);
|
| - throw new HermeticAccessException(uri);
|
| - }
|
| -}
|
| -
|
| -class HermeticAccessException extends FileSystemException {
|
| - HermeticAccessException(Uri uri)
|
| - : super(
|
| - uri,
|
| - 'Invalid access to $uri: '
|
| - 'the file is accessed in a modular hermetic build, '
|
| - 'but it was not explicitly listed as an input.');
|
| -
|
| - @override
|
| - String toString() => message;
|
| -}
|
| -
|
| -/// An error that only contains a message and no error location.
|
| -class _CompilationError implements CompilationError {
|
| - String get correction => null;
|
| - SourceSpan get span => null;
|
| - final String message;
|
| - _CompilationError(this.message);
|
| -
|
| - String toString() => message;
|
| }
|
|
|