Issue 45672. Report constant errors when null value where non-nullable type is expected.
Bug: https://github.com/dart-lang/sdk/issues/45672
Change-Id: I9d006955523bf470c762fde57444e3596e4dccae
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/196042
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
diff --git a/pkg/analyzer/lib/src/dart/constant/evaluation.dart b/pkg/analyzer/lib/src/dart/constant/evaluation.dart
index d8536a9..21d0e6a 100644
--- a/pkg/analyzer/lib/src/dart/constant/evaluation.dart
+++ b/pkg/analyzer/lib/src/dart/constant/evaluation.dart
@@ -822,9 +822,6 @@
DartObjectImpl obj,
DartType type,
) {
- if (obj.isNull) {
- return true;
- }
var objType = obj.type;
return library.typeSystem.isSubtypeOf(objType, type);
}
diff --git a/pkg/analyzer/test/generated/constant_test.dart b/pkg/analyzer/test/generated/constant_test.dart
index 5b8847d..f4a4079 100644
--- a/pkg/analyzer/test/generated/constant_test.dart
+++ b/pkg/analyzer/test/generated/constant_test.dart
@@ -50,7 +50,7 @@
"const Center(name: 'v')",
context: '''
class Align {
- final double widthFactor;
+ final double? widthFactor;
const Align({String name, this.widthFactor})
assert(widthFactor == null || widthFactor >= 0.0);
}
diff --git a/pkg/analyzer/test/src/diagnostics/const_constructor_field_type_mismatch_test.dart b/pkg/analyzer/test/src/diagnostics/const_constructor_field_type_mismatch_test.dart
index 1a3846a..cf0fdcb 100644
--- a/pkg/analyzer/test/src/diagnostics/const_constructor_field_type_mismatch_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/const_constructor_field_type_mismatch_test.dart
@@ -15,7 +15,7 @@
@reflectiveTest
class ConstConstructorFieldTypeMismatchTest extends PubPackageResolutionTest {
- test_assignable_generic() async {
+ test_generic_int_int() async {
await assertErrorsInCode(
r'''
class C<T> {
@@ -31,41 +31,7 @@
);
}
- test_assignable_nullValue() async {
- await assertNoErrorsInCode(r'''
-class A {
- const A(x) : y = x;
- final int y;
-}
-var v = const A(null);
-''');
- }
-
- test_assignable_unresolvedFieldAndNullValue() async {
- await assertErrorsInCode(r'''
-class A {
- const A(x) : y = x;
- final Unresolved y;
-}
-var v = const A(null);
-''', [
- error(CompileTimeErrorCode.UNDEFINED_CLASS, 40, 10),
- ]);
- }
-
- test_notAssignable() async {
- await assertErrorsInCode(r'''
-class A {
- const A(x) : y = x;
- final int y;
-}
-var v = const A('foo');
-''', [
- error(CompileTimeErrorCode.CONST_CONSTRUCTOR_FIELD_TYPE_MISMATCH, 57, 14),
- ]);
- }
-
- test_notAssignable_generic() async {
+ test_generic_string_int() async {
await assertErrorsInCode(
r'''
class C<T> {
@@ -83,13 +49,50 @@
);
}
- test_notAssignable_unresolved() async {
+ test_notGeneric_int_int() async {
+ await assertErrorsInCode(r'''
+class A {
+ const A(x) : y = x;
+ final int y;
+}
+var v = const A('foo');
+''', [
+ error(CompileTimeErrorCode.CONST_CONSTRUCTOR_FIELD_TYPE_MISMATCH, 57, 14),
+ ]);
+ }
+
+ test_notGeneric_int_null() async {
+ var errors = expectedErrorsByNullability(nullable: [
+ error(CompileTimeErrorCode.CONST_CONSTRUCTOR_FIELD_TYPE_MISMATCH, 57, 13),
+ ], legacy: []);
+ await assertErrorsInCode(r'''
+class A {
+ const A(x) : y = x;
+ final int y;
+}
+var v = const A(null);
+''', errors);
+ }
+
+ test_notGeneric_unresolved_int() async {
await assertErrorsInCode(r'''
class A {
const A(x) : y = x;
final Unresolved y;
}
-var v = const A('foo');
+var v = const A(0);
+''', [
+ error(CompileTimeErrorCode.UNDEFINED_CLASS, 40, 10),
+ ]);
+ }
+
+ test_notGeneric_unresolved_null() async {
+ await assertErrorsInCode(r'''
+class A {
+ const A(x) : y = x;
+ final Unresolved y;
+}
+var v = const A(null);
''', [
error(CompileTimeErrorCode.UNDEFINED_CLASS, 40, 10),
]);
diff --git a/pkg/analyzer/test/src/diagnostics/list_element_type_not_assignable_test.dart b/pkg/analyzer/test/src/diagnostics/list_element_type_not_assignable_test.dart
index 54f519d..0521fda 100644
--- a/pkg/analyzer/test/src/diagnostics/list_element_type_not_assignable_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/list_element_type_not_assignable_test.dart
@@ -10,12 +10,19 @@
main() {
defineReflectiveSuite(() {
defineReflectiveTests(ListElementTypeNotAssignableTest);
+ defineReflectiveTests(ListElementTypeNotAssignableWithoutNullSafetyTest);
});
}
@reflectiveTest
class ListElementTypeNotAssignableTest extends PubPackageResolutionTest
- with ListElementTypeNotAssignableTestCases {}
+ with ListElementTypeNotAssignableTestCases {
+ test_const_stringQuestion_null_value() async {
+ await assertNoErrorsInCode('''
+var v = const <String?>[null];
+''');
+ }
+}
mixin ListElementTypeNotAssignableTestCases on PubPackageResolutionTest {
test_const_ifElement_thenElseFalse_intInt() async {
@@ -67,6 +74,32 @@
]);
}
+ test_const_intInt() async {
+ await assertNoErrorsInCode(r'''
+var v1 = <int> [42];
+var v2 = const <int> [42];
+''');
+ }
+
+ test_const_intNull_dynamic() async {
+ var errors = expectedErrorsByNullability(nullable: [
+ error(CompileTimeErrorCode.LIST_ELEMENT_TYPE_NOT_ASSIGNABLE, 36, 1),
+ ], legacy: []);
+ await assertErrorsInCode('''
+const a = null;
+var v = const <int>[a];
+''', errors);
+ }
+
+ test_const_intNull_value() async {
+ var errors = expectedErrorsByNullability(nullable: [
+ error(CompileTimeErrorCode.LIST_ELEMENT_TYPE_NOT_ASSIGNABLE, 20, 4),
+ ], legacy: []);
+ await assertErrorsInCode('''
+var v = const <int>[null];
+''', errors);
+ }
+
test_const_spread_intInt() async {
await assertNoErrorsInCode('''
var v = const <int>[...[0, 1]];
@@ -90,32 +123,12 @@
]);
}
- test_const_stringNull() async {
- await assertNoErrorsInCode('''
-var v = const <String?>[null];
-''');
- }
-
- test_const_stringNull_dynamic() async {
- await assertNoErrorsInCode('''
-const dynamic x = null;
-var v = const <String>[x];
-''');
- }
-
test_const_voidInt() async {
await assertNoErrorsInCode('''
var v = const <void>[42];
''');
}
- test_element_type_is_assignable() async {
- await assertNoErrorsInCode(r'''
-var v1 = <int> [42];
-var v2 = const <int> [42];
-''');
- }
-
test_nonConst_ifElement_thenElseFalse_intDynamic() async {
await assertNoErrorsInCode('''
const dynamic a = 'a';
@@ -181,3 +194,8 @@
''');
}
}
+
+@reflectiveTest
+class ListElementTypeNotAssignableWithoutNullSafetyTest
+ extends PubPackageResolutionTest
+ with WithoutNullSafetyMixin, ListElementTypeNotAssignableTestCases {}
diff --git a/pkg/analyzer/test/src/diagnostics/map_key_type_not_assignable_test.dart b/pkg/analyzer/test/src/diagnostics/map_key_type_not_assignable_test.dart
index 44ef7ef..31bc498 100644
--- a/pkg/analyzer/test/src/diagnostics/map_key_type_not_assignable_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/map_key_type_not_assignable_test.dart
@@ -16,7 +16,20 @@
@reflectiveTest
class MapKeyTypeNotAssignableTest extends PubPackageResolutionTest
- with MapKeyTypeNotAssignableTestCases {}
+ with MapKeyTypeNotAssignableTestCases {
+ test_const_intQuestion_null_dynamic() async {
+ await assertNoErrorsInCode('''
+const dynamic a = null;
+var v = const <int?, bool>{a : true};
+''');
+ }
+
+ test_const_intQuestion_null_value() async {
+ await assertNoErrorsInCode('''
+var v = const <int?, bool>{null : true};
+''');
+ }
+}
mixin MapKeyTypeNotAssignableTestCases on PubPackageResolutionTest {
test_const_ifElement_thenElseFalse_intInt_dynamic() async {
@@ -84,6 +97,25 @@
''');
}
+ test_const_intNull_dynamic() async {
+ var errors = expectedErrorsByNullability(nullable: [
+ error(CompileTimeErrorCode.MAP_KEY_TYPE_NOT_ASSIGNABLE, 50, 1),
+ ], legacy: []);
+ await assertErrorsInCode('''
+const dynamic a = null;
+var v = const <int, bool>{a : true};
+''', errors);
+ }
+
+ test_const_intNull_value() async {
+ var errors = expectedErrorsByNullability(nullable: [
+ error(CompileTimeErrorCode.MAP_KEY_TYPE_NOT_ASSIGNABLE, 26, 4),
+ ], legacy: []);
+ await assertErrorsInCode('''
+var v = const <int, bool>{null : true};
+''', errors);
+ }
+
test_const_intString_dynamic() async {
await assertErrorsInCode('''
const dynamic a = 'a';
diff --git a/pkg/analyzer/test/src/diagnostics/map_value_type_not_assignable_test.dart b/pkg/analyzer/test/src/diagnostics/map_value_type_not_assignable_test.dart
index e5d6220..8f1ae13 100644
--- a/pkg/analyzer/test/src/diagnostics/map_value_type_not_assignable_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/map_value_type_not_assignable_test.dart
@@ -16,7 +16,20 @@
@reflectiveTest
class MapValueTypeNotAssignableTest extends PubPackageResolutionTest
- with MapValueTypeNotAssignableTestCases {}
+ with MapValueTypeNotAssignableTestCases {
+ test_const_intQuestion_null_dynamic() async {
+ await assertNoErrorsInCode('''
+const dynamic a = null;
+var v = const <bool, int?>{true: a};
+''');
+ }
+
+ test_const_intQuestion_null_value() async {
+ await assertNoErrorsInCode('''
+var v = const <bool, int?>{true: null};
+''');
+ }
+}
mixin MapValueTypeNotAssignableTestCases on PubPackageResolutionTest {
test_const_ifElement_thenElseFalse_intInt_dynamic() async {
@@ -84,6 +97,25 @@
''');
}
+ test_const_intNull_dynamic() async {
+ var errors = expectedErrorsByNullability(nullable: [
+ error(CompileTimeErrorCode.MAP_VALUE_TYPE_NOT_ASSIGNABLE, 56, 1),
+ ], legacy: []);
+ await assertErrorsInCode('''
+const dynamic a = null;
+var v = const <bool, int>{true: a};
+''', errors);
+ }
+
+ test_const_intNull_value() async {
+ var errors = expectedErrorsByNullability(nullable: [
+ error(CompileTimeErrorCode.MAP_VALUE_TYPE_NOT_ASSIGNABLE, 32, 4),
+ ], legacy: []);
+ await assertErrorsInCode('''
+var v = const <bool, int>{true: null};
+''', errors);
+ }
+
test_const_intString_dynamic() async {
await assertErrorsInCode('''
const dynamic a = 'a';
diff --git a/pkg/analyzer/test/src/diagnostics/not_enough_positional_arguments_test.dart b/pkg/analyzer/test/src/diagnostics/not_enough_positional_arguments_test.dart
index b08bd58..c3ca2c0 100644
--- a/pkg/analyzer/test/src/diagnostics/not_enough_positional_arguments_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/not_enough_positional_arguments_test.dart
@@ -24,6 +24,7 @@
const A();
}
''', [
+ error(CompileTimeErrorCode.CONST_CONSTRUCTOR_PARAM_TYPE_MISMATCH, 41, 9),
error(CompileTimeErrorCode.NOT_ENOUGH_POSITIONAL_ARGUMENTS, 48, 2),
]);
}
diff --git a/pkg/analyzer/test/src/diagnostics/set_element_type_not_assignable_test.dart b/pkg/analyzer/test/src/diagnostics/set_element_type_not_assignable_test.dart
index 1d34872..ee0e079 100644
--- a/pkg/analyzer/test/src/diagnostics/set_element_type_not_assignable_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/set_element_type_not_assignable_test.dart
@@ -10,12 +10,26 @@
main() {
defineReflectiveSuite(() {
defineReflectiveTests(SetElementTypeNotAssignableTest);
+ defineReflectiveTests(SetElementTypeNotAssignableWithoutNullSafetyTest);
});
}
@reflectiveTest
class SetElementTypeNotAssignableTest extends PubPackageResolutionTest
- with SetElementTypeNotAssignableTestCases {}
+ with SetElementTypeNotAssignableTestCases {
+ test_const_stringQuestion_null_dynamic() async {
+ await assertNoErrorsInCode('''
+const a = null;
+var v = const <String?>{a};
+''');
+ }
+
+ test_const_stringQuestion_null_value() async {
+ await assertNoErrorsInCode('''
+var v = const <String?>{null};
+''');
+ }
+}
mixin SetElementTypeNotAssignableTestCases on PubPackageResolutionTest {
test_const_ifElement_thenElseFalse_intInt() async {
@@ -67,44 +81,61 @@
]);
}
- test_const_spread_intInt() async {
+ test_const_intInt_dynamic() async {
await assertNoErrorsInCode('''
-var v = const <int>{...[0, 1]};
+const dynamic a = 42;
+var v = const <int>{a};
''');
}
- test_explicitTypeArgs_const() async {
- await assertErrorsInCode('''
-var v = const <String>{42};
-''', [
- error(CompileTimeErrorCode.SET_ELEMENT_TYPE_NOT_ASSIGNABLE, 23, 2),
- ]);
- }
-
- test_explicitTypeArgs_const_actualTypeMatch() async {
+ test_const_intInt_value() async {
await assertNoErrorsInCode('''
-const dynamic x = null;
-var v = const <String>{x};
+var v = const <int>{42};
''');
}
- test_explicitTypeArgs_const_actualTypeMismatch() async {
+ test_const_intNull_dynamic() async {
+ var errors = expectedErrorsByNullability(nullable: [
+ error(CompileTimeErrorCode.SET_ELEMENT_TYPE_NOT_ASSIGNABLE, 36, 1),
+ ], legacy: []);
await assertErrorsInCode('''
-const dynamic x = 42;
-var v = const <String>{x};
+const a = null;
+var v = const <int>{a};
+''', errors);
+ }
+
+ test_const_intNull_value() async {
+ var errors = expectedErrorsByNullability(nullable: [
+ error(CompileTimeErrorCode.SET_ELEMENT_TYPE_NOT_ASSIGNABLE, 20, 4),
+ ], legacy: []);
+ await assertErrorsInCode('''
+var v = const <int>{null};
+''', errors);
+ }
+
+ test_const_intString_dynamic() async {
+ await assertErrorsInCode('''
+const dynamic x = 'abc';
+var v = const <int>{x};
''', [
error(CompileTimeErrorCode.SET_ELEMENT_TYPE_NOT_ASSIGNABLE, 45, 1),
]);
}
- test_explicitTypeArgs_notConst() async {
+ test_const_intString_value() async {
await assertErrorsInCode('''
-var v = <String>{42};
+var v = const <int>{'abc'};
''', [
- error(CompileTimeErrorCode.SET_ELEMENT_TYPE_NOT_ASSIGNABLE, 17, 2),
+ error(CompileTimeErrorCode.SET_ELEMENT_TYPE_NOT_ASSIGNABLE, 20, 5),
]);
}
+ test_const_spread_intInt() async {
+ await assertNoErrorsInCode('''
+var v = const <int>{...[0, 1]};
+''');
+ }
+
test_nonConst_ifElement_thenElseFalse_intDynamic() async {
await assertNoErrorsInCode('''
const dynamic a = 'a';
@@ -148,4 +179,24 @@
var v = <int>{...[0, 1]};
''');
}
+
+ test_notConst_intString_dynamic() async {
+ await assertNoErrorsInCode('''
+const dynamic x = 'abc';
+var v = <int>{x};
+''');
+ }
+
+ test_notConst_intString_value() async {
+ await assertErrorsInCode('''
+var v = <int>{'abc'};
+''', [
+ error(CompileTimeErrorCode.SET_ELEMENT_TYPE_NOT_ASSIGNABLE, 14, 5),
+ ]);
+ }
}
+
+@reflectiveTest
+class SetElementTypeNotAssignableWithoutNullSafetyTest
+ extends PubPackageResolutionTest
+ with WithoutNullSafetyMixin, SetElementTypeNotAssignableTestCases {}
diff --git a/tests/language/constructor/bodyless_wrong_arg_test.dart b/tests/language/constructor/bodyless_wrong_arg_test.dart
index 4e669d0..51f16f5 100644
--- a/tests/language/constructor/bodyless_wrong_arg_test.dart
+++ b/tests/language/constructor/bodyless_wrong_arg_test.dart
@@ -18,4 +18,6 @@
main() {
const C("str");
+//^^^^^^^^^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.CONST_EVAL_THROWS_EXCEPTION
}
diff --git a/tests/language/string/interpolation1_test.dart b/tests/language/string/interpolation1_test.dart
index 7f43236..d5eaea9 100644
--- a/tests/language/string/interpolation1_test.dart
+++ b/tests/language/string/interpolation1_test.dart
@@ -12,6 +12,8 @@
class StringInterpolation1NegativeTest {
// Dollar not followed by "{" or identifier.
static const DOLLAR = const A("$");
+ // [error line 14, column 33, length 3]
+ // [analyzer] COMPILE_TIME_ERROR.CONST_CONSTRUCTOR_PARAM_TYPE_MISMATCH
// [error line 14, column 35, length 0]
// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
// [cfe] A '$' has special meaning inside a string, and must be followed by an identifier or an expression in curly braces ({}).