Skip to content

Commit 56ef379

Browse files
committed
[ConstraintSystem] Integrate IgnoreInvalidFunctionBuilderBody into the solver
1 parent da6bb36 commit 56ef379

File tree

4 files changed

+70
-10
lines changed

4 files changed

+70
-10
lines changed

lib/Sema/BuilderTransform.cpp

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1622,16 +1622,23 @@ ConstraintSystem::matchFunctionBuilder(
16221622
// Pre-check the body: pre-check any expressions in it and look
16231623
// for return statements.
16241624
auto request =
1625-
PreCheckFunctionBuilderRequest{{fn, /*SuppressDiagnostics=*/false}};
1625+
PreCheckFunctionBuilderRequest{{fn, /*SuppressDiagnostics=*/true}};
16261626
switch (evaluateOrDefault(getASTContext().evaluator, request,
16271627
FunctionBuilderBodyPreCheck::Error)) {
16281628
case FunctionBuilderBodyPreCheck::Okay:
16291629
// If the pre-check was okay, apply the function-builder transform.
16301630
break;
16311631

1632-
case FunctionBuilderBodyPreCheck::Error:
1633-
// If the pre-check had an error, flag that.
1634-
return getTypeMatchFailure(locator);
1632+
case FunctionBuilderBodyPreCheck::Error: {
1633+
if (!shouldAttemptFixes())
1634+
return getTypeMatchFailure(locator);
1635+
1636+
if (recordFix(IgnoreInvalidFunctionBuilderBody::create(
1637+
*this, getConstraintLocator(fn.getBody()))))
1638+
return getTypeMatchFailure(locator);
1639+
1640+
return getTypeMatchSuccess();
1641+
}
16351642

16361643
case FunctionBuilderBodyPreCheck::HasReturnStmt:
16371644
// If the body has a return statement, suppress the transform but

lib/Sema/CSBindings.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1206,7 +1206,14 @@ bool TypeVariableBinding::attempt(ConstraintSystem &cs) const {
12061206
} else if (TypeVar->getImpl().isClosureParameterType()) {
12071207
fix = SpecifyClosureParameterType::create(cs, dstLocator);
12081208
} else if (TypeVar->getImpl().isClosureResultType()) {
1209-
fix = SpecifyClosureReturnType::create(cs, dstLocator);
1209+
auto *locator = TypeVar->getImpl().getLocator();
1210+
auto *closure = castToExpr<ClosureExpr>(locator->getAnchor());
1211+
// If the whole body is being ignored due to a pre-check failure,
1212+
// let's not record a fix about result type since there is
1213+
// just not enough context to infer it without a body.
1214+
if (!cs.hasFixFor(cs.getConstraintLocator(closure->getBody()),
1215+
FixKind::IgnoreInvalidFunctionBuilderBody))
1216+
fix = SpecifyClosureReturnType::create(cs, dstLocator);
12101217
} else if (srcLocator->directlyAt<ObjectLiteralExpr>()) {
12111218
fix = SpecifyObjectLiteralTypeImport::create(cs, dstLocator);
12121219
} else if (srcLocator->isKeyPathRoot()) {

test/Constraints/function_builder_diags.swift

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ enum Either<T,U> {
66
}
77

88
@_functionBuilder
9-
struct TupleBuilder { // expected-note 3{{struct 'TupleBuilder' declared here}}
9+
struct TupleBuilder { // expected-note 2 {{struct 'TupleBuilder' declared here}}
1010
static func buildBlock() -> () { }
1111

1212
static func buildBlock<T1>(_ t1: T1) -> T1 {
@@ -87,7 +87,7 @@ func testDiags() {
8787
// For loop
8888
tuplify(true) { _ in
8989
17
90-
for c in name { // expected-error{{closure containing control flow statement cannot be used with function builder 'TupleBuilder'}}
90+
for c in name {
9191
// expected-error@-1 {{cannot find 'name' in scope}}
9292
}
9393
}
@@ -418,13 +418,16 @@ func testNonExhaustiveSwitch(e: E) {
418418
// rdar://problem/59856491
419419
struct TestConstraintGenerationErrors {
420420
@TupleBuilder var buildTupleFnBody: String {
421-
let a = nil // expected-error {{'nil' requires a contextual type}}
421+
let a = nil // There is no diagnostic here because next line fails to pre-check, so body is invalid
422422
String(nothing) // expected-error {{cannot find 'nothing' in scope}}
423423
}
424424

425+
@TupleBuilder var nilWithoutContext: String {
426+
let a = nil // expected-error {{'nil' requires a contextual type}}
427+
}
428+
425429
func buildTupleClosure() {
426-
// FIXME: suppress the ambiguity error
427-
tuplify(true) { _ in // expected-error {{type of expression is ambiguous without more context}}
430+
tuplify(true) { _ in
428431
let a = nothing // expected-error {{cannot find 'nothing' in scope}}
429432
String(nothing) // expected-error {{cannot find 'nothing' in scope}}
430433
}

test/Constraints/rdar65320500.swift

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// RUN: %target-typecheck-verify-swift
2+
3+
struct Result {}
4+
5+
@_functionBuilder
6+
struct Builder {
7+
static func buildBlock() -> Result {
8+
Result()
9+
}
10+
}
11+
12+
func test_builder<T>(@Builder _: () -> T) {}
13+
func test_builder(@Builder _: () -> Int) {}
14+
15+
test_builder {
16+
let _ = 0
17+
18+
if let x = does_not_exist { // expected-error {{cannot find 'does_not_exist' in scope}}
19+
}
20+
}
21+
22+
func test(_: Int) -> Bool {
23+
return false
24+
}
25+
26+
test_builder {
27+
let totalSeconds = 42000
28+
test(totalseconds / 3600) // expected-error {{cannot find 'totalseconds' in scope}}
29+
}
30+
31+
test_builder {
32+
test(doesntExist()) // expected-error {{cannot find 'doesntExist' in scope}}
33+
34+
if let result = doesntExist() { // expected-error {{cannot find 'doesntExist' in scope}}
35+
}
36+
37+
if bar = test(42) {} // expected-error {{cannot find 'bar' in scope}}
38+
39+
let foo = bar() // expected-error {{cannot find 'bar' in scope}}
40+
41+
switch (doesntExist()) { // expected-error {{cannot find 'doesntExist' in scope}}
42+
}
43+
}

0 commit comments

Comments
 (0)