mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
This is in preparation for COW support. More optimizer tests require an optimized non-assert stdlib build.
171 lines
5.3 KiB
Swift
171 lines
5.3 KiB
Swift
// RUN: %target-swift-frontend -O -emit-sil -enforce-exclusivity=unchecked -Xllvm -sil-print-generic-specialization-loops -Xllvm -sil-print-generic-specialization-info %s 2>&1 | %FileCheck --check-prefix=CHECK %s
|
|
|
|
// REQUIRES: swift_stdlib_no_asserts,optimized_stdlib
|
|
|
|
// Check that the generic specializer does not hang a compiler by
|
|
// creating and infinite loop of generic specializations.
|
|
|
|
// This is a complete set of expected detected generic specialization loops:
|
|
// CHECK-DAG: generic specialization loop{{.*}}testFoo7
|
|
// CHECK-DAG: generic specialization loop{{.*}}testFoo6
|
|
// CHECK-DAG: generic specialization loop{{.*}}foo3
|
|
// CHECK-DAG: generic specialization loop{{.*}}foo4
|
|
// CHECK-DAG: generic specialization loop{{.*}}bar4
|
|
// CHECK-DAG: generic specialization loop{{.*}}Something{{.*}}compoundValue
|
|
|
|
// CHECK-LABEL: sil_stage canonical
|
|
|
|
// Check that a specialization information for a specialized function was produced.
|
|
// CHECK-LABEL: // Generic specialization information for function $s044generic_specialization_loops_detection_with_C04foo4yyx_q_tr0_lFSi_SdTg5
|
|
// CHECK-NEXT: // Caller: $s044generic_specialization_loops_detection_with_C011testFooBar4yyF
|
|
// CHECK-NEXT: // Parent: $s044generic_specialization_loops_detection_with_C04foo4yyx_q_tr0_lF
|
|
// CHECK-NEXT: // Substitutions: <Int, Double>
|
|
|
|
// Check that the compiler has produced a specialization information for a call-site that
|
|
// was inlined from a specialized generic function.
|
|
// CHECK-LABEL: // Generic specialization information for call-site $s044generic_specialization_loops_detection_with_C04foo4yyx_q_tr0_lFSaySays5UInt8VGG_SaySaySiGGTg5:
|
|
// CHECK-NEXT: // Caller: $s044generic_specialization_loops_detection_with_C04foo4yyx_q_tr0_lFSi_SdTg5
|
|
// CHECK-NEXT: // Parent: $s044generic_specialization_loops_detection_with_C04bar4yyx_q_tr0_lF
|
|
// CHECK-NEXT: // Substitutions: <Array<UInt8>, Array<Int>>
|
|
// CHECK-NEXT: //
|
|
// CHECK-NEXT: // Caller: $s044generic_specialization_loops_detection_with_C011testFooBar4yyF
|
|
// CHECK-NEXT: // Parent: $s044generic_specialization_loops_detection_with_C04foo4yyx_q_tr0_lF
|
|
// CHECK-NEXT: // Substitutions: <Int, Double>
|
|
// CHECK-NEXT: //
|
|
// CHECK-NEXT: apply %{{.*}}Array<Array<UInt8>>
|
|
|
|
// Check specializations of mutually recursive functions which
|
|
// may result in an infinite specialization loop.
|
|
public struct MyStruct<A, B> {
|
|
}
|
|
|
|
func foo3<T, S>(_ t: T, _ s: S) {
|
|
bar3(s, t)
|
|
}
|
|
|
|
func bar3<T, S>(_ t: T, _ s: S) {
|
|
foo3(t, MyStruct<T, S>())
|
|
}
|
|
|
|
public func testFooBar3() {
|
|
foo3(1, 2.0)
|
|
}
|
|
|
|
// Check specializations of mutually recursive functions which
|
|
// may result in an infinite specialization loop.
|
|
public var g = 0
|
|
func foo4<T, S>(_ t: T, _ s: S) {
|
|
// Here we have multiple call-sites of the same generic
|
|
// functions inside the same caller.
|
|
// Some of these call-sites use different generic type parameters.
|
|
bar4([UInt8(1)], [t])
|
|
if g > 0 {
|
|
bar4(t, t)
|
|
} else {
|
|
bar4(t, s)
|
|
}
|
|
}
|
|
|
|
func bar4<T, S>(_ t: T, _ s: S) {
|
|
foo4([t], [s])
|
|
}
|
|
|
|
public func testFooBar4() {
|
|
foo4(1, 2.0)
|
|
}
|
|
|
|
// This is an example of a deeply nested generics which
|
|
// may result in an infinite specialization loop.
|
|
class Something<T> {
|
|
var somethingArray: Something<Array<T>>? = nil
|
|
var somethingOptional: Something<Optional<T>>? = nil
|
|
var value: T? = nil
|
|
|
|
init() {
|
|
}
|
|
|
|
init(plainValue: T) {
|
|
value = plainValue
|
|
}
|
|
|
|
init(compoundValue: T) {
|
|
value = compoundValue
|
|
somethingArray = Something<Array<T>>(compoundValue: [compoundValue])
|
|
somethingOptional = Something<Optional<T>>(plainValue: compoundValue as T?)
|
|
}
|
|
|
|
func map<U>(_ f: (T) -> (U)) -> Something<U> {
|
|
let somethingArrayU = somethingArray?.map { $0.map { f($0) } }
|
|
let somethingOptionalU = somethingOptional?.map { $0.map { f($0) } }
|
|
let valueU = value.map { f($0) }
|
|
let s = Something<U>()
|
|
s.value = valueU
|
|
s.somethingArray = somethingArrayU
|
|
s.somethingOptional = somethingOptionalU
|
|
return s
|
|
}
|
|
}
|
|
|
|
print(Something<Int8>(compoundValue: 0))
|
|
print(Something<Int8>(compoundValue: 0).map { Double($0) })
|
|
|
|
// Test more complex cases, where types of substitutions are partially
|
|
// contained in each other.
|
|
protocol P {
|
|
associatedtype X: P
|
|
}
|
|
|
|
struct Start {}
|
|
struct Step<Param> {}
|
|
|
|
struct Outer<Param>: P {
|
|
typealias X = Outer<Step<Param>>
|
|
}
|
|
|
|
func testFoo6<T: P>(_: T.Type) {
|
|
testFoo6(T.X.self)
|
|
}
|
|
|
|
func testFoo7<T: P>(_: T.Type) {
|
|
testFoo7(T.X.self)
|
|
}
|
|
|
|
struct Outer1<Param>: P {
|
|
typealias X = Outer2<Param>
|
|
}
|
|
|
|
struct Outer2<Param>: P {
|
|
typealias X = Outer3<Param>
|
|
}
|
|
|
|
struct Outer3<Param>: P {
|
|
typealias X = Outer4<Param>
|
|
}
|
|
|
|
struct Outer4<Param>: P {
|
|
typealias X = Outer5<Param>
|
|
}
|
|
|
|
struct Outer5<Param>: P {
|
|
typealias X = Outer1<Step<Param>>
|
|
}
|
|
|
|
// T will look like:
|
|
// Outer<Start>
|
|
// Outer<Step<Start>>
|
|
// Outer<Step<Step<Start>>>
|
|
// ...
|
|
// As it can be seen, the substitution type is growing, but a type
|
|
// on each specialization iteration would not completely contain a type from
|
|
// the previous iteration. Instead, it partially contains it. That is,
|
|
// if all common structural prefixes are dropped, then it looks like:
|
|
// Start
|
|
// Step<Start>
|
|
// Step<Step<Start>>
|
|
// ...
|
|
// And it can be easily seen that the type used by the new iteration contains
|
|
// a type from the previous one.
|
|
testFoo6(Outer<Start>.self)
|
|
// Check a more complex, but similar idea.
|
|
testFoo7(Outer1<Start>.self)
|