Skip to content

Commit 778e130

Browse files
committed
[Sema] Add TypeBase::isCallableNominalType
This checks whether a type supports being called via callAsFunction. A request is used in order to cache the result of this query.
1 parent 53e2b5c commit 778e130

File tree

7 files changed

+58
-14
lines changed

7 files changed

+58
-14
lines changed

include/swift/AST/TypeCheckRequests.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1910,6 +1910,26 @@ class CallerSideDefaultArgExprRequest
19101910
void cacheResult(Expr *expr) const;
19111911
};
19121912

1913+
/// Computes whether this is a type that supports being called through the
1914+
/// implementation of a \c callAsFunction method.
1915+
class IsCallableNominalTypeRequest
1916+
: public SimpleRequest<IsCallableNominalTypeRequest,
1917+
bool(CanType, DeclContext *), CacheKind::Cached> {
1918+
public:
1919+
using SimpleRequest::SimpleRequest;
1920+
1921+
private:
1922+
friend SimpleRequest;
1923+
1924+
// Evaluation.
1925+
llvm::Expected<bool> evaluate(Evaluator &evaluator, CanType ty,
1926+
DeclContext *dc) const;
1927+
1928+
public:
1929+
// Cached.
1930+
bool isCached() const { return true; }
1931+
};
1932+
19131933
// Allow AnyValue to compare two Type values, even though Type doesn't
19141934
// support ==.
19151935
template<>

include/swift/AST/TypeCheckerTypeIDZone.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,8 @@ SWIFT_REQUEST(TypeChecker, InterfaceTypeRequest,
8888
Type(ValueDecl *), SeparatelyCached, NoLocationInfo)
8989
SWIFT_REQUEST(TypeChecker, IsAccessorTransparentRequest, bool(AccessorDecl *),
9090
SeparatelyCached, NoLocationInfo)
91+
SWIFT_REQUEST(TypeChecker, IsCallableNominalTypeRequest,
92+
bool(CanType, DeclContext *), Cached, NoLocationInfo)
9193
SWIFT_REQUEST(TypeChecker, IsDynamicRequest, bool(ValueDecl *),
9294
SeparatelyCached, NoLocationInfo)
9395
SWIFT_REQUEST(TypeChecker, IsFinalRequest, bool(ValueDecl *), SeparatelyCached,

include/swift/AST/Types.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -818,6 +818,10 @@ class alignas(1 << TypeAlignInBits) TypeBase {
818818
getAnyNominal());
819819
}
820820

821+
/// Checks whether this is a type that supports being called through the
822+
/// implementation of a \c callAsFunction method.
823+
bool isCallableNominalType(DeclContext *dc);
824+
821825
/// Retrieve the superclass of this type.
822826
///
823827
/// \param useArchetypes Whether to use context archetypes for outer generic

lib/AST/Type.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1480,6 +1480,17 @@ bool TypeBase::satisfiesClassConstraint() {
14801480
return mayHaveSuperclass() || isObjCExistentialType();
14811481
}
14821482

1483+
bool TypeBase::isCallableNominalType(DeclContext *dc) {
1484+
// If the type cannot have members, we're done.
1485+
if (!mayHaveMembers())
1486+
return false;
1487+
1488+
auto canTy = getCanonicalType();
1489+
auto &ctx = canTy->getASTContext();
1490+
return evaluateOrDefault(ctx.evaluator,
1491+
IsCallableNominalTypeRequest{canTy, dc}, false);
1492+
}
1493+
14831494
Type TypeBase::getSuperclass(bool useArchetypes) {
14841495
auto *nominalDecl = getAnyNominal();
14851496
auto *classDecl = dyn_cast_or_null<ClassDecl>(nominalDecl);

lib/Sema/CSDiag.cpp

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2616,13 +2616,7 @@ bool FailureDiagnosis::visitApplyExpr(ApplyExpr *callExpr) {
26162616
auto isDynamicCallable =
26172617
CS.DynamicCallableCache[fnType->getCanonicalType()].isValid();
26182618

2619-
// Note: Consider caching `hasCallAsFunctionMethods` in `NominalTypeDecl`.
2620-
auto *nominal = fnType->getAnyNominal();
2621-
auto hasCallAsFunctionMethods = nominal &&
2622-
llvm::any_of(nominal->getMembers(), [](Decl *member) {
2623-
auto funcDecl = dyn_cast<FuncDecl>(member);
2624-
return funcDecl && funcDecl->isCallAsFunctionMethod();
2625-
});
2619+
auto hasCallAsFunctionMethods = fnType->isCallableNominalType(CS.DC);
26262620

26272621
// Diagnose specific @dynamicCallable errors.
26282622
if (isDynamicCallable) {

lib/Sema/CSSimplify.cpp

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7334,13 +7334,7 @@ ConstraintSystem::simplifyApplicableFnConstraint(
73347334
// Handle applications of types with `callAsFunction` methods.
73357335
// Do this before stripping optional types below, when `shouldAttemptFixes()`
73367336
// is true.
7337-
auto hasCallAsFunctionMethods =
7338-
desugar2->mayHaveMembers() &&
7339-
llvm::any_of(lookupMember(desugar2, DeclName(ctx.Id_callAsFunction)),
7340-
[](LookupResultEntry entry) {
7341-
return isa<FuncDecl>(entry.getValueDecl());
7342-
});
7343-
if (hasCallAsFunctionMethods) {
7337+
if (desugar2->isCallableNominalType(DC)) {
73447338
auto memberLoc = getConstraintLocator(
73457339
outerLocator.withPathElement(ConstraintLocator::Member));
73467340
// Add a `callAsFunction` member constraint, binding the member type to a

lib/Sema/TypeCheckConstraints.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
#include "swift/AST/ProtocolConformance.h"
3737
#include "swift/AST/SubstitutionMap.h"
3838
#include "swift/AST/TypeCheckerDebugConsumer.h"
39+
#include "swift/AST/TypeCheckRequests.h"
3940
#include "swift/Basic/Statistic.h"
4041
#include "swift/Parse/Confusables.h"
4142
#include "swift/Parse/Lexer.h"
@@ -4569,3 +4570,21 @@ ForcedCheckedCastExpr *swift::findForcedDowncast(ASTContext &ctx, Expr *expr) {
45694570

45704571
return nullptr;
45714572
}
4573+
4574+
llvm::Expected<bool>
4575+
IsCallableNominalTypeRequest::evaluate(Evaluator &evaluator, CanType ty,
4576+
DeclContext *dc) const {
4577+
auto options = defaultMemberLookupOptions;
4578+
if (isa<AbstractFunctionDecl>(dc))
4579+
options |= NameLookupFlags::KnownPrivate;
4580+
4581+
// Look for a callAsFunction method.
4582+
auto &ctx = ty->getASTContext();
4583+
auto results =
4584+
TypeChecker::lookupMember(dc, ty, ctx.Id_callAsFunction, options);
4585+
return llvm::any_of(results, [](LookupResultEntry entry) -> bool {
4586+
if (auto *fd = dyn_cast<FuncDecl>(entry.getValueDecl()))
4587+
return fd->isCallAsFunctionMethod();
4588+
return false;
4589+
});
4590+
}

0 commit comments

Comments
 (0)