Skip to content

Commit 847dbce

Browse files
authored
Merge pull request #64334 from ahoppen/ahoppen/dont-precheck-twice
[Sema] Don't abort the result builder transform if the builder contained an ErrorExpr
2 parents b3bbaec + cbb32aa commit 847dbce

6 files changed

+31
-39
lines changed

lib/Sema/BuilderTransform.cpp

+13-13
Original file line numberDiff line numberDiff line change
@@ -2462,8 +2462,11 @@ ConstraintSystem::matchResultBuilder(AnyFunctionRef fn, Type builderType,
24622462
return getTypeMatchSuccess();
24632463
}
24642464

2465-
// Pre-check the body: pre-check any expressions in it and look
2466-
// for return statements.
2465+
// We have already pre-checked the result builder body. Technically, we
2466+
// shouldn't need to do anything here, but there was a bug here that we did
2467+
// not apply the result builder transform if it contained an explicit return.
2468+
// To maintain source compatibility, we still need to check for HasReturnStmt.
2469+
// https://github.com/apple/swift/issues/64332.
24672470
auto request =
24682471
PreCheckResultBuilderRequest{{fn, /*SuppressDiagnostics=*/false}};
24692472
switch (evaluateOrDefault(getASTContext().evaluator, request,
@@ -2473,16 +2476,10 @@ ConstraintSystem::matchResultBuilder(AnyFunctionRef fn, Type builderType,
24732476
break;
24742477

24752478
case ResultBuilderBodyPreCheck::Error: {
2476-
InvalidResultBuilderBodies.insert(fn);
2477-
2478-
if (!shouldAttemptFixes())
2479-
return getTypeMatchFailure(locator);
2480-
2481-
if (recordFix(IgnoreInvalidResultBuilderBody::create(
2482-
*this, getConstraintLocator(fn.getAbstractClosureExpr()))))
2483-
return getTypeMatchFailure(locator);
2484-
2485-
return getTypeMatchSuccess();
2479+
llvm_unreachable(
2480+
"Running PreCheckResultBuilderRequest on a function shouldn't run "
2481+
"preCheckExpression and thus we should never enter this case.");
2482+
break;
24862483
}
24872484

24882485
case ResultBuilderBodyPreCheck::HasReturnStmt:
@@ -2800,8 +2797,11 @@ class PreCheckResultBuilderApplication : public ASTWalker {
28002797

28012798
ResultBuilderBodyPreCheck PreCheckResultBuilderRequest::evaluate(
28022799
Evaluator &evaluator, PreCheckResultBuilderDescriptor owner) const {
2800+
// Closures should already be pre-checked when we run this, so there's no need
2801+
// to pre-check them again.
2802+
bool skipPrecheck = owner.Fn.getAbstractClosureExpr();
28032803
return PreCheckResultBuilderApplication(
2804-
owner.Fn, /*skipPrecheck=*/false,
2804+
owner.Fn, skipPrecheck,
28052805
/*suppressDiagnostics=*/owner.SuppressDiagnostics)
28062806
.run();
28072807
}

test/Constraints/rdar65320500.swift

+7-4
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
struct Result {}
44

55
@resultBuilder
6-
struct Builder {
6+
struct Builder { // expected-note 4 {{add 'buildOptional(_:)' to the result builder 'Builder' to add support for 'if' statements without an 'else'}}
77
static func buildBlock() -> Result {
88
Result()
99
}
@@ -12,10 +12,12 @@ struct Builder {
1212
func test_builder<T>(@Builder _: () -> T) {}
1313
func test_builder(@Builder _: () -> Int) {}
1414

15-
test_builder {
15+
test_builder { // expected-error {{no exact matches in call to global function 'test_builder'}}
1616
let _ = 0
1717

18-
if let x = does_not_exist { // expected-error {{cannot find 'does_not_exist' in scope}}
18+
// expected-error@+2 {{cannot find 'does_not_exist' in scope}}
19+
// expected-note@+1 2 {{closure containing control flow statement cannot be used with result builder 'Builder'}}
20+
if let x = does_not_exist {
1921
}
2022
}
2123

@@ -28,9 +30,10 @@ test_builder {
2830
test(totalseconds / 3600) // expected-error {{cannot find 'totalseconds' in scope; did you mean 'totalSeconds'?}}
2931
}
3032

31-
test_builder {
33+
test_builder { // expected-error {{no exact matches in call to global function 'test_builder'}}
3234
test(doesntExist()) // expected-error {{cannot find 'doesntExist' in scope}}
3335

36+
// expected-note@+1 2 {{closure containing control flow statement cannot be used with result builder 'Builder'}}
3437
if let result = doesntExist() { // expected-error {{cannot find 'doesntExist' in scope}}
3538
}
3639

test/Constraints/result_builder_diags.swift

+8-7
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,9 @@ enum Either<T,U> {
55
case second(U)
66
}
77

8-
@resultBuilder
9-
struct TupleBuilder { // expected-note {{struct 'TupleBuilder' declared here}}
8+
// expected-note @+2 {{add 'buildArray(_:)' to the result builder 'TupleBuilder' to add support for 'for'..'in' loops}}
9+
// expected-note @+1 2 {{struct 'TupleBuilder' declared here}}
10+
@resultBuilder struct TupleBuilder {
1011
static func buildBlock() -> () { }
1112

1213
static func buildBlock<T1>(_ t1: T1) -> T1 {
@@ -78,7 +79,7 @@ struct TupleBuilderWithoutIf { // expected-note 3{{struct 'TupleBuilderWithoutIf
7879
static func buildDo<T>(_ value: T) -> T { return value }
7980
}
8081

81-
func tuplify<T>(_ cond: Bool, @TupleBuilder body: (Bool) -> T) { // expected-note 2{{in call to function 'tuplify(_:body:)'}}
82+
func tuplify<T>(_ cond: Bool, @TupleBuilder body: (Bool) -> T) { // expected-note {{'tuplify(_:body:)' declared here}}
8283
print(body(cond))
8384
}
8485

@@ -88,9 +89,9 @@ func tuplifyWithoutIf<T>(_ cond: Bool, @TupleBuilderWithoutIf body: (Bool) -> T)
8889

8990
func testDiags() {
9091
// For loop
91-
tuplify(true) { _ in // expected-error {{generic parameter 'T' could not be inferred}}
92+
tuplify(true) { _ in
9293
17
93-
for c in name {
94+
for c in name { // expected-error {{closure containing control flow statement cannot be used with result builder 'TupleBuilder'}}
9495
// expected-error@-1 {{cannot find 'name' in scope}}
9596
}
9697
}
@@ -464,7 +465,7 @@ struct TestConstraintGenerationErrors {
464465
}
465466

466467
func buildTupleClosure() {
467-
tuplify(true) { _ in // expected-error {{generic parameter 'T' could not be inferred}}
468+
tuplify(true) { _ in
468469
let a = nothing // expected-error {{cannot find 'nothing' in scope}}
469470
String(nothing) // expected-error {{cannot find 'nothing' in scope}}
470471
}
@@ -732,7 +733,7 @@ struct TuplifiedStructWithInvalidClosure {
732733

733734
@TupleBuilder var nestedErrorsDiagnosedByParser: some Any {
734735
tuplify(true) { _ in
735-
tuplify { _ in
736+
tuplify { _ in // expected-error {{missing argument for parameter #1 in call}}
736737
self. // expected-error {{expected member name following '.'}}
737738
}
738739
42

test/IDE/complete_ambiguous.swift

+1-2
Original file line numberDiff line numberDiff line change
@@ -424,11 +424,10 @@ CreateThings {
424424
}
425425
}
426426

427-
// FIXME: No results in multi-statement closure with erroreous sibling result builder element
428427
CreateThings {
429428
Thing { point in
430429
print("hello")
431-
point.#^MULTICLOSURE_FUNCBUILDER_FIXME?check=NORESULTS^#
430+
point.#^MULTICLOSURE_FUNCBUILDER_FIXME?check=POINT_MEMBER^#
432431
}
433432
Thing. // ErrorExpr
434433
}

test/IDE/complete_literal.swift

+2-10
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,5 @@
1-
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=LITERAL1 | %FileCheck %s -check-prefix=LITERAL1
2-
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=LITERAL2 | %FileCheck %s -check-prefix=LITERAL2
3-
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=LITERAL3 | %FileCheck %s -check-prefix=LITERAL3
4-
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=LITERAL4 | %FileCheck %s -check-prefix=LITERAL4
5-
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=LITERAL5 | %FileCheck %s -check-prefix=LITERAL5
6-
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=LITERAL6 | %FileCheck %s -check-prefix=LITERAL6
7-
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=LITERAL7 | %FileCheck %s -check-prefix=LITERAL7
8-
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=LITERAL8 | %FileCheck %s -check-prefix=LITERAL8
9-
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=LITERAL9 | %FileCheck %s -check-prefix=LITERAL9
10-
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=LITERAL10 | %FileCheck %s -check-prefix=LITERAL10
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swift-ide-test -batch-code-completion -source-filename %s -filecheck %raw-FileCheck -completion-output-dir %t
113

124
{
135
1.#^LITERAL1^#

test/IDE/complete_value_expr.swift

-3
Original file line numberDiff line numberDiff line change
@@ -1204,9 +1204,6 @@ func testTypeCheckWithUnsolvedVariables3() {
12041204
// TC_UNSOLVED_VARIABLES_3-DAG: Decl[InstanceMethod]/CurrNominal: addString({#(s): String#})[#BuilderStyle<Int>#]{{; name=.+$}}
12051205
// TC_UNSOLVED_VARIABLES_3-DAG: Decl[InstanceMethod]/CurrNominal: add({#(t): Int#})[#BuilderStyle<Int>#]{{; name=.+$}}
12061206
// TC_UNSOLVED_VARIABLES_3-DAG: Decl[InstanceMethod]/CurrNominal: get()[#Int#]{{; name=.+$}}
1207-
// TC_UNSOLVED_VARIABLES_3-DAG: Keyword[self]/CurrNominal: self[#BuilderStyle<Double>#]{{; name=.+$}}
1208-
// TC_UNSOLVED_VARIABLES_3-DAG: Decl[InstanceMethod]/CurrNominal: addString({#(s): String#})[#BuilderStyle<Double>#]{{; name=.+$}}
1209-
// TC_UNSOLVED_VARIABLES_3-DAG: Decl[InstanceMethod]/CurrNominal: add({#(t): Double#})[#BuilderStyle<Double>#]{{; name=.+$}}
12101207
// TC_UNSOLVED_VARIABLES_3: End completions
12111208

12121209
func testTypeCheckNil() {

0 commit comments

Comments
 (0)