mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Fixes rdar://133393259 (Swift CI: test: Interpreter/convenience_init_peer_delegation.swift)
216 lines
6.6 KiB
Swift
216 lines
6.6 KiB
Swift
// RUN: %empty-directory(%t)
|
|
//
|
|
// RUN: %target-build-swift %s -o %t/main
|
|
// RUN: %target-codesign %t/main
|
|
// RUN: %target-run %t/main | %FileCheck %s
|
|
|
|
// RUN: %empty-directory(%t)
|
|
//
|
|
// RUN: sed -e 's/required//g' < %s > %t/without_required.swift
|
|
// RUN: %target-build-swift %t/without_required.swift -o %t/without_required
|
|
// RUN: %target-codesign %t/without_required
|
|
// RUN: %target-run %t/without_required | %FileCheck %s
|
|
|
|
// RUN: %empty-directory(%t)
|
|
//
|
|
// RUN: %target-build-swift %s -o %t/main -swift-version 5
|
|
// RUN: %target-codesign %t/main
|
|
// RUN: %target-run %t/main | %FileCheck %s
|
|
|
|
// RUN: %empty-directory(%t)
|
|
//
|
|
// RUN: sed -e 's/required//g' < %s > %t/without_required.swift
|
|
// RUN: %target-build-swift %t/without_required.swift -o %t/without_required -swift-version 5
|
|
// RUN: %target-codesign %t/without_required
|
|
// RUN: %target-run %t/without_required | %FileCheck %s
|
|
|
|
// REQUIRES: executable_test
|
|
// REQUIRES: objc_interop
|
|
// REQUIRES: foundation
|
|
// XFAIL: CPU=arm64e
|
|
|
|
// Because of the use of 'sed' in this test.
|
|
// REQUIRES: shell
|
|
|
|
import Darwin
|
|
import Foundation
|
|
|
|
class Base {
|
|
init(swift: ()) {
|
|
print("\(#function) \(type(of: self))")
|
|
}
|
|
@objc(initAsObjC) required init(objc: ()) {
|
|
print("\(#function) \(type(of: self))")
|
|
}
|
|
|
|
convenience init(swiftToSwift: ()) {
|
|
print("\(#function) \(type(of: self))")
|
|
self.init(swift: ())
|
|
}
|
|
@objc convenience required init(objcToSwift: ()) {
|
|
print("\(#function) \(type(of: self))")
|
|
self.init(swift: ())
|
|
}
|
|
convenience init(swiftToObjC: ()) {
|
|
print("\(#function) \(type(of: self))")
|
|
self.init(objc: ())
|
|
}
|
|
@objc convenience required init(objcToObjC: ()) {
|
|
print("\(#function) \(type(of: self))")
|
|
self.init(objc: ())
|
|
}
|
|
|
|
convenience init(swiftToSwiftConvenience: ()) {
|
|
print("\(#function) \(type(of: self))")
|
|
self.init(swiftToSwift: ())
|
|
}
|
|
@objc convenience required init(objcToSwiftConvenience: ()) {
|
|
print("\(#function) \(type(of: self))")
|
|
self.init(swiftToSwift: ())
|
|
}
|
|
convenience init(swiftToObjCConvenience: ()) {
|
|
print("\(#function) \(type(of: self))")
|
|
self.init(objcToObjC: ())
|
|
}
|
|
@objc convenience required init(objcToObjCConvenience: ()) {
|
|
print("\(#function) \(type(of: self))")
|
|
self.init(objcToObjC: ())
|
|
}
|
|
}
|
|
|
|
class Sub: Base {}
|
|
|
|
@objc protocol ForceObjCDispatch {
|
|
@objc(initAsObjC) init(objc: ())
|
|
init(objcToSwift: ())
|
|
init(objcToObjC: ())
|
|
init(objcToSwiftConvenience: ())
|
|
init(objcToObjCConvenience: ())
|
|
}
|
|
|
|
// Replace swift_allocObject so that we can keep track of what gets allocated.
|
|
var baseCounter = 0
|
|
var subCounter = 0
|
|
|
|
typealias AllocObjectType =
|
|
@convention(c) (UnsafeRawPointer, Int, Int) -> UnsafeMutableRawPointer
|
|
let allocObjectImpl =
|
|
dlsym(UnsafeMutableRawPointer(bitPattern: -1), "_swift_allocObject")
|
|
.assumingMemoryBound(to: AllocObjectType.self)
|
|
|
|
/// Like `ObjectIdentifier.init(Any.Type)`, but with a pointer as the
|
|
/// destination type.
|
|
func asUnsafeRawPointer(_ someClass: AnyObject.Type) -> UnsafeRawPointer {
|
|
let opaque = Unmanaged.passUnretained(someClass as AnyObject).toOpaque()
|
|
return UnsafeRawPointer(opaque)
|
|
}
|
|
|
|
let originalAllocObject = allocObjectImpl.pointee
|
|
allocObjectImpl.pointee = {
|
|
switch $0 {
|
|
case asUnsafeRawPointer(Base.self):
|
|
baseCounter += 1
|
|
case asUnsafeRawPointer(Sub.self):
|
|
subCounter += 1
|
|
default:
|
|
break
|
|
}
|
|
|
|
return originalAllocObject($0, $1, $2)
|
|
}
|
|
|
|
/// Checks that `op` performs `base` allocations of Base and `sub` allocations
|
|
/// of Sub.
|
|
@inline(never)
|
|
func check(base: Int = 0, sub: Int = 0,
|
|
file: StaticString = #file, line: UInt = #line,
|
|
op: () -> AnyObject) {
|
|
baseCounter = 0
|
|
subCounter = 0
|
|
_ = op()
|
|
precondition(baseCounter == base,
|
|
"expected \(base) Base instances, got \(baseCounter)",
|
|
file: file, line: line)
|
|
precondition(subCounter == sub,
|
|
"expected \(sub) Sub instances, got \(subCounter)",
|
|
file: file, line: line)
|
|
}
|
|
|
|
|
|
// Specialization of the 'check' function may result in the closure being deleted, which breaks the test. Disabling
|
|
// optimization of this calling function prevents closure specialization.
|
|
@_optimize(none)
|
|
func main() {
|
|
// CHECK: START
|
|
print("START")
|
|
|
|
// Check that this whole setup works.
|
|
// CHECK-NEXT: init(swift:) Base
|
|
check(base: 1) { Base(swift: ()) }
|
|
// CHECK-NEXT: init(swift:) Sub
|
|
check(sub: 1) { Sub(swift: ()) }
|
|
// CHECK-NEXT: init(objc:) Base
|
|
check(base: 1) { Base(objc: ()) }
|
|
// CHECK-NEXT: init(objc:) Sub
|
|
check(sub: 1) { Sub(objc: ()) }
|
|
|
|
// CHECK-NEXT: init(swiftToSwift:) Sub
|
|
// CHECK-NEXT: init(swift:) Sub
|
|
check(sub: 1) { Sub(swiftToSwift: ()) }
|
|
// CHECK-NEXT: init(objcToSwift:) Sub
|
|
// CHECK-NEXT: init(swift:) Sub
|
|
check(sub: 2) { Sub(objcToSwift: ()) }
|
|
// CHECK-NEXT: init(swiftToObjC:) Sub
|
|
// CHECK-NEXT: init(objc:) Sub
|
|
check(sub: 1) { Sub(swiftToObjC: ()) }
|
|
// CHECK-NEXT: init(objcToObjC:) Sub
|
|
// CHECK-NEXT: init(objc:) Sub
|
|
check(sub: 1) { Sub(objcToObjC: ()) }
|
|
|
|
// CHECK-NEXT: init(swiftToSwiftConvenience:) Sub
|
|
// CHECK-NEXT: init(swiftToSwift:) Sub
|
|
// CHECK-NEXT: init(swift:) Sub
|
|
check(sub: 1) { Sub(swiftToSwiftConvenience: ()) }
|
|
// CHECK-NEXT: init(objcToSwiftConvenience:) Sub
|
|
// CHECK-NEXT: init(swiftToSwift:) Sub
|
|
// CHECK-NEXT: init(swift:) Sub
|
|
check(sub: 2) { Sub(objcToSwiftConvenience: ()) }
|
|
// CHECK-NEXT: init(swiftToObjCConvenience:) Sub
|
|
// CHECK-NEXT: init(objcToObjC:) Sub
|
|
// CHECK-NEXT: init(objc:) Sub
|
|
check(sub: 1) { Sub(swiftToObjCConvenience: ()) }
|
|
// CHECK-NEXT: init(objcToObjCConvenience:) Sub
|
|
// CHECK-NEXT: init(objcToObjC:) Sub
|
|
// CHECK-NEXT: init(objc:) Sub
|
|
check(sub: 1) { Sub(objcToObjCConvenience: ()) }
|
|
|
|
// Force ObjC dispatch without conforming Sub or Base to the protocol,
|
|
// because it's possible that `required` perturbs things and we want to test
|
|
// both ways.
|
|
let SubAsObjC = unsafeBitCast(Sub.self as AnyObject,
|
|
to: ForceObjCDispatch.Type.self)
|
|
|
|
// CHECK-NEXT: init(objc:) Sub
|
|
check(sub: 1) { SubAsObjC.init(objc: ()) }
|
|
// CHECK-NEXT: init(objcToSwift:) Sub
|
|
// CHECK-NEXT: init(swift:) Sub
|
|
check(sub: 2) { SubAsObjC.init(objcToSwift: ()) }
|
|
// CHECK-NEXT: init(objcToObjC:) Sub
|
|
// CHECK-NEXT: init(objc:) Sub
|
|
check(sub: 1) { SubAsObjC.init(objcToObjC: ()) }
|
|
// CHECK-NEXT: init(objcToSwiftConvenience:) Sub
|
|
// CHECK-NEXT: init(swiftToSwift:) Sub
|
|
// CHECK-NEXT: init(swift:) Sub
|
|
check(sub: 2) { SubAsObjC.init(objcToSwiftConvenience: ()) }
|
|
// CHECK-NEXT: init(objcToObjCConvenience:) Sub
|
|
// CHECK-NEXT: init(objcToObjC:) Sub
|
|
// CHECK-NEXT: init(objc:) Sub
|
|
check(sub: 1) { SubAsObjC.init(objcToObjCConvenience: ()) }
|
|
|
|
// CHECK-NEXT: END
|
|
print("END")
|
|
}
|
|
|
|
main()
|
|
|