Skip to content

Commit 902c0d3

Browse files
committed
Runtime: Handle symbolic references inside other mangling nodes
Previously we could only handle symbolic references at the top level, but this is insufficient; for example, you can have a nested type X.Y where X is defined in the current translation unit and Y is defined in an extension of X in a different translation unit. In this case, X.Y mangles as a tree where the child contains a symbolic reference to X. Handle this by adding a new form of Demangle::mangleNode() which takes a callback for resolving symbolic references. Fixes <rdar://problem/39613190>.
1 parent 0168fa4 commit 902c0d3

File tree

5 files changed

+67
-10
lines changed

5 files changed

+67
-10
lines changed

include/swift/Demangling/Demangle.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -466,6 +466,14 @@ void mangleIdentifier(const char *data, size_t length,
466466
/// This should always round-trip perfectly with demangleSymbolAsNode.
467467
std::string mangleNode(const NodePointer &root);
468468

469+
using SymbolicResolver = llvm::function_ref<Demangle::NodePointer (const void *)>;
470+
471+
/// \brief Remangle a demangled parse tree, using a callback to resolve
472+
/// symbolic references.
473+
///
474+
/// This should always round-trip perfectly with demangleSymbolAsNode.
475+
std::string mangleNode(const NodePointer &root, SymbolicResolver resolver);
476+
469477
/// Remangle in the old mangling scheme.
470478
///
471479
/// This is only used for objc-runtime names and should be removed as soon as

lib/Demangling/Remangler.cpp

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,9 @@ class Remangler {
152152
// nested generics. This factory owns them.
153153
NodeFactory Factory;
154154

155+
// A callback for resolving symbolic references.
156+
SymbolicResolver Resolver;
157+
155158
StringRef getBufferStr() const { return Buffer.getStringRef(); }
156159

157160
void resetBuffer(size_t toPos) { Buffer.resetSize(toPos); }
@@ -284,7 +287,8 @@ class Remangler {
284287
#include "swift/Demangling/DemangleNodes.def"
285288

286289
public:
287-
Remangler(DemanglerPrinter &Buffer) : Buffer(Buffer) {}
290+
Remangler(DemanglerPrinter &Buffer,
291+
SymbolicResolver Resolver) : Buffer(Buffer), Resolver(Resolver) {}
288292

289293
void mangle(Node *node) {
290294
switch (node->getKind()) {
@@ -1994,18 +1998,25 @@ void Remangler::mangleUnresolvedSymbolicReference(Node *node) {
19941998
}
19951999

19962000
void Remangler::mangleSymbolicReference(Node *node) {
1997-
unreachable("should not try to mangle a symbolic reference; "
1998-
"resolve it to a non-symbolic demangling tree instead");
2001+
return mangle(Resolver((const void *)node->getIndex()));
19992002
}
20002003

20012004
} // anonymous namespace
20022005

20032006
/// The top-level interface to the remangler.
20042007
std::string Demangle::mangleNode(const NodePointer &node) {
2008+
return mangleNode(node, [](const void *) -> NodePointer {
2009+
unreachable("should not try to mangle a symbolic reference; "
2010+
"resolve it to a non-symbolic demangling tree instead");
2011+
});
2012+
}
2013+
2014+
std::string
2015+
Demangle::mangleNode(const NodePointer &node, SymbolicResolver resolver) {
20052016
if (!node) return "";
20062017

20072018
DemanglerPrinter printer;
2008-
Remangler(printer).mangle(node);
2019+
Remangler(printer, resolver).mangle(node);
20092020

20102021
return std::move(printer).str();
20112022
}

stdlib/public/runtime/MetadataLookup.cpp

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,8 @@ _searchTypeMetadataRecords(const TypeMetadataPrivateState &T,
263263
}
264264

265265
static const TypeContextDescriptor *
266-
_findNominalTypeDescriptor(Demangle::NodePointer node) {
266+
_findNominalTypeDescriptor(Demangle::NodePointer node,
267+
Demangle::Demangler &Dem) {
267268
const TypeContextDescriptor *foundNominal = nullptr;
268269
auto &T = TypeMetadataRecords.get();
269270

@@ -275,7 +276,13 @@ _findNominalTypeDescriptor(Demangle::NodePointer node) {
275276
return cast<TypeContextDescriptor>(
276277
(const ContextDescriptor *)symbolicNode->getIndex());
277278

278-
auto mangledName = Demangle::mangleNode(node);
279+
auto mangledName =
280+
Demangle::mangleNode(node,
281+
[&](const void *context) -> NodePointer {
282+
return _buildDemanglingForContext(
283+
(const ContextDescriptor *) context,
284+
{}, false, Dem);
285+
});
279286

280287
// Look for an existing entry.
281288
// Find the bucket for the metadata entry.
@@ -696,7 +703,7 @@ class DecodedMetadataBuilder {
696703
#endif
697704

698705
// Look for a nominal type descriptor based on its mangled name.
699-
return _findNominalTypeDescriptor(node);
706+
return _findNominalTypeDescriptor(node, demangler);
700707
}
701708

702709
BuiltProtocolDecl createProtocolDecl(
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
struct OtherStruct {
2+
let a: OtherOuter.Inner
3+
let b: OtherOuterGeneric<Int>.Inner<String>
4+
}
5+
6+
struct OtherOuter {}
7+
struct OtherOuterGeneric<T> {}

test/stdlib/Mirror.swift

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,14 @@
1010
//
1111
//===----------------------------------------------------------------------===//
1212
// RUN: %empty-directory(%t)
13+
// RUN: cp %s %t/main.swift
1314
//
1415
// RUN: if [ %target-runtime == "objc" ]; \
1516
// RUN: then \
1617
// RUN: %target-clang %S/Inputs/Mirror/Mirror.mm -c -o %t/Mirror.mm.o -g && \
17-
// RUN: %target-build-swift %s -I %S/Inputs/Mirror/ -Xlinker %t/Mirror.mm.o -o %t/Mirror; \
18+
// RUN: %target-build-swift %t/main.swift %S/Inputs/Mirror/MirrorOther.swift -I %S/Inputs/Mirror/ -Xlinker %t/Mirror.mm.o -o %t/Mirror; \
1819
// RUN: else \
19-
// RUN: %target-build-swift %s -o %t/Mirror; \
20+
// RUN: %target-build-swift %t/main.swift %S/Inputs/Mirror/MirrorOther.swift -o %t/Mirror; \
2021
// RUN: fi
2122
// RUN: %target-run %t/Mirror
2223
// REQUIRES: executable_test
@@ -791,11 +792,34 @@ struct e<f> {
791792
var constraints: [Int: a<f>.c] = [:]
792793
}
793794

794-
mirrors.test("field with generic nested type") {
795+
mirrors.test("GenericNestedTypeField") {
795796
let x = e<d>()
796797

797798
expectTrue(type(of: Mirror(reflecting: x).children.first!.value)
798799
== [Int: a<d>.c].self)
799800
}
800801

802+
extension OtherOuter {
803+
struct Inner {}
804+
}
805+
806+
extension OtherOuterGeneric {
807+
struct Inner<U> {}
808+
}
809+
810+
mirrors.test("SymbolicReferenceInsideType") {
811+
let s = OtherStruct(a: OtherOuter.Inner(),
812+
b: OtherOuterGeneric<Int>.Inner<String>())
813+
814+
var output = ""
815+
dump(s, to: &output)
816+
817+
let expected =
818+
"▿ Mirror.OtherStruct\n" +
819+
" - a: Mirror.OtherOuter.Inner\n" +
820+
" - b: Mirror.OtherOuterGeneric<Swift.Int>.Inner<Swift.String>\n"
821+
822+
expectEqual(expected, output)
823+
}
824+
801825
runAllTests()

0 commit comments

Comments
 (0)