Merge pull request #19826 from lnicola/sync-from-rust

minor: Sync from downstream
This commit is contained in:
Laurențiu Nicola 2025-05-20 07:15:48 +00:00 committed by GitHub
commit 404670a818
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
37 changed files with 625 additions and 383 deletions

View File

@ -14,7 +14,7 @@ jobs:
if: github.repository == 'rust-lang/rustc-dev-guide' if: github.repository == 'rust-lang/rustc-dev-guide'
runs-on: ubuntu-latest runs-on: ubuntu-latest
env: env:
MDBOOK_VERSION: 0.4.21 MDBOOK_VERSION: 0.4.48
MDBOOK_LINKCHECK2_VERSION: 0.9.1 MDBOOK_LINKCHECK2_VERSION: 0.9.1
MDBOOK_MERMAID_VERSION: 0.12.6 MDBOOK_MERMAID_VERSION: 0.12.6
MDBOOK_TOC_VERSION: 0.11.2 MDBOOK_TOC_VERSION: 0.11.2

View File

@ -91,6 +91,16 @@ Older versions of `josh-proxy` may not round trip commits losslessly so it is im
3) Push the branch to your fork and create a PR into `rustc-dev-guide` 3) Push the branch to your fork and create a PR into `rustc-dev-guide`
### Push changes from this repository into `rust-lang/rust` ### Push changes from this repository into `rust-lang/rust`
NOTE: If you use Git protocol to push to your fork of `rust-lang/rust`,
ensure that you have this entry in your Git config,
else the 2 steps that follow would prompt for a username and password:
```
[url "git@github.com:"]
insteadOf = "https://github.com/"
```
1) Run the push command to create a branch named `<branch-name>` in a `rustc` fork under the `<gh-username>` account 1) Run the push command to create a branch named `<branch-name>` in a `rustc` fork under the `<gh-username>` account
``` ```
cargo run --manifest-path josh-sync/Cargo.toml rustc-push <branch-name> <gh-username> cargo run --manifest-path josh-sync/Cargo.toml rustc-push <branch-name> <gh-username>

207
ci/date-check/Cargo.lock generated
View File

@ -1,6 +1,6 @@
# This file is automatically @generated by Cargo. # This file is automatically @generated by Cargo.
# It is not intended for manual editing. # It is not intended for manual editing.
version = 3 version = 4
[[package]] [[package]]
name = "aho-corasick" name = "aho-corasick"
@ -28,21 +28,24 @@ dependencies = [
[[package]] [[package]]
name = "autocfg" name = "autocfg"
version = "1.3.0" version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
[[package]] [[package]]
name = "bumpalo" name = "bumpalo"
version = "3.16.0" version = "3.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf"
[[package]] [[package]]
name = "cc" name = "cc"
version = "1.0.106" version = "1.2.22"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "066fce287b1d4eafef758e89e09d724a24808a9196fe9756b8ca90e86d0719a2" checksum = "32db95edf998450acc7881c932f94cd9b05c87b4b2599e8bab064753da4acfd1"
dependencies = [
"shlex",
]
[[package]] [[package]]
name = "cfg-if" name = "cfg-if"
@ -52,27 +55,27 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]] [[package]]
name = "chrono" name = "chrono"
version = "0.4.38" version = "0.4.41"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d"
dependencies = [ dependencies = [
"android-tzdata", "android-tzdata",
"iana-time-zone", "iana-time-zone",
"js-sys", "js-sys",
"num-traits", "num-traits",
"wasm-bindgen", "wasm-bindgen",
"windows-targets", "windows-link",
] ]
[[package]] [[package]]
name = "core-foundation-sys" name = "core-foundation-sys"
version = "0.8.6" version = "0.8.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
[[package]] [[package]]
name = "date-check" name = "date-check"
version = "0.1.0" version = "0.0.0"
dependencies = [ dependencies = [
"chrono", "chrono",
"glob", "glob",
@ -81,20 +84,21 @@ dependencies = [
[[package]] [[package]]
name = "glob" name = "glob"
version = "0.3.1" version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2"
[[package]] [[package]]
name = "iana-time-zone" name = "iana-time-zone"
version = "0.1.60" version = "0.1.63"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8"
dependencies = [ dependencies = [
"android_system_properties", "android_system_properties",
"core-foundation-sys", "core-foundation-sys",
"iana-time-zone-haiku", "iana-time-zone-haiku",
"js-sys", "js-sys",
"log",
"wasm-bindgen", "wasm-bindgen",
"windows-core", "windows-core",
] ]
@ -110,24 +114,25 @@ dependencies = [
[[package]] [[package]]
name = "js-sys" name = "js-sys"
version = "0.3.69" version = "0.3.77"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f"
dependencies = [ dependencies = [
"once_cell",
"wasm-bindgen", "wasm-bindgen",
] ]
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.155" version = "0.2.172"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa"
[[package]] [[package]]
name = "log" name = "log"
version = "0.4.22" version = "0.4.27"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
[[package]] [[package]]
name = "memchr" name = "memchr"
@ -146,33 +151,33 @@ dependencies = [
[[package]] [[package]]
name = "once_cell" name = "once_cell"
version = "1.19.0" version = "1.21.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.86" version = "1.0.95"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
dependencies = [ dependencies = [
"unicode-ident", "unicode-ident",
] ]
[[package]] [[package]]
name = "quote" name = "quote"
version = "1.0.36" version = "1.0.40"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
] ]
[[package]] [[package]]
name = "regex" name = "regex"
version = "1.10.5" version = "1.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f" checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
dependencies = [ dependencies = [
"aho-corasick", "aho-corasick",
"memchr", "memchr",
@ -182,9 +187,9 @@ dependencies = [
[[package]] [[package]]
name = "regex-automata" name = "regex-automata"
version = "0.4.7" version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908"
dependencies = [ dependencies = [
"aho-corasick", "aho-corasick",
"memchr", "memchr",
@ -193,15 +198,27 @@ dependencies = [
[[package]] [[package]]
name = "regex-syntax" name = "regex-syntax"
version = "0.8.4" version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
[[package]]
name = "rustversion"
version = "1.0.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2"
[[package]]
name = "shlex"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
[[package]] [[package]]
name = "syn" name = "syn"
version = "2.0.70" version = "2.0.101"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2f0209b68b3613b093e0ec905354eccaedcfe83b8cb37cbdeae64026c3064c16" checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -210,29 +227,30 @@ dependencies = [
[[package]] [[package]]
name = "unicode-ident" name = "unicode-ident"
version = "1.0.12" version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
[[package]] [[package]]
name = "wasm-bindgen" name = "wasm-bindgen"
version = "0.2.92" version = "0.2.100"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"once_cell",
"rustversion",
"wasm-bindgen-macro", "wasm-bindgen-macro",
] ]
[[package]] [[package]]
name = "wasm-bindgen-backend" name = "wasm-bindgen-backend"
version = "0.2.92" version = "0.2.100"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6"
dependencies = [ dependencies = [
"bumpalo", "bumpalo",
"log", "log",
"once_cell",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn",
@ -241,9 +259,9 @@ dependencies = [
[[package]] [[package]]
name = "wasm-bindgen-macro" name = "wasm-bindgen-macro"
version = "0.2.92" version = "0.2.100"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407"
dependencies = [ dependencies = [
"quote", "quote",
"wasm-bindgen-macro-support", "wasm-bindgen-macro-support",
@ -251,9 +269,9 @@ dependencies = [
[[package]] [[package]]
name = "wasm-bindgen-macro-support" name = "wasm-bindgen-macro-support"
version = "0.2.92" version = "0.2.100"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -264,79 +282,68 @@ dependencies = [
[[package]] [[package]]
name = "wasm-bindgen-shared" name = "wasm-bindgen-shared"
version = "0.2.92" version = "0.2.100"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d"
dependencies = [
"unicode-ident",
]
[[package]] [[package]]
name = "windows-core" name = "windows-core"
version = "0.52.0" version = "0.61.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" checksum = "4763c1de310c86d75a878046489e2e5ba02c649d185f21c67d4cf8a56d098980"
dependencies = [ dependencies = [
"windows-targets", "windows-implement",
"windows-interface",
"windows-link",
"windows-result",
"windows-strings",
] ]
[[package]] [[package]]
name = "windows-targets" name = "windows-implement"
version = "0.52.6" version = "0.60.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836"
dependencies = [ dependencies = [
"windows_aarch64_gnullvm", "proc-macro2",
"windows_aarch64_msvc", "quote",
"windows_i686_gnu", "syn",
"windows_i686_gnullvm",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
] ]
[[package]] [[package]]
name = "windows_aarch64_gnullvm" name = "windows-interface"
version = "0.52.6" version = "0.59.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]] [[package]]
name = "windows_aarch64_msvc" name = "windows-link"
version = "0.52.6" version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38"
[[package]] [[package]]
name = "windows_i686_gnu" name = "windows-result"
version = "0.52.6" version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" checksum = "c64fd11a4fd95df68efcfee5f44a294fe71b8bc6a91993e2791938abcc712252"
dependencies = [
"windows-link",
]
[[package]] [[package]]
name = "windows_i686_gnullvm" name = "windows-strings"
version = "0.52.6" version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" checksum = "7a2ba9642430ee452d5a7aa78d72907ebe8cfda358e8cb7918a2050581322f97"
dependencies = [
[[package]] "windows-link",
name = "windows_i686_msvc" ]
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"

View File

@ -1,10 +1,6 @@
[package] [package]
name = "date-check" name = "date-check"
version = "0.1.0" edition = "2024"
authors = ["Noah Lev <camelidcamel@gmail.com>"]
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
glob = "0.3" glob = "0.3"

View File

@ -114,7 +114,7 @@ fn filter_dates(
fn main() { fn main() {
let mut args = env::args(); let mut args = env::args();
if args.len() == 1 { if args.len() == 1 {
eprintln!("error: expected root Markdown directory as CLI argument"); eprintln!("error: expected root of Markdown directory as CLI argument");
process::exit(1); process::exit(1);
} }
let root_dir = args.nth(1).unwrap(); let root_dir = args.nth(1).unwrap();

2
josh-sync/Cargo.lock generated
View File

@ -161,7 +161,7 @@ checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
[[package]] [[package]]
name = "josh-sync" name = "josh-sync"
version = "0.1.0" version = "0.0.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"clap", "clap",

View File

@ -1,7 +1,6 @@
[package] [package]
name = "josh-sync" name = "josh-sync"
version = "0.1.0" edition = "2024"
edition = "2021"
[dependencies] [dependencies]
anyhow = "1.0.95" anyhow = "1.0.95"

View File

@ -1,4 +1,5 @@
use clap::Parser; use clap::Parser;
use crate::sync::{GitSync, RustcPullError}; use crate::sync::{GitSync, RustcPullError};
mod sync; mod sync;
@ -11,10 +12,7 @@ enum Args {
/// Push changes from `rustc-dev-guide` to the given `branch` of a `rustc` fork under the given /// Push changes from `rustc-dev-guide` to the given `branch` of a `rustc` fork under the given
/// GitHub `username`. /// GitHub `username`.
/// The pushed branch should then be merged into the `rustc` repository. /// The pushed branch should then be merged into the `rustc` repository.
RustcPush { RustcPush { branch: String, github_username: String },
branch: String,
github_username: String
}
} }
fn main() -> anyhow::Result<()> { fn main() -> anyhow::Result<()> {

View File

@ -1,10 +1,11 @@
use std::io::Write;
use std::ops::Not; use std::ops::Not;
use std::path::PathBuf; use std::path::PathBuf;
use std::{env, net, process};
use std::io::Write;
use std::time::Duration; use std::time::Duration;
use anyhow::{anyhow, bail, Context}; use std::{env, net, process};
use xshell::{cmd, Shell};
use anyhow::{Context, anyhow, bail};
use xshell::{Shell, cmd};
/// Used for rustc syncs. /// Used for rustc syncs.
const JOSH_FILTER: &str = ":/src/doc/rustc-dev-guide"; const JOSH_FILTER: &str = ":/src/doc/rustc-dev-guide";
@ -15,10 +16,13 @@ pub enum RustcPullError {
/// No changes are available to be pulled. /// No changes are available to be pulled.
NothingToPull, NothingToPull,
/// A rustc-pull has failed, probably a git operation error has occurred. /// A rustc-pull has failed, probably a git operation error has occurred.
PullFailed(anyhow::Error) PullFailed(anyhow::Error),
} }
impl<E> From<E> for RustcPullError where E: Into<anyhow::Error> { impl<E> From<E> for RustcPullError
where
E: Into<anyhow::Error>,
{
fn from(error: E) -> Self { fn from(error: E) -> Self {
Self::PullFailed(error.into()) Self::PullFailed(error.into())
} }
@ -32,9 +36,7 @@ pub struct GitSync {
/// (https://github.com/rust-lang/miri/blob/6a68a79f38064c3bc30617cca4bdbfb2c336b140/miri-script/src/commands.rs#L236). /// (https://github.com/rust-lang/miri/blob/6a68a79f38064c3bc30617cca4bdbfb2c336b140/miri-script/src/commands.rs#L236).
impl GitSync { impl GitSync {
pub fn from_current_dir() -> anyhow::Result<Self> { pub fn from_current_dir() -> anyhow::Result<Self> {
Ok(Self { Ok(Self { dir: std::env::current_dir()? })
dir: std::env::current_dir()?
})
} }
pub fn rustc_pull(&self, commit: Option<String>) -> Result<(), RustcPullError> { pub fn rustc_pull(&self, commit: Option<String>) -> Result<(), RustcPullError> {
@ -51,7 +53,10 @@ impl GitSync {
})?; })?;
// Make sure the repo is clean. // Make sure the repo is clean.
if cmd!(sh, "git status --untracked-files=no --porcelain").read()?.is_empty().not() { if cmd!(sh, "git status --untracked-files=no --porcelain").read()?.is_empty().not() {
return Err(anyhow::anyhow!("working directory must be clean before performing rustc pull").into()); return Err(anyhow::anyhow!(
"working directory must be clean before performing rustc pull"
)
.into());
} }
// Make sure josh is running. // Make sure josh is running.
let josh = Self::start_josh()?; let josh = Self::start_josh()?;
@ -94,7 +99,8 @@ impl GitSync {
}; };
let num_roots_before = num_roots()?; let num_roots_before = num_roots()?;
let sha = cmd!(sh, "git rev-parse HEAD").output().context("FAILED to get current commit")?.stdout; let sha =
cmd!(sh, "git rev-parse HEAD").output().context("FAILED to get current commit")?.stdout;
// Merge the fetched commit. // Merge the fetched commit.
const MERGE_COMMIT_MESSAGE: &str = "Merge from rustc"; const MERGE_COMMIT_MESSAGE: &str = "Merge from rustc";
@ -102,18 +108,24 @@ impl GitSync {
.run() .run()
.context("FAILED to merge new commits, something went wrong")?; .context("FAILED to merge new commits, something went wrong")?;
let current_sha = cmd!(sh, "git rev-parse HEAD").output().context("FAILED to get current commit")?.stdout; let current_sha =
cmd!(sh, "git rev-parse HEAD").output().context("FAILED to get current commit")?.stdout;
if current_sha == sha { if current_sha == sha {
cmd!(sh, "git reset --hard HEAD^") cmd!(sh, "git reset --hard HEAD^")
.run() .run()
.expect("FAILED to clean up after creating the preparation commit"); .expect("FAILED to clean up after creating the preparation commit");
eprintln!("No merge was performed, no changes to pull were found. Rolled back the preparation commit."); eprintln!(
"No merge was performed, no changes to pull were found. Rolled back the preparation commit."
);
return Err(RustcPullError::NothingToPull); return Err(RustcPullError::NothingToPull);
} }
// Check that the number of roots did not increase. // Check that the number of roots did not increase.
if num_roots()? != num_roots_before { if num_roots()? != num_roots_before {
return Err(anyhow::anyhow!("Josh created a new root commit. This is probably not the history you want.").into()); return Err(anyhow::anyhow!(
"Josh created a new root commit. This is probably not the history you want."
)
.into());
} }
drop(josh); drop(josh);
@ -194,7 +206,7 @@ impl GitSync {
); );
println!( println!(
// Open PR with `subtree update` title to silence the `no-merges` triagebot check // Open PR with `subtree update` title to silence the `no-merges` triagebot check
" https://github.com/{UPSTREAM_REPO}/compare/{github_user}:{branch}?quick_pull=1&title=Rustc+dev+guide+subtree+update&body=r?+@ghost" " https://github.com/{UPSTREAM_REPO}/compare/{github_user}:{branch}?quick_pull=1&title=rustc-dev-guide+subtree+update&body=r?+@ghost"
); );
drop(josh); drop(josh);

View File

@ -1 +1 @@
deb947971c8748f5c6203548ce4af9022f21eaf0 414482f6a0d4e7290f614300581a0b55442552a3

View File

@ -157,6 +157,7 @@
- [ADTs and Generic Arguments](./ty_module/generic_arguments.md) - [ADTs and Generic Arguments](./ty_module/generic_arguments.md)
- [Parameter types/consts/regions](./ty_module/param_ty_const_regions.md) - [Parameter types/consts/regions](./ty_module/param_ty_const_regions.md)
- [`TypeFolder` and `TypeFoldable`](./ty-fold.md) - [`TypeFolder` and `TypeFoldable`](./ty-fold.md)
- [Aliases and Normalization](./normalization.md)
- [Typing/Param Envs](./typing_parameter_envs.md) - [Typing/Param Envs](./typing_parameter_envs.md)
- [Type inference](./type-inference.md) - [Type inference](./type-inference.md)
- [Trait solving](./traits/resolution.md) - [Trait solving](./traits/resolution.md)
@ -176,7 +177,6 @@
- [Coinduction](./solve/coinduction.md) - [Coinduction](./solve/coinduction.md)
- [Caching](./solve/caching.md) - [Caching](./solve/caching.md)
- [Proof trees](./solve/proof-trees.md) - [Proof trees](./solve/proof-trees.md)
- [Normalization](./solve/normalization.md)
- [Opaque types](./solve/opaque-types.md) - [Opaque types](./solve/opaque-types.md)
- [Significant changes and quirks](./solve/significant-changes.md) - [Significant changes and quirks](./solve/significant-changes.md)
- [`Unsize` and `CoerceUnsized` traits](./traits/unsize.md) - [`Unsize` and `CoerceUnsized` traits](./traits/unsize.md)

View File

@ -1,6 +1,6 @@
# Installation # Installation
In the near future, `std::autodiff` should become available in nightly builds for users. As a contribute however, you will still need to build rustc from source. Please be aware that the msvc target is not supported at the moment, all other tier 1 targets should work. Please open an issue if you encounter any problems on a supported tier 1 target, or if you succesfully build this project on a tier2/tier3 target. In the near future, `std::autodiff` should become available in nightly builds for users. As a contributor however, you will still need to build rustc from source. Please be aware that the msvc target is not supported at the moment, all other tier 1 targets should work. Please open an issue if you encounter any problems on a supported tier 1 target, or if you successfully build this project on a tier2/tier3 target.
## Build instructions ## Build instructions

View File

@ -80,41 +80,11 @@ approachable and practical; it may make sense to direct users to an RFC or some
other issue for the full details. The issue also serves as a place where users other issue for the full details. The issue also serves as a place where users
can comment with questions or other concerns. can comment with questions or other concerns.
A template for these breaking-change tracking issues can be found below. An A template for these breaking-change tracking issues can be found
example of how such an issue should look can be [found [here][template]. An example of how such an issue should look can be [found
here][breaking-change-issue]. here][breaking-change-issue].
The issue should be tagged with (at least) `B-unstable` and `T-compiler`. [template]: https://github.com/rust-lang/rust/issues/new?template=tracking_issue_future.md
### Tracking issue template
This is a template to use for tracking issues:
```
This is the **summary issue** for the `YOUR_LINT_NAME_HERE`
future-compatibility warning and other related errors. The goal of
this page is describe why this change was made and how you can fix
code that is affected by it. It also provides a place to ask questions
or register a complaint if you feel the change should not be made. For
more information on the policy around future-compatibility warnings,
see our [breaking change policy guidelines][guidelines].
[guidelines]: LINK_TO_THIS_RFC
#### What is the warning for?
*Describe the conditions that trigger the warning and how they can be
fixed. Also explain why the change was made.**
#### When will this warning become a hard error?
At the beginning of each 6-week release cycle, the Rust compiler team
will review the set of outstanding future compatibility warnings and
nominate some of them for **Final Comment Period**. Toward the end of
the cycle, we will review any comments and make a final determination
whether to convert the warning into a hard error or remove it
entirely.
```
### Issuing future compatibility warnings ### Issuing future compatibility warnings

View File

@ -6,8 +6,8 @@ of the same compiler.
This raises a chicken-and-egg paradox: where did the first compiler come from? This raises a chicken-and-egg paradox: where did the first compiler come from?
It must have been written in a different language. In Rust's case it was It must have been written in a different language. In Rust's case it was
[written in OCaml][ocaml-compiler]. However it was abandoned long ago and the [written in OCaml][ocaml-compiler]. However, it was abandoned long ago, and the
only way to build a modern version of rustc is a slightly less modern only way to build a modern version of rustc is with a slightly less modern
version. version.
This is exactly how `x.py` works: it downloads the current beta release of This is exactly how `x.py` works: it downloads the current beta release of

View File

@ -8,8 +8,8 @@ the same compiler.
This raises a chicken-and-egg paradox: where did the first compiler come from? This raises a chicken-and-egg paradox: where did the first compiler come from?
It must have been written in a different language. In Rust's case it was It must have been written in a different language. In Rust's case it was
[written in OCaml][ocaml-compiler]. However it was abandoned long ago and the [written in OCaml][ocaml-compiler]. However, it was abandoned long ago, and the
only way to build a modern version of `rustc` is a slightly less modern version. only way to build a modern version of `rustc` is with a slightly less modern version.
This is exactly how [`./x.py`] works: it downloads the current beta release of This is exactly how [`./x.py`] works: it downloads the current beta release of
`rustc`, then uses it to compile the new compiler. `rustc`, then uses it to compile the new compiler.

View File

@ -62,21 +62,20 @@ huge. There is also the `rustc` crate which is the actual binary (i.e. the
[`rustc_driver`] crate, which drives the various parts of compilation in other [`rustc_driver`] crate, which drives the various parts of compilation in other
crates. crates.
The dependency structure of these crates is complex, but roughly it is The dependency order of these crates is complex, but roughly it is
something like this: something like this:
- `rustc` (the binary) calls [`rustc_driver::main`][main]. 1. `rustc` (the binary) calls [`rustc_driver::main`][main].
- [`rustc_driver`] depends on a lot of other crates, but the main one is 1. [`rustc_driver`] depends on a lot of other crates, but the main one is
[`rustc_interface`]. [`rustc_interface`].
- [`rustc_interface`] depends on most of the other compiler crates. It 1. [`rustc_interface`] depends on most of the other compiler crates. It is a
is a fairly generic interface for driving the whole compilation. fairly generic interface for driving the whole compilation.
- Most of the other `rustc_*` crates depend on [`rustc_middle`], 1. Most of the other `rustc_*` crates depend on [`rustc_middle`], which defines
which defines a lot of central data structures in the compiler. a lot of central data structures in the compiler.
- [`rustc_middle`] and most of the other crates depend on a 1. [`rustc_middle`] and most of the other crates depend on a handful of crates
handful of crates representing the early parts of the representing the early parts of the compiler (e.g. the parser), fundamental
compiler (e.g. the parser), fundamental data structures (e.g. data structures (e.g. [`Span`]), or error reporting:
[`Span`]), or error reporting: [`rustc_data_structures`], [`rustc_data_structures`], [`rustc_span`], [`rustc_errors`], etc.
[`rustc_span`], [`rustc_errors`], etc.
[`rustc_data_structures`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_data_structures/index.html [`rustc_data_structures`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_data_structures/index.html
[`rustc_driver`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_driver/index.html [`rustc_driver`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_driver/index.html
@ -87,8 +86,12 @@ something like this:
[`Span`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_span/struct.Span.html [`Span`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_span/struct.Span.html
[main]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_driver/fn.main.html [main]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_driver/fn.main.html
You can see the exact dependencies by reading the [`Cargo.toml`] for the various You can see the exact dependencies by running `cargo tree`,
crates, just like a normal Rust crate. just like you would for any other Rust package:
```console
cargo tree --package rustc_driver
```
One final thing: [`src/llvm-project`] is a submodule for our fork of LLVM. One final thing: [`src/llvm-project`] is a submodule for our fork of LLVM.
During bootstrapping, LLVM is built and the [`compiler/rustc_llvm`] crate During bootstrapping, LLVM is built and the [`compiler/rustc_llvm`] crate

View File

@ -193,6 +193,23 @@ When a user runs `cargo fix --edition`, cargo will pass the `--force-warn rust-2
flag to force all of these lints to appear during the edition migration. flag to force all of these lints to appear during the edition migration.
Cargo also passes `--cap-lints=allow` so that no other lints interfere with the edition migration. Cargo also passes `--cap-lints=allow` so that no other lints interfere with the edition migration.
Make sure that the example code sets the correct edition. The example should illustrate the previous edition, and show what the migration warning would look like. For example, this lint for a 2024 migration shows an example in 2021:
```rust,ignore
declare_lint! {
/// The `keyword_idents_2024` lint detects ...
///
/// ### Example
///
/// ```rust,edition2021
/// #![warn(keyword_idents_2024)]
/// fn gen() {}
/// ```
///
/// {{produces}}
}
```
Migration lints can be either `Allow` or `Warn` by default. Migration lints can be either `Allow` or `Warn` by default.
If it is `Allow`, users usually won't see this warning unless they are doing an edition migration If it is `Allow`, users usually won't see this warning unless they are doing an edition migration
manually or there is a problem during the migration. manually or there is a problem during the migration.
@ -334,3 +351,40 @@ In general it is recommended to avoid these special cases except for very high v
[into-iter]: https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html [into-iter]: https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html
[panic-macro]: https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html [panic-macro]: https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html
[`non_fmt_panics`]: https://doc.rust-lang.org/nightly/rustc/lints/listing/warn-by-default.html#non-fmt-panics [`non_fmt_panics`]: https://doc.rust-lang.org/nightly/rustc/lints/listing/warn-by-default.html#non-fmt-panics
### Migrating the standard library edition
Updating the edition of the standard library itself roughly involves the following process:
- Wait until the newly stabilized edition has reached beta and the bootstrap compiler has been updated.
- Apply migration lints. This can be an involved process since some code is in external submodules[^std-submodules], and the standard library makes heavy use of conditional compilation. Also, running `cargo fix --edition` can be impractical on the standard library itself. One approach is to individually add `#![warn(...)]` at the top of each crate for each lint, run `./x check library`, apply the migrations, remove the `#![warn(...)]` and commit each migration separately. You'll likely need to run `./x check` with `--target` for many different targets to get full coverage (otherwise you'll likely spend days or weeks getting CI to pass)[^ed-docker]. See also the [advanced migration guide] for more tips.
- Apply migrations to [`backtrace-rs`]. [Example for 2024](https://github.com/rust-lang/backtrace-rs/pull/700). Note that this doesn't update the edition of the crate itself because that is published independently on crates.io, and that would otherwise restrict the minimum Rust version. Consider adding some `#![deny()]` attributes to avoid regressions until its edition gets updated.
- Apply migrations to [`stdarch`], and update its edition, and formatting. [Example for 2024](https://github.com/rust-lang/stdarch/pull/1710).
- Post PRs to update the backtrace and stdarch submodules, and wait for those to land.
- Apply migration lints to the standard library crates, and update their edition. I recommend working one crate at a time starting with `core`. [Example for 2024](https://github.com/rust-lang/rust/pull/138162).
[^std-submodules]: This will hopefully change in the future to pull these submodules into `rust-lang/rust`.
[^ed-docker]: You'll also likely need to do a lot of testing for different targets, and this is where [docker testing](../tests/docker.md) comes in handy.
[advanced migration guide]: https://doc.rust-lang.org/nightly/edition-guide/editions/advanced-migrations.html
[`backtrace-rs`]: https://github.com/rust-lang/backtrace-rs/
[`stdarch`]: https://github.com/rust-lang/stdarch/
## Stabilizing an edition
After the edition team has given the go-ahead, the process for stabilizing an edition is roughly:
- Update [`LATEST_STABLE_EDITION`].
- Update [`Edition::is_stable`].
- Hunt and find any document that refers to edition by number, and update it:
- [`--edition` flag](https://github.com/rust-lang/rust/blob/master/src/doc/rustc/src/command-line-arguments.md#--edition-specify-the-edition-to-use)
- [Rustdoc attributes](https://github.com/rust-lang/rust/blob/master/src/doc/rustdoc/src/write-documentation/documentation-tests.md#attributes)
- Clean up any tests that use the `//@ edition` header to remove the `-Zunstable-options` flag to ensure they are indeed stable. Note: Ideally this should be automated, see [#133582].
- Bless any tests that change.
- Update `lint-docs` to default to the new edition.
See [example for 2024](https://github.com/rust-lang/rust/pull/133349).
[`LATEST_STABLE_EDITION`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_span/edition/constant.LATEST_STABLE_EDITION.html
[`Edition::is_stable`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_span/edition/enum.Edition.html#method.is_stable
[#133582]: https://github.com/rust-lang/rust/issues/133582

View File

@ -2,9 +2,6 @@
<!-- toc --> <!-- toc -->
> N.B. [`rustc_ast`], [`rustc_expand`], and [`rustc_builtin_macros`] are all
> undergoing refactoring, so some of the links in this chapter may be broken.
Rust has a very powerful macro system. In the previous chapter, we saw how Rust has a very powerful macro system. In the previous chapter, we saw how
the parser sets aside macros to be expanded (using temporary [placeholders]). the parser sets aside macros to be expanded (using temporary [placeholders]).
This chapter is about the process of expanding those macros iteratively until This chapter is about the process of expanding those macros iteratively until
@ -12,9 +9,6 @@ we have a complete [*Abstract Syntax Tree* (AST)][ast] for our crate with no
unexpanded macros (or a compile error). unexpanded macros (or a compile error).
[ast]: ./ast-validation.md [ast]: ./ast-validation.md
[`rustc_ast`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_ast/index.html
[`rustc_expand`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_expand/index.html
[`rustc_builtin_macros`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_builtin_macros/index.html
[placeholders]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_expand/placeholders/index.html [placeholders]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_expand/placeholders/index.html
First, we discuss the algorithm that expands and integrates macro output into First, we discuss the algorithm that expands and integrates macro output into

View File

@ -148,8 +148,7 @@ whereas this code uses [`ResultsCursor`]:
```rust,ignore ```rust,ignore
let mut results = MyAnalysis::new() let mut results = MyAnalysis::new()
.into_engine(tcx, body, def_id) .iterate_to_fixpoint(tcx, body, None);
.iterate_to_fixpoint()
.into_results_cursor(body); .into_results_cursor(body);
// Inspect the fixpoint state immediately before each `Drop` terminator. // Inspect the fixpoint state immediately before each `Drop` terminator.

309
src/normalization.md Normal file
View File

@ -0,0 +1,309 @@
# Aliases and Normalization
<!-- toc -->
## Aliases
In Rust there are a number of types that are considered equal to some "underlying" type, for example inherent associated types, trait associated types, free type aliases (`type Foo = u32`), and opaque types (`-> impl RPIT`). We consider such types to be "aliases", alias types are represented by the [`TyKind::Alias`][tykind_alias] variant, with the kind of alias tracked by the [`AliasTyKind`][aliaskind] enum.
Normalization is the process of taking these alias types and replacing them with the underlying type that they are equal to. For example given some type alias `type Foo = u32`, normalizing `Foo` would give `u32`.
The concept of an alias is not unique to *types* and the concept also applies to constants/const generics. However, right now in the compiler we don't really treat const aliases as a "first class concept" so this chapter mostly discusses things in the context of types (even though the concepts transfer just fine).
[tykind_alias]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_type_ir/enum.TyKind.html#variant.Alias
[aliaskind]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_type_ir/enum.AliasTyKind.html
### Rigid, Ambiguous and Unnormalized Aliases
Aliases can either be "rigid", "ambiguous", or simply unnormalized.
We consider types to be rigid if their "shape" isn't going to change, for example `Box` is rigid as no amount of normalization can turn a `Box` into a `u32`, whereas `<vec::IntoIter<u32> as Iterator>::Item` is not rigid as it can be normalized to `u32`.
Aliases are rigid when we will never be able to normalize them further. A concrete example of a *rigid* alias would be `<T as Iterator>::Item` in an environment where there is no `T: Iterator<Item = ...>` bound, only a `T: Iterator` bound:
```rust
fn foo<T: Iterator>() {
// This alias is *rigid*
let _: <T as Iterator>::Item;
}
fn bar<T: Iterator<Item = u32>>() {
// This alias is *not* rigid as it can be normalized to `u32`
let _: <T as Iterator>::Item;
}
```
When an alias can't yet be normalized but may wind up normalizable in the [current environment](./typing_parameter_envs.md), we consider it to be an "ambiguous" alias. This can occur when an alias contains inference variables which prevent being able to determine how the trait is implemented:
```rust
fn foo<T: Iterator, U: Iterator>() {
// This alias is considered to be "ambiguous"
let _: <_ as Iterator>::Item;
}
```
The reason we call them "ambiguous" aliases is because its *ambiguous* whether this is a rigid alias or not.
The source of the `_: Iterator` trait impl is *ambiguous* (i.e. unknown), it could be some `impl Iterator for u32` or it could be some `T: Iterator` trait bound, we don't know yet. Depending on why `_: Iterator` holds the alias could be an unnormalized alias or it could be a rigid alias; it's *ambiguous* what kind of alias this is.
Finally, an alias can just be unnormalized, `<Vec<u32> as IntoIterator>::Iter` is an unnormalized alias as it can already be normalized to `std::vec::IntoIter<u32>`, it just hasn't been done yet.
---
It is worth noting that Free and Inherent aliases cannot be rigid or ambiguous as naming them also implies having resolved the definition of the alias, which specifies the underlying type of the alias.
### Diverging Aliases
An alias is considered to "diverge" if its definition does not specify an underlying non-alias type to normalize to. A concrete example of diverging aliases:
```rust
type Diverges = Diverges;
trait Trait {
type DivergingAssoc;
}
impl Trait for () {
type DivergingAssoc = <() as Trait>::DivergingAssoc;
}
```
In this example both `Diverges` and `DivergingAssoc` are "trivial" cases of diverging type aliases where they have been defined as being equal to themselves. There is no underlying type that `Diverges` can ever be normalized to.
We generally try to error when diverging aliases are defined, but this is entirely a "best effort" check. In the previous example the definitions are "simple enough" to be detected and so errors are emitted. However, in more complex cases, or cases where only some instantiations of generic parameters would result in a diverging alias, we don't emit an error:
```rust
trait Trait {
type DivergingAssoc<U: Trait>;
}
impl<T: ?Sized> Trait for T {
// This alias always diverges but we don't emit an error because
// the compiler can't "see" that.
type DivergingAssoc<U: Trait> = <U as Trait>::DivergingAssoc<U>;
}
```
Ultimately this means that we have no guarantee that aliases in the type system are non-diverging. As aliases may only diverge for some specific generic arguments, it also means that we only know whether an alias diverges once it is fully concrete. This means that codegen/const-evaluation also has to handle diverging aliases:
```rust
trait Trait {
type Diverges<U: Trait>;
}
impl<T: ?Sized> Trait for T {
type Diverges<U: Trait> = <U as Trait>::Diverges<U>;
}
fn foo<T: Trait>() {
let a: T::Diverges<T>;
}
fn main() {
foo::<()>();
}
```
In this example we only encounter an error from the diverging alias during codegen of `foo::<()>`, if the call to `foo` is removed then no compilation error will be emitted.
### Opaque Types
Opaque types are a relatively special kind of alias, and are covered in their own chapter: [Opaque types](./opaque-types-type-alias-impl-trait.md).
### Const Aliases
Unlike type aliases, const aliases are not represented directly in the type system, instead const aliases are always an anonymous body containing a path expression to a const item. This means that the only "const alias" in the type system is an anonymous unevaluated const body.
As such there is no `ConstKind::Alias(AliasCtKind::Projection/Inherent/Free, _)`, instead we only have `ConstKind::Unevaluated` which is used for representing anonymous constants.
```rust
fn foo<const N: usize>() {}
const FREE_CONST: usize = 1 + 1;
fn bar() {
foo::<{ FREE_CONST }>();
// The const arg is represented with some anonymous constant:
// ```pseudo-rust
// const ANON: usize = FREE_CONST;
// foo::<ConstKind::Unevaluated(DefId(ANON), [])>();
// ```
}
```
This is likely to change as const generics functionality is improved, for example `feature(associated_const_equality)` and `feature(min_generic_const_args)` both require handling const aliases similarly to types (without an anonymous constant wrapping all const args).
## What is Normalization
### Structural vs Deep normalization
There are two forms of normalization, structural (sometimes called *shallow*) and deep. Structural normalization should be thought of as only normalizing the "outermost" part of a type. On the other hand deep normalization will normalize *all* aliases in a type.
In practice structural normalization can result in more than just the outer layer of the type being normalized, but this behaviour should not be relied upon. Unnormalizable non-rigid aliases making use of bound variables (`for<'a>`) cannot be normalized by either kind of normalization.
As an example: conceptually, structurally normalizing the type `Vec<<u8 as Identity>::Assoc>` would be a no-op, whereas deeply normalizing would give `Vec<u8>`. In practice even structural normalization would give `Vec<u8>`, though, again, this should not be relied upon.
Changing the alias to use bound variables will result in different behaviour; `Vec<for<'a> fn(<&'a u8 as Identity>::Assoc)>` would result in no change when structurally normalized, but would result in `Vec<for<'a> fn(&'a u8)>` when deeply normalized.
### Core normalization logic
Structurally normalizing aliases is a little bit more nuanced than replacing the alias with whatever it is defined as being equal to in its definition; the result of normalizing an alias should either be a rigid type or an inference variable (which will later be inferred to a rigid type). To accomplish this we do two things:
First, when normalizing an ambiguous alias it is normalized to an inference variable instead of leaving it as-is, this has two main effects:
- Even though an inference variable is not a rigid type, it will always wind up inferred *to* a rigid type so we ensure that the result of normalization will not need to be normalized again
- Inference variables are used in all cases where a type is non-rigid, allowing the rest of the compiler to not have to deal with *both* ambiguous aliases *and* inference variables
Secondly, instead of having normalization directly return the type specified in the definition of the alias, we normalize the type first before returning it[^1]. We do this so that normalization is idempotent/callers do not need to run it in a loop.
```rust
#![feature(lazy_type_alias)]
type Foo<T: Iterator> = Bar<T>;
type Bar<T: Iterator> = <T as Iterator>::Item;
fn foo() {
let a_: Foo<_>;
}
```
In this example:
- Normalizing `Foo<?x>` would result in `Bar<?x>`, except we want to normalize aliases in the type `Foo` is defined as equal to
- Normalizing `Bar<?x>` would result in `<?x as Iterator>::Item`, except, again, we want to normalize aliases in the type `Bar` is defined as equal to
- Normalizing `<?x as Iterator>::Item` results in some new inference variable `?y`, as `<?x as Iterator>::Item` is an ambiguous alias
- The final result is that normalizing `Foo<?x>` results in `?y`
## How to normalize
When interfacing with the type system it will often be the case that it's necessary to request a type be normalized. There are a number of different entry points to the underlying normalization logic and each entry point should only be used in specific parts of the compiler.
An additional complication is that the compiler is currently undergoing a transition from the old trait solver to the new trait solver. As part of this transition our approach to normalization in the compiler has changed somewhat significantly, resulting in some normalization entry points being "old solver only" slated for removal in the long-term once the new solver has stabilized.
Here is a rough overview of the different entry points to normalization in the compiler:
- `infcx.at.structurally_normalize`
- `infcx.at.(deeply_)?normalize`
- `infcx.query_normalize`
- `tcx.normalize_erasing_regions`
- `traits::normalize_with_depth(_to)`
- `EvalCtxt::structurally_normalize`
### Outside of the trait solver
The [`InferCtxt`][infcx] type exposes the "main" ways to normalize during analysis: [`normalize`][normalize], [`deeply_normalize`][deeply_normalize] and [`structurally_normalize`][structurally_normalize]. These functions are often wrapped and re-exposed on various `InferCtxt` wrapper types, such as [`FnCtxt`][fcx] or [`ObligationCtxt`][ocx] with minor API tweaks to handle some arguments or parts of the return type automatically.
#### Structural `InferCtxt` normalization
[`infcx.at.structurally_normalize`][structurally_normalize] exposes structural normalization that is able to handle inference variables and regions. It should generally be used whenever inspecting the kind of a type.
Inside of HIR Typeck there is a related method of normalization- [`fcx.structurally_resolve`][structurally_resolve], which will error if the type being resolved is an unresolved inference variable. When the new solver is enabled it will also attempt to structurally normalize the type.
Due to this there is a pattern in HIR typeck where a type is first normalized via `normalize` (only normalizing in the old solver), and then `structurally_resolve`'d (only normalizing in the new solver). This pattern should be preferred over calling `structurally_normalize` during HIR typeck as `structurally_resolve` will attempt to make inference progress by evaluating goals whereas `structurally_normalize` does not.
#### Deep `InferCtxt` normalization
##### `infcx.at.(deeply_)?normalize`
There are two ways to deeply normalize with an `InferCtxt`, `normalize` and `deeply_normalize`. The reason for this is that `normalize` is a "legacy" normalization entry point used only by the old solver, whereas `deeply_normalize` is intended to be the long term way to deeply normalize. Both of these methods can handle regions.
When the new solver is stabilized the `infcx.at.normalize` function will be removed and everything will have been migrated to the new deep or structural normalization methods. For this reason the `normalize` function is a no-op under the new solver, making it suitable only when the old solver needs normalization but the new solver does not.
Using `deeply_normalize` will result in errors being emitted when encountering ambiguous aliases[^2] as it is not possible to support normalizing *all* ambiguous aliases to inference variables[^3]. `deeply_normalize` should generally only be used in cases where we do not expect to encounter ambiguous aliases, for example when working with types from item signatures.
##### `infcx.query_normalize`
[`infcx.query_normalize`][query_norm] is very rarely used, it has almost all the same restrictions as `normalize_erasing_regions` (cannot handle inference variables, no diagnostics support) with the main difference being that it retains lifetime information. For this reason `normalize_erasing_regions` is the better choice in almost all circumstances as it is more efficient due to caching lifetime-erased queries.
In practice `query_normalize` is used for normalization in the borrow checker, and elsewhere as a performance optimization over `infcx.normalize`. Once the new solver is stabilized it is expected that `query_normalize` can be removed from the compiler as the new solvers normalization implementation should be performant enough for it to not be a performance regression.
##### `tcx.normalize_erasing_regions`
[`normalize_erasing_regions`][norm_erasing_regions] is generally used by parts of the compiler that are not doing type system analysis. This normalization entry point does not handle inference variables, lifetimes, or any diagnostics. Lints and codegen make heavy use of this entry point as they typically are working with fully inferred aliases that can be assumed to be well formed (or at least, are not responsible for erroring on).
[query_norm]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_trait_selection/infer/at/struct.At.html#method.query_normalize
[norm_erasing_regions]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyCtxt.html#method.normalize_erasing_regions
[normalize]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_trait_selection/infer/at/struct.At.html#method.normalize
[deeply_normalize]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_trait_selection/traits/normalize/trait.NormalizeExt.html#tymethod.deeply_normalize
[structurally_normalize]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_trait_selection/traits/trait.StructurallyNormalizeExt.html#tymethod.structurally_normalize_ty
[infcx]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_trait_selection/infer/struct.InferCtxt.html
[fcx]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir_typeck/fn_ctxt/struct.FnCtxt.html
[ocx]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_trait_selection/traits/struct.ObligationCtxt.html
[structurally_resolve]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir_typeck/fn_ctxt/struct.FnCtxt.html#method.structurally_resolve_type
### Inside of the trait solver
[`traits::normalize_with_depth(_to)`][norm_with_depth] and [`EvalCtxt::structurally_normalize`][eval_ctxt_structural_norm] are only used by the internals of the trait solvers (old and new respectively). It is effectively a raw entry point to the internals of how normalization is implemented by each trait solver. Other normalization entry points cannot be used from within the internals of trait solving as it wouldn't handle goal cycles and recursion depth correctly.
[norm_with_depth]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_trait_selection/traits/normalize/fn.normalize_with_depth.html
[eval_ctxt_structural_norm]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_next_trait_solver/solve/struct.EvalCtxt.html#method.structurally_normalize_term
## When/Where to normalize (Old vs New solver)
One of the big changes between the old and new solver is our approach to when we expect aliases to be normalized.
### Old solver
All types are expected to be normalized as soon as possible, so that all types encountered in the type system are either rigid or an inference variable (which will later be inferred to a rigid term).
As a concrete example: equality of aliases is implemented by assuming they're rigid and recursively equating the generic arguments of the alias.
### New solver
It's expected that all types potentially contain ambiguous or unnormalized aliases. Whenever an operation is performed that requires aliases to be normalized, it's the responsibility of that logic to normalize the alias (this means that matching on `ty.kind()` pretty much always has to structurally normalize first).
As a concrete example: equality of aliases is implemented by a custom goal kind ([`PredicateKind::AliasRelate`][aliasrelate]) so that it can handle normalization of the aliases itself instead of assuming all alias types being equated are rigid.
Despite this approach we still deeply normalize during [writeback][writeback] for performance/simplicity, so that types in the MIR can still be assumed to have been deeply normalized.
[aliasrelate]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/type.PredicateKind.html#variant.AliasRelate
[writeback]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir_typeck/writeback/index.html
---
There were a few main issues with the old solver's approach to normalization that motivated changing things in the new solver:
### Missing normalization calls
It was a frequent occurrence that normalization calls would be missing, resulting in passing unnormalized types to APIs expecting everything to already be normalized. Treating ambiguous or unnormalized aliases as rigid would result in all sorts of weird errors from aliases not being considered equal to one another, or surprising inference guidance from equating unnormalized aliases' generic arguments.
### Normalizing parameter environments
Another problem was that it was not possible to normalize `ParamEnv`s correctly in the old solver as normalization itself would expect a normalized `ParamEnv` in order to give correct results. See the chapter on `ParamEnv`s for more information: [`Typing/ParamEnv`s: Normalizing all bounds](./typing_parameter_envs.md#normalizing-all-bounds)
### Unnormalizable non-rigid aliases in higher ranked types
Given a type such as `for<'a> fn(<?x as Trait<'a>::Assoc>)`, it is not possible to correctly handle this with the old solver's approach to normalization.
If we were to normalize it to `for<'a> fn(?y)` and register a goal to normalize `for<'a> <?x as Trait<'a>>::Assoc -> ?y`, this would result in errors in cases where `<?x as Trait<'a>>::Assoc` normalized to `&'a u32`. The inference variable `?y` would be in a lower [universe][universes] than the placeholders made when instantiating the `for<'a>` binder.
Leaving the alias unnormalized would also be wrong as the old solver expects all aliases to be rigid. This was a soundness bug before the new solver was stabilized in coherence: [relating projection substs is unsound during coherence](https://github.com/rust-lang/rust/issues/102048).
Ultimately this means that it is not always possible to ensure all aliases inside of a value are rigid.
[universes]: https://rustc-dev-guide.rust-lang.org/borrow_check/region_inference/placeholders_and_universes.html#what-is-a-universe
[deeply_normalize]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_trait_selection/traits/normalize/trait.NormalizeExt.html#tymethod.deeply_normalize
## Handling uses of diverging aliases
Diverging aliases, like ambiguous aliases, are normalized to inference variables. As normalizing diverging aliases results in trait solver cycles, it always results in an error in the old solver. In the new solver it only results in an error if we wind up requiring all goals to hold in the current context. E.g. normalizing diverging aliases during HIR typeck will result in an error in both solvers.
Alias well formedness doesn't require that the alias doesn't diverge[^4], this means that checking an alias is well formed isn't sufficient to cause an error to be emitted for diverging aliases; actually attempting to normalize the alias is required.
Erroring on diverging aliases being a side effect of normalization means that it is very *arbitrary* whether we actually emit an error, it also differs between the old and new solver as we now normalize in less places.
An example of the ad-hoc nature of erroring on diverging aliases causing "problems":
```rust
trait Trait {
type Diverges<D: Trait>;
}
impl<T> Trait for T {
type Diverges<D: Trait> = D::Diverges<D>;
}
struct Bar<T: ?Sized = <u8 as Trait>::Diverges<u8>>(Box<T>);
```
In this example a diverging alias is used but we happen to not emit an error as we never explicitly normalize the defaults of generic parameters. If the `?Sized` opt out is removed then an error is emitted because we wind up happening to normalize a `<u8 as Trait>::Diverges<u8>: Sized` goal which as a side effect results in erroring about the diverging alias.
Const aliases differ from type aliases a bit here; well formedness of const aliases requires that they can be successfully evaluated (via [`ConstEvaluatable`][const_evaluatable] goals). This means that simply checking well formedness of const arguments is sufficient to error if they would fail to evaluate. It is somewhat unclear whether it would make sense to adopt this for type aliases too or if const aliases should stop requiring this for well formedness[^5].
[^1]: In the new solver this is done implicitly
[^2]: There is a subtle difference in how ambiguous aliases in binders are handled between old and new solver. In the old solver we fail to error on some ambiguous aliases inside of higher ranked types whereas the new solver correctly errors.
[^3]: Ambiguous aliases inside of binders cannot be normalized to inference variables, this will be covered more later.
[^4]: As checking aliases are non-diverging cannot be done until they are fully concrete, this would either imply that we cant check aliases are well formed before codegen/const-evaluation or that aliases would go from being well-formed to not well-formed after monomorphization.
[^5]: Const aliases certainly wouldn't be *less* sound than type aliases if we stopped doing this
[const_evaluatable]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/type.ClauseKind.html#variant.ConstEvaluatable

View File

@ -1,9 +1,9 @@
# Rust for Linux notification group # Rust for Linux notification group
**Github Label:** [O-rfl] <br> **Github Label:** [A-rust-for-linux] <br>
**Ping command:** `@rustbot ping rfl` **Ping command:** `@rustbot ping rfl`
[O-rfl]: https://github.com/rust-lang/rust/labels/O-rfl [A-rust-for-linux]: https://github.com/rust-lang/rust/labels/A-rust-for-linux
This list will be used to notify [Rust for Linux (RfL)][rfl] maintainers This list will be used to notify [Rust for Linux (RfL)][rfl] maintainers
when the compiler or the standard library changes in a way that would when the compiler or the standard library changes in a way that would

View File

@ -55,8 +55,8 @@ The first step in [`clean::utils::krate`][ck1] is to invoke
* inlining public `use` exports of private items, or showing a "Reexport" * inlining public `use` exports of private items, or showing a "Reexport"
line in the module page line in the module page
* inlining items with `#[doc(hidden)]` if the base item is hidden but the * inlining items with `#[doc(hidden)]` if the base item is hidden but the
* showing `#[macro_export]`-ed macros at the crate root, regardless of where * showing `#[macro_export]`-ed macros at the crate root, regardless of whether
they're defined reexport is not they're defined as a reexport or not
After this step, `clean::krate` invokes [`clean_doc_module`], which actually After this step, `clean::krate` invokes [`clean_doc_module`], which actually
converts the `HIR` items to the cleaned [`AST`][ast]. This is also the step where cross- converts the `HIR` items to the cleaned [`AST`][ast]. This is also the step where cross-

View File

@ -16,10 +16,10 @@ In addition to the directives listed here,
`rustdoc` tests also support most `rustdoc` tests also support most
[compiletest directives](../tests/directives.html). [compiletest directives](../tests/directives.html).
All `PATH`s in directives are relative to the the rustdoc output directory (`build/TARGET/test/rustdoc/TESTNAME`), All `PATH`s in directives are relative to the rustdoc output directory (`build/TARGET/test/rustdoc/TESTNAME`),
so it is conventional to use a `#![crate_name = "foo"]` attribute to avoid so it is conventional to use a `#![crate_name = "foo"]` attribute to avoid
having to write a long crate name multiple times. having to write a long crate name multiple times.
To avoid repetion, `-` can be used in any `PATH` argument to re-use the previous `PATH` argument. To avoid repetition, `-` can be used in any `PATH` argument to re-use the previous `PATH` argument.
All arguments take the form of quoted strings All arguments take the form of quoted strings
(both single and double quotes are supported), (both single and double quotes are supported),
@ -87,7 +87,7 @@ compiletest's `--bless` flag is forwarded to htmldocck.
Usage: `//@ has-dir PATH` Usage: `//@ has-dir PATH`
Checks for the existance of directory `PATH`. Checks for the existence of directory `PATH`.
### `files` ### `files`
@ -106,7 +106,7 @@ Example: `//@ files "foo/bar" '["index.html", "sidebar-items.js"]'`
## Limitations ## Limitations
`htmldocck.py` uses the xpath implementation from the standard library. `htmldocck.py` uses the xpath implementation from the standard library.
This leads to several limitations: This leads to several limitations:
* All `XPATH` arguments must start with `//` due to a flaw in the implemention. * All `XPATH` arguments must start with `//` due to a flaw in the implementation.
* Many XPath features (functions, axies, etc.) are not supported. * Many XPath features (functions, axies, etc.) are not supported.
* Only well-formed HTML can be parsed (hopefully rustdoc doesn't output mismatched tags). * Only well-formed HTML can be parsed (hopefully rustdoc doesn't output mismatched tags).

View File

@ -169,7 +169,7 @@ The `LazyArray<[T]>` and `LazyTable<I, T>` types provide some functionality over
than the one being read. than the one being read.
**note**: `LazyValue<T>` does not cache its value after being deserialized the **note**: `LazyValue<T>` does not cache its value after being deserialized the
first time. Instead the query system its self is the main way of caching these first time. Instead the query system itself is the main way of caching these
results. results.
[`LazyArray<T>`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_metadata/rmeta/struct.LazyValue.html [`LazyArray<T>`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_metadata/rmeta/struct.LazyValue.html

View File

@ -1,127 +0,0 @@
# Normalization in the new solver
> FIXME: Normalization has been changed significantly since this chapter was written.
With the new solver we've made some fairly significant changes to normalization when compared
to the existing implementation.
We now differentiate between "one-step normalization", "structural normalization" and
"deep normalization".
## One-step normalization
One-step normalization is implemented via `NormalizesTo` goals. Unlike other goals
in the trait solver, `NormalizesTo` always expects the term to be an unconstrained
inference variable[^opaques]. Think of it as a function, taking an alias as input
and returning its underlying value. If the alias is rigid, `NormalizesTo` fails and
returns `NoSolution`. This is the case for `<T as Trait>::Assoc` if there's a `T: Trait`
where-bound and for opaque types with `Reveal::UserFacing` unless they are in the
defining scope. We must not treat any aliases as rigid in coherence.
The underlying value may itself be an unnormalized alias, e.g.
`NormalizesTo(<<() as Id>::This as Id>::This)` only returns `<() as Id>::This`,
even though that alias can be further normalized to `()`. As the term is
always an unconstrained inference variable, the expected term cannot influence
normalization, see [trait-system-refactor-initiative#22] for more.
Only ever computing `NormalizesTo` goals with an unconstrained inference variable
requires special solver support. It is only used by `AliasRelate` goals and pending
`NormalizesTo` goals are tracked separately from other goals: [source][try-eval-norm].
As the expected term is always erased in `NormalizesTo`, we have to return its
ambiguous nested goals to its caller as not doing so weakens inference. See
[#122687] for more details.
[trait-system-refactor-initiative#22]: https://github.com/rust-lang/trait-system-refactor-initiative/issues/22
[try-eval-norm]: https://github.com/rust-lang/rust/blob/2627e9f3012a97d3136b3e11bf6bd0853c38a534/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs#L523-L537
[#122687]: https://github.com/rust-lang/rust/pull/122687
## `AliasRelate` and structural normalization
We structurally normalize an alias by applying one-step normalization until
we end up with a rigid alias, ambiguity, or overflow. This is done by repeatedly
evaluating `NormalizesTo` goals inside of a snapshot: [source][structural_norm].
`AliasRelate(lhs, rhs)` is implemented by first structurally normalizing both the
`lhs` and the `rhs` and then relating the resulting rigid types (or inference
variables). Importantly, if `lhs` or `rhs` ends up as an alias, this alias can
now be treated as rigid and gets unified without emitting a nested `AliasRelate`
goal: [source][structural-relate].
This means that `AliasRelate` with an unconstrained `rhs` ends up functioning
similar to `NormalizesTo`, acting as a function which fully normalizes `lhs`
before assigning the resulting rigid type to an inference variable. This is used by
`fn structurally_normalize_ty` both [inside] and [outside] of the trait solver.
This has to be used whenever we match on the value of some type, both inside
and outside of the trait solver.
<!--
FIXME: structure, maybe we should have an "alias handling" chapter instead as
talking about normalization without explaining that doesn't make too much
sense.
FIXME: it is likely that this will subtly change again by mostly moving structural
normalization into `NormalizesTo`.
-->
[structural_norm]: https://github.com/rust-lang/rust/blob/2627e9f3012a97d3136b3e11bf6bd0853c38a534/compiler/rustc_trait_selection/src/solve/alias_relate.rs#L140-L175
[structural-relate]: https://github.com/rust-lang/rust/blob/a0569fa8f91b5271e92d2f73fd252de7d3d05b9c/compiler/rustc_trait_selection/src/solve/alias_relate.rs#L88-L107
[inside]: https://github.com/rust-lang/rust/blob/a0569fa8f91b5271e92d2f73fd252de7d3d05b9c/compiler/rustc_trait_selection/src/solve/mod.rs#L278-L299
[outside]: https://github.com/rust-lang/rust/blob/a0569fa8f91b5271e92d2f73fd252de7d3d05b9c/compiler/rustc_trait_selection/src/traits/structural_normalize.rs#L17-L48
## Deep normalization
By walking over a type, and using `fn structurally_normalize_ty` for each encountered
alias, it is possible to deeply normalize a type, normalizing all aliases as much as
possible. However, this only works for aliases referencing bound variables if they are
not ambiguous as we're unable to replace the alias with a corresponding inference
variable without leaking universes.
<!--
FIXME: we previously had to also be careful about instantiating the new inference
variable with another normalizeable alias. Due to our recent changes to generalization,
this should not be the case anymore. Equating an inference variable with an alias
now always uses `AliasRelate` to fully normalize the alias before instantiating the
inference variable: [source][generalize-no-alias]
-->
[generalize-no-alias]: https://github.com/rust-lang/rust/blob/a0569fa8f91b5271e92d2f73fd252de7d3d05b9c/compiler/rustc_infer/src/infer/relate/generalize.rs#L353-L358
## Outside of the trait solver
The core type system - relating types and trait solving - will not need deep
normalization with the new solver. There are still some areas which depend on it.
For these areas there is the function `At::deeply_normalize`. Without additional
trait solver support deep normalization does not always work in case of ambiguity.
Luckily deep normalization is currently only necessary in places where there is no ambiguity.
`At::deeply_normalize` immediately fails if there's ambiguity.
If we only care about the outermost layer of types, we instead use
`At::structurally_normalize` or `FnCtxt::(try_)structurally_resolve_type`.
Unlike `At::deeply_normalize`, structural normalization is also used in cases where we
have to handle ambiguity.
Because this may result in behavior changes depending on how the trait solver handles
ambiguity, it is safer to also require full normalization there. This happens in
`FnCtxt::structurally_resolve_type` which always emits a hard error if the self type ends
up as an inference variable. There are some existing places which have a fallback for
inference variables instead. These places use `try_structurally_resolve_type` instead.
## Why deep normalization with ambiguity is hard
Fully correct deep normalization is very challenging, especially with the new solver
given that we do not want to deeply normalize inside of the solver. Mostly deeply normalizing
but sometimes failing to do so is bound to cause very hard to minimize and understand bugs.
If possible, avoiding any reliance on deep normalization entirely therefore feels preferable.
If the solver itself does not deeply normalize, any inference constraints returned by the
solver would require normalization. Handling this correctly is ugly. This also means that
we change goals we provide to the trait solver by "normalizing away" some projections.
The way we (mostly) guarantee deep normalization with the old solver is by eagerly replacing
the projection with an inference variable and emitting a nested `Projection` goal. This works
as `Projection` goals in the old solver deeply normalize. Unless we add another `PredicateKind`
for deep normalization to the new solver we cannot emulate this behavior. This does not work
for projections with bound variables, sometimes leaving them unnormalized. An approach which
also supports projections with bound variables will be even more involved.
[^opaques]: opaque types are currently handled a bit differently. this may change in the future

View File

@ -106,4 +106,4 @@ their ambiguous nested goals are returned to the caller which then evaluates the
See [#122687] for more details. See [#122687] for more details.
[#122687]: https://github.com/rust-lang/rust/pull/122687 [#122687]: https://github.com/rust-lang/rust/pull/122687
[normalization]: ./normalization.md [normalization]: ../normalization.md

View File

@ -70,6 +70,11 @@ related tests.
> //! > //!
> //! Regression test for <https://github.com/rust-lang/rust/issues/123456>. > //! Regression test for <https://github.com/rust-lang/rust/issues/123456>.
> ``` > ```
>
> One exception to this rule is [crashes tests]: there it is canonical that
> tests are named only after issue numbers because its purpose is to track
> snippets from which issues no longer ICE/crash, and they would either be
> removed or converted into proper ui/other tests in the fix PRs.
## Test organization ## Test organization
@ -194,3 +199,4 @@ See [LLVM FileCheck guide][FileCheck] for details.
[compiletest directives]: ./directives.md [compiletest directives]: ./directives.md
[`run-make`]: ./compiletest.md#run-make-tests [`run-make`]: ./compiletest.md#run-make-tests
[FileCheck]: https://llvm.org/docs/CommandGuide/FileCheck.html [FileCheck]: https://llvm.org/docs/CommandGuide/FileCheck.html
[crashes tests]: ./compiletest.md#crashes-tests

View File

@ -135,12 +135,16 @@ There are several use-cases for try builds:
- Run a specific CI job (e.g. Windows tests) on a PR, to quickly test if it - Run a specific CI job (e.g. Windows tests) on a PR, to quickly test if it
passes the test suite executed by that job. passes the test suite executed by that job.
You can select which CI jobs will By default, if you send a comment with `@bors try`, the jobs defined in the `try` section of
be executed in the try build by adding lines containing `try-job: [`jobs.yml`] will be executed. We call this mode a "fast try build". Such a try build
<job pattern>` to the PR description. All such specified jobs will be executed will not execute any tests, and it will allow compilation warnings. It is useful when you want to
in the try build once the `@bors try` command is used on the PR. If no try get an optimized toolchain as fast as possible, for a crater run or performance benchmarks,
jobs are specified in this way, the jobs defined in the `try` section of even if it might not be working fully correctly.
[`jobs.yml`] will be executed by default.
If you want to run a custom CI job in a try build and make sure that it passes all tests and does
not produce any compilation warnings, you can select CI jobs to be executed by adding lines
containing `try-job: <job pattern>` to the PR description. All such specified jobs will be executed
in the try build once the `@bors try` command is used on the PR.
Each pattern can either be an exact name of a job or a glob pattern that matches multiple jobs, Each pattern can either be an exact name of a job or a glob pattern that matches multiple jobs,
for example `*msvc*` or `*-alt`. You can start at most 20 jobs in a single try build. When using for example `*msvc*` or `*-alt`. You can start at most 20 jobs in a single try build. When using

View File

@ -325,12 +325,8 @@ The tests in [`tests/codegen-units`] test the
[monomorphization](../backend/monomorph.md) collector and CGU partitioning. [monomorphization](../backend/monomorph.md) collector and CGU partitioning.
These tests work by running `rustc` with a flag to print the result of the These tests work by running `rustc` with a flag to print the result of the
monomorphization collection pass, and then special annotations in the file are monomorphization collection pass, i.e., `-Zprint-mono-items`, and then special
used to compare against that. annotations in the file are used to compare against that.
Each test should be annotated with the `//@
compile-flags:-Zprint-mono-items=VAL` directive with the appropriate `VAL` to
instruct `rustc` to print the monomorphization information.
Then, the test should be annotated with comments of the form `//~ MONO_ITEM Then, the test should be annotated with comments of the form `//~ MONO_ITEM
name` where `name` is the monomorphized string printed by rustc like `fn <u32 as name` where `name` is the monomorphized string printed by rustc like `fn <u32 as

View File

@ -102,11 +102,12 @@ by passing a path to a book to `./x test`.
### Documentation link checker ### Documentation link checker
Links across all documentation is validated with a link checker tool. Links across all documentation is validated with a link checker tool,
and it can be invoked so:
> Example: `./x test src/tools/linkchecker` ```console
./x test linkchecker
> Example: `./x test linkchecker` ```
This requires building all of the documentation, which might take a while. This requires building all of the documentation, which might take a while.

View File

@ -344,8 +344,7 @@ For checking runtime output, `//@ check-run-results` may be preferable.
Only use `error-pattern` if none of the above works. Only use `error-pattern` if none of the above works.
Line annotations `//~` are still checked in tests using `error-pattern`. Line annotations `//~` and `error-pattern` are compatible and can be used in the same test.
In exceptional cases, use `//@ compile-flags: --error-format=human` to opt out of these checks.
### Diagnostic kinds (error levels) ### Diagnostic kinds (error levels)
@ -356,9 +355,12 @@ The diagnostic kinds that you can have are:
- `NOTE` - `NOTE`
- `HELP` - `HELP`
- `SUGGESTION` - `SUGGESTION`
- `RAW`
The `SUGGESTION` kind is used for specifying what the expected replacement text The `SUGGESTION` kind is used for specifying what the expected replacement text
should be for a diagnostic suggestion. should be for a diagnostic suggestion.
The `RAW` kind can be used for matching on lines from non-structured output sometimes emitted
by the compiler instead of or in addition to structured json.
`ERROR` and `WARN` kinds are required to be exhaustively covered by line annotations `ERROR` and `WARN` kinds are required to be exhaustively covered by line annotations
`//~` by default. `//~` by default.

View File

@ -32,21 +32,21 @@ Built-in implementations are provided for:
## Structural implementations ## Structural implementations
There are two implementations of `Unsize` which can be thought of as There is one implementation of `Unsize` which can be thought of as
structural: structural:
* `(A1, A2, .., An): Unsize<(A1, A2, .., U)>` given `An: Unsize<U>`, which
allows the tail field of a tuple to be unsized. This is gated behind the
[`unsized_tuple_coercion`] feature.
* `Struct<.., Pi, .., Pj, ..>: Unsize<Struct<.., Ui, .., Uj, ..>>` given * `Struct<.., Pi, .., Pj, ..>: Unsize<Struct<.., Ui, .., Uj, ..>>` given
`TailField<Pi, .., Pj>: Unsize<Ui, .. Uj>`, which allows the tail field of a `TailField<Pi, .., Pj>: Unsize<Ui, .. Uj>`, which allows the tail field of a
struct to be unsized if it is the only field that mentions generic parameters struct to be unsized if it is the only field that mentions generic parameters
`Pi`, .., `Pj` (which don't need to be contiguous). `Pi`, .., `Pj` (which don't need to be contiguous).
The rules for the latter implementation are slightly complicated, since they The rules for struct unsizing are slightly complicated, since they
may allow more than one parameter to be changed (not necessarily unsized) and may allow more than one parameter to be changed (not necessarily unsized) and
are best stated in terms of the tail field of the struct. are best stated in terms of the tail field of the struct.
[`unsized_tuple_coercion`]: https://doc.rust-lang.org/beta/unstable-book/language-features/unsized-tuple-coercion.html (Tuple unsizing was previously implemented behind the feature gate
`unsized_tuple_coercion`, but the implementation was removed by [#137728].)
[#137728]: https://github.com/rust-lang/rust/pull/137728
## Upcasting implementations ## Upcasting implementations

View File

@ -1,26 +1,28 @@
<!-- date-check: may 2024 -->
# `TypeFoldable` and `TypeFolder` # `TypeFoldable` and `TypeFolder`
In the previous chapter we discussed instantiating binders. This must involves looking at everything inside of a `Early/Binder` In [a previous chapter], we discussed instantiating binders.
to find any usages of the bound vars in order to replace them. Binders can wrap an arbitrary rust type `T` not just a `Ty` so This involves looking at everything inside of a `Early(Binder)`
how do we implement the `instantiate` methods on the `Early/Binder` types. to find any usages of the bound vars in order to replace them.
Binders can wrap an arbitrary Rust type `T`, not just a `Ty`.
So, how do we implement the `instantiate` methods on the `Early/Binder` types?
The answer is a couple of traits: The answer is a couple of traits:
[`TypeFoldable`](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/fold/trait.TypeFoldable.html) [`TypeFoldable`]
and and
[`TypeFolder`](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/fold/trait.TypeFolder.html). [`TypeFolder`].
- `TypeFoldable` is implemented by types that embed type information. It allows you to recursively - `TypeFoldable` is implemented by types that embed type information. It allows you to recursively
process the contents of the `TypeFoldable` and do stuff to them. process the contents of the `TypeFoldable` and do stuff to them.
- `TypeFolder` defines what you want to do with the types you encounter while processing the - `TypeFolder` defines what you want to do with the types you encounter while processing the
`TypeFoldable`. `TypeFoldable`.
For example, the `TypeFolder` trait has a method For example, the `TypeFolder` trait has a method [`fold_ty`]
[`fold_ty`](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/fold/trait.TypeFolder.html#method.fold_ty) that takes a type as input and returns a new type as a result.
that takes a type as input and returns a new type as a result. `TypeFoldable` invokes the `TypeFoldable` invokes the `TypeFolder` `fold_foo` methods on itself,
`TypeFolder` `fold_foo` methods on itself, giving the `TypeFolder` access to its contents (the giving the `TypeFolder` access to its contents (the types, regions, etc that are contained within).
types, regions, etc that are contained within).
You can think of it with this analogy to the iterator combinators we have come to love in rust: You can think of it with this analogy to the iterator combinators we have come to love in Rust:
```rust,ignore ```rust,ignore
vec.iter().map(|e1| foo(e2)).collect() vec.iter().map(|e1| foo(e2)).collect()
@ -33,8 +35,7 @@ So to reiterate:
- `TypeFolder` is a trait that defines a “map” operation. - `TypeFolder` is a trait that defines a “map” operation.
- `TypeFoldable` is a trait that is implemented by things that embed types. - `TypeFoldable` is a trait that is implemented by things that embed types.
In the case of `subst`, we can see that it is implemented as a `TypeFolder`: In the case of `subst`, we can see that it is implemented as a `TypeFolder`: [`ArgFolder`].
[`ArgFolder`](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_type_ir/binder/struct.ArgFolder.html).
Looking at its implementation, we see where the actual substitutions are happening. Looking at its implementation, we see where the actual substitutions are happening.
However, you might also notice that the implementation calls this `super_fold_with` method. What is However, you might also notice that the implementation calls this `super_fold_with` method. What is
@ -88,17 +89,22 @@ things. We only want to do something when we reach a type. That means there may
`TypeFoldable` types whose implementations basically just forward to their fields `TypeFoldable` `TypeFoldable` types whose implementations basically just forward to their fields `TypeFoldable`
implementations. Such implementations of `TypeFoldable` tend to be pretty tedious to write by hand. implementations. Such implementations of `TypeFoldable` tend to be pretty tedious to write by hand.
For this reason, there is a `derive` macro that allows you to `#![derive(TypeFoldable)]`. It is For this reason, there is a `derive` macro that allows you to `#![derive(TypeFoldable)]`. It is
defined defined [here].
[here](https://github.com/rust-lang/rust/blob/master/compiler/rustc_macros/src/type_foldable.rs).
**`subst`** In the case of substitutions the [actual **`subst`** In the case of substitutions the [actual folder]
folder](https://github.com/rust-lang/rust/blob/75ff3110ac6d8a0259023b83fd20d7ab295f8dd6/src/librustc_middle/ty/subst.rs#L440-L451) is going to be doing the indexing weve already mentioned.
is going to be doing the indexing weve already mentioned. There we define a `Folder` and call There we define a `Folder` and call `fold_with` on the `TypeFoldable` to process yourself.
`fold_with` on the `TypeFoldable` to process yourself. Then Then [fold_ty] the method that process each type it looks for a `ty::Param` and for those
[fold_ty](https://github.com/rust-lang/rust/blob/75ff3110ac6d8a0259023b83fd20d7ab295f8dd6/src/librustc_middle/ty/subst.rs#L512-L536) it replaces it for something from the list of substitutions, otherwise recursively process the type.
the method that process each type it looks for a `ty::Param` and for those it replaces it for To replace it, calls [ty_for_param]
something from the list of substitutions, otherwise recursively process the type. To replace it,
calls
[ty_for_param](https://github.com/rust-lang/rust/blob/75ff3110ac6d8a0259023b83fd20d7ab295f8dd6/src/librustc_middle/ty/subst.rs#L552-L587)
and all that does is index into the list of substitutions with the index of the `Param`. and all that does is index into the list of substitutions with the index of the `Param`.
[a previous chapter]: ty_module/instantiating_binders.md
[`TypeFoldable`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/trait.TypeFoldable.html
[`TypeFolder`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/trait.TypeFolder.html
[`fold_ty`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/trait.TypeFolder.html#method.fold_ty
[`ArgFolder`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_type_ir/binder/struct.ArgFolder.html
[here]: https://github.com/rust-lang/rust/blob/master/compiler/rustc_macros/src/type_foldable.rs
[actual folder]: https://github.com/rust-lang/rust/blob/75ff3110ac6d8a0259023b83fd20d7ab295f8dd6/src/librustc_middle/ty/subst.rs#L440-L451
[fold_ty]: https://github.com/rust-lang/rust/blob/75ff3110ac6d8a0259023b83fd20d7ab295f8dd6/src/librustc_middle/ty/subst.rs#L512-L536
[ty_for_param]: https://github.com/rust-lang/rust/blob/75ff3110ac6d8a0259023b83fd20d7ab295f8dd6/src/librustc_middle/ty/subst.rs#L552-L587

View File

@ -17,7 +17,7 @@ Type "collection" is the process of converting the types found in the HIR
**internal representation** used by the compiler (`Ty<'tcx>`) we also do **internal representation** used by the compiler (`Ty<'tcx>`) we also do
similar conversions for where-clauses and other bits of the function signature. similar conversions for where-clauses and other bits of the function signature.
To try and get a sense for the difference, consider this function: To try and get a sense of the difference, consider this function:
```rust,ignore ```rust,ignore
struct Foo { } struct Foo { }

View File

@ -19,7 +19,7 @@ Here, the type of `things` is *inferred* to be `Vec<&str>` because of the value
we push into `things`. we push into `things`.
The type inference is based on the standard Hindley-Milner (HM) type inference The type inference is based on the standard Hindley-Milner (HM) type inference
algorithm, but extended in various way to accommodate subtyping, region algorithm, but extended in various ways to accommodate subtyping, region
inference, and higher-ranked types. inference, and higher-ranked types.
## A note on terminology ## A note on terminology

View File

@ -4,7 +4,7 @@
## Typing Environments ## Typing Environments
When interacting with the type system there are a few variables to consider that can affect the results of trait solving. The the set of in-scope where clauses, and what phase of the compiler type system operations are being performed in (the [`ParamEnv`][penv] and [`TypingMode`][tmode] structs respectively). When interacting with the type system there are a few variables to consider that can affect the results of trait solving. The set of in-scope where clauses, and what phase of the compiler type system operations are being performed in (the [`ParamEnv`][penv] and [`TypingMode`][tmode] structs respectively).
When an environment to perform type system operations in has not yet been created, the [`TypingEnv`][tenv] can be used to bundle all of the external context required into a single type. When an environment to perform type system operations in has not yet been created, the [`TypingEnv`][tenv] can be used to bundle all of the external context required into a single type.
@ -13,11 +13,11 @@ Once a context to perform type system operations in has been created (e.g. an [`
[ocx]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_trait_selection/traits/struct.ObligationCtxt.html [ocx]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_trait_selection/traits/struct.ObligationCtxt.html
[fnctxt]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir_typeck/fn_ctxt/struct.FnCtxt.html [fnctxt]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir_typeck/fn_ctxt/struct.FnCtxt.html
## Parameter Environemnts ## Parameter Environments
### What is a `ParamEnv` ### What is a `ParamEnv`
The [`ParamEnv`][penv] is a list of in-scope where-clauses, it typically corresponds to a specific item's where clauses. Some clauses are not explicitly written but are instead are implicitly added in the [`predicates_of`][predicates_of] query, such as `ConstArgHasType` or (some) implied bounds. The [`ParamEnv`][penv] is a list of in-scope where-clauses, it typically corresponds to a specific item's where clauses. Some clauses are not explicitly written but are instead implicitly added in the [`predicates_of`][predicates_of] query, such as `ConstArgHasType` or (some) implied bounds.
In most cases `ParamEnv`s are initially created via the [`param_env` query][query] which returns a `ParamEnv` derived from the provided item's where clauses. A `ParamEnv` can also be created with arbitrary sets of clauses that are not derived from a specific item, such as in [`compare_method_predicate_entailment`][method_pred_entailment] where we create a hybrid `ParamEnv` consisting of the impl's where clauses and the trait definition's function's where clauses. In most cases `ParamEnv`s are initially created via the [`param_env` query][query] which returns a `ParamEnv` derived from the provided item's where clauses. A `ParamEnv` can also be created with arbitrary sets of clauses that are not derived from a specific item, such as in [`compare_method_predicate_entailment`][method_pred_entailment] where we create a hybrid `ParamEnv` consisting of the impl's where clauses and the trait definition's function's where clauses.
@ -73,7 +73,7 @@ fn foo2<T>(a: T) {
### Acquiring a `ParamEnv` ### Acquiring a `ParamEnv`
Using the wrong [`ParamEnv`][penv] when interacting with the type system can lead to ICEs, illformed programs compiling, or erroing when we shouldn't. See [#82159](https://github.com/rust-lang/rust/pull/82159) and [#82067](https://github.com/rust-lang/rust/pull/82067) as examples of PRs that modified the compiler to use the correct param env and in the process fixed ICEs. Using the wrong [`ParamEnv`][penv] when interacting with the type system can lead to ICEs, illformed programs compiling, or erroring when we shouldn't. See [#82159](https://github.com/rust-lang/rust/pull/82159) and [#82067](https://github.com/rust-lang/rust/pull/82067) as examples of PRs that modified the compiler to use the correct param env and in the process fixed ICEs.
In the large majority of cases, when a `ParamEnv` is required it either already exists somewhere in scope, or above in the call stack and should be passed down. A non exhaustive list of places where you might find an existing `ParamEnv`: In the large majority of cases, when a `ParamEnv` is required it either already exists somewhere in scope, or above in the call stack and should be passed down. A non exhaustive list of places where you might find an existing `ParamEnv`:
- During typeck `FnCtxt` has a [`param_env` field][fnctxt_param_env] - During typeck `FnCtxt` has a [`param_env` field][fnctxt_param_env]

View File

@ -13,3 +13,6 @@ allow-unauthenticated = [
# Automatically close and reopen PRs made by bots to run CI on them # Automatically close and reopen PRs made by bots to run CI on them
[bot-pull-requests] [bot-pull-requests]
[behind-upstream]
days-threshold = 7