Skip to content

AST: AvailabilityContext gardening #78788

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 2 commits into from
Jan 22, 2025
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
12 changes: 7 additions & 5 deletions include/swift/AST/AvailabilityContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,14 @@ class AvailabilityContext {
class Storage;

private:
struct PlatformInfo;
class Info;

/// A non-null pointer to uniqued storage for this availability context.
const Storage *Info;
const Storage *storage;

AvailabilityContext(const Storage *info) : Info(info) { assert(info); };
AvailabilityContext(const Storage *storage) : storage(storage) {
assert(storage);
};

/// Retrieves an `AvailabilityContext` with the given platform availability
/// parameters.
Expand Down Expand Up @@ -108,12 +110,12 @@ class AvailabilityContext {

friend bool operator==(const AvailabilityContext &lhs,
const AvailabilityContext &rhs) {
return lhs.Info == rhs.Info;
return lhs.storage == rhs.storage;
}

friend bool operator!=(const AvailabilityContext &lhs,
const AvailabilityContext &rhs) {
return lhs.Info != rhs.Info;
return lhs.storage != rhs.storage;
}

void print(llvm::raw_ostream &os) const;
Expand Down
15 changes: 8 additions & 7 deletions include/swift/AST/AvailabilityContextStorage.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,9 @@

namespace swift {

/// Summarizes platform specific availability constraints.
struct AvailabilityContext::PlatformInfo {
/// Summarizes availability the constraints contained by an AvailabilityContext.
class AvailabilityContext::Info {
public:
/// The introduction version.
AvailabilityRange Range;

Expand All @@ -46,7 +47,7 @@ struct AvailabilityContext::PlatformInfo {
/// Sets each field to the value of the corresponding field in `other` if the
/// other is more restrictive. Returns true if any field changed as a result
/// of adding this constraint.
bool constrainWith(const PlatformInfo &other);
bool constrainWith(const Info &other);

/// Updates each field to reflect the availability of `decl`, if that
/// availability is more restrictive. Returns true if any field was updated.
Expand All @@ -55,7 +56,7 @@ struct AvailabilityContext::PlatformInfo {
bool constrainUnavailability(std::optional<PlatformKind> unavailablePlatform);

/// Returns true if `other` is as available or is more available.
bool isContainedIn(const PlatformInfo &other) const;
bool isContainedIn(const Info &other) const;

void Profile(llvm::FoldingSetNodeID &ID) const {
Range.getRawVersionRange().Profile(ID);
Expand All @@ -69,12 +70,12 @@ struct AvailabilityContext::PlatformInfo {
/// As an implementation detail, the values that make up an `Availability`
/// context are uniqued and stored as folding set nodes.
class AvailabilityContext::Storage final : public llvm::FoldingSetNode {
Storage(const PlatformInfo &platformInfo) : Platform(platformInfo){};
Storage(const Info &info) : info(info){};

public:
PlatformInfo Platform;
Info info;

static const Storage *get(const PlatformInfo &platformInfo, ASTContext &ctx);
static const Storage *get(const Info &info, ASTContext &ctx);

void Profile(llvm::FoldingSetNodeID &ID) const;
};
Expand Down
7 changes: 3 additions & 4 deletions lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5651,10 +5651,9 @@ SubstitutionMap::Storage *SubstitutionMap::Storage::get(
}

const AvailabilityContext::Storage *
AvailabilityContext::Storage::get(const PlatformInfo &platformInfo,
ASTContext &ctx) {
AvailabilityContext::Storage::get(const Info &info, ASTContext &ctx) {
llvm::FoldingSetNodeID id;
platformInfo.Profile(id);
info.Profile(id);

auto &foldingSet =
ctx.getImpl().getArena(AllocationArena::Permanent).AvailabilityContexts;
Expand All @@ -5665,7 +5664,7 @@ AvailabilityContext::Storage::get(const PlatformInfo &platformInfo,

void *mem = ctx.Allocate(sizeof(AvailabilityContext::Storage),
alignof(AvailabilityContext::Storage));
auto *newNode = ::new (mem) AvailabilityContext::Storage(platformInfo);
auto *newNode = ::new (mem) AvailabilityContext::Storage(info);
foldingSet.InsertNode(newNode, insertPos);

return newNode;
Expand Down
76 changes: 40 additions & 36 deletions lib/AST/AvailabilityContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,7 @@ static bool constrainRange(AvailabilityRange &existing,
return true;
}

bool AvailabilityContext::PlatformInfo::constrainWith(
const PlatformInfo &other) {
bool AvailabilityContext::Info::constrainWith(const Info &other) {
bool isConstrained = false;
isConstrained |= constrainRange(Range, other.Range);
if (other.IsUnavailable) {
Expand All @@ -51,7 +50,7 @@ bool AvailabilityContext::PlatformInfo::constrainWith(
return isConstrained;
}

bool AvailabilityContext::PlatformInfo::constrainWith(const Decl *decl) {
bool AvailabilityContext::Info::constrainWith(const Decl *decl) {
bool isConstrained = false;

if (auto range = AvailabilityInference::annotatedAvailableRange(decl))
Expand All @@ -68,7 +67,7 @@ bool AvailabilityContext::PlatformInfo::constrainWith(const Decl *decl) {
return isConstrained;
}

bool AvailabilityContext::PlatformInfo::constrainUnavailability(
bool AvailabilityContext::Info::constrainUnavailability(
std::optional<PlatformKind> unavailablePlatform) {
if (!unavailablePlatform)
return false;
Expand All @@ -94,8 +93,7 @@ bool AvailabilityContext::PlatformInfo::constrainUnavailability(
return true;
}

bool AvailabilityContext::PlatformInfo::isContainedIn(
const PlatformInfo &other) const {
bool AvailabilityContext::Info::isContainedIn(const Info &other) const {
if (!Range.isContainedIn(other.Range))
return false;

Expand All @@ -120,17 +118,17 @@ bool AvailabilityContext::PlatformInfo::isContainedIn(
}

void AvailabilityContext::Storage::Profile(llvm::FoldingSetNodeID &id) const {
Platform.Profile(id);
info.Profile(id);
}

AvailabilityContext
AvailabilityContext::forPlatformRange(const AvailabilityRange &range,
ASTContext &ctx) {
PlatformInfo platformInfo{range, PlatformKind::none,
/*IsUnavailable*/ false,
/*IsUnavailableInEmbedded*/ false,
/*IsDeprecated*/ false};
return AvailabilityContext(Storage::get(platformInfo, ctx));
Info info{range, PlatformKind::none,
/*IsUnavailable*/ false,
/*IsUnavailableInEmbedded*/ false,
/*IsDeprecated*/ false};
return AvailabilityContext(Storage::get(info, ctx));
}

AvailabilityContext AvailabilityContext::forInliningTarget(ASTContext &ctx) {
Expand All @@ -147,40 +145,44 @@ AvailabilityContext
AvailabilityContext::get(const AvailabilityRange &platformAvailability,
std::optional<PlatformKind> unavailablePlatform,
bool deprecated, ASTContext &ctx) {
PlatformInfo platformInfo{platformAvailability,
unavailablePlatform.has_value()
? *unavailablePlatform
: PlatformKind::none,
unavailablePlatform.has_value(),
/*IsUnavailableInEmbedded*/ false, deprecated};
return AvailabilityContext(Storage::get(platformInfo, ctx));
Info info{platformAvailability,
unavailablePlatform.has_value() ? *unavailablePlatform
: PlatformKind::none,
unavailablePlatform.has_value(),
/*IsUnavailableInEmbedded*/ false, deprecated};
return AvailabilityContext(Storage::get(info, ctx));
}

AvailabilityRange AvailabilityContext::getPlatformRange() const {
return Info->Platform.Range;
return storage->info.Range;
}

std::optional<PlatformKind>
AvailabilityContext::getUnavailablePlatformKind() const {
if (Info->Platform.IsUnavailable)
return Info->Platform.UnavailablePlatform;
if (storage->info.IsUnavailable)
return storage->info.UnavailablePlatform;
return std::nullopt;
}

bool AvailabilityContext::isUnavailableInEmbedded() const {
return Info->Platform.IsUnavailableInEmbedded;
return storage->info.IsUnavailableInEmbedded;
}

bool AvailabilityContext::isDeprecated() const {
return Info->Platform.IsDeprecated;
return storage->info.IsDeprecated;
}

void AvailabilityContext::constrainWithContext(const AvailabilityContext &other,
ASTContext &ctx) {
PlatformInfo platformAvailability{Info->Platform};
if (platformAvailability.constrainWith(other.Info->Platform)) {
Info = Storage::get(platformAvailability, ctx);
}
bool isConstrained = false;

Info info{storage->info};
isConstrained |= info.constrainWith(other.storage->info);

if (!isConstrained)
return;

storage = Storage::get(info, ctx);
}

void AvailabilityContext::constrainWithDecl(const Decl *decl) {
Expand All @@ -189,28 +191,30 @@ void AvailabilityContext::constrainWithDecl(const Decl *decl) {

void AvailabilityContext::constrainWithPlatformRange(
const AvailabilityRange &platformRange, ASTContext &ctx) {
PlatformInfo platformAvailability{Info->Platform};
if (!constrainRange(platformAvailability.Range, platformRange))

Info info{storage->info};
if (!constrainRange(info.Range, platformRange))
return;

Info = Storage::get(platformAvailability, ctx);
storage = Storage::get(info, ctx);
}

void AvailabilityContext::constrainWithDeclAndPlatformRange(
const Decl *decl, const AvailabilityRange &platformRange) {
PlatformInfo platformAvailability{Info->Platform};
bool isConstrained = false;
isConstrained |= platformAvailability.constrainWith(decl);
isConstrained |= constrainRange(platformAvailability.Range, platformRange);

Info info{storage->info};
isConstrained |= info.constrainWith(decl);
isConstrained |= constrainRange(info.Range, platformRange);

if (!isConstrained)
return;

Info = Storage::get(platformAvailability, decl->getASTContext());
storage = Storage::get(info, decl->getASTContext());
}

bool AvailabilityContext::isContainedIn(const AvailabilityContext other) const {
if (!Info->Platform.isContainedIn(other.Info->Platform))
if (!storage->info.isContainedIn(other.storage->info))
return false;

return true;
Expand Down