Skip to content

Commit 7ee3f73

Browse files
srawlinscommit-bot@chromium.org
authored andcommitted
Analyzer: Allow generic function types as type arguments and bounds
Bug: #44929 Change-Id: I9c83a9abd47ec6b3d59c118493c838632fc3182a Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/185305 Commit-Queue: Samuel Rawlins <[email protected]> Reviewed-by: Brian Wilkerson <[email protected]> Reviewed-by: Konstantin Shcheglov <[email protected]>
1 parent a84ee96 commit 7ee3f73

17 files changed

+291
-71
lines changed

pkg/analysis_server/lib/src/services/completion/dart/extension_member_contributor.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,8 @@ class ExtensionMemberContributor extends DartCompletionContributor {
150150
extension.extendedType,
151151
'extendedType',
152152
);
153-
var typeArguments = inferrer.infer(typeParameters, failAtError: true);
153+
var typeArguments = inferrer.infer(typeParameters,
154+
failAtError: true, genericMetadataIsEnabled: true);
154155
if (typeArguments == null) {
155156
return null;
156157
}

pkg/analyzer/lib/src/dart/element/generic_inferrer.dart

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -118,12 +118,15 @@ class GenericInferrer {
118118
/// `_` to precisely represent an unknown type. If [downwardsInferPhase] is
119119
/// false, we are on our final inference pass, have all available information
120120
/// including argument types, and must not conclude `_` for any type formal.
121-
List<DartType>? infer(List<TypeParameterElement> typeFormals,
122-
{bool considerExtendsClause = true,
123-
ErrorReporter? errorReporter,
124-
AstNode? errorNode,
125-
bool failAtError = false,
126-
bool downwardsInferPhase = false}) {
121+
List<DartType>? infer(
122+
List<TypeParameterElement> typeFormals, {
123+
bool considerExtendsClause = true,
124+
ErrorReporter? errorReporter,
125+
AstNode? errorNode,
126+
bool failAtError = false,
127+
bool downwardsInferPhase = false,
128+
required bool genericMetadataIsEnabled,
129+
}) {
127130
// Initialize the inferred type array.
128131
//
129132
// In the downwards phase, they all start as `_` to offer reasonable
@@ -204,7 +207,9 @@ class GenericInferrer {
204207
// more errors (e.g. because `dynamic` is the most common bound).
205208
}
206209

207-
if (inferred is FunctionType && inferred.typeFormals.isNotEmpty) {
210+
if (inferred is FunctionType &&
211+
inferred.typeFormals.isNotEmpty &&
212+
!genericMetadataIsEnabled) {
208213
if (failAtError) return null;
209214
var typeFormals = inferred.typeFormals;
210215
var typeFormalsStr = typeFormals.map(_elementStr).join(', ');
@@ -215,12 +220,6 @@ class GenericInferrer {
215220
' [$typeFormalsStr], but a function with'
216221
' type parameters cannot be used as a type argument.'
217222
]);
218-
219-
// Heuristic: Using a generic function type as a bound makes subtyping
220-
// undecidable. Therefore, we cannot keep [inferred] unless we wish to
221-
// generate bogus subtyping errors. Instead generate plain [Function],
222-
// which is the most general function type.
223-
inferred = typeProvider.functionType;
224223
}
225224

226225
if (UnknownInferredType.isKnown(inferred)) {

pkg/analyzer/lib/src/dart/element/type_system.dart

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -419,8 +419,12 @@ class TypeSystemImpl implements TypeSystem {
419419
/// uninstantiated, or a [fnType] that is already instantiated, it will have
420420
/// no effect and return `null`.
421421
List<DartType>? inferFunctionTypeInstantiation(
422-
FunctionType contextType, FunctionType fnType,
423-
{ErrorReporter? errorReporter, AstNode? errorNode}) {
422+
FunctionType contextType,
423+
FunctionType fnType, {
424+
ErrorReporter? errorReporter,
425+
AstNode? errorNode,
426+
required bool genericMetadataIsEnabled,
427+
}) {
424428
if (contextType.typeFormals.isNotEmpty || fnType.typeFormals.isEmpty) {
425429
return const <DartType>[];
426430
}
@@ -437,6 +441,7 @@ class TypeSystemImpl implements TypeSystem {
437441
fnType.typeFormals,
438442
errorReporter: errorReporter,
439443
errorNode: errorNode,
444+
genericMetadataIsEnabled: genericMetadataIsEnabled,
440445
);
441446
}
442447

@@ -472,6 +477,7 @@ class TypeSystemImpl implements TypeSystem {
472477
AstNode? errorNode,
473478
bool downwards = false,
474479
bool isConst = false,
480+
required bool genericMetadataIsEnabled,
475481
}) {
476482
if (typeParameters.isEmpty) {
477483
return null;
@@ -506,6 +512,7 @@ class TypeSystemImpl implements TypeSystem {
506512
errorReporter: errorReporter,
507513
errorNode: errorNode,
508514
downwardsInferPhase: downwards,
515+
genericMetadataIsEnabled: genericMetadataIsEnabled,
509516
);
510517
}
511518

@@ -1250,8 +1257,9 @@ class TypeSystemImpl implements TypeSystem {
12501257
List<DartType>? matchSupertypeConstraints(
12511258
ClassElement mixinElement,
12521259
List<DartType> srcTypes,
1253-
List<DartType> destTypes,
1254-
) {
1260+
List<DartType> destTypes, {
1261+
required bool genericMetadataIsEnabled,
1262+
}) {
12551263
var typeParameters = mixinElement.typeParameters;
12561264
var inferrer = GenericInferrer(this, typeParameters);
12571265
for (int i = 0; i < srcTypes.length; i++) {
@@ -1262,6 +1270,7 @@ class TypeSystemImpl implements TypeSystem {
12621270
var inferredTypes = inferrer.infer(
12631271
typeParameters,
12641272
considerExtendsClause: false,
1273+
genericMetadataIsEnabled: genericMetadataIsEnabled,
12651274
)!;
12661275
inferredTypes =
12671276
inferredTypes.map(_removeBoundsOfGenericFunctionTypes).toList();

pkg/analyzer/lib/src/dart/resolver/extension_member_resolver.dart

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// for details. All rights reserved. Use of this source code is governed by a
33
// BSD-style license that can be found in the LICENSE file.
44

5+
import 'package:analyzer/dart/analysis/features.dart';
56
import 'package:analyzer/dart/ast/ast.dart';
67
import 'package:analyzer/dart/ast/syntactic_entity.dart';
78
import 'package:analyzer/dart/element/element.dart';
@@ -31,6 +32,9 @@ class ExtensionMemberResolver {
3132

3233
ErrorReporter get _errorReporter => _resolver.errorReporter;
3334

35+
bool get _genericMetadataIsEnabled =>
36+
_resolver.definingLibrary.featureSet.isEnabled(Feature.generic_metadata);
37+
3438
Scope get _nameScope => _resolver.nameScope;
3539

3640
TypeProvider get _typeProvider => _resolver.typeProvider;
@@ -289,6 +293,7 @@ class ExtensionMemberResolver {
289293
var typeArguments = inferrer.infer(
290294
freshTypeParameters,
291295
failAtError: true,
296+
genericMetadataIsEnabled: _genericMetadataIsEnabled,
292297
);
293298
if (typeArguments == null) {
294299
continue;
@@ -407,6 +412,7 @@ class ExtensionMemberResolver {
407412
typeParameters,
408413
errorReporter: _errorReporter,
409414
errorNode: node.extensionName,
415+
genericMetadataIsEnabled: _genericMetadataIsEnabled,
410416
);
411417
}
412418
}

pkg/analyzer/lib/src/dart/resolver/invocation_inference_helper.dart

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// for details. All rights reserved. Use of this source code is governed by a
33
// BSD-style license that can be found in the LICENSE file.
44

5+
import 'package:analyzer/dart/analysis/features.dart';
56
import 'package:analyzer/dart/ast/ast.dart';
67
import 'package:analyzer/dart/element/element.dart';
78
import 'package:analyzer/dart/element/type.dart';
@@ -20,19 +21,22 @@ class InvocationInferenceHelper {
2021
final ErrorReporter _errorReporter;
2122
final TypeSystemImpl _typeSystem;
2223
final MigrationResolutionHooks? _migrationResolutionHooks;
24+
final bool _genericMetadataIsEnabled;
2325

2426
List<DartType>? _typeArgumentTypes;
2527
FunctionType? _invokeType;
2628

27-
InvocationInferenceHelper(
28-
{required ResolverVisitor resolver,
29-
required ErrorReporter errorReporter,
30-
required TypeSystemImpl typeSystem,
31-
required MigrationResolutionHooks? migrationResolutionHooks})
32-
: _resolver = resolver,
29+
InvocationInferenceHelper({
30+
required ResolverVisitor resolver,
31+
required ErrorReporter errorReporter,
32+
required TypeSystemImpl typeSystem,
33+
required MigrationResolutionHooks? migrationResolutionHooks,
34+
}) : _resolver = resolver,
3335
_errorReporter = errorReporter,
3436
_typeSystem = typeSystem,
35-
_migrationResolutionHooks = migrationResolutionHooks;
37+
_migrationResolutionHooks = migrationResolutionHooks,
38+
_genericMetadataIsEnabled = resolver.definingLibrary.featureSet
39+
.isEnabled(Feature.generic_metadata);
3640

3741
/// Compute the return type of the method or function represented by the given
3842
/// type that is being invoked.
@@ -62,6 +66,7 @@ class InvocationInferenceHelper {
6266
isConst: isConst,
6367
errorReporter: _errorReporter,
6468
errorNode: errorNode,
69+
genericMetadataIsEnabled: _genericMetadataIsEnabled,
6570
);
6671
if (typeArguments != null) {
6772
return uninstantiatedType.instantiate(typeArguments);
@@ -164,6 +169,7 @@ class InvocationInferenceHelper {
164169
tearOffType,
165170
errorReporter: _resolver.errorReporter,
166171
errorNode: expression,
172+
genericMetadataIsEnabled: _genericMetadataIsEnabled,
167173
)!;
168174
(identifier as SimpleIdentifierImpl).tearOffTypeArgumentTypes =
169175
typeArguments;
@@ -266,6 +272,7 @@ class InvocationInferenceHelper {
266272
isConst: isConst,
267273
errorReporter: _errorReporter,
268274
errorNode: errorNode,
275+
genericMetadataIsEnabled: _genericMetadataIsEnabled,
269276
);
270277
}
271278

@@ -302,6 +309,7 @@ class InvocationInferenceHelper {
302309
isConst: isConst,
303310
errorReporter: _errorReporter,
304311
errorNode: errorNode,
312+
genericMetadataIsEnabled: _genericMetadataIsEnabled,
305313
);
306314
return typeArgs;
307315
}

pkg/analyzer/lib/src/dart/resolver/type_name_resolver.dart

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// for details. All rights reserved. Use of this source code is governed by a
33
// BSD-style license that can be found in the LICENSE file.
44

5+
import 'package:analyzer/dart/analysis/features.dart';
56
import 'package:analyzer/dart/ast/ast.dart';
67
import 'package:analyzer/dart/element/element.dart';
78
import 'package:analyzer/dart/element/nullability_suffix.dart';
@@ -54,6 +55,9 @@ class TypeNameResolver {
5455
this.isNonNullableByDefault, this.errorReporter)
5556
: dynamicType = typeProvider.dynamicType;
5657

58+
bool get _genericMetadataIsEnabled =>
59+
enclosingClass!.library.featureSet.isEnabled(Feature.generic_metadata);
60+
5761
NullabilitySuffix get _noneOrStarSuffix {
5862
return isNonNullableByDefault
5963
? NullabilitySuffix.none
@@ -167,6 +171,7 @@ class TypeNameResolver {
167171
declaredReturnType: element.thisType,
168172
argumentTypes: const [],
169173
contextReturnType: enclosingClass!.thisType,
174+
genericMetadataIsEnabled: _genericMetadataIsEnabled,
170175
)!;
171176
return element.instantiate(
172177
typeArguments: typeArguments,

pkg/analyzer/lib/src/dart/resolver/typed_literal_resolver.dart

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,9 @@ class TypedLiteralResolver {
6464

6565
DynamicTypeImpl get _dynamicType => DynamicTypeImpl.instance;
6666

67+
bool get _genericMetadataIsEnabled =>
68+
_resolver.definingLibrary.featureSet.isEnabled(Feature.generic_metadata);
69+
6770
NullabilitySuffix get _noneOrStarSuffix {
6871
return _isNonNullableByDefault
6972
? NullabilitySuffix.none
@@ -460,6 +463,7 @@ class TypedLiteralResolver {
460463
isConst: node.isConst,
461464
errorReporter: _errorReporter,
462465
errorNode: node,
466+
genericMetadataIsEnabled: _genericMetadataIsEnabled,
463467
)!;
464468
return element.instantiate(
465469
typeArguments: typeArguments,
@@ -484,6 +488,7 @@ class TypedLiteralResolver {
484488
isConst: node.isConst,
485489
errorReporter: _errorReporter,
486490
errorNode: node,
491+
genericMetadataIsEnabled: _genericMetadataIsEnabled,
487492
)!;
488493
return element.instantiate(
489494
typeArguments: typeArguments,
@@ -582,6 +587,7 @@ class TypedLiteralResolver {
582587
isConst: node.isConst,
583588
errorReporter: _errorReporter,
584589
errorNode: node,
590+
genericMetadataIsEnabled: _genericMetadataIsEnabled,
585591
)!;
586592
return element.instantiate(
587593
typeArguments: typeArguments,
@@ -782,6 +788,7 @@ class TypedLiteralResolver {
782788
declaredReturnType: element.thisType,
783789
argumentTypes: argumentTypes,
784790
contextReturnType: contextType,
791+
genericMetadataIsEnabled: _genericMetadataIsEnabled,
785792
)!;
786793
return element.instantiate(
787794
typeArguments: typeArguments,
@@ -813,6 +820,7 @@ class TypedLiteralResolver {
813820
declaredReturnType: element.thisType,
814821
argumentTypes: argumentTypes,
815822
contextReturnType: contextType,
823+
genericMetadataIsEnabled: _genericMetadataIsEnabled,
816824
)!;
817825
return element.instantiate(
818826
typeArguments: typeArguments,

pkg/analyzer/lib/src/error/type_arguments_verifier.dart

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
import "dart:math" as math;
66

7+
import 'package:analyzer/dart/analysis/features.dart';
78
import 'package:analyzer/dart/ast/ast.dart';
89
import 'package:analyzer/dart/element/element.dart';
910
import 'package:analyzer/dart/element/type.dart';
@@ -216,10 +217,12 @@ class TypeArgumentsVerifier {
216217
var typeArgument = typeArguments[i];
217218

218219
if (typeArgument is FunctionType && typeArgument.typeFormals.isNotEmpty) {
219-
_errorReporter.reportErrorForNode(
220-
CompileTimeErrorCode.GENERIC_FUNCTION_TYPE_CANNOT_BE_TYPE_ARGUMENT,
221-
_typeArgumentErrorNode(typeName, i),
222-
);
220+
if (!_libraryElement.featureSet.isEnabled(Feature.generic_metadata)) {
221+
_errorReporter.reportErrorForNode(
222+
CompileTimeErrorCode.GENERIC_FUNCTION_TYPE_CANNOT_BE_TYPE_ARGUMENT,
223+
_typeArgumentErrorNode(typeName, i),
224+
);
225+
}
223226
continue;
224227
}
225228

@@ -354,10 +357,13 @@ class TypeArgumentsVerifier {
354357
DartType argType = typeArgs[i];
355358

356359
if (argType is FunctionType && argType.typeFormals.isNotEmpty) {
357-
_errorReporter.reportErrorForNode(
358-
CompileTimeErrorCode.GENERIC_FUNCTION_TYPE_CANNOT_BE_TYPE_ARGUMENT,
359-
typeArgumentList[i],
360-
);
360+
if (!_libraryElement.featureSet.isEnabled(Feature.generic_metadata)) {
361+
_errorReporter.reportErrorForNode(
362+
CompileTimeErrorCode
363+
.GENERIC_FUNCTION_TYPE_CANNOT_BE_TYPE_ARGUMENT,
364+
typeArgumentList[i],
365+
);
366+
}
361367
continue;
362368
}
363369

pkg/analyzer/lib/src/generated/error_verifier.dart

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2684,6 +2684,9 @@ class ErrorVerifier extends RecursiveAstVisitor<void> {
26842684
if (node == null) {
26852685
return;
26862686
}
2687+
if (_featureSet?.isEnabled(Feature.generic_metadata) ?? false) {
2688+
return;
2689+
}
26872690
DartType type = node.type!;
26882691
if (type is FunctionType && type.typeFormals.isNotEmpty) {
26892692
_errorReporter.reportErrorForNode(
@@ -4915,6 +4918,8 @@ class ErrorVerifier extends RecursiveAstVisitor<void> {
49154918
mixinElement,
49164919
mixinSupertypeConstraints,
49174920
matchingInterfaceTypes,
4921+
genericMetadataIsEnabled: _currentLibrary.featureSet
4922+
.isEnabled(Feature.generic_metadata),
49184923
);
49194924
if (inferredTypeArguments == null) {
49204925
_errorReporter.reportErrorForToken(

pkg/analyzer/lib/src/generated/resolver.dart

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -333,10 +333,11 @@ class ResolverVisitor extends ScopedVisitor {
333333
extensionResolver = ExtensionMemberResolver(this);
334334
typePropertyResolver = TypePropertyResolver(this);
335335
inferenceHelper = InvocationInferenceHelper(
336-
resolver: this,
337-
errorReporter: errorReporter,
338-
typeSystem: typeSystem,
339-
migrationResolutionHooks: migrationResolutionHooks);
336+
resolver: this,
337+
errorReporter: errorReporter,
338+
typeSystem: typeSystem,
339+
migrationResolutionHooks: migrationResolutionHooks,
340+
);
340341
_assignmentExpressionResolver = AssignmentExpressionResolver(
341342
resolver: this,
342343
);

pkg/analyzer/lib/src/summary2/types_builder.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,8 @@ class _MixinInference {
303303
mixinElement,
304304
mixinSupertypeConstraints,
305305
matchingInterfaceTypes,
306+
genericMetadataIsEnabled:
307+
mixinElement.library.featureSet.isEnabled(Feature.generic_metadata),
306308
);
307309
if (inferredTypeArguments != null) {
308310
var inferredMixin = mixinElement.instantiate(

pkg/analyzer/test/src/dart/element/generic_inferrer_test.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -654,6 +654,7 @@ class GenericFunctionInferenceTest extends AbstractTypeSystemNullSafetyTest {
654654
contextReturnType: returnType,
655655
errorReporter: reporter,
656656
errorNode: astFactory.nullLiteral(KeywordToken(Keyword.NULL, 0)),
657+
genericMetadataIsEnabled: true,
657658
);
658659

659660
if (expectError) {

0 commit comments

Comments
 (0)