diff --git a/cmd/stringer/golden_test.go b/cmd/stringer/golden_test.go index 46118407124..256eec4e95a 100644 --- a/cmd/stringer/golden_test.go +++ b/cmd/stringer/golden_test.go @@ -38,6 +38,8 @@ var golden = []Golden{ {"prefix", "Type", false, prefix_in, prefix_out}, {"tokens", "", true, tokens_in, tokens_out}, {"overflow8", "", false, overflow8_in, overflow8_out}, + {"ubounds0", "", false, ubounds0_in, ubounds0_out}, + {"ubounds1", "", false, ubounds1_in, ubounds1_out}, } // Each example starts with "type XXX [u]int", with a single space separating them. @@ -988,6 +990,57 @@ func (i Overflow8) String() string { } ` +const ubounds0_in = `type UBounds uint8 +const ( + B0 UBounds = 0 +) +` + +const ubounds0_out = `func _() { + // An "invalid array index" compiler error signifies that the constant values have changed. + // Re-run the stringer command to generate them again. + var x [1]struct{} + _ = x[B0-0] +} + +const _UBounds_name = "B0" + +var _UBounds_index = [...]uint8{0, 2} + +func (i UBounds) String() string { + idx := int(i) - 0 + if idx >= len(_UBounds_index)-1 { + return "UBounds(" + strconv.FormatInt(int64(i), 10) + ")" + } + return _UBounds_name[_UBounds_index[idx]:_UBounds_index[idx+1]] +} +` + +const ubounds1_in = `type UBounds uint8 +const ( + B1 UBounds = 1 +) +` +const ubounds1_out = `func _() { + // An "invalid array index" compiler error signifies that the constant values have changed. + // Re-run the stringer command to generate them again. + var x [1]struct{} + _ = x[B1-1] +} + +const _UBounds_name = "B1" + +var _UBounds_index = [...]uint8{0, 2} + +func (i UBounds) String() string { + idx := int(i) - 1 + if i < 1 || idx >= len(_UBounds_index)-1 { + return "UBounds(" + strconv.FormatInt(int64(i), 10) + ")" + } + return _UBounds_name[_UBounds_index[idx]:_UBounds_index[idx+1]] +} +` + func TestGolden(t *testing.T) { testenv.NeedsTool(t, "go") diff --git a/cmd/stringer/stringer.go b/cmd/stringer/stringer.go index 7ff0ee8d0c8..3e1edeade6c 100644 --- a/cmd/stringer/stringer.go +++ b/cmd/stringer/stringer.go @@ -641,7 +641,12 @@ func (g *Generator) buildOneRun(runs [][]Value, typeName string) { values := runs[0] g.Printf("\n") g.declareIndexAndNameVar(values, typeName) - g.Printf(stringOneRun, typeName, values[0].String()) + + if values[0].signed || values[0].String() != "0" { + g.Printf(stringOneRun, typeName, values[0].String()) + } else { + g.Printf(stringOneRunUnsigned, typeName, values[0].String()) + } } // Arguments to format are: @@ -657,6 +662,22 @@ const stringOneRun = `func (i %[1]s) String() string { } ` +// Arguments to format are: +// +// [1]: type name +// [2]: lowest defined value for type, as a string +// +// This is the unsigned version of [stringOneRun] with the lower bound check +// removed. +const stringOneRunUnsigned = `func (i %[1]s) String() string { + idx := int(i) - %[2]s + if idx >= len(_%[1]s_index)-1 { + return "%[1]s(" + strconv.FormatInt(int64(i), 10) + ")" + } + return _%[1]s_name[_%[1]s_index[idx] : _%[1]s_index[idx+1]] +} +` + // buildMultipleRuns generates the variables and String method for multiple runs of contiguous values. // For this pattern, a single Printf format won't do. func (g *Generator) buildMultipleRuns(runs [][]Value, typeName string) {