@@ -130,15 +130,27 @@ private struct FunctionChecker {
130
130
throw Diagnostic ( . embedded_swift_allocating_type, ( instruction as! SingleValueInstruction ) . type,
131
131
at: instruction. location)
132
132
}
133
- case is BeginApplyInst :
134
- throw Diagnostic ( . embedded_swift_allocating_coroutine, at: instruction. location)
133
+
135
134
case is ThunkInst :
136
- throw Diagnostic ( . embedded_swift_allocating, at: instruction. location)
135
+ if context. options. noAllocations {
136
+ throw Diagnostic ( . embedded_swift_allocating, at: instruction. location)
137
+ }
138
+
139
+ case let ba as BeginApplyInst :
140
+ if context. options. noAllocations {
141
+ throw Diagnostic ( . embedded_swift_allocating_coroutine, at: instruction. location)
142
+ }
143
+ try checkApply ( apply: ba)
137
144
138
145
case let pai as PartialApplyInst :
139
146
if context. options. noAllocations && !pai. isOnStack {
140
147
throw Diagnostic ( . embedded_swift_allocating_closure, at: instruction. location)
141
148
}
149
+ try checkApply ( apply: pai)
150
+
151
+ // Remaining apply instructions
152
+ case let apply as ApplySite :
153
+ try checkApply ( apply: apply)
142
154
143
155
case let bi as BuiltinInst :
144
156
switch bi. id {
@@ -156,39 +168,45 @@ private struct FunctionChecker {
156
168
break
157
169
}
158
170
159
- case let apply as ApplySite :
160
- if context . options . noAllocations && apply . isAsync {
161
- throw Diagnostic ( . embedded_swift_allocating_type , at : instruction . location )
162
- }
171
+ default :
172
+ break
173
+ }
174
+ }
163
175
164
- if !apply. callee. type. hasValidSignatureForEmbedded,
165
- // Some runtime functions have generic parameters in SIL, which are not used in IRGen.
166
- // Therefore exclude runtime functions at all.
167
- !apply. callsEmbeddedRuntimeFunction
168
- {
169
- switch apply. callee {
170
- case let cmi as ClassMethodInst :
171
- throw Diagnostic ( . embedded_cannot_specialize_class_method, cmi. member, at: instruction. location)
172
- case let wmi as WitnessMethodInst :
173
- throw Diagnostic ( . embedded_cannot_specialize_witness_method, wmi. member, at: instruction. location)
174
- default :
175
- throw Diagnostic ( . embedded_call_generic_function, at: instruction. location)
176
- }
177
- }
176
+ mutating func checkApply( apply: ApplySite ) throws {
177
+ if context. options. noAllocations && apply. isAsync {
178
+ throw Diagnostic ( . embedded_swift_allocating_type, at: apply. location)
179
+ }
178
180
179
- // Although all (non-generic) functions are initially put into the worklist there are two reasons
180
- // to call `checkFunction` recursively:
181
- // * To get a better caller info in the diagnostics.
182
- // * When passing an opened existential to a generic function, it's valid in Embedded swift even if the
183
- // generic is not specialized. We need to check such generic functions, too.
184
- if let callee = apply. referencedFunction {
185
- callStack. push ( CallSite ( apply: apply, callee: callee) )
186
- try checkFunction ( callee)
187
- _ = callStack. pop ( )
181
+ if !apply. callee. type. hasValidSignatureForEmbedded,
182
+ // Some runtime functions have generic parameters in SIL, which are not used in IRGen.
183
+ // Therefore exclude runtime functions at all.
184
+ !apply. callsEmbeddedRuntimeFunction
185
+ {
186
+ switch apply. callee {
187
+ case let cmi as ClassMethodInst :
188
+ throw Diagnostic ( . embedded_cannot_specialize_class_method, cmi. member, at: apply. location)
189
+ case let wmi as WitnessMethodInst :
190
+ throw Diagnostic ( . embedded_cannot_specialize_witness_method, wmi. member, at: apply. location)
191
+ default :
192
+ if apply. substitutionMap. replacementTypes. contains ( where: { $0. hasDynamicSelf } ) ,
193
+ apply. calleeHasGenericSelfMetatypeParameter
194
+ {
195
+ throw Diagnostic ( . embedded_call_generic_function_with_dynamic_self, at: apply. location)
196
+ }
197
+ throw Diagnostic ( . embedded_call_generic_function, at: apply. location)
188
198
}
199
+ }
189
200
190
- default :
191
- break
201
+ // Although all (non-generic) functions are initially put into the worklist there are two reasons
202
+ // to call `checkFunction` recursively:
203
+ // * To get a better caller info in the diagnostics.
204
+ // * When passing an opened existential to a generic function, it's valid in Embedded swift even if the
205
+ // generic is not specialized. We need to check such generic functions, too.
206
+ if let callee = apply. referencedFunction {
207
+ callStack. push ( CallSite ( apply: apply, callee: callee) )
208
+ try checkFunction ( callee)
209
+ _ = callStack. pop ( )
192
210
}
193
211
}
194
212
@@ -355,6 +373,15 @@ private extension ApplySite {
355
373
}
356
374
return false
357
375
}
376
+
377
+ var calleeHasGenericSelfMetatypeParameter : Bool {
378
+ let convention = FunctionConvention ( for: callee. type. canonicalType, in: parentFunction)
379
+ guard convention. hasSelfParameter, let selfParam = convention. parameters. last else {
380
+ return false
381
+ }
382
+ let selfParamType = selfParam. type
383
+ return selfParamType. isMetatype && selfParamType. instanceTypeOfMetatype. isGenericTypeParameter
384
+ }
358
385
}
359
386
360
387
private extension Type {
0 commit comments