Skip to content

Commit 611534c

Browse files
authored
Merge pull request #23378 from gottesmm/pr-5d07f093c8b0891046d822d507c526e7ec6cfc1d
2 parents f19c2d2 + b1a7b48 commit 611534c

File tree

5 files changed

+323
-97
lines changed

5 files changed

+323
-97
lines changed

include/swift/AST/Decl.h

Lines changed: 48 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4579,7 +4579,7 @@ class VarDecl : public AbstractStorageDecl {
45794579
};
45804580

45814581
protected:
4582-
llvm::PointerUnion<PatternBindingDecl*, Stmt*> ParentPattern;
4582+
PointerUnion3<PatternBindingDecl *, Stmt *, VarDecl *> Parent;
45834583

45844584
VarDecl(DeclKind Kind, bool IsStatic, Specifier Sp, bool IsCaptureList,
45854585
SourceLoc NameLoc, Identifier Name, DeclContext *DC)
@@ -4650,12 +4650,15 @@ class VarDecl : public AbstractStorageDecl {
46504650
/// Return the parent pattern binding that may provide an initializer for this
46514651
/// VarDecl. This returns null if there is none associated with the VarDecl.
46524652
PatternBindingDecl *getParentPatternBinding() const {
4653-
return ParentPattern.dyn_cast<PatternBindingDecl *>();
4653+
if (!Parent)
4654+
return nullptr;
4655+
return Parent.dyn_cast<PatternBindingDecl *>();
46544656
}
46554657
void setParentPatternBinding(PatternBindingDecl *PBD) {
4656-
ParentPattern = PBD;
4658+
assert(PBD);
4659+
Parent = PBD;
46574660
}
4658-
4661+
46594662
/// Return the Pattern involved in initializing this VarDecl. However, recall
46604663
/// that the Pattern may be involved in initializing more than just this one
46614664
/// vardecl. For example, if this is a VarDecl for "x", the pattern may be
@@ -4666,16 +4669,53 @@ class VarDecl : public AbstractStorageDecl {
46664669
/// returns null.
46674670
///
46684671
Pattern *getParentPattern() const;
4669-
4672+
46704673
/// Return the statement that owns the pattern associated with this VarDecl,
46714674
/// if one exists.
4675+
///
4676+
/// NOTE: After parsing and before type checking, all VarDecls from
4677+
/// CaseLabelItem's Patterns return their CaseStmt. After type checking, we
4678+
/// will have constructed the CaseLabelItem VarDecl linked list implying this
4679+
/// will return nullptr. After type checking, if one wishes to find a parent
4680+
/// pattern of a VarDecl of a CaseStmt, \see getRecursiveParentPatternStmt
4681+
/// instead.
46724682
Stmt *getParentPatternStmt() const {
4673-
return ParentPattern.dyn_cast<Stmt*>();
4683+
if (!Parent)
4684+
return nullptr;
4685+
return Parent.dyn_cast<Stmt *>();
46744686
}
4675-
void setParentPatternStmt(Stmt *S) {
4676-
ParentPattern = S;
4687+
4688+
void setParentPatternStmt(Stmt *s) {
4689+
assert(s);
4690+
Parent = s;
46774691
}
46784692

4693+
/// Look for the parent pattern stmt of this var decl, recursively
4694+
/// looking through var decl pointers and then through any
4695+
/// fallthroughts.
4696+
Stmt *getRecursiveParentPatternStmt() const;
4697+
4698+
/// Returns the var decl that this var decl is an implicit reference to if
4699+
/// such a var decl exists.
4700+
VarDecl *getParentVarDecl() const {
4701+
if (!Parent)
4702+
return nullptr;
4703+
return Parent.dyn_cast<VarDecl *>();
4704+
}
4705+
4706+
/// Set \p v to be the pattern produced VarDecl that is the parent of this
4707+
/// var decl.
4708+
void setParentVarDecl(VarDecl *v) {
4709+
assert(v);
4710+
Parent = v;
4711+
}
4712+
4713+
/// If this is a VarDecl that does not belong to a CaseLabelItem's pattern,
4714+
/// return this. Otherwise, this VarDecl must belong to a CaseStmt's
4715+
/// CaseLabelItem. In that case, return the first case label item of the first
4716+
/// case stmt in a sequence of case stmts that fallthrough into each other.
4717+
VarDecl *getCanonicalVarDecl() const;
4718+
46794719
/// True if the global stored property requires lazy initialization.
46804720
bool isLazilyInitializedGlobal() const;
46814721

include/swift/Basic/LLVM.h

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ namespace llvm {
4343
template<typename T> class TinyPtrVector;
4444
template<typename T> class Optional;
4545
template <typename PT1, typename PT2> class PointerUnion;
46+
template <typename PT1, typename PT2, typename PT3> class PointerUnion3;
4647
class SmallBitVector;
4748

4849
// Other common classes.
@@ -62,22 +63,23 @@ namespace swift {
6263
using llvm::cast_or_null;
6364

6465
// Containers.
66+
using llvm::ArrayRef;
67+
using llvm::MutableArrayRef;
6568
using llvm::None;
6669
using llvm::Optional;
67-
using llvm::SmallPtrSetImpl;
70+
using llvm::PointerUnion;
71+
using llvm::PointerUnion3;
72+
using llvm::SmallBitVector;
6873
using llvm::SmallPtrSet;
74+
using llvm::SmallPtrSetImpl;
75+
using llvm::SmallSetVector;
6976
using llvm::SmallString;
70-
using llvm::StringRef;
71-
using llvm::StringLiteral;
72-
using llvm::Twine;
73-
using llvm::SmallVectorImpl;
7477
using llvm::SmallVector;
75-
using llvm::ArrayRef;
76-
using llvm::MutableArrayRef;
78+
using llvm::SmallVectorImpl;
79+
using llvm::StringLiteral;
80+
using llvm::StringRef;
7781
using llvm::TinyPtrVector;
78-
using llvm::PointerUnion;
79-
using llvm::SmallSetVector;
80-
using llvm::SmallBitVector;
82+
using llvm::Twine;
8183

8284
// Other common classes.
8385
using llvm::APFloat;

lib/AST/Decl.cpp

Lines changed: 78 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4876,14 +4876,74 @@ SourceRange VarDecl::getTypeSourceRangeForDiagnostics() const {
48764876
return SourceRange();
48774877
}
48784878

4879-
static bool isVarInPattern(const VarDecl *VD, Pattern *P) {
4879+
static bool isVarInPattern(const VarDecl *vd, Pattern *p) {
48804880
bool foundIt = false;
4881-
P->forEachVariable([&](VarDecl *FoundFD) {
4882-
foundIt |= FoundFD == VD;
4883-
});
4881+
p->forEachVariable([&](VarDecl *foundFD) { foundIt |= foundFD == vd; });
48844882
return foundIt;
48854883
}
48864884

4885+
static Optional<std::pair<CaseStmt *, Pattern *>>
4886+
findParentPatternCaseStmtAndPattern(const VarDecl *inputVD) {
4887+
auto getMatchingPattern = [&](CaseStmt *cs) -> Pattern * {
4888+
for (auto &item : cs->getMutableCaseLabelItems()) {
4889+
if (isVarInPattern(inputVD, item.getPattern())) {
4890+
return item.getPattern();
4891+
}
4892+
}
4893+
return nullptr;
4894+
};
4895+
4896+
// First find our canonical var decl. This is the VarDecl corresponding to the
4897+
// first case label item of the first case block in the fallthrough chain that
4898+
// our case block is within. Grab the case stmt associated with that var decl
4899+
// and start traveling down the fallthrough chain looking for the case
4900+
// statement that the input VD belongs to by using getMatchingPattern().
4901+
auto *canonicalVD = inputVD->getCanonicalVarDecl();
4902+
auto *caseStmt =
4903+
dyn_cast_or_null<CaseStmt>(canonicalVD->getParentPatternStmt());
4904+
if (!caseStmt)
4905+
return None;
4906+
4907+
if (auto *p = getMatchingPattern(caseStmt))
4908+
return std::make_pair(caseStmt, p);
4909+
4910+
while ((caseStmt = caseStmt->getFallthroughDest().getPtrOrNull())) {
4911+
if (auto *p = getMatchingPattern(caseStmt))
4912+
return std::make_pair(caseStmt, p);
4913+
}
4914+
4915+
return None;
4916+
}
4917+
4918+
VarDecl *VarDecl::getCanonicalVarDecl() const {
4919+
// Any var decl without a parent var decl is canonical. This means that before
4920+
// type checking, all var decls are canonical.
4921+
auto *cur = const_cast<VarDecl *>(this);
4922+
auto *vd = cur->getParentVarDecl();
4923+
if (!vd)
4924+
return cur;
4925+
4926+
while (vd) {
4927+
cur = vd;
4928+
vd = vd->getParentVarDecl();
4929+
}
4930+
4931+
return cur;
4932+
}
4933+
4934+
Stmt *VarDecl::getRecursiveParentPatternStmt() const {
4935+
// If our parent is already a pattern stmt, just return that.
4936+
if (auto *stmt = getParentPatternStmt())
4937+
return stmt;
4938+
4939+
// Otherwise, see if we have a parent var decl. If we do not, then return
4940+
// nullptr. Otherwise, return the case stmt that we found.
4941+
auto result = findParentPatternCaseStmtAndPattern(this);
4942+
if (!result.hasValue())
4943+
return nullptr;
4944+
return result->first;
4945+
}
4946+
48874947
/// Return the Pattern involved in initializing this VarDecl. Recall that the
48884948
/// Pattern may be involved in initializing more than just this one vardecl
48894949
/// though. For example, if this is a VarDecl for "x", the pattern may be
@@ -4905,25 +4965,35 @@ Pattern *VarDecl::getParentPattern() const {
49054965

49064966
if (auto *CS = dyn_cast<CatchStmt>(stmt))
49074967
return CS->getErrorPattern();
4908-
4968+
49094969
if (auto *cs = dyn_cast<CaseStmt>(stmt)) {
49104970
// In a case statement, search for the pattern that contains it. This is
49114971
// a bit silly, because you can't have something like "case x, y:" anyway.
49124972
for (auto items : cs->getCaseLabelItems()) {
49134973
if (isVarInPattern(this, items.getPattern()))
49144974
return items.getPattern();
49154975
}
4916-
} else if (auto *LCS = dyn_cast<LabeledConditionalStmt>(stmt)) {
4976+
}
4977+
4978+
if (auto *LCS = dyn_cast<LabeledConditionalStmt>(stmt)) {
49174979
for (auto &elt : LCS->getCond())
49184980
if (auto pat = elt.getPatternOrNull())
49194981
if (isVarInPattern(this, pat))
49204982
return pat;
49214983
}
4922-
4984+
49234985
//stmt->dump();
49244986
assert(0 && "Unknown parent pattern statement?");
49254987
}
4926-
4988+
4989+
// Otherwise, check if we have to walk our case stmt's var decl list to find
4990+
// the pattern.
4991+
if (auto caseStmtPatternPair = findParentPatternCaseStmtAndPattern(this)) {
4992+
return caseStmtPatternPair->second;
4993+
}
4994+
4995+
// Otherwise, this is a case we do not know or understand. Return nullptr to
4996+
// signal we do not have any information.
49274997
return nullptr;
49284998
}
49294999

lib/Sema/MiscDiagnostics.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2623,7 +2623,7 @@ VarDeclUsageChecker::~VarDeclUsageChecker() {
26232623
}
26242624
else {
26252625
bool suggestLet = true;
2626-
if (auto *stmt = var->getParentPatternStmt()) {
2626+
if (auto *stmt = var->getRecursiveParentPatternStmt()) {
26272627
// Don't try to suggest 'var' -> 'let' conversion
26282628
// in case of 'for' loop because it's an implicitly
26292629
// immutable context.

0 commit comments

Comments
 (0)