diff --git a/go/ssa/builder.go b/go/ssa/builder.go
index a75257c..3336203 100644
--- a/go/ssa/builder.go
+++ b/go/ssa/builder.go
@@ -1467,13 +1467,14 @@
var nextCond *BasicBlock
for _, cond := range cc.List {
nextCond = fn.newBasicBlock("switch.next")
- // TODO(adonovan): opt: when tag==vTrue, we'd
- // get better code if we use b.cond(cond)
- // instead of BinOp(EQL, tag, b.expr(cond))
- // followed by If. Don't forget conversions
- // though.
- cond := emitCompare(fn, token.EQL, tag, b.expr(fn, cond), cond.Pos())
- emitIf(fn, cond, body, nextCond)
+ // For boolean switches, emit short-circuit control flow,
+ // just like an if/else-chain.
+ if tag == vTrue && !isNonTypeParamInterface(fn.info.Types[cond].Type) {
+ b.cond(fn, cond, body, nextCond)
+ } else {
+ c := emitCompare(fn, token.EQL, tag, b.expr(fn, cond), cond.Pos())
+ emitIf(fn, c, body, nextCond)
+ }
fn.currentBlock = nextCond
}
fn.currentBlock = body
diff --git a/gopls/internal/analysis/yield/testdata/src/a/a.go b/gopls/internal/analysis/yield/testdata/src/a/a.go
index 820cabd..15ee3f5 100644
--- a/gopls/internal/analysis/yield/testdata/src/a/a.go
+++ b/gopls/internal/analysis/yield/testdata/src/a/a.go
@@ -145,3 +145,21 @@
}
}
}
+
+// Regression test for issue #77681. A boolean switch is now
+// handled just like an if/else chain in the SSA builder.
+func switchShortCircuit(seq iter.Seq[int]) iter.Seq[int] {
+ return func(yield func(int) bool) {
+ for item := range seq {
+ isZero := item == 0
+ switch {
+ case !isZero && !yield(item): // ok
+ return
+ case !isZero:
+ continue
+ case !yield(0): // ok
+ return
+ }
+ }
+ }
+}