Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SA5010: False Positive When Comparing Generic Types Against Concrete Types #1354

Closed
superlinkx opened this issue Jan 20, 2023 · 2 comments
Closed

Comments

@superlinkx
Copy link
Sponsor

superlinkx commented Jan 20, 2023

The following example is a bit contrived in order to be as minimal as possible while showing the exceptional case. What appears to be happening is that this check assumes all type assertions will be against concrete types, which works well in the general case but in this generics case we are getting an unhelpful linter message. This code does correctly run the type assertions, counter to what the linter rule suggests.

  • The output of 'staticcheck -version'
    • staticcheck 2022.1.3 (v0.3.3)
  • The output of 'staticcheck -debug.version' (it is fine if this command fails)
    •    staticcheck 2022.1.3 (v0.3.3)
         
         Compiled with Go version: go1.18.2
         Main module:
                 honnef.co/go/tools@v0.3.3 (sum: h1:oDx7VAwstgpYpb3wv0oxiZlxY+foCpRAwY7Vk6XpAgA=)
         Dependencies:
                 github.com/BurntSushi/toml@v0.4.1 (sum: h1:GaI7EiDXDRfa8VshkTj7Fym7ha+y8/XxIgD2okUIjLw=)
                 golang.org/x/exp/typeparams@v0.0.0-20220218215828-6cf2b201936e (sum: h1:qyrTQ++p1afMkO4DPEeLGq/3oTsdlvdH4vqZUBWzUKM=)
                 golang.org/x/mod@v0.6.0-dev.0.20220419223038-86c51ed26bb4 (sum: h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s=)
                 golang.org/x/sys@v0.0.0-20211019181941-9d821ace8654 (sum: h1:id054HUawV2/6IGm2IV8KZQjqtwAOo2CYlOToYqa0d0=)
                 golang.org/x/tools@v0.1.11-0.20220513221640-090b14e8501f (sum: h1:OKYpQQVE3DKSc3r3zHVzq46vq5YH7x8xpR3/k9ixmUg=)
      
  • The output of 'go version'
    • go version go1.18.2 linux/amd64
  • The output of 'go env'
    •    GO111MODULE=""
         GOARCH="amd64"
         GOBIN=""
         GOCACHE="/home/alyx/.cache/go-build"
         GOENV="/home/alyx/.config/go/env"
         GOEXE=""
         GOEXPERIMENT=""
         GOFLAGS=""
         GOHOSTARCH="amd64"
         GOHOSTOS="linux"
         GOINSECURE=""
         GOMODCACHE="/home/alyx/go/pkg/mod"
         GONOPROXY=""
         GONOSUMDB=""
         GOOS="linux"
         GOPATH="/home/alyx/go"
         GOPRIVATE=""
         GOPROXY="https://proxy.golang.org,direct"
         GOROOT="/usr/local/go"
         GOSUMDB="sum.golang.org"
         GOTMPDIR=""
         GOTOOLDIR="/usr/local/go/pkg/tool/linux_amd64"
         GOVCS=""
         GOVERSION="go1.18.2"
         GCCGO="gccgo"
         GOAMD64="v1"
         AR="ar"
         CC="gcc"
         CXX="g++"
         CGO_ENABLED="1"
         GOMOD="/home/alyx/workspace/monorepo_tests/go.mod"
         GOWORK=""
         CGO_CFLAGS="-g -O2"
         CGO_CPPFLAGS=""
         CGO_CXXFLAGS="-g -O2"
         CGO_FFLAGS="-g -O2"
         CGO_LDFLAGS="-g -O2"
         PKG_CONFIG="pkg-config"
         GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build3620740618=/tmp/go-build -gno-record-gcc-switches"
      
  • Exactly which command you ran
    • staticcheck (within the folder containing the example package below)
  • Output of the command and what's wrong with the output
    •    generic_type_switch.go:23:10: impossible type assertion; ExampleType[uint32] and ExampleType[T] contradict each other:
                 wrong type for SomeMethod method
                         have func() generics_exception.ExampleType[uint32]
                         want func() generics_exception.ExampleType[T] (SA5010)
         generic_type_switch.go:25:10: impossible type assertion; ExampleType[uint64] and ExampleType[T] contradict each other:
                 wrong type for SomeMethod method
                         have func() generics_exception.ExampleType[uint64]
                         want func() generics_exception.ExampleType[T] (SA5010)
      
  • Where we can read the code you're running Staticcheck on
    •    package generics_exception
      
         type ExampleType[T uint32 | uint64] interface {
           SomeMethod() ExampleType[T]
         }
      
         type emptyExampleType[T uint32 | uint64] struct{}
         ​
         func (s emptyExampleType[T]) SomeMethod() ExampleType[T] {
           return nil
         }
      
         var (
           emptyUint32ExampleType ExampleType[uint32] = emptyExampleType[uint32]{}
           emptyUint64ExampleType ExampleType[uint64] = emptyExampleType[uint64]{}
         )
      
         func EmptyExampleType[T uint32 | uint64]() ExampleType[T] {
           var emptyT T
      
           switch any(emptyT).(type) {
           case uint32:
             return emptyUint32ExampleType.(ExampleType[T])
           case uint64:
             return emptyUint64ExampleType.(ExampleType[T])
           }
      
           return nil
         }
@superlinkx superlinkx added false-positive needs-triage Newly filed issue that needs triage labels Jan 20, 2023
@dominikh
Copy link
Owner

Awesome, will fix.

@dominikh dominikh removed the needs-triage Newly filed issue that needs triage label Jan 20, 2023
@dominikh
Copy link
Owner

Simpler, albeit even more contrived, reproducer:

package pkg

type ExampleType[T uint32] interface {
	SomeMethod() ExampleType[T]
}

type emptyExampleType[T uint32] struct{}

func (s emptyExampleType[T]) SomeMethod() ExampleType[T] {
	return nil
}

var emptyUint32ExampleType ExampleType[uint32] = emptyExampleType[uint32]{}

func EmptyExampleType[T uint32]() ExampleType[T] {
	return emptyUint32ExampleType.(ExampleType[T])
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants