diff --git a/include/swift/AST/Attr.h b/include/swift/AST/Attr.h index 776b22a25b259..de46bdf627b8a 100644 --- a/include/swift/AST/Attr.h +++ b/include/swift/AST/Attr.h @@ -52,6 +52,7 @@ class FuncDecl; class ClassDecl; class GenericFunctionType; class LazyConformanceLoader; +class LazyMemberLoader; class PatternBindingInitializer; class TrailingWhereClause; @@ -1010,18 +1011,31 @@ class DynamicReplacementAttr final : public DeclAttribute, private llvm::TrailingObjects { friend TrailingObjects; + friend class DynamicallyReplacedDeclRequest; DeclName ReplacedFunctionName; - AbstractFunctionDecl *ReplacedFunction; + LazyMemberLoader *Resolver = nullptr; + uint64_t ResolverContextData; /// Create an @_dynamicReplacement(for:) attribute written in the source. DynamicReplacementAttr(SourceLoc atLoc, SourceRange baseRange, DeclName replacedFunctionName, SourceRange parenRange); - explicit DynamicReplacementAttr(DeclName name) + DynamicReplacementAttr(DeclName name, AbstractFunctionDecl *f) : DeclAttribute(DAK_DynamicReplacement, SourceLoc(), SourceRange(), /*Implicit=*/false), - ReplacedFunctionName(name), ReplacedFunction(nullptr) { + ReplacedFunctionName(name), + Resolver(nullptr), ResolverContextData(0) { + Bits.DynamicReplacementAttr.HasTrailingLocationInfo = false; + } + + DynamicReplacementAttr(DeclName name, + LazyMemberLoader *Resolver = nullptr, + uint64_t Data = 0) + : DeclAttribute(DAK_DynamicReplacement, SourceLoc(), SourceRange(), + /*Implicit=*/false), + ReplacedFunctionName(name), + Resolver(Resolver), ResolverContextData(Data) { Bits.DynamicReplacementAttr.HasTrailingLocationInfo = false; } @@ -1045,25 +1059,18 @@ class DynamicReplacementAttr final SourceLoc LParenLoc, DeclName replacedFunction, SourceLoc RParenLoc); static DynamicReplacementAttr *create(ASTContext &ctx, - DeclName replacedFunction); + DeclName replacedFunction, + AbstractFunctionDecl *replacedFuncDecl); static DynamicReplacementAttr *create(ASTContext &ctx, DeclName replacedFunction, - AbstractFunctionDecl *replacedFuncDecl); + LazyMemberLoader *Resolver, + uint64_t Data); DeclName getReplacedFunctionName() const { return ReplacedFunctionName; } - AbstractFunctionDecl *getReplacedFunction() const { - return ReplacedFunction; - } - - void setReplacedFunction(AbstractFunctionDecl *f) { - assert(ReplacedFunction == nullptr); - ReplacedFunction = f; - } - /// Retrieve the location of the opening parentheses, if there is one. SourceLoc getLParenLoc() const; diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index c1cbba1c20596..60198bc1e3860 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -2382,6 +2382,7 @@ class ValueDecl : public Decl { unsigned isIUO : 1; } LazySemanticInfo = { }; + friend class DynamicallyReplacedDeclRequest; friend class OverriddenDeclsRequest; friend class IsObjCRequest; friend class IsFinalRequest; @@ -2742,6 +2743,11 @@ class ValueDecl : public Decl { /// Retrieve the @functionBuilder type attached to this declaration, /// if there is one. Type getFunctionBuilderType() const; + + /// If this value or its backing storage is annotated + /// @_dynamicReplacement(for: ...), compute the original declaration + /// that this declaration dynamically replaces. + ValueDecl *getDynamicallyReplacedDecl() const; }; /// This is a common base class for declarations which declare a type. @@ -4761,8 +4767,6 @@ class AbstractStorageDecl : public ValueDecl { bool hasAnyNativeDynamicAccessors() const; - bool hasAnyDynamicReplacementAccessors() const; - // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return D->getKind() >= DeclKind::First_AbstractStorageDecl && diff --git a/include/swift/AST/LazyResolver.h b/include/swift/AST/LazyResolver.h index b6cabd44b2a04..afd90352852cf 100644 --- a/include/swift/AST/LazyResolver.h +++ b/include/swift/AST/LazyResolver.h @@ -103,6 +103,11 @@ class alignas(void*) LazyMemberLoader { virtual void loadRequirementSignature(const ProtocolDecl *proto, uint64_t contextData, SmallVectorImpl &requirements) = 0; + + /// Returns the replaced decl for a given @_dynamicReplacement(for:) attribute. + virtual ValueDecl * + loadDynamicallyReplacedFunctionDecl(const DynamicReplacementAttr *DRA, + uint64_t contextData) = 0; }; /// A class that can lazily load conformances from a serialized format. diff --git a/include/swift/AST/TypeCheckRequests.h b/include/swift/AST/TypeCheckRequests.h index f62653436e8ea..4b0c8b937c3e0 100644 --- a/include/swift/AST/TypeCheckRequests.h +++ b/include/swift/AST/TypeCheckRequests.h @@ -1886,6 +1886,25 @@ class DefaultArgumentExprRequest void cacheResult(Expr *expr) const; }; +class DynamicallyReplacedDeclRequest + : public SimpleRequest { +public: + using SimpleRequest::SimpleRequest; + +private: + friend SimpleRequest; + + // Evaluation. + llvm::Expected + evaluate(Evaluator &evaluator, ValueDecl *VD) const; + +public: + // Caching. + bool isCached() const { return true; } +}; + // Allow AnyValue to compare two Type values, even though Type doesn't // support ==. template<> diff --git a/include/swift/AST/TypeCheckerTypeIDZone.def b/include/swift/AST/TypeCheckerTypeIDZone.def index 95ec95ce10449..5485d24cc2c07 100644 --- a/include/swift/AST/TypeCheckerTypeIDZone.def +++ b/include/swift/AST/TypeCheckerTypeIDZone.def @@ -41,6 +41,9 @@ SWIFT_REQUEST(TypeChecker, DefaultDefinitionTypeRequest, SWIFT_REQUEST(TypeChecker, DefaultTypeRequest, Type(KnownProtocolKind, const DeclContext *), SeparatelyCached, NoLocationInfo) +SWIFT_REQUEST(TypeChecker, DynamicallyReplacedDeclRequest, + ValueDecl *(ValueDecl *), + Cached, NoLocationInfo) SWIFT_REQUEST(TypeChecker, EmittedMembersRequest, DeclRange(ClassDecl *), SeparatelyCached, NoLocationInfo) SWIFT_REQUEST(TypeChecker, EnumRawValuesRequest, diff --git a/lib/AST/Attr.cpp b/lib/AST/Attr.cpp index 3fdb973a67805..c7217aaa929c1 100644 --- a/lib/AST/Attr.cpp +++ b/lib/AST/Attr.cpp @@ -22,14 +22,14 @@ #include "swift/AST/GenericEnvironment.h" #include "swift/AST/IndexSubset.h" #include "swift/AST/Module.h" +#include "swift/AST/ParameterList.h" #include "swift/AST/TypeRepr.h" #include "swift/AST/Types.h" -#include "swift/AST/ParameterList.h" #include "swift/Basic/Defer.h" #include "llvm/ADT/SmallString.h" -#include "llvm/Support/raw_ostream.h" -#include "llvm/Support/ErrorHandling.h" #include "llvm/ADT/StringSwitch.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" using namespace swift; #define DECL_ATTR(_, Id, ...) \ @@ -1135,7 +1135,7 @@ DynamicReplacementAttr::DynamicReplacementAttr(SourceLoc atLoc, SourceRange parenRange) : DeclAttribute(DAK_DynamicReplacement, atLoc, baseRange, /*Implicit=*/false), - ReplacedFunctionName(name), ReplacedFunction(nullptr) { + ReplacedFunctionName(name) { Bits.DynamicReplacementAttr.HasTrailingLocationInfo = true; getTrailingLocations()[0] = parenRange.Start; getTrailingLocations()[1] = parenRange.End; @@ -1152,17 +1152,16 @@ DynamicReplacementAttr::create(ASTContext &Ctx, SourceLoc AtLoc, SourceRange(LParenLoc, RParenLoc)); } -DynamicReplacementAttr *DynamicReplacementAttr::create(ASTContext &Ctx, - DeclName name) { - return new (Ctx) DynamicReplacementAttr(name); +DynamicReplacementAttr * +DynamicReplacementAttr::create(ASTContext &Ctx, DeclName name, + AbstractFunctionDecl *f) { + return new (Ctx) DynamicReplacementAttr(name, f); } DynamicReplacementAttr * DynamicReplacementAttr::create(ASTContext &Ctx, DeclName name, - AbstractFunctionDecl *f) { - auto res = new (Ctx) DynamicReplacementAttr(name); - res->setReplacedFunction(f); - return res; + LazyMemberLoader *Resolver, uint64_t Data) { + return new (Ctx) DynamicReplacementAttr(name, Resolver, Data); } SourceLoc DynamicReplacementAttr::getLParenLoc() const { diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 8a1dce1007355..05461859dd5a1 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -2817,6 +2817,13 @@ void ValueDecl::setIsDynamic(bool value) { LazySemanticInfo.isDynamic = value; } +ValueDecl *ValueDecl::getDynamicallyReplacedDecl() const { + return evaluateOrDefault(getASTContext().evaluator, + DynamicallyReplacedDeclRequest{ + const_cast(this)}, + nullptr); +} + bool ValueDecl::canBeAccessedByDynamicLookup() const { if (!hasName()) return false; @@ -4942,9 +4949,9 @@ bool AbstractStorageDecl::hasPrivateAccessor() const { bool AbstractStorageDecl::hasDidSetOrWillSetDynamicReplacement() const { if (auto *func = getParsedAccessor(AccessorKind::DidSet)) - return func->getAttrs().hasAttribute(); + return (bool)func->getDynamicallyReplacedDecl(); if (auto *func = getParsedAccessor(AccessorKind::WillSet)) - return func->getAttrs().hasAttribute(); + return (bool)func->getDynamicallyReplacedDecl(); return false; } @@ -4956,13 +4963,6 @@ bool AbstractStorageDecl::hasAnyNativeDynamicAccessors() const { return false; } -bool AbstractStorageDecl::hasAnyDynamicReplacementAccessors() const { - for (auto accessor : getAllAccessors()) { - if (accessor->getAttrs().hasAttribute()) - return true; - } - return false; -} void AbstractStorageDecl::setAccessors(SourceLoc lbraceLoc, ArrayRef accessors, SourceLoc rbraceLoc) { diff --git a/lib/ClangImporter/ImporterImpl.h b/lib/ClangImporter/ImporterImpl.h index 7dba7c806ea3e..86a51564f738d 100644 --- a/lib/ClangImporter/ImporterImpl.h +++ b/lib/ClangImporter/ImporterImpl.h @@ -1230,6 +1230,12 @@ class LLVM_LIBRARY_VISIBILITY ClangImporter::Implementation llvm_unreachable("unimplemented for ClangImporter"); } + ValueDecl * + loadDynamicallyReplacedFunctionDecl(const DynamicReplacementAttr *DRA, + uint64_t contextData) override { + llvm_unreachable("unimplemented for ClangImporter"); + } + void loadRequirementSignature(const ProtocolDecl *decl, uint64_t contextData, SmallVectorImpl &reqs) override { llvm_unreachable("unimplemented for ClangImporter"); diff --git a/lib/IRGen/GenArchetype.cpp b/lib/IRGen/GenArchetype.cpp index a9afa0d8a5313..18a3c38d2a22c 100644 --- a/lib/IRGen/GenArchetype.cpp +++ b/lib/IRGen/GenArchetype.cpp @@ -452,21 +452,18 @@ withOpaqueTypeGenericArgs(IRGenFunction &IGF, bool shouldUseOpaqueTypeDescriptorAccessor(OpaqueTypeDecl *opaque) { auto *namingDecl = opaque->getNamingDecl(); - auto *abstractStorage = dyn_cast(namingDecl); // Don't emit accessors for abstract storage that is not dynamic or a dynamic // replacement. - if (abstractStorage) { + if (auto *abstractStorage = dyn_cast(namingDecl)) { return abstractStorage->hasAnyNativeDynamicAccessors() || - abstractStorage->hasAnyDynamicReplacementAccessors(); + abstractStorage->getDynamicallyReplacedDecl(); } // Don't emit accessors for functions that are not dynamic or dynamic // replacements. - return opaque->getNamingDecl()->isNativeDynamic() || - opaque->getNamingDecl() - ->getAttrs() - .hasAttribute(); + return namingDecl->isNativeDynamic() || + (bool)namingDecl->getDynamicallyReplacedDecl(); } static llvm::Value * diff --git a/lib/IRGen/GenDecl.cpp b/lib/IRGen/GenDecl.cpp index 2c15da60dc75b..cf64b040e7eb5 100644 --- a/lib/IRGen/GenDecl.cpp +++ b/lib/IRGen/GenDecl.cpp @@ -2349,13 +2349,12 @@ void IRGenModule::emitOpaqueTypeDescriptorAccessor(OpaqueTypeDecl *opaque) { auto *abstractStorage = dyn_cast(namingDecl); bool isNativeDynamic = false; - bool isDynamicReplacement = false; + const bool isDynamicReplacement = namingDecl->getDynamicallyReplacedDecl(); // Don't emit accessors for abstract storage that is not dynamic or a dynamic // replacement. if (abstractStorage) { isNativeDynamic = abstractStorage->hasAnyNativeDynamicAccessors(); - isDynamicReplacement = abstractStorage->hasAnyDynamicReplacementAccessors(); if (!isNativeDynamic && !isDynamicReplacement) return; } @@ -2363,10 +2362,7 @@ void IRGenModule::emitOpaqueTypeDescriptorAccessor(OpaqueTypeDecl *opaque) { // Don't emit accessors for functions that are not dynamic or dynamic // replacements. if (!abstractStorage) { - isNativeDynamic = opaque->getNamingDecl()->isNativeDynamic(); - isDynamicReplacement = opaque->getNamingDecl() - ->getAttrs() - .hasAttribute(); + isNativeDynamic = namingDecl->isNativeDynamic(); if (!isNativeDynamic && !isDynamicReplacement) return; } diff --git a/lib/SIL/SILFunctionBuilder.cpp b/lib/SIL/SILFunctionBuilder.cpp index 85c962470be37..0330b3d93cca0 100644 --- a/lib/SIL/SILFunctionBuilder.cpp +++ b/lib/SIL/SILFunctionBuilder.cpp @@ -76,13 +76,13 @@ void SILFunctionBuilder::addFunctionAttributes(SILFunction *F, SILFunctionTypeRepresentation::ObjCMethod) return; - auto *replacedFuncAttr = Attrs.getAttribute(); - if (!replacedFuncAttr) + // Only assign replacements when the thing being replaced is function-like and + // explicitly declared. + auto *origDecl = decl->getDynamicallyReplacedDecl(); + auto *replacedDecl = dyn_cast_or_null(origDecl); + if (!replacedDecl) return; - auto *replacedDecl = replacedFuncAttr->getReplacedFunction(); - assert(replacedDecl); - if (decl->isObjC()) { F->setObjCReplacement(replacedDecl); return; diff --git a/lib/SILGen/SILGenApply.cpp b/lib/SILGen/SILGenApply.cpp index d2980f81c191c..386217d3cc092 100644 --- a/lib/SILGen/SILGenApply.cpp +++ b/lib/SILGen/SILGenApply.cpp @@ -789,8 +789,7 @@ bool isCallToReplacedInDynamicReplacement(SILGenFunction &SGF, bool &isObjCReplacementSelfCall) { if (auto *func = dyn_cast_or_null(SGF.FunctionDC->getAsDecl())) { - auto *repl = func->getAttrs().getAttribute(); - if (repl && repl->getReplacedFunction() == afd) { + if (func->getDynamicallyReplacedDecl() == afd) { isObjCReplacementSelfCall = afd->isObjC(); return true; } diff --git a/lib/Sema/TypeCheckAttr.cpp b/lib/Sema/TypeCheckAttr.cpp index 661880b093dcc..4678e6d36999b 100644 --- a/lib/Sema/TypeCheckAttr.cpp +++ b/lib/Sema/TypeCheckAttr.cpp @@ -2060,10 +2060,10 @@ void AttributeChecker::visitDiscardableResultAttr(DiscardableResultAttr *attr) { } /// Lookup the replaced decl in the replacments scope. -void lookupReplacedDecl(DeclName replacedDeclName, - const DynamicReplacementAttr *attr, - const ValueDecl *replacement, - SmallVectorImpl &results) { +static void lookupReplacedDecl(DeclName replacedDeclName, + const DynamicReplacementAttr *attr, + const ValueDecl *replacement, + SmallVectorImpl &results) { auto *declCtxt = replacement->getDeclContext(); // Look at the accessors' storage's context. @@ -2220,11 +2220,12 @@ findReplacedFunction(DeclName replacedFunctionName, // Check for static/instance mismatch. if (result->isStatic() != replacement->isStatic()) continue; - + + auto resultTy = result->getInterfaceType(); + auto replaceTy = replacement->getInterfaceType(); TypeMatchOptions matchMode = TypeMatchFlags::AllowABICompatible; matchMode |= TypeMatchFlags::AllowCompatibleOpaqueTypeArchetypes; - if (result->getInterfaceType()->getCanonicalType()->matches( - replacement->getInterfaceType()->getCanonicalType(), matchMode)) { + if (resultTy->matches(replaceTy, matchMode)) { if (!result->isDynamic()) { if (Diags) { Diags->diagnose(attr->getLocation(), @@ -2274,9 +2275,11 @@ findReplacedStorageDecl(DeclName replacedFunctionName, // Check for static/instance mismatch. if (result->isStatic() != replacement->isStatic()) continue; - if (result->getInterfaceType()->getCanonicalType()->matches( - replacement->getInterfaceType()->getCanonicalType(), - TypeMatchFlags::AllowABICompatible)) { + auto resultTy = result->getInterfaceType(); + auto replaceTy = replacement->getInterfaceType(); + TypeMatchOptions matchMode = TypeMatchFlags::AllowABICompatible; + matchMode |= TypeMatchFlags::AllowCompatibleOpaqueTypeArchetypes; + if (resultTy->matches(replaceTy, matchMode)) { if (!result->isDynamic()) { return nullptr; } @@ -2286,113 +2289,48 @@ findReplacedStorageDecl(DeclName replacedFunctionName, return nullptr; } -ValueDecl *TypeChecker::findReplacedDynamicFunction(const ValueDecl *vd) { - assert(isa(vd) || isa(vd)); - if (isa(vd)) - return nullptr; - - auto *attr = vd->getAttrs().getAttribute(); - if (!attr) - return nullptr; - - auto *afd = dyn_cast(vd); - if (afd) { - // When we pass nullptr as the type checker argument attr is truely const. - return findReplacedFunction(attr->getReplacedFunctionName(), afd, - const_cast(attr), - nullptr); - } - auto *storageDecl = dyn_cast(vd); - if (!storageDecl) - return nullptr; - return findReplacedStorageDecl(attr->getReplacedFunctionName(), storageDecl, attr); -} - void AttributeChecker::visitDynamicReplacementAttr(DynamicReplacementAttr *attr) { assert(isa(D) || isa(D)); - auto *VD = cast(D); + auto *replacement = cast(D); - if (!isa(VD->getDeclContext()) && - !VD->getDeclContext()->isModuleScopeContext()) { + if (!isa(replacement->getDeclContext()) && + !replacement->getDeclContext()->isModuleScopeContext()) { diagnose(attr->getLocation(), diag::dynamic_replacement_not_in_extension, - VD->getBaseName()); + replacement->getBaseName()); attr->setInvalid(); return; } - if (VD->isNativeDynamic()) { + if (replacement->isNativeDynamic()) { diagnose(attr->getLocation(), diag::dynamic_replacement_must_not_be_dynamic, - VD->getBaseName()); + replacement->getBaseName()); attr->setInvalid(); return; } - // Don't process a declaration twice. This will happen to accessor decls after - // we have processed their var decls. - if (attr->getReplacedFunction()) + auto *original = replacement->getDynamicallyReplacedDecl(); + if (!original) { + attr->setInvalid(); return; - - SmallVector replacements; - SmallVector origs; - - // Collect the accessor replacement mapping if this is an abstract storage. - if (auto *var = dyn_cast(VD)) { - var->visitParsedAccessors([&](AccessorDecl *accessor) { - if (attr->isInvalid()) - return; - - auto *orig = findReplacedAccessor(attr->getReplacedFunctionName(), - accessor, attr, Ctx); - if (!orig) - return; - - origs.push_back(orig); - replacements.push_back(accessor); - }); - } else { - // Otherwise, find the matching function. - auto *fun = cast(VD); - if (auto *orig = findReplacedFunction(attr->getReplacedFunctionName(), fun, - attr, &Ctx.Diags)) { - origs.push_back(orig); - replacements.push_back(fun); - } else - return; } - // Annotate the replacement with the original func decl. - for (auto index : indices(replacements)) { - if (auto *attr = replacements[index] - ->getAttrs() - .getAttribute()) { - auto *replacedFun = origs[index]; - auto *replacement = replacements[index]; - if (replacedFun->isObjC() && !replacement->isObjC()) { - diagnose(attr->getLocation(), - diag::dynamic_replacement_replacement_not_objc_dynamic, - attr->getReplacedFunctionName()); - attr->setInvalid(); - return; - } - if (!replacedFun->isObjC() && replacement->isObjC()) { - diagnose(attr->getLocation(), - diag::dynamic_replacement_replaced_not_objc_dynamic, - attr->getReplacedFunctionName()); - attr->setInvalid(); - return; - } - attr->setReplacedFunction(replacedFun); - continue; - } - auto *newAttr = DynamicReplacementAttr::create( - VD->getASTContext(), attr->getReplacedFunctionName(), origs[index]); - DeclAttributes &attrs = replacements[index]->getAttrs(); - attrs.add(newAttr); + if (original->isObjC() && !replacement->isObjC()) { + diagnose(attr->getLocation(), + diag::dynamic_replacement_replacement_not_objc_dynamic, + attr->getReplacedFunctionName()); + attr->setInvalid(); + } + if (!original->isObjC() && replacement->isObjC()) { + diagnose(attr->getLocation(), + diag::dynamic_replacement_replaced_not_objc_dynamic, + attr->getReplacedFunctionName()); + attr->setInvalid(); } - if (auto *CD = dyn_cast(VD)) { + + if (auto *CD = dyn_cast(replacement)) { auto *attr = CD->getAttrs().getAttribute(); auto replacedIsConvenienceInit = - cast(attr->getReplacedFunction())->isConvenienceInit(); + cast(original)->isConvenienceInit(); if (replacedIsConvenienceInit &&!CD->isConvenienceInit()) { diagnose(attr->getLocation(), diag::dynamic_replacement_replaced_constructor_is_convenience, @@ -2404,13 +2342,6 @@ void AttributeChecker::visitDynamicReplacementAttr(DynamicReplacementAttr *attr) attr->getReplacedFunctionName()); } } - - - // Remove the attribute on the abstract storage (we have moved it to the - // accessor decl). - if (!isa(VD)) - return; - D->getAttrs().removeAttribute(attr); } void AttributeChecker::visitImplementsAttr(ImplementsAttr *attr) { @@ -2882,3 +2813,53 @@ void TypeChecker::addImplicitDynamicAttribute(Decl *D) { D->getAttrs().add(attr); } } + +llvm::Expected +DynamicallyReplacedDeclRequest::evaluate(Evaluator &evaluator, + ValueDecl *VD) const { + // Dynamic replacements must be explicit. + if (VD->isImplicit()) + return nullptr; + + auto *attr = VD->getAttrs().getAttribute(); + if (!attr) { + // It's likely that the accessor isn't annotated but its storage is. + if (auto *AD = dyn_cast(VD)) { + // Try to grab the attribute from the storage. + attr = AD->getStorage()->getAttrs().getAttribute(); + } + + if (!attr) { + // Otherwise, it's not dynamically replacing anything. + return nullptr; + } + } + + // If the attribute is invalid, bail. + if (attr->isInvalid()) + return nullptr; + + // If we can lazily resolve the function, do so now. + if (auto *LazyResolver = attr->Resolver) { + auto decl = attr->Resolver->loadDynamicallyReplacedFunctionDecl( + attr, attr->ResolverContextData); + attr->Resolver = nullptr; + return decl; + } + + auto &Ctx = VD->getASTContext(); + if (auto *AD = dyn_cast(VD)) { + return findReplacedAccessor(attr->getReplacedFunctionName(), AD, attr, Ctx); + } + + if (auto *AFD = dyn_cast(VD)) { + return findReplacedFunction(attr->getReplacedFunctionName(), AFD, + attr, &Ctx.Diags); + } + + if (auto *SD = dyn_cast(VD)) { + return findReplacedStorageDecl(attr->getReplacedFunctionName(), SD, attr); + } + + return nullptr; +} diff --git a/lib/Sema/TypeCheckDeclObjC.cpp b/lib/Sema/TypeCheckDeclObjC.cpp index 59eccfb70903b..54fe278987e52 100644 --- a/lib/Sema/TypeCheckDeclObjC.cpp +++ b/lib/Sema/TypeCheckDeclObjC.cpp @@ -1045,11 +1045,7 @@ Optional shouldMarkAsObjC(const ValueDecl *VD, bool allowImplicit) { if (isa(VD) || isa(VD)) if (auto *replacementAttr = VD->getAttrs().getAttribute()) { - if (auto *replaced = replacementAttr->getReplacedFunction()) { - if (replaced->isObjC()) - return ObjCReason(ObjCReason::ImplicitlyObjC); - } else if (auto *replaced = - TypeChecker::findReplacedDynamicFunction(VD)) { + if (auto *replaced = VD->getDynamicallyReplacedDecl()) { if (replaced->isObjC()) return ObjCReason(ObjCReason::ImplicitlyObjC); } diff --git a/lib/Sema/TypeCheckDeclPrimary.cpp b/lib/Sema/TypeCheckDeclPrimary.cpp index b82a865af0564..1ca2a7516cccf 100644 --- a/lib/Sema/TypeCheckDeclPrimary.cpp +++ b/lib/Sema/TypeCheckDeclPrimary.cpp @@ -2054,7 +2054,8 @@ class DeclChecker : public DeclVisitor { // Force these requests in case they emit diagnostics. (void) FD->getInterfaceType(); (void) FD->getOperatorDecl(); - + (void) FD->getDynamicallyReplacedDecl(); + if (!FD->isInvalid()) { checkGenericParams(FD); TypeChecker::checkReferencedGenericParams(FD); diff --git a/lib/Sema/TypeChecker.h b/lib/Sema/TypeChecker.h index ef096a3e98de5..8df184c37c6e3 100644 --- a/lib/Sema/TypeChecker.h +++ b/lib/Sema/TypeChecker.h @@ -725,7 +725,6 @@ class TypeChecker final { static void addImplicitDynamicAttribute(Decl *D); static void checkDeclAttributes(Decl *D); static void checkParameterAttributes(ParameterList *params); - static ValueDecl *findReplacedDynamicFunction(const ValueDecl *d); static Type checkReferenceOwnershipAttr(VarDecl *D, Type interfaceType, ReferenceOwnershipAttr *attr); diff --git a/lib/Serialization/Deserialization.cpp b/lib/Serialization/Deserialization.cpp index 56e23d273fc8f..7cd75394bbabb 100644 --- a/lib/Serialization/Deserialization.cpp +++ b/lib/Serialization/Deserialization.cpp @@ -4082,9 +4082,6 @@ llvm::Error DeclDeserializer::deserializeDeclAttributes() { serialization::decls_block::DynamicReplacementDeclAttrLayout:: readRecord(scratch, isImplicit, replacedFunID, numArgs, rawPieceIDs); - auto replacedFunDecl = MF.getDeclChecked(replacedFunID); - if (!replacedFunDecl) - return replacedFunDecl.takeError(); auto baseName = MF.getDeclBaseName(rawPieceIDs[0]); SmallVector pieces; for (auto pieceID : rawPieceIDs.slice(1)) @@ -4093,8 +4090,8 @@ llvm::Error DeclDeserializer::deserializeDeclAttributes() { assert(numArgs != 0); assert(!isImplicit && "Need to update for implicit"); Attr = DynamicReplacementAttr::create( - ctx, DeclName(ctx, baseName, ArrayRef(pieces)), - cast(*replacedFunDecl)); + ctx, DeclName(ctx, baseName, ArrayRef(pieces)), &MF, + replacedFunID); break; } @@ -5415,6 +5412,11 @@ ModuleFile::loadAssociatedTypeDefault(const swift::AssociatedTypeDecl *ATD, return getType(contextData); } +ValueDecl *ModuleFile::loadDynamicallyReplacedFunctionDecl( + const DynamicReplacementAttr *DRA, uint64_t contextData) { + return cast(getDecl(contextData)); +} + void ModuleFile::finishNormalConformance(NormalProtocolConformance *conformance, uint64_t contextData) { using namespace decls_block; diff --git a/lib/Serialization/ModuleFile.h b/lib/Serialization/ModuleFile.h index a18febcfdab1b..839fb3c30265a 100644 --- a/lib/Serialization/ModuleFile.h +++ b/lib/Serialization/ModuleFile.h @@ -831,6 +831,10 @@ class ModuleFile virtual Type loadAssociatedTypeDefault(const AssociatedTypeDecl *ATD, uint64_t contextData) override; + virtual ValueDecl * + loadDynamicallyReplacedFunctionDecl(const DynamicReplacementAttr *DRA, + uint64_t contextData) override; + virtual void finishNormalConformance(NormalProtocolConformance *conformance, uint64_t contextData) override; diff --git a/lib/Serialization/ModuleFormat.h b/lib/Serialization/ModuleFormat.h index 18907813aa127..0c148267a1dae 100644 --- a/lib/Serialization/ModuleFormat.h +++ b/lib/Serialization/ModuleFormat.h @@ -52,7 +52,7 @@ const uint16_t SWIFTMODULE_VERSION_MAJOR = 0; /// describe what change you made. The content of this comment isn't important; /// it just ensures a conflict if two people change the module format. /// Don't worry about adhering to the 80-column limit for this line. -const uint16_t SWIFTMODULE_VERSION_MINOR = 524; // function type differentiability +const uint16_t SWIFTMODULE_VERSION_MINOR = 526; // @_dynamicReplacement adjustments /// A standard hash seed used for all string hashes in a serialized module. /// diff --git a/lib/Serialization/Serialization.cpp b/lib/Serialization/Serialization.cpp index c490924d422e5..890863d1aa53c 100644 --- a/lib/Serialization/Serialization.cpp +++ b/lib/Serialization/Serialization.cpp @@ -2070,7 +2070,7 @@ class Serializer::DeclSerializer : public DeclVisitor { didVerifyAttrs = true; } - void writeDeclAttribute(const DeclAttribute *DA) { + void writeDeclAttribute(const Decl *D, const DeclAttribute *DA) { using namespace decls_block; // Completely ignore attributes that aren't serialized. @@ -2246,10 +2246,11 @@ class Serializer::DeclSerializer : public DeclVisitor { pieces.push_back(S.addDeclBaseNameRef(replacedFun.getBaseName())); for (auto argName : replacedFun.getArgumentNames()) pieces.push_back(S.addDeclBaseNameRef(argName)); - assert(theAttr->getReplacedFunction()); + auto *afd = cast(D)->getDynamicallyReplacedDecl(); + assert(afd && "Missing replaced decl!"); DynamicReplacementDeclAttrLayout::emitRecord( S.Out, S.ScratchRecord, abbrCode, false, /*implicit flag*/ - S.addDeclRef(theAttr->getReplacedFunction()), pieces.size(), pieces); + S.addDeclRef(afd), pieces.size(), pieces); return; } @@ -2658,7 +2659,7 @@ class Serializer::DeclSerializer : public DeclVisitor { void visit(const Decl *D) { // Emit attributes (if any). for (auto Attr : D->getAttrs()) - writeDeclAttribute(Attr); + writeDeclAttribute(D, Attr); if (auto *value = dyn_cast(D)) writeDiscriminatorsIfNeeded(value); diff --git a/lib/TBDGen/TBDGen.cpp b/lib/TBDGen/TBDGen.cpp index f9929708d3cda..1f3fea838c059 100644 --- a/lib/TBDGen/TBDGen.cpp +++ b/lib/TBDGen/TBDGen.cpp @@ -226,7 +226,7 @@ void TBDGenVisitor::visitAbstractFunctionDecl(AbstractFunctionDecl *AFD) { addSymbol( LinkEntity::forDynamicallyReplaceableFunctionKey(AFD, useAllocator)); } - if (AFD->getAttrs().hasAttribute()) { + if (AFD->getDynamicallyReplacedDecl()) { bool useAllocator = shouldUseAllocatorMangling(AFD); addSymbol(LinkEntity::forDynamicallyReplaceableFunctionVariable( AFD, useAllocator)); @@ -254,7 +254,7 @@ void TBDGenVisitor::visitFuncDecl(FuncDecl *FD) { addSymbol(LinkEntity::forOpaqueTypeDescriptorAccessorKey(opaqueResult)); addSymbol(LinkEntity::forOpaqueTypeDescriptorAccessorVar(opaqueResult)); } - if (FD->getAttrs().hasAttribute()) { + if (FD->getDynamicallyReplacedDecl()) { addSymbol(LinkEntity::forOpaqueTypeDescriptorAccessor(opaqueResult)); addSymbol(LinkEntity::forOpaqueTypeDescriptorAccessorVar(opaqueResult)); } @@ -282,7 +282,7 @@ void TBDGenVisitor::visitAbstractStorageDecl(AbstractStorageDecl *ASD) { addSymbol(LinkEntity::forOpaqueTypeDescriptorAccessorKey(opaqueResult)); addSymbol(LinkEntity::forOpaqueTypeDescriptorAccessorVar(opaqueResult)); } - if (ASD->hasAnyDynamicReplacementAccessors()) { + if (ASD->getDynamicallyReplacedDecl()) { addSymbol(LinkEntity::forOpaqueTypeDescriptorAccessor(opaqueResult)); addSymbol(LinkEntity::forOpaqueTypeDescriptorAccessorVar(opaqueResult)); }