Add a diagnostic associated with the default List constructor
Change-Id: I41ba3e34c2f209c27bf83015feed0a2ce7918ea0
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/100789
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Commit-Queue: Brian Wilkerson <brianwilkerson@google.com>
diff --git a/pkg/analyzer/lib/error/error.dart b/pkg/analyzer/lib/error/error.dart
index 07c6b92..e3e6471 100644
--- a/pkg/analyzer/lib/error/error.dart
+++ b/pkg/analyzer/lib/error/error.dart
@@ -115,6 +115,7 @@
CompileTimeErrorCode.CONST_WITH_TYPE_PARAMETERS,
CompileTimeErrorCode.CONST_WITH_UNDEFINED_CONSTRUCTOR,
CompileTimeErrorCode.CONST_WITH_UNDEFINED_CONSTRUCTOR_DEFAULT,
+ CompileTimeErrorCode.DEFAULT_LIST_CONSTRUCTOR_MISMATCH,
CompileTimeErrorCode.DEFAULT_VALUE_IN_FUNCTION_TYPED_PARAMETER,
CompileTimeErrorCode.DEFAULT_VALUE_IN_FUNCTION_TYPE_ALIAS,
CompileTimeErrorCode.DEFAULT_VALUE_IN_REDIRECTING_FACTORY_CONSTRUCTOR,
diff --git a/pkg/analyzer/lib/src/error/codes.dart b/pkg/analyzer/lib/src/error/codes.dart
index a92ca03..8a3e142 100644
--- a/pkg/analyzer/lib/src/error/codes.dart
+++ b/pkg/analyzer/lib/src/error/codes.dart
@@ -785,6 +785,17 @@
correction: "Try removing the default value.");
/**
+ * It is an error to call the default List constructor with a length argument
+ * and a type argument which is potentially non-nullable.
+ */
+ static const CompileTimeErrorCode DEFAULT_LIST_CONSTRUCTOR_MISMATCH =
+ const CompileTimeErrorCode(
+ 'DEFAULT_LIST_CONSTRUCTOR_MISMATCH',
+ "A list whose values cannot be 'null' cannot be given an initial length "
+ "because the initial values would all be 'null'.",
+ correction: "Try removing the argument.");
+
+ /**
* 6.2.1 Required Formals: By means of a function signature that names the
* parameter and describes its type as a function type. It is a compile-time
* error if any default values are specified in the signature of such a
diff --git a/pkg/analyzer/lib/src/generated/error_verifier.dart b/pkg/analyzer/lib/src/generated/error_verifier.dart
index eedf26d..fa6ce99 100644
--- a/pkg/analyzer/lib/src/generated/error_verifier.dart
+++ b/pkg/analyzer/lib/src/generated/error_verifier.dart
@@ -960,6 +960,7 @@
} else {
_checkForNewWithUndefinedConstructor(node, constructorName, typeName);
}
+ _checkForListConstructor(node, type);
}
_checkForImplicitDynamicType(typeName);
super.visitInstanceCreationExpression(node);
@@ -3908,6 +3909,17 @@
}
}
+ void _checkForListConstructor(
+ InstanceCreationExpression node, InterfaceType type) {
+ if (node.argumentList.arguments.length == 1 &&
+ _isDartCoreList(type) &&
+ _typeSystem.isPotentiallyNonNullable(type.typeArguments[0])) {
+ _errorReporter.reportErrorForNode(
+ CompileTimeErrorCode.DEFAULT_LIST_CONSTRUCTOR_MISMATCH,
+ node.constructorName);
+ }
+ }
+
/**
* Verify that the elements of the given list [literal] are subtypes of the
* list's static type.
@@ -6212,6 +6224,14 @@
}
}
+ bool _isDartCoreList(InterfaceType type) {
+ ClassElement element = type.element;
+ if (element == null) {
+ return false;
+ }
+ return element.name == "List" && element.library.isDartCore;
+ }
+
bool _isFunctionType(DartType type) {
if (type.isDynamic || type.isDartCoreNull) {
return true;
diff --git a/pkg/analyzer/test/src/diagnostics/default_list_constructor_mismatch_test.dart b/pkg/analyzer/test/src/diagnostics/default_list_constructor_mismatch_test.dart
new file mode 100644
index 0000000..1769170
--- /dev/null
+++ b/pkg/analyzer/test/src/diagnostics/default_list_constructor_mismatch_test.dart
@@ -0,0 +1,70 @@
+// 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/dart/analysis/features.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(DefaultListConstructorMismatch);
+ });
+}
+
+@reflectiveTest
+class DefaultListConstructorMismatch extends DriverResolutionTest {
+ @override
+ AnalysisOptionsImpl get analysisOptions => AnalysisOptionsImpl()
+ ..contextFeatures = new FeatureSet.forTesting(
+ sdkVersion: '2.3.0', additionalFeatures: [Feature.non_nullable]);
+
+ test_nonNullableType() async {
+ await assertErrorsInCode('''
+var l = new List<int>(3);
+''', [
+ error(CompileTimeErrorCode.DEFAULT_LIST_CONSTRUCTOR_MISMATCH, 12, 9),
+ ]);
+ }
+
+ test_nullableType() async {
+ await assertNoErrorsInCode('''
+var l = new List<String?>(3);
+''');
+ }
+
+ @failingTest
+ test_inferredType() async {
+ // This test is failing because summary support is incomplete, which results
+ // in the constructor having a type of 'List<C*>*'.
+ await assertErrorsInCode('''
+class C {}
+List<C> v = List(5);
+''', [
+ error(CompileTimeErrorCode.DEFAULT_LIST_CONSTRUCTOR_MISMATCH, 23, 4),
+ ]);
+ }
+
+ test_starType() async {
+ // TODO(brianwilkerson) This test is currently taking advantage of the fact
+ // that the SDK is not opted in, which makes the use of `int` below a
+ // reference to 'int*'. When it's possible to opt-out in a test this needs
+ // to be updated to use an explicitly opted out type.
+ await assertNoErrorsInCode('''
+List<int> v = List(5);
+''');
+ }
+
+ test_typeParameter() async {
+ await assertErrorsInCode('''
+class C<T> {
+ var l = new List<T>(3);
+}
+''', [
+ error(CompileTimeErrorCode.DEFAULT_LIST_CONSTRUCTOR_MISMATCH, 27, 7),
+ ]);
+ }
+}
diff --git a/pkg/analyzer/test/src/diagnostics/test_all.dart b/pkg/analyzer/test/src/diagnostics/test_all.dart
index bf8f3b2..a9a5ec0 100644
--- a/pkg/analyzer/test/src/diagnostics/test_all.dart
+++ b/pkg/analyzer/test/src/diagnostics/test_all.dart
@@ -22,6 +22,8 @@
as const_spread_expected_list_or_set;
import 'const_spread_expected_map_test.dart' as const_spread_expected_map;
import 'dead_code_test.dart' as dead_code;
+import 'default_list_constructor_mismatch_test.dart'
+ as default_list_constructor_mismatch;
import 'default_value_on_required_parameter_test.dart'
as default_value_on_required_paramter;
import 'deprecated_member_use_test.dart' as deprecated_member_use;
@@ -169,6 +171,7 @@
const_spread_expected_list_or_set.main();
const_spread_expected_map.main();
dead_code.main();
+ default_list_constructor_mismatch.main();
default_value_on_required_paramter.main();
deprecated_member_use.main();
division_optimization.main();