Skip to content

Commit d1cbc2b

Browse files
authored
Merge pull request #60194 from hamishknight/dynamo
2 parents c2f5d57 + 09744f8 commit d1cbc2b

16 files changed

+247
-309
lines changed

include/swift/AST/NameLookup.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -498,9 +498,16 @@ namespace namelookup {
498498
/// Add semantic members to \p type before attempting a semantic lookup.
499499
void installSemanticMembersIfNeeded(Type type, DeclNameRef name);
500500

501+
/// Extracts directly referenced nominal type decls from a given type, asserting
502+
/// if the type does not contain any references to a nominal.
501503
void extractDirectlyReferencedNominalTypes(
502504
Type type, SmallVectorImpl<NominalTypeDecl *> &decls);
503505

506+
/// Extracts directly referenced nominal type decls from a given type, or leaves
507+
/// the vector empty if the type does not contain any references to a nominal.
508+
void tryExtractDirectlyReferencedNominalTypes(
509+
Type type, SmallVectorImpl<NominalTypeDecl *> &decls);
510+
504511
/// Once name lookup has gathered a set of results, perform any necessary
505512
/// steps to prune the result set before returning it to the caller.
506513
void pruneLookupResultSet(const DeclContext *dc, NLOptions options,

include/swift/AST/NameLookupRequests.h

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -806,6 +806,62 @@ class LookupPrecedenceGroupRequest
806806
bool isCached() const { return true; }
807807
};
808808

809+
/// Computes whether this is a decl that supports being called through the
810+
/// implementation of a \c callAsFunction method.
811+
class IsCallAsFunctionNominalRequest
812+
: public SimpleRequest<IsCallAsFunctionNominalRequest,
813+
bool(NominalTypeDecl *, DeclContext *),
814+
RequestFlags::Cached> {
815+
public:
816+
using SimpleRequest::SimpleRequest;
817+
818+
private:
819+
friend SimpleRequest;
820+
821+
// Evaluation.
822+
bool evaluate(Evaluator &evaluator, NominalTypeDecl *decl,
823+
DeclContext *dc) const;
824+
825+
public:
826+
bool isCached() const { return true; }
827+
};
828+
829+
/// Computes whether the specified decl or a super-class/super-protocol has the
830+
/// @dynamicMemberLookup attribute on it.
831+
class HasDynamicMemberLookupAttributeRequest
832+
: public SimpleRequest<HasDynamicMemberLookupAttributeRequest,
833+
bool(NominalTypeDecl *), RequestFlags::Cached> {
834+
public:
835+
using SimpleRequest::SimpleRequest;
836+
837+
private:
838+
friend SimpleRequest;
839+
840+
// Evaluation.
841+
bool evaluate(Evaluator &evaluator, NominalTypeDecl *decl) const;
842+
843+
public:
844+
bool isCached() const { return true; }
845+
};
846+
847+
/// Computes whether the specified decl or a super-class/super-protocol has the
848+
/// @dynamicCallable attribute on it.
849+
class HasDynamicCallableAttributeRequest
850+
: public SimpleRequest<HasDynamicCallableAttributeRequest,
851+
bool(NominalTypeDecl *), RequestFlags::Cached> {
852+
public:
853+
using SimpleRequest::SimpleRequest;
854+
855+
private:
856+
friend SimpleRequest;
857+
858+
// Evaluation.
859+
bool evaluate(Evaluator &evaluator, NominalTypeDecl *decl) const;
860+
861+
public:
862+
bool isCached() const { return true; }
863+
};
864+
809865
#define SWIFT_TYPEID_ZONE NameLookup
810866
#define SWIFT_TYPEID_HEADER "swift/AST/NameLookupTypeIDZone.def"
811867
#include "swift/Basic/DefineTypeIDZone.h"

include/swift/AST/NameLookupTypeIDZone.def

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,3 +98,9 @@ SWIFT_REQUEST(NameLookup, LookupPostfixOperatorRequest,
9898
SWIFT_REQUEST(NameLookup, LookupPrecedenceGroupRequest,
9999
TinyPtrVector<PrecedenceGroupDecl *>(OperatorLookupDescriptor),
100100
Cached, NoLocationInfo)
101+
SWIFT_REQUEST(NameLookup, IsCallAsFunctionNominalRequest,
102+
bool(NominalTypeDecl *, DeclContext *), Cached, NoLocationInfo)
103+
SWIFT_REQUEST(NameLookup, HasDynamicMemberLookupAttributeRequest,
104+
bool(NominalTypeDecl *), Cached, NoLocationInfo)
105+
SWIFT_REQUEST(NameLookup, HasDynamicCallableAttributeRequest,
106+
bool(NominalTypeDecl *), Cached, NoLocationInfo)

include/swift/AST/TypeCheckRequests.h

Lines changed: 0 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -2792,25 +2792,6 @@ class CallerSideDefaultArgExprRequest
27922792
void cacheResult(Expr *expr) const;
27932793
};
27942794

2795-
/// Computes whether this is a type that supports being called through the
2796-
/// implementation of a \c callAsFunction method.
2797-
class IsCallableNominalTypeRequest
2798-
: public SimpleRequest<IsCallableNominalTypeRequest,
2799-
bool(CanType, DeclContext *), RequestFlags::Cached> {
2800-
public:
2801-
using SimpleRequest::SimpleRequest;
2802-
2803-
private:
2804-
friend SimpleRequest;
2805-
2806-
// Evaluation.
2807-
bool evaluate(Evaluator &evaluator, CanType ty, DeclContext *dc) const;
2808-
2809-
public:
2810-
// Cached.
2811-
bool isCached() const { return true; }
2812-
};
2813-
28142795
class DynamicallyReplacedDeclRequest
28152796
: public SimpleRequest<DynamicallyReplacedDeclRequest,
28162797
ValueDecl *(ValueDecl *), RequestFlags::Cached> {
@@ -2892,52 +2873,6 @@ class TypeCheckSourceFileRequest
28922873
readDependencySource(const evaluator::DependencyRecorder &) const;
28932874
};
28942875

2895-
/// Computes whether the specified type or a super-class/super-protocol has the
2896-
/// @dynamicMemberLookup attribute on it.
2897-
class HasDynamicMemberLookupAttributeRequest
2898-
: public SimpleRequest<HasDynamicMemberLookupAttributeRequest,
2899-
bool(CanType), RequestFlags::Cached> {
2900-
public:
2901-
using SimpleRequest::SimpleRequest;
2902-
2903-
private:
2904-
friend SimpleRequest;
2905-
2906-
// Evaluation.
2907-
bool evaluate(Evaluator &evaluator, CanType ty) const;
2908-
2909-
public:
2910-
bool isCached() const {
2911-
// Don't cache types containing type variables, as they must not outlive
2912-
// the constraint system that created them.
2913-
auto ty = std::get<0>(getStorage());
2914-
return !ty->hasTypeVariable();
2915-
}
2916-
};
2917-
2918-
/// Computes whether the specified type or a super-class/super-protocol has the
2919-
/// @dynamicCallable attribute on it.
2920-
class HasDynamicCallableAttributeRequest
2921-
: public SimpleRequest<HasDynamicCallableAttributeRequest,
2922-
bool(CanType), RequestFlags::Cached> {
2923-
public:
2924-
using SimpleRequest::SimpleRequest;
2925-
2926-
private:
2927-
friend SimpleRequest;
2928-
2929-
// Evaluation.
2930-
bool evaluate(Evaluator &evaluator, CanType ty) const;
2931-
2932-
public:
2933-
bool isCached() const {
2934-
// Don't cache types containing type variables, as they must not outlive
2935-
// the constraint system that created them.
2936-
auto ty = std::get<0>(getStorage());
2937-
return !ty->hasTypeVariable();
2938-
}
2939-
};
2940-
29412876
/// Determines the type of a given pattern.
29422877
///
29432878
/// Note that this returns the "raw" pattern type, which can involve

include/swift/AST/TypeCheckerTypeIDZone.def

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -169,10 +169,6 @@ SWIFT_REQUEST(TypeChecker, HasCircularInheritedProtocolsRequest,
169169
bool(ProtocolDecl *), Cached, NoLocationInfo)
170170
SWIFT_REQUEST(TypeChecker, HasCircularRawValueRequest,
171171
bool(EnumDecl *), Cached, NoLocationInfo)
172-
SWIFT_REQUEST(TypeChecker, HasDynamicMemberLookupAttributeRequest,
173-
bool(CanType), Cached, NoLocationInfo)
174-
SWIFT_REQUEST(TypeChecker, HasDynamicCallableAttributeRequest,
175-
bool(CanType), Cached, NoLocationInfo)
176172
SWIFT_REQUEST(TypeChecker, HasImplementationOnlyImportsRequest,
177173
bool(SourceFile *), Cached, NoLocationInfo)
178174
SWIFT_REQUEST(TypeChecker, ModuleLibraryLevelRequest,
@@ -201,8 +197,6 @@ SWIFT_REQUEST(TypeChecker, InterfaceTypeRequest,
201197
Type(ValueDecl *), SeparatelyCached, NoLocationInfo)
202198
SWIFT_REQUEST(TypeChecker, IsAccessorTransparentRequest, bool(AccessorDecl *),
203199
SeparatelyCached, NoLocationInfo)
204-
SWIFT_REQUEST(TypeChecker, IsCallableNominalTypeRequest,
205-
bool(CanType, DeclContext *), Cached, NoLocationInfo)
206200
SWIFT_REQUEST(TypeChecker, IsDynamicRequest, bool(ValueDecl *),
207201
SeparatelyCached, NoLocationInfo)
208202
SWIFT_REQUEST(TypeChecker, IsFinalRequest, bool(ValueDecl *), SeparatelyCached,

include/swift/AST/Types.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -921,7 +921,7 @@ class alignas(1 << TypeAlignInBits) TypeBase
921921
/// Checks whether this is a type that supports being called through the
922922
/// implementation of a \c callAsFunction method. Note that this does not
923923
/// check access control.
924-
bool isCallableNominalType(DeclContext *dc);
924+
bool isCallAsFunctionType(DeclContext *dc);
925925

926926
/// Return true if the specified type or a super-class/super-protocol has the
927927
/// @dynamicMemberLookup attribute on it.

include/swift/Sema/ConstraintSystem.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1717,6 +1717,13 @@ struct DynamicCallableMethods {
17171717
keywordArgumentsMethods.insert(method);
17181718
}
17191719

1720+
void addMethods(const DynamicCallableMethods &other) {
1721+
argumentsMethods.insert(other.argumentsMethods.begin(),
1722+
other.argumentsMethods.end());
1723+
keywordArgumentsMethods.insert(other.keywordArgumentsMethods.begin(),
1724+
other.keywordArgumentsMethods.end());
1725+
}
1726+
17201727
/// Returns true if type defines either of the @dynamicCallable
17211728
/// required methods. Returns false iff type does not satisfy @dynamicCallable
17221729
/// requirements.
@@ -2827,7 +2834,8 @@ class ConstraintSystem {
28272834

28282835
/// A cache that stores the @dynamicCallable required methods implemented by
28292836
/// types.
2830-
llvm::DenseMap<CanType, DynamicCallableMethods> DynamicCallableCache;
2837+
llvm::DenseMap<NominalTypeDecl *, DynamicCallableMethods>
2838+
DynamicCallableCache;
28312839

28322840
/// A cache of implicitly generated dot-member expressions used as roots
28332841
/// for some `.callAsFunction` calls. The key here is "base" locator for

lib/AST/NameLookup.cpp

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1900,6 +1900,12 @@ void namelookup::extractDirectlyReferencedNominalTypes(
19001900
llvm_unreachable("Not a type containing nominal types?");
19011901
}
19021902

1903+
void namelookup::tryExtractDirectlyReferencedNominalTypes(
1904+
Type type, SmallVectorImpl<NominalTypeDecl *> &decls) {
1905+
if (!type->is<ModuleType>() && type->mayHaveMembers())
1906+
namelookup::extractDirectlyReferencedNominalTypes(type, decls);
1907+
}
1908+
19031909
bool DeclContext::lookupQualified(Type type,
19041910
DeclNameRef member,
19051911
NLOptions options,
@@ -3048,6 +3054,102 @@ swift::getDirectlyInheritedNominalTypeDecls(
30483054
return result;
30493055
}
30503056

3057+
bool IsCallAsFunctionNominalRequest::evaluate(Evaluator &evaluator,
3058+
NominalTypeDecl *decl,
3059+
DeclContext *dc) const {
3060+
auto &ctx = dc->getASTContext();
3061+
3062+
// Do a qualified lookup for `callAsFunction`. We want to ignore access, as
3063+
// that will be checked when we actually try to solve with a `callAsFunction`
3064+
// member access.
3065+
SmallVector<ValueDecl *, 4> results;
3066+
auto opts = NL_QualifiedDefault | NL_ProtocolMembers | NL_IgnoreAccessControl;
3067+
dc->lookupQualified(decl, DeclNameRef(ctx.Id_callAsFunction), opts, results);
3068+
3069+
return llvm::any_of(results, [](ValueDecl *decl) -> bool {
3070+
if (auto *fd = dyn_cast<FuncDecl>(decl))
3071+
return fd->isCallAsFunctionMethod();
3072+
return false;
3073+
});
3074+
}
3075+
3076+
bool TypeBase::isCallAsFunctionType(DeclContext *dc) {
3077+
// We can perform the lookup at module scope to allow us to better cache the
3078+
// result across different contexts. Given we'll be doing a qualified lookup,
3079+
// this shouldn't make a difference.
3080+
dc = dc->getModuleScopeContext();
3081+
3082+
// Note this excludes AnyObject.
3083+
SmallVector<NominalTypeDecl *, 4> decls;
3084+
tryExtractDirectlyReferencedNominalTypes(this, decls);
3085+
3086+
auto &ctx = dc->getASTContext();
3087+
return llvm::any_of(decls, [&](auto *decl) {
3088+
IsCallAsFunctionNominalRequest req(decl, dc);
3089+
return evaluateOrDefault(ctx.evaluator, req, false);
3090+
});
3091+
}
3092+
3093+
template <class DynamicAttribute, class Req>
3094+
static bool checkForDynamicAttribute(Evaluator &eval, NominalTypeDecl *decl) {
3095+
// If this type has the attribute on it, then yes!
3096+
if (decl->getAttrs().hasAttribute<DynamicAttribute>())
3097+
return true;
3098+
3099+
auto hasAttribute = [&](NominalTypeDecl *decl) -> bool {
3100+
return evaluateOrDefault(eval, Req{decl}, false);
3101+
};
3102+
3103+
// Check the protocols the type conforms to.
3104+
for (auto *proto : decl->getAllProtocols()) {
3105+
if (hasAttribute(proto))
3106+
return true;
3107+
}
3108+
3109+
// Check the superclass if present.
3110+
if (auto *classDecl = dyn_cast<ClassDecl>(decl)) {
3111+
if (auto *superclass = classDecl->getSuperclassDecl()) {
3112+
if (hasAttribute(superclass))
3113+
return true;
3114+
}
3115+
}
3116+
return false;
3117+
}
3118+
3119+
bool HasDynamicMemberLookupAttributeRequest::evaluate(
3120+
Evaluator &eval, NominalTypeDecl *decl) const {
3121+
using Req = HasDynamicMemberLookupAttributeRequest;
3122+
return checkForDynamicAttribute<DynamicMemberLookupAttr, Req>(eval, decl);
3123+
}
3124+
3125+
bool TypeBase::hasDynamicMemberLookupAttribute() {
3126+
SmallVector<NominalTypeDecl *, 4> decls;
3127+
tryExtractDirectlyReferencedNominalTypes(this, decls);
3128+
3129+
auto &ctx = getASTContext();
3130+
return llvm::any_of(decls, [&](auto *decl) {
3131+
HasDynamicMemberLookupAttributeRequest req(decl);
3132+
return evaluateOrDefault(ctx.evaluator, req, false);
3133+
});
3134+
}
3135+
3136+
bool HasDynamicCallableAttributeRequest::evaluate(Evaluator &eval,
3137+
NominalTypeDecl *decl) const {
3138+
using Req = HasDynamicCallableAttributeRequest;
3139+
return checkForDynamicAttribute<DynamicCallableAttr, Req>(eval, decl);
3140+
}
3141+
3142+
bool TypeBase::hasDynamicCallableAttribute() {
3143+
SmallVector<NominalTypeDecl *, 4> decls;
3144+
tryExtractDirectlyReferencedNominalTypes(this, decls);
3145+
3146+
auto &ctx = getASTContext();
3147+
return llvm::any_of(decls, [&](auto *decl) {
3148+
HasDynamicCallableAttributeRequest req(decl);
3149+
return evaluateOrDefault(ctx.evaluator, req, false);
3150+
});
3151+
}
3152+
30513153
void FindLocalVal::checkPattern(const Pattern *Pat, DeclVisibilityKind Reason) {
30523154
Pat->forEachVariable([&](VarDecl *VD) { checkValueDecl(VD, Reason); });
30533155
}

lib/AST/Type.cpp

Lines changed: 0 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -2006,41 +2006,6 @@ bool TypeBase::satisfiesClassConstraint() {
20062006
return mayHaveSuperclass() || isObjCExistentialType();
20072007
}
20082008

2009-
bool TypeBase::isCallableNominalType(DeclContext *dc) {
2010-
// Don't allow callAsFunction to be used with dynamic lookup.
2011-
if (isAnyObject())
2012-
return false;
2013-
2014-
// If the type cannot have members, we're done.
2015-
if (!mayHaveMembers())
2016-
return false;
2017-
2018-
auto canTy = getCanonicalType();
2019-
auto &ctx = canTy->getASTContext();
2020-
return evaluateOrDefault(ctx.evaluator,
2021-
IsCallableNominalTypeRequest{canTy, dc}, false);
2022-
}
2023-
2024-
bool TypeBase::hasDynamicMemberLookupAttribute() {
2025-
if (!mayHaveMembers())
2026-
return false;
2027-
2028-
auto canTy = getCanonicalType();
2029-
auto &ctx = canTy->getASTContext();
2030-
return evaluateOrDefault(
2031-
ctx.evaluator, HasDynamicMemberLookupAttributeRequest{canTy}, false);
2032-
}
2033-
2034-
bool TypeBase::hasDynamicCallableAttribute() {
2035-
if (!mayHaveMembers())
2036-
return false;
2037-
2038-
auto canTy = getCanonicalType();
2039-
auto &ctx = canTy->getASTContext();
2040-
return evaluateOrDefault(
2041-
ctx.evaluator, HasDynamicCallableAttributeRequest{canTy}, false);
2042-
}
2043-
20442009
Type TypeBase::getSuperclass(bool useArchetypes) {
20452010
auto *nominalDecl = getAnyNominal();
20462011
auto *classDecl = dyn_cast_or_null<ClassDecl>(nominalDecl);

lib/Sema/CSApply.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7749,7 +7749,7 @@ Expr *ExprRewriter::finishApply(ApplyExpr *apply, Type openedType,
77497749

77507750
// If this is an implicit call to a `callAsFunction` method, build the
77517751
// appropriate member reference.
7752-
if (cs.getType(fn)->getRValueType()->isCallableNominalType(dc)) {
7752+
if (cs.getType(fn)->getRValueType()->isCallAsFunctionType(dc)) {
77537753
fn = buildCallAsFunctionMethodRef(*this, apply, *overload, calleeLoc);
77547754
if (!fn)
77557755
return nullptr;

lib/Sema/CSDiagnostics.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ Expr *FailureDiagnostic::getBaseExprFor(const Expr *anchor) const {
147147
return MRE->getBase();
148148
else if (auto *call = dyn_cast<CallExpr>(anchor)) {
149149
auto fnType = getType(call->getFn());
150-
if (fnType->isCallableNominalType(getDC())) {
150+
if (fnType->isCallAsFunctionType(getDC())) {
151151
return call->getFn();
152152
}
153153
}

0 commit comments

Comments
 (0)