Skip to content

Commit 4072608

Browse files
mvdanianlancetaylor
authored andcommitted
cmd/vet: %s is valid for an array of stringer
vet was quiet for []stringer, but not for [N]stringer. The source of the problem was how the recursive call used .Elem().Underlying() for arrays, but .Elem() for slices. In the first case, the named type is dropped, thus losing all information of attached methods. Be consistent across slices and arrays, by dropping the Underlying call that is causing trouble. Add regression tests too, including cases where the element type does not implement fmt.Stringer. Fixes #23552. Change-Id: I0fde07d101f112d5768be0a79207ef0b3dc45f2e Reviewed-on: https://go-review.googlesource.com/90455 Run-TryBot: Daniel Martí <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Ian Lance Taylor <[email protected]> Reviewed-by: Rob Pike <[email protected]>
1 parent 1f85917 commit 4072608

File tree

2 files changed

+24
-13
lines changed

2 files changed

+24
-13
lines changed

src/cmd/vet/testdata/print.go

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -130,8 +130,8 @@ func PrintfTests() {
130130
fmt.Printf("%U", x) // ERROR "Printf format %U has arg x of wrong type float64"
131131
fmt.Printf("%x", nil) // ERROR "Printf format %x has arg nil of wrong type untyped nil"
132132
fmt.Printf("%X", 2.3) // ERROR "Printf format %X has arg 2.3 of wrong type float64"
133-
fmt.Printf("%s", stringerv) // ERROR "Printf format %s has arg stringerv of wrong type testdata.stringer"
134-
fmt.Printf("%t", stringerv) // ERROR "Printf format %t has arg stringerv of wrong type testdata.stringer"
133+
fmt.Printf("%s", stringerv) // ERROR "Printf format %s has arg stringerv of wrong type testdata.ptrStringer"
134+
fmt.Printf("%t", stringerv) // ERROR "Printf format %t has arg stringerv of wrong type testdata.ptrStringer"
135135
fmt.Printf("%s", embeddedStringerv) // ERROR "Printf format %s has arg embeddedStringerv of wrong type testdata.embeddedStringer"
136136
fmt.Printf("%t", embeddedStringerv) // ERROR "Printf format %t has arg embeddedStringerv of wrong type testdata.embeddedStringer"
137137
fmt.Printf("%q", notstringerv) // ERROR "Printf format %q has arg notstringerv of wrong type testdata.notstringer"
@@ -168,7 +168,7 @@ func PrintfTests() {
168168
Printf(format, "hi", "there")
169169
Printf(format, "hi") // ERROR "Printf format %s reads arg #2, but call has only 1 arg$"
170170
Printf("%s %d %.3v %q", "str", 4) // ERROR "Printf format %.3v reads arg #3, but call has only 2 args"
171-
f := new(stringer)
171+
f := new(ptrStringer)
172172
f.Warn(0, "%s", "hello", 3) // ERROR "Warn call has possible formatting directive %s"
173173
f.Warnf(0, "%s", "hello", 3) // ERROR "Warnf call needs 1 arg but has 2 args"
174174
f.Warnf(0, "%r", "hello") // ERROR "Warnf format %r has unknown verb r"
@@ -352,25 +352,29 @@ func multi() []interface{} {
352352
panic("don't call - testing only")
353353
}
354354

355-
type stringer float64
355+
type stringer int
356356

357-
var stringerv stringer
357+
func (stringer) String() string { return "string" }
358358

359-
func (*stringer) String() string {
359+
type ptrStringer float64
360+
361+
var stringerv ptrStringer
362+
363+
func (*ptrStringer) String() string {
360364
return "string"
361365
}
362366

363-
func (*stringer) Warn(int, ...interface{}) string {
367+
func (*ptrStringer) Warn(int, ...interface{}) string {
364368
return "warn"
365369
}
366370

367-
func (*stringer) Warnf(int, string, ...interface{}) string {
371+
func (*ptrStringer) Warnf(int, string, ...interface{}) string {
368372
return "warnf"
369373
}
370374

371375
type embeddedStringer struct {
372376
foo string
373-
stringer
377+
ptrStringer
374378
bar int
375379
}
376380

@@ -479,13 +483,13 @@ type RecursiveStruct2 struct {
479483

480484
var recursiveStruct1V = &RecursiveStruct1{}
481485

482-
// Issue 17798: unexported stringer cannot be formatted.
486+
// Issue 17798: unexported ptrStringer cannot be formatted.
483487
type unexportedStringer struct {
484-
t stringer
488+
t ptrStringer
485489
}
486490
type unexportedStringerOtherFields struct {
487491
s string
488-
t stringer
492+
t ptrStringer
489493
S string
490494
}
491495

@@ -533,6 +537,13 @@ func UnexportedStringerOrError() {
533537
fmt.Println("foo\n") // ERROR "Println arg list ends with redundant newline"
534538
fmt.Println("foo\\n") // not an error
535539
fmt.Println(`foo\n`) // not an error
540+
541+
intSlice := []int{3, 4}
542+
fmt.Printf("%s", intSlice) // ERROR "Printf format %s has arg intSlice of wrong type \[\]int"
543+
nonStringerArray := [1]unexportedStringer{{}}
544+
fmt.Printf("%s", nonStringerArray) // ERROR "Printf format %s has arg nonStringerArray of wrong type \[1\]testdata.unexportedStringer"
545+
fmt.Printf("%s", []stringer{3, 4}) // not an error
546+
fmt.Printf("%s", [2]stringer{3, 4}) // not an error
536547
}
537548

538549
// TODO: Disable complaint about '0' for Go 1.10. To be fixed properly in 1.11.

src/cmd/vet/types.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ func (f *File) matchArgTypeInternal(t printfArgType, typ types.Type, arg ast.Exp
172172
return true // %s matches []byte
173173
}
174174
// Recur: []int matches %d.
175-
return t&argPointer != 0 || f.matchArgTypeInternal(t, typ.Elem().Underlying(), arg, inProgress)
175+
return t&argPointer != 0 || f.matchArgTypeInternal(t, typ.Elem(), arg, inProgress)
176176

177177
case *types.Slice:
178178
// Same as array.

0 commit comments

Comments
 (0)