Skip to content

Commit c60b661

Browse files
committed
Add a request for replaced decls
Add DynamicallyReplacedDeclRequest to ValueDecl and plumb the request through to TypeCheckAttr where it replaces TypeChecker::findReplacedDynamicFunction.
1 parent eea5cfb commit c60b661

File tree

7 files changed

+122
-107
lines changed

7 files changed

+122
-107
lines changed

include/swift/AST/Decl.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2389,6 +2389,7 @@ class ValueDecl : public Decl {
23892389
unsigned isIUO : 1;
23902390
} LazySemanticInfo = { };
23912391

2392+
friend class DynamicallyReplacedDeclRequest;
23922393
friend class OverriddenDeclsRequest;
23932394
friend class IsObjCRequest;
23942395
friend class IsFinalRequest;
@@ -2749,6 +2750,11 @@ class ValueDecl : public Decl {
27492750
/// Retrieve the @functionBuilder type attached to this declaration,
27502751
/// if there is one.
27512752
Type getFunctionBuilderType() const;
2753+
2754+
/// If this value or its backing storage is annotated
2755+
/// @_dynamicReplacement(for: ...), compute the original declaration
2756+
/// that this declaration dynamically replaces.
2757+
ValueDecl *getDynamicallyReplacedDecl() const;
27522758
};
27532759

27542760
/// This is a common base class for declarations which declare a type.

include/swift/AST/TypeCheckRequests.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1930,6 +1930,24 @@ class IsCallableNominalTypeRequest
19301930
bool isCached() const { return true; }
19311931
};
19321932

1933+
class DynamicallyReplacedDeclRequest
1934+
: public SimpleRequest<DynamicallyReplacedDeclRequest,
1935+
ValueDecl *(ValueDecl *), CacheKind::Cached> {
1936+
public:
1937+
using SimpleRequest::SimpleRequest;
1938+
1939+
private:
1940+
friend SimpleRequest;
1941+
1942+
// Evaluation.
1943+
llvm::Expected<ValueDecl *> evaluate(Evaluator &evaluator,
1944+
ValueDecl *VD) const;
1945+
1946+
public:
1947+
// Caching.
1948+
bool isCached() const { return true; }
1949+
};
1950+
19331951
// Allow AnyValue to compare two Type values, even though Type doesn't
19341952
// support ==.
19351953
template<>

include/swift/AST/TypeCheckerTypeIDZone.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@ SWIFT_REQUEST(TypeChecker, DefaultDefinitionTypeRequest,
4343
SWIFT_REQUEST(TypeChecker, DefaultTypeRequest,
4444
Type(KnownProtocolKind, const DeclContext *), SeparatelyCached,
4545
NoLocationInfo)
46+
SWIFT_REQUEST(TypeChecker, DynamicallyReplacedDeclRequest,
47+
ValueDecl *(ValueDecl *),
48+
Cached, NoLocationInfo)
4649
SWIFT_REQUEST(TypeChecker, EmittedMembersRequest, DeclRange(ClassDecl *),
4750
SeparatelyCached, NoLocationInfo)
4851
SWIFT_REQUEST(TypeChecker, EnumRawValuesRequest,

lib/AST/Decl.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2833,6 +2833,13 @@ void ValueDecl::setIsDynamic(bool value) {
28332833
LazySemanticInfo.isDynamic = value;
28342834
}
28352835

2836+
ValueDecl *ValueDecl::getDynamicallyReplacedDecl() const {
2837+
return evaluateOrDefault(getASTContext().evaluator,
2838+
DynamicallyReplacedDeclRequest{
2839+
const_cast<ValueDecl *>(this)},
2840+
nullptr);
2841+
}
2842+
28362843
bool ValueDecl::canBeAccessedByDynamicLookup() const {
28372844
if (!hasName())
28382845
return false;

lib/Sema/TypeCheckAttr.cpp

Lines changed: 86 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -2072,10 +2072,10 @@ void AttributeChecker::visitDiscardableResultAttr(DiscardableResultAttr *attr) {
20722072
}
20732073

20742074
/// Lookup the replaced decl in the replacments scope.
2075-
void lookupReplacedDecl(DeclName replacedDeclName,
2076-
const DynamicReplacementAttr *attr,
2077-
const ValueDecl *replacement,
2078-
SmallVectorImpl<ValueDecl *> &results) {
2075+
static void lookupReplacedDecl(DeclName replacedDeclName,
2076+
const DynamicReplacementAttr *attr,
2077+
const ValueDecl *replacement,
2078+
SmallVectorImpl<ValueDecl *> &results) {
20792079
auto *declCtxt = replacement->getDeclContext();
20802080

20812081
// Look at the accessors' storage's context.
@@ -2232,11 +2232,12 @@ findReplacedFunction(DeclName replacedFunctionName,
22322232
// Check for static/instance mismatch.
22332233
if (result->isStatic() != replacement->isStatic())
22342234
continue;
2235-
2235+
2236+
auto resultTy = result->getInterfaceType();
2237+
auto replaceTy = replacement->getInterfaceType();
22362238
TypeMatchOptions matchMode = TypeMatchFlags::AllowABICompatible;
22372239
matchMode |= TypeMatchFlags::AllowCompatibleOpaqueTypeArchetypes;
2238-
if (result->getInterfaceType()->getCanonicalType()->matches(
2239-
replacement->getInterfaceType()->getCanonicalType(), matchMode)) {
2240+
if (resultTy->matches(replaceTy, matchMode)) {
22402241
if (!result->isDynamic()) {
22412242
if (Diags) {
22422243
Diags->diagnose(attr->getLocation(),
@@ -2286,9 +2287,11 @@ findReplacedStorageDecl(DeclName replacedFunctionName,
22862287
// Check for static/instance mismatch.
22872288
if (result->isStatic() != replacement->isStatic())
22882289
continue;
2289-
if (result->getInterfaceType()->getCanonicalType()->matches(
2290-
replacement->getInterfaceType()->getCanonicalType(),
2291-
TypeMatchFlags::AllowABICompatible)) {
2290+
auto resultTy = result->getInterfaceType();
2291+
auto replaceTy = replacement->getInterfaceType();
2292+
TypeMatchOptions matchMode = TypeMatchFlags::AllowABICompatible;
2293+
matchMode |= TypeMatchFlags::AllowCompatibleOpaqueTypeArchetypes;
2294+
if (resultTy->matches(replaceTy, matchMode)) {
22922295
if (!result->isDynamic()) {
22932296
return nullptr;
22942297
}
@@ -2298,113 +2301,48 @@ findReplacedStorageDecl(DeclName replacedFunctionName,
22982301
return nullptr;
22992302
}
23002303

2301-
ValueDecl *TypeChecker::findReplacedDynamicFunction(const ValueDecl *vd) {
2302-
assert(isa<AbstractFunctionDecl>(vd) || isa<AbstractStorageDecl>(vd));
2303-
if (isa<AccessorDecl>(vd))
2304-
return nullptr;
2305-
2306-
auto *attr = vd->getAttrs().getAttribute<DynamicReplacementAttr>();
2307-
if (!attr)
2308-
return nullptr;
2309-
2310-
auto *afd = dyn_cast<AbstractFunctionDecl>(vd);
2311-
if (afd) {
2312-
// When we pass nullptr as the type checker argument attr is truely const.
2313-
return findReplacedFunction(attr->getReplacedFunctionName(), afd,
2314-
const_cast<DynamicReplacementAttr *>(attr),
2315-
nullptr);
2316-
}
2317-
auto *storageDecl = dyn_cast<AbstractStorageDecl>(vd);
2318-
if (!storageDecl)
2319-
return nullptr;
2320-
return findReplacedStorageDecl(attr->getReplacedFunctionName(), storageDecl, attr);
2321-
}
2322-
23232304
void AttributeChecker::visitDynamicReplacementAttr(DynamicReplacementAttr *attr) {
23242305
assert(isa<AbstractFunctionDecl>(D) || isa<AbstractStorageDecl>(D));
2325-
auto *VD = cast<ValueDecl>(D);
2306+
auto *replacement = cast<ValueDecl>(D);
23262307

2327-
if (!isa<ExtensionDecl>(VD->getDeclContext()) &&
2328-
!VD->getDeclContext()->isModuleScopeContext()) {
2308+
if (!isa<ExtensionDecl>(replacement->getDeclContext()) &&
2309+
!replacement->getDeclContext()->isModuleScopeContext()) {
23292310
diagnose(attr->getLocation(), diag::dynamic_replacement_not_in_extension,
2330-
VD->getBaseName());
2311+
replacement->getBaseName());
23312312
attr->setInvalid();
23322313
return;
23332314
}
23342315

2335-
if (VD->isNativeDynamic()) {
2316+
if (replacement->isNativeDynamic()) {
23362317
diagnose(attr->getLocation(), diag::dynamic_replacement_must_not_be_dynamic,
2337-
VD->getBaseName());
2318+
replacement->getBaseName());
23382319
attr->setInvalid();
23392320
return;
23402321
}
23412322

2342-
// Don't process a declaration twice. This will happen to accessor decls after
2343-
// we have processed their var decls.
2344-
if (attr->getReplacedFunction())
2323+
auto *original = replacement->getDynamicallyReplacedDecl();
2324+
if (!original) {
2325+
attr->setInvalid();
23452326
return;
2346-
2347-
SmallVector<AbstractFunctionDecl *, 4> replacements;
2348-
SmallVector<AbstractFunctionDecl *, 4> origs;
2349-
2350-
// Collect the accessor replacement mapping if this is an abstract storage.
2351-
if (auto *var = dyn_cast<AbstractStorageDecl>(VD)) {
2352-
var->visitParsedAccessors([&](AccessorDecl *accessor) {
2353-
if (attr->isInvalid())
2354-
return;
2355-
2356-
auto *orig = findReplacedAccessor(attr->getReplacedFunctionName(),
2357-
accessor, attr, Ctx);
2358-
if (!orig)
2359-
return;
2360-
2361-
origs.push_back(orig);
2362-
replacements.push_back(accessor);
2363-
});
2364-
} else {
2365-
// Otherwise, find the matching function.
2366-
auto *fun = cast<AbstractFunctionDecl>(VD);
2367-
if (auto *orig = findReplacedFunction(attr->getReplacedFunctionName(), fun,
2368-
attr, &Ctx.Diags)) {
2369-
origs.push_back(orig);
2370-
replacements.push_back(fun);
2371-
} else
2372-
return;
23732327
}
23742328

2375-
// Annotate the replacement with the original func decl.
2376-
for (auto index : indices(replacements)) {
2377-
if (auto *attr = replacements[index]
2378-
->getAttrs()
2379-
.getAttribute<DynamicReplacementAttr>()) {
2380-
auto *replacedFun = origs[index];
2381-
auto *replacement = replacements[index];
2382-
if (replacedFun->isObjC() && !replacement->isObjC()) {
2383-
diagnose(attr->getLocation(),
2384-
diag::dynamic_replacement_replacement_not_objc_dynamic,
2385-
attr->getReplacedFunctionName());
2386-
attr->setInvalid();
2387-
return;
2388-
}
2389-
if (!replacedFun->isObjC() && replacement->isObjC()) {
2390-
diagnose(attr->getLocation(),
2391-
diag::dynamic_replacement_replaced_not_objc_dynamic,
2392-
attr->getReplacedFunctionName());
2393-
attr->setInvalid();
2394-
return;
2395-
}
2396-
attr->setReplacedFunction(replacedFun);
2397-
continue;
2398-
}
2399-
auto *newAttr = DynamicReplacementAttr::create(
2400-
VD->getASTContext(), attr->getReplacedFunctionName(), origs[index]);
2401-
DeclAttributes &attrs = replacements[index]->getAttrs();
2402-
attrs.add(newAttr);
2329+
if (original->isObjC() && !replacement->isObjC()) {
2330+
diagnose(attr->getLocation(),
2331+
diag::dynamic_replacement_replacement_not_objc_dynamic,
2332+
attr->getReplacedFunctionName());
2333+
attr->setInvalid();
2334+
}
2335+
if (!original->isObjC() && replacement->isObjC()) {
2336+
diagnose(attr->getLocation(),
2337+
diag::dynamic_replacement_replaced_not_objc_dynamic,
2338+
attr->getReplacedFunctionName());
2339+
attr->setInvalid();
24032340
}
2404-
if (auto *CD = dyn_cast<ConstructorDecl>(VD)) {
2341+
2342+
if (auto *CD = dyn_cast<ConstructorDecl>(replacement)) {
24052343
auto *attr = CD->getAttrs().getAttribute<DynamicReplacementAttr>();
24062344
auto replacedIsConvenienceInit =
2407-
cast<ConstructorDecl>(attr->getReplacedFunction())->isConvenienceInit();
2345+
cast<ConstructorDecl>(original)->isConvenienceInit();
24082346
if (replacedIsConvenienceInit &&!CD->isConvenienceInit()) {
24092347
diagnose(attr->getLocation(),
24102348
diag::dynamic_replacement_replaced_constructor_is_convenience,
@@ -2416,13 +2354,6 @@ void AttributeChecker::visitDynamicReplacementAttr(DynamicReplacementAttr *attr)
24162354
attr->getReplacedFunctionName());
24172355
}
24182356
}
2419-
2420-
2421-
// Remove the attribute on the abstract storage (we have moved it to the
2422-
// accessor decl).
2423-
if (!isa<AbstractStorageDecl>(VD))
2424-
return;
2425-
D->getAttrs().removeAttribute(attr);
24262357
}
24272358

24282359
void AttributeChecker::visitImplementsAttr(ImplementsAttr *attr) {
@@ -2911,3 +2842,53 @@ void TypeChecker::addImplicitDynamicAttribute(Decl *D) {
29112842
D->getAttrs().add(attr);
29122843
}
29132844
}
2845+
2846+
llvm::Expected<ValueDecl *>
2847+
DynamicallyReplacedDeclRequest::evaluate(Evaluator &evaluator,
2848+
ValueDecl *VD) const {
2849+
// Dynamic replacements must be explicit.
2850+
if (VD->isImplicit())
2851+
return nullptr;
2852+
2853+
auto *attr = VD->getAttrs().getAttribute<DynamicReplacementAttr>();
2854+
if (!attr) {
2855+
// It's likely that the accessor isn't annotated but its storage is.
2856+
if (auto *AD = dyn_cast<AccessorDecl>(VD)) {
2857+
// Try to grab the attribute from the storage.
2858+
attr = AD->getStorage()->getAttrs().getAttribute<DynamicReplacementAttr>();
2859+
}
2860+
2861+
if (!attr) {
2862+
// Otherwise, it's not dynamically replacing anything.
2863+
return nullptr;
2864+
}
2865+
}
2866+
2867+
// If the attribute is invalid, bail.
2868+
if (attr->isInvalid())
2869+
return nullptr;
2870+
2871+
// If we can lazily resolve the function, do so now.
2872+
if (auto *LazyResolver = attr->Resolver) {
2873+
auto decl = attr->Resolver->loadDynamicallyReplacedFunctionDecl(
2874+
attr, attr->ResolverContextData);
2875+
attr->Resolver = nullptr;
2876+
return decl;
2877+
}
2878+
2879+
auto &Ctx = VD->getASTContext();
2880+
if (auto *AD = dyn_cast<AccessorDecl>(VD)) {
2881+
return findReplacedAccessor(attr->getReplacedFunctionName(), AD, attr, Ctx);
2882+
}
2883+
2884+
if (auto *AFD = dyn_cast<AbstractFunctionDecl>(VD)) {
2885+
return findReplacedFunction(attr->getReplacedFunctionName(), AFD,
2886+
attr, &Ctx.Diags);
2887+
}
2888+
2889+
if (auto *SD = dyn_cast<AbstractStorageDecl>(VD)) {
2890+
return findReplacedStorageDecl(attr->getReplacedFunctionName(), SD, attr);
2891+
}
2892+
2893+
return nullptr;
2894+
}

lib/Sema/TypeCheckDeclPrimary.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2056,7 +2056,8 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
20562056
// Force these requests in case they emit diagnostics.
20572057
(void) FD->getInterfaceType();
20582058
(void) FD->getOperatorDecl();
2059-
2059+
(void) FD->getDynamicallyReplacedDecl();
2060+
20602061
if (!FD->isInvalid()) {
20612062
checkGenericParams(FD);
20622063
TypeChecker::checkReferencedGenericParams(FD);

lib/Sema/TypeChecker.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -723,7 +723,6 @@ class TypeChecker final {
723723
static void addImplicitDynamicAttribute(Decl *D);
724724
static void checkDeclAttributes(Decl *D);
725725
static void checkParameterAttributes(ParameterList *params);
726-
static ValueDecl *findReplacedDynamicFunction(const ValueDecl *d);
727726

728727
static Type checkReferenceOwnershipAttr(VarDecl *D, Type interfaceType,
729728
ReferenceOwnershipAttr *attr);

0 commit comments

Comments
 (0)