Skip to content

Commit abbaaa9

Browse files
authored
Merge pull request #63642 from xedin/issue-63455-addition-5.8
[5.8][CSGen] Detect nested out-of-scope variables in recursive declarations
2 parents 3d736de + 9e77be0 commit abbaaa9

File tree

3 files changed

+71
-10
lines changed

3 files changed

+71
-10
lines changed

lib/Sema/CSGen.cpp

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1351,20 +1351,41 @@ namespace {
13511351
Type visitDeclRefExpr(DeclRefExpr *E) {
13521352
auto locator = CS.getConstraintLocator(E);
13531353

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

13601367
if (knownType) {
1368+
// An out-of-scope type variable(s) could appear the type of
1369+
// a declaration only in diagnostic mode when invalid variable
1370+
// declaration is recursively referenced inside of a multi-statement
1371+
// closure located somewhere within its initializer e.g.:
1372+
// `let x = [<call>] { ... print(x) }`. It happens because the
1373+
// variable assumes the result type of its initializer unless
1374+
// its specified explicitly.
1375+
if (isa<ClosureExpr>(CurDC) && knownType->hasTypeVariable()) {
1376+
if (knownType.findIf([&](Type type) {
1377+
auto *typeVar = type->getAs<TypeVariableType>();
1378+
if (!typeVar || CS.getFixedType(typeVar))
1379+
return false;
1380+
1381+
return !CS.isActiveTypeVariable(typeVar);
1382+
}))
1383+
return invalidateReference();
1384+
}
1385+
13611386
// If the known type has an error, bail out.
13621387
if (knownType->hasError()) {
1363-
auto *hole = CS.createTypeVariable(locator, TVO_CanBindToHole);
1364-
(void)CS.recordFix(AllowRefToInvalidDecl::create(CS, locator));
1365-
if (!CS.hasType(E))
1366-
CS.setType(E, hole);
1367-
return hole;
1388+
return invalidateReference();
13681389
}
13691390

13701391
if (!knownType->hasPlaceholder()) {
@@ -1381,10 +1402,7 @@ namespace {
13811402
// (in getTypeOfReference) so we can match non-error param types.
13821403
if (!knownType && E->getDecl()->isInvalid() &&
13831404
!CS.isForCodeCompletion()) {
1384-
auto *hole = CS.createTypeVariable(locator, TVO_CanBindToHole);
1385-
(void)CS.recordFix(AllowRefToInvalidDecl::create(CS, locator));
1386-
CS.setType(E, hole);
1387-
return hole;
1405+
return invalidateReference();
13881406
}
13891407

13901408
// 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
@@ -64,7 +64,7 @@ class TypeVariableRefFinder : public ASTWalker {
6464
if (auto *DRE = dyn_cast<DeclRefExpr>(expr)) {
6565
auto *decl = DRE->getDecl();
6666

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

test/expr/closure/multi_statement.swift

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -650,3 +650,46 @@ func test_that_closures_are_attempted_in_order() {
650650
return false
651651
}
652652
}
653+
654+
func test_use_of_concrete_params_in_for_condition() {
655+
struct S {
656+
var cond: Bool
657+
}
658+
659+
func test(_: (S) -> Void) {}
660+
661+
test { data in
662+
for i in 0...10 where !data.cond { // Ok
663+
print(i)
664+
}
665+
}
666+
}
667+
668+
// https://github.com/apple/swift/issues/63455
669+
func test_recursive_var_reference_in_multistatement_closure() {
670+
struct MyStruct {
671+
func someMethod() {}
672+
}
673+
674+
func takeClosure(_ x: () -> Void) {}
675+
676+
func test(optionalInt: Int?, themes: MyStruct?) {
677+
takeClosure {
678+
let int = optionalInt { // expected-error {{cannot call value of non-function type 'Int?'}}
679+
print(int)
680+
}
681+
}
682+
683+
takeClosure {
684+
let theme = themes?.someMethod() { // expected-error {{extra trailing closure passed in call}}
685+
_ = theme
686+
}
687+
}
688+
689+
takeClosure {
690+
let theme = themes?.filter({ $0 }) { // expected-error {{value of type 'MyStruct' has no member 'filter'}}
691+
_ = theme
692+
}
693+
}
694+
}
695+
}

0 commit comments

Comments
 (0)