Files
swift-mirror/test/SILOptimizer/definite_init_cross_module.swift
Robert Widmann c9b316433a Correct the DeclContext Used For 'super.init()' Synthesis
When a subclass inherits from a superclass that declares a no-args
desginated initializer and no other visible inits, the subclass may
elide calls to 'super.init()'. The way this was enforced was by looking
into the superclass *from the subclass' init*, not from the subclass.
This ensured that not only would we get results for initializers, we'd
get results for initializers that were actually _callable_ from the
subclass.

The changes in apple/swift#33515 accidentally swapped the decl context
here, which caused this lookup to start returning additional results.
In that case, we consider it ambiguous as to which designated
initializer we should synthesize, and so we bail.

The net result is DI errors where there previously were none. Let's put
this back in order.

rdar://67560590, rdar://67686660, rdar://67690116, SR-13427
2020-08-24 16:12:13 -07:00

281 lines
8.9 KiB
Swift

// RUN: %empty-directory(%t)
// RUN: %target-swift-frontend -emit-module -emit-module-path=%t/OtherModule.swiftmodule %S/Inputs/definite_init_cross_module/OtherModule.swift
// RUN: %target-swift-frontend -emit-sil -verify -I %t -swift-version 5 %s > /dev/null -enable-objc-interop -disable-objc-attr-requires-foundation-module -import-objc-header %S/Inputs/definite_init_cross_module/BridgingHeader.h
// RUN: %empty-directory(%t)
// RUN: %target-swift-frontend -emit-module -emit-module-path=%t/OtherModule.swiftmodule %S/Inputs/definite_init_cross_module/OtherModule.swift
// RUN: %target-swift-frontend -emit-sil -verify -I %t -swift-version 5 %s > /dev/null -enable-objc-interop -disable-objc-attr-requires-foundation-module -import-objc-header %S/Inputs/definite_init_cross_module/BridgingHeader.h
import OtherModule
extension Point {
init(xx: Double, yy: Double) {
self.x = xx // expected-error {{'self' used before 'self.init' call or assignment to 'self'}}
self.y = yy // 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}}
init(xx: Double) {
self.x = xx // 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}}
init(xxx: Double, yyy: Double) {
// This is OK
self.init(x: xxx, y: yyy)
}
init(other: Point) {
// This is OK
self = other
}
init(other: Point, x: Double) {
// This is OK
self = other
self.x = x
}
init(other: Point, xx: Double) {
self.x = xx // expected-error {{'self' used before 'self.init' call or assignment to 'self'}}
self = other
}
init(other: Point, x: Double, cond: Bool) {
// This is OK
self = other
if cond { self.x = x }
}
init(other: Point, xx: Double, cond: Bool) {
if cond { self = other }
self.x = xx // expected-error {{'self' used before 'self.init' call or assignment to 'self'}}
self.y = 0 // 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}}
// Test failable initializer.
init?(p: Point) {
if p.x > 0 {
self = p
}
} // expected-error {{'self.init' isn't called on all paths before returning from initializer}}
}
extension GenericPoint {
init(xx: T, yy: T) {
self.x = xx // expected-error {{'self' used before 'self.init' call or assignment to 'self'}}
self.y = yy // 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}}
init(xxx: T, yyy: T) {
// This is OK
self.init(x: xxx, y: yyy)
}
init(other: GenericPoint<T>) {
// This is OK
self = other
}
init(other: GenericPoint<T>, x: T) {
// This is OK
self = other
self.x = x
}
init(other: GenericPoint<T>, xx: T) {
self.x = xx // expected-error {{'self' used before 'self.init' call or assignment to 'self'}}
self = other
}
init(other: GenericPoint<T>, x: T, cond: Bool) {
// This is OK
self = other
if cond { self.x = x }
}
init(other: GenericPoint<T>, xx: T, cond: Bool) {
if cond { self = other }
self.x = xx // expected-error {{'self' used before 'self.init' call or assignment to 'self'}}
self.y = xx // 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}}
}
extension GenericPoint where T == Double {
init(xx: Double, yy: Double) {
self.x = xx // expected-error {{'self' used before 'self.init' call or assignment to 'self'}}
self.y = yy // 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}}
init(xxx: Double, yyy: Double) {
// This is OK
self.init(x: xxx, y: yyy)
}
init(other: GenericPoint<Double>) {
// This is OK
self = other
}
init(other: GenericPoint<Double>, x: Double) {
// This is OK
self = other
self.x = x
}
init(other: GenericPoint<Double>, xx: Double) {
self.x = xx // expected-error {{'self' used before 'self.init' call or assignment to 'self'}}
self = other
}
init(other: GenericPoint<Double>, x: Double, cond: Bool) {
// This is OK
self = other
if cond { self.x = x }
}
init(other: GenericPoint<Double>, xx: Double, cond: Bool) {
if cond { self = other }
self.x = xx // expected-error {{'self' used before 'self.init' call or assignment to 'self'}}
self.y = 0 // 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}}
}
typealias MyGenericPoint<Q> = GenericPoint<Q>
extension MyGenericPoint {
init(myX: T, myY: T) {
self.x = myX // expected-error {{'self' used before 'self.init' call or assignment to 'self'}}
self.y = myY // 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}}
}
extension CPoint {
init(xx: Double, yy: Double) {
self.x = xx // expected-error {{'self' used before 'self.init' call or assignment to 'self'}} expected-note {{use "self.init()" to initialize the struct with zero values}} {{5-5=self.init()\n}}
self.y = yy // 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}}
init(xxx: Double, yyy: Double) {
// This is OK
self.init(x: xxx, y: yyy)
}
init(other: CPoint) {
// This is OK
self = other
}
init(other: CPoint, x: Double) {
// This is OK
self = other
self.x = x
}
init(other: CPoint, xx: Double) {
self.x = xx // expected-error {{'self' used before 'self.init' call or assignment to 'self'}} expected-note {{use "self.init()" to initialize the struct with zero values}} {{5-5=self.init()\n}}
self = other
}
init(other: CPoint, x: Double, cond: Bool) {
// This is OK
self = other
if cond { self.x = x }
}
init(other: CPoint, xx: Double, cond: Bool) {
if cond { self = other }
self.x = xx // expected-error {{'self' used before 'self.init' call or assignment to 'self'}}
self.y = 0 // 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}}
}
extension NonnullWrapper {
init(p: UnsafeMutableRawPointer) {
self.ptr = p // expected-error {{'self' used before 'self.init' call or assignment to 'self'}}
// No suggestion for "self.init()" because this struct does not support a
// zeroing initializer.
} // expected-error {{'self.init' isn't called on all paths before returning from initializer}}
}
extension PrivatePoint {
init(xxx: Double, yyy: Double) {
// This is OK
self.init(x: xxx, y: yyy)
}
init(other: PrivatePoint) {
// This is OK
self = other
}
init(other: PrivatePoint, cond: Bool) {
if cond { self = other }
} // expected-error {{'self.init' isn't called on all paths before returning from initializer}}
init() {
} // expected-error {{'self.init' isn't called on all paths before returning from initializer}}
}
extension Empty {
init(x: Double) {
// This is OK
self.init()
}
init(other: Empty) {
// This is okay
self = other
}
init(other: Empty, cond: Bool) {
if cond { self = other }
} // expected-error {{'self.init' isn't called on all paths before returning from initializer}}
init(xx: Double) {
} // expected-error {{'self.init' isn't called on all paths before returning from initializer}}
}
extension GenericEmpty {
init(x: Double) {
// This is OK
self.init()
}
init(other: GenericEmpty<T>) {
// This is okay
self = other
}
init(other: GenericEmpty<T>, cond: Bool) {
if cond { self = other }
} // expected-error {{'self.init' isn't called on all paths before returning from initializer}}
init(xx: Double) {
} // expected-error {{'self.init' isn't called on all paths before returning from initializer}}
}
class AcceptsVisibleNoArgsDesignatedInit: VisibleNoArgsDesignatedInit {
var y: Float
init(y: Float) {
self.y = y
// no error
}
}
open class InModuleVisibleNoArgsDesignatedInit {
var x: Float
public init() { x = 0.0 }
// Add a designated init the subclass cannot see.
private init(x: Float) { self.x = x }
}
class AcceptsInModuleVisibleNoArgsDesignatedInit: InModuleVisibleNoArgsDesignatedInit {
var y: Float
init(y: Float) {
self.y = y
// no error
}
}