Skip to content

Commit 4a74bf4

Browse files
committed
ASTDemangler: Add support for lowered function types
1 parent 13a50c2 commit 4a74bf4

File tree

6 files changed

+390
-17
lines changed

6 files changed

+390
-17
lines changed

include/swift/AST/ASTDemangler.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,13 @@ 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);

include/swift/Demangling/TypeDecoder.h

Lines changed: 204 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,147 @@ class FunctionParam {
7777
}
7878
};
7979

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+
};
80221

81222
#if SWIFT_OBJC_INTEROP
82223
/// For a mangled node that refers to an Objective-C class or protocol,
@@ -391,12 +532,11 @@ class TypeDecoder {
391532
return Builder.createFunctionType(parameters, result, flags);
392533
}
393534
case NodeKind::ImplFunctionType: {
394-
// Minimal support for lowered function types. These come up in
395-
// reflection as capture types. For the reflection library's
396-
// purposes, the only part that matters is the convention.
397-
//
398-
// TODO: Do we want to reflect @escaping?
399-
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;
400540

401541
for (unsigned i = 0; i < Node->getNumChildren(); i++) {
402542
auto child = Node->getChild(i);
@@ -407,7 +547,9 @@ class TypeDecoder {
407547

408548
if (child->getText() == "@convention(thin)") {
409549
flags =
410-
flags.withConvention(FunctionMetadataConvention::Thin);
550+
flags.withRepresentation(ImplFunctionRepresentation::Thin);
551+
} else if (child->getText() == "@callee_guaranteed") {
552+
calleeConvention = ImplParameterConvention::Direct_Guaranteed;
411553
}
412554
} else if (child->getKind() == NodeKind::ImplFunctionAttribute) {
413555
if (!child->hasText())
@@ -416,24 +558,46 @@ class TypeDecoder {
416558
StringRef text = child->getText();
417559
if (text == "@convention(c)") {
418560
flags =
419-
flags.withConvention(FunctionMetadataConvention::CFunctionPointer);
561+
flags.withRepresentation(ImplFunctionRepresentation::CFunctionPointer);
420562
} else if (text == "@convention(block)") {
421563
flags =
422-
flags.withConvention(FunctionMetadataConvention::Block);
564+
flags.withRepresentation(ImplFunctionRepresentation::Block);
423565
}
424566
} else if (child->getKind() == NodeKind::ImplEscaping) {
425-
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();
426579
}
427580
}
428581

429-
// Completely punt on argument types and results.
430-
std::vector<FunctionParam<BuiltType>> parameters;
431-
432-
std::vector<BuiltType> elements;
433-
std::string labels;
434-
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+
}
435592

436-
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);
437601
}
438602

439603
case NodeKind::ArgumentTuple:
@@ -577,6 +741,29 @@ class TypeDecoder {
577741
}
578742

579743
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+
580767
bool decodeMangledTypeDecl(Demangle::NodePointer node,
581768
BuiltTypeDecl &typeDecl,
582769
BuiltType &parent,

include/swift/Reflection/TypeRefBuilder.h

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,39 @@ class TypeRefBuilder {
275275
return FunctionTypeRef::create(*this, params, result, flags);
276276
}
277277

278+
const FunctionTypeRef *createImplFunctionType(
279+
Demangle::ImplParameterConvention calleeConvention,
280+
ArrayRef<Demangle::ImplFunctionParam<const TypeRef *>> params,
281+
ArrayRef<Demangle::ImplFunctionResult<const TypeRef *>> results,
282+
Optional<Demangle::ImplFunctionResult<const TypeRef *>> errorResult,
283+
ImplFunctionTypeFlags flags) {
284+
// Minimal support for lowered function types. These come up in
285+
// reflection as capture types. For the reflection library's
286+
// purposes, the only part that matters is the convention.
287+
FunctionTypeFlags funcFlags;
288+
switch (flags.getRepresentation()) {
289+
case Demangle::ImplFunctionRepresentation::Thick:
290+
case Demangle::ImplFunctionRepresentation::Closure:
291+
funcFlags = funcFlags.withConvention(FunctionMetadataConvention::Swift);
292+
break;
293+
case Demangle::ImplFunctionRepresentation::Thin:
294+
case Demangle::ImplFunctionRepresentation::Method:
295+
case Demangle::ImplFunctionRepresentation::ObjCMethod:
296+
case Demangle::ImplFunctionRepresentation::WitnessMethod:
297+
funcFlags = funcFlags.withConvention(FunctionMetadataConvention::Thin);
298+
break;
299+
case Demangle::ImplFunctionRepresentation::CFunctionPointer:
300+
funcFlags = funcFlags.withConvention(FunctionMetadataConvention::CFunctionPointer);
301+
break;
302+
case Demangle::ImplFunctionRepresentation::Block:
303+
funcFlags = funcFlags.withConvention(FunctionMetadataConvention::Block);
304+
break;
305+
}
306+
307+
auto result = createTupleType({}, "", false);
308+
return FunctionTypeRef::create(*this, {}, result, funcFlags);
309+
}
310+
278311
const ProtocolCompositionTypeRef *
279312
createProtocolCompositionType(ArrayRef<BuiltProtocolDecl> protocols,
280313
BuiltType superclass,

0 commit comments

Comments
 (0)