Skip to content

Sema: Allow some references to declarations that are unavailable-in-Swift #70708

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
25 changes: 24 additions & 1 deletion lib/Sema/TypeCheckAvailability.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,27 @@ static bool isInsideCompatibleUnavailableDeclaration(
inheritsAvailabilityFromPlatform(platform, *referencedPlatform));
}

static bool shouldAllowReferenceToUnavailableInSwiftDeclaration(
const Decl *D, const ExportContext &where) {
auto *DC = where.getDeclContext();
auto *SF = DC->getParentSourceFile();

// Unavailable-in-Swift declarations shouldn't be referenced directly in
// source. However, they can be referenced in implicit declarations that are
// printed in .swiftinterfaces.
if (!SF || SF->Kind != SourceFileKind::Interface)
return false;

if (auto constructor = dyn_cast_or_null<ConstructorDecl>(DC->getAsDecl())) {
// Designated initializers inherited from an Obj-C superclass may have
// parameters that are unavailable-in-Swift.
if (constructor->isObjC())
return true;
}

return false;
}

namespace {

/// A class to walk the AST to build the type refinement context hierarchy.
Expand Down Expand Up @@ -3038,7 +3059,9 @@ bool swift::diagnoseExplicitUnavailability(
break;

case PlatformAgnosticAvailabilityKind::UnavailableInSwift:
// This API is explicitly unavailable in Swift.
if (shouldAllowReferenceToUnavailableInSwiftDeclaration(D, Where))
return true;

platform = "Swift";
break;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
#import <Foundation/Foundation.h>

@interface FrameworkObject : NSObject
- (nonnull instancetype)initWithInvocation:(nullable NSInvocation *)invocation NS_SWIFT_UNAVAILABLE("unavailable");
- (nonnull instancetype)initWithSelector:(nonnull SEL)selector;
- (nonnull instancetype)initWithInteger:(NSInteger)integer;
NS_SWIFT_UNAVAILABLE("unavailable")
@interface UnavailableInSwift : NSObject
@end

@interface HasAvailableInit : NSObject
- (nonnull instancetype)initWithUnavailable:(nonnull UnavailableInSwift *)unavailable;
@end

@interface HasUnavailableInit : NSObject
- (nonnull instancetype)initWithUnavailable:(nonnull UnavailableInSwift *)unavailable NS_SWIFT_UNAVAILABLE("unavailable");
@end

18 changes: 12 additions & 6 deletions test/ModuleInterface/inherited-objc-superclass-initializers.swift
Original file line number Diff line number Diff line change
@@ -1,15 +1,21 @@
// RUN: %target-swift-emit-module-interface(%t.swiftinterface) %s -I %S/Inputs/inherited-objc-initializers/
// RUN: %target-swift-typecheck-module-from-interface(%t.swiftinterface) -I %S/Inputs/inherited-objc-initializers/
// RUN: %target-swift-emit-module-interface(%t.swiftinterface) %s -I %S/Inputs/inherited-objc-initializers/ -module-name Test
// RUN: %target-swift-typecheck-module-from-interface(%t.swiftinterface) -I %S/Inputs/inherited-objc-initializers/ -module-name Test
// RUN: %FileCheck %s < %t.swiftinterface

// REQUIRES: objc_interop

import InheritedObjCInits

// CHECK: @objc @_inheritsConvenienceInitializers public class Subclass : InheritedObjCInits.FrameworkObject {
public class Subclass: FrameworkObject {
// CHECK-NEXT: @objc override dynamic public init(selector: ObjectiveC.Selector)
// CHECK-NEXT: @objc override dynamic public init(integer: Swift.Int)
// CHECK: @objc @_inheritsConvenienceInitializers public class Subclass2 : InheritedObjCInits.HasAvailableInit {
public class Subclass2: HasAvailableInit {
// CHECK-NEXT: @objc override dynamic public init(unavailable: InheritedObjCInits.UnavailableInSwift)
// CHECK-NEXT: @objc override dynamic public init()
// CHECK-NEXT: @objc deinit
} // CHECK-NEXT:{{^}$}}

// CHECK: @objc @_inheritsConvenienceInitializers public class Subclass1 : InheritedObjCInits.HasUnavailableInit {
public class Subclass1: HasUnavailableInit {
// CHECK-NOT: InheritedObjCInits.UnavailableInSwift
// CHECK-NEXT: @objc override dynamic public init()
// CHECK-NEXT: @objc deinit
} // CHECK-NEXT:{{^}$}}