// RUN: %target-swift-frontend -emit-silgen %s | FileCheck %s func foo() -> String? { return "" } func bar() -> String? { return "" } func a(x: String) {} func b(x: String) {} func c(x: String) {} func marker_1() {} func marker_2() {} func marker_3() {} // CHECK-LABEL: sil hidden @_TF16if_while_binding10if_no_else func if_no_else() { // CHECK: [[FOO:%.*]] = function_ref @_TF16if_while_binding3fooFT_GSqSS_ // CHECK: [[OPT_RES:%.*]] = apply [[FOO]]() // CHECK: switch_enum [[OPT_RES]] : $Optional, case #Optional.Some!enumelt.1: [[YES:bb[0-9]+]], default [[CONT:bb[0-9]+]] if let x = foo() { // CHECK: [[YES]]([[VAL:%[0-9]+]] : $String): // CHECK: [[A:%.*]] = function_ref @_TF16if_while_binding // CHECK: retain_value [[VAL]] // CHECK: apply [[A]]([[VAL]]) // CHECK: release_value [[VAL]] // CHECK: br [[CONT]] a(x) } // CHECK: [[CONT]]: // CHECK-NEXT: tuple () } // CHECK-LABEL: sil hidden @_TF16if_while_binding13if_else_chainFT_T_ : $@convention(thin) () -> () { func if_else_chain() { // CHECK: [[FOO:%.*]] = function_ref @_TF16if_while_binding3foo // CHECK-NEXT: [[OPT_RES:%.*]] = apply [[FOO]]() // CHECK-NEXT: switch_enum [[OPT_RES]] : $Optional, case #Optional.Some!enumelt.1: [[YESX:bb[0-9]+]], default [[NOX:bb[0-9]+]] if let x = foo() { // CHECK: [[YESX]]([[VAL:%[0-9]+]] : $String): // CHECK: debug_value [[VAL]] : $String // let x // CHECK: [[A:%.*]] = function_ref @_TF16if_while_binding // CHECK: retain_value [[VAL]] // CHECK: apply [[A]]([[VAL]]) // CHECK: release_value [[VAL]] // CHECK: br [[CONT_X:bb[0-9]+]] a(x) // CHECK: [[NOX]]: // CHECK: alloc_box $String // var y // CHECK: switch_enum {{.*}} : $Optional, case #Optional.Some!enumelt.1: [[YESY:bb[0-9]+]], default [[ELSE1:bb[0-9]+]] // CHECK: [[ELSE1]]: // CHECK: dealloc_box $String // CHECK: br [[ELSE:bb[0-9]+]] } else if var y = bar() { // CHECK: [[YESY]]([[VAL:%[0-9]+]] : $String): // CHECK: br [[CONT_Y:bb[0-9]+]] b(y) } else { // CHECK: [[ELSE]]: // CHECK: function_ref if_while_binding.c c("") // CHECK: br [[CONT_Y]] } // CHECK: [[CONT_Y]]: // br [[CONT_X]] // CHECK: [[CONT_X]]: } // CHECK-LABEL: sil hidden @_TF16if_while_binding10while_loopFT_T_ : $@convention(thin) () -> () { func while_loop() { // CHECK: br [[LOOP_ENTRY:bb[0-9]+]] // CHECK: [[LOOP_ENTRY]]: // CHECK: switch_enum {{.*}} : $Optional, case #Optional.Some!enumelt.1: [[LOOP_BODY:bb[0-9]+]], default [[LOOP_EXIT:bb[0-9]+]] while let x = foo() { // CHECK: [[LOOP_BODY]]([[X:%[0-9]+]] : $String): // CHECK: switch_enum {{.*}} : $Optional, case #Optional.Some!enumelt.1: [[YES:bb[0-9]+]], default [[NO:bb[0-9]+]] if let y = bar() { // CHECK: [[YES]]([[Y:%[0-9]+]] : $String): a(y) break // CHECK: release_value [[Y]] // CHECK: release_value [[X]] // CHECK: br [[LOOP_EXIT]] } // CHECK: [[NO]]: // CHECK: release_value [[X]] // CHECK: br [[LOOP_ENTRY]] } // CHECK: [[LOOP_EXIT]]: // CHECK-NEXT: tuple () // CHECK-NEXT: return } // Don't leak alloc_stacks for address-only conditional bindings in 'while'. // // CHECK-LABEL: sil hidden @_TF16if_while_binding18while_loop_generic // CHECK: br [[COND:bb[0-9]+]] // CHECK: [[COND]]: // CHECK: [[X:%.*]] = alloc_stack $T // let x // CHECK: [[OPTBUF:%[0-9]+]] = alloc_stack $Optional // CHECK: switch_enum_addr {{.*}}, case #Optional.Some!enumelt.1: [[LOOPBODY:bb.*]], default [[OUT:bb[0-9]+]] // CHECK: [[OUT]]: // CHECK: dealloc_stack [[OPTBUF]]#0 // CHECK: dealloc_stack [[X]] // CHECK: br [[DONE:bb[0-9]+]] // CHECK: [[LOOPBODY]]: // CHECK: [[ENUMVAL:%.*]] = unchecked_take_enum_data_addr // CHECK: copy_addr [take] [[ENUMVAL]] to [initialization] [[X]]#1 // CHECK: destroy_addr [[X]] // CHECK: dealloc_stack [[X]] // CHECK: br [[COND]] // CHECK: [[DONE]]: // CHECK: strong_release %0 func while_loop_generic(source: () -> T?) { while let x = source() { } } // Improve 'if let' to avoid optional pyramid of doom // CHECK-LABEL: sil hidden @_TF16if_while_binding16while_loop_multiFT_T_ func while_loop_multi() { // CHECK: br [[LOOP_ENTRY:bb[0-9]+]] // CHECK: [[LOOP_ENTRY]]: // CHECK: switch_enum {{.*}}, case #Optional.Some!enumelt.1: [[CHECKBUF2:bb.*]], default [[LOOP_EXIT0:bb[0-9]+]] // CHECK: [[CHECKBUF2]]([[A:%[0-9]+]] : $String): // CHECK: debug_value [[A]] : $String // let a // CHECK: switch_enum {{.*}}, case #Optional.Some!enumelt.1: [[LOOP_BODY:bb.*]], default [[LOOP_EXIT2a:bb[0-9]+]] // CHECK: [[LOOP_EXIT2a]]: // CHECK: release_value [[A]] // CHECK: br [[LOOP_EXIT0]] // CHECK: [[LOOP_BODY]]([[B:%[0-9]+]] : $String): while let a = foo(), b = bar() { // CHECK: debug_value [[B]] : $String // let b // CHECK: debug_value [[A]] : $String // let c // CHECK: release_value [[B]] // CHECK: release_value [[A]] // CHECK: br [[LOOP_ENTRY]] let c = a } // CHECK: [[LOOP_EXIT0]]: // CHECK-NEXT: tuple () // CHECK-NEXT: return } // CHECK-LABEL: sil hidden @_TF16if_while_binding8if_multiFT_T_ func if_multi() { // CHECK: switch_enum {{.*}}, case #Optional.Some!enumelt.1: [[CHECKBUF2:bb.*]], default [[IF_DONE:bb[0-9]+]] // CHECK: [[CHECKBUF2]]([[A:%[0-9]+]] : $String): // CHECK: debug_value [[A]] : $String // let a // CHECK: [[B:%[0-9]+]] = alloc_box $String // var b // CHECK: switch_enum {{.*}}, case #Optional.Some!enumelt.1: [[IF_BODY:bb.*]], default [[IF_EXIT1a:bb[0-9]+]] // CHECK: [[IF_EXIT1a]]: // CHECK: dealloc_box $String, [[B]] // CHECK: release_value [[A]] // CHECK: br [[IF_DONE]] // CHECK: [[IF_BODY]]([[BVAL:%[0-9]+]] : $String): if let a = foo(), var b = bar() { // CHECK: store [[BVAL]] to [[B]]#1 : $*String // CHECK: debug_value {{.*}} : $String // let c // CHECK: strong_release [[B]] // CHECK: release_value [[A]] // CHECK: br [[IF_DONE]] let c = a } // CHECK: [[IF_DONE]]: // CHECK-NEXT: tuple () // CHECK-NEXT: return } // CHECK-LABEL: sil hidden @_TF16if_while_binding13if_multi_elseFT_T_ func if_multi_else() { // CHECK: switch_enum {{.*}}, case #Optional.Some!enumelt.1: [[CHECKBUF2:bb.*]], default [[ELSE:bb[0-9]+]] // CHECK: [[CHECKBUF2]]([[A:%[0-9]+]] : $String): // CHECK: debug_value [[A]] : $String // let a // CHECK: [[B:%[0-9]+]] = alloc_box $String // var b // CHECK: switch_enum {{.*}}, case #Optional.Some!enumelt.1: [[IF_BODY:bb.*]], default [[IF_EXIT1a:bb[0-9]+]] // CHECK: [[IF_EXIT1a]]: // CHECK: dealloc_box $String, [[B]]#0 // CHECK: release_value [[A]] // CHECK: br [[ELSE]] // CHECK: [[IF_BODY]]([[BVAL:%[0-9]+]] : $String): if let a = foo(), var b = bar() { // CHECK: store [[BVAL]] to [[B]]#1 : $*String // CHECK: debug_value {{.*}} : $String // let c // CHECK: strong_release [[B]] // CHECK: release_value [[A]] // CHECK: br [[IF_DONE:bb[0-9]+]] let c = a } else { let d = 0 // CHECK: [[ELSE]]: // CHECK: debug_value {{.*}} : $Int // let d // CHECK: br [[IF_DONE]] } // CHECK: [[IF_DONE]]: // CHECK-NEXT: tuple () // CHECK-NEXT: return } // CHECK-LABEL: sil hidden @_TF16if_while_binding14if_multi_whereFT_T_ func if_multi_where() { // CHECK: switch_enum {{.*}}, case #Optional.Some!enumelt.1: [[CHECKBUF2:bb.*]], default [[ELSE:bb[0-9]+]] // CHECK: [[CHECKBUF2]]([[A:%[0-9]+]] : $String): // CHECK: debug_value [[A]] : $String // let a // CHECK: [[BBOX:%[0-9]+]] = alloc_box $String // var b // CHECK: switch_enum {{.*}}, case #Optional.Some!enumelt.1: [[CHECK_WHERE:bb.*]], default [[IF_EXIT1a:bb[0-9]+]] // CHECK: [[IF_EXIT1a]]: // CHECK: dealloc_box $String, [[BBOX]] // CHECK: release_value [[A]] // CHECK: br [[ELSE]] // CHECK: [[CHECK_WHERE]]([[B:%[0-9]+]] : $String): // CHECK: function_ref Swift.Bool._getBuiltinLogicValue (Swift.Bool)() -> Builtin.Int1 // CHECK: cond_br {{.*}}, [[IF_BODY:bb[0-9]+]], [[IF_EXIT3:bb[0-9]+]] // CHECK: [[IF_EXIT3]]: // CHECK: strong_release [[BBOX]]#0 // CHECK: release_value [[A]] // CHECK: br [[IF_DONE:bb[0-9]+]] if let a = foo(), var b = bar() where a == b { // CHECK: [[IF_BODY]]: // CHECK: debug_value [[CVAL:%[0-9]+]] : $String // let c // CHECK: strong_release [[BBOX]]#0 // CHECK: release_value [[A]] // CHECK: br [[IF_DONE]] let c = a } // CHECK: [[IF_DONE]]: // CHECK-NEXT: tuple () // CHECK-NEXT: return } // Swift 1.2's "if" has 2 behaviours. They could be unified. // CHECK-LABEL: sil hidden @_TF16if_while_binding18if_leading_booleanFSiT_ func if_leading_boolean(a : Int) { // Test the boolean condition. // CHECK: debug_value %0 : $Int // let a // CHECK: [[EQRESULT:%[0-9]+]] = apply {{.*}}(%0, %0) : $@convention(thin) (Int, Int) -> Bool // CHECK-NEXT: [[EQRESULTI1:%[0-9]+]] = apply %2([[EQRESULT]]) : $@convention(method) (Bool) -> Builtin.Int1 // CHECK-NEXT: cond_br [[EQRESULTI1]], [[CHECKFOO:bb[0-9]+]], [[IFDONE:bb[0-9]+]] // Call Foo and test for the optional being present. // CHECK: [[CHECKFOO]]: // CHECK: [[OPTRESULT:%[0-9]+]] = apply {{.*}}() : $@convention(thin) () -> @owned Optional // CHECK: switch_enum [[OPTRESULT]] : $Optional, case #Optional.Some!enumelt.1: [[SUCCESS:bb.*]], default [[IF_DONE:bb[0-9]+]] // CHECK: [[SUCCESS]]([[B:%[0-9]+]] : $String): // CHECK-NEXT: debug_value [[B:%[0-9]+]] : $String // let b // CHECK-NEXT: debug_value [[B:%[0-9]+]] : $String // let c // CHECK-NEXT: release_value [[B]] // CHECK-NEXT: br [[IFDONE]] if a == a, let b = foo() { let c = b } // CHECK: [[IFDONE]]: // CHECK-NEXT: tuple () } /// Assertion failure when using 'as' pattern in 'if let' class BaseClass {} class DerivedClass : BaseClass {} // CHECK-LABEL: sil hidden @_TF16if_while_binding20testAsPatternInIfLetFGSqCS_9BaseClass_T_ func testAsPatternInIfLet(a : BaseClass?) { // CHECK-NEXT: bb0(%0 : $Optional): // CHECK-NEXT: debug_value %0 : $Optional // let a // CHECK-NEXT: retain_value %0 : $Optional // CHECK-NEXT: switch_enum %0 : $Optional, case #Optional.Some!enumelt.1: [[OPTPRESENTBB:bb[0-9]+]], default [[NILBB:bb[0-9]+]] // CHECK: [[OPTPRESENTBB]](%4 : $BaseClass): // CHECK-NEXT: checked_cast_br %4 : $BaseClass to $DerivedClass, [[ISDERIVEDBB:bb[0-9]+]], [[ISBASEBB:bb[0-9]+]] // CHECK: [[ISDERIVEDBB]](%6 : $DerivedClass): // CHECK: enum $Optional, #Optional.Some!enumelt.1, %6 : $DerivedClass // CHECK: br [[MERGE:bb[0-9]+]]( // CHECK: [[ISBASEBB]]: // CHECK: strong_release %4 : $BaseClass // CHECK: = enum $Optional, #Optional.None!enumelt // CHECK: br [[MERGE]]( // CHECK: [[MERGE]]([[OPTVAL:%[0-9]+]] : $Optional): // CHECK: switch_enum [[OPTVAL]] : $Optional, case #Optional.Some!enumelt.1: [[ISDERIVEDBB:bb[0-9]+]], default [[NILBB:bb[0-9]+]] // CHECK: [[ISDERIVEDBB]]([[DERIVEDVAL:%[0-9]+]] : $DerivedClass): // CHECK-NEXT: debug_value [[DERIVEDVAL]] : $DerivedClass // CHECK-NEXT: strong_release [[DERIVEDVAL]] : $DerivedClass // CHECK-NEXT: br [[NILBB]] // CHECK: [[NILBB]]: // CHECK-NEXT: release_value %0 : $Optional // CHECK-NEXT: tuple () // CHECK-NEXT: return if case let b as DerivedClass = a { } }