Skip to content

[NFC] Refactor @_dynamicReplacement Checking #28434

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Dec 4, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 21 additions & 14 deletions include/swift/AST/Attr.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ class FuncDecl;
class ClassDecl;
class GenericFunctionType;
class LazyConformanceLoader;
class LazyMemberLoader;
class PatternBindingInitializer;
class TrailingWhereClause;

Expand Down Expand Up @@ -1010,18 +1011,31 @@ class DynamicReplacementAttr final
: public DeclAttribute,
private llvm::TrailingObjects<DynamicReplacementAttr, SourceLoc> {
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;
}

Expand All @@ -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;

Expand Down
8 changes: 6 additions & 2 deletions include/swift/AST/Decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -2389,6 +2389,7 @@ class ValueDecl : public Decl {
unsigned isIUO : 1;
} LazySemanticInfo = { };

friend class DynamicallyReplacedDeclRequest;
friend class OverriddenDeclsRequest;
friend class IsObjCRequest;
friend class IsFinalRequest;
Expand Down Expand Up @@ -2749,6 +2750,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.
Expand Down Expand Up @@ -4768,8 +4774,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 &&
Expand Down
5 changes: 5 additions & 0 deletions include/swift/AST/LazyResolver.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,11 @@ class alignas(void*) LazyMemberLoader {
virtual void
loadRequirementSignature(const ProtocolDecl *proto, uint64_t contextData,
SmallVectorImpl<Requirement> &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.
Expand Down
18 changes: 18 additions & 0 deletions include/swift/AST/TypeCheckRequests.h
Original file line number Diff line number Diff line change
Expand Up @@ -1930,6 +1930,24 @@ class IsCallableNominalTypeRequest
bool isCached() const { return true; }
};

class DynamicallyReplacedDeclRequest
: public SimpleRequest<DynamicallyReplacedDeclRequest,
ValueDecl *(ValueDecl *), CacheKind::Cached> {
public:
using SimpleRequest::SimpleRequest;

private:
friend SimpleRequest;

// Evaluation.
llvm::Expected<ValueDecl *> 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<>
Expand Down
3 changes: 3 additions & 0 deletions include/swift/AST/TypeCheckerTypeIDZone.def
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,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,
Expand Down
21 changes: 10 additions & 11 deletions lib/AST/Attr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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, ...) \
Expand Down Expand Up @@ -1148,7 +1148,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;
Expand All @@ -1165,17 +1165,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 {
Expand Down
18 changes: 9 additions & 9 deletions lib/AST/Decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2833,6 +2833,13 @@ void ValueDecl::setIsDynamic(bool value) {
LazySemanticInfo.isDynamic = value;
}

ValueDecl *ValueDecl::getDynamicallyReplacedDecl() const {
return evaluateOrDefault(getASTContext().evaluator,
DynamicallyReplacedDeclRequest{
const_cast<ValueDecl *>(this)},
nullptr);
}

bool ValueDecl::canBeAccessedByDynamicLookup() const {
if (!hasName())
return false;
Expand Down Expand Up @@ -4958,9 +4965,9 @@ bool AbstractStorageDecl::hasPrivateAccessor() const {

bool AbstractStorageDecl::hasDidSetOrWillSetDynamicReplacement() const {
if (auto *func = getParsedAccessor(AccessorKind::DidSet))
return func->getAttrs().hasAttribute<DynamicReplacementAttr>();
return (bool)func->getDynamicallyReplacedDecl();
if (auto *func = getParsedAccessor(AccessorKind::WillSet))
return func->getAttrs().hasAttribute<DynamicReplacementAttr>();
return (bool)func->getDynamicallyReplacedDecl();
return false;
}

Expand All @@ -4972,13 +4979,6 @@ bool AbstractStorageDecl::hasAnyNativeDynamicAccessors() const {
return false;
}

bool AbstractStorageDecl::hasAnyDynamicReplacementAccessors() const {
for (auto accessor : getAllAccessors()) {
if (accessor->getAttrs().hasAttribute<DynamicReplacementAttr>())
return true;
}
return false;
}
void AbstractStorageDecl::setAccessors(SourceLoc lbraceLoc,
ArrayRef<AccessorDecl *> accessors,
SourceLoc rbraceLoc) {
Expand Down
6 changes: 6 additions & 0 deletions lib/ClangImporter/ImporterImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<Requirement> &reqs) override {
llvm_unreachable("unimplemented for ClangImporter");
Expand Down
11 changes: 4 additions & 7 deletions lib/IRGen/GenArchetype.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -452,21 +452,18 @@ withOpaqueTypeGenericArgs(IRGenFunction &IGF,

bool shouldUseOpaqueTypeDescriptorAccessor(OpaqueTypeDecl *opaque) {
auto *namingDecl = opaque->getNamingDecl();
auto *abstractStorage = dyn_cast<AbstractStorageDecl>(namingDecl);

// Don't emit accessors for abstract storage that is not dynamic or a dynamic
// replacement.
if (abstractStorage) {
if (auto *abstractStorage = dyn_cast<AbstractStorageDecl>(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<DynamicReplacementAttr>();
return namingDecl->isNativeDynamic() ||
(bool)namingDecl->getDynamicallyReplacedDecl();
}

static llvm::Value *
Expand Down
8 changes: 2 additions & 6 deletions lib/IRGen/GenDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2371,24 +2371,20 @@ void IRGenModule::emitOpaqueTypeDescriptorAccessor(OpaqueTypeDecl *opaque) {
auto *abstractStorage = dyn_cast<AbstractStorageDecl>(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;
}

// Don't emit accessors for functions that are not dynamic or dynamic
// replacements.
if (!abstractStorage) {
isNativeDynamic = opaque->getNamingDecl()->isNativeDynamic();
isDynamicReplacement = opaque->getNamingDecl()
->getAttrs()
.hasAttribute<DynamicReplacementAttr>();
isNativeDynamic = namingDecl->isNativeDynamic();
if (!isNativeDynamic && !isDynamicReplacement)
return;
}
Expand Down
10 changes: 5 additions & 5 deletions lib/SIL/SILFunctionBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,13 +76,13 @@ void SILFunctionBuilder::addFunctionAttributes(SILFunction *F,
SILFunctionTypeRepresentation::ObjCMethod)
return;

auto *replacedFuncAttr = Attrs.getAttribute<DynamicReplacementAttr>();
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<AbstractFunctionDecl>(origDecl);
if (!replacedDecl)
return;

auto *replacedDecl = replacedFuncAttr->getReplacedFunction();
assert(replacedDecl);

if (decl->isObjC()) {
F->setObjCReplacement(replacedDecl);
return;
Expand Down
3 changes: 1 addition & 2 deletions lib/SILGen/SILGenApply.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -789,8 +789,7 @@ bool isCallToReplacedInDynamicReplacement(SILGenFunction &SGF,
bool &isObjCReplacementSelfCall) {
if (auto *func =
dyn_cast_or_null<AbstractFunctionDecl>(SGF.FunctionDC->getAsDecl())) {
auto *repl = func->getAttrs().getAttribute<DynamicReplacementAttr>();
if (repl && repl->getReplacedFunction() == afd) {
if (func->getDynamicallyReplacedDecl() == afd) {
isObjCReplacementSelfCall = afd->isObjC();
return true;
}
Expand Down
Loading