Bad diagnostics and code completion, caused by Swift bug?

In the screenshot example, I'd expect only methodOnAllThings() and methodOnThingsWhereFooIsInt() to show up in the list of code completions, but Xcode will list all methods in all extensions, including methodOnThingsWhereFooIsBool() even though thing is clearly an instance of a type where Foo is Int, not Bool.
I know this might be something Xcode specific and thus OT here, but the error message in the code example below the screenshot makes me wonder if it's caused by something in the Swift implementation?


struct Thing<Foo, Bar> {
    func methodOnAllThings() {}
}

extension Thing where Foo == Int {
    func methodOnThingsWhereFooIsInt() {}
}

extension Thing where Foo == Bool {
    func methodOnThingsWhereFooIsBool() {}
}

func test() {
    
    let thing = Thing<Int, Double>()
    
    thing.methodOnThingsWhereFooIsBool() // ERROR: Generic parameter 'Bar'
                                         //        could not be inferred
    
}
test()

Hi Jens! This is a code completion bug, meaning it is a Swift bug. I filed the same issue almost a year ago, and probably there are some dupes roaming on JIRA as well. The senseless error message is a separate issue that also deserves a SR number.

1 Like

Thank's! I noticed that you're the assignee (as well as reporter) of that issue, does that mean you are working on fixing it?

I've filed SR-9396 for the nonsensical error message and linked it to yours even though I'm not sure if they might be related.

1 Like

I assigned myself just now because I figured I'd give it a go in the nearish future.

2 Likes

I tried the protocol-workaround mentioned in this comment to SR-7046. But (disappointingly) this only works as long as all code is in the same file.

An example:

Start a new command line app project (in Xcode 10.1).

Create these files:

Library.swift:

protocol LibraryProtocol {
    associatedtype Kind
}

struct Library<Kind> : LibraryProtocol {}

Foo.swift:

enum Foo {}

extension LibraryProtocol where Kind == Foo {
    func onlyIfKindIsFoo() {}
}

Bar.swift

enum Bar {}

extension LibraryProtocol where Kind == Bar {
    func onlyIfKindIsBar() {}
}

main.swift:

func test() {
    let barLib = Library<Bar>()
    barLib.
}

Here's what the list of code completions looks for after barLib.:


: (
As can be seen, onlyIfKindIsFoo() is there even though it shouldn't. But cutting and pasting all the code into main.swift will result in the expected single entry list of completions:


The project we're currently working on relies heavily on a code construct like this but this issue takes away much of the joy of using it (veeery long lists of code completions where 90% of the entries are useless/irrelevant). So a fix for this would be greatly appreciated!

1 Like

This bug (SR-9396) is still in Xcode 10.2.1.

Here's another perhaps simpler way to demonstrate it:

extension Array where Element == Int {
    // This foo() method will (unexpectedly) _always_ be
    // visible in code completion of any Array value,
    // regardless of what type Element is.
    func foo() { }
}

func test() {
    
    let nonIntArray = ["hello", "world"]
    
    // NOTE 1: foo() is in list of completions for `nonIntArray.`.
    
    // NOTE 2: This nonsensical error message:
    nonIntArray.foo() // ERROR: [String]' is not convertible to 'Array<Int>'
}
test()

And perhaps even simpler, this (what I guess is a) manifestation of the same bug:

let floatRange = Float(0) ..< Float(1)
floatRange.cou // ERROR: Value of type 'Range<Float>' has no member 'cou'; did you mean 'count'?

even though Range<Float> has no count.
(You'd get an error if you followed the error message's unhelpful "did you mean count?").
(I'd expect count to not even show up in the list of code completions for floatRange.)