[Sema] Continue type-checking for body when preamble fails

Skipping type-checking the body when the preamble fails to type-check
seems to be more of a historical artifact than intentional behavior.
Certain elements of the body may still get type-checked through
request evaluation, and as such may introduce autoclosures that won't
be properly contextualized. 

Make sure we continue type-checking the body even if the preamble
fails. We already invalidate any variables bound in the element
pattern, so downstream type-checking should be able to handle it
just fine. This ensures autoclosures get contextualized, and that
we're still able to provide semantic diagnostics for other issues in
the body.

rdar://136500008
This commit is contained in:
Hamish Knight
2025-05-15 20:48:25 +01:00
parent 5856ec09f8
commit abf0808173
4 changed files with 20 additions and 6 deletions

View File

@@ -1433,8 +1433,7 @@ public:
}
Stmt *visitForEachStmt(ForEachStmt *S) {
if (TypeChecker::typeCheckForEachPreamble(DC, S))
return nullptr;
TypeChecker::typeCheckForEachPreamble(DC, S);
// Type-check the body of the loop.
auto sourceFile = DC->getParentSourceFile();

View File

@@ -210,8 +210,10 @@ func missingControllingExprInForEach() {
// The #if block is used to provide a scope for the for stmt to force it to end
// where necessary to provoke the crash.
#if true // <rdar://problem/21679557> compiler crashes on "for{{"
// expected-error @+2 {{expected pattern}}
// expected-error @+1 {{expected Sequence expression for for-each loop}}
// expected-error @+4 {{expected pattern}}
// expected-error @+3 {{expected Sequence expression for for-each loop}}
// expected-error @+2 {{closure expression is unused}}
// expected-note @+1 {{did you mean to use a 'do' statement?}}
for{{ // expected-note 2 {{to match this opening '{'}}
#endif // expected-error {{expected '}' at end of closure}} expected-error {{expected '}' at end of brace statement}}

View File

@@ -32,9 +32,9 @@ for ; other<count; other+=1 { // expected-error {{C-style for statement was remo
}
for (var number : Int8 = start; number < count; number+=1) { // expected-error {{C-style for statement was removed in Swift 3}} {{none}}
print(number)
print(number) // expected-error {{cannot find 'number' in scope}}
}
for (var m : Int8 = start; m < count; m+=1) { // expected-error {{C-style for statement was removed in Swift 3}} {{none}}
m += 3
m += 3 // expected-error {{cannot find 'm' in scope}}
}

View File

@@ -351,3 +351,16 @@ do {
}
}
}
// Make sure the bodies still type-check okay if the preamble is invalid.
func testInvalidPreamble() {
func takesAutoclosure(_ x: @autoclosure () -> Int) -> Int { 0 }
for _ in undefined { // expected-error {{cannot find 'undefined' in scope}}
let a = takesAutoclosure(0) // Fine
}
for x in undefined { // expected-error {{cannot find 'undefined' in scope}}
let b: Int = x // No type error, `x` is invalid.
_ = "" as Int // expected-error {{cannot convert value of type 'String' to type 'Int' in coercion}}
}
}