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

go/types: maintain "owner" information for interface methods and struct fields #8178

Closed
adonovan opened this issue Jun 10, 2014 · 12 comments
Closed
Assignees
Labels
NeedsDecision Feedback is required from experts, contributors, and/or the community before a change can be made.
Milestone

Comments

@adonovan
Copy link
Member

Hi Robert,

in our indexer for Go, when we load (from export data) a package that defines types such
as the following:

    type T struct { X int }
    type U T
    type S U

there is nothing in the go/types API that allows the client to determine that although
the *types.Var for X is a member of S, T and U, it was originally declared beneath T. 
(Underlying() returns the same struct type for S, T and U.)

An analogous situation holds for interface methods:

   type Closer interface { func Close() error }
   type WriterCloser interface { Writer; Closer }

i.e. there is no record of the fact that the Close() method was originally declared
beneath Closer, not WriterCloser.

The indexer needs this information because it must invent a globally unique stable name
for T.X that relates its definition in this package to its uses in other packages. 
Right now, it picks---consistently but arbitrarily---the lexicographically least name
from the set {S.X, T.X, U.X}, i.e. S.X.  So long as all invocations of go/types use
export data that includes S, then all will use the same least name S.X.  However, if the
package was loaded from partial export data that does not include the least name, the
result is a dangling link.

What the indexer needs is that go/types expose some information about the field X that
allows us to come up with a stable name for it each time we encounter it across
different invocations of the type checker.  Associating X with its "true"
owner (T.X) is the most logical approach and will doubtless have benefits for other
applications, but any stable name could work (e.g. the least name, or some fingerprint).

So: how should we do this?
@griesemer
Copy link
Contributor

Comment 1:

Labels changed: added release-none, repo-tools.

Status changed to Thinking.

@rsc rsc added this to the Unplanned milestone Apr 10, 2015
@rsc rsc removed the release-none label Apr 10, 2015
@rsc rsc changed the title go/types: maintain "owner" information for interface methods and struct fields x/tools/go/types: maintain "owner" information for interface methods and struct fields Apr 14, 2015
@rsc rsc modified the milestones: Unreleased, Unplanned Apr 14, 2015
@rsc rsc removed the repo-tools label Apr 14, 2015
@griesemer griesemer changed the title x/tools/go/types: maintain "owner" information for interface methods and struct fields go/types: maintain "owner" information for interface methods and struct fields Jul 31, 2015
@griesemer griesemer added NeedsDecision Feedback is required from experts, contributors, and/or the community before a change can be made. and removed Thinking labels Dec 20, 2017
@griesemer
Copy link
Contributor

@adonovan Is this still of interest? If so, please comment on this issue and mark for 1.11, "early in cycle" and I'll try to address it. Thanks.

@stapelberg
Copy link
Contributor

I just ran into this limitation, too, when working on a tool to surface “// Deprecated: ” comments. (See Google-internal cl/478490109 for more context.)

My code works by iterating through info.Uses, constructing a stable name, and then matching said name against an index of known-deprecated symbols (which is produced by using ast.Inspect).

Currently, I can’t surface deprecation warnings for struct fields (only for the struct type itself, or methods on it) because of this limitation.

@griesemer Would you still be interested in looking into this? Timing-wise, the 1.21 cycle should start soon, so perhaps this is an opportune moment. Thank you!

@griesemer
Copy link
Contributor

@stapelberg Marking for 1.21 so it's on the radar as we may look into some changes in this space. But exposing the information would be an API change which would require a (if small) proposal.

@griesemer griesemer modified the milestones: Unreleased, Go1.21 Jan 17, 2023
@griesemer griesemer self-assigned this Jan 17, 2023
@stapelberg
Copy link
Contributor

Thank you! Let me know if there’s anything I can help with, happy to try out a pending change or similar :)

@griesemer
Copy link
Contributor

@adonovan @findleyr for feedback in whether this is something we need to prioritize ("early in cycle"). Moving to 1.22 for now.

@griesemer griesemer modified the milestones: Go1.21, Go1.22 May 25, 2023
@adonovan
Copy link
Member Author

I have learned to live with this design, so don't keep this open on my account.

@stapelberg
Copy link
Contributor

We’re still interested in this!

(Though, now that I read Alan’s comment, maybe I should try again to find a workaround for our use-case. I’ll try that as time permits.)

@adonovan
Copy link
Member Author

FWIW, now that the export and import of type information preserves precise positions, you could use the position of the field to resolve the ambiguity: the named struct type whose position most closely precedes the field position is its "owner".

@griesemer griesemer modified the milestones: Go1.22, Backlog May 30, 2023
@griesemer
Copy link
Contributor

Just to be clear, we could easily maintain an owner link but at least for go/types this would require an API change if it needs to be accessible externally. That would require a proposal. For now put on Backlog. Feel free to "reactivate" (and send out a proposal) if this continues to be important. Also, feel free to close if no need.

@stapelberg
Copy link
Contributor

We managed to work around this issue as well: we now look at the AST, and when we find a KeyValueExpr, we go back up the stack to the containing CompositeLit to extract its type.

I’ll close this issue, but please report back in case anyone has a use-case where this limitation cannot be worked around.

@ghost
Copy link

ghost commented Jun 26, 2023

I ran into this as well, and ended up using a go/ast based solution, specifically because of this limitation. I think it would be a useful addition to go/types, or at a minimum it would be helpful if go/types documented it as a non-feature.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
NeedsDecision Feedback is required from experts, contributors, and/or the community before a change can be made.
Projects
None yet
Development

No branches or pull requests

4 participants