Skip to content

Commit d29b545

Browse files
authored
Merge pull request #22185 from slavapestov/type-reconstruction-part-2
Type reconstruction rework, part 2
2 parents eb44285 + 9c8a5b5 commit d29b545

File tree

18 files changed

+677
-147
lines changed

18 files changed

+677
-147
lines changed

include/swift/AST/ASTDemangler.h

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,13 +82,22 @@ class ASTBuilder {
8282
Type createFunctionType(ArrayRef<Demangle::FunctionParam<Type>> params,
8383
Type output, FunctionTypeFlags flags);
8484

85+
Type createImplFunctionType(
86+
Demangle::ImplParameterConvention calleeConvention,
87+
ArrayRef<Demangle::ImplFunctionParam<Type>> params,
88+
ArrayRef<Demangle::ImplFunctionResult<Type>> results,
89+
Optional<Demangle::ImplFunctionResult<Type>> errorResult,
90+
ImplFunctionTypeFlags flags);
91+
8592
Type createProtocolCompositionType(ArrayRef<ProtocolDecl *> protocols,
8693
Type superclass,
8794
bool isClassBound);
8895

89-
Type createExistentialMetatypeType(Type instance);
96+
Type createExistentialMetatypeType(Type instance,
97+
Optional<Demangle::ImplMetatypeRepresentation> repr=None);
9098

91-
Type createMetatypeType(Type instance, bool wasAbstract=false);
99+
Type createMetatypeType(Type instance,
100+
Optional<Demangle::ImplMetatypeRepresentation> repr=None);
92101

93102
Type createGenericTypeParameterType(unsigned depth, unsigned index);
94103

include/swift/Demangling/TypeDecoder.h

Lines changed: 222 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,11 @@
2828
namespace swift {
2929
namespace Demangle {
3030

31-
/// Strip generic arguments from the "spine" of a context node, producing a
32-
/// bare context to be used in (e.g.) forming nominal type descriptors.
33-
NodePointer stripGenericArgsFromContextNode(NodePointer node,
34-
NodeFactory &factory);
31+
enum class ImplMetatypeRepresentation {
32+
Thin,
33+
Thick,
34+
ObjC,
35+
};
3536

3637
/// Describe a function parameter, parameterized on the type
3738
/// representation.
@@ -76,6 +77,147 @@ class FunctionParam {
7677
}
7778
};
7879

80+
enum class ImplParameterConvention {
81+
Indirect_In,
82+
Indirect_In_Constant,
83+
Indirect_In_Guaranteed,
84+
Indirect_Inout,
85+
Indirect_InoutAliasable,
86+
Direct_Owned,
87+
Direct_Unowned,
88+
Direct_Guaranteed,
89+
};
90+
91+
/// Describe a lowered function parameter, parameterized on the type
92+
/// representation.
93+
template <typename BuiltType>
94+
class ImplFunctionParam {
95+
ImplParameterConvention Convention;
96+
BuiltType Type;
97+
98+
public:
99+
using ConventionType = ImplParameterConvention;
100+
101+
static Optional<ConventionType>
102+
getConventionFromString(StringRef conventionString) {
103+
if (conventionString == "@in")
104+
return ConventionType::Indirect_In;
105+
if (conventionString == "@indirect_in_constant")
106+
return ConventionType::Indirect_In_Constant;
107+
if (conventionString == "@in_guaranteed")
108+
return ConventionType::Indirect_In_Guaranteed;
109+
if (conventionString == "@inout")
110+
return ConventionType::Indirect_Inout;
111+
if (conventionString == "@inout_aliasable")
112+
return ConventionType::Indirect_InoutAliasable;
113+
if (conventionString == "@owned")
114+
return ConventionType::Direct_Owned;
115+
if (conventionString == "@unowned")
116+
return ConventionType::Direct_Unowned;
117+
if (conventionString == "@guaranteed")
118+
return ConventionType::Direct_Guaranteed;
119+
120+
return None;
121+
}
122+
123+
ImplFunctionParam(ImplParameterConvention convention, BuiltType type)
124+
: Convention(convention), Type(type) {}
125+
126+
ImplParameterConvention getConvention() const { return Convention; }
127+
128+
BuiltType getType() const { return Type; }
129+
};
130+
131+
enum class ImplResultConvention {
132+
Indirect,
133+
Owned,
134+
Unowned,
135+
UnownedInnerPointer,
136+
Autoreleased,
137+
};
138+
139+
/// Describe a lowered function result, parameterized on the type
140+
/// representation.
141+
template <typename BuiltType>
142+
class ImplFunctionResult {
143+
ImplResultConvention Convention;
144+
BuiltType Type;
145+
146+
public:
147+
using ConventionType = ImplResultConvention;
148+
149+
static Optional<ConventionType>
150+
getConventionFromString(StringRef conventionString) {
151+
if (conventionString == "@out")
152+
return ConventionType::Indirect;
153+
if (conventionString == "@owned")
154+
return ConventionType::Owned;
155+
if (conventionString == "@unowned")
156+
return ConventionType::Unowned;
157+
if (conventionString == "@unowned_inner_pointer")
158+
return ConventionType::UnownedInnerPointer;
159+
if (conventionString == "@autoreleased")
160+
return ConventionType::Autoreleased;
161+
162+
return None;
163+
}
164+
165+
ImplFunctionResult(ImplResultConvention convention, BuiltType type)
166+
: Convention(convention), Type(type) {}
167+
168+
ImplResultConvention getConvention() const { return Convention; }
169+
170+
BuiltType getType() const { return Type; }
171+
};
172+
173+
enum class ImplFunctionRepresentation {
174+
Thick,
175+
Block,
176+
Thin,
177+
CFunctionPointer,
178+
Method,
179+
ObjCMethod,
180+
WitnessMethod,
181+
Closure
182+
};
183+
184+
class ImplFunctionTypeFlags {
185+
unsigned Rep : 3;
186+
unsigned Pseudogeneric : 1;
187+
unsigned Escaping : 1;
188+
189+
public:
190+
ImplFunctionTypeFlags() : Rep(0), Pseudogeneric(0), Escaping(0) {}
191+
192+
ImplFunctionTypeFlags(ImplFunctionRepresentation rep,
193+
bool pseudogeneric, bool noescape)
194+
: Rep(unsigned(rep)), Pseudogeneric(pseudogeneric), Escaping(noescape) {}
195+
196+
ImplFunctionTypeFlags
197+
withRepresentation(ImplFunctionRepresentation rep) const {
198+
return ImplFunctionTypeFlags(rep, Pseudogeneric, Escaping);
199+
}
200+
201+
ImplFunctionTypeFlags
202+
withEscaping() const {
203+
return ImplFunctionTypeFlags(ImplFunctionRepresentation(Rep),
204+
Pseudogeneric, true);
205+
}
206+
207+
ImplFunctionTypeFlags
208+
withPseudogeneric() const {
209+
return ImplFunctionTypeFlags(ImplFunctionRepresentation(Rep),
210+
true, Escaping);
211+
}
212+
213+
ImplFunctionRepresentation getRepresentation() const {
214+
return ImplFunctionRepresentation(Rep);
215+
}
216+
217+
bool isEscaping() const { return Escaping; }
218+
219+
bool isPseudogeneric() const { return Pseudogeneric; }
220+
};
79221

80222
#if SWIFT_OBJC_INTEROP
81223
/// For a mangled node that refers to an Objective-C class or protocol,
@@ -248,18 +390,22 @@ class TypeDecoder {
248390
case NodeKind::Metatype:
249391
case NodeKind::ExistentialMetatype: {
250392
unsigned i = 0;
251-
bool wasAbstract = false;
393+
Optional<ImplMetatypeRepresentation> repr;
252394

253395
// Handle lowered metatypes in a hackish way. If the representation
254396
// was not thin, force the resulting typeref to have a non-empty
255397
// representation.
256398
if (Node->getNumChildren() >= 2) {
257-
auto repr = Node->getChild(i++);
258-
if (repr->getKind() != NodeKind::MetatypeRepresentation ||
259-
!repr->hasText())
399+
auto reprNode = Node->getChild(i++);
400+
if (reprNode->getKind() != NodeKind::MetatypeRepresentation ||
401+
!reprNode->hasText())
260402
return BuiltType();
261-
if (repr->getText() != "@thin")
262-
wasAbstract = true;
403+
if (reprNode->getText() == "@thin")
404+
repr = ImplMetatypeRepresentation::Thin;
405+
else if (reprNode->getText() == "@thick")
406+
repr = ImplMetatypeRepresentation::Thick;
407+
else if (reprNode->getText() == "@objc_metatype")
408+
repr = ImplMetatypeRepresentation::ObjC;
263409
} else if (Node->getNumChildren() < 1) {
264410
return BuiltType();
265411
}
@@ -268,11 +414,9 @@ class TypeDecoder {
268414
if (!instance)
269415
return BuiltType();
270416
if (Node->getKind() == NodeKind::Metatype) {
271-
return Builder.createMetatypeType(instance, wasAbstract);
417+
return Builder.createMetatypeType(instance, repr);
272418
} else if (Node->getKind() == NodeKind::ExistentialMetatype) {
273-
// FIXME: Ignore representation of existential metatype
274-
// completely for now
275-
return Builder.createExistentialMetatypeType(instance);
419+
return Builder.createExistentialMetatypeType(instance, repr);
276420
} else {
277421
assert(false);
278422
return nullptr;
@@ -388,12 +532,11 @@ class TypeDecoder {
388532
return Builder.createFunctionType(parameters, result, flags);
389533
}
390534
case NodeKind::ImplFunctionType: {
391-
// Minimal support for lowered function types. These come up in
392-
// reflection as capture types. For the reflection library's
393-
// purposes, the only part that matters is the convention.
394-
//
395-
// TODO: Do we want to reflect @escaping?
396-
FunctionTypeFlags flags;
535+
auto calleeConvention = ImplParameterConvention::Direct_Unowned;
536+
std::vector<ImplFunctionParam<BuiltType>> parameters;
537+
std::vector<ImplFunctionResult<BuiltType>> results;
538+
std::vector<ImplFunctionResult<BuiltType>> errorResults;
539+
ImplFunctionTypeFlags flags;
397540

398541
for (unsigned i = 0; i < Node->getNumChildren(); i++) {
399542
auto child = Node->getChild(i);
@@ -404,7 +547,9 @@ class TypeDecoder {
404547

405548
if (child->getText() == "@convention(thin)") {
406549
flags =
407-
flags.withConvention(FunctionMetadataConvention::Thin);
550+
flags.withRepresentation(ImplFunctionRepresentation::Thin);
551+
} else if (child->getText() == "@callee_guaranteed") {
552+
calleeConvention = ImplParameterConvention::Direct_Guaranteed;
408553
}
409554
} else if (child->getKind() == NodeKind::ImplFunctionAttribute) {
410555
if (!child->hasText())
@@ -413,24 +558,46 @@ class TypeDecoder {
413558
StringRef text = child->getText();
414559
if (text == "@convention(c)") {
415560
flags =
416-
flags.withConvention(FunctionMetadataConvention::CFunctionPointer);
561+
flags.withRepresentation(ImplFunctionRepresentation::CFunctionPointer);
417562
} else if (text == "@convention(block)") {
418563
flags =
419-
flags.withConvention(FunctionMetadataConvention::Block);
564+
flags.withRepresentation(ImplFunctionRepresentation::Block);
420565
}
421566
} else if (child->getKind() == NodeKind::ImplEscaping) {
422-
flags = flags.withEscaping(true);
567+
flags = flags.withEscaping();
568+
} else if (child->getKind() == NodeKind::ImplParameter) {
569+
if (decodeImplFunctionPart(child, parameters))
570+
return BuiltType();
571+
} else if (child->getKind() == NodeKind::ImplResult) {
572+
if (decodeImplFunctionPart(child, results))
573+
return BuiltType();
574+
} else if (child->getKind() == NodeKind::ImplErrorResult) {
575+
if (decodeImplFunctionPart(child, errorResults))
576+
return BuiltType();
577+
} else {
578+
return BuiltType();
423579
}
424580
}
425581

426-
// Completely punt on argument types and results.
427-
std::vector<FunctionParam<BuiltType>> parameters;
428-
429-
std::vector<BuiltType> elements;
430-
std::string labels;
431-
auto result = Builder.createTupleType(elements, std::move(labels), false);
582+
Optional<ImplFunctionResult<BuiltType>> errorResult;
583+
switch (errorResults.size()) {
584+
case 0:
585+
break;
586+
case 1:
587+
errorResult = errorResults.front();
588+
break;
589+
default:
590+
return BuiltType();
591+
}
432592

433-
return Builder.createFunctionType(parameters, result, flags);
593+
// TODO: Some cases not handled above, but *probably* they cannot
594+
// appear as the types of values in SIL (yet?):
595+
// - functions with yield returns
596+
// - functions with generic signatures
597+
// - foreign error conventions
598+
return Builder.createImplFunctionType(calleeConvention,
599+
parameters, results,
600+
errorResult, flags);
434601
}
435602

436603
case NodeKind::ArgumentTuple:
@@ -574,6 +741,29 @@ class TypeDecoder {
574741
}
575742

576743
private:
744+
template <typename T>
745+
bool decodeImplFunctionPart(Demangle::NodePointer node,
746+
std::vector<T> &results) {
747+
if (node->getNumChildren() != 2)
748+
return true;
749+
750+
if (node->getChild(0)->getKind() != Node::Kind::ImplConvention ||
751+
node->getChild(1)->getKind() != Node::Kind::Type)
752+
return true;
753+
754+
StringRef conventionString = node->getChild(0)->getText();
755+
Optional<typename T::ConventionType> convention =
756+
T::getConventionFromString(conventionString);
757+
if (!convention)
758+
return true;
759+
BuiltType type = decodeMangledType(node->getChild(1));
760+
if (!type)
761+
return true;
762+
763+
results.emplace_back(*convention, type);
764+
return false;
765+
}
766+
577767
bool decodeMangledTypeDecl(Demangle::NodePointer node,
578768
BuiltTypeDecl &typeDecl,
579769
BuiltType &parent,
@@ -611,8 +801,7 @@ class TypeDecoder {
611801
parent = decodeMangledType(parentContext);
612802
// Remove any generic arguments from the context node, producing a
613803
// node that references the nominal type declaration.
614-
declNode =
615-
stripGenericArgsFromContextNode(node, Builder.getNodeFactory());
804+
declNode = Demangle::getUnspecialized(node, Builder.getNodeFactory());
616805
break;
617806
}
618807
}

0 commit comments

Comments
 (0)