Skip to content

AST: Store AvailableAttr's rename decl in split request evaluator storage #77818

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 7 commits into from
Dec 2, 2024
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
40 changes: 27 additions & 13 deletions include/swift/AST/Attr.h
Original file line number Diff line number Diff line change
Expand Up @@ -147,13 +147,17 @@ class DeclAttribute : public AttributeBase {
Value : 32
);

SWIFT_INLINE_BITFIELD(AvailableAttr, DeclAttribute, 8+8+1+1,
SWIFT_INLINE_BITFIELD(AvailableAttr, DeclAttribute, 8+8+1+1+1+1,
/// A `PlatformKind` value.
Platform : 8,

/// A `PlatformAgnosticAvailabilityKind` value.
PlatformAgnostic : 8,

/// State storage for `RenamedDeclRequest`.
HasComputedRenamedDecl : 1,
HasRenamedDecl : 1,

/// Whether this attribute was spelled `@_spi_available`.
IsSPI : 1,

Expand Down Expand Up @@ -730,7 +734,7 @@ enum class PlatformAgnosticAvailabilityKind : uint8_t {
class AvailableAttr : public DeclAttribute {
public:
AvailableAttr(SourceLoc AtLoc, SourceRange Range, PlatformKind Platform,
StringRef Message, StringRef Rename, ValueDecl *RenameDecl,
StringRef Message, StringRef Rename,
const llvm::VersionTuple &Introduced,
SourceRange IntroducedRange,
const llvm::VersionTuple &Deprecated,
Expand All @@ -748,14 +752,13 @@ class AvailableAttr : public DeclAttribute {
/// This should take the form of an operator, identifier, or full function
/// name, optionally with a prefixed type, similar to the syntax used for
/// the `NS_SWIFT_NAME` annotation in Objective-C.
///
/// \c ValueDecl::getRenamedDecl() can be used to look up the declaration
/// referred to by this string. Note that this attribute can have a rename
/// target that was provided directly when synthesized and therefore can have
/// a rename decl even when this string is empty.
const StringRef Rename;

/// The declaration referred to by \c Rename. Note that this is only set for
/// deserialized attributes or inferred attributes from ObjectiveC code.
/// \c ValueDecl::getRenamedDecl should be used to find the declaration
/// corresponding to \c Rename.
ValueDecl *RenameDecl;

/// Indicates when the symbol was introduced.
const std::optional<llvm::VersionTuple> Introduced;

Expand Down Expand Up @@ -849,11 +852,6 @@ class AvailableAttr : public DeclAttribute {
llvm::VersionTuple Obsoleted
= llvm::VersionTuple());

/// Create an AvailableAttr that indicates the given \p AsyncFunc should be
/// preferentially used in async contexts
static AvailableAttr *createForAlternative(ASTContext &C,
AbstractFunctionDecl *AsyncFunc);

AvailableAttr *clone(ASTContext &C, bool implicit) const;
AvailableAttr *clone(ASTContext &C) const {
return clone(C, isImplicit());
Expand All @@ -862,6 +860,22 @@ class AvailableAttr : public DeclAttribute {
static bool classof(const DeclAttribute *DA) {
return DA->getKind() == DeclAttrKind::Available;
}

bool hasCachedRenamedDecl() const {
return Bits.AvailableAttr.HasRenamedDecl;
}

private:
friend class RenamedDeclRequest;

bool hasComputedRenamedDecl() const {
return Bits.AvailableAttr.HasComputedRenamedDecl;
}

void setComputedRenamedDecl(bool hasRenamedDecl) {
Bits.AvailableAttr.HasComputedRenamedDecl = true;
Bits.AvailableAttr.HasRenamedDecl = hasRenamedDecl;
}
};

/// Indicates that the given declaration is visible to Objective-C.
Expand Down
9 changes: 9 additions & 0 deletions include/swift/AST/Decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -3262,6 +3262,15 @@ class ValueDecl : public Decl {
/// @_dynamicReplacement(for: ...), compute the original declaration
/// that this declaration dynamically replaces.
ValueDecl *getDynamicallyReplacedDecl() const;

/// Performs a request to look up the decl that this decl has been renamed to
/// if `attr` indicates that it has been renamed.
ValueDecl *getRenamedDecl(const AvailableAttr *attr) const;

/// Directly sets the renamed decl corresponding to `attr`. This should only
/// be used when synthesizing an `AvailableAttr`, before calling
/// `getRenamedDecl()`.
void setRenamedDecl(const AvailableAttr *attr, ValueDecl *renameDecl) const;
};

/// This is a common base class for declarations which declare a type.
Expand Down
7 changes: 5 additions & 2 deletions include/swift/AST/TypeCheckRequests.h
Original file line number Diff line number Diff line change
Expand Up @@ -4085,8 +4085,9 @@ class ConditionalRequirementsRequest

class RenamedDeclRequest
: public SimpleRequest<RenamedDeclRequest,
ValueDecl *(const ValueDecl *, const AvailableAttr *),
RequestFlags::Cached> {
ValueDecl *(const ValueDecl *,
const AvailableAttr *),
RequestFlags::Cached | RequestFlags::SplitCached> {
public:
using SimpleRequest::SimpleRequest;

Expand All @@ -4098,6 +4099,8 @@ class RenamedDeclRequest

public:
bool isCached() const { return true; }
std::optional<ValueDecl *> getCachedResult() const;
void cacheResult(ValueDecl *value) const;
};

using AvailableAttrDeclPair = std::pair<const AvailableAttr *, const Decl *>;
Expand Down
78 changes: 34 additions & 44 deletions lib/AST/Attr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1113,7 +1113,8 @@ ParsedDeclAttrFilter::operator()(const DeclAttribute *Attr) const {
return Attr;
}

static void printAvailableAttr(const AvailableAttr *Attr, ASTPrinter &Printer,
static void printAvailableAttr(const Decl *D, const AvailableAttr *Attr,
ASTPrinter &Printer,
const PrintOptions &Options) {
if (Attr->isLanguageVersionSpecific())
Printer << "swift";
Expand All @@ -1138,17 +1139,19 @@ static void printAvailableAttr(const AvailableAttr *Attr, ASTPrinter &Printer,

if (!Attr->Rename.empty()) {
Printer << ", renamed: \"" << Attr->Rename << "\"";
} else if (Attr->RenameDecl) {
Printer << ", renamed: \"";
if (auto *Accessor = dyn_cast<AccessorDecl>(Attr->RenameDecl)) {
SmallString<32> Name;
llvm::raw_svector_ostream OS(Name);
Accessor->printUserFacingName(OS);
Printer << Name.str();
} else {
Printer << Attr->RenameDecl->getName();
} else if (auto *VD = dyn_cast<ValueDecl>(D)) {
if (auto *renamedDecl = VD->getRenamedDecl(Attr)) {
Printer << ", renamed: \"";
if (auto *Accessor = dyn_cast<AccessorDecl>(renamedDecl)) {
SmallString<32> Name;
llvm::raw_svector_ostream OS(Name);
Accessor->printUserFacingName(OS);
Printer << Name.str();
} else {
Printer << renamedDecl->getName();
}
Printer << "\"";
}
Printer << "\"";
}

// If there's no message, but this is specifically an imported
Expand Down Expand Up @@ -1365,7 +1368,7 @@ bool DeclAttribute::printImpl(ASTPrinter &Printer, const PrintOptions &Options,
Printer.printAttrName("@available");
}
Printer << "(";
printAvailableAttr(Attr, Printer, Options);
printAvailableAttr(D, Attr, Printer, Options);
Printer << ")";
break;
}
Expand Down Expand Up @@ -1464,7 +1467,7 @@ bool DeclAttribute::printImpl(ASTPrinter &Printer, const PrintOptions &Options,
Printer << "availability: ";
auto numAttrs = availAttrs.size();
if (numAttrs == 1) {
printAvailableAttr(availAttrs[0], Printer, Options);
printAvailableAttr(D, availAttrs[0], Printer, Options);
Printer << "; ";
} else {
SmallVector<const DeclAttribute *, 8> tmp(availAttrs.begin(),
Expand Down Expand Up @@ -2223,19 +2226,21 @@ Type RawLayoutAttr::getResolvedCountType(StructDecl *sd) const {

AvailableAttr::AvailableAttr(
SourceLoc AtLoc, SourceRange Range, PlatformKind Platform,
StringRef Message, StringRef Rename, ValueDecl *RenameDecl,
StringRef Message, StringRef Rename,
const llvm::VersionTuple &Introduced, SourceRange IntroducedRange,
const llvm::VersionTuple &Deprecated, SourceRange DeprecatedRange,
const llvm::VersionTuple &Obsoleted, SourceRange ObsoletedRange,
PlatformAgnosticAvailabilityKind PlatformAgnostic, bool Implicit,
bool IsSPI, bool IsForEmbedded)
: DeclAttribute(DeclAttrKind::Available, AtLoc, Range, Implicit),
Message(Message), Rename(Rename), RenameDecl(RenameDecl),
Message(Message), Rename(Rename),
INIT_VER_TUPLE(Introduced), IntroducedRange(IntroducedRange),
INIT_VER_TUPLE(Deprecated), DeprecatedRange(DeprecatedRange),
INIT_VER_TUPLE(Obsoleted), ObsoletedRange(ObsoletedRange) {
Bits.AvailableAttr.Platform = static_cast<uint8_t>(Platform);
Bits.AvailableAttr.PlatformAgnostic = static_cast<uint8_t>(PlatformAgnostic);
Bits.AvailableAttr.HasComputedRenamedDecl = false;
Bits.AvailableAttr.HasRenamedDecl = false;
Bits.AvailableAttr.IsSPI = IsSPI;

if (IsForEmbedded) {
Expand All @@ -2260,22 +2265,10 @@ AvailableAttr::createPlatformAgnostic(ASTContext &C,
assert(!Obsoleted.empty());
}
return new (C) AvailableAttr(
SourceLoc(), SourceRange(), PlatformKind::none, Message, Rename, nullptr,
NoVersion, SourceRange(),
NoVersion, SourceRange(),
Obsoleted, SourceRange(),
Kind, /* isImplicit */ false, /*SPI*/false);
}

AvailableAttr *AvailableAttr::createForAlternative(
ASTContext &C, AbstractFunctionDecl *AsyncFunc) {
llvm::VersionTuple NoVersion;
return new (C) AvailableAttr(
SourceLoc(), SourceRange(), PlatformKind::none, "", "", AsyncFunc,
NoVersion, SourceRange(),
NoVersion, SourceRange(),
NoVersion, SourceRange(),
PlatformAgnosticAvailabilityKind::None, /*Implicit=*/true, /*SPI*/false);
SourceLoc(), SourceRange(), PlatformKind::none, Message, Rename,
/*Introduced=*/NoVersion, SourceRange(), /*Deprecated=*/NoVersion,
SourceRange(), Obsoleted, SourceRange(), Kind, /*Implicit=*/false,
/*SPI=*/false);
}

bool AvailableAttr::isActivePlatform(const ASTContext &ctx) const {
Expand All @@ -2288,19 +2281,16 @@ bool BackDeployedAttr::isActivePlatform(const ASTContext &ctx,
}

AvailableAttr *AvailableAttr::clone(ASTContext &C, bool implicit) const {
return new (C) AvailableAttr(implicit ? SourceLoc() : AtLoc,
implicit ? SourceRange() : getRange(),
getPlatform(), Message, Rename, RenameDecl,
Introduced ? *Introduced : llvm::VersionTuple(),
implicit ? SourceRange() : IntroducedRange,
Deprecated ? *Deprecated : llvm::VersionTuple(),
implicit ? SourceRange() : DeprecatedRange,
Obsoleted ? *Obsoleted : llvm::VersionTuple(),
implicit ? SourceRange() : ObsoletedRange,
getPlatformAgnosticAvailability(),
implicit,
isSPI(),
isForEmbedded());
return new (C) AvailableAttr(
implicit ? SourceLoc() : AtLoc, implicit ? SourceRange() : getRange(),
getPlatform(), Message, Rename,
Introduced ? *Introduced : llvm::VersionTuple(),
implicit ? SourceRange() : IntroducedRange,
Deprecated ? *Deprecated : llvm::VersionTuple(),
implicit ? SourceRange() : DeprecatedRange,
Obsoleted ? *Obsoleted : llvm::VersionTuple(),
implicit ? SourceRange() : ObsoletedRange,
getPlatformAgnosticAvailability(), implicit, isSPI(), isForEmbedded());
}

std::optional<OriginallyDefinedInAttr::ActiveVersion>
Expand Down
22 changes: 11 additions & 11 deletions lib/AST/Availability.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -183,13 +183,10 @@ static AvailableAttr *createAvailableAttr(PlatformKind Platform,
Inferred.Obsoleted.value_or(llvm::VersionTuple());

return new (Context)
AvailableAttr(SourceLoc(), SourceRange(), Platform,
Message, Rename, RenameDecl,
Introduced, /*IntroducedRange=*/SourceRange(),
Deprecated, /*DeprecatedRange=*/SourceRange(),
Obsoleted, /*ObsoletedRange=*/SourceRange(),
Inferred.PlatformAgnostic, /*Implicit=*/true,
Inferred.IsSPI);
AvailableAttr(SourceLoc(), SourceRange(), Platform, Message, Rename,
Introduced, SourceRange(), Deprecated, SourceRange(),
Obsoleted, SourceRange(), Inferred.PlatformAgnostic,
/*Implicit=*/true, Inferred.IsSPI);
}

void AvailabilityInference::applyInferredAvailableAttrs(
Expand Down Expand Up @@ -233,10 +230,8 @@ void AvailabilityInference::applyInferredAvailableAttrs(
if (Message.empty() && !AvAttr->Message.empty())
Message = AvAttr->Message;

if (Rename.empty() && !AvAttr->Rename.empty()) {
if (Rename.empty() && !AvAttr->Rename.empty())
Rename = AvAttr->Rename;
RenameDecl = AvAttr->RenameDecl;
}
}

MergedAttrs.append(PendingAttrs);
Expand All @@ -248,15 +243,20 @@ void AvailabilityInference::applyInferredAvailableAttrs(
}

DeclAttributes &Attrs = ToDecl->getAttrs();
auto *ToValueDecl = dyn_cast<ValueDecl>(ToDecl);

// Create an availability attribute for each observed platform and add
// to ToDecl.
for (auto &Pair : Inferred) {
auto *Attr = createAvailableAttr(Pair.first, Pair.second, Message,
Rename, RenameDecl, Context);

if (Attr)
if (Attr) {
if (RenameDecl && ToValueDecl)
ToValueDecl->setRenamedDecl(Attr, RenameDecl);

Attrs.add(Attr);
}
}
}

Expand Down
47 changes: 28 additions & 19 deletions lib/AST/Decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4231,6 +4231,19 @@ bool ValueDecl::canInferObjCFromRequirement(ValueDecl *requirement) {
return false;
}

ValueDecl *ValueDecl::getRenamedDecl(const AvailableAttr *attr) const {
return evaluateOrDefault(getASTContext().evaluator,
RenamedDeclRequest{this, attr}, nullptr);
}

void ValueDecl::setRenamedDecl(const AvailableAttr *attr,
ValueDecl *renameDecl) const {
// This is only designed to be used with decls synthesized by ClangImporter.
assert(hasClangNode());
getASTContext().evaluator.cacheNonEmptyOutput(RenamedDeclRequest{this, attr},
std::move(renameDecl));
}

SourceLoc Decl::getAttributeInsertionLoc(bool forModifier) const {
// Some decls have a parent/child split where the introducer keyword is on the
// parent, but the attributes are on the children. If this is a child in such
Expand Down Expand Up @@ -9240,30 +9253,26 @@ AbstractFunctionDecl *AbstractFunctionDecl::getAsyncAlternative() const {
if (hasAsync())
return nullptr;

const AvailableAttr *avAttr = nullptr;
// Prefer the first availability attribute with no platform and a valid
// rename target, falling back to the first with a rename. Note that
// `getAttrs` is in reverse source order, so the last attribute is the
// first in source.
AbstractFunctionDecl *alternative = nullptr;
for (const auto *attr : getAttrs().getAttributes<AvailableAttr>()) {
// If there's an attribute with an already-resolved rename decl, use it
if (attr->RenameDecl) {
avAttr = attr;
break;
}
if (attr->isNoAsync())
continue;

if (attr->getPlatform() != PlatformKind::none && alternative != nullptr)
continue;

// Otherwise prefer the first availability attribute with no platform and
// rename parameter, falling back to the first with a rename. Note that
// `getAttrs` is in reverse source order, so the last attribute is the
// first in source
if (!attr->Rename.empty() &&
(attr->getPlatform() == PlatformKind::none || !avAttr) &&
!attr->isNoAsync()) {
avAttr = attr;
if (auto *renamedDecl = getRenamedDecl(attr)) {
if (auto *afd = dyn_cast<AbstractFunctionDecl>(renamedDecl)) {
if (afd->hasAsync())
alternative = afd;
}
}
}

auto *renamedDecl = evaluateOrDefault(
getASTContext().evaluator, RenamedDeclRequest{this, avAttr}, nullptr);
auto *alternative = dyn_cast_or_null<AbstractFunctionDecl>(renamedDecl);
if (!alternative || !alternative->hasAsync())
return nullptr;
return alternative;
}

Expand Down
Loading