parent
bb5cdc19cb
commit
37e0c09f77
83
src/salsa.md
83
src/salsa.md
|
|
@ -4,17 +4,17 @@
|
|||
|
||||
This chapter is based on the explanation given by Niko Matsakis in this
|
||||
[video](https://www.youtube.com/watch?v=_muY4HjSqVw) about
|
||||
[Salsa](https://github.com/salsa-rs/salsa). To find out more you may
|
||||
want to watch [Salsa In More
|
||||
[`Salsa`](https://github.com/salsa-rs/salsa). To find out more you may
|
||||
want to watch [`Salsa` In More
|
||||
Depth](https://www.youtube.com/watch?v=i_IhACacPRY), also by Niko
|
||||
Matsakis.
|
||||
|
||||
> As of <!-- date-check --> November 2022, although Salsa is inspired by
|
||||
> (among other things) rustc's query system, it is not used directly in rustc.
|
||||
> It _is_ used in [chalk], an implementation of Rust's trait system, and extensively in
|
||||
> [`rust-analyzer`], the official implementation of the language server protocol for Rust, but
|
||||
> there are no medium or long-term concrete plans to integrate it into the
|
||||
> compiler.
|
||||
> As of <!-- date-check --> November 2022, although `Salsa` is inspired by (among
|
||||
> other things) `rustc`'s query system, it is not used directly in `rustc`. It
|
||||
> _is_ used in [chalk], an implementation of Rust's trait system, and
|
||||
> extensively in [`rust-analyzer`], the official implementation of the language
|
||||
> server protocol for Rust, but there are no medium or long-term concrete
|
||||
> plans to integrate it into the compiler.
|
||||
|
||||
|
||||
[`rust-analyzer`]: https://rust-analyzer.github.io/
|
||||
|
|
@ -22,19 +22,19 @@ Matsakis.
|
|||
|
||||
## What is Salsa?
|
||||
|
||||
Salsa is a library for incremental recomputation. This means it allows reusing
|
||||
`Salsa` is a library for incremental recomputation. This means it allows reusing
|
||||
computations that were already done in the past to increase the efficiency
|
||||
of future computations.
|
||||
|
||||
The objectives of Salsa are:
|
||||
The objectives of `Salsa` are:
|
||||
* Provide that functionality in an automatic way, so reusing old computations
|
||||
is done automatically by the library
|
||||
is done automatically by the library.
|
||||
* Doing so in a "sound", or "correct", way, therefore leading to the same
|
||||
results as if it had been done from scratch
|
||||
results as if it had been done from scratch.
|
||||
|
||||
Salsa's actual model is much richer, allowing many kinds of inputs and many
|
||||
`Salsa`'s actual model is much richer, allowing many kinds of inputs and many
|
||||
different outputs.
|
||||
For example, integrating Salsa with an IDE could mean that the inputs could be
|
||||
For example, integrating `Salsa` with an IDE could mean that the inputs could be
|
||||
the manifest (`Cargo.toml`), entire source files (`foo.rs`), snippets and so
|
||||
on; the outputs of such an integration could range from a binary executable, to
|
||||
lints, types (for example, if a user selects a certain variable and wishes to
|
||||
|
|
@ -42,10 +42,10 @@ see its type), completions, etc.
|
|||
|
||||
## How does it work?
|
||||
|
||||
The first thing that Salsa has to do is identify the "base inputs" that
|
||||
The first thing that `Salsa` has to do is identify the "base inputs" that
|
||||
are not something computed but given as input.
|
||||
|
||||
Then Salsa has to also identify intermediate, "derived" values, which are
|
||||
Then `Salsa` has to also identify intermediate, "derived" values, which are
|
||||
something that the library produces, but, for each derived value there's a
|
||||
"pure" function that computes the derived value.
|
||||
|
||||
|
|
@ -53,16 +53,16 @@ For example, there might be a function `ast(x: Path) -> AST`. The produced
|
|||
`AST` isn't a final value, it's an intermediate value that the library would
|
||||
use for the computation.
|
||||
|
||||
This means that when you try to compute with the library, Salsa is going to
|
||||
This means that when you try to compute with the library, `Salsa` is going to
|
||||
compute various derived values, and eventually read the input and produce the
|
||||
result for the asked computation.
|
||||
|
||||
In the course of computing, Salsa tracks which inputs were accessed and which
|
||||
In the course of computing, `Salsa` tracks which inputs were accessed and which
|
||||
values are derived. This information is used to determine what's going to
|
||||
happen when the inputs change: are the derived values still valid?
|
||||
|
||||
This doesn't necessarily mean that each computation downstream from the input
|
||||
is going to be checked, which could be costly. Salsa only needs to check each
|
||||
is going to be checked, which could be costly. `Salsa` only needs to check each
|
||||
downstream computation until it finds one that isn't changed. At that point, it
|
||||
won't check other derived computations since they wouldn't need to change.
|
||||
|
||||
|
|
@ -78,7 +78,7 @@ J <- B <--+
|
|||
|
||||
When an input `I` changes, the derived value `A` could change. The derived
|
||||
value `B`, which does not depend on `I`, `A`, or any value derived from `A` or
|
||||
`I`, is not subject to change. Therefore, Salsa can reuse the computation done
|
||||
`I`, is not subject to change. Therefore, `Salsa` can reuse the computation done
|
||||
for `B` in the past, without having to compute it again.
|
||||
|
||||
The computation could also terminate early. Keeping the same graph as before,
|
||||
|
|
@ -88,29 +88,29 @@ computation. This leads to an "early termination", because there's no need to
|
|||
check if `C` needs to change, since both `C` direct inputs, `A` and `B`,
|
||||
haven't changed.
|
||||
|
||||
## Key Salsa concepts
|
||||
## Key `Salsa` concepts
|
||||
|
||||
### Query
|
||||
|
||||
A query is some value that Salsa can access in the course of computation. Each
|
||||
A query is some value that `Salsa` can access in the course of computation. Each
|
||||
query can have a number of keys (from 0 to many), and all queries have a
|
||||
result, akin to functions. 0-key queries are called "input" queries.
|
||||
result, akin to functions. `0-key` queries are called "input" queries.
|
||||
|
||||
### Database
|
||||
|
||||
The database is basically the context for the entire computation, it's meant to
|
||||
store Salsa's internal state, all intermediate values for each query, and
|
||||
anything else that the computation might need. The database must know all the
|
||||
queries that the library is going to do before it can be built, but they don't
|
||||
need to be specified in the same place.
|
||||
store `Salsa`'s internal state, all intermediate values for each query, and
|
||||
anything else that the computation might need. The database must know all the
|
||||
queries the library is going to do before it can be built, but they don't need
|
||||
to be specified in the same place.
|
||||
|
||||
After the database is formed, it can be accessed with queries that are very
|
||||
similar to functions. Since each query's result is stored in the database,
|
||||
when a query is invoked N times, it will return N **cloned** results, without
|
||||
having to recompute the query (unless the input has changed in such a way that
|
||||
it warrants recomputation).
|
||||
similar to functions. Since each query's result is stored in the database, when
|
||||
a query is invoked `N`-times, it will return `N`-**cloned** results, without having
|
||||
to recompute the query (unless the input has changed in such a way that it
|
||||
warrants recomputation).
|
||||
|
||||
For each input query (0-key), a "set" method is generated, allowing the user to
|
||||
For each input query (`0-key`), a "set" method is generated, allowing the user to
|
||||
change the output of such query, and trigger previous memoized values to be
|
||||
potentially invalidated.
|
||||
|
||||
|
|
@ -118,7 +118,7 @@ potentially invalidated.
|
|||
|
||||
A query group is a set of queries which have been defined together as a unit.
|
||||
The database is formed by combining query groups. Query groups are akin to
|
||||
"Salsa modules".
|
||||
"`Salsa` modules".
|
||||
|
||||
A set of queries in a query group are just a set of methods in a trait.
|
||||
|
||||
|
|
@ -132,7 +132,7 @@ Example input query group:
|
|||
|
||||
```rust,ignore
|
||||
/// This attribute will process this tree, produce this tree as output, and produce
|
||||
/// a bunch of intermediate stuff that Salsa also uses. One of these things is a
|
||||
/// a bunch of intermediate stuff that Salsa also uses. One of these things is a
|
||||
/// "StorageStruct", whose name we have specified in the attribute.
|
||||
///
|
||||
/// This query group is a bunch of **input** queries, that do not rely on any
|
||||
|
|
@ -154,9 +154,9 @@ this one depends on by specifying them as supertraits, as seen in the following
|
|||
example:
|
||||
|
||||
```rust,ignore
|
||||
/// This query group is going to contain queries that depend on derived values. A
|
||||
/// query group can access another query group's queries by specifying the
|
||||
/// dependency as a super trait. Query groups can be stacked as much as needed using
|
||||
/// This query group is going to contain queries that depend on derived values.
|
||||
/// A query group can access another query group's queries by specifying the
|
||||
/// dependency as a supertrait. Query groups can be stacked as much as needed using
|
||||
/// that pattern.
|
||||
#[salsa::query_group(ParserStorage)]
|
||||
pub trait Parser: Inputs {
|
||||
|
|
@ -172,10 +172,11 @@ Trait` (or `dyn Trait`), where `Trait` is the query group that the definition
|
|||
belongs to, in addition to the other keys.
|
||||
|
||||
```rust,ignore
|
||||
///This is going to be the definition of the `ast` query in the `Parser` trait.
|
||||
///So, when the query `ast` is invoked, and it needs to be recomputed, Salsa is going to call this function
|
||||
///and it's going to give it the database as `impl Parser`.
|
||||
///The function doesn't need to be aware of all the queries of all the query groups
|
||||
/// This is going to be the definition of the `ast` query in the `Parser` trait.
|
||||
/// So, when the query `ast` is invoked, and it needs to be recomputed, Salsa is
|
||||
/// going to call this function and it's going to give it the database as `impl
|
||||
/// Parser`. The function doesn't need to be aware of all the queries of all the
|
||||
/// query groups
|
||||
fn ast(db: &impl Parser, name: String) -> String {
|
||||
//! Note, `impl Parser` is used here but `dyn Parser` works just as well
|
||||
/* code */
|
||||
|
|
|
|||
Loading…
Reference in New Issue