SIL: Fix signature of reabstraction thunk involving parameterized existential

Fixes https://github.com/swiftlang/swift/issues/74569
Fixes rdar://problem/130402282
This commit is contained in:
Slava Pestov
2024-08-07 15:09:46 -04:00
parent a142b19de5
commit de16ed8d27
4 changed files with 91 additions and 1 deletions

View File

@@ -136,7 +136,7 @@ GenericSignature swift::buildGenericSignatureWithCapturedEnvironments(
case GenericEnvironment::Kind::OpenedExistential: {
auto constraint = genericEnv->getOpenedExistentialType();
if (auto existential = constraint->getAs<ExistentialType>())
constraint = existential->getConstraintType();
constraint = existential->getConstraintType()->mapTypeOutOfContext();
collector.addOpenedExistential(constraint);
continue;
}

View File

@@ -0,0 +1,15 @@
// RUN: %target-swift-emit-silgen -disable-availability-checking %s | %FileCheck %s
protocol P<A> {
associatedtype A
associatedtype B
var function: () -> B { get }
}
func f<A>(p: any P<A>) {
_ = p.function()
}
// CHECK-LABEL: sil hidden [ossa] @$s40parameterized_existentials_reabstraction1f1pyAA1P_px1ARts_XP_tlF : $@convention(thin) <A> (@in_guaranteed any P<A>) -> () {
// CHECK-LABEL: sil shared [transparent] [serialized] [reabstraction_thunk] [ossa] @$s1B40parameterized_existentials_reabstraction1PPQyd__Iegr_ypIegr_1AQyd__RszAbCRd__r__lTR : $@convention(thin) <τ_0_0><τ_1_0 where τ_0_0 == τ_1_0.A, τ_1_0 : P> (@guaranteed @callee_guaranteed () -> @out τ_1_0.B) -> @out Any {

View File

@@ -0,0 +1,14 @@
// RUN: %target-swift-frontend -emit-ir %s -disable-availability-checking
protocol Cache<Object> {
associatedtype Object
associatedtype Snapshot: Sequence<Object>
func entries(_ body: (Snapshot) -> Void) -> AsyncStream<Object>
}
func readFromCacheImpl<T>(cache: any Cache<T>) async {
let updateStream = cache.entries { _ in }
for await _ in updateStream {}
}

View File

@@ -0,0 +1,61 @@
// RUN: %target-swift-frontend -emit-ir %s -disable-availability-checking
protocol ContextDescriptor: Sendable { }
protocol OutcomeDescriptor: Sendable { }
protocol ResultDescriptor: Sendable { }
protocol ErasedReducer<Context>: Sendable {
associatedtype Context: ContextDescriptor
associatedtype TriggerOutcome: OutcomeDescriptor
associatedtype Result: ResultDescriptor
var name: String { get }
var function: @Sendable (_ context: Context?, _ trigger: TriggerOutcome) -> Result { get }
}
protocol Reducer<Context, TriggerOutcome>: ErasedReducer {
var name: String { get }
var function: @Sendable (_ context: Context?, _ trigger: TriggerOutcome) -> Result { get }
}
struct ExampleContext: ContextDescriptor { }
struct ExampleOutcome: OutcomeDescriptor { }
struct ExampleResult: ResultDescriptor { }
struct ExampleReducer<Context: ContextDescriptor, TriggerOutcome: OutcomeDescriptor, Result: ResultDescriptor>: Reducer {
let name: String
let function: @Sendable (_ context: Context?, _ trigger: TriggerOutcome) -> Result
}
class ExampleService<Context: ContextDescriptor> {
let reducers: [any ErasedReducer<Context>]
public init(reducers: [any ErasedReducer<Context>]) {
self.reducers = reducers
}
func reduce<TriggerOutcome: OutcomeDescriptor>(outcome: TriggerOutcome, context: Context) -> (any ResultDescriptor)? {
// This line appears to be what's causing the crash
guard let reducer = (reducers.compactMap { reducer in reducer as? any Reducer<Context, TriggerOutcome> }).first else {
return nil
}
return reducer.function(context, outcome)
}
}
public func testReducing() {
let erasedReducers: [any ErasedReducer<ExampleContext>] = [
ExampleReducer<ExampleContext, ExampleOutcome, ExampleResult>(name: "Example", function: { (_, _) in ExampleResult() })
]
let context = ExampleContext()
let trigger = ExampleOutcome()
let service = ExampleService<ExampleContext>(reducers: erasedReducers)
_ = service.reduce(outcome: trigger, context: context)
}