// RUN: %target-swift-emit-silgen -Xllvm -sil-print-types %s | %FileCheck %s class A {} class B : A {} // CHECK-LABEL: sil hidden [ossa] @$s4main3fooyyAA1ACSgF : $@convention(thin) (@guaranteed Optional) -> () { // CHECK: bb0([[ARG:%.*]] : @guaranteed $Optional): // CHECK: [[X:%.*]] = alloc_box ${ var Optional }, var, name "x" // CHECK: [[X_LIFETIME:%[^,]+]] = begin_borrow [lexical] [var_decl] [[X]] // CHECK-NEXT: [[PB:%.*]] = project_box [[X_LIFETIME]] // Check whether the temporary holds a value. // CHECK: [[ARG_COPY:%.*]] = copy_value [[ARG]] // CHECK: switch_enum [[ARG_COPY]] : $Optional, case #Optional.some!enumelt: [[IS_PRESENT:bb[0-9]+]], case #Optional.none!enumelt: [[NOT_PRESENT:bb[0-9]+]] // // If so, pull the value out and check whether it's a B. // CHECK: [[IS_PRESENT]]([[VAL:%.*]] : // CHECK-NEXT: [[X_VALUE:%.*]] = init_enum_data_addr [[PB]] : $*Optional, #Optional.some // CHECK-NEXT: checked_cast_br A in [[VAL]] : $A to B, [[IS_B:bb.*]], [[NOT_B:bb[0-9]+]] // // If so, materialize that and inject it into x. // CHECK: [[IS_B]]([[T0:%.*]] : @owned $B): // CHECK-NEXT: store [[T0]] to [init] [[X_VALUE]] : $*B // CHECK-NEXT: inject_enum_addr [[PB]] : $*Optional, #Optional.some // CHECK-NEXT: br [[CONT:bb[0-9]+]] // // If not, destroy_value the A and inject nothing into x. // CHECK: [[NOT_B]]([[ORIGINAL_VALUE:%.*]] : @owned $A): // CHECK-NEXT: destroy_value [[ORIGINAL_VALUE]] // CHECK-NEXT: inject_enum_addr [[PB]] : $*Optional, #Optional.none // CHECK-NEXT: br [[CONT]] // // Finish the present path. // CHECK: [[CONT]]: // CHECK-NEXT: br [[RETURN_BB:bb[0-9]+]] // // Finish. // CHECK: [[RETURN_BB]]: // CHECK-NEXT: end_borrow [[X_LIFETIME]] // CHECK-NEXT: destroy_value [[X]] // CHECK-NOT: destroy_value [[ARG]] // CHECK-NEXT: tuple // CHECK-NEXT: return // // Finish the not-present path. // CHECK: [[NOT_PRESENT]]: // CHECK-NEXT: inject_enum_addr [[PB]] {{.*}}none // CHECK-NEXT: br [[RETURN_BB]] func foo(_ y : A?) { var x = (y as? B) } // CHECK-LABEL: sil hidden [ossa] @$s4main3baryyAA1ACSgSgSgSgF : $@convention(thin) (@guaranteed Optional>>>) -> () { // CHECK: bb0([[ARG:%.*]] : @guaranteed $Optional>>>): // CHECK: [[X:%.*]] = alloc_box ${ var Optional>> }, var, name "x" // CHECK: [[X_LIFETIME:%[^,]+]] = begin_borrow [lexical] [var_decl] [[X]] // CHECK-NEXT: [[PB:%.*]] = project_box [[X_LIFETIME]] // -- Check for some(...) // CHECK-NEXT: [[ARG_COPY:%.*]] = copy_value [[ARG]] // CHECK-NEXT: switch_enum [[ARG_COPY]] : ${{.*}}, case #Optional.some!enumelt: [[P:bb[0-9]+]], case #Optional.none!enumelt: [[NIL_DEPTH_1:bb[0-9]+]] // // CHECK: [[NIL_DEPTH_1]]: // CHECK: br [[FINISH_NIL_0:bb[0-9]+]] // // If so, drill down another level and check for some(some(...)). // CHECK: [[P]]([[VALUE_OOOA:%.*]] : // CHECK-NEXT: switch_enum [[VALUE_OOOA]] : ${{.*}}, case #Optional.some!enumelt: [[PP:bb[0-9]+]], case #Optional.none!enumelt: [[NIL_DEPTH_2:bb[0-9]+]] // // CHECK: [[NIL_DEPTH_2]]: // CHECK: br [[FINISH_NIL_0]] // // If so, drill down another level and check for some(some(some(...))). // CHECK: [[PP]]([[VALUE_OOA:%.*]] : // CHECK-NEXT: switch_enum [[VALUE_OOA]] : ${{.*}}, case #Optional.some!enumelt: [[PPP:bb[0-9]+]], case #Optional.none!enumelt: [[NIL_DEPTH_3:bb[0-9]+]] // // If so, drill down another level and check for some(some(some(some(...)))). // CHECK: [[PPP]]([[VALUE_OA:%.*]] : // CHECK-NEXT: switch_enum [[VALUE_OA]] : ${{.*}}, case #Optional.some!enumelt: [[PPPP:bb[0-9]+]], case #Optional.none!enumelt: [[NIL_DEPTH_4:bb[0-9]+]] // // If so, pull out the A and check whether it's a B. // CHECK: [[PPPP]]([[VAL:%.*]] : // CHECK-NEXT: checked_cast_br A in [[VAL]] : $A to B, [[IS_B:bb.*]], [[NOT_B:bb[0-9]+]] // // If so, inject it back into an optional. // TODO: We're going to switch back out of this; we really should peephole it. // CHECK: [[IS_B]]([[T0:%.*]] : @owned $B): // CHECK-NEXT: enum $Optional, #Optional.some!enumelt, [[T0]] // CHECK-NEXT: br [[SWITCH_OB2:bb[0-9]+]]( // // If not, inject nothing into an optional. // CHECK: [[NOT_B]]([[ORIGINAL_VALUE:%.*]] : @owned $A): // CHECK-NEXT: destroy_value [[ORIGINAL_VALUE]] // CHECK-NEXT: enum $Optional, #Optional.none!enumelt // CHECK-NEXT: br [[SWITCH_OB2]]( // // Switch out on the value in [[OB2]]. // CHECK: [[SWITCH_OB2]]([[VAL:%[0-9]+]] : @owned $Optional): // CHECK-NEXT: switch_enum [[VAL]] : ${{.*}}, case #Optional.some!enumelt: [[HAVE_B:bb[0-9]+]], case #Optional.none!enumelt: [[FINISH_NIL_4:bb[0-9]+]] // // CHECK: [[FINISH_NIL_4]]: // CHECK: br [[FINISH_NIL_0]] // // CHECK: [[HAVE_B]]([[UNWRAPPED_VAL:%.*]] : // CHECK: [[REWRAPPED_VAL:%.*]] = enum $Optional, #Optional.some!enumelt, [[UNWRAPPED_VAL]] // CHECK: br [[DONE_DEPTH0:bb[0-9]+]] // // CHECK: [[DONE_DEPTH0]]( // CHECK-NEXT: enum $Optional>, #Optional.some!enumelt, // CHECK-NEXT: br [[DONE_DEPTH1:bb[0-9]+]] // // Set X := some(OOB). // CHECK: [[DONE_DEPTH1]] // CHECK-NEXT: enum $Optional>>, #Optional.some!enumelt, // CHECK: br [[DONE_DEPTH2:bb[0-9]+]] // CHECK: [[DONE_DEPTH2]] // CHECK-NEXT: end_borrow [[X_LIFETIME]] // CHECK-NEXT: destroy_value [[X]] // CHECK-NOT: destroy_value %0 // CHECK: return // // On various failure paths, set OOB := nil. // CHECK: [[NIL_DEPTH_4]]: // CHECK-NEXT: enum $Optional, #Optional.none!enumelt // CHECK-NEXT: br [[DONE_DEPTH0]] // // CHECK: [[NIL_DEPTH_3]]: // CHECK-NEXT: enum $Optional>, #Optional.none!enumelt // CHECK-NEXT: br [[DONE_DEPTH1]] // // On various failure paths, set X := nil. // CHECK: [[FINISH_NIL_0]]: // CHECK-NEXT: inject_enum_addr [[PB]] {{.*}}none // CHECK-NEXT: br [[DONE_DEPTH2]] // Done. func bar(_ y : A????) { var x = (y as? B??) } // CHECK-LABEL: sil hidden [ossa] @$s4main3bazyyyXlSgF : $@convention(thin) (@guaranteed Optional) -> () { // CHECK: bb0([[ARG:%.*]] : @guaranteed $Optional): // CHECK: [[X:%.*]] = alloc_box ${ var Optional }, var, name "x" // CHECK: [[X_LIFETIME:%[^,]+]] = begin_borrow [lexical] [var_decl] [[X]] // CHECK-NEXT: [[PB:%.*]] = project_box [[X_LIFETIME]] // CHECK-NEXT: [[ARG_COPY:%.*]] = copy_value [[ARG]] // CHECK: switch_enum [[ARG_COPY]] // CHECK: bb1([[VAL:%.*]] : @owned $AnyObject): // CHECK-NEXT: [[X_VALUE:%.*]] = init_enum_data_addr [[PB]] : $*Optional, #Optional.some // CHECK-NEXT: checked_cast_br AnyObject in [[VAL]] : $AnyObject to B, [[IS_B:bb.*]], [[NOT_B:bb[0-9]+]] // CHECK: [[IS_B]]([[CASTED_VALUE:%.*]] : @owned $B): // CHECK: store [[CASTED_VALUE]] to [init] [[X_VALUE]] // CHECK: [[NOT_B]]([[ORIGINAL_VALUE:%.*]] : @owned $AnyObject): // CHECK: destroy_value [[ORIGINAL_VALUE]] // CHECK: } // end sil function '$s4main3bazyyyXlSgF' func baz(_ y : AnyObject?) { var x = (y as? B) } // T! <-> T? conversions should not produce a diamond // CHECK-LABEL: sil hidden [ossa] @$s4main07opt_to_B8_trivialySiSgACF // CHECK: bb0(%0 : $Optional): // CHECK-NEXT: debug_value %0 : $Optional, let, name "x" // CHECK-NEXT: return %0 : $Optional // CHECK-NEXT:} func opt_to_opt_trivial(_ x: Int?) -> Int! { return x } // CHECK-LABEL: sil hidden [ossa] @$s4main07opt_to_B10_referenceyAA1CCSgAEF // CHECK: bb0([[ARG:%.*]] : @guaranteed $Optional): // CHECK: debug_value [[ARG]] : $Optional, let, name "x" // CHECK: [[RESULT:%.*]] = copy_value [[ARG]] // CHECK-NOT: destroy_value [[ARG]] // CHECK: return [[RESULT]] : $Optional // CHECK: } // end sil function '$s4main07opt_to_B10_referenceyAA1CCSgAEF' func opt_to_opt_reference(_ x : C!) -> C? { return x } // CHECK-LABEL: sil hidden [ossa] @$s4main07opt_to_B12_addressOnly{{[_0-9a-zA-Z]*}}F // CHECK: bb0(%0 : $*Optional, %1 : $*Optional): // CHECK-NEXT: debug_value %1 : $*Optional, let, name "x", {{.*}} expr op_deref // CHECK-NEXT: copy_addr %1 to [init] %0 // CHECK-NOT: destroy_addr %1 func opt_to_opt_addressOnly(_ x : T!) -> T? { return x } class C {} public struct TestAddressOnlyStruct { func f(_ a : T?) {} // CHECK-LABEL: sil hidden [ossa] @$s4main21TestAddressOnlyStructV8testCall{{[_0-9a-zA-Z]*}}F // CHECK: bb0(%0 : $*Optional, %1 : $TestAddressOnlyStruct): // CHECK: apply {{.*}}(%0, %1) func testCall(_ a : T!) { f(a) } } // CHECK-LABEL: sil hidden [ossa] @$s4main35testContextualInitOfNonAddrOnlyTypeyySiSgF // CHECK: bb0(%0 : $Optional): // CHECK-NEXT: debug_value %0 : $Optional, let, name "a" // CHECK-NEXT: [[X:%.*]] = alloc_box ${ var Optional }, var, name "x" // CHECK-NEXT: [[L:%.*]] = begin_borrow [var_decl] [[X]] // CHECK-NEXT: [[PB:%.*]] = project_box [[L]] // CHECK-NEXT: store %0 to [trivial] [[PB]] : $*Optional // CHECK-NEXT: end_borrow [[L]] // CHECK-NEXT: destroy_value [[X]] : ${ var Optional } func testContextualInitOfNonAddrOnlyType(_ a : Int?) { var x: Int! = a }