| // REQUIRES: no_asan |
| // RUN: %empty-directory(%t) |
| // RUN: %target-build-swift %s -emit-module -emit-library -module-name capture_descriptors -o %t/capture_descriptors.%target-dylib-extension |
| // RUN: %target-swift-reflection-dump -binary-filename %t/capture_descriptors.%target-dylib-extension | %FileCheck %s |
| |
| sil_stage canonical |
| |
| import Builtin |
| import Swift |
| import SwiftShims |
| |
| // CHECK: CAPTURE DESCRIPTORS: |
| // CHECK-NEXT: ==================== |
| |
| // Concrete caller and callee -- nothing interesting going on |
| |
| protocol P {} |
| |
| sil @concrete_callee1 : $@convention(thin) (Int, @owned <τ_0_0> { var τ_0_0 } <Int>, @thin Int.Type, @thick P.Type) -> () { |
| bb0(%i: $Int, %b: $<τ_0_0> { var τ_0_0 } <Int>, %m: $@thin Int.Type, %p: $@thick P.Type): |
| %12 = tuple () |
| return %12 : $() |
| } |
| |
| sil @concrete_caller1 : $@convention(thin) (Int, @thick P.Type) -> @owned @callee_owned () -> () { |
| bb0(%i: $Int, %p: $@thick P.Type): |
| %f = function_ref @concrete_callee1 : $@convention(thin) (Int, @owned <τ_0_0> { var τ_0_0 } <Int>, @thin Int.Type, @thick P.Type) -> () |
| %b = alloc_box $<τ_0_0> { var τ_0_0 } <Int> |
| %m = metatype $@thin Int.Type |
| %c = partial_apply %f(%i, %b, %m, %p) : $@convention(thin) (Int, @owned <τ_0_0> { var τ_0_0 } <Int>, @thin Int.Type, @thick P.Type) -> () |
| return %c : $@callee_owned () -> () |
| } |
| |
| // This is the descriptor for '<τ_0_0> { var τ_0_0 } <Int>' above |
| |
| // CHECK: - Capture types: |
| // CHECK-NEXT: (struct Swift.Int) |
| // CHECK-NEXT: - Metadata sources: |
| |
| // CHECK: - Capture types: |
| // CHECK-NEXT: (struct Swift.Int) |
| // CHECK-NEXT: (sil_box |
| // CHECK-NEXT: (struct Swift.Int)) |
| // CHECK-NEXT: (existential_metatype |
| // CHECK-NEXT: (protocol capture_descriptors.P)) |
| // CHECK-NEXT: - Metadata sources: |
| |
| |
| // Concrete caller and generic callee -- capture types are fully substituted, |
| // and there are no metadata bindings |
| |
| sil @generic_callee2 : $@convention(thin) <T, U> (@in T, @owned <τ_0_0> { var τ_0_0 } <U>) -> () { |
| bb0(%i: $*T, %b: $<τ_0_0> { var τ_0_0 } <U>): |
| %12 = tuple () |
| return %12 : $() |
| } |
| |
| sil @concrete_caller2 : $@convention(thin) () -> @owned @callee_owned () -> () { |
| bb0: |
| %f = function_ref @generic_callee2 : $@convention(thin) <T, U> (@in T, @owned <τ_0_0> { var τ_0_0 } <U>) -> () |
| %i = alloc_stack $Int |
| %b = alloc_box $<τ_0_0> { var τ_0_0 } <String> |
| %c = partial_apply %f<Int, String>(%i, %b) : $@convention(thin) <T, U> (@in T, @owned <τ_0_0> { var τ_0_0 } <U>) -> () |
| dealloc_stack %i : $*Int |
| return %c : $@callee_owned () -> () |
| } |
| |
| // This is the descriptor for '<τ_0_0> { var τ_0_0 } <String>' above |
| |
| // CHECK: - Capture types: |
| // CHECK-NEXT: (struct Swift.String) |
| // CHECK-NEXT: - Metadata sources: |
| |
| // CHECK: - Capture types: |
| // CHECK-NEXT: (struct Swift.Int) |
| // CHECK-NEXT: (sil_box |
| // CHECK-NEXT: (struct Swift.String)) |
| // CHECK-NEXT: - Metadata sources: |
| |
| |
| // Generic caller and generic callee -- capture types are written in terms of |
| // the caller's generic parameters, and metadata bindings are present for |
| // structural sub-terms of the callee's substituted generic parameters that |
| // contain the caller's generic parameters. |
| |
| sil @generic_callee3 : $@convention(thin) <T, U> (@in T) -> () { |
| bb0(%t: $*T): |
| %12 = tuple () |
| return %12 : $() |
| } |
| |
| sil @generic_caller3 : $@convention(thin) <A, B, C> () -> @owned @callee_owned () -> () { |
| bb0: |
| %f = function_ref @generic_callee3 : $@convention(thin) <T, U> (@in T) -> () |
| %t = alloc_stack $Optional<@callee_owned (@in A) -> @out B> |
| %c = partial_apply %f<Optional<(A) -> B>, (B, (C) -> Int)>(%t) : $@convention(thin) <T, U> (@in T) -> () |
| dealloc_stack %t : $*Optional<@callee_owned (@in A) -> @out B> |
| return %c : $@callee_owned () -> () |
| } |
| |
| // CHECK: - Capture types: |
| // CHECK-NEXT: (bound_generic_enum Swift.Optional |
| // CHECK-NEXT: (function |
| // CHECK-NEXT: (tuple))) |
| // CHECK-NEXT: - Metadata sources: |
| // CHECK-NEXT: (bound_generic_enum Swift.Optional |
| // CHECK-NEXT: (function |
| // CHECK-NEXT: (generic_type_parameter depth=0 index=0) |
| // CHECK-NEXT: (generic_type_parameter depth=0 index=1))) |
| // CHECK-NEXT: (closure_binding index=0) |
| // CHECK-NEXT: (generic_type_parameter depth=0 index=1) |
| // CHECK-NEXT: (closure_binding index=1) |
| // CHECK-NEXT: (generic_type_parameter depth=0 index=2) |
| // CHECK-NEXT: (closure_binding index=2) |
| |
| |
| // Generic caller and generic callee -- and one of the type parameters is |
| // fulfilled by a thick metatype value. |
| |
| sil @generic_callee4 : $@convention(thin) <T, U> (@thick Optional<T>.Type) -> () { |
| bb0(%t: $@thick Optional<T>.Type): |
| %12 = tuple () |
| return %12 : $() |
| } |
| |
| sil @generic_caller4 : $@convention(thin) <A, B, C> () -> @owned @callee_owned () -> () { |
| bb0: |
| %f = function_ref @generic_callee4 : $@convention(thin) <T, U> (@thick Optional<T>.Type) -> () |
| %t = metatype $@thick Optional<(B) -> C>.Type |
| %c = partial_apply %f<(B) -> C, Int>(%t) : $@convention(thin) <T, U> (@thick Optional<T>.Type) -> () |
| return %c : $@callee_owned () -> () |
| } |
| |
| // CHECK: - Capture types: |
| // CHECK-NEXT: (metatype was_abstract |
| // CHECK-NEXT: (bound_generic_enum Swift.Optional |
| // CHECK-NEXT: (function |
| // CHECK-NEXT: (generic_type_parameter depth=0 index=1) |
| // CHECK-NEXT: (generic_type_parameter depth=0 index=2)))) |
| // CHECK-NEXT: - Metadata sources: |
| // CHECK-NEXT: (function |
| // CHECK-NEXT: (generic_type_parameter depth=0 index=1) |
| // CHECK-NEXT: (generic_type_parameter depth=0 index=2)) |
| // CHECK-NEXT: (generic_argument index=0 |
| // CHECK-NEXT: (metadata_capture index=0)) |
| |
| |
| // Generic caller and generic callee -- and one of the type parameters is |
| // fulfilled by the isa pointer of a class instance. |
| |
| class GenericClass<T, U> {} |
| |
| sil @generic_callee5 : $@convention(thin) <T, U, V> (@owned GenericClass<T, U>) -> () { |
| bb0(%t: $GenericClass<T, U>): |
| %12 = tuple () |
| return %12 : $() |
| } |
| |
| sil @generic_caller5 : $@convention(thin) <A, B, C> (@owned GenericClass<(A, B), (B, C)>) -> @owned @callee_owned () -> () { |
| bb0(%g: $GenericClass<(A, B), (B, C)>): |
| %f = function_ref @generic_callee5 : $@convention(thin) <T, U, V> (@owned GenericClass<T, U>) -> () |
| %c = partial_apply %f<(A, B), (B, C), (C, A)>(%g) : $@convention(thin) <T, U, V> (@owned GenericClass<T, U>) -> () |
| return %c : $@callee_owned () -> () |
| } |
| |
| sil_vtable GenericClass {} |
| |
| // CHECK: - Capture types: |
| // CHECK-NEXT: (bound_generic_class capture_descriptors.GenericClass |
| // CHECK-NEXT: (tuple |
| // CHECK-NEXT: (generic_type_parameter depth=0 index=0) |
| // CHECK-NEXT: (generic_type_parameter depth=0 index=1)) |
| // CHECK-NEXT: (tuple |
| // CHECK-NEXT: (generic_type_parameter depth=0 index=1) |
| // CHECK-NEXT: (generic_type_parameter depth=0 index=2))) |
| // CHECK-NEXT: - Metadata sources: |
| // CHECK-NEXT: (generic_type_parameter depth=0 index=2) |
| // CHECK-NEXT: (closure_binding index=0) |
| // CHECK-NEXT: (generic_type_parameter depth=0 index=0) |
| // CHECK-NEXT: (closure_binding index=1) |
| // CHECK-NEXT: (tuple |
| // CHECK-NEXT: (generic_type_parameter depth=0 index=0) |
| // CHECK-NEXT: (generic_type_parameter depth=0 index=1)) |
| // CHECK-NEXT: (generic_argument index=0 |
| // CHECK-NEXT: (reference_capture index=0)) |
| // CHECK-NEXT: (tuple |
| // CHECK-NEXT: (generic_type_parameter depth=0 index=1) |
| // CHECK-NEXT: (generic_type_parameter depth=0 index=2)) |
| // CHECK-NEXT: (generic_argument index=1 |
| // CHECK-NEXT: (reference_capture index=0)) |
| |
| |
| // Pseudogeneric caller and pseudogeneric callee -- type parameters are |
| // erased at runtime. |
| |
| sil @pseudogeneric_callee : $@convention(thin) @pseudogeneric <T : AnyObject, U : AnyObject> (@owned T, @owned U) -> () { |
| bb0(%t: $T, %u: $U): |
| %12 = tuple () |
| return %12 : $() |
| } |
| |
| sil @pseudogeneric_caller : $@convention(thin) @pseudogeneric <A : AnyObject, B : AnyObject, C : AnyObject> (@owned A, @owned B) -> @owned @pseudogeneric @callee_owned () -> () { |
| bb0(%a: $A, %b: $B): |
| %f = function_ref @pseudogeneric_callee : $@convention(thin) @pseudogeneric <T : AnyObject, U : AnyObject> (@owned T, @owned U) -> () |
| %c = partial_apply %f<A, B>(%a, %b) : $@convention(thin) @pseudogeneric <A : AnyObject, B : AnyObject> (@owned A, @owned B) -> () |
| return %c : $@pseudogeneric @callee_owned () -> () |
| } |
| |
| // CHECK: - Capture types: |
| // CHECK-NEXT: (protocol_composition any_object) |
| // CHECK-NEXT: (protocol_composition any_object) |
| // CHECK-NEXT: - Metadata sources: |
| |
| |
| // Capturing lowered function types |
| |
| sil @function_callee : $@convention(thin) (@convention(thin) () -> (), @convention(c) () -> (), @convention(block) () -> (), @convention(thick) () -> (), @convention(method) () -> (), @convention(witness_method) () -> ()) -> () { |
| bb0(%thin: $@convention(thin) () -> (), %c: $@convention(c) () -> (), %block: $@convention(block) () -> (), %thick: $@convention(thick) () -> (), %method: $@convention(method) () -> (), %witness_method: $@convention(witness_method) () -> ()): |
| %12 = tuple () |
| return %12 : $() |
| } |
| |
| sil @function_caller : $@convention(thin) (@convention(thin) () -> (), @convention(c) () -> (), @convention(block) () -> (), @convention(thick) () -> (), @convention(method) () -> (), @convention(witness_method) () -> ()) -> @owned @callee_owned () -> () { |
| bb0(%thin: $@convention(thin) () -> (), %c: $@convention(c) () -> (), %block: $@convention(block) () -> (), %thick: $@convention(thick) () -> (), %method: $@convention(method) () -> (), %witness_method: $@convention(witness_method) () -> ()): |
| %f = function_ref @function_callee : $@convention(thin) (@convention(thin) () -> (), @convention(c) () -> (), @convention(block) () -> (), @convention(thick) () -> (), @convention(method) () -> (), @convention(witness_method) () -> ()) -> () |
| %result = partial_apply %f(%thin, %c, %block, %thick, %method, %witness_method) : $@convention(thin) (@convention(thin) () -> (), @convention(c) () -> (), @convention(block) () -> (), @convention(thick) () -> (), @convention(method) () -> (), @convention(witness_method) () -> ()) -> () |
| return %result : $@callee_owned () -> () |
| } |
| |
| // CHECK: - Capture types: |
| // CHECK-NEXT: (function convention=thin |
| // CHECK-NEXT: (tuple)) |
| // CHECK-NEXT: (function convention=c |
| // CHECK-NEXT: (tuple)) |
| // CHECK-NEXT: (function convention=block |
| // CHECK-NEXT: (tuple)) |
| // CHECK-NEXT: (function |
| // CHECK-NEXT: (tuple)) |
| // CHECK-NEXT: (function convention=thin |
| // CHECK-NEXT: (tuple)) |
| // CHECK-NEXT: (function convention=thin |
| // CHECK-NEXT: (tuple)) |
| // CHECK-NEXT: - Metadata sources: |
| |
| // Capturing opened existentials |
| // |
| // Not supported yet -- make sure we bail out instead of crashing. |
| // |
| // FIXME: Eventually, we should emit a useful capture descriptor |
| // for this case. |
| |
| sil @existential_callee : $@convention(thin) <τ_0_0 where τ_0_0 : P> () -> @out P { |
| bb0(%0 : $*P): |
| unreachable |
| } |
| |
| |
| sil @existential_caller : $@convention(thin) (@in P) -> () { |
| bb0(%0 : $*P): |
| %payload = open_existential_addr immutable_access %0 : $*P to $*@opened("2D7A8F84-2973-11E7-838D-34363BD08DA0") P |
| %f = function_ref @existential_callee : $@convention(thin) <τ_0_0 where τ_0_0 : P> () -> @out P |
| %result = partial_apply %f<@opened("2D7A8F84-2973-11E7-838D-34363BD08DA0") P>() : $@convention(thin) <τ_0_0 where τ_0_0 : P> () -> @out P |
| destroy_value %result : $@callee_owned () -> @out P |
| destroy_addr %0 : $*P |
| %tuple = tuple () |
| return %tuple : $() |
| } |