Skip to content

AST: Refactor AvailabilityContext into a value type #77144

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 3 commits into from
Oct 22, 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
72 changes: 0 additions & 72 deletions include/swift/AST/Availability.h
Original file line number Diff line number Diff line change
Expand Up @@ -335,78 +335,6 @@ class AvailabilityRange {
}
};

/// An `AvailabilityContext` summarizes the availability constraints for a
/// specific scope, such as within a declaration or at a particular source
/// location in a function body. This context is sufficient to determine whether
/// a declaration is available or not in that scope.
class AvailabilityContext : public llvm::FoldingSetNode {
/// Summarizes platform specific availability constraints.
struct PlatformInfo {
/// The introduction version.
AvailabilityRange Range;

/// Sets `Range` to `other` if `other` is more restrictive. Returns true if
/// any property changed as a result of adding this constraint.
bool constrainRange(const AvailabilityRange &other) {
if (!other.isContainedIn(Range))
return false;

Range = other;
return true;
}

/// Sets `Range` to the platform introduction range of `decl` if that range
/// is more restrictive. Returns true if
/// any property changed as a result of adding this constraint.
bool constrainRange(const Decl *decl);

void Profile(llvm::FoldingSetNodeID &ID) const {
Range.getRawVersionRange().Profile(ID);
}
};
PlatformInfo PlatformAvailability;

AvailabilityContext(const PlatformInfo &platformInfo)
: PlatformAvailability(platformInfo){};

static const AvailabilityContext *get(const PlatformInfo &platformInfo,
ASTContext &ctx);

public:
/// Retrieves the default `AvailabilityContext`, which is maximally available.
/// The platform availability range will be set to the deployment target (or
/// minimum inlining target when applicable).
static const AvailabilityContext *getDefault(ASTContext &ctx);

/// Retrieves a uniqued `AvailabilityContext` with the given platform
/// availability parameters.
static const AvailabilityContext *
get(const AvailabilityRange &platformAvailability, ASTContext &ctx) {
PlatformInfo platformInfo{platformAvailability};
return get(platformInfo, ctx);
}

/// Returns the range of platform versions which may execute code in the
/// availability context, starting at its introduction version.
AvailabilityRange getPlatformRange() const {
return PlatformAvailability.Range;
}

/// Returns the unique context that is the result of constraining the current
/// context's platform availability range with `platformRange`.
const AvailabilityContext *
constrainWithPlatformRange(const AvailabilityRange &platformRange,
ASTContext &ctx) const;

/// Returns the unique context that is the result of constraining the current
/// context both with the availability attributes of `decl` and with
/// `platformRange`.
const AvailabilityContext *constrainWithDeclAndPlatformRange(
Decl *decl, const AvailabilityRange &platformRange) const;

void Profile(llvm::FoldingSetNodeID &ID) const;
};

class AvailabilityInference {
public:
/// Returns the decl that should be considered the parent decl of the given
Expand Down
103 changes: 103 additions & 0 deletions include/swift/AST/AvailabilityContext.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
//===--- AvailabilityContext.h - Swift Availability Structures --*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2024 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This file defines the AvailabilityContext data structure, which summarizes
// availability constraints for a specific scope.
//
//===----------------------------------------------------------------------===//

#ifndef SWIFT_AST_AVAILABILITY_CONTEXT_H
#define SWIFT_AST_AVAILABILITY_CONTEXT_H

#include "swift/AST/Availability.h"
#include "swift/AST/PlatformKind.h"
#include "swift/Basic/LLVM.h"
#include <optional>

namespace swift {
class ASTContext;
class AvailableAttr;
class Decl;

/// An `AvailabilityContext` summarizes the availability constraints for a
/// specific scope, such as within a declaration or at a particular source
/// location in a function body. This context is sufficient to determine whether
/// a declaration is available or not in that scope.
class AvailabilityContext {
public:
class Storage;

private:
struct PlatformInfo;

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

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

public:
AvailabilityContext(const AvailabilityContext &other) : Info(other.Info){};

/// Retrieves the default `AvailabilityContext`, which is maximally available.
/// The platform availability range will be set to the deployment target (or
/// minimum inlining target when applicable).
static AvailabilityContext getDefault(ASTContext &ctx);

/// Retrieves a uniqued `AvailabilityContext` with the given platform
/// availability parameters.
static AvailabilityContext
get(const AvailabilityRange &platformAvailability,
std::optional<PlatformKind> unavailablePlatform, bool deprecated,
ASTContext &ctx);

/// Returns the range of platform versions which may execute code in the
/// availability context, starting at its introduction version.
AvailabilityRange getPlatformRange() const;

/// When the context is unavailable on the current platform this returns the
/// broadest `PlatformKind` for which the context is unavailable. Otherwise,
/// returns `nullopt`.
std::optional<PlatformKind> getUnavailablePlatformKind() const;

/// Returns true if this context is deprecated on the current platform.
bool isDeprecated() const;

/// Constrain the platform availability range with `platformRange`.
void constrainWithPlatformRange(const AvailabilityRange &platformRange,
ASTContext &ctx);

/// Constrain the platform availability range with both the availability
/// attributes of `decl` and with `platformRange`.
void
constrainWithDeclAndPlatformRange(Decl *decl,
const AvailabilityRange &platformRange);

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

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

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

void print(llvm::raw_ostream &os) const;
SWIFT_DEBUG_DUMP;
};

} // end namespace swift

#endif
93 changes: 93 additions & 0 deletions include/swift/AST/AvailabilityContextStorage.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
//===--- AvailabilityContextStorage.h - Swift AvailabilityContext ---------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2024 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This file defines types used in the implementation of AvailabilityContext.
//
//===----------------------------------------------------------------------===//

#ifndef SWIFT_AST_AVAILABILITY_CONTEXT_STORAGE_H
#define SWIFT_AST_AVAILABILITY_CONTEXT_STORAGE_H

#include "swift/AST/AvailabilityContext.h"
#include "llvm/ADT/FoldingSet.h"
#include <optional>

namespace swift {

/// Summarizes platform specific availability constraints.
struct AvailabilityContext::PlatformInfo {
/// The introduction version.
AvailabilityRange Range;

/// When `IsUnavailable` is true, this value stores the broadest platform
/// kind for which the context is unavailable.
PlatformKind UnavailablePlatform;

/// Whether or not the context is considered unavailable on the current
/// platform.
unsigned IsUnavailable : 1;

/// Whether or not the context is considered deprecated on the current
/// platform.
unsigned IsDeprecated : 1;

/// Sets `Range` to `other` if `other` is more restrictive. Returns true if
/// any property changed as a result of adding this constraint.
bool constrainRange(const AvailabilityRange &other) {
if (!other.isContainedIn(Range))
return false;

Range = other;
return true;
}

/// Sets `Range` to the platform introduction range of `decl` if that range
/// is more restrictive. Returns true if
/// any property changed as a result of adding this constraint.
bool constrainRange(const Decl *decl);

/// Updates `UnavailablePlatform` and `IsUnavailable` to reflect the status
/// of `decl` if its platform unavailability is more restrictive. Returns
/// true if any property changed as a result of adding this constraint.
bool constrainUnavailability(const Decl *decl);

/// If `decl` is deprecated, sets `IsDeprecated` to true. Returns true if
/// any property changed as a result of adding this constraint.
bool constrainDeprecated(const Decl *decl);

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

void Profile(llvm::FoldingSetNodeID &ID) const {
Range.getRawVersionRange().Profile(ID);
ID.AddBoolean(IsUnavailable);
ID.AddInteger(static_cast<uint8_t>(UnavailablePlatform));
ID.AddBoolean(IsDeprecated);
}
};

/// 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){};

public:
PlatformInfo Platform;

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

void Profile(llvm::FoldingSetNodeID &ID) const;
};

} // end namespace swift

#endif
27 changes: 14 additions & 13 deletions include/swift/AST/TypeRefinementContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#define SWIFT_TYPEREFINEMENTCONTEXT_H

#include "swift/AST/Availability.h"
#include "swift/AST/AvailabilityContext.h"
#include "swift/AST/Identifier.h"
#include "swift/AST/Stmt.h" // for PoundAvailableInfo
#include "swift/Basic/Debug.h"
Expand Down Expand Up @@ -171,7 +172,7 @@ class TypeRefinementContext : public ASTAllocated<TypeRefinementContext> {

/// A canonical availability info for this context, computed top-down from the
/// root context.
const AvailabilityContext *AvailabilityInfo;
const AvailabilityContext AvailabilityInfo;

std::vector<TypeRefinementContext *> Children;

Expand All @@ -184,33 +185,33 @@ class TypeRefinementContext : public ASTAllocated<TypeRefinementContext> {

TypeRefinementContext(ASTContext &Ctx, IntroNode Node,
TypeRefinementContext *Parent, SourceRange SrcRange,
const AvailabilityContext *Info);
const AvailabilityContext Info);

public:
/// Create the root refinement context for the given SourceFile.
static TypeRefinementContext *
createForSourceFile(SourceFile *SF, const AvailabilityContext *Info);
createForSourceFile(SourceFile *SF, const AvailabilityContext Info);

/// Create a refinement context for the given declaration.
static TypeRefinementContext *createForDecl(ASTContext &Ctx, Decl *D,
TypeRefinementContext *Parent,
const AvailabilityContext *Info,
const AvailabilityContext Info,
SourceRange SrcRange);

/// Create a refinement context for the given declaration.
static TypeRefinementContext *
createForDeclImplicit(ASTContext &Ctx, Decl *D, TypeRefinementContext *Parent,
const AvailabilityContext *Info, SourceRange SrcRange);
const AvailabilityContext Info, SourceRange SrcRange);

/// Create a refinement context for the Then branch of the given IfStmt.
static TypeRefinementContext *
createForIfStmtThen(ASTContext &Ctx, IfStmt *S, TypeRefinementContext *Parent,
const AvailabilityContext *Info);
const AvailabilityContext Info);

/// Create a refinement context for the Else branch of the given IfStmt.
static TypeRefinementContext *
createForIfStmtElse(ASTContext &Ctx, IfStmt *S, TypeRefinementContext *Parent,
const AvailabilityContext *Info);
const AvailabilityContext Info);

/// Create a refinement context for the true-branch control flow to
/// further StmtConditionElements following a #available() query in
Expand All @@ -219,24 +220,24 @@ class TypeRefinementContext : public ASTAllocated<TypeRefinementContext> {
createForConditionFollowingQuery(ASTContext &Ctx, PoundAvailableInfo *PAI,
const StmtConditionElement &LastElement,
TypeRefinementContext *Parent,
const AvailabilityContext *Info);
const AvailabilityContext Info);

/// Create a refinement context for the fallthrough of a GuardStmt.
static TypeRefinementContext *createForGuardStmtFallthrough(
ASTContext &Ctx, GuardStmt *RS, BraceStmt *ContainingBraceStmt,
TypeRefinementContext *Parent, const AvailabilityContext *Info);
TypeRefinementContext *Parent, const AvailabilityContext Info);

/// Create a refinement context for the else branch of a GuardStmt.
static TypeRefinementContext *
createForGuardStmtElse(ASTContext &Ctx, GuardStmt *RS,
TypeRefinementContext *Parent,
const AvailabilityContext *Info);
const AvailabilityContext Info);

/// Create a refinement context for the body of a WhileStmt.
static TypeRefinementContext *
createForWhileStmtBody(ASTContext &Ctx, WhileStmt *WS,
TypeRefinementContext *Parent,
const AvailabilityContext *Info);
const AvailabilityContext Info);

Decl *getDeclOrNull() const {
auto IntroReason = getReason();
Expand Down Expand Up @@ -277,14 +278,14 @@ class TypeRefinementContext : public ASTAllocated<TypeRefinementContext> {
SourceRange getSourceRange() const { return SrcRange; }

/// Returns the availability context of code contained in this context.
const AvailabilityContext *getAvailabilityContext() const {
const AvailabilityContext getAvailabilityContext() const {
return AvailabilityInfo;
}

/// Returns the platform version range that can be assumed present at run
/// time when running code contained in this context.
const AvailabilityRange getPlatformAvailabilityRange() const {
return AvailabilityInfo->getPlatformRange();
return AvailabilityInfo.getPlatformRange();
}

/// Adds a child refinement context.
Expand Down
Loading