Skip to content

AST: Refactor AvailabilityDomain to prepare for external definitions #78627

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
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
108 changes: 96 additions & 12 deletions include/swift/AST/AvailabilityDomain.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@

#include "swift/AST/PlatformKind.h"
#include "swift/Basic/LLVM.h"
#include "llvm/ADT/PointerEmbeddedInt.h"
#include "llvm/ADT/PointerUnion.h"

namespace swift {
class ASTContext;
Expand All @@ -44,17 +46,66 @@ class AvailabilityDomain final {
};

private:
Kind kind;
PlatformKind platform;
friend struct llvm::PointerLikeTypeTraits<AvailabilityDomain>;

/// For a subset of domain kinds, all the information needed to represent the
/// domain can be encapsulated inline in this class.
class InlineDomain {
Kind kind;
PlatformKind platform;

public:
using IntReprType = uint32_t;
enum : uintptr_t {
ReprBits = sizeof(IntReprType) * CHAR_BIT - 8,
KindShift = ReprBits - sizeof(Kind) * CHAR_BIT,
PlatformShift = KindShift - sizeof(PlatformKind) * CHAR_BIT,
};

InlineDomain(Kind kind, PlatformKind platform)
: kind(kind), platform(platform) {};
InlineDomain(IntReprType value)
: kind(static_cast<Kind>(value >> KindShift)),
platform(static_cast<PlatformKind>(value >> PlatformShift)) {}

/// Serializes the domain into an integer value that must be smaller than a
/// a pointer.
IntReprType asInteger() const {
return static_cast<IntReprType>(kind) << KindShift |
static_cast<IntReprType>(platform) << PlatformShift;
}

Kind getKind() const { return kind; }
PlatformKind getPlatform() { return platform; }
};

AvailabilityDomain(Kind kind) : kind(kind), platform(PlatformKind::none) {
/// This will eventually be a class storing information about externally
/// defined availability domains.
using ExternalDomain = void;

using InlineDomainPtr = llvm::PointerEmbeddedInt<uint32_t, InlineDomain::ReprBits>;
using Storage = llvm::PointerUnion<ExternalDomain *, InlineDomainPtr>;
Storage storage;

AvailabilityDomain(Kind kind)
: storage(InlineDomain(kind, PlatformKind::none).asInteger()) {
assert(kind != Kind::Platform);
};

AvailabilityDomain(PlatformKind platform)
: kind(Kind::Platform), platform(platform) {
assert(platform != PlatformKind::none);
};
: storage(InlineDomain(Kind::Platform, platform).asInteger()) {};

AvailabilityDomain(void *opaque)
: storage(Storage::getFromOpaqueValue(opaque)) {};

void *getOpaqueValue() const { return storage.getOpaqueValue(); }

std::optional<InlineDomain> getInlineDomain() const {
return storage.is<InlineDomainPtr>()
? static_cast<std::optional<InlineDomain>>(
storage.get<InlineDomainPtr>())
: std::nullopt;
}

public:
AvailabilityDomain() {}
Expand All @@ -75,18 +126,30 @@ class AvailabilityDomain final {
return AvailabilityDomain(Kind::PackageDescription);
}

Kind getKind() const { return kind; }
Kind getKind() const {
if (auto inlineDomain = getInlineDomain())
return inlineDomain->getKind();

llvm_unreachable("unimplemented");
}

bool isUniversal() const { return kind == Kind::Universal; }
bool isUniversal() const { return getKind() == Kind::Universal; }

bool isPlatform() const { return kind == Kind::Platform; }
bool isPlatform() const { return getKind() == Kind::Platform; }

bool isSwiftLanguage() const { return kind == Kind::SwiftLanguage; }
bool isSwiftLanguage() const { return getKind() == Kind::SwiftLanguage; }

bool isPackageDescription() const { return kind == Kind::PackageDescription; }
bool isPackageDescription() const {
return getKind() == Kind::PackageDescription;
}

/// Returns the platform kind for this domain if applicable.
PlatformKind getPlatformKind() const { return platform; }
PlatformKind getPlatformKind() const {
if (auto inlineDomain = getInlineDomain())
return inlineDomain->getPlatform();

return PlatformKind::none;
}

/// Returns true if this domain is considered active in the current
/// compilation context.
Expand Down Expand Up @@ -136,4 +199,25 @@ class AvailabilityDomain final {

} // end namespace swift

namespace llvm {
// An AvailabilityDomain is "pointer like".
template <typename T>
struct PointerLikeTypeTraits;
template <>
struct PointerLikeTypeTraits<swift::AvailabilityDomain> {
public:
static inline void *getAsVoidPointer(swift::AvailabilityDomain domain) {
return domain.storage.getOpaqueValue();
}
static inline swift::AvailabilityDomain getFromVoidPointer(void *P) {
return swift::AvailabilityDomain(P);
}
enum {
NumLowBitsAvailable = PointerLikeTypeTraits<
swift::AvailabilityDomain::Storage>::NumLowBitsAvailable
};
};

} // end namespace llvm

#endif
1 change: 0 additions & 1 deletion include/swift/AST/AvailabilityScope.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
#include "swift/Basic/LLVM.h"
#include "swift/Basic/STLExtras.h"
#include "swift/Basic/SourceLoc.h"
#include "llvm/ADT/PointerUnion.h"
#include "llvm/Support/ErrorHandling.h"

namespace swift {
Expand Down
6 changes: 3 additions & 3 deletions lib/AST/AvailabilityDomain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
using namespace swift;

bool AvailabilityDomain::isActive(const ASTContext &ctx) const {
switch (kind) {
switch (getKind()) {
case Kind::Universal:
case Kind::SwiftLanguage:
case Kind::PackageDescription:
Expand All @@ -28,7 +28,7 @@ bool AvailabilityDomain::isActive(const ASTContext &ctx) const {
}

llvm::StringRef AvailabilityDomain::getNameForDiagnostics() const {
switch (kind) {
switch (getKind()) {
case Kind::Universal:
return "";
case Kind::SwiftLanguage:
Expand All @@ -41,7 +41,7 @@ llvm::StringRef AvailabilityDomain::getNameForDiagnostics() const {
}

llvm::StringRef AvailabilityDomain::getNameForAttributePrinting() const {
switch (kind) {
switch (getKind()) {
case Kind::Universal:
return "*";
case Kind::SwiftLanguage:
Expand Down