Overloaded constructors in 2331 now fail to compile (Silver/Cooper)?


(Jon Nermut) #1

This valid swift used to compile as recently as .2321, but doesn’t in .2331, it gives a “Duplicate constructor” error. Which I’m guessing is fair enough in Java where you can’t overload constructors, but it used to work fine?

/// Used when an API can return String data or a fatal error.
open class DataOrError: NSObject
{
    
    fileprivate(set) open var error: String?
    fileprivate(set) open var data: String?
    
    public init(data: String)
    {
        self.data = data
    }
    
    public init(error: String)
    {
        self.error = error
    }
    
    open class func data(_ data: String) -> DataOrError
    {
        return DataOrError(data: data)
    }
    
    open class func error(_ error: String) -> DataOrError
    {
        return DataOrError(error: error)
    }
}

Similarly, all calls to DataOrError(error: ‘blah’) also fail to compile.


(Carlo Kok) #2

This is an unfortunate limitation of java itself. Constructors can’t be named there so they’ll match on their types. You can create a private init method that takes both error and data, and public convenience constructors that call those to get around this.


(Jon Nermut) #3

Thanks Carlo.
Interestingly the convenience inits suffered the same problem, but I will just change all the calling code to call the existing statics anyway:


(RemObjects) #4

Thanks, logged as bugs://81138


(Carlo Kok) #5

Yeah it’s a bit tricky. I thought convenience did a trick here but was confused. I’m going to see how to best solve this but for now your workaround will have to do.


(Jon Nermut) #6

Thanks, in this case there were only a dozen or so callers, so no big deal


(Jon Nermut) #7

Carlo, got more strangeness with constructors in 2331. This looks like a reasonably serious regression in 2331, and possibly related to the above.

The attached project is a small repro of a problem I’m having with constructors of Swift superclass and Java base class.

consoleapplication79999.zip (208.3 KB)

public typealias OpaquePointer = Int32
public class BasePtrWrapper
{
    
    internal var address: OpaquePointer

    
    public required init(ptr: OpaquePointer)
    {
        super.init()
        
        self.address = ptr
    }

}

@objc(AuthTokenWrapper)
open class AuthToken  : BasePtrWrapper
{
    /*
    public required init(ptr: OpaquePointer)
    {
        super.init(ptr: ptr)
    }
    */
}

let at = AuthToken(ptr: 333)
print(at)

Running it gives
!> Fatal exception of type java.lang.VerifyError on thread 0001 ()
!> Message: java.lang.VerifyError: (class: consoleapplication79999/__Global, method: main$ signature: ([Ljava/lang/String;)I) Call to wrong initialization method

If you uncomment out the overridden constructor, you get a similar error.
I can’t work out what’s actually the determining factor here.

In my actual project I end up with decompiled code that looks like this:

public class AuthToken extends BasePtrWrapper {
    public AuthToken(int ptr) {
        Object Result = null;
        super(ptr);
        return Result;
    }

Where returning a value from a constructor is the bytecode problem I guess.

Any workarounds appreciated, as its yet another blocker trying to upgrade to Fire 10, which I’ve been on for ~6 weeks now.


(RemObjects) #8

bugs://81138 got closed with status fixed.


(Carlo Kok) #9

Curious issue. For Island/Darwin we added Cocoa support and different class models. @Objc makes a class into those, and it confused the compiler. Fixed now.


(Jon Nermut) #10

Ah, thanks. The @objc is for the XCode cross compile. I’ll comment them out FTB so I can keep moving.