| // RUN: %target-sil-opt -assume-parsing-unqualified-ownership-sil -enable-sil-verify-all -sil-combine %s | %FileCheck %s |
| |
| import Swift |
| |
| class AClass { |
| deinit |
| init() |
| } |
| |
| struct S {} |
| |
| @objc class NSCloud {} |
| |
| // CHECK-LABEL: sil @dont_fold_unconditional_checked_cast_to_existentials |
| // CHECK: unconditional_checked_cast %1 : $NSCloud to $AnyObject |
| sil @dont_fold_unconditional_checked_cast_to_existentials : $@convention(thin) () -> AnyObject { |
| entry: |
| %0 = alloc_stack $NSCloud |
| %1 = load %0 : $*NSCloud |
| %2 = unconditional_checked_cast %1 : $NSCloud to $AnyObject |
| dealloc_stack %0 : $*NSCloud |
| return %2 : $AnyObject |
| } |
| |
| // CHECK-LABEL: sil @dont_fold_unconditional_checked_cast_from_existentials |
| // CHECK: unconditional_checked_cast %0 : $AnyObject to $NSCloud |
| sil @dont_fold_unconditional_checked_cast_from_existentials : $@convention(thin) (AnyObject) -> NSCloud { |
| entry (%0 : $AnyObject): |
| %1 = unconditional_checked_cast %0 : $AnyObject to $NSCloud |
| return %1 : $NSCloud |
| } |
| |
| // CHECK-LABEL: sil @function_cast_nothrow_to_nothrow |
| // CHECK: load |
| // CHECK: store |
| sil @function_cast_nothrow_to_nothrow : $@convention(thin) <T> () -> () { |
| entry: |
| unconditional_checked_cast_addr () -> () in undef : $*(@in ()) -> @out () to () -> () in undef : $*(@in ()) -> @out () |
| return undef : $() |
| } |
| |
| // CHECK-LABEL: sil @function_cast_nothrow_to_nothrow_substitutable |
| // CHECK: unconditional_checked_cast_addr |
| sil @function_cast_nothrow_to_nothrow_substitutable : $@convention(thin) <T> () -> () { |
| entry: |
| unconditional_checked_cast_addr () -> () in undef : $*(@in ()) -> @out () to (T) -> T in undef : $*(@in T) -> @out T |
| return undef : $() |
| } |
| |
| // CHECK-LABEL: sil @function_cast_nothrow_substitutable_to_nothrow |
| // CHECK: unconditional_checked_cast_addr |
| sil @function_cast_nothrow_substitutable_to_nothrow : $@convention(thin) <T> () -> () { |
| entry: |
| unconditional_checked_cast_addr (T) -> T in undef : $*(@in T) -> @out T to () -> () in undef : $*(@in ()) -> @out () |
| return undef : $() |
| } |
| |
| // CHECK-LABEL: sil @function_cast_throw_to_nothrow |
| // CHECK: builtin "int_trap" |
| sil @function_cast_throw_to_nothrow : $@convention(thin) <T> () -> () { |
| entry: |
| unconditional_checked_cast_addr () throws -> () in undef : $*(@in ()) -> (@out (), @error Error) to () -> () in undef : $*(@in ()) -> @out () |
| return undef : $() |
| } |
| |
| // TODO: Do a function_conversion? |
| // CHECK-LABEL: sil @function_cast_nothrow_to_throw |
| // CHECK: unconditional_checked_cast_addr |
| sil @function_cast_nothrow_to_throw : $@convention(thin) <T> () -> () { |
| entry: |
| unconditional_checked_cast_addr () -> () in undef : $*(@in ()) -> @out () to () throws -> () in undef : $*(@in ()) -> (@out (), @error Error) |
| return undef : $() |
| } |
| |
| // CHECK-LABEL: sil @function_cast_throw_to_throw |
| // CHECK: load |
| // CHECK: store |
| sil @function_cast_throw_to_throw : $@convention(thin) <T> () -> () { |
| entry: |
| unconditional_checked_cast_addr () throws -> () in undef : $*(@in ()) -> (@out (), @error Error) to () throws -> () in undef : $*(@in ()) -> (@out (), @error Error) |
| return undef : $() |
| } |
| |
| // CHECK-LABEL: sil @function_ref_cast_promote |
| // CHECK: [[LD:%.*]] = load %1 : $*AnyObject |
| // CHECK-NEXT: unchecked_ref_cast [[LD]] : $AnyObject to $AClass |
| // CHECK-NEXT: store %{{.*}} to %0 : $*AClass |
| sil @function_ref_cast_promote : $@convention(thin) (@in AnyObject) -> @out AClass { |
| bb0(%0 : $*AClass, %1 : $*AnyObject): |
| unchecked_ref_cast_addr AnyObject in %1 : $*AnyObject to AClass in %0 : $*AClass |
| %4 = tuple () |
| return %4 : $() |
| } |
| |
| // Do not promote a ref cast for invalid types. It's a runtime error. |
| // CHECK-LABEL: sil @function_ref_cast_struct |
| // CHECK: unchecked_ref_cast_addr |
| sil @function_ref_cast_struct : $@convention(thin) () -> @owned AnyObject { |
| bb0: |
| %0 = struct $S () |
| %1 = alloc_stack $S |
| store %0 to %1 : $*S |
| %4 = alloc_stack $AnyObject |
| unchecked_ref_cast_addr S in %1 : $*S to AnyObject in %4 : $*AnyObject |
| %6 = load %4 : $*AnyObject |
| dealloc_stack %4 : $*AnyObject |
| dealloc_stack %1 : $*S |
| return %6 : $AnyObject |
| } |
| |
| // CHECK-LABEL: sil @destroy_source_of_removed_cast |
| // CHECK: destroy_addr %0 |
| sil @destroy_source_of_removed_cast : $@convention(thin) (@in AnyObject) -> () { |
| bb0(%0 : $*AnyObject): |
| %2 = alloc_stack $Int |
| unconditional_checked_cast_addr AnyObject in %0 : $*AnyObject to Int in %2 : $*Int |
| %3 = load %2 : $*Int |
| dealloc_stack %2 : $*Int |
| %r = tuple () |
| return %r : $() |
| } |
| |
| protocol P {} |
| |
| // CHECK-LABEL: sil @remove_dead_checked_cast |
| // CHECK: bb0(%0 : $*AnyObject): |
| // CHECK-NEXT: alloc_stack |
| // CHECK-NEXT: destroy_addr %0 |
| // CHECK-NEXT: dealloc_stack |
| // CHECK-NEXT: tuple |
| // CHECK-NEXT: return |
| sil @remove_dead_checked_cast : $@convention(thin) (@in AnyObject) -> () { |
| bb0(%0 : $*AnyObject): |
| %5 = alloc_stack $P |
| unconditional_checked_cast_addr AnyObject in %0 : $*AnyObject to P in %5 : $*P |
| destroy_addr %5 : $*P |
| dealloc_stack %5 : $*P |
| %r = tuple () |
| return %r : $() |
| } |
| |
| // CHECK-LABEL: sil @testIOU |
| // CHECK: bb0(%0 : $*Optional<AnyObject>, %1 : $*Optional<AnyObject>): |
| // CHECK: [[TMP:%.*]] = load %1 : $*Optional<AnyObject> |
| // CHECK: store [[TMP]] to %0 : $*Optional<AnyObject> |
| sil @testIOU : $@convention(thin) (@in Optional<AnyObject>) -> (@out Optional<AnyObject>) { |
| bb0(%0 : $*Optional<AnyObject>, %1: $*Optional<AnyObject>): |
| unconditional_checked_cast_addr ImplicitlyUnwrappedOptional<AnyObject> in %1 : $*Optional<AnyObject> to Optional<AnyObject> in %0 : $*Optional<AnyObject> |
| %2 = tuple () |
| return %2 : $() |
| } |