Fix second half on #33343: disallow generic functions as type arguments.
There is a seeming parse error in typedefs, and an open question on the
issue (33343) about what to do when a generic function type is inferred.
Otherwise this seems ready to go.
Bug: 33343
Change-Id: I10d2ea9b6ca26ed2c6ff6b24ffe5008fc4797ef2
Reviewed-on: https://dart-review.googlesource.com/61109
Commit-Queue: Mike Fairhurst <mfairhurst@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
diff --git a/pkg/analyzer/lib/error/error.dart b/pkg/analyzer/lib/error/error.dart
index 316443a..1557389 100644
--- a/pkg/analyzer/lib/error/error.dart
+++ b/pkg/analyzer/lib/error/error.dart
@@ -130,6 +130,7 @@
CompileTimeErrorCode.FINAL_INITIALIZED_MULTIPLE_TIMES,
CompileTimeErrorCode.GENERIC_FUNCTION_TYPED_PARAM_UNSUPPORTED,
CompileTimeErrorCode.GENERIC_FUNCTION_TYPE_CANNOT_BE_BOUND,
+ CompileTimeErrorCode.GENERIC_FUNCTION_CANNOT_BE_TYPE_ARGUMENT,
CompileTimeErrorCode.GETTER_AND_METHOD_WITH_SAME_NAME,
CompileTimeErrorCode.IMPLEMENTS_DEFERRED_CLASS,
CompileTimeErrorCode.IMPLEMENTS_DISALLOWED_CLASS,
diff --git a/pkg/analyzer/lib/src/error/codes.dart b/pkg/analyzer/lib/src/error/codes.dart
index e071c48..5d1bada 100644
--- a/pkg/analyzer/lib/src/error/codes.dart
+++ b/pkg/analyzer/lib/src/error/codes.dart
@@ -2410,6 +2410,18 @@
' of the larger declaration signature');
/**
+ * It is a compile-time error if a generic function type is used as an actual
+ * type argument.
+ */
+ static const CompileTimeErrorCode GENERIC_FUNCTION_CANNOT_BE_TYPE_ARGUMENT =
+ const CompileTimeErrorCode(
+ 'GENERIC_FUNCTION_CANNOT_BE_TYPE_ARGUMENT',
+ "Generic function has type parameters '<{0}>', so it may not be used"
+ ' as a type argument',
+ correction: "Try removing the type parameters '<{0}>', or using"
+ " 'dynamic' as the type argument here instead of a function.");
+
+ /**
* 15.3.1 Typedef: Any self reference, either directly, or recursively via
* another typedef, is a compile time error.
*/
diff --git a/pkg/analyzer/lib/src/generated/error_verifier.dart b/pkg/analyzer/lib/src/generated/error_verifier.dart
index 7cf79c0..b470ac2 100644
--- a/pkg/analyzer/lib/src/generated/error_verifier.dart
+++ b/pkg/analyzer/lib/src/generated/error_verifier.dart
@@ -5947,11 +5947,19 @@
for (int i = 0; i < loopThroughIndex; i++) {
TypeAnnotation argumentNode = argumentNodes[i];
DartType argType = argumentNode.type;
+ if (argType is FunctionType && argType.typeFormals.isNotEmpty) {
+ _errorReporter.reportTypeErrorForNode(
+ CompileTimeErrorCode.GENERIC_FUNCTION_CANNOT_BE_TYPE_ARGUMENT,
+ argumentNode,
+ [argType.typeFormals.join(', ')]);
+ continue;
+ }
DartType boundType = parameterElements[i].bound;
if (argType != null && boundType != null) {
if (shouldSubstitute) {
boundType = boundType.substitute2(arguments, parameterTypes);
}
+
if (!_typeSystem.isSubtypeOf(argType, boundType)) {
ErrorCode errorCode;
if (_isInConstInstanceCreation) {
@@ -6471,6 +6479,15 @@
// <T extends Clonable<T>>
//
DartType argType = typeArgs[i];
+
+ if (argType is FunctionType && argType.typeFormals.isNotEmpty) {
+ _errorReporter.reportTypeErrorForNode(
+ CompileTimeErrorCode.GENERIC_FUNCTION_CANNOT_BE_TYPE_ARGUMENT,
+ typeArgumentList[i],
+ [argType.typeFormals.join(', ')]);
+ continue;
+ }
+
DartType bound =
fnTypeParams[i].bound.substitute2(typeArgs, fnTypeParams);
if (!_typeSystem.isSubtypeOf(argType, bound)) {
diff --git a/pkg/analyzer/lib/src/generated/type_system.dart b/pkg/analyzer/lib/src/generated/type_system.dart
index e54318a..a500975 100644
--- a/pkg/analyzer/lib/src/generated/type_system.dart
+++ b/pkg/analyzer/lib/src/generated/type_system.dart
@@ -15,7 +15,8 @@
import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/dart/element/member.dart' show TypeParameterMember;
import 'package:analyzer/src/dart/element/type.dart';
-import 'package:analyzer/src/error/codes.dart' show StrongModeCode;
+import 'package:analyzer/src/error/codes.dart'
+ show StrongModeCode, CompileTimeErrorCode;
import 'package:analyzer/src/generated/engine.dart'
show AnalysisContext, AnalysisOptionsImpl;
import 'package:analyzer/src/generated/resolver.dart' show TypeProvider;
diff --git a/pkg/analyzer/test/generated/compile_time_error_code_kernel_test.dart b/pkg/analyzer/test/generated/compile_time_error_code_kernel_test.dart
index 8232bc7..97fa300 100644
--- a/pkg/analyzer/test/generated/compile_time_error_code_kernel_test.dart
+++ b/pkg/analyzer/test/generated/compile_time_error_code_kernel_test.dart
@@ -3133,6 +3133,34 @@
test_genericFunctionTypeAsBound_typedef() async {
await super.test_genericFunctionTypeAsBound_typedef();
}
+
+ @override
+ @failingTest
+ @potentialAnalyzerProblem
+ test_genericFunctionTypeArgument_class() async {
+ await super.test_genericFunctionTypeArgument_class();
+ }
+
+ @override
+ @failingTest
+ @potentialAnalyzerProblem
+ test_genericFunctionTypeArgument_functionType() async {
+ await super.test_genericFunctionTypeArgument_functionType();
+ }
+
+ @override
+ @failingTest
+ @potentialAnalyzerProblem
+ test_genericFunctionTypeArgument_function() async {
+ await super.test_genericFunctionTypeArgument_function();
+ }
+
+ @override
+ @failingTest
+ @potentialAnalyzerProblem
+ test_genericFunctionTypeArgument_method() async {
+ await super.test_genericFunctionTypeArgument_method();
+ }
}
/// Tests marked with this annotation fail because of a Fasta problem.
diff --git a/pkg/analyzer/test/generated/compile_time_error_code_test.dart b/pkg/analyzer/test/generated/compile_time_error_code_test.dart
index 8b91102..6f250b2 100644
--- a/pkg/analyzer/test/generated/compile_time_error_code_test.dart
+++ b/pkg/analyzer/test/generated/compile_time_error_code_test.dart
@@ -7063,6 +7063,98 @@
verify([source]);
}
+ test_genericFunctionTypeArgument_class() async {
+ Source source = addSource(r'''
+class C<T> {}
+C<T Function<T>(T)> c;''');
+ await computeAnalysisResult(source);
+ assertErrors(source,
+ [CompileTimeErrorCode.GENERIC_FUNCTION_CANNOT_BE_TYPE_ARGUMENT]);
+ verify([source]);
+ }
+
+ test_genericFunctionTypeArgument_functionType() async {
+ Source source = addSource(r'''
+T Function<T>(T) f;
+main() { f<S Function<S>(S)>(null); }''');
+ await computeAnalysisResult(source);
+ assertErrors(source,
+ [CompileTimeErrorCode.GENERIC_FUNCTION_CANNOT_BE_TYPE_ARGUMENT]);
+ verify([source]);
+ }
+
+ test_genericFunctionTypeArgument_function() async {
+ Source source = addSource(r'''
+T f<T>(T) => null;
+main() { f<S Function<S>(S)>(null); }''');
+ await computeAnalysisResult(source);
+ assertErrors(source,
+ [CompileTimeErrorCode.GENERIC_FUNCTION_CANNOT_BE_TYPE_ARGUMENT]);
+ verify([source]);
+ }
+
+ test_genericFunctionTypeArgument_method() async {
+ Source source = addSource(r'''
+class C {
+ T f<T>(T) => null;
+}
+main() { new C().f<S Function<S>(S)>(null); }''');
+ await computeAnalysisResult(source);
+ assertErrors(source,
+ [CompileTimeErrorCode.GENERIC_FUNCTION_CANNOT_BE_TYPE_ARGUMENT]);
+ verify([source]);
+ }
+
+ @failingTest
+ test_genericFunctionTypeArgument_inference_functionType() async {
+ // TODO(mfairhurst) how should these inference errors be reported?
+ Source source = addSource(r'''
+T Function<T>(T) f;
+main() { f(<S>(S s) => s); }''');
+ await computeAnalysisResult(source);
+ assertErrors(source,
+ [CompileTimeErrorCode.GENERIC_FUNCTION_CANNOT_BE_TYPE_ARGUMENT]);
+ verify([source]);
+ }
+
+ @failingTest
+ test_genericFunctionTypeArgument_inference_function() async {
+ // TODO(mfairhurst) how should these inference errors be reported?
+ Source source = addSource(r'''
+T f<T>(T) => null;
+main() { f(<S>(S s) => s); }''');
+ await computeAnalysisResult(source);
+ assertErrors(source,
+ [CompileTimeErrorCode.GENERIC_FUNCTION_CANNOT_BE_TYPE_ARGUMENT]);
+ verify([source]);
+ }
+
+ @failingTest
+ test_genericFunctionTypeArgument_inference_method() async {
+ // TODO(mfairhurst) how should these inference errors be reported?
+ Source source = addSource(r'''
+class C {
+ T f<T>(T) => null;
+}
+main() { new C().f(<S>(S s) => s); }''');
+ await computeAnalysisResult(source);
+ assertErrors(source,
+ [CompileTimeErrorCode.GENERIC_FUNCTION_CANNOT_BE_TYPE_ARGUMENT]);
+ verify([source]);
+ }
+
+ @failingTest
+ test_genericFunctionTypeArgument_typedef() async {
+ // TODO(mfairhurst) diagnose these parse errors to give the correct error
+ Source source = addSource(r'''
+typedef T f<T>(T t);
+final T<Function<S>(int)> x = null;''');
+ await computeAnalysisResult(source);
+ assertErrors(source,
+ [CompileTimeErrorCode.GENERIC_FUNCTION_CANNOT_BE_TYPE_ARGUMENT]);
+ verify([source]);
+ }
+
test_undefinedAnnotation_unresolved_identifier() async {
Source source = addSource(r'''
@unresolved
diff --git a/tests/language_2/language_2_analyzer.status b/tests/language_2/language_2_analyzer.status
index 79bacbd..705f190 100644
--- a/tests/language_2/language_2_analyzer.status
+++ b/tests/language_2/language_2_analyzer.status
@@ -33,7 +33,6 @@
final_syntax_test/04: Fail # Issue 11124
function_type_parameter2_negative_test: CompileTimeError
function_type_parameter_negative_test: CompileTimeError
-generic_function_type_as_type_argument_test/01: MissingCompileTimeError # Issue 30929
generic_function_type_as_type_argument_test/02: MissingCompileTimeError # Issue 30929
generic_local_functions_test: CompileTimeError # Issue 28515
generic_methods_generic_function_parameter_test: CompileTimeError # Issue 28515
@@ -1354,7 +1353,6 @@
generic_constructor_mixin_test/01: MissingCompileTimeError
generic_field_mixin6_test/01: MissingCompileTimeError
generic_function_typedef2_test/04: MissingCompileTimeError
-generic_methods_generic_function_result_test/01: MissingCompileTimeError # Issue #30207
generic_methods_overriding_test/01: MissingCompileTimeError
generic_test/01: MissingCompileTimeError
identical_const_test/01: MissingCompileTimeError
diff --git a/tests/language_2/language_2_dartdevc.status b/tests/language_2/language_2_dartdevc.status
index d93e1c8..a643e67 100644
--- a/tests/language_2/language_2_dartdevc.status
+++ b/tests/language_2/language_2_dartdevc.status
@@ -384,6 +384,7 @@
function_type_parameter2_negative_test: Fail
function_type_parameter_negative_test: Fail
generic_function_bounds_test: RuntimeError
+generic_function_type_as_type_argument_test/01: MissingCompileTimeError # Issue 29920
generic_methods_generic_function_result_test/01: MissingCompileTimeError
generic_methods_overriding_test/01: MissingCompileTimeError # Issue 29920
generic_methods_recursive_bound_test/02: MissingCompileTimeError
@@ -666,7 +667,6 @@
flatten_test/12: MissingRuntimeError # Issue 29920
for_variable_capture_test: RuntimeError # Issue 29920; Expect.equals(expected: <1>, actual: <0>) fails.
function_subtype_inline2_test: RuntimeError # Expect.fail('Missing type error: 'new C.c1(m2)'.')
-generic_function_type_as_type_argument_test/01: MissingCompileTimeError # Issue 29920
generic_function_type_as_type_argument_test/02: MissingCompileTimeError # Issue 29920
generic_instanceof2_test: RuntimeError # Issue 29920; ReferenceError: FooOfK$String is not defined
generic_is_check_test: RuntimeError # Issue 29920; Expect.isTrue(false) fails.