swiftlang / swift

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

[SR-4985] Strange associated type inference #47562

Open swift-ci opened 7 years ago

swift-ci commented 7 years ago
Previous ID SR-4985
Radar rdar://problem/32378586
Original Reporter tarunon (JIRA User)
Type Bug

Attachment: Download

Environment Xcode Version 8.3.2 (8E2002) Apple Swift version 3.1 (swiftlang-802.0.53 clang-802.0.42), Target: x86_64-apple-macosx10.9
Additional Detail from JIRA | | | |------------------|-----------------| |Votes | 0 | |Component/s | Compiler | |Labels | Bug | |Assignee | None | |Priority | Medium | md5: 31385fa142ec2bae214f5e8af12d7e56

Issue Description:

If we extend a protocol restrict some case, and write default implementation of function that referencing associated type, we can find some of strange type inferences.

Minimum code is here

protocol Foo {
    associatedtype Bar
    func bar() -> Bar
}

extension Foo where Bar == String {
    func bar() -> String {
        return "hello"
    }
}

struct Piyo: Foo {
    // doesn't need to define Bar
}

Piyo().bar() // "hello"

And I find some of other type inferences also, I attach MyPlayground.zip.

belkadan commented 7 years ago

The first inference seems reasonable, but the others are not. Uploading your pages as standalone Swift files.

belkadan commented 7 years ago

Ah, it looks like the second page is now also accepted, which seems reasonable as well. So it's just about the default case.

protocol Foo {
    associatedtype Bar = Int
    func bar() -> Bar
}

extension Foo where Bar == String {
    func bar() -> String {
        return "hello"
    }
}

extension Foo where Bar == Int {
    func bar() -> Bar {
        return 108
    }
}

struct Piyo: Foo {
    // Bar is String...
}

print(Piyo().bar())
belkadan commented 7 years ago

@swift-ci create

belkadan commented 7 years ago

Interestingly, if I change the second extension to return Int instead of Bar then it becomes ambiguous.

swift-ci commented 7 years ago

Comment by Nobuo Saito (JIRA)

@belkadan
Thank you for checking,
In my opinion, this inference has two problems.

1. Undecidable inference,
In first case, the following extension works the default Bar,

extension Foo where Bar == String {
    func bar() -> String {
        return "hello"
    }
}

but in my opinion it should not affect default `Bar`.
`Bar` is determined to be a `String` by function implement, but It should work only `Bar` is `String` case.
There aren't any other information, it seems don't affect `Bar` type is reasonable, maybe.

2. Different behavior by type declaration.
If I write function implement using `Bar` instead of `String` like,

extension Foo where Bar == String {
    func bar() -> Bar {
        return "hello"
    }
}

then, in first case it's require that define `Bar` type. It seems this behavior is better than 1. case.