From 04ba0e26c045fa45ef3a882f590ef5aabdca0a04 Mon Sep 17 00:00:00 2001 From: Leonard Lyubich Date: Fri, 14 Nov 2025 22:35:38 +0300 Subject: [PATCH] compiler: Fix expression `switch` with non-last `default` According to https://go.dev/ref/spec#Expression_switches: > There can be at most one default case and it may appear anywhere in the "switch" statement. Previously, `default` statements executed even if they are followed by a matching `case`. Signed-off-by: Leonard Lyubich --- pkg/compiler/codegen.go | 8 ++++++++ pkg/compiler/switch_test.go | 40 +++++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/pkg/compiler/codegen.go b/pkg/compiler/codegen.go index 12af57da52..ab3ed94027 100644 --- a/pkg/compiler/codegen.go +++ b/pkg/compiler/codegen.go @@ -878,6 +878,14 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor { c.currentSwitch = label c.pushStackLabel(label, 1) + last := len(n.Body.List) - 1 + for i := range last { + if n.Body.List[i].(*ast.CaseClause).List == nil { // early default + n.Body.List[i], n.Body.List[last] = n.Body.List[last], n.Body.List[i] + break + } + } + startLabels := make([]uint16, len(n.Body.List)) for i := range startLabels { startLabels[i] = c.newLabel() diff --git a/pkg/compiler/switch_test.go b/pkg/compiler/switch_test.go index 21b62785aa..d59849edd1 100644 --- a/pkg/compiler/switch_test.go +++ b/pkg/compiler/switch_test.go @@ -122,6 +122,46 @@ var switchTestCases = []testCase{ `, big.NewInt(1), }, + { + "case after first default", + `func F%d() int { + a := 5 + switch a { + default: return 4 + case 5: return 2 + } + } + `, + big.NewInt(2), + }, + { + "case after intermediate default", + `func F%d() int { + a := 6 + switch a { + case 5: return 2 + default: return 4 + case 6: + } + return 1 + } + `, + big.NewInt(1), + }, + { + "intermediate default", + `func F%d() int { + a := 3 + switch a { + case 5: return 2 + default: return 4 + case 6: + } + return 1 + } + `, + big.NewInt(4), + }, { "expression in case clause", `func F%d() int {