File: objc_preconcurrency.swift

package info (click to toggle)
swiftlang 6.0.3-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 2,519,992 kB
  • sloc: cpp: 9,107,863; ansic: 2,040,022; asm: 1,135,751; python: 296,500; objc: 82,456; f90: 60,502; lisp: 34,951; pascal: 19,946; sh: 18,133; perl: 7,482; ml: 4,937; javascript: 4,117; makefile: 3,840; awk: 3,535; xml: 914; fortran: 619; cs: 573; ruby: 573
file content (160 lines) | stat: -rw-r--r-- 10,784 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
// RUN: %target-swift-emit-silgen -module-name objc_preconcurrency -sdk %S/Inputs -I %S/Inputs -enable-source-import -import-objc-header %S/Inputs/objc_preconcurrency.h %s -disable-objc-attr-requires-foundation-module | %FileCheck %s

// REQUIRES: objc_interop

@objc protocol P {
  @preconcurrency @objc optional func f(_ completionHandler: @Sendable @escaping () -> Void)
  @preconcurrency var sendyHandler: @Sendable () -> Void { get set }
}

@preconcurrency class OldWorld {
  @preconcurrency var handler: (@Sendable () -> Void)?
  @preconcurrency var mainHandler: (@MainActor () -> Void)?
  @preconcurrency var nonOptionalHandler: @Sendable () -> Void = {}
  @preconcurrency var nonOptionalMainHandler: @MainActor () -> Void = {}
}

// CHECK-LABEL: sil hidden [ossa] @$s19objc_preconcurrency19testDynamicDispatch1p17completionHandleryAA1P_p_yyctF
// CHECK: dynamic_method_br
// CHECK: bb{{[0-9]+}}(%{{[0-9]+}} : $@convention(objc_method) (@convention(block) @Sendable () -> (), @opened
func testDynamicDispatch(p: P, completionHandler: @escaping () -> Void) {
  p.f?(completionHandler)

  // CHECK: dynamic_method_br
  // CHECK: bb{{[0-9]+}}(%{{[0-9]+}} : $@convention(objc_method) (@convention(block) @Sendable () -> (), @opened
  let _ = p.f
}

// CHECK-LABEL: sil hidden [ossa] @$s19objc_preconcurrency21testOptionalVarAccessyySo12NSTouchGrassCF
// CHECK:         unchecked_bitwise_cast {{.*}} : $Optional<@Sendable @callee_guaranteed () -> ()> to $Optional<@callee_guaranteed () -> ()>
// CHECK:       } // end sil function '$s19objc_preconcurrency21testOptionalVarAccessyySo12NSTouchGrassCF'
func testOptionalVarAccess(_ grass: NSTouchGrass) {
  grass.cancellationHandler?()
}

// CHECK-LABEL: sil hidden [ossa] @$s19objc_preconcurrency33testOptionalVarAccessPartialApplyyyycSgSo12NSTouchGrassCF
// CHECK:         unchecked_bitwise_cast {{.*}} : $Optional<@Sendable @callee_guaranteed () -> ()> to $Optional<@callee_guaranteed () -> ()>
// CHECK: } // end sil function '$s19objc_preconcurrency33testOptionalVarAccessPartialApplyyyycSgSo12NSTouchGrassCF'
func testOptionalVarAccessPartialApply(_ grass: NSTouchGrass) -> (() -> Void)? {
  let handler = grass.cancellationHandler
  if let unwrapped = handler {
    unwrapped()
  }
  return handler
}

// CHECK-LABEL: sil hidden [ossa] @$s19objc_preconcurrency16testObjCVarWriteyySo12NSTouchGrassCF
// CHECK:         unchecked_bitwise_cast {{.*}} : $Optional<@callee_guaranteed () -> ()> to $Optional<@Sendable @callee_guaranteed () -> ()>
// CHECK:         objc_method {{.*}} : $NSTouchGrass, #NSTouchGrass.cancellationHandler!setter.foreign : (NSTouchGrass) -> ((@Sendable () -> ())?) -> (), $@convention(objc_method) (Optional<@convention(block) @Sendable () -> ()>, NSTouchGrass) -> ()
// CHECK:       } // end sil function '$s19objc_preconcurrency16testObjCVarWriteyySo12NSTouchGrassCF'
func testObjCVarWrite(_ grass: NSTouchGrass) {
  grass.cancellationHandler = {}
}

// the below looks kinda long and wonky, but is expected. for a summary, the steps are:
// 1. objc to native
// 2. Sendable to non-Sendable (major part of this test)
// 3. non-optional to optional
// 4. from non-Sendable to Sendable (major part of this test)
// 5. from native to objc (which involves unwrapping and rewrapping that optional; kinda silly but optimization will clean it up)
//
// CHECK-LABEL: sil hidden [ossa] @$s19objc_preconcurrency22testObjCVarWriteAcrossyySo12NSTouchGrassCF
// CHECK:         [[GET_EXCEPTION:%[0-9]+]] = objc_method {{.*}} : $NSTouchGrass, #NSTouchGrass.exceptionHandler!getter.foreign
// CHECK:         [[SENDABLE_BLOCK:%[0-9]+]] = apply [[GET_EXCEPTION]]({{.*}}) : $@convention(objc_method) (NSTouchGrass) -> @autoreleased @convention(block) @Sendable () -> ()
//                           << step 1 >>
// CHECK:         [[NATIVE_THUNK:%[0-9]+]] = function_ref @$sIeyBh_Iegh_TR : $@convention(thin) @Sendable (@guaranteed @convention(block) @Sendable () -> ()) -> ()
// CHECK:         [[NATIVE_SENDABLE_EXCEPTION:%[0-9]+]] = partial_apply [callee_guaranteed] [[NATIVE_THUNK]]([[SENDABLE_BLOCK]])
//                           << step 2 >>
// CHECK:         [[NATIVE_EXCEPTION:%[0-9]+]] = convert_function [[NATIVE_SENDABLE_EXCEPTION]] : $@Sendable @callee_guaranteed () -> () to $@callee_guaranteed () -> ()
//                           << step 3 >>
// CHECK:         [[OPTIONAL_NATIVE_EXCEPTION:%[0-9]+]] = enum $Optional<@callee_guaranteed () -> ()>, #Optional.some!enumelt, [[NATIVE_EXCEPTION]] : $@callee_guaranteed () -> ()
//                           << step 4 >>
// CHECK:         = unchecked_bitwise_cast [[OPTIONAL_NATIVE_EXCEPTION]] : $Optional<@callee_guaranteed () -> ()> to $Optional<@Sendable @callee_guaranteed () -> ()>
//                           << step 5 >>
// CHECK:         switch_enum {{.*}} : $Optional<@Sendable @callee_guaranteed () -> ()>
//
// CHECK:         bb1({{.*}} : @owned $@Sendable @callee_guaranteed () -> ()):
// CHECK:           init_block_storage_header {{.*}} : $*@block_storage @Sendable @callee_guaranteed () -> ()
// CHECK:       } // end sil function '$s19objc_preconcurrency22testObjCVarWriteAcrossyySo12NSTouchGrassCF'
func testObjCVarWriteAcross(_ grass: NSTouchGrass) {
  grass.cancellationHandler = grass.exceptionHandler // *slaps roof of assignment* this bad boy can fit so much conversion in it!
}

// CHECK-LABEL: sil hidden [ossa] @$s19objc_preconcurrency25testOptionalAssignSetter1yyAA8OldWorldCF
// CHECK:  unchecked_bitwise_cast {{.*}} : $Optional<@callee_guaranteed () -> ()> to $Optional<@Sendable @callee_guaranteed () -> ()>
// CHECK:  #OldWorld.handler!setter : (OldWorld) -> ((@Sendable () -> ())?) -> ()
// CHECK: } // end sil function '$s19objc_preconcurrency25testOptionalAssignSetter1yyAA8OldWorldCF'
func testOptionalAssignSetter1(_ oldWorld: OldWorld) {
  oldWorld.handler = {}
}

// CHECK-LABEL: sil hidden [ossa] @$s19objc_preconcurrency25testOptionalAssignSetter2yyAA8OldWorldCF
// CHECK:  convert_function {{.*}} : $@callee_guaranteed () -> () to $@Sendable @callee_guaranteed () -> ()
// CHECK:  $OldWorld, #OldWorld.nonOptionalHandler!setter : (OldWorld) -> (@escaping @Sendable () -> ()) -> ()
// CHECK: } // end sil function '$s19objc_preconcurrency25testOptionalAssignSetter2yyAA8OldWorldCF'
func testOptionalAssignSetter2(_ oldWorld: OldWorld) {
  oldWorld.nonOptionalHandler = {}
}

// CHECK-LABEL: sil hidden [ossa] @$s19objc_preconcurrency21testMainHandlerWritesyyAA8OldWorldCF
// CHECK:         = unchecked_bitwise_cast {{.*}} : $Optional<@callee_guaranteed () -> ()> to $Optional<@Sendable @callee_guaranteed () -> ()>
// CHECK:         = unchecked_bitwise_cast {{.*}} : $Optional<@Sendable @callee_guaranteed () -> ()> to $Optional<@callee_guaranteed () -> ()>
// CHECK:       } // end sil function '$s19objc_preconcurrency21testMainHandlerWritesyyAA8OldWorldCF'
func testMainHandlerWrites(_ oldWorld: OldWorld) {
  oldWorld.handler = oldWorld.mainHandler
  oldWorld.mainHandler = oldWorld.handler
}

// CHECK-LABEL: sil hidden [ossa] @$s19objc_preconcurrency32testMainHandlerNonOptionalWritesyyAA8OldWorldCF
// CHECK:         = convert_function {{.*}} : $@callee_guaranteed () -> () to $@Sendable @callee_guaranteed () -> ()
// CHECK:         = convert_function {{.*}} : $@Sendable @callee_guaranteed () -> () to $@callee_guaranteed () -> ()
// CHECK:       } // end sil function '$s19objc_preconcurrency32testMainHandlerNonOptionalWritesyyAA8OldWorldCF'
func testMainHandlerNonOptionalWrites(_ oldWorld: OldWorld) {
  oldWorld.nonOptionalHandler = oldWorld.nonOptionalMainHandler
  oldWorld.nonOptionalMainHandler = oldWorld.nonOptionalHandler
}

// CHECK-LABEL: sil hidden [ossa] @$s19objc_preconcurrency15testMixedWritesyyAA8OldWorldCF
//
//                << sendable conversions should be here >>
// CHECK:         = unchecked_bitwise_cast {{.*}} : $Optional<@Sendable @callee_guaranteed () -> ()> to $Optional<@callee_guaranteed () -> ()>
// CHECK:         = convert_function {{.*}} : $@callee_guaranteed () -> () to $@Sendable @callee_guaranteed () -> ()
//
//                << but main actor type mismatches are accepted by SIL >>
// CHECK:         [[NO_MAIN_ACTOR:%[0-9]+]] = partial_apply {{.*}} : $@convention(thin) (@guaranteed @callee_guaranteed () -> @out ()) -> ()
// CHECK:         [[SETTER:%[0-9]+]] = class_method {{.*}} : $OldWorld, #OldWorld.nonOptionalMainHandler!setter : (OldWorld) -> (@escaping @MainActor () -> ()) -> (), $@convention(method) (@owned @callee_guaranteed () -> (), @guaranteed OldWorld) -> ()
// CHECK:         apply [[SETTER]]([[NO_MAIN_ACTOR]]
// CHECK:       } // end sil function '$s19objc_preconcurrency15testMixedWritesyyAA8OldWorldCF'
func testMixedWrites(_ oldWorld: OldWorld) {
  oldWorld.nonOptionalHandler = oldWorld.handler ?? {}
  oldWorld.nonOptionalMainHandler = oldWorld.mainHandler ?? {}
}

func modify(_ v: inout () -> Void) {
  v = {}
}

// CHECK-LABEL: sil hidden [ossa] @$s19objc_preconcurrency15testInoutAccessyySo12NSTouchGrassCF
// CHECK:         [[BEFORE_MODIFY:%[0-9]+]] = convert_function {{.*}} : $@Sendable @callee_guaranteed () -> () to $@callee_guaranteed () -> ()
// CHECK:         store [[BEFORE_MODIFY]] to [init] [[INOUT_ALLOC:%[0-9]+]] : $*@callee_guaranteed () -> ()
// CHECK:         [[MODIFY_FN:%[0-9]+]] = function_ref @$s19objc_preconcurrency6modifyyyyyczF : $@convention(thin) (@inout @callee_guaranteed () -> ()) -> ()
// CHECK:         = apply [[MODIFY_FN]]([[INOUT_ALLOC]])
// CHECK:         [[AFTER_MODIFY:%[0-9]+]] = load [take] [[INOUT_ALLOC]] : $*@callee_guaranteed () -> ()
// CHECK:         convert_function [[AFTER_MODIFY]] : $@callee_guaranteed () -> () to $@Sendable @callee_guaranteed () -> ()
// CHECK:       } // end sil function '$s19objc_preconcurrency15testInoutAccessyySo12NSTouchGrassCF'
func testInoutAccess(_ grass: NSTouchGrass) {
  modify(&grass.exceptionHandler)
}


// CHECK-LABEL: sil hidden [ossa] @$s19objc_preconcurrency21testProtocolVarAccess1pyAA1P_p_tF
// CHECK:         [[BEFORE_MODIFY:%[0-9]+]] = convert_function {{.*}} : $@Sendable @callee_guaranteed () -> () to $@callee_guaranteed () -> ()
// CHECK:         store [[BEFORE_MODIFY]] to [init] [[INOUT_ALLOC:%[0-9]+]] : $*@callee_guaranteed () -> ()
// CHECK:         [[MODIFY_FN:%[0-9]+]] = function_ref @$s19objc_preconcurrency6modifyyyyyczF : $@convention(thin) (@inout @callee_guaranteed () -> ()) -> ()
// CHECK:         = apply [[MODIFY_FN]]([[INOUT_ALLOC]])
// CHECK:         [[AFTER_MODIFY:%[0-9]+]] = load [take] [[INOUT_ALLOC]] : $*@callee_guaranteed () -> ()
// CHECK:         convert_function [[AFTER_MODIFY]] : $@callee_guaranteed () -> () to $@Sendable @callee_guaranteed () -> ()
// CHECK:       } // end sil function '$s19objc_preconcurrency21testProtocolVarAccess1pyAA1P_p_tF'
func testProtocolVarAccess(p: P) {
  modify(&p.sendyHandler)
}