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-10257] Inference of @objc from witnessed protocol requirement fails sometimes #52657

Closed
bjhomer opened this issue Apr 1, 2019 · 15 comments
Closed
Assignees
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 @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

@bjhomer
Copy link
Contributor

bjhomer commented Apr 1, 2019

Previous ID SR-10257
Radar rdar://problem/49987299
Original Reporter @bjhomer
Type Bug
Status Resolved
Resolution Done

Attachment: Download

Environment

Swift 5.0 (Xcode 10.2.0)
macOS 10.14.4

Additional Detail from JIRA
Votes 8
Component/s Compiler
Labels Bug, 5.0Regression, WholeModuleOnly
Assignee @slavapestov
Priority Medium

md5: a179bcfc08d34eda3229b62320cb8489

is duplicated by:

Issue Description:

The short version: In certain cases, the Swift 5.0 compiler does not infer @objc correctly for a function. This only happens in wholemodule mode, which means that there's an observable behavior difference between incremental and whole-module compilation.

There are three files involved:

  • BaseVC.swift

  • ChildVC.swift

  • UnrelatedClass.swift

BaseVC declares conformance to UITableViewDelegate, but does not implement anything.

ChildVC implements 'func tableView(_:didSelectRowAt:)'

The app delegate checks whether ChildVC responds to -tableView:didSelectRowAtIndexPath:. Up to this point, it does.

Now we add in a third file, "UnrelatedClass.swift"

If all of the following hold true, then the ChildVC.respondsToSelector() check fails:

1. The third file contains an 'AnyObject'-dispatched call to .selectionChanged()
2. The order of the files passed to the compiler is [BaseVC, UnrelatedClass, ChildVC].
3. ChildVC.tableView(_:didSelectRowAt:) is not tagged @objc
4. The compiler is running in 'wholemodule' mode.

In that case, the ObjC runtime does not see the implementation of -tableView:didSelectRowAtIndexPath:.

Only under those four conditions does this bug appear.

In Swift 4.2, @objc was inferred. In Swift 5.0 incremental mode, @objc is inferred.

I'm attaching a sample Xcode project which reproduces the issue easily. Just look at the console output on launch.

@bjhomer
Copy link
Contributor Author

bjhomer commented Apr 2, 2019

A code example, because a wall of descriptive text is hard to read:

// BaseVC.swift
import UIKit
class BaseVC: UIViewController, UITableViewDelegate {}
// ChildVC.swift
import UIKit

class ChildVC: BaseVC {
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {}
}
// UnrelatedView.swift

import UIKit

class UnrelatedView: UIView {
    var selectionFeedbackGenerator: AnyObject?

    func breakThings() {
        // Comment out this line to make the bug go away
        selectionFeedbackGenerator?.selectionChanged()
    }   
}

Given just that code and the conditions detailed above*, ChildVC will not be notified when a table row is selected, because it does not implement the ObjC method -tableView:didSelectRowAtIndexPath:.

* (Swift 5.0 compiler, wholemodule, files passed in [BaseVC.swift, UnrelatedView.swift, ChildVC.swift] order.)

@belkadan
Copy link
Contributor

belkadan commented Apr 2, 2019

Thank you for putting the effort in to track this down!

@bjhomer
Copy link
Contributor Author

bjhomer commented Apr 9, 2019

@swift-ci
Copy link
Collaborator

swift-ci commented Apr 9, 2019

Comment by Dimitar Topalov (JIRA)

I believe this needs a higher priority, as it can raise some serious issues that are hard to catch until the app is archived.

@swift-ci
Copy link
Collaborator

Comment by Robin Trigodet (JIRA)

I had it too. The solution is to add @objc before protocol function

@swift-ci
Copy link
Collaborator

Comment by Dan Hogan (JIRA)

I agree that this issue needs a higher priority. I work on a large project and we are not confident that we can identify all of the affected files. For now we are delaying swift 5 migration and using XCode 10.1 due to this issue

@swift-ci
Copy link
Collaborator

Comment by Lance (JIRA)

I believe there is some other trigger or variation that causes this to happen as well.

In our project the exact same thing happens (no @objc inference for protocol methods first implemented in a subclass), with a couple of differences:

  1. It happens in incremental builds as well

  2. It only happens after cleaning the build folder and not altering the file containing the subclass. If I edit that file, even adding a space and then deleting it, and then rebuild, the method will be included in the header. If I clean the build folder and then rebuild, method is not included in generated header.

Happens every time when whole module.

I have been unable to reproduce the incremental build version in a simple project so far.

@slavapestov
Copy link
Member

#24256

@swift-ci
Copy link
Collaborator

Comment by Alicia Tams (JIRA)

We're seeing the same thing on our recent update to Swift 5. Almost dead in the water because we're going from 3.2 to 5 and really cannot wait until Xcode 11 is in GM or released to release our app. We also can no longer debug to our phones because iOS enjoys upgrading to the latest version without consent after we explicitly decline to update a number of times over the course of a few weeks. Our codebase is quite large and these are silent failures, finding them all is going to be a nightmare. Will this possibly be hot fixed in the 5 compiler in an Xcode 10.2.2 update?

@swift-ci
Copy link
Collaborator

Comment by Kiel (JIRA)

I strongly plead for an Xcode 10.2.2 hotfix update.

As with others, we're stuck with Xcode 10.1 because those silent failures we know about are causing issues. Further, due to the subtly of the bug's side effects, we don't know what other issues this introduces, especially with third party SDKs and UIKit, such as delegate methods (where we are especially bitten). Since those methods are not exposed to the Objective-C runtime, things just break or stop working altogether.

Please consider hotfixing Xcode 10.2.1 for this.
https://feedbackassistant.apple.com/feedback/6205539

@swift-ci
Copy link
Collaborator

Comment by Kiel (JIRA)

This seems to happen for us irrespective of whole module or incremental compilation.

@swift-ci
Copy link
Collaborator

Comment by Jasper (JIRA)

Status resolved with no open duplicates? I still have the problem on a generic class (generic UITableView type) on every tableview delegate methods. I have seen this bug in Xcode 10.2.?, Xcode 11 beta 1, 2 and 3 (so the current Xcode version) with Swift 5.0 and 5.1. I now just override everything (https://stackoverflow.com/a/55594515/7715250) and someone else also got my problem (https://stackoverflow.com/questions/55592341/xcode-10-2-with-swift-5-0-compiler-protocol-inheritance-issue#comment99581546_55593277).

Is this bug considered closed and fixed? I can try to create a reproduction project if needed.

@slavapestov
Copy link
Member

Yes this bug is considered fixed in Swift 5.1. If you are seeing a similar issue in the latest beta, please file a new bug with a reproducer project.

@swift-ci
Copy link
Collaborator

swift-ci commented Aug 8, 2019

Comment by Claus Joergensen (JIRA)

@slavapestov hey, people are suggesting the fix was backported to Xcode 10.3, can this be confirmed or denied by the Swift team?

Thanks

@swift-ci
Copy link
Collaborator

Comment by Christian Gossain (JIRA)

This just happened to me with Xcode 10.3 and Swift 5. I found out too late because this only shows up in the release version that was released to the public.

Anyways, I just disabled "Whole Module" optimization on my "Release" target and this solved the issue for now. Hopefully this issue get's fixed in the next release.

@swift-ci swift-ci transferred this issue from apple/swift-issues Apr 25, 2022
@AnthonyLatsis AnthonyLatsis added attributes Feature: Declaration and type attributes @objc Feature → attributes: The @objc attribute labels Jan 19, 2024
@AnthonyLatsis AnthonyLatsis added conformances Feature → protocol: protocol conformances type checker Area → compiler: Semantic analysis labels Jan 19, 2024
@AnthonyLatsis AnthonyLatsis added objective-c interop Feature: Interoperability with Objective-C unexpected behavior Bug: Unexpected behavior or incorrect output 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 @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

5 participants