Skip to content

Commit 9401926

Browse files
authored
Merge pull request #63505 from xedin/issue-63455
[CSGen] Handle recursive use of variable declarations
2 parents b9cf9ad + 83dd93a commit 9401926

File tree

4 files changed

+58
-10
lines changed

4 files changed

+58
-10
lines changed

lib/Sema/CSGen.cpp

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1354,20 +1354,33 @@ namespace {
13541354
Type visitDeclRefExpr(DeclRefExpr *E) {
13551355
auto locator = CS.getConstraintLocator(E);
13561356

1357+
auto invalidateReference = [&]() -> Type {
1358+
auto *hole = CS.createTypeVariable(locator, TVO_CanBindToHole);
1359+
(void)CS.recordFix(AllowRefToInvalidDecl::create(CS, locator));
1360+
CS.setType(E, hole);
1361+
return hole;
1362+
};
1363+
13571364
Type knownType;
13581365
if (auto *VD = dyn_cast<VarDecl>(E->getDecl())) {
13591366
knownType = CS.getTypeIfAvailable(VD);
13601367
if (!knownType)
13611368
knownType = CS.getVarType(VD);
13621369

13631370
if (knownType) {
1371+
// An out-of-scope type variable could be a type of a declaration
1372+
// only in diagnostic mode when invalid variable declaration is
1373+
// recursively referenced inside of a multi-statement closure
1374+
// located somewhere within its initializer e.g.:
1375+
// `let x = [<call>] { ... print(x) }`
1376+
if (auto *typeVar = knownType->getAs<TypeVariableType>()) {
1377+
if (!CS.isActiveTypeVariable(typeVar))
1378+
return invalidateReference();
1379+
}
1380+
13641381
// If the known type has an error, bail out.
13651382
if (knownType->hasError()) {
1366-
auto *hole = CS.createTypeVariable(locator, TVO_CanBindToHole);
1367-
(void)CS.recordFix(AllowRefToInvalidDecl::create(CS, locator));
1368-
if (!CS.hasType(E))
1369-
CS.setType(E, hole);
1370-
return hole;
1383+
return invalidateReference();
13711384
}
13721385

13731386
if (!knownType->hasPlaceholder()) {
@@ -1384,10 +1397,7 @@ namespace {
13841397
// (in getTypeOfReference) so we can match non-error param types.
13851398
if (!knownType && E->getDecl()->isInvalid() &&
13861399
!CS.isForCodeCompletion()) {
1387-
auto *hole = CS.createTypeVariable(locator, TVO_CanBindToHole);
1388-
(void)CS.recordFix(AllowRefToInvalidDecl::create(CS, locator));
1389-
CS.setType(E, hole);
1390-
return hole;
1400+
return invalidateReference();
13911401
}
13921402

13931403
// Create an overload choice referencing this declaration and immediately

lib/Sema/CSSyntacticElement.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ class TypeVariableRefFinder : public ASTWalker {
7474
if (auto *DRE = dyn_cast<DeclRefExpr>(expr)) {
7575
auto *decl = DRE->getDecl();
7676

77-
if (auto type = CS.getTypeIfAvailable(DRE->getDecl())) {
77+
if (auto type = CS.getTypeIfAvailable(decl)) {
7878
auto &ctx = CS.getASTContext();
7979
// If this is not one of the closure parameters which
8080
// is inferrable from the body, let's replace type

test/expr/closure/multi_statement.swift

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -650,3 +650,16 @@ func test_that_closures_are_attempted_in_order() {
650650
return false
651651
}
652652
}
653+
654+
// https://github.com/apple/swift/issues/63455
655+
func test_recursive_var_reference_in_multistatement_closure() {
656+
func takeClosure(_ x: () -> Void) {}
657+
658+
func test(optionalInt: Int?) {
659+
takeClosure {
660+
let int = optionalInt { // expected-error {{cannot call value of non-function type 'Int?'}}
661+
print(int)
662+
}
663+
}
664+
}
665+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// RUN: %swift-ide-test -code-completion -source-filename %s -code-completion-token COMPLETE
2+
3+
func sheet(onDismiss: () -> Void) -> EmptyView {
4+
fatalError()
5+
}
6+
7+
@resultBuilder struct ViewBuilder2 {
8+
static func buildBlock(_ content: EmptyView) -> EmptyView {
9+
return content
10+
}
11+
}
12+
13+
struct EmptyView {}
14+
15+
struct SettingsView {
16+
var importedFile: Int?
17+
18+
@ViewBuilder2 var body2: EmptyView {
19+
sheet {
20+
#^COMPLETE^#if let url = self.importedFile {
21+
print(url)
22+
}
23+
}
24+
}
25+
}

0 commit comments

Comments
 (0)