Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(994)

Unified Diff: lib/src/codegen/nullable_type_inference.dart

Issue 1752193002: Add a few more known non-null cases (Closed) Base URL: git@github.com:dart-lang/dev_compiler.git@master
Patch Set: Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « lib/src/codegen/js_codegen.dart ('k') | test/codegen/expect/expect.js » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: lib/src/codegen/nullable_type_inference.dart
diff --git a/lib/src/codegen/nullable_type_inference.dart b/lib/src/codegen/nullable_type_inference.dart
index d8ec62c85ba7409711684a76ed1f19119af67cee..54999a4802d1788dabd647095502b5b20db92bad 100644
--- a/lib/src/codegen/nullable_type_inference.dart
+++ b/lib/src/codegen/nullable_type_inference.dart
@@ -7,7 +7,6 @@ import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/ast/token.dart' show TokenType;
import 'package:analyzer/dart/ast/visitor.dart' show RecursiveAstVisitor;
import 'package:analyzer/src/generated/element.dart';
-import 'package:func/func.dart';
import '../utils.dart' show getStaticType, isInlineJS;
/// An inference engine for nullable types.
@@ -20,20 +19,22 @@ import '../utils.dart' show getStaticType, isInlineJS;
/// optimize some patterns.
// TODO(vsm): Revisit whether we really need this when we get
// better non-nullability in the type system.
-class NullableTypeInference {
- final Func1<DartType, bool> _isPrimitiveType;
+abstract class NullableTypeInference {
+ bool isPrimitiveType(DartType type);
+ bool isObjectProperty(String name);
/// Known non-null local variables.
HashSet<LocalVariableElement> _notNullLocals;
- NullableTypeInference.forLibrary(
- this._isPrimitiveType, Iterable<CompilationUnit> units) {
+ void inferNullableTypesInLibrary(Iterable<CompilationUnit> units) {
var visitor = new _NullableLocalInference(this);
for (var unit in units) unit.accept(visitor);
_notNullLocals = visitor.computeNotNullLocals();
}
- void addVariable(LocalVariableElement local, {bool nullable: true}) {
+ /// Adds a new variable, typically a compiler generated temporary, and record
+ /// whether its type is nullable.
+ void addTemporaryVariable(LocalVariableElement local, {bool nullable: true}) {
if (!nullable) _notNullLocals.add(local);
}
@@ -51,19 +52,28 @@ class NullableTypeInference {
// leads to O(depth) cost for calling this function. We could store the
// resulting value if that becomes an issue, so we maintain the invariant
// that each node is visited once.
-
- if (expr is SimpleIdentifier) {
+ Element element = null;
+ if (expr is PropertyAccess) {
+ element = expr.propertyName.staticElement;
+ } else if (expr is Identifier) {
+ element = expr.staticElement;
+ }
+ if (element != null) {
// Type literals are not null.
- var e = expr.staticElement;
- if (e is ClassElement || e is FunctionTypeAliasElement) {
+ if (element is ClassElement || element is FunctionTypeAliasElement) {
return false;
}
- if (e is LocalVariableElement) {
+ if (element is LocalVariableElement) {
if (localIsNullable != null) {
- return localIsNullable(e);
+ return localIsNullable(element);
}
- return !_notNullLocals.contains(e);
+ return !_notNullLocals.contains(element);
+ }
+
+ if (element is FunctionElement || element is MethodElement) {
+ // A function or method. This can't be null.
+ return false;
}
// Other types of identifiers are nullable (parameters, fields).
@@ -75,7 +85,27 @@ class NullableTypeInference {
if (expr is FunctionExpression) return false;
if (expr is ThisExpression) return false;
if (expr is SuperExpression) return false;
- if (expr is CascadeExpression) return false;
+ if (expr is CascadeExpression) {
+ // Cascades normally can't return `null`, because if the target is null,
+ // they will throw noSuchMethod.
+ // The only properties/methods on `null` are those on Object itself.
+ for (var section in expr.cascadeSections) {
+ Element e = null;
+ if (section is PropertyAccess) {
+ e = section.propertyName.staticElement;
+ } else if (section is MethodInvocation) {
+ e = section.methodName.staticElement;
+ } else if (section is IndexExpression) {
+ // Object does not have operator []=.
+ return false;
+ }
+ // We encountered a non-Object method/property.
+ if (e != null && !isObjectProperty(e.name)) {
+ return false;
+ }
+ }
+ return _isNullable(expr.target, localIsNullable);
+ }
if (expr is ConditionalExpression) {
return _isNullable(expr.thenExpression, localIsNullable) ||
_isNullable(expr.elseExpression, localIsNullable);
@@ -83,6 +113,25 @@ class NullableTypeInference {
if (expr is ParenthesizedExpression) {
return _isNullable(expr.expression, localIsNullable);
}
+ if (expr is InstanceCreationExpression) {
+ var e = expr.staticElement;
+ if (e == null) return true;
+
+ // Follow redirects.
+ while (e.redirectedConstructor != null) {
+ e = e.redirectedConstructor;
+ }
+
+ // Generative constructors are not nullable.
+ if (!e.isFactory) return false;
+
+ // Factory constructors are nullable. However it is a bad pattern and
+ // our own SDK will never do this.
+ // TODO(jmesserly): we could enforce this for user-defined constructors.
+ if (e.library.source.isInSystemLibrary) return false;
+
+ return true;
+ }
DartType type = null;
if (expr is BinaryExpression) {
@@ -103,7 +152,7 @@ class NullableTypeInference {
} else if (expr is PostfixExpression) {
type = getStaticType(expr.operand);
}
- if (type != null && _isPrimitiveType(type)) {
+ if (type != null && isPrimitiveType(type)) {
return false;
}
if (expr is MethodInvocation) {
@@ -127,12 +176,16 @@ class NullableTypeInference {
}
}
}
- // TODO(ochafik): Handle `identical` invocations.
+
+ if (e != null &&
+ e.name == 'identical' &&
+ e.library.source.uri.toString() == 'dart:core') {
+ return false;
+ }
}
- // TODO(ochafik): Handle PrefixedIdentifier, refs to top-level finals
- // that have been assigned non-nullable values, non-generative constructor
- // calls, refs to local functions...
+ // TODO(ochafik,jmesserly): handle other cases such as: refs to top-level
+ // finals that have been assigned non-nullable values.
// Failed to recognize a non-nullable case: assume it can be null.
return true;
« no previous file with comments | « lib/src/codegen/js_codegen.dart ('k') | test/codegen/expect/expect.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698