Skip to content

Commit ec85589

Browse files
authored
Merge pull request #77720 from tshortli/remove-get-potentially-unavailable
AST: Remove `DeclAttributes::getPotentiallyUnavailable()`
2 parents a8a8eaf + b3f6421 commit ec85589

11 files changed

+159
-91
lines changed

include/swift/AST/Attr.h

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2932,11 +2932,6 @@ class DeclAttributes {
29322932
findMostSpecificActivePlatform(const ASTContext &ctx,
29332933
bool ignoreAppExtensions = false) const;
29342934

2935-
/// Returns the first @available attribute that indicates
2936-
/// a declaration is unavailable, or the first one that indicates it's
2937-
/// potentially unavailable, or null otherwise.
2938-
const AvailableAttr *getPotentiallyUnavailable(const ASTContext &ctx) const;
2939-
29402935
/// Returns the first @available attribute that indicates
29412936
/// a declaration is unavailable, or null otherwise.
29422937
const AvailableAttr *getUnavailable(const ASTContext &ctx,

include/swift/AST/AvailabilityConstraint.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,10 @@ class AvailabilityConstraint {
8787
Kind getKind() const { return kind; }
8888
const AvailableAttr *getAttr() const { return attr; }
8989

90+
/// Returns the platform that this constraint applies to, or
91+
/// `PlatformKind::none` if it is not platform specific.
92+
PlatformKind getPlatform() const;
93+
9094
/// Returns the required range for `IntroducedInNewerVersion` requirements, or
9195
/// `std::nullopt` otherwise.
9296
std::optional<AvailabilityRange>
@@ -95,6 +99,10 @@ class AvailabilityConstraint {
9599
/// Returns true if this unmet requirement can be satisfied by introducing an
96100
/// `if #available(...)` condition in source.
97101
bool isConditionallySatisfiable() const;
102+
103+
/// Some availability constraints are active for type-checking but cannot
104+
/// be translated directly into an `if #available(...)` runtime query.
105+
bool isActiveForRuntimeQueries(ASTContext &ctx) const;
98106
};
99107

100108
} // end namespace swift

include/swift/AST/AvailabilityContext.h

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -44,18 +44,27 @@ class AvailabilityContext {
4444

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

47-
/// Retrieves a uniqued `AvailabilityContext` with the given platform
48-
/// availability parameters.
47+
/// Retrieves an `AvailabilityContext` with the given platform availability
48+
/// parameters.
4949
static AvailabilityContext
5050
get(const AvailabilityRange &platformAvailability,
5151
std::optional<PlatformKind> unavailablePlatform, bool deprecated,
5252
ASTContext &ctx);
5353

5454
public:
55-
/// Retrieves the default `AvailabilityContext`, which is maximally available.
56-
/// The platform availability range will be set to the deployment target (or
57-
/// minimum inlining target when applicable).
58-
static AvailabilityContext getDefault(ASTContext &ctx);
55+
/// Retrieves an `AvailabilityContext` constrained by the given platform
56+
/// availability range.
57+
static AvailabilityContext forPlatformRange(const AvailabilityRange &range,
58+
ASTContext &ctx);
59+
60+
/// Retrieves the maximally available `AvailabilityContext` for the
61+
/// compilation. The platform availability range will be set to the minimum
62+
/// inlining target (which may just be the deployment target).
63+
static AvailabilityContext forInliningTarget(ASTContext &ctx);
64+
65+
/// Retrieves an `AvailabilityContext` with the platform availability range
66+
/// set to the deployment target.
67+
static AvailabilityContext forDeploymentTarget(ASTContext &ctx);
5968

6069
/// Returns the range of platform versions which may execute code in the
6170
/// availability context, starting at its introduction version.

lib/AST/Attr.cpp

Lines changed: 0 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -427,48 +427,6 @@ DeclAttributes::findMostSpecificActivePlatform(const ASTContext &ctx,
427427
return bestAttr;
428428
}
429429

430-
const AvailableAttr *
431-
DeclAttributes::getPotentiallyUnavailable(const ASTContext &ctx) const {
432-
const AvailableAttr *potential = nullptr;
433-
const AvailableAttr *conditional = nullptr;
434-
435-
for (auto Attr : *this)
436-
if (auto AvAttr = dyn_cast<AvailableAttr>(Attr)) {
437-
if (AvAttr->isInvalid())
438-
continue;
439-
440-
if (!AvAttr->isActivePlatform(ctx) &&
441-
!AvAttr->isLanguageVersionSpecific() &&
442-
!AvAttr->isPackageDescriptionVersionSpecific())
443-
continue;
444-
445-
// Definitely not available.
446-
if (AvAttr->isUnconditionallyUnavailable())
447-
return AvAttr;
448-
449-
switch (AvAttr->getVersionAvailability(ctx)) {
450-
case AvailableVersionComparison::Available:
451-
// Doesn't limit the introduced version.
452-
break;
453-
454-
case AvailableVersionComparison::PotentiallyUnavailable:
455-
// We'll return this if we don't see something that proves it's
456-
// not available in this version.
457-
potential = AvAttr;
458-
break;
459-
460-
case AvailableVersionComparison::Unavailable:
461-
case AvailableVersionComparison::Obsoleted:
462-
conditional = AvAttr;
463-
break;
464-
}
465-
}
466-
467-
if (conditional)
468-
return conditional;
469-
return potential;
470-
}
471-
472430
const AvailableAttr *
473431
DeclAttributes::getUnavailable(const ASTContext &ctx,
474432
bool ignoreAppExtensions) const {

lib/AST/Availability.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,10 @@ AvailabilityRange AvailabilityRange::forRuntimeTarget(const ASTContext &Ctx) {
6565
return AvailabilityRange(VersionRange::allGTE(Ctx.LangOpts.RuntimeVersion));
6666
}
6767

68+
PlatformKind AvailabilityConstraint::getPlatform() const {
69+
return attr->Platform;
70+
}
71+
6872
std::optional<AvailabilityRange>
6973
AvailabilityConstraint::getRequiredNewerAvailabilityRange(
7074
ASTContext &ctx) const {
@@ -89,6 +93,15 @@ bool AvailabilityConstraint::isConditionallySatisfiable() const {
8993
}
9094
}
9195

96+
bool AvailabilityConstraint::isActiveForRuntimeQueries(ASTContext &ctx) const {
97+
if (attr->Platform == PlatformKind::none)
98+
return true;
99+
100+
return swift::isPlatformActive(attr->Platform, ctx.LangOpts,
101+
/*forTargetVariant=*/false,
102+
/*forRuntimeQuery=*/true);
103+
}
104+
92105
namespace {
93106

94107
/// The inferred availability required to access a group of declarations

lib/AST/AvailabilityContext.cpp

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -124,15 +124,26 @@ void AvailabilityContext::Storage::Profile(llvm::FoldingSetNodeID &id) const {
124124
Platform.Profile(id);
125125
}
126126

127-
AvailabilityContext AvailabilityContext::getDefault(ASTContext &ctx) {
128-
PlatformInfo platformInfo{AvailabilityRange::forInliningTarget(ctx),
129-
PlatformKind::none,
127+
AvailabilityContext
128+
AvailabilityContext::forPlatformRange(const AvailabilityRange &range,
129+
ASTContext &ctx) {
130+
PlatformInfo platformInfo{range, PlatformKind::none,
130131
/*IsUnavailable*/ false,
131132
/*IsUnavailableInEmbedded*/ false,
132133
/*IsDeprecated*/ false};
133134
return AvailabilityContext(Storage::get(platformInfo, ctx));
134135
}
135136

137+
AvailabilityContext AvailabilityContext::forInliningTarget(ASTContext &ctx) {
138+
return AvailabilityContext::forPlatformRange(
139+
AvailabilityRange::forInliningTarget(ctx), ctx);
140+
}
141+
142+
AvailabilityContext AvailabilityContext::forDeploymentTarget(ASTContext &ctx) {
143+
return AvailabilityContext::forPlatformRange(
144+
AvailabilityRange::forDeploymentTarget(ctx), ctx);
145+
}
146+
136147
AvailabilityContext
137148
AvailabilityContext::get(const AvailabilityRange &platformAvailability,
138149
std::optional<PlatformKind> unavailablePlatform,

lib/Sema/DerivedConformanceRawRepresentable.cpp

Lines changed: 24 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,18 @@
1616
//===----------------------------------------------------------------------===//
1717

1818
#include "CodeSynthesis.h"
19+
#include "DerivedConformances.h"
20+
#include "TypeCheckAvailability.h"
21+
#include "TypeCheckDecl.h"
1922
#include "TypeChecker.h"
2023
#include "swift/AST/Decl.h"
21-
#include "swift/AST/Stmt.h"
2224
#include "swift/AST/Expr.h"
23-
#include "swift/AST/Pattern.h"
2425
#include "swift/AST/ParameterList.h"
26+
#include "swift/AST/Pattern.h"
27+
#include "swift/AST/Stmt.h"
2528
#include "swift/AST/Types.h"
2629
#include "swift/Basic/Assertions.h"
2730
#include "llvm/ADT/APInt.h"
28-
#include "DerivedConformances.h"
29-
#include "TypeCheckDecl.h"
3031

3132
using namespace swift;
3233

@@ -236,38 +237,35 @@ struct RuntimeVersionCheck {
236237
/// information about the runtime check needed to ensure it is available to
237238
/// \c versionCheck and returns true.
238239
static bool
239-
checkAvailability(const EnumElementDecl *elt, ASTContext &C,
240+
checkAvailability(const EnumElementDecl *elt, DeclContext *dc,
241+
AvailabilityContext availabilityContext,
240242
std::optional<RuntimeVersionCheck> &versionCheck) {
241-
auto *attr = elt->getAttrs().getPotentiallyUnavailable(C);
243+
auto &C = dc->getASTContext();
244+
auto constraint =
245+
getUnsatisfiedAvailabilityConstraint(elt, dc, availabilityContext);
242246

243247
// Is it always available?
244-
if (!attr)
248+
if (!constraint)
245249
return true;
246250

247-
// For type-checking purposes, iOS availability is inherited for visionOS
248-
// targets. However, it is not inherited for the sake of code-generation
249-
// of runtime availability queries, and is assumed to be available.
250-
if ((attr->Platform == PlatformKind::iOS ||
251-
attr->Platform == PlatformKind::iOSApplicationExtension) &&
252-
C.LangOpts.Target.isXROS())
251+
// Some constraints are active for type checking but can't translate to
252+
// runtime restrictions.
253+
if (!constraint->isActiveForRuntimeQueries(C))
253254
return true;
254255

255-
AvailableVersionComparison availability = attr->getVersionAvailability(C);
256-
257-
assert(availability != AvailableVersionComparison::Available &&
258-
"DeclAttributes::getPotentiallyUnavailable() shouldn't "
259-
"return an available attribute");
260-
261256
// Is it never available?
262-
if (availability != AvailableVersionComparison::PotentiallyUnavailable)
257+
if (!constraint->isConditionallySatisfiable())
263258
return false;
264259

265260
// It's conditionally available; create a version constraint and return true.
266-
assert(attr->getPlatformAgnosticAvailability() ==
267-
PlatformAgnosticAvailabilityKind::None &&
268-
"can only express #available(somePlatform version) checks");
269-
versionCheck.emplace(attr->Platform, *attr->Introduced);
261+
auto platform = constraint->getPlatform();
262+
auto range = constraint->getRequiredNewerAvailabilityRange(C);
263+
264+
// Only platform version constraints are supported currently.
265+
ASSERT(platform != PlatformKind::none);
266+
ASSERT(range);
270267

268+
versionCheck.emplace(platform, range->getRawMinimumVersion());
271269
return true;
272270
}
273271

@@ -294,6 +292,7 @@ deriveBodyRawRepresentable_init(AbstractFunctionDecl *initDecl, void *) {
294292

295293
auto parentDC = initDecl->getDeclContext();
296294
ASTContext &C = parentDC->getASTContext();
295+
auto availabilityContext = AvailabilityContext::forDeploymentTarget(C);
297296

298297
auto nominalTypeDecl = parentDC->getSelfNominalTypeDecl();
299298
auto enumDecl = cast<EnumDecl>(nominalTypeDecl);
@@ -317,7 +316,7 @@ deriveBodyRawRepresentable_init(AbstractFunctionDecl *initDecl, void *) {
317316
// information about that check in versionCheck and keep processing this
318317
// element.
319318
std::optional<RuntimeVersionCheck> versionCheck(std::nullopt);
320-
if (!checkAvailability(elt, C, versionCheck))
319+
if (!checkAvailability(elt, parentDC, availabilityContext, versionCheck))
321320
continue;
322321

323322
// litPat = elt.rawValueExpr as a pattern

lib/Sema/TypeCheckAvailability.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1428,7 +1428,7 @@ void TypeChecker::buildAvailabilityScopes(SourceFile &SF) {
14281428
// The root availability scope reflects the fact that all parts of
14291429
// the source file are guaranteed to be executing on at least the minimum
14301430
// platform version for inlining.
1431-
auto AvailabilityContext = AvailabilityContext::getDefault(Context);
1431+
auto AvailabilityContext = AvailabilityContext::forInliningTarget(Context);
14321432
AvailabilityScope *RootScope =
14331433
AvailabilityScope::createForSourceFile(&SF, AvailabilityContext);
14341434
SF.setAvailabilityScope(RootScope);
@@ -1493,7 +1493,7 @@ TypeChecker::availabilityAtLocation(SourceLoc loc, const DeclContext *DC,
14931493
// this will be a real problem.
14941494

14951495
// We can assume we are running on at least the minimum inlining target.
1496-
auto baseAvailability = AvailabilityContext::getDefault(Context);
1496+
auto baseAvailability = AvailabilityContext::forInliningTarget(Context);
14971497
auto isInvalidLoc = [SF](SourceLoc loc) {
14981498
return SF ? loc.isInvalid() : true;
14991499
};

test/SILGen/enum_raw_representable_available.swift

Lines changed: 46 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,20 @@
11
// RUN: %target-typecheck-verify-swift -target %target-cpu-apple-macosx10.52
22

3-
// RUN: %target-swift-emit-silgen -target %target-cpu-apple-macosx10.52 -emit-sorted-sil -o %t.fragile.sil %s
4-
// RUN: %FileCheck %s < %t.fragile.sil
5-
// RUN: %FileCheck -check-prefix NEGATIVE %s < %t.fragile.sil
3+
// RUN: %target-swift-emit-silgen -target %target-cpu-apple-macosx10.52 -emit-sorted-sil %s -o %t.fragile.sil
4+
// RUN: %FileCheck -check-prefixes=CHECK,CHECK-NO-EXTENSION %s < %t.fragile.sil
5+
// RUN: %FileCheck -check-prefixes=NEGATIVE,NEGATIVE-NO-EXTENSION %s < %t.fragile.sil
66

7-
// RUN: %target-swift-emit-silgen -target %target-cpu-apple-macosx10.52 -emit-sorted-sil -enable-library-evolution -o %t.resilient.sil %s
8-
// RUN: %FileCheck %s < %t.resilient.sil
9-
// RUN: %FileCheck -check-prefix NEGATIVE %s < %t.resilient.sil
7+
// RUN: %target-swift-emit-silgen -target %target-cpu-apple-macosx10.52 -emit-sorted-sil %s -o %t.extensions-fragile.sil -application-extension
8+
// RUN: %FileCheck -check-prefixes=CHECK,CHECK-EXTENSION %s < %t.extensions-fragile.sil
9+
// RUN: %FileCheck -check-prefixes=NEGATIVE,NEGATIVE-EXTENSION %s < %t.extensions-fragile.sil
10+
11+
// RUN: %target-swift-emit-silgen -target %target-cpu-apple-macosx10.52 -emit-sorted-sil %s -enable-library-evolution -o %t.resilient.sil
12+
// RUN: %FileCheck -check-prefixes=CHECK,CHECK-NO-EXTENSION %s < %t.resilient.sil
13+
// RUN: %FileCheck -check-prefixes=NEGATIVE,NEGATIVE-NO-EXTENSION %s < %t.resilient.sil
14+
15+
// RUN: %target-swift-emit-silgen -target %target-cpu-apple-macosx10.52 -emit-sorted-sil %s -enable-library-evolution -o %t.extensions-resilient.sil -application-extension
16+
// RUN: %FileCheck -check-prefixes=CHECK,CHECK-EXTENSION %s < %t.extensions-resilient.sil
17+
// RUN: %FileCheck -check-prefixes=NEGATIVE,NEGATIVE-EXTENSION %s < %t.extensions-resilient.sil
1018

1119
// This test just requires a platform with meaningful #available() checks, but
1220
// for simplicity, it's written for macOS only.
@@ -25,9 +33,15 @@ public enum E: Int {
2533
@available(macOS 10.55, *)
2634
case potentiallyUnavailable = -3000
2735

36+
@available(macOSApplicationExtension 10.56, *)
37+
case potentiallyUnavailableForExtensions = -3001
38+
2839
@available(macOS, unavailable)
2940
case neverAvailable = -4000
3041

42+
@available(macOSApplicationExtension, unavailable)
43+
case neverAvailableForExtensions = -4001
44+
3145
@available(macOS, obsoleted: 10.99)
3246
case notObsoleteYet = -5000
3347

@@ -46,13 +60,36 @@ public enum E: Int {
4660
// CHECK: integer_literal $Builtin.IntLiteral, -3000
4761
// CHECK: cond_br {{[^,]+}}, [[potentiallyUnavailable:bb[0-9]+]]
4862

63+
// CHECK: integer_literal $Builtin.IntLiteral, -3001
64+
// CHECK: cond_br {{[^,]+}}, [[potentiallyUnavailableForExtensions:bb[0-9]+]]
65+
66+
// CHECK-NO-EXTENSION: integer_literal $Builtin.IntLiteral, -4001
67+
// CHECK-NO-EXTENSION: cond_br {{[^,]+}}, [[neverAvailableForExtensions:bb[0-9]+]]
68+
4969
// CHECK: integer_literal $Builtin.IntLiteral, -5000
5070
// CHECK: cond_br {{[^,]+}}, [[notObsoleteYet:bb[0-9]+]]
5171

5272
// CHECK: [[notObsoleteYet]]:
5373
// CHECK-NOT: function_ref @$ss26_stdlib_isOSVersionAtLeastyBi1_Bw_BwBwtF
5474
// CHECK: {{enum \$E|inject_enum_addr %[0-9]+ : \$\*E}}, #E.notObsoleteYet!enumelt
5575

76+
// CHECK-NO-EXTENSION: [[neverAvailableForExtensions]]:
77+
// CHECK-NO-EXTENSION-NOT: function_ref @$ss26_stdlib_isOSVersionAtLeastyBi1_Bw_BwBwtF
78+
// CHECK-NO-EXTENSION: {{enum \$E|inject_enum_addr %[0-9]+ : \$\*E}}, #E.neverAvailableForExtensions!enumelt
79+
80+
// CHECK: [[potentiallyUnavailableForExtensions]]:
81+
// CHECK-NO-EXTENSION-NOT: function_ref @$ss26_stdlib_isOSVersionAtLeastyBi1_Bw_BwBwtF
82+
// CHECK-NO-EXTENSION: {{enum \$E|inject_enum_addr %[0-9]+ : \$\*E}}, #E.potentiallyUnavailableForExtensions!enumelt
83+
// CHECK-EXTENSION-NEXT: extend_lifetime
84+
// CHECK-EXTENSION-NEXT: integer_literal $Builtin.Word, 10
85+
// CHECK-EXTENSION-NEXT: integer_literal $Builtin.Word, 56
86+
// CHECK-EXTENSION-NEXT: integer_literal $Builtin.Word, 0
87+
// CHECK-EXTENSION: function_ref @$ss26_stdlib_isOSVersionAtLeastyBi1_Bw_BwBwtF
88+
// CHECK-EXTENSION: cond_br {{[^,]+}}, [[potentiallyUnavailableForExtensions_newEnough:bb[0-9]+]],
89+
90+
// CHECK-EXTENSION: [[potentiallyUnavailableForExtensions_newEnough]]:
91+
// CHECK-EXTENSION: {{enum \$E|inject_enum_addr %[0-9]+ : \$\*E}}, #E.potentiallyUnavailableForExtensions!enumelt
92+
5693
// CHECK: [[potentiallyUnavailable]]:
5794
// CHECK-NEXT: extend_lifetime
5895
// CHECK-NEXT: integer_literal $Builtin.Word, 10
@@ -84,6 +121,9 @@ public enum E: Int {
84121
// Should not try to match neverAvailable's raw value
85122
// NEGATIVE-NOT: integer_literal $Builtin.IntLiteral, -4000
86123

124+
// When building with -application-extension, should not try to match neverAvailableForExtensions's raw value
125+
// NEGATIVE-EXTENSION-NOT: integer_literal $Builtin.IntLiteral, -4001
126+
87127
// Should not try to match nowObsolete's raw value
88128
// NEGATIVE-NOT: integer_literal $Builtin.IntLiteral, -6000
89129

test/SILGen/visionos_available_rawvalue_enum.swift renamed to test/SILGen/enum_raw_representable_available_visionos.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
// RUN: cp -r %test-resource-dir/xros/Swift.swiftmodule %t/mock-sdk/usr/lib/swift/Swift.swiftmodule
55
// RUN: cp %S/Inputs/mock-visionos-sdk/SDKSettings.json %t/mock-sdk/SDKSettings.json
66
// RUN: %swift -emit-sil -parse-as-library %s -target arm64-apple-xros1.0 -sdk %t/mock-sdk -I %t/mock-sdk/usr/lib/swift/ -verify
7-
// RUN: %swift -emit-silgen -parse-as-library %s -target arm64-apple-xros1.0 -sdk %t/mock-sdk -I %t/mock-sdk/usr/lib/swift/ -o %t/ios_available_rawvalue_enum_on_visionos.sil
8-
// RUN: %FileCheck %s < %t/ios_available_rawvalue_enum_on_visionos.sil
7+
// RUN: %swift -emit-silgen -parse-as-library %s -target arm64-apple-xros1.0 -sdk %t/mock-sdk -I %t/mock-sdk/usr/lib/swift/ -o %t/output.sil
8+
// RUN: %FileCheck %s < %t/output.sil
99

1010
// REQUIRES: OS=xros
1111

0 commit comments

Comments
 (0)