mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
It is necessary for opaque values where for casts that will newly start out as checked_cast_brs and be lowered to checked_cast_addr_brs, since the latter has the source formal type, IRGen relies on being able to access it, and there's no way in general to obtain the source formal type from the source lowered type.
210 lines
4.2 KiB
Swift
210 lines
4.2 KiB
Swift
// RUN: %target-swift-frontend -Xllvm -sil-inline-generics -emit-sorted-sil -emit-sil -enable-spec-devirt -O %s | %FileCheck %s
|
|
|
|
// We used to crash on this when trying to devirtualize t.boo(a, 1),
|
|
// because it is an "apply" with replacement types that contain
|
|
// archetypes, and the devirtualizer was not able to handle that
|
|
// case correctly.
|
|
//
|
|
// rdar://19912272
|
|
|
|
protocol P {
|
|
associatedtype Node
|
|
}
|
|
|
|
class C<T:P> {
|
|
typealias Node = T.Node
|
|
|
|
func foo(_ n:Node) {
|
|
}
|
|
|
|
func boo<S>(_ n:Node, s:S) {
|
|
}
|
|
}
|
|
|
|
func test1<T>(_ t:C<T>, a: T.Node) {
|
|
t.boo(a, s:1)
|
|
}
|
|
|
|
|
|
class Base<T> {
|
|
func foo() {
|
|
}
|
|
|
|
class func boo() {
|
|
}
|
|
}
|
|
|
|
class Derived<T> : Base<T> {
|
|
override func foo() {
|
|
}
|
|
|
|
override class func boo() {
|
|
}
|
|
}
|
|
|
|
// Check that testDevirt is specialized and uses speculative devirtualization.
|
|
// CHECK-LABEL: sil shared [noinline] @{{.*}}testDevirt
|
|
// CHECK: checked_cast_br [exact] CC<Int32> in %{{.*}} : $CC<Int32> to CC<Int32>
|
|
// CHECK: class_method
|
|
// CHECK: }
|
|
@inline(never)
|
|
public func testDevirt<T>(_ c: CC<T>) -> T? {
|
|
return c.next()
|
|
}
|
|
|
|
|
|
// Check that the instance method Derived<T>.foo can be devirtualized, because Derived.foo is an internal function,
|
|
// Derived has no subclasses and it is a WMO compilation.
|
|
// CHECK-LABEL: sil shared [noinline] @$s22devirt_unbound_generic5test2yyAA7DerivedCyxGlFTf4d_n
|
|
// CHECK-NOT: class_method
|
|
// CHECK-NOT: witness_method
|
|
// CHECK-NOT: apply
|
|
// CHECK: return
|
|
// CHECK: end sil function '$s22devirt_unbound_generic5test2yyAA7DerivedCyxGlFTf4d_n'
|
|
@inline(never)
|
|
func test2<T>(_ d: Derived<T>) {
|
|
d.foo()
|
|
}
|
|
|
|
public func doTest2<T>(_ t:T) {
|
|
test2(Derived<T>())
|
|
}
|
|
|
|
// Check that the class method Derived<T>.boo can be devirtualized, because Derived.boo is an internal function,
|
|
// Derived has no subclasses and it is a WMO compilation.
|
|
// CHECK: sil shared [noinline] @$s22devirt_unbound_generic5test3yyAA7DerivedCyxGlFTf4d_n
|
|
// CHECK-NOT: class_method
|
|
// CHECK-NOT: witness_method
|
|
// CHECK-NOT: apply
|
|
// CHECK: return
|
|
// CHECK: end sil function '$s22devirt_unbound_generic5test3yyAA7DerivedCyxGlFTf4d_n'
|
|
@inline(never)
|
|
func test3<T>(_ d: Derived<T>) {
|
|
type(of: d).boo()
|
|
}
|
|
|
|
public func doTest3<T>(_ t:T) {
|
|
test3(Derived<T>())
|
|
}
|
|
|
|
|
|
public protocol ProtocolWithAssocType {
|
|
associatedtype Element
|
|
}
|
|
|
|
private class CP<Base: ProtocolWithAssocType> {
|
|
var value: Base.Element
|
|
init(_ v: Base.Element) {
|
|
value = v
|
|
}
|
|
|
|
func getCount() -> Int32 {
|
|
return 1
|
|
}
|
|
}
|
|
|
|
private class Base1: ProtocolWithAssocType {
|
|
typealias Element = Int32
|
|
}
|
|
|
|
|
|
private class Base2<T>: ProtocolWithAssocType {
|
|
typealias Element = Int32
|
|
}
|
|
|
|
private class CP2: CP<Base2<Int>> {
|
|
init() {
|
|
super.init(1)
|
|
}
|
|
|
|
override func getCount() -> Int32 {
|
|
return 2
|
|
}
|
|
}
|
|
|
|
private class CP3: CP<Base2<Int>> {
|
|
init() {
|
|
super.init(1)
|
|
}
|
|
|
|
override func getCount() -> Int32 {
|
|
return 3
|
|
}
|
|
}
|
|
|
|
public class CC<CT> {
|
|
func next() -> CT? {
|
|
return nil
|
|
}
|
|
}
|
|
|
|
public protocol QQ {
|
|
associatedtype Base: PP
|
|
}
|
|
|
|
public protocol PP {
|
|
associatedtype Element
|
|
}
|
|
|
|
internal class D<DT: QQ> : CC<DT.Base.Element> {
|
|
override func next() -> DT.Base.Element? {
|
|
return nil
|
|
}
|
|
}
|
|
|
|
public struct S: PP {
|
|
public typealias Element = Int32
|
|
}
|
|
|
|
final public class E: QQ {
|
|
public typealias Base = S
|
|
}
|
|
|
|
// Check that c.next() inside test4 gets completely devirtualized.
|
|
// CHECK-LABEL: sil @{{.*}}test4{{.*}}
|
|
// CHECK-NOT: class_method
|
|
// CHECK: return
|
|
public func test4() -> Int32? {
|
|
let c: CC<Int32> = D<E>();
|
|
return c.next()
|
|
}
|
|
|
|
public func test5() -> Int32? {
|
|
return testDevirt(D<E>())
|
|
}
|
|
|
|
// The compiler used to crash on this code, because of
|
|
// generic types involved in the devirtualization.
|
|
//
|
|
// rdar://25891588
|
|
//
|
|
// CHECK-LABEL: sil private [noinline] {{.*}}@{{.*}}test6
|
|
// CHECK-NOT: class_method
|
|
// CHECK-NOT: checked_cast_br
|
|
// CHECK-NOT: class_method
|
|
// CHECK: }
|
|
@inline(never)
|
|
private func test6<T: ProtocolWithAssocType>(_ c: CP<T>) -> T.Element {
|
|
return c.value
|
|
}
|
|
|
|
public func doTest6() {
|
|
test6(CP<Base1>(1))
|
|
}
|
|
|
|
// CHECK-LABEL: sil private [noinline] @{{.*}}test7
|
|
// CHECK-NOT: class_method
|
|
// CHECK: checked_cast_br
|
|
// CHECK-NOT: class_method
|
|
// CHECK: }
|
|
@inline(never)
|
|
private func test7<T: ProtocolWithAssocType>(_ c: CP<T>) -> Int32 {
|
|
return c.getCount()
|
|
}
|
|
|
|
public func doTest7() {
|
|
test7(CP2())
|
|
}
|
|
|
|
|