go: go/types: add Object.Origin [freeze exception]
I propose to add the following methods to types.Var
and types.Func
:
// Origin returns the canonical object for its receiver, i.e. the object
// recorded in Info.Defs.
//
// For instantiated variables Origin returns the type-parameterized object from
// which the receiver was created. For all other variables Origin returns the
// receiver.
func (obj *Var) Origin() *Var
// Origin returns the canonical object for its receiver, i.e. the object
// recorded in Info.Defs.
//
// For instantiated functions Origin returns the type-parameterized object from
// which the receiver was created. For all other functions, Origin returns
// receiver.
func (obj *Func) Origin() *Func
While instantiating types, we necessarily have to create instantiated copies of their methods/fields/parameters/etc. However, as we work on updating tools for generics, an emerging theme is that is useful to be able to answer the following two questions:
- Is this object canonical?
- What is the canonical object corresponding to this object?
Right now, these are not easy questions to answer. For methods, these can be answered by a lookup on the receiver base origin type. For fields / parameters / etc., it is more difficult and may require finding the relevant *ast.Ident
and looking in Info.Defs
.
Adding an Origin
method to these types answers both of these questions trivially, at the cost of a pointer per object. If the added memory is a concern, there are several internal fields on types.object
used during type-checking that may be externalized to free memory.
About this issue
- Original URL
- State: closed
- Created 2 years ago
- Reactions: 3
- Comments: 20 (19 by maintainers)
This freeze exemption has been approved. Nothing else is required for the exemption request.
CC @golang/release
This issue was filed early in the dev cycle, but due to ongoing discussion and the abbreviated cycle, was not accepted until a few days before the freeze. With other priorities in go/types (particularly the urgent https://go.dev/issue/52715), I didn’t get to the implementation of this feature before the freeze.
I’d like to request a freeze exception to land this proposal for 1.19, as it allows us to redefine a ‘canonical’ invariant that was broken with generics. Certain types of static analysis (such as https://github.com/dominikh/go-tools/issues/1215 or some Google-internal analyses) would be facilitated by these new APIs.
Please let me know if you’d like me to file a new issue for the freeze exception request, or if you need any other information to help make a determination.
Discussed this with @griesemer, and it seems like the arguments for concrete result types are compelling:
On the other hand, we wouldn’t be able to pass around
interface{ Origin() Object }
as @dominikh suggests, but it would of course be easy to write a helperfunc originObject(Object) Object
.By way of analogy, we document that
Type()
of a*Func
is always*Signature
, yet I have seen many places inx/tools
where we use a commaok type assertion and handle the case that theType()
of a*Func
is not a*Signature
. I would guess that returningObject
will lead to similar misuse.