Skip to content

Commit 0205150

Browse files
authored
Merge pull request #23687 from gottesmm/pr-aa1beb8a78e3e8b7772bb6e273d51f214e0aa30d
2 parents 3b99358 + 7b0d845 commit 0205150

File tree

14 files changed

+479
-142
lines changed

14 files changed

+479
-142
lines changed

include/swift/AST/Decl.h

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
#include "swift/Basic/ArrayRefView.h"
3737
#include "swift/Basic/Compiler.h"
3838
#include "swift/Basic/InlineBitfield.h"
39+
#include "swift/Basic/NullablePtr.h"
3940
#include "swift/Basic/OptionalEnum.h"
4041
#include "swift/Basic/Range.h"
4142
#include "llvm/ADT/DenseMap.h"
@@ -4747,8 +4748,32 @@ class VarDecl : public AbstractStorageDecl {
47474748
/// return this. Otherwise, this VarDecl must belong to a CaseStmt's
47484749
/// CaseLabelItem. In that case, return the first case label item of the first
47494750
/// case stmt in a sequence of case stmts that fallthrough into each other.
4751+
///
4752+
/// NOTE: During type checking, we emit an error if we have a single case
4753+
/// label item with a pattern that has multiple var decls of the same
4754+
/// name. This means that during type checking and before type checking, we
4755+
/// may have a _malformed_ switch stmt var decl linked list since var decls in
4756+
/// the same case label item that have the same name will point at the same
4757+
/// canonical var decl, namely the first var decl with the name in the
4758+
/// canonical case label item's var decl list. This is ok, since we are going
4759+
/// to emit the error, but it requires us to be more careful/cautious before
4760+
/// type checking has been complete when relying on canonical var decls
4761+
/// matching up.
47504762
VarDecl *getCanonicalVarDecl() const;
47514763

4764+
/// If this is a case stmt var decl, return the var decl that corresponds to
4765+
/// this var decl in the first case label item of the case stmt. Returns
4766+
/// nullptr if this isn't a VarDecl that is part of a case stmt.
4767+
NullablePtr<VarDecl> getCorrespondingFirstCaseLabelItemVarDecl() const;
4768+
4769+
/// If this is a case stmt var decl, return the case body var decl that this
4770+
/// var decl maps to.
4771+
NullablePtr<VarDecl> getCorrespondingCaseBodyVariable() const;
4772+
4773+
/// Return true if this var decl is an implicit var decl belonging to a case
4774+
/// stmt's body.
4775+
bool isCaseBodyVariable() const;
4776+
47524777
/// True if the global stored property requires lazy initialization.
47534778
bool isLazilyInitializedGlobal() const;
47544779

include/swift/AST/Pattern.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,13 @@ class alignas(8) Pattern {
168168
/// pattern.
169169
void forEachVariable(llvm::function_ref<void(VarDecl *)> f) const;
170170

171+
/// Returns true if \p vd is in the pattern.
172+
bool containsVarDecl(const VarDecl *inputVD) const {
173+
bool result = false;
174+
forEachVariable([&](VarDecl *vd) { result |= inputVD == vd; });
175+
return result;
176+
}
177+
171178
/// apply the specified function to all pattern nodes recursively in
172179
/// this pattern. This is a pre-order traversal.
173180
void forEachNode(llvm::function_ref<void(Pattern *)> f);

include/swift/Basic/NullablePtr.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,13 @@ class NullablePtr {
6161

6262
explicit operator bool() const { return Ptr; }
6363

64-
bool operator==(NullablePtr<T> &&other) const { return other.Ptr == Ptr; }
64+
bool operator==(const NullablePtr<T> &other) const {
65+
return other.Ptr == Ptr;
66+
}
6567

66-
bool operator!=(NullablePtr<T> &&other) const { return !(*this == other); }
68+
bool operator!=(const NullablePtr<T> &other) const {
69+
return !(*this == other);
70+
}
6771

6872
bool operator==(const T *other) const { return other == Ptr; }
6973

include/swift/Parse/Parser.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -689,11 +689,11 @@ class Parser {
689689
swift::ScopeInfo &getScopeInfo() { return State->getScopeInfo(); }
690690

691691
/// Add the given Decl to the current scope.
692-
void addToScope(ValueDecl *D) {
692+
void addToScope(ValueDecl *D, bool diagnoseRedefinitions = true) {
693693
if (Context.LangOpts.EnableASTScopeLookup)
694694
return;
695695

696-
getScopeInfo().addToScope(D, *this);
696+
getScopeInfo().addToScope(D, *this, diagnoseRedefinitions);
697697
}
698698

699699
ValueDecl *lookupInScope(DeclName Name) {

include/swift/Parse/Scope.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,8 @@ class ScopeInfo {
5252

5353
/// addToScope - Register the specified decl as being in the current lexical
5454
/// scope.
55-
void addToScope(ValueDecl *D, Parser &TheParser);
55+
void addToScope(ValueDecl *D, Parser &TheParser,
56+
bool diagnoseRedefinitions = true);
5657

5758
bool isInactiveConfigBlock() const;
5859

lib/AST/ASTVerifier.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2500,6 +2500,20 @@ class Verifier : public ASTWalker {
25002500
}
25012501
}
25022502

2503+
if (auto *caseStmt =
2504+
dyn_cast_or_null<CaseStmt>(var->getRecursiveParentPatternStmt())) {
2505+
// In a type checked AST, a case stmt that is a recursive parent pattern
2506+
// stmt of a var decl, must have bound decls. This is because we
2507+
// guarantee that all case label items bind corresponding patterns and
2508+
// the case body var decls of a case stmt are created from the var decls
2509+
// of the first case label items.
2510+
if (!caseStmt->hasBoundDecls()) {
2511+
Out << "parent CaseStmt of VarDecl does not have any case body "
2512+
"decls?!\n";
2513+
abort();
2514+
}
2515+
}
2516+
25032517
verifyCheckedBase(var);
25042518
}
25052519

lib/AST/Decl.cpp

Lines changed: 54 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1294,27 +1294,19 @@ VarDecl *PatternBindingInitializer::getInitializedLazyVar() const {
12941294
return nullptr;
12951295
}
12961296

1297-
static bool patternContainsVarDeclBinding(const Pattern *P, const VarDecl *VD) {
1298-
bool Result = false;
1299-
P->forEachVariable([&](VarDecl *FoundVD) {
1300-
Result |= FoundVD == VD;
1301-
});
1302-
return Result;
1303-
}
1304-
13051297
unsigned PatternBindingDecl::getPatternEntryIndexForVarDecl(const VarDecl *VD) const {
13061298
assert(VD && "Cannot find a null VarDecl");
13071299

13081300
auto List = getPatternList();
13091301
if (List.size() == 1) {
1310-
assert(patternContainsVarDeclBinding(List[0].getPattern(), VD) &&
1302+
assert(List[0].getPattern()->containsVarDecl(VD) &&
13111303
"Single entry PatternBindingDecl is set up wrong");
13121304
return 0;
13131305
}
13141306

13151307
unsigned Result = 0;
13161308
for (auto entry : List) {
1317-
if (patternContainsVarDeclBinding(entry.getPattern(), VD))
1309+
if (entry.getPattern()->containsVarDecl(VD))
13181310
return Result;
13191311
++Result;
13201312
}
@@ -4927,12 +4919,6 @@ SourceRange VarDecl::getTypeSourceRangeForDiagnostics() const {
49274919
return SourceRange();
49284920
}
49294921

4930-
static bool isVarInPattern(const VarDecl *vd, Pattern *p) {
4931-
bool foundIt = false;
4932-
p->forEachVariable([&](VarDecl *foundFD) { foundIt |= foundFD == vd; });
4933-
return foundIt;
4934-
}
4935-
49364922
static Optional<std::pair<CaseStmt *, Pattern *>>
49374923
findParentPatternCaseStmtAndPattern(const VarDecl *inputVD) {
49384924
auto getMatchingPattern = [&](CaseStmt *cs) -> Pattern * {
@@ -4946,7 +4932,7 @@ findParentPatternCaseStmtAndPattern(const VarDecl *inputVD) {
49464932

49474933
// Then check the rest of our case label items.
49484934
for (auto &item : cs->getMutableCaseLabelItems()) {
4949-
if (isVarInPattern(inputVD, item.getPattern())) {
4935+
if (item.getPattern()->containsVarDecl(inputVD)) {
49504936
return item.getPattern();
49514937
}
49524938
}
@@ -5039,15 +5025,15 @@ Pattern *VarDecl::getParentPattern() const {
50395025
// In a case statement, search for the pattern that contains it. This is
50405026
// a bit silly, because you can't have something like "case x, y:" anyway.
50415027
for (auto items : cs->getCaseLabelItems()) {
5042-
if (isVarInPattern(this, items.getPattern()))
5028+
if (items.getPattern()->containsVarDecl(this))
50435029
return items.getPattern();
50445030
}
50455031
}
50465032

50475033
if (auto *LCS = dyn_cast<LabeledConditionalStmt>(stmt)) {
50485034
for (auto &elt : LCS->getCond())
50495035
if (auto pat = elt.getPatternOrNull())
5050-
if (isVarInPattern(this, pat))
5036+
if (pat->containsVarDecl(this))
50515037
return pat;
50525038
}
50535039

@@ -5066,6 +5052,55 @@ Pattern *VarDecl::getParentPattern() const {
50665052
return nullptr;
50675053
}
50685054

5055+
NullablePtr<VarDecl>
5056+
VarDecl::getCorrespondingFirstCaseLabelItemVarDecl() const {
5057+
if (!hasName())
5058+
return nullptr;
5059+
5060+
auto *caseStmt = dyn_cast_or_null<CaseStmt>(getRecursiveParentPatternStmt());
5061+
if (!caseStmt)
5062+
return nullptr;
5063+
5064+
auto *pattern = caseStmt->getCaseLabelItems().front().getPattern();
5065+
SmallVector<VarDecl *, 8> vars;
5066+
pattern->collectVariables(vars);
5067+
for (auto *vd : vars) {
5068+
if (vd->hasName() && vd->getName() == getName())
5069+
return vd;
5070+
}
5071+
return nullptr;
5072+
}
5073+
5074+
bool VarDecl::isCaseBodyVariable() const {
5075+
auto *caseStmt = dyn_cast_or_null<CaseStmt>(getRecursiveParentPatternStmt());
5076+
if (!caseStmt)
5077+
return false;
5078+
return llvm::any_of(caseStmt->getCaseBodyVariablesOrEmptyArray(),
5079+
[&](VarDecl *vd) { return vd == this; });
5080+
}
5081+
5082+
NullablePtr<VarDecl> VarDecl::getCorrespondingCaseBodyVariable() const {
5083+
// Only var decls associated with case statements can have child var decls.
5084+
auto *caseStmt = dyn_cast_or_null<CaseStmt>(getRecursiveParentPatternStmt());
5085+
if (!caseStmt)
5086+
return nullptr;
5087+
5088+
// If this var decl doesn't have a name, it can not have a corresponding case
5089+
// body variable.
5090+
if (!hasName())
5091+
return nullptr;
5092+
5093+
auto name = getName();
5094+
5095+
// A var decl associated with a case stmt implies that the case stmt has body
5096+
// var decls. So we can access the optional value here without worry.
5097+
auto caseBodyVars = *caseStmt->getCaseBodyVariables();
5098+
auto result = llvm::find_if(caseBodyVars, [&](VarDecl *caseBodyVar) {
5099+
return caseBodyVar->getName() == name;
5100+
});
5101+
return (result != caseBodyVars.end()) ? *result : nullptr;
5102+
}
5103+
50695104
bool VarDecl::isSelfParameter() const {
50705105
if (isa<ParamDecl>(this)) {
50715106
if (auto *AFD = dyn_cast<AbstractFunctionDecl>(getDeclContext()))

lib/AST/NameLookup.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2347,8 +2347,14 @@ void FindLocalVal::visitCaseStmt(CaseStmt *S) {
23472347
}
23482348
}
23492349
}
2350-
if (!inPatterns && !items.empty())
2351-
checkPattern(items[0].getPattern(), DeclVisibilityKind::LocalVariable);
2350+
2351+
if (!inPatterns && !items.empty()) {
2352+
if (auto caseBodyVars = S->getCaseBodyVariables()) {
2353+
for (auto *vd : *caseBodyVars) {
2354+
checkValueDecl(vd, DeclVisibilityKind::LocalVariable);
2355+
}
2356+
}
2357+
}
23522358
visit(S->getBody());
23532359
}
23542360

lib/Parse/ParseStmt.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2476,6 +2476,20 @@ ParserResult<CaseStmt> Parser::parseStmtCase(bool IsActive) {
24762476

24772477
assert(!CaseLabelItems.empty() && "did not parse any labels?!");
24782478

2479+
// Add a scope so that the parser can find our body bound decls if it emits
2480+
// optimized accesses.
2481+
Optional<Scope> BodyScope;
2482+
if (CaseBodyDecls) {
2483+
BodyScope.emplace(this, ScopeKind::CaseVars);
2484+
for (auto *v : *CaseBodyDecls) {
2485+
setLocalDiscriminator(v);
2486+
// If we had any bad redefinitions, we already diagnosed them against the
2487+
// first case label item.
2488+
if (v->hasName())
2489+
addToScope(v, false /*diagnoseRedefinitions*/);
2490+
}
2491+
}
2492+
24792493
SmallVector<ASTNode, 8> BodyItems;
24802494

24812495
SourceLoc StartOfBody = Tok.getLoc();

lib/Parse/Scope.cpp

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,8 @@ static bool checkValidOverload(const ValueDecl *D1, const ValueDecl *D2,
104104

105105
/// addToScope - Register the specified decl as being in the current lexical
106106
/// scope.
107-
void ScopeInfo::addToScope(ValueDecl *D, Parser &TheParser) {
107+
void ScopeInfo::addToScope(ValueDecl *D, Parser &TheParser,
108+
bool diagnoseRedefinitions) {
108109
if (!CurScope->isResolvable())
109110
return;
110111

@@ -121,9 +122,13 @@ void ScopeInfo::addToScope(ValueDecl *D, Parser &TheParser) {
121122

122123
// If this is in a resolvable scope, diagnose redefinitions. Later
123124
// phases will handle scopes like module-scope, etc.
124-
if (CurScope->getDepth() >= ResolvableDepth)
125-
return TheParser.diagnoseRedefinition(PrevDecl, D);
126-
125+
if (CurScope->getDepth() >= ResolvableDepth) {
126+
if (diagnoseRedefinitions) {
127+
return TheParser.diagnoseRedefinition(PrevDecl, D);
128+
}
129+
return;
130+
}
131+
127132
// If this is at top-level scope, validate that the members of the overload
128133
// set all agree.
129134

0 commit comments

Comments
 (0)