Skip to content

go/ast: establish File.FileStart <= Node.Pos <= Node.End <= File.FileEnd for all Nodes in a File #73438

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

Open
adonovan opened this issue Apr 18, 2025 · 5 comments
Assignees
Labels
LibraryProposal Issues describing a requested change to the Go standard library or x/ libraries, but not to a tool
Milestone

Comments

@adonovan
Copy link
Member

Background: Some ast.Node types, such as ast.StructType and ast.InterfaceType, compute their End position based on assumptions about where "}" braces appear in well-formed input. However, in a truncated file--a common input to gopls when one is composing a new file--the brace may be missing and the computed End position may be beyond EOF; or it may be zero. Both have been a widespread source of bugs (e.g. 71659).

Proposal: We propose to establish
(a) the invariant that, in all ast.File trees produced by the parser, every Node has a non-zero Pos and End value, and
(b) the inequality File.FileStart <= Node.Pos <= Node.End <= and File.End.

This will likely require the addition of new fields to record token.Pos values (or their absence) in the AST.

@jba @findleyr @griesemer

@findleyr
Copy link
Member

Thank you for filing this issue. It should be a proposal, since it will require adding new fields to the AST.

However, I consider it a bug that End overflows the file. It should be the case that if the parser accepts a struct keyword as a struct type, with no braces, then it must record the absence of those braces.

The alternative would be to use BadExpr for a dangling struct keyword. The only downside I see there is that we could not record valuable information about struct{ Fields... with no closing brace, although given the current poor recovery in the presence of mismatching delimiters, I'm not sure that makes much difference.

My preference would be to:

  1. Add LBrace and RBrace to StructType.
  2. Document the invariant.

Note that InterfaceType should be fine since FieldList records its Opening and Closing position.

@jba jba self-assigned this Apr 18, 2025
@adonovan
Copy link
Member Author

I agree it will need a proposal, but the first step is to investigate what changes are needed to the parser and go/ast. Once that's done, we can turn this into a proposal.

A complete audit is required; StructType is just one of the known problematic cases. It's possible that StructType can be fixed with only a change to the logic in End. For example:

  • struct EOF -> Pos + len("struct")
  • struct { EOF -> s.Fields.Opening + 1

@adonovan adonovan added this to the Go1.25 milestone Apr 18, 2025
@gabyhelp gabyhelp added the LibraryProposal Issues describing a requested change to the Go standard library or x/ libraries, but not to a tool label Apr 18, 2025
@adonovan
Copy link
Member Author

@jba, I am stealing this from you.

@adonovan adonovan assigned adonovan and unassigned jba Apr 25, 2025
@gopherbot
Copy link
Contributor

Change https://go.dev/cl/668238 mentions this issue: go/ast: enforce FileStart <= Node.Pos <= Node.End <= FileEnd

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
LibraryProposal Issues describing a requested change to the Go standard library or x/ libraries, but not to a tool
Projects
None yet
Development

No branches or pull requests

5 participants