Skip to content

Commit f6c6c26

Browse files
committed
[Compile Time Constant Extraction] Add extraction of tuples
1 parent 31b1820 commit f6c6c26

File tree

3 files changed

+221
-86
lines changed

3 files changed

+221
-86
lines changed

include/swift/AST/ConstTypeInfo.h

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ class Type;
2727
/// in a type property initializer expression
2828
class CompileTimeValue {
2929
public:
30-
enum ValueKind { RawLiteral, InitCall, Builder, Dictionary, Runtime };
30+
enum ValueKind { RawLiteral, InitCall, Builder, Dictionary, Runtime, Tuple };
3131

3232
ValueKind getKind() const { return Kind; }
3333

@@ -104,6 +104,28 @@ class DictionaryValue : public CompileTimeValue {
104104
}
105105
};
106106

107+
struct TupleElement {
108+
Optional<std::string> Label;
109+
swift::Type Type;
110+
std::shared_ptr<CompileTimeValue> Value;
111+
};
112+
113+
/// A representation of a tuple and each tuple-element
114+
class TupleValue : public CompileTimeValue {
115+
public:
116+
TupleValue(std::vector<TupleElement> Elements)
117+
: CompileTimeValue(ValueKind::Tuple), Elements(Elements) {}
118+
119+
static bool classof(const CompileTimeValue *T) {
120+
return T->getKind() == ValueKind::Tuple;
121+
}
122+
123+
std::vector<TupleElement> getElements() const { return Elements; }
124+
125+
private:
126+
std::vector<TupleElement> Elements;
127+
};
128+
107129
/// A representation of an arbitrary value that does not fall under
108130
/// any of the above categories.
109131
class RuntimeValue : public CompileTimeValue {

lib/ConstExtract/ConstExtract.cpp

Lines changed: 110 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -128,69 +128,116 @@ static std::string extractLiteralOutput(Expr *expr) {
128128
return LiteralOutput;
129129
}
130130

131-
static std::shared_ptr<CompileTimeValue>
132-
extractPropertyInitializationValue(VarDecl *propertyDecl) {
133-
auto binding = propertyDecl->getParentPatternBinding();
134-
if (binding) {
135-
auto originalInit = binding->getOriginalInit(0);
136-
if (originalInit) {
137-
auto literalOutput = extractLiteralOutput(originalInit);
138-
if (!literalOutput.empty()) {
139-
return std::make_shared<RawLiteralValue>(literalOutput);
140-
}
131+
static std::shared_ptr<CompileTimeValue> extractCompileTimeValue(Expr *expr) {
132+
switch (expr->getKind()) {
133+
case ExprKind::Array:
134+
case ExprKind::Dictionary:
135+
case ExprKind::BooleanLiteral:
136+
case ExprKind::IntegerLiteral:
137+
case ExprKind::FloatLiteral:
138+
case ExprKind::NilLiteral:
139+
case ExprKind::StringLiteral: {
140+
std::string literalOutput;
141+
llvm::raw_string_ostream OutputStream(literalOutput);
142+
expr->printConstExprValue(&OutputStream, nullptr);
143+
144+
if (literalOutput.empty()) {
145+
return std::make_shared<RuntimeValue>();
146+
}
141147

142-
if (auto callExpr = dyn_cast<CallExpr>(originalInit)) {
143-
if (callExpr->getFn()->getKind() != ExprKind::ConstructorRefCall) {
144-
return std::make_shared<RuntimeValue>();
145-
}
148+
return std::make_shared<RawLiteralValue>(literalOutput);
149+
}
146150

147-
std::vector<FunctionParameter> parameters;
148-
const auto args = callExpr->getArgs();
149-
for (auto arg : *args) {
150-
auto label = arg.getLabel().str().str();
151-
auto expr = arg.getExpr();
151+
case ExprKind::Tuple: {
152+
auto tupleExpr = cast<TupleExpr>(expr);
152153

153-
switch (expr->getKind()) {
154-
case ExprKind::DefaultArgument: {
155-
auto defaultArgument = cast<DefaultArgumentExpr>(expr);
156-
auto *decl = defaultArgument->getParamDecl();
154+
std::vector<TupleElement> elements;
155+
if (tupleExpr->hasElementNames()) {
156+
for (auto pair :
157+
llvm::zip(tupleExpr->getElements(), tupleExpr->getElementNames())) {
158+
auto elementExpr = std::get<0>(pair);
159+
auto elementName = std::get<1>(pair);
157160

158-
if (decl->hasDefaultExpr()) {
159-
literalOutput =
160-
extractLiteralOutput(decl->getTypeCheckedDefaultExpr());
161-
}
161+
Optional<std::string> label =
162+
elementName.empty()
163+
? Optional<std::string>()
164+
: Optional<std::string>(elementName.str().str());
162165

163-
break;
164-
}
165-
default:
166-
literalOutput = extractLiteralOutput(expr);
167-
break;
168-
}
166+
elements.push_back({label, elementExpr->getType(),
167+
extractCompileTimeValue(elementExpr)});
168+
}
169+
} else {
170+
for (auto elementExpr : tupleExpr->getElements()) {
171+
elements.push_back({Optional<std::string>(), elementExpr->getType(),
172+
extractCompileTimeValue(elementExpr)});
173+
}
174+
}
175+
return std::make_shared<TupleValue>(elements);
176+
}
169177

170-
if (literalOutput.empty()) {
171-
parameters.push_back(
172-
{label, expr->getType(), std::make_shared<RuntimeValue>()});
173-
} else {
174-
parameters.push_back(
175-
{label, expr->getType(),
176-
std::make_shared<RawLiteralValue>(literalOutput)});
177-
}
178+
case ExprKind::Call: {
179+
auto callExpr = cast<CallExpr>(expr);
180+
181+
if (callExpr->getFn()->getKind() != ExprKind::ConstructorRefCall) {
182+
return std::make_shared<RuntimeValue>();
183+
}
184+
185+
std::vector<FunctionParameter> parameters;
186+
const auto args = callExpr->getArgs();
187+
for (auto arg : *args) {
188+
auto label = arg.getLabel().str().str();
189+
auto expr = arg.getExpr();
190+
191+
std::string literalOutput;
192+
switch (expr->getKind()) {
193+
case ExprKind::DefaultArgument: {
194+
auto defaultArgument = cast<DefaultArgumentExpr>(expr);
195+
auto *decl = defaultArgument->getParamDecl();
196+
197+
if (decl->hasDefaultExpr()) {
198+
literalOutput =
199+
extractLiteralOutput(decl->getTypeCheckedDefaultExpr());
178200
}
179201

180-
auto name = toFullyQualifiedTypeNameString(callExpr->getType());
181-
return std::make_shared<InitCallValue>(name, parameters);
202+
break;
203+
}
204+
default:
205+
literalOutput = extractLiteralOutput(expr);
206+
break;
207+
}
208+
209+
if (literalOutput.empty()) {
210+
parameters.push_back(
211+
{label, expr->getType(), std::make_shared<RuntimeValue>()});
212+
} else {
213+
parameters.push_back(
214+
{label, expr->getType(),
215+
std::make_shared<RawLiteralValue>(literalOutput)});
182216
}
183217
}
218+
219+
auto name = toFullyQualifiedTypeNameString(callExpr->getType());
220+
return std::make_shared<InitCallValue>(name, parameters);
221+
}
222+
223+
default:
224+
return std::make_shared<RuntimeValue>();
225+
}
226+
}
227+
228+
static std::shared_ptr<CompileTimeValue>
229+
extractPropertyInitializationValue(VarDecl *propertyDecl) {
230+
if (auto binding = propertyDecl->getParentPatternBinding()) {
231+
if (auto originalInit = binding->getOriginalInit(0)) {
232+
return extractCompileTimeValue(originalInit);
233+
}
184234
}
185235

186236
if (auto accessorDecl = propertyDecl->getAccessor(AccessorKind::Get)) {
187237
auto node = accessorDecl->getTypecheckedBody()->getFirstElement();
188238
if (node.is<Stmt *>()) {
189239
if (auto returnStmt = dyn_cast<ReturnStmt>(node.get<Stmt *>())) {
190-
auto expr = returnStmt->getResult();
191-
std::string LiteralOutput = extractLiteralOutput(expr);
192-
if (!LiteralOutput.empty())
193-
return std::make_shared<RawLiteralValue>(LiteralOutput);
240+
return extractCompileTimeValue(returnStmt->getResult());
194241
}
195242
}
196243
}
@@ -284,6 +331,22 @@ void writeValue(llvm::json::OStream &JSON,
284331
break;
285332
}
286333

334+
case CompileTimeValue::ValueKind::Tuple: {
335+
auto tupleValue = cast<TupleValue>(value);
336+
337+
JSON.attribute("valueKind", "Tuple");
338+
JSON.attributeArray("value", [&] {
339+
for (auto TV : tupleValue->getElements()) {
340+
JSON.object([&] {
341+
JSON.attribute("label", TV.Label);
342+
JSON.attribute("type", toFullyQualifiedTypeNameString(TV.Type));
343+
writeValue(JSON, TV.Value);
344+
});
345+
}
346+
});
347+
break;
348+
}
349+
287350
case CompileTimeValue::ValueKind::Builder: {
288351
JSON.attribute("valueKind", "Builder");
289352
break;

0 commit comments

Comments
 (0)