Created
December 11, 2017 18:04
-
-
Save Westacular/621612b07c425dcd4d2e95c6346a85db to your computer and use it in GitHub Desktop.
Testing the covariance/contravariance behaviours of casting function types, both directly and in a generic context. There are several inconsistencies.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
protocol Foo { } | |
protocol Bar { } | |
protocol Baz { } | |
struct FooStruct: Foo, Bar {} | |
/// Test covariance of return type | |
let block: () -> FooStruct = { FooStruct() } | |
block is () -> FooStruct // true | |
block is () -> Foo // false, but expected true | |
block is () -> Bar // false, but expected true | |
block is () -> Baz // false | |
block as? () -> FooStruct // non-nil | |
block as? () -> Foo // non-nil | |
block as? () -> Bar // non-nil | |
block as? () -> Baz // nil | |
func testIs<T,U>(_ returnType: U.Type, _ block: @escaping ()->T) -> Bool { | |
return block is () -> U | |
} | |
testIs(FooStruct.self, block) // true | |
testIs(Foo.self, block) // false, but expected true | |
testIs(Bar.self, block) // false, but expected true | |
testIs(Baz.self, block) // false | |
func testAs<T,U>(_ returnType: U.Type, _ block: @escaping ()->T) -> ( () -> U )? { | |
return block as? () -> U | |
} | |
testAs(FooStruct.self, block) // non-nil | |
testAs(Foo.self, block) // nil, but expected non-nil | |
testAs(Bar.self, block) // nil, but expected non-nil | |
testAs(Baz.self, block) // nil | |
func testRun<T,U>(_ returnType: U.Type, _ block: @escaping ()->T) -> Bool { | |
return block() is U | |
} | |
testRun(FooStruct.self, block) // true | |
testRun(Foo.self, block) // true | |
testRun(Bar.self, block) // true | |
testRun(Baz.self, block) // false | |
/// Test contravariance of parameter types | |
let block2: (Foo) -> () = { _ in return } | |
block2 is (Foo) -> () // true | |
block2 is (FooStruct) -> () // false, but expected true | |
block2 as? (Foo) -> () // non-nil | |
block2 as? (FooStruct) -> () // non-nil | |
func testIs2<T,U>(_ paramType: U.Type, _ block: @escaping (T)->()) -> Bool { | |
return block is (U) -> () | |
} | |
testIs2(Foo.self, block2) // true | |
testIs2(FooStruct.self, block2) // false, but expected true | |
func testAs2<T,U>(_ paramType: U.Type, _ block: @escaping (T)->()) -> ( (U) -> () )? { | |
return block as? (U) -> () | |
} | |
testAs2(Foo.self, block2) // non-nil | |
testAs2(FooStruct.self, block2) // nil, but expected non-nil |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment