Skip to content

Commit 02160e6

Browse files
committed
Recursively reconstruct nested generics, skipping non-generic
This is a more correct fix for the issue that inspired PR #62854. In particular, this does not change the numbering of generic argument levels, and so does not break generic type parameter lookups. Added a new test case to verify that nested types that mix generics and non-generics in different ways consistently identify the correct generic argument labels.
1 parent 89f98e9 commit 02160e6

File tree

2 files changed

+148
-32
lines changed

2 files changed

+148
-32
lines changed

include/swift/RemoteInspection/TypeRefBuilder.h

Lines changed: 31 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -567,58 +567,58 @@ class TypeRefBuilder {
567567
return nullptr;
568568
}
569569

570+
// Recursively constructs TypeRef for a bound generic, including
571+
// the enclosing (parent) generic contexts
570572
const BoundGenericTypeRef *createBoundGenericTypeReconstructingParent(
571573
const NodePointer node, const TypeRefDecl &decl, size_t shapeIndex,
572574
const llvm::ArrayRef<const TypeRef *> &args, size_t argsIndex) {
573575
if (!node || !node->hasChildren())
574576
return nullptr;
575-
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);
587+
}
588+
589+
// How many generic args are at this level?
576590
auto maybeGenericParamsPerLevel = decl.genericParamsPerLevel;
577591
if (!maybeGenericParamsPerLevel)
578592
return nullptr;
579-
580593
auto genericParamsPerLevel = *maybeGenericParamsPerLevel;
581-
582-
auto kind = node->getKind();
583-
// Kinds who have a "BoundGeneric..." variant.
584-
if (kind != Node::Kind::Class && kind != Node::Kind::Structure &&
585-
kind != Node::Kind::Enum)
594+
if (shapeIndex >= genericParamsPerLevel.size())
586595
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);
602+
}
603+
604+
// Collect args for the BoundGenericTypeRef::create() call:
605+
606+
// * Mangling
587607
auto mangling = Demangle::mangleNode(node);
588608
if (!mangling.isSuccess())
589609
return nullptr;
590610

591-
if (shapeIndex >= genericParamsPerLevel.size())
592-
return nullptr;
593-
594-
auto numGenericArgs = genericParamsPerLevel[shapeIndex];
595-
611+
// * Generic params for this node
596612
auto startOffsetFromEnd = argsIndex + numGenericArgs;
597613
auto endOffsetFromEnd = argsIndex;
598614
if (startOffsetFromEnd > args.size() || endOffsetFromEnd > args.size())
599615
return nullptr;
600-
601616
std::vector<const TypeRef *> genericParams(
602617
args.end() - startOffsetFromEnd, args.end() - endOffsetFromEnd);
603618

604-
const BoundGenericTypeRef *parent = nullptr;
605-
if (node->hasChildren()) {
606-
// Skip over nodes that are not of type class, enum or struct
607-
auto parentNode = node->getFirstChild();
608-
while (parentNode->getKind() != Node::Kind::Class &&
609-
parentNode->getKind() != Node::Kind::Structure &&
610-
parentNode->getKind() != Node::Kind::Enum) {
611-
if (parentNode->hasChildren()) {
612-
parentNode = parentNode->getFirstChild();
613-
} else {
614-
parentNode = nullptr;
615-
break;
616-
}
617-
}
618-
if (parentNode)
619-
parent = createBoundGenericTypeReconstructingParent(
620-
parentNode, decl, --shapeIndex, args, argsIndex + numGenericArgs);
621-
}
619+
// * Reconstructed parent
620+
auto parent = createBoundGenericTypeReconstructingParent(
621+
parentNode, decl, --shapeIndex, args, argsIndex + numGenericArgs);
622622

623623
return BoundGenericTypeRef::create(*this, mangling.result(), genericParams,
624624
parent);
@@ -633,7 +633,6 @@ class TypeRefBuilder {
633633
if (!builtTypeDecl->genericParamsPerLevel)
634634
return BoundGenericTypeRef::create(*this, builtTypeDecl->mangledName, args, nullptr);
635635

636-
637636
auto node = Dem.demangleType(builtTypeDecl->mangledName);
638637
if (!node || !node->hasChildren() || node->getKind() != Node::Kind::Type)
639638
return nullptr;
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-build-swift -lswiftSwiftReflectionTest %s -o %t/reflect_nested_generic
3+
// RUN: %target-codesign %t/reflect_nested_generic
4+
5+
// RUN: %target-run %target-swift-reflection-test %t/reflect_nested_generic | tee /dev/stderr | %FileCheck %s --check-prefix=CHECK --check-prefix=X%target-ptrsize --dump-input=fail
6+
7+
// REQUIRES: reflection_test_support
8+
// REQUIRES: objc_interop
9+
// REQUIRES: executable_test
10+
// UNSUPPORTED: use_os_stdlib
11+
12+
import SwiftReflectionTest
13+
14+
enum Outer1 {
15+
class C<T> {
16+
enum Inner {
17+
struct S<U> {
18+
var u: U? = nil
19+
var t: T? = nil
20+
}
21+
}
22+
}
23+
}
24+
25+
reflect(enum: Outer1.C<Void>.Inner.S<(Int,Int)>?.none)
26+
27+
//CHECK: Reflecting an enum.
28+
//CHECK-NEXT: Instance pointer in child address space: 0x{{[0-9a-fA-F]+}}
29+
//CHECK-NEXT: Type reference:
30+
//CHECK-NEXT: (bound_generic_enum Swift.Optional
31+
//CHECK-NEXT: (bound_generic_struct reflect_nested_generic.Outer1.C.Inner.S
32+
//CHECK-NEXT: (tuple
33+
//CHECK-NEXT: (struct Swift.Int)
34+
//CHECK-NEXT: (struct Swift.Int))
35+
//CHECK-NEXT: (bound_generic_class reflect_nested_generic.Outer1.C
36+
//CHECK-NEXT: (tuple))))
37+
38+
//CHECK: Type info:
39+
40+
//X64-NEXT: (single_payload_enum size=19 alignment=8 stride=24 num_extra_inhabitants=0 bitwise_takable=1
41+
//X64-NEXT: (case name=some index=0 offset=0
42+
//X64-NEXT: (struct size=18 alignment=8 stride=24 num_extra_inhabitants=0 bitwise_takable=1
43+
//X64-NEXT: (field name=u offset=0
44+
//X64-NEXT: (single_payload_enum size=17 alignment=8 stride=24 num_extra_inhabitants=0 bitwise_takable=1
45+
//X64-NEXT: (case name=some index=0 offset=0
46+
//X64-NEXT: (tuple size=16 alignment=8 stride=16 num_extra_inhabitants=0 bitwise_takable=1
47+
//X64-NEXT: (field offset=0
48+
//X64-NEXT: (struct size=8 alignment=8 stride=8 num_extra_inhabitants=0 bitwise_takable=1
49+
//X64-NEXT: (field name=_value offset=0
50+
//X64-NEXT: (builtin size=8 alignment=8 stride=8 num_extra_inhabitants=0 bitwise_takable=1))))
51+
//X64-NEXT: (field offset=8
52+
//X64-NEXT: (struct size=8 alignment=8 stride=8 num_extra_inhabitants=0 bitwise_takable=1
53+
//X64-NEXT: (field name=_value offset=0
54+
//X64-NEXT: (builtin size=8 alignment=8 stride=8 num_extra_inhabitants=0 bitwise_takable=1))))))
55+
//X64-NEXT: (case name=none index=1)))
56+
//X64-NEXT: (field name=t offset=17
57+
//X64-NEXT: (single_payload_enum size=1 alignment=1 stride=1 num_extra_inhabitants=0 bitwise_takable=1
58+
//X64-NEXT: (case name=some index=0 offset=0
59+
//X64-NEXT: (tuple size=0 alignment=1 stride=1 num_extra_inhabitants=0 bitwise_takable=1))
60+
//X64-NEXT: (case name=none index=1)))))
61+
//X64-NEXT: (case name=none index=1))
62+
63+
//TODO: X32
64+
65+
//CHECK: Mangled name: $s22reflect_nested_generic6Outer1O1CC1SVy_yt_Si_SitGSg
66+
//CHECK-NEXT: Demangled name: Swift.Optional<reflect_nested_generic.Outer1.C<()>.S<(Swift.Int, Swift.Int)>>
67+
68+
//CHECK: Enum value:
69+
//CHECK-NEXT: (enum_value name=none index=1)
70+
71+
72+
protocol P {}
73+
74+
struct S1: P { var a: Int; var b: Int }
75+
struct S2: P { }
76+
77+
struct Outer2 {
78+
enum E<T: P> {
79+
struct Inner {
80+
enum F<U: P> {
81+
case u(U)
82+
case a
83+
case b
84+
}
85+
}
86+
}
87+
}
88+
89+
reflect(enum: Outer2.E<S1>.Inner.F<S2>.b)
90+
91+
//CHECK: Reflecting an enum.
92+
//CHECK-NEXT: Instance pointer in child address space: 0x{{[0-9a-fA-F]+}}
93+
//CHECK-NEXT: Type reference:
94+
//CHECK-NEXT: (bound_generic_enum reflect_nested_generic.Outer2.E.Inner.F
95+
//CHECK-NEXT: (struct reflect_nested_generic.S2)
96+
//CHECK-NEXT: (bound_generic_enum reflect_nested_generic.Outer2.E
97+
//CHECK-NEXT: (struct reflect_nested_generic.S1)))
98+
99+
// Note: layout here is correct for both 32- and 64-bit platforms
100+
101+
//CHECK: Type info:
102+
//CHECK-NEXT: (single_payload_enum size=1 alignment=1 stride=1 num_extra_inhabitants=0 bitwise_takable=1
103+
//CHECK-NEXT: (case name=u index=0 offset=0
104+
//CHECK-NEXT: (struct size=0 alignment=1 stride=1 num_extra_inhabitants=0 bitwise_takable=1))
105+
//CHECK-NEXT: (case name=a index=1)
106+
//CHECK-NEXT: (case name=b index=2))
107+
108+
//CHECK: Mangled name: $s22reflect_nested_generic6Outer2V1EO1FOy_AA2S1V_AA2S2VG
109+
//CHECK-NEXT: Demangled name: reflect_nested_generic.Outer2.E<reflect_nested_generic.S1>.F<reflect_nested_generic.S2>
110+
111+
//CHECK: Enum value:
112+
//CHECK-NEXT: (enum_value name=b index=2)
113+
114+
doneReflecting()
115+
116+
// CHECK: Done.
117+

0 commit comments

Comments
 (0)