From d497e650b521a5571d9f6cb5402b85583ae828b0 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Thu, 18 Dec 2025 15:32:35 -0500 Subject: [PATCH] SILGen: Fix assert when emitting re-abstraction thunk in edge case involving opaque return type If we can see the underlying type of an opaque return type, and this underlying type does not depend on the opaque return type's generic signature, then we can end up in a situation where the lowered type of a re-abstraction thunk is not generic, but the formal type is. This would trigger an assertion failure. Check both the lowered type and formal type for type parameters to cope with this. - Fixes https://github.com/swiftlang/swift/issues/86118. --- lib/SIL/IR/SILFunctionType.cpp | 4 +++- test/SILGen/opaque_result_type_thunk.swift | 19 +++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 test/SILGen/opaque_result_type_thunk.swift diff --git a/lib/SIL/IR/SILFunctionType.cpp b/lib/SIL/IR/SILFunctionType.cpp index 83400b833e382..468ede36a1d20 100644 --- a/lib/SIL/IR/SILFunctionType.cpp +++ b/lib/SIL/IR/SILFunctionType.cpp @@ -3605,7 +3605,9 @@ CanSILFunctionType swift::buildSILFunctionThunkType( if (!capturedEnvs.empty() || expectedType->hasPrimaryArchetype() || - sourceType->hasPrimaryArchetype()) { + sourceType->hasPrimaryArchetype() || + (inputSubstType && inputSubstType->hasPrimaryArchetype()) || + (outputSubstType && outputSubstType->hasPrimaryArchetype())) { // Get the existing generic signature. baseGenericSig = fn->getLoweredFunctionType() ->getInvocationGenericSignature(); diff --git a/test/SILGen/opaque_result_type_thunk.swift b/test/SILGen/opaque_result_type_thunk.swift new file mode 100644 index 0000000000000..dfacbabb2dd34 --- /dev/null +++ b/test/SILGen/opaque_result_type_thunk.swift @@ -0,0 +1,19 @@ +// RUN: %target-swift-emit-silgen %s + +// https://github.com/swiftlang/swift/issues/86118 + +// The AST type of the thunk depends on the generic signature, but the +// lowered type does not, because we can see the opaque return type's +// underlying type from the expansion point, and it does not involve +// type parameters. Make sure this does not cause us to assert. + +public struct G { + public static func f(_: Any, _: Any) -> some Any { + return 123 + } +} + +public func g(_: T) { + let fn: (Any, Any) -> _ = G.f + let fn2: (Int, Int) -> _ = fn +}