blob: d678ff8e724cf940127f7dda2ba8514ad0459563 [file] [log] [blame]
// RUN: %target-typecheck-verify-swift
// REQUIRES: objc_interop
import Foundation
struct S0 {
init!(int: Int) { }
init! (uint: UInt) { }
init !(float: Float) { }
init?(string: String) { }
init ?(double: Double) { }
init ? (char: Character) { }
}
struct S1<T> {
init?(value: T) { }
}
class DuplicateDecls {
init!() { } // expected-note{{'init()' previously declared here}}
init?() { } // expected-error{{invalid redeclaration of 'init()'}}
init!(string: String) { } // expected-note{{'init(string:)' previously declared here}}
init(string: String) { } // expected-error{{invalid redeclaration of 'init(string:)'}}
init(double: Double) { } // expected-note{{'init(double:)' previously declared here}}
init?(double: Double) { } // expected-error{{invalid redeclaration of 'init(double:)'}}
}
// Construct via a failable initializer.
func testConstruction(_ i: Int, s: String) {
let s0Opt = S0(string: s)
assert(s0Opt != nil)
var _: S0 = s0Opt // expected-error{{value of optional type 'S0?' must be unwrapped}}
// expected-note@-1{{coalesce}}
// expected-note@-2{{force-unwrap}}
let s0IUO = S0(int: i)
assert(s0IUO != nil)
_ = s0IUO
}
// ----------------------------------------------------------------------------
// Superclass initializer chaining
// ----------------------------------------------------------------------------
class Super {
init?(fail: String) { }
init!(failIUO: String) { }
init() { } // expected-note 2{{non-failable initializer 'init()' overridden here}}
}
class Sub : Super {
override init() { super.init() } // okay, never fails
init(nonfail: Int) { // expected-note{{propagate the failure with 'init?'}}{{7-7=?}}
super.init(fail: "boom") // expected-error{{a non-failable initializer cannot chain to failable initializer 'init(fail:)' written with 'init?'}}
// expected-note@-1{{force potentially-failing result with '!'}}{{29-29=!}}
}
convenience init(forceNonfail: Int) {
self.init(nonfail: forceNonfail)! // expected-error{{cannot force unwrap value of non-optional type 'Sub'}} {{37-38=}}
}
init(nonfail2: Int) { // okay, traps on nil
super.init(failIUO: "boom")
}
init(nonfail3: Int) {
super.init(fail: "boom")!
}
override init?(fail: String) {
super.init(fail: fail) // okay, propagates ?
}
init?(fail2: String) { // okay, propagates ! as ?
super.init(failIUO: fail2)
}
init?(fail3: String) { // okay, can introduce its own failure
super.init()
}
override init!(failIUO: String) {
super.init(failIUO: failIUO) // okay, propagates !
}
init!(failIUO2: String) { // okay, propagates ? as !
super.init(fail: failIUO2)
}
init!(failIUO3: String) { // okay, can introduce its own failure
super.init()
}
}
// ----------------------------------------------------------------------------
// Initializer delegation
// ----------------------------------------------------------------------------
extension Super {
convenience init(convenienceNonFailNonFail: String) { // okay, non-failable
self.init()
}
convenience init(convenienceNonFailFail: String) { // expected-note{{propagate the failure with 'init?'}}{{19-19=?}}
self.init(fail: convenienceNonFailFail) // expected-error{{a non-failable initializer cannot delegate to failable initializer 'init(fail:)' written with 'init?'}}
// expected-note@-1{{force potentially-failing result with '!'}}{{44-44=!}}
}
convenience init(convenienceNonFailFailForce: String) {
self.init(fail: convenienceNonFailFailForce)!
}
convenience init(convenienceNonFailFailIUO: String) { // okay, trap on failure
self.init(failIUO: convenienceNonFailFailIUO)
}
convenience init?(convenienceFailNonFail: String) {
self.init() // okay, can introduce its own failure
}
convenience init?(convenienceFailFail: String) {
self.init(fail: convenienceFailFail) // okay, propagates ?
}
convenience init?(convenienceFailFailIUO: String) { // okay, propagates ! as ?
self.init(failIUO: convenienceFailFailIUO)
}
convenience init!(convenienceFailIUONonFail: String) {
self.init() // okay, can introduce its own failure
}
convenience init!(convenienceFailIUOFail: String) {
self.init(fail: convenienceFailIUOFail) // okay, propagates ? as !
}
convenience init!(convenienceFailIUOFailIUO: String) { // okay, propagates !
self.init(failIUO: convenienceFailIUOFailIUO)
}
}
struct SomeStruct {
init(nonFail: Int) { // expected-note{{propagate the failure with 'init?'}}{{8-8=?}}
self.init(fail: nonFail) // expected-error{{a non-failable initializer cannot delegate to failable initializer 'init(fail:)' written with 'init?'}}
// expected-note@-1{{force potentially-failing result with '!'}}{{29-29=!}}
}
init(nonFail2: Int) {
self.init(fail: nonFail2)!
}
init?(fail: Int) {}
}
// ----------------------------------------------------------------------------
// Initializer overriding
// ----------------------------------------------------------------------------
class Sub2 : Super {
override init!(fail: String) { // okay to change ? to !
super.init(fail: fail)
}
override init?(failIUO: String) { // okay to change ! to ?
super.init(failIUO: failIUO)
}
override init() { super.init() } // no change
}
// Dropping optionality
class Sub3 : Super {
override init(fail: String) { // okay, strengthened result type
super.init()
}
override init(failIUO: String) { // okay, strengthened result type
super.init()
}
override init() { } // no change
}
// Adding optionality
class Sub4 : Super {
override init?(fail: String) { super.init() }
override init!(failIUO: String) { super.init() }
override init?() { // expected-error{{failable initializer 'init()' cannot override a non-failable initializer}}
super.init()
}
}
class Sub5 : Super {
override init?(fail: String) { super.init() }
override init!(failIUO: String) { super.init() }
override init!() { // expected-error{{failable initializer 'init()' cannot override a non-failable initializer}}
super.init()
}
}
// ----------------------------------------------------------------------------
// Initializer conformances
// ----------------------------------------------------------------------------
protocol P1 {
init(string: String)
}
@objc protocol P1_objc {
init(string: String)
}
protocol P2 {
init?(fail: String)
}
protocol P3 {
init!(failIUO: String)
}
class C1a : P1 {
required init?(string: String) { } // expected-error{{non-failable initializer requirement 'init(string:)' cannot be satisfied by a failable initializer ('init?')}}
}
class C1b : P1 {
required init!(string: String) { } // okay
}
class C1b_objc : P1_objc {
@objc required init!(string: String) { } // expected-error{{non-failable initializer requirement 'init(string:)' in Objective-C protocol cannot be satisfied by a failable initializer ('init!')}}
}
class C1c {
required init?(string: String) { } // expected-note {{'init(string:)' declared here}}
}
extension C1c: P1 {} // expected-error{{non-failable initializer requirement 'init(string:)' cannot be satisfied by a failable initializer ('init?')}}
class C2a : P2 {
required init(fail: String) { } // okay to remove failability
}
class C2b : P2 {
required init?(fail: String) { } // okay, ? matches
}
class C2c : P2 {
required init!(fail: String) { } // okay to satisfy init? with init!
}
class C3a : P3 {
required init(failIUO: String) { } // okay to remove failability
}
class C3b : P3 {
required init?(failIUO: String) { } // okay to satisfy ! with ?
}
class C3c : P3 {
required init!(failIUO: String) { } // okay, ! matches
}
// ----------------------------------------------------------------------------
// Initiating failure
// ----------------------------------------------------------------------------
struct InitiateFailureS {
init(string: String) { // expected-note{{use 'init?' to make the initializer 'init(string:)' failable}}{{7-7=?}}
return (nil) // expected-error{{only a failable initializer can return 'nil'}}
}
init(int: Int) {
return 0 // expected-error{{'nil' is the only return value permitted in an initializer}}
}
init?(double: Double) {
return nil // ok
}
init!(char: Character) {
return nil // ok
}
}