@@ -5987,6 +5987,7 @@ ConstraintSystem::simplifyApplicableFnConstraint(
5987
5987
Type type2,
5988
5988
TypeMatchOptions flags,
5989
5989
ConstraintLocatorBuilder locator) {
5990
+ auto &ctx = getASTContext ();
5990
5991
5991
5992
// By construction, the left hand side is a type that looks like the
5992
5993
// following: $T1 -> $T2.
@@ -6011,6 +6012,15 @@ ConstraintSystem::simplifyApplicableFnConstraint(
6011
6012
}
6012
6013
}
6013
6014
6015
+ // Before stripping lvalue-ness and optional types, save original type for
6016
+ // handling `func callAsFunction` and `@dynamicCallable` applications.
6017
+ // This supports the following cases:
6018
+ // - Generating constraints for `mutating func callAsFunction`. The nominal
6019
+ // type (`type2`) should be an lvalue type.
6020
+ // - Extending `Optional` itself with `func callAsFunction` or
6021
+ // `@dynamicCallable` functionality. Optional types are stripped below if
6022
+ // `shouldAttemptFixes()` is true.
6023
+ auto *origType2 = type2->getDesugaredType ();
6014
6024
// Drill down to the concrete type on the right hand side.
6015
6025
type2 = getFixedTypeRecursive (type2, flags, /* wantRValue=*/ true );
6016
6026
auto desugar2 = type2->getDesugaredType ();
@@ -6080,10 +6090,33 @@ ConstraintSystem::simplifyApplicableFnConstraint(
6080
6090
ConstraintLocatorBuilder outerLocator =
6081
6091
getConstraintLocator (anchor, parts, locator.getSummaryFlags ());
6082
6092
6083
- // Before stripping optional types, save original type for handling
6084
- // @dynamicCallable applications. This supports the fringe case where
6085
- // `Optional` itself is extended with @dynamicCallable functionality.
6086
- auto origType2 = desugar2;
6093
+ // Handle applications of types with `callAsFunction` methods.
6094
+ // Do this before stripping optional types below, when `shouldAttemptFixes()`
6095
+ // is true.
6096
+ auto hasCallAsFunctionMethods =
6097
+ desugar2->mayHaveMembers () &&
6098
+ llvm::any_of (lookupMember (desugar2, DeclName (ctx.Id_callAsFunction )),
6099
+ [](LookupResultEntry entry) {
6100
+ return isa<FuncDecl>(entry.getValueDecl ());
6101
+ });
6102
+ if (hasCallAsFunctionMethods) {
6103
+ auto memberLoc = getConstraintLocator (
6104
+ outerLocator.withPathElement (ConstraintLocator::Member));
6105
+ // Add a `callAsFunction` member constraint, binding the member type to a
6106
+ // type variable.
6107
+ auto memberTy = createTypeVariable (memberLoc, TVO_CanBindToLValue |
6108
+ TVO_CanBindToNoEscape |
6109
+ TVO_CanBindToInOut);
6110
+ addValueMemberConstraint (origType2, DeclName (ctx.Id_callAsFunction ),
6111
+ memberTy, DC, FunctionRefKind::SingleApply,
6112
+ /* outerAlternatives*/ {}, locator);
6113
+ // Add new applicable function constraint based on the member type
6114
+ // variable.
6115
+ addConstraint (ConstraintKind::ApplicableFunction, func1, memberTy,
6116
+ locator);
6117
+ return SolutionKind::Solved;
6118
+ }
6119
+
6087
6120
unsigned unwrapCount = 0 ;
6088
6121
if (shouldAttemptFixes ()) {
6089
6122
// If we have an optional type, try forcing it to see if that
@@ -6165,60 +6198,6 @@ ConstraintSystem::simplifyApplicableFnConstraint(
6165
6198
return simplified;
6166
6199
}
6167
6200
6168
- // Handle applications of types with `callAsFunction` methods.
6169
- if (desugar2->mayHaveMembers ()) {
6170
- auto &ctx = getASTContext ();
6171
- // Get all `callAsFunction` methods of the nominal type.
6172
- // Note: Consider caching `callAsFunction` methods.
6173
- SmallVector<FuncDecl *, 4 > callMethods;
6174
- auto candidates = lookupMember (desugar2, DeclName (ctx.Id_callAsFunction ));
6175
- for (auto entry : candidates) {
6176
- auto callMethod = dyn_cast<FuncDecl>(entry.getValueDecl ());
6177
- if (!callMethod)
6178
- continue ;
6179
- callMethods.push_back (callMethod);
6180
- }
6181
-
6182
- // Handle `callAsFunction` methods calls.
6183
- if (!callMethods.empty ()) {
6184
- // Create a type variable for the `callAsFunction` method.
6185
- auto loc = getConstraintLocator (locator);
6186
- auto tv = createTypeVariable (loc, TVO_CanBindToLValue);
6187
-
6188
- // Record the `callAsFunction` method overload set.
6189
- SmallVector<OverloadChoice, 4 > choices;
6190
- for (auto candidate : callMethods) {
6191
- TC.validateDecl (candidate);
6192
- if (candidate->isInvalid ()) continue ;
6193
- choices.push_back (
6194
- OverloadChoice (type2, candidate, FunctionRefKind::SingleApply));
6195
- }
6196
- if (choices.empty ()) return SolutionKind::Error;
6197
- addOverloadSet (tv, choices, DC, loc);
6198
-
6199
- // Create type variables for each parameter type.
6200
- SmallVector<AnyFunctionType::Param, 4 > tvParams;
6201
- for (unsigned i : range (func1->getNumParams ())) {
6202
- auto param = func1->getParams ()[i];
6203
- auto paramType = param.getPlainType ();
6204
-
6205
- auto *tvParam = createTypeVariable (loc, TVO_CanBindToNoEscape);
6206
- auto locatorBuilder =
6207
- locator.withPathElement (LocatorPathElt::getTupleElement (i));
6208
- addConstraint (ConstraintKind::ArgumentConversion, paramType,
6209
- tvParam, locatorBuilder);
6210
- tvParams.push_back (AnyFunctionType::Param (
6211
- tvParam, Identifier (), param.getParameterFlags ()));
6212
- }
6213
- // Create target function type and an applicable function constraint.
6214
- AnyFunctionType *funcType =
6215
- FunctionType::get (tvParams, func1->getResult ());
6216
- addConstraint (ConstraintKind::ApplicableFunction, funcType, tv, locator);
6217
-
6218
- return SolutionKind::Solved;
6219
- }
6220
- }
6221
-
6222
6201
// Handle applications of @dynamicCallable types.
6223
6202
return simplifyDynamicCallableApplicableFnConstraint (type1, origType2,
6224
6203
subflags, locator);
@@ -6359,6 +6338,13 @@ getDynamicCallableMethods(Type type, ConstraintSystem &CS,
6359
6338
return result;
6360
6339
}
6361
6340
6341
+ // TODO: Refactor/simplify this function.
6342
+ // - It should perform less duplicate work with its caller
6343
+ // `ConstraintSystem::simplifyApplicableFnConstraint`.
6344
+ // - It should generate a member constraint instead of manually forming an
6345
+ // overload set for `func dynamicallyCall` candidates.
6346
+ // - It should support `mutating func dynamicallyCall`. This should fall out of
6347
+ // using member constraints with an lvalue base type.
6362
6348
ConstraintSystem::SolutionKind
6363
6349
ConstraintSystem::simplifyDynamicCallableApplicableFnConstraint (
6364
6350
Type type1,
0 commit comments