Skip to content

[6.1] Fix the demangling of sending result types when combined with isolation #78641

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
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
15 changes: 12 additions & 3 deletions docs/ABI/Mangling.rst
Original file line number Diff line number Diff line change
Expand Up @@ -732,10 +732,12 @@ Types
FUNCTION-KIND ::= 'A' // @auto_closure function type (escaping)
FUNCTION-KIND ::= 'E' // function type (noescape)

C-TYPE is mangled according to the Itanium ABI, and prefixed with the length.
Non-ASCII identifiers are preserved as-is; we do not use Punycode.
C-TYPE ::= NATURAL CHAR* // raw Itanium mangling

function-signature ::= params-type params-type async? sendable? throws? differentiable? function-isolation? // results and parameters
function-signature ::= result-type params-type async? sendable? throws? differentiable? function-isolation? sending-result? // results and parameters

result-type ::= type
result-type ::= empty-list // shortcut for ()

params-type ::= type 'z'? 'h'? // tuple in case of multiple parameters or a single parameter with a single tuple type
// with optional inout convention, shared convention. parameters don't have labels,
Expand All @@ -751,6 +753,7 @@ Types
#if SWIFT_RUNTIME_VERSION >= 6.0
throws ::= type 'YK' // 'throws(type)' annotation on function types
function-isolation ::= type 'YA' // @isolated(any) on function type
sending-result ::= 'YT' // -> sending T
#endif
differentiable ::= 'Yjf' // @differentiable(_forward) on function type
differentiable ::= 'Yjr' // @differentiable(reverse) on function type
Expand All @@ -762,6 +765,12 @@ Types
// FIXME: Consider replacing 'h' with a two-char code
list-type ::= type identifier? 'Yk'? 'z'? 'h'? 'n'? 'Yi'? 'd'? 'Yt'? // type with optional label, '@noDerivative', inout convention, shared convention, owned convention, actor 'isolated', variadic specifier, and compile-time constant

In the mangling of C function types,``C-TYPE`` is mangled according to the Itanium ABI, prefixed with its length. This resembles the mangling of ``identifier``, but it does not honor substitutions or Punycode.

The 6.0 Swift runtime supports demangling ``sending-result``, but has a bug when it's combined with ``function-isolation``.

::

METATYPE-REPR ::= 't' // Thin metatype representation
METATYPE-REPR ::= 'T' // Thick metatype representation
METATYPE-REPR ::= 'o' // ObjC metatype representation
Expand Down
12 changes: 6 additions & 6 deletions include/swift/Demangling/TypeDecoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -915,6 +915,12 @@ class TypeDecoder {
++firstChildIdx;
}

if (Node->getChild(firstChildIdx)->getKind() ==
NodeKind::SendingResultFunctionType) {
extFlags = extFlags.withSendingResult();
++firstChildIdx;
}

BuiltType globalActorType = BuiltType();
if (Node->getChild(firstChildIdx)->getKind() ==
NodeKind::GlobalActorFunctionType) {
Expand All @@ -937,12 +943,6 @@ class TypeDecoder {
++firstChildIdx;
}

if (Node->getChild(firstChildIdx)->getKind() ==
NodeKind::SendingResultFunctionType) {
extFlags = extFlags.withSendingResult();
++firstChildIdx;
}

FunctionMetadataDifferentiabilityKind diffKind;
if (Node->getChild(firstChildIdx)->getKind() ==
NodeKind::DifferentiableFunctionType) {
Expand Down
37 changes: 32 additions & 5 deletions lib/Demangling/Demangler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1628,24 +1628,51 @@ NodePointer Demangler::demanglePlainFunction() {

NodePointer Demangler::popFunctionType(Node::Kind kind, bool hasClangType) {
NodePointer FuncType = createNode(kind);

// Demangle a C function type if the function node kind says that
// one follows.
NodePointer ClangType = nullptr;
if (hasClangType) {
ClangType = demangleClangType();
}
addChild(FuncType, ClangType);
addChild(FuncType, popNode(Node::Kind::GlobalActorFunctionType));
addChild(FuncType, popNode(Node::Kind::IsolatedAnyFunctionType));

// The components of function-signature. Note that these need to be
// popped in the reverse of the order they're mangled. If you add a
// new component, be sure to add a demangling test case for combinations
// of specifiers.

// sending-result?
addChild(FuncType, popNode(Node::Kind::SendingResultFunctionType));

// function-isolation?
auto isFunctionIsolation = [](Node::Kind kind) {
return kind == Node::Kind::GlobalActorFunctionType ||
kind == Node::Kind::IsolatedAnyFunctionType;
};
addChild(FuncType, popNode(isFunctionIsolation));

// differentiable?
addChild(FuncType, popNode(Node::Kind::DifferentiableFunctionType));

// throws?
addChild(FuncType, popNode([](Node::Kind kind) {
return kind == Node::Kind::ThrowsAnnotation ||
kind == Node::Kind::TypedThrowsAnnotation;
}));

// sendable?
addChild(FuncType, popNode(Node::Kind::ConcurrentFunctionType));

// async?
addChild(FuncType, popNode(Node::Kind::AsyncAnnotation));

// params-type
FuncType = addChild(FuncType, popFunctionParams(Node::Kind::ArgumentTuple));

// result-type
FuncType = addChild(FuncType, popFunctionParams(Node::Kind::ReturnType));

return createType(FuncType);
}

Expand Down Expand Up @@ -1675,15 +1702,15 @@ NodePointer Demangler::popFunctionParamLabels(NodePointer Type) {
return nullptr;

unsigned FirstChildIdx = 0;
if (FuncType->getChild(FirstChildIdx)->getKind() ==
Node::Kind::SendingResultFunctionType)
++FirstChildIdx;
if (FuncType->getChild(FirstChildIdx)->getKind()
== Node::Kind::GlobalActorFunctionType)
++FirstChildIdx;
if (FuncType->getChild(FirstChildIdx)->getKind()
== Node::Kind::IsolatedAnyFunctionType)
++FirstChildIdx;
if (FuncType->getChild(FirstChildIdx)->getKind() ==
Node::Kind::SendingResultFunctionType)
++FirstChildIdx;
if (FuncType->getChild(FirstChildIdx)->getKind()
== Node::Kind::DifferentiableFunctionType)
++FirstChildIdx;
Expand Down
18 changes: 13 additions & 5 deletions lib/Demangling/NodePrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -898,6 +898,18 @@ class NodePrinter {
// handled earlier
++startIndex;
}

// Be sure to check for function signature components in the same
// order that they're added by the demangler, which is the reverse
// of the order that they appear in the mangling grammar.

if (node->getChild(startIndex)->getKind() ==
Node::Kind::SendingResultFunctionType) {
++startIndex;
hasSendingResult = true;
}

// function-isolation; note that these can't actually both appear.
if (node->getChild(startIndex)->getKind()
== Node::Kind::IsolatedAnyFunctionType) {
print(node->getChild(startIndex), depth + 1);
Expand All @@ -908,6 +920,7 @@ class NodePrinter {
print(node->getChild(startIndex), depth + 1);
++startIndex;
}

if (node->getChild(startIndex)->getKind() ==
Node::Kind::DifferentiableFunctionType) {
diffKind =
Expand All @@ -932,11 +945,6 @@ class NodePrinter {
++startIndex;
isAsync = true;
}
if (node->getChild(startIndex)->getKind() ==
Node::Kind::SendingResultFunctionType) {
++startIndex;
hasSendingResult = true;
}

switch (diffKind) {
case MangledDifferentiabilityKind::Forward:
Expand Down
12 changes: 9 additions & 3 deletions stdlib/public/RemoteInspection/TypeRef.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -766,6 +766,15 @@ class DemanglingForTypeRef

auto funcNode = Dem.createNode(kind);

// This needs to use the same order as the demangler.

// TODO: the C function type would go here

if (F->getExtFlags().hasSendingResult()) {
auto node = Dem.createNode(Node::Kind::SendingResultFunctionType);
funcNode->addChild(node, Dem);
}

if (auto globalActor = F->getGlobalActor()) {
auto node = Dem.createNode(Node::Kind::GlobalActorFunctionType);
auto globalActorNode = visit(globalActor);
Expand All @@ -774,9 +783,6 @@ class DemanglingForTypeRef
} else if (F->getExtFlags().isIsolatedAny()) {
auto node = Dem.createNode(Node::Kind::IsolatedAnyFunctionType);
funcNode->addChild(node, Dem);
} else if (F->getExtFlags().hasSendingResult()) {
auto node = Dem.createNode(Node::Kind::SendingResultFunctionType);
funcNode->addChild(node, Dem);
}

if (F->getFlags().isDifferentiable()) {
Expand Down
12 changes: 7 additions & 5 deletions stdlib/public/runtime/Demangle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -741,8 +741,14 @@ swift::_swift_buildDemanglingForMetadata(const Metadata *type,

NodePointer result = Dem.createNode(Node::Kind::ReturnType);
result->addChild(resultTy, Dem);

auto funcNode = Dem.createNode(kind);
// Add the components of the function-signature production in the same
// order that the demangler would.
// TODO: C function type would go here
if (func->getExtendedFlags().hasSendingResult())
funcNode->addChild(Dem.createNode(Node::Kind::SendingResultFunctionType),
Dem);
if (func->hasGlobalActor()) {
auto globalActorTypeNode =
_swift_buildDemanglingForMetadata(func->getGlobalActor(), Dem);
Expand Down Expand Up @@ -798,10 +804,6 @@ swift::_swift_buildDemanglingForMetadata(const Metadata *type,
if (func->isAsync())
funcNode->addChild(Dem.createNode(Node::Kind::AsyncAnnotation), Dem);

if (func->getExtendedFlags().hasSendingResult())
funcNode->addChild(Dem.createNode(Node::Kind::SendingResultFunctionType),
Dem);

funcNode->addChild(parameters, Dem);
funcNode->addChild(result, Dem);
return funcNode;
Expand Down
4 changes: 3 additions & 1 deletion test/Demangle/Inputs/manglings.txt
Original file line number Diff line number Diff line change
Expand Up @@ -465,7 +465,7 @@ $sS3fIedgyywTd_D ---> @escaping @differentiable @callee_guaranteed (@unowned Swi
$sS3fIedgyyTd_D ---> @escaping @differentiable @callee_guaranteed (@unowned Swift.Float, @unowned sending Swift.Float) -> (@unowned Swift.Float)
$s4testA2A5KlassCyYTF ---> test.test() -> sending test.Klass
$s4main5KlassCACYTcMD ---> demangling cache variable for type metadata for (main.Klass) -> sending main.Klass
$s4null19transferAsyncResultAA16NonSendableKlassCyYaYTF ---> null.transferAsyncResult() -> sending null.NonSendableKlass
$s4null19transferAsyncResultAA16NonSendableKlassCyYaYTF ---> null.transferAsyncResult() async -> sending null.NonSendableKlass
$s4null16NonSendableKlassCIegHo_ACs5Error_pIegHTrzo_TR ---> {T:} reabstraction thunk helper from @escaping @callee_guaranteed @async () -> (@owned null.NonSendableKlass) to @escaping @callee_guaranteed @async () -> sending (@out null.NonSendableKlass, @error @owned Swift.Error)
$sSRyxG15Synchronization19AtomicRepresentableABRi_zrlMc ---> protocol conformance descriptor for < where A: ~Swift.Copyable> Swift.UnsafeBufferPointer<A> : Synchronization.AtomicRepresentable in Synchronization
$sSRyxG15Synchronization19AtomicRepresentableABRi0_zrlMc ---> protocol conformance descriptor for < where A: ~Swift.Escapable> Swift.UnsafeBufferPointer<A> : Synchronization.AtomicRepresentable in Synchronization
Expand All @@ -483,3 +483,5 @@ $s4mainAAyyycAA1CCFTTH ---> hop to main actor thunk of main.main(main.C) -> () -

$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