Skip to content

Commit e26e2a6

Browse files
authored
Merge pull request #83008 from justin-s-kang/open-existential-extraction
[Compile Time Constant Extraction] Support for open existential expressions
2 parents 61cb1a9 + dfe8a46 commit e26e2a6

File tree

3 files changed

+102
-18
lines changed

3 files changed

+102
-18
lines changed

lib/ConstExtract/ConstExtract.cpp

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -302,10 +302,8 @@ extractCompileTimeValue(Expr *expr, const DeclContext *declContext) {
302302

303303
case ExprKind::Call: {
304304
auto callExpr = cast<CallExpr>(expr);
305-
auto functionKind = callExpr->getFn()->getKind();
306305

307-
if (functionKind == ExprKind::DeclRef) {
308-
auto declRefExpr = cast<DeclRefExpr>(callExpr->getFn());
306+
if (auto declRefExpr = dyn_cast<DeclRefExpr>(callExpr->getFn())) {
309307
auto identifier =
310308
declRefExpr->getDecl()->getName().getBaseIdentifier().str().str();
311309

@@ -314,17 +312,15 @@ extractCompileTimeValue(Expr *expr, const DeclContext *declContext) {
314312
return std::make_shared<FunctionCallValue>(identifier, parameters);
315313
}
316314

317-
if (functionKind == ExprKind::ConstructorRefCall) {
315+
if (auto constructorRefCall = dyn_cast<ConstructorRefCallExpr>(callExpr->getFn())) {
318316
std::vector<FunctionParameter> parameters =
319317
extractFunctionArguments(callExpr->getArgs(), declContext);
320318
return std::make_shared<InitCallValue>(callExpr->getType(), parameters);
321319
}
322320

323-
if (functionKind == ExprKind::DotSyntaxCall) {
324-
auto dotSyntaxCallExpr = cast<DotSyntaxCallExpr>(callExpr->getFn());
321+
if (auto dotSyntaxCallExpr = dyn_cast<DotSyntaxCallExpr>(callExpr->getFn())) {
325322
auto fn = dotSyntaxCallExpr->getFn();
326-
if (fn->getKind() == ExprKind::DeclRef) {
327-
auto declRefExpr = cast<DeclRefExpr>(fn);
323+
if (auto declRefExpr = dyn_cast<DeclRefExpr>(fn)) {
328324
auto baseIdentifierName =
329325
declRefExpr->getDecl()->getName().getBaseIdentifier().str().str();
330326

@@ -355,14 +351,24 @@ extractCompileTimeValue(Expr *expr, const DeclContext *declContext) {
355351
}
356352
}
357353

354+
if (auto functionConversionExpr = dyn_cast<FunctionConversionExpr>(callExpr->getFn())) {
355+
if (auto declRefExpr = dyn_cast<DeclRefExpr>(functionConversionExpr->getSubExpr())) {
356+
auto identifier =
357+
declRefExpr->getDecl()->getName().getBaseIdentifier().str().str();
358+
359+
std::vector<FunctionParameter> parameters =
360+
extractFunctionArguments(callExpr->getArgs(), declContext);
361+
return std::make_shared<FunctionCallValue>(identifier, parameters);
362+
}
363+
}
364+
358365
break;
359366
}
360367

361368
case ExprKind::DotSyntaxCall: {
362369
auto dotSyntaxCallExpr = cast<DotSyntaxCallExpr>(expr);
363370
auto fn = dotSyntaxCallExpr->getFn();
364-
if (fn->getKind() == ExprKind::DeclRef) {
365-
auto declRefExpr = cast<DeclRefExpr>(fn);
371+
if (auto declRefExpr = dyn_cast<DeclRefExpr>(fn)) {
366372
auto caseName =
367373
declRefExpr->getDecl()->getName().getBaseIdentifier().str().str();
368374
return std::make_shared<EnumValue>(caseName, std::nullopt);
@@ -507,6 +513,12 @@ extractCompileTimeValue(Expr *expr, const DeclContext *declContext) {
507513
auto derivedExpr = cast<DerivedToBaseExpr>(expr);
508514
return extractCompileTimeValue(derivedExpr->getSubExpr(), declContext);
509515
}
516+
517+
case ExprKind::OpenExistential: {
518+
auto openExistentialExpr = cast<OpenExistentialExpr>(expr);
519+
return extractCompileTimeValue(openExistentialExpr->getExistentialValue(), declContext);
520+
}
521+
510522
default: {
511523
break;
512524
}

test/ConstExtraction/ExtractKeyPaths.swift

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
// RUN: %empty-directory(%t)
22
// RUN: echo "[MyProto]" > %t/protocols.json
33

4-
// RUN: %target-swift-frontend -typecheck -emit-const-values-path %t/ExtractKeyPaths.swiftconstvalues -const-gather-protocols-file %t/protocols.json -primary-file %s
4+
// RUN: %target-swift-frontend -enable-upcoming-feature InferSendableFromCaptures -typecheck -emit-const-values-path %t/ExtractKeyPaths.swiftconstvalues -const-gather-protocols-file %t/protocols.json -primary-file %s
55
// RUN: cat %t/ExtractKeyPaths.swiftconstvalues 2>&1 | %FileCheck %s
66

7+
// REQUIRES: swift_feature_InferSendableFromCaptures
8+
79
protocol MyProto {}
810

911
public struct MyType {
@@ -59,7 +61,7 @@ public struct KeyPaths: MyProto {
5961
// CHECK-NEXT: "isStatic": "true",
6062
// CHECK-NEXT: "isComputed": "false",
6163
// CHECK-NEXT: "file": "{{.*}}test{{/|\\\\}}ConstExtraction{{/|\\\\}}ExtractKeyPaths.swift",
62-
// CHECK-NEXT: "line": 31,
64+
// CHECK-NEXT: "line": 33,
6365
// CHECK-NEXT: "valueKind": "KeyPath",
6466
// CHECK-NEXT: "value": {
6567
// CHECK-NEXT: "path": "foo",
@@ -79,7 +81,7 @@ public struct KeyPaths: MyProto {
7981
// CHECK-NEXT: "isStatic": "true",
8082
// CHECK-NEXT: "isComputed": "false",
8183
// CHECK-NEXT: "file": "{{.*}}test{{/|\\\\}}ConstExtraction{{/|\\\\}}ExtractKeyPaths.swift",
82-
// CHECK-NEXT: "line": 32,
84+
// CHECK-NEXT: "line": 34,
8385
// CHECK-NEXT: "valueKind": "KeyPath",
8486
// CHECK-NEXT: "value": {
8587
// CHECK-NEXT: "path": "foo",
@@ -99,7 +101,7 @@ public struct KeyPaths: MyProto {
99101
// CHECK-NEXT: "isStatic": "true",
100102
// CHECK-NEXT: "isComputed": "false",
101103
// CHECK-NEXT: "file": "{{.*}}test{{/|\\\\}}ConstExtraction{{/|\\\\}}ExtractKeyPaths.swift",
102-
// CHECK-NEXT: "line": 33,
104+
// CHECK-NEXT: "line": 35,
103105
// CHECK-NEXT: "valueKind": "KeyPath",
104106
// CHECK-NEXT: "value": {
105107
// CHECK-NEXT: "path": "foo",
@@ -119,7 +121,7 @@ public struct KeyPaths: MyProto {
119121
// CHECK-NEXT: "isStatic": "true",
120122
// CHECK-NEXT: "isComputed": "false",
121123
// CHECK-NEXT: "file": "{{.*}}test{{/|\\\\}}ConstExtraction{{/|\\\\}}ExtractKeyPaths.swift",
122-
// CHECK-NEXT: "line": 34,
124+
// CHECK-NEXT: "line": 36,
123125
// CHECK-NEXT: "valueKind": "KeyPath",
124126
// CHECK-NEXT: "value": {
125127
// CHECK-NEXT: "path": "bar",
@@ -139,7 +141,7 @@ public struct KeyPaths: MyProto {
139141
// CHECK-NEXT: "isStatic": "true",
140142
// CHECK-NEXT: "isComputed": "false",
141143
// CHECK-NEXT: "file": "{{.*}}test{{/|\\\\}}ConstExtraction{{/|\\\\}}ExtractKeyPaths.swift",
142-
// CHECK-NEXT: "line": 35,
144+
// CHECK-NEXT: "line": 37,
143145
// CHECK-NEXT: "valueKind": "KeyPath",
144146
// CHECK-NEXT: "value": {
145147
// CHECK-NEXT: "path": "bar",
@@ -154,12 +156,12 @@ public struct KeyPaths: MyProto {
154156
// CHECK-NEXT: },
155157
// CHECK-NEXT: {
156158
// CHECK-NEXT: "label": "nestedKeyPath",
157-
// CHECK-NEXT: "type": "Swift.WritableKeyPath<ExtractKeyPaths.MyType, Swift.String>",
159+
// CHECK-NEXT: "type": "any Swift.WritableKeyPath<ExtractKeyPaths.MyType, Swift.String> & Swift.Sendable",
158160
// CHECK-NEXT: "mangledTypeName": "n/a - deprecated",
159161
// CHECK-NEXT: "isStatic": "true",
160162
// CHECK-NEXT: "isComputed": "false",
161163
// CHECK-NEXT: "file": "{{.*}}test{{/|\\\\}}ConstExtraction{{/|\\\\}}ExtractKeyPaths.swift",
162-
// CHECK-NEXT: "line": 36,
164+
// CHECK-NEXT: "line": 38,
163165
// CHECK-NEXT: "valueKind": "KeyPath",
164166
// CHECK-NEXT: "value": {
165167
// CHECK-NEXT: "path": "nested.foo.bar.baz",
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: echo "[MyProto]" > %t/protocols.json
3+
4+
// RUN: %target-swift-frontend -typecheck -emit-const-values-path %t/ExtractOpenExistential.swiftconstvalues -const-gather-protocols-file %t/protocols.json -primary-file %s
5+
// RUN: cat %t/ExtractOpenExistential.swiftconstvalues 2>&1 | %FileCheck %s
6+
7+
protocol MyProto {}
8+
9+
protocol ExampleProtocol {
10+
var protocolProperty: String { get }
11+
}
12+
13+
struct ConcreteType: ExampleProtocol {
14+
let protocolProperty: String = "Concrete implementation"
15+
}
16+
17+
func useExistential(_ example: any ExampleProtocol) -> String {
18+
return example.protocolProperty
19+
}
20+
21+
public struct External: MyProto {
22+
static let existentialValue = useExistential(ConcreteType())
23+
}
24+
25+
26+
// CHECK: [
27+
// CHECK-NEXT: {
28+
// CHECK-NEXT: "typeName": "ExtractOpenExistential.External",
29+
// CHECK-NEXT: "mangledTypeName": "22ExtractOpenExistential8ExternalV",
30+
// CHECK-NEXT: "kind": "struct",
31+
// CHECK-NEXT: "file": "{{.*}}test{{/|\\\\}}ConstExtraction{{/|\\\\}}ExtractOpenExistential.swift",
32+
// CHECK-NEXT: "line": 21,
33+
// CHECK-NEXT: "conformances": [
34+
// CHECK-NEXT: "ExtractOpenExistential.MyProto"
35+
// CHECK-NEXT: ],
36+
// CHECK-NEXT: "allConformances": [
37+
// CHECK-NEXT: {
38+
// CHECK-NEXT: "protocolName": "ExtractOpenExistential.MyProto"
39+
// CHECK-NEXT: "conformanceDefiningModule": "ExtractOpenExistential"
40+
// CHECK-NEXT: }
41+
// CHECK-NEXT: ],
42+
// CHECK-NEXT: "associatedTypeAliases": [],
43+
// CHECK-NEXT: "properties": [
44+
// CHECK-NEXT: {
45+
// CHECK-NEXT: "label": "existentialValue",
46+
// CHECK-NEXT: "type": "Swift.String",
47+
// CHECK-NEXT: "mangledTypeName": "n/a - deprecated",
48+
// CHECK-NEXT: "isStatic": "true",
49+
// CHECK-NEXT: "isComputed": "false",
50+
// CHECK-NEXT: "file": "{{.*}}test{{/|\\\\}}ConstExtraction{{/|\\\\}}ExtractOpenExistential.swift",
51+
// CHECK-NEXT: "line": 22,
52+
// CHECK-NEXT: "valueKind": "FunctionCall",
53+
// CHECK-NEXT: "value": {
54+
// CHECK-NEXT: "name": "useExistential",
55+
// CHECK-NEXT: "arguments": [
56+
// CHECK-NEXT: {
57+
// CHECK-NEXT: "label": "",
58+
// CHECK-NEXT: "type": "any ExtractOpenExistential.ExampleProtocol",
59+
// CHECK-NEXT: "valueKind": "InitCall",
60+
// CHECK-NEXT: "value": {
61+
// CHECK-NEXT: "type": "ExtractOpenExistential.ConcreteType",
62+
// CHECK-NEXT: "arguments": []
63+
// CHECK-NEXT: }
64+
// CHECK-NEXT: }
65+
// CHECK-NEXT: ]
66+
// CHECK-NEXT: }
67+
// CHECK-NEXT: }
68+
// CHECK-NEXT: ]
69+
// CHECK-NEXT: }
70+
// CHECK-NEXT: ]

0 commit comments

Comments
 (0)