@@ -5987,6 +5987,7 @@ ConstraintSystem::simplifyApplicableFnConstraint(
59875987 Type type2,
59885988 TypeMatchOptions flags,
59895989 ConstraintLocatorBuilder locator) {
5990+ auto &ctx = getASTContext ();
59905991
59915992 // By construction, the left hand side is a type that looks like the
59925993 // following: $T1 -> $T2.
@@ -6011,6 +6012,15 @@ ConstraintSystem::simplifyApplicableFnConstraint(
60116012 }
60126013 }
60136014
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 ();
60146024 // Drill down to the concrete type on the right hand side.
60156025 type2 = getFixedTypeRecursive (type2, flags, /* wantRValue=*/ true );
60166026 auto desugar2 = type2->getDesugaredType ();
@@ -6080,10 +6090,33 @@ ConstraintSystem::simplifyApplicableFnConstraint(
60806090 ConstraintLocatorBuilder outerLocator =
60816091 getConstraintLocator (anchor, parts, locator.getSummaryFlags ());
60826092
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+
60876120 unsigned unwrapCount = 0 ;
60886121 if (shouldAttemptFixes ()) {
60896122 // If we have an optional type, try forcing it to see if that
@@ -6165,60 +6198,6 @@ ConstraintSystem::simplifyApplicableFnConstraint(
61656198 return simplified;
61666199 }
61676200
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-
62226201 // Handle applications of @dynamicCallable types.
62236202 return simplifyDynamicCallableApplicableFnConstraint (type1, origType2,
62246203 subflags, locator);
@@ -6359,6 +6338,13 @@ getDynamicCallableMethods(Type type, ConstraintSystem &CS,
63596338 return result;
63606339}
63616340
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.
63626348ConstraintSystem::SolutionKind
63636349ConstraintSystem::simplifyDynamicCallableApplicableFnConstraint (
63646350 Type type1,
0 commit comments