swiftlang / swift

The Swift Programming Language
https://swift.org
Apache License 2.0
67.27k stars 10.33k forks source link

[SR-2978] "is" or "as?" operator doesn't work correctly for protocol for struct? #45568

Open swift-ci opened 7 years ago

swift-ci commented 7 years ago
Previous ID SR-2978
Radar None
Original Reporter mshibanami (JIRA User)
Type Bug

Attachment: Download

Environment Xcode 8.3.1 beta (8T29o)
Additional Detail from JIRA | | | |------------------|-----------------| |Votes | 0 | |Component/s | Compiler | |Labels | Bug, Runtime | |Assignee | None | |Priority | Medium | md5: 212788bca1d39fae8e28f366c2274c2d

Issue Description:

See the following code or the attached project.

// ViewController.swift
protocol MyProtocol {}
struct MyStruct: MyProtocol {}

class ViewController: NSViewController {
    @IBOutlet weak var outlineVIew: NSOutlineView!
}

extension ViewController: NSOutlineViewDataSource {

    public func outlineView(_ outlineView: NSOutlineView, numberOfChildrenOfItem item: Any?) -> Int {
        return 1;
    }

    public func outlineView(_ outlineView: NSOutlineView, child index: Int, ofItem item: Any?) -> Any {
        return MyStruct()
    }

    public func outlineView(_ outlineView: NSOutlineView, isItemExpandable item: Any) -> Bool {
        return false;
    }
}

extension ViewController: NSOutlineViewDelegate
{
    func outlineView(_ outlineView: NSOutlineView, viewFor tableColumn: NSTableColumn?, item: Any) -> NSView?
    {
        let cellView = outlineView.make(withIdentifier: "cell", owner: self)

        guard item is MyStruct else {
            fatalError("'item' should be a MyStruct instance.")
        }

        guard item is MyProtocol else {
            fatalError("'item' should implement MyProtocol")
        }

        return cellView
    }
}

When I ran this code, it reached to fatalError() in the 2nd guard clause.
I thought this is weird. Because the valuable "item" is a instance of MyStruct, and MyStruct implements MyProtocol.
And if I changed MyStruct to class from struct, It didn't happen.

It also happend If I changed 2nd guard like this.

guard let i = item as? MyProtocol else {
    fatalError("'item' should implement MyProtocol")
}

I'm afraid if this is just a newbee mistake or a AppKit's bug...

belkadan commented 7 years ago

cc @jckarter

jckarter commented 7 years ago

This is probably an instance of the general problem that we don't try to bridge ObjC objects back to Swift structs (or vice versa) when casting to protocol types.