Report an error when a potentially non-nullable local variable is not initialized.
R=brianwilkerson@google.com, paulberry@google.com
Change-Id: Ie1d148ff584c202edc334659eeb4f792bb8773d4
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/106620
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Reviewed-by: Paul Berry <paulberry@google.com>
diff --git a/pkg/analyzer/lib/error/error.dart b/pkg/analyzer/lib/error/error.dart
index ed09816..046a034 100644
--- a/pkg/analyzer/lib/error/error.dart
+++ b/pkg/analyzer/lib/error/error.dart
@@ -236,6 +236,7 @@
CompileTimeErrorCode.NON_GENERATIVE_CONSTRUCTOR,
CompileTimeErrorCode.NON_SYNC_FACTORY,
CompileTimeErrorCode.NOT_ENOUGH_REQUIRED_ARGUMENTS,
+ CompileTimeErrorCode.NOT_INITIALIZED_POTENTIALLY_NON_NULLABLE_LOCAL_VARIABLE,
CompileTimeErrorCode.NOT_ITERABLE_SPREAD,
CompileTimeErrorCode.NOT_MAP_SPREAD,
CompileTimeErrorCode.NOT_NULL_AWARE_NULL_SPREAD,
diff --git a/pkg/analyzer/lib/src/error/codes.dart b/pkg/analyzer/lib/src/error/codes.dart
index 278a7f7..faec666 100644
--- a/pkg/analyzer/lib/src/error/codes.dart
+++ b/pkg/analyzer/lib/src/error/codes.dart
@@ -2453,6 +2453,22 @@
correction: "Try adding the missing arguments.");
/**
+ * It is an error if a potentially non-nullable local variable which has no
+ * initializer expression and is not marked `late` is used before it is
+ * definitely assigned.
+ *
+ * TODO(scheglov) Update the code and the message when implement definite
+ * assignment analysis.
+ */
+ static const CompileTimeErrorCode
+ NOT_INITIALIZED_POTENTIALLY_NON_NULLABLE_LOCAL_VARIABLE =
+ const CompileTimeErrorCode(
+ 'NOT_INITIALIZED_POTENTIALLY_NON_NULLABLE_LOCAL_VARIABLE',
+ "Non-nullable local variable '{0}' must be initialized.",
+ correction:
+ "Try giving it an initializer expression, or mark it 'late'.");
+
+ /**
* No parameters.
*/
// #### Description
diff --git a/pkg/analyzer/lib/src/generated/error_verifier.dart b/pkg/analyzer/lib/src/generated/error_verifier.dart
index db6b5ca..bcb76f5 100644
--- a/pkg/analyzer/lib/src/generated/error_verifier.dart
+++ b/pkg/analyzer/lib/src/generated/error_verifier.dart
@@ -1439,6 +1439,7 @@
@override
void visitVariableDeclarationStatement(VariableDeclarationStatement node) {
_checkForFinalNotInitialized(node.variables);
+ _checkForNotInitializedPotentiallyNonNullableLocalVariable(node.variables);
super.visitVariableDeclarationStatement(node);
}
@@ -3367,6 +3368,43 @@
}
}
+ void _checkForNotInitializedPotentiallyNonNullableLocalVariable(
+ VariableDeclarationList node,
+ ) {
+ // Const and final checked separately.
+ if (node.isConst || node.isFinal) {
+ return;
+ }
+
+ if (!_isNonNullable) {
+ return;
+ }
+
+ if (node.isLate) {
+ return;
+ }
+
+ if (node.type == null) {
+ return;
+ }
+ var type = node.type.type;
+
+ if (!_typeSystem.isPotentiallyNonNullable(type)) {
+ return;
+ }
+
+ for (var variable in node.variables) {
+ if (variable.initializer == null) {
+ _errorReporter.reportErrorForNode(
+ CompileTimeErrorCode
+ .NOT_INITIALIZED_POTENTIALLY_NON_NULLABLE_LOCAL_VARIABLE,
+ variable.name,
+ [variable.name.name],
+ );
+ }
+ }
+ }
+
/**
* If there are no constructors in the given [members], verify that all
* final fields are initialized. Cases in which there is at least one
diff --git a/pkg/analyzer/test/src/dart/resolution/non_nullable_test.dart b/pkg/analyzer/test/src/dart/resolution/non_nullable_test.dart
index c722521..35f6532 100644
--- a/pkg/analyzer/test/src/dart/resolution/non_nullable_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/non_nullable_test.dart
@@ -26,243 +26,6 @@
@override
bool get typeToStringWithNullability => true;
- test_local_getterNullAwareAccess_interfaceType() async {
- addTestFile(r'''
-m() {
- int? x;
- return x?.isEven;
-}
-''');
-
- await resolveTestFile();
- assertNoTestErrors();
- assertType(findNode.propertyAccess('x?.isEven'), 'bool?');
- }
-
- test_local_methodNullAwareCall_interfaceType() async {
- await addTestFile(r'''
-class C {
- bool x() => true;
-}
-m() {
- C? c;
- return c?.x();
-}
-''');
-
- await resolveTestFile();
- assertNoTestErrors();
- assertType(findNode.methodInvocation('c?.x()'), 'bool?');
- }
-
- test_local_nullCoalesce_nullableInt_int() async {
- await addTestFile(r'''
-m() {
- int? x;
- int y;
- x ?? y;
-}
-''');
- await resolveTestFile();
- assertNoTestErrors();
- assertType(findNode.binary('x ?? y'), 'int');
- }
-
- test_local_nullCoalesce_nullableInt_nullableInt() async {
- await addTestFile(r'''
-m() {
- int? x;
- x ?? x;
-}
-''');
- await resolveTestFile();
- assertNoTestErrors();
- assertType(findNode.binary('x ?? x'), 'int?');
- }
-
- test_local_nullCoalesceAssign_nullableInt_int() async {
- await addTestFile(r'''
-m() {
- int? x;
- int y;
- x ??= y;
-}
-''');
- await resolveTestFile();
- assertNoTestErrors();
- assertType(findNode.assignment('x ??= y'), 'int');
- }
-
- test_local_nullCoalesceAssign_nullableInt_nullableInt() async {
- await addTestFile(r'''
-m() {
- int? x;
- x ??= x;
-}
-''');
- await resolveTestFile();
- assertNoTestErrors();
- assertType(findNode.assignment('x ??= x'), 'int?');
- }
-
- test_local_parameter_interfaceType() async {
- addTestFile('''
-main() {
- f(int? a, int b) {}
-}
-''');
- await resolveTestFile();
- assertNoTestErrors();
-
- assertType(findNode.typeName('int? a'), 'int?');
- assertType(findNode.typeName('int b'), 'int');
- }
-
- test_local_returnType_interfaceType() async {
- addTestFile('''
-main() {
- int? f() => 0;
- int g() => 0;
-}
-''');
- await resolveTestFile();
- assertNoTestErrors();
-
- assertType(findNode.typeName('int? f'), 'int?');
- assertType(findNode.typeName('int g'), 'int');
- }
-
- @failingTest
- test_local_variable_genericFunctionType() async {
- addTestFile('''
-main() {
- int? Function(bool, String?)? a;
-}
-''');
- await resolveTestFile();
- assertNoTestErrors();
-
- assertType(
- findNode.genericFunctionType('Function('),
- '(bool!, String?) → int??',
- );
- }
-
- test_local_variable_interfaceType() async {
- addTestFile('''
-main() {
- int? a = 0;
- int b = 0;
-}
-''');
- await resolveTestFile();
- assertNoTestErrors();
-
- assertType(findNode.typeName('int? a'), 'int?');
- assertType(findNode.typeName('int b'), 'int');
- }
-
- test_local_variable_interfaceType_generic() async {
- addTestFile('''
-main() {
- List<int?>? a = [];
- List<int>? b = [];
- List<int?> c = [];
- List<int> d = [];
-}
-''');
- await resolveTestFile();
- assertNoTestErrors();
-
- assertType(findNode.typeName('List<int?>? a'), 'List<int?>?');
- assertType(findNode.typeName('List<int>? b'), 'List<int>?');
- assertType(findNode.typeName('List<int?> c'), 'List<int?>');
- assertType(findNode.typeName('List<int> d'), 'List<int>');
- }
-
- test_local_variable_typeParameter() async {
- addTestFile('''
-class A<T> {
- main(T a) {
- T? b;
- }
-}
-''');
- await resolveTestFile();
- assertNoTestErrors();
-
- assertType(findNode.typeName('T a'), 'T');
- assertType(findNode.typeName('T? b'), 'T?');
- }
-
- test_member_potentiallyNullable_called() async {
- addTestFile(r'''
-m<T extends Function>() {
- List<T?> x;
- x.first();
-}
-''');
- await resolveTestFile();
- // Do not assert no test errors. Deliberately invokes nullable type.
- assertType(findNode.methodInvocation('first').methodName, 'Function?');
- }
-
- test_null_assertion_operator_changes_null_to_never() async {
- addTestFile('''
-main() {
- Null x = null;
- x!;
-}
-''');
- await resolveTestFile();
- assertNoTestErrors();
- assertType(findNode.postfix('x!'), 'Never');
- }
-
- test_null_assertion_operator_removes_nullability() async {
- addTestFile('''
-main() {
- Object? x = null;
- x!;
-}
-''');
- await resolveTestFile();
- assertNoTestErrors();
- assertType(findNode.postfix('x!'), 'Object');
- }
-
- test_typedef_classic() async {
- addTestFile('''
-typedef int? F(bool a, String? b);
-
-main() {
- F? a;
-}
-''');
- await resolveTestFile();
- assertNoTestErrors();
-
- assertType(findNode.typeName('F? a'), 'int? Function(bool, String?)?');
- }
-
- @failingTest
- test_typedef_function() async {
- addTestFile('''
-typedef F<T> = int? Function(bool, T, T?);
-
-main() {
- F<String>? a;
-}
-''');
- await resolveTestFile();
- assertNoTestErrors();
-
- assertType(
- findNode.typeName('F<String>'),
- 'int? Function(bool!, String!, String?)?',
- );
- }
-
test_class_hierarchy() async {
addTestFile('''
class A {}
@@ -295,6 +58,187 @@
assertType(findNode.typeName('C;'), 'C');
}
+ test_local_getterNullAwareAccess_interfaceType() async {
+ addTestFile(r'''
+main() {
+ int? x;
+ return x?.isEven;
+}
+''');
+
+ await resolveTestFile();
+ assertNoTestErrors();
+ assertType(findNode.propertyAccess('x?.isEven'), 'bool?');
+ }
+
+ test_local_interfaceType() async {
+ addTestFile('''
+main() {
+ int? a = 0;
+ int b = 0;
+}
+''');
+ await resolveTestFile();
+ assertNoTestErrors();
+
+ assertType(findNode.typeName('int? a'), 'int?');
+ assertType(findNode.typeName('int b'), 'int');
+ }
+
+ test_local_interfaceType_generic() async {
+ addTestFile('''
+main() {
+ List<int?>? a = [];
+ List<int>? b = [];
+ List<int?> c = [];
+ List<int> d = [];
+}
+''');
+ await resolveTestFile();
+ assertNoTestErrors();
+
+ assertType(findNode.typeName('List<int?>? a'), 'List<int?>?');
+ assertType(findNode.typeName('List<int>? b'), 'List<int>?');
+ assertType(findNode.typeName('List<int?> c'), 'List<int?>');
+ assertType(findNode.typeName('List<int> d'), 'List<int>');
+ }
+
+ test_local_methodNullAwareCall_interfaceType() async {
+ await addTestFile(r'''
+class C {
+ bool x() => true;
+}
+
+main() {
+ C? c;
+ return c?.x();
+}
+''');
+
+ await resolveTestFile();
+ assertNoTestErrors();
+ assertType(findNode.methodInvocation('c?.x()'), 'bool?');
+ }
+
+ test_local_nullCoalesce_nullableInt_int() async {
+ await addTestFile(r'''
+main() {
+ int? x;
+ int y = 0;
+ x ?? y;
+}
+''');
+ await resolveTestFile();
+ assertNoTestErrors();
+ assertType(findNode.binary('x ?? y'), 'int');
+ }
+
+ test_local_nullCoalesce_nullableInt_nullableInt() async {
+ await addTestFile(r'''
+main() {
+ int? x;
+ x ?? x;
+}
+''');
+ await resolveTestFile();
+ assertNoTestErrors();
+ assertType(findNode.binary('x ?? x'), 'int?');
+ }
+
+ test_local_nullCoalesceAssign_nullableInt_int() async {
+ await addTestFile(r'''
+main() {
+ int? x;
+ int y = 0;
+ x ??= y;
+}
+''');
+ await resolveTestFile();
+ assertNoTestErrors();
+ assertType(findNode.assignment('x ??= y'), 'int');
+ }
+
+ test_local_nullCoalesceAssign_nullableInt_nullableInt() async {
+ await addTestFile(r'''
+main() {
+ int? x;
+ x ??= x;
+}
+''');
+ await resolveTestFile();
+ assertNoTestErrors();
+ assertType(findNode.assignment('x ??= x'), 'int?');
+ }
+
+ test_local_typeParameter() async {
+ addTestFile('''
+main<T>(T a) {
+ T x = a;
+ T? y;
+}
+''');
+ await resolveTestFile();
+ assertNoTestErrors();
+
+ assertType(findNode.typeName('T x'), 'T');
+ assertType(findNode.typeName('T? y'), 'T?');
+ }
+
+ @failingTest
+ test_local_variable_genericFunctionType() async {
+ addTestFile('''
+main() {
+ int? Function(bool, String?)? a;
+}
+''');
+ await resolveTestFile();
+ assertNoTestErrors();
+
+ assertType(
+ findNode.genericFunctionType('Function('),
+ '(bool!, String?) → int??',
+ );
+ }
+
+ test_localFunction_parameter_interfaceType() async {
+ addTestFile('''
+main() {
+ f(int? a, int b) {}
+}
+''');
+ await resolveTestFile();
+ assertNoTestErrors();
+
+ assertType(findNode.typeName('int? a'), 'int?');
+ assertType(findNode.typeName('int b'), 'int');
+ }
+
+ test_localFunction_returnType_interfaceType() async {
+ addTestFile('''
+main() {
+ int? f() => 0;
+ int g() => 0;
+}
+''');
+ await resolveTestFile();
+ assertNoTestErrors();
+
+ assertType(findNode.typeName('int? f'), 'int?');
+ assertType(findNode.typeName('int g'), 'int');
+ }
+
+ test_member_potentiallyNullable_called() async {
+ addTestFile(r'''
+m<T extends Function>() {
+ List<T?> x;
+ x.first();
+}
+''');
+ await resolveTestFile();
+ // Do not assert no test errors. Deliberately invokes nullable type.
+ assertType(findNode.methodInvocation('first').methodName, 'Function?');
+ }
+
test_mixin_hierarchy() async {
addTestFile('''
class A {}
@@ -308,6 +252,187 @@
assertType(findNode.typeName('A {} // 1'), 'A');
assertType(findNode.typeName('A {} // 2'), 'A');
}
+
+ test_null_assertion_operator_changes_null_to_never() async {
+ addTestFile('''
+main() {
+ Null x = null;
+ x!;
+}
+''');
+ await resolveTestFile();
+ assertNoTestErrors();
+ assertType(findNode.postfix('x!'), 'Never');
+ }
+
+ test_null_assertion_operator_removes_nullability() async {
+ addTestFile('''
+main() {
+ Object? x = null;
+ x!;
+}
+''');
+ await resolveTestFile();
+ assertNoTestErrors();
+ assertType(findNode.postfix('x!'), 'Object');
+ }
+
+ @failingTest
+ test_parameter_genericFunctionType() async {
+ addTestFile('''
+main(int? Function(bool, String?)? a) {
+}
+''');
+ await resolveTestFile();
+ assertNoTestErrors();
+
+ assertType(
+ findNode.genericFunctionType('Function('),
+ '(bool!, String?) → int??',
+ );
+ }
+
+ test_parameter_getterNullAwareAccess_interfaceType() async {
+ addTestFile(r'''
+main(int? x) {
+ return x?.isEven;
+}
+''');
+
+ await resolveTestFile();
+ assertNoTestErrors();
+ assertType(findNode.propertyAccess('x?.isEven'), 'bool?');
+ }
+
+ test_parameter_interfaceType() async {
+ addTestFile('''
+main(int? a, int b) {
+}
+''');
+ await resolveTestFile();
+ assertNoTestErrors();
+
+ assertType(findNode.typeName('int? a'), 'int?');
+ assertType(findNode.typeName('int b'), 'int');
+ }
+
+ test_parameter_interfaceType_generic() async {
+ addTestFile('''
+main(List<int?>? a, List<int>? b, List<int?> c, List<int> d) {
+}
+''');
+ await resolveTestFile();
+ assertNoTestErrors();
+
+ assertType(findNode.typeName('List<int?>? a'), 'List<int?>?');
+ assertType(findNode.typeName('List<int>? b'), 'List<int>?');
+ assertType(findNode.typeName('List<int?> c'), 'List<int?>');
+ assertType(findNode.typeName('List<int> d'), 'List<int>');
+ }
+
+ test_parameter_methodNullAwareCall_interfaceType() async {
+ await addTestFile(r'''
+class C {
+ bool x() => true;
+}
+
+main(C? c) {
+ return c?.x();
+}
+''');
+
+ await resolveTestFile();
+ assertNoTestErrors();
+ assertType(findNode.methodInvocation('c?.x()'), 'bool?');
+ }
+
+ test_parameter_nullCoalesce_nullableInt_int() async {
+ await addTestFile(r'''
+main(int? x, int y) {
+ x ?? y;
+}
+''');
+ await resolveTestFile();
+ assertNoTestErrors();
+ assertType(findNode.binary('x ?? y'), 'int');
+ }
+
+ test_parameter_nullCoalesce_nullableInt_nullableInt() async {
+ await addTestFile(r'''
+main(int? x) {
+ x ?? x;
+}
+''');
+ await resolveTestFile();
+ assertNoTestErrors();
+ assertType(findNode.binary('x ?? x'), 'int?');
+ }
+
+ test_parameter_nullCoalesceAssign_nullableInt_int() async {
+ await addTestFile(r'''
+main(int? x, int y) {
+ x ??= y;
+}
+''');
+ await resolveTestFile();
+ assertNoTestErrors();
+ assertType(findNode.assignment('x ??= y'), 'int');
+ }
+
+ test_parameter_nullCoalesceAssign_nullableInt_nullableInt() async {
+ await addTestFile(r'''
+main(int? x) {
+ x ??= x;
+}
+''');
+ await resolveTestFile();
+ assertNoTestErrors();
+ assertType(findNode.assignment('x ??= x'), 'int?');
+ }
+
+ test_parameter_typeParameter() async {
+ addTestFile('''
+main<T>(T a, T? b) {
+}
+''');
+ await resolveTestFile();
+ assertNoTestErrors();
+
+ assertType(findNode.typeName('T a'), 'T');
+ assertType(findNode.typeName('T? b'), 'T?');
+ }
+
+ test_typedef_classic() async {
+ addTestFile('''
+typedef int? F(bool a, String? b);
+
+main() {
+ F? a;
+}
+''');
+ await resolveTestFile();
+ assertNoTestErrors();
+
+ assertType(findNode.typeName('F? a'), 'int? Function(bool, String?)?');
+ }
+
+ @failingTest
+ test_typedef_function() async {
+ addTestFile('''
+typedef F<T> = int? Function(bool, T, T?);
+
+main() {
+ F<String>? a;
+}
+''');
+ await resolveTestFile();
+ assertNoTestErrors();
+
+ assertType(
+ findNode.typeName('F<String>'),
+ 'int? Function(bool!, String!, String?)?',
+ );
+ }
}
@reflectiveTest
diff --git a/pkg/analyzer/test/src/diagnostics/dead_code_test.dart b/pkg/analyzer/test/src/diagnostics/dead_code_test.dart
index c84553a..3a2c54b 100644
--- a/pkg/analyzer/test/src/diagnostics/dead_code_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/dead_code_test.dart
@@ -724,12 +724,11 @@
@pragma('analyzer:non-nullable')
library foo;
-m() {
- int x;
+m(int x) {
x ?? 1;
}
''', [
- error(HintCode.DEAD_CODE, 69, 1),
+ error(HintCode.DEAD_CODE, 65, 1),
]);
}
@@ -774,12 +773,11 @@
@pragma('analyzer:non-nullable')
library foo;
-m() {
- int x;
+m(int x) {
x ??= 1;
}
''', [
- error(HintCode.DEAD_CODE, 70, 1),
+ error(HintCode.DEAD_CODE, 66, 1),
]);
}
diff --git a/pkg/analyzer/test/src/diagnostics/not_initialized_potentially_non_nullable_local_variable_test.dart b/pkg/analyzer/test/src/diagnostics/not_initialized_potentially_non_nullable_local_variable_test.dart
new file mode 100644
index 0000000..373e9b5
--- /dev/null
+++ b/pkg/analyzer/test/src/diagnostics/not_initialized_potentially_non_nullable_local_variable_test.dart
@@ -0,0 +1,104 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// 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.
+
+import 'package:analyzer/src/dart/analysis/experiments.dart';
+import 'package:analyzer/src/error/codes.dart';
+import 'package:analyzer/src/generated/engine.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../dart/resolution/driver_resolution.dart';
+
+main() {
+ defineReflectiveSuite(() {
+ defineReflectiveTests(
+ NotInitializedPotentiallyNonNullableLocalVariableTest,
+ );
+ });
+}
+
+@reflectiveTest
+class NotInitializedPotentiallyNonNullableLocalVariableTest
+ extends DriverResolutionTest {
+ @override
+ AnalysisOptionsImpl get analysisOptions =>
+ AnalysisOptionsImpl()..enabledExperiments = [EnableString.non_nullable];
+
+ test_hasInitializer() async {
+ assertNoErrorsInCode('''
+f() {
+ int v = 0;
+}
+''');
+ }
+
+ test_late() async {
+ assertNoErrorsInCode('''
+f() {
+ late int v;
+}
+''');
+ }
+
+ test_noInitializer() async {
+ assertErrorsInCode('''
+f() {
+ int v;
+}
+''', [
+ error(
+ CompileTimeErrorCode
+ .NOT_INITIALIZED_POTENTIALLY_NON_NULLABLE_LOCAL_VARIABLE,
+ 12,
+ 1),
+ error(HintCode.UNUSED_LOCAL_VARIABLE, 12, 1),
+ ]);
+ }
+
+ test_noInitializer_typeParameter() async {
+ assertErrorsInCode('''
+f<T>() {
+ T v;
+}
+''', [
+ error(
+ CompileTimeErrorCode
+ .NOT_INITIALIZED_POTENTIALLY_NON_NULLABLE_LOCAL_VARIABLE,
+ 13,
+ 1),
+ error(HintCode.UNUSED_LOCAL_VARIABLE, 13, 1),
+ ]);
+ }
+
+ test_nullable() async {
+ assertNoErrorsInCode('''
+f() {
+ int? v;
+}
+''');
+ }
+
+ test_type_dynamic() async {
+ assertNoErrorsInCode('''
+f() {
+ dynamic v;
+}
+''');
+ }
+
+ test_type_dynamicImplicit() async {
+ assertNoErrorsInCode('''
+f() {
+ var v;
+}
+''');
+ }
+
+ test_type_void() async {
+ assertNoErrorsInCode('''
+f() {
+ void v;
+}
+''');
+ }
+}
diff --git a/pkg/analyzer/test/src/diagnostics/test_all.dart b/pkg/analyzer/test/src/diagnostics/test_all.dart
index bf27038..2f965be 100644
--- a/pkg/analyzer/test/src/diagnostics/test_all.dart
+++ b/pkg/analyzer/test/src/diagnostics/test_all.dart
@@ -96,6 +96,8 @@
import 'non_constant_spread_expression_from_deferred_library_test.dart'
as non_constant_spread_expression_from_deferred_library;
import 'non_null_opt_out_test.dart' as non_null_opt_out;
+import 'not_initialized_potentially_non_nullable_local_variable_test.dart'
+ as not_initialized_potentially_non_nullable_local_variable;
import 'not_iterable_spread_test.dart' as not_iterable_spread;
import 'not_map_spread_test.dart' as not_map_spread;
import 'not_null_aware_null_spread_test.dart' as not_null_aware_null_spread;
@@ -235,6 +237,7 @@
non_constant_set_element_from_deferred_library.main();
non_constant_spread_expression_from_deferred_library.main();
non_null_opt_out.main();
+ not_initialized_potentially_non_nullable_local_variable.main();
not_iterable_spread.main();
not_map_spread.main();
not_null_aware_null_spread.main();
diff --git a/pkg/analyzer/test/src/diagnostics/unchecked_use_of_nullable_value_test.dart b/pkg/analyzer/test/src/diagnostics/unchecked_use_of_nullable_value_test.dart
index a78ae34..906d4da 100644
--- a/pkg/analyzer/test/src/diagnostics/unchecked_use_of_nullable_value_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/unchecked_use_of_nullable_value_test.dart
@@ -305,23 +305,21 @@
test_member_potentiallyNullable() async {
await assertErrorsInCode(r'''
-m<T extends int?>() {
- T x;
+m<T extends int?>(T x) {
x.isEven;
}
''', [
- error(StaticWarningCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 31, 1),
+ error(StaticWarningCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 27, 1),
]);
}
test_member_potentiallyNullable_called() async {
await assertErrorsInCode(r'''
-m<T extends Function>() {
- List<T?> x;
+m<T extends Function>(List<T?> x) {
x.first();
}
''', [
- error(StaticWarningCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 44, 5),
+ error(StaticWarningCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 40, 5),
]);
}
@@ -354,8 +352,7 @@
test_method_noSuchMethod_nullable() async {
await assertNoErrorsInCode(r'''
-m() {
- int x;
+m(int x) {
x.noSuchMethod(throw '');
}
''');
@@ -383,8 +380,7 @@
test_method_toString_nullable() async {
await assertNoErrorsInCode(r'''
-m() {
- int x;
+m(int x) {
x.toString();
}
''');
@@ -503,8 +499,7 @@
test_operatorPostfixInc_nonNullable() async {
await assertNoErrorsInCode(r'''
-m() {
- int x;
+m(int x) {
x++;
}
''');
@@ -512,13 +507,11 @@
test_operatorPostfixInc_nullable() async {
await assertErrorsInCode(r'''
-m() {
- int? x;
+m(int? x) {
x++;
}
''', [
- error(HintCode.UNUSED_LOCAL_VARIABLE, 13, 1),
- error(StaticWarningCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 18, 1),
+ error(StaticWarningCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 14, 1),
]);
}
@@ -545,8 +538,7 @@
test_operatorPrefixInc_nonNullable() async {
await assertNoErrorsInCode(r'''
-m() {
- int x;
+m(int x) {
++x;
}
''');
@@ -554,13 +546,11 @@
test_operatorPrefixInc_nullable() async {
await assertErrorsInCode(r'''
-m() {
- int? x;
+m(int? x) {
++x;
}
''', [
- error(HintCode.UNUSED_LOCAL_VARIABLE, 13, 1),
- error(StaticWarningCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 20, 1),
+ error(StaticWarningCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 16, 1),
]);
}
@@ -607,8 +597,7 @@
test_plusEq_nonNullable() async {
await assertNoErrorsInCode(r'''
-m() {
- int x;
+m(int x) {
x += 1;
}
''');
@@ -616,13 +605,11 @@
test_plusEq_nullable() async {
await assertErrorsInCode(r'''
-m() {
- int? x;
+m(int? x) {
x += 1;
}
''', [
- error(HintCode.UNUSED_LOCAL_VARIABLE, 13, 1),
- error(StaticWarningCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 18, 1),
+ error(StaticWarningCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 14, 1),
]);
}
diff --git a/pkg/analyzer/test/src/diagnostics/unnecessary_null_aware_call_test.dart b/pkg/analyzer/test/src/diagnostics/unnecessary_null_aware_call_test.dart
index 35d157a..110b35b 100644
--- a/pkg/analyzer/test/src/diagnostics/unnecessary_null_aware_call_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/unnecessary_null_aware_call_test.dart
@@ -23,19 +23,17 @@
test_getter_parenthesized_nonNull() async {
await assertErrorsInCode('''
-f() {
- int x;
+f(int x) {
(x)?.isEven;
}
''', [
- error(HintCode.UNNECESSARY_NULL_AWARE_CALL, 20, 2),
+ error(HintCode.UNNECESSARY_NULL_AWARE_CALL, 16, 2),
]);
}
test_getter_parenthesized_nullable() async {
await assertNoErrorsInCode('''
-f() {
- int? x;
+f(int? x) {
(x)?.isEven;
}
''');
@@ -43,19 +41,17 @@
test_getter_simple_nonNull() async {
await assertErrorsInCode('''
-f() {
- int x;
+f(int x) {
x?.isEven;
}
''', [
- error(HintCode.UNNECESSARY_NULL_AWARE_CALL, 18, 2),
+ error(HintCode.UNNECESSARY_NULL_AWARE_CALL, 14, 2),
]);
}
test_getter_simple_nullable() async {
await assertNoErrorsInCode('''
-f() {
- int? x;
+f(int? x) {
x?.isEven;
}
''');
@@ -63,19 +59,17 @@
test_method_parenthesized_nonNull() async {
await assertErrorsInCode('''
-f() {
- int x;
+f(int x) {
(x)?.round();
}
''', [
- error(HintCode.UNNECESSARY_NULL_AWARE_CALL, 20, 2),
+ error(HintCode.UNNECESSARY_NULL_AWARE_CALL, 16, 2),
]);
}
test_method_parenthesized_nullable() async {
await assertNoErrorsInCode('''
-f() {
- int? x;
+f(int? x) {
(x)?.round();
}
''');
@@ -83,19 +77,17 @@
test_method_simple_nonNull() async {
await assertErrorsInCode('''
-f() {
- int x;
+f(int x) {
x?.round();
}
''', [
- error(HintCode.UNNECESSARY_NULL_AWARE_CALL, 18, 2),
+ error(HintCode.UNNECESSARY_NULL_AWARE_CALL, 14, 2),
]);
}
test_method_simple_nullable() async {
await assertNoErrorsInCode('''
-f() {
- int? x;
+f(int? x) {
x?.round();
}
''');
diff --git a/tests/language_2/nnbd/static_errors/equals_parameter_made_nullable_at_invoke_test.dart b/tests/language_2/nnbd/static_errors/equals_parameter_made_nullable_at_invoke_test.dart
index 35e756e..9757f79 100644
--- a/tests/language_2/nnbd/static_errors/equals_parameter_made_nullable_at_invoke_test.dart
+++ b/tests/language_2/nnbd/static_errors/equals_parameter_made_nullable_at_invoke_test.dart
@@ -20,14 +20,14 @@
// operator==, but it should not be an error to "assign null" to the parameter
// of the comparison operator.
main() {
- Object o;
+ Object o = 0;
// Valid comparison.
o == null;
// Caveat: it is NOT that the argument is promoted to non-null. Otherwise,
// types which we can't cleanly promote, such as FutureOr<int?>, would not be
// assignable in comparisons.
- FutureOr<int?> foInt;
+ FutureOr<int?> foInt = Future.value(0);
// Valid comparison.
o == foInt;
diff --git a/tests/language_2/nnbd/static_errors/not_initialized_potentially_non_nullable_local_test.dart b/tests/language_2/nnbd/static_errors/not_initialized_potentially_non_nullable_local_test.dart
new file mode 100644
index 0000000..d4b2207
--- /dev/null
+++ b/tests/language_2/nnbd/static_errors/not_initialized_potentially_non_nullable_local_test.dart
@@ -0,0 +1,29 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// 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.
+
+// SharedOptions=--enable-experiment=non-nullable
+
+// It is an error if a potentially non-nullable local variable which has no
+// initializer expression and is not marked `late` is used before it is
+// definitely assigned.
+// TODO(scheglov) Update once we implement definite assignment analysis.
+
+void main() {
+ int v; //# 01: compile-time error
+ int v = 0; //# 02: ok
+ late int v; //# 03: ok
+ late int v = 0; //# 04: ok
+ int? v; //# 05: ok
+ int? v = 0; //# 06: ok
+
+}
+
+f<T>(T a) {
+ T v; //# 07: compile-time error
+ T v = a; //# 08: ok
+ late T v; //# 09: ok
+ late T v = a; //# 10: ok
+ T? v; //# 11: ok
+ T? v = a; //# 12: ok
+}
diff --git a/tests/language_2/nnbd/static_errors/unchecked_use_of_nullable_test.dart b/tests/language_2/nnbd/static_errors/unchecked_use_of_nullable_test.dart
index 56679cf..9043d0e 100644
--- a/tests/language_2/nnbd/static_errors/unchecked_use_of_nullable_test.dart
+++ b/tests/language_2/nnbd/static_errors/unchecked_use_of_nullable_test.dart
@@ -10,7 +10,7 @@
bool? cond;
List? list;
Function? func;
- List<Function?> funcList;
+ List<Function?> funcList = [];
Stream? stream;
x.isEven; //# 00: compile-time error
x.round(); //# 01: compile-time error
diff --git a/tests/language_2/nnbd/syntax/null_assertion_ambiguous_test.dart b/tests/language_2/nnbd/syntax/null_assertion_ambiguous_test.dart
index 29200e7..68c6037 100644
--- a/tests/language_2/nnbd/syntax/null_assertion_ambiguous_test.dart
+++ b/tests/language_2/nnbd/syntax/null_assertion_ambiguous_test.dart
@@ -38,7 +38,7 @@
// behavior by trying to assign to a non-nullable variable. We check the
// runtime behavior by verifying that the exception is thrown before an
// assignment occurs.
- Object x3;
+ Object x3 = 0;
Expect.throws(() {
x3 = a!;
});
diff --git a/tests/language_2/nnbd/syntax/null_assertion_test.dart b/tests/language_2/nnbd/syntax/null_assertion_test.dart
index 4b27e00..6acea53 100644
--- a/tests/language_2/nnbd/syntax/null_assertion_test.dart
+++ b/tests/language_2/nnbd/syntax/null_assertion_test.dart
@@ -23,7 +23,7 @@
Object? f() => null;
main() {
- List<Object> listOfObject;
+ List<Object> listOfObject = [];
var x1 = [0!];
listOfObject = x1;