From 71eb55a8d2333b6c858673bcd0e55c3e4e9f77a5 Mon Sep 17 00:00:00 2001 From: John McCall Date: Wed, 12 Jun 2024 22:32:54 -0400 Subject: [PATCH] Properly handle `@objc` thunks for generic classes and actors Fixes rdar://129187133 --- lib/SILGen/SILGenBridging.cpp | 19 +++++++++---- test/SILGen/objc_generic_class.swift | 40 ++++++++++++++++++++++++++-- 2 files changed, 52 insertions(+), 7 deletions(-) diff --git a/lib/SILGen/SILGenBridging.cpp b/lib/SILGen/SILGenBridging.cpp index f0f7ba95519a1..2654527ec85f7 100644 --- a/lib/SILGen/SILGenBridging.cpp +++ b/lib/SILGen/SILGenBridging.cpp @@ -1514,7 +1514,7 @@ SILFunction *SILGenFunction::emitNativeAsyncToForeignThunk(SILDeclRef thunk) { .withAsync() .withSendable() .build(); - auto closureTy = objcFnTy->getWithExtInfo(closureExtInfo); + auto closureTy = objcInfo.SILFnType->getWithExtInfo(closureExtInfo); SmallString<64> closureName(F.getName().begin(), F.getName().end()); // Trim off the thunk suffix and mangle this like a closure nested inside the @@ -1535,7 +1535,7 @@ SILFunction *SILGenFunction::emitNativeAsyncToForeignThunk(SILDeclRef thunk) { IsNotDistributed, IsNotRuntimeAccessible); auto closureRef = B.createFunctionRef(loc, closure); - + auto closureVal = B.createPartialApply(loc, closureRef, subs, closureArgs, ParameterConvention::Direct_Guaranteed); @@ -1575,15 +1575,17 @@ void SILGenFunction::emitNativeToForeignThunk(SILDeclRef thunk) { } } + // Use the same generic environment as the native entry point. + // We need to set this before we can call things like + // F.getForwardingSubstitutionMap(). + F.setGenericEnvironment(SGM.Types.getConstantGenericEnvironment(native)); + auto nativeInfo = getConstantInfo(getTypeExpansionContext(), native); auto subs = F.getForwardingSubstitutionMap(); auto substTy = nativeInfo.SILFnType->substGenericArgs( SGM.M, subs, getTypeExpansionContext()); SILFunctionConventions substConv(substTy, SGM.M); - // Use the same generic environment as the native entry point. - F.setGenericEnvironment(SGM.Types.getConstantGenericEnvironment(native)); - auto loc = thunk.getAsRegularLocation(); loc.markAutoGenerated(); Scope scope(Cleanups, CleanupLocation(loc)); @@ -1848,6 +1850,13 @@ void SILGenFunction::emitNativeToForeignThunk(SILDeclRef thunk) { // The immediate function result is an empty tuple. return SILUndef::get(&F, SGM.Types.getEmptyTupleType()); }; + + // If the function we're calling isn't actually polymorphic, drop the + // substitutions. This should only happen in concrete specializations. + if (subs && !nativeFn->getType().castTo()->isPolymorphic()) { + assert(subs.getGenericSignature()->areAllParamsConcrete()); + subs = SubstitutionMap(); + } if (!substTy->hasErrorResult()) { // Create the apply. diff --git a/test/SILGen/objc_generic_class.swift b/test/SILGen/objc_generic_class.swift index 2c9a00e7a0a90..9d0fcd10013e1 100644 --- a/test/SILGen/objc_generic_class.swift +++ b/test/SILGen/objc_generic_class.swift @@ -1,6 +1,7 @@ -// RUN: %target-swift-emit-silgen -sdk %S/Inputs -I %S/Inputs -enable-source-import %s | %FileCheck %s +// RUN: %target-swift-emit-silgen -sdk %S/Inputs -I %S/Inputs -enable-source-import %s -disable-availability-checking | %FileCheck %s // REQUIRES: objc_interop +// REQUIRES: concurrency import gizmo @@ -11,9 +12,23 @@ import gizmo // CHECK-NOT: sil hidden [ossa] @$sSo7GenericCfd // CHECK-NOT: sil hidden [ossa] @$sSo8NSObjectCfd -class Generic: NSObject { +class Generic: NSObject, ObjCProtocol { var x: Int = 10 + // CHECK-LABEL: sil private [thunk] [ossa] @$s18objc_generic_class7GenericC5evokeyyFTo : $@convention(objc_method) (Generic) -> () { + // CHECK: [[FN:%.*]] = function_ref @$s18objc_generic_class7GenericC5evokeyyF + // CHECK-NEXT: apply [[FN]] + func evoke() {} + + // CHECK-LABEL: sil private [thunk] [ossa] @$s18objc_generic_class7GenericC10evokeAsyncyyYaFTo : $@convention(objc_method) (@convention(block) () -> (), Generic) -> () { + // CHECK: [[FN:%.*]] = function_ref @$s18objc_generic_class7GenericC10evokeAsyncyyYaFyyYacfU_To + // CHECK-NEXT: partial_apply [callee_guaranteed] [[FN]] + + // CHECK-LABEL: sil shared [thunk] [ossa] @$s18objc_generic_class7GenericC10evokeAsyncyyYaFyyYacfU_To : $@convention(thin) @Sendable @async (@convention(block) () -> (), Generic) -> () + // CHECK: [[FN:%.*]] = function_ref @$s18objc_generic_class7GenericC10evokeAsyncyyYaF : $@convention(method) @async <τ_0_0> (@guaranteed Generic<τ_0_0>) -> () + // CHECK-NEXT: apply [[FN]] + func evokeAsync() async {} + // CHECK-LABEL: sil hidden [ossa] @$s18objc_generic_class7GenericCfD : $@convention(method) (@owned Generic) -> () { // CHECK: bb0({{%.*}} : @owned $Generic): // CHECK: } // end sil function '$s18objc_generic_class7GenericCfD' @@ -33,6 +48,11 @@ class Generic: NSObject { // CHECK-NOT: sil hidden [ossa] @$s18objc_generic_class7GenericCfd // CHECK-NOT: sil hidden [ossa] @$sSo8NSObjectCfd +@objc protocol ObjCProtocol { + func evoke() + func evokeAsync() async +} + // CHECK-LABEL: sil hidden [ossa] @$s18objc_generic_class11SubGeneric1CfD : $@convention(method) (@owned SubGeneric1) -> () { // CHECK: bb0([[SELF:%.*]] : @owned $SubGeneric1): // CHECK: [[SUPER_DEALLOC:%.*]] = objc_super_method [[SELF]] : $SubGeneric1, #Generic.deinit!deallocator.foreign : (Generic) -> () -> (), $@convention(objc_method) <τ_0_0> (Generic<τ_0_0>) -> () @@ -51,3 +71,19 @@ public extension GenericStruct where T == String { @objc public func f() -> String { "hello" } } } + +// rdar://129187133 - handle generic @objc thunks properly +actor GenericActor : SendableObjCProtocol { + // CHECK-LABEL: sil private [thunk] [ossa] @$s18objc_generic_class12GenericActorC10evokeAsyncyyYaFTo : $@convention(objc_method) (@convention(block) () -> (), @sil_isolated GenericActor) -> () + // CHECK: [[FN:%.*]] = function_ref @$s18objc_generic_class12GenericActorC10evokeAsyncyyYaFyyYacfU_To : $@convention(thin) @Sendable @async <τ_0_0> (@convention(block) () -> (), @sil_isolated GenericActor<τ_0_0>) -> () + // CHECK-NEXT: partial_apply [callee_guaranteed] [[FN]] + func evokeAsync() async {} + + // CHECK-LABEL: sil shared [thunk] [ossa] @$s18objc_generic_class12GenericActorC10evokeAsyncyyYaFyyYacfU_To : $@convention(thin) @Sendable @async (@convention(block) () -> (), @sil_isolated GenericActor) -> () + // CHECK: [[FN:%.*]] = function_ref @$s18objc_generic_class12GenericActorC10evokeAsyncyyYaF : $@convention(method) @async <τ_0_0> (@sil_isolated @guaranteed GenericActor<τ_0_0>) -> () + // CHECK-NEXT: apply [[FN]] +} + +@objc protocol SendableObjCProtocol : Sendable { + func evokeAsync() async +}