Skip to content

Sema: Correctly treat overloads in unavailable extensions as unavailable #77258

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 7 additions & 13 deletions lib/Sema/ConstraintSystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4676,20 +4676,14 @@ void ConstraintSystem::diagnoseFailureFor(SyntacticElementTarget target) {

bool ConstraintSystem::isDeclUnavailable(const Decl *D,
ConstraintLocator *locator) const {
// First check whether this declaration is universally unavailable.
if (D->getAttrs().isUnavailable(getASTContext()))
return true;

return TypeChecker::isDeclarationUnavailable(D, DC, [&] {
SourceLoc loc;

if (locator) {
if (auto anchor = locator->getAnchor())
loc = getLoc(anchor);
}
SourceLoc loc;
if (locator) {
if (auto anchor = locator->getAnchor())
loc = getLoc(anchor);
}

return TypeChecker::overApproximateAvailabilityAtLocation(loc, DC);
});
auto availabilityContext = TypeChecker::availabilityAtLocation(loc, DC);
return checkDeclarationAvailability(D, DC, availabilityContext).has_value();
}

bool ConstraintSystem::isConformanceUnavailable(ProtocolConformanceRef conformance,
Expand Down
5 changes: 3 additions & 2 deletions lib/Sema/TypeCheckAvailability.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2205,6 +2205,8 @@ diagnosePotentialUnavailability(const ValueDecl *D, SourceRange ReferenceRange,
const AvailabilityRange &Availability,
bool WarnBeforeDeploymentTarget = false) {
ASTContext &Context = ReferenceDC->getASTContext();
if (Context.LangOpts.DisableAvailabilityChecking)
return false;

bool IsError;
{
Expand Down Expand Up @@ -3100,8 +3102,6 @@ swift::checkDeclarationAvailability(const Decl *decl,
const DeclContext *declContext,
AvailabilityContext availabilityContext) {
auto &ctx = declContext->getASTContext();
if (ctx.LangOpts.DisableAvailabilityChecking)
return std::nullopt;

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

auto *DC = Where.getDeclContext();
auto &ctx = DC->getASTContext();

auto unmetRequirement =
checkDeclarationAvailability(D, DC, Where.getAvailability());
auto requiredRange =
Expand Down
15 changes: 15 additions & 0 deletions stdlib/public/core/Assert.swift
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@
/// is called.
@_transparent
@_unavailableInEmbedded
#if $Embedded
@_disfavoredOverload
#endif
public func assert(
_ condition: @autoclosure () -> Bool,
_ message: @autoclosure () -> String = String(),
Expand Down Expand Up @@ -99,6 +102,9 @@ public func assert(
/// `precondition(_:_:file:line:)` is called.
@_transparent
@_unavailableInEmbedded
#if $Embedded
@_disfavoredOverload
#endif
public func precondition(
_ condition: @autoclosure () -> Bool,
_ message: @autoclosure () -> String = String(),
Expand Down Expand Up @@ -162,6 +168,9 @@ public func precondition(
@inlinable
@inline(__always)
@_unavailableInEmbedded
#if $Embedded
@_disfavoredOverload
#endif
public func assertionFailure(
_ message: @autoclosure () -> String = String(),
file: StaticString = #file, line: UInt = #line
Expand Down Expand Up @@ -221,6 +230,9 @@ public func assertionFailure(
/// line number where `preconditionFailure(_:file:line:)` is called.
@_transparent
@_unavailableInEmbedded
#if $Embedded
@_disfavoredOverload
#endif
public func preconditionFailure(
_ message: @autoclosure () -> String = String(),
file: StaticString = #file, line: UInt = #line
Expand Down Expand Up @@ -264,6 +276,9 @@ public func preconditionFailure(
/// line number where `fatalError(_:file:line:)` is called.
@_transparent
@_unavailableInEmbedded
#if $Embedded
@_disfavoredOverload
#endif
public func fatalError(
_ message: @autoclosure () -> String = String(),
file: StaticString = #file, line: UInt = #line
Expand Down
22 changes: 22 additions & 0 deletions test/Constraints/availability.swift
Original file line number Diff line number Diff line change
Expand Up @@ -64,3 +64,25 @@ extension Box where T == Int {
// memberwise initializer.
_ = Box(value: 42)
}

// rdar://87403752 - ambiguity with member declared in unavailable extension
struct HasUnavailableExtesion {
}

@available(*, unavailable)
extension HasUnavailableExtesion {
static var foo: Self = HasUnavailableExtesion()
}

func test_contextual_member_with_unavailable_extension() {
struct A {
static var foo: A = A()
}

struct Test {
init(_: A) {}
init(_: HasUnavailableExtesion) {}
}

_ = Test(.foo) // Ok `A.foo` since `foo` from `HasUnavailableExtesion` is unavailable
}
8 changes: 4 additions & 4 deletions test/embedded/availability.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ public func universally_unavailable() { }
@_unavailableInEmbedded
public func unused() { } // no error

public struct S1 {}
public struct S2 {}
public struct S1 {} // expected-note {{found this candidate}}
public struct S2 {} // expected-note {{found this candidate}}

@_unavailableInEmbedded
public func has_unavailable_in_embedded_overload(_ s1: S1) { }
Expand All @@ -47,11 +47,11 @@ public func available(
@_unavailableInEmbedded
public func also_unavailable_in_embedded(
_ uie: UnavailableInEmbedded, // OK
_ uu: UniverallyUnavailable // FIXME: should be an error
_ uu: UniverallyUnavailable // OK
) {
unavailable_in_embedded() // OK
universally_unavailable() // expected-error {{'universally_unavailable()' is unavailable: always unavailable}}
has_unavailable_in_embedded_overload(.init()) // FIXME: should be ambiguous
has_unavailable_in_embedded_overload(.init()) // expected-error {{ambiguous use of 'init()'}}
has_universally_unavailable_overload(.init()) // not ambiguous, selects available overload
}

Expand Down