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-14064] Accessing Static Member on Downcast Type not Calling Overridden Implementation #56453

Closed
swift-ci opened this issue Jan 17, 2021 · 2 comments
Labels
bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. compiler The Swift compiler in itself

Comments

@swift-ci
Copy link
Collaborator

Previous ID SR-14064
Radar None
Original Reporter klemen_verdnik (JIRA User)
Type Bug
Status Resolved
Resolution Invalid

Attachment: Download

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

md5: ad172b3baa93495175a765a9ffb6a869

relates to:

  • SR-2620 Conditional Downcast from AnyHashable to [file]private Protocol Fails Unless Going Through Intermediate Internal/Public Protocol

Issue Description:

I'm noticing that if I call a protocol defined static member on a generic (which conforms to the protocol), runtime doesn't call the overridden implementation (see extension CarouselView where Component == Label ).

edit: follow the conversation in the Swift Forums: SR-14064: Accessing Static Member on Downcast Type not Calling Overridden Implementation

Here's a real-life example:

/**
 Type-erased View
 */
protocol AnyView: AnyObject { }
protocol ViewBuilder {
    func makeView() -> AnyView
}

/**
 Configurable View. It requires that the type has an associated
 Configuration type which is used to build the AnyView instances
 (due to ViewBuilder requirement)
 */
protocol ConfigurableView: AnyView, PreviewProvider {
    associatedtype Configuration: ViewConfiguration
    var configuration: Configuration { get }
    init(_ configuration: Configuration)
}

protocol ViewConfiguration: ViewBuilder {
    associatedtype View: ConfigurableView where View.Configuration == Self
}

protocol PreviewProvider {
    static var previewConfigurations: [ViewBuilder] { get }
}

extension ViewConfiguration {
    // Implementing the ViewBuilder protocol.
    func makeView() -> AnyView {
        View(self)
    }
}

/**
 An example of a simple `ConfigurableView` implementation.
 Think of it as a simple Label view that can render a line of text with
 configurable font size.
 */
class Label: ConfigurableView {
    var configuration: Configuration
    required init(_ configuration: Configuration) {
        self.configuration = configuration
    }
    struct Configuration: ViewConfiguration {
        typealias View = Label
        let text: String
        let fontSize: Int
    }
}

extension Label {
    static var previewConfigurations: [ViewBuilder] { [
        Label.Configuration(text: "Regular size label", fontSize: 1),
        Label.Configuration(text: "Bigger label", fontSize: 2),
        Label.Configuration(text: "Even bigger label", fontSize: 3),
    ] }
}

/**
 An example of a `ConfigurableView` implementation using generics.
 Think of it as a scrollable collection of configurable views.
 */
class CarouselView<Component: ConfigurableView>: ConfigurableView {
    var configuration: Configuration
    required init(_ configuration: Configuration) {
        self.configuration = configuration
    }
    struct Configuration: ViewConfiguration {
        typealias View = CarouselView<Component>
        let items: [Component.Configuration]
    }
}

extension CarouselView {
    static var previewConfigurations: [ViewBuilder] { [ ] }
}

extension CarouselView where Component == Label {
    static var previewConfigurations: [ViewBuilder] { [
        CarouselView.Configuration(
            items: [
                Label.Configuration(text: "Hello", fontSize: 1),
                Label.Configuration(text: "World", fontSize: 1),
            ])
    ] }
}

And here's the test:

import XCTest
@testable import DynamicDispatchIssue

final class DynamicDispatchIssueTests: XCTestCase {
    func testCallingStaticMemberDirectly() {
        XCTAssertEqual(Label.previewConfigurations.count, 3)
        XCTAssertEqual(CarouselView<Label>.previewConfigurations.count, 1)
        XCTAssertEqual(CarouselView<Label>.self.previewConfigurations.count, 1)
    }
    
    func testCallingStaticMemberOnDowncastType() {
        XCTAssertEqual((CarouselView<Label>.self as PreviewProvider.Type).previewConfigurations.count, 1)
        // This assert fails because of (CarouselView<Label>.self as PreviewProvider.Type)
    }
    
    static var allTests = [
        ("testCallingStaticMemberDirectly", testCallingStaticMemberDirectly),
        ("testCallingStaticMemberOnDowncastType", testCallingStaticMemberOnDowncastType),
    ]
}

Is this expected?

Find the package with the code attached. Run it with:

swift test
@swift-ci
Copy link
Collaborator Author

Comment by Klemen Verdnik (JIRA)

SR-2620 might be related to my issue.

@xwu
Copy link
Collaborator

xwu commented Jan 17, 2021

Closing as invalid. This is the expected behavior, as explained in the forums. Please feel free to ask for further clarification in the forums.

@swift-ci swift-ci transferred this issue from apple/swift-issues Apr 25, 2022
This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. compiler The Swift compiler in itself
Projects
None yet
Development

No branches or pull requests

2 participants