Skip to content

Commit ccf75d6

Browse files
srawlinscommit-bot@chromium.org
authored andcommitted
Revert "Implement Generic Function Instantiation via wrapping node"
This reverts commit 1c8f56f. Reason for revert: This breaks package:collection at ListComparableExtensions.binarySearch, at `comparable ?? compareComparable`: The argument type 'Function' can't be assigned to the parameter type 'intFunction(E, E)'. #argument_type_not_assignable Original change's description: > Implement Generic Function Instantiation via wrapping node > > This is a non-breaking change (when analyzing code at language version > 2.14 and earlier). If constructor-tearoffs is enabled (language version > 2.15), then FunctionReference nodes are inserted, to represent generic > function instantiation. Constant evaluation can then use the > `typeArgumentTypes` to instantiate arbitrary function-typed > expressions. > > If constructor-tearoffs is not enabled, generic function instantiation > continues to take place at a SimpleIdentifier, PrefixedIdentifier, or > PropertyAccess only, with constant evaluation using > SimpleIdentifier.tearOffTypeArgumentTypes. > > Bug: #46020 > Change-Id: Ie370c00c8a2ce7a4791ac9cdb7459a01339a79c1 > Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/217880 > Commit-Queue: Samuel Rawlins <[email protected]> > Reviewed-by: Brian Wilkerson <[email protected]> > Reviewed-by: Konstantin Shcheglov <[email protected]> [email protected],[email protected],[email protected] Change-Id: Ie76cd703e05cbf65fecaa76b72e829f8272b8307 No-Presubmit: true No-Tree-Checks: true No-Try: true Bug: #46020 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/218089 Reviewed-by: Samuel Rawlins <[email protected]> Commit-Queue: Samuel Rawlins <[email protected]>
1 parent e050ab0 commit ccf75d6

14 files changed

+133
-555
lines changed

pkg/analyzer/lib/src/dart/constant/evaluation.dart

+21-62
Original file line numberDiff line numberDiff line change
@@ -682,37 +682,27 @@ class ConstantVisitor extends UnifyingAstVisitor<DartObjectImpl> {
682682
if (functionResult == null) {
683683
return functionResult;
684684
}
685-
686-
// Report an error if any of the _inferred_ type argument types refer to a
687-
// type parameter. If, however, `node.typeArguments` is not `null`, then
688-
// any type parameters contained therein are reported as non-constant in
689-
// [ConstantVerifier].
690-
if (node.typeArguments == null &&
691-
(node.typeArgumentTypes?.any(hasTypeParameterReference) ?? false)) {
692-
_error(node, null);
693-
}
694-
695685
var typeArgumentList = node.typeArguments;
696686
if (typeArgumentList == null) {
697-
return _instantiateFunctionType(node, functionResult);
698-
}
699-
700-
var typeArguments = <DartType>[];
701-
for (var typeArgument in typeArgumentList.arguments) {
702-
var object = typeArgument.accept(this);
703-
if (object == null) {
704-
return null;
705-
}
706-
var typeArgumentType = object.toTypeValue();
707-
if (typeArgumentType == null) {
708-
return null;
687+
return functionResult;
688+
} else {
689+
var typeArguments = <DartType>[];
690+
for (var typeArgument in typeArgumentList.arguments) {
691+
var object = typeArgument.accept(this);
692+
if (object == null) {
693+
return null;
694+
}
695+
var typeArgumentType = object.toTypeValue();
696+
if (typeArgumentType == null) {
697+
return null;
698+
}
699+
// TODO(srawlins): Test type alias types (`typedef i = int`) used as
700+
// type arguments. Possibly change implementation based on
701+
// canonicalization rules.
702+
typeArguments.add(typeArgumentType);
709703
}
710-
// TODO(srawlins): Test type alias types (`typedef i = int`) used as
711-
// type arguments. Possibly change implementation based on
712-
// canonicalization rules.
713-
typeArguments.add(typeArgumentType);
704+
return _dartObjectComputer.typeInstantiate(functionResult, typeArguments);
714705
}
715-
return _dartObjectComputer.typeInstantiate(functionResult, typeArguments);
716706
}
717707

718708
@override
@@ -1010,7 +1000,7 @@ class ConstantVisitor extends UnifyingAstVisitor<DartObjectImpl> {
10101000
DartObjectImpl? visitSimpleIdentifier(SimpleIdentifier node) {
10111001
var value = _lexicalEnvironment?[node.name];
10121002
if (value != null) {
1013-
return _instantiateFunctionTypeForSimpleIdentifier(node, value);
1003+
return _instantiateFunctionType(node, value);
10141004
}
10151005

10161006
return _getConstantValue(node, node);
@@ -1222,8 +1212,6 @@ class ConstantVisitor extends UnifyingAstVisitor<DartObjectImpl> {
12221212
var variableElement =
12231213
element is PropertyAccessorElement ? element.variable : element;
12241214

1225-
// TODO(srawlins): Remove this check when [FunctionReference]s are inserted
1226-
// for generic function instantiation for pre-constructor-references code.
12271215
if (node is SimpleIdentifier &&
12281216
(node.tearOffTypeArgumentTypes?.any(hasTypeParameterReference) ??
12291217
false)) {
@@ -1242,7 +1230,7 @@ class ConstantVisitor extends UnifyingAstVisitor<DartObjectImpl> {
12421230
if (value == null) {
12431231
return value;
12441232
}
1245-
return _instantiateFunctionTypeForSimpleIdentifier(identifier, value);
1233+
return _instantiateFunctionType(identifier, value);
12461234
}
12471235
} else if (variableElement is ConstructorElement) {
12481236
return DartObjectImpl(
@@ -1258,7 +1246,7 @@ class ConstantVisitor extends UnifyingAstVisitor<DartObjectImpl> {
12581246
function.type,
12591247
FunctionState(function),
12601248
);
1261-
return _instantiateFunctionTypeForSimpleIdentifier(identifier, rawType);
1249+
return _instantiateFunctionType(identifier, rawType);
12621250
}
12631251
} else if (variableElement is ClassElement) {
12641252
var type = variableElement.instantiate(
@@ -1317,41 +1305,12 @@ class ConstantVisitor extends UnifyingAstVisitor<DartObjectImpl> {
13171305
return null;
13181306
}
13191307

1320-
/// If the type of [value] is a generic [FunctionType], and [node] has type
1321-
/// argument types, returns [value] type-instantiated with those [node]'s
1322-
/// type argument types, otherwise returns [value].
1323-
DartObjectImpl? _instantiateFunctionType(
1324-
FunctionReference node, DartObjectImpl value) {
1325-
var functionElement = value.toFunctionValue();
1326-
if (functionElement is! ExecutableElement) {
1327-
return value;
1328-
}
1329-
var valueType = functionElement.type;
1330-
if (valueType.typeFormals.isNotEmpty) {
1331-
var typeArgumentTypes = node.typeArgumentTypes;
1332-
if (typeArgumentTypes != null && typeArgumentTypes.isNotEmpty) {
1333-
var instantiatedType =
1334-
functionElement.type.instantiate(typeArgumentTypes);
1335-
var substitution = _substitution;
1336-
if (substitution != null) {
1337-
instantiatedType =
1338-
substitution.substituteType(instantiatedType) as FunctionType;
1339-
}
1340-
return value.typeInstantiate(
1341-
typeSystem, instantiatedType, typeArgumentTypes);
1342-
}
1343-
}
1344-
return value;
1345-
}
1346-
13471308
/// If the type of [value] is a generic [FunctionType], and [node] is a
13481309
/// [SimpleIdentifier] with tear-off type argument types, returns [value]
13491310
/// type-instantiated with those [node]'s tear-off type argument types,
13501311
/// otherwise returns [value].
1351-
DartObjectImpl? _instantiateFunctionTypeForSimpleIdentifier(
1312+
DartObjectImpl? _instantiateFunctionType(
13521313
SimpleIdentifier node, DartObjectImpl value) {
1353-
// TODO(srawlins): When all code uses [FunctionReference]s generated via
1354-
// generic function instantiation, remove this method and all call sites.
13551314
var functionElement = value.toFunctionValue();
13561315
if (functionElement is! ExecutableElement) {
13571316
return value;

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

+3-6
Original file line numberDiff line numberDiff line change
@@ -242,12 +242,9 @@ class AssignmentExpressionResolver {
242242
}
243243

244244
_inferenceHelper.recordStaticType(node, nodeType);
245-
var wrappingExpression =
246-
_resolver.insertImplicitCallReference(rightHandSide);
247-
wrappingExpression =
248-
_resolver.insertGenericFunctionInstantiation(wrappingExpression);
249-
if (wrappingExpression != rightHandSide) {
250-
assignedType = wrappingExpression.typeOrThrow;
245+
var callReference = _resolver.insertImplicitCallReference(rightHandSide);
246+
if (callReference != rightHandSide) {
247+
assignedType = callReference.typeOrThrow;
251248
}
252249

253250
// TODO(scheglov) Remove from ErrorVerifier?

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

+2-9
Original file line numberDiff line numberDiff line change
@@ -83,15 +83,8 @@ class PrefixedIdentifierResolver {
8383
type = result.functionTypeCallType!;
8484
}
8585

86-
if (!_resolver.isConstructorTearoffsEnabled) {
87-
// Only perform a generic function instantiation on a [PrefixedIdentifier]
88-
// in pre-constructor-tearoffs code. In constructor-tearoffs-enabled code,
89-
// generic function instantiation is performed at assignability check
90-
// sites.
91-
// TODO(srawlins): Switch all resolution to use the latter method, in a
92-
// breaking change release.
93-
type = _inferenceHelper.inferTearOff(node, identifier, type);
94-
}
86+
type = _inferenceHelper.inferTearOff(node, identifier, type);
87+
9588
_recordStaticType(identifier, type);
9689
_recordStaticType(node, type);
9790
}

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

+4-11
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import 'package:analyzer/src/dart/element/element.dart';
1212
import 'package:analyzer/src/dart/element/type.dart';
1313
import 'package:analyzer/src/dart/element/type_provider.dart';
1414
import 'package:analyzer/src/dart/resolver/flow_analysis_visitor.dart';
15+
import 'package:analyzer/src/dart/resolver/invocation_inference_helper.dart';
1516
import 'package:analyzer/src/dart/resolver/property_element_resolver.dart';
1617
import 'package:analyzer/src/error/codes.dart';
1718
import 'package:analyzer/src/generated/resolver.dart';
@@ -24,6 +25,8 @@ class SimpleIdentifierResolver {
2425

2526
ErrorReporter get _errorReporter => _resolver.errorReporter;
2627

28+
InvocationInferenceHelper get _inferenceHelper => _resolver.inferenceHelper;
29+
2730
TypeProviderImpl get _typeProvider => _resolver.typeProvider;
2831

2932
void resolve(SimpleIdentifierImpl node) {
@@ -256,17 +259,7 @@ class SimpleIdentifierResolver {
256259
} else {
257260
staticType = DynamicTypeImpl.instance;
258261
}
259-
260-
if (!_resolver.isConstructorTearoffsEnabled) {
261-
// Only perform a generic function instantiation on a [PrefixedIdentifier]
262-
// in pre-constructor-tearoffs code. In constructor-tearoffs-enabled code,
263-
// generic function instantiation is performed at assignability check
264-
// sites.
265-
// TODO(srawlins): Switch all resolution to use the latter method, in a
266-
// breaking change release.
267-
staticType =
268-
_resolver.inferenceHelper.inferTearOff(node, node, staticType);
269-
}
262+
staticType = _inferenceHelper.inferTearOff(node, node, staticType);
270263
_recordStaticType(node, staticType);
271264
}
272265

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

+1-2
Original file line numberDiff line numberDiff line change
@@ -601,8 +601,7 @@ class TypedLiteralResolver {
601601

602602
void _insertImplicitCallReference(CollectionElement? node) {
603603
if (node is Expression) {
604-
var wrappingExpression = _resolver.insertImplicitCallReference(node);
605-
_resolver.insertGenericFunctionInstantiation(wrappingExpression);
604+
_resolver.insertImplicitCallReference(node);
606605
} else if (node is MapLiteralEntry) {
607606
_insertImplicitCallReference(node.key);
608607
_insertImplicitCallReference(node.value);

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

+5-3
Original file line numberDiff line numberDiff line change
@@ -65,15 +65,17 @@ class VariableDeclarationResolver {
6565
_resolver.flowAnalysis.flow?.lateInitializer_end();
6666
}
6767

68-
initializer = _resolver.insertImplicitCallReference(initializer);
69-
initializer = _resolver.insertGenericFunctionInstantiation(initializer);
70-
7168
// Initializers of top-level variables and fields are already included
7269
// into elements during linking.
7370
if (element is ConstLocalVariableElementImpl) {
7471
element.constantInitializer = initializer;
7572
}
7673

74+
var callReference = _resolver.insertImplicitCallReference(initializer);
75+
if (callReference != initializer) {
76+
initializer = callReference;
77+
}
78+
7779
_resolver.checkForInvalidAssignment(node.name, initializer,
7880
whyNotPromoted: whyNotPromoted);
7981
}

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

+6-82
Original file line numberDiff line numberDiff line change
@@ -459,10 +459,8 @@ class ResolverVisitor extends ResolverBase with ErrorDetectionHelpers {
459459
for (var argument in argumentList.arguments) {
460460
if (argument is NamedExpression) {
461461
insertImplicitCallReference(argument.expression);
462-
insertGenericFunctionInstantiation(argument.expression);
463462
} else {
464463
insertImplicitCallReference(argument);
465-
insertGenericFunctionInstantiation(argument);
466464
}
467465
}
468466
var arguments = argumentList.arguments;
@@ -630,62 +628,6 @@ class ResolverVisitor extends ResolverBase with ErrorDetectionHelpers {
630628
return null;
631629
}
632630

633-
/// If generic function instantiation should be performed on `expression`,
634-
/// inserts a [FunctionReference] node which wraps [expression].
635-
///
636-
/// If an [FunctionReference] is inserted, returns it; otherwise, returns
637-
/// [expression].
638-
ExpressionImpl insertGenericFunctionInstantiation(Expression expression) {
639-
expression as ExpressionImpl;
640-
if (!isConstructorTearoffsEnabled) {
641-
// Temporarily, only create [ImplicitCallReference] nodes under the
642-
// 'constructor-tearoffs' feature.
643-
// TODO(srawlins): When we are ready to make a breaking change release to
644-
// the analyzer package, remove this exception.
645-
return expression;
646-
}
647-
648-
var staticType = expression.staticType;
649-
var context = InferenceContext.getContext(expression);
650-
if (context == null ||
651-
staticType is! FunctionType ||
652-
staticType.typeFormals.isEmpty) {
653-
return expression;
654-
}
655-
656-
context = typeSystem.flatten(context);
657-
if (context is! FunctionType || context.typeFormals.isNotEmpty) {
658-
return expression;
659-
}
660-
661-
List<DartType> typeArgumentTypes =
662-
typeSystem.inferFunctionTypeInstantiation(
663-
context,
664-
staticType,
665-
errorReporter: errorReporter,
666-
errorNode: expression,
667-
// If the constructor-tearoffs feature is enabled, then so is
668-
// generic-metadata.
669-
genericMetadataIsEnabled: true,
670-
)!;
671-
if (typeArgumentTypes.isNotEmpty) {
672-
staticType = staticType.instantiate(typeArgumentTypes);
673-
}
674-
675-
var parent = expression.parent;
676-
var genericFunctionInstantiation = astFactory.functionReference(
677-
function: expression,
678-
typeArguments: null,
679-
) as FunctionReferenceImpl;
680-
NodeReplacer.replace(expression, genericFunctionInstantiation,
681-
parent: parent);
682-
683-
genericFunctionInstantiation.typeArgumentTypes = typeArgumentTypes;
684-
genericFunctionInstantiation.staticType = staticType;
685-
686-
return genericFunctionInstantiation;
687-
}
688-
689631
/// If `expression` should be treated as `expression.call`, inserts an
690632
/// [ImplicitCallReferece] node which wraps [expression].
691633
///
@@ -725,7 +667,6 @@ class ResolverVisitor extends ResolverBase with ErrorDetectionHelpers {
725667
typeArgumentTypes = typeSystem.inferFunctionTypeInstantiation(
726668
context,
727669
callMethodType,
728-
errorReporter: errorReporter,
729670
errorNode: expression,
730671
// If the constructor-tearoffs feature is enabled, then so is
731672
// generic-metadata.
@@ -1364,11 +1305,9 @@ class ResolverVisitor extends ResolverBase with ErrorDetectionHelpers {
13641305
node.accept(typeAnalyzer);
13651306
if (fieldElement != null) {
13661307
if (fieldType != null && expression.staticType != null) {
1367-
var wrappingExpression = insertImplicitCallReference(expression);
1368-
wrappingExpression =
1369-
insertGenericFunctionInstantiation(wrappingExpression);
1370-
if (expression != wrappingExpression) {
1371-
checkForInvalidAssignment(node.fieldName, wrappingExpression,
1308+
var callReference = insertImplicitCallReference(expression);
1309+
if (expression != callReference) {
1310+
checkForInvalidAssignment(node.fieldName, callReference,
13721311
whyNotPromoted: whyNotPromoted);
13731312
}
13741313
}
@@ -1406,13 +1345,8 @@ class ResolverVisitor extends ResolverBase with ErrorDetectionHelpers {
14061345
void visitDefaultFormalParameter(DefaultFormalParameter node) {
14071346
InferenceContext.setType(node.defaultValue, node.declaredElement?.type);
14081347
super.visitDefaultFormalParameter(node);
1409-
var defaultValue = node.defaultValue;
1410-
if (defaultValue != null) {
1411-
// TODO(srawlins): Presumably we should also perform implicit tear-off
1412-
// conversion here, e.g. `f(Function p = C()])`.
1413-
insertGenericFunctionInstantiation(defaultValue);
1414-
}
14151348
ParameterElement element = node.declaredElement!;
1349+
14161350
if (element is DefaultParameterElementImpl && node.isOfLocalFunction) {
14171351
element.constantInitializer = node.defaultValue;
14181352
}
@@ -1485,7 +1419,6 @@ class ResolverVisitor extends ResolverBase with ErrorDetectionHelpers {
14851419

14861420
super.visitExpressionFunctionBody(node);
14871421
insertImplicitCallReference(node.expression);
1488-
insertGenericFunctionInstantiation(node.expression);
14891422

14901423
flowAnalysis.flow?.handleExit();
14911424

@@ -1956,15 +1889,7 @@ class ResolverVisitor extends ResolverBase with ErrorDetectionHelpers {
19561889
type = DynamicTypeImpl.instance;
19571890
}
19581891

1959-
if (!isConstructorTearoffsEnabled) {
1960-
// Only perform a generic function instantiation on a [PrefixedIdentifier]
1961-
// in pre-constructor-tearoffs code. In constructor-tearoffs-enabled code,
1962-
// generic function instantiation is performed at assignability check
1963-
// sites.
1964-
// TODO(srawlins): Switch all resolution to use the latter method, in a
1965-
// breaking change release.
1966-
type = inferenceHelper.inferTearOff(node, propertyName, type);
1967-
}
1892+
type = inferenceHelper.inferTearOff(node, propertyName, type);
19681893

19691894
inferenceHelper.recordStaticType(propertyName, type);
19701895
inferenceHelper.recordStaticType(node, type);
@@ -2010,8 +1935,7 @@ class ResolverVisitor extends ResolverBase with ErrorDetectionHelpers {
20101935

20111936
var expression = node.expression;
20121937
if (expression != null) {
2013-
expression = insertImplicitCallReference(expression);
2014-
insertGenericFunctionInstantiation(expression);
1938+
insertImplicitCallReference(expression);
20151939
}
20161940
}
20171941

0 commit comments

Comments
 (0)