Opt-in to generate code for compile-time error. Only supported for SSA.

BUG=
R=karlklose@google.com

Review URL: https://codereview.chromium.org//1167353003
This commit is contained in:
Johnni Winther 2015-06-09 14:36:38 +02:00
parent dae0c0d6f0
commit bac7481d3d
10 changed files with 195 additions and 19 deletions

View file

@ -88,6 +88,7 @@ class Compiler extends leg.Compiler {
hasOption(options, '--enable-experimental-mirrors'),
generateCodeWithCompileTimeErrors:
hasOption(options, '--generate-code-with-compile-time-errors'),
testMode: hasOption(options, '--test-mode'),
allowNativeExtensions:
hasOption(options, '--allow-native-extensions'),
enableNullAwareOperators:

View file

@ -302,8 +302,6 @@ abstract class Backend {
List<CompilerTask> get tasks;
bool get canHandleCompilationFailed;
void onResolutionComplete() {}
void onTypeInferenceComplete() {}
@ -314,9 +312,13 @@ abstract class Backend {
bool classNeedsRti(ClassElement cls);
bool methodNeedsRti(FunctionElement function);
/// Register deferred loading. Returns `true` if the backend supports deferred
/// Enable compilation of code with compile time errors. Returns `true` if
/// supported by the backend.
bool enableCodegenWithErrorsIfSupported(Spannable node);
/// Enable deferred loading. Returns `true` if the backend supports deferred
/// loading.
bool registerDeferredLoading(Spannable node, Registry registry);
bool enableDeferredLoadingIfSupported(Spannable node, Registry registry);
/// Called during codegen when [constant] has been used.
void registerCompileTimeConstant(ConstantValue constant, Registry registry) {}
@ -794,6 +796,9 @@ abstract class Compiler implements DiagnosticListener {
/// Generate output even when there are compile-time errors.
final bool generateCodeWithCompileTimeErrors;
/// The compiler is run from the build bot.
final bool testMode;
bool disableInlining = false;
List<Uri> librariesToAnalyzeWhenRun;
@ -1053,6 +1058,7 @@ abstract class Compiler implements DiagnosticListener {
this.allowNativeExtensions: false,
this.enableNullAwareOperators: false,
this.generateCodeWithCompileTimeErrors: false,
this.testMode: false,
api.CompilerOutputProvider outputProvider,
List<String> strips: const []})
: this.disableTypeInferenceFlag =
@ -1621,9 +1627,11 @@ abstract class Compiler implements DiagnosticListener {
});
}
// TODO(sigurdm): The dart backend should handle failed compilations.
if (compilationFailed && !backend.canHandleCompilationFailed) {
return;
if (compilationFailed){
if (!generateCodeWithCompileTimeErrors) return;
if (!backend.enableCodegenWithErrorsIfSupported(NO_LOCATION_SPANNABLE)) {
return;
}
}
if (analyzeOnly) {
@ -2159,7 +2167,14 @@ abstract class Compiler implements DiagnosticListener {
}
EventSink<String> outputProvider(String name, String extension) {
if (compilationFailed) return new NullSink('$name.$extension');
if (compilationFailed) {
if (!generateCodeWithCompileTimeErrors || testMode) {
// Disable output in test mode: The build bot currently uses the time
// stamp of the generated file to determine whether the output is
// up-to-date.
return new NullSink('$name.$extension');
}
}
return userOutputProvider(name, extension);
}
}

View file

@ -360,6 +360,7 @@ Future<api.CompilationResult> compile(List<String> argv) {
}),
new OptionHandler('--allow-native-extensions', setAllowNativeExtensions),
new OptionHandler('--generate-code-with-compile-time-errors', passThrough),
new OptionHandler('--test-mode', passThrough),
// The following three options must come last.
new OptionHandler('-D.+=.*', addInEnvironment),

View file

@ -49,7 +49,13 @@ class DartBackend extends Backend {
final Set<ClassElement> _userImplementedPlatformClasses =
new Set<ClassElement>();
bool get canHandleCompilationFailed => false;
bool enableCodegenWithErrorsIfSupported(Spannable node) {
compiler.reportHint(node,
MessageKind.GENERIC,
{'text': "Generation of code with compile time errors is not "
"supported for dart2dart."});
return false;
}
/**
* Tells whether it is safe to remove type declarations from variables,
@ -314,7 +320,7 @@ class DartBackend extends Backend {
}
@override
bool registerDeferredLoading(Spannable node, Registry registry) {
bool enableDeferredLoadingIfSupported(Spannable node, Registry registry) {
// TODO(sigurdm): Implement deferred loading for dart2dart.
compiler.reportWarning(node, MessageKind.DEFERRED_LIBRARY_DART_2_DART);
return false;

View file

@ -776,7 +776,7 @@ class DeferredLoadTask extends CompilerTask {
});
}
if (isProgramSplit) {
isProgramSplit = compiler.backend.registerDeferredLoading(
isProgramSplit = compiler.backend.enableDeferredLoadingIfSupported(
lastDeferred, compiler.globalDependencies);
}
}

View file

@ -608,8 +608,6 @@ class JavaScriptBackend extends Backend {
PatchResolverTask patchResolverTask;
bool get canHandleCompilationFailed => true;
bool enabledNoSuchMethod = false;
JavaScriptBackend(Compiler compiler,
@ -2679,10 +2677,23 @@ class JavaScriptBackend extends Backend {
}
@override
bool registerDeferredLoading(Spannable node, Registry registry) {
bool enableDeferredLoadingIfSupported(Spannable node, Registry registry) {
registerCheckDeferredIsLoaded(registry);
return true;
}
@override
bool enableCodegenWithErrorsIfSupported(Spannable node) {
if (compiler.useCpsIr) {
compiler.reportHint(
node,
MessageKind.GENERIC,
{'text': "Generation of code with compile time errors is currently "
"not supported with the CPS IR."});
return false;
}
return true;
}
}
/// Handling of special annotations for tests.

View file

@ -64,7 +64,7 @@ runCompiler(String main, List<String> options,
main() {
runCompiler(
"",
[],
['--generate-code-with-compile-time-errors'],
(String code, List errors, List warnings) {
Expect.isNotNull(code);
Expect.isTrue(errors.isEmpty, 'errors is not empty: $errors');
@ -75,7 +75,7 @@ main() {
runCompiler(
"main() {}",
[],
['--generate-code-with-compile-time-errors'],
(String code, List errors, List warnings) {
Expect.isNotNull(code);
Expect.isTrue(errors.isEmpty);

View file

@ -0,0 +1,142 @@
// Copyright (c) 2015, 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.
// Test that the compiler can generates code with compile time error according
// to the compiler options.
library dart2js.test.import;
import 'package:expect/expect.dart';
import 'package:async_helper/async_helper.dart';
import 'package:compiler/src/dart2jslib.dart';
import 'package:compiler/src/dart_backend/dart_backend.dart';
import 'package:compiler/src/js_backend/js_backend.dart';
import 'memory_compiler.dart';
import 'output_collector.dart';
const MEMORY_SOURCE_FILES = const {
'main.dart': '''
foo() {
const list = [];
}
main() {
foo();
}
''',
};
test(List<String> options,
{bool expectedOutput,
bool expectedCodeGenerated,
bool expectHint: false}) async {
DiagnosticCollector collector = new DiagnosticCollector();
OutputCollector outputCollector = new OutputCollector();
Compiler compiler = compilerFor(
MEMORY_SOURCE_FILES,
diagnosticHandler: collector,
outputProvider: outputCollector,
options: options);
return compiler.run(Uri.parse('memory:main.dart')).then(
(bool success) {
Expect.isFalse(
success,
"Expected compilation failure.");
Expect.isTrue(
collector.warnings.isEmpty,
"Unexpected warnings: ${collector.warnings}");
Expect.isFalse(
collector.errors.isEmpty,
"Expected compile-time errors.");
Expect.equals(
expectHint,
collector.hints.isNotEmpty,
"Unexpected hints: ${collector.warnings}");
bool isCodeGenerated;
if (options.contains('--output-type=dart')) {
DartBackend backend = compiler.backend;
isCodeGenerated = backend.outputter.libraryInfo != null;
} else {
JavaScriptBackend backend = compiler.backend;
isCodeGenerated = backend.generatedCode.isNotEmpty;
}
Expect.equals(
expectedCodeGenerated,
isCodeGenerated,
expectedCodeGenerated
? "Expected generated code for options $options."
: "Expected no code generated for options $options.");
Expect.equals(
expectedOutput,
outputCollector.outputMap.isNotEmpty,
expectedOutput
? "Expected output for options $options."
: "Expected no output for options $options.");
});
}
void main() {
asyncTest(() async {
await test(
[],
expectedCodeGenerated: false,
expectedOutput: false);
await test(
['--test-mode'],
expectedCodeGenerated: false,
expectedOutput: false);
await test(
['--generate-code-with-compile-time-errors'],
expectedCodeGenerated: true,
expectedOutput: true);
await test(
['--generate-code-with-compile-time-errors', '--test-mode'],
expectedCodeGenerated: true,
expectedOutput: false);
await test(
['--use-cps-ir'],
expectedCodeGenerated: false,
expectedOutput: false);
await test(
['--use-cps-ir', '--test-mode'],
expectedCodeGenerated: false,
expectedOutput: false);
await test(
['--use-cps-ir', '--generate-code-with-compile-time-errors'],
expectedCodeGenerated: false,
expectedOutput: false,
expectHint: true);
await test(
['--use-cps-ir',
'--generate-code-with-compile-time-errors',
'--test-mode'],
expectedCodeGenerated: false,
expectedOutput: false,
expectHint: true);
await test(
['--output-type=dart'],
expectedCodeGenerated: false,
expectedOutput: false);
await test(
['--output-type=dart', '--test-mode'],
expectedCodeGenerated: false,
expectedOutput: false);
await test(
['--output-type=dart', '--generate-code-with-compile-time-errors'],
expectedCodeGenerated: false,
expectedOutput: false,
expectHint: true);
await test(
['--output-type=dart',
'--generate-code-with-compile-time-errors',
'--test-mode'],
expectedCodeGenerated: false,
expectedOutput: false,
expectHint: true);
});
}

View file

@ -389,9 +389,9 @@ api.DiagnosticHandler createHandler(MockCompiler compiler, String text,
sourceFile = compiler.sourceFiles[uri.toString()];
}
if (sourceFile != null && begin != null && end != null) {
print(sourceFile.getLocationMessage(message, begin, end));
print('${kind}: ${sourceFile.getLocationMessage(message, begin, end)}');
} else {
print(message);
print('${kind}: $message');
}
};
}

View file

@ -2199,7 +2199,7 @@ class TestUtils {
}
String compiler = configuration["compiler"];
if (compiler == "dart2js") {
args = [];
args = ['--generate-code-with-compile-time-errors', '--test-mode'];
if (configuration["checked"]) {
args.add('--enable-checked-mode');
}