Skip to content

Commit 8a892f2

Browse files
authored
Merge pull request #29989 from atrick/fix-existential-generic
Disable ExistentialSpecializer on generic functions.
2 parents 4609b1c + b38ca0c commit 8a892f2

File tree

3 files changed

+89
-25
lines changed

3 files changed

+89
-25
lines changed

lib/SILOptimizer/FunctionSignatureTransforms/ExistentialSpecializer.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,16 @@ bool ExistentialSpecializer::canSpecializeCalleeFunction(FullApplySite &Apply) {
227227
if (Callee->hasOwnership())
228228
return false;
229229

230+
// Ignore generic functions. Generic functions should be fully specialized
231+
// before attempting to introduce new generic parameters for existential
232+
// arguments. Otherwise, there's no guarantee that the generic specializer
233+
// will be able to specialize the new generic parameter created by this pass.
234+
//
235+
// Enabling this would require additional implementation work to correctly
236+
// substitute the original archetypes into the new generic signature.
237+
if (Callee->getLoweredFunctionType()->getSubstGenericSignature())
238+
return false;
239+
230240
/// Ignore functions with indirect results.
231241
if (Callee->getConventions().hasIndirectSILResults())
232242
return false;

test/SILOptimizer/existential_specializer_soletype.sil

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -381,3 +381,66 @@ bb0(%0 : $S, %1 : $*P):
381381
return %15 : $()
382382
}
383383

384+
//===----------------------------------------------------------------------===//
385+
// Test an existential with a generic constraint
386+
// rdar://56923071; [SR-11714]: Compiler crash when generic class is passed as
387+
// a parameter to a function accepting a generic class
388+
//
389+
// Allowing this results in the error:
390+
// SIL verification failed: Operand is of an ArchetypeType that does not exist
391+
// in the Caller's generic param list.: isArchetypeValidInFunction(A, F)
392+
//
393+
// This could be fixed by preserving the original function's
394+
// archetypes when rewriting the generic signature. However, the
395+
// ExistentialSpecializer should not specialize generic functions in
396+
// the first place because, without partial specialization, there's no
397+
// guarantee that the new generic form will be able to be
398+
// specialized. Preferably, all other generic parameters will be
399+
// specialized first before attempting to specialize the existential.
400+
//===----------------------------------------------------------------------===//
401+
402+
public class ClassA<T> { }
403+
404+
public protocol ProtocolA {
405+
func foo() -> Int
406+
}
407+
408+
public class ClassB<T> : ClassA<T> {
409+
public func foo() -> Int
410+
override init()
411+
}
412+
413+
extension ClassB : ProtocolA {}
414+
415+
// Pass an existential argument that happens to also have a generic constraint.
416+
//
417+
// CHECK-LABEL: sil @testExistentialGenericConstraint : $@convention(thin) <T> (@guaranteed ClassB<T>) -> Int {
418+
// CHECK: [[E:%.*]] = init_existential_ref %0 : $ClassB<T> : $ClassB<T>, $ClassA<T> & ProtocolA
419+
// CHECK: [[F:%.*]] = function_ref @testExistentialGenericConstraintHelper : $@convention(thin) <τ_0_0> (@guaranteed ClassA<τ_0_0> & ProtocolA) -> Int
420+
// CHECK: apply [[F]]<T>([[E]]) : $@convention(thin) <τ_0_0> (@guaranteed ClassA<τ_0_0> & ProtocolA) -> Int
421+
// CHECK-LABEL: } // end sil function 'testExistentialGenericConstraint'
422+
sil @testExistentialGenericConstraint : $@convention(thin) <T> (@guaranteed ClassB<T>) -> Int {
423+
bb0(%0 : $ClassB<T>):
424+
strong_retain %0 : $ClassB<T>
425+
%3 = init_existential_ref %0 : $ClassB<T> : $ClassB<T>, $ClassA<T> & ProtocolA
426+
%4 = function_ref @testExistentialGenericConstraintHelper : $@convention(thin) <τ_0_0> (@guaranteed ClassA<τ_0_0> & ProtocolA) -> Int
427+
%5 = apply %4<T>(%3) : $@convention(thin) <τ_0_0> (@guaranteed ClassA<τ_0_0> & ProtocolA) -> Int
428+
strong_release %3 : $ClassA<T> & ProtocolA
429+
return %5 : $Int
430+
}
431+
432+
// This generic function should not be "specialized" by ExistentialSpecializer, which would add more generic parameters.
433+
//
434+
// CHECK-LABEL: sil hidden @testExistentialGenericConstraintHelper : $@convention(thin) <T> (@guaranteed ClassA<T> & ProtocolA) -> Int {
435+
// CHECK: bb0(%0 : $ClassA<T> & ProtocolA):
436+
// CHECK-LABEL: } // end sil function 'testExistentialGenericConstraintHelper'
437+
sil hidden @testExistentialGenericConstraintHelper : $@convention(thin) <T> (@guaranteed ClassA<T> & ProtocolA) -> Int {
438+
bb0(%0 : $ClassA<T> & ProtocolA):
439+
%2 = open_existential_ref %0 : $ClassA<T> & ProtocolA to $@opened("92C29DA8-5479-11EA-8668-ACDE48001122") ClassA<T> & ProtocolA
440+
%3 = alloc_stack $@opened("92C29DA8-5479-11EA-8668-ACDE48001122") ClassA<T> & ProtocolA
441+
store %2 to %3 : $*@opened("92C29DA8-5479-11EA-8668-ACDE48001122") ClassA<T> & ProtocolA
442+
%5 = witness_method $@opened("92C29DA8-5479-11EA-8668-ACDE48001122") ClassA<T> & ProtocolA, #ProtocolA.foo!1 : <Self where Self : ProtocolA> (Self) -> () -> Int, %2 : $@opened("92C29DA8-5479-11EA-8668-ACDE48001122") ClassA<T> & ProtocolA : $@convention(witness_method: ProtocolA) <τ_0_0 where τ_0_0 : ProtocolA> (@in_guaranteed τ_0_0) -> Int
443+
%6 = apply %5<@opened("92C29DA8-5479-11EA-8668-ACDE48001122") ClassA<T> & ProtocolA>(%3) : $@convention(witness_method: ProtocolA) <τ_0_0 where τ_0_0 : ProtocolA> (@in_guaranteed τ_0_0) -> Int
444+
dealloc_stack %3 : $*@opened("92C29DA8-5479-11EA-8668-ACDE48001122") ClassA<T> & ProtocolA
445+
return %6 : $Int
446+
}

test/SILOptimizer/existential_transform.swift

Lines changed: 16 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -288,21 +288,17 @@ class GC: GP {
288288
func wrap_gcp<T:GP>(_ a:T,_ b:GP) -> Int {
289289
return a.foo() + b.foo()
290290
}
291+
// For this case to be handled by ExistentialSpecializer, GenericSpecializer needs to run first to remove the generic argument.
292+
//
291293
// CHECK-LABEL: sil hidden [noinline] @$s21existential_transform3gcpySixAA2GPRzlF : $@convention(thin) <T where T : GP> (@in_guaranteed T) -> Int {
292294
// CHECK: bb0(%0 : $*T):
293-
// CHECK: debug_value_addr
294-
// CHECK: alloc_ref
295-
// CHECK: debug_value
296-
// CHECK: debug_value
297-
// CHECK: alloc_stack
298-
// CHECK: init_existential_addr
299-
// CHECK: store
300-
// CHECK: function_ref @$s21existential_transform8wrap_gcpySix_AA2GP_ptAaCRzlFTf4ne_n : $@convention(thin) <τ_0_0 where τ_0_0 : GP><τ_1_0 where τ_1_0 : GP> (@in_guaranteed τ_0_0, @in_guaranteed τ_1_0) -> Int
301-
// CHECK: open_existential_addr
302-
// CHECK: strong_retain
303-
// CHECK: apply
295+
// CHECK: [[REF:%.*]] = alloc_ref
296+
// CHECK: [[E:%.*]] = alloc_stack
297+
// CHECK: [[EADR:%.*]] = init_existential_addr [[E]]
298+
// CHECK: store [[REF]] to [[EADR]]
299+
// CHECK: [[F:%.*]] = function_ref @$s21existential_transform8wrap_gcpySix_AA2GP_ptAaCRzlF : $@convention(thin) <τ_0_0 where τ_0_0 : GP> (@in_guaranteed τ_0_0, @in_guaranteed GP) -> Int
300+
// CHECK: apply [[F]]<T>(%0, [[E]]) : $@convention(thin) <τ_0_0 where τ_0_0 : GP> (@in_guaranteed τ_0_0, @in_guaranteed GP) -> Int
304301
// CHECK: destroy_addr
305-
// CHECK: strong_release
306302
// CHECK: dealloc_stack
307303
// CHECK: return
308304
// CHECK: } // end sil function '$s21existential_transform3gcpySixAA2GPRzlF'
@@ -314,22 +310,17 @@ func wrap_gcp<T:GP>(_ a:T,_ b:GP) -> Int {
314310
func wrap_gcp_arch<T:GP>(_ a:T,_ b:GP, _ c:inout Array<T>) -> Int {
315311
return a.foo() + b.foo() + c[0].foo()
316312
}
313+
// For this case to be handled by ExistentialSpecializer, GenericSpecializer needs to run first to remove the generic argument.
314+
//
317315
// CHECK-LABEL: sil hidden [noinline] @$s21existential_transform8gcp_archySix_SayxGztAA2GPRzlF : $@convention(thin) <T where T : GP> (@in_guaranteed T, @inout Array<T>) -> Int {
318316
// CHECK: bb0(%0 : $*T, %1 : $*Array<T>):
319-
// CHECK: debug_value_addr
320-
// CHECK: debug_value_addr
321-
// CHECK: alloc_ref
322-
// CHECK: debug_value
323-
// CHECK: debug_value
324-
// CHECK: alloc_stack
325-
// CHECK: init_existential_addr
326-
// CHECK: store
327-
// CHECK: function_ref @$s21existential_transform13wrap_gcp_archySix_AA2GP_pSayxGztAaCRzlFTf4nen_n : $@convention(thin) <τ_0_0 where τ_0_0 : GP><τ_1_0 where τ_1_0 : GP> (@in_guaranteed τ_0_0, @in_guaranteed τ_1_0, @inout Array<τ_0_0>) -> Int
328-
// CHECK: open_existential_addr
329-
// CHECK: strong_retain
330-
// CHECK: apply
317+
// CHECK: [[REF:%.*]] = alloc_ref
318+
// CHECK: [[E:%.*]] = alloc_stack
319+
// CHECK: [[EADR:%.*]] = init_existential_addr [[E]]
320+
// CHECK: store [[REF]] to [[EADR]]
321+
// CHECK: [[F:%.*]] = function_ref @$s21existential_transform13wrap_gcp_archySix_AA2GP_pSayxGztAaCRzlF : $@convention(thin) <τ_0_0 where τ_0_0 : GP> (@in_guaranteed τ_0_0, @in_guaranteed GP, @inout Array<τ_0_0>) -> Int
322+
// CHECK: apply [[F]]<T>(%0, [[E]], %1) : $@convention(thin) <τ_0_0 where τ_0_0 : GP> (@in_guaranteed τ_0_0, @in_guaranteed GP, @inout Array<τ_0_0>) -> Int
331323
// CHECK: destroy_addr
332-
// CHECK: strong_release
333324
// CHECK: dealloc_stack
334325
// CHECK: return
335326
// CHECK-LABEL: } // end sil function '$s21existential_transform8gcp_archySix_SayxGztAA2GPRzlF'

0 commit comments

Comments
 (0)