Files
swift-mirror/test/PrintAsObjC/blocks.swift
Becca Royal-Gordon da07ff577c [PrintAsClang] Warn about unstable decl order
PrintAsClang is supposed to emit declarations in the same order regardless of the compiler’s internal state, but we have repeatedly found that our current criteria are inadequate, resulting in non-functionality-affecting changes to generated header content. Add a diagnostic that’s emitted when this happens soliciting a bug report.

Since there *should* be no cases where the compiler fails to order declarations, this diagnostic is never actually emitted. Instead, we test this change by enabling `-verify` on nearly all PrintAsClang tests to make sure they are unaffected.

This did demonstrate a missing criterion that only mattered in C++ mode: extensions that varied only in their generic signature were not sorted stably. Add a sort criterion for this.
2025-02-14 21:41:36 -08:00

147 lines
7.3 KiB
Swift

// Please keep this file in alphabetical order!
// RUN: %empty-directory(%t)
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -emit-module -o %t %s -disable-objc-attr-requires-foundation-module
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -parse-as-library %t/blocks.swiftmodule -typecheck -verify -emit-objc-header-path %t/blocks.h -import-objc-header %S/../Inputs/empty.h -disable-objc-attr-requires-foundation-module
// RUN: %FileCheck %s < %t/blocks.h
// RUN: %check-in-clang %t/blocks.h
// REQUIRES: objc_interop
import ObjectiveC
typealias MyInt = Int
typealias MyBlockWithEscapingParam = (@escaping () -> ()) -> Int
typealias MyBlockWithNoescapeParam = (() -> ()) -> Int
// Please see related tests in PrintAsObjC/imported-block-typedefs.swift.
// CHECK-LABEL: @interface Callbacks
@objc class Callbacks {
// CHECK-NEXT: - (void (^ _Nonnull)(void))voidBlocks:(void (^ _Nonnull)(void))input SWIFT_WARN_UNUSED_RESULT;
@objc func voidBlocks(_ input: @escaping () -> ()) -> () -> () {
return input
}
// CHECK-NEXT: - (void)manyArguments:(void (^ _Nonnull)(float, float, double, double))input;
@objc func manyArguments(_ input: @escaping (Float, Float, Double, Double) -> ()) {}
// CHECK-NEXT: - (void)blockTakesBlock:(void (^ _Nonnull)(SWIFT_NOESCAPE void (^ _Nonnull)(void)))input;
@objc func blockTakesBlock(_ input: @escaping (() -> ()) -> ()) {}
// CHECK-NEXT: - (void)blockReturnsBlock:(void (^ _Nonnull (^ _Nonnull)(void))(void))input;
@objc func blockReturnsBlock(_ input: @escaping () -> () -> ()) {}
// CHECK-NEXT: - (void)blockTakesAndReturnsBlock:(SWIFT_NOESCAPE uint8_t (^ _Nonnull (^ _Nonnull)(SWIFT_NOESCAPE uint16_t (^ _Nonnull)(int16_t)))(int8_t))input;
@objc func blockTakesAndReturnsBlock(_ input:
((Int16) -> (UInt16)) ->
((Int8) -> (UInt8))) {}
// CHECK-NEXT: - (void)blockTakesTwoBlocksAndReturnsBlock:(SWIFT_NOESCAPE uint8_t (^ _Nonnull (^ _Nonnull)(SWIFT_NOESCAPE uint16_t (^ _Nonnull)(int16_t), SWIFT_NOESCAPE uint32_t (^ _Nonnull)(int32_t)))(int8_t))input;
@objc func blockTakesTwoBlocksAndReturnsBlock(_ input:
((Int16) -> (UInt16),
(Int32) -> (UInt32)) ->
((Int8) -> (UInt8))) {}
// CHECK-NEXT: - (void (^ _Nullable)(NSObject * _Nonnull))returnsBlockWithInput SWIFT_WARN_UNUSED_RESULT;
@objc func returnsBlockWithInput() -> ((NSObject) -> ())? {
return nil
}
// CHECK-NEXT: - (void (^ _Nullable)(NSObject * _Nonnull))returnsBlockWithParenthesizedInput SWIFT_WARN_UNUSED_RESULT;
@objc func returnsBlockWithParenthesizedInput() -> ((NSObject) -> ())? {
return nil
}
// CHECK-NEXT: - (void (^ _Nullable)(NSObject * _Nonnull, NSObject * _Nonnull))returnsBlockWithTwoInputs SWIFT_WARN_UNUSED_RESULT;
@objc func returnsBlockWithTwoInputs() -> ((NSObject, NSObject) -> ())? {
return nil
}
// CHECK-NEXT: - (void)blockWithSimpleTypealias:(NSInteger (^ _Nonnull)(NSInteger))input;
@objc func blockWithSimpleTypealias(_ input: @escaping (MyInt) -> MyInt) {}
// CHECK-NEXT: - (void)namedArguments:(void (^ _Nonnull)(float, float, double, double))input;
@objc func namedArguments(_ input: @escaping (_ f1: Float, _ f2: Float, _ d1: Double, _ d2: Double) -> ()) {}
// CHECK-NEXT: - (void)blockTakesNamedBlock:(void (^ _Nonnull)(SWIFT_NOESCAPE void (^ _Nonnull)(void)))input;
@objc func blockTakesNamedBlock(_ input: @escaping (_ block: () -> ()) -> ()) {}
// CHECK-NEXT: - (void (^ _Nullable)(NSObject * _Nonnull))returnsBlockWithNamedInput SWIFT_WARN_UNUSED_RESULT;
@objc func returnsBlockWithNamedInput() -> ((_ object: NSObject) -> ())? {
return nil
}
// CHECK-NEXT: - (void)blockWithKeyword:(SWIFT_NOESCAPE NSInteger (^ _Nonnull)(NSInteger))_Nullable_;
@objc func blockWithKeyword(_ _Nullable: (_ `class`: Int) -> Int) {}
// CHECK-NEXT: - (NSInteger (* _Nonnull)(NSInteger))functionPointers:(NSInteger (* _Nonnull)(NSInteger))input SWIFT_WARN_UNUSED_RESULT;
@objc func functionPointers(_ input: @escaping @convention(c) (Int) -> Int)
-> @convention(c) (Int) -> Int {
return input
}
// CHECK-NEXT: - (void)blockWithBlockTypealias:(SWIFT_NOESCAPE NSInteger (^ _Nonnull)(void (^ _Nonnull)(void)))block;
@objc func blockWithBlockTypealias(_ block: MyBlockWithEscapingParam) {}
// CHECK-NEXT: - (void)blockWithBlockTypealias2:(NSInteger (^ _Nonnull)(void (^ _Nonnull)(void)))block;
@objc func blockWithBlockTypealias2(_ block: @escaping MyBlockWithEscapingParam) {}
// CHECK-NEXT: - (void)blockWithBlockTypealias3:(SWIFT_NOESCAPE NSInteger (^ _Nonnull)(SWIFT_NOESCAPE void (^ _Nonnull)(void)))block;
@objc func blockWithBlockTypealias3(_ block: MyBlockWithNoescapeParam) {}
// CHECK-NEXT: - (void)blockWithBlockTypealias4:(NSInteger (^ _Nonnull)(SWIFT_NOESCAPE void (^ _Nonnull)(void)))block;
@objc func blockWithBlockTypealias4(_ block: @escaping MyBlockWithNoescapeParam) {}
// CHECK-NEXT: - (void)functionPointerTakesAndReturnsFunctionPointer:(NSInteger (* _Nonnull (^ _Nonnull (* _Nonnull)(NSInteger))(NSInteger))(NSInteger))input;
@objc func functionPointerTakesAndReturnsFunctionPointer(
_ input: @escaping @convention(c) (Int) -> (Int)
-> @convention(c) (Int) -> Int
) {
}
// CHECK-NEXT: - (void (* _Nonnull)(NSInteger (* _Nonnull)(NSInteger, NSInteger)))returnsFunctionPointerThatTakesFunctionPointer SWIFT_WARN_UNUSED_RESULT;
@objc func returnsFunctionPointerThatTakesFunctionPointer() ->
@convention(c) (_ comparator: @convention(c) (_ x: Int, _ y: Int) -> Int) -> Void {
fatalError()
}
// CHECK-NEXT: - (NSInteger (* _Nonnull)(NSInteger))functionPointersWithName:(NSInteger (* _Nonnull)(NSInteger))input SWIFT_WARN_UNUSED_RESULT;
@objc func functionPointersWithName(_ input: @escaping @convention(c) (_ value: Int) -> Int)
-> @convention(c) (_ result: Int) -> Int {
return input
}
// CHECK-NEXT: - (void)blockWithConsumingArgument:(void (^ _Nonnull)(SWIFT_RELEASES_ARGUMENT NSObject * _Nonnull))block;
@objc func blockWithConsumingArgument(_ block: @escaping (__owned NSObject) -> ()) {}
// CHECK-NEXT: @property (nonatomic, copy) NSInteger (^ _Nullable savedBlock)(NSInteger);
@objc var savedBlock: ((Int) -> Int)?
// CHECK-NEXT: @property (nonatomic, copy) NSInteger (^ _Nullable savedBlockWithName)(NSInteger);
@objc var savedBlockWithName: ((_ x: Int) -> Int)?
// CHECK-NEXT: @property (nonatomic) NSInteger (* _Nonnull savedFunctionPointer)(NSInteger);
@objc var savedFunctionPointer: @convention(c) (Int) -> Int = { $0 }
// CHECK-NEXT: @property (nonatomic) NSInteger (* _Nullable savedFunctionPointer2)(NSInteger);
@objc var savedFunctionPointer2: (@convention(c) (Int) -> Int)? = { $0 }
// CHECK-NEXT: @property (nonatomic) NSInteger (* _Nonnull savedFunctionPointerWithName)(NSInteger);
@objc var savedFunctionPointerWithName: @convention(c) (_ x: Int) -> Int = { $0 }
// The following uses a clang keyword as the name.
// CHECK-NEXT: @property (nonatomic, copy, getter=this, setter=setThis:) NSInteger (^ _Nonnull this_)(NSInteger);
@objc var this: (_ block: Int) -> Int = { $0 }
// CHECK-NEXT: @property (nonatomic, getter=class, setter=setClass:) NSInteger (* _Nonnull class_)(NSInteger);
@objc var `class`: @convention(c) (_ function: Int) -> Int = { $0 }
// CHECK-NEXT: init
@objc init() {}
}
// CHECK-NEXT: @end