Skip to content

Commit 8781645

Browse files
committed
[BuilderTransform] AST Transform: Inject buildOptional to top-level if else conditions
Fixes a bug in `buildOptional` injection for `if else` branches without unconditional `else` which leaves type-join with just `.some(...)` and results in optionality mismatch if `buildOptional` don't not produce an optional type.
1 parent af94916 commit 8781645

File tree

2 files changed

+54
-2
lines changed

2 files changed

+54
-2
lines changed

lib/Sema/BuilderTransform.cpp

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1245,10 +1245,26 @@ class ResultBuilderTransform
12451245
auto *builderCall =
12461246
buildWrappedChainPayload(branchVarRef, i, numPayloads, isOptional);
12471247

1248+
auto isTopLevel = [&](Stmt *anchor) {
1249+
if (ifStmt->getThenStmt() == anchor)
1250+
return true;
1251+
1252+
// The situation is this:
1253+
//
1254+
// if <cond> {
1255+
// ...
1256+
// } else if <other-cond> {
1257+
// ...
1258+
// }
1259+
if (auto *innerIf = getAsStmt<IfStmt>(ifStmt->getElseStmt()))
1260+
return innerIf->getThenStmt() == anchor;
1261+
1262+
return ifStmt->getElseStmt() == anchor;
1263+
};
1264+
12481265
// The operand should have optional type if we had optional results,
12491266
// so we just need to call `buildIf` now, since we're at the top level.
1250-
if (isOptional && (ifStmt->getThenStmt() == anchor ||
1251-
ifStmt->getElseStmt() == anchor)) {
1267+
if (isOptional && isTopLevel(anchor)) {
12521268
builderCall = buildCallIfWanted(ifStmt->getEndLoc(),
12531269
builder.getBuildOptionalId(),
12541270
builderCall, /*argLabels=*/{});

test/Constraints/result_builder.swift

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1216,3 +1216,39 @@ do {
12161216
}
12171217
// CHECK: (42, "", [true])
12181218
}
1219+
1220+
do {
1221+
@resultBuilder
1222+
struct MyBuilder {
1223+
static func buildBlock<T1: ExpressibleByStringLiteral>(_ t1: T1) -> (T1) {
1224+
return (t1)
1225+
}
1226+
1227+
static func buildBlock<T1, T2>(_ t1: T1, _ t2: T2) -> (T1, T2) {
1228+
return (t1, t2)
1229+
}
1230+
1231+
static func buildOptional<T>(_ value: T?) -> T { return value! }
1232+
1233+
static func buildEither<T>(first value: T) -> T {
1234+
return value
1235+
}
1236+
1237+
static func buildEither<U>(second value: U) -> U {
1238+
return value
1239+
}
1240+
}
1241+
1242+
func test<T>(@MyBuilder _ builder: (Int) -> T) {
1243+
print(builder(42))
1244+
}
1245+
1246+
test {
1247+
if $0 < 0 {
1248+
"\($0)"
1249+
} else if $0 == 42 {
1250+
"the answer"
1251+
}
1252+
}
1253+
// CHECK: the answer
1254+
}

0 commit comments

Comments
 (0)