aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--guide.md72
1 files changed, 36 insertions, 36 deletions
diff --git a/guide.md b/guide.md
index e103c7f9c..d5ae2d1e0 100644
--- a/guide.md
+++ b/guide.md
@@ -2,7 +2,7 @@
2 2
3## About the guide 3## About the guide
4 4
5This guide describes the current start of the rust-analyzer as of 2019-01-20 5This guide describes the current state of `rust-analyzer` as of 2019-01-20
6(git tag [guide-2019-01]). Its purpose is to document various problems and 6(git tag [guide-2019-01]). Its purpose is to document various problems and
7architectural solutions related to the problem of building IDE-first compiler 7architectural solutions related to the problem of building IDE-first compiler
8for Rust. 8for Rust.
@@ -11,24 +11,24 @@ for Rust.
11 11
12## The big picture 12## The big picture
13 13
14On the highest possible level, rust analyzer is a stateful component. Client may 14On the highest possible level, rust analyzer is a stateful component. A client may
15apply changes to the analyzer (new contents of `foo.rs` file is "fn main() {}") 15apply changes to the analyzer (new contents of `foo.rs` file is "fn main() {}")
16and it may ask semantic questions about the current state (what is the 16and it may ask semantic questions about the current state (what is the
17definition of the identifier with offset 92 in file `bar.rs`?). Two important 17definition of the identifier with offset 92 in file `bar.rs`?). Two important
18properties hold: 18properties hold:
19 19
20* Analyzer does not do any IO. It starts in an empty state and all input data is 20* Analyzer does not do any I/O. It starts in an empty state and all input data is
21 provided via `apply_change` API. 21 provided via `apply_change` API.
22 22
23* Only queries about the current state are supported. One can, of course, 23* Only queries about the current state are supported. One can, of course,
24 simulate undo and redo by keeping log of changes and inverse-changes. 24 simulate undo and redo by keeping a log of changes and inverse changes respectively.
25 25
26## IDE API 26## IDE API
27 27
28To see this big picture, let's take a look at the [`AnalysisHost`] and 28To see the bigger picture of how the IDE features works, let's take a look at the [`AnalysisHost`] and
29[`Analysis`] pair of types. `AnalysisHost` has three methods: 29[`Analysis`] pair of types. `AnalysisHost` has three methods:
30 30
31* `default` for creating an empty analysis 31* `default()` for creating an empty analysis instance
32* `apply_change(&mut self)` to make changes (this is how you get from an empty 32* `apply_change(&mut self)` to make changes (this is how you get from an empty
33 state to something interesting) 33 state to something interesting)
34* `analysis(&self)` to get an instance of `Analysis` 34* `analysis(&self)` to get an instance of `Analysis`
@@ -42,28 +42,28 @@ stack, we'll talk about it later.
42[`AnalysisHost`]: https://github.com/rust-analyzer/rust-analyzer/blob/guide-2019-01/crates/ra_ide_api/src/lib.rs#L265-L284 42[`AnalysisHost`]: https://github.com/rust-analyzer/rust-analyzer/blob/guide-2019-01/crates/ra_ide_api/src/lib.rs#L265-L284
43[`Analysis`]: https://github.com/rust-analyzer/rust-analyzer/blob/guide-2019-01/crates/ra_ide_api/src/lib.rs#L291-L478 43[`Analysis`]: https://github.com/rust-analyzer/rust-analyzer/blob/guide-2019-01/crates/ra_ide_api/src/lib.rs#L291-L478
44 44
45The reason for `Analysis` and `AnalysisHost` separation is that we want apply 45The reason for this separation of `Analysis` and `AnalysisHost` is that we want to apply
46changes "uniquely", but we might want to fork an `Analysis` and send it to 46changes "uniquely", but we might also want to fork an `Analysis` and send it to
47another thread for background processing. That is, there is only a single 47another thread for background processing. That is, there is only a single
48`AnalysisHost`, but there may be several (equivalent) `Analysis`. 48`AnalysisHost`, but there may be several (equivalent) `Analysis`.
49 49
50Note that all of the `Analysis` API return `Cancelable<T>`. This is required to 50Note that all of the `Analysis` API return `Cancelable<T>`. This is required to
51be responsive in IDE setting. Sometimes a long-running query is being computed 51be responsive in an IDE setting. Sometimes a long-running query is being computed
52and the user types something in the editor and asks for completion. In this 52and the user types something in the editor and asks for completion. In this
53case, we cancel the long-running computation (so it returns `Err(Canceled)`), 53case, we cancel the long-running computation (so it returns `Err(Canceled)`),
54apply the change and execute request for completion. We never use stale data to 54apply the change and execute request for completion. We never use stale data to
55answer requests. Under the cover, `AnalysisHost` "remembers" all outstanding 55answer requests. Under the cover, `AnalysisHost` "remembers" all outstanding
56`Analysis` instances. `AnalysisHost::apply_change` method cancels all 56`Analysis` instances. The `AnalysisHost::apply_change` method cancels all
57`Analysis`es, blocks until of them are `Dropped` and then applies change 57`Analysis`es, blocks until all of them are `Dropped` and then applies changes
58in-place. This is the familiar to rustaceans read-write lock interior 58in-place. This may be familiar to Rustaceans who use read-write locks for interior
59mutability. 59mutability.
60 60
61Next, lets talk about what are inputs to the Analysis, precisely. 61Next, let's talk about what the inputs to the `Analysis` are, precisely.
62 62
63## Inputs 63## Inputs
64 64
65Rust Analyzer never does any IO itself, all inputs get passed explicitly via 65Rust Analyzer never does any I/O itself, all inputs get passed explicitly via
66`AnalysisHost::apply_change` method, which accepts a single argument: 66the `AnalysisHost::apply_change` method, which accepts a single argument, a
67`AnalysisChange`. [`AnalysisChange`] is a builder for a single change 67`AnalysisChange`. [`AnalysisChange`] is a builder for a single change
68"transaction", so it suffices to study its methods to understand all of the 68"transaction", so it suffices to study its methods to understand all of the
69input data. 69input data.
@@ -72,12 +72,12 @@ input data.
72 72
73The `(add|change|remove)_file` methods control the set of the input files, where 73The `(add|change|remove)_file` methods control the set of the input files, where
74each file has an integer id (`FileId`, picked by the client), text (`String`) 74each file has an integer id (`FileId`, picked by the client), text (`String`)
75and a filesystem path. Paths are tricky, they'll be explained in source roots 75and a filesystem path. Paths are tricky; they'll be explained below, in source roots
76section, together with `add_root` method. `add_library` method allows to add a 76section, together with the `add_root` method. The `add_library` method allows us to add a
77group of files which are assumed to rarely change. It's mostly an optimization 77group of files which are assumed to rarely change. It's mostly an optimization
78and does not change fundamental picture. 78and does not change the fundamental picture.
79 79
80`set_crate_graph` method allows to control how the input files are partitioned 80The `set_crate_graph` method allows us to control how the input files are partitioned
81into compilation unites -- crates. It also controls (in theory, not implemented 81into compilation unites -- crates. It also controls (in theory, not implemented
82yet) `cfg` flags. `CrateGraph` is a directed acyclic graph of crates. Each crate 82yet) `cfg` flags. `CrateGraph` is a directed acyclic graph of crates. Each crate
83has a root `FileId`, a set of active `cfg` flags and a set of dependencies. Each 83has a root `FileId`, a set of active `cfg` flags and a set of dependencies. Each
@@ -220,21 +220,21 @@ of type V. Queries come in two basic varieties:
220 220
221* **Functions**: pure functions (no side effects) that transform your inputs 221* **Functions**: pure functions (no side effects) that transform your inputs
222 into other values. The results of queries is memoized to avoid recomputing 222 into other values. The results of queries is memoized to avoid recomputing
223 them a lot. When you make changes to the inputs, we'll figure out (fairlywe 223 them a lot. When you make changes to the inputs, we'll figure out (fairly
224 intelligently) when we can re-use these memoized values and when we have we 224 intelligently) when we can re-use these memoized values and when we have to
225 recompute them. 225 recompute them.
226 226
227 227
228For further discussion, its important to understand one bit of "fairly 228For further discussion, its important to understand one bit of "fairly
229intelligently". Suppose we have to functions, `f1` and `f2`, and one input,we 229intelligently". Suppose we have two functions, `f1` and `f2`, and one input, `z`.
230We call `f1(X)` which in turn calls `f2(Y)` which inspects `i(Z)`. `i(Z)` 230We call `f1(X)` which in turn calls `f2(Y)` which inspects `i(Z)`. `i(Z)`
231returns some value `V1`, `f2` uses that and returns `R1`, `f1` uses that anwe 231returns some value `V1`, `f2` uses that and returns `R1`, `f1` uses that and
232returns `O`. Now, let's change `i` at `Z` to `V2` from `V1` and try to compwe 232returns `O`. Now, let's change `i` at `Z` to `V2` from `V1` and try to compute
233`f1(X)` again. Because `f1(X)` (transitively) depends on `i(Z)`, we can't jwe 233`f1(X)` again. Because `f1(X)` (transitively) depends on `i(Z)`, we can't just
234reuse its value as is. However, if `f2(Y)` is *still* equal to `R1` (despitwe 234reuse its value as is. However, if `f2(Y)` is *still* equal to `R1` (despite
235`i`'s change), we, in fact, *can* reuse `O` as result of `f1(X)`. And that'we 235`i`'s change), we, in fact, *can* reuse `O` as result of `f1(X)`. And that's how
236salsa works: it recomputes results in *reverse* order, starting from inputswe 236salsa works: it recomputes results in *reverse* order, starting from inputs and
237progressing towards outputs, stopping as soon as it sees an intermediate vawe 237progressing towards outputs, stopping as soon as it sees an intermediate value
238that hasn't changed. 238that hasn't changed.
239 239
240## Salsa Input Queries 240## Salsa Input Queries
@@ -312,7 +312,7 @@ of the syntax trees:
312 `Option`s. The tree for `fn foo` will contain a function declaration with 312 `Option`s. The tree for `fn foo` will contain a function declaration with
313 `None` for parameter list and body. 313 `None` for parameter list and body.
314 314
315* Syntax trees do not know the file they are build from, they only know about 315* Syntax trees do not know the file they are built from, they only know about
316 the text. 316 the text.
317 317
318The implementation is based on the generic [rowan] crate on top of which a 318The implementation is based on the generic [rowan] crate on top of which a
@@ -335,10 +335,10 @@ declarations and recursively process child modules. This is handled by the
335 335
336First, rust analyzer builds a module tree for all crates in a source root 336First, rust analyzer builds a module tree for all crates in a source root
337simultaneously. The main reason for this is historical (`module_tree` predates 337simultaneously. The main reason for this is historical (`module_tree` predates
338`CrateGraph`), but this approach also allows to account for files which are not 338`CrateGraph`), but this approach also enables accounting for files which are not
339part of any crate. That is, if you create a file but do not include it as a 339part of any crate. That is, if you create a file but do not include it as a
340submodule anywhere, you still get semantic completion, and you get a warning 340submodule anywhere, you still get semantic completion, and you get a warning
341about free-floating module (the actual warning is not implemented yet). 341about a free-floating module (the actual warning is not implemented yet).
342 342
343The second difference is that `module_tree_query` does not *directly* depend on 343The second difference is that `module_tree_query` does not *directly* depend on
344the "parse" query (which is confusingly called `source_file`). Why would calling 344the "parse" query (which is confusingly called `source_file`). Why would calling
@@ -347,14 +347,14 @@ an insignificant whitespace. Adding whitespace changes the parse tree (because
347it includes whitespace), and that means recomputing the whole module tree. 347it includes whitespace), and that means recomputing the whole module tree.
348 348
349We deal with this problem by introducing an intermediate [`submodules_query`]. 349We deal with this problem by introducing an intermediate [`submodules_query`].
350This query processes the syntax tree an extract a set of declared submodule 350This query processes the syntax tree and extracts a set of declared submodule
351names. Now, changing the whitespace results in `submodules_query` being 351names. Now, changing the whitespace results in `submodules_query` being
352re-executed for a *single* module, but because the result of this query stays 352re-executed for a *single* module, but because the result of this query stays
353the same, we don't have to re-execute [`module_tree_query`]. In fact, we only 353the same, we don't have to re-execute [`module_tree_query`]. In fact, we only
354need to re-execute it when we add/remove new files or when we change mod 354need to re-execute it when we add/remove new files or when we change mod
355declarations. 355declarations.
356 356
357[`submodules_query`]: https://github.com/rust-analyzer/rust-analyzer/blob/guide-2019-01/crates/ra_hir/src/module_tree.rs#L41) 357[`submodules_query`]: https://github.com/rust-analyzer/rust-analyzer/blob/guide-2019-01/crates/ra_hir/src/module_tree.rs#L41
358 358
359We store the resulting modules in a `Vec`-based indexed arena. The indices in 359We store the resulting modules in a `Vec`-based indexed arena. The indices in
360the arena becomes module ids. And this brings us to the next topic: 360the arena becomes module ids. And this brings us to the next topic:
@@ -445,7 +445,7 @@ we modify bodies of the items. After that we [loop] resolving all imports until
445we've reached a fixed point. 445we've reached a fixed point.
446 446
447[lower]: https://github.com/rust-analyzer/rust-analyzer/blob/guide-2019-01/crates/ra_hir/src/nameres/lower.rs#L113-L117 447[lower]: https://github.com/rust-analyzer/rust-analyzer/blob/guide-2019-01/crates/ra_hir/src/nameres/lower.rs#L113-L117
448[loop]: https://github.com/rust-analyzer/rust-analyzer/blob/guide-2019-01/crates/ra_hir/src/nameres/lower.rs#L113-L117 448[loop]: https://github.com/rust-analyzer/rust-analyzer/blob/guide-2019-01/crates/ra_hir/src/nameres.rs#L186-L196
449 449
450And, given all our preparation with ids and position-independent representation, 450And, given all our preparation with ids and position-independent representation,
451it is satisfying to [test] that typing inside function body does not invalidate 451it is satisfying to [test] that typing inside function body does not invalidate
@@ -514,7 +514,7 @@ construct a mapping from `ExprId`s to types.
514[lower ast]: https://github.com/rust-analyzer/rust-analyzer/blob/guide-2019-01/crates/ra_hir/src/expr.rs 514[lower ast]: https://github.com/rust-analyzer/rust-analyzer/blob/guide-2019-01/crates/ra_hir/src/expr.rs
515[positional id]: https://github.com/rust-analyzer/rust-analyzer/blob/guide-2019-01/crates/ra_hir/src/expr.rs#L13-L15 515[positional id]: https://github.com/rust-analyzer/rust-analyzer/blob/guide-2019-01/crates/ra_hir/src/expr.rs#L13-L15
516[a source map]: https://github.com/rust-analyzer/rust-analyzer/blob/guide-2019-01/crates/ra_hir/src/expr.rs#L41-L44 516[a source map]: https://github.com/rust-analyzer/rust-analyzer/blob/guide-2019-01/crates/ra_hir/src/expr.rs#L41-L44
517[type-inference]: https://github.com/rust-analyzer/rust-analyzer/blob/guide-2019-01/crates/ra_hir/src/ty.rs#L1208-L1223 517[type inference]: https://github.com/rust-analyzer/rust-analyzer/blob/guide-2019-01/crates/ra_hir/src/ty.rs#L1208-L1223
518 518
519## Tying it all together: completion 519## Tying it all together: completion
520 520