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();