Skip to content

Commit 9503df9

Browse files
authored
Merge pull request #78037 from tshortli/introduce-availability-domain
2 parents 5aacff4 + 7cf5d4b commit 9503df9

File tree

6 files changed

+233
-76
lines changed

6 files changed

+233
-76
lines changed
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
//===--- AvailabilityDomain.h - Swift Availability Domains ------*- C++ -*-===//
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 the AvailabilityDomain class, which represents a domain
14+
// for which availability can be checked.
15+
//
16+
//===----------------------------------------------------------------------===//
17+
18+
#ifndef SWIFT_AST_AVAILABILITY_DOMAIN_H
19+
#define SWIFT_AST_AVAILABILITY_DOMAIN_H
20+
21+
#include "swift/AST/PlatformKind.h"
22+
#include "swift/Basic/LLVM.h"
23+
24+
namespace swift {
25+
26+
/// Represents a dimension of availability (e.g. macOS platform or Swift
27+
/// language mode).
28+
class AvailabilityDomain final {
29+
public:
30+
enum class Kind : uint8_t {
31+
/// The root availability domain. This is used for declarations that are
32+
/// universally unavailable or deprecated, for example.
33+
Universal,
34+
35+
/// Represents availability for a specific operating system platform.
36+
Platform,
37+
38+
/// Represents availability with respect to Swift language mode.
39+
SwiftLanguage,
40+
41+
/// Represents PackageDescription availability.
42+
PackageDescription,
43+
};
44+
45+
private:
46+
Kind kind;
47+
PlatformKind platform;
48+
49+
AvailabilityDomain(Kind kind) : kind(kind), platform(PlatformKind::none) {
50+
assert(kind != Kind::Platform);
51+
};
52+
53+
AvailabilityDomain(PlatformKind platform)
54+
: kind(Kind::Platform), platform(platform) {
55+
assert(platform != PlatformKind::none);
56+
};
57+
58+
public:
59+
static AvailabilityDomain forUniversal() {
60+
return AvailabilityDomain(Kind::Universal);
61+
}
62+
63+
static AvailabilityDomain forPlatform(PlatformKind platformKind) {
64+
return AvailabilityDomain(platformKind);
65+
}
66+
67+
static AvailabilityDomain forSwiftLanguage() {
68+
return AvailabilityDomain(Kind::SwiftLanguage);
69+
}
70+
71+
static AvailabilityDomain forPackageDescription() {
72+
return AvailabilityDomain(Kind::PackageDescription);
73+
}
74+
75+
Kind getKind() const { return kind; }
76+
77+
bool isUniversal() const { return kind == Kind::Universal; }
78+
79+
bool isPlatform() const { return kind == Kind::Platform; }
80+
81+
bool isSwiftLanguage() const { return kind == Kind::SwiftLanguage; }
82+
83+
bool isPackageDescription() const { return kind == Kind::PackageDescription; }
84+
85+
/// Returns the platform kind for this domain if applicable.
86+
PlatformKind getPlatformKind() const {
87+
assert(kind == Kind::Platform);
88+
return platform;
89+
}
90+
91+
/// Returns the string to use in diagnostics to identify the domain. May
92+
/// return an empty string.
93+
llvm::StringRef getNameForDiagnostics() const;
94+
95+
/// Returns the string to use when printing an `@available` attribute.
96+
llvm::StringRef getNameForAttributePrinting() const;
97+
};
98+
99+
} // end namespace swift
100+
101+
#endif

include/swift/AST/Decl.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ namespace swift {
6666
class AccessorDecl;
6767
class ApplyExpr;
6868
class AvailabilityRange;
69+
class AvailabilityDomain;
6970
class GenericEnvironment;
7071
class ArchetypeType;
7172
class ASTContext;
@@ -1390,6 +1391,10 @@ class alignas(1 << DeclAlignInBits) Decl : public ASTAllocated<Decl>, public Swi
13901391
/// and its DeclContext does not.
13911392
bool isOutermostPrivateOrFilePrivateScope() const;
13921393

1394+
/// Returns the availability domain associated with the given `AvailableAttr`
1395+
/// that is attached to this decl.
1396+
AvailabilityDomain getDomainForAvailableAttr(const AvailableAttr *attr) const;
1397+
13931398
/// Returns the active platform-specific `@available` attribute for this decl.
13941399
/// There may be multiple `@available` attributes that are relevant to the
13951400
/// current platform, but the returned one has the highest priority.

lib/AST/Attr.cpp

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "swift/AST/Attr.h"
1818
#include "swift/AST/ASTContext.h"
1919
#include "swift/AST/ASTPrinter.h"
20+
#include "swift/AST/AvailabilityDomain.h"
2021
#include "swift/AST/Decl.h"
2122
#include "swift/AST/Expr.h"
2223
#include "swift/AST/GenericEnvironment.h"
@@ -487,36 +488,32 @@ static bool isShortFormAvailabilityImpliedByOther(const AvailableAttr *Attr,
487488
/// @available(iOS, introduced: 8.0)
488489
/// this will print:
489490
/// @available(OSX 10.10, iOS 8.0, *)
490-
static void printShortFormAvailable(ArrayRef<const DeclAttribute *> Attrs,
491+
static void printShortFormAvailable(const Decl *D,
492+
ArrayRef<const DeclAttribute *> Attrs,
491493
ASTPrinter &Printer,
492494
const PrintOptions &Options,
493495
bool forAtSpecialize = false) {
494496
assert(!Attrs.empty());
495497
if (!forAtSpecialize)
496498
Printer << "@available(";
497499
auto FirstAvail = cast<AvailableAttr>(Attrs.front());
498-
if (Attrs.size() == 1 &&
499-
FirstAvail->getPlatformAgnosticAvailability() !=
500-
PlatformAgnosticAvailabilityKind::None) {
500+
auto FirstAvailDomain = D->getDomainForAvailableAttr(FirstAvail);
501+
if (Attrs.size() == 1 && !FirstAvailDomain.isPlatform()) {
501502
assert(FirstAvail->Introduced.has_value());
502-
if (FirstAvail->isLanguageVersionSpecific()) {
503-
Printer << "swift ";
504-
} else {
505-
assert(FirstAvail->isPackageDescriptionVersionSpecific());
506-
Printer << "_PackageDescription ";
507-
}
503+
Printer << FirstAvailDomain.getNameForAttributePrinting() << " ";
508504
Printer << FirstAvail->Introduced.value().getAsString();
509505
if (!forAtSpecialize)
510506
Printer << ")";
511507
} else {
512508
for (auto *DA : Attrs) {
513509
auto *AvailAttr = cast<AvailableAttr>(DA);
510+
auto AvailAttrDomain = D->getDomainForAvailableAttr(AvailAttr);
514511
assert(AvailAttr->Introduced.has_value());
515512
// Avoid omitting available attribute when we are printing module interface.
516513
if (!Options.IsForSwiftInterface &&
517514
isShortFormAvailabilityImpliedByOther(AvailAttr, Attrs))
518515
continue;
519-
Printer << platformString(AvailAttr->getPlatform()) << " "
516+
Printer << AvailAttrDomain.getNameForAttributePrinting() << " "
520517
<< AvailAttr->Introduced.value().getAsString() << ", ";
521518
}
522519
Printer << "*";
@@ -848,11 +845,11 @@ void DeclAttributes::print(ASTPrinter &Printer, const PrintOptions &Options,
848845
}
849846

850847
if (swiftVersionAvailableAttribute)
851-
printShortFormAvailable(swiftVersionAvailableAttribute, Printer, Options);
848+
printShortFormAvailable(D, swiftVersionAvailableAttribute, Printer, Options);
852849
if (packageDescriptionVersionAvailableAttribute)
853-
printShortFormAvailable(packageDescriptionVersionAvailableAttribute, Printer, Options);
850+
printShortFormAvailable(D, packageDescriptionVersionAvailableAttribute, Printer, Options);
854851
if (!shortAvailableAttributes.empty())
855-
printShortFormAvailable(shortAvailableAttributes, Printer, Options);
852+
printShortFormAvailable(D, shortAvailableAttributes, Printer, Options);
856853
if (!backDeployedAttributes.empty())
857854
printShortFormBackDeployed(backDeployedAttributes, Printer, Options);
858855

@@ -901,12 +898,16 @@ ParsedDeclAttrFilter::operator()(const DeclAttribute *Attr) const {
901898
static void printAvailableAttr(const Decl *D, const AvailableAttr *Attr,
902899
ASTPrinter &Printer,
903900
const PrintOptions &Options) {
904-
if (Attr->isLanguageVersionSpecific())
905-
Printer << "swift";
906-
else if (Attr->isPackageDescriptionVersionSpecific())
907-
Printer << "_PackageDescription";
901+
auto Domain = D->getDomainForAvailableAttr(Attr);
902+
903+
// The parser rejects `@available(swift, unavailable)`, so when printing
904+
// attributes that are universally unavailable in Swift, we must print them
905+
// as universally unavailable instead.
906+
// FIXME: Reconsider this, it's a weird special case.
907+
if (Domain.isSwiftLanguage() && Attr->isUnconditionallyUnavailable())
908+
Printer << "*";
908909
else
909-
Printer << Attr->platformString();
910+
Printer << Domain.getNameForAttributePrinting();
910911

911912
if (Attr->isUnconditionallyUnavailable())
912913
Printer << ", unavailable";
@@ -945,8 +946,7 @@ static void printAvailableAttr(const Decl *D, const AvailableAttr *Attr,
945946
if (!Attr->Message.empty()) {
946947
Printer << ", message: ";
947948
Printer.printEscapedStringLiteral(Attr->Message);
948-
} else if (Attr->getPlatformAgnosticAvailability() ==
949-
PlatformAgnosticAvailabilityKind::UnavailableInSwift)
949+
} else if (Domain.isSwiftLanguage() && Attr->isUnconditionallyUnavailable())
950950
Printer << ", message: \"Not available in Swift\"";
951951
}
952952

@@ -1257,7 +1257,7 @@ bool DeclAttribute::printImpl(ASTPrinter &Printer, const PrintOptions &Options,
12571257
} else {
12581258
SmallVector<const DeclAttribute *, 8> tmp(availAttrs.begin(),
12591259
availAttrs.end());
1260-
printShortFormAvailable(tmp, Printer, Options,
1260+
printShortFormAvailable(D, tmp, Printer, Options,
12611261
true /*forAtSpecialize*/);
12621262
Printer << "; ";
12631263
}

lib/AST/AvailabilityDomain.cpp

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
//===--- AvailabilityDomain.cpp - Swift Availability Domains --------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2017 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+
#include "swift/AST/AvailabilityDomain.h"
14+
#include "swift/AST/Decl.h"
15+
16+
using namespace swift;
17+
18+
AvailabilityDomain
19+
Decl::getDomainForAvailableAttr(const AvailableAttr *attr) const {
20+
if (attr->hasPlatform())
21+
return AvailabilityDomain::forPlatform(attr->getPlatform());
22+
23+
switch (attr->getPlatformAgnosticAvailability()) {
24+
case PlatformAgnosticAvailabilityKind::Deprecated:
25+
case PlatformAgnosticAvailabilityKind::Unavailable:
26+
case PlatformAgnosticAvailabilityKind::NoAsync:
27+
case PlatformAgnosticAvailabilityKind::None:
28+
return AvailabilityDomain::forUniversal();
29+
30+
case PlatformAgnosticAvailabilityKind::UnavailableInSwift:
31+
case PlatformAgnosticAvailabilityKind::SwiftVersionSpecific:
32+
return AvailabilityDomain::forSwiftLanguage();
33+
34+
case PlatformAgnosticAvailabilityKind::PackageDescriptionVersionSpecific:
35+
return AvailabilityDomain::forPackageDescription();
36+
}
37+
}
38+
39+
llvm::StringRef AvailabilityDomain::getNameForDiagnostics() const {
40+
switch (kind) {
41+
case Kind::Universal:
42+
return "";
43+
case Kind::Platform:
44+
return swift::prettyPlatformString(getPlatformKind());
45+
case Kind::SwiftLanguage:
46+
return "Swift";
47+
case Kind::PackageDescription:
48+
return "PackageDescription";
49+
}
50+
}
51+
52+
llvm::StringRef AvailabilityDomain::getNameForAttributePrinting() const {
53+
switch (kind) {
54+
case Kind::Universal:
55+
return "*";
56+
case Kind::Platform:
57+
return swift::platformString(getPlatformKind());
58+
case Kind::SwiftLanguage:
59+
return "swift";
60+
case Kind::PackageDescription:
61+
return "_PackageDescription";
62+
}
63+
}

lib/AST/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ add_swift_host_library(swiftAST STATIC
2828
AutoDiff.cpp
2929
Availability.cpp
3030
AvailabilityContext.cpp
31+
AvailabilityDomain.cpp
3132
AvailabilityScope.cpp
3233
AvailabilitySpec.cpp
3334
Builtins.cpp

0 commit comments

Comments
 (0)