Skip to content

cmd/vet: printfunc false negative on struct without String method #17798

Closed
@josharian

Description

@josharian
package main

import "fmt"

type T int

func (T) String() string { return "T" }

type S struct {
	t T
}

func main() {
	var t T
	fmt.Printf("%s\n", t)
	var s S
	fmt.Printf("%s\n", s)
}
$ go tool vet x.go
$ go run x.go 
T
{%!s(main.T=0)}

vet should know that S isn't a fmt.Stringer. The printfunc's "satisfies interface" check needs improvements. Related is #17057.

cc @robpike @valyala

Activity

added
NeedsFixThe path to resolution is known, but the work has not been done.
on Nov 4, 2016
added this to the Go1.9 milestone on Nov 4, 2016
valyala

valyala commented on Nov 4, 2016

@valyala
Contributor

I'll look into this and the #17057 on the weekend.

valyala

valyala commented on Nov 4, 2016

@valyala
Contributor

FYI, it looks like the cl 28959 breaks printf check on errror interfaces:

err := errors.New("foobar")
fmt.Printf("%d", err) // vet silently skips this
valyala

valyala commented on Nov 4, 2016

@valyala
Contributor

I think it would be better to fix these issues in go 1.8.

josharian

josharian commented on Nov 4, 2016

@josharian
ContributorAuthor

CL 28959 doesn't change cmd/vet at all. It only changes cmd/vet/all, which is a script that runs cmd/vet over the standard library.

I think it would be better to fix these issues in go 1.8.

If the changes are fairly safe and we can get them in soon, I think that's fine.

josharian

josharian commented on Nov 4, 2016

@josharian
ContributorAuthor

FYI, it looks like the cl 28959 breaks printf check on errror interfaces:

Btw, this is intentional. See #16314.

valyala

valyala commented on Jun 2, 2017

@valyala
Contributor

This looks like a bug in package fmt - it must properly print all the struct fields if they implement fmt.Stringer according to the rule:

For compound operands such as slices and structs, the format applies to the elements of each operand, recursively, not to the operand as a whole.

In this case struct S contains only a single field of type T, which implements Stringer. So fmt.Printf must print contents of the struct - {T} instead of printing {%!s(main.T=0)}.

fmt.Printf works as expected for slices, arrays and maps with fmt.Stringer values, but doesn't work for structs:

type S [5]T
type S []T
type S map[string]T
valyala

valyala commented on Jun 2, 2017

@valyala
Contributor
martisch

martisch commented on Jun 2, 2017

@martisch
Contributor
type S struct {
	t T
}

the field t is not exported. If t is changed to be exported fmt will print {T}. fmt is in another package and does not have access to call the String method of t if it is not exported.

see also #18281 #17409 #16698

gopherbot

gopherbot commented on Jun 5, 2017

@gopherbot
Contributor

CL https://golang.org/cl/44831 mentions this issue.

modified the milestones: Go1.10, Go1.9 on Jun 16, 2017
mvdan

mvdan commented on Jun 16, 2017

@mvdan
Member

CL was marked as R=go1.10, so moving the issue milestone too.

gopherbot

gopherbot commented on Jan 29, 2018

@gopherbot
Contributor

Change https://golang.org/cl/90516 mentions this issue: cmd/vet: unexported interface fields on %s are ok

locked and limited conversation to collaborators on Jan 29, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    FrozenDueToAgeNeedsFixThe path to resolution is known, but the work has not been done.

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @josharian@martisch@valyala@mvdan@gopherbot

        Issue actions

          cmd/vet: printfunc false negative on struct without String method · Issue #17798 · golang/go