Check type parameters in const function tearoff

Fixes https://github.com/dart-lang/sdk/issues/47213

Change-Id: I6c1c7e386e64b877e1ea7d312335d924488f2306
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/214134
Commit-Queue: Samuel Rawlins <srawlins@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
diff --git a/pkg/analyzer/lib/error/error.dart b/pkg/analyzer/lib/error/error.dart
index d80043e..c07ce8f 100644
--- a/pkg/analyzer/lib/error/error.dart
+++ b/pkg/analyzer/lib/error/error.dart
@@ -141,6 +141,7 @@
   CompileTimeErrorCode.CONST_WITH_NON_TYPE,
   CompileTimeErrorCode.CONST_WITH_TYPE_PARAMETERS,
   CompileTimeErrorCode.CONST_WITH_TYPE_PARAMETERS_CONSTRUCTOR_TEAROFF,
+  CompileTimeErrorCode.CONST_WITH_TYPE_PARAMETERS_FUNCTION_TEAROFF,
   CompileTimeErrorCode.CONST_WITH_UNDEFINED_CONSTRUCTOR,
   CompileTimeErrorCode.CONST_WITH_UNDEFINED_CONSTRUCTOR_DEFAULT,
   CompileTimeErrorCode.CONTINUE_LABEL_ON_SWITCH,
diff --git a/pkg/analyzer/lib/src/dart/constant/constant_verifier.dart b/pkg/analyzer/lib/src/dart/constant/constant_verifier.dart
index 98d8a04..9dd8d87b 100644
--- a/pkg/analyzer/lib/src/dart/constant/constant_verifier.dart
+++ b/pkg/analyzer/lib/src/dart/constant/constant_verifier.dart
@@ -129,6 +129,21 @@
   }
 
   @override
+  void visitFunctionReference(FunctionReference node) {
+    super.visitFunctionReference(node);
+    if (node.inConstantContext) {
+      var typeArguments = node.typeArguments;
+      if (typeArguments == null) {
+        return;
+      }
+      for (var typeArgument in typeArguments.arguments) {
+        _checkForConstWithTypeParameters(typeArgument,
+            CompileTimeErrorCode.CONST_WITH_TYPE_PARAMETERS_FUNCTION_TEAROFF);
+      }
+    }
+  }
+
+  @override
   void visitGenericFunctionType(GenericFunctionType node) {
     // TODO(srawlins): Also check interface types (TypeName?).
     super.visitGenericFunctionType(node);
diff --git a/pkg/analyzer/lib/src/error/codes.dart b/pkg/analyzer/lib/src/error/codes.dart
index 3945838..6427f89 100644
--- a/pkg/analyzer/lib/src/error/codes.dart
+++ b/pkg/analyzer/lib/src/error/codes.dart
@@ -2899,6 +2899,18 @@
           hasPublishedDocs: true);
 
   /**
+   * No parameters.
+   */
+  static const CompileTimeErrorCode
+      CONST_WITH_TYPE_PARAMETERS_FUNCTION_TEAROFF = CompileTimeErrorCode(
+          'CONST_WITH_TYPE_PARAMETERS',
+          "A constant function tearoff can't use a type parameter as a type "
+              "argument.",
+          correction: "Try replacing the type parameter with a different type.",
+          uniqueName: 'CONST_WITH_TYPE_PARAMETERS_FUNCTION_TEAROFF',
+          hasPublishedDocs: true);
+
+  /**
    * 16.12.2 Const: It is a compile-time error if <i>T.id</i> is not the name of
    * a constant constructor declared by the type <i>T</i>.
    *
diff --git a/pkg/analyzer/test/src/diagnostics/const_with_type_parameters_test.dart b/pkg/analyzer/test/src/diagnostics/const_with_type_parameters_test.dart
index 6df3560..6b02405 100644
--- a/pkg/analyzer/test/src/diagnostics/const_with_type_parameters_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/const_with_type_parameters_test.dart
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:analyzer/src/error/codes.dart';
+import 'package:test/test.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
 import '../dart/resolution/context_collection_resolution.dart';
@@ -10,6 +11,7 @@
 main() {
   defineReflectiveSuite(() {
     defineReflectiveTests(ConstWithTypeParametersConstructorTearoffTest);
+    defineReflectiveTests(ConstWithTypeParametersFunctionTearoffTest);
     defineReflectiveTests(ConstWithTypeParametersTest);
   });
 }
@@ -84,6 +86,71 @@
 }
 
 @reflectiveTest
+class ConstWithTypeParametersFunctionTearoffTest
+    extends PubPackageResolutionTest {
+  @FailingTest(
+    reason: 'The default value of an optional parameter is not considered a '
+        '"constant context". Currently only ConstantVerifier checks '
+        'CONST_WITH_TYPE_PARAMETERS (and related) errors, and only for '
+        'constant contexts. These checks should probably be moved to '
+        'ConstantVisitor (evaluation.dart), so as to check all expressions '
+        'expected to be constant expressions. Another example of a missing '
+        'error is a field initializer in a class with a constant constructor.',
+  )
+  test_defaultValue() async {
+    addTestFile('''
+void f<T>(T a) {}
+class A<U> {
+  void m([void Function(U) fn = f<U>]) {}
+}
+''');
+    await resolveTestFile();
+    expect(result.errors, isNotEmpty);
+  }
+
+  test_direct() async {
+    await assertErrorsInCode('''
+void f<T>(T a) {}
+class A<U> {
+  void m() {
+    const c = f<U>;
+  }
+}
+''', [
+      error(HintCode.UNUSED_LOCAL_VARIABLE, 54, 1),
+      error(CompileTimeErrorCode.CONST_WITH_TYPE_PARAMETERS_FUNCTION_TEAROFF,
+          60, 1),
+    ]);
+  }
+
+  test_indirect() async {
+    await assertErrorsInCode('''
+void f<T>(T a) {}
+class A<U> {
+  void m() {
+    const c = f<List<U>>;
+  }
+}
+''', [
+      error(HintCode.UNUSED_LOCAL_VARIABLE, 54, 1),
+      error(CompileTimeErrorCode.CONST_WITH_TYPE_PARAMETERS_FUNCTION_TEAROFF,
+          65, 1),
+    ]);
+  }
+
+  test_nonConst() async {
+    await assertNoErrorsInCode('''
+void f<T>(T a) {}
+class A<U> {
+  void m() {
+    f<U>;
+  }
+}
+''');
+  }
+}
+
+@reflectiveTest
 class ConstWithTypeParametersTest extends PubPackageResolutionTest {
   test_direct() async {
     await assertErrorsInCode('''
diff --git a/pkg/analyzer/tool/diagnostics/diagnostics.md b/pkg/analyzer/tool/diagnostics/diagnostics.md
index 9a10697..b519644 100644
--- a/pkg/analyzer/tool/diagnostics/diagnostics.md
+++ b/pkg/analyzer/tool/diagnostics/diagnostics.md
@@ -2648,6 +2648,8 @@
 
 _A constant creation can't use a type parameter as a type argument._
 
+_A constant function tearoff can't use a type parameter as a type argument._
+
 #### Description
 
 The analyzer produces this diagnostic when a type parameter is used as a