Skip to content

Commit 98b34c6

Browse files
committed
Sema: Correctly treat overloads in unavailable extensions as unavailable.
Instead of checking for unavailability attributes directly in the solver, which does not correctly handle members of unavailable extensions, query `checkDeclarationAvailability()` instead. By using the same underlying logic as the availability checker the constraint solver can be confident in the accuracy of this result. Resolves rdar://87403752.
1 parent 26bd056 commit 98b34c6

File tree

4 files changed

+36
-19
lines changed

4 files changed

+36
-19
lines changed

lib/Sema/ConstraintSystem.cpp

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4676,20 +4676,14 @@ void ConstraintSystem::diagnoseFailureFor(SyntacticElementTarget target) {
46764676

46774677
bool ConstraintSystem::isDeclUnavailable(const Decl *D,
46784678
ConstraintLocator *locator) const {
4679-
// First check whether this declaration is universally unavailable.
4680-
if (D->getAttrs().isUnavailable(getASTContext()))
4681-
return true;
4682-
4683-
return TypeChecker::isDeclarationUnavailable(D, DC, [&] {
4684-
SourceLoc loc;
4685-
4686-
if (locator) {
4687-
if (auto anchor = locator->getAnchor())
4688-
loc = getLoc(anchor);
4689-
}
4679+
SourceLoc loc;
4680+
if (locator) {
4681+
if (auto anchor = locator->getAnchor())
4682+
loc = getLoc(anchor);
4683+
}
46904684

4691-
return TypeChecker::overApproximateAvailabilityAtLocation(loc, DC);
4692-
});
4685+
auto availabilityContext = TypeChecker::availabilityAtLocation(loc, DC);
4686+
return checkDeclarationAvailability(D, DC, availabilityContext).has_value();
46934687
}
46944688

46954689
bool ConstraintSystem::isConformanceUnavailable(ProtocolConformanceRef conformance,

lib/Sema/TypeCheckAvailability.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2205,6 +2205,8 @@ diagnosePotentialUnavailability(const ValueDecl *D, SourceRange ReferenceRange,
22052205
const AvailabilityRange &Availability,
22062206
bool WarnBeforeDeploymentTarget = false) {
22072207
ASTContext &Context = ReferenceDC->getASTContext();
2208+
if (Context.LangOpts.DisableAvailabilityChecking)
2209+
return false;
22082210

22092211
bool IsError;
22102212
{
@@ -3100,8 +3102,6 @@ swift::checkDeclarationAvailability(const Decl *decl,
31003102
const DeclContext *declContext,
31013103
AvailabilityContext availabilityContext) {
31023104
auto &ctx = declContext->getASTContext();
3103-
if (ctx.LangOpts.DisableAvailabilityChecking)
3104-
return std::nullopt;
31053105

31063106
// Generic parameters are always available.
31073107
if (isa<GenericTypeParamDecl>(decl))
@@ -4150,6 +4150,7 @@ bool swift::diagnoseDeclAvailability(const ValueDecl *D, SourceRange R,
41504150

41514151
auto *DC = Where.getDeclContext();
41524152
auto &ctx = DC->getASTContext();
4153+
41534154
auto unmetRequirement =
41544155
checkDeclarationAvailability(D, DC, Where.getAvailability());
41554156
auto requiredRange =

test/Constraints/availability.swift

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,3 +64,25 @@ extension Box where T == Int {
6464
// memberwise initializer.
6565
_ = Box(value: 42)
6666
}
67+
68+
// rdar://87403752 - ambiguity with member declared in unavailable extension
69+
struct HasUnavailableExtesion {
70+
}
71+
72+
@available(*, unavailable)
73+
extension HasUnavailableExtesion {
74+
static var foo: Self = HasUnavailableExtesion()
75+
}
76+
77+
func test_contextual_member_with_unavailable_extension() {
78+
struct A {
79+
static var foo: A = A()
80+
}
81+
82+
struct Test {
83+
init(_: A) {}
84+
init(_: HasUnavailableExtesion) {}
85+
}
86+
87+
_ = Test(.foo) // Ok `A.foo` since `foo` from `HasUnavailableExtesion` is unavailable
88+
}

test/embedded/availability.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ public func universally_unavailable() { }
2121
@_unavailableInEmbedded
2222
public func unused() { } // no error
2323

24-
public struct S1 {}
25-
public struct S2 {}
24+
public struct S1 {} // expected-note {{found this candidate}}
25+
public struct S2 {} // expected-note {{found this candidate}}
2626

2727
@_unavailableInEmbedded
2828
public func has_unavailable_in_embedded_overload(_ s1: S1) { }
@@ -47,11 +47,11 @@ public func available(
4747
@_unavailableInEmbedded
4848
public func also_unavailable_in_embedded(
4949
_ uie: UnavailableInEmbedded, // OK
50-
_ uu: UniverallyUnavailable // FIXME: should be an error
50+
_ uu: UniverallyUnavailable // OK
5151
) {
5252
unavailable_in_embedded() // OK
5353
universally_unavailable() // expected-error {{'universally_unavailable()' is unavailable: always unavailable}}
54-
has_unavailable_in_embedded_overload(.init()) // FIXME: should be ambiguous
54+
has_unavailable_in_embedded_overload(.init()) // expected-error {{ambiguous use of 'init()'}}
5555
has_universally_unavailable_overload(.init()) // not ambiguous, selects available overload
5656
}
5757

0 commit comments

Comments
 (0)