Unifying compiler context

Changes in this CL:
 - Updated CompilerContext:
    - it now contains a ProcessedOptions object

    - it no longer depends on CompilerCommandLine/CommandLine

    - it delegates to ProcessedOptions.report so all error reporting
      goes to one single place.

    - use "withContext" term instead of "withGlobalOptions" to be
      more clear about the intent

 - Changes in public API
    - added more options that correspond to flags in command-line
      fasta tools

    - default onError is different: we now use the
      command_line_reporting report, which prints and throws
      on fatal messages, but doesn't throw eagerly on all messages
      as before.

    - introduced "printMessages" option: make it easy to have
      both onError + command_line_reporting  (kernel-service.dart
      is the main use case at this time, other ideas welcome!)

    - renamed CompilationError to CompilationMessage

 - Other changes

    - set exit code is done on report, not on format
    - fixed corner cases not covered in previous CL
        - error reporting with missing-main needs to happen with
          a context
        - missing error cases when inferring .packages and input
          URIs are not file:* URIs

Ideas for follow up after this CL:
 - combine ProcessedOptions and CompilerContext into a single class
   (or extend one from the other)
 - switch onError to a stream

R=ahe@google.com

Review-Url: https://codereview.chromium.org/2982093003 .
This commit is contained in:
Sigmund Cherem 2017-07-18 17:02:55 -07:00
parent 749b61f8ec
commit 1aa139bc94
27 changed files with 509 additions and 351 deletions

View file

@ -17,7 +17,6 @@ import 'package:analyzer/src/generated/scanner.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/generated/utilities_dart.dart';
import 'package:front_end/src/base/instrumentation.dart' as fasta;
import 'package:front_end/src/fasta/compiler_command_line.dart' as fasta;
import 'package:front_end/src/fasta/compiler_context.dart' as fasta;
import 'package:front_end/src/fasta/testing/validating_instrumentation.dart'
as fasta;
@ -135,7 +134,7 @@ class _ElementNamer {
class _FrontEndInferenceTest extends BaseAnalysisDriverTest {
Future<String> runTest(String path, String code) {
return fasta.CompilerCommandLine.withGlobalOptions("", [""], (_) async {
return fasta.CompilerContext.runWithDefaultOptions((_) async {
Uri uri = provider.pathContext.toUri(path);
List<int> lineStarts = new LineInfo.fromContent(code).lineStarts;

View file

@ -23,8 +23,8 @@ main(List<String> args) async {
..target = new Dart2jsTarget(new TargetFlags())
..packagesFileUri = Uri.base.resolve('.packages')
..compileSdk = true
..linkedDependencies = [Uri.base.resolve(flags['platform'])]
..onError = errorHandler;
..setExitCodeOnProblem = true
..linkedDependencies = [Uri.base.resolve(flags['platform'])];
if (flags.rest.isEmpty) {
var script = relativizeUri(Platform.script);
@ -39,11 +39,6 @@ main(List<String> args) async {
await writeProgramToBinary(program, flags['out']);
}
void errorHandler(CompilationError e) {
exitCode = 1;
print(e.message);
}
ArgParser _argParser = new ArgParser()
..addOption('platform',
help: 'location of the precompiled dart2js sdk',

View file

@ -1,28 +0,0 @@
// Copyright (c) 2016, 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.
/// Defines the API for the front end to communicate information about
/// compilation errors to clients.
library front_end.compilation_error;
import 'package:source_span/source_span.dart' show SourceSpan;
/// A single error that occurred during compilation, and information about where
/// it occurred and how to fix it.
///
/// TODO(paulberry): add a reference to the analyzer error code.
///
/// Not intended to be implemented or extended by clients.
// TODO(sigmund): rename to CompliationMessage
abstract class CompilationError {
/// A text description of the compile error.
String get message;
/// A suggestion for the user to hint them on how to fix the error. May be
/// `null`.
String get tip;
/// The source span where the error occurred.
SourceSpan get span;
}

View file

@ -0,0 +1,38 @@
// Copyright (c) 2016, 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.
/// Defines the API for the front end to communicate information about
/// compilation messages to clients.
library front_end.compilation_message;
import 'package:source_span/source_span.dart' show SourceSpan;
import 'package:front_end/src/fasta/severity.dart' show Severity;
export 'package:front_end/src/fasta/severity.dart' show Severity;
/// A single message, typically an error, reported during compilation, and
/// information about where it occurred and suggestions on how to fix it.
///
/// Not intended to be implemented or extended by clients.
abstract class CompilationMessage {
/// A text description of the problem.
String get message;
/// A suggestion for how to fix the problem. May be `null`.
String get tip;
/// The source span where the error occurred.
SourceSpan get span;
/// The severity level of the error.
Severity get severity;
/// The corresponding analyzer error code, or null if there is no
/// corresponding message in analyzer.
String get analyzerCode;
/// The corresponding dart2js error code, or null if there is no corresponding
/// message in dart2js.
String get dart2jsCode;
}

View file

@ -8,15 +8,12 @@ import 'package:front_end/src/base/performace_logger.dart';
import 'package:front_end/src/incremental/byte_store.dart';
import 'package:kernel/target/targets.dart' show Target;
import 'compilation_error.dart';
import 'compilation_message.dart';
import 'file_system.dart';
import 'physical_file_system.dart';
/// Default error handler used by [CompilerOptions.onError].
void defaultErrorHandler(CompilationError error) => throw error;
/// Callback used to report errors encountered during compilation.
typedef void ErrorHandler(CompilationError error);
typedef void ErrorHandler(CompilationMessage error);
/// Front-end options relevant to compiler back ends.
///
@ -43,9 +40,21 @@ class CompilerOptions {
/// Callback to which compilation errors should be delivered.
///
/// By default, the first error will be reported by throwing an exception of
/// type [CompilationError].
ErrorHandler onError = defaultErrorHandler;
/// By default, when no callback is provided, the compiler will report
/// messages on the console and will throw when fatal errors are discovered.
ErrorHandler onError;
/// Whether messages should be reported using the compiler's internal
/// reporting mechanism.
///
/// If no [onError] handler is provided, the default is true. If an [onError]
/// handler is provided, the default is false. Setting this to true will
/// ensure that error messages are printed in the console and that fatal
/// errors cause an exception.
// TODO(sigmund): add also an API for formatting errors and provide a default
// formatter. This way user can configure error style in the console and in
// generated code that contains error messages.
bool reportMessages;
/// URI of the ".packages" file (typically a "file:" URI).
///
@ -197,4 +206,30 @@ class CompilerOptions {
/// Whether to set the exit code to non-zero if any problem (including
/// warning, etc.) is encountered during compilation.
bool setExitCodeOnProblem = false;
/// Whether to embed the input sources in generated kernel programs.
///
/// The kernel `Program` API includes a `uriToSource` map field that is used
/// to embed the entire contents of the source files. This part of the kernel
/// API is in flux and it is not necessary for some tools. Today it is used
/// for translating error locations and stack traces in the VM.
// TODO(sigmund): change the default.
bool embedSourceText = true;
/// Whether the compiler should throw as soon as it encounters a
/// compilation error.
// TODO(sigmund): change the default (issue #30194).
bool throwOnErrors = true;
/// Whether the compiler should throw as soon as it encounters a
/// compilation warning.
///
/// Typically used by developers to debug internals of the compiler.
bool throwOnWarnings = false;
/// Whether the compiler should throw as soon as it encounters a
/// compilation nit.
///
/// Typically used by developers to debug internals of the compiler.
bool throwOnNits = false;
}

View file

@ -8,7 +8,7 @@
library front_end.front_end;
export 'compiler_options.dart';
export 'compilation_error.dart';
export 'compilation_message.dart';
export 'kernel_generator.dart';
export 'summary_generator.dart';
export 'file_system.dart';

View file

@ -13,6 +13,8 @@ import 'package:kernel/kernel.dart' show Program;
import 'compiler_options.dart';
import 'src/base/processed_options.dart';
import 'src/fasta/fasta_codes.dart';
import 'src/fasta/compiler_context.dart';
import 'src/fasta/severity.dart';
import 'src/kernel_generator_impl.dart';
/// Generates a kernel representation of the program whose main library is in
@ -37,15 +39,17 @@ import 'src/kernel_generator_impl.dart';
// TODO(sigmund): rename to kernelForScript?
Future<Program> kernelForProgram(Uri source, CompilerOptions options) async {
var pOptions = new ProcessedOptions(options, false, [source]);
var program = (await generateKernel(pOptions))?.program;
if (program == null) return null;
return await CompilerContext.runWithOptions(pOptions, (context) async {
var program = (await generateKernelInternal())?.program;
if (program == null) return null;
if (program.mainMethod == null) {
pOptions.reportMessage(messageMissingMain.withLocation(source, -1));
return null;
}
return program;
if (program.mainMethod == null) {
context.options
.report(messageMissingMain.withLocation(source, -1), Severity.error);
return null;
}
return program;
});
}
/// Generates a kernel representation for a build unit containing [sources].

View file

@ -4,15 +4,16 @@
import 'dart:async';
import 'package:front_end/compilation_error.dart';
import 'package:front_end/compilation_message.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/fasta_codes.dart';
import 'package:front_end/src/fasta/problems.dart' show unimplemented;
import 'package:front_end/src/fasta/severity.dart';
import 'package:front_end/src/fasta/ticker.dart';
import 'package:front_end/src/fasta/uri_translator.dart';
import 'package:front_end/src/fasta/uri_translator_impl.dart';
import 'package:front_end/src/fasta/problems.dart' show unimplemented;
import 'package:front_end/src/incremental/byte_store.dart';
import 'package:front_end/src/multi_root_file_system.dart';
import 'package:kernel/kernel.dart'
@ -24,6 +25,8 @@ import 'package:package_config/src/packages_impl.dart'
show NonFilePackagesDirectoryPackages, MapPackages;
import 'package:package_config/packages_file.dart' as package_config;
import 'package:source_span/source_span.dart' show SourceSpan, SourceLocation;
import 'package:front_end/src/fasta/command_line_reporting.dart'
as command_line_reporting;
/// All options needed for the front end implementation.
///
@ -88,6 +91,14 @@ class ProcessedOptions {
bool get setExitCodeOnProblem => _raw.setExitCodeOnProblem;
bool get embedSourceText => _raw.embedSourceText;
bool get throwOnErrors => _raw.throwOnErrors;
bool get throwOnWarnings => _raw.throwOnWarnings;
bool get throwOnNits => _raw.throwOnNits;
/// Like [CompilerOptions.chaseDependencies] but with the appropriate default
/// value filled in.
bool get chaseDependencies => _raw.chaseDependencies ?? !_modularApi;
@ -100,10 +111,15 @@ class ProcessedOptions {
/// The entry-points provided to the compiler.
final List<Uri> inputs;
/// The Uri where output is generated, may be null.
final Uri output;
/// Initializes a [ProcessedOptions] object wrapping the given [rawOptions].
ProcessedOptions(CompilerOptions rawOptions,
[this._modularApi = false, this.inputs = const []])
[this._modularApi = false, this.inputs = const [], this.output])
: this._raw = rawOptions,
// TODO(sigmund, ahe): create ticker even earlier or pass in a stopwatch
// collecting time since the start of the VM.
ticker = new Ticker(isVerbose: rawOptions.verbose);
/// The logger to report compilation progress.
@ -116,18 +132,34 @@ class ProcessedOptions {
return _raw.byteStore;
}
void reportMessage(LocatedMessage message) {
_raw.onError(new _CompilationMessage(message));
bool get _reportMessages => _raw.reportMessages ?? (_raw.onError == null);
void report(LocatedMessage message, Severity severity) {
if (_raw.onError != null) {
_raw.onError(new _CompilationMessage(message, severity));
}
if (_reportMessages) command_line_reporting.report(message, severity);
}
void reportMessageWithoutLocation(Message message) =>
reportMessage(message.withLocation(null, -1));
void reportWithoutLocation(Message message, Severity severity) {
if (_raw.onError != null) {
_raw.onError(
new _CompilationMessage(message.withLocation(null, -1), severity));
}
if (_reportMessages) {
command_line_reporting.reportWithoutLocation(message, severity);
}
}
/// 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 {
if (verbose) print(debugString());
if (inputs.isEmpty) {
reportMessageWithoutLocation(messageMissingInput);
reportWithoutLocation(messageMissingInput, Severity.error);
return false;
}
@ -140,30 +172,31 @@ class ProcessedOptions {
if (source.scheme != 'dart' &&
source.scheme != 'packages' &&
!await fileSystem.entityForUri(source).exists()) {
reportMessageWithoutLocation(
templateInputFileNotFound.withArguments('$source'));
reportWithoutLocation(
templateInputFileNotFound.withArguments('$source'), Severity.error);
return false;
}
}
if (_raw.sdkRoot != null &&
!await fileSystem.entityForUri(sdkRoot).exists()) {
reportMessageWithoutLocation(
templateSdkRootNotFound.withArguments('$sdkRoot'));
reportWithoutLocation(
templateSdkRootNotFound.withArguments('$sdkRoot'), Severity.error);
return false;
}
var summary = sdkSummary;
if (summary != null && !await fileSystem.entityForUri(summary).exists()) {
reportMessageWithoutLocation(
templateSdkSummaryNotFound.withArguments('$summary'));
reportWithoutLocation(
templateSdkSummaryNotFound.withArguments('$summary'), Severity.error);
return false;
}
if (compileSdk && summary != null) {
reportMessageWithoutLocation(
reportWithoutLocation(
templateInternalProblemUnsupported.withArguments(
"The compileSdk and sdkSummary options are mutually exclusive"));
"The compileSdk and sdkSummary options are mutually exclusive"),
Severity.internalProblem);
return false;
}
return true;
@ -263,21 +296,31 @@ class ProcessedOptions {
/// This is an asynchronous getter since file system operations may be
/// required to locate/read the packages file.
Future<Packages> _getPackages() async {
if (_packages == null) {
if (_raw.packagesFileUri == null) {
if (inputs.length > 1) {
// TODO(sigmund): consider not reporting an error if we would infer
// the same .packages file from all of the inputs.
reportMessageWithoutLocation(messageCantInferPackagesFromManyInputs);
_packages = Packages.noPackages;
} else {
_packages = await _findPackages(inputs.first);
}
} else {
_packages = await createPackagesFromFile(_raw.packagesFileUri);
}
if (_packages != null) return _packages;
if (_raw.packagesFileUri != null) {
return _packages = await createPackagesFromFile(_raw.packagesFileUri);
}
return _packages;
if (inputs.length > 1) {
// TODO(sigmund): consider not reporting an error if we would infer
// the same .packages file from all of the inputs.
reportWithoutLocation(
messageCantInferPackagesFromManyInputs, Severity.error);
return _packages = Packages.noPackages;
}
var input = inputs.first;
// When compiling the SDK the input files are normaly `dart:` URIs.
if (input.scheme == 'dart') return _packages = Packages.noPackages;
if (input.scheme == 'packages') {
report(messageCantInferPackagesFromPackageUri.withLocation(input, -1),
Severity.error);
return _packages = Packages.noPackages;
}
return _packages = await _findPackages(inputs.first);
}
/// Create a [Packages] given the Uri to a `.packages` file.
@ -287,9 +330,11 @@ class ProcessedOptions {
Map<String, Uri> map = package_config.parse(contents, file);
return new MapPackages(map);
} catch (e) {
reportMessage(templateCannotReadPackagesFile
.withArguments("$e")
.withLocation(file, -1));
report(
templateCannotReadPackagesFile
.withArguments("$e")
.withLocation(file, -1),
Severity.error);
return Packages.noPackages;
}
}
@ -318,8 +363,10 @@ class ProcessedOptions {
Future<Packages> _findPackages(Uri scriptUri) async {
var dir = scriptUri.resolve('.');
if (!dir.isAbsolute) {
reportMessageWithoutLocation(templateInternalProblemUnsupported
.withArguments("Expected input Uri to be absolute: $scriptUri."));
reportWithoutLocation(
templateInternalProblemUnsupported
.withArguments("Expected input Uri to be absolute: $scriptUri."),
Severity.internalProblem);
return Packages.noPackages;
}
@ -413,6 +460,56 @@ class ProcessedOptions {
}
return result;
}
String debugString() {
var sb = new StringBuffer();
writeList(String name, List elements) {
if (elements.isEmpty) {
sb.writeln('$name: <empty>');
return;
}
sb.writeln('$name:');
elements.forEach((s) {
sb.writeln(' - $s');
});
}
sb.writeln('Inputs: ${inputs}');
sb.writeln('Output: ${output}');
sb.writeln('Was error handler provided: '
'${_raw.onError == null ? "no" : "yes"}');
sb.writeln('FileSystem: ${_fileSystem.runtimeType} '
'(provided: ${_raw.fileSystem.runtimeType})');
writeList('Input Summaries', _raw.inputSummaries);
writeList('Linked Dependencies', _raw.linkedDependencies);
writeList('Multiroots', _raw.multiRoots);
sb.writeln('Modular: ${_modularApi}');
sb.writeln('Hermetic: ${!chaseDependencies}'
' (provided: ${!_raw.chaseDependencies})');
sb.writeln('Packages uri: ${_raw.packagesFileUri}');
sb.writeln('Packages: ${_packages}');
sb.writeln('Compile SDK: ${compileSdk}');
sb.writeln('SDK root: ${_sdkRoot} (provided: ${_raw.sdkRoot})');
sb.writeln('SDK summary: ${_sdkSummary} (provided: ${_raw.sdkSummary})');
sb.writeln('Strong: ${strongMode}');
sb.writeln('Target: ${_target?.name} (provided: ${_raw.target?.name})');
sb.writeln('throwOnErrorsAreFatal: ${throwOnErrors}');
sb.writeln('throwOnWarningsAreFatal: ${throwOnWarnings}');
sb.writeln('throwOnNits: ${throwOnNits}');
sb.writeln('exit on problem: ${setExitCodeOnProblem}');
sb.writeln('Embed sources: ${embedSourceText}');
sb.writeln('debugDump: ${debugDump}');
sb.writeln('verbose: ${verbose}');
sb.writeln('verify: ${verify}');
return '$sb';
}
}
/// A [FileSystem] that only allows access to files that have been explicitly
@ -441,19 +538,24 @@ class HermeticAccessException extends FileSystemException {
String toString() => message;
}
/// Wraps a [LocatedMessage] to implement the public [CompilationError] API.
class _CompilationMessage implements CompilationError {
final LocatedMessage original;
/// Wraps a [LocatedMessage] to implement the public [CompilationMessage] API.
class _CompilationMessage implements CompilationMessage {
final LocatedMessage _original;
final Severity severity;
String get message => original.message;
String get message => _original.message;
String get tip => original.tip;
String get tip => _original.tip;
String get analyzerCode => _original.code.analyzerCode;
String get dart2jsCode => _original.code.dart2jsCode;
SourceSpan get span =>
new SourceLocation(original.charOffset, sourceUrl: original.uri)
new SourceLocation(_original.charOffset, sourceUrl: _original.uri)
.pointSpan();
_CompilationMessage(this.original);
_CompilationMessage(this._original, this.severity);
String toString() => message;
}

View file

@ -27,6 +27,7 @@ class ParsedArguments {
toString() => "ParsedArguments($options, $arguments)";
}
/// Abstract parser for command-line options.
class CommandLine {
final Map<String, dynamic> options;

View file

@ -34,16 +34,9 @@ const bool hideWarnings = false;
/// command-line tool. This includes source snippets and different colors based
/// on [severity].
///
/// It is a assumed that a formatted message is reported to a user, so
/// [exitCode] is also set depending on the value of
/// `CompilerContext.current.options.setExitCodeOnProblem`.
///
/// This is shared implementation used by methods below, and isn't intended to
/// be called directly.
String formatInternal(Message message, Severity severity, Uri uri, int offset) {
if (CompilerContext.current.options.setExitCodeOnProblem) {
exitCode = 1;
}
String text =
"${severityName(severity, capitalized: true)}: ${message.message}";
if (message.tip != null) {
@ -107,16 +100,16 @@ bool isHidden(Severity severity) {
bool isFatal(Severity severity) {
switch (severity) {
case Severity.error:
return CompilerContext.current.options.errorsAreFatal;
return CompilerContext.current.options.throwOnErrors;
case Severity.internalProblem:
return true;
case Severity.nit:
return CompilerContext.current.options.nitsAreFatal;
return CompilerContext.current.options.throwOnNits;
case Severity.warning:
return CompilerContext.current.options.warningsAreFatal;
return CompilerContext.current.options.throwOnWarnings;
}
return unhandled("$severity", "isFatal", -1, null);
}
@ -139,11 +132,25 @@ String severityName(Severity severity, {bool capitalized: false}) {
return unhandled("$severity", "severityName", -1, null);
}
/// Print a formatted message and throw when errors are treated as fatal.
/// Also set [exitCode] depending on the value of
/// `CompilerContext.current.options.setExitCodeOnProblem`.
void _printAndThrowIfFatal(
String text, Severity severity, Uri uri, int charOffset) {
// I believe we should only set it if we are reporting something, if we are
// formatting to embed the error in the program, then we probably don't want
// to do it in format.
// Note: I also want to limit dependencies to dart:io for when we use the FE
// outside of the VM. This default reporting is likely not going to be used in
// that context, but the default formatter is.
if (CompilerContext.current.options.setExitCodeOnProblem) {
exitCode = 1;
}
print(text);
if (isFatal(severity)) {
if (isVerbose) print(StackTrace.current);
// TODO(sigmund,ahe): ensure there is no circularity when InputError is
// handled.
throw new deprecated_InputError(uri, charOffset,
"Compilation aborted due to fatal ${severityName(severity)}.");
}

View file

@ -8,11 +8,7 @@ import 'dart:async' show Future;
import 'dart:io' show exitCode, File;
import '../../compiler_options.dart' show CompilerOptions;
import '../base/processed_options.dart' show ProcessedOptions;
import '../kernel_generator_impl.dart' show generateKernel;
import '../kernel_generator_impl.dart' show generateKernelInternal;
import 'compiler_command_line.dart' show CompilerCommandLine;
@ -24,8 +20,6 @@ import 'kernel/utils.dart' show writeProgramToFile;
import 'severity.dart' show Severity;
import 'ticker.dart' show Ticker;
const int iterations = const int.fromEnvironment("iterations", defaultValue: 1);
Future mainEntryPoint(List<String> arguments) async {
@ -37,54 +31,44 @@ Future mainEntryPoint(List<String> arguments) async {
await compilePlatform(arguments);
} on deprecated_InputError catch (e) {
exitCode = 1;
CompilerCommandLine.deprecated_withDefaultOptions(() => CompilerContext
.current
.report(deprecated_InputError.toMessage(e), Severity.error));
CompilerContext.runWithDefaultOptions(
(c) => c.report(deprecated_InputError.toMessage(e), Severity.error));
return null;
}
}
}
Future compilePlatform(List<String> arguments) async {
Ticker ticker = new Ticker();
await CompilerCommandLine.withGlobalOptions("compile_platform", arguments,
(CompilerContext c) {
Uri patchedSdk = Uri.base.resolveUri(new Uri.file(c.options.arguments[0]));
Uri fullOutput = Uri.base.resolveUri(new Uri.file(c.options.arguments[1]));
Uri outlineOutput =
Uri.base.resolveUri(new Uri.file(c.options.arguments[2]));
return compilePlatformInternal(
c, ticker, patchedSdk, fullOutput, outlineOutput);
await CompilerCommandLine
.withGlobalOptions("compile_platform", arguments, false,
(CompilerContext c, List<String> restArguments) {
c.options.inputs.add(Uri.parse('dart:core'));
// Note: the patchedSdk argument is already stored in c.options.sdkRoot.
Uri fullOutput = Uri.base.resolveUri(new Uri.file(restArguments[1]));
Uri outlineOutput = Uri.base.resolveUri(new Uri.file(restArguments[2]));
return compilePlatformInternal(c, fullOutput, outlineOutput);
});
}
Future compilePlatformInternal(CompilerContext c, Ticker ticker, Uri patchedSdk,
Uri fullOutput, Uri outlineOutput) async {
var options = new CompilerOptions()
..strongMode = c.options.strongMode
..sdkRoot = patchedSdk
..packagesFileUri = c.options.packages
..compileSdk = true
..chaseDependencies = true
..target = c.options.target
..debugDump = c.options.dumpIr
..verify = c.options.verify
..verbose = c.options.verbose;
if (options.strongMode) {
Future compilePlatformInternal(
CompilerContext c, Uri fullOutput, Uri outlineOutput) async {
if (c.options.strongMode) {
print("Note: strong mode support is preliminary and may not work.");
}
if (options.verbose) {
print("Generating outline of $patchedSdk into $outlineOutput");
print("Compiling $patchedSdk to $fullOutput");
if (c.options.verbose) {
print("Generating outline of ${c.options.sdkRoot} into $outlineOutput");
print("Compiling ${c.options.sdkRoot} to $fullOutput");
}
var result = await generateKernel(
new ProcessedOptions(options, false, [Uri.parse('dart:core')]),
buildSummary: true,
buildProgram: true);
var result =
await generateKernelInternal(buildSummary: true, buildProgram: true);
if (result == null) {
// Note: an error should have been reported by now.
print('The platform .dill files were not created.');
return;
}
new File.fromUri(outlineOutput).writeAsBytesSync(result.summary);
ticker.logMs("Wrote outline to ${outlineOutput.toFilePath()}");
c.options.ticker.logMs("Wrote outline to ${outlineOutput.toFilePath()}");
await writeProgramToFile(result.program, fullOutput);
ticker.logMs("Wrote program to ${fullOutput.toFilePath()}");
c.options.ticker.logMs("Wrote program to ${fullOutput.toFilePath()}");
}

View file

@ -6,27 +6,22 @@ library fasta.compiler_command_line;
import 'dart:io' show exit;
import 'dart:async' show runZoned;
import 'package:kernel/target/targets.dart'
show Target, getTarget, TargetFlags, targets;
import '../../compiler_options.dart';
import '../base/processed_options.dart';
import 'command_line.dart' show CommandLine, deprecated_argumentError;
import 'compiler_context.dart' show CompilerContext, compilerContextKey;
import 'command_line_reporting.dart' as command_line_reporting;
import 'compiler_context.dart' show CompilerContext;
import 'fasta_codes.dart'
show
LocatedMessage,
Message,
messageFastaUsageLong,
messageFastaUsageShort,
templateUnspecified;
import 'severity.dart' show Severity;
const Map<String, dynamic> optionSpecification = const <String, dynamic>{
"--compile-sdk": Uri,
"--fatal": ",",
@ -39,6 +34,8 @@ const Map<String, dynamic> optionSpecification = const <String, dynamic>{
"-t": String,
};
/// Parser for options accepted by the `fasta` command-line tools.
// TODO(ahe,sigmund): move this and other tools under pkg/front_end/tool/
class CompilerCommandLine extends CommandLine {
final String programName;
@ -61,13 +58,9 @@ class CompilerCommandLine extends CommandLine {
options.containsKey("/?");
}
bool get setExitCodeOnProblem {
return options.containsKey("--set-exit-code-on-problem");
}
void validate() {
if (help) {
print(computeUsage(programName, verbose));
print(computeUsage(programName, verbose).message);
exit(0);
}
@ -84,8 +77,16 @@ class CompilerCommandLine extends CommandLine {
return deprecated_argumentError(
usage, "Can't specify both '--compile-sdk' and '--platform'.");
}
if (programName == "compile_platform" && arguments.length != 3) {
return deprecated_argumentError(usage, "Expected three arguments.");
if (programName == "compile_platform") {
if (arguments.length != 3) {
return deprecated_argumentError(usage, "Expected three arguments.");
}
if (options.containsKey("--compile-sdk")) {
return deprecated_argumentError(usage,
"Cannot specify '--compile-sdk' option to compile_platform.");
}
options['--compile-sdk'] =
Uri.base.resolveUri(new Uri.file(arguments[0]));
} else if (arguments.isEmpty) {
return deprecated_argumentError(usage, "No Dart file specified.");
}
@ -113,7 +114,7 @@ class CompilerCommandLine extends CommandLine {
: options["--platform"] ?? Uri.base.resolve("platform.dill");
}
Uri get packages => options["--packages"] ?? Uri.base.resolve(".packages");
Uri get packages => options["--packages"];
Uri get sdk => options["--sdk"] ?? options["--compile-sdk"];
@ -135,43 +136,41 @@ class CompilerCommandLine extends CommandLine {
Target get target => options["target"];
void Function(LocatedMessage, Severity) get report {
return options["report"] ?? command_line_reporting.report;
}
static dynamic withGlobalOptions(
String programName,
List<String> arguments,
bool areRestArgumentsInputs,
dynamic f(CompilerContext context, List<String> restArguments)) {
// TODO(sigmund,ahe): delete this wrapper by moving validation into the
// callback. Note that this requires some subtle changes because validate
// sets some implicit options (like --compile-sdk in compile_platform).
var cl = CompilerContext.runWithDefaultOptions(
(_) => new CompilerCommandLine(programName, arguments));
var options = new CompilerOptions()
..compileSdk = cl.options.containsKey("--compile-sdk")
..sdkRoot = cl.sdk
..sdkSummary = cl.platform
..packagesFileUri = cl.packages
..strongMode = cl.strongMode
..target = cl.target
..throwOnErrors = cl.errorsAreFatal
..throwOnWarnings = cl.warningsAreFatal
..throwOnNits = cl.nitsAreFatal
..embedSourceText = !cl.excludeSource
// All command-line tools take only a single entry point and chase
// dependencies, and provide a non-zero exit code when errors are found.
..chaseDependencies = true
..setExitCodeOnProblem = true
..debugDump = cl.dumpIr
..verbose = cl.verbose
..verify = cl.verify;
void Function(Message, Severity) get reportWithoutLocation {
return options["reportWithoutLocation"] ??
command_line_reporting.reportWithoutLocation;
}
String Function(LocatedMessage, Severity) get format {
return options["format"] ?? command_line_reporting.format;
}
String Function(Message, Severity) get formatWithoutLocation {
return options["formatWithoutLocation"] ??
command_line_reporting.formatWithoutLocation;
}
static dynamic withGlobalOptions(String programName, List<String> arguments,
dynamic f(CompilerContext context)) {
CompilerCommandLine cl = deprecated_withDefaultOptions(
() => new CompilerCommandLine(programName, arguments));
return CompilerContext.withGlobalOptions(cl, f);
}
// TODO(sigmund, ahe): delete. We use this to wrap places where we require a
// context but we shoudln't. Right now this includes:
// - constructor calls to CompilerCommandLine (because it is calling
// [validate] which may report errors). This should be fixed by doing
// validation after creating these objects.
// - top-level try-catch in command-line tools that capture
// deprecated_InputError, and then report errors using fasta's error
// reporting mechanism. Those should be unnecessary once we get rid of all
// deprecated_InputErrors.
static dynamic deprecated_withDefaultOptions(dynamic f()) {
var defaultContext = new CompilerContext(new CompilerCommandLine("", [""]));
return runZoned(f, zoneValues: {compilerContextKey: defaultContext});
var inputs = <Uri>[];
if (areRestArgumentsInputs) {
inputs = cl.arguments.map(Uri.base.resolve).toList();
}
var pOptions = new ProcessedOptions(options, false, inputs, cl.output);
return CompilerContext.runWithOptions(pOptions, (c) => f(c, cl.arguments));
}
}

View file

@ -6,12 +6,12 @@ library fasta.compiler_context;
import 'dart:async' show Zone, runZoned;
import 'package:front_end/compiler_options.dart';
import 'package:front_end/file_system.dart';
import 'package:front_end/physical_file_system.dart';
import 'package:front_end/src/base/processed_options.dart';
import 'package:front_end/src/fasta/fasta_codes.dart';
import 'package:kernel/ast.dart' show Source;
import 'compiler_command_line.dart' show CompilerCommandLine;
import 'command_line_reporting.dart' as command_line_reporting;
import 'colors.dart' show computeEnableColors;
@ -21,13 +21,28 @@ import 'severity.dart' show Severity;
final Object compilerContextKey = new Object();
/// Shared context used throughout the compiler.
///
/// The compiler works with a single instance of this class. To avoid
/// passing it around as an argument everywhere, it is stored as a zone-value.
///
/// For convenience the static getter [CompilerContext.current] retrieves the
/// context stored in the current zone.
class CompilerContext {
final FileSystem fileSystem = PhysicalFileSystem.instance;
final CompilerCommandLine options;
// TODO(sigmund): Move here any method in ProcessedOptions that doesn't seem
// appropriate as an "option", or consider merging ProcessedOptions entirely
// within this class, and depend only on the raw options here.
final ProcessedOptions options;
/// Sources seen by the compiler.
///
/// This is populated as the compiler reads files, and it is used for error
/// reporting and to generate source location information in the compiled
/// programs.
final Map<String, Source> uriToSource = <String, Source>{};
FileSystem get fileSystem => options.fileSystem;
bool enableColorsCached = null;
CompilerContext(this.options);
@ -48,12 +63,12 @@ class CompilerContext {
/// Format [message] as a text string that can be included in generated code.
String format(LocatedMessage message, Severity severity) {
return options.format(message, severity);
return command_line_reporting.format(message, severity);
}
/// Format [message] as a text string that can be included in generated code.
String formatWithoutLocation(Message message, Severity severity) {
return options.formatWithoutLocation(message, severity);
return command_line_reporting.formatWithoutLocation(message, severity);
}
static CompilerContext get current {
@ -68,12 +83,22 @@ class CompilerContext {
return context;
}
/// Perform [action] in a [Zone] where [cl] will be available as
/// Perform [action] in a [Zone] where [this] will be available as
/// `CompilerContext.current.options`.
static dynamic withGlobalOptions(
CompilerCommandLine cl, dynamic action(CompilerContext c)) {
CompilerContext c = new CompilerContext(cl);
return runZoned(() => action(c), zoneValues: {compilerContextKey: c});
T runInContext<T>(T action(CompilerContext c)) {
return runZoned(() => action(this), zoneValues: {compilerContextKey: this});
}
/// Perform [action] in a [Zone] where [options] will be available as
/// `CompilerContext.current.options`.
static T runWithOptions<T>(
ProcessedOptions options, T action(CompilerContext c)) {
return new CompilerContext(options).runInContext(action);
}
static T runWithDefaultOptions<T>(T action(CompilerContext c)) {
var options = new ProcessedOptions(new CompilerOptions());
return new CompilerContext(options).runInContext(action);
}
static bool get enableColors {

View file

@ -10,9 +10,10 @@ import 'dart:convert' show JSON;
import 'dart:io' show BytesBuilder, File, exitCode;
import 'package:front_end/compiler_options.dart';
import 'package:front_end/src/base/processed_options.dart';
import 'package:front_end/physical_file_system.dart';
import 'package:front_end/src/fasta/kernel/utils.dart';
import 'package:front_end/src/fasta/uri_translator_impl.dart';
import 'package:kernel/kernel.dart' show Program, loadProgramFromBytes;
@ -25,9 +26,9 @@ import 'deprecated_problems.dart'
import 'kernel/kernel_target.dart' show KernelTarget;
import 'dill/dill_target.dart' show DillTarget;
import 'package:kernel/target/targets.dart' show Target;
import 'compile_platform.dart' show compilePlatformInternal;
import 'dill/dill_target.dart' show DillTarget;
import 'severity.dart' show Severity;
@ -70,8 +71,8 @@ outlineEntryPoint(List<String> arguments) async {
Future<KernelTarget> outline(List<String> arguments) async {
try {
return await CompilerCommandLine.withGlobalOptions("outline", arguments,
(CompilerContext c) async {
return await CompilerCommandLine.withGlobalOptions(
"outline", arguments, true, (CompilerContext c, _) async {
if (c.options.verbose) {
print("Building outlines for ${arguments.join(' ')}");
}
@ -81,17 +82,16 @@ Future<KernelTarget> outline(List<String> arguments) async {
});
} on deprecated_InputError catch (e) {
exitCode = 1;
CompilerCommandLine.deprecated_withDefaultOptions(() => CompilerContext
.current
.report(deprecated_InputError.toMessage(e), Severity.error));
CompilerContext.runWithDefaultOptions(
(c) => c.report(deprecated_InputError.toMessage(e), Severity.error));
return null;
}
}
Future<Uri> compile(List<String> arguments) async {
try {
return await CompilerCommandLine.withGlobalOptions("compile", arguments,
(CompilerContext c) async {
return await CompilerCommandLine.withGlobalOptions(
"compile", arguments, true, (CompilerContext c, _) async {
if (c.options.verbose) {
print("Compiling directly to Kernel: ${arguments.join(' ')}");
}
@ -101,9 +101,8 @@ Future<Uri> compile(List<String> arguments) async {
});
} on deprecated_InputError catch (e) {
exitCode = 1;
CompilerCommandLine.deprecated_withDefaultOptions(() => CompilerContext
.current
.report(deprecated_InputError.toMessage(e), Severity.error));
CompilerContext.runWithDefaultOptions(
(c) => c.report(deprecated_InputError.toMessage(e), Severity.error));
return null;
}
}
@ -125,8 +124,7 @@ class CompileTask {
}
Future<KernelTarget> buildOutline([Uri output]) async {
UriTranslator uriTranslator = await UriTranslatorImpl
.parse(c.fileSystem, c.options.sdk, packages: c.options.packages);
UriTranslator uriTranslator = await c.options.getUriTranslator();
ticker.logMs("Read packages file");
DillTarget dillTarget = createDillTarget(uriTranslator);
KernelTarget kernelTarget =
@ -134,13 +132,12 @@ class CompileTask {
if (c.options.strongMode) {
print("Note: strong mode support is preliminary and may not work.");
}
Uri platform = c.options.platform;
Uri platform = c.options.sdkSummary;
if (platform != null) {
_appendDillForUri(dillTarget, platform);
}
String argument = c.options.arguments.first;
Uri uri = Uri.base.resolve(argument);
String path = uriTranslator.translate(uri)?.path ?? argument;
Uri uri = c.options.inputs.first;
String path = uriTranslator.translate(uri)?.path ?? uri.path;
if (path.endsWith(".dart")) {
kernelTarget.read(uri);
} else {
@ -148,7 +145,7 @@ class CompileTask {
}
await dillTarget.buildOutlines();
var outline = await kernelTarget.buildOutlines();
if (c.options.dumpIr && output != null) {
if (c.options.debugDump && output != null) {
printProgramText(outline, libraryFilter: kernelTarget.isSourceLibrary);
}
if (output != null) {
@ -163,7 +160,7 @@ class CompileTask {
if (exitCode != 0) return null;
Uri uri = c.options.output;
var program = await kernelTarget.buildProgram(verify: c.options.verify);
if (c.options.dumpIr) {
if (c.options.debugDump) {
printProgramText(program, libraryFilter: kernelTarget.isSourceLibrary);
}
await writeProgramToFile(program, uri);
@ -172,50 +169,26 @@ class CompileTask {
}
}
Future compilePlatform(Uri patchedSdk, Uri fullOutput,
{Uri outlineOutput,
Uri packages,
bool verbose: false,
String backendTarget}) async {
backendTarget ??= "vm_fasta";
Ticker ticker = new Ticker(isVerbose: verbose);
await CompilerCommandLine.withGlobalOptions("", [""], (CompilerContext c) {
c.options.options["--target"] = backendTarget;
c.options.options["--packages"] = packages;
if (verbose) {
c.options.options["--verbose"] = true;
}
c.options.validate();
return compilePlatformInternal(
c, ticker, patchedSdk, fullOutput, outlineOutput);
});
}
// TODO(sigmund): reimplement this API using the directive listener intead.
Future<List<Uri>> getDependencies(Uri script,
{Uri sdk,
Uri packages,
Uri platform,
bool verbose: false,
String backendTarget}) async {
backendTarget ??= "vm_fasta";
Ticker ticker = new Ticker(isVerbose: verbose);
return await CompilerCommandLine.withGlobalOptions("", [""],
Target target}) async {
var options = new CompilerOptions()
..target = target
..verbose = verbose
..packagesFileUri = packages
..sdkSummary = platform
..sdkRoot = sdk;
var pOptions = new ProcessedOptions(options);
return await CompilerContext.runWithOptions(pOptions,
(CompilerContext c) async {
c.options.options["--target"] = backendTarget;
c.options.options["--strong-mode"] = false;
c.options.options["--packages"] = packages;
if (verbose) {
c.options.options["--verbose"] = true;
}
c.options.validate();
sdk ??= c.options.sdk;
UriTranslator uriTranslator = await UriTranslatorImpl
.parse(c.fileSystem, sdk, packages: c.options.packages);
ticker.logMs("Read packages file");
UriTranslator uriTranslator = await c.options.getUriTranslator();
c.options.ticker.logMs("Read packages file");
DillTarget dillTarget =
new DillTarget(ticker, uriTranslator, c.options.target);
new DillTarget(c.options.ticker, uriTranslator, c.options.target);
if (platform != null) _appendDillForUri(dillTarget, platform);
KernelTarget kernelTarget = new KernelTarget(PhysicalFileSystem.instance,
false, dillTarget, uriTranslator, c.uriToSource);

View file

@ -209,7 +209,17 @@ const Code<Null> codeCantInferPackagesFromManyInputs =
const MessageCode messageCantInferPackagesFromManyInputs = const MessageCode(
"CantInferPackagesFromManyInputs",
message:
r"""Cannot infer a .packages file when compiling multiple inputs.""",
r"""Can't infer a .packages file when compiling multiple inputs.""",
tip: r"""Try specifying the file explicitly with the --packages option.""");
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Code<Null> codeCantInferPackagesFromPackageUri =
messageCantInferPackagesFromPackageUri;
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const MessageCode messageCantInferPackagesFromPackageUri = const MessageCode(
"CantInferPackagesFromPackageUri",
message: r"""Can't infer a .packages file from an input 'package:*' URI.""",
tip: r"""Try specifying the file explicitly with the --packages option.""");
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@ -1394,7 +1404,7 @@ const MessageCode messageInternalProblemMissingContext = const MessageCode(
"InternalProblemMissingContext",
message: r"""Compiler cannot run without a compiler context.""",
tip:
r"""Are calls to the compiler wrapped in CompilerContext.withGlobalOptions?""");
r"""Are calls to the compiler wrapped in CompilerContext.runInContext?""");
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Template<Message Function(String name)> templateInternalProblemNotFound =

View file

@ -30,8 +30,10 @@ const int iterations = const int.fromEnvironment("iterations", defaultValue: 1);
mainEntryPoint(List<String> arguments) async {
Uri uri;
for (int i = 0; i < iterations; i++) {
await CompilerCommandLine.withGlobalOptions("run", arguments,
(CompilerContext c) async {
await CompilerCommandLine.withGlobalOptions("run", arguments, false,
(CompilerContext c, List<String> restArguments) async {
var input = Uri.base.resolve(restArguments[0]);
c.options.inputs.add(input);
if (i > 0) {
print("\n");
}
@ -46,17 +48,17 @@ mainEntryPoint(List<String> arguments) async {
}
if (exitCode != 0) exit(exitCode);
if (i + 1 == iterations) {
exit(await run(uri, c));
exit(await run(uri, c, restArguments));
}
});
}
}
Future<int> run(Uri uri, CompilerContext c) async {
Future<int> run(Uri uri, CompilerContext c, List<String> allArguments) async {
Uri sdk = await computePatchedSdk();
Uri dartVm = computeDartVm(sdk);
List<String> arguments = <String>["${uri.toFilePath()}"]
..addAll(c.options.arguments.skip(1));
..addAll(allArguments.skip(1));
if (c.options.verbose) {
print("Running ${dartVm.toFilePath()} ${arguments.join(' ')}");
}

View file

@ -80,7 +80,7 @@ class SourceLoader<L> extends Loader<L> {
final Map<Uri, List<int>> sourceBytes = <Uri, List<int>>{};
final bool excludeSource = CompilerContext.current.options.excludeSource;
final bool excludeSource = !CompilerContext.current.options.embedSourceText;
// Used when building directly to kernel.
ClassHierarchy hierarchy;

View file

@ -25,7 +25,7 @@ import 'package:kernel/ast.dart' show Library, Program;
import '../kernel/verifier.dart' show verifyProgram;
import '../compiler_command_line.dart';
import '../compiler_context.dart';
import 'package:kernel/binary/ast_to_binary.dart' show BinaryPrinter;
@ -38,6 +38,9 @@ import 'package:kernel/ast.dart' show Program;
import 'package:front_end/front_end.dart';
import 'package:front_end/src/base/processed_options.dart'
show ProcessedOptions;
import 'patched_sdk_location.dart' show computePatchedSdk;
class Print extends Step<Program, Program, ChainContext> {
@ -67,7 +70,9 @@ class Verify extends Step<Program, Program, ChainContext> {
String get name => "verify";
Future<Result<Program>> run(Program program, ChainContext context) async {
return await CompilerCommandLine.withGlobalOptions("", [""], (_) async {
var options =
new ProcessedOptions(new CompilerOptions()..throwOnErrors = false);
return await CompilerContext.runWithOptions(options, (_) async {
var errors = verifyProgram(program, isOutline: !fullCompile);
if (errors.isEmpty) {
return pass(program);
@ -191,7 +196,7 @@ class Compile extends Step<TestDescription, Program, CompileContext> {
Future<Result<Program>> run(
TestDescription description, CompileContext context) async {
Result<Program> result;
reportError(CompilationError error) {
reportError(CompilationMessage error) {
result ??= fail(null, error.message);
}

View file

@ -5,9 +5,10 @@
import 'dart:async';
import 'package:front_end/file_system.dart';
import 'package:front_end/compiler_options.dart';
import 'package:front_end/src/base/api_signature.dart';
import 'package:front_end/src/base/processed_options.dart';
import 'package:front_end/src/base/performace_logger.dart';
import 'package:front_end/src/fasta/compiler_command_line.dart';
import 'package:front_end/src/fasta/compiler_context.dart';
import 'package:front_end/src/fasta/dill/dill_library_builder.dart';
import 'package:front_end/src/fasta/dill/dill_target.dart';
@ -149,13 +150,15 @@ class KernelDriver {
}
Future<T> runWithFrontEndContext<T>(String msg, Future<T> f()) async {
return await CompilerCommandLine.withGlobalOptions("", [""],
(CompilerContext context) {
context.options.options["--target"] = _target;
context.options.options["report"] = (message, severity) {};
context.options.options["reportWithoutLocation"] = (message, severity) {};
return _logger.runAsync(msg, f);
});
var options = new CompilerOptions()
..target = _target
// Note: we do not report error on the console because the driver is an
// ongoing background service that shouldn't polute stdout.
// TODO(scheglov,sigmund): add an error handler to forward errors to
// analyzer driver and incremental kernel generator.
..reportMessages = false;
return await CompilerContext.runWithOptions(
new ProcessedOptions(options), (_) => _logger.runAsync(msg, f));
}
/// The file with the given [uri] might have changed - updated, added, or

View file

@ -11,7 +11,7 @@ import 'dart:async';
import 'package:kernel/kernel.dart' show Program, CanonicalName;
import 'base/processed_options.dart';
import 'fasta/compiler_command_line.dart' show CompilerCommandLine;
import 'fasta/severity.dart' show Severity;
import 'fasta/compiler_context.dart' show CompilerContext;
import 'fasta/deprecated_problems.dart' show deprecated_InputError, reportCrash;
import 'fasta/dill/dill_target.dart' show DillTarget;
@ -27,34 +27,19 @@ Future<CompilerResult> generateKernel(ProcessedOptions options,
{bool buildSummary: false,
bool buildProgram: true,
bool trimDependencies: false}) async {
// TODO(sigmund): Replace CompilerCommandLine and instead simply use a
// CompilerContext that directly uses the ProcessedOptions through the
// system.
String programName = "";
List<String> arguments = <String>[programName, "--target=none"];
if (options.strongMode) {
arguments.add("--strong-mode");
}
if (options.verbose) {
arguments.add("--verbose");
}
if (options.setExitCodeOnProblem) {
arguments.add("--set-exit-code-on-problem");
}
return await CompilerCommandLine.withGlobalOptions(programName, arguments,
(CompilerContext context) async {
context.options.options["--target"] = options.target;
return await generateKernelInternal(options,
return await CompilerContext.runWithOptions(options, (_) async {
return await generateKernelInternal(
buildSummary: buildSummary,
buildProgram: buildProgram,
trimDependencies: trimDependencies);
});
}
Future<CompilerResult> generateKernelInternal(ProcessedOptions options,
Future<CompilerResult> generateKernelInternal(
{bool buildSummary: false,
bool buildProgram: true,
bool trimDependencies: false}) async {
var options = CompilerContext.current.options;
var fs = options.fileSystem;
if (!await options.validateOptions()) return null;
options.ticker.logMs("Validated arguments");
@ -120,7 +105,9 @@ Future<CompilerResult> generateKernelInternal(ProcessedOptions options,
trimProgram(summaryProgram, (uri) => !excluded.contains(uri));
}
if (options.verify) {
verifyProgram(summaryProgram).forEach(options.reportMessage);
for (var error in verifyProgram(summaryProgram)) {
options.report(error, Severity.error);
}
}
if (options.debugDump) {
printProgramText(summaryProgram,
@ -147,8 +134,8 @@ Future<CompilerResult> generateKernelInternal(ProcessedOptions options,
}
if (kernelTarget.errors.isNotEmpty) {
// TODO(ahe): The errors have already been reported via CompilerContext.
kernelTarget.errors.forEach(options.reportMessage);
// Note: we don't report errors here because they have been already
// reported through the compiler context.
return null;
}
@ -157,7 +144,8 @@ Future<CompilerResult> generateKernelInternal(ProcessedOptions options,
program: program,
deps: kernelTarget.loader.getDependencies());
} on deprecated_InputError catch (e) {
options.reportMessage(deprecated_InputError.toMessage(e));
options.report(
deprecated_InputError.toMessage(e), Severity.internalProblem);
return null;
} catch (e, t) {
return reportCrash(e, t);

View file

@ -628,7 +628,7 @@ InternalProblemBodyOnAbstractMethod:
InternalProblemMissingContext:
template: "Compiler cannot run without a compiler context."
tip: "Are calls to the compiler wrapped in CompilerContext.withGlobalOptions?"
tip: "Are calls to the compiler wrapped in CompilerContext.runInContext?"
InternalVerificationError:
template: "Verification of the generated program failed: #string."
@ -881,7 +881,11 @@ CannotReadPackagesFile:
template: "Unable to read '.packages' file:\n #string."
CantInferPackagesFromManyInputs:
template: "Cannot infer a .packages file when compiling multiple inputs."
template: "Can't infer a .packages file when compiling multiple inputs."
tip: "Try specifying the file explicitly with the --packages option."
CantInferPackagesFromPackageUri:
template: "Can't infer a .packages file from an input 'package:*' URI."
tip: "Try specifying the file explicitly with the --packages option."
PackageNotFound:

View file

@ -20,8 +20,9 @@ import 'dart:convert' show JSON;
import 'dart:io' show File;
export 'package:testing/testing.dart' show Chain, runMe;
import 'package:front_end/physical_file_system.dart';
import 'package:front_end/src/fasta/compiler_command_line.dart';
import 'package:front_end/compiler_options.dart';
import 'package:front_end/src/base/processed_options.dart';
import 'package:front_end/src/fasta/compiler_context.dart';
import 'package:front_end/src/fasta/dill/dill_target.dart' show DillTarget;
import 'package:front_end/src/fasta/deprecated_problems.dart'
show deprecated_InputError;
@ -31,9 +32,6 @@ import 'package:front_end/src/fasta/kernel/kernel_target.dart'
import 'package:front_end/src/fasta/kernel/verifier.dart' show verifyProgram;
import 'package:front_end/src/fasta/testing/kernel_chain.dart' show runDiff;
import 'package:front_end/src/fasta/testing/patched_sdk_location.dart';
import 'package:front_end/src/fasta/ticker.dart' show Ticker;
import 'package:front_end/src/fasta/uri_translator.dart' show UriTranslator;
import 'package:front_end/src/fasta/uri_translator_impl.dart';
import 'package:front_end/src/fasta/util/relativize.dart' show relativizeUri;
import 'package:kernel/ast.dart' show Program;
import 'package:kernel/kernel.dart' show loadProgramFromBytes;
@ -53,7 +51,7 @@ Future<TreeShakerContext> createContext(
/// Context used to run the tree-shaking test suite.
class TreeShakerContext extends ChainContext {
final UriTranslator uriTranslator;
final ProcessedOptions options;
final Uri outlineUri;
final List<Step> steps;
final List<int> outlineBytes;
@ -61,8 +59,8 @@ class TreeShakerContext extends ChainContext {
final ExpectationSet expectationSet =
new ExpectationSet.fromJsonList(JSON.decode(EXPECTATIONS));
TreeShakerContext(this.outlineUri, this.uriTranslator, this.outlineBytes,
bool updateExpectations)
TreeShakerContext(
this.outlineUri, this.options, this.outlineBytes, bool updateExpectations)
: steps = <Step>[
const BuildProgram(),
new CheckShaker(updateExpectations: updateExpectations),
@ -81,12 +79,11 @@ class TreeShakerContext extends ChainContext {
bool updateExpectations = environment["updateExpectations"] == "true";
Uri sdk = await computePatchedSdk();
Uri outlineUri = sdk.resolve('outline.dill');
Uri packages = Uri.base.resolve(".packages");
UriTranslator uriTranslator = await UriTranslatorImpl
.parse(PhysicalFileSystem.instance, sdk, packages: packages);
var options = new CompilerOptions()
..packagesFileUri = Uri.base.resolve(".packages");
List<int> outlineBytes = new File.fromUri(outlineUri).readAsBytesSync();
return new TreeShakerContext(
outlineUri, uriTranslator, outlineBytes, updateExpectations);
return new TreeShakerContext(outlineUri, new ProcessedOptions(options),
outlineBytes, updateExpectations);
}
}
@ -98,17 +95,16 @@ class BuildProgram
String get name => "build program";
Future<Result<_IntermediateData>> run(
TestDescription description, TreeShakerContext context) async {
return await CompilerCommandLine.withGlobalOptions("", [""], (_) async {
return await CompilerContext.runWithOptions(context.options, (_) async {
try {
var platformOutline = context.loadPlatformOutline();
platformOutline.unbindCanonicalNames();
var dillTarget = new DillTarget(
new Ticker(isVerbose: false),
context.uriTranslator,
var uriTranslator = await context.options.getUriTranslator();
var dillTarget = new DillTarget(context.options.ticker, uriTranslator,
new VmFastaTarget(new TargetFlags(strongMode: false)));
dillTarget.loader.appendLibraries(platformOutline);
var sourceTarget = new KernelTarget(PhysicalFileSystem.instance, false,
dillTarget, context.uriTranslator);
var sourceTarget = new KernelTarget(
context.options.fileSystem, false, dillTarget, uriTranslator);
await dillTarget.buildOutlines();
var inputUri = description.uri;

View file

@ -12,8 +12,6 @@ import 'dart:convert' show JSON;
import 'package:front_end/physical_file_system.dart' show PhysicalFileSystem;
import 'package:front_end/src/fasta/compiler_command_line.dart';
import 'package:front_end/src/fasta/testing/validating_instrumentation.dart'
show ValidatingInstrumentation;
@ -33,6 +31,11 @@ import 'package:testing/testing.dart'
TestDescription,
StdioProcess;
import 'package:front_end/compiler_options.dart' show CompilerOptions;
import 'package:front_end/src/base/processed_options.dart'
show ProcessedOptions;
import 'package:front_end/src/fasta/compiler_context.dart' show CompilerContext;
import 'package:front_end/src/fasta/deprecated_problems.dart'
@ -224,7 +227,9 @@ class Outline extends Step<TestDescription, Program, FastaContext> {
Future<Result<Program>> run(
TestDescription description, FastaContext context) async {
return await CompilerCommandLine.withGlobalOptions("", [""], (_) async {
var options =
new ProcessedOptions(new CompilerOptions()..throwOnErrors = false);
return await CompilerContext.runWithOptions(options, (_) async {
// Disable colors to ensure that expectation files are the same across
// platforms and independent of stdin/stderr.
CompilerContext.current.disableColors();

View file

@ -4,6 +4,8 @@
import 'package:front_end/front_end.dart';
import 'package:front_end/src/fasta/kernel/utils.dart';
import 'package:front_end/src/fasta/deprecated_problems.dart'
show deprecated_InputError;
import 'package:front_end/src/testing/compiler_common.dart';
import 'package:kernel/ast.dart';
@ -61,13 +63,14 @@ main() {
expect(errors.first.message, contains("No 'main' method found"));
});
test('default error handler throws', () async {
test('default error handler throws on errors', () async {
var options = new CompilerOptions();
var exceptionThrown = false;
try {
await compileScript('a() => print("hi");');
} on CompilationError catch (e) {
await compileScript('a() => print("hi");', options: options);
} on deprecated_InputError catch (e) {
exceptionThrown = true;
expect(e.message, contains("No 'main' method found"));
expect('${e.error}', contains("Compilation aborted"));
}
expect(exceptionThrown, isTrue);
});

View file

@ -25,7 +25,7 @@ import 'package:analyzer/src/summary/format.dart';
import 'package:analyzer/src/summary/idl.dart';
import 'package:analyzer/src/summary/link.dart';
import 'package:analyzer/src/summary/summarize_ast.dart';
import 'package:front_end/compilation_error.dart';
import 'package:front_end/compilation_message.dart';
import 'package:front_end/compiler_options.dart';
import 'package:front_end/src/scanner/reader.dart';
import 'package:front_end/src/scanner/scanner.dart';
@ -201,9 +201,12 @@ void _reportErrors(List errors, ErrorHandler onError) {
}
}
class _DartkError implements CompilationError {
class _DartkError implements CompilationMessage {
String get tip => null;
SourceSpan get span => null;
String get analyzerCode => null;
String get dart2jsCode => null;
Severity get severity => Severity.error;
final String message;
_DartkError(this.message);
}

View file

@ -52,8 +52,8 @@ main() {
..packagesFileUri = Platform.script.resolve('../../../.packages')
..compileSdk = true
..linkedDependencies = [platform]
..verify = true
..onError = errorHandler;
..setExitCodeOnProblem = true
..verify = true;
List<int> kernelBinary =
serializeProgram(await kernelForProgram(uri, options));
@ -79,8 +79,3 @@ main() {
Expect.isNotNull(member);
});
}
void errorHandler(CompilationError e) {
exitCode = 1;
print(e.message);
}

View file

@ -78,12 +78,22 @@ Future _processLoadRequest(request) async {
..packagesFileUri = packagesUri
..sdkSummary = sdkSummary
..verbose = verbose
..onError = (CompilationError e) => errors.add(e.message);
..throwOnErrors = false
..reportMessages = true
..onError = (CompilationMessage e) {
if (e.severity == Severity.error) {
// TODO(sigmund): support emitting code with errors as long as they are
// handled in the generated code (issue #30194).
errors.add(e.message);
}
};
CompilationResult result;
try {
Program program = await kernelForProgram(script, options);
if (errors.isNotEmpty) {
// TODO(sigmund): the compiler prints errors to the console, so we
// shouldn't print those messages again here.
result = new CompilationResult.errors(errors);
} else {
// We serialize the program excluding platform.dill because the VM has