Skip to content

Commit 024be91

Browse files
committed
[One-way constraints] Don’t inject one-way constraints into buildEither calls
We need both sides of a buildEither constraint to be unified, so don’t inject one-way constraints on the inputs to buildEither. (cherry picked from commit 7aecca0)
1 parent 6eb4e54 commit 024be91

File tree

2 files changed

+34
-16
lines changed

2 files changed

+34
-16
lines changed

lib/Sema/BuilderTransform.cpp

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,8 @@ class BuilderClosureVisitor
5252
/// Produce a builder call to the given named function with the given arguments.
5353
Expr *buildCallIfWanted(SourceLoc loc,
5454
Identifier fnName, ArrayRef<Expr *> args,
55-
ArrayRef<Identifier> argLabels = {}) {
55+
ArrayRef<Identifier> argLabels,
56+
bool allowOneWay) {
5657
if (!wantExpr)
5758
return nullptr;
5859

@@ -86,7 +87,7 @@ class BuilderClosureVisitor
8687
/*trailing closure*/ nullptr,
8788
/*implicit*/true);
8889

89-
if (ctx.LangOpts.FunctionBuilderOneWayConstraints) {
90+
if (ctx.LangOpts.FunctionBuilderOneWayConstraints && allowOneWay) {
9091
// Form a one-way constraint to prevent backward propagation.
9192
result = new (ctx) OneWayExpr(result);
9293
}
@@ -176,7 +177,9 @@ class BuilderClosureVisitor
176177

177178
// Call Builder.buildBlock(... args ...)
178179
return buildCallIfWanted(braceStmt->getStartLoc(),
179-
ctx.Id_buildBlock, expressions);
180+
ctx.Id_buildBlock, expressions,
181+
/*argLabels=*/{ },
182+
/*allowOneWay=*/true);
180183
}
181184

182185
Expr *visitReturnStmt(ReturnStmt *stmt) {
@@ -201,7 +204,8 @@ class BuilderClosureVisitor
201204
if (!arg)
202205
return nullptr;
203206

204-
return buildCallIfWanted(doStmt->getStartLoc(), ctx.Id_buildDo, arg);
207+
return buildCallIfWanted(doStmt->getStartLoc(), ctx.Id_buildDo, arg,
208+
/*argLabels=*/{ }, /*allowOneWay=*/true);
205209
}
206210

207211
CONTROL_FLOW_STMT(Yield)
@@ -286,7 +290,12 @@ class BuilderClosureVisitor
286290
// so we just need to call `buildIf` now, since we're at the top level.
287291
if (isOptional) {
288292
chainExpr = buildCallIfWanted(ifStmt->getStartLoc(),
289-
ctx.Id_buildIf, chainExpr);
293+
ctx.Id_buildIf, chainExpr,
294+
/*argLabels=*/{ },
295+
/*allowOneWay=*/true);
296+
} else if (ctx.LangOpts.FunctionBuilderOneWayConstraints) {
297+
// Form a one-way constraint to prevent backward propagation.
298+
chainExpr = new (ctx) OneWayExpr(chainExpr);
290299
}
291300

292301
return chainExpr;
@@ -406,7 +415,8 @@ class BuilderClosureVisitor
406415
bool isSecond = (path & 1);
407416
operand = buildCallIfWanted(operand->getStartLoc(),
408417
ctx.Id_buildEither, operand,
409-
{isSecond ? ctx.Id_second : ctx.Id_first});
418+
{isSecond ? ctx.Id_second : ctx.Id_first},
419+
/*allowOneWay=*/false);
410420
}
411421

412422
// Inject into Optional if required. We'll be adding the call to

test/Constraints/function_builder_one_way.swift

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@ enum Either<T,U> {
88

99
@_functionBuilder
1010
struct TupleBuilder {
11+
static func buildBlock<T1>(_ t1: T1) -> T1 {
12+
return t1
13+
}
14+
1115
static func buildBlock<T1, T2>(_ t1: T1, _ t2: T2) -> (T1, T2) {
1216
return (t1, t2)
1317
}
@@ -44,16 +48,18 @@ func tuplify<C: Collection, T>(_ collection: C, @TupleBuilder body: (C.Element)
4448
}
4549

4650
// CHECK: ---Connected components---
47-
// CHECK-NEXT: 0: $T1 $T2 $T3 $T5 $T6 $T7 $T8 $T61 depends on 1
48-
// CHECK-NEXT: 1: $T9 $T11 $T13 $T16 $T30 $T54 $T55 $T56 $T57 $T58 $T59 $T60 depends on 2, 3, 4, 5, 6
49-
// CHECK-NEXT: 6: $T31 $T32 $T34 $T35 $T36 $T47 $T48 $T49 $T50 $T51 $T52 $T53 depends on 7
50-
// CHECK-NEXT: 7: $T37 $T39 $T43 $T44 $T45 $T46 depends on 8, 9
51-
// CHECK-NEXT: 9: $T40 $T41 $T42
52-
// CHECK-NEXT: 8: $T38
53-
// CHECK-NEXT: 5: $T17 $T18 $T19 $T20 $T21 $T22 $T23 $T24 $T25 $T26 $T27 $T28 $T29
54-
// CHECK-NEXT: 4: $T14 $T15
55-
// CHECK-NEXT: 3: $T12
56-
// CHECK-NEXT: 2: $T10
51+
// CHECK-NEXT: 0: $T1 $T2 $T3 $T5 $T6 $T7 $T8 $T69 depends on 1
52+
// CHECK-NEXT: 1: $T9 $T11 $T13 $T16 $T30 $T62 $T63 $T64 $T65 $T66 $T67 $T68 depends on 2, 3, 4, 5, 6
53+
// CHECK-NEXT: 6: $T32 $T43 $T44 $T45 $T46 $T47 $T57 $T58 $T59 $T60 $T61 depends on 7, 10
54+
// CHECK-NEXT: 10: $T48 $T54 $T55 $T56 depends on 11
55+
// CHECK-NEXT: 11: $T49 $T50 $T51 $T52 $T53
56+
// CHECK-NEXT: 7: $T33 $T35 $T39 $T40 $T41 $T42 depends on 8, 9
57+
// CHECK-NEXT: 9: $T36 $T37 $T38
58+
// CHECK-NEXT: 8: $T34
59+
// CHECK-NEXT: 5: $T17 $T18 $T19 $T20 $T21 $T22 $T23 $T24 $T25 $T26 $T27 $T28 $T29
60+
// CHECK-NEXT: 4: $T14 $T15
61+
// CHECK-NEXT: 3: $T12
62+
// CHECK-NEXT: 2: $T10
5763
let names = ["Alice", "Bob", "Charlie"]
5864
let b = true
5965
print(
@@ -67,5 +73,7 @@ print(
6773
if b {
6874
2.71828
6975
["if", "stmt"]
76+
} else {
77+
[1, 2, 3, 4]
7078
}
7179
})

0 commit comments

Comments
 (0)