mirror of
https://github.com/dart-lang/sdk
synced 2024-09-16 00:19:48 +00:00
[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:
parent
11e3c5c291
commit
c52dd252f8
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue