Skip to content

Commit a3fbe3d

Browse files
committed
AST: Introduce queries on Decl for active @available attrs.
Use these queries to replace some duplicated code. Also, move the `attr_inlinable_available.swift` test to the `Availability` sub-directory since the test has more to do with availability checking than it has to do specifically with the `@inlinable` attr.
1 parent b97df26 commit a3fbe3d

File tree

6 files changed

+84
-37
lines changed

6 files changed

+84
-37
lines changed

include/swift/AST/AvailabilityDomain.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,12 @@ class AvailabilityDomain final {
260260
/// universal domain (`*`) is the bottom element.
261261
bool contains(const AvailabilityDomain &other) const;
262262

263+
/// Returns true if availability in `other` is a subset of availability in
264+
/// this domain or vice-versa.
265+
bool isRelated(const AvailabilityDomain &other) const {
266+
return contains(other) || other.contains(*this);
267+
}
268+
263269
/// Returns true for domains that are not contained by any domain other than
264270
/// the universal domain.
265271
bool isRoot() const;

include/swift/AST/Decl.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1464,6 +1464,27 @@ class alignas(1 << DeclAlignInBits) Decl : public ASTAllocated<Decl>, public Swi
14641464
std::optional<SemanticAvailableAttr>
14651465
getAvailableAttrForPlatformIntroduction(bool checkExtension = true) const;
14661466

1467+
/// Returns true if `decl` has any active `@available` attribute attached to
1468+
/// it.
1469+
bool hasAnyActiveAvailableAttr() const {
1470+
return hasAnyMatchingActiveAvailableAttr(
1471+
[](SemanticAvailableAttr attr) -> bool { return true; });
1472+
}
1473+
1474+
/// Returns true if `predicate` returns true for any active availability
1475+
/// attribute attached to `decl`. The predicate function should accept a
1476+
/// `SemanticAvailableAttr`.
1477+
template <typename F>
1478+
bool hasAnyMatchingActiveAvailableAttr(F predicate) const {
1479+
auto &ctx = getASTContext();
1480+
auto decl = getAbstractSyntaxDeclForAttributes();
1481+
for (auto attr : decl->getSemanticAvailableAttrs()) {
1482+
if (attr.isActive(ctx) && predicate(attr))
1483+
return true;
1484+
}
1485+
return false;
1486+
}
1487+
14671488
/// Returns true if the declaration is deprecated at the current deployment
14681489
/// target.
14691490
bool isDeprecated() const { return getDeprecatedAttr().has_value(); }

lib/AST/AvailabilityScopeBuilder.cpp

Lines changed: 8 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -30,20 +30,6 @@
3030

3131
using namespace swift;
3232

33-
/// Returns true if there is any availability attribute on the declaration
34-
/// that is active.
35-
// FIXME: [availability] De-duplicate this with TypeCheckAvailability.cpp.
36-
static bool hasActiveAvailableAttribute(const Decl *decl, ASTContext &ctx) {
37-
decl = decl->getAbstractSyntaxDeclForAttributes();
38-
39-
for (auto attr : decl->getSemanticAvailableAttrs()) {
40-
if (attr.isActive(ctx))
41-
return true;
42-
}
43-
44-
return false;
45-
}
46-
4733
static bool computeContainedByDeploymentTarget(AvailabilityScope *scope,
4834
ASTContext &ctx) {
4935
return scope->getPlatformAvailabilityRange().isContainedIn(
@@ -397,7 +383,7 @@ class AvailabilityScopeBuilder : private ASTWalker {
397383
return nullptr;
398384

399385
// Declarations with explicit availability attributes always get a scope.
400-
if (hasActiveAvailableAttribute(decl, Context)) {
386+
if (decl->hasAnyActiveAvailableAttr()) {
401387
return AvailabilityScope::createForDecl(
402388
Context, decl, getCurrentScope(),
403389
getEffectiveAvailabilityForDeclSignature(decl),
@@ -423,16 +409,20 @@ class AvailabilityScopeBuilder : private ASTWalker {
423409
getEffectiveAvailabilityForDeclSignature(const Decl *decl) {
424410
auto effectiveIntroduction = AvailabilityRange::alwaysAvailable();
425411

426-
// Availability attributes are found abstract syntax decls.
412+
// Availability attributes are found on abstract syntax decls.
427413
decl = decl->getAbstractSyntaxDeclForAttributes();
428414

429415
// As a special case, extension decls are treated as effectively as
430416
// available as the nominal type they extend, up to the deployment target.
431417
// This rule is a convenience for library authors who have written
432-
// extensions without specifying availabilty on the extension itself.
418+
// extensions without specifying platform availabilty on the extension
419+
// itself.
433420
if (auto *extension = dyn_cast<ExtensionDecl>(decl)) {
434421
auto extendedType = extension->getExtendedType();
435-
if (extendedType && !hasActiveAvailableAttribute(decl, Context)) {
422+
if (extendedType && !decl->hasAnyMatchingActiveAvailableAttr(
423+
[](SemanticAvailableAttr attr) -> bool {
424+
return attr.getDomain().isPlatform();
425+
})) {
436426
effectiveIntroduction.intersectWith(
437427
swift::AvailabilityInference::inferForType(extendedType));
438428

lib/Sema/TypeCheckAvailability.cpp

Lines changed: 7 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -241,20 +241,6 @@ ExportContext::getExportabilityReason() const {
241241
return std::nullopt;
242242
}
243243

244-
/// Returns true if there is any availability attribute on the declaration
245-
/// that is active.
246-
// FIXME: [availability] De-duplicate this with AvailabilityScopeBuilder.cpp.
247-
static bool hasActiveAvailableAttribute(const Decl *D, ASTContext &ctx) {
248-
D = D->getAbstractSyntaxDeclForAttributes();
249-
250-
for (auto Attr : D->getSemanticAvailableAttrs()) {
251-
if (Attr.isActive(ctx))
252-
return true;
253-
}
254-
255-
return false;
256-
}
257-
258244
static bool shouldAllowReferenceToUnavailableInSwiftDeclaration(
259245
const Decl *D, const ExportContext &where) {
260246
auto *DC = where.getDeclContext();
@@ -639,15 +625,18 @@ static void fixAvailabilityForDecl(
639625
const AvailabilityRange &RequiredAvailability, ASTContext &Context) {
640626
assert(D);
641627

642-
// Don't suggest adding an @available() to a declaration where we would
628+
// Don't suggest adding an @available to a declaration where we would
643629
// emit a diagnostic saying it is not allowed.
644630
if (TypeChecker::diagnosticIfDeclCannotBePotentiallyUnavailable(D).has_value())
645631
return;
646632

647-
if (hasActiveAvailableAttribute(D, Context)) {
648-
// For QoI, in future should emit a fixit to update the existing attribute.
633+
// Don't suggest adding an @available attribute to a declaration that already
634+
// has one that is active for the given domain.
635+
// FIXME: Emit a fix-it to adjust the existing attribute instead.
636+
if (D->hasAnyMatchingActiveAvailableAttr([&](SemanticAvailableAttr attr) {
637+
return attr.getDomain().isRelated(Domain);
638+
}))
649639
return;
650-
}
651640

652641
// For some declarations (variables, enum elements), the location in concrete
653642
// syntax to suggest the Fix-It may differ from the declaration to which

test/Availability/availability_scopes.swift

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %target-swift-frontend -typecheck -dump-availability-scopes %s -target %target-cpu-apple-macos50 > %t.dump 2>&1
1+
// RUN: %target-swift-frontend -typecheck -dump-availability-scopes %s -target %target-cpu-apple-macos50 -swift-version 5 > %t.dump 2>&1
22
// RUN: %FileCheck --strict-whitespace %s < %t.dump
33

44
// REQUIRES: OS=macosx
@@ -454,6 +454,23 @@ func deprecatedOnMacOS() {
454454
let x = 1
455455
}
456456

457+
// Since availableOniOS() doesn't have any active @available attributes it
458+
// shouldn't create a scope.
459+
// CHECK-NOT: availableOniOS
460+
461+
@available(iOS, introduced: 53)
462+
func availableOniOS() { }
463+
464+
// CHECK-NEXT: {{^}} (decl version=50 decl=availableInSwift5
465+
466+
@available(swift 5)
467+
func availableInSwift5() { }
468+
469+
// CHECK-NEXT: {{^}} (decl version=50 unavailable=swift decl=availableInSwift6
470+
471+
@available(swift 6)
472+
func availableInSwift6() { }
473+
457474
// CHECK-NEXT: {{^}} (decl version=51 decl=FinalDecl
458475

459476
@available(OSX 51, *)

test/attr/attr_inlinable_available.swift renamed to test/Availability/availability_target_min_inlining.swift

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1292,6 +1292,30 @@ extension BetweenTargets { // expected-note 2 {{add '@available' attribute to en
12921292
) {}
12931293
}
12941294

1295+
@available(iOS 8.0, *)
1296+
extension BetweenTargets { // expected-note 2 {{add '@available' attribute to enclosing extension}}
1297+
public func publicFuncInExtensionWithExplicitiOSAvailability( // expected-note 2 {{add '@available' attribute to enclosing instance method}}
1298+
_: NoAvailable,
1299+
_: BeforeInliningTarget,
1300+
_: AtInliningTarget,
1301+
_: BetweenTargets,
1302+
_: AtDeploymentTarget, // expected-error {{'AtDeploymentTarget' is only available in macOS 10.15 or newer; clients of 'Test' may have a lower deployment target}}
1303+
_: AfterDeploymentTarget // expected-error {{'AfterDeploymentTarget' is only available in macOS 11 or newer}}
1304+
) {}
1305+
}
1306+
1307+
@available(swift 5)
1308+
extension BetweenTargets { // expected-note 2 {{add '@available' attribute to enclosing extension}}
1309+
public func publicFuncInExtensionWithExplicitSwiftAvailability( // expected-note 2 {{add '@available' attribute to enclosing instance method}}
1310+
_: NoAvailable,
1311+
_: BeforeInliningTarget,
1312+
_: AtInliningTarget,
1313+
_: BetweenTargets,
1314+
_: AtDeploymentTarget, // expected-error {{'AtDeploymentTarget' is only available in macOS 10.15 or newer; clients of 'Test' may have a lower deployment target}}
1315+
_: AfterDeploymentTarget // expected-error {{'AfterDeploymentTarget' is only available in macOS 11 or newer}}
1316+
) {}
1317+
}
1318+
12951319
@available(macOS 10.15, *)
12961320
extension BetweenTargets {
12971321
public func publicFuncInExtensionWithExplicitAvailability( // expected-note {{add '@available' attribute to enclosing instance method}}

0 commit comments

Comments
 (0)