Skip to content

Commit 5350cd5

Browse files
committed
Rework createBoundGenericTypeReconstructingParent
The recursive structure made it a little awkward to correctly distinguish between the root node (which has to be included regardless of whether it has direct generic params) and the parent nodes (which must only be included if they have direct params). So I rewrote this to do a simple two-pass iteration: * The first pass walks the parent list collecting candidates * The second pass walks the list backwards, assigning generic params We then just stack the start node onto the end of the list regardless of whether it has generic params.
1 parent ed28d8e commit 5350cd5

File tree

1 file changed

+93
-52
lines changed

1 file changed

+93
-52
lines changed

include/swift/RemoteInspection/TypeRefBuilder.h

Lines changed: 93 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -567,61 +567,95 @@ class TypeRefBuilder {
567567
return nullptr;
568568
}
569569

570-
// Recursively constructs TypeRef for a bound generic, including
571-
// the enclosing (parent) generic contexts
570+
// Construct a bound generic type ref along with the parent type info
571+
// The parent list contains every parent type with at least 1 generic
572+
// type parameter.
572573
const BoundGenericTypeRef *createBoundGenericTypeReconstructingParent(
573-
const NodePointer node, const TypeRefDecl &decl, size_t shapeIndex,
574-
const llvm::ArrayRef<const TypeRef *> &args, size_t argsIndex) {
575-
if (!node || !node->hasChildren())
576-
return nullptr;
577-
NodePointer parentNode = node->getFirstChild();
578-
579-
// If this node can't possibly be generic, skip it and
580-
// return results for our parent instead
581-
auto kind = node->getKind();
582-
if (kind != Node::Kind::Class
583-
&& kind != Node::Kind::Structure
584-
&& kind != Node::Kind::Enum) {
585-
return createBoundGenericTypeReconstructingParent(
586-
parentNode, decl, --shapeIndex, args, argsIndex);
574+
const NodePointer startNode,
575+
const std::vector<size_t> &genericParamsPerLevel,
576+
const llvm::ArrayRef<const TypeRef *> &args)
577+
{
578+
// Collect all the relevant nodes, including the current node
579+
std::vector<NodePointer> nodes;
580+
581+
// Iterate our parents, collecting the first N parents
582+
// that potentially have generic args
583+
NodePointer node = startNode;
584+
while (nodes.size() < genericParamsPerLevel.size() - 1) {
585+
if (!node || !node->hasChildren()) {
586+
return nullptr;
587+
}
588+
node = node->getFirstChild();
589+
switch (node->getKind()) {
590+
case Node::Kind::Class:
591+
case Node::Kind::Structure:
592+
case Node::Kind::Enum:
593+
nodes.push_back(node);
594+
break;
595+
default:
596+
break;
597+
}
587598
}
599+
assert(nodes.size() == genericParamsPerLevel.size() - 1);
600+
601+
// We're now going to build the type tree from the
602+
// outermost parent in, which matches the order of
603+
// the generic parameter list and genericParamsPerLevel.
604+
std::reverse(nodes.begin(), nodes.end());
605+
606+
// Walk the list of parent types together with
607+
// the generic argument list...
608+
const BoundGenericTypeRef *typeref = nullptr;
609+
auto argBegin = args.begin();
610+
size_t totalArgs = 0;
611+
for (size_t i = 0; i < nodes.size(); i++) {
612+
// Get the mangling for this node
613+
auto mangling = Demangle::mangleNode(nodes[i]);
614+
if (!mangling.isSuccess()) {
615+
return nullptr;
616+
}
588617

589-
// How many generic args are at this level?
590-
auto maybeGenericParamsPerLevel = decl.genericParamsPerLevel;
591-
if (!maybeGenericParamsPerLevel)
592-
return nullptr;
593-
auto genericParamsPerLevel = *maybeGenericParamsPerLevel;
594-
if (shapeIndex >= genericParamsPerLevel.size())
595-
return nullptr;
596-
auto numGenericArgs = genericParamsPerLevel[shapeIndex];
597-
598-
// Nodes with no generic args can be replaced with their parent
599-
if (numGenericArgs == 0) {
600-
return createBoundGenericTypeReconstructingParent(
601-
parentNode, decl, --shapeIndex, args, argsIndex);
618+
// Use the next N params for this node
619+
auto numGenericArgs = genericParamsPerLevel[i];
620+
// Skip nodes that don't have any actual type params.
621+
if (numGenericArgs == 0) {
622+
continue;
623+
}
624+
if (numGenericArgs > args.size() || totalArgs + numGenericArgs > args.size()) {
625+
return nullptr;
626+
}
627+
auto argEnd = argBegin + numGenericArgs;
628+
totalArgs += numGenericArgs;
629+
std::vector<const TypeRef *> params(argBegin, argEnd);
630+
argBegin = argEnd;
631+
632+
// Extend the typeref up one level
633+
typeref = BoundGenericTypeRef::create(*this, mangling.result(), params, typeref);
602634
}
603635

604-
// Collect args for the BoundGenericTypeRef::create() call:
605-
606-
// * Mangling
607-
auto mangling = Demangle::mangleNode(node);
608-
if (!mangling.isSuccess())
636+
// Now let's stack the startNode on top of the parent list
637+
// to obtain the final full typeref:
638+
auto mangling = Demangle::mangleNode(startNode);
639+
if (!mangling.isSuccess()) {
609640
return nullptr;
641+
}
610642

611-
// * Generic params for this node
612-
auto startOffsetFromEnd = argsIndex + numGenericArgs;
613-
auto endOffsetFromEnd = argsIndex;
614-
if (startOffsetFromEnd > args.size() || endOffsetFromEnd > args.size())
643+
// Collect the final set of generic params for the
644+
// startNode. Note: This will sometimes be empty:
645+
// consider `Foo<Int, String>.Bar.Baz<Double>.Quux`
646+
// which has 2 parents in the parent list
647+
// (`Foo<Int,String>`, `Baz<Double>`), and the
648+
// startNode is `Quux` with no params.
649+
auto numGenericArgs = genericParamsPerLevel[genericParamsPerLevel.size() - 1];
650+
auto argEnd = argBegin + numGenericArgs;
651+
if (argEnd != args.end()) {
652+
// This node should exactly consume the remaining args
615653
return nullptr;
616-
std::vector<const TypeRef *> genericParams(
617-
args.end() - startOffsetFromEnd, args.end() - endOffsetFromEnd);
618-
619-
// * Reconstructed parent
620-
auto parent = createBoundGenericTypeReconstructingParent(
621-
parentNode, decl, --shapeIndex, args, argsIndex + numGenericArgs);
654+
}
655+
std::vector<const TypeRef *> params(argBegin, argEnd);
622656

623-
return BoundGenericTypeRef::create(*this, mangling.result(), genericParams,
624-
parent);
657+
// Build and return the top typeref
658+
return BoundGenericTypeRef::create(*this, mangling.result(), params, typeref);
625659
}
626660

627661
const BoundGenericTypeRef *
@@ -630,16 +664,23 @@ class TypeRefBuilder {
630664
if (!builtTypeDecl)
631665
return nullptr;
632666

633-
if (!builtTypeDecl->genericParamsPerLevel)
667+
// If there aren't generic params on the parent types, we just emit
668+
// a single BG typeref with all the generic args
669+
auto maybeGenericParamsPerLevel = builtTypeDecl->genericParamsPerLevel;
670+
if (!maybeGenericParamsPerLevel) {
634671
return BoundGenericTypeRef::create(*this, builtTypeDecl->mangledName, args, nullptr);
672+
}
635673

674+
// Otherwise, work from a full demangle tree to produce a
675+
// typeref that includes all parents that have generic params
636676
auto node = Dem.demangleType(builtTypeDecl->mangledName);
637-
if (!node || !node->hasChildren() || node->getKind() != Node::Kind::Type)
677+
if (node && node->hasChildren() && node->getKind() == Node::Kind::Type) {
678+
auto type = node->getFirstChild();
679+
auto genericParamsPerLevel = *maybeGenericParamsPerLevel;
680+
return createBoundGenericTypeReconstructingParent(type, genericParamsPerLevel, args);
681+
} else {
638682
return nullptr;
639-
640-
auto type = node->getFirstChild();
641-
return createBoundGenericTypeReconstructingParent(
642-
type, *builtTypeDecl, builtTypeDecl->genericParamsPerLevel->size() - 1, args, 0);
683+
}
643684
}
644685

645686
const BoundGenericTypeRef *

0 commit comments

Comments
 (0)