blob: 1dc875696328c0407bc5d29c7320a0d1e93b919b [file] [log] [blame]
// RUN: %target-swift-frontend -emit-sil -primary-file %s -o /dev/null -verify
import Swift
func markUsed<T>(_ t: T) {}
// These are tests for definite initialization, which is implemented by the
// memory promotion pass.
func test1() -> Int {
// expected-warning @+1 {{variable 'a' was never mutated; consider changing to 'let' constant}} {{3-6=let}}
var a : Int // expected-note {{variable defined here}}
return a // expected-error {{variable 'a' used before being initialized}}
}
func takes_inout(_ a: inout Int) {}
func takes_inout_any(_ a: inout Any) {}
func takes_closure(_ fn: () -> ()) {}
class SomeClass {
var x : Int // expected-note {{'self.x' not initialized}}
var computedProperty : Int { return 42 }
init() { x = 0 }
init(b : Bool) {
if (b) {}
} // expected-error {{return from initializer without initializing all stored properties}}
func baseMethod() {}
}
struct SomeStruct { var x = 1 }
func takesPointer<T>(_: UnsafePointer<T>) {}
func test2() {
// inout.
var a1 : Int // expected-note {{variable defined here}}
takes_inout(&a1) // expected-error {{variable 'a1' passed by reference before being initialized}}
var a2 = 4
takes_inout(&a2) // ok.
var a3 : Int
a3 = 4
takes_inout(&a3) // ok.
var a4 : Int // expected-note {{variable defined here}}
takesPointer(&a4) // expected-error {{address of variable 'a4' taken before it is initialized}}
// Closures.
// expected-warning @+1 {{variable 'b1' was never mutated}} {{3-6=let}}
var b1 : Int // expected-note {{variable defined here}}
takes_closure { // expected-error {{variable 'b1' captured by a closure before being initialized}}
markUsed(b1)
}
var b1a : Int // expected-note {{variable defined here}}
takes_closure { // expected-error {{variable 'b1a' captured by a closure before being initialized}}
b1a += 1
markUsed(b1a)
}
var b2 = 4
takes_closure { // ok.
markUsed(b2)
}
b2 = 1
var b3 : Int
b3 = 4
takes_closure { // ok.
markUsed(b3)
}
var b4 : Int?
takes_closure { // ok.
markUsed(b4!)
}
b4 = 7
// Structs
var s1 : SomeStruct
s1 = SomeStruct() // ok
_ = s1
var s2 : SomeStruct // expected-note {{variable defined here}}
s2.x = 1 // expected-error {{struct 's2' must be completely initialized before a member is stored to}}
// Classes
// expected-warning @+1 {{variable 'c1' was never mutated}} {{3-6=let}}
var c1 : SomeClass // expected-note {{variable defined here}}
markUsed(c1.x) // expected-error {{variable 'c1' used before being initialized}}
let c2 = SomeClass()
markUsed(c2.x) // ok
// Weak
weak var w1 : SomeClass?
_ = w1 // ok: default-initialized
// expected-warning@+3 {{instance will be immediately deallocated because variable 'w2' is 'weak'}}
// expected-note@+2 {{a strong reference is required to prevent the instance from being deallocated}}
// expected-note@+1 {{'w2' declared here}}
weak var w2 = SomeClass()
_ = w2 // ok
// Unowned. This is immediately crashing code (it causes a retain of a
// released object).
// expected-warning @+1 {{variable 'u1' was never mutated; consider changing to 'let' constant}} {{11-14=let}}
unowned var u1 : SomeClass // expected-note {{variable defined here}}
_ = u1 // expected-error {{variable 'u1' used before being initialized}}
// expected-warning@+3 {{instance will be immediately deallocated because variable 'u2' is 'unowned'}}
// expected-note@+2 {{a strong reference is required to prevent the instance from being deallocated}}
// expected-note@+1 {{'u2' declared here}}
unowned let u2 = SomeClass()
_ = u2 // ok
}
// Tuple field sensitivity.
func test4() {
// expected-warning @+1 {{variable 't1' was never mutated; consider changing to 'let' constant}} {{3-6=let}}
var t1 = (1, 2, 3)
markUsed(t1.0 + t1.1 + t1.2) // ok
// expected-warning @+1 {{variable 't2' was never mutated; consider changing to 'let' constant}} {{3-6=let}}
var t2 : (Int, Int, Int) // expected-note 3 {{variable defined here}}
markUsed(t2.0) // expected-error {{variable 't2.0' used before being initialized}}
markUsed(t2.1) // expected-error {{variable 't2.1' used before being initialized}}
markUsed(t2.2) // expected-error {{variable 't2.2' used before being initialized}}
var t3 : (Int, Int, Int) // expected-note {{variable defined here}}
t3.0 = 1; t3.2 = 42
markUsed(t3.0)
markUsed(t3.1) // expected-error {{variable 't3.1' used before being initialized}}
markUsed(t3.2)
// Partially set, wholly read.
var t4 : (Int, Int, Int) // expected-note 1 {{variable defined here}}
t4.0 = 1; t4.2 = 42
_ = t4 // expected-error {{variable 't4.1' used before being initialized}}
// Subelement sets.
var t5 : (a : (Int, Int), b : Int) // expected-note {{variable defined here}}
t5.a = (1,2)
markUsed(t5.a.0)
markUsed(t5.a.1)
markUsed(t5.b) // expected-error {{variable 't5.b' used before being initialized}}
var t6 : (a : (Int, Int), b : Int) // expected-note {{variable defined here}}
t6.b = 12; t6.a.1 = 1
markUsed(t6.a.0) // expected-error {{variable 't6.a.0' used before being initialized}}
markUsed(t6.a.1)
markUsed(t6.b)
}
func tupleinout(_ a: inout (lo: Int, hi: Int)) {
markUsed(a.0) // ok
markUsed(a.1) // ok
}
// Address only types
func test5<T>(_ x: T, y: T) {
var a : ((T, T), T) // expected-note {{variable defined here}}
a.0 = (x, y)
_ = a // expected-error {{variable 'a.1' used before being initialized}}
}
struct IntFloatStruct { var a = 1, b = 2.0 }
func test6() -> Int {
var a = IntFloatStruct()
a.a = 1
a.b = 2
return a.a
}
// Control flow.
func test7(_ cond: Bool) {
var a : Int
if cond { a = 42 } else { a = 17 }
markUsed(a) // ok
var b : Int // expected-note {{variable defined here}}
if cond { } else { b = 17 }
markUsed(b) // expected-error {{variable 'b' used before being initialized}}
}
protocol SomeProtocol {
func protoMe()
}
protocol DerivedProtocol : SomeProtocol {}
func existentials(_ i: Int, dp: DerivedProtocol) {
// expected-warning @+1 {{variable 'a' was written to, but never read}}
var a : Any = ()
a = i
// expected-warning @+1 {{variable 'b' was written to, but never read}}
var b : Any
b = ()
// expected-warning @+1 {{variable 'c' was never used}} {{7-8=_}}
var c : Any // no uses.
// expected-warning @+1 {{variable 'd1' was never mutated}} {{3-6=let}}
var d1 : Any // expected-note {{variable defined here}}
_ = d1 // expected-error {{variable 'd1' used before being initialized}}
// expected-warning @+1 {{variable 'e' was never mutated}} {{3-6=let}}
var e : SomeProtocol // expected-note {{variable defined here}}
e.protoMe() // expected-error {{variable 'e' used before being initialized}}
var f : SomeProtocol = dp // ok, init'd by existential upcast.
// expected-warning @+1 {{variable 'g' was never mutated}} {{3-6=let}}
var g : DerivedProtocol // expected-note {{variable defined here}}
f = g // expected-error {{variable 'g' used before being initialized}}
_ = f
}
// Tests for top level code.
var g1 : Int // expected-note {{variable defined here}}
var g2 : Int = 42
func testTopLevelCode() { // expected-error {{variable 'g1' used by function definition before being initialized}}
markUsed(g1)
markUsed(g2)
}
var (g3,g4) : (Int,Int) // expected-note 2 {{variable defined here}}
class DITLC_Class {
init() { // expected-error {{variable 'g3' used by function definition before being initialized}}
markUsed(g3)
}
deinit { // expected-error {{variable 'g4' used by function definition before being initialized}}
markUsed(g4)
}
}
struct EmptyStruct {}
func useEmptyStruct(_ a: EmptyStruct) {}
func emptyStructTest() {
// <rdar://problem/20065892> Diagnostic for an uninitialized constant calls it a variable
let a : EmptyStruct // expected-note {{constant defined here}}
useEmptyStruct(a) // expected-error {{constant 'a' used before being initialized}}
var (b,c,d) : (EmptyStruct,EmptyStruct,EmptyStruct) // expected-note 2 {{variable defined here}}
c = EmptyStruct()
useEmptyStruct(b) // expected-error {{variable 'b' used before being initialized}}
useEmptyStruct(c)
useEmptyStruct(d) // expected-error {{variable 'd' used before being initialized}}
var (e,f) : (EmptyStruct,EmptyStruct)
(e, f) = (EmptyStruct(),EmptyStruct())
useEmptyStruct(e)
useEmptyStruct(f)
var g : (EmptyStruct,EmptyStruct)
g = (EmptyStruct(),EmptyStruct())
useEmptyStruct(g.0)
useEmptyStruct(g.1)
}
func takesTuplePair(_ a : inout (SomeClass, SomeClass)) {}
// This tests cases where a store might be an init or assign based on control
// flow path reaching it.
func conditionalInitOrAssign(_ c : Bool, x : Int) {
var t : Int // Test trivial types.
if c {
t = 0
}
if c {
t = x
}
t = 2
_ = t
// Nontrivial type
var sc : SomeClass
if c {
sc = SomeClass()
}
sc = SomeClass()
_ = sc
// Tuple element types
var tt : (SomeClass, SomeClass)
if c {
tt.0 = SomeClass()
} else {
tt.1 = SomeClass()
}
tt.0 = SomeClass()
tt.1 = tt.0
var t2 : (SomeClass, SomeClass) // expected-note {{variable defined here}}
t2.0 = SomeClass()
takesTuplePair(&t2) // expected-error {{variable 't2.1' passed by reference before being initialized}}
}
enum NotInitializedUnion {
init() {
} // expected-error {{'self.init' isn't called on all paths before returning from initializer}}
case X
case Y
}
extension NotInitializedUnion {
init(a : Int) {
} // expected-error {{'self.init' isn't called on all paths before returning from initializer}}
}
enum NotInitializedGenericUnion<T> {
init() {
} // expected-error {{'self.init' isn't called on all paths before returning from initializer}}
case X
}
class SomeDerivedClass : SomeClass {
var y : Int
override init() {
y = 42 // ok
super.init()
}
init(a : Bool) {
super.init() // expected-error {{property 'self.y' not initialized at super.init call}}
}
init(a : Bool, b : Bool) {
// x is a superclass member. It cannot be used before we are initialized.
x = 17 // expected-error {{'self' used in property access 'x' before 'super.init' call}}
y = 42
super.init()
}
init(a : Bool, b : Bool, c : Bool) {
y = 42
super.init()
}
init(a : Bool, b : Bool, c : Bool, d : Bool) {
y = 42
super.init()
super.init() // expected-error {{'super.init' called multiple times in initializer}}
}
init(a : Bool, b : Bool, c : Bool, d : Bool, e : Bool) {
super.init() // expected-error {{property 'self.y' not initialized at super.init call}}
super.init() // expected-error {{'super.init' called multiple times in initializer}}
}
init(a : Bool, b : Bool, c : Bool, d : Bool, e : Bool, f : Bool) {
y = 11
if a { super.init() }
x = 42 // expected-error {{'self' used in property access 'x' before 'super.init' call}}
} // expected-error {{'super.init' isn't called on all paths before returning from initializer}}
func someMethod() {}
init(a : Int) {
y = 42
super.init()
}
init(a : Int, b : Bool) {
y = 42
someMethod() // expected-error {{'self' used in method call 'someMethod' before 'super.init' call}}
super.init()
}
init(a : Int, b : Int) {
y = 42
baseMethod() // expected-error {{'self' used in method call 'baseMethod' before 'super.init' call}}
super.init()
}
init(a : Int, b : Int, c : Int) {
y = computedProperty // expected-error {{'self' used in property access 'computedProperty' before 'super.init' call}}
super.init()
}
}
//===----------------------------------------------------------------------===//
// Delegating initializers
//===----------------------------------------------------------------------===//
class DelegatingCtorClass {
var ivar: EmptyStruct
init() { ivar = EmptyStruct() }
convenience init(x: EmptyStruct) {
self.init()
_ = ivar // okay: ivar has been initialized by the delegation above
}
convenience init(x: EmptyStruct, y: EmptyStruct) {
_ = ivar // expected-error {{'self' used before 'self.init' call}}
ivar = x // expected-error {{'self' used before 'self.init' call}}
self.init()
}
convenience init(x: EmptyStruct, y: EmptyStruct, z: EmptyStruct) {
self.init()
self.init()
}
convenience init(x: (EmptyStruct, EmptyStruct)) {
method() // expected-error {{'self' used before 'self.init' call}}
self.init()
}
convenience init(c : Bool) {
if c {
return
}
self.init()
} // expected-error {{'self.init' isn't called on all paths before returning from initializer}}
convenience init(bool: Bool) {
doesNotReturn()
}
convenience init(double: Double) {
} // expected-error{{'self.init' isn't called on all paths before returning from initializer}}
func method() {}
}
//===----------------------------------------------------------------------===//
// Delegating initializers vs extensions
//===----------------------------------------------------------------------===//
protocol TriviallyConstructible {
init()
func go(_ x: Int)
}
extension TriviallyConstructible {
init(down: Int) {
go(down) // expected-error {{'self' used before 'self.init' call or assignment to 'self'}}
self.init()
}
}
//===----------------------------------------------------------------------===//
// Various bugs
//===----------------------------------------------------------------------===//
// rdar://16119509 - Dataflow problem where we reject valid code.
class rdar16119509_Buffer {
init(x : Int) { }
}
class rdar16119509_Base {}
class rdar16119509_Derived : rdar16119509_Base {
override init() {
var capacity = 2
while capacity < 2 {
capacity <<= 1
}
buffer = rdar16119509_Buffer(x: capacity)
}
var buffer : rdar16119509_Buffer
}
// <rdar://problem/16797372> Bogus error: self.init called multiple times in initializer
extension Foo {
convenience init() {
for _ in 0..<42 {
}
self.init(a: 4)
}
}
class Foo {
init(a : Int) {}
}
func doesNotReturn() -> Never {
while true {}
}
func doesReturn() {}
func testNoReturn1(_ b : Bool) -> Any {
var a : Any
if b {
a = 42
} else {
doesNotReturn()
}
return a // Ok, because the noreturn call path isn't viable.
}
func testNoReturn2(_ b : Bool) -> Any {
var a : Any // expected-note {{variable defined here}}
if b {
a = 42
} else {
doesReturn()
}
// Not ok, since doesReturn() doesn't kill control flow.
return a // expected-error {{variable 'a' used before being initialized}}
}
class PerpetualMotion {
func start() -> Never {
repeat {} while true
}
static func stop() -> Never {
repeat {} while true
}
}
func testNoReturn3(_ b : Bool) -> Any {
let a : Int
switch b {
default:
PerpetualMotion().start() // expected-note {{a call to a never-returning function}}
}
return a // expected-warning {{will never be executed}}
}
func testNoReturn4(_ b : Bool) -> Any {
let a : Int
switch b {
default:
PerpetualMotion.stop() // expected-note {{a call to a never-returning function}}
}
return a // expected-warning {{will never be executed}}
}
// <rdar://problem/16687555> [DI] New convenience initializers cannot call inherited convenience initializers
class BaseWithConvenienceInits {
init(int: Int) {}
convenience init() {
self.init(int: 3)
}
}
class DerivedUsingConvenienceInits : BaseWithConvenienceInits {
convenience init(string: String) {
self.init()
}
}
// <rdar://problem/16660680> QoI: preconditionFailure() in init method complains about super.init being called multiple times
class ClassWhoseInitDoesntReturn : BaseWithConvenienceInits {
init() {
preconditionFailure("leave me alone dude");
}
}
// <rdar://problem/17233681> DI: Incorrectly diagnostic in delegating init with generic enum
enum r17233681Lazy<T> {
case Thunk(() -> T)
case Value(T)
init(value: T) {
self = .Value(value)
}
}
extension r17233681Lazy {
init(otherValue: T) {
self.init(value: otherValue)
}
}
// <rdar://problem/17556858> delegating init that delegates to @_transparent init fails
struct FortyTwo { }
extension Double {
init(v : FortyTwo) {
self.init(0.0)
}
}
// <rdar://problem/17686667> If super.init is implicitly inserted, DI diagnostics have no location info
class r17686667Base {}
class r17686667Test : r17686667Base {
var x: Int
override init() { // expected-error {{property 'self.x' not initialized at implicitly generated super.init call}}
}
}
// <rdar://problem/18199087> DI doesn't catch use of super properties lexically inside super.init call
class r18199087BaseClass {
let data: Int
init(val: Int) {
data = val
}
}
class r18199087SubClassA: r18199087BaseClass {
init() {
super.init(val: self.data) // expected-error {{'self' used in property access 'data' before 'super.init' call}}
}
}
class r18199087BaseClassNonTrivial {
let data: SomeClass
init(val: SomeClass) {
data = val
}
}
class r18199087SubClassANonTrivial: r18199087BaseClassNonTrivial {
init() {
super.init(val: self.data) // expected-error {{'self' used in property access 'data' before 'super.init' call}}
}
}
// <rdar://problem/18414728> QoI: DI should talk about "implicit use of self" instead of individual properties in some cases
class rdar18414728Base {
var prop:String? { return "boo" }
// expected-note @+1 {{change 'let' to 'var' to make it mutable}} {{3-6=var}}
let aaaaa:String // expected-note 3 {{'self.aaaaa' not initialized}}
init() {
if let p1 = prop { // expected-error {{'self' used in property access 'prop' before all stored properties are initialized}}
aaaaa = p1
}
aaaaa = "foo" // expected-error {{immutable value 'self.aaaaa' may only be initialized once}}
}
init(a : ()) {
method1(42) // expected-error {{'self' used in method call 'method1' before all stored properties are initialized}}
aaaaa = "foo"
}
init(b : ()) {
final_method() // expected-error {{'self' used in method call 'final_method' before all stored properties are initialized}}
aaaaa = "foo"
}
init(c : ()) {
aaaaa = "foo"
final_method() // ok
}
func method1(_ a : Int) {}
final func final_method() {}
}
class rdar18414728Derived : rdar18414728Base {
var prop2:String? { return "boo" }
// expected-note @+1 2 {{change 'let' to 'var' to make it mutable}} {{3-6=var}} {{3-6=var}}
let aaaaa2:String
override init() {
if let p1 = prop2 { // expected-error {{'self' used in property access 'prop2' before 'super.init' call}}
aaaaa2 = p1
}
aaaaa2 = "foo" // expected-error {{immutable value 'self.aaaaa2' may only be initialized once}}
super.init()
}
override init(a : ()) {
method2() // expected-error {{'self' used in method call 'method2' before 'super.init' call}}
aaaaa2 = "foo"
super.init()
}
override init(b : ()) {
aaaaa2 = "foo"
method2() // expected-error {{'self' used in method call 'method2' before 'super.init' call}}
super.init()
}
override init(c : ()) {
super.init() // expected-error {{property 'self.aaaaa2' not initialized at super.init call}}
aaaaa2 = "foo" // expected-error {{immutable value 'self.aaaaa2' may only be initialized once}}
method2()
}
func method2() {}
}
struct rdar18414728Struct {
var computed:Int? { return 4 }
var i : Int // expected-note 2 {{'self.i' not initialized}}
var j : Int // expected-note {{'self.j' not initialized}}
init() {
j = 42
if let p1 = computed { // expected-error {{'self' used before all stored properties are initialized}}
i = p1
}
i = 1
}
init(a : ()) {
method(42) // expected-error {{'self' used before all stored properties are initialized}}
i = 1
j = 2
}
func method(_ a : Int) {}
}
extension Int {
mutating func mutate() {}
func inspect() {}
}
extension Array {
subscript(replacing index: Int, with newValue: Element) -> Element {
mutating get {
let oldValue = self[index]
self[index] = newValue
return oldValue
}
}
}
func throwingSwap<T>(_ a: inout T, _ b: inout T) throws {}
// <rdar://problem/19035287> let properties should only be initializable, not reassignable
struct LetProperties {
// expected-note @+1 5 {{change 'let' to 'var' to make it mutable}} {{3-6=var}}
let arr : [Int]
// expected-note @+1 7 {{change 'let' to 'var' to make it mutable}} {{3-6=var}} {{3-6=var}}
let (u, v) : (Int, Int)
// expected-note @+1 2 {{change 'let' to 'var' to make it mutable}} {{3-6=var}} {{3-6=var}}
let w : (Int, Int)
let x = 42
// expected-note @+1 {{change 'let' to 'var' to make it mutable}} {{3-6=var}}
let y : Int
let z : Int? // expected-note{{'self.z' not initialized}}
func methodTakesInOut(_ x: inout Int) {}
func throwingMethodTakesInOut(_ x: inout Int) throws {}
// Let properties can be initialized naturally exactly once along any given
// path through an initializer.
init(cond : Bool) {
if cond {
w.0 = 4
(u,v) = (4,2)
y = 71
} else {
y = 13
v = 2
u = v+1
w.0 = 7
}
w.1 = 19
z = nil
arr = []
}
// Multiple initializations are an error.
init(a : Int) {
y = a
y = a // expected-error {{immutable value 'self.y' may only be initialized once}}
u = a
v = a
u = a // expected-error {{immutable value 'self.u' may only be initialized once}}
v = a // expected-error {{immutable value 'self.v' may only be initialized once}}
w.0 = a
w.1 = a
w.0 = a // expected-error {{immutable value 'self.w.0' may only be initialized once}}
w.1 = a // expected-error {{immutable value 'self.w.1' may only be initialized once}}
arr = []
arr = [] // expected-error {{immutable value 'self.arr' may only be initialized once}}
} // expected-error {{return from initializer without initializing all stored properties}}
// inout uses of let properties are an error.
init() throws {
u = 1; v = 13; w = (1,2); y = 1 ; z = u
var variable = 42
swap(&u, &variable) // expected-error {{immutable value 'self.u' must not be passed inout}}
try throwingSwap(&u, &variable) // expected-error {{immutable value 'self.u' must not be passed inout}}
u.inspect() // ok, non mutating.
u.mutate() // expected-error {{mutating method 'mutate' may not be used on immutable value 'self.u'}}
arr = []
arr += [] // expected-error {{mutating operator '+=' may not be used on immutable value 'self.arr'}}
arr.append(4) // expected-error {{mutating method 'append' may not be used on immutable value 'self.arr'}}
arr[12] = 17 // expected-error {{cannot mutate subscript of immutable value 'self.arr'}}
let _ = arr[replacing: 12, with: 17] // expected-error {{mutating accessor for subscript may not be used on immutable value 'self.arr'}}
methodTakesInOut(&u) // expected-error {{immutable value 'self.u' must not be passed inout}}
try throwingMethodTakesInOut(&u) // expected-error {{immutable value 'self.u' must not be passed inout}}
}
}
// <rdar://problem/19215313> let properties don't work with protocol method dispatch
protocol TestMutabilityProtocol {
func toIntMax()
mutating func changeToIntMax()
}
class C<T : TestMutabilityProtocol> {
let x : T
let y : T // expected-note {{change 'let' to 'var' to make it mutable}}
init(a : T) {
x = a; y = a
x.toIntMax()
y.changeToIntMax() // expected-error {{mutating method 'changeToIntMax' may not be used on immutable value 'self.y'}}
}
}
struct MyMutabilityImplementation : TestMutabilityProtocol {
func toIntMax() {
}
mutating func changeToIntMax() {
}
}
// <rdar://problem/16181314> don't require immediate initialization of 'let' values
func testLocalProperties(_ b : Int) -> Int {
// expected-note @+1 {{change 'let' to 'var' to make it mutable}} {{3-6=var}}
let x : Int
let y : Int // never assigned is ok expected-warning {{immutable value 'y' was never used}} {{7-8=_}}
x = b
x = b // expected-error {{immutable value 'x' may only be initialized once}}
// This is ok, since it is assigned multiple times on different paths.
let z : Int
if true || false {
z = b
} else {
z = b
}
_ = z
return x
}
// Should be rejected as multiple assignment.
func testAddressOnlyProperty<T>(_ b : T) -> T {
// expected-note @+1 {{change 'let' to 'var' to make it mutable}} {{3-6=var}}
let x : T // expected-note {{change 'let' to 'var' to make it mutable}}
let y : T
let z : T // never assigned is ok. expected-warning {{immutable value 'z' was never used}} {{7-8=_}}
x = b
y = b
x = b // expected-error {{immutable value 'x' may only be initialized once}}
var tmp = b
swap(&x, &tmp) // expected-error {{immutable value 'x' must not be passed inout}}
return y
}
// <rdar://problem/19254812> DI bug when referencing let member of a class
class r19254812Base {}
class r19254812Derived: r19254812Base{
let pi = 3.14159265359
init(x : ()) {
markUsed(pi) // ok, no diagnostic expected.
}
}
// <rdar://problem/19259730> Using mutating methods in a struct initializer with a let property is rejected
struct StructMutatingMethodTest {
let a, b: String // expected-note 2 {{'self.b' not initialized}}
init(x: String, y: String) {
a = x
b = y
mutate() // ok
}
init(x: String) {
a = x
mutate() // expected-error {{'self' used before all stored properties are initialized}}
b = x
}
init() {
a = ""
nonmutate() // expected-error {{'self' used before all stored properties are initialized}}
b = ""
}
mutating func mutate() {}
func nonmutate() {}
}
// <rdar://problem/19268443> DI should reject this call to transparent function
class TransparentFunction {
let x : Int // expected-note {{change 'let' to 'var' to make it mutable}}
let y : Int // expected-note {{change 'let' to 'var' to make it mutable}}
init() {
x = 42
x += 1 // expected-error {{mutating operator '+=' may not be used on immutable value 'self.x'}}
y = 12
myTransparentFunction(&y) // expected-error {{immutable value 'self.y' must not be passed inout}}
}
}
@_transparent
func myTransparentFunction(_ x : inout Int) {}
// <rdar://problem/19782264> Immutable, optional class members can't have their subproperties read from during init()
class MyClassWithAnInt {
let channelCount : Int = 42
}
class MyClassTestExample {
let clientFormat : MyClassWithAnInt!
init(){
clientFormat = MyClassWithAnInt()
_ = clientFormat.channelCount
}
}
// <rdar://problem/19746552> QoI: variable "used before being initialized" instead of "returned uninitialized" in address-only enum/struct
struct AddressOnlyStructWithInit<T, U> {
let a : T?
let b : U? // expected-note {{'self.b' not initialized}}
init(a : T) {
self.a = a
} // expected-error {{return from initializer without initializing all stored properties}}
}
enum AddressOnlyEnumWithInit<T> {
case X(T), Y
init() {
} // expected-error {{'self.init' isn't called on all paths before returning from initializer}}
}
// <rdar://problem/20135113> QoI: enum failable init that doesn't assign to self produces poor error
enum MyAwesomeEnum {
case One, Two
init?() {
} // expected-error {{'self' used before 'self.init' call or assignment to 'self'}}
}
// <rdar://problem/20679379> DI crashes on initializers on protocol extensions
extension SomeProtocol {
init?() {
let a = self // expected-error {{'self' used before 'self.init' call or assignment to 'self'}}
self = a
}
init(a : Int) {
} // expected-error {{'self.init' isn't called on all paths before returning from initializer}}
init(c : Float) {
protoMe() // expected-error {{'self' used before 'self.init' call or assignment to 'self'}}
} // expected-error {{'self.init' isn't called on all paths before returning from initializer}}
}
// Lvalue check when the archetypes are not the same.
struct LValueCheck<T> {
// expected-note @+1 {{change 'let' to 'var' to make it mutable}} {{3-6=var}}
let x = 0 // expected-note {{initial value already provided in 'let' declaration}}
}
extension LValueCheck {
init(newY: Int) {
x = 42 // expected-error {{immutable value 'self.x' may only be initialized once}}
}
}
// <rdar://problem/20477982> Accessing let-property with default value in init() can throw spurious error
struct DontLoadFullStruct {
let x: Int = 1
let y: Int
init() {
y = x // ok!
}
}
func testReassignment() {
let c : Int // expected-note {{change 'let' to 'var' to make it mutable}} {{3-6=var}}
c = 12
c = 32 // expected-error {{immutable value 'c' may only be initialized once}}
_ = c
}
// <rdar://problem/21295093> Swift protocol cannot implement default initializer
protocol ProtocolInitTest {
init()
init(a : Int)
var i: Int { get set }
}
extension ProtocolInitTest {
init() {
} // expected-error {{'self.init' isn't called on all paths before returning from initializer}}
init(b : Float) {
self.init(a: 42) // ok
}
// <rdar://problem/21684596> QoI: Poor DI diagnostic in protocol extension initializer
init(test1 ii: Int) {
i = ii // expected-error {{'self' used before 'self.init' call or assignment to 'self'}}
self.init()
}
init(test2 ii: Int) {
self = unsafeBitCast(0, to: Self.self)
i = ii
}
init(test3 ii: Int) {
i = ii // expected-error {{'self' used before 'self.init' call or assignment to 'self'}}
self = unsafeBitCast(0, to: Self.self)
}
init(test4 ii: Int) {
i = ii // expected-error {{'self' used before 'self.init' call or assignment to 'self'}}
} // expected-error {{'self.init' isn't called on all paths before returning from initializer}}
}
// <rdar://problem/22436880> Function accepting UnsafeMutablePointer is able to change value of immutable value
func bug22436880(_ x: UnsafeMutablePointer<Int>) {}
func test22436880() {
let x: Int // expected-note {{change 'let' to 'var' to make it mutable}}
x = 1
bug22436880(&x) // expected-error {{immutable value 'x' must not be passed inout}}
}
// sr-184
let x: String? // expected-note 2 {{constant defined here}}
print(x?.count as Any) // expected-error {{constant 'x' used before being initialized}}
print(x!) // expected-error {{constant 'x' used before being initialized}}
// <rdar://problem/22723281> QoI: [DI] Misleading error from Swift compiler when using an instance method in init()
protocol PMI {
func getg()
}
extension PMI {
func getg() {}
}
class WS: PMI {
final let x: String // expected-note {{'self.x' not initialized}}
init() {
getg() // expected-error {{'self' used in method call 'getg' before all stored properties are initialized}}
self.x = "foo"
}
}
// <rdar://problem/23013334> DI QoI: Diagnostic claims that property is being used when it actually isn't
class r23013334 {
var B: Int // expected-note {{'self.B' not initialized}}
var A: String
init(A: String) throws {
self.A = A
self.A.withCString { cString -> () in // expected-error {{'self' captured by a closure before all members were initialized}}
print(self.A)
return ()
}
self.B = 0
}
}
class r23013334Derived : rdar16119509_Base {
var B: Int // expected-note {{'self.B' not initialized}}
var A: String
init(A: String) throws {
self.A = A
self.A.withCString { cString -> () in // expected-error {{'self' captured by a closure before all members were initialized}}
print(self.A)
return ()
}
self.B = 0
}
}
// sr-1469
struct SR1469_Struct1 {
let a: Int
let b: Int // expected-note {{'self.b' not initialized}}
init?(x: Int, y: Int) {
self.a = x
if y == 42 {
return // expected-error {{return from initializer without initializing all stored properties}}
}
// many lines later
self.b = y
}
}
struct SR1469_Struct2 {
let a: Int
let b: Int // expected-note {{'self.b' not initialized}}
init?(x: Int, y: Int) {
self.a = x
return // expected-error {{return from initializer without initializing all stored properties}}
}
}
struct SR1469_Struct3 {
let a: Int
let b: Int // expected-note {{'self.b' not initialized}}
init?(x: Int, y: Int) {
self.a = x
if y == 42 {
self.b = y
return
}
} // expected-error {{return from initializer without initializing all stored properties}}
}
enum SR1469_Enum1 {
case A, B
init?(x: Int) {
if x == 42 {
return
}
// many lines later
self = .A
} // expected-error {{'self' used before 'self.init' call or assignment to 'self'}}
}
enum SR1469_Enum2 {
case A, B
init?() {
return
} // expected-error {{'self' used before 'self.init' call or assignment to 'self'}}
}
enum SR1469_Enum3 {
case A, B
init?(x: Int) {
if x == 42 {
self = .A
return
}
} // expected-error {{'self' used before 'self.init' call or assignment to 'self'}}
}
class BadFooSuper {
init() {}
init(_ x: BadFooSuper) {}
}
class BadFooSubclass: BadFooSuper {
override init() {
super.init(self) // expected-error {{'self' used before 'super.init' call}}
}
}
class SuperConvenienceBase {
public init(_ i: Int) {}
public convenience init(_ i1: Int, _ i2: Int) {
self.init(i2)
}
}
class SuperConvenienceSub : SuperConvenienceBase {
public override init(_ i: Int) {
super.init(i)
}
public init(_ i1: Int, _ i2: Int, _ i3: Int) {
self.init(i1, i1) // expected-error{{'self' used before 'super.init' call}}
} // expected-error{{'super.init' isn't called}}
}
// While testing some changes I found this regression that wasn't
// covered by any existing tests
class Base {}
func makeAnAny() -> Any { return 3 }
class Derived : Base {
var x: Int?
var y: Int?
override init() {
x = makeAnAny() as? Int
y = makeAnAny() as? Int
super.init()
}
}
// This test makes sure that we properly error (but don't crash) when calling a
// subclass method as an argument to a super.init.
class MethodTestParent {
init(i: Int) {}
}
class MethodTestChild : MethodTestParent {
init() {
super.init(i: getInt()) // expected-error {{'self' used in method call 'getInt' before 'super.init' call}}
}
init(val: ()) {
// Currently we squelch the inner error of using self in method call for 'getInt2'
super.init(i: getInt2(x: self)) // expected-error {{'self' used in method call 'getInt2' before 'super.init' call}}
}
func getInt() -> Int {
return 0
}
func getInt2(x: MethodTestChild) -> Int {
return 0
}
}
// This test makes sure that if we cast self to a protocol (implicitly or not), we properly error.
protocol ProtocolCastTestProtocol : class {
}
class ProtocolCastTestParent {
init(foo f: ProtocolCastTestProtocol) {
}
init(foo2 f: Any) {
}
}
class ProtocolCastTestChild : ProtocolCastTestParent, ProtocolCastTestProtocol {
private let value: Int
init(value1 v: Int) {
value = v
super.init(foo: self) // expected-error {{'self' used before 'super.init' call}}
}
init(value2 v: Int) {
value = v
super.init(foo: self as ProtocolCastTestProtocol) // expected-error {{'self' used before 'super.init' call}}
}
init(value3 v: Int) {
value = v
super.init(foo2: self) // expected-error {{'self' used before 'super.init' call}}
}
init(value4 v: Int) {
value = v
super.init(foo2: self as Any) // expected-error {{'self' used before 'super.init' call}}
}
}
// Make sure we don't diagnose immediate deallocation of instances if we first
// assign them through strong variables.
func testDontDiagnoseUnownedImmediateDeallocationThroughStrong() {
weak var c1: SomeClass?
do {
let tmp = SomeClass()
c1 = tmp
}
unowned let c2: SomeClass
do {
let tmp = SomeClass()
c2 = tmp
}
weak var c3: SomeClass?
let c3Tmp = SomeClass()
c3 = c3Tmp
unowned let c4: SomeClass
let c4Tmp = SomeClass()
c4 = c4Tmp
_ = c1; _ = c2; _ = c3; _ = c4
}
class ClassWithUnownedProperties {
weak var c1: SomeClass?
unowned var c2: SomeClass
init(c2: SomeClass) {
self.c2 = c2
}
func assignToC1() {
let tmp = SomeClass()
c1 = tmp
}
func assignToC2() {
let tmp = SomeClass()
c2 = tmp
}
}
// Tests for DI when optionals are defined using unchecked_take_enum_data_addr
// <rdar://38624845>
func testOptionalDoubleWrite() -> String? {
let sConst: String? // expected-note {{change 'let' to 'var' to make it mutable}}
sConst = ""
sConst? = "v2" // expected-error {{immutable value 'sConst' may only be initialized once}}
return sConst
}
func testOptionalDoubleWrite2() -> Int? {
let x: Int? // expected-note {{change 'let' to 'var' to make it mutable}}
x = 0
x? = 0 // expected-error {{immutable value 'x' may only be initialized once}}
return x
}
protocol DIOptionalTestProtocol {
var f: Int { get set }
}
func testOptionalDoubleWrite3(p1: DIOptionalTestProtocol) -> DIOptionalTestProtocol? {
let x: DIOptionalTestProtocol? // expected-note {{change 'let' to 'var' to make it mutable}}
x = p1
x? = p1 // expected-error {{immutable value 'x' may only be initialized once}}
return x
}
func testOptionalWrite() {
let x: Int? // expected-note {{constant defined here}}
// expected-warning@-1 {{immutable value 'x' was never used; consider removing it}}
x? = 0 // expected-error {{constant 'x' used before being initialized}}
}
func testOptionalWriteGenerics<T>(p: T) -> T? {
let x: T? // expected-note {{constant defined here}}
// expected-note@-1 {{change 'let' to 'var' to make it mutable}}
x? = p // expected-error {{constant 'x' used before being initialized}}
x = p // expected-error {{immutable value 'x' may only be initialized once}}
return x
}
func testOptionalWriteGenerics2<T>(p: T) -> T? {
let x: T? // expected-note {{change 'let' to 'var' to make it mutable}}
x = p
x? = p // expected-error {{immutable value 'x' may only be initialized once}}
return x
}
enum TestOptionalEnum {
case Cons(Int)
case Nil
}
func testOptionalWithEnum(p: TestOptionalEnum) -> TestOptionalEnum? {
let x: TestOptionalEnum? // expected-note {{change 'let' to 'var' to make it mutable}}
x = p
x? = p // expected-error {{immutable value 'x' may only be initialized once}}
return x
}
// Tests for optional chaining
class DIOptionalTestClass {
var r: DIOptionalTestClass? = nil
var f: Int = 0;
let g: Int = 0;
}
func testOptionalChaining(p: DIOptionalTestClass?) {
p?.f = 2
}
func testOptionalChaining2(p: DIOptionalTestClass?) -> DIOptionalTestClass? {
let x: DIOptionalTestClass?
x = p
x?.f = 1
p?.r?.f = 2
return x
}
struct DIOptionalTestStruct {
var f: Int
}
func testOptionalChaining3() -> DIOptionalTestStruct? {
let x: DIOptionalTestStruct? // expected-note {{change 'let' to 'var' to make it mutable}}
x = DIOptionalTestStruct(f: 0)
x?.f = 2 // expected-error {{immutable value 'x' may only be initialized once}}
return x
}
extension DIOptionalTestStruct {
public init?() {
self.f = 0
}
}
func testOptionalChaining4() -> DIOptionalTestStruct? {
let x: DIOptionalTestStruct? // expected-note {{change 'let' to 'var' to make it mutable}}
x = DIOptionalTestStruct()
x?.f = 2 // expected-error {{immutable value 'x' may only be initialized once}}
return x
}
struct DIOptionalTestStructPair {
var pair: (Int, Int)
}
func test6() -> DIOptionalTestStructPair? {
let x: DIOptionalTestStructPair? // expected-note {{change 'let' to 'var' to make it mutable}}
x = DIOptionalTestStructPair(pair: (0, 0))
x?.pair.0 = 1 // expected-error {{immutable value 'x' may only be initialized once}}
return x
}
func testOptionalChainingWithGenerics<T: DIOptionalTestProtocol>(p: T) -> T? {
let x: T? // expected-note {{constant defined here}}
// expected-note@-1 {{constant defined here}}
// expected-note@-2 {{constant defined here}}
// note that here assignment to 'f' is a call to the setter.
x?.f = 0 // expected-error {{constant 'x' used before being initialized}}
// expected-error@-1 {{constant 'x' passed by reference before being initialized}}
return x // expected-error {{constant 'x' used before being initialized}}
}
// Test optional tuples
func testOptionalTupleUse(x: Bool) -> Int? {
let optTuple: (Int, Int)? // expected-note {{constant defined here}}
// expected-note@-1 {{constant defined here}}
return optTuple?.1 // expected-error {{constant 'optTuple' used before being initialized}}
// expected-error@-1 {{constant 'optTuple' used before being initialized}}
}
func testOptionalTupleOverwrite(x: Bool) -> (Int, Int)? {
let tupleVar: (Int, Int)? // expected-note {{change 'let' to 'var' to make it mutable}}
tupleVar = (0, 0)
tupleVar?.1 = 1 // expected-error {{immutable value 'tupleVar' may only be initialized once}}
return tupleVar
}
func testOptionalTupleNoError(x: Bool) -> Int? {
let optTuple: (Int, Int)?
optTuple = (0, 0)
return optTuple?.1
}
func testOptionalTupleNoError2(x: Bool) -> (Int, Int)? {
var tupleVar: (Int, Int)?
tupleVar = (0, 0)
tupleVar?.1 = 1
return tupleVar
}
// Test forced unwrapping of optionals
func testOptionalUseByUnwrap() {
let x: Int? // expected-note {{constant defined here}}
// expected-warning@-1 {{immutable value 'x' was never used; consider removing it}}
x! = 0 // expected-error {{constant 'x' used before being initialized}}
}
func testOptionalWriteByUnwrap() -> Int? {
let x: Int? // expected-note {{change 'let' to 'var' to make it mutable}}
x = 0
x! = 0 // expected-error {{immutable value 'x' may only be initialized once}}
return x
}
func testOptionalUnwrapNoError() -> Int? {
let x: Int?
x = 0
return x!
}
// <https://bugs.swift.org/browse/SR-9451>
class StrongCycle {
var c: StrongCycle
var d: Int
init(first: ()) {
self.d = 10
self.c = self // expected-error {{variable 'self.c' used before being initialized}}
}
init(second: ()) {
self.c = self // expected-error {{variable 'self.c' used before being initialized}}
self.d = 10
}
}
class WeakCycle {
weak var c: WeakCycle?
var d: Int
init(first: ()) { // FIXME: This is inconsistent with the strong reference behavior above
self.d = 10
self.c = self
}
init(second: ()) {
self.c = self // expected-error {{variable 'self.d' used before being initialized}}
self.d = 10
}
}