mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
227 lines
10 KiB
Swift
227 lines
10 KiB
Swift
// 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()
|
|
}
|
|
}
|