You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The design of go/ast and go/types is rather modular, in that go/ast is a purely untyped AST (albeit with semi-working object resolution, which is superseded by go/types). go/types stores all of its information in maps (Defs, Uses and so on). This approach has two drawbacks:
Performance. Using maps for many many thousands of objects is significantly more memory and CPU intensive than storing them directly in fields of AST nodes.
Ease of use. While separating AST and type information makes for an elegant implementation, it doesn't make for very elegant use. One has to constantly jump between two different domains. The lack of methods and fields on AST nodes also makes relations between the two domains much harder to discover. Furthermore, it complicates passing around data in a static analysis framework. Instead of just passing around the AST, we also have to pass around the correct types.Info. Adding to that go/packages decision to have one types.Info per checked package, instead of a single types.Info for the entire program. makes the mapping even more difficult
I have a WIP branch that forks and merges go/ast and go/types. Significant performance improvements have been observed. Additionally, the AST portions of the code could be simplified due to the removal of ast.Scope and ast.Object. Most checks could be transformed rather simply; replacing info.ObjectOf(ident) with ident.Obj() and so on. The only significant change in idioms is that we can no longer iterate over Info.Types and similar, something that unused does. Instead, we now have to walk the AST and extract the data that we need. This, however, isn't really an issue. Overall, it is still more performant than the original code. Furthermore, unused is the only client doing this, and it will soon be rewritten in terms of SSA, making both Info.Types and AST walking unnecessary.
Initially, I had hoped to keep go/ast and go/types as two separate packages, by introducing a third package containing just the relevant definitions that go/ast will depend on. Unfortunately, go/types depends on a lot of internal state in these definitions, which made splitting it into two packages infeasible.
The text was updated successfully, but these errors were encountered:
The design of go/ast and go/types is rather modular, in that go/ast is a purely untyped AST (albeit with semi-working object resolution, which is superseded by go/types). go/types stores all of its information in maps (Defs, Uses and so on). This approach has two drawbacks:
I have a WIP branch that forks and merges go/ast and go/types. Significant performance improvements have been observed. Additionally, the AST portions of the code could be simplified due to the removal of ast.Scope and ast.Object. Most checks could be transformed rather simply; replacing
info.ObjectOf(ident)
withident.Obj()
and so on. The only significant change in idioms is that we can no longer iterate over Info.Types and similar, something thatunused
does. Instead, we now have to walk the AST and extract the data that we need. This, however, isn't really an issue. Overall, it is still more performant than the original code. Furthermore,unused
is the only client doing this, and it will soon be rewritten in terms of SSA, making both Info.Types and AST walking unnecessary.Initially, I had hoped to keep go/ast and go/types as two separate packages, by introducing a third package containing just the relevant definitions that go/ast will depend on. Unfortunately, go/types depends on a lot of internal state in these definitions, which made splitting it into two packages infeasible.
The text was updated successfully, but these errors were encountered: