blob: ef62bdd0aee3b9bcca9070f8092a2225de861abd [file] [log] [blame]
// RUN: %target-swift-emit-silgen -parse-as-library -module-name Swift -parse-stdlib %s | %FileCheck %s
// This test checks specific codegen related to normal arguments being passed at
// +0. Eventually, it should be merged into normal SILGen tests.
/////////////////
// Fake Stdlib //
/////////////////
precedencegroup AssignmentPrecedence {
assignment: true
}
public protocol ExpressibleByNilLiteral {
init(nilLiteral: ())
}
protocol IteratorProtocol {
associatedtype Element
mutating func next() -> Element?
}
protocol Sequence {
associatedtype Element
associatedtype Iterator : IteratorProtocol where Iterator.Element == Element
func makeIterator() -> Iterator
}
enum Optional<T> {
case none
case some(T)
}
extension Optional : ExpressibleByNilLiteral {
public init(nilLiteral: ()) {
self = .none
}
}
func _diagnoseUnexpectedNilOptional(_filenameStart: Builtin.RawPointer,
_filenameLength: Builtin.Word,
_filenameIsASCII: Builtin.Int1,
_line: Builtin.Word) {
// This would usually contain an assert, but we don't need one since we are
// just emitting SILGen.
}
class Klass {
init() {}
}
struct Buffer {
var k: Klass
init(inK: Klass) {
k = inK
}
}
public typealias AnyObject = Builtin.AnyObject
protocol Protocol {
associatedtype AssocType
static func useInput(_ input: Builtin.Int32, into processInput: (AssocType) -> ())
}
struct FakeArray<Element> {
// Just to make this type non-trivial
var k: Klass
// We are only interested in this being called. We are not interested in its
// implementation.
mutating func append(_ t: Element) {}
}
struct FakeDictionary<Key, Value> {
}
struct FakeDictionaryIterator<Key, Value> {
var dictionary: FakeDictionary<Key, Value>?
init(_ newDictionary: FakeDictionary<Key, Value>) {
dictionary = newDictionary
}
}
extension FakeDictionaryIterator : IteratorProtocol {
public typealias Element = (Key, Value)
public mutating func next() -> Element? {
return .none
}
}
extension FakeDictionary : Sequence {
public typealias Element = (Key, Value)
public typealias Iterator = FakeDictionaryIterator<Key, Value>
public func makeIterator() -> FakeDictionaryIterator<Key, Value> {
return FakeDictionaryIterator(self)
}
}
public struct Unmanaged<Instance : AnyObject> {
internal unowned(unsafe) var _value: Instance
}
///////////
// Tests //
///////////
class KlassWithBuffer {
var buffer: Buffer
// Make sure that the allocating init forwards into the initializing init at +1.
// CHECK-LABEL: sil hidden [ossa] @$ss15KlassWithBufferC3inKABs0A0C_tcfC : $@convention(method) (@owned Klass, @thick KlassWithBuffer.Type) -> @owned KlassWithBuffer {
// CHECK: bb0([[ARG:%.*]] : @owned $Klass,
// CHECK: [[INITIALIZING_INIT:%.*]] = function_ref @$ss15KlassWithBufferC3inKABs0A0C_tcfc : $@convention(method) (@owned Klass, @owned KlassWithBuffer) -> @owned KlassWithBuffer
// CHECK: apply [[INITIALIZING_INIT]]([[ARG]],
// CHECK: } // end sil function '$ss15KlassWithBufferC3inKABs0A0C_tcfC'
init(inK: Klass = Klass()) {
buffer = Buffer(inK: inK)
}
// This test makes sure that we:
//
// 1. Are able to propagate a +0 value value buffer.k into a +0 value and that
// we then copy that +0 value into a +1 value, before we begin the epilog and
// then return that value.
// CHECK-LABEL: sil hidden [ossa] @$ss15KlassWithBufferC03getC14AsNativeObjectBoyF : $@convention(method) (@guaranteed KlassWithBuffer) -> @owned Builtin.NativeObject {
// CHECK: bb0([[SELF:%.*]] : @guaranteed $KlassWithBuffer):
// CHECK: [[METHOD:%.*]] = class_method [[SELF]] : $KlassWithBuffer, #KlassWithBuffer.buffer!getter.1
// CHECK: [[BUF:%.*]] = apply [[METHOD]]([[SELF]])
// CHECK: [[BUF_BORROW:%.*]] = begin_borrow [[BUF]]
// CHECK: [[K:%.*]] = struct_extract [[BUF_BORROW]] : $Buffer, #Buffer.k
// CHECK: [[COPIED_K:%.*]] = copy_value [[K]]
// CHECK: end_borrow [[BUF_BORROW]]
// CHECK: [[CASTED_COPIED_K:%.*]] = unchecked_ref_cast [[COPIED_K]]
// CHECK: destroy_value [[BUF]]
// CHECK: return [[CASTED_COPIED_K]]
// CHECK: } // end sil function '$ss15KlassWithBufferC03getC14AsNativeObjectBoyF'
func getBufferAsNativeObject() -> Builtin.NativeObject {
return Builtin.unsafeCastToNativeObject(buffer.k)
}
}
struct StructContainingBridgeObject {
var rawValue: Builtin.BridgeObject
// CHECK-LABEL: sil hidden [ossa] @$ss28StructContainingBridgeObjectV8swiftObjAByXl_tcfC : $@convention(method) (@owned AnyObject, @thin StructContainingBridgeObject.Type) -> @owned StructContainingBridgeObject {
// CHECK: bb0([[ARG:%.*]] : @owned $AnyObject,
// CHECK: [[BORROWED_ARG:%.*]] = begin_borrow [[ARG]]
// CHECK: [[COPIED_ARG:%.*]] = copy_value [[BORROWED_ARG]]
// CHECK: [[CASTED_ARG:%.*]] = unchecked_ref_cast [[COPIED_ARG]] : $AnyObject to $Builtin.BridgeObject
// CHECK: assign [[CASTED_ARG]] to
// CHECK: } // end sil function '$ss28StructContainingBridgeObjectV8swiftObjAByXl_tcfC'
init(swiftObj: AnyObject) {
rawValue = Builtin.reinterpretCast(swiftObj)
}
}
struct ReabstractionThunkTest : Protocol {
typealias AssocType = Builtin.Int32
static func useInput(_ input: Builtin.Int32, into processInput: (AssocType) -> ()) {
processInput(input)
}
}
// Make sure that we provide a cleanup to x properly before we pass it to
// result.
extension FakeDictionary {
// CHECK-LABEL: sil hidden [ossa] @$ss14FakeDictionaryV20makeSureToCopyTuplesyyF : $@convention(method) <Key, Value> (FakeDictionary<Key, Value>) -> () {
// CHECK: [[X:%.*]] = alloc_stack $(Key, Value), let, name "x"
// CHECK: [[INDUCTION_VAR:%.*]] = unchecked_take_enum_data_addr {{%.*}} : $*Optional<(Key, Value)>, #Optional.some!enumelt.1
// CHECK: [[INDUCTION_VAR_0:%.*]] = tuple_element_addr [[INDUCTION_VAR]] : $*(Key, Value), 0
// CHECK: [[INDUCTION_VAR_1:%.*]] = tuple_element_addr [[INDUCTION_VAR]] : $*(Key, Value), 1
// CHECK: [[X_0:%.*]] = tuple_element_addr [[X]] : $*(Key, Value), 0
// CHECK: [[X_1:%.*]] = tuple_element_addr [[X]] : $*(Key, Value), 1
// CHECK: copy_addr [take] [[INDUCTION_VAR_0]] to [initialization] [[X_0]]
// CHECK: copy_addr [take] [[INDUCTION_VAR_1]] to [initialization] [[X_1]]
// CHECK: [[X_0:%.*]] = tuple_element_addr [[X]] : $*(Key, Value), 0
// CHECK: [[X_1:%.*]] = tuple_element_addr [[X]] : $*(Key, Value), 1
// CHECK: [[TMP_X:%.*]] = alloc_stack $(Key, Value)
// CHECK: [[TMP_X_0:%.*]] = tuple_element_addr [[TMP_X]] : $*(Key, Value), 0
// CHECK: [[TMP_X_1:%.*]] = tuple_element_addr [[TMP_X]] : $*(Key, Value), 1
// CHECK: [[TMP_0:%.*]] = alloc_stack $Key
// CHECK: copy_addr [[X_0]] to [initialization] [[TMP_0]]
// CHECK: copy_addr [take] [[TMP_0]] to [initialization] [[TMP_X_0]]
// CHECK: [[TMP_1:%.*]] = alloc_stack $Value
// CHECK: copy_addr [[X_1]] to [initialization] [[TMP_1]]
// CHECK: copy_addr [take] [[TMP_1]] to [initialization] [[TMP_X_1]]
// CHECK: [[FUNC:%.*]] = function_ref @$ss9FakeArrayV6appendyyxF : $@convention(method) <τ_0_0> (@in_guaranteed τ_0_0, @inout FakeArray<τ_0_0>) -> ()
// CHECK: apply [[FUNC]]<(Key, Value)>([[TMP_X]],
// CHECK: } // end sil function '$ss14FakeDictionaryV20makeSureToCopyTuplesyyF'
func makeSureToCopyTuples() {
var result = FakeArray<Element>(k: Klass())
for x in self {
result.append(x)
}
}
}
extension Unmanaged {
// Just make sure that we do not crash on this.
func unsafeGuaranteedTest<Result>(
_ body: (Instance) -> Result
) -> Result {
let (guaranteedInstance, token) = Builtin.unsafeGuaranteed(_value)
let result = body(guaranteedInstance)
Builtin.unsafeGuaranteedEnd(token)
return result
}
}
// Make sure that we properly forward x into memory and don't crash.
public func forwardIntoMemory(fromNative x: AnyObject, y: Builtin.Word) -> Builtin.BridgeObject {
// y would normally be 0._builtinWordValue. We don't want to define that
// conformance.
let object = Builtin.castToBridgeObject(x, y)
return object
}
public struct StructWithOptionalAddressOnlyField<T> {
public let newValue: T?
}
func useStructWithOptionalAddressOnlyField<T>(t: T) -> StructWithOptionalAddressOnlyField<T> {
return StructWithOptionalAddressOnlyField<T>(newValue: t)
}