Reland "[vm/nnbd] Auto-detect null-safety from entry point in kernel compilers"

This is a reland of fd19c8cc25
No changes were made to the original CL.

The following fixes landed separately:
* Flutter tests which use --enable-experiment=non-nullable are
  disabled in https://github.com/flutter/flutter/pull/57235.
* Auto-detection of null-safety mode from dill file in gen_snapshot is
  implemented in https://dart-review.googlesource.com/c/sdk/+/148152.

Original change's description:
> [vm/nnbd] Auto-detect null-safety from entry point in kernel compilers
>
> If --null-safety flag is not specified, tools should infer null safety
> mode from a legacy status of an entry point script.
> This change adds such auto-detection to kernel compilers (front-end
> server and gen_kernel).
>
> Issue: https://github.com/dart-lang/sdk/issues/41206
> Change-Id: If78491d08390c28b98e86857ec7d61520433dee9
> Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/148024
> Reviewed-by: Ryan Macnak <rmacnak@google.com>
> Reviewed-by: Alexander Aprelev <aam@google.com>
> Commit-Queue: Alexander Markov <alexmarkov@google.com>

Change-Id: Ibc185caa6975087a35c89ff69faf3f6c11fcf14c
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/148201
Reviewed-by: Alexander Aprelev <aam@google.com>
Commit-Queue: Alexander Markov <alexmarkov@google.com>
This commit is contained in:
Alexander Markov 2020-05-14 22:10:45 +00:00 committed by commit-bot@chromium.org
parent a6148714f0
commit bbe469eabd
6 changed files with 88 additions and 21 deletions

View file

@ -152,7 +152,7 @@ ArgParser argParser = ArgParser(allowTrailingOptions: true)
..addFlag('null-safety',
help:
'Respect the nullability of types at runtime in casts and instance checks.',
defaultsTo: false)
defaultsTo: null)
..addMultiOption('enable-experiment',
help: 'Comma separated list of experimental features, eg set-literals.',
hide: true)
@ -385,7 +385,8 @@ class FrontendCompiler implements CompilerInterface {
..experimentalFlags = parseExperimentalFlags(
parseExperimentalArguments(options['enable-experiment']),
onError: (msg) => errors.add(msg))
..nnbdMode = options['null-safety'] ? NnbdMode.Strong : NnbdMode.Weak
..nnbdMode =
(options['null-safety'] == true) ? NnbdMode.Strong : NnbdMode.Weak
..onDiagnostic = (DiagnosticMessage message) {
bool printMessage;
switch (message.severity) {
@ -446,6 +447,11 @@ class FrontendCompiler implements CompilerInterface {
}
}
if (options['null-safety'] == null &&
compilerOptions.experimentalFlags[ExperimentalFlag.nonNullable]) {
await autoDetectNullSafetyMode(_mainSource, compilerOptions);
}
compilerOptions.bytecode = options['gen-bytecode'];
final BytecodeOptions bytecodeOptions = BytecodeOptions(
enableAsserts: options['enable-asserts'],
@ -459,7 +465,7 @@ class FrontendCompiler implements CompilerInterface {
compilerOptions.target = createFrontEndTarget(
options['target'],
trackWidgetCreation: options['track-widget-creation'],
nullSafety: options['null-safety'],
nullSafety: compilerOptions.nnbdMode == NnbdMode.Strong,
);
if (compilerOptions.target == null) {
print('Failed to create front-end target ${options['target']}.');

View file

@ -31,7 +31,6 @@ import 'package:build_integration/file_system/multi_root.dart';
import 'package:front_end/src/api_prototype/experimental_flags.dart';
import 'package:front_end/src/api_prototype/front_end.dart' as fe
show CompilerResult;
import 'package:front_end/src/api_prototype/language_version.dart';
import 'package:front_end/src/api_prototype/memory_file_system.dart';
import 'package:front_end/src/api_unstable/vm.dart';
import 'package:kernel/binary/ast_to_binary.dart';
@ -46,7 +45,10 @@ import 'package:vm/bytecode/gen_bytecode.dart'
import 'package:vm/bytecode/options.dart' show BytecodeOptions;
import 'package:vm/incremental_compiler.dart';
import 'package:vm/kernel_front_end.dart'
show createLoadedLibrariesSet, runWithFrontEndCompilerContext;
show
autoDetectNullSafetyMode,
createLoadedLibrariesSet,
runWithFrontEndCompilerContext;
import 'package:vm/http_filesystem.dart';
import 'package:vm/target/vm.dart' show VmTarget;
import 'package:front_end/src/api_prototype/compiler_options.dart'
@ -90,12 +92,6 @@ const int kNullSafetyOptionUnspecified = 0;
const int kNullSafetyOptionWeak = 1;
const int kNullSafetyOptionStrong = 2;
Future<void> autoDetectNullSafetyMode(
Uri script, CompilerOptions options) async {
var isLegacy = await uriUsesLegacyLanguageVersion(script, options);
options.nnbdMode = isLegacy ? NnbdMode.Weak : NnbdMode.Strong;
}
abstract class Compiler {
final int isolateId;
final FileSystem fileSystem;

View file

@ -15,6 +15,9 @@ import 'package:build_integration/file_system/multi_root.dart'
import 'package:crypto/crypto.dart';
import 'package:front_end/src/api_prototype/language_version.dart'
show uriUsesLegacyLanguageVersion;
import 'package:front_end/src/api_unstable/vm.dart'
show
CompilerContext,
@ -22,6 +25,7 @@ import 'package:front_end/src/api_unstable/vm.dart'
CompilerResult,
DiagnosticMessage,
DiagnosticMessageHandler,
ExperimentalFlag,
FileSystem,
FileSystemEntity,
FileSystemException,
@ -110,7 +114,7 @@ void declareCompilerOptions(ArgParser args) {
args.addFlag('null-safety',
help:
'Respect the nullability of types at runtime in casts and instance checks.',
defaultsTo: false);
defaultsTo: null);
args.addFlag('split-output-by-packages',
help:
'Split resulting kernel file into multiple files (one per package).',
@ -200,12 +204,6 @@ Future<int> runCompiler(ArgResults options, String usage) async {
aot: aot,
)..parseCommandLineFlags(options['bytecode-options']);
final target = createFrontEndTarget(targetName, nullSafety: nullSafety);
if (target == null) {
print('Failed to create front-end target $targetName.');
return badUsageExitCode;
}
final fileSystem =
createFrontEndFileSystem(fileSystemScheme, fileSystemRoots);
@ -227,19 +225,30 @@ Future<int> runCompiler(ArgResults options, String usage) async {
final CompilerOptions compilerOptions = new CompilerOptions()
..sdkSummary = platformKernelUri
..target = target
..fileSystem = fileSystem
..additionalDills = additionalDills
..packagesFileUri = packagesUri
..experimentalFlags = parseExperimentalFlags(
parseExperimentalArguments(experimentalFlags),
onError: print)
..nnbdMode = nullSafety ? NnbdMode.Strong : NnbdMode.Weak
..nnbdMode = (nullSafety == true) ? NnbdMode.Strong : NnbdMode.Weak
..onDiagnostic = (DiagnosticMessage m) {
errorDetector(m);
}
..embedSourceText = embedSources;
if (nullSafety == null &&
compilerOptions.experimentalFlags[ExperimentalFlag.nonNullable]) {
await autoDetectNullSafetyMode(mainUri, compilerOptions);
}
compilerOptions.target = createFrontEndTarget(targetName,
nullSafety: compilerOptions.nnbdMode == NnbdMode.Strong);
if (compilerOptions.target == null) {
print('Failed to create front-end target $targetName.');
return badUsageExitCode;
}
final results = await compileToKernel(mainUri, compilerOptions,
includePlatform: additionalDills.isNotEmpty,
aot: aot,
@ -558,6 +567,13 @@ bool parseCommandLineDefines(
return true;
}
/// Detect null safety mode from an entry point and set [options.nnbdMode].
Future<void> autoDetectNullSafetyMode(
Uri script, CompilerOptions options) async {
var isLegacy = await uriUsesLegacyLanguageVersion(script, options);
options.nnbdMode = isLegacy ? NnbdMode.Weak : NnbdMode.Strong;
}
/// Create front-end target with given name.
Target createFrontEndTarget(String targetName,
{bool trackWidgetCreation = false, bool nullSafety = false}) {

View file

@ -8,7 +8,6 @@ import 'package:path/path.dart' as path;
import 'package:test/test.dart';
import 'package:vm/snapshot/instruction_sizes.dart' as instruction_sizes;
import 'package:vm/snapshot/name.dart';
void main() async {
if (!Platform.executable.contains('dart-sdk')) {

View file

@ -0,0 +1,44 @@
// Copyright (c) 2020, 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.
// Tests auto-detection of null safety mode in gen_kernel tool.
import 'dart:io' show File, Platform;
import 'package:path/path.dart' as path;
import 'snapshot_test_helper.dart';
compileAndRunTest(String comment, String expectedOutput) async {
await withTempDir((String temp) async {
final testScriptPath = path.join(temp, 'test.dart');
File(testScriptPath).writeAsStringSync('''
// $comment
void main() {
try {
null as int;
print('weak mode');
} on TypeError {
print('strong mode');
}
}
''');
final testDillPath = path.join(temp, 'test.dill');
await runGenKernel('BUILD DILL FILE', [
'--enable-experiment=non-nullable',
'--output=$testDillPath',
testScriptPath,
]);
final result = await runBinary(
'RUN TEST FROM DILL', Platform.executable, [testDillPath]);
expectOutput(expectedOutput, result);
});
}
main() async {
await compileAndRunTest('', 'strong mode');
await compileAndRunTest('@dart=2.7', 'weak mode');
}

View file

@ -17,6 +17,7 @@ dart/data_uri_import_test/none: SkipByDesign
dart/emit_aot_size_info_flag_test: Pass, Slow # Spawns several subprocesses
dart/minimal_kernel_bytecode_test: Pass, Slow # Spawns several subprocesses
dart/minimal_kernel_test: Pass, Slow # Spawns several subprocesses
dart/null_safety_autodetection_in_kernel_compiler_test: Pass, Slow # Spawns several subprocesses
dart/slow_path_shared_stub_test: Pass, Slow # Uses --shared-slow-path-triggers-gc flag.
dart/snapshot_version_test: Skip # This test is a Dart1 test (script snapshot)
dart/stack_overflow_shared_test: Pass, Slow # Uses --shared-slow-path-triggers-gc flag.
@ -52,6 +53,7 @@ dart/appjit*: SkipByDesign # Test needs to a particular opt-counter value
dart/kernel_determinism_test: SkipSlow
dart/minimal_kernel_bytecode_test: SkipSlow # gen_kernel is too slow with optimization_counter_threshold
dart/minimal_kernel_test: SkipSlow # gen_kernel is too slow with optimization_counter_threshold
dart/null_safety_autodetection_in_kernel_compiler_test: SkipSlow # gen_kernel is too slow with optimization_counter_threshold
[ $builder_tag == tsan ]
dart/appjit_cha_deopt_test: SkipSlow
@ -79,6 +81,7 @@ cc/VerifyImplicit_Crash: Crash # Negative tests of VerifiedMemory should crash i
dart/appjit_cha_deopt_test: Pass, Slow # Quite slow in debug mode, uses --optimization-counter-threshold=100
dart/minimal_kernel_bytecode_test: SkipSlow # gen_kernel is too slow in debug mode
dart/minimal_kernel_test: SkipSlow # gen_kernel is too slow in debug mode
dart/null_safety_autodetection_in_kernel_compiler_test: SkipSlow # gen_kernel is too slow in debug mode
dart/spawn_shutdown_test: Pass, Slow # VM Shutdown test, It can take some time for all the isolates to shutdown in a Debug build.
[ $mode == product ]
@ -141,6 +144,7 @@ dart/bytecode_and_ast_mix_test: SkipByDesign # Test needs to run from source
dart/kernel_determinism_test: SkipByDesign # Test needs to run from source
dart/minimal_kernel_bytecode_test: SkipByDesign # Test needs to run from source
dart/minimal_kernel_test: SkipByDesign # Test needs to run from source
dart/null_safety_autodetection_in_kernel_compiler_test: SkipByDesign # Test needs to run from source
dart/snapshot_depfile_test: SkipByDesign # Test needs to run from source
[ $compiler == dartkp && ($runtime == dart_precompiled || $runtime == vm) ]
@ -202,6 +206,7 @@ dart/appjit*: SkipSlow # DFE too slow
dart/data_uri_spawn_test: Skip # Please triage.
dart/minimal_kernel_bytecode_test: SkipSlow # gen_kernel is too slow on simulated architectures
dart/minimal_kernel_test: SkipSlow # gen_kernel is too slow on simulated architectures
dart/null_safety_autodetection_in_kernel_compiler_test: SkipSlow # gen_kernel is too slow on simulated architectures
dart/snapshot_version_test: RuntimeError # Please triage.
[ $hot_reload || $hot_reload_rollback ]
@ -302,6 +307,7 @@ dart/disassemble_determinism_test: SkipSlow # Runs expensive fibonacci(32) compu
dart/issue_31959_31960_test: SkipSlow
dart/minimal_kernel_bytecode_test: SkipSlow # gen_kernel is too slow in hot reload testing mode
dart/minimal_kernel_test: SkipSlow # gen_kernel is too slow in hot reload testing mode
dart/null_safety_autodetection_in_kernel_compiler_test: SkipSlow # gen_kernel is too slow in hot reload testing mode
dart/print_flow_graph_determinism_test: SkipSlow
dart/slow_path_shared_stub_test: SkipSlow # Too slow with --shared-slow-path-triggers-gc flag and not relevant outside precompiled.
dart/spawn_infinite_loop_test: Skip # We can shutdown an isolate before it reloads.