diff --git a/lib/Sema/MiscDiagnostics.cpp b/lib/Sema/MiscDiagnostics.cpp index 9e3e2f158ebbc..e79c864e408d0 100644 --- a/lib/Sema/MiscDiagnostics.cpp +++ b/lib/Sema/MiscDiagnostics.cpp @@ -22,6 +22,7 @@ #include "swift/AST/Pattern.h" #include "swift/Basic/Defer.h" #include "swift/Basic/SourceManager.h" +#include "swift/Basic/Statistic.h" #include "swift/Basic/StringExtras.h" #include "swift/Parse/Lexer.h" #include "swift/Parse/Parser.h" @@ -29,6 +30,8 @@ #include "llvm/ADT/MapVector.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/SaveAndRestore.h" + +#define DEBUG_TYPE "Sema" using namespace swift; /// Return true if this expression is an implicit promotion from T to T?. @@ -1992,6 +1995,10 @@ class VarDeclUsageChecker : public ASTWalker { /// This is a mapping from VarDecls to the if/while/guard statement that they /// occur in, when they are in a pattern in a StmtCondition. llvm::SmallDenseMap StmtConditionForVD; + +#ifndef NDEBUG + llvm::SmallPtrSet AllExprsSeen; +#endif bool sawError = false; @@ -2732,6 +2739,10 @@ void VarDeclUsageChecker::markStoredOrInOutExpr(Expr *E, unsigned Flags) { /// The heavy lifting happens when visiting expressions. std::pair VarDeclUsageChecker::walkToExprPre(Expr *E) { + STATISTIC(VarDeclUsageCheckerExprVisits, + "# of times VarDeclUsageChecker::walkToExprPre is called"); + ++VarDeclUsageCheckerExprVisits; + // Sema leaves some subexpressions null, which seems really unfortunate. It // should replace them with ErrorExpr. if (E == nullptr || !E->getType() || E->getType()->hasError()) { @@ -2739,6 +2750,8 @@ std::pair VarDeclUsageChecker::walkToExprPre(Expr *E) { return { false, E }; } + assert(AllExprsSeen.insert(E).second && "duplicate traversal"); + // If this is a DeclRefExpr found in a random place, it is a load of the // vardecl. if (auto *DRE = dyn_cast(E)) { @@ -2783,9 +2796,13 @@ std::pair VarDeclUsageChecker::walkToExprPre(Expr *E) { return { false, E }; } - // If we see an OpenExistentialExpr, remember the mapping for its OpaqueValue. - if (auto *oee = dyn_cast(E)) + // If we see an OpenExistentialExpr, remember the mapping for its OpaqueValue + // and only walk the subexpr. + if (auto *oee = dyn_cast(E)) { OpaqueValueMap[oee->getOpaqueValue()] = oee->getExistentialValue(); + oee->getSubExpr()->walk(*this); + return { false, E }; + } // Visit bindings. if (auto ove = dyn_cast(E)) { diff --git a/validation-test/compiler_scale/var_decl_usage_checker.swift.gyb b/validation-test/compiler_scale/var_decl_usage_checker.swift.gyb new file mode 100644 index 0000000000000..158eb2f333fd0 --- /dev/null +++ b/validation-test/compiler_scale/var_decl_usage_checker.swift.gyb @@ -0,0 +1,17 @@ +// RUN: %scale-test --begin 1 --end 5 --step 1 --select VarDeclUsageCheckerExprVisits %s +// REQUIRES: OS=macosx +// REQUIRES: asserts + +protocol Proto {} +extension Proto { + var selfish: Proto { return self } +} + +struct X: Proto {} + +func test(_ x: X) -> Proto { + return x +%for i in range(0, N*5): + .selfish +%end +}