Skip to content

Commit 9820865

Browse files
author
Venkatesh Sriram
committed
[Compile Time Constant Extraction] Extract Interpolated String Literals
1 parent da65626 commit 9820865

File tree

5 files changed

+352
-18
lines changed

5 files changed

+352
-18
lines changed

include/swift/AST/ConstTypeInfo.h

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ class CompileTimeValue {
3838
Enum,
3939
Type,
4040
KeyPath,
41+
FunctionCall,
42+
MemberReference,
43+
InterpolatedString,
4144
Runtime
4245
};
4346

@@ -185,7 +188,7 @@ class EnumValue : public CompileTimeValue {
185188
std::optional<std::vector<FunctionParameter>> Parameters;
186189
};
187190

188-
/// An type value representation
191+
/// A type value representation
189192
class TypeValue : public CompileTimeValue {
190193
public:
191194
TypeValue(swift::Type Type) : CompileTimeValue(ValueKind::Type), Type(Type) {}
@@ -228,6 +231,68 @@ class KeyPathValue : public CompileTimeValue {
228231
std::vector<Component> Components;
229232
};
230233

234+
/// A function call representation. This is for a function declaration such as
235+
/// let foo = bar(baz: "abc")
236+
class FunctionCallValue : public CompileTimeValue {
237+
public:
238+
FunctionCallValue(std::string Identifier,
239+
std::optional<std::vector<FunctionParameter>> Parameters)
240+
: CompileTimeValue(ValueKind::FunctionCall), Identifier(Identifier),
241+
Parameters(Parameters) {}
242+
243+
std::string getIdentifier() const { return Identifier; }
244+
std::optional<std::vector<FunctionParameter>> getParameters() const {
245+
return Parameters;
246+
}
247+
248+
static bool classof(const CompileTimeValue *T) {
249+
return T->getKind() == ValueKind::FunctionCall;
250+
}
251+
252+
private:
253+
std::string Identifier;
254+
std::optional<std::vector<FunctionParameter>> Parameters;
255+
};
256+
257+
/// A member reference representation such as
258+
/// let foo = MyStruct.bar
259+
class MemberReferenceValue : public CompileTimeValue {
260+
public:
261+
MemberReferenceValue(swift::Type BaseType, std::string MemberLabel)
262+
: CompileTimeValue(ValueKind::MemberReference), BaseType(BaseType),
263+
MemberLabel(MemberLabel) {}
264+
265+
std::string getMemberLabel() const { return MemberLabel; }
266+
swift::Type getBaseType() const { return BaseType; }
267+
268+
static bool classof(const CompileTimeValue *T) {
269+
return T->getKind() == ValueKind::MemberReference;
270+
}
271+
272+
private:
273+
swift::Type BaseType;
274+
std::string MemberLabel;
275+
};
276+
277+
/// A representation of an Interpolated String Literal
278+
class InterpolatedStringLiteralValue : public CompileTimeValue {
279+
public:
280+
InterpolatedStringLiteralValue(
281+
std::vector<std::shared_ptr<CompileTimeValue>> Segments)
282+
: CompileTimeValue(ValueKind::InterpolatedString), Segments(Segments) {}
283+
284+
std::vector<std::shared_ptr<CompileTimeValue>> getSegments() const {
285+
return Segments;
286+
}
287+
288+
static bool classof(const CompileTimeValue *T) {
289+
return T->getKind() == ValueKind::InterpolatedString;
290+
}
291+
292+
private:
293+
std::vector<std::shared_ptr<CompileTimeValue>> Segments;
294+
};
295+
231296
/// A representation of an arbitrary value that does not fall under
232297
/// any of the above categories.
233298
class RuntimeValue : public CompileTimeValue {

lib/ConstExtract/ConstExtract.cpp

Lines changed: 104 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -286,13 +286,25 @@ static std::shared_ptr<CompileTimeValue> extractCompileTimeValue(Expr *expr) {
286286

287287
case ExprKind::Call: {
288288
auto callExpr = cast<CallExpr>(expr);
289-
if (callExpr->getFn()->getKind() == ExprKind::ConstructorRefCall) {
289+
auto functionKind = callExpr->getFn()->getKind();
290+
291+
if (functionKind == ExprKind::DeclRef) {
292+
auto declRefExpr = cast<DeclRefExpr>(callExpr->getFn());
293+
auto caseName =
294+
declRefExpr->getDecl()->getName().getBaseIdentifier().str().str();
295+
296+
std::vector<FunctionParameter> parameters =
297+
extractFunctionArguments(callExpr->getArgs());
298+
return std::make_shared<FunctionCallValue>(caseName, parameters);
299+
}
300+
301+
if (functionKind == ExprKind::ConstructorRefCall) {
290302
std::vector<FunctionParameter> parameters =
291303
extractFunctionArguments(callExpr->getArgs());
292304
return std::make_shared<InitCallValue>(callExpr->getType(), parameters);
293305
}
294306

295-
if (callExpr->getFn()->getKind() == ExprKind::DotSyntaxCall) {
307+
if (functionKind == ExprKind::DotSyntaxCall) {
296308
auto dotSyntaxCallExpr = cast<DotSyntaxCallExpr>(callExpr->getFn());
297309
auto fn = dotSyntaxCallExpr->getFn();
298310
if (fn->getKind() == ExprKind::DeclRef) {
@@ -408,6 +420,38 @@ static std::shared_ptr<CompileTimeValue> extractCompileTimeValue(Expr *expr) {
408420
return extractCompileTimeValue(injectIntoOptionalExpr->getSubExpr());
409421
}
410422

423+
case ExprKind::Load: {
424+
auto loadExpr = cast<LoadExpr>(expr);
425+
return extractCompileTimeValue(loadExpr->getSubExpr());
426+
}
427+
428+
case ExprKind::MemberRef: {
429+
auto memberExpr = cast<MemberRefExpr>(expr);
430+
if (isa<TypeExpr>(memberExpr->getBase())) {
431+
auto baseTypeExpr = cast<TypeExpr>(memberExpr->getBase());
432+
auto label = memberExpr->getDecl().getDecl()->getBaseIdentifier().str();
433+
return std::make_shared<MemberReferenceValue>(
434+
baseTypeExpr->getInstanceType(), label.str());
435+
}
436+
break;
437+
}
438+
439+
case ExprKind::InterpolatedStringLiteral: {
440+
auto interpolatedStringExpr = cast<InterpolatedStringLiteralExpr>(expr);
441+
auto tapExpr = interpolatedStringExpr->getAppendingExpr();
442+
auto &Ctx = tapExpr->getVar()->getASTContext();
443+
444+
std::vector<std::shared_ptr<CompileTimeValue>> segments;
445+
interpolatedStringExpr->forEachSegment(
446+
Ctx, [&](bool isInterpolation, CallExpr *segment) -> void {
447+
auto arg = segment->getArgs()->get(0);
448+
auto expr = arg.getExpr();
449+
segments.push_back(extractCompileTimeValue(expr));
450+
});
451+
452+
return std::make_shared<InterpolatedStringLiteralValue>(segments);
453+
}
454+
411455
default: {
412456
break;
413457
}
@@ -725,23 +769,69 @@ void writeValue(llvm::json::OStream &JSON,
725769
break;
726770
}
727771

728-
case CompileTimeValue::KeyPath: {
729-
auto keyPathValue = cast<KeyPathValue>(value);
730-
JSON.attribute("valueKind", "KeyPath");
731-
JSON.attributeObject("value", [&]() {
732-
JSON.attribute("path", keyPathValue->getPath());
733-
JSON.attribute("rootType", toFullyQualifiedTypeNameString(keyPathValue->getRootType()));
734-
JSON.attributeArray("components", [&] {
735-
auto components = keyPathValue->getComponents();
736-
for (auto c : components) {
772+
case CompileTimeValue::ValueKind::KeyPath: {
773+
auto keyPathValue = cast<KeyPathValue>(value);
774+
JSON.attribute("valueKind", "KeyPath");
775+
JSON.attributeObject("value", [&]() {
776+
JSON.attribute("path", keyPathValue->getPath());
777+
JSON.attribute("rootType", toFullyQualifiedTypeNameString(
778+
keyPathValue->getRootType()));
779+
JSON.attributeArray("components", [&] {
780+
auto components = keyPathValue->getComponents();
781+
for (auto c : components) {
782+
JSON.object([&] {
783+
JSON.attribute("label", c.Label);
784+
JSON.attribute("type", toFullyQualifiedTypeNameString(c.Type));
785+
});
786+
}
787+
});
788+
});
789+
break;
790+
}
791+
792+
case CompileTimeValue::ValueKind::FunctionCall: {
793+
auto functionCallValue = cast<FunctionCallValue>(value);
794+
JSON.attribute("valueKind", "FunctionCall");
795+
JSON.attributeObject("value", [&]() {
796+
JSON.attribute("name", functionCallValue->getIdentifier());
797+
if (functionCallValue->getParameters().has_value()) {
798+
auto params = functionCallValue->getParameters().value();
799+
JSON.attributeArray("arguments", [&] {
800+
for (auto FP : params) {
737801
JSON.object([&] {
738-
JSON.attribute("label", c.Label);
739-
JSON.attribute("type", toFullyQualifiedTypeNameString(c.Type));
802+
JSON.attribute("label", FP.Label);
803+
JSON.attribute("type", toFullyQualifiedTypeNameString(FP.Type));
804+
writeValue(JSON, FP.Value);
740805
});
741806
}
742807
});
808+
}
809+
});
810+
break;
811+
}
812+
813+
case CompileTimeValue::ValueKind::MemberReference: {
814+
auto memberReferenceValue = cast<MemberReferenceValue>(value);
815+
JSON.attribute("valueKind", "MemberReference");
816+
JSON.attributeObject("value", [&]() {
817+
JSON.attribute("baseType", toFullyQualifiedTypeNameString(
818+
memberReferenceValue->getBaseType()));
819+
JSON.attribute("memberLabel", memberReferenceValue->getMemberLabel());
820+
});
821+
break;
822+
}
823+
case CompileTimeValue::ValueKind::InterpolatedString: {
824+
auto interpolatedStringValue = cast<InterpolatedStringLiteralValue>(value);
825+
JSON.attribute("valueKind", "InterpolatedStringLiteral");
826+
JSON.attributeObject("value", [&]() {
827+
JSON.attributeArray("segments", [&] {
828+
auto segments = interpolatedStringValue->getSegments();
829+
for (auto s : segments) {
830+
JSON.object([&] { writeValue(JSON, s); });
831+
}
743832
});
744-
break;
833+
});
834+
break;
745835
}
746836

747837
case CompileTimeValue::ValueKind::Runtime: {

test/ConstExtraction/ExtractCalls.swift

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,24 @@ public struct Bat {
110110
// CHECK-NEXT: {
111111
// CHECK-NEXT: "label": "fuz",
112112
// CHECK-NEXT: "type": "Swift.Int",
113-
// CHECK-NEXT: "valueKind": "Runtime"
113+
// CHECK-NEXT: "valueKind": "FunctionCall",
114+
// CHECK-NEXT: "value": {
115+
// CHECK-NEXT: "name": "adder",
116+
// CHECK-NEXT: "arguments": [
117+
// CHECK-NEXT: {
118+
// CHECK-NEXT: "label": "",
119+
// CHECK-NEXT: "type": "Swift.Int",
120+
// CHECK-NEXT: "valueKind": "RawLiteral",
121+
// CHECK-NEXT: "value": "2"
122+
// CHECK-NEXT: },
123+
// CHECK-NEXT: {
124+
// CHECK-NEXT: "label": "",
125+
// CHECK-NEXT: "type": "Swift.Int",
126+
// CHECK-NEXT: "valueKind": "RawLiteral",
127+
// CHECK-NEXT: "value": "3"
128+
// CHECK-NEXT: }
129+
// CHECK-NEXT: ]
130+
// CHECK-NEXT: }
114131
// CHECK-NEXT: }
115132
// CHECK-NEXT: ]
116133
// CHECK-NEXT: }
@@ -123,7 +140,24 @@ public struct Bat {
123140
// CHECK-NEXT: "isComputed": "false",
124141
// CHECK-NEXT: "file": "{{.*}}test{{/|\\\\}}ConstExtraction{{/|\\\\}}ExtractCalls.swift",
125142
// CHECK-NEXT: "line": 15,
126-
// CHECK-NEXT: "valueKind": "Runtime"
143+
// CHECK-NEXT: "valueKind": "FunctionCall",
144+
// CHECK-NEXT: "value": {
145+
// CHECK-NEXT: "name": "adder",
146+
// CHECK-NEXT: "arguments": [
147+
// CHECK-NEXT: {
148+
// CHECK-NEXT: "label": "",
149+
// CHECK-NEXT: "type": "Swift.Int",
150+
// CHECK-NEXT: "valueKind": "RawLiteral",
151+
// CHECK-NEXT: "value": "2"
152+
// CHECK-NEXT: },
153+
// CHECK-NEXT: {
154+
// CHECK-NEXT: "label": "",
155+
// CHECK-NEXT: "type": "Swift.Int",
156+
// CHECK-NEXT: "valueKind": "RawLiteral",
157+
// CHECK-NEXT: "value": "3"
158+
// CHECK-NEXT: }
159+
// CHECK-NEXT: ]
160+
// CHECK-NEXT: }
127161
// CHECK-NEXT: },
128162
// CHECK-NEXT: {
129163
// CHECK-NEXT: "label": "init4",

test/ConstExtraction/ExtractEnums.swift

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,17 @@ public struct Enums: MyProto {
4848
// CHECK-NEXT: "mangledTypeName": "n/a - deprecated",
4949
// CHECK-NEXT: "isStatic": "false",
5050
// CHECK-NEXT: "isComputed": "true",
51-
// CHECK-NEXT: "valueKind": "Runtime"
51+
// CHECK-NEXT: "valueKind": "FunctionCall",
52+
// CHECK-NEXT: "value": {
53+
// CHECK-NEXT: "name": "_hashValue",
54+
// CHECK-NEXT: "arguments": [
55+
// CHECK-NEXT: {
56+
// CHECK-NEXT: "label": "for",
57+
// CHECK-NEXT: "type": "ExtractEnums.SimpleEnum",
58+
// CHECK-NEXT: "valueKind": "Runtime"
59+
// CHECK-NEXT: }
60+
// CHECK-NEXT: ]
61+
// CHECK-NEXT: }
5262
// CHECK-NEXT: }
5363
// CHECK-NEXT: ],
5464
// CHECK-NEXT: "cases": [

0 commit comments

Comments
 (0)