25
25
#include " swift/AST/Evaluator.h"
26
26
#include " swift/AST/Expr.h"
27
27
#include " swift/AST/TypeCheckRequests.h"
28
+ #include " swift/AST/TypeVisitor.h"
28
29
29
30
using namespace swift ;
30
31
@@ -52,6 +53,88 @@ void checkImplicitCopyReturnType(const ClosureExpr *Closure,
52
53
}
53
54
}
54
55
56
+ class HasExistentialAnyType : public TypeVisitor <HasExistentialAnyType, bool > {
57
+ public:
58
+ static bool check (Type type) {
59
+ return HasExistentialAnyType ().visit (type->getCanonicalType ());
60
+ }
61
+
62
+ bool visitExistentialType (ExistentialType *ET) {
63
+ return true ;
64
+ }
65
+
66
+ bool visitTupleType (TupleType *TT) {
67
+ for (const auto &element : TT->getElements ()) {
68
+ if (visit (element.getType ())) {
69
+ return true ;
70
+ }
71
+ }
72
+ return false ;
73
+ }
74
+
75
+ bool visitBoundGenericType (BoundGenericType *BGT) {
76
+ // Check generic arguments (e.g., Array<any Protocol>)
77
+ for (Type arg : BGT->getGenericArgs ()) {
78
+ if (visit (arg)) {
79
+ return true ;
80
+ }
81
+ }
82
+ return false ;
83
+ }
84
+
85
+ bool visitFunctionType (FunctionType *FT) {
86
+ for (const auto ¶m : FT->getParams ()) {
87
+ if (visit (param.getPlainType ()->getCanonicalType ())) {
88
+ return true ;
89
+ }
90
+ }
91
+
92
+ return visit (FT->getResult ()->getCanonicalType ());
93
+ }
94
+
95
+ bool visitType (TypeBase *T) {
96
+ return false ;
97
+ }
98
+ };
99
+
100
+ void checkExistentialAnyReturnType (FuncDecl *FD, DiagnosticEngine &Diags) {
101
+ Type T = FD->getResultInterfaceType ();
102
+
103
+ if (HasExistentialAnyType::check (T))
104
+ Diags.diagnose (FD, diag::perf_hint_func_returns_existential, FD);
105
+ }
106
+
107
+ void checkExistentialAnyReturnType (ClosureExpr *CE, DiagnosticEngine &Diags) {
108
+ Type T = CE->getResultType ();
109
+
110
+ if (HasExistentialAnyType::check (T))
111
+ Diags.diagnose (CE->getLoc (), diag::perf_hint_closure_returns_existential);
112
+ }
113
+
114
+ void checkExistentialAnyVarType (const VarDecl *VD, DiagnosticEngine &Diags) {
115
+ Type T = VD->getInterfaceType ();
116
+
117
+ if (HasExistentialAnyType::check (T))
118
+ Diags.diagnose (VD, diag::perf_hint_var_uses_existential, VD);
119
+ }
120
+
121
+ void checkExistentialAnyPatternType (const AnyPattern *AP,
122
+ DiagnosticEngine &Diags) {
123
+ Type T = AP->getType ();
124
+
125
+ if (HasExistentialAnyType::check (T))
126
+ Diags.diagnose (AP->getLoc (), diag::perf_hint_pat_uses_existential);
127
+ }
128
+
129
+ void checkExistentialAnyTypeAlias (const TypeAliasDecl *TAD,
130
+ DiagnosticEngine &Diags) {
131
+ Type T = TAD->getUnderlyingType ();
132
+
133
+ if (HasExistentialAnyType::check (T))
134
+ Diags.diagnose (TAD->getLoc (), diag::perf_hint_typealias_uses_existential,
135
+ TAD);
136
+ }
137
+
55
138
// / Produce performance hint diagnostics for a SourceFile.
56
139
class PerformanceHintDiagnosticWalker final : public ASTWalker {
57
140
ASTContext &Ctx;
@@ -64,16 +147,63 @@ class PerformanceHintDiagnosticWalker final : public ASTWalker {
64
147
SF->walk (Walker);
65
148
}
66
149
150
+ PreWalkResult<Pattern *> walkToPatternPre (Pattern *P) override {
151
+ if (P->isImplicit ())
152
+ return Action::SkipNode (P);
153
+
154
+ if (const AnyPattern *AP = dyn_cast<AnyPattern>(P)) {
155
+ checkExistentialAnyPatternType (AP, Ctx.Diags );
156
+ }
157
+
158
+ return Action::Continue (P);
159
+ }
160
+
67
161
PreWalkResult<Expr *> walkToExprPre (Expr *E) override {
68
- if (auto Closure = dyn_cast<ClosureExpr>(E))
162
+ if (E->isImplicit ())
163
+ return Action::SkipNode (E);
164
+
165
+ if (const ClosureExpr* Closure = dyn_cast<ClosureExpr>(E)) {
69
166
checkImplicitCopyReturnType (Closure, Ctx.Diags );
167
+ }
168
+
169
+ return Action::Continue (E);
170
+ }
171
+
172
+ PostWalkResult<Expr *> walkToExprPost (Expr *E) override {
173
+ assert (
174
+ !E->isImplicit () &&
175
+ " Traversing implicit expressions is disabled in the pre-walk visitor" );
176
+
177
+ if (auto Closure = dyn_cast<ClosureExpr>(E)) {
178
+ checkExistentialAnyReturnType (Closure, Ctx.Diags );
179
+ }
70
180
71
181
return Action::Continue (E);
72
182
}
73
183
74
184
PreWalkAction walkToDeclPre (Decl *D) override {
75
- if (auto *FD = dyn_cast<FuncDecl>(D))
185
+ if (D->isImplicit ())
186
+ return Action::SkipNode ();
187
+
188
+ if (const FuncDecl *FD = dyn_cast<FuncDecl>(D)) {
76
189
checkImplicitCopyReturnType (FD, Ctx.Diags );
190
+ } else if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
191
+ checkExistentialAnyVarType (VD, Ctx.Diags );
192
+ } else if (const TypeAliasDecl *TAD = dyn_cast<TypeAliasDecl>(D)) {
193
+ checkExistentialAnyTypeAlias (TAD, Ctx.Diags );
194
+ }
195
+
196
+ return Action::Continue ();
197
+ }
198
+
199
+ PostWalkAction walkToDeclPost (Decl *D) override {
200
+ assert (
201
+ !D->isImplicit () &&
202
+ " Traversing implicit declarations is disabled in the pre-walk visitor" );
203
+
204
+ if (auto *FD = dyn_cast<FuncDecl>(D)) {
205
+ checkExistentialAnyReturnType (FD, Ctx.Diags );
206
+ }
77
207
78
208
return Action::Continue ();
79
209
}
0 commit comments