Skip to content

Commit 465634c

Browse files
Merge pull request #74491 from venkatesh5789/interpolated-string-extraction
[Compile Time Constant Extraction] Extract Interpolated String Literals
2 parents af36238 + 9820865 commit 465634c

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
@@ -287,13 +287,25 @@ static std::shared_ptr<CompileTimeValue> extractCompileTimeValue(Expr *expr) {
287287

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

296-
if (callExpr->getFn()->getKind() == ExprKind::DotSyntaxCall) {
308+
if (functionKind == ExprKind::DotSyntaxCall) {
297309
auto dotSyntaxCallExpr = cast<DotSyntaxCallExpr>(callExpr->getFn());
298310
auto fn = dotSyntaxCallExpr->getFn();
299311
if (fn->getKind() == ExprKind::DeclRef) {
@@ -409,6 +421,38 @@ static std::shared_ptr<CompileTimeValue> extractCompileTimeValue(Expr *expr) {
409421
return extractCompileTimeValue(injectIntoOptionalExpr->getSubExpr());
410422
}
411423

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

736-
case CompileTimeValue::KeyPath: {
737-
auto keyPathValue = cast<KeyPathValue>(value);
738-
JSON.attribute("valueKind", "KeyPath");
739-
JSON.attributeObject("value", [&]() {
740-
JSON.attribute("path", keyPathValue->getPath());
741-
JSON.attribute("rootType", toFullyQualifiedTypeNameString(keyPathValue->getRootType()));
742-
JSON.attributeArray("components", [&] {
743-
auto components = keyPathValue->getComponents();
744-
for (auto c : components) {
780+
case CompileTimeValue::ValueKind::KeyPath: {
781+
auto keyPathValue = cast<KeyPathValue>(value);
782+
JSON.attribute("valueKind", "KeyPath");
783+
JSON.attributeObject("value", [&]() {
784+
JSON.attribute("path", keyPathValue->getPath());
785+
JSON.attribute("rootType", toFullyQualifiedTypeNameString(
786+
keyPathValue->getRootType()));
787+
JSON.attributeArray("components", [&] {
788+
auto components = keyPathValue->getComponents();
789+
for (auto c : components) {
790+
JSON.object([&] {
791+
JSON.attribute("label", c.Label);
792+
JSON.attribute("type", toFullyQualifiedTypeNameString(c.Type));
793+
});
794+
}
795+
});
796+
});
797+
break;
798+
}
799+
800+
case CompileTimeValue::ValueKind::FunctionCall: {
801+
auto functionCallValue = cast<FunctionCallValue>(value);
802+
JSON.attribute("valueKind", "FunctionCall");
803+
JSON.attributeObject("value", [&]() {
804+
JSON.attribute("name", functionCallValue->getIdentifier());
805+
if (functionCallValue->getParameters().has_value()) {
806+
auto params = functionCallValue->getParameters().value();
807+
JSON.attributeArray("arguments", [&] {
808+
for (auto FP : params) {
745809
JSON.object([&] {
746-
JSON.attribute("label", c.Label);
747-
JSON.attribute("type", toFullyQualifiedTypeNameString(c.Type));
810+
JSON.attribute("label", FP.Label);
811+
JSON.attribute("type", toFullyQualifiedTypeNameString(FP.Type));
812+
writeValue(JSON, FP.Value);
748813
});
749814
}
750815
});
816+
}
817+
});
818+
break;
819+
}
820+
821+
case CompileTimeValue::ValueKind::MemberReference: {
822+
auto memberReferenceValue = cast<MemberReferenceValue>(value);
823+
JSON.attribute("valueKind", "MemberReference");
824+
JSON.attributeObject("value", [&]() {
825+
JSON.attribute("baseType", toFullyQualifiedTypeNameString(
826+
memberReferenceValue->getBaseType()));
827+
JSON.attribute("memberLabel", memberReferenceValue->getMemberLabel());
828+
});
829+
break;
830+
}
831+
case CompileTimeValue::ValueKind::InterpolatedString: {
832+
auto interpolatedStringValue = cast<InterpolatedStringLiteralValue>(value);
833+
JSON.attribute("valueKind", "InterpolatedStringLiteral");
834+
JSON.attributeObject("value", [&]() {
835+
JSON.attributeArray("segments", [&] {
836+
auto segments = interpolatedStringValue->getSegments();
837+
for (auto s : segments) {
838+
JSON.object([&] { writeValue(JSON, s); });
839+
}
751840
});
752-
break;
841+
});
842+
break;
753843
}
754844

755845
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)