[ddc] Inline the sound null safety flag

Now that the sound null safety mode is a compile time flag
instead of a runtime flag there is no need to set the value in
the bootstrapping code before running main(). The sound and weak
versions of the sdk now have it already set.

Add compileTimeFlag() method that will inline the constant value
directly into the generated output.

Change-Id: I5b9243c47cffc421067ac820ef49342b9d0efff9
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/154100
Reviewed-by: Mark Zhou <markzipan@google.com>
Reviewed-by: Sigmund Cherem <sigmund@google.com>
Commit-Queue: Nicholas Shahan <nshahan@google.com>
This commit is contained in:
Nicholas Shahan 2020-07-13 22:45:19 +00:00 committed by commit-bot@chromium.org
parent 69d11907ec
commit 7478143e5f
8 changed files with 32 additions and 40 deletions

View file

@ -4849,6 +4849,14 @@ class ProgramCompiler extends ComputeOnceConstantVisitor<js_ast.Expression>
if (name == 'extensionSymbol' && firstArg is StringLiteral) {
return getExtensionSymbolInternal(firstArg.value);
}
if (name == 'compileTimeFlag' && firstArg is StringLiteral) {
var flagName = firstArg.value;
if (flagName == 'soundNullSafety') {
return js.boolean(_options.soundNullSafety);
}
throw UnsupportedError('Invalid flag in call to $name: $flagName');
}
} else if (node.arguments.positional.length == 2) {
var firstArg = node.arguments.positional[0];
var secondArg = node.arguments.positional[1];

View file

@ -259,8 +259,6 @@ class RunD8 implements IOModularStep {
var runjs = '''
import { dart, _isolate_helper } from 'dart_sdk.js';
import { main } from 'main.js';
// Run with weak null safety.
dart.nullSafety(false);
_isolate_helper.startRootIsolate(() => {}, []);
main.main();
''';

View file

@ -263,7 +263,6 @@ class RunD8 implements IOModularStep {
var runjs = '''
import { dart, _isolate_helper } from 'dart_sdk.js';
import { main } from 'main.js';
dart.nullSafety(false);
_isolate_helper.startRootIsolate(() => {}, []);
main.main();
''';

View file

@ -276,7 +276,6 @@ void main(List<String> args) async {
function(sdk, app) {
'use strict';
if ($nnbd) {
sdk.dart.nullSafety($soundNullSafety);
sdk.dart.weakNullSafetyWarnings(!$soundNullSafety);
sdk.dart.nonNullAsserts($nonNullAsserts);
}
@ -310,7 +309,6 @@ let sdk = require(\"dart_sdk\");
let main = require(\"./$basename\").$libname.main;
try {
if ($nnbd) {
sdk.dart.nullSafety($soundNullSafety);
sdk.dart.weakNullSafetyWarnings(!$soundNullSafety);
sdk.dart.nonNullAsserts($nonNullAsserts);
}
@ -345,7 +343,6 @@ import { $libname } from '$basename.js';
let main = $libname.main;
try {
if ($nnbd) {
dart.nullSafety($soundNullSafety);
dart.weakNullSafetyWarnings(!$soundNullSafety);
dart.nonNullAsserts($nonNullAsserts);
}

View file

@ -233,7 +233,6 @@ requirejs(["$testName", "dart_sdk", "async_helper"],
};
if ($isNnbd) {
sdk.dart.nullSafety($isNnbdStrong);
sdk.dart.weakNullSafetyWarnings(!$isNnbdStrong);
sdk.dart.nonNullAsserts($nonNullAsserts);
}

View file

@ -11,7 +11,8 @@ import 'dart:_foreign_helper' show JS;
import 'dart:_runtime' as dart;
@patch
bool typeAcceptsNull<T>() => !dart.strictNullSafety || null is T;
bool typeAcceptsNull<T>() =>
!dart.compileTimeFlag('soundNullSafety') || null is T;
@patch
class Symbol implements core.Symbol {

View file

@ -185,7 +185,7 @@ String? _argumentErrors(FunctionType type, List actuals, namedActuals) {
if (missingRequired.isNotEmpty) {
var error = "Dynamic call with missing required named arguments: "
"${missingRequired.join(', ')}.";
if (!strictNullSafety) {
if (!compileTimeFlag('soundNullSafety')) {
_nullWarn(error);
} else {
return error;
@ -430,7 +430,7 @@ bool instanceOf(obj, type) {
cast(obj, type) {
// We hoist the common case where null is checked against another type here
// for better performance.
if (obj == null && !strictNullSafety) {
if (obj == null && !compileTimeFlag('soundNullSafety')) {
// Check the null comparison cache to avoid emitting repeated warnings.
_nullWarnOnType(type);
return obj;
@ -450,7 +450,9 @@ bool test(bool? obj) {
bool dtest(obj) {
// Only throw an AssertionError in weak mode for compatibility. Strong mode
// should throw a TypeError.
if (obj is! bool) booleanConversionFailed(strictNullSafety ? obj : test(obj));
if (obj is! bool)
booleanConversionFailed(
compileTimeFlag('soundNullSafety') ? obj : test(obj));
return obj;
}
@ -462,7 +464,7 @@ void booleanConversionFailed(obj) {
asInt(obj) {
// Note: null (and undefined) will fail this test.
if (JS('!', 'Math.floor(#) != #', obj, obj)) {
if (obj == null && !strictNullSafety) {
if (obj == null && !compileTimeFlag('soundNullSafety')) {
_nullWarnOnType(JS('', '#', int));
return null;
} else {
@ -498,7 +500,7 @@ _notNull(x) {
/// variants of the same type.
nullCast(x, type) {
if (x == null) {
if (!strictNullSafety) {
if (!compileTimeFlag('soundNullSafety')) {
_nullWarnOnType(type);
} else {
castError(x, type);

View file

@ -5,32 +5,17 @@
/// This library defines the representation of runtime types.
part of dart._runtime;
/// Returns the state of [flag] that is determined at compile time.
///
/// The constant value itself is inlined by the compiler in place of the call
/// to this method.
@notNull
external bool compileTimeFlag(String flag);
_throwNullSafetyWarningError() => throw UnsupportedError(
'Null safety errors cannot be shown as warnings when running with sound '
'null safety.');
@notNull
bool _setNullSafety = false;
@notNull
bool strictNullSafety = false;
/// Sets the mode of the runtime subtype checks.
///
/// Changing the mode after the application has started running is not
/// supported.
void nullSafety(bool soundNullSafety) {
if (_setNullSafety) {
throw UnsupportedError('The Null Safety mode can only be set once.');
}
if (soundNullSafety && _weakNullSafetyWarnings)
_throwNullSafetyWarningError();
strictNullSafety = soundNullSafety;
_setNullSafety = true;
}
@notNull
bool _weakNullSafetyWarnings = false;
@ -40,7 +25,9 @@ bool _weakNullSafetyWarnings = false;
/// is enabled. Showing warnings while running with sound null safety is not
/// supported (they will be errors).
void weakNullSafetyWarnings(bool showWarnings) {
if (showWarnings && strictNullSafety) _throwNullSafetyWarningError();
if (showWarnings && compileTimeFlag('soundNullSafety')) {
_throwNullSafetyWarningError();
}
_weakNullSafetyWarnings = showWarnings;
}
@ -910,7 +897,7 @@ class GenericFunctionTypeIdentifier extends AbstractFunctionType {
var bound = typeBounds[i];
if (_equalType(bound, dynamic) ||
JS<bool>('!', '# === #', bound, nullable(unwrapType(Object))) ||
(!strictNullSafety && _equalType(bound, Object))) {
(!compileTimeFlag('soundNullSafety') && _equalType(bound, Object))) {
// Do not print the bound when it is a top type. In weak mode the bounds
// of Object and Object* will also be elided.
continue;
@ -1009,7 +996,8 @@ class GenericFunctionType extends AbstractFunctionType {
// difference is rare.
if (_equalType(type, dynamic)) return true;
if (_jsInstanceOf(type, NullableType) ||
(!strictNullSafety && _jsInstanceOf(type, LegacyType))) {
(!compileTimeFlag('soundNullSafety') &&
_jsInstanceOf(type, LegacyType))) {
return _equalType(JS('!', '#.type', type), Object);
}
return false;
@ -1301,7 +1289,7 @@ bool isSubtypeOf(@notNull Object t1, @notNull Object t2) {
if (JS('!', '# !== void 0', result)) return result;
var validSubtype = _isSubtype(t1, t2, true);
if (!validSubtype && !strictNullSafety) {
if (!validSubtype && !compileTimeFlag('soundNullSafety')) {
validSubtype = _isSubtype(t1, t2, false);
if (validSubtype) {
// TODO(nshahan) Need more information to be helpful here.
@ -1757,7 +1745,7 @@ class _TypeInferrer {
var supertypeRequiredNamed = supertype.getRequiredNamedParameters();
var subtypeNamed = supertype.getNamedParameters();
var subtypeRequiredNamed = supertype.getRequiredNamedParameters();
if (!strictNullSafety) {
if (!compileTimeFlag('soundNullSafety')) {
// In weak mode, treat required named params as optional named params.
supertypeNamed = {...supertypeNamed, ...supertypeRequiredNamed};
subtypeNamed = {...subtypeNamed, ...subtypeRequiredNamed};