From 4de8818152864e612946faca0478f5f572c529ad Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Wed, 30 Sep 2026 11:22:33 +0200 Subject: [PATCH 01/26] sembr src/const-generics.md --- src/const-generics.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/const-generics.md b/src/const-generics.md index 349e9de9da..d327ad150f 100644 --- a/src/const-generics.md +++ b/src/const-generics.md @@ -27,7 +27,8 @@ struct Foo; type Alias = [u8; 1 + 1]; ``` -In this example we have a const argument of `1 + 1` (the array length) which is represented as an *anon const*. The desugaring would look something like: +In this example we have a const argument of `1 + 1` (the array length) which is represented as an *anon const*. +The desugaring would look something like: ```rust struct Foo; From 89d4f88180a0460c0015fd806914dc18baa3427c Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Wed, 30 Sep 2026 11:24:22 +0200 Subject: [PATCH 02/26] manual sembr --- src/const-generics.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/const-generics.md b/src/const-generics.md index d327ad150f..a5c7ec506b 100644 --- a/src/const-generics.md +++ b/src/const-generics.md @@ -82,9 +82,11 @@ type Alias = [u8; ANON]; When we go through HIR ty lowering for the array type in `Alias`, we will lower the array length too, and feed `type_of(ANON) -> usize`. This will effectively set the type of the `ANON` const item during some later part of the compiler rather than when constructing the HIR. -After all of this desugaring has taken place the final representation in the type system (ie as a `ty::Const`) is a `ConstKind::Alias` with the `DefId` of the `AnonConst`. This is equivalent to how we would representa a usage of an actual const item if we were to represent them without going through an anon const (e.g. when `gca_min_const_items` is enabled). +After all of this desugaring has taken place the final representation in the type system (ie as a `ty::Const`) is a `ConstKind::Alias` with the `DefId` of the `AnonConst`. +This is equivalent to how we would representa a usage of an actual const item if we were to represent them without going through an anon const (e.g. when `gca_generic_const_args` is enabled). -This allows the representation for const "aliases" to be the same as the representation of `TyKind::Alias`. Having a proper HIR body also allows for a *lot* of code re-use, e.g. we can reuse HIR typechecking and all of the lowering steps to MIR where we can then reuse const eval. +This allows the representation for const "aliases" to be the same as the representation of `TyKind::Alias`. +Having a proper HIR body also allows for a *lot* of code re-use, e.g. we can reuse HIR typechecking and all of the lowering steps to MIR where we can then reuse const eval. ### Enforcing lack of generic parameters From 4c54522fc0a217651b5a16c32eae19372ba37366 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Wed, 30 Sep 2026 11:28:21 +0200 Subject: [PATCH 03/26] sometimes shortens lines, for looks --- ci/sembr/src/main.rs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/ci/sembr/src/main.rs b/ci/sembr/src/main.rs index 359deab6f6..052036bb87 100644 --- a/ci/sembr/src/main.rs +++ b/ci/sembr/src/main.rs @@ -50,12 +50,12 @@ fn main() -> Result<()> { let old = fs::read_to_string(&path)?; let mut new = comply(&old); if cli.reflow_harder { - new = lengthen_lines(&new, cli.line_length_limit) + new = reformat_lines(&new, cli.line_length_limit) } if new == old { compliant.push(path.clone()); } else if cli.overwrite { - fs::write(&path, lengthen_lines(&new, cli.line_length_limit))?; + fs::write(&path, reformat_lines(&new, cli.line_length_limit))?; made_compliant.push(path.clone()); } else { not_compliant.push(path.clone()); @@ -133,7 +133,8 @@ fn comply(content: &str) -> String { new_content.join("\n") + "\n" } -fn lengthen_lines(content: &str, limit: usize) -> String { +// This reformats lines, so that changes of "fn comply" look more pretty +fn reformat_lines(content: &str, limit: usize) -> String { let content: Vec<_> = content.lines().map(std::borrow::ToOwned::to_owned).collect(); let mut new_content = content.clone(); let mut new_n = 0; @@ -277,7 +278,7 @@ r? @reviewer } #[test] -fn test_lengthen_lines() { +fn test_reformat_lines() { let original = "\ do not split short sentences @@ -342,7 +343,7 @@ html comment closing [a target]: https://example.com [another target]: https://example.com "; - assert_eq!(expected, lengthen_lines(original, 50)); + assert_eq!(expected, reformat_lines(original, 50)); } #[test] @@ -368,7 +369,7 @@ which could themselves be either base or derived. Each derived value has a dependency, on other values, which could themselves be either base or derived. "; - assert_eq!(expected, lengthen_lines(original, 100)) + assert_eq!(expected, reformat_lines(original, 100)) } #[test] @@ -387,7 +388,7 @@ encountering a cycle doesn't mean that we would get an infinite proof tree. Because of canonicalization of regions and inference variables, encountering a cycle doesn't mean that we would get an infinite proof tree. "; - assert_eq!(expected, lengthen_lines(original, 100)) + assert_eq!(expected, reformat_lines(original, 100)) } #[test] From 1138eeb8d883b4b5d21effc5a3002d2740c39e4f Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Wed, 30 Sep 2026 11:29:08 +0200 Subject: [PATCH 04/26] reflow src/building/bootstrapping/what-bootstrapping-does.md --- src/building/bootstrapping/what-bootstrapping-does.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/building/bootstrapping/what-bootstrapping-does.md b/src/building/bootstrapping/what-bootstrapping-does.md index 4572d001f1..fda9f29ae3 100644 --- a/src/building/bootstrapping/what-bootstrapping-does.md +++ b/src/building/bootstrapping/what-bootstrapping-does.md @@ -15,8 +15,8 @@ See [bootstrap/README.md][bootstrap-internals] to read about bootstrap internals - Stage 3: the same-result test Compiling `rustc` is done in stages. -Here's a diagram, adapted from Jynn -Nelson's [talk on bootstrapping][rustconf22-talk] at RustConf 2022, +Here's a diagram, +adapted from Jynn Nelson's [talk on bootstrapping][rustconf22-talk] at RustConf 2022, with detailed explanations below. The `A`, `B`, `C`, and `D` show the ordering of the stages of bootstrapping. @@ -300,8 +300,8 @@ but `lib` will never be part of the search path. Since `lib/rustlib/` is part of the search path we have to be careful about which crates are included in it. -In particular, all crates except for the -standard library are built with the flag `-Z force-unstable-if-unmarked`, +In particular, +all crates except for the standard library are built with the flag `-Z force-unstable-if-unmarked`, which means that you have to use `#![feature(rustc_private)]` in order to load it (as opposed to the standard library, which is always available). From 62ac12a9ae8da80a82594b4678dadd34ee25dd90 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Wed, 30 Sep 2026 11:33:11 +0200 Subject: [PATCH 05/26] improve building/bootstrapping/what-bootstrapping-does.md --- .../bootstrapping/what-bootstrapping-does.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/building/bootstrapping/what-bootstrapping-does.md b/src/building/bootstrapping/what-bootstrapping-does.md index fda9f29ae3..4fe42ebffd 100644 --- a/src/building/bootstrapping/what-bootstrapping-does.md +++ b/src/building/bootstrapping/what-bootstrapping-does.md @@ -298,12 +298,12 @@ but `lib` will never be part of the search path. #### `-Z force-unstable-if-unmarked` -Since `lib/rustlib/` is part of the search path we have to be careful about -which crates are included in it. -In particular, -all crates except for the standard library are built with the flag `-Z force-unstable-if-unmarked`, -which means that you have to use `#![feature(rustc_private)]` in order to load it (as -opposed to the standard library, which is always available). +Since `lib/rustlib/` is part of the search path, +we have to be careful about which crates are included in it. +In particular, all crates, except for the standard library, +are built with the flag `-Z force-unstable-if-unmarked`, +meaning that you have to use `#![feature(rustc_private)]` in order to load it +(as opposed to the standard library, which is always available). The `-Z force-unstable-if-unmarked` flag has a variety of purposes to help enforce that the correct crates are marked as `unstable`. From 97688d7d22fed99569a27f27c38c1830a034d36f Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Wed, 30 Sep 2026 12:02:06 +0200 Subject: [PATCH 06/26] make it one big test --- ci/sembr/src/main.rs | 76 +++++++++++++++++--------------------------- 1 file changed, 30 insertions(+), 46 deletions(-) diff --git a/ci/sembr/src/main.rs b/ci/sembr/src/main.rs index 052036bb87..5ee0c3af1b 100644 --- a/ci/sembr/src/main.rs +++ b/ci/sembr/src/main.rs @@ -240,6 +240,8 @@ o? whatever r? @reviewer r? @reviewer ~? diagnostic + +the queries that we do, as well as the **query DAG**. The "; let expected = " # some. heading @@ -273,6 +275,9 @@ whatever r? @reviewer r? @reviewer ~? diagnostic + +the queries that we do, as well as the **query DAG**. +The "; assert_eq!(expected, comply(original)); } @@ -309,6 +314,18 @@ html comment closing handle the indented well +split on comma (filler), of +current line + + split on comma (filler), of + current line + +split on +comma (filler), of next line + + split on + comma (filler), of next line + [a target]: https://example.com [another target]: https://example.com "; @@ -340,10 +357,22 @@ html comment closing handle the indented well +split on comma (filler), +of current line + + split on comma (filler), + of current line + +split on comma (filler), +of next line + + split on comma (filler), + of next line + [a target]: https://example.com [another target]: https://example.com "; - assert_eq!(expected, reformat_lines(original, 50)); + assert_eq!(expected, reformat_lines(original, 30)); } #[test] @@ -352,48 +381,3 @@ fn should_pass() { let original = "if you see `input isn't interesting! verify interesting-ness test`."; assert_eq!(original, comply(original)); } - -#[test] -fn split_on_comma_of_current_line() { - let original = " -Each derived value has a dependency, on other values, which could themselves be either base or -derived. - - Each derived value has a dependency, on other values, which could themselves be either base or - derived. -"; - let expected = " -Each derived value has a dependency, on other values, -which could themselves be either base or derived. - - Each derived value has a dependency, on other values, - which could themselves be either base or derived. -"; - assert_eq!(expected, reformat_lines(original, 100)) -} - -#[test] -fn split_on_comma_of_next_line() { - let original = " -Because of canonicalization of regions and -inference variables, encountering a cycle doesn't mean that we would get an infinite proof tree. - - Because of canonicalization of regions and - inference variables, encountering a cycle doesn't mean that we would get an infinite proof tree. -"; - let expected = " -Because of canonicalization of regions and inference variables, -encountering a cycle doesn't mean that we would get an infinite proof tree. - - Because of canonicalization of regions and inference variables, - encountering a cycle doesn't mean that we would get an infinite proof tree. -"; - assert_eq!(expected, reformat_lines(original, 100)) -} - -#[test] -fn should_split() { - let original = "the queries that we do, as well as the **query DAG**. The"; - let expected = "the queries that we do, as well as the **query DAG**.\nThe\n"; - assert_eq!(expected, comply(original)); -} From 00071b79b0b0230a958971f057f6c6012b08227e Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Wed, 30 Sep 2026 12:02:53 +0200 Subject: [PATCH 07/26] shorten, to match the other fn, "comply" --- ci/sembr/src/main.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ci/sembr/src/main.rs b/ci/sembr/src/main.rs index 5ee0c3af1b..54c716959e 100644 --- a/ci/sembr/src/main.rs +++ b/ci/sembr/src/main.rs @@ -50,12 +50,12 @@ fn main() -> Result<()> { let old = fs::read_to_string(&path)?; let mut new = comply(&old); if cli.reflow_harder { - new = reformat_lines(&new, cli.line_length_limit) + new = reformat(&new, cli.line_length_limit) } if new == old { compliant.push(path.clone()); } else if cli.overwrite { - fs::write(&path, reformat_lines(&new, cli.line_length_limit))?; + fs::write(&path, reformat(&new, cli.line_length_limit))?; made_compliant.push(path.clone()); } else { not_compliant.push(path.clone()); @@ -134,7 +134,7 @@ fn comply(content: &str) -> String { } // This reformats lines, so that changes of "fn comply" look more pretty -fn reformat_lines(content: &str, limit: usize) -> String { +fn reformat(content: &str, limit: usize) -> String { let content: Vec<_> = content.lines().map(std::borrow::ToOwned::to_owned).collect(); let mut new_content = content.clone(); let mut new_n = 0; @@ -372,7 +372,7 @@ of next line [a target]: https://example.com [another target]: https://example.com "; - assert_eq!(expected, reformat_lines(original, 30)); + assert_eq!(expected, reformat(original, 30)); } #[test] From 97eae66d5d1e9ed30764fd518426dbb6b44b6825 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Wed, 30 Sep 2026 18:42:42 +0200 Subject: [PATCH 08/26] sembr src/diagnostics.md --- src/diagnostics.md | 197 ++++++++++++++++++++++----------------------- 1 file changed, 98 insertions(+), 99 deletions(-) diff --git a/src/diagnostics.md b/src/diagnostics.md index 0928f27940..b807c7b381 100644 --- a/src/diagnostics.md +++ b/src/diagnostics.md @@ -41,15 +41,15 @@ LL | more code - Primary and secondary spans underlying the users' code. These spans can optionally contain one or more labels. - Primary spans should have enough text to describe the problem in such a - way that if it were the only thing being displayed (for example, in an - IDE) it would still make sense. - Because it is "spatially aware" (it - points at the code), it can generally be more succinct than the error message. - - If cluttered output can be foreseen in cases when multiple span labels - overlap, it is a good idea to tweak the output appropriately. + way that if it were the only thing being displayed (for example, + in an IDE) it would still make sense. + Because it is "spatially aware" (it points at the code), + it can generally be more succinct than the error message. + - If cluttered output can be foreseen in cases when multiple span labels overlap, + it is a good idea to tweak the output appropriately. For example, the `if/else arms have incompatible types` error uses different - spans depending on whether the arms are all in the same line, if one of - the arms is empty and if none of those cases applies. + spans depending on whether the arms are all in the same line, + if one of the arms is empty and if none of those cases applies. - Sub-diagnostics. Any error can have multiple sub-diagnostics that look similar to the main part of the error. These are used for cases where the @@ -57,15 +57,15 @@ LL | more code If the order of the explanation can be "order free", leveraging secondary labels in the main diagnostic is preferred, as it is typically less verbose. -The text should be matter of fact and avoid capitalization and periods, unless -multiple sentences are _needed_: +The text should be matter of fact and avoid capitalization and periods, +unless multiple sentences are _needed_: ```txt error: the fobrulator needs to be krontrificated ``` -When code or an identifier must appear in a message or label, it should be -surrounded with backticks: +When code or an identifier must appear in a message or label, +it should be surrounded with backticks: ```txt error: the identifier `foo.bar` is invalid @@ -84,12 +84,12 @@ explanation would give more information than the error itself. A lot of the time it's better to put all the information in the emitted error itself. However, sometimes that would make the error verbose or there are too many possible -triggers to include useful information for all cases in the error, in which case -it's a good idea to add an explanation.[^estebank] +triggers to include useful information for all cases in the error, +in which case it's a good idea to add an explanation.[^estebank] As always, if you are not sure, just ask your reviewer! -If you decide to add a new error with an associated error code, please read -[this section][error-codes] for a guide and important details about the process. +If you decide to add a new error with an associated error code, +please read [this section][error-codes] for a guide and important details about the process. [^estebank]: This rule of thumb was suggested by **@estebank** [here][estebank-comment]. @@ -102,23 +102,23 @@ If you decide to add a new error with an associated error code, please read Some messages are emitted via [lints](#lints), where the user can control the level. Most diagnostics are hard-coded such that the user cannot control the level. -Usually it is obvious whether a diagnostic should be "fixed" or a lint, but -there are some grey areas. +Usually it is obvious whether a diagnostic should be "fixed" or a lint, +but there are some grey areas. Here are a few examples: - Borrow checker errors: these are fixed errors. The user cannot adjust the level of these diagnostics to silence the borrow checker. - Dead code: this is a lint. - While the user probably doesn't want dead code in - their crate, making this a hard error would make refactoring and development very painful. + While the user probably doesn't want dead code in their crate, + making this a hard error would make refactoring and development very painful. - [future-incompatible lints]: these are silenceable lints. It was decided that making them fixed errors would cause too much breakage, so warnings are instead emitted, and will eventually be turned into fixed (hard) errors. -Hard-coded warnings (those using methods like `span_warn`) should be avoided -for normal code, preferring to use lints instead. +Hard-coded warnings (those using methods like `span_warn`) should be avoided for normal code, +preferring to use lints instead. Some cases, such as warnings with CLI flags, will require the use of hard-coded warnings. See the `deny` [lint level](#diagnostic-levels) below for guidelines when to @@ -133,11 +133,11 @@ use an error-level lint instead of a fixed error. small – screen (which hasn't been cleaned for a while), cannot be understood by a normal programmer, who just came out of bed after a night partying, it's too complex. -- `Error`, `Warning`, `Note`, and `Help` messages start with a lowercase - letter and do not end with punctuation. +- `Error`, `Warning`, `Note`, + and `Help` messages start with a lowercase letter and do not end with punctuation. - Error messages should be succinct. - Users will see these error messages many - times, and more verbose descriptions can be viewed with the `--explain` flag. + Users will see these error messages many times, + and more verbose descriptions can be viewed with the `--explain` flag. That said, don't make it so terse that it's hard to understand. - The word "illegal" is illegal. Prefer "invalid" or a more specific word instead. @@ -145,8 +145,8 @@ use an error-level lint instead of a fixed error. [`rustc_errors::DiagCtxt`][DiagCtxt]'s `span_*` methods or a diagnostic struct's `#[primary_span]` to easily do this). Also `note` other spans that have contributed to the error if the span isn't too large. -- When emitting a message with span, try to reduce the span to the smallest - amount possible that still signifies the issue +- When emitting a message with span, + try to reduce the span to the smallest amount possible that still signifies the issue - Try not to emit multiple error messages for the same error. This may require detecting duplicates. - When the compiler has too little information for a specific error message, @@ -154,8 +154,8 @@ use an error-level lint instead of a fixed error. allow adding more information. For example, see [`#[rustc_on_unimplemented]`](#rustc_on_unimplemented). Use these annotations when available! -- Keep in mind that Rust's learning curve is rather steep, and that the - compiler messages are an important learning tool. +- Keep in mind that Rust's learning curve is rather steep, + and that the compiler messages are an important learning tool. - When talking about the compiler, call it `the compiler`, not `Rust` or `rustc`. - Use the [Oxford comma](https://en.wikipedia.org/wiki/Serial_comma) when writing lists of items. - When mentioning attributes, use this form whenever possible: "the `inline` attribute". @@ -168,8 +168,8 @@ From [RFC 0344], lint names should be consistent, with the following guidelines: The basic rule is: the lint name should make sense when read as "allow *lint-name*" or "allow *lint-name* items". -For example, "allow `deprecated` items" and "allow `dead_code`" makes sense, while "allow -`unsafe_block`" is ungrammatical (should be plural). +For example, "allow `deprecated` items" and "allow `dead_code`" makes sense, +while "allow `unsafe_block`" is ungrammatical (should be plural). - Lint names should state the bad thing being checked for, e.g. `deprecated`, so that `#[allow(deprecated)]` (items) reads correctly. @@ -180,8 +180,8 @@ For example, "allow `deprecated` items" and "allow `dead_code`" makes sense, whi This keeps lint names short. (Again, think "allow *lint-name* items".) -- If a lint applies to a specific grammatical class, mention that class and - use the plural form: use `unused_variables` rather than `unused_variable`. +- If a lint applies to a specific grammatical class, + mention that class and use the plural form: use `unused_variables` rather than `unused_variable`. This makes `#[allow(unused_variables)]` read correctly. - Lints that catch unnecessary, unused, or useless aspects of code should use @@ -200,12 +200,12 @@ Guidelines for different diagnostic levels: has decided to make a specific `warning` into an error. - `warning`: emitted when the compiler detects something odd about a program. - Care should be taken when adding warnings to avoid warning fatigue, and - avoid false-positives where there really isn't a problem with the code. + Care should be taken when adding warnings to avoid warning fatigue, + and avoid false-positives where there really isn't a problem with the code. Some examples of when it is appropriate to issue a warning: - - A situation where the user *should* take action, such as swap out a - deprecated item, or use a `Result`, but otherwise doesn't prevent compilation. + - A situation where the user *should* take action, such as swap out a deprecated item, + or use a `Result`, but otherwise doesn't prevent compilation. - Unnecessary syntax that can be removed without affecting the semantics of the code. For example, unused code, or unnecessary `unsafe`. - Code that is very likely to be incorrect, dangerous, or confusing, but the @@ -214,13 +214,13 @@ Guidelines for different diagnostic levels: `bindings_with_variant_name` (the user likely did not intend to create a binding in a pattern). - [Future-incompatible lints](#future-incompatible), where something was - accidentally or erroneously accepted in the past, but rejecting would - cause excessive breakage in the ecosystem. + accidentally or erroneously accepted in the past, + but rejecting would cause excessive breakage in the ecosystem. - Stylistic choices. For example, camel or snake case, or the `dyn` trait warning in the 2018 edition. These have a high bar to be added, and should only be used in exceptional circumstances. - Other stylistic choices should - either be allow-by-default lints, or part of other tools like Clippy or rustfmt. + Other stylistic choices should either be allow-by-default lints, + or part of other tools like Clippy or rustfmt. - `help`: emitted following an `error` or `warning` to give additional information to the user about how to solve their problem. @@ -247,8 +247,8 @@ Not to be confused with *lint levels*, whose guidelines are: Some examples: - A future-incompatible or edition-based lint that has graduated from the warning level. - - Something that has an extremely high confidence that is incorrect, but - still want an escape hatch to allow it to pass. + - Something that has an extremely high confidence that is incorrect, + but still want an escape hatch to allow it to pass. - `warn`: Equivalent to the `warning` diagnostic level. See `warning` above for guidelines. @@ -279,8 +279,8 @@ There are three main ways to find where a given error is emitted: constructed behind a relatively deep call-stack. Even then, it is a good way to get your bearings. - Invoking `rustc` with the nightly-only flag `-Z treat-err-as-bug=1` - will treat the first error being emitted as an Internal Compiler Error, which - allows you to get a stack trace at the point the error has been emitted. + will treat the first error being emitted as an Internal Compiler Error, + which allows you to get a stack trace at the point the error has been emitted. Change the `1` to something else if you wish to trigger on a later error. There are limitations with this approach: @@ -299,8 +299,8 @@ order things are happening. [`Span`][span] is the primary data structure in `rustc` used to represent a location in the code being compiled. -`Span`s are attached to most constructs in -HIR and MIR, allowing for more informative error reporting. +`Span`s are attached to most constructs in HIR and MIR, +allowing for more informative error reporting. [span]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_span/struct.Span.html @@ -320,8 +320,8 @@ The [`rustc_errors`][errors] crate defines most of the utilities used for report Diagnostics can be implemented as types which implement the `Diagnostic` trait. This is preferred for new diagnostics as it enforces a separation between diagnostic emitting logic and the main code paths. -For less-complex diagnostics, the `Diagnostic` trait can be derived -- see [Diagnostic -structs][diagnostic-structs]. +For less-complex diagnostics, +the `Diagnostic` trait can be derived -- see [Diagnostic structs][diagnostic-structs]. Within the trait implementation, the APIs described below can be used as normal. [diagnostic-structs]: ./diagnostics/diagnostic-structs.md @@ -337,12 +337,11 @@ warnings, errors, fatal errors, suggestions, etc. In general, there are two classes of such methods: ones that emit an error directly and ones that allow finer control over what to emit. For example, -[`span_err`][spanerr] emits the given error message at the given `Span`, but -[`struct_span_err`][strspanerr] instead returns a [`Diag`][diag]. +[`span_err`][spanerr] emits the given error message at the given `Span`, +but [`struct_span_err`][strspanerr] instead returns a [`Diag`][diag]. Most of these methods will accept strings, but it is recommended that typed -identifiers for translatable diagnostics be used for new diagnostics (see -[Translation]). +identifiers for translatable diagnostics be used for new diagnostics (see [Translation]). [translation]: ./diagnostics/translation.md @@ -385,8 +384,8 @@ example-example-error = oh no! this is an error! ## Suggestions -In addition to telling the user exactly _why_ their code is wrong, it's -oftentimes furthermore possible to tell them how to fix it. +In addition to telling the user exactly _why_ their code is wrong, +it's oftentimes furthermore possible to tell them how to fix it. To this end, [`Diag`][diag] offers a structured suggestions API, which formats code suggestions pleasingly in the terminal, or (when the `--error-format json` flag @@ -398,8 +397,7 @@ Not all suggestions should be applied mechanically; they have a degree of confidence in the suggested code, from high (`Applicability::MachineApplicable`) to low (`Applicability::MaybeIncorrect`). Be conservative when choosing the level. -Use the [`span_suggestion`][span_suggestion] method of `Diag` to -make a suggestion. +Use the [`span_suggestion`][span_suggestion] method of `Diag` to make a suggestion. The last argument provides a hint to tools whether the suggestion is mechanically applicable or not. Suggestions point to one or more spans with corresponding code that will @@ -515,8 +513,8 @@ Some of the passes are: - Example: [`keyword_idents`] checks for identifiers that will become keywords in future editions, but is sensitive to identifiers used in macros. -- Early lint pass: Works on [AST nodes] after [macro expansion] and name - resolution, just before [AST lowering]. +- Early lint pass: Works on [AST nodes] after [macro expansion] and name resolution, + just before [AST lowering]. These lints are for purely syntactical lints. - Example: The [`unused_parens`] lint checks for parenthesized-expressions in situations where they are not needed, like an `if` condition. @@ -534,11 +532,11 @@ Some of the passes are: - Example: The [`arithmetic_overflow`] lint is emitted when it detects a constant value that may overflow. -Most lints work well via the pass systems, and they have a fairly -straightforward interface and easy way to integrate (mostly just implementing +Most lints work well via the pass systems, +and they have a fairly straightforward interface and easy way to integrate (mostly just implementing a specific `check` function). -However, some lints are easier to write when -they live on a specific code path anywhere in the compiler. +However, +some lints are easier to write when they live on a specific code path anywhere in the compiler. For example, the [`unused_mut`] lint is implemented in the borrow checker as it requires some information and state in the borrow checker. @@ -589,8 +587,8 @@ One benefit is that it is close to the dependency root, so it can be much faster [`rustc_lint_defs`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint_defs/index.html Every lint is implemented via a `struct` that implements the `LintPass` `trait` -(you can also implement one of the more specific lint pass traits, either -`EarlyLintPass` or `LateLintPass` depending on when is best for your lint to run). +(you can also implement one of the more specific lint pass traits, +either `EarlyLintPass` or `LateLintPass` depending on when is best for your lint to run). The trait implementation allows you to check certain syntactic constructs as the linter walks the AST. You can then choose to emit lints in a very similar way to compile errors. @@ -711,10 +709,11 @@ In general, future-incompatible code exists for two reasons: * The user has written unsound code that the compiler mistakenly accepted. While it is within Rust's backwards compatibility guarantees to fix the soundness hole (breaking the user's code), the lint is there to warn the user that this will happen -in some upcoming version of rustc *regardless of which edition the code uses*. This is the -meaning that rustc exclusively exposes to users as "future incompatible". +in some upcoming version of rustc *regardless of which edition the code uses*. +This is the meaning that rustc exclusively exposes to users as "future incompatible". * The user has written code that will either no longer compiler *or* will change -meaning in an upcoming *edition*. These are often called "edition lints" and can be +meaning in an upcoming *edition*. +These are often called "edition lints" and can be typically seen in the various "edition compatibility" lint groups (e.g., `rust_2021_compatibility`) that are used to lint against code that will break if the user updates the crate's edition. See [migration lints](guides/editions.md#migration-lints) for more details. @@ -735,8 +734,8 @@ declare_lint! { Notice the `reason` field which describes why the future incompatible change is happening. This will change the diagnostic message the user receives as well as determine which lint groups the lint is added to. -In the example above, the lint is an "edition lint" -(since its "reason" is `EditionError`), signifying to the user that the use of anonymous +In the example above, the lint is an "edition lint" (since its "reason" is `EditionError`), +signifying to the user that the use of anonymous parameters will no longer compile in Rust 2018 and beyond. Inside [LintStore::register_lints][fi-lint-groupings], lints with `future_incompatible` @@ -745,16 +744,16 @@ an edition) or into the `future_incompatibility` lint group. [fi-lint-groupings]: https://github.com/rust-lang/rust/blob/51fd129ac12d5bfeca7d216c47b0e337bf13e0c2/compiler/rustc_lint/src/context.rs#L212-L237 -If you need a combination of options that's not supported by the -`declare_lint!` macro, you can always change the `declare_lint!` macro to support this. +If you need a combination of options that's not supported by the `declare_lint!` macro, +you can always change the `declare_lint!` macro to support this. ### Renaming or removing a lint If it is determined that a lint is either improperly named or no longer needed, -the lint must be registered for renaming or removal, which will trigger a warning if a user tries -to use the old lint name. -To declare a rename/remove, add a line with -[`store.register_renamed`] or [`store.register_removed`] to the code of the +the lint must be registered for renaming or removal, +which will trigger a warning if a user tries to use the old lint name. +To declare a rename/remove, +add a line with [`store.register_renamed`] or [`store.register_removed`] to the code of the [`rustc_lint::register_builtins`] function. ```rust,ignore @@ -785,15 +784,15 @@ add_lint_group!(sess, ``` This defines the `nonstandard_style` group which turns on the listed lints. -A user can turn on these lints with a `#![warn(nonstandard_style)]` attribute in -the source code, or by passing `-W nonstandard-style` on the command line. +A user can turn on these lints with a `#![warn(nonstandard_style)]` attribute in the source code, +or by passing `-W nonstandard-style` on the command line. Some lint groups are created automatically in `LintStore::register_lints`. For instance, any lint declared with `FutureIncompatibleInfo` where the reason is `FutureIncompatibilityReason::FutureReleaseError` (the default when -`@future_incompatible` is used in `declare_lint!`), will be added to -the `future_incompatible` lint group. +`@future_incompatible` is used in `declare_lint!`), +will be added to the `future_incompatible` lint group. Editions also have their own lint groups (e.g., `rust_2021_compatibility`) automatically generated for any lints signaling future-incompatible code that will break in the specified edition. @@ -813,15 +812,15 @@ The linting system automatically takes care of handling buffered lints later. [sessbl]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_session/struct.Session.html#method.buffer_lint [parsebl]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_session/parse/struct.ParseSess.html#method.buffer_lint -Thus, to define a lint that runs early in the compilation, one defines a lint -like normal but invokes the lint with `buffer_lint`. +Thus, to define a lint that runs early in the compilation, +one defines a lint like normal but invokes the lint with `buffer_lint`. #### Linting even earlier in the compiler The parser (`rustc_ast`) is interesting in that it cannot have dependencies on any of the other `rustc*` crates. -In particular, it cannot depend on -`rustc_middle::lint` or `rustc_lint`, where all of the compiler linting infrastructure is defined. +In particular, it cannot depend on `rustc_middle::lint` or `rustc_lint`, +where all of the compiler linting infrastructure is defined. That's troublesome! To solve this, `rustc_ast` defines its own buffered lint type, which `ParseSess::buffer_lint` uses. @@ -841,20 +840,20 @@ $ rustc json_error_demo.rs --error-format json {"message":"For more information about this error, try `rustc --explain E0277`.","code":null,"level":"","spans":[],"children":[],"rendered":"For more information about this error, try `rustc --explain E0277`.\n"} ``` -Note that the output is a series of lines, each of which is a JSON -object, but the series of lines taken together is, unfortunately, not +Note that the output is a series of lines, each of which is a JSON object, +but the series of lines taken together is, unfortunately, not valid JSON, thwarting tools and tricks (such as [piping to `python3 -m json.tool`](https://docs.python.org/3/library/json.html#module-json.tool)) that require such. -(One speculates that this was intentional for LSP -performance purposes, so that each line/object can be sent as it is flushed?) +(One speculates that this was intentional for LSP performance purposes, +so that each line/object can be sent as it is flushed?) Also note the "rendered" field, which contains the "human" output as a string; this was introduced so that UI tests could both make use of -the structured JSON and see the "human" output (well, _sans_ colors) -without having to compile everything twice. +the structured JSON and see the "human" output (well, +_sans_ colors) without having to compile everything twice. -The "human" readable and the json format emitter can be found under -`rustc_errors`, both were moved from the `rustc_ast` crate to the +The "human" readable and the json format emitter can be found under `rustc_errors`, +both were moved from the `rustc_ast` crate to the [rustc_errors crate](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_errors/index.html). The JSON emitter defines [its own `Diagnostic` @@ -937,16 +936,16 @@ If you can, you should use that instead. ### Filtering -To allow more targeted error messages, it is possible to filter the -application of these fields with `on`. +To allow more targeted error messages, +it is possible to filter the application of these fields with `on`. You can filter on the following boolean flags: - `crate_local`: whether the code causing the trait bound to not be fulfilled is part of the user's crate. This is used to avoid suggesting code changes that would require modifying a dependency. - `direct`: whether this is a user-specified rather than derived obligation. - - `from_desugaring`: whether we are in some kind of desugaring, like `?` - or a `try` block for example. + - `from_desugaring`: whether we are in some kind of desugaring, + like `?` or a `try` block for example. This flag can also be matched on, see below. You can match on the following names and values, using `name = "value"`: @@ -955,8 +954,8 @@ You can match on the following names and values, using `name = "value"`: - `from_desugaring`: Match against a particular variant of the `DesugaringKind` enum. The desugaring is identified by its variant name, for example `"QuestionMark"` for `?` desugaring, or `"TryBlock"` for `try` blocks. - - `Self` and any generic arguments of the trait, like `Self = "alloc::string::String"` - or `Rhs="i32"`. + - `Self` and any generic arguments of the trait, + like `Self = "alloc::string::String"` or `Rhs="i32"`. The compiler can provide several values to match on, for example: - the self_ty, pretty printed with and without type arguments resolved. From b54ba6bde5430018a5e46ad87b574984d9d504f2 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Wed, 30 Sep 2026 19:03:37 +0200 Subject: [PATCH 09/26] improve diagnostics.md --- src/diagnostics.md | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/diagnostics.md b/src/diagnostics.md index b807c7b381..661e07af71 100644 --- a/src/diagnostics.md +++ b/src/diagnostics.md @@ -49,7 +49,7 @@ LL | more code it is a good idea to tweak the output appropriately. For example, the `if/else arms have incompatible types` error uses different spans depending on whether the arms are all in the same line, - if one of the arms is empty and if none of those cases applies. + if one of the arms is empty, and if none of those cases applies. - Sub-diagnostics. Any error can have multiple sub-diagnostics that look similar to the main part of the error. These are used for cases where the @@ -588,7 +588,7 @@ One benefit is that it is close to the dependency root, so it can be much faster Every lint is implemented via a `struct` that implements the `LintPass` `trait` (you can also implement one of the more specific lint pass traits, -either `EarlyLintPass` or `LateLintPass` depending on when is best for your lint to run). +either `EarlyLintPass` or `LateLintPass`, depending on when is best for your lint to run). The trait implementation allows you to check certain syntactic constructs as the linter walks the AST. You can then choose to emit lints in a very similar way to compile errors. @@ -698,25 +698,25 @@ declare_lint! { } ``` -### Future-incompatible lints +### future-incompatible lints The use of the term `future-incompatible` within the compiler has a slightly broader meaning than what rustc exposes to users of the compiler. -Inside rustc, future-incompatible lints are for signalling to the user that code they have -written may not compile in the future. +Inside rustc, +future-incompatible lints are for signalling to the user their code may not compile in the future. In general, future-incompatible code exists for two reasons: -* The user has written unsound code that the compiler mistakenly accepted. +* The code is unsound, and the compiler mistakenly accepted it. While it is within Rust's backwards compatibility guarantees to fix the soundness hole -(breaking the user's code), the lint is there to warn the user that this will happen -in some upcoming version of rustc *regardless of which edition the code uses*. -This is the meaning that rustc exclusively exposes to users as "future incompatible". -* The user has written code that will either no longer compiler *or* will change -meaning in an upcoming *edition*. -These are often called "edition lints" and can be -typically seen in the various "edition compatibility" lint groups (e.g., `rust_2021_compatibility`) -that are used to lint against code that will break if the user updates the crate's edition. -See [migration lints](guides/editions.md#migration-lints) for more details. + (breaking the user's code), the lint is there to warn the user that this will happen + in some upcoming version of rustc *regardless of which edition the code uses*. + This is the meaning that rustc exclusively exposes to users as "future incompatible". +* The code will either no longer compile *or* will change + meaning in an upcoming *edition*. + These are often called "edition lints" and can be + typically seen in the various "edition compatibility" lint groups (e.g., `rust_2021_compatibility`) + that are used to lint against code that will break if the user updates the crate's edition. + See [migration lints](guides/editions.md#migration-lints) for more details. A future-incompatible lint should be declared with the `@future_incompatible` additional "field": From 9a0c24f7aa4b0b7ee749b3e58c186dd32ed733e2 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Wed, 30 Sep 2026 19:15:00 +0200 Subject: [PATCH 10/26] sembr src/mir/index.md --- src/mir/index.md | 92 ++++++++++++++++++++++++------------------------ 1 file changed, 46 insertions(+), 46 deletions(-) diff --git a/src/mir/index.md b/src/mir/index.md index b5b5b20500..a4075d1eae 100644 --- a/src/mir/index.md +++ b/src/mir/index.md @@ -7,18 +7,18 @@ It is a radically simplified form of Rust that is used for certain flow-sensitive safety checks – notably the borrow checker! – and also for optimization and code generation. -If you'd like a very high-level introduction to MIR, as well as some -of the compiler concepts that it relies on (such as control-flow +If you'd like a very high-level introduction to MIR, +as well as some of the compiler concepts that it relies on (such as control-flow graphs and desugaring), you may enjoy the [rust-lang blog post that introduced MIR][blog]. [blog]: https://blog.rust-lang.org/2016/04/19/MIR.html ## Introduction to MIR -MIR is defined in the [`compiler/rustc_middle/src/mir/`][mir] module, but much of the code -that manipulates it is found in [`compiler/rustc_mir_build`][mirmanip_build], -[`compiler/rustc_mir_transform`][mirmanip_transform], and -[`compiler/rustc_mir_dataflow`][mirmanip_dataflow]. +MIR is defined in the [`compiler/rustc_middle/src/mir/`][mir] module, +but much of the code that manipulates it is found in [`compiler/rustc_mir_build`][mirmanip_build], +[`compiler/rustc_mir_transform`][mirmanip_transform], +and [`compiler/rustc_mir_dataflow`][mirmanip_dataflow]. [RFC 1211]: https://rust-lang.github.io/rfcs/1211-mir.html @@ -38,22 +38,22 @@ This section introduces the key concepts of MIR, summarized here: - **statements:** actions with one successor - **terminators:** actions with potentially multiple successors; always at the end of a block - (if you're not familiar with the term *basic block*, see the [background chapter][cfg]) -- **Locals:** Memory locations allocated on the stack (conceptually, at - least), such as function arguments, local variables, and temporaries. +- **Locals:** Memory locations allocated on the stack (conceptually, at least), + such as function arguments, local variables, and temporaries. These are identified by an index, written with a leading underscore, like `_1`. There is also a special "local" (`_0`) allocated to store the return value. - **Places:** expressions that identify a location in memory, like `_1` or `_1.f`. - **Rvalues:** expressions that produce a value. The "R" stands for the fact that these are the "right-hand side" of an assignment. - - **Operands:** the arguments to an rvalue, which can either be a - constant (like `22`) or a place (like `_1`). + - **Operands:** the arguments to an rvalue, + which can either be a constant (like `22`) or a place (like `_1`). You can get a feeling for how MIR is constructed by translating simple programs into MIR and reading the pretty printed output. -In fact, the playground makes this easy, since it supplies a MIR button that will -show you the MIR for your program. -Try putting this program into play -(or [clicking on this link][sample-play]), and then clicking the "MIR" button on the top: +In fact, the playground makes this easy, +since it supplies a MIR button that will show you the MIR for your program. +Try putting this program into play (or [clicking on this link][sample-play]), +and then clicking the "MIR" button on the top: [sample-play]: https://play.rust-lang.org/?gist=30074856e62e74e91f06abd19bd72ece&version=stable&edition=2021 @@ -83,8 +83,8 @@ We can use `rustc [filename].rs -Z mir-opt-level=0 --emit mir` to view unoptimiz This requires the nightly toolchain. -**Variable declarations.** If we drill in a bit, we'll see it begins -with a bunch of variable declarations. +**Variable declarations.** If we drill in a bit, +we'll see it begins with a bunch of variable declarations. They look like this: ```mir @@ -101,8 +101,8 @@ like `_0` or `_1`. We also intermingle the user's variables (e.g., `_1`) with temporary values (e.g., `_2` or `_3`). You can tell apart user-defined variables because they have debuginfo associated to them (see below). -**User variable debuginfo.** Below the variable declarations, we find the only -hint that `_1` represents a user variable: +**User variable debuginfo.** Below the variable declarations, +we find the only hint that `_1` represents a user variable: ```mir scope 1 { debug vec => _1; // in scope 1 at src/main.rs:2:9: 2:16 @@ -130,15 +130,15 @@ bb0: { } ``` -A basic block is defined by a series of **statements** and a final -**terminator**. In this case, there is one statement: +A basic block is defined by a series of **statements** and a final **terminator**. + In this case, there is one statement: ```mir StorageLive(_1); ``` -This statement indicates that the variable `_1` is "live", meaning -that it may be used later – this will persist until we encounter a +This statement indicates that the variable `_1` is "live", +meaning that it may be used later – this will persist until we encounter a `StorageDead(_1)` statement, which indicates that the variable `_1` is done being used. These "storage statements" are used by LLVM to allocate stack space. @@ -151,8 +151,8 @@ _1 = const >::new() -> bb2; Terminators are different from statements because they can have more than one successor – that is, control may flow to different places. Function calls like the call to `Vec::new` are always -terminators because of the possibility of unwinding, although in the -case of `Vec::new` we are able to see that indeed unwinding is not +terminators because of the possibility of unwinding, +although in the case of `Vec::new` we are able to see that indeed unwinding is not possible, and hence we list only one successor block, `bb2`. If we look ahead to `bb2`, we will see it looks like this: @@ -165,8 +165,8 @@ bb2: { } ``` -Here there are two statements: another `StorageLive`, introducing the `_3` -temporary, and then an assignment: +Here there are two statements: another `StorageLive`, introducing the `_3` temporary, +and then an assignment: ```mir _3 = &mut _1; @@ -179,8 +179,8 @@ Assignments in general have the form: ``` A place is an expression like `_3`, `_3.f` or `*_3` – it denotes a location in memory. -An **Rvalue** is an expression that creates a -value: in this case, the rvalue is a mutable borrow expression, which looks like `&mut `. +An **Rvalue** is an expression that creates a value: in this case, +the rvalue is a mutable borrow expression, which looks like `&mut `. So we can kind of define a grammar for rvalues like so: ```text @@ -194,21 +194,21 @@ So we can kind of define a grammar for rvalues like so: | move Place ``` -As you can see from this grammar, rvalues cannot be nested – they can -only reference places and constants. +As you can see from this grammar, +rvalues cannot be nested – they can only reference places and constants. Moreover, when you use a place, we indicate whether we are **copying it** (which requires that the place have a type `T` where `T: Copy`) or **moving it** (which works for a place of any type). -So, for example, if we had the expression `x -= a + b + c` in Rust, that would get compiled to two statements and a temporary: +So, for example, if we had the expression `x = a + b + c` in Rust, +that would get compiled to two statements and a temporary: ```mir TMP1 = a + b x = TMP1 + c ``` -([Try it and see][play-abc], though you may want to do release mode to skip -over the overflow checks.) +([Try it and see][play-abc], +though you may want to do release mode to skip over the overflow checks.) [play-abc]: https://play.rust-lang.org/?gist=1751196d63b2a71f8208119e59d8a5b6&version=stable @@ -225,8 +225,8 @@ but [you can read about those below](#promoted-constants)). - **Basic blocks**: The basic blocks are stored in the field [`Body::basic_blocks`][basicblocks]; this is a vector of [`BasicBlockData`] structures. - Nobody ever references a basic block directly: instead, we pass around [`BasicBlock`] - values, which are [newtype'd] indices into this vector. + Nobody ever references a basic block directly: instead, we pass around [`BasicBlock`] values, + which are [newtype'd] indices into this vector. - **Statements** are represented by the type [`Statement`]. - **Terminators** are represented by the [`Terminator`]. - **Locals** are represented by a [newtype'd] index type [`Local`]. @@ -240,8 +240,8 @@ but [you can read about those below](#promoted-constants)). These are represented by the [newtype'd] type [`ProjectionElem`]. So e.g. the place `_1.f` is a projection, with `f` being the "projection element" and `_1` being the base path. - `*_1` is also a projection, with the `*` being represented - by the [`ProjectionElem::Deref`] element. + `*_1` is also a projection, + with the `*` being represented by the [`ProjectionElem::Deref`] element. - **Rvalues** are represented by the enum [`Rvalue`]. - **Operands** are represented by the enum [`Operand`]. @@ -251,8 +251,8 @@ When code has reached the MIR stage, constants can generally come in two forms: *MIR constants* ([`mir::Constant`]) and *type system constants* ([`ty::Const`]). MIR constants are used as operands: in `x + CONST`, `CONST` is a MIR constant; similarly, in `x + 2`, `2` is a MIR constant. -Type system constants are used in -the type system, in particular for array lengths but also for const generics. +Type system constants are used in the type system, +in particular for array lengths but also for const generics. Generally, both kinds of constants can be "unevaluated" or "already evaluated". An unevaluated constant simply stores the `DefId` of what needs to be evaluated @@ -270,8 +270,8 @@ parameter is used as an operand. ### MIR constant values -In general, a MIR constant value (`mir::ConstValue`) was computed by evaluating -some constant the user wrote. +In general, +a MIR constant value (`mir::ConstValue`) was computed by evaluating some constant the user wrote. This [const evaluation](../const-eval.md) produces a very low-level representation of the result in terms of individual bytes. We call this an "indirect" constant (`mir::ConstValue::Indirect`) since the value @@ -280,8 +280,8 @@ is stored in-memory. However, storing everything in-memory would be awfully inefficient. Hence there are some other variants in `mir::ConstValue` that can represent certain simple and common values more efficiently. -In particular, everything that can be -directly written as a literal in Rust (integers, floats, chars, bools, but also +In particular, everything that can be directly written as a literal in Rust (integers, +floats, chars, bools, but also `"string literals"` and `b"byte string literals"`) has an optimized variant that avoids the full overhead of the in-memory representation. @@ -301,8 +301,8 @@ In other words, a specific value must only be representable in one specific way. For example, there is only one way to represent an array of two integers as a `ValTree`: `Branch([Leaf(first_int), Leaf(second_int)])`. Even though theoretically a `[u32; 2]` could be encoded in a `u64` and thus just be a -`Leaf(bits_of_two_u32)`, that is not a legal construction of `ValTree` -(and is very complex to do, so it is unlikely anyone is tempted to do so). +`Leaf(bits_of_two_u32)`, that is not a legal construction of `ValTree` (and is very complex to do, +so it is unlikely anyone is tempted to do so). These rules also mean that some values are not representable. There can be no `union`s in type level constants, From d17747091ff7169f27aad6b62d9258df6ef7baa1 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Wed, 30 Sep 2026 19:23:27 +0200 Subject: [PATCH 11/26] improve mir/index.md --- src/mir/index.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mir/index.md b/src/mir/index.md index a4075d1eae..6854447b66 100644 --- a/src/mir/index.md +++ b/src/mir/index.md @@ -131,7 +131,7 @@ bb0: { ``` A basic block is defined by a series of **statements** and a final **terminator**. - In this case, there is one statement: +In this case, there is one statement: ```mir StorageLive(_1); @@ -252,7 +252,7 @@ When code has reached the MIR stage, constants can generally come in two forms: MIR constants are used as operands: in `x + CONST`, `CONST` is a MIR constant; similarly, in `x + 2`, `2` is a MIR constant. Type system constants are used in the type system, -in particular for array lengths but also for const generics. +in particular for array lengths, but also for const generics. Generally, both kinds of constants can be "unevaluated" or "already evaluated". An unevaluated constant simply stores the `DefId` of what needs to be evaluated From dda63b9fc033342d603012b9fb6aa5a293279dd3 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Wed, 30 Sep 2026 19:23:35 +0200 Subject: [PATCH 12/26] reflow src/mir/index.md --- src/mir/index.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/mir/index.md b/src/mir/index.md index 6854447b66..005dc0cac2 100644 --- a/src/mir/index.md +++ b/src/mir/index.md @@ -152,8 +152,8 @@ Terminators are different from statements because they can have more than one successor – that is, control may flow to different places. Function calls like the call to `Vec::new` are always terminators because of the possibility of unwinding, -although in the case of `Vec::new` we are able to see that indeed unwinding is not -possible, and hence we list only one successor block, `bb2`. +although in the case of `Vec::new` we are able to see that indeed unwinding is not possible, +and hence we list only one successor block, `bb2`. If we look ahead to `bb2`, we will see it looks like this: @@ -281,8 +281,8 @@ However, storing everything in-memory would be awfully inefficient. Hence there are some other variants in `mir::ConstValue` that can represent certain simple and common values more efficiently. In particular, everything that can be directly written as a literal in Rust (integers, -floats, chars, bools, but also -`"string literals"` and `b"byte string literals"`) has an optimized variant that +floats, chars, bools, +but also `"string literals"` and `b"byte string literals"`) has an optimized variant that avoids the full overhead of the in-memory representation. ### ValTrees From b31fb023907d8123e08e1ae004077c73ab2c6983 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Wed, 30 Sep 2026 19:24:12 +0200 Subject: [PATCH 13/26] sembr src/tracing.md --- src/tracing.md | 83 +++++++++++++++++++++++++------------------------- 1 file changed, 42 insertions(+), 41 deletions(-) diff --git a/src/tracing.md b/src/tracing.md index ae819003e1..811e36bb21 100644 --- a/src/tracing.md +++ b/src/tracing.md @@ -1,9 +1,9 @@ # Using tracing to debug the compiler -The compiler has a lot of [`debug!`] (or `trace!`) calls, which print out logging information -at many points. -These are very useful to at least narrow down the location of -a bug if not to find it entirely, or just to orient yourself as to why the +The compiler has a lot of [`debug!`] (or `trace!`) calls, +which print out logging information at many points. +These are very useful to at least narrow down the location of a bug if not to find it entirely, +or just to orient yourself as to why the compiler is doing a particular thing. [`debug!`]: https://docs.rs/tracing/0.1/tracing/macro.debug.html @@ -66,8 +66,8 @@ RUSTC_LOG=rustc_borrowck[do_mir_borrowck] ### I don't want all calls -If you are compiling libcore, you likely don't want *all* borrowck dumps, but only one -for a specific function. +If you are compiling libcore, you likely don't want *all* borrowck dumps, +but only one for a specific function. You can filter function calls by their arguments by regexing them. ``` @@ -75,8 +75,8 @@ RUSTC_LOG=[do_mir_borrowck{id=\.\*from_utf8_unchecked\.\*}] ``` will only give you the logs of borrowchecking `from_utf8_unchecked`. -Note that you will -still get a short message per ignored `do_mir_borrowck`, but none of the things inside those calls. +Note that you will still get a short message per ignored `do_mir_borrowck`, +but none of the things inside those calls. This helps you in looking through the calls that are happening and helps you adjust your regex if you mistyped it. @@ -105,40 +105,41 @@ You can find a list of queries and their arguments in ## Broad module level filters -You can also use filters similar to the `log` crate's filters, which will enable -everything within a specific module. +You can also use filters similar to the `log` crate's filters, +which will enable everything within a specific module. This is often too verbose and too unstructured, so it is recommended to use function level filters. Your log filter can be just `debug` to get all `debug!` output and higher (e.g., it will also include `info!`), or `path::to::module` to get *all* -output (which will include `trace!`) from a particular module, or -`path::to::module=debug` to get `debug!` output and higher from a particular module. +output (which will include `trace!`) from a particular module, +or `path::to::module=debug` to get `debug!` output and higher from a particular module. -For example, to get the `debug!` output and higher for a specific module, you -can run the compiler with `RUSTC_LOG=path::to::module=debug rustc my-file.rs`. +For example, to get the `debug!` output and higher for a specific module, +you can run the compiler with `RUSTC_LOG=path::to::module=debug rustc my-file.rs`. All `debug!` output will then appear in standard error. Note that you can use a partial path and the filter will still work. For example, if you want to see `info!` output from only -`rustdoc::passes::collect_intra_doc_links`, you could use -`RUSTDOC_LOG=rustdoc::passes::collect_intra_doc_links=info` *or* you could use +`rustdoc::passes::collect_intra_doc_links`, +you could use `RUSTDOC_LOG=rustdoc::passes::collect_intra_doc_links=info` *or* you could use `RUSTDOC_LOG=rustdoc::passes::collect_intra=info`. If you are developing rustdoc, use `RUSTDOC_LOG` instead. If you are developing Miri, use `MIRI_LOG` instead. You get the idea :) -See the [`tracing`] crate's docs, and specifically the docs for [`debug!`] to -see the full syntax you can use. -(Note: unlike the compiler, the [`tracing`] -crate and its examples use the `RUSTC_LOG` environment variable. +See the [`tracing`] crate's docs, +and specifically the docs for [`debug!`] to see the full syntax you can use. +(Note: unlike the compiler, +the [`tracing`] crate and its examples use the `RUSTC_LOG` environment variable. rustc, rustdoc, and other tools set custom environment variables.) -**Note that unless you use a very strict filter, the logger will emit a lot of -output, so use the most specific module(s) you can (comma-separated if -multiple)**. It's typically a good idea to pipe standard error to a file and +**Note that unless you use a very strict filter, the logger will emit a lot of output, +so use the most specific module(s) you can (comma-separated if +multiple)**. +It's typically a good idea to pipe standard error to a file and look at the log output with a text editor. So, to put it together: @@ -180,13 +181,13 @@ $ RUSTDOC_LOG=rustdoc=debug rustdoc +stage1 my-file.rs ## Log colors -By default, rustc (and other tools, like rustdoc and Miri) will be smart about -when to use ANSI colors in the log output. +By default, rustc (and other tools, +like rustdoc and Miri) will be smart about when to use ANSI colors in the log output. If they are outputting to a terminal, -they will use colors, and if they are outputting to a file or being piped -somewhere else, they will not. -However, it's hard to read log output in your -terminal unless you have a very strict filter, so you may want to pipe the +they will use colors, and if they are outputting to a file or being piped somewhere else, +they will not. +However, it's hard to read log output in your terminal unless you have a very strict filter, +so you may want to pipe the output to a pager like `less`. But then there won't be any colors, which makes it hard to pick out what you're looking for! @@ -201,18 +202,18 @@ So, if you want to enable colors when piping to `less`, use something similar to $ RUSTC_LOG=debug RUSTC_LOG_COLOR=always rustc +stage1 ... | less -R ``` -Note that `MIRI_LOG_COLOR` will only color logs that come from Miri, not logs -from rustc functions that Miri calls. +Note that `MIRI_LOG_COLOR` will only color logs that come from Miri, +not logs from rustc functions that Miri calls. Use `RUSTC_LOG_COLOR` to color logs from rustc. ## How to keep or remove `debug!` and `trace!` calls from the resulting binary While calls to `error!`, `warn!` and `info!` are included in every build of the compiler, calls to `debug!` and `trace!` are only included in the program if -`rust.debug-logging=true` is turned on in bootstrap.toml (it is -turned off by default), so if you don't see `DEBUG` logs, especially -if you run the compiler with `RUSTC_LOG=rustc rustc some.rs` and only see -`INFO` logs, make sure that `rust.debug-logging=true` is turned on in your bootstrap.toml. +`rust.debug-logging=true` is turned on in bootstrap.toml (it is turned off by default), +so if you don't see `DEBUG` logs, especially +if you run the compiler with `RUSTC_LOG=rustc rustc some.rs` and only see `INFO` logs, +make sure that `rust.debug-logging=true` is turned on in your bootstrap.toml. ## Logging etiquette and conventions @@ -220,11 +221,11 @@ Because calls to `debug!` are removed by default, in most cases, don't worry about the performance of adding "unnecessary" calls to `debug!` and leaving them in code you commit - they won't slow down the performance of what we ship. -That said, there can also be excessive tracing calls, especially -when they are redundant with other calls nearby or in functions called from here. +That said, there can also be excessive tracing calls, +especially when they are redundant with other calls nearby or in functions called from here. There is no perfect balance to hit here, and it is left to the reviewer's -discretion to decide whether to let you leave `debug!` statements in, or whether to ask -you to remove them before merging. +discretion to decide whether to let you leave `debug!` statements in, +or whether to ask you to remove them before merging. It may be preferable to use `trace!` over `debug!` for very noisy logs. @@ -243,8 +244,8 @@ If in the module `rustc::foo` you have a statement debug!(x = ?random_operation(tcx)); ``` -Then if someone runs a debug `rustc` with `RUSTC_LOG=rustc::foo`, then -`random_operation()` will run. +Then if someone runs a debug `rustc` with `RUSTC_LOG=rustc::foo`, +then `random_operation()` will run. `RUSTC_LOG` filters that do not enable this debug statement will not execute `random_operation`. This means that you should not put anything too expensive or likely to crash From 4ce4ced6476d24dbaf51dac4a0bbe5f1ce6a1aa7 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Wed, 30 Sep 2026 19:29:23 +0200 Subject: [PATCH 14/26] improve tracing.md --- src/tracing.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/tracing.md b/src/tracing.md index 811e36bb21..e3c492bbf8 100644 --- a/src/tracing.md +++ b/src/tracing.md @@ -209,11 +209,11 @@ Use `RUSTC_LOG_COLOR` to color logs from rustc. ## How to keep or remove `debug!` and `trace!` calls from the resulting binary While calls to `error!`, `warn!` and `info!` are included in every build of the compiler, -calls to `debug!` and `trace!` are only included in the program if -`rust.debug-logging=true` is turned on in bootstrap.toml (it is turned off by default), +calls to `debug!` and `trace!` are only included in the program if you have +`rust.debug-logging = true` in bootstrap.toml (it is turned off by default), so if you don't see `DEBUG` logs, especially if you run the compiler with `RUSTC_LOG=rustc rustc some.rs` and only see `INFO` logs, -make sure that `rust.debug-logging=true` is turned on in your bootstrap.toml. +make sure that `rust.debug-logging` is turned on in your bootstrap.toml. ## Logging etiquette and conventions From 41206946548afff990c7bada2d6c7c149d85a4ab Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Wed, 30 Sep 2026 19:29:42 +0200 Subject: [PATCH 15/26] reflow src/tracing.md --- src/tracing.md | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/src/tracing.md b/src/tracing.md index e3c492bbf8..0e2f29f698 100644 --- a/src/tracing.md +++ b/src/tracing.md @@ -3,8 +3,7 @@ The compiler has a lot of [`debug!`] (or `trace!`) calls, which print out logging information at many points. These are very useful to at least narrow down the location of a bug if not to find it entirely, -or just to orient yourself as to why the -compiler is doing a particular thing. +or just to orient yourself as to why the compiler is doing a particular thing. [`debug!`]: https://docs.rs/tracing/0.1/tracing/macro.debug.html @@ -120,8 +119,7 @@ you can run the compiler with `RUSTC_LOG=path::to::module=debug rustc my-file.rs All `debug!` output will then appear in standard error. Note that you can use a partial path and the filter will still work. -For example, if you want to see `info!` output from only -`rustdoc::passes::collect_intra_doc_links`, +For example, if you want to see `info!` output from only `rustdoc::passes::collect_intra_doc_links`, you could use `RUSTDOC_LOG=rustdoc::passes::collect_intra_doc_links=info` *or* you could use `RUSTDOC_LOG=rustdoc::passes::collect_intra=info`. @@ -137,8 +135,7 @@ rustc, rustdoc, and other tools set custom environment variables.) **Note that unless you use a very strict filter, the logger will emit a lot of output, -so use the most specific module(s) you can (comma-separated if -multiple)**. +so use the most specific module(s) you can (comma-separated if multiple)**. It's typically a good idea to pipe standard error to a file and look at the log output with a text editor. @@ -187,8 +184,7 @@ If they are outputting to a terminal, they will use colors, and if they are outputting to a file or being piped somewhere else, they will not. However, it's hard to read log output in your terminal unless you have a very strict filter, -so you may want to pipe the -output to a pager like `less`. +so you may want to pipe the output to a pager like `less`. But then there won't be any colors, which makes it hard to pick out what you're looking for! You can override whether to have colors in log output with the `RUSTC_LOG_COLOR` @@ -211,8 +207,8 @@ Use `RUSTC_LOG_COLOR` to color logs from rustc. While calls to `error!`, `warn!` and `info!` are included in every build of the compiler, calls to `debug!` and `trace!` are only included in the program if you have `rust.debug-logging = true` in bootstrap.toml (it is turned off by default), -so if you don't see `DEBUG` logs, especially -if you run the compiler with `RUSTC_LOG=rustc rustc some.rs` and only see `INFO` logs, +so if you don't see `DEBUG` logs, +especially if you run the compiler with `RUSTC_LOG=rustc rustc some.rs` and only see `INFO` logs, make sure that `rust.debug-logging` is turned on in your bootstrap.toml. ## Logging etiquette and conventions From 83be608e9e49d0fdf1b04ae5a0835ec79ae4a9e5 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Wed, 30 Sep 2026 19:46:39 +0200 Subject: [PATCH 16/26] sembr src/debuginfo/llvm-codegen.md --- src/debuginfo/llvm-codegen.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/debuginfo/llvm-codegen.md b/src/debuginfo/llvm-codegen.md index 4f5bdaa1e6..e72b94ea5b 100644 --- a/src/debuginfo/llvm-codegen.md +++ b/src/debuginfo/llvm-codegen.md @@ -1,13 +1,13 @@ # LLVM codegen -When Rust calls an LLVM `DIBuilder` function, LLVM translates the given information to a -["debug record"][dbg_record] that is format-agnostic. +When Rust calls an LLVM `DIBuilder` function, +LLVM translates the given information to a ["debug record"][dbg_record] that is format-agnostic. These records can be inspected in the LLVM-IR. [dbg_record]: https://llvm.org/docs/SourceLevelDebugging.html#debug-records -It is important to note that tags within the debug records are **always stored as DWARF tags**. If -the target calls for PDB debug info, during codegen the debug records will then be passed through +It is important to note that tags within the debug records are **always stored as DWARF tags**. +If the target calls for PDB debug info, during codegen the debug records will then be passed through [a module that translates the DWARF tags to their CodeView counterparts][cv]. [cv]:https://github.com/llvm/llvm-project/blob/main/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp From 730ad61a25b1c276d4c24ee44cc2fce4e65b6aae Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Wed, 30 Sep 2026 19:47:40 +0200 Subject: [PATCH 17/26] improve debuginfo/llvm-codegen.md --- src/debuginfo/llvm-codegen.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/debuginfo/llvm-codegen.md b/src/debuginfo/llvm-codegen.md index e72b94ea5b..1cdc7c0929 100644 --- a/src/debuginfo/llvm-codegen.md +++ b/src/debuginfo/llvm-codegen.md @@ -7,7 +7,7 @@ These records can be inspected in the LLVM-IR. [dbg_record]: https://llvm.org/docs/SourceLevelDebugging.html#debug-records It is important to note that tags within the debug records are **always stored as DWARF tags**. -If the target calls for PDB debug info, during codegen the debug records will then be passed through +If the target calls for PDB debug info, during codegen, the debug records will then be passed through [a module that translates the DWARF tags to their CodeView counterparts][cv]. [cv]:https://github.com/llvm/llvm-project/blob/main/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp From 66042f51926e04a0f962b1a1d2bd07f8c3ea44a0 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Wed, 30 Sep 2026 19:48:04 +0200 Subject: [PATCH 18/26] sembr src/profiling/with-perf.md --- src/profiling/with-perf.md | 64 ++++++++++++++++++-------------------- 1 file changed, 31 insertions(+), 33 deletions(-) diff --git a/src/profiling/with-perf.md b/src/profiling/with-perf.md index b55afed47f..9c3cf1d887 100644 --- a/src/profiling/with-perf.md +++ b/src/profiling/with-perf.md @@ -60,8 +60,8 @@ cargo install --locked addr2line --features="bin" ### Gathering a perf profile from a `perf.rust-lang.org` test Often we want to analyze a specific test from `perf.rust-lang.org`. -The easiest way to do that is to use the [rustc-perf] -benchmarking suite, this approach is described [here](with-rustc-perf.md). +The easiest way to do that is to use the [rustc-perf] benchmarking suite, +this approach is described [here](with-rustc-perf.md). Instead of using the benchmark suite CLI, you can also profile the benchmarks manually. First, you need to clone the [rustc-perf] repository: @@ -96,8 +96,8 @@ CARGO_INCREMENTAL=0 cargo + check Next: we want record the execution time for *just* the clap-rs crate, running cargo check. -I tend to use `cargo rustc` for this, since it -also allows me to add explicit flags, which we'll do later on. +I tend to use `cargo rustc` for this, since it also allows me to add explicit flags, +which we'll do later on. ```bash touch src/lib.rs @@ -106,8 +106,8 @@ CARGO_INCREMENTAL=0 perf record -F99 --call-graph dwarf cargo rustc --profile ch Note that final command: it's a doozy! It uses the `cargo rustc` command, which executes rustc with (potentially) additional options; -the `--profile check` and `--lib` options specify that we are doing a -`cargo check` execution, and that this is a library (not a binary). +the `--profile check` and `--lib` options specify that we are doing a `cargo check` execution, +and that this is a library (not a binary). At this point, we can use `perf` tooling to analyze the results. For example: @@ -121,14 +121,14 @@ In simple cases, that can be helpful. For more detailed examination, the [`perf-focus` tool][pf] can be helpful; it is covered below. **A note of caution.** Each of the rustc-perf tests is its own special snowflake. - In particular, some of them are not libraries, in which - case you would want to do `touch src/main.rs` and avoid passing `--lib`. + In particular, some of them are not libraries, + in which case you would want to do `touch src/main.rs` and avoid passing `--lib`. I'm not sure how best to tell which test is which to be honest. ### Gathering NLL data -If you want to profile an NLL run, you can just pass extra options to -the `cargo rustc` command, like so: +If you want to profile an NLL run, you can just pass extra options to the `cargo rustc` command, +like so: ```bash touch src/lib.rs @@ -152,8 +152,8 @@ To understand how it works, you have to know just a bit about perf. Basically, perf works by *sampling* your process on a regular basis (or whenever some event occurs). For each sample, perf gathers a backtrace. `perf focus` lets you write a regular expression that tests -which functions appear in that backtrace, and then tells you which -percentage of samples had a backtrace that met the regular expression. +which functions appear in that backtrace, +and then tells you which percentage of samples had a backtrace that met the regular expression. It's probably easiest to explain by walking through how I would analyze NLL performance. ### Installing `perf-focus` @@ -168,8 +168,7 @@ cargo install --locked perf-focus Let's say we've gathered the NLL data for a test. We'd like to know how much time it is spending in the MIR borrow-checker. -The "main" function of the MIR borrowck is called `do_mir_borrowck`, so we can do -this command: +The "main" function of the MIR borrowck is called `do_mir_borrowck`, so we can do this command: ```bash $ perf focus '{do_mir_borrowck}' @@ -179,22 +178,22 @@ Not Matches: 542 Percentage : 29% ``` -The `'{do_mir_borrowck}'` argument is called the **matcher**. It -specifies the test to be applied on the backtrace. +The `'{do_mir_borrowck}'` argument is called the **matcher**. +It specifies the test to be applied on the backtrace. In this case, the `{X}` indicates that there must be *some* function on the backtrace that meets the regular expression `X`. -In this case, that regex is just the name of the function we want -(in fact, it's a subset of the name; +In this case, that regex is just the name of the function we want (in fact, +it's a subset of the name; the full name includes a bunch of other stuff, like the module path). In this mode, perf-focus just prints out the percentage of samples where `do_mir_borrowck` was on the stack: in this case, 29%. -**A note about c++filt.** To get the data from `perf`, `perf focus` - currently executes `perf script` (perhaps there is a better way...). +**A note about c++filt.** To get the data from `perf`, + `perf focus` currently executes `perf script` (perhaps there is a better way...). I've sometimes found that `perf script` outputs C++ mangled names. This is annoying. You can tell by running `perf script | - head` yourself — if you see names like `5rustc6middle` instead of - `rustc::middle`, then you have the same problem. + head` yourself — if you see names like `5rustc6middle` instead of `rustc::middle`, + then you have the same problem. You can solve this by doing: ```bash @@ -203,10 +202,10 @@ perf script | c++filt | perf focus --from-stdin ... This will pipe the output from `perf script` through `c++filt` and should mostly convert those names into a more friendly format. -The `--from-stdin` flag to `perf focus` tells it to get its data from -stdin, rather than executing `perf focus`. -We should make this more convenient (at worst, maybe add a `c++filt` option to `perf focus`, or -just always use it — it's pretty harmless). +The `--from-stdin` flag to `perf focus` tells it to get its data from stdin, +rather than executing `perf focus`. +We should make this more convenient (at worst, maybe add a `c++filt` option to `perf focus`, +or just always use it — it's pretty harmless). ### Example: How much time does MIR borrowck spend solving traits? @@ -275,17 +274,16 @@ Usually "total" is the more interesting number, but not always. ### Relative percentages -By default, all in perf-focus are relative to the **total program -execution**. This is useful to help you keep perspective — often as -we drill down to find hot spots, we can lose sight of the fact that, +By default, all in perf-focus are relative to the **total program execution**. +This is useful to help you keep perspective — often as we drill down to find hot spots, +we can lose sight of the fact that, in terms of overall program execution, this "hot spot" is actually not important. It also ensures that percentages between different queries are easily compared against one another. -That said, sometimes it's useful to get relative percentages, so `perf -focus` offers a `--relative` option. +That said, sometimes it's useful to get relative percentages, +so `perf focus` offers a `--relative` option. In this case, the percentages are listed only for samples that match (vs all samples). -So for example we could get our percentages relative to the borrowck itself -like so: +So for example we could get our percentages relative to the borrowck itself like so: ```bash $ perf focus '{do_mir_borrowck}' --tree-callees --relative --tree-max-depth 1 --tree-min-percent 5 From a8b144ffbbb28b223e9dc33bb9e322a712e2ad33 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Wed, 30 Sep 2026 19:51:12 +0200 Subject: [PATCH 19/26] missing pauses --- src/profiling/with-perf.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/profiling/with-perf.md b/src/profiling/with-perf.md index 9c3cf1d887..1a3b986d82 100644 --- a/src/profiling/with-perf.md +++ b/src/profiling/with-perf.md @@ -283,7 +283,7 @@ It also ensures that percentages between different queries are easily compared a That said, sometimes it's useful to get relative percentages, so `perf focus` offers a `--relative` option. In this case, the percentages are listed only for samples that match (vs all samples). -So for example we could get our percentages relative to the borrowck itself like so: +So, for example, we could get our percentages relative to the borrowck itself like so: ```bash $ perf focus '{do_mir_borrowck}' --tree-callees --relative --tree-max-depth 1 --tree-min-percent 5 From 8fda284b255a1a9275fc674672afecd5cefec654 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Wed, 30 Sep 2026 19:51:30 +0200 Subject: [PATCH 20/26] sembr src/effects.md --- src/effects.md | 55 +++++++++++++++++++++++++------------------------- 1 file changed, 28 insertions(+), 27 deletions(-) diff --git a/src/effects.md b/src/effects.md index 9c54705e00..55e00d4acf 100644 --- a/src/effects.md +++ b/src/effects.md @@ -3,20 +3,20 @@ ## The `HostEffect` predicate [`HostEffectPredicate`]s are a kind of predicate from `[const] Tr` or `const Tr` bounds. -It has a trait reference, and a `constness` which could be `Maybe` or -`Const` depending on the bound. +It has a trait reference, +and a `constness` which could be `Maybe` or `Const` depending on the bound. Because `[const] Tr`, or rather `Maybe` bounds -apply differently based on whichever contexts they are in, they have different -behavior than normal bounds. +apply differently based on whichever contexts they are in, +they have different behavior than normal bounds. Where normal trait bounds on a function such as `T: Tr` are collected within the [`clauses_of`] query to be proven when a -function is called and to be assumed within the function, bounds such as -`T: [const] Tr` will behave as a normal trait bound and add `T: Tr` to the result +function is called and to be assumed within the function, +bounds such as `T: [const] Tr` will behave as a normal trait bound and add `T: Tr` to the result from `clauses_of`, but also adds a `HostEffectPredicate` to the [`const_conditions`] query. On the other hand, `T: const Tr` bounds do not change meaning across contexts, -therefore they will result in `HostEffect(T: Tr, const)` being added to -`clauses_of`, and not `const_conditions`. +therefore they will result in `HostEffect(T: Tr, const)` being added to `clauses_of`, +and not `const_conditions`. [`HostEffectPredicate`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_type_ir/predicate/struct.HostEffectPredicate.html [`clauses_of`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyCtxt.html#method.clauses_of @@ -34,14 +34,15 @@ fn foo() where T: Default {} We must be able to prove that `T` implements `Default`. In a similar vein, `const_conditions` represents a set of predicates that need to be proven to use -an item *in const contexts*. If we adjust the example above to use `const` trait bounds: +an item *in const contexts*. +If we adjust the example above to use `const` trait bounds: ```rust const fn foo() where T: [const] Default {} ``` -Then `foo` would get a `HostEffect(T: Default, maybe)` in the `const_conditions` -query, suggesting that in order to call `foo` from const contexts, one must +Then `foo` would get a `HostEffect(T: Default, maybe)` in the `const_conditions` query, +suggesting that in order to call `foo` from const contexts, one must prove that `T` has a const implementation of `Default`. ## Enforcement of `const_conditions` @@ -51,8 +52,8 @@ prove that `T` has a const implementation of `Default`. Every call in HIR from a const context (which includes `const fn` and `const` items) will check that `const_conditions` of the function we are calling hold. This is done in [`FnCtxt::enforce_context_effects`]. -Note that we don't check -if the function is only referred to but not called, as the following code needs to compile: +Note that we don't check if the function is only referred to but not called, +as the following code needs to compile: ```rust const fn hi() -> T { @@ -61,8 +62,8 @@ const fn hi() -> T { const X: fn() -> u32 = hi::; ``` -For a trait `impl` to be well-formed, we must be able to prove the -`const_conditions` of the trait from the `impl`'s environment. +For a trait `impl` to be well-formed, +we must be able to prove the `const_conditions` of the trait from the `impl`'s environment. This is checked in [`wfcheck::check_impl`]. Here's an example: @@ -79,8 +80,8 @@ impl const Foo for () {} Methods of trait impls must not have stricter bounds than the method of the trait that they are implementing. -To check that the methods are compatible, a -hybrid environment is constructed with the predicates of the `impl` plus the +To check that the methods are compatible, +a hybrid environment is constructed with the predicates of the `impl` plus the predicates of the trait method, and we attempt to prove the predicates of the impl method. We do the same for `const_conditions`: @@ -113,8 +114,8 @@ are revalidated again in [`Checker::revalidate_conditional_constness`]. ## `explicit_implied_const_bounds` on associated types and traits -Bounds on associated types, opaque types, and supertraits such as the following -have their bounds represented differently: +Bounds on associated types, opaque types, +and supertraits such as the following have their bounds represented differently: ```rust trait Foo: [const] PartialEq { @@ -132,8 +133,8 @@ bounds on functions), these bounds need to be proved at definition (at the impl, or when returning the opaque) but can be assumed for callers. The non-const equivalent of these bounds are called [`explicit_item_bounds`]. -These bounds are checked in [`compare_impl_item::check_type_bounds`] for HIR -typeck, [`evaluate_host_effect_from_item_bounds`] in the old solver and +These bounds are checked in [`compare_impl_item::check_type_bounds`] for HIR typeck, +[`evaluate_host_effect_from_item_bounds`] in the old solver and [`consider_additional_alias_assumptions`] in the new solver. [`explicit_item_bounds`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyCtxt.html#method.explicit_item_bounds @@ -147,11 +148,11 @@ typeck, [`evaluate_host_effect_from_item_bounds`] in the old solver and In general, we can prove a `HostEffect` predicate when either of these conditions are met: * The predicate can be assumed from caller bounds; -* The type has a `const` `impl` for the trait, *and* that const conditions on - the impl holds, *and* that the `explicit_implied_const_bounds` on the trait holds; or +* The type has a `const` `impl` for the trait, *and* that const conditions on the impl holds, + *and* that the `explicit_implied_const_bounds` on the trait holds; or * The type has a built-in implementation for the trait in const contexts. - For example, `Fn` may be implemented by function items if their const conditions - are satisfied, or `Destruct` is implemented in const contexts if the type can + For example, `Fn` may be implemented by function items if their const conditions are satisfied, + or `Destruct` is implemented in const contexts if the type can be dropped at compile time. [old solver]: https://doc.rust-lang.org/nightly/nightly-rustc/src/rustc_trait_selection/traits/effects.rs.html @@ -164,8 +165,8 @@ To be expanded later. ### The `#[rustc_non_const_trait_method]` attribute This is intended for internal (standard library) usage only. -With this attribute applied to a trait method, the compiler will not check the default body of this -method for ability to run in compile time. +With this attribute applied to a trait method, +the compiler will not check the default body of this method for ability to run in compile time. Users of the trait will also not be allowed to use this trait method in const contexts. This attribute is primarily used for constifying large traits such as `Iterator` without having to make all From 93e34ed4b94a9bfe9a02b7bdd361d2c0ab7c3f28 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Wed, 30 Sep 2026 19:54:41 +0200 Subject: [PATCH 21/26] missing pause --- src/effects.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/effects.md b/src/effects.md index 55e00d4acf..f6a11b435a 100644 --- a/src/effects.md +++ b/src/effects.md @@ -4,7 +4,7 @@ [`HostEffectPredicate`]s are a kind of predicate from `[const] Tr` or `const Tr` bounds. It has a trait reference, -and a `constness` which could be `Maybe` or `Const` depending on the bound. +and a `constness` which could be `Maybe` or `Const`, depending on the bound. Because `[const] Tr`, or rather `Maybe` bounds apply differently based on whichever contexts they are in, they have different behavior than normal bounds. From c33a2d209f36192511574a46bdd78a7be7f3023f Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Wed, 30 Sep 2026 19:54:46 +0200 Subject: [PATCH 22/26] sembr src/query.md --- src/query.md | 38 ++++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/src/query.md b/src/query.md index 471b445c14..19145a5a7a 100644 --- a/src/query.md +++ b/src/query.md @@ -9,16 +9,17 @@ Instead of entirely independent passes (parsing, type-checking, etc.), a set of function-like *queries* compute information about the input source. For example, -there is a query called `type_of` that, given the [`DefId`] of -some item, will compute the type of that item and return it to you. +there is a query called `type_of` that, given the [`DefId`] of some item, +will compute the type of that item and return it to you. [`DefId`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_span/def_id/struct.DefId.html [Overview of the compiler]: overview.md#queries -Query execution is *memoized*. The first time you invoke a -query, it will go do the computation, but the next time, the result is returned from a hashtable. -Moreover, query execution fits nicely into -*incremental computation*; the idea is roughly that, when you invoke a +Query execution is *memoized*. +The first time you invoke a query, +it will go do the computation, but the next time, the result is returned from a hashtable. +Moreover, query execution fits nicely into *incremental computation*; the idea is roughly that, +when you invoke a query, the result *may* be returned to you by loading stored data from disk.[^incr-comp-detail] When we execute a query, @@ -39,8 +40,8 @@ For example: - That query in turn would invoke something asking for the HIR. - This keeps going further and further back until we wind up doing the actual parsing. -Although this vision is not fully realized, large sections of the -compiler (for example, generating [MIR]) currently work exactly like this. +Although this vision is not fully realized, large sections of the compiler (for example, +generating [MIR]) currently work exactly like this. [^incr-comp-detail]: The [Incremental compilation in detail] chapter gives a more in-depth description of what queries are and how they work. @@ -65,22 +66,22 @@ let ty = tcx.type_of(some_def_id); So you may be wondering what happens when you invoke a query method. The answer is that, for each query, the compiler maintains a -cache – if your query has already been executed, then, the answer is -simple: we clone the return value out of the cache and return it +cache – if your query has already been executed, then, +the answer is simple: we clone the return value out of the cache and return it (therefore, you should try to ensure that the return types of queries are cheaply cloneable; insert an `Rc` if necessary). ### Providers -If, however, the query is *not* in the cache, then the compiler will -call the corresponding **provider** function. +If, however, the query is *not* in the cache, +then the compiler will call the corresponding **provider** function. A provider is a function implemented in a specific module and **manually registered** into either the [`Providers`][providers_struct] struct (for local crate queries) or the [`ExternProviders`][extern_providers_struct] struct (for external crate queries) during compiler initialization. The macro system generates both structs, -which act as function tables for all query implementations, where each -field is a function pointer to the actual provider. +which act as function tables for all query implementations, +where each field is a function pointer to the actual provider. **Note:** Both the `Providers` and `ExternProviders` structs are generated by macros and act as function tables for all query implementations. They are **not** Rust traits, but plain structs with function pointer fields. @@ -112,10 +113,11 @@ Providers take two arguments: the `tcx` and the query key. They return the result of the query. N.B. Most of the `rustc_*` crates only provide **local -providers**. Almost all **extern providers** wind up going through the -[`rustc_metadata` crate][rustc_metadata], which loads the information from the crate metadata. -But in some cases there are crates that -provide queries for *both* local and external crates, in which case +providers**. +Almost all **extern providers** wind up going through the [`rustc_metadata` crate][rustc_metadata], +which loads the information from the crate metadata. +But in some cases there are crates that provide queries for *both* local and external crates, +in which case they define both a `provide` and a `provide_extern` function, through [`wasm_import_module_map`][wasm_import_module_map], that `rustc_driver` can invoke. From b57a63fe8888772eb4ce6ae6b64a198ff7483491 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Wed, 30 Sep 2026 19:56:54 +0200 Subject: [PATCH 23/26] reflow src/query.md --- src/query.md | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/query.md b/src/query.md index 19145a5a7a..a4b9eef02f 100644 --- a/src/query.md +++ b/src/query.md @@ -19,8 +19,8 @@ Query execution is *memoized*. The first time you invoke a query, it will go do the computation, but the next time, the result is returned from a hashtable. Moreover, query execution fits nicely into *incremental computation*; the idea is roughly that, -when you invoke a -query, the result *may* be returned to you by loading stored data from disk.[^incr-comp-detail] +when you invoke a query, +the result *may* be returned to you by loading stored data from disk.[^incr-comp-detail] When we execute a query, we also discover (at runtime!) what other queries it depends on. @@ -67,8 +67,8 @@ let ty = tcx.type_of(some_def_id); So you may be wondering what happens when you invoke a query method. The answer is that, for each query, the compiler maintains a cache – if your query has already been executed, then, -the answer is simple: we clone the return value out of the cache and return it -(therefore, you should try to ensure that the return types of queries +the answer is simple: we clone the return value out of the cache and return it (therefore, +you should try to ensure that the return types of queries are cheaply cloneable; insert an `Rc` if necessary). ### Providers @@ -117,8 +117,7 @@ providers**. Almost all **extern providers** wind up going through the [`rustc_metadata` crate][rustc_metadata], which loads the information from the crate metadata. But in some cases there are crates that provide queries for *both* local and external crates, -in which case -they define both a `provide` and a `provide_extern` function, through +in which case they define both a `provide` and a `provide_extern` function, through [`wasm_import_module_map`][wasm_import_module_map], that `rustc_driver` can invoke. [rustc_metadata]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_metadata/index.html From ab32a2e1f4c16cc3d4d4350ed82ae9af93d0aa10 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Wed, 30 Sep 2026 19:57:15 +0200 Subject: [PATCH 24/26] sembr src/ty.md --- src/ty.md | 88 +++++++++++++++++++++++++++---------------------------- 1 file changed, 44 insertions(+), 44 deletions(-) diff --git a/src/ty.md b/src/ty.md index ef2ea37b7c..b9776523dd 100644 --- a/src/ty.md +++ b/src/ty.md @@ -1,8 +1,8 @@ # The `ty` module: representing types The `ty` module defines how the Rust compiler represents types internally. -It also defines the -*typing context* (`tcx` or `TyCtxt`), which is the central data structure in the compiler. +It also defines the *typing context* (`tcx` or `TyCtxt`), +which is the central data structure in the compiler. ## `ty::Ty` @@ -22,12 +22,13 @@ The distinction is important, so we will discuss it first before going into the The HIR in rustc can be thought of as the high-level intermediate representation. It is more or less the AST (see [this chapter](hir.md)) as it represents the -syntax that the user wrote, and is obtained after parsing and some *desugaring*. It has a -representation of types, but in reality it reflects more of what the user wrote, that is, what they +syntax that the user wrote, and is obtained after parsing and some *desugaring*. +It has a representation of types, +but in reality it reflects more of what the user wrote, that is, what they wrote so as to represent that type. -In contrast, `ty::Ty` represents the semantics of a type, that is, the *meaning* of what the user -wrote. +In contrast, `ty::Ty` represents the semantics of a type, that is, +the *meaning* of what the user wrote. For example, `rustc_hir::Ty` would record the fact that a user used the name `u32` twice in their program, but the `ty::Ty` would record the fact that both usages refer to the same type. @@ -46,16 +47,16 @@ That is, they have two different [`Span`s][span] (locations). **Example: `fn foo(x: &u32) -> &u32`** In addition, HIR might have information left out. -This type -`&u32` is incomplete, since in the full Rust type there is actually a lifetime, but we didn’t need +This type `&u32` is incomplete, +since in the full Rust type there is actually a lifetime, but we didn’t need to write those lifetimes. There are also some elision rules that insert information. The result may look like `fn foo<'a>(x: &'a u32) -> &'a u32`. In the HIR level, these things are not spelled out and you can say the picture is rather incomplete. However, at the `ty::Ty` level, these details are added and it is complete. -Moreover, we will have -exactly one `ty::Ty` for a given type, like `u32`, and that `ty::Ty` is used for all `u32`s in the +Moreover, we will have exactly one `ty::Ty` for a given type, +like `u32`, and that `ty::Ty` is used for all `u32`s in the whole program, not a specific usage, unlike `rustc_hir::Ty`. Here is a summary: @@ -74,8 +75,8 @@ Here is a summary: HIR is built directly from the AST, so it happens before any `ty::Ty` is produced. After HIR is built, some basic type inference and type checking is done. -During the type inference, we -figure out what the `ty::Ty` of everything is and we also check if the type of something is +During the type inference, +we figure out what the `ty::Ty` of everything is and we also check if the type of something is ambiguous. The `ty::Ty` is then used for type checking while making sure everything has the expected type. The [`hir_ty_lowering` module][hir_ty_lowering] is where the code responsible for @@ -102,8 +103,8 @@ Consider another example: `fn foo(x: T) -> u32`. Suppose that someone invokes `foo::(0)`. This means that `T` and `u32` (in this invocation) actually turns out to be the same type, so we would eventually end up with the same `ty::Ty` in the end, but we have distinct `rustc_hir::Ty`. -(This is a bit over-simplified, though, since during type checking, we would check the function -generically and would still have a `T` distinct from `u32`. +(This is a bit over-simplified, though, since during type checking, +we would check the function generically and would still have a `T` distinct from `u32`. Later, when doing code generation, we would always be handling "monomorphized" (fully substituted) versions of each function, and hence we would know what `T` represents (and specifically that it is `u32`).) @@ -125,8 +126,8 @@ Here the type `X` will vary depending on context, clearly. If you look at the `rustc_hir::Ty`, you will get back that `X` is an alias in both cases (though it will be mapped via name resolution to distinct aliases). -But if you look at the `ty::Ty` signature, it will be either `fn(u32) -> u32` -or `fn(i32) -> i32` (with type aliases fully expanded). +But if you look at the `ty::Ty` signature, +it will be either `fn(u32) -> u32` or `fn(i32) -> i32` (with type aliases fully expanded). ## `ty::Ty` implementation @@ -140,8 +141,7 @@ We always hide them within `Ty` and skip over it via `Deref` impls or methods. They are convenient hacks for efficiency and summarize information about the type that we may want to know, but they don’t come into the picture as much here. -Finally, [`Interned`](./memory.md) allows the `ty::Ty` to be a thin pointer-like -type. +Finally, [`Interned`](./memory.md) allows the `ty::Ty` to be a thin pointer-like type. This allows us to do cheap comparisons for equality, along with the other benefits of interning. [tykind]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_type_ir/ty_kind/enum.TyKind.html @@ -170,8 +170,8 @@ You can also find various common types in the `tcx` itself by accessing its fiel ## Comparing types Because types are interned, it is possible to compare them for equality efficiently using `==` -– however, this is almost never what you want to do unless you happen to be hashing and looking -for duplicates. +– however, +this is almost never what you want to do unless you happen to be hashing and looking for duplicates. This is because often in Rust there are multiple ways to represent the same type, particularly once inference is involved. @@ -182,11 +182,11 @@ diagnostics code). `==` on them will return `false` though, since they are different types. The simplest way to compare two types correctly requires an inference context (`infcx`). -If you have one, you can use `infcx.can_eq(param_env, ty1, ty2)` -to check whether the types can be made equal. +If you have one, you can use `infcx.can_eq(param_env, ty1, +ty2)` to check whether the types can be made equal. This is typically what you want to check during diagnostics, which is concerned with questions such -as whether two types can be assigned to each other, not whether they're represented identically in -the compiler's type-checking layer. +as whether two types can be assigned to each other, +not whether they're represented identically in the compiler's type-checking layer. When working with an inference context, you have to be careful to ensure that potential inference variables inside the types actually belong to that inference context. @@ -199,24 +199,24 @@ To compare them correctly, you have to normalize the types first. This is primarily a concern during HIR type checking and with all types from a `TyCtxt` query (for example from `tcx.type_of()`). -When a `FnCtxt` or an `ObligationCtxt` is available during type checking, `.normalize(ty)` -should be used on them to normalize the type. +When a `FnCtxt` or an `ObligationCtxt` is available during type checking, +`.normalize(ty)` should be used on them to normalize the type. After type checking, diagnostics code can use `tcx.normalize_erasing_regions(ty)`. There are also cases where using `==` on `Ty` is fine. -This is, for example, the case in late lints -or after monomorphization, since type checking has been completed, meaning all inference variables +This is, for example, the case in late lints or after monomorphization, +since type checking has been completed, meaning all inference variables are resolved and all regions have been erased. -In these cases, if you know that inference variables -or normalization won't be a concern, `#[allow]` or `#[expect]`ing the lint is recommended. +In these cases, if you know that inference variables or normalization won't be a concern, +`#[allow]` or `#[expect]`ing the lint is recommended. When diagnostics code does not have access to an inference context, it should be threaded through the function calls if one is available in some place (like during type checking). -If no inference context is available at all, then one can be created as described in -[type-inference]. -But this is only useful when the involved types (for example, if -they came from a query like `tcx.type_of()`) are actually substituted with fresh +If no inference context is available at all, +then one can be created as described in [type-inference]. +But this is only useful when the involved types (for example, +if they came from a query like `tcx.type_of()`) are actually substituted with fresh inference variables using [`fresh_args_for_item`]. This can be used to answer questions like "can `Vec` for any `T` be unified with `Vec`?". @@ -237,8 +237,8 @@ fn foo(x: Ty<'tcx>) { } ``` -The `kind` field is of type `TyKind<'tcx>`, which is an enum defining all of the different kinds of -types in the compiler. +The `kind` field is of type `TyKind<'tcx>`, +which is an enum defining all of the different kinds of types in the compiler. > N.B. inspecting the `kind` field on types during type inference can be risky, as there may be > inference variables and other things to consider, or sometimes types are not yet known and will @@ -247,8 +247,8 @@ types in the compiler. There are a lot of related types, and we’ll cover them in time (e.g regions/lifetimes, “substitutions”, etc). -There are many variants on the `TyKind` enum, which you can see by looking at its -[documentation][tykind]. +There are many variants on the `TyKind` enum, +which you can see by looking at its [documentation][tykind]. Here is a sampling: - [**Algebraic Data Types (ADTs)**][kindadt] An [*algebraic data type*][wikiadt] is a `struct`, @@ -264,8 +264,8 @@ Here is a sampling: - [**Array**][kindarray] Corresponds to `[T; n]`. - [**RawPtr**][kindrawptr] Corresponds to `*mut T` or `*const T`. - [**Ref**][kindref] `Ref` stands for safe references, `&'a mut T` or `&'a T`. - `Ref` has some - associated parts, like `Ty<'tcx>` which is the type that the reference references. + `Ref` has some associated parts, + like `Ty<'tcx>` which is the type that the reference references. `Region<'tcx>` is the lifetime or region of the reference and `Mutability` if the reference is mutable or not. - [**Param**][kindparam] Represents a type parameter (e.g. the `T` in `Vec`). @@ -314,15 +314,15 @@ which case the error should've been reported when that error type was produced). It's important to maintain this invariant because the whole point of the `Error` type is to suppress other errors -- i.e., we don't report them. If we were to produce an `Error` type without actually -emitting an error to the user, then this could cause later errors to be suppressed, and the -compilation might inadvertently succeed! +emitting an error to the user, then this could cause later errors to be suppressed, +and the compilation might inadvertently succeed! Sometimes there is a third case. You believe that an error has been reported, but you believe it would've been reported earlier in the compilation, not locally. In that case, you can create a "delayed bug" with [`delayed_bug`] or [`span_delayed_bug`]. -This will make a note that you expect -compilation to yield an error -- if, however, compilation should succeed, then it will trigger a +This will make a note that you expect compilation to yield an error -- if, +however, compilation should succeed, then it will trigger a compiler bug report. [`delayed_bug`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_errors/struct.DiagCtxt.html#method.delayed_bug From 4bcc3ba7159075e839b0e9efaaed985fdd590a6a Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Wed, 30 Sep 2026 20:05:04 +0200 Subject: [PATCH 25/26] improve ty.md --- src/ty.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/ty.md b/src/ty.md index b9776523dd..887dd822e6 100644 --- a/src/ty.md +++ b/src/ty.md @@ -24,11 +24,11 @@ The HIR in rustc can be thought of as the high-level intermediate representation It is more or less the AST (see [this chapter](hir.md)) as it represents the syntax that the user wrote, and is obtained after parsing and some *desugaring*. It has a representation of types, -but in reality it reflects more of what the user wrote, that is, what they -wrote so as to represent that type. +but in reality, it reflects more of what the user wrote, +so as to represent that type. -In contrast, `ty::Ty` represents the semantics of a type, that is, -the *meaning* of what the user wrote. +In contrast, `ty::Ty` represents the semantics of a type; +that is, the *meaning* of what the user wrote. For example, `rustc_hir::Ty` would record the fact that a user used the name `u32` twice in their program, but the `ty::Ty` would record the fact that both usages refer to the same type. @@ -169,9 +169,9 @@ You can also find various common types in the `tcx` itself by accessing its fiel ## Comparing types -Because types are interned, it is possible to compare them for equality efficiently using `==` -– however, -this is almost never what you want to do unless you happen to be hashing and looking for duplicates. +Because types are interned, it is possible to compare them for equality efficiently using `==`. +However, this is almost never what you want to do, +unless you happen to be hashing and looking for duplicates. This is because often in Rust there are multiple ways to represent the same type, particularly once inference is involved. @@ -182,8 +182,8 @@ diagnostics code). `==` on them will return `false` though, since they are different types. The simplest way to compare two types correctly requires an inference context (`infcx`). -If you have one, you can use `infcx.can_eq(param_env, ty1, -ty2)` to check whether the types can be made equal. +If you have one, +you can use `infcx.can_eq(param_env, ty1, ty2)` to check whether the types can be made equal. This is typically what you want to check during diagnostics, which is concerned with questions such as whether two types can be assigned to each other, not whether they're represented identically in the compiler's type-checking layer. @@ -265,7 +265,7 @@ Here is a sampling: - [**RawPtr**][kindrawptr] Corresponds to `*mut T` or `*const T`. - [**Ref**][kindref] `Ref` stands for safe references, `&'a mut T` or `&'a T`. `Ref` has some associated parts, - like `Ty<'tcx>` which is the type that the reference references. + like `Ty<'tcx>`, which is the type that the reference references. `Region<'tcx>` is the lifetime or region of the reference and `Mutability` if the reference is mutable or not. - [**Param**][kindparam] Represents a type parameter (e.g. the `T` in `Vec`). From c20e323a7bfdd9e7cff3366fc7596ffb5bace6fa Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Wed, 30 Sep 2026 20:11:07 +0200 Subject: [PATCH 26/26] extraneous --- src/const-generics.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/const-generics.md b/src/const-generics.md index a5c7ec506b..2738782db9 100644 --- a/src/const-generics.md +++ b/src/const-generics.md @@ -83,7 +83,7 @@ When we go through HIR ty lowering for the array type in `Alias`, we will lower This will effectively set the type of the `ANON` const item during some later part of the compiler rather than when constructing the HIR. After all of this desugaring has taken place the final representation in the type system (ie as a `ty::Const`) is a `ConstKind::Alias` with the `DefId` of the `AnonConst`. -This is equivalent to how we would representa a usage of an actual const item if we were to represent them without going through an anon const (e.g. when `gca_generic_const_args` is enabled). +This is equivalent to how we would represent a usage of an actual const item if we were to represent them without going through an anon const (e.g. when `gca_generic_const_args` is enabled). This allows the representation for const "aliases" to be the same as the representation of `TyKind::Alias`. Having a proper HIR body also allows for a *lot* of code re-use, e.g. we can reuse HIR typechecking and all of the lowering steps to MIR where we can then reuse const eval.