Skip to content

Commit 11abffb

Browse files
committed
AST: Adopt new AvailableAttr constructor in attribute inference.
It was difficult to preserve the existing, buggy behavior of availability attribute inference with respect to attributes specifying availability for non-platform-specific domains. Instead, this change improves attribute merging by tracking every domain independently, and only merging attributes from the same domain.
1 parent 8cd9319 commit 11abffb

File tree

5 files changed

+98
-53
lines changed

5 files changed

+98
-53
lines changed

include/swift/AST/Attr.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -836,6 +836,23 @@ class AvailableAttr : public DeclAttribute {
836836
Bits.AvailableAttr.PlatformAgnostic);
837837
}
838838

839+
/// Returns the kind of availability the attribute specifies.
840+
Kind getKind() const {
841+
switch (getPlatformAgnosticAvailability()) {
842+
case PlatformAgnosticAvailabilityKind::None:
843+
case PlatformAgnosticAvailabilityKind::SwiftVersionSpecific:
844+
case PlatformAgnosticAvailabilityKind::PackageDescriptionVersionSpecific:
845+
return Kind::Default;
846+
case PlatformAgnosticAvailabilityKind::Deprecated:
847+
return Kind::Deprecated;
848+
case PlatformAgnosticAvailabilityKind::UnavailableInSwift:
849+
case PlatformAgnosticAvailabilityKind::Unavailable:
850+
return Kind::Unavailable;
851+
case PlatformAgnosticAvailabilityKind::NoAsync:
852+
return Kind::NoAsync;
853+
}
854+
}
855+
839856
/// Create an `AvailableAttr` that specifies universal unavailability, e.g.
840857
/// `@available(*, unavailable)`.
841858
static AvailableAttr *createUniversallyUnavailable(ASTContext &C,

include/swift/AST/AvailabilityDomain.h

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,14 +33,14 @@ class AvailabilityDomain final {
3333
/// universally unavailable or deprecated, for example.
3434
Universal,
3535

36-
/// Represents availability for a specific operating system platform.
37-
Platform,
38-
3936
/// Represents availability with respect to Swift language mode.
4037
SwiftLanguage,
4138

4239
/// Represents PackageDescription availability.
4340
PackageDescription,
41+
42+
/// Represents availability for a specific operating system platform.
43+
Platform,
4444
};
4545

4646
private:
@@ -98,6 +98,40 @@ class AvailabilityDomain final {
9898

9999
/// Returns the string to use when printing an `@available` attribute.
100100
llvm::StringRef getNameForAttributePrinting() const;
101+
102+
bool operator==(const AvailabilityDomain &other) const {
103+
if (getKind() != other.getKind())
104+
return false;
105+
106+
switch (getKind()) {
107+
case Kind::Universal:
108+
case Kind::SwiftLanguage:
109+
case Kind::PackageDescription:
110+
// These availability domains are singletons.
111+
return true;
112+
case Kind::Platform:
113+
return getPlatformKind() == other.getPlatformKind();
114+
}
115+
}
116+
117+
bool operator!=(const AvailabilityDomain &other) const {
118+
return !(*this == other);
119+
}
120+
121+
bool operator<(const AvailabilityDomain &other) const {
122+
if (getKind() != other.getKind())
123+
return getKind() < other.getKind();
124+
125+
switch (getKind()) {
126+
case Kind::Universal:
127+
case Kind::SwiftLanguage:
128+
case Kind::PackageDescription:
129+
// These availability domains are singletons.
130+
return false;
131+
case Kind::Platform:
132+
return getPlatformKind() < other.getPlatformKind();
133+
}
134+
}
101135
};
102136

103137
} // end namespace swift

lib/AST/Availability.cpp

Lines changed: 26 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -109,12 +109,14 @@ namespace {
109109
/// The inferred availability required to access a group of declarations
110110
/// on a single platform.
111111
struct InferredAvailability {
112-
PlatformAgnosticAvailabilityKind PlatformAgnostic
113-
= PlatformAgnosticAvailabilityKind::None;
112+
AvailableAttr::Kind Kind = AvailableAttr::Kind::Default;
114113

115114
std::optional<llvm::VersionTuple> Introduced;
116115
std::optional<llvm::VersionTuple> Deprecated;
117116
std::optional<llvm::VersionTuple> Obsoleted;
117+
118+
StringRef Message;
119+
StringRef Rename;
118120
bool IsSPI = false;
119121
};
120122

@@ -148,10 +150,9 @@ mergeIntoInferredVersion(const std::optional<llvm::VersionTuple> &Version,
148150
static void mergeWithInferredAvailability(SemanticAvailableAttr Attr,
149151
InferredAvailability &Inferred) {
150152
auto *ParsedAttr = Attr.getParsedAttr();
151-
Inferred.PlatformAgnostic = static_cast<PlatformAgnosticAvailabilityKind>(
152-
std::max(static_cast<unsigned>(Inferred.PlatformAgnostic),
153-
static_cast<unsigned>(
154-
ParsedAttr->getPlatformAgnosticAvailability())));
153+
Inferred.Kind = static_cast<AvailableAttr::Kind>(
154+
std::max(static_cast<unsigned>(Inferred.Kind),
155+
static_cast<unsigned>(ParsedAttr->getKind())));
155156

156157
// The merge of two introduction versions is the maximum of the two versions.
157158
if (mergeIntoInferredVersion(Attr.getIntroduced(), Inferred.Introduced,
@@ -162,21 +163,24 @@ static void mergeWithInferredAvailability(SemanticAvailableAttr Attr,
162163
// The merge of deprecated and obsoleted versions takes the minimum.
163164
mergeIntoInferredVersion(Attr.getDeprecated(), Inferred.Deprecated, std::min);
164165
mergeIntoInferredVersion(Attr.getObsoleted(), Inferred.Obsoleted, std::min);
166+
167+
if (Inferred.Message.empty() && !Attr.getMessage().empty())
168+
Inferred.Message = Attr.getMessage();
169+
170+
if (Inferred.Rename.empty() && !Attr.getRename().empty())
171+
Inferred.Rename = Attr.getRename();
165172
}
166173

167-
/// Create an implicit availability attribute for the given platform
174+
/// Create an implicit availability attribute for the given domain
168175
/// and with the inferred availability.
169-
static AvailableAttr *createAvailableAttr(PlatformKind Platform,
176+
static AvailableAttr *createAvailableAttr(AvailabilityDomain Domain,
170177
const InferredAvailability &Inferred,
171-
StringRef Message,
172-
StringRef Rename,
173-
ValueDecl *RenameDecl,
174178
ASTContext &Context) {
175179
// If there is no information that would go into the availability attribute,
176180
// don't create one.
177-
if (Inferred.PlatformAgnostic == PlatformAgnosticAvailabilityKind::None &&
178-
!Inferred.Introduced && !Inferred.Deprecated && !Inferred.Obsoleted &&
179-
Message.empty() && Rename.empty() && !RenameDecl)
181+
if (Inferred.Kind == AvailableAttr::Kind::Default && !Inferred.Introduced &&
182+
!Inferred.Deprecated && !Inferred.Obsoleted && Inferred.Message.empty() &&
183+
Inferred.Rename.empty())
180184
return nullptr;
181185

182186
llvm::VersionTuple Introduced =
@@ -186,36 +190,26 @@ static AvailableAttr *createAvailableAttr(PlatformKind Platform,
186190
llvm::VersionTuple Obsoleted =
187191
Inferred.Obsoleted.value_or(llvm::VersionTuple());
188192

189-
return new (Context)
190-
AvailableAttr(SourceLoc(), SourceRange(), Platform, Message, Rename,
191-
Introduced, SourceRange(), Deprecated, SourceRange(),
192-
Obsoleted, SourceRange(), Inferred.PlatformAgnostic,
193-
/*Implicit=*/true, Inferred.IsSPI);
193+
return new (Context) AvailableAttr(
194+
SourceLoc(), SourceRange(), Domain, Inferred.Kind, Inferred.Message,
195+
Inferred.Rename, Introduced, SourceRange(), Deprecated, SourceRange(),
196+
Obsoleted, SourceRange(), /*Implicit=*/true, Inferred.IsSPI);
194197
}
195198

196199
void AvailabilityInference::applyInferredAvailableAttrs(
197200
Decl *ToDecl, ArrayRef<const Decl *> InferredFromDecls) {
198201
auto &Context = ToDecl->getASTContext();
199202

200-
// Let the new AvailabilityAttr inherit the message and rename.
201-
// The first encountered message / rename will win; this matches the
202-
// behaviour of diagnostics for 'non-inherited' AvailabilityAttrs.
203-
StringRef Message;
204-
StringRef Rename;
205-
ValueDecl *RenameDecl = nullptr;
206-
207203
// Iterate over the declarations and infer required availability on
208204
// a per-platform basis.
209-
// FIXME: [availability] Generalize to AvailabilityDomain.
210-
std::map<PlatformKind, InferredAvailability> Inferred;
205+
std::map<AvailabilityDomain, InferredAvailability> Inferred;
211206
for (const Decl *D : InferredFromDecls) {
212207
llvm::SmallVector<SemanticAvailableAttr, 8> MergedAttrs;
213208

214209
do {
215210
llvm::SmallVector<SemanticAvailableAttr, 8> PendingAttrs;
216211

217-
for (auto AvAttr :
218-
D->getSemanticAvailableAttrs()) {
212+
for (auto AvAttr : D->getSemanticAvailableAttrs()) {
219213
// Skip an attribute from an outer declaration if it is for a platform
220214
// that was already handled implicitly by an attribute from an inner
221215
// declaration.
@@ -226,14 +220,8 @@ void AvailabilityInference::applyInferredAvailableAttrs(
226220
}))
227221
continue;
228222

229-
mergeWithInferredAvailability(AvAttr, Inferred[AvAttr.getPlatform()]);
223+
mergeWithInferredAvailability(AvAttr, Inferred[AvAttr.getDomain()]);
230224
PendingAttrs.push_back(AvAttr);
231-
232-
if (Message.empty() && !AvAttr.getMessage().empty())
233-
Message = AvAttr.getMessage();
234-
235-
if (Rename.empty() && !AvAttr.getRename().empty())
236-
Rename = AvAttr.getRename();
237225
}
238226

239227
MergedAttrs.append(PendingAttrs);
@@ -245,20 +233,12 @@ void AvailabilityInference::applyInferredAvailableAttrs(
245233
}
246234

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

250237
// Create an availability attribute for each observed platform and add
251238
// to ToDecl.
252239
for (auto &Pair : Inferred) {
253-
auto *Attr = createAvailableAttr(Pair.first, Pair.second, Message,
254-
Rename, RenameDecl, Context);
255-
256-
if (Attr) {
257-
if (RenameDecl && ToValueDecl)
258-
ToValueDecl->setRenamedDecl(Attr, RenameDecl);
259-
240+
if (auto Attr = createAvailableAttr(Pair.first, Pair.second, Context))
260241
Attrs.add(Attr);
261-
}
262242
}
263243
}
264244

lib/AST/AvailabilityDomain.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,24 +31,24 @@ llvm::StringRef AvailabilityDomain::getNameForDiagnostics() const {
3131
switch (kind) {
3232
case Kind::Universal:
3333
return "";
34-
case Kind::Platform:
35-
return swift::prettyPlatformString(getPlatformKind());
3634
case Kind::SwiftLanguage:
3735
return "Swift";
3836
case Kind::PackageDescription:
3937
return "PackageDescription";
38+
case Kind::Platform:
39+
return swift::prettyPlatformString(getPlatformKind());
4040
}
4141
}
4242

4343
llvm::StringRef AvailabilityDomain::getNameForAttributePrinting() const {
4444
switch (kind) {
4545
case Kind::Universal:
4646
return "*";
47-
case Kind::Platform:
48-
return swift::platformString(getPlatformKind());
4947
case Kind::SwiftLanguage:
5048
return "swift";
5149
case Kind::PackageDescription:
5250
return "_PackageDescription";
51+
case Kind::Platform:
52+
return swift::platformString(getPlatformKind());
5353
}
5454
}

test/ModuleInterface/actor_availability.swift

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,20 @@ public actor UnavailableActor {
3939
// CHECK-NEXT: }
4040
}
4141

42+
// CHECK: @_hasMissingDesignatedInitializers @available(*, deprecated, message: "Will be unavailable Swift 6")
43+
// CHECK-NEXT: @available(swift, obsoleted: 6)
44+
// CHECK-NEXT: public actor DeprecatedAndObsoleteInSwift6Actor {
45+
@available(*, deprecated, message: "Will be unavailable Swift 6")
46+
@available(swift, obsoleted: 6)
47+
public actor DeprecatedAndObsoleteInSwift6Actor {
48+
// CHECK: @available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 10.15, *)
49+
// CHECK-NEXT: @available(*, deprecated, message: "Will be unavailable Swift 6")
50+
// CHECK-NEXT: @available(swift, obsoleted: 6)
51+
// CHECK-NEXT: @_semantics("defaultActor") nonisolated final public var unownedExecutor: _Concurrency.UnownedSerialExecutor {
52+
// CHECK-NEXT: get
53+
// CHECK-NEXT: }
54+
}
55+
4256
// CHECK: @available(macOS 10.15.4, iOS 13.4, watchOS 6.2, tvOS 13.4, *)
4357
// CHECK-NEXT: public enum Enum {
4458
@available(SwiftStdlib 5.2, *)

0 commit comments

Comments
 (0)