// RUN: %target-swift-frontend -Xllvm -sil-full-demangle -emit-silgen %s | %FileCheck %s // RUN: %target-swift-frontend -Xllvm -sil-full-demangle -emit-silgen %s | %FileCheck %s --check-prefix=GUARANTEED func test_type_lowering(_ x: Error) { } // CHECK-LABEL: sil hidden @_T018boxed_existentials18test_type_loweringys5Error_pF : $@convention(thin) (@owned Error) -> () { // CHECK: destroy_value %0 : $Error class Document {} enum ClericalError: Error { case MisplacedDocument(Document) var _domain: String { return "" } var _code: Int { return 0 } } func test_concrete_erasure(_ x: ClericalError) -> Error { return x } // CHECK-LABEL: sil hidden @_T018boxed_existentials21test_concrete_erasures5Error_pAA08ClericalF0OF // CHECK: bb0([[ARG:%.*]] : $ClericalError): // CHECK: [[EXISTENTIAL:%.*]] = alloc_existential_box $Error, $ClericalError // CHECK: [[ADDR:%.*]] = project_existential_box $ClericalError in [[EXISTENTIAL]] : $Error // CHECK: [[BORROWED_ARG:%.*]] = begin_borrow [[ARG]] // CHECK: [[ARG_COPY:%.*]] = copy_value [[BORROWED_ARG]] // CHECK: store [[ARG_COPY]] to [init] [[ADDR]] : $*ClericalError // CHECK: end_borrow [[BORROWED_ARG]] from [[ARG]] // CHECK: destroy_value [[ARG]] // CHECK: return [[EXISTENTIAL]] : $Error protocol HairType {} func test_composition_erasure(_ x: HairType & Error) -> Error { return x } // CHECK-LABEL: sil hidden @_T018boxed_existentials24test_composition_erasures5Error_psAC_AA8HairTypepF // CHECK: [[VALUE_ADDR:%.*]] = open_existential_addr immutable_access [[OLD_EXISTENTIAL:%.*]] : $*Error & HairType to $*[[VALUE_TYPE:@opened\(.*\) Error & HairType]] // CHECK: [[NEW_EXISTENTIAL:%.*]] = alloc_existential_box $Error, $[[VALUE_TYPE]] // CHECK: [[ADDR:%.*]] = project_existential_box $[[VALUE_TYPE]] in [[NEW_EXISTENTIAL]] : $Error // CHECK: copy_addr [[VALUE_ADDR]] to [initialization] [[ADDR]] // CHECK: destroy_addr [[OLD_EXISTENTIAL]] // CHECK: return [[NEW_EXISTENTIAL]] protocol HairClass: class {} func test_class_composition_erasure(_ x: HairClass & Error) -> Error { return x } // CHECK-LABEL: sil hidden @_T018boxed_existentials30test_class_composition_erasures5Error_psAC_AA9HairClasspF // CHECK: [[VALUE:%.*]] = open_existential_ref [[OLD_EXISTENTIAL:%.*]] : $Error & HairClass to $[[VALUE_TYPE:@opened\(.*\) Error & HairClass]] // CHECK: [[NEW_EXISTENTIAL:%.*]] = alloc_existential_box $Error, $[[VALUE_TYPE]] // CHECK: [[ADDR:%.*]] = project_existential_box $[[VALUE_TYPE]] in [[NEW_EXISTENTIAL]] : $Error // CHECK: [[COPIED_VALUE:%.*]] = copy_value [[VALUE]] // CHECK: store [[COPIED_VALUE]] to [init] [[ADDR]] // CHECK: return [[NEW_EXISTENTIAL]] func test_property(_ x: Error) -> String { return x._domain } // CHECK-LABEL: sil hidden @_T018boxed_existentials13test_propertySSs5Error_pF // CHECK: bb0([[ARG:%.*]] : $Error): // CHECK: [[BORROWED_ARG:%.*]] = begin_borrow [[ARG]] // CHECK: [[VALUE:%.*]] = open_existential_box [[BORROWED_ARG]] : $Error to $*[[VALUE_TYPE:@opened\(.*\) Error]] // FIXME: Extraneous copy here // CHECK-NEXT: [[COPY:%[0-9]+]] = alloc_stack $[[VALUE_TYPE]] // CHECK-NEXT: copy_addr [[VALUE]] to [initialization] [[COPY]] : $*[[VALUE_TYPE]] // CHECK: [[METHOD:%.*]] = witness_method $[[VALUE_TYPE]], #Error._domain!getter.1 // -- self parameter of witness is @in_guaranteed; no need to copy since // value in box is immutable and box is guaranteed // CHECK: [[RESULT:%.*]] = apply [[METHOD]]<[[VALUE_TYPE]]>([[COPY]]) // CHECK: end_borrow [[BORROWED_ARG]] from [[ARG]] // CHECK: destroy_value [[ARG]] // CHECK: return [[RESULT]] func test_property_of_lvalue(_ x: Error) -> String { var x = x return x._domain } // CHECK-LABEL: sil hidden @_T018boxed_existentials23test_property_of_lvalueSSs5Error_pF : // CHECK: bb0([[ARG:%.*]] : $Error): // CHECK: [[VAR:%.*]] = alloc_box ${ var Error } // CHECK: [[PVAR:%.*]] = project_box [[VAR]] // CHECK: [[BORROWED_ARG:%.*]] = begin_borrow [[ARG]] // CHECK: [[ARG_COPY:%.*]] = copy_value [[BORROWED_ARG]] : $Error // CHECK: store [[ARG_COPY]] to [init] [[PVAR]] // CHECK: [[ACCESS:%.*]] = begin_access [read] [unknown] [[PVAR]] : $*Error // CHECK: [[VALUE_BOX:%.*]] = load [copy] [[ACCESS]] // CHECK: [[VALUE:%.*]] = open_existential_box [[VALUE_BOX]] : $Error to $*[[VALUE_TYPE:@opened\(.*\) Error]] // CHECK: [[COPY:%.*]] = alloc_stack $[[VALUE_TYPE]] // CHECK: copy_addr [[VALUE]] to [initialization] [[COPY]] // CHECK: [[METHOD:%.*]] = witness_method $[[VALUE_TYPE]], #Error._domain!getter.1 // CHECK: [[RESULT:%.*]] = apply [[METHOD]]<[[VALUE_TYPE]]>([[COPY]]) // CHECK: destroy_addr [[COPY]] // CHECK: dealloc_stack [[COPY]] // CHECK: destroy_value [[VALUE_BOX]] // CHECK: destroy_value [[VAR]] // CHECK: destroy_value [[ARG]] // CHECK: return [[RESULT]] // CHECK: } // end sil function '_T018boxed_existentials23test_property_of_lvalueSSs5Error_pF' extension Error { func extensionMethod() { } } // CHECK-LABEL: sil hidden @_T018boxed_existentials21test_extension_methodys5Error_pF func test_extension_method(_ error: Error) { // CHECK: bb0([[ARG:%.*]] : $Error): // CHECK: [[BORROWED_ARG:%.*]] = begin_borrow [[ARG]] // CHECK: [[VALUE:%.*]] = open_existential_box [[BORROWED_ARG]] // CHECK: [[METHOD:%.*]] = function_ref // CHECK-NOT: copy_addr // CHECK: apply [[METHOD]]<{{.*}}>([[VALUE]]) // CHECK-NOT: destroy_addr [[COPY]] // CHECK-NOT: destroy_addr [[VALUE]] // CHECK-NOT: destroy_addr [[VALUE]] // -- destroy_value the owned argument // CHECK: destroy_value %0 error.extensionMethod() } func plusOneError() -> Error { } // CHECK-LABEL: sil hidden @_T018boxed_existentials31test_open_existential_semanticsys5Error_p_sAC_ptF // GUARANTEED-LABEL: sil hidden @_T018boxed_existentials31test_open_existential_semanticsys5Error_p_sAC_ptF // CHECK: bb0([[ARG0:%.*]]: $Error, // GUARANTEED: bb0([[ARG0:%.*]]: $Error, func test_open_existential_semantics(_ guaranteed: Error, _ immediate: Error) { var immediate = immediate // CHECK: [[IMMEDIATE_BOX:%.*]] = alloc_box ${ var Error } // CHECK: [[PB:%.*]] = project_box [[IMMEDIATE_BOX]] // GUARANTEED: [[IMMEDIATE_BOX:%.*]] = alloc_box ${ var Error } // GUARANTEED: [[PB:%.*]] = project_box [[IMMEDIATE_BOX]] // CHECK-NOT: copy_value [[ARG0]] // CHECK: [[BORROWED_ARG0:%.*]] = begin_borrow [[ARG0]] // CHECK: [[VALUE:%.*]] = open_existential_box [[BORROWED_ARG0]] // CHECK: [[METHOD:%.*]] = function_ref // CHECK-NOT: copy_addr // CHECK: apply [[METHOD]]<{{.*}}>([[VALUE]]) // CHECK: end_borrow [[BORROWED_ARG0]] from [[ARG0]] // CHECK-NOT: destroy_value [[ARG0]] // GUARANTEED-NOT: copy_value [[ARG0]] // GUARANTEED: [[BORROWED_ARG0:%.*]] = begin_borrow [[ARG0]] // GUARANTEED: [[VALUE:%.*]] = open_existential_box [[BORROWED_ARG0]] // GUARANTEED: [[METHOD:%.*]] = function_ref // GUARANTEED: apply [[METHOD]]<{{.*}}>([[VALUE]]) // GUARANTEED: end_borrow [[BORROWED_ARG0]] from [[ARG0]] // GUARANTEED-NOT: destroy_addr [[VALUE]] // GUARANTEED-NOT: destroy_value [[ARG0]] guaranteed.extensionMethod() // CHECK: [[ACCESS:%.*]] = begin_access [read] [unknown] [[PB]] : $*Error // CHECK: [[IMMEDIATE:%.*]] = load [copy] [[ACCESS]] // -- need a copy_value to guarantee // CHECK: [[VALUE:%.*]] = open_existential_box [[IMMEDIATE]] // CHECK: [[METHOD:%.*]] = function_ref // CHECK-NOT: copy_addr // CHECK: apply [[METHOD]]<{{.*}}>([[VALUE]]) // -- end the guarantee // -- TODO: could in theory do this sooner, after the value's been copied // out. // CHECK: destroy_value [[IMMEDIATE]] // GUARANTEED: [[ACCESS:%.*]] = begin_access [read] [unknown] [[PB]] : $*Error // GUARANTEED: [[IMMEDIATE:%.*]] = load [copy] [[ACCESS]] // -- need a copy_value to guarantee // GUARANTEED: [[VALUE:%.*]] = open_existential_box [[IMMEDIATE]] // GUARANTEED: [[METHOD:%.*]] = function_ref // GUARANTEED: apply [[METHOD]]<{{.*}}>([[VALUE]]) // GUARANTEED-NOT: destroy_addr [[VALUE]] // -- end the guarantee // GUARANTEED: destroy_value [[IMMEDIATE]] immediate.extensionMethod() // CHECK: [[F:%.*]] = function_ref {{.*}}plusOneError // CHECK: [[PLUS_ONE:%.*]] = apply [[F]]() // CHECK: [[VALUE:%.*]] = open_existential_box [[PLUS_ONE]] // CHECK: [[METHOD:%.*]] = function_ref // CHECK-NOT: copy_addr // CHECK: apply [[METHOD]]<{{.*}}>([[VALUE]]) // CHECK: destroy_value [[PLUS_ONE]] // GUARANTEED: [[F:%.*]] = function_ref {{.*}}plusOneError // GUARANTEED: [[PLUS_ONE:%.*]] = apply [[F]]() // GUARANTEED: [[VALUE:%.*]] = open_existential_box [[PLUS_ONE]] // GUARANTEED: [[METHOD:%.*]] = function_ref // GUARANTEED: apply [[METHOD]]<{{.*}}>([[VALUE]]) // GUARANTEED-NOT: destroy_addr [[VALUE]] // GUARANTEED: destroy_value [[PLUS_ONE]] plusOneError().extensionMethod() } // CHECK-LABEL: sil hidden @_T018boxed_existentials14erasure_to_anyyps5Error_p_sAC_ptF // CHECK: bb0([[OUT:%.*]] : $*Any, [[GUAR:%.*]] : $Error, func erasure_to_any(_ guaranteed: Error, _ immediate: Error) -> Any { var immediate = immediate // CHECK: [[IMMEDIATE_BOX:%.*]] = alloc_box ${ var Error } // CHECK: [[PB:%.*]] = project_box [[IMMEDIATE_BOX]] if true { // CHECK-NOT: copy_value [[GUAR]] // CHECK: [[FROM_VALUE:%.*]] = open_existential_box [[GUAR:%.*]] // CHECK: [[TO_VALUE:%.*]] = init_existential_addr [[OUT]] // CHECK: copy_addr [[FROM_VALUE]] to [initialization] [[TO_VALUE]] // CHECK-NOT: destroy_value [[GUAR]] return guaranteed } else if true { // CHECK: [[ACCESS:%.*]] = begin_access [read] [unknown] [[PB]] // CHECK: [[IMMEDIATE:%.*]] = load [copy] [[ACCESS]] // CHECK: [[FROM_VALUE:%.*]] = open_existential_box [[IMMEDIATE]] // CHECK: [[TO_VALUE:%.*]] = init_existential_addr [[OUT]] // CHECK: copy_addr [[FROM_VALUE]] to [initialization] [[TO_VALUE]] // CHECK: destroy_value [[IMMEDIATE]] return immediate } else if true { // CHECK: function_ref boxed_existentials.plusOneError // CHECK: [[PLUS_ONE:%.*]] = apply // CHECK: [[FROM_VALUE:%.*]] = open_existential_box [[PLUS_ONE]] // CHECK: [[TO_VALUE:%.*]] = init_existential_addr [[OUT]] // CHECK: copy_addr [[FROM_VALUE]] to [initialization] [[TO_VALUE]] // CHECK: destroy_value [[PLUS_ONE]] return plusOneError() } }