mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
We had four duplicated implementations of checking how a protocol requirement uses 'Self', all slightly wrong or incomplete: - When deciding if the protocol type can be used as an existential. This one would just ignore 'Self' in the return type of a method completely, which was incorrect for cases where 'Self' is contravariant but part of the return value, for example: func foo() -> (Self -> ()) - When deciding if a member access can be performed on an existential value. This is distinct from the former, because the member may have been defined in a protocol extension, in which case it cannot be used even if the protocol type can be used as an existential. Unfortunately, this implementation was overly conservative, and would reject uses of 'Self' where Sema could in fact erase the existential type, for example: func foo() -> Self?? func foo() -> Self.Type func foo() -> (Self, Self) This function handled function return types correctly, effectively plugging the leak in the previous code. It did lead to inconsistent behavior with protocols that had contravariant Self in requirements though; sometimes we would diagnose uses of the existential type, other times we would only complain about specific members. - When deciding if a method in a non-final class can model a protocol requirement. This one was the most elaborate one, but here contravariance and uses of associated types are actually okay, so it was written to pick up covariant 'Self' only. However, it also did not handle metatypes and tuples. - When opening the type of member of an existential, we would check if the return value was 'Self' or an optional of 'Self', but again this check was too conservative, so after the previous three were fixed, we could reference members on existentials that did not have a correct opened type. Now, these have been combined into one check. To fix some crashes, Sema's implementation of erasing existentials now relies on coerceToType() instead of hand-rolling a few coercions of its own, and wrapping the rest in CovariantFunctionConversionExpr, which didn't make much sense if the result was not a function type. SILGen still does not support function type conversions where an existential return value is being erased; these would silently miscompile before, but crash with an assertion now, because they are correctly modeled as a FunctionConversionExpr, and not CovariantFunctionConversionExpr.
119 lines
3.5 KiB
Swift
119 lines
3.5 KiB
Swift
// RUN: %target-parse-verify-swift
|
|
|
|
protocol Fooable { func foo() }
|
|
protocol Barable { func bar() }
|
|
|
|
extension Int : Fooable, Barable {
|
|
func foo() {}
|
|
func bar() {}
|
|
}
|
|
|
|
extension Float32 : Barable {
|
|
func bar() {}
|
|
}
|
|
|
|
func f0(_: Barable) {}
|
|
func f1(x: protocol<Fooable, Barable>) {}
|
|
func f2(_: Float) {}
|
|
let nilFunc: Optional<(Barable) -> ()> = nil
|
|
|
|
func g(_: (protocol<Barable, Fooable>) -> ()) {}
|
|
|
|
protocol Classable : AnyObject {}
|
|
class SomeArbitraryClass {}
|
|
|
|
func fc0(_: Classable) {}
|
|
func fc1(_: protocol<Fooable, Classable>) {}
|
|
func fc2(_: AnyObject) {}
|
|
func fc3(_: SomeArbitraryClass) {}
|
|
func gc(_: (protocol<Classable, Fooable>) -> ()) {}
|
|
|
|
var i : Int
|
|
var f : Float
|
|
var b : Barable
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Conversion to and among existential types
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
f0(i)
|
|
f0(f)
|
|
f0(b)
|
|
f1(i)
|
|
|
|
f1(f) // expected-error{{argument type 'Float' does not conform to expected type 'protocol<Barable, Fooable>'}}
|
|
f1(b) // expected-error{{argument type 'Barable' does not conform to expected type 'protocol<Barable, Fooable>'}}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Subtyping
|
|
//===----------------------------------------------------------------------===//
|
|
g(f0) // okay (subtype)
|
|
g(f1) // okay (exact match)
|
|
|
|
g(f2) // expected-error{{cannot convert value of type '(Float) -> ()' to expected argument type '(protocol<Barable, Fooable>) -> ()'}}
|
|
|
|
// FIXME: Workaround for ?? not playing nice with function types.
|
|
infix operator ??* {}
|
|
func ??*<T>(lhs: T?, rhs: T) -> T { return lhs ?? rhs }
|
|
g(nilFunc ??* f0)
|
|
|
|
gc(fc0) // okay
|
|
gc(fc1) // okay
|
|
gc(fc2) // okay
|
|
gc(fc3) // expected-error{{cannot convert value of type '(SomeArbitraryClass) -> ()' to expected argument type '(protocol<Classable, Fooable>) -> ()'}}
|
|
|
|
// rdar://problem/19600325
|
|
func getAnyObject() -> AnyObject? {
|
|
return SomeArbitraryClass()
|
|
}
|
|
|
|
func castToClass(object: Any) -> SomeArbitraryClass? {
|
|
return object as? SomeArbitraryClass
|
|
}
|
|
|
|
_ = getAnyObject().map(castToClass)
|
|
|
|
|
|
_ = { (_: Any) -> Void in
|
|
return
|
|
} as ((Int) -> Void)
|
|
|
|
let _: (Int) -> Void = {
|
|
(_: Any) -> Void in
|
|
return
|
|
}
|
|
|
|
let _: () -> Any = {
|
|
() -> Int in
|
|
return 0
|
|
}
|
|
|
|
let _: () -> Int = {
|
|
() -> String in // expected-error {{declared closure result 'String' is incompatible with contextual type 'Int'}}
|
|
return ""
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Dynamic self
|
|
//===----------------------------------------------------------------------===//
|
|
protocol Clonable {
|
|
func maybeClone() -> Self?
|
|
func doubleMaybeClone() -> Self??
|
|
func subdivideClone() -> (Self, Self)
|
|
func metatypeOfClone() -> Self.Type
|
|
func badClonerFn() -> (Self -> Self)
|
|
func veryBadClonerFn() -> ((inout Self) -> ())
|
|
func goodClonerFn() -> (() -> Self)
|
|
}
|
|
|
|
func testClonable(v : Clonable) { // expected-error {{protocol 'Clonable' can only be used as a generic constraint because it has Self or associated type requirements}}
|
|
let v2 = v.maybeClone()
|
|
let v3 = v.doubleMaybeClone()
|
|
let v4 = v.subdivideClone()
|
|
let v5 = v.metatypeOfClone()
|
|
let v6 = v.goodClonerFn()
|
|
|
|
let v7 = v.badClonerFn() // expected-error {{member 'badClonerFn' cannot be used on value of protocol type 'Clonable'; use a generic constraint instead}}
|
|
let v8 = v.veryBadClonerFn() // expected-error {{member 'veryBadClonerFn' cannot be used on value of protocol type 'Clonable'; use a generic constraint instead}}
|
|
}
|