Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 6a1c54e

Browse files
stereotype441commit-bot@chromium.org
authored andcommitted
Flow analysis: promote to non-nullable on initialization
When flow analysis encounters a variable declaration of the form `T? x = expr;`, if the type of `expr` is `T`, then the variable is immediately promoted to type `T`. Fixes #43099. Change-Id: Ia206fe0d50e2fdd9bdf637e13c85633d8490dbcc Bug: dart-lang/sdk#43099 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/163841 Commit-Queue: Paul Berry <[email protected]> Reviewed-by: Bob Nystrom <[email protected]> Reviewed-by: Johnni Winther <[email protected]> Reviewed-by: Konstantin Shcheglov <[email protected]>
1 parent 94f1c0b commit 6a1c54e

File tree

57 files changed

+142
-116
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

57 files changed

+142
-116
lines changed

pkg/_fe_analyzer_shared/test/flow_analysis/type_promotion/data/initialization.dart

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,18 @@ localVariable_ifElse_sameTypes(bool a) {
5555
x;
5656
}
5757

58+
localVariable_initialized_nonNull() {
59+
num? x = 0;
60+
/*num*/ x;
61+
x = null;
62+
x;
63+
}
64+
65+
localVariable_initialized_nonNull_final() {
66+
final num? x = 0;
67+
x;
68+
}
69+
5870
localVariable_initialized_promoted_type_var<T>(T t) {
5971
if (t is num) {
6072
var x = /*T & num*/ t;
@@ -94,13 +106,13 @@ localVariable_initialized_unpromoted_type_var_with_bound<T extends num?>(T t) {
94106

95107
localVariable_initialized_promoted_type_var_typed<T>(T t) {
96108
if (t is num) {
97-
// TODO(paulberry): This should promote to `T & Object`, because that's the
98-
// non-nullable version of T, but it shouldn't promote to `T & num`.
109+
// This should promote to `T & Object`, because that's the non-nullable
110+
// version of T, but it shouldn't promote to `T & num`.
99111
T x = /*T & num*/ t;
100-
x;
112+
/*T & Object*/ x;
101113
// Check that `T & Object` is a type of interest by promoting and then
102114
// writing to it
103-
if (x is int) {
115+
if (/*T & Object*/ x is int) {
104116
/*T & int*/ x;
105117
x = /*T & num*/ t;
106118
/*T & Object*/ x;

pkg/analyzer/lib/src/generated/resolver.dart

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1994,12 +1994,17 @@ class ResolverVisitor extends ScopedVisitor {
19941994
}
19951995

19961996
var initializer = node.initializer;
1997-
var parent = node.parent;
1998-
TypeAnnotation declaredType = (parent as VariableDeclarationList).type;
1999-
if (declaredType == null && initializer != null) {
1997+
var parent = node.parent as VariableDeclarationList;
1998+
TypeAnnotation declaredType = parent.type;
1999+
if (initializer != null) {
20002000
var initializerStaticType = initializer.staticType;
2001-
if (initializerStaticType is TypeParameterType) {
2002-
_flowAnalysis?.flow?.promote(declaredElement, initializerStaticType);
2001+
if (declaredType == null) {
2002+
if (initializerStaticType is TypeParameterType) {
2003+
_flowAnalysis?.flow?.promote(declaredElement, initializerStaticType);
2004+
}
2005+
} else if (!parent.isFinal) {
2006+
_flowAnalysis?.flow?.write(declaredElement, initializerStaticType,
2007+
viaInitializer: true);
20032008
}
20042009
}
20052010
}

pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5740,8 +5740,17 @@ class InferenceVisitor
57405740
}
57415741
if (initializerResult != null) {
57425742
DartType initializerType = initializerResult.inferredType;
5743-
if (node.isImplicitlyTyped && initializerType is TypeParameterType) {
5744-
inferrer.flowAnalysis.promote(node, initializerType);
5743+
if (node.isImplicitlyTyped) {
5744+
if (initializerType is TypeParameterType) {
5745+
inferrer.flowAnalysis.promote(node, initializerType);
5746+
}
5747+
} else if (!node.isFinal) {
5748+
// TODO(paulberry): `initializerType` is sometimes `null` during top
5749+
// level inference. Figure out how to prevent this.
5750+
if (initializerType != null) {
5751+
inferrer.flowAnalysis
5752+
.write(node, initializerType, viaInitializer: true);
5753+
}
57455754
}
57465755
Expression initializer = inferrer.ensureAssignableResult(
57475756
node.type, initializerResult,

pkg/front_end/testcases/incremental_initialize_from_dill/experiments_enabled_1.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ worlds:
1414
main() {
1515
dynamic x;
1616
print(x >>> 2);
17-
Class? c = new Class();
17+
Class? c = new Class() as Class?;
1818
print(c!);
1919
}
2020
class Class {}
21-
expectedLibraryCount: 1
21+
expectedLibraryCount: 1

pkg/front_end/testcases/nnbd/issue41114.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
// BSD-style license that can be found in the LICENSE file.
44

55
main() async {
6-
List<String>? a = <String>[];
6+
List<String>? a = <String>[] as List<String>?;
77
Iterable<String>? b = a?.map((e) => e);
88
Iterable<String>? i = b ?? a;
99
print(i);

pkg/front_end/testcases/nnbd/issue41114.dart.strong.expect

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import self as self;
33
import "dart:core" as core;
44

55
static method main() → dynamic async {
6-
core::List<core::String>? a = <core::String>[];
6+
core::List<core::String>? a = <core::String>[] as{ForNonNullableByDefault} core::List<core::String>?;
77
core::Iterable<core::String>? b = let final core::List<core::String>? #t1 = a in #t1.{core::List::==}(null) ?{core::Iterable<core::String>?} null : #t1{core::List<core::String>}.{core::Iterable::map}<core::String>((core::String e) → core::String => e);
88
core::Iterable<core::String>? i = let final core::Iterable<core::String>? #t2 = b in #t2.{core::Object::==}(null) ?{core::Iterable<core::String>?} a : #t2{core::Iterable<core::String>};
99
core::print(i);

pkg/front_end/testcases/nnbd/issue41114.dart.weak.expect

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import self as self;
33
import "dart:core" as core;
44

55
static method main() → dynamic async {
6-
core::List<core::String>? a = <core::String>[];
6+
core::List<core::String>? a = <core::String>[] as{ForNonNullableByDefault} core::List<core::String>?;
77
core::Iterable<core::String>? b = let final core::List<core::String>? #t1 = a in #t1.{core::List::==}(null) ?{core::Iterable<core::String>?} null : #t1{core::List<core::String>}.{core::Iterable::map}<core::String>((core::String e) → core::String => e);
88
core::Iterable<core::String>? i = let final core::Iterable<core::String>? #t2 = b in #t2.{core::Object::==}(null) ?{core::Iterable<core::String>?} a : #t2{core::Iterable<core::String>};
99
core::print(i);

pkg/front_end/testcases/nnbd/issue41495.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ class A {
1010
main() {}
1111

1212
errors() {
13-
A? a1 = new A();
13+
A? a1 = new A() as A?;
1414
a1.c1;
1515
a1.test;
1616
}

pkg/front_end/testcases/nnbd/issue41495.dart.strong.expect

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ class A extends core::Object {
2727
}
2828
static method main() → dynamic {}
2929
static method errors() → dynamic {
30-
self::A? a1 = new self::A::•();
30+
self::A? a1 = new self::A::•() as{ForNonNullableByDefault} self::A?;
3131
let final<BottomType> #t1 = invalid-expression "pkg/front_end/testcases/nnbd/issue41495.dart:14:6: Error: Property 'c1' cannot be accessed on 'A?' because it is potentially null.
3232
- 'A' is from 'pkg/front_end/testcases/nnbd/issue41495.dart'.
3333
Try accessing using ?. instead.

pkg/front_end/testcases/nnbd/issue41495.dart.weak.expect

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ class A extends core::Object {
2727
}
2828
static method main() → dynamic {}
2929
static method errors() → dynamic {
30-
self::A? a1 = new self::A::•();
30+
self::A? a1 = new self::A::•() as{ForNonNullableByDefault} self::A?;
3131
let final<BottomType> #t1 = invalid-expression "pkg/front_end/testcases/nnbd/issue41495.dart:14:6: Error: Property 'c1' cannot be accessed on 'A?' because it is potentially null.
3232
- 'A' is from 'pkg/front_end/testcases/nnbd/issue41495.dart'.
3333
Try accessing using ?. instead.

0 commit comments

Comments
 (0)