Skip to content

all: switch fallthrough bug. Variables scoped outside of switch remain unchanged when modified inside a case block. #60334

@dexterp

Description

@dexterp

When a case statement modifies a variable that is scoped outside a switch statement, the next fallthrough + case statement evaluates the variable as unchanged for the line where the next case is set, but is evaluates as changed within the next case code block. See example code in "What did you do?

What version of Go are you using (go version)?

$ go version
go version go1.20.4 darwin/arm64

Does this issue reproduce with the latest release?

Yes, at the time of writing 1.20.4

What operating system and processor architecture are you using (go env)?

go env Output
$ go env
GOOS="darwin"
GOARCH="arm64"

What did you do?

func main() {
	F()
}

func F() error {
	var err error
	switch {
	case true:
		fmt.Println("first case statement should execute")
		err = FuncNoError()
		fallthrough
	case err == nil:
		fmt.Println("second case statement should execute")

		// FUNCTION RETURNS AN ERROR
		err = FuncHasError()
		fallthrough
	case err == nil:
		fmt.Println("third case statement SHOULD NOT execute")
		err = FuncNoError()
		fallthrough
	case err != nil:
		fmt.Printf("type of err: %T\n", err)
		return fmt.Errorf("found an error: %w", err)
	}
	return nil
}

// FuncNoError a function that returns no error
func FuncNoError() error {
	return nil
}

// FuncHasError a function that returns an error
func FuncHasError() error {
	return errors.New("FuncHasError")
}

What did you expect to see?

  • The third case statement case err == nil should evaluate as false skipping the code block.
  • The fourth case statement case err != nil even though err is nil (according to fmt.Printf("%T", err)) the fourth code block is still executed. So err is remains "nil" when evaluated at the same line as the case statement, but evaluates to not nil when in the case code block.

The output from the code above should be

first case statement should execute
second case statement should execute

What did you see instead?

first case statement should execute
second case statement should execute
third case statement SHOULD NOT execute
type of err: <nil>

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions