@@ -130,15 +130,27 @@ private struct FunctionChecker {
130130 throw Diagnostic ( . embedded_swift_allocating_type, ( instruction as! SingleValueInstruction ) . type,
131131 at: instruction. location)
132132 }
133- case is BeginApplyInst :
134- throw Diagnostic ( . embedded_swift_allocating_coroutine, at: instruction. location)
133+
135134 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)
137144
138145 case let pai as PartialApplyInst :
139146 if context. options. noAllocations && !pai. isOnStack {
140147 throw Diagnostic ( . embedded_swift_allocating_closure, at: instruction. location)
141148 }
149+ try checkApply ( apply: pai)
150+
151+ // Remaining apply instructions
152+ case let apply as ApplySite :
153+ try checkApply ( apply: apply)
142154
143155 case let bi as BuiltinInst :
144156 switch bi. id {
@@ -156,39 +168,45 @@ private struct FunctionChecker {
156168 break
157169 }
158170
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+ }
163175
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+ }
178180
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)
188198 }
199+ }
189200
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 ( )
192210 }
193211 }
194212
@@ -355,6 +373,15 @@ private extension ApplySite {
355373 }
356374 return false
357375 }
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+ }
358385}
359386
360387private extension Type {
0 commit comments