Skip to content

Commit 8614aa3

Browse files
committed
[Compile Time Constant Extraction] Add extraction of property wrappers
1 parent 0b74e7b commit 8614aa3

File tree

4 files changed

+255
-12
lines changed

4 files changed

+255
-12
lines changed

include/swift/AST/ConstTypeInfo.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,9 +115,25 @@ class RuntimeValue : public CompileTimeValue {
115115
}
116116
};
117117

118+
struct CustomAttrValue {
119+
swift::Type Type;
120+
std::vector<FunctionParameter> Parameters;
121+
};
122+
118123
struct ConstValueTypePropertyInfo {
119124
swift::VarDecl *VarDecl;
120125
std::shared_ptr<CompileTimeValue> Value;
126+
llvm::Optional<std::vector<CustomAttrValue>> PropertyWrappers;
127+
128+
ConstValueTypePropertyInfo(
129+
swift::VarDecl *VarDecl, std::shared_ptr<CompileTimeValue> Value,
130+
llvm::Optional<std::vector<CustomAttrValue>> PropertyWrappers)
131+
: VarDecl(VarDecl), Value(Value), PropertyWrappers(PropertyWrappers) {}
132+
133+
ConstValueTypePropertyInfo(swift::VarDecl *VarDecl,
134+
std::shared_ptr<CompileTimeValue> Value)
135+
: VarDecl(VarDecl), Value(Value),
136+
PropertyWrappers(llvm::Optional<std::vector<CustomAttrValue>>()) {}
121137
};
122138

123139
struct ConstValueTypeInfo {

lib/ConstExtract/ConstExtract.cpp

Lines changed: 69 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -172,24 +172,57 @@ static std::shared_ptr<CompileTimeValue> extractCompileTimeValue(Expr *expr) {
172172
return std::make_shared<RuntimeValue>();
173173
}
174174

175-
static std::shared_ptr<CompileTimeValue>
176-
extractPropertyInitializationValue(VarDecl *propertyDecl) {
177-
if (auto binding = propertyDecl->getParentPatternBinding()) {
178-
if (auto originalInit = binding->getOriginalInit(0)) {
179-
return extractCompileTimeValue(originalInit);
175+
static std::vector<CustomAttrValue>
176+
extractCustomAttrValues(VarDecl *propertyDecl) {
177+
std::vector<CustomAttrValue> customAttrValues;
178+
179+
for (auto *propertyWrapper : propertyDecl->getAttachedPropertyWrappers()) {
180+
std::vector<FunctionParameter> parameters;
181+
182+
if (const auto *args = propertyWrapper->getArgs()) {
183+
for (auto arg : *args) {
184+
const auto label = arg.getLabel().str().str();
185+
auto argExpr = arg.getExpr();
186+
187+
if (auto defaultArgument = dyn_cast<DefaultArgumentExpr>(argExpr)) {
188+
auto *decl = defaultArgument->getParamDecl();
189+
if (decl->hasDefaultExpr()) {
190+
argExpr = decl->getTypeCheckedDefaultExpr();
191+
}
192+
}
193+
parameters.push_back(
194+
{label, argExpr->getType(), extractCompileTimeValue(argExpr)});
195+
}
196+
}
197+
customAttrValues.push_back({propertyWrapper->getType(), parameters});
198+
}
199+
200+
return customAttrValues;
201+
}
202+
203+
static ConstValueTypePropertyInfo
204+
extractPropertyTypeInfo(VarDecl *propertyDecl) {
205+
if (const auto binding = propertyDecl->getParentPatternBinding()) {
206+
if (const auto originalInit = binding->getOriginalInit(0)) {
207+
if (propertyDecl->hasAttachedPropertyWrapper()) {
208+
return {propertyDecl, extractCompileTimeValue(originalInit),
209+
extractCustomAttrValues(propertyDecl)};
210+
}
211+
212+
return {propertyDecl, extractCompileTimeValue(originalInit)};
180213
}
181214
}
182215

183216
if (auto accessorDecl = propertyDecl->getAccessor(AccessorKind::Get)) {
184217
auto node = accessorDecl->getTypecheckedBody()->getFirstElement();
185218
if (node.is<Stmt *>()) {
186219
if (auto returnStmt = dyn_cast<ReturnStmt>(node.get<Stmt *>())) {
187-
return extractCompileTimeValue(returnStmt->getResult());
220+
return {propertyDecl, extractCompileTimeValue(returnStmt->getResult())};
188221
}
189222
}
190223
}
191224

192-
return std::make_shared<RuntimeValue>();
225+
return {propertyDecl, std::make_shared<RuntimeValue>()};
193226
}
194227

195228
ConstValueTypeInfo
@@ -202,8 +235,7 @@ ConstantValueInfoRequest::evaluate(Evaluator &Evaluator,
202235

203236
std::vector<ConstValueTypePropertyInfo> Properties;
204237
for (auto Property : StoredProperties) {
205-
Properties.push_back(
206-
{Property, extractPropertyInitializationValue(Property)});
238+
Properties.push_back(extractPropertyTypeInfo(Property));
207239
}
208240

209241
for (auto Member : Decl->getMembers()) {
@@ -212,13 +244,13 @@ ConstantValueInfoRequest::evaluate(Evaluator &Evaluator,
212244
// instead gather up remaining static and computed properties.
213245
if (!VD || StoredPropertiesSet.count(VD))
214246
continue;
215-
Properties.push_back({VD, extractPropertyInitializationValue(VD)});
247+
Properties.push_back(extractPropertyTypeInfo(VD));
216248
}
217249

218250
for (auto Extension: Decl->getExtensions()) {
219251
for (auto Member : Extension->getMembers()) {
220252
if (auto *VD = dyn_cast<VarDecl>(Member)) {
221-
Properties.push_back({VD, extractPropertyInitializationValue(VD)});
253+
Properties.push_back(extractPropertyTypeInfo(VD));
222254
}
223255
}
224256
}
@@ -304,6 +336,31 @@ void writeValue(llvm::json::OStream &JSON,
304336
}
305337
}
306338

339+
void writeAttributes(
340+
llvm::json::OStream &JSON,
341+
llvm::Optional<std::vector<CustomAttrValue>> PropertyWrappers) {
342+
if (!PropertyWrappers.hasValue()) {
343+
return;
344+
}
345+
346+
JSON.attributeArray("attributes", [&] {
347+
for (auto PW : PropertyWrappers.value()) {
348+
JSON.object([&] {
349+
JSON.attribute("type", toFullyQualifiedTypeNameString(PW.Type));
350+
JSON.attributeArray("arguments", [&] {
351+
for (auto FP : PW.Parameters) {
352+
JSON.object([&] {
353+
JSON.attribute("label", FP.Label);
354+
JSON.attribute("type", toFullyQualifiedTypeNameString(FP.Type));
355+
writeValue(JSON, FP.Value);
356+
});
357+
}
358+
});
359+
});
360+
}
361+
});
362+
}
363+
307364
bool writeAsJSONToFile(const std::vector<ConstValueTypeInfo> &ConstValueInfos,
308365
llvm::raw_fd_ostream &OS) {
309366
llvm::json::OStream JSON(OS, 2);
@@ -327,6 +384,7 @@ bool writeAsJSONToFile(const std::vector<ConstValueTypeInfo> &ConstValueInfos,
327384
JSON.attribute("isComputed",
328385
!decl->hasStorage() ? "true" : "false");
329386
writeValue(JSON, PropertyInfo.Value);
387+
writeAttributes(JSON, PropertyInfo.PropertyWrappers);
330388
});
331389
}
332390
});

test/ConstExtraction/ExtractCalls.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,6 @@ public struct Foo : MyProto {
9898
let func1: Int = adder(2, 3)
9999
}
100100

101-
102101
extension Foo {
103102
struct Boo {}
104103

test/ConstExtraction/ExtractLiterals.swift

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,119 @@
8484
// CHECK-NEXT: "value": "\"Hello, World\""
8585
// CHECK-NEXT: }
8686
// CHECK-NEXT: ]
87+
// CHECK-NEXT: },
88+
// CHECK-NEXT: {
89+
// CHECK-NEXT: "typeName": "ExtractLiterals.PropertyWrappers",
90+
// CHECK-NEXT: "kind": "struct",
91+
// CHECK-NEXT: "properties": [
92+
// CHECK-NEXT: {
93+
// CHECK-NEXT: "label": "_propertyWrapper1",
94+
// CHECK-NEXT: "type": "ExtractLiterals.Buffered<Swift.String>",
95+
// CHECK-NEXT: "isStatic": "false",
96+
// CHECK-NEXT: "isComputed": "false",
97+
// CHECK-NEXT: "valueKind": "Runtime"
98+
// CHECK-NEXT: },
99+
// CHECK-NEXT: {
100+
// CHECK-NEXT: "label": "_propertyWrapper2",
101+
// CHECK-NEXT: "type": "ExtractLiterals.Clamping<Swift.Int>",
102+
// CHECK-NEXT: "isStatic": "false",
103+
// CHECK-NEXT: "isComputed": "false",
104+
// CHECK-NEXT: "valueKind": "Runtime"
105+
// CHECK-NEXT: },
106+
// CHECK-NEXT: {
107+
// CHECK-NEXT: "label": "_propertyWrapper3",
108+
// CHECK-NEXT: "type": "ExtractLiterals.Buffered<ExtractLiterals.Clamping<Swift.Int>>",
109+
// CHECK-NEXT: "isStatic": "false",
110+
// CHECK-NEXT: "isComputed": "false",
111+
// CHECK-NEXT: "valueKind": "Runtime"
112+
// CHECK-NEXT: },
113+
// CHECK-NEXT: {
114+
// CHECK-NEXT: "label": "propertyWrapper1",
115+
// CHECK-NEXT: "type": "Swift.String",
116+
// CHECK-NEXT: "isStatic": "false",
117+
// CHECK-NEXT: "isComputed": "true",
118+
// CHECK-NEXT: "valueKind": "RawLiteral",
119+
// CHECK-NEXT: "value": "\"Hello\"",
120+
// CHECK-NEXT: "attributes": [
121+
// CHECK-NEXT: {
122+
// CHECK-NEXT: "type": "ExtractLiterals.Buffered",
123+
// CHECK-NEXT: "arguments": []
124+
// CHECK-NEXT: }
125+
// CHECK-NEXT: ]
126+
// CHECK-NEXT: },
127+
// CHECK-NEXT: {
128+
// CHECK-NEXT: "label": "$propertyWrapper1",
129+
// CHECK-NEXT: "type": "(Swift.String, Swift.String?)",
130+
// CHECK-NEXT: "isStatic": "false",
131+
// CHECK-NEXT: "isComputed": "true",
132+
// CHECK-NEXT: "valueKind": "Runtime"
133+
// CHECK-NEXT: },
134+
// CHECK-NEXT: {
135+
// CHECK-NEXT: "label": "propertyWrapper2",
136+
// CHECK-NEXT: "type": "Swift.Int",
137+
// CHECK-NEXT: "isStatic": "false",
138+
// CHECK-NEXT: "isComputed": "true",
139+
// CHECK-NEXT: "valueKind": "RawLiteral",
140+
// CHECK-NEXT: "value": "128",
141+
// CHECK-NEXT: "attributes": [
142+
// CHECK-NEXT: {
143+
// CHECK-NEXT: "type": "ExtractLiterals.Clamping",
144+
// CHECK-NEXT: "arguments": [
145+
// CHECK-NEXT: {
146+
// CHECK-NEXT: "label": "min",
147+
// CHECK-NEXT: "type": "Swift.Int",
148+
// CHECK-NEXT: "valueKind": "RawLiteral",
149+
// CHECK-NEXT: "value": "0"
150+
// CHECK-NEXT: },
151+
// CHECK-NEXT: {
152+
// CHECK-NEXT: "label": "max",
153+
// CHECK-NEXT: "type": "Swift.Int",
154+
// CHECK-NEXT: "valueKind": "RawLiteral",
155+
// CHECK-NEXT: "value": "255"
156+
// CHECK-NEXT: }
157+
// CHECK-NEXT: ]
158+
// CHECK-NEXT: }
159+
// CHECK-NEXT: ]
160+
// CHECK-NEXT: },
161+
// CHECK-NEXT: {
162+
// CHECK-NEXT: "label": "propertyWrapper3",
163+
// CHECK-NEXT: "type": "Swift.Int",
164+
// CHECK-NEXT: "isStatic": "false",
165+
// CHECK-NEXT: "isComputed": "true",
166+
// CHECK-NEXT: "valueKind": "RawLiteral",
167+
// CHECK-NEXT: "value": "128",
168+
// CHECK-NEXT: "attributes": [
169+
// CHECK-NEXT: {
170+
// CHECK-NEXT: "type": "ExtractLiterals.Buffered",
171+
// CHECK-NEXT: "arguments": []
172+
// CHECK-NEXT: },
173+
// CHECK-NEXT: {
174+
// CHECK-NEXT: "type": "ExtractLiterals.Clamping",
175+
// CHECK-NEXT: "arguments": [
176+
// CHECK-NEXT: {
177+
// CHECK-NEXT: "label": "min",
178+
// CHECK-NEXT: "type": "Swift.Int",
179+
// CHECK-NEXT: "valueKind": "RawLiteral",
180+
// CHECK-NEXT: "value": "0"
181+
// CHECK-NEXT: },
182+
// CHECK-NEXT: {
183+
// CHECK-NEXT: "label": "max",
184+
// CHECK-NEXT: "type": "Swift.Int",
185+
// CHECK-NEXT: "valueKind": "RawLiteral",
186+
// CHECK-NEXT: "value": "255"
187+
// CHECK-NEXT: }
188+
// CHECK-NEXT: ]
189+
// CHECK-NEXT: }
190+
// CHECK-NEXT: ]
191+
// CHECK-NEXT: },
192+
// CHECK-NEXT: {
193+
// CHECK-NEXT: "label": "$propertyWrapper3",
194+
// CHECK-NEXT: "type": "(ExtractLiterals.Clamping<Swift.Int>, ExtractLiterals.Clamping<Swift.Int>?)",
195+
// CHECK-NEXT: "isStatic": "false",
196+
// CHECK-NEXT: "isComputed": "true",
197+
// CHECK-NEXT: "valueKind": "Runtime"
198+
// CHECK-NEXT: }
199+
// CHECK-NEXT: ]
87200
// CHECK-NEXT: }
88201
// CHECK-NEXT:]
89202

@@ -107,3 +220,60 @@ public struct Floats : MyProto {
107220
public struct Strings : MyProto {
108221
let string1: String = "Hello, World"
109222
}
223+
224+
public struct PropertyWrappers : MyProto {
225+
@Buffered
226+
var propertyWrapper1: String = "Hello"
227+
228+
@Clamping(min: 0, max: 255)
229+
var propertyWrapper2: Int = 128
230+
231+
@Buffered @Clamping(min: 0, max: 255)
232+
var propertyWrapper3: Int = 128
233+
}
234+
235+
@propertyWrapper
236+
struct Clamping<V: Comparable> {
237+
var value: V
238+
let min: V
239+
let max: V
240+
241+
init(wrappedValue: V, min: V, max: V) {
242+
self.value = wrappedValue
243+
self.min = min
244+
self.max = max
245+
}
246+
247+
var wrappedValue: V {
248+
get { return self.value }
249+
set {
250+
if newValue < self.min {
251+
self.value = self.min
252+
} else if newValue > self.max {
253+
self.value = self.max
254+
} else {
255+
self.value = newValue
256+
}
257+
}
258+
}
259+
}
260+
261+
@propertyWrapper
262+
struct Buffered<V> {
263+
var value: V
264+
var lastValue: V?
265+
266+
init(wrappedValue: V) {
267+
self.value = wrappedValue
268+
}
269+
270+
var wrappedValue: V {
271+
get { return value }
272+
set {
273+
self.lastValue = self.value
274+
self.value = newValue
275+
}
276+
}
277+
278+
var projectedValue: (V, V?) { (self.value, self.lastValue) }
279+
}

0 commit comments

Comments
 (0)