Skip to content
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

[SR-10498] Warn about implementing @optional Objective-C protocol methods in a Swift subclass of a class that conforms to that protocol #52898

Closed
swift-ci opened this issue Apr 17, 2019 · 10 comments
Labels
attributes Feature: Declaration and type attributes bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. compiler The Swift compiler in itself conformances Feature → protocol: protocol conformances duplicate Resolution: Duplicates another issue @objc Feature → attributes: The @objc attribute objective-c interop Feature: Interoperability with Objective-C regression swift 5.0 type checker Area → compiler: Semantic analysis unexpected behavior Bug: Unexpected behavior or incorrect output whole module optimization only Flag: An issue whose reproduction requires whole module optimization

Comments

@swift-ci
Copy link
Collaborator

swift-ci commented Apr 17, 2019

Previous ID SR-10498
Radar rdar://problem/49987299
Original Reporter marcetcheverry (JIRA User)
Type Bug
Status Resolved
Resolution Duplicate
Environment

Xcode Version 10.2.1 (10E1001)

macOS 10.14.4

Additional Detail from JIRA
Votes 1
Component/s Compiler
Labels Bug
Assignee None
Priority Medium

md5: c866fe67ee173d629a2501ffc7f4ee23

duplicates:

Issue Description:

Description

If you have an abstract Swift class that conforms to an Objective-C protocol, in the test case here UITableViewDataSource, which has both @required and @optional methods, implementing any optional method of that protocol in a Swift subclass will fail silently on 'Release' runtime without any compile-time warning.

Actual results

If you implement something as the below test case, which is probably very common, the Objective-C implementation of UITableView in this case (or any Objective-C implementation) will fail to detect that you actually implement that Objc-C optional protocol. You will not get your section headers in this case. This only happens under certain compilation conditions.

Expected results

The compiler should warn you at compile time that a superclass conforms to a protocol that has the same method signature marked as an Objective-C optional and you need to declare it as `@objc` for it to be exposed at runtime.

Reproduction Steps:
I could only reproduce this bug with the standard Release configuration in Xcode for Swift projects. Optimization level or other Swift compiler settings are definitely at play with this interaction with UIKit and perhaps all similar Objective-C runtime optional checking implementations. It took me significant time to catch this bug because of this and because there is absolutely no compiler warning about this.

Please note the item below is not a full test case for UITableView, but it compiles and shows that Swift does not warn about implementing these method signatures that will do nothing at runtime.

A RDAR link is attached, for whatever it's worth.

Compilation Mode must be Whole Module Optimization.

Search metadata:

`UITableView titleForHeader not getting called`, `UITableViewDelegate Swift not getting called`, `UITableViewDataSource Swift not getting called`

import UIKit

// This class is an abstract class for all table view controllers. It only implements @required methods
class BaseTableViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
    @IBOutlet var tableView: UITableView!
    
    // MARK: - UITableViewDataSource
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 0
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        return UITableViewCell()
    }
}

// This is a concrete class that now wants to implement some of the optional methods in UITableViewDelegate & UITableViewDataSource
class MyContentTableViewController: BaseTableViewController {
    // This is an optional method in UITableViewDataSource
    // FIXME: Compiler should warn that you need to add @objc since this matches an optional method in a protocol conformed to in the superclass, or this method won't appear as implemented to UITableView, which probably uses respondsToSelector
    func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
        return "Section Header"
    }
}
@swift-ci
Copy link
Collaborator Author

Comment by Khaos Tian (JIRA)

We also observed similar issue with Swift 5 and Xcode 10.2.1

Under certain conditions (When SWIFT_COMPILATION_MODE = wholemodule, SWIFT_OPTIMIZATION_LEVEL = -O), Swift compiler failed to expose the optional protocol method in Objective-C, causing selector check to fail silently.

I was not able to reproduce the issue with a clean, simple project so the issue is likely related to how complier optimize a complex project?

@belkadan
Copy link
Contributor

I think we have a dup of this, but the Release build note is definitely good to have. (It's probably about whole-module compilation, not optimization.) You are not supposed to need @objc for this case.

@swift-ci
Copy link
Collaborator Author

Comment by Khaos Tian (JIRA)

Okay I was able to confirm this happens as long as SWIFT_COMPILATION_MODE = wholemodule, optimization level doesn't affect the outcome.

@swift-ci
Copy link
Collaborator Author

Comment by Marc Etcheverry (JIRA)

Still broken on the just released Xcode Version 10.2.1 (10E1001). Apple Swift version 5.0.1 (swiftlang-1001.0.82.4 clang-1001.0.46.5).

This Swift version does fix some `@objc` issues but not this one.

Turning off Whole Module Optimization does indeed prevent this subtle and silent bug. I wouldn't be surprised if many existing apps are affected by this.

@swift-ci
Copy link
Collaborator Author

Comment by Ryder Mackay (JIRA)

Just got bitten by this. In our case, module A defines a base class that conforms to an Objective-C protocol. Module B defines a subclass that implements an optional protocol method. With WMO turned on, the compiler does not expose the optional method to the Objective-C runtime. Adding an explicit @objc annotation (or turning off WMO) fixes the problem.

As far as I know, this is a regression in Xcode 10.2.1 or 10.2. Our previous release, built with Xcode 10.1, wasn't affected.

@bjhomer
Copy link
Contributor

bjhomer commented Apr 23, 2019

This is likely the same issue as SR-10257

@belkadan
Copy link
Contributor

If anyone has a project they can share (either here or with Apple only at https://bugreport.apple.com) that will help a lot with tracking this down!

@bjhomer
Copy link
Contributor

bjhomer commented Apr 23, 2019

Assuming this is the same issue as SR-10257, I attached a minimal sample project there.

@belkadan
Copy link
Contributor

Right, fair point.

@swift-ci
Copy link
Collaborator Author

Comment by Ryder Mackay (JIRA)

@bjhomer yes, what I described above is the same as SR-10257. Seems like the intermodule aspect is irrelevant. Thanks for reducing the problem.

@swift-ci swift-ci transferred this issue from apple/swift-issues Apr 25, 2022
@AnthonyLatsis AnthonyLatsis added duplicate Resolution: Duplicates another issue type checker Area → compiler: Semantic analysis conformances Feature → protocol: protocol conformances regression attributes Feature: Declaration and type attributes objective-c interop Feature: Interoperability with Objective-C unexpected behavior Bug: Unexpected behavior or incorrect output @objc Feature → attributes: The @objc attribute whole module optimization only Flag: An issue whose reproduction requires whole module optimization swift 5.0 labels Jan 19, 2024
This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
attributes Feature: Declaration and type attributes bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. compiler The Swift compiler in itself conformances Feature → protocol: protocol conformances duplicate Resolution: Duplicates another issue @objc Feature → attributes: The @objc attribute objective-c interop Feature: Interoperability with Objective-C regression swift 5.0 type checker Area → compiler: Semantic analysis unexpected behavior Bug: Unexpected behavior or incorrect output whole module optimization only Flag: An issue whose reproduction requires whole module optimization
Projects
None yet
Development

No branches or pull requests

4 participants