-
Notifications
You must be signed in to change notification settings - Fork 10.6k
[Performance Hints] Implement check for existential any #84684
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 1 commit
13a5c2d
8ab27fc
cbfb79d
52304ec
30c6b5f
d0ebe90
75c1fad
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -25,12 +25,27 @@ | |
#include "swift/AST/Evaluator.h" | ||
#include "swift/AST/Expr.h" | ||
#include "swift/AST/TypeCheckRequests.h" | ||
#include "swift/AST/TypeVisitor.h" | ||
|
||
using namespace swift; | ||
|
||
bool swift::performanceHintDiagnosticsEnabled(ASTContext &ctx) { | ||
return !ctx.Diags.isIgnoredDiagnostic(diag::perf_hint_closure_returns_array.ID) || | ||
!ctx.Diags.isIgnoredDiagnostic(diag::perf_hint_function_returns_array.ID); | ||
return !ctx.Diags.isIgnoredDiagnostic( | ||
diag::perf_hint_closure_returns_array.ID) || | ||
!ctx.Diags.isIgnoredDiagnostic( | ||
diag::perf_hint_function_returns_array.ID) || | ||
!ctx.Diags.isIgnoredDiagnostic( | ||
diag::perf_hint_param_expects_existential_any.ID) || | ||
!ctx.Diags.isIgnoredDiagnostic( | ||
diag::perf_hint_func_returns_existential_any.ID) || | ||
!ctx.Diags.isIgnoredDiagnostic( | ||
diag::perf_hint_closure_returns_existential_any.ID) || | ||
!ctx.Diags.isIgnoredDiagnostic( | ||
diag::perf_hint_var_uses_existential_any.ID) || | ||
!ctx.Diags.isIgnoredDiagnostic( | ||
diag::perf_hint_any_pattern_uses_existential_any.ID) || | ||
!ctx.Diags.isIgnoredDiagnostic( | ||
diag::perf_hint_typealias_uses_existential_any.ID); | ||
} | ||
|
||
namespace { | ||
|
@@ -52,6 +67,88 @@ void checkImplicitCopyReturnType(const ClosureExpr *Closure, | |
} | ||
} | ||
|
||
class CheckExistentialAny : public TypeVisitor<CheckExistentialAny, bool> { | ||
public: | ||
static bool inType(Type type) { | ||
return CheckExistentialAny().visit(type->getCanonicalType()); | ||
} | ||
|
||
static void inFunctionReturnType(FuncDecl *FD, DiagnosticEngine &Diags) { | ||
Type T = FD->getResultInterfaceType(); | ||
|
||
if (inType(T)) | ||
Diags.diagnose(FD, diag::perf_hint_func_returns_existential_any, FD); | ||
} | ||
|
||
static void inClosureReturnType(ClosureExpr *CE, DiagnosticEngine &Diags) { | ||
Type T = CE->getResultType(); | ||
|
||
if (inType(T)) | ||
Diags.diagnose(CE->getLoc(), | ||
diag::perf_hint_closure_returns_existential_any); | ||
} | ||
|
||
static void inVariableType(const VarDecl *VD, DiagnosticEngine &Diags) { | ||
Type T = VD->getInterfaceType(); | ||
|
||
if (inType(T)) | ||
Diags.diagnose(VD, diag::perf_hint_var_uses_existential_any, VD); | ||
} | ||
|
||
static void inPatternType(const AnyPattern *AP, DiagnosticEngine &Diags) { | ||
Type T = AP->getType(); | ||
|
||
if (inType(T)) | ||
Diags.diagnose(AP->getLoc(), | ||
diag::perf_hint_any_pattern_uses_existential_any); | ||
} | ||
|
||
static void inTypeAlias(const TypeAliasDecl *TAD, DiagnosticEngine &Diags) { | ||
Type T = TAD->getUnderlyingType(); | ||
|
||
if (inType(T)) | ||
Diags.diagnose(TAD->getLoc(), | ||
diag::perf_hint_typealias_uses_existential_any, TAD); | ||
} | ||
|
||
bool visitExistentialType(ExistentialType *ET) { | ||
return true; | ||
} | ||
|
||
bool visitTupleType(TupleType *TT) { | ||
|
||
for (const auto &element : TT->getElements()) { | ||
if (visit(element.getType())) { | ||
return true; | ||
} | ||
} | ||
return false; | ||
} | ||
|
||
bool visitBoundGenericType(BoundGenericType *BGT) { | ||
// Check generic arguments (e.g., Array<any Protocol>) | ||
for (Type arg : BGT->getGenericArgs()) { | ||
if (visit(arg)) { | ||
return true; | ||
} | ||
} | ||
return false; | ||
} | ||
|
||
bool visitFunctionType(FunctionType *FT) { | ||
for (const auto ¶m : FT->getParams()) { | ||
if (visit(param.getPlainType()->getCanonicalType())) { | ||
return true; | ||
} | ||
} | ||
|
||
return visit(FT->getResult()->getCanonicalType()); | ||
} | ||
|
||
bool visitType(TypeBase *T) { | ||
return false; | ||
} | ||
}; | ||
|
||
/// Produce performance hint diagnostics for a SourceFile. | ||
class PerformanceHintDiagnosticWalker final : public ASTWalker { | ||
ASTContext &Ctx; | ||
|
@@ -64,16 +161,63 @@ class PerformanceHintDiagnosticWalker final : public ASTWalker { | |
SF->walk(Walker); | ||
} | ||
|
||
PreWalkResult<Pattern *> walkToPatternPre(Pattern *P) override { | ||
if (P->isImplicit()) | ||
return Action::SkipNode(P); | ||
|
||
if (const AnyPattern *AP = dyn_cast<AnyPattern>(P)) { | ||
CheckExistentialAny::inPatternType(AP, Ctx.Diags); | ||
} | ||
|
||
return Action::Continue(P); | ||
} | ||
|
||
PreWalkResult<Expr *> walkToExprPre(Expr *E) override { | ||
if (auto Closure = dyn_cast<ClosureExpr>(E)) | ||
if (E->isImplicit()) | ||
return Action::SkipNode(E); | ||
|
||
if (const ClosureExpr* Closure = dyn_cast<ClosureExpr>(E)) { | ||
checkImplicitCopyReturnType(Closure, Ctx.Diags); | ||
} | ||
|
||
return Action::Continue(E); | ||
} | ||
|
||
PostWalkResult<Expr *> walkToExprPost(Expr *E) override { | ||
assert( | ||
!E->isImplicit() && | ||
"Traversing implicit expressions is disabled in the pre-walk visitor"); | ||
|
||
if (auto Closure = dyn_cast<ClosureExpr>(E)) { | ||
CheckExistentialAny::inClosureReturnType(Closure, Ctx.Diags); | ||
} | ||
|
||
return Action::Continue(E); | ||
} | ||
|
||
PreWalkAction walkToDeclPre(Decl *D) override { | ||
if (auto *FD = dyn_cast<FuncDecl>(D)) | ||
if (D->isImplicit()) | ||
return Action::SkipNode(); | ||
|
||
if (const FuncDecl *FD = dyn_cast<FuncDecl>(D)) { | ||
checkImplicitCopyReturnType(FD, Ctx.Diags); | ||
} else if (const VarDecl *VD = dyn_cast<VarDecl>(D)) { | ||
CheckExistentialAny::inVariableType(VD, Ctx.Diags); | ||
} else if (const TypeAliasDecl *TAD = dyn_cast<TypeAliasDecl>(D)) { | ||
CheckExistentialAny::inTypeAlias(TAD, Ctx.Diags); | ||
} | ||
|
||
return Action::Continue(); | ||
} | ||
|
||
PostWalkAction walkToDeclPost(Decl *D) override { | ||
assert( | ||
!D->isImplicit() && | ||
"Traversing implicit declarations is disabled in the pre-walk visitor"); | ||
|
||
if (auto *FD = dyn_cast<FuncDecl>(D)) { | ||
CheckExistentialAny::inFunctionReturnType(FD, Ctx.Diags); | ||
} | ||
|
||
return Action::Continue(); | ||
} | ||
|
Uh oh!
There was an error while loading. Please reload this page.