mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-26 13:03:31 +00:00
guide about recursive macto magic
This commit is contained in:
parent
d832149a1f
commit
c00059c822
1 changed files with 53 additions and 11 deletions
64
guide.md
64
guide.md
|
@ -218,21 +218,21 @@ of type V. Queries come in two basic varieties:
|
|||
|
||||
* **Functions**: pure functions (no side effects) that transform your inputs
|
||||
into other values. The results of queries is memoized to avoid recomputing
|
||||
them a lot. When you make changes to the inputs, we'll figure out (fairly
|
||||
intelligently) when we can re-use these memoized values and when we have to
|
||||
them a lot. When you make changes to the inputs, we'll figure out (fairlywe
|
||||
intelligently) when we can re-use these memoized values and when we have we
|
||||
recompute them.
|
||||
|
||||
|
||||
For further discussion, its important to understand one bit of "fairly
|
||||
intelligently". Suppose we have to functions, `f1` and `f2`, and one input, `i`.
|
||||
intelligently". Suppose we have to functions, `f1` and `f2`, and one input,we
|
||||
We call `f1(X)` which in turn calls `f2(Y)` which inspects `i(Z)`. `i(Z)`
|
||||
returns some value `V1`, `f2` uses that and returns `R1`, `f1` uses that and
|
||||
returns `O`. Now, let's change `i` at `Z` to `V2` from `V1` and try to compute
|
||||
`f1(X)` again. Because `f1(X)` (transitively) depends on `i(Z)`, we can't just
|
||||
reuse its value as is. However, if `f2(Y)` is *still* equal to `R1` (despite the
|
||||
`i`'s change), we, in fact, *can* reuse `O` as result of `f1(X)`. And that's how
|
||||
salsa works: it recomputes results in *reverse* order, starting from inputs and
|
||||
progressing towards outputs, stopping as soon as it sees an intermediate value
|
||||
returns some value `V1`, `f2` uses that and returns `R1`, `f1` uses that anwe
|
||||
returns `O`. Now, let's change `i` at `Z` to `V2` from `V1` and try to compwe
|
||||
`f1(X)` again. Because `f1(X)` (transitively) depends on `i(Z)`, we can't jwe
|
||||
reuse its value as is. However, if `f2(Y)` is *still* equal to `R1` (despitwe
|
||||
`i`'s change), we, in fact, *can* reuse `O` as result of `f1(X)`. And that'we
|
||||
salsa works: it recomputes results in *reverse* order, starting from inputswe
|
||||
progressing towards outputs, stopping as soon as it sees an intermediate vawe
|
||||
that hasn't changed.
|
||||
|
||||
## Salsa Input Queries
|
||||
|
@ -380,10 +380,52 @@ unused locations is an open question.
|
|||
[interners]: https://github.com/rust-analyzer/rust-analyzer/blob/guide-2019-01/crates/ra_hir/src/db.rs#L22-L23
|
||||
|
||||
For example, we use `LocationInterner` to assign ids to defs: functions,
|
||||
structs, enums, etc.
|
||||
structs, enums, etc. The location, [`DefLoc`] contains two bits of information:
|
||||
|
||||
* the id of the module which contains the def,
|
||||
* the id of the specific item in the modules source code.
|
||||
|
||||
We "could" use a text offset for location a particular item, but that would play
|
||||
badly with salsa: offsets change after edits. So, as a rule of thumb, we avoid
|
||||
using offsets, text ranges or syntax trees as keys and values for queries. What
|
||||
we do instead is we store "index" of the item among all of the items of a file
|
||||
(so, a positional based ID, but localized to a single file).
|
||||
|
||||
[`DefLoc`]: https://github.com/rust-analyzer/rust-analyzer/blob/guide-2019-01/crates/ra_hir/src/ids.rs#L127-L139
|
||||
|
||||
One thing we've glossed over for the time being is support for macros. We have
|
||||
only proof of concept handling of macros at the moment, but they are extremely
|
||||
interesting from "assigning ids" perspective.
|
||||
|
||||
## Macros and recursive locations
|
||||
|
||||
The tricky bit about macros is that they effectively create new source files.
|
||||
While we can use `FileId`s to refer to original files, we can't just assign them
|
||||
willy-nilly to the pseudo files of macro expansion. Instead, we use a special
|
||||
ID, [`HirFileId`] to refer to either a usual file or a macro-generated file:
|
||||
|
||||
```rust
|
||||
enum HirFileId {
|
||||
FileId(FileId),
|
||||
Macro(MacroCallId),
|
||||
}
|
||||
```
|
||||
|
||||
`MacroCallId` is an interned ID that specifies a particular macro invocation.
|
||||
Its `MacroCallLoc` contains:
|
||||
|
||||
* `ModuleId` of the containing module
|
||||
* `HirFileId` of the containing file or pseudo file
|
||||
* an index of this particular macro invocation in this file (positional id
|
||||
again).
|
||||
|
||||
Note how `HirFileId` is defined in terms of `MacroCallLoc` which is defined in
|
||||
terms of `HirFileId`! This does not recur infinitely though: any chain of
|
||||
`HirFileId`s bottoms out in `HirFileId::FileId`, that is, some source file
|
||||
actually written by the user.
|
||||
|
||||
[`HirFileId`]: https://github.com/rust-analyzer/rust-analyzer/blob/guide-2019-01/crates/ra_hir/src/ids.rs#L18-L125
|
||||
|
||||
## Name resolution
|
||||
|
||||
## Source Map pattern
|
||||
|
|
Loading…
Reference in a new issue