2525#include " swift/AST/Evaluator.h"
2626#include " swift/AST/Expr.h"
2727#include " swift/AST/TypeCheckRequests.h"
28+ #include " swift/AST/TypeVisitor.h"
2829
2930using namespace swift ;
3031
3132bool swift::performanceHintDiagnosticsEnabled (ASTContext &ctx) {
32- return !ctx.Diags .isIgnoredDiagnostic (diag::perf_hint_closure_returns_array.ID ) ||
33- !ctx.Diags .isIgnoredDiagnostic (diag::perf_hint_function_returns_array.ID );
33+ return !ctx.Diags .isIgnoredDiagnostic (
34+ diag::perf_hint_closure_returns_array.ID ) ||
35+ !ctx.Diags .isIgnoredDiagnostic (
36+ diag::perf_hint_function_returns_array.ID ) ||
37+ !ctx.Diags .isIgnoredDiagnostic (
38+ diag::perf_hint_param_expects_existential.ID ) ||
39+ !ctx.Diags .isIgnoredDiagnostic (
40+ diag::perf_hint_func_returns_existential.ID ) ||
41+ !ctx.Diags .isIgnoredDiagnostic (
42+ diag::perf_hint_closure_returns_existential.ID ) ||
43+ !ctx.Diags .isIgnoredDiagnostic (
44+ diag::perf_hint_var_uses_existential.ID ) ||
45+ !ctx.Diags .isIgnoredDiagnostic (
46+ diag::perf_hint_any_pattern_uses_existential.ID ) ||
47+ !ctx.Diags .isIgnoredDiagnostic (
48+ diag::perf_hint_typealias_uses_existential.ID );
3449}
3550
3651namespace {
@@ -52,6 +67,52 @@ void checkImplicitCopyReturnType(const ClosureExpr *Closure,
5267 }
5368}
5469
70+ bool hasExistentialAnyInType (Type T) {
71+ return T->getCanonicalType ().findIf (
72+ [](CanType CT) { return isa<ExistentialType>(CT); });
73+ }
74+
75+ void checkExistentialInFunctionReturnType (const FuncDecl *FD,
76+ DiagnosticEngine &Diags) {
77+ Type T = FD->getResultInterfaceType ();
78+
79+ if (hasExistentialAnyInType (T))
80+ Diags.diagnose (FD, diag::perf_hint_func_returns_existential, FD);
81+ }
82+
83+ void checkExistentialInClosureReturnType (const ClosureExpr *CE,
84+ DiagnosticEngine &Diags) {
85+ Type T = CE->getResultType ();
86+
87+ if (hasExistentialAnyInType (T))
88+ Diags.diagnose (CE->getLoc (), diag::perf_hint_closure_returns_existential);
89+ }
90+
91+ void checkExistentialInVariableType (const VarDecl *VD,
92+ DiagnosticEngine &Diags) {
93+ Type T = VD->getInterfaceType ();
94+
95+ if (hasExistentialAnyInType (T))
96+ Diags.diagnose (VD, diag::perf_hint_var_uses_existential, VD);
97+ }
98+
99+ void checkExistentialInPatternType (const AnyPattern *AP,
100+ DiagnosticEngine &Diags) {
101+ Type T = AP->getType ();
102+
103+ if (hasExistentialAnyInType (T))
104+ Diags.diagnose (AP->getLoc (), diag::perf_hint_any_pattern_uses_existential);
105+ }
106+
107+ void checkExistentialInTypeAlias (const TypeAliasDecl *TAD,
108+ DiagnosticEngine &Diags) {
109+ Type T = TAD->getUnderlyingType ();
110+
111+ if (hasExistentialAnyInType (T))
112+ Diags.diagnose (TAD->getLoc (), diag::perf_hint_typealias_uses_existential,
113+ TAD);
114+ }
115+
55116// / Produce performance hint diagnostics for a SourceFile.
56117class PerformanceHintDiagnosticWalker final : public ASTWalker {
57118 ASTContext &Ctx;
@@ -64,16 +125,64 @@ class PerformanceHintDiagnosticWalker final : public ASTWalker {
64125 SF->walk (Walker);
65126 }
66127
128+ PreWalkResult<Pattern *> walkToPatternPre (Pattern *P) override {
129+ if (P->isImplicit ())
130+ return Action::SkipNode (P);
131+
132+ return Action::Continue (P);
133+ }
134+
135+ PostWalkResult<Pattern *> walkToPatternPost (Pattern *P) override {
136+ assert (!P->isImplicit () &&
137+ " Traversing implicit patterns is disabled in the pre-walk visitor" );
138+
139+ if (const AnyPattern *AP = dyn_cast<AnyPattern>(P)) {
140+ checkExistentialInPatternType (AP, Ctx.Diags );
141+ }
142+
143+ return Action::Continue (P);
144+ }
145+
67146 PreWalkResult<Expr *> walkToExprPre (Expr *E) override {
68- if (auto Closure = dyn_cast<ClosureExpr>(E))
69- checkImplicitCopyReturnType (Closure, Ctx.Diags );
147+ if (E->isImplicit ())
148+ return Action::SkipNode (E);
149+
150+ return Action::Continue (E);
151+ }
152+
153+ PostWalkResult<Expr *> walkToExprPost (Expr *E) override {
154+ assert (
155+ !E->isImplicit () &&
156+ " Traversing implicit expressions is disabled in the pre-walk visitor" );
157+
158+ if (const ClosureExpr *CE = dyn_cast<ClosureExpr>(E)) {
159+ checkImplicitCopyReturnType (CE, Ctx.Diags );
160+ checkExistentialInClosureReturnType (CE, Ctx.Diags );
161+ }
70162
71163 return Action::Continue (E);
72164 }
73165
74166 PreWalkAction walkToDeclPre (Decl *D) override {
75- if (auto *FD = dyn_cast<FuncDecl>(D))
167+ if (D->isImplicit ())
168+ return Action::SkipNode ();
169+
170+ return Action::Continue ();
171+ }
172+
173+ PostWalkAction walkToDeclPost (Decl *D) override {
174+ assert (
175+ !D->isImplicit () &&
176+ " Traversing implicit declarations is disabled in the pre-walk visitor" );
177+
178+ if (const FuncDecl *FD = dyn_cast<FuncDecl>(D)) {
76179 checkImplicitCopyReturnType (FD, Ctx.Diags );
180+ checkExistentialInFunctionReturnType (FD, Ctx.Diags );
181+ } else if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
182+ checkExistentialInVariableType (VD, Ctx.Diags );
183+ } else if (const TypeAliasDecl *TAD = dyn_cast<TypeAliasDecl>(D)) {
184+ checkExistentialInTypeAlias (TAD, Ctx.Diags );
185+ }
77186
78187 return Action::Continue ();
79188 }
0 commit comments