mirror of
https://github.com/dart-lang/sdk
synced 2024-10-14 09:58:32 +00:00
[ddc] Add option to throw null safety violations
Allows sound-like null safety when running mixed applications in weak mode. This is not a specified option and is only intended to assist large scale migration efforts. Change-Id: Icd0abb0e876d16e719a01e8381eef55a2b511051 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/171821 Commit-Queue: Nicholas Shahan <nshahan@google.com> Reviewed-by: Bob Nystrom <rnystrom@google.com> Reviewed-by: Mark Zhou <markzipan@google.com>
This commit is contained in:
parent
7878baf1eb
commit
bfe8aa8d5b
|
@ -49,18 +49,18 @@ void main(List<String> args) async {
|
|||
..addFlag('sound-null-safety',
|
||||
help: 'Compile for sound null safety at runtime. Passed through to the '
|
||||
'DDC binary. Defaults to false.',
|
||||
defaultsTo: false,
|
||||
negatable: true)
|
||||
defaultsTo: false)
|
||||
..addFlag('null-assertions',
|
||||
help: 'Run with assertions that values passed to non-nullable method '
|
||||
'parameters are not null.',
|
||||
defaultsTo: false,
|
||||
negatable: true)
|
||||
defaultsTo: false)
|
||||
..addFlag('native-null-assertions',
|
||||
help: 'Run with assertions on non-nullable values returned from native '
|
||||
'APIs.',
|
||||
defaultsTo: true,
|
||||
negatable: true)
|
||||
..addFlag('weak-null-safety-errors',
|
||||
help: 'Treat weak null safety warnings as errors.', defaultsTo: false)
|
||||
..addFlag('observe',
|
||||
help:
|
||||
'Run the compiler in the Dart VM with --observe. Implies --debug.',
|
||||
|
@ -86,7 +86,6 @@ void main(List<String> args) async {
|
|||
abbr: 'v',
|
||||
help: 'Echos the commands, arguments, and environment this script is '
|
||||
'running.',
|
||||
negatable: false,
|
||||
defaultsTo: false)
|
||||
..addOption('vm-service-port',
|
||||
help: 'Specify the observatory port. Implied --observe.');
|
||||
|
@ -115,19 +114,10 @@ void main(List<String> args) async {
|
|||
var compile = mode == 'compile' || mode == 'all';
|
||||
var run = mode == 'run' || mode == 'all';
|
||||
var verbose = options['verbose'] as bool;
|
||||
var soundNullSafety = options['sound-null-safety'] as bool;
|
||||
var nonNullAsserts = options['null-assertions'] as bool;
|
||||
var nativeNonNullAsserts = options['null-assertions'] as bool;
|
||||
|
||||
var soundNullSafety = options['sound-null-safety'] as bool;
|
||||
// Enable null safety either by passing the `non-nullable` experiment flag or
|
||||
// `sound-null-safety`.
|
||||
var nnbd = experiments.contains('non-nullable') || soundNullSafety;
|
||||
|
||||
// Ensure non-nullable is passed as a flag.
|
||||
if (soundNullSafety && !experiments.contains('non-nullable')) {
|
||||
experiments.add('non-nullable');
|
||||
}
|
||||
|
||||
var weakNullSafetyErrors = options['weak-null-safety-errors'] as bool;
|
||||
var entry = p.canonicalize(options.rest.first);
|
||||
var out = (options['out'] as String) ?? p.setExtension(entry, '.js');
|
||||
var libRoot = p.dirname(entry);
|
||||
|
@ -275,11 +265,12 @@ void main(List<String> args) async {
|
|||
require(['dart_sdk', '$basename'],
|
||||
function(sdk, app) {
|
||||
'use strict';
|
||||
if ($nnbd) {
|
||||
sdk.dart.weakNullSafetyWarnings(!$soundNullSafety);
|
||||
sdk.dart.nonNullAsserts($nonNullAsserts);
|
||||
sdk.dart.nativeNonNullAsserts($nativeNonNullAsserts);
|
||||
}
|
||||
|
||||
sdk.dart.weakNullSafetyWarnings(
|
||||
!($weakNullSafetyErrors || $soundNullSafety));
|
||||
sdk.dart.weakNullSafetyErrors($weakNullSafetyErrors);
|
||||
sdk.dart.nonNullAsserts($nonNullAsserts);
|
||||
sdk.dart.nativeNonNullAsserts($nativeNonNullAsserts);
|
||||
sdk._debugger.registerDevtoolsFormatter();
|
||||
app.$libname.main([]);
|
||||
});
|
||||
|
@ -311,11 +302,11 @@ let sdk = require(\"dart_sdk\");
|
|||
sdk.dart.global.self = sdk.dart.global;
|
||||
let main = require(\"./$basename\").$libname.main;
|
||||
try {
|
||||
if ($nnbd) {
|
||||
sdk.dart.weakNullSafetyWarnings(!$soundNullSafety);
|
||||
sdk.dart.nonNullAsserts($nonNullAsserts);
|
||||
sdk.dart.nativeNonNullAsserts($nativeNonNullAsserts);
|
||||
}
|
||||
sdk.dart.weakNullSafetyWarnings(
|
||||
!($weakNullSafetyErrors || $soundNullSafety));
|
||||
sdk.dart.weakNullSafetyErrors($weakNullSafetyErrors);
|
||||
sdk.dart.nonNullAsserts($nonNullAsserts);
|
||||
sdk.dart.nativeNonNullAsserts($nativeNonNullAsserts);
|
||||
sdk._isolate_helper.startRootIsolate(main, []);
|
||||
} catch(e) {
|
||||
if (!source_maps) {
|
||||
|
@ -346,14 +337,14 @@ load("$ddcPath/lib/js/legacy/dart_library.js");
|
|||
load("$sdkJsPath/dart_sdk.js");
|
||||
load("$out");
|
||||
|
||||
let dart_sdk = dart_library.import('dart_sdk');
|
||||
let sdk = dart_library.import('dart_sdk');
|
||||
// Create a self reference for JS interop tests that set fields on self.
|
||||
dart_sdk.dart.global.self = dart_sdk.dart.global;
|
||||
if ($nnbd) {
|
||||
dart_sdk.dart.weakNullSafetyWarnings(!$soundNullSafety);
|
||||
dart_sdk.dart.nonNullAsserts($nonNullAsserts);
|
||||
dart_sdk.dart.nativeNonNullAsserts($nativeNonNullAsserts);
|
||||
}
|
||||
sdk.dart.global.self = sdk.dart.global;
|
||||
sdk.dart.weakNullSafetyWarnings(
|
||||
!($weakNullSafetyErrors || $soundNullSafety));
|
||||
sdk.dart.weakNullSafetyErrors($weakNullSafetyErrors);
|
||||
sdk.dart.nonNullAsserts($nonNullAsserts);
|
||||
sdk.dart.nativeNonNullAsserts($nativeNonNullAsserts);
|
||||
dart_library.start('$basename', '$libname');
|
||||
''';
|
||||
var d8File = p.setExtension(out, '.d8.js');
|
||||
|
|
|
@ -147,9 +147,16 @@ bool _invalidVariableName(String keyword, {bool strictMode = true}) {
|
|||
/// [testJSDir] is the relative path to the build directory where the
|
||||
/// dartdevc-generated JS file is stored. [nonNullAsserts] enables non-null
|
||||
/// assertions for non-nullable method parameters when running with weak null
|
||||
/// safety.
|
||||
String dartdevcHtml(String testName, String testNameAlias, String testJSDir,
|
||||
Compiler compiler, NnbdMode mode, bool nonNullAsserts) {
|
||||
/// safety. [weakNullSafetyErrors] enables null safety type violations to throw
|
||||
/// when running in weak mode.
|
||||
String dartdevcHtml(
|
||||
String testName,
|
||||
String testNameAlias,
|
||||
String testJSDir,
|
||||
Compiler compiler,
|
||||
NnbdMode mode,
|
||||
bool nonNullAsserts,
|
||||
bool weakNullSafetyErrors) {
|
||||
var testId = pathToJSIdentifier(testName);
|
||||
var testIdAlias = pathToJSIdentifier(testNameAlias);
|
||||
var isNnbd = mode != NnbdMode.legacy;
|
||||
|
@ -233,7 +240,8 @@ requirejs(["$testName", "dart_sdk", "async_helper"],
|
|||
};
|
||||
|
||||
if ($isNnbd) {
|
||||
sdk.dart.weakNullSafetyWarnings(!$isNnbdStrong);
|
||||
sdk.dart.weakNullSafetyWarnings(!($weakNullSafetyErrors || $isNnbdStrong));
|
||||
sdk.dart.weakNullSafetyErrors($weakNullSafetyErrors);
|
||||
sdk.dart.nonNullAsserts($nonNullAsserts);
|
||||
}
|
||||
|
||||
|
|
|
@ -925,8 +925,16 @@ class StandardTestSuite extends TestSuite {
|
|||
Path(compilationTempDir).relativeTo(Repository.dir).toString();
|
||||
var nullAssertions =
|
||||
testFile.sharedOptions.contains('--null-assertions');
|
||||
content = dartdevcHtml(nameNoExt, nameFromModuleRootNoExt, jsDir,
|
||||
configuration.compiler, configuration.nnbdMode, nullAssertions);
|
||||
var weakNullSafetyErrors =
|
||||
testFile.ddcOptions.contains('--weak-null-safety-errors');
|
||||
content = dartdevcHtml(
|
||||
nameNoExt,
|
||||
nameFromModuleRootNoExt,
|
||||
jsDir,
|
||||
configuration.compiler,
|
||||
configuration.nnbdMode,
|
||||
nullAssertions,
|
||||
weakNullSafetyErrors);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -12,26 +12,49 @@ part of dart._runtime;
|
|||
@notNull
|
||||
external bool compileTimeFlag(String flag);
|
||||
|
||||
_throwNullSafetyWarningError() => throw UnsupportedError(
|
||||
'Null safety errors cannot be shown as warnings when running with sound '
|
||||
'null safety.');
|
||||
_throwInvalidFlagError(String message) =>
|
||||
throw UnsupportedError('Invalid flag combination.\n$message');
|
||||
|
||||
@notNull
|
||||
bool _weakNullSafetyWarnings = false;
|
||||
|
||||
/// Sets the runtime mode to show warnings when running with weak null safety.
|
||||
/// Sets the runtime mode to show warnings when types violate sound null safety.
|
||||
///
|
||||
/// These are warnings for issues that will become errors when sound null safety
|
||||
/// is enabled. Showing warnings while running with sound null safety is not
|
||||
/// supported (they will be errors).
|
||||
/// This option is not compatible with weak null safety errors or sound null
|
||||
/// safety (the warnings will be errors).
|
||||
void weakNullSafetyWarnings(bool showWarnings) {
|
||||
if (showWarnings && compileTimeFlag('soundNullSafety')) {
|
||||
_throwNullSafetyWarningError();
|
||||
_throwInvalidFlagError(
|
||||
'Null safety violations cannot be shown as warnings when running with '
|
||||
'sound null safety.');
|
||||
}
|
||||
|
||||
_weakNullSafetyWarnings = showWarnings;
|
||||
}
|
||||
|
||||
@notNull
|
||||
bool _weakNullSafetyErrors = false;
|
||||
|
||||
/// Sets the runtime mode to throw errors when types violate sound null safety.
|
||||
///
|
||||
/// This option is not compatible with weak null safety warnings (the warnings
|
||||
/// are now errors) or sound null safety (the errors are already errors).
|
||||
void weakNullSafetyErrors(bool showErrors) {
|
||||
if (showErrors && compileTimeFlag('soundNullSafety')) {
|
||||
_throwInvalidFlagError(
|
||||
'Null safety violations are already thrown as errors when running with '
|
||||
'sound null safety.');
|
||||
}
|
||||
|
||||
if (showErrors && _weakNullSafetyWarnings) {
|
||||
_throwInvalidFlagError(
|
||||
'Null safety violations can be shown as warnings or thrown as errors, '
|
||||
'not both.');
|
||||
}
|
||||
|
||||
_weakNullSafetyErrors = showErrors;
|
||||
}
|
||||
|
||||
@notNull
|
||||
bool _nonNullAsserts = false;
|
||||
|
||||
|
@ -250,10 +273,12 @@ void _warn(arg) {
|
|||
JS('void', 'console.warn(#)', arg);
|
||||
}
|
||||
|
||||
void _nullWarn(arg) {
|
||||
void _nullWarn(message) {
|
||||
if (_weakNullSafetyWarnings) {
|
||||
_warn('$arg\n'
|
||||
_warn('$message\n'
|
||||
'This will become a failure when runtime null safety is enabled.');
|
||||
} else if (_weakNullSafetyErrors) {
|
||||
throw TypeErrorImpl(message);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
17
tests/dartdevc/weak_null_safety_errors_test.dart
Normal file
17
tests/dartdevc/weak_null_safety_errors_test.dart
Normal file
|
@ -0,0 +1,17 @@
|
|||
// 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.
|
||||
|
||||
// Requirements=nnbd-weak
|
||||
|
||||
// dartdevcOptions=--weak-null-safety-errors
|
||||
|
||||
import 'package:expect/expect.dart';
|
||||
|
||||
void main() {
|
||||
Expect.throwsTypeError(() => null as int);
|
||||
dynamic dynamicNull = null;
|
||||
Expect.throwsTypeError(() => fn(dynamicNull));
|
||||
}
|
||||
|
||||
void fn(StringBuffer arg) {}
|
Loading…
Reference in a new issue