Skip to content

Commit

Permalink
Fix second half on #33343: disallow generic functions as type arguments.
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
MichaelRFairhurst authored and commit-bot@chromium.org committed Jun 25, 2018
1 parent 97c81d6 commit 3640037
Show file tree
Hide file tree
Showing 8 changed files with 153 additions and 4 deletions.
1 change: 1 addition & 0 deletions pkg/analyzer/lib/error/error.dart
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ const List<ErrorCode> errorCodeValues = const [
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,
Expand Down
12 changes: 12 additions & 0 deletions pkg/analyzer/lib/src/error/codes.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2409,6 +2409,18 @@ class CompileTimeErrorCode extends ErrorCode {
correction: 'Try making the free variable in the function type part'
' 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.
Expand Down
17 changes: 17 additions & 0 deletions pkg/analyzer/lib/src/generated/error_verifier.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5947,11 +5947,19 @@ class ErrorVerifier extends RecursiveAstVisitor<Object> {
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) {
Expand Down Expand Up @@ -6471,6 +6479,15 @@ class ErrorVerifier extends RecursiveAstVisitor<Object> {
// <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)) {
Expand Down
3 changes: 2 additions & 1 deletion pkg/analyzer/lib/src/generated/type_system.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ import 'package:analyzer/error/listener.dart' show ErrorReporter;
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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3133,6 +3133,34 @@ class CompileTimeErrorCodeTest_Kernel extends CompileTimeErrorCodeTest_Driver {
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.
Expand Down
92 changes: 92 additions & 0 deletions pkg/analyzer/test/generated/compile_time_error_code_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7063,6 +7063,98 @@ f() { return const G<B>(); }''');
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
Expand Down
2 changes: 0 additions & 2 deletions tests/language_2/language_2_analyzer.status
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ final_syntax_test/03: Fail # Issue 11124
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
Expand Down Expand Up @@ -1354,7 +1353,6 @@ generic_constructor_mixin3_test/01: MissingCompileTimeError
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
Expand Down
2 changes: 1 addition & 1 deletion tests/language_2/language_2_dartdevc.status
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,7 @@ function_propagation_test: RuntimeError
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
Expand Down Expand Up @@ -666,7 +667,6 @@ flatten_test/09: MissingRuntimeError # Issue 29920
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.
Expand Down

0 comments on commit 3640037

Please sign in to comment.