Convenience init and inheritance

Stumbled across an issue with inherited convenience init when compiled with optimization, but works fine in debug:

class Foo {
  var a: Int

  private init(a: Int) {
    self.a = a
  }

  convenience init() {
    self.init(a: 10)
  }
}

class Baz: Foo {
  func print() {
    Swift.print("Print from Baz")
  }
}

func testCast(foo: Foo) {
  let baz = foo as! Baz // Runtime error: Could not cast value of type 'conv_init.Foo' (0x100008188) to 'conv_init.Baz' (0x100008240).
  baz.print()
  dump(foo)
  dump(baz)
}

let baz = Baz()
testCast(foo: baz)

I'm not sure what is wrong exactly: should this work or the compiler shouldn't syntesize Bar.init if super.init is a convinience init and should produce an error instead?

2 Likes

This is a bug. A distilled version:

class Base {
    private // comment this out – then it won't crash
    init(designated: Int) {
        print("designated")
    }
    convenience init(convenience: Int) {
        print("convenience")
        self.init(designated: 10)
    }
}
class Derived: Base {}

let derived: Base = Derived(convenience: 1)
print(derived as! Derived) // 💣 crash in release, ok in debug
2 Likes