| // RUN: %target-swift-frontend -emit-sil -O %s | %FileCheck %s |
| |
| // Check that devirtualizer can properly handle concrete non-generic subclasses |
| // of generic classes. |
| // It should not crash on them. |
| |
| public class Base<T> { |
| func foo() -> Int32 { |
| return 1 |
| } |
| |
| func boo() -> Int32 { |
| return 11 |
| } |
| } |
| |
| public class Derived: Base<Int> { |
| override func foo() -> Int32 { |
| return 2 |
| } |
| } |
| |
| // CHECK-LABEL: sil [noinline] @_T041devirt_concrete_subclass_of_generic_class5test1s5Int32VyF |
| @inline(never) |
| public func test1() -> Int32 { |
| let o = Derived() |
| return o.foo() + o.boo() |
| } |
| |
| @inline(never) |
| public func test2(_ o: Derived) -> Int32 { |
| return o.foo() + o.boo() |
| } |
| |
| |
| @inline(never) |
| public func test3() -> Int32 { |
| let o: Base<Int> = Derived() |
| return o.foo() + o.boo() |
| } |
| |
| @inline(never) |
| public func test4(_ o: Base<Int>) -> Int32 { |
| return o.foo() + o.boo() |
| } |
| |
| @inline(never) |
| public func test5<T>(_ o: Base<T>) -> Int32 { |
| return o.foo() + o.boo() |
| } |
| |
| print(test1()) |
| print(test2(Derived())) |
| |
| print(test3()) |
| print(test4(Derived())) |
| |
| print(test5(Derived())) |
| |
| // Check that we handle indirect devirtualization through an intermediate |
| // method. rdar://problem/24993618 |
| |
| private class IndirectMethodCall<T> { |
| func bug() { |
| overrideMe() |
| } |
| |
| @inline(never) |
| func overrideMe() { } |
| } |
| |
| private class IndirectChildConcrete: IndirectMethodCall<Int> { |
| @inline(never) |
| override func overrideMe() { } |
| } |
| |
| private class IndirectChildTuple<U>: IndirectMethodCall<(U, U)> { |
| @inline(never) |
| override func overrideMe() { } |
| } |
| |
| private class IndirectChildTupleConcrete: IndirectChildTuple<Int> { |
| @inline(never) |
| override func overrideMe() { } |
| } |
| |
| private class IndirectChildMeta<U>: IndirectMethodCall<U.Type> { |
| @inline(never) |
| override func overrideMe() { } |
| } |
| private class IndirectChildMetaConcrete: IndirectChildMeta<Int> { |
| @inline(never) |
| override func overrideMe() { } |
| } |
| |
| private class IndirectChildBoundGeneric<U>: IndirectMethodCall<Array<U>> { |
| @inline(never) |
| override func overrideMe() { } |
| } |
| |
| private class IndirectChildBoundGenericConcrete: |
| IndirectChildBoundGeneric<Int> { |
| @inline(never) |
| override func overrideMe() { } |
| } |
| |
| private class IndirectChildFunction<U>: IndirectMethodCall<(U) -> U> { |
| @inline(never) |
| override func overrideMe() { } |
| } |
| private class IndirectChildFunctionConcrete: IndirectChildFunction<Int> { |
| @inline(never) |
| override func overrideMe() { } |
| } |
| |
| // CHECK-LABEL: sil {{.*}} @{{.*}}test6 |
| @inline(never) |
| func test6() { |
| // CHECK: function_ref @{{.*}}IndirectChildConcrete{{.*}}overrideMe |
| IndirectChildConcrete().bug() |
| // CHECK: function_ref @{{.*}}IndirectChildTuple{{.*}}overrideMe |
| IndirectChildTuple<Int>().bug() |
| // CHECK: function_ref @{{.*}}IndirectChildTupleConcrete{{.*}}overrideMe |
| IndirectChildTupleConcrete().bug() |
| // CHECK: function_ref @{{.*}}IndirectChildMeta{{.*}}overrideMe |
| IndirectChildMeta<Int>().bug() |
| // CHECK: function_ref @{{.*}}IndirectChildMetaConcrete{{.*}}overrideMe |
| IndirectChildMetaConcrete().bug() |
| // CHECK: function_ref @{{.*}}IndirectChildBoundGeneric{{.*}}overrideMe |
| IndirectChildBoundGeneric<Int>().bug() |
| // CHECK: function_ref @{{.*}}IndirectChildBoundGenericConcrete{{.*}}overrideMe |
| IndirectChildBoundGenericConcrete().bug() |
| // CHECK: function_ref @{{.*}}IndirectChildFunction{{.*}}overrideMe |
| IndirectChildFunction<Int>().bug() |
| // CHECK: function_ref @{{.*}}IndirectChildFunctionConcrete{{.*}}overrideMe |
| IndirectChildFunctionConcrete().bug() |
| } |
| |
| print(test6()) |