Skip to content

go/types: types.Identical is false for identical types loaded with different golang.org/x/tools/go/packages.Load calls #64477

Closed as not planned
@jmattheis

Description

@jmattheis

Go version

go version go1.21.4 linux/amd64

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

GO111MODULE=''
GOARCH='amd64'
GOBIN=''
GOCACHE='/home/jm/.cache/go-build'
GOENV='/home/jm/.config/go/env'
GOEXE=''
GOEXPERIMENT=''
GOFLAGS=''
GOHOSTARCH='amd64'
GOHOSTOS='linux'
GOINSECURE=''
GOMODCACHE='/home/jm/go/pkg/mod'
GONOPROXY=''
GONOSUMDB=''
GOOS='linux'
GOPATH='/home/jm/go'
GOPRIVATE=''
GOPROXY='https://proxy.golang.org,direct'
GOROOT='/usr/lib/go'
GOSUMDB='sum.golang.org'
GOTMPDIR=''
GOTOOLCHAIN='auto'
GOTOOLDIR='/usr/lib/go/pkg/tool/linux_amd64'
GOVCS=''
GOVERSION='go1.21.4'
GCCGO='gccgo'
GOAMD64='v1'
AR='ar'
CC='gcc'
CXX='g++'
CGO_ENABLED='1'
GOMOD='/home/jm/src/jmattheis/goverter/test/go.mod'
GOWORK=''
CGO_CFLAGS='-O2 -g'
CGO_CPPFLAGS=''
CGO_CXXFLAGS='-O2 -g'
CGO_FFLAGS='-O2 -g'
CGO_LDFLAGS='-O2 -g'
PKG_CONFIG='pkg-config'
GOGCCFLAGS='-fPIC -m64 -pthread -Wl,--no-gc-sections -fmessage-length=0 -ffile-prefix-map=/tmp/go-build961093412=/tmp/go-build -gno-record-gcc-switches'

What did you do?

I'm trying to do types.Type assignable checks with types from different golang.org/x/tools/go/packages.Load calls but they don't work as I'd expect. Here is an example to reproduce:

module jmattheis/issue

go 1.21.4

require golang.org/x/tools v0.16.0

require golang.org/x/mod v0.14.0 // indirect
package main

import (
	"fmt"
	"go/types"

	"golang.org/x/tools/go/packages"
)

type Input struct{ ID string }

func main() {
	one := load("./").Types.Scope().Lookup("Input").(*types.TypeName).Type()
	two := load("./").Types.Scope().Lookup("Input").(*types.TypeName).Type()

	fmt.Println("one =", one.String())
	fmt.Println("two =", two.String())
	fmt.Println("identical =", types.Identical(one, two))
}

func load(pkg string) *packages.Package {
	cfg := &packages.Config{
		Mode: packages.NeedSyntax | packages.NeedCompiledGoFiles | packages.NeedTypes |
			packages.NeedModule | packages.NeedFiles | packages.NeedName | packages.NeedImports,
	}
	pkgs, err := packages.Load(cfg, pkg)
	if err != nil { panic(err) }
	if len(pkgs[0].Errors) != 0 { panic(pkgs[0].Errors) }
	return pkgs[0]
}

My actual use-case is a little more complex with with parsing multiple different packages and then comparing types between them mainly with types.AssignableTo which uses types.Identical.

I could load all all my packages in one golang.org/x/tools/go/packages.Load call, but this would make my application more complex and I think the current behavior of go/types.Identical isn't obvious when using it.

What did you expect to see?

go/types.Identical should return true when supplying the same types. Even if the types are from different packages.Load calls.

What did you see instead?

The string representation is the same but the types aren't identical.

one = jmattheis/issue.Input
two = jmattheis/issue.Input
identical = false

The call to indenticalOrigin(x, y) inside predicates.go returns false.

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