-
Notifications
You must be signed in to change notification settings - Fork 18.5k
Description
The following go/types APIs all use Pos in semantically significant ways:
Scope.LookupParent(name, pos)
Scope.Contains(pos)
Scope.Innermost(pos)
CheckExpr(fset, pkg, pos, expr, info)
Eval(fset, pkg, pos)
As the doc comment on Innermost says, "The result is guaranteed to be valid only if the type-checked AST has complete position information." This restriction applies equally to all these operations, and should probably be made explicit for all of them.
For example, Scope.LookupParent uses the position of the reference to compute the set of declarations that are in scope. This assumes the position information is accurate, which it is for trees produced by the parser, but not for ones that have been modified by refactoring algorithms or synthesized directly. It should be possible to type-check any syntax tree correctly, even without accurate position information.
In each case, the position is used as a shorthand to indicate the portion of the environment that is accessible at a given point. It would be possible to provide parallel APIs for these 5 functions, without the restriction, that replaces pos with a different parameter that indicates the environment. For example, it could be something like an []ast.Node indicating a path from the root of the tree to the designated node.
Internally, the tree of Scopes could record the environment in a form that is independent of position, similar to my lazy type checker, which mapped each Node to a pair of a Scope and an int that represents the length of the prefix of Scope symbols that are in scope at that point. Ignoring efficiency concerns, I imagine the existing Pos-based functions could become wrappers around a function that resolves a Pos to a []Node (assuming valid pos info), followed by a call to the []Node-based API.
This would open the door to composable refactorings that mutate the tree in a sequence of passes, invalidating position info but still allowing the type checker to be reinvoked after each mutation, before finally formatting the tree to produce the updated output. There are still many open questions about how to build such refactorings: we rely heavily on pos for debugging and error reporting; re-typechecking may require additional packages that were not needed before; and so on. But it is both viable and desirable to make the type checker itself fully independent of syntax positions, so they are used only for error messages, or passed through to Object.Pos, but have no semantics.