Swift: method overloading is not reliable

Originator:gwendal.roue
Number:rdar://19017096 Date Originated:2014-11-18
Status:Open Resolved:
Product:Developper Tools Product Version:Xcode 6.1 (6A1052d)
Classification:Serious Bug Reproducible:Always
 
Summary:
Given a set of argument types, Swift should always chose the same overloaded method in the set of methods that accept those arguments. This is not the case.

Steps to Reproduce:
Run the following code in a Playground:

import Foundation

protocol P1: Printable { }
protocol P2: Printable { }

class Container {
    let type: String
    init(type: String) {
        self.type = type
        println(type)
    }
    convenience init(_ o:AnyObject?)          { self.init(type: "AnyObject(\(o))") }
    convenience init(_ o:P1)                  { self.init(type: "P1(\(o.description))") }
    convenience init(_ o:P2)                  { self.init(type: "P2(\(o.description))") }
    convenience init(_ o:protocol<P1,P2>)     { self.init(type: "P1,P2(\(o.description))") }
    convenience init(_ d:[String: Container]) { self.init(type: "Dictionary") }
}

class O1: P1 { let description = "O1" }
class O2: P2 { let description = "O2" }
class O12: P1, P2 { let description = "O12" }

Container([
    "a": Container([
        "o1": Container(O1()),
        "o2": Container(O2()),
        "o12": Container(O12()),
        "any": Container("string"),
        ]),
    "b": Container([
        "o1": Container(O1()),
        "o2": Container(O2()),
        "o12": Container(O12()),
        "any": Container("string"),
        ]),
])


Expected Results:
The `Container(O1())` expressions should *always* trigger the same Container.init(_ o:P1) constructor, and the program outputs:

P1(O1)
P2(O2)
P1,P2(O12)
AnyObject(Optional(string))
Dictionary
P1(O1)
P2(O2)
P1,P2(O12)
AnyObject(Optional(string))
Dictionary
Dictionary


Actual Results:
The `Container(O1())` expressions sometimes trigger the Container.init(_ o:P1) constructor, and sometimes trigger the convenience init(_ o:AnyObject?) constructor, and outputs:

AnyObject(Optional(__lldb_expr_1511.O1))
AnyObject(Optional(__lldb_expr_1511.O2))
AnyObject(Optional(__lldb_expr_1511.O12))
AnyObject(Optional(string))
Dictionary
P1(O1)
P2(O2)
P1,P2(O12)
AnyObject(Optional(string))
Dictionary
Dictionary


Version:
Xcode 6.1 (6A1052d)

Notes:
This bug is particularly painful when you want to implement an API that relies on method overloading in order to avoid to explicitly give a name to initial parameters. The goal is to be nicer to the API user (who does not have to remember which method to use), and this is better for future compatibility (since newly introduced types or refactored types don't need API change).

See for instance the consequences of this bug in the "TODO: avoid this `as [String: Value]` cast" comments in https://github.com/groue/GRMustache.swift/blob/5be90ab67ada61bc8c0222b2df3edb07cf8889f0/GRMustacheTests/Public/FilterTests/VariadicFilterTests.swift

Configuration:
OSX 10.10 (14A389)

Comments


Please note: Reports posted here will not necessarily be seen by Apple. All problems should be submitted at bugreport.apple.com before they are posted here. Please only post information for Radars that you have filed yourself, and please do not include Apple confidential information in your posts. Thank you!