Skip to content

Commit 8534f29

Browse files
authored
Merge pull request #79122 from tshortli/loosen-more-available-than-enclosing-extension
Sema: Loosen more available than enclosing extension diagnostic
2 parents 0c901e8 + aed1a01 commit 8534f29

File tree

5 files changed

+58
-12
lines changed

5 files changed

+58
-12
lines changed

include/swift/AST/Decl.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1437,8 +1437,13 @@ class alignas(1 << DeclAlignInBits) Decl : public ASTAllocated<Decl>, public Swi
14371437

14381438
/// Returns the active platform-specific `@available` attribute that should be
14391439
/// used to determine the platform introduction version of the decl.
1440+
///
1441+
/// If the declaration does not have a platform introduction attribute of its
1442+
/// own and is a member of an extension then the platform introduction
1443+
/// attribute attached to the extension will be returned instead unless \p
1444+
/// checkExtension is false.
14401445
std::optional<SemanticAvailableAttr>
1441-
getAvailableAttrForPlatformIntroduction() const;
1446+
getAvailableAttrForPlatformIntroduction(bool checkExtension = true) const;
14421447

14431448
/// Returns true if the declaration is deprecated at the current deployment
14441449
/// target.

lib/AST/Availability.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -793,7 +793,7 @@ AvailabilityRange AvailabilityInference::annotatedAvailableRangeForAttr(
793793
}
794794

795795
std::optional<SemanticAvailableAttr>
796-
Decl::getAvailableAttrForPlatformIntroduction() const {
796+
Decl::getAvailableAttrForPlatformIntroduction(bool checkExtension) const {
797797
if (auto attr = getDeclAvailableAttrForPlatformIntroduction(this))
798798
return attr;
799799

@@ -804,6 +804,8 @@ Decl::getAvailableAttrForPlatformIntroduction() const {
804804
// if the declaration does not have an explicit @available attribute
805805
// itself. This check relies on the fact that we cannot have nested
806806
// extensions.
807+
if (!checkExtension)
808+
return std::nullopt;
807809

808810
if (auto parent =
809811
AvailabilityInference::parentDeclForInferredAvailability(this)) {

lib/Sema/TypeCheckAttr.cpp

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2338,7 +2338,8 @@ static Decl *getEnclosingDeclForDecl(Decl *D) {
23382338

23392339
static std::optional<std::pair<SemanticAvailableAttr, const Decl *>>
23402340
getSemanticAvailableRangeDeclAndAttr(const Decl *decl) {
2341-
if (auto attr = decl->getAvailableAttrForPlatformIntroduction())
2341+
if (auto attr = decl->getAvailableAttrForPlatformIntroduction(
2342+
/*checkExtension=*/false))
23422343
return std::make_pair(*attr, decl);
23432344

23442345
if (auto *parent =
@@ -2467,12 +2468,6 @@ void AttributeChecker::visitAvailableAttr(AvailableAttr *parsedAttr) {
24672468
// not diagnosed previously, so only emit a warning in that case.
24682469
if (isa<ExtensionDecl>(DC->getTopmostDeclarationDeclContext()))
24692470
limit = DiagnosticBehavior::Warning;
2470-
} else if (enclosingAttr.getPlatform() != attr->getPlatform()) {
2471-
// Downgrade to a warning when the limiting attribute is for a more
2472-
// specific platform.
2473-
if (inheritsAvailabilityFromPlatform(enclosingAttr.getPlatform(),
2474-
attr->getPlatform()))
2475-
limit = DiagnosticBehavior::Warning;
24762471
}
24772472
diagnose(D->isImplicit() ? enclosingDecl->getLoc()
24782473
: parsedAttr->getLocation(),

test/Sema/availability_versions.swift

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1184,9 +1184,14 @@ extension ClassToExtend : ProtocolAvailableOn51 {
11841184
}
11851185

11861186
@available(OSX, introduced: 51)
1187-
extension ClassToExtend { // expected-note {{enclosing scope requires availability of macOS 51 or newer}}
1187+
extension ClassToExtend { // expected-note 2 {{enclosing scope requires availability of macOS 51 or newer}}
11881188
@available(OSX, introduced: 10.9) // expected-error {{instance method cannot be more available than enclosing scope}}
11891189
func extensionMethod10_9() { }
1190+
1191+
struct Nested {
1192+
@available(OSX, introduced: 10.9) // expected-warning {{instance method cannot be more available than enclosing scope}}
1193+
func nestedTypeMethod10_9() { }
1194+
}
11901195
}
11911196

11921197
func usePotentiallyUnavailableExtension() {

test/attr/attr_availability_maccatalyst.swift

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -167,8 +167,8 @@ public extension AvailableOnMacCatalyst { } // ok
167167

168168
@available(iOS, introduced: 14.0)
169169
@available(macCatalyst, introduced: 14.5)
170-
public struct AvailableLaterOnMacCatalyst { // expected-note {{enclosing scope requires availability of Mac Catalyst 14.5 or newer}}
171-
@available(iOS, introduced: 14.0) // expected-warning {{instance method cannot be more available than enclosing scope}}
170+
public struct AvailableLaterOnMacCatalyst { // expected-note 2 {{enclosing scope requires availability of Mac Catalyst 14.5 or newer}}
171+
@available(iOS, introduced: 14.0) // expected-error {{instance method cannot be more available than enclosing scope}}
172172
func iOSOnly() { }
173173

174174
@available(macCatalyst, introduced: 14.5)
@@ -177,4 +177,43 @@ public struct AvailableLaterOnMacCatalyst { // expected-note {{enclosing scope r
177177
@available(iOS, introduced: 14.0)
178178
@available(macCatalyst, introduced: 14.5)
179179
func iOSAndMacCatalyst() { }
180+
181+
struct Nested {
182+
@available(iOS, introduced: 14.0) // expected-error {{instance method cannot be more available than enclosing scope}}
183+
func iOSOnlyNested() { }
184+
185+
@available(macCatalyst, introduced: 14.5)
186+
func macCatalystOnlyNested() { }
187+
188+
@available(iOS, introduced: 14.0)
189+
@available(macCatalyst, introduced: 14.5)
190+
func iOSAndMacCatalystNested() { }
191+
}
192+
}
193+
194+
@available(iOS, introduced: 14.0)
195+
@available(macCatalyst, introduced: 14.5)
196+
extension AvailableLaterOnMacCatalyst { // expected-note 2 {{enclosing scope requires availability of Mac Catalyst 14.5 or newer}}
197+
@available(iOS, introduced: 14.0) // expected-error {{instance method cannot be more available than enclosing scope}}
198+
func iOSOnlyInExtension() { }
199+
200+
@available(macCatalyst, introduced: 14.5)
201+
func macCatalystOnlyInExtension() { }
202+
203+
@available(iOS, introduced: 14.0)
204+
@available(macCatalyst, introduced: 14.5)
205+
func iOSAndMacCatalystInExtension() { }
206+
207+
struct NestedInExtension {
208+
@available(iOS, introduced: 14.0) // expected-warning {{instance method cannot be more available than enclosing scope}}
209+
func iOSOnlyNestedInExtension() { }
210+
211+
@available(macCatalyst, introduced: 14.5)
212+
func macCatalystOnlyNestedInExtension() { }
213+
214+
@available(iOS, introduced: 14.0)
215+
@available(macCatalyst, introduced: 14.5)
216+
func iOSAndMacCatalystNestedInExtension() { }
217+
}
218+
180219
}

0 commit comments

Comments
 (0)