Skip to content

Commit 92b18ea

Browse files
committed
[Sema] Teach typeCheckASTNodeAtLoc to check StmtConditionElement
Type checking a StmtConditionElement is slightly different than type checking the VarDecl declared by it because it doesn’t complain about redeclaration like `if let myVar = myVar`. Thus, we need to handle it in `typeCheckASTNodeAtLoc`
1 parent bf6c9f9 commit 92b18ea

File tree

2 files changed

+47
-1
lines changed

2 files changed

+47
-1
lines changed

lib/Sema/TypeCheckStmt.cpp

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1583,6 +1583,12 @@ void StmtChecker::typeCheckASTNode(ASTNode &node) {
15831583
return;
15841584
}
15851585

1586+
if (auto *Cond = node.dyn_cast<StmtConditionElement *>()) {
1587+
bool IsFalsable; // ignored
1588+
TypeChecker::typeCheckStmtConditionElement(*Cond, IsFalsable, DC);
1589+
return;
1590+
}
1591+
15861592
llvm_unreachable("Type checking null ASTNode");
15871593
}
15881594

@@ -1910,6 +1916,19 @@ bool TypeCheckASTNodeAtLocRequest::evaluate(
19101916
class ASTNodeFinder : public ASTWalker {
19111917
SourceManager &SM;
19121918
SourceLoc Loc;
1919+
1920+
/// When the \c ASTNode that we want to check was found inside a brace
1921+
/// statement, we need to store a *reference* to the element in the
1922+
/// \c BraceStmt. When the brace statement gets type checked for result
1923+
/// builders its elements will be updated in-place, which makes
1924+
/// \c FoundNodeRef now point to the type-checked replacement node. We need
1925+
/// this behavior.
1926+
///
1927+
/// But for all other cases, we just want to store a plain \c ASTNode. To
1928+
/// make sure we free the \c ASTNode again, we store it in
1929+
/// \c FoundNodeStorage and set \c FoundNodeRef to point to
1930+
/// \c FoundNodeStorage.
1931+
ASTNode FoundNodeStorage;
19131932
ASTNode *FoundNode = nullptr;
19141933

19151934
/// The innermost DeclContext that contains \c FoundNode.
@@ -1977,6 +1996,20 @@ bool TypeCheckASTNodeAtLocRequest::evaluate(
19771996
}
19781997
// Already walked into.
19791998
return Action::Stop();
1999+
} else if (auto Conditional = dyn_cast<LabeledConditionalStmt>(S)) {
2000+
for (StmtConditionElement &Cond : Conditional->getCond()) {
2001+
if (SM.isBeforeInBuffer(Loc, Cond.getStartLoc())) {
2002+
break;
2003+
}
2004+
SourceLoc endLoc = Lexer::getLocForEndOfToken(SM, Cond.getEndLoc());
2005+
if (SM.isBeforeInBuffer(endLoc, Loc) || endLoc == Loc) {
2006+
continue;
2007+
}
2008+
2009+
FoundNodeStorage = ASTNode(&Cond);
2010+
FoundNode = &FoundNodeStorage;
2011+
return Action::Stop();
2012+
}
19802013
}
19812014

19822015
return Action::Continue(S);
@@ -2017,7 +2050,8 @@ bool TypeCheckASTNodeAtLocRequest::evaluate(
20172050
SourceLoc endLoc = Lexer::getLocForEndOfToken(SM, D->getEndLoc());
20182051
if (!(SM.isBeforeInBuffer(endLoc, Loc) || endLoc == Loc)) {
20192052
if (!isa<TopLevelCodeDecl>(D)) {
2020-
FoundNode = new ASTNode(D);
2053+
FoundNodeStorage = ASTNode(D);
2054+
FoundNode = &FoundNodeStorage;
20212055
}
20222056
}
20232057
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
func foo() {
2+
let myVar: Int? = 2
3+
// RUN: %sourcekitd-test -req=cursor -pos=%(line + 1):10 %s -- %s | %FileCheck %s
4+
if let myVar = myVar {
5+
}
6+
}
7+
8+
// CHECK: source.lang.swift.decl.var.local (4:10-4:15)
9+
// CHECK-NEXT: myVar
10+
// CHECK-NEXT: s:24cursor_on_if_let_binding3fooyyF5myVarL0_Sivp
11+
// CHECK-NEXT: source.lang.swift
12+
// CHECK-NEXT: Int

0 commit comments

Comments
 (0)