Before, you were generally working with syntax from a single file, so there was no need for fine-grained tweaking of the context.

Now, you can hold several trees simulatenously, which originate from different macros, and kind-a need to pair a tree with ctx...

btw,

It does not actually yield a true global identity, because the same file can be included twice into a module tree of a crate (Note how this makes syntax<->semantics not a bijection, which is painful to deal with).

And that's actually is interesting, because, unlike SyntaxNode<Context>, the context is meaningless. Ie, does this mean that we don't even need an index, and just SyntaxNode<impl Eq>?

Ok, I think I am onto something!

So, this is the proposal:

We add an u32 field, tree_identity, to rowan::SyntaxNode. By default it is assigned to 0, but there's an option to provide your own value when constructing a tree. All nodes within a tree share a tree_identity

Rowan takes this tree_identity into account when implementing Eq & Hash, with the rule that if you parse the three twice from the same string and the same identity, the correspoinding nodes will be equal, and nodes with different identities will always be distinct (this last part is what is not satisfied by rowan today). This gives us essentially "pointer identity", except that it's fine to reparse trees

We add rowan::SyntaxNode::identity_key, which returns an opaque Copy key which you can, eg, store in a hash map without holding the whole tree

In hir, we assign tree identities to macro files and file-root modules. I think this requires the use of salsa interning, but this is an implementation detail. We only need to make sure that id does not change if the module did not change, we won't use lookup_ query at all.

the API to get types of things will be based on trees with identities.

you start with asking for a syntax tree for a particular file. A tree with some identity is returned (this is inheritnly ambigious due to aliasing modules)

in the tree, you find an ast::Expr

you find an ast::FnDef which contains the expression

you ask for hir::Function for this ast::FnDef. This works, roughly, by listing all functions and finding the one which originates from the same tree_identity and position.

we typecheck the function, getting a map from SyntaxNodes to types, whcih includes all macro-expanded files

we look the result up in the map

I remember you saying that green node doesn't have an identity and is easily interned, but red one has through the parent pointer. I guess these properties are preserved with your proposal, aren't they? And if Syntax Node already has an identity, making it global seems reasonable

We don't increase the size of GreenNodes, the size of SyntaxNodes does not matter that much as there are few of them, and otherwise we add roughly one u32 + interning metadata per file/macro

Ok, I am experiemnting with it right now, and I have a problem: I need a thing, which is exactly like SourceBinder and SourceAnalyzer, but different from those, and I need a name for it :laughter_tears:

The funniest thing is that I think we don't need a strong identity for this to work. I need to think through this tomorrow, but it looks like the fact that we store syntax nodes in the cache solves the potential problem when we get two different trees due to LRU.

well, this approach only works if we only obtain syntax nodes through the Semantics thing, right?

Right. I was thinking it could be useful for someone else

well, this approach only works if we only obtain syntax nodes through the Semantics thing, right?

I think this is true for any identity based approach. If all you have is an identity, the only way to get something out of it is to look it up in a hashmap which was created by an entity that returned you this thing with identity