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