Skip to content

[Runtime] Properly form generic arguments for metadata-to-demangle-tree. #19559

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
126 changes: 86 additions & 40 deletions stdlib/public/runtime/Demangle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ using namespace swift;
Demangle::NodePointer
swift::_buildDemanglingForContext(const ContextDescriptor *context,
llvm::ArrayRef<NodePointer> demangledGenerics,
bool concretizedGenerics,
Demangle::Demangler &Dem) {
unsigned usedDemangledGenerics = 0;
NodePointer node = nullptr;
Expand All @@ -45,13 +44,6 @@ swift::_buildDemanglingForContext(const ContextDescriptor *context,

auto getGenericArgsTypeListForContext =
[&](const ContextDescriptor *context) -> NodePointer {
// ABI TODO: As a hack to maintain existing broken behavior,
// if there were any generic arguments eliminated by same type
// constraints, we don't mangle any of them into intermediate contexts,
// and pile all of the non-concrete arguments into the innermost context.
if (concretizedGenerics)
return nullptr;

if (demangledGenerics.empty())
return nullptr;

Expand All @@ -73,7 +65,6 @@ swift::_buildDemanglingForContext(const ContextDescriptor *context,
return genericArgsList;
};

auto innermostComponent = descriptorPath.front();
for (auto component : reversed(descriptorPath)) {
switch (auto kind = component->getKind()) {
case ContextDescriptorKind::Module: {
Expand All @@ -91,9 +82,6 @@ swift::_buildDemanglingForContext(const ContextDescriptor *context,
selfType = selfType->getChild(0);

// Substitute in the generic arguments.
// TODO: This kludge only kinda works if there are no same-type
// constraints. We'd need to handle those correctly everywhere else too
// though.
auto genericArgsList = getGenericArgsTypeListForContext(component);

if (selfType->getKind() == Node::Kind::BoundGenericEnum
Expand Down Expand Up @@ -197,28 +185,6 @@ swift::_buildDemanglingForContext(const ContextDescriptor *context,
node = genericNode;
}

// ABI TODO: If there were concretized generic arguments, just pile
// all the non-concretized generic arguments into the innermost context.
if (concretizedGenerics
&& !demangledGenerics.empty()
&& component == innermostComponent) {
auto unspecializedType = Dem.createNode(Node::Kind::Type);
unspecializedType->addChild(node, Dem);

auto genericTypeList = Dem.createNode(Node::Kind::TypeList);
for (auto arg : demangledGenerics) {
if (!arg) continue;
genericTypeList->addChild(arg, Dem);
}

if (genericTypeList->getNumChildren() > 0) {
auto genericNode = Dem.createNode(genericNodeKind);
genericNode->addChild(unspecializedType, Dem);
genericNode->addChild(genericTypeList, Dem);
node = genericNode;
}
}

break;
}

Expand Down Expand Up @@ -312,8 +278,10 @@ _buildDemanglingForNominalType(const Metadata *type, Demangle::Demangler &Dem) {

// Demangle the generic arguments.
std::vector<NodePointer> demangledGenerics;
bool concretizedGenerics = false;

if (auto generics = description->getGenericContext()) {
std::vector<const Metadata *> allGenericArgs;
bool concretizedGenerics = false;
auto genericArgs = description->getGenericArguments(type);
for (auto param : generics->getGenericParams()) {
switch (param.getKind()) {
Expand All @@ -332,10 +300,12 @@ _buildDemanglingForNominalType(const Metadata *type, Demangle::Demangler &Dem) {
_swift_buildDemanglingForMetadata(paramType, Dem);
if (!paramDemangling)
return nullptr;
allGenericArgs.push_back(paramType);
demangledGenerics.push_back(paramDemangling);
} else {
// Leave a gap for us to fill in by looking at same type info.
demangledGenerics.push_back(nullptr);
allGenericArgs.push_back(nullptr);
concretizedGenerics = true;
}
break;
Expand All @@ -358,11 +328,88 @@ _buildDemanglingForNominalType(const Metadata *type, Demangle::Demangler &Dem) {

// If we have concretized generic arguments, check for same type
// requirements to get the argument values.
// ABI TODO
if (concretizedGenerics) {
// Retrieve the mapping information needed for depth/index -> flat index.
std::vector<unsigned> genericParamCounts;
(void)_gatherGenericParameterCounts(description, genericParamCounts);

// Walk through the generic requirements to evaluate same-type
// constraints that are needed to fill in missing generic arguments.
for (const auto &req : generics->getGenericRequirements()) {
// We only care about same-type constraints.
if (req.Flags.getKind() != GenericRequirementKind::SameType)
continue;

// Where the left-hand side is a generic parameter.
if (req.Param.begin() != req.Param.end())
continue;

// If we don't yet have an argument for this parameter, it's a
// same-type-to-concrete constraint.
unsigned lhsFlatIndex = req.Param.getRootParamIndex();
if (!allGenericArgs[lhsFlatIndex]) {
// Substitute into the right-hand side.
auto genericArg =
_getTypeByMangledName(req.getMangledTypeName(),
[&](unsigned depth, unsigned index) {
if (auto flatIndex = _depthIndexToFlatIndex(depth, index,
genericParamCounts))
return allGenericArgs[*flatIndex];

return (const Metadata *)nullptr;
});
if (!genericArg)
return nullptr;

allGenericArgs[lhsFlatIndex] = genericArg;

// Form a demangling for this argument.
auto argDemangling =
_swift_buildDemanglingForMetadata(genericArg, Dem);
if (!argDemangling)
return nullptr;

demangledGenerics[lhsFlatIndex] = argDemangling;
continue;
}

// If we do have an argument for this parameter, it might be that
// the right-hand side is itself a generic parameter, which means
// we have a same-type constraint A == B where A is already filled in.
Demangler demangler;
NodePointer node = demangler.demangleType(req.getMangledTypeName());
if (!node)
continue;

// Find the flat index that the right-hand side refers to.
if (node->getKind() == Demangle::Node::Kind::Type)
node = node->getChild(0);
if (node->getKind() != Demangle::Node::Kind::DependentGenericParamType)
continue;

auto rhsFlatIndex =
_depthIndexToFlatIndex(node->getChild(0)->getIndex(),
node->getChild(1)->getIndex(),
genericParamCounts);
if (!rhsFlatIndex || *rhsFlatIndex > allGenericArgs.size())
return nullptr;

if (allGenericArgs[*rhsFlatIndex] || !allGenericArgs[lhsFlatIndex])
continue;

allGenericArgs[*rhsFlatIndex] = allGenericArgs[lhsFlatIndex];
demangledGenerics[*rhsFlatIndex] = demangledGenerics[lhsFlatIndex];
}

// Make sure that all of the demangled generics are filled in now.
for (const auto node : demangledGenerics) {
if (!node)
return nullptr;
}
}
}

return _buildDemanglingForContext(description, demangledGenerics,
concretizedGenerics, Dem);
return _buildDemanglingForContext(description, demangledGenerics, Dem);
}

// Build a demangled type tree for a type.
Expand Down Expand Up @@ -449,8 +496,7 @@ swift::_swift_buildDemanglingForMetadata(const Metadata *type,
#endif

auto protocolNode =
_buildDemanglingForContext(protocol.getSwiftProtocol(), { }, false,
Dem);
_buildDemanglingForContext(protocol.getSwiftProtocol(), { }, Dem);
if (!protocolNode)
return nullptr;

Expand Down
4 changes: 2 additions & 2 deletions stdlib/public/runtime/MetadataLookup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -527,7 +527,7 @@ _findNominalTypeDescriptor(Demangle::NodePointer node,
[&](const void *context) -> NodePointer {
return _buildDemanglingForContext(
(const ContextDescriptor *) context,
{}, false, Dem);
{}, Dem);
});

// Look for an existing entry.
Expand Down Expand Up @@ -662,7 +662,7 @@ _findProtocolDescriptor(const Demangle::NodePointer &node,
[&](const void *context) -> NodePointer {
return _buildDemanglingForContext(
(const ContextDescriptor *) context,
{}, false, Dem);
{}, Dem);
});

// Look for an existing entry.
Expand Down
3 changes: 1 addition & 2 deletions stdlib/public/runtime/Private.h
Original file line number Diff line number Diff line change
Expand Up @@ -345,7 +345,6 @@ class TypeInfo {
Demangle::NodePointer
_buildDemanglingForContext(const ContextDescriptor *context,
llvm::ArrayRef<NodePointer> demangledGenerics,
bool concretizedGenerics,
Demangle::Demangler &Dem);

/// Symbolic reference resolver that produces the demangling tree for the
Expand All @@ -360,7 +359,7 @@ class TypeInfo {
auto descriptor =
(const ContextDescriptor *)detail::applyRelativeOffset(base, offset);

return _buildDemanglingForContext(descriptor, {}, false, Dem);
return _buildDemanglingForContext(descriptor, {}, Dem);
}
};

Expand Down
3 changes: 1 addition & 2 deletions test/stdlib/Mirror.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1822,9 +1822,8 @@ mirrors.test("GenericNestedWithSameTypeConstraints") {
var output = ""
dump(value, to: &output)

// FIXME: The generic arguments are in the wrong place
let expected =
"▿ (extension in Mirror):Mirror.OuterTwoParams.InnerEqualParams<Mirror.ConformsToP1AndP2, Mirror.ConformsToP3>\n" +
"▿ (extension in Mirror):Mirror.OuterTwoParams<Mirror.ConformsToP1AndP2, Mirror.ConformsToP1AndP2>.InnerEqualParams<Mirror.ConformsToP3>\n" +
" - x: Mirror.ConformsToP1AndP2\n" +
" - y: Mirror.ConformsToP1AndP2\n" +
" - z: Mirror.ConformsToP3\n"
Expand Down
4 changes: 2 additions & 2 deletions test/stdlib/RuntimeObjC.swift
Original file line number Diff line number Diff line change
Expand Up @@ -782,8 +782,8 @@ RuntimeClassNamesTestSuite.test("private class nested in same-type-constrained e
let clas = unsafeBitCast(type(of: util), to: NSObject.self)
// Name should look like _TtC1aP.*Inner
let desc = clas.description
expectEqual(desc.prefix(7), "_TtC1aP")
expectEqual(desc.suffix(5), "Inner")
expectEqual("_TtGC1a", desc.prefix(7))
expectEqual("Data_", desc.suffix(5))
}

runAllTests()
4 changes: 2 additions & 2 deletions test/stdlib/TypeName.swift
Original file line number Diff line number Diff line change
Expand Up @@ -203,9 +203,9 @@ extension SomeOuterGenericClass where T == Int {
}

TypeNameTests.test("NestedInConstrainedExtension") {
expectEqual("(extension in main):main.SomeOuterGenericClass.AnotherInnerStruct",
expectEqual("(extension in main):main.SomeOuterGenericClass<Swift.Int>.AnotherInnerStruct",
_typeName(SomeOuterGenericClass<Int>.AnotherInnerStruct.self));
expectEqual("(extension in main):main.SomeOuterGenericClass.AnotherInnerGenericStruct<Swift.String>",
expectEqual("(extension in main):main.SomeOuterGenericClass<Swift.Int>.AnotherInnerGenericStruct<Swift.String>",
_typeName(SomeOuterGenericClass<Int>.AnotherInnerGenericStruct<String>.self));
}

Expand Down