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, x/tools/gopls: improve the positioning of type checker errors #42290

Closed
findleyr opened this issue Oct 30, 2020 · 6 comments
Closed
Labels
FrozenDueToAge gopls Issues related to the Go language server, gopls. Tools This label describes issues relating to any tools in the x/tools repository.
Milestone

Comments

@findleyr
Copy link
Contributor

This issue tracks work in both go/types and gopls to improve the position information associated with type checker errors.

Errors produced by go/types currently consist (mostly) of an error message and a position in the source. Related errors are grouped by prefixing continuation errors with \t. This works well for command-line applications, but causes problems for gopls when presenting these errors as diagnostics in the editor.

Specifically:

  • The heuristics used by gopls to guess the end position for an error are often incorrect. For example, in var _ = int(1) + int64(1), gopls will put the error under just int(1), even though the problem is that the entire RHS expression has mismatching types.
  • Continuation errors are broken. For example, in the case of an invalid type cycle go/types produces continuation errors of the form \tT2 refers to, which gopls sends to the editor as diagnostics. Absent context, these are nonsensical.
  • go/types uses the convention that each error should be positioned on the first syntactic element in the source where the error is known to exist. This need not be the best location to show to a user. For example in func f() int {}, the error is on the ‘}’, as that is the first token where a ‘missing return’ error is known. But for the user it might be clearer to position this error on the function signature -- the mistake could equally well be an extraneous result parameter.

There are two limitations of types.Error preventing gopls from addressing these problems in a robust way. First, a single position is not sufficient to accurately determine the span of syntax that led to an error. Second, with only a plain-text message gopls cannot reliably identify the error, and therefore cannot implement an optimal UX for each error kind.

After discussing with @griesemer the tentative plan is to

  1. Add an error code field to types.Error, identifying its kind.
  2. Add start and end positions to types.Error, defining its syntactic extent.

We’re still not sure what the correct API is for these, but we’d like to at least start defining error codes internally for 1.16 (CL 264179).

I'm opening this issue to track that work, as well as any progress we make on defining the API.

@gopherbot gopherbot added the gopls Issues related to the Go language server, gopls. label Oct 30, 2020
@gopherbot
Copy link

Change https://golang.org/cl/264179 mentions this issue: go/types: add internal error codes

@findleyr findleyr changed the title go/types,x/tools/gopls: improve error spans for type checker errors go/types,x/tools/gopls: improve the positioning of type checker errors Oct 30, 2020
@stamblerre stamblerre added this to the gopls/unplanned milestone Oct 30, 2020
@stamblerre stamblerre added the Tools This label describes issues relating to any tools in the x/tools repository. label Oct 30, 2020
gopherbot pushed a commit that referenced this issue Oct 30, 2020
Tools using go/types sometimes need to implement special handling for
certain errors produced by the type-checker. They can offer suggested
fixes, expand the error position to surrounding syntax, highlight
related syntax (for example in the case of a declaration cycle), link to
additional documentation, group errors by category, or correlate errors
with signals produced by other static analysis tools.

All these require a notion of error identity. Tools need to be able to
reliably determine the nature of an error without re-implementing type
checking logic or parsing error messages. This CL is a first-pass at
adding such an identifier to types.Error: a (for the moment unexported)
field containing one of many declared errorCode constants.

A wide variety of error code constants are defined, and assigned to type
checker errors according to their 'functional equivalence', meaning that
they should be ideally be stable under refactoring.

With few exceptions, each error code is documented with an example that
produces it. This is enforced by tests.

When error codes are exported they will represent quite a large API
surface. For this reason, as well as the likelihood that error codes
will change at the start, both the code field and the codes themselves
are initially unexported. gopls will read these fields using reflection
during this experimental phase. Others can obviously do the same,
provided they accept the lack of forward compatibility.

For #42290

Change-Id: I15e3c2bffd2046c20297b1857057d421f633098a
Reviewed-on: https://go-review.googlesource.com/c/go/+/264179
Run-TryBot: Robert Findley <rfindley@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Robert Griesemer <gri@golang.org>
Trust: Robert Griesemer <gri@golang.org>
Trust: Robert Findley <rfindley@google.com>
@gopherbot
Copy link

Change https://golang.org/cl/266637 mentions this issue: go/types: reorganize error codes into categories

@findleyr findleyr changed the title go/types,x/tools/gopls: improve the positioning of type checker errors go/types, x/tools/gopls: improve the positioning of type checker errors Oct 30, 2020
gopherbot pushed a commit that referenced this issue Oct 30, 2020
In CL 264179, some reorganization of error codes was deferred in order
to minimize diffs between patch-sets.

This CL reorganizes the error codes as discussed. It is a pure
reordering, with no material changes other than the changing of internal
const values.

For #42290

Change-Id: I0e9b421a92e96b19e53039652f8de898c5255290
Reviewed-on: https://go-review.googlesource.com/c/go/+/266637
Run-TryBot: Robert Findley <rfindley@google.com>
Trust: Robert Findley <rfindley@google.com>
Trust: Robert Griesemer <gri@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Robert Griesemer <gri@golang.org>
@findleyr findleyr self-assigned this Oct 31, 2020
@gopherbot
Copy link

Change https://golang.org/cl/265250 mentions this issue: go/types: add unexported start and end positions to type checker errors

gopherbot pushed a commit that referenced this issue Nov 5, 2020
Tools often need to associate errors not with a single position, but
with a span of source code. For example, gopls currently estimates
diagnostic spans using heuristics to expand the positions reported by
the type checker to surrounding source code. Unfortunately this is often
inaccurate.

This CL lays the groundwork to solve this within go/types by adding a
start and end position to type checker errors. This is an experimental
API, both because we are uncertain of the ideal representation for these
spans and because their initial positioning is naive. In most cases this
CL simply expands errors to the surrounding ast.Node being typechecked,
if available. This might not be the best error span to present to the
user. For these reasons the API is unexported -- gopls can read these
positions using reflection, allowing us to gain experience and improve
them during the next development cycle.

For #42290

Change-Id: I39a04d70ea2bb2134b4d4c937f32b2ddb4456430
Reviewed-on: https://go-review.googlesource.com/c/go/+/265250
Run-TryBot: Robert Findley <rfindley@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Robert Griesemer <gri@golang.org>
Trust: Robert Findley <rfindley@google.com>
Trust: Robert Griesemer <gri@golang.org>
@gopherbot
Copy link

Change https://golang.org/cl/267939 mentions this issue: internal/typesinternal: add a copy of the Go 1.16 go/types error codes

@gopherbot
Copy link

Change https://golang.org/cl/268539 mentions this issue: internal/typesinternal: use Go 1.16 metadata for go/types errors

gopherbot pushed a commit to golang/tools that referenced this issue Nov 10, 2020
This CL adds a copy of the internal error codes added to go/types in
https://golang.org/cl/264179. In a subsequent CL, we will use these to
extract the unexported error code from go/types errors via reflection.

A generated String method is added to provide a human-readable code for
the user.

For golang/go#42290

Change-Id: I280c9b111598426dce4eef38b9979919ed590068
Reviewed-on: https://go-review.googlesource.com/c/tools/+/267939
Trust: Robert Findley <rfindley@google.com>
Run-TryBot: Robert Findley <rfindley@google.com>
gopls-CI: kokoro <noreply+kokoro@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Rebecca Stambler <rstambler@golang.org>
gopherbot pushed a commit to golang/tools that referenced this issue Dec 7, 2020
In Go 1.16 error codes as well as start and end positions are added for
go/types errors. This information is temporarily stored in unexported
fields, until we're more confident in the correctness of both the API
and the underlying data.

Read this information using reflection and, if available, use it to set
the corresponding field in compiler diagnostics. This establishes a
positive feedback loop: in most cases this should improve the gopls
diagnostic, and wherever it doesn't we can make a note and fall back on
the old heuristics for that error code.

For golang/go#42290

Change-Id: I37475189cbd14a0a5bcfde163f599c9a7b957372
Reviewed-on: https://go-review.googlesource.com/c/tools/+/268539
Run-TryBot: Robert Findley <rfindley@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
gopls-CI: kokoro <noreply+kokoro@google.com>
Trust: Robert Findley <rfindley@google.com>
Reviewed-by: Rebecca Stambler <rstambler@golang.org>
marwan-at-work pushed a commit to marwan-at-work/tools that referenced this issue Dec 23, 2020
In Go 1.16 error codes as well as start and end positions are added for
go/types errors. This information is temporarily stored in unexported
fields, until we're more confident in the correctness of both the API
and the underlying data.

Read this information using reflection and, if available, use it to set
the corresponding field in compiler diagnostics. This establishes a
positive feedback loop: in most cases this should improve the gopls
diagnostic, and wherever it doesn't we can make a note and fall back on
the old heuristics for that error code.

For golang/go#42290

Change-Id: I37475189cbd14a0a5bcfde163f599c9a7b957372
Reviewed-on: https://go-review.googlesource.com/c/tools/+/268539
Run-TryBot: Robert Findley <rfindley@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
gopls-CI: kokoro <noreply+kokoro@google.com>
Trust: Robert Findley <rfindley@google.com>
Reviewed-by: Rebecca Stambler <rstambler@golang.org>
@findleyr
Copy link
Contributor Author

I'm going to close this as the main requirement has been met, and follow-on work should be tracked in separate issues: go/types records both error code and span, and gopls reads this information to provide better context for errors.

Two issues are still unresolved:

  • This data is still unexported on types.Error (and read by gopls via reflection). We should export it, but that should be tracked by a separate issue.
  • We still don't have perfect handling for continuation errors (prefixed by '\t'), but @heschi did do some work to improve the situation a bit. types2 uses a different pattern for grouping errors, which could be useful in go/types provided we had a better mechanism for associating errors.

@golang golang locked and limited conversation to collaborators Apr 30, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
FrozenDueToAge gopls Issues related to the Go language server, gopls. Tools This label describes issues relating to any tools in the x/tools repository.
Projects
None yet
Development

No branches or pull requests

3 participants