golang/go

go/types: improve documentation on `*types.Named` identity

Open

#53,914 opened on Jul 16, 2022

View on GitHub
 (4 comments) (0 reactions) (0 assignees)Go (19,008 forks)batch import
DocumentationNeedsFixhelp wanted

Repository metrics

Stars
 (133,883 stars)
PR merge metrics
 (No merged PRs in 30d)

Description

What version of Go are you using (go version)?

Does this issue reproduce with the latest release?

It also reproduces in Go 1.18.3.

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

What did you do?

I am using golang.org/x/tools/go/ssa to build the SSA form for TinyGo. We recently added generics support, which was surprisingly easy because the ssa package does all the hard work of instantiating generic functions. Unfortunately, it resulted in an issue. Previously, we could rely on *types.Named to have pointer identity, meaning, that we could create a map[*types.Named]someOtherType and rely on the fact that every unique named type would have only one entry in the map.

What did you expect to see?

I expected this to remain the same while adding support for generics.

What did you see instead?

It broke. It works most of the time, but in some cases (in particular, methods on generic structs) there can be two *types.Named objects for the same named type.

Here is a reproducer: https://go.dev/play/p/AIZZDnqqm0l?v=gotip

I've tried to look at the documentation and comments inside the package what the intended behavior is, but I see somewhat conflicting information. In any case, it would be very helpful if *types.Named would be unique again.

  1. This comment seems to suggest *types.Named is intended to have pointer identity but doesn't at the moment. https://github.com/golang/go/blob/2aa473cc54128c1498f80263763a2a876308e565/src/go/types/predicates.go#L428-L431
  2. types.Instantiate says that not all types may be uniqued:

    If ctxt is non-nil, it may be used to de-duplicate the instance against previous instances with the same identity. As a special case, generic *Signature origin types are only considered identical if they are pointer equivalent, so that instantiating distinct (but possibly identical) signatures will yield different instances. The use of a shared context does not guarantee that identical instances are deduplicated in all cases.

  3. The comment at the top of src/go/types/named.go says that *types.Named may not be unique: https://github.com/golang/go/blob/2aa473cc54128c1498f80263763a2a876308e565/src/go/types/named.go#L74-L81

From this, it appears to be a design decision to change the uniqueness of *types.Named pointers for generic types. This is a problem for me, as I need a way to create unique IDs per *types.Named instance (types.Identical is not a solution, because you can't use it in a map). I tried typ.Obj().Pkg().Path() + "." + typ.Obj().Name() but that doesn't work for named types inside functions (which create a new scope but may have the same name as a named type in the outer scope).

I'm reporting this as a bug as it feels like a regression to me, even though it's not technically a regression.

Contributor guide