// REQUIRES: no_asan // https://github.com/apple/swift/issues/55339 // XFAIL: OS=openbsd // UNSUPPORTED: OS=linux-android, OS=linux-androideabi // RUN: %empty-directory(%t) // RUN: %target-build-swift %s -emit-module -emit-library -module-name capture_descriptors -o %t/capture_descriptors%{target-shared-library-suffix} -L%t/../../.. -lBlocksRuntime // RUN: %target-swift-reflection-dump %t/capture_descriptors%{target-shared-library-suffix} | %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 {} extension Int: P {} sil [ossa] @concrete_callee1 : $@convention(thin) (Int, @owned <τ_0_0> { var τ_0_0 } , @thin Int.Type, @thick P.Type) -> () { bb0(%i : $Int, %b : @owned $<τ_0_0> { var τ_0_0 } , %m : $@thin Int.Type, %p : $@thick P.Type): %12 = tuple () destroy_value %b : $<τ_0_0> { var τ_0_0 } return %12 : $() } sil [ossa] @concrete_caller1 : $@convention(thin) (Int, @thick P.Type) -> @owned @callee_guaranteed () -> () { bb0(%i : $Int, %p : $@thick P.Type): %f = function_ref @concrete_callee1 : $@convention(thin) (Int, @owned <τ_0_0> { var τ_0_0 } , @thin Int.Type, @thick P.Type) -> () %b = alloc_box $<τ_0_0> { var τ_0_0 } %m = metatype $@thin Int.Type %c = partial_apply [callee_guaranteed] %f(%i, %b, %m, %p) : $@convention(thin) (Int, @owned <τ_0_0> { var τ_0_0 } , @thin Int.Type, @thick P.Type) -> () return %c : $@callee_guaranteed () -> () } // This is the descriptor for '<τ_0_0> { var τ_0_0 } ' 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_with_layout // CHECK-NEXT: (layout // CHECK-NEXT: (var // CHECK-NEXT: (generic_type_parameter depth=0 index=0))) // CHECK-NEXT: (generic_signature // CHECK-NEXT: (substitution // CHECK-NEXT: (generic_type_parameter depth=0 index=0) // CHECK-NEXT: (struct Swift.Int)))) // CHECK-NEXT: (existential_metatype // CHECK-NEXT: (protocol_composition // 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 [ossa] @generic_callee2 : $@convention(thin) (@in T, @owned <τ_0_0> { var τ_0_0 } ) -> () { bb0(%i : $*T, %b : @owned $<τ_0_0> { var τ_0_0 } ): %12 = tuple () destroy_value %b : $<τ_0_0> { var τ_0_0 } destroy_addr %i : $*T return %12 : $() } sil [ossa] @concrete_caller2 : $@convention(thin) (Int) -> @owned @callee_guaranteed () -> () { bb0(%0 : $Int): %f = function_ref @generic_callee2 : $@convention(thin) (@in T, @owned <τ_0_0> { var τ_0_0 } ) -> () %i = alloc_stack $Int store %0 to [trivial] %i : $*Int %b = alloc_box $<τ_0_0> { var τ_0_0 } %c = partial_apply [callee_guaranteed] %f(%i, %b) : $@convention(thin) (@in T, @owned <τ_0_0> { var τ_0_0 } ) -> () dealloc_stack %i : $*Int return %c : $@callee_guaranteed () -> () } // This is the descriptor for '<τ_0_0> { var τ_0_0 } ' 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_with_layout // CHECK-NEXT: (layout // CHECK-NEXT: (var // CHECK-NEXT: (generic_type_parameter depth=0 index=0))) // CHECK-NEXT: (generic_signature // CHECK-NEXT: (substitution // CHECK-NEXT: (generic_type_parameter depth=0 index=0) // 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 [ossa] @generic_callee3 : $@convention(thin) (@in_guaranteed T) -> () { bb0(%t : $*T): %12 = tuple () return %12 : $() } sil [ossa] @generic_caller3 : $@convention(thin) (@owned Optional<@callee_guaranteed @substituted (@in_guaranteed X) -> @out Y for >) -> @owned @callee_guaranteed () -> () { bb0(%0 : @owned $Optional<@callee_guaranteed @substituted (@in_guaranteed X) -> @out Y for >): %f = function_ref @generic_callee3 : $@convention(thin) (@in_guaranteed T) -> () %t = alloc_stack $Optional<@callee_guaranteed @substituted (@in_guaranteed X) -> @out Y for > store %0 to [init] %t : $*Optional<@callee_guaranteed @substituted (@in_guaranteed X) -> @out Y for > %c = partial_apply [callee_guaranteed] %f B>, (B, (C) -> Int)>(%t) : $@convention(thin) (@in_guaranteed T) -> () dealloc_stack %t : $*Optional<@callee_guaranteed @substituted (@in_guaranteed X) -> @out Y for > return %c : $@callee_guaranteed () -> () } // CHECK: - Capture types: // CHECK-NEXT: (bound_generic_enum Swift.Optional // CHECK-NEXT: (function // CHECK-NEXT: (parameters) // CHECK-NEXT: (result // CHECK-NEXT: (tuple))) // CHECK-NEXT: - Metadata sources: // CHECK-NEXT: (bound_generic_enum Swift.Optional // CHECK-NEXT: (function // CHECK-NEXT: (parameters // CHECK-NEXT: (generic_type_parameter depth=0 index=0) // CHECK-NEXT: (result // CHECK-NEXT: (generic_type_parameter depth=0 index=1))) // CHECK-NEXT: (closure_binding index=0) // CHECK-NEXT: (tuple // CHECK-NEXT: (generic_type_parameter depth=0 index=1) // CHECK-NEXT: (function // CHECK-NEXT: (parameters // CHECK-NEXT: (generic_type_parameter depth=0 index=2) // CHECK-NEXT: (result // CHECK-NEXT: (struct Swift.Int))) // CHECK-NEXT: (closure_binding index=1) // Generic caller and generic callee -- and one of the type parameters is // fulfilled by a thick metatype value. sil [ossa] @generic_callee4 : $@convention(thin) (@thick Optional.Type) -> () { bb0(%t : $@thick Optional.Type): %12 = tuple () return %12 : $() } sil [ossa] @generic_caller4 : $@convention(thin) () -> @owned @callee_guaranteed () -> () { bb0: %f = function_ref @generic_callee4 : $@convention(thin) (@thick Optional.Type) -> () %t = metatype $@thick Optional<(B) -> C>.Type %c = partial_apply [callee_guaranteed] %f<(B) -> C, Int>(%t) : $@convention(thin) (@thick Optional.Type) -> () return %c : $@callee_guaranteed () -> () } // CHECK: - Capture types: // CHECK-NEXT: (metatype was_abstract // CHECK-NEXT: (bound_generic_enum Swift.Optional // CHECK-NEXT: (function // CHECK-NEXT: (parameters // CHECK-NEXT: (generic_type_parameter depth=0 index=1) // CHECK-NEXT: (result // CHECK-NEXT: (generic_type_parameter depth=0 index=2)))) // CHECK-NEXT: - Metadata sources: // CHECK-NEXT: (function // CHECK-NEXT: (parameters // CHECK-NEXT: (generic_type_parameter depth=0 index=1) // CHECK-NEXT: (result // 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 {} sil [ossa] @generic_callee5 : $@convention(thin) (@owned GenericClass) -> () { bb0(%t : @owned $GenericClass): %12 = tuple () destroy_value %t : $GenericClass return %12 : $() } sil [ossa] @generic_caller5 : $@convention(thin) (@owned GenericClass<(A, B), (B, C)>) -> @owned @callee_guaranteed () -> () { bb0(%g : @owned $GenericClass<(A, B), (B, C)>): %f = function_ref @generic_callee5 : $@convention(thin) (@owned GenericClass) -> () %c = partial_apply [callee_guaranteed] %f<(A, B), (B, C), (C, A)>(%g) : $@convention(thin) (@owned GenericClass) -> () return %c : $@callee_guaranteed () -> () } 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: (tuple // CHECK-NEXT: (generic_type_parameter depth=0 index=2) // CHECK-NEXT: (generic_type_parameter depth=0 index=0)) // CHECK-NEXT: (closure_binding index=0) // 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 [ossa] @pseudogeneric_callee : $@convention(thin) @pseudogeneric (@owned T, @owned U) -> () { bb0(%t : @owned $T, %u : @owned $U): %12 = tuple () destroy_value %t : $T destroy_value %u : $U return %12 : $() } sil [ossa] @pseudogeneric_caller : $@convention(thin) @pseudogeneric (@owned A, @owned B) -> @owned @callee_guaranteed () -> () { bb0(%a : @owned $A, %b : @owned $B): %f = function_ref @pseudogeneric_callee : $@convention(thin) @pseudogeneric (@owned T, @owned U) -> () %c = partial_apply [callee_guaranteed] %f(%a, %b) : $@convention(thin) @pseudogeneric (@owned A, @owned B) -> () return %c : $@callee_guaranteed () -> () } // CHECK: - Capture types: // CHECK-NEXT: (protocol_composition any_object) // CHECK-NEXT: (protocol_composition any_object) // CHECK-NEXT: - Metadata sources: // Capturing lowered function types sil [ossa] @function_callee : $@convention(thin) (@convention(thin) () -> (), @convention(c) () -> (), @convention(block) () -> (), @convention(thick) () -> (), @convention(method) () -> (), @convention(witness_method: P) (Int) -> ()) -> () { bb0(%thin : $@convention(thin) () -> (), %c : $@convention(c) () -> (), %block : @unowned $@convention(block) () -> (), %thick : @unowned $@convention(thick) () -> (), %method : $@convention(method) () -> (), %witness_method : $@convention(witness_method: P) (Int) -> ()): %12 = tuple () return %12 : $() } sil [ossa] @function_caller : $@convention(thin) (@convention(thin) () -> (), @convention(c) () -> (), @owned @convention(block) () -> (), @owned @convention(thick) () -> (), @convention(method) () -> (), @convention(witness_method: P) (Int) -> ()) -> @owned @callee_guaranteed () -> () { bb0(%thin: $@convention(thin) () -> (), %c: $@convention(c) () -> (), %block: @owned $@convention(block) () -> (), %thick: @owned $@convention(thick) () -> (), %method: $@convention(method) () -> (), %witness_method: $@convention(witness_method: P) (Int) -> ()): %f = function_ref @function_callee : $@convention(thin) (@convention(thin) () -> (), @convention(c) () -> (), @convention(block) () -> (), @convention(thick) () -> (), @convention(method) () -> (), @convention(witness_method: P) (Int) -> ()) -> () %result = partial_apply [callee_guaranteed] %f(%thin, %c, %block, %thick, %method, %witness_method) : $@convention(thin) (@convention(thin) () -> (), @convention(c) () -> (), @convention(block) () -> (), @convention(thick) () -> (), @convention(method) () -> (), @convention(witness_method: P) (Int) -> ()) -> () return %result : $@callee_guaranteed () -> () } // CHECK: - Capture types: // CHECK-NEXT: (function convention=thin // CHECK-NEXT: (parameters) // CHECK-NEXT: (result // CHECK-NEXT: (tuple)) // CHECK-NEXT: (function convention=c // CHECK-NEXT: (parameters) // CHECK-NEXT: (result // CHECK-NEXT: (tuple)) // CHECK-NEXT: (function convention=block // CHECK-NEXT: (parameters) // CHECK-NEXT: (result // CHECK-NEXT: (tuple)) // CHECK-NEXT: (function // CHECK-NEXT: (parameters) // CHECK-NEXT: (result // CHECK-NEXT: (tuple)) // CHECK-NEXT: (function convention=thin // CHECK-NEXT: (parameters) // CHECK-NEXT: (result // CHECK-NEXT: (tuple)) // CHECK-NEXT: (function convention=thin // CHECK-NEXT: (parameters) // CHECK-NEXT: (result // 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 [ossa] @existential_callee : $@convention(thin) <τ_0_0 where τ_0_0 : P> () -> @out P { bb0(%0 : $*P): unreachable } sil [ossa] @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) Self %f = function_ref @existential_callee : $@convention(thin) <τ_0_0 where τ_0_0 : P> () -> @out P %result = partial_apply [callee_guaranteed] %f<@opened("2D7A8F84-2973-11E7-838D-34363BD08DA0", P) Self>() : $@convention(thin) <τ_0_0 where τ_0_0 : P> () -> @out P destroy_value %result : $@callee_guaranteed () -> @out P destroy_addr %0 : $*P %tuple = tuple () return %tuple : $() }