Skip to content

[6.1] [rbi] Fix demangling of sending results when demangling impl-function-type #78666

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jan 30, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions docs/ABI/Mangling.rst
Original file line number Diff line number Diff line change
Expand Up @@ -836,7 +836,7 @@ mangled in to disambiguate.
impl-function-type ::= type* 'I' FUNC-ATTRIBUTES '_'
impl-function-type ::= type* generic-signature 'I' FUNC-ATTRIBUTES '_'

FUNC-ATTRIBUTES ::= PATTERN-SUBS? INVOCATION-SUBS? PSEUDO-GENERIC? CALLEE-ESCAPE? ISOLATION? DIFFERENTIABILITY-KIND? CALLEE-CONVENTION FUNC-REPRESENTATION? COROUTINE-KIND? SENDABLE? ASYNC? (PARAM-CONVENTION PARAM-DIFFERENTIABILITY?)* RESULT-CONVENTION* ('Y' PARAM-CONVENTION)* ('z' RESULT-CONVENTION RESULT-DIFFERENTIABILITY?)?
FUNC-ATTRIBUTES ::= PATTERN-SUBS? INVOCATION-SUBS? PSEUDO-GENERIC? CALLEE-ESCAPE? ISOLATION? DIFFERENTIABILITY-KIND? CALLEE-CONVENTION FUNC-REPRESENTATION? COROUTINE-KIND? SENDABLE? ASYNC? SENDING-RESULT? (PARAM-CONVENTION PARAM-DIFFERENTIABILITY?)* RESULT-CONVENTION* ('Y' PARAM-CONVENTION)* ('z' RESULT-CONVENTION RESULT-DIFFERENTIABILITY?)?

PATTERN-SUBS ::= 's' // has pattern substitutions
INVOCATION-SUB ::= 'I' // has invocation substitutions
Expand Down Expand Up @@ -870,8 +870,12 @@ mangled in to disambiguate.
COROUTINE-KIND ::= 'G' // yield-many coroutine

#if SWIFT_RUNTIME_VERSION >= 5.5
SENDABLE ::= 'h' // @Sendable
ASYNC ::= 'H' // @async
SENDABLE ::= 'h' // @Sendable
ASYNC ::= 'H' // @async
#endif

#if SWIFT_RUNTIME_VERSION >= 6.0
SENDING-RESULT ::= 'T' // sending result
#endif

PARAM-CONVENTION ::= 'i' // indirect in
Expand Down
4 changes: 2 additions & 2 deletions include/swift/AST/Types.h
Original file line number Diff line number Diff line change
Expand Up @@ -4789,12 +4789,12 @@ class SILResultInfo {
SILType getSILStorageInterfaceType() const;
/// Return a version of this result info with the type replaced.
SILResultInfo getWithInterfaceType(CanType type) const {
return SILResultInfo(type, getConvention());
return SILResultInfo(type, getConvention(), getOptions());
}

/// Return a version of this result info with the convention replaced.
SILResultInfo getWithConvention(ResultConvention c) const {
return SILResultInfo(getInterfaceType(), c);
return SILResultInfo(getInterfaceType(), c, getOptions());
}

// Does this result convention require indirect storage? This reflects a
Expand Down
7 changes: 7 additions & 0 deletions include/swift/Demangling/TypeDecoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -1093,7 +1093,14 @@ class TypeDecoder {
flags = flags.withSendable();
} else if (child->getText() == "@async") {
flags = flags.withAsync();
} else if (child->getText() == "sending-result") {
flags = flags.withSendingResult();
}
} else if (child->getKind() == NodeKind::ImplSendingResult) {
// NOTE: This flag needs to be set both at the function level and on
// each of the parameters. The flag on the function just means that
// all parameters are sending (which is always true today).
flags = flags.withSendingResult();
} else if (child->getKind() == NodeKind::ImplCoroutineKind) {
if (!child->hasText())
return MAKE_NODE_TYPE_ERROR0(child, "expected text");
Expand Down
4 changes: 4 additions & 0 deletions lib/AST/ASTDemangler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -677,6 +677,10 @@ Type ASTBuilder::createImplFunctionType(
auto type = result.getType()->getCanonicalType();
auto conv = getResultConvention(result.getConvention());
auto options = *getResultOptions(result.getOptions());
// We currently set sending result at the function level, but we set sending
// result on each result.
if (flags.hasSendingResult())
options |= SILResultInfo::IsSending;
funcResults.emplace_back(type, conv, options);
}

Expand Down
17 changes: 13 additions & 4 deletions lib/AST/ASTMangler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2200,6 +2200,19 @@ void ASTMangler::appendImplFunctionType(SILFunctionType *fn,
OpArgs.push_back('H');
}

// Mangle if we have a sending result and we are in a recursive position.
//
// DISCUSSION: We only want sending results to be in the mangling if it is
// being used in a function value passed to a parameter or generic
// position... but not if it is just added to a return type.
//
// E.x.:
//
// func foo() -> sending X // No mangling
// func bar(_ x: () -> sending X) {} // Add to mangling for x
if (isInRecursion && fn->hasSendingResult())
OpArgs.push_back('T');

GenericSignature sig = fn->getSubstGenericSignature();

// Mangle the parameters.
Expand All @@ -2212,10 +2225,6 @@ void ASTMangler::appendImplFunctionType(SILFunctionType *fn,
appendType(param.getInterfaceType(), sig, forDecl);
}

// Mangle if we have a sending result.
if (isInRecursion && fn->hasSendingResult())
OpArgs.push_back('T');

// Mangle the results.
for (auto result : fn->getResults()) {
OpArgs.push_back(getResultConvention(result.getConvention()));
Expand Down
10 changes: 5 additions & 5 deletions lib/Demangling/Demangler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2412,6 +2412,10 @@ NodePointer Demangler::demangleImplFunctionType() {
*this);
}

if (nextIf('T')) {
type->addChild(createNode(Node::Kind::ImplSendingResult), *this);
}

addChild(type, GenSig);

int NumTypesToAdd = 0;
Expand All @@ -2425,10 +2429,6 @@ NodePointer Demangler::demangleImplFunctionType() {
++NumTypesToAdd;
}

if (nextIf('T')) {
type->addChild(createNode(Node::Kind::ImplSendingResult), *this);
}

while (NodePointer Result = demangleImplResultConvention(
Node::Kind::ImplResult)) {
type = addChild(type, Result);
Expand Down Expand Up @@ -2461,7 +2461,7 @@ NodePointer Demangler::demangleImplFunctionType() {
return nullptr;
type->getChild(type->getNumChildren() - Idx - 1)->addChild(ConvTy, *this);
}

return createType(type);
}

Expand Down
6 changes: 3 additions & 3 deletions lib/Demangling/Remangler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2111,9 +2111,9 @@ ManglingError Remangler::mangleImplFunctionType(Node *node, unsigned depth) {
}
case Node::Kind::ImplFunctionAttribute: {
char FuncAttr = llvm::StringSwitch<char>(Child->getText())
.Case("@Sendable", 'h')
.Case("@async", 'H')
.Default(0);
.Case("@Sendable", 'h')
.Case("@async", 'H')
.Default(0);
if (!FuncAttr) {
return MANGLING_ERROR(ManglingError::InvalidImplFunctionAttribute,
Child);
Expand Down
22 changes: 21 additions & 1 deletion test/Concurrency/sending_mangling.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
// RUN: %target-swift-frontend %s -emit-silgen -swift-version 6 | swift-demangle | %FileCheck -check-prefix=CHECK %s
// RUN: %empty-directory(%t)
// RUN: %target-swift-frontend %s -emit-silgen -swift-version 6 | swift-demangle | %FileCheck %s
// RUN: %target-swift-frontend %s -emit-silgen -swift-version 6 | %FileCheck -check-prefix=SIL %s

// REQUIRES: concurrency
// REQUIRES: asserts
Expand Down Expand Up @@ -110,3 +112,21 @@ struct ConstructorSharedTest {
// CHECK: sil hidden [ossa] @sending_mangling.ConstructorSharedTest.functionSuppressed(sending_mangling.NonSendableKlass) -> () : $@convention(method) (@sil_sending @guaranteed NonSendableKlass, ConstructorSharedTest) -> () {
func functionSuppressed(_ x: __shared sending NonSendableKlass) {}
}

// Make sure that we produce the appropriate reabstraction thunk.
func reabstractionThunkTest_takeSendingReturnSending<T>(
_ x: sending T) -> sending T { fatalError() }
func reabstractionThunkTest_reabstractionThunkGenerator<T>(
_ x: sending T,
_ f: (sending T) -> T) {}

// CHECK: sil shared [transparent] [serialized] [reabstraction_thunk] [ossa] @reabstraction thunk helper from @escaping @callee_guaranteed (@in sending sending_mangling.NonSendableKlass) -> sending (@out sending_mangling.NonSendableKlass) to @escaping @callee_guaranteed (@owned sending sending_mangling.NonSendableKlass) -> sending (@owned sending_mangling.NonSendableKlass) : $@convention(thin) (@sil_sending @owned NonSendableKlass, @guaranteed @callee_guaranteed (@sil_sending @in NonSendableKlass) -> @sil_sending @out NonSendableKlass) -> @sil_sending @owned NonSendableKlass {
// SIL: sil shared [transparent] [serialized] [reabstraction_thunk] [ossa] @$s16sending_mangling16NonSendableKlassCACIegTiTr_A2CIegTxTo_TR : $@convention(thin) (@sil_sending @owned NonSendableKlass, @guaranteed @callee_guaranteed (@sil_sending @in NonSendableKlass) -> @sil_sending @out NonSendableKlass) -> @sil_sending @owned NonSendableKlass {

// CHECK: sil shared [transparent] [serialized] [reabstraction_thunk] [ossa] @reabstraction thunk helper from @callee_guaranteed (@owned sending sending_mangling.NonSendableKlass) -> (@owned sending_mangling.NonSendableKlass) to @escaping @callee_guaranteed (@in sending sending_mangling.NonSendableKlass) -> (@out sending_mangling.NonSendableKlass) : $@convention(thin) (@sil_sending @in NonSendableKlass, @guaranteed @noescape @callee_guaranteed (@sil_sending @owned NonSendableKlass) -> @owned NonSendableKlass) -> @out NonSendableKlass {
// SIL: sil shared [transparent] [serialized] [reabstraction_thunk] [ossa] @$s16sending_mangling16NonSendableKlassCACIgxTo_A2CIegiTr_TR : $@convention(thin) (@sil_sending @in NonSendableKlass, @guaranteed @noescape @callee_guaranteed (@sil_sending @owned NonSendableKlass) -> @owned NonSendableKlass) -> @out NonSendableKlass {
func reabstractionThunkTest() {
reabstractionThunkTest_reabstractionThunkGenerator(
NonSendableKlass(),
reabstractionThunkTest_takeSendingReturnSending)
}
2 changes: 2 additions & 0 deletions test/Demangle/Inputs/manglings.txt
Original file line number Diff line number Diff line change
Expand Up @@ -485,3 +485,5 @@ $s4main6VectorVy$1_SiG ---> main.Vector<2, Swift.Int>
$s$n3_SSBV ---> Builtin.FixedArray<-4, Swift.String>
$s3red7MyActorC3runyxxyYaKACYcYTXEYaKlFZ ---> static red.MyActor.run<A>(@red.MyActor () async throws -> sending A) async throws -> A
$s3red7MyActorC3runyxxyYaKYAYTXEYaKlFZ ---> static red.MyActor.run<A>(@isolated(any) () async throws -> sending A) async throws -> A
$s7ToolKit10TypedValueOACs5Error_pIgHTnTrzo_A2CsAD_pIegHiTrzr_TR ---> {T:} reabstraction thunk helper from @callee_guaranteed @async (@in_guaranteed sending ToolKit.TypedValue) -> sending (@out ToolKit.TypedValue, @error @owned Swift.Error) to @escaping @callee_guaranteed @async (@in sending ToolKit.TypedValue) -> (@out ToolKit.TypedValue, @error @out Swift.Error)
$s16sending_mangling16NonSendableKlassCACIegTiTr_A2CIegTxTo_TR ---> {T:} reabstraction thunk helper from @escaping @callee_guaranteed (@in sending sending_mangling.NonSendableKlass) -> sending (@out sending_mangling.NonSendableKlass) to @escaping @callee_guaranteed (@owned sending sending_mangling.NonSendableKlass) -> sending (@owned sending_mangling.NonSendableKlass)