Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 9 additions & 9 deletions ci/sembr/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,12 +121,10 @@ fn comply(content: &str) -> String {
line.find(|ch: char| !ch.is_whitespace()).unwrap()
};
let mut newly_split_lines = line.split_inclusive(&*REGEX_SPLIT);
let first = newly_split_lines.next().unwrap().trim_end().to_owned();
let mut remaining: Vec<_> = newly_split_lines
.map(|portion| format!("{:indent$}{}", "", portion.trim_end()))
.collect();
let mut new_lines = Vec::new();
new_lines.push(first);
new_lines.push(newly_split_lines.next().unwrap().trim_end().to_owned());
let mut remaining: Vec<_> =
newly_split_lines.map(|portion| format!("{:indent$}{}", "", portion.trim())).collect();
new_lines.append(&mut remaining);
new_content.splice(new_n..=new_n, new_lines.clone());
new_n += new_lines.len() - 1;
Expand Down Expand Up @@ -244,13 +242,14 @@ some code. block
```
sentence with *italics* should not be ignored. truly.
git log main.. compiler
foo. bar. baz
o? whatever
r? @reviewer
r? @reviewer
~? diagnostic
the queries that we do, as well as the **query DAG**. The
trim double space. or many spaces. in this next sentence
";
let expected = "
# some. heading
Expand All @@ -276,9 +275,6 @@ some code. block
sentence with *italics* should not be ignored.
truly.
git log main.. compiler
foo.
bar.
baz
o?
whatever
r? @reviewer
Expand All @@ -287,6 +283,10 @@ r? @reviewer
the queries that we do, as well as the **query DAG**.
The
trim double space.
or many spaces.
in this next sentence
";
assert_eq!(expected, comply(original));
}
Expand Down
12 changes: 6 additions & 6 deletions src/rustdoc-internals/rustdoc-html-test-suite.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
This page is about the test suite named `rustdoc-html` used to test the HTML output of `rustdoc`.
For other rustdoc-specific test suites, see [Rustdoc test suites].

Each test file in this test suite is simply a Rust source file `file.rs` sprinkled with
Each test file in this test suite is simply a Rust source file sprinkled with
so-called *directives* located inside normal Rust code comments.
These come in two flavors: *Compiletest* and *HtmlDocCk*.

Expand Down Expand Up @@ -145,8 +145,8 @@ Checks that the directory given by `PATH` contains exactly `ENTRIES`.
## Compiletest Directives (Brief)

As mentioned in the introduction, you also have access to [compiletest directives].
Most importantly, they allow you to register auxiliary crates and
to pass flags to the `rustdoc` binary under test.
Most importantly,
they allow you to register auxiliary crates and to pass flags to the `rustdoc` binary under test.
It's *strongly recommended* to read that chapter if you don't know anything about them yet.

Here are some details that are relevant to this test suite specifically:
Expand Down Expand Up @@ -177,9 +177,9 @@ the original negative check failing.

**Note**: Please avoid the use of *negated* checks!

**Tip**: If you can't avoid it, please **always** pair it with an analogous positive check in the
immediate vicinity, so people changing "the shape" have a chance to notice and to update the
negated check!
**Tip**: If you can't avoid it,
please **always** pair it with an analogous positive check in the immediate vicinity,
so people changing "the shape" have a chance to notice and to update the negated check!

## Limitations

Expand Down
13 changes: 8 additions & 5 deletions src/tests/directives.md
Original file line number Diff line number Diff line change
Expand Up @@ -274,9 +274,11 @@ For example:
- A test with the `//@ edition: 2015..2021` directive can be run under the 2015 and the 2018 edition,
so the upper bound is exclusive just like in Rust
(note that there's no equivalent to Rust's `..=` where the upper bound is inclusive).
However, CI will only run the test with the lowest edition in the range (which is 2015 in this example).
However,
CI will only run the test with the lowest edition in the range (which is 2015 in this example).
- A test with the `//@ edition: 2018..` directive will run under 2018 edition or greater.
However, CI will only run the test with the lowest edition in the range (which is 2018 in this example).
However,
CI will only run the test with the lowest edition in the range (which is 2018 in this example).

You can also force `./x test` to use a specific edition by passing the `-- --edition=` argument.
However, tests with the `//@ edition` directive will clamp the value passed to the argument.
Expand All @@ -300,10 +302,11 @@ Asked in

#### Test-suite-specific directives

The test suites [`rustdoc-html`][rustdoc-html-tests], [`rustdoc-js`/`rustdoc-js-std`][rustdoc-js-tests]
The test suites [`rustdoc-html`][rustdoc-html-tests],
[`rustdoc-js`/`rustdoc-js-std`][rustdoc-js-tests],
and [`rustdoc-json`][rustdoc-json-tests] each feature an additional set of directives whose basic
syntax resembles the one of compiletest directives but which are ultimately read and checked by
separate tools.
syntax resembles one of the compiletest directives,
but which are ultimately read and checked by separate tools.
For more information, please read their respective chapters as linked above.

[rustdoc-html-tests]: ../rustdoc-internals/rustdoc-html-test-suite.md
Expand Down
173 changes: 84 additions & 89 deletions src/traits/canonicalization.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,52 +4,48 @@
> [Next-gen trait solving Canonicalization chapter](../solve/canonicalization.md).
> It is suggested to reorganize these contents in the future.

Canonicalization is the process of **isolating** an inference value
from its context. It is a key part of implementing
[canonical queries][cq], and you may wish to read the parent chapter
to get more context.
Canonicalization is the process of **isolating** an inference value from its context.
It is a key part of implementing [canonical queries][cq],
and you may wish to read the parent chapter to get more context.

Canonicalization is really based on a very simple concept: every
[inference variable](../type-inference.md#vars) is always in one of
two states: either it is **unbound**, in which case we don't know yet
what type it is, or it is **bound**, in which case we do. So to
isolate some data-structure T that contains types/regions from its
environment, we just walk down and find the unbound variables that
two states: either it is **unbound**, in which case we don't know yet what type it is,
or it is **bound**, in which case we do.
So, to isolate some data-structure T that contains types/regions from its environment,
we just walk down and find the unbound variables that
appear in T; those variables get replaced with "canonical variables",
starting from zero and numbered in a fixed order (left to right, for
the most part, but really it doesn't matter as long as it is
consistent).
starting from zero and numbered in a fixed order (left to right, for the most part,
but really it doesn't matter as long as it is consistent).

[cq]: ./canonical-queries.md

So, for example, if we have the type `X = (?T, ?U)`, where `?T` and
`?U` are distinct, unbound inference variables, then the canonical
form of `X` would be `(?0, ?1)`, where `?0` and `?1` represent these
**canonical placeholders**. Note that the type `Y = (?U, ?T)` also
canonicalizes to `(?0, ?1)`. But the type `Z = (?T, ?T)` would
canonicalize to `(?0, ?0)` (as would `(?U, ?U)`). In other words, the
exact identity of the inference variables is not important – unless
they are repeated.

We use this to improve caching as well as to detect cycles and other
things during trait resolution. Roughly speaking, the idea is that if
two trait queries have the same canonical form, then they will get
the same answer. That answer will be expressed in terms of the
canonical variables (`?0`, `?1`), which we can then map back to the
original variables (`?T`, `?U`).
So, for example, if we have the type `X = (?T, ?U)`, where `?T` and `?U` are distinct
unbound inference variables, then the canonical form of `X` would be `(?0, ?1)`,
where `?0` and `?1` represent these **canonical placeholders**.
Note that the type `Y = (?U, ?T)` also canonicalizes to `(?0, ?1)`.
But the type `Z = (?T, ?T)` would canonicalize to `(?0, ?0)` (as would `(?U, ?U)`).
In other words, the exact identity of the inference variables is not important,
unless they are repeated.

We use this to improve caching as well as to detect cycles and other things during trait resolution.
Roughly speaking, the idea is that if two trait queries have the same canonical form,
then they will get the same answer.
That answer will be expressed in terms of the canonical variables (`?0`,
`?1`), which we can then map back to the original variables (`?T`, `?U`).

## Canonicalizing the query

To see how it works, imagine that we are asking to solve the following
trait query: `?A: Foo<'static, ?B>`, where `?A` and `?B` are unbound.
This query contains two unbound variables, but it also contains the
lifetime `'static`. The trait system generally ignores all lifetimes
and treats them equally, so when canonicalizing, we will *also*
replace any [free lifetime](../appendix/background.md#free-vs-bound) with a
canonical variable (Note that `'static` is actually a _free_ lifetime
variable here. We are not considering it in the typing context of the whole
program but only in the context of this trait reference. Mathematically, we
are not quantifying over the whole program, but only this obligation).
This query contains two unbound variables, but it also contains the lifetime `'static`.
The trait system generally ignores all lifetimes and treats them equally,
so when canonicalizing,
we will *also* replace any [free lifetime](../appendix/background.md#free-vs-bound) with a
canonical variable (Note that `'static` is actually a _free_ lifetime variable here.
We are not considering it in the typing context of the whole program,
but only in the context of this trait reference.
Mathematically, we are not quantifying over the whole program, but only this obligation).
Therefore, we get the following result:

```text
Expand All @@ -62,12 +58,11 @@ Sometimes we write this differently, like so:
for<T,L,T> { ?0: Foo<'?1, ?2> }
```

This `for<>` gives some information about each of the canonical
variables within. In this case, each `T` indicates a type variable,
so `?0` and `?2` are types; the `L` indicates a lifetime variable, so
`?1` is a lifetime. The `canonicalize` method *also* gives back a
`CanonicalVarValues` array OV with the "original values" for each
canonicalized variable:
This `for<>` gives some information about each of the canonical variables within.
In this case, each `T` indicates a type variable,
so `?0` and `?2` are types; the `L` indicates a lifetime variable, so `?1` is a lifetime.
The `canonicalize` method *also* gives back a
`CanonicalVarValues` array OV with the "original values" for each canonicalized variable:

```text
[?A, 'static, ?B]
Expand All @@ -79,8 +74,8 @@ We'll need this vector OV later, when we process the query response.

Once we've constructed the canonical query, we can try to solve it.
To do so, we will wind up creating a fresh inference context and
**instantiating** the canonical query in that context. The idea is that
we create a substitution S from the canonical form containing a fresh
**instantiating** the canonical query in that context.
The idea is that we create a substitution S from the canonical form containing a fresh
inference variable (of suitable kind) for each canonical variable.
So, for our example query:

Expand All @@ -94,22 +89,22 @@ the substitution S might be:
S = [?A, '?B, ?C]
```

We can then replace the bound canonical variables (`?0`, etc) with
these inference variables, yielding the following fully instantiated
query:
We can then replace the bound canonical variables (`?0`, etc) with these inference variables,
yielding the following fully instantiated query:

```text
?A: Foo<'?B, ?C>
```

Remember that substitution S though! We're going to need it later.
Remember that substitution S though!
We're going to need it later.

OK, now that we have a fresh inference context and an instantiated
query, we can go ahead and try to solve it. The trait solver itself is
explained in more detail in [another section](../solve/the-solver.md), but
suffice to say that it will compute a [certainty value][cqqr] (`Proven` or
`Ambiguous`) and have side-effects on the inference variables we've
created. For example, if there were only one impl of `Foo`, like so:
OK, now that we have a fresh inference context and an instantiated query,
we can go ahead and try to solve it.
The trait solver itself is explained in more detail in [another section](../solve/the-solver.md),
but suffice to say that it will compute a [certainty value][cqqr] (`Proven` or
`Ambiguous`) and have side-effects on the inference variables we've created.
For example, if there were only one impl of `Foo`, like so:

[cqqr]: ./canonical-queries.md#query-response

Expand All @@ -119,35 +114,35 @@ where X: 'a
{ ... }
```

then we might wind up with a certainty value of `Proven`, as well as
creating fresh inference variables `'?D` and `?E` (to represent the
then we might wind up with a certainty value of `Proven`,
as well as creating fresh inference variables `'?D` and `?E` (to represent the
parameters on the impl) and unifying as follows:

- `'?B = '?D`
- `?A = Vec<?E>`
- `?C = ?E`

We would also accumulate the region constraint `?E: '?D`, due to the
where clause.
We would also accumulate the region constraint `?E: '?D`, due to the where clause.

In order to create our final query result, we have to "lift" these
values out of the query's inference context and into something that
can be reapplied in our original inference context. We do that by
**re-applying canonicalization**, but to the **query result**.
In order to create our final query result,
we have to "lift" these values out of the query's inference context and into something that
can be reapplied in our original inference context.
We do that by **re-applying canonicalization**, but to the **query result**.

## Canonicalizing the query result

As discussed in [the parent section][cqqr], most trait queries wind up
with a result that brings together a "certainty value" `certainty`, a
result substitution `var_values`, and some region constraints. To
create this, we wind up re-using the substitution S that we created
when first instantiating our query. To refresh your memory, we had a query
result substitution `var_values`, and some region constraints.
To create this,
we wind up re-using the substitution S that we created when first instantiating our query.
To refresh your memory, we had a query:

```text
for<T,L,T> { ?0: Foo<'?1, ?2> }
```

for which we made a substutition S:
We made a substutition S for it:

```text
S = [?A, '?B, ?C]
Expand All @@ -160,10 +155,10 @@ If we "refresh" S with the latest results, we get:
S = [Vec<?E>, '?D, ?E]
```

These are precisely the new values for the three input variables from
our original query. Note though that they include some new variables
(like `?E`). We can make those go away by canonicalizing again! We don't
just canonicalize S, though, we canonicalize the whole query response QR:
These are precisely the new values for the three input variables from our original query.
Note though that they include some new variables (like `?E`).
We can make those go away by canonicalizing again!
We don't just canonicalize S, though, we canonicalize the whole query response QR:

```text
QR = {
Expand All @@ -187,20 +182,20 @@ Canonical(QR) = for<T, L> {
}
```

(One subtle point: when we canonicalize the query **result**, we do not
use any special treatment for free lifetimes. Note that both
references to `'?D`, for example, were converted into the same
canonical variable (`?1`). This is in contrast to the original query,
where we canonicalized every free lifetime into a fresh canonical
variable.)
(One subtle point: when we canonicalize the query **result**,
we do not use any special treatment for free lifetimes.
Note that both references to `'?D`, for example,
were converted into the same canonical variable (`?1`).
This is in contrast to the original query,
where we canonicalized every free lifetime into a fresh canonical variable.)

Now, this result must be reapplied in each context where needed.

## Processing the canonicalized query result

In the previous section we produced a canonical query result. We now have
to apply that result in our original context. If you recall, way back in the
beginning, we were trying to prove this query:
In the previous section, we produced a canonical query result.
We now have to apply that result in our original context.
If you recall, way back in the beginning, we were trying to prove this query:

```text
?A: Foo<'static, ?B>
Expand All @@ -223,11 +218,11 @@ for<T, L> {
}
```

We now want to apply that response to our context. Conceptually, how
we do that is to (a) instantiate each of the canonical variables in
We now want to apply that response to our context.
Conceptually, how we do that is to (a) instantiate each of the canonical variables in
the result with a fresh inference variable, (b) unify the values in
the result with the original values, and then (c) record the region
constraints for later. Doing step (a) would yield a result of
the result with the original values, and then (c) record the region constraints for later.
Doing step (a) would yield this result:

```text
{
Expand All @@ -247,13 +242,13 @@ Step (b) would then unify:
?B with ?C
```

And finally the region constraint of `?C: 'static` would be recorded
for later verification.
And finally, the region constraint of `?C: 'static` would be recorded for later verification.

(What we *actually* do is a mildly optimized variant of that: Rather
than eagerly instantiating all of the canonical values in the result
with variables, we instead walk the vector of values, looking for
cases where the value is just a canonical variable. In our example,
`values[2]` is `?C`, so that means we can deduce that `?C := ?B` and
`'?D := 'static`. This gives us a partial set of values. Anything for
which we do not find a value, we create an inference variable.)
than eagerly instantiating all of the canonical values in the result with variables,
we instead walk the vector of values,
looking for cases where the value is just a canonical variable.
In our example,
`values[2]` is `?C`, so that means we can deduce that `?C := ?B` and `'?D := 'static`.
This gives us a partial set of values.
Anything for which we do not find a value, we create an inference variable.)
Loading
Loading