aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2019-01-19 18:44:18 +0000
committerAleksey Kladov <[email protected]>2019-01-21 08:27:01 +0000
commitc00059c8224772778586bdf063c76dcbdd04f011 (patch)
tree14ca5723e2e2d6dd29bfab1ee40257db0fc8fe3d
parentd832149a1f16fe83163455da560bb665a672d4d7 (diff)
guide about recursive macto magic
-rw-r--r--guide.md64
1 files changed, 53 insertions, 11 deletions
diff --git a/guide.md b/guide.md
index de51f7216..babf58488 100644
--- a/guide.md
+++ b/guide.md
@@ -218,21 +218,21 @@ of type V. Queries come in two basic varieties:
218 218
219* **Functions**: pure functions (no side effects) that transform your inputs 219* **Functions**: pure functions (no side effects) that transform your inputs
220 into other values. The results of queries is memoized to avoid recomputing 220 into other values. The results of queries is memoized to avoid recomputing
221 them a lot. When you make changes to the inputs, we'll figure out (fairly 221 them a lot. When you make changes to the inputs, we'll figure out (fairlywe
222 intelligently) when we can re-use these memoized values and when we have to 222 intelligently) when we can re-use these memoized values and when we have we
223 recompute them. 223 recompute them.
224 224
225 225
226For further discussion, its important to understand one bit of "fairly 226For further discussion, its important to understand one bit of "fairly
227intelligently". Suppose we have to functions, `f1` and `f2`, and one input, `i`. 227intelligently". Suppose we have to functions, `f1` and `f2`, and one input,we
228We call `f1(X)` which in turn calls `f2(Y)` which inspects `i(Z)`. `i(Z)` 228We call `f1(X)` which in turn calls `f2(Y)` which inspects `i(Z)`. `i(Z)`
229returns some value `V1`, `f2` uses that and returns `R1`, `f1` uses that and 229returns some value `V1`, `f2` uses that and returns `R1`, `f1` uses that anwe
230returns `O`. Now, let's change `i` at `Z` to `V2` from `V1` and try to compute 230returns `O`. Now, let's change `i` at `Z` to `V2` from `V1` and try to compwe
231`f1(X)` again. Because `f1(X)` (transitively) depends on `i(Z)`, we can't just 231`f1(X)` again. Because `f1(X)` (transitively) depends on `i(Z)`, we can't jwe
232reuse its value as is. However, if `f2(Y)` is *still* equal to `R1` (despite the 232reuse its value as is. However, if `f2(Y)` is *still* equal to `R1` (despitwe
233`i`'s change), we, in fact, *can* reuse `O` as result of `f1(X)`. And that's how 233`i`'s change), we, in fact, *can* reuse `O` as result of `f1(X)`. And that'we
234salsa works: it recomputes results in *reverse* order, starting from inputs and 234salsa works: it recomputes results in *reverse* order, starting from inputswe
235progressing towards outputs, stopping as soon as it sees an intermediate value 235progressing towards outputs, stopping as soon as it sees an intermediate vawe
236that hasn't changed. 236that hasn't changed.
237 237
238## Salsa Input Queries 238## Salsa Input Queries
@@ -380,10 +380,52 @@ unused locations is an open question.
380[interners]: https://github.com/rust-analyzer/rust-analyzer/blob/guide-2019-01/crates/ra_hir/src/db.rs#L22-L23 380[interners]: https://github.com/rust-analyzer/rust-analyzer/blob/guide-2019-01/crates/ra_hir/src/db.rs#L22-L23
381 381
382For example, we use `LocationInterner` to assign ids to defs: functions, 382For example, we use `LocationInterner` to assign ids to defs: functions,
383structs, enums, etc. 383structs, enums, etc. The location, [`DefLoc`] contains two bits of information:
384
385* the id of the module which contains the def,
386* the id of the specific item in the modules source code.
387
388We "could" use a text offset for location a particular item, but that would play
389badly with salsa: offsets change after edits. So, as a rule of thumb, we avoid
390using offsets, text ranges or syntax trees as keys and values for queries. What
391we do instead is we store "index" of the item among all of the items of a file
392(so, a positional based ID, but localized to a single file).
393
394[`DefLoc`]: https://github.com/rust-analyzer/rust-analyzer/blob/guide-2019-01/crates/ra_hir/src/ids.rs#L127-L139
395
396One thing we've glossed over for the time being is support for macros. We have
397only proof of concept handling of macros at the moment, but they are extremely
398interesting from "assigning ids" perspective.
384 399
385## Macros and recursive locations 400## Macros and recursive locations
386 401
402The tricky bit about macros is that they effectively create new source files.
403While we can use `FileId`s to refer to original files, we can't just assign them
404willy-nilly to the pseudo files of macro expansion. Instead, we use a special
405ID, [`HirFileId`] to refer to either a usual file or a macro-generated file:
406
407```rust
408enum HirFileId {
409 FileId(FileId),
410 Macro(MacroCallId),
411}
412```
413
414`MacroCallId` is an interned ID that specifies a particular macro invocation.
415Its `MacroCallLoc` contains:
416
417* `ModuleId` of the containing module
418* `HirFileId` of the containing file or pseudo file
419* an index of this particular macro invocation in this file (positional id
420 again).
421
422Note how `HirFileId` is defined in terms of `MacroCallLoc` which is defined in
423terms of `HirFileId`! This does not recur infinitely though: any chain of
424`HirFileId`s bottoms out in `HirFileId::FileId`, that is, some source file
425actually written by the user.
426
427[`HirFileId`]: https://github.com/rust-analyzer/rust-analyzer/blob/guide-2019-01/crates/ra_hir/src/ids.rs#L18-L125
428
387## Name resolution 429## Name resolution
388 430
389## Source Map pattern 431## Source Map pattern