Skip to content

Commit 2ce7f1c

Browse files
committed
[Sema] Add for-in lazy type-checking hack for IDE inspection
Avoid type-checking the `where` clause when computing the interface type of a variable bound in the pattern of the loop as otherwise that will trigger cycles and give us an ErrorType result.
1 parent 4397036 commit 2ce7f1c

File tree

4 files changed

+38
-13
lines changed

4 files changed

+38
-13
lines changed

lib/Sema/TypeCheckConstraints.cpp

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -893,7 +893,8 @@ bool TypeChecker::typeCheckPatternBinding(PatternBindingDecl *PBD,
893893
return hadError;
894894
}
895895

896-
bool TypeChecker::typeCheckForEachPreamble(DeclContext *dc, ForEachStmt *stmt) {
896+
bool TypeChecker::typeCheckForEachPreamble(DeclContext *dc, ForEachStmt *stmt,
897+
bool skipWhere) {
897898
auto &Context = dc->getASTContext();
898899
FrontendStatsTracer statsTracer(Context.Stats, "typecheck-for-each", stmt);
899900
PrettyStackTraceStmt stackTrace(Context, "type-checking-for-each", stmt);
@@ -902,18 +903,20 @@ bool TypeChecker::typeCheckForEachPreamble(DeclContext *dc, ForEachStmt *stmt) {
902903
if (!typeCheckTarget(target))
903904
return true;
904905

905-
if (auto *where = stmt->getWhere()) {
906-
auto boolType = dc->getASTContext().getBoolType();
907-
if (!boolType)
908-
return true;
906+
if (!skipWhere) {
907+
if (auto *where = stmt->getWhere()) {
908+
auto boolType = dc->getASTContext().getBoolType();
909+
if (!boolType)
910+
return true;
909911

910-
SyntacticElementTarget whereClause(where, dc, {boolType, CTP_Condition},
911-
/*isDiscarded=*/false);
912-
auto result = typeCheckTarget(whereClause);
913-
if (!result)
914-
return true;
912+
SyntacticElementTarget whereClause(where, dc, {boolType, CTP_Condition},
913+
/*isDiscarded=*/false);
914+
auto result = typeCheckTarget(whereClause);
915+
if (!result)
916+
return true;
915917

916-
stmt->setWhere(result->getAsExpr());
918+
stmt->setWhere(result->getAsExpr());
919+
}
917920
}
918921

919922
// Check to see if the sequence expr is throwing (in async context),

lib/Sema/TypeCheckStmt.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1463,7 +1463,15 @@ class StmtChecker : public StmtVisitor<StmtChecker, Stmt*> {
14631463
}
14641464

14651465
Stmt *visitForEachStmt(ForEachStmt *S) {
1466-
TypeChecker::typeCheckForEachPreamble(DC, S);
1466+
// If we're performing IDE inspection, we also want to skip the where
1467+
// clause if we're leaving the body unchecked.
1468+
// FIXME: This is a hack to avoid cycles through NamingPatternRequest when
1469+
// doing lazy type-checking, we ought to fix the request to be granular in
1470+
// the type-checking work it kicks.
1471+
bool skipWhere = LeaveBraceStmtBodyUnchecked &&
1472+
Ctx.SourceMgr.hasIDEInspectionTargetBuffer();
1473+
1474+
TypeChecker::typeCheckForEachPreamble(DC, S, skipWhere);
14671475

14681476
// Type-check the body of the loop.
14691477
auto sourceFile = DC->getParentSourceFile();

lib/Sema/TypeChecker.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -799,7 +799,8 @@ bool typeCheckPatternBinding(PatternBindingDecl *PBD, unsigned patternNumber,
799799
/// together.
800800
///
801801
/// \returns true if a failure occurred.
802-
bool typeCheckForEachPreamble(DeclContext *dc, ForEachStmt *stmt);
802+
bool typeCheckForEachPreamble(DeclContext *dc, ForEachStmt *stmt,
803+
bool skipWhereClause);
803804

804805
/// Compute the set of captures for the given closure.
805806
void computeCaptures(AbstractClosureExpr *ACE);

test/IDE/complete_loop.swift

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,3 +81,16 @@ do {
8181
for t in #^LOOP_8^# {}
8282
}
8383
// LOOP_8-DAG: Keyword[repeat]/None: repeat; name=repeat
84+
85+
do {
86+
struct S {
87+
var foo: Bool
88+
}
89+
func bar(_ xs: [S]) {
90+
// Make sure we can resolve 'x' here without causing a request cycle.
91+
for x in xs where x.foo {
92+
x.#^LOOP_9^#
93+
// LOOP_9-DAG: Decl[InstanceVar]/CurrNominal: foo[#Bool#]; name=foo
94+
}
95+
}
96+
}

0 commit comments

Comments
 (0)