Update salsa.md

Formatting updates.
This commit is contained in:
Tbkhi 2024-02-25 11:26:26 -04:00 committed by nora
parent bb5cdc19cb
commit 37e0c09f77
1 changed files with 42 additions and 41 deletions

View File

@ -4,17 +4,17 @@
This chapter is based on the explanation given by Niko Matsakis in this This chapter is based on the explanation given by Niko Matsakis in this
[video](https://www.youtube.com/watch?v=_muY4HjSqVw) about [video](https://www.youtube.com/watch?v=_muY4HjSqVw) about
[Salsa](https://github.com/salsa-rs/salsa). To find out more you may [`Salsa`](https://github.com/salsa-rs/salsa). To find out more you may
want to watch [Salsa In More want to watch [`Salsa` In More
Depth](https://www.youtube.com/watch?v=i_IhACacPRY), also by Niko Depth](https://www.youtube.com/watch?v=i_IhACacPRY), also by Niko
Matsakis. Matsakis.
> As of <!-- date-check --> November 2022, although Salsa is inspired by > As of <!-- date-check --> November 2022, although `Salsa` is inspired by (among
> (among other things) rustc's query system, it is not used directly in rustc. > other things) `rustc`'s query system, it is not used directly in `rustc`. It
> It _is_ used in [chalk], an implementation of Rust's trait system, and extensively in > _is_ used in [chalk], an implementation of Rust's trait system, and
> [`rust-analyzer`], the official implementation of the language server protocol for Rust, but > extensively in [`rust-analyzer`], the official implementation of the language
> there are no medium or long-term concrete plans to integrate it into the > server protocol for Rust, but there are no medium or long-term concrete
> compiler. > plans to integrate it into the compiler.
[`rust-analyzer`]: https://rust-analyzer.github.io/ [`rust-analyzer`]: https://rust-analyzer.github.io/
@ -22,19 +22,19 @@ Matsakis.
## What is Salsa? ## 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 computations that were already done in the past to increase the efficiency
of future computations. of future computations.
The objectives of Salsa are: The objectives of `Salsa` are:
* Provide that functionality in an automatic way, so reusing old computations * 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 * 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. 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 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 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 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? ## 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. 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 something that the library produces, but, for each derived value there's a
"pure" function that computes the derived value. "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 `AST` isn't a final value, it's an intermediate value that the library would
use for the computation. 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 compute various derived values, and eventually read the input and produce the
result for the asked computation. 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 values are derived. This information is used to determine what's going to
happen when the inputs change: are the derived values still valid? happen when the inputs change: are the derived values still valid?
This doesn't necessarily mean that each computation downstream from the input 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 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. 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 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 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. for `B` in the past, without having to compute it again.
The computation could also terminate early. Keeping the same graph as before, 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`, check if `C` needs to change, since both `C` direct inputs, `A` and `B`,
haven't changed. haven't changed.
## Key Salsa concepts ## Key `Salsa` concepts
### Query ### 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 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 ### Database
The database is basically the context for the entire computation, it's meant to 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 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 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 queries the library is going to do before it can be built, but they don't need
need to be specified in the same place. to be specified in the same place.
After the database is formed, it can be accessed with queries that are very 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, similar to functions. Since each query's result is stored in the database, when
when a query is invoked N times, it will return N **cloned** results, without a query is invoked `N`-times, it will return `N`-**cloned** results, without having
having to recompute the query (unless the input has changed in such a way that to recompute the query (unless the input has changed in such a way that it
it warrants recomputation). 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 change the output of such query, and trigger previous memoized values to be
potentially invalidated. potentially invalidated.
@ -118,7 +118,7 @@ potentially invalidated.
A query group is a set of queries which have been defined together as a unit. 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 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. A set of queries in a query group are just a set of methods in a trait.
@ -154,8 +154,8 @@ this one depends on by specifying them as supertraits, as seen in the following
example: example:
```rust,ignore ```rust,ignore
/// This query group is going to contain queries that depend on derived values. A /// This query group is going to contain queries that depend on derived values.
/// query group can access another query group's queries by specifying the /// 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 /// dependency as a supertrait. Query groups can be stacked as much as needed using
/// that pattern. /// that pattern.
#[salsa::query_group(ParserStorage)] #[salsa::query_group(ParserStorage)]
@ -173,9 +173,10 @@ belongs to, in addition to the other keys.
```rust,ignore ```rust,ignore
/// This is going to be the definition of the `ast` query in the `Parser` trait. /// 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 /// So, when the query `ast` is invoked, and it needs to be recomputed, Salsa is
///and it's going to give it the database as `impl Parser`. /// going to call this function and it's going to give it the database as `impl
///The function doesn't need to be aware of all the queries of all the query groups /// 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 { fn ast(db: &impl Parser, name: String) -> String {
//! Note, `impl Parser` is used here but `dyn Parser` works just as well //! Note, `impl Parser` is used here but `dyn Parser` works just as well
/* code */ /* code */