Skip to content

Commit b346385

Browse files
committed
AST: Refactor AvailabilityContext into a value type.
Make the pointer to uniqued storage an implementation detail of an `AvailabilityContext` value. This way clients of `AvailabilityContext` don't need to think about pointers and can have access to mutating operations on a context when appropriate.
1 parent 0730209 commit b346385

7 files changed

+228
-165
lines changed

include/swift/AST/AvailabilityContext.h

+38-92
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
#include "swift/AST/Availability.h"
2222
#include "swift/AST/PlatformKind.h"
2323
#include "swift/Basic/LLVM.h"
24-
#include "llvm/ADT/FoldingSet.h"
2524
#include <optional>
2625

2726
namespace swift {
@@ -33,123 +32,70 @@ class Decl;
3332
/// specific scope, such as within a declaration or at a particular source
3433
/// location in a function body. This context is sufficient to determine whether
3534
/// a declaration is available or not in that scope.
36-
class AvailabilityContext : public llvm::FoldingSetNode {
37-
/// Summarizes platform specific availability constraints.
38-
struct PlatformInfo {
39-
/// The introduction version.
40-
AvailabilityRange Range;
41-
42-
/// When `IsUnavailable` is true, this value stores the broadest platform
43-
/// kind for which the context is unavailable.
44-
PlatformKind UnavailablePlatform;
45-
46-
/// Whether or not the context is considered unavailable on the current
47-
/// platform.
48-
unsigned IsUnavailable : 1;
49-
50-
/// Whether or not the context is considered deprecated on the current
51-
/// platform.
52-
unsigned IsDeprecated : 1;
53-
54-
/// Sets `Range` to `other` if `other` is more restrictive. Returns true if
55-
/// any property changed as a result of adding this constraint.
56-
bool constrainRange(const AvailabilityRange &other) {
57-
if (!other.isContainedIn(Range))
58-
return false;
59-
60-
Range = other;
61-
return true;
62-
}
63-
64-
/// Sets `Range` to the platform introduction range of `decl` if that range
65-
/// is more restrictive. Returns true if
66-
/// any property changed as a result of adding this constraint.
67-
bool constrainRange(const Decl *decl);
68-
69-
/// Updates `UnavailablePlatform` and `IsUnavailable` to reflect the status
70-
/// of `decl` if its platform unavailability is more restrictive. Returns
71-
/// true if any property changed as a result of adding this constraint.
72-
bool constrainUnavailability(const Decl *decl);
73-
74-
/// If `decl` is deprecated, sets `IsDeprecated` to true. Returns true if
75-
/// any property changed as a result of adding this constraint.
76-
bool constrainDeprecated(const Decl *decl);
77-
78-
/// Returns true if `other` is as available or is more available.
79-
bool isContainedIn(const PlatformInfo &other) const;
80-
81-
void Profile(llvm::FoldingSetNodeID &ID) const {
82-
Range.getRawVersionRange().Profile(ID);
83-
ID.AddBoolean(IsUnavailable);
84-
ID.AddInteger(static_cast<uint8_t>(UnavailablePlatform));
85-
ID.AddBoolean(IsDeprecated);
86-
}
87-
};
88-
PlatformInfo PlatformAvailability;
89-
90-
AvailabilityContext(const PlatformInfo &platformInfo)
91-
: PlatformAvailability(platformInfo){};
92-
93-
static const AvailabilityContext *get(const PlatformInfo &platformInfo,
94-
ASTContext &ctx);
35+
class AvailabilityContext {
36+
public:
37+
class Storage;
38+
39+
private:
40+
struct PlatformInfo;
41+
42+
/// A non-null pointer to uniqued storage for this availability context.
43+
const Storage *Info;
44+
45+
AvailabilityContext(const Storage *info) : Info(info) { assert(info); };
9546

9647
public:
48+
AvailabilityContext(const AvailabilityContext &other) : Info(other.Info){};
49+
9750
/// Retrieves the default `AvailabilityContext`, which is maximally available.
9851
/// The platform availability range will be set to the deployment target (or
9952
/// minimum inlining target when applicable).
100-
static const AvailabilityContext *getDefault(ASTContext &ctx);
53+
static AvailabilityContext getDefault(ASTContext &ctx);
10154

10255
/// Retrieves a uniqued `AvailabilityContext` with the given platform
10356
/// availability parameters.
104-
static const AvailabilityContext *
57+
static AvailabilityContext
10558
get(const AvailabilityRange &platformAvailability,
10659
std::optional<PlatformKind> unavailablePlatform, bool deprecated,
107-
ASTContext &ctx) {
108-
PlatformInfo platformInfo{platformAvailability,
109-
unavailablePlatform.has_value()
110-
? *unavailablePlatform
111-
: PlatformKind::none,
112-
unavailablePlatform.has_value(), deprecated};
113-
return get(platformInfo, ctx);
114-
}
60+
ASTContext &ctx);
11561

11662
/// Returns the range of platform versions which may execute code in the
11763
/// availability context, starting at its introduction version.
118-
AvailabilityRange getPlatformRange() const {
119-
return PlatformAvailability.Range;
120-
}
64+
AvailabilityRange getPlatformRange() const;
12165

12266
/// When the context is unavailable on the current platform this returns the
12367
/// broadest `PlatformKind` for which the context is unavailable. Otherwise,
12468
/// returns `nullopt`.
125-
std::optional<PlatformKind> getUnavailablePlatformKind() const {
126-
if (PlatformAvailability.IsUnavailable)
127-
return PlatformAvailability.UnavailablePlatform;
128-
return std::nullopt;
129-
}
69+
std::optional<PlatformKind> getUnavailablePlatformKind() const;
13070

13171
/// Returns true if this context is deprecated on the current platform.
132-
bool isDeprecated() const { return PlatformAvailability.IsDeprecated; }
72+
bool isDeprecated() const;
13373

134-
/// Returns the unique context that is the result of constraining the current
135-
/// context's platform availability range with `platformRange`.
136-
const AvailabilityContext *
137-
constrainWithPlatformRange(const AvailabilityRange &platformRange,
138-
ASTContext &ctx) const;
74+
/// Constrain the platform availability range with `platformRange`.
75+
void constrainWithPlatformRange(const AvailabilityRange &platformRange,
76+
ASTContext &ctx);
13977

140-
/// Returns the unique context that is the result of constraining the current
141-
/// context both with the availability attributes of `decl` and with
142-
/// `platformRange`.
143-
const AvailabilityContext *constrainWithDeclAndPlatformRange(
144-
Decl *decl, const AvailabilityRange &platformRange) const;
78+
/// Constrain the platform availability range with both the availability
79+
/// attributes of `decl` and with `platformRange`.
80+
void
81+
constrainWithDeclAndPlatformRange(Decl *decl,
82+
const AvailabilityRange &platformRange);
14583

14684
/// Returns true if `other` is as available or is more available.
147-
bool isContainedIn(const AvailabilityContext *other) const;
85+
bool isContainedIn(const AvailabilityContext other) const;
86+
87+
friend bool operator==(const AvailabilityContext &lhs,
88+
const AvailabilityContext &rhs) {
89+
return lhs.Info == rhs.Info;
90+
}
91+
92+
friend bool operator!=(const AvailabilityContext &lhs,
93+
const AvailabilityContext &rhs) {
94+
return lhs.Info != rhs.Info;
95+
}
14896

14997
void print(llvm::raw_ostream &os) const;
15098
SWIFT_DEBUG_DUMP;
151-
152-
void Profile(llvm::FoldingSetNodeID &ID) const;
15399
};
154100

155101
} // end namespace swift
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
//===--- AvailabilityContextStorage.h - Swift AvailabilityContext ---------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2024 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
//
13+
// This file defines types used in the implementation of AvailabilityContext.
14+
//
15+
//===----------------------------------------------------------------------===//
16+
17+
#ifndef SWIFT_AST_AVAILABILITY_CONTEXT_STORAGE_H
18+
#define SWIFT_AST_AVAILABILITY_CONTEXT_STORAGE_H
19+
20+
#include "swift/AST/AvailabilityContext.h"
21+
#include "llvm/ADT/FoldingSet.h"
22+
#include <optional>
23+
24+
namespace swift {
25+
26+
/// Summarizes platform specific availability constraints.
27+
struct AvailabilityContext::PlatformInfo {
28+
/// The introduction version.
29+
AvailabilityRange Range;
30+
31+
/// When `IsUnavailable` is true, this value stores the broadest platform
32+
/// kind for which the context is unavailable.
33+
PlatformKind UnavailablePlatform;
34+
35+
/// Whether or not the context is considered unavailable on the current
36+
/// platform.
37+
unsigned IsUnavailable : 1;
38+
39+
/// Whether or not the context is considered deprecated on the current
40+
/// platform.
41+
unsigned IsDeprecated : 1;
42+
43+
/// Sets `Range` to `other` if `other` is more restrictive. Returns true if
44+
/// any property changed as a result of adding this constraint.
45+
bool constrainRange(const AvailabilityRange &other) {
46+
if (!other.isContainedIn(Range))
47+
return false;
48+
49+
Range = other;
50+
return true;
51+
}
52+
53+
/// Sets `Range` to the platform introduction range of `decl` if that range
54+
/// is more restrictive. Returns true if
55+
/// any property changed as a result of adding this constraint.
56+
bool constrainRange(const Decl *decl);
57+
58+
/// Updates `UnavailablePlatform` and `IsUnavailable` to reflect the status
59+
/// of `decl` if its platform unavailability is more restrictive. Returns
60+
/// true if any property changed as a result of adding this constraint.
61+
bool constrainUnavailability(const Decl *decl);
62+
63+
/// If `decl` is deprecated, sets `IsDeprecated` to true. Returns true if
64+
/// any property changed as a result of adding this constraint.
65+
bool constrainDeprecated(const Decl *decl);
66+
67+
/// Returns true if `other` is as available or is more available.
68+
bool isContainedIn(const PlatformInfo &other) const;
69+
70+
void Profile(llvm::FoldingSetNodeID &ID) const {
71+
Range.getRawVersionRange().Profile(ID);
72+
ID.AddBoolean(IsUnavailable);
73+
ID.AddInteger(static_cast<uint8_t>(UnavailablePlatform));
74+
ID.AddBoolean(IsDeprecated);
75+
}
76+
};
77+
78+
/// As an implementation detail, the values that make up an `Availability`
79+
/// context are uniqued and stored as folding set nodes.
80+
class AvailabilityContext::Storage final : public llvm::FoldingSetNode {
81+
Storage(const PlatformInfo &platformInfo) : Platform(platformInfo){};
82+
83+
public:
84+
PlatformInfo Platform;
85+
86+
static const Storage *get(const PlatformInfo &platformInfo, ASTContext &ctx);
87+
88+
void Profile(llvm::FoldingSetNodeID &ID) const;
89+
};
90+
91+
} // end namespace swift
92+
93+
#endif

include/swift/AST/TypeRefinementContext.h

+13-13
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ class TypeRefinementContext : public ASTAllocated<TypeRefinementContext> {
172172

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

177177
std::vector<TypeRefinementContext *> Children;
178178

@@ -185,33 +185,33 @@ class TypeRefinementContext : public ASTAllocated<TypeRefinementContext> {
185185

186186
TypeRefinementContext(ASTContext &Ctx, IntroNode Node,
187187
TypeRefinementContext *Parent, SourceRange SrcRange,
188-
const AvailabilityContext *Info);
188+
const AvailabilityContext Info);
189189

190190
public:
191191
/// Create the root refinement context for the given SourceFile.
192192
static TypeRefinementContext *
193-
createForSourceFile(SourceFile *SF, const AvailabilityContext *Info);
193+
createForSourceFile(SourceFile *SF, const AvailabilityContext Info);
194194

195195
/// Create a refinement context for the given declaration.
196196
static TypeRefinementContext *createForDecl(ASTContext &Ctx, Decl *D,
197197
TypeRefinementContext *Parent,
198-
const AvailabilityContext *Info,
198+
const AvailabilityContext Info,
199199
SourceRange SrcRange);
200200

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

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

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

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

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

230230
/// Create a refinement context for the else branch of a GuardStmt.
231231
static TypeRefinementContext *
232232
createForGuardStmtElse(ASTContext &Ctx, GuardStmt *RS,
233233
TypeRefinementContext *Parent,
234-
const AvailabilityContext *Info);
234+
const AvailabilityContext Info);
235235

236236
/// Create a refinement context for the body of a WhileStmt.
237237
static TypeRefinementContext *
238238
createForWhileStmtBody(ASTContext &Ctx, WhileStmt *WS,
239239
TypeRefinementContext *Parent,
240-
const AvailabilityContext *Info);
240+
const AvailabilityContext Info);
241241

242242
Decl *getDeclOrNull() const {
243243
auto IntroReason = getReason();
@@ -278,14 +278,14 @@ class TypeRefinementContext : public ASTAllocated<TypeRefinementContext> {
278278
SourceRange getSourceRange() const { return SrcRange; }
279279

280280
/// Returns the availability context of code contained in this context.
281-
const AvailabilityContext *getAvailabilityContext() const {
281+
const AvailabilityContext getAvailabilityContext() const {
282282
return AvailabilityInfo;
283283
}
284284

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

291291
/// Adds a child refinement context.

0 commit comments

Comments
 (0)