mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
A protocol extension initializer creates a new instance of the static type of Self at the call site. However a convenience initializer in a class is expected to initialize an instance of the dynamic type of the 'self' value, because convenience initializers can be inherited by subclasses. This means that when a convenience initializer delegates to a protocol extension initializer, we have to substitute the 'Self' type in the protocol extension generic signature with the DynamicSelfType, and not the static type. Since the substitution is formed from the type of the 'self' parameter in the class convenience initializer, the solution is to change the type of 'self' in a class convenience initializer to DynamicSelfType, just like we do for methods that return 'Self'. This fixes cases where we allowed code to type check that should not type check (if the protocol extension initializer has 'Self' in contravariant position, and we pass in an instance of the static type). It also fixes a miscompile with valid code -- if the protocol extension initializer was implemented by calling 'Self()', it would again use the static type and not the dynamic type. Note that the SILGen change is necessary because Sema now creates CovariantReturnExprs that convert a static class type to DynamicSelfType, but the latter lowers to the former at the SIL level, so we have to peephole away unnecessary unchecked_ref_cast instructions in this case. Because this change breaks source compatibility, it is guarded by a '-swift-version 5' check.
391 lines
10 KiB
Swift
391 lines
10 KiB
Swift
// RUN: %target-typecheck-verify-swift -swift-version 5
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// DynamicSelf is only allowed on the return type of class and
|
|
// protocol methods.
|
|
func global() -> Self { } // expected-error{{global function cannot return 'Self'}}
|
|
|
|
func inFunction() {
|
|
func local() -> Self { } // expected-error{{local function cannot return 'Self'}}
|
|
}
|
|
|
|
struct S0 {
|
|
func f() -> Self { } // expected-error{{'Self' is only available in a protocol or as the result of a method in a class; did you mean 'S0'?}}{{15-19=S0}}
|
|
|
|
func g(_ ds: Self) { } // expected-error{{'Self' is only available in a protocol or as the result of a method in a class; did you mean 'S0'?}}{{16-20=S0}}
|
|
}
|
|
|
|
enum E0 {
|
|
func f() -> Self { } // expected-error{{'Self' is only available in a protocol or as the result of a method in a class; did you mean 'E0'?}}{{15-19=E0}}
|
|
|
|
func g(_ ds: Self) { } // expected-error{{'Self' is only available in a protocol or as the result of a method in a class; did you mean 'E0'?}}{{16-20=E0}}
|
|
}
|
|
|
|
class C0 {
|
|
func f() -> Self { } // okay
|
|
|
|
func g(_ ds: Self) { } // expected-error{{'Self' is only available in a protocol or as the result of a method in a class; did you mean 'C0'?}}{{16-20=C0}}
|
|
|
|
func h(_ ds: Self) -> Self { } // expected-error{{'Self' is only available in a protocol or as the result of a method in a class; did you mean 'C0'?}}{{16-20=C0}}
|
|
}
|
|
|
|
protocol P0 {
|
|
func f() -> Self // okay
|
|
|
|
func g(_ ds: Self) // okay
|
|
}
|
|
|
|
extension P0 {
|
|
func h() -> Self { // okay
|
|
func g(_ t : Self) -> Self { // okay
|
|
return t
|
|
}
|
|
return g(self)
|
|
}
|
|
}
|
|
|
|
protocol P1: class {
|
|
func f() -> Self // okay
|
|
|
|
func g(_ ds: Self) // okay
|
|
}
|
|
|
|
extension P1 {
|
|
func h() -> Self { // okay
|
|
func g(_ t : Self) -> Self { // okay
|
|
return t
|
|
}
|
|
return g(self)
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// The 'self' type of a Self method is based on Self
|
|
class C1 {
|
|
required init(int i: Int) {}
|
|
|
|
// Instance methods have a self of type Self.
|
|
func f(_ b: Bool) -> Self {
|
|
// FIXME: below diagnostic should complain about C1 -> Self conversion
|
|
if b { return C1(int: 5) } // expected-error{{cannot convert return expression of type 'C1' to return type 'Self'}}
|
|
|
|
// One can use `type(of:)` to attempt to construct an object of type Self.
|
|
if !b { return type(of: self).init(int: 5) }
|
|
|
|
// Can't utter Self within the body of a method.
|
|
var _: Self = self // expected-error{{'Self' is only available in a protocol or as the result of a method in a class; did you mean 'C1'?}} {{12-16=C1}}
|
|
|
|
// Okay to return 'self', because it has the appropriate type.
|
|
return self // okay
|
|
}
|
|
|
|
// Type methods have a self of type Self.Type.
|
|
class func factory(_ b: Bool) -> Self {
|
|
// Check directly.
|
|
var x: Int = self // expected-error{{cannot convert value of type 'Self.Type' to specified type 'Int'}}
|
|
|
|
// Can't utter Self within the body of a method.
|
|
var c1 = C1(int: 5) as Self // expected-error{{'Self' is only available in a protocol or as the result of a method in a class; did you mean 'C1'?}} {{28-32=C1}}
|
|
|
|
if b { return self.init(int: 5) }
|
|
|
|
return Self() // expected-error{{use of unresolved identifier 'Self'}} expected-note {{did you mean 'self'?}}
|
|
}
|
|
|
|
// This used to crash because metatype construction went down a
|
|
// different code path that didn't handle DynamicSelfType.
|
|
class func badFactory() -> Self {
|
|
return self(int: 0)
|
|
// expected-error@-1 {{initializing from a metatype value must reference 'init' explicitly}}
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Using a method with a Self result carries the receiver type.
|
|
class X {
|
|
func instance() -> Self {
|
|
}
|
|
|
|
class func factory() -> Self {
|
|
}
|
|
|
|
func produceX() -> X { }
|
|
}
|
|
|
|
class Y : X {
|
|
func produceY() -> Y { }
|
|
}
|
|
|
|
func testInvokeInstanceMethodSelf() {
|
|
// Trivial case: invoking on the declaring class.
|
|
var x = X()
|
|
var x2 = x.instance()
|
|
x = x2 // at least an X
|
|
x2 = x // no more than an X
|
|
|
|
// Invoking on a subclass.
|
|
var y = Y()
|
|
var y2 = y.instance();
|
|
y = y2 // at least a Y
|
|
y2 = y // no more than a Y
|
|
}
|
|
|
|
func testInvokeTypeMethodSelf() {
|
|
// Trivial case: invoking on the declaring class.
|
|
var x = X()
|
|
var x2 = X.factory()
|
|
x = x2 // at least an X
|
|
x2 = x // no more than an X
|
|
|
|
// Invoking on a subclass.
|
|
var y = Y()
|
|
var y2 = Y.factory()
|
|
y = y2 // at least a Y
|
|
y2 = y // no more than a Y
|
|
}
|
|
|
|
func testCurryInstanceMethodSelf() {
|
|
// Trivial case: currying on the declaring class.
|
|
var produceX = X.produceX
|
|
var produceX2 = X.instance
|
|
produceX = produceX2
|
|
produceX2 = produceX
|
|
|
|
// Currying on a subclass.
|
|
var produceY = Y.produceY
|
|
var produceY2 = Y.instance
|
|
produceY = produceY2
|
|
produceY2 = produceY
|
|
}
|
|
|
|
class GX<T> {
|
|
func instance() -> Self {
|
|
}
|
|
|
|
class func factory() -> Self {
|
|
}
|
|
|
|
func produceGX() -> GX { }
|
|
}
|
|
|
|
class GY<T> : GX<[T]> {
|
|
func produceGY() -> GY { }
|
|
}
|
|
|
|
func testInvokeInstanceMethodSelfGeneric() {
|
|
// Trivial case: invoking on the declaring class.
|
|
var x = GX<Int>()
|
|
var x2 = x.instance()
|
|
x = x2 // at least an GX<Int>
|
|
x2 = x // no more than an GX<Int>
|
|
|
|
// Invoking on a subclass.
|
|
var y = GY<Int>()
|
|
var y2 = y.instance();
|
|
y = y2 // at least a GY<Int>
|
|
y2 = y // no more than a GY<Int>
|
|
}
|
|
|
|
func testInvokeTypeMethodSelfGeneric() {
|
|
// Trivial case: invoking on the declaring class.
|
|
var x = GX<Int>()
|
|
var x2 = GX<Int>.factory()
|
|
x = x2 // at least an GX<Int>
|
|
x2 = x // no more than an GX<Int>
|
|
|
|
// Invoking on a subclass.
|
|
var y = GY<Int>()
|
|
var y2 = GY<Int>.factory();
|
|
y = y2 // at least a GY<Int>
|
|
y2 = y // no more than a GY<Int>
|
|
}
|
|
|
|
func testCurryInstanceMethodSelfGeneric() {
|
|
// Trivial case: currying on the declaring class.
|
|
var produceGX = GX<Int>.produceGX
|
|
var produceGX2 = GX<Int>.instance
|
|
produceGX = produceGX2
|
|
produceGX2 = produceGX
|
|
|
|
// Currying on a subclass.
|
|
var produceGY = GY<Int>.produceGY
|
|
var produceGY2 = GY<Int>.instance
|
|
produceGY = produceGY2
|
|
produceGY2 = produceGY
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Overriding a method with a Self
|
|
class Z : Y {
|
|
override func instance() -> Self {
|
|
}
|
|
|
|
override class func factory() -> Self {
|
|
}
|
|
}
|
|
|
|
func testOverriddenMethodSelfGeneric() {
|
|
var z = Z()
|
|
|
|
var z2 = z.instance();
|
|
z = z2
|
|
z2 = z
|
|
|
|
var z3 = Z.factory()
|
|
z = z3
|
|
z3 = z
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Generic uses of Self methods.
|
|
protocol P {
|
|
func f() -> Self
|
|
}
|
|
|
|
func testGenericCall<T: P>(_ t: T) {
|
|
var t = t
|
|
var t2 = t.f()
|
|
t2 = t
|
|
t = t2
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Existential uses of Self methods.
|
|
func testExistentialCall(_ p: P) {
|
|
_ = p.f()
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Dynamic lookup of Self methods.
|
|
@objc class SomeClass {
|
|
@objc func method() -> Self { return self }
|
|
}
|
|
|
|
func testAnyObject(_ ao: AnyObject) {
|
|
var ao = ao
|
|
var result : AnyObject = ao.method!()
|
|
result = ao
|
|
ao = result
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Name lookup on Self values
|
|
extension Y {
|
|
func testInstance() -> Self {
|
|
if false { return self.instance() }
|
|
return instance()
|
|
}
|
|
|
|
class func testFactory() -> Self {
|
|
if false { return self.factory() }
|
|
return factory()
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Optional Self returns
|
|
|
|
extension X {
|
|
func tryToClone() -> Self? { return nil }
|
|
func cloneOrFail() -> Self { return self }
|
|
func cloneAsObjectSlice() -> X? { return self }
|
|
}
|
|
extension Y {
|
|
func operationThatOnlyExistsOnY() {}
|
|
}
|
|
func testOptionalSelf(_ y : Y) {
|
|
if let clone = y.tryToClone() {
|
|
clone.operationThatOnlyExistsOnY()
|
|
}
|
|
|
|
// Sanity-checking to make sure that the above succeeding
|
|
// isn't coincidental.
|
|
if let clone = y.cloneOrFail() { // expected-error {{initializer for conditional binding must have Optional type, not 'Y'}}
|
|
clone.operationThatOnlyExistsOnY()
|
|
}
|
|
|
|
// Sanity-checking to make sure that the above succeeding
|
|
// isn't coincidental.
|
|
if let clone = y.cloneAsObjectSlice() {
|
|
clone.operationThatOnlyExistsOnY() // expected-error {{value of type 'X' has no member 'operationThatOnlyExistsOnY'}}
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Conformance lookup on Self
|
|
|
|
protocol Runcible {
|
|
}
|
|
|
|
extension Runcible {
|
|
func runce() {}
|
|
}
|
|
|
|
func wantsRuncible<T : Runcible>(_: T) {}
|
|
|
|
class Runce : Runcible {
|
|
func getRunced() -> Self {
|
|
runce()
|
|
wantsRuncible(self)
|
|
return self
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Forming a type with 'Self' in invariant position
|
|
|
|
struct Generic<T> { init(_: T) {} }
|
|
|
|
class InvariantSelf {
|
|
func me() -> Self {
|
|
let a = Generic(self)
|
|
let _: Generic<InvariantSelf> = a
|
|
// expected-error@-1 {{cannot convert value of type 'Generic<Self>' to specified type 'Generic<InvariantSelf>'}}
|
|
|
|
return self
|
|
}
|
|
}
|
|
|
|
// FIXME: This should be allowed
|
|
|
|
final class FinalInvariantSelf {
|
|
func me() -> Self {
|
|
let a = Generic(self)
|
|
let _: Generic<FinalInvariantSelf> = a
|
|
// expected-error@-1 {{cannot convert value of type 'Generic<Self>' to specified type 'Generic<FinalInvariantSelf>'}}
|
|
|
|
return self
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Semi-bogus factory init pattern
|
|
|
|
protocol FactoryPattern {
|
|
init(factory: @autoclosure () -> Self)
|
|
}
|
|
|
|
extension FactoryPattern {
|
|
init(factory: @autoclosure () -> Self) { self = factory() }
|
|
}
|
|
|
|
class Factory : FactoryPattern {
|
|
init(_string: String) {}
|
|
|
|
convenience init(string: String) {
|
|
self.init(factory: Factory(_string: string))
|
|
// expected-error@-1 {{incorrect argument label in call (have 'factory:', expected '_string:')}}
|
|
// FIXME: Bogus diagnostic
|
|
}
|
|
}
|
|
|
|
// Final classes are OK
|
|
|
|
final class FinalFactory : FactoryPattern {
|
|
init(_string: String) {}
|
|
|
|
convenience init(string: String) {
|
|
self.init(factory: FinalFactory(_string: string))
|
|
}
|
|
}
|