[ddc] Migrate nullable_inference to null safety

Also migrate the test file and temporarily inline some path
generation logic to break import of command.dart until it is
migrated.

Issue: https://github.com/dart-lang/sdk/issues/46617
Change-Id: I50c158729346f3e31059241b90008ba861a65422
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/248341
Reviewed-by: Anna Gringauze <annagrin@google.com>
This commit is contained in:
Nicholas Shahan 2022-06-22 21:30:16 +00:00 committed by Commit Bot
parent 11e3c5c291
commit c52dd252f8
2 changed files with 43 additions and 36 deletions

View file

@ -2,8 +2,6 @@
// 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.
// @dart = 2.9
import 'dart:collection';
import 'package:kernel/core_types.dart';
@ -46,7 +44,7 @@ class NullableInference extends ExpressionVisitor<bool> {
final bool _soundNullSafety;
NullableInference(this.jsTypeRep, this._staticTypeContext,
{SharedCompilerOptions options})
{SharedCompilerOptions? options})
: coreTypes = jsTypeRep.coreTypes,
_soundNullSafety = options?.soundNullSafety ?? false {
_variableInference._nullInference = this;
@ -65,7 +63,7 @@ class NullableInference extends ExpressionVisitor<bool> {
}
/// Returns true if [expr] can be null.
bool isNullable(Expression expr) => expr != null ? expr.accept(this) : false;
bool isNullable(Expression expr) => expr.accept(this);
@override
bool defaultExpression(Expression node) => true;
@ -161,8 +159,8 @@ class NullableInference extends ExpressionVisitor<bool> {
_invocationIsNullable(node.interfaceTarget, node.name.text, node);
bool _invocationIsNullable(
Member target, String name, InvocationExpression node,
[Expression receiver]) {
Member? target, String name, InvocationExpression node,
[Expression? receiver]) {
// TODO(jmesserly): this is not a valid assumption for user-defined equality
// but it is added to match the behavior of the Analyzer backend.
// https://github.com/dart-lang/sdk/issues/31854
@ -170,7 +168,8 @@ class NullableInference extends ExpressionVisitor<bool> {
if (_staticallyNonNullable(node.getStaticType(_staticTypeContext))) {
return false;
}
if (target == null) return true; // dynamic call
// Dynamic call.
if (target == null) return true;
if (target.name.text == 'toString' &&
receiver != null &&
receiver.getStaticType(_staticTypeContext) ==
@ -184,20 +183,19 @@ class NullableInference extends ExpressionVisitor<bool> {
return _returnValueIsNullable(target);
}
bool _getterIsNullable(Member target, Expression node) {
bool _getterIsNullable(Member? target, Expression node) {
if (_staticallyNonNullable(node.getStaticType(_staticTypeContext))) {
return false;
}
// Dynamic access.
if (target == null) return true;
// tear-offs are not null
// Tear-offs are not null.
if (target is Procedure && !target.isAccessor) return false;
return _returnValueIsNullable(target);
}
bool _staticallyNonNullable(DartType type) =>
_soundNullSafety &&
type != null &&
type.nullability == Nullability.nonNullable;
_soundNullSafety && type.nullability == Nullability.nonNullable;
bool _returnValueIsNullable(Member target) {
var targetClass = target.enclosingClass;
@ -359,7 +357,7 @@ class NullableInference extends ExpressionVisitor<bool> {
///
// TODO(jmesserly): Introduce flow analysis.
class _NullableVariableInference extends RecursiveVisitor {
NullableInference _nullInference;
late NullableInference _nullInference;
/// Variables that are currently believed to be not-null.
final _notNullLocals = HashSet<VariableDeclaration>.identity();
@ -378,7 +376,7 @@ class _NullableVariableInference extends RecursiveVisitor {
/// The current variable we are setting/initializing, so we can track if it
/// is [_assignedTo] from another variable.
VariableDeclaration _variableAssignedTo;
VariableDeclaration? _variableAssignedTo;
void enterFunction(FunctionNode node) {
if (_functions.contains(node)) return; // local function already analyzed.
@ -395,7 +393,7 @@ class _NullableVariableInference extends RecursiveVisitor {
@override
void visitFunctionDeclaration(FunctionDeclaration node) {
_notNullLocals.add(node.variable);
node.function?.accept(this);
node.function.accept(this);
}
@override
@ -460,7 +458,7 @@ class _NullableVariableInference extends RecursiveVisitor {
_variableAssignedTo = variable;
if (_nullInference.isNullable(node.value)) {
void markNullable(VariableDeclaration v) {
void markNullable(VariableDeclaration? v) {
_notNullLocals.remove(v);
_assignedTo.remove(v)?.forEach(markNullable);
}
@ -476,7 +474,7 @@ class _NullableVariableInference extends RecursiveVisitor {
bool variableIsNullable(VariableDeclaration variable) {
if (_notNullLocals.contains(variable)) {
if (_variableAssignedTo != null) {
_assignedTo.putIfAbsent(variable, () => []).add(_variableAssignedTo);
_assignedTo.putIfAbsent(variable, () => []).add(_variableAssignedTo!);
}
return false;
}

View file

@ -2,12 +2,9 @@
// 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.
// @dart = 2.9
import 'dart:async';
import 'dart:io';
import 'package:dev_compiler/src/kernel/command.dart';
import 'package:dev_compiler/src/kernel/js_typerep.dart';
import 'package:dev_compiler/src/kernel/nullable_inference.dart';
import 'package:dev_compiler/src/kernel/target.dart';
@ -18,6 +15,7 @@ import 'package:kernel/kernel.dart';
import 'package:kernel/src/printer.dart';
import 'package:kernel/target/targets.dart';
import 'package:kernel/type_environment.dart';
import 'package:path/path.dart' as p;
import 'package:test/test.dart';
const AstTextStrategy astTextStrategy = AstTextStrategy(
@ -535,13 +533,13 @@ Future expectAllNotNull(String code) async {
}
bool useAnnotations = false;
NullableInference inference;
NullableInference? inference;
class _TestRecursiveVisitor extends RecursiveVisitor {
final Set<Library> librariesFromDill;
int _functionNesting = 0;
TypeEnvironment _typeEnvironment;
StatefulStaticTypeContext _staticTypeContext;
late TypeEnvironment _typeEnvironment;
late StatefulStaticTypeContext _staticTypeContext;
_TestRecursiveVisitor(this.librariesFromDill);
@ -558,8 +556,8 @@ class _TestRecursiveVisitor extends RecursiveVisitor {
inference ??= NullableInference(jsTypeRep, _staticTypeContext);
if (useAnnotations) {
inference.allowNotNullDeclarations = useAnnotations;
inference.allowPackageMetaAnnotations = useAnnotations;
inference!.allowNotNullDeclarations = useAnnotations;
inference!.allowPackageMetaAnnotations = useAnnotations;
}
super.visitComponent(node);
}
@ -601,10 +599,10 @@ class _TestRecursiveVisitor extends RecursiveVisitor {
void visitFunctionNode(FunctionNode node) {
_functionNesting++;
if (_functionNesting == 1) {
inference.enterFunction(node);
inference!.enterFunction(node);
}
super.visitFunctionNode(node);
if (_functionNesting == 1) inference.exitFunction(node);
if (_functionNesting == 1) inference!.exitFunction(node);
_functionNesting--;
}
}
@ -616,7 +614,7 @@ class NotNullCollector extends _TestRecursiveVisitor {
@override
void defaultExpression(Expression node) {
if (!inference.isNullable(node)) {
if (!inference!.isNullable(node)) {
notNullExpressions.add(node);
}
super.defaultExpression(node);
@ -628,13 +626,13 @@ class ExpectAllNotNull extends _TestRecursiveVisitor {
@override
void defaultExpression(Expression node) {
expect(inference.isNullable(node), false,
expect(inference!.isNullable(node), false,
reason: 'expression `$node` should be inferred as not-null');
super.defaultExpression(node);
}
}
fe.InitializedCompilerState _compilerState;
fe.InitializedCompilerState? _compilerState;
final _fileSystem = fe.MemoryFileSystem(Uri.file('/memory/'));
class CompileResult {
@ -653,11 +651,22 @@ Future<CompileResult> kernelCompile(String code) async {
fe.printDiagnosticMessage(message, print);
}
var root = Uri.file('/memory');
var sdkUri = Uri.file('/memory/dart_sdk.dill');
var sdkFile = _fileSystem.entityForUri(sdkUri);
if (!await sdkFile.exists()) {
sdkFile.writeAsBytesSync(
File(defaultSdkSummaryPath(soundNullSafety: false)).readAsBytesSync());
// TODO(46617) Call defaultSdkSummaryPath() to get the outlineDill path.
var sdkPath = p.dirname(p.dirname(Platform.resolvedExecutable));
var outlineDill = p.join(sdkPath, 'lib', '_internal', 'ddc_sdk.dill');
sdkFile.writeAsBytesSync(File(outlineDill).readAsBytesSync());
}
var librariesUri = Uri.file('/memory/libraries.json');
var librariesFile = _fileSystem.entityForUri(librariesUri);
if (!await librariesFile.exists()) {
// TODO(46617) Call getSdkPath() to get the SDK path.
var sdkPath = p.dirname(p.dirname(Platform.resolvedExecutable));
var librariesJson = p.join(sdkPath, 'lib', 'libraries.json');
librariesFile.writeAsBytesSync(File(librariesJson).readAsBytesSync());
}
var packagesUri = Uri.file('/memory/.packages');
var packagesFile = _fileSystem.entityForUri(packagesUri);
@ -676,17 +685,17 @@ const nullCheck = const _NullCheck();
var mainUri = Uri.file('/memory/test.dart');
_fileSystem.entityForUri(mainUri).writeAsStringSync(code);
var oldCompilerState = _compilerState;
_compilerState = fe.initializeCompiler(oldCompilerState, false, null, sdkUri,
packagesUri, null, [], DevCompilerTarget(TargetFlags()),
_compilerState = fe.initializeCompiler(oldCompilerState, false, root, sdkUri,
packagesUri, librariesUri, [], DevCompilerTarget(TargetFlags()),
fileSystem: _fileSystem,
explicitExperimentalFlags: const {},
environmentDefines: const {},
nnbdMode: fe.NnbdMode.Weak);
if (!identical(oldCompilerState, _compilerState)) inference = null;
var result =
await fe.compile(_compilerState, [mainUri], diagnosticMessageHandler);
await (fe.compile(_compilerState!, [mainUri], diagnosticMessageHandler));
expect(succeeded, true);
var librariesFromDill = result.computeLibrariesFromDill();
var librariesFromDill = result!.computeLibrariesFromDill();
return CompileResult(result.component, librariesFromDill);
}