mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
SIL type lowering erases DynamicSelfType, so we generate incorrect code when casting to DynamicSelfType. Fixing this requires a fair amount of plumbing, but most of the changes are mechanical. Note that the textual SIL syntax for casts has changed slightly; the target type is now a formal type without a '$', not a SIL type. Also, the unconditional_checked_cast_value and checked_cast_value_br instructions now take the _source_ formal type as well, just like the *_addr forms they are intended to replace.
152 lines
5.5 KiB
Plaintext
152 lines
5.5 KiB
Plaintext
// RUN: %target-sil-opt -enable-objc-interop -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 : $()
|
|
}
|