diff --git a/.mailmap b/.mailmap index fc8e83d6493c..6c168bbbcb55 100644 --- a/.mailmap +++ b/.mailmap @@ -680,6 +680,7 @@ Valerii Lashmanov Vitali Haravy Vitali Haravy Vitaly Shukela Waffle Lapkin +Waffle Lapkin Waffle Lapkin Weihang Lo Weihang Lo diff --git a/Cargo.lock b/Cargo.lock index 2c290b392d59..5e9ba9b43279 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -75,7 +75,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "710e8eae58854cdc1790fcb56cca04d712a17be849eeb81da2a724bf4bae2bc4" dependencies = [ "anstyle", - "unicode-width 0.2.1", + "unicode-width 0.2.2", +] + +[[package]] +name = "annotate-snippets" +version = "0.12.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47224528f74de27d1d06aad6a5dda4f865b6ebe2e56c538943d746a7270cb67e" +dependencies = [ + "anstyle", + "unicode-width 0.2.2", ] [[package]] @@ -136,7 +146,7 @@ dependencies = [ "anstyle-lossy", "anstyle-parse", "html-escape", - "unicode-width 0.2.1", + "unicode-width 0.2.2", ] [[package]] @@ -464,10 +474,11 @@ version = "0.1.0" [[package]] name = "cc" -version = "1.2.16" +version = "1.2.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be714c154be609ec7f5dad223a33bf1482fff90472de28f7362806e6d4832b8c" +checksum = "e1354349954c6fc9cb0deab020f27f783cf0b604e8bb754dc4658ecf0d29c35f" dependencies = [ + "find-msvc-tools", "jobserver", "libc", "shlex", @@ -677,7 +688,7 @@ checksum = "fe6d2e5af09e8c8ad56c969f2157a3d4238cebc7c55f0a517728c38f7b200f81" dependencies = [ "serde", "termcolor", - "unicode-width 0.2.1", + "unicode-width 0.2.2", ] [[package]] @@ -808,7 +819,7 @@ dependencies = [ "encode_unicode", "libc", "once_cell", - "unicode-width 0.2.1", + "unicode-width 0.2.2", "windows-sys 0.59.0", ] @@ -1485,7 +1496,7 @@ version = "0.2.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cfe4fbac503b8d1f88e6676011885f34b7174f46e59956bba534ba83abded4df" dependencies = [ - "unicode-width 0.2.1", + "unicode-width 0.2.2", ] [[package]] @@ -1887,7 +1898,7 @@ dependencies = [ "console", "number_prefix", "portable-atomic", - "unicode-width 0.2.1", + "unicode-width 0.2.2", "web-time", ] @@ -3756,7 +3767,7 @@ dependencies = [ name = "rustc_errors" version = "0.0.0" dependencies = [ - "annotate-snippets 0.11.5", + "annotate-snippets 0.12.7", "anstream", "anstyle", "derive_setters", @@ -4331,7 +4342,7 @@ dependencies = [ "thin-vec", "tracing", "unicode-normalization", - "unicode-width 0.2.1", + "unicode-width 0.2.2", ] [[package]] @@ -4590,7 +4601,7 @@ dependencies = [ "sha1", "sha2", "tracing", - "unicode-width 0.2.1", + "unicode-width 0.2.2", ] [[package]] @@ -5936,9 +5947,9 @@ checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" [[package]] name = "unicode-width" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a1a07cc7db3810833284e8d372ccdc6da29741639ecc70c9ec107df0fa6154c" +checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" [[package]] name = "unicode-xid" @@ -6223,7 +6234,7 @@ dependencies = [ "bumpalo", "leb128fmt", "memchr", - "unicode-width 0.2.1", + "unicode-width 0.2.2", "wasm-encoder 0.240.0", ] diff --git a/RELEASES.md b/RELEASES.md index aa5f37fffebf..74b0d4424c16 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,3 +1,214 @@ +Version 1.91.0 (2025-10-30) +========================== + + + +Language +-------- + +- [Lower pattern bindings in the order they're written and base drop order on primary bindings' order](https://github.com/rust-lang/rust/pull/143764) +- [Stabilize declaration of C-style variadic functions for `sysv64`, `win64`, `efiapi`, and `aapcs` ABIs](https://github.com/rust-lang/rust/pull/144066). + This brings these ABIs in line with the C ABI: variadic functions can be declared in extern blocks but not defined. +- [Add `dangling_pointers_from_locals` lint to warn against dangling pointers from local variables](https://github.com/rust-lang/rust/pull/144322) +- [Upgrade `semicolon_in_expressions_from_macros` from warn to deny](https://github.com/rust-lang/rust/pull/144369) +- [Stabilize LoongArch32 inline assembly](https://github.com/rust-lang/rust/pull/144402) +- [Add warn-by-default `integer_to_ptr_transmutes` lint against integer-to-pointer transmutes](https://github.com/rust-lang/rust/pull/144531) +- [Stabilize `sse4a` and `tbm` target features](https://github.com/rust-lang/rust/pull/144542) +- [Add `target_env = "macabi"` and `target_env = "sim"` cfgs](https://github.com/rust-lang/rust/pull/139451) as replacements for the `target_abi` cfgs with the same values. + + + +Compiler +-------- + +- [Don't warn on never-to-any `as` casts as unreachable](https://github.com/rust-lang/rust/pull/144804) + + + +Platform Support +---------------- + +- [Promote `aarch64-pc-windows-gnullvm` and `x86_64-pc-windows-gnullvm` to Tier 2 with host tools.](https://github.com/rust-lang/rust/pull/143031) + Note: llvm-tools and MSI installers are missing but will be added in future releases. +- [Promote `aarch64-pc-windows-msvc` to Tier 1](https://github.com/rust-lang/rust/pull/145682) + +Refer to Rust's [platform support page][platform-support-doc] +for more information on Rust's tiered platform support. + +[platform-support-doc]: https://doc.rust-lang.org/rustc/platform-support.html + + + +Libraries +--------- + +- [Print thread ID in panic message](https://github.com/rust-lang/rust/pull/115746) +- [Fix overly restrictive lifetime in `core::panic::Location::file` return type](https://github.com/rust-lang/rust/pull/132087) +- [Guarantee parameter order for `_by()` variants of `min` / `max`/ `minmax` in `std::cmp`](https://github.com/rust-lang/rust/pull/139357) +- [Document assumptions about `Clone` and `Eq` traits](https://github.com/rust-lang/rust/pull/144330/) +- [`std::thread`: Return error if setting thread stack size fails](https://github.com/rust-lang/rust/pull/144210) + This used to panic within the standard library. + + + +Stabilized APIs +--------------- + +- [`Path::file_prefix`](https://doc.rust-lang.org/stable/std/path/struct.Path.html#method.file_prefix) +- [`AtomicPtr::fetch_ptr_add`](https://doc.rust-lang.org/stable/std/sync/atomic/struct.AtomicPtr.html#method.fetch_ptr_add) +- [`AtomicPtr::fetch_ptr_sub`](https://doc.rust-lang.org/stable/std/sync/atomic/struct.AtomicPtr.html#method.fetch_ptr_sub) +- [`AtomicPtr::fetch_byte_add`](https://doc.rust-lang.org/stable/std/sync/atomic/struct.AtomicPtr.html#method.fetch_byte_add) +- [`AtomicPtr::fetch_byte_sub`](https://doc.rust-lang.org/stable/std/sync/atomic/struct.AtomicPtr.html#method.fetch_byte_sub) +- [`AtomicPtr::fetch_or`](https://doc.rust-lang.org/stable/std/sync/atomic/struct.AtomicPtr.html#method.fetch_or) +- [`AtomicPtr::fetch_and`](https://doc.rust-lang.org/stable/std/sync/atomic/struct.AtomicPtr.html#method.fetch_and) +- [`AtomicPtr::fetch_xor`](https://doc.rust-lang.org/stable/std/sync/atomic/struct.AtomicPtr.html#method.fetch_xor) +- [`{integer}::strict_add`](https://doc.rust-lang.org/stable/std/primitive.u32.html#method.strict_add) +- [`{integer}::strict_sub`](https://doc.rust-lang.org/stable/std/primitive.u32.html#method.strict_sub) +- [`{integer}::strict_mul`](https://doc.rust-lang.org/stable/std/primitive.u32.html#method.strict_mul) +- [`{integer}::strict_div`](https://doc.rust-lang.org/stable/std/primitive.i32.html#method.strict_div) +- [`{integer}::strict_div_euclid`](https://doc.rust-lang.org/stable/std/primitive.i32.html#method.strict_div_euclid) +- [`{integer}::strict_rem`](https://doc.rust-lang.org/stable/std/primitive.i32.html#method.strict_rem) +- [`{integer}::strict_rem_euclid`](https://doc.rust-lang.org/stable/std/primitive.i32.html#method.strict_rem_euclid) +- [`{integer}::strict_neg`](https://doc.rust-lang.org/stable/std/primitive.u32.html#method.strict_neg) +- [`{integer}::strict_shl`](https://doc.rust-lang.org/stable/std/primitive.u32.html#method.strict_shl) +- [`{integer}::strict_shr`](https://doc.rust-lang.org/stable/std/primitive.u32.html#method.strict_shr) +- [`{integer}::strict_pow`](https://doc.rust-lang.org/stable/std/primitive.u32.html#method.strict_pow) +- [`i{N}::strict_add_unsigned`](https://doc.rust-lang.org/stable/std/primitive.i32.html#method.strict_add_unsigned) +- [`i{N}::strict_sub_unsigned`](https://doc.rust-lang.org/stable/std/primitive.i32.html#method.strict_sub_unsigned) +- [`i{N}::strict_abs`](https://doc.rust-lang.org/stable/std/primitive.i32.html#method.strict_abs) +- [`u{N}::strict_add_signed`](https://doc.rust-lang.org/stable/std/primitive.u32.html#method.strict_add_signed) +- [`u{N}::strict_sub_signed`](https://doc.rust-lang.org/stable/std/primitive.u32.html#method.strict_sub_signed) +- [`PanicHookInfo::payload_as_str`](https://doc.rust-lang.org/stable/std/panic/struct.PanicHookInfo.html#method.payload_as_str) +- [`core::iter::chain`](https://doc.rust-lang.org/stable/core/iter/fn.chain.html) +- [`u{N}::checked_signed_diff`](https://doc.rust-lang.org/stable/std/primitive.u16.html#method.checked_signed_diff) +- [`core::array::repeat`](https://doc.rust-lang.org/stable/core/array/fn.repeat.html) +- [`PathBuf::add_extension`](https://doc.rust-lang.org/stable/std/path/struct.PathBuf.html#method.add_extension) +- [`PathBuf::with_added_extension`](https://doc.rust-lang.org/stable/std/path/struct.PathBuf.html#method.with_added_extension) +- [`Duration::from_mins`](https://doc.rust-lang.org/stable/std/time/struct.Duration.html#method.from_mins) +- [`Duration::from_hours`](https://doc.rust-lang.org/stable/std/time/struct.Duration.html#method.from_hours) +- [`impl PartialEq for PathBuf`](https://doc.rust-lang.org/stable/std/path/struct.PathBuf.html#impl-PartialEq%3Cstr%3E-for-PathBuf) +- [`impl PartialEq for PathBuf`](https://doc.rust-lang.org/stable/std/path/struct.PathBuf.html#impl-PartialEq%3CString%3E-for-PathBuf) +- [`impl PartialEq for Path`](https://doc.rust-lang.org/stable/std/path/struct.Path.html#impl-PartialEq%3Cstr%3E-for-Path) +- [`impl PartialEq for Path`](https://doc.rust-lang.org/stable/std/path/struct.Path.html#impl-PartialEq%3CString%3E-for-Path) +- [`impl PartialEq for String`](https://doc.rust-lang.org/stable/std/string/struct.String.html#impl-PartialEq%3CPathBuf%3E-for-String) +- [`impl PartialEq for String`](https://doc.rust-lang.org/stable/std/string/struct.String.html#impl-PartialEq%3CPath%3E-for-String) +- [`impl PartialEq for str`](https://doc.rust-lang.org/stable/std/primitive.str.html#impl-PartialEq%3CPathBuf%3E-for-str) +- [`impl PartialEq for str`](https://doc.rust-lang.org/stable/std/primitive.str.html#impl-PartialEq%3CPath%3E-for-str) +- [`Ipv4Addr::from_octets`](https://doc.rust-lang.org/stable/std/net/struct.Ipv4Addr.html#method.from_octets) +- [`Ipv6Addr::from_octets`](https://doc.rust-lang.org/stable/std/net/struct.Ipv6Addr.html#method.from_octets) +- [`Ipv6Addr::from_segments`](https://doc.rust-lang.org/stable/std/net/struct.Ipv6Addr.html#method.from_segments) +- [`impl Default for Pin> where Box: Default, T: ?Sized`](https://doc.rust-lang.org/stable/std/default/trait.Default.html#impl-Default-for-Pin%3CBox%3CT%3E%3E) +- [`impl Default for Pin> where Rc: Default, T: ?Sized`](https://doc.rust-lang.org/stable/std/default/trait.Default.html#impl-Default-for-Pin%3CRc%3CT%3E%3E) +- [`impl Default for Pin> where Arc: Default, T: ?Sized`](https://doc.rust-lang.org/stable/std/default/trait.Default.html#impl-Default-for-Pin%3CArc%3CT%3E%3E) +- [`Cell::as_array_of_cells`](https://doc.rust-lang.org/stable/std/cell/struct.Cell.html#method.as_array_of_cells) +- [`u{N}::carrying_add`](https://doc.rust-lang.org/stable/std/primitive.u64.html#method.carrying_add) +- [`u{N}::borrowing_sub`](https://doc.rust-lang.org/stable/std/primitive.u64.html#method.borrowing_sub) +- [`u{N}::carrying_mul`](https://doc.rust-lang.org/stable/std/primitive.u64.html#method.carrying_mul) +- [`u{N}::carrying_mul_add`](https://doc.rust-lang.org/stable/std/primitive.u64.html#method.carrying_mul_add) +- [`BTreeMap::extract_if`](https://doc.rust-lang.org/stable/std/collections/struct.BTreeMap.html#method.extract_if) +- [`BTreeSet::extract_if`](https://doc.rust-lang.org/stable/std/collections/struct.BTreeSet.html#method.extract_if) +- [`impl Debug for windows::ffi::EncodeWide<'_>`](https://doc.rust-lang.org/stable/std/os/windows/ffi/struct.EncodeWide.html#impl-Debug-for-EncodeWide%3C'_%3E) +- [`str::ceil_char_boundary`](https://doc.rust-lang.org/stable/std/primitive.str.html#method.ceil_char_boundary) +- [`str::floor_char_boundary`](https://doc.rust-lang.org/stable/std/primitive.str.html#method.floor_char_boundary) +- [`impl Sum for Saturating`](https://doc.rust-lang.org/stable/std/num/struct.Saturating.html#impl-Sum-for-Saturating%3Cu32%3E) +- [`impl Sum<&Self> for Saturating`](https://doc.rust-lang.org/stable/std/num/struct.Saturating.html#impl-Sum%3C%26Saturating%3Cu32%3E%3E-for-Saturating%3Cu32%3E) +- [`impl Product for Saturating`](https://doc.rust-lang.org/stable/std/num/struct.Saturating.html#impl-Product-for-Saturating%3Cu32%3E) +- [`impl Product<&Self> for Saturating`](https://doc.rust-lang.org/stable/std/num/struct.Saturating.html#impl-Product%3C%26Saturating%3Cu32%3E%3E-for-Saturating%3Cu32%3E) + +These previously stable APIs are now stable in const contexts: + +- [`<[T; N]>::each_ref`](https://doc.rust-lang.org/stable/std/primitive.array.html#method.each_ref) +- [`<[T; N]>::each_mut`](https://doc.rust-lang.org/stable/std/primitive.array.html#method.each_mut) +- [`OsString::new`](https://doc.rust-lang.org/stable/std/ffi/struct.OsString.html#method.new) +- [`PathBuf::new`](https://doc.rust-lang.org/stable/std/path/struct.PathBuf.html#method.new) +- [`TypeId::of`](https://doc.rust-lang.org/stable/std/any/struct.TypeId.html#method.of) +- [`ptr::with_exposed_provenance`](https://doc.rust-lang.org/stable/std/ptr/fn.with_exposed_provenance.html) +- [`ptr::with_exposed_provenance_mut`](https://doc.rust-lang.org/stable/std/ptr/fn.with_exposed_provenance_mut.html) + + + +Cargo +----- + +- 🎉 Stabilize `build.build-dir`. + This config sets the directory where intermediate build artifacts are stored. + These artifacts are produced by Cargo and rustc during the build process. + End users usually won't need to interact with them, and the layout inside + `build-dir` is an implementation detail that may change without notice. + ([config doc](https://doc.rust-lang.org/stable/cargo/reference/config.html#buildbuild-dir)) + ([build cache doc](https://doc.rust-lang.org/stable/cargo/reference/build-cache.html)) + [#15833](https://github.com/rust-lang/cargo/pull/15833) + [#15840](https://github.com/rust-lang/cargo/pull/15840) +- The `--target` flag and the `build.target` configuration can now take literal + `"host-tuple"` string, which will internally be substituted by the host + machine's target triple. + [#15838](https://github.com/rust-lang/cargo/pull/15838) + [#16003](https://github.com/rust-lang/cargo/pull/16003) + [#16032](https://github.com/rust-lang/cargo/pull/16032) + + + +Rustdoc +----- +- [In search results, rank doc aliases lower than non-alias items with the same name](https://github.com/rust-lang/rust/pull/145100) +- [Raw pointers now work in type-based search like references](https://github.com/rust-lang/rust/pull/145731). This means you can now search for things like `*const u8 ->`, and additionally functions that take or return raw pointers will now display their signature properly in search results. + + + +Compatibility Notes +------------------- + +- [Always require coroutine captures to be drop-live](https://github.com/rust-lang/rust/pull/144156) +- [Apple: Always pass SDK root when linking with `cc`, and pass it via `SDKROOT` env var](https://github.com/rust-lang/rust/pull/131477). This should fix linking issues with `rustc` running inside Xcode. Libraries in `/usr/local/lib` may no longer be linked automatically, if you develop or use a crate that relies on this, you should explicitly set `cargo::rustc-link-search=/usr/local/lib` in a `build.rs` script. +- [Relaxed bounds in associated type bound position like in `TraitRef` are now correctly forbidden](https://github.com/rust-lang/rust/pull/135331) +- [Add unstable `#[sanitize(xyz = "on|off")]` built-in attribute that shadows procedural macros with the same name](https://github.com/rust-lang/rust/pull/142681) +- [Fix the drop checker being more permissive for bindings declared with let-else](https://github.com/rust-lang/rust/pull/143028) +- [Be more strict when parsing attributes, erroring on many invalid attributes](https://github.com/rust-lang/rust/pull/144689) + - [Error on invalid `#[should_panic]` attributes](https://github.com/rust-lang/rust/pull/143808) + - [Error on invalid `#[link]` attributes](https://github.com/rust-lang/rust/pull/143193) +- [Mark all deprecation lints in name resolution as deny-by-default and also report in dependencies](https://github.com/rust-lang/rust/pull/143929) +- The lint `semicolon_in_expressions_from_macros`, for `macro_rules!` macros in expression position that expand to end in a semicolon (`;`), is now deny-by-default. It was already warn-by-default, and a future compatibility warning (FCW) that warned even in dependencies. This lint will become a hard error in the future. +- [Trait impl modifiers (e.g., `unsafe`, `!`, `default`) in inherent impls are no longer syntactically valid](https://github.com/rust-lang/rust/pull/144386) +- [Start reporting future breakage for `ill_formed_attribute_input` in dependencies](https://github.com/rust-lang/rust/pull/144544) +- [Restrict the scope of temporaries created by the macros `pin!`, `format_args!`, `write!`, and `writeln!` in `if let` scrutinees in Rust Edition 2024.](https://github.com/rust-lang/rust/pull/145342) This applies [Rust Edition 2024's `if let` temporary scope rules](https://doc.rust-lang.org/edition-guide/rust-2024/temporary-if-let-scope.html) to these temporaries, which previously could live past the `if` expression regardless of Edition. +- [Invalid numeric literal suffixes in tuple indexing, tuple struct indexing, and struct field name positions are now correctly rejected](https://github.com/rust-lang/rust/pull/145463) +- [Closures marked with the keyword `static` are now syntactically invalid](https://github.com/rust-lang/rust/pull/145604) +- [Shebangs inside `--cfg` and `--check-cfg` arguments are no longer allowed](https://github.com/rust-lang/rust/pull/146211) +- [Add future incompatibility lint for temporary lifetime shortening in Rust 1.92](https://github.com/rust-lang/rust/pull/147056) + +Cargo compatibility notes: + +- `cargo publish` no longer keeps `.crate` tarballs as final build artifacts + when `build.build-dir` is set. These tarballs were previously included due to + an oversight and are now treated as intermediate artifacts. + To get `.crate` tarballs as final artifacts, use `cargo package`. + In a future version, this change will apply regardless of `build.build-dir`. + [#15910](https://github.com/rust-lang/cargo/pull/15910) +- Adjust Cargo messages to match rustc diagnostic style. + This changes some of the terminal colors used by Cargo messages. + [#15928](https://github.com/rust-lang/cargo/pull/15928) +- Tools and projects relying on the + [internal details of Cargo's `build-dir`](https://doc.rust-lang.org/cargo/reference/build-cache.html) + may not work for users changing their `build-dir` layout. + For those doing so, we'd recommend proactively testing these cases + particularly as we are considering changing the default location of the `build-dir` in the future + ([cargo#16147](https://github.com/rust-lang/cargo/issues/16147)). + If you can't migrate off of Cargo's internal details, + we'd like to learn more about your use case as we prepare to change the layout of the `build-dir` + ([cargo#15010](https://github.com/rust-lang/cargo/issues/15010)). + + + +Internal Changes +---------------- + +These changes do not affect any public interfaces of Rust, but they represent +significant improvements to the performance or internals of rustc and related +tools. + +- [Update to LLVM 21](https://github.com/rust-lang/rust/pull/143684) + + Version 1.90.0 (2025-09-18) =========================== diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 94c15094f525..e93351bcf712 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -3680,6 +3680,9 @@ pub struct TraitImplHeader { #[derive(Clone, Encodable, Decodable, Debug, Default, Walkable)] pub struct FnContract { + /// Declarations of variables accessible both in the `requires` and + /// `ensures` clauses. + pub declarations: ThinVec, pub requires: Option>, pub ensures: Option>, } diff --git a/compiler/rustc_ast_lowering/src/block.rs b/compiler/rustc_ast_lowering/src/block.rs index f1e810a8b9ea..5bfe63008516 100644 --- a/compiler/rustc_ast_lowering/src/block.rs +++ b/compiler/rustc_ast_lowering/src/block.rs @@ -27,7 +27,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { hir::Block { hir_id, stmts, expr, rules, span: self.lower_span(b.span), targeted_by_break } } - fn lower_stmts( + pub(super) fn lower_stmts( &mut self, mut ast_stmts: &[Stmt], ) -> (&'hir [hir::Stmt<'hir>], Option<&'hir hir::Expr<'hir>>) { diff --git a/compiler/rustc_ast_lowering/src/contract.rs b/compiler/rustc_ast_lowering/src/contract.rs index 2f1c3d66d4e7..bafc49607f41 100644 --- a/compiler/rustc_ast_lowering/src/contract.rs +++ b/compiler/rustc_ast_lowering/src/contract.rs @@ -18,6 +18,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { body: impl FnOnce(&mut Self) -> rustc_hir::Expr<'hir>, contract: &rustc_ast::FnContract, ) -> rustc_hir::Expr<'hir> { + // The order in which things are lowered is important! I.e to + // refer to variables in contract_decls from postcond/precond, + // we must lower it first! + let contract_decls = self.lower_stmts(&contract.declarations).0; + match (&contract.requires, &contract.ensures) { (Some(req), Some(ens)) => { // Lower the fn contract, which turns: @@ -27,6 +32,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // into: // // let __postcond = if contract_checks { + // CONTRACT_DECLARATIONS; // contract_check_requires(PRECOND); // Some(|ret_val| POSTCOND) // } else { @@ -45,8 +51,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let precond = self.lower_precond(req); let postcond_checker = self.lower_postcond_checker(ens); - let contract_check = - self.lower_contract_check_with_postcond(Some(precond), postcond_checker); + let contract_check = self.lower_contract_check_with_postcond( + contract_decls, + Some(precond), + postcond_checker, + ); let wrapped_body = self.wrap_body_with_contract_check(body, contract_check, postcond_checker.span); @@ -68,15 +77,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // let ret = { body }; // // if contract_checks { + // CONTRACT_DECLARATIONS; // contract_check_ensures(__postcond, ret) // } else { // ret // } // } - let postcond_checker = self.lower_postcond_checker(ens); let contract_check = - self.lower_contract_check_with_postcond(None, postcond_checker); + self.lower_contract_check_with_postcond(contract_decls, None, postcond_checker); let wrapped_body = self.wrap_body_with_contract_check(body, contract_check, postcond_checker.span); @@ -91,12 +100,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // // { // if contracts_checks { + // CONTRACT_DECLARATIONS; // contract_requires(PRECOND); // } // body // } let precond = self.lower_precond(req); - let precond_check = self.lower_contract_check_just_precond(precond); + let precond_check = self.lower_contract_check_just_precond(contract_decls, precond); let body = self.arena.alloc(body(self)); @@ -145,9 +155,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fn lower_contract_check_just_precond( &mut self, + contract_decls: &'hir [rustc_hir::Stmt<'hir>], precond: rustc_hir::Stmt<'hir>, ) -> rustc_hir::Stmt<'hir> { - let stmts = self.arena.alloc_from_iter([precond].into_iter()); + let stmts = self + .arena + .alloc_from_iter(contract_decls.into_iter().map(|d| *d).chain([precond].into_iter())); let then_block_stmts = self.block_all(precond.span, stmts, None); let then_block = self.arena.alloc(self.expr_block(&then_block_stmts)); @@ -164,10 +177,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fn lower_contract_check_with_postcond( &mut self, + contract_decls: &'hir [rustc_hir::Stmt<'hir>], precond: Option>, postcond_checker: &'hir rustc_hir::Expr<'hir>, ) -> &'hir rustc_hir::Expr<'hir> { - let stmts = self.arena.alloc_from_iter(precond.into_iter()); + let stmts = self + .arena + .alloc_from_iter(contract_decls.into_iter().map(|d| *d).chain(precond.into_iter())); let span = match precond { Some(precond) => precond.span, None => postcond_checker.span, diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 4a9b9f544b53..7e1130d9f233 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -7,6 +7,7 @@ use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir as hir; use rustc_hir::attrs::AttributeKind; use rustc_hir::def::{DefKind, Res}; +use rustc_hir::definitions::DefPathData; use rustc_hir::{HirId, Target, find_attr}; use rustc_middle::span_bug; use rustc_middle::ty::TyCtxt; @@ -62,13 +63,14 @@ impl<'hir> LoweringContext<'_, 'hir> { pub(super) fn lower_expr_mut(&mut self, e: &Expr) -> hir::Expr<'hir> { ensure_sufficient_stack(|| { + let mut span = self.lower_span(e.span); match &e.kind { // Parenthesis expression does not have a HirId and is handled specially. ExprKind::Paren(ex) => { let mut ex = self.lower_expr_mut(ex); // Include parens in span, but only if it is a super-span. if e.span.contains(ex.span) { - ex.span = self.lower_span(e.span); + ex.span = self.lower_span(e.span.with_ctxt(ex.span.ctxt())); } // Merge attributes into the inner expression. if !e.attrs.is_empty() { @@ -287,7 +289,8 @@ impl<'hir> LoweringContext<'_, 'hir> { self.lower_span(*brackets_span), ), ExprKind::Range(e1, e2, lims) => { - self.lower_expr_range(e.span, e1.as_deref(), e2.as_deref(), *lims) + span = self.mark_span_with_reason(DesugaringKind::RangeExpr, span, None); + self.lower_expr_range(span, e1.as_deref(), e2.as_deref(), *lims) } ExprKind::Underscore => { let guar = self.dcx().emit_err(UnderscoreExprLhsAssign { span: e.span }); @@ -379,7 +382,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ExprKind::MacCall(_) => panic!("{:?} shouldn't exist here", e.span), }; - hir::Expr { hir_id: expr_hir_id, kind, span: self.lower_span(e.span) } + hir::Expr { hir_id: expr_hir_id, kind, span } }) } @@ -461,7 +464,13 @@ impl<'hir> LoweringContext<'_, 'hir> { for (idx, arg) in args.iter().cloned().enumerate() { if legacy_args_idx.contains(&idx) { let node_id = self.next_node_id(); - self.create_def(node_id, None, DefKind::AnonConst, f.span); + self.create_def( + node_id, + None, + DefKind::AnonConst, + DefPathData::LateAnonConst, + f.span, + ); let mut visitor = WillCreateDefIdsVisitor {}; let const_value = if let ControlFlow::Break(span) = visitor.visit_expr(&arg) { Box::new(Expr { @@ -1233,13 +1242,8 @@ impl<'hir> LoweringContext<'_, 'hir> { let rhs = self.lower_expr(rhs); // Introduce a `let` for destructuring: `let (lhs1, lhs2) = t`. - let destructure_let = self.stmt_let_pat( - None, - whole_span, - Some(rhs), - pat, - hir::LocalSource::AssignDesugar(self.lower_span(eq_sign_span)), - ); + let destructure_let = + self.stmt_let_pat(None, whole_span, Some(rhs), pat, hir::LocalSource::AssignDesugar); // `a = lhs1; b = lhs2;`. let stmts = self.arena.alloc_from_iter(std::iter::once(destructure_let).chain(assignments)); @@ -1475,7 +1479,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_expr_range_closed(&mut self, span: Span, e1: &Expr, e2: &Expr) -> hir::ExprKind<'hir> { let e1 = self.lower_expr_mut(e1); let e2 = self.lower_expr_mut(e2); - let fn_path = hir::QPath::LangItem(hir::LangItem::RangeInclusiveNew, self.lower_span(span)); + let fn_path = hir::QPath::LangItem(hir::LangItem::RangeInclusiveNew, span); let fn_expr = self.arena.alloc(self.expr(span, hir::ExprKind::Path(fn_path))); hir::ExprKind::Call(fn_expr, arena_vec![self; e1, e2]) } @@ -1552,14 +1556,16 @@ impl<'hir> LoweringContext<'_, 'hir> { ) })) .map(|(s, e)| { + let span = self.lower_span(e.span); + let span = self.mark_span_with_reason(DesugaringKind::RangeExpr, span, None); let expr = self.lower_expr(e); - let ident = Ident::new(s, self.lower_span(e.span)); - self.expr_field(ident, expr, e.span) + let ident = Ident::new(s, span); + self.expr_field(ident, expr, span) }), ); hir::ExprKind::Struct( - self.arena.alloc(hir::QPath::LangItem(lang_item, self.lower_span(span))), + self.arena.alloc(hir::QPath::LangItem(lang_item, span)), fields, hir::StructTailExpr::None, ) diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index d959657e7fe5..be9db9257356 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -51,6 +51,7 @@ use rustc_data_structures::tagged_ptr::TaggedRef; use rustc_errors::{DiagArgFromDisplay, DiagCtxtHandle}; use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res}; use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE, LocalDefId}; +use rustc_hir::definitions::{DefPathData, DisambiguatorState}; use rustc_hir::lints::DelayedLint; use rustc_hir::{ self as hir, AngleBrackets, ConstArg, GenericArg, HirId, ItemLocalMap, LifetimeSource, @@ -93,6 +94,7 @@ rustc_fluent_macro::fluent_messages! { "../messages.ftl" } struct LoweringContext<'a, 'hir> { tcx: TyCtxt<'hir>, resolver: &'a mut ResolverAstLowering, + disambiguator: DisambiguatorState, /// Used to allocate HIR nodes. arena: &'hir hir::Arena<'hir>, @@ -155,6 +157,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // Pseudo-globals. tcx, resolver, + disambiguator: DisambiguatorState::new(), arena: tcx.hir_arena, // HirId handling. @@ -546,6 +549,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { node_id: ast::NodeId, name: Option, def_kind: DefKind, + def_path_data: DefPathData, span: Span, ) -> LocalDefId { let parent = self.current_hir_id_owner.def_id; @@ -561,7 +565,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let def_id = self .tcx .at(span) - .create_def(parent, name, def_kind, None, &mut self.resolver.disambiguator) + .create_def(parent, name, def_kind, Some(def_path_data), &mut self.disambiguator) .def_id(); debug!("create_def: def_id_to_node_id[{:?}] <-> {:?}", def_id, node_id); @@ -846,6 +850,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { param, Some(kw::UnderscoreLifetime), DefKind::LifetimeParam, + DefPathData::DesugaredAnonymousLifetime, ident.span, ); debug!(?_def_id); @@ -2290,7 +2295,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // We're lowering a const argument that was originally thought to be a type argument, // so the def collector didn't create the def ahead of time. That's why we have to do // it here. - let def_id = self.create_def(node_id, None, DefKind::AnonConst, span); + let def_id = self.create_def( + node_id, + None, + DefKind::AnonConst, + DefPathData::LateAnonConst, + span, + ); let hir_id = self.lower_node_id(node_id); let path_expr = Expr { diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs index 7e4fa840f252..815338c84fa6 100644 --- a/compiler/rustc_ast_lowering/src/pat.rs +++ b/compiler/rustc_ast_lowering/src/pat.rs @@ -3,6 +3,7 @@ use std::sync::Arc; use rustc_ast::*; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir::def::{DefKind, Res}; +use rustc_hir::definitions::DefPathData; use rustc_hir::{self as hir, LangItem, Target}; use rustc_middle::span_bug; use rustc_span::source_map::{Spanned, respan}; @@ -527,7 +528,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // We're generating a range end that didn't exist in the AST, // so the def collector didn't create the def ahead of time. That's why we have to do // it here. - let def_id = self.create_def(node_id, None, DefKind::AnonConst, span); + let def_id = + self.create_def(node_id, None, DefKind::AnonConst, DefPathData::LateAnonConst, span); let hir_id = self.lower_node_id(node_id); let unstable_span = self.mark_span_with_reason( diff --git a/compiler/rustc_ast_pretty/src/pp.rs b/compiler/rustc_ast_pretty/src/pp.rs index 8a0dbadf18cd..4108671a3629 100644 --- a/compiler/rustc_ast_pretty/src/pp.rs +++ b/compiler/rustc_ast_pretty/src/pp.rs @@ -298,7 +298,7 @@ impl Printer { } } - // This is is where `BoxMarker`s are produced. + // This is where `BoxMarker`s are produced. fn scan_begin(&mut self, token: BeginToken) -> BoxMarker { if self.scan_stack.is_empty() { self.left_total = 1; @@ -310,7 +310,7 @@ impl Printer { BoxMarker } - // This is is where `BoxMarker`s are consumed. + // This is where `BoxMarker`s are consumed. fn scan_end(&mut self, b: BoxMarker) { if self.scan_stack.is_empty() { self.print_end(); diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg.rs b/compiler/rustc_attr_parsing/src/attributes/cfg.rs index af94e8acaf68..dab9e7666c23 100644 --- a/compiler/rustc_attr_parsing/src/attributes/cfg.rs +++ b/compiler/rustc_attr_parsing/src/attributes/cfg.rs @@ -326,7 +326,8 @@ pub fn parse_cfg_attr( }) { Ok(r) => return Some(r), Err(e) => { - let suggestions = CFG_ATTR_TEMPLATE.suggestions(cfg_attr.style, sym::cfg_attr); + let suggestions = + CFG_ATTR_TEMPLATE.suggestions(Some(cfg_attr.style), sym::cfg_attr); e.with_span_suggestions( cfg_attr.span, "must be of the form", @@ -356,7 +357,7 @@ pub fn parse_cfg_attr( template: CFG_ATTR_TEMPLATE, attribute: AttrPath::from_ast(&cfg_attr.get_normal_item().path), reason, - attr_style: cfg_attr.style, + suggestions: CFG_ATTR_TEMPLATE.suggestions(Some(cfg_attr.style), sym::cfg_attr), }); } } @@ -388,6 +389,7 @@ fn parse_cfg_attr_internal<'a>( let cfg_predicate = AttributeParser::parse_single_args( sess, attribute.span, + attribute.get_normal_item().span(), attribute.style, AttrPath { segments: attribute diff --git a/compiler/rustc_attr_parsing/src/attributes/inline.rs b/compiler/rustc_attr_parsing/src/attributes/inline.rs index a10ad27fcc68..eda272fb7f2b 100644 --- a/compiler/rustc_attr_parsing/src/attributes/inline.rs +++ b/compiler/rustc_attr_parsing/src/attributes/inline.rs @@ -56,8 +56,7 @@ impl SingleAttributeParser for InlineParser { } } ArgParser::NameValue(_) => { - let suggestions = >::TEMPLATE - .suggestions(cx.attr_style, "inline"); + let suggestions = cx.suggestions(); let span = cx.attr_span; cx.emit_lint(AttributeLintKind::IllFormedAttributeInput { suggestions }, span); return None; diff --git a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs index 40ecd91e5cfc..797d04b914dd 100644 --- a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs @@ -71,8 +71,7 @@ impl CombineAttributeParser for LinkParser { // Specifically `#[link = "dl"]` is accepted with a FCW // For more information, see https://github.com/rust-lang/rust/pull/143193 ArgParser::NameValue(nv) if nv.value_as_str().is_some_and(|v| v == sym::dl) => { - let suggestions = >::TEMPLATE - .suggestions(cx.attr_style, "link"); + let suggestions = cx.suggestions(); let span = cx.attr_span; cx.emit_lint(AttributeLintKind::IllFormedAttributeInput { suggestions }, span); return None; diff --git a/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs index 849141c34f7d..787003519e78 100644 --- a/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs @@ -1,4 +1,3 @@ -use rustc_ast::AttrStyle; use rustc_errors::DiagArgValue; use rustc_hir::attrs::MacroUseArgs; @@ -102,7 +101,7 @@ impl AttributeParser for MacroUseParser { } } ArgParser::NameValue(_) => { - let suggestions = MACRO_USE_TEMPLATE.suggestions(cx.attr_style, sym::macro_use); + let suggestions = cx.suggestions(); cx.emit_err(IllFormedAttributeInputLint { num_suggestions: suggestions.len(), suggestions: DiagArgValue::StrListSepByAnd( @@ -149,19 +148,14 @@ impl SingleAttributeParser for MacroExportParser { ]); fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { - let suggestions = || { - >::TEMPLATE - .suggestions(AttrStyle::Inner, "macro_export") - }; let local_inner_macros = match args { ArgParser::NoArgs => false, ArgParser::List(list) => { let Some(l) = list.single() else { let span = cx.attr_span; + let suggestions = cx.suggestions(); cx.emit_lint( - AttributeLintKind::InvalidMacroExportArguments { - suggestions: suggestions(), - }, + AttributeLintKind::InvalidMacroExportArguments { suggestions }, span, ); return None; @@ -170,10 +164,9 @@ impl SingleAttributeParser for MacroExportParser { Some(sym::local_inner_macros) => true, _ => { let span = cx.attr_span; + let suggestions = cx.suggestions(); cx.emit_lint( - AttributeLintKind::InvalidMacroExportArguments { - suggestions: suggestions(), - }, + AttributeLintKind::InvalidMacroExportArguments { suggestions }, span, ); return None; @@ -182,7 +175,7 @@ impl SingleAttributeParser for MacroExportParser { } ArgParser::NameValue(_) => { let span = cx.attr_span; - let suggestions = suggestions(); + let suggestions = cx.suggestions(); cx.emit_err(IllFormedAttributeInputLint { num_suggestions: suggestions.len(), suggestions: DiagArgValue::StrListSepByAnd( diff --git a/compiler/rustc_attr_parsing/src/attributes/must_use.rs b/compiler/rustc_attr_parsing/src/attributes/must_use.rs index e6a5141d7830..51b43e96adf9 100644 --- a/compiler/rustc_attr_parsing/src/attributes/must_use.rs +++ b/compiler/rustc_attr_parsing/src/attributes/must_use.rs @@ -45,8 +45,7 @@ impl SingleAttributeParser for MustUseParser { Some(value_str) } ArgParser::List(_) => { - let suggestions = >::TEMPLATE - .suggestions(cx.attr_style, "must_use"); + let suggestions = cx.suggestions(); cx.emit_err(IllFormedAttributeInputLint { num_suggestions: suggestions.len(), suggestions: DiagArgValue::StrListSepByAnd( diff --git a/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs index 510ff1ded490..23ecc0bf7d29 100644 --- a/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs @@ -20,8 +20,7 @@ impl SingleAttributeParser for IgnoreParser { ArgParser::NoArgs => None, ArgParser::NameValue(name_value) => { let Some(str_value) = name_value.value_as_str() else { - let suggestions = >::TEMPLATE - .suggestions(cx.attr_style, "ignore"); + let suggestions = cx.suggestions(); let span = cx.attr_span; cx.emit_lint( AttributeLintKind::IllFormedAttributeInput { suggestions }, @@ -32,8 +31,7 @@ impl SingleAttributeParser for IgnoreParser { Some(str_value) } ArgParser::List(_) => { - let suggestions = >::TEMPLATE - .suggestions(cx.attr_style, "ignore"); + let suggestions = cx.suggestions(); let span = cx.attr_span; cx.emit_lint(AttributeLintKind::IllFormedAttributeInput { suggestions }, span); return None; diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 6749bdfb1a67..6694dac8bb25 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -337,8 +337,16 @@ pub struct Late; /// Gives [`AttributeParser`]s enough information to create errors, for example. pub struct AcceptContext<'f, 'sess, S: Stage> { pub(crate) shared: SharedContext<'f, 'sess, S>, - /// The span of the attribute currently being parsed + + /// The outer span of the attribute currently being parsed + /// #[attribute(...)] + /// ^^^^^^^^^^^^^^^^^ outer span + /// For attributes in `cfg_attr`, the outer span and inner spans are equal. pub(crate) attr_span: Span, + /// The inner span of the attribute currently being parsed + /// #[attribute(...)] + /// ^^^^^^^^^^^^^^ inner span + pub(crate) inner_span: Span, /// Whether it is an inner or outer attribute pub(crate) attr_style: AttrStyle, @@ -427,7 +435,7 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> { i.kind.is_bytestr().then(|| self.sess().source_map().start_point(i.span)) }), }, - attr_style: self.attr_style, + suggestions: self.suggestions(), }) } @@ -438,7 +446,7 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> { template: self.template.clone(), attribute: self.attr_path.clone(), reason: AttributeParseErrorReason::ExpectedIntegerLiteral, - attr_style: self.attr_style, + suggestions: self.suggestions(), }) } @@ -449,7 +457,7 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> { template: self.template.clone(), attribute: self.attr_path.clone(), reason: AttributeParseErrorReason::ExpectedList, - attr_style: self.attr_style, + suggestions: self.suggestions(), }) } @@ -460,7 +468,7 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> { template: self.template.clone(), attribute: self.attr_path.clone(), reason: AttributeParseErrorReason::ExpectedNoArgs, - attr_style: self.attr_style, + suggestions: self.suggestions(), }) } @@ -472,7 +480,7 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> { template: self.template.clone(), attribute: self.attr_path.clone(), reason: AttributeParseErrorReason::ExpectedIdentifier, - attr_style: self.attr_style, + suggestions: self.suggestions(), }) } @@ -485,7 +493,7 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> { template: self.template.clone(), attribute: self.attr_path.clone(), reason: AttributeParseErrorReason::ExpectedNameValue(name), - attr_style: self.attr_style, + suggestions: self.suggestions(), }) } @@ -497,7 +505,7 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> { template: self.template.clone(), attribute: self.attr_path.clone(), reason: AttributeParseErrorReason::DuplicateKey(key), - attr_style: self.attr_style, + suggestions: self.suggestions(), }) } @@ -510,7 +518,7 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> { template: self.template.clone(), attribute: self.attr_path.clone(), reason: AttributeParseErrorReason::UnexpectedLiteral, - attr_style: self.attr_style, + suggestions: self.suggestions(), }) } @@ -521,7 +529,7 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> { template: self.template.clone(), attribute: self.attr_path.clone(), reason: AttributeParseErrorReason::ExpectedSingleArgument, - attr_style: self.attr_style, + suggestions: self.suggestions(), }) } @@ -532,7 +540,7 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> { template: self.template.clone(), attribute: self.attr_path.clone(), reason: AttributeParseErrorReason::ExpectedAtLeastOneArgument, - attr_style: self.attr_style, + suggestions: self.suggestions(), }) } @@ -552,7 +560,7 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> { strings: false, list: false, }, - attr_style: self.attr_style, + suggestions: self.suggestions(), }) } @@ -573,7 +581,7 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> { strings: false, list: true, }, - attr_style: self.attr_style, + suggestions: self.suggestions(), }) } @@ -593,7 +601,7 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> { strings: true, list: false, }, - attr_style: self.attr_style, + suggestions: self.suggestions(), }) } @@ -605,6 +613,13 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> { span, ); } + + pub(crate) fn suggestions(&self) -> Vec { + // If the outer and inner spans are equal, we are parsing an attribute from `cfg_attr`, + // So don't display an attribute style in the suggestions + let style = (self.attr_span != self.inner_span).then_some(self.attr_style); + self.template.suggestions(style, &self.attr_path) + } } impl<'f, 'sess, S: Stage> Deref for AcceptContext<'f, 'sess, S> { diff --git a/compiler/rustc_attr_parsing/src/interface.rs b/compiler/rustc_attr_parsing/src/interface.rs index b8ef11c26d80..953b0ebfaf04 100644 --- a/compiler/rustc_attr_parsing/src/interface.rs +++ b/compiler/rustc_attr_parsing/src/interface.rs @@ -142,6 +142,7 @@ impl<'sess> AttributeParser<'sess, Early> { Self::parse_single_args( sess, attr.span, + normal_attr.item.span(), attr.style, path.get_attribute_path(), target_span, @@ -159,6 +160,7 @@ impl<'sess> AttributeParser<'sess, Early> { pub fn parse_single_args( sess: &'sess Session, attr_span: Span, + inner_span: Span, attr_style: AttrStyle, attr_path: AttrPath, target_span: Span, @@ -186,6 +188,7 @@ impl<'sess> AttributeParser<'sess, Early> { }, }, attr_span, + inner_span, attr_style, template, attr_path, @@ -305,6 +308,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { emit_lint: &mut emit_lint, }, attr_span: lower_span(attr.span), + inner_span: lower_span(attr.get_normal_item().span()), attr_style: attr.style, template: &accept.template, attr_path: path.get_attribute_path(), diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs index 7b82f3baec09..82bd29218313 100644 --- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs @@ -1,6 +1,6 @@ use std::num::IntErrorKind; -use rustc_ast::{self as ast, AttrStyle, Path}; +use rustc_ast::{self as ast, Path}; use rustc_errors::codes::*; use rustc_errors::{ Applicability, Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, @@ -613,10 +613,10 @@ pub(crate) enum AttributeParseErrorReason<'a> { pub(crate) struct AttributeParseError<'a> { pub(crate) span: Span, pub(crate) attr_span: Span, - pub(crate) attr_style: AttrStyle, pub(crate) template: AttributeTemplate, pub(crate) attribute: AttrPath, pub(crate) reason: AttributeParseErrorReason<'a>, + pub(crate) suggestions: Vec, } impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError<'_> { @@ -752,16 +752,15 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError<'_> { if let Some(link) = self.template.docs { diag.note(format!("for more information, visit <{link}>")); } - let suggestions = self.template.suggestions(self.attr_style, &name); diag.span_suggestions( self.attr_span, - if suggestions.len() == 1 { + if self.suggestions.len() == 1 { "must be of the form" } else { "try changing it to one of the following valid forms of the attribute" }, - suggestions, + self.suggestions, Applicability::HasPlaceholders, ); diff --git a/compiler/rustc_builtin_macros/src/contracts.rs b/compiler/rustc_builtin_macros/src/contracts.rs index 118efd15412e..52ddfbaa99f9 100644 --- a/compiler/rustc_builtin_macros/src/contracts.rs +++ b/compiler/rustc_builtin_macros/src/contracts.rs @@ -17,7 +17,7 @@ impl AttrProcMacro for ExpandRequires { annotation: TokenStream, annotated: TokenStream, ) -> Result { - expand_requires_tts(ecx, span, annotation, annotated) + expand_contract_clause_tts(ecx, span, annotation, annotated, kw::ContractRequires) } } @@ -29,7 +29,7 @@ impl AttrProcMacro for ExpandEnsures { annotation: TokenStream, annotated: TokenStream, ) -> Result { - expand_ensures_tts(ecx, span, annotation, annotated) + expand_contract_clause_tts(ecx, span, annotation, annotated, kw::ContractEnsures) } } @@ -130,42 +130,17 @@ fn expand_contract_clause( Ok(new_tts) } -fn expand_requires_tts( +fn expand_contract_clause_tts( ecx: &mut ExtCtxt<'_>, attr_span: Span, annotation: TokenStream, annotated: TokenStream, + clause_keyword: rustc_span::Symbol, ) -> Result { let feature_span = ecx.with_def_site_ctxt(attr_span); expand_contract_clause(ecx, attr_span, annotated, |new_tts| { new_tts.push_tree(TokenTree::Token( - token::Token::from_ast_ident(Ident::new(kw::ContractRequires, feature_span)), - Spacing::Joint, - )); - new_tts.push_tree(TokenTree::Token( - token::Token::new(token::TokenKind::OrOr, attr_span), - Spacing::Alone, - )); - new_tts.push_tree(TokenTree::Delimited( - DelimSpan::from_single(attr_span), - DelimSpacing::new(Spacing::JointHidden, Spacing::JointHidden), - token::Delimiter::Brace, - annotation, - )); - Ok(()) - }) -} - -fn expand_ensures_tts( - ecx: &mut ExtCtxt<'_>, - attr_span: Span, - annotation: TokenStream, - annotated: TokenStream, -) -> Result { - let feature_span = ecx.with_def_site_ctxt(attr_span); - expand_contract_clause(ecx, attr_span, annotated, |new_tts| { - new_tts.push_tree(TokenTree::Token( - token::Token::from_ast_ident(Ident::new(kw::ContractEnsures, feature_span)), + token::Token::from_ast_ident(Ident::new(clause_keyword, feature_span)), Spacing::Joint, )); new_tts.push_tree(TokenTree::Delimited( diff --git a/compiler/rustc_codegen_cranelift/src/driver/aot.rs b/compiler/rustc_codegen_cranelift/src/driver/aot.rs index 7e77781dc2fc..7bf1efc10653 100644 --- a/compiler/rustc_codegen_cranelift/src/driver/aot.rs +++ b/compiler/rustc_codegen_cranelift/src/driver/aot.rs @@ -671,18 +671,7 @@ pub(crate) fn run_aot(tcx: TyCtxt<'_>) -> Box { } .to_owned(); - let cgus = if tcx.sess.opts.output_types.should_codegen() { - tcx.collect_and_partition_mono_items(()).codegen_units - } else { - // If only `--emit metadata` is used, we shouldn't perform any codegen. - // Also `tcx.collect_and_partition_mono_items` may panic in that case. - return Box::new(OngoingCodegen { - modules: vec![], - allocator_module: None, - crate_info: CrateInfo::new(tcx, target_cpu), - concurrency_limiter: ConcurrencyLimiter::new(0), - }); - }; + let cgus = tcx.collect_and_partition_mono_items(()).codegen_units; if tcx.dep_graph.is_fully_enabled() { for cgu in cgus { diff --git a/compiler/rustc_codegen_cranelift/src/driver/jit.rs b/compiler/rustc_codegen_cranelift/src/driver/jit.rs index b3497503bf06..fec46bf26975 100644 --- a/compiler/rustc_codegen_cranelift/src/driver/jit.rs +++ b/compiler/rustc_codegen_cranelift/src/driver/jit.rs @@ -33,9 +33,7 @@ fn create_jit_module(tcx: TyCtxt<'_>) -> (UnwindModule, CodegenCx) { } pub(crate) fn run_jit(tcx: TyCtxt<'_>, jit_args: Vec) -> ! { - if !tcx.sess.opts.output_types.should_codegen() { - tcx.dcx().fatal("JIT mode doesn't work with `cargo check`"); - } + // FIXME error on check mode or crate types other than bin in CodegenBackend::init() if !tcx.crate_types().contains(&rustc_session::config::CrateType::Executable) { tcx.dcx().fatal("can't jit non-executable crate"); diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs index 680ad98593e7..e03c2868b0f1 100644 --- a/compiler/rustc_codegen_llvm/src/abi.rs +++ b/compiler/rustc_codegen_llvm/src/abi.rs @@ -39,13 +39,11 @@ trait ArgAttributesExt { const ABI_AFFECTING_ATTRIBUTES: [(ArgAttribute, llvm::AttributeKind); 1] = [(ArgAttribute::InReg, llvm::AttributeKind::InReg)]; -const OPTIMIZATION_ATTRIBUTES: [(ArgAttribute, llvm::AttributeKind); 6] = [ +const OPTIMIZATION_ATTRIBUTES: [(ArgAttribute, llvm::AttributeKind); 4] = [ (ArgAttribute::NoAlias, llvm::AttributeKind::NoAlias), - (ArgAttribute::CapturesAddress, llvm::AttributeKind::CapturesAddress), (ArgAttribute::NonNull, llvm::AttributeKind::NonNull), (ArgAttribute::ReadOnly, llvm::AttributeKind::ReadOnly), (ArgAttribute::NoUndef, llvm::AttributeKind::NoUndef), - (ArgAttribute::CapturesReadOnly, llvm::AttributeKind::CapturesReadOnly), ]; fn get_attrs<'ll>(this: &ArgAttributes, cx: &CodegenCx<'ll, '_>) -> SmallVec<[&'ll Attribute; 8]> { @@ -81,15 +79,23 @@ fn get_attrs<'ll>(this: &ArgAttributes, cx: &CodegenCx<'ll, '_>) -> SmallVec<[&' } for (attr, llattr) in OPTIMIZATION_ATTRIBUTES { if regular.contains(attr) { - // captures(...) is only available since LLVM 21. - if (attr == ArgAttribute::CapturesReadOnly || attr == ArgAttribute::CapturesAddress) - && llvm_util::get_version() < (21, 0, 0) - { - continue; - } attrs.push(llattr.create_attr(cx.llcx)); } } + // captures(...) is only available since LLVM 21. + if (21, 0, 0) <= llvm_util::get_version() { + const CAPTURES_ATTRIBUTES: [(ArgAttribute, llvm::AttributeKind); 3] = [ + (ArgAttribute::CapturesNone, llvm::AttributeKind::CapturesNone), + (ArgAttribute::CapturesAddress, llvm::AttributeKind::CapturesAddress), + (ArgAttribute::CapturesReadOnly, llvm::AttributeKind::CapturesReadOnly), + ]; + for (attr, llattr) in CAPTURES_ATTRIBUTES { + if regular.contains(attr) { + attrs.push(llattr.create_attr(cx.llcx)); + break; + } + } + } } else if cx.tcx.sess.opts.unstable_opts.sanitizer.contains(SanitizerSet::MEMORY) { // If we're not optimising, *but* memory sanitizer is on, emit noundef, since it affects // memory sanitizer's behavior. diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs index 7e873347c82b..b3a11f8b12bf 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs @@ -128,7 +128,7 @@ impl GlobalFileTable { for file in all_files { raw_file_table.entry(file.stable_id).or_insert_with(|| { file.name - .for_scope(tcx.sess, RemapPathScopeComponents::MACRO) + .for_scope(tcx.sess, RemapPathScopeComponents::COVERAGE) .to_string_lossy() .into_owned() }); @@ -147,7 +147,7 @@ impl GlobalFileTable { .sess .opts .working_dir - .for_scope(tcx.sess, RemapPathScopeComponents::MACRO) + .for_scope(tcx.sess, RemapPathScopeComponents::COVERAGE) .to_string_lossy(); table.push(base_dir.as_ref()); diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 2456ed2e46d6..53f0f9ff9d01 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -289,6 +289,7 @@ pub(crate) enum AttributeKind { DeadOnUnwind = 43, DeadOnReturn = 44, CapturesReadOnly = 45, + CapturesNone = 46, } /// LLVMIntPredicate diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index 7518bbaf16a1..368a2e307bb2 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -1274,13 +1274,7 @@ fn start_executing_work( }) .expect("failed to spawn helper thread"); - let ol = - if tcx.sess.opts.unstable_opts.no_codegen || !tcx.sess.opts.output_types.should_codegen() { - // If we know that we won’t be doing codegen, create target machines without optimisation. - config::OptLevel::No - } else { - tcx.backend_optimization_level(()) - }; + let ol = tcx.backend_optimization_level(()); let backend_features = tcx.global_backend_features(()); let remark_dir = if let Some(ref dir) = sess.opts.unstable_opts.remark_dir { diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index c35b05f798ea..f58be0a3b9a3 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -684,17 +684,6 @@ pub fn codegen_crate( tcx: TyCtxt<'_>, target_cpu: String, ) -> OngoingCodegen { - // Skip crate items and just output metadata in -Z no-codegen mode. - if tcx.sess.opts.unstable_opts.no_codegen || !tcx.sess.opts.output_types.should_codegen() { - let ongoing_codegen = start_async_codegen(backend, tcx, target_cpu, None); - - ongoing_codegen.codegen_finished(tcx); - - ongoing_codegen.check_for_errors(tcx.sess); - - return ongoing_codegen; - } - if tcx.sess.target.need_explicit_cpu && tcx.sess.opts.cg.target_cpu.is_none() { // The target has no default cpu, but none is set explicitly tcx.dcx().emit_fatal(errors::CpuRequired); diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs index befa00c6861e..cc3316c7f8cc 100644 --- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs +++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs @@ -120,8 +120,15 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { | sym::atomic_singlethreadfence | sym::caller_location => {} _ => { - span_bug!(span, "nullary intrinsic {name} must either be in a const block or explicitly opted out because it is inherently a runtime intrinsic -"); + span_bug!( + span, + "Nullary intrinsic {name} must be called in a const block. \ + If you are seeing this message from code outside the standard library, the \ + unstable implementation details of the relevant intrinsic may have changed. \ + Consider using stable APIs instead. \ + If you are adding a new nullary intrinsic that is inherently a runtime \ + intrinsic, update this check." + ); } } } diff --git a/compiler/rustc_codegen_ssa/src/traits/backend.rs b/compiler/rustc_codegen_ssa/src/traits/backend.rs index ec53d9f53eb8..85bff4540814 100644 --- a/compiler/rustc_codegen_ssa/src/traits/backend.rs +++ b/compiler/rustc_codegen_ssa/src/traits/backend.rs @@ -10,7 +10,7 @@ use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; use rustc_middle::ty::TyCtxt; use rustc_middle::util::Providers; use rustc_session::Session; -use rustc_session::config::{self, OutputFilenames, PrintRequest}; +use rustc_session::config::{self, CrateType, OutputFilenames, PrintRequest}; use rustc_span::Symbol; use super::CodegenObject; @@ -62,6 +62,18 @@ pub trait CodegenBackend { } } + fn supported_crate_types(&self, _sess: &Session) -> Vec { + vec![ + CrateType::Executable, + CrateType::Dylib, + CrateType::Rlib, + CrateType::Staticlib, + CrateType::Cdylib, + CrateType::ProcMacro, + CrateType::Sdylib, + ] + } + fn print_passes(&self) {} fn print_version(&self) {} diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs index bf5787c86bd5..beea1b4a28c9 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -7,7 +7,7 @@ use rustc_hir::def::DefKind; use rustc_middle::mir::interpret::{AllocId, ErrorHandled, InterpErrorInfo, ReportedErrorInfo}; use rustc_middle::mir::{self, ConstAlloc, ConstValue}; use rustc_middle::query::TyCtxtAt; -use rustc_middle::ty::layout::HasTypingEnv; +use rustc_middle::ty::layout::{HasTypingEnv, TyAndLayout}; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::{bug, throw_inval}; @@ -24,13 +24,11 @@ use crate::interpret::{ }; use crate::{CTRL_C_RECEIVED, errors}; -// Returns a pointer to where the result lives -#[instrument(level = "trace", skip(ecx, body))] -fn eval_body_using_ecx<'tcx, R: InterpretationResult<'tcx>>( +fn setup_for_eval<'tcx>( ecx: &mut CompileTimeInterpCx<'tcx>, cid: GlobalId<'tcx>, - body: &'tcx mir::Body<'tcx>, -) -> InterpResult<'tcx, R> { + layout: TyAndLayout<'tcx>, +) -> InterpResult<'tcx, (InternKind, MPlaceTy<'tcx>)> { let tcx = *ecx.tcx; assert!( cid.promoted.is_some() @@ -46,7 +44,6 @@ fn eval_body_using_ecx<'tcx, R: InterpretationResult<'tcx>>( "Unexpected DefKind: {:?}", ecx.tcx.def_kind(cid.instance.def_id()) ); - let layout = ecx.layout_of(body.bound_return_ty().instantiate(tcx, cid.instance.args))?; assert!(layout.is_sized()); let intern_kind = if cid.promoted.is_some() { @@ -58,12 +55,25 @@ fn eval_body_using_ecx<'tcx, R: InterpretationResult<'tcx>>( } }; - let ret = if let InternKind::Static(_) = intern_kind { - create_static_alloc(ecx, cid.instance.def_id().expect_local(), layout)? + let return_place = if let InternKind::Static(_) = intern_kind { + create_static_alloc(ecx, cid.instance.def_id().expect_local(), layout) } else { - ecx.allocate(layout, MemoryKind::Stack)? + ecx.allocate(layout, MemoryKind::Stack) }; + return_place.map(|ret| (intern_kind, ret)) +} + +#[instrument(level = "trace", skip(ecx, body))] +fn eval_body_using_ecx<'tcx, R: InterpretationResult<'tcx>>( + ecx: &mut CompileTimeInterpCx<'tcx>, + cid: GlobalId<'tcx>, + body: &'tcx mir::Body<'tcx>, +) -> InterpResult<'tcx, R> { + let tcx = *ecx.tcx; + let layout = ecx.layout_of(body.bound_return_ty().instantiate(tcx, cid.instance.args))?; + let (intern_kind, ret) = setup_for_eval(ecx, cid, layout)?; + trace!( "eval_body_using_ecx: pushing stack frame for global: {}{}", with_no_trimmed_paths!(ecx.tcx.def_path_str(cid.instance.def_id())), @@ -87,6 +97,31 @@ fn eval_body_using_ecx<'tcx, R: InterpretationResult<'tcx>>( } } + intern_and_validate(ecx, cid, intern_kind, ret) +} + +#[instrument(level = "trace", skip(ecx))] +fn eval_trivial_const_using_ecx<'tcx, R: InterpretationResult<'tcx>>( + ecx: &mut CompileTimeInterpCx<'tcx>, + cid: GlobalId<'tcx>, + val: ConstValue, + ty: Ty<'tcx>, +) -> InterpResult<'tcx, R> { + let layout = ecx.layout_of(ty)?; + let (intern_kind, return_place) = setup_for_eval(ecx, cid, layout)?; + + let opty = ecx.const_val_to_op(val, ty, Some(layout))?; + ecx.copy_op(&opty, &return_place)?; + + intern_and_validate(ecx, cid, intern_kind, return_place) +} + +fn intern_and_validate<'tcx, R: InterpretationResult<'tcx>>( + ecx: &mut CompileTimeInterpCx<'tcx>, + cid: GlobalId<'tcx>, + intern_kind: InternKind, + ret: MPlaceTy<'tcx>, +) -> InterpResult<'tcx, R> { // Intern the result let intern_result = intern_const_alloc_recursive(ecx, intern_kind, &ret); @@ -292,6 +327,9 @@ pub fn eval_to_const_value_raw_provider<'tcx>( tcx: TyCtxt<'tcx>, key: ty::PseudoCanonicalInput<'tcx, GlobalId<'tcx>>, ) -> ::rustc_middle::mir::interpret::EvalToConstValueResult<'tcx> { + if let Some((value, _ty)) = tcx.trivial_const(key.value.instance.def_id()) { + return Ok(value); + } tcx.eval_to_allocation_raw(key).map(|val| turn_into_const_value(tcx, val, key)) } @@ -368,10 +406,14 @@ fn eval_in_interpreter<'tcx, R: InterpretationResult<'tcx>>( // so we have to reject reading mutable global memory. CompileTimeMachine::new(CanAccessMutGlobal::from(is_static), CheckAlignment::Error), ); - let res = ecx.load_mir(cid.instance.def, cid.promoted); - res.and_then(|body| eval_body_using_ecx(&mut ecx, cid, body)) - .report_err() - .map_err(|error| report_eval_error(&ecx, cid, error)) + + let result = if let Some((value, ty)) = tcx.trivial_const(def) { + eval_trivial_const_using_ecx(&mut ecx, cid, value, ty) + } else { + ecx.load_mir(cid.instance.def, cid.promoted) + .and_then(|body| eval_body_using_ecx(&mut ecx, cid, body)) + }; + result.report_err().map_err(|error| report_eval_error(&ecx, cid, error)) } #[inline(always)] diff --git a/compiler/rustc_const_eval/src/interpret/util.rs b/compiler/rustc_const_eval/src/interpret/util.rs index b5cf6c4c3723..1e18a22be81c 100644 --- a/compiler/rustc_const_eval/src/interpret/util.rs +++ b/compiler/rustc_const_eval/src/interpret/util.rs @@ -121,7 +121,7 @@ impl EnteredTraceSpan for tracing::span::EnteredSpan { /// ### `tracing_separate_thread` parameter /// /// This macro was introduced to obtain better traces of Miri without impacting release performance. -/// Miri saves traces using the the `tracing_chrome` `tracing::Layer` so that they can be visualized +/// Miri saves traces using the `tracing_chrome` `tracing::Layer` so that they can be visualized /// in . To instruct `tracing_chrome` to put some spans on a separate trace /// thread/line than other spans when viewed in , you can pass /// `tracing_separate_thread = tracing::field::Empty` to the tracing macros. This is useful to diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 9529ef2b99ad..c926a7c742a0 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -686,7 +686,8 @@ fn print_crate_info( }; let t_outputs = rustc_interface::util::build_output_filenames(attrs, sess); let crate_name = passes::get_crate_name(sess, attrs); - let crate_types = collect_crate_types(sess, attrs); + let crate_types = + collect_crate_types(sess, &codegen_backend.supported_crate_types(sess), attrs); for &style in &crate_types { let fname = rustc_session::output::filename_for_input( sess, style, crate_name, &t_outputs, diff --git a/compiler/rustc_errors/Cargo.toml b/compiler/rustc_errors/Cargo.toml index b7b5cbd35741..6ade87ea3b25 100644 --- a/compiler/rustc_errors/Cargo.toml +++ b/compiler/rustc_errors/Cargo.toml @@ -5,7 +5,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -annotate-snippets = "0.11" +annotate-snippets = "0.12.7" anstream = "0.6.20" anstyle = "1.0.13" derive_setters = "0.1.6" diff --git a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs index 2eb3c23259ff..854e3ddf15e4 100644 --- a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs +++ b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs @@ -5,32 +5,70 @@ //! //! [annotate_snippets]: https://docs.rs/crate/annotate-snippets/ +use std::borrow::Cow; +use std::error::Report; +use std::fmt::Debug; +use std::io; +use std::io::Write; use std::sync::Arc; -use annotate_snippets::{Renderer, Snippet}; -use rustc_error_messages::FluentArgs; -use rustc_span::SourceFile; +use annotate_snippets::renderer::DEFAULT_TERM_WIDTH; +use annotate_snippets::{AnnotationKind, Group, Origin, Padding, Patch, Renderer, Snippet}; +use anstream::ColorChoice; +use derive_setters::Setters; +use rustc_data_structures::sync::IntoDynSyncSend; +use rustc_error_messages::{FluentArgs, SpanLabel}; +use rustc_lint_defs::pluralize; use rustc_span::source_map::SourceMap; +use rustc_span::{BytePos, FileName, Pos, SourceFile, Span}; +use tracing::debug; -use crate::emitter::FileWithAnnotatedLines; +use crate::emitter::{ + ConfusionType, Destination, MAX_SUGGESTIONS, OutputTheme, detect_confusion_type, is_different, + normalize_whitespace, should_show_source_code, +}; use crate::registry::Registry; -use crate::snippet::Line; use crate::translation::{Translator, to_fluent_args}; use crate::{ CodeSuggestion, DiagInner, DiagMessage, Emitter, ErrCode, Level, MultiSpan, Style, Subdiag, + SuggestionStyle, TerminalUrl, }; /// Generates diagnostics using annotate-snippet +#[derive(Setters)] pub struct AnnotateSnippetEmitter { - source_map: Option>, + #[setters(skip)] + dst: IntoDynSyncSend, + sm: Option>, + #[setters(skip)] translator: Translator, - - /// If true, hides the longer explanation text short_message: bool, - /// If true, will normalize line numbers with `LL` to prevent noise in UI test diffs. ui_testing: bool, + ignored_directories_in_source_blocks: Vec, + diagnostic_width: Option, macro_backtrace: bool, + track_diagnostics: bool, + terminal_url: TerminalUrl, + theme: OutputTheme, +} + +impl Debug for AnnotateSnippetEmitter { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("AnnotateSnippetEmitter") + .field("short_message", &self.short_message) + .field("ui_testing", &self.ui_testing) + .field( + "ignored_directories_in_source_blocks", + &self.ignored_directories_in_source_blocks, + ) + .field("diagnostic_width", &self.diagnostic_width) + .field("macro_backtrace", &self.macro_backtrace) + .field("track_diagnostics", &self.track_diagnostics) + .field("terminal_url", &self.terminal_url) + .field("theme", &self.theme) + .finish() + } } impl Emitter for AnnotateSnippetEmitter { @@ -38,6 +76,10 @@ impl Emitter for AnnotateSnippetEmitter { fn emit_diagnostic(&mut self, mut diag: DiagInner, _registry: &Registry) { let fluent_args = to_fluent_args(diag.args.iter()); + if self.track_diagnostics && diag.span.has_primary_spans() && !diag.span.is_dummy() { + diag.children.insert(0, diag.emitted_at_sub_diag()); + } + let mut suggestions = diag.suggestions.unwrap_tag(); self.primary_span_formatted(&mut diag.span, &mut suggestions, &fluent_args); @@ -55,12 +97,12 @@ impl Emitter for AnnotateSnippetEmitter { &diag.code, &diag.span, &diag.children, - &suggestions, + suggestions, ); } fn source_map(&self) -> Option<&SourceMap> { - self.source_map.as_deref() + self.sm.as_deref() } fn should_show_explain(&self) -> bool { @@ -70,128 +112,648 @@ impl Emitter for AnnotateSnippetEmitter { fn translator(&self) -> &Translator { &self.translator } + + fn supports_color(&self) -> bool { + false + } } -/// Provides the source string for the given `line` of `file` -fn source_string(file: Arc, line: &Line) -> String { - file.get_line(line.line_index - 1).map(|a| a.to_string()).unwrap_or_default() -} - -/// Maps [`crate::Level`] to [`annotate_snippets::Level`] -fn annotation_level_for_level(level: Level) -> annotate_snippets::Level { +fn annotation_level_for_level(level: Level) -> annotate_snippets::level::Level<'static> { match level { - Level::Bug | Level::Fatal | Level::Error | Level::DelayedBug => { - annotate_snippets::Level::Error + Level::Bug | Level::DelayedBug => { + annotate_snippets::Level::ERROR.with_name("error: internal compiler error") } - Level::ForceWarning | Level::Warning => annotate_snippets::Level::Warning, - Level::Note | Level::OnceNote => annotate_snippets::Level::Note, - Level::Help | Level::OnceHelp => annotate_snippets::Level::Help, - // FIXME(#59346): Not sure how to map this level - Level::FailureNote => annotate_snippets::Level::Error, + Level::Fatal | Level::Error => annotate_snippets::level::ERROR, + Level::ForceWarning | Level::Warning => annotate_snippets::Level::WARNING, + Level::Note | Level::OnceNote => annotate_snippets::Level::NOTE, + Level::Help | Level::OnceHelp => annotate_snippets::Level::HELP, + Level::FailureNote => annotate_snippets::Level::NOTE.no_name(), Level::Allow => panic!("Should not call with Allow"), Level::Expect => panic!("Should not call with Expect"), } } impl AnnotateSnippetEmitter { - pub fn new( - source_map: Option>, - translator: Translator, - short_message: bool, - macro_backtrace: bool, - ) -> Self { - Self { source_map, translator, short_message, ui_testing: false, macro_backtrace } - } - - /// Allows to modify `Self` to enable or disable the `ui_testing` flag. - /// - /// If this is set to true, line numbers will be normalized as `LL` in the output. - pub fn ui_testing(mut self, ui_testing: bool) -> Self { - self.ui_testing = ui_testing; - self + pub fn new(dst: Destination, translator: Translator) -> Self { + Self { + dst: IntoDynSyncSend(dst), + sm: None, + translator, + short_message: false, + ui_testing: false, + ignored_directories_in_source_blocks: Vec::new(), + diagnostic_width: None, + macro_backtrace: false, + track_diagnostics: false, + terminal_url: TerminalUrl::No, + theme: OutputTheme::Ascii, + } } fn emit_messages_default( &mut self, level: &Level, - messages: &[(DiagMessage, Style)], + msgs: &[(DiagMessage, Style)], args: &FluentArgs<'_>, code: &Option, msp: &MultiSpan, - _children: &[Subdiag], - _suggestions: &[CodeSuggestion], + children: &[Subdiag], + suggestions: Vec, ) { - let message = self.translator.translate_messages(messages, args); - if let Some(source_map) = &self.source_map { - // Make sure our primary file comes first - let primary_lo = if let Some(primary_span) = msp.primary_span().as_ref() { - if primary_span.is_dummy() { - // FIXME(#59346): Not sure when this is the case and what - // should be done if it happens - return; - } else { - source_map.lookup_char_pos(primary_span.lo()) - } - } else { - // FIXME(#59346): Not sure when this is the case and what - // should be done if it happens - return; - }; - let mut annotated_files = FileWithAnnotatedLines::collect_annotations(self, args, msp); - if let Ok(pos) = - annotated_files.binary_search_by(|x| x.file.name.cmp(&primary_lo.file.name)) - { - annotated_files.swap(0, pos); - } - // owned: file name, line source, line index, annotations - type Owned = (String, String, usize, Vec); - let annotated_files: Vec = annotated_files - .into_iter() - .flat_map(|annotated_file| { - let file = annotated_file.file; - annotated_file - .lines - .into_iter() - .map(|line| { - // Ensure the source file is present before we try - // to load a string from it. - // FIXME(#115869): support -Z ignore-directory-in-diagnostics-source-blocks - source_map.ensure_source_file_source_present(&file); - ( - format!("{}", source_map.filename_for_diagnostics(&file.name)), - source_string(Arc::clone(&file), &line), - line.line_index, - line.annotations, - ) - }) - .collect::>() - }) - .collect(); - let code = code.map(|code| code.to_string()); + let renderer = self.renderer(); + let annotation_level = annotation_level_for_level(*level); - let snippets = - annotated_files.iter().map(|(file_name, source, line_index, annotations)| { - Snippet::source(source) - .line_start(*line_index) - .origin(file_name) - // FIXME(#59346): Not really sure when `fold` should be true or false - .fold(false) - .annotations(annotations.iter().map(|annotation| { - annotation_level_for_level(*level) - .span(annotation.start_col.display..annotation.end_col.display) - .label(annotation.label.as_deref().unwrap_or_default()) - })) - }); - let mut message = annotation_level_for_level(*level).title(&message).snippets(snippets); - if let Some(code) = code.as_deref() { - message = message.id(code) + // If at least one portion of the message is styled, we need to + // "pre-style" the message + let mut title = if msgs.iter().any(|(_, style)| style != &crate::Style::NoStyle) { + annotation_level + .clone() + .secondary_title(Cow::Owned(self.pre_style_msgs(msgs, *level, args))) + } else { + annotation_level.clone().primary_title(self.translator.translate_messages(msgs, args)) + }; + + if let Some(c) = code { + title = title.id(c.to_string()); + if let TerminalUrl::Yes = self.terminal_url { + title = title.id_url(format!("https://doc.rust-lang.org/error_codes/{c}.html")); } - // FIXME(#59346): Figure out if we can _always_ print to stderr or not. - // `emitter.rs` has the `Destination` enum that lists various possible output - // destinations. - let renderer = Renderer::plain().anonymized_line_numbers(self.ui_testing); - eprintln!("{}", renderer.render(message)) } - // FIXME(#59346): Is it ok to return None if there's no source_map? + + let mut report = vec![]; + let mut group = Group::with_title(title); + + // If we don't have span information, emit and exit + let Some(sm) = self.sm.as_ref() else { + group = group.elements(children.iter().map(|c| { + let msg = self.translator.translate_messages(&c.messages, args).to_string(); + let level = annotation_level_for_level(c.level); + level.message(msg) + })); + + report.push(group); + if let Err(e) = emit_to_destination( + renderer.render(&report), + level, + &mut self.dst, + self.short_message, + ) { + panic!("failed to emit error: {e}"); + } + return; + }; + + let mut file_ann = collect_annotations(args, msp, sm, &self.translator); + + // Make sure our primary file comes first + let primary_span = msp.primary_span().unwrap_or_default(); + if !primary_span.is_dummy() { + let primary_lo = sm.lookup_char_pos(primary_span.lo()); + if let Ok(pos) = file_ann.binary_search_by(|(f, _)| f.name.cmp(&primary_lo.file.name)) { + file_ann.swap(0, pos); + } + + for (file_idx, (file, annotations)) in file_ann.into_iter().enumerate() { + if should_show_source_code(&self.ignored_directories_in_source_blocks, sm, &file) { + if let Some(snippet) = self.annotated_snippet(annotations, &file.name, sm) { + group = group.element(snippet); + } + // we can't annotate anything if the source is unavailable. + } else if !self.short_message { + // We'll just print unannotated messages + group = self.unannotated_messages( + annotations, + &file.name, + sm, + file_idx, + &mut report, + group, + &annotation_level, + ); + // If this is the last annotation for a file, and + // this is the last file, and the first child is a + // "secondary" message, we need to add padding + // ╭▸ /rustc/FAKE_PREFIX/library/core/src/clone.rs:236:13 + // │ + // ├ note: the late bound lifetime parameter + // │ (<- It adds *this*) + // ╰ warning: this was previously accepted + if let Some(c) = children.first() + && (!c.span.has_primary_spans() && !c.span.has_span_labels()) + { + group = group.element(Padding); + } + } + } + } + + for c in children { + let level = annotation_level_for_level(c.level); + + // If at least one portion of the message is styled, we need to + // "pre-style" the message + let msg = if c.messages.iter().any(|(_, style)| style != &crate::Style::NoStyle) { + Cow::Owned(self.pre_style_msgs(&c.messages, c.level, args)) + } else { + self.translator.translate_messages(&c.messages, args) + }; + + // This is a secondary message with no span info + if !c.span.has_primary_spans() && !c.span.has_span_labels() { + group = group.element(level.clone().message(msg)); + continue; + } + + report.push(std::mem::replace( + &mut group, + Group::with_title(level.clone().secondary_title(msg)), + )); + + let mut file_ann = collect_annotations(args, &c.span, sm, &self.translator); + let primary_span = c.span.primary_span().unwrap_or_default(); + if !primary_span.is_dummy() { + let primary_lo = sm.lookup_char_pos(primary_span.lo()); + if let Ok(pos) = + file_ann.binary_search_by(|(f, _)| f.name.cmp(&primary_lo.file.name)) + { + file_ann.swap(0, pos); + } + } + + for (file_idx, (file, annotations)) in file_ann.into_iter().enumerate() { + if should_show_source_code(&self.ignored_directories_in_source_blocks, sm, &file) { + if let Some(snippet) = self.annotated_snippet(annotations, &file.name, sm) { + group = group.element(snippet); + } + // we can't annotate anything if the source is unavailable. + } else if !self.short_message { + // We'll just print unannotated messages + group = self.unannotated_messages( + annotations, + &file.name, + sm, + file_idx, + &mut report, + group, + &level, + ); + } + } + } + + let suggestions_expected = suggestions + .iter() + .filter(|s| { + matches!( + s.style, + SuggestionStyle::HideCodeInline + | SuggestionStyle::ShowCode + | SuggestionStyle::ShowAlways + ) + }) + .count(); + for suggestion in suggestions { + match suggestion.style { + SuggestionStyle::CompletelyHidden => { + // do not display this suggestion, it is meant only for tools + } + SuggestionStyle::HideCodeAlways => { + let msg = self + .translator + .translate_messages(&[(suggestion.msg.to_owned(), Style::HeaderMsg)], args); + group = group.element(annotate_snippets::Level::HELP.message(msg)); + } + SuggestionStyle::HideCodeInline + | SuggestionStyle::ShowCode + | SuggestionStyle::ShowAlways => { + let substitutions = suggestion + .substitutions + .into_iter() + .filter_map(|mut subst| { + // Suggestions coming from macros can have malformed spans. This is a heavy + // handed approach to avoid ICEs by ignoring the suggestion outright. + let invalid = + subst.parts.iter().any(|item| sm.is_valid_span(item.span).is_err()); + if invalid { + debug!("suggestion contains an invalid span: {:?}", subst); + } + + // Assumption: all spans are in the same file, and all spans + // are disjoint. Sort in ascending order. + subst.parts.sort_by_key(|part| part.span.lo()); + // Verify the assumption that all spans are disjoint + assert_eq!( + subst.parts.array_windows().find(|[a, b]| a.span.overlaps(b.span)), + None, + "all spans must be disjoint", + ); + + // Account for cases where we are suggesting the same code that's already + // there. This shouldn't happen often, but in some cases for multipart + // suggestions it's much easier to handle it here than in the origin. + subst.parts.retain(|p| is_different(sm, &p.snippet, p.span)); + + let item_span = subst.parts.first()?; + let file = sm.lookup_source_file(item_span.span.lo()); + if !invalid + && should_show_source_code( + &self.ignored_directories_in_source_blocks, + sm, + &file, + ) + { + Some(subst) + } else { + None + } + }) + .collect::>(); + + if substitutions.is_empty() { + continue; + } + let mut msg = self + .translator + .translate_message(&suggestion.msg, args) + .map_err(Report::new) + .unwrap() + .to_string(); + + let lo = substitutions + .iter() + .find_map(|sub| sub.parts.first().map(|p| p.span.lo())) + .unwrap(); + let file = sm.lookup_source_file(lo); + + let filename = + sm.filename_for_diagnostics(&file.name).to_string_lossy().to_string(); + + let other_suggestions = substitutions.len().saturating_sub(MAX_SUGGESTIONS); + + let subs = substitutions + .into_iter() + .take(MAX_SUGGESTIONS) + .filter_map(|sub| { + let mut confusion_type = ConfusionType::None; + for part in &sub.parts { + let part_confusion = + detect_confusion_type(sm, &part.snippet, part.span); + confusion_type = confusion_type.combine(part_confusion); + } + + if !matches!(confusion_type, ConfusionType::None) { + msg.push_str(confusion_type.label_text()); + } + + let mut parts = sub + .parts + .into_iter() + .filter_map(|p| { + if is_different(sm, &p.snippet, p.span) { + Some((p.span, p.snippet)) + } else { + None + } + }) + .collect::>(); + + if parts.is_empty() { + None + } else { + let spans = parts.iter().map(|(span, _)| *span).collect::>(); + // The suggestion adds an entire line of code, ending on a newline, so we'll also + // print the *following* line, to provide context of what we're advising people to + // do. Otherwise you would only see contextless code that can be confused for + // already existing code, despite the colors and UI elements. + // We special case `#[derive(_)]\n` and other attribute suggestions, because those + // are the ones where context is most useful. + let fold = if let [(p, snippet)] = &mut parts[..] + && snippet.trim().starts_with("#[") + // This allows for spaces to come between the attribute and the newline + && snippet.trim().ends_with("]") + && snippet.ends_with('\n') + && p.hi() == p.lo() + && let Ok(b) = sm.span_to_prev_source(*p) + && let b = b.rsplit_once('\n').unwrap_or_else(|| ("", &b)).1 + && b.trim().is_empty() + { + // FIXME: This is a hack: + // The span for attribute suggestions often times points to the + // beginning of an item, disregarding leading whitespace. This + // causes the attribute to be properly indented, but leaves original + // item without indentation when rendered. + // This fixes that problem by adjusting the span to point to the start + // of the whitespace, and adds the whitespace to the replacement. + // + // Source: " extern "custom" fn negate(a: i64) -> i64 {\n" + // Span: 4..4 + // Replacement: "#[unsafe(naked)]\n" + // + // Before: + // help: convert this to an `#[unsafe(naked)]` function + // | + // LL + #[unsafe(naked)] + // LL | extern "custom" fn negate(a: i64) -> i64 { + // | + // + // After + // help: convert this to an `#[unsafe(naked)]` function + // | + // LL + #[unsafe(naked)] + // LL | extern "custom" fn negate(a: i64) -> i64 { + // | + if !b.is_empty() && !snippet.ends_with(b) { + snippet.insert_str(0, b); + let offset = BytePos(b.len() as u32); + *p = p.with_lo(p.lo() - offset).shrink_to_lo(); + } + false + } else { + true + }; + + if let Some((bounding_span, source, line_offset)) = + shrink_file(spans.as_slice(), &file.name, sm) + { + let adj_lo = bounding_span.lo().to_usize(); + Some( + Snippet::source(source) + .line_start(line_offset) + .path(filename.clone()) + .fold(fold) + .patches(parts.into_iter().map( + |(span, replacement)| { + let lo = + span.lo().to_usize().saturating_sub(adj_lo); + let hi = + span.hi().to_usize().saturating_sub(adj_lo); + + Patch::new(lo..hi, replacement) + }, + )), + ) + } else { + None + } + } + }) + .collect::>(); + if !subs.is_empty() { + report.push(std::mem::replace( + &mut group, + Group::with_title(annotate_snippets::Level::HELP.secondary_title(msg)), + )); + + group = group.elements(subs); + if other_suggestions > 0 { + group = group.element( + annotate_snippets::Level::NOTE.no_name().message(format!( + "and {} other candidate{}", + other_suggestions, + pluralize!(other_suggestions) + )), + ); + } + } + } + } + } + + // FIXME: This hack should be removed once annotate_snippets is the + // default emitter. + if suggestions_expected > 0 && report.is_empty() { + group = group.element(Padding); + } + + if !group.is_empty() { + report.push(group); + } + if let Err(e) = + emit_to_destination(renderer.render(&report), level, &mut self.dst, self.short_message) + { + panic!("failed to emit error: {e}"); + } + } + + fn renderer(&self) -> Renderer { + let width = if let Some(width) = self.diagnostic_width { + width + } else if self.ui_testing || cfg!(miri) { + DEFAULT_TERM_WIDTH + } else { + termize::dimensions().map(|(w, _)| w).unwrap_or(DEFAULT_TERM_WIDTH) + }; + let decor_style = match self.theme { + OutputTheme::Ascii => annotate_snippets::renderer::DecorStyle::Ascii, + OutputTheme::Unicode => annotate_snippets::renderer::DecorStyle::Unicode, + }; + + match self.dst.current_choice() { + ColorChoice::AlwaysAnsi | ColorChoice::Always | ColorChoice::Auto => Renderer::styled(), + ColorChoice::Never => Renderer::plain(), + } + .term_width(width) + .anonymized_line_numbers(self.ui_testing) + .decor_style(decor_style) + .short_message(self.short_message) + } + + fn pre_style_msgs( + &self, + msgs: &[(DiagMessage, Style)], + level: Level, + args: &FluentArgs<'_>, + ) -> String { + msgs.iter() + .filter_map(|(m, style)| { + let text = self.translator.translate_message(m, args).map_err(Report::new).unwrap(); + let style = style.anstyle(level); + if text.is_empty() { None } else { Some(format!("{style}{text}{style:#}")) } + }) + .collect() + } + + fn annotated_snippet<'a>( + &self, + annotations: Vec, + file_name: &FileName, + sm: &Arc, + ) -> Option>> { + let spans = annotations.iter().map(|a| a.span).collect::>(); + if let Some((bounding_span, source, offset_line)) = shrink_file(&spans, file_name, sm) { + let adj_lo = bounding_span.lo().to_usize(); + let filename = sm.filename_for_diagnostics(file_name).to_string_lossy().to_string(); + Some(Snippet::source(source).line_start(offset_line).path(filename).annotations( + annotations.into_iter().map(move |a| { + let lo = a.span.lo().to_usize().saturating_sub(adj_lo); + let hi = a.span.hi().to_usize().saturating_sub(adj_lo); + let ann = a.kind.span(lo..hi); + if let Some(label) = a.label { ann.label(label) } else { ann } + }), + )) + } else { + None + } + } + + fn unannotated_messages<'a>( + &self, + annotations: Vec, + file_name: &FileName, + sm: &Arc, + file_idx: usize, + report: &mut Vec>, + mut group: Group<'a>, + level: &annotate_snippets::level::Level<'static>, + ) -> Group<'a> { + let filename = sm.filename_for_diagnostics(file_name).to_string_lossy().to_string(); + let mut line_tracker = vec![]; + for (i, a) in annotations.into_iter().enumerate() { + let lo = sm.lookup_char_pos(a.span.lo()); + let hi = sm.lookup_char_pos(a.span.hi()); + if i == 0 || (a.label.is_some()) { + // Render each new file after the first in its own Group + // ╭▸ $DIR/deriving-meta-unknown-trait.rs:1:10 + // │ + // LL │ #[derive(Eqr)] + // │ ━━━ + // ╰╴ (<- It makes it so *this* will get printed) + // ╭▸ $SRC_DIR/core/src/option.rs:594:0 + // ⸬ $SRC_DIR/core/src/option.rs:602:4 + // │ + // ╰ note: not covered + if i == 0 && file_idx != 0 { + report.push(std::mem::replace(&mut group, Group::with_level(level.clone()))); + } + + if !line_tracker.contains(&lo.line) { + line_tracker.push(lo.line); + // ╭▸ $SRC_DIR/core/src/option.rs:594:0 (<- It adds *this*) + // ⸬ $SRC_DIR/core/src/option.rs:602:4 + // │ + // ╰ note: not covered + group = group.element( + Origin::path(filename.clone()) + .line(sm.doctest_offset_line(file_name, lo.line)) + .char_column(lo.col_display), + ); + } + + if hi.line > lo.line + && a.label.as_ref().is_some_and(|l| !l.is_empty()) + && !line_tracker.contains(&hi.line) + { + line_tracker.push(hi.line); + // ╭▸ $SRC_DIR/core/src/option.rs:594:0 + // ⸬ $SRC_DIR/core/src/option.rs:602:4 (<- It adds *this*) + // │ + // ╰ note: not covered + group = group.element( + Origin::path(filename.clone()) + .line(sm.doctest_offset_line(file_name, hi.line)) + .char_column(hi.col_display), + ); + } + + if let Some(label) = a.label + && !label.is_empty() + { + // ╭▸ $SRC_DIR/core/src/option.rs:594:0 + // ⸬ $SRC_DIR/core/src/option.rs:602:4 + // │ (<- It adds *this*) + // ╰ note: not covered (<- and *this*) + group = group + .element(Padding) + .element(annotate_snippets::Level::NOTE.message(label)); + } + } + } + group } } + +fn emit_to_destination( + rendered: String, + lvl: &Level, + dst: &mut Destination, + short_message: bool, +) -> io::Result<()> { + use crate::lock; + let _buffer_lock = lock::acquire_global_lock("rustc_errors"); + writeln!(dst, "{rendered}")?; + if !short_message && !lvl.is_failure_note() { + writeln!(dst)?; + } + dst.flush()?; + Ok(()) +} + +#[derive(Debug)] +struct Annotation { + kind: AnnotationKind, + span: Span, + label: Option, +} + +fn collect_annotations( + args: &FluentArgs<'_>, + msp: &MultiSpan, + sm: &Arc, + translator: &Translator, +) -> Vec<(Arc, Vec)> { + let mut output: Vec<(Arc, Vec)> = vec![]; + + for SpanLabel { span, is_primary, label } in msp.span_labels() { + // If we don't have a useful span, pick the primary span if that exists. + // Worst case we'll just print an error at the top of the main file. + let span = match (span.is_dummy(), msp.primary_span()) { + (_, None) | (false, _) => span, + (true, Some(span)) => span, + }; + let file = sm.lookup_source_file(span.lo()); + + let kind = if is_primary { AnnotationKind::Primary } else { AnnotationKind::Context }; + + let label = label.as_ref().map(|m| { + normalize_whitespace( + &translator.translate_message(m, args).map_err(Report::new).unwrap(), + ) + }); + + let ann = Annotation { kind, span, label }; + if sm.is_valid_span(ann.span).is_ok() { + // Look through each of our files for the one we're adding to. We + // use each files `stable_id` to avoid issues with file name + // collisions when multiple versions of the same crate are present + // in the dependency graph + if let Some((_, annotations)) = + output.iter_mut().find(|(f, _)| f.stable_id == file.stable_id) + { + annotations.push(ann); + } else { + output.push((file, vec![ann])); + } + } + } + output +} + +fn shrink_file( + spans: &[Span], + file_name: &FileName, + sm: &Arc, +) -> Option<(Span, String, usize)> { + let lo_byte = spans.iter().map(|s| s.lo()).min()?; + let lo_loc = sm.lookup_char_pos(lo_byte); + let lo = lo_loc.file.line_bounds(lo_loc.line.saturating_sub(1)).start; + + let hi_byte = spans.iter().map(|s| s.hi()).max()?; + let hi_loc = sm.lookup_char_pos(hi_byte); + let hi = lo_loc.file.line_bounds(hi_loc.line.saturating_sub(1)).end; + + let bounding_span = Span::with_root_ctxt(lo, hi); + let source = sm.span_to_snippet(bounding_span).unwrap_or_default(); + let offset_line = sm.doctest_offset_line(file_name, lo_loc.line); + + Some((bounding_span, source, offset_line)) +} diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 220388ffe435..a2acac8b3045 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -133,24 +133,29 @@ pub struct AttributeTemplate { } impl AttributeTemplate { - pub fn suggestions(&self, style: AttrStyle, name: impl std::fmt::Display) -> Vec { + pub fn suggestions( + &self, + style: Option, + name: impl std::fmt::Display, + ) -> Vec { let mut suggestions = vec![]; - let inner = match style { - AttrStyle::Outer => "", - AttrStyle::Inner => "!", + let (start, end) = match style { + Some(AttrStyle::Outer) => ("#[", "]"), + Some(AttrStyle::Inner) => ("#![", "]"), + None => ("", ""), }; if self.word { - suggestions.push(format!("#{inner}[{name}]")); + suggestions.push(format!("{start}{name}{end}")); } if let Some(descr) = self.list { for descr in descr { - suggestions.push(format!("#{inner}[{name}({descr})]")); + suggestions.push(format!("{start}{name}({descr}){end}")); } } - suggestions.extend(self.one_of.iter().map(|&word| format!("#{inner}[{name}({word})]"))); + suggestions.extend(self.one_of.iter().map(|&word| format!("{start}{name}({word}){end}"))); if let Some(descr) = self.name_value_str { for descr in descr { - suggestions.push(format!("#{inner}[{name} = \"{descr}\"]")); + suggestions.push(format!("{start}{name} = \"{descr}\"{end}")); } } suggestions.sort(); diff --git a/compiler/rustc_feature/src/removed.rs b/compiler/rustc_feature/src/removed.rs index 539d67e0b6bc..a7584df8927e 100644 --- a/compiler/rustc_feature/src/removed.rs +++ b/compiler/rustc_feature/src/removed.rs @@ -102,9 +102,9 @@ declare_features! ( /// Allows deriving traits as per `SmartPointer` specification (removed, derive_smart_pointer, "1.84.0", Some(123430), Some("replaced by `CoercePointee`"), 131284), /// Tells rustdoc to automatically generate `#[doc(cfg(...))]`. - (removed, doc_auto_cfg, "CURRENT_RUSTC_VERSION", Some(43781), Some("merged into `doc_cfg`"), 138907), + (removed, doc_auto_cfg, "1.92.0", Some(43781), Some("merged into `doc_cfg`"), 138907), /// Allows `#[doc(cfg_hide(...))]`. - (removed, doc_cfg_hide, "CURRENT_RUSTC_VERSION", Some(43781), Some("merged into `doc_cfg`"), 138907), + (removed, doc_cfg_hide, "1.92.0", Some(43781), Some("merged into `doc_cfg`"), 138907), /// Allows using `#[doc(keyword = "...")]`. (removed, doc_keyword, "1.58.0", Some(51315), Some("merged into `#![feature(rustdoc_internals)]`"), 90420), diff --git a/compiler/rustc_hir/src/definitions.rs b/compiler/rustc_hir/src/definitions.rs index 698406d53a43..07d5bcdd6ee9 100644 --- a/compiler/rustc_hir/src/definitions.rs +++ b/compiler/rustc_hir/src/definitions.rs @@ -302,6 +302,10 @@ pub enum DefPathData { Ctor, /// A constant expression (see `{ast,hir}::AnonConst`). AnonConst, + /// A constant expression created during AST->HIR lowering.. + LateAnonConst, + /// A fresh anonymous lifetime created by desugaring elided lifetimes. + DesugaredAnonymousLifetime, /// An existential `impl Trait` type node. /// Argument position `impl Trait` have a `TypeNs` with their pretty-printed name. OpaqueTy, @@ -454,6 +458,8 @@ impl DefPathData { TypeNs(name) | ValueNs(name) | MacroNs(name) | LifetimeNs(name) | OpaqueLifetime(name) => Some(name), + DesugaredAnonymousLifetime => Some(kw::UnderscoreLifetime), + Impl | ForeignMod | CrateRoot @@ -462,6 +468,7 @@ impl DefPathData { | Closure | Ctor | AnonConst + | LateAnonConst | OpaqueTy | AnonAssocTy(..) | SyntheticCoroutineBody @@ -475,6 +482,8 @@ impl DefPathData { TypeNs(name) | ValueNs(name) | MacroNs(name) | LifetimeNs(name) | AnonAssocTy(name) | OpaqueLifetime(name) => Some(name), + DesugaredAnonymousLifetime => Some(kw::UnderscoreLifetime), + Impl | ForeignMod | CrateRoot @@ -483,6 +492,7 @@ impl DefPathData { | Closure | Ctor | AnonConst + | LateAnonConst | OpaqueTy | SyntheticCoroutineBody | NestedStatic => None, @@ -502,7 +512,8 @@ impl DefPathData { GlobalAsm => DefPathDataName::Anon { namespace: sym::global_asm }, Closure => DefPathDataName::Anon { namespace: sym::closure }, Ctor => DefPathDataName::Anon { namespace: sym::constructor }, - AnonConst => DefPathDataName::Anon { namespace: sym::constant }, + AnonConst | LateAnonConst => DefPathDataName::Anon { namespace: sym::constant }, + DesugaredAnonymousLifetime => DefPathDataName::Named(kw::UnderscoreLifetime), OpaqueTy => DefPathDataName::Anon { namespace: sym::opaque }, AnonAssocTy(..) => DefPathDataName::Anon { namespace: sym::anon_assoc }, SyntheticCoroutineBody => DefPathDataName::Anon { namespace: sym::synthetic }, diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 90bf82f15f81..8b55a0d73299 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -2460,6 +2460,12 @@ impl Expr<'_> { } } + /// If this is a desugared range expression, + /// returns the span of the range without desugaring context. + pub fn range_span(&self) -> Option { + is_range_literal(self).then(|| self.span.parent_callsite().unwrap()) + } + /// Check if expression is an integer literal that can be used /// where `usize` is expected. pub fn is_size_lit(&self) -> bool { @@ -2969,8 +2975,7 @@ pub enum LocalSource { /// A desugared `.await`. AwaitDesugar, /// A desugared `expr = expr`, where the LHS is a tuple, struct, array or underscore expression. - /// The span is that of the `=` sign. - AssignDesugar(Span), + AssignDesugar, /// A contract `#[ensures(..)]` attribute injects a let binding for the check that runs at point of return. Contract, } @@ -5007,7 +5012,7 @@ mod size_asserts { static_assert_size!(ImplItemKind<'_>, 40); static_assert_size!(Item<'_>, 88); static_assert_size!(ItemKind<'_>, 64); - static_assert_size!(LetStmt<'_>, 72); + static_assert_size!(LetStmt<'_>, 64); static_assert_size!(Param<'_>, 32); static_assert_size!(Pat<'_>, 80); static_assert_size!(PatKind<'_>, 56); diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 95b47c8aba67..25ab91ebc9cf 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -12,9 +12,7 @@ use rustc_hir::def::{CtorKind, DefKind}; use rustc_hir::{LangItem, Node, attrs, find_attr, intravisit}; use rustc_infer::infer::{RegionVariableOrigin, TyCtxtInferExt}; use rustc_infer::traits::{Obligation, ObligationCauseCode, WellFormedLoc}; -use rustc_lint_defs::builtin::{ - REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS, UNSUPPORTED_CALLING_CONVENTIONS, -}; +use rustc_lint_defs::builtin::{REPR_TRANSPARENT_NON_ZST_FIELDS, UNSUPPORTED_CALLING_CONVENTIONS}; use rustc_middle::hir::nested_filter; use rustc_middle::middle::resolve_bound_vars::ResolvedArg; use rustc_middle::middle::stability::EvalResult; @@ -1509,8 +1507,25 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>) } let typing_env = ty::TypingEnv::non_body_analysis(tcx, adt.did()); - // For each field, figure out if it's known to have "trivial" layout (i.e., is a 1-ZST), with - // "known" respecting #[non_exhaustive] attributes. + // For each field, figure out if it has "trivial" layout (i.e., is a 1-ZST). + // Even some 1-ZST fields are not allowed though, if they have `non_exhaustive` or private + // fields or `repr(C)`. We call those fields "unsuited". + struct FieldInfo<'tcx> { + span: Span, + trivial: bool, + unsuited: Option>, + } + struct UnsuitedInfo<'tcx> { + /// The source of the problem, a type that is found somewhere within the field type. + ty: Ty<'tcx>, + reason: UnsuitedReason, + } + enum UnsuitedReason { + NonExhaustive, + PrivateField, + ReprC, + } + let field_infos = adt.all_fields().map(|field| { let ty = field.ty(tcx, GenericArgs::identity_for_item(tcx, field.did)); let layout = tcx.layout_of(typing_env.as_query_input(ty)); @@ -1518,22 +1533,20 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>) let span = tcx.hir_span_if_local(field.did).unwrap(); let trivial = layout.is_ok_and(|layout| layout.is_1zst()); if !trivial { - return (span, trivial, None); + // No need to even compute `unsuited`. + return FieldInfo { span, trivial, unsuited: None }; } - // Even some 1-ZST fields are not allowed though, if they have `non_exhaustive`. - fn check_non_exhaustive<'tcx>( + fn check_unsuited<'tcx>( tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>, - t: Ty<'tcx>, - ) -> ControlFlow<(&'static str, DefId, GenericArgsRef<'tcx>, bool)> { + ty: Ty<'tcx>, + ) -> ControlFlow> { // We can encounter projections during traversal, so ensure the type is normalized. - let t = tcx.try_normalize_erasing_regions(typing_env, t).unwrap_or(t); - match t.kind() { - ty::Tuple(list) => { - list.iter().try_for_each(|t| check_non_exhaustive(tcx, typing_env, t)) - } - ty::Array(ty, _) => check_non_exhaustive(tcx, typing_env, *ty), + let ty = tcx.try_normalize_erasing_regions(typing_env, ty).unwrap_or(ty); + match ty.kind() { + ty::Tuple(list) => list.iter().try_for_each(|t| check_unsuited(tcx, typing_env, t)), + ty::Array(ty, _) => check_unsuited(tcx, typing_env, *ty), ty::Adt(def, args) => { if !def.did().is_local() && !find_attr!( @@ -1548,28 +1561,36 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>) .any(ty::VariantDef::is_field_list_non_exhaustive); let has_priv = def.all_fields().any(|f| !f.vis.is_public()); if non_exhaustive || has_priv { - return ControlFlow::Break(( - def.descr(), - def.did(), - args, - non_exhaustive, - )); + return ControlFlow::Break(UnsuitedInfo { + ty, + reason: if non_exhaustive { + UnsuitedReason::NonExhaustive + } else { + UnsuitedReason::PrivateField + }, + }); } } + if def.repr().c() { + return ControlFlow::Break(UnsuitedInfo { + ty, + reason: UnsuitedReason::ReprC, + }); + } def.all_fields() .map(|field| field.ty(tcx, args)) - .try_for_each(|t| check_non_exhaustive(tcx, typing_env, t)) + .try_for_each(|t| check_unsuited(tcx, typing_env, t)) } _ => ControlFlow::Continue(()), } } - (span, trivial, check_non_exhaustive(tcx, typing_env, ty).break_value()) + FieldInfo { span, trivial, unsuited: check_unsuited(tcx, typing_env, ty).break_value() } }); let non_trivial_fields = field_infos .clone() - .filter_map(|(span, trivial, _non_exhaustive)| if !trivial { Some(span) } else { None }); + .filter_map(|field| if !field.trivial { Some(field.span) } else { None }); let non_trivial_count = non_trivial_fields.clone().count(); if non_trivial_count >= 2 { bad_non_zero_sized_fields( @@ -1581,36 +1602,40 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>) ); return; } - let mut prev_non_exhaustive_1zst = false; - for (span, _trivial, non_exhaustive_1zst) in field_infos { - if let Some((descr, def_id, args, non_exhaustive)) = non_exhaustive_1zst { + + let mut prev_unsuited_1zst = false; + for field in field_infos { + if let Some(unsuited) = field.unsuited { + assert!(field.trivial); // If there are any non-trivial fields, then there can be no non-exhaustive 1-zsts. // Otherwise, it's only an issue if there's >1 non-exhaustive 1-zst. - if non_trivial_count > 0 || prev_non_exhaustive_1zst { + if non_trivial_count > 0 || prev_unsuited_1zst { tcx.node_span_lint( - REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS, + REPR_TRANSPARENT_NON_ZST_FIELDS, tcx.local_def_id_to_hir_id(adt.did().expect_local()), - span, + field.span, |lint| { - lint.primary_message( - "zero-sized fields in `repr(transparent)` cannot \ - contain external non-exhaustive types", - ); - let note = if non_exhaustive { - "is marked with `#[non_exhaustive]`" - } else { - "contains private fields" + let title = match unsuited.reason { + UnsuitedReason::NonExhaustive => "external non-exhaustive types", + UnsuitedReason::PrivateField => "external types with private fields", + UnsuitedReason::ReprC => "`repr(C)` types", + }; + lint.primary_message( + format!("zero-sized fields in `repr(transparent)` cannot contain {title}"), + ); + let note = match unsuited.reason { + UnsuitedReason::NonExhaustive => "is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future.", + UnsuitedReason::PrivateField => "contains private fields, so it could become non-zero-sized in the future.", + UnsuitedReason::ReprC => "is a `#[repr(C)]` type, so it is not guaranteed to be zero-sized on all targets.", }; - let field_ty = tcx.def_path_str_with_args(def_id, args); lint.note(format!( - "this {descr} contains `{field_ty}`, which {note}, \ - and makes it not a breaking change to become \ - non-zero-sized in the future." + "this field contains `{field_ty}`, which {note}", + field_ty = unsuited.ty, )); }, - ) + ); } else { - prev_non_exhaustive_1zst = true; + prev_unsuited_1zst = true; } } } diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs index 67284e162156..6b51e3157961 100644 --- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs +++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs @@ -12,7 +12,9 @@ use tracing::{debug, instrument}; use super::ItemCtxt; use super::predicates_of::assert_only_contains_predicates_from; -use crate::hir_ty_lowering::{HirTyLowerer, OverlappingAsssocItemConstraints, PredicateFilter}; +use crate::hir_ty_lowering::{ + HirTyLowerer, ImpliedBoundsContext, OverlappingAsssocItemConstraints, PredicateFilter, +}; /// For associated types we include both bounds written on the type /// (`type X: Trait`) and predicates from the trait: `where Self::X: Trait`. @@ -52,15 +54,20 @@ fn associated_type_bounds<'tcx>( | PredicateFilter::SelfTraitThatDefines(_) | PredicateFilter::SelfAndAssociatedTypeBounds => { // Implicit bounds are added to associated types unless a `?Trait` bound is found. - icx.lowerer().add_sizedness_bounds( + icx.lowerer().add_implicit_sizedness_bounds( &mut bounds, item_ty, hir_bounds, - None, - None, + ImpliedBoundsContext::AssociatedTypeOrImplTrait, + span, + ); + icx.lowerer().add_default_traits( + &mut bounds, + item_ty, + hir_bounds, + ImpliedBoundsContext::AssociatedTypeOrImplTrait, span, ); - icx.lowerer().add_default_traits(&mut bounds, item_ty, hir_bounds, None, span); // Also collect `where Self::Assoc: Trait` from the parent trait's where clauses. let trait_def_id = tcx.local_parent(assoc_item_def_id); @@ -372,15 +379,20 @@ fn opaque_type_bounds<'tcx>( | PredicateFilter::SelfOnly | PredicateFilter::SelfTraitThatDefines(_) | PredicateFilter::SelfAndAssociatedTypeBounds => { - icx.lowerer().add_sizedness_bounds( + icx.lowerer().add_implicit_sizedness_bounds( &mut bounds, item_ty, hir_bounds, - None, - None, + ImpliedBoundsContext::AssociatedTypeOrImplTrait, + span, + ); + icx.lowerer().add_default_traits( + &mut bounds, + item_ty, + hir_bounds, + ImpliedBoundsContext::AssociatedTypeOrImplTrait, span, ); - icx.lowerer().add_default_traits(&mut bounds, item_ty, hir_bounds, None, span); } //`ConstIfConst` is only interested in `[const]` bounds. PredicateFilter::ConstIfConst | PredicateFilter::SelfConstIfConst => {} diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index e66accc7dcff..79aaa0cb7970 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -19,7 +19,8 @@ use crate::collect::ItemCtxt; use crate::constrained_generic_params as cgp; use crate::delegation::inherit_predicates_for_delegation_item; use crate::hir_ty_lowering::{ - HirTyLowerer, OverlappingAsssocItemConstraints, PredicateFilter, RegionInferReason, + HirTyLowerer, ImpliedBoundsContext, OverlappingAsssocItemConstraints, PredicateFilter, + RegionInferReason, }; /// Returns a list of all type predicates (explicit and implicit) for the definition with @@ -189,19 +190,18 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen PredicateFilter::All, OverlappingAsssocItemConstraints::Allowed, ); - icx.lowerer().add_sizedness_bounds( + icx.lowerer().add_implicit_sizedness_bounds( &mut bounds, tcx.types.self_param, self_bounds, - None, - Some(def_id), + ImpliedBoundsContext::TraitDef(def_id), span, ); - icx.lowerer().add_default_super_traits( - def_id, + icx.lowerer().add_default_traits( &mut bounds, + tcx.types.self_param, self_bounds, - hir_generics, + ImpliedBoundsContext::TraitDef(def_id), span, ); predicates.extend(bounds); @@ -229,19 +229,18 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen let param_ty = icx.lowerer().lower_ty_param(param.hir_id); let mut bounds = Vec::new(); // Implicit bounds are added to type params unless a `?Trait` bound is found - icx.lowerer().add_sizedness_bounds( + icx.lowerer().add_implicit_sizedness_bounds( &mut bounds, param_ty, &[], - Some((param.def_id, hir_generics.predicates)), - None, + ImpliedBoundsContext::TyParam(param.def_id, hir_generics.predicates), param.span, ); icx.lowerer().add_default_traits( &mut bounds, param_ty, &[], - Some((param.def_id, hir_generics.predicates)), + ImpliedBoundsContext::TyParam(param.def_id, hir_generics.predicates), param.span, ); trace!(?bounds); @@ -676,11 +675,18 @@ pub(super) fn implied_predicates_with_filter<'tcx>( | PredicateFilter::SelfOnly | PredicateFilter::SelfTraitThatDefines(_) | PredicateFilter::SelfAndAssociatedTypeBounds => { - icx.lowerer().add_default_super_traits( - trait_def_id, + icx.lowerer().add_implicit_sizedness_bounds( &mut bounds, + self_param_ty, superbounds, - generics, + ImpliedBoundsContext::TraitDef(trait_def_id), + item.span, + ); + icx.lowerer().add_default_traits( + &mut bounds, + self_param_ty, + superbounds, + ImpliedBoundsContext::TraitDef(trait_def_id), item.span, ); } diff --git a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs index a02990fe4aba..870a7b656386 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs @@ -242,6 +242,16 @@ pub(super) fn find_opaque_ty_constraints_for_rpit<'tcx>( owner_def_id: LocalDefId, opaque_types_from: DefiningScopeKind, ) -> Ty<'tcx> { + // When an opaque type is stranded, its hidden type cannot be inferred + // so we should not continue. + if !tcx.opaque_types_defined_by(owner_def_id).contains(&def_id) { + let opaque_type_span = tcx.def_span(def_id); + let guar = tcx + .dcx() + .span_delayed_bug(opaque_type_span, "cannot infer type for stranded opaque type"); + return Ty::new_error(tcx, guar); + } + match opaque_types_from { DefiningScopeKind::HirTypeck => { let tables = tcx.typeck(owner_def_id); diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs index a3cb49e32d80..1832e6e890b9 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs @@ -1,4 +1,3 @@ -use std::assert_matches::assert_matches; use std::ops::ControlFlow; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; @@ -7,7 +6,7 @@ use rustc_errors::struct_span_code_err; use rustc_hir as hir; use rustc_hir::PolyTraitRef; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LocalDefId}; +use rustc_hir::def_id::{CRATE_DEF_ID, DefId}; use rustc_middle::bug; use rustc_middle::ty::{ self as ty, IsSuggestable, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, @@ -18,11 +17,10 @@ use rustc_trait_selection::traits; use smallvec::SmallVec; use tracing::{debug, instrument}; -use super::errors::GenericsArgsErrExtend; use crate::errors; use crate::hir_ty_lowering::{ - AssocItemQSelf, FeedConstTy, HirTyLowerer, OverlappingAsssocItemConstraints, PredicateFilter, - RegionInferReason, + AssocItemQSelf, FeedConstTy, GenericsArgsErrExtend, HirTyLowerer, ImpliedBoundsContext, + OverlappingAsssocItemConstraints, PredicateFilter, RegionInferReason, }; #[derive(Debug, Default)] @@ -62,7 +60,7 @@ impl CollectedSizednessBounds { fn search_bounds_for<'tcx>( hir_bounds: &'tcx [hir::GenericBound<'tcx>], - self_ty_where_predicates: Option<(LocalDefId, &'tcx [hir::WherePredicate<'tcx>])>, + context: ImpliedBoundsContext<'tcx>, mut f: impl FnMut(&'tcx PolyTraitRef<'tcx>), ) { let mut search_bounds = |hir_bounds: &'tcx [hir::GenericBound<'tcx>]| { @@ -76,7 +74,7 @@ fn search_bounds_for<'tcx>( }; search_bounds(hir_bounds); - if let Some((self_ty, where_clause)) = self_ty_where_predicates { + if let ImpliedBoundsContext::TyParam(self_ty, where_clause) = context { for clause in where_clause { if let hir::WherePredicateKind::BoundPredicate(pred) = clause.kind && pred.is_param_bound(self_ty.to_def_id()) @@ -89,10 +87,10 @@ fn search_bounds_for<'tcx>( fn collect_relaxed_bounds<'tcx>( hir_bounds: &'tcx [hir::GenericBound<'tcx>], - self_ty_where_predicates: Option<(LocalDefId, &'tcx [hir::WherePredicate<'tcx>])>, + context: ImpliedBoundsContext<'tcx>, ) -> SmallVec<[&'tcx PolyTraitRef<'tcx>; 1]> { let mut relaxed_bounds: SmallVec<[_; 1]> = SmallVec::new(); - search_bounds_for(hir_bounds, self_ty_where_predicates, |ptr| { + search_bounds_for(hir_bounds, context, |ptr| { if matches!(ptr.modifiers.polarity, hir::BoundPolarity::Maybe(_)) { relaxed_bounds.push(ptr); } @@ -102,11 +100,11 @@ fn collect_relaxed_bounds<'tcx>( fn collect_bounds<'a, 'tcx>( hir_bounds: &'a [hir::GenericBound<'tcx>], - self_ty_where_predicates: Option<(LocalDefId, &'tcx [hir::WherePredicate<'tcx>])>, + context: ImpliedBoundsContext<'tcx>, target_did: DefId, ) -> CollectedBound { let mut collect_into = CollectedBound::default(); - search_bounds_for(hir_bounds, self_ty_where_predicates, |ptr| { + search_bounds_for(hir_bounds, context, |ptr| { if !matches!(ptr.trait_ref.path.res, Res::Def(DefKind::Trait, did) if did == target_did) { return; } @@ -123,17 +121,17 @@ fn collect_bounds<'a, 'tcx>( fn collect_sizedness_bounds<'tcx>( tcx: TyCtxt<'tcx>, hir_bounds: &'tcx [hir::GenericBound<'tcx>], - self_ty_where_predicates: Option<(LocalDefId, &'tcx [hir::WherePredicate<'tcx>])>, + context: ImpliedBoundsContext<'tcx>, span: Span, ) -> CollectedSizednessBounds { let sized_did = tcx.require_lang_item(hir::LangItem::Sized, span); - let sized = collect_bounds(hir_bounds, self_ty_where_predicates, sized_did); + let sized = collect_bounds(hir_bounds, context, sized_did); let meta_sized_did = tcx.require_lang_item(hir::LangItem::MetaSized, span); - let meta_sized = collect_bounds(hir_bounds, self_ty_where_predicates, meta_sized_did); + let meta_sized = collect_bounds(hir_bounds, context, meta_sized_did); let pointee_sized_did = tcx.require_lang_item(hir::LangItem::PointeeSized, span); - let pointee_sized = collect_bounds(hir_bounds, self_ty_where_predicates, pointee_sized_did); + let pointee_sized = collect_bounds(hir_bounds, context, pointee_sized_did); CollectedSizednessBounds { sized, meta_sized, pointee_sized } } @@ -161,13 +159,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { /// bounds are present. /// - On parameters, opaque type, associated types and trait aliases, add a `MetaSized` bound if /// a `?Sized` bound is present. - pub(crate) fn add_sizedness_bounds( + pub(crate) fn add_implicit_sizedness_bounds( &self, bounds: &mut Vec<(ty::Clause<'tcx>, Span)>, self_ty: Ty<'tcx>, hir_bounds: &'tcx [hir::GenericBound<'tcx>], - self_ty_where_predicates: Option<(LocalDefId, &'tcx [hir::WherePredicate<'tcx>])>, - trait_did: Option, + context: ImpliedBoundsContext<'tcx>, span: Span, ) { let tcx = self.tcx(); @@ -181,33 +178,36 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let pointee_sized_did = tcx.require_lang_item(hir::LangItem::PointeeSized, span); // If adding sizedness bounds to a trait, then there are some relevant early exits - if let Some(trait_did) = trait_did { - let trait_did = trait_did.to_def_id(); - // Never add a default supertrait to `PointeeSized`. - if trait_did == pointee_sized_did { - return; + match context { + ImpliedBoundsContext::TraitDef(trait_did) => { + let trait_did = trait_did.to_def_id(); + // Never add a default supertrait to `PointeeSized`. + if trait_did == pointee_sized_did { + return; + } + // Don't add default sizedness supertraits to auto traits because it isn't possible to + // relax an automatically added supertrait on the defn itself. + if tcx.trait_is_auto(trait_did) { + return; + } } - // Don't add default sizedness supertraits to auto traits because it isn't possible to - // relax an automatically added supertrait on the defn itself. - if tcx.trait_is_auto(trait_did) { - return; + ImpliedBoundsContext::TyParam(..) | ImpliedBoundsContext::AssociatedTypeOrImplTrait => { + // Report invalid relaxed bounds. + // FIXME: Since we only call this validation function here in this function, we only + // fully validate relaxed bounds in contexts where we perform + // "sized elaboration". In most cases that doesn't matter because we *usually* + // reject such relaxed bounds outright during AST lowering. + // However, this can easily get out of sync! Ideally, we would perform this step + // where we are guaranteed to catch *all* bounds like in + // `Self::lower_poly_trait_ref`. List of concrete issues: + // FIXME(more_maybe_bounds): We don't call this for trait object tys, supertrait + // bounds, trait alias bounds, assoc type bounds (ATB)! + let bounds = collect_relaxed_bounds(hir_bounds, context); + self.reject_duplicate_relaxed_bounds(bounds); } - } else { - // Report invalid relaxed bounds. - // FIXME: Since we only call this validation function here in this function, we only - // fully validate relaxed bounds in contexts where we perform - // "sized elaboration". In most cases that doesn't matter because we *usually* - // reject such relaxed bounds outright during AST lowering. - // However, this can easily get out of sync! Ideally, we would perform this step - // where we are guaranteed to catch *all* bounds like in - // `Self::lower_poly_trait_ref`. List of concrete issues: - // FIXME(more_maybe_bounds): We don't call this for trait object tys, supertrait - // bounds, trait alias bounds, assoc type bounds (ATB)! - let bounds = collect_relaxed_bounds(hir_bounds, self_ty_where_predicates); - self.reject_duplicate_relaxed_bounds(bounds); } - let collected = collect_sizedness_bounds(tcx, hir_bounds, self_ty_where_predicates, span); + let collected = collect_sizedness_bounds(tcx, hir_bounds, context, span); if (collected.sized.maybe || collected.sized.negative) && !collected.sized.positive && !collected.meta_sized.any() @@ -217,62 +217,33 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // other explicit ones) - this can happen for trait aliases as well as bounds. add_trait_bound(tcx, bounds, self_ty, meta_sized_did, span); } else if !collected.any() { - if trait_did.is_some() { - // If there are no explicit sizedness bounds on a trait then add a default - // `MetaSized` supertrait. - add_trait_bound(tcx, bounds, self_ty, meta_sized_did, span); - } else { - // If there are no explicit sizedness bounds on a parameter then add a default - // `Sized` bound. - let sized_did = tcx.require_lang_item(hir::LangItem::Sized, span); - add_trait_bound(tcx, bounds, self_ty, sized_did, span); + match context { + ImpliedBoundsContext::TraitDef(..) => { + // If there are no explicit sizedness bounds on a trait then add a default + // `MetaSized` supertrait. + add_trait_bound(tcx, bounds, self_ty, meta_sized_did, span); + } + ImpliedBoundsContext::TyParam(..) + | ImpliedBoundsContext::AssociatedTypeOrImplTrait => { + // If there are no explicit sizedness bounds on a parameter then add a default + // `Sized` bound. + let sized_did = tcx.require_lang_item(hir::LangItem::Sized, span); + add_trait_bound(tcx, bounds, self_ty, sized_did, span); + } } } } - /// Adds `experimental_default_bounds` bounds to the supertrait bounds. - pub(crate) fn add_default_super_traits( - &self, - trait_def_id: LocalDefId, - bounds: &mut Vec<(ty::Clause<'tcx>, Span)>, - hir_bounds: &'tcx [hir::GenericBound<'tcx>], - hir_generics: &'tcx hir::Generics<'tcx>, - span: Span, - ) { - assert_matches!(self.tcx().def_kind(trait_def_id), DefKind::Trait | DefKind::TraitAlias); - - // Supertraits for auto trait are unsound according to the unstable book: - // https://doc.rust-lang.org/beta/unstable-book/language-features/auto-traits.html#supertraits - if self.tcx().trait_is_auto(trait_def_id.to_def_id()) { - return; - } - - self.add_default_traits( - bounds, - self.tcx().types.self_param, - hir_bounds, - Some((trait_def_id, hir_generics.predicates)), - span, - ); - } - pub(crate) fn add_default_traits( &self, bounds: &mut Vec<(ty::Clause<'tcx>, Span)>, self_ty: Ty<'tcx>, hir_bounds: &[hir::GenericBound<'tcx>], - self_ty_where_predicates: Option<(LocalDefId, &'tcx [hir::WherePredicate<'tcx>])>, + context: ImpliedBoundsContext<'tcx>, span: Span, ) { self.tcx().default_traits().iter().for_each(|default_trait| { - self.add_default_trait( - *default_trait, - bounds, - self_ty, - hir_bounds, - self_ty_where_predicates, - span, - ); + self.add_default_trait(*default_trait, bounds, self_ty, hir_bounds, context, span); }); } @@ -285,15 +256,23 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { bounds: &mut Vec<(ty::Clause<'tcx>, Span)>, self_ty: Ty<'tcx>, hir_bounds: &[hir::GenericBound<'tcx>], - self_ty_where_predicates: Option<(LocalDefId, &'tcx [hir::WherePredicate<'tcx>])>, + context: ImpliedBoundsContext<'tcx>, span: Span, ) { let tcx = self.tcx(); - let trait_id = tcx.lang_items().get(trait_); - if let Some(trait_id) = trait_id - && self.should_add_default_traits(trait_id, hir_bounds, self_ty_where_predicates) + + // Supertraits for auto trait are unsound according to the unstable book: + // https://doc.rust-lang.org/beta/unstable-book/language-features/auto-traits.html#supertraits + if let ImpliedBoundsContext::TraitDef(trait_did) = context + && self.tcx().trait_is_auto(trait_did.into()) { - add_trait_bound(tcx, bounds, self_ty, trait_id, span); + return; + } + + if let Some(trait_did) = tcx.lang_items().get(trait_) + && self.should_add_default_traits(trait_did, hir_bounds, context) + { + add_trait_bound(tcx, bounds, self_ty, trait_did, span); } } @@ -302,9 +281,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { &self, trait_def_id: DefId, hir_bounds: &'a [hir::GenericBound<'tcx>], - self_ty_where_predicates: Option<(LocalDefId, &'tcx [hir::WherePredicate<'tcx>])>, + context: ImpliedBoundsContext<'tcx>, ) -> bool { - let collected = collect_bounds(hir_bounds, self_ty_where_predicates, trait_def_id); + let collected = collect_bounds(hir_bounds, context, trait_def_id); !self.tcx().has_attr(CRATE_DEF_ID, sym::rustc_no_implicit_bounds) && !collected.any() } diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs index c0b137730892..15d7da3a0070 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs @@ -4,9 +4,9 @@ use rustc_errors::codes::*; use rustc_errors::{ Applicability, Diag, EmissionGuarantee, StashKey, Suggestions, struct_span_code_err, }; -use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; +use rustc_hir::{self as hir, LangItem}; use rustc_lint_defs::builtin::{BARE_TRAIT_OBJECTS, UNUSED_ASSOCIATED_TYPE_BOUNDS}; use rustc_middle::ty::elaborate::ClauseWithSupertraitSpan; use rustc_middle::ty::{ @@ -24,7 +24,8 @@ use tracing::{debug, instrument}; use super::HirTyLowerer; use crate::errors::SelfInTypeAlias; use crate::hir_ty_lowering::{ - GenericArgCountMismatch, OverlappingAsssocItemConstraints, PredicateFilter, RegionInferReason, + GenericArgCountMismatch, ImpliedBoundsContext, OverlappingAsssocItemConstraints, + PredicateFilter, RegionInferReason, }; impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { @@ -76,12 +77,26 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .iter() .map(|&trait_ref| hir::GenericBound::Trait(trait_ref)) .collect::>(), - None, + ImpliedBoundsContext::AssociatedTypeOrImplTrait, span, ); - let (elaborated_trait_bounds, elaborated_projection_bounds) = + let (mut elaborated_trait_bounds, elaborated_projection_bounds) = traits::expand_trait_aliases(tcx, user_written_bounds.iter().copied()); + + // FIXME(sized-hierarchy): https://github.com/rust-lang/rust/pull/142712#issuecomment-3013231794 + debug!(?user_written_bounds, ?elaborated_trait_bounds); + let meta_sized_did = tcx.require_lang_item(LangItem::MetaSized, span); + // Don't strip out `MetaSized` when the user wrote it explicitly, only when it was + // elaborated + if user_written_bounds + .iter() + .all(|(clause, _)| clause.as_trait_clause().map(|p| p.def_id()) != Some(meta_sized_did)) + { + elaborated_trait_bounds.retain(|(pred, _)| pred.def_id() != meta_sized_did); + } + debug!(?user_written_bounds, ?elaborated_trait_bounds); + let (regular_traits, mut auto_traits): (Vec<_>, Vec<_>) = elaborated_trait_bounds .into_iter() .partition(|(trait_ref, _)| !tcx.trait_is_auto(trait_ref.def_id())); diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index 00f909575780..82a931dcca2a 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -56,6 +56,19 @@ use crate::hir_ty_lowering::errors::{GenericsArgsErrExtend, prohibit_assoc_item_ use crate::hir_ty_lowering::generics::{check_generic_arg_count, lower_generic_args}; use crate::middle::resolve_bound_vars as rbv; +/// The context in which an implied bound is being added to a item being lowered (i.e. a sizedness +/// trait or a default trait) +#[derive(Clone, Copy)] +pub(crate) enum ImpliedBoundsContext<'tcx> { + /// An implied bound is added to a trait definition (i.e. a new supertrait), used when adding + /// a default `MetaSized` supertrait + TraitDef(LocalDefId), + /// An implied bound is added to a type parameter + TyParam(LocalDefId, &'tcx [hir::WherePredicate<'tcx>]), + /// An implied bound being added in any other context + AssociatedTypeOrImplTrait, +} + /// A path segment that is semantically allowed to have generic arguments. #[derive(Debug)] pub struct GenericPathSegment(pub DefId, pub usize); @@ -2513,12 +2526,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { PredicateFilter::All, OverlappingAsssocItemConstraints::Allowed, ); - self.add_sizedness_bounds( + self.add_implicit_sizedness_bounds( &mut bounds, self_ty, hir_bounds, - None, - None, + ImpliedBoundsContext::AssociatedTypeOrImplTrait, hir_ty.span, ); self.register_trait_ascription_bounds(bounds, hir_ty.hir_id, hir_ty.span); diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 1e5fea1db9fc..857e4f66489a 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -35,13 +35,13 @@ //! // and are then unable to coerce `&7i32` to `&mut i32`. //! ``` -use std::ops::Deref; +use std::ops::{ControlFlow, Deref}; use rustc_errors::codes::*; use rustc_errors::{Applicability, Diag, struct_span_code_err}; -use rustc_hir as hir; use rustc_hir::attrs::InlineAttr; use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_hir::{self as hir, LangItem}; use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer; use rustc_infer::infer::relate::RelateResult; use rustc_infer::infer::{DefineOpaqueTypes, InferOk, InferResult, RegionVariableOrigin}; @@ -56,6 +56,8 @@ use rustc_middle::ty::error::TypeError; use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt, TypeVisitableExt}; use rustc_span::{BytePos, DUMMY_SP, DesugaringKind, Span}; use rustc_trait_selection::infer::InferCtxtExt as _; +use rustc_trait_selection::solve::inspect::{self, InferCtxtProofTreeExt, ProofTreeVisitor}; +use rustc_trait_selection::solve::{Certainty, Goal, NoSolution}; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; use rustc_trait_selection::traits::{ self, ImplSource, NormalizeExt, ObligationCause, ObligationCauseCode, ObligationCtxt, @@ -639,11 +641,44 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { Adjust::Pointer(PointerCoercion::Unsize), )?; - let mut selcx = traits::SelectionContext::new(self); - // Create an obligation for `Source: CoerceUnsized`. let cause = self.cause(self.cause.span, ObligationCauseCode::Coercion { source, target }); + let pred = ty::TraitRef::new(self.tcx, coerce_unsized_did, [coerce_source, coerce_target]); + let obligation = Obligation::new(self.tcx, cause, self.fcx.param_env, pred); + if self.next_trait_solver() { + coercion.obligations.push(obligation); + + if self + .infcx + .visit_proof_tree( + Goal::new(self.tcx, self.param_env, pred), + &mut CoerceVisitor { fcx: self.fcx, span: self.cause.span }, + ) + .is_break() + { + return Err(TypeError::Mismatch); + } + } else { + self.coerce_unsized_old_solver( + obligation, + &mut coercion, + coerce_unsized_did, + unsize_did, + )?; + } + + Ok(coercion) + } + + fn coerce_unsized_old_solver( + &self, + obligation: Obligation<'tcx, ty::Predicate<'tcx>>, + coercion: &mut InferOk<'tcx, (Vec>, Ty<'tcx>)>, + coerce_unsized_did: DefId, + unsize_did: DefId, + ) -> Result<(), TypeError<'tcx>> { + let mut selcx = traits::SelectionContext::new(self); // Use a FIFO queue for this custom fulfillment procedure. // // A Vec (or SmallVec) is not a natural choice for a queue. However, @@ -651,12 +686,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // and almost never more than 3. By using a SmallVec we avoid an // allocation, at the (very small) cost of (occasionally) having to // shift subsequent elements down when removing the front element. - let mut queue: SmallVec<[PredicateObligation<'tcx>; 4]> = smallvec![Obligation::new( - self.tcx, - cause, - self.fcx.param_env, - ty::TraitRef::new(self.tcx, coerce_unsized_did, [coerce_source, coerce_target]) - )]; + let mut queue: SmallVec<[PredicateObligation<'tcx>; 4]> = smallvec![obligation]; // Keep resolving `CoerceUnsized` and `Unsize` predicates to avoid // emitting a coercion in cases like `Foo<$1>` -> `Foo<$2>`, where @@ -749,7 +779,6 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // with the unsizing - the lack of a coercion should // be silent, as it causes a type mismatch later. } - Ok(Some(ImplSource::UserDefined(impl_source))) => { queue.extend(impl_source.nested); // Certain incoherent `CoerceUnsized` implementations may cause ICEs, @@ -767,7 +796,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { } } - Ok(coercion) + Ok(()) } /// Applies reborrowing for `Pin` @@ -2005,3 +2034,69 @@ impl AsCoercionSite for hir::Arm<'_> { self.body } } + +/// Recursively visit goals to decide whether an unsizing is possible. +/// `Break`s when it isn't, and an error should be raised. +/// `Continue`s when an unsizing ok based on an implementation of the `Unsize` trait / lang item. +struct CoerceVisitor<'a, 'tcx> { + fcx: &'a FnCtxt<'a, 'tcx>, + span: Span, +} + +impl<'tcx> ProofTreeVisitor<'tcx> for CoerceVisitor<'_, 'tcx> { + type Result = ControlFlow<()>; + + fn span(&self) -> Span { + self.span + } + + fn visit_goal(&mut self, goal: &inspect::InspectGoal<'_, 'tcx>) -> Self::Result { + let Some(pred) = goal.goal().predicate.as_trait_clause() else { + return ControlFlow::Continue(()); + }; + + // Make sure this predicate is referring to either an `Unsize` or `CoerceUnsized` trait, + // Otherwise there's nothing to do. + if !self.fcx.tcx.is_lang_item(pred.def_id(), LangItem::Unsize) + && !self.fcx.tcx.is_lang_item(pred.def_id(), LangItem::CoerceUnsized) + { + return ControlFlow::Continue(()); + } + + match goal.result() { + // If we prove the `Unsize` or `CoerceUnsized` goal, continue recursing. + Ok(Certainty::Yes) => ControlFlow::Continue(()), + Err(NoSolution) => { + // Even if we find no solution, continue recursing if we find a single candidate + // for which we're shallowly certain it holds to get the right error source. + if let [only_candidate] = &goal.candidates()[..] + && only_candidate.shallow_certainty() == Certainty::Yes + { + only_candidate.visit_nested_no_probe(self) + } else { + ControlFlow::Break(()) + } + } + Ok(Certainty::Maybe { .. }) => { + // FIXME: structurally normalize? + if self.fcx.tcx.is_lang_item(pred.def_id(), LangItem::Unsize) + && let ty::Dynamic(..) = pred.skip_binder().trait_ref.args.type_at(1).kind() + && let ty::Infer(ty::TyVar(vid)) = *pred.self_ty().skip_binder().kind() + && self.fcx.type_var_is_sized(vid) + { + // We get here when trying to unsize a type variable to a `dyn Trait`, + // knowing that that variable is sized. Unsizing definitely has to happen in that case. + // If the variable weren't sized, we may not need an unsizing coercion. + // In general, we don't want to add coercions too eagerly since it makes error messages much worse. + ControlFlow::Continue(()) + } else if let Some(cand) = goal.unique_applicable_candidate() + && cand.shallow_certainty() == Certainty::Yes + { + cand.visit_nested_no_probe(self) + } else { + ControlFlow::Break(()) + } + } + } + } +} diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 2605aa18b91e..0b1c725ba408 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -2509,11 +2509,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .tcx .sess .source_map() - .span_extend_while_whitespace(range_start.span) + .span_extend_while_whitespace(range_start.expr.span) .shrink_to_hi() - .to(range_end.span); + .to(range_end.expr.span); - err.subdiagnostic(TypeMismatchFruTypo { expr_span: range_start.span, fru_span, expr }); + err.subdiagnostic(TypeMismatchFruTypo { + expr_span: range_start.expr.span, + fru_span, + expr, + }); // Suppress any range expr type mismatches self.dcx().try_steal_replace_and_emit_err( diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 4d1c7be39197..abdb01bcefb2 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -1112,8 +1112,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { hir::Stmt { kind: hir::StmtKind::Let(hir::LetStmt { - source: - hir::LocalSource::AssignDesugar(_), + source: hir::LocalSource::AssignDesugar, .. }), .. diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs index 82a68c4d615a..1ab7ac4c2e36 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs @@ -5,7 +5,7 @@ use rustc_middle::ty::{self, Ty, TypeVisitableExt}; use rustc_span::Span; use rustc_trait_selection::solve::Certainty; use rustc_trait_selection::solve::inspect::{ - InspectConfig, InspectGoal, ProofTreeInferCtxtExt, ProofTreeVisitor, + InferCtxtProofTreeExt, InspectConfig, InspectGoal, ProofTreeVisitor, }; use tracing::{debug, instrument, trace}; diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 5bb717a2a828..d097f8ab8485 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -1666,7 +1666,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { match expr.kind { ExprKind::Struct(QPath::LangItem(LangItem::Range, ..), [start, end], _) => { err.span_suggestion_verbose( - start.span.shrink_to_hi().with_hi(end.span.lo()), + start.expr.span.shrink_to_hi().with_hi(end.expr.span.lo()), "remove the unnecessary `.` operator for a floating point literal", '.', Applicability::MaybeIncorrect, @@ -1674,8 +1674,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { true } ExprKind::Struct(QPath::LangItem(LangItem::RangeFrom, ..), [start], _) => { + let range_span = expr.span.parent_callsite().unwrap(); err.span_suggestion_verbose( - expr.span.with_lo(start.span.hi()), + range_span.with_lo(start.expr.span.hi()), "remove the unnecessary `.` operator for a floating point literal", '.', Applicability::MaybeIncorrect, @@ -1683,8 +1684,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { true } ExprKind::Struct(QPath::LangItem(LangItem::RangeTo, ..), [end], _) => { + let range_span = expr.span.parent_callsite().unwrap(); err.span_suggestion_verbose( - expr.span.until(end.span), + range_span.until(end.expr.span), "remove the unnecessary `.` operator and add an integer part for a floating point literal", "0.", Applicability::MaybeIncorrect, @@ -2693,7 +2695,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { bool, /* suggest `&` or `&mut` type annotation */ )> { let sess = self.sess(); - let sp = expr.span; + let sp = expr.range_span().unwrap_or(expr.span); let sm = sess.source_map(); // If the span is from an external macro, there's no suggestion we can make. diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 8f2e06dd7127..f7df5dafa184 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -3046,46 +3046,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } foreign_preds.sort_by_key(|pred: &&ty::TraitPredicate<'_>| pred.trait_ref.to_string()); - let foreign_def_ids = foreign_preds - .iter() - .filter_map(|pred| match pred.self_ty().kind() { - ty::Adt(def, _) => Some(def.did()), - _ => None, - }) - .collect::>(); - let mut foreign_spans: MultiSpan = foreign_def_ids - .iter() - .filter_map(|def_id| { - let span = self.tcx.def_span(*def_id); - if span.is_dummy() { None } else { Some(span) } - }) - .collect::>() - .into(); - for pred in &foreign_preds { - if let ty::Adt(def, _) = pred.self_ty().kind() { - foreign_spans.push_span_label( - self.tcx.def_span(def.did()), - format!("not implement `{}`", pred.trait_ref.print_trait_sugared()), - ); + + for pred in foreign_preds { + let ty = pred.self_ty(); + let ty::Adt(def, _) = ty.kind() else { continue }; + let span = self.tcx.def_span(def.did()); + if span.is_dummy() { + continue; } - } - if foreign_spans.primary_span().is_some() { - let msg = if let [foreign_pred] = foreign_preds.as_slice() { - format!( - "the foreign item type `{}` doesn't implement `{}`", - foreign_pred.self_ty(), - foreign_pred.trait_ref.print_trait_sugared() - ) - } else { - format!( - "the foreign item type{} {} implement required trait{} for this \ - operation to be valid", - pluralize!(foreign_def_ids.len()), - if foreign_def_ids.len() > 1 { "don't" } else { "doesn't" }, - pluralize!(foreign_preds.len()), - ) - }; - err.span_note(foreign_spans, msg); + let mut mspan: MultiSpan = span.into(); + mspan.push_span_label(span, format!("`{ty}` is defined in another crate")); + err.span_note( + mspan, + format!("`{ty}` does not implement `{}`", pred.trait_ref.print_trait_sugared()), + ); } let preds: Vec<_> = errors diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index 697029e55f7c..50b6fe1ad5ec 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -798,7 +798,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { } else { let predicate = self.tcx().erase_and_anonymize_regions(predicate); if cause.has_infer() || cause.has_placeholders() { - // We can't use the the obligation cause as it references + // We can't use the obligation cause as it references // information local to this query. cause = self.fcx.misc(cause.span); } diff --git a/compiler/rustc_incremental/src/persist/fs.rs b/compiler/rustc_incremental/src/persist/fs.rs index 975bf1d18622..f73cc4d43e8c 100644 --- a/compiler/rustc_incremental/src/persist/fs.rs +++ b/compiler/rustc_incremental/src/persist/fs.rs @@ -116,8 +116,6 @@ use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_data_structures::{base_n, flock}; use rustc_fs_util::{LinkOrCopy, link_or_copy, try_canonicalize}; use rustc_middle::bug; -use rustc_session::config::CrateType; -use rustc_session::output::collect_crate_types; use rustc_session::{Session, StableCrateId}; use rustc_span::Symbol; use tracing::debug; @@ -212,7 +210,11 @@ pub fn in_incr_comp_dir(incr_comp_session_dir: &Path, file_name: &str) -> PathBu /// The garbage collection will take care of it. /// /// [`rustc_interface::queries::dep_graph`]: ../../rustc_interface/struct.Queries.html#structfield.dep_graph -pub(crate) fn prepare_session_directory(sess: &Session, crate_name: Symbol) { +pub(crate) fn prepare_session_directory( + sess: &Session, + crate_name: Symbol, + stable_crate_id: StableCrateId, +) { if sess.opts.incremental.is_none() { return; } @@ -222,7 +224,7 @@ pub(crate) fn prepare_session_directory(sess: &Session, crate_name: Symbol) { debug!("prepare_session_directory"); // {incr-comp-dir}/{crate-name-and-disambiguator} - let crate_dir = crate_path(sess, crate_name); + let crate_dir = crate_path(sess, crate_name, stable_crate_id); debug!("crate-dir: {}", crate_dir.display()); create_dir(sess, &crate_dir, "crate"); @@ -595,17 +597,9 @@ fn string_to_timestamp(s: &str) -> Result { Ok(UNIX_EPOCH + duration) } -fn crate_path(sess: &Session, crate_name: Symbol) -> PathBuf { +fn crate_path(sess: &Session, crate_name: Symbol, stable_crate_id: StableCrateId) -> PathBuf { let incr_dir = sess.opts.incremental.as_ref().unwrap().clone(); - let crate_types = collect_crate_types(sess, &[]); - let stable_crate_id = StableCrateId::new( - crate_name, - crate_types.contains(&CrateType::Executable), - sess.opts.cg.metadata.clone(), - sess.cfg_version, - ); - let crate_name = format!("{crate_name}-{}", stable_crate_id.as_u64().to_base_fixed_len(CASE_INSENSITIVE)); incr_dir.join(crate_name) diff --git a/compiler/rustc_incremental/src/persist/load.rs b/compiler/rustc_incremental/src/persist/load.rs index 0e646b136c45..1b2a283a1a0d 100644 --- a/compiler/rustc_incremental/src/persist/load.rs +++ b/compiler/rustc_incremental/src/persist/load.rs @@ -10,8 +10,8 @@ use rustc_middle::dep_graph::{DepGraph, DepsType, SerializedDepGraph, WorkProduc use rustc_middle::query::on_disk_cache::OnDiskCache; use rustc_serialize::Decodable; use rustc_serialize::opaque::MemDecoder; -use rustc_session::Session; use rustc_session::config::IncrementalStateAssertion; +use rustc_session::{Session, StableCrateId}; use rustc_span::Symbol; use tracing::{debug, warn}; @@ -208,9 +208,14 @@ pub fn load_query_result_cache(sess: &Session) -> Option { /// Setups the dependency graph by loading an existing graph from disk and set up streaming of a /// new graph to an incremental session directory. -pub fn setup_dep_graph(sess: &Session, crate_name: Symbol, deps: &DepsType) -> DepGraph { +pub fn setup_dep_graph( + sess: &Session, + crate_name: Symbol, + stable_crate_id: StableCrateId, + deps: &DepsType, +) -> DepGraph { // `load_dep_graph` can only be called after `prepare_session_directory`. - prepare_session_directory(sess, crate_name); + prepare_session_directory(sess, crate_name, stable_crate_id); let res = sess.opts.build_dep_graph().then(|| load_dep_graph(sess, deps)); diff --git a/compiler/rustc_index/src/idx.rs b/compiler/rustc_index/src/idx.rs index 2fb2008f9a3d..60c4dd90d8f6 100644 --- a/compiler/rustc_index/src/idx.rs +++ b/compiler/rustc_index/src/idx.rs @@ -135,7 +135,7 @@ impl IntoSliceIdx for core::range::RangeInclusive { } } -#[cfg(all(feature = "nightly", not(bootstrap)))] +#[cfg(feature = "nightly")] impl IntoSliceIdx for core::range::RangeToInclusive { type Output = core::range::RangeToInclusive; #[inline] diff --git a/compiler/rustc_index/src/lib.rs b/compiler/rustc_index/src/lib.rs index f61b5cf52798..42d284938468 100644 --- a/compiler/rustc_index/src/lib.rs +++ b/compiler/rustc_index/src/lib.rs @@ -1,6 +1,5 @@ // tidy-alphabetical-start #![cfg_attr(all(feature = "nightly", test), feature(stmt_expr_attributes))] -#![cfg_attr(bootstrap, feature(new_zeroed_alloc))] #![cfg_attr(feature = "nightly", allow(internal_features))] #![cfg_attr(feature = "nightly", feature(extend_one, step_trait, test))] #![cfg_attr(feature = "nightly", feature(new_range_api))] diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index a41d6b858795..58ed71a97077 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -8,6 +8,7 @@ use std::{env, fs, iter}; use rustc_ast as ast; use rustc_attr_parsing::{AttributeParser, ShouldEmit}; use rustc_codegen_ssa::traits::CodegenBackend; +use rustc_codegen_ssa::{CodegenResults, CrateInfo}; use rustc_data_structures::jobserver::Proxy; use rustc_data_structures::steal::Steal; use rustc_data_structures::sync::{AppendOnlyIndexVec, FreezeLock, WorkerLocal}; @@ -925,7 +926,11 @@ pub fn create_and_enter_global_ctxt FnOnce(TyCtxt<'tcx>) -> T>( let pre_configured_attrs = rustc_expand::config::pre_configure_attrs(sess, &krate.attrs); let crate_name = get_crate_name(sess, &pre_configured_attrs); - let crate_types = collect_crate_types(sess, &pre_configured_attrs); + let crate_types = collect_crate_types( + sess, + &compiler.codegen_backend.supported_crate_types(sess), + &pre_configured_attrs, + ); let stable_crate_id = StableCrateId::new( crate_name, crate_types.contains(&CrateType::Executable), @@ -936,7 +941,7 @@ pub fn create_and_enter_global_ctxt FnOnce(TyCtxt<'tcx>) -> T>( let outputs = util::build_output_filenames(&pre_configured_attrs, sess); let dep_type = DepsType { dep_names: rustc_query_impl::dep_kind_names() }; - let dep_graph = setup_dep_graph(sess, crate_name, &dep_type); + let dep_graph = setup_dep_graph(sess, crate_name, stable_crate_id, &dep_type); let cstore = FreezeLock::new(Box::new(CStore::new(compiler.codegen_backend.metadata_loader())) as _); @@ -1088,9 +1093,15 @@ fn run_required_analyses(tcx: TyCtxt<'_>) { sess.time("MIR_borrow_checking", || { tcx.par_hir_body_owners(|def_id| { - if !tcx.is_typeck_child(def_id.to_def_id()) { + let not_typeck_child = !tcx.is_typeck_child(def_id.to_def_id()); + if not_typeck_child { // Child unsafety and borrowck happens together with the parent tcx.ensure_ok().check_unsafety(def_id); + } + if tcx.is_trivial_const(def_id) { + return; + } + if not_typeck_child { tcx.ensure_ok().mir_borrowck(def_id); tcx.ensure_ok().check_transmutes(def_id); } @@ -1198,7 +1209,9 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) { if tcx.sess.opts.unstable_opts.validate_mir { sess.time("ensuring_final_MIR_is_computable", || { tcx.par_hir_body_owners(|def_id| { - tcx.instance_mir(ty::InstanceKind::Item(def_id.into())); + if !tcx.is_trivial_const(def_id) { + tcx.instance_mir(ty::InstanceKind::Item(def_id.into())); + } }); }); } @@ -1236,7 +1249,21 @@ pub(crate) fn start_codegen<'tcx>( let metadata = rustc_metadata::fs::encode_and_write_metadata(tcx); - let codegen = tcx.sess.time("codegen_crate", move || codegen_backend.codegen_crate(tcx)); + let codegen = tcx.sess.time("codegen_crate", move || { + if tcx.sess.opts.unstable_opts.no_codegen || !tcx.sess.opts.output_types.should_codegen() { + // Skip crate items and just output metadata in -Z no-codegen mode. + tcx.sess.dcx().abort_if_errors(); + + // Linker::link will skip join_codegen in case of a CodegenResults Any value. + Box::new(CodegenResults { + modules: vec![], + allocator_module: None, + crate_info: CrateInfo::new(tcx, "".to_owned()), + }) + } else { + codegen_backend.codegen_crate(tcx) + } + }); info!("Post-codegen\n{:?}", tcx.debug_stats()); diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs index 280214ab4183..3799485077ef 100644 --- a/compiler/rustc_interface/src/queries.rs +++ b/compiler/rustc_interface/src/queries.rs @@ -3,6 +3,7 @@ use std::sync::Arc; use rustc_codegen_ssa::CodegenResults; use rustc_codegen_ssa::traits::CodegenBackend; +use rustc_data_structures::indexmap::IndexMap; use rustc_data_structures::svh::Svh; use rustc_errors::timings::TimingSection; use rustc_hir::def_id::LOCAL_CRATE; @@ -46,7 +47,14 @@ impl Linker { pub fn link(self, sess: &Session, codegen_backend: &dyn CodegenBackend) { let (codegen_results, mut work_products) = sess.time("finish_ongoing_codegen", || { - codegen_backend.join_codegen(self.ongoing_codegen, sess, &self.output_filenames) + match self.ongoing_codegen.downcast::() { + // This was a check only build + Ok(codegen_results) => (*codegen_results, IndexMap::default()), + + Err(ongoing_codegen) => { + codegen_backend.join_codegen(ongoing_codegen, sess, &self.output_filenames) + } + } }); sess.timings.end_section(sess.dcx(), TimingSection::Codegen); diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index be2fd0787b98..5e9cb4236504 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -354,6 +354,14 @@ impl CodegenBackend for DummyCodegenBackend { "dummy" } + fn supported_crate_types(&self, _sess: &Session) -> Vec { + // This includes bin despite failing on the link step to ensure that you + // can still get the frontend handling for binaries. For all library + // like crate types cargo will fallback to rlib unless you specifically + // say that only a different crate type must be used. + vec![CrateType::Rlib, CrateType::Executable] + } + fn codegen_crate<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Box { Box::new(CodegenResults { modules: vec![], @@ -380,12 +388,16 @@ impl CodegenBackend for DummyCodegenBackend { ) { // JUSTIFICATION: TyCtxt no longer available here #[allow(rustc::bad_opt_access)] - if sess.opts.crate_types.iter().any(|&crate_type| crate_type != CrateType::Rlib) { + if let Some(&crate_type) = codegen_results + .crate_info + .crate_types + .iter() + .find(|&&crate_type| crate_type != CrateType::Rlib) + { #[allow(rustc::untranslatable_diagnostic)] #[allow(rustc::diagnostic_outside_of_impl)] sess.dcx().fatal(format!( - "crate type {} not supported by the dummy codegen backend", - sess.opts.crate_types[0], + "crate type {crate_type} not supported by the dummy codegen backend" )); } diff --git a/compiler/rustc_lint/src/let_underscore.rs b/compiler/rustc_lint/src/let_underscore.rs index 3e2c1af97f43..d061a56c9346 100644 --- a/compiler/rustc_lint/src/let_underscore.rs +++ b/compiler/rustc_lint/src/let_underscore.rs @@ -152,7 +152,7 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore { // We can't suggest `drop()` when we're on the top level. drop_fn_start_end: can_use_init .map(|init| (local.span.until(init.span), init.span.shrink_to_hi())), - is_assign_desugar: matches!(local.source, rustc_hir::LocalSource::AssignDesugar(_)), + is_assign_desugar: matches!(local.source, rustc_hir::LocalSource::AssignDesugar), }; if is_sync_lock { let span = MultiSpan::from_span(pat.span); diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index b4c18483a923..faaeb7706e39 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -362,6 +362,10 @@ fn register_builtins(store: &mut LintStore) { store.register_renamed("static_mut_ref", "static_mut_refs"); store.register_renamed("temporary_cstring_as_ptr", "dangling_pointers_from_temporaries"); store.register_renamed("elided_named_lifetimes", "mismatched_lifetime_syntaxes"); + store.register_renamed( + "repr_transparent_external_private_fields", + "repr_transparent_non_zst_fields", + ); // These were moved to tool lints, but rustc still sees them when compiling normally, before // tool lints are registered, so `check_tool_name_for_backwards_compat` doesn't work. Use diff --git a/compiler/rustc_lint/src/types/literal.rs b/compiler/rustc_lint/src/types/literal.rs index 1febbff4bbf8..d49f599407c2 100644 --- a/compiler/rustc_lint/src/types/literal.rs +++ b/compiler/rustc_lint/src/types/literal.rs @@ -1,4 +1,4 @@ -use hir::{ExprKind, Node, is_range_literal}; +use hir::{ExprKind, Node}; use rustc_abi::{Integer, Size}; use rustc_hir::{HirId, attrs}; use rustc_middle::ty::Ty; @@ -44,7 +44,7 @@ fn lint_overflowing_range_endpoint<'tcx>( let Node::Expr(struct_expr) = cx.tcx.parent_hir_node(field.hir_id) else { return false; }; - if !is_range_literal(struct_expr) { + let Some(range_span) = struct_expr.range_span() else { return false; }; let ExprKind::Struct(_, [start, end], _) = &struct_expr.kind else { @@ -71,7 +71,7 @@ fn lint_overflowing_range_endpoint<'tcx>( return false; }; UseInclusiveRange::WithoutParen { - sugg: struct_expr.span.shrink_to_lo().to(lit_span.shrink_to_hi()), + sugg: range_span.shrink_to_lo().to(lit_span.shrink_to_hi()), start, literal: lit_val - 1, suffix, @@ -87,7 +87,7 @@ fn lint_overflowing_range_endpoint<'tcx>( cx.emit_span_lint( OVERFLOWING_LITERALS, - struct_expr.span, + range_span, RangeEndpointOutOfRange { ty, sub: sub_sugg }, ); diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 1e965083d669..8c474ed28240 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -86,7 +86,7 @@ declare_lint_pass! { REFINING_IMPL_TRAIT_INTERNAL, REFINING_IMPL_TRAIT_REACHABLE, RENAMED_AND_REMOVED_LINTS, - REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS, + REPR_TRANSPARENT_NON_ZST_FIELDS, RUST_2021_INCOMPATIBLE_CLOSURE_CAPTURES, RUST_2021_INCOMPATIBLE_OR_PATTERNS, RUST_2021_PREFIXES_INCOMPATIBLE_SYNTAX, @@ -3011,10 +3011,9 @@ declare_lint! { } declare_lint! { - /// The `repr_transparent_external_private_fields` lint + /// The `repr_transparent_non_zst_fields` lint /// detects types marked `#[repr(transparent)]` that (transitively) - /// contain an external ZST type marked `#[non_exhaustive]` or containing - /// private fields + /// contain a type that is not guaranteed to remain a ZST type under all configurations. /// /// ### Example /// @@ -3022,8 +3021,13 @@ declare_lint! { /// #![deny(repr_transparent_external_private_fields)] /// use foo::NonExhaustiveZst; /// + /// #[repr(C)] + /// struct CZst([u8; 0]); + /// /// #[repr(transparent)] /// struct Bar(u32, ([u32; 0], NonExhaustiveZst)); + /// #[repr(transparent)] + /// struct Baz(u32, CZst); /// ``` /// /// This will produce: @@ -3042,26 +3046,39 @@ declare_lint! { /// | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /// = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! /// = note: for more information, see issue #78586 - /// = note: this struct contains `NonExhaustiveZst`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future. + /// = note: this field contains `NonExhaustiveZst`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. + /// + /// error: zero-sized fields in repr(transparent) cannot contain `#[repr(C)]` types + /// --> src/main.rs:5:28 + /// | + /// 5 | struct Baz(u32, CZst); + /// | ^^^^ + /// = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + /// = note: for more information, see issue #78586 + /// = note: this field contains `CZst`, which is a `#[repr(C)]` type, so it is not guaranteed to be zero-sized on all targets. /// ``` /// /// ### Explanation /// - /// Previous, Rust accepted fields that contain external private zero-sized types, - /// even though it should not be a breaking change to add a non-zero-sized field to - /// that private type. + /// Previous, Rust accepted fields that contain external private zero-sized types, even though + /// those types could gain a non-zero-sized field in a future, semver-compatible update. + /// + /// Rust also accepted fields that contain `repr(C)` zero-sized types, even though those types + /// are not guaranteed to be zero-sized on all targets, and even though those types can + /// make a difference for the ABI (and therefore cannot be ignored by `repr(transparent)`). /// /// This is a [future-incompatible] lint to transition this /// to a hard error in the future. See [issue #78586] for more details. /// /// [issue #78586]: https://github.com/rust-lang/rust/issues/78586 /// [future-incompatible]: ../index.md#future-incompatible-lints - pub REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS, - Warn, + pub REPR_TRANSPARENT_NON_ZST_FIELDS, + Deny, "transparent type contains an external ZST that is marked #[non_exhaustive] or contains private fields", @future_incompatible = FutureIncompatibleInfo { reason: FutureIncompatibilityReason::FutureReleaseError, reference: "issue #78586 ", + report_in_deps: true, }; } diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 40a818a3c9dc..ec26c35ffdc9 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -403,7 +403,7 @@ pub enum FutureIncompatibilityReason { /// /// After a lint has been in this state for a while and you feel like it is ready to graduate /// to warning everyone, consider setting [`FutureIncompatibleInfo::report_in_deps`] to true. - /// (see it's documentation for more guidance) + /// (see its documentation for more guidance) /// /// After some period of time, lints with this variant can be turned into /// hard errors (and the lint removed). Preferably when there is some diff --git a/compiler/rustc_llvm/Cargo.toml b/compiler/rustc_llvm/Cargo.toml index ad93c7453813..209ee93a9fef 100644 --- a/compiler/rustc_llvm/Cargo.toml +++ b/compiler/rustc_llvm/Cargo.toml @@ -11,7 +11,7 @@ libc = "0.2.73" [build-dependencies] # tidy-alphabetical-start # `cc` updates often break things, so we pin it here. -cc = "=1.2.16" +cc = "=1.2.39" # tidy-alphabetical-end [features] diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index 6b4f8a6dba79..ad459986826a 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -245,6 +245,7 @@ enum class LLVMRustAttributeKind { DeadOnUnwind = 43, DeadOnReturn = 44, CapturesReadOnly = 45, + CapturesNone = 46, }; static Attribute::AttrKind fromRust(LLVMRustAttributeKind Kind) { @@ -339,6 +340,7 @@ static Attribute::AttrKind fromRust(LLVMRustAttributeKind Kind) { #endif case LLVMRustAttributeKind::CapturesAddress: case LLVMRustAttributeKind::CapturesReadOnly: + case LLVMRustAttributeKind::CapturesNone: report_fatal_error("Should be handled separately"); } report_fatal_error("bad LLVMRustAttributeKind"); @@ -390,6 +392,9 @@ extern "C" void LLVMRustEraseInstFromParent(LLVMValueRef Instr) { extern "C" LLVMAttributeRef LLVMRustCreateAttrNoValue(LLVMContextRef C, LLVMRustAttributeKind RustAttr) { #if LLVM_VERSION_GE(21, 0) + if (RustAttr == LLVMRustAttributeKind::CapturesNone) { + return wrap(Attribute::getWithCaptureInfo(*unwrap(C), CaptureInfo::none())); + } if (RustAttr == LLVMRustAttributeKind::CapturesAddress) { return wrap(Attribute::getWithCaptureInfo( *unwrap(C), CaptureInfo(CaptureComponents::Address))); diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index df3add316ec2..d20df618b38b 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -240,6 +240,7 @@ provide! { tcx, def_id, other, cdata, thir_abstract_const => { table } optimized_mir => { table } mir_for_ctfe => { table } + trivial_const => { table } closure_saved_names_of_captured_variables => { table } mir_coroutine_witnesses => { table } promoted_mir => { table } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index e13ef7e70f44..778007854b77 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1791,8 +1791,15 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { record!(self.tables.mir_coroutine_witnesses[def_id.to_def_id()] <- witnesses); } } + let mut is_trivial = false; if encode_const { - record!(self.tables.mir_for_ctfe[def_id.to_def_id()] <- tcx.mir_for_ctfe(def_id)); + if let Some((val, ty)) = tcx.trivial_const(def_id) { + is_trivial = true; + record!(self.tables.trivial_const[def_id.to_def_id()] <- (val, ty)); + } else { + is_trivial = false; + record!(self.tables.mir_for_ctfe[def_id.to_def_id()] <- tcx.mir_for_ctfe(def_id)); + } // FIXME(generic_const_exprs): this feels wrong to have in `encode_mir` let abstract_const = tcx.thir_abstract_const(def_id); @@ -1810,7 +1817,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } } } - record!(self.tables.promoted_mir[def_id.to_def_id()] <- tcx.promoted_mir(def_id)); + if !is_trivial { + record!(self.tables.promoted_mir[def_id.to_def_id()] <- tcx.promoted_mir(def_id)); + } if self.tcx.is_coroutine(def_id.to_def_id()) && let Some(witnesses) = tcx.mir_coroutine_witnesses(def_id) @@ -2234,6 +2243,9 @@ fn prefetch_mir(tcx: TyCtxt<'_>) { let reachable_set = tcx.reachable_set(()); par_for_each_in(tcx.mir_keys(()), |&&def_id| { + if tcx.is_trivial_const(def_id) { + return; + } let (encode_const, encode_opt) = should_encode_mir(tcx, reachable_set, def_id); if encode_const { diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 9fbfa0a9f765..8f1c7bbb3968 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -29,6 +29,7 @@ use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo}; use rustc_middle::middle::lib_features::FeatureStability; use rustc_middle::middle::resolve_bound_vars::ObjectLifetimeDefault; use rustc_middle::mir; +use rustc_middle::mir::ConstValue; use rustc_middle::ty::fast_reject::SimplifiedType; use rustc_middle::ty::{self, Ty, TyCtxt, UnusedGenericParams}; use rustc_middle::util::Providers; @@ -426,6 +427,7 @@ define_tables! { object_lifetime_default: Table>, optimized_mir: Table>>, mir_for_ctfe: Table>>, + trivial_const: Table)>>, closure_saved_names_of_captured_variables: Table>>, mir_coroutine_witnesses: Table>>, promoted_mir: Table>>>, diff --git a/compiler/rustc_metadata/src/rmeta/parameterized.rs b/compiler/rustc_metadata/src/rmeta/parameterized.rs index 733e33f310a6..d8bae5a54e31 100644 --- a/compiler/rustc_metadata/src/rmeta/parameterized.rs +++ b/compiler/rustc_metadata/src/rmeta/parameterized.rs @@ -102,6 +102,7 @@ trivially_parameterized_over_tcx! { rustc_middle::middle::lib_features::FeatureStability, rustc_middle::middle::resolve_bound_vars::ObjectLifetimeDefault, rustc_middle::mir::ConstQualifs, + rustc_middle::mir::ConstValue, rustc_middle::ty::AnonConstKind, rustc_middle::ty::AssocContainer, rustc_middle::ty::AsyncDestructor, diff --git a/compiler/rustc_middle/src/middle/deduced_param_attrs.rs b/compiler/rustc_middle/src/middle/deduced_param_attrs.rs index 68d1c852f0e2..5e9e625f4c74 100644 --- a/compiler/rustc_middle/src/middle/deduced_param_attrs.rs +++ b/compiler/rustc_middle/src/middle/deduced_param_attrs.rs @@ -2,19 +2,21 @@ use rustc_macros::{Decodable, Encodable, HashStable}; use crate::ty::{Ty, TyCtxt, TypingEnv}; -/// Flags that dictate how a parameter is mutated. If the flags are empty, the param is -/// read-only. If non-empty, it is read-only if *all* flags' conditions are met. +/// Summarizes how a parameter (a return place or an argument) is used inside a MIR body. #[derive(Clone, Copy, PartialEq, Debug, Decodable, Encodable, HashStable)] -pub struct DeducedReadOnlyParam(u8); +pub struct UsageSummary(u8); bitflags::bitflags! { - impl DeducedReadOnlyParam: u8 { - /// This parameter is dropped. It is read-only if `!needs_drop`. - const IF_NO_DROP = 1 << 0; - /// This parameter is borrowed. It is read-only if `Freeze`. - const IF_FREEZE = 1 << 1; - /// This parameter is mutated. It is never read-only. - const MUTATED = 1 << 2; + impl UsageSummary: u8 { + /// This parameter is dropped when it `needs_drop`. + const DROP = 1 << 0; + /// There is a shared borrow to this parameter. + /// It allows for mutation unless parameter is `Freeze`. + const SHARED_BORROW = 1 << 1; + /// This parameter is mutated (excluding through a drop or a shared borrow). + const MUTATE = 1 << 2; + /// This parameter is captured (excluding through a drop). + const CAPTURE = 1 << 3; } } @@ -24,43 +26,53 @@ bitflags::bitflags! { /// These can be useful for optimization purposes when a function is directly called. We compute /// them and store them into the crate metadata so that downstream crates can make use of them. /// -/// Right now, we only have `read_only`, but `no_capture` and `no_alias` might be useful in the +/// Right now, we have `readonly` and `captures(none)`, but `no_alias` might be useful in the /// future. #[derive(Clone, Copy, PartialEq, Debug, Decodable, Encodable, HashStable)] pub struct DeducedParamAttrs { - /// The parameter is marked immutable in the function. - pub read_only: DeducedReadOnlyParam, -} - -// By default, consider the parameters to be mutated. -impl Default for DeducedParamAttrs { - #[inline] - fn default() -> DeducedParamAttrs { - DeducedParamAttrs { read_only: DeducedReadOnlyParam::MUTATED } - } + pub usage: UsageSummary, } impl DeducedParamAttrs { + /// Returns true if no attributes have been deduced. #[inline] pub fn is_default(self) -> bool { - self.read_only.contains(DeducedReadOnlyParam::MUTATED) + self.usage.contains(UsageSummary::MUTATE | UsageSummary::CAPTURE) } + /// For parameters passed indirectly, returns true if pointer is never written through. pub fn read_only<'tcx>( &self, tcx: TyCtxt<'tcx>, typing_env: TypingEnv<'tcx>, ty: Ty<'tcx>, ) -> bool { - let read_only = self.read_only; - // We have to check *all* set bits; only if all checks pass is this truly read-only. - if read_only.contains(DeducedReadOnlyParam::MUTATED) { + // Only if all checks pass is this truly read-only. + if self.usage.contains(UsageSummary::MUTATE) { return false; } - if read_only.contains(DeducedReadOnlyParam::IF_NO_DROP) && ty.needs_drop(tcx, typing_env) { + if self.usage.contains(UsageSummary::DROP) && ty.needs_drop(tcx, typing_env) { return false; } - if read_only.contains(DeducedReadOnlyParam::IF_FREEZE) && !ty.is_freeze(tcx, typing_env) { + if self.usage.contains(UsageSummary::SHARED_BORROW) && !ty.is_freeze(tcx, typing_env) { + return false; + } + true + } + + /// For parameters passed indirectly, returns true if pointer is not captured, i.e., its + /// address is not captured, and pointer is used neither for reads nor writes after function + /// returns. + pub fn captures_none<'tcx>( + &self, + tcx: TyCtxt<'tcx>, + typing_env: TypingEnv<'tcx>, + ty: Ty<'tcx>, + ) -> bool { + if self.usage.contains(UsageSummary::CAPTURE) { + return false; + } + if self.usage.contains(UsageSummary::DROP) && ty.needs_drop(tcx, typing_env) { return false; } true diff --git a/compiler/rustc_middle/src/mir/graphviz.rs b/compiler/rustc_middle/src/mir/graphviz.rs index a64b122fbc9e..cbfeae205177 100644 --- a/compiler/rustc_middle/src/mir/graphviz.rs +++ b/compiler/rustc_middle/src/mir/graphviz.rs @@ -16,6 +16,7 @@ where let mirs = def_ids .iter() + .filter(|def_id| !tcx.is_trivial_const(*def_id)) .flat_map(|def_id| { if tcx.is_const_fn(*def_id) { vec![tcx.optimized_mir(*def_id), tcx.mir_for_ctfe(*def_id)] diff --git a/compiler/rustc_middle/src/mir/interpret/queries.rs b/compiler/rustc_middle/src/mir/interpret/queries.rs index ecf35d9dd6d7..89034981cbd6 100644 --- a/compiler/rustc_middle/src/mir/interpret/queries.rs +++ b/compiler/rustc_middle/src/mir/interpret/queries.rs @@ -134,6 +134,7 @@ impl<'tcx> TyCtxt<'tcx> { // If we don't *only* FCW anon consts we can wind up incorrectly FCW'ing uses of assoc // consts in pattern positions. #140447 && self.def_kind(cid.instance.def_id()) == DefKind::AnonConst + && !self.is_trivial_const(cid.instance.def_id()) { let mir_body = self.mir_for_ctfe(cid.instance.def_id()); if mir_body.is_polymorphic { diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index 17d8eeee68bf..929513c0dced 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -353,8 +353,16 @@ pub fn write_mir_pretty<'tcx>( // are shared between mir_for_ctfe and optimized_mir writer.write_mir_fn(tcx.mir_for_ctfe(def_id), w)?; } else { - let instance_mir = tcx.instance_mir(ty::InstanceKind::Item(def_id)); - render_body(w, instance_mir)?; + if let Some((val, ty)) = tcx.trivial_const(def_id) { + ty::print::with_forced_impl_filename_line! { + // see notes on #41697 elsewhere + write!(w, "const {}", tcx.def_path_str(def_id))? + } + writeln!(w, ": {} = const {};", ty, Const::Val(val, ty))?; + } else { + let instance_mir = tcx.instance_mir(ty::InstanceKind::Item(def_id)); + render_body(w, instance_mir)?; + } } } Ok(()) diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs index ad82e83ee40b..46100358c7d7 100644 --- a/compiler/rustc_middle/src/query/erase.rs +++ b/compiler/rustc_middle/src/query/erase.rs @@ -160,6 +160,10 @@ impl EraseType for Result { type Result = [u8; size_of::>()]; } +impl EraseType for Option<(mir::ConstValue, Ty<'_>)> { + type Result = [u8; size_of::)>>()]; +} + impl EraseType for EvalToValTreeResult<'_> { type Result = [u8; size_of::>()]; } diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 588ff68ba572..30d4cc8b3c8d 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -2719,6 +2719,12 @@ rustc_queries! { separate_provide_extern } + query trivial_const(def_id: DefId) -> Option<(mir::ConstValue, Ty<'tcx>)> { + desc { |tcx| "checking if `{}` is a trivial const", tcx.def_path_str(def_id) } + cache_on_disk_if { def_id.is_local() } + separate_provide_extern + } + /// Checks for the nearest `#[sanitize(xyz = "off")]` or /// `#[sanitize(xyz = "on")]` on this def and any enclosing defs, up to the /// crate root. diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 1a3eb0949116..60effa13406b 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -3545,6 +3545,13 @@ impl<'tcx> TyCtxt<'tcx> { self.get_diagnostic_attr(def_id, sym::do_not_recommend).is_some() } + pub fn is_trivial_const

(self, def_id: P) -> bool + where + P: IntoQueryParam, + { + self.trivial_const(def_id).is_some() + } + /// Whether this def is one of the special bin crate entrypoint functions that must have a /// monomorphization and also not be internalized in the bin crate. pub fn is_entrypoint(self, def_id: DefId) -> bool { diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index c3e1defef809..93d0c77c1dae 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -37,7 +37,6 @@ use rustc_errors::{Diag, ErrorGuaranteed, LintBuffer}; use rustc_hir::attrs::{AttributeKind, StrippedCfgItem}; use rustc_hir::def::{CtorKind, CtorOf, DefKind, DocLinkResMap, LifetimeRes, Res}; use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LocalDefIdMap}; -use rustc_hir::definitions::DisambiguatorState; use rustc_hir::{LangItem, attrs as attr, find_attr}; use rustc_index::IndexVec; use rustc_index::bit_set::BitMatrix; @@ -211,8 +210,6 @@ pub struct ResolverAstLowering { pub node_id_to_def_id: NodeMap, - pub disambiguator: DisambiguatorState, - pub trait_map: NodeMap>, /// List functions and methods for which lifetime elision was successful. pub lifetime_elision_allowed: FxHashSet, diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 0af7fe808ef9..06744ae6e242 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -2156,6 +2156,7 @@ fn guess_def_namespace(tcx: TyCtxt<'_>, def_id: DefId) -> Namespace { DefPathData::ValueNs(..) | DefPathData::AnonConst + | DefPathData::LateAnonConst | DefPathData::Closure | DefPathData::Ctor => Namespace::ValueNS, diff --git a/compiler/rustc_mir_build/src/builder/expr/as_place.rs b/compiler/rustc_mir_build/src/builder/expr/as_place.rs index 5e7a57d51a9c..1b143f37a585 100644 --- a/compiler/rustc_mir_build/src/builder/expr/as_place.rs +++ b/compiler/rustc_mir_build/src/builder/expr/as_place.rs @@ -454,7 +454,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { index, mutability, fake_borrow_temps, - expr.temp_lifetime, expr_span, source_info, ), @@ -625,7 +624,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { index: ExprId, mutability: Mutability, fake_borrow_temps: Option<&mut Vec>, - temp_lifetime: TempLifetime, expr_span: Span, source_info: SourceInfo, ) -> BlockAnd> { @@ -639,7 +637,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Making this a *fresh* temporary means we do not have to worry about // the index changing later: Nothing will ever change this temporary. // The "retagging" transformation (for Stacked Borrows) relies on this. - let idx = unpack!(block = self.as_temp(block, temp_lifetime, index, Mutability::Not)); + let index_lifetime = self.thir[index].temp_lifetime; + let idx = unpack!(block = self.as_temp(block, index_lifetime, index, Mutability::Not)); block = self.bounds_check(block, &base_place, idx, expr_span, source_info); diff --git a/compiler/rustc_mir_build/src/builder/matches/mod.rs b/compiler/rustc_mir_build/src/builder/matches/mod.rs index 926a3eb018ff..82f12a969bb1 100644 --- a/compiler/rustc_mir_build/src/builder/matches/mod.rs +++ b/compiler/rustc_mir_build/src/builder/matches/mod.rs @@ -2897,8 +2897,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { for (_, node) in tcx.hir_parent_iter(var_id.0) { // FIXME(khuey) at what point is it safe to bail on the iterator? // Can we stop at the first non-Pat node? - if matches!(node, Node::LetStmt(&LetStmt { source: LocalSource::AssignDesugar(_), .. })) - { + if matches!(node, Node::LetStmt(&LetStmt { source: LocalSource::AssignDesugar, .. })) { return false; } } diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs index e5e9cd192afa..2ccd8178e667 100644 --- a/compiler/rustc_mir_transform/src/coroutine.rs +++ b/compiler/rustc_mir_transform/src/coroutine.rs @@ -132,8 +132,8 @@ struct SelfArgVisitor<'tcx> { } impl<'tcx> SelfArgVisitor<'tcx> { - fn new(tcx: TyCtxt<'tcx>, elem: ProjectionElem>) -> Self { - Self { tcx, new_base: Place { local: SELF_ARG, projection: tcx.mk_place_elems(&[elem]) } } + fn new(tcx: TyCtxt<'tcx>, new_base: Place<'tcx>) -> Self { + Self { tcx, new_base } } } @@ -146,16 +146,14 @@ impl<'tcx> MutVisitor<'tcx> for SelfArgVisitor<'tcx> { assert_ne!(*local, SELF_ARG); } - fn visit_place(&mut self, place: &mut Place<'tcx>, context: PlaceContext, location: Location) { + fn visit_place(&mut self, place: &mut Place<'tcx>, _: PlaceContext, _: Location) { if place.local == SELF_ARG { replace_base(place, self.new_base, self.tcx); - } else { - self.visit_local(&mut place.local, context, location); + } - for elem in place.projection.iter() { - if let PlaceElem::Index(local) = elem { - assert_ne!(local, SELF_ARG); - } + for elem in place.projection.iter() { + if let PlaceElem::Index(local) = elem { + assert_ne!(local, SELF_ARG); } } } @@ -515,20 +513,22 @@ fn make_aggregate_adt<'tcx>( #[tracing::instrument(level = "trace", skip(tcx, body))] fn make_coroutine_state_argument_indirect<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - let coroutine_ty = body.local_decls.raw[1].ty; + let coroutine_ty = body.local_decls[SELF_ARG].ty; let ref_coroutine_ty = Ty::new_mut_ref(tcx, tcx.lifetimes.re_erased, coroutine_ty); // Replace the by value coroutine argument - body.local_decls.raw[1].ty = ref_coroutine_ty; + body.local_decls[SELF_ARG].ty = ref_coroutine_ty; // Add a deref to accesses of the coroutine state - SelfArgVisitor::new(tcx, ProjectionElem::Deref).visit_body(body); + SelfArgVisitor::new(tcx, tcx.mk_place_deref(SELF_ARG.into())).visit_body(body); } #[tracing::instrument(level = "trace", skip(tcx, body))] fn make_coroutine_state_argument_pinned<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - let ref_coroutine_ty = body.local_decls.raw[1].ty; + let coroutine_ty = body.local_decls[SELF_ARG].ty; + + let ref_coroutine_ty = Ty::new_mut_ref(tcx, tcx.lifetimes.re_erased, coroutine_ty); let pin_did = tcx.require_lang_item(LangItem::Pin, body.span); let pin_adt_ref = tcx.adt_def(pin_did); @@ -536,11 +536,33 @@ fn make_coroutine_state_argument_pinned<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body let pin_ref_coroutine_ty = Ty::new_adt(tcx, pin_adt_ref, args); // Replace the by ref coroutine argument - body.local_decls.raw[1].ty = pin_ref_coroutine_ty; + body.local_decls[SELF_ARG].ty = pin_ref_coroutine_ty; + + let unpinned_local = body.local_decls.push(LocalDecl::new(ref_coroutine_ty, body.span)); // Add the Pin field access to accesses of the coroutine state - SelfArgVisitor::new(tcx, ProjectionElem::Field(FieldIdx::ZERO, ref_coroutine_ty)) - .visit_body(body); + SelfArgVisitor::new(tcx, tcx.mk_place_deref(unpinned_local.into())).visit_body(body); + + let source_info = SourceInfo::outermost(body.span); + let pin_field = tcx.mk_place_field(SELF_ARG.into(), FieldIdx::ZERO, ref_coroutine_ty); + + let statements = &mut body.basic_blocks.as_mut_preserves_cfg()[START_BLOCK].statements; + // Miri requires retags to be the very first thing in the body. + // We insert this assignment just after. + let insert_point = statements + .iter() + .position(|stmt| !matches!(stmt.kind, StatementKind::Retag(..))) + .unwrap_or(statements.len()); + statements.insert( + insert_point, + Statement::new( + source_info, + StatementKind::Assign(Box::new(( + unpinned_local.into(), + Rvalue::Use(Operand::Copy(pin_field)), + ))), + ), + ); } /// Transforms the `body` of the coroutine applying the following transforms: @@ -1292,8 +1314,6 @@ fn create_coroutine_resume_function<'tcx>( let default_block = insert_term_block(body, TerminatorKind::Unreachable); insert_switch(body, cases, &transform, default_block); - make_coroutine_state_argument_indirect(tcx, body); - match transform.coroutine_kind { CoroutineKind::Coroutine(_) | CoroutineKind::Desugared(CoroutineDesugaring::Async | CoroutineDesugaring::AsyncGen, _) => @@ -1302,7 +1322,9 @@ fn create_coroutine_resume_function<'tcx>( } // Iterator::next doesn't accept a pinned argument, // unlike for all other coroutine kinds. - CoroutineKind::Desugared(CoroutineDesugaring::Gen, _) => {} + CoroutineKind::Desugared(CoroutineDesugaring::Gen, _) => { + make_coroutine_state_argument_indirect(tcx, body); + } } // Make sure we remove dead blocks to remove diff --git a/compiler/rustc_mir_transform/src/coroutine/drop.rs b/compiler/rustc_mir_transform/src/coroutine/drop.rs index 41c588f0d8d3..2699a051a8fe 100644 --- a/compiler/rustc_mir_transform/src/coroutine/drop.rs +++ b/compiler/rustc_mir_transform/src/coroutine/drop.rs @@ -684,12 +684,13 @@ pub(super) fn create_coroutine_drop_shim_async<'tcx>( let poll_enum = Ty::new_adt(tcx, poll_adt_ref, tcx.mk_args(&[tcx.types.unit.into()])); body.local_decls[RETURN_PLACE] = LocalDecl::with_source_info(poll_enum, source_info); - make_coroutine_state_argument_indirect(tcx, &mut body); - match transform.coroutine_kind { // Iterator::next doesn't accept a pinned argument, // unlike for all other coroutine kinds. - CoroutineKind::Desugared(CoroutineDesugaring::Gen, _) => {} + CoroutineKind::Desugared(CoroutineDesugaring::Gen, _) => { + make_coroutine_state_argument_indirect(tcx, &mut body); + } + _ => { make_coroutine_state_argument_pinned(tcx, &mut body); } diff --git a/compiler/rustc_mir_transform/src/deduce_param_attrs.rs b/compiler/rustc_mir_transform/src/deduce_param_attrs.rs index e421e47bd161..1b3e01f3a380 100644 --- a/compiler/rustc_mir_transform/src/deduce_param_attrs.rs +++ b/compiler/rustc_mir_transform/src/deduce_param_attrs.rs @@ -11,65 +11,91 @@ use rustc_hir::def_id::LocalDefId; use rustc_index::IndexVec; -use rustc_middle::middle::deduced_param_attrs::{DeducedParamAttrs, DeducedReadOnlyParam}; +use rustc_middle::middle::deduced_param_attrs::{DeducedParamAttrs, UsageSummary}; use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor}; use rustc_middle::mir::*; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_session::config::OptLevel; -/// A visitor that determines which arguments have been mutated. We can't use the mutability field -/// on LocalDecl for this because it has no meaning post-optimization. -struct DeduceReadOnly { - /// Each bit is indexed by argument number, starting at zero (so 0 corresponds to local decl - /// 1). The bit is false if the argument may have been mutated or true if we know it hasn't - /// been up to the point we're at. - read_only: IndexVec, +/// A visitor that determines how a return place and arguments are used inside MIR body. +/// To determine whether a local is mutated we can't use the mutability field on LocalDecl +/// because it has no meaning post-optimization. +struct DeduceParamAttrs { + /// Summarizes how a return place and arguments are used inside MIR body. + usage: IndexVec, } -impl DeduceReadOnly { - /// Returns a new DeduceReadOnly instance. - fn new(arg_count: usize) -> Self { - Self { read_only: IndexVec::from_elem_n(DeducedReadOnlyParam::empty(), arg_count) } +impl DeduceParamAttrs { + /// Returns a new DeduceParamAttrs instance. + fn new(body: &Body<'_>) -> Self { + let mut this = + Self { usage: IndexVec::from_elem_n(UsageSummary::empty(), body.arg_count + 1) }; + // Code generation indicates that a return place is writable. To avoid setting both + // `readonly` and `writable` attributes, when return place is never written to, mark it as + // mutated. + this.usage[RETURN_PLACE] |= UsageSummary::MUTATE; + this } - /// Returns whether the given local is a parameter and its index. - fn as_param(&self, local: Local) -> Option { - // Locals and parameters are shifted by `RETURN_PLACE`. - let param_index = local.as_usize().checked_sub(1)?; - if param_index < self.read_only.len() { Some(param_index) } else { None } + /// Returns whether a local is the return place or an argument and returns its index. + fn as_param(&self, local: Local) -> Option { + if local.index() < self.usage.len() { Some(local) } else { None } } } -impl<'tcx> Visitor<'tcx> for DeduceReadOnly { +impl<'tcx> Visitor<'tcx> for DeduceParamAttrs { fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, _location: Location) { - // We're only interested in arguments. - let Some(param_index) = self.as_param(place.local) else { return }; + // We're only interested in the return place or an argument. + let Some(i) = self.as_param(place.local) else { return }; match context { - // Not mutating, so it's fine. + // Not actually using the local. PlaceContext::NonUse(..) => {} - // Dereference is not a mutation. + // Neither mutated nor captured. _ if place.is_indirect_first_projection() => {} // This is a `Drop`. It could disappear at monomorphization, so mark it specially. PlaceContext::MutatingUse(MutatingUseContext::Drop) // Projection changes the place's type, so `needs_drop(local.ty)` is not // `needs_drop(place.ty)`. if place.projection.is_empty() => { - self.read_only[param_index] |= DeducedReadOnlyParam::IF_NO_DROP; + self.usage[i] |= UsageSummary::DROP; + } + PlaceContext::MutatingUse( + MutatingUseContext::Call + | MutatingUseContext::Yield + | MutatingUseContext::Drop + | MutatingUseContext::Borrow + | MutatingUseContext::RawBorrow) => { + self.usage[i] |= UsageSummary::MUTATE; + self.usage[i] |= UsageSummary::CAPTURE; + } + PlaceContext::MutatingUse( + MutatingUseContext::Store + | MutatingUseContext::SetDiscriminant + | MutatingUseContext::AsmOutput + | MutatingUseContext::Projection + | MutatingUseContext::Retag) => { + self.usage[i] |= UsageSummary::MUTATE; } - // This is a mutation, so mark it as such. - PlaceContext::MutatingUse(..) - // Whether mutating though a `&raw const` is allowed is still undecided, so we - // disable any sketchy `readonly` optimizations for now. | PlaceContext::NonMutatingUse(NonMutatingUseContext::RawBorrow) => { - self.read_only[param_index] |= DeducedReadOnlyParam::MUTATED; + // Whether mutating though a `&raw const` is allowed is still undecided, so we + // disable any sketchy `readonly` optimizations for now. + self.usage[i] |= UsageSummary::MUTATE; + self.usage[i] |= UsageSummary::CAPTURE; } - // Not mutating if the parameter is `Freeze`. PlaceContext::NonMutatingUse(NonMutatingUseContext::SharedBorrow) => { - self.read_only[param_index] |= DeducedReadOnlyParam::IF_FREEZE; + // Not mutating if the parameter is `Freeze`. + self.usage[i] |= UsageSummary::SHARED_BORROW; + self.usage[i] |= UsageSummary::CAPTURE; } // Not mutating, so it's fine. - PlaceContext::NonMutatingUse(..) => {} + PlaceContext::NonMutatingUse( + NonMutatingUseContext::Inspect + | NonMutatingUseContext::Copy + | NonMutatingUseContext::Move + | NonMutatingUseContext::FakeBorrow + | NonMutatingUseContext::PlaceMention + | NonMutatingUseContext::Projection) => {} } } @@ -98,11 +124,11 @@ impl<'tcx> Visitor<'tcx> for DeduceReadOnly { if let TerminatorKind::Call { ref args, .. } = terminator.kind { for arg in args { if let Operand::Move(place) = arg.node - // We're only interested in arguments. - && let Some(param_index) = self.as_param(place.local) && !place.is_indirect_first_projection() + && let Some(i) = self.as_param(place.local) { - self.read_only[param_index] |= DeducedReadOnlyParam::MUTATED; + self.usage[i] |= UsageSummary::MUTATE; + self.usage[i] |= UsageSummary::CAPTURE; } } }; @@ -154,10 +180,9 @@ pub(super) fn deduced_param_attrs<'tcx>( if matches!(fn_ty.kind(), ty::FnDef(..)) && fn_ty .fn_sig(tcx) - .inputs() + .inputs_and_output() .skip_binder() .iter() - .cloned() .all(type_will_always_be_passed_directly) { return &[]; @@ -170,13 +195,18 @@ pub(super) fn deduced_param_attrs<'tcx>( // Grab the optimized MIR. Analyze it to determine which arguments have been mutated. let body: &Body<'tcx> = tcx.optimized_mir(def_id); - let mut deduce_read_only = DeduceReadOnly::new(body.arg_count); - deduce_read_only.visit_body(body); - tracing::trace!(?deduce_read_only.read_only); + // Arguments spread at ABI level are currently unsupported. + if body.spread_arg.is_some() { + return &[]; + } - let mut deduced_param_attrs: &[_] = tcx.arena.alloc_from_iter( - deduce_read_only.read_only.into_iter().map(|read_only| DeducedParamAttrs { read_only }), - ); + let mut deduce = DeduceParamAttrs::new(body); + deduce.visit_body(body); + tracing::trace!(?deduce.usage); + + let mut deduced_param_attrs: &[_] = tcx + .arena + .alloc_from_iter(deduce.usage.into_iter().map(|usage| DeducedParamAttrs { usage })); // Trailing parameters past the size of the `deduced_param_attrs` array are assumed to have the // default set of attributes, so we don't have to store them explicitly. Pop them off to save a diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 4625b20fd890..18b798c01faa 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -55,6 +55,7 @@ mod liveness; mod patch; mod shim; mod ssa; +mod trivial_const; /// We import passes via this macro so that we can have a static list of pass names /// (used to verify CLI arguments). It takes a list of modules, followed by the passes @@ -226,6 +227,7 @@ pub fn provide(providers: &mut Providers) { promoted_mir, deduced_param_attrs: deduce_param_attrs::deduced_param_attrs, coroutine_by_move_body_def_id: coroutine::coroutine_by_move_body_def_id, + trivial_const: trivial_const::trivial_const_provider, ..providers.queries }; } @@ -379,6 +381,16 @@ fn mir_const_qualif(tcx: TyCtxt<'_>, def: LocalDefId) -> ConstQualifs { fn mir_built(tcx: TyCtxt<'_>, def: LocalDefId) -> &Steal> { let mut body = build_mir(tcx, def); + // Identifying trivial consts based on their mir_built is easy, but a little wasteful. + // Trying to push this logic earlier in the compiler and never even produce the Body would + // probably improve compile time. + if trivial_const::trivial_const(tcx, def, || &body).is_some() { + // Skip all the passes below for trivial consts. + let body = tcx.alloc_steal_mir(body); + pass_manager::dump_mir_for_phase_change(tcx, &body.borrow()); + return body; + } + pass_manager::dump_mir_for_phase_change(tcx, &body); pm::run_passes( @@ -409,6 +421,8 @@ fn mir_promoted( tcx: TyCtxt<'_>, def: LocalDefId, ) -> (&Steal>, &Steal>>) { + debug_assert!(!tcx.is_trivial_const(def), "Tried to get mir_promoted of a trivial const"); + // Ensure that we compute the `mir_const_qualif` for constants at // this point, before we steal the mir-const result. // Also this means promotion can rely on all const checks having been done. @@ -436,6 +450,9 @@ fn mir_promoted( tcx.ensure_done().coroutine_by_move_body_def_id(def); } + // the `trivial_const` query uses mir_built, so make sure it is run. + tcx.ensure_done().trivial_const(def); + let mut body = tcx.mir_built(def).steal(); if let Some(error_reported) = const_qualifs.tainted_by_errors { body.tainted_by_errors = Some(error_reported); @@ -463,6 +480,7 @@ fn mir_promoted( /// Compute the MIR that is used during CTFE (and thus has no optimizations run on it) fn mir_for_ctfe(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &Body<'_> { + debug_assert!(!tcx.is_trivial_const(def_id), "Tried to get mir_for_ctfe of a trivial const"); tcx.arena.alloc(inner_mir_for_ctfe(tcx, def_id)) } diff --git a/compiler/rustc_mir_transform/src/trivial_const.rs b/compiler/rustc_mir_transform/src/trivial_const.rs new file mode 100644 index 000000000000..3b80ae30be42 --- /dev/null +++ b/compiler/rustc_mir_transform/src/trivial_const.rs @@ -0,0 +1,110 @@ +use std::ops::Deref; + +use rustc_hir::def::DefKind; +use rustc_hir::def_id::LocalDefId; +use rustc_middle::mir::{ + Body, Const, ConstValue, Operand, Place, RETURN_PLACE, Rvalue, START_BLOCK, StatementKind, + TerminatorKind, UnevaluatedConst, +}; +use rustc_middle::ty::{Ty, TyCtxt, TypeVisitableExt}; + +/// If the given def is a trivial const, returns the value and type the const evaluates to. +/// +/// A "trivial const" is a const which can be easily proven to evaluate successfully, and the value +/// that it evaluates to can be easily found without going through the usual MIR phases for a const. +/// +/// Currently, we support two forms of trivial const. +/// +/// The base case is this: +/// ``` +/// const A: usize = 0; +/// ``` +/// which has this MIR: +/// ```text +/// const A: usize = { +/// let mut _0: usize; +/// +/// bb0: { +/// _0 = const 0_usize; +/// return; +/// } +/// } +/// ``` +/// Which we recognize by looking for a Body which has a single basic block with a return +/// terminator and a single statement which assigns an `Operand::Constant(Const::Val)` to the +/// return place. +/// This scenario meets the required criteria because: +/// * Control flow cannot panic, we don't have any calls or assert terminators +/// * The value of the const is already computed, so it cannot fail +/// +/// In addition to assignment of literals, assignments of trivial consts are also considered +/// trivial consts. In this case, both `A` and `B` are trivial: +/// ``` +/// const A: usize = 0; +/// const B: usize = A; +/// ``` +pub(crate) fn trivial_const<'a, 'tcx: 'a, F, B>( + tcx: TyCtxt<'tcx>, + def: LocalDefId, + body_provider: F, +) -> Option<(ConstValue, Ty<'tcx>)> +where + F: FnOnce() -> B, + B: Deref>, +{ + if !matches!(tcx.def_kind(def), DefKind::AssocConst | DefKind::Const | DefKind::AnonConst) { + return None; + } + + let body = body_provider(); + + if body.has_opaque_types() { + return None; + } + + if body.basic_blocks.len() != 1 { + return None; + } + + let block = &body.basic_blocks[START_BLOCK]; + if block.statements.len() != 1 { + return None; + } + + if block.terminator().kind != TerminatorKind::Return { + return None; + } + + let StatementKind::Assign(box (place, rvalue)) = &block.statements[0].kind else { + return None; + }; + + if *place != Place::from(RETURN_PLACE) { + return None; + } + + let Rvalue::Use(Operand::Constant(c)) = rvalue else { + return None; + }; + match c.const_ { + Const::Ty(..) => None, + Const::Unevaluated(UnevaluatedConst { def, args, .. }, _ty) => { + if !args.is_empty() { + return None; + } + tcx.trivial_const(def) + } + Const::Val(v, ty) => Some((v, ty)), + } +} + +// The query provider is based on calling the free function trivial_const, which calls mir_built, +// which internally has a fast-path for trivial consts so it too calls trivial_const. This isn't +// recursive, but we are checking if the const is trivial twice. A better design might detect +// trivial consts before getting to MIR, which would hopefully straighten this out. +pub(crate) fn trivial_const_provider<'tcx>( + tcx: TyCtxt<'tcx>, + def: LocalDefId, +) -> Option<(ConstValue, Ty<'tcx>)> { + trivial_const(tcx, def, || tcx.mir_built(def).borrow()) +} diff --git a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs index 48bd0963c874..695a29e58a5e 100644 --- a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs @@ -211,10 +211,32 @@ where } fn consider_builtin_copy_clone_candidate( - _ecx: &mut EvalCtxt<'_, D>, - _goal: Goal, + ecx: &mut EvalCtxt<'_, D>, + goal: Goal, ) -> Result, NoSolution> { - Err(NoSolution) + let cx = ecx.cx(); + + let self_ty = goal.predicate.self_ty(); + let constituent_tys = + structural_traits::instantiate_constituent_tys_for_copy_clone_trait(ecx, self_ty)?; + + ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| { + ecx.enter_forall(constituent_tys, |ecx, tys| { + ecx.add_goals( + GoalSource::ImplWhereBound, + tys.into_iter().map(|ty| { + goal.with( + cx, + ty::ClauseKind::HostEffect( + goal.predicate.with_replaced_self_ty(cx, ty), + ), + ) + }), + ); + }); + + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + }) } fn consider_builtin_fn_ptr_trait_candidate( diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index f72bd1b8c268..8d0a3ac94d5a 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -1308,36 +1308,6 @@ where }, ); - // HACK: We bail with overflow if the response would have too many non-region - // inference variables. This tends to only happen if we encounter a lot of - // ambiguous alias types which get replaced with fresh inference variables - // during generalization. This prevents hangs caused by an exponential blowup, - // see tests/ui/traits/next-solver/coherence-alias-hang.rs. - match self.current_goal_kind { - // We don't do so for `NormalizesTo` goals as we erased the expected term and - // bailing with overflow here would prevent us from detecting a type-mismatch, - // causing a coherence error in diesel, see #131969. We still bail with overflow - // when later returning from the parent AliasRelate goal. - CurrentGoalKind::NormalizesTo => {} - CurrentGoalKind::Misc | CurrentGoalKind::CoinductiveTrait => { - let num_non_region_vars = canonical - .variables - .iter() - .filter(|c| !c.is_region() && c.is_existential()) - .count(); - if num_non_region_vars > self.cx().recursion_limit() { - debug!(?num_non_region_vars, "too many inference variables -> overflow"); - return Ok(self.make_ambiguous_response_no_constraints( - MaybeCause::Overflow { - suggest_increasing_limit: true, - keep_constraints: false, - }, - OpaqueTypesJank::AllGood, - )); - } - } - } - Ok(canonical) } diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 57bd0d500d5a..e7c89f079622 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -4036,6 +4036,30 @@ impl<'a> Parser<'a> { self.mk_expr(span, ExprKind::Err(guar)) } + pub(crate) fn mk_unit_expr(&self, span: Span) -> Box { + self.mk_expr(span, ExprKind::Tup(Default::default())) + } + + pub(crate) fn mk_closure_expr(&self, span: Span, body: Box) -> Box { + self.mk_expr( + span, + ast::ExprKind::Closure(Box::new(ast::Closure { + binder: rustc_ast::ClosureBinder::NotPresent, + constness: rustc_ast::Const::No, + movability: rustc_ast::Movability::Movable, + capture_clause: rustc_ast::CaptureBy::Ref, + coroutine_kind: None, + fn_decl: Box::new(rustc_ast::FnDecl { + inputs: Default::default(), + output: rustc_ast::FnRetTy::Default(span), + }), + fn_arg_span: span, + fn_decl_span: span, + body, + })), + ) + } + /// Create expression span ensuring the span of the parent node /// is larger than the span of lhs and rhs, including the attributes. fn mk_expr_sp(&self, lhs: &Box, lhs_span: Span, op_span: Span, rhs_span: Span) -> Span { diff --git a/compiler/rustc_parse/src/parser/generics.rs b/compiler/rustc_parse/src/parser/generics.rs index eb684c3a62f9..2c76c0fe3583 100644 --- a/compiler/rustc_parse/src/parser/generics.rs +++ b/compiler/rustc_parse/src/parser/generics.rs @@ -312,25 +312,48 @@ impl<'a> Parser<'a> { /// Parses an experimental fn contract /// (`contract_requires(WWW) contract_ensures(ZZZ)`) pub(super) fn parse_contract(&mut self) -> PResult<'a, Option>> { - let requires = if self.eat_keyword_noexpect(exp!(ContractRequires).kw) { - self.psess.gated_spans.gate(sym::contracts_internals, self.prev_token.span); - let precond = self.parse_expr()?; - Some(precond) + let (declarations, requires) = self.parse_contract_requires()?; + let ensures = self.parse_contract_ensures()?; + + if requires.is_none() && ensures.is_none() { + Ok(None) } else { - None - }; - let ensures = if self.eat_keyword_noexpect(exp!(ContractEnsures).kw) { + Ok(Some(Box::new(ast::FnContract { declarations, requires, ensures }))) + } + } + + fn parse_contract_requires( + &mut self, + ) -> PResult<'a, (ThinVec, Option>)> { + Ok(if self.eat_keyword_noexpect(exp!(ContractRequires).kw) { + self.psess.gated_spans.gate(sym::contracts_internals, self.prev_token.span); + let mut decls_and_precond = self.parse_block()?; + + let precond = match decls_and_precond.stmts.pop() { + Some(precond) => match precond.kind { + rustc_ast::StmtKind::Expr(expr) => expr, + // Insert dummy node that will be rejected by typechecker to + // avoid reinventing an error + _ => self.mk_unit_expr(decls_and_precond.span), + }, + None => self.mk_unit_expr(decls_and_precond.span), + }; + let precond = self.mk_closure_expr(precond.span, precond); + let decls = decls_and_precond.stmts; + (decls, Some(precond)) + } else { + (Default::default(), None) + }) + } + + fn parse_contract_ensures(&mut self) -> PResult<'a, Option>> { + Ok(if self.eat_keyword_noexpect(exp!(ContractEnsures).kw) { self.psess.gated_spans.gate(sym::contracts_internals, self.prev_token.span); let postcond = self.parse_expr()?; Some(postcond) } else { None - }; - if requires.is_none() && ensures.is_none() { - Ok(None) - } else { - Ok(Some(Box::new(ast::FnContract { requires, ensures }))) - } + }) } /// Parses an optional where-clause. diff --git a/compiler/rustc_public_bridge/src/context/impls.rs b/compiler/rustc_public_bridge/src/context/impls.rs index d9fa65431f5c..25be9e7b3041 100644 --- a/compiler/rustc_public_bridge/src/context/impls.rs +++ b/compiler/rustc_public_bridge/src/context/impls.rs @@ -92,7 +92,8 @@ impl<'tcx, B: Bridge> CompilerCtxt<'tcx, B> { } else { false }; - !must_override && self.tcx.is_mir_available(def_id) + // FIXME: A good reason to make is_mir_available or mir_keys change behavior + !must_override && self.tcx.is_mir_available(def_id) && !self.tcx.is_trivial_const(def_id) } fn filter_fn_def(&self, def_id: DefId) -> Option { diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 1589e3f4092c..9e82237694e3 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -180,6 +180,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { let mut expected = source.descr_expected(); let path_str = Segment::names_to_string(path); let item_str = path.last().unwrap().ident; + if let Some(res) = res { BaseError { msg: format!("expected {}, found {} `{}`", expected, res.descr(), path_str), @@ -821,12 +822,18 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { args_snippet = snippet; } - err.span_suggestion( - call_span, - format!("try calling `{ident}` as a method"), - format!("self.{path_str}({args_snippet})"), - Applicability::MachineApplicable, - ); + if let Some(Res::Def(DefKind::Struct, def_id)) = res { + self.update_err_for_private_tuple_struct_fields(err, &source, def_id); + err.note("constructor is not visible here due to private fields"); + } else { + err.span_suggestion( + call_span, + format!("try calling `{ident}` as a method"), + format!("self.{path_str}({args_snippet})"), + Applicability::MachineApplicable, + ); + } + return (true, suggested_candidates, candidates); } } @@ -1611,6 +1618,47 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { } } + fn update_err_for_private_tuple_struct_fields( + &mut self, + err: &mut Diag<'_>, + source: &PathSource<'_, '_, '_>, + def_id: DefId, + ) -> Option> { + match source { + // e.g. `if let Enum::TupleVariant(field1, field2) = _` + PathSource::TupleStruct(_, pattern_spans) => { + err.primary_message( + "cannot match against a tuple struct which contains private fields", + ); + + // Use spans of the tuple struct pattern. + Some(Vec::from(*pattern_spans)) + } + // e.g. `let _ = Enum::TupleVariant(field1, field2);` + PathSource::Expr(Some(Expr { + kind: ExprKind::Call(path, args), + span: call_span, + .. + })) => { + err.primary_message( + "cannot initialize a tuple struct which contains private fields", + ); + self.suggest_alternative_construction_methods( + def_id, + err, + path.span, + *call_span, + &args[..], + ); + // Use spans of the tuple struct definition. + self.r + .field_idents(def_id) + .map(|fields| fields.iter().map(|f| f.span).collect::>()) + } + _ => None, + } + } + /// Provides context-dependent help for errors reported by the `smart_resolve_path_fragment` /// function. /// Returns `true` if able to provide context-dependent help. @@ -1942,42 +1990,6 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { return true; }; - let update_message = - |this: &mut Self, err: &mut Diag<'_>, source: &PathSource<'_, '_, '_>| { - match source { - // e.g. `if let Enum::TupleVariant(field1, field2) = _` - PathSource::TupleStruct(_, pattern_spans) => { - err.primary_message( - "cannot match against a tuple struct which contains private fields", - ); - - // Use spans of the tuple struct pattern. - Some(Vec::from(*pattern_spans)) - } - // e.g. `let _ = Enum::TupleVariant(field1, field2);` - PathSource::Expr(Some(Expr { - kind: ExprKind::Call(path, args), - span: call_span, - .. - })) => { - err.primary_message( - "cannot initialize a tuple struct which contains private fields", - ); - this.suggest_alternative_construction_methods( - def_id, - err, - path.span, - *call_span, - &args[..], - ); - // Use spans of the tuple struct definition. - this.r - .field_idents(def_id) - .map(|fields| fields.iter().map(|f| f.span).collect::>()) - } - _ => None, - } - }; let is_accessible = self.r.is_accessible_from(ctor_vis, self.parent_scope.module); if let Some(use_span) = self.r.inaccessible_ctor_reexport.get(&span) && is_accessible @@ -2006,13 +2018,14 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { Applicability::MachineApplicable, ); } - update_message(self, err, &source); + self.update_err_for_private_tuple_struct_fields(err, &source, def_id); } if !is_expected(ctor_def) || is_accessible { return true; } - let field_spans = update_message(self, err, &source); + let field_spans = + self.update_err_for_private_tuple_struct_fields(err, &source, def_id); if let Some(spans) = field_spans.filter(|spans| spans.len() > 0 && fields.len() == spans.len()) diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 1636605b234f..f6a4f59cb339 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -1791,7 +1791,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { .into_items() .map(|(k, f)| (k, f.key())) .collect(), - disambiguator: self.disambiguator, trait_map: self.trait_map, lifetime_elision_allowed: self.lifetime_elision_allowed, lint_buffer: Steal::new(self.lint_buffer), diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index de71568e454a..4a5894c9ffa8 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -1107,8 +1107,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // If such resolution is successful and gives the same result // (e.g. if the macro is re-imported), then silence the lint. let no_macro_rules = self.arenas.alloc_macro_rules_scope(MacroRulesScope::Empty); + let ident = path.segments[0].ident; let fallback_binding = self.reborrow().resolve_ident_in_scope_set( - path.segments[0].ident, + ident, ScopeSet::Macro(MacroKind::Bang), &ParentScope { macro_rules: no_macro_rules, ..*parent_scope }, None, @@ -1116,7 +1117,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { None, None, ); - if fallback_binding.ok().and_then(|b| b.res().opt_def_id()) != Some(def_id) { + if let Ok(fallback_binding) = fallback_binding + && fallback_binding.res().opt_def_id() == Some(def_id) + { + // Silence `unused_imports` on the fallback import as well. + self.get_mut().record_use(ident, fallback_binding, Used::Other); + } else { let location = match parent_scope.module.kind { ModuleKind::Def(kind, def_id, name) => { if let Some(name) = name { diff --git a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs index 621cc0fb3ef1..60b3b42989b7 100644 --- a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs +++ b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs @@ -712,7 +712,8 @@ fn encode_ty_name(tcx: TyCtxt<'_>, def_id: DefId) -> String { hir::definitions::DefPathData::ValueNs(..) => "v", hir::definitions::DefPathData::Closure => "C", hir::definitions::DefPathData::Ctor => "c", - hir::definitions::DefPathData::AnonConst => "k", + hir::definitions::DefPathData::AnonConst => "K", + hir::definitions::DefPathData::LateAnonConst => "k", hir::definitions::DefPathData::OpaqueTy => "i", hir::definitions::DefPathData::SyntheticCoroutineBody => "s", hir::definitions::DefPathData::NestedStatic => "n", @@ -722,6 +723,7 @@ fn encode_ty_name(tcx: TyCtxt<'_>, def_id: DefId) -> String { | hir::definitions::DefPathData::MacroNs(..) | hir::definitions::DefPathData::OpaqueLifetime(..) | hir::definitions::DefPathData::LifetimeNs(..) + | hir::definitions::DefPathData::DesugaredAnonymousLifetime | hir::definitions::DefPathData::AnonAssocTy(..) => { bug!("encode_ty_name: unexpected `{:?}`", disambiguated_data.data); } diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 8ff6d567422b..60e301a5fd87 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -1386,10 +1386,12 @@ bitflags::bitflags! { const DIAGNOSTICS = 1 << 1; /// Apply remappings to debug information const DEBUGINFO = 1 << 3; + /// Apply remappings to coverage information + const COVERAGE = 1 << 4; - /// An alias for `macro` and `debuginfo`. This ensures all paths in compiled - /// executables or libraries are remapped but not elsewhere. - const OBJECT = Self::MACRO.bits() | Self::DEBUGINFO.bits(); + /// An alias for `macro`, `debuginfo` and `coverage`. This ensures all paths in compiled + /// executables, libraries and objects are remapped but not elsewhere. + const OBJECT = Self::MACRO.bits() | Self::DEBUGINFO.bits() | Self::COVERAGE.bits(); } } diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 6dd90546de1b..b89aec7d22a9 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -869,8 +869,7 @@ mod desc { pub(crate) const parse_branch_protection: &str = "a `,` separated combination of `bti`, `gcs`, `pac-ret`, (optionally with `pc`, `b-key`, `leaf` if `pac-ret` is set)"; pub(crate) const parse_proc_macro_execution_strategy: &str = "one of supported execution strategies (`same-thread`, or `cross-thread`)"; - pub(crate) const parse_remap_path_scope: &str = - "comma separated list of scopes: `macro`, `diagnostics`, `debuginfo`, `object`, `all`"; + pub(crate) const parse_remap_path_scope: &str = "comma separated list of scopes: `macro`, `diagnostics`, `debuginfo`, `coverage`, `object`, `all`"; pub(crate) const parse_inlining_threshold: &str = "either a boolean (`yes`, `no`, `on`, `off`, etc), or a non-negative number"; pub(crate) const parse_llvm_module_flag: &str = ":::. Type must currently be `u32`. Behavior should be one of (`error`, `warning`, `require`, `override`, `append`, `appendunique`, `max`, `min`)"; @@ -1705,6 +1704,7 @@ pub mod parse { "macro" => RemapPathScopeComponents::MACRO, "diagnostics" => RemapPathScopeComponents::DIAGNOSTICS, "debuginfo" => RemapPathScopeComponents::DEBUGINFO, + "coverage" => RemapPathScopeComponents::COVERAGE, "object" => RemapPathScopeComponents::OBJECT, "all" => RemapPathScopeComponents::all(), _ => return false, diff --git a/compiler/rustc_session/src/output.rs b/compiler/rustc_session/src/output.rs index cba70b5bd5d1..a48a4f649da1 100644 --- a/compiler/rustc_session/src/output.rs +++ b/compiler/rustc_session/src/output.rs @@ -174,7 +174,11 @@ pub fn categorize_crate_type(s: Symbol) -> Option { Some(CRATE_TYPES.iter().find(|(key, _)| *key == s)?.1) } -pub fn collect_crate_types(session: &Session, attrs: &[ast::Attribute]) -> Vec { +pub fn collect_crate_types( + session: &Session, + backend_crate_types: &[CrateType], + attrs: &[ast::Attribute], +) -> Vec { // If we're generating a test executable, then ignore all other output // styles at all other locations if session.opts.test { @@ -219,7 +223,12 @@ pub fn collect_crate_types(session: &Session, attrs: &[ast::Attribute]) -> Vec { "expression that expanded into a format string literal" } + DesugaringKind::RangeExpr => "range expression", } } @@ -1287,6 +1289,7 @@ impl DesugaringKind { DesugaringKind::Contract => value == "Contract", DesugaringKind::PatTyRange => value == "PatTyRange", DesugaringKind::FormatLiteral { .. } => value == "FormatLiteral", + DesugaringKind::RangeExpr => value == "RangeExpr", } } } diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index 2c71b22c4a2b..e40fc04d7664 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -877,7 +877,8 @@ impl<'tcx> Printer<'tcx> for V0SymbolMangler<'tcx> { DefPathData::ValueNs(_) => 'v', DefPathData::Closure => 'C', DefPathData::Ctor => 'c', - DefPathData::AnonConst => 'k', + DefPathData::AnonConst => 'K', + DefPathData::LateAnonConst => 'k', DefPathData::OpaqueTy => 'i', DefPathData::SyntheticCoroutineBody => 's', DefPathData::NestedStatic => 'n', @@ -889,6 +890,7 @@ impl<'tcx> Printer<'tcx> for V0SymbolMangler<'tcx> { | DefPathData::Impl | DefPathData::MacroNs(_) | DefPathData::LifetimeNs(_) + | DefPathData::DesugaredAnonymousLifetime | DefPathData::OpaqueLifetime(_) | DefPathData::AnonAssocTy(..) => { bug!("symbol_names: unexpected DefPathData: {:?}", disambiguated_data.data) diff --git a/compiler/rustc_target/src/callconv/mod.rs b/compiler/rustc_target/src/callconv/mod.rs index 3f7382ee0e2b..a33c246c88c6 100644 --- a/compiler/rustc_target/src/callconv/mod.rs +++ b/compiler/rustc_target/src/callconv/mod.rs @@ -113,13 +113,14 @@ mod attr_impl { pub struct ArgAttribute(u8); bitflags::bitflags! { impl ArgAttribute: u8 { - const NoAlias = 1 << 1; - const CapturesAddress = 1 << 2; - const NonNull = 1 << 3; - const ReadOnly = 1 << 4; - const InReg = 1 << 5; - const NoUndef = 1 << 6; - const CapturesReadOnly = 1 << 7; + const CapturesNone = 0b111; + const CapturesAddress = 0b110; + const CapturesReadOnly = 0b100; + const NoAlias = 1 << 3; + const NonNull = 1 << 4; + const ReadOnly = 1 << 5; + const InReg = 1 << 6; + const NoUndef = 1 << 7; } } rustc_data_structures::external_bitflags_debug! { ArgAttribute } diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index 136a61598d50..4ecc48d6cc40 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -20,7 +20,7 @@ use rustc_hir::intravisit::{Visitor, VisitorExt}; use rustc_hir::lang_items::LangItem; use rustc_hir::{ self as hir, AmbigArg, CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, HirId, Node, - expr_needs_parens, is_range_literal, + expr_needs_parens, }; use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes, InferCtxt, InferOk}; use rustc_middle::middle::privacy::Level; @@ -668,12 +668,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ); } let derefs = "*".repeat(steps); - let needs_parens = steps > 0 - && match expr.kind { - hir::ExprKind::Cast(_, _) | hir::ExprKind::Binary(_, _, _) => true, - _ if is_range_literal(expr) => true, - _ => false, - }; + let needs_parens = steps > 0 && expr_needs_parens(expr); let mut suggestion = if needs_parens { vec![ ( diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs index ddd79e1dc940..7b61a653ae31 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs @@ -24,7 +24,7 @@ use tracing::instrument; use self::derive_errors::*; use super::Certainty; use super::delegate::SolverDelegate; -use super::inspect::{self, ProofTreeInferCtxtExt}; +use super::inspect::{self, InferCtxtProofTreeExt}; use crate::traits::{FulfillmentError, ScrubbedTraitError}; mod derive_errors; diff --git a/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs b/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs index 598de27dfd3c..8482c8a2972d 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs @@ -15,7 +15,7 @@ use rustc_next_trait_solver::solve::{GoalEvaluation, SolverDelegateEvalExt as _} use tracing::{instrument, trace}; use crate::solve::delegate::SolverDelegate; -use crate::solve::inspect::{self, ProofTreeInferCtxtExt, ProofTreeVisitor}; +use crate::solve::inspect::{self, InferCtxtProofTreeExt, ProofTreeVisitor}; use crate::solve::{Certainty, deeply_normalize_for_diagnostics}; use crate::traits::{FulfillmentError, FulfillmentErrorCode, wf}; diff --git a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs index 488315054c6a..cdbf2b0aeb83 100644 --- a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs +++ b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs @@ -463,7 +463,7 @@ pub trait ProofTreeVisitor<'tcx> { fn visit_goal(&mut self, goal: &InspectGoal<'_, 'tcx>) -> Self::Result; } -#[extension(pub trait ProofTreeInferCtxtExt<'tcx>)] +#[extension(pub trait InferCtxtProofTreeExt<'tcx>)] impl<'tcx> InferCtxt<'tcx> { fn visit_proof_tree>( &self, diff --git a/compiler/rustc_trait_selection/src/solve/select.rs b/compiler/rustc_trait_selection/src/solve/select.rs index d7e7ffd5d28c..1feaab240415 100644 --- a/compiler/rustc_trait_selection/src/solve/select.rs +++ b/compiler/rustc_trait_selection/src/solve/select.rs @@ -12,7 +12,7 @@ use rustc_middle::{bug, span_bug}; use rustc_span::Span; use thin_vec::thin_vec; -use crate::solve::inspect::{self, ProofTreeInferCtxtExt}; +use crate::solve::inspect::{self, InferCtxtProofTreeExt}; #[extension(pub trait InferCtxtSelectExt<'tcx>)] impl<'tcx> InferCtxt<'tcx> { diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index f0c006b5e3f6..45357be56399 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -29,7 +29,7 @@ use tracing::{debug, instrument, warn}; use super::ObligationCtxt; use crate::error_reporting::traits::suggest_new_overflow_limit; use crate::infer::InferOk; -use crate::solve::inspect::{InspectGoal, ProofTreeInferCtxtExt, ProofTreeVisitor}; +use crate::solve::inspect::{InferCtxtProofTreeExt, InspectGoal, ProofTreeVisitor}; use crate::solve::{SolverDelegate, deeply_normalize_for_diagnostics, inspect}; use crate::traits::query::evaluate_obligation::InferCtxtExt; use crate::traits::select::IntercrateAmbiguityCause; diff --git a/compiler/rustc_trait_selection/src/traits/effects.rs b/compiler/rustc_trait_selection/src/traits/effects.rs index 7f2a9999d646..c29e3281f224 100644 --- a/compiler/rustc_trait_selection/src/traits/effects.rs +++ b/compiler/rustc_trait_selection/src/traits/effects.rs @@ -8,7 +8,7 @@ use rustc_middle::span_bug; use rustc_middle::traits::query::NoSolution; use rustc_middle::ty::elaborate::elaborate; use rustc_middle::ty::fast_reject::DeepRejectCtxt; -use rustc_middle::ty::{self, TypingMode}; +use rustc_middle::ty::{self, Ty, TypingMode}; use thin_vec::{ThinVec, thin_vec}; use super::SelectionContext; @@ -303,6 +303,9 @@ fn evaluate_host_effect_from_builtin_impls<'tcx>( obligation: &HostEffectObligation<'tcx>, ) -> Result>, EvaluationFailure> { match selcx.tcx().as_lang_item(obligation.predicate.def_id()) { + Some(LangItem::Copy | LangItem::Clone) => { + evaluate_host_effect_for_copy_clone_goal(selcx, obligation) + } Some(LangItem::Destruct) => evaluate_host_effect_for_destruct_goal(selcx, obligation), Some(LangItem::Fn | LangItem::FnMut | LangItem::FnOnce) => { evaluate_host_effect_for_fn_goal(selcx, obligation) @@ -311,6 +314,100 @@ fn evaluate_host_effect_from_builtin_impls<'tcx>( } } +fn evaluate_host_effect_for_copy_clone_goal<'tcx>( + selcx: &mut SelectionContext<'_, 'tcx>, + obligation: &HostEffectObligation<'tcx>, +) -> Result>, EvaluationFailure> { + let tcx = selcx.tcx(); + let self_ty = obligation.predicate.self_ty(); + let constituent_tys = match *self_ty.kind() { + // impl Copy/Clone for FnDef, FnPtr + ty::FnDef(..) | ty::FnPtr(..) | ty::Error(_) => Ok(ty::Binder::dummy(vec![])), + + // Implementations are provided in core + ty::Uint(_) + | ty::Int(_) + | ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) + | ty::Bool + | ty::Float(_) + | ty::Char + | ty::RawPtr(..) + | ty::Never + | ty::Ref(_, _, ty::Mutability::Not) + | ty::Array(..) => Err(EvaluationFailure::NoSolution), + + // Cannot implement in core, as we can't be generic over patterns yet, + // so we'd have to list all patterns and type combinations. + ty::Pat(ty, ..) => Ok(ty::Binder::dummy(vec![ty])), + + ty::Dynamic(..) + | ty::Str + | ty::Slice(_) + | ty::Foreign(..) + | ty::Ref(_, _, ty::Mutability::Mut) + | ty::Adt(_, _) + | ty::Alias(_, _) + | ty::Param(_) + | ty::Placeholder(..) => Err(EvaluationFailure::NoSolution), + + ty::Bound(..) + | ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { + panic!("unexpected type `{self_ty:?}`") + } + + // impl Copy/Clone for (T1, T2, .., Tn) where T1: Copy/Clone, T2: Copy/Clone, .. Tn: Copy/Clone + ty::Tuple(tys) => Ok(ty::Binder::dummy(tys.to_vec())), + + // impl Copy/Clone for Closure where Self::TupledUpvars: Copy/Clone + ty::Closure(_, args) => Ok(ty::Binder::dummy(vec![args.as_closure().tupled_upvars_ty()])), + + // impl Copy/Clone for CoroutineClosure where Self::TupledUpvars: Copy/Clone + ty::CoroutineClosure(_, args) => { + Ok(ty::Binder::dummy(vec![args.as_coroutine_closure().tupled_upvars_ty()])) + } + + // only when `coroutine_clone` is enabled and the coroutine is movable + // impl Copy/Clone for Coroutine where T: Copy/Clone forall T in (upvars, witnesses) + ty::Coroutine(def_id, args) => { + if selcx.should_stall_coroutine(def_id) { + return Err(EvaluationFailure::Ambiguous); + } + match tcx.coroutine_movability(def_id) { + ty::Movability::Static => Err(EvaluationFailure::NoSolution), + ty::Movability::Movable => { + if tcx.features().coroutine_clone() { + Ok(ty::Binder::dummy(vec![ + args.as_coroutine().tupled_upvars_ty(), + Ty::new_coroutine_witness_for_coroutine(tcx, def_id, args), + ])) + } else { + Err(EvaluationFailure::NoSolution) + } + } + } + } + + ty::UnsafeBinder(_) => Err(EvaluationFailure::NoSolution), + + // impl Copy/Clone for CoroutineWitness where T: Copy/Clone forall T in coroutine_hidden_types + ty::CoroutineWitness(def_id, args) => Ok(tcx + .coroutine_hidden_types(def_id) + .instantiate(tcx, args) + .map_bound(|bound| bound.types.to_vec())), + }?; + + Ok(constituent_tys + .iter() + .map(|ty| { + obligation.with( + tcx, + ty.map_bound(|ty| ty::TraitRef::new(tcx, obligation.predicate.def_id(), [ty])) + .to_host_effect_clause(tcx, obligation.predicate.constness), + ) + }) + .collect()) +} + // NOTE: Keep this in sync with `const_conditions_for_destruct` in the new solver. fn evaluate_host_effect_for_destruct_goal<'tcx>( selcx: &mut SelectionContext<'_, 'tcx>, diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 70a0896ae384..ea903bac9d61 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -2877,7 +2877,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { obligations } - fn should_stall_coroutine(&self, def_id: DefId) -> bool { + pub(super) fn should_stall_coroutine(&self, def_id: DefId) -> bool { match self.infcx.typing_mode() { TypingMode::Analysis { defining_opaque_types_and_generators: stalled_generators } => { def_id.as_local().is_some_and(|def_id| stalled_generators.contains(&def_id)) diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs index ed5289c6850e..0f09e548f0e2 100644 --- a/compiler/rustc_ty_utils/src/abi.rs +++ b/compiler/rustc_ty_utils/src/abi.rs @@ -5,6 +5,7 @@ use rustc_abi::{BackendRepr, ExternAbi, PointerKind, Scalar, Size}; use rustc_hir as hir; use rustc_hir::lang_items::LangItem; use rustc_middle::bug; +use rustc_middle::middle::deduced_param_attrs::DeducedParamAttrs; use rustc_middle::query::Providers; use rustc_middle::ty::layout::{ FnAbiError, HasTyCtxt, HasTypingEnv, LayoutCx, LayoutOf, TyAndLayout, fn_can_unwind, @@ -614,37 +615,19 @@ fn fn_abi_adjust_for_abi<'tcx>( if abi.is_rustic_abi() { fn_abi.adjust_for_rust_abi(cx); - // Look up the deduced parameter attributes for this function, if we have its def ID and // we're optimizing in non-incremental mode. We'll tag its parameters with those attributes // as appropriate. - let deduced_param_attrs = + let deduced = if tcx.sess.opts.optimize != OptLevel::No && tcx.sess.opts.incremental.is_none() { fn_def_id.map(|fn_def_id| tcx.deduced_param_attrs(fn_def_id)).unwrap_or_default() } else { &[] }; - - for (arg_idx, arg) in fn_abi.args.iter_mut().enumerate() { - if arg.is_ignore() { - continue; - } - - // If we deduced that this parameter was read-only, add that to the attribute list now. - // - // The `readonly` parameter only applies to pointers, so we can only do this if the - // argument was passed indirectly. (If the argument is passed directly, it's an SSA - // value, so it's implicitly immutable.) - if let &mut PassMode::Indirect { ref mut attrs, .. } = &mut arg.mode { - // The `deduced_param_attrs` list could be empty if this is a type of function - // we can't deduce any parameters for, so make sure the argument index is in - // bounds. - if let Some(deduced_param_attrs) = deduced_param_attrs.get(arg_idx) - && deduced_param_attrs.read_only(tcx, cx.typing_env, arg.layout.ty) - { - debug!("added deduced read-only attribute"); - attrs.regular.insert(ArgAttribute::ReadOnly); - } + if !deduced.is_empty() { + apply_deduced_attributes(cx, deduced, 0, &mut fn_abi.ret); + for (arg_idx, arg) in fn_abi.args.iter_mut().enumerate() { + apply_deduced_attributes(cx, deduced, arg_idx + 1, arg); } } } else { @@ -652,6 +635,34 @@ fn fn_abi_adjust_for_abi<'tcx>( } } +/// Apply deduced optimization attributes to a parameter using an indirect pass mode. +/// +/// `deduced` is a possibly truncated list of deduced attributes for a return place and arguments. +/// `idx` the index of the parameter on the list (0 for a return place, and 1.. for arguments). +fn apply_deduced_attributes<'tcx>( + cx: &LayoutCx<'tcx>, + deduced: &[DeducedParamAttrs], + idx: usize, + arg: &mut ArgAbi<'tcx, Ty<'tcx>>, +) { + // Deduction is performed under the assumption of the indirection pass mode. + let PassMode::Indirect { ref mut attrs, .. } = arg.mode else { + return; + }; + // The default values at the tail of the list are not encoded. + let Some(deduced) = deduced.get(idx) else { + return; + }; + if deduced.read_only(cx.tcx(), cx.typing_env, arg.layout.ty) { + debug!("added deduced ReadOnly attribute"); + attrs.regular.insert(ArgAttribute::ReadOnly); + } + if deduced.captures_none(cx.tcx(), cx.typing_env, arg.layout.ty) { + debug!("added deduced CapturesNone attribute"); + attrs.regular.insert(ArgAttribute::CapturesNone); + } +} + #[tracing::instrument(level = "debug", skip(cx))] fn make_thin_self_ptr<'tcx>( cx: &(impl HasTyCtxt<'tcx> + HasTypingEnv<'tcx>), diff --git a/compiler/rustc_type_ir/src/search_graph/mod.rs b/compiler/rustc_type_ir/src/search_graph/mod.rs index b2a871a21149..4f3f140af67d 100644 --- a/compiler/rustc_type_ir/src/search_graph/mod.rs +++ b/compiler/rustc_type_ir/src/search_graph/mod.rs @@ -924,7 +924,7 @@ enum RebaseReason { /// /// This either happens in the first evaluation step for the cycle head. /// In this case the used provisional result depends on the cycle `PathKind`. - /// We store this path kind to check whether the the provisional cache entry + /// We store this path kind to check whether the provisional cache entry /// we're rebasing relied on the same cycles. /// /// In later iterations cycles always return `stack_entry.provisional_result` diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index ae43fbfe1d69..7d8077f231dd 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -300,7 +300,7 @@ impl Box { /// [zeroed]: mem::MaybeUninit::zeroed #[cfg(not(no_global_oom_handling))] #[inline] - #[stable(feature = "new_zeroed_alloc", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "new_zeroed_alloc", since = "1.92.0")] #[must_use] pub fn new_zeroed() -> Box> { Self::new_zeroed_in(Global) @@ -692,7 +692,7 @@ impl Box<[T]> { /// /// [zeroed]: mem::MaybeUninit::zeroed #[cfg(not(no_global_oom_handling))] - #[stable(feature = "new_zeroed_alloc", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "new_zeroed_alloc", since = "1.92.0")] #[must_use] pub fn new_zeroed_slice(len: usize) -> Box<[mem::MaybeUninit]> { unsafe { RawVec::with_capacity_zeroed(len).into_box(len) } diff --git a/library/alloc/src/collections/btree/map/entry.rs b/library/alloc/src/collections/btree/map/entry.rs index df51be3de54b..add8782a9499 100644 --- a/library/alloc/src/collections/btree/map/entry.rs +++ b/library/alloc/src/collections/btree/map/entry.rs @@ -284,7 +284,7 @@ impl<'a, K: Ord, V, A: Allocator + Clone> Entry<'a, K, V, A> { /// assert_eq!(entry.key(), &"poneyland"); /// ``` #[inline] - #[stable(feature = "btree_entry_insert", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "btree_entry_insert", since = "1.92.0")] pub fn insert_entry(self, value: V) -> OccupiedEntry<'a, K, V, A> { match self { Occupied(mut entry) => { @@ -394,7 +394,7 @@ impl<'a, K: Ord, V, A: Allocator + Clone> VacantEntry<'a, K, V, A> { /// } /// assert_eq!(map["poneyland"], 37); /// ``` - #[stable(feature = "btree_entry_insert", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "btree_entry_insert", since = "1.92.0")] pub fn insert_entry(mut self, value: V) -> OccupiedEntry<'a, K, V, A> { let handle = match self.handle { None => { diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index 2b62b92d4388..0baae0b314eb 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -529,7 +529,7 @@ impl Rc { /// /// [zeroed]: mem::MaybeUninit::zeroed #[cfg(not(no_global_oom_handling))] - #[stable(feature = "new_zeroed_alloc", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "new_zeroed_alloc", since = "1.92.0")] #[must_use] pub fn new_zeroed() -> Rc> { unsafe { @@ -1057,7 +1057,7 @@ impl Rc<[T]> { /// /// [zeroed]: mem::MaybeUninit::zeroed #[cfg(not(no_global_oom_handling))] - #[stable(feature = "new_zeroed_alloc", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "new_zeroed_alloc", since = "1.92.0")] #[must_use] pub fn new_zeroed_slice(len: usize) -> Rc<[mem::MaybeUninit]> { unsafe { diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index c78f2c8a47e0..c6b85ca5b30b 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -536,7 +536,7 @@ impl Arc { /// [zeroed]: mem::MaybeUninit::zeroed #[cfg(not(no_global_oom_handling))] #[inline] - #[stable(feature = "new_zeroed_alloc", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "new_zeroed_alloc", since = "1.92.0")] #[must_use] pub fn new_zeroed() -> Arc> { unsafe { @@ -1205,7 +1205,7 @@ impl Arc<[T]> { /// [zeroed]: mem::MaybeUninit::zeroed #[cfg(not(no_global_oom_handling))] #[inline] - #[stable(feature = "new_zeroed_alloc", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "new_zeroed_alloc", since = "1.92.0")] #[must_use] pub fn new_zeroed_slice(len: usize) -> Arc<[mem::MaybeUninit]> { unsafe { diff --git a/library/core/src/alloc/layout.rs b/library/core/src/alloc/layout.rs index cd5fd77f8659..1f37c978fecf 100644 --- a/library/core/src/alloc/layout.rs +++ b/library/core/src/alloc/layout.rs @@ -316,8 +316,7 @@ impl Layout { // Size 1 Align MAX or Size isize::MAX Align 2 round up to `isize::MAX + 1`.) unsafe { let align_m1 = unchecked_sub(align.as_usize(), 1); - let size_rounded_up = unchecked_add(self.size, align_m1) & !align_m1; - size_rounded_up + unchecked_add(self.size, align_m1) & !align_m1 } } diff --git a/library/core/src/hint.rs b/library/core/src/hint.rs index 23cfdf5bfde2..6efe95a9edce 100644 --- a/library/core/src/hint.rs +++ b/library/core/src/hint.rs @@ -4,6 +4,7 @@ //! //! Hints may be compile time or runtime. +use crate::marker::Destruct; use crate::mem::MaybeUninit; use crate::{intrinsics, ub_checks}; @@ -771,7 +772,11 @@ pub const fn cold_path() { /// ``` #[inline(always)] #[stable(feature = "select_unpredictable", since = "1.88.0")] -pub fn select_unpredictable(condition: bool, true_val: T, false_val: T) -> T { +#[rustc_const_unstable(feature = "const_select_unpredictable", issue = "145938")] +pub const fn select_unpredictable(condition: bool, true_val: T, false_val: T) -> T +where + T: [const] Destruct, +{ // FIXME(https://github.com/rust-lang/unsafe-code-guidelines/issues/245): // Change this to use ManuallyDrop instead. let mut true_val = MaybeUninit::new(true_val); diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index c397e762d558..4cee77fda4fb 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -55,7 +55,7 @@ #![allow(missing_docs)] use crate::ffi::va_list::{VaArgSafe, VaListImpl}; -use crate::marker::{ConstParamTy, DiscriminantKind, PointeeSized, Tuple}; +use crate::marker::{ConstParamTy, Destruct, DiscriminantKind, PointeeSized, Tuple}; use crate::ptr; mod bounds; @@ -477,11 +477,15 @@ pub const fn unlikely(b: bool) -> bool { /// However unlike the public form, the intrinsic will not drop the value that /// is not selected. #[unstable(feature = "core_intrinsics", issue = "none")] +#[rustc_const_unstable(feature = "const_select_unpredictable", issue = "145938")] #[rustc_intrinsic] #[rustc_nounwind] #[miri::intrinsic_fallback_is_spec] #[inline] -pub fn select_unpredictable(b: bool, true_val: T, false_val: T) -> T { +pub const fn select_unpredictable(b: bool, true_val: T, false_val: T) -> T +where + T: [const] Destruct, +{ if b { true_val } else { false_val } } @@ -2728,6 +2732,11 @@ pub unsafe fn vtable_align(ptr: *const ()) -> usize; /// More specifically, this is the offset in bytes between successive /// items of the same type, including alignment padding. /// +/// Note that, unlike most intrinsics, this can only be called at compile-time +/// as backends do not have an implementation for it. The only caller (its +/// stable counterpart) wraps this intrinsic call in a `const` block so that +/// backends only see an evaluated constant. +/// /// The stabilized version of this intrinsic is [`core::mem::size_of`]. #[rustc_nounwind] #[unstable(feature = "core_intrinsics", issue = "none")] @@ -2742,6 +2751,11 @@ pub const fn size_of() -> usize; /// Therefore, implementations must not require the user to uphold /// any safety invariants. /// +/// Note that, unlike most intrinsics, this can only be called at compile-time +/// as backends do not have an implementation for it. The only caller (its +/// stable counterpart) wraps this intrinsic call in a `const` block so that +/// backends only see an evaluated constant. +/// /// The stabilized version of this intrinsic is [`core::mem::align_of`]. #[rustc_nounwind] #[unstable(feature = "core_intrinsics", issue = "none")] diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index bc428c37a88f..e213e1d91a75 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -106,6 +106,7 @@ #![feature(const_cmp)] #![feature(const_destruct)] #![feature(const_eval_select)] +#![feature(const_select_unpredictable)] #![feature(core_intrinsics)] #![feature(coverage_attribute)] #![feature(disjoint_bitor)] diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index fcdb65bd45c9..efb0665b7f46 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -1382,11 +1382,8 @@ macro_rules! nonzero_integer_signedness_dependent_impls { #[doc = concat!("let three = NonZero::new(3", stringify!($Int), ").unwrap();")] /// assert_eq!(three.div_ceil(two), two); /// ``` - #[stable(feature = "unsigned_nonzero_div_ceil", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable( - feature = "unsigned_nonzero_div_ceil", - since = "CURRENT_RUSTC_VERSION" - )] + #[stable(feature = "unsigned_nonzero_div_ceil", since = "1.92.0")] + #[rustc_const_stable(feature = "unsigned_nonzero_div_ceil", since = "1.92.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] diff --git a/library/core/src/panic/location.rs b/library/core/src/panic/location.rs index 593584934447..8176af03d13a 100644 --- a/library/core/src/panic/location.rs +++ b/library/core/src/panic/location.rs @@ -194,8 +194,8 @@ impl<'a> Location<'a> { /// `std::source_location::file_name`, both of which return a nul-terminated `const char*`. #[must_use] #[inline] - #[stable(feature = "file_with_nul", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "file_with_nul", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "file_with_nul", since = "1.92.0")] + #[rustc_const_stable(feature = "file_with_nul", since = "1.92.0")] pub const fn file_as_c_str(&self) -> &'a CStr { let filename = self.filename.as_ptr(); diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 61eb78294f68..024868873395 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -3629,7 +3629,7 @@ impl [T] { /// assert_eq!(a, ['a', 'c', 'd', 'e', 'b', 'f']); /// ``` #[stable(feature = "slice_rotate", since = "1.26.0")] - #[rustc_const_stable(feature = "const_slice_rotate", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_slice_rotate", since = "1.92.0")] pub const fn rotate_left(&mut self, mid: usize) { assert!(mid <= self.len()); let k = self.len() - mid; @@ -3675,7 +3675,7 @@ impl [T] { /// assert_eq!(a, ['a', 'e', 'b', 'c', 'd', 'f']); /// ``` #[stable(feature = "slice_rotate", since = "1.26.0")] - #[rustc_const_stable(feature = "const_slice_rotate", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_slice_rotate", since = "1.92.0")] pub const fn rotate_right(&mut self, k: usize) { assert!(k <= self.len()); let mid = self.len() - k; diff --git a/library/core/src/wtf8.rs b/library/core/src/wtf8.rs index 0c03496c5e36..11cd2b8776f2 100644 --- a/library/core/src/wtf8.rs +++ b/library/core/src/wtf8.rs @@ -565,7 +565,7 @@ impl Iterator for EncodeWide<'_> { #[stable(feature = "encode_wide_fused_iterator", since = "1.62.0")] impl FusedIterator for EncodeWide<'_> {} -#[stable(feature = "encode_wide_debug", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "encode_wide_debug", since = "1.92.0")] impl fmt::Debug for EncodeWide<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { struct CodeUnit(u16); diff --git a/library/coretests/tests/floats/f128.rs b/library/coretests/tests/floats/f128.rs index 62278bf96c3c..8e4f0c9899e1 100644 --- a/library/coretests/tests/floats/f128.rs +++ b/library/coretests/tests/floats/f128.rs @@ -1,8 +1,6 @@ // FIXME(f16_f128): only tested on platforms that have symbols and aren't buggy #![cfg(target_has_reliable_f128)] -#[cfg(any(miri, target_has_reliable_f128_math))] -use super::assert_approx_eq; use super::assert_biteq; // Note these tolerances make sense around zero, but not for more extreme exponents. @@ -20,16 +18,6 @@ const TOL_PRECISE: f128 = 1e-28; // FIXME(f16_f128,miri): many of these have to be disabled since miri does not yet support // the intrinsics. -#[test] -#[cfg(any(miri, target_has_reliable_f128_math))] -fn test_max_recip() { - assert_approx_eq!( - f128::MAX.recip(), - 8.40525785778023376565669454330438228902076605e-4933, - 1e-4900 - ); -} - #[test] fn test_from() { assert_biteq!(f128::from(false), 0.0); diff --git a/library/coretests/tests/floats/f16.rs b/library/coretests/tests/floats/f16.rs index 7ffafd467a51..3cff4259de54 100644 --- a/library/coretests/tests/floats/f16.rs +++ b/library/coretests/tests/floats/f16.rs @@ -1,7 +1,7 @@ // FIXME(f16_f128): only tested on platforms that have symbols and aren't buggy #![cfg(target_has_reliable_f16)] -use super::{assert_approx_eq, assert_biteq}; +use super::assert_biteq; /// Tolerance for results on the order of 10.0e-2 #[allow(unused)] @@ -22,12 +22,6 @@ const TOL_P4: f16 = 10.0; // FIXME(f16_f128,miri): many of these have to be disabled since miri does not yet support // the intrinsics. -#[test] -#[cfg(any(miri, target_has_reliable_f16_math))] -fn test_max_recip() { - assert_approx_eq!(f16::MAX.recip(), 1.526624e-5f16, 1e-4); -} - #[test] fn test_from() { assert_biteq!(f16::from(false), 0.0); diff --git a/library/coretests/tests/floats/mod.rs b/library/coretests/tests/floats/mod.rs index 0348065d17fe..63d5b8fb2c6e 100644 --- a/library/coretests/tests/floats/mod.rs +++ b/library/coretests/tests/floats/mod.rs @@ -38,6 +38,8 @@ trait TestableFloat: Sized { const MUL_ADD_RESULT: Self; /// The result of (-12.3).mul_add(-4.5, -6.7) const NEG_MUL_ADD_RESULT: Self; + /// Reciprocal of the maximum val + const MAX_RECIP: Self; } impl TestableFloat for f16 { @@ -64,6 +66,7 @@ impl TestableFloat for f16 { const RAW_MINUS_14_DOT_25: Self = Self::from_bits(0xcb20); const MUL_ADD_RESULT: Self = 62.031; const NEG_MUL_ADD_RESULT: Self = 48.625; + const MAX_RECIP: Self = 1.526624e-5; } impl TestableFloat for f32 { @@ -92,6 +95,7 @@ impl TestableFloat for f32 { const RAW_MINUS_14_DOT_25: Self = Self::from_bits(0xc1640000); const MUL_ADD_RESULT: Self = 62.05; const NEG_MUL_ADD_RESULT: Self = 48.65; + const MAX_RECIP: Self = 2.938736e-39; } impl TestableFloat for f64 { @@ -116,6 +120,7 @@ impl TestableFloat for f64 { const RAW_MINUS_14_DOT_25: Self = Self::from_bits(0xc02c800000000000); const MUL_ADD_RESULT: Self = 62.050000000000004; const NEG_MUL_ADD_RESULT: Self = 48.650000000000006; + const MAX_RECIP: Self = 5.562684646268003e-309; } impl TestableFloat for f128 { @@ -140,6 +145,7 @@ impl TestableFloat for f128 { const RAW_MINUS_14_DOT_25: Self = Self::from_bits(0xc002c800000000000000000000000000); const MUL_ADD_RESULT: Self = 62.0500000000000000000000000000000037; const NEG_MUL_ADD_RESULT: Self = 48.6500000000000000000000000000000049; + const MAX_RECIP: Self = 8.40525785778023376565669454330438228902076605e-4933; } /// Determine the tolerance for values of the argument type. @@ -1425,6 +1431,7 @@ float_test! { let nan: Float = Float::NAN; let inf: Float = Float::INFINITY; let neg_inf: Float = Float::NEG_INFINITY; + let max: Float = Float::MAX; assert_biteq!((1.0 as Float).recip(), 1.0); assert_biteq!((2.0 as Float).recip(), 0.5); assert_biteq!((-0.4 as Float).recip(), -2.5); @@ -1432,6 +1439,7 @@ float_test! { assert!(nan.recip().is_nan()); assert_biteq!(inf.recip(), 0.0); assert_biteq!(neg_inf.recip(), -0.0); + assert_biteq!(max.recip(), Float::MAX_RECIP); } } diff --git a/library/coretests/tests/hint.rs b/library/coretests/tests/hint.rs index 24de27b24b80..d15730823eb5 100644 --- a/library/coretests/tests/hint.rs +++ b/library/coretests/tests/hint.rs @@ -1,25 +1,33 @@ #[test] fn select_unpredictable_drop() { use core::cell::Cell; + struct X<'a>(&'a Cell); - impl Drop for X<'_> { + impl const Drop for X<'_> { fn drop(&mut self) { self.0.set(true); } } - let a_dropped = Cell::new(false); - let b_dropped = Cell::new(false); - let a = X(&a_dropped); - let b = X(&b_dropped); - assert!(!a_dropped.get()); - assert!(!b_dropped.get()); - let selected = core::hint::select_unpredictable(core::hint::black_box(true), a, b); - assert!(!a_dropped.get()); - assert!(b_dropped.get()); - drop(selected); - assert!(a_dropped.get()); - assert!(b_dropped.get()); + const fn do_test() { + let a_dropped = Cell::new(false); + let b_dropped = Cell::new(false); + let a = X(&a_dropped); + let b = X(&b_dropped); + assert!(!a_dropped.get()); + assert!(!b_dropped.get()); + let selected = core::hint::select_unpredictable(core::hint::black_box(true), a, b); + assert!(!a_dropped.get()); + assert!(b_dropped.get()); + drop(selected); + assert!(a_dropped.get()); + assert!(b_dropped.get()); + } + + do_test(); + const { + do_test(); + } } #[test] diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs index 5c2522acb136..24e59d7cd73b 100644 --- a/library/coretests/tests/lib.rs +++ b/library/coretests/tests/lib.rs @@ -27,6 +27,7 @@ #![feature(const_option_ops)] #![feature(const_ref_cell)] #![feature(const_result_trait_fn)] +#![feature(const_select_unpredictable)] #![feature(const_trait_impl)] #![feature(control_flow_ok)] #![feature(core_float_math)] diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs index 1aa6064633c3..4efdfcad924b 100644 --- a/library/proc_macro/src/lib.rs +++ b/library/proc_macro/src/lib.rs @@ -379,7 +379,7 @@ impl Extend for TokenStream { macro_rules! extend_items { ($($item:ident)*) => { $( - #[stable(feature = "token_stream_extend_tt_items", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "token_stream_extend_tt_items", since = "1.92.0")] impl Extend<$item> for TokenStream { fn extend>(&mut self, iter: T) { self.extend(iter.into_iter().map(TokenTree::$item)); diff --git a/library/std/src/sync/poison/rwlock.rs b/library/std/src/sync/poison/rwlock.rs index fe51d8975e42..10e45bc8c11a 100644 --- a/library/std/src/sync/poison/rwlock.rs +++ b/library/std/src/sync/poison/rwlock.rs @@ -859,7 +859,7 @@ impl<'rwlock, T: ?Sized> RwLockWriteGuard<'rwlock, T> { /// # let final_check = rw.read().unwrap(); /// # assert_eq!(*final_check, 3); /// ``` - #[stable(feature = "rwlock_downgrade", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "rwlock_downgrade", since = "1.92.0")] pub fn downgrade(s: Self) -> RwLockReadGuard<'rwlock, T> { let lock = s.lock; diff --git a/library/std/src/sys/pal/unix/sync/condvar.rs b/library/std/src/sys/pal/unix/sync/condvar.rs index b6c3ba4136f2..73768860723d 100644 --- a/library/std/src/sys/pal/unix/sync/condvar.rs +++ b/library/std/src/sys/pal/unix/sync/condvar.rs @@ -1,6 +1,10 @@ use super::Mutex; use crate::cell::UnsafeCell; use crate::pin::Pin; +#[cfg(not(target_os = "nto"))] +use crate::sys::pal::time::TIMESPEC_MAX; +#[cfg(target_os = "nto")] +use crate::sys::pal::time::TIMESPEC_MAX_CAPPED; use crate::time::Duration; pub struct Condvar { @@ -51,10 +55,6 @@ impl Condvar { /// * `mutex` must be locked by the current thread. /// * This condition variable may only be used with the same mutex. pub unsafe fn wait_timeout(&self, mutex: Pin<&Mutex>, dur: Duration) -> bool { - #[cfg(not(target_os = "nto"))] - use crate::sys::pal::time::TIMESPEC_MAX; - #[cfg(target_os = "nto")] - use crate::sys::pal::time::TIMESPEC_MAX_CAPPED; use crate::sys::pal::time::Timespec; let mutex = mutex.raw(); @@ -118,10 +118,12 @@ impl Condvar { let (dur, clamped) = if dur <= MAX_DURATION { (dur, false) } else { (MAX_DURATION, true) }; - let timeout = libc::timespec { - // This cannot overflow because of the clamping above. - tv_sec: dur.as_secs() as i64, - tv_nsec: dur.subsec_nanos() as i64, + // This can overflow on 32-bit platforms, but not on 64-bit because of the clamping above. + let timeout = if let Ok(tv_sec) = dur.as_secs().try_into() { + libc::timespec { tv_sec, tv_nsec: dur.subsec_nanos() as _ } + } else { + // This is less than `MAX_DURATION` on 32-bit platforms. + TIMESPEC_MAX }; let r = unsafe { libc::pthread_cond_timedwait_relative_np(self.raw(), mutex, &timeout) }; diff --git a/src/bootstrap/src/core/build_steps/doc.rs b/src/bootstrap/src/core/build_steps/doc.rs index 70a9bcf38c0f..6622aae069d5 100644 --- a/src/bootstrap/src/core/build_steps/doc.rs +++ b/src/bootstrap/src/core/build_steps/doc.rs @@ -709,12 +709,12 @@ impl Step for Std { if builder.paths.iter().any(|path| path.ends_with("library")) { // For `x.py doc library --open`, open `std` by default. let index = out.join("std").join("index.html"); - builder.open_in_browser(index); + builder.maybe_open_in_browser::(index); } else { for requested_crate in crates { if STD_PUBLIC_CRATES.iter().any(|&k| k == requested_crate) { let index = out.join(requested_crate).join("index.html"); - builder.open_in_browser(index); + builder.maybe_open_in_browser::(index); break; } } diff --git a/src/bootstrap/src/core/sanity.rs b/src/bootstrap/src/core/sanity.rs index eaa9e3a6a3e9..d0405270f663 100644 --- a/src/bootstrap/src/core/sanity.rs +++ b/src/bootstrap/src/core/sanity.rs @@ -34,7 +34,6 @@ pub struct Finder { // Targets can be removed from this list once they are present in the stage0 compiler (usually by updating the beta compiler of the bootstrap). const STAGE0_MISSING_TARGETS: &[&str] = &[ // just a dummy comment so the list doesn't get onelined - "x86_64-unknown-motor", ]; /// Minimum version threshold for libstdc++ required when using prebuilt LLVM diff --git a/src/ci/citool/src/analysis.rs b/src/ci/citool/src/analysis.rs index 8ba8f1ab564b..39b115154f9f 100644 --- a/src/ci/citool/src/analysis.rs +++ b/src/ci/citool/src/analysis.rs @@ -237,7 +237,7 @@ pub fn output_largest_duration_changes( println!("# Job duration changes"); for (index, entry) in changes.into_iter().take(10).enumerate() { println!( - "{}. {}: {:.1}s -> {:.1}s ({:.1}%)", + "{}. {}: {:.1}s -> {:.1}s ({:+.1}%)", index + 1, format_job_link(job_info_resolver, job_metrics, entry.job), entry.before.as_secs_f64(), diff --git a/src/ci/docker/host-x86_64/dist-loongarch64-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-loongarch64-linux/Dockerfile index e3f23149284e..4b86ed32fd55 100644 --- a/src/ci/docker/host-x86_64/dist-loongarch64-linux/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-loongarch64-linux/Dockerfile @@ -21,7 +21,9 @@ ENV PATH=$PATH:/x-tools/loongarch64-unknown-linux-gnu/bin ENV CC_loongarch64_unknown_linux_gnu=loongarch64-unknown-linux-gnu-gcc \ AR_loongarch64_unknown_linux_gnu=loongarch64-unknown-linux-gnu-ar \ - CXX_loongarch64_unknown_linux_gnu=loongarch64-unknown-linux-gnu-g++ + CXX_loongarch64_unknown_linux_gnu=loongarch64-unknown-linux-gnu-g++ \ + CFLAGS_loongarch64_unknown_linux_gnu="-mcmodel=medium" \ + CXXFLAGS_loongarch64_unknown_linux_gnu="-mcmodel=medium" # We re-use the Linux toolchain for bare-metal, because upstream bare-metal # target support for LoongArch is only available from GCC 14+. diff --git a/src/ci/docker/host-x86_64/dist-loongarch64-musl/Dockerfile b/src/ci/docker/host-x86_64/dist-loongarch64-musl/Dockerfile index 2c33b5526eeb..763b29ae1c5e 100644 --- a/src/ci/docker/host-x86_64/dist-loongarch64-musl/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-loongarch64-musl/Dockerfile @@ -21,7 +21,9 @@ ENV PATH=$PATH:/x-tools/loongarch64-unknown-linux-musl/bin ENV CC_loongarch64_unknown_linux_musl=loongarch64-unknown-linux-musl-gcc \ AR_loongarch64_unknown_linux_musl=loongarch64-unknown-linux-musl-ar \ - CXX_loongarch64_unknown_linux_musl=loongarch64-unknown-linux-musl-g++ + CXX_loongarch64_unknown_linux_musl=loongarch64-unknown-linux-musl-g++ \ + CFLAGS_loongarch64_unknown_linux_musl="-mcmodel=medium" \ + CXXFLAGS_loongarch64_unknown_linux_musl="-mcmodel=medium" ENV HOSTS=loongarch64-unknown-linux-musl diff --git a/src/doc/rustc-dev-guide/rust-version b/src/doc/rustc-dev-guide/rust-version index 47552aee08f7..f100e4116686 100644 --- a/src/doc/rustc-dev-guide/rust-version +++ b/src/doc/rustc-dev-guide/rust-version @@ -1 +1 @@ -4fa824bb78318a3cba8c7339d5754b4909922547 +b1b464d6f61ec8c4e609c1328106378c066a9729 diff --git a/src/doc/rustc-dev-guide/src/building/how-to-build-and-run.md b/src/doc/rustc-dev-guide/src/building/how-to-build-and-run.md index ace834a55b71..efb21726e3c6 100644 --- a/src/doc/rustc-dev-guide/src/building/how-to-build-and-run.md +++ b/src/doc/rustc-dev-guide/src/building/how-to-build-and-run.md @@ -235,12 +235,6 @@ What this command does is: - Build `library` (the standard libraries) with the stage1 compiler that was just built. - Assemble a working stage1 sysroot, containing the stage1 compiler and stage1 standard libraries. -To build `rustc` with the in-tree `std`, use this command instead: - -```console -./x build library --stage 2 -``` - This final product (stage1 compiler + libs built using that compiler) is what you need to build other Rust programs (unless you use `#![no_std]` or `#![no_core]`). diff --git a/src/doc/rustc-dev-guide/src/contributing.md b/src/doc/rustc-dev-guide/src/contributing.md index b4c8f9e9a58c..44d630080bbf 100644 --- a/src/doc/rustc-dev-guide/src/contributing.md +++ b/src/doc/rustc-dev-guide/src/contributing.md @@ -52,9 +52,9 @@ channels: stable, beta, and nightly. - **Stable**: this is the latest stable release for general usage. - **Beta**: this is the next release (will be stable within 6 weeks). -- **Nightly**: follows the `master` branch of the repo. This is the only - channel where unstable, incomplete, or experimental features are usable with - feature gates. +- **Nightly**: follows the `master` branch of the repo. + This is the only channel where unstable features are intended to be used, + which happens via opt-in feature gates. See [this chapter on implementing new features](./implementing_new_features.md) for more information. diff --git a/src/doc/rustc-dev-guide/src/offload/usage.md b/src/doc/rustc-dev-guide/src/offload/usage.md index 9f519984d9bc..7d1a5c9e2e0e 100644 --- a/src/doc/rustc-dev-guide/src/offload/usage.md +++ b/src/doc/rustc-dev-guide/src/offload/usage.md @@ -56,6 +56,13 @@ fn main() { unsafe extern "C" { pub fn kernel_1(array_b: *mut [f64; 256]); } + +#[cfg(not(target_os = "linux"))] +#[unsafe(no_mangle)] +#[inline(never)] +pub extern "gpu-kernel" fn kernel_1(x: *mut [f64; 256]) { + unsafe { (*x)[0] = 21.0 }; +} ``` ## Compile instructions diff --git a/src/doc/rustc-dev-guide/src/rustdoc-internals/search.md b/src/doc/rustc-dev-guide/src/rustdoc-internals/search.md index beff0a94c1ec..9cf59ea0c381 100644 --- a/src/doc/rustc-dev-guide/src/rustdoc-internals/search.md +++ b/src/doc/rustc-dev-guide/src/rustdoc-internals/search.md @@ -521,4 +521,25 @@ const EXPECTED = [ returned: [], }, ] -``` \ No newline at end of file +``` + +If the [`//@ revisions`] directive is used, the JS file will +have access to a variable called `REVISION`. + +```js +const EXPECTED = [ + // This first test targets name-based search. + { + query: "constructor", + others: REVISION === "has_constructor" ? + [ + { path: "constructor_search", name: "constructor" }, + ] : + [], + in_args: [], + returned: [], + }, +]; +``` + +[`//@ revisions`]: ../tests/compiletest.md#revisions diff --git a/src/doc/rustc-dev-guide/src/tests/directives.md b/src/doc/rustc-dev-guide/src/tests/directives.md index 2c6cfeb0ac70..12ceef0c928d 100644 --- a/src/doc/rustc-dev-guide/src/tests/directives.md +++ b/src/doc/rustc-dev-guide/src/tests/directives.md @@ -163,8 +163,10 @@ Some examples of `X` in `ignore-X` or `only-X`: The following directives will check rustc build settings and target settings: -- `needs-asm-support` — ignores if it is running on a target that doesn't have - stable support for `asm!` +- `needs-asm-support` — ignores if the **host** architecture doesn't have + stable support for `asm!`. For tests that cross-compile to explicit targets + via `--target`, use `needs-llvm-components` instead to ensure the appropriate + backend is available. - `needs-profiler-runtime` — ignores the test if the profiler runtime was not enabled for the target (`build.profiler = true` in rustc's `bootstrap.toml`) diff --git a/src/doc/rustc/src/platform-support/android.md b/src/doc/rustc/src/platform-support/android.md index a54288f8f050..dcf7659130a3 100644 --- a/src/doc/rustc/src/platform-support/android.md +++ b/src/doc/rustc/src/platform-support/android.md @@ -9,8 +9,9 @@ ## Target maintainers [@chriswailes](https://github.com/chriswailes) +[@jfgoog](https://github.com/jfgoog) [@maurer](https://github.com/maurer) -[@mgeisler](https://github.com/mgeisler) +[@pirama-arumuga-nainar](https://github.com/pirama-arumuga-nainar) ## Requirements diff --git a/src/doc/rustc/src/platform-support/windows-msvc.md b/src/doc/rustc/src/platform-support/windows-msvc.md index 826c75b79c57..c4b56201e796 100644 --- a/src/doc/rustc/src/platform-support/windows-msvc.md +++ b/src/doc/rustc/src/platform-support/windows-msvc.md @@ -12,6 +12,7 @@ Windows MSVC targets. [@ChrisDenton](https://github.com/ChrisDenton) [@dpaoliello](https://github.com/dpaoliello) +[@Fulgen301](https://github.com/Fulgen301) [@lambdageek](https://github.com/lambdageek) [@sivadeilra](https://github.com/sivadeilra) [@wesleywiser](https://github.com/wesleywiser) diff --git a/src/doc/unstable-book/src/compiler-flags/remap-path-scope.md b/src/doc/unstable-book/src/compiler-flags/remap-path-scope.md index 65219dc68e97..fb1c7d7a6878 100644 --- a/src/doc/unstable-book/src/compiler-flags/remap-path-scope.md +++ b/src/doc/unstable-book/src/compiler-flags/remap-path-scope.md @@ -10,7 +10,8 @@ This flag accepts a comma-separated list of values and may be specified multiple - `macro` - apply remappings to the expansion of `std::file!()` macro. This is where paths in embedded panic messages come from - `diagnostics` - apply remappings to printed compiler diagnostics -- `debuginfo` - apply remappings to debug informations +- `debuginfo` - apply remappings to debug information +- `coverage` - apply remappings to coverage information - `object` - apply remappings to all paths in compiled executables or libraries, but not elsewhere. Currently an alias for `macro,debuginfo`. - `all` - an alias for all of the above, also equivalent to supplying only `--remap-path-prefix` without `--remap-path-scope`. diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index cf0858810f55..630b2a6e5c18 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -311,7 +311,6 @@ pub(crate) enum ModuleSorting { #[derive(Clone, Debug, PartialEq, Eq)] pub(crate) enum EmitType { - Unversioned, Toolchain, InvocationSpecific, DepInfo(Option), @@ -322,7 +321,6 @@ impl FromStr for EmitType { fn from_str(s: &str) -> Result { match s { - "unversioned-shared-resources" => Ok(Self::Unversioned), "toolchain-shared-resources" => Ok(Self::Toolchain), "invocation-specific" => Ok(Self::InvocationSpecific), "dep-info" => Ok(Self::DepInfo(None)), diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 51f79047f991..0d551a969d63 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -1016,9 +1016,6 @@ impl CreateRunnableDocTests { .span(scraped_test.span) .build(dcx); let is_standalone = !doctest.can_be_merged - || scraped_test.langstr.compile_fail - || scraped_test.langstr.test_harness - || scraped_test.langstr.standalone_crate || self.rustdoc_options.nocapture || self.rustdoc_options.test_args.iter().any(|arg| arg == "--show-output"); if is_standalone { diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index f2055608aa9d..c37736f137df 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -8,8 +8,9 @@ use std::borrow::Cow; use std::collections::VecDeque; use std::fmt::{self, Display, Write}; -use std::{cmp, iter}; +use std::iter; +use itertools::Either; use rustc_data_structures::fx::FxIndexMap; use rustc_lexer::{Cursor, FrontmatterAllowed, LiteralKind, TokenKind}; use rustc_span::BytePos; @@ -134,151 +135,322 @@ fn can_merge(class1: Option, class2: Option, text: &str) -> bool { } } +#[derive(Debug)] +struct ClassInfo { + class: Class, + /// If `Some`, then it means the tag was opened and needs to be closed. + closing_tag: Option<&'static str>, + /// Set to `true` by `exit_elem` to signal that all the elements of this class have been pushed. + /// + /// The class will be closed and removed from the stack when the next non-mergeable item is + /// pushed. When it is removed, the closing tag will be written if (and only if) + /// `self.closing_tag` is `Some`. + pending_exit: bool, +} + +impl ClassInfo { + fn new(class: Class, closing_tag: Option<&'static str>) -> Self { + Self { class, closing_tag, pending_exit: closing_tag.is_some() } + } + + fn close_tag(&self, out: &mut W) { + if let Some(closing_tag) = self.closing_tag { + out.write_str(closing_tag).unwrap(); + } + } + + fn is_open(&self) -> bool { + self.closing_tag.is_some() + } +} + +/// This represents the stack of HTML elements. For example a macro expansion +/// will contain other elements which might themselves contain other elements +/// (like macros). +/// +/// This allows to easily handle HTML tags instead of having a more complicated +/// state machine to keep track of which tags are open. +#[derive(Debug)] +struct ClassStack { + open_classes: Vec, +} + +impl ClassStack { + fn new() -> Self { + Self { open_classes: Vec::new() } + } + + fn enter_elem( + &mut self, + out: &mut W, + href_context: &Option>, + new_class: Class, + closing_tag: Option<&'static str>, + ) { + if let Some(current_class) = self.open_classes.last_mut() { + if can_merge(Some(current_class.class), Some(new_class), "") { + current_class.pending_exit = false; + return; + } else if current_class.pending_exit { + current_class.close_tag(out); + self.open_classes.pop(); + } + } + let mut class_info = ClassInfo::new(new_class, closing_tag); + if closing_tag.is_none() { + if matches!(new_class, Class::Decoration(_) | Class::Original) { + // Even if a whitespace characters follows, we need to open the class right away + // as these characters are part of the element. + // FIXME: Should we instead add a new boolean field to `ClassInfo` to force a + // non-open tag to be added if another one comes before it's open? + write!(out, "", new_class.as_html()).unwrap(); + class_info.closing_tag = Some(""); + } else if new_class.get_span().is_some() + && let Some(closing_tag) = + string_without_closing_tag(out, "", Some(class_info.class), href_context, false) + && !closing_tag.is_empty() + { + class_info.closing_tag = Some(closing_tag); + } + } + + self.open_classes.push(class_info); + } + + /// This sets the `pending_exit` field to `true`. Meaning that if we try to push another stack + /// which is not compatible with this one, it will exit the current one before adding the new + /// one. + fn exit_elem(&mut self) { + let current_class = + self.open_classes.last_mut().expect("`exit_elem` called on empty class stack"); + if !current_class.pending_exit { + current_class.pending_exit = true; + return; + } + // If the current class was already closed, it means we are actually closing its parent. + self.open_classes.pop(); + let current_class = + self.open_classes.last_mut().expect("`exit_elem` called on empty class stack parent"); + current_class.pending_exit = true; + } + + fn last_class(&self) -> Option { + self.open_classes.last().map(|c| c.class) + } + + fn last_class_is_open(&self) -> bool { + if let Some(last) = self.open_classes.last() { + last.is_open() + } else { + // If there is no class, then it's already open. + true + } + } + + fn close_last_if_needed(&mut self, out: &mut W) { + if let Some(last) = self.open_classes.pop_if(|class| class.pending_exit && class.is_open()) + { + last.close_tag(out); + } + } + + fn push( + &mut self, + out: &mut W, + href_context: &Option>, + class: Option, + text: Cow<'_, str>, + needs_escape: bool, + ) { + // If the new token cannot be merged with the currently open `Class`, we close the `Class` + // if possible. + if !can_merge(self.last_class(), class, &text) { + self.close_last_if_needed(out) + } + + let current_class = self.last_class(); + + // If we have a `Class` that hasn't been "open" yet (ie, we received only an `EnterSpan` + // event), we need to open the `Class` before going any further so the new token will be + // written inside it. + if class.is_none() && !self.last_class_is_open() { + if let Some(current_class_info) = self.open_classes.last_mut() { + let class_s = current_class_info.class.as_html(); + if !class_s.is_empty() { + write!(out, "").unwrap(); + } + current_class_info.closing_tag = Some(""); + } + } + + let current_class_is_open = self.open_classes.last().is_some_and(|c| c.is_open()); + let can_merge = can_merge(class, current_class, &text); + let should_open_tag = !current_class_is_open || !can_merge; + + let text = + if needs_escape { Either::Left(&EscapeBodyText(&text)) } else { Either::Right(text) }; + + let closing_tag = + string_without_closing_tag(out, &text, class, href_context, should_open_tag); + if class.is_some() && should_open_tag && closing_tag.is_none() { + panic!( + "called `string_without_closing_tag` with a class but no closing tag was returned" + ); + } else if let Some(closing_tag) = closing_tag + && !closing_tag.is_empty() + { + // If this is a link, we need to close it right away and not open a new `Class`, + // otherwise extra content would go into the `` HTML tag. + if closing_tag == "" { + out.write_str(closing_tag).unwrap(); + // If the current `Class` is not compatible with this one, we create a new `Class`. + } else if let Some(class) = class + && !can_merge + { + self.enter_elem(out, href_context, class, Some("")); + // Otherwise, we consider the actual `Class` to have been open. + } else if let Some(current_class_info) = self.open_classes.last_mut() { + current_class_info.closing_tag = Some(""); + } + } + } + + /// This method closes all open tags and returns the list of `Class` which were not already + /// closed (ie `pending_exit` set to `true`). + /// + /// It is used when starting a macro expansion: we need to close all HTML tags and then to + /// reopen them inside the newly created expansion HTML tag. Same goes when we close the + /// expansion. + fn empty_stack(&mut self, out: &mut W) -> Vec { + let mut classes = Vec::with_capacity(self.open_classes.len()); + + // We close all open tags and only keep the ones that were not already waiting to be closed. + while let Some(class_info) = self.open_classes.pop() { + class_info.close_tag(out); + if !class_info.pending_exit { + classes.push(class_info.class); + } + } + classes + } +} + /// This type is used as a conveniency to prevent having to pass all its fields as arguments into /// the various functions (which became its methods). struct TokenHandler<'a, 'tcx, F: Write> { out: &'a mut F, - /// It contains the closing tag and the associated `Class`. - closing_tags: Vec<(&'static str, Class)>, - /// This is used because we don't automatically generate the closing tag on `ExitSpan` in - /// case an `EnterSpan` event with the same class follows. - pending_exit_span: Option, - /// `current_class` and `pending_elems` are used to group HTML elements with same `class` - /// attributes to reduce the DOM size. - current_class: Option, + class_stack: ClassStack, /// We need to keep the `Class` for each element because it could contain a `Span` which is /// used to generate links. - pending_elems: Vec<(Cow<'a, str>, Option)>, href_context: Option>, - write_line_number: fn(&mut F, u32, &'static str), + write_line_number: fn(u32) -> String, + line: u32, + max_lines: u32, } impl std::fmt::Debug for TokenHandler<'_, '_, F> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("TokenHandler") - .field("closing_tags", &self.closing_tags) - .field("pending_exit_span", &self.pending_exit_span) - .field("current_class", &self.current_class) - .field("pending_elems", &self.pending_elems) - .finish() + f.debug_struct("TokenHandler").field("class_stack", &self.class_stack).finish() } } -impl TokenHandler<'_, '_, F> { - fn handle_exit_span(&mut self) { - // We can't get the last `closing_tags` element using `pop()` because `closing_tags` is - // being used in `write_pending_elems`. - let class = self.closing_tags.last().expect("ExitSpan without EnterSpan").1; - // We flush everything just in case... - self.write_pending_elems(Some(class)); - - exit_span(self.out, self.closing_tags.pop().expect("ExitSpan without EnterSpan").0); - self.pending_exit_span = None; +impl<'a, F: Write> TokenHandler<'a, '_, F> { + fn handle_backline(&mut self) -> Option { + self.line += 1; + if self.line < self.max_lines { + return Some((self.write_line_number)(self.line)); + } + None } - /// Write all the pending elements sharing a same (or at mergeable) `Class`. - /// - /// If there is a "parent" (if a `EnterSpan` event was encountered) and the parent can be merged - /// with the elements' class, then we simply write the elements since the `ExitSpan` event will - /// close the tag. - /// - /// Otherwise, if there is only one pending element, we let the `string` function handle both - /// opening and closing the tag, otherwise we do it into this function. - /// - /// It returns `true` if `current_class` must be set to `None` afterwards. - fn write_pending_elems(&mut self, current_class: Option) -> bool { - if self.pending_elems.is_empty() { - return false; - } - if let Some((_, parent_class)) = self.closing_tags.last() - && can_merge(current_class, Some(*parent_class), "") + fn push_token_without_backline_check( + &mut self, + class: Option, + text: Cow<'a, str>, + needs_escape: bool, + ) { + self.class_stack.push(self.out, &self.href_context, class, text, needs_escape); + } + + fn push_token(&mut self, class: Option, text: Cow<'a, str>) { + if text == "\n" + && let Some(backline) = self.handle_backline() { - for (text, class) in self.pending_elems.iter() { - string( - self.out, - EscapeBodyText(text), - *class, - &self.href_context, - false, - self.write_line_number, - ); - } + self.out.write_str(&text).unwrap(); + self.out.write_str(&backline).unwrap(); } else { - // We only want to "open" the tag ourselves if we have more than one pending and if the - // current parent tag is not the same as our pending content. - let close_tag = if self.pending_elems.len() > 1 - && let Some(current_class) = current_class - // `PreludeTy` can never include more than an ident so it should not generate - // a wrapping `span`. - && !matches!(current_class, Class::PreludeTy(_)) - { - Some(enter_span(self.out, current_class, &self.href_context)) - } else { - None - }; - // To prevent opening a macro expansion span being closed right away because - // the currently open item is replaced by a new class. - let last_pending = - self.pending_elems.pop_if(|(_, class)| *class == Some(Class::Expansion)); - for (text, class) in self.pending_elems.iter() { - string( - self.out, - EscapeBodyText(text), - *class, - &self.href_context, - close_tag.is_none(), - self.write_line_number, - ); - } - if let Some(close_tag) = close_tag { - exit_span(self.out, close_tag); - } - if let Some((text, class)) = last_pending { - string( - self.out, - EscapeBodyText(&text), - class, - &self.href_context, - close_tag.is_none(), - self.write_line_number, - ); - } + self.push_token_without_backline_check(class, text, true); } - self.pending_elems.clear(); - true } - #[inline] - fn write_line_number(&mut self, line: u32, extra: &'static str) { - (self.write_line_number)(self.out, line, extra); + fn start_expansion(&mut self) { + // We close all open tags. + let classes = self.class_stack.empty_stack(self.out); + + // We start the expansion tag. + self.class_stack.enter_elem(self.out, &self.href_context, Class::Expansion, None); + self.push_token_without_backline_check( + Some(Class::Expansion), + Cow::Owned(format!( + "", + self.line, + )), + false, + ); + + // We re-open all tags that didn't have `pending_exit` set to `true`. + for class in classes.into_iter().rev() { + self.class_stack.enter_elem(self.out, &self.href_context, class, None); + } + } + + fn add_expanded_code(&mut self, expanded_code: &ExpandedCode) { + self.push_token_without_backline_check( + None, + Cow::Owned(format!("{}", expanded_code.code)), + false, + ); + self.class_stack.enter_elem(self.out, &self.href_context, Class::Original, None); + } + + fn close_expansion(&mut self) { + // We close all open tags. + let classes = self.class_stack.empty_stack(self.out); + + // We re-open all tags without expansion-related ones. + for class in classes.into_iter().rev() { + if !matches!(class, Class::Expansion | Class::Original) { + self.class_stack.enter_elem(self.out, &self.href_context, class, None); + } + } } } impl Drop for TokenHandler<'_, '_, F> { /// When leaving, we need to flush all pending data to not have missing content. fn drop(&mut self) { - if self.pending_exit_span.is_some() { - self.handle_exit_span(); - } else { - self.write_pending_elems(self.current_class); - } + self.class_stack.empty_stack(self.out); } } -fn write_scraped_line_number(out: &mut impl Write, line: u32, extra: &'static str) { +fn scraped_line_number(line: u32) -> String { // https://developers.google.com/search/docs/crawling-indexing/robots-meta-tag#data-nosnippet-attr // Do not show "1 2 3 4 5 ..." in web search results. - write!(out, "{extra}{line}",).unwrap(); + format!("{line}") } -fn write_line_number(out: &mut impl Write, line: u32, extra: &'static str) { +fn line_number(line: u32) -> String { // https://developers.google.com/search/docs/crawling-indexing/robots-meta-tag#data-nosnippet-attr // Do not show "1 2 3 4 5 ..." in web search results. - write!(out, "{extra}{line}",).unwrap(); + format!("{line}") } -fn empty_line_number(out: &mut impl Write, _: u32, extra: &'static str) { - out.write_str(extra).unwrap(); +fn empty_line_number(_: u32) -> String { + String::new() } fn get_next_expansion( @@ -292,80 +464,24 @@ fn get_next_expansion( fn get_expansion<'a, W: Write>( token_handler: &mut TokenHandler<'_, '_, W>, expanded_codes: &'a [ExpandedCode], - line: u32, span: Span, ) -> Option<&'a ExpandedCode> { - if let Some(expanded_code) = get_next_expansion(expanded_codes, line, span) { - let (closing, reopening) = if let Some(current_class) = token_handler.current_class - && let class = current_class.as_html() - && !class.is_empty() - { - ("", format!("")) - } else { - ("", String::new()) - }; - let id = format!("expand-{line}"); - token_handler.pending_elems.push(( - Cow::Owned(format!( - "{closing}\ -\ - {reopening}", - )), - Some(Class::Expansion), - )); - Some(expanded_code) - } else { - None - } -} - -fn start_expansion(out: &mut Vec<(Cow<'_, str>, Option)>, expanded_code: &ExpandedCode) { - out.push(( - Cow::Owned(format!( - "{}", - expanded_code.code, - )), - Some(Class::Expansion), - )); + let expanded_code = get_next_expansion(expanded_codes, token_handler.line, span)?; + token_handler.start_expansion(); + Some(expanded_code) } fn end_expansion<'a, W: Write>( token_handler: &mut TokenHandler<'_, '_, W>, expanded_codes: &'a [ExpandedCode], - expansion_start_tags: &[(&'static str, Class)], - line: u32, span: Span, ) -> Option<&'a ExpandedCode> { - if let Some(expanded_code) = get_next_expansion(expanded_codes, line, span) { - // We close the current "original" content. - token_handler.pending_elems.push((Cow::Borrowed(""), Some(Class::Expansion))); - return Some(expanded_code); + token_handler.class_stack.exit_elem(); + let expansion = get_next_expansion(expanded_codes, token_handler.line, span); + if expansion.is_none() { + token_handler.close_expansion(); } - - let skip = iter::zip(token_handler.closing_tags.as_slice(), expansion_start_tags) - .position(|(tag, start_tag)| tag != start_tag) - .unwrap_or_else(|| cmp::min(token_handler.closing_tags.len(), expansion_start_tags.len())); - - let tags = iter::chain( - expansion_start_tags.iter().skip(skip), - token_handler.closing_tags.iter().skip(skip), - ); - - let mut elem = Cow::Borrowed(""); - - for (tag, _) in tags.clone() { - elem.to_mut().push_str(tag); - } - for (_, class) in tags { - write!(elem.to_mut(), "", class.as_html()).unwrap(); - } - - token_handler.pending_elems.push((elem, Some(Class::Expansion))); - None + expansion } #[derive(Clone, Copy)] @@ -417,29 +533,29 @@ pub(super) fn write_code( if src.contains('\r') { src.replace("\r\n", "\n").into() } else { Cow::Borrowed(src) }; let mut token_handler = TokenHandler { out, - closing_tags: Vec::new(), - pending_exit_span: None, - current_class: None, - pending_elems: Vec::with_capacity(20), href_context, write_line_number: match line_info { Some(line_info) => { if line_info.is_scraped_example { - write_scraped_line_number + scraped_line_number } else { - write_line_number + line_number } } None => empty_line_number, }, + line: 0, + max_lines: u32::MAX, + class_stack: ClassStack::new(), }; - let (mut line, max_lines) = if let Some(line_info) = line_info { - token_handler.write_line_number(line_info.start_line, ""); - (line_info.start_line, line_info.max_lines) - } else { - (0, u32::MAX) - }; + if let Some(line_info) = line_info { + token_handler.line = line_info.start_line - 1; + token_handler.max_lines = line_info.max_lines; + if let Some(text) = token_handler.handle_backline() { + token_handler.push_token_without_backline_check(None, Cow::Owned(text), false); + } + } let (expanded_codes, file_span) = match token_handler.href_context.as_ref().and_then(|c| { let expanded_codes = c.context.shared.expanded_codes.get(&c.file_span.lo())?; @@ -448,114 +564,53 @@ pub(super) fn write_code( Some((expanded_codes, file_span)) => (expanded_codes.as_slice(), file_span), None => (&[] as &[ExpandedCode], DUMMY_SP), }; - let mut current_expansion = get_expansion(&mut token_handler, expanded_codes, line, file_span); - token_handler.write_pending_elems(None); - let mut expansion_start_tags = Vec::new(); + let mut current_expansion = get_expansion(&mut token_handler, expanded_codes, file_span); Classifier::new( &src, token_handler.href_context.as_ref().map(|c| c.file_span).unwrap_or(DUMMY_SP), decoration_info, ) - .highlight(&mut |span, highlight| { - match highlight { - Highlight::Token { text, class } => { - // If we received a `ExitSpan` event and then have a non-compatible `Class`, we - // need to close the ``. - let need_current_class_update = if let Some(pending) = - token_handler.pending_exit_span - && !can_merge(Some(pending), class, text) + .highlight(&mut |span, highlight| match highlight { + Highlight::Token { text, class } => { + token_handler.push_token(class, Cow::Borrowed(text)); + + if text == "\n" { + if current_expansion.is_none() { + current_expansion = get_expansion(&mut token_handler, expanded_codes, span); + } + if let Some(ref current_expansion) = current_expansion + && current_expansion.span.lo() == span.hi() { - token_handler.handle_exit_span(); - true - // If the two `Class` are different, time to flush the current content and start - // a new one. - } else if !can_merge(token_handler.current_class, class, text) { - token_handler.write_pending_elems(token_handler.current_class); - true - } else { - token_handler.current_class.is_none() - }; - - if need_current_class_update { - token_handler.current_class = class.map(Class::dummy); + token_handler.add_expanded_code(current_expansion); } - if text == "\n" { - line += 1; - if line < max_lines { - token_handler - .pending_elems - .push((Cow::Borrowed(text), Some(Class::Backline(line)))); - } - if current_expansion.is_none() { - current_expansion = - get_expansion(&mut token_handler, expanded_codes, line, span); - expansion_start_tags = token_handler.closing_tags.clone(); - } - if let Some(ref current_expansion) = current_expansion - && current_expansion.span.lo() == span.hi() + } else { + let mut need_end = false; + if let Some(ref current_expansion) = current_expansion { + if current_expansion.span.lo() == span.hi() { + token_handler.add_expanded_code(current_expansion); + } else if current_expansion.end_line == token_handler.line + && span.hi() >= current_expansion.span.hi() { - start_expansion(&mut token_handler.pending_elems, current_expansion); - } - } else { - token_handler.pending_elems.push((Cow::Borrowed(text), class)); - - let mut need_end = false; - if let Some(ref current_expansion) = current_expansion { - if current_expansion.span.lo() == span.hi() { - start_expansion(&mut token_handler.pending_elems, current_expansion); - } else if current_expansion.end_line == line - && span.hi() >= current_expansion.span.hi() - { - need_end = true; - } - } - if need_end { - current_expansion = end_expansion( - &mut token_handler, - expanded_codes, - &expansion_start_tags, - line, - span, - ); + need_end = true; } } - } - Highlight::EnterSpan { class } => { - let mut should_add = true; - if let Some(pending_exit_span) = token_handler.pending_exit_span { - if class.is_equal_to(pending_exit_span) { - should_add = false; - } else { - token_handler.handle_exit_span(); - } - } else { - // We flush everything just in case... - if token_handler.write_pending_elems(token_handler.current_class) { - token_handler.current_class = None; - } + if need_end { + current_expansion = end_expansion(&mut token_handler, expanded_codes, span); } - if should_add { - let closing_tag = - enter_span(token_handler.out, class, &token_handler.href_context); - token_handler.closing_tags.push((closing_tag, class)); - } - - token_handler.current_class = None; - token_handler.pending_exit_span = None; } - Highlight::ExitSpan => { - token_handler.current_class = None; - token_handler.pending_exit_span = Some( - token_handler - .closing_tags - .last() - .as_ref() - .expect("ExitSpan without EnterSpan") - .1, - ); - } - }; + } + Highlight::EnterSpan { class } => { + token_handler.class_stack.enter_elem( + token_handler.out, + &token_handler.href_context, + class, + None, + ); + } + Highlight::ExitSpan => { + token_handler.class_stack.exit_elem(); + } }); } @@ -585,9 +640,10 @@ enum Class { PreludeVal(Span), QuestionMark, Decoration(&'static str), - Backline(u32), /// Macro expansion. Expansion, + /// "original" code without macro expansion. + Original, } impl Class { @@ -605,17 +661,6 @@ impl Class { } } - /// If `self` contains a `Span`, it'll be replaced with `DUMMY_SP` to prevent creating links - /// on "empty content" (because of the attributes merge). - fn dummy(self) -> Self { - match self { - Self::Self_(_) => Self::Self_(DUMMY_SP), - Self::Macro(_) => Self::Macro(DUMMY_SP), - Self::Ident(_) => Self::Ident(DUMMY_SP), - s => s, - } - } - /// Returns the css class expected by rustdoc for each `Class`. fn as_html(self) -> &'static str { match self { @@ -636,8 +681,8 @@ impl Class { Class::PreludeVal(_) => "prelude-val", Class::QuestionMark => "question-mark", Class::Decoration(kind) => kind, - Class::Backline(_) => "", - Class::Expansion => "", + Class::Expansion => "expansion", + Class::Original => "original", } } @@ -662,12 +707,22 @@ impl Class { | Self::Lifetime | Self::QuestionMark | Self::Decoration(_) - | Self::Backline(_) + | Self::Original | Self::Expansion => None, } } } +impl fmt::Display for Class { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let html = self.as_html(); + if html.is_empty() { + return Ok(()); + } + write!(f, " class=\"{html}\"") + } +} + #[derive(Debug)] enum Highlight<'a> { Token { text: &'a str, class: Option }, @@ -745,12 +800,15 @@ impl<'a> PeekIter<'a> { None } } + + fn stop_peeking(&mut self) { + self.peek_pos = 0; + } } impl<'a> Iterator for PeekIter<'a> { type Item = (TokenKind, &'a str); fn next(&mut self) -> Option { - self.peek_pos = 0; if let Some(first) = self.stored.pop_front() { Some(first) } else { self.iter.next() } } } @@ -1130,31 +1188,35 @@ impl<'src> Classifier<'src> { LiteralKind::Float { .. } | LiteralKind::Int { .. } => Class::Number, }, TokenKind::GuardedStrPrefix => return no_highlight(sink), - TokenKind::Ident | TokenKind::RawIdent if lookahead == Some(TokenKind::Bang) => { + TokenKind::Ident | TokenKind::RawIdent + if self.peek_non_whitespace() == Some(TokenKind::Bang) => + { self.in_macro = true; let span = new_span(before, text, file_span); sink(DUMMY_SP, Highlight::EnterSpan { class: Class::Macro(span) }); sink(span, Highlight::Token { text, class: None }); return; } - TokenKind::Ident => match get_real_ident_class(text, false) { - None => match text { - "Option" | "Result" => Class::PreludeTy(new_span(before, text, file_span)), - "Some" | "None" | "Ok" | "Err" => { - Class::PreludeVal(new_span(before, text, file_span)) - } - // "union" is a weak keyword and is only considered as a keyword when declaring - // a union type. - "union" if self.check_if_is_union_keyword() => Class::KeyWord, - _ if self.in_macro_nonterminal => { - self.in_macro_nonterminal = false; - Class::MacroNonTerminal - } - "self" | "Self" => Class::Self_(new_span(before, text, file_span)), - _ => Class::Ident(new_span(before, text, file_span)), - }, - Some(c) => c, - }, + TokenKind::Ident => { + match get_real_ident_class(text, false) { + None => match text { + "Option" | "Result" => Class::PreludeTy(new_span(before, text, file_span)), + "Some" | "None" | "Ok" | "Err" => { + Class::PreludeVal(new_span(before, text, file_span)) + } + // "union" is a weak keyword and is only considered as a keyword when declaring + // a union type. + "union" if self.check_if_is_union_keyword() => Class::KeyWord, + _ if self.in_macro_nonterminal => { + self.in_macro_nonterminal = false; + Class::MacroNonTerminal + } + "self" | "Self" => Class::Self_(new_span(before, text, file_span)), + _ => Class::Ident(new_span(before, text, file_span)), + }, + Some(c) => c, + } + } TokenKind::RawIdent | TokenKind::UnknownPrefix | TokenKind::InvalidIdent => { Class::Ident(new_span(before, text, file_span)) } @@ -1179,68 +1241,20 @@ impl<'src> Classifier<'src> { self.tokens.peek().map(|(token_kind, _text)| *token_kind) } - fn check_if_is_union_keyword(&mut self) -> bool { - while let Some(kind) = self.tokens.peek_next().map(|(token_kind, _text)| token_kind) { - if *kind == TokenKind::Whitespace { - continue; + fn peek_non_whitespace(&mut self) -> Option { + while let Some((token_kind, _)) = self.tokens.peek_next() { + if *token_kind != TokenKind::Whitespace { + let token_kind = *token_kind; + self.tokens.stop_peeking(); + return Some(token_kind); } - return *kind == TokenKind::Ident; } - false + self.tokens.stop_peeking(); + None } -} -/// Called when we start processing a span of text that should be highlighted. -/// The `Class` argument specifies how it should be highlighted. -fn enter_span( - out: &mut impl Write, - klass: Class, - href_context: &Option>, -) -> &'static str { - string_without_closing_tag(out, "", Some(klass), href_context, true).expect( - "internal error: enter_span was called with Some(klass) but did not return a \ - closing HTML tag", - ) -} - -/// Called at the end of a span of highlighted text. -fn exit_span(out: &mut impl Write, closing_tag: &str) { - out.write_str(closing_tag).unwrap(); -} - -/// Called for a span of text. If the text should be highlighted differently -/// from the surrounding text, then the `Class` argument will be a value other -/// than `None`. -/// -/// The following sequences of callbacks are equivalent: -/// ```plain -/// enter_span(Foo), string("text", None), exit_span() -/// string("text", Foo) -/// ``` -/// -/// The latter can be thought of as a shorthand for the former, which is more -/// flexible. -/// -/// Note that if `context` is not `None` and that the given `klass` contains a `Span`, the function -/// will then try to find this `span` in the `span_correspondence_map`. If found, it'll then -/// generate a link for this element (which corresponds to where its definition is located). -fn string( - out: &mut W, - text: EscapeBodyText<'_>, - klass: Option, - href_context: &Option>, - open_tag: bool, - write_line_number_callback: fn(&mut W, u32, &'static str), -) { - if let Some(Class::Backline(line)) = klass { - write_line_number_callback(out, line, "\n"); - } else if let Some(Class::Expansion) = klass { - // This has already been escaped so we get the text to write it directly. - out.write_str(text.0).unwrap(); - } else if let Some(closing_tag) = - string_without_closing_tag(out, text, klass, href_context, open_tag) - { - out.write_str(closing_tag).unwrap(); + fn check_if_is_union_keyword(&mut self) -> bool { + self.peek_non_whitespace().is_some_and(|kind| kind == TokenKind::Ident) } } diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 5f72064f0a8c..dd6378b25def 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -6,6 +6,7 @@ #![feature(ascii_char)] #![feature(ascii_char_variants)] #![feature(assert_matches)] +#![feature(box_into_inner)] #![feature(box_patterns)] #![feature(debug_closure_helpers)] #![feature(file_buffered)] @@ -566,7 +567,7 @@ fn opts() -> Vec { "", "emit", "Comma separated list of types of output for rustdoc to emit", - "[unversioned-shared-resources,toolchain-shared-resources,invocation-specific,dep-info]", + "[toolchain-shared-resources,invocation-specific,dep-info]", ), opt(Unstable, FlagMulti, "", "no-run", "Compile doctests without running them", ""), opt( diff --git a/src/stage0 b/src/stage0 index 556ced41d3da..43e1a635a42c 100644 --- a/src/stage0 +++ b/src/stage0 @@ -13,528 +13,528 @@ nightly_branch=master # All changes below this comment will be overridden the next time the # tool is executed. -compiler_channel_manifest_hash=55f3014ea3a3b17cfa5060d9188fd13d13b065456661a3d670dd061719713f32 -compiler_git_commit_hash=bb624dcb4c8ab987e10c0808d92d76f3b84dd117 -compiler_date=2025-09-21 +compiler_channel_manifest_hash=d8adf7e1722d2dc8ebdb327ee661e58a58145464bfcd9bb3cab66d652cc7bb90 +compiler_git_commit_hash=3b4dd9bf1410f8da6329baa36ce5e37673cbbd1f +compiler_date=2025-10-28 compiler_version=beta -rustfmt_channel_manifest_hash=2f19b9b74a17d0283264a227ed552d7df6729929fcb73b2d5bb321feed8a5c85 -rustfmt_git_commit_hash=54a8a1db604e4caff93e26e167ad4a6fde9f0681 -rustfmt_date=2025-09-27 +rustfmt_channel_manifest_hash=108599f303463cabaef3b53ab5e0c0e560a6a5a97f606d75a802efb595141baf +rustfmt_git_commit_hash=adaa838976ff99a4f0661136322f64cb466b58a0 +rustfmt_date=2025-10-28 rustfmt_version=nightly -dist/2025-09-21/rustc-beta-aarch64-apple-darwin.tar.gz=08f8aee2085d8da9041fa9f4c7c6d79b5b1c06c544a3e2309f353844e1250bd0 -dist/2025-09-21/rustc-beta-aarch64-apple-darwin.tar.xz=a36bed31d0f600ca8e8efc19322fe05a88e31bc218078e79c8ca0e7c3d582b20 -dist/2025-09-21/rustc-beta-aarch64-pc-windows-gnullvm.tar.gz=2b6b8f275d1b03ed7bc05e631378c0b462d274b7f1f038f2feec752b29993b10 -dist/2025-09-21/rustc-beta-aarch64-pc-windows-gnullvm.tar.xz=13adf0b39c176761adcf754671911d5309cf04348ef9f93fcf8c09afa6b70da0 -dist/2025-09-21/rustc-beta-aarch64-pc-windows-msvc.tar.gz=568566c82dd296babbd5588d0c69f23c5b5bfd32b3b25e493e6d45f15d645db7 -dist/2025-09-21/rustc-beta-aarch64-pc-windows-msvc.tar.xz=8357fb4ec176279416cabc0edbb2f7c3d4c812975867c8dd490fd2ee30ed1d1f -dist/2025-09-21/rustc-beta-aarch64-unknown-linux-gnu.tar.gz=a885d01f6f5043bacb3bf4820777e29ab45aac4dbdfed75ee71a3de01b056e05 -dist/2025-09-21/rustc-beta-aarch64-unknown-linux-gnu.tar.xz=3a2bed859214bbea2cdd13675eaf480e62c01646efed26067ba7078e6dd8591f -dist/2025-09-21/rustc-beta-aarch64-unknown-linux-musl.tar.gz=4b66e79a48d172eb674ba7e6b4eea91ebda2351d6d253deef90010ffc48d4801 -dist/2025-09-21/rustc-beta-aarch64-unknown-linux-musl.tar.xz=131f270aee35b36ae02959abe032c77e1de0c75f23f7c61bbca1e2c18a23f4f9 -dist/2025-09-21/rustc-beta-arm-unknown-linux-gnueabi.tar.gz=d8c38594dfd1ef17c9ceb2ea614be730f4647fa5e75e80b5bc12d235216ecbf4 -dist/2025-09-21/rustc-beta-arm-unknown-linux-gnueabi.tar.xz=1643434757b590b1586e9074e82be3cc9e50e5551212d5f2040fdd8feba8f1e2 -dist/2025-09-21/rustc-beta-arm-unknown-linux-gnueabihf.tar.gz=1619461791fa6c2b8750043a41acd285bdf1f32d376af675343be3449bb7e5b8 -dist/2025-09-21/rustc-beta-arm-unknown-linux-gnueabihf.tar.xz=cd2ed3ae30cf77b5530a2ebee13daeb1419ceec2ab18f754d07b081dd6a607c1 -dist/2025-09-21/rustc-beta-armv7-unknown-linux-gnueabihf.tar.gz=b0703e79530bd836df864facbfb5065c3e5e8b3a457e4ef55b4f7a4d362b9ba8 -dist/2025-09-21/rustc-beta-armv7-unknown-linux-gnueabihf.tar.xz=a647780abbe8d36049edd90857b3baab556ac9b61caaef1d98307fe92fc20453 -dist/2025-09-21/rustc-beta-i686-pc-windows-gnu.tar.gz=c7ec1f853b96edbf1a914b8345b025c87641225e0c49507bbffd88f2da05b8f4 -dist/2025-09-21/rustc-beta-i686-pc-windows-gnu.tar.xz=53803baae3061eb164f34900f5867cfdf3bf50733ca0a6bda674b491bc0250b8 -dist/2025-09-21/rustc-beta-i686-pc-windows-msvc.tar.gz=a0f9192059b9989db0c4dba57b5eae9cace1b8e6f8bb2362b028c7f36e34d44c -dist/2025-09-21/rustc-beta-i686-pc-windows-msvc.tar.xz=f8c237af5f0e2fe293671ddfe7fcf90f6e2b161a52314b2eb622f2a1b23ba3fc -dist/2025-09-21/rustc-beta-i686-unknown-linux-gnu.tar.gz=da2a42e5a76e95460a348ba70cdf1c5c6ade82eb6ad3796935158bbf5859b602 -dist/2025-09-21/rustc-beta-i686-unknown-linux-gnu.tar.xz=c98df2f0156c3065179f50d55dafda8c5db1f2eae99ecb3f568a8861299be289 -dist/2025-09-21/rustc-beta-loongarch64-unknown-linux-gnu.tar.gz=1149494d96b4ce949308620a360a365c4304b8ee8f8c9512a35f08048aa13c78 -dist/2025-09-21/rustc-beta-loongarch64-unknown-linux-gnu.tar.xz=c906f519bc65a3a7514a62f8920d334bc10623a76dd2d3464af88065b79cb334 -dist/2025-09-21/rustc-beta-loongarch64-unknown-linux-musl.tar.gz=e3a9dd7ae0179ebb7659024532b9f3cca9ac4cdf62c0ae411b00d8f8768aaa34 -dist/2025-09-21/rustc-beta-loongarch64-unknown-linux-musl.tar.xz=d9f3428d80a7b72b15c62bd3306628820f73b64f48de37ea079699b733bda048 -dist/2025-09-21/rustc-beta-powerpc-unknown-linux-gnu.tar.gz=4b52241a8b65a9a42db2a75e057176a99e3b434907f498c4b6b9da104e138c72 -dist/2025-09-21/rustc-beta-powerpc-unknown-linux-gnu.tar.xz=40f3a5fc7478b40153ab20e3f14a6d838c80dda529481735e898de989a31f963 -dist/2025-09-21/rustc-beta-powerpc64-unknown-linux-gnu.tar.gz=f5aa411dfe614ed288351fa4b17d1e2935501c804c0ad51f22e3db71617b17ea -dist/2025-09-21/rustc-beta-powerpc64-unknown-linux-gnu.tar.xz=b9efeb2e185e43775d309d083d8c4f45e30e18b7af71b9c45e397af6bc723fcf -dist/2025-09-21/rustc-beta-powerpc64le-unknown-linux-gnu.tar.gz=38b6a69885e4dac48f7c3128ff1e88d0bf2d0ce1fbd6a5baa9dda62bca0b2b08 -dist/2025-09-21/rustc-beta-powerpc64le-unknown-linux-gnu.tar.xz=8576ae6d787b0f8b127bb2dbeee213cc6093ba92dc7d5ff08f463d56e2e6ce90 -dist/2025-09-21/rustc-beta-powerpc64le-unknown-linux-musl.tar.gz=5e91ce627e900da2606782ae60598843a6ba17593a7eb0dcc8f5f9a1cc20676d -dist/2025-09-21/rustc-beta-powerpc64le-unknown-linux-musl.tar.xz=fe24fad781f829838592e6670655dcff52002ae720f987868fd4b17eb9ed631e -dist/2025-09-21/rustc-beta-riscv64gc-unknown-linux-gnu.tar.gz=170ccaaa94eb7c813bcedf2afb37cb0c696c5f48ca9d93238ee8cf26efc5bafa -dist/2025-09-21/rustc-beta-riscv64gc-unknown-linux-gnu.tar.xz=db5a862a260fe8688e3b1da1161948eed5361723a296bb27dcc62758eaa2b873 -dist/2025-09-21/rustc-beta-s390x-unknown-linux-gnu.tar.gz=c764aa7b70dacf7ac3ef5d2184d021304b633309b771f24d62375fa64791614f -dist/2025-09-21/rustc-beta-s390x-unknown-linux-gnu.tar.xz=69eedf71d20924d9729684e27a3a8cebc60efa7c0e7a3f8b6fe664f469a36788 -dist/2025-09-21/rustc-beta-sparcv9-sun-solaris.tar.gz=efb9d78cc395774e05353615c029ed674c1ba55204ae9be3d022abda9f5c6d9c -dist/2025-09-21/rustc-beta-sparcv9-sun-solaris.tar.xz=e8de37de871888886bb58d915f3a27bfd8c30a912ea3f3af4abf52f66708268f -dist/2025-09-21/rustc-beta-x86_64-apple-darwin.tar.gz=b945ef94a4efdc0fdd4a66c3708cb95a97592c922652af06d8d1b6bbaaf71660 -dist/2025-09-21/rustc-beta-x86_64-apple-darwin.tar.xz=876a6080177df194c14d0984f112692295a21186b05bd03a77d0a304dec5ad51 -dist/2025-09-21/rustc-beta-x86_64-pc-solaris.tar.gz=d7c0b4fb19c785ed3a0c16d903cef266438031c3a43b1721d19864a1923d3cb4 -dist/2025-09-21/rustc-beta-x86_64-pc-solaris.tar.xz=b4a5494890bd92b85f66054523b26e9aae5e74b3177c9eae64740ed7fa1d4da4 -dist/2025-09-21/rustc-beta-x86_64-pc-windows-gnu.tar.gz=ea55aab0bd57f0cd6568a6e78c9d0a3727fb7cfaf8ada9379084091244b3221b -dist/2025-09-21/rustc-beta-x86_64-pc-windows-gnu.tar.xz=426009c68fa78001b34f8b329cac7634dd8921c569061f45972058b770206f9f -dist/2025-09-21/rustc-beta-x86_64-pc-windows-gnullvm.tar.gz=c79a925f6f2b406db97732e22e1b245ef2c7d1291a574b0d55a861d3c7e5d766 -dist/2025-09-21/rustc-beta-x86_64-pc-windows-gnullvm.tar.xz=0f46e118b67656fe16c484589ee0213654cd6edfbe5a29d641aa810bddcc8c62 -dist/2025-09-21/rustc-beta-x86_64-pc-windows-msvc.tar.gz=d7b5fb269841039af498a6d0be2cbd70cb7b65f6a9918a2b6c022cadfdb30fcd -dist/2025-09-21/rustc-beta-x86_64-pc-windows-msvc.tar.xz=dfef15ca4fcf06622953296ebec960e446402ce542e2f264c12c0c03b9a476ce -dist/2025-09-21/rustc-beta-x86_64-unknown-freebsd.tar.gz=09994a33e03f50212cabee85294dfb684fafcef95e1de5b082540d01d92df1ce -dist/2025-09-21/rustc-beta-x86_64-unknown-freebsd.tar.xz=a0e3409ec6f6b02517c8f9d0e00a0627434f6b06a5360da286c46ceab9d12ab1 -dist/2025-09-21/rustc-beta-x86_64-unknown-illumos.tar.gz=01daeea1f1f10d84444b56e8e74e3a451c54e65832234b2caa2ce0a63c0a9ea1 -dist/2025-09-21/rustc-beta-x86_64-unknown-illumos.tar.xz=6299fa81533b9362d1cdbf7984506fcbc26f7d9e857a942f081f5325c87cc4c4 -dist/2025-09-21/rustc-beta-x86_64-unknown-linux-gnu.tar.gz=cafaecb5158fcf39b676baf2d0060fb8b31558be0e442389755ae33a3e7bb42f -dist/2025-09-21/rustc-beta-x86_64-unknown-linux-gnu.tar.xz=5d3c1fceba5285bc54f5a327841ecb8893e719ba874e483c904b903f4dc293ed -dist/2025-09-21/rustc-beta-x86_64-unknown-linux-musl.tar.gz=290a07f32c769f74d21c57a856b3aa39da89e2f086e53c42f3333d1f9ffb5673 -dist/2025-09-21/rustc-beta-x86_64-unknown-linux-musl.tar.xz=8bb354230d3da85bb0fc280c3e95ceadd9f7522d231fe787be8c82aa072ad506 -dist/2025-09-21/rustc-beta-x86_64-unknown-netbsd.tar.gz=af3c98fb99b419cfe50433f5f4a046065066183b248708ec8800253867c678df -dist/2025-09-21/rustc-beta-x86_64-unknown-netbsd.tar.xz=0ea09297621d3b735b2931f6472f95e1587d38f6fb0df7fdf5e427fa3baec4a1 -dist/2025-09-21/rust-std-beta-aarch64-apple-darwin.tar.gz=8c08542fe69e9fd5b2256d17d84427ac206c9e79e265fddbcdf12d1af4e5d913 -dist/2025-09-21/rust-std-beta-aarch64-apple-darwin.tar.xz=7ddd43d1e32a829ffa9a7a798e1339d0569e773d841d8b7ad33701664373b8ae -dist/2025-09-21/rust-std-beta-aarch64-apple-ios.tar.gz=bf3df6d2eb7e5515ae86bb970b5c145140f8e9d503e636fcfc435d47797b650a -dist/2025-09-21/rust-std-beta-aarch64-apple-ios.tar.xz=fbb88375a8c0c5e41d35e4838ecbd31e4ad1b96e22eb689ae37dd50322545d39 -dist/2025-09-21/rust-std-beta-aarch64-apple-ios-macabi.tar.gz=26e9fb3607dfeab90500bac3e9eaa23170f7f22a4738ae6b58e2e89e0c87f72a -dist/2025-09-21/rust-std-beta-aarch64-apple-ios-macabi.tar.xz=6c9622771203bf342d59673bb1f53fe715b4255f0860feb6b19be57de2ef9f92 -dist/2025-09-21/rust-std-beta-aarch64-apple-ios-sim.tar.gz=a9c15e05b58adede5d08d7628de75d47d5c38ca60fad87dca8b8c9801050ee1a -dist/2025-09-21/rust-std-beta-aarch64-apple-ios-sim.tar.xz=bd847e7952c02312e36900766a71a5284c221b177ddef0b9cb071c5f6186a70b -dist/2025-09-21/rust-std-beta-aarch64-linux-android.tar.gz=2dbfa47893553b2868c375bedda6c4e08c33bbfa9cc96ff6e89ccf0525f8b14b -dist/2025-09-21/rust-std-beta-aarch64-linux-android.tar.xz=6b83da57cd768bad91a820d698bd18ae60586b0920950ea14105d6f23b4b1db8 -dist/2025-09-21/rust-std-beta-aarch64-pc-windows-gnullvm.tar.gz=a71a57f26812c2e1529c10e2e02b8d9b466564065a8a10ceb69f22cb76e83814 -dist/2025-09-21/rust-std-beta-aarch64-pc-windows-gnullvm.tar.xz=29f8789707c545e45680acd30a329fa28613dd247ce7c91d65b13a10c0c21202 -dist/2025-09-21/rust-std-beta-aarch64-pc-windows-msvc.tar.gz=07067546648ac6e784f9d5f6455534b62b9eb5cd86805c327b98505a0caeb2d8 -dist/2025-09-21/rust-std-beta-aarch64-pc-windows-msvc.tar.xz=f224f6b979ceef56ef8a10eaf063a6ea072d405a52ef123b720d44925b530d36 -dist/2025-09-21/rust-std-beta-aarch64-unknown-fuchsia.tar.gz=756534ef3e62c80481e4886348bc80632ca68ec9c49045d71838dc7ef0751373 -dist/2025-09-21/rust-std-beta-aarch64-unknown-fuchsia.tar.xz=c6eee692a79106d7733c1cbc525b241b6d88a53ee08242e494d286eb0ad3024a -dist/2025-09-21/rust-std-beta-aarch64-unknown-linux-gnu.tar.gz=4843b5a6d3e8b89a54ab91e44768bb023178c8cc7cd745639d9a616f2331d9a2 -dist/2025-09-21/rust-std-beta-aarch64-unknown-linux-gnu.tar.xz=89a808aade0a91043bef23f3e3f38d193b4f02b6556f01cbaf103c43ce428478 -dist/2025-09-21/rust-std-beta-aarch64-unknown-linux-musl.tar.gz=6c09b424925e89957fb1921887b7034c3d3adf012571415b9930e1d0119bed41 -dist/2025-09-21/rust-std-beta-aarch64-unknown-linux-musl.tar.xz=3c34d71b74adb145302772db2a5c565235576a14c42eca0a270b0e9e67ac9032 -dist/2025-09-21/rust-std-beta-aarch64-unknown-linux-ohos.tar.gz=70225984fa7ad361126efd9cbd40fe9dcf4756866b23079e4dbde5ec51f3a10d -dist/2025-09-21/rust-std-beta-aarch64-unknown-linux-ohos.tar.xz=e696cf9ac5b4b0e16e3947377424515c761697541351d0924b61a37557394828 -dist/2025-09-21/rust-std-beta-aarch64-unknown-none.tar.gz=7b754105300a911c24f7483b7eb482d076f5f98e16f685215d06df3dab1fdcba -dist/2025-09-21/rust-std-beta-aarch64-unknown-none.tar.xz=8168916ec457eaeb32ad1d274ce67666d6ff8fdf662f32bc6e17656ef4ff7c81 -dist/2025-09-21/rust-std-beta-aarch64-unknown-none-softfloat.tar.gz=1ff511547185b42b801ce51f84985767d580c08f183b15033e8ae05274b7f90c -dist/2025-09-21/rust-std-beta-aarch64-unknown-none-softfloat.tar.xz=263e10d4226c5328cb41299466b82e154fa1c94c67fc3a185a0bb9a6639bebad -dist/2025-09-21/rust-std-beta-aarch64-unknown-uefi.tar.gz=eb3710b6ccbde9a265217a4e64f2c62bb22bcc79dd58a48381cc81c5e95073d4 -dist/2025-09-21/rust-std-beta-aarch64-unknown-uefi.tar.xz=b1c231790f55fd9a3dfcb9e6c946f34afb3bf96c57bb9d8615894d81aed44f95 -dist/2025-09-21/rust-std-beta-arm-linux-androideabi.tar.gz=0d12ed3a2980fce0d71d728d6c2840eac36a3e3ae93f2dfc3cb391d56c20cbf1 -dist/2025-09-21/rust-std-beta-arm-linux-androideabi.tar.xz=2219966a5e884a94c324b74872a2a4a12378d595cae10b53958190acc05ccd45 -dist/2025-09-21/rust-std-beta-arm-unknown-linux-gnueabi.tar.gz=286c12975e333cdf9c7ad0b21217e3b83682047c37c1dba766cff4a201bab40b -dist/2025-09-21/rust-std-beta-arm-unknown-linux-gnueabi.tar.xz=9e56db5ac01ae18077551117348fe56050426f521e41f217ac3d71c23eff4d88 -dist/2025-09-21/rust-std-beta-arm-unknown-linux-gnueabihf.tar.gz=f52e699638e352d9f816a21965a5696acc5fd77325ff074f93c27587292bca19 -dist/2025-09-21/rust-std-beta-arm-unknown-linux-gnueabihf.tar.xz=d0a4abaa489bfc6f2f7d2305e8edbd502b12f247357ba4cda541786377648108 -dist/2025-09-21/rust-std-beta-arm-unknown-linux-musleabi.tar.gz=7ee043969e94b14ea74e083fd3edb9e0639d68c2bdd7ebdb188e98b36c854fcb -dist/2025-09-21/rust-std-beta-arm-unknown-linux-musleabi.tar.xz=8ce6bafaae0e8217bdb138d104955ce7f0a747ef915aebb181cf3047beb4456f -dist/2025-09-21/rust-std-beta-arm-unknown-linux-musleabihf.tar.gz=8e5c901df3f932bac7dad635bc1197ffbee4884c0a101632d51a32f23c875cdb -dist/2025-09-21/rust-std-beta-arm-unknown-linux-musleabihf.tar.xz=166a1d949b6847e9bf102a89f9a417a30d8ac25a35fe3f732d6a513a7674af85 -dist/2025-09-21/rust-std-beta-arm64ec-pc-windows-msvc.tar.gz=8660de6d0d97fdffe3bbcfd5ffc7e11bbfe9c43f80067ba17845414958778845 -dist/2025-09-21/rust-std-beta-arm64ec-pc-windows-msvc.tar.xz=8b563eb032535c58c487d4ad992a12a106208861e45ea78c342e940b9356ebf1 -dist/2025-09-21/rust-std-beta-armebv7r-none-eabi.tar.gz=cd761b3f761198cc6ac64809eaa28ac299b67ba48d964298db3f5b4ea52f3623 -dist/2025-09-21/rust-std-beta-armebv7r-none-eabi.tar.xz=071864464c52c37bd102fad26b5d28f31aa9e06d34ee868a33ead297c3e20a4d -dist/2025-09-21/rust-std-beta-armebv7r-none-eabihf.tar.gz=402c044cdaad16d2b60365b6894250aa43424902c0b3f0526e849d7d0d452315 -dist/2025-09-21/rust-std-beta-armebv7r-none-eabihf.tar.xz=0028e17d0164bbb8166ddaad815874123fcc326dffef4740389ff2cb069a3e2b -dist/2025-09-21/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.gz=0b9be6bfa168756361aa5feb7802133c4cbebd3fd20d75d32a4385b716417a9f -dist/2025-09-21/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.xz=1893fcd9b16f0c334257cbc78dc416cc048d7c1603ba632ed7300bbf6c0bffb0 -dist/2025-09-21/rust-std-beta-armv5te-unknown-linux-musleabi.tar.gz=5aa03609f57d6c959673963b633adf194ea240b3604ba6635a6ef5fbe5c519d3 -dist/2025-09-21/rust-std-beta-armv5te-unknown-linux-musleabi.tar.xz=8f075eb3b1ed0bdfde8af08ee69778af2d2e896d1cdf17035657d1a84c85e856 -dist/2025-09-21/rust-std-beta-armv7-linux-androideabi.tar.gz=1499f0b4c3a4838dbd7b0df7303fbe7e157dfaec396b5ee1a6ae6a727ea3122a -dist/2025-09-21/rust-std-beta-armv7-linux-androideabi.tar.xz=f0ad36dd56abf6c03395bfc246209bce90aba1887dee81a2841f7e1013f93850 -dist/2025-09-21/rust-std-beta-armv7-unknown-linux-gnueabi.tar.gz=4a430fa04ef3d23dcf1d5e1f69c37127a5fb58e883ac52c8885125e0f578cde9 -dist/2025-09-21/rust-std-beta-armv7-unknown-linux-gnueabi.tar.xz=6fab12ecab36252aa1a4f6aa523ae1546f534548394e2585e96a869b87656806 -dist/2025-09-21/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.gz=4081b51910cb95fbacafc9518ee5891e1131af79a8348635c13765706c18c3ea -dist/2025-09-21/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.xz=ed9a56e0e8b4e0f639afd9c6c75c4adfeddc7ce0aaa9132591f774754f412b6e -dist/2025-09-21/rust-std-beta-armv7-unknown-linux-musleabi.tar.gz=571a08bf8eaa522017b0aa67fb78b344590fde57ab3425575c01ceb3b258c557 -dist/2025-09-21/rust-std-beta-armv7-unknown-linux-musleabi.tar.xz=e50728c440ae8fc9d154a3893914126d4486ca7dd197891b78531f7d5d081211 -dist/2025-09-21/rust-std-beta-armv7-unknown-linux-musleabihf.tar.gz=1f8570de307fbc59e962ef6b419009d57fb05b2e1d5fc9ade9d425e3c9977cfe -dist/2025-09-21/rust-std-beta-armv7-unknown-linux-musleabihf.tar.xz=35db980cea1ba70003374a738f20af63d54796e9181b8cf0e9d0626e0935a9a2 -dist/2025-09-21/rust-std-beta-armv7-unknown-linux-ohos.tar.gz=ba5a8487dbb60851fc927dc24ee58186aa6e74d42dbf5202df7981a456b5f8f7 -dist/2025-09-21/rust-std-beta-armv7-unknown-linux-ohos.tar.xz=f763ae3e33f4785ff505eb068ed6515aff8ffcdb9895595d23c2cea519e26355 -dist/2025-09-21/rust-std-beta-armv7a-none-eabi.tar.gz=3cd90f1a7c14a732a951026458a976fd5e833f212c6f6433f8de348b7b742b9c -dist/2025-09-21/rust-std-beta-armv7a-none-eabi.tar.xz=237f44f2b9984743f71ef0cab8d693092748fd2da25cabd3468e3e45ca20e2bc -dist/2025-09-21/rust-std-beta-armv7r-none-eabi.tar.gz=ec38043fd7877d45331414d059d0198d055ab724e84c077ca75a2902afbb2d6b -dist/2025-09-21/rust-std-beta-armv7r-none-eabi.tar.xz=f511909286f3e1cb52f0e698722bec1a3cfb750e19bb2fa781bfff225620ca8c -dist/2025-09-21/rust-std-beta-armv7r-none-eabihf.tar.gz=556365cb3ed473222e1b135be77086214f3f94f863817de4a87ee7d75456b824 -dist/2025-09-21/rust-std-beta-armv7r-none-eabihf.tar.xz=8483d2550782e253cdace51fe24249fbd6bd0b10a850c75e62dc60f803be17b0 -dist/2025-09-21/rust-std-beta-i586-unknown-linux-gnu.tar.gz=0ed5faa9e8e73f4e7b9e75741d000954558bafeaf776a6e61a4e44ac120b91e9 -dist/2025-09-21/rust-std-beta-i586-unknown-linux-gnu.tar.xz=665d5a0debd829f3682572e4c3578d41bec58b01df10cc8c71ca66d326a3579f -dist/2025-09-21/rust-std-beta-i586-unknown-linux-musl.tar.gz=c59dcbce2435a5826161d4319dcf84e128f9fa4c0bf075fab2a26c2bfb5d9887 -dist/2025-09-21/rust-std-beta-i586-unknown-linux-musl.tar.xz=13a2292936e289941be4a02903051eadb076bb44368494d530cf66832978f46f -dist/2025-09-21/rust-std-beta-i686-linux-android.tar.gz=5d23e660218e04a7dc4aaf940959619ec9aa14bf5574a554c0d8f377910ed017 -dist/2025-09-21/rust-std-beta-i686-linux-android.tar.xz=cffd08cc85df3cc661d8a572e940316da06754b61893efcd9ad3b7db09a0e6ee -dist/2025-09-21/rust-std-beta-i686-pc-windows-gnu.tar.gz=91743434207475f4404707cf7a203b46f032a041184a729ddcaeca280b2fac05 -dist/2025-09-21/rust-std-beta-i686-pc-windows-gnu.tar.xz=1f0240a71bf5a3bd74e1ae960c1aae440c3b3e32e6c62835287f78cc777f0d7f -dist/2025-09-21/rust-std-beta-i686-pc-windows-gnullvm.tar.gz=ec5907cfb6faafcc20f3d7cdb22fd7836c9c2d7cb4871c48e64732bb7f5dcba5 -dist/2025-09-21/rust-std-beta-i686-pc-windows-gnullvm.tar.xz=e7e8453b9dafc3c8c222455f5327fc8cde127f8dc877991688afd3c2f23675f5 -dist/2025-09-21/rust-std-beta-i686-pc-windows-msvc.tar.gz=50dd40b16e8ea85fd7ca67583d5cae80910d36531a7babe13a94cb638015a1d3 -dist/2025-09-21/rust-std-beta-i686-pc-windows-msvc.tar.xz=dafeb013333acc8a3a4181358584851b47c5f21138d8164ccfd6863b171309ba -dist/2025-09-21/rust-std-beta-i686-unknown-freebsd.tar.gz=91d741bfd158f22f4dea8bf768c5fb60ca05f5dc64cd5a848428b8dfe8beccbf -dist/2025-09-21/rust-std-beta-i686-unknown-freebsd.tar.xz=12ddbbb201a973148979a99ccbac3c65690010dd2f6984fa390fe5e63a28dbda -dist/2025-09-21/rust-std-beta-i686-unknown-linux-gnu.tar.gz=975e30f37f03afb47777a38edcd535df6729311cc0acb587d417ebff694df796 -dist/2025-09-21/rust-std-beta-i686-unknown-linux-gnu.tar.xz=bc95dd6129e90c9275e0340962993de7a0842040bdfcde9aa419f227d79dbf31 -dist/2025-09-21/rust-std-beta-i686-unknown-linux-musl.tar.gz=1c937cce8b40567851578790512fe079c0aa828374a3bb76423d685357388576 -dist/2025-09-21/rust-std-beta-i686-unknown-linux-musl.tar.xz=b42d227d63f0b3352d4d66f1198294c2f4df574c48fff794ac3483cef869c2bf -dist/2025-09-21/rust-std-beta-i686-unknown-uefi.tar.gz=0e8c239ce3b8701c4a26b46aca9a700083667ffc3228d796ba0ba6d0728c6826 -dist/2025-09-21/rust-std-beta-i686-unknown-uefi.tar.xz=54cba2405dfa2a23164bb8e7de5e0d6a6a6523f36b0763f077d2bfec1f303576 -dist/2025-09-21/rust-std-beta-loongarch64-unknown-linux-gnu.tar.gz=72db70ab9289bce8ace5da246432d2a00552b4cd9ebef7930b563e04d1cdebf1 -dist/2025-09-21/rust-std-beta-loongarch64-unknown-linux-gnu.tar.xz=5b578548a62dfd3902920719acd17550f45d0e9106049cbdc1f36c8907a8291f -dist/2025-09-21/rust-std-beta-loongarch64-unknown-linux-musl.tar.gz=993fdc6d1894f823b3782fe180ac40a3ad7baba110f2eff68d9e38e8f79a95a4 -dist/2025-09-21/rust-std-beta-loongarch64-unknown-linux-musl.tar.xz=b5161bd0064bfb312cf156ec4689a3f5922c7df24468660e1046798c8984938c -dist/2025-09-21/rust-std-beta-loongarch64-unknown-none.tar.gz=670ef40754ac30a2edb65384de65f028a4f8e96dca49fd0bb5eb2d9d6020e906 -dist/2025-09-21/rust-std-beta-loongarch64-unknown-none.tar.xz=b9aa6311d6a3e428f151fc6720147ea8759092545b05cad3f16b6e563d523813 -dist/2025-09-21/rust-std-beta-loongarch64-unknown-none-softfloat.tar.gz=5c4c2e6bdc6d3c79578a3fd581064ba6aeb21fd9311a39a62bf58b36e7ea00cc -dist/2025-09-21/rust-std-beta-loongarch64-unknown-none-softfloat.tar.xz=8e272682e98ff8b139da621d7273cf71efa407538ea176d873a1ea7e22246ebd -dist/2025-09-21/rust-std-beta-nvptx64-nvidia-cuda.tar.gz=0781275b356176417c21c1bd1a4068fe2a42dc6de9b34695c937d5ba94b98ad6 -dist/2025-09-21/rust-std-beta-nvptx64-nvidia-cuda.tar.xz=8747e3e686fbf41389a8ad958596577670f0626a610d380b0a775e704bc6c6be -dist/2025-09-21/rust-std-beta-powerpc-unknown-linux-gnu.tar.gz=95e8443355571edf645d75d31a33277f0d6f7161f8592ec213a407bc4839819c -dist/2025-09-21/rust-std-beta-powerpc-unknown-linux-gnu.tar.xz=4abcda8b23d17f6e6681329b54215f37cca5fc1f3383e58dd60c38220f5528de -dist/2025-09-21/rust-std-beta-powerpc64-unknown-linux-gnu.tar.gz=a24d3b7db647c114c95f7da40ca2001085d935ebffcc17e269af5be636ec1f2a -dist/2025-09-21/rust-std-beta-powerpc64-unknown-linux-gnu.tar.xz=7579f587df01fb55211e6a0a61ed96f14955b7f56990e679715157b06b49fe79 -dist/2025-09-21/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.gz=ea071da90747334a786f1e4784e39c11058d7f7719e498a8b6ae29672a999abb -dist/2025-09-21/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.xz=d612ed01011c1e7f24b08318029523f6b7ffb12ec38b1f41ebcedf463f924430 -dist/2025-09-21/rust-std-beta-powerpc64le-unknown-linux-musl.tar.gz=722b93d6c5e1f9a326461bb920fafef62cc8257ff67732c3f65ecc540782a504 -dist/2025-09-21/rust-std-beta-powerpc64le-unknown-linux-musl.tar.xz=5b5010f550b317facbd599fa363d633e0540836145717f35ffa0bff14ec80558 -dist/2025-09-21/rust-std-beta-riscv32i-unknown-none-elf.tar.gz=7dea77dc10830754d5aa9a6e5ae3272e4955cab8df1e20f0784901ca6a60c49d -dist/2025-09-21/rust-std-beta-riscv32i-unknown-none-elf.tar.xz=f212b4afaaa954809af920d3fb3de76a611d387910e6162b902fad8f38f36c49 -dist/2025-09-21/rust-std-beta-riscv32im-unknown-none-elf.tar.gz=3f81a7134f44a87b7724a510e4cd4209ab52fb03fee3dc051c26bc0612e4b1af -dist/2025-09-21/rust-std-beta-riscv32im-unknown-none-elf.tar.xz=cd9db852c6f7e454e94161379c032e3ccabfcdaeddd74e8f612870ef39eb230f -dist/2025-09-21/rust-std-beta-riscv32imac-unknown-none-elf.tar.gz=6da7d7c9cdc05fc3b86930d98fe9828ecef02b5b3cead51252fe9f131ab5f9e2 -dist/2025-09-21/rust-std-beta-riscv32imac-unknown-none-elf.tar.xz=97ad71f7f63f2c3b01ba822164df457d88331880bd21837a18354fffd1b38918 -dist/2025-09-21/rust-std-beta-riscv32imafc-unknown-none-elf.tar.gz=9a5d94e1a77159a4bbf4fe7490019fff763daeb24dc2b8c732442275619f9ffd -dist/2025-09-21/rust-std-beta-riscv32imafc-unknown-none-elf.tar.xz=dc5826fef922a6987650b491957b17693c49d1ab26b618efacbb1bb0b5a9b1bc -dist/2025-09-21/rust-std-beta-riscv32imc-unknown-none-elf.tar.gz=1b9c1cc0648fc86fdaaf23e6793fa826f3639bab9d42e1bbe2c70f19cecc11a8 -dist/2025-09-21/rust-std-beta-riscv32imc-unknown-none-elf.tar.xz=90cb9c376894a122f3872a77a653e3decf95f1eef54ba7980846165e6f34377f -dist/2025-09-21/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.gz=22069b14b3eab5f3bd24a0f10185a5484022ac60fb7b2b5cb0019281bee79a4d -dist/2025-09-21/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.xz=395f2975bc86a63736ba7661985db038efa5f5982459add18201c97e4b1a9200 -dist/2025-09-21/rust-std-beta-riscv64gc-unknown-linux-musl.tar.gz=7932c8dbc9727a85dbf2ad28066cef1da46cf0ced358aea0e78a254fc1e423f9 -dist/2025-09-21/rust-std-beta-riscv64gc-unknown-linux-musl.tar.xz=69b8ce57a0c459ca57353cd8302deba6791a19dcf54e16b8d07f76b44e3c65fa -dist/2025-09-21/rust-std-beta-riscv64gc-unknown-none-elf.tar.gz=27717f0b8b51f90c7e1579a2e3fa781f2a19064872133a951e60200c05db1df8 -dist/2025-09-21/rust-std-beta-riscv64gc-unknown-none-elf.tar.xz=d6cccdb4ca0856ce1d314c03779c082ee0dff153aa6bf9ea050ca3d0a395dc1c -dist/2025-09-21/rust-std-beta-riscv64imac-unknown-none-elf.tar.gz=9fd58b7c529d530e8b894a24e7f3a33d291d7305357c7cf52bbe708cde28c381 -dist/2025-09-21/rust-std-beta-riscv64imac-unknown-none-elf.tar.xz=f62de7e74f558a27bc2ef04897ad2f4fdfc162a17f21fde8efb2ba15435d80f2 -dist/2025-09-21/rust-std-beta-s390x-unknown-linux-gnu.tar.gz=3e97b06bc72aa51aafd2d2f65b4c4d9ab08599c2616729b79dbd9c51886ab6f4 -dist/2025-09-21/rust-std-beta-s390x-unknown-linux-gnu.tar.xz=8f149e17d654de210a71ace9db03f23bd1a80d0e2c17f8336da2b1ec2315c8a0 -dist/2025-09-21/rust-std-beta-sparc64-unknown-linux-gnu.tar.gz=ae6f3a738f1793fb9659e7613811b2ac151e91e3d8e470166b6ae615e5a285b2 -dist/2025-09-21/rust-std-beta-sparc64-unknown-linux-gnu.tar.xz=92af1bc3beaf80a763aac682a15957d82771fc619d446fb4327f4e8be229438d -dist/2025-09-21/rust-std-beta-sparcv9-sun-solaris.tar.gz=b1f5ef77e28e9ed25050b130299a1c431a851df8b11bd457393fd464a7a9c35a -dist/2025-09-21/rust-std-beta-sparcv9-sun-solaris.tar.xz=e5d744447649c57f8238c7d020f405559185d644b9739cae53c6963cdb380ea1 -dist/2025-09-21/rust-std-beta-thumbv6m-none-eabi.tar.gz=964c824519d8f352ea049766c428e6409549f7a4921c50f91dc548f2ec7f65f0 -dist/2025-09-21/rust-std-beta-thumbv6m-none-eabi.tar.xz=2f3b6d4781b21902e5f6986b75f3a0617198bad4741d4a9b957ab5ae2beab05d -dist/2025-09-21/rust-std-beta-thumbv7em-none-eabi.tar.gz=7a95faa851ac8dff7f57cfa42169018b29683fbe06dbcf29e2cb311a0c880e84 -dist/2025-09-21/rust-std-beta-thumbv7em-none-eabi.tar.xz=deb1eafb4cdad0391bad8dd0657577d4c0960fb7fad7b7552ef1e662c4c1f12a -dist/2025-09-21/rust-std-beta-thumbv7em-none-eabihf.tar.gz=1b35c7e25986065e63dfe8e8a1824bf13b62daa5777f32b140f03d0f4fe5cd1e -dist/2025-09-21/rust-std-beta-thumbv7em-none-eabihf.tar.xz=335b28756025f8454ae7c6ef6760a512f0b59385cdeacc7dca0ea1bfe5e9a703 -dist/2025-09-21/rust-std-beta-thumbv7m-none-eabi.tar.gz=2291b4c7f27fa0408f394c48390cfd6c7144db5cc4e51c8891c3bb24300b8421 -dist/2025-09-21/rust-std-beta-thumbv7m-none-eabi.tar.xz=16b6104ae79bc0f3fa6d862c72cb3f35a9f67bbea7f9aee7b2a3b0c810225c6b -dist/2025-09-21/rust-std-beta-thumbv7neon-linux-androideabi.tar.gz=6a7f167dd4c457d6185ee47dc206d19d6ca93e3e0418b21c0745d84c53995e64 -dist/2025-09-21/rust-std-beta-thumbv7neon-linux-androideabi.tar.xz=4fb366719cdadec26e88d64154b2b1b459affe5b894b426a0509681d173cf823 -dist/2025-09-21/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.gz=3ff578be0c8b1171c5c2d0aaa3f4fc20f3a252f5adf050bd5856b201cc22841f -dist/2025-09-21/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.xz=16c518c3daf87722a5e2556e92e97d429a06b2ed2c79380989db04ffa4791279 -dist/2025-09-21/rust-std-beta-thumbv8m.base-none-eabi.tar.gz=b1d67e62ac198fcff25c29e731f2dca9eba3fbb09adb29db68d823b0ad63e85b -dist/2025-09-21/rust-std-beta-thumbv8m.base-none-eabi.tar.xz=ac586b0a3cd91eb2928861ded895b96a85880851df2f3e63c2391cb38d98d140 -dist/2025-09-21/rust-std-beta-thumbv8m.main-none-eabi.tar.gz=93cfb0ceb07879366ecb4e00caf5b4459574852943363b0d6fd3293c4a0c27eb -dist/2025-09-21/rust-std-beta-thumbv8m.main-none-eabi.tar.xz=879724fc40ca55193760b3739387dc237587e91c30e334709d5453e07840d4d0 -dist/2025-09-21/rust-std-beta-thumbv8m.main-none-eabihf.tar.gz=7eb1217837173f0974f7a0fc69b0e9fea484f2d457f3b193ca3b2c04ed83bcd9 -dist/2025-09-21/rust-std-beta-thumbv8m.main-none-eabihf.tar.xz=c38af1e6560589be7a0733508b800e68bb5b57f2ec3c5452fb14000cf9ef2fa0 -dist/2025-09-21/rust-std-beta-wasm32-unknown-emscripten.tar.gz=9475cb292c64491c545a02df4deae77d4174d77db18a84c8db635ae6de691b8e -dist/2025-09-21/rust-std-beta-wasm32-unknown-emscripten.tar.xz=6e477e9ea0e5bac0b567deacfba3c236ceda28fab4d63c011d6bc54ac22c8570 -dist/2025-09-21/rust-std-beta-wasm32-unknown-unknown.tar.gz=eb7bf16e819eabe3f685bb8dd09bfff31d35d87cf03535195c411ec1738b6647 -dist/2025-09-21/rust-std-beta-wasm32-unknown-unknown.tar.xz=05a2bc1539b02ef314b268fc2860836c111705b872d5d56ba6ea511cb47e7169 -dist/2025-09-21/rust-std-beta-wasm32-wasip1.tar.gz=aa34f89676c72a3ce5df82cd819466631ed91896dd7a1b64fb4ca9a97595e254 -dist/2025-09-21/rust-std-beta-wasm32-wasip1.tar.xz=ad5756f4ce3e0309d04746609abdee2152fae66383b2b13d338c900b8f787060 -dist/2025-09-21/rust-std-beta-wasm32-wasip1-threads.tar.gz=36c42b952305d381718c36f34c4d5c1705aec71f946eee56c685eae56f9c40d1 -dist/2025-09-21/rust-std-beta-wasm32-wasip1-threads.tar.xz=c0285e26be272e3e832a74f22960899ac0f350dc6764701df748541ddbf69377 -dist/2025-09-21/rust-std-beta-wasm32-wasip2.tar.gz=198d4cb5195fa1e992cec8bf84716eed1ade0e9a8cc3981f3fb3cb9971e2796d -dist/2025-09-21/rust-std-beta-wasm32-wasip2.tar.xz=0fd2cd8923741931aa17d1571a5f8c20c9b0e96d74dc75ab47cd9245586bfa03 -dist/2025-09-21/rust-std-beta-wasm32v1-none.tar.gz=cef69dbdfbd0352bf781c1e59129c29c17a6c1367aa00184be309c56f8f29dfe -dist/2025-09-21/rust-std-beta-wasm32v1-none.tar.xz=a412840ff9550e447a2608a9c26ec02e969b2579bfe5c635a3af0cccd011922f -dist/2025-09-21/rust-std-beta-x86_64-apple-darwin.tar.gz=290fefcf45ff24a79459c44523bfbbeeaf9eb9bf3e7e64fcab64368fe21ed2d7 -dist/2025-09-21/rust-std-beta-x86_64-apple-darwin.tar.xz=176634d6797df21873c317b93cecfc32f415b3248139a32bfdbee83607e734c1 -dist/2025-09-21/rust-std-beta-x86_64-apple-ios.tar.gz=639916204bcc229bd5d5fd1ccb455d9a962a11d05388252c1e5e310d424f1ef6 -dist/2025-09-21/rust-std-beta-x86_64-apple-ios.tar.xz=c0c597f428fdc8f2f89e26c0e5d9debef45ec449b869ea0a738102a8727e8da4 -dist/2025-09-21/rust-std-beta-x86_64-apple-ios-macabi.tar.gz=debfb6dfe448e345cc934e5a0d09715ca899ed9593c26eab07c58c41683113f4 -dist/2025-09-21/rust-std-beta-x86_64-apple-ios-macabi.tar.xz=a9b6b2de9e26182f5a37a8ff56487916379809b2afe9e14d34ee55f98d526267 -dist/2025-09-21/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.gz=2517ded939281e8722e5ca6d2cdff6a78a4fa39b5828a3048d9f25a3ec40bbea -dist/2025-09-21/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.xz=7e8efa9cb373f580c46fa348b1f76acb46456c71fb6afea2b22d5a16b90ce28a -dist/2025-09-21/rust-std-beta-x86_64-linux-android.tar.gz=2bb9470fe62c5c1e1d31f63544b2bedb833c07c5305448e46283b48d8a575d65 -dist/2025-09-21/rust-std-beta-x86_64-linux-android.tar.xz=66a024fd9bda49ff4db5d70a2dc094708ef73c027ad0aa7dcbd7cea8449b151f -dist/2025-09-21/rust-std-beta-x86_64-pc-solaris.tar.gz=104b17a08a01593195921a56153a2b54782640f9dbf9e59c7da9f29afe3fe4aa -dist/2025-09-21/rust-std-beta-x86_64-pc-solaris.tar.xz=c3950a3a8bdd1326ab7d0ac08dc2a4f5c354e9ef6447324145cbe9fdef54f026 -dist/2025-09-21/rust-std-beta-x86_64-pc-windows-gnu.tar.gz=d1d998991c9c8107f919c851d327d730beb6d4f4937a9f8dd2de2fbade1c1dd6 -dist/2025-09-21/rust-std-beta-x86_64-pc-windows-gnu.tar.xz=654322ad813f9414e7ba2c5c5cb141db234d73b9ad237595d844dad564917a98 -dist/2025-09-21/rust-std-beta-x86_64-pc-windows-gnullvm.tar.gz=6b9323f0bc1055dbf3e5fb4ec5fa09f28b7a0cd04ee8bb40e727d85d1a5225b5 -dist/2025-09-21/rust-std-beta-x86_64-pc-windows-gnullvm.tar.xz=3ea958ef88fc3334e98556fd3bcc00264d9dd75cccf6f19f6f5514ec447d0557 -dist/2025-09-21/rust-std-beta-x86_64-pc-windows-msvc.tar.gz=ddfbb760544eb8a7562cc8fab7cf313d45f490dacde3575329f627546971db0b -dist/2025-09-21/rust-std-beta-x86_64-pc-windows-msvc.tar.xz=25f8e1279fc8647e117c6f3dbf3f4059e7ddc058cf6e02b43f499a72bee6ebbe -dist/2025-09-21/rust-std-beta-x86_64-unknown-freebsd.tar.gz=2941d17a2370ecab1e839236ba092c065cfa1b94e448a77a5851dab9ec2f1a59 -dist/2025-09-21/rust-std-beta-x86_64-unknown-freebsd.tar.xz=ff2aae7c2e37e48f500df5876c3a26d3dd10affd04e888ce54a4635a5345efa6 -dist/2025-09-21/rust-std-beta-x86_64-unknown-fuchsia.tar.gz=1cdbbbdf1aa9c6e764493576adbd962e004ff029b064089be35910768f409579 -dist/2025-09-21/rust-std-beta-x86_64-unknown-fuchsia.tar.xz=8196d32e28630a3ccc1dc96d9abb3efb5f2090b7bdce9963b2579995f575435c -dist/2025-09-21/rust-std-beta-x86_64-unknown-illumos.tar.gz=bbe4419e2d9f5bee75f6c1f7b0cf272100e3a37aebc28bc626820c886fabec47 -dist/2025-09-21/rust-std-beta-x86_64-unknown-illumos.tar.xz=2fc8f8ccd022152a87a447079169340218d7541b3513eed36cf7af20d5f565ce -dist/2025-09-21/rust-std-beta-x86_64-unknown-linux-gnu.tar.gz=222198fa6b782010beac1710693ee1aeac1ad7eb9ac183625128de788a1a4bfd -dist/2025-09-21/rust-std-beta-x86_64-unknown-linux-gnu.tar.xz=b60da22feb82c21128a151013c690cdef1c291de33e1b6ada5dcc95d3bff3899 -dist/2025-09-21/rust-std-beta-x86_64-unknown-linux-gnux32.tar.gz=31ab3940e428fe58ac584c33072be16d31edb0c16df379d9847cb904947126cc -dist/2025-09-21/rust-std-beta-x86_64-unknown-linux-gnux32.tar.xz=8304e2e4440e0a91b05bfe58bd44e7087c28c2682a1a5f5b659e2aba708463fb -dist/2025-09-21/rust-std-beta-x86_64-unknown-linux-musl.tar.gz=c15ecaa46a814cfd5fa27b29aed9e0e578a652b8f6392b916341d30172da7ede -dist/2025-09-21/rust-std-beta-x86_64-unknown-linux-musl.tar.xz=08a84716ed6bc70a58841c5d61216a781b8a947bbb5fb5ebde757e537a2e5dd3 -dist/2025-09-21/rust-std-beta-x86_64-unknown-linux-ohos.tar.gz=5f1a8ed2093099b18cc83eddb304234f201f8ab137ae950c73329156570ba975 -dist/2025-09-21/rust-std-beta-x86_64-unknown-linux-ohos.tar.xz=ebcd581394fd243eac3d683e334d73ef3d3bbaf7de28bd4082329683e2c770c1 -dist/2025-09-21/rust-std-beta-x86_64-unknown-netbsd.tar.gz=430f4b7f7eceb5e633bccafa9acf08095c1aa4b3dfaa94734fcd331b3d69ca44 -dist/2025-09-21/rust-std-beta-x86_64-unknown-netbsd.tar.xz=2e403587de5c02ba9c5f9f2515d4c9fdffde59cec28c8dcafdfe40d03e4f3152 -dist/2025-09-21/rust-std-beta-x86_64-unknown-none.tar.gz=84d695e6f19706fdd7c01dbfc4607f310e8495f57c29bad2476e00c7bb269646 -dist/2025-09-21/rust-std-beta-x86_64-unknown-none.tar.xz=6e12698afd8a6743a9a6a011ad67ab16d5a40b6dbf1d09104b8294ea95fc2636 -dist/2025-09-21/rust-std-beta-x86_64-unknown-redox.tar.gz=cadafa58684734fc43417742d9151aea36b62f82aa3cd7b858140ce31e9a6ce6 -dist/2025-09-21/rust-std-beta-x86_64-unknown-redox.tar.xz=f1089cab004cb67134bbac6d8acb09b4dd5e02010e069790e13970b004ca4ab5 -dist/2025-09-21/rust-std-beta-x86_64-unknown-uefi.tar.gz=2dbc6eec98b7d730fe2ba982d78f7331346e9018146597200340256d28c0aaf2 -dist/2025-09-21/rust-std-beta-x86_64-unknown-uefi.tar.xz=8a5896f3301a6238984114cf52f7f234bdcb712cb6d914093159ecc82904ba7e -dist/2025-09-21/cargo-beta-aarch64-apple-darwin.tar.gz=4c6172e8523576deaa6c83274dbd993338d545a794e42aca3c074450d7e7cea0 -dist/2025-09-21/cargo-beta-aarch64-apple-darwin.tar.xz=5e8978daaaed1304e94c071ab5414ce90eb9c7bd1c4f1c8c5f4ff515f6558851 -dist/2025-09-21/cargo-beta-aarch64-pc-windows-gnullvm.tar.gz=49cba73291916ddf2e4912d4ea02add165f2786ad7f7b8885628d92579cbebd8 -dist/2025-09-21/cargo-beta-aarch64-pc-windows-gnullvm.tar.xz=d60a0a176b7d15606f6ee31b67d4a5ac6735e5a0b012022e9212fe723bddec48 -dist/2025-09-21/cargo-beta-aarch64-pc-windows-msvc.tar.gz=dfd4aa83d38a6236789676ef02c81382f0741671ed9a973cd74d37c65b3f111a -dist/2025-09-21/cargo-beta-aarch64-pc-windows-msvc.tar.xz=8ab6cd565993b58c6e2169bfb468c441dd385c5336081c45f6a60608522ce549 -dist/2025-09-21/cargo-beta-aarch64-unknown-linux-gnu.tar.gz=eb361e2d12c90c9380112ef48b81db1b41f04b4ae08cd061fe1caa46cca9ce6b -dist/2025-09-21/cargo-beta-aarch64-unknown-linux-gnu.tar.xz=e9f4c66995b8e955e86a67c44fd8d7f6e7349645393bfa605c6c1bb0afc7b930 -dist/2025-09-21/cargo-beta-aarch64-unknown-linux-musl.tar.gz=dc88806e5ac4004a9a3cb24f0c850fde2c22b0e38e6ad84bd570069043485bfc -dist/2025-09-21/cargo-beta-aarch64-unknown-linux-musl.tar.xz=e103f1d074ab105d03a88066363d2b103508ec95c18cbf8b1f92d0f473ddbf40 -dist/2025-09-21/cargo-beta-arm-unknown-linux-gnueabi.tar.gz=e35bcf36bd7578cdbccb60d554feb19f8376fd41850e4e8046e0b2f931040c01 -dist/2025-09-21/cargo-beta-arm-unknown-linux-gnueabi.tar.xz=ff1b46781284948aaf8c8f582203877ffda5a78d86c266bf724fbb08503a6e80 -dist/2025-09-21/cargo-beta-arm-unknown-linux-gnueabihf.tar.gz=dd657b5eb50264c90fafbd967b20768d9e4df14ef179902420b3f9a3e2145271 -dist/2025-09-21/cargo-beta-arm-unknown-linux-gnueabihf.tar.xz=3f821c437963aec534cdbd686f719eb86bfe41cf254ed5395730f7827d45a68a -dist/2025-09-21/cargo-beta-armv7-unknown-linux-gnueabihf.tar.gz=7874b945f3d77e2a8ca308e5400a2411ab4f615f45a036bd9fab8a74434c309d -dist/2025-09-21/cargo-beta-armv7-unknown-linux-gnueabihf.tar.xz=39523f09c76473d10b91ee946523976e01dc337d2af067f08168f1d9cb44226a -dist/2025-09-21/cargo-beta-i686-pc-windows-gnu.tar.gz=43b095acb25cf5c0dbfffc6fbc864c2b2415251931b149b282d5e70844fc2c50 -dist/2025-09-21/cargo-beta-i686-pc-windows-gnu.tar.xz=6cac1a1a6d74765f4233908920d295761570ddcd8cf3638bbc8f8eb427084b92 -dist/2025-09-21/cargo-beta-i686-pc-windows-msvc.tar.gz=7f4314596e6ea01a35b9e2e250227a74b5d4bd772ac8d33d12bd44f8c11b37e5 -dist/2025-09-21/cargo-beta-i686-pc-windows-msvc.tar.xz=eeaca23bf3cafbd01cdcef890d02ecd622d3ccfd6d9830f1e599d29acfa371bb -dist/2025-09-21/cargo-beta-i686-unknown-linux-gnu.tar.gz=e79e3a25bb790c5f6ed9e81a0559a55750a1a3e35250f0fc5fd92c195625aa28 -dist/2025-09-21/cargo-beta-i686-unknown-linux-gnu.tar.xz=1fe31a0e463736a9ae90ef11c1e3c7b7972eb82779ecdf5b6bff1f643684a014 -dist/2025-09-21/cargo-beta-loongarch64-unknown-linux-gnu.tar.gz=917db09ef343b6702c1410c2c68070c4bcfd90f6951591490a6a237290a4aed3 -dist/2025-09-21/cargo-beta-loongarch64-unknown-linux-gnu.tar.xz=222010f8428a3d165801d95a820b639ac930747af3cb4a42a25548330585f73e -dist/2025-09-21/cargo-beta-loongarch64-unknown-linux-musl.tar.gz=7e949bc169a58e450e58088fd716aac9a05f5fca0790d94dd211ce823c2c5d36 -dist/2025-09-21/cargo-beta-loongarch64-unknown-linux-musl.tar.xz=dfeb99ac76e18160aee7ff1c878b44b9fdb725f7be28609e637bd372aab448a3 -dist/2025-09-21/cargo-beta-powerpc-unknown-linux-gnu.tar.gz=523103d950944aed52578002dd372207b3bb38e4130b4b11097b03f7d55345c9 -dist/2025-09-21/cargo-beta-powerpc-unknown-linux-gnu.tar.xz=db5c4ce1a1a4d87cca4fb64a6c533cc5ab1c94e25e69b26e13808b0fa5e853e9 -dist/2025-09-21/cargo-beta-powerpc64-unknown-linux-gnu.tar.gz=68479082544f7f68a2fe073ed3d35e1895643f8ab9abe9d0e968efa9f342de36 -dist/2025-09-21/cargo-beta-powerpc64-unknown-linux-gnu.tar.xz=8878cf473faf120efb80bac0564b193f3baa14a9027fb4c060574e6fc921edcc -dist/2025-09-21/cargo-beta-powerpc64le-unknown-linux-gnu.tar.gz=eb37177cdbc9e2b7f9b74856b351bb764e5c2603366fd92a5c863cbad26e6940 -dist/2025-09-21/cargo-beta-powerpc64le-unknown-linux-gnu.tar.xz=92734c444e0156e16c8d8998a8432b24d9d01b82da15123508d0002eb008b9bb -dist/2025-09-21/cargo-beta-powerpc64le-unknown-linux-musl.tar.gz=502d5d2ec61d9fcd5b92caa0b4f0aaa11f27fccb7ec4736e05beca313f306585 -dist/2025-09-21/cargo-beta-powerpc64le-unknown-linux-musl.tar.xz=e00bc0ef1784b2f7b1fdbb757cd50342cacc49f7f5d2d3f7b36f9f4eca23882c -dist/2025-09-21/cargo-beta-riscv64gc-unknown-linux-gnu.tar.gz=3e00c4c0d64977ddd2fcece9407a01f92ec9b44ea37d72ebbdb77cf0c532163c -dist/2025-09-21/cargo-beta-riscv64gc-unknown-linux-gnu.tar.xz=3be5932af030c758a84bc09cbb1c2bc5abecc4e7d8a82de58c2a069ad36e737e -dist/2025-09-21/cargo-beta-s390x-unknown-linux-gnu.tar.gz=aefcadb257bbcf93dda58526390962316b4e579707c043c45e52bfd4d7a097dc -dist/2025-09-21/cargo-beta-s390x-unknown-linux-gnu.tar.xz=3d163f9fdc2b8b0f5cbbf846caf1dccaee07984d8783250e8988ef447e53663d -dist/2025-09-21/cargo-beta-sparcv9-sun-solaris.tar.gz=bc1692d8d75654012a823adb40b87d3b5721b19beb49a30b404a6c78f431c944 -dist/2025-09-21/cargo-beta-sparcv9-sun-solaris.tar.xz=ff7f36d7832b094b9ca2132df4851cf0ca50c9fc2de3d55bb6c75b46dd028f10 -dist/2025-09-21/cargo-beta-x86_64-apple-darwin.tar.gz=1a67e618eeadf362e868bf2cb35c1a312db83d1a59cee38f61794e45cba3ba4e -dist/2025-09-21/cargo-beta-x86_64-apple-darwin.tar.xz=28c0ae4f78f37abe27a3db5e5fb8c78c51a98b71cd0c4c69f9256b5d4064e78d -dist/2025-09-21/cargo-beta-x86_64-pc-solaris.tar.gz=c2da94328a164d889ebbbcd5f403068126e8f28ebc0c4ff7bf5cde1e8cc380b4 -dist/2025-09-21/cargo-beta-x86_64-pc-solaris.tar.xz=4fb30f600f8a10f43bfbf4361fbc7e906217007d46d65731b1bae0007eaca783 -dist/2025-09-21/cargo-beta-x86_64-pc-windows-gnu.tar.gz=86e23a551906f961a8a05b50185185de683f824a69bc739c3786e4f2004d83f8 -dist/2025-09-21/cargo-beta-x86_64-pc-windows-gnu.tar.xz=860562d5c50c60233d088886dd22b23c0c40504107b04cdfb51506c631d948ba -dist/2025-09-21/cargo-beta-x86_64-pc-windows-gnullvm.tar.gz=b568148f13e609e6cbb7e2b424c13a8b85126c8ef84f3b884043aab204352615 -dist/2025-09-21/cargo-beta-x86_64-pc-windows-gnullvm.tar.xz=7983768e6c77334eedd563cea4cd51cbf85d5234d1952801783016f07f1d6ce7 -dist/2025-09-21/cargo-beta-x86_64-pc-windows-msvc.tar.gz=839f7866c75750a5fdc0e7b9fdf37e0b60e71be916b496a9be3ecedc87473c2c -dist/2025-09-21/cargo-beta-x86_64-pc-windows-msvc.tar.xz=5d0e3c8e9082a00be80cc3924e12b7d9d067f9ecfbe14dd1e1bfadff55d2bccd -dist/2025-09-21/cargo-beta-x86_64-unknown-freebsd.tar.gz=8c22ee4fb01955f20d04dba271b44e69718266d70610fbd979565d95df316e6b -dist/2025-09-21/cargo-beta-x86_64-unknown-freebsd.tar.xz=6356f4d133c3820736f82c4eb2857548b5255af4ead57f1f8e66ebc6aaa628ed -dist/2025-09-21/cargo-beta-x86_64-unknown-illumos.tar.gz=43523fa8da79aca1e5a618c10ea031404250cdf1a41b0da369ed6efd05c4190e -dist/2025-09-21/cargo-beta-x86_64-unknown-illumos.tar.xz=c9a1b43c762b3658b0fac5145c6314a1c9e416d025ac22958fc0809fbb24d1e0 -dist/2025-09-21/cargo-beta-x86_64-unknown-linux-gnu.tar.gz=ba780983f067e7dbcce49dd4d39a0d3c0002dbe7dba73eb2a98d7eae17f70931 -dist/2025-09-21/cargo-beta-x86_64-unknown-linux-gnu.tar.xz=07aa13a5411a49238b31191a0797d63b74120a1fa9b5658a67f6c1065271c30c -dist/2025-09-21/cargo-beta-x86_64-unknown-linux-musl.tar.gz=96e6367138d6ff9ae2ca4343f3d5277b5fce39fe6909cfccdd57f1867eb9b021 -dist/2025-09-21/cargo-beta-x86_64-unknown-linux-musl.tar.xz=83e6fb5196805c9bdfca4e80e76e185a885da0820108e98e1fc7ef4aeea7f1e5 -dist/2025-09-21/cargo-beta-x86_64-unknown-netbsd.tar.gz=422fdb2cc97767f235d6abb29dbb0e802b320e11c743f794f8ad13160e4c7c7c -dist/2025-09-21/cargo-beta-x86_64-unknown-netbsd.tar.xz=75c4aee9a720fa55ac5e80c58a890efbf88c57fbd2c57043b9f29bdbd6ae0e3b -dist/2025-09-21/clippy-beta-aarch64-apple-darwin.tar.gz=de39b5014bffa7e20ae1f981616664703828428b6b1a74a6fee80fbab446e74e -dist/2025-09-21/clippy-beta-aarch64-apple-darwin.tar.xz=d5ad3181f6978604f725db8607daf39ee20cbbb6ade35bb50ae7b032b0b62e9f -dist/2025-09-21/clippy-beta-aarch64-pc-windows-gnullvm.tar.gz=a4f5538776b2f1f31bef81f37615d9bc3495080174fe83be0c549508923c9e9b -dist/2025-09-21/clippy-beta-aarch64-pc-windows-gnullvm.tar.xz=a78a56cf381483703f120c596d6921b04aface91847310e20da53aa887a2e603 -dist/2025-09-21/clippy-beta-aarch64-pc-windows-msvc.tar.gz=06a6ee3aa204812322d0b9946ea31dbc5045e59253891fea7e079d4c7e1de894 -dist/2025-09-21/clippy-beta-aarch64-pc-windows-msvc.tar.xz=a4f0add69dad90f0dd7c47966b12f6cb7a4c6e34cc1b44e4a816d359659ae012 -dist/2025-09-21/clippy-beta-aarch64-unknown-linux-gnu.tar.gz=9d88fade821957052581f65765ae84286eee07e0985504d5a7324f615649a506 -dist/2025-09-21/clippy-beta-aarch64-unknown-linux-gnu.tar.xz=0c278a9aaa1ae41bd9bd96f52fed50b1a11a65822024fd01a9eacfa3aa8f1de9 -dist/2025-09-21/clippy-beta-aarch64-unknown-linux-musl.tar.gz=7d04aeb77402ca2ad964b6430ad75d0ec08a68efb505573f5e134664a5aae044 -dist/2025-09-21/clippy-beta-aarch64-unknown-linux-musl.tar.xz=d28207a804219edccb110160ffdf1c1525248ac225df89f4d11e3538a5dd0dcb -dist/2025-09-21/clippy-beta-arm-unknown-linux-gnueabi.tar.gz=2433be238da05b6dbf44a74537e48a1dcd96fc03a8059ab78e553833546f1b97 -dist/2025-09-21/clippy-beta-arm-unknown-linux-gnueabi.tar.xz=74d5920785504fbc0c1e0237a4ee4e8355ffeba2c4bd9471c38d44e3ae52ef4d -dist/2025-09-21/clippy-beta-arm-unknown-linux-gnueabihf.tar.gz=f83867145c740302ad81912f8e39433aac19fa5312f14d35aee2b59638660299 -dist/2025-09-21/clippy-beta-arm-unknown-linux-gnueabihf.tar.xz=420c7b7b6cf54eb27fc3446223ab03a3f90628b47d6b4ae66e432380b57661ad -dist/2025-09-21/clippy-beta-armv7-unknown-linux-gnueabihf.tar.gz=14eefaa624591a49d6d2a3af9663ea4f3aca804d3563f668c734d9e18cc0b39b -dist/2025-09-21/clippy-beta-armv7-unknown-linux-gnueabihf.tar.xz=14e8371566643fdf146117d06b9fa77aa886360d3696d9e43482f288338822b6 -dist/2025-09-21/clippy-beta-i686-pc-windows-gnu.tar.gz=b7ceb33faebadc67294e1df3f08d8d9760a6a17ca1ad30f26da3c586487a14c6 -dist/2025-09-21/clippy-beta-i686-pc-windows-gnu.tar.xz=f0a3f41a65d90119a4c66c6a2007d1f1a75a24e86d9a572837c4410b02af426b -dist/2025-09-21/clippy-beta-i686-pc-windows-msvc.tar.gz=dbdf0cae38daed8bee11eb63d7c3f1c5d019777c238495149baa5ccb10af0f37 -dist/2025-09-21/clippy-beta-i686-pc-windows-msvc.tar.xz=adc49c09b72ff46d3d03f31c8c641675af389ba99c4c517149a10ae471c37c25 -dist/2025-09-21/clippy-beta-i686-unknown-linux-gnu.tar.gz=793ace0c8927a48caf443b794de097895f9e503299da07da13238a56ea8ac07e -dist/2025-09-21/clippy-beta-i686-unknown-linux-gnu.tar.xz=22b9b2b27d0b6b1fd88d67b18d34a4a91207e6b64ba8d47dbfd0c58763d429b3 -dist/2025-09-21/clippy-beta-loongarch64-unknown-linux-gnu.tar.gz=101437e0f1bdc8ca07455d92c87bc32914a5047f6c9d7b7ab9e34799c5d4a5a3 -dist/2025-09-21/clippy-beta-loongarch64-unknown-linux-gnu.tar.xz=afd8c55fa82482a852b564511c4fdddf12abbffc0bbee1b0b4155fd1d6c04105 -dist/2025-09-21/clippy-beta-loongarch64-unknown-linux-musl.tar.gz=df33c329856ed057d069a479181b4fa97fd4a11d109abfa32d6b46c36215e6f3 -dist/2025-09-21/clippy-beta-loongarch64-unknown-linux-musl.tar.xz=ca8451dfcb5b919c1a6510616c8e93dfb15914e689cb30f7debf4c1a4aef58fe -dist/2025-09-21/clippy-beta-powerpc-unknown-linux-gnu.tar.gz=1b738f58256186f0b530375ea2da804aa1834a908412e56767c9a44b134cfd68 -dist/2025-09-21/clippy-beta-powerpc-unknown-linux-gnu.tar.xz=93333f47a041d4ddea4fd9ad3fb3ab43c40fcee4fabe6405190fa26d6bfe3e2a -dist/2025-09-21/clippy-beta-powerpc64-unknown-linux-gnu.tar.gz=2f0da38cf8efcda85634249df5398bb99f3b34982fb4509a0a3171437d809ab0 -dist/2025-09-21/clippy-beta-powerpc64-unknown-linux-gnu.tar.xz=fb3d68e09e40cbf7d6c330c3866c37c759ed728c1d8cbeb6e8e834f6a1fce1c9 -dist/2025-09-21/clippy-beta-powerpc64le-unknown-linux-gnu.tar.gz=7cb5fdfebbc0565e2d883da09815dfb626104afe39c01b169a919a82f62df607 -dist/2025-09-21/clippy-beta-powerpc64le-unknown-linux-gnu.tar.xz=d6705b1e6722e3faf5b863fb319cd811fcb27f4a564e633f164f02f8699c9255 -dist/2025-09-21/clippy-beta-powerpc64le-unknown-linux-musl.tar.gz=ea33f22a67f7c8354e7421129bfcbfb4bce7d909fcfa6a64a3107d82be69d213 -dist/2025-09-21/clippy-beta-powerpc64le-unknown-linux-musl.tar.xz=081e303cf123ddc162633d4d1e3adef4e6fd39598f60ac9dd75c76230df39ddb -dist/2025-09-21/clippy-beta-riscv64gc-unknown-linux-gnu.tar.gz=76ac5dc8b8284437e5fe81cb4978460a6aa5c4a857c4f14246dfabf1831998f4 -dist/2025-09-21/clippy-beta-riscv64gc-unknown-linux-gnu.tar.xz=2ed67a738a07e9d07c1db7789cc5ebe7af033334670fcb1ce84441b9e474ec0c -dist/2025-09-21/clippy-beta-s390x-unknown-linux-gnu.tar.gz=d5a7e6cfdd099ed18e54d88dc1d740b90d1f7d2f22d1fe6ca7960b7319b0783a -dist/2025-09-21/clippy-beta-s390x-unknown-linux-gnu.tar.xz=78231b81d8e612a4c41828428ba2e9af926f2119308b291c8ce81a5233c3c6a6 -dist/2025-09-21/clippy-beta-sparcv9-sun-solaris.tar.gz=a1b0086259586a26f6ca65b02adea83b953989a508385d58fa56c7eafb770227 -dist/2025-09-21/clippy-beta-sparcv9-sun-solaris.tar.xz=b58151b098d58b19bc900f72813138799e2e568a5ad3038528045e5ac562606e -dist/2025-09-21/clippy-beta-x86_64-apple-darwin.tar.gz=62ecc253fa747ec67ae11c7a1672661cbac7d78c1001654e17ca5c0e3bd72d91 -dist/2025-09-21/clippy-beta-x86_64-apple-darwin.tar.xz=b7e9785d3ab00163a0070b7772a4354e9503cdb8456d1a2b0708920658aac614 -dist/2025-09-21/clippy-beta-x86_64-pc-solaris.tar.gz=783d47012b943cd4497c2e0e854cd7727b0957518178165cc1cbc4dc5e6509ff -dist/2025-09-21/clippy-beta-x86_64-pc-solaris.tar.xz=94efccbbe73b2f15f5f86c90324b3adbd1b58bbdb81ea9c32d7efaf067bc6795 -dist/2025-09-21/clippy-beta-x86_64-pc-windows-gnu.tar.gz=8b12cc5e7b9b7e0b234a29886c81455878e806067c025cf3d26eef4a52e08bc5 -dist/2025-09-21/clippy-beta-x86_64-pc-windows-gnu.tar.xz=35fc298fd25949b491c54bfa2f40c963d7ca530b65ac8e52031edf17624b3d05 -dist/2025-09-21/clippy-beta-x86_64-pc-windows-gnullvm.tar.gz=824e1590e12bcad69b43912068e27585466fcc5cf7a2f92f41f727aa39cbcaad -dist/2025-09-21/clippy-beta-x86_64-pc-windows-gnullvm.tar.xz=6fad67e180d0eb0d551b2101dc27bf6846ae2840c63d1ef05588691d055e3806 -dist/2025-09-21/clippy-beta-x86_64-pc-windows-msvc.tar.gz=1353d8c3310d53576d94aa744fe0844b5527d8b54fe43a692042be78b0fca6f5 -dist/2025-09-21/clippy-beta-x86_64-pc-windows-msvc.tar.xz=a7ca6fecd77dc44f3102abad7fbe1fa3846d9ff6ea98a25d4c3bd703800894d2 -dist/2025-09-21/clippy-beta-x86_64-unknown-freebsd.tar.gz=33b5f8dd6a0ef045ad19df4327259a468ece00b250d9fbfe1be7c0f293f874ce -dist/2025-09-21/clippy-beta-x86_64-unknown-freebsd.tar.xz=1bd56197e30fc325c7482aa7a42006a7ad9a0ffad9f3d74d209e98582d2897e4 -dist/2025-09-21/clippy-beta-x86_64-unknown-illumos.tar.gz=0ba3c497472c34de44bda2485d3b964cdab83e3700b44ffd8b41037ccf59a932 -dist/2025-09-21/clippy-beta-x86_64-unknown-illumos.tar.xz=040302a04decb3cfcd599b329db3f17e5f96b7aa4b8174d6f2b17ba19c991853 -dist/2025-09-21/clippy-beta-x86_64-unknown-linux-gnu.tar.gz=21fde20675c5f786b5da4f1be39785d1106f748d88a6609fd4976bfe372e6817 -dist/2025-09-21/clippy-beta-x86_64-unknown-linux-gnu.tar.xz=217255d6ea157f7b06aa66d033dca6239bbc296bc14ff3f0017d5c68bb4d1022 -dist/2025-09-21/clippy-beta-x86_64-unknown-linux-musl.tar.gz=7be4202a658df30aeba451e6dd4f740068dbcc769fe0eaa9a7eb8cb2c2e264ff -dist/2025-09-21/clippy-beta-x86_64-unknown-linux-musl.tar.xz=d2cf3cfa0c5c67d57867586709c274e320c1a76418ffe7dcf65b271448d4de06 -dist/2025-09-21/clippy-beta-x86_64-unknown-netbsd.tar.gz=91f510466f2a8606efc746a5be209a1f0ffe1e20b803f9c54ee91786053cabbc -dist/2025-09-21/clippy-beta-x86_64-unknown-netbsd.tar.xz=2c17d3a00885495f81cb8606ceb78674f63396b3c2a0b3415bb2e62ab39f9d87 -dist/2025-09-21/rust-beta-aarch64-pc-windows-msvc.msi=d5e39b0a1deaaeaf956e57da755e16255b265e80722428625783e7be0835cbb8 -dist/2025-09-21/rust-beta-i686-pc-windows-gnu.msi=edcb39b92d1e84c7d6b0d2559e37be673795a14e807e77e40b32dcaac8b9d415 -dist/2025-09-21/rust-beta-i686-pc-windows-msvc.msi=dac7d64336aa8fcc77761910392efc845aa2137fff8be8df980b02d48809bbd4 -dist/2025-09-21/rust-beta-x86_64-pc-windows-gnu.msi=44e1e8298714b11bc7cc44184f2b20aa39fbadc23f8b2b86005e74879b8430f8 -dist/2025-09-21/rust-beta-x86_64-pc-windows-msvc.msi=4c673f514c7f0f9bf780c2448fa4a4bbe4e4db618d6a9931bd092a6116d432fa -dist/2025-09-21/rust-beta-aarch64-apple-darwin.pkg=4a23353da7a58deac032341011c7bdb78f069ff4bda97d837c67e54454e6e1af -dist/2025-09-21/rust-beta-x86_64-apple-darwin.pkg=5e02da3f6ab8791426060ca40ac7c719451f6f5acba06ec27c273e6f2590cad6 -dist/2025-09-21/rustc-beta-src.tar.gz=22b0288ca9f949cac41260370afd4e6e487c1e3430f6aef23340b50ec4e4ea9b -dist/2025-09-21/rustc-beta-src.tar.xz=31f4b8b4b3471e7063da5038fe5072e44293705ec65b2c272f8d4cdd37875ff1 -dist/2025-09-27/rustfmt-nightly-aarch64-apple-darwin.tar.gz=78627de068d788f65482cdb2763b27fb7570a197b97056ad16f9f6117fccff8a -dist/2025-09-27/rustfmt-nightly-aarch64-apple-darwin.tar.xz=d6c4252e895d303337ce1c8edf2fcfd02078b81007e785ff7a15f773a1789e3e -dist/2025-09-27/rustfmt-nightly-aarch64-pc-windows-gnullvm.tar.gz=d65ef7c1348a74dc1b042c30281ec57c2619a25bdfd8151223415f9d6e067fc5 -dist/2025-09-27/rustfmt-nightly-aarch64-pc-windows-gnullvm.tar.xz=dcd986e9560c45eae6f1d0ee0bce9ad2365d101f4c9b792062557cb26a26152e -dist/2025-09-27/rustfmt-nightly-aarch64-pc-windows-msvc.tar.gz=8b5a164ee78ee9bf76c1ac9d95f63743cc0b05cff9823d42b88d596ee34c9b52 -dist/2025-09-27/rustfmt-nightly-aarch64-pc-windows-msvc.tar.xz=da675f08931285b2d59be0b8cda46f7489855ec9cc07a608d17e4c0f1e6de486 -dist/2025-09-27/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.gz=7a1b11c66f3832e0ccd390441a921cd50a25ae87e641bb856966fd81cd3d5d59 -dist/2025-09-27/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.xz=5f6aa12529624b66f1de643afe6805cf5484c57e3a7c791f85023d28b590dac2 -dist/2025-09-27/rustfmt-nightly-aarch64-unknown-linux-musl.tar.gz=0cc213fabdad76e6ff699f2f0462c8b3dfe5bdc6b14131fc2c87d915a8fdabbb -dist/2025-09-27/rustfmt-nightly-aarch64-unknown-linux-musl.tar.xz=ca84ce0de6d11b69ddc691f4edca1474e66b513f695fab738374942d57ab8b83 -dist/2025-09-27/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.gz=dc0f391a0ac09a8ae2271443584dc8f1338bc0b89b50ee82d47599912fb74c52 -dist/2025-09-27/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.xz=d4bebefbc157ecde2fbf7f7ef6a6d8c703d264f56e2ca8a80b7c241b8e14f862 -dist/2025-09-27/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.gz=672fd91b880195a0fb2eb294129c0ec465aa3be217451fd4b835b2c3294d4c1b -dist/2025-09-27/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.xz=4aa45c993b82f9d9f6b8bf79db2d04acb83cd70147c9ecb1804a3c8258a6c022 -dist/2025-09-27/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.gz=3a8fef72bf471ea1c575c3a6d3a0ffb957fd862f55afb0d40b39c85ff7fc1f13 -dist/2025-09-27/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.xz=08854b212790685caa928e37aa7fe50009590050873c390d2999d6b814bcd2bc -dist/2025-09-27/rustfmt-nightly-i686-pc-windows-gnu.tar.gz=e99f0d4b314c59b7564e85be580477e751e46acf30752b970c36aa9719e10995 -dist/2025-09-27/rustfmt-nightly-i686-pc-windows-gnu.tar.xz=ba3b9a0e0c44c6edc1396915034efe9e7f59e0724271fd6c1fd4805382e95677 -dist/2025-09-27/rustfmt-nightly-i686-pc-windows-msvc.tar.gz=40f42081d1d2eec00bf49f62c12d75e5e5c345e2a4d8da4fa0741239aea72218 -dist/2025-09-27/rustfmt-nightly-i686-pc-windows-msvc.tar.xz=1b9ef88c7ea98880835d8c298625e2bdd219af46eabb18b8c18c92882d81d054 -dist/2025-09-27/rustfmt-nightly-i686-unknown-linux-gnu.tar.gz=2ff88b8231c70044e9b35c3855515d143aac1b3d7a82bfc84833f76f45539c97 -dist/2025-09-27/rustfmt-nightly-i686-unknown-linux-gnu.tar.xz=e07bab9116c10576b7ab01e26af72bdc97bd34a56aa2468e188e58864b030c33 -dist/2025-09-27/rustfmt-nightly-loongarch64-unknown-linux-gnu.tar.gz=766a69e69be097f710a7c175dbfa39b20970135a6fe420457191e095de5fab1e -dist/2025-09-27/rustfmt-nightly-loongarch64-unknown-linux-gnu.tar.xz=ad4a38853cb9e6bb6029dbb2ffedf4b49dfc7cb696edbcb561b204bfa89fd8d8 -dist/2025-09-27/rustfmt-nightly-loongarch64-unknown-linux-musl.tar.gz=f08d5f5ac31fda285b81069709a74eb382450543c4d22289980a9ef94a473fac -dist/2025-09-27/rustfmt-nightly-loongarch64-unknown-linux-musl.tar.xz=40bb1e41db10d4c6b22e46c0f8b5fa1a6ad06cd5f3102c189705380383444323 -dist/2025-09-27/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.gz=d3bf8c8c186c94a0190ae73386839e53dd6ea76cd81e9132438fb7f245d955c5 -dist/2025-09-27/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.xz=665dce6b1a464e1969e3901d7bd293d35a85d5a50ad976600566dcc2a9c46b58 -dist/2025-09-27/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.gz=a28c82ea8a7e2bbd61043e89994cf2be71ead745b3fa782d0653a99fd81bfa64 -dist/2025-09-27/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.xz=3c5cc78a7e311f73c39030f42b8f1d3dd0e54e09f4d636be6a581a829f15483d -dist/2025-09-27/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.gz=372c476dc902ffb7ebb8ab8934a89d1bbddf9df9c810bc6d90d3afab984b8205 -dist/2025-09-27/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.xz=cf2e738c44ea95d71090bc3526d8c7c70e4554667449f4705614c93444e817a9 -dist/2025-09-27/rustfmt-nightly-powerpc64le-unknown-linux-musl.tar.gz=47f215d0c639f0a4bb67423c65c5b87a06cbecd47ea53484b57c9b7d87c6791b -dist/2025-09-27/rustfmt-nightly-powerpc64le-unknown-linux-musl.tar.xz=9085b66b2e8e3460f0993896ca3d684395001ab4ed37a16947ce1d15d5aa224b -dist/2025-09-27/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.gz=0f07ac40b25eeef46a4f4a0d34cf50c9336407f2d7f23c05c47fe35f3a7a1d49 -dist/2025-09-27/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.xz=ce08e9b33e75eb504f28ba23e1cc3003c0aa503fbdceb04271bd533613713160 -dist/2025-09-27/rustfmt-nightly-s390x-unknown-linux-gnu.tar.gz=4e64fc0ec680a294308f897131f8ab185872dc68cd1312fbe1a306ed6e53ba26 -dist/2025-09-27/rustfmt-nightly-s390x-unknown-linux-gnu.tar.xz=b46d423db54a90944276cee172b8cf0ea70562c01537c37c65f3ea17c13a47fe -dist/2025-09-27/rustfmt-nightly-sparcv9-sun-solaris.tar.gz=3a84501e05cc7430f91903dbb0de0946621d05c095459c47dde3cf7e662e771f -dist/2025-09-27/rustfmt-nightly-sparcv9-sun-solaris.tar.xz=0107d3c129e1a18a814d5c213b6445aa7ecb7dd95507641d2cb3d0c39293818c -dist/2025-09-27/rustfmt-nightly-x86_64-apple-darwin.tar.gz=c58e0a2db9b3933539a20614b143e6575f6aa1459ee35af4d67210dd572e6af0 -dist/2025-09-27/rustfmt-nightly-x86_64-apple-darwin.tar.xz=0cd4d7a8cfedc2787bacebbb2fa481d5efe3d56ba476ef8799c34325c40283e1 -dist/2025-09-27/rustfmt-nightly-x86_64-pc-solaris.tar.gz=ad3fdf81b7b00ee670b05ed2bdc05f79a9c066104d797dc7eaa4d767dfe2eeae -dist/2025-09-27/rustfmt-nightly-x86_64-pc-solaris.tar.xz=df79594ece4b8753d8215672004e9071a8c10c8ece8c86d1d3608c8d7c3f0486 -dist/2025-09-27/rustfmt-nightly-x86_64-pc-windows-gnu.tar.gz=cb800c92a8f899d148adc96283818aa81c115b73555c047e07a67d738e9cd2c9 -dist/2025-09-27/rustfmt-nightly-x86_64-pc-windows-gnu.tar.xz=09f6d95c49725c36bace10c8e119d6850dabee1dcdebac264074e296f9e8ab48 -dist/2025-09-27/rustfmt-nightly-x86_64-pc-windows-gnullvm.tar.gz=e061a3925b95a99dffb17d34c85803bbcac4604f95da2674872f0725d82cdda4 -dist/2025-09-27/rustfmt-nightly-x86_64-pc-windows-gnullvm.tar.xz=1090793fe09cd2ec4c54063600c1999f5e53a9ddc5c5d74e4f5e85dc6f2ef98f -dist/2025-09-27/rustfmt-nightly-x86_64-pc-windows-msvc.tar.gz=f3978135d4a9bf2537625e38866fca74ca1f0655fc9fae736bf87d257d6cd0d5 -dist/2025-09-27/rustfmt-nightly-x86_64-pc-windows-msvc.tar.xz=03814722fe9798b503ab7d8284c67e84cf18a9a2f179fe227e3313d0ae3e2cff -dist/2025-09-27/rustfmt-nightly-x86_64-unknown-freebsd.tar.gz=d5a477ce3f220016f097f8949fc2eb1c700c612e97105804156e82264e7ba787 -dist/2025-09-27/rustfmt-nightly-x86_64-unknown-freebsd.tar.xz=0fe90bad20ee599e4e57c46d4bf700c5775c484f0a8bfb2ce4957d2aa2df90cb -dist/2025-09-27/rustfmt-nightly-x86_64-unknown-illumos.tar.gz=6d48ed9c944fb01655d4025c4aa3b719813cfef040fecff1f59b8b51a0b9510d -dist/2025-09-27/rustfmt-nightly-x86_64-unknown-illumos.tar.xz=34d5a066b9f5bcef81b38badcc96f295150c2b2a96c35621235bdcc54ce92158 -dist/2025-09-27/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.gz=61a6a8feaf0490e3db169e86e85989538bff994fb76481a81a1ae02222c7ba59 -dist/2025-09-27/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.xz=cd94e20b4985964442b080454c2b628bcb435898e50bc2de55799cc51cd75f16 -dist/2025-09-27/rustfmt-nightly-x86_64-unknown-linux-musl.tar.gz=c2912263d24904ee5b1014a98d5b349754a6fa1bd66498f607cc62ebcf903cc3 -dist/2025-09-27/rustfmt-nightly-x86_64-unknown-linux-musl.tar.xz=8ad5b1284c91798a01fd25b3b690f88b55026e109471e759d4cecdefd1f83a39 -dist/2025-09-27/rustfmt-nightly-x86_64-unknown-netbsd.tar.gz=e0f52a6511c36c2ece175bc993861cffe0cc72a2e1b56b1def246e09f70d3a75 -dist/2025-09-27/rustfmt-nightly-x86_64-unknown-netbsd.tar.xz=229b92a2c0ef8ab1ac588858bb371ea0ed3449dec82a11ca7386df6efb2f65b7 -dist/2025-09-27/rustc-nightly-aarch64-apple-darwin.tar.gz=de7af74b8c91fb87b20df2d65b536fe6f49cc632b1f0c52a1e65a215fd5e4a06 -dist/2025-09-27/rustc-nightly-aarch64-apple-darwin.tar.xz=7a3e8c68f0bf4d393393628bd85d22242eee59605e3d56e0e94d06163ee2d4e9 -dist/2025-09-27/rustc-nightly-aarch64-pc-windows-gnullvm.tar.gz=2826132a82eb5adaabe2fdadc76ddc21460834365085ff2a113d934c11870a41 -dist/2025-09-27/rustc-nightly-aarch64-pc-windows-gnullvm.tar.xz=47980ea13cb887d85f8e501ca2b5d6e4b77ba8f229b2cfb9a1f28426c60d87a9 -dist/2025-09-27/rustc-nightly-aarch64-pc-windows-msvc.tar.gz=10dc98065c0b19d737ea93506df1ac399c33190edb3f6bbc51d6c1697e910f8a -dist/2025-09-27/rustc-nightly-aarch64-pc-windows-msvc.tar.xz=d791bf9c54ccdb02da34e408aa93e0680f19a3bfbed1e5dbd61b57f1e1f38fdd -dist/2025-09-27/rustc-nightly-aarch64-unknown-linux-gnu.tar.gz=ba6e33f6efa2f5a97790e29bb72c89bd460d758244dc9dfa4684e01bc75b6656 -dist/2025-09-27/rustc-nightly-aarch64-unknown-linux-gnu.tar.xz=4e38e862770ed0215720445e56fb027570e4f3c09d63a7f68cdacbff482b4cec -dist/2025-09-27/rustc-nightly-aarch64-unknown-linux-musl.tar.gz=b126fbef234c0b67df42fb0568580b3d95ce98b7346095c3762214fcdece14a5 -dist/2025-09-27/rustc-nightly-aarch64-unknown-linux-musl.tar.xz=07af694d0ab0b55b18bd437ec9edb965f451f1bbb8334e1667f87d1d8e8354b2 -dist/2025-09-27/rustc-nightly-arm-unknown-linux-gnueabi.tar.gz=6901b57b0fe7182a45b1934e1d7a006ba353daf114ea7601563caade4de1b2c2 -dist/2025-09-27/rustc-nightly-arm-unknown-linux-gnueabi.tar.xz=c1af7bcb75c1ce5975e606aacb2d3decaf7a8470cd347d4caf75f11f84d3122f -dist/2025-09-27/rustc-nightly-arm-unknown-linux-gnueabihf.tar.gz=8f29e493bd15175ed2a72d50857cbcc07992194c0b38d2b0a4660217b04b8276 -dist/2025-09-27/rustc-nightly-arm-unknown-linux-gnueabihf.tar.xz=fe478ade162b6b5d33808f4872de54e0b9dedd84e9e420480a370a2555d28cbc -dist/2025-09-27/rustc-nightly-armv7-unknown-linux-gnueabihf.tar.gz=f03a3368f41969d061a9ec2e87af512c346f9e82b6286eea65dbce33de90391e -dist/2025-09-27/rustc-nightly-armv7-unknown-linux-gnueabihf.tar.xz=c771ab34e5bab9344be3dab9315225296e41b3fa70cfe59fd3e0b287c4985fc2 -dist/2025-09-27/rustc-nightly-i686-pc-windows-gnu.tar.gz=9f5555633f1f1462285c0eb39aa42d0beb45cdb3b45c524483e4e4c6b76b6551 -dist/2025-09-27/rustc-nightly-i686-pc-windows-gnu.tar.xz=ae8c171fa20a49d7323bb5e6a36b262947caae260adb942204206aada00bcfaf -dist/2025-09-27/rustc-nightly-i686-pc-windows-msvc.tar.gz=2b50b6d9027d5b480dcd2693a551bf80db7d3dae802bfd9a825b68a50ab022a6 -dist/2025-09-27/rustc-nightly-i686-pc-windows-msvc.tar.xz=d4b396eb0256cd62718751f3a52498dba992ba063ed77e5d675da8dc06a6751e -dist/2025-09-27/rustc-nightly-i686-unknown-linux-gnu.tar.gz=f74acd9ecd35d10040e388d5224a9c88e66348dca09930d89068e87a0371a7d8 -dist/2025-09-27/rustc-nightly-i686-unknown-linux-gnu.tar.xz=92bb07e968cbbbfcf1bc7d0ecdd1a088b8c2975691bbf6ed846bc69708e34f13 -dist/2025-09-27/rustc-nightly-loongarch64-unknown-linux-gnu.tar.gz=7b756904c495de2d37993d71fe1e70e182c232aa408296c6ba05f71a94423406 -dist/2025-09-27/rustc-nightly-loongarch64-unknown-linux-gnu.tar.xz=522114675fb36949b953491d9a5fa0db39d22118f015f8ce92a120eab39244b0 -dist/2025-09-27/rustc-nightly-loongarch64-unknown-linux-musl.tar.gz=2309e49988ec8c35ef17f7293d6b2a787589eb38bba217a8f9429446713cc2a4 -dist/2025-09-27/rustc-nightly-loongarch64-unknown-linux-musl.tar.xz=820950e1cbfe6d973e1835532f9e201fe215d149bc415ac7ea011b16bf6b7bc8 -dist/2025-09-27/rustc-nightly-powerpc-unknown-linux-gnu.tar.gz=6fe053425d6b840c72352a88021c3b2b6deb389986575cb5e7b8c5991e86d039 -dist/2025-09-27/rustc-nightly-powerpc-unknown-linux-gnu.tar.xz=d62cad3e6a7dbab7cbefa493e78a0b7d7e8f724dcd766ae03b6715c325594fe5 -dist/2025-09-27/rustc-nightly-powerpc64-unknown-linux-gnu.tar.gz=8bc6b3d521f5117bd3f9321d9d086e928fecf548be58edc71b257269e68ad21c -dist/2025-09-27/rustc-nightly-powerpc64-unknown-linux-gnu.tar.xz=d08a0ed4adb7fdf451d39c1dd56171d6ce345b10cf905515c07ac5eb66f7d030 -dist/2025-09-27/rustc-nightly-powerpc64le-unknown-linux-gnu.tar.gz=02ac6a9c23c1dfaf12e26b466bb33057787c28f2bfe8503b998a5d5aa55a4370 -dist/2025-09-27/rustc-nightly-powerpc64le-unknown-linux-gnu.tar.xz=77709b47a9d99657e03c77f32183b2127e75488df59cd000ed20cad5868afd5d -dist/2025-09-27/rustc-nightly-powerpc64le-unknown-linux-musl.tar.gz=b811bfae5380ffe89e2f48f6c0e6f293e8db33461a1fda94a85759d3464100c4 -dist/2025-09-27/rustc-nightly-powerpc64le-unknown-linux-musl.tar.xz=bc41de8c0c65d912b5d6be06f3b12b3e4be1c20c1dc6ce1b7f5226e7d3ab3ae2 -dist/2025-09-27/rustc-nightly-riscv64gc-unknown-linux-gnu.tar.gz=110b42065218c2607b01edb83d41425176d7f065fac52c5836bed0d2215fc5b3 -dist/2025-09-27/rustc-nightly-riscv64gc-unknown-linux-gnu.tar.xz=97e3a41b0718ea14be4b7320aa4efc7f19b3feeabc7aa9079ce4ea487cad8064 -dist/2025-09-27/rustc-nightly-s390x-unknown-linux-gnu.tar.gz=4e1fd4ed9df5ae921380e3396159053c87623a9ee1c7bcc1f897674c9165714d -dist/2025-09-27/rustc-nightly-s390x-unknown-linux-gnu.tar.xz=1e2833f165f7b255731fb1d26bd6026f5b6152ed91ac70d8dceb4f692ea9a66f -dist/2025-09-27/rustc-nightly-sparcv9-sun-solaris.tar.gz=8113fa75d9ad92c411c71b6769f2af4450ed3ae285be1ebf10afe022abe52661 -dist/2025-09-27/rustc-nightly-sparcv9-sun-solaris.tar.xz=150128e8dde149bfbb2071cc933844ff87931cb856939db922eab98230ab7bb1 -dist/2025-09-27/rustc-nightly-x86_64-apple-darwin.tar.gz=727f7ae1f1e5fe51a3722105211cef3eb92f792cd054857ffef7bf858d0963cd -dist/2025-09-27/rustc-nightly-x86_64-apple-darwin.tar.xz=295672b0d6afb6e80f25dfd6d1643414f976eab6da00a5babf377ecede580e56 -dist/2025-09-27/rustc-nightly-x86_64-pc-solaris.tar.gz=3505cebc0659388e110d1e55a5eca94ac945d75b3320f16ed9ded08629a91638 -dist/2025-09-27/rustc-nightly-x86_64-pc-solaris.tar.xz=515d5a5046dd2c4b3ac2b21a6dd4bc834eba20d08b902ed396e0b62101978210 -dist/2025-09-27/rustc-nightly-x86_64-pc-windows-gnu.tar.gz=838ce3f625b6dfb87f0271770515988d3b3f1535d75353b8f0f4a69074c1ceac -dist/2025-09-27/rustc-nightly-x86_64-pc-windows-gnu.tar.xz=186eae6c01ecfc67facc96ac75d8518c31de1bf8897d82bc587941c3f686f4c3 -dist/2025-09-27/rustc-nightly-x86_64-pc-windows-gnullvm.tar.gz=76e5d092c78b663c2d75ee9d95f6c60d1ecb509b440312f4a8ad333d58de54b8 -dist/2025-09-27/rustc-nightly-x86_64-pc-windows-gnullvm.tar.xz=69ffcda8f985b3c5b78b18f0eea037890f2efc205f0b7cc4b788f1b35a3b7eb1 -dist/2025-09-27/rustc-nightly-x86_64-pc-windows-msvc.tar.gz=2b08c563daa21d817bdac9c8dd81021a80967e7e671a312c2990575e3622b928 -dist/2025-09-27/rustc-nightly-x86_64-pc-windows-msvc.tar.xz=2e54f6a6b6e096be1f717361d2e474b2ca94957ee006d5fa62910ff3d85cf05b -dist/2025-09-27/rustc-nightly-x86_64-unknown-freebsd.tar.gz=6e00949c5d3a2f0ba86f1d89f54278f09e58f043cfd00d1f5df984835228d28d -dist/2025-09-27/rustc-nightly-x86_64-unknown-freebsd.tar.xz=46d9945d5361b758448454c4778a42ce01b4cff7370b9988d5e7b2c7d889d24f -dist/2025-09-27/rustc-nightly-x86_64-unknown-illumos.tar.gz=83f3d4d069729a72da4b96067400b812367e0a81284bfe3cd73b1939fb81db9c -dist/2025-09-27/rustc-nightly-x86_64-unknown-illumos.tar.xz=110ca4f2630368f1c94084332d825964f3852bc9e70db8ec738de2cd4f450f2a -dist/2025-09-27/rustc-nightly-x86_64-unknown-linux-gnu.tar.gz=e1ad313cbe777997222bbdd4b26a5b4c21da50b6378e434501c58219137dad77 -dist/2025-09-27/rustc-nightly-x86_64-unknown-linux-gnu.tar.xz=2ab176057835fabd55e6e2372b036c245be44c0705198557ef2a16d187ea9457 -dist/2025-09-27/rustc-nightly-x86_64-unknown-linux-musl.tar.gz=3e643ce549e9db3768c478b37f088afbf9b2f63dc0275bfdf7c2cbb48ac4fef8 -dist/2025-09-27/rustc-nightly-x86_64-unknown-linux-musl.tar.xz=597c47ff84de68f317b0672d5564a3121edd88cbf5dd3d27192d133ca4ac05a8 -dist/2025-09-27/rustc-nightly-x86_64-unknown-netbsd.tar.gz=5f948f48d64420119f1bd1a90952a04cec074ca45bda8d46f020163cb2809016 -dist/2025-09-27/rustc-nightly-x86_64-unknown-netbsd.tar.xz=977612fd1ed20d57b95e577dd9b3632209fb1f376f46c66467e2a2ccdd7d29f0 -dist/2025-09-27/rust-nightly-aarch64-pc-windows-msvc.msi=b39edbdc83f4329be0e194be1b7e002e764153628bb107bdc77e6f8c2331abe1 -dist/2025-09-27/rust-nightly-i686-pc-windows-gnu.msi=d023b88f94d2d25b4a29c03d4e1243484fd7a20d67753fd3e9a10e6f39069df8 -dist/2025-09-27/rust-nightly-i686-pc-windows-msvc.msi=8441a5f6e8650613b5b9c0c2778bc88bcf259fd4f3acd226a6ec52f1b4a960cb -dist/2025-09-27/rust-nightly-x86_64-pc-windows-gnu.msi=15a83b7056623d30dc1d47560151ec79e2cb7db1d229069085e73b782347e8e7 -dist/2025-09-27/rust-nightly-x86_64-pc-windows-msvc.msi=607a9219272d8b41fd6bedf884515d3584471c75be19f9353c1c67826c115aea -dist/2025-09-27/rust-nightly-aarch64-apple-darwin.pkg=55cc7129e581244dcbc567eb905183ff3e45edc8847fc58cb350394e6df55e96 -dist/2025-09-27/rust-nightly-x86_64-apple-darwin.pkg=a6add14a01bfd77634e67425db47cf63144dbc0b618beeaa4f37be2d7103146c -dist/2025-09-27/rustc-nightly-src.tar.gz=419d5aea9252c3a9377fcfefe0a0e91b7be1354b9c33e36e346c547c4a9ec3eb -dist/2025-09-27/rustc-nightly-src.tar.xz=fd454f13408f045e3ba1d4618699a3c6e42fcc66902c37972aa3729bb681d951 +dist/2025-10-28/rustc-beta-aarch64-apple-darwin.tar.gz=5d971d3a1c127d314f94f41440f0717b51692176630fef7f05a70d9bcd3bae44 +dist/2025-10-28/rustc-beta-aarch64-apple-darwin.tar.xz=2cedfc3a96acc9ebe82c5cf5bcf5355902a5726e1c28e7d50b15cfa2ee343174 +dist/2025-10-28/rustc-beta-aarch64-pc-windows-gnullvm.tar.gz=1875833b43088879444902023cc76682fa58f39520a1135e438afaacf3605f88 +dist/2025-10-28/rustc-beta-aarch64-pc-windows-gnullvm.tar.xz=a925fb02b296b8ce753ff7b1fae583a27fb2ef6de582a80f1428678a2f61a466 +dist/2025-10-28/rustc-beta-aarch64-pc-windows-msvc.tar.gz=28f423bb7db80232b887bd0d47243341a50611eca913c17c305dd55fa6bd3f12 +dist/2025-10-28/rustc-beta-aarch64-pc-windows-msvc.tar.xz=3be7d39a956afd591ba4b22785b4851fd6c0c7afd23d045c54d6b603cc14bc2d +dist/2025-10-28/rustc-beta-aarch64-unknown-linux-gnu.tar.gz=8b98b7e04ef03c3b2bc95e0d6e3a92ad7849bad8d5a8969d6c9eefe169673066 +dist/2025-10-28/rustc-beta-aarch64-unknown-linux-gnu.tar.xz=1b35688d58c10fdd1f1d02325022ae9eb36ee139f76ae753e16a0f4524d0f6d4 +dist/2025-10-28/rustc-beta-aarch64-unknown-linux-musl.tar.gz=c1de08dbaff419f08f82aef49972965d87e02054822e83e6e7f73714afbc4155 +dist/2025-10-28/rustc-beta-aarch64-unknown-linux-musl.tar.xz=2755a71cee31227e4638499dc882347ed9ecf0698cc64a177ff8a94c6ff3be8c +dist/2025-10-28/rustc-beta-arm-unknown-linux-gnueabi.tar.gz=dac50bed8e2bb5d65b5f6ea52963d2b268829c9f79800304a225e058152be0bd +dist/2025-10-28/rustc-beta-arm-unknown-linux-gnueabi.tar.xz=f818783e566cebc2ac392f923efd0ae8f51ae77ce6ade284514a57c21d288b7e +dist/2025-10-28/rustc-beta-arm-unknown-linux-gnueabihf.tar.gz=922d9d3aba6c5ac4da95ab9310d0f33ec7da4830a7d424b83d6f0181af96bccb +dist/2025-10-28/rustc-beta-arm-unknown-linux-gnueabihf.tar.xz=746a200dab88eec922dc08ea244ae818c27a0ca91360278e578ab9fc433bd3be +dist/2025-10-28/rustc-beta-armv7-unknown-linux-gnueabihf.tar.gz=ac45fe7547dc1064286de6704a9343e95fa760163247ac02ff88ebf2bf4d7d8c +dist/2025-10-28/rustc-beta-armv7-unknown-linux-gnueabihf.tar.xz=35ab727f335242d588742f79f29fb94590ac0c3bef29d012538f2e925cb9f96f +dist/2025-10-28/rustc-beta-i686-pc-windows-gnu.tar.gz=42eab38b498e0b8efd7fae51facd7caaf253e1bc341f915f978b484065e4c812 +dist/2025-10-28/rustc-beta-i686-pc-windows-gnu.tar.xz=d663982b6293285fa1ffcc5987ded64569216c0133476243b5525768cd6123bb +dist/2025-10-28/rustc-beta-i686-pc-windows-msvc.tar.gz=571eeccc9c1f25c4b9c2c6f45d15dbd9730bf6c0ac0f75a5b49652b6d4e98f68 +dist/2025-10-28/rustc-beta-i686-pc-windows-msvc.tar.xz=595a8b6b74910fa53a947ddde81f5519152f8c773a41a2f5b0d663540bc913fa +dist/2025-10-28/rustc-beta-i686-unknown-linux-gnu.tar.gz=3f2261279e5c16b0a4b572e799e2d3079aa33192e7713803214011e14c5c6707 +dist/2025-10-28/rustc-beta-i686-unknown-linux-gnu.tar.xz=c49c0e84b4b43aa6b72dc355173b4b5dc41563f3f76e882c405a8625c00befbc +dist/2025-10-28/rustc-beta-loongarch64-unknown-linux-gnu.tar.gz=92cea4e2708fbd86b35bc798b25a69ab10b62f28e972ff0624709e6e8268db60 +dist/2025-10-28/rustc-beta-loongarch64-unknown-linux-gnu.tar.xz=224f6e9896d19e00e369da70bc0e0dbd545d04033ff6ecff12b3f2d2bfe73fc8 +dist/2025-10-28/rustc-beta-loongarch64-unknown-linux-musl.tar.gz=74901d397d5f6695df197520d16851986df2a5c5d432b8f24da1a5c3a5c0474b +dist/2025-10-28/rustc-beta-loongarch64-unknown-linux-musl.tar.xz=02d8962da7234bfd365147b4177497a99c8f1f12f6841160abede61332edd35f +dist/2025-10-28/rustc-beta-powerpc-unknown-linux-gnu.tar.gz=b8d810c76102a325cdecb98e7d7fab480a8d349328ce8a275366018a627fa4bf +dist/2025-10-28/rustc-beta-powerpc-unknown-linux-gnu.tar.xz=f09c4e8d4a4ae4cf490e55bcd29ab00b6f7c1aed09c93b63f10fc3f812f415e7 +dist/2025-10-28/rustc-beta-powerpc64-unknown-linux-gnu.tar.gz=6c71850444d597cdc07a7169bd5d2564cbd99d1a34ec806ac8b818b39c9fd529 +dist/2025-10-28/rustc-beta-powerpc64-unknown-linux-gnu.tar.xz=01f3537787f41c2fd2ed1f955520ff0852bb27d899141cf44de3ae126abf8808 +dist/2025-10-28/rustc-beta-powerpc64le-unknown-linux-gnu.tar.gz=833dcfab6dc87d375154d593c8e53cd5c74b3029f8b94c753928de718185283c +dist/2025-10-28/rustc-beta-powerpc64le-unknown-linux-gnu.tar.xz=cf99a56b49b3db107d33f5c6e668310317aaeb2b2ca3c80a0ea2b30a09b453dd +dist/2025-10-28/rustc-beta-powerpc64le-unknown-linux-musl.tar.gz=55b1db794a4bb0f535e46a2c4a85eb7ea0016482b7086b6deae033746a42a69d +dist/2025-10-28/rustc-beta-powerpc64le-unknown-linux-musl.tar.xz=a741b18a92f5fa35cab2ed93d90782175b70e3ef5a127e21fde7acabb6228b59 +dist/2025-10-28/rustc-beta-riscv64gc-unknown-linux-gnu.tar.gz=97335caa2ace3f33cd959dc35f01ec8a3d2de5699518b93fd191766eda3fe318 +dist/2025-10-28/rustc-beta-riscv64gc-unknown-linux-gnu.tar.xz=2127853b7b4e2b3cf906ef292e9c7e370ec3f3760ce5576b447ed7902048794f +dist/2025-10-28/rustc-beta-s390x-unknown-linux-gnu.tar.gz=eb3df84c1a840cc69799ef0649972e5312afe59144700ba3652bd6083f48074a +dist/2025-10-28/rustc-beta-s390x-unknown-linux-gnu.tar.xz=16942680ea11ead1ab4d9d46d31389a14f237637a6877b278cd30a608446b787 +dist/2025-10-28/rustc-beta-sparcv9-sun-solaris.tar.gz=5c7848ab2b2cb181bd7f64cdbdc3b5b659b61850c14604a7977c35b9807daa48 +dist/2025-10-28/rustc-beta-sparcv9-sun-solaris.tar.xz=0f12cb118e253206ea74e7b1dabdda6e95bb0b10d47657aa4c560fa9ca28cf83 +dist/2025-10-28/rustc-beta-x86_64-apple-darwin.tar.gz=3c34e03deee0445864c7f5ebc89883db051a3c69b874a2daff658fb5dd364aba +dist/2025-10-28/rustc-beta-x86_64-apple-darwin.tar.xz=292d40e5ea57295ecd921a07fa11796771953d38793edcea9841a95e79d94ac2 +dist/2025-10-28/rustc-beta-x86_64-pc-solaris.tar.gz=6ac79775ff166ba76e663e8760ddf9625e06a28e5033d4d8cc570dcca73ca725 +dist/2025-10-28/rustc-beta-x86_64-pc-solaris.tar.xz=46c214af2c11ccb17529a991201624bad044d59c171c6f872468acb8523b6f96 +dist/2025-10-28/rustc-beta-x86_64-pc-windows-gnu.tar.gz=29067fc4a5e0f123c34a045a1b0d55f88170bc9f658584d50e32219cd5945854 +dist/2025-10-28/rustc-beta-x86_64-pc-windows-gnu.tar.xz=30c20794d0c244bd04dbd4de304ef3aea5ba11e26882f2a004680281f21e05b0 +dist/2025-10-28/rustc-beta-x86_64-pc-windows-gnullvm.tar.gz=6c6c7614b538d9bad498b3642321adf0b2b6cdd3b24706903a8eb2125c0c122a +dist/2025-10-28/rustc-beta-x86_64-pc-windows-gnullvm.tar.xz=09822c7d5bbf218d5113e902968b37719949997fd788523bf80400274f428986 +dist/2025-10-28/rustc-beta-x86_64-pc-windows-msvc.tar.gz=fcf05b8150cf7199e100f560854f6acb6874985a5cfbb00ead36914dc3fb66e9 +dist/2025-10-28/rustc-beta-x86_64-pc-windows-msvc.tar.xz=f5259f5b521ea10f093c522abd5bcec4e9dfb94ce3e384e3b53865a223e700d0 +dist/2025-10-28/rustc-beta-x86_64-unknown-freebsd.tar.gz=c3719366a9687d243483431231b86140e268bf2ce99e1ea1759a611524ea8ade +dist/2025-10-28/rustc-beta-x86_64-unknown-freebsd.tar.xz=015e02fb99098c31d502738e9e525d48ac6ca386e16f3ecb55235c7268d4abe7 +dist/2025-10-28/rustc-beta-x86_64-unknown-illumos.tar.gz=508acec5f2b092d09d55590e7fe921f7415aacc13c535532997776c4ebb86483 +dist/2025-10-28/rustc-beta-x86_64-unknown-illumos.tar.xz=f7437c9b0e747b0eccd7755a3ef551fa81194f23304ddb40ae44bca5782dda4b +dist/2025-10-28/rustc-beta-x86_64-unknown-linux-gnu.tar.gz=cd985cf21af999dbb76e25cb6c9b5ac5723e8cda8625cf511e7df2c98e7e735a +dist/2025-10-28/rustc-beta-x86_64-unknown-linux-gnu.tar.xz=d30acafe9f3ddfd25148abdd3078deaaafb6bb62f7979252e9e7880abc260b23 +dist/2025-10-28/rustc-beta-x86_64-unknown-linux-musl.tar.gz=1778c649d790e52b8462d5ea377339443e607b2434fa9b579236b465f63748c7 +dist/2025-10-28/rustc-beta-x86_64-unknown-linux-musl.tar.xz=909808e6e3a10cd3fc2c0927f47dbe4ac8de4653b4e771c9c44b8e58cbe5fe2d +dist/2025-10-28/rustc-beta-x86_64-unknown-netbsd.tar.gz=8584d5ad71c7cedcf6e64b0f83ed2cfa82346e88a1000acac677f464dbb0e6f6 +dist/2025-10-28/rustc-beta-x86_64-unknown-netbsd.tar.xz=7b85928ce5f6908ad82895097ba07fad70990b7810aa23c63725d7ecbbf54d54 +dist/2025-10-28/rust-std-beta-aarch64-apple-darwin.tar.gz=312c1121edf001f03ea169e8fff9668efd1925a45962b282b32d5f126bd6b010 +dist/2025-10-28/rust-std-beta-aarch64-apple-darwin.tar.xz=11e0fd642939358a892e66ebeea7f1737a009ad23692da486c7427cdce60c37d +dist/2025-10-28/rust-std-beta-aarch64-apple-ios.tar.gz=d7086698f3414ebf1410f79f8167ef2e4cf8e9143dc7e3704200d67e64252080 +dist/2025-10-28/rust-std-beta-aarch64-apple-ios.tar.xz=a71fd039b0bfa2fa7a1abd13c622c89371f7af273fc44b3c210b1ead6a1f9156 +dist/2025-10-28/rust-std-beta-aarch64-apple-ios-macabi.tar.gz=52795cad4c58b32c3f36fb7b596c25a8e3277c85c165e161445d1fc81e0c4200 +dist/2025-10-28/rust-std-beta-aarch64-apple-ios-macabi.tar.xz=7db4e584f7890bd05d7cf8a991f539be249e0f04526e30743575129dada977c2 +dist/2025-10-28/rust-std-beta-aarch64-apple-ios-sim.tar.gz=575b6d5185a71a4f4d29dc881f5dea5fe492d7b21a01c0bd9987cc212bb8ca25 +dist/2025-10-28/rust-std-beta-aarch64-apple-ios-sim.tar.xz=ea1c7896e21d0a89da399405611a25ec447ff71495a4b5d48501c9f8129b2a20 +dist/2025-10-28/rust-std-beta-aarch64-linux-android.tar.gz=f7a85a478dd9d55491a2395dda9539ab7898385782ef5be479362ba35e8be837 +dist/2025-10-28/rust-std-beta-aarch64-linux-android.tar.xz=4fc53a2be557540332410446f6f43f5e6339d10d8010c153d99d707df64a5ef1 +dist/2025-10-28/rust-std-beta-aarch64-pc-windows-gnullvm.tar.gz=99b3f95696883f18e3734d02c75a5dc91edac003b6d9627c5a32baac41f3c69c +dist/2025-10-28/rust-std-beta-aarch64-pc-windows-gnullvm.tar.xz=375db4717baaac6a784d8f53f84035f99d5f76f9a3f7df7dd385ee2d93027368 +dist/2025-10-28/rust-std-beta-aarch64-pc-windows-msvc.tar.gz=b650ca7708ae5b05fc82c7aa483f9aaa42be83d6bcc6c524690da745f32f6f60 +dist/2025-10-28/rust-std-beta-aarch64-pc-windows-msvc.tar.xz=1683d5a33387dd546ff641222b501e90049241df0f52c2f1a5dc568b35594135 +dist/2025-10-28/rust-std-beta-aarch64-unknown-fuchsia.tar.gz=3e2d64dd8d2fdedb30b25f899f8ed8deff653c4d3f3f7e16e534ab7e1eec8a66 +dist/2025-10-28/rust-std-beta-aarch64-unknown-fuchsia.tar.xz=e83d63666e0372f27d404a4ddf48de7abc5b646d9f087ebf8856bcbfe6f86362 +dist/2025-10-28/rust-std-beta-aarch64-unknown-linux-gnu.tar.gz=8a99f5fbaf869f68bced6435acf18127ac8880193fb23e44cb5791546bc795d7 +dist/2025-10-28/rust-std-beta-aarch64-unknown-linux-gnu.tar.xz=53be5ecbcb4d47e6a1fb811a6e8b4ecec7fd6ae2b6efac7d9934dee4cfb19dce +dist/2025-10-28/rust-std-beta-aarch64-unknown-linux-musl.tar.gz=f61af59bc40a53dddf0a85b5205bec90d287a41ee3ac32345a97d21861ae6546 +dist/2025-10-28/rust-std-beta-aarch64-unknown-linux-musl.tar.xz=9ed2894300f6ac917ac33d0724133ba2fada2ab2e42a0b21a9bd994d70c942f4 +dist/2025-10-28/rust-std-beta-aarch64-unknown-linux-ohos.tar.gz=70ad473c7d4934bab123afb8cff98773993fdbb73b4941f6022a25ef2942a223 +dist/2025-10-28/rust-std-beta-aarch64-unknown-linux-ohos.tar.xz=d0a06230a38c725ceed103c89e8031b541b7bc15a3646a1a3662d8147901b2fd +dist/2025-10-28/rust-std-beta-aarch64-unknown-none.tar.gz=90d4484a1e390e0d3edf25331d41f9b419730bd2e318e8927c4a891b2c035652 +dist/2025-10-28/rust-std-beta-aarch64-unknown-none.tar.xz=5b795b7378b6753fb2a8ea0ecef760009ffa05c9a4778815d2d2b4085baffe14 +dist/2025-10-28/rust-std-beta-aarch64-unknown-none-softfloat.tar.gz=52d0e13f1dc2083787d3294d5c3569b11227724ab4ced4ba9905ac0a5f25bde0 +dist/2025-10-28/rust-std-beta-aarch64-unknown-none-softfloat.tar.xz=981dca064b73d6617039bb35a32a17111445bc1ed9ba957525d227d3be9e8f6d +dist/2025-10-28/rust-std-beta-aarch64-unknown-uefi.tar.gz=fbb7066da0824513e4441bb59d4c6a6d4c8bc34f67ed79f67da3b8ec69ff3a4c +dist/2025-10-28/rust-std-beta-aarch64-unknown-uefi.tar.xz=c0bb51d8c513c0b5d597cbc00260bf2764595b12244906606c20ae6f98e0fc66 +dist/2025-10-28/rust-std-beta-arm-linux-androideabi.tar.gz=7cd5763f202c5679dc1bdc0e6551dc8093ee95a9b2d405ad8cbd31fcf232332c +dist/2025-10-28/rust-std-beta-arm-linux-androideabi.tar.xz=126b3a04432a3f6f5f1aef6f5e22deec98629da4a0809b0c7739911ae5e4b6cc +dist/2025-10-28/rust-std-beta-arm-unknown-linux-gnueabi.tar.gz=01bc31ad9812edeb11dc4b6c15d4bf80a325e286390829babd85176b91c38cfa +dist/2025-10-28/rust-std-beta-arm-unknown-linux-gnueabi.tar.xz=0b1c799856c8314afddfaa5109535535c36df31bb9188a319c1e45f4968a7079 +dist/2025-10-28/rust-std-beta-arm-unknown-linux-gnueabihf.tar.gz=8792d0115ba1d9b0e3bfefbd7a9ddf7859f7bbf8431ef32530b05ec7cf9c68b8 +dist/2025-10-28/rust-std-beta-arm-unknown-linux-gnueabihf.tar.xz=fc470db282fb0fab537e4b93a9498d4b4fc65cf014536905654cc2c14f82d245 +dist/2025-10-28/rust-std-beta-arm-unknown-linux-musleabi.tar.gz=fe82493d2a7f4a9566916beefcd7fb26301bd13b8b838b5251398ecac0c867ef +dist/2025-10-28/rust-std-beta-arm-unknown-linux-musleabi.tar.xz=b7cd0514db083e115d8aacceb3f7998da11f26e9f2be44137e8af2e2f9ac786e +dist/2025-10-28/rust-std-beta-arm-unknown-linux-musleabihf.tar.gz=0adc4e2e0f5bee4c28c81ba2cfd9796268e830d23b23b80c71121c30f08e3326 +dist/2025-10-28/rust-std-beta-arm-unknown-linux-musleabihf.tar.xz=8c98799e7b4c454cad130d0eb87e8ed59e0e7e64bb0513af8beb6d1d5f8e3ac7 +dist/2025-10-28/rust-std-beta-arm64ec-pc-windows-msvc.tar.gz=bb1da273578b508b9f397074438ecb2527a729e404d2820bd34d67dc8824106a +dist/2025-10-28/rust-std-beta-arm64ec-pc-windows-msvc.tar.xz=e004d91a9732284851d613a3c488909bc7d457b2053a1af45710aa4bbe3169e9 +dist/2025-10-28/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.gz=7e6b5d4266306001366003cdc4fd4b60d700e86ec5dce01b58b0e73bd6a50c42 +dist/2025-10-28/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.xz=170b32ea83d21436e744d11a56ea8e298278f8b9aa58fd82d6d788ff1e3258f3 +dist/2025-10-28/rust-std-beta-armv5te-unknown-linux-musleabi.tar.gz=8ee71b71a8e90b21d580f9e64cc115f182db8582cd6238f946e24fc32de27e65 +dist/2025-10-28/rust-std-beta-armv5te-unknown-linux-musleabi.tar.xz=9319475d974dce729182c3d99696bd5cf6a36257b1b80186f261d2885610ddb9 +dist/2025-10-28/rust-std-beta-armv7-linux-androideabi.tar.gz=71db2b02df33e229899f0dafc675572f2b4041400954f9145796edee7cd923d4 +dist/2025-10-28/rust-std-beta-armv7-linux-androideabi.tar.xz=0f331806b4523d61204f38f2d7ddd07e6f3dcda8a15806a9f01cb1747a587e8f +dist/2025-10-28/rust-std-beta-armv7-unknown-linux-gnueabi.tar.gz=52f331579373b749fb1c7a6302a770a4be33008cdd9db4a5640208ba1ba7b540 +dist/2025-10-28/rust-std-beta-armv7-unknown-linux-gnueabi.tar.xz=1e8c5dcc4cb672c4e8ba2862549cd281ea6802fb73701c885eaf5423673ab233 +dist/2025-10-28/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.gz=2d0dded898f567cbfa5605dcc09b1e44970e345a030ef91c806eafcac4470258 +dist/2025-10-28/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.xz=3a63913c874f30c8a68d5cbb62dc654ec9c3bf2f4488e1098034f60c51824bb7 +dist/2025-10-28/rust-std-beta-armv7-unknown-linux-musleabi.tar.gz=24c341427a9b5a4d883e7f322a9c7760446896e8c2eeb1f8654b80cef00db6ea +dist/2025-10-28/rust-std-beta-armv7-unknown-linux-musleabi.tar.xz=53c5607351479ad76c3450bcc81353633f2587aafda473487bb11e42f80d8523 +dist/2025-10-28/rust-std-beta-armv7-unknown-linux-musleabihf.tar.gz=beda2ede28453b81588d639c18b36fa6e935e586723159e39ab9b714291c680a +dist/2025-10-28/rust-std-beta-armv7-unknown-linux-musleabihf.tar.xz=f175a55fc81159e9a40407b1d97ea658239014cf0f5191a3533318e53ee1ff7f +dist/2025-10-28/rust-std-beta-armv7-unknown-linux-ohos.tar.gz=db1f0cfd65d795d23a60d29e44f24e6174a0a516b998e65bd1964230c9c6c03c +dist/2025-10-28/rust-std-beta-armv7-unknown-linux-ohos.tar.xz=264efedfd340c095dfe08fc95a35c36392eda0d1c2c179e56c75b27685b90d7e +dist/2025-10-28/rust-std-beta-armv7a-none-eabi.tar.gz=578fe97f24afa73c155290bf7386594e8b18a4652f54477d7a4e3f6f3ada0b5a +dist/2025-10-28/rust-std-beta-armv7a-none-eabi.tar.xz=a373109143f701d266ba53b3fff32206d88f5dfabdd888ac988606fade0b4928 +dist/2025-10-28/rust-std-beta-armv7a-none-eabihf.tar.gz=b3d6ec33c14a034c621aaf7de6ec81f0a916e18f5acc933713cc479fc21af755 +dist/2025-10-28/rust-std-beta-armv7a-none-eabihf.tar.xz=6550b2a97ce84884aa0da9133b81703e08b6e57b65c2e93f310fad2559ea4a08 +dist/2025-10-28/rust-std-beta-armv7r-none-eabi.tar.gz=b50984f65ee8a9e8c1b62158d8e91cb976f7c36f6ebc3c70ccfcab2a3da26533 +dist/2025-10-28/rust-std-beta-armv7r-none-eabi.tar.xz=0227fe58cacca86a04d85860a1de852a29ab9ac1bfea7bc50c2f560b73951d8b +dist/2025-10-28/rust-std-beta-armv7r-none-eabihf.tar.gz=da5e26a7cb5b91d3b8ec4f1a02c81b0f538dbb416e10e9453f3fd9d5cfc08129 +dist/2025-10-28/rust-std-beta-armv7r-none-eabihf.tar.xz=9132e8a69bf5dbd144def8bc647c659304fa785612a0f68f2e1a2df5dc195e33 +dist/2025-10-28/rust-std-beta-armv8r-none-eabihf.tar.gz=a312253ad16ccffacd0d840cba85d290fb5d2580865de99887990eff96f58b45 +dist/2025-10-28/rust-std-beta-armv8r-none-eabihf.tar.xz=474813a75bd586e562cf76705bdabf37a915cda6edb45afe029cbcbe54be3cb5 +dist/2025-10-28/rust-std-beta-i586-unknown-linux-gnu.tar.gz=4be0898bb9da3e8d75cb9b4851d5119efdd3136eb10cf31a42109f188781b6ea +dist/2025-10-28/rust-std-beta-i586-unknown-linux-gnu.tar.xz=5a51fb1f2da0dd645c1eb6ce19f37f16f356042ba176ab109f8bcd4ad3514ad3 +dist/2025-10-28/rust-std-beta-i586-unknown-linux-musl.tar.gz=96f621043d426d00f6baec72f66db5d91940215ba3e6985bb823c7b02acbd7ff +dist/2025-10-28/rust-std-beta-i586-unknown-linux-musl.tar.xz=2e62b9a670e3ca1d892ab18da1cd4b2bd946395e35c3b7829dd4b03726a73e4c +dist/2025-10-28/rust-std-beta-i686-linux-android.tar.gz=6c3b0e8796cb87e1a0369b55a91e49d5129af929deb4b63a623cf68219679543 +dist/2025-10-28/rust-std-beta-i686-linux-android.tar.xz=682747e9ab2706e90b5071ce13e8bff21160987d42ed0565f8e0012acded5f40 +dist/2025-10-28/rust-std-beta-i686-pc-windows-gnu.tar.gz=e7afe1e6ccb84fcf03114a6a3fd7232b40d7b2005f31a00a02d9c8e092af8b5d +dist/2025-10-28/rust-std-beta-i686-pc-windows-gnu.tar.xz=99d64d295d7bc0befe84a1da5d888de3ee0daa67a027c8628f78c36ab53eb7b4 +dist/2025-10-28/rust-std-beta-i686-pc-windows-gnullvm.tar.gz=1b36e3979b73348b46a01961a2515bc6ae19a54924e63272cb1bca709a07bcf0 +dist/2025-10-28/rust-std-beta-i686-pc-windows-gnullvm.tar.xz=f579f144f9f653df8be318e4f5ba363116a538b840030d3cd5305f87e03b9e23 +dist/2025-10-28/rust-std-beta-i686-pc-windows-msvc.tar.gz=79de79f2ed569a93dcd57aba35c7995582dde8b633bafbf0fc43ab6a8fb9d152 +dist/2025-10-28/rust-std-beta-i686-pc-windows-msvc.tar.xz=8c3fdbeb815085aaa9d484f1b22d0adbcc829a88511df5930bb518b139d20801 +dist/2025-10-28/rust-std-beta-i686-unknown-freebsd.tar.gz=d25fbb684148778444743e9d651a6d36dc4527d42367bfa67eebc43200e6cc0f +dist/2025-10-28/rust-std-beta-i686-unknown-freebsd.tar.xz=32c6d84e419a72cb862294a110fc79a88b123c4180a3a64bd53c38b200c60f9a +dist/2025-10-28/rust-std-beta-i686-unknown-linux-gnu.tar.gz=577cec0f5fb83cd22a9256dcf7c74529d95572976f102a8a63eb1cb9550f0a6c +dist/2025-10-28/rust-std-beta-i686-unknown-linux-gnu.tar.xz=dc537d7c09efaeb054d2954689842c813b5e9d646fcad912005f4b10e137181d +dist/2025-10-28/rust-std-beta-i686-unknown-linux-musl.tar.gz=5713f1784a424f509f47f70e0bce2bf8ae82e1a16efab8cd771677988b37516b +dist/2025-10-28/rust-std-beta-i686-unknown-linux-musl.tar.xz=1a3dc46f4cb4e4c8e4f96e9835b1188242addcb7a5a8ebbe3ef614c3aef862c4 +dist/2025-10-28/rust-std-beta-i686-unknown-uefi.tar.gz=4c32dcb28c1fbaeb910c9c7c60ea7dfe50e6556663eb3f002b66ec3ed42bd7ed +dist/2025-10-28/rust-std-beta-i686-unknown-uefi.tar.xz=1683c1c2838a2693b2f08a9daf0626675623d6bccbc4c996fcda8489eac853a1 +dist/2025-10-28/rust-std-beta-loongarch64-unknown-linux-gnu.tar.gz=401945e68f2246d1f502d4ac63666d5443ca7fa2f81ce38e76fbb0647fed4643 +dist/2025-10-28/rust-std-beta-loongarch64-unknown-linux-gnu.tar.xz=9b8d7d2f8a4ebf1369718d8bd3ae6973c977cdcb7030ccea0542f9e28970c281 +dist/2025-10-28/rust-std-beta-loongarch64-unknown-linux-musl.tar.gz=ae351e8f921f0c3b8bcccafa0c84402e15ced7591debf82287e63bac0965801b +dist/2025-10-28/rust-std-beta-loongarch64-unknown-linux-musl.tar.xz=7d64ee15508ebb610abe61e1aa03607140302fdbe41200e82070be85312d4a07 +dist/2025-10-28/rust-std-beta-loongarch64-unknown-none.tar.gz=9f951f51a32a4f037f3548935a07208e14f3e67d29100954ae6fbf61a8e56c06 +dist/2025-10-28/rust-std-beta-loongarch64-unknown-none.tar.xz=80494d9d9e02d7a6f56a638d93253d087a4edb83d4662b4771bd1d5c2cba97b3 +dist/2025-10-28/rust-std-beta-loongarch64-unknown-none-softfloat.tar.gz=f23fd6331ba600a3a4350565ad11f51129ad13a248f35c37b9d485fab725b4ac +dist/2025-10-28/rust-std-beta-loongarch64-unknown-none-softfloat.tar.xz=03d765256191ab9fac9f37102fa4252f7efb05261c8d2464745826232351dcd7 +dist/2025-10-28/rust-std-beta-nvptx64-nvidia-cuda.tar.gz=509bcbeb245d69fcb828bf9f3fa4413d1d4d59a0e85ed28c4f412929c734aacf +dist/2025-10-28/rust-std-beta-nvptx64-nvidia-cuda.tar.xz=543aa41bd2ae544c0114cca0e5a50c15eb7ed78d3d132bf5b48f93f2f92b502d +dist/2025-10-28/rust-std-beta-powerpc-unknown-linux-gnu.tar.gz=d67670d0b9385f4433635a473548031d083fe14e1a407766fb1ae5c4762da93e +dist/2025-10-28/rust-std-beta-powerpc-unknown-linux-gnu.tar.xz=e2f403936d191b38347bbad4e9b9bd66270b23e9df238ba9b5d52f81aaebfdb8 +dist/2025-10-28/rust-std-beta-powerpc64-unknown-linux-gnu.tar.gz=15ef51a8fc10b2298db444d68130ef350414722133097d670b8106e8de68609b +dist/2025-10-28/rust-std-beta-powerpc64-unknown-linux-gnu.tar.xz=515151364a93fc458ab5f11831797d2d708b22d9a71c78f717cf89e4e593417a +dist/2025-10-28/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.gz=8ea0204c3ac93828c5a72f671c12167d0b5120cde99bb797c8d839caeb3ba3d8 +dist/2025-10-28/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.xz=138969d2a43b6c4d736a950f8ba5bc0ed5fc7868c7044623d389d8278727e759 +dist/2025-10-28/rust-std-beta-powerpc64le-unknown-linux-musl.tar.gz=a3423e7917b59232faaf855ad9b9cd3b23e5d2188aeb8636e2cef324d405beb4 +dist/2025-10-28/rust-std-beta-powerpc64le-unknown-linux-musl.tar.xz=36914d3ce6a2e5a56a2a394d2c5a461a7c8a40fc235b3552a658ab1ed7d786f6 +dist/2025-10-28/rust-std-beta-riscv32i-unknown-none-elf.tar.gz=dbc0b69f7eba79726bc08a0a6b357f9d818623d3cbe153dff5f2fcb31aeea61b +dist/2025-10-28/rust-std-beta-riscv32i-unknown-none-elf.tar.xz=39def1e42a80080159347b5e85bc666830a3a346c9b0e83eea8207e94659ed94 +dist/2025-10-28/rust-std-beta-riscv32im-unknown-none-elf.tar.gz=7aebf847c08b0eee42c77da8defc6b30439f4b6d29e4122802f02d029518a31e +dist/2025-10-28/rust-std-beta-riscv32im-unknown-none-elf.tar.xz=35c49b2df4b3e18e0ec8ac20ec8b9a4a81b69f026921d85a666e0a97a671045b +dist/2025-10-28/rust-std-beta-riscv32imac-unknown-none-elf.tar.gz=b10e9e0a0457db1441a9bfeb3c4b9a8b2af4d33518bc58a8ee1d3fa7546c0bb5 +dist/2025-10-28/rust-std-beta-riscv32imac-unknown-none-elf.tar.xz=8e210b59b95b3c8db109d978ea73a540478315fb49d4515ccf248aafa7517617 +dist/2025-10-28/rust-std-beta-riscv32imafc-unknown-none-elf.tar.gz=e2bfdac9e858f144db5e9ae79b494f1e09b2a012b18f0eaac96ce684a6a43e25 +dist/2025-10-28/rust-std-beta-riscv32imafc-unknown-none-elf.tar.xz=6d2f5e60af9f6824fe2078a58a6cb804e61116e4848e1502289e08b0b9a5196c +dist/2025-10-28/rust-std-beta-riscv32imc-unknown-none-elf.tar.gz=382f448ea95627ee9fbb3d42c32ab9ecffe21ea12c00810e4eb8e94553d463a9 +dist/2025-10-28/rust-std-beta-riscv32imc-unknown-none-elf.tar.xz=ad7f534565c1b97495bf29054c202d8fada0a0ddfa0cca110c14a8221c654cb9 +dist/2025-10-28/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.gz=7c8cf6afaa4edb589259dcc61ec5e1e667a5deeace8e277f752a433f20bcbf8d +dist/2025-10-28/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.xz=8a396e9db63f1352bfde7a0d51446dabe6873c9a0a46e3c74f59ee775092e2af +dist/2025-10-28/rust-std-beta-riscv64gc-unknown-linux-musl.tar.gz=551d398055ee522ec4a67a9173daca7a1f0f537ab006383ed2ada6b00cc81cbc +dist/2025-10-28/rust-std-beta-riscv64gc-unknown-linux-musl.tar.xz=cf08dcb74f961bff041ad52efcae0c8e239e6439ecdcb32f869eb57b1a3aea1d +dist/2025-10-28/rust-std-beta-riscv64gc-unknown-none-elf.tar.gz=fd4e49a23ea0d512ed32bbaaefc1e5ea32c837e9a371513b94643966afabc521 +dist/2025-10-28/rust-std-beta-riscv64gc-unknown-none-elf.tar.xz=10700fa42e00a3b58ddcd664c0179016b837b43a31476fe4c56e8124619e4a22 +dist/2025-10-28/rust-std-beta-riscv64imac-unknown-none-elf.tar.gz=ea2f2873255dcc73185490b2c396abb4bcd5f1623f7749f77885426f753ce29f +dist/2025-10-28/rust-std-beta-riscv64imac-unknown-none-elf.tar.xz=7c02315d003cf65ac1246e3ac21b6da39cb1d99e61078ba9941647ae48bf9aa5 +dist/2025-10-28/rust-std-beta-s390x-unknown-linux-gnu.tar.gz=008321f0ccd9b96e77829b709c2683c0053acbb19ae86f2fccef49c2cb964531 +dist/2025-10-28/rust-std-beta-s390x-unknown-linux-gnu.tar.xz=047db35903bec7fee6c1d9deee5b4dc21db546a06e11c30d8372ffaf09814c59 +dist/2025-10-28/rust-std-beta-sparc64-unknown-linux-gnu.tar.gz=19677dc6495a139eac6c5827cb765e54e3b099d64f83e92273190f09ead7dab7 +dist/2025-10-28/rust-std-beta-sparc64-unknown-linux-gnu.tar.xz=d5815d1eb4906a442da0a0b56fe61cf94767dda29479da447d94a23803f9cf0e +dist/2025-10-28/rust-std-beta-sparcv9-sun-solaris.tar.gz=184424d0d18c2c49ce1c819e49804d7667edf2bce34fafedd4eeb6d4f427ae5e +dist/2025-10-28/rust-std-beta-sparcv9-sun-solaris.tar.xz=30ad3f9e3eaf48af0eb700d528b330118ad39f221a7beaab1a42e52b1ffa8531 +dist/2025-10-28/rust-std-beta-thumbv6m-none-eabi.tar.gz=c9a72ea7a13651f1b9bc6e509d9d6d32e56a4659d541e20f571ef9f6dd858480 +dist/2025-10-28/rust-std-beta-thumbv6m-none-eabi.tar.xz=6dd3a25ee5060cdf4631d8b0b7f16aa569bf611ef392d93826e88846053779e5 +dist/2025-10-28/rust-std-beta-thumbv7em-none-eabi.tar.gz=ccf8d09ba0bed60fecc775689649f2de31bab68cff273d796378d213c9d1e44a +dist/2025-10-28/rust-std-beta-thumbv7em-none-eabi.tar.xz=b7a972a9b972a2e0665387cd825491bf0ee9581ff26a586806c986014f0ae742 +dist/2025-10-28/rust-std-beta-thumbv7em-none-eabihf.tar.gz=26baa00580268fb5b7aba63a069c187dcca43dcf29161a0c1b849ef3765bbbda +dist/2025-10-28/rust-std-beta-thumbv7em-none-eabihf.tar.xz=dcd67a3ad1f2c553fb90009c630a8edcd8f571e28e5fcef0ade63c624fa11037 +dist/2025-10-28/rust-std-beta-thumbv7m-none-eabi.tar.gz=cef72caa89fcd3d48c070b1aae2fe85f29547c9b615446af2d51767ef42b5045 +dist/2025-10-28/rust-std-beta-thumbv7m-none-eabi.tar.xz=70ad20d0016c6c81b4526ccf89bbd96f4bc0a97b904b2c06487fd0a0368d7a17 +dist/2025-10-28/rust-std-beta-thumbv7neon-linux-androideabi.tar.gz=f22aeb9cdd40a4a465525fca7e6520aaa74b5fbfb41f45777e1376742f711c59 +dist/2025-10-28/rust-std-beta-thumbv7neon-linux-androideabi.tar.xz=48410a5a2f05c80f3d76b9f0b3e0eb89521495b273a854b40386048f27b553c2 +dist/2025-10-28/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.gz=a791f5442467819c154f943c3126de1dd8f5fdd6b62527aadd88260ecb8c380b +dist/2025-10-28/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.xz=cf43ec766a353cad48150d47d108d8df4b1561101b2c95241b909d4a5ec47bce +dist/2025-10-28/rust-std-beta-thumbv8m.base-none-eabi.tar.gz=3699e5b727abc016ab9fa78f40655ef7d88ff157e46759297cd80e5c169136f8 +dist/2025-10-28/rust-std-beta-thumbv8m.base-none-eabi.tar.xz=a6942c04a569f68cf1c5126e520400c51dfccd9e18a1d3941e28d7a8e63ae648 +dist/2025-10-28/rust-std-beta-thumbv8m.main-none-eabi.tar.gz=eb27f46d3ee51e4f71316a75087d4ca2493f55ed5e0b720f0dfa3564c8f19a67 +dist/2025-10-28/rust-std-beta-thumbv8m.main-none-eabi.tar.xz=f50b7fa2830844fd27041ced4c96eaa68ae6595b370eef1c958e3542c718d5aa +dist/2025-10-28/rust-std-beta-thumbv8m.main-none-eabihf.tar.gz=398556eca8a50c1d905ef7e2bf3f25d75f8dcf1d9b679af87b565f5f58af5c2b +dist/2025-10-28/rust-std-beta-thumbv8m.main-none-eabihf.tar.xz=8dc4a5036cfda5725120a8d7e7d0cd05151230ed967ff77fa028c4b73dde6885 +dist/2025-10-28/rust-std-beta-wasm32-unknown-emscripten.tar.gz=212f761263b9a4c72a53aba0b76986f70b3d624557f34d36af2e7d935702359d +dist/2025-10-28/rust-std-beta-wasm32-unknown-emscripten.tar.xz=89c0dae14955afab89b8fa2892944325ff154987c863fd36f93089f29ef993b6 +dist/2025-10-28/rust-std-beta-wasm32-unknown-unknown.tar.gz=92159d52588bb1ca6346025f894dce5520b42d89cb54a78a3ff42ee119c1e90b +dist/2025-10-28/rust-std-beta-wasm32-unknown-unknown.tar.xz=a187e36833f587ad5f117b012a5d9ddacb3122b39b902bc2a9d9d03b5aba27a2 +dist/2025-10-28/rust-std-beta-wasm32-wasip1.tar.gz=fa8971fcd7c22f5d382f4239fa8742238ec967f70fa40180ac9d8a39bffc28b3 +dist/2025-10-28/rust-std-beta-wasm32-wasip1.tar.xz=0603acb7e6fa5540fb458cf363fe473889b0abba91ec0c124ce380ffb1869cbf +dist/2025-10-28/rust-std-beta-wasm32-wasip1-threads.tar.gz=7651d409d4a89dab576cabf51cdd2947f877b77f09f668c6f9b8826dccd5c322 +dist/2025-10-28/rust-std-beta-wasm32-wasip1-threads.tar.xz=a6c3bc7f7f2e6a4cee6db2aa16f74af80cdd17ca92dcfcb1ab1e0c06bbaddd79 +dist/2025-10-28/rust-std-beta-wasm32-wasip2.tar.gz=77537c7a4518e62cb592e5e9d41df02d1ec8a3038b87cdfe082c98ae578973d5 +dist/2025-10-28/rust-std-beta-wasm32-wasip2.tar.xz=794a3c2e08edd74b7a004489017172c30a3242f7f0c5538c3b033937787da332 +dist/2025-10-28/rust-std-beta-wasm32v1-none.tar.gz=746ac6eb726ea2d2996b68be881d5c5fbeeba2bec1fbe57e6c315d4953cccba1 +dist/2025-10-28/rust-std-beta-wasm32v1-none.tar.xz=8bdbcf0cc2b598cbb2098f113128e6f94085dfdaea3ed3d5e15cfd0a82262b56 +dist/2025-10-28/rust-std-beta-x86_64-apple-darwin.tar.gz=2082bcdfd0e837163aec012cba1ae674825f52f5891c8cf3d4d00c619d5bd27b +dist/2025-10-28/rust-std-beta-x86_64-apple-darwin.tar.xz=b2267e0df76f21bcfbb55ab323c58015501d3a3060c4127a005e29fa0e628a7b +dist/2025-10-28/rust-std-beta-x86_64-apple-ios.tar.gz=6a48b60d0aa883ffad612a657d9de232ad1df92f937a5166532a7ee4e655fcc7 +dist/2025-10-28/rust-std-beta-x86_64-apple-ios.tar.xz=81ee2cdad7fd25b56be24d919268d0dc61c1d44d50bccb4c1811e30e85b97869 +dist/2025-10-28/rust-std-beta-x86_64-apple-ios-macabi.tar.gz=01d5952f0970508064fa24196e126cb09aca5085ad6258c53397c3b23b006217 +dist/2025-10-28/rust-std-beta-x86_64-apple-ios-macabi.tar.xz=3c10717be0087060ffb0e5b83c86ce69bff8b0dee9dee95b1be6a44f4238b5c5 +dist/2025-10-28/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.gz=ce87a282ea73eb83015a321b208abfa9d4afdf4a797c799d9efeb1a246e4a64d +dist/2025-10-28/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.xz=5c8866ec1cb4ec7826a94510c00f5cbc7f31822dd7e01ec2fe6b781b25e2afa8 +dist/2025-10-28/rust-std-beta-x86_64-linux-android.tar.gz=19538e0dd74d638b3ac1ac9ed679b8ebc6c058f661d7f167f957eb0866f7cb65 +dist/2025-10-28/rust-std-beta-x86_64-linux-android.tar.xz=15554ba8cc8d1d1c4c46e0438503170aff5a5519eb8bedef07a32d187ca32915 +dist/2025-10-28/rust-std-beta-x86_64-pc-solaris.tar.gz=41a6db659dff188414e33595448dc9c2b99103dbbdedab53d74c6aeccbb76458 +dist/2025-10-28/rust-std-beta-x86_64-pc-solaris.tar.xz=2bbcb13b8271c39a48ac2774e7444fdce883a283622400085623c161f8be405d +dist/2025-10-28/rust-std-beta-x86_64-pc-windows-gnu.tar.gz=e2390bf5da8a91f056df7133020d053d5d90c84c81763738efe8a862864318ae +dist/2025-10-28/rust-std-beta-x86_64-pc-windows-gnu.tar.xz=5d6fb692f2a1d2bad7b550b79e1288223ec598a46975848d07f2a5105b36cb4d +dist/2025-10-28/rust-std-beta-x86_64-pc-windows-gnullvm.tar.gz=30c66f64c7343388f3205e172e64e51dc2930214fae46eb3b21648285092c944 +dist/2025-10-28/rust-std-beta-x86_64-pc-windows-gnullvm.tar.xz=25788901f6fc13a4963bba4e985d619e0739b1239a5679406229a2bd5eaafbaa +dist/2025-10-28/rust-std-beta-x86_64-pc-windows-msvc.tar.gz=9fab4a6cc38c2f06113ae9f0620e40ff5e9134f83562c32576c1e82048ad3bc8 +dist/2025-10-28/rust-std-beta-x86_64-pc-windows-msvc.tar.xz=1b7007f9bc3619cfba09bfa92c3b1e5460316501fee4ae7c8492703a79517f4a +dist/2025-10-28/rust-std-beta-x86_64-unknown-freebsd.tar.gz=461036ed77e332851e88fb6f0f5c64068aef0b177b27662f326d157c06c7115a +dist/2025-10-28/rust-std-beta-x86_64-unknown-freebsd.tar.xz=fd7c7b75a50833650f131a6a676df90dcd57c4784654aee12ce594846da1c219 +dist/2025-10-28/rust-std-beta-x86_64-unknown-fuchsia.tar.gz=882fe895b376384d9b1b1d9c01d9b641ab56b1405d63d7a83266f228b4b759d7 +dist/2025-10-28/rust-std-beta-x86_64-unknown-fuchsia.tar.xz=e9d1fdbd0ba327b6d4e618622c0336eb6895e0e188005423710d514e145baac7 +dist/2025-10-28/rust-std-beta-x86_64-unknown-illumos.tar.gz=aade9f95b362cf13ee48e1d7608eb8487229cf86cc72082afe21fef533e45f5d +dist/2025-10-28/rust-std-beta-x86_64-unknown-illumos.tar.xz=de92c9cf00a2413d5481e96e1db5157c5cb3814851951076e4881b9269651cb9 +dist/2025-10-28/rust-std-beta-x86_64-unknown-linux-gnu.tar.gz=04f6feb37de8305d17e7aacc6174395bd55447340963303767c5a66a63200149 +dist/2025-10-28/rust-std-beta-x86_64-unknown-linux-gnu.tar.xz=2838910a0ef0084245a69fefdc67845ea579f49629cd24fa051b4db0bdc76d98 +dist/2025-10-28/rust-std-beta-x86_64-unknown-linux-gnux32.tar.gz=d2f88d608fdccd0aecbcd83cc184d157d93159e29ad525583188013f327572d1 +dist/2025-10-28/rust-std-beta-x86_64-unknown-linux-gnux32.tar.xz=b5e7ae18377727f93fece51d9ee5704ffd5a9ccd00c540b38ebbf3b9155cf20a +dist/2025-10-28/rust-std-beta-x86_64-unknown-linux-musl.tar.gz=40a52cf3527090a12095b0ed4ad8d35fa5e3cef39146a9a8bff9009cf5772dc1 +dist/2025-10-28/rust-std-beta-x86_64-unknown-linux-musl.tar.xz=28be865d06f9bd744aaad2e82ab8bdb87045e6e2d7ee6fceef2024fa620ba920 +dist/2025-10-28/rust-std-beta-x86_64-unknown-linux-ohos.tar.gz=e0afdd5422adac97fe8c6943470a8561847a614d3e367cb983f28250c0e2e34c +dist/2025-10-28/rust-std-beta-x86_64-unknown-linux-ohos.tar.xz=3007d13a0640d915eca622260c6b8b6a8936788a1228011b90df817b6888155c +dist/2025-10-28/rust-std-beta-x86_64-unknown-netbsd.tar.gz=1744c2485854792601518dcf7855d4223db63e9f3693e2d06c1ac285b92ba33b +dist/2025-10-28/rust-std-beta-x86_64-unknown-netbsd.tar.xz=757803d3cfb8db12dd7c9528852c1e28fb3a9ba97e4230d1e29dbf1834cf3f84 +dist/2025-10-28/rust-std-beta-x86_64-unknown-none.tar.gz=21d5de489cc22d849f246225909278f123483a446e1a3c68b14b8b992c104082 +dist/2025-10-28/rust-std-beta-x86_64-unknown-none.tar.xz=62755ecf24c0a2423b4d05c09ec8e8d38737e6762312d1ba993e1a9417083ba9 +dist/2025-10-28/rust-std-beta-x86_64-unknown-redox.tar.gz=0339d37d857f7f5ecb1607e8c53c499623f0c3563e3b68f2b939ee960d31b270 +dist/2025-10-28/rust-std-beta-x86_64-unknown-redox.tar.xz=613b5ca94e5c33c46d9f29cb557d1e512abd1104c5d81f1897915f6153175cc5 +dist/2025-10-28/rust-std-beta-x86_64-unknown-uefi.tar.gz=1da6167f0a2652b1622cae5ac815d55e307dbd639e4901005a3b225150dcafa7 +dist/2025-10-28/rust-std-beta-x86_64-unknown-uefi.tar.xz=6fca79a15c1ef9f8a3974f84af805106ab453099bdb6f652f584abcd7c8174be +dist/2025-10-28/cargo-beta-aarch64-apple-darwin.tar.gz=e66d076303fe8010c27fdbf8a9e31f47223508a280cd2ffcfea698aede848986 +dist/2025-10-28/cargo-beta-aarch64-apple-darwin.tar.xz=f4e87741a4070fe5bc4ad59ecfd324785cd9a477c539543d6a4fc1675afa8111 +dist/2025-10-28/cargo-beta-aarch64-pc-windows-gnullvm.tar.gz=5e9213968960bab07ad28408563b46d01c1d881c26ccd07651bdb527440461cb +dist/2025-10-28/cargo-beta-aarch64-pc-windows-gnullvm.tar.xz=ec01099da59fab595f8ed8a2f6fb308fbaaabf563cf50c103d47fad4595d72ec +dist/2025-10-28/cargo-beta-aarch64-pc-windows-msvc.tar.gz=ed3cd99db73648bb87c5a25556da30993346f1acc665f9dc906094639370282a +dist/2025-10-28/cargo-beta-aarch64-pc-windows-msvc.tar.xz=c5f89cae65188a7d1b5b5a93f8645774f878db6a14032abb8fd960fa9f4cdb06 +dist/2025-10-28/cargo-beta-aarch64-unknown-linux-gnu.tar.gz=2c85f1c5b1a8bb9532194a16ceb8b04f1586d0ade14442f45e740f3e85022924 +dist/2025-10-28/cargo-beta-aarch64-unknown-linux-gnu.tar.xz=a675601cf6552783625b79c33c1d42715c3918a08078e6eed01236910bafc4b4 +dist/2025-10-28/cargo-beta-aarch64-unknown-linux-musl.tar.gz=e5f2cc9f31b927e2e02117c38a5822c39993242459a057c48e7e11695dabe5a5 +dist/2025-10-28/cargo-beta-aarch64-unknown-linux-musl.tar.xz=1830b8b7e43fc03f0348503ae036b30d0e906cb024bc2257e717a58df95ac222 +dist/2025-10-28/cargo-beta-arm-unknown-linux-gnueabi.tar.gz=eef6f553184a8177525a1ee932d6e293f42eaed6986c1c83f7d76d579f02b867 +dist/2025-10-28/cargo-beta-arm-unknown-linux-gnueabi.tar.xz=13c81e5874532e490c987dbc46b19cf3a7eac14fefdffc30d0c5493a84f8a257 +dist/2025-10-28/cargo-beta-arm-unknown-linux-gnueabihf.tar.gz=56d7f1b41af4d72091c8a99b9a583f24d5aa3912f6dfcbfeeae4eb47bfbf158e +dist/2025-10-28/cargo-beta-arm-unknown-linux-gnueabihf.tar.xz=010292117dca5b10b71b7aabe38d1e8c2f0180ab54e9bf072a9ca8bab3f40ced +dist/2025-10-28/cargo-beta-armv7-unknown-linux-gnueabihf.tar.gz=91671bdd6438df48e4c529e5897afe57b91e8575c12d40c3cb3280493599c0d9 +dist/2025-10-28/cargo-beta-armv7-unknown-linux-gnueabihf.tar.xz=0da8474db35ef547b28f123e8c98ec84dcc4a4a5c4a487a222ac006e809ceb80 +dist/2025-10-28/cargo-beta-i686-pc-windows-gnu.tar.gz=5d9ce7ba82e8d694e53ac877214c0873b0dd78a60c8eabcfe9128433d199d12e +dist/2025-10-28/cargo-beta-i686-pc-windows-gnu.tar.xz=209100fad49e274457d8299360a4c2e83803411a69fec69898a03d9a2bdee955 +dist/2025-10-28/cargo-beta-i686-pc-windows-msvc.tar.gz=edca4ca03b055b40d0c4778e325b93e3759123f207a6d32d7ff42cfa0f323604 +dist/2025-10-28/cargo-beta-i686-pc-windows-msvc.tar.xz=5146440d030e04450de61bd6022cd7ad6364fd06f9cec28bbb7889bad171e579 +dist/2025-10-28/cargo-beta-i686-unknown-linux-gnu.tar.gz=d1045ab266d914060e24224b0e74ea865f4bf4cd527d9a09c5631441c40f48a3 +dist/2025-10-28/cargo-beta-i686-unknown-linux-gnu.tar.xz=caed7a0786cc9f476d1b9fb5367c67a02397ccb12ed18a357b5ed04fe77fb12f +dist/2025-10-28/cargo-beta-loongarch64-unknown-linux-gnu.tar.gz=017335d6ca97cbe4bf93e2ffb4def850b05a8efa0367b008de4cc8b55f1af3cf +dist/2025-10-28/cargo-beta-loongarch64-unknown-linux-gnu.tar.xz=f5671ec0dee9841d4a482183f56ccb986f358a80d043d1ec4b05bc8a356f8ad7 +dist/2025-10-28/cargo-beta-loongarch64-unknown-linux-musl.tar.gz=0a280ebc1b5aab8452f1445fe858ad4808fd7035dd498510951d8b7caa13edc8 +dist/2025-10-28/cargo-beta-loongarch64-unknown-linux-musl.tar.xz=8ab41df2264470d6ed0a6d82b665992f76f9065046a153bc8ee1eda9ca81eaae +dist/2025-10-28/cargo-beta-powerpc-unknown-linux-gnu.tar.gz=7368d0d297fa06108271b03138a9dda0cfbdbe5463a614ebf6fb5b573dde08d7 +dist/2025-10-28/cargo-beta-powerpc-unknown-linux-gnu.tar.xz=1ad0b7d4e3173150768db7105b1a691e8c85db3e9c6a391390e2f5df7844d420 +dist/2025-10-28/cargo-beta-powerpc64-unknown-linux-gnu.tar.gz=75740d0b1847f73777894f484e085f70f24d981b0ef69d00cb5b0c29d276c5b5 +dist/2025-10-28/cargo-beta-powerpc64-unknown-linux-gnu.tar.xz=1ca71e60a6fa9752dd27bfe4f354a1b732b67e55c9e645021e6041a2450b7994 +dist/2025-10-28/cargo-beta-powerpc64le-unknown-linux-gnu.tar.gz=ab37e6d39ccb7fe33c55bf62836c2174f1a4197f02cbe9d88d118b81ec6d49e2 +dist/2025-10-28/cargo-beta-powerpc64le-unknown-linux-gnu.tar.xz=77cc38c5b89fc65fb7453dcc3c3212e0a512923497420b7782ffbfd88f00b39f +dist/2025-10-28/cargo-beta-powerpc64le-unknown-linux-musl.tar.gz=29a2dd23fe30b2d1741e1d4032d4250b4f7f0e2af5ae718b309f2d271e13ef41 +dist/2025-10-28/cargo-beta-powerpc64le-unknown-linux-musl.tar.xz=bac42c5d4af02abbb4db1a9dd4664340d686e4c23f923f372d3b08e090bd105c +dist/2025-10-28/cargo-beta-riscv64gc-unknown-linux-gnu.tar.gz=3b396bf0ddede9f4964bc9fb27b52e628db1d9ccc38dbc5d5e06c316ba8bef87 +dist/2025-10-28/cargo-beta-riscv64gc-unknown-linux-gnu.tar.xz=e706521e4496c79bb677d7d06d79fc1ae2770cdba4a81d8c28ede81ab4ee7909 +dist/2025-10-28/cargo-beta-s390x-unknown-linux-gnu.tar.gz=2fa6ecf04d1cb20dde5f700a0e425ea186d628c5704885e84e197e4494af101f +dist/2025-10-28/cargo-beta-s390x-unknown-linux-gnu.tar.xz=e8810699e679fd0306d4e6c95608970ec5a1d1ccffcdd707fe4a4508518a0e6d +dist/2025-10-28/cargo-beta-sparcv9-sun-solaris.tar.gz=2fcae7eb2f538d84545944c744bbac39e28b3bd58e8d2bdc862d5f66df7068e7 +dist/2025-10-28/cargo-beta-sparcv9-sun-solaris.tar.xz=2fe42f27469fdc23a9e45ec025c60a09f00be07a239cd8c8df74ce52e94b4cab +dist/2025-10-28/cargo-beta-x86_64-apple-darwin.tar.gz=c92c1a580eb85d96f973df4dd9cf4440eb661f8fab9c632b5f0621cf0839badc +dist/2025-10-28/cargo-beta-x86_64-apple-darwin.tar.xz=6c2b13253e1066e49fc52f3cb1654776d5d38853a15e8022652b4a2cb6845daa +dist/2025-10-28/cargo-beta-x86_64-pc-solaris.tar.gz=ca98af5dcaae734ccc02fde2807dca8d95947918eb753d407c12dd05ae937568 +dist/2025-10-28/cargo-beta-x86_64-pc-solaris.tar.xz=864ed5842890359e9f767b4050b8a27ec9c27c88a8cef20993b8f775c213d394 +dist/2025-10-28/cargo-beta-x86_64-pc-windows-gnu.tar.gz=ec8a9e8436f83388736f16f7ad9962a1d9b72673c3da56b8233a6b39dde54534 +dist/2025-10-28/cargo-beta-x86_64-pc-windows-gnu.tar.xz=1f059aae8e6faedcc56663d833a07417e07eededdc2776b2762822987a010131 +dist/2025-10-28/cargo-beta-x86_64-pc-windows-gnullvm.tar.gz=f364bf2f20f35c7ff0381cbd34c88a256849a1b9a27267436e14bc01b7bacfbd +dist/2025-10-28/cargo-beta-x86_64-pc-windows-gnullvm.tar.xz=451f18d049f1c47bfa0c010481e499afa1baaffb889de11534cf451578c62f76 +dist/2025-10-28/cargo-beta-x86_64-pc-windows-msvc.tar.gz=96ca48b12b27b8e933cbb426e7123873a1120bd884a62d150aceb6a26bfc7694 +dist/2025-10-28/cargo-beta-x86_64-pc-windows-msvc.tar.xz=dfe14d019f5c1744a312da8d926059147974de0b5bcdcd869526b5257a1112b3 +dist/2025-10-28/cargo-beta-x86_64-unknown-freebsd.tar.gz=7ef3d3edb6b536382f5063a5de5aaf036d6ba09bf7bd1ff770b87d8942110c2a +dist/2025-10-28/cargo-beta-x86_64-unknown-freebsd.tar.xz=beb5587235e8ff471a8eb9fd84ae5cf4380e7ec9b00ab03dc0c549be0e661dd0 +dist/2025-10-28/cargo-beta-x86_64-unknown-illumos.tar.gz=b97f511486ad044dae0c8b50df8430e489887ac36b770155f163d8e4216cd9c9 +dist/2025-10-28/cargo-beta-x86_64-unknown-illumos.tar.xz=21fc84a42fa988632fb9b0d9dccdf6ab2fbbd06a6780076282fc9bea56567559 +dist/2025-10-28/cargo-beta-x86_64-unknown-linux-gnu.tar.gz=d5b05dc398716909df77415b4a68233b68a5d578855e0e91dcf423f2985fc1cd +dist/2025-10-28/cargo-beta-x86_64-unknown-linux-gnu.tar.xz=21e79bba772e93a6fd910e9d6ee833b55a53b80088f8280525717a4cd800c21b +dist/2025-10-28/cargo-beta-x86_64-unknown-linux-musl.tar.gz=4d126f2591652ddea26884973c1ae1f1e25246cc5f60baeb3a52d6ff45a1aa15 +dist/2025-10-28/cargo-beta-x86_64-unknown-linux-musl.tar.xz=62113a7383f7ff8a9bee099155ca55c3c69d16bf135fc06046f672b2102deafa +dist/2025-10-28/cargo-beta-x86_64-unknown-netbsd.tar.gz=e9a07f035f308d4b9cf5f1b0ab4ef969cad1c41528adea2fca81d8dfe45ebff0 +dist/2025-10-28/cargo-beta-x86_64-unknown-netbsd.tar.xz=3f3d87269072d8e219e7213ca878a7fd441aaf74e4d052ca44ccc7ad75e83eee +dist/2025-10-28/clippy-beta-aarch64-apple-darwin.tar.gz=a44daddb30309be19856b9572679569ffc2ab2c30318706ad59aa2dc14887587 +dist/2025-10-28/clippy-beta-aarch64-apple-darwin.tar.xz=00576ad0f30db5be96e6434e22a2fcdd167067d65ab85199df06a6d11d1ef6c0 +dist/2025-10-28/clippy-beta-aarch64-pc-windows-gnullvm.tar.gz=24fb3dc6680e845c84e535f9c14be5e3d4052ef3ccc800e0fd81815edccb4836 +dist/2025-10-28/clippy-beta-aarch64-pc-windows-gnullvm.tar.xz=20d2ebdb6e2a902eb74ad502a14a2a66e6a9316d5f94513ec9781d146c323d9d +dist/2025-10-28/clippy-beta-aarch64-pc-windows-msvc.tar.gz=652e5bdffbb89ba281cbd5efe3a2cf103adea6af7ba56a21cb6bb538a2ea6536 +dist/2025-10-28/clippy-beta-aarch64-pc-windows-msvc.tar.xz=59d0fb72db77c484571ebab8c992303659225735d3f820ed7048122d8f96d764 +dist/2025-10-28/clippy-beta-aarch64-unknown-linux-gnu.tar.gz=6bf6fb7279ecf5df6edca6014db5f8ba0427fd8cd32f073630b6b02e2e69feaf +dist/2025-10-28/clippy-beta-aarch64-unknown-linux-gnu.tar.xz=0a8d19bca62dc38e64cf527b239106901fa2e0642ca5c2ef1cde070faaa901b0 +dist/2025-10-28/clippy-beta-aarch64-unknown-linux-musl.tar.gz=663581dbd93b22b3b20d281486c8dc0580e43ceca42d9455d78f2d2c341cc758 +dist/2025-10-28/clippy-beta-aarch64-unknown-linux-musl.tar.xz=49548d8ee0561ab96629e354ad055ed5f0c6f3f60c1559ca2a27352b441ff848 +dist/2025-10-28/clippy-beta-arm-unknown-linux-gnueabi.tar.gz=b3d44866b1f909576e0e586aa34b480f1170aa3eba28209ac5bcb929f544d07c +dist/2025-10-28/clippy-beta-arm-unknown-linux-gnueabi.tar.xz=717397166acd760e391c251b1c308657f45deadd928035d2860c772c8b377b91 +dist/2025-10-28/clippy-beta-arm-unknown-linux-gnueabihf.tar.gz=8911fa3347ca26a2afed6140bc4cafa629830740b8e4ff5e648c517f6ea43c6b +dist/2025-10-28/clippy-beta-arm-unknown-linux-gnueabihf.tar.xz=e7360c728068520ec7bd712d57357ce30bbfbb629ec69cfdcf6596002751d93b +dist/2025-10-28/clippy-beta-armv7-unknown-linux-gnueabihf.tar.gz=6d94df05e43804f1054d17542db72cfd3f2df27eedc275c810b35362f9d581c1 +dist/2025-10-28/clippy-beta-armv7-unknown-linux-gnueabihf.tar.xz=25c33744d9722aad4f9fc80674233d16eb653adb17d0deadcd3be8f16a79ecb7 +dist/2025-10-28/clippy-beta-i686-pc-windows-gnu.tar.gz=dfb9ba0cc842b7c92f1dda8bb88bd1db9beeac746c3ca3d144dd4d66d91ff6ff +dist/2025-10-28/clippy-beta-i686-pc-windows-gnu.tar.xz=20f3cf3fe6b52b8f54391be7edd11331a376313c37b674f4987589f50eac68d0 +dist/2025-10-28/clippy-beta-i686-pc-windows-msvc.tar.gz=bcabe1f7679e1ae416c7ed56afd74ad224ff47cd9b5413dececb0e6f503ce393 +dist/2025-10-28/clippy-beta-i686-pc-windows-msvc.tar.xz=f8ebfef39e7119b45a4f714e91b47964aeb6653fbdaf9b01786ef629cbaf3d31 +dist/2025-10-28/clippy-beta-i686-unknown-linux-gnu.tar.gz=f0fc318e90de4f45f6ca7d0d6ca3ed5d044db75f97254d792cdea9a7b196042e +dist/2025-10-28/clippy-beta-i686-unknown-linux-gnu.tar.xz=27c9adb19a7f84edb19ff4c8ce34dd836fb8d10e8786999591e41ec9c60e4602 +dist/2025-10-28/clippy-beta-loongarch64-unknown-linux-gnu.tar.gz=04673347c7e13eee9e301ffc1640ce7a5ed733915c29d90750706829d6b02884 +dist/2025-10-28/clippy-beta-loongarch64-unknown-linux-gnu.tar.xz=2484f24346fbbd2d48f69d86ab7710ef65a5952bb5ea0141f3388f616c7d6d0c +dist/2025-10-28/clippy-beta-loongarch64-unknown-linux-musl.tar.gz=656eb1b94dd2324958e6ba0b1c7a37281abe24dac7d87b0e406fc10931ea0d29 +dist/2025-10-28/clippy-beta-loongarch64-unknown-linux-musl.tar.xz=3349952da5d2693554d2e1ae60bb7ff9cd64451719cadf4227095b73377228c1 +dist/2025-10-28/clippy-beta-powerpc-unknown-linux-gnu.tar.gz=40eeba3b2807a1d807ed25c3bc0482d5b91135a769d2281a894ec8cb8bb52a35 +dist/2025-10-28/clippy-beta-powerpc-unknown-linux-gnu.tar.xz=0a6e79cea6655d6b3e1ff1218651c627886d8f06a5d36e9c3bd3c9c45b375f57 +dist/2025-10-28/clippy-beta-powerpc64-unknown-linux-gnu.tar.gz=b11f919fce34d70816a6dfa0884e37939c38336bad6261fccf5d67d25935852c +dist/2025-10-28/clippy-beta-powerpc64-unknown-linux-gnu.tar.xz=ead91ce4260d07d4e4f950092e94ae224f067ae3c711efe2ccedc9250b2f3dd7 +dist/2025-10-28/clippy-beta-powerpc64le-unknown-linux-gnu.tar.gz=481a2e3b45751e2d86c30d4fb3897f0a7a18e9eadde2c9a3ad1a8b0259fa2066 +dist/2025-10-28/clippy-beta-powerpc64le-unknown-linux-gnu.tar.xz=d5d6529cfc89c29443d9e87041a5f93b746e5bc5791016242e2f271be5bcb557 +dist/2025-10-28/clippy-beta-powerpc64le-unknown-linux-musl.tar.gz=a70d30948f5e95cdd454fa2b3284b97f29134f59e98e130fc2877781f3b62e89 +dist/2025-10-28/clippy-beta-powerpc64le-unknown-linux-musl.tar.xz=8dddfc0b1b2ca8e8866a11a1c95b8601c50150f1e52adbd3803cca2fabb386e9 +dist/2025-10-28/clippy-beta-riscv64gc-unknown-linux-gnu.tar.gz=bd1b28dd79a52de657515ba5c25063b0b6015eb30ee3b0ee05511567b429c992 +dist/2025-10-28/clippy-beta-riscv64gc-unknown-linux-gnu.tar.xz=5262011db6be068ef70905a28939b1838a2fd2b719d38d59e80754695049269b +dist/2025-10-28/clippy-beta-s390x-unknown-linux-gnu.tar.gz=6d3d83d03c46e1de2cc6b6f204e701acc9dddb6d4baef80fada9d868b7eb86cc +dist/2025-10-28/clippy-beta-s390x-unknown-linux-gnu.tar.xz=e57ac819f962d9b431b699b40a047d3e2530f76f2670c5a04747b7de11c3d5e2 +dist/2025-10-28/clippy-beta-sparcv9-sun-solaris.tar.gz=7a492d27b49facb9554248935728cba483eb7ecf3de317751a7445c3932932e6 +dist/2025-10-28/clippy-beta-sparcv9-sun-solaris.tar.xz=cc02f4f971b9e5eb63ca65ff6947cf3490101bfb40ea9fb2b310283bb6d10b27 +dist/2025-10-28/clippy-beta-x86_64-apple-darwin.tar.gz=56f11b8ca012467ef6aa8dc3458a5bf45950f1de062a616a01f6c0aae412d0fd +dist/2025-10-28/clippy-beta-x86_64-apple-darwin.tar.xz=01fe53ec63d71a8427fa3220d037313fc31f8d0fa33a64305b01109344aac21a +dist/2025-10-28/clippy-beta-x86_64-pc-solaris.tar.gz=d222cfda8613bba09b0ac1d02fad99c0d081d10733f0f9253d809221ffdda506 +dist/2025-10-28/clippy-beta-x86_64-pc-solaris.tar.xz=918706ee8ed38bf398cbf0dad85333e3082dc461fff2fb2399b96e840dc24766 +dist/2025-10-28/clippy-beta-x86_64-pc-windows-gnu.tar.gz=7764df051100b08b4b4e5c434d5ced1aaa84d9665f6a4401c9ed6350db983b70 +dist/2025-10-28/clippy-beta-x86_64-pc-windows-gnu.tar.xz=4a43dee6ce0279de929566f844fa4987d10fa5ca856bb2a2cbea4327eef3308e +dist/2025-10-28/clippy-beta-x86_64-pc-windows-gnullvm.tar.gz=add2532fe4e8afb8b53aee8a729fde0c0b36f83a8f6a859c39ae25f3d01e8dd6 +dist/2025-10-28/clippy-beta-x86_64-pc-windows-gnullvm.tar.xz=7117f0afc57ac09c277ba99be4a7de80d62ffaebe4174706910d5ab6501ec9f7 +dist/2025-10-28/clippy-beta-x86_64-pc-windows-msvc.tar.gz=e71d45b8bdb5346d89f769b4698b404b293884878a7f697680318c72829c1d6f +dist/2025-10-28/clippy-beta-x86_64-pc-windows-msvc.tar.xz=67be8cf6580a4a6e36eff94bfe19fdad290eae5db598d2a016dfcc7516178e14 +dist/2025-10-28/clippy-beta-x86_64-unknown-freebsd.tar.gz=03b78bad90efe98cab6416ecc641b7da0c9a2be5950edbb4c520c0758cdb90a8 +dist/2025-10-28/clippy-beta-x86_64-unknown-freebsd.tar.xz=056aecae34c8ae10a41516834809d983bd6126bd0374a7bf0857710492f0d0a5 +dist/2025-10-28/clippy-beta-x86_64-unknown-illumos.tar.gz=a67147c647da8a9b68a507087b66610ed19e65b94538b08326b000e66c170260 +dist/2025-10-28/clippy-beta-x86_64-unknown-illumos.tar.xz=09bd43034d7bc1e9ad1873610237f98543751809ebe63d8255813eadf4a00e70 +dist/2025-10-28/clippy-beta-x86_64-unknown-linux-gnu.tar.gz=9397e5c3b1f45ce949b8e3420233e8b86f95a887667c917b8e7615218989820f +dist/2025-10-28/clippy-beta-x86_64-unknown-linux-gnu.tar.xz=5b67e9eb803c180d101e799f6d7c2a6ea7ec07a93a6395b4f688bf2592bc30d5 +dist/2025-10-28/clippy-beta-x86_64-unknown-linux-musl.tar.gz=b255c33a89b0b1bd666ffb584c20554daa3a7c48123de75eae5e1b4cbc53e1aa +dist/2025-10-28/clippy-beta-x86_64-unknown-linux-musl.tar.xz=bc7f3f7d59f9c52370849092541a9368632f390ed9bc88f2566f1e3700f4da80 +dist/2025-10-28/clippy-beta-x86_64-unknown-netbsd.tar.gz=a8f366918520cc5a82c9bcfbb419570e6792712455ec5c04655e6557a657e949 +dist/2025-10-28/clippy-beta-x86_64-unknown-netbsd.tar.xz=dad3555be56e7c8d042f65dfced7915856f9f23cec13a7a633a4aad38c634247 +dist/2025-10-28/rust-beta-aarch64-pc-windows-msvc.msi=943683af0d464ecd36678e1c87b1207a67105820cb3d1516eeebaae450a2928b +dist/2025-10-28/rust-beta-i686-pc-windows-gnu.msi=8532743b3406fbf2926e5c6643300194eaace9de492e7f2ad0caa6f7d040f8db +dist/2025-10-28/rust-beta-i686-pc-windows-msvc.msi=1b3b15aa90c3dca73e9d72d53d214eb3c02b97386c83d8755a03f571cc09de4e +dist/2025-10-28/rust-beta-x86_64-pc-windows-gnu.msi=6249ad7cfcfe78b541e4935ed18dc4cfb10130252885668383a4c8f5046ecc2d +dist/2025-10-28/rust-beta-x86_64-pc-windows-msvc.msi=700f63a1baf0de2f0d1972454486f890af15b3700481698ffb0daf403778390a +dist/2025-10-28/rust-beta-aarch64-apple-darwin.pkg=1f2862fd5dbf8a9c7a765e75391cfffc5a3cd6837066b29f95778b5a346f0f59 +dist/2025-10-28/rust-beta-x86_64-apple-darwin.pkg=ffa2c6275b401c73575a5158911bc53edfece2edc03f6b3f6a140823cf870ee4 +dist/2025-10-28/rustc-beta-src.tar.gz=dbbae9e1c0b5e914b588ba5b659b7fb6af3d5b422831aba028d64b00c7161417 +dist/2025-10-28/rustc-beta-src.tar.xz=aa771d2b1ea8c933444c962c03c384bf2511bdeddf90edcaac8f45bd49f5232c +dist/2025-10-28/rustfmt-nightly-aarch64-apple-darwin.tar.gz=5a5e525f45010fd3e30503f408f21eef78cafa54e42adf9709cff50f6cb29720 +dist/2025-10-28/rustfmt-nightly-aarch64-apple-darwin.tar.xz=b6f92173abde0be1f4f3378c682e42016390e6e5e20df7e84cbd7804a6161114 +dist/2025-10-28/rustfmt-nightly-aarch64-pc-windows-gnullvm.tar.gz=430775c6856f4aea6a2b83e245904d5527f6ace134a9375dc7172f77ecd328f6 +dist/2025-10-28/rustfmt-nightly-aarch64-pc-windows-gnullvm.tar.xz=3d14ccf194d04ad5767a5fc3df6f9c1427cd0e282671887d2264b8314586e168 +dist/2025-10-28/rustfmt-nightly-aarch64-pc-windows-msvc.tar.gz=251f7fa0b78fdad3be1977ffd6a2f563d1524b6423d2bab73d1741aec97b4717 +dist/2025-10-28/rustfmt-nightly-aarch64-pc-windows-msvc.tar.xz=534cacc40024fec78c02916e7e2d46cde8b8153d303efc1b805af8789f25fb1e +dist/2025-10-28/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.gz=5663e413cd9ae9f403a4b5c5e9a9862c00d57bcd68bde9161c91e852115e45cd +dist/2025-10-28/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.xz=3625b287a83796cb71741b9a4b002eb4517950d386f97a91470c0acd5aed835c +dist/2025-10-28/rustfmt-nightly-aarch64-unknown-linux-musl.tar.gz=657b0774a95a925eb38d039ef11bc23d15c4733d0b322f172f0b8236bc7410f6 +dist/2025-10-28/rustfmt-nightly-aarch64-unknown-linux-musl.tar.xz=4e058f11346ec86801bc9cdb830c6dec2620b81fe2cd4b439b275a5145859dfa +dist/2025-10-28/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.gz=820ece81e455d11f65ddf09093b6bf97359cc803959d951bd199c70a79ae117e +dist/2025-10-28/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.xz=8a72a3e715ab2427fc120f8af20d67f722881ee9e13bf482e45ef07f5fb2bf86 +dist/2025-10-28/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.gz=fb583c846e1a11663a1fc525f02c0146dc70e7b4da12c264c8b00cf7927ad9c9 +dist/2025-10-28/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.xz=8a15430000d48b702142cc4569a5eef3aba59c07f33f69cfb6966250fae18178 +dist/2025-10-28/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.gz=c470dd9f35b1b701e8475716e61cfadee5475fa29a2994f407d532a794c0ef82 +dist/2025-10-28/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.xz=774898dd43893b99e4e11d004c52244d78d2fb08aaa6fa242cf1d7070d9ff8ac +dist/2025-10-28/rustfmt-nightly-i686-pc-windows-gnu.tar.gz=31ef71bea5f5ce3668b903fabb1582dc256fe6e2f97e5c23ca468e05f3deb7c9 +dist/2025-10-28/rustfmt-nightly-i686-pc-windows-gnu.tar.xz=232351f0a578f9973b536eb587b2e90cb01ca5f76ad376c09d7dd225c09810b0 +dist/2025-10-28/rustfmt-nightly-i686-pc-windows-msvc.tar.gz=eb469e8475af339d36e1381474f931e326ef1f095a6f56f44730019c5f6422fb +dist/2025-10-28/rustfmt-nightly-i686-pc-windows-msvc.tar.xz=42c5f2e88f81cdcc375d26c4ab6d9ec03b387b8de632af8a3fa75bcbfcbf56da +dist/2025-10-28/rustfmt-nightly-i686-unknown-linux-gnu.tar.gz=79e06c14b8f18927b1c24cc4ea97e55a805355137a9bdbe3ba616e334878d85a +dist/2025-10-28/rustfmt-nightly-i686-unknown-linux-gnu.tar.xz=3883c297de03da522a20b893f24970305fadaf726dd9388f89196e1f284115e9 +dist/2025-10-28/rustfmt-nightly-loongarch64-unknown-linux-gnu.tar.gz=b3ddf283d7964a4c261668df7685bc47b469c7294325f975436d465cb7d44163 +dist/2025-10-28/rustfmt-nightly-loongarch64-unknown-linux-gnu.tar.xz=9e63e1bd8b4c52943092e91942737be9b3ee9c128dfbeafdc01d3dc732058165 +dist/2025-10-28/rustfmt-nightly-loongarch64-unknown-linux-musl.tar.gz=83845c5809a9b525655565b3e3b4889e2a07562587c6f046280a44dcbb809094 +dist/2025-10-28/rustfmt-nightly-loongarch64-unknown-linux-musl.tar.xz=533113ead2985a36cf685cfbd6645d43f1a7e2e66b6eaadbde2ff5a72d10c5dd +dist/2025-10-28/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.gz=82c6aa57adb0f03b96982f51edc65aebfac3811cd2845d280b7bf5fb81cbe92a +dist/2025-10-28/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.xz=8f4b3c91072d56ba80ba4702e611dbc6fe66163666e6ee35d74602ef36fe9839 +dist/2025-10-28/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.gz=4fe0b85296e2249b36a0b021d6b82e7c31c40a5f717a5f447b6bf9b9524069a2 +dist/2025-10-28/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.xz=9257bb295a58a7df3fbbda809bafc74a8601618afd0fd41467439a8972278cae +dist/2025-10-28/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.gz=d3a5851060a66a0e027ba142dbdb6e827f4f5f5116b5fdb0b8e86ee56616d682 +dist/2025-10-28/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.xz=fe1e9e4e3a234ba8cb656b08b7bbf5349f5068906cb60a4c5c53f7fe3e214487 +dist/2025-10-28/rustfmt-nightly-powerpc64le-unknown-linux-musl.tar.gz=2187f1ccbd4e638efaf9f05566998b579b32729fd9ee4332964a3c54556c3a20 +dist/2025-10-28/rustfmt-nightly-powerpc64le-unknown-linux-musl.tar.xz=88526ca6af21bdbc6c46130012cb5fdde25fd44e6372187e66d273067efbc052 +dist/2025-10-28/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.gz=9299c8d4dfc320cf331dc4005c36a0108961a6d5ad750a5b0a6be8c7cda77953 +dist/2025-10-28/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.xz=7da58822a9ba4d65258ca0cd514b9abcc85070baa195ce65d40ed9d9de049049 +dist/2025-10-28/rustfmt-nightly-s390x-unknown-linux-gnu.tar.gz=e07cc8f1166bb39aada202559c1e2ee9190cf85fc11b4d4abb921cab352748f8 +dist/2025-10-28/rustfmt-nightly-s390x-unknown-linux-gnu.tar.xz=ebcb49b4ee1e8dded5e6569c7edea1578a369e92aac9030a51d11e95bd8bb8b1 +dist/2025-10-28/rustfmt-nightly-sparcv9-sun-solaris.tar.gz=247ce6a1fb10911b8f38bc8f88617d9a7dd2147e1f1896710b0b610f8bb4b86e +dist/2025-10-28/rustfmt-nightly-sparcv9-sun-solaris.tar.xz=020d64391c730a61f4c61d802b432a463d4909d0e4d5fe4756db4683df6e000c +dist/2025-10-28/rustfmt-nightly-x86_64-apple-darwin.tar.gz=547d7711acee55435e271fca1cebead82045375b0fb136404be7df379b0d404b +dist/2025-10-28/rustfmt-nightly-x86_64-apple-darwin.tar.xz=e8ef4fa56be91b642fd3a8c29afb9dfb3fb7601c8fbd24393be4f3dea1802163 +dist/2025-10-28/rustfmt-nightly-x86_64-pc-solaris.tar.gz=0e41caa314927c9a8656d16b6623c95463a64f07a23941d03597a17582c224d6 +dist/2025-10-28/rustfmt-nightly-x86_64-pc-solaris.tar.xz=d73dcd42d9110befbdf64c46b9e4e8bad07839302cec49e2d8cd99ab436d4bbf +dist/2025-10-28/rustfmt-nightly-x86_64-pc-windows-gnu.tar.gz=8e821c45dc91d5df1b9f8487554cadc4deb86a9ef3db25f4e21b38eab3cc8ed2 +dist/2025-10-28/rustfmt-nightly-x86_64-pc-windows-gnu.tar.xz=f98ccfcc37b7412788a546cbafe5f09b90c26f823e3cad17e71432df4ba910ef +dist/2025-10-28/rustfmt-nightly-x86_64-pc-windows-gnullvm.tar.gz=762e15406bac23f0f41dae2b1b3370458b92e8be771868b4f8f536f53cb26fc3 +dist/2025-10-28/rustfmt-nightly-x86_64-pc-windows-gnullvm.tar.xz=cd87b4a4c2af3edea8ba09ce9bb8704449d8f51c5dee8ba10161e0ce2ec2aa19 +dist/2025-10-28/rustfmt-nightly-x86_64-pc-windows-msvc.tar.gz=7de2ee69be5384656024a6d7c3481315fe90abc9ba9a26726f1eab09aae2c818 +dist/2025-10-28/rustfmt-nightly-x86_64-pc-windows-msvc.tar.xz=16377ae5474e30b6c11ba886579ef13db4039d0b9f43240db00aacf7366b37d7 +dist/2025-10-28/rustfmt-nightly-x86_64-unknown-freebsd.tar.gz=d98fd17080ed5a4fda444719011540a80320001a0b0dc36148f2e3f78e5f5c33 +dist/2025-10-28/rustfmt-nightly-x86_64-unknown-freebsd.tar.xz=c825c2b46f43fe71f4452494fb422cd9565ec6454857835a6c77081553081523 +dist/2025-10-28/rustfmt-nightly-x86_64-unknown-illumos.tar.gz=8844743cc05351b1f6ba8fb50ac1d86161a285775eb4c0e474308aec71b631c7 +dist/2025-10-28/rustfmt-nightly-x86_64-unknown-illumos.tar.xz=172dc660ceb00e7003e855a09f46d9f83096773495ed6d7b8b1ed6b9e770912f +dist/2025-10-28/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.gz=2710450c26834b07a5eb80bf990dc67a6db89f87e26d6b613ed96116c28958d4 +dist/2025-10-28/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.xz=bbb8eac454e0ba3b23c9803d8201fa341d0f0af509aa9e8b530c9b98a1d9886c +dist/2025-10-28/rustfmt-nightly-x86_64-unknown-linux-musl.tar.gz=e6bb6a67878c9cbbbbc96f1a1858500403ecc3b8c951366e18ace0f2601f41cb +dist/2025-10-28/rustfmt-nightly-x86_64-unknown-linux-musl.tar.xz=f6509af9551e73ac16c425c53e667382bf7b6b48be65f4779485ee7843e68030 +dist/2025-10-28/rustfmt-nightly-x86_64-unknown-netbsd.tar.gz=3915f1907939fbfcd82012efa4293e7ddf22bd5bf1484efffacb31c805e6cf68 +dist/2025-10-28/rustfmt-nightly-x86_64-unknown-netbsd.tar.xz=cca6182ce9f2906a8b16971741a8435dbcf60d9ef6020cc7d6f7909525a73dc2 +dist/2025-10-28/rustc-nightly-aarch64-apple-darwin.tar.gz=876004fa16a6154ea8ea46cd1bb60a06fc14b24e72e26e20e42fde4e32882b46 +dist/2025-10-28/rustc-nightly-aarch64-apple-darwin.tar.xz=0a98f29bb6a2a1555f6ceaa161ecdd2e599ffe879b98bc98c6066e257fc12362 +dist/2025-10-28/rustc-nightly-aarch64-pc-windows-gnullvm.tar.gz=b07b2f7975b463970cbb4a8c92e51788ac63c3a46d3ae6c8cb54c7024161d899 +dist/2025-10-28/rustc-nightly-aarch64-pc-windows-gnullvm.tar.xz=5445b2e30804733fe2a7d07f66a77c2e3ec5e7c71bb55403541b8d365cf91870 +dist/2025-10-28/rustc-nightly-aarch64-pc-windows-msvc.tar.gz=d2cff6b8cb52172f4bb394f8ca891897c774ece1b87f9d30729aa236dfa24900 +dist/2025-10-28/rustc-nightly-aarch64-pc-windows-msvc.tar.xz=a6d0c00367b49654c91d4b71b33819854f628d51b7193c2475b9f737258a575a +dist/2025-10-28/rustc-nightly-aarch64-unknown-linux-gnu.tar.gz=c30649c2360aef41d97bdbf76d55bbfe674a1225161bc125a8215d3954656cda +dist/2025-10-28/rustc-nightly-aarch64-unknown-linux-gnu.tar.xz=3b204fb1461f47b4e2a79a67923abcf8610ab7ab006ee3f9a70cdc87458f81c5 +dist/2025-10-28/rustc-nightly-aarch64-unknown-linux-musl.tar.gz=949f55697b50db7d70a6465b100ae4458d2f676b818ca7227014ddc9c5f707e5 +dist/2025-10-28/rustc-nightly-aarch64-unknown-linux-musl.tar.xz=ff500cd8f318f0316936af462264254df2aa1bd5a2b368ad3c5758e9079eaf71 +dist/2025-10-28/rustc-nightly-arm-unknown-linux-gnueabi.tar.gz=231c4cfa37df03a0e0517843bd115a0f0b13ec259397d6e4dfb4014d3a0d4d9f +dist/2025-10-28/rustc-nightly-arm-unknown-linux-gnueabi.tar.xz=50f4d7060d02833949ffc970b88c5ad2183fabd3c498334bf63d87d0c9602720 +dist/2025-10-28/rustc-nightly-arm-unknown-linux-gnueabihf.tar.gz=f89586ea5bac722a06c225a50d7d603b4895aea89297509f248a1cb51a5cf0ed +dist/2025-10-28/rustc-nightly-arm-unknown-linux-gnueabihf.tar.xz=0de0552ae68cb9b61f2c5031cdbefae5ccde39c4003441e93c2e4e704d3751aa +dist/2025-10-28/rustc-nightly-armv7-unknown-linux-gnueabihf.tar.gz=019bbb267d1c0520a715287e0a1a680b58dd5e9ece2071f3ebd6f2b1d8eb2228 +dist/2025-10-28/rustc-nightly-armv7-unknown-linux-gnueabihf.tar.xz=069bcd46adfb5e14786fd8aced5ceb74af24cc05dfa2bd41ebd81ac146122598 +dist/2025-10-28/rustc-nightly-i686-pc-windows-gnu.tar.gz=911eb977b10aa4bb1f25124f08f3397fb3ac65f36666865be40bf44259b5d77a +dist/2025-10-28/rustc-nightly-i686-pc-windows-gnu.tar.xz=14ed0abc8708a90e8bbaf0c0de2aec1a4ed60c63b4db00fd4a732f3c808c125b +dist/2025-10-28/rustc-nightly-i686-pc-windows-msvc.tar.gz=8917e6dd4786f0f413908e9db4c92e060bce525f91b9cc0d43b453d26057435d +dist/2025-10-28/rustc-nightly-i686-pc-windows-msvc.tar.xz=86a8580a180de9224c176beb1ada2c69acc37fc73ae0e7c7780bbbded842365c +dist/2025-10-28/rustc-nightly-i686-unknown-linux-gnu.tar.gz=0d29e999ccbc46ff6b0c50a5648e0c5c8f767daa9a0d1fc86dff30c6e0078dd5 +dist/2025-10-28/rustc-nightly-i686-unknown-linux-gnu.tar.xz=bcafb54ca3f587d3cc9302c057da2fbdb4531e2279ef462fc8682e82e1046561 +dist/2025-10-28/rustc-nightly-loongarch64-unknown-linux-gnu.tar.gz=0a5bfd49a7a2fb98fe06815a2a50d9dc859722da3cc107928e36596c7b8c7f8e +dist/2025-10-28/rustc-nightly-loongarch64-unknown-linux-gnu.tar.xz=b8ec7898e087577b78ef1b716f8935c7023d740b389234f38075a09b2c7b494a +dist/2025-10-28/rustc-nightly-loongarch64-unknown-linux-musl.tar.gz=5cab6709c372feed484b5148ec642cf9767e7fe051146023459467012f2e0b64 +dist/2025-10-28/rustc-nightly-loongarch64-unknown-linux-musl.tar.xz=e42a3c007bdf7e8179c597daffc61d7a6bd8eac782b8d81d0b883267bc226f86 +dist/2025-10-28/rustc-nightly-powerpc-unknown-linux-gnu.tar.gz=a7cb220770ebd482ff9737d787d04e2e1274c46b7da0809041d06712e27f69ae +dist/2025-10-28/rustc-nightly-powerpc-unknown-linux-gnu.tar.xz=088b1d0898bc5b5d83d0fe20edfdadc2d1c0865c39108d11a5d078074aa37a1f +dist/2025-10-28/rustc-nightly-powerpc64-unknown-linux-gnu.tar.gz=90a3b28ca667187fb18eee8b87f5aebdb2c2e457acbe5b7b088d9b9a39314a1a +dist/2025-10-28/rustc-nightly-powerpc64-unknown-linux-gnu.tar.xz=4eb8f1d20b2eeb85a2b78d3e28a1d665e1171e1271540bdd8453833818d53c30 +dist/2025-10-28/rustc-nightly-powerpc64le-unknown-linux-gnu.tar.gz=e4fc106d7d4e098912b4dc0ac0211769ecc1f01731e118bf6c0bca33c7ceb9f5 +dist/2025-10-28/rustc-nightly-powerpc64le-unknown-linux-gnu.tar.xz=74bf23136731240e8dac7497d8b1a244fc35cd529d12f77fff308099354f3aef +dist/2025-10-28/rustc-nightly-powerpc64le-unknown-linux-musl.tar.gz=85ada50366246530a0dcbd462aef31a6edac600d22074d97bfc07321569eafdf +dist/2025-10-28/rustc-nightly-powerpc64le-unknown-linux-musl.tar.xz=f0cb51df2f6639fc65091608d569b9ac0730f5a8d88e27079d87bc8a8834b1e4 +dist/2025-10-28/rustc-nightly-riscv64gc-unknown-linux-gnu.tar.gz=c37432d8d8db7aaad9132e1301025dd5bf3671bad0ac1fea0f04e9aae238cae3 +dist/2025-10-28/rustc-nightly-riscv64gc-unknown-linux-gnu.tar.xz=57f72896f0309149a4b376a21d56ea28e65316db08065bfe32cdbd750bbc9657 +dist/2025-10-28/rustc-nightly-s390x-unknown-linux-gnu.tar.gz=170776eefa09f01859af0b3694c013ebfab04e9fcf8fb44233593ef4a763bd38 +dist/2025-10-28/rustc-nightly-s390x-unknown-linux-gnu.tar.xz=29335ffe7d88b758ec1a7a067056e35fe8f24430e8d899df3256b4e2d19ac16e +dist/2025-10-28/rustc-nightly-sparcv9-sun-solaris.tar.gz=14b5cfe710c92e8691aaad99de891695ef025638eca065587107c075a31215bf +dist/2025-10-28/rustc-nightly-sparcv9-sun-solaris.tar.xz=d21bb41b4abdaededefd199192bc257424295ec74d482693d032ca67f02dee15 +dist/2025-10-28/rustc-nightly-x86_64-apple-darwin.tar.gz=09c7d0777ea308ad552ea1e958f5c65fa3380c9cb93efa1e6edec3a29fc30b5c +dist/2025-10-28/rustc-nightly-x86_64-apple-darwin.tar.xz=923ef47f5bd9608d277b6636b8c798c5b2760460264fa6f0c0836f317746a89c +dist/2025-10-28/rustc-nightly-x86_64-pc-solaris.tar.gz=805643ab958df449ffd8dd5557e43c5e7060a10a3deab2238096b721ab451f08 +dist/2025-10-28/rustc-nightly-x86_64-pc-solaris.tar.xz=f2fb0c0643808bd9f483bf9bf66ead4444285f2e50bc1264b4861deddfaa9c62 +dist/2025-10-28/rustc-nightly-x86_64-pc-windows-gnu.tar.gz=05b7ee4041b2cdcee1739da7a22e4083acc24c043d11cb3f61d0c22237a9f42a +dist/2025-10-28/rustc-nightly-x86_64-pc-windows-gnu.tar.xz=2f3b04d56dd929ab5997711bc52395fa700247ff38b9362cda375b685c740337 +dist/2025-10-28/rustc-nightly-x86_64-pc-windows-gnullvm.tar.gz=52575038868d91349b40434ec8faf9836a0aa0a4f77c2decc634a9ba02796c07 +dist/2025-10-28/rustc-nightly-x86_64-pc-windows-gnullvm.tar.xz=d2d1f2a0d26cc3dc86d88ae46a9dcaa5f0ce694ebac3f46b7466fb058a1a76e5 +dist/2025-10-28/rustc-nightly-x86_64-pc-windows-msvc.tar.gz=5469701cbe03939a82ce5ec50dc166342ab968d2f96cb372dee8f29dfd6e4362 +dist/2025-10-28/rustc-nightly-x86_64-pc-windows-msvc.tar.xz=e6d18f7b7fa3a3613f1aa129f4a14820d4fa1977550689cd99b7dad12054edab +dist/2025-10-28/rustc-nightly-x86_64-unknown-freebsd.tar.gz=e2a5ff9df2b07f8c939fdb885da717faf19a5b3e63ab780962dc288f832cba6f +dist/2025-10-28/rustc-nightly-x86_64-unknown-freebsd.tar.xz=b577558a8f1b42d6bbbc80804e3b72835a85979c98659696db32832595283d04 +dist/2025-10-28/rustc-nightly-x86_64-unknown-illumos.tar.gz=5535a693d5b8edf3fae7e1da97c20596a1f60135fefe22835109ed3648765a16 +dist/2025-10-28/rustc-nightly-x86_64-unknown-illumos.tar.xz=bfc15f0678099ea110135d4e7bcb1b9a545f041e5810f6528d49e0b5451a29bb +dist/2025-10-28/rustc-nightly-x86_64-unknown-linux-gnu.tar.gz=877bf56730551f851e2ce5279c105f231906959bcf904aa2fc29acaba5160cc5 +dist/2025-10-28/rustc-nightly-x86_64-unknown-linux-gnu.tar.xz=911bf7891d7687675f9200d3bd51946e21df3762b5320b7d31bd49d58526a8a7 +dist/2025-10-28/rustc-nightly-x86_64-unknown-linux-musl.tar.gz=c0c26704d16d6612d0d99ad078bbcb2ac0ed86419a0404a9e08739990acc5ad9 +dist/2025-10-28/rustc-nightly-x86_64-unknown-linux-musl.tar.xz=677f5c6126262b64126b5fc7c3c527cbc9e8ba62aaf4376c924149b6d05e16db +dist/2025-10-28/rustc-nightly-x86_64-unknown-netbsd.tar.gz=84c82523969ff1b987a09d5f7401e9a773b3110f51f00d708a4791ef6615272b +dist/2025-10-28/rustc-nightly-x86_64-unknown-netbsd.tar.xz=680eb70467d5695e986b013b3d16dbd0c0b0b7bc85cf8df4a3392c100f97eff9 +dist/2025-10-28/rust-nightly-aarch64-pc-windows-msvc.msi=a8f7ef71113d5ca8094d9433f23d5bab8ae910803e0cc23110d4fd0e04816bf3 +dist/2025-10-28/rust-nightly-i686-pc-windows-gnu.msi=6c4c49c2c2303f94a39d5c598c4f75b9d2c894b1c30aa6b49c8ab7ca674c8ca9 +dist/2025-10-28/rust-nightly-i686-pc-windows-msvc.msi=f7c80d8c614f5b53a596bfd8a263fc0e680b554ec47630e36e23354afb7fd426 +dist/2025-10-28/rust-nightly-x86_64-pc-windows-gnu.msi=2f830bf3391a7da78de14ba4ffd82de8a49652262fcc7a3ae377a3703fe7ab93 +dist/2025-10-28/rust-nightly-x86_64-pc-windows-msvc.msi=c9b61b50bace832fc504853a5ea5dacd869909946c04d1d9c95b15385e98fd47 +dist/2025-10-28/rust-nightly-aarch64-apple-darwin.pkg=8d7cb75018220eac497ffa180c94b210e2e53e8e8c36ab8a39d6c4c6234fe72b +dist/2025-10-28/rust-nightly-x86_64-apple-darwin.pkg=82e9979fe0cdbac0e008f46cd2d7da70e9fa2caa0d4f1df56654cf57114c993a +dist/2025-10-28/rustc-nightly-src.tar.gz=f6da3a086dd47e5ace7eec9f03879d4c3082503912fe631e54e38168dac60f22 +dist/2025-10-28/rustc-nightly-src.tar.xz=523289ae9e6a87f076decc1beb412897184e728302826882bf53dfde4df4ce15 diff --git a/src/tools/cargo b/src/tools/cargo index 344c4567c634..6c1b61003436 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit 344c4567c634a25837e3c3476aac08af84cf9203 +Subproject commit 6c1b6100343691341b9e76c5acc594e78220f963 diff --git a/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs b/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs index a2da43c2ca24..7e48fe28011a 100644 --- a/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs +++ b/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs @@ -28,6 +28,7 @@ pub(super) fn check<'tcx>( start: Some(start), end: Some(end), limits, + span: _, }) = higher::Range::hir(arg) // the var must be a single name && let PatKind::Binding(_, canonical_id, _, _) = pat.kind diff --git a/src/tools/clippy/clippy_lints/src/loops/manual_slice_fill.rs b/src/tools/clippy/clippy_lints/src/loops/manual_slice_fill.rs index 15c656cc7bc7..94cddb4a1506 100644 --- a/src/tools/clippy/clippy_lints/src/loops/manual_slice_fill.rs +++ b/src/tools/clippy/clippy_lints/src/loops/manual_slice_fill.rs @@ -31,6 +31,7 @@ pub(super) fn check<'tcx>( start: Some(start), end: Some(end), limits: RangeLimits::HalfOpen, + span: _, }) = higher::Range::hir(arg) && let ExprKind::Lit(Spanned { node: LitKind::Int(Pu128(0), _), diff --git a/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs b/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs index 11edb929d70b..7d890621d47c 100644 --- a/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs +++ b/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs @@ -30,6 +30,7 @@ pub(super) fn check<'tcx>( start: Some(start), ref end, limits, + span, }) = higher::Range::hir(arg) // the var must be a single name && let PatKind::Binding(_, canonical_id, ident, _) = pat.kind @@ -149,7 +150,7 @@ pub(super) fn check<'tcx>( span_lint_and_then( cx, NEEDLESS_RANGE_LOOP, - arg.span, + span, format!("the loop variable `{}` is used to index `{indexed}`", ident.name), |diag| { diag.multipart_suggestion( @@ -157,7 +158,7 @@ pub(super) fn check<'tcx>( vec![ (pat.span, format!("({}, )", ident.name)), ( - arg.span, + span, format!("{indexed}.{method}().enumerate(){method_1}{method_2}"), ), ], @@ -175,12 +176,12 @@ pub(super) fn check<'tcx>( span_lint_and_then( cx, NEEDLESS_RANGE_LOOP, - arg.span, + span, format!("the loop variable `{}` is only used to index `{indexed}`", ident.name), |diag| { diag.multipart_suggestion( "consider using an iterator", - vec![(pat.span, "".to_string()), (arg.span, repl)], + vec![(pat.span, "".to_string()), (span, repl)], Applicability::HasPlaceholders, ); }, diff --git a/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs b/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs index 8c6abbeac448..456b48808090 100644 --- a/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs +++ b/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs @@ -110,6 +110,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualIsAsciiCheck { start: Some(start), end: Some(end), limits: RangeLimits::Closed, + span: _, }) = higher::Range::hir(receiver) && !matches!(cx.typeck_results().expr_ty(arg).peel_refs().kind(), ty::Param(_)) { diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_next_slice.rs b/src/tools/clippy/clippy_lints/src/methods/iter_next_slice.rs index 01f35ff02d44..f37b15371c25 100644 --- a/src/tools/clippy/clippy_lints/src/methods/iter_next_slice.rs +++ b/src/tools/clippy/clippy_lints/src/methods/iter_next_slice.rs @@ -30,6 +30,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, cal start: Some(start_expr), end: None, limits: ast::RangeLimits::HalfOpen, + span: _, }) = higher::Range::hir(index_expr) && let hir::ExprKind::Lit(start_lit) = &start_expr.kind && let ast::LitKind::Int(start_idx, _) = start_lit.node diff --git a/src/tools/clippy/clippy_lints/src/methods/map_with_unused_argument_over_ranges.rs b/src/tools/clippy/clippy_lints/src/methods/map_with_unused_argument_over_ranges.rs index a2a522a60687..38ca15cb1334 100644 --- a/src/tools/clippy/clippy_lints/src/methods/map_with_unused_argument_over_ranges.rs +++ b/src/tools/clippy/clippy_lints/src/methods/map_with_unused_argument_over_ranges.rs @@ -63,7 +63,7 @@ pub(super) fn check( receiver: &Expr<'_>, arg: &Expr<'_>, msrv: Msrv, - method_call_span: Span, + method_name_span: Span, ) { let mut applicability = Applicability::MaybeIncorrect; if let Some(range) = higher::Range::hir(receiver) @@ -105,7 +105,7 @@ pub(super) fn check( // collate all our parts here and then remove those that are empty. let mut parts = vec![ ( - receiver.span.to(method_call_span), + ex.span.with_hi(method_name_span.hi()), format!("{exec_context}::iter::{method_to_use_name}"), ), new_span, diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs index c9066be51c44..48fa5f7bdc6e 100644 --- a/src/tools/clippy/clippy_lints/src/methods/mod.rs +++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs @@ -4854,8 +4854,8 @@ impl_lint_pass!(Methods => [ /// come from expansion. pub fn method_call<'tcx>(recv: &'tcx Expr<'tcx>) -> Option<(Symbol, &'tcx Expr<'tcx>, &'tcx [Expr<'tcx>], Span, Span)> { if let ExprKind::MethodCall(path, receiver, args, call_span) = recv.kind - && !args.iter().any(|e| e.span.from_expansion()) - && !receiver.span.from_expansion() + && !args.iter().any(|e| e.range_span().unwrap_or(e.span).from_expansion()) + && !receiver.range_span().unwrap_or(receiver.span).from_expansion() { Some((path.ident.name, receiver, args, path.ident.span, call_span)) } else { diff --git a/src/tools/clippy/clippy_lints/src/no_effect.rs b/src/tools/clippy/clippy_lints/src/no_effect.rs index 701923cf6efc..fdb8e1b475c1 100644 --- a/src/tools/clippy/clippy_lints/src/no_effect.rs +++ b/src/tools/clippy/clippy_lints/src/no_effect.rs @@ -122,7 +122,7 @@ impl NoEffect { return true; } - if expr.span.from_expansion() { + if expr.range_span().unwrap_or(expr.span).from_expansion() { return false; } let expr = peel_blocks(expr); @@ -273,7 +273,7 @@ fn check_unnecessary_operation(cx: &LateContext<'_>, stmt: &Stmt<'_>) { if let StmtKind::Semi(expr) = stmt.kind && !stmt.span.in_external_macro(cx.sess().source_map()) && let ctxt = stmt.span.ctxt() - && expr.span.ctxt() == ctxt + && expr.range_span().unwrap_or(expr.span).ctxt() == ctxt && let Some(reduced) = reduce_expression(cx, expr) && reduced.iter().all(|e| e.span.ctxt() == ctxt) { @@ -330,7 +330,7 @@ fn check_unnecessary_operation(cx: &LateContext<'_>, stmt: &Stmt<'_>) { } fn reduce_expression<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option>> { - if expr.span.from_expansion() { + if expr.range_span().unwrap_or(expr.span).from_expansion() { return None; } match expr.kind { diff --git a/src/tools/clippy/clippy_lints/src/ranges.rs b/src/tools/clippy/clippy_lints/src/ranges.rs index e4c91b7efd2b..ac2cc11d3020 100644 --- a/src/tools/clippy/clippy_lints/src/ranges.rs +++ b/src/tools/clippy/clippy_lints/src/ranges.rs @@ -501,17 +501,18 @@ fn check_range_switch<'tcx>( msg: &'static str, operator: &str, ) { - if expr.span.can_be_used_for_suggestions() - && let Some(higher::Range { + if let Some(range) = higher::Range::hir(expr) + && let higher::Range { start, end: Some(end), limits, - }) = higher::Range::hir(expr) + span, + } = range + && span.can_be_used_for_suggestions() && limits == kind && let Some(y) = predicate(cx, end) && can_switch_ranges(cx, expr, kind, cx.typeck_results().expr_ty(y)) { - let span = expr.span; span_lint_and_then(cx, lint, span, msg, |diag| { let mut app = Applicability::MachineApplicable; let start = start.map_or(String::new(), |x| { @@ -567,6 +568,7 @@ fn check_reversed_empty_range(cx: &LateContext<'_>, expr: &Expr<'_>) { start: Some(start), end: Some(end), limits, + span, }) = higher::Range::hir(expr) && let ty = cx.typeck_results().expr_ty(start) && let ty::Int(_) | ty::Uint(_) = ty.kind() @@ -582,7 +584,7 @@ fn check_reversed_empty_range(cx: &LateContext<'_>, expr: &Expr<'_>) { span_lint( cx, REVERSED_EMPTY_RANGES, - expr.span, + span, "this range is reversed and using it to index a slice will panic at run-time", ); } @@ -591,7 +593,7 @@ fn check_reversed_empty_range(cx: &LateContext<'_>, expr: &Expr<'_>) { span_lint_and_then( cx, REVERSED_EMPTY_RANGES, - expr.span, + span, "this range is empty so it will yield no values", |diag| { if ordering != Ordering::Equal { @@ -603,7 +605,7 @@ fn check_reversed_empty_range(cx: &LateContext<'_>, expr: &Expr<'_>) { }; diag.span_suggestion( - expr.span, + span, "consider using the following if you are attempting to iterate over this \ range in reverse", format!("({end_snippet}{dots}{start_snippet}).rev()"), diff --git a/src/tools/clippy/clippy_lints/src/shadow.rs b/src/tools/clippy/clippy_lints/src/shadow.rs index 7fdea6bec510..f6083394fea5 100644 --- a/src/tools/clippy/clippy_lints/src/shadow.rs +++ b/src/tools/clippy/clippy_lints/src/shadow.rs @@ -133,7 +133,7 @@ impl<'tcx> LateLintPass<'tcx> for Shadow { .tcx .hir_parent_iter(pat.hir_id) .find(|(_, node)| !matches!(node, Node::Pat(_) | Node::PatField(_))) - && let LocalSource::AssignDesugar(_) = let_stmt.source + && let LocalSource::AssignDesugar = let_stmt.source { return; } diff --git a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs index 9afa9d65c261..9935dc309611 100644 --- a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs +++ b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs @@ -374,7 +374,7 @@ fn expr_has_unnecessary_safety_comment<'tcx>( hir::Stmt { kind: hir::StmtKind::Let(hir::LetStmt { - source: hir::LocalSource::AssignDesugar(_), + source: hir::LocalSource::AssignDesugar, .. }), .. diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_struct_initialization.rs b/src/tools/clippy/clippy_lints/src/unnecessary_struct_initialization.rs index 51596859e4c7..51397accefea 100644 --- a/src/tools/clippy/clippy_lints/src/unnecessary_struct_initialization.rs +++ b/src/tools/clippy/clippy_lints/src/unnecessary_struct_initialization.rs @@ -6,6 +6,7 @@ use clippy_utils::{get_parent_expr, is_mutable}; use rustc_hir::{Expr, ExprField, ExprKind, Path, QPath, StructTailExpr, UnOp}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; +use rustc_span::{DesugaringKind, Ident}; declare_clippy_lint! { /// ### What it does @@ -52,7 +53,8 @@ impl LateLintPass<'_> for UnnecessaryStruct { return; }; - if expr.span.from_expansion() { + let expr_span = expr.range_span().unwrap_or(expr.span); + if expr_span.from_expansion() { // Prevent lint from hitting inside macro code return; } @@ -80,7 +82,7 @@ impl LateLintPass<'_> for UnnecessaryStruct { span_lint_and_sugg( cx, UNNECESSARY_STRUCT_INITIALIZATION, - expr.span, + expr_span, "unnecessary struct building", "replace with", snippet(cx, sugg, "..").into_owned(), @@ -130,7 +132,7 @@ fn same_path_in_all_fields<'tcx>( // expression type matches && ty == cx.typeck_results().expr_ty(src_expr) // field name matches - && f.ident == ident + && ident_without_range_desugaring(f.ident) == ident // assigned from a path expression && let ExprKind::Path(QPath::Resolved(None, src_path)) = src_expr.kind { @@ -197,3 +199,14 @@ fn path_matches_base(path: &Path<'_>, base: &Expr<'_>) -> bool { }; path.res == base_path.res } + +fn ident_without_range_desugaring(ident: Ident) -> Ident { + if ident.span.desugaring_kind() == Some(DesugaringKind::RangeExpr) { + Ident { + span: ident.span.parent_callsite().unwrap(), + ..ident + } + } else { + ident + } +} diff --git a/src/tools/clippy/clippy_utils/src/higher.rs b/src/tools/clippy/clippy_utils/src/higher.rs index 3383e66fe368..9d895c9aa649 100644 --- a/src/tools/clippy/clippy_utils/src/higher.rs +++ b/src/tools/clippy/clippy_utils/src/higher.rs @@ -209,12 +209,14 @@ pub struct Range<'a> { pub end: Option<&'a Expr<'a>>, /// Whether the interval is open or closed. pub limits: ast::RangeLimits, + pub span: Span } impl<'a> Range<'a> { /// Higher a `hir` range to something similar to `ast::ExprKind::Range`. #[expect(clippy::similar_names)] pub fn hir(expr: &'a Expr<'_>) -> Option> { + let span = expr.range_span()?; match expr.kind { ExprKind::Call(path, [arg1, arg2]) if matches!( @@ -226,6 +228,7 @@ impl<'a> Range<'a> { start: Some(arg1), end: Some(arg2), limits: ast::RangeLimits::Closed, + span, }) }, ExprKind::Struct(path, fields, StructTailExpr::None) => match (path, fields) { @@ -233,12 +236,14 @@ impl<'a> Range<'a> { start: None, end: None, limits: ast::RangeLimits::HalfOpen, + span, }), (QPath::LangItem(hir::LangItem::RangeFrom, ..), [field]) if field.ident.name == sym::start => { Some(Range { start: Some(field.expr), end: None, limits: ast::RangeLimits::HalfOpen, + span, }) }, (QPath::LangItem(hir::LangItem::Range, ..), [field1, field2]) => { @@ -251,6 +256,7 @@ impl<'a> Range<'a> { start: Some(start), end: Some(end), limits: ast::RangeLimits::HalfOpen, + span, }) }, (QPath::LangItem(hir::LangItem::RangeToInclusive, ..), [field]) if field.ident.name == sym::end => { @@ -258,12 +264,14 @@ impl<'a> Range<'a> { start: None, end: Some(field.expr), limits: ast::RangeLimits::Closed, + span, }) }, (QPath::LangItem(hir::LangItem::RangeTo, ..), [field]) if field.ident.name == sym::end => Some(Range { start: None, end: Some(field.expr), limits: ast::RangeLimits::HalfOpen, + span, }), _ => None, }, diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index c8943523e179..6ee991eae137 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -1282,7 +1282,7 @@ pub fn is_else_clause_in_let_else(tcx: TyCtxt<'_>, expr: &Expr<'_>) -> bool { /// If the given `Expr` is not some kind of range, the function returns `false`. pub fn is_range_full(cx: &LateContext<'_>, expr: &Expr<'_>, container_path: Option<&Path<'_>>) -> bool { let ty = cx.typeck_results().expr_ty(expr); - if let Some(Range { start, end, limits }) = Range::hir(expr) { + if let Some(Range { start, end, limits, .. }) = Range::hir(expr) { let start_is_none_or_min = start.is_none_or(|start| { if let rustc_ty::Adt(_, subst) = ty.kind() && let bnd_ty = subst.type_at(0) diff --git a/src/tools/clippy/clippy_utils/src/source.rs b/src/tools/clippy/clippy_utils/src/source.rs index 83d7f6bc565d..954a71f6c320 100644 --- a/src/tools/clippy/clippy_utils/src/source.rs +++ b/src/tools/clippy/clippy_utils/src/source.rs @@ -13,8 +13,8 @@ use rustc_middle::ty::TyCtxt; use rustc_session::Session; use rustc_span::source_map::{SourceMap, original_sp}; use rustc_span::{ - BytePos, DUMMY_SP, FileNameDisplayPreference, Pos, RelativeBytePos, SourceFile, SourceFileAndLine, Span, SpanData, - SyntaxContext, hygiene, + BytePos, DesugaringKind, DUMMY_SP, FileNameDisplayPreference, Pos, RelativeBytePos, SourceFile, SourceFileAndLine, + Span, SpanData, SyntaxContext, hygiene, }; use std::borrow::Cow; use std::fmt; @@ -670,6 +670,14 @@ fn snippet_with_context_sess<'a>( default: &'a str, applicability: &mut Applicability, ) -> (Cow<'a, str>, bool) { + // If it is just range desugaring, use the desugaring span since it may include parenthesis. + if span.desugaring_kind() == Some(DesugaringKind::RangeExpr) && span.parent_callsite().unwrap().ctxt() == outer { + return ( + snippet_with_applicability_sess(sess, span, default, applicability), + false, + ) + } + let (span, is_macro_call) = walk_span_to_context(span, outer).map_or_else( || { // The span is from a macro argument, and the outer context is the macro using the argument diff --git a/src/tools/clippy/tests/ui/range_plus_minus_one.stderr b/src/tools/clippy/tests/ui/range_plus_minus_one.stderr index a419d935bd62..60abe50efa10 100644 --- a/src/tools/clippy/tests/ui/range_plus_minus_one.stderr +++ b/src/tools/clippy/tests/ui/range_plus_minus_one.stderr @@ -32,22 +32,22 @@ LL | for _ in 1..ONE + ONE {} | ^^^^^^^^^^^^ help: use: `1..=ONE` error: an inclusive range would be more readable - --> tests/ui/range_plus_minus_one.rs:70:5 + --> tests/ui/range_plus_minus_one.rs:70:6 | LL | (1..10 + 1).for_each(|_| {}); - | ^^^^^^^^^^^ help: use: `(1..=10)` + | ^^^^^^^^^ help: use: `1..=10` error: an inclusive range would be more readable - --> tests/ui/range_plus_minus_one.rs:75:5 + --> tests/ui/range_plus_minus_one.rs:75:6 | LL | (1..10 + 1).into_iter().for_each(|_| {}); - | ^^^^^^^^^^^ help: use: `(1..=10)` + | ^^^^^^^^^ help: use: `1..=10` error: an inclusive range would be more readable - --> tests/ui/range_plus_minus_one.rs:80:17 + --> tests/ui/range_plus_minus_one.rs:80:18 | LL | let _ = (1..10 + 1).start_bound(); - | ^^^^^^^^^^^ help: use: `(1..=10)` + | ^^^^^^^^^ help: use: `1..=10` error: an inclusive range would be more readable --> tests/ui/range_plus_minus_one.rs:86:16 @@ -80,10 +80,10 @@ LL | a[0..2 + 1][0] = 1; | ^^^^^^^^ help: use: `0..=2` error: an exclusive range would be more readable - --> tests/ui/range_plus_minus_one.rs:180:5 + --> tests/ui/range_plus_minus_one.rs:180:6 | LL | (1..=n - 1).sum() - | ^^^^^^^^^^^ help: use: `(1..n)` + | ^^^^^^^^^ help: use: `1..n` | = note: `-D clippy::range-minus-one` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::range_minus_one)]` diff --git a/src/tools/clippy/tests/ui/reversed_empty_ranges_fixable.fixed b/src/tools/clippy/tests/ui/reversed_empty_ranges_fixable.fixed index ba5059bbaa37..6c866aceed4f 100644 --- a/src/tools/clippy/tests/ui/reversed_empty_ranges_fixable.fixed +++ b/src/tools/clippy/tests/ui/reversed_empty_ranges_fixable.fixed @@ -6,9 +6,9 @@ const ANSWER: i32 = 42; fn main() { // These should be linted: - (21..=42).rev().for_each(|x| println!("{}", x)); + ((21..=42).rev()).for_each(|x| println!("{}", x)); //~^ reversed_empty_ranges - let _ = (21..ANSWER).rev().filter(|x| x % 2 == 0).take(10).collect::>(); + let _ = ((21..ANSWER).rev()).filter(|x| x % 2 == 0).take(10).collect::>(); //~^ reversed_empty_ranges for _ in (-42..=-21).rev() {} diff --git a/src/tools/clippy/tests/ui/reversed_empty_ranges_fixable.stderr b/src/tools/clippy/tests/ui/reversed_empty_ranges_fixable.stderr index 3fadc4c169f1..f3d3ac298cec 100644 --- a/src/tools/clippy/tests/ui/reversed_empty_ranges_fixable.stderr +++ b/src/tools/clippy/tests/ui/reversed_empty_ranges_fixable.stderr @@ -1,27 +1,27 @@ error: this range is empty so it will yield no values - --> tests/ui/reversed_empty_ranges_fixable.rs:9:5 + --> tests/ui/reversed_empty_ranges_fixable.rs:9:6 | LL | (42..=21).for_each(|x| println!("{}", x)); - | ^^^^^^^^^ + | ^^^^^^^ | = note: `-D clippy::reversed-empty-ranges` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::reversed_empty_ranges)]` help: consider using the following if you are attempting to iterate over this range in reverse | LL - (42..=21).for_each(|x| println!("{}", x)); -LL + (21..=42).rev().for_each(|x| println!("{}", x)); +LL + ((21..=42).rev()).for_each(|x| println!("{}", x)); | error: this range is empty so it will yield no values - --> tests/ui/reversed_empty_ranges_fixable.rs:11:13 + --> tests/ui/reversed_empty_ranges_fixable.rs:11:14 | LL | let _ = (ANSWER..21).filter(|x| x % 2 == 0).take(10).collect::>(); - | ^^^^^^^^^^^^ + | ^^^^^^^^^^ | help: consider using the following if you are attempting to iterate over this range in reverse | LL - let _ = (ANSWER..21).filter(|x| x % 2 == 0).take(10).collect::>(); -LL + let _ = (21..ANSWER).rev().filter(|x| x % 2 == 0).take(10).collect::>(); +LL + let _ = ((21..ANSWER).rev()).filter(|x| x % 2 == 0).take(10).collect::>(); | error: this range is empty so it will yield no values diff --git a/src/tools/clippy/tests/ui/reversed_empty_ranges_loops_fixable.fixed b/src/tools/clippy/tests/ui/reversed_empty_ranges_loops_fixable.fixed index 55080da8a137..9fb46c9533cd 100644 --- a/src/tools/clippy/tests/ui/reversed_empty_ranges_loops_fixable.fixed +++ b/src/tools/clippy/tests/ui/reversed_empty_ranges_loops_fixable.fixed @@ -34,7 +34,7 @@ fn main() { println!("{}", i); } - for i in (0..10).rev().map(|x| x * 2) { + for i in ((0..10).rev()).map(|x| x * 2) { //~^ reversed_empty_ranges println!("{}", i); } diff --git a/src/tools/clippy/tests/ui/reversed_empty_ranges_loops_fixable.stderr b/src/tools/clippy/tests/ui/reversed_empty_ranges_loops_fixable.stderr index eadd9d3675e1..775d109296a1 100644 --- a/src/tools/clippy/tests/ui/reversed_empty_ranges_loops_fixable.stderr +++ b/src/tools/clippy/tests/ui/reversed_empty_ranges_loops_fixable.stderr @@ -37,15 +37,15 @@ LL + for i in (0..MAX_LEN).rev() { | error: this range is empty so it will yield no values - --> tests/ui/reversed_empty_ranges_loops_fixable.rs:37:14 + --> tests/ui/reversed_empty_ranges_loops_fixable.rs:37:15 | LL | for i in (10..0).map(|x| x * 2) { - | ^^^^^^^ + | ^^^^^ | help: consider using the following if you are attempting to iterate over this range in reverse | LL - for i in (10..0).map(|x| x * 2) { -LL + for i in (0..10).rev().map(|x| x * 2) { +LL + for i in ((0..10).rev()).map(|x| x * 2) { | error: this range is empty so it will yield no values diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index 0a2f4340bbea..8e47d51ee4db 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -248,6 +248,9 @@ pub struct Config { /// Path to libraries needed to run the *staged* `rustc`-under-test on the **host** platform. /// + /// For example: + /// - `/home/ferris/rust/build/x86_64-unknown-linux-gnu/stage1/bin/lib` + /// /// FIXME: maybe rename this to reflect (1) which target platform (host, not target), and (2) /// which `rustc` (the `rustc`-under-test, not the stage 0 `rustc` unless forced). pub compile_lib_path: Utf8PathBuf, @@ -255,6 +258,9 @@ pub struct Config { /// Path to libraries needed to run the compiled executable for the **target** platform. This /// corresponds to the **target** sysroot libraries, including the **target** standard library. /// + /// For example: + /// - `/home/ferris/rust/build/x86_64-unknown-linux-gnu/stage1/lib/rustlib/i686-unknown-linux-gnu/lib` + /// /// FIXME: maybe rename this to reflect (1) which target platform (target, not host), and (2) /// what "run libraries" are against. /// @@ -266,6 +272,9 @@ pub struct Config { /// Path to the *staged* `rustc`-under-test. Unless forced, this `rustc` is *staged*, and must /// not be confused with [`Self::stage0_rustc_path`]. /// + /// For example: + /// - `/home/ferris/rust/build/x86_64-unknown-linux-gnu/stage1/bin/rustc` + /// /// FIXME: maybe rename this to reflect that this is the `rustc`-under-test. pub rustc_path: Utf8PathBuf, @@ -274,11 +283,17 @@ pub struct Config { /// *not* used to compile the test recipes), and so must be staged as there may be differences /// between e.g. beta `cargo` vs in-tree `cargo`. /// + /// For example: + /// - `/home/ferris/rust/build/x86_64-unknown-linux-gnu/stage1-tools-bin/cargo` + /// /// FIXME: maybe rename this to reflect that this is a *staged* host cargo. pub cargo_path: Option, /// Path to the stage 0 `rustc` used to build `run-make` recipes. This must not be confused with /// [`Self::rustc_path`]. + /// + /// For example: + /// - `/home/ferris/rust/build/x86_64-unknown-linux-gnu/stage0/bin/rustc` pub stage0_rustc_path: Option, /// Path to the stage 1 or higher `rustc` used to obtain target information via @@ -312,6 +327,9 @@ pub struct Config { pub llvm_filecheck: Option, /// Path to a host LLVM bintools directory. + /// + /// For example: + /// - `/home/ferris/rust/build/x86_64-unknown-linux-gnu/llvm/bin` pub llvm_bin_dir: Option, /// The path to the **target** `clang` executable to run `clang`-based tests with. If `None`, @@ -321,28 +339,39 @@ pub struct Config { /// Path to the directory containing the sources. This corresponds to the root folder of a /// `rust-lang/rust` checkout. /// + /// For example: + /// - `/home/ferris/rust` + /// /// FIXME: this name is confusing, because this is actually `$checkout_root`, **not** the /// `$checkout_root/src/` folder. pub src_root: Utf8PathBuf, - /// Path to the directory containing the test suites sources. This corresponds to the - /// `$src_root/tests/` folder. + /// Absolute path to the test suite directory. /// - /// Must be an immediate subdirectory of [`Self::src_root`]. - /// - /// FIXME: this name is also confusing, maybe just call it `tests_root`. + /// For example: + /// - `/home/ferris/rust/tests/ui` + /// - `/home/ferris/rust/tests/coverage` pub src_test_suite_root: Utf8PathBuf, - /// Path to the build directory (e.g. `build/`). + /// Path to the top-level build directory used by bootstrap. + /// + /// For example: + /// - `/home/ferris/rust/build` pub build_root: Utf8PathBuf, - /// Path to the test suite specific build directory (e.g. `build/host/test/ui/`). + /// Path to the build directory used by the current test suite. /// - /// Must be a subdirectory of [`Self::build_root`]. + /// For example: + /// - `/home/ferris/rust/build/x86_64-unknown-linux-gnu/test/ui` + /// - `/home/ferris/rust/build/x86_64-unknown-linux-gnu/test/coverage` pub build_test_suite_root: Utf8PathBuf, /// Path to the directory containing the sysroot of the `rustc`-under-test. /// + /// For example: + /// - `/home/ferris/rust/build/x86_64-unknown-linux-gnu/stage1` + /// - `/home/ferris/rust/build/x86_64-unknown-linux-gnu/stage2` + /// /// When stage 0 is forced, this will correspond to the sysroot *of* that specified stage 0 /// `rustc`. /// @@ -1075,10 +1104,31 @@ fn query_rustc_output(config: &Config, args: &[&str], envs: HashMap ShouldPanic::No, - _ if should_fail => ShouldPanic::Yes, - _ => ShouldPanic::No, + let should_fail = if should_fail && config.mode != TestMode::Pretty { + ShouldFail::Yes + } else { + ShouldFail::No }; CollectedTestDesc { @@ -1377,7 +1377,7 @@ pub(crate) fn make_test_description( filterable_path: filterable_path.to_owned(), ignore, ignore_message, - should_panic, + should_fail, } } diff --git a/src/tools/compiletest/src/directives/tests.rs b/src/tools/compiletest/src/directives/tests.rs index 98249e69601b..0bf2bcd3af43 100644 --- a/src/tools/compiletest/src/directives/tests.rs +++ b/src/tools/compiletest/src/directives/tests.rs @@ -7,7 +7,7 @@ use crate::directives::{ extract_llvm_version, extract_version_range, iter_directives, line_directive, parse_edition, parse_normalize_rule, }; -use crate::executor::{CollectedTestDesc, ShouldPanic}; +use crate::executor::{CollectedTestDesc, ShouldFail}; fn make_test_description( config: &Config, @@ -247,9 +247,9 @@ fn should_fail() { let p = Utf8Path::new("a.rs"); let d = make_test_description(&config, tn.clone(), p, p, "", None); - assert_eq!(d.should_panic, ShouldPanic::No); + assert_eq!(d.should_fail, ShouldFail::No); let d = make_test_description(&config, tn, p, p, "//@ should-fail", None); - assert_eq!(d.should_panic, ShouldPanic::Yes); + assert_eq!(d.should_fail, ShouldFail::Yes); } #[test] diff --git a/src/tools/compiletest/src/executor.rs b/src/tools/compiletest/src/executor.rs index c7aca6d1c5aa..5a2136c55b05 100644 --- a/src/tools/compiletest/src/executor.rs +++ b/src/tools/compiletest/src/executor.rs @@ -98,32 +98,43 @@ pub(crate) fn run_tests(config: &Config, tests: Vec) -> bool { fn spawn_test_thread( id: TestId, test: &CollectedTest, - completion_tx: mpsc::Sender, + completion_sender: mpsc::Sender, ) -> Option> { if test.desc.ignore && !test.config.run_ignored { - completion_tx + completion_sender .send(TestCompletion { id, outcome: TestOutcome::Ignored, stdout: None }) .unwrap(); return None; } - let runnable_test = RunnableTest::new(test); - let should_panic = test.desc.should_panic; - let run_test = move || run_test_inner(id, should_panic, runnable_test, completion_tx); - + let args = TestThreadArgs { + id, + config: Arc::clone(&test.config), + testpaths: test.testpaths.clone(), + revision: test.revision.clone(), + should_fail: test.desc.should_fail, + completion_sender, + }; let thread_builder = thread::Builder::new().name(test.desc.name.clone()); - let join_handle = thread_builder.spawn(run_test).unwrap(); + let join_handle = thread_builder.spawn(move || test_thread_main(args)).unwrap(); Some(join_handle) } -/// Runs a single test, within the dedicated thread spawned by the caller. -fn run_test_inner( +/// All of the owned data needed by `test_thread_main`. +struct TestThreadArgs { id: TestId, - should_panic: ShouldPanic, - runnable_test: RunnableTest, + + config: Arc, + testpaths: TestPaths, + revision: Option, + should_fail: ShouldFail, + completion_sender: mpsc::Sender, -) { - let capture = CaptureKind::for_config(&runnable_test.config); +} + +/// Runs a single test, within the dedicated thread spawned by the caller. +fn test_thread_main(args: TestThreadArgs) { + let capture = CaptureKind::for_config(&args.config); // Install a panic-capture buffer for use by the custom panic hook. if capture.should_set_panic_hook() { @@ -133,7 +144,24 @@ fn run_test_inner( let stdout = capture.stdout(); let stderr = capture.stderr(); - let panic_payload = panic::catch_unwind(move || runnable_test.run(stdout, stderr)).err(); + // Run the test, catching any panics so that we can gracefully report + // failure (or success). + // + // FIXME(Zalathar): Ideally we would report test failures with `Result`, + // and use panics only for bugs within compiletest itself, but that would + // require a major overhaul of error handling in the test runners. + let panic_payload = panic::catch_unwind(|| { + __rust_begin_short_backtrace(|| { + crate::runtest::run( + &args.config, + stdout, + stderr, + &args.testpaths, + args.revision.as_deref(), + ); + }); + }) + .err(); if let Some(panic_buf) = panic_hook::take_capture_buf() { let panic_buf = panic_buf.lock().unwrap_or_else(|e| e.into_inner()); @@ -141,16 +169,17 @@ fn run_test_inner( write!(stderr, "{panic_buf}"); } - let outcome = match (should_panic, panic_payload) { - (ShouldPanic::No, None) | (ShouldPanic::Yes, Some(_)) => TestOutcome::Succeeded, - (ShouldPanic::No, Some(_)) => TestOutcome::Failed { message: None }, - (ShouldPanic::Yes, None) => { - TestOutcome::Failed { message: Some("test did not panic as expected") } + // Interpret the presence/absence of a panic as test failure/success. + let outcome = match (args.should_fail, panic_payload) { + (ShouldFail::No, None) | (ShouldFail::Yes, Some(_)) => TestOutcome::Succeeded, + (ShouldFail::No, Some(_)) => TestOutcome::Failed { message: None }, + (ShouldFail::Yes, None) => { + TestOutcome::Failed { message: Some("`//@ should-fail` test did not fail as expected") } } }; let stdout = capture.into_inner(); - completion_sender.send(TestCompletion { id, outcome, stdout }).unwrap(); + args.completion_sender.send(TestCompletion { id: args.id, outcome, stdout }).unwrap(); } enum CaptureKind { @@ -207,33 +236,6 @@ impl CaptureKind { #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] struct TestId(usize); -struct RunnableTest { - config: Arc, - testpaths: TestPaths, - revision: Option, -} - -impl RunnableTest { - fn new(test: &CollectedTest) -> Self { - let config = Arc::clone(&test.config); - let testpaths = test.testpaths.clone(); - let revision = test.revision.clone(); - Self { config, testpaths, revision } - } - - fn run(&self, stdout: &dyn ConsoleOut, stderr: &dyn ConsoleOut) { - __rust_begin_short_backtrace(|| { - crate::runtest::run( - Arc::clone(&self.config), - stdout, - stderr, - &self.testpaths, - self.revision.as_deref(), - ); - }); - } -} - /// Fixed frame used to clean the backtrace with `RUST_BACKTRACE=1`. #[inline(never)] fn __rust_begin_short_backtrace T>(f: F) -> T { @@ -336,7 +338,7 @@ pub(crate) struct CollectedTestDesc { pub(crate) filterable_path: Utf8PathBuf, pub(crate) ignore: bool, pub(crate) ignore_message: Option>, - pub(crate) should_panic: ShouldPanic, + pub(crate) should_fail: ShouldFail, } /// Whether console output should be colored or not. @@ -348,9 +350,10 @@ pub enum ColorConfig { NeverColor, } -/// Whether test is expected to panic or not. +/// Tests with `//@ should-fail` are tests of compiletest itself, and should +/// be reported as successful if and only if they would have _failed_. #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] -pub(crate) enum ShouldPanic { +pub(crate) enum ShouldFail { No, Yes, } diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index ff275df9b31c..b82a533271c1 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -6,7 +6,6 @@ use std::hash::{DefaultHasher, Hash, Hasher}; use std::io::prelude::*; use std::io::{self, BufReader}; use std::process::{Child, Command, ExitStatus, Output, Stdio}; -use std::sync::Arc; use std::{env, fmt, iter, str}; use build_helper::fs::remove_and_create_dir_all; @@ -110,7 +109,7 @@ fn dylib_name(name: &str) -> String { } pub fn run( - config: Arc, + config: &Config, stdout: &dyn ConsoleOut, stderr: &dyn ConsoleOut, testpaths: &TestPaths, @@ -1000,8 +999,15 @@ impl<'test> TestCx<'test> { /// `root_out_dir` and `root_testpaths` refer to the parameters of the actual test being run. /// Auxiliaries, no matter how deep, have the same root_out_dir and root_testpaths. - fn document(&self, root_out_dir: &Utf8Path, root_testpaths: &TestPaths) -> ProcRes { + fn document( + &self, + root_out_dir: &Utf8Path, + root_testpaths: &TestPaths, + kind: DocKind, + ) -> ProcRes { if self.props.build_aux_docs { + assert_eq!(kind, DocKind::Html, "build-aux-docs only make sense for html output"); + for rel_ab in &self.props.aux.builds { let aux_testpaths = self.compute_aux_test_paths(root_testpaths, rel_ab); let props_for_aux = @@ -1018,7 +1024,7 @@ impl<'test> TestCx<'test> { create_dir_all(aux_cx.output_base_dir()).unwrap(); // use root_testpaths here, because aux-builds should have the // same --out-dir and auxiliary directory. - let auxres = aux_cx.document(&root_out_dir, root_testpaths); + let auxres = aux_cx.document(&root_out_dir, root_testpaths, kind); if !auxres.status.success() { return auxres; } @@ -1063,8 +1069,11 @@ impl<'test> TestCx<'test> { .args(&self.props.compile_flags) .args(&self.props.doc_flags); - if self.config.mode == TestMode::RustdocJson { - rustdoc.arg("--output-format").arg("json").arg("-Zunstable-options"); + match kind { + DocKind::Html => {} + DocKind::Json => { + rustdoc.arg("--output-format").arg("json").arg("-Zunstable-options"); + } } if let Some(ref linker) = self.config.target_linker { @@ -2203,7 +2212,7 @@ impl<'test> TestCx<'test> { let aux_dir = new_rustdoc.aux_output_dir(); new_rustdoc.build_all_auxiliary(&new_rustdoc.testpaths, &aux_dir, &mut rustc); - let proc_res = new_rustdoc.document(&compare_dir, &new_rustdoc.testpaths); + let proc_res = new_rustdoc.document(&compare_dir, &new_rustdoc.testpaths, DocKind::Html); if !proc_res.status.success() { writeln!(self.stderr, "failed to run nightly rustdoc"); return; @@ -2997,7 +3006,7 @@ impl<'test> TestCx<'test> { self.delete_file(&examined_path); } // If we want them to be the same, but they are different, then error. - // We do this wether we bless or not + // We do this whether we bless or not (_, true, false) => { self.fatal_proc_rec( &format!("`{}` should not have different output from base test!", kind), @@ -3121,6 +3130,12 @@ enum CompareOutcome { Differed, } +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +enum DocKind { + Html, + Json, +} + impl CompareOutcome { fn should_error(&self) -> bool { matches!(self, CompareOutcome::Differed) diff --git a/src/tools/compiletest/src/runtest/js_doc.rs b/src/tools/compiletest/src/runtest/js_doc.rs index fd53f01ca174..f7c2e6f01180 100644 --- a/src/tools/compiletest/src/runtest/js_doc.rs +++ b/src/tools/compiletest/src/runtest/js_doc.rs @@ -1,13 +1,13 @@ use std::process::Command; -use super::TestCx; +use super::{DocKind, TestCx}; impl TestCx<'_> { pub(super) fn run_rustdoc_js_test(&self) { if let Some(nodejs) = &self.config.nodejs { let out_dir = self.output_base_dir(); - self.document(&out_dir, &self.testpaths); + self.document(&out_dir, &self.testpaths, DocKind::Html); let file_stem = self.testpaths.file.file_stem().expect("no file stem"); let res = self.run_command_to_procres( @@ -18,7 +18,9 @@ impl TestCx<'_> { .arg("--crate-name") .arg(file_stem.replace("-", "_")) .arg("--test-file") - .arg(self.testpaths.file.with_extension("js")), + .arg(self.testpaths.file.with_extension("js")) + .arg("--revision") + .arg(self.revision.unwrap_or_default()), ); if !res.status.success() { self.fatal_proc_rec("rustdoc-js test failed!", &res); diff --git a/src/tools/compiletest/src/runtest/rustdoc.rs b/src/tools/compiletest/src/runtest/rustdoc.rs index 4a143aa5824e..32b1823961be 100644 --- a/src/tools/compiletest/src/runtest/rustdoc.rs +++ b/src/tools/compiletest/src/runtest/rustdoc.rs @@ -1,6 +1,6 @@ use std::process::Command; -use super::{TestCx, remove_and_create_dir_all}; +use super::{DocKind, TestCx, remove_and_create_dir_all}; impl TestCx<'_> { pub(super) fn run_rustdoc_test(&self) { @@ -11,7 +11,7 @@ impl TestCx<'_> { panic!("failed to remove and recreate output directory `{out_dir}`: {e}") }); - let proc_res = self.document(&out_dir, &self.testpaths); + let proc_res = self.document(&out_dir, &self.testpaths, DocKind::Html); if !proc_res.status.success() { self.fatal_proc_rec("rustdoc failed!", &proc_res); } diff --git a/src/tools/compiletest/src/runtest/rustdoc_json.rs b/src/tools/compiletest/src/runtest/rustdoc_json.rs index b8da6e2ac528..dd7ebe9efaee 100644 --- a/src/tools/compiletest/src/runtest/rustdoc_json.rs +++ b/src/tools/compiletest/src/runtest/rustdoc_json.rs @@ -1,6 +1,6 @@ use std::process::Command; -use super::{TestCx, remove_and_create_dir_all}; +use super::{DocKind, TestCx, remove_and_create_dir_all}; impl TestCx<'_> { pub(super) fn run_rustdoc_json_test(&self) { @@ -13,7 +13,7 @@ impl TestCx<'_> { panic!("failed to remove and recreate output directory `{out_dir}`: {e}") }); - let proc_res = self.document(&out_dir, &self.testpaths); + let proc_res = self.document(&out_dir, &self.testpaths, DocKind::Json); if !proc_res.status.success() { self.fatal_proc_rec("rustdoc failed!", &proc_res); } diff --git a/src/tools/compiletest/src/runtest/ui.rs b/src/tools/compiletest/src/runtest/ui.rs index d683a325c866..c0adb6302e9d 100644 --- a/src/tools/compiletest/src/runtest/ui.rs +++ b/src/tools/compiletest/src/runtest/ui.rs @@ -207,8 +207,12 @@ impl TestCx<'_> { debug!( "run_ui_test: explicit={:?} config.compare_mode={:?} \ - proc_res.status={:?} props.error_patterns={:?}", - explicit, self.config.compare_mode, proc_res.status, self.props.error_patterns + proc_res.status={:?} props.error_patterns={:?} output_to_check={:?}", + explicit, + self.config.compare_mode, + proc_res.status, + self.props.error_patterns, + output_to_check, ); // Compiler diagnostics (expected errors) are always tied to the compile-time ProcRes. diff --git a/src/tools/miri/.github/workflows/ci.yml b/src/tools/miri/.github/workflows/ci.yml index 3078cd35b108..27d2f4a6df30 100644 --- a/src/tools/miri/.github/workflows/ci.yml +++ b/src/tools/miri/.github/workflows/ci.yml @@ -31,7 +31,8 @@ jobs: os: ubuntu-24.04-arm multiarch: armhf gcc_cross: arm-linux-gnueabihf - # Disabled due to Ubuntu repo trouble + # Ubuntu mirrors are not reliable enough for these architectures + # (see ). # - host_target: riscv64gc-unknown-linux-gnu # os: ubuntu-latest # multiarch: riscv64 @@ -68,7 +69,7 @@ jobs: - name: install multiarch if: ${{ matrix.multiarch != '' }} run: | - # s390x, ppc64el, riscv64 need Ubuntu Ports to be in the mirror list + # armhf, s390x, ppc64el, riscv64 need Ubuntu Ports to be in the mirror list sudo bash -c "echo 'https://ports.ubuntu.com/ priority:4' >> /etc/apt/apt-mirrors.txt" # Add architecture sudo dpkg --add-architecture ${{ matrix.multiarch }} diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index 405e0026b305..bf33c10dd035 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -27050c0d15af664cf43ce4b0badec230e0bfcac5 +292be5c7c05138d753bbd4b30db7a3f1a5c914f7 diff --git a/src/tools/miri/src/clock.rs b/src/tools/miri/src/clock.rs index dbbe741a0714..47608f873a48 100644 --- a/src/tools/miri/src/clock.rs +++ b/src/tools/miri/src/clock.rs @@ -46,21 +46,7 @@ impl Instant { InstantKind::Virtual { nanoseconds: earlier }, ) => { let duration = nanoseconds.saturating_sub(earlier); - cfg_select! { - bootstrap => { - // `Duration` does not provide a nice constructor from a `u128` of nanoseconds, - // so we have to implement this ourselves. - // It is possible for second to overflow because u64::MAX < (u128::MAX / 1e9). - // It will be saturated to u64::MAX seconds if the value after division exceeds u64::MAX. - let seconds = u64::try_from(duration / 1_000_000_000).unwrap_or(u64::MAX); - // It is impossible for nanosecond to overflow because u32::MAX > 1e9. - let nanosecond = u32::try_from(duration.wrapping_rem(1_000_000_000)).unwrap(); - Duration::new(seconds, nanosecond) - } - _ => { - Duration::from_nanos_u128(duration) - } - } + Duration::from_nanos_u128(duration) } _ => panic!("all `Instant` must be of the same kind"), } diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs index 1206859d1cdc..b756fbb901bc 100644 --- a/src/tools/miri/src/lib.rs +++ b/src/tools/miri/src/lib.rs @@ -17,7 +17,7 @@ #![feature(derive_coerce_pointee)] #![feature(arbitrary_self_types)] #![feature(iter_advance_by)] -#![cfg_attr(not(bootstrap), feature(duration_from_nanos_u128))] +#![feature(duration_from_nanos_u128)] // Configure clippy and other lints #![allow( clippy::collapsible_else_if, diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock index 267b51621095..535833d9e2a9 100644 --- a/src/tools/rust-analyzer/Cargo.lock +++ b/src/tools/rust-analyzer/Cargo.lock @@ -235,6 +235,7 @@ name = "cfg" version = "0.0.0" dependencies = [ "arbitrary", + "cfg", "expect-test", "intern", "oorandom", @@ -257,28 +258,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" -[[package]] -name = "chalk-derive" -version = "0.104.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ea9b1e80910f66ae87c772247591432032ef3f6a67367ff17f8343db05beafa" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "synstructure", -] - -[[package]] -name = "chalk-ir" -version = "0.104.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7047a516de16226cd17344d41a319d0ea1064bf9e60bd612ab341ab4a34bbfa8" -dependencies = [ - "bitflags 2.9.4", - "chalk-derive", -] - [[package]] name = "clap" version = "4.5.48" @@ -776,8 +755,6 @@ dependencies = [ "arrayvec", "base-db", "bitflags 2.9.4", - "chalk-derive", - "chalk-ir", "cov-mark", "either", "ena", @@ -819,11 +796,11 @@ dependencies = [ [[package]] name = "home" -version = "0.5.11" +version = "0.5.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf" +checksum = "cc627f471c528ff0c4a49e1d5e60450c8f6461dd6d10ba9dcd3a61d3dff7728d" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.61.0", ] [[package]] @@ -929,6 +906,7 @@ dependencies = [ "ide-diagnostics", "ide-ssr", "itertools", + "macros", "nohash-hasher", "oorandom", "profile", @@ -975,6 +953,7 @@ dependencies = [ "hir", "ide-db", "itertools", + "macros", "smallvec", "stdx", "syntax", @@ -999,6 +978,7 @@ dependencies = [ "indexmap", "itertools", "line-index 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "macros", "memchr", "nohash-hasher", "parser", @@ -1008,6 +988,7 @@ dependencies = [ "rustc-hash 2.1.1", "salsa", "salsa-macros", + "smallvec", "span", "stdx", "syntax", @@ -1404,14 +1385,14 @@ dependencies = [ [[package]] name = "mio" -version = "1.0.4" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" +checksum = "69d83b0086dc8ecf3ce9ae2874b2d1290252e2a30720bea58a5c6639b0092873" dependencies = [ "libc", "log", "wasi", - "windows-sys 0.59.0", + "windows-sys 0.61.0", ] [[package]] @@ -1467,11 +1448,11 @@ checksum = "5e0826a989adedc2a244799e823aece04662b66609d96af8dff7ac6df9a8925d" [[package]] name = "nu-ansi-term" -version = "0.50.1" +version = "0.50.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4a28e057d01f97e61255210fcff094d74ed0466038633e95017f5beb68e4399" +checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.60.2", ] [[package]] @@ -1578,6 +1559,7 @@ dependencies = [ "rustc-literal-escaper 0.0.4", "stdx", "tracing", + "winnow", ] [[package]] @@ -1842,9 +1824,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_abi" -version = "0.133.0" +version = "0.137.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c063a7fef3c49d03837ee9a5d988aad83630c3460b03b32355c279d3fafa7d07" +checksum = "a4ce5c9ea794353e02beae390c4674f74ffb23a2ad9de763469fdcef5c1026ef" dependencies = [ "bitflags 2.9.4", "ra-ap-rustc_hashes", @@ -1854,24 +1836,24 @@ dependencies = [ [[package]] name = "ra-ap-rustc_ast_ir" -version = "0.133.0" +version = "0.137.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a210dbd77e794b33ff17d2d15750dee44eeabd1330685d69a6bad272d515892a" +checksum = "1696b77af9bbfe1fcc7a09c907561061c6ef4c8bd6d5f1675b927bc62d349103" [[package]] name = "ra-ap-rustc_hashes" -version = "0.133.0" +version = "0.137.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dea031ea45bb92cd346ed222b35c812e355f304183096ee91bb437b3813c6348" +checksum = "c055d8b0d8a592d8cf9547495189f52c1ee5c691d28df1628253a816214e8521" dependencies = [ "rustc-stable-hash", ] [[package]] name = "ra-ap-rustc_index" -version = "0.133.0" +version = "0.137.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db0114f842b20cba9beb2d9002ca31ae706b47f28ba2d6a49cbf9fd65fa72b9d" +checksum = "a08a03e3d4a452144b68f48130eda3a2894d4d79e99ddb44bdb4e0ab8c384e10" dependencies = [ "ra-ap-rustc_index_macros", "smallvec", @@ -1879,9 +1861,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_index_macros" -version = "0.133.0" +version = "0.137.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc738a5bb06fb3893725fbeb3640ff1822bb2aae3f416c4a49f0a706ba89d1cc" +checksum = "a1e0446b4d65a8ce19d8fd12826c4bf2365ffa4b8fe0ee94daf5968fe36e920c" dependencies = [ "proc-macro2", "quote", @@ -1890,9 +1872,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_lexer" -version = "0.133.0" +version = "0.137.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31c35b3d812cfc101d3f534640c13f24c0ec50ee2249685e4c20b2868609c9ee" +checksum = "ac80365383a3c749f38af567fdcfaeff3fa6ea5df3846852abbce73e943921b9" dependencies = [ "memchr", "unicode-properties", @@ -1901,9 +1883,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_next_trait_solver" -version = "0.133.0" +version = "0.137.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7b0fa6fb8e0717ebd0836f8de4a6efc954fca1a8652980fd2584dbe448c7d95" +checksum = "a39b419d2d6f7fdec7e0981b7fb7d5beb5dda7140064f1199704ec9dadbb6f73" dependencies = [ "derive-where", "ra-ap-rustc_index", @@ -1914,9 +1896,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_parse_format" -version = "0.133.0" +version = "0.137.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33d01bad23470cc749ef607476890aabcc8993ca3ef87d4241d0f6a08c6f9402" +checksum = "b743b0c8f795842e41b1720bbc5af6e896129fb9acf04e9785774bfb0dc5947c" dependencies = [ "ra-ap-rustc_lexer", "rustc-literal-escaper 0.0.5", @@ -1924,9 +1906,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_pattern_analysis" -version = "0.133.0" +version = "0.137.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a181cf7943dc16e888046584d6172be95818811b25d695dbacbb4dd71973cc3" +checksum = "cf944dce80137195528f89a576f70153c2060a6f8ca49c3fa9f55f9da14ab937" dependencies = [ "ra-ap-rustc_index", "rustc-hash 2.1.1", @@ -1937,9 +1919,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_type_ir" -version = "0.133.0" +version = "0.137.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87c99f33be18d9e50cefef5442822da1f0b416e9a17a483879a9704e08a6a6e6" +checksum = "1bfe2722b20bc889a9d7711bd3a1f4f7b082940491241615aa643c17e0deffec" dependencies = [ "arrayvec", "bitflags 2.9.4", @@ -1957,9 +1939,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_type_ir_macros" -version = "0.133.0" +version = "0.137.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77b162d65e058abfc058e6b67ae68156cc282fbd78da148c1a7ec77b4230661e" +checksum = "6fad1527df26aaa77367393fae86f42818b33e02b3737a19f3846d1c7671e7f9" dependencies = [ "proc-macro2", "quote", @@ -2991,24 +2973,6 @@ dependencies = [ "windows-link 0.1.3", ] -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-sys" -version = "0.59.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" -dependencies = [ - "windows-targets 0.52.6", -] - [[package]] name = "windows-sys" version = "0.60.2" diff --git a/src/tools/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/Cargo.toml index f94fd37e52a7..ecb2686a2277 100644 --- a/src/tools/rust-analyzer/Cargo.toml +++ b/src/tools/rust-analyzer/Cargo.toml @@ -37,8 +37,6 @@ debug = 2 [patch.'crates-io'] # rowan = { path = "../rowan" } -# chalk-ir = { path = "../chalk/chalk-ir" } -# chalk-derive = { path = "../chalk/chalk-derive" } # line-index = { path = "lib/line-index" } # la-arena = { path = "lib/la-arena" } # lsp-server = { path = "lib/lsp-server" } @@ -88,14 +86,14 @@ vfs-notify = { path = "./crates/vfs-notify", version = "0.0.0" } vfs = { path = "./crates/vfs", version = "0.0.0" } edition = { path = "./crates/edition", version = "0.0.0" } -ra-ap-rustc_lexer = { version = "0.133", default-features = false } -ra-ap-rustc_parse_format = { version = "0.133", default-features = false } -ra-ap-rustc_index = { version = "0.133", default-features = false } -ra-ap-rustc_abi = { version = "0.133", default-features = false } -ra-ap-rustc_pattern_analysis = { version = "0.133", default-features = false } -ra-ap-rustc_ast_ir = { version = "0.133", default-features = false } -ra-ap-rustc_type_ir = { version = "0.133", default-features = false } -ra-ap-rustc_next_trait_solver = { version = "0.133", default-features = false } +ra-ap-rustc_lexer = { version = "0.137", default-features = false } +ra-ap-rustc_parse_format = { version = "0.137", default-features = false } +ra-ap-rustc_index = { version = "0.137", default-features = false } +ra-ap-rustc_abi = { version = "0.137", default-features = false } +ra-ap-rustc_pattern_analysis = { version = "0.137", default-features = false } +ra-ap-rustc_ast_ir = { version = "0.137", default-features = false } +ra-ap-rustc_type_ir = { version = "0.137", default-features = false } +ra-ap-rustc_next_trait_solver = { version = "0.137", default-features = false } # local crates that aren't published to crates.io. These should not have versions. @@ -110,8 +108,6 @@ arrayvec = "0.7.6" bitflags = "2.9.1" cargo_metadata = "0.21.0" camino = "1.1.10" -chalk-ir = "0.104.0" -chalk-derive = "0.104.0" crossbeam-channel = "0.5.15" dissimilar = "1.0.10" dot = "0.1.4" diff --git a/src/tools/rust-analyzer/crates/cfg/Cargo.toml b/src/tools/rust-analyzer/crates/cfg/Cargo.toml index af95f86c8352..e17969bd82d4 100644 --- a/src/tools/rust-analyzer/crates/cfg/Cargo.toml +++ b/src/tools/rust-analyzer/crates/cfg/Cargo.toml @@ -29,5 +29,8 @@ arbitrary = { version = "1.4.1", features = ["derive"] } syntax-bridge.workspace = true syntax.workspace = true +# tt is needed for testing +cfg = { path = ".", default-features = false, features = ["tt"] } + [lints] workspace = true diff --git a/src/tools/rust-analyzer/crates/cfg/src/lib.rs b/src/tools/rust-analyzer/crates/cfg/src/lib.rs index 906106ca5db0..b1ec4c273a85 100644 --- a/src/tools/rust-analyzer/crates/cfg/src/lib.rs +++ b/src/tools/rust-analyzer/crates/cfg/src/lib.rs @@ -115,6 +115,13 @@ impl CfgOptions { pub fn shrink_to_fit(&mut self) { self.enabled.shrink_to_fit(); } + + pub fn append(&mut self, other: CfgOptions) { + // Do not call `insert_any_atom()`, as it'll check for `true` and `false`, but this is not + // needed since we already checked for that when constructing `other`. Furthermore, this + // will always err, as `other` inevitably contains `true` (just as we do). + self.enabled.extend(other.enabled); + } } impl Extend for CfgOptions { diff --git a/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml b/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml index ec6563315407..378a0f0382c3 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml +++ b/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml @@ -24,8 +24,6 @@ oorandom = "11.1.5" tracing.workspace = true rustc-hash.workspace = true scoped-tls = "1.0.1" -chalk-ir.workspace = true -chalk-derive.workspace = true la-arena.workspace = true triomphe.workspace = true typed-arena = "2.0.2" diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/builder.rs b/src/tools/rust-analyzer/crates/hir-ty/src/builder.rs deleted file mode 100644 index 706bbe856c67..000000000000 --- a/src/tools/rust-analyzer/crates/hir-ty/src/builder.rs +++ /dev/null @@ -1,398 +0,0 @@ -//! `TyBuilder`, a helper for building instances of `Ty` and related types. - -use chalk_ir::{ - AdtId, DebruijnIndex, Scalar, - cast::{Cast, CastTo, Caster}, -}; -use hir_def::{GenericDefId, GenericParamId, TraitId, TypeAliasId, builtin_type::BuiltinType}; -use smallvec::SmallVec; - -use crate::{ - BoundVar, CallableSig, GenericArg, GenericArgData, Interner, ProjectionTy, Substitution, - TraitRef, Ty, TyDefId, TyExt, TyKind, - consteval::unknown_const_as_generic, - db::HirDatabase, - error_lifetime, - generics::generics, - infer::unify::InferenceTable, - next_solver::{ - DbInterner, EarlyBinder, - mapping::{ChalkToNextSolver, NextSolverToChalk}, - }, - primitive, to_assoc_type_id, to_chalk_trait_id, -}; - -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum ParamKind { - Type, - Lifetime, - Const(Ty), -} - -/// This is a builder for `Ty` or anything that needs a `Substitution`. -pub struct TyBuilder { - /// The `data` field is used to keep track of what we're building (e.g. an - /// ADT, a `TraitRef`, ...). - data: D, - vec: SmallVec<[GenericArg; 2]>, - param_kinds: SmallVec<[ParamKind; 2]>, - parent_subst: Substitution, -} - -impl TyBuilder { - fn with_data(self, data: B) -> TyBuilder { - TyBuilder { - data, - vec: self.vec, - param_kinds: self.param_kinds, - parent_subst: self.parent_subst, - } - } -} - -impl TyBuilder { - fn new( - data: D, - param_kinds: SmallVec<[ParamKind; 2]>, - parent_subst: Option, - ) -> Self { - let parent_subst = parent_subst.unwrap_or_else(|| Substitution::empty(Interner)); - Self { data, vec: SmallVec::with_capacity(param_kinds.len()), param_kinds, parent_subst } - } - - fn new_empty(data: D) -> Self { - TyBuilder::new(data, SmallVec::new(), None) - } - - fn build_internal(self) -> (D, Substitution) { - assert_eq!( - self.vec.len(), - self.param_kinds.len(), - "{} args received, {} expected ({:?})", - self.vec.len(), - self.param_kinds.len(), - &self.param_kinds - ); - for (a, e) in self.vec.iter().zip(self.param_kinds.iter()) { - self.assert_match_kind(a, e); - } - let subst = Substitution::from_iter( - Interner, - self.parent_subst.iter(Interner).cloned().chain(self.vec), - ); - (self.data, subst) - } - - pub fn build_into_subst(self) -> Substitution { - self.build_internal().1 - } - - pub fn push(mut self, arg: impl CastTo) -> Self { - assert!(self.remaining() > 0); - let arg = arg.cast(Interner); - let expected_kind = &self.param_kinds[self.vec.len()]; - - let arg_kind = match arg.data(Interner) { - GenericArgData::Ty(_) => ParamKind::Type, - GenericArgData::Lifetime(_) => panic!("Got lifetime in TyBuilder::push"), - GenericArgData::Const(c) => { - let c = c.data(Interner); - ParamKind::Const(c.ty.clone()) - } - }; - assert_eq!(*expected_kind, arg_kind); - - self.vec.push(arg); - - self - } - - pub fn remaining(&self) -> usize { - self.param_kinds.len() - self.vec.len() - } - - pub fn fill_with_bound_vars(self, debruijn: DebruijnIndex, starting_from: usize) -> Self { - // self.fill is inlined to make borrow checker happy - let mut this = self; - let other = &this.param_kinds[this.vec.len()..]; - let filler = (starting_from..).zip(other).map(|(idx, kind)| match kind { - ParamKind::Type => BoundVar::new(debruijn, idx).to_ty(Interner).cast(Interner), - ParamKind::Const(ty) => { - BoundVar::new(debruijn, idx).to_const(Interner, ty.clone()).cast(Interner) - } - ParamKind::Lifetime => { - BoundVar::new(debruijn, idx).to_lifetime(Interner).cast(Interner) - } - }); - this.vec.extend(filler.take(this.remaining()).casted(Interner)); - assert_eq!(this.remaining(), 0); - this - } - - pub fn fill_with_unknown(self) -> Self { - let interner = DbInterner::conjure(); - // self.fill is inlined to make borrow checker happy - let mut this = self; - let filler = this.param_kinds[this.vec.len()..].iter().map(|x| match x { - ParamKind::Type => TyKind::Error.intern(Interner).cast(Interner), - ParamKind::Const(ty) => { - unknown_const_as_generic(ty.to_nextsolver(interner)).to_chalk(interner) - } - ParamKind::Lifetime => error_lifetime().cast(Interner), - }); - this.vec.extend(filler.casted(Interner)); - assert_eq!(this.remaining(), 0); - this - } - - #[tracing::instrument(skip_all)] - pub(crate) fn fill_with_inference_vars(self, table: &mut InferenceTable<'_>) -> Self { - self.fill(|x| { - match x { - ParamKind::Type => crate::next_solver::GenericArg::Ty(table.next_ty_var()), - ParamKind::Const(_) => table.next_const_var().into(), - ParamKind::Lifetime => table.next_region_var().into(), - } - .to_chalk(table.interner()) - }) - } - - pub fn fill(mut self, filler: impl FnMut(&ParamKind) -> GenericArg) -> Self { - self.vec.extend(self.param_kinds[self.vec.len()..].iter().map(filler)); - assert_eq!(self.remaining(), 0); - self - } - - fn assert_match_kind(&self, a: &chalk_ir::GenericArg, e: &ParamKind) { - match (a.data(Interner), e) { - (GenericArgData::Ty(_), ParamKind::Type) - | (GenericArgData::Const(_), ParamKind::Const(_)) - | (GenericArgData::Lifetime(_), ParamKind::Lifetime) => (), - _ => panic!("Mismatched kinds: {a:?}, {:?}, {:?}", self.vec, self.param_kinds), - } - } -} - -impl TyBuilder<()> { - pub fn unit() -> Ty { - TyKind::Tuple(0, Substitution::empty(Interner)).intern(Interner) - } - - // FIXME: rustc's ty is dependent on the adt type, maybe we need to do that as well - pub fn discr_ty() -> Ty { - TyKind::Scalar(chalk_ir::Scalar::Int(chalk_ir::IntTy::I128)).intern(Interner) - } - - pub fn bool() -> Ty { - TyKind::Scalar(chalk_ir::Scalar::Bool).intern(Interner) - } - - pub fn usize() -> Ty { - TyKind::Scalar(chalk_ir::Scalar::Uint(chalk_ir::UintTy::Usize)).intern(Interner) - } - - pub fn fn_ptr(sig: CallableSig) -> Ty { - TyKind::Function(sig.to_fn_ptr()).intern(Interner) - } - - pub fn builtin(builtin: BuiltinType) -> Ty { - match builtin { - BuiltinType::Char => TyKind::Scalar(Scalar::Char).intern(Interner), - BuiltinType::Bool => TyKind::Scalar(Scalar::Bool).intern(Interner), - BuiltinType::Str => TyKind::Str.intern(Interner), - BuiltinType::Int(t) => { - TyKind::Scalar(Scalar::Int(primitive::int_ty_from_builtin(t))).intern(Interner) - } - BuiltinType::Uint(t) => { - TyKind::Scalar(Scalar::Uint(primitive::uint_ty_from_builtin(t))).intern(Interner) - } - BuiltinType::Float(t) => { - TyKind::Scalar(Scalar::Float(primitive::float_ty_from_builtin(t))).intern(Interner) - } - } - } - - pub fn slice(argument: Ty) -> Ty { - TyKind::Slice(argument).intern(Interner) - } - - pub fn placeholder_subst(db: &dyn HirDatabase, def: impl Into) -> Substitution { - let params = generics(db, def.into()); - params.placeholder_subst(db) - } - - pub fn unknown_subst(db: &dyn HirDatabase, def: impl Into) -> Substitution { - let interner = DbInterner::conjure(); - let params = generics(db, def.into()); - Substitution::from_iter( - Interner, - params.iter_id().map(|id| match id { - GenericParamId::TypeParamId(_) => TyKind::Error.intern(Interner).cast(Interner), - GenericParamId::ConstParamId(id) => { - unknown_const_as_generic(db.const_param_ty_ns(id)) - .to_chalk(interner) - .cast(Interner) - } - GenericParamId::LifetimeParamId(_) => error_lifetime().cast(Interner), - }), - ) - } - - #[tracing::instrument(skip_all)] - pub fn subst_for_def( - db: &dyn HirDatabase, - def: impl Into, - parent_subst: Option, - ) -> TyBuilder<()> { - let generics = generics(db, def.into()); - assert!(generics.parent_generics().is_some() == parent_subst.is_some()); - let params = generics - .iter_self() - .map(|(id, _data)| match id { - GenericParamId::TypeParamId(_) => ParamKind::Type, - GenericParamId::ConstParamId(id) => ParamKind::Const(db.const_param_ty(id)), - GenericParamId::LifetimeParamId(_) => ParamKind::Lifetime, - }) - .collect(); - TyBuilder::new((), params, parent_subst) - } - - pub fn build(self) -> Substitution { - let ((), subst) = self.build_internal(); - subst - } -} - -impl TyBuilder { - pub fn adt(db: &dyn HirDatabase, def: hir_def::AdtId) -> TyBuilder { - TyBuilder::subst_for_def(db, def, None).with_data(def) - } - - pub fn fill_with_defaults( - mut self, - db: &dyn HirDatabase, - mut fallback: impl FnMut() -> Ty, - ) -> Self { - let interner = DbInterner::conjure(); - // Note that we're building ADT, so we never have parent generic parameters. - let defaults = db.generic_defaults(self.data.into()); - - if let Some(defaults) = defaults.get(self.vec.len()..) { - for default_ty in defaults { - // NOTE(skip_binders): we only check if the arg type is error type. - if let Some(x) = default_ty.skip_binders().ty(Interner) - && x.is_unknown() - { - self.vec.push(fallback().cast(Interner)); - continue; - } - // Each default can only depend on the previous parameters. - self.vec.push(default_ty.clone().substitute(Interner, &*self.vec).cast(Interner)); - } - } - - // The defaults may be missing if no param has default, so fill that. - let filler = self.param_kinds[self.vec.len()..].iter().map(|x| match x { - ParamKind::Type => fallback().cast(Interner), - ParamKind::Const(ty) => { - unknown_const_as_generic(ty.to_nextsolver(interner)).to_chalk(interner) - } - ParamKind::Lifetime => error_lifetime().cast(Interner), - }); - self.vec.extend(filler.casted(Interner)); - - self - } - - pub fn build(self) -> Ty { - let (adt, subst) = self.build_internal(); - TyKind::Adt(AdtId(adt), subst).intern(Interner) - } -} - -pub struct Tuple(usize); -impl TyBuilder { - pub fn tuple(size: usize) -> TyBuilder { - TyBuilder::new(Tuple(size), std::iter::repeat_n(ParamKind::Type, size).collect(), None) - } - - pub fn build(self) -> Ty { - let (Tuple(size), subst) = self.build_internal(); - TyKind::Tuple(size, subst).intern(Interner) - } - - pub fn tuple_with(elements: I) -> Ty - where - I: IntoIterator, - ::IntoIter: ExactSizeIterator, - { - let elements = elements.into_iter(); - let len = elements.len(); - let mut b = - TyBuilder::new(Tuple(len), std::iter::repeat_n(ParamKind::Type, len).collect(), None); - for e in elements { - b = b.push(e); - } - b.build() - } -} - -impl TyBuilder { - pub fn trait_ref(db: &dyn HirDatabase, def: TraitId) -> TyBuilder { - TyBuilder::subst_for_def(db, def, None).with_data(def) - } - - pub fn build(self) -> TraitRef { - let (trait_id, substitution) = self.build_internal(); - TraitRef { trait_id: to_chalk_trait_id(trait_id), substitution } - } -} - -impl TyBuilder { - pub fn assoc_type_projection( - db: &dyn HirDatabase, - def: TypeAliasId, - parent_subst: Option, - ) -> TyBuilder { - TyBuilder::subst_for_def(db, def, parent_subst).with_data(def) - } - - pub fn build(self) -> ProjectionTy { - let (type_alias, substitution) = self.build_internal(); - ProjectionTy { associated_ty_id: to_assoc_type_id(type_alias), substitution } - } -} - -impl<'db, T: rustc_type_ir::TypeFoldable>> TyBuilder> { - pub fn build(self, interner: DbInterner<'db>) -> T { - let (b, subst) = self.build_internal(); - let args: crate::next_solver::GenericArgs<'db> = subst.to_nextsolver(interner); - b.instantiate(interner, args) - } -} - -impl<'db> TyBuilder>> { - pub fn def_ty( - db: &'db dyn HirDatabase, - def: TyDefId, - parent_subst: Option, - ) -> TyBuilder>> { - let poly_ty = db.ty(def); - let id: GenericDefId = match def { - TyDefId::BuiltinType(_) => { - assert!(parent_subst.is_none()); - return TyBuilder::new_empty(poly_ty); - } - TyDefId::AdtId(id) => id.into(), - TyDefId::TypeAliasId(id) => id.into(), - }; - TyBuilder::subst_for_def(db, id, parent_subst).with_data(poly_ty) - } - - pub fn impl_self_ty( - db: &'db dyn HirDatabase, - def: hir_def::ImplId, - ) -> TyBuilder>> { - TyBuilder::subst_for_def(db, def, None).with_data(db.impl_self_ty(def)) - } -} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs deleted file mode 100644 index 3d06b5210670..000000000000 --- a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs +++ /dev/null @@ -1,55 +0,0 @@ -//! The implementation of `RustIrDatabase` for Chalk, which provides information -//! about the code that Chalk needs. -use hir_def::{CallableDefId, GenericDefId}; - -use crate::{Interner, db::HirDatabase, mapping::from_chalk}; - -pub(crate) type AssocTypeId = chalk_ir::AssocTypeId; -pub(crate) type TraitId = chalk_ir::TraitId; -pub(crate) type AdtId = chalk_ir::AdtId; -pub(crate) type ImplId = chalk_ir::ImplId; -pub(crate) type Variances = chalk_ir::Variances; - -impl chalk_ir::UnificationDatabase for &dyn HirDatabase { - fn fn_def_variance( - &self, - fn_def_id: chalk_ir::FnDefId, - ) -> chalk_ir::Variances { - HirDatabase::fn_def_variance(*self, from_chalk(*self, fn_def_id)) - } - - fn adt_variance(&self, adt_id: chalk_ir::AdtId) -> chalk_ir::Variances { - HirDatabase::adt_variance(*self, adt_id.0) - } -} - -pub(crate) fn fn_def_variance_query( - db: &dyn HirDatabase, - callable_def: CallableDefId, -) -> Variances { - Variances::from_iter( - Interner, - db.variances_of(GenericDefId::from_callable(db, callable_def)) - .as_deref() - .unwrap_or_default() - .iter() - .map(|v| match v { - crate::variance::Variance::Covariant => chalk_ir::Variance::Covariant, - crate::variance::Variance::Invariant => chalk_ir::Variance::Invariant, - crate::variance::Variance::Contravariant => chalk_ir::Variance::Contravariant, - crate::variance::Variance::Bivariant => chalk_ir::Variance::Invariant, - }), - ) -} - -pub(crate) fn adt_variance_query(db: &dyn HirDatabase, adt_id: hir_def::AdtId) -> Variances { - Variances::from_iter( - Interner, - db.variances_of(adt_id.into()).as_deref().unwrap_or_default().iter().map(|v| match v { - crate::variance::Variance::Covariant => chalk_ir::Variance::Covariant, - crate::variance::Variance::Invariant => chalk_ir::Variance::Invariant, - crate::variance::Variance::Contravariant => chalk_ir::Variance::Contravariant, - crate::variance::Variance::Bivariant => chalk_ir::Variance::Invariant, - }), - ) -} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs deleted file mode 100644 index e9960374c6f5..000000000000 --- a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs +++ /dev/null @@ -1,168 +0,0 @@ -//! Various extensions traits for Chalk types. - -use chalk_ir::Mutability; -use hir_def::{FunctionId, ItemContainerId, Lookup, TraitId}; - -use crate::{ - AdtId, Binders, CallableDefId, CallableSig, DynTy, Interner, Lifetime, ProjectionTy, - Substitution, ToChalk, TraitRef, Ty, TyKind, TypeFlags, WhereClause, db::HirDatabase, - from_assoc_type_id, from_chalk_trait_id, generics::generics, to_chalk_trait_id, - utils::ClosureSubst, -}; - -pub(crate) trait TyExt { - fn is_unit(&self) -> bool; - fn is_unknown(&self) -> bool; - fn contains_unknown(&self) -> bool; - - fn as_adt(&self) -> Option<(hir_def::AdtId, &Substitution)>; - fn as_tuple(&self) -> Option<&Substitution>; - fn as_fn_def(&self, db: &dyn HirDatabase) -> Option; - fn as_reference(&self) -> Option<(&Ty, Lifetime, Mutability)>; - - fn callable_def(&self, db: &dyn HirDatabase) -> Option; - fn callable_sig(&self, db: &dyn HirDatabase) -> Option; - - fn strip_references(&self) -> &Ty; - - /// If this is a `dyn Trait`, returns that trait. - fn dyn_trait(&self) -> Option; -} - -impl TyExt for Ty { - fn is_unit(&self) -> bool { - matches!(self.kind(Interner), TyKind::Tuple(0, _)) - } - - fn is_unknown(&self) -> bool { - matches!(self.kind(Interner), TyKind::Error) - } - - fn contains_unknown(&self) -> bool { - self.data(Interner).flags.contains(TypeFlags::HAS_ERROR) - } - - fn as_adt(&self) -> Option<(hir_def::AdtId, &Substitution)> { - match self.kind(Interner) { - TyKind::Adt(AdtId(adt), parameters) => Some((*adt, parameters)), - _ => None, - } - } - - fn as_tuple(&self) -> Option<&Substitution> { - match self.kind(Interner) { - TyKind::Tuple(_, substs) => Some(substs), - _ => None, - } - } - - fn as_fn_def(&self, db: &dyn HirDatabase) -> Option { - match self.callable_def(db) { - Some(CallableDefId::FunctionId(func)) => Some(func), - Some(CallableDefId::StructId(_) | CallableDefId::EnumVariantId(_)) | None => None, - } - } - - fn as_reference(&self) -> Option<(&Ty, Lifetime, Mutability)> { - match self.kind(Interner) { - TyKind::Ref(mutability, lifetime, ty) => Some((ty, lifetime.clone(), *mutability)), - _ => None, - } - } - - fn callable_def(&self, db: &dyn HirDatabase) -> Option { - match self.kind(Interner) { - &TyKind::FnDef(def, ..) => Some(ToChalk::from_chalk(db, def)), - _ => None, - } - } - - fn callable_sig(&self, db: &dyn HirDatabase) -> Option { - match self.kind(Interner) { - TyKind::Function(fn_ptr) => Some(CallableSig::from_fn_ptr(fn_ptr)), - TyKind::FnDef(def, parameters) => Some(CallableSig::from_def(db, *def, parameters)), - TyKind::Closure(.., substs) => ClosureSubst(substs).sig_ty(db).callable_sig(db), - _ => None, - } - } - - fn dyn_trait(&self) -> Option { - let trait_ref = match self.kind(Interner) { - // The principal trait bound should be the first element of the bounds. This is an - // invariant ensured by `TyLoweringContext::lower_dyn_trait()`. - // FIXME: dyn types may not have principal trait and we don't want to return auto trait - // here. - TyKind::Dyn(dyn_ty) => dyn_ty.bounds.skip_binders().interned().first().and_then(|b| { - match b.skip_binders() { - WhereClause::Implemented(trait_ref) => Some(trait_ref), - _ => None, - } - }), - _ => None, - }?; - Some(from_chalk_trait_id(trait_ref.trait_id)) - } - - fn strip_references(&self) -> &Ty { - let mut t: &Ty = self; - while let TyKind::Ref(_mutability, _lifetime, ty) = t.kind(Interner) { - t = ty; - } - t - } -} - -pub trait ProjectionTyExt { - fn trait_ref(&self, db: &dyn HirDatabase) -> TraitRef; - fn trait_(&self, db: &dyn HirDatabase) -> TraitId; - fn self_type_parameter(&self, db: &dyn HirDatabase) -> Ty; -} - -impl ProjectionTyExt for ProjectionTy { - fn trait_ref(&self, db: &dyn HirDatabase) -> TraitRef { - // FIXME: something like `Split` trait from chalk-solve might be nice. - let generics = generics(db, from_assoc_type_id(self.associated_ty_id).into()); - let parent_len = generics.parent_generics().map_or(0, |g| g.len_self()); - let substitution = - Substitution::from_iter(Interner, self.substitution.iter(Interner).take(parent_len)); - TraitRef { trait_id: to_chalk_trait_id(self.trait_(db)), substitution } - } - - fn trait_(&self, db: &dyn HirDatabase) -> TraitId { - match from_assoc_type_id(self.associated_ty_id).lookup(db).container { - ItemContainerId::TraitId(it) => it, - _ => panic!("projection ty without parent trait"), - } - } - - fn self_type_parameter(&self, db: &dyn HirDatabase) -> Ty { - self.trait_ref(db).self_type_parameter(Interner) - } -} - -pub(crate) trait DynTyExt { - fn principal(&self) -> Option>>; -} - -impl DynTyExt for DynTy { - fn principal(&self) -> Option>> { - self.bounds.as_ref().filter_map(|bounds| { - bounds.interned().first().and_then(|b| { - b.as_ref().filter_map(|b| match b { - crate::WhereClause::Implemented(trait_ref) => Some(trait_ref), - _ => None, - }) - }) - }) - } -} - -pub trait TraitRefExt { - fn hir_trait_id(&self) -> TraitId; -} - -impl TraitRefExt for TraitRef { - fn hir_trait_id(&self) -> TraitId { - from_chalk_trait_id(self.trait_id) - } -} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs b/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs index 002e0823b9d1..18ebe7d7a539 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs @@ -5,76 +5,29 @@ mod tests; use base_db::Crate; use hir_def::{ - EnumVariantId, GeneralConstId, - expr_store::{Body, HygieneId, path::Path}, + EnumVariantId, GeneralConstId, HasModule, StaticId, + expr_store::Body, hir::{Expr, ExprId}, - resolver::{Resolver, ValueNs}, type_ref::LiteralConstRef, }; -use hir_def::{HasModule, StaticId}; use hir_expand::Lookup; -use rustc_type_ir::{UnevaluatedConst, inherent::IntoKind}; -use stdx::never; +use rustc_type_ir::inherent::IntoKind; use triomphe::Arc; use crate::{ - MemoryMap, TraitEnvironment, + LifetimeElisionKind, MemoryMap, TraitEnvironment, TyLoweringContext, db::HirDatabase, display::DisplayTarget, - generics::Generics, infer::InferenceContext, mir::{MirEvalError, MirLowerError}, next_solver::{ Const, ConstBytes, ConstKind, DbInterner, ErrorGuaranteed, GenericArg, GenericArgs, - ParamConst, SolverDefId, Ty, ValueConst, + SolverDefId, Ty, ValueConst, }, }; use super::mir::{interpret_mir, lower_to_mir, pad16}; -pub(crate) fn path_to_const<'a, 'g>( - db: &'a dyn HirDatabase, - resolver: &Resolver<'a>, - path: &Path, - args: impl FnOnce() -> &'g Generics, - _expected_ty: Ty<'a>, -) -> Option> { - let interner = DbInterner::new_with(db, Some(resolver.krate()), None); - match resolver.resolve_path_in_value_ns_fully(db, path, HygieneId::ROOT) { - Some(ValueNs::GenericParam(p)) => { - let args = args(); - match args - .type_or_const_param(p.into()) - .and_then(|(idx, p)| p.const_param().map(|p| (idx, p.clone()))) - { - Some((idx, _param)) => { - Some(Const::new_param(interner, ParamConst { index: idx as u32, id: p })) - } - None => { - never!( - "Generic list doesn't contain this param: {:?}, {:?}, {:?}", - args, - path, - p - ); - None - } - } - } - Some(ValueNs::ConstId(c)) => { - let args = GenericArgs::new_from_iter(interner, []); - Some(Const::new( - interner, - rustc_type_ir::ConstKind::Unevaluated(UnevaluatedConst::new( - SolverDefId::ConstId(c), - args, - )), - )) - } - _ => None, - } -} - pub fn unknown_const<'db>(_ty: Ty<'db>) -> Const<'db> { Const::new(DbInterner::conjure(), rustc_type_ir::ConstKind::Error(ErrorGuaranteed)) } @@ -280,8 +233,14 @@ pub(crate) fn eval_to_const<'db>(expr: ExprId, ctx: &mut InferenceContext<'_, 'd return unknown_const(infer[expr]); } if let Expr::Path(p) = &ctx.body[expr] { - let resolver = &ctx.resolver; - if let Some(c) = path_to_const(ctx.db, resolver, p, || ctx.generics(), infer[expr]) { + let mut ctx = TyLoweringContext::new( + ctx.db, + &ctx.resolver, + ctx.body, + ctx.generic_def, + LifetimeElisionKind::Infer, + ); + if let Some(c) = ctx.path_to_const(p) { return c; } } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/consteval_chalk.rs b/src/tools/rust-analyzer/crates/hir-ty/src/consteval_chalk.rs deleted file mode 100644 index 07b783ea9292..000000000000 --- a/src/tools/rust-analyzer/crates/hir-ty/src/consteval_chalk.rs +++ /dev/null @@ -1,108 +0,0 @@ -//! Constant evaluation details - -use base_db::Crate; -use chalk_ir::{BoundVar, DebruijnIndex, cast::Cast}; -use hir_def::{ - expr_store::{HygieneId, path::Path}, - resolver::{Resolver, ValueNs}, - type_ref::LiteralConstRef, -}; -use stdx::never; - -use crate::{ - Const, ConstData, ConstScalar, ConstValue, GenericArg, Interner, MemoryMap, Substitution, - TraitEnvironment, Ty, - db::HirDatabase, - generics::Generics, - lower::ParamLoweringMode, - next_solver::{DbInterner, mapping::ChalkToNextSolver}, - to_placeholder_idx, -}; - -pub(crate) fn path_to_const<'g>( - db: &dyn HirDatabase, - resolver: &Resolver<'_>, - path: &Path, - mode: ParamLoweringMode, - args: impl FnOnce() -> &'g Generics, - debruijn: DebruijnIndex, - expected_ty: Ty, -) -> Option { - match resolver.resolve_path_in_value_ns_fully(db, path, HygieneId::ROOT) { - Some(ValueNs::GenericParam(p)) => { - let ty = db.const_param_ty(p); - let args = args(); - let value = match mode { - ParamLoweringMode::Placeholder => { - let idx = args.type_or_const_param_idx(p.into()).unwrap(); - ConstValue::Placeholder(to_placeholder_idx(db, p.into(), idx as u32)) - } - ParamLoweringMode::Variable => match args.type_or_const_param_idx(p.into()) { - Some(it) => ConstValue::BoundVar(BoundVar::new(debruijn, it)), - None => { - never!( - "Generic list doesn't contain this param: {:?}, {:?}, {:?}", - args, - path, - p - ); - return None; - } - }, - }; - Some(ConstData { ty, value }.intern(Interner)) - } - Some(ValueNs::ConstId(c)) => Some(intern_const_scalar( - ConstScalar::UnevaluatedConst(c.into(), Substitution::empty(Interner)), - expected_ty, - )), - // FIXME: With feature(adt_const_params), we also need to consider other things here, e.g. struct constructors. - _ => None, - } -} - -pub(crate) fn unknown_const(ty: Ty) -> Const { - ConstData { - ty, - value: ConstValue::Concrete(chalk_ir::ConcreteConst { interned: ConstScalar::Unknown }), - } - .intern(Interner) -} - -pub(crate) fn unknown_const_as_generic(ty: Ty) -> GenericArg { - unknown_const(ty).cast(Interner) -} - -/// Interns a constant scalar with the given type -pub(crate) fn intern_const_scalar(value: ConstScalar, ty: Ty) -> Const { - ConstData { ty, value: ConstValue::Concrete(chalk_ir::ConcreteConst { interned: value }) } - .intern(Interner) -} - -/// Interns a constant scalar with the given type -pub(crate) fn intern_const_ref( - db: &dyn HirDatabase, - value: &LiteralConstRef, - ty: Ty, - krate: Crate, -) -> Const { - let interner = DbInterner::new_with(db, Some(krate), None); - let layout = || db.layout_of_ty(ty.to_nextsolver(interner), TraitEnvironment::empty(krate)); - let bytes = match value { - LiteralConstRef::Int(i) => { - // FIXME: We should handle failure of layout better. - let size = layout().map(|it| it.size.bytes_usize()).unwrap_or(16); - ConstScalar::Bytes(i.to_le_bytes()[0..size].into(), MemoryMap::default()) - } - LiteralConstRef::UInt(i) => { - let size = layout().map(|it| it.size.bytes_usize()).unwrap_or(16); - ConstScalar::Bytes(i.to_le_bytes()[0..size].into(), MemoryMap::default()) - } - LiteralConstRef::Bool(b) => ConstScalar::Bytes(Box::new([*b as u8]), MemoryMap::default()), - LiteralConstRef::Char(c) => { - ConstScalar::Bytes((*c as u32).to_le_bytes().into(), MemoryMap::default()) - } - LiteralConstRef::Unknown => ConstScalar::Unknown, - }; - intern_const_scalar(bytes, ty) -} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs index 4b33c8a84a81..9b58abbe4f92 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs @@ -1,8 +1,7 @@ //! The home of `HirDatabase`, which is the Salsa database containing all the //! type inference-related queries. -use base_db::Crate; -use base_db::target::TargetLoadError; +use base_db::{Crate, target::TargetLoadError}; use hir_def::{ AdtId, BlockId, CallableDefId, ConstParamId, DefWithBodyId, EnumVariantId, FunctionId, GeneralConstId, GenericDefId, ImplId, LifetimeParamId, LocalFieldId, StaticId, TraitId, @@ -16,15 +15,14 @@ use smallvec::SmallVec; use triomphe::Arc; use crate::{ - Binders, ImplTraitId, ImplTraits, InferenceResult, TraitEnvironment, Ty, TyDefId, ValueTyDefId, - chalk_db, + ImplTraitId, InferenceResult, TraitEnvironment, TyDefId, ValueTyDefId, consteval::ConstEvalError, dyn_compatibility::DynCompatibilityViolation, layout::{Layout, LayoutError}, - lower::{Diagnostics, GenericDefaults, GenericPredicates}, + lower::{Diagnostics, GenericDefaults, GenericPredicates, ImplTraits}, method_resolution::{InherentImpls, TraitImpls, TyFingerprint}, mir::{BorrowckResult, MirBody, MirLowerError}, - traits::NextTraitSolveResult, + next_solver::{Const, EarlyBinder, GenericArgs, PolyFnSig, TraitRef, Ty, VariancesOf}, }; #[query_group::query_group] @@ -53,7 +51,7 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug { fn monomorphized_mir_body<'db>( &'db self, def: DefWithBodyId, - subst: crate::next_solver::GenericArgs<'db>, + subst: GenericArgs<'db>, env: Arc>, ) -> Result>, MirLowerError<'db>>; @@ -61,7 +59,7 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug { fn monomorphized_mir_body_for_closure<'db>( &'db self, def: InternedClosureId, - subst: crate::next_solver::GenericArgs<'db>, + subst: GenericArgs<'db>, env: Arc>, ) -> Result>, MirLowerError<'db>>; @@ -77,16 +75,13 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug { fn const_eval<'db>( &'db self, def: GeneralConstId, - subst: crate::next_solver::GenericArgs<'db>, + subst: GenericArgs<'db>, trait_env: Option>>, - ) -> Result, ConstEvalError<'db>>; + ) -> Result, ConstEvalError<'db>>; #[salsa::invoke(crate::consteval::const_eval_static_query)] #[salsa::cycle(cycle_result = crate::consteval::const_eval_static_cycle_result)] - fn const_eval_static<'db>( - &'db self, - def: StaticId, - ) -> Result, ConstEvalError<'db>>; + fn const_eval_static<'db>(&'db self, def: StaticId) -> Result, ConstEvalError<'db>>; #[salsa::invoke(crate::consteval::const_eval_discriminant_variant)] #[salsa::cycle(cycle_result = crate::consteval::const_eval_discriminant_cycle_result)] @@ -96,12 +91,13 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug { ) -> Result>; #[salsa::invoke(crate::method_resolution::lookup_impl_method_query)] + #[salsa::transparent] fn lookup_impl_method<'db>( &'db self, env: Arc>, func: FunctionId, - fn_subst: crate::next_solver::GenericArgs<'db>, - ) -> (FunctionId, crate::next_solver::GenericArgs<'db>); + fn_subst: GenericArgs<'db>, + ) -> (FunctionId, GenericArgs<'db>); // endregion:mir @@ -110,7 +106,7 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug { fn layout_of_adt<'db>( &'db self, def: AdtId, - args: crate::next_solver::GenericArgs<'db>, + args: GenericArgs<'db>, trait_env: Arc>, ) -> Result, LayoutError>; @@ -118,7 +114,7 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug { #[salsa::cycle(cycle_result = crate::layout::layout_of_ty_cycle_result)] fn layout_of_ty<'db>( &'db self, - ty: crate::next_solver::Ty<'db>, + ty: Ty<'db>, env: Arc>, ) -> Result, LayoutError>; @@ -128,149 +124,130 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug { #[salsa::invoke(crate::dyn_compatibility::dyn_compatibility_of_trait_query)] fn dyn_compatibility_of_trait(&self, trait_: TraitId) -> Option; - #[salsa::invoke(crate::lower_nextsolver::ty_query)] + #[salsa::invoke(crate::lower::ty_query)] #[salsa::transparent] - fn ty<'db>( - &'db self, - def: TyDefId, - ) -> crate::next_solver::EarlyBinder<'db, crate::next_solver::Ty<'db>>; + fn ty<'db>(&'db self, def: TyDefId) -> EarlyBinder<'db, Ty<'db>>; - #[salsa::invoke(crate::lower_nextsolver::type_for_type_alias_with_diagnostics_query)] - #[salsa::cycle(cycle_result = crate::lower_nextsolver::type_for_type_alias_with_diagnostics_cycle_result)] + #[salsa::invoke(crate::lower::type_for_type_alias_with_diagnostics_query)] + #[salsa::cycle(cycle_result = crate::lower::type_for_type_alias_with_diagnostics_cycle_result)] fn type_for_type_alias_with_diagnostics<'db>( &'db self, def: TypeAliasId, - ) -> (crate::next_solver::EarlyBinder<'db, crate::next_solver::Ty<'db>>, Diagnostics); + ) -> (EarlyBinder<'db, Ty<'db>>, Diagnostics); /// Returns the type of the value of the given constant, or `None` if the `ValueTyDefId` is /// a `StructId` or `EnumVariantId` with a record constructor. - #[salsa::invoke(crate::lower_nextsolver::value_ty_query)] - fn value_ty<'db>( - &'db self, - def: ValueTyDefId, - ) -> Option>>; + #[salsa::invoke(crate::lower::value_ty_query)] + fn value_ty<'db>(&'db self, def: ValueTyDefId) -> Option>>; - #[salsa::invoke(crate::lower_nextsolver::impl_self_ty_with_diagnostics_query)] - #[salsa::cycle(cycle_result = crate::lower_nextsolver::impl_self_ty_with_diagnostics_cycle_result)] + #[salsa::invoke(crate::lower::impl_self_ty_with_diagnostics_query)] + #[salsa::cycle(cycle_result = crate::lower::impl_self_ty_with_diagnostics_cycle_result)] fn impl_self_ty_with_diagnostics<'db>( &'db self, def: ImplId, - ) -> (crate::next_solver::EarlyBinder<'db, crate::next_solver::Ty<'db>>, Diagnostics); + ) -> (EarlyBinder<'db, Ty<'db>>, Diagnostics); - #[salsa::invoke(crate::lower_nextsolver::impl_self_ty_query)] + #[salsa::invoke(crate::lower::impl_self_ty_query)] #[salsa::transparent] - fn impl_self_ty<'db>( - &'db self, - def: ImplId, - ) -> crate::next_solver::EarlyBinder<'db, crate::next_solver::Ty<'db>>; + fn impl_self_ty<'db>(&'db self, def: ImplId) -> EarlyBinder<'db, Ty<'db>>; // FIXME: Make this a non-interned query. - #[salsa::invoke_interned(crate::lower_nextsolver::const_param_ty_with_diagnostics_query)] - #[salsa::cycle(cycle_result = crate::lower_nextsolver::const_param_ty_with_diagnostics_cycle_result)] - fn const_param_ty_with_diagnostics<'db>( - &'db self, - def: ConstParamId, - ) -> (crate::next_solver::Ty<'db>, Diagnostics); + #[salsa::invoke_interned(crate::lower::const_param_ty_with_diagnostics_query)] + #[salsa::cycle(cycle_result = crate::lower::const_param_ty_with_diagnostics_cycle_result)] + fn const_param_ty_with_diagnostics<'db>(&'db self, def: ConstParamId) + -> (Ty<'db>, Diagnostics); - // FIXME: Make this a non-interned query. - #[salsa::invoke_interned(crate::lower::const_param_ty_query)] - #[salsa::cycle(cycle_result = crate::lower::const_param_ty_cycle_result)] - fn const_param_ty(&self, def: ConstParamId) -> Ty; + #[salsa::invoke(crate::lower::const_param_ty_query)] + #[salsa::transparent] + fn const_param_ty_ns<'db>(&'db self, def: ConstParamId) -> Ty<'db>; - #[salsa::invoke(crate::lower_nextsolver::impl_trait_with_diagnostics_query)] + #[salsa::invoke(crate::lower::impl_trait_with_diagnostics_query)] fn impl_trait_with_diagnostics<'db>( &'db self, def: ImplId, - ) -> Option<( - crate::next_solver::EarlyBinder<'db, crate::next_solver::TraitRef<'db>>, - Diagnostics, - )>; + ) -> Option<(EarlyBinder<'db, TraitRef<'db>>, Diagnostics)>; - #[salsa::invoke(crate::lower_nextsolver::impl_trait_query)] + #[salsa::invoke(crate::lower::impl_trait_query)] #[salsa::transparent] - fn impl_trait<'db>( - &'db self, - def: ImplId, - ) -> Option>>; + fn impl_trait<'db>(&'db self, def: ImplId) -> Option>>; - #[salsa::invoke(crate::lower_nextsolver::field_types_with_diagnostics_query)] + #[salsa::invoke(crate::lower::field_types_with_diagnostics_query)] fn field_types_with_diagnostics<'db>( &'db self, var: VariantId, - ) -> ( - Arc< - ArenaMap< - LocalFieldId, - crate::next_solver::EarlyBinder<'db, crate::next_solver::Ty<'db>>, - >, - >, - Diagnostics, - ); + ) -> (Arc>>>, Diagnostics); #[salsa::invoke(crate::lower::field_types_query)] #[salsa::transparent] - fn field_types(&self, var: VariantId) -> Arc>>; + fn field_types<'db>( + &'db self, + var: VariantId, + ) -> Arc>>>; - #[salsa::invoke(crate::lower_nextsolver::callable_item_signature_query)] + #[salsa::invoke(crate::lower::callable_item_signature_query)] fn callable_item_signature<'db>( &'db self, def: CallableDefId, - ) -> crate::next_solver::EarlyBinder<'db, crate::next_solver::PolyFnSig<'db>>; + ) -> EarlyBinder<'db, PolyFnSig<'db>>; #[salsa::invoke(crate::lower::return_type_impl_traits)] - fn return_type_impl_traits(&self, def: FunctionId) -> Option>>; + fn return_type_impl_traits<'db>( + &'db self, + def: FunctionId, + ) -> Option>>>; #[salsa::invoke(crate::lower::type_alias_impl_traits)] - fn type_alias_impl_traits(&self, def: TypeAliasId) -> Option>>; + fn type_alias_impl_traits<'db>( + &'db self, + def: TypeAliasId, + ) -> Option>>>; - #[salsa::invoke(crate::lower::generic_predicates_for_param_query)] - #[salsa::cycle(cycle_result = crate::lower::generic_predicates_for_param_cycle_result)] - fn generic_predicates_for_param( - &self, - def: GenericDefId, - param_id: TypeOrConstParamId, - assoc_name: Option, - ) -> GenericPredicates; - - #[salsa::invoke(crate::lower::generic_predicates_query)] - fn generic_predicates(&self, def: GenericDefId) -> GenericPredicates; - - #[salsa::invoke( - crate::lower_nextsolver::generic_predicates_without_parent_with_diagnostics_query - )] + #[salsa::invoke(crate::lower::generic_predicates_without_parent_with_diagnostics_query)] fn generic_predicates_without_parent_with_diagnostics<'db>( &'db self, def: GenericDefId, - ) -> (crate::lower_nextsolver::GenericPredicates<'db>, Diagnostics); + ) -> (GenericPredicates<'db>, Diagnostics); - #[salsa::invoke(crate::lower_nextsolver::generic_predicates_without_parent_query)] + #[salsa::invoke(crate::lower::generic_predicates_without_parent_query)] #[salsa::transparent] fn generic_predicates_without_parent<'db>( &'db self, def: GenericDefId, - ) -> crate::lower_nextsolver::GenericPredicates<'db>; + ) -> GenericPredicates<'db>; - #[salsa::invoke(crate::lower_nextsolver::trait_environment_for_body_query)] + #[salsa::invoke(crate::lower::generic_predicates_for_param_query)] + #[salsa::cycle(cycle_result = crate::lower::generic_predicates_for_param_cycle_result)] + fn generic_predicates_for_param<'db>( + &'db self, + def: GenericDefId, + param_id: TypeOrConstParamId, + assoc_name: Option, + ) -> GenericPredicates<'db>; + + #[salsa::invoke(crate::lower::generic_predicates_query)] + fn generic_predicates<'db>(&'db self, def: GenericDefId) -> GenericPredicates<'db>; + + #[salsa::invoke(crate::lower::trait_environment_for_body_query)] #[salsa::transparent] fn trait_environment_for_body<'db>(&'db self, def: DefWithBodyId) -> Arc>; - #[salsa::invoke(crate::lower_nextsolver::trait_environment_query)] + #[salsa::invoke(crate::lower::trait_environment_query)] fn trait_environment<'db>(&'db self, def: GenericDefId) -> Arc>; #[salsa::invoke(crate::lower::generic_defaults_with_diagnostics_query)] #[salsa::cycle(cycle_result = crate::lower::generic_defaults_with_diagnostics_cycle_result)] - fn generic_defaults_with_diagnostics( - &self, + fn generic_defaults_with_diagnostics<'db>( + &'db self, def: GenericDefId, - ) -> (GenericDefaults, Diagnostics); + ) -> (GenericDefaults<'db>, Diagnostics); /// This returns an empty list if no parameter has default. /// /// The binders of the returned defaults are only up to (not including) this parameter. #[salsa::invoke(crate::lower::generic_defaults_query)] #[salsa::transparent] - fn generic_defaults(&self, def: GenericDefId) -> GenericDefaults; + fn generic_defaults<'db>(&'db self, def: GenericDefId) -> GenericDefaults<'db>; #[salsa::invoke(InherentImpls::inherent_impls_in_crate_query)] fn inherent_impls_in_crate(&self, krate: Crate) -> Arc; @@ -298,9 +275,9 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug { #[salsa::invoke(TraitImpls::trait_impls_in_deps_query)] fn trait_impls_in_deps(&self, krate: Crate) -> Arc<[Arc]>; - // Interned IDs for Chalk integration + // Interned IDs for solver integration #[salsa::interned] - fn intern_impl_trait_id(&self, id: ImplTraitId) -> InternedOpaqueTyId; + fn intern_impl_trait_id(&self, id: ImplTraitId<'_>) -> InternedOpaqueTyId; #[salsa::interned] fn intern_closure(&self, id: InternedClosure) -> InternedClosureId; @@ -308,95 +285,13 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug { #[salsa::interned] fn intern_coroutine(&self, id: InternedCoroutine) -> InternedCoroutineId; - #[salsa::invoke(chalk_db::fn_def_variance_query)] - fn fn_def_variance(&self, fn_def_id: CallableDefId) -> chalk_db::Variances; - - #[salsa::invoke(chalk_db::adt_variance_query)] - fn adt_variance(&self, adt_id: AdtId) -> chalk_db::Variances; - #[salsa::invoke(crate::variance::variances_of)] #[salsa::cycle( // cycle_fn = crate::variance::variances_of_cycle_fn, // cycle_initial = crate::variance::variances_of_cycle_initial, cycle_result = crate::variance::variances_of_cycle_initial, )] - fn variances_of(&self, def: GenericDefId) -> Option>; - - #[salsa::invoke(crate::traits::normalize_projection_query)] - #[salsa::transparent] - fn normalize_projection( - &self, - projection: crate::ProjectionTy, - env: Arc>, - ) -> Ty; - - #[salsa::invoke(crate::traits::trait_solve_query)] - #[salsa::transparent] - fn trait_solve( - &self, - krate: Crate, - block: Option, - goal: crate::Canonical>, - ) -> NextTraitSolveResult; - - // next trait solver - - #[salsa::invoke(crate::lower_nextsolver::const_param_ty_query)] - #[salsa::transparent] - fn const_param_ty_ns<'db>(&'db self, def: ConstParamId) -> crate::next_solver::Ty<'db>; - - #[salsa::invoke(crate::lower_nextsolver::field_types_query)] - #[salsa::transparent] - fn field_types_ns<'db>( - &'db self, - var: VariantId, - ) -> Arc< - ArenaMap>>, - >; - - #[salsa::invoke(crate::lower_nextsolver::return_type_impl_traits)] - fn return_type_impl_traits_ns<'db>( - &'db self, - def: FunctionId, - ) -> Option>>>; - - #[salsa::invoke(crate::lower_nextsolver::type_alias_impl_traits)] - fn type_alias_impl_traits_ns<'db>( - &'db self, - def: TypeAliasId, - ) -> Option>>>; - - #[salsa::invoke(crate::lower_nextsolver::generic_predicates_for_param_query)] - #[salsa::cycle(cycle_result = crate::lower_nextsolver::generic_predicates_for_param_cycle_result)] - fn generic_predicates_for_param_ns<'db>( - &'db self, - def: GenericDefId, - param_id: TypeOrConstParamId, - assoc_name: Option, - ) -> crate::lower_nextsolver::GenericPredicates<'db>; - - #[salsa::invoke(crate::lower_nextsolver::generic_predicates_query)] - fn generic_predicates_ns<'db>( - &'db self, - def: GenericDefId, - ) -> crate::lower_nextsolver::GenericPredicates<'db>; - - #[salsa::invoke(crate::lower_nextsolver::generic_defaults_with_diagnostics_query)] - #[salsa::cycle(cycle_result = crate::lower_nextsolver::generic_defaults_with_diagnostics_cycle_result)] - fn generic_defaults_ns_with_diagnostics<'db>( - &'db self, - def: GenericDefId, - ) -> (crate::lower_nextsolver::GenericDefaults<'db>, Diagnostics); - - /// This returns an empty list if no parameter has default. - /// - /// The binders of the returned defaults are only up to (not including) this parameter. - #[salsa::invoke(crate::lower_nextsolver::generic_defaults_query)] - #[salsa::transparent] - fn generic_defaults_ns<'db>( - &'db self, - def: GenericDefId, - ) -> crate::lower_nextsolver::GenericDefaults<'db>; + fn variances_of<'db>(&'db self, def: GenericDefId) -> VariancesOf<'db>; } #[test] @@ -427,7 +322,7 @@ pub struct InternedConstParamId { #[salsa_macros::interned(no_lifetime, debug, revisions = usize::MAX)] #[derive(PartialOrd, Ord)] pub struct InternedOpaqueTyId { - pub loc: ImplTraitId, + pub loc: ImplTraitId<'db>, } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs index 7b6fb994ecaf..0eca0c09d690 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs @@ -15,6 +15,7 @@ use intern::sym; use itertools::Itertools; use rustc_hash::FxHashSet; use rustc_pattern_analysis::constructor::Constructor; +use rustc_type_ir::inherent::{AdtDef, IntoKind}; use syntax::{ AstNode, ast::{self, UnaryOp}, @@ -23,16 +24,18 @@ use tracing::debug; use triomphe::Arc; use typed_arena::Arena; -use crate::next_solver::DbInterner; -use crate::next_solver::mapping::NextSolverToChalk; use crate::{ - Adjust, InferenceResult, Interner, TraitEnvironment, Ty, TyExt, TyKind, + Adjust, InferenceResult, TraitEnvironment, db::HirDatabase, diagnostics::match_check::{ self, pat_analysis::{self, DeconstructedPat, MatchCheckCtx, WitnessPat}, }, display::{DisplayTarget, HirDisplay}, + next_solver::{ + DbInterner, Ty, TyKind, TypingMode, + infer::{DbInternerInferExt, InferCtxt}, + }, }; pub(crate) use hir_def::{ @@ -77,6 +80,8 @@ impl BodyValidationDiagnostic { let body = db.body(owner); let env = db.trait_environment_for_body(owner); let interner = DbInterner::new_with(db, Some(env.krate), env.block); + let infcx = + interner.infer_ctxt().build(TypingMode::typeck_for_body(interner, owner.into())); let mut validator = ExprValidator { owner, body, @@ -84,9 +89,9 @@ impl BodyValidationDiagnostic { diagnostics: Vec::new(), validate_lints, env, - interner, + infcx, }; - validator.validate_body(db); + validator.validate_body(); validator.diagnostics } } @@ -98,11 +103,17 @@ struct ExprValidator<'db> { env: Arc>, diagnostics: Vec, validate_lints: bool, - interner: DbInterner<'db>, + infcx: InferCtxt<'db>, } impl<'db> ExprValidator<'db> { - fn validate_body(&mut self, db: &'db dyn HirDatabase) { + #[inline] + fn db(&self) -> &'db dyn HirDatabase { + self.infcx.interner.db + } + + fn validate_body(&mut self) { + let db = self.db(); let mut filter_map_next_checker = None; // we'll pass &mut self while iterating over body.exprs, so they need to be disjoint let body = Arc::clone(&self.body); @@ -124,19 +135,19 @@ impl<'db> ExprValidator<'db> { match expr { Expr::Match { expr, arms } => { - self.validate_match(id, *expr, arms, db); + self.validate_match(id, *expr, arms); } Expr::Call { .. } | Expr::MethodCall { .. } => { - self.validate_call(db, id, expr, &mut filter_map_next_checker); + self.validate_call(id, expr, &mut filter_map_next_checker); } Expr::Closure { body: body_expr, .. } => { self.check_for_trailing_return(*body_expr, &body); } Expr::If { .. } => { - self.check_for_unnecessary_else(id, expr, db); + self.check_for_unnecessary_else(id, expr); } Expr::Block { .. } | Expr::Async { .. } | Expr::Unsafe { .. } => { - self.validate_block(db, expr); + self.validate_block(expr); } _ => {} } @@ -157,10 +168,9 @@ impl<'db> ExprValidator<'db> { fn validate_call( &mut self, - db: &dyn HirDatabase, call_id: ExprId, expr: &Expr, - filter_map_next_checker: &mut Option, + filter_map_next_checker: &mut Option>, ) { if !self.validate_lints { return; @@ -176,8 +186,9 @@ impl<'db> ExprValidator<'db> { None => return, }; - let checker = filter_map_next_checker - .get_or_insert_with(|| FilterMapNextChecker::new(&self.owner.resolver(db), db)); + let checker = filter_map_next_checker.get_or_insert_with(|| { + FilterMapNextChecker::new(&self.owner.resolver(self.db()), self.db()) + }); if checker.check(call_id, receiver, &callee).is_some() { self.diagnostics.push(BodyValidationDiagnostic::ReplaceFilterMapNextWithFindMap { @@ -186,27 +197,20 @@ impl<'db> ExprValidator<'db> { } if let Some(receiver_ty) = self.infer.type_of_expr_with_adjust(*receiver) { - checker.prev_receiver_ty = Some(receiver_ty.to_chalk(self.interner)); + checker.prev_receiver_ty = Some(receiver_ty); } } } - fn validate_match( - &mut self, - match_expr: ExprId, - scrutinee_expr: ExprId, - arms: &[MatchArm], - db: &dyn HirDatabase, - ) { + fn validate_match(&mut self, match_expr: ExprId, scrutinee_expr: ExprId, arms: &[MatchArm]) { let Some(scrut_ty) = self.infer.type_of_expr_with_adjust(scrutinee_expr) else { return; }; - let scrut_ty = scrut_ty.to_chalk(self.interner); - if scrut_ty.contains_unknown() { + if scrut_ty.references_non_lt_error() { return; } - let cx = MatchCheckCtx::new(self.owner.module(db), self.owner, db, self.env.clone()); + let cx = MatchCheckCtx::new(self.owner.module(self.db()), &self.infcx, self.env.clone()); let pattern_arena = Arena::new(); let mut m_arms = Vec::with_capacity(arms.len()); @@ -217,8 +221,7 @@ impl<'db> ExprValidator<'db> { let Some(pat_ty) = self.infer.type_of_pat_with_adjust(arm.pat) else { return; }; - let pat_ty = pat_ty.to_chalk(self.interner); - if pat_ty.contains_unknown() { + if pat_ty.references_non_lt_error() { return; } @@ -235,14 +238,14 @@ impl<'db> ExprValidator<'db> { if (pat_ty == scrut_ty || scrut_ty .as_reference() - .map(|(match_expr_ty, ..)| *match_expr_ty == pat_ty) + .map(|(match_expr_ty, ..)| match_expr_ty == pat_ty) .unwrap_or(false)) && types_of_subpatterns_do_match(arm.pat, &self.body, &self.infer) { // If we had a NotUsefulMatchArm diagnostic, we could // check the usefulness of each pattern as we added it // to the matrix here. - let pat = self.lower_pattern(&cx, arm.pat, db, &mut has_lowering_errors); + let pat = self.lower_pattern(&cx, arm.pat, &mut has_lowering_errors); let m_arm = pat_analysis::MatchArm { pat: pattern_arena.alloc(pat), has_guard: arm.guard.is_some(), @@ -258,15 +261,12 @@ impl<'db> ExprValidator<'db> { return; } - let known_valid_scrutinee = Some(self.is_known_valid_scrutinee(scrutinee_expr, db)); - let report = match cx.compute_match_usefulness( - m_arms.as_slice(), - scrut_ty.clone(), - known_valid_scrutinee, - ) { - Ok(report) => report, - Err(()) => return, - }; + let known_valid_scrutinee = Some(self.is_known_valid_scrutinee(scrutinee_expr)); + let report = + match cx.compute_match_usefulness(m_arms.as_slice(), scrut_ty, known_valid_scrutinee) { + Ok(report) => report, + Err(()) => return, + }; // FIXME Report unreachable arms // https://github.com/rust-lang/rust/blob/f31622a50/compiler/rustc_mir_build/src/thir/pattern/check_match.rs#L200 @@ -277,10 +277,10 @@ impl<'db> ExprValidator<'db> { match_expr, uncovered_patterns: missing_match_arms( &cx, - &scrut_ty, + scrut_ty, witnesses, m_arms.is_empty(), - self.owner.krate(db), + self.owner.krate(self.db()), ), }); } @@ -291,7 +291,9 @@ impl<'db> ExprValidator<'db> { // While the above function in rustc uses thir exprs, r-a doesn't have them. // So, the logic here is getting same result as "hir lowering + match with lowered thir" // with "hir only" - fn is_known_valid_scrutinee(&self, scrutinee_expr: ExprId, db: &dyn HirDatabase) -> bool { + fn is_known_valid_scrutinee(&self, scrutinee_expr: ExprId) -> bool { + let db = self.db(); + if self .infer .expr_adjustments @@ -311,20 +313,18 @@ impl<'db> ExprValidator<'db> { ); value_or_partial.is_none_or(|v| !matches!(v, ValueNs::StaticId(_))) } - Expr::Field { expr, .. } => { - match self.infer.type_of_expr[*expr].to_chalk(self.interner).kind(Interner) { - TyKind::Adt(adt, ..) if matches!(adt.0, AdtId::UnionId(_)) => false, - _ => self.is_known_valid_scrutinee(*expr, db), - } - } - Expr::Index { base, .. } => self.is_known_valid_scrutinee(*base, db), - Expr::Cast { expr, .. } => self.is_known_valid_scrutinee(*expr, db), + Expr::Field { expr, .. } => match self.infer.type_of_expr[*expr].kind() { + TyKind::Adt(adt, ..) if matches!(adt.def_id().0, AdtId::UnionId(_)) => false, + _ => self.is_known_valid_scrutinee(*expr), + }, + Expr::Index { base, .. } => self.is_known_valid_scrutinee(*base), + Expr::Cast { expr, .. } => self.is_known_valid_scrutinee(*expr), Expr::Missing => false, _ => true, } } - fn validate_block(&mut self, db: &dyn HirDatabase, expr: &Expr) { + fn validate_block(&mut self, expr: &Expr) { let (Expr::Block { statements, .. } | Expr::Async { statements, .. } | Expr::Unsafe { statements, .. }) = expr @@ -332,7 +332,7 @@ impl<'db> ExprValidator<'db> { return; }; let pattern_arena = Arena::new(); - let cx = MatchCheckCtx::new(self.owner.module(db), self.owner, db, self.env.clone()); + let cx = MatchCheckCtx::new(self.owner.module(self.db()), &self.infcx, self.env.clone()); for stmt in &**statements { let &Statement::Let { pat, initializer, else_branch: None, .. } = stmt else { continue; @@ -342,13 +342,12 @@ impl<'db> ExprValidator<'db> { } let Some(initializer) = initializer else { continue }; let Some(ty) = self.infer.type_of_expr_with_adjust(initializer) else { continue }; - let ty = ty.to_chalk(self.interner); - if ty.contains_unknown() { + if ty.references_non_lt_error() { continue; } let mut have_errors = false; - let deconstructed_pat = self.lower_pattern(&cx, pat, db, &mut have_errors); + let deconstructed_pat = self.lower_pattern(&cx, pat, &mut have_errors); // optimization, wildcard trivially hold if have_errors || matches!(deconstructed_pat.ctor(), Constructor::Wildcard) { @@ -360,7 +359,7 @@ impl<'db> ExprValidator<'db> { has_guard: false, arm_data: (), }; - let report = match cx.compute_match_usefulness(&[match_arm], ty.clone(), None) { + let report = match cx.compute_match_usefulness(&[match_arm], ty, None) { Ok(v) => v, Err(e) => { debug!(?e, "match usefulness error"); @@ -373,24 +372,23 @@ impl<'db> ExprValidator<'db> { pat, uncovered_patterns: missing_match_arms( &cx, - &ty, + ty, witnesses, false, - self.owner.krate(db), + self.owner.krate(self.db()), ), }); } } } - fn lower_pattern<'p>( + fn lower_pattern<'a>( &self, - cx: &MatchCheckCtx<'p>, + cx: &MatchCheckCtx<'a, 'db>, pat: PatId, - db: &dyn HirDatabase, have_errors: &mut bool, - ) -> DeconstructedPat<'p> { - let mut patcx = match_check::PatCtxt::new(db, &self.infer, &self.body); + ) -> DeconstructedPat<'a, 'db> { + let mut patcx = match_check::PatCtxt::new(self.db(), &self.infer, &self.body); let pattern = patcx.lower_pattern(pat); let pattern = cx.lower_pat(&pattern); if !patcx.errors.is_empty() { @@ -434,7 +432,7 @@ impl<'db> ExprValidator<'db> { } } - fn check_for_unnecessary_else(&mut self, id: ExprId, expr: &Expr, db: &dyn HirDatabase) { + fn check_for_unnecessary_else(&mut self, id: ExprId, expr: &Expr) { if !self.validate_lints { return; } @@ -453,11 +451,11 @@ impl<'db> ExprValidator<'db> { && last_then_expr_ty.is_never() { // Only look at sources if the then branch diverges and we have an else branch. - let source_map = db.body_with_source_map(self.owner).1; + let source_map = self.db().body_with_source_map(self.owner).1; let Ok(source_ptr) = source_map.expr_syntax(id) else { return; }; - let root = source_ptr.file_syntax(db); + let root = source_ptr.file_syntax(self.db()); let either::Left(ast::Expr::IfExpr(if_expr)) = source_ptr.value.to_node(&root) else { return; @@ -491,15 +489,15 @@ impl<'db> ExprValidator<'db> { } } -struct FilterMapNextChecker { +struct FilterMapNextChecker<'db> { filter_map_function_id: Option, next_function_id: Option, prev_filter_map_expr_id: Option, - prev_receiver_ty: Option>, + prev_receiver_ty: Option>, } -impl FilterMapNextChecker { - fn new(resolver: &hir_def::resolver::Resolver<'_>, db: &dyn HirDatabase) -> Self { +impl<'db> FilterMapNextChecker<'db> { + fn new(resolver: &hir_def::resolver::Resolver<'db>, db: &'db dyn HirDatabase) -> Self { // Find and store the FunctionIds for Iterator::filter_map and Iterator::next let (next_function_id, filter_map_function_id) = match LangItem::IteratorNext .resolve_function(db, resolver.krate()) @@ -639,15 +637,19 @@ fn types_of_subpatterns_do_match(pat: PatId, body: &Body, infer: &InferenceResul !has_type_mismatches } -fn missing_match_arms<'p>( - cx: &MatchCheckCtx<'p>, - scrut_ty: &Ty, - witnesses: Vec>, +fn missing_match_arms<'a, 'db>( + cx: &MatchCheckCtx<'a, 'db>, + scrut_ty: Ty<'a>, + witnesses: Vec>, arms_is_empty: bool, krate: Crate, ) -> String { - struct DisplayWitness<'a, 'p>(&'a WitnessPat<'p>, &'a MatchCheckCtx<'p>, DisplayTarget); - impl fmt::Display for DisplayWitness<'_, '_> { + struct DisplayWitness<'a, 'b, 'db>( + &'a WitnessPat<'b, 'db>, + &'a MatchCheckCtx<'b, 'db>, + DisplayTarget, + ); + impl fmt::Display for DisplayWitness<'_, '_, '_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let DisplayWitness(witness, cx, display_target) = *self; let pat = cx.hoist_witness_pat(witness); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check.rs index af541ffa342e..80b65ace77cd 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check.rs @@ -9,7 +9,6 @@ mod pat_util; pub(crate) mod pat_analysis; -use chalk_ir::Mutability; use hir_def::{ AdtId, EnumVariantId, LocalFieldId, Lookup, VariantId, expr_store::{Body, path::Path}, @@ -17,16 +16,16 @@ use hir_def::{ item_tree::FieldsShape, }; use hir_expand::name::Name; +use rustc_type_ir::inherent::{IntoKind, SliceLike}; use span::Edition; -use stdx::{always, never}; +use stdx::{always, never, variance::PhantomCovariantLifetime}; -use crate::next_solver::DbInterner; -use crate::next_solver::mapping::NextSolverToChalk; use crate::{ - InferenceResult, Interner, Substitution, Ty, TyExt, TyKind, + InferenceResult, db::HirDatabase, display::{HirDisplay, HirDisplayError, HirFormatter}, infer::BindingMode, + next_solver::{GenericArgs, Mutability, Ty, TyKind}, }; use self::pat_util::EnumerateAndAdjustIterator; @@ -41,46 +40,46 @@ pub(crate) enum PatternError { } #[derive(Clone, Debug, PartialEq)] -pub(crate) struct FieldPat { +pub(crate) struct FieldPat<'db> { pub(crate) field: LocalFieldId, - pub(crate) pattern: Pat, + pub(crate) pattern: Pat<'db>, } #[derive(Clone, Debug, PartialEq)] -pub(crate) struct Pat { - pub(crate) ty: Ty, - pub(crate) kind: Box, +pub(crate) struct Pat<'db> { + pub(crate) ty: Ty<'db>, + pub(crate) kind: Box>, } /// Close relative to `rustc_mir_build::thir::pattern::PatKind` #[derive(Clone, Debug, PartialEq)] -pub(crate) enum PatKind { +pub(crate) enum PatKind<'db> { Wild, Never, /// `x`, `ref x`, `x @ P`, etc. Binding { name: Name, - subpattern: Option, + subpattern: Option>, }, /// `Foo(...)` or `Foo{...}` or `Foo`, where `Foo` is a variant name from an ADT with /// multiple variants. Variant { - substs: Substitution, + substs: GenericArgs<'db>, enum_variant: EnumVariantId, - subpatterns: Vec, + subpatterns: Vec>, }, /// `(...)`, `Foo(...)`, `Foo{...}`, or `Foo`, where `Foo` is a variant name from an ADT with /// a single variant. Leaf { - subpatterns: Vec, + subpatterns: Vec>, }, /// `&P`, `&mut P`, etc. Deref { - subpattern: Pat, + subpattern: Pat<'db>, }, // FIXME: for now, only bool literals are implemented @@ -91,28 +90,27 @@ pub(crate) enum PatKind { /// An or-pattern, e.g. `p | q`. /// Invariant: `pats.len() >= 2`. Or { - pats: Vec, + pats: Vec>, }, } -pub(crate) struct PatCtxt<'db> { +pub(crate) struct PatCtxt<'a, 'db> { db: &'db dyn HirDatabase, - infer: &'db InferenceResult<'db>, - body: &'db Body, + infer: &'a InferenceResult<'db>, + body: &'a Body, pub(crate) errors: Vec, - interner: DbInterner<'db>, } -impl<'a> PatCtxt<'a> { +impl<'a, 'db> PatCtxt<'a, 'db> { pub(crate) fn new( - db: &'a dyn HirDatabase, - infer: &'a InferenceResult<'a>, + db: &'db dyn HirDatabase, + infer: &'a InferenceResult<'db>, body: &'a Body, ) -> Self { - Self { db, infer, body, errors: Vec::new(), interner: DbInterner::new_with(db, None, None) } + Self { db, infer, body, errors: Vec::new() } } - pub(crate) fn lower_pattern(&mut self, pat: PatId) -> Pat { + pub(crate) fn lower_pattern(&mut self, pat: PatId) -> Pat<'db> { // XXX(iDawer): Collecting pattern adjustments feels imprecise to me. // When lowering of & and box patterns are implemented this should be tested // in a manner of `match_ergonomics_issue_9095` test. @@ -121,15 +119,12 @@ impl<'a> PatCtxt<'a> { let unadjusted_pat = self.lower_pattern_unadjusted(pat); self.infer.pat_adjustments.get(&pat).map(|it| &**it).unwrap_or_default().iter().rev().fold( unadjusted_pat, - |subpattern, ref_ty| Pat { - ty: ref_ty.to_chalk(self.interner).clone(), - kind: Box::new(PatKind::Deref { subpattern }), - }, + |subpattern, ref_ty| Pat { ty: *ref_ty, kind: Box::new(PatKind::Deref { subpattern }) }, ) } - fn lower_pattern_unadjusted(&mut self, pat: PatId) -> Pat { - let mut ty = self.infer[pat].to_chalk(self.interner); + fn lower_pattern_unadjusted(&mut self, pat: PatId) -> Pat<'db> { + let mut ty = self.infer[pat]; let variant = self.infer.variant_resolution_for_pat(pat); let kind = match self.body[pat] { @@ -142,8 +137,8 @@ impl<'a> PatCtxt<'a> { } hir_def::hir::Pat::Tuple { ref args, ellipsis } => { - let arity = match *ty.kind(Interner) { - TyKind::Tuple(arity, _) => arity, + let arity = match ty.kind() { + TyKind::Tuple(tys) => tys.len(), _ => { never!("unexpected type for tuple pattern: {:?}", ty); self.errors.push(PatternError::UnexpectedType); @@ -156,10 +151,10 @@ impl<'a> PatCtxt<'a> { hir_def::hir::Pat::Bind { id, subpat, .. } => { let bm = self.infer.binding_modes[pat]; - ty = self.infer[id].to_chalk(self.interner); + ty = self.infer[id]; let name = &self.body[id].name; - match (bm, ty.kind(Interner)) { - (BindingMode::Ref(_), TyKind::Ref(.., rty)) => ty = rty.clone(), + match (bm, ty.kind()) { + (BindingMode::Ref(_), TyKind::Ref(_, rty, _)) => ty = rty, (BindingMode::Ref(_), _) => { never!( "`ref {}` has wrong type {:?}", @@ -167,7 +162,7 @@ impl<'a> PatCtxt<'a> { ty ); self.errors.push(PatternError::UnexpectedType); - return Pat { ty: ty.clone(), kind: PatKind::Wild.into() }; + return Pat { ty, kind: PatKind::Wild.into() }; } _ => (), } @@ -177,7 +172,7 @@ impl<'a> PatCtxt<'a> { hir_def::hir::Pat::TupleStruct { ref args, ellipsis, .. } if variant.is_some() => { let expected_len = variant.unwrap().fields(self.db).fields().len(); let subpatterns = self.lower_tuple_subpats(args, expected_len, ellipsis); - self.lower_variant_or_leaf(pat, &ty, subpatterns) + self.lower_variant_or_leaf(pat, ty, subpatterns) } hir_def::hir::Pat::Record { ref args, .. } if variant.is_some() => { @@ -193,7 +188,7 @@ impl<'a> PatCtxt<'a> { }) .collect(); match subpatterns { - Some(subpatterns) => self.lower_variant_or_leaf(pat, &ty, subpatterns), + Some(subpatterns) => self.lower_variant_or_leaf(pat, ty, subpatterns), None => { self.errors.push(PatternError::MissingField); PatKind::Wild @@ -213,7 +208,7 @@ impl<'a> PatCtxt<'a> { } }; - Pat { ty: ty.clone(), kind: Box::new(kind) } + Pat { ty, kind: Box::new(kind) } } fn lower_tuple_subpats( @@ -221,7 +216,7 @@ impl<'a> PatCtxt<'a> { pats: &[PatId], expected_len: usize, ellipsis: Option, - ) -> Vec { + ) -> Vec> { if pats.len() > expected_len { self.errors.push(PatternError::ExtraFields); return Vec::new(); @@ -236,28 +231,28 @@ impl<'a> PatCtxt<'a> { .collect() } - fn lower_patterns(&mut self, pats: &[PatId]) -> Vec { + fn lower_patterns(&mut self, pats: &[PatId]) -> Vec> { pats.iter().map(|&p| self.lower_pattern(p)).collect() } - fn lower_opt_pattern(&mut self, pat: Option) -> Option { + fn lower_opt_pattern(&mut self, pat: Option) -> Option> { pat.map(|p| self.lower_pattern(p)) } fn lower_variant_or_leaf( &mut self, pat: PatId, - ty: &Ty, - subpatterns: Vec, - ) -> PatKind { + ty: Ty<'db>, + subpatterns: Vec>, + ) -> PatKind<'db> { match self.infer.variant_resolution_for_pat(pat) { Some(variant_id) => { if let VariantId::EnumVariantId(enum_variant) = variant_id { - let substs = match ty.kind(Interner) { - TyKind::Adt(_, substs) => substs.clone(), + let substs = match ty.kind() { + TyKind::Adt(_, substs) => substs, kind => { always!( - matches!(kind, TyKind::FnDef(..) | TyKind::Error), + matches!(kind, TyKind::FnDef(..) | TyKind::Error(_)), "inappropriate type for def: {:?}", ty ); @@ -277,13 +272,13 @@ impl<'a> PatCtxt<'a> { } } - fn lower_path(&mut self, pat: PatId, _path: &Path) -> Pat { - let ty = self.infer[pat].to_chalk(self.interner); + fn lower_path(&mut self, pat: PatId, _path: &Path) -> Pat<'db> { + let ty = self.infer[pat]; - let pat_from_kind = |kind| Pat { ty: ty.clone(), kind: Box::new(kind) }; + let pat_from_kind = |kind| Pat { ty, kind: Box::new(kind) }; match self.infer.variant_resolution_for_pat(pat) { - Some(_) => pat_from_kind(self.lower_variant_or_leaf(pat, &ty, Vec::new())), + Some(_) => pat_from_kind(self.lower_variant_or_leaf(pat, ty, Vec::new())), None => { self.errors.push(PatternError::UnresolvedVariant); pat_from_kind(PatKind::Wild) @@ -291,7 +286,7 @@ impl<'a> PatCtxt<'a> { } } - fn lower_lit(&mut self, expr: hir_def::hir::ExprId) -> PatKind { + fn lower_lit(&mut self, expr: hir_def::hir::ExprId) -> PatKind<'db> { use hir_def::hir::{Expr, Literal::Bool}; match self.body[expr] { @@ -304,8 +299,8 @@ impl<'a> PatCtxt<'a> { } } -impl HirDisplay for Pat { - fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { +impl<'db> HirDisplay<'db> for Pat<'db> { + fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> { match &*self.kind { PatKind::Wild => write!(f, "_"), PatKind::Never => write!(f, "!"), @@ -361,7 +356,7 @@ impl HirDisplay for Pat { .filter(|p| !matches!(*p.pattern.kind, PatKind::Wild)) .map(|p| { printed += 1; - WriteWith(|f| { + WriteWith::new(|f| { write!( f, "{}: ", @@ -387,7 +382,7 @@ impl HirDisplay for Pat { if num_fields != 0 || variant.is_none() { write!(f, "(")?; let subpats = (0..num_fields).map(|i| { - WriteWith(move |f| { + WriteWith::new(move |f| { let fid = LocalFieldId::from_raw((i as u32).into()); if let Some(p) = subpatterns.get(i) && p.field == fid @@ -402,7 +397,7 @@ impl HirDisplay for Pat { }) }); f.write_joined(subpats, ", ")?; - if let (TyKind::Tuple(..), 1) = (self.ty.kind(Interner), num_fields) { + if let (TyKind::Tuple(..), 1) = (self.ty.kind(), num_fields) { write!(f, ",")?; } write!(f, ")")?; @@ -411,8 +406,8 @@ impl HirDisplay for Pat { Ok(()) } PatKind::Deref { subpattern } => { - match self.ty.kind(Interner) { - &TyKind::Ref(mutbl, ..) => { + match self.ty.kind() { + TyKind::Ref(.., mutbl) => { write!(f, "&{}", if mutbl == Mutability::Mut { "mut " } else { "" })? } _ => never!("{:?} is a bad Deref pattern type", self.ty), @@ -425,15 +420,24 @@ impl HirDisplay for Pat { } } -struct WriteWith(F) +struct WriteWith<'db, F>(F, PhantomCovariantLifetime<'db>) where - F: Fn(&mut HirFormatter<'_>) -> Result<(), HirDisplayError>; + F: Fn(&mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError>; -impl HirDisplay for WriteWith +impl<'db, F> WriteWith<'db, F> where - F: Fn(&mut HirFormatter<'_>) -> Result<(), HirDisplayError>, + F: Fn(&mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError>, { - fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { + fn new(f: F) -> Self { + Self(f, PhantomCovariantLifetime::new()) + } +} + +impl<'db, F> HirDisplay<'db> for WriteWith<'db, F> +where + F: Fn(&mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError>, +{ + fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> { (self.0)(f) } } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs index eb20d3c51ff4..fb942e336e65 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs @@ -1,24 +1,27 @@ //! Interface with `rustc_pattern_analysis`. -use std::cell::LazyCell; -use std::fmt; +use std::{cell::LazyCell, fmt}; -use hir_def::{DefWithBodyId, EnumId, EnumVariantId, HasModule, LocalFieldId, ModuleId, VariantId}; +use hir_def::{EnumId, EnumVariantId, HasModule, LocalFieldId, ModuleId, VariantId}; use intern::sym; use rustc_pattern_analysis::{ IndexVec, PatCx, PrivateUninhabitedField, constructor::{Constructor, ConstructorSet, VariantVisibility}, usefulness::{PlaceValidity, UsefulnessReport, compute_match_usefulness}, }; +use rustc_type_ir::inherent::{AdtDef, IntoKind, SliceLike}; use smallvec::{SmallVec, smallvec}; use stdx::never; use triomphe::Arc; use crate::{ - AdtId, Interner, Scalar, TraitEnvironment, Ty, TyExt, TyKind, + TraitEnvironment, db::HirDatabase, - infer::normalize, inhabitedness::{is_enum_variant_uninhabited_from, is_ty_uninhabited_from}, + next_solver::{ + Ty, TyKind, + infer::{InferCtxt, traits::ObligationCause}, + }, }; use super::{FieldPat, Pat, PatKind}; @@ -26,10 +29,12 @@ use super::{FieldPat, Pat, PatKind}; use Constructor::*; // Re-export r-a-specific versions of all these types. -pub(crate) type DeconstructedPat<'db> = - rustc_pattern_analysis::pat::DeconstructedPat>; -pub(crate) type MatchArm<'db> = rustc_pattern_analysis::MatchArm<'db, MatchCheckCtx<'db>>; -pub(crate) type WitnessPat<'db> = rustc_pattern_analysis::pat::WitnessPat>; +pub(crate) type DeconstructedPat<'a, 'db> = + rustc_pattern_analysis::pat::DeconstructedPat>; +pub(crate) type MatchArm<'a, 'b, 'db> = + rustc_pattern_analysis::MatchArm<'b, MatchCheckCtx<'a, 'db>>; +pub(crate) type WitnessPat<'a, 'db> = + rustc_pattern_analysis::pat::WitnessPat>; /// [Constructor] uses this in unimplemented variants. /// It allows porting match expressions from upstream algorithm without losing semantics. @@ -65,37 +70,37 @@ impl rustc_pattern_analysis::Idx for EnumVariantContiguousIndex { } #[derive(Clone)] -pub(crate) struct MatchCheckCtx<'db> { +pub(crate) struct MatchCheckCtx<'a, 'db> { module: ModuleId, - body: DefWithBodyId, pub(crate) db: &'db dyn HirDatabase, exhaustive_patterns: bool, env: Arc>, + infcx: &'a InferCtxt<'db>, } -impl<'db> MatchCheckCtx<'db> { +impl<'a, 'db> MatchCheckCtx<'a, 'db> { pub(crate) fn new( module: ModuleId, - body: DefWithBodyId, - db: &'db dyn HirDatabase, + infcx: &'a InferCtxt<'db>, env: Arc>, ) -> Self { + let db = infcx.interner.db; let def_map = module.crate_def_map(db); let exhaustive_patterns = def_map.is_unstable_feature_enabled(&sym::exhaustive_patterns); - Self { module, body, db, exhaustive_patterns, env } + Self { module, db, exhaustive_patterns, env, infcx } } - pub(crate) fn compute_match_usefulness( + pub(crate) fn compute_match_usefulness<'b>( &self, - arms: &[MatchArm<'db>], - scrut_ty: Ty, + arms: &[MatchArm<'a, 'b, 'db>], + scrut_ty: Ty<'db>, known_valid_scrutinee: Option, - ) -> Result, ()> { - if scrut_ty.contains_unknown() { + ) -> Result, ()> { + if scrut_ty.references_non_lt_error() { return Err(()); } for arm in arms { - if arm.pat.ty().contains_unknown() { + if arm.pat.ty().references_non_lt_error() { return Err(()); } } @@ -106,8 +111,8 @@ impl<'db> MatchCheckCtx<'db> { compute_match_usefulness(self, arms, scrut_ty, place_validity, complexity_limit) } - fn is_uninhabited(&self, ty: &Ty) -> bool { - is_ty_uninhabited_from(self.db, ty, self.module, self.env.clone()) + fn is_uninhabited(&self, ty: Ty<'db>) -> bool { + is_ty_uninhabited_from(self.infcx, ty, self.module, self.env.clone()) } /// Returns whether the given ADT is from another crate declared `#[non_exhaustive]`. @@ -140,23 +145,27 @@ impl<'db> MatchCheckCtx<'db> { // This lists the fields of a variant along with their types. fn list_variant_fields( &self, - ty: &Ty, + ty: Ty<'db>, variant: VariantId, - ) -> impl Iterator { + ) -> impl Iterator)> { let (_, substs) = ty.as_adt().unwrap(); let field_tys = self.db.field_types(variant); let fields_len = variant.fields(self.db).fields().len() as u32; (0..fields_len).map(|idx| LocalFieldId::from_raw(idx.into())).map(move |fid| { - let ty = field_tys[fid].clone().substitute(Interner, substs); - let ty = normalize(self.db, self.db.trait_environment_for_body(self.body), ty); + let ty = field_tys[fid].instantiate(self.infcx.interner, substs); + let ty = self + .infcx + .at(&ObligationCause::dummy(), self.env.env) + .deeply_normalize(ty) + .unwrap_or(ty); (fid, ty) }) } - pub(crate) fn lower_pat(&self, pat: &Pat) -> DeconstructedPat<'db> { - let singleton = |pat: DeconstructedPat<'db>| vec![pat.at_index(0)]; + pub(crate) fn lower_pat(&self, pat: &Pat<'db>) -> DeconstructedPat<'a, 'db> { + let singleton = |pat: DeconstructedPat<'a, 'db>| vec![pat.at_index(0)]; let ctor; let mut fields: Vec<_>; let arity; @@ -169,7 +178,7 @@ impl<'db> MatchCheckCtx<'db> { arity = 0; } PatKind::Deref { subpattern } => { - ctor = match pat.ty.kind(Interner) { + ctor = match pat.ty.kind() { TyKind::Ref(..) => Ref, _ => { never!("pattern has unexpected type: pat: {:?}, ty: {:?}", pat, &pat.ty); @@ -187,12 +196,13 @@ impl<'db> MatchCheckCtx<'db> { self.lower_pat(&pat.pattern).at_index(idx as usize) }) .collect(); - match pat.ty.kind(Interner) { - TyKind::Tuple(_, substs) => { + match pat.ty.kind() { + TyKind::Tuple(substs) => { ctor = Struct; - arity = substs.len(Interner); + arity = substs.len(); } - &TyKind::Adt(AdtId(adt), _) => { + TyKind::Adt(adt_def, _) => { + let adt = adt_def.def_id().0; ctor = match pat.kind.as_ref() { PatKind::Leaf { .. } if matches!(adt, hir_def::AdtId::UnionId(_)) => { UnionField @@ -240,15 +250,15 @@ impl<'db> MatchCheckCtx<'db> { arity = pats.len(); } } - DeconstructedPat::new(ctor, fields, arity, pat.ty.clone(), ()) + DeconstructedPat::new(ctor, fields, arity, pat.ty, ()) } - pub(crate) fn hoist_witness_pat(&self, pat: &WitnessPat<'db>) -> Pat { + pub(crate) fn hoist_witness_pat(&self, pat: &WitnessPat<'a, 'db>) -> Pat<'db> { let mut subpatterns = pat.iter_fields().map(|p| self.hoist_witness_pat(p)); let kind = match pat.ctor() { &Bool(value) => PatKind::LiteralBool { value }, IntRange(_) => unimplemented!(), - Struct | Variant(_) | UnionField => match pat.ty().kind(Interner) { + Struct | Variant(_) | UnionField => match pat.ty().kind() { TyKind::Tuple(..) => PatKind::Leaf { subpatterns: subpatterns .zip(0u32..) @@ -259,15 +269,16 @@ impl<'db> MatchCheckCtx<'db> { .collect(), }, TyKind::Adt(adt, substs) => { - let variant = Self::variant_id_for_adt(self.db, pat.ctor(), adt.0).unwrap(); + let variant = + Self::variant_id_for_adt(self.db, pat.ctor(), adt.def_id().0).unwrap(); let subpatterns = self - .list_variant_fields(pat.ty(), variant) + .list_variant_fields(*pat.ty(), variant) .zip(subpatterns) .map(|((field, _ty), pattern)| FieldPat { field, pattern }) .collect(); if let VariantId::EnumVariantId(enum_variant) = variant { - PatKind::Variant { substs: substs.clone(), enum_variant, subpatterns } + PatKind::Variant { substs, enum_variant, subpatterns } } else { PatKind::Leaf { subpatterns } } @@ -293,13 +304,13 @@ impl<'db> MatchCheckCtx<'db> { PatKind::Wild } }; - Pat { ty: pat.ty().clone(), kind: Box::new(kind) } + Pat { ty: *pat.ty(), kind: Box::new(kind) } } } -impl PatCx for MatchCheckCtx<'_> { +impl<'a, 'db> PatCx for MatchCheckCtx<'a, 'db> { type Error = (); - type Ty = Ty; + type Ty = Ty<'db>; type VariantIdx = EnumVariantContiguousIndex; type StrLit = Void; type ArmData = (); @@ -315,10 +326,11 @@ impl PatCx for MatchCheckCtx<'_> { ty: &Self::Ty, ) -> usize { match ctor { - Struct | Variant(_) | UnionField => match *ty.kind(Interner) { - TyKind::Tuple(arity, ..) => arity, - TyKind::Adt(AdtId(adt), ..) => { - let variant = Self::variant_id_for_adt(self.db, ctor, adt).unwrap(); + Struct | Variant(_) | UnionField => match ty.kind() { + TyKind::Tuple(tys) => tys.len(), + TyKind::Adt(adt_def, ..) => { + let variant = + Self::variant_id_for_adt(self.db, ctor, adt_def.def_id().0).unwrap(); variant.fields(self.db).fields().len() } _ => { @@ -346,24 +358,24 @@ impl PatCx for MatchCheckCtx<'_> { ) -> impl ExactSizeIterator { let single = |ty| smallvec![(ty, PrivateUninhabitedField(false))]; let tys: SmallVec<[_; 2]> = match ctor { - Struct | Variant(_) | UnionField => match ty.kind(Interner) { - TyKind::Tuple(_, substs) => { - let tys = substs.iter(Interner).map(|ty| ty.assert_ty_ref(Interner)); - tys.cloned().map(|ty| (ty, PrivateUninhabitedField(false))).collect() + Struct | Variant(_) | UnionField => match ty.kind() { + TyKind::Tuple(substs) => { + substs.iter().map(|ty| (ty, PrivateUninhabitedField(false))).collect() } - TyKind::Ref(.., rty) => single(rty.clone()), - &TyKind::Adt(AdtId(adt), ..) => { + TyKind::Ref(_, rty, _) => single(rty), + TyKind::Adt(adt_def, ..) => { + let adt = adt_def.def_id().0; let variant = Self::variant_id_for_adt(self.db, ctor, adt).unwrap(); let visibilities = LazyCell::new(|| self.db.field_visibilities(variant)); - self.list_variant_fields(ty, variant) + self.list_variant_fields(*ty, variant) .map(move |(fid, ty)| { let is_visible = || { matches!(adt, hir_def::AdtId::EnumId(..)) || visibilities[fid].is_visible_from(self.db, self.module) }; - let is_uninhabited = self.is_uninhabited(&ty); + let is_uninhabited = self.is_uninhabited(ty); let private_uninhabited = is_uninhabited && !is_visible(); (ty, PrivateUninhabitedField(private_uninhabited)) }) @@ -371,14 +383,14 @@ impl PatCx for MatchCheckCtx<'_> { } ty_kind => { never!("Unexpected type for `{:?}` constructor: {:?}", ctor, ty_kind); - single(ty.clone()) + single(*ty) } }, - Ref => match ty.kind(Interner) { - TyKind::Ref(.., rty) => single(rty.clone()), + Ref => match ty.kind() { + TyKind::Ref(_, rty, _) => single(rty), ty_kind => { never!("Unexpected type for `{:?}` constructor: {:?}", ctor, ty_kind); - single(ty.clone()) + single(*ty) } }, Slice(_) => unreachable!("Found a `Slice` constructor in match checking"), @@ -414,42 +426,51 @@ impl PatCx for MatchCheckCtx<'_> { // returned list of constructors. // Invariant: this is empty if and only if the type is uninhabited (as determined by // `cx.is_uninhabited()`). - Ok(match ty.kind(Interner) { - TyKind::Scalar(Scalar::Bool) => ConstructorSet::Bool, - TyKind::Scalar(Scalar::Char) => unhandled(), - TyKind::Scalar(Scalar::Int(..) | Scalar::Uint(..)) => unhandled(), + Ok(match ty.kind() { + TyKind::Bool => ConstructorSet::Bool, + TyKind::Char => unhandled(), + TyKind::Int(..) | TyKind::Uint(..) => unhandled(), TyKind::Array(..) | TyKind::Slice(..) => unhandled(), - &TyKind::Adt(AdtId(adt @ hir_def::AdtId::EnumId(enum_id)), ref subst) => { - let enum_data = enum_id.enum_variants(cx.db); - let is_declared_nonexhaustive = cx.is_foreign_non_exhaustive(adt); + TyKind::Adt(adt_def, subst) => { + let adt = adt_def.def_id().0; + match adt { + hir_def::AdtId::EnumId(enum_id) => { + let enum_data = enum_id.enum_variants(cx.db); + let is_declared_nonexhaustive = cx.is_foreign_non_exhaustive(adt); - if enum_data.variants.is_empty() && !is_declared_nonexhaustive { - ConstructorSet::NoConstructors - } else { - let mut variants = IndexVec::with_capacity(enum_data.variants.len()); - for &(variant, _, _) in enum_data.variants.iter() { - let is_uninhabited = is_enum_variant_uninhabited_from( - cx.db, - variant, - subst, - cx.module, - self.env.clone(), - ); - let visibility = if is_uninhabited { - VariantVisibility::Empty + if enum_data.variants.is_empty() && !is_declared_nonexhaustive { + ConstructorSet::NoConstructors } else { - VariantVisibility::Visible - }; - variants.push(visibility); - } + let mut variants = IndexVec::with_capacity(enum_data.variants.len()); + for &(variant, _, _) in enum_data.variants.iter() { + let is_uninhabited = is_enum_variant_uninhabited_from( + cx.infcx, + variant, + subst, + cx.module, + self.env.clone(), + ); + let visibility = if is_uninhabited { + VariantVisibility::Empty + } else { + VariantVisibility::Visible + }; + variants.push(visibility); + } - ConstructorSet::Variants { variants, non_exhaustive: is_declared_nonexhaustive } + ConstructorSet::Variants { + variants, + non_exhaustive: is_declared_nonexhaustive, + } + } + } + hir_def::AdtId::UnionId(_) => ConstructorSet::Union, + hir_def::AdtId::StructId(_) => { + ConstructorSet::Struct { empty: cx.is_uninhabited(*ty) } + } } } - TyKind::Adt(AdtId(hir_def::AdtId::UnionId(_)), _) => ConstructorSet::Union, - TyKind::Adt(..) | TyKind::Tuple(..) => { - ConstructorSet::Struct { empty: cx.is_uninhabited(ty) } - } + TyKind::Tuple(..) => ConstructorSet::Struct { empty: cx.is_uninhabited(*ty) }, TyKind::Ref(..) => ConstructorSet::Ref, TyKind::Never => ConstructorSet::NoConstructors, // This type is one for which we cannot list constructors, like `str` or `f64`. @@ -492,14 +513,14 @@ impl PatCx for MatchCheckCtx<'_> { fn report_mixed_deref_pat_ctors( &self, - _deref_pat: &DeconstructedPat<'_>, - _normal_pat: &DeconstructedPat<'_>, + _deref_pat: &DeconstructedPat<'a, 'db>, + _normal_pat: &DeconstructedPat<'a, 'db>, ) { // FIXME(deref_patterns): This could report an error comparable to the one in rustc. } } -impl fmt::Debug for MatchCheckCtx<'_> { +impl fmt::Debug for MatchCheckCtx<'_, '_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("MatchCheckCtx").finish() } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs index 31100e17f846..53524d66a33c 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs @@ -5,22 +5,21 @@ use std::mem; use either::Either; use hir_def::{ - AdtId, DefWithBodyId, FieldId, FunctionId, VariantId, + AdtId, CallableDefId, DefWithBodyId, FieldId, FunctionId, VariantId, expr_store::{Body, path::Path}, hir::{AsmOperand, Expr, ExprId, ExprOrPatId, InlineAsmKind, Pat, PatId, Statement, UnaryOp}, resolver::{HasResolver, ResolveValueResult, Resolver, ValueNs}, signatures::StaticFlags, type_ref::Rawness, }; +use rustc_type_ir::inherent::IntoKind; use span::Edition; -use crate::next_solver::DbInterner; -use crate::next_solver::mapping::NextSolverToChalk; -use crate::utils::TargetFeatureIsSafeInTarget; use crate::{ - InferenceResult, Interner, TargetFeatures, TyExt, TyKind, + InferenceResult, TargetFeatures, db::HirDatabase, - utils::{is_fn_unsafe_to_call, target_feature_is_safe_in_target}, + next_solver::{CallableIdWrapper, TyKind, abi::Safety}, + utils::{TargetFeatureIsSafeInTarget, is_fn_unsafe_to_call, target_feature_is_safe_in_target}, }; #[derive(Debug, Default)] @@ -151,7 +150,6 @@ struct UnsafeVisitor<'db> { /// On some targets (WASM), calling safe functions with `#[target_feature]` is always safe, even when /// the target feature is not enabled. This flag encodes that. target_feature_is_safe: TargetFeatureIsSafeInTarget, - interner: DbInterner<'db>, } impl<'db> UnsafeVisitor<'db> { @@ -186,7 +184,6 @@ impl<'db> UnsafeVisitor<'db> { def_target_features, edition, target_feature_is_safe, - interner: DbInterner::new_with(db, None, None), } } @@ -289,12 +286,14 @@ impl<'db> UnsafeVisitor<'db> { let inside_assignment = mem::replace(&mut self.inside_assignment, false); match expr { &Expr::Call { callee, .. } => { - let callee = self.infer[callee].to_chalk(self.interner); - if let Some(func) = callee.as_fn_def(self.db) { + let callee = self.infer[callee]; + if let TyKind::FnDef(CallableIdWrapper(CallableDefId::FunctionId(func)), _) = + callee.kind() + { self.check_call(current, func); } - if let TyKind::Function(fn_ptr) = callee.kind(Interner) - && fn_ptr.sig.safety == chalk_ir::Safety::Unsafe + if let TyKind::FnPtr(_, hdr) = callee.kind() + && hdr.safety == Safety::Unsafe { self.on_unsafe_op(current.into(), UnsafetyReason::UnsafeFnCall); } @@ -342,7 +341,7 @@ impl<'db> UnsafeVisitor<'db> { } } Expr::UnaryOp { expr, op: UnaryOp::Deref } => { - if let TyKind::Raw(..) = &self.infer[*expr].to_chalk(self.interner).kind(Interner) { + if let TyKind::RawPtr(..) = self.infer[*expr].kind() { self.on_unsafe_op(current.into(), UnsafetyReason::RawPtrDeref); } } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs index bcd93c6699cc..dd1b212d4c29 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs @@ -8,7 +8,6 @@ use std::{ }; use base_db::Crate; -use chalk_ir::{BoundVar, Safety, TyKind}; use either::Either; use hir_def::{ FindPathConfig, GeneralConstId, GenericDefId, HasModule, LocalFieldId, Lookup, ModuleDefId, @@ -36,39 +35,33 @@ use rustc_apfloat::{ Float, ieee::{Half as f16, Quad as f128}, }; +use rustc_ast_ir::FloatTy; use rustc_hash::FxHashSet; use rustc_type_ir::{ - AliasTyKind, CoroutineArgsParts, RegionKind, - inherent::{AdtDef, GenericArgs as _, IntoKind, SliceLike}, + AliasTyKind, BoundVarIndexKind, CoroutineArgsParts, CoroutineClosureArgsParts, RegionKind, + Upcast, + inherent::{AdtDef, GenericArgs as _, IntoKind, SliceLike, Term as _, Ty as _, Tys as _}, }; use smallvec::SmallVec; use span::Edition; use stdx::never; use triomphe::Arc; -use crate::next_solver::infer::traits::ObligationCause; -use crate::next_solver::{infer::DbInternerInferExt, mapping::NextSolverToChalk}; use crate::{ - AliasEq, AliasTy, Binders, CallableDefId, CallableSig, ConcreteConst, Const, ConstScalar, - ConstValue, DomainGoal, FnAbi, GenericArg, ImplTraitId, Interner, Lifetime, LifetimeData, - LifetimeOutlives, MemoryMap, OpaqueTy, ProjectionTy, ProjectionTyExt, QuantifiedWhereClause, - TraitEnvironment, TraitRef, TraitRefExt, Ty, TyExt, WhereClause, consteval, - db::{HirDatabase, InternedClosure}, - from_assoc_type_id, from_placeholder_idx, + CallableDefId, FnAbi, ImplTraitId, MemoryMap, TraitEnvironment, consteval, + db::{HirDatabase, InternedClosure, InternedCoroutine}, generics::generics, - infer::normalize, layout::Layout, - lt_from_placeholder_idx, mir::pad16, next_solver::{ - BoundExistentialPredicate, DbInterner, GenericArgs, SolverDefId, - mapping::{ - ChalkToNextSolver, convert_args_for_result, convert_const_for_result, - convert_region_for_result, convert_ty_for_result, - }, + AliasTy, Clause, ClauseKind, Const, ConstKind, DbInterner, EarlyBinder, + ExistentialPredicate, FnSig, GenericArg, GenericArgs, PolyFnSig, Region, SolverDefId, Term, + TraitRef, Ty, TyKind, TypingMode, + abi::Safety, + infer::{DbInternerInferExt, traits::ObligationCause}, }, - primitive, to_assoc_type_id, - utils::{self, ClosureSubst, detect_variant_from_bytes}, + primitive, + utils::{self, detect_variant_from_bytes}, }; pub trait HirWrite: fmt::Write { @@ -82,9 +75,10 @@ impl HirWrite for String {} // `core::Formatter` will ignore metadata impl HirWrite for fmt::Formatter<'_> {} -pub struct HirFormatter<'a> { +pub struct HirFormatter<'a, 'db> { /// The database handle - pub db: &'a dyn HirDatabase, + pub db: &'db dyn HirDatabase, + pub interner: DbInterner<'db>, /// The sink to write into fmt: &'a mut dyn HirWrite, /// A buffer to intercept writes with, this allows us to track the overall size of the formatted output. @@ -103,7 +97,7 @@ pub struct HirFormatter<'a> { display_lifetimes: DisplayLifetime, display_kind: DisplayKind, display_target: DisplayTarget, - bounds_formatting_ctx: BoundsFormattingCtx, + bounds_formatting_ctx: BoundsFormattingCtx<'db>, } // FIXME: To consider, ref and dyn trait lifetimes can be omitted if they are `'_`, path args should @@ -121,7 +115,7 @@ pub enum DisplayLifetime { } #[derive(Default)] -enum BoundsFormattingCtx { +enum BoundsFormattingCtx<'db> { Entered { /// We can have recursive bounds like the following case: /// ```ignore @@ -131,14 +125,14 @@ enum BoundsFormattingCtx { /// ``` /// So, record the projection types met while formatting bounds and //. prevent recursing into their bounds to avoid infinite loops. - projection_tys_met: FxHashSet, + projection_tys_met: FxHashSet>, }, #[default] Exited, } -impl BoundsFormattingCtx { - fn contains(&mut self, proj: &ProjectionTy) -> bool { +impl<'db> BoundsFormattingCtx<'db> { + fn contains(&self, proj: &AliasTy<'db>) -> bool { match self { BoundsFormattingCtx::Entered { projection_tys_met } => { projection_tys_met.contains(proj) @@ -148,7 +142,7 @@ impl BoundsFormattingCtx { } } -impl HirFormatter<'_> { +impl<'db> HirFormatter<'_, 'db> { fn start_location_link(&mut self, location: ModuleDefId) { self.fmt.start_location_link(location); } @@ -159,7 +153,7 @@ impl HirFormatter<'_> { fn format_bounds_with T>( &mut self, - target: ProjectionTy, + target: AliasTy<'db>, format_bounds: F, ) -> T { match self.bounds_formatting_ctx { @@ -181,52 +175,28 @@ impl HirFormatter<'_> { } } - fn render_lifetime(&self, lifetime: &Lifetime) -> bool { + fn render_region(&self, lifetime: Region<'db>) -> bool { match self.display_lifetimes { DisplayLifetime::Always => true, - DisplayLifetime::OnlyStatic => matches!(***lifetime.interned(), LifetimeData::Static), + DisplayLifetime::OnlyStatic => matches!(lifetime.kind(), RegionKind::ReStatic), DisplayLifetime::OnlyNamed => { - matches!(***lifetime.interned(), LifetimeData::Placeholder(_)) + matches!(lifetime.kind(), RegionKind::ReEarlyParam(_)) } - DisplayLifetime::OnlyNamedOrStatic => matches!( - ***lifetime.interned(), - LifetimeData::Static | LifetimeData::Placeholder(_) - ), - DisplayLifetime::Never => false, - } - } - - fn render_region(&self, lifetime: crate::next_solver::Region<'_>) -> bool { - match self.display_lifetimes { - DisplayLifetime::Always => true, - DisplayLifetime::OnlyStatic => { - matches!(lifetime.kind(), rustc_type_ir::RegionKind::ReStatic) + DisplayLifetime::OnlyNamedOrStatic => { + matches!(lifetime.kind(), RegionKind::ReStatic | RegionKind::ReEarlyParam(_)) } - DisplayLifetime::OnlyNamed => { - matches!( - lifetime.kind(), - rustc_type_ir::RegionKind::RePlaceholder(_) - | rustc_type_ir::RegionKind::ReEarlyParam(_) - ) - } - DisplayLifetime::OnlyNamedOrStatic => matches!( - lifetime.kind(), - rustc_type_ir::RegionKind::ReStatic - | rustc_type_ir::RegionKind::RePlaceholder(_) - | rustc_type_ir::RegionKind::ReEarlyParam(_) - ), DisplayLifetime::Never => false, } } } -pub trait HirDisplay { - fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError>; +pub trait HirDisplay<'db> { + fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError>; /// Returns a `Display`able type that is human-readable. fn into_displayable<'a>( &'a self, - db: &'a dyn HirDatabase, + db: &'db dyn HirDatabase, max_size: Option, limited_size: Option, omit_verbose_types: bool, @@ -234,7 +204,7 @@ pub trait HirDisplay { display_kind: DisplayKind, closure_style: ClosureStyle, show_container_bounds: bool, - ) -> HirDisplayWrapper<'a, Self> + ) -> HirDisplayWrapper<'a, 'db, Self> where Self: Sized, { @@ -260,9 +230,9 @@ pub trait HirDisplay { /// Use this for showing types to the user (e.g. diagnostics) fn display<'a>( &'a self, - db: &'a dyn HirDatabase, + db: &'db dyn HirDatabase, display_target: DisplayTarget, - ) -> HirDisplayWrapper<'a, Self> + ) -> HirDisplayWrapper<'a, 'db, Self> where Self: Sized, { @@ -284,10 +254,10 @@ pub trait HirDisplay { /// Use this for showing types to the user where space is constrained (e.g. doc popups) fn display_truncated<'a>( &'a self, - db: &'a dyn HirDatabase, + db: &'db dyn HirDatabase, max_size: Option, display_target: DisplayTarget, - ) -> HirDisplayWrapper<'a, Self> + ) -> HirDisplayWrapper<'a, 'db, Self> where Self: Sized, { @@ -309,10 +279,10 @@ pub trait HirDisplay { /// Use this for showing definitions which may contain too many items, like `trait`, `struct`, `enum` fn display_limited<'a>( &'a self, - db: &'a dyn HirDatabase, + db: &'db dyn HirDatabase, limited_size: Option, display_target: DisplayTarget, - ) -> HirDisplayWrapper<'a, Self> + ) -> HirDisplayWrapper<'a, 'db, Self> where Self: Sized, { @@ -334,13 +304,16 @@ pub trait HirDisplay { /// Use this when generating code (e.g. assists) fn display_source_code<'a>( &'a self, - db: &'a dyn HirDatabase, + db: &'db dyn HirDatabase, module_id: ModuleId, allow_opaque: bool, ) -> Result { let mut result = String::new(); + let interner = + DbInterner::new_with(db, Some(module_id.krate()), module_id.containing_block()); match self.hir_fmt(&mut HirFormatter { db, + interner, fmt: &mut result, buf: String::with_capacity(20), curr_size: 0, @@ -364,9 +337,9 @@ pub trait HirDisplay { /// Returns a String representation of `self` for test purposes fn display_test<'a>( &'a self, - db: &'a dyn HirDatabase, + db: &'db dyn HirDatabase, display_target: DisplayTarget, - ) -> HirDisplayWrapper<'a, Self> + ) -> HirDisplayWrapper<'a, 'db, Self> where Self: Sized, { @@ -388,10 +361,10 @@ pub trait HirDisplay { /// the container for functions fn display_with_container_bounds<'a>( &'a self, - db: &'a dyn HirDatabase, + db: &'db dyn HirDatabase, show_container_bounds: bool, display_target: DisplayTarget, - ) -> HirDisplayWrapper<'a, Self> + ) -> HirDisplayWrapper<'a, 'db, Self> where Self: Sized, { @@ -410,7 +383,7 @@ pub trait HirDisplay { } } -impl HirFormatter<'_> { +impl<'db> HirFormatter<'_, 'db> { pub fn krate(&self) -> Crate { self.display_target.krate } @@ -419,7 +392,7 @@ impl HirFormatter<'_> { self.display_target.edition } - pub fn write_joined( + pub fn write_joined>( &mut self, iter: impl IntoIterator, sep: &str, @@ -536,8 +509,8 @@ impl From for HirDisplayError { } } -pub struct HirDisplayWrapper<'a, T> { - db: &'a dyn HirDatabase, +pub struct HirDisplayWrapper<'a, 'db, T> { + db: &'db dyn HirDatabase, t: &'a T, max_size: Option, limited_size: Option, @@ -564,10 +537,17 @@ pub enum ClosureStyle { Hide, } -impl HirDisplayWrapper<'_, T> { +impl<'db, T: HirDisplay<'db>> HirDisplayWrapper<'_, 'db, T> { pub fn write_to(&self, f: &mut F) -> Result<(), HirDisplayError> { + let krate = self.display_target.krate; + let block = match self.display_kind { + DisplayKind::SourceCode { target_module_id, .. } => target_module_id.containing_block(), + DisplayKind::Diagnostics | DisplayKind::Test => None, + }; + let interner = DbInterner::new_with(self.db, Some(krate), block); self.t.hir_fmt(&mut HirFormatter { db: self.db, + interner, fmt: f, buf: String::with_capacity(self.max_size.unwrap_or(20)), curr_size: 0, @@ -594,9 +574,9 @@ impl HirDisplayWrapper<'_, T> { } } -impl fmt::Display for HirDisplayWrapper<'_, T> +impl<'db, T> fmt::Display for HirDisplayWrapper<'_, 'db, T> where - T: HirDisplay, + T: HirDisplay<'db>, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self.write_to(f) { @@ -614,196 +594,149 @@ where const TYPE_HINT_TRUNCATION: &str = "…"; -impl HirDisplay for &T { - fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { +impl<'db, T: HirDisplay<'db>> HirDisplay<'db> for &T { + fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> { HirDisplay::hir_fmt(*self, f) } } -impl HirDisplay for Interned { - fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { +impl<'db, T: HirDisplay<'db> + Internable> HirDisplay<'db> for Interned { + fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> { HirDisplay::hir_fmt(self.as_ref(), f) } } -impl HirDisplay for ProjectionTy { - fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { - if f.should_truncate() { - return write!(f, "{TYPE_HINT_TRUNCATION}"); - } - let trait_ref = self.trait_ref(f.db); - let self_ty = trait_ref.self_type_parameter(Interner); +fn write_projection<'db>( + f: &mut HirFormatter<'_, 'db>, + alias: &AliasTy<'db>, +) -> Result<(), HirDisplayError> { + if f.should_truncate() { + return write!(f, "{TYPE_HINT_TRUNCATION}"); + } + let trait_ref = alias.trait_ref(f.interner); + let self_ty = trait_ref.self_ty(); - // if we are projection on a type parameter, check if the projection target has bounds - // itself, if so, we render them directly as `impl Bound` instead of the less useful - // `::Assoc` - if !f.display_kind.is_source_code() - && let TyKind::Placeholder(idx) = self_ty.kind(Interner) - && !f.bounds_formatting_ctx.contains(self) - { - let db = f.db; - let id = from_placeholder_idx(db, *idx).0; - let generics = generics(db, id.parent); - - let substs = generics.placeholder_subst(db); - let bounds = db - .generic_predicates(id.parent) - .iter() - .map(|pred| pred.clone().substitute(Interner, &substs)) + // if we are projection on a type parameter, check if the projection target has bounds + // itself, if so, we render them directly as `impl Bound` instead of the less useful + // `::Assoc` + if !f.display_kind.is_source_code() + && let TyKind::Param(param) = self_ty.kind() + && !f.bounds_formatting_ctx.contains(alias) + { + // FIXME: We shouldn't use `param.id`, it should be removed. We should know the + // `GenericDefId` from the formatted type (store it inside the `HirFormatter`). + let bounds = + f.db.generic_predicates(param.id.parent()) + .instantiate_identity() + .into_iter() + .flatten() .filter(|wc| { - let ty = match wc.skip_binders() { - WhereClause::Implemented(tr) => tr.self_type_parameter(Interner), - WhereClause::TypeOutlives(t) => t.ty.clone(), - // We shouldn't be here if these exist - WhereClause::AliasEq(_) | WhereClause::LifetimeOutlives(_) => { - return false; - } + let ty = match wc.kind().skip_binder() { + ClauseKind::Trait(tr) => tr.self_ty(), + ClauseKind::TypeOutlives(t) => t.0, + _ => return false, }; - let TyKind::Alias(AliasTy::Projection(proj)) = ty.kind(Interner) else { + let TyKind::Alias(AliasTyKind::Projection, a) = ty.kind() else { return false; }; - proj == self + a == *alias }) .collect::>(); - if !bounds.is_empty() { - return f.format_bounds_with(self.clone(), |f| { - write_bounds_like_dyn_trait_with_prefix( - f, - "impl", - Either::Left( - &TyKind::Alias(AliasTy::Projection(self.clone())).intern(Interner), - ), - &bounds, - SizedByDefault::NotSized, - ) - }); - } + if !bounds.is_empty() { + return f.format_bounds_with(*alias, |f| { + write_bounds_like_dyn_trait_with_prefix( + f, + "impl", + Either::Left(Ty::new_alias(f.interner, AliasTyKind::Projection, *alias)), + &bounds, + SizedByDefault::NotSized, + ) + }); } - - write!(f, "<")?; - self_ty.hir_fmt(f)?; - write!(f, " as ")?; - trait_ref.hir_fmt(f)?; - write!( - f, - ">::{}", - f.db.type_alias_signature(from_assoc_type_id(self.associated_ty_id)) - .name - .display(f.db, f.edition()) - )?; - let proj_params = - &self.substitution.as_slice(Interner)[trait_ref.substitution.len(Interner)..]; - hir_fmt_generics(f, proj_params, None, None) } + + write!(f, "<")?; + self_ty.hir_fmt(f)?; + write!(f, " as ")?; + trait_ref.hir_fmt(f)?; + write!( + f, + ">::{}", + f.db.type_alias_signature(alias.def_id.expect_type_alias()).name.display(f.db, f.edition()) + )?; + let proj_params = &alias.args.as_slice()[trait_ref.args.len()..]; + hir_fmt_generics(f, proj_params, None, None) } -impl HirDisplay for OpaqueTy { - fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { - if f.should_truncate() { - return write!(f, "{TYPE_HINT_TRUNCATION}"); - } - - self.substitution.at(Interner, 0).hir_fmt(f) - } -} - -impl HirDisplay for GenericArg { - fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { - match self.interned() { - crate::GenericArgData::Ty(ty) => ty.hir_fmt(f), - crate::GenericArgData::Lifetime(lt) => lt.hir_fmt(f), - crate::GenericArgData::Const(c) => c.hir_fmt(f), +impl<'db> HirDisplay<'db> for GenericArg<'db> { + fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> { + match self { + GenericArg::Ty(ty) => ty.hir_fmt(f), + GenericArg::Lifetime(lt) => lt.hir_fmt(f), + GenericArg::Const(c) => c.hir_fmt(f), } } } -impl<'db> HirDisplay for crate::next_solver::GenericArg<'db> { - fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { +impl<'db> HirDisplay<'db> for Const<'db> { + fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> { match self.kind() { - rustc_type_ir::GenericArgKind::Type(ty) => ty.hir_fmt(f), - rustc_type_ir::GenericArgKind::Lifetime(lt) => lt.hir_fmt(f), - rustc_type_ir::GenericArgKind::Const(c) => c.hir_fmt(f), - } - } -} - -impl HirDisplay for Const { - fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { - let c = self.to_nextsolver(DbInterner::new_with(f.db, None, None)); - c.hir_fmt(f) - } -} - -impl<'db> HirDisplay for crate::next_solver::Const<'db> { - fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { - match self.kind() { - rustc_type_ir::ConstKind::Placeholder(_) => write!(f, ""), - rustc_type_ir::ConstKind::Bound(db, bound_const) => { + ConstKind::Placeholder(_) => write!(f, ""), + ConstKind::Bound(BoundVarIndexKind::Bound(db), bound_const) => { write!(f, "?{}.{}", db.as_u32(), bound_const.var.as_u32()) } - rustc_type_ir::ConstKind::Infer(..) => write!(f, "#c#"), - rustc_type_ir::ConstKind::Param(param) => { + ConstKind::Bound(BoundVarIndexKind::Canonical, bound_const) => { + write!(f, "?c.{}", bound_const.var.as_u32()) + } + ConstKind::Infer(..) => write!(f, "#c#"), + ConstKind::Param(param) => { let generics = generics(f.db, param.id.parent()); let param_data = &generics[param.id.local_id()]; write!(f, "{}", param_data.name().unwrap().display(f.db, f.edition()))?; Ok(()) } - rustc_type_ir::ConstKind::Value(const_bytes) => render_const_scalar_ns( + ConstKind::Value(const_bytes) => render_const_scalar( f, &const_bytes.value.inner().memory, &const_bytes.value.inner().memory_map, const_bytes.ty, ), - rustc_type_ir::ConstKind::Unevaluated(unev) => { + ConstKind::Unevaluated(unev) => { let c = match unev.def { SolverDefId::ConstId(id) => GeneralConstId::ConstId(id), SolverDefId::StaticId(id) => GeneralConstId::StaticId(id), _ => unreachable!(), }; write!(f, "{}", c.name(f.db))?; - hir_fmt_generics_ns(f, unev.args.as_slice(), c.generic_def(f.db), None)?; + hir_fmt_generics(f, unev.args.as_slice(), c.generic_def(f.db), None)?; Ok(()) } - rustc_type_ir::ConstKind::Error(..) => f.write_char('_'), - rustc_type_ir::ConstKind::Expr(..) => write!(f, ""), + ConstKind::Error(..) => f.write_char('_'), + ConstKind::Expr(..) => write!(f, ""), } } } -fn render_const_scalar( - f: &mut HirFormatter<'_>, +fn render_const_scalar<'db>( + f: &mut HirFormatter<'_, 'db>, b: &[u8], - memory_map: &MemoryMap<'_>, - ty: &Ty, + memory_map: &MemoryMap<'db>, + ty: Ty<'db>, ) -> Result<(), HirDisplayError> { let trait_env = TraitEnvironment::empty(f.krate()); - let interner = DbInterner::new_with(f.db, Some(trait_env.krate), trait_env.block); - let ty = normalize(f.db, trait_env.clone(), ty.clone()); - let ty = ty.to_nextsolver(interner); - render_const_scalar_inner(f, b, memory_map, ty, trait_env) -} - -fn render_const_scalar_ns( - f: &mut HirFormatter<'_>, - b: &[u8], - memory_map: &MemoryMap<'_>, - ty: crate::next_solver::Ty<'_>, -) -> Result<(), HirDisplayError> { - let trait_env = TraitEnvironment::empty(f.krate()); - let interner = DbInterner::new_with(f.db, Some(trait_env.krate), trait_env.block); - let infcx = interner.infer_ctxt().build(rustc_type_ir::TypingMode::PostAnalysis); + let infcx = f.interner.infer_ctxt().build(TypingMode::PostAnalysis); let ty = infcx.at(&ObligationCause::new(), trait_env.env).deeply_normalize(ty).unwrap_or(ty); render_const_scalar_inner(f, b, memory_map, ty, trait_env) } fn render_const_scalar_inner<'db>( - f: &mut HirFormatter<'_>, + f: &mut HirFormatter<'_, 'db>, b: &[u8], - memory_map: &MemoryMap<'_>, - ty: crate::next_solver::Ty<'db>, + memory_map: &MemoryMap<'db>, + ty: Ty<'db>, trait_env: Arc>, ) -> Result<(), HirDisplayError> { - use rustc_type_ir::TyKind; + use TyKind; match ty.kind() { TyKind::Bool => write!(f, "{}", b[0] != 0), TyKind::Char => { @@ -822,7 +755,7 @@ fn render_const_scalar_inner<'db>( write!(f, "{it}") } TyKind::Float(fl) => match fl { - rustc_type_ir::FloatTy::F16 => { + FloatTy::F16 => { // FIXME(#17451): Replace with builtins once they are stabilised. let it = f16::from_bits(u16::from_le_bytes(b.try_into().unwrap()).into()); let s = it.to_string(); @@ -833,15 +766,15 @@ fn render_const_scalar_inner<'db>( write!(f, "{s}") } } - rustc_type_ir::FloatTy::F32 => { + FloatTy::F32 => { let it = f32::from_le_bytes(b.try_into().unwrap()); write!(f, "{it:?}") } - rustc_type_ir::FloatTy::F64 => { + FloatTy::F64 => { let it = f64::from_le_bytes(b.try_into().unwrap()); write!(f, "{it:?}") } - rustc_type_ir::FloatTy::F128 => { + FloatTy::F128 => { // FIXME(#17451): Replace with builtins once they are stabilised. let it = f128::from_bits(u128::from_le_bytes(b.try_into().unwrap())); let s = it.to_string(); @@ -890,7 +823,7 @@ fn render_const_scalar_inner<'db>( f.write_str(", ")?; } let offset = size_one * i; - render_const_scalar_ns(f, &bytes[offset..offset + size_one], memory_map, ty)?; + render_const_scalar(f, &bytes[offset..offset + size_one], memory_map, ty)?; } f.write_str("]") } @@ -908,7 +841,7 @@ fn render_const_scalar_inner<'db>( return f.write_str(""); }; f.write_str("&")?; - render_const_scalar_ns(f, bytes, memory_map, t) + render_const_scalar(f, bytes, memory_map, t) } TyKind::Adt(adt, _) if b.len() == 2 * size_of::() => match adt.def_id().0 { hir_def::AdtId::StructId(s) => { @@ -938,7 +871,7 @@ fn render_const_scalar_inner<'db>( return f.write_str(""); }; f.write_str("&")?; - render_const_scalar_ns(f, bytes, memory_map, t) + render_const_scalar(f, bytes, memory_map, t) } }, TyKind::Tuple(tys) => { @@ -959,7 +892,7 @@ fn render_const_scalar_inner<'db>( continue; }; let size = layout.size.bytes_usize(); - render_const_scalar_ns(f, &b[offset..offset + size], memory_map, ty)?; + render_const_scalar(f, &b[offset..offset + size], memory_map, ty)?; } f.write_str(")") } @@ -1041,7 +974,7 @@ fn render_const_scalar_inner<'db>( f.write_str(", ")?; } let offset = size_one * i; - render_const_scalar_ns(f, &b[offset..offset + size_one], memory_map, ty)?; + render_const_scalar(f, &b[offset..offset + size_one], memory_map, ty)?; } f.write_str("]") } @@ -1067,28 +1000,24 @@ fn render_const_scalar_inner<'db>( fn render_variant_after_name<'db>( data: &VariantFields, - f: &mut HirFormatter<'_>, - field_types: &ArenaMap>, + f: &mut HirFormatter<'_, 'db>, + field_types: &ArenaMap>>, trait_env: Arc>, layout: &Layout, - args: GenericArgs<'_>, + args: GenericArgs<'db>, b: &[u8], - memory_map: &MemoryMap<'_>, + memory_map: &MemoryMap<'db>, ) -> Result<(), HirDisplayError> { - let interner = DbInterner::new_with(f.db, Some(trait_env.krate), trait_env.block); match data.shape { FieldsShape::Record | FieldsShape::Tuple => { - let render_field = |f: &mut HirFormatter<'_>, id: LocalFieldId| { + let render_field = |f: &mut HirFormatter<'_, 'db>, id: LocalFieldId| { let offset = layout.fields.offset(u32::from(id.into_raw()) as usize).bytes_usize(); - let ty = field_types[id] - .clone() - .substitute(Interner, &convert_args_for_result(interner, args.as_slice())); - let Ok(layout) = f.db.layout_of_ty(ty.to_nextsolver(interner), trait_env.clone()) - else { + let ty = field_types[id].instantiate(f.interner, args); + let Ok(layout) = f.db.layout_of_ty(ty, trait_env.clone()) else { return f.write_str(""); }; let size = layout.size.bytes_usize(); - render_const_scalar(f, &b[offset..offset + size], memory_map, &ty) + render_const_scalar(f, &b[offset..offset + size], memory_map, ty) }; let mut it = data.fields().iter(); if matches!(data.shape, FieldsShape::Record) { @@ -1120,41 +1049,25 @@ fn render_variant_after_name<'db>( } } -impl HirDisplay for BoundVar { - fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { - write!(f, "?{}.{}", self.debruijn.depth(), self.index) - } -} - -impl HirDisplay for Ty { +impl<'db> HirDisplay<'db> for Ty<'db> { fn hir_fmt( &self, - f @ &mut HirFormatter { db, .. }: &mut HirFormatter<'_>, + f @ &mut HirFormatter { db, .. }: &mut HirFormatter<'_, 'db>, ) -> Result<(), HirDisplayError> { - let ty = self.to_nextsolver(DbInterner::new_with(db, None, None)); - ty.hir_fmt(f) - } -} - -impl<'db> HirDisplay for crate::next_solver::Ty<'db> { - fn hir_fmt( - &self, - f @ &mut HirFormatter { db, .. }: &mut HirFormatter<'_>, - ) -> Result<(), HirDisplayError> { - let interner = DbInterner::new_with(db, None, None); + let interner = f.interner; if f.should_truncate() { return write!(f, "{TYPE_HINT_TRUNCATION}"); } - use rustc_type_ir::TyKind; + use TyKind; match self.kind() { TyKind::Never => write!(f, "!")?, TyKind::Str => write!(f, "str")?, TyKind::Bool => write!(f, "bool")?, TyKind::Char => write!(f, "char")?, - TyKind::Float(t) => write!(f, "{}", primitive::float_ty_to_string_ns(t))?, - TyKind::Int(t) => write!(f, "{}", primitive::int_ty_to_string_ns(t))?, - TyKind::Uint(t) => write!(f, "{}", primitive::uint_ty_to_string_ns(t))?, + TyKind::Float(t) => write!(f, "{}", primitive::float_ty_to_string(t))?, + TyKind::Int(t) => write!(f, "{}", primitive::int_ty_to_string(t))?, + TyKind::Uint(t) => write!(f, "{}", primitive::uint_ty_to_string(t))?, TyKind::Slice(t) => { write!(f, "[")?; t.hir_fmt(f)?; @@ -1164,14 +1077,14 @@ impl<'db> HirDisplay for crate::next_solver::Ty<'db> { write!(f, "[")?; t.hir_fmt(f)?; write!(f, "; ")?; - convert_const_for_result(interner, c).hir_fmt(f)?; + c.hir_fmt(f)?; write!(f, "]")?; } kind @ (TyKind::RawPtr(t, m) | TyKind::Ref(_, t, m)) => { if let TyKind::Ref(l, _, _) = kind { f.write_char('&')?; if f.render_region(l) { - convert_region_for_result(interner, l).hir_fmt(f)?; + l.hir_fmt(f)?; f.write_char(' ')?; } match m { @@ -1190,32 +1103,18 @@ impl<'db> HirDisplay for crate::next_solver::Ty<'db> { } // FIXME: all this just to decide whether to use parentheses... - let contains_impl_fn = |bounds: &[QuantifiedWhereClause]| { - bounds.iter().any(|bound| { - if let WhereClause::Implemented(trait_ref) = bound.skip_binders() { - let trait_ = trait_ref.hir_trait_id(); - fn_traits(db, trait_).any(|it| it == trait_) - } else { - false - } - }) - }; - let contains_impl_fn_ns = |bounds: &[BoundExistentialPredicate<'_>]| { - bounds.iter().any(|bound| match bound.skip_binder() { - rustc_type_ir::ExistentialPredicate::Trait(trait_ref) => { - let trait_ = trait_ref.def_id.0; - fn_traits(db, trait_).any(|it| it == trait_) - } - _ => false, - }) - }; let (preds_to_print, has_impl_fn_pred) = match t.kind() { TyKind::Dynamic(bounds, region) => { + let contains_impl_fn = + bounds.iter().any(|bound| match bound.skip_binder() { + ExistentialPredicate::Trait(trait_ref) => { + let trait_ = trait_ref.def_id.0; + fn_traits(db, trait_).any(|it| it == trait_) + } + _ => false, + }); let render_lifetime = f.render_region(region); - ( - bounds.len() + render_lifetime as usize, - contains_impl_fn_ns(bounds.as_slice()), - ) + (bounds.len() + render_lifetime as usize, contains_impl_fn) } TyKind::Alias(AliasTyKind::Opaque, ty) => { let opaque_ty_id = match ty.def_id { @@ -1227,26 +1126,23 @@ impl<'db> HirDisplay for crate::next_solver::Ty<'db> { let datas = db .return_type_impl_traits(func) .expect("impl trait id without data"); - let data = - (*datas).as_ref().map(|rpit| rpit.impl_traits[idx].bounds.clone()); - let bounds = data.substitute( - Interner, - &convert_args_for_result(interner, ty.args.as_slice()), - ); - let mut len = bounds.skip_binders().len(); + let data = (*datas) + .as_ref() + .map_bound(|rpit| &rpit.impl_traits[idx].predicates); + let bounds = + || data.iter_instantiated_copied(f.interner, ty.args.as_slice()); + let mut len = bounds().count(); // Don't count Sized but count when it absent // (i.e. when explicit ?Sized bound is set). let default_sized = SizedByDefault::Sized { anchor: func.krate(db) }; - let sized_bounds = bounds - .skip_binders() - .iter() + let sized_bounds = bounds() .filter(|b| { matches!( - b.skip_binders(), - WhereClause::Implemented(trait_ref) + b.kind().skip_binder(), + ClauseKind::Trait(trait_ref) if default_sized.is_sized_trait( - trait_ref.hir_trait_id(), + trait_ref.def_id().0, db, ), ) @@ -1259,7 +1155,15 @@ impl<'db> HirDisplay for crate::next_solver::Ty<'db> { } } - (len, contains_impl_fn(bounds.skip_binders())) + let contains_impl_fn = bounds().any(|bound| { + if let ClauseKind::Trait(trait_ref) = bound.kind().skip_binder() { + let trait_ = trait_ref.def_id().0; + fn_traits(db, trait_).any(|it| it == trait_) + } else { + false + } + }); + (len, contains_impl_fn) } else { (0, false) } @@ -1291,31 +1195,28 @@ impl<'db> HirDisplay for crate::next_solver::Ty<'db> { } } TyKind::FnPtr(sig, header) => { - let sig = CallableSig::from_fn_sig_and_header(interner, sig, header); + let sig = sig.with(header); sig.hir_fmt(f)?; } TyKind::FnDef(def, args) => { let def = def.0; - let sig = db - .callable_item_signature(def) - .instantiate(interner, args) - .skip_binder() - .to_chalk(interner); + let sig = db.callable_item_signature(def).instantiate(interner, args); if f.display_kind.is_source_code() { // `FnDef` is anonymous and there's no surface syntax for it. Show it as a // function pointer type. return sig.hir_fmt(f); } - if let Safety::Unsafe = sig.safety { + if let Safety::Unsafe = sig.safety() { write!(f, "unsafe ")?; } - if !matches!(sig.abi, FnAbi::Rust | FnAbi::RustCall) { + if !matches!(sig.abi(), FnAbi::Rust | FnAbi::RustCall) { f.write_str("extern \"")?; - f.write_str(sig.abi.as_str())?; + f.write_str(sig.abi().as_str())?; f.write_str("\" ")?; } + let sig = sig.skip_binder(); write!(f, "fn ")?; f.start_location_link(def.into()); match def { @@ -1338,13 +1239,12 @@ impl<'db> HirDisplay for crate::next_solver::Ty<'db> { }; f.end_location_link(); - let parameters = convert_args_for_result(interner, args.as_slice()); - if parameters.len(Interner) > 0 { + if args.len() > 0 { let generic_def_id = GenericDefId::from_callable(db, def); let generics = generics(db, generic_def_id); let (parent_len, self_param, type_, const_, impl_, lifetime) = generics.provenance_split(); - let parameters = parameters.as_slice(Interner); + let parameters = args.as_slice(); debug_assert_eq!( parameters.len(), parent_len + self_param as usize + type_ + const_ + impl_ + lifetime @@ -1389,9 +1289,9 @@ impl<'db> HirDisplay for crate::next_solver::Ty<'db> { } } write!(f, "(")?; - f.write_joined(sig.params(), ", ")?; + f.write_joined(sig.inputs(), ", ")?; write!(f, ")")?; - let ret = sig.ret(); + let ret = sig.output(); if !ret.is_unit() { write!(f, " -> ")?; ret.hir_fmt(f)?; @@ -1434,27 +1334,9 @@ impl<'db> HirDisplay for crate::next_solver::Ty<'db> { } f.end_location_link(); - hir_fmt_generics( - f, - convert_args_for_result(interner, parameters.as_slice()).as_slice(Interner), - Some(def.def_id().0.into()), - None, - )?; - } - TyKind::Alias(AliasTyKind::Projection, alias_ty) => { - let type_alias = match alias_ty.def_id { - SolverDefId::TypeAliasId(id) => id, - _ => unreachable!(), - }; - let parameters = convert_args_for_result(interner, alias_ty.args.as_slice()); - - let projection_ty = ProjectionTy { - associated_ty_id: to_assoc_type_id(type_alias), - substitution: parameters.clone(), - }; - - projection_ty.hir_fmt(f)?; + hir_fmt_generics(f, parameters.as_slice(), Some(def.def_id().0.into()), None)?; } + TyKind::Alias(AliasTyKind::Projection, alias_ty) => write_projection(f, &alias_ty)?, TyKind::Foreign(alias) => { let type_alias = db.type_alias_signature(alias.0); f.start_location_link(alias.0.into()); @@ -1466,7 +1348,6 @@ impl<'db> HirDisplay for crate::next_solver::Ty<'db> { SolverDefId::InternedOpaqueTyId(id) => id, _ => unreachable!(), }; - let parameters = convert_args_for_result(interner, alias_ty.args.as_slice()); if !f.display_kind.allows_opaque() { return Err(HirDisplayError::DisplaySourceCodeError( DisplaySourceCodeError::OpaqueType, @@ -1478,14 +1359,16 @@ impl<'db> HirDisplay for crate::next_solver::Ty<'db> { let datas = db.return_type_impl_traits(func).expect("impl trait id without data"); let data = - (*datas).as_ref().map(|rpit| rpit.impl_traits[idx].bounds.clone()); - let bounds = data.substitute(Interner, ¶meters); + (*datas).as_ref().map_bound(|rpit| &rpit.impl_traits[idx].predicates); + let bounds = data + .iter_instantiated_copied(interner, alias_ty.args.as_slice()) + .collect::>(); let krate = func.krate(db); write_bounds_like_dyn_trait_with_prefix( f, "impl", - Either::Left(&convert_ty_for_result(interner, *self)), - bounds.skip_binders(), + Either::Left(*self), + &bounds, SizedByDefault::Sized { anchor: krate }, )?; // FIXME: it would maybe be good to distinguish this from the alias type (when debug printing), and to show the substitution @@ -1493,20 +1376,254 @@ impl<'db> HirDisplay for crate::next_solver::Ty<'db> { ImplTraitId::TypeAliasImplTrait(alias, idx) => { let datas = db.type_alias_impl_traits(alias).expect("impl trait id without data"); - let data = (*datas).as_ref().map(|it| it.impl_traits[idx].bounds.clone()); - let bounds = data.substitute(Interner, ¶meters); + let data = + (*datas).as_ref().map_bound(|rpit| &rpit.impl_traits[idx].predicates); + let bounds = data + .iter_instantiated_copied(interner, alias_ty.args.as_slice()) + .collect::>(); let krate = alias.krate(db); write_bounds_like_dyn_trait_with_prefix( f, "impl", - Either::Left(&convert_ty_for_result(interner, *self)), - bounds.skip_binders(), + Either::Left(*self), + &bounds, SizedByDefault::Sized { anchor: krate }, )?; } - ImplTraitId::AsyncBlockTypeImplTrait(body, ..) => { + } + } + TyKind::Closure(id, substs) => { + let id = id.0; + if f.display_kind.is_source_code() { + if !f.display_kind.allows_opaque() { + return Err(HirDisplayError::DisplaySourceCodeError( + DisplaySourceCodeError::OpaqueType, + )); + } else if f.closure_style != ClosureStyle::ImplFn { + never!("Only `impl Fn` is valid for displaying closures in source code"); + } + } + match f.closure_style { + ClosureStyle::Hide => return write!(f, "{TYPE_HINT_TRUNCATION}"), + ClosureStyle::ClosureWithId => { + return write!( + f, + "{{closure#{:?}}}", + salsa::plumbing::AsId::as_id(&id).index() + ); + } + ClosureStyle::ClosureWithSubst => { + write!(f, "{{closure#{:?}}}", salsa::plumbing::AsId::as_id(&id).index())?; + return hir_fmt_generics(f, substs.as_slice(), None, None); + } + _ => (), + } + let sig = substs + .split_closure_args_untupled() + .closure_sig_as_fn_ptr_ty + .callable_sig(interner); + if let Some(sig) = sig { + let sig = sig.skip_binder(); + let InternedClosure(def, _) = db.lookup_intern_closure(id); + let infer = db.infer(def); + let (_, kind) = infer.closure_info(id); + match f.closure_style { + ClosureStyle::ImplFn => write!(f, "impl {kind:?}(")?, + ClosureStyle::RANotation => write!(f, "|")?, + _ => unreachable!(), + } + if sig.inputs().is_empty() { + } else if f.should_truncate() { + write!(f, "{TYPE_HINT_TRUNCATION}")?; + } else { + f.write_joined(sig.inputs(), ", ")?; + }; + match f.closure_style { + ClosureStyle::ImplFn => write!(f, ")")?, + ClosureStyle::RANotation => write!(f, "|")?, + _ => unreachable!(), + } + if f.closure_style == ClosureStyle::RANotation || !sig.output().is_unit() { + write!(f, " -> ")?; + sig.output().hir_fmt(f)?; + } + } else { + write!(f, "{{closure}}")?; + } + } + TyKind::CoroutineClosure(id, args) => { + let id = id.0; + if f.display_kind.is_source_code() { + if !f.display_kind.allows_opaque() { + return Err(HirDisplayError::DisplaySourceCodeError( + DisplaySourceCodeError::OpaqueType, + )); + } else if f.closure_style != ClosureStyle::ImplFn { + never!("Only `impl Fn` is valid for displaying closures in source code"); + } + } + match f.closure_style { + ClosureStyle::Hide => return write!(f, "{TYPE_HINT_TRUNCATION}"), + ClosureStyle::ClosureWithId => { + return write!( + f, + "{{async closure#{:?}}}", + salsa::plumbing::AsId::as_id(&id).index() + ); + } + ClosureStyle::ClosureWithSubst => { + write!( + f, + "{{async closure#{:?}}}", + salsa::plumbing::AsId::as_id(&id).index() + )?; + return hir_fmt_generics(f, args.as_slice(), None, None); + } + _ => (), + } + let CoroutineClosureArgsParts { closure_kind_ty, signature_parts_ty, .. } = + args.split_coroutine_closure_args(); + let kind = closure_kind_ty.to_opt_closure_kind().unwrap(); + let kind = match kind { + rustc_type_ir::ClosureKind::Fn => "AsyncFn", + rustc_type_ir::ClosureKind::FnMut => "AsyncFnMut", + rustc_type_ir::ClosureKind::FnOnce => "AsyncFnOnce", + }; + let TyKind::FnPtr(coroutine_sig, _) = signature_parts_ty.kind() else { + unreachable!("invalid coroutine closure signature"); + }; + let coroutine_sig = coroutine_sig.skip_binder(); + let coroutine_inputs = coroutine_sig.inputs(); + let TyKind::Tuple(coroutine_inputs) = coroutine_inputs.as_slice()[1].kind() else { + unreachable!("invalid coroutine closure signature"); + }; + let TyKind::Tuple(coroutine_output) = coroutine_sig.output().kind() else { + unreachable!("invalid coroutine closure signature"); + }; + let coroutine_output = coroutine_output.as_slice()[1]; + match f.closure_style { + ClosureStyle::ImplFn => write!(f, "impl {kind}(")?, + ClosureStyle::RANotation => write!(f, "async |")?, + _ => unreachable!(), + } + if coroutine_inputs.is_empty() { + } else if f.should_truncate() { + write!(f, "{TYPE_HINT_TRUNCATION}")?; + } else { + f.write_joined(coroutine_inputs, ", ")?; + }; + match f.closure_style { + ClosureStyle::ImplFn => write!(f, ")")?, + ClosureStyle::RANotation => write!(f, "|")?, + _ => unreachable!(), + } + if f.closure_style == ClosureStyle::RANotation || !coroutine_output.is_unit() { + write!(f, " -> ")?; + coroutine_output.hir_fmt(f)?; + } + } + TyKind::Placeholder(_) => write!(f, "{{placeholder}}")?, + TyKind::Param(param) => { + // FIXME: We should not access `param.id`, it should be removed, and we should know the + // parent from the formatted type. + let generics = generics(db, param.id.parent()); + let param_data = &generics[param.id.local_id()]; + match param_data { + TypeOrConstParamData::TypeParamData(p) => match p.provenance { + TypeParamProvenance::TypeParamList | TypeParamProvenance::TraitSelf => { + write!( + f, + "{}", + p.name + .clone() + .unwrap_or_else(Name::missing) + .display(f.db, f.edition()) + )? + } + TypeParamProvenance::ArgumentImplTrait => { + let bounds = db + .generic_predicates(param.id.parent()) + .instantiate_identity() + .into_iter() + .flatten() + .filter(|wc| match wc.kind().skip_binder() { + ClauseKind::Trait(tr) => tr.self_ty() == *self, + ClauseKind::Projection(proj) => proj.self_ty() == *self, + ClauseKind::TypeOutlives(to) => to.0 == *self, + _ => false, + }) + .collect::>(); + let krate = param.id.parent().module(db).krate(); + write_bounds_like_dyn_trait_with_prefix( + f, + "impl", + Either::Left(*self), + &bounds, + SizedByDefault::Sized { anchor: krate }, + )?; + } + }, + TypeOrConstParamData::ConstParamData(p) => { + write!(f, "{}", p.name.display(f.db, f.edition()))?; + } + } + } + TyKind::Bound(BoundVarIndexKind::Bound(debruijn), ty) => { + write!(f, "?{}.{}", debruijn.as_usize(), ty.var.as_usize())? + } + TyKind::Bound(BoundVarIndexKind::Canonical, ty) => { + write!(f, "?c.{}", ty.var.as_usize())? + } + TyKind::Dynamic(bounds, region) => { + // We want to put auto traits after principal traits, regardless of their written order. + let mut bounds_to_display = SmallVec::<[_; 4]>::new(); + let mut auto_trait_bounds = SmallVec::<[_; 4]>::new(); + for bound in bounds.iter() { + let clause = bound.with_self_ty(interner, *self); + match bound.skip_binder() { + ExistentialPredicate::Trait(_) | ExistentialPredicate::Projection(_) => { + bounds_to_display.push(clause); + } + ExistentialPredicate::AutoTrait(_) => auto_trait_bounds.push(clause), + } + } + bounds_to_display.append(&mut auto_trait_bounds); + + if f.render_region(region) { + bounds_to_display + .push(rustc_type_ir::OutlivesPredicate(*self, region).upcast(interner)); + } + + write_bounds_like_dyn_trait_with_prefix( + f, + "dyn", + Either::Left(*self), + &bounds_to_display, + SizedByDefault::NotSized, + )?; + } + TyKind::Error(_) => { + if f.display_kind.is_source_code() { + f.write_char('_')?; + } else { + write!(f, "{{unknown}}")?; + } + } + TyKind::Infer(..) => write!(f, "_")?, + TyKind::Coroutine(coroutine_id, subst) => { + let InternedCoroutine(owner, expr_id) = coroutine_id.0.loc(db); + let CoroutineArgsParts { resume_ty, yield_ty, return_ty, .. } = + subst.split_coroutine_args(); + let body = db.body(owner); + let expr = &body[expr_id]; + match expr { + hir_def::hir::Expr::Closure { + closure_kind: hir_def::hir::ClosureKind::Async, + .. + } + | hir_def::hir::Expr::Async { .. } => { let future_trait = - LangItem::Future.resolve_trait(db, body.module(db).krate()); + LangItem::Future.resolve_trait(db, owner.module(db).krate()); let output = future_trait.and_then(|t| { t.trait_items(db) .associated_type_by_name(&Name::new_symbol_root(sym::Output)) @@ -1528,205 +1645,45 @@ impl<'db> HirDisplay for crate::next_solver::Ty<'db> { f.end_location_link(); } write!(f, " = ")?; - parameters.at(Interner, 0).hir_fmt(f)?; + return_ty.hir_fmt(f)?; write!(f, ">")?; } - } - } - TyKind::Closure(id, substs) => { - let id = id.0; - let substs = convert_args_for_result(interner, substs.as_slice()); - if f.display_kind.is_source_code() { - if !f.display_kind.allows_opaque() { - return Err(HirDisplayError::DisplaySourceCodeError( - DisplaySourceCodeError::OpaqueType, - )); - } else if f.closure_style != ClosureStyle::ImplFn { - never!("Only `impl Fn` is valid for displaying closures in source code"); - } - } - match f.closure_style { - ClosureStyle::Hide => return write!(f, "{TYPE_HINT_TRUNCATION}"), - ClosureStyle::ClosureWithId => { - return write!( - f, - "{{closure#{:?}}}", - salsa::plumbing::AsId::as_id(&id).index() - ); - } - ClosureStyle::ClosureWithSubst => { - write!(f, "{{closure#{:?}}}", salsa::plumbing::AsId::as_id(&id).index())?; - return hir_fmt_generics(f, substs.as_slice(Interner), None, None); - } - _ => (), - } - let sig = ClosureSubst(&substs).sig_ty(db).callable_sig(db); - if let Some(sig) = sig { - let InternedClosure(def, _) = db.lookup_intern_closure(id); - let infer = db.infer(def); - let (_, kind) = infer.closure_info(id); - match f.closure_style { - ClosureStyle::ImplFn => write!(f, "impl {kind:?}(")?, - ClosureStyle::RANotation => write!(f, "|")?, - _ => unreachable!(), - } - if sig.params().is_empty() { - } else if f.should_truncate() { - write!(f, "{TYPE_HINT_TRUNCATION}")?; - } else { - f.write_joined(sig.params(), ", ")?; - }; - match f.closure_style { - ClosureStyle::ImplFn => write!(f, ")")?, - ClosureStyle::RANotation => write!(f, "|")?, - _ => unreachable!(), - } - if f.closure_style == ClosureStyle::RANotation || !sig.ret().is_unit() { + hir_def::hir::Expr::Closure { + closure_kind: hir_def::hir::ClosureKind::Coroutine(..), + .. + } => { + if f.display_kind.is_source_code() { + return Err(HirDisplayError::DisplaySourceCodeError( + DisplaySourceCodeError::Coroutine, + )); + } + write!(f, "|")?; + resume_ty.hir_fmt(f)?; + write!(f, "|")?; + + write!(f, " yields ")?; + yield_ty.hir_fmt(f)?; + write!(f, " -> ")?; - // FIXME: We display `AsyncFn` as `-> impl Future`, but this is hard to fix because - // we don't have a trait environment here, required to normalize `::Output`. - sig.ret().hir_fmt(f)?; + return_ty.hir_fmt(f)?; } - } else { - write!(f, "{{closure}}")?; + _ => panic!("invalid expr for coroutine: {expr:?}"), } } - TyKind::Placeholder(_) => write!(f, "{{placeholder}}")?, - TyKind::Param(param) => { - let generics = generics(db, param.id.parent()); - let param_data = &generics[param.id.local_id()]; - match param_data { - TypeOrConstParamData::TypeParamData(p) => match p.provenance { - TypeParamProvenance::TypeParamList | TypeParamProvenance::TraitSelf => { - write!( - f, - "{}", - p.name - .clone() - .unwrap_or_else(Name::missing) - .display(f.db, f.edition()) - )? - } - TypeParamProvenance::ArgumentImplTrait => { - let substs = generics.placeholder_subst(db); - let bounds = db - .generic_predicates(param.id.parent()) - .iter() - .map(|pred| pred.clone().substitute(Interner, &substs)) - .filter(|wc| match wc.skip_binders() { - WhereClause::Implemented(tr) => { - tr.self_type_parameter(Interner) - == convert_ty_for_result(interner, *self) - } - WhereClause::AliasEq(AliasEq { - alias: AliasTy::Projection(proj), - ty: _, - }) => { - proj.self_type_parameter(db) - == convert_ty_for_result(interner, *self) - } - WhereClause::AliasEq(_) => false, - WhereClause::TypeOutlives(to) => { - to.ty == convert_ty_for_result(interner, *self) - } - WhereClause::LifetimeOutlives(_) => false, - }) - .collect::>(); - let krate = param.id.parent().module(db).krate(); - write_bounds_like_dyn_trait_with_prefix( - f, - "impl", - Either::Left(&convert_ty_for_result(interner, *self)), - &bounds, - SizedByDefault::Sized { anchor: krate }, - )?; - } - }, - TypeOrConstParamData::ConstParamData(p) => { - write!(f, "{}", p.name.display(f.db, f.edition()))?; - } - } - } - TyKind::Bound(debruijn_index, ty) => { - let idx = chalk_ir::BoundVar { - debruijn: chalk_ir::DebruijnIndex::new(debruijn_index.as_u32()), - index: ty.var.as_usize(), - }; - idx.hir_fmt(f)? - } - TyKind::Dynamic(..) => { - let ty = convert_ty_for_result(interner, *self); - let chalk_ir::TyKind::Dyn(dyn_ty) = ty.kind(Interner) else { unreachable!() }; - // Reorder bounds to satisfy `write_bounds_like_dyn_trait()`'s expectation. - // FIXME: `Iterator::partition_in_place()` or `Vec::extract_if()` may make it - // more efficient when either of them hits stable. - let mut bounds: SmallVec<[_; 4]> = - dyn_ty.bounds.skip_binders().iter(Interner).cloned().collect(); - let (auto_traits, others): (SmallVec<[_; 4]>, _) = - bounds.drain(1..).partition(|b| b.skip_binders().trait_id().is_some()); - bounds.extend(others); - bounds.extend(auto_traits); - - if f.render_lifetime(&dyn_ty.lifetime) { - // we skip the binders in `write_bounds_like_dyn_trait_with_prefix` - bounds.push(Binders::empty( - Interner, - chalk_ir::WhereClause::TypeOutlives(chalk_ir::TypeOutlives { - ty: ty.clone(), - lifetime: dyn_ty.lifetime.clone(), - }), - )); - } - - write_bounds_like_dyn_trait_with_prefix( - f, - "dyn", - Either::Left(&ty), - &bounds, - SizedByDefault::NotSized, - )?; - } - TyKind::Error(_) => { - if f.display_kind.is_source_code() { - f.write_char('_')?; - } else { - write!(f, "{{unknown}}")?; - } - } - TyKind::Infer(..) => write!(f, "_")?, - TyKind::Coroutine(_, subst) => { - if f.display_kind.is_source_code() { - return Err(HirDisplayError::DisplaySourceCodeError( - DisplaySourceCodeError::Coroutine, - )); - } - let CoroutineArgsParts { resume_ty, yield_ty, return_ty, .. } = - subst.split_coroutine_args(); - write!(f, "|")?; - resume_ty.hir_fmt(f)?; - write!(f, "|")?; - - write!(f, " yields ")?; - yield_ty.hir_fmt(f)?; - - write!(f, " -> ")?; - return_ty.hir_fmt(f)?; - } TyKind::CoroutineWitness(..) => write!(f, "{{coroutine witness}}")?, TyKind::Pat(_, _) => write!(f, "{{pat}}")?, TyKind::UnsafeBinder(_) => write!(f, "{{unsafe binder}}")?, - TyKind::CoroutineClosure(_, _) => write!(f, "{{coroutine closure}}")?, TyKind::Alias(_, _) => write!(f, "{{alias}}")?, } Ok(()) } } -fn hir_fmt_generics( - f: &mut HirFormatter<'_>, - parameters: &[GenericArg], +fn hir_fmt_generics<'db>( + f: &mut HirFormatter<'_, 'db>, + parameters: &[GenericArg<'db>], generic_def: Option, - self_: Option<&Ty>, + self_: Option>, ) -> Result<(), HirDisplayError> { if parameters.is_empty() { return Ok(()); @@ -1743,70 +1700,23 @@ fn hir_fmt_generics( Ok(()) } -fn hir_fmt_generics_ns<'db>( - f: &mut HirFormatter<'_>, - parameters: &[crate::next_solver::GenericArg<'db>], +fn generic_args_sans_defaults<'ga, 'db>( + f: &mut HirFormatter<'_, 'db>, generic_def: Option, - self_: Option>, -) -> Result<(), HirDisplayError> { - if parameters.is_empty() { - return Ok(()); - } - - let parameters_to_write = generic_args_sans_defaults_ns(f, generic_def, parameters); - - if !parameters_to_write.is_empty() { - write!(f, "<")?; - hir_fmt_generic_arguments_ns(f, parameters_to_write, self_)?; - write!(f, ">")?; - } - - Ok(()) -} - -fn generic_args_sans_defaults<'ga>( - f: &mut HirFormatter<'_>, - generic_def: Option, - parameters: &'ga [GenericArg], -) -> &'ga [GenericArg] { + parameters: &'ga [GenericArg<'db>], +) -> &'ga [GenericArg<'db>] { if f.display_kind.is_source_code() || f.omit_verbose_types() { - match generic_def - .map(|generic_def_id| f.db.generic_defaults(generic_def_id)) - .filter(|it| !it.is_empty()) - { + match generic_def.map(|generic_def_id| f.db.generic_defaults(generic_def_id)) { None => parameters, Some(default_parameters) => { - let should_show = |arg: &GenericArg, i: usize| { - let is_err = |arg: &GenericArg| match arg.data(Interner) { - chalk_ir::GenericArgData::Lifetime(it) => { - *it.data(Interner) == LifetimeData::Error - } - chalk_ir::GenericArgData::Ty(it) => *it.kind(Interner) == TyKind::Error, - chalk_ir::GenericArgData::Const(it) => matches!( - it.data(Interner).value, - ConstValue::Concrete(ConcreteConst { - interned: ConstScalar::Unknown, - .. - }) - ), - }; - // if the arg is error like, render it to inform the user - if is_err(arg) { - return true; - } - // otherwise, if the arg is equal to the param default, hide it (unless the - // default is an error which can happen for the trait Self type) - match default_parameters.get(i) { - None => true, - Some(default_parameter) => { - // !is_err(default_parameter.skip_binders()) - // && - arg != &default_parameter.clone().substitute(Interner, ¶meters[..i]) - } + let should_show = |arg: GenericArg<'db>, i: usize| match default_parameters.get(i) { + None => true, + Some(default_parameter) => { + arg != default_parameter.instantiate(f.interner, ¶meters[..i]) } }; let mut default_from = 0; - for (i, parameter) in parameters.iter().enumerate() { + for (i, ¶meter) in parameters.iter().enumerate() { if should_show(parameter, i) { default_from = i + 1; } @@ -1820,114 +1730,30 @@ fn generic_args_sans_defaults<'ga>( } fn hir_fmt_generic_args<'db>( - f: &mut HirFormatter<'_>, - parameters: &[crate::next_solver::GenericArg<'db>], + f: &mut HirFormatter<'_, 'db>, + parameters: &[GenericArg<'db>], generic_def: Option, - self_: Option>, + self_: Option>, ) -> Result<(), HirDisplayError> { if parameters.is_empty() { return Ok(()); } - let parameters_to_write = generic_args_sans_defaults_ns(f, generic_def, parameters); + let parameters_to_write = generic_args_sans_defaults(f, generic_def, parameters); if !parameters_to_write.is_empty() { write!(f, "<")?; - hir_fmt_generic_arguments_ns(f, parameters_to_write, self_)?; + hir_fmt_generic_arguments(f, parameters_to_write, self_)?; write!(f, ">")?; } Ok(()) } -fn generic_args_sans_defaults_ns<'ga, 'db>( - f: &mut HirFormatter<'_>, - generic_def: Option, - parameters: &'ga [crate::next_solver::GenericArg<'db>], -) -> &'ga [crate::next_solver::GenericArg<'db>] { - let interner = DbInterner::new_with(f.db, Some(f.krate()), None); - if f.display_kind.is_source_code() || f.omit_verbose_types() { - match generic_def - .map(|generic_def_id| f.db.generic_defaults(generic_def_id)) - .filter(|it| !it.is_empty()) - { - None => parameters, - Some(default_parameters) => { - let should_show = |arg: &crate::next_solver::GenericArg<'db>, i: usize| { - let is_err = |arg: &crate::next_solver::GenericArg<'db>| match arg.kind() { - rustc_type_ir::GenericArgKind::Lifetime(it) => { - matches!(it.kind(), RegionKind::ReError(..)) - } - rustc_type_ir::GenericArgKind::Type(it) => { - matches!(it.kind(), rustc_type_ir::TyKind::Error(..)) - } - rustc_type_ir::GenericArgKind::Const(it) => { - matches!(it.kind(), rustc_type_ir::ConstKind::Error(..),) - } - }; - // if the arg is error like, render it to inform the user - if is_err(arg) { - return true; - } - // otherwise, if the arg is equal to the param default, hide it (unless the - // default is an error which can happen for the trait Self type) - match default_parameters.get(i) { - None => true, - Some(default_parameter) => { - // !is_err(default_parameter.skip_binders()) - // && - arg != &default_parameter - .clone() - .substitute( - Interner, - &convert_args_for_result(interner, ¶meters[..i]), - ) - .to_nextsolver(interner) - } - } - }; - let mut default_from = 0; - for (i, parameter) in parameters.iter().enumerate() { - if should_show(parameter, i) { - default_from = i + 1; - } - } - ¶meters[0..default_from] - } - } - } else { - parameters - } -} - -fn hir_fmt_generic_arguments( - f: &mut HirFormatter<'_>, - parameters: &[GenericArg], - self_: Option<&Ty>, -) -> Result<(), HirDisplayError> { - let mut first = true; - let lifetime_offset = parameters.iter().position(|arg| arg.lifetime(Interner).is_some()); - - let (ty_or_const, lifetimes) = match lifetime_offset { - Some(offset) => parameters.split_at(offset), - None => (parameters, &[][..]), - }; - for generic_arg in lifetimes.iter().chain(ty_or_const) { - if !mem::take(&mut first) { - write!(f, ", ")?; - } - match self_ { - self_ @ Some(_) if generic_arg.ty(Interner) == self_ => write!(f, "Self")?, - _ => generic_arg.hir_fmt(f)?, - } - } - Ok(()) -} - -fn hir_fmt_generic_arguments_ns<'db>( - f: &mut HirFormatter<'_>, - parameters: &[crate::next_solver::GenericArg<'db>], - self_: Option>, +fn hir_fmt_generic_arguments<'db>( + f: &mut HirFormatter<'_, 'db>, + parameters: &[GenericArg<'db>], + self_: Option>, ) -> Result<(), HirDisplayError> { let mut first = true; let lifetime_offset = parameters.iter().position(|arg| arg.region().is_some()); @@ -1948,9 +1774,28 @@ fn hir_fmt_generic_arguments_ns<'db>( Ok(()) } -impl HirDisplay for CallableSig { - fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { - let CallableSig { params_and_return: _, is_varargs, safety, abi: _ } = *self; +fn hir_fmt_tys<'db>( + f: &mut HirFormatter<'_, 'db>, + tys: &[Ty<'db>], + self_: Option>, +) -> Result<(), HirDisplayError> { + let mut first = true; + + for ty in tys { + if !mem::take(&mut first) { + write!(f, ", ")?; + } + match self_ { + Some(self_) if *ty == self_ => write!(f, "Self")?, + _ => ty.hir_fmt(f)?, + } + } + Ok(()) +} + +impl<'db> HirDisplay<'db> for PolyFnSig<'db> { + fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> { + let FnSig { inputs_and_output, c_variadic, safety, abi: _ } = self.skip_binder(); if let Safety::Unsafe = safety { write!(f, "unsafe ")?; } @@ -1961,16 +1806,16 @@ impl HirDisplay for CallableSig { // f.write_str("\" ")?; // } write!(f, "fn(")?; - f.write_joined(self.params(), ", ")?; - if is_varargs { - if self.params().is_empty() { + f.write_joined(inputs_and_output.inputs(), ", ")?; + if c_variadic { + if inputs_and_output.inputs().is_empty() { write!(f, "...")?; } else { write!(f, ", ...")?; } } write!(f, ")")?; - let ret = self.ret(); + let ret = inputs_and_output.output(); if !ret.is_unit() { write!(f, " -> ")?; ret.hir_fmt(f)?; @@ -1979,6 +1824,15 @@ impl HirDisplay for CallableSig { } } +impl<'db> HirDisplay<'db> for Term<'db> { + fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> { + match self { + Term::Ty(it) => it.hir_fmt(f), + Term::Const(it) => it.hir_fmt(f), + } + } +} + fn fn_traits(db: &dyn DefDatabase, trait_: TraitId) -> impl Iterator + '_ { let krate = trait_.lookup(db).container.krate(); utils::fn_traits(db, krate) @@ -2002,11 +1856,11 @@ impl SizedByDefault { } } -pub fn write_bounds_like_dyn_trait_with_prefix( - f: &mut HirFormatter<'_>, +pub fn write_bounds_like_dyn_trait_with_prefix<'db>( + f: &mut HirFormatter<'_, 'db>, prefix: &str, - this: Either<&Ty, &Lifetime>, - predicates: &[QuantifiedWhereClause], + this: Either, Region<'db>>, + predicates: &[Clause<'db>], default_sized: SizedByDefault, ) -> Result<(), HirDisplayError> { write!(f, "{prefix}")?; @@ -2020,10 +1874,10 @@ pub fn write_bounds_like_dyn_trait_with_prefix( } } -fn write_bounds_like_dyn_trait( - f: &mut HirFormatter<'_>, - this: Either<&Ty, &Lifetime>, - predicates: &[QuantifiedWhereClause], +fn write_bounds_like_dyn_trait<'db>( + f: &mut HirFormatter<'_, 'db>, + this: Either, Region<'db>>, + predicates: &[Clause<'db>], default_sized: SizedByDefault, ) -> Result<(), HirDisplayError> { // Note: This code is written to produce nice results (i.e. @@ -2036,10 +1890,10 @@ fn write_bounds_like_dyn_trait( let mut angle_open = false; let mut is_fn_trait = false; let mut is_sized = false; - for p in predicates.iter() { - match p.skip_binders() { - WhereClause::Implemented(trait_ref) => { - let trait_ = trait_ref.hir_trait_id(); + for p in predicates { + match p.kind().skip_binder() { + ClauseKind::Trait(trait_ref) => { + let trait_ = trait_ref.def_id().0; if default_sized.is_sized_trait(trait_, f.db) { is_sized = true; if matches!(default_sized, SizedByDefault::Sized { .. }) { @@ -2064,31 +1918,30 @@ fn write_bounds_like_dyn_trait( write!(f, "{}", f.db.trait_signature(trait_).name.display(f.db, f.edition()))?; f.end_location_link(); if is_fn_trait { - if let [self_, params @ ..] = trait_ref.substitution.as_slice(Interner) - && let Some(args) = - params.first().and_then(|it| it.assert_ty_ref(Interner).as_tuple()) + if let [_self, params @ ..] = trait_ref.trait_ref.args.as_slice() + && let Some(args) = params.first().and_then(|it| it.ty()?.as_tuple()) { write!(f, "(")?; - hir_fmt_generic_arguments(f, args.as_slice(Interner), self_.ty(Interner))?; + hir_fmt_tys(f, args.as_slice(), Some(trait_ref.trait_ref.self_ty()))?; write!(f, ")")?; } } else { let params = generic_args_sans_defaults( f, Some(trait_.into()), - trait_ref.substitution.as_slice(Interner), + trait_ref.trait_ref.args.as_slice(), ); - if let [self_, params @ ..] = params + if let [_self, params @ ..] = params && !params.is_empty() { write!(f, "<")?; - hir_fmt_generic_arguments(f, params, self_.ty(Interner))?; + hir_fmt_generic_arguments(f, params, Some(trait_ref.trait_ref.self_ty()))?; // there might be assoc type bindings, so we leave the angle brackets open angle_open = true; } } } - WhereClause::TypeOutlives(to) if Either::Left(&to.ty) == this => { + ClauseKind::TypeOutlives(to) if Either::Left(to.0) == this => { if !is_fn_trait && angle_open { write!(f, ">")?; angle_open = false; @@ -2096,10 +1949,9 @@ fn write_bounds_like_dyn_trait( if !first { write!(f, " + ")?; } - to.lifetime.hir_fmt(f)?; + to.1.hir_fmt(f)?; } - WhereClause::TypeOutlives(_) => {} - WhereClause::LifetimeOutlives(lo) if Either::Right(&lo.a) == this => { + ClauseKind::RegionOutlives(lo) if Either::Right(lo.0) == this => { if !is_fn_trait && angle_open { write!(f, ">")?; angle_open = false; @@ -2107,17 +1959,16 @@ fn write_bounds_like_dyn_trait( if !first { write!(f, " + ")?; } - lo.b.hir_fmt(f)?; + lo.1.hir_fmt(f)?; } - WhereClause::LifetimeOutlives(_) => {} - WhereClause::AliasEq(alias_eq) if is_fn_trait => { + ClauseKind::Projection(projection) if is_fn_trait => { is_fn_trait = false; - if !alias_eq.ty.is_unit() { + if !projection.term.as_type().is_some_and(|it| it.is_unit()) { write!(f, " -> ")?; - alias_eq.ty.hir_fmt(f)?; + projection.term.hir_fmt(f)?; } } - WhereClause::AliasEq(AliasEq { ty, alias }) => { + ClauseKind::Projection(projection) => { // in types in actual Rust, these will always come // after the corresponding Implemented predicate if angle_open { @@ -2126,28 +1977,22 @@ fn write_bounds_like_dyn_trait( write!(f, "<")?; angle_open = true; } - if let AliasTy::Projection(proj) = alias { - let assoc_ty_id = from_assoc_type_id(proj.associated_ty_id); - let type_alias = f.db.type_alias_signature(assoc_ty_id); - f.start_location_link(assoc_ty_id.into()); - write!(f, "{}", type_alias.name.display(f.db, f.edition()))?; - f.end_location_link(); + let assoc_ty_id = projection.def_id().expect_type_alias(); + let type_alias = f.db.type_alias_signature(assoc_ty_id); + f.start_location_link(assoc_ty_id.into()); + write!(f, "{}", type_alias.name.display(f.db, f.edition()))?; + f.end_location_link(); - let proj_arg_count = generics(f.db, assoc_ty_id.into()).len_self(); - let parent_len = proj.substitution.len(Interner) - proj_arg_count; - if proj_arg_count > 0 { - write!(f, "<")?; - hir_fmt_generic_arguments( - f, - &proj.substitution.as_slice(Interner)[parent_len..], - None, - )?; - write!(f, ">")?; - } - write!(f, " = ")?; + let own_args = projection.projection_term.own_args(f.interner); + if !own_args.is_empty() { + write!(f, "<")?; + hir_fmt_generic_arguments(f, own_args.as_slice(), None)?; + write!(f, ">")?; } - ty.hir_fmt(f)?; + write!(f, " = ")?; + projection.term.hir_fmt(f)?; } + _ => {} } first = false; } @@ -2177,154 +2022,52 @@ fn write_bounds_like_dyn_trait( Ok(()) } -impl HirDisplay for TraitRef { - fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { - let trait_ = self.hir_trait_id(); - f.start_location_link(trait_.into()); - write!(f, "{}", f.db.trait_signature(trait_).name.display(f.db, f.edition()))?; - f.end_location_link(); - let substs = self.substitution.as_slice(Interner); - hir_fmt_generics(f, &substs[1..], None, substs[0].ty(Interner)) - } -} - -impl<'db> HirDisplay for crate::next_solver::TraitRef<'db> { - fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { +impl<'db> HirDisplay<'db> for TraitRef<'db> { + fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> { let trait_ = self.def_id.0; f.start_location_link(trait_.into()); write!(f, "{}", f.db.trait_signature(trait_).name.display(f.db, f.edition()))?; f.end_location_link(); let substs = self.args.as_slice(); - hir_fmt_generic_args(f, &substs[1..], None, substs[0].ty()) + hir_fmt_generic_args(f, &substs[1..], None, Some(self.self_ty())) } } -impl HirDisplay for WhereClause { - fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { - if f.should_truncate() { - return write!(f, "{TYPE_HINT_TRUNCATION}"); - } - - match self { - WhereClause::Implemented(trait_ref) => { - trait_ref.self_type_parameter(Interner).hir_fmt(f)?; - write!(f, ": ")?; - trait_ref.hir_fmt(f)?; - } - WhereClause::AliasEq(AliasEq { alias: AliasTy::Projection(projection_ty), ty }) => { - write!(f, "<")?; - let trait_ref = &projection_ty.trait_ref(f.db); - trait_ref.self_type_parameter(Interner).hir_fmt(f)?; - write!(f, " as ")?; - trait_ref.hir_fmt(f)?; - write!(f, ">::",)?; - let type_alias = from_assoc_type_id(projection_ty.associated_ty_id); - f.start_location_link(type_alias.into()); - write!( - f, - "{}", - f.db.type_alias_signature(type_alias).name.display(f.db, f.edition()), - )?; - f.end_location_link(); - write!(f, " = ")?; - ty.hir_fmt(f)?; - } - WhereClause::AliasEq(_) => write!(f, "{{error}}")?, - - // FIXME implement these - WhereClause::TypeOutlives(..) => {} - WhereClause::LifetimeOutlives(..) => {} - } - Ok(()) - } -} - -impl HirDisplay for LifetimeOutlives { - fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { - self.a.hir_fmt(f)?; - write!(f, ": ")?; - self.b.hir_fmt(f) - } -} - -impl HirDisplay for Lifetime { - fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { - self.interned().hir_fmt(f) - } -} - -impl HirDisplay for LifetimeData { - fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { - match self { - LifetimeData::Placeholder(idx) => { - let id = lt_from_placeholder_idx(f.db, *idx).0; - let generics = generics(f.db, id.parent); - let param_data = &generics[id.local_id]; - write!(f, "{}", param_data.name.display(f.db, f.edition()))?; - Ok(()) - } - LifetimeData::BoundVar(idx) => idx.hir_fmt(f), - LifetimeData::InferenceVar(_) => write!(f, "_"), - LifetimeData::Static => write!(f, "'static"), - LifetimeData::Error => { - if cfg!(test) { - write!(f, "'?") - } else { - write!(f, "'_") - } - } - LifetimeData::Erased => write!(f, "'"), - LifetimeData::Phantom(void, _) => match *void {}, - } - } -} - -impl<'db> HirDisplay for crate::next_solver::Region<'db> { - fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { +impl<'db> HirDisplay<'db> for Region<'db> { + fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> { match self.kind() { - rustc_type_ir::RegionKind::ReEarlyParam(param) => { + RegionKind::ReEarlyParam(param) => { let generics = generics(f.db, param.id.parent); let param_data = &generics[param.id.local_id]; write!(f, "{}", param_data.name.display(f.db, f.edition()))?; Ok(()) } - rustc_type_ir::RegionKind::ReBound(db, idx) => { + RegionKind::ReBound(BoundVarIndexKind::Bound(db), idx) => { write!(f, "?{}.{}", db.as_u32(), idx.var.as_u32()) } - rustc_type_ir::RegionKind::ReVar(_) => write!(f, "_"), - rustc_type_ir::RegionKind::ReStatic => write!(f, "'static"), - rustc_type_ir::RegionKind::ReError(..) => { + RegionKind::ReBound(BoundVarIndexKind::Canonical, idx) => { + write!(f, "?c.{}", idx.var.as_u32()) + } + RegionKind::ReVar(_) => write!(f, "_"), + RegionKind::ReStatic => write!(f, "'static"), + RegionKind::ReError(..) => { if cfg!(test) { write!(f, "'?") } else { write!(f, "'_") } } - rustc_type_ir::RegionKind::ReErased => write!(f, "'"), - rustc_type_ir::RegionKind::RePlaceholder(_) => write!(f, ""), - rustc_type_ir::RegionKind::ReLateParam(_) => write!(f, ""), + RegionKind::ReErased => write!(f, "'"), + RegionKind::RePlaceholder(_) => write!(f, ""), + RegionKind::ReLateParam(_) => write!(f, ""), } } } -impl HirDisplay for DomainGoal { - fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { - match self { - DomainGoal::Holds(wc) => { - write!(f, "Holds(")?; - wc.hir_fmt(f)?; - write!(f, ")")?; - } - _ => write!(f, "_")?, - } - Ok(()) - } -} - -pub fn write_visibility( +pub fn write_visibility<'db>( module_id: ModuleId, vis: Visibility, - f: &mut HirFormatter<'_>, + f: &mut HirFormatter<'_, 'db>, ) -> Result<(), HirDisplayError> { match vis { Visibility::Public => write!(f, "pub "), @@ -2346,28 +2089,30 @@ pub fn write_visibility( } } -pub trait HirDisplayWithExpressionStore { +pub trait HirDisplayWithExpressionStore<'db> { fn hir_fmt( &self, - f: &mut HirFormatter<'_>, + f: &mut HirFormatter<'_, 'db>, store: &ExpressionStore, ) -> Result<(), HirDisplayError>; } -impl HirDisplayWithExpressionStore for &'_ T { +impl<'db, T: ?Sized + HirDisplayWithExpressionStore<'db>> HirDisplayWithExpressionStore<'db> + for &'_ T +{ fn hir_fmt( &self, - f: &mut HirFormatter<'_>, + f: &mut HirFormatter<'_, 'db>, store: &ExpressionStore, ) -> Result<(), HirDisplayError> { T::hir_fmt(&**self, f, store) } } -pub fn hir_display_with_store<'a, T: HirDisplayWithExpressionStore + 'a>( +pub fn hir_display_with_store<'a, 'db, T: HirDisplayWithExpressionStore<'db> + 'a>( value: T, store: &'a ExpressionStore, -) -> impl HirDisplay + 'a { +) -> impl HirDisplay<'db> + 'a { ExpressionStoreAdapter(value, store) } @@ -2379,15 +2124,15 @@ impl<'a, T> ExpressionStoreAdapter<'a, T> { } } -impl HirDisplay for ExpressionStoreAdapter<'_, T> { - fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { +impl<'db, T: HirDisplayWithExpressionStore<'db>> HirDisplay<'db> for ExpressionStoreAdapter<'_, T> { + fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> { T::hir_fmt(&self.0, f, self.1) } } -impl HirDisplayWithExpressionStore for LifetimeRefId { +impl<'db> HirDisplayWithExpressionStore<'db> for LifetimeRefId { fn hir_fmt( &self, - f: &mut HirFormatter<'_>, + f: &mut HirFormatter<'_, 'db>, store: &ExpressionStore, ) -> Result<(), HirDisplayError> { match &store[*self] { @@ -2407,10 +2152,10 @@ impl HirDisplayWithExpressionStore for LifetimeRefId { } } -impl HirDisplayWithExpressionStore for TypeRefId { +impl<'db> HirDisplayWithExpressionStore<'db> for TypeRefId { fn hir_fmt( &self, - f: &mut HirFormatter<'_>, + f: &mut HirFormatter<'_, 'db>, store: &ExpressionStore, ) -> Result<(), HirDisplayError> { match &store[*self] { @@ -2536,10 +2281,10 @@ impl HirDisplayWithExpressionStore for TypeRefId { } } -impl HirDisplayWithExpressionStore for ConstRef { +impl<'db> HirDisplayWithExpressionStore<'db> for ConstRef { fn hir_fmt( &self, - f: &mut HirFormatter<'_>, + f: &mut HirFormatter<'_, 'db>, _store: &ExpressionStore, ) -> Result<(), HirDisplayError> { // FIXME @@ -2549,10 +2294,10 @@ impl HirDisplayWithExpressionStore for ConstRef { } } -impl HirDisplayWithExpressionStore for TypeBound { +impl<'db> HirDisplayWithExpressionStore<'db> for TypeBound { fn hir_fmt( &self, - f: &mut HirFormatter<'_>, + f: &mut HirFormatter<'_, 'db>, store: &ExpressionStore, ) -> Result<(), HirDisplayError> { match self { @@ -2593,10 +2338,10 @@ impl HirDisplayWithExpressionStore for TypeBound { } } -impl HirDisplayWithExpressionStore for Path { +impl<'db> HirDisplayWithExpressionStore<'db> for Path { fn hir_fmt( &self, - f: &mut HirFormatter<'_>, + f: &mut HirFormatter<'_, 'db>, store: &ExpressionStore, ) -> Result<(), HirDisplayError> { match (self.type_anchor(), self.kind()) { @@ -2745,10 +2490,10 @@ impl HirDisplayWithExpressionStore for Path { } } -impl HirDisplayWithExpressionStore for hir_def::expr_store::path::GenericArg { +impl<'db> HirDisplayWithExpressionStore<'db> for hir_def::expr_store::path::GenericArg { fn hir_fmt( &self, - f: &mut HirFormatter<'_>, + f: &mut HirFormatter<'_, 'db>, store: &ExpressionStore, ) -> Result<(), HirDisplayError> { match self { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/drop.rs b/src/tools/rust-analyzer/crates/hir-ty/src/drop.rs index aaf274799c63..b09d1fb196c4 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/drop.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/drop.rs @@ -85,7 +85,7 @@ fn has_drop_glue_impl<'db>( { return DropGlue::None; } - db.field_types_ns(id.into()) + db.field_types(id.into()) .iter() .map(|(_, field_ty)| { has_drop_glue_impl( @@ -105,7 +105,7 @@ fn has_drop_glue_impl<'db>( .variants .iter() .map(|&(variant, _, _)| { - db.field_types_ns(variant.into()) + db.field_types(variant.into()) .iter() .map(|(_, field_ty)| { has_drop_glue_impl( diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs b/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs index b2406a088958..437141e41db9 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs @@ -7,7 +7,6 @@ use hir_def::{ TypeAliasId, TypeOrConstParamId, TypeParamId, hir::generics::LocalTypeOrConstParamId, lang_item::LangItem, signatures::TraitFlags, }; -use intern::Symbol; use rustc_hash::FxHashSet; use rustc_type_ir::{ AliasTyKind, ClauseKind, PredicatePolarity, TypeSuperVisitable as _, TypeVisitable as _, @@ -19,10 +18,10 @@ use smallvec::SmallVec; use crate::{ ImplTraitId, db::{HirDatabase, InternedOpaqueTyId}, - lower_nextsolver::associated_ty_item_bounds, + lower::associated_ty_item_bounds, next_solver::{ - Clause, Clauses, DbInterner, GenericArgs, ParamEnv, SolverDefId, TraitPredicate, TraitRef, - TypingMode, infer::DbInternerInferExt, mk_param, + Binder, Clause, Clauses, DbInterner, EarlyBinder, GenericArgs, Goal, ParamEnv, ParamTy, + SolverDefId, TraitPredicate, TraitRef, Ty, TypingMode, infer::DbInternerInferExt, mk_param, }, traits::next_trait_solve_in_ctxt, }; @@ -137,7 +136,7 @@ pub fn generics_require_sized_self(db: &dyn HirDatabase, def: GenericDefId) -> b }; let interner = DbInterner::new_with(db, Some(krate), None); - let predicates = db.generic_predicates_ns(def); + let predicates = db.generic_predicates(def); // FIXME: We should use `explicit_predicates_of` here, which hasn't been implemented to // rust-analyzer yet // https://github.com/rust-lang/rust/blob/ddaf12390d3ffb7d5ba74491a48f3cd528e5d777/compiler/rustc_hir_analysis/src/collect/predicates_of.rs#L490 @@ -163,7 +162,7 @@ pub fn generics_require_sized_self(db: &dyn HirDatabase, def: GenericDefId) -> b // but we don't have good way to render such locations. // So, just return single boolean value for existence of such `Self` reference fn predicates_reference_self(db: &dyn HirDatabase, trait_: TraitId) -> bool { - db.generic_predicates_ns(trait_.into()) + db.generic_predicates(trait_.into()) .iter() .any(|pred| predicate_references_self(db, trait_, pred, AllowSelfProjection::No)) } @@ -379,7 +378,7 @@ where }) = pred && let trait_data = db.trait_signature(pred_trait_ref.def_id.0) && trait_data.flags.contains(TraitFlags::AUTO) - && let rustc_type_ir::TyKind::Param(crate::next_solver::ParamTy { index: 0, .. }) = + && let rustc_type_ir::TyKind::Param(ParamTy { index: 0, .. }) = pred_trait_ref.self_ty().kind() { continue; @@ -398,10 +397,7 @@ fn receiver_is_dispatchable<'db>( db: &dyn HirDatabase, trait_: TraitId, func: FunctionId, - sig: &crate::next_solver::EarlyBinder< - 'db, - crate::next_solver::Binder<'db, rustc_type_ir::FnSig>>, - >, + sig: &EarlyBinder<'db, Binder<'db, rustc_type_ir::FnSig>>>, ) -> bool { let sig = sig.instantiate_identity(); @@ -410,10 +406,8 @@ fn receiver_is_dispatchable<'db>( parent: trait_.into(), local_id: LocalTypeOrConstParamId::from_raw(la_arena::RawIdx::from_u32(0)), }); - let self_param_ty = crate::next_solver::Ty::new( - interner, - rustc_type_ir::TyKind::Param(crate::next_solver::ParamTy { index: 0, id: self_param_id }), - ); + let self_param_ty = + Ty::new(interner, rustc_type_ir::TyKind::Param(ParamTy { index: 0, id: self_param_id })); // `self: Self` can't be dispatched on, but this is already considered dyn-compatible // See rustc's comment on https://github.com/rust-lang/rust/blob/3f121b9461cce02a703a0e7e450568849dfaa074/compiler/rustc_trait_selection/src/traits/object_safety.rs#L433-L437 @@ -441,21 +435,20 @@ fn receiver_is_dispatchable<'db>( // Type `U` // FIXME: That seems problematic to fake a generic param like that? - let unsized_self_ty = - crate::next_solver::Ty::new_param(interner, self_param_id, u32::MAX, Symbol::empty()); + let unsized_self_ty = Ty::new_param(interner, self_param_id, u32::MAX); // `Receiver[Self => U]` let unsized_receiver_ty = receiver_for_self_ty(interner, func, receiver_ty, unsized_self_ty); let param_env = { - let generic_predicates = &*db.generic_predicates_ns(func.into()); + let generic_predicates = &*db.generic_predicates(func.into()); // Self: Unsize let unsize_predicate = TraitRef::new(interner, unsize_did.into(), [self_param_ty, unsized_self_ty]); // U: Trait - let args = GenericArgs::for_item(interner, trait_.into(), |name, index, kind, _| { - if index == 0 { unsized_self_ty.into() } else { mk_param(interner, index, name, kind) } + let args = GenericArgs::for_item(interner, trait_.into(), |index, kind, _| { + if index == 0 { unsized_self_ty.into() } else { mk_param(interner, index, kind) } }); let trait_predicate = TraitRef::new_from_args(interner, trait_.into(), args); @@ -477,7 +470,7 @@ fn receiver_is_dispatchable<'db>( // Receiver: DispatchFromDyn U]> let predicate = TraitRef::new(interner, dispatch_from_dyn_did.into(), [receiver_ty, unsized_receiver_ty]); - let goal = crate::next_solver::Goal::new(interner, param_env, predicate); + let goal = Goal::new(interner, param_env, predicate); let infcx = interner.infer_ctxt().build(TypingMode::non_body_analysis()); // the receiver is dispatchable iff the obligation holds @@ -488,26 +481,19 @@ fn receiver_is_dispatchable<'db>( fn receiver_for_self_ty<'db>( interner: DbInterner<'db>, func: FunctionId, - receiver_ty: crate::next_solver::Ty<'db>, - self_ty: crate::next_solver::Ty<'db>, -) -> crate::next_solver::Ty<'db> { - let args = crate::next_solver::GenericArgs::for_item( - interner, - SolverDefId::FunctionId(func), - |name, index, kind, _| { - if index == 0 { self_ty.into() } else { mk_param(interner, index, name, kind) } - }, - ); + receiver_ty: Ty<'db>, + self_ty: Ty<'db>, +) -> Ty<'db> { + let args = GenericArgs::for_item(interner, SolverDefId::FunctionId(func), |index, kind, _| { + if index == 0 { self_ty.into() } else { mk_param(interner, index, kind) } + }); - crate::next_solver::EarlyBinder::bind(receiver_ty).instantiate(interner, args) + EarlyBinder::bind(receiver_ty).instantiate(interner, args) } fn contains_illegal_impl_trait_in_trait<'db>( db: &'db dyn HirDatabase, - sig: &crate::next_solver::EarlyBinder< - 'db, - crate::next_solver::Binder<'db, rustc_type_ir::FnSig>>, - >, + sig: &EarlyBinder<'db, Binder<'db, rustc_type_ir::FnSig>>>, ) -> Option { struct OpaqueTypeCollector(FxHashSet); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs b/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs index e179e41b1cbe..26e03aa01a1d 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs @@ -9,7 +9,6 @@ //! where parent follows the same scheme. use std::ops; -use chalk_ir::{BoundVar, DebruijnIndex, cast::Cast as _}; use hir_def::{ ConstParamId, GenericDefId, GenericParamId, ItemContainerId, LifetimeParamId, Lookup, TypeOrConstParamId, TypeParamId, @@ -23,8 +22,6 @@ use hir_def::{ use itertools::chain; use triomphe::Arc; -use crate::{Interner, Substitution, db::HirDatabase, lt_to_placeholder_idx, to_placeholder_idx}; - pub fn generics(db: &dyn DefDatabase, def: GenericDefId) -> Generics { let parent_generics = parent_generic_def(db, def).map(|def| Box::new(generics(db, def))); let (params, store) = db.generic_params_and_store(def); @@ -130,11 +127,16 @@ impl Generics { /// Returns total number of generic parameters in scope, including those from parent. pub(crate) fn len(&self) -> usize { - let parent = self.parent_generics().map_or(0, Generics::len); + let parent = self.len_parent(); let child = self.params.len(); parent + child } + #[inline] + pub(crate) fn len_parent(&self) -> usize { + self.parent_generics().map_or(0, Generics::len) + } + /// Returns numbers of generic parameters excluding those from parent. pub(crate) fn len_self(&self) -> usize { self.params.len() @@ -225,50 +227,6 @@ impl Generics { pub(crate) fn parent_generics(&self) -> Option<&Generics> { self.parent_generics.as_deref() } - - pub(crate) fn parent_or_self(&self) -> &Generics { - self.parent_generics.as_deref().unwrap_or(self) - } - - /// Returns a Substitution that replaces each parameter by a bound variable. - pub(crate) fn bound_vars_subst( - &self, - db: &dyn HirDatabase, - debruijn: DebruijnIndex, - ) -> Substitution { - Substitution::from_iter( - Interner, - self.iter_id().enumerate().map(|(idx, id)| match id { - GenericParamId::ConstParamId(id) => BoundVar::new(debruijn, idx) - .to_const(Interner, db.const_param_ty(id)) - .cast(Interner), - GenericParamId::TypeParamId(_) => { - BoundVar::new(debruijn, idx).to_ty(Interner).cast(Interner) - } - GenericParamId::LifetimeParamId(_) => { - BoundVar::new(debruijn, idx).to_lifetime(Interner).cast(Interner) - } - }), - ) - } - - /// Returns a Substitution that replaces each parameter by itself (i.e. `Ty::Param`). - pub fn placeholder_subst(&self, db: &dyn HirDatabase) -> Substitution { - Substitution::from_iter( - Interner, - self.iter_id().enumerate().map(|(index, id)| match id { - GenericParamId::TypeParamId(id) => { - to_placeholder_idx(db, id.into(), index as u32).to_ty(Interner).cast(Interner) - } - GenericParamId::ConstParamId(id) => to_placeholder_idx(db, id.into(), index as u32) - .to_const(Interner, db.const_param_ty(id)) - .cast(Interner), - GenericParamId::LifetimeParamId(id) => { - lt_to_placeholder_idx(db, id, index as u32).to_lifetime(Interner).cast(Interner) - } - }), - ) - } } pub(crate) fn trait_self_param_idx(db: &dyn DefDatabase, def: GenericDefId) -> Option { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs index 72498681aca5..361e66522df6 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs @@ -55,29 +55,24 @@ use stdx::never; use triomphe::Arc; use crate::{ - ImplTraitId, IncorrectGenericsLenKind, Interner, PathLoweringDiagnostic, TargetFeatures, - TraitEnvironment, + ImplTraitId, IncorrectGenericsLenKind, PathLoweringDiagnostic, TargetFeatures, db::{HirDatabase, InternedClosureId, InternedOpaqueTyId}, - generics::Generics, infer::{ coerce::{CoerceMany, DynamicCoerceMany}, diagnostics::{Diagnostics, InferenceTyLoweringContext as TyLoweringContext}, expr::ExprIsRead, unify::InferenceTable, }, - lower::diagnostics::TyLoweringDiagnostic, - lower_nextsolver::{ImplTraitIdx, ImplTraitLoweringMode, LifetimeElisionKind}, + lower::{ + ImplTraitIdx, ImplTraitLoweringMode, LifetimeElisionKind, diagnostics::TyLoweringDiagnostic, + }, mir::MirSpan, next_solver::{ AliasTy, Const, DbInterner, ErrorGuaranteed, GenericArg, GenericArgs, Region, Ty, TyKind, Tys, abi::Safety, fold::fold_tys, - infer::{ - DefineOpaqueTypes, - traits::{Obligation, ObligationCause}, - }, - mapping::{ChalkToNextSolver, NextSolverToChalk}, + infer::traits::{Obligation, ObligationCause}, }, traits::FnTrait, utils::TargetFeatureIsSafeInTarget, @@ -166,31 +161,6 @@ pub(crate) fn infer_cycle_result( }) } -/// Fully normalize all the types found within `ty` in context of `owner` body definition. -/// -/// This is appropriate to use only after type-check: it assumes -/// that normalization will succeed, for example. -#[tracing::instrument(level = "debug", skip(db))] -pub(crate) fn normalize( - db: &dyn HirDatabase, - trait_env: Arc>, - ty: crate::Ty, -) -> crate::Ty { - // FIXME: TypeFlags::HAS_CT_PROJECTION is not implemented in chalk, so TypeFlags::HAS_PROJECTION only - // works for the type case, so we check array unconditionally. Remove the array part - // when the bug in chalk becomes fixed. - if !ty.data(Interner).flags.intersects(crate::TypeFlags::HAS_PROJECTION) - && !matches!(ty.kind(Interner), crate::TyKind::Array(..)) - { - return ty; - } - let mut table = unify::InferenceTable::new(db, trait_env); - - let ty_with_vars = table.normalize_associated_types_in(ty.to_nextsolver(table.interner())); - table.select_obligations_where_possible(); - table.resolve_completely(ty_with_vars).to_chalk(table.interner()) -} - /// Binding modes inferred for patterns. /// #[derive(Copy, Clone, Debug, Eq, PartialEq, Default)] @@ -789,8 +759,7 @@ pub(crate) struct InferenceContext<'body, 'db> { /// and resolve the path via its methods. This will ensure proper error reporting. pub(crate) resolver: Resolver<'db>, target_features: OnceCell<(TargetFeatures, TargetFeatureIsSafeInTarget)>, - generic_def: GenericDefId, - generics: OnceCell, + pub(crate) generic_def: GenericDefId, table: unify::InferenceTable<'db>, /// The traits in scope, disregarding block modules. This is used for caching purposes. traits_in_scope: FxHashSet, @@ -899,7 +868,6 @@ impl<'body, 'db> InferenceContext<'body, 'db> { return_ty: types.error, // set in collect_* calls types, target_features: OnceCell::new(), - generics: OnceCell::new(), table, tuple_field_accesses_rev: Default::default(), resume_yield_tys: None, @@ -928,10 +896,6 @@ impl<'body, 'db> InferenceContext<'body, 'db> { } } - pub(crate) fn generics(&self) -> &Generics { - self.generics.get_or_init(|| crate::generics::generics(self.db, self.generic_def)) - } - #[inline] fn krate(&self) -> Crate { self.resolver.krate() @@ -1159,7 +1123,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> { GenericArgs::for_item_with_defaults( self.interner(), va_list.into(), - |_, _, id, _| self.table.next_var_for_param(id), + |_, id, _| self.table.next_var_for_param(id), ), ), None => self.err_ty(), @@ -1195,7 +1159,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> { }, ); let return_ty = self.insert_type_vars(return_ty); - if let Some(rpits) = self.db.return_type_impl_traits_ns(func) { + if let Some(rpits) = self.db.return_type_impl_traits(func) { let mut mode = ImplTraitReplacingMode::ReturnPosition(FxHashSet::default()); let result = self.insert_inference_vars_for_impl_trait(return_ty, &mut mode); if let ImplTraitReplacingMode::ReturnPosition(taits) = mode { @@ -1263,14 +1227,12 @@ impl<'body, 'db> InferenceContext<'body, 'db> { if matches!(mode, ImplTraitReplacingMode::TypeAlias) { // RPITs don't have `tait_coercion_table`, so use inserted inference // vars for them. - if let Some(ty) = - self.result.type_of_rpit.get(idx.to_nextsolver(self.interner())) - { + if let Some(ty) = self.result.type_of_rpit.get(idx) { return *ty; } return ty; } - (self.db.return_type_impl_traits_ns(def), idx) + (self.db.return_type_impl_traits(def), idx) } ImplTraitId::TypeAliasImplTrait(def, idx) => { if let ImplTraitReplacingMode::ReturnPosition(taits) = mode { @@ -1279,17 +1241,15 @@ impl<'body, 'db> InferenceContext<'body, 'db> { taits.insert(ty); return ty; } - (self.db.type_alias_impl_traits_ns(def), idx) + (self.db.type_alias_impl_traits(def), idx) } - _ => unreachable!(), }; let Some(impl_traits) = impl_traits else { return ty; }; - let bounds = (*impl_traits).as_ref().map_bound(|its| { - its.impl_traits[idx.to_nextsolver(self.interner())].predicates.as_slice() - }); - let var = match self.result.type_of_rpit.entry(idx.to_nextsolver(self.interner())) { + let bounds = + (*impl_traits).as_ref().map_bound(|its| its.impl_traits[idx].predicates.as_slice()); + let var = match self.result.type_of_rpit.entry(idx) { Entry::Occupied(entry) => return *entry.get(), Entry::Vacant(entry) => *entry.insert(self.table.next_ty_var()), }; @@ -1640,8 +1600,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> { match ty.kind() { TyKind::Adt(adt_def, substs) => match adt_def.def_id().0 { AdtId::StructId(struct_id) => { - match self.db.field_types_ns(struct_id.into()).values().next_back().copied() - { + match self.db.field_types(struct_id.into()).values().next_back().copied() { Some(field) => { ty = field.instantiate(self.interner(), substs); } @@ -1702,7 +1661,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> { .table .infer_ctxt .at(&ObligationCause::new(), self.table.trait_env.env) - .eq(DefineOpaqueTypes::Yes, expected, actual) + .eq(expected, actual) .map(|infer_ok| self.table.register_infer_ok(infer_ok)); if let Err(_err) = result { // FIXME: Emit diagnostic. diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/cast.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/cast.rs index 990281a7c896..c128977d7b08 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/cast.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/cast.rs @@ -394,7 +394,7 @@ fn pointer_kind<'db>( let struct_data = id.fields(ctx.db); if let Some((last_field, _)) = struct_data.fields().iter().last() { let last_field_ty = - ctx.db.field_types_ns(id.into())[last_field].instantiate(ctx.interner(), subst); + ctx.db.field_types(id.into())[last_field].instantiate(ctx.interner(), subst); pointer_kind(last_field_ty, ctx) } else { Ok(Some(PointerKind::Thin)) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs index 2637ed6b3ec9..06f8307eb0ab 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs @@ -11,8 +11,9 @@ use hir_def::{ type_ref::TypeRefId, }; use rustc_type_ir::{ - ClosureArgs, ClosureArgsParts, CoroutineArgs, CoroutineArgsParts, Interner, TypeSuperVisitable, - TypeVisitable, TypeVisitableExt, TypeVisitor, + ClosureArgs, ClosureArgsParts, CoroutineArgs, CoroutineArgsParts, CoroutineClosureArgs, + CoroutineClosureArgsParts, Interner, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, + TypeVisitor, inherent::{BoundExistentialPredicates, GenericArgs as _, IntoKind, SliceLike, Ty as _}, }; use tracing::debug; @@ -22,11 +23,12 @@ use crate::{ db::{InternedClosure, InternedCoroutine}, infer::{BreakableKind, Diverges, coerce::CoerceMany}, next_solver::{ - AliasTy, Binder, ClauseKind, DbInterner, ErrorGuaranteed, FnSig, GenericArgs, PolyFnSig, - PolyProjectionPredicate, Predicate, PredicateKind, SolverDefId, Ty, TyKind, + AliasTy, Binder, BoundRegionKind, BoundVarKind, BoundVarKinds, ClauseKind, DbInterner, + ErrorGuaranteed, FnSig, GenericArgs, PolyFnSig, PolyProjectionPredicate, Predicate, + PredicateKind, SolverDefId, Ty, TyKind, abi::Safety, infer::{ - BoundRegionConversionTime, DefineOpaqueTypes, InferOk, InferResult, + BoundRegionConversionTime, InferOk, InferResult, traits::{ObligationCause, PredicateObligations}, }, util::explicit_item_bounds, @@ -72,6 +74,8 @@ impl<'db> InferenceContext<'_, 'db> { let sig_ty = Ty::new_fn_ptr(interner, bound_sig); let parent_args = GenericArgs::identity_for_item(interner, self.generic_def.into()); + // FIXME: Make this an infer var and infer it later. + let tupled_upvars_ty = self.types.unit; let (id, ty, resume_yield_tys) = match closure_kind { ClosureKind::Coroutine(_) => { let yield_ty = self.table.next_ty_var(); @@ -80,11 +84,11 @@ impl<'db> InferenceContext<'_, 'db> { // FIXME: Infer the upvars later. let parts = CoroutineArgsParts { parent_args, - kind_ty: Ty::new_unit(interner), + kind_ty: self.types.unit, resume_ty, yield_ty, return_ty: body_ret_ty, - tupled_upvars_ty: Ty::new_unit(interner), + tupled_upvars_ty, }; let coroutine_id = @@ -97,9 +101,7 @@ impl<'db> InferenceContext<'_, 'db> { (None, coroutine_ty, Some((resume_ty, yield_ty))) } - // FIXME(next-solver): `ClosureKind::Async` should really be a separate arm that creates a `CoroutineClosure`. - // But for now we treat it as a closure. - ClosureKind::Closure | ClosureKind::Async => { + ClosureKind::Closure => { let closure_id = self.db.intern_closure(InternedClosure(self.owner, tgt_expr)); match expected_kind { Some(kind) => { @@ -117,7 +119,7 @@ impl<'db> InferenceContext<'_, 'db> { } None => {} }; - // FIXME: Infer the kind and the upvars later when needed. + // FIXME: Infer the kind later if needed. let parts = ClosureArgsParts { parent_args, closure_kind_ty: Ty::from_closure_kind( @@ -125,7 +127,7 @@ impl<'db> InferenceContext<'_, 'db> { expected_kind.unwrap_or(rustc_type_ir::ClosureKind::Fn), ), closure_sig_as_fn_ptr_ty: sig_ty, - tupled_upvars_ty: Ty::new_unit(interner), + tupled_upvars_ty, }; let closure_ty = Ty::new_closure( interner, @@ -136,6 +138,61 @@ impl<'db> InferenceContext<'_, 'db> { self.add_current_closure_dependency(closure_id); (Some(closure_id), closure_ty, None) } + ClosureKind::Async => { + // async closures always return the type ascribed after the `->` (if present), + // and yield `()`. + let bound_return_ty = bound_sig.skip_binder().output(); + let bound_yield_ty = self.types.unit; + // rustc uses a special lang item type for the resume ty. I don't believe this can cause us problems. + let resume_ty = self.types.unit; + + // FIXME: Infer the kind later if needed. + let closure_kind_ty = Ty::from_closure_kind( + interner, + expected_kind.unwrap_or(rustc_type_ir::ClosureKind::Fn), + ); + + // FIXME: Infer captures later. + // `for<'env> fn() -> ()`, for no captures. + let coroutine_captures_by_ref_ty = Ty::new_fn_ptr( + interner, + Binder::bind_with_vars( + interner.mk_fn_sig([], self.types.unit, false, Safety::Safe, FnAbi::Rust), + BoundVarKinds::new_from_iter( + interner, + [BoundVarKind::Region(BoundRegionKind::ClosureEnv)], + ), + ), + ); + let closure_args = CoroutineClosureArgs::new( + interner, + CoroutineClosureArgsParts { + parent_args, + closure_kind_ty, + signature_parts_ty: Ty::new_fn_ptr( + interner, + bound_sig.map_bound(|sig| { + interner.mk_fn_sig( + [ + resume_ty, + Ty::new_tup_from_iter(interner, sig.inputs().iter()), + ], + Ty::new_tup(interner, &[bound_yield_ty, bound_return_ty]), + sig.c_variadic, + sig.safety, + sig.abi, + ) + }), + ), + tupled_upvars_ty, + coroutine_captures_by_ref_ty, + }, + ); + + let coroutine_id = + self.db.intern_coroutine(InternedCoroutine(self.owner, tgt_expr)).into(); + (None, Ty::new_coroutine_closure(interner, coroutine_id, closure_args.args), None) + } }; // Now go through the argument patterns @@ -307,7 +364,7 @@ impl<'db> InferenceContext<'_, 'db> { .table .infer_ctxt .at(&ObligationCause::new(), self.table.trait_env.env) - .eq(DefineOpaqueTypes::Yes, inferred_fnptr_sig, generalized_fnptr_sig) + .eq(inferred_fnptr_sig, generalized_fnptr_sig) .map(|infer_ok| self.table.register_infer_ok(infer_ok)); let resolved_sig = @@ -692,18 +749,16 @@ impl<'db> InferenceContext<'_, 'db> { let InferOk { value: (), obligations } = table .infer_ctxt .at(&cause, table.trait_env.env) - .eq(DefineOpaqueTypes::Yes, expected_ty, supplied_ty)?; + .eq(expected_ty, supplied_ty)?; all_obligations.extend(obligations); } let supplied_output_ty = supplied_sig.output(); let cause = ObligationCause::new(); - let InferOk { value: (), obligations } = - table.infer_ctxt.at(&cause, table.trait_env.env).eq( - DefineOpaqueTypes::Yes, - expected_sigs.liberated_sig.output(), - supplied_output_ty, - )?; + let InferOk { value: (), obligations } = table + .infer_ctxt + .at(&cause, table.trait_env.env) + .eq(expected_sigs.liberated_sig.output(), supplied_output_ty)?; all_obligations.extend(obligations); let inputs = supplied_sig diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs index 4620da714743..78889ccb89a2 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs @@ -63,7 +63,7 @@ use crate::{ GenericArgs, PolyFnSig, PredicateKind, Region, RegionKind, SolverDefId, TraitRef, Ty, TyKind, infer::{ - DefineOpaqueTypes, InferCtxt, InferOk, InferResult, + InferCtxt, InferOk, InferResult, relate::RelateResult, select::{ImplSource, SelectionError}, traits::{Obligation, ObligationCause, PredicateObligation, PredicateObligations}, @@ -149,7 +149,7 @@ impl<'a, 'b, 'db> Coerce<'a, 'b, 'db> { let res = if this.use_lub { at.lub(b, a) } else { - at.sup(DefineOpaqueTypes::Yes, b, a) + at.sup(b, a) .map(|InferOk { value: (), obligations }| InferOk { value: b, obligations }) }; @@ -1460,19 +1460,12 @@ impl<'db, 'exprs> CoerceMany<'db, 'exprs> { // // Another example is `break` with no argument expression. assert!(expression_ty.is_unit(), "if let hack without unit type"); - icx.table - .infer_ctxt - .at(cause, icx.table.trait_env.env) - .eq( - // needed for tests/ui/type-alias-impl-trait/issue-65679-inst-opaque-ty-from-val-twice.rs - DefineOpaqueTypes::Yes, - expected, - found, - ) - .map(|infer_ok| { + icx.table.infer_ctxt.at(cause, icx.table.trait_env.env).eq(expected, found).map( + |infer_ok| { icx.table.register_infer_ok(infer_ok); expression_ty - }) + }, + ) }; debug!(?result); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/diagnostics.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/diagnostics.rs index 39e70c262a24..844eb02ab0d4 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/diagnostics.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/diagnostics.rs @@ -15,8 +15,8 @@ use la_arena::{Idx, RawIdx}; use crate::{ InferenceDiagnostic, InferenceTyDiagnosticSource, TyLoweringDiagnostic, db::HirDatabase, - lower_nextsolver::path::{PathDiagnosticCallback, PathLoweringContext}, - lower_nextsolver::{LifetimeElisionKind, TyLoweringContext}, + lower::path::{PathDiagnosticCallback, PathLoweringContext}, + lower::{LifetimeElisionKind, TyLoweringContext}, }; // Unfortunately, this struct needs to use interior mutability (but we encapsulate it) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs index 179eaccc652b..fd4e374d9c89 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs @@ -18,7 +18,7 @@ use hir_expand::name::Name; use intern::sym; use rustc_ast_ir::Mutability; use rustc_type_ir::{ - AliasTyKind, InferTy, Interner, + CoroutineArgs, CoroutineArgsParts, InferTy, Interner, inherent::{AdtDef, GenericArgs as _, IntoKind, SliceLike, Ty as _}, }; use syntax::ast::RangeOp; @@ -29,6 +29,7 @@ use crate::{ IncorrectGenericsLenKind, Rawness, TraitEnvironment, autoderef::overloaded_deref_ty, consteval, + db::InternedCoroutine, generics::generics, infer::{ AllowTwoPhase, BreakableKind, @@ -37,16 +38,16 @@ use crate::{ pat::contains_explicit_ref_binding, }, lang_items::lang_items_for_bin_op, - lower_nextsolver::{ + lower::{ LifetimeElisionKind, lower_mutability, path::{GenericArgsLowerer, TypeLikeConst, substs_from_args_and_bindings}, }, method_resolution::{self, VisibleFromModule}, next_solver::{ - AliasTy, Const, DbInterner, ErrorGuaranteed, GenericArg, GenericArgs, TraitRef, Ty, TyKind, + Const, DbInterner, ErrorGuaranteed, GenericArg, GenericArgs, TraitRef, Ty, TyKind, TypeError, infer::{ - DefineOpaqueTypes, InferOk, + InferOk, traits::{Obligation, ObligationCause}, }, obligation_ctxt::ObligationCtxt, @@ -564,7 +565,7 @@ impl<'db> InferenceContext<'_, 'db> { match def_id { _ if fields.is_empty() => {} Some(def) => { - let field_types = self.db.field_types_ns(def); + let field_types = self.db.field_types(def); let variant_data = def.fields(self.db); let visibilities = self.db.field_visibilities(def); for field in fields.iter() { @@ -1132,18 +1133,26 @@ impl<'db> InferenceContext<'_, 'db> { inner_ty: Ty<'db>, tgt_expr: ExprId, ) -> Ty<'db> { - // Use the first type parameter as the output type of future. - // existential type AsyncBlockImplTrait: Future - let impl_trait_id = crate::ImplTraitId::AsyncBlockTypeImplTrait(self.owner, tgt_expr); - let opaque_ty_id = self.db.intern_impl_trait_id(impl_trait_id).into(); - Ty::new_alias( + let coroutine_id = InternedCoroutine(self.owner, tgt_expr); + let coroutine_id = self.db.intern_coroutine(coroutine_id).into(); + let parent_args = GenericArgs::identity_for_item(self.interner(), self.generic_def.into()); + Ty::new_coroutine( self.interner(), - AliasTyKind::Opaque, - AliasTy::new( + coroutine_id, + CoroutineArgs::new( self.interner(), - opaque_ty_id, - GenericArgs::new_from_iter(self.interner(), [inner_ty.into()]), - ), + CoroutineArgsParts { + parent_args, + kind_ty: self.types.unit, + // rustc uses a special lang item type for the resume ty. I don't believe this can cause us problems. + resume_ty: self.types.unit, + yield_ty: self.types.unit, + return_ty: inner_ty, + // FIXME: Infer upvars. + tupled_upvars_ty: self.types.unit, + }, + ) + .args, ) } @@ -1333,7 +1342,7 @@ impl<'db> InferenceContext<'_, 'db> { self.interner(), box_id.into(), [inner_ty.into()], - |_, _, id, _| self.table.next_var_for_param(id), + |_, id, _| self.table.next_var_for_param(id), ), ) } else { @@ -1622,7 +1631,7 @@ impl<'db> InferenceContext<'_, 'db> { } return None; } - let ty = self.db.field_types_ns(field_id.parent)[field_id.local_id] + let ty = self.db.field_types(field_id.parent)[field_id.local_id] .instantiate(interner, parameters); Some((Either::Left(field_id), ty)) }); @@ -1637,7 +1646,7 @@ impl<'db> InferenceContext<'_, 'db> { None => { let (field_id, subst) = private_field?; let adjustments = autoderef.adjust_steps(); - let ty = self.db.field_types_ns(field_id.parent)[field_id.local_id] + let ty = self.db.field_types(field_id.parent)[field_id.local_id] .instantiate(self.interner(), subst); let ty = self.process_remote_user_written_ty(ty); @@ -2122,7 +2131,7 @@ impl<'db> InferenceContext<'_, 'db> { .table .infer_ctxt .at(&ObligationCause::new(), this.table.trait_env.env) - .eq(DefineOpaqueTypes::Yes, formal_input_ty, coerced_ty); + .eq(formal_input_ty, coerced_ty); // If neither check failed, the types are compatible match formal_ty_error { @@ -2320,7 +2329,7 @@ impl<'db> InferenceContext<'_, 'db> { let callable_ty = self.table.try_structurally_resolve_type(callable_ty); if let TyKind::FnDef(fn_def, parameters) = callable_ty.kind() { let generic_predicates = - self.db.generic_predicates_ns(GenericDefId::from_callable(self.db, fn_def.0)); + self.db.generic_predicates(GenericDefId::from_callable(self.db, fn_def.0)); if let Some(predicates) = generic_predicates.instantiate(self.interner(), parameters) { let interner = self.interner(); let param_env = self.table.trait_env.env; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/mutability.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/mutability.rs index 9edbc9dda0f1..71a9c94bf5e5 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/mutability.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/mutability.rs @@ -18,7 +18,7 @@ use crate::next_solver::{GenericArgs, TraitRef}; use crate::{ Adjust, Adjustment, AutoBorrow, OverloadedDeref, infer::{Expectation, InferenceContext, expr::ExprIsRead}, - lower_nextsolver::lower_mutability, + lower::lower_mutability, next_solver::TyKind, }; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs index 452ae316620f..8019844b5df3 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs @@ -19,7 +19,7 @@ use crate::{ AllowTwoPhase, BindingMode, Expectation, InferenceContext, TypeMismatch, coerce::CoerceNever, expr::ExprIsRead, }, - lower_nextsolver::lower_mutability, + lower::lower_mutability, next_solver::{GenericArgs, Ty, TyKind}, }; @@ -59,7 +59,7 @@ impl<'db> InferenceContext<'_, 'db> { match def { _ if subs.is_empty() => {} Some(def) => { - let field_types = self.db.field_types_ns(def); + let field_types = self.db.field_types(def); let variant_data = def.fields(self.db); let visibilities = self.db.field_visibilities(def); @@ -128,7 +128,7 @@ impl<'db> InferenceContext<'_, 'db> { match def { _ if subs.len() == 0 => {} Some(def) => { - let field_types = self.db.field_types_ns(def); + let field_types = self.db.field_types(def); let variant_data = def.fields(self.db); let visibilities = self.db.field_visibilities(def); @@ -358,7 +358,7 @@ impl<'db> InferenceContext<'_, 'db> { self.interner(), box_adt.into(), std::iter::once(inner_ty.into()).chain(alloc_ty.map(Into::into)), - |_, _, id, _| self.table.next_var_for_param(id), + |_, id, _| self.table.next_var_for_param(id), ), ) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs index f70ed90b953a..2dae7cb04ffa 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs @@ -13,7 +13,7 @@ use crate::{ InferenceDiagnostic, ValueTyDefId, generics::generics, infer::diagnostics::InferenceTyLoweringContext as TyLoweringContext, - lower_nextsolver::LifetimeElisionKind, + lower::LifetimeElisionKind, method_resolution::{self, VisibleFromModule}, next_solver::{ GenericArg, GenericArgs, TraitRef, Ty, @@ -118,7 +118,7 @@ impl<'db> InferenceContext<'_, 'db> { self.interner(), generic_def.into(), self_subst.iter().flat_map(|it| it.iter()).chain(substs.iter().skip(parent_substs_len)), - |_, _, id, _| GenericArg::error_from_id(self.interner(), id), + |_, id, _| GenericArg::error_from_id(self.interner(), id), ); Some(ValuePathResolution::GenericDef(value_def, generic_def, substs)) @@ -221,7 +221,7 @@ impl<'db> InferenceContext<'_, 'db> { def: GenericDefId, subst: GenericArgs<'db>, ) { - let predicates = self.db.generic_predicates_ns(def); + let predicates = self.db.generic_predicates(def); let interner = self.interner(); let param_env = self.table.trait_env.env; if let Some(predicates) = predicates.instantiate(self.interner(), subst) { @@ -352,7 +352,7 @@ impl<'db> InferenceContext<'_, 'db> { self.interner(), trait_.into(), [ty.into()], - |_, _, id, _| self.table.next_var_for_param(id), + |_, id, _| self.table.next_var_for_param(id), ); let trait_ref = TraitRef::new(self.interner(), trait_.into(), args); self.table.register_predicate(Obligation::new( diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs index 8f754f0e1aaa..a18cdda559d0 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs @@ -25,7 +25,7 @@ use crate::{ SolverDefId, SolverDefIds, TraitRef, Ty, TyKind, TypingMode, fulfill::{FulfillmentCtxt, NextSolverError}, infer::{ - DbInternerInferExt, DefineOpaqueTypes, InferCtxt, InferOk, InferResult, + DbInternerInferExt, InferCtxt, InferOk, InferResult, at::ToTrace, snapshot::CombinedSnapshot, traits::{Obligation, ObligationCause, PredicateObligation}, @@ -148,7 +148,7 @@ fn could_unify_impl<'db>( let ((ty1_with_vars, ty2_with_vars), _) = infcx.instantiate_canonical(tys); let mut ctxt = ObligationCtxt::new(&infcx); let can_unify = at - .eq(DefineOpaqueTypes::No, ty1_with_vars, ty2_with_vars) + .eq(ty1_with_vars, ty2_with_vars) .map(|infer_ok| ctxt.register_infer_ok_obligations(infer_ok)) .is_ok(); can_unify && select(&mut ctxt).is_empty() @@ -452,11 +452,7 @@ impl<'db> InferenceTable<'db> { /// Unify two relatable values (e.g. `Ty`) and return new trait goals arising from it, so the /// caller needs to deal with them. pub(crate) fn try_unify>(&mut self, t1: T, t2: T) -> InferResult<'db, ()> { - self.infer_ctxt.at(&ObligationCause::new(), self.trait_env.env).eq( - DefineOpaqueTypes::Yes, - t1, - t2, - ) + self.infer_ctxt.at(&ObligationCause::new(), self.trait_env.env).eq(t1, t2) } pub(crate) fn shallow_resolve(&self, ty: Ty<'db>) -> Ty<'db> { @@ -804,7 +800,7 @@ impl<'db> InferenceTable<'db> { while let Some((AdtId::StructId(id), subst)) = ty.as_adt() { let struct_data = id.fields(self.db); if let Some((last_field, _)) = struct_data.fields().iter().next_back() { - let last_field_ty = self.db.field_types_ns(id.into())[last_field] + let last_field_ty = self.db.field_types(id.into())[last_field] .instantiate(self.interner(), subst); if structs.contains(&ty) { // A struct recursively contains itself as a tail field somewhere. diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/inhabitedness.rs b/src/tools/rust-analyzer/crates/hir-ty/src/inhabitedness.rs index 826f19cf0b68..5e742bba3ebe 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/inhabitedness.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/inhabitedness.rs @@ -1,60 +1,62 @@ //! Type inhabitedness logic. use std::ops::ControlFlow::{self, Break, Continue}; -use chalk_ir::{ - DebruijnIndex, - visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor}, -}; use hir_def::{AdtId, EnumVariantId, ModuleId, VariantId, visibility::Visibility}; use rustc_hash::FxHashSet; +use rustc_type_ir::{ + TypeSuperVisitable, TypeVisitable, TypeVisitor, + inherent::{AdtDef, IntoKind}, +}; use triomphe::Arc; use crate::{ - AliasTy, Binders, Interner, Substitution, TraitEnvironment, Ty, TyKind, + TraitEnvironment, consteval::try_const_usize, db::HirDatabase, - next_solver::{DbInterner, mapping::ChalkToNextSolver}, + next_solver::{ + DbInterner, EarlyBinder, GenericArgs, Ty, TyKind, + infer::{InferCtxt, traits::ObligationCause}, + obligation_ctxt::ObligationCtxt, + }, }; // FIXME: Turn this into a query, it can be quite slow /// Checks whether a type is visibly uninhabited from a particular module. -pub(crate) fn is_ty_uninhabited_from( - db: &dyn HirDatabase, - ty: &Ty, +pub(crate) fn is_ty_uninhabited_from<'db>( + infcx: &InferCtxt<'db>, + ty: Ty<'db>, target_mod: ModuleId, - env: Arc>, + env: Arc>, ) -> bool { let _p = tracing::info_span!("is_ty_uninhabited_from", ?ty).entered(); - let mut uninhabited_from = - UninhabitedFrom { target_mod, db, max_depth: 500, recursive_ty: FxHashSet::default(), env }; - let inhabitedness = ty.visit_with(&mut uninhabited_from, DebruijnIndex::INNERMOST); + let mut uninhabited_from = UninhabitedFrom::new(infcx, target_mod, env); + let inhabitedness = ty.visit_with(&mut uninhabited_from); inhabitedness == BREAK_VISIBLY_UNINHABITED } // FIXME: Turn this into a query, it can be quite slow /// Checks whether a variant is visibly uninhabited from a particular module. -pub(crate) fn is_enum_variant_uninhabited_from( - db: &dyn HirDatabase, +pub(crate) fn is_enum_variant_uninhabited_from<'db>( + infcx: &InferCtxt<'db>, variant: EnumVariantId, - subst: &Substitution, + subst: GenericArgs<'db>, target_mod: ModuleId, - env: Arc>, + env: Arc>, ) -> bool { let _p = tracing::info_span!("is_enum_variant_uninhabited_from").entered(); - let mut uninhabited_from = - UninhabitedFrom { target_mod, db, max_depth: 500, recursive_ty: FxHashSet::default(), env }; + let mut uninhabited_from = UninhabitedFrom::new(infcx, target_mod, env); let inhabitedness = uninhabited_from.visit_variant(variant.into(), subst); inhabitedness == BREAK_VISIBLY_UNINHABITED } -struct UninhabitedFrom<'a> { +struct UninhabitedFrom<'a, 'db> { target_mod: ModuleId, - recursive_ty: FxHashSet, + recursive_ty: FxHashSet>, // guard for preventing stack overflow in non trivial non terminating types max_depth: usize, - db: &'a dyn HirDatabase, - env: Arc>, + infcx: &'a InferCtxt<'db>, + env: Arc>, } const CONTINUE_OPAQUELY_INHABITED: ControlFlow = Continue(()); @@ -62,63 +64,73 @@ const BREAK_VISIBLY_UNINHABITED: ControlFlow = Break(Visibly #[derive(PartialEq, Eq)] struct VisiblyUninhabited; -impl TypeVisitor for UninhabitedFrom<'_> { - type BreakTy = VisiblyUninhabited; +impl<'db> TypeVisitor> for UninhabitedFrom<'_, 'db> { + type Result = ControlFlow; - fn as_dyn(&mut self) -> &mut dyn TypeVisitor { - self - } - - fn visit_ty( - &mut self, - ty: &Ty, - outer_binder: DebruijnIndex, - ) -> ControlFlow { - if self.recursive_ty.contains(ty) || self.max_depth == 0 { + fn visit_ty(&mut self, mut ty: Ty<'db>) -> ControlFlow { + if self.recursive_ty.contains(&ty) || self.max_depth == 0 { // rustc considers recursive types always inhabited. I think it is valid to consider // recursive types as always uninhabited, but we should do what rustc is doing. return CONTINUE_OPAQUELY_INHABITED; } - self.recursive_ty.insert(ty.clone()); + self.recursive_ty.insert(ty); self.max_depth -= 1; - let interner = DbInterner::new_with(self.db, None, None); - let r = match ty.kind(Interner) { - TyKind::Adt(adt, subst) => self.visit_adt(adt.0, subst), + + if matches!(ty.kind(), TyKind::Alias(..)) { + let mut ocx = ObligationCtxt::new(self.infcx); + match ocx.structurally_normalize_ty(&ObligationCause::dummy(), self.env.env, ty) { + Ok(it) => ty = it, + Err(_) => return CONTINUE_OPAQUELY_INHABITED, + } + } + + let r = match ty.kind() { + TyKind::Adt(adt, subst) => self.visit_adt(adt.def_id().0, subst), TyKind::Never => BREAK_VISIBLY_UNINHABITED, - TyKind::Tuple(..) => ty.super_visit_with(self, outer_binder), - TyKind::Array(item_ty, len) => { - match try_const_usize(self.db, len.to_nextsolver(interner)) { - Some(0) | None => CONTINUE_OPAQUELY_INHABITED, - Some(1..) => item_ty.super_visit_with(self, outer_binder), - } - } - TyKind::Alias(AliasTy::Projection(projection)) => { - // FIXME: I think this currently isn't used for monomorphized bodies, so there is no need to handle - // `TyKind::AssociatedType`, but perhaps in the future it will. - let normalized = self.db.normalize_projection(projection.clone(), self.env.clone()); - self.visit_ty(&normalized, outer_binder) - } + TyKind::Tuple(..) => ty.super_visit_with(self), + TyKind::Array(item_ty, len) => match try_const_usize(self.infcx.interner.db, len) { + Some(0) | None => CONTINUE_OPAQUELY_INHABITED, + Some(1..) => item_ty.visit_with(self), + }, _ => CONTINUE_OPAQUELY_INHABITED, }; - self.recursive_ty.remove(ty); + self.recursive_ty.remove(&ty); self.max_depth += 1; r } - - fn interner(&self) -> Interner { - Interner - } } -impl UninhabitedFrom<'_> { - fn visit_adt(&mut self, adt: AdtId, subst: &Substitution) -> ControlFlow { +impl<'a, 'db> UninhabitedFrom<'a, 'db> { + fn new( + infcx: &'a InferCtxt<'db>, + target_mod: ModuleId, + env: Arc>, + ) -> Self { + Self { target_mod, recursive_ty: FxHashSet::default(), max_depth: 500, infcx, env } + } + + #[inline] + fn interner(&self) -> DbInterner<'db> { + self.infcx.interner + } + + #[inline] + fn db(&self) -> &'db dyn HirDatabase { + self.interner().db + } + + fn visit_adt( + &mut self, + adt: AdtId, + subst: GenericArgs<'db>, + ) -> ControlFlow { // An ADT is uninhabited iff all its variants uninhabited. match adt { // rustc: For now, `union`s are never considered uninhabited. AdtId::UnionId(_) => CONTINUE_OPAQUELY_INHABITED, AdtId::StructId(s) => self.visit_variant(s.into(), subst), AdtId::EnumId(e) => { - let enum_data = e.enum_variants(self.db); + let enum_data = e.enum_variants(self.db()); for &(variant, _, _) in enum_data.variants.iter() { let variant_inhabitedness = self.visit_variant(variant.into(), subst); @@ -135,17 +147,17 @@ impl UninhabitedFrom<'_> { fn visit_variant( &mut self, variant: VariantId, - subst: &Substitution, + subst: GenericArgs<'db>, ) -> ControlFlow { - let variant_data = variant.fields(self.db); + let variant_data = variant.fields(self.db()); let fields = variant_data.fields(); if fields.is_empty() { return CONTINUE_OPAQUELY_INHABITED; } let is_enum = matches!(variant, VariantId::EnumVariantId(..)); - let field_tys = self.db.field_types(variant); - let field_vis = if is_enum { None } else { Some(self.db.field_visibilities(variant)) }; + let field_tys = self.db().field_types(variant); + let field_vis = if is_enum { None } else { Some(self.db().field_visibilities(variant)) }; for (fid, _) in fields.iter() { self.visit_field(field_vis.as_ref().map(|it| it[fid]), &field_tys[fid], subst)?; @@ -156,12 +168,12 @@ impl UninhabitedFrom<'_> { fn visit_field( &mut self, vis: Option, - ty: &Binders, - subst: &Substitution, + ty: &EarlyBinder<'db, Ty<'db>>, + subst: GenericArgs<'db>, ) -> ControlFlow { - if vis.is_none_or(|it| it.is_visible_from(self.db, self.target_mod)) { - let ty = ty.clone().substitute(Interner, subst); - ty.visit_with(self, DebruijnIndex::INNERMOST) + if vis.is_none_or(|it| it.is_visible_from(self.db(), self.target_mod)) { + let ty = ty.instantiate(self.interner(), subst); + ty.visit_with(self) } else { CONTINUE_OPAQUELY_INHABITED } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/interner.rs b/src/tools/rust-analyzer/crates/hir-ty/src/interner.rs deleted file mode 100644 index 57ef5523b433..000000000000 --- a/src/tools/rust-analyzer/crates/hir-ty/src/interner.rs +++ /dev/null @@ -1,403 +0,0 @@ -//! Implementation of the Chalk `Interner` trait, which allows customizing the -//! representation of the various objects Chalk deals with (types, goals etc.). - -use crate::{ - AliasTy, CanonicalVarKind, CanonicalVarKinds, ClosureId, Const, ConstData, ConstScalar, FnAbi, - FnDefId, GenericArg, GenericArgData, Goal, GoalData, InEnvironment, Lifetime, LifetimeData, - OpaqueTy, OpaqueTyId, ProgramClause, ProjectionTy, QuantifiedWhereClause, - QuantifiedWhereClauses, Substitution, Ty, TyKind, VariableKind, chalk_db, tls, -}; -use chalk_ir::{ProgramClauseImplication, SeparatorTraitRef, Variance}; -use hir_def::TypeAliasId; -use intern::{Interned, impl_internable}; -use smallvec::SmallVec; -use std::fmt; -use triomphe::Arc; - -type TyData = chalk_ir::TyData; -type VariableKinds = chalk_ir::VariableKinds; -type Goals = chalk_ir::Goals; -type ProgramClauseData = chalk_ir::ProgramClauseData; -type Constraint = chalk_ir::Constraint; -type Constraints = chalk_ir::Constraints; -type ProgramClauses = chalk_ir::ProgramClauses; - -#[derive(Debug, Copy, Clone, Hash, PartialOrd, Ord, PartialEq, Eq)] -pub struct Interner; - -#[derive(PartialEq, Eq, Hash, PartialOrd, Ord, Clone)] -pub struct InternedWrapper(pub(crate) T); - -impl fmt::Debug for InternedWrapper { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Debug::fmt(&self.0, f) - } -} - -#[derive(PartialEq, Eq, Hash, PartialOrd, Ord, Clone)] -pub struct InternedWrapperNoDebug(pub(crate) T); - -impl std::ops::Deref for InternedWrapper { - type Target = T; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl_internable!( - InternedWrapper>, - InternedWrapper>, - InternedWrapper, - InternedWrapper, - InternedWrapper, - InternedWrapper, - InternedWrapper>, - InternedWrapper>, - InternedWrapper>, - InternedWrapper>, -); - -impl chalk_ir::interner::Interner for Interner { - type InternedType = Interned>; - type InternedLifetime = Interned>; - type InternedConst = Interned>; - type InternedConcreteConst = ConstScalar; - type InternedGenericArg = GenericArgData; - // We could do the following, but that saves "only" 20mb on self while increasing inference - // time by ~2.5% - // type InternedGoal = Interned>; - type InternedGoal = Arc; - type InternedGoals = Vec; - type InternedSubstitution = Interned>>; - type InternedProgramClauses = Interned>>; - type InternedProgramClause = ProgramClauseData; - type InternedQuantifiedWhereClauses = Interned>>; - type InternedVariableKinds = Interned>>; - type InternedCanonicalVarKinds = Interned>>; - type InternedConstraints = Vec>; - type InternedVariances = SmallVec<[Variance; 16]>; - type DefId = salsa::Id; - type InternedAdtId = hir_def::AdtId; - type Identifier = TypeAliasId; - type FnAbi = FnAbi; - - fn debug_adt_id( - type_kind_id: chalk_db::AdtId, - fmt: &mut fmt::Formatter<'_>, - ) -> Option { - tls::with_current_program(|prog| Some(prog?.debug_struct_id(type_kind_id, fmt))) - } - - fn debug_trait_id( - type_kind_id: chalk_db::TraitId, - fmt: &mut fmt::Formatter<'_>, - ) -> Option { - tls::with_current_program(|prog| Some(prog?.debug_trait_id(type_kind_id, fmt))) - } - - fn debug_assoc_type_id( - id: chalk_db::AssocTypeId, - fmt: &mut fmt::Formatter<'_>, - ) -> Option { - tls::with_current_program(|prog| Some(prog?.debug_assoc_type_id(id, fmt))) - } - - fn debug_opaque_ty_id( - opaque_ty_id: OpaqueTyId, - fmt: &mut fmt::Formatter<'_>, - ) -> Option { - Some(write!(fmt, "OpaqueTy#{:?}", opaque_ty_id.0)) - } - - fn debug_fn_def_id(fn_def_id: FnDefId, fmt: &mut fmt::Formatter<'_>) -> Option { - tls::with_current_program(|prog| Some(prog?.debug_fn_def_id(fn_def_id, fmt))) - } - - fn debug_closure_id( - _fn_def_id: ClosureId, - _fmt: &mut fmt::Formatter<'_>, - ) -> Option { - None - } - - fn debug_alias(alias: &AliasTy, fmt: &mut fmt::Formatter<'_>) -> Option { - use std::fmt::Debug; - match alias { - AliasTy::Projection(projection_ty) => Interner::debug_projection_ty(projection_ty, fmt), - AliasTy::Opaque(opaque_ty) => Some(opaque_ty.fmt(fmt)), - } - } - - fn debug_projection_ty( - proj: &ProjectionTy, - fmt: &mut fmt::Formatter<'_>, - ) -> Option { - tls::with_current_program(|prog| Some(prog?.debug_projection_ty(proj, fmt))) - .or_else(|| Some(fmt.write_str("ProjectionTy"))) - } - - fn debug_opaque_ty(opaque_ty: &OpaqueTy, fmt: &mut fmt::Formatter<'_>) -> Option { - Some(write!(fmt, "{:?}", opaque_ty.opaque_ty_id)) - } - - fn debug_ty(ty: &Ty, fmt: &mut fmt::Formatter<'_>) -> Option { - Some(write!(fmt, "{:?}", ty.data(Interner))) - } - - fn debug_lifetime(lifetime: &Lifetime, fmt: &mut fmt::Formatter<'_>) -> Option { - Some(write!(fmt, "{:?}", lifetime.data(Interner))) - } - - fn debug_const(constant: &Const, fmt: &mut fmt::Formatter<'_>) -> Option { - Some(write!(fmt, "{:?}", constant.data(Interner))) - } - - fn debug_generic_arg( - parameter: &GenericArg, - fmt: &mut fmt::Formatter<'_>, - ) -> Option { - Some(write!(fmt, "{:?}", parameter.data(Interner).inner_debug())) - } - - fn debug_variable_kinds( - variable_kinds: &VariableKinds, - fmt: &mut fmt::Formatter<'_>, - ) -> Option { - Some(write!(fmt, "{:?}", variable_kinds.as_slice(Interner))) - } - - fn debug_variable_kinds_with_angles( - variable_kinds: &VariableKinds, - fmt: &mut fmt::Formatter<'_>, - ) -> Option { - Some(write!(fmt, "{:?}", variable_kinds.inner_debug(Interner))) - } - - fn debug_canonical_var_kinds( - canonical_var_kinds: &CanonicalVarKinds, - fmt: &mut fmt::Formatter<'_>, - ) -> Option { - Some(write!(fmt, "{:?}", canonical_var_kinds.as_slice(Interner))) - } - fn debug_goal(goal: &Goal, fmt: &mut fmt::Formatter<'_>) -> Option { - let goal_data = goal.data(Interner); - Some(write!(fmt, "{goal_data:?}")) - } - fn debug_goals(goals: &Goals, fmt: &mut fmt::Formatter<'_>) -> Option { - Some(write!(fmt, "{:?}", goals.debug(Interner))) - } - fn debug_program_clause_implication( - pci: &ProgramClauseImplication, - fmt: &mut fmt::Formatter<'_>, - ) -> Option { - Some(write!(fmt, "{:?}", pci.debug(Interner))) - } - fn debug_program_clause( - clause: &ProgramClause, - fmt: &mut fmt::Formatter<'_>, - ) -> Option { - Some(write!(fmt, "{:?}", clause.data(Interner))) - } - fn debug_program_clauses( - clauses: &ProgramClauses, - fmt: &mut fmt::Formatter<'_>, - ) -> Option { - Some(write!(fmt, "{:?}", clauses.as_slice(Interner))) - } - fn debug_substitution( - substitution: &Substitution, - fmt: &mut fmt::Formatter<'_>, - ) -> Option { - Some(write!(fmt, "{:?}", substitution.debug(Interner))) - } - fn debug_separator_trait_ref( - separator_trait_ref: &SeparatorTraitRef<'_, Interner>, - fmt: &mut fmt::Formatter<'_>, - ) -> Option { - Some(write!(fmt, "{:?}", separator_trait_ref.debug(Interner))) - } - - fn debug_quantified_where_clauses( - clauses: &QuantifiedWhereClauses, - fmt: &mut fmt::Formatter<'_>, - ) -> Option { - Some(write!(fmt, "{:?}", clauses.as_slice(Interner))) - } - - fn debug_constraints( - _clauses: &Constraints, - _fmt: &mut fmt::Formatter<'_>, - ) -> Option { - None - } - - fn intern_ty(self, kind: TyKind) -> Self::InternedType { - let flags = kind.compute_flags(self); - Interned::new(InternedWrapper(TyData { kind, flags })) - } - - fn ty_data(self, ty: &Self::InternedType) -> &TyData { - &ty.0 - } - - fn intern_lifetime(self, lifetime: LifetimeData) -> Self::InternedLifetime { - Interned::new(InternedWrapper(lifetime)) - } - - fn lifetime_data(self, lifetime: &Self::InternedLifetime) -> &LifetimeData { - &lifetime.0 - } - - fn intern_const(self, constant: ConstData) -> Self::InternedConst { - Interned::new(InternedWrapper(constant)) - } - - fn const_data(self, constant: &Self::InternedConst) -> &ConstData { - &constant.0 - } - - fn const_eq( - self, - _ty: &Self::InternedType, - c1: &Self::InternedConcreteConst, - c2: &Self::InternedConcreteConst, - ) -> bool { - !matches!(c1, ConstScalar::Bytes(..)) || !matches!(c2, ConstScalar::Bytes(..)) || (c1 == c2) - } - - fn intern_generic_arg(self, parameter: GenericArgData) -> Self::InternedGenericArg { - parameter - } - - fn generic_arg_data(self, parameter: &Self::InternedGenericArg) -> &GenericArgData { - parameter - } - - fn intern_goal(self, goal: GoalData) -> Self::InternedGoal { - Arc::new(goal) - } - - fn goal_data(self, goal: &Self::InternedGoal) -> &GoalData { - goal - } - - fn intern_goals( - self, - data: impl IntoIterator>, - ) -> Result { - // let hash = - // std::hash::BuildHasher::hash_one(&BuildHasherDefault::::default(), &goal); - // Interned::new(InternedWrapper(PreHashedWrapper(goal, hash))) - data.into_iter().collect() - } - - fn goals_data(self, goals: &Self::InternedGoals) -> &[Goal] { - goals - } - - fn intern_substitution( - self, - data: impl IntoIterator>, - ) -> Result { - Ok(Interned::new(InternedWrapper(data.into_iter().collect::>()?))) - } - - fn substitution_data(self, substitution: &Self::InternedSubstitution) -> &[GenericArg] { - &substitution.as_ref().0 - } - - fn intern_program_clause(self, data: ProgramClauseData) -> Self::InternedProgramClause { - data - } - - fn program_clause_data(self, clause: &Self::InternedProgramClause) -> &ProgramClauseData { - clause - } - - fn intern_program_clauses( - self, - data: impl IntoIterator>, - ) -> Result { - Ok(Interned::new(InternedWrapper(data.into_iter().collect::>()?))) - } - - fn program_clauses_data(self, clauses: &Self::InternedProgramClauses) -> &[ProgramClause] { - clauses - } - - fn intern_quantified_where_clauses( - self, - data: impl IntoIterator>, - ) -> Result { - Ok(Interned::new(InternedWrapper(data.into_iter().collect::>()?))) - } - - fn quantified_where_clauses_data( - self, - clauses: &Self::InternedQuantifiedWhereClauses, - ) -> &[QuantifiedWhereClause] { - clauses - } - - fn intern_generic_arg_kinds( - self, - data: impl IntoIterator>, - ) -> Result { - Ok(Interned::new(InternedWrapper(data.into_iter().collect::>()?))) - } - - fn variable_kinds_data(self, parameter_kinds: &Self::InternedVariableKinds) -> &[VariableKind] { - ¶meter_kinds.as_ref().0 - } - - fn intern_canonical_var_kinds( - self, - data: impl IntoIterator>, - ) -> Result { - Ok(Interned::new(InternedWrapper(data.into_iter().collect::>()?))) - } - - fn canonical_var_kinds_data( - self, - canonical_var_kinds: &Self::InternedCanonicalVarKinds, - ) -> &[CanonicalVarKind] { - canonical_var_kinds - } - fn intern_constraints( - self, - data: impl IntoIterator, E>>, - ) -> Result { - data.into_iter().collect() - } - fn constraints_data( - self, - constraints: &Self::InternedConstraints, - ) -> &[InEnvironment] { - constraints - } - - fn intern_variances( - self, - data: impl IntoIterator>, - ) -> Result { - data.into_iter().collect::>() - } - - fn variances_data(self, variances: &Self::InternedVariances) -> &[Variance] { - variances - } -} - -impl chalk_ir::interner::HasInterner for Interner { - type Interner = Self; -} - -#[macro_export] -macro_rules! has_interner { - ($t:ty) => { - impl HasInterner for $t { - type Interner = $crate::Interner; - } - }; -} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs index a857602fa08a..fc0b9d30b333 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs @@ -138,7 +138,7 @@ fn layout_of_simd_ty<'db>( // * #[repr(simd)] struct S([T; 4]) // // where T is a primitive scalar (integer/float/pointer). - let fields = db.field_types_ns(id.into()); + let fields = db.field_types(id.into()); let mut fields = fields.iter(); let Some(TyKind::Array(e_ty, e_len)) = fields .next() @@ -401,7 +401,7 @@ fn field_ty<'a>( fd: LocalFieldId, args: &GenericArgs<'a>, ) -> Ty<'a> { - db.field_types_ns(def)[fd].instantiate(DbInterner::new_with(db, None, None), args) + db.field_types(def)[fd].instantiate(DbInterner::new_with(db, None, None), args) } fn scalar_unit(dl: &TargetDataLayout, value: Primitive) -> Scalar { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs index 734483a823e4..25579e04ed01 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs @@ -23,23 +23,16 @@ extern crate ra_ap_rustc_next_trait_solver as rustc_next_trait_solver; extern crate self as hir_ty; -mod builder; -mod chalk_db; -mod chalk_ext; mod infer; mod inhabitedness; -mod interner; mod lower; -mod lower_nextsolver; -mod mapping; pub mod next_solver; +mod specialization; mod target_feature; -mod tls; mod utils; pub mod autoderef; pub mod consteval; -mod consteval_chalk; pub mod db; pub mod diagnostics; pub mod display; @@ -61,42 +54,32 @@ mod variance; use std::hash::Hash; -use chalk_ir::{ - VariableKinds, - fold::{Shift, TypeFoldable}, - interner::HasInterner, -}; -use hir_def::{CallableDefId, GeneralConstId, TypeOrConstParamId, hir::ExprId, type_ref::Rawness}; +use hir_def::{CallableDefId, TypeOrConstParamId, type_ref::Rawness}; use hir_expand::name::Name; use indexmap::{IndexMap, map::Entry}; use intern::{Symbol, sym}; -use la_arena::{Arena, Idx}; use mir::{MirEvalError, VTableMap}; use rustc_hash::{FxBuildHasher, FxHashMap, FxHashSet}; use rustc_type_ir::{ - TypeSuperVisitable, TypeVisitableExt, UpcastFrom, + BoundVarIndexKind, TypeSuperVisitable, TypeVisitableExt, UpcastFrom, inherent::{IntoKind, SliceLike, Ty as _}, }; use syntax::ast::{ConstArg, make}; use traits::FnTrait; use triomphe::Arc; -#[cfg(not(debug_assertions))] -use crate::next_solver::ErrorGuaranteed; use crate::{ db::HirDatabase, display::{DisplayTarget, HirDisplay}, - generics::Generics, infer::unify::InferenceTable, next_solver::{ - DbInterner, - mapping::{ChalkToNextSolver, NextSolverToChalk, convert_ty_for_result}, + AliasTy, Binder, BoundConst, BoundRegion, BoundRegionKind, BoundTy, BoundTyKind, Canonical, + CanonicalVarKind, CanonicalVars, Const, ConstKind, DbInterner, FnSig, PolyFnSig, Predicate, + Region, RegionKind, TraitRef, Ty, TyKind, Tys, abi, }, }; pub use autoderef::autoderef; -pub use builder::{ParamKind, TyBuilder}; -pub use chalk_ext::*; pub use infer::{ Adjust, Adjustment, AutoBorrow, BindingMode, InferenceDiagnostic, InferenceResult, InferenceTyDiagnosticSource, OverloadedDeref, PointerCast, @@ -104,15 +87,9 @@ pub use infer::{ closure::analysis::{CaptureKind, CapturedItem}, could_coerce, could_unify, could_unify_deeply, }; -pub use interner::Interner; -pub use lower::{ImplTraitLoweringMode, ParamLoweringMode, TyDefId, ValueTyDefId, diagnostics::*}; -pub use lower_nextsolver::{ - LifetimeElisionKind, TyLoweringContext, associated_type_shorthand_candidates, -}; -pub use mapping::{ - ToChalk, from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id, from_placeholder_idx, - lt_from_placeholder_idx, lt_to_placeholder_idx, to_assoc_type_id, to_chalk_trait_id, - to_foreign_def_id, to_placeholder_idx, to_placeholder_idx_no_index, +pub use lower::{ + LifetimeElisionKind, TyDefId, TyLoweringContext, ValueTyDefId, + associated_type_shorthand_candidates, diagnostics::*, }; pub use method_resolution::check_orphan_rules; pub use next_solver::interner::{attach_db, attach_db_allow_change, with_attached_db}; @@ -122,79 +99,6 @@ pub use utils::{ TargetFeatureIsSafeInTarget, Unsafety, all_super_traits, direct_super_traits, is_fn_unsafe_to_call, target_feature_is_safe_in_target, }; -pub use variance::Variance; - -use chalk_ir::{AdtId, BoundVar, DebruijnIndex, Safety, Scalar}; - -pub(crate) type ForeignDefId = chalk_ir::ForeignDefId; -pub(crate) type AssocTypeId = chalk_ir::AssocTypeId; -pub(crate) type FnDefId = chalk_ir::FnDefId; -pub(crate) type ClosureId = chalk_ir::ClosureId; -pub(crate) type OpaqueTyId = chalk_ir::OpaqueTyId; -pub(crate) type PlaceholderIndex = chalk_ir::PlaceholderIndex; - -pub(crate) type CanonicalVarKinds = chalk_ir::CanonicalVarKinds; - -pub(crate) type VariableKind = chalk_ir::VariableKind; -/// Represents generic parameters and an item bound by them. When the item has parent, the binders -/// also contain the generic parameters for its parent. See chalk's documentation for details. -/// -/// One thing to keep in mind when working with `Binders` (and `Substitution`s, which represent -/// generic arguments) in rust-analyzer is that the ordering within *is* significant - the generic -/// parameters/arguments for an item MUST come before those for its parent. This is to facilitate -/// the integration with chalk-solve, which mildly puts constraints as such. See #13335 for its -/// motivation in detail. -pub(crate) type Binders = chalk_ir::Binders; -/// Interned list of generic arguments for an item. When an item has parent, the `Substitution` for -/// it contains generic arguments for both its parent and itself. See chalk's documentation for -/// details. -/// -/// See `Binders` for the constraint on the ordering. -pub(crate) type Substitution = chalk_ir::Substitution; -pub(crate) type GenericArg = chalk_ir::GenericArg; -pub(crate) type GenericArgData = chalk_ir::GenericArgData; - -pub(crate) type Ty = chalk_ir::Ty; -pub type TyKind = chalk_ir::TyKind; -pub(crate) type TypeFlags = chalk_ir::TypeFlags; -pub(crate) type DynTy = chalk_ir::DynTy; -pub(crate) type FnPointer = chalk_ir::FnPointer; -pub(crate) use chalk_ir::FnSubst; // a re-export so we don't lose the tuple constructor - -pub type AliasTy = chalk_ir::AliasTy; - -pub(crate) type ProjectionTy = chalk_ir::ProjectionTy; -pub(crate) type OpaqueTy = chalk_ir::OpaqueTy; - -pub(crate) type Lifetime = chalk_ir::Lifetime; -pub(crate) type LifetimeData = chalk_ir::LifetimeData; -pub(crate) type LifetimeOutlives = chalk_ir::LifetimeOutlives; - -pub(crate) type ConstValue = chalk_ir::ConstValue; - -pub(crate) type Const = chalk_ir::Const; -pub(crate) type ConstData = chalk_ir::ConstData; -pub(crate) type ConcreteConst = chalk_ir::ConcreteConst; - -pub(crate) type TraitRef = chalk_ir::TraitRef; -pub(crate) type QuantifiedWhereClause = Binders; -pub(crate) type Canonical = chalk_ir::Canonical; - -pub(crate) type ChalkTraitId = chalk_ir::TraitId; -pub(crate) type QuantifiedWhereClauses = chalk_ir::QuantifiedWhereClauses; - -pub(crate) type FnSig = chalk_ir::FnSig; - -pub(crate) type InEnvironment = chalk_ir::InEnvironment; -pub type AliasEq = chalk_ir::AliasEq; -pub type WhereClause = chalk_ir::WhereClause; - -pub(crate) type DomainGoal = chalk_ir::DomainGoal; -pub(crate) type Goal = chalk_ir::Goal; - -pub(crate) type CanonicalVarKind = chalk_ir::CanonicalVarKind; -pub(crate) type GoalData = chalk_ir::GoalData; -pub(crate) type ProgramClause = chalk_ir::ProgramClause; /// A constant can have reference to other things. Memory map job is holding /// the necessary bits of memory of the const eval session to keep the constant @@ -229,7 +133,7 @@ impl ComplexMemoryMap<'_> { } impl<'db> MemoryMap<'db> { - pub fn vtable_ty(&self, id: usize) -> Result, MirEvalError<'db>> { + pub fn vtable_ty(&self, id: usize) -> Result, MirEvalError<'db>> { match self { MemoryMap::Empty | MemoryMap::Simple(_) => Err(MirEvalError::InvalidVTableId(id)), MemoryMap::Complex(cm) => cm.vtable.ty(id), @@ -279,118 +183,11 @@ impl<'db> MemoryMap<'db> { } } -// FIXME(next-solver): add a lifetime to this -/// A concrete constant value -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum ConstScalar { - Bytes(Box<[u8]>, MemoryMap<'static>), - // FIXME: this is a hack to get around chalk not being able to represent unevaluatable - // constants - UnevaluatedConst(GeneralConstId, Substitution), - /// Case of an unknown value that rustc might know but we don't - // FIXME: this is a hack to get around chalk not being able to represent unevaluatable - // constants - // https://github.com/rust-lang/rust-analyzer/pull/8813#issuecomment-840679177 - // https://rust-lang.zulipchat.com/#narrow/stream/144729-wg-traits/topic/Handling.20non.20evaluatable.20constants'.20equality/near/238386348 - Unknown, -} - -impl Hash for ConstScalar { - fn hash(&self, state: &mut H) { - core::mem::discriminant(self).hash(state); - if let ConstScalar::Bytes(b, _) = self { - b.hash(state) - } - } -} - -/// A concrete constant value -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum ConstScalarNs<'db> { - Bytes(Box<[u8]>, MemoryMap<'db>), - // FIXME: this is a hack to get around chalk not being able to represent unevaluatable - // constants - UnevaluatedConst(GeneralConstId, Substitution), - /// Case of an unknown value that rustc might know but we don't - // FIXME: this is a hack to get around chalk not being able to represent unevaluatable - // constants - // https://github.com/rust-lang/rust-analyzer/pull/8813#issuecomment-840679177 - // https://rust-lang.zulipchat.com/#narrow/stream/144729-wg-traits/topic/Handling.20non.20evaluatable.20constants'.20equality/near/238386348 - Unknown, -} - -impl Hash for ConstScalarNs<'_> { - fn hash(&self, state: &mut H) { - core::mem::discriminant(self).hash(state); - if let ConstScalarNs::Bytes(b, _) = self { - b.hash(state) - } - } -} - /// Return an index of a parameter in the generic type parameter list by it's id. pub fn param_idx(db: &dyn HirDatabase, id: TypeOrConstParamId) -> Option { generics::generics(db, id.parent).type_or_const_param_idx(id) } -pub(crate) fn wrap_empty_binders(value: T) -> Binders -where - T: TypeFoldable + HasInterner, -{ - Binders::empty(Interner, value.shifted_in_from(Interner, DebruijnIndex::ONE)) -} - -pub(crate) fn make_single_type_binders>( - value: T, -) -> Binders { - Binders::new( - chalk_ir::VariableKinds::from_iter( - Interner, - std::iter::once(chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General)), - ), - value, - ) -} - -pub(crate) fn make_binders>( - db: &dyn HirDatabase, - generics: &Generics, - value: T, -) -> Binders { - Binders::new(variable_kinds_from_iter(db, generics.iter_id()), value) -} - -pub(crate) fn variable_kinds_from_iter( - db: &dyn HirDatabase, - iter: impl Iterator, -) -> VariableKinds { - VariableKinds::from_iter( - Interner, - iter.map(|x| match x { - hir_def::GenericParamId::ConstParamId(id) => { - chalk_ir::VariableKind::Const(db.const_param_ty(id)) - } - hir_def::GenericParamId::TypeParamId(_) => { - chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General) - } - hir_def::GenericParamId::LifetimeParamId(_) => chalk_ir::VariableKind::Lifetime, - }), - ) -} - -// FIXME: get rid of this, just replace it by FnPointer -/// A function signature as seen by type inference: Several parameter types and -/// one return type. -#[derive(Clone, PartialEq, Eq, Debug)] -pub struct CallableSig { - params_and_return: Arc<[Ty]>, - is_varargs: bool, - safety: Safety, - abi: FnAbi, -} - -has_interner!(CallableSig); - #[derive(Debug, Copy, Clone, Eq)] pub enum FnAbi { Aapcs, @@ -534,195 +331,23 @@ impl FnAbi { } } -/// A polymorphic function signature. -pub type PolyFnSig = Binders; - -impl CallableSig { - pub fn from_params_and_return( - params: impl Iterator, - ret: Ty, - is_varargs: bool, - safety: Safety, - abi: FnAbi, - ) -> CallableSig { - let mut params_and_return = Vec::with_capacity(params.size_hint().0 + 1); - params_and_return.extend(params); - params_and_return.push(ret); - CallableSig { params_and_return: params_and_return.into(), is_varargs, safety, abi } - } - - pub fn from_def(db: &dyn HirDatabase, def: FnDefId, substs: &Substitution) -> CallableSig { - let callable_def = ToChalk::from_chalk(db, def); - let interner = DbInterner::new_with(db, None, None); - let args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner); - let sig = db.callable_item_signature(callable_def); - sig.instantiate(interner, args).skip_binder().to_chalk(interner) - } - pub fn from_fn_ptr(fn_ptr: &FnPointer) -> CallableSig { - CallableSig { - // FIXME: what to do about lifetime params? -> return PolyFnSig - params_and_return: Arc::from_iter( - fn_ptr - .substitution - .clone() - .shifted_out_to(Interner, DebruijnIndex::ONE) - .expect("unexpected lifetime vars in fn ptr") - .0 - .as_slice(Interner) - .iter() - .map(|arg| arg.assert_ty_ref(Interner).clone()), - ), - is_varargs: fn_ptr.sig.variadic, - safety: fn_ptr.sig.safety, - abi: fn_ptr.sig.abi, - } - } - pub fn from_fn_sig_and_header<'db>( - interner: DbInterner<'db>, - sig: crate::next_solver::Binder<'db, rustc_type_ir::FnSigTys>>, - header: rustc_type_ir::FnHeader>, - ) -> CallableSig { - CallableSig { - // FIXME: what to do about lifetime params? -> return PolyFnSig - params_and_return: Arc::from_iter( - sig.skip_binder() - .inputs_and_output - .iter() - .map(|t| convert_ty_for_result(interner, t)), - ), - is_varargs: header.c_variadic, - safety: match header.safety { - next_solver::abi::Safety::Safe => chalk_ir::Safety::Safe, - next_solver::abi::Safety::Unsafe => chalk_ir::Safety::Unsafe, - }, - abi: header.abi, - } - } - - pub fn to_fn_ptr(&self) -> FnPointer { - FnPointer { - num_binders: 0, - sig: FnSig { abi: self.abi, safety: self.safety, variadic: self.is_varargs }, - substitution: FnSubst(Substitution::from_iter( - Interner, - self.params_and_return.iter().cloned(), - )), - } - } - - pub fn abi(&self) -> FnAbi { - self.abi - } - - pub fn params(&self) -> &[Ty] { - &self.params_and_return[0..self.params_and_return.len() - 1] - } - - pub fn ret(&self) -> &Ty { - &self.params_and_return[self.params_and_return.len() - 1] - } -} - -impl TypeFoldable for CallableSig { - fn try_fold_with( - self, - folder: &mut dyn chalk_ir::fold::FallibleTypeFolder, - outer_binder: DebruijnIndex, - ) -> Result { - let vec = self.params_and_return.to_vec(); - let folded = vec.try_fold_with(folder, outer_binder)?; - Ok(CallableSig { - params_and_return: folded.into(), - is_varargs: self.is_varargs, - safety: self.safety, - abi: self.abi, - }) - } -} - #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] -pub enum ImplTraitId { - ReturnTypeImplTrait(hir_def::FunctionId, ImplTraitIdx), // FIXME(next-solver): Should be crate::nextsolver::ImplTraitIdx. - TypeAliasImplTrait(hir_def::TypeAliasId, ImplTraitIdx), - AsyncBlockTypeImplTrait(hir_def::DefWithBodyId, ExprId), -} - -#[derive(PartialEq, Eq, Debug, Hash)] -pub struct ImplTraits { - pub(crate) impl_traits: Arena, -} - -has_interner!(ImplTraits); - -#[derive(PartialEq, Eq, Debug, Hash)] -pub struct ImplTrait { - pub(crate) bounds: Binders>, -} - -pub type ImplTraitIdx = Idx; - -pub fn static_lifetime() -> Lifetime { - LifetimeData::Static.intern(Interner) -} - -pub fn error_lifetime() -> Lifetime { - LifetimeData::Error.intern(Interner) -} - -pub(crate) fn fold_free_vars + TypeFoldable>( - t: T, - for_ty: impl FnMut(BoundVar, DebruijnIndex) -> Ty, - for_const: impl FnMut(Ty, BoundVar, DebruijnIndex) -> Const, -) -> T { - use chalk_ir::fold::TypeFolder; - - #[derive(chalk_derive::FallibleTypeFolder)] - #[has_interner(Interner)] - struct FreeVarFolder< - F1: FnMut(BoundVar, DebruijnIndex) -> Ty, - F2: FnMut(Ty, BoundVar, DebruijnIndex) -> Const, - >(F1, F2); - impl Ty, F2: FnMut(Ty, BoundVar, DebruijnIndex) -> Const> - TypeFolder for FreeVarFolder - { - fn as_dyn(&mut self) -> &mut dyn TypeFolder { - self - } - - fn interner(&self) -> Interner { - Interner - } - - fn fold_free_var_ty(&mut self, bound_var: BoundVar, outer_binder: DebruijnIndex) -> Ty { - self.0(bound_var, outer_binder) - } - - fn fold_free_var_const( - &mut self, - ty: Ty, - bound_var: BoundVar, - outer_binder: DebruijnIndex, - ) -> Const { - self.1(ty, bound_var, outer_binder) - } - } - t.fold_with(&mut FreeVarFolder(for_ty, for_const), DebruijnIndex::INNERMOST) +pub enum ImplTraitId<'db> { + ReturnTypeImplTrait(hir_def::FunctionId, next_solver::ImplTraitIdx<'db>), + TypeAliasImplTrait(hir_def::TypeAliasId, next_solver::ImplTraitIdx<'db>), } /// 'Canonicalizes' the `t` by replacing any errors with new variables. Also /// ensures there are no unbound variables or inference variables anywhere in /// the `t`. -pub fn replace_errors_with_variables<'db, T>( - interner: DbInterner<'db>, - t: &T, -) -> crate::next_solver::Canonical<'db, T> +pub fn replace_errors_with_variables<'db, T>(interner: DbInterner<'db>, t: &T) -> Canonical<'db, T> where T: rustc_type_ir::TypeFoldable> + Clone, { use rustc_type_ir::{FallibleTypeFolder, TypeSuperFoldable}; struct ErrorReplacer<'db> { interner: DbInterner<'db>, - vars: Vec>, + vars: Vec>, binder: rustc_type_ir::DebruijnIndex, } impl<'db> FallibleTypeFolder> for ErrorReplacer<'db> { @@ -735,10 +360,7 @@ where self.interner } - fn try_fold_binder( - &mut self, - t: crate::next_solver::Binder<'db, T>, - ) -> Result, Self::Error> + fn try_fold_binder(&mut self, t: Binder<'db, T>) -> Result, Self::Error> where T: rustc_type_ir::TypeFoldable>, { @@ -748,10 +370,7 @@ where result } - fn try_fold_ty( - &mut self, - t: crate::next_solver::Ty<'db>, - ) -> Result, Self::Error> { + fn try_fold_ty(&mut self, t: Ty<'db>) -> Result, Self::Error> { if !t.has_type_flags( rustc_type_ir::TypeFlags::HAS_ERROR | rustc_type_ir::TypeFlags::HAS_TY_INFER @@ -764,34 +383,28 @@ where #[cfg(debug_assertions)] let error = || Err(()); #[cfg(not(debug_assertions))] - let error = || Ok(crate::next_solver::Ty::new_error(self.interner, ErrorGuaranteed)); + let error = || Ok(Ty::new_error(self.interner, crate::next_solver::ErrorGuaranteed)); match t.kind() { - crate::next_solver::TyKind::Error(_) => { + TyKind::Error(_) => { let var = rustc_type_ir::BoundVar::from_usize(self.vars.len()); - self.vars.push(crate::next_solver::CanonicalVarKind::Ty { + self.vars.push(CanonicalVarKind::Ty { ui: rustc_type_ir::UniverseIndex::ZERO, sub_root: var, }); - Ok(crate::next_solver::Ty::new_bound( + Ok(Ty::new_bound( self.interner, self.binder, - crate::next_solver::BoundTy { - var, - kind: crate::next_solver::BoundTyKind::Anon, - }, + BoundTy { var, kind: BoundTyKind::Anon }, )) } - crate::next_solver::TyKind::Infer(_) => error(), - crate::next_solver::TyKind::Bound(index, _) if index > self.binder => error(), + TyKind::Infer(_) => error(), + TyKind::Bound(BoundVarIndexKind::Bound(index), _) if index > self.binder => error(), _ => t.try_super_fold_with(self), } } - fn try_fold_const( - &mut self, - ct: crate::next_solver::Const<'db>, - ) -> Result, Self::Error> { + fn try_fold_const(&mut self, ct: Const<'db>) -> Result, Self::Error> { if !ct.has_type_flags( rustc_type_ir::TypeFlags::HAS_ERROR | rustc_type_ir::TypeFlags::HAS_TY_INFER @@ -804,52 +417,42 @@ where #[cfg(debug_assertions)] let error = || Err(()); #[cfg(not(debug_assertions))] - let error = || Ok(crate::next_solver::Const::error(self.interner)); + let error = || Ok(Const::error(self.interner)); match ct.kind() { - crate::next_solver::ConstKind::Error(_) => { + ConstKind::Error(_) => { let var = rustc_type_ir::BoundVar::from_usize(self.vars.len()); - self.vars.push(crate::next_solver::CanonicalVarKind::Const( - rustc_type_ir::UniverseIndex::ZERO, - )); - Ok(crate::next_solver::Const::new_bound( - self.interner, - self.binder, - crate::next_solver::BoundConst { var }, - )) + self.vars.push(CanonicalVarKind::Const(rustc_type_ir::UniverseIndex::ZERO)); + Ok(Const::new_bound(self.interner, self.binder, BoundConst { var })) + } + ConstKind::Infer(_) => error(), + ConstKind::Bound(BoundVarIndexKind::Bound(index), _) if index > self.binder => { + error() } - crate::next_solver::ConstKind::Infer(_) => error(), - crate::next_solver::ConstKind::Bound(index, _) if index > self.binder => error(), _ => ct.try_super_fold_with(self), } } - fn try_fold_region( - &mut self, - region: crate::next_solver::Region<'db>, - ) -> Result, Self::Error> { + fn try_fold_region(&mut self, region: Region<'db>) -> Result, Self::Error> { #[cfg(debug_assertions)] let error = || Err(()); #[cfg(not(debug_assertions))] - let error = || Ok(crate::next_solver::Region::error(self.interner)); + let error = || Ok(Region::error(self.interner)); match region.kind() { - crate::next_solver::RegionKind::ReError(_) => { + RegionKind::ReError(_) => { let var = rustc_type_ir::BoundVar::from_usize(self.vars.len()); - self.vars.push(crate::next_solver::CanonicalVarKind::Region( - rustc_type_ir::UniverseIndex::ZERO, - )); - Ok(crate::next_solver::Region::new_bound( + self.vars.push(CanonicalVarKind::Region(rustc_type_ir::UniverseIndex::ZERO)); + Ok(Region::new_bound( self.interner, self.binder, - crate::next_solver::BoundRegion { - var, - kind: crate::next_solver::BoundRegionKind::Anon, - }, + BoundRegion { var, kind: BoundRegionKind::Anon }, )) } - crate::next_solver::RegionKind::ReVar(_) => error(), - crate::next_solver::RegionKind::ReBound(index, _) if index > self.binder => error(), + RegionKind::ReVar(_) => error(), + RegionKind::ReBound(BoundVarIndexKind::Bound(index), _) if index > self.binder => { + error() + } _ => Ok(region), } } @@ -861,18 +464,18 @@ where Ok(t) => t, Err(_) => panic!("Encountered unbound or inference vars in {t:?}"), }; - crate::next_solver::Canonical { + Canonical { value, max_universe: rustc_type_ir::UniverseIndex::ZERO, - variables: crate::next_solver::CanonicalVars::new_from_iter(interner, error_replacer.vars), + variables: CanonicalVars::new_from_iter(interner, error_replacer.vars), } } pub fn callable_sig_from_fn_trait<'db>( - self_ty: crate::next_solver::Ty<'db>, + self_ty: Ty<'db>, trait_env: Arc>, db: &'db dyn HirDatabase, -) -> Option<(FnTrait, crate::next_solver::PolyFnSig<'db>)> { +) -> Option<(FnTrait, PolyFnSig<'db>)> { let krate = trait_env.krate; let fn_once_trait = FnTrait::FnOnce.get_id(db, krate)?; let output_assoc_type = fn_once_trait @@ -880,54 +483,46 @@ pub fn callable_sig_from_fn_trait<'db>( .associated_type_by_name(&Name::new_symbol_root(sym::Output))?; let mut table = InferenceTable::new(db, trait_env.clone()); - let b = TyBuilder::trait_ref(db, fn_once_trait); - if b.remaining() != 2 { - return None; - } // Register two obligations: // - Self: FnOnce // - >::Output == ?ret_ty let args_ty = table.next_ty_var(); let args = [self_ty, args_ty]; - let trait_ref = crate::next_solver::TraitRef::new(table.interner(), fn_once_trait.into(), args); - let projection = crate::next_solver::Ty::new_alias( + let trait_ref = TraitRef::new(table.interner(), fn_once_trait.into(), args); + let projection = Ty::new_alias( table.interner(), rustc_type_ir::AliasTyKind::Projection, - crate::next_solver::AliasTy::new(table.interner(), output_assoc_type.into(), args), + AliasTy::new(table.interner(), output_assoc_type.into(), args), ); - let pred = crate::next_solver::Predicate::upcast_from(trait_ref, table.interner()); + let pred = Predicate::upcast_from(trait_ref, table.interner()); if !table.try_obligation(pred).no_solution() { table.register_obligation(pred); let return_ty = table.normalize_alias_ty(projection); for fn_x in [FnTrait::Fn, FnTrait::FnMut, FnTrait::FnOnce] { let fn_x_trait = fn_x.get_id(db, krate)?; - let trait_ref = - crate::next_solver::TraitRef::new(table.interner(), fn_x_trait.into(), args); + let trait_ref = TraitRef::new(table.interner(), fn_x_trait.into(), args); if !table - .try_obligation(crate::next_solver::Predicate::upcast_from( - trait_ref, - table.interner(), - )) + .try_obligation(Predicate::upcast_from(trait_ref, table.interner())) .no_solution() { let ret_ty = table.resolve_completely(return_ty); let args_ty = table.resolve_completely(args_ty); - let crate::next_solver::TyKind::Tuple(params) = args_ty.kind() else { + let TyKind::Tuple(params) = args_ty.kind() else { return None; }; - let inputs_and_output = crate::next_solver::Tys::new_from_iter( + let inputs_and_output = Tys::new_from_iter( table.interner(), params.iter().chain(std::iter::once(ret_ty)), ); return Some(( fn_x, - crate::next_solver::Binder::dummy(crate::next_solver::FnSig { + Binder::dummy(FnSig { inputs_and_output, c_variadic: false, - safety: crate::next_solver::abi::Safety::Safe, + safety: abi::Safety::Safe, abi: FnAbi::RustCall, }), )); @@ -946,16 +541,16 @@ struct ParamCollector { impl<'db> rustc_type_ir::TypeVisitor> for ParamCollector { type Result = (); - fn visit_ty(&mut self, ty: crate::next_solver::Ty<'db>) -> Self::Result { - if let crate::next_solver::TyKind::Param(param) = ty.kind() { + fn visit_ty(&mut self, ty: Ty<'db>) -> Self::Result { + if let TyKind::Param(param) = ty.kind() { self.params.insert(param.id.into()); } ty.super_visit_with(self); } - fn visit_const(&mut self, konst: crate::next_solver::Const<'db>) -> Self::Result { - if let crate::next_solver::ConstKind::Param(param) = konst.kind() { + fn visit_const(&mut self, konst: Const<'db>) -> Self::Result { + if let ConstKind::Param(param) = konst.kind() { self.params.insert(param.id.into()); } @@ -974,7 +569,7 @@ where } pub fn known_const_to_ast<'db>( - konst: crate::next_solver::Const<'db>, + konst: Const<'db>, db: &'db dyn HirDatabase, display_target: DisplayTarget, ) -> Option { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs index b18d713c411e..a181ae0157cc 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs @@ -11,82 +11,93 @@ pub(crate) mod path; use std::{ cell::OnceCell, iter, mem, - ops::{self, Not as _}, + ops::{self, Deref, Not as _}, }; use base_db::Crate; -use chalk_ir::{ - Mutability, Safety, TypeOutlives, - cast::Cast, - fold::{Shift, TypeFoldable}, - interner::HasInterner, -}; - use either::Either; use hir_def::{ - AdtId, AssocItemId, ConstId, ConstParamId, EnumId, EnumVariantId, FunctionId, GenericDefId, - GenericParamId, LocalFieldId, Lookup, StaticId, StructId, TypeAliasId, TypeOrConstParamId, + AdtId, AssocItemId, CallableDefId, ConstId, ConstParamId, DefWithBodyId, EnumId, EnumVariantId, + FunctionId, GenericDefId, GenericParamId, HasModule, ImplId, ItemContainerId, LifetimeParamId, + LocalFieldId, Lookup, StaticId, StructId, TypeAliasId, TypeOrConstParamId, TypeParamId, UnionId, VariantId, builtin_type::BuiltinType, - expr_store::{ExpressionStore, path::Path}, - hir::generics::{GenericParamDataRef, TypeOrConstParamData, WherePredicate}, + expr_store::{ExpressionStore, HygieneId, path::Path}, + hir::generics::{ + GenericParamDataRef, TypeOrConstParamData, TypeParamProvenance, WherePredicate, + }, + item_tree::FieldsShape, lang_item::LangItem, - resolver::{HasResolver, LifetimeNs, Resolver, TypeNs}, - signatures::TraitFlags, + resolver::{HasResolver, LifetimeNs, Resolver, TypeNs, ValueNs}, + signatures::{FunctionSignature, TraitFlags, TypeAliasFlags}, type_ref::{ - ConstRef, LifetimeRefId, LiteralConstRef, PathId, TraitBoundModifier, TypeBound, TypeRef, - TypeRefId, + ConstRef, LifetimeRefId, LiteralConstRef, PathId, TraitBoundModifier, + TraitRef as HirTraitRef, TypeBound, TypeRef, TypeRefId, }, }; use hir_expand::name::Name; -use la_arena::{Arena, ArenaMap}; +use la_arena::{Arena, ArenaMap, Idx}; +use path::{PathDiagnosticCallback, PathLoweringContext}; +use rustc_ast_ir::Mutability; use rustc_hash::FxHashSet; +use rustc_pattern_analysis::Captures; +use rustc_type_ir::{ + AliasTyKind, BoundVarIndexKind, ConstKind, DebruijnIndex, ExistentialPredicate, + ExistentialProjection, ExistentialTraitRef, FnSig, OutlivesPredicate, + TyKind::{self}, + TypeVisitableExt, + inherent::{GenericArg as _, GenericArgs as _, IntoKind as _, Region as _, SliceLike, Ty as _}, +}; +use salsa::plumbing::AsId; +use smallvec::{SmallVec, smallvec}; use stdx::{impl_from, never}; use triomphe::{Arc, ThinArc}; use crate::{ - AliasTy, Binders, BoundVar, Const, DebruijnIndex, DynTy, FnAbi, FnPointer, FnSig, FnSubst, - ImplTrait, ImplTraitId, ImplTraits, Interner, Lifetime, LifetimeData, LifetimeOutlives, - QuantifiedWhereClause, QuantifiedWhereClauses, Substitution, TraitRef, TraitRefExt, Ty, - TyBuilder, TyKind, WhereClause, all_super_traits, - consteval_chalk::{intern_const_ref, path_to_const, unknown_const, unknown_const_as_generic}, + FnAbi, ImplTraitId, TraitEnvironment, TyLoweringDiagnostic, TyLoweringDiagnosticKind, + consteval::intern_const_ref, db::HirDatabase, - error_lifetime, generics::{Generics, generics, trait_self_param_idx}, - lower::{ - diagnostics::*, - path::{PathDiagnosticCallback, PathLoweringContext}, - }, - make_binders, - mapping::{from_chalk_trait_id, lt_to_placeholder_idx}, next_solver::{ - DbInterner, - mapping::{ChalkToNextSolver, NextSolverToChalk}, + AliasTy, Binder, BoundExistentialPredicates, Clause, Clauses, Const, DbInterner, + EarlyBinder, EarlyParamRegion, ErrorGuaranteed, GenericArg, GenericArgs, ParamConst, + ParamEnv, PolyFnSig, Predicate, Region, SolverDefId, TraitPredicate, TraitRef, Ty, Tys, + UnevaluatedConst, abi::Safety, }, - static_lifetime, to_chalk_trait_id, to_placeholder_idx, - utils::all_super_trait_refs, - variable_kinds_from_iter, }; +pub(crate) struct PathDiagnosticCallbackData(pub(crate) TypeRefId); + +#[derive(PartialEq, Eq, Debug, Hash)] +pub struct ImplTraits<'db> { + pub(crate) impl_traits: Arena>, +} + +#[derive(PartialEq, Eq, Debug, Hash)] +pub struct ImplTrait<'db> { + pub(crate) predicates: Vec>, +} + +pub type ImplTraitIdx<'db> = Idx>; + #[derive(Debug, Default)] -struct ImplTraitLoweringState { +struct ImplTraitLoweringState<'db> { /// When turning `impl Trait` into opaque types, we have to collect the /// bounds at the same time to get the IDs correct (without becoming too /// complicated). mode: ImplTraitLoweringMode, // This is structured as a struct with fields and not as an enum because it helps with the borrow checker. - opaque_type_data: Arena, + opaque_type_data: Arena>, } -impl ImplTraitLoweringState { - fn new(mode: ImplTraitLoweringMode) -> ImplTraitLoweringState { + +impl<'db> ImplTraitLoweringState<'db> { + fn new(mode: ImplTraitLoweringMode) -> ImplTraitLoweringState<'db> { Self { mode, opaque_type_data: Arena::new() } } } -pub(crate) struct PathDiagnosticCallbackData(pub(crate) TypeRefId); - #[derive(Debug, Clone)] -pub(crate) enum LifetimeElisionKind { +pub enum LifetimeElisionKind<'db> { /// Create a new anonymous lifetime parameter and reference it. /// /// If `report_in_path`, report an error when encountering lifetime elision in a path: @@ -104,75 +115,109 @@ pub(crate) enum LifetimeElisionKind { AnonymousCreateParameter { report_in_path: bool }, /// Replace all anonymous lifetimes by provided lifetime. - Elided(Lifetime), + Elided(Region<'db>), /// Give a hard error when either `&` or `'_` is written. Used to /// rule out things like `where T: Foo<'_>`. Does not imply an /// error on default object bounds (e.g., `Box`). AnonymousReportError, + /// Resolves elided lifetimes to `'static` if there are no other lifetimes in scope, + /// otherwise give a warning that the previous behavior of introducing a new early-bound + /// lifetime is a bug and will be removed (if `only_lint` is enabled). + StaticIfNoLifetimeInScope { only_lint: bool }, + + /// Signal we cannot find which should be the anonymous lifetime. + ElisionFailure, + /// Infer all elided lifetimes. Infer, } -impl LifetimeElisionKind { +impl<'db> LifetimeElisionKind<'db> { #[inline] - pub(crate) fn for_fn_ret() -> LifetimeElisionKind { + pub(crate) fn for_const( + interner: DbInterner<'db>, + const_parent: ItemContainerId, + ) -> LifetimeElisionKind<'db> { + match const_parent { + ItemContainerId::ExternBlockId(_) | ItemContainerId::ModuleId(_) => { + LifetimeElisionKind::Elided(Region::new_static(interner)) + } + ItemContainerId::ImplId(_) => { + LifetimeElisionKind::StaticIfNoLifetimeInScope { only_lint: true } + } + ItemContainerId::TraitId(_) => { + LifetimeElisionKind::StaticIfNoLifetimeInScope { only_lint: false } + } + } + } + + #[inline] + pub(crate) fn for_fn_params(data: &FunctionSignature) -> LifetimeElisionKind<'db> { + LifetimeElisionKind::AnonymousCreateParameter { report_in_path: data.is_async() } + } + + #[inline] + pub(crate) fn for_fn_ret(interner: DbInterner<'db>) -> LifetimeElisionKind<'db> { // FIXME: We should use the elided lifetime here, or `ElisionFailure`. - LifetimeElisionKind::Elided(error_lifetime()) + LifetimeElisionKind::Elided(Region::error(interner)) } } #[derive(Debug)] -pub(crate) struct TyLoweringContext<'db> { +pub struct TyLoweringContext<'db, 'a> { pub db: &'db dyn HirDatabase, - resolver: &'db Resolver<'db>, - store: &'db ExpressionStore, + interner: DbInterner<'db>, + resolver: &'a Resolver<'db>, + store: &'a ExpressionStore, def: GenericDefId, generics: OnceCell, in_binders: DebruijnIndex, - /// Note: Conceptually, it's thinkable that we could be in a location where - /// some type params should be represented as placeholders, and others - /// should be converted to variables. I think in practice, this isn't - /// possible currently, so this should be fine for now. - pub type_param_mode: ParamLoweringMode, - impl_trait_mode: ImplTraitLoweringState, + impl_trait_mode: ImplTraitLoweringState<'db>, /// Tracks types with explicit `?Sized` bounds. - pub(crate) unsized_types: FxHashSet, + pub(crate) unsized_types: FxHashSet>, pub(crate) diagnostics: Vec, - lifetime_elision: LifetimeElisionKind, + lifetime_elision: LifetimeElisionKind<'db>, + /// When lowering the defaults for generic params, this contains the index of the currently lowered param. + /// We disallow referring to later params, or to ADT's `Self`. + lowering_param_default: Option, } -impl<'db> TyLoweringContext<'db> { - pub(crate) fn new( +impl<'db, 'a> TyLoweringContext<'db, 'a> { + pub fn new( db: &'db dyn HirDatabase, - resolver: &'db Resolver<'db>, - store: &'db ExpressionStore, + resolver: &'a Resolver<'db>, + store: &'a ExpressionStore, def: GenericDefId, - lifetime_elision: LifetimeElisionKind, + lifetime_elision: LifetimeElisionKind<'db>, ) -> Self { let impl_trait_mode = ImplTraitLoweringState::new(ImplTraitLoweringMode::Disallowed); - let type_param_mode = ParamLoweringMode::Placeholder; - let in_binders = DebruijnIndex::INNERMOST; + let in_binders = DebruijnIndex::ZERO; Self { db, + interner: DbInterner::new_with(db, Some(resolver.krate()), None), resolver, def, generics: Default::default(), store, in_binders, impl_trait_mode, - type_param_mode, unsized_types: FxHashSet::default(), diagnostics: Vec::new(), lifetime_elision, + lowering_param_default: None, } } + pub(crate) fn set_lifetime_elision(&mut self, lifetime_elision: LifetimeElisionKind<'db>) { + self.lifetime_elision = lifetime_elision; + } + pub(crate) fn with_debruijn( &mut self, debruijn: DebruijnIndex, - f: impl FnOnce(&mut TyLoweringContext<'_>) -> T, + f: impl FnOnce(&mut TyLoweringContext<'db, '_>) -> T, ) -> T { let old_debruijn = mem::replace(&mut self.in_binders, debruijn); let result = f(self); @@ -183,28 +228,22 @@ impl<'db> TyLoweringContext<'db> { pub(crate) fn with_shifted_in( &mut self, debruijn: DebruijnIndex, - f: impl FnOnce(&mut TyLoweringContext<'_>) -> T, + f: impl FnOnce(&mut TyLoweringContext<'db, '_>) -> T, ) -> T { - self.with_debruijn(self.in_binders.shifted_in_from(debruijn), f) - } - - fn with_lifetime_elision( - &mut self, - lifetime_elision: LifetimeElisionKind, - f: impl FnOnce(&mut TyLoweringContext<'_>) -> T, - ) -> T { - let old_lifetime_elision = mem::replace(&mut self.lifetime_elision, lifetime_elision); - let result = f(self); - self.lifetime_elision = old_lifetime_elision; - result + self.with_debruijn(self.in_binders.shifted_in(debruijn.as_u32()), f) } pub(crate) fn with_impl_trait_mode(self, impl_trait_mode: ImplTraitLoweringMode) -> Self { Self { impl_trait_mode: ImplTraitLoweringState::new(impl_trait_mode), ..self } } - pub(crate) fn with_type_param_mode(self, type_param_mode: ParamLoweringMode) -> Self { - Self { type_param_mode, ..self } + pub(crate) fn impl_trait_mode(&mut self, impl_trait_mode: ImplTraitLoweringMode) -> &mut Self { + self.impl_trait_mode = ImplTraitLoweringState::new(impl_trait_mode); + self + } + + pub(crate) fn lowering_param_default(&mut self, index: u32) { + self.lowering_param_default = Some(index); } pub(crate) fn push_diagnostic(&mut self, type_ref: TypeRefId, kind: TyLoweringDiagnosticKind) { @@ -213,7 +252,7 @@ impl<'db> TyLoweringContext<'db> { } #[derive(Copy, Clone, Debug, PartialEq, Eq, Default)] -pub enum ImplTraitLoweringMode { +pub(crate) enum ImplTraitLoweringMode { /// `impl Trait` gets lowered into an opaque type that doesn't unify with /// anything except itself. This is used in places where values flow 'out', /// i.e. for arguments of the function we're currently checking, and return @@ -224,30 +263,17 @@ pub enum ImplTraitLoweringMode { Disallowed, } -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub enum ParamLoweringMode { - Placeholder, - Variable, -} - -impl<'db> TyLoweringContext<'db> { - pub(crate) fn lower_ty(&mut self, type_ref: TypeRefId) -> Ty { +impl<'db, 'a> TyLoweringContext<'db, 'a> { + pub fn lower_ty(&mut self, type_ref: TypeRefId) -> Ty<'db> { self.lower_ty_ext(type_ref).0 } - pub(crate) fn lower_const(&mut self, const_ref: &ConstRef, const_type: Ty) -> Const { + pub(crate) fn lower_const(&mut self, const_ref: ConstRef, const_type: Ty<'db>) -> Const<'db> { let const_ref = &self.store[const_ref.expr]; match const_ref { - hir_def::hir::Expr::Path(path) => path_to_const( - self.db, - self.resolver, - path, - self.type_param_mode, - || self.generics(), - self.in_binders, - const_type.clone(), - ) - .unwrap_or_else(|| unknown_const(const_type)), + hir_def::hir::Expr::Path(path) => { + self.path_to_const(path).unwrap_or_else(|| unknown_const(const_type)) + } hir_def::hir::Expr::Literal(literal) => intern_const_ref( self.db, &match *literal { @@ -290,32 +316,88 @@ impl<'db> TyLoweringContext<'db> { } } - pub(crate) fn lower_path_as_const(&mut self, path: &Path, const_type: Ty) -> Const { - path_to_const( - self.db, - self.resolver, - path, - self.type_param_mode, - || self.generics(), - self.in_binders, - const_type.clone(), - ) - .unwrap_or_else(|| unknown_const(const_type)) + pub(crate) fn path_to_const(&mut self, path: &Path) -> Option> { + match self.resolver.resolve_path_in_value_ns_fully(self.db, path, HygieneId::ROOT) { + Some(ValueNs::GenericParam(p)) => { + let args = self.generics(); + match args.type_or_const_param_idx(p.into()) { + Some(idx) => Some(self.const_param(p, idx as u32)), + None => { + never!( + "Generic list doesn't contain this param: {:?}, {:?}, {:?}", + args, + path, + p + ); + None + } + } + } + Some(ValueNs::ConstId(c)) => { + let args = GenericArgs::new_from_iter(self.interner, []); + Some(Const::new( + self.interner, + rustc_type_ir::ConstKind::Unevaluated(UnevaluatedConst::new( + SolverDefId::ConstId(c), + args, + )), + )) + } + _ => None, + } + } + + pub(crate) fn lower_path_as_const(&mut self, path: &Path, const_type: Ty<'db>) -> Const<'db> { + self.path_to_const(path).unwrap_or_else(|| unknown_const(const_type)) } fn generics(&self) -> &Generics { self.generics.get_or_init(|| generics(self.db, self.def)) } - pub(crate) fn lower_ty_ext(&mut self, type_ref_id: TypeRefId) -> (Ty, Option) { + fn param_index_is_disallowed(&self, index: u32) -> bool { + self.lowering_param_default + .is_some_and(|disallow_params_after| index >= disallow_params_after) + } + + fn type_param(&mut self, id: TypeParamId, index: u32) -> Ty<'db> { + if self.param_index_is_disallowed(index) { + // FIXME: Report an error. + Ty::new_error(self.interner, ErrorGuaranteed) + } else { + Ty::new_param(self.interner, id, index) + } + } + + fn const_param(&mut self, id: ConstParamId, index: u32) -> Const<'db> { + if self.param_index_is_disallowed(index) { + // FIXME: Report an error. + Const::error(self.interner) + } else { + Const::new_param(self.interner, ParamConst { id, index }) + } + } + + fn region_param(&mut self, id: LifetimeParamId, index: u32) -> Region<'db> { + if self.param_index_is_disallowed(index) { + // FIXME: Report an error. + Region::error(self.interner) + } else { + Region::new_early_param(self.interner, EarlyParamRegion { id, index }) + } + } + + #[tracing::instrument(skip(self), ret)] + pub fn lower_ty_ext(&mut self, type_ref_id: TypeRefId) -> (Ty<'db>, Option) { + let interner = self.interner; let mut res = None; let type_ref = &self.store[type_ref_id]; + tracing::debug!(?type_ref); let ty = match type_ref { - TypeRef::Never => TyKind::Never.intern(Interner), + TypeRef::Never => Ty::new(interner, TyKind::Never), TypeRef::Tuple(inner) => { let inner_tys = inner.iter().map(|&tr| self.lower_ty(tr)); - TyKind::Tuple(inner_tys.len(), Substitution::from_iter(Interner, inner_tys)) - .intern(Interner) + Ty::new_tup_from_iter(interner, inner_tys) } TypeRef::Path(path) => { let (ty, res_) = @@ -325,81 +407,61 @@ impl<'db> TyLoweringContext<'db> { } &TypeRef::TypeParam(type_param_id) => { res = Some(TypeNs::GenericParam(type_param_id)); - match self.type_param_mode { - ParamLoweringMode::Placeholder => { - let generics = self.generics(); - let idx = generics.type_or_const_param_idx(type_param_id.into()).unwrap(); - TyKind::Placeholder(to_placeholder_idx( - self.db, - type_param_id.into(), - idx as u32, - )) - } - ParamLoweringMode::Variable => { - let idx = - self.generics().type_or_const_param_idx(type_param_id.into()).unwrap(); - TyKind::BoundVar(BoundVar::new(self.in_binders, idx)) - } - } - .intern(Interner) + + let generics = self.generics(); + let (idx, _data) = + generics.type_or_const_param(type_param_id.into()).expect("matching generics"); + self.type_param(type_param_id, idx as u32) } &TypeRef::RawPtr(inner, mutability) => { let inner_ty = self.lower_ty(inner); - TyKind::Raw(lower_to_chalk_mutability(mutability), inner_ty).intern(Interner) + Ty::new(interner, TyKind::RawPtr(inner_ty, lower_mutability(mutability))) } TypeRef::Array(array) => { let inner_ty = self.lower_ty(array.ty); - let const_len = self.lower_const(&array.len, TyBuilder::usize()); - TyKind::Array(inner_ty, const_len).intern(Interner) + let const_len = self.lower_const(array.len, Ty::new_usize(interner)); + Ty::new_array_with_const_len(interner, inner_ty, const_len) } &TypeRef::Slice(inner) => { let inner_ty = self.lower_ty(inner); - TyKind::Slice(inner_ty).intern(Interner) + Ty::new_slice(interner, inner_ty) } TypeRef::Reference(ref_) => { let inner_ty = self.lower_ty(ref_.ty); - // FIXME: It should infer the eldided lifetimes instead of stubbing with static + // FIXME: It should infer the eldided lifetimes instead of stubbing with error let lifetime = ref_ .lifetime - .as_ref() - .map_or_else(error_lifetime, |&lr| self.lower_lifetime(lr)); - TyKind::Ref(lower_to_chalk_mutability(ref_.mutability), lifetime, inner_ty) - .intern(Interner) + .map_or_else(|| Region::error(interner), |lr| self.lower_lifetime(lr)); + Ty::new_ref(interner, lifetime, inner_ty, lower_mutability(ref_.mutability)) } - TypeRef::Placeholder => TyKind::Error.intern(Interner), + TypeRef::Placeholder => Ty::new_error(interner, ErrorGuaranteed), TypeRef::Fn(fn_) => { - let substs = self.with_shifted_in(DebruijnIndex::ONE, |ctx| { - let (params, ret) = fn_.split_params_and_ret(); - let mut subst = Vec::with_capacity(fn_.params.len()); - ctx.with_lifetime_elision( - LifetimeElisionKind::AnonymousCreateParameter { report_in_path: false }, - |ctx| { - subst.extend(params.iter().map(|&(_, tr)| ctx.lower_ty(tr))); - }, - ); - ctx.with_lifetime_elision(LifetimeElisionKind::for_fn_ret(), |ctx| { - subst.push(ctx.lower_ty(ret)); - }); - Substitution::from_iter(Interner, subst) - }); - TyKind::Function(FnPointer { - num_binders: 0, // FIXME lower `for<'a> fn()` correctly - sig: FnSig { + let substs = self.with_shifted_in( + DebruijnIndex::from_u32(1), + |ctx: &mut TyLoweringContext<'_, '_>| { + Tys::new_from_iter( + interner, + fn_.params.iter().map(|&(_, tr)| ctx.lower_ty(tr)), + ) + }, + ); + Ty::new_fn_ptr( + interner, + Binder::dummy(FnSig { abi: fn_.abi.as_ref().map_or(FnAbi::Rust, FnAbi::from_symbol), safety: if fn_.is_unsafe { Safety::Unsafe } else { Safety::Safe }, - variadic: fn_.is_varargs, - }, - substitution: FnSubst(substs), - }) - .intern(Interner) + c_variadic: fn_.is_varargs, + inputs_and_output: substs, + }), + ) } TypeRef::DynTrait(bounds) => self.lower_dyn_trait(bounds), TypeRef::ImplTrait(bounds) => { match self.impl_trait_mode.mode { ImplTraitLoweringMode::Opaque => { - let origin = match self.def { - GenericDefId::FunctionId(it) => Either::Left(it), - GenericDefId::TypeAliasId(it) => Either::Right(it), + let origin = match self.resolver.generic_def() { + Some(GenericDefId::FunctionId(it)) => Either::Left(it), + Some(GenericDefId::TypeAliasId(it)) => Either::Right(it), _ => panic!( "opaque impl trait lowering must be in function or type alias" ), @@ -408,9 +470,18 @@ impl<'db> TyLoweringContext<'db> { // this dance is to make sure the data is in the right // place even if we encounter more opaque types while // lowering the bounds - let idx = self.impl_trait_mode.opaque_type_data.alloc(ImplTrait { - bounds: crate::make_single_type_binders(Vec::default()), - }); + let idx = self + .impl_trait_mode + .opaque_type_data + .alloc(ImplTrait { predicates: Vec::default() }); + + let impl_trait_id = origin.either( + |f| ImplTraitId::ReturnTypeImplTrait(f, idx), + |a| ImplTraitId::TypeAliasImplTrait(a, idx), + ); + let opaque_ty_id: SolverDefId = + self.db.intern_impl_trait_id(impl_trait_id).into(); + // We don't want to lower the bounds inside the binders // we're currently in, because they don't end up inside // those binders. E.g. when we have `impl Trait TyLoweringContext<'db> { // parameter of the outer function, it's just one binder // away instead of two. let actual_opaque_type_data = self - .with_debruijn(DebruijnIndex::INNERMOST, |ctx| { - ctx.lower_impl_trait(bounds, self.resolver.krate()) + .with_debruijn(DebruijnIndex::ZERO, |ctx| { + ctx.lower_impl_trait(opaque_ty_id, bounds, self.resolver.krate()) }); self.impl_trait_mode.opaque_type_data[idx] = actual_opaque_type_data; - let impl_trait_id = origin.either( - |f| ImplTraitId::ReturnTypeImplTrait(f, idx), - |a| ImplTraitId::TypeAliasImplTrait(a, idx), - ); - let opaque_ty_id = self.db.intern_impl_trait_id(impl_trait_id).into(); - let generics = generics(self.db, origin.either(|f| f.into(), |a| a.into())); - let parameters = generics.bound_vars_subst(self.db, self.in_binders); - TyKind::OpaqueType(opaque_ty_id, parameters).intern(Interner) + let args = GenericArgs::identity_for_item(self.interner, opaque_ty_id); + Ty::new_alias( + self.interner, + AliasTyKind::Opaque, + AliasTy::new_from_args(self.interner, opaque_ty_id, args), + ) } ImplTraitLoweringMode::Disallowed => { // FIXME: report error - TyKind::Error.intern(Interner) + Ty::new_error(self.interner, ErrorGuaranteed) } } } - TypeRef::Error => TyKind::Error.intern(Interner), + TypeRef::Error => Ty::new_error(self.interner, ErrorGuaranteed), }; (ty, res) } @@ -449,8 +518,8 @@ impl<'db> TyLoweringContext<'db> { /// This is only for `generic_predicates_for_param`, where we can't just /// lower the self types of the predicates since that could lead to cycles. /// So we just check here if the `type_ref` resolves to a generic param, and which. - fn lower_ty_only_param(&mut self, type_ref_id: TypeRefId) -> Option { - let type_ref = &self.store[type_ref_id]; + fn lower_ty_only_param(&self, type_ref: TypeRefId) -> Option { + let type_ref = &self.store[type_ref]; let path = match type_ref { TypeRef::Path(path) => path, &TypeRef::TypeParam(idx) => return Some(idx.into()), @@ -462,9 +531,8 @@ impl<'db> TyLoweringContext<'db> { if path.segments().len() > 1 { return None; } - let mut ctx = self.at_path(PathId::from_type_ref_unchecked(type_ref_id)); - let resolution = match ctx.resolve_path_in_type_ns() { - Some((it, None)) => it, + let resolution = match self.resolver.resolve_path_in_type_ns(self.db, path) { + Some((it, None, _)) => it, _ => return None, }; match resolution { @@ -474,7 +542,7 @@ impl<'db> TyLoweringContext<'db> { } #[inline] - fn on_path_diagnostic_callback<'a>(type_ref: TypeRefId) -> PathDiagnosticCallback<'a, 'db> { + fn on_path_diagnostic_callback<'b>(type_ref: TypeRefId) -> PathDiagnosticCallback<'b, 'db> { PathDiagnosticCallback { data: Either::Left(PathDiagnosticCallbackData(type_ref)), callback: |data, this, diag| { @@ -485,7 +553,7 @@ impl<'db> TyLoweringContext<'db> { } #[inline] - fn at_path(&mut self, path_id: PathId) -> PathLoweringContext<'_, 'db> { + fn at_path(&mut self, path_id: PathId) -> PathLoweringContext<'_, 'a, 'db> { PathLoweringContext::new( self, Self::on_path_diagnostic_callback(path_id.type_ref()), @@ -493,7 +561,7 @@ impl<'db> TyLoweringContext<'db> { ) } - pub(crate) fn lower_path(&mut self, path: &Path, path_id: PathId) -> (Ty, Option) { + pub(crate) fn lower_path(&mut self, path: &Path, path_id: PathId) -> (Ty<'db>, Option) { // Resolve the path (in type namespace) if let Some(type_ref) = path.type_anchor() { let (ty, res) = self.lower_ty_ext(type_ref); @@ -504,7 +572,7 @@ impl<'db> TyLoweringContext<'db> { let mut ctx = self.at_path(path_id); let (resolution, remaining_index) = match ctx.resolve_path_in_type_ns() { Some(it) => it, - None => return (TyKind::Error.intern(Interner), None), + None => return (Ty::new_error(self.interner, ErrorGuaranteed), None), }; if matches!(resolution, TypeNs::TraitId(_)) && remaining_index.is_none() { @@ -520,8 +588,8 @@ impl<'db> TyLoweringContext<'db> { fn lower_trait_ref_from_path( &mut self, path_id: PathId, - explicit_self_ty: Ty, - ) -> Option<(TraitRef, PathLoweringContext<'_, 'db>)> { + explicit_self_ty: Ty<'db>, + ) -> Option<(TraitRef<'db>, PathLoweringContext<'_, 'a, 'db>)> { let mut ctx = self.at_path(path_id); let resolved = match ctx.resolve_path_in_type_ns_fully()? { // FIXME(trait_alias): We need to handle trait alias here. @@ -531,26 +599,57 @@ impl<'db> TyLoweringContext<'db> { Some((ctx.lower_trait_ref_from_resolved_path(resolved, explicit_self_ty, false), ctx)) } - /// When lowering predicates from parents (impl, traits) for children defs (fns, consts, types), `generics` should - /// contain the `Generics` for the **child**, while `predicate_owner` should contain the `GenericDefId` of the - /// **parent**. This is important so we generate the correct bound var/placeholder. + fn lower_trait_ref( + &mut self, + trait_ref: &HirTraitRef, + explicit_self_ty: Ty<'db>, + ) -> Option> { + self.lower_trait_ref_from_path(trait_ref.path, explicit_self_ty).map(|it| it.0) + } + pub(crate) fn lower_where_predicate<'b>( &'b mut self, where_predicate: &'b WherePredicate, ignore_bindings: bool, - ) -> impl Iterator + use<'db, 'b> { + generics: &Generics, + predicate_filter: PredicateFilter, + ) -> impl Iterator> + use<'a, 'b, 'db> { match where_predicate { WherePredicate::ForLifetime { target, bound, .. } | WherePredicate::TypeBound { target, bound } => { + if let PredicateFilter::SelfTrait = predicate_filter { + let target_type = &self.store[*target]; + let self_type = 'is_self: { + if let TypeRef::Path(path) = target_type + && path.is_self_type() + { + break 'is_self true; + } + if let TypeRef::TypeParam(param) = target_type + && generics[param.local_id()].is_trait_self() + { + break 'is_self true; + } + false + }; + if !self_type { + return Either::Left(Either::Left(iter::empty())); + } + } let self_ty = self.lower_ty(*target); - Either::Left(self.lower_type_bound(bound, self_ty, ignore_bindings)) + Either::Left(Either::Right(self.lower_type_bound(bound, self_ty, ignore_bindings))) + } + &WherePredicate::Lifetime { bound, target } => { + Either::Right(iter::once(Clause(Predicate::new( + self.interner, + Binder::dummy(rustc_type_ir::PredicateKind::Clause( + rustc_type_ir::ClauseKind::RegionOutlives(OutlivesPredicate( + self.lower_lifetime(bound), + self.lower_lifetime(target), + )), + )), + )))) } - &WherePredicate::Lifetime { bound, target } => Either::Right(iter::once( - crate::wrap_empty_binders(WhereClause::LifetimeOutlives(LifetimeOutlives { - a: self.lower_lifetime(bound), - b: self.lower_lifetime(target), - })), - )), } .into_iter() } @@ -558,40 +657,40 @@ impl<'db> TyLoweringContext<'db> { pub(crate) fn lower_type_bound<'b>( &'b mut self, bound: &'b TypeBound, - self_ty: Ty, + self_ty: Ty<'db>, ignore_bindings: bool, - ) -> impl Iterator + use<'b, 'db> { + ) -> impl Iterator> + use<'b, 'a, 'db> { + let interner = self.interner; let mut assoc_bounds = None; let mut clause = None; match bound { &TypeBound::Path(path, TraitBoundModifier::None) | &TypeBound::ForLifetime(_, path) => { // FIXME Don't silently drop the hrtb lifetimes here - if let Some((trait_ref, mut ctx)) = - self.lower_trait_ref_from_path(path, self_ty.clone()) - { + if let Some((trait_ref, mut ctx)) = self.lower_trait_ref_from_path(path, self_ty) { // FIXME(sized-hierarchy): Remove this bound modifications once we have implemented // sized-hierarchy correctly. let meta_sized = LangItem::MetaSized .resolve_trait(ctx.ty_ctx().db, ctx.ty_ctx().resolver.krate()); let pointee_sized = LangItem::PointeeSized .resolve_trait(ctx.ty_ctx().db, ctx.ty_ctx().resolver.krate()); - let destruct = LangItem::Destruct - .resolve_trait(ctx.ty_ctx().db, ctx.ty_ctx().resolver.krate()); - let hir_trait_id = trait_ref.hir_trait_id(); - if meta_sized.is_some_and(|it| it == hir_trait_id) - || destruct.is_some_and(|it| it == hir_trait_id) - { + if meta_sized.is_some_and(|it| it == trait_ref.def_id.0) { // Ignore this bound - } else if pointee_sized.is_some_and(|it| it == hir_trait_id) { + } else if pointee_sized.is_some_and(|it| it == trait_ref.def_id.0) { // Regard this as `?Sized` bound ctx.ty_ctx().unsized_types.insert(self_ty); } else { if !ignore_bindings { - assoc_bounds = - ctx.assoc_type_bindings_from_type_bound(trait_ref.clone()); + assoc_bounds = ctx.assoc_type_bindings_from_type_bound(trait_ref); } - clause = - Some(crate::wrap_empty_binders(WhereClause::Implemented(trait_ref))); + clause = Some(Clause(Predicate::new( + interner, + Binder::dummy(rustc_type_ir::PredicateKind::Clause( + rustc_type_ir::ClauseKind::Trait(TraitPredicate { + trait_ref, + polarity: rustc_type_ir::PredicatePolarity::Positive, + }), + )), + ))); } } } @@ -601,95 +700,137 @@ impl<'db> TyLoweringContext<'db> { // `?Sized` has no of them. // If we got another trait here ignore the bound completely. let trait_id = self - .lower_trait_ref_from_path(path, self_ty.clone()) - .map(|(trait_ref, _)| trait_ref.hir_trait_id()); + .lower_trait_ref_from_path(path, self_ty) + .map(|(trait_ref, _)| trait_ref.def_id.0); if trait_id == sized_trait { self.unsized_types.insert(self_ty); } } &TypeBound::Lifetime(l) => { let lifetime = self.lower_lifetime(l); - clause = Some(crate::wrap_empty_binders(WhereClause::TypeOutlives(TypeOutlives { - ty: self_ty, - lifetime, - }))); + clause = Some(Clause(Predicate::new( + self.interner, + Binder::dummy(rustc_type_ir::PredicateKind::Clause( + rustc_type_ir::ClauseKind::TypeOutlives(OutlivesPredicate( + self_ty, lifetime, + )), + )), + ))); } TypeBound::Use(_) | TypeBound::Error => {} } clause.into_iter().chain(assoc_bounds.into_iter().flatten()) } - fn lower_dyn_trait(&mut self, bounds: &[TypeBound]) -> Ty { - let self_ty = TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)).intern(Interner); + fn lower_dyn_trait(&mut self, bounds: &[TypeBound]) -> Ty<'db> { + let interner = self.interner; + // FIXME: we should never create non-existential predicates in the first place + // For now, use an error type so we don't run into dummy binder issues + let self_ty = Ty::new_error(interner, ErrorGuaranteed); // INVARIANT: The principal trait bound, if present, must come first. Others may be in any // order but should be in the same order for the same set but possibly different order of // bounds in the input. // INVARIANT: If this function returns `DynTy`, there should be at least one trait bound. // These invariants are utilized by `TyExt::dyn_trait()` and chalk. let mut lifetime = None; - let bounds = self.with_shifted_in(DebruijnIndex::ONE, |ctx| { - let mut lowered_bounds = Vec::new(); + let bounds = self.with_shifted_in(DebruijnIndex::from_u32(1), |ctx| { + let mut lowered_bounds: Vec< + rustc_type_ir::Binder, ExistentialPredicate>>, + > = Vec::new(); for b in bounds { - ctx.lower_type_bound(b, self_ty.clone(), false).for_each(|b| { - let filter = match b.skip_binders() { - WhereClause::Implemented(_) | WhereClause::AliasEq(_) => true, - WhereClause::LifetimeOutlives(_) => false, - WhereClause::TypeOutlives(t) => { - lifetime = Some(t.lifetime.clone()); - false - } - }; - if filter { - lowered_bounds.push(b); + let db = ctx.db; + ctx.lower_type_bound(b, self_ty, false).for_each(|b| { + if let Some(bound) = b + .kind() + .map_bound(|c| match c { + rustc_type_ir::ClauseKind::Trait(t) => { + let id = t.def_id(); + let is_auto = + db.trait_signature(id.0).flags.contains(TraitFlags::AUTO); + if is_auto { + Some(ExistentialPredicate::AutoTrait(t.def_id())) + } else { + Some(ExistentialPredicate::Trait( + ExistentialTraitRef::new_from_args( + interner, + t.def_id(), + GenericArgs::new_from_iter( + interner, + t.trait_ref.args.iter().skip(1), + ), + ), + )) + } + } + rustc_type_ir::ClauseKind::Projection(p) => { + Some(ExistentialPredicate::Projection( + ExistentialProjection::new_from_args( + interner, + p.def_id(), + GenericArgs::new_from_iter( + interner, + p.projection_term.args.iter().skip(1), + ), + p.term, + ), + )) + } + rustc_type_ir::ClauseKind::TypeOutlives(outlives_predicate) => { + lifetime = Some(outlives_predicate.1); + None + } + rustc_type_ir::ClauseKind::RegionOutlives(_) + | rustc_type_ir::ClauseKind::ConstArgHasType(_, _) + | rustc_type_ir::ClauseKind::WellFormed(_) + | rustc_type_ir::ClauseKind::ConstEvaluatable(_) + | rustc_type_ir::ClauseKind::HostEffect(_) + | rustc_type_ir::ClauseKind::UnstableFeature(_) => unreachable!(), + }) + .transpose() + { + lowered_bounds.push(bound); } - }); + }) } let mut multiple_regular_traits = false; let mut multiple_same_projection = false; lowered_bounds.sort_unstable_by(|lhs, rhs| { use std::cmp::Ordering; - match (lhs.skip_binders(), rhs.skip_binders()) { - (WhereClause::Implemented(lhs), WhereClause::Implemented(rhs)) => { - let lhs_id = lhs.trait_id; - let lhs_is_auto = ctx - .db - .trait_signature(from_chalk_trait_id(lhs_id)) - .flags - .contains(TraitFlags::AUTO); - let rhs_id = rhs.trait_id; - let rhs_is_auto = ctx - .db - .trait_signature(from_chalk_trait_id(rhs_id)) - .flags - .contains(TraitFlags::AUTO); - - if !lhs_is_auto && !rhs_is_auto { - multiple_regular_traits = true; - } - // Note that the ordering here is important; this ensures the invariant - // mentioned above. - (lhs_is_auto, lhs_id).cmp(&(rhs_is_auto, rhs_id)) + match ((*lhs).skip_binder(), (*rhs).skip_binder()) { + (ExistentialPredicate::Trait(_), ExistentialPredicate::Trait(_)) => { + multiple_regular_traits = true; + // Order doesn't matter - we error + Ordering::Equal } - (WhereClause::Implemented(_), _) => Ordering::Less, - (_, WhereClause::Implemented(_)) => Ordering::Greater, - (WhereClause::AliasEq(lhs), WhereClause::AliasEq(rhs)) => { - match (&lhs.alias, &rhs.alias) { - (AliasTy::Projection(lhs_proj), AliasTy::Projection(rhs_proj)) => { - // We only compare the `associated_ty_id`s. We shouldn't have - // multiple bounds for an associated type in the correct Rust code, - // and if we do, we error out. - if lhs_proj.associated_ty_id == rhs_proj.associated_ty_id { - multiple_same_projection = true; - } - lhs_proj.associated_ty_id.cmp(&rhs_proj.associated_ty_id) - } - // We don't produce `AliasTy::Opaque`s yet. + ( + ExistentialPredicate::AutoTrait(lhs_id), + ExistentialPredicate::AutoTrait(rhs_id), + ) => lhs_id.0.cmp(&rhs_id.0), + (ExistentialPredicate::Trait(_), _) => Ordering::Less, + (_, ExistentialPredicate::Trait(_)) => Ordering::Greater, + (ExistentialPredicate::AutoTrait(_), _) => Ordering::Less, + (_, ExistentialPredicate::AutoTrait(_)) => Ordering::Greater, + ( + ExistentialPredicate::Projection(lhs), + ExistentialPredicate::Projection(rhs), + ) => { + let lhs_id = match lhs.def_id { + SolverDefId::TypeAliasId(id) => id, _ => unreachable!(), + }; + let rhs_id = match rhs.def_id { + SolverDefId::TypeAliasId(id) => id, + _ => unreachable!(), + }; + // We only compare the `associated_ty_id`s. We shouldn't have + // multiple bounds for an associated type in the correct Rust code, + // and if we do, we error out. + if lhs_id == rhs_id { + multiple_same_projection = true; } + lhs_id.as_id().index().cmp(&rhs_id.as_id().index()) } - // `WhereClause::{TypeOutlives, LifetimeOutlives}` have been filtered out - _ => unreachable!(), } }); @@ -697,568 +838,195 @@ impl<'db> TyLoweringContext<'db> { return None; } - lowered_bounds.first().and_then(|b| b.trait_id())?; + if !lowered_bounds.first().map_or(false, |b| { + matches!( + b.as_ref().skip_binder(), + ExistentialPredicate::Trait(_) | ExistentialPredicate::AutoTrait(_) + ) + }) { + return None; + } // As multiple occurrences of the same auto traits *are* permitted, we deduplicate the // bounds. We shouldn't have repeated elements besides auto traits at this point. lowered_bounds.dedup(); - Some(QuantifiedWhereClauses::from_iter(Interner, lowered_bounds)) + Some(BoundExistentialPredicates::new_from_iter(interner, lowered_bounds)) }); if let Some(bounds) = bounds { - let bounds = crate::make_single_type_binders(bounds); - TyKind::Dyn(DynTy { - bounds, - lifetime: match lifetime { - Some(it) => match it.bound_var(Interner) { - Some(bound_var) => bound_var - .shifted_out_to(DebruijnIndex::new(2)) - .map(|bound_var| LifetimeData::BoundVar(bound_var).intern(Interner)) - .unwrap_or(it), - None => it, - }, - None => error_lifetime(), + let region = match lifetime { + Some(it) => match it.kind() { + rustc_type_ir::RegionKind::ReBound(BoundVarIndexKind::Bound(db), var) => { + Region::new_bound( + self.interner, + db.shifted_out_to_binder(DebruijnIndex::from_u32(2)), + var, + ) + } + _ => it, }, - }) - .intern(Interner) + None => Region::new_static(self.interner), + }; + Ty::new_dynamic(self.interner, bounds, region) } else { // FIXME: report error // (additional non-auto traits, associated type rebound, or no resolved trait) - TyKind::Error.intern(Interner) + Ty::new_error(self.interner, ErrorGuaranteed) } } - fn lower_impl_trait(&mut self, bounds: &[TypeBound], krate: Crate) -> ImplTrait { + fn lower_impl_trait( + &mut self, + def_id: SolverDefId, + bounds: &[TypeBound], + krate: Crate, + ) -> ImplTrait<'db> { + let interner = self.interner; cov_mark::hit!(lower_rpit); - let self_ty = TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)).intern(Interner); - let predicates = self.with_shifted_in(DebruijnIndex::ONE, |ctx| { + let args = GenericArgs::identity_for_item(interner, def_id); + let self_ty = Ty::new_alias( + self.interner, + rustc_type_ir::AliasTyKind::Opaque, + AliasTy::new_from_args(interner, def_id, args), + ); + let predicates = self.with_shifted_in(DebruijnIndex::from_u32(1), |ctx| { let mut predicates = Vec::new(); for b in bounds { - predicates.extend(ctx.lower_type_bound(b, self_ty.clone(), false)); + predicates.extend(ctx.lower_type_bound(b, self_ty, false)); } if !ctx.unsized_types.contains(&self_ty) { - let sized_trait = - LangItem::Sized.resolve_trait(ctx.db, krate).map(to_chalk_trait_id); + let sized_trait = LangItem::Sized.resolve_trait(self.db, krate); let sized_clause = sized_trait.map(|trait_id| { - let clause = WhereClause::Implemented(TraitRef { - trait_id, - substitution: Substitution::from1(Interner, self_ty.clone()), - }); - crate::wrap_empty_binders(clause) + let trait_ref = TraitRef::new_from_args( + interner, + trait_id.into(), + GenericArgs::new_from_iter(interner, [self_ty.into()]), + ); + Clause(Predicate::new( + interner, + Binder::dummy(rustc_type_ir::PredicateKind::Clause( + rustc_type_ir::ClauseKind::Trait(TraitPredicate { + trait_ref, + polarity: rustc_type_ir::PredicatePolarity::Positive, + }), + )), + )) }); predicates.extend(sized_clause); } predicates.shrink_to_fit(); predicates }); - ImplTrait { bounds: crate::make_single_type_binders(predicates) } + ImplTrait { predicates } } - pub(crate) fn lower_lifetime(&self, lifetime: LifetimeRefId) -> Lifetime { + pub(crate) fn lower_lifetime(&mut self, lifetime: LifetimeRefId) -> Region<'db> { match self.resolver.resolve_lifetime(&self.store[lifetime]) { Some(resolution) => match resolution { - LifetimeNs::Static => static_lifetime(), - LifetimeNs::LifetimeParam(id) => match self.type_param_mode { - ParamLoweringMode::Placeholder => { - let generics = self.generics(); - let idx = generics.lifetime_idx(id).unwrap(); - LifetimeData::Placeholder(lt_to_placeholder_idx(self.db, id, idx as u32)) - } - ParamLoweringMode::Variable => { - let idx = match self.generics().lifetime_idx(id) { - None => return error_lifetime(), - Some(idx) => idx, - }; - - LifetimeData::BoundVar(BoundVar::new(self.in_binders, idx)) - } + LifetimeNs::Static => Region::new_static(self.interner), + LifetimeNs::LifetimeParam(id) => { + let idx = match self.generics().lifetime_idx(id) { + None => return Region::error(self.interner), + Some(idx) => idx, + }; + self.region_param(id, idx as u32) } - .intern(Interner), }, - None => error_lifetime(), + None => Region::error(self.interner), } } } -fn named_associated_type_shorthand_candidates( - db: &dyn HirDatabase, - // If the type parameter is defined in an impl and we're in a method, there - // might be additional where clauses to consider - def: GenericDefId, - res: TypeNs, - assoc_name: Option, - // Do NOT let `cb` touch `TraitRef` outside of `TyLoweringContext`. Its substitution contains - // free `BoundVar`s that need to be shifted and only `TyLoweringContext` knows how to do that - // properly (see `TyLoweringContext::select_associated_type()`). - mut cb: impl FnMut(&Name, &TraitRef, TypeAliasId) -> Option, -) -> Option { - let mut search = |t| { - all_super_trait_refs(db, t, |t| { - let data = t.hir_trait_id().trait_items(db); - - for (name, assoc_id) in &data.items { - if let AssocItemId::TypeAliasId(alias) = assoc_id - && let Some(result) = cb(name, &t, *alias) - { - return Some(result); - } - } - None - }) - }; - - let interner = DbInterner::new_with(db, None, None); - match res { - TypeNs::SelfType(impl_id) => { - let trait_ref = db.impl_trait(impl_id)?; - - let impl_id_as_generic_def: GenericDefId = impl_id.into(); - if impl_id_as_generic_def != def { - let subst = TyBuilder::subst_for_def(db, impl_id, None) - .fill_with_bound_vars(DebruijnIndex::INNERMOST, 0) - .build(); - let args: crate::next_solver::GenericArgs<'_> = subst.to_nextsolver(interner); - let trait_ref = trait_ref.instantiate(interner, args).to_chalk(interner); - search(trait_ref) - } else { - search(trait_ref.skip_binder().to_chalk(interner)) - } - } - TypeNs::GenericParam(param_id) => { - let predicates = db.generic_predicates_for_param(def, param_id.into(), assoc_name); - let res = predicates.iter().find_map(|pred| match pred.skip_binders().skip_binders() { - // FIXME: how to correctly handle higher-ranked bounds here? - WhereClause::Implemented(tr) => search( - tr.clone() - .shifted_out_to(Interner, DebruijnIndex::ONE) - .expect("FIXME unexpected higher-ranked trait bound"), - ), - _ => None, - }); - if res.is_some() { - return res; - } - // Handle `Self::Type` referring to own associated type in trait definitions - if let GenericDefId::TraitId(trait_id) = param_id.parent() { - let trait_generics = generics(db, trait_id.into()); - if trait_generics[param_id.local_id()].is_trait_self() { - let trait_ref = TyBuilder::trait_ref(db, trait_id) - .fill_with_bound_vars(DebruijnIndex::INNERMOST, 0) - .build(); - return search(trait_ref); - } - } - None - } - _ => None, +pub(crate) fn lower_mutability(m: hir_def::type_ref::Mutability) -> Mutability { + match m { + hir_def::type_ref::Mutability::Shared => Mutability::Not, + hir_def::type_ref::Mutability::Mut => Mutability::Mut, } } +fn unknown_const(_ty: Ty<'_>) -> Const<'_> { + Const::new(DbInterner::conjure(), ConstKind::Error(ErrorGuaranteed)) +} + pub(crate) type Diagnostics = Option>; pub(crate) fn create_diagnostics(diagnostics: Vec) -> Diagnostics { (!diagnostics.is_empty()).then(|| ThinArc::from_header_and_iter((), diagnostics.into_iter())) } -pub(crate) fn field_types_query( - db: &dyn HirDatabase, - variant_id: VariantId, -) -> Arc>> { - field_types_with_diagnostics_query(db, variant_id).0 -} - -/// Build the type of all specific fields of a struct or enum variant. -pub(crate) fn field_types_with_diagnostics_query( - db: &dyn HirDatabase, - variant_id: VariantId, -) -> (Arc>>, Diagnostics) { - let var_data = variant_id.fields(db); - let fields = var_data.fields(); - if fields.is_empty() { - return (Arc::new(ArenaMap::default()), None); - } - - let (resolver, def): (_, GenericDefId) = match variant_id { - VariantId::StructId(it) => (it.resolver(db), it.into()), - VariantId::UnionId(it) => (it.resolver(db), it.into()), - VariantId::EnumVariantId(it) => (it.resolver(db), it.lookup(db).parent.into()), - }; - let generics = generics(db, def); - let mut res = ArenaMap::default(); - let mut ctx = TyLoweringContext::new( - db, - &resolver, - &var_data.store, - def, - LifetimeElisionKind::AnonymousReportError, - ) - .with_type_param_mode(ParamLoweringMode::Variable); - for (field_id, field_data) in fields.iter() { - res.insert(field_id, make_binders(db, &generics, ctx.lower_ty(field_data.type_ref))); - } - (Arc::new(res), create_diagnostics(ctx.diagnostics)) -} - -/// This query exists only to be used when resolving short-hand associated types -/// like `T::Item`. -/// -/// See the analogous query in rustc and its comment: -/// -/// This is a query mostly to handle cycles somewhat gracefully; e.g. the -/// following bounds are disallowed: `T: Foo, U: Foo`, but -/// these are fine: `T: Foo, U: Foo<()>`. -pub(crate) fn generic_predicates_for_param_query( - db: &dyn HirDatabase, - def: GenericDefId, - param_id: TypeOrConstParamId, - assoc_name: Option, -) -> GenericPredicates { - let generics = generics(db, def); - if generics.has_no_predicates() && generics.is_empty() { - return GenericPredicates(None); - } - - let resolver = def.resolver(db); - let mut ctx = TyLoweringContext::new( - db, - &resolver, - generics.store(), - def, - LifetimeElisionKind::AnonymousReportError, - ) - .with_type_param_mode(ParamLoweringMode::Variable); - - // we have to filter out all other predicates *first*, before attempting to lower them - let predicate = |pred: &_, ctx: &mut TyLoweringContext<'_>| match pred { - WherePredicate::ForLifetime { target, bound, .. } - | WherePredicate::TypeBound { target, bound, .. } => { - let invalid_target = { ctx.lower_ty_only_param(*target) != Some(param_id) }; - if invalid_target { - // FIXME(sized-hierarchy): Revisit and adjust this properly once we have implemented - // sized-hierarchy correctly. - // If this is filtered out without lowering, `?Sized` or `PointeeSized` is not gathered into - // `ctx.unsized_types` - let lower = || -> bool { - match bound { - TypeBound::Path(_, TraitBoundModifier::Maybe) => true, - TypeBound::Path(path, _) | TypeBound::ForLifetime(_, path) => { - let TypeRef::Path(path) = &ctx.store[path.type_ref()] else { - return false; - }; - let Some(pointee_sized) = - LangItem::PointeeSized.resolve_trait(ctx.db, ctx.resolver.krate()) - else { - return false; - }; - // Lower the path directly with `Resolver` instead of PathLoweringContext` - // to prevent diagnostics duplications. - ctx.resolver.resolve_path_in_type_ns_fully(ctx.db, path).is_some_and( - |it| matches!(it, TypeNs::TraitId(tr) if tr == pointee_sized), - ) - } - _ => false, - } - }(); - if lower { - ctx.lower_where_predicate(pred, true).for_each(drop); - } - return false; - } - - match bound { - &TypeBound::ForLifetime(_, path) | &TypeBound::Path(path, _) => { - // Only lower the bound if the trait could possibly define the associated - // type we're looking for. - let path = &ctx.store[path]; - - let Some(assoc_name) = &assoc_name else { return true }; - let Some(TypeNs::TraitId(tr)) = - resolver.resolve_path_in_type_ns_fully(db, path) - else { - return false; - }; - - all_super_traits(db, tr).iter().any(|tr| { - tr.trait_items(db).items.iter().any(|(name, item)| { - matches!(item, AssocItemId::TypeAliasId(_)) && name == assoc_name - }) - }) - } - TypeBound::Use(_) | TypeBound::Lifetime(_) | TypeBound::Error => false, - } - } - WherePredicate::Lifetime { .. } => false, - }; - let mut predicates = Vec::new(); - for maybe_parent_generics in - std::iter::successors(Some(&generics), |generics| generics.parent_generics()) - { - ctx.store = maybe_parent_generics.store(); - for pred in maybe_parent_generics.where_predicates() { - if predicate(pred, &mut ctx) { - predicates.extend( - ctx.lower_where_predicate(pred, true).map(|p| make_binders(db, &generics, p)), - ); - } - } - } - - let subst = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST); - if !subst.is_empty(Interner) { - let explicitly_unsized_tys = ctx.unsized_types; - if let Some(implicitly_sized_predicates) = implicitly_sized_clauses( - db, - param_id.parent, - &explicitly_unsized_tys, - &subst, - &resolver, - ) { - predicates.extend( - implicitly_sized_predicates - .map(|p| make_binders(db, &generics, crate::wrap_empty_binders(p))), - ); - }; - } - GenericPredicates(predicates.is_empty().not().then(|| predicates.into())) -} - -pub(crate) fn generic_predicates_for_param_cycle_result( - _db: &dyn HirDatabase, - _def: GenericDefId, - _param_id: TypeOrConstParamId, - _assoc_name: Option, -) -> GenericPredicates { - GenericPredicates(None) -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct GenericPredicates(Option]>>); - -impl ops::Deref for GenericPredicates { - type Target = [Binders]; - - fn deref(&self) -> &Self::Target { - self.0.as_deref().unwrap_or(&[]) - } -} - -/// Resolve the where clause(s) of an item with generics. -pub(crate) fn generic_predicates_query( - db: &dyn HirDatabase, - def: GenericDefId, -) -> GenericPredicates { - generic_predicates_filtered_by(db, def, |_, _| true).0 -} - -/// Resolve the where clause(s) of an item with generics, -/// with a given filter -fn generic_predicates_filtered_by( - db: &dyn HirDatabase, - def: GenericDefId, - filter: F, -) -> (GenericPredicates, Diagnostics) -where - F: Fn(&WherePredicate, GenericDefId) -> bool, -{ - let generics = generics(db, def); - if generics.has_no_predicates() && generics.is_empty() { - return (GenericPredicates(None), None); - } - - let resolver = def.resolver(db); - let mut ctx = TyLoweringContext::new( - db, - &resolver, - generics.store(), - def, - LifetimeElisionKind::AnonymousReportError, - ) - .with_type_param_mode(ParamLoweringMode::Variable); - - let mut predicates = Vec::new(); - for maybe_parent_generics in - std::iter::successors(Some(&generics), |generics| generics.parent_generics()) - { - ctx.store = maybe_parent_generics.store(); - for pred in maybe_parent_generics.where_predicates() { - if filter(pred, maybe_parent_generics.def()) { - // We deliberately use `generics` and not `maybe_parent_generics` here. This is not a mistake! - // If we use the parent generics - predicates.extend( - ctx.lower_where_predicate(pred, false).map(|p| make_binders(db, &generics, p)), - ); - } - } - } - - if !generics.is_empty() { - let subst = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST); - let explicitly_unsized_tys = ctx.unsized_types; - if let Some(implicitly_sized_predicates) = - implicitly_sized_clauses(db, def, &explicitly_unsized_tys, &subst, &resolver) - { - predicates.extend( - implicitly_sized_predicates - .map(|p| make_binders(db, &generics, crate::wrap_empty_binders(p))), - ); - }; - } - - ( - GenericPredicates(predicates.is_empty().not().then(|| predicates.into())), - create_diagnostics(ctx.diagnostics), - ) -} - -/// Generate implicit `: Sized` predicates for all generics that has no `?Sized` bound. -/// Exception is Self of a trait def. -fn implicitly_sized_clauses<'db, 'a, 'subst: 'a>( +pub(crate) fn impl_trait_query<'db>( db: &'db dyn HirDatabase, - def: GenericDefId, - explicitly_unsized_tys: &'a FxHashSet, - substitution: &'subst Substitution, - resolver: &Resolver<'db>, -) -> Option> { - let sized_trait = LangItem::Sized.resolve_trait(db, resolver.krate()).map(to_chalk_trait_id)?; - - let trait_self_idx = trait_self_param_idx(db, def); - - Some( - substitution - .iter(Interner) - .enumerate() - .filter_map( - move |(idx, generic_arg)| { - if Some(idx) == trait_self_idx { None } else { Some(generic_arg) } - }, - ) - .filter_map(|generic_arg| generic_arg.ty(Interner)) - .filter(move |&self_ty| !explicitly_unsized_tys.contains(self_ty)) - .map(move |self_ty| { - WhereClause::Implemented(TraitRef { - trait_id: sized_trait, - substitution: Substitution::from1(Interner, self_ty.clone()), - }) - }), - ) + impl_id: ImplId, +) -> Option>> { + db.impl_trait_with_diagnostics(impl_id).map(|it| it.0) } -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct GenericDefaults(Option]>>); - -impl ops::Deref for GenericDefaults { - type Target = [Binders]; - - fn deref(&self) -> &Self::Target { - self.0.as_deref().unwrap_or(&[]) - } -} - -pub(crate) fn generic_defaults_query(db: &dyn HirDatabase, def: GenericDefId) -> GenericDefaults { - db.generic_defaults_with_diagnostics(def).0 -} - -/// Resolve the default type params from generics. -/// -/// Diagnostics are only returned for this `GenericDefId` (returned defaults include parents). -pub(crate) fn generic_defaults_with_diagnostics_query( - db: &dyn HirDatabase, - def: GenericDefId, -) -> (GenericDefaults, Diagnostics) { - let generic_params = generics(db, def); - if generic_params.is_empty() { - return (GenericDefaults(None), None); - } - let resolver = def.resolver(db); - +pub(crate) fn impl_trait_with_diagnostics_query<'db>( + db: &'db dyn HirDatabase, + impl_id: ImplId, +) -> Option<(EarlyBinder<'db, TraitRef<'db>>, Diagnostics)> { + let impl_data = db.impl_signature(impl_id); + let resolver = impl_id.resolver(db); let mut ctx = TyLoweringContext::new( db, &resolver, - generic_params.store(), - def, - LifetimeElisionKind::AnonymousReportError, - ) - .with_impl_trait_mode(ImplTraitLoweringMode::Disallowed) - .with_type_param_mode(ParamLoweringMode::Variable); - let mut idx = 0; - let mut has_any_default = false; - let mut defaults = generic_params - .iter_parents_with_store() - .map(|((id, p), store)| { - ctx.store = store; - let (result, has_default) = handle_generic_param(&mut ctx, idx, id, p, &generic_params); - has_any_default |= has_default; - idx += 1; - result - }) - .collect::>(); - ctx.diagnostics.clear(); // Don't include diagnostics from the parent. - defaults.extend(generic_params.iter_self().map(|(id, p)| { - let (result, has_default) = handle_generic_param(&mut ctx, idx, id, p, &generic_params); - has_any_default |= has_default; - idx += 1; - result - })); - let diagnostics = create_diagnostics(mem::take(&mut ctx.diagnostics)); - let defaults = if has_any_default { - GenericDefaults(Some(Arc::from_iter(defaults))) + &impl_data.store, + impl_id.into(), + LifetimeElisionKind::AnonymousCreateParameter { report_in_path: true }, + ); + let self_ty = db.impl_self_ty(impl_id).skip_binder(); + let target_trait = impl_data.target_trait.as_ref()?; + let trait_ref = EarlyBinder::bind(ctx.lower_trait_ref(target_trait, self_ty)?); + Some((trait_ref, create_diagnostics(ctx.diagnostics))) +} + +pub(crate) fn return_type_impl_traits<'db>( + db: &'db dyn HirDatabase, + def: hir_def::FunctionId, +) -> Option>>> { + // FIXME unify with fn_sig_for_fn instead of doing lowering twice, maybe + let data = db.function_signature(def); + let resolver = def.resolver(db); + let mut ctx_ret = + TyLoweringContext::new(db, &resolver, &data.store, def.into(), LifetimeElisionKind::Infer) + .with_impl_trait_mode(ImplTraitLoweringMode::Opaque); + if let Some(ret_type) = data.ret_type { + let _ret = ctx_ret.lower_ty(ret_type); + } + let return_type_impl_traits = + ImplTraits { impl_traits: ctx_ret.impl_trait_mode.opaque_type_data }; + if return_type_impl_traits.impl_traits.is_empty() { + None } else { - GenericDefaults(None) - }; - return (defaults, diagnostics); - - fn handle_generic_param( - ctx: &mut TyLoweringContext<'_>, - idx: usize, - id: GenericParamId, - p: GenericParamDataRef<'_>, - generic_params: &Generics, - ) -> (Binders, bool) { - let binders = variable_kinds_from_iter(ctx.db, generic_params.iter_id().take(idx)); - match p { - GenericParamDataRef::TypeParamData(p) => { - let ty = p.default.as_ref().map_or_else( - || TyKind::Error.intern(Interner), - |ty| { - // Each default can only refer to previous parameters. - // Type variable default referring to parameter coming - // after it is forbidden (FIXME: report diagnostic) - fallback_bound_vars(ctx.lower_ty(*ty), idx) - }, - ); - (Binders::new(binders, ty.cast(Interner)), p.default.is_some()) - } - GenericParamDataRef::ConstParamData(p) => { - let GenericParamId::ConstParamId(id) = id else { - unreachable!("Unexpected lifetime or type argument") - }; - - let mut val = p.default.as_ref().map_or_else( - || unknown_const_as_generic(ctx.db.const_param_ty(id)), - |c| { - let param_ty = ctx.lower_ty(p.ty); - let c = ctx.lower_const(c, param_ty); - c.cast(Interner) - }, - ); - // Each default can only refer to previous parameters, see above. - val = fallback_bound_vars(val, idx); - (Binders::new(binders, val), p.default.is_some()) - } - GenericParamDataRef::LifetimeParamData(_) => { - (Binders::new(binders, error_lifetime().cast(Interner)), false) - } - } + Some(Arc::new(EarlyBinder::bind(return_type_impl_traits))) } } -pub(crate) fn generic_defaults_with_diagnostics_cycle_result( - _db: &dyn HirDatabase, - _def: GenericDefId, -) -> (GenericDefaults, Diagnostics) { - (GenericDefaults(None), None) +pub(crate) fn type_alias_impl_traits<'db>( + db: &'db dyn HirDatabase, + def: hir_def::TypeAliasId, +) -> Option>>> { + let data = db.type_alias_signature(def); + let resolver = def.resolver(db); + let mut ctx = TyLoweringContext::new( + db, + &resolver, + &data.store, + def.into(), + LifetimeElisionKind::AnonymousReportError, + ) + .with_impl_trait_mode(ImplTraitLoweringMode::Opaque); + if let Some(type_ref) = data.ty { + let _ty = ctx.lower_ty(type_ref); + } + let type_alias_impl_traits = ImplTraits { impl_traits: ctx.impl_trait_mode.opaque_type_data }; + if type_alias_impl_traits.impl_traits.is_empty() { + None + } else { + Some(Arc::new(EarlyBinder::bind(type_alias_impl_traits))) + } } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] @@ -1293,18 +1061,203 @@ impl ValueTyDefId { } } -pub(crate) fn const_param_ty_query(db: &dyn HirDatabase, def: ConstParamId) -> Ty { - const_param_ty_with_diagnostics_query(db, def).0 +/// Build the declared type of an item. This depends on the namespace; e.g. for +/// `struct Foo(usize)`, we have two types: The type of the struct itself, and +/// the constructor function `(usize) -> Foo` which lives in the values +/// namespace. +pub(crate) fn ty_query<'db>(db: &'db dyn HirDatabase, def: TyDefId) -> EarlyBinder<'db, Ty<'db>> { + let interner = DbInterner::new_with(db, None, None); + match def { + TyDefId::BuiltinType(it) => EarlyBinder::bind(Ty::from_builtin_type(interner, it)), + TyDefId::AdtId(it) => EarlyBinder::bind(Ty::new_adt( + interner, + it, + GenericArgs::identity_for_item(interner, it.into()), + )), + TyDefId::TypeAliasId(it) => db.type_for_type_alias_with_diagnostics(it).0, + } +} + +/// Build the declared type of a function. This should not need to look at the +/// function body. +fn type_for_fn<'db>(db: &'db dyn HirDatabase, def: FunctionId) -> EarlyBinder<'db, Ty<'db>> { + let interner = DbInterner::new_with(db, None, None); + EarlyBinder::bind(Ty::new_fn_def( + interner, + CallableDefId::FunctionId(def).into(), + GenericArgs::identity_for_item(interner, def.into()), + )) +} + +/// Build the declared type of a const. +fn type_for_const<'db>(db: &'db dyn HirDatabase, def: ConstId) -> EarlyBinder<'db, Ty<'db>> { + let resolver = def.resolver(db); + let data = db.const_signature(def); + let parent = def.loc(db).container; + let mut ctx = TyLoweringContext::new( + db, + &resolver, + &data.store, + def.into(), + LifetimeElisionKind::AnonymousReportError, + ); + ctx.set_lifetime_elision(LifetimeElisionKind::for_const(ctx.interner, parent)); + EarlyBinder::bind(ctx.lower_ty(data.type_ref)) +} + +/// Build the declared type of a static. +fn type_for_static<'db>(db: &'db dyn HirDatabase, def: StaticId) -> EarlyBinder<'db, Ty<'db>> { + let resolver = def.resolver(db); + let data = db.static_signature(def); + let mut ctx = TyLoweringContext::new( + db, + &resolver, + &data.store, + def.into(), + LifetimeElisionKind::AnonymousReportError, + ); + ctx.set_lifetime_elision(LifetimeElisionKind::Elided(Region::new_static(ctx.interner))); + EarlyBinder::bind(ctx.lower_ty(data.type_ref)) +} + +/// Build the type of a tuple struct constructor. +fn type_for_struct_constructor<'db>( + db: &'db dyn HirDatabase, + def: StructId, +) -> Option>> { + let struct_data = def.fields(db); + match struct_data.shape { + FieldsShape::Record => None, + FieldsShape::Unit => Some(type_for_adt(db, def.into())), + FieldsShape::Tuple => { + let interner = DbInterner::new_with(db, None, None); + Some(EarlyBinder::bind(Ty::new_fn_def( + interner, + CallableDefId::StructId(def).into(), + GenericArgs::identity_for_item(interner, def.into()), + ))) + } + } +} + +/// Build the type of a tuple enum variant constructor. +fn type_for_enum_variant_constructor<'db>( + db: &'db dyn HirDatabase, + def: EnumVariantId, +) -> Option>> { + let struct_data = def.fields(db); + match struct_data.shape { + FieldsShape::Record => None, + FieldsShape::Unit => Some(type_for_adt(db, def.loc(db).parent.into())), + FieldsShape::Tuple => { + let interner = DbInterner::new_with(db, None, None); + Some(EarlyBinder::bind(Ty::new_fn_def( + interner, + CallableDefId::EnumVariantId(def).into(), + GenericArgs::identity_for_item(interner, def.loc(db).parent.into()), + ))) + } + } +} + +pub(crate) fn value_ty_query<'db>( + db: &'db dyn HirDatabase, + def: ValueTyDefId, +) -> Option>> { + match def { + ValueTyDefId::FunctionId(it) => Some(type_for_fn(db, it)), + ValueTyDefId::StructId(it) => type_for_struct_constructor(db, it), + ValueTyDefId::UnionId(it) => Some(type_for_adt(db, it.into())), + ValueTyDefId::EnumVariantId(it) => type_for_enum_variant_constructor(db, it), + ValueTyDefId::ConstId(it) => Some(type_for_const(db, it)), + ValueTyDefId::StaticId(it) => Some(type_for_static(db, it)), + } +} + +pub(crate) fn type_for_type_alias_with_diagnostics_query<'db>( + db: &'db dyn HirDatabase, + t: TypeAliasId, +) -> (EarlyBinder<'db, Ty<'db>>, Diagnostics) { + let type_alias_data = db.type_alias_signature(t); + let mut diags = None; + let resolver = t.resolver(db); + let interner = DbInterner::new_with(db, Some(resolver.krate()), None); + let inner = if type_alias_data.flags.contains(TypeAliasFlags::IS_EXTERN) { + EarlyBinder::bind(Ty::new_foreign(interner, t.into())) + } else { + let mut ctx = TyLoweringContext::new( + db, + &resolver, + &type_alias_data.store, + t.into(), + LifetimeElisionKind::AnonymousReportError, + ) + .with_impl_trait_mode(ImplTraitLoweringMode::Opaque); + let res = EarlyBinder::bind( + type_alias_data + .ty + .map(|type_ref| ctx.lower_ty(type_ref)) + .unwrap_or_else(|| Ty::new_error(interner, ErrorGuaranteed)), + ); + diags = create_diagnostics(ctx.diagnostics); + res + }; + (inner, diags) +} + +pub(crate) fn type_for_type_alias_with_diagnostics_cycle_result<'db>( + db: &'db dyn HirDatabase, + _adt: TypeAliasId, +) -> (EarlyBinder<'db, Ty<'db>>, Diagnostics) { + (EarlyBinder::bind(Ty::new_error(DbInterner::new_with(db, None, None), ErrorGuaranteed)), None) +} + +pub(crate) fn impl_self_ty_query<'db>( + db: &'db dyn HirDatabase, + impl_id: ImplId, +) -> EarlyBinder<'db, Ty<'db>> { + db.impl_self_ty_with_diagnostics(impl_id).0 +} + +pub(crate) fn impl_self_ty_with_diagnostics_query<'db>( + db: &'db dyn HirDatabase, + impl_id: ImplId, +) -> (EarlyBinder<'db, Ty<'db>>, Diagnostics) { + let resolver = impl_id.resolver(db); + + let impl_data = db.impl_signature(impl_id); + let mut ctx = TyLoweringContext::new( + db, + &resolver, + &impl_data.store, + impl_id.into(), + LifetimeElisionKind::AnonymousCreateParameter { report_in_path: true }, + ); + let ty = ctx.lower_ty(impl_data.self_ty); + assert!(!ty.has_escaping_bound_vars()); + (EarlyBinder::bind(ty), create_diagnostics(ctx.diagnostics)) +} + +pub(crate) fn impl_self_ty_with_diagnostics_cycle_result( + db: &dyn HirDatabase, + _impl_id: ImplId, +) -> (EarlyBinder<'_, Ty<'_>>, Diagnostics) { + (EarlyBinder::bind(Ty::new_error(DbInterner::new_with(db, None, None), ErrorGuaranteed)), None) +} + +pub(crate) fn const_param_ty_query<'db>(db: &'db dyn HirDatabase, def: ConstParamId) -> Ty<'db> { + db.const_param_ty_with_diagnostics(def).0 } // returns None if def is a type arg -pub(crate) fn const_param_ty_with_diagnostics_query( - db: &dyn HirDatabase, +pub(crate) fn const_param_ty_with_diagnostics_query<'db>( + db: &'db dyn HirDatabase, def: ConstParamId, -) -> (Ty, Diagnostics) { +) -> (Ty<'db>, Diagnostics) { let (parent_data, store) = db.generic_params_and_store(def.parent()); let data = &parent_data[def.local_id()]; let resolver = def.parent().resolver(db); + let interner = DbInterner::new_with(db, Some(resolver.krate()), None); let mut ctx = TyLoweringContext::new( db, &resolver, @@ -1315,103 +1268,912 @@ pub(crate) fn const_param_ty_with_diagnostics_query( let ty = match data { TypeOrConstParamData::TypeParamData(_) => { never!(); - Ty::new(Interner, TyKind::Error) + Ty::new_error(interner, ErrorGuaranteed) } TypeOrConstParamData::ConstParamData(d) => ctx.lower_ty(d.ty), }; (ty, create_diagnostics(ctx.diagnostics)) } -pub(crate) fn const_param_ty_cycle_result( - _: &dyn HirDatabase, +pub(crate) fn const_param_ty_with_diagnostics_cycle_result<'db>( + db: &'db dyn HirDatabase, _: crate::db::HirDatabaseData, - _: ConstParamId, -) -> Ty { - TyKind::Error.intern(Interner) + def: ConstParamId, +) -> (Ty<'db>, Diagnostics) { + let resolver = def.parent().resolver(db); + let interner = DbInterner::new_with(db, Some(resolver.krate()), None); + (Ty::new_error(interner, ErrorGuaranteed), None) } -pub(crate) fn return_type_impl_traits( - db: &dyn HirDatabase, - def: hir_def::FunctionId, -) -> Option>> { - // FIXME unify with fn_sig_for_fn instead of doing lowering twice, maybe - let data = db.function_signature(def); - let resolver = def.resolver(db); - let mut ctx_ret = - TyLoweringContext::new(db, &resolver, &data.store, def.into(), LifetimeElisionKind::Infer) - .with_impl_trait_mode(ImplTraitLoweringMode::Opaque) - .with_type_param_mode(ParamLoweringMode::Variable); - if let Some(ret_type) = data.ret_type { - let _ret = ctx_ret.lower_ty(ret_type); - } - let generics = generics(db, def.into()); - let return_type_impl_traits = - ImplTraits { impl_traits: ctx_ret.impl_trait_mode.opaque_type_data }; - if return_type_impl_traits.impl_traits.is_empty() { - None - } else { - Some(Arc::new(make_binders(db, &generics, return_type_impl_traits))) - } +pub(crate) fn field_types_query<'db>( + db: &'db dyn HirDatabase, + variant_id: VariantId, +) -> Arc>>> { + db.field_types_with_diagnostics(variant_id).0 } -pub(crate) fn type_alias_impl_traits( - db: &dyn HirDatabase, - def: hir_def::TypeAliasId, -) -> Option>> { - let data = db.type_alias_signature(def); +/// Build the type of all specific fields of a struct or enum variant. +pub(crate) fn field_types_with_diagnostics_query<'db>( + db: &'db dyn HirDatabase, + variant_id: VariantId, +) -> (Arc>>>, Diagnostics) { + let var_data = variant_id.fields(db); + let fields = var_data.fields(); + if fields.is_empty() { + return (Arc::new(ArenaMap::default()), None); + } + + let (resolver, def): (_, GenericDefId) = match variant_id { + VariantId::StructId(it) => (it.resolver(db), it.into()), + VariantId::UnionId(it) => (it.resolver(db), it.into()), + VariantId::EnumVariantId(it) => (it.resolver(db), it.lookup(db).parent.into()), + }; + let mut res = ArenaMap::default(); + let mut ctx = TyLoweringContext::new( + db, + &resolver, + &var_data.store, + def, + LifetimeElisionKind::AnonymousReportError, + ); + for (field_id, field_data) in var_data.fields().iter() { + res.insert(field_id, EarlyBinder::bind(ctx.lower_ty(field_data.type_ref))); + } + (Arc::new(res), create_diagnostics(ctx.diagnostics)) +} + +/// This query exists only to be used when resolving short-hand associated types +/// like `T::Item`. +/// +/// See the analogous query in rustc and its comment: +/// +/// This is a query mostly to handle cycles somewhat gracefully; e.g. the +/// following bounds are disallowed: `T: Foo, U: Foo`, but +/// these are fine: `T: Foo, U: Foo<()>`. +#[tracing::instrument(skip(db), ret)] +pub(crate) fn generic_predicates_for_param_query<'db>( + db: &'db dyn HirDatabase, + def: GenericDefId, + param_id: TypeOrConstParamId, + assoc_name: Option, +) -> GenericPredicates<'db> { + let generics = generics(db, def); + let interner = DbInterner::new_with(db, None, None); let resolver = def.resolver(db); let mut ctx = TyLoweringContext::new( db, &resolver, - &data.store, - def.into(), + generics.store(), + def, + LifetimeElisionKind::AnonymousReportError, + ); + + // we have to filter out all other predicates *first*, before attempting to lower them + let predicate = |pred: &_, ctx: &mut TyLoweringContext<'_, '_>| match pred { + WherePredicate::ForLifetime { target, bound, .. } + | WherePredicate::TypeBound { target, bound, .. } => { + let invalid_target = { ctx.lower_ty_only_param(*target) != Some(param_id) }; + if invalid_target { + // FIXME(sized-hierarchy): Revisit and adjust this properly once we have implemented + // sized-hierarchy correctly. + // If this is filtered out without lowering, `?Sized` or `PointeeSized` is not gathered into + // `ctx.unsized_types` + let lower = || -> bool { + match bound { + TypeBound::Path(_, TraitBoundModifier::Maybe) => true, + TypeBound::Path(path, _) | TypeBound::ForLifetime(_, path) => { + let TypeRef::Path(path) = &ctx.store[path.type_ref()] else { + return false; + }; + let Some(pointee_sized) = + LangItem::PointeeSized.resolve_trait(ctx.db, ctx.resolver.krate()) + else { + return false; + }; + // Lower the path directly with `Resolver` instead of PathLoweringContext` + // to prevent diagnostics duplications. + ctx.resolver.resolve_path_in_type_ns_fully(ctx.db, path).is_some_and( + |it| matches!(it, TypeNs::TraitId(tr) if tr == pointee_sized), + ) + } + _ => false, + } + }(); + if lower { + ctx.lower_where_predicate(pred, true, &generics, PredicateFilter::All) + .for_each(drop); + } + return false; + } + + match bound { + &TypeBound::ForLifetime(_, path) | &TypeBound::Path(path, _) => { + // Only lower the bound if the trait could possibly define the associated + // type we're looking for. + let path = &ctx.store[path]; + + let Some(assoc_name) = &assoc_name else { return true }; + let Some(TypeNs::TraitId(tr)) = + resolver.resolve_path_in_type_ns_fully(db, path) + else { + return false; + }; + + rustc_type_ir::elaborate::supertrait_def_ids(interner, tr.into()).any(|tr| { + tr.0.trait_items(db).items.iter().any(|(name, item)| { + matches!(item, AssocItemId::TypeAliasId(_)) && name == assoc_name + }) + }) + } + TypeBound::Use(_) | TypeBound::Lifetime(_) | TypeBound::Error => false, + } + } + WherePredicate::Lifetime { .. } => false, + }; + let mut predicates = Vec::new(); + for maybe_parent_generics in + std::iter::successors(Some(&generics), |generics| generics.parent_generics()) + { + ctx.store = maybe_parent_generics.store(); + for pred in maybe_parent_generics.where_predicates() { + if predicate(pred, &mut ctx) { + predicates.extend(ctx.lower_where_predicate( + pred, + true, + maybe_parent_generics, + PredicateFilter::All, + )); + } + } + } + + let args = GenericArgs::identity_for_item(interner, def.into()); + if !args.is_empty() { + let explicitly_unsized_tys = ctx.unsized_types; + if let Some(implicitly_sized_predicates) = + implicitly_sized_clauses(db, param_id.parent, &explicitly_unsized_tys, &args, &resolver) + { + predicates.extend(implicitly_sized_predicates); + }; + } + GenericPredicates(predicates.is_empty().not().then(|| predicates.into())) +} + +pub(crate) fn generic_predicates_for_param_cycle_result( + _db: &dyn HirDatabase, + _def: GenericDefId, + _param_id: TypeOrConstParamId, + _assoc_name: Option, +) -> GenericPredicates<'_> { + GenericPredicates(None) +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct GenericPredicates<'db>(Option]>>); + +impl<'db> GenericPredicates<'db> { + #[inline] + pub fn instantiate( + &self, + interner: DbInterner<'db>, + args: GenericArgs<'db>, + ) -> Option>> { + self.0 + .as_ref() + .map(|it| EarlyBinder::bind(it.iter().copied()).iter_instantiated(interner, args)) + } + + #[inline] + pub fn instantiate_identity(&self) -> Option>> { + self.0.as_ref().map(|it| it.iter().copied()) + } +} + +impl<'db> ops::Deref for GenericPredicates<'db> { + type Target = [Clause<'db>]; + + fn deref(&self) -> &Self::Target { + self.0.as_deref().unwrap_or(&[]) + } +} + +pub(crate) fn trait_environment_for_body_query( + db: &dyn HirDatabase, + def: DefWithBodyId, +) -> Arc> { + let Some(def) = def.as_generic_def_id(db) else { + let krate = def.module(db).krate(); + return TraitEnvironment::empty(krate); + }; + db.trait_environment(def) +} + +pub(crate) fn trait_environment_query<'db>( + db: &'db dyn HirDatabase, + def: GenericDefId, +) -> Arc> { + let generics = generics(db, def); + if generics.has_no_predicates() && generics.is_empty() { + return TraitEnvironment::empty(def.krate(db)); + } + + let resolver = def.resolver(db); + let mut ctx = TyLoweringContext::new( + db, + &resolver, + generics.store(), + def, + LifetimeElisionKind::AnonymousReportError, + ); + let mut traits_in_scope = Vec::new(); + let mut clauses = Vec::new(); + for maybe_parent_generics in + std::iter::successors(Some(&generics), |generics| generics.parent_generics()) + { + ctx.store = maybe_parent_generics.store(); + for pred in maybe_parent_generics.where_predicates() { + for pred in ctx.lower_where_predicate(pred, false, &generics, PredicateFilter::All) { + if let rustc_type_ir::ClauseKind::Trait(tr) = pred.kind().skip_binder() { + traits_in_scope.push((tr.self_ty(), tr.def_id().0)); + } + clauses.push(pred); + } + } + } + + if let Some(trait_id) = def.assoc_trait_container(db) { + // add `Self: Trait` to the environment in trait + // function default implementations (and speculative code + // inside consts or type aliases) + cov_mark::hit!(trait_self_implements_self); + let trait_ref = TraitRef::identity(ctx.interner, trait_id.into()); + let clause = Clause(Predicate::new( + ctx.interner, + Binder::dummy(rustc_type_ir::PredicateKind::Clause(rustc_type_ir::ClauseKind::Trait( + TraitPredicate { trait_ref, polarity: rustc_type_ir::PredicatePolarity::Positive }, + ))), + )); + clauses.push(clause); + } + + let explicitly_unsized_tys = ctx.unsized_types; + + let sized_trait = LangItem::Sized.resolve_trait(db, resolver.krate()); + if let Some(sized_trait) = sized_trait { + let (mut generics, mut def_id) = + (crate::next_solver::generics::generics(db, def.into()), def); + loop { + let self_idx = trait_self_param_idx(db, def_id); + for (idx, p) in generics.own_params.iter().enumerate() { + if let Some(self_idx) = self_idx + && p.index() as usize == self_idx + { + continue; + } + let GenericParamId::TypeParamId(param_id) = p.id else { + continue; + }; + let idx = idx as u32 + generics.parent_count as u32; + let param_ty = Ty::new_param(ctx.interner, param_id, idx); + if explicitly_unsized_tys.contains(¶m_ty) { + continue; + } + let trait_ref = TraitRef::new_from_args( + ctx.interner, + sized_trait.into(), + GenericArgs::new_from_iter(ctx.interner, [param_ty.into()]), + ); + let clause = Clause(Predicate::new( + ctx.interner, + Binder::dummy(rustc_type_ir::PredicateKind::Clause( + rustc_type_ir::ClauseKind::Trait(TraitPredicate { + trait_ref, + polarity: rustc_type_ir::PredicatePolarity::Positive, + }), + )), + )); + clauses.push(clause); + } + + if let Some(g) = generics.parent { + generics = crate::next_solver::generics::generics(db, g.into()); + def_id = g; + } else { + break; + } + } + } + + let clauses = rustc_type_ir::elaborate::elaborate(ctx.interner, clauses); + let clauses = Clauses::new_from_iter(ctx.interner, clauses); + let env = ParamEnv { clauses }; + + TraitEnvironment::new(resolver.krate(), None, traits_in_scope.into_boxed_slice(), env) +} + +#[derive(Copy, Clone, Debug)] +pub(crate) enum PredicateFilter { + SelfTrait, + All, +} + +/// Resolve the where clause(s) of an item with generics. +#[tracing::instrument(skip(db))] +pub(crate) fn generic_predicates_query<'db>( + db: &'db dyn HirDatabase, + def: GenericDefId, +) -> GenericPredicates<'db> { + generic_predicates_filtered_by(db, def, PredicateFilter::All, |_| true).0 +} + +pub(crate) fn generic_predicates_without_parent_query<'db>( + db: &'db dyn HirDatabase, + def: GenericDefId, +) -> GenericPredicates<'db> { + generic_predicates_filtered_by(db, def, PredicateFilter::All, |d| d == def).0 +} + +/// Resolve the where clause(s) of an item with generics, +/// except the ones inherited from the parent +pub(crate) fn generic_predicates_without_parent_with_diagnostics_query<'db>( + db: &'db dyn HirDatabase, + def: GenericDefId, +) -> (GenericPredicates<'db>, Diagnostics) { + generic_predicates_filtered_by(db, def, PredicateFilter::All, |d| d == def) +} + +/// Resolve the where clause(s) of an item with generics, +/// with a given filter +#[tracing::instrument(skip(db, filter), ret)] +pub(crate) fn generic_predicates_filtered_by<'db, F>( + db: &'db dyn HirDatabase, + def: GenericDefId, + predicate_filter: PredicateFilter, + filter: F, +) -> (GenericPredicates<'db>, Diagnostics) +where + F: Fn(GenericDefId) -> bool, +{ + let generics = generics(db, def); + let resolver = def.resolver(db); + let interner = DbInterner::new_with(db, Some(resolver.krate()), None); + let mut ctx = TyLoweringContext::new( + db, + &resolver, + generics.store(), + def, + LifetimeElisionKind::AnonymousReportError, + ); + + let mut predicates = Vec::new(); + for maybe_parent_generics in + std::iter::successors(Some(&generics), |generics| generics.parent_generics()) + { + ctx.store = maybe_parent_generics.store(); + for pred in maybe_parent_generics.where_predicates() { + tracing::debug!(?pred); + if filter(maybe_parent_generics.def()) { + predicates.extend(ctx.lower_where_predicate( + pred, + false, + maybe_parent_generics, + predicate_filter, + )); + } + } + } + + let explicitly_unsized_tys = ctx.unsized_types; + + let sized_trait = LangItem::Sized.resolve_trait(db, resolver.krate()); + if let Some(sized_trait) = sized_trait { + let mut add_sized_clause = |param_idx, param_id, param_data| { + let ( + GenericParamId::TypeParamId(param_id), + GenericParamDataRef::TypeParamData(param_data), + ) = (param_id, param_data) + else { + return; + }; + + if param_data.provenance == TypeParamProvenance::TraitSelf { + return; + } + + let param_ty = Ty::new_param(interner, param_id, param_idx); + if explicitly_unsized_tys.contains(¶m_ty) { + return; + } + let trait_ref = TraitRef::new_from_args( + interner, + sized_trait.into(), + GenericArgs::new_from_iter(interner, [param_ty.into()]), + ); + let clause = Clause(Predicate::new( + interner, + Binder::dummy(rustc_type_ir::PredicateKind::Clause( + rustc_type_ir::ClauseKind::Trait(TraitPredicate { + trait_ref, + polarity: rustc_type_ir::PredicatePolarity::Positive, + }), + )), + )); + predicates.push(clause); + }; + if generics.parent_generics().is_some_and(|parent| filter(parent.def())) { + generics.iter_parent().enumerate().for_each(|(param_idx, (param_id, param_data))| { + add_sized_clause(param_idx as u32, param_id, param_data); + }); + } + if filter(def) { + let parent_params_len = generics.len_parent(); + generics.iter_self().enumerate().for_each(|(param_idx, (param_id, param_data))| { + add_sized_clause((param_idx + parent_params_len) as u32, param_id, param_data); + }); + } + } + + // FIXME: rustc gathers more predicates by recursing through resulting trait predicates. + // See https://github.com/rust-lang/rust/blob/76c5ed2847cdb26ef2822a3a165d710f6b772217/compiler/rustc_hir_analysis/src/collect/predicates_of.rs#L689-L715 + + ( + GenericPredicates(predicates.is_empty().not().then(|| predicates.into())), + create_diagnostics(ctx.diagnostics), + ) +} + +/// Generate implicit `: Sized` predicates for all generics that has no `?Sized` bound. +/// Exception is Self of a trait def. +fn implicitly_sized_clauses<'a, 'subst, 'db>( + db: &'db dyn HirDatabase, + def: GenericDefId, + explicitly_unsized_tys: &'a FxHashSet>, + args: &'subst GenericArgs<'db>, + resolver: &Resolver<'db>, +) -> Option> + Captures<'a> + Captures<'subst>> { + let interner = DbInterner::new_with(db, Some(resolver.krate()), None); + let sized_trait = LangItem::Sized.resolve_trait(db, resolver.krate())?; + + let trait_self_idx = trait_self_param_idx(db, def); + + Some( + args.iter() + .enumerate() + .filter_map( + move |(idx, generic_arg)| { + if Some(idx) == trait_self_idx { None } else { Some(generic_arg) } + }, + ) + .filter_map(|generic_arg| generic_arg.as_type()) + .filter(move |self_ty| !explicitly_unsized_tys.contains(self_ty)) + .map(move |self_ty| { + let trait_ref = TraitRef::new_from_args( + interner, + sized_trait.into(), + GenericArgs::new_from_iter(interner, [self_ty.into()]), + ); + Clause(Predicate::new( + interner, + Binder::dummy(rustc_type_ir::PredicateKind::Clause( + rustc_type_ir::ClauseKind::Trait(TraitPredicate { + trait_ref, + polarity: rustc_type_ir::PredicatePolarity::Positive, + }), + )), + )) + }), + ) +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct GenericDefaults<'db>(Option>>]>>); + +impl<'db> GenericDefaults<'db> { + #[inline] + pub fn get(&self, idx: usize) -> Option>> { + self.0.as_ref()?[idx] + } +} + +pub(crate) fn generic_defaults_query( + db: &dyn HirDatabase, + def: GenericDefId, +) -> GenericDefaults<'_> { + db.generic_defaults_with_diagnostics(def).0 +} + +/// Resolve the default type params from generics. +/// +/// Diagnostics are only returned for this `GenericDefId` (returned defaults include parents). +pub(crate) fn generic_defaults_with_diagnostics_query( + db: &dyn HirDatabase, + def: GenericDefId, +) -> (GenericDefaults<'_>, Diagnostics) { + let generic_params = generics(db, def); + if generic_params.is_empty() { + return (GenericDefaults(None), None); + } + let resolver = def.resolver(db); + + let mut ctx = TyLoweringContext::new( + db, + &resolver, + generic_params.store(), + def, LifetimeElisionKind::AnonymousReportError, ) - .with_impl_trait_mode(ImplTraitLoweringMode::Opaque) - .with_type_param_mode(ParamLoweringMode::Variable); - if let Some(type_ref) = data.ty { - let _ty = ctx.lower_ty(type_ref); - } - let type_alias_impl_traits = ImplTraits { impl_traits: ctx.impl_trait_mode.opaque_type_data }; - if type_alias_impl_traits.impl_traits.is_empty() { - None + .with_impl_trait_mode(ImplTraitLoweringMode::Disallowed); + let mut idx = 0; + let mut has_any_default = false; + let mut defaults = generic_params + .iter_parents_with_store() + .map(|((_id, p), store)| { + ctx.store = store; + let (result, has_default) = handle_generic_param(&mut ctx, idx, p); + has_any_default |= has_default; + idx += 1; + result + }) + .collect::>(); + ctx.diagnostics.clear(); // Don't include diagnostics from the parent. + defaults.extend(generic_params.iter_self().map(|(_id, p)| { + let (result, has_default) = handle_generic_param(&mut ctx, idx, p); + has_any_default |= has_default; + idx += 1; + result + })); + let diagnostics = create_diagnostics(mem::take(&mut ctx.diagnostics)); + let defaults = if has_any_default { + GenericDefaults(Some(Arc::from_iter(defaults))) } else { - let generics = generics(db, def.into()); - Some(Arc::new(make_binders(db, &generics, type_alias_impl_traits))) + GenericDefaults(None) + }; + return (defaults, diagnostics); + + fn handle_generic_param<'db>( + ctx: &mut TyLoweringContext<'db, '_>, + idx: usize, + p: GenericParamDataRef<'_>, + ) -> (Option>>, bool) { + ctx.lowering_param_default(idx as u32); + match p { + GenericParamDataRef::TypeParamData(p) => { + let ty = p.default.map(|ty| ctx.lower_ty(ty)); + (ty.map(|ty| EarlyBinder::bind(ty.into())), p.default.is_some()) + } + GenericParamDataRef::ConstParamData(p) => { + let val = p.default.map(|c| { + let param_ty = ctx.lower_ty(p.ty); + let c = ctx.lower_const(c, param_ty); + c.into() + }); + (val.map(EarlyBinder::bind), p.default.is_some()) + } + GenericParamDataRef::LifetimeParamData(_) => (None, false), + } } } -pub(crate) fn lower_to_chalk_mutability(m: hir_def::type_ref::Mutability) -> Mutability { - match m { - hir_def::type_ref::Mutability::Shared => Mutability::Not, - hir_def::type_ref::Mutability::Mut => Mutability::Mut, +pub(crate) fn generic_defaults_with_diagnostics_cycle_result( + _db: &dyn HirDatabase, + _def: GenericDefId, +) -> (GenericDefaults<'_>, Diagnostics) { + (GenericDefaults(None), None) +} + +/// Build the signature of a callable item (function, struct or enum variant). +pub(crate) fn callable_item_signature_query<'db>( + db: &'db dyn HirDatabase, + def: CallableDefId, +) -> EarlyBinder<'db, PolyFnSig<'db>> { + match def { + CallableDefId::FunctionId(f) => fn_sig_for_fn(db, f), + CallableDefId::StructId(s) => fn_sig_for_struct_constructor(db, s), + CallableDefId::EnumVariantId(e) => fn_sig_for_enum_variant_constructor(db, e), } } -/// Replaces any 'free' `BoundVar`s in `s` by `TyKind::Error` from the perspective of generic -/// parameter whose index is `param_index`. A `BoundVar` is free when it appears after the -/// generic parameter of `param_index`. -fn fallback_bound_vars + HasInterner>( - s: T, - param_index: usize, -) -> T { - let is_allowed = |index| (0..param_index).contains(&index); +fn fn_sig_for_fn<'db>( + db: &'db dyn HirDatabase, + def: FunctionId, +) -> EarlyBinder<'db, PolyFnSig<'db>> { + let data = db.function_signature(def); + let resolver = def.resolver(db); + let interner = DbInterner::new_with(db, Some(resolver.krate()), None); + let mut ctx_params = TyLoweringContext::new( + db, + &resolver, + &data.store, + def.into(), + LifetimeElisionKind::for_fn_params(&data), + ); + let params = data.params.iter().map(|&tr| ctx_params.lower_ty(tr)); - crate::fold_free_vars( - s, - |bound, binders| { - if bound.index_if_innermost().is_none_or(is_allowed) { - bound.shifted_in_from(binders).to_ty(Interner) - } else { - TyKind::Error.intern(Interner) - } - }, - |ty, bound, binders| { - if bound.index_if_innermost().is_none_or(is_allowed) { - bound.shifted_in_from(binders).to_const(Interner, ty) - } else { - unknown_const(ty) - } - }, - ) + let ret = match data.ret_type { + Some(ret_type) => { + let mut ctx_ret = TyLoweringContext::new( + db, + &resolver, + &data.store, + def.into(), + LifetimeElisionKind::for_fn_ret(interner), + ) + .with_impl_trait_mode(ImplTraitLoweringMode::Opaque); + ctx_ret.lower_ty(ret_type) + } + None => Ty::new_tup(interner, &[]), + }; + + let inputs_and_output = Tys::new_from_iter(interner, params.chain(Some(ret))); + // If/when we track late bound vars, we need to switch this to not be `dummy` + EarlyBinder::bind(rustc_type_ir::Binder::dummy(FnSig { + abi: data.abi.as_ref().map_or(FnAbi::Rust, FnAbi::from_symbol), + c_variadic: data.is_varargs(), + safety: if data.is_unsafe() { Safety::Unsafe } else { Safety::Safe }, + inputs_and_output, + })) +} + +fn type_for_adt<'db>(db: &'db dyn HirDatabase, adt: AdtId) -> EarlyBinder<'db, Ty<'db>> { + let interner = DbInterner::new_with(db, None, None); + let args = GenericArgs::identity_for_item(interner, adt.into()); + let ty = Ty::new_adt(interner, adt, args); + EarlyBinder::bind(ty) +} + +fn fn_sig_for_struct_constructor<'db>( + db: &'db dyn HirDatabase, + def: StructId, +) -> EarlyBinder<'db, PolyFnSig<'db>> { + let field_tys = db.field_types(def.into()); + let params = field_tys.iter().map(|(_, ty)| ty.skip_binder()); + let ret = type_for_adt(db, def.into()).skip_binder(); + + let inputs_and_output = + Tys::new_from_iter(DbInterner::new_with(db, None, None), params.chain(Some(ret))); + EarlyBinder::bind(Binder::dummy(FnSig { + abi: FnAbi::RustCall, + c_variadic: false, + safety: Safety::Safe, + inputs_and_output, + })) +} + +fn fn_sig_for_enum_variant_constructor<'db>( + db: &'db dyn HirDatabase, + def: EnumVariantId, +) -> EarlyBinder<'db, PolyFnSig<'db>> { + let field_tys = db.field_types(def.into()); + let params = field_tys.iter().map(|(_, ty)| ty.skip_binder()); + let parent = def.lookup(db).parent; + let ret = type_for_adt(db, parent.into()).skip_binder(); + + let inputs_and_output = + Tys::new_from_iter(DbInterner::new_with(db, None, None), params.chain(Some(ret))); + EarlyBinder::bind(Binder::dummy(FnSig { + abi: FnAbi::RustCall, + c_variadic: false, + safety: Safety::Safe, + inputs_and_output, + })) +} + +// FIXME(next-solver): should merge this with `explicit_item_bounds` in some way +pub(crate) fn associated_ty_item_bounds<'db>( + db: &'db dyn HirDatabase, + type_alias: TypeAliasId, +) -> EarlyBinder<'db, BoundExistentialPredicates<'db>> { + let type_alias_data = db.type_alias_signature(type_alias); + let resolver = hir_def::resolver::HasResolver::resolver(type_alias, db); + let interner = DbInterner::new_with(db, Some(resolver.krate()), None); + let mut ctx = TyLoweringContext::new( + db, + &resolver, + &type_alias_data.store, + type_alias.into(), + LifetimeElisionKind::AnonymousReportError, + ); + // FIXME: we should never create non-existential predicates in the first place + // For now, use an error type so we don't run into dummy binder issues + let self_ty = Ty::new_error(interner, ErrorGuaranteed); + + let mut bounds = Vec::new(); + for bound in &type_alias_data.bounds { + ctx.lower_type_bound(bound, self_ty, false).for_each(|pred| { + if let Some(bound) = pred + .kind() + .map_bound(|c| match c { + rustc_type_ir::ClauseKind::Trait(t) => { + let id = t.def_id(); + let is_auto = db.trait_signature(id.0).flags.contains(TraitFlags::AUTO); + if is_auto { + Some(ExistentialPredicate::AutoTrait(t.def_id())) + } else { + Some(ExistentialPredicate::Trait(ExistentialTraitRef::new_from_args( + interner, + t.def_id(), + GenericArgs::new_from_iter( + interner, + t.trait_ref.args.iter().skip(1), + ), + ))) + } + } + rustc_type_ir::ClauseKind::Projection(p) => Some( + ExistentialPredicate::Projection(ExistentialProjection::new_from_args( + interner, + p.def_id(), + GenericArgs::new_from_iter( + interner, + p.projection_term.args.iter().skip(1), + ), + p.term, + )), + ), + rustc_type_ir::ClauseKind::TypeOutlives(_) => None, + rustc_type_ir::ClauseKind::RegionOutlives(_) + | rustc_type_ir::ClauseKind::ConstArgHasType(_, _) + | rustc_type_ir::ClauseKind::WellFormed(_) + | rustc_type_ir::ClauseKind::ConstEvaluatable(_) + | rustc_type_ir::ClauseKind::HostEffect(_) + | rustc_type_ir::ClauseKind::UnstableFeature(_) => unreachable!(), + }) + .transpose() + { + bounds.push(bound); + } + }); + } + + if !ctx.unsized_types.contains(&self_ty) + && let Some(sized_trait) = LangItem::Sized.resolve_trait(db, resolver.krate()) + { + let sized_clause = Binder::dummy(ExistentialPredicate::Trait(ExistentialTraitRef::new( + interner, + sized_trait.into(), + [] as [GenericArg<'_>; 0], + ))); + bounds.push(sized_clause); + } + + EarlyBinder::bind(BoundExistentialPredicates::new_from_iter(interner, bounds)) +} + +pub(crate) fn associated_type_by_name_including_super_traits<'db>( + db: &'db dyn HirDatabase, + trait_ref: TraitRef<'db>, + name: &Name, +) -> Option<(TraitRef<'db>, TypeAliasId)> { + let interner = DbInterner::new_with(db, None, None); + rustc_type_ir::elaborate::supertraits(interner, Binder::dummy(trait_ref)).find_map(|t| { + let trait_id = t.as_ref().skip_binder().def_id.0; + let assoc_type = trait_id.trait_items(db).associated_type_by_name(name)?; + Some((t.skip_binder(), assoc_type)) + }) +} + +pub fn associated_type_shorthand_candidates( + db: &dyn HirDatabase, + def: GenericDefId, + res: TypeNs, + mut cb: impl FnMut(&Name, TypeAliasId) -> bool, +) -> Option { + let interner = DbInterner::new_with(db, None, None); + named_associated_type_shorthand_candidates(interner, def, res, None, |name, _, id| { + cb(name, id).then_some(id) + }) +} + +#[tracing::instrument(skip(interner, check_alias))] +fn named_associated_type_shorthand_candidates<'db, R>( + interner: DbInterner<'db>, + // If the type parameter is defined in an impl and we're in a method, there + // might be additional where clauses to consider + def: GenericDefId, + res: TypeNs, + assoc_name: Option, + mut check_alias: impl FnMut(&Name, TraitRef<'db>, TypeAliasId) -> Option, +) -> Option { + let db = interner.db; + let mut search = |t: TraitRef<'db>| -> Option { + let mut checked_traits = FxHashSet::default(); + let mut check_trait = |trait_ref: TraitRef<'db>| { + let trait_id = trait_ref.def_id.0; + let name = &db.trait_signature(trait_id).name; + tracing::debug!(?trait_id, ?name); + if !checked_traits.insert(trait_id) { + return None; + } + let data = trait_id.trait_items(db); + + tracing::debug!(?data.items); + for (name, assoc_id) in &data.items { + if let &AssocItemId::TypeAliasId(alias) = assoc_id + && let Some(ty) = check_alias(name, trait_ref, alias) + { + return Some(ty); + } + } + None + }; + let mut stack: SmallVec<[_; 4]> = smallvec![t]; + while let Some(trait_ref) = stack.pop() { + if let Some(alias) = check_trait(trait_ref) { + return Some(alias); + } + for pred in generic_predicates_filtered_by( + db, + GenericDefId::TraitId(trait_ref.def_id.0), + PredicateFilter::SelfTrait, + // We are likely in the midst of lowering generic predicates of `def`. + // So, if we allow `pred == def` we might fall into an infinite recursion. + // Actually, we have already checked for the case `pred == def` above as we started + // with a stack including `trait_id` + |pred| pred != def && pred == GenericDefId::TraitId(trait_ref.def_id.0), + ) + .0 + .deref() + { + tracing::debug!(?pred); + let sup_trait_ref = match pred.kind().skip_binder() { + rustc_type_ir::ClauseKind::Trait(pred) => pred.trait_ref, + _ => continue, + }; + let sup_trait_ref = + EarlyBinder::bind(sup_trait_ref).instantiate(interner, trait_ref.args); + stack.push(sup_trait_ref); + } + tracing::debug!(?stack); + } + + None + }; + + match res { + TypeNs::SelfType(impl_id) => { + let trait_ref = db.impl_trait(impl_id)?; + + // FIXME(next-solver): same method in `lower` checks for impl or not + // Is that needed here? + + // we're _in_ the impl -- the binders get added back later. Correct, + // but it would be nice to make this more explicit + search(trait_ref.skip_binder()) + } + TypeNs::GenericParam(param_id) => { + // Handle `Self::Type` referring to own associated type in trait definitions + // This *must* be done first to avoid cycles with + // `generic_predicates_for_param`, but not sure that it's sufficient, + if let GenericDefId::TraitId(trait_id) = param_id.parent() { + let trait_name = &db.trait_signature(trait_id).name; + tracing::debug!(?trait_name); + let trait_generics = generics(db, trait_id.into()); + tracing::debug!(?trait_generics); + if trait_generics[param_id.local_id()].is_trait_self() { + let args = GenericArgs::identity_for_item(interner, trait_id.into()); + let trait_ref = TraitRef::new_from_args(interner, trait_id.into(), args); + tracing::debug!(?args, ?trait_ref); + return search(trait_ref); + } + } + + let predicates = + db.generic_predicates_for_param(def, param_id.into(), assoc_name.clone()); + predicates + .iter() + .find_map(|pred| match (*pred).kind().skip_binder() { + rustc_type_ir::ClauseKind::Trait(trait_predicate) => Some(trait_predicate), + _ => None, + }) + .and_then(|trait_predicate| { + let trait_ref = trait_predicate.trait_ref; + assert!( + !trait_ref.has_escaping_bound_vars(), + "FIXME unexpected higher-ranked trait bound" + ); + search(trait_ref) + }) + } + _ => None, + } } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower/path.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower/path.rs index 09a256a86dcc..9ba0da6f4964 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower/path.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower/path.rs @@ -1,42 +1,52 @@ //! A wrapper around [`TyLoweringContext`] specifically for lowering paths. -use chalk_ir::{BoundVar, cast::Cast, fold::Shift}; use either::Either; use hir_def::{ - GenericDefId, GenericParamId, TraitId, + GenericDefId, GenericParamId, Lookup, TraitId, TypeAliasId, expr_store::{ - ExpressionStore, - path::{GenericArg, GenericArgs, GenericArgsParentheses, Path, PathSegment, PathSegments}, + ExpressionStore, HygieneId, + path::{ + GenericArg as HirGenericArg, GenericArgs as HirGenericArgs, GenericArgsParentheses, + Path, PathSegment, PathSegments, + }, }, hir::generics::{ GenericParamDataRef, TypeOrConstParamData, TypeParamData, TypeParamProvenance, }, - resolver::TypeNs, + resolver::{ResolveValueResult, TypeNs, ValueNs}, signatures::TraitFlags, type_ref::{TypeRef, TypeRefId}, }; +use hir_expand::name::Name; +use rustc_type_ir::{ + AliasTerm, AliasTy, AliasTyKind, + inherent::{GenericArgs as _, Region as _, SliceLike, Ty as _}, +}; use smallvec::SmallVec; use stdx::never; use crate::{ - AliasEq, AliasTy, GenericArgsProhibitedReason, ImplTraitLoweringMode, IncorrectGenericsLenKind, - Interner, ParamLoweringMode, PathGenericsSource, PathLoweringDiagnostic, ProjectionTy, - QuantifiedWhereClause, Substitution, TraitRef, Ty, TyBuilder, TyDefId, TyKind, WhereClause, - consteval_chalk::{unknown_const, unknown_const_as_generic}, + GenericArgsProhibitedReason, IncorrectGenericsLenKind, PathGenericsSource, + PathLoweringDiagnostic, TyDefId, ValueTyDefId, + consteval::{unknown_const, unknown_const_as_generic}, db::HirDatabase, - error_lifetime, generics::{Generics, generics}, - lower::{LifetimeElisionKind, TyLoweringContext, named_associated_type_shorthand_candidates}, - next_solver::{ - DbInterner, - mapping::{ChalkToNextSolver, NextSolverToChalk}, + lower::{ + LifetimeElisionKind, PathDiagnosticCallbackData, named_associated_type_shorthand_candidates, }, - to_assoc_type_id, to_chalk_trait_id, to_placeholder_idx, - utils::associated_type_by_name_including_super_traits, + next_solver::{ + Binder, Clause, Const, DbInterner, ErrorGuaranteed, GenericArg, GenericArgs, Predicate, + ProjectionPredicate, Region, TraitRef, Ty, + }, +}; + +use super::{ + ImplTraitLoweringMode, TyLoweringContext, associated_type_by_name_including_super_traits, + const_param_ty_query, ty_query, }; type CallbackData<'a, 'db> = Either< - super::PathDiagnosticCallbackData, + PathDiagnosticCallbackData, crate::infer::diagnostics::PathDiagnosticCallbackData<'a, 'db>, >; @@ -45,12 +55,12 @@ type CallbackData<'a, 'db> = Either< pub(crate) struct PathDiagnosticCallback<'a, 'db> { pub(crate) data: CallbackData<'a, 'db>, pub(crate) callback: - fn(&CallbackData<'_, 'db>, &mut TyLoweringContext<'_>, PathLoweringDiagnostic), + fn(&CallbackData<'_, 'db>, &mut TyLoweringContext<'db, '_>, PathLoweringDiagnostic), } -pub(crate) struct PathLoweringContext<'a, 'b> { - ctx: &'a mut TyLoweringContext<'b>, - on_diagnostic: PathDiagnosticCallback<'a, 'b>, +pub(crate) struct PathLoweringContext<'a, 'b, 'db> { + ctx: &'a mut TyLoweringContext<'db, 'b>, + on_diagnostic: PathDiagnosticCallback<'a, 'db>, path: &'a Path, segments: PathSegments<'a>, current_segment_idx: usize, @@ -58,11 +68,11 @@ pub(crate) struct PathLoweringContext<'a, 'b> { current_or_prev_segment: PathSegment<'a>, } -impl<'a, 'b> PathLoweringContext<'a, 'b> { +impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> { #[inline] pub(crate) fn new( - ctx: &'a mut TyLoweringContext<'b>, - on_diagnostic: PathDiagnosticCallback<'a, 'b>, + ctx: &'a mut TyLoweringContext<'db, 'b>, + on_diagnostic: PathDiagnosticCallback<'a, 'db>, path: &'a Path, ) -> Self { let segments = path.segments(); @@ -84,7 +94,7 @@ impl<'a, 'b> PathLoweringContext<'a, 'b> { } #[inline] - pub(crate) fn ty_ctx(&mut self) -> &mut TyLoweringContext<'b> { + pub(crate) fn ty_ctx(&mut self) -> &mut TyLoweringContext<'db, 'b> { self.ctx } @@ -109,11 +119,25 @@ impl<'a, 'b> PathLoweringContext<'a, 'b> { self.segments.get(self.current_segment_idx).unwrap_or(self.current_or_prev_segment); } + #[inline] + pub(crate) fn ignore_last_segment(&mut self) { + self.segments = self.segments.strip_last(); + } + + #[inline] + pub(crate) fn set_current_segment(&mut self, segment: usize) { + self.current_segment_idx = segment; + self.current_or_prev_segment = self + .segments + .get(segment) + .expect("invalid segment passed to PathLoweringContext::set_current_segment()"); + } + #[inline] fn with_lifetime_elision( &mut self, - lifetime_elision: LifetimeElisionKind, - f: impl FnOnce(&mut PathLoweringContext<'_, '_>) -> T, + lifetime_elision: LifetimeElisionKind<'db>, + f: impl FnOnce(&mut PathLoweringContext<'_, '_, 'db>) -> T, ) -> T { let old_lifetime_elision = std::mem::replace(&mut self.ctx.lifetime_elision, lifetime_elision); @@ -124,12 +148,13 @@ impl<'a, 'b> PathLoweringContext<'a, 'b> { pub(crate) fn lower_ty_relative_path( &mut self, - ty: Ty, + ty: Ty<'db>, // We need the original resolution to lower `Self::AssocTy` correctly res: Option, infer_args: bool, - ) -> (Ty, Option) { - match self.segments.len() - self.current_segment_idx { + ) -> (Ty<'db>, Option) { + let remaining_segments = self.segments.len() - self.current_segment_idx; + match remaining_segments { 0 => (ty, res), 1 => { // resolve unselected assoc types @@ -137,7 +162,7 @@ impl<'a, 'b> PathLoweringContext<'a, 'b> { } _ => { // FIXME report error (ambiguous associated type) - (TyKind::Error.intern(Interner), None) + (Ty::new_error(self.ctx.interner, ErrorGuaranteed), None) } } } @@ -147,8 +172,11 @@ impl<'a, 'b> PathLoweringContext<'a, 'b> { &mut self, resolution: TypeNs, infer_args: bool, - ) -> (Ty, Option) { + ) -> (Ty<'db>, Option) { let remaining_segments = self.segments.skip(self.current_segment_idx + 1); + tracing::debug!(?remaining_segments); + let rem_seg_len = remaining_segments.len(); + tracing::debug!(?rem_seg_len); let ty = match resolution { TypeNs::TraitId(trait_) => { @@ -156,15 +184,17 @@ impl<'a, 'b> PathLoweringContext<'a, 'b> { 1 => { let trait_ref = self.lower_trait_ref_from_resolved_path( trait_, - TyKind::Error.intern(Interner), - infer_args, + Ty::new_error(self.ctx.interner, ErrorGuaranteed), + false, ); - + tracing::debug!(?trait_ref); self.skip_resolved_segment(); let segment = self.current_or_prev_segment; + let trait_id = trait_ref.def_id.0; let found = - trait_.trait_items(self.ctx.db).associated_type_by_name(segment.name); + trait_id.trait_items(self.ctx.db).associated_type_by_name(segment.name); + tracing::debug!(?found); match found { Some(associated_ty) => { // FIXME: `substs_from_path_segment()` pushes `TyKind::Error` for every parent @@ -173,27 +203,30 @@ impl<'a, 'b> PathLoweringContext<'a, 'b> { // this point (`trait_ref.substitution`). let substitution = self.substs_from_path_segment( associated_ty.into(), - infer_args, + false, None, true, ); - let substitution = Substitution::from_iter( - Interner, - trait_ref.substitution.iter(Interner).chain( - substitution - .iter(Interner) - .skip(trait_ref.substitution.len(Interner)), - ), + let args = GenericArgs::new_from_iter( + self.ctx.interner, + trait_ref + .args + .iter() + .chain(substitution.iter().skip(trait_ref.args.len())), ); - TyKind::Alias(AliasTy::Projection(ProjectionTy { - associated_ty_id: to_assoc_type_id(associated_ty), - substitution, - })) - .intern(Interner) + Ty::new_alias( + self.ctx.interner, + AliasTyKind::Projection, + AliasTy::new_from_args( + self.ctx.interner, + associated_ty.into(), + args, + ), + ) } None => { // FIXME: report error (associated type not found) - TyKind::Error.intern(Interner) + Ty::new_error(self.ctx.interner, ErrorGuaranteed) } } } @@ -201,73 +234,34 @@ impl<'a, 'b> PathLoweringContext<'a, 'b> { // Trait object type without dyn; this should be handled in upstream. See // `lower_path()`. stdx::never!("unexpected fully resolved trait path"); - TyKind::Error.intern(Interner) + Ty::new_error(self.ctx.interner, ErrorGuaranteed) } _ => { // FIXME report error (ambiguous associated type) - TyKind::Error.intern(Interner) + Ty::new_error(self.ctx.interner, ErrorGuaranteed) } }; return (ty, None); } - TypeNs::GenericParam(param_id) => match self.ctx.type_param_mode { - ParamLoweringMode::Placeholder => { - let generics = self.ctx.generics(); - let idx = generics.type_or_const_param_idx(param_id.into()).unwrap(); - TyKind::Placeholder(to_placeholder_idx( - self.ctx.db, - param_id.into(), - idx as u32, - )) - } - ParamLoweringMode::Variable => { - let idx = match self.ctx.generics().type_or_const_param_idx(param_id.into()) { - None => { - never!("no matching generics"); - return (TyKind::Error.intern(Interner), None); - } - Some(idx) => idx, - }; - - TyKind::BoundVar(BoundVar::new(self.ctx.in_binders, idx)) - } - } - .intern(Interner), - TypeNs::SelfType(impl_id) => { + TypeNs::GenericParam(param_id) => { let generics = self.ctx.generics(); - - match self.ctx.type_param_mode { - ParamLoweringMode::Placeholder => { - // `def` can be either impl itself or item within, and we need impl itself - // now. - let generics = generics.parent_or_self(); - let interner = DbInterner::new_with(self.ctx.db, None, None); - let subst = generics.placeholder_subst(self.ctx.db); - let args: crate::next_solver::GenericArgs<'_> = - subst.to_nextsolver(interner); - self.ctx - .db - .impl_self_ty(impl_id) - .instantiate(interner, args) - .to_chalk(interner) + let idx = generics.type_or_const_param_idx(param_id.into()); + match idx { + None => { + never!("no matching generics"); + Ty::new_error(self.ctx.interner, ErrorGuaranteed) + } + Some(idx) => { + let (pidx, _param) = generics.iter().nth(idx).unwrap(); + assert_eq!(pidx, param_id.into()); + self.ctx.type_param(param_id, idx as u32) } - ParamLoweringMode::Variable => TyBuilder::impl_self_ty(self.ctx.db, impl_id) - .fill_with_bound_vars(self.ctx.in_binders, 0) - .build(DbInterner::conjure()) - .to_chalk(DbInterner::conjure()), } } + TypeNs::SelfType(impl_id) => self.ctx.db.impl_self_ty(impl_id).skip_binder(), TypeNs::AdtSelfType(adt) => { - let generics = generics(self.ctx.db, adt.into()); - let substs = match self.ctx.type_param_mode { - ParamLoweringMode::Placeholder => generics.placeholder_subst(self.ctx.db), - ParamLoweringMode::Variable => { - generics.bound_vars_subst(self.ctx.db, self.ctx.in_binders) - } - }; - let interner = DbInterner::conjure(); - let args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner); - self.ctx.db.ty(adt.into()).instantiate(interner, args).to_chalk(interner) + let args = GenericArgs::identity_for_item(self.ctx.interner, adt.into()); + Ty::new_adt(self.ctx.interner, adt, args) } TypeNs::AdtId(it) => self.lower_path_inner(it.into(), infer_args), @@ -275,15 +269,19 @@ impl<'a, 'b> PathLoweringContext<'a, 'b> { TypeNs::TypeAliasId(it) => self.lower_path_inner(it.into(), infer_args), // FIXME: report error TypeNs::EnumVariantId(_) | TypeNs::ModuleId(_) => { - return (TyKind::Error.intern(Interner), None); + return (Ty::new_error(self.ctx.interner, ErrorGuaranteed), None); } }; + tracing::debug!(?ty); + self.skip_resolved_segment(); self.lower_ty_relative_path(ty, Some(resolution), infer_args) } - fn handle_type_ns_resolution(&mut self, resolution: &TypeNs) { + /// This returns whether to keep the resolution (`true`) of throw it (`false`). + #[must_use] + fn handle_type_ns_resolution(&mut self, resolution: &TypeNs) -> bool { let mut prohibit_generics_on_resolved = |reason| { if self.current_or_prev_segment.args_and_bindings.is_some() { let segment = self.current_segment_u32(); @@ -302,7 +300,13 @@ impl<'a, 'b> PathLoweringContext<'a, 'b> { prohibit_generics_on_resolved(GenericArgsProhibitedReason::TyParam) } TypeNs::AdtSelfType(_) => { - prohibit_generics_on_resolved(GenericArgsProhibitedReason::SelfTy) + prohibit_generics_on_resolved(GenericArgsProhibitedReason::SelfTy); + + if self.ctx.lowering_param_default.is_some() { + // Generic defaults are not allowed to refer to `Self`. + // FIXME: Emit an error. + return false; + } } TypeNs::BuiltinType(_) => { prohibit_generics_on_resolved(GenericArgsProhibitedReason::PrimitiveTy) @@ -315,6 +319,8 @@ impl<'a, 'b> PathLoweringContext<'a, 'b> { | TypeNs::TypeAliasId(_) | TypeNs::TraitId(_) => {} } + + true } pub(crate) fn resolve_path_in_type_ns_fully(&mut self) -> Option { @@ -325,6 +331,7 @@ impl<'a, 'b> PathLoweringContext<'a, 'b> { Some(res) } + #[tracing::instrument(skip(self), ret)] pub(crate) fn resolve_path_in_type_ns(&mut self) -> Option<(TypeNs, Option)> { let (resolution, remaining_index, _, prefix_info) = self.ctx.resolver.resolve_path_in_type_ns_with_prefix_info(self.ctx.db, self.path)?; @@ -347,11 +354,6 @@ impl<'a, 'b> PathLoweringContext<'a, 'b> { self.current_or_prev_segment = segments.get(resolved_segment_idx).expect("should have resolved segment"); - if matches!(self.path, Path::BarePath(..)) { - // Bare paths cannot have generics, so skip them as an optimization. - return Some((resolution, remaining_index)); - } - for (i, mod_segment) in module_segments.iter().enumerate() { if mod_segment.args_and_bindings.is_some() { self.on_diagnostic(PathLoweringDiagnostic::GenericArgsProhibited { @@ -371,87 +373,233 @@ impl<'a, 'b> PathLoweringContext<'a, 'b> { }); } - self.handle_type_ns_resolution(&resolution); + if !self.handle_type_ns_resolution(&resolution) { + return None; + } Some((resolution, remaining_index)) } - fn select_associated_type(&mut self, res: Option, infer_args: bool) -> Ty { - let Some(res) = res else { - return TyKind::Error.intern(Interner); - }; - let segment = self.current_or_prev_segment; - let ty = named_associated_type_shorthand_candidates( + pub(crate) fn resolve_path_in_value_ns( + &mut self, + hygiene_id: HygieneId, + ) -> Option { + let (res, prefix_info) = self.ctx.resolver.resolve_path_in_value_ns_with_prefix_info( self.ctx.db, - self.ctx.def, - res, - Some(segment.name.clone()), - move |name, t, associated_ty| { - if name != segment.name { - return None; - } - let generics = self.ctx.generics(); + self.path, + hygiene_id, + )?; - let parent_subst = t.substitution.clone(); - let parent_subst = match self.ctx.type_param_mode { - ParamLoweringMode::Placeholder => { - // if we're lowering to placeholders, we have to put them in now. - let s = generics.placeholder_subst(self.ctx.db); - s.apply(parent_subst, Interner) - } - ParamLoweringMode::Variable => { - // We need to shift in the bound vars, since - // `named_associated_type_shorthand_candidates` does not do that. - parent_subst.shifted_in_from(Interner, self.ctx.in_binders) + let segments = self.segments; + if segments.is_empty() || matches!(self.path, Path::LangItem(..)) { + // `segments.is_empty()` can occur with `self`. + return Some(res); + } + + let (mod_segments, enum_segment, resolved_segment_idx) = match res { + ResolveValueResult::Partial(_, unresolved_segment, _) => { + (segments.take(unresolved_segment - 1), None, unresolved_segment - 1) + } + ResolveValueResult::ValueNs(ValueNs::EnumVariantId(_), _) + if prefix_info.enum_variant => + { + (segments.strip_last_two(), segments.len().checked_sub(2), segments.len() - 1) + } + ResolveValueResult::ValueNs(..) => (segments.strip_last(), None, segments.len() - 1), + }; + + self.current_segment_idx = resolved_segment_idx; + self.current_or_prev_segment = + segments.get(resolved_segment_idx).expect("should have resolved segment"); + + for (i, mod_segment) in mod_segments.iter().enumerate() { + if mod_segment.args_and_bindings.is_some() { + self.on_diagnostic(PathLoweringDiagnostic::GenericArgsProhibited { + segment: i as u32, + reason: GenericArgsProhibitedReason::Module, + }); + } + } + + if let Some(enum_segment) = enum_segment + && segments.get(enum_segment).is_some_and(|it| it.args_and_bindings.is_some()) + && segments.get(enum_segment + 1).is_some_and(|it| it.args_and_bindings.is_some()) + { + self.on_diagnostic(PathLoweringDiagnostic::GenericArgsProhibited { + segment: (enum_segment + 1) as u32, + reason: GenericArgsProhibitedReason::EnumVariant, + }); + } + + match &res { + ResolveValueResult::ValueNs(resolution, _) => { + let resolved_segment_idx = self.current_segment_u32(); + let resolved_segment = self.current_or_prev_segment; + + let mut prohibit_generics_on_resolved = |reason| { + if resolved_segment.args_and_bindings.is_some() { + self.on_diagnostic(PathLoweringDiagnostic::GenericArgsProhibited { + segment: resolved_segment_idx, + reason, + }); } }; - // FIXME: `substs_from_path_segment()` pushes `TyKind::Error` for every parent - // generic params. It's inefficient to splice the `Substitution`s, so we may want - // that method to optionally take parent `Substitution` as we already know them at - // this point (`t.substitution`). - let substs = - self.substs_from_path_segment(associated_ty.into(), infer_args, None, true); - - let substs = Substitution::from_iter( - Interner, - parent_subst - .iter(Interner) - .chain(substs.iter(Interner).skip(parent_subst.len(Interner))), - ); - - Some( - TyKind::Alias(AliasTy::Projection(ProjectionTy { - associated_ty_id: to_assoc_type_id(associated_ty), - substitution: substs, - })) - .intern(Interner), - ) - }, - ); - - ty.unwrap_or_else(|| TyKind::Error.intern(Interner)) + match resolution { + ValueNs::ImplSelf(_) => { + prohibit_generics_on_resolved(GenericArgsProhibitedReason::SelfTy); + } + // FIXME: rustc generates E0107 (incorrect number of generic arguments) and not + // E0109 (generic arguments provided for a type that doesn't accept them) for + // consts and statics, presumably as a defense against future in which consts + // and statics can be generic, or just because it was easier for rustc implementors. + // That means we'll show the wrong error code. Because of us it's easier to do it + // this way :) + ValueNs::GenericParam(_) => { + prohibit_generics_on_resolved(GenericArgsProhibitedReason::Const) + } + ValueNs::StaticId(_) => { + prohibit_generics_on_resolved(GenericArgsProhibitedReason::Static) + } + ValueNs::LocalBinding(_) => { + prohibit_generics_on_resolved(GenericArgsProhibitedReason::LocalVariable) + } + ValueNs::FunctionId(_) + | ValueNs::StructId(_) + | ValueNs::EnumVariantId(_) + | ValueNs::ConstId(_) => {} + } + } + ResolveValueResult::Partial(resolution, _, _) => { + if !self.handle_type_ns_resolution(resolution) { + return None; + } + } + }; + Some(res) } - fn lower_path_inner(&mut self, typeable: TyDefId, infer_args: bool) -> Ty { + #[tracing::instrument(skip(self), ret)] + fn select_associated_type(&mut self, res: Option, infer_args: bool) -> Ty<'db> { + let interner = self.ctx.interner; + let Some(res) = res else { + return Ty::new_error(self.ctx.interner, ErrorGuaranteed); + }; + let def = self.ctx.def; + let segment = self.current_or_prev_segment; + let assoc_name = segment.name; + let check_alias = |name: &Name, t: TraitRef<'db>, associated_ty: TypeAliasId| { + if name != assoc_name { + return None; + } + + // FIXME: `substs_from_path_segment()` pushes `TyKind::Error` for every parent + // generic params. It's inefficient to splice the `Substitution`s, so we may want + // that method to optionally take parent `Substitution` as we already know them at + // this point (`t.substitution`). + let substs = + self.substs_from_path_segment(associated_ty.into(), infer_args, None, true); + + let substs = GenericArgs::new_from_iter( + interner, + t.args.iter().chain(substs.iter().skip(t.args.len())), + ); + + Some(Ty::new_alias( + interner, + AliasTyKind::Projection, + AliasTy::new(interner, associated_ty.into(), substs), + )) + }; + named_associated_type_shorthand_candidates( + interner, + def, + res, + Some(assoc_name.clone()), + check_alias, + ) + .unwrap_or_else(|| Ty::new_error(interner, ErrorGuaranteed)) + } + + fn lower_path_inner(&mut self, typeable: TyDefId, infer_args: bool) -> Ty<'db> { let generic_def = match typeable { - TyDefId::BuiltinType(builtin) => return TyBuilder::builtin(builtin), + TyDefId::BuiltinType(builtinty) => { + return Ty::from_builtin_type(self.ctx.interner, builtinty); + } TyDefId::AdtId(it) => it.into(), TyDefId::TypeAliasId(it) => it.into(), }; - let substs = self.substs_from_path_segment(generic_def, infer_args, None, false); - let interner = DbInterner::conjure(); - let args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner); - self.ctx.db.ty(typeable).instantiate(interner, args).to_chalk(interner) + let args = self.substs_from_path_segment(generic_def, infer_args, None, false); + let ty = ty_query(self.ctx.db, typeable); + ty.instantiate(self.ctx.interner, args) + } + + /// Collect generic arguments from a path into a `Substs`. See also + /// `create_substs_for_ast_path` and `def_to_ty` in rustc. + pub(crate) fn substs_from_path( + &mut self, + // Note that we don't call `db.value_type(resolved)` here, + // `ValueTyDefId` is just a convenient way to pass generics and + // special-case enum variants + resolved: ValueTyDefId, + infer_args: bool, + lowering_assoc_type_generics: bool, + ) -> GenericArgs<'db> { + let interner = self.ctx.interner; + let prev_current_segment_idx = self.current_segment_idx; + let prev_current_segment = self.current_or_prev_segment; + + let generic_def = match resolved { + ValueTyDefId::FunctionId(it) => it.into(), + ValueTyDefId::StructId(it) => it.into(), + ValueTyDefId::UnionId(it) => it.into(), + ValueTyDefId::ConstId(it) => it.into(), + ValueTyDefId::StaticId(_) => { + return GenericArgs::new_from_iter(interner, []); + } + ValueTyDefId::EnumVariantId(var) => { + // the generic args for an enum variant may be either specified + // on the segment referring to the enum, or on the segment + // referring to the variant. So `Option::::None` and + // `Option::None::` are both allowed (though the former is + // FIXME: This isn't strictly correct, enum variants may be used not through the enum + // (via `use Enum::Variant`). The resolver returns whether they were, but we don't have its result + // available here. The worst that can happen is that we will show some confusing diagnostics to the user, + // if generics exist on the module and they don't match with the variant. + // preferred). See also `def_ids_for_path_segments` in rustc. + // + // `wrapping_sub(1)` will return a number which `get` will return None for if current_segment_idx<2. + // This simplifies the code a bit. + let penultimate_idx = self.current_segment_idx.wrapping_sub(1); + let penultimate = self.segments.get(penultimate_idx); + if let Some(penultimate) = penultimate + && self.current_or_prev_segment.args_and_bindings.is_none() + && penultimate.args_and_bindings.is_some() + { + self.current_segment_idx = penultimate_idx; + self.current_or_prev_segment = penultimate; + } + var.lookup(self.ctx.db).parent.into() + } + }; + let result = self.substs_from_path_segment( + generic_def, + infer_args, + None, + lowering_assoc_type_generics, + ); + self.current_segment_idx = prev_current_segment_idx; + self.current_or_prev_segment = prev_current_segment; + result } pub(crate) fn substs_from_path_segment( &mut self, def: GenericDefId, infer_args: bool, - explicit_self_ty: Option, + explicit_self_ty: Option>, lowering_assoc_type_generics: bool, - ) -> Substitution { + ) -> GenericArgs<'db> { let old_lifetime_elision = self.ctx.lifetime_elision.clone(); if let Some(args) = self.current_or_prev_segment.args_and_bindings @@ -478,7 +626,7 @@ impl<'a, 'b> PathLoweringContext<'a, 'b> { PathLoweringDiagnostic::ParenthesizedGenericArgsWithoutFnTrait { segment }, ); - return TyBuilder::unknown_subst(self.ctx.db, def); + return unknown_subst(self.ctx.interner, def); } // `Fn()`-style generics are treated like functions for the purpose of lifetime elision. @@ -501,20 +649,20 @@ impl<'a, 'b> PathLoweringContext<'a, 'b> { pub(super) fn substs_from_args_and_bindings( &mut self, - args_and_bindings: Option<&GenericArgs>, + args_and_bindings: Option<&HirGenericArgs>, def: GenericDefId, infer_args: bool, - explicit_self_ty: Option, + explicit_self_ty: Option>, generics_source: PathGenericsSource, lowering_assoc_type_generics: bool, - lifetime_elision: LifetimeElisionKind, - ) -> Substitution { - struct LowererCtx<'a, 'b, 'c> { - ctx: &'a mut PathLoweringContext<'b, 'c>, + lifetime_elision: LifetimeElisionKind<'db>, + ) -> GenericArgs<'db> { + struct LowererCtx<'a, 'b, 'c, 'db> { + ctx: &'a mut PathLoweringContext<'b, 'c, 'db>, generics_source: PathGenericsSource, } - impl GenericArgsLowerer for LowererCtx<'_, '_, '_> { + impl<'db> GenericArgsLowerer<'db> for LowererCtx<'_, '_, '_, 'db> { fn report_len_mismatch( &mut self, def: GenericDefId, @@ -549,23 +697,24 @@ impl<'a, 'b> PathLoweringContext<'a, 'b> { &mut self, param_id: GenericParamId, param: GenericParamDataRef<'_>, - arg: &GenericArg, - ) -> crate::GenericArg { - match (param, arg) { - (GenericParamDataRef::LifetimeParamData(_), GenericArg::Lifetime(lifetime)) => { - self.ctx.ctx.lower_lifetime(*lifetime).cast(Interner) + arg: &HirGenericArg, + ) -> GenericArg<'db> { + match (param, *arg) { + ( + GenericParamDataRef::LifetimeParamData(_), + HirGenericArg::Lifetime(lifetime), + ) => self.ctx.ctx.lower_lifetime(lifetime).into(), + (GenericParamDataRef::TypeParamData(_), HirGenericArg::Type(type_ref)) => { + self.ctx.ctx.lower_ty(type_ref).into() } - (GenericParamDataRef::TypeParamData(_), GenericArg::Type(type_ref)) => { - self.ctx.ctx.lower_ty(*type_ref).cast(Interner) - } - (GenericParamDataRef::ConstParamData(_), GenericArg::Const(konst)) => { + (GenericParamDataRef::ConstParamData(_), HirGenericArg::Const(konst)) => { let GenericParamId::ConstParamId(const_id) = param_id else { unreachable!("non-const param ID for const param"); }; self.ctx .ctx - .lower_const(konst, self.ctx.ctx.db.const_param_ty(const_id)) - .cast(Interner) + .lower_const(konst, const_param_ty_query(self.ctx.ctx.db, const_id)) + .into() } _ => unreachable!("unmatching param kinds were passed to `provided_kind()`"), } @@ -573,9 +722,9 @@ impl<'a, 'b> PathLoweringContext<'a, 'b> { fn provided_type_like_const( &mut self, - const_ty: Ty, + const_ty: Ty<'db>, arg: TypeLikeConst<'_>, - ) -> crate::Const { + ) -> Const<'db> { match arg { TypeLikeConst::Path(path) => self.ctx.ctx.lower_path_as_const(path, const_ty), TypeLikeConst::Infer => unknown_const(const_ty), @@ -588,18 +737,19 @@ impl<'a, 'b> PathLoweringContext<'a, 'b> { param_id: GenericParamId, param: GenericParamDataRef<'_>, infer_args: bool, - preceding_args: &[crate::GenericArg], - ) -> crate::GenericArg { - let default = || { - self.ctx - .ctx - .db - .generic_defaults(def) - .get(preceding_args.len()) - .map(|default| default.clone().substitute(Interner, preceding_args)) - }; + preceding_args: &[GenericArg<'db>], + ) -> GenericArg<'db> { + let default = + || { + self.ctx.ctx.db.generic_defaults(def).get(preceding_args.len()).map( + |default| default.instantiate(self.ctx.ctx.interner, preceding_args), + ) + }; match param { - GenericParamDataRef::LifetimeParamData(_) => error_lifetime().cast(Interner), + GenericParamDataRef::LifetimeParamData(_) => { + Region::new(self.ctx.ctx.interner, rustc_type_ir::ReError(ErrorGuaranteed)) + .into() + } GenericParamDataRef::TypeParamData(param) => { if !infer_args && param.default.is_some() @@ -607,7 +757,7 @@ impl<'a, 'b> PathLoweringContext<'a, 'b> { { return default; } - TyKind::Error.intern(Interner).cast(Interner) + Ty::new_error(self.ctx.ctx.interner, ErrorGuaranteed).into() } GenericParamDataRef::ConstParamData(param) => { if !infer_args @@ -619,19 +769,23 @@ impl<'a, 'b> PathLoweringContext<'a, 'b> { let GenericParamId::ConstParamId(const_id) = param_id else { unreachable!("non-const param ID for const param"); }; - unknown_const_as_generic(self.ctx.ctx.db.const_param_ty(const_id)) - .cast(Interner) + unknown_const_as_generic(const_param_ty_query(self.ctx.ctx.db, const_id)) } } } - fn parent_arg(&mut self, param_id: GenericParamId) -> crate::GenericArg { + fn parent_arg(&mut self, param_id: GenericParamId) -> GenericArg<'db> { match param_id { - GenericParamId::TypeParamId(_) => TyKind::Error.intern(Interner).cast(Interner), - GenericParamId::ConstParamId(const_id) => { - unknown_const_as_generic(self.ctx.ctx.db.const_param_ty(const_id)) + GenericParamId::TypeParamId(_) => { + Ty::new_error(self.ctx.ctx.interner, ErrorGuaranteed).into() + } + GenericParamId::ConstParamId(const_id) => { + unknown_const_as_generic(const_param_ty_query(self.ctx.ctx.db, const_id)) + } + GenericParamId::LifetimeParamId(_) => { + Region::new(self.ctx.ctx.interner, rustc_type_ir::ReError(ErrorGuaranteed)) + .into() } - GenericParamId::LifetimeParamId(_) => error_lifetime().cast(Interner), } } @@ -649,6 +803,14 @@ impl<'a, 'b> PathLoweringContext<'a, 'b> { }); } + fn report_elision_failure(&mut self, def: GenericDefId, expected_count: u32) { + self.ctx.on_diagnostic(PathLoweringDiagnostic::ElisionFailure { + generics_source: self.generics_source, + def, + expected_count, + }); + } + fn report_missing_lifetime(&mut self, def: GenericDefId, expected_count: u32) { self.ctx.on_diagnostic(PathLoweringDiagnostic::MissingLifetime { generics_source: self.generics_source, @@ -674,38 +836,39 @@ impl<'a, 'b> PathLoweringContext<'a, 'b> { pub(crate) fn lower_trait_ref_from_resolved_path( &mut self, resolved: TraitId, - explicit_self_ty: Ty, + explicit_self_ty: Ty<'db>, infer_args: bool, - ) -> TraitRef { - let substs = self.trait_ref_substs_from_path(resolved, explicit_self_ty, infer_args); - TraitRef { trait_id: to_chalk_trait_id(resolved), substitution: substs } + ) -> TraitRef<'db> { + let args = self.trait_ref_substs_from_path(resolved, explicit_self_ty, infer_args); + TraitRef::new_from_args(self.ctx.interner, resolved.into(), args) } fn trait_ref_substs_from_path( &mut self, resolved: TraitId, - explicit_self_ty: Ty, + explicit_self_ty: Ty<'db>, infer_args: bool, - ) -> Substitution { + ) -> GenericArgs<'db> { self.substs_from_path_segment(resolved.into(), infer_args, Some(explicit_self_ty), false) } pub(super) fn assoc_type_bindings_from_type_bound<'c>( mut self, - trait_ref: TraitRef, - ) -> Option + use<'a, 'b, 'c>> { + trait_ref: TraitRef<'db>, + ) -> Option> + use<'a, 'b, 'c, 'db>> { + let interner = self.ctx.interner; self.current_or_prev_segment.args_and_bindings.map(|args_and_bindings| { args_and_bindings.bindings.iter().enumerate().flat_map(move |(binding_idx, binding)| { let found = associated_type_by_name_including_super_traits( self.ctx.db, - trait_ref.clone(), + trait_ref, &binding.name, ); let (super_trait_ref, associated_ty) = match found { None => return SmallVec::new(), Some(t) => t, }; - let substitution = + let args = self.with_lifetime_elision(LifetimeElisionKind::AnonymousReportError, |this| { // FIXME: `substs_from_path_segment()` pushes `TyKind::Error` for every parent // generic params. It's inefficient to splice the `Substitution`s, so we may want @@ -715,7 +878,7 @@ impl<'a, 'b> PathLoweringContext<'a, 'b> { binding.args.as_ref(), associated_ty.into(), false, // this is not relevant - Some(super_trait_ref.self_type_parameter(Interner)), + Some(super_trait_ref.self_ty()), PathGenericsSource::AssocType { segment: this.current_segment_u32(), assoc_type: binding_idx as u32, @@ -724,27 +887,20 @@ impl<'a, 'b> PathLoweringContext<'a, 'b> { this.ctx.lifetime_elision.clone(), ) }); - let substitution = Substitution::from_iter( - Interner, - super_trait_ref.substitution.iter(Interner).chain( - substitution - .iter(Interner) - .skip(super_trait_ref.substitution.len(Interner)), - ), + let args = GenericArgs::new_from_iter( + interner, + super_trait_ref.args.iter().chain(args.iter().skip(super_trait_ref.args.len())), ); - let projection_ty = ProjectionTy { - associated_ty_id: to_assoc_type_id(associated_ty), - substitution, - }; + let projection_term = + AliasTerm::new_from_args(interner, associated_ty.into(), args); let mut predicates: SmallVec<[_; 1]> = SmallVec::with_capacity( binding.type_ref.as_ref().map_or(0, |_| 1) + binding.bounds.len(), ); - if let Some(type_ref) = binding.type_ref { let lifetime_elision = if args_and_bindings.parenthesized == GenericArgsParentheses::ParenSugar { // `Fn()`-style generics are elided like functions. This is `Output` (we lower to it in hir-def). - LifetimeElisionKind::for_fn_ret() + LifetimeElisionKind::for_fn_ret(self.ctx.interner) } else { self.ctx.lifetime_elision.clone() }; @@ -756,31 +912,33 @@ impl<'a, 'b> PathLoweringContext<'a, 'b> { ImplTraitLoweringMode::Disallowed | ImplTraitLoweringMode::Opaque, ) => { let ty = this.ctx.lower_ty(type_ref); - let alias_eq = AliasEq { - alias: AliasTy::Projection(projection_ty.clone()), - ty, - }; - predicates.push(crate::wrap_empty_binders(WhereClause::AliasEq( - alias_eq, - ))); + let pred = Clause(Predicate::new( + interner, + Binder::dummy(rustc_type_ir::PredicateKind::Clause( + rustc_type_ir::ClauseKind::Projection( + ProjectionPredicate { + projection_term, + term: ty.into(), + }, + ), + )), + )); + predicates.push(pred); } } - }); + }) + } + for bound in binding.bounds.iter() { + predicates.extend(self.ctx.lower_type_bound( + bound, + Ty::new_alias( + self.ctx.interner, + AliasTyKind::Projection, + AliasTy::new_from_args(self.ctx.interner, associated_ty.into(), args), + ), + false, + )); } - - self.with_lifetime_elision(LifetimeElisionKind::AnonymousReportError, |this| { - for bound in binding.bounds.iter() { - predicates.extend( - this.ctx.lower_type_bound( - bound, - TyKind::Alias(AliasTy::Projection(projection_ty.clone())) - .intern(Interner), - false, - ), - ); - } - }); - predicates }) }) @@ -793,7 +951,7 @@ pub(crate) enum TypeLikeConst<'a> { Path(&'a Path), } -pub(crate) trait GenericArgsLowerer { +pub(crate) trait GenericArgsLowerer<'db> { fn report_elided_lifetimes_in_path( &mut self, def: GenericDefId, @@ -801,6 +959,8 @@ pub(crate) trait GenericArgsLowerer { hard_error: bool, ); + fn report_elision_failure(&mut self, def: GenericDefId, expected_count: u32); + fn report_missing_lifetime(&mut self, def: GenericDefId, expected_count: u32); fn report_len_mismatch( @@ -817,10 +977,11 @@ pub(crate) trait GenericArgsLowerer { &mut self, param_id: GenericParamId, param: GenericParamDataRef<'_>, - arg: &GenericArg, - ) -> crate::GenericArg; + arg: &HirGenericArg, + ) -> GenericArg<'db>; - fn provided_type_like_const(&mut self, const_ty: Ty, arg: TypeLikeConst<'_>) -> crate::Const; + fn provided_type_like_const(&mut self, const_ty: Ty<'db>, arg: TypeLikeConst<'_>) + -> Const<'db>; fn inferred_kind( &mut self, @@ -828,21 +989,21 @@ pub(crate) trait GenericArgsLowerer { param_id: GenericParamId, param: GenericParamDataRef<'_>, infer_args: bool, - preceding_args: &[crate::GenericArg], - ) -> crate::GenericArg; + preceding_args: &[GenericArg<'db>], + ) -> GenericArg<'db>; - fn parent_arg(&mut self, param_id: GenericParamId) -> crate::GenericArg; + fn parent_arg(&mut self, param_id: GenericParamId) -> GenericArg<'db>; } /// Returns true if there was an error. -fn check_generic_args_len( - args_and_bindings: Option<&GenericArgs>, +fn check_generic_args_len<'db>( + args_and_bindings: Option<&HirGenericArgs>, def: GenericDefId, def_generics: &Generics, infer_args: bool, - lifetime_elision: &LifetimeElisionKind, + lifetime_elision: &LifetimeElisionKind<'db>, lowering_assoc_type_generics: bool, - ctx: &mut impl GenericArgsLowerer, + ctx: &mut impl GenericArgsLowerer<'db>, ) -> bool { let mut had_error = false; @@ -851,8 +1012,10 @@ fn check_generic_args_len( let args_no_self = &args_and_bindings.args[usize::from(args_and_bindings.has_self_type)..]; for arg in args_no_self { match arg { - GenericArg::Lifetime(_) => provided_lifetimes_count += 1, - GenericArg::Type(_) | GenericArg::Const(_) => provided_types_and_consts_count += 1, + HirGenericArg::Lifetime(_) => provided_lifetimes_count += 1, + HirGenericArg::Type(_) | HirGenericArg::Const(_) => { + provided_types_and_consts_count += 1 + } } } } @@ -873,6 +1036,13 @@ fn check_generic_args_len( ctx.report_missing_lifetime(def, lifetime_args_len as u32); had_error = true } + LifetimeElisionKind::ElisionFailure => { + ctx.report_elision_failure(def, lifetime_args_len as u32); + had_error = true; + } + LifetimeElisionKind::StaticIfNoLifetimeInScope { only_lint: _ } => { + // FIXME: Check there are other lifetimes in scope, and error/lint. + } LifetimeElisionKind::Elided(_) => { ctx.report_elided_lifetimes_in_path(def, lifetime_args_len as u32, false); } @@ -919,17 +1089,21 @@ fn check_generic_args_len( had_error } -pub(crate) fn substs_from_args_and_bindings( - db: &dyn HirDatabase, +pub(crate) fn substs_from_args_and_bindings<'db>( + db: &'db dyn HirDatabase, store: &ExpressionStore, - args_and_bindings: Option<&GenericArgs>, + args_and_bindings: Option<&HirGenericArgs>, def: GenericDefId, mut infer_args: bool, - lifetime_elision: LifetimeElisionKind, + lifetime_elision: LifetimeElisionKind<'db>, lowering_assoc_type_generics: bool, - explicit_self_ty: Option, - ctx: &mut impl GenericArgsLowerer, -) -> Substitution { + explicit_self_ty: Option>, + ctx: &mut impl GenericArgsLowerer<'db>, +) -> GenericArgs<'db> { + let interner = DbInterner::new_with(db, None, None); + + tracing::debug!(?args_and_bindings); + // Order is // - Parent parameters // - Optional Self parameter @@ -940,7 +1114,7 @@ pub(crate) fn substs_from_args_and_bindings( // We do not allow inference if there are specified args, i.e. we do not allow partial inference. let has_non_lifetime_args = - args_slice.iter().any(|arg| !matches!(arg, GenericArg::Lifetime(_))); + args_slice.iter().any(|arg| !matches!(arg, HirGenericArg::Lifetime(_))); infer_args &= !has_non_lifetime_args; let had_count_error = check_generic_args_len( @@ -981,7 +1155,7 @@ pub(crate) fn substs_from_args_and_bindings( let (_, self_ty) = args.next().expect("has_self_type=true, should have Self type"); ctx.provided_kind(self_param_id, self_param, self_ty) } else { - explicit_self_ty.map(|it| it.cast(Interner)).unwrap_or_else(|| { + explicit_self_ty.map(|it| it.into()).unwrap_or_else(|| { ctx.inferred_kind(def, self_param_id, self_param, infer_args, &substs) }) }; @@ -996,7 +1170,7 @@ pub(crate) fn substs_from_args_and_bindings( // input. We try to handle both sensibly. match (args.peek(), params.peek()) { (Some(&(arg_idx, arg)), Some(&(param_id, param))) => match (arg, param) { - (GenericArg::Type(_), GenericParamDataRef::TypeParamData(type_param)) + (HirGenericArg::Type(_), GenericParamDataRef::TypeParamData(type_param)) if type_param.provenance == TypeParamProvenance::ArgumentImplTrait => { // Do not allow specifying `impl Trait` explicitly. We already err at that, but if we won't handle it here @@ -1004,15 +1178,15 @@ pub(crate) fn substs_from_args_and_bindings( substs.push(ctx.inferred_kind(def, param_id, param, infer_args, &substs)); params.next(); } - (GenericArg::Lifetime(_), GenericParamDataRef::LifetimeParamData(_)) - | (GenericArg::Type(_), GenericParamDataRef::TypeParamData(_)) - | (GenericArg::Const(_), GenericParamDataRef::ConstParamData(_)) => { + (HirGenericArg::Lifetime(_), GenericParamDataRef::LifetimeParamData(_)) + | (HirGenericArg::Type(_), GenericParamDataRef::TypeParamData(_)) + | (HirGenericArg::Const(_), GenericParamDataRef::ConstParamData(_)) => { substs.push(ctx.provided_kind(param_id, param, arg)); args.next(); params.next(); } ( - GenericArg::Type(_) | GenericArg::Const(_), + HirGenericArg::Type(_) | HirGenericArg::Const(_), GenericParamDataRef::LifetimeParamData(_), ) => { // We expected a lifetime argument, but got a type or const @@ -1021,13 +1195,13 @@ pub(crate) fn substs_from_args_and_bindings( params.next(); force_infer_lt = Some((arg_idx as u32, param_id)); } - (GenericArg::Type(type_ref), GenericParamDataRef::ConstParamData(_)) => { + (HirGenericArg::Type(type_ref), GenericParamDataRef::ConstParamData(_)) => { if let Some(konst) = type_looks_like_const(store, *type_ref) { let GenericParamId::ConstParamId(param_id) = param_id else { panic!("unmatching param kinds"); }; - let const_ty = db.const_param_ty(param_id); - substs.push(ctx.provided_type_like_const(const_ty, konst).cast(Interner)); + let const_ty = const_param_ty_query(db, param_id); + substs.push(ctx.provided_type_like_const(const_ty, konst).into()); args.next(); params.next(); } else { @@ -1066,7 +1240,7 @@ pub(crate) fn substs_from_args_and_bindings( // after a type or const). We want to throw an error in this case. if !had_count_error { assert!( - matches!(arg, GenericArg::Lifetime(_)), + matches!(arg, HirGenericArg::Lifetime(_)), "the only possible situation here is incorrect lifetime order" ); let (provided_arg_idx, param_id) = @@ -1081,12 +1255,16 @@ pub(crate) fn substs_from_args_and_bindings( // If there are fewer arguments than parameters, it means we're inferring the remaining arguments. let param = if let GenericParamId::LifetimeParamId(_) = param_id { match &lifetime_elision { - LifetimeElisionKind::AnonymousCreateParameter { report_in_path: true } + LifetimeElisionKind::ElisionFailure + | LifetimeElisionKind::AnonymousCreateParameter { report_in_path: true } | LifetimeElisionKind::AnonymousReportError => { assert!(had_count_error); ctx.inferred_kind(def, param_id, param, infer_args, &substs) } - LifetimeElisionKind::Elided(lifetime) => lifetime.clone().cast(Interner), + LifetimeElisionKind::StaticIfNoLifetimeInScope { only_lint: _ } => { + Region::new_static(interner).into() + } + LifetimeElisionKind::Elided(lifetime) => (*lifetime).into(), LifetimeElisionKind::AnonymousCreateParameter { report_in_path: false } | LifetimeElisionKind::Infer => { // FIXME: With `AnonymousCreateParameter`, we need to create a new lifetime parameter here @@ -1105,7 +1283,7 @@ pub(crate) fn substs_from_args_and_bindings( } } - Substitution::from_iter(Interner, substs) + GenericArgs::new_from_iter(interner, substs) } fn type_looks_like_const( @@ -1124,3 +1302,17 @@ fn type_looks_like_const( _ => None, } } + +fn unknown_subst<'db>(interner: DbInterner<'db>, def: impl Into) -> GenericArgs<'db> { + let params = generics(interner.db(), def.into()); + GenericArgs::new_from_iter( + interner, + params.iter_id().map(|id| match id { + GenericParamId::TypeParamId(_) => Ty::new_error(interner, ErrorGuaranteed).into(), + GenericParamId::ConstParamId(id) => { + unknown_const_as_generic(const_param_ty_query(interner.db(), id)) + } + GenericParamId::LifetimeParamId(_) => Region::error(interner).into(), + }), + ) +} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver.rs deleted file mode 100644 index abca6b6bb9e5..000000000000 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver.rs +++ /dev/null @@ -1,2220 +0,0 @@ -//! Methods for lowering the HIR to types. There are two main cases here: -//! -//! - Lowering a type reference like `&usize` or `Option` to a -//! type: The entry point for this is `TyLoweringContext::lower_ty`. -//! - Building the type for an item: This happens through the `ty` query. -//! -//! This usually involves resolving names, collecting generic arguments etc. -#![allow(unused)] -// FIXME(next-solver): this should get removed as things get moved to rustc_type_ir from chalk_ir -pub(crate) mod path; - -use std::{ - cell::OnceCell, - iter, mem, - ops::{self, Deref, Not as _}, -}; - -use base_db::Crate; -use either::Either; -use hir_def::hir::generics::GenericParamDataRef; -use hir_def::item_tree::FieldsShape; -use hir_def::{ - AdtId, AssocItemId, CallableDefId, ConstParamId, DefWithBodyId, EnumVariantId, FunctionId, - GenericDefId, GenericParamId, HasModule, ImplId, ItemContainerId, LocalFieldId, Lookup, - StructId, TraitId, TypeAliasId, TypeOrConstParamId, VariantId, - expr_store::{ - ExpressionStore, - path::{GenericArg, Path}, - }, - hir::generics::{TypeOrConstParamData, WherePredicate}, - lang_item::LangItem, - resolver::{HasResolver, LifetimeNs, Resolver, TypeNs}, - signatures::{FunctionSignature, TraitFlags, TypeAliasFlags}, - type_ref::{ - ConstRef, LifetimeRefId, LiteralConstRef, PathId, TraitBoundModifier, - TraitRef as HirTraitRef, TypeBound, TypeRef, TypeRefId, - }, -}; -use hir_def::{ConstId, LifetimeParamId, StaticId, TypeParamId}; -use hir_expand::name::Name; -use intern::{Symbol, sym}; -use la_arena::{Arena, ArenaMap, Idx}; -use path::{PathDiagnosticCallback, PathLoweringContext}; -use rustc_ast_ir::Mutability; -use rustc_hash::FxHashSet; -use rustc_pattern_analysis::Captures; -use rustc_type_ir::{ - AliasTyKind, ConstKind, DebruijnIndex, ExistentialPredicate, ExistentialProjection, - ExistentialTraitRef, FnSig, OutlivesPredicate, - TyKind::{self}, - TypeVisitableExt, - inherent::{GenericArg as _, GenericArgs as _, IntoKind as _, Region as _, SliceLike, Ty as _}, -}; -use rustc_type_ir::{TypeFoldable, TypeFolder, Upcast}; -use salsa::plumbing::AsId; -use smallvec::{SmallVec, smallvec}; -use stdx::never; -use triomphe::Arc; - -use crate::ValueTyDefId; -use crate::next_solver::ParamConst; -use crate::{ - FnAbi, ImplTraitId, Interner, ParamKind, TraitEnvironment, TyDefId, TyLoweringDiagnostic, - TyLoweringDiagnosticKind, - consteval::{intern_const_ref, path_to_const, unknown_const_as_generic}, - db::HirDatabase, - generics::{Generics, generics, trait_self_param_idx}, - lower::{Diagnostics, PathDiagnosticCallbackData, create_diagnostics}, - next_solver::{ - AdtDef, AliasTy, Binder, BoundExistentialPredicates, BoundRegionKind, BoundTyKind, - BoundVarKind, BoundVarKinds, Clause, Clauses, Const, DbInterner, EarlyBinder, - EarlyParamRegion, ErrorGuaranteed, GenericArgs, ParamEnv, PolyFnSig, Predicate, Region, - SolverDefId, TraitPredicate, TraitRef, Ty, Tys, - abi::Safety, - mapping::{ChalkToNextSolver, convert_ty_for_result}, - }, -}; - -#[derive(PartialEq, Eq, Debug, Hash)] -pub struct ImplTraits<'db> { - pub(crate) impl_traits: Arena>, -} - -#[derive(PartialEq, Eq, Debug, Hash)] -pub struct ImplTrait<'db> { - pub(crate) predicates: Vec>, -} - -pub type ImplTraitIdx<'db> = Idx>; - -#[derive(Debug, Default)] -struct ImplTraitLoweringState<'db> { - /// When turning `impl Trait` into opaque types, we have to collect the - /// bounds at the same time to get the IDs correct (without becoming too - /// complicated). - mode: ImplTraitLoweringMode, - // This is structured as a struct with fields and not as an enum because it helps with the borrow checker. - opaque_type_data: Arena>, - param_and_variable_counter: u16, -} -impl<'db> ImplTraitLoweringState<'db> { - fn new(mode: ImplTraitLoweringMode) -> ImplTraitLoweringState<'db> { - Self { mode, opaque_type_data: Arena::new(), param_and_variable_counter: 0 } - } -} - -#[derive(Debug, Clone)] -pub enum LifetimeElisionKind<'db> { - /// Create a new anonymous lifetime parameter and reference it. - /// - /// If `report_in_path`, report an error when encountering lifetime elision in a path: - /// ```compile_fail - /// struct Foo<'a> { x: &'a () } - /// async fn foo(x: Foo) {} - /// ``` - /// - /// Note: the error should not trigger when the elided lifetime is in a pattern or - /// expression-position path: - /// ``` - /// struct Foo<'a> { x: &'a () } - /// async fn foo(Foo { x: _ }: Foo<'_>) {} - /// ``` - AnonymousCreateParameter { report_in_path: bool }, - - /// Replace all anonymous lifetimes by provided lifetime. - Elided(Region<'db>), - - /// Give a hard error when either `&` or `'_` is written. Used to - /// rule out things like `where T: Foo<'_>`. Does not imply an - /// error on default object bounds (e.g., `Box`). - AnonymousReportError, - - /// Resolves elided lifetimes to `'static` if there are no other lifetimes in scope, - /// otherwise give a warning that the previous behavior of introducing a new early-bound - /// lifetime is a bug and will be removed (if `only_lint` is enabled). - StaticIfNoLifetimeInScope { only_lint: bool }, - - /// Signal we cannot find which should be the anonymous lifetime. - ElisionFailure, - - /// Infer all elided lifetimes. - Infer, -} - -impl<'db> LifetimeElisionKind<'db> { - #[inline] - pub(crate) fn for_const( - interner: DbInterner<'db>, - const_parent: ItemContainerId, - ) -> LifetimeElisionKind<'db> { - match const_parent { - ItemContainerId::ExternBlockId(_) | ItemContainerId::ModuleId(_) => { - LifetimeElisionKind::Elided(Region::new_static(interner)) - } - ItemContainerId::ImplId(_) => { - LifetimeElisionKind::StaticIfNoLifetimeInScope { only_lint: true } - } - ItemContainerId::TraitId(_) => { - LifetimeElisionKind::StaticIfNoLifetimeInScope { only_lint: false } - } - } - } - - #[inline] - pub(crate) fn for_fn_params(data: &FunctionSignature) -> LifetimeElisionKind<'db> { - LifetimeElisionKind::AnonymousCreateParameter { report_in_path: data.is_async() } - } - - #[inline] - pub(crate) fn for_fn_ret(interner: DbInterner<'db>) -> LifetimeElisionKind<'db> { - // FIXME: We should use the elided lifetime here, or `ElisionFailure`. - LifetimeElisionKind::Elided(Region::error(interner)) - } -} - -#[derive(Debug)] -pub struct TyLoweringContext<'db, 'a> { - pub db: &'db dyn HirDatabase, - interner: DbInterner<'db>, - resolver: &'a Resolver<'db>, - store: &'a ExpressionStore, - def: GenericDefId, - generics: OnceCell, - in_binders: DebruijnIndex, - impl_trait_mode: ImplTraitLoweringState<'db>, - /// Tracks types with explicit `?Sized` bounds. - pub(crate) unsized_types: FxHashSet>, - pub(crate) diagnostics: Vec, - lifetime_elision: LifetimeElisionKind<'db>, - /// We disallow referencing generic parameters that have an index greater than or equal to this number. - disallow_params_after: u32, -} - -impl<'db, 'a> TyLoweringContext<'db, 'a> { - pub fn new( - db: &'db dyn HirDatabase, - resolver: &'a Resolver<'db>, - store: &'a ExpressionStore, - def: GenericDefId, - lifetime_elision: LifetimeElisionKind<'db>, - ) -> Self { - let impl_trait_mode = ImplTraitLoweringState::new(ImplTraitLoweringMode::Disallowed); - let in_binders = DebruijnIndex::ZERO; - Self { - db, - interner: DbInterner::new_with(db, Some(resolver.krate()), None), - resolver, - def, - generics: Default::default(), - store, - in_binders, - impl_trait_mode, - unsized_types: FxHashSet::default(), - diagnostics: Vec::new(), - lifetime_elision, - disallow_params_after: u32::MAX, - } - } - - pub(crate) fn set_lifetime_elision(&mut self, lifetime_elision: LifetimeElisionKind<'db>) { - self.lifetime_elision = lifetime_elision; - } - - pub(crate) fn with_debruijn( - &mut self, - debruijn: DebruijnIndex, - f: impl FnOnce(&mut TyLoweringContext<'db, '_>) -> T, - ) -> T { - let old_debruijn = mem::replace(&mut self.in_binders, debruijn); - let result = f(self); - self.in_binders = old_debruijn; - result - } - - pub(crate) fn with_shifted_in( - &mut self, - debruijn: DebruijnIndex, - f: impl FnOnce(&mut TyLoweringContext<'db, '_>) -> T, - ) -> T { - self.with_debruijn(self.in_binders.shifted_in(debruijn.as_u32()), f) - } - - pub(crate) fn with_impl_trait_mode(self, impl_trait_mode: ImplTraitLoweringMode) -> Self { - Self { impl_trait_mode: ImplTraitLoweringState::new(impl_trait_mode), ..self } - } - - pub(crate) fn impl_trait_mode(&mut self, impl_trait_mode: ImplTraitLoweringMode) -> &mut Self { - self.impl_trait_mode = ImplTraitLoweringState::new(impl_trait_mode); - self - } - - pub(crate) fn disallow_params_after(&mut self, after: u32) { - self.disallow_params_after = after; - } - - pub(crate) fn push_diagnostic(&mut self, type_ref: TypeRefId, kind: TyLoweringDiagnosticKind) { - self.diagnostics.push(TyLoweringDiagnostic { source: type_ref, kind }); - } -} - -#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)] -pub(crate) enum ImplTraitLoweringMode { - /// `impl Trait` gets lowered into an opaque type that doesn't unify with - /// anything except itself. This is used in places where values flow 'out', - /// i.e. for arguments of the function we're currently checking, and return - /// types of functions we're calling. - Opaque, - /// `impl Trait` is disallowed and will be an error. - #[default] - Disallowed, -} - -impl<'db, 'a> TyLoweringContext<'db, 'a> { - pub fn lower_ty(&mut self, type_ref: TypeRefId) -> Ty<'db> { - self.lower_ty_ext(type_ref).0 - } - - pub(crate) fn lower_const(&mut self, const_ref: ConstRef, const_type: Ty<'db>) -> Const<'db> { - let const_ref = &self.store[const_ref.expr]; - match const_ref { - hir_def::hir::Expr::Path(path) => { - path_to_const(self.db, self.resolver, path, || self.generics(), const_type) - .unwrap_or_else(|| unknown_const(const_type)) - } - hir_def::hir::Expr::Literal(literal) => intern_const_ref( - self.db, - &match *literal { - hir_def::hir::Literal::Float(_, _) - | hir_def::hir::Literal::String(_) - | hir_def::hir::Literal::ByteString(_) - | hir_def::hir::Literal::CString(_) => LiteralConstRef::Unknown, - hir_def::hir::Literal::Char(c) => LiteralConstRef::Char(c), - hir_def::hir::Literal::Bool(b) => LiteralConstRef::Bool(b), - hir_def::hir::Literal::Int(val, _) => LiteralConstRef::Int(val), - hir_def::hir::Literal::Uint(val, _) => LiteralConstRef::UInt(val), - }, - const_type, - self.resolver.krate(), - ), - hir_def::hir::Expr::UnaryOp { expr: inner_expr, op: hir_def::hir::UnaryOp::Neg } => { - if let hir_def::hir::Expr::Literal(literal) = &self.store[*inner_expr] { - // Only handle negation for signed integers and floats - match literal { - hir_def::hir::Literal::Int(_, _) | hir_def::hir::Literal::Float(_, _) => { - if let Some(negated_literal) = literal.clone().negate() { - intern_const_ref( - self.db, - &negated_literal.into(), - const_type, - self.resolver.krate(), - ) - } else { - unknown_const(const_type) - } - } - // For unsigned integers, chars, bools, etc., negation is not meaningful - _ => unknown_const(const_type), - } - } else { - unknown_const(const_type) - } - } - _ => unknown_const(const_type), - } - } - - pub(crate) fn lower_path_as_const(&mut self, path: &Path, const_type: Ty<'db>) -> Const<'db> { - path_to_const(self.db, self.resolver, path, || self.generics(), const_type) - .unwrap_or_else(|| unknown_const(const_type)) - } - - fn generics(&self) -> &Generics { - self.generics.get_or_init(|| generics(self.db, self.def)) - } - - fn type_param(&mut self, id: TypeParamId, index: u32, name: Symbol) -> Ty<'db> { - if index >= self.disallow_params_after { - // FIXME: Report an error. - Ty::new_error(self.interner, ErrorGuaranteed) - } else { - Ty::new_param(self.interner, id, index, name) - } - } - - fn const_param(&mut self, id: ConstParamId, index: u32) -> Const<'db> { - if index >= self.disallow_params_after { - // FIXME: Report an error. - Const::error(self.interner) - } else { - Const::new_param(self.interner, ParamConst { id, index }) - } - } - - fn region_param(&mut self, id: LifetimeParamId, index: u32) -> Region<'db> { - if index >= self.disallow_params_after { - // FIXME: Report an error. - Region::error(self.interner) - } else { - Region::new_early_param(self.interner, EarlyParamRegion { id, index }) - } - } - - #[tracing::instrument(skip(self), ret)] - pub fn lower_ty_ext(&mut self, type_ref_id: TypeRefId) -> (Ty<'db>, Option) { - let interner = self.interner; - let mut res = None; - let type_ref = &self.store[type_ref_id]; - tracing::debug!(?type_ref); - let ty = match type_ref { - TypeRef::Never => Ty::new(interner, TyKind::Never), - TypeRef::Tuple(inner) => { - let inner_tys = inner.iter().map(|&tr| self.lower_ty(tr)); - Ty::new_tup_from_iter(interner, inner_tys) - } - TypeRef::Path(path) => { - let (ty, res_) = - self.lower_path(path, PathId::from_type_ref_unchecked(type_ref_id)); - res = res_; - ty - } - &TypeRef::TypeParam(type_param_id) => { - res = Some(TypeNs::GenericParam(type_param_id)); - - let generics = self.generics(); - let (idx, data) = - generics.type_or_const_param(type_param_id.into()).expect("matching generics"); - let type_data = match data { - TypeOrConstParamData::TypeParamData(ty) => ty, - _ => unreachable!(), - }; - self.type_param( - type_param_id, - idx as u32, - type_data - .name - .as_ref() - .map_or_else(|| sym::MISSING_NAME.clone(), |d| d.symbol().clone()), - ) - } - &TypeRef::RawPtr(inner, mutability) => { - let inner_ty = self.lower_ty(inner); - Ty::new(interner, TyKind::RawPtr(inner_ty, lower_mutability(mutability))) - } - TypeRef::Array(array) => { - let inner_ty = self.lower_ty(array.ty); - let const_len = self.lower_const(array.len, Ty::new_usize(interner)); - Ty::new_array_with_const_len(interner, inner_ty, const_len) - } - &TypeRef::Slice(inner) => { - let inner_ty = self.lower_ty(inner); - Ty::new_slice(interner, inner_ty) - } - TypeRef::Reference(ref_) => { - let inner_ty = self.lower_ty(ref_.ty); - // FIXME: It should infer the eldided lifetimes instead of stubbing with error - let lifetime = ref_ - .lifetime - .map_or_else(|| Region::error(interner), |lr| self.lower_lifetime(lr)); - Ty::new_ref(interner, lifetime, inner_ty, lower_mutability(ref_.mutability)) - } - TypeRef::Placeholder => Ty::new_error(interner, ErrorGuaranteed), - TypeRef::Fn(fn_) => { - let substs = self.with_shifted_in( - DebruijnIndex::from_u32(1), - |ctx: &mut TyLoweringContext<'_, '_>| { - Tys::new_from_iter( - interner, - fn_.params.iter().map(|&(_, tr)| ctx.lower_ty(tr)), - ) - }, - ); - Ty::new_fn_ptr( - interner, - Binder::dummy(FnSig { - abi: fn_.abi.as_ref().map_or(FnAbi::Rust, FnAbi::from_symbol), - safety: if fn_.is_unsafe { Safety::Unsafe } else { Safety::Safe }, - c_variadic: fn_.is_varargs, - inputs_and_output: substs, - }), - ) - } - TypeRef::DynTrait(bounds) => self.lower_dyn_trait(bounds), - TypeRef::ImplTrait(bounds) => { - match self.impl_trait_mode.mode { - ImplTraitLoweringMode::Opaque => { - let origin = match self.resolver.generic_def() { - Some(GenericDefId::FunctionId(it)) => Either::Left(it), - Some(GenericDefId::TypeAliasId(it)) => Either::Right(it), - _ => panic!( - "opaque impl trait lowering must be in function or type alias" - ), - }; - - // this dance is to make sure the data is in the right - // place even if we encounter more opaque types while - // lowering the bounds - let idx = self - .impl_trait_mode - .opaque_type_data - .alloc(ImplTrait { predicates: Vec::default() }); - - // FIXME(next-solver): this from_raw/into_raw dance isn't nice, but it's minimal - let impl_trait_id = origin.either( - |f| ImplTraitId::ReturnTypeImplTrait(f, Idx::from_raw(idx.into_raw())), - |a| ImplTraitId::TypeAliasImplTrait(a, Idx::from_raw(idx.into_raw())), - ); - let opaque_ty_id: SolverDefId = - self.db.intern_impl_trait_id(impl_trait_id).into(); - - // We don't want to lower the bounds inside the binders - // we're currently in, because they don't end up inside - // those binders. E.g. when we have `impl Trait>`, the `impl OtherTrait` can't refer - // to the self parameter from `impl Trait`, and the - // bounds aren't actually stored nested within each - // other, but separately. So if the `T` refers to a type - // parameter of the outer function, it's just one binder - // away instead of two. - let actual_opaque_type_data = self - .with_debruijn(DebruijnIndex::ZERO, |ctx| { - ctx.lower_impl_trait(opaque_ty_id, bounds, self.resolver.krate()) - }); - self.impl_trait_mode.opaque_type_data[idx] = actual_opaque_type_data; - - let args = GenericArgs::identity_for_item(self.interner, opaque_ty_id); - Ty::new_alias( - self.interner, - AliasTyKind::Opaque, - AliasTy::new_from_args(self.interner, opaque_ty_id, args), - ) - } - ImplTraitLoweringMode::Disallowed => { - // FIXME: report error - Ty::new_error(self.interner, ErrorGuaranteed) - } - } - } - TypeRef::Error => Ty::new_error(self.interner, ErrorGuaranteed), - }; - (ty, res) - } - - /// This is only for `generic_predicates_for_param`, where we can't just - /// lower the self types of the predicates since that could lead to cycles. - /// So we just check here if the `type_ref` resolves to a generic param, and which. - fn lower_ty_only_param(&self, type_ref: TypeRefId) -> Option { - let type_ref = &self.store[type_ref]; - let path = match type_ref { - TypeRef::Path(path) => path, - &TypeRef::TypeParam(idx) => return Some(idx.into()), - _ => return None, - }; - if path.type_anchor().is_some() { - return None; - } - if path.segments().len() > 1 { - return None; - } - let resolution = match self.resolver.resolve_path_in_type_ns(self.db, path) { - Some((it, None, _)) => it, - _ => return None, - }; - match resolution { - TypeNs::GenericParam(param_id) => Some(param_id.into()), - _ => None, - } - } - - #[inline] - fn on_path_diagnostic_callback<'b>(type_ref: TypeRefId) -> PathDiagnosticCallback<'b, 'db> { - PathDiagnosticCallback { - data: Either::Left(PathDiagnosticCallbackData(type_ref)), - callback: |data, this, diag| { - let type_ref = data.as_ref().left().unwrap().0; - this.push_diagnostic(type_ref, TyLoweringDiagnosticKind::PathDiagnostic(diag)) - }, - } - } - - #[inline] - fn at_path(&mut self, path_id: PathId) -> PathLoweringContext<'_, 'a, 'db> { - PathLoweringContext::new( - self, - Self::on_path_diagnostic_callback(path_id.type_ref()), - &self.store[path_id], - ) - } - - pub(crate) fn lower_path(&mut self, path: &Path, path_id: PathId) -> (Ty<'db>, Option) { - // Resolve the path (in type namespace) - if let Some(type_ref) = path.type_anchor() { - let (ty, res) = self.lower_ty_ext(type_ref); - let mut ctx = self.at_path(path_id); - return ctx.lower_ty_relative_path(ty, res, false); - } - - let mut ctx = self.at_path(path_id); - let (resolution, remaining_index) = match ctx.resolve_path_in_type_ns() { - Some(it) => it, - None => return (Ty::new_error(self.interner, ErrorGuaranteed), None), - }; - - if matches!(resolution, TypeNs::TraitId(_)) && remaining_index.is_none() { - // trait object type without dyn - let bound = TypeBound::Path(path_id, TraitBoundModifier::None); - let ty = self.lower_dyn_trait(&[bound]); - return (ty, None); - } - - ctx.lower_partly_resolved_path(resolution, false) - } - - fn lower_trait_ref_from_path( - &mut self, - path_id: PathId, - explicit_self_ty: Ty<'db>, - ) -> Option<(TraitRef<'db>, PathLoweringContext<'_, 'a, 'db>)> { - let mut ctx = self.at_path(path_id); - let resolved = match ctx.resolve_path_in_type_ns_fully()? { - // FIXME(trait_alias): We need to handle trait alias here. - TypeNs::TraitId(tr) => tr, - _ => return None, - }; - Some((ctx.lower_trait_ref_from_resolved_path(resolved, explicit_self_ty, false), ctx)) - } - - fn lower_trait_ref( - &mut self, - trait_ref: &HirTraitRef, - explicit_self_ty: Ty<'db>, - ) -> Option> { - self.lower_trait_ref_from_path(trait_ref.path, explicit_self_ty).map(|it| it.0) - } - - pub(crate) fn lower_where_predicate<'b>( - &'b mut self, - where_predicate: &'b WherePredicate, - ignore_bindings: bool, - generics: &Generics, - predicate_filter: PredicateFilter, - ) -> impl Iterator> + use<'a, 'b, 'db> { - match where_predicate { - WherePredicate::ForLifetime { target, bound, .. } - | WherePredicate::TypeBound { target, bound } => { - if let PredicateFilter::SelfTrait = predicate_filter { - let target_type = &self.store[*target]; - let self_type = 'is_self: { - if let TypeRef::Path(path) = target_type - && path.is_self_type() - { - break 'is_self true; - } - if let TypeRef::TypeParam(param) = target_type - && generics[param.local_id()].is_trait_self() - { - break 'is_self true; - } - false - }; - if !self_type { - return Either::Left(Either::Left(iter::empty())); - } - } - let self_ty = self.lower_ty(*target); - Either::Left(Either::Right(self.lower_type_bound(bound, self_ty, ignore_bindings))) - } - &WherePredicate::Lifetime { bound, target } => { - Either::Right(iter::once(Clause(Predicate::new( - self.interner, - Binder::dummy(rustc_type_ir::PredicateKind::Clause( - rustc_type_ir::ClauseKind::RegionOutlives(OutlivesPredicate( - self.lower_lifetime(bound), - self.lower_lifetime(target), - )), - )), - )))) - } - } - .into_iter() - } - - pub(crate) fn lower_type_bound<'b>( - &'b mut self, - bound: &'b TypeBound, - self_ty: Ty<'db>, - ignore_bindings: bool, - ) -> impl Iterator> + use<'b, 'a, 'db> { - let interner = self.interner; - let mut assoc_bounds = None; - let mut clause = None; - match bound { - &TypeBound::Path(path, TraitBoundModifier::None) | &TypeBound::ForLifetime(_, path) => { - // FIXME Don't silently drop the hrtb lifetimes here - if let Some((trait_ref, mut ctx)) = self.lower_trait_ref_from_path(path, self_ty) { - // FIXME(sized-hierarchy): Remove this bound modifications once we have implemented - // sized-hierarchy correctly. - let meta_sized = LangItem::MetaSized - .resolve_trait(ctx.ty_ctx().db, ctx.ty_ctx().resolver.krate()); - let pointee_sized = LangItem::PointeeSized - .resolve_trait(ctx.ty_ctx().db, ctx.ty_ctx().resolver.krate()); - if meta_sized.is_some_and(|it| it == trait_ref.def_id.0) { - // Ignore this bound - } else if pointee_sized.is_some_and(|it| it == trait_ref.def_id.0) { - // Regard this as `?Sized` bound - ctx.ty_ctx().unsized_types.insert(self_ty); - } else { - if !ignore_bindings { - assoc_bounds = ctx.assoc_type_bindings_from_type_bound(trait_ref); - } - clause = Some(Clause(Predicate::new( - interner, - Binder::dummy(rustc_type_ir::PredicateKind::Clause( - rustc_type_ir::ClauseKind::Trait(TraitPredicate { - trait_ref, - polarity: rustc_type_ir::PredicatePolarity::Positive, - }), - )), - ))); - } - } - } - &TypeBound::Path(path, TraitBoundModifier::Maybe) => { - let sized_trait = LangItem::Sized.resolve_trait(self.db, self.resolver.krate()); - // Don't lower associated type bindings as the only possible relaxed trait bound - // `?Sized` has no of them. - // If we got another trait here ignore the bound completely. - let trait_id = self - .lower_trait_ref_from_path(path, self_ty) - .map(|(trait_ref, _)| trait_ref.def_id.0); - if trait_id == sized_trait { - self.unsized_types.insert(self_ty); - } - } - &TypeBound::Lifetime(l) => { - let lifetime = self.lower_lifetime(l); - clause = Some(Clause(Predicate::new( - self.interner, - Binder::dummy(rustc_type_ir::PredicateKind::Clause( - rustc_type_ir::ClauseKind::TypeOutlives(OutlivesPredicate( - self_ty, lifetime, - )), - )), - ))); - } - TypeBound::Use(_) | TypeBound::Error => {} - } - clause.into_iter().chain(assoc_bounds.into_iter().flatten()) - } - - fn lower_dyn_trait(&mut self, bounds: &[TypeBound]) -> Ty<'db> { - let interner = self.interner; - // FIXME: we should never create non-existential predicates in the first place - // For now, use an error type so we don't run into dummy binder issues - let self_ty = Ty::new_error(interner, ErrorGuaranteed); - // INVARIANT: The principal trait bound, if present, must come first. Others may be in any - // order but should be in the same order for the same set but possibly different order of - // bounds in the input. - // INVARIANT: If this function returns `DynTy`, there should be at least one trait bound. - // These invariants are utilized by `TyExt::dyn_trait()` and chalk. - let mut lifetime = None; - let bounds = self.with_shifted_in(DebruijnIndex::from_u32(1), |ctx| { - let mut lowered_bounds: Vec< - rustc_type_ir::Binder, ExistentialPredicate>>, - > = Vec::new(); - for b in bounds { - let db = ctx.db; - ctx.lower_type_bound(b, self_ty, false).for_each(|b| { - if let Some(bound) = b - .kind() - .map_bound(|c| match c { - rustc_type_ir::ClauseKind::Trait(t) => { - let id = t.def_id(); - let is_auto = - db.trait_signature(id.0).flags.contains(TraitFlags::AUTO); - if is_auto { - Some(ExistentialPredicate::AutoTrait(t.def_id())) - } else { - Some(ExistentialPredicate::Trait( - ExistentialTraitRef::new_from_args( - interner, - t.def_id(), - GenericArgs::new_from_iter( - interner, - t.trait_ref.args.iter().skip(1), - ), - ), - )) - } - } - rustc_type_ir::ClauseKind::Projection(p) => { - Some(ExistentialPredicate::Projection( - ExistentialProjection::new_from_args( - interner, - p.def_id(), - GenericArgs::new_from_iter( - interner, - p.projection_term.args.iter().skip(1), - ), - p.term, - ), - )) - } - rustc_type_ir::ClauseKind::TypeOutlives(outlives_predicate) => { - lifetime = Some(outlives_predicate.1); - None - } - rustc_type_ir::ClauseKind::RegionOutlives(_) - | rustc_type_ir::ClauseKind::ConstArgHasType(_, _) - | rustc_type_ir::ClauseKind::WellFormed(_) - | rustc_type_ir::ClauseKind::ConstEvaluatable(_) - | rustc_type_ir::ClauseKind::HostEffect(_) - | rustc_type_ir::ClauseKind::UnstableFeature(_) => unreachable!(), - }) - .transpose() - { - lowered_bounds.push(bound); - } - }) - } - - let mut multiple_regular_traits = false; - let mut multiple_same_projection = false; - lowered_bounds.sort_unstable_by(|lhs, rhs| { - use std::cmp::Ordering; - match ((*lhs).skip_binder(), (*rhs).skip_binder()) { - (ExistentialPredicate::Trait(_), ExistentialPredicate::Trait(_)) => { - multiple_regular_traits = true; - // Order doesn't matter - we error - Ordering::Equal - } - ( - ExistentialPredicate::AutoTrait(lhs_id), - ExistentialPredicate::AutoTrait(rhs_id), - ) => lhs_id.0.cmp(&rhs_id.0), - (ExistentialPredicate::Trait(_), _) => Ordering::Less, - (_, ExistentialPredicate::Trait(_)) => Ordering::Greater, - (ExistentialPredicate::AutoTrait(_), _) => Ordering::Less, - (_, ExistentialPredicate::AutoTrait(_)) => Ordering::Greater, - ( - ExistentialPredicate::Projection(lhs), - ExistentialPredicate::Projection(rhs), - ) => { - let lhs_id = match lhs.def_id { - SolverDefId::TypeAliasId(id) => id, - _ => unreachable!(), - }; - let rhs_id = match rhs.def_id { - SolverDefId::TypeAliasId(id) => id, - _ => unreachable!(), - }; - // We only compare the `associated_ty_id`s. We shouldn't have - // multiple bounds for an associated type in the correct Rust code, - // and if we do, we error out. - if lhs_id == rhs_id { - multiple_same_projection = true; - } - lhs_id.as_id().index().cmp(&rhs_id.as_id().index()) - } - } - }); - - if multiple_regular_traits || multiple_same_projection { - return None; - } - - if !lowered_bounds.first().map_or(false, |b| { - matches!( - b.as_ref().skip_binder(), - ExistentialPredicate::Trait(_) | ExistentialPredicate::AutoTrait(_) - ) - }) { - return None; - } - - // As multiple occurrences of the same auto traits *are* permitted, we deduplicate the - // bounds. We shouldn't have repeated elements besides auto traits at this point. - lowered_bounds.dedup(); - - Some(BoundExistentialPredicates::new_from_iter(interner, lowered_bounds)) - }); - - if let Some(bounds) = bounds { - let region = match lifetime { - Some(it) => match it.kind() { - rustc_type_ir::RegionKind::ReBound(db, var) => Region::new_bound( - self.interner, - db.shifted_out_to_binder(DebruijnIndex::from_u32(2)), - var, - ), - _ => it, - }, - None => Region::new_static(self.interner), - }; - Ty::new_dynamic(self.interner, bounds, region) - } else { - // FIXME: report error - // (additional non-auto traits, associated type rebound, or no resolved trait) - Ty::new_error(self.interner, ErrorGuaranteed) - } - } - - fn lower_impl_trait( - &mut self, - def_id: SolverDefId, - bounds: &[TypeBound], - krate: Crate, - ) -> ImplTrait<'db> { - let interner = self.interner; - cov_mark::hit!(lower_rpit); - let args = GenericArgs::identity_for_item(interner, def_id); - let self_ty = Ty::new_alias( - self.interner, - rustc_type_ir::AliasTyKind::Opaque, - AliasTy::new_from_args(interner, def_id, args), - ); - let predicates = self.with_shifted_in(DebruijnIndex::from_u32(1), |ctx| { - let mut predicates = Vec::new(); - for b in bounds { - predicates.extend(ctx.lower_type_bound(b, self_ty, false)); - } - - if !ctx.unsized_types.contains(&self_ty) { - let sized_trait = LangItem::Sized.resolve_trait(self.db, krate); - let sized_clause = sized_trait.map(|trait_id| { - let trait_ref = TraitRef::new_from_args( - interner, - trait_id.into(), - GenericArgs::new_from_iter(interner, [self_ty.into()]), - ); - Clause(Predicate::new( - interner, - Binder::dummy(rustc_type_ir::PredicateKind::Clause( - rustc_type_ir::ClauseKind::Trait(TraitPredicate { - trait_ref, - polarity: rustc_type_ir::PredicatePolarity::Positive, - }), - )), - )) - }); - predicates.extend(sized_clause); - } - predicates.shrink_to_fit(); - predicates - }); - ImplTrait { predicates } - } - - pub(crate) fn lower_lifetime(&mut self, lifetime: LifetimeRefId) -> Region<'db> { - match self.resolver.resolve_lifetime(&self.store[lifetime]) { - Some(resolution) => match resolution { - LifetimeNs::Static => Region::new_static(self.interner), - LifetimeNs::LifetimeParam(id) => { - let idx = match self.generics().lifetime_idx(id) { - None => return Region::error(self.interner), - Some(idx) => idx, - }; - self.region_param(id, idx as u32) - } - }, - None => Region::error(self.interner), - } - } -} - -pub(crate) fn lower_mutability(m: hir_def::type_ref::Mutability) -> Mutability { - match m { - hir_def::type_ref::Mutability::Shared => Mutability::Not, - hir_def::type_ref::Mutability::Mut => Mutability::Mut, - } -} - -fn unknown_const(_ty: Ty<'_>) -> Const<'_> { - Const::new(DbInterner::conjure(), ConstKind::Error(ErrorGuaranteed)) -} - -pub(crate) fn impl_trait_query<'db>( - db: &'db dyn HirDatabase, - impl_id: ImplId, -) -> Option>> { - db.impl_trait_with_diagnostics(impl_id).map(|it| it.0) -} - -pub(crate) fn impl_trait_with_diagnostics_query<'db>( - db: &'db dyn HirDatabase, - impl_id: ImplId, -) -> Option<(EarlyBinder<'db, TraitRef<'db>>, Diagnostics)> { - let impl_data = db.impl_signature(impl_id); - let resolver = impl_id.resolver(db); - let mut ctx = TyLoweringContext::new( - db, - &resolver, - &impl_data.store, - impl_id.into(), - LifetimeElisionKind::AnonymousCreateParameter { report_in_path: true }, - ); - let self_ty = db.impl_self_ty(impl_id).skip_binder(); - let target_trait = impl_data.target_trait.as_ref()?; - let trait_ref = EarlyBinder::bind(ctx.lower_trait_ref(target_trait, self_ty)?); - Some((trait_ref, create_diagnostics(ctx.diagnostics))) -} - -pub(crate) fn return_type_impl_traits<'db>( - db: &'db dyn HirDatabase, - def: hir_def::FunctionId, -) -> Option>>> { - // FIXME unify with fn_sig_for_fn instead of doing lowering twice, maybe - let data = db.function_signature(def); - let resolver = def.resolver(db); - let mut ctx_ret = - TyLoweringContext::new(db, &resolver, &data.store, def.into(), LifetimeElisionKind::Infer) - .with_impl_trait_mode(ImplTraitLoweringMode::Opaque); - if let Some(ret_type) = data.ret_type { - let _ret = ctx_ret.lower_ty(ret_type); - } - let return_type_impl_traits = - ImplTraits { impl_traits: ctx_ret.impl_trait_mode.opaque_type_data }; - if return_type_impl_traits.impl_traits.is_empty() { - None - } else { - Some(Arc::new(EarlyBinder::bind(return_type_impl_traits))) - } -} - -pub(crate) fn type_alias_impl_traits<'db>( - db: &'db dyn HirDatabase, - def: hir_def::TypeAliasId, -) -> Option>>> { - let data = db.type_alias_signature(def); - let resolver = def.resolver(db); - let mut ctx = TyLoweringContext::new( - db, - &resolver, - &data.store, - def.into(), - LifetimeElisionKind::AnonymousReportError, - ) - .with_impl_trait_mode(ImplTraitLoweringMode::Opaque); - if let Some(type_ref) = data.ty { - let _ty = ctx.lower_ty(type_ref); - } - let type_alias_impl_traits = ImplTraits { impl_traits: ctx.impl_trait_mode.opaque_type_data }; - if type_alias_impl_traits.impl_traits.is_empty() { - None - } else { - Some(Arc::new(EarlyBinder::bind(type_alias_impl_traits))) - } -} - -/// Build the declared type of an item. This depends on the namespace; e.g. for -/// `struct Foo(usize)`, we have two types: The type of the struct itself, and -/// the constructor function `(usize) -> Foo` which lives in the values -/// namespace. -pub(crate) fn ty_query<'db>(db: &'db dyn HirDatabase, def: TyDefId) -> EarlyBinder<'db, Ty<'db>> { - let interner = DbInterner::new_with(db, None, None); - match def { - TyDefId::BuiltinType(it) => EarlyBinder::bind(Ty::from_builtin_type(interner, it)), - TyDefId::AdtId(it) => EarlyBinder::bind(Ty::new_adt( - interner, - it, - GenericArgs::identity_for_item(interner, it.into()), - )), - TyDefId::TypeAliasId(it) => db.type_for_type_alias_with_diagnostics(it).0, - } -} - -/// Build the declared type of a function. This should not need to look at the -/// function body. -fn type_for_fn<'db>(db: &'db dyn HirDatabase, def: FunctionId) -> EarlyBinder<'db, Ty<'db>> { - let interner = DbInterner::new_with(db, None, None); - EarlyBinder::bind(Ty::new_fn_def( - interner, - CallableDefId::FunctionId(def).into(), - GenericArgs::identity_for_item(interner, def.into()), - )) -} - -/// Build the declared type of a const. -fn type_for_const<'db>(db: &'db dyn HirDatabase, def: ConstId) -> EarlyBinder<'db, Ty<'db>> { - let resolver = def.resolver(db); - let data = db.const_signature(def); - let parent = def.loc(db).container; - let mut ctx = TyLoweringContext::new( - db, - &resolver, - &data.store, - def.into(), - LifetimeElisionKind::AnonymousReportError, - ); - ctx.set_lifetime_elision(LifetimeElisionKind::for_const(ctx.interner, parent)); - EarlyBinder::bind(ctx.lower_ty(data.type_ref)) -} - -/// Build the declared type of a static. -fn type_for_static<'db>(db: &'db dyn HirDatabase, def: StaticId) -> EarlyBinder<'db, Ty<'db>> { - let resolver = def.resolver(db); - let module = resolver.module(); - let interner = DbInterner::new_with(db, Some(module.krate()), module.containing_block()); - let data = db.static_signature(def); - let parent = def.loc(db).container; - let mut ctx = TyLoweringContext::new( - db, - &resolver, - &data.store, - def.into(), - LifetimeElisionKind::AnonymousReportError, - ); - ctx.set_lifetime_elision(LifetimeElisionKind::Elided(Region::new_static(ctx.interner))); - EarlyBinder::bind(ctx.lower_ty(data.type_ref)) -} - -/// Build the type of a tuple struct constructor. -fn type_for_struct_constructor<'db>( - db: &'db dyn HirDatabase, - def: StructId, -) -> Option>> { - let struct_data = def.fields(db); - match struct_data.shape { - FieldsShape::Record => None, - FieldsShape::Unit => Some(type_for_adt(db, def.into())), - FieldsShape::Tuple => { - let interner = DbInterner::new_with(db, None, None); - Some(EarlyBinder::bind(Ty::new_fn_def( - interner, - CallableDefId::StructId(def).into(), - GenericArgs::identity_for_item(interner, def.into()), - ))) - } - } -} - -/// Build the type of a tuple enum variant constructor. -fn type_for_enum_variant_constructor<'db>( - db: &'db dyn HirDatabase, - def: EnumVariantId, -) -> Option>> { - let struct_data = def.fields(db); - match struct_data.shape { - FieldsShape::Record => None, - FieldsShape::Unit => Some(type_for_adt(db, def.loc(db).parent.into())), - FieldsShape::Tuple => { - let interner = DbInterner::new_with(db, None, None); - Some(EarlyBinder::bind(Ty::new_fn_def( - interner, - CallableDefId::EnumVariantId(def).into(), - GenericArgs::identity_for_item(interner, def.loc(db).parent.into()), - ))) - } - } -} - -pub(crate) fn value_ty_query<'db>( - db: &'db dyn HirDatabase, - def: ValueTyDefId, -) -> Option>> { - match def { - ValueTyDefId::FunctionId(it) => Some(type_for_fn(db, it)), - ValueTyDefId::StructId(it) => type_for_struct_constructor(db, it), - ValueTyDefId::UnionId(it) => Some(type_for_adt(db, it.into())), - ValueTyDefId::EnumVariantId(it) => type_for_enum_variant_constructor(db, it), - ValueTyDefId::ConstId(it) => Some(type_for_const(db, it)), - ValueTyDefId::StaticId(it) => Some(type_for_static(db, it)), - } -} - -pub(crate) fn type_for_type_alias_with_diagnostics_query<'db>( - db: &'db dyn HirDatabase, - t: TypeAliasId, -) -> (EarlyBinder<'db, Ty<'db>>, Diagnostics) { - let type_alias_data = db.type_alias_signature(t); - let mut diags = None; - let resolver = t.resolver(db); - let interner = DbInterner::new_with(db, Some(resolver.krate()), None); - let inner = if type_alias_data.flags.contains(TypeAliasFlags::IS_EXTERN) { - EarlyBinder::bind(Ty::new_foreign(interner, t.into())) - } else { - let mut ctx = TyLoweringContext::new( - db, - &resolver, - &type_alias_data.store, - t.into(), - LifetimeElisionKind::AnonymousReportError, - ) - .with_impl_trait_mode(ImplTraitLoweringMode::Opaque); - let res = EarlyBinder::bind( - type_alias_data - .ty - .map(|type_ref| ctx.lower_ty(type_ref)) - .unwrap_or_else(|| Ty::new_error(interner, ErrorGuaranteed)), - ); - diags = create_diagnostics(ctx.diagnostics); - res - }; - (inner, diags) -} - -pub(crate) fn type_for_type_alias_with_diagnostics_cycle_result<'db>( - db: &'db dyn HirDatabase, - _adt: TypeAliasId, -) -> (EarlyBinder<'db, Ty<'db>>, Diagnostics) { - (EarlyBinder::bind(Ty::new_error(DbInterner::new_with(db, None, None), ErrorGuaranteed)), None) -} - -pub(crate) fn impl_self_ty_query<'db>( - db: &'db dyn HirDatabase, - impl_id: ImplId, -) -> EarlyBinder<'db, Ty<'db>> { - db.impl_self_ty_with_diagnostics(impl_id).0 -} - -pub(crate) fn impl_self_ty_with_diagnostics_query<'db>( - db: &'db dyn HirDatabase, - impl_id: ImplId, -) -> (EarlyBinder<'db, Ty<'db>>, Diagnostics) { - let resolver = impl_id.resolver(db); - let interner = DbInterner::new_with(db, Some(resolver.krate()), None); - - let impl_data = db.impl_signature(impl_id); - let mut ctx = TyLoweringContext::new( - db, - &resolver, - &impl_data.store, - impl_id.into(), - LifetimeElisionKind::AnonymousCreateParameter { report_in_path: true }, - ); - let ty = ctx.lower_ty(impl_data.self_ty); - assert!(!ty.has_escaping_bound_vars()); - (EarlyBinder::bind(ty), create_diagnostics(ctx.diagnostics)) -} - -pub(crate) fn impl_self_ty_with_diagnostics_cycle_result( - db: &dyn HirDatabase, - _impl_id: ImplId, -) -> (EarlyBinder<'_, Ty<'_>>, Diagnostics) { - (EarlyBinder::bind(Ty::new_error(DbInterner::new_with(db, None, None), ErrorGuaranteed)), None) -} - -pub(crate) fn const_param_ty_query<'db>(db: &'db dyn HirDatabase, def: ConstParamId) -> Ty<'db> { - db.const_param_ty_with_diagnostics(def).0 -} - -// returns None if def is a type arg -pub(crate) fn const_param_ty_with_diagnostics_query<'db>( - db: &'db dyn HirDatabase, - def: ConstParamId, -) -> (Ty<'db>, Diagnostics) { - let (parent_data, store) = db.generic_params_and_store(def.parent()); - let data = &parent_data[def.local_id()]; - let resolver = def.parent().resolver(db); - let interner = DbInterner::new_with(db, Some(resolver.krate()), None); - let mut ctx = TyLoweringContext::new( - db, - &resolver, - &store, - def.parent(), - LifetimeElisionKind::AnonymousReportError, - ); - let ty = match data { - TypeOrConstParamData::TypeParamData(_) => { - never!(); - Ty::new_error(interner, ErrorGuaranteed) - } - TypeOrConstParamData::ConstParamData(d) => ctx.lower_ty(d.ty), - }; - (ty, create_diagnostics(ctx.diagnostics)) -} - -pub(crate) fn const_param_ty_with_diagnostics_cycle_result<'db>( - db: &'db dyn HirDatabase, - _: crate::db::HirDatabaseData, - def: ConstParamId, -) -> (Ty<'db>, Diagnostics) { - let resolver = def.parent().resolver(db); - let interner = DbInterner::new_with(db, Some(resolver.krate()), None); - (Ty::new_error(interner, ErrorGuaranteed), None) -} - -pub(crate) fn field_types_query<'db>( - db: &'db dyn HirDatabase, - variant_id: VariantId, -) -> Arc>>> { - db.field_types_with_diagnostics(variant_id).0 -} - -/// Build the type of all specific fields of a struct or enum variant. -pub(crate) fn field_types_with_diagnostics_query<'db>( - db: &'db dyn HirDatabase, - variant_id: VariantId, -) -> (Arc>>>, Diagnostics) { - let var_data = variant_id.fields(db); - let fields = var_data.fields(); - if fields.is_empty() { - return (Arc::new(ArenaMap::default()), None); - } - - let (resolver, def): (_, GenericDefId) = match variant_id { - VariantId::StructId(it) => (it.resolver(db), it.into()), - VariantId::UnionId(it) => (it.resolver(db), it.into()), - VariantId::EnumVariantId(it) => (it.resolver(db), it.lookup(db).parent.into()), - }; - let mut res = ArenaMap::default(); - let mut ctx = TyLoweringContext::new( - db, - &resolver, - &var_data.store, - def, - LifetimeElisionKind::AnonymousReportError, - ); - for (field_id, field_data) in var_data.fields().iter() { - res.insert(field_id, EarlyBinder::bind(ctx.lower_ty(field_data.type_ref))); - } - (Arc::new(res), create_diagnostics(ctx.diagnostics)) -} - -/// This query exists only to be used when resolving short-hand associated types -/// like `T::Item`. -/// -/// See the analogous query in rustc and its comment: -/// -/// This is a query mostly to handle cycles somewhat gracefully; e.g. the -/// following bounds are disallowed: `T: Foo, U: Foo`, but -/// these are fine: `T: Foo, U: Foo<()>`. -#[tracing::instrument(skip(db), ret)] -pub(crate) fn generic_predicates_for_param_query<'db>( - db: &'db dyn HirDatabase, - def: GenericDefId, - param_id: TypeOrConstParamId, - assoc_name: Option, -) -> GenericPredicates<'db> { - let generics = generics(db, def); - let interner = DbInterner::new_with(db, None, None); - let resolver = def.resolver(db); - let mut ctx = TyLoweringContext::new( - db, - &resolver, - generics.store(), - def, - LifetimeElisionKind::AnonymousReportError, - ); - - // we have to filter out all other predicates *first*, before attempting to lower them - let predicate = |pred: &_, ctx: &mut TyLoweringContext<'_, '_>| match pred { - WherePredicate::ForLifetime { target, bound, .. } - | WherePredicate::TypeBound { target, bound, .. } => { - let invalid_target = { ctx.lower_ty_only_param(*target) != Some(param_id) }; - if invalid_target { - // FIXME(sized-hierarchy): Revisit and adjust this properly once we have implemented - // sized-hierarchy correctly. - // If this is filtered out without lowering, `?Sized` or `PointeeSized` is not gathered into - // `ctx.unsized_types` - let lower = || -> bool { - match bound { - TypeBound::Path(_, TraitBoundModifier::Maybe) => true, - TypeBound::Path(path, _) | TypeBound::ForLifetime(_, path) => { - let TypeRef::Path(path) = &ctx.store[path.type_ref()] else { - return false; - }; - let Some(pointee_sized) = - LangItem::PointeeSized.resolve_trait(ctx.db, ctx.resolver.krate()) - else { - return false; - }; - // Lower the path directly with `Resolver` instead of PathLoweringContext` - // to prevent diagnostics duplications. - ctx.resolver.resolve_path_in_type_ns_fully(ctx.db, path).is_some_and( - |it| matches!(it, TypeNs::TraitId(tr) if tr == pointee_sized), - ) - } - _ => false, - } - }(); - if lower { - ctx.lower_where_predicate(pred, true, &generics, PredicateFilter::All) - .for_each(drop); - } - return false; - } - - match bound { - &TypeBound::ForLifetime(_, path) | &TypeBound::Path(path, _) => { - // Only lower the bound if the trait could possibly define the associated - // type we're looking for. - let path = &ctx.store[path]; - - let Some(assoc_name) = &assoc_name else { return true }; - let Some(TypeNs::TraitId(tr)) = - resolver.resolve_path_in_type_ns_fully(db, path) - else { - return false; - }; - - rustc_type_ir::elaborate::supertrait_def_ids(interner, tr.into()).any(|tr| { - tr.0.trait_items(db).items.iter().any(|(name, item)| { - matches!(item, AssocItemId::TypeAliasId(_)) && name == assoc_name - }) - }) - } - TypeBound::Use(_) | TypeBound::Lifetime(_) | TypeBound::Error => false, - } - } - WherePredicate::Lifetime { .. } => false, - }; - let mut predicates = Vec::new(); - for maybe_parent_generics in - std::iter::successors(Some(&generics), |generics| generics.parent_generics()) - { - ctx.store = maybe_parent_generics.store(); - for pred in maybe_parent_generics.where_predicates() { - if predicate(pred, &mut ctx) { - predicates.extend(ctx.lower_where_predicate( - pred, - true, - maybe_parent_generics, - PredicateFilter::All, - )); - } - } - } - - let args = GenericArgs::identity_for_item(interner, def.into()); - if !args.is_empty() { - let explicitly_unsized_tys = ctx.unsized_types; - if let Some(implicitly_sized_predicates) = - implicitly_sized_clauses(db, param_id.parent, &explicitly_unsized_tys, &args, &resolver) - { - predicates.extend(implicitly_sized_predicates); - }; - } - GenericPredicates(predicates.is_empty().not().then(|| predicates.into())) -} - -pub(crate) fn generic_predicates_for_param_cycle_result( - _db: &dyn HirDatabase, - _def: GenericDefId, - _param_id: TypeOrConstParamId, - _assoc_name: Option, -) -> GenericPredicates<'_> { - GenericPredicates(None) -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct GenericPredicates<'db>(Option]>>); - -impl<'db> GenericPredicates<'db> { - #[inline] - pub fn instantiate( - &self, - interner: DbInterner<'db>, - args: GenericArgs<'db>, - ) -> Option>> { - self.0 - .as_ref() - .map(|it| EarlyBinder::bind(it.iter().copied()).iter_instantiated(interner, args)) - } - - #[inline] - pub fn instantiate_identity(&self) -> Option>> { - self.0.as_ref().map(|it| it.iter().copied()) - } -} - -impl<'db> ops::Deref for GenericPredicates<'db> { - type Target = [Clause<'db>]; - - fn deref(&self) -> &Self::Target { - self.0.as_deref().unwrap_or(&[]) - } -} - -pub(crate) fn trait_environment_for_body_query( - db: &dyn HirDatabase, - def: DefWithBodyId, -) -> Arc> { - let Some(def) = def.as_generic_def_id(db) else { - let krate = def.module(db).krate(); - return TraitEnvironment::empty(krate); - }; - db.trait_environment(def) -} - -pub(crate) fn trait_environment_query<'db>( - db: &'db dyn HirDatabase, - def: GenericDefId, -) -> Arc> { - let generics = generics(db, def); - if generics.has_no_predicates() && generics.is_empty() { - return TraitEnvironment::empty(def.krate(db)); - } - - let interner = DbInterner::new_with(db, Some(def.krate(db)), None); - let resolver = def.resolver(db); - let mut ctx = TyLoweringContext::new( - db, - &resolver, - generics.store(), - def, - LifetimeElisionKind::AnonymousReportError, - ); - let mut traits_in_scope = Vec::new(); - let mut clauses = Vec::new(); - for maybe_parent_generics in - std::iter::successors(Some(&generics), |generics| generics.parent_generics()) - { - ctx.store = maybe_parent_generics.store(); - for pred in maybe_parent_generics.where_predicates() { - for pred in ctx.lower_where_predicate(pred, false, &generics, PredicateFilter::All) { - if let rustc_type_ir::ClauseKind::Trait(tr) = pred.kind().skip_binder() { - traits_in_scope.push((tr.self_ty(), tr.def_id().0)); - } - clauses.push(pred); - } - } - } - - if let Some(trait_id) = def.assoc_trait_container(db) { - // add `Self: Trait` to the environment in trait - // function default implementations (and speculative code - // inside consts or type aliases) - cov_mark::hit!(trait_self_implements_self); - let trait_ref = TraitRef::identity(ctx.interner, trait_id.into()); - let clause = Clause(Predicate::new( - ctx.interner, - Binder::dummy(rustc_type_ir::PredicateKind::Clause(rustc_type_ir::ClauseKind::Trait( - TraitPredicate { trait_ref, polarity: rustc_type_ir::PredicatePolarity::Positive }, - ))), - )); - clauses.push(clause); - } - - let explicitly_unsized_tys = ctx.unsized_types; - - let sized_trait = LangItem::Sized.resolve_trait(db, resolver.krate()); - if let Some(sized_trait) = sized_trait { - let (mut generics, mut def_id) = - (crate::next_solver::generics::generics(db, def.into()), def); - loop { - let self_idx = trait_self_param_idx(db, def_id); - for (idx, p) in generics.own_params.iter().enumerate() { - if let Some(self_idx) = self_idx - && p.index() as usize == self_idx - { - continue; - } - let GenericParamId::TypeParamId(param_id) = p.id else { - continue; - }; - let idx = idx as u32 + generics.parent_count as u32; - let param_ty = Ty::new_param(ctx.interner, param_id, idx, p.name.clone()); - if explicitly_unsized_tys.contains(¶m_ty) { - continue; - } - let trait_ref = TraitRef::new_from_args( - ctx.interner, - sized_trait.into(), - GenericArgs::new_from_iter(ctx.interner, [param_ty.into()]), - ); - let clause = Clause(Predicate::new( - ctx.interner, - Binder::dummy(rustc_type_ir::PredicateKind::Clause( - rustc_type_ir::ClauseKind::Trait(TraitPredicate { - trait_ref, - polarity: rustc_type_ir::PredicatePolarity::Positive, - }), - )), - )); - clauses.push(clause); - } - - if let Some(g) = generics.parent { - generics = crate::next_solver::generics::generics(db, g.into()); - def_id = g; - } else { - break; - } - } - } - - let clauses = rustc_type_ir::elaborate::elaborate(ctx.interner, clauses); - let clauses = Clauses::new_from_iter(ctx.interner, clauses); - let env = ParamEnv { clauses }; - - TraitEnvironment::new(resolver.krate(), None, traits_in_scope.into_boxed_slice(), env) -} - -#[derive(Copy, Clone, Debug)] -pub(crate) enum PredicateFilter { - SelfTrait, - All, -} - -/// Resolve the where clause(s) of an item with generics. -#[tracing::instrument(skip(db))] -pub(crate) fn generic_predicates_query<'db>( - db: &'db dyn HirDatabase, - def: GenericDefId, -) -> GenericPredicates<'db> { - generic_predicates_filtered_by(db, def, PredicateFilter::All, |_| true).0 -} - -pub(crate) fn generic_predicates_without_parent_query<'db>( - db: &'db dyn HirDatabase, - def: GenericDefId, -) -> GenericPredicates<'db> { - generic_predicates_filtered_by(db, def, PredicateFilter::All, |d| d == def).0 -} - -/// Resolve the where clause(s) of an item with generics, -/// except the ones inherited from the parent -pub(crate) fn generic_predicates_without_parent_with_diagnostics_query<'db>( - db: &'db dyn HirDatabase, - def: GenericDefId, -) -> (GenericPredicates<'db>, Diagnostics) { - generic_predicates_filtered_by(db, def, PredicateFilter::All, |d| d == def) -} - -/// Resolve the where clause(s) of an item with generics, -/// with a given filter -#[tracing::instrument(skip(db, filter), ret)] -pub(crate) fn generic_predicates_filtered_by<'db, F>( - db: &'db dyn HirDatabase, - def: GenericDefId, - predicate_filter: PredicateFilter, - filter: F, -) -> (GenericPredicates<'db>, Diagnostics) -where - F: Fn(GenericDefId) -> bool, -{ - let generics = generics(db, def); - let resolver = def.resolver(db); - let interner = DbInterner::new_with(db, Some(resolver.krate()), None); - let mut ctx = TyLoweringContext::new( - db, - &resolver, - generics.store(), - def, - LifetimeElisionKind::AnonymousReportError, - ); - - let mut predicates = Vec::new(); - for maybe_parent_generics in - std::iter::successors(Some(&generics), |generics| generics.parent_generics()) - { - ctx.store = maybe_parent_generics.store(); - for pred in maybe_parent_generics.where_predicates() { - tracing::debug!(?pred); - if filter(maybe_parent_generics.def()) { - // We deliberately use `generics` and not `maybe_parent_generics` here. This is not a mistake! - // If we use the parent generics - predicates.extend(ctx.lower_where_predicate( - pred, - false, - maybe_parent_generics, - predicate_filter, - )); - } - } - } - - let explicitly_unsized_tys = ctx.unsized_types; - - let sized_trait = LangItem::Sized.resolve_trait(db, resolver.krate()); - if let Some(sized_trait) = sized_trait { - let (mut generics, mut def_id) = - (crate::next_solver::generics::generics(db, def.into()), def); - loop { - if filter(def_id) { - let self_idx = trait_self_param_idx(db, def_id); - for (idx, p) in generics.own_params.iter().enumerate() { - if let Some(self_idx) = self_idx - && p.index() as usize == self_idx - { - continue; - } - let GenericParamId::TypeParamId(param_id) = p.id else { - continue; - }; - let idx = idx as u32 + generics.parent_count as u32; - let param_ty = Ty::new_param(interner, param_id, idx, p.name.clone()); - if explicitly_unsized_tys.contains(¶m_ty) { - continue; - } - let trait_ref = TraitRef::new_from_args( - interner, - sized_trait.into(), - GenericArgs::new_from_iter(interner, [param_ty.into()]), - ); - let clause = Clause(Predicate::new( - interner, - Binder::dummy(rustc_type_ir::PredicateKind::Clause( - rustc_type_ir::ClauseKind::Trait(TraitPredicate { - trait_ref, - polarity: rustc_type_ir::PredicatePolarity::Positive, - }), - )), - )); - predicates.push(clause); - } - } - - if let Some(g) = generics.parent { - generics = crate::next_solver::generics::generics(db, g.into()); - def_id = g; - } else { - break; - } - } - } - - // FIXME: rustc gathers more predicates by recursing through resulting trait predicates. - // See https://github.com/rust-lang/rust/blob/76c5ed2847cdb26ef2822a3a165d710f6b772217/compiler/rustc_hir_analysis/src/collect/predicates_of.rs#L689-L715 - - ( - GenericPredicates(predicates.is_empty().not().then(|| predicates.into())), - create_diagnostics(ctx.diagnostics), - ) -} - -/// Generate implicit `: Sized` predicates for all generics that has no `?Sized` bound. -/// Exception is Self of a trait def. -fn implicitly_sized_clauses<'a, 'subst, 'db>( - db: &'db dyn HirDatabase, - def: GenericDefId, - explicitly_unsized_tys: &'a FxHashSet>, - args: &'subst GenericArgs<'db>, - resolver: &Resolver<'db>, -) -> Option> + Captures<'a> + Captures<'subst>> { - let interner = DbInterner::new_with(db, Some(resolver.krate()), None); - let sized_trait = LangItem::Sized.resolve_trait(db, resolver.krate())?; - - let trait_self_idx = trait_self_param_idx(db, def); - - Some( - args.iter() - .enumerate() - .filter_map( - move |(idx, generic_arg)| { - if Some(idx) == trait_self_idx { None } else { Some(generic_arg) } - }, - ) - .filter_map(|generic_arg| generic_arg.as_type()) - .filter(move |self_ty| !explicitly_unsized_tys.contains(self_ty)) - .map(move |self_ty| { - let trait_ref = TraitRef::new_from_args( - interner, - sized_trait.into(), - GenericArgs::new_from_iter(interner, [self_ty.into()]), - ); - Clause(Predicate::new( - interner, - Binder::dummy(rustc_type_ir::PredicateKind::Clause( - rustc_type_ir::ClauseKind::Trait(TraitPredicate { - trait_ref, - polarity: rustc_type_ir::PredicatePolarity::Positive, - }), - )), - )) - }), - ) -} - -pub(crate) fn make_binders<'db, T: rustc_type_ir::TypeVisitable>>( - interner: DbInterner<'db>, - generics: &Generics, - value: T, -) -> Binder<'db, T> { - Binder::bind_with_vars( - value, - BoundVarKinds::new_from_iter( - interner, - generics.iter_id().map(|x| match x { - hir_def::GenericParamId::ConstParamId(_) => BoundVarKind::Const, - hir_def::GenericParamId::TypeParamId(_) => BoundVarKind::Ty(BoundTyKind::Anon), - hir_def::GenericParamId::LifetimeParamId(_) => { - BoundVarKind::Region(BoundRegionKind::Anon) - } - }), - ), - ) -} - -/// Checks if the provided generic arg matches its expected kind, then lower them via -/// provided closures. Use unknown if there was kind mismatch. -/// -pub(crate) fn lower_generic_arg<'a, 'db, T>( - db: &'db dyn HirDatabase, - kind_id: GenericParamId, - arg: &'a GenericArg, - this: &mut T, - store: &ExpressionStore, - for_type: impl FnOnce(&mut T, TypeRefId) -> Ty<'db> + 'a, - for_const: impl FnOnce(&mut T, &ConstRef, Ty<'db>) -> Const<'db> + 'a, - for_const_ty_path_fallback: impl FnOnce(&mut T, &Path, Ty<'db>) -> Const<'db> + 'a, - for_lifetime: impl FnOnce(&mut T, &LifetimeRefId) -> Region<'db> + 'a, -) -> crate::next_solver::GenericArg<'db> { - let interner = DbInterner::new_with(db, None, None); - let kind = match kind_id { - GenericParamId::TypeParamId(_) => ParamKind::Type, - GenericParamId::ConstParamId(id) => { - let ty = db.const_param_ty(id); - ParamKind::Const(ty) - } - GenericParamId::LifetimeParamId(_) => ParamKind::Lifetime, - }; - match (arg, kind) { - (GenericArg::Type(type_ref), ParamKind::Type) => for_type(this, *type_ref).into(), - (GenericArg::Const(c), ParamKind::Const(c_ty)) => { - for_const(this, c, c_ty.to_nextsolver(interner)).into() - } - (GenericArg::Lifetime(lifetime_ref), ParamKind::Lifetime) => { - for_lifetime(this, lifetime_ref).into() - } - (GenericArg::Const(_), ParamKind::Type) => Ty::new_error(interner, ErrorGuaranteed).into(), - (GenericArg::Lifetime(_), ParamKind::Type) => { - Ty::new_error(interner, ErrorGuaranteed).into() - } - (GenericArg::Type(t), ParamKind::Const(c_ty)) => match &store[*t] { - TypeRef::Path(p) => { - for_const_ty_path_fallback(this, p, c_ty.to_nextsolver(interner)).into() - } - _ => unknown_const_as_generic(c_ty.to_nextsolver(interner)), - }, - (GenericArg::Lifetime(_), ParamKind::Const(c_ty)) => { - unknown_const(c_ty.to_nextsolver(interner)).into() - } - (GenericArg::Type(_), ParamKind::Lifetime) => Region::error(interner).into(), - (GenericArg::Const(_), ParamKind::Lifetime) => Region::error(interner).into(), - } -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct GenericDefaults<'db>( - Option>>]>>, -); - -impl<'db> GenericDefaults<'db> { - #[inline] - pub fn get(&self, idx: usize) -> Option>> { - self.0.as_ref()?[idx] - } -} - -pub(crate) fn generic_defaults_query( - db: &dyn HirDatabase, - def: GenericDefId, -) -> GenericDefaults<'_> { - db.generic_defaults_ns_with_diagnostics(def).0 -} - -/// Resolve the default type params from generics. -/// -/// Diagnostics are only returned for this `GenericDefId` (returned defaults include parents). -pub(crate) fn generic_defaults_with_diagnostics_query( - db: &dyn HirDatabase, - def: GenericDefId, -) -> (GenericDefaults<'_>, Diagnostics) { - let generic_params = generics(db, def); - if generic_params.is_empty() { - return (GenericDefaults(None), None); - } - let resolver = def.resolver(db); - - let mut ctx = TyLoweringContext::new( - db, - &resolver, - generic_params.store(), - def, - LifetimeElisionKind::AnonymousReportError, - ) - .with_impl_trait_mode(ImplTraitLoweringMode::Disallowed); - let mut idx = 0; - let mut has_any_default = false; - let mut defaults = generic_params - .iter_parents_with_store() - .map(|((id, p), store)| { - ctx.store = store; - let (result, has_default) = handle_generic_param(&mut ctx, idx, id, p, &generic_params); - has_any_default |= has_default; - idx += 1; - result - }) - .collect::>(); - ctx.diagnostics.clear(); // Don't include diagnostics from the parent. - defaults.extend(generic_params.iter_self().map(|(id, p)| { - let (result, has_default) = handle_generic_param(&mut ctx, idx, id, p, &generic_params); - has_any_default |= has_default; - idx += 1; - result - })); - let diagnostics = create_diagnostics(mem::take(&mut ctx.diagnostics)); - let defaults = if has_any_default { - GenericDefaults(Some(Arc::from_iter(defaults))) - } else { - GenericDefaults(None) - }; - return (defaults, diagnostics); - - fn handle_generic_param<'db>( - ctx: &mut TyLoweringContext<'db, '_>, - idx: usize, - id: GenericParamId, - p: GenericParamDataRef<'_>, - generic_params: &Generics, - ) -> (Option>>, bool) { - // Each default can only refer to previous parameters. - // Type variable default referring to parameter coming - // after it is forbidden. - ctx.disallow_params_after(idx as u32); - match p { - GenericParamDataRef::TypeParamData(p) => { - let ty = p.default.map(|ty| ctx.lower_ty(ty)); - (ty.map(|ty| EarlyBinder::bind(ty.into())), p.default.is_some()) - } - GenericParamDataRef::ConstParamData(p) => { - let GenericParamId::ConstParamId(id) = id else { - unreachable!("Unexpected lifetime or type argument") - }; - - let mut val = p.default.map(|c| { - let param_ty = ctx.lower_ty(p.ty); - let c = ctx.lower_const(c, param_ty); - c.into() - }); - (val.map(EarlyBinder::bind), p.default.is_some()) - } - GenericParamDataRef::LifetimeParamData(_) => (None, false), - } - } -} - -pub(crate) fn generic_defaults_with_diagnostics_cycle_result( - _db: &dyn HirDatabase, - _def: GenericDefId, -) -> (GenericDefaults<'_>, Diagnostics) { - (GenericDefaults(None), None) -} - -/// Build the signature of a callable item (function, struct or enum variant). -pub(crate) fn callable_item_signature_query<'db>( - db: &'db dyn HirDatabase, - def: CallableDefId, -) -> EarlyBinder<'db, PolyFnSig<'db>> { - match def { - CallableDefId::FunctionId(f) => fn_sig_for_fn(db, f), - CallableDefId::StructId(s) => fn_sig_for_struct_constructor(db, s), - CallableDefId::EnumVariantId(e) => fn_sig_for_enum_variant_constructor(db, e), - } -} - -fn fn_sig_for_fn<'db>( - db: &'db dyn HirDatabase, - def: FunctionId, -) -> EarlyBinder<'db, PolyFnSig<'db>> { - let data = db.function_signature(def); - let resolver = def.resolver(db); - let interner = DbInterner::new_with(db, Some(resolver.krate()), None); - let mut ctx_params = TyLoweringContext::new( - db, - &resolver, - &data.store, - def.into(), - LifetimeElisionKind::for_fn_params(&data), - ); - let params = data.params.iter().map(|&tr| ctx_params.lower_ty(tr)); - - let ret = match data.ret_type { - Some(ret_type) => { - let mut ctx_ret = TyLoweringContext::new( - db, - &resolver, - &data.store, - def.into(), - LifetimeElisionKind::for_fn_ret(interner), - ) - .with_impl_trait_mode(ImplTraitLoweringMode::Opaque); - ctx_ret.lower_ty(ret_type) - } - None => Ty::new_tup(interner, &[]), - }; - - let inputs_and_output = Tys::new_from_iter(interner, params.chain(Some(ret))); - // If/when we track late bound vars, we need to switch this to not be `dummy` - EarlyBinder::bind(rustc_type_ir::Binder::dummy(FnSig { - abi: data.abi.as_ref().map_or(FnAbi::Rust, FnAbi::from_symbol), - c_variadic: data.is_varargs(), - safety: if data.is_unsafe() { Safety::Unsafe } else { Safety::Safe }, - inputs_and_output, - })) -} - -fn type_for_adt<'db>(db: &'db dyn HirDatabase, adt: AdtId) -> EarlyBinder<'db, Ty<'db>> { - let interner = DbInterner::new_with(db, None, None); - let args = GenericArgs::identity_for_item(interner, adt.into()); - let ty = Ty::new_adt(interner, adt, args); - EarlyBinder::bind(ty) -} - -fn fn_sig_for_struct_constructor<'db>( - db: &'db dyn HirDatabase, - def: StructId, -) -> EarlyBinder<'db, PolyFnSig<'db>> { - let field_tys = db.field_types_ns(def.into()); - let params = field_tys.iter().map(|(_, ty)| ty.skip_binder()); - let ret = type_for_adt(db, def.into()).skip_binder(); - - let inputs_and_output = - Tys::new_from_iter(DbInterner::new_with(db, None, None), params.chain(Some(ret))); - EarlyBinder::bind(Binder::dummy(FnSig { - abi: FnAbi::RustCall, - c_variadic: false, - safety: Safety::Safe, - inputs_and_output, - })) -} - -fn fn_sig_for_enum_variant_constructor<'db>( - db: &'db dyn HirDatabase, - def: EnumVariantId, -) -> EarlyBinder<'db, PolyFnSig<'db>> { - let field_tys = db.field_types_ns(def.into()); - let params = field_tys.iter().map(|(_, ty)| ty.skip_binder()); - let parent = def.lookup(db).parent; - let ret = type_for_adt(db, parent.into()).skip_binder(); - - let inputs_and_output = - Tys::new_from_iter(DbInterner::new_with(db, None, None), params.chain(Some(ret))); - EarlyBinder::bind(Binder::dummy(FnSig { - abi: FnAbi::RustCall, - c_variadic: false, - safety: Safety::Safe, - inputs_and_output, - })) -} - -// FIXME(next-solver): should merge this with `explicit_item_bounds` in some way -pub(crate) fn associated_ty_item_bounds<'db>( - db: &'db dyn HirDatabase, - type_alias: TypeAliasId, -) -> EarlyBinder<'db, BoundExistentialPredicates<'db>> { - let trait_ = match type_alias.lookup(db).container { - ItemContainerId::TraitId(t) => t, - _ => panic!("associated type not in trait"), - }; - - let type_alias_data = db.type_alias_signature(type_alias); - let resolver = hir_def::resolver::HasResolver::resolver(type_alias, db); - let interner = DbInterner::new_with(db, Some(resolver.krate()), None); - let mut ctx = TyLoweringContext::new( - db, - &resolver, - &type_alias_data.store, - type_alias.into(), - LifetimeElisionKind::AnonymousReportError, - ); - // FIXME: we should never create non-existential predicates in the first place - // For now, use an error type so we don't run into dummy binder issues - let self_ty = Ty::new_error(interner, ErrorGuaranteed); - - let mut bounds = Vec::new(); - for bound in &type_alias_data.bounds { - ctx.lower_type_bound(bound, self_ty, false).for_each(|pred| { - if let Some(bound) = pred - .kind() - .map_bound(|c| match c { - rustc_type_ir::ClauseKind::Trait(t) => { - let id = t.def_id(); - let is_auto = db.trait_signature(id.0).flags.contains(TraitFlags::AUTO); - if is_auto { - Some(ExistentialPredicate::AutoTrait(t.def_id())) - } else { - Some(ExistentialPredicate::Trait(ExistentialTraitRef::new_from_args( - interner, - t.def_id(), - GenericArgs::new_from_iter( - interner, - t.trait_ref.args.iter().skip(1), - ), - ))) - } - } - rustc_type_ir::ClauseKind::Projection(p) => Some( - ExistentialPredicate::Projection(ExistentialProjection::new_from_args( - interner, - p.def_id(), - GenericArgs::new_from_iter( - interner, - p.projection_term.args.iter().skip(1), - ), - p.term, - )), - ), - rustc_type_ir::ClauseKind::TypeOutlives(outlives_predicate) => None, - rustc_type_ir::ClauseKind::RegionOutlives(_) - | rustc_type_ir::ClauseKind::ConstArgHasType(_, _) - | rustc_type_ir::ClauseKind::WellFormed(_) - | rustc_type_ir::ClauseKind::ConstEvaluatable(_) - | rustc_type_ir::ClauseKind::HostEffect(_) - | rustc_type_ir::ClauseKind::UnstableFeature(_) => unreachable!(), - }) - .transpose() - { - bounds.push(bound); - } - }); - } - - if !ctx.unsized_types.contains(&self_ty) { - let sized_trait = LangItem::Sized.resolve_trait(db, resolver.krate()); - let sized_clause = Binder::dummy(ExistentialPredicate::Trait(ExistentialTraitRef::new( - interner, - trait_.into(), - [] as [crate::next_solver::GenericArg<'_>; 0], - ))); - bounds.push(sized_clause); - bounds.shrink_to_fit(); - } - - EarlyBinder::bind(BoundExistentialPredicates::new_from_iter(interner, bounds)) -} - -pub(crate) fn associated_type_by_name_including_super_traits<'db>( - db: &'db dyn HirDatabase, - trait_ref: TraitRef<'db>, - name: &Name, -) -> Option<(TraitRef<'db>, TypeAliasId)> { - let interner = DbInterner::new_with(db, None, None); - rustc_type_ir::elaborate::supertraits(interner, Binder::dummy(trait_ref)).find_map(|t| { - let trait_id = t.as_ref().skip_binder().def_id.0; - let assoc_type = trait_id.trait_items(db).associated_type_by_name(name)?; - Some((t.skip_binder(), assoc_type)) - }) -} - -pub fn associated_type_shorthand_candidates( - db: &dyn HirDatabase, - def: GenericDefId, - res: TypeNs, - mut cb: impl FnMut(&Name, TypeAliasId) -> bool, -) -> Option { - let interner = DbInterner::new_with(db, None, None); - named_associated_type_shorthand_candidates(interner, def, res, None, |name, _, id| { - cb(name, id).then_some(id) - }) -} - -#[tracing::instrument(skip(interner, check_alias))] -fn named_associated_type_shorthand_candidates<'db, R>( - interner: DbInterner<'db>, - // If the type parameter is defined in an impl and we're in a method, there - // might be additional where clauses to consider - def: GenericDefId, - res: TypeNs, - assoc_name: Option, - mut check_alias: impl FnMut(&Name, TraitRef<'db>, TypeAliasId) -> Option, -) -> Option { - let db = interner.db; - let mut search = |t: TraitRef<'db>| -> Option { - let trait_id = t.def_id.0; - let mut checked_traits = FxHashSet::default(); - let mut check_trait = |trait_ref: TraitRef<'db>| { - let trait_id = trait_ref.def_id.0; - let name = &db.trait_signature(trait_id).name; - tracing::debug!(?trait_id, ?name); - if !checked_traits.insert(trait_id) { - return None; - } - let data = trait_id.trait_items(db); - - tracing::debug!(?data.items); - for (name, assoc_id) in &data.items { - if let &AssocItemId::TypeAliasId(alias) = assoc_id - && let Some(ty) = check_alias(name, trait_ref, alias) - { - return Some(ty); - } - } - None - }; - let mut stack: SmallVec<[_; 4]> = smallvec![t]; - while let Some(trait_ref) = stack.pop() { - if let Some(alias) = check_trait(trait_ref) { - return Some(alias); - } - for pred in generic_predicates_filtered_by( - db, - GenericDefId::TraitId(trait_ref.def_id.0), - PredicateFilter::SelfTrait, - // We are likely in the midst of lowering generic predicates of `def`. - // So, if we allow `pred == def` we might fall into an infinite recursion. - // Actually, we have already checked for the case `pred == def` above as we started - // with a stack including `trait_id` - |pred| pred != def && pred == GenericDefId::TraitId(trait_ref.def_id.0), - ) - .0 - .deref() - { - tracing::debug!(?pred); - let sup_trait_ref = match pred.kind().skip_binder() { - rustc_type_ir::ClauseKind::Trait(pred) => pred.trait_ref, - _ => continue, - }; - let sup_trait_ref = - EarlyBinder::bind(sup_trait_ref).instantiate(interner, trait_ref.args); - stack.push(sup_trait_ref); - } - tracing::debug!(?stack); - } - - None - }; - - match res { - TypeNs::SelfType(impl_id) => { - let trait_ref = db.impl_trait(impl_id)?; - - // FIXME(next-solver): same method in `lower` checks for impl or not - // Is that needed here? - - // we're _in_ the impl -- the binders get added back later. Correct, - // but it would be nice to make this more explicit - search(trait_ref.skip_binder()) - } - TypeNs::GenericParam(param_id) => { - // Handle `Self::Type` referring to own associated type in trait definitions - // This *must* be done first to avoid cycles with - // `generic_predicates_for_param`, but not sure that it's sufficient, - if let GenericDefId::TraitId(trait_id) = param_id.parent() { - let trait_name = &db.trait_signature(trait_id).name; - tracing::debug!(?trait_name); - let trait_generics = generics(db, trait_id.into()); - tracing::debug!(?trait_generics); - if trait_generics[param_id.local_id()].is_trait_self() { - let args = crate::next_solver::GenericArgs::identity_for_item( - interner, - trait_id.into(), - ); - let trait_ref = TraitRef::new_from_args(interner, trait_id.into(), args); - tracing::debug!(?args, ?trait_ref); - return search(trait_ref); - } - } - - let predicates = - db.generic_predicates_for_param_ns(def, param_id.into(), assoc_name.clone()); - predicates - .iter() - .find_map(|pred| match (*pred).kind().skip_binder() { - rustc_type_ir::ClauseKind::Trait(trait_predicate) => Some(trait_predicate), - _ => None, - }) - .and_then(|trait_predicate| { - let trait_ref = trait_predicate.trait_ref; - assert!( - !trait_ref.has_escaping_bound_vars(), - "FIXME unexpected higher-ranked trait bound" - ); - search(trait_ref) - }) - } - _ => None, - } -} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver/path.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver/path.rs deleted file mode 100644 index ef2c392f0861..000000000000 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver/path.rs +++ /dev/null @@ -1,1354 +0,0 @@ -//! A wrapper around [`TyLoweringContext`] specifically for lowering paths. - -use std::ops::Deref; - -use either::Either; -use hir_def::{ - AssocItemId, GenericDefId, GenericParamId, Lookup, TraitId, TypeAliasId, - builtin_type::BuiltinType, - expr_store::{ - ExpressionStore, HygieneId, - path::{GenericArg, GenericArgs, GenericArgsParentheses, Path, PathSegment, PathSegments}, - }, - hir::generics::{ - GenericParamDataRef, TypeOrConstParamData, TypeParamData, TypeParamProvenance, - }, - resolver::{ResolveValueResult, TypeNs, ValueNs}, - signatures::TraitFlags, - type_ref::{TypeRef, TypeRefId}, -}; -use hir_expand::name::Name; -use intern::sym; -use rustc_hash::FxHashSet; -use rustc_type_ir::{ - AliasTerm, AliasTy, AliasTyKind, TypeVisitableExt, - inherent::{GenericArgs as _, IntoKind, Region as _, SliceLike, Ty as _}, -}; -use smallvec::{SmallVec, smallvec}; -use stdx::never; - -use crate::{ - GenericArgsProhibitedReason, IncorrectGenericsLenKind, PathGenericsSource, - PathLoweringDiagnostic, TyDefId, ValueTyDefId, - consteval::{unknown_const, unknown_const_as_generic}, - db::HirDatabase, - generics::{Generics, generics}, - lower::PathDiagnosticCallbackData, - lower_nextsolver::{ - LifetimeElisionKind, PredicateFilter, generic_predicates_filtered_by, - named_associated_type_shorthand_candidates, - }, - next_solver::{ - AdtDef, Binder, Clause, Const, DbInterner, ErrorGuaranteed, Predicate, ProjectionPredicate, - Region, SolverDefId, TraitRef, Ty, - mapping::{ChalkToNextSolver, convert_binder_to_early_binder}, - }, - primitive, -}; - -use super::{ - ImplTraitLoweringMode, TyLoweringContext, associated_type_by_name_including_super_traits, - const_param_ty_query, ty_query, -}; - -type CallbackData<'a, 'db> = Either< - PathDiagnosticCallbackData, - crate::infer::diagnostics::PathDiagnosticCallbackData<'a, 'db>, ->; - -// We cannot use `&mut dyn FnMut()` because of lifetime issues, and we don't want to use `Box` -// because of the allocation, so we create a lifetime-less callback, tailored for our needs. -pub(crate) struct PathDiagnosticCallback<'a, 'db> { - pub(crate) data: CallbackData<'a, 'db>, - pub(crate) callback: - fn(&CallbackData<'_, 'db>, &mut TyLoweringContext<'db, '_>, PathLoweringDiagnostic), -} - -pub(crate) struct PathLoweringContext<'a, 'b, 'db> { - ctx: &'a mut TyLoweringContext<'db, 'b>, - on_diagnostic: PathDiagnosticCallback<'a, 'db>, - path: &'a Path, - segments: PathSegments<'a>, - current_segment_idx: usize, - /// Contains the previous segment if `current_segment_idx == segments.len()` - current_or_prev_segment: PathSegment<'a>, -} - -impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> { - #[inline] - pub(crate) fn new( - ctx: &'a mut TyLoweringContext<'db, 'b>, - on_diagnostic: PathDiagnosticCallback<'a, 'db>, - path: &'a Path, - ) -> Self { - let segments = path.segments(); - let first_segment = segments.first().unwrap_or(PathSegment::MISSING); - Self { - ctx, - on_diagnostic, - path, - segments, - current_segment_idx: 0, - current_or_prev_segment: first_segment, - } - } - - #[inline] - #[cold] - fn on_diagnostic(&mut self, diag: PathLoweringDiagnostic) { - (self.on_diagnostic.callback)(&self.on_diagnostic.data, self.ctx, diag); - } - - #[inline] - pub(crate) fn ty_ctx(&mut self) -> &mut TyLoweringContext<'db, 'b> { - self.ctx - } - - #[inline] - fn current_segment_u32(&self) -> u32 { - self.current_segment_idx as u32 - } - - #[inline] - fn skip_resolved_segment(&mut self) { - if !matches!(self.path, Path::LangItem(..)) { - // In lang items, the resolved "segment" is not one of the segments. Perhaps we should've put it - // point at -1, but I don't feel this is clearer. - self.current_segment_idx += 1; - } - self.update_current_segment(); - } - - #[inline] - fn update_current_segment(&mut self) { - self.current_or_prev_segment = - self.segments.get(self.current_segment_idx).unwrap_or(self.current_or_prev_segment); - } - - #[inline] - pub(crate) fn ignore_last_segment(&mut self) { - self.segments = self.segments.strip_last(); - } - - #[inline] - pub(crate) fn set_current_segment(&mut self, segment: usize) { - self.current_segment_idx = segment; - self.current_or_prev_segment = self - .segments - .get(segment) - .expect("invalid segment passed to PathLoweringContext::set_current_segment()"); - } - - #[inline] - fn with_lifetime_elision( - &mut self, - lifetime_elision: LifetimeElisionKind<'db>, - f: impl FnOnce(&mut PathLoweringContext<'_, '_, 'db>) -> T, - ) -> T { - let old_lifetime_elision = - std::mem::replace(&mut self.ctx.lifetime_elision, lifetime_elision); - let result = f(self); - self.ctx.lifetime_elision = old_lifetime_elision; - result - } - - pub(crate) fn lower_ty_relative_path( - &mut self, - ty: Ty<'db>, - // We need the original resolution to lower `Self::AssocTy` correctly - res: Option, - infer_args: bool, - ) -> (Ty<'db>, Option) { - let remaining_segments = self.segments.len() - self.current_segment_idx; - match remaining_segments { - 0 => (ty, res), - 1 => { - // resolve unselected assoc types - (self.select_associated_type(res, infer_args), None) - } - _ => { - // FIXME report error (ambiguous associated type) - (Ty::new_error(self.ctx.interner, ErrorGuaranteed), None) - } - } - } - - fn prohibit_parenthesized_generic_args(&mut self) -> bool { - if let Some(generic_args) = self.current_or_prev_segment.args_and_bindings { - match generic_args.parenthesized { - GenericArgsParentheses::No => {} - GenericArgsParentheses::ReturnTypeNotation | GenericArgsParentheses::ParenSugar => { - let segment = self.current_segment_u32(); - self.on_diagnostic( - PathLoweringDiagnostic::ParenthesizedGenericArgsWithoutFnTrait { segment }, - ); - return true; - } - } - } - false - } - - // When calling this, the current segment is the resolved segment (we don't advance it yet). - pub(crate) fn lower_partly_resolved_path( - &mut self, - resolution: TypeNs, - infer_args: bool, - ) -> (Ty<'db>, Option) { - let remaining_segments = self.segments.skip(self.current_segment_idx + 1); - tracing::debug!(?remaining_segments); - let rem_seg_len = remaining_segments.len(); - tracing::debug!(?rem_seg_len); - - let ty = match resolution { - TypeNs::TraitId(trait_) => { - let ty = match remaining_segments.len() { - 1 => { - let trait_ref = self.lower_trait_ref_from_resolved_path( - trait_, - Ty::new_error(self.ctx.interner, ErrorGuaranteed), - false, - ); - tracing::debug!(?trait_ref); - self.skip_resolved_segment(); - let segment = self.current_or_prev_segment; - let trait_id = trait_ref.def_id.0; - let found = - trait_id.trait_items(self.ctx.db).associated_type_by_name(segment.name); - - tracing::debug!(?found); - match found { - Some(associated_ty) => { - // FIXME: `substs_from_path_segment()` pushes `TyKind::Error` for every parent - // generic params. It's inefficient to splice the `Substitution`s, so we may want - // that method to optionally take parent `Substitution` as we already know them at - // this point (`trait_ref.substitution`). - let substitution = self.substs_from_path_segment( - associated_ty.into(), - false, - None, - true, - ); - let args = crate::next_solver::GenericArgs::new_from_iter( - self.ctx.interner, - trait_ref - .args - .iter() - .chain(substitution.iter().skip(trait_ref.args.len())), - ); - Ty::new_alias( - self.ctx.interner, - AliasTyKind::Projection, - AliasTy::new_from_args( - self.ctx.interner, - associated_ty.into(), - args, - ), - ) - } - None => { - // FIXME: report error (associated type not found) - Ty::new_error(self.ctx.interner, ErrorGuaranteed) - } - } - } - 0 => { - // Trait object type without dyn; this should be handled in upstream. See - // `lower_path()`. - stdx::never!("unexpected fully resolved trait path"); - Ty::new_error(self.ctx.interner, ErrorGuaranteed) - } - _ => { - // FIXME report error (ambiguous associated type) - Ty::new_error(self.ctx.interner, ErrorGuaranteed) - } - }; - return (ty, None); - } - TypeNs::GenericParam(param_id) => { - let generics = self.ctx.generics(); - let idx = generics.type_or_const_param_idx(param_id.into()); - match idx { - None => { - never!("no matching generics"); - Ty::new_error(self.ctx.interner, ErrorGuaranteed) - } - Some(idx) => { - let (pidx, param) = generics.iter().nth(idx).unwrap(); - assert_eq!(pidx, param_id.into()); - let p = match param { - GenericParamDataRef::TypeParamData(p) => p, - _ => unreachable!(), - }; - self.ctx.type_param( - param_id, - idx as u32, - p.name - .as_ref() - .map_or_else(|| sym::MISSING_NAME.clone(), |p| p.symbol().clone()), - ) - } - } - } - TypeNs::SelfType(impl_id) => self.ctx.db.impl_self_ty(impl_id).skip_binder(), - TypeNs::AdtSelfType(adt) => { - let args = crate::next_solver::GenericArgs::identity_for_item( - self.ctx.interner, - adt.into(), - ); - Ty::new_adt(self.ctx.interner, adt, args) - } - - TypeNs::AdtId(it) => self.lower_path_inner(it.into(), infer_args), - TypeNs::BuiltinType(it) => self.lower_path_inner(it.into(), infer_args), - TypeNs::TypeAliasId(it) => self.lower_path_inner(it.into(), infer_args), - // FIXME: report error - TypeNs::EnumVariantId(_) | TypeNs::ModuleId(_) => { - return (Ty::new_error(self.ctx.interner, ErrorGuaranteed), None); - } - }; - - tracing::debug!(?ty); - - self.skip_resolved_segment(); - self.lower_ty_relative_path(ty, Some(resolution), infer_args) - } - - fn handle_type_ns_resolution(&mut self, resolution: &TypeNs) { - let mut prohibit_generics_on_resolved = |reason| { - if self.current_or_prev_segment.args_and_bindings.is_some() { - let segment = self.current_segment_u32(); - self.on_diagnostic(PathLoweringDiagnostic::GenericArgsProhibited { - segment, - reason, - }); - } - }; - - match resolution { - TypeNs::SelfType(_) => { - prohibit_generics_on_resolved(GenericArgsProhibitedReason::SelfTy) - } - TypeNs::GenericParam(_) => { - prohibit_generics_on_resolved(GenericArgsProhibitedReason::TyParam) - } - TypeNs::AdtSelfType(_) => { - prohibit_generics_on_resolved(GenericArgsProhibitedReason::SelfTy) - } - TypeNs::BuiltinType(_) => { - prohibit_generics_on_resolved(GenericArgsProhibitedReason::PrimitiveTy) - } - TypeNs::ModuleId(_) => { - prohibit_generics_on_resolved(GenericArgsProhibitedReason::Module) - } - TypeNs::AdtId(_) - | TypeNs::EnumVariantId(_) - | TypeNs::TypeAliasId(_) - | TypeNs::TraitId(_) => {} - } - } - - pub(crate) fn resolve_path_in_type_ns_fully(&mut self) -> Option { - let (res, unresolved) = self.resolve_path_in_type_ns()?; - if unresolved.is_some() { - return None; - } - Some(res) - } - - #[tracing::instrument(skip(self), ret)] - pub(crate) fn resolve_path_in_type_ns(&mut self) -> Option<(TypeNs, Option)> { - let (resolution, remaining_index, _, prefix_info) = - self.ctx.resolver.resolve_path_in_type_ns_with_prefix_info(self.ctx.db, self.path)?; - - let segments = self.segments; - if segments.is_empty() || matches!(self.path, Path::LangItem(..)) { - // `segments.is_empty()` can occur with `self`. - return Some((resolution, remaining_index)); - } - - let (module_segments, resolved_segment_idx, enum_segment) = match remaining_index { - None if prefix_info.enum_variant => { - (segments.strip_last_two(), segments.len() - 1, Some(segments.len() - 2)) - } - None => (segments.strip_last(), segments.len() - 1, None), - Some(i) => (segments.take(i - 1), i - 1, None), - }; - - self.current_segment_idx = resolved_segment_idx; - self.current_or_prev_segment = - segments.get(resolved_segment_idx).expect("should have resolved segment"); - - if matches!(self.path, Path::BarePath(..)) { - // Bare paths cannot have generics, so skip them as an optimization. - return Some((resolution, remaining_index)); - } - - for (i, mod_segment) in module_segments.iter().enumerate() { - if mod_segment.args_and_bindings.is_some() { - self.on_diagnostic(PathLoweringDiagnostic::GenericArgsProhibited { - segment: i as u32, - reason: GenericArgsProhibitedReason::Module, - }); - } - } - - if let Some(enum_segment) = enum_segment - && segments.get(enum_segment).is_some_and(|it| it.args_and_bindings.is_some()) - && segments.get(enum_segment + 1).is_some_and(|it| it.args_and_bindings.is_some()) - { - self.on_diagnostic(PathLoweringDiagnostic::GenericArgsProhibited { - segment: (enum_segment + 1) as u32, - reason: GenericArgsProhibitedReason::EnumVariant, - }); - } - - self.handle_type_ns_resolution(&resolution); - - Some((resolution, remaining_index)) - } - - pub(crate) fn resolve_path_in_value_ns( - &mut self, - hygiene_id: HygieneId, - ) -> Option { - let (res, prefix_info) = self.ctx.resolver.resolve_path_in_value_ns_with_prefix_info( - self.ctx.db, - self.path, - hygiene_id, - )?; - - let segments = self.segments; - if segments.is_empty() || matches!(self.path, Path::LangItem(..)) { - // `segments.is_empty()` can occur with `self`. - return Some(res); - } - - let (mod_segments, enum_segment, resolved_segment_idx) = match res { - ResolveValueResult::Partial(_, unresolved_segment, _) => { - (segments.take(unresolved_segment - 1), None, unresolved_segment - 1) - } - ResolveValueResult::ValueNs(ValueNs::EnumVariantId(_), _) - if prefix_info.enum_variant => - { - (segments.strip_last_two(), segments.len().checked_sub(2), segments.len() - 1) - } - ResolveValueResult::ValueNs(..) => (segments.strip_last(), None, segments.len() - 1), - }; - - self.current_segment_idx = resolved_segment_idx; - self.current_or_prev_segment = - segments.get(resolved_segment_idx).expect("should have resolved segment"); - - for (i, mod_segment) in mod_segments.iter().enumerate() { - if mod_segment.args_and_bindings.is_some() { - self.on_diagnostic(PathLoweringDiagnostic::GenericArgsProhibited { - segment: i as u32, - reason: GenericArgsProhibitedReason::Module, - }); - } - } - - if let Some(enum_segment) = enum_segment - && segments.get(enum_segment).is_some_and(|it| it.args_and_bindings.is_some()) - && segments.get(enum_segment + 1).is_some_and(|it| it.args_and_bindings.is_some()) - { - self.on_diagnostic(PathLoweringDiagnostic::GenericArgsProhibited { - segment: (enum_segment + 1) as u32, - reason: GenericArgsProhibitedReason::EnumVariant, - }); - } - - match &res { - ResolveValueResult::ValueNs(resolution, _) => { - let resolved_segment_idx = self.current_segment_u32(); - let resolved_segment = self.current_or_prev_segment; - - let mut prohibit_generics_on_resolved = |reason| { - if resolved_segment.args_and_bindings.is_some() { - self.on_diagnostic(PathLoweringDiagnostic::GenericArgsProhibited { - segment: resolved_segment_idx, - reason, - }); - } - }; - - match resolution { - ValueNs::ImplSelf(_) => { - prohibit_generics_on_resolved(GenericArgsProhibitedReason::SelfTy) - } - // FIXME: rustc generates E0107 (incorrect number of generic arguments) and not - // E0109 (generic arguments provided for a type that doesn't accept them) for - // consts and statics, presumably as a defense against future in which consts - // and statics can be generic, or just because it was easier for rustc implementors. - // That means we'll show the wrong error code. Because of us it's easier to do it - // this way :) - ValueNs::GenericParam(_) => { - prohibit_generics_on_resolved(GenericArgsProhibitedReason::Const) - } - ValueNs::StaticId(_) => { - prohibit_generics_on_resolved(GenericArgsProhibitedReason::Static) - } - ValueNs::LocalBinding(_) => { - prohibit_generics_on_resolved(GenericArgsProhibitedReason::LocalVariable) - } - ValueNs::FunctionId(_) - | ValueNs::StructId(_) - | ValueNs::EnumVariantId(_) - | ValueNs::ConstId(_) => {} - } - } - ResolveValueResult::Partial(resolution, _, _) => { - self.handle_type_ns_resolution(resolution); - } - }; - Some(res) - } - - #[tracing::instrument(skip(self), ret)] - fn select_associated_type(&mut self, res: Option, infer_args: bool) -> Ty<'db> { - let interner = self.ctx.interner; - let Some(res) = res else { - return Ty::new_error(self.ctx.interner, ErrorGuaranteed); - }; - let db = self.ctx.db; - let def = self.ctx.def; - let segment = self.current_or_prev_segment; - let assoc_name = segment.name; - let mut check_alias = |name: &Name, t: TraitRef<'db>, associated_ty: TypeAliasId| { - if name != assoc_name { - return None; - } - - // FIXME: `substs_from_path_segment()` pushes `TyKind::Error` for every parent - // generic params. It's inefficient to splice the `Substitution`s, so we may want - // that method to optionally take parent `Substitution` as we already know them at - // this point (`t.substitution`). - let substs = - self.substs_from_path_segment(associated_ty.into(), infer_args, None, true); - - let substs = crate::next_solver::GenericArgs::new_from_iter( - interner, - t.args.iter().chain(substs.iter().skip(t.args.len())), - ); - - Some(Ty::new_alias( - interner, - AliasTyKind::Projection, - AliasTy::new(interner, associated_ty.into(), substs), - )) - }; - named_associated_type_shorthand_candidates( - interner, - def, - res, - Some(assoc_name.clone()), - check_alias, - ) - .unwrap_or_else(|| Ty::new_error(interner, ErrorGuaranteed)) - } - - fn lower_path_inner(&mut self, typeable: TyDefId, infer_args: bool) -> Ty<'db> { - let generic_def = match typeable { - TyDefId::BuiltinType(builtinty) => { - return Ty::from_builtin_type(self.ctx.interner, builtinty); - } - TyDefId::AdtId(it) => it.into(), - TyDefId::TypeAliasId(it) => it.into(), - }; - let args = self.substs_from_path_segment(generic_def, infer_args, None, false); - let ty = ty_query(self.ctx.db, typeable); - ty.instantiate(self.ctx.interner, args) - } - - /// Collect generic arguments from a path into a `Substs`. See also - /// `create_substs_for_ast_path` and `def_to_ty` in rustc. - pub(crate) fn substs_from_path( - &mut self, - // Note that we don't call `db.value_type(resolved)` here, - // `ValueTyDefId` is just a convenient way to pass generics and - // special-case enum variants - resolved: ValueTyDefId, - infer_args: bool, - lowering_assoc_type_generics: bool, - ) -> crate::next_solver::GenericArgs<'db> { - let interner = self.ctx.interner; - let prev_current_segment_idx = self.current_segment_idx; - let prev_current_segment = self.current_or_prev_segment; - - let generic_def = match resolved { - ValueTyDefId::FunctionId(it) => it.into(), - ValueTyDefId::StructId(it) => it.into(), - ValueTyDefId::UnionId(it) => it.into(), - ValueTyDefId::ConstId(it) => it.into(), - ValueTyDefId::StaticId(_) => { - return crate::next_solver::GenericArgs::new_from_iter(interner, []); - } - ValueTyDefId::EnumVariantId(var) => { - // the generic args for an enum variant may be either specified - // on the segment referring to the enum, or on the segment - // referring to the variant. So `Option::::None` and - // `Option::None::` are both allowed (though the former is - // FIXME: This isn't strictly correct, enum variants may be used not through the enum - // (via `use Enum::Variant`). The resolver returns whether they were, but we don't have its result - // available here. The worst that can happen is that we will show some confusing diagnostics to the user, - // if generics exist on the module and they don't match with the variant. - // preferred). See also `def_ids_for_path_segments` in rustc. - // - // `wrapping_sub(1)` will return a number which `get` will return None for if current_segment_idx<2. - // This simplifies the code a bit. - let penultimate_idx = self.current_segment_idx.wrapping_sub(1); - let penultimate = self.segments.get(penultimate_idx); - if let Some(penultimate) = penultimate - && self.current_or_prev_segment.args_and_bindings.is_none() - && penultimate.args_and_bindings.is_some() - { - self.current_segment_idx = penultimate_idx; - self.current_or_prev_segment = penultimate; - } - var.lookup(self.ctx.db).parent.into() - } - }; - let result = self.substs_from_path_segment( - generic_def, - infer_args, - None, - lowering_assoc_type_generics, - ); - self.current_segment_idx = prev_current_segment_idx; - self.current_or_prev_segment = prev_current_segment; - result - } - - pub(crate) fn substs_from_path_segment( - &mut self, - def: GenericDefId, - infer_args: bool, - explicit_self_ty: Option>, - lowering_assoc_type_generics: bool, - ) -> crate::next_solver::GenericArgs<'db> { - let old_lifetime_elision = self.ctx.lifetime_elision.clone(); - - if let Some(args) = self.current_or_prev_segment.args_and_bindings - && args.parenthesized != GenericArgsParentheses::No - { - let prohibit_parens = match def { - GenericDefId::TraitId(trait_) => { - // RTN is prohibited anyways if we got here. - let is_rtn = args.parenthesized == GenericArgsParentheses::ReturnTypeNotation; - let is_fn_trait = self - .ctx - .db - .trait_signature(trait_) - .flags - .contains(TraitFlags::RUSTC_PAREN_SUGAR); - is_rtn || !is_fn_trait - } - _ => true, - }; - - if prohibit_parens { - let segment = self.current_segment_u32(); - self.on_diagnostic( - PathLoweringDiagnostic::ParenthesizedGenericArgsWithoutFnTrait { segment }, - ); - - return unknown_subst(self.ctx.interner, def); - } - - // `Fn()`-style generics are treated like functions for the purpose of lifetime elision. - self.ctx.lifetime_elision = - LifetimeElisionKind::AnonymousCreateParameter { report_in_path: false }; - } - - let result = self.substs_from_args_and_bindings( - self.current_or_prev_segment.args_and_bindings, - def, - infer_args, - explicit_self_ty, - PathGenericsSource::Segment(self.current_segment_u32()), - lowering_assoc_type_generics, - self.ctx.lifetime_elision.clone(), - ); - self.ctx.lifetime_elision = old_lifetime_elision; - result - } - - pub(super) fn substs_from_args_and_bindings( - &mut self, - args_and_bindings: Option<&GenericArgs>, - def: GenericDefId, - infer_args: bool, - explicit_self_ty: Option>, - generics_source: PathGenericsSource, - lowering_assoc_type_generics: bool, - lifetime_elision: LifetimeElisionKind<'db>, - ) -> crate::next_solver::GenericArgs<'db> { - struct LowererCtx<'a, 'b, 'c, 'db> { - ctx: &'a mut PathLoweringContext<'b, 'c, 'db>, - generics_source: PathGenericsSource, - } - - impl<'db> GenericArgsLowerer<'db> for LowererCtx<'_, '_, '_, 'db> { - fn report_len_mismatch( - &mut self, - def: GenericDefId, - provided_count: u32, - expected_count: u32, - kind: IncorrectGenericsLenKind, - ) { - self.ctx.on_diagnostic(PathLoweringDiagnostic::IncorrectGenericsLen { - generics_source: self.generics_source, - provided_count, - expected_count, - kind, - def, - }); - } - - fn report_arg_mismatch( - &mut self, - param_id: GenericParamId, - arg_idx: u32, - has_self_arg: bool, - ) { - self.ctx.on_diagnostic(PathLoweringDiagnostic::IncorrectGenericsOrder { - generics_source: self.generics_source, - param_id, - arg_idx, - has_self_arg, - }); - } - - fn provided_kind( - &mut self, - param_id: GenericParamId, - param: GenericParamDataRef<'_>, - arg: &GenericArg, - ) -> crate::next_solver::GenericArg<'db> { - match (param, *arg) { - (GenericParamDataRef::LifetimeParamData(_), GenericArg::Lifetime(lifetime)) => { - self.ctx.ctx.lower_lifetime(lifetime).into() - } - (GenericParamDataRef::TypeParamData(_), GenericArg::Type(type_ref)) => { - self.ctx.ctx.lower_ty(type_ref).into() - } - (GenericParamDataRef::ConstParamData(_), GenericArg::Const(konst)) => { - let GenericParamId::ConstParamId(const_id) = param_id else { - unreachable!("non-const param ID for const param"); - }; - self.ctx - .ctx - .lower_const(konst, const_param_ty_query(self.ctx.ctx.db, const_id)) - .into() - } - _ => unreachable!("unmatching param kinds were passed to `provided_kind()`"), - } - } - - fn provided_type_like_const( - &mut self, - const_ty: Ty<'db>, - arg: TypeLikeConst<'_>, - ) -> crate::next_solver::Const<'db> { - match arg { - TypeLikeConst::Path(path) => self.ctx.ctx.lower_path_as_const(path, const_ty), - TypeLikeConst::Infer => unknown_const(const_ty), - } - } - - fn inferred_kind( - &mut self, - def: GenericDefId, - param_id: GenericParamId, - param: GenericParamDataRef<'_>, - infer_args: bool, - preceding_args: &[crate::next_solver::GenericArg<'db>], - ) -> crate::next_solver::GenericArg<'db> { - let default = || { - self.ctx.ctx.db.generic_defaults(def).get(preceding_args.len()).map(|default| { - convert_binder_to_early_binder( - self.ctx.ctx.interner, - def, - default.to_nextsolver(self.ctx.ctx.interner), - ) - .instantiate(self.ctx.ctx.interner, preceding_args) - }) - }; - match param { - GenericParamDataRef::LifetimeParamData(_) => { - Region::new(self.ctx.ctx.interner, rustc_type_ir::ReError(ErrorGuaranteed)) - .into() - } - GenericParamDataRef::TypeParamData(param) => { - if !infer_args - && param.default.is_some() - && let Some(default) = default() - { - return default; - } - Ty::new_error(self.ctx.ctx.interner, ErrorGuaranteed).into() - } - GenericParamDataRef::ConstParamData(param) => { - if !infer_args - && param.default.is_some() - && let Some(default) = default() - { - return default; - } - let GenericParamId::ConstParamId(const_id) = param_id else { - unreachable!("non-const param ID for const param"); - }; - unknown_const_as_generic(const_param_ty_query(self.ctx.ctx.db, const_id)) - } - } - } - - fn parent_arg( - &mut self, - param_id: GenericParamId, - ) -> crate::next_solver::GenericArg<'db> { - match param_id { - GenericParamId::TypeParamId(_) => { - Ty::new_error(self.ctx.ctx.interner, ErrorGuaranteed).into() - } - GenericParamId::ConstParamId(const_id) => { - unknown_const_as_generic(const_param_ty_query(self.ctx.ctx.db, const_id)) - } - GenericParamId::LifetimeParamId(_) => { - Region::new(self.ctx.ctx.interner, rustc_type_ir::ReError(ErrorGuaranteed)) - .into() - } - } - } - - fn report_elided_lifetimes_in_path( - &mut self, - def: GenericDefId, - expected_count: u32, - hard_error: bool, - ) { - self.ctx.on_diagnostic(PathLoweringDiagnostic::ElidedLifetimesInPath { - generics_source: self.generics_source, - def, - expected_count, - hard_error, - }); - } - - fn report_elision_failure(&mut self, def: GenericDefId, expected_count: u32) { - self.ctx.on_diagnostic(PathLoweringDiagnostic::ElisionFailure { - generics_source: self.generics_source, - def, - expected_count, - }); - } - - fn report_missing_lifetime(&mut self, def: GenericDefId, expected_count: u32) { - self.ctx.on_diagnostic(PathLoweringDiagnostic::MissingLifetime { - generics_source: self.generics_source, - def, - expected_count, - }); - } - } - - substs_from_args_and_bindings( - self.ctx.db, - self.ctx.store, - args_and_bindings, - def, - infer_args, - lifetime_elision, - lowering_assoc_type_generics, - explicit_self_ty, - &mut LowererCtx { ctx: self, generics_source }, - ) - } - - pub(crate) fn lower_trait_ref_from_resolved_path( - &mut self, - resolved: TraitId, - explicit_self_ty: Ty<'db>, - infer_args: bool, - ) -> TraitRef<'db> { - let args = self.trait_ref_substs_from_path(resolved, explicit_self_ty, infer_args); - TraitRef::new_from_args(self.ctx.interner, resolved.into(), args) - } - - fn trait_ref_substs_from_path( - &mut self, - resolved: TraitId, - explicit_self_ty: Ty<'db>, - infer_args: bool, - ) -> crate::next_solver::GenericArgs<'db> { - self.substs_from_path_segment(resolved.into(), infer_args, Some(explicit_self_ty), false) - } - - pub(super) fn assoc_type_bindings_from_type_bound<'c>( - mut self, - trait_ref: TraitRef<'db>, - ) -> Option> + use<'a, 'b, 'c, 'db>> { - let interner = self.ctx.interner; - self.current_or_prev_segment.args_and_bindings.map(|args_and_bindings| { - args_and_bindings.bindings.iter().enumerate().flat_map(move |(binding_idx, binding)| { - let found = associated_type_by_name_including_super_traits( - self.ctx.db, - trait_ref, - &binding.name, - ); - let (super_trait_ref, associated_ty) = match found { - None => return SmallVec::new(), - Some(t) => t, - }; - let args = - self.with_lifetime_elision(LifetimeElisionKind::AnonymousReportError, |this| { - // FIXME: `substs_from_path_segment()` pushes `TyKind::Error` for every parent - // generic params. It's inefficient to splice the `Substitution`s, so we may want - // that method to optionally take parent `Substitution` as we already know them at - // this point (`super_trait_ref.substitution`). - this.substs_from_args_and_bindings( - binding.args.as_ref(), - associated_ty.into(), - false, // this is not relevant - Some(super_trait_ref.self_ty()), - PathGenericsSource::AssocType { - segment: this.current_segment_u32(), - assoc_type: binding_idx as u32, - }, - false, - this.ctx.lifetime_elision.clone(), - ) - }); - let args = crate::next_solver::GenericArgs::new_from_iter( - interner, - super_trait_ref.args.iter().chain(args.iter().skip(super_trait_ref.args.len())), - ); - let projection_term = - AliasTerm::new_from_args(interner, associated_ty.into(), args); - let mut predicates: SmallVec<[_; 1]> = SmallVec::with_capacity( - binding.type_ref.as_ref().map_or(0, |_| 1) + binding.bounds.len(), - ); - if let Some(type_ref) = binding.type_ref { - let lifetime_elision = - if args_and_bindings.parenthesized == GenericArgsParentheses::ParenSugar { - // `Fn()`-style generics are elided like functions. This is `Output` (we lower to it in hir-def). - LifetimeElisionKind::for_fn_ret(self.ctx.interner) - } else { - self.ctx.lifetime_elision.clone() - }; - self.with_lifetime_elision(lifetime_elision, |this| { - match (&this.ctx.store[type_ref], this.ctx.impl_trait_mode.mode) { - (TypeRef::ImplTrait(_), ImplTraitLoweringMode::Disallowed) => (), - ( - _, - ImplTraitLoweringMode::Disallowed | ImplTraitLoweringMode::Opaque, - ) => { - let ty = this.ctx.lower_ty(type_ref); - let pred = Clause(Predicate::new( - interner, - Binder::dummy(rustc_type_ir::PredicateKind::Clause( - rustc_type_ir::ClauseKind::Projection( - ProjectionPredicate { - projection_term, - term: ty.into(), - }, - ), - )), - )); - predicates.push(pred); - } - } - }) - } - for bound in binding.bounds.iter() { - predicates.extend(self.ctx.lower_type_bound( - bound, - Ty::new_alias( - self.ctx.interner, - AliasTyKind::Projection, - AliasTy::new_from_args(self.ctx.interner, associated_ty.into(), args), - ), - false, - )); - } - predicates - }) - }) - } -} - -/// A const that were parsed like a type. -pub(crate) enum TypeLikeConst<'a> { - Infer, - Path(&'a Path), -} - -pub(crate) trait GenericArgsLowerer<'db> { - fn report_elided_lifetimes_in_path( - &mut self, - def: GenericDefId, - expected_count: u32, - hard_error: bool, - ); - - fn report_elision_failure(&mut self, def: GenericDefId, expected_count: u32); - - fn report_missing_lifetime(&mut self, def: GenericDefId, expected_count: u32); - - fn report_len_mismatch( - &mut self, - def: GenericDefId, - provided_count: u32, - expected_count: u32, - kind: IncorrectGenericsLenKind, - ); - - fn report_arg_mismatch(&mut self, param_id: GenericParamId, arg_idx: u32, has_self_arg: bool); - - fn provided_kind( - &mut self, - param_id: GenericParamId, - param: GenericParamDataRef<'_>, - arg: &GenericArg, - ) -> crate::next_solver::GenericArg<'db>; - - fn provided_type_like_const(&mut self, const_ty: Ty<'db>, arg: TypeLikeConst<'_>) - -> Const<'db>; - - fn inferred_kind( - &mut self, - def: GenericDefId, - param_id: GenericParamId, - param: GenericParamDataRef<'_>, - infer_args: bool, - preceding_args: &[crate::next_solver::GenericArg<'db>], - ) -> crate::next_solver::GenericArg<'db>; - - fn parent_arg(&mut self, param_id: GenericParamId) -> crate::next_solver::GenericArg<'db>; -} - -/// Returns true if there was an error. -fn check_generic_args_len<'db>( - args_and_bindings: Option<&GenericArgs>, - def: GenericDefId, - def_generics: &Generics, - infer_args: bool, - lifetime_elision: &LifetimeElisionKind<'db>, - lowering_assoc_type_generics: bool, - ctx: &mut impl GenericArgsLowerer<'db>, -) -> bool { - let mut had_error = false; - - let (mut provided_lifetimes_count, mut provided_types_and_consts_count) = (0usize, 0usize); - if let Some(args_and_bindings) = args_and_bindings { - let args_no_self = &args_and_bindings.args[usize::from(args_and_bindings.has_self_type)..]; - for arg in args_no_self { - match arg { - GenericArg::Lifetime(_) => provided_lifetimes_count += 1, - GenericArg::Type(_) | GenericArg::Const(_) => provided_types_and_consts_count += 1, - } - } - } - - let lifetime_args_len = def_generics.len_lifetimes_self(); - if provided_lifetimes_count == 0 - && lifetime_args_len > 0 - && (!lowering_assoc_type_generics || infer_args) - { - // In generic associated types, we never allow inferring the lifetimes, but only in type context, that is - // when `infer_args == false`. In expression/pattern context we always allow inferring them, even for GATs. - match lifetime_elision { - &LifetimeElisionKind::AnonymousCreateParameter { report_in_path } => { - ctx.report_elided_lifetimes_in_path(def, lifetime_args_len as u32, report_in_path); - had_error |= report_in_path; - } - LifetimeElisionKind::AnonymousReportError => { - ctx.report_missing_lifetime(def, lifetime_args_len as u32); - had_error = true - } - LifetimeElisionKind::ElisionFailure => { - ctx.report_elision_failure(def, lifetime_args_len as u32); - had_error = true; - } - LifetimeElisionKind::StaticIfNoLifetimeInScope { only_lint: _ } => { - // FIXME: Check there are other lifetimes in scope, and error/lint. - } - LifetimeElisionKind::Elided(_) => { - ctx.report_elided_lifetimes_in_path(def, lifetime_args_len as u32, false); - } - LifetimeElisionKind::Infer => { - // Allow eliding lifetimes. - } - } - } else if lifetime_args_len != provided_lifetimes_count { - ctx.report_len_mismatch( - def, - provided_lifetimes_count as u32, - lifetime_args_len as u32, - IncorrectGenericsLenKind::Lifetimes, - ); - had_error = true; - } - - let defaults_count = - def_generics.iter_self_type_or_consts().filter(|(_, param)| param.has_default()).count(); - let named_type_and_const_params_count = def_generics - .iter_self_type_or_consts() - .filter(|(_, param)| match param { - TypeOrConstParamData::TypeParamData(param) => { - param.provenance == TypeParamProvenance::TypeParamList - } - TypeOrConstParamData::ConstParamData(_) => true, - }) - .count(); - let expected_max = named_type_and_const_params_count; - let expected_min = - if infer_args { 0 } else { named_type_and_const_params_count - defaults_count }; - if provided_types_and_consts_count < expected_min - || expected_max < provided_types_and_consts_count - { - ctx.report_len_mismatch( - def, - provided_types_and_consts_count as u32, - named_type_and_const_params_count as u32, - IncorrectGenericsLenKind::TypesAndConsts, - ); - had_error = true; - } - - had_error -} - -pub(crate) fn substs_from_args_and_bindings<'db>( - db: &'db dyn HirDatabase, - store: &ExpressionStore, - args_and_bindings: Option<&GenericArgs>, - def: GenericDefId, - mut infer_args: bool, - lifetime_elision: LifetimeElisionKind<'db>, - lowering_assoc_type_generics: bool, - explicit_self_ty: Option>, - ctx: &mut impl GenericArgsLowerer<'db>, -) -> crate::next_solver::GenericArgs<'db> { - let interner = DbInterner::new_with(db, None, None); - - tracing::debug!(?args_and_bindings); - - // Order is - // - Parent parameters - // - Optional Self parameter - // - Lifetime parameters - // - Type or Const parameters - let def_generics = generics(db, def); - let args_slice = args_and_bindings.map(|it| &*it.args).unwrap_or_default(); - - // We do not allow inference if there are specified args, i.e. we do not allow partial inference. - let has_non_lifetime_args = - args_slice.iter().any(|arg| !matches!(arg, GenericArg::Lifetime(_))); - infer_args &= !has_non_lifetime_args; - - let had_count_error = check_generic_args_len( - args_and_bindings, - def, - &def_generics, - infer_args, - &lifetime_elision, - lowering_assoc_type_generics, - ctx, - ); - - let mut substs = Vec::with_capacity(def_generics.len()); - - substs.extend(def_generics.iter_parent_id().map(|id| ctx.parent_arg(id))); - - let mut args = args_slice.iter().enumerate().peekable(); - let mut params = def_generics.iter_self().peekable(); - - // If we encounter a type or const when we expect a lifetime, we infer the lifetimes. - // If we later encounter a lifetime, we know that the arguments were provided in the - // wrong order. `force_infer_lt` records the type or const that forced lifetimes to be - // inferred, so we can use it for diagnostics later. - let mut force_infer_lt = None; - - let has_self_arg = args_and_bindings.is_some_and(|it| it.has_self_type); - // First, handle `Self` parameter. Consume it from the args if provided, otherwise from `explicit_self_ty`, - // and lastly infer it. - if let Some(&( - self_param_id, - self_param @ GenericParamDataRef::TypeParamData(TypeParamData { - provenance: TypeParamProvenance::TraitSelf, - .. - }), - )) = params.peek() - { - let self_ty = if has_self_arg { - let (_, self_ty) = args.next().expect("has_self_type=true, should have Self type"); - ctx.provided_kind(self_param_id, self_param, self_ty) - } else { - explicit_self_ty.map(|it| it.into()).unwrap_or_else(|| { - ctx.inferred_kind(def, self_param_id, self_param, infer_args, &substs) - }) - }; - params.next(); - substs.push(self_ty); - } - - loop { - // We're going to iterate through the generic arguments that the user - // provided, matching them with the generic parameters we expect. - // Mismatches can occur as a result of elided lifetimes, or for malformed - // input. We try to handle both sensibly. - match (args.peek(), params.peek()) { - (Some(&(arg_idx, arg)), Some(&(param_id, param))) => match (arg, param) { - (GenericArg::Type(_), GenericParamDataRef::TypeParamData(type_param)) - if type_param.provenance == TypeParamProvenance::ArgumentImplTrait => - { - // Do not allow specifying `impl Trait` explicitly. We already err at that, but if we won't handle it here - // we will handle it as if it was specified, instead of inferring it. - substs.push(ctx.inferred_kind(def, param_id, param, infer_args, &substs)); - params.next(); - } - (GenericArg::Lifetime(_), GenericParamDataRef::LifetimeParamData(_)) - | (GenericArg::Type(_), GenericParamDataRef::TypeParamData(_)) - | (GenericArg::Const(_), GenericParamDataRef::ConstParamData(_)) => { - substs.push(ctx.provided_kind(param_id, param, arg)); - args.next(); - params.next(); - } - ( - GenericArg::Type(_) | GenericArg::Const(_), - GenericParamDataRef::LifetimeParamData(_), - ) => { - // We expected a lifetime argument, but got a type or const - // argument. That means we're inferring the lifetime. - substs.push(ctx.inferred_kind(def, param_id, param, infer_args, &substs)); - params.next(); - force_infer_lt = Some((arg_idx as u32, param_id)); - } - (GenericArg::Type(type_ref), GenericParamDataRef::ConstParamData(_)) => { - if let Some(konst) = type_looks_like_const(store, *type_ref) { - let GenericParamId::ConstParamId(param_id) = param_id else { - panic!("unmatching param kinds"); - }; - let const_ty = const_param_ty_query(db, param_id); - substs.push(ctx.provided_type_like_const(const_ty, konst).into()); - args.next(); - params.next(); - } else { - // See the `_ => { ... }` branch. - if !had_count_error { - ctx.report_arg_mismatch(param_id, arg_idx as u32, has_self_arg); - } - while args.next().is_some() {} - } - } - _ => { - // We expected one kind of parameter, but the user provided - // another. This is an error. However, if we already know that - // the arguments don't match up with the parameters, we won't issue - // an additional error, as the user already knows what's wrong. - if !had_count_error { - ctx.report_arg_mismatch(param_id, arg_idx as u32, has_self_arg); - } - - // We've reported the error, but we want to make sure that this - // problem doesn't bubble down and create additional, irrelevant - // errors. In this case, we're simply going to ignore the argument - // and any following arguments. The rest of the parameters will be - // inferred. - while args.next().is_some() {} - } - }, - - (Some(&(_, arg)), None) => { - // We should never be able to reach this point with well-formed input. - // There are two situations in which we can encounter this issue. - // - // 1. The number of arguments is incorrect. In this case, an error - // will already have been emitted, and we can ignore it. - // 2. We've inferred some lifetimes, which have been provided later (i.e. - // after a type or const). We want to throw an error in this case. - if !had_count_error { - assert!( - matches!(arg, GenericArg::Lifetime(_)), - "the only possible situation here is incorrect lifetime order" - ); - let (provided_arg_idx, param_id) = - force_infer_lt.expect("lifetimes ought to have been inferred"); - ctx.report_arg_mismatch(param_id, provided_arg_idx, has_self_arg); - } - - break; - } - - (None, Some(&(param_id, param))) => { - // If there are fewer arguments than parameters, it means we're inferring the remaining arguments. - let param = if let GenericParamId::LifetimeParamId(_) = param_id { - match &lifetime_elision { - LifetimeElisionKind::ElisionFailure - | LifetimeElisionKind::AnonymousCreateParameter { report_in_path: true } - | LifetimeElisionKind::AnonymousReportError => { - assert!(had_count_error); - ctx.inferred_kind(def, param_id, param, infer_args, &substs) - } - LifetimeElisionKind::StaticIfNoLifetimeInScope { only_lint: _ } => { - Region::new_static(interner).into() - } - LifetimeElisionKind::Elided(lifetime) => (*lifetime).into(), - LifetimeElisionKind::AnonymousCreateParameter { report_in_path: false } - | LifetimeElisionKind::Infer => { - // FIXME: With `AnonymousCreateParameter`, we need to create a new lifetime parameter here - // (but this will probably be done in hir-def lowering instead). - ctx.inferred_kind(def, param_id, param, infer_args, &substs) - } - } - } else { - ctx.inferred_kind(def, param_id, param, infer_args, &substs) - }; - substs.push(param); - params.next(); - } - - (None, None) => break, - } - } - - crate::next_solver::GenericArgs::new_from_iter(interner, substs) -} - -fn type_looks_like_const( - store: &ExpressionStore, - type_ref: TypeRefId, -) -> Option> { - // A path/`_` const will be parsed as a type, instead of a const, because when parsing/lowering - // in hir-def we don't yet know the expected argument kind. rustc does this a bit differently, - // when lowering to HIR it resolves the path, and if it doesn't resolve to the type namespace - // it is lowered as a const. Our behavior could deviate from rustc when the value is resolvable - // in both the type and value namespaces, but I believe we only allow more code. - let type_ref = &store[type_ref]; - match type_ref { - TypeRef::Path(path) => Some(TypeLikeConst::Path(path)), - TypeRef::Placeholder => Some(TypeLikeConst::Infer), - _ => None, - } -} - -fn unknown_subst<'db>( - interner: DbInterner<'db>, - def: impl Into, -) -> crate::next_solver::GenericArgs<'db> { - let params = generics(interner.db(), def.into()); - crate::next_solver::GenericArgs::new_from_iter( - interner, - params.iter_id().map(|id| match id { - GenericParamId::TypeParamId(_) => Ty::new_error(interner, ErrorGuaranteed).into(), - GenericParamId::ConstParamId(id) => { - unknown_const_as_generic(const_param_ty_query(interner.db(), id)) - } - GenericParamId::LifetimeParamId(_) => { - crate::next_solver::Region::error(interner).into() - } - }), - ) -} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mapping.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mapping.rs deleted file mode 100644 index 5125a38825cb..000000000000 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mapping.rs +++ /dev/null @@ -1,169 +0,0 @@ -//! This module contains the implementations of the `ToChalk` trait, which -//! handles conversion between our data types and their corresponding types in -//! Chalk (in both directions); plus some helper functions for more specialized -//! conversions. - -use hir_def::{LifetimeParamId, TraitId, TypeAliasId, TypeOrConstParamId}; -use salsa::{ - Id, - plumbing::{AsId, FromId}, -}; - -use crate::{ - AssocTypeId, CallableDefId, ChalkTraitId, FnDefId, ForeignDefId, Interner, OpaqueTyId, - PlaceholderIndex, chalk_db, - db::{HirDatabase, InternedLifetimeParamId, InternedTypeOrConstParamId}, -}; - -pub trait ToChalk { - type Chalk; - fn to_chalk(self, db: &dyn HirDatabase) -> Self::Chalk; - fn from_chalk(db: &dyn HirDatabase, chalk: Self::Chalk) -> Self; -} - -pub(crate) fn from_chalk(db: &dyn HirDatabase, chalk: ChalkT) -> T -where - T: ToChalk, -{ - T::from_chalk(db, chalk) -} - -impl ToChalk for hir_def::ImplId { - type Chalk = chalk_db::ImplId; - - fn to_chalk(self, _db: &dyn HirDatabase) -> chalk_db::ImplId { - chalk_ir::ImplId(self.as_id()) - } - - fn from_chalk(_db: &dyn HirDatabase, impl_id: chalk_db::ImplId) -> hir_def::ImplId { - FromId::from_id(impl_id.0.as_id()) - } -} - -impl ToChalk for CallableDefId { - type Chalk = FnDefId; - - fn to_chalk(self, _db: &dyn HirDatabase) -> FnDefId { - chalk_ir::FnDefId(salsa::plumbing::AsId::as_id(&self)) - } - - fn from_chalk(db: &dyn HirDatabase, fn_def_id: FnDefId) -> CallableDefId { - salsa::plumbing::FromIdWithDb::from_id(fn_def_id.0, db.zalsa()) - } -} - -impl From for crate::db::InternedOpaqueTyId { - fn from(id: OpaqueTyId) -> Self { - FromId::from_id(id.0) - } -} - -impl From for OpaqueTyId { - fn from(id: crate::db::InternedOpaqueTyId) -> Self { - chalk_ir::OpaqueTyId(id.as_id()) - } -} - -impl From> for crate::db::InternedClosureId { - fn from(id: chalk_ir::ClosureId) -> Self { - FromId::from_id(id.0) - } -} - -impl From for chalk_ir::ClosureId { - fn from(id: crate::db::InternedClosureId) -> Self { - chalk_ir::ClosureId(id.as_id()) - } -} - -impl From> for crate::db::InternedCoroutineId { - fn from(id: chalk_ir::CoroutineId) -> Self { - Self::from_id(id.0) - } -} - -impl From for chalk_ir::CoroutineId { - fn from(id: crate::db::InternedCoroutineId) -> Self { - chalk_ir::CoroutineId(id.as_id()) - } -} - -pub fn to_foreign_def_id(id: TypeAliasId) -> ForeignDefId { - chalk_ir::ForeignDefId(id.as_id()) -} - -pub fn from_foreign_def_id(id: ForeignDefId) -> TypeAliasId { - FromId::from_id(id.0) -} - -pub fn to_assoc_type_id(id: TypeAliasId) -> AssocTypeId { - chalk_ir::AssocTypeId(id.as_id()) -} - -pub fn from_assoc_type_id(id: AssocTypeId) -> TypeAliasId { - FromId::from_id(id.0) -} - -pub fn from_placeholder_idx( - db: &dyn HirDatabase, - idx: PlaceholderIndex, -) -> (TypeOrConstParamId, u32) { - assert_eq!(idx.ui, chalk_ir::UniverseIndex::ROOT); - // SAFETY: We cannot really encapsulate this unfortunately, so just hope this is sound. - let interned_id = - InternedTypeOrConstParamId::from_id(unsafe { Id::from_index(idx.idx.try_into().unwrap()) }); - interned_id.loc(db) -} - -pub fn to_placeholder_idx( - db: &dyn HirDatabase, - id: TypeOrConstParamId, - idx: u32, -) -> PlaceholderIndex { - let interned_id = InternedTypeOrConstParamId::new(db, (id, idx)); - PlaceholderIndex { - ui: chalk_ir::UniverseIndex::ROOT, - idx: interned_id.as_id().index() as usize, - } -} - -pub fn to_placeholder_idx_no_index( - db: &dyn HirDatabase, - id: TypeOrConstParamId, -) -> PlaceholderIndex { - let index = crate::generics::generics(db, id.parent) - .type_or_const_param_idx(id) - .expect("param not found"); - to_placeholder_idx(db, id, index as u32) -} - -pub fn lt_from_placeholder_idx( - db: &dyn HirDatabase, - idx: PlaceholderIndex, -) -> (LifetimeParamId, u32) { - assert_eq!(idx.ui, chalk_ir::UniverseIndex::ROOT); - // SAFETY: We cannot really encapsulate this unfortunately, so just hope this is sound. - let interned_id = - InternedLifetimeParamId::from_id(unsafe { Id::from_index(idx.idx.try_into().unwrap()) }); - interned_id.loc(db) -} - -pub fn lt_to_placeholder_idx( - db: &dyn HirDatabase, - id: LifetimeParamId, - idx: u32, -) -> PlaceholderIndex { - let interned_id = InternedLifetimeParamId::new(db, (id, idx)); - PlaceholderIndex { - ui: chalk_ir::UniverseIndex::ROOT, - idx: interned_id.as_id().index() as usize, - } -} - -pub fn to_chalk_trait_id(id: TraitId) -> ChalkTraitId { - chalk_ir::TraitId(id.as_id()) -} - -pub fn from_chalk_trait_id(id: ChalkTraitId) -> TraitId { - FromId::from_id(id.0) -} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs index 06c7cdd4e416..cec63566338f 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs @@ -25,10 +25,8 @@ use smallvec::{SmallVec, smallvec}; use stdx::never; use triomphe::Arc; -use crate::next_solver::infer::InferCtxt; -use crate::next_solver::infer::select::ImplSource; use crate::{ - TraitEnvironment, TyBuilder, + TraitEnvironment, autoderef::{self, AutoderefKind}, db::HirDatabase, infer::{Adjust, Adjustment, OverloadedDeref, PointerCast, unify::InferenceTable}, @@ -37,7 +35,8 @@ use crate::{ Canonical, DbInterner, ErrorGuaranteed, GenericArgs, Goal, Predicate, Region, SolverDefId, TraitRef, Ty, TyKind, TypingMode, infer::{ - DbInternerInferExt, DefineOpaqueTypes, + DbInternerInferExt, InferCtxt, + select::ImplSource, traits::{Obligation, ObligationCause, PredicateObligation}, }, obligation_ctxt::ObligationCtxt, @@ -1597,9 +1596,9 @@ fn is_valid_impl_method_candidate<'db>( return IsValidCandidate::NotVisible; } let self_ty_matches = table.run_in_snapshot(|table| { - let expected_self_ty = TyBuilder::impl_self_ty(db, impl_id) - .fill_with_inference_vars(table) - .build(table.interner()); + let impl_args = table.fresh_args_for_item(impl_id.into()); + let expected_self_ty = + db.impl_self_ty(impl_id).instantiate(table.interner(), impl_args); table.unify(expected_self_ty, self_ty) }); if !self_ty_matches { @@ -1654,7 +1653,7 @@ fn is_valid_trait_method_candidate<'db>( let res = table .infer_ctxt .at(&ObligationCause::dummy(), table.trait_env.env) - .relate(DefineOpaqueTypes::No, expected_receiver, variance, receiver_ty); + .relate(expected_receiver, variance, receiver_ty); let Ok(infer_ok) = res else { return IsValidCandidate::No; }; @@ -1727,7 +1726,7 @@ fn is_valid_impl_fn_candidate<'db>( // We need to consider the bounds on the impl to distinguish functions of the same name // for a type. - let predicates = db.generic_predicates_ns(impl_id.into()); + let predicates = db.generic_predicates(impl_id.into()); let Some(predicates) = predicates.instantiate(table.interner(), impl_subst) else { return IsValidCandidate::Yes; }; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs index 936895fb7fd3..7aebe17e5b4e 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs @@ -196,7 +196,7 @@ impl ProjectionElem { }, ProjectionElem::Field(Either::Left(f)) => match base.kind() { TyKind::Adt(_, subst) => { - db.field_types_ns(f.parent)[f.local_id].instantiate(interner, subst) + db.field_types(f.parent)[f.local_id].instantiate(interner, subst) } ty => { never!("Only adt has field, found {:?}", ty); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs index 444336ca3f9b..6e62bcbbddef 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs @@ -1696,7 +1696,7 @@ impl<'db> Evaluator<'db> { if let TyKind::Adt(adt_ef, subst) = kind && let AdtId::StructId(struct_id) = adt_ef.def_id().0 { - let field_types = self.db.field_types_ns(struct_id.into()); + let field_types = self.db.field_types(struct_id.into()); if let Some(ty) = field_types.iter().last().map(|it| it.1.instantiate(self.interner(), subst)) { @@ -1775,9 +1775,9 @@ impl<'db> Evaluator<'db> { else { not_supported!("unsizing struct without field"); }; - let target_last_field = self.db.field_types_ns(id.into())[last_field] + let target_last_field = self.db.field_types(id.into())[last_field] .instantiate(self.interner(), target_subst); - let current_last_field = self.db.field_types_ns(id.into())[last_field] + let current_last_field = self.db.field_types(id.into())[last_field] .instantiate(self.interner(), current_subst); return self.unsizing_ptr_from_addr( target_last_field, @@ -2268,7 +2268,7 @@ impl<'db> Evaluator<'db> { AdtId::StructId(s) => { let data = s.fields(this.db); let layout = this.layout(ty)?; - let field_types = this.db.field_types_ns(s.into()); + let field_types = this.db.field_types(s.into()); for (f, _) in data.fields().iter() { let offset = layout .fields @@ -2296,7 +2296,7 @@ impl<'db> Evaluator<'db> { e, ) { let data = v.fields(this.db); - let field_types = this.db.field_types_ns(v.into()); + let field_types = this.db.field_types(v.into()); for (f, _) in data.fields().iter() { let offset = l.fields.offset(u32::from(f.into_raw()) as usize).bytes_usize(); @@ -2373,7 +2373,7 @@ impl<'db> Evaluator<'db> { } TyKind::Adt(id, args) => match id.def_id().0 { AdtId::StructId(s) => { - for (i, (_, ty)) in self.db.field_types_ns(s.into()).iter().enumerate() { + for (i, (_, ty)) in self.db.field_types(s.into()).iter().enumerate() { let offset = layout.fields.offset(i).bytes_usize(); let ty = ty.instantiate(self.interner(), args); self.patch_addresses( @@ -2394,7 +2394,7 @@ impl<'db> Evaluator<'db> { self.read_memory(addr, layout.size.bytes_usize())?, e, ) { - for (i, (_, ty)) in self.db.field_types_ns(ev.into()).iter().enumerate() { + for (i, (_, ty)) in self.db.field_types(ev.into()).iter().enumerate() { let offset = layout.fields.offset(i).bytes_usize(); let ty = ty.instantiate(self.interner(), args); self.patch_addresses( @@ -2895,7 +2895,7 @@ impl<'db> Evaluator<'db> { let variant_fields = s.fields(self.db); match variant_fields.shape { FieldsShape::Record | FieldsShape::Tuple => { - let field_types = self.db.field_types_ns(s.into()); + let field_types = self.db.field_types(s.into()); for (field, _) in variant_fields.fields().iter() { let offset = layout .fields diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs index c45ae9dcc3d3..4b1adecf8c87 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs @@ -1383,7 +1383,7 @@ impl<'db> Evaluator<'db> { AdtId::StructId(s) => s, _ => not_supported!("unsized enum or union"), }; - let field_types = self.db.field_types_ns(id.into()); + let field_types = self.db.field_types(id.into()); let last_field_ty = field_types.iter().next_back().unwrap().1.instantiate(self.interner(), subst); let sized_part_size = diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim/simd.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim/simd.rs index ade94b94c0ee..4c64a70a7a62 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim/simd.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim/simd.rs @@ -34,7 +34,7 @@ impl<'db> Evaluator<'db> { let Some((first_field, _)) = fields.iter().next() else { not_supported!("simd type with no field"); }; - let field_ty = self.db.field_types_ns(id.into())[first_field] + let field_ty = self.db.field_types(id.into())[first_field] .instantiate(self.interner(), subst); return Ok((fields.len(), field_ty)); } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs index 4eb4aa91598e..f242115afeff 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs @@ -636,16 +636,13 @@ fn main() { ); } -#[ignore = " -FIXME(next-solver): -This does not work currently because I replaced homemade selection with selection by the trait solver; -This will work once we implement `Interner::impl_specializes()` properly. -"] #[test] fn specialization_array_clone() { check_pass( r#" //- minicore: copy, derive, slice, index, coerce_unsized, panic +#![feature(min_specialization)] + impl Clone for [T; N] { #[inline] fn clone(&self) -> Self { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs index 92f9cd42615e..1439c43e99e8 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs @@ -43,7 +43,6 @@ use crate::{ next_solver::{ Const, DbInterner, ParamConst, Region, TyKind, TypingMode, UnevaluatedConst, infer::{DbInternerInferExt, InferCtxt}, - mapping::NextSolverToChalk, }, traits::FnTrait, }; @@ -303,6 +302,7 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { let resolver = owner.resolver(db); let env = db.trait_environment_for_body(owner); let interner = DbInterner::new_with(db, Some(env.krate), env.block); + // FIXME(next-solver): Is `non_body_analysis()` correct here? Don't we want to reveal opaque types defined by this body? let infcx = interner.infer_ctxt().build(TypingMode::non_body_analysis()); MirLowerCtx { @@ -1766,8 +1766,8 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { fn is_uninhabited(&self, expr_id: ExprId) -> bool { is_ty_uninhabited_from( - self.db, - &self.infer[expr_id].to_chalk(self.interner()), + &self.infcx, + self.infer[expr_id], self.owner.module(self.db), self.env.clone(), ) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/pretty.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/pretty.rs index e46edb815918..0c5a64935e49 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/pretty.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/pretty.rs @@ -118,10 +118,10 @@ enum LocalName<'db> { Binding(Name, LocalId<'db>), } -impl<'db> HirDisplay for LocalName<'db> { +impl<'db> HirDisplay<'db> for LocalName<'db> { fn hir_fmt( &self, - f: &mut crate::display::HirFormatter<'_>, + f: &mut crate::display::HirFormatter<'_, 'db>, ) -> Result<(), crate::display::HirDisplayError> { match self { LocalName::Unknown(l) => write!(f, "_{}", u32::from(l.into_raw())), @@ -489,7 +489,7 @@ impl<'a, 'db> MirPrettyCtx<'a, 'db> { } } - fn hir_display<'b, T: HirDisplay>(&self, ty: &'b T) -> impl Display + use<'a, 'b, 'db, T> + fn hir_display<'b, T: HirDisplay<'db>>(&self, ty: &'b T) -> impl Display + use<'a, 'b, 'db, T> where 'db: 'b, { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver.rs index 776e0d956f40..8c52a847d1e9 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver.rs @@ -1,5 +1,4 @@ //! Things relevant to the next trait solver. -#![allow(unused, unreachable_pub)] pub mod abi; mod consts; @@ -12,7 +11,6 @@ pub mod infer; pub(crate) mod inspect; pub mod interner; mod ir_print; -pub mod mapping; pub mod normalize; pub mod obligation_ctxt; mod opaques; @@ -33,7 +31,7 @@ pub use region::*; pub use solver::*; pub use ty::*; -pub use crate::lower_nextsolver::ImplTraitIdx; +pub use crate::lower::ImplTraitIdx; pub use rustc_ast_ir::Mutability; pub type Binder<'db, T> = rustc_type_ir::Binder, T>; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/consts.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/consts.rs index 2fc1fc4f45a5..926dbdc03d03 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/consts.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/consts.rs @@ -2,21 +2,20 @@ use std::hash::Hash; -use hir_def::{ConstParamId, TypeOrConstParamId}; -use intern::{Interned, Symbol}; +use hir_def::ConstParamId; use macros::{TypeFoldable, TypeVisitable}; -use rustc_ast_ir::{try_visit, visit::VisitorResult}; +use rustc_ast_ir::visit::VisitorResult; use rustc_type_ir::{ - BoundVar, DebruijnIndex, FlagComputation, Flags, TypeFoldable, TypeSuperFoldable, - TypeSuperVisitable, TypeVisitable, TypeVisitableExt, WithCachedTypeInfo, + BoundVar, BoundVarIndexKind, ConstVid, DebruijnIndex, FlagComputation, Flags, InferConst, + TypeFoldable, TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, + WithCachedTypeInfo, inherent::{IntoKind, ParamEnv as _, PlaceholderLike, SliceLike}, relate::Relate, }; use crate::{ - ConstScalar, MemoryMap, - interner::InternedWrapperNoDebug, - next_solver::{ClauseKind, ParamEnv}, + MemoryMap, + next_solver::{ClauseKind, ParamEnv, interner::InternedWrapperNoDebug}, }; use super::{BoundVarKind, DbInterner, ErrorGuaranteed, GenericArgs, Placeholder, Ty}; @@ -51,11 +50,11 @@ impl<'db> Const<'db> { } pub fn error(interner: DbInterner<'db>) -> Self { - Const::new(interner, rustc_type_ir::ConstKind::Error(ErrorGuaranteed)) + Const::new(interner, ConstKind::Error(ErrorGuaranteed)) } pub fn new_param(interner: DbInterner<'db>, param: ParamConst) -> Self { - Const::new(interner, rustc_type_ir::ConstKind::Param(param)) + Const::new(interner, ConstKind::Param(param)) } pub fn new_placeholder(interner: DbInterner<'db>, placeholder: PlaceholderConst) -> Self { @@ -63,7 +62,7 @@ impl<'db> Const<'db> { } pub fn new_bound(interner: DbInterner<'db>, index: DebruijnIndex, bound: BoundConst) -> Self { - Const::new(interner, ConstKind::Bound(index, bound)) + Const::new(interner, ConstKind::Bound(BoundVarIndexKind::Bound(index), bound)) } pub fn new_valtree( @@ -82,7 +81,11 @@ impl<'db> Const<'db> { } pub fn is_ct_infer(&self) -> bool { - matches!(&self.inner().internee, ConstKind::Infer(_)) + matches!(self.kind(), ConstKind::Infer(_)) + } + + pub fn is_error(&self) -> bool { + matches!(self.kind(), ConstKind::Error(_)) } pub fn is_trivially_wf(self) -> bool { @@ -338,28 +341,34 @@ impl<'db> Flags for Const<'db> { } impl<'db> rustc_type_ir::inherent::Const> for Const<'db> { - fn new_infer(interner: DbInterner<'db>, var: rustc_type_ir::InferConst) -> Self { + fn new_infer(interner: DbInterner<'db>, var: InferConst) -> Self { Const::new(interner, ConstKind::Infer(var)) } - fn new_var(interner: DbInterner<'db>, var: rustc_type_ir::ConstVid) -> Self { - Const::new(interner, ConstKind::Infer(rustc_type_ir::InferConst::Var(var))) + fn new_var(interner: DbInterner<'db>, var: ConstVid) -> Self { + Const::new(interner, ConstKind::Infer(InferConst::Var(var))) } - fn new_bound( - interner: DbInterner<'db>, - debruijn: rustc_type_ir::DebruijnIndex, - var: BoundConst, - ) -> Self { - Const::new(interner, ConstKind::Bound(debruijn, var)) + fn new_bound(interner: DbInterner<'db>, debruijn: DebruijnIndex, var: BoundConst) -> Self { + Const::new(interner, ConstKind::Bound(BoundVarIndexKind::Bound(debruijn), var)) } - fn new_anon_bound( + fn new_anon_bound(interner: DbInterner<'db>, debruijn: DebruijnIndex, var: BoundVar) -> Self { + Const::new( + interner, + ConstKind::Bound(BoundVarIndexKind::Bound(debruijn), BoundConst { var }), + ) + } + + fn new_canonical_bound(interner: DbInterner<'db>, var: BoundVar) -> Self { + Const::new(interner, ConstKind::Bound(BoundVarIndexKind::Canonical, BoundConst { var })) + } + + fn new_placeholder( interner: DbInterner<'db>, - debruijn: rustc_type_ir::DebruijnIndex, - var: rustc_type_ir::BoundVar, + param: as rustc_type_ir::Interner>::PlaceholderConst, ) -> Self { - Const::new(interner, ConstKind::Bound(debruijn, BoundConst { var })) + Const::new(interner, ConstKind::Placeholder(param)) } fn new_unevaluated( @@ -376,13 +385,6 @@ impl<'db> rustc_type_ir::inherent::Const> for Const<'db> { fn new_error(interner: DbInterner<'db>, guar: ErrorGuaranteed) -> Self { Const::new(interner, ConstKind::Error(guar)) } - - fn new_placeholder( - interner: DbInterner<'db>, - param: as rustc_type_ir::Interner>::PlaceholderConst, - ) -> Self { - Const::new(interner, ConstKind::Placeholder(param)) - } } #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] @@ -425,7 +427,7 @@ impl<'db> PlaceholderLike> for PlaceholderConst { impl<'db> Relate> for ExprConst { fn relate>>( - relation: &mut R, + _relation: &mut R, a: Self, b: Self, ) -> rustc_type_ir::relate::RelateResult, Self> { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/def_id.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/def_id.rs index 789be3b731b1..0ff0b086a087 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/def_id.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/def_id.rs @@ -1,8 +1,8 @@ //! Definition of `SolverDefId` use hir_def::{ - AdtId, CallableDefId, ConstId, EnumId, EnumVariantId, FunctionId, GeneralConstId, GenericDefId, - ImplId, StaticId, StructId, TraitId, TypeAliasId, UnionId, + AdtId, CallableDefId, ConstId, DefWithBodyId, EnumId, EnumVariantId, FunctionId, + GeneralConstId, GenericDefId, ImplId, StaticId, StructId, TraitId, TypeAliasId, UnionId, }; use rustc_type_ir::inherent; use stdx::impl_from; @@ -29,6 +29,8 @@ pub enum SolverDefId { InternedClosureId(InternedClosureId), InternedCoroutineId(InternedCoroutineId), InternedOpaqueTyId(InternedOpaqueTyId), + EnumVariantId(EnumVariantId), + // FIXME(next-solver): Do we need the separation of `Ctor`? It duplicates some variants. Ctor(Ctor), } @@ -73,6 +75,16 @@ impl std::fmt::Debug for SolverDefId { SolverDefId::InternedOpaqueTyId(id) => { f.debug_tuple("InternedOpaqueTyId").field(&id).finish() } + SolverDefId::EnumVariantId(id) => { + let parent_enum = id.loc(db).parent; + f.debug_tuple("EnumVariantId") + .field(&format_args!( + "\"{}::{}\"", + db.enum_signature(parent_enum).name.as_str(), + parent_enum.enum_variants(db).variant_name_by_id(id).unwrap().as_str() + )) + .finish() + } SolverDefId::Ctor(Ctor::Struct(id)) => { f.debug_tuple("Ctor").field(&db.struct_signature(id).name.as_str()).finish() } @@ -101,6 +113,7 @@ impl_from!( InternedClosureId, InternedCoroutineId, InternedOpaqueTyId, + EnumVariantId, Ctor for SolverDefId ); @@ -129,8 +142,20 @@ impl From for SolverDefId { } } +impl From for SolverDefId { + #[inline] + fn from(value: DefWithBodyId) -> Self { + match value { + DefWithBodyId::FunctionId(id) => id.into(), + DefWithBodyId::StaticId(id) => id.into(), + DefWithBodyId::ConstId(id) => id.into(), + DefWithBodyId::VariantId(id) => id.into(), + } + } +} + impl TryFrom for GenericDefId { - type Error = SolverDefId; + type Error = (); fn try_from(value: SolverDefId) -> Result { Ok(match value { @@ -141,10 +166,11 @@ impl TryFrom for GenericDefId { SolverDefId::StaticId(static_id) => GenericDefId::StaticId(static_id), SolverDefId::TraitId(trait_id) => GenericDefId::TraitId(trait_id), SolverDefId::TypeAliasId(type_alias_id) => GenericDefId::TypeAliasId(type_alias_id), - SolverDefId::InternedClosureId(_) => return Err(value), - SolverDefId::InternedCoroutineId(_) => return Err(value), - SolverDefId::InternedOpaqueTyId(_) => return Err(value), - SolverDefId::Ctor(_) => return Err(value), + SolverDefId::InternedClosureId(_) + | SolverDefId::InternedCoroutineId(_) + | SolverDefId::InternedOpaqueTyId(_) + | SolverDefId::EnumVariantId(_) + | SolverDefId::Ctor(_) => return Err(()), }) } } @@ -185,7 +211,7 @@ macro_rules! declare_id_wrapper { impl std::fmt::Debug for $name { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - std::fmt::Debug::fmt(&self.0, f) + std::fmt::Debug::fmt(&SolverDefId::from(self.0), f) } } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/fold.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/fold.rs index a42fdb094304..f776b6ecfc43 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/fold.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/fold.rs @@ -1,9 +1,8 @@ //! Fold impls for the next-trait-solver. use rustc_type_ir::{ - BoundVar, DebruijnIndex, RegionKind, TypeFoldable, TypeFolder, TypeSuperFoldable, - TypeVisitableExt, - inherent::{IntoKind, Region as _}, + BoundVarIndexKind, DebruijnIndex, RegionKind, TypeFoldable, TypeFolder, TypeSuperFoldable, + TypeVisitableExt, inherent::IntoKind, }; use crate::next_solver::BoundConst; @@ -55,7 +54,7 @@ pub(crate) struct BoundVarReplacer<'db, D> { } impl<'db, D: BoundVarReplacerDelegate<'db>> BoundVarReplacer<'db, D> { - pub fn new(tcx: DbInterner<'db>, delegate: D) -> Self { + pub(crate) fn new(tcx: DbInterner<'db>, delegate: D) -> Self { BoundVarReplacer { interner: tcx, current_index: DebruijnIndex::ZERO, delegate } } } @@ -80,7 +79,9 @@ where fn fold_ty(&mut self, t: Ty<'db>) -> Ty<'db> { match t.kind() { - TyKind::Bound(debruijn, bound_ty) if debruijn == self.current_index => { + TyKind::Bound(BoundVarIndexKind::Bound(debruijn), bound_ty) + if debruijn == self.current_index => + { let ty = self.delegate.replace_ty(bound_ty); debug_assert!(!ty.has_vars_bound_above(DebruijnIndex::ZERO)); rustc_type_ir::shift_vars(self.interner, ty, self.current_index.as_u32()) @@ -97,9 +98,12 @@ where fn fold_region(&mut self, r: Region<'db>) -> Region<'db> { match r.kind() { - RegionKind::ReBound(debruijn, br) if debruijn == self.current_index => { + RegionKind::ReBound(BoundVarIndexKind::Bound(debruijn), br) + if debruijn == self.current_index => + { let region = self.delegate.replace_region(br); - if let RegionKind::ReBound(debruijn1, br) = region.kind() { + if let RegionKind::ReBound(BoundVarIndexKind::Bound(debruijn1), br) = region.kind() + { // If the callback returns a bound region, // that region should always use the INNERMOST // debruijn index. Then we adjust it to the @@ -116,7 +120,9 @@ where fn fold_const(&mut self, ct: Const<'db>) -> Const<'db> { match ct.kind() { - ConstKind::Bound(debruijn, bound_const) if debruijn == self.current_index => { + ConstKind::Bound(BoundVarIndexKind::Bound(debruijn), bound_const) + if debruijn == self.current_index => + { let ct = self.delegate.replace_const(bound_const); debug_assert!(!ct.has_vars_bound_above(DebruijnIndex::ZERO)); rustc_type_ir::shift_vars(self.interner, ct, self.current_index.as_u32()) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/fulfill.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/fulfill.rs index 262da858d466..7783075d1a36 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/fulfill.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/fulfill.rs @@ -2,7 +2,7 @@ mod errors; -use std::{marker::PhantomData, mem, ops::ControlFlow, vec::ExtractIf}; +use std::{mem, ops::ControlFlow}; use rustc_hash::FxHashSet; use rustc_next_trait_solver::{ @@ -46,6 +46,7 @@ pub struct FulfillmentCtxt<'db> { /// outside of this snapshot leads to subtle bugs if the snapshot /// gets rolled back. Because of this we explicitly check that we only /// use the context in exactly this snapshot. + #[expect(unused)] usable_in_snapshot: usize, } @@ -69,10 +70,6 @@ impl<'db> ObligationStorage<'db> { self.pending.push((obligation, stalled_on)); } - fn has_pending_obligations(&self) -> bool { - !self.pending.is_empty() || !self.overflowed.is_empty() - } - fn clone_pending(&self) -> PredicateObligations<'db> { let mut obligations: PredicateObligations<'db> = self.pending.iter().map(|(o, _)| o.clone()).collect(); @@ -125,10 +122,10 @@ impl<'db> FulfillmentCtxt<'db> { } impl<'db> FulfillmentCtxt<'db> { - #[tracing::instrument(level = "trace", skip(self, infcx))] + #[tracing::instrument(level = "trace", skip(self, _infcx))] pub(crate) fn register_predicate_obligation( &mut self, - infcx: &InferCtxt<'db>, + _infcx: &InferCtxt<'db>, obligation: PredicateObligation<'db>, ) { // FIXME: See the comment in `try_evaluate_obligations()`. @@ -138,7 +135,7 @@ impl<'db> FulfillmentCtxt<'db> { pub(crate) fn register_predicate_obligations( &mut self, - infcx: &InferCtxt<'db>, + _infcx: &InferCtxt<'db>, obligations: impl IntoIterator>, ) { // FIXME: See the comment in `try_evaluate_obligations()`. @@ -148,7 +145,7 @@ impl<'db> FulfillmentCtxt<'db> { pub(crate) fn collect_remaining_errors( &mut self, - infcx: &InferCtxt<'db>, + _infcx: &InferCtxt<'db>, ) -> Vec> { self.obligations .pending @@ -235,10 +232,6 @@ impl<'db> FulfillmentCtxt<'db> { self.collect_remaining_errors(infcx) } - fn has_pending_obligations(&self) -> bool { - self.obligations.has_pending_obligations() - } - pub(crate) fn pending_obligations(&self) -> PredicateObligations<'db> { self.obligations.clone_pending() } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/fulfill/errors.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/fulfill/errors.rs index ab4a229fbc05..82dbf9403cab 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/fulfill/errors.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/fulfill/errors.rs @@ -9,15 +9,15 @@ use rustc_next_trait_solver::solve::{GoalEvaluation, SolverDelegateEvalExt}; use rustc_type_ir::{ AliasRelationDirection, AliasTermKind, HostEffectPredicate, Interner, PredicatePolarity, error::ExpectedFound, - inherent::{IntoKind, PlaceholderConst, SliceLike, Span as _}, + inherent::{IntoKind, SliceLike, Span as _}, lang_items::SolverTraitLangItem, - solve::{CandidateSource, Certainty, GoalSource, MaybeCause, NoSolution}, + solve::{Certainty, GoalSource, MaybeCause, NoSolution}, }; use tracing::{instrument, trace}; use crate::next_solver::{ AliasTerm, Binder, ClauseKind, Const, ConstKind, DbInterner, PolyTraitPredicate, PredicateKind, - SolverContext, SolverDefId, Span, Term, TraitPredicate, Ty, TyKind, TypeError, + SolverContext, Span, Term, TraitPredicate, Ty, TyKind, TypeError, fulfill::NextSolverError, infer::{ InferCtxt, @@ -529,7 +529,6 @@ impl<'db> ProofTreeVisitor<'db> for BestObligation<'db> { } } - let mut impl_where_bound_count = 0; for nested_goal in nested_goals { trace!(nested_goal = ?(nested_goal.goal(), nested_goal.source(), nested_goal.result())); @@ -542,34 +541,27 @@ impl<'db> ProofTreeVisitor<'db> for BestObligation<'db> { recursion_depth: self.obligation.recursion_depth + 1, }; - let obligation; - match (child_mode, nested_goal.source()) { + let obligation = match (child_mode, nested_goal.source()) { ( ChildMode::Trait(_) | ChildMode::Host(_), GoalSource::Misc | GoalSource::TypeRelating | GoalSource::NormalizeGoal(_), ) => { continue; } - (ChildMode::Trait(parent_trait_pred), GoalSource::ImplWhereBound) => { - obligation = make_obligation(); - impl_where_bound_count += 1; + (ChildMode::Trait(_parent_trait_pred), GoalSource::ImplWhereBound) => { + make_obligation() } ( - ChildMode::Host(parent_host_pred), + ChildMode::Host(_parent_host_pred), GoalSource::ImplWhereBound | GoalSource::AliasBoundConstCondition, - ) => { - obligation = make_obligation(); - impl_where_bound_count += 1; - } + ) => make_obligation(), // Skip over a higher-ranked predicate. - (_, GoalSource::InstantiateHigherRanked) => { - obligation = self.obligation.clone(); - } + (_, GoalSource::InstantiateHigherRanked) => self.obligation.clone(), (ChildMode::PassThrough, _) | (_, GoalSource::AliasWellFormed | GoalSource::AliasBoundConstCondition) => { - obligation = make_obligation(); + make_obligation() } - } + }; self.with_derived_obligation(obligation, |this| nested_goal.visit_with(this))?; } @@ -628,35 +620,29 @@ impl<'db> NextSolverError<'db> { } mod wf { - use std::iter; - use hir_def::ItemContainerId; use rustc_type_ir::inherent::{ - AdtDef, BoundExistentialPredicates, GenericArg, GenericArgs as _, IntoKind, SliceLike, - Term as _, Ty as _, + AdtDef, BoundExistentialPredicates, GenericArgs as _, IntoKind, SliceLike, Term as _, + Ty as _, }; use rustc_type_ir::lang_items::SolverTraitLangItem; use rustc_type_ir::{ - Interner, PredicatePolarity, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, - TypeVisitor, + Interner, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, }; - use tracing::{debug, instrument, trace}; + use tracing::{debug, instrument}; use crate::next_solver::infer::InferCtxt; - use crate::next_solver::infer::traits::{ - Obligation, ObligationCause, PredicateObligation, PredicateObligations, - }; + use crate::next_solver::infer::traits::{Obligation, ObligationCause, PredicateObligations}; use crate::next_solver::{ - AliasTerm, Binder, ClauseKind, Const, ConstKind, Ctor, DbInterner, ExistentialPredicate, - GenericArgs, ParamEnv, Predicate, PredicateKind, Region, SolverDefId, Term, TraitPredicate, - TraitRef, Ty, TyKind, + Binder, ClauseKind, Const, ConstKind, Ctor, DbInterner, ExistentialPredicate, GenericArgs, + ParamEnv, Predicate, PredicateKind, Region, SolverDefId, Term, TraitRef, Ty, TyKind, }; /// Compute the predicates that are required for a type to be well-formed. /// /// This is only intended to be used in the new solver, since it does not /// take into account recursion depth or proper error-reporting spans. - pub fn unnormalized_obligations<'db>( + pub(crate) fn unnormalized_obligations<'db>( infcx: &InferCtxt<'db>, param_env: ParamEnv<'db>, term: Term<'db>, @@ -683,158 +669,11 @@ mod wf { recursion_depth: usize, } - /// Controls whether we "elaborate" supertraits and so forth on the WF - /// predicates. This is a kind of hack to address #43784. The - /// underlying problem in that issue was a trait structure like: - /// - /// ```ignore (illustrative) - /// trait Foo: Copy { } - /// trait Bar: Foo { } - /// impl Foo for T { } - /// impl Bar for T { } - /// ``` - /// - /// Here, in the `Foo` impl, we will check that `T: Copy` holds -- but - /// we decide that this is true because `T: Bar` is in the - /// where-clauses (and we can elaborate that to include `T: - /// Copy`). This wouldn't be a problem, except that when we check the - /// `Bar` impl, we decide that `T: Foo` must hold because of the `Foo` - /// impl. And so nowhere did we check that `T: Copy` holds! - /// - /// To resolve this, we elaborate the WF requirements that must be - /// proven when checking impls. This means that (e.g.) the `impl Bar - /// for T` will be forced to prove not only that `T: Foo` but also `T: - /// Copy` (which it won't be able to do, because there is no `Copy` - /// impl for `T`). - #[derive(Debug, PartialEq, Eq, Copy, Clone)] - enum Elaborate { - All, - None, - } - impl<'a, 'db> WfPredicates<'a, 'db> { fn interner(&self) -> DbInterner<'db> { self.infcx.interner } - /// Pushes the obligations required for `trait_ref` to be WF into `self.out`. - fn add_wf_preds_for_trait_pred( - &mut self, - trait_pred: TraitPredicate<'db>, - elaborate: Elaborate, - ) { - let tcx = self.interner(); - let trait_ref = trait_pred.trait_ref; - - // Negative trait predicates don't require supertraits to hold, just - // that their args are WF. - if trait_pred.polarity == PredicatePolarity::Negative { - self.add_wf_preds_for_negative_trait_pred(trait_ref); - return; - } - - // if the trait predicate is not const, the wf obligations should not be const as well. - let obligations = self.nominal_obligations(trait_ref.def_id.0.into(), trait_ref.args); - - debug!("compute_trait_pred obligations {:?}", obligations); - let param_env = self.param_env; - let depth = self.recursion_depth; - - let extend = |PredicateObligation { predicate, mut cause, .. }| { - Obligation::with_depth(tcx, cause, depth, param_env, predicate) - }; - - if let Elaborate::All = elaborate { - let implied_obligations = rustc_type_ir::elaborate::elaborate(tcx, obligations); - let implied_obligations = implied_obligations.map(extend); - self.out.extend(implied_obligations); - } else { - self.out.extend(obligations); - } - - self.out.extend( - trait_ref - .args - .iter() - .enumerate() - .filter_map(|(i, arg)| arg.as_term().map(|t| (i, t))) - .filter(|(_, term)| !term.has_escaping_bound_vars()) - .map(|(i, term)| { - let mut cause = ObligationCause::misc(); - // The first arg is the self ty - use the correct span for it. - Obligation::with_depth( - tcx, - cause, - depth, - param_env, - ClauseKind::WellFormed(term), - ) - }), - ); - } - - // Compute the obligations that are required for `trait_ref` to be WF, - // given that it is a *negative* trait predicate. - fn add_wf_preds_for_negative_trait_pred(&mut self, trait_ref: TraitRef<'db>) { - for arg in trait_ref.args { - if let Some(term) = arg.as_term() { - self.add_wf_preds_for_term(term); - } - } - } - - /// Pushes the obligations required for an alias (except inherent) to be WF - /// into `self.out`. - fn add_wf_preds_for_alias_term(&mut self, data: AliasTerm<'db>) { - // A projection is well-formed if - // - // (a) its predicates hold (*) - // (b) its args are wf - // - // (*) The predicates of an associated type include the predicates of - // the trait that it's contained in. For example, given - // - // trait A: Clone { - // type X where T: Copy; - // } - // - // The predicates of `<() as A>::X` are: - // [ - // `(): Sized` - // `(): Clone` - // `(): A` - // `i32: Sized` - // `i32: Clone` - // `i32: Copy` - // ] - let obligations = self.nominal_obligations(data.def_id, data.args); - self.out.extend(obligations); - - self.add_wf_preds_for_projection_args(data.args); - } - - fn add_wf_preds_for_projection_args(&mut self, args: GenericArgs<'db>) { - let tcx = self.interner(); - let cause = ObligationCause::new(); - let param_env = self.param_env; - let depth = self.recursion_depth; - - self.out.extend( - args.iter() - .filter_map(|arg| arg.as_term()) - .filter(|term| !term.has_escaping_bound_vars()) - .map(|term| { - Obligation::with_depth( - tcx, - cause.clone(), - depth, - param_env, - ClauseKind::WellFormed(term), - ) - }), - ); - } - fn require_sized(&mut self, subty: Ty<'db>) { if !subty.has_escaping_bound_vars() { let cause = ObligationCause::new(); @@ -895,7 +734,7 @@ mod wf { fn add_wf_preds_for_dyn_ty( &mut self, - ty: Ty<'db>, + _ty: Ty<'db>, data: &[Binder<'db, ExistentialPredicate<'db>>], region: Region<'db>, ) { @@ -1013,7 +852,7 @@ mod wf { )); } - TyKind::Pat(base_ty, pat) => { + TyKind::Pat(base_ty, _pat) => { self.require_sized(base_ty); } @@ -1036,7 +875,7 @@ mod wf { let obligations = self.nominal_obligations(data.def_id, data.args); self.out.extend(obligations); } - TyKind::Alias(rustc_type_ir::Inherent, data) => { + TyKind::Alias(rustc_type_ir::Inherent, _data) => { return; } @@ -1148,7 +987,7 @@ mod wf { // Let the visitor iterate into the argument/return // types appearing in the fn signature. } - TyKind::UnsafeBinder(ty) => {} + TyKind::UnsafeBinder(_ty) => {} TyKind::Dynamic(data, r) => { // WfObject @@ -1291,7 +1130,7 @@ mod wf { /// /// Requires that trait definitions have been processed so that we can /// elaborate predicates and walk supertraits. - pub fn object_region_bounds<'db>( + pub(crate) fn object_region_bounds<'db>( interner: DbInterner<'db>, existential_predicates: &[Binder<'db, ExistentialPredicate<'db>>], ) -> Vec> { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/generic_arg.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/generic_arg.rs index 38293c45422c..90bd44aee86f 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/generic_arg.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/generic_arg.rs @@ -1,27 +1,20 @@ //! Things related to generic args in the next-trait-solver. use hir_def::{GenericDefId, GenericParamId}; -use intern::{Interned, Symbol}; use macros::{TypeFoldable, TypeVisitable}; -use rustc_type_ir::inherent::Const as _; use rustc_type_ir::{ - ClosureArgs, CollectAndApply, ConstVid, CoroutineArgs, CoroutineClosureArgs, FnSig, FnSigTys, - GenericArgKind, IntTy, Interner, TermKind, TyKind, TyVid, TypeFoldable, TypeVisitable, - Variance, - inherent::{ - GenericArg as _, GenericArgs as _, GenericsOf, IntoKind, SliceLike, Term as _, Ty as _, - }, + ClosureArgs, CollectAndApply, ConstVid, CoroutineArgs, CoroutineClosureArgs, FnSigTys, + GenericArgKind, Interner, TermKind, TyKind, TyVid, Variance, + inherent::{GenericArg as _, GenericsOf, IntoKind, SliceLike, Term as _, Ty as _}, relate::{Relate, VarianceDiagInfo}, }; use smallvec::SmallVec; -use crate::db::HirDatabase; -use crate::next_solver::{Binder, PolyFnSig}; +use crate::next_solver::{PolyFnSig, interned_vec_db}; use super::{ Const, DbInterner, EarlyParamRegion, ErrorGuaranteed, ParamConst, Region, SolverDefId, Ty, Tys, - generics::{GenericParamDef, Generics}, - interned_vec_db, + generics::Generics, }; #[derive(Copy, Clone, PartialEq, Eq, Hash, TypeVisitable, TypeFoldable)] @@ -191,7 +184,7 @@ impl<'db> GenericArgs<'db> { mut mk_kind: F, ) -> GenericArgs<'db> where - F: FnMut(&Symbol, u32, GenericParamId, &[GenericArg<'db>]) -> GenericArg<'db>, + F: FnMut(u32, GenericParamId, &[GenericArg<'db>]) -> GenericArg<'db>, { let defs = interner.generics_of(def_id); let count = defs.count(); @@ -202,9 +195,7 @@ impl<'db> GenericArgs<'db> { /// Creates an all-error `GenericArgs`. pub fn error_for_item(interner: DbInterner<'db>, def_id: SolverDefId) -> GenericArgs<'db> { - GenericArgs::for_item(interner, def_id, |_, _, id, _| { - GenericArg::error_from_id(interner, id) - }) + GenericArgs::for_item(interner, def_id, |_, id, _| GenericArg::error_from_id(interner, id)) } /// Like `for_item`, but prefers the default of a parameter if it has any. @@ -214,14 +205,12 @@ impl<'db> GenericArgs<'db> { mut fallback: F, ) -> GenericArgs<'db> where - F: FnMut(&Symbol, u32, GenericParamId, &[GenericArg<'db>]) -> GenericArg<'db>, + F: FnMut(u32, GenericParamId, &[GenericArg<'db>]) -> GenericArg<'db>, { - let defaults = interner.db.generic_defaults_ns(def_id); - Self::for_item(interner, def_id.into(), |name, idx, id, prev| { - match defaults.get(idx as usize) { - Some(default) => default.instantiate(interner, prev), - None => fallback(name, idx, id, prev), - } + let defaults = interner.db.generic_defaults(def_id); + Self::for_item(interner, def_id.into(), |idx, id, prev| match defaults.get(idx as usize) { + Some(default) => default.instantiate(interner, prev), + None => fallback(idx, id, prev), }) } @@ -233,11 +222,11 @@ impl<'db> GenericArgs<'db> { mut fallback: F, ) -> GenericArgs<'db> where - F: FnMut(&Symbol, u32, GenericParamId, &[GenericArg<'db>]) -> GenericArg<'db>, + F: FnMut(u32, GenericParamId, &[GenericArg<'db>]) -> GenericArg<'db>, { let mut iter = first.into_iter(); - Self::for_item(interner, def_id, |name, idx, id, prev| { - iter.next().unwrap_or_else(|| fallback(name, idx, id, prev)) + Self::for_item(interner, def_id, |idx, id, prev| { + iter.next().unwrap_or_else(|| fallback(idx, id, prev)) }) } @@ -249,14 +238,14 @@ impl<'db> GenericArgs<'db> { mut fallback: F, ) -> GenericArgs<'db> where - F: FnMut(&Symbol, u32, GenericParamId, &[GenericArg<'db>]) -> GenericArg<'db>, + F: FnMut(u32, GenericParamId, &[GenericArg<'db>]) -> GenericArg<'db>, { - let defaults = interner.db.generic_defaults_ns(def_id); - Self::fill_rest(interner, def_id.into(), first, |name, idx, id, prev| { + let defaults = interner.db.generic_defaults(def_id); + Self::fill_rest(interner, def_id.into(), first, |idx, id, prev| { defaults .get(idx as usize) .map(|default| default.instantiate(interner, prev)) - .unwrap_or_else(|| fallback(name, idx, id, prev)) + .unwrap_or_else(|| fallback(idx, id, prev)) }) } @@ -266,9 +255,8 @@ impl<'db> GenericArgs<'db> { defs: Generics, mk_kind: &mut F, ) where - F: FnMut(&Symbol, u32, GenericParamId, &[GenericArg<'db>]) -> GenericArg<'db>, + F: FnMut(u32, GenericParamId, &[GenericArg<'db>]) -> GenericArg<'db>, { - let self_len = defs.own_params.len() as u32; if let Some(def_id) = defs.parent { let parent_defs = interner.generics_of(def_id.into()); Self::fill_item(args, interner, parent_defs, mk_kind); @@ -278,12 +266,11 @@ impl<'db> GenericArgs<'db> { fn fill_single(args: &mut SmallVec<[GenericArg<'db>; 8]>, defs: &Generics, mk_kind: &mut F) where - F: FnMut(&Symbol, u32, GenericParamId, &[GenericArg<'db>]) -> GenericArg<'db>, + F: FnMut(u32, GenericParamId, &[GenericArg<'db>]) -> GenericArg<'db>, { - let start_len = args.len(); args.reserve(defs.own_params.len()); for param in &defs.own_params { - let kind = mk_kind(¶m.name, args.len() as u32, param.id, args); + let kind = mk_kind(args.len() as u32, param.id, args); args.push(kind); } } @@ -374,9 +361,7 @@ impl<'db> rustc_type_ir::inherent::GenericArgs> for GenericArgs< interner: DbInterner<'db>, def_id: as rustc_type_ir::Interner>::DefId, ) -> as rustc_type_ir::Interner>::GenericArgs { - Self::for_item(interner, def_id, |name, index, kind, _| { - mk_param(interner, index, name, kind) - }) + Self::for_item(interner, def_id, |index, kind, _| mk_param(interner, index, kind)) } fn extend_with_error( @@ -384,7 +369,7 @@ impl<'db> rustc_type_ir::inherent::GenericArgs> for GenericArgs< def_id: as rustc_type_ir::Interner>::DefId, original_args: &[ as rustc_type_ir::Interner>::GenericArg], ) -> as rustc_type_ir::Interner>::GenericArgs { - Self::for_item(interner, def_id, |name, index, kind, _| { + Self::for_item(interner, def_id, |index, kind, _| { if let Some(arg) = original_args.get(index as usize) { *arg } else { @@ -461,7 +446,6 @@ impl<'db> rustc_type_ir::inherent::GenericArgs> for GenericArgs< signature_parts_ty, tupled_upvars_ty, coroutine_captures_by_ref_ty, - coroutine_witness_ty, ] => rustc_type_ir::CoroutineClosureArgsParts { parent_args: GenericArgs::new_from_iter( DbInterner::conjure(), @@ -494,18 +478,12 @@ impl<'db> rustc_type_ir::inherent::GenericArgs> for GenericArgs< } } -pub fn mk_param<'db>( - interner: DbInterner<'db>, - index: u32, - name: &Symbol, - id: GenericParamId, -) -> GenericArg<'db> { - let name = name.clone(); +pub fn mk_param<'db>(interner: DbInterner<'db>, index: u32, id: GenericParamId) -> GenericArg<'db> { match id { GenericParamId::LifetimeParamId(id) => { Region::new_early_param(interner, EarlyParamRegion { index, id }).into() } - GenericParamId::TypeParamId(id) => Ty::new_param(interner, id, index, name).into(), + GenericParamId::TypeParamId(id) => Ty::new_param(interner, id, index).into(), GenericParamId::ConstParamId(id) => { Const::new_param(interner, ParamConst { index, id }).into() } @@ -596,13 +574,4 @@ impl<'db> DbInterner<'db> { { T::collect_and_apply(iter, |xs| self.mk_args(xs)) } - - pub(super) fn check_args_compatible(self, def_id: SolverDefId, args: GenericArgs<'db>) -> bool { - // TODO - true - } - - pub(super) fn debug_assert_args_compatible(self, def_id: SolverDefId, args: GenericArgs<'db>) { - // TODO - } } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/generics.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/generics.rs index 5ec9a18a6c20..4d164a7e3bc5 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/generics.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/generics.rs @@ -1,36 +1,22 @@ //! Things related to generics in the next-trait-solver. use hir_def::{ - ConstParamId, GenericDefId, GenericParamId, ItemContainerId, LifetimeParamId, Lookup, - TypeOrConstParamId, TypeParamId, - db::DefDatabase, - expr_store::ExpressionStore, - hir::generics::{ - GenericParamDataRef, GenericParams, LifetimeParamData, LocalLifetimeParamId, - LocalTypeOrConstParamId, TypeOrConstParamData, TypeParamData, TypeParamProvenance, - WherePredicate, - }, + ConstParamId, GenericDefId, GenericParamId, LifetimeParamId, TypeOrConstParamId, TypeParamId, + hir::generics::{GenericParams, TypeOrConstParamData}, }; -use hir_expand::name::Name; -use intern::{Symbol, sym}; -use la_arena::Arena; -use rustc_type_ir::inherent::Ty as _; -use triomphe::Arc; -use crate::{db::HirDatabase, generics::parent_generic_def, next_solver::Ty}; +use crate::{db::HirDatabase, generics::parent_generic_def}; -use super::{Const, EarlyParamRegion, ErrorGuaranteed, ParamConst, Region, SolverDefId}; +use super::SolverDefId; -use super::{DbInterner, GenericArg}; +use super::DbInterner; pub(crate) fn generics(db: &dyn HirDatabase, def: SolverDefId) -> Generics { - let mk_lt = |parent, index, local_id, lt: &LifetimeParamData| { - let name = lt.name.symbol().clone(); + let mk_lt = |parent, index, local_id| { let id = GenericParamId::LifetimeParamId(LifetimeParamId { parent, local_id }); - GenericParamDef { name, index, id } + GenericParamDef { index, id } }; let mk_ty = |parent, index, local_id, p: &TypeOrConstParamData| { - let name = p.name().map(|n| n.symbol().clone()).unwrap_or_else(|| sym::MISSING_NAME); let id = TypeOrConstParamId { parent, local_id }; let id = match p { TypeOrConstParamData::TypeParamData(_) => { @@ -40,7 +26,7 @@ pub(crate) fn generics(db: &dyn HirDatabase, def: SolverDefId) -> Generics { GenericParamId::ConstParamId(ConstParamId::from_unchecked(id)) } }; - GenericParamDef { name, index, id } + GenericParamDef { index, id } }; let own_params_for_generic_params = |parent, params: &GenericParams| { let mut result = Vec::with_capacity(params.len()); @@ -51,8 +37,8 @@ pub(crate) fn generics(db: &dyn HirDatabase, def: SolverDefId) -> Generics { type_and_consts.next(); index += 1; } - result.extend(params.iter_lt().map(|(local_id, data)| { - let lt = mk_lt(parent, index, local_id, data); + result.extend(params.iter_lt().map(|(local_id, _data)| { + let lt = mk_lt(parent, index, local_id); index += 1; lt })); @@ -78,27 +64,6 @@ pub(crate) fn generics(db: &dyn HirDatabase, def: SolverDefId) -> Generics { crate::ImplTraitId::TypeAliasImplTrait(type_alias_id, _) => { (Some(type_alias_id.into()), Vec::new()) } - crate::ImplTraitId::AsyncBlockTypeImplTrait(def, _) => { - let param = TypeOrConstParamData::TypeParamData(TypeParamData { - name: None, - default: None, - provenance: TypeParamProvenance::TypeParamList, - }); - // Yes, there is a parent but we don't include it in the generics - // FIXME: It seems utterly sensitive to fake a generic param here. - // Also, what a horrible mess! - ( - None, - vec![mk_ty( - GenericDefId::FunctionId(salsa::plumbing::FromId::from_id(unsafe { - salsa::Id::from_index(salsa::Id::MAX_U32 - 1) - })), - 0, - LocalTypeOrConstParamId::from_raw(la_arena::RawIdx::from_u32(0)), - ¶m, - )], - ) - } } } _ => panic!("No generics for {def:?}"), @@ -121,8 +86,6 @@ pub struct Generics { #[derive(Debug)] pub struct GenericParamDef { - pub(crate) name: Symbol, - //def_id: GenericDefId, index: u32, pub(crate) id: GenericParamId, } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/at.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/at.rs index 8dfffe0d365e..70b659406f86 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/at.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/at.rs @@ -36,7 +36,7 @@ use crate::next_solver::{ AliasTerm, AliasTy, Binder, Const, DbInterner, GenericArg, Goal, ParamEnv, PolyExistentialProjection, PolyExistentialTraitRef, PolyFnSig, Predicate, Region, Span, Term, TraitRef, Ty, - fulfill::{FulfillmentCtxt, NextSolverError}, + fulfill::NextSolverError, infer::relate::lattice::{LatticeOp, LatticeOpKind}, }; @@ -45,16 +45,6 @@ use super::{ traits::{Obligation, ObligationCause}, }; -/// Whether we should define opaque types or just treat them opaquely. -/// -/// Currently only used to prevent predicate matching from matching anything -/// against opaque types. -#[derive(Debug, PartialEq, Eq, Clone, Copy)] -pub enum DefineOpaqueTypes { - Yes, - No, -} - #[derive(Clone, Copy)] pub struct At<'a, 'db> { pub infcx: &'a InferCtxt<'db>, @@ -107,12 +97,7 @@ impl<'a, 'db> At<'a, 'db> { /// call like `foo(x)`, where `foo: fn(i32)`, you might have /// `sup(i32, x)`, since the "expected" type is the type that /// appears in the signature. - pub fn sup( - self, - define_opaque_types: DefineOpaqueTypes, - expected: T, - actual: T, - ) -> InferResult<'db, ()> + pub fn sup(self, expected: T, actual: T) -> InferResult<'db, ()> where T: ToTrace<'db>, { @@ -128,12 +113,7 @@ impl<'a, 'db> At<'a, 'db> { } /// Makes `expected <: actual`. - pub fn sub( - self, - define_opaque_types: DefineOpaqueTypes, - expected: T, - actual: T, - ) -> InferResult<'db, ()> + pub fn sub(self, expected: T, actual: T) -> InferResult<'db, ()> where T: ToTrace<'db>, { @@ -149,31 +129,7 @@ impl<'a, 'db> At<'a, 'db> { } /// Makes `expected == actual`. - pub fn eq( - self, - define_opaque_types: DefineOpaqueTypes, - expected: T, - actual: T, - ) -> InferResult<'db, ()> - where - T: ToTrace<'db>, - { - self.eq_trace( - define_opaque_types, - ToTrace::to_trace(self.cause, expected, actual), - expected, - actual, - ) - } - - /// Makes `expected == actual`. - pub fn eq_trace( - self, - define_opaque_types: DefineOpaqueTypes, - trace: TypeTrace<'db>, - expected: T, - actual: T, - ) -> InferResult<'db, ()> + pub fn eq(self, expected: T, actual: T) -> InferResult<'db, ()> where T: Relate>, { @@ -188,20 +144,14 @@ impl<'a, 'db> At<'a, 'db> { .map(|goals| self.goals_to_obligations(goals)) } - pub fn relate( - self, - define_opaque_types: DefineOpaqueTypes, - expected: T, - variance: Variance, - actual: T, - ) -> InferResult<'db, ()> + pub fn relate(self, expected: T, variance: Variance, actual: T) -> InferResult<'db, ()> where T: ToTrace<'db>, { match variance { - Variance::Covariant => self.sub(define_opaque_types, expected, actual), - Variance::Invariant => self.eq(define_opaque_types, expected, actual), - Variance::Contravariant => self.sup(define_opaque_types, expected, actual), + Variance::Covariant => self.sub(expected, actual), + Variance::Invariant => self.eq(expected, actual), + Variance::Contravariant => self.sup(expected, actual), // We could make this make sense but it's not readily // exposed and I don't feel like dealing with it. Note diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/canonical/canonicalizer.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/canonical/canonicalizer.rs index beaac11a2de4..7995545b0eed 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/canonical/canonicalizer.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/canonical/canonicalizer.rs @@ -10,17 +10,16 @@ use rustc_index::Idx; use rustc_type_ir::InferTy::{self, FloatVar, IntVar, TyVar}; use rustc_type_ir::inherent::{Const as _, IntoKind as _, Region as _, SliceLike, Ty as _}; use rustc_type_ir::{ - BoundVar, CanonicalQueryInput, DebruijnIndex, Flags, InferConst, RegionKind, TyVid, TypeFlags, - TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, UniverseIndex, + BoundVar, BoundVarIndexKind, CanonicalQueryInput, DebruijnIndex, Flags, InferConst, RegionKind, + TyVid, TypeFlags, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, UniverseIndex, }; use smallvec::SmallVec; use tracing::debug; use crate::next_solver::infer::InferCtxt; use crate::next_solver::{ - Binder, BoundConst, BoundRegion, BoundRegionKind, BoundTy, Canonical, CanonicalVarKind, - CanonicalVars, Const, ConstKind, DbInterner, GenericArg, ParamEnvAnd, Placeholder, Region, Ty, - TyKind, + Binder, Canonical, CanonicalVarKind, CanonicalVars, Const, ConstKind, DbInterner, GenericArg, + ParamEnvAnd, Placeholder, Region, Ty, TyKind, }; /// When we canonicalize a value to form a query, we wind up replacing @@ -345,12 +344,9 @@ impl<'cx, 'db> TypeFolder> for Canonicalizer<'cx, 'db> { fn fold_region(&mut self, r: Region<'db>) -> Region<'db> { match r.kind() { - RegionKind::ReBound(index, ..) => { - if index >= self.binder_index { - panic!("escaping late-bound region during canonicalization"); - } else { - r - } + RegionKind::ReBound(BoundVarIndexKind::Bound(..), ..) => r, + RegionKind::ReBound(BoundVarIndexKind::Canonical, ..) => { + panic!("canonicalized bound var found during canonicalization"); } RegionKind::ReStatic @@ -427,12 +423,9 @@ impl<'cx, 'db> TypeFolder> for Canonicalizer<'cx, 'db> { self.canonicalize_ty_var(CanonicalVarKind::PlaceholderTy(placeholder), t) } - TyKind::Bound(debruijn, _) => { - if debruijn >= self.binder_index { - panic!("escaping bound type during canonicalization") - } else { - t - } + TyKind::Bound(BoundVarIndexKind::Bound(..), _) => t, + TyKind::Bound(BoundVarIndexKind::Canonical, ..) => { + panic!("canonicalized bound var found during canonicalization"); } TyKind::Closure(..) @@ -503,12 +496,11 @@ impl<'cx, 'db> TypeFolder> for Canonicalizer<'cx, 'db> { ConstKind::Infer(InferConst::Fresh(_)) => { panic!("encountered a fresh const during canonicalization") } - ConstKind::Bound(debruijn, _) => { - if debruijn >= self.binder_index { - panic!("escaping bound const during canonicalization") - } else { - return ct; - } + ConstKind::Bound(BoundVarIndexKind::Bound(..), _) => { + return ct; + } + ConstKind::Bound(BoundVarIndexKind::Canonical, ..) => { + panic!("canonicalized bound var found during canonicalization"); } ConstKind::Placeholder(placeholder) => { return self @@ -758,8 +750,7 @@ impl<'cx, 'db> Canonicalizer<'cx, 'db> { r: Region<'db>, ) -> Region<'db> { let var = self.canonical_var(info, r.into()); - let br = BoundRegion { var, kind: BoundRegionKind::Anon }; - Region::new_bound(self.cx(), self.binder_index, br) + Region::new_canonical_bound(self.cx(), var) } /// Given a type variable `ty_var` of the given kind, first check @@ -769,11 +760,7 @@ impl<'cx, 'db> Canonicalizer<'cx, 'db> { fn canonicalize_ty_var(&mut self, info: CanonicalVarKind<'db>, ty_var: Ty<'db>) -> Ty<'db> { debug_assert_eq!(ty_var, self.infcx.shallow_resolve(ty_var)); let var = self.canonical_var(info, ty_var.into()); - Ty::new_bound( - self.tcx, - self.binder_index, - BoundTy { kind: crate::next_solver::BoundTyKind::Anon, var }, - ) + Ty::new_canonical_bound(self.cx(), var) } /// Given a type variable `const_var` of the given kind, first check @@ -787,6 +774,6 @@ impl<'cx, 'db> Canonicalizer<'cx, 'db> { ) -> Const<'db> { debug_assert_eq!(const_var, self.infcx.shallow_resolve_const(const_var)); let var = self.canonical_var(info, const_var.into()); - Const::new_bound(self.tcx, self.binder_index, BoundConst { var }) + Const::new_canonical_bound(self.cx(), var) } } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/canonical/instantiate.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/canonical/instantiate.rs index 6c7a87ef5249..636029107154 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/canonical/instantiate.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/canonical/instantiate.rs @@ -6,24 +6,15 @@ //! //! [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html -use crate::next_solver::BoundConst; use crate::next_solver::{ - AliasTy, Binder, BoundRegion, BoundTy, Canonical, CanonicalVarValues, Const, DbInterner, Goal, - ParamEnv, Predicate, PredicateKind, Region, Ty, TyKind, - fold::FnMutDelegate, - infer::{ - DefineOpaqueTypes, InferCtxt, TypeTrace, - traits::{Obligation, PredicateObligations}, - }, + BoundConst, BoundRegion, BoundTy, Canonical, CanonicalVarValues, Clauses, Const, ConstKind, + DbInterner, GenericArg, Predicate, Region, RegionKind, Ty, TyKind, fold::FnMutDelegate, }; +use rustc_hash::FxHashMap; use rustc_type_ir::{ - AliasRelationDirection, AliasTyKind, BoundVar, GenericArgKind, InferTy, TypeFoldable, Upcast, - Variance, - inherent::{IntoKind, SliceLike}, - relate::{ - Relate, TypeRelation, VarianceDiagInfo, - combine::{super_combine_consts, super_combine_tys}, - }, + BoundVarIndexKind, GenericArgKind, TypeFlags, TypeFoldable, TypeFolder, TypeSuperFoldable, + TypeVisitableExt, + inherent::{GenericArg as _, IntoKind, SliceLike}, }; pub trait CanonicalExt<'db, V> { @@ -102,6 +93,79 @@ where }, }; - tcx.replace_escaping_bound_vars_uncached(value, delegate) + let value = tcx.replace_escaping_bound_vars_uncached(value, delegate); + value.fold_with(&mut CanonicalInstantiator { + tcx, + var_values: var_values.var_values.as_slice(), + cache: Default::default(), + }) + } +} + +/// Replaces the bound vars in a canonical binder with var values. +struct CanonicalInstantiator<'db, 'a> { + tcx: DbInterner<'db>, + + // The values that the bound vars are being instantiated with. + var_values: &'a [GenericArg<'db>], + + // Because we use `BoundVarIndexKind::Canonical`, we can cache + // based only on the entire ty, not worrying about a `DebruijnIndex` + cache: FxHashMap, Ty<'db>>, +} + +impl<'db, 'a> TypeFolder> for CanonicalInstantiator<'db, 'a> { + fn cx(&self) -> DbInterner<'db> { + self.tcx + } + + fn fold_ty(&mut self, t: Ty<'db>) -> Ty<'db> { + match t.kind() { + TyKind::Bound(BoundVarIndexKind::Canonical, bound_ty) => { + self.var_values[bound_ty.var.as_usize()].expect_ty() + } + _ => { + if !t.has_type_flags(TypeFlags::HAS_CANONICAL_BOUND) { + t + } else if let Some(&t) = self.cache.get(&t) { + t + } else { + let res = t.super_fold_with(self); + assert!(self.cache.insert(t, res).is_none()); + res + } + } + } + } + + fn fold_region(&mut self, r: Region<'db>) -> Region<'db> { + match r.kind() { + RegionKind::ReBound(BoundVarIndexKind::Canonical, br) => { + self.var_values[br.var.as_usize()].expect_region() + } + _ => r, + } + } + + fn fold_const(&mut self, ct: Const<'db>) -> Const<'db> { + match ct.kind() { + ConstKind::Bound(BoundVarIndexKind::Canonical, bound_const) => { + self.var_values[bound_const.var.as_usize()].expect_const() + } + _ => ct.super_fold_with(self), + } + } + + fn fold_predicate(&mut self, p: Predicate<'db>) -> Predicate<'db> { + if p.has_type_flags(TypeFlags::HAS_CANONICAL_BOUND) { p.super_fold_with(self) } else { p } + } + + fn fold_clauses(&mut self, c: Clauses<'db>) -> Clauses<'db> { + if !c.has_type_flags(TypeFlags::HAS_CANONICAL_BOUND) { + return c; + } + + // FIXME: We might need cache here for perf like rustc + c.super_fold_with(self) } } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/canonical/mod.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/canonical/mod.rs index d0669f5c3bcc..b3bd0a437b8d 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/canonical/mod.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/canonical/mod.rs @@ -22,26 +22,13 @@ //! [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html use crate::next_solver::{ - AliasTy, Binder, Canonical, CanonicalVarValues, CanonicalVars, Const, DbInterner, GenericArg, - Goal, ParamEnv, PlaceholderConst, PlaceholderRegion, PlaceholderTy, Predicate, PredicateKind, - Region, Ty, TyKind, - infer::{ - DefineOpaqueTypes, InferCtxt, TypeTrace, - traits::{Obligation, PredicateObligations}, - }, + Canonical, CanonicalVarValues, Const, DbInterner, GenericArg, PlaceholderConst, + PlaceholderRegion, PlaceholderTy, Region, Ty, TyKind, infer::InferCtxt, }; use instantiate::CanonicalExt; use rustc_index::IndexVec; use rustc_type_ir::inherent::IntoKind; -use rustc_type_ir::{ - AliasRelationDirection, AliasTyKind, CanonicalVarKind, InferTy, TypeFoldable, UniverseIndex, - Upcast, Variance, - inherent::{SliceLike, Ty as _}, - relate::{ - Relate, TypeRelation, VarianceDiagInfo, - combine::{super_combine_consts, super_combine_tys}, - }, -}; +use rustc_type_ir::{CanonicalVarKind, InferTy, TypeFoldable, UniverseIndex, inherent::Ty as _}; pub mod canonicalizer; pub mod instantiate; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/context.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/context.rs index 5aa5ad14af55..397986e2edd3 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/context.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/context.rs @@ -1,19 +1,19 @@ //! Definition of `InferCtxtLike` from the librarified type layer. use rustc_type_ir::{ - ConstVid, FloatVarValue, FloatVid, GenericArgKind, InferConst, InferTy, IntTy, IntVarValue, - IntVid, RegionVid, TyVid, TypeFoldable, TypingMode, UniverseIndex, - inherent::{Const as _, IntoKind, Span as _, Ty as _}, + ConstVid, FloatVarValue, FloatVid, GenericArgKind, InferConst, InferTy, IntVarValue, IntVid, + RegionVid, TyVid, TypeFoldable, TypingMode, UniverseIndex, + inherent::{Const as _, IntoKind, Ty as _}, relate::combine::PredicateEmittingRelation, }; use crate::next_solver::{ - Binder, Const, ConstKind, DbInterner, ErrorGuaranteed, GenericArgs, OpaqueTypeKey, ParamEnv, - Region, SolverDefId, Span, Ty, TyKind, + Binder, Const, ConstKind, DbInterner, ErrorGuaranteed, GenericArgs, OpaqueTypeKey, Region, + SolverDefId, Span, Ty, TyKind, infer::opaque_types::{OpaqueHiddenType, table::OpaqueTypeStorageEntries}, }; -use super::{BoundRegionConversionTime, InferCtxt, relate::RelateResult, traits::ObligationCause}; +use super::{BoundRegionConversionTime, InferCtxt, relate::RelateResult}; impl<'db> rustc_type_ir::InferCtxtLike for InferCtxt<'db> { type Interner = DbInterner<'db>; @@ -250,16 +250,16 @@ impl<'db> rustc_type_ir::InferCtxtLike for InferCtxt<'db> { self.probe(|_| probe()) } - fn sub_regions(&self, sub: Region<'db>, sup: Region<'db>, span: Span) { + fn sub_regions(&self, sub: Region<'db>, sup: Region<'db>, _span: Span) { self.inner.borrow_mut().unwrap_region_constraints().make_subregion(sub, sup); } - fn equate_regions(&self, a: Region<'db>, b: Region<'db>, span: Span) { + fn equate_regions(&self, a: Region<'db>, b: Region<'db>, _span: Span) { self.inner.borrow_mut().unwrap_region_constraints().make_eqregion(a, b); } - fn register_ty_outlives(&self, ty: Ty<'db>, r: Region<'db>, span: Span) { - //self.register_region_obligation_with_cause(ty, r, &ObligationCause::dummy_with_span(Span::dummy())); + fn register_ty_outlives(&self, _ty: Ty<'db>, _r: Region<'db>, _span: Span) { + // self.register_type_outlives_constraint(ty, r, &ObligationCause::dummy()); } type OpaqueTypeStorageEntries = OpaqueTypeStorageEntries; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/mod.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/mod.rs index e1a46fa0694c..36c6c48c5a0b 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/mod.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/mod.rs @@ -6,32 +6,23 @@ use std::ops::Range; use std::sync::Arc; pub use BoundRegionConversionTime::*; -pub use at::DefineOpaqueTypes; -use ena::undo_log::UndoLogs; use ena::unify as ut; use hir_def::GenericParamId; use hir_def::lang_item::LangItem; -use intern::Symbol; use opaque_types::{OpaqueHiddenType, OpaqueTypeStorage}; -use region_constraints::{ - GenericKind, RegionConstraintCollector, RegionConstraintStorage, UndoLog, VarInfos, VerifyBound, -}; -pub use relate::StructurallyRelateAliases; -pub use relate::combine::PredicateEmittingRelation; -use rustc_hash::{FxHashMap, FxHashSet}; +use region_constraints::{RegionConstraintCollector, RegionConstraintStorage}; use rustc_next_trait_solver::solve::SolverDelegateEvalExt; use rustc_pattern_analysis::Captures; +use rustc_type_ir::TypeFoldable; use rustc_type_ir::error::{ExpectedFound, TypeError}; use rustc_type_ir::inherent::{ - Const as _, GenericArg as _, GenericArgs as _, IntoKind, ParamEnv as _, SliceLike, Term as _, - Ty as _, + Const as _, GenericArg as _, GenericArgs as _, IntoKind, SliceLike, Term as _, Ty as _, }; use rustc_type_ir::{ - BoundVar, ClosureKind, ConstVid, FloatTy, FloatVarValue, FloatVid, GenericArgKind, InferConst, - InferTy, IntTy, IntVarValue, IntVid, OutlivesPredicate, RegionVid, TyVid, UniverseIndex, + ClosureKind, ConstVid, FloatVarValue, FloatVid, GenericArgKind, InferConst, InferTy, + IntVarValue, IntVid, OutlivesPredicate, RegionVid, TyVid, UniverseIndex, }; use rustc_type_ir::{TermKind, TypeVisitableExt}; -use rustc_type_ir::{TypeFoldable, TypeFolder, TypeSuperFoldable}; use snapshot::undo_log::InferCtxtUndoLogs; use tracing::{debug, instrument}; use traits::{ObligationCause, PredicateObligations}; @@ -39,19 +30,17 @@ use type_variable::TypeVariableOrigin; use unify_key::{ConstVariableOrigin, ConstVariableValue, ConstVidKey}; use crate::next_solver::fold::BoundVarReplacerDelegate; -use crate::next_solver::infer::opaque_types::table::OpaqueTypeStorageEntries; use crate::next_solver::infer::select::EvaluationResult; use crate::next_solver::infer::traits::PredicateObligation; use crate::next_solver::obligation_ctxt::ObligationCtxt; use crate::next_solver::{BoundConst, BoundRegion, BoundTy, BoundVarKind, Goal, SolverContext}; -use super::generics::GenericParamDef; use super::{ - AliasTerm, Binder, BoundRegionKind, CanonicalQueryInput, CanonicalVarValues, Const, ConstKind, - DbInterner, ErrorGuaranteed, FxIndexMap, GenericArg, GenericArgs, OpaqueTypeKey, ParamEnv, - PlaceholderRegion, PolyCoercePredicate, PolyExistentialProjection, PolyExistentialTraitRef, - PolyFnSig, PolyRegionOutlivesPredicate, PolySubtypePredicate, Predicate, Region, SolverDefId, - SubtypePredicate, Term, TraitPredicate, TraitRef, Ty, TyKind, TypingMode, + AliasTerm, Binder, CanonicalQueryInput, CanonicalVarValues, Const, ConstKind, DbInterner, + ErrorGuaranteed, GenericArg, GenericArgs, OpaqueTypeKey, ParamEnv, PolyCoercePredicate, + PolyExistentialProjection, PolyExistentialTraitRef, PolyFnSig, PolyRegionOutlivesPredicate, + PolySubtypePredicate, Region, SolverDefId, SubtypePredicate, Term, TraitRef, Ty, TyKind, + TypingMode, }; pub mod at; @@ -82,8 +71,6 @@ pub struct InferOk<'db, T> { } pub type InferResult<'db, T> = Result, TypeError>>; -pub(crate) type FixupResult = Result; // "fixup result" - pub(crate) type UnificationTable<'a, 'db, T> = ut::UnificationTable< ut::InPlace, &'a mut InferCtxtUndoLogs<'db>>, >; @@ -440,6 +427,7 @@ impl<'db> InferCtxt<'db> { /// check::<&'_ T>(); /// } /// ``` + #[expect(dead_code, reason = "this is used in rustc")] fn predicate_must_hold_considering_regions( &self, obligation: &PredicateObligation<'db>, @@ -452,14 +440,13 @@ impl<'db> InferCtxt<'db> { /// not entirely accurate if inference variables are involved. /// /// This version ignores all outlives constraints. + #[expect(dead_code, reason = "this is used in rustc")] fn predicate_must_hold_modulo_regions(&self, obligation: &PredicateObligation<'db>) -> bool { self.evaluate_obligation(obligation).must_apply_modulo_regions() } /// Evaluate a given predicate, capturing overflow and propagating it back. fn evaluate_obligation(&self, obligation: &PredicateObligation<'db>) -> EvaluationResult { - let param_env = obligation.param_env; - self.probe(|snapshot| { let mut ocx = ObligationCtxt::new(self); ocx.register_obligation(obligation.clone()); @@ -583,16 +570,16 @@ impl<'db> InferCtxt<'db> { self.enter_forall(predicate, |SubtypePredicate { a_is_expected, a, b }| { if a_is_expected { - Ok(self.at(cause, param_env).sub(DefineOpaqueTypes::Yes, a, b)) + Ok(self.at(cause, param_env).sub(a, b)) } else { - Ok(self.at(cause, param_env).sup(DefineOpaqueTypes::Yes, b, a)) + Ok(self.at(cause, param_env).sup(b, a)) } }) } pub fn region_outlives_predicate( &self, - cause: &traits::ObligationCause, + _cause: &traits::ObligationCause, predicate: PolyRegionOutlivesPredicate<'db>, ) { self.enter_forall(predicate, |OutlivesPredicate(r_a, r_b)| { @@ -632,7 +619,7 @@ impl<'db> InferCtxt<'db> { } pub fn next_const_var(&self) -> Const<'db> { - self.next_const_var_with_origin(ConstVariableOrigin { param_def_id: None }) + self.next_const_var_with_origin(ConstVariableOrigin {}) } pub fn next_const_vid(&self) -> ConstVid { @@ -640,7 +627,7 @@ impl<'db> InferCtxt<'db> { .borrow_mut() .const_unification_table() .new_key(ConstVariableValue::Unknown { - origin: ConstVariableOrigin { param_def_id: None }, + origin: ConstVariableOrigin {}, universe: self.universe(), }) .vid @@ -657,7 +644,7 @@ impl<'db> InferCtxt<'db> { } pub fn next_const_var_in_universe(&self, universe: UniverseIndex) -> Const<'db> { - let origin = ConstVariableOrigin { param_def_id: None }; + let origin = ConstVariableOrigin {}; let vid = self .inner .borrow_mut() @@ -738,7 +725,7 @@ impl<'db> InferCtxt<'db> { self.next_region_var_in_universe(universe) } - fn var_for_def(&self, id: GenericParamId, name: &Symbol) -> GenericArg<'db> { + fn var_for_def(&self, id: GenericParamId) -> GenericArg<'db> { match id { GenericParamId::LifetimeParamId(_) => { // Create a region inference variable for the given @@ -763,7 +750,7 @@ impl<'db> InferCtxt<'db> { Ty::new_var(self.interner, ty_var_id).into() } GenericParamId::ConstParamId(_) => { - let origin = ConstVariableOrigin { param_def_id: None }; + let origin = ConstVariableOrigin {}; let const_var_id = self .inner .borrow_mut() @@ -778,9 +765,7 @@ impl<'db> InferCtxt<'db> { /// Given a set of generics defined on a type or impl, returns the generic parameters mapping /// each type/region parameter to a fresh inference variable. pub fn fresh_args_for_item(&self, def_id: SolverDefId) -> GenericArgs<'db> { - GenericArgs::for_item(self.interner, def_id, |name, index, kind, _| { - self.var_for_def(kind, name) - }) + GenericArgs::for_item(self.interner, def_id, |_index, kind, _| self.var_for_def(kind)) } /// Like `fresh_args_for_item()`, but first uses the args from `first`. @@ -789,8 +774,8 @@ impl<'db> InferCtxt<'db> { def_id: SolverDefId, first: impl IntoIterator>, ) -> GenericArgs<'db> { - GenericArgs::fill_rest(self.interner, def_id, first, |name, index, kind, _| { - self.var_for_def(kind, name) + GenericArgs::fill_rest(self.interner, def_id, first, |_index, kind, _| { + self.var_for_def(kind) }) } @@ -828,8 +813,8 @@ impl<'db> InferCtxt<'db> { defining_opaque_types_and_generators.contains(&id.into()) } TypingMode::Coherence | TypingMode::PostAnalysis => false, - TypingMode::Borrowck { defining_opaque_types } => unimplemented!(), - TypingMode::PostBorrowckAnalysis { defined_opaque_types } => unimplemented!(), + TypingMode::Borrowck { defining_opaque_types: _ } => unimplemented!(), + TypingMode::PostBorrowckAnalysis { defined_opaque_types: _ } => unimplemented!(), } } @@ -998,7 +983,7 @@ impl<'db> InferCtxt<'db> { // use [`InferCtxt::enter_forall`] instead. pub fn instantiate_binder_with_fresh_vars( &self, - lbrct: BoundRegionConversionTime, + _lbrct: BoundRegionConversionTime, value: Binder<'db, T>, ) -> T where @@ -1014,7 +999,7 @@ impl<'db> InferCtxt<'db> { for bound_var_kind in bound_vars { let arg: GenericArg<'db> = match bound_var_kind { BoundVarKind::Ty(_) => self.next_ty_var().into(), - BoundVarKind::Region(br) => self.next_region_var().into(), + BoundVarKind::Region(_) => self.next_region_var().into(), BoundVarKind::Const => self.next_const_var().into(), }; args.push(arg); @@ -1070,7 +1055,7 @@ impl<'db> InferCtxt<'db> { #[inline] pub fn is_ty_infer_var_definitely_unchanged<'a>( &'a self, - ) -> (impl Fn(TyOrConstInferVar) -> bool + Captures<'db> + 'a) { + ) -> impl Fn(TyOrConstInferVar) -> bool + Captures<'db> + 'a { // This hoists the borrow/release out of the loop body. let inner = self.inner.try_borrow(); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/opaque_types/mod.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/opaque_types/mod.rs index 0f68ec8cdb5b..06d998488e15 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/opaque_types/mod.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/opaque_types/mod.rs @@ -1,40 +1,10 @@ //! Things related to the infer context of the next-trait-solver. -use std::sync::Arc; - -use tracing::{debug, instrument}; - -use crate::next_solver::{ - Clause, ClauseKind, FxIndexMap, GenericArgs, OpaqueTypeKey, ProjectionPredicate, SolverDefId, - TypingMode, util::BottomUpFolder, -}; - pub(crate) mod table; pub(crate) use table::{OpaqueTypeStorage, OpaqueTypeTable}; -use crate::next_solver::{ - AliasTy, Binder, BoundRegion, BoundTy, Canonical, CanonicalVarValues, Const, DbInterner, Goal, - ParamEnv, Predicate, PredicateKind, Region, Ty, TyKind, - fold::FnMutDelegate, - infer::{ - DefineOpaqueTypes, InferCtxt, TypeTrace, - traits::{Obligation, PredicateObligations}, - }, -}; -use rustc_type_ir::{ - AliasRelationDirection, AliasTyKind, BoundConstness, BoundVar, Flags, GenericArgKind, InferTy, - Interner, RegionKind, TypeFlags, TypeFoldable, TypeSuperVisitable, TypeVisitable, - TypeVisitableExt, TypeVisitor, Upcast, Variance, - error::{ExpectedFound, TypeError}, - inherent::{DefId, GenericArgs as _, IntoKind, SliceLike}, - relate::{ - Relate, TypeRelation, VarianceDiagInfo, - combine::{super_combine_consts, super_combine_tys}, - }, -}; - -use super::{InferOk, traits::ObligationCause}; +use crate::next_solver::{OpaqueTypeKey, Ty, infer::InferCtxt}; #[derive(Copy, Clone, Debug)] pub struct OpaqueHiddenType<'db> { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/opaque_types/table.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/opaque_types/table.rs index 8ab409d78281..0f8b23870fd0 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/opaque_types/table.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/opaque_types/table.rs @@ -54,7 +54,7 @@ impl<'db> OpaqueTypeStorage<'db> { assert!(entry.is_some()); } - pub fn is_empty(&self) -> bool { + pub(crate) fn is_empty(&self) -> bool { let OpaqueTypeStorage { opaque_types, duplicate_entries } = self; opaque_types.is_empty() && duplicate_entries.is_empty() } @@ -66,14 +66,14 @@ impl<'db> OpaqueTypeStorage<'db> { std::mem::take(opaque_types).into_iter().chain(std::mem::take(duplicate_entries)) } - pub fn num_entries(&self) -> OpaqueTypeStorageEntries { + pub(crate) fn num_entries(&self) -> OpaqueTypeStorageEntries { OpaqueTypeStorageEntries { opaque_types: self.opaque_types.len(), duplicate_entries: self.duplicate_entries.len(), } } - pub fn opaque_types_added_since( + pub(crate) fn opaque_types_added_since( &self, prev_entries: OpaqueTypeStorageEntries, ) -> impl Iterator, OpaqueHiddenType<'db>)> { @@ -89,7 +89,7 @@ impl<'db> OpaqueTypeStorage<'db> { /// /// Outside of canonicalization one should generally use `iter_opaque_types` /// to also consider duplicate entries. - pub fn iter_lookup_table( + pub(crate) fn iter_lookup_table( &self, ) -> impl Iterator, OpaqueHiddenType<'db>)> { self.opaque_types.iter().map(|(k, v)| (*k, *v)) @@ -100,13 +100,13 @@ impl<'db> OpaqueTypeStorage<'db> { /// These have to considered when checking all opaque type uses but are e.g. /// irrelevant for canonical inputs as nested queries never meaningfully /// accesses them. - pub fn iter_duplicate_entries( + pub(crate) fn iter_duplicate_entries( &self, ) -> impl Iterator, OpaqueHiddenType<'db>)> { self.duplicate_entries.iter().copied() } - pub fn iter_opaque_types( + pub(crate) fn iter_opaque_types( &self, ) -> impl Iterator, OpaqueHiddenType<'db>)> { let OpaqueTypeStorage { opaque_types, duplicate_entries } = self; @@ -144,7 +144,7 @@ impl<'db> Deref for OpaqueTypeTable<'_, 'db> { impl<'a, 'db> OpaqueTypeTable<'a, 'db> { #[instrument(skip(self), level = "debug")] - pub fn register( + pub(crate) fn register( &mut self, key: OpaqueTypeKey<'db>, hidden_type: OpaqueHiddenType<'db>, @@ -159,7 +159,11 @@ impl<'a, 'db> OpaqueTypeTable<'a, 'db> { None } - pub fn add_duplicate(&mut self, key: OpaqueTypeKey<'db>, hidden_type: OpaqueHiddenType<'db>) { + pub(crate) fn add_duplicate( + &mut self, + key: OpaqueTypeKey<'db>, + hidden_type: OpaqueHiddenType<'db>, + ) { self.storage.duplicate_entries.push((key, hidden_type)); self.undo_log.push(UndoLog::DuplicateOpaqueType); } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/region_constraints/mod.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/region_constraints/mod.rs index 7f15a467b3e8..ae5930d55c72 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/region_constraints/mod.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/region_constraints/mod.rs @@ -1,7 +1,6 @@ //! See `README.md`. use std::ops::Range; -use std::sync::Arc; use std::{cmp, fmt, mem}; use ena::undo_log::{Rollback, UndoLogs}; @@ -18,9 +17,7 @@ use super::MemberConstraint; use super::unify_key::RegionVidKey; use crate::next_solver::infer::snapshot::undo_log::{InferCtxtUndoLogs, Snapshot}; use crate::next_solver::infer::unify_key::RegionVariableValue; -use crate::next_solver::{ - AliasTy, Binder, DbInterner, OpaqueTypeKey, ParamTy, PlaceholderTy, Region, Ty, -}; +use crate::next_solver::{AliasTy, Binder, DbInterner, ParamTy, PlaceholderTy, Region, Ty}; #[derive(Debug, Clone, Default)] pub struct RegionConstraintStorage<'db> { @@ -254,6 +251,7 @@ pub(crate) enum UndoLog<'db> { AddConstraint(usize), /// We added the given `verify`. + #[expect(dead_code, reason = "this is used in rustc")] AddVerify(usize), /// We added a GLB/LUB "combination variable". diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/relate/generalize.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/relate/generalize.rs index 7e2735db3b77..d06984cac11c 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/relate/generalize.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/relate/generalize.rs @@ -7,8 +7,8 @@ use rustc_type_ir::error::TypeError; use rustc_type_ir::inherent::{Const as _, IntoKind, Ty as _}; use rustc_type_ir::relate::VarianceDiagInfo; use rustc_type_ir::{ - AliasRelationDirection, AliasTyKind, ConstVid, InferConst, InferCtxtLike, InferTy, RegionKind, - TermKind, TyVid, UniverseIndex, Variance, + AliasRelationDirection, ConstVid, InferConst, InferCtxtLike, InferTy, RegionKind, TermKind, + TyVid, UniverseIndex, Variance, }; use rustc_type_ir::{Interner, TypeVisitable, TypeVisitableExt}; use tracing::{debug, instrument, warn}; @@ -21,9 +21,8 @@ use crate::next_solver::infer::unify_key::ConstVariableValue; use crate::next_solver::infer::{InferCtxt, relate}; use crate::next_solver::util::MaxUniverse; use crate::next_solver::{ - AliasTy, Binder, ClauseKind, Const, ConstKind, DbInterner, GenericArgs, PredicateKind, - ProjectionPredicate, Region, SolverDefId, Term, TermVid, Ty, TyKind, TypingMode, - UnevaluatedConst, + AliasTy, Binder, ClauseKind, Const, ConstKind, DbInterner, GenericArgs, PredicateKind, Region, + SolverDefId, Term, TermVid, Ty, TyKind, TypingMode, UnevaluatedConst, }; impl<'db> InferCtxt<'db> { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/relate/higher_ranked.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/relate/higher_ranked.rs index 62028e0e7039..c523751e03e3 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/relate/higher_ranked.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/relate/higher_ranked.rs @@ -2,13 +2,10 @@ //! the end of the file for details. use rustc_type_ir::TypeFoldable; -use rustc_type_ir::{BoundVar, UniverseIndex}; use tracing::{debug, instrument}; -use super::RelateResult; use crate::next_solver::fold::FnMutDelegate; use crate::next_solver::infer::InferCtxt; -use crate::next_solver::infer::snapshot::CombinedSnapshot; use crate::next_solver::{ Binder, BoundConst, BoundRegion, BoundTy, Const, DbInterner, PlaceholderConst, PlaceholderRegion, PlaceholderTy, Region, Ty, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/relate/lattice.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/relate/lattice.rs index c7f771ffe37f..374895c337c7 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/relate/lattice.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/relate/lattice.rs @@ -30,7 +30,7 @@ use crate::next_solver::{ AliasTy, Binder, Const, DbInterner, Goal, ParamEnv, Predicate, PredicateKind, Region, Span, Ty, TyKind, infer::{ - DefineOpaqueTypes, InferCtxt, TypeTrace, + InferCtxt, TypeTrace, relate::RelateResult, traits::{Obligation, PredicateObligations}, }, @@ -92,10 +92,7 @@ impl<'db> TypeRelation> for LatticeOp<'_, 'db> { match variance { Variance::Invariant => { self.obligations.extend( - self.infcx - .at(&self.trace.cause, self.param_env) - .eq_trace(DefineOpaqueTypes::Yes, self.trace.clone(), a, b)? - .into_obligations(), + self.infcx.at(&self.trace.cause, self.param_env).eq(a, b)?.into_obligations(), ); Ok(a) } @@ -213,12 +210,12 @@ impl<'infcx, 'db> LatticeOp<'infcx, 'db> { let at = self.infcx.at(&self.trace.cause, self.param_env); match self.kind { LatticeOpKind::Glb => { - self.obligations.extend(at.sub(DefineOpaqueTypes::Yes, v, a)?.into_obligations()); - self.obligations.extend(at.sub(DefineOpaqueTypes::Yes, v, b)?.into_obligations()); + self.obligations.extend(at.sub(v, a)?.into_obligations()); + self.obligations.extend(at.sub(v, b)?.into_obligations()); } LatticeOpKind::Lub => { - self.obligations.extend(at.sub(DefineOpaqueTypes::Yes, a, v)?.into_obligations()); - self.obligations.extend(at.sub(DefineOpaqueTypes::Yes, b, v)?.into_obligations()); + self.obligations.extend(at.sub(a, v)?.into_obligations()); + self.obligations.extend(at.sub(b, v)?.into_obligations()); } } Ok(()) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/resolve.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/resolve.rs index 4bd3fbd4985d..b6e5225e5a7e 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/resolve.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/resolve.rs @@ -1,15 +1,14 @@ //! Things for resolving vars in the infer context of the next-trait-solver. use rustc_type_ir::{ - ConstKind, FallibleTypeFolder, InferConst, InferTy, RegionKind, TyKind, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, data_structures::DelayedMap, - inherent::{Const as _, IntoKind, Ty as _}, + inherent::{Const as _, Ty as _}, }; use crate::next_solver::{Const, DbInterner, ErrorGuaranteed, Region, Ty}; -use super::{FixupError, FixupResult, InferCtxt}; +use super::InferCtxt; /////////////////////////////////////////////////////////////////////////// // OPPORTUNISTIC VAR RESOLVER diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/select.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/select.rs index 79b0a2933236..52ad410df6be 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/select.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/select.rs @@ -1,3 +1,5 @@ +#![expect(dead_code, reason = "this is used by rustc")] + use std::ops::ControlFlow; use hir_def::{ImplId, TraitId}; @@ -61,7 +63,7 @@ pub enum NotConstEvaluatable { /// so they are noops when unioned with a definite error, and within /// the categories it's easy to see that the unions are correct. #[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq)] -pub enum EvaluationResult { +pub(crate) enum EvaluationResult { /// Evaluation successful. EvaluatedToOk, /// Evaluation successful, but there were unevaluated region obligations. @@ -91,17 +93,17 @@ pub enum EvaluationResult { impl EvaluationResult { /// Returns `true` if this evaluation result is known to apply, even /// considering outlives constraints. - pub fn must_apply_considering_regions(self) -> bool { + pub(crate) fn must_apply_considering_regions(self) -> bool { self == EvaluatedToOk } /// Returns `true` if this evaluation result is known to apply, ignoring /// outlives constraints. - pub fn must_apply_modulo_regions(self) -> bool { + pub(crate) fn must_apply_modulo_regions(self) -> bool { self <= EvaluatedToOkModuloRegions } - pub fn may_apply(self) -> bool { + pub(crate) fn may_apply(self) -> bool { match self { EvaluatedToOkModuloOpaqueTypes | EvaluatedToOk @@ -113,7 +115,7 @@ impl EvaluationResult { } } - pub fn is_stack_dependent(self) -> bool { + pub(crate) fn is_stack_dependent(self) -> bool { match self { EvaluatedToAmbigStackDependent => true, @@ -135,9 +137,9 @@ pub enum OverflowError { #[derive(Clone, Debug, PartialEq, Eq)] pub struct SignatureMismatchData<'db> { - pub found_trait_ref: TraitRef<'db>, - pub expected_trait_ref: TraitRef<'db>, - pub terr: TypeError<'db>, + pub(crate) found_trait_ref: TraitRef<'db>, + pub(crate) expected_trait_ref: TraitRef<'db>, + pub(crate) terr: TypeError<'db>, } /// When performing resolution, it is typically the case that there @@ -147,7 +149,7 @@ pub struct SignatureMismatchData<'db> { /// - `Ok(None)`: could not definitely determine anything, usually due /// to inconclusive type inference. /// - `Err(e)`: error `e` occurred -pub type SelectionResult<'db, T> = Result, SelectionError<'db>>; +pub(crate) type SelectionResult<'db, T> = Result, SelectionError<'db>>; /// Given the successful resolution of an obligation, the `ImplSource` /// indicates where the impl comes from. @@ -179,7 +181,7 @@ pub type SelectionResult<'db, T> = Result, SelectionError<'db>>; /// /// See explanation on `ImplSourceUserDefinedData`. #[derive(Debug, Clone, PartialEq, Eq, Hash, TypeVisitable, TypeFoldable)] -pub enum ImplSource<'db, N> { +pub(crate) enum ImplSource<'db, N> { /// ImplSource identifying a particular impl. UserDefined(ImplSourceUserDefinedData<'db, N>), @@ -194,28 +196,28 @@ pub enum ImplSource<'db, N> { } impl<'db, N> ImplSource<'db, N> { - pub fn nested_obligations(self) -> Vec { + pub(crate) fn nested_obligations(self) -> Vec { match self { ImplSource::UserDefined(i) => i.nested, ImplSource::Param(n) | ImplSource::Builtin(_, n) => n, } } - pub fn borrow_nested_obligations(&self) -> &[N] { + pub(crate) fn borrow_nested_obligations(&self) -> &[N] { match self { ImplSource::UserDefined(i) => &i.nested, ImplSource::Param(n) | ImplSource::Builtin(_, n) => n, } } - pub fn borrow_nested_obligations_mut(&mut self) -> &mut [N] { + pub(crate) fn borrow_nested_obligations_mut(&mut self) -> &mut [N] { match self { ImplSource::UserDefined(i) => &mut i.nested, ImplSource::Param(n) | ImplSource::Builtin(_, n) => n, } } - pub fn map(self, f: F) -> ImplSource<'db, M> + pub(crate) fn map(self, f: F) -> ImplSource<'db, M> where F: FnMut(N) -> M, { @@ -244,15 +246,15 @@ impl<'db, N> ImplSource<'db, N> { /// is `()`, because codegen only requires a shallow resolution of an /// impl, and nested obligations are satisfied later. #[derive(Debug, Clone, PartialEq, Eq, Hash, TypeVisitable, TypeFoldable)] -pub struct ImplSourceUserDefinedData<'db, N> { +pub(crate) struct ImplSourceUserDefinedData<'db, N> { #[type_visitable(ignore)] #[type_foldable(identity)] - pub impl_def_id: ImplId, - pub args: GenericArgs<'db>, - pub nested: Vec, + pub(crate) impl_def_id: ImplId, + pub(crate) args: GenericArgs<'db>, + pub(crate) nested: Vec, } -pub type Selection<'db> = ImplSource<'db, PredicateObligation<'db>>; +pub(crate) type Selection<'db> = ImplSource<'db, PredicateObligation<'db>>; impl<'db> InferCtxt<'db> { pub(crate) fn select( @@ -351,7 +353,9 @@ fn candidate_should_be_dropped_in_favor_of<'db>( // Prefer dyn candidates over non-dyn candidates. This is necessary to // handle the unsoundness between `impl Any for T` and `dyn Any: Any`. ( - CandidateSource::Impl(_) | CandidateSource::ParamEnv(_) | CandidateSource::AliasBound, + CandidateSource::Impl(_) + | CandidateSource::ParamEnv(_) + | CandidateSource::AliasBound(_), CandidateSource::BuiltinImpl(BuiltinImplSource::Object { .. }), ) => true, @@ -397,7 +401,9 @@ fn to_selection<'db>(cand: InspectCandidate<'_, 'db>) -> Option> }) } CandidateSource::BuiltinImpl(builtin) => ImplSource::Builtin(builtin, nested), - CandidateSource::ParamEnv(_) | CandidateSource::AliasBound => ImplSource::Param(nested), + CandidateSource::ParamEnv(_) | CandidateSource::AliasBound(_) => { + ImplSource::Param(nested) + } CandidateSource::CoherenceUnknowable => { panic!("didn't expect to select an unknowable candidate") } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/snapshot/fudge.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/snapshot/fudge.rs index 74353574e329..5902f8043b5e 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/snapshot/fudge.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/snapshot/fudge.rs @@ -41,9 +41,7 @@ fn const_vars_since_snapshot<'db>( range.clone(), iter_idx_range(range) .map(|index| match table.probe_value(index) { - ConstVariableValue::Known { value: _ } => { - ConstVariableOrigin { param_def_id: None } - } + ConstVariableValue::Known { value: _ } => ConstVariableOrigin {}, ConstVariableValue::Unknown { origin, universe: _ } => origin, }) .collect(), @@ -228,7 +226,6 @@ impl<'a, 'db> TypeFolder> for InferenceFudger<'a, 'db> { fn fold_region(&mut self, r: Region<'db>) -> Region<'db> { if let RegionKind::ReVar(vid) = r.kind() { if self.snapshot_vars.region_vars.contains(&vid) { - let idx = vid.index() - self.snapshot_vars.region_vars.start.index(); self.infcx.next_region_var() } else { r diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/snapshot/undo_log.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/snapshot/undo_log.rs index 05a1013b3fbd..c8ec8da7f31c 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/snapshot/undo_log.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/snapshot/undo_log.rs @@ -1,7 +1,5 @@ //! Snapshotting in the infer ctxt of the next-trait-solver. -use std::marker::PhantomData; - use ena::snapshot_vec as sv; use ena::undo_log::{Rollback, UndoLogs}; use ena::unify as ut; @@ -14,7 +12,6 @@ use crate::next_solver::infer::opaque_types::OpaqueHiddenType; use crate::next_solver::infer::unify_key::ConstVidKey; use crate::next_solver::infer::unify_key::RegionVidKey; use crate::next_solver::infer::{InferCtxtInner, region_constraints, type_variable}; -use crate::traits; pub struct Snapshot { pub(crate) undo_len: usize, @@ -31,6 +28,7 @@ pub(crate) enum UndoLog<'db> { FloatUnificationTable(sv::UndoLog>), RegionConstraintCollector(region_constraints::UndoLog<'db>), RegionUnificationTable(sv::UndoLog>>), + #[expect(dead_code, reason = "this is used in rustc")] PushRegionObligation, } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/traits.rs index bc905c2e0b95..4f000c24cc73 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/traits.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/traits.rs @@ -9,17 +9,13 @@ use std::{ use hir_def::TraitId; use macros::{TypeFoldable, TypeVisitable}; +use rustc_type_ir::Upcast; use rustc_type_ir::elaborate::Elaboratable; -use rustc_type_ir::{ - PredicatePolarity, Upcast, - solve::{Certainty, NoSolution}, -}; -use rustc_type_ir::{TypeFoldable, TypeVisitable}; use tracing::debug; use crate::next_solver::{ - Binder, Clause, DbInterner, Goal, ParamEnv, PolyTraitPredicate, Predicate, SolverDefId, Span, - TraitPredicate, TraitRef, Ty, + Clause, DbInterner, Goal, ParamEnv, PolyTraitPredicate, Predicate, Span, TraitPredicate, + TraitRef, Ty, }; use super::InferCtxt; @@ -106,9 +102,9 @@ impl<'db> Elaboratable> for PredicateObligation<'db> { fn child_with_derived_cause( &self, clause: Clause<'db>, - span: Span, - parent_trait_pred: PolyTraitPredicate<'db>, - index: usize, + _span: Span, + _parent_trait_pred: PolyTraitPredicate<'db>, + _index: usize, ) -> Self { let cause = ObligationCause::new(); Obligation { @@ -153,16 +149,16 @@ impl<'db, P> From> for Goal<'db, P> { } } -pub type PredicateObligation<'db> = Obligation<'db, Predicate<'db>>; -pub type TraitObligation<'db> = Obligation<'db, TraitPredicate<'db>>; +pub(crate) type PredicateObligation<'db> = Obligation<'db, Predicate<'db>>; +pub(crate) type TraitObligation<'db> = Obligation<'db, TraitPredicate<'db>>; -pub type PredicateObligations<'db> = Vec>; +pub(crate) type PredicateObligations<'db> = Vec>; impl<'db> PredicateObligation<'db> { /// Flips the polarity of the inner predicate. /// /// Given `T: Trait` predicate it returns `T: !Trait` and given `T: !Trait` returns `T: Trait`. - pub fn flip_polarity(&self, tcx: DbInterner<'db>) -> Option> { + pub fn flip_polarity(&self, _interner: DbInterner<'db>) -> Option> { Some(PredicateObligation { cause: self.cause.clone(), param_env: self.param_env, @@ -215,7 +211,7 @@ impl<'db, O> Obligation<'db, O> { /// `bound` or is not known to meet bound (note that this is /// conservative towards *no impl*, which is the opposite of the /// `evaluate` methods). -pub fn type_known_to_meet_bound_modulo_regions<'tcx>( +pub(crate) fn type_known_to_meet_bound_modulo_regions<'tcx>( infcx: &InferCtxt<'tcx>, param_env: ParamEnv<'tcx>, ty: Ty<'tcx>, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/unify_key.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/unify_key.rs index dc913b262a7c..a09f65f082d9 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/unify_key.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/unify_key.rs @@ -6,18 +6,18 @@ use std::marker::PhantomData; use ena::unify::{NoError, UnifyKey, UnifyValue}; use rustc_type_ir::{ConstVid, RegionKind, RegionVid, UniverseIndex, inherent::IntoKind}; -use crate::next_solver::{Const, Region, SolverDefId, Ty}; +use crate::next_solver::{Const, Region}; #[derive(Clone, Debug)] -pub enum RegionVariableValue<'db> { +pub(crate) enum RegionVariableValue<'db> { Known { value: Region<'db> }, Unknown { universe: UniverseIndex }, } #[derive(PartialEq, Copy, Clone, Debug)] -pub struct RegionVidKey<'db> { - pub vid: RegionVid, - pub phantom: PhantomData>, +pub(crate) struct RegionVidKey<'db> { + pub(crate) vid: RegionVid, + pub(crate) phantom: PhantomData>, } impl<'db> From for RegionVidKey<'db> { @@ -41,7 +41,7 @@ impl<'db> UnifyKey for RegionVidKey<'db> { } } -pub struct RegionUnificationError; +pub(crate) struct RegionUnificationError; impl<'db> UnifyValue for RegionVariableValue<'db> { type Error = RegionUnificationError; @@ -90,15 +90,10 @@ impl<'db> UnifyValue for RegionVariableValue<'db> { // Generic consts. #[derive(Copy, Clone, Debug)] -pub struct ConstVariableOrigin { - /// `DefId` of the const parameter this was instantiated for, if any. - /// - /// This should only be used for diagnostics. - pub param_def_id: Option, -} +pub struct ConstVariableOrigin {} #[derive(Clone, Debug)] -pub enum ConstVariableValue<'db> { +pub(crate) enum ConstVariableValue<'db> { Known { value: Const<'db> }, Unknown { origin: ConstVariableOrigin, universe: UniverseIndex }, } @@ -106,7 +101,7 @@ pub enum ConstVariableValue<'db> { impl<'db> ConstVariableValue<'db> { /// If this value is known, returns the const it is known to be. /// Otherwise, `None`. - pub fn known(&self) -> Option> { + pub(crate) fn known(&self) -> Option> { match self { ConstVariableValue::Unknown { .. } => None, ConstVariableValue::Known { value } => Some(*value), @@ -115,9 +110,9 @@ impl<'db> ConstVariableValue<'db> { } #[derive(PartialEq, Copy, Clone, Debug)] -pub struct ConstVidKey<'db> { - pub vid: ConstVid, - pub phantom: PhantomData>, +pub(crate) struct ConstVidKey<'db> { + pub(crate) vid: ConstVid, + pub(crate) phantom: PhantomData>, } impl<'db> From for ConstVidKey<'db> { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/inspect.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/inspect.rs index 0db474672175..d66aa9f277c7 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/inspect.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/inspect.rs @@ -1,4 +1,4 @@ -pub use rustc_next_trait_solver::solve::inspect::*; +pub(crate) use rustc_next_trait_solver::solve::inspect::*; use rustc_ast_ir::try_visit; use rustc_next_trait_solver::{ @@ -23,11 +23,11 @@ use crate::next_solver::{ obligation_ctxt::ObligationCtxt, }; -pub struct InspectConfig { - pub max_depth: usize, +pub(crate) struct InspectConfig { + pub(crate) max_depth: usize, } -pub struct InspectGoal<'a, 'db> { +pub(crate) struct InspectGoal<'a, 'db> { infcx: &'a SolverContext<'db>, depth: usize, orig_values: Vec>, @@ -103,7 +103,7 @@ impl<'db> NormalizesToTermHack<'db> { } } -pub struct InspectCandidate<'a, 'db> { +pub(crate) struct InspectCandidate<'a, 'db> { goal: &'a InspectGoal<'a, 'db>, kind: inspect::ProbeKind>, steps: Vec<&'a inspect::ProbeStep>>, @@ -113,15 +113,15 @@ pub struct InspectCandidate<'a, 'db> { } impl<'a, 'db> InspectCandidate<'a, 'db> { - pub fn kind(&self) -> inspect::ProbeKind> { + pub(crate) fn kind(&self) -> inspect::ProbeKind> { self.kind } - pub fn result(&self) -> Result { + pub(crate) fn result(&self) -> Result { self.result.map(|c| c.value.certainty) } - pub fn goal(&self) -> &'a InspectGoal<'a, 'db> { + pub(crate) fn goal(&self) -> &'a InspectGoal<'a, 'db> { self.goal } @@ -133,14 +133,17 @@ impl<'a, 'db> InspectCandidate<'a, 'db> { /// /// This is *not* the certainty of the candidate's full nested evaluation, which /// can be accessed with [`Self::result`] instead. - pub fn shallow_certainty(&self) -> Certainty { + pub(crate) fn shallow_certainty(&self) -> Certainty { self.shallow_certainty } /// Visit all nested goals of this candidate without rolling /// back their inference constraints. This function modifies /// the state of the `infcx`. - pub fn visit_nested_no_probe>(&self, visitor: &mut V) -> V::Result { + pub(crate) fn visit_nested_no_probe>( + &self, + visitor: &mut V, + ) -> V::Result { for goal in self.instantiate_nested_goals() { try_visit!(goal.visit_with(visitor)); } @@ -152,7 +155,7 @@ impl<'a, 'db> InspectCandidate<'a, 'db> { /// inference constraints. This function modifies the state of the `infcx`. /// /// See [`Self::instantiate_impl_args`] if you need the impl args too. - pub fn instantiate_nested_goals(&self) -> Vec> { + pub(crate) fn instantiate_nested_goals(&self) -> Vec> { let infcx = self.goal.infcx; let param_env = self.goal.goal.param_env; let mut orig_values = self.goal.orig_values.to_vec(); @@ -200,7 +203,7 @@ impl<'a, 'db> InspectCandidate<'a, 'db> { /// Instantiate the args of an impl if this candidate came from a /// `CandidateSource::Impl`. This function modifies the state of the /// `infcx`. - pub fn instantiate_impl_args(&self) -> GenericArgs<'db> { + pub(crate) fn instantiate_impl_args(&self) -> GenericArgs<'db> { let infcx = self.goal.infcx; let param_env = self.goal.goal.param_env; let mut orig_values = self.goal.orig_values.to_vec(); @@ -241,7 +244,7 @@ impl<'a, 'db> InspectCandidate<'a, 'db> { panic!("expected impl args probe step for `instantiate_impl_args`"); } - pub fn instantiate_proof_tree_for_nested_goal( + pub(crate) fn instantiate_proof_tree_for_nested_goal( &self, source: GoalSource, goal: Goal<'db, Predicate<'db>>, @@ -307,29 +310,33 @@ impl<'a, 'db> InspectCandidate<'a, 'db> { /// Visit all nested goals of this candidate, rolling back /// all inference constraints. - pub fn visit_nested_in_probe>(&self, visitor: &mut V) -> V::Result { + #[expect(dead_code, reason = "used in rustc")] + pub(crate) fn visit_nested_in_probe>( + &self, + visitor: &mut V, + ) -> V::Result { self.goal.infcx.probe(|_| self.visit_nested_no_probe(visitor)) } } impl<'a, 'db> InspectGoal<'a, 'db> { - pub fn infcx(&self) -> &'a InferCtxt<'db> { + pub(crate) fn infcx(&self) -> &'a InferCtxt<'db> { self.infcx } - pub fn goal(&self) -> Goal<'db, Predicate<'db>> { + pub(crate) fn goal(&self) -> Goal<'db, Predicate<'db>> { self.goal } - pub fn result(&self) -> Result { + pub(crate) fn result(&self) -> Result { self.result } - pub fn source(&self) -> GoalSource { + pub(crate) fn source(&self) -> GoalSource { self.source } - pub fn depth(&self) -> usize { + pub(crate) fn depth(&self) -> usize { self.depth } @@ -405,7 +412,7 @@ impl<'a, 'db> InspectGoal<'a, 'db> { } } - pub fn candidates(&'a self) -> Vec> { + pub(crate) fn candidates(&'a self) -> Vec> { let mut candidates = vec![]; let mut nested_goals = vec![]; self.candidates_recur(&mut candidates, &mut nested_goals, &self.final_revision); @@ -415,7 +422,7 @@ impl<'a, 'db> InspectGoal<'a, 'db> { /// Returns the single candidate applicable for the current goal, if it exists. /// /// Returns `None` if there are either no or multiple applicable candidates. - pub fn unique_applicable_candidate(&'a self) -> Option> { + pub(crate) fn unique_applicable_candidate(&'a self) -> Option> { // FIXME(-Znext-solver): This does not handle impl candidates // hidden by env candidates. let mut candidates = self.candidates(); @@ -467,7 +474,7 @@ impl<'a, 'db> InspectGoal<'a, 'db> { } /// The public API to interact with proof trees. -pub trait ProofTreeVisitor<'db> { +pub(crate) trait ProofTreeVisitor<'db> { type Result: VisitorResult; fn config(&self) -> InspectConfig { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs index 3fd8e7b39dd7..c1ccbaf78a70 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs @@ -1,89 +1,68 @@ //! Things related to the Interner in the next-trait-solver. -#![allow(unused)] // FIXME(next-solver): Remove this. use std::{fmt, ops::ControlFlow}; +pub use tls_cache::clear_tls_solver_cache; pub use tls_db::{attach_db, attach_db_allow_change, with_attached_db}; use base_db::Crate; -use chalk_ir::{ProgramClauseImplication, SeparatorTraitRef, Variances}; use hir_def::{ - AdtId, AttrDefId, BlockId, CallableDefId, EnumVariantId, GenericDefId, ItemContainerId, Lookup, - StructId, TypeAliasId, UnionId, VariantId, + AdtId, AttrDefId, BlockId, CallableDefId, EnumVariantId, ItemContainerId, StructId, UnionId, + VariantId, lang_item::LangItem, signatures::{FieldData, FnFlags, ImplFlags, StructFlags, TraitFlags}, }; -use intern::sym::non_exhaustive; -use intern::{Interned, impl_internable, sym}; use la_arena::Idx; -use rustc_abi::{Align, ReprFlags, ReprOptions}; -use rustc_ast_ir::visit::VisitorResult; +use rustc_abi::{ReprFlags, ReprOptions}; use rustc_hash::FxHashSet; -use rustc_index::{IndexVec, bit_set::DenseBitSet}; +use rustc_index::bit_set::DenseBitSet; use rustc_type_ir::{ - AliasTerm, AliasTermKind, AliasTy, AliasTyKind, BoundVar, CollectAndApply, DebruijnIndex, - EarlyBinder, FlagComputation, Flags, GenericArgKind, ImplPolarity, InferTy, - ProjectionPredicate, RegionKind, TermKind, TraitPredicate, TraitRef, TypeVisitableExt, - UniverseIndex, Upcast, Variance, WithCachedTypeInfo, - elaborate::{self, elaborate}, + AliasTermKind, AliasTyKind, BoundVar, CollectAndApply, CoroutineWitnessTypes, DebruijnIndex, + EarlyBinder, FlagComputation, Flags, GenericArgKind, ImplPolarity, InferTy, Interner, TraitRef, + TypeVisitableExt, UniverseIndex, Upcast, Variance, + elaborate::elaborate, error::TypeError, - inherent::{ - self, AdtDef as _, Const as _, GenericArgs as _, GenericsOf, IntoKind, ParamEnv as _, - Region as _, SliceLike as _, Span as _, Ty as _, - }, - ir_print, + inherent::{self, GenericsOf, IntoKind, SliceLike as _, Span as _, Ty as _}, lang_items::{SolverAdtLangItem, SolverLangItem, SolverTraitLangItem}, - relate, solve::SizedTraitKind, }; -use salsa::plumbing::AsId; -use smallvec::{SmallVec, smallvec}; -use syntax::ast::SelfParamKind; -use tracing::debug; -use triomphe::Arc; use crate::{ - ConstScalar, FnAbi, Interner, - db::HirDatabase, - lower_nextsolver::{self, TyLoweringContext}, + FnAbi, + db::{HirDatabase, InternedCoroutine}, method_resolution::{ALL_FLOAT_FPS, ALL_INT_FPS, TyFingerprint}, next_solver::{ AdtIdWrapper, BoundConst, CallableIdWrapper, CanonicalVarKind, ClosureIdWrapper, - CoroutineIdWrapper, Ctor, FnSig, FxIndexMap, ImplIdWrapper, InternedWrapperNoDebug, + CoroutineIdWrapper, Ctor, FnSig, FxIndexMap, ImplIdWrapper, OpaqueTypeKey, RegionAssumptions, SolverContext, SolverDefIds, TraitIdWrapper, TypeAliasIdWrapper, - TypingMode, - infer::{ - DbInternerInferExt, InferCtxt, - traits::{Obligation, ObligationCause}, - }, - obligation_ctxt::ObligationCtxt, util::{ContainsTypeErrors, explicit_item_bounds, for_trait_impls}, }, }; use super::{ - Binder, BoundExistentialPredicate, BoundExistentialPredicates, BoundTy, BoundTyKind, Clause, - ClauseKind, Clauses, Const, ConstKind, ErrorGuaranteed, ExprConst, ExternalConstraints, - ExternalConstraintsData, GenericArg, GenericArgs, InternedClausesWrapper, ParamConst, ParamEnv, - ParamTy, PlaceholderConst, PlaceholderTy, PredefinedOpaques, PredefinedOpaquesData, Predicate, - PredicateKind, SolverDefId, Term, Ty, TyKind, Tys, Valtree, ValueConst, + Binder, BoundExistentialPredicates, BoundTy, BoundTyKind, Clause, ClauseKind, Clauses, Const, + ErrorGuaranteed, ExprConst, ExternalConstraints, GenericArg, GenericArgs, ParamConst, ParamEnv, + ParamTy, PlaceholderConst, PlaceholderTy, PredefinedOpaques, Predicate, SolverDefId, Term, Ty, + TyKind, Tys, Valtree, ValueConst, abi::Safety, fold::{BoundVarReplacer, BoundVarReplacerDelegate, FnMutDelegate}, generics::{Generics, generics}, - mapping::ChalkToNextSolver, region::{ BoundRegion, BoundRegionKind, EarlyParamRegion, LateParamRegion, PlaceholderRegion, Region, }, util::sizedness_constraint_for_ty, }; +#[derive(PartialEq, Eq, Hash, PartialOrd, Ord, Clone)] +pub struct InternedWrapperNoDebug(pub(crate) T); + #[macro_export] #[doc(hidden)] macro_rules! _interned_vec_nolifetime_salsa { ($name:ident, $ty:ty) => { interned_vec_nolifetime_salsa!($name, $ty, nofold); - impl<'db> rustc_type_ir::TypeFoldable> for $name { + impl<'db> rustc_type_ir::TypeFoldable> for $name<'db> { fn try_fold_with>>( self, folder: &mut F, @@ -104,7 +83,7 @@ macro_rules! _interned_vec_nolifetime_salsa { } } - impl<'db> rustc_type_ir::TypeVisitable> for $name { + impl<'db> rustc_type_ir::TypeVisitable> for $name<'db> { fn visit_with>>( &self, visitor: &mut V, @@ -117,14 +96,14 @@ macro_rules! _interned_vec_nolifetime_salsa { } }; ($name:ident, $ty:ty, nofold) => { - #[salsa::interned(no_lifetime, constructor = new_, debug)] + #[salsa::interned(constructor = new_, debug)] pub struct $name { #[returns(ref)] inner_: smallvec::SmallVec<[$ty; 2]>, } - impl $name { - pub fn new_from_iter<'db>( + impl<'db> $name<'db> { + pub fn new_from_iter( interner: DbInterner<'db>, data: impl IntoIterator, ) -> Self { @@ -140,7 +119,7 @@ macro_rules! _interned_vec_nolifetime_salsa { } } - impl rustc_type_ir::inherent::SliceLike for $name { + impl<'db> rustc_type_ir::inherent::SliceLike for $name<'db> { type Item = $ty; type IntoIter = as IntoIterator>::IntoIter; @@ -154,7 +133,7 @@ macro_rules! _interned_vec_nolifetime_salsa { } } - impl IntoIterator for $name { + impl<'db> IntoIterator for $name<'db> { type Item = $ty; type IntoIter = ::IntoIter; @@ -163,7 +142,7 @@ macro_rules! _interned_vec_nolifetime_salsa { } } - impl Default for $name { + impl<'db> Default for $name<'db> { fn default() -> Self { $name::new_from_iter(DbInterner::conjure(), []) } @@ -631,12 +610,11 @@ impl<'db> inherent::AdtDef> for AdtDef { self, interner: DbInterner<'db>, ) -> Option, Ty<'db>>> { - let db = interner.db(); let hir_def::AdtId::StructId(struct_id) = self.inner().id else { return None; }; let id: VariantId = struct_id.into(); - let field_types = interner.db().field_types_ns(id); + let field_types = interner.db().field_types(id); field_types.iter().last().map(|f| *f.1) } @@ -647,23 +625,10 @@ impl<'db> inherent::AdtDef> for AdtDef { ) -> EarlyBinder, impl IntoIterator>> { let db = interner.db(); // FIXME: this is disabled just to match the behavior with chalk right now - let field_tys = |id: VariantId| { - let variant_data = id.fields(db); - let fields = if variant_data.fields().is_empty() { - vec![] - } else { - let field_types = db.field_types_ns(id); - variant_data - .fields() - .iter() - .map(|(idx, _)| { - let ty = field_types[idx]; - ty.skip_binder() - }) - .collect() - }; + let _field_tys = |id: VariantId| { + db.field_types(id).iter().map(|(_, ty)| ty.skip_binder()).collect::>() }; - let field_tys = |id: VariantId| vec![]; + let field_tys = |_id: VariantId| vec![]; let tys: Vec<_> = match self.inner().id { hir_def::AdtId::StructId(id) => field_tys(id.into()), hir_def::AdtId::UnionId(id) => field_tys(id.into()), @@ -696,7 +661,7 @@ impl<'db> inherent::AdtDef> for AdtDef { fn destructor( self, - interner: DbInterner<'db>, + _interner: DbInterner<'db>, ) -> Option { // FIXME(next-solver) None @@ -742,7 +707,7 @@ impl<'db> inherent::Features> for Features { false } - fn feature_bound_holds_in_crate(self, symbol: ()) -> bool { + fn feature_bound_holds_in_crate(self, _symbol: ()) -> bool { false } } @@ -884,10 +849,10 @@ macro_rules! as_lang_item { }}; } -impl<'db> rustc_type_ir::Interner for DbInterner<'db> { +impl<'db> Interner for DbInterner<'db> { type DefId = SolverDefId; type LocalDefId = SolverDefId; - type LocalDefIds = SolverDefIds; + type LocalDefIds = SolverDefIds<'db>; type TraitId = TraitIdWrapper; type ForeignId = TypeAliasIdWrapper; type FunctionId = CallableIdWrapper; @@ -904,16 +869,16 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { type Term = Term<'db>; - type BoundVarKinds = BoundVarKinds; + type BoundVarKinds = BoundVarKinds<'db>; type BoundVarKind = BoundVarKind; type PredefinedOpaques = PredefinedOpaques<'db>; fn mk_predefined_opaques_in_body( self, - data: rustc_type_ir::solve::PredefinedOpaquesData, + data: &[(OpaqueTypeKey<'db>, Self::Ty)], ) -> Self::PredefinedOpaques { - PredefinedOpaques::new(self, data) + PredefinedOpaques::new_from_iter(self, data.iter().cloned()) } type CanonicalVarKinds = CanonicalVars<'db>; @@ -977,7 +942,7 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { type GenericsOf = Generics; - type VariancesOf = VariancesOf; + type VariancesOf = VariancesOf<'db>; type AdtDef = AdtDef; @@ -1002,7 +967,7 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { fn mk_tracked( self, data: T, - dep_node: Self::DepNodeIndex, + _dep_node: Self::DepNodeIndex, ) -> Self::Tracked { Tracked(data) } @@ -1024,15 +989,15 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { fn canonical_param_env_cache_get_or_insert( self, - param_env: Self::ParamEnv, + _param_env: Self::ParamEnv, f: impl FnOnce() -> rustc_type_ir::CanonicalParamEnvCacheEntry, from_entry: impl FnOnce(&rustc_type_ir::CanonicalParamEnvCacheEntry) -> R, ) -> R { from_entry(&f()) } - fn evaluation_is_concurrent(&self) -> bool { - false + fn assert_evaluation_is_concurrent(&self) { + panic!("evaluation shouldn't be concurrent yet") } fn expand_abstract_consts>(self, _: T) -> T { @@ -1045,10 +1010,9 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { fn variances_of(self, def_id: Self::DefId) -> Self::VariancesOf { let generic_def = match def_id { - SolverDefId::FunctionId(def_id) => def_id.into(), - SolverDefId::AdtId(def_id) => def_id.into(), - SolverDefId::Ctor(Ctor::Struct(def_id)) => def_id.into(), - SolverDefId::Ctor(Ctor::Enum(def_id)) => def_id.loc(self.db).parent.into(), + SolverDefId::Ctor(Ctor::Enum(def_id)) | SolverDefId::EnumVariantId(def_id) => { + def_id.loc(self.db).parent.into() + } SolverDefId::InternedOpaqueTyId(_def_id) => { // FIXME(next-solver): track variances // @@ -1059,17 +1023,20 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { (0..self.generics_of(def_id).count()).map(|_| Variance::Invariant), ); } - _ => return VariancesOf::new_from_iter(self, []), + SolverDefId::Ctor(Ctor::Struct(def_id)) => def_id.into(), + SolverDefId::AdtId(def_id) => def_id.into(), + SolverDefId::FunctionId(def_id) => def_id.into(), + SolverDefId::ConstId(_) + | SolverDefId::StaticId(_) + | SolverDefId::TraitId(_) + | SolverDefId::TypeAliasId(_) + | SolverDefId::ImplId(_) + | SolverDefId::InternedClosureId(_) + | SolverDefId::InternedCoroutineId(_) => { + return VariancesOf::new_from_iter(self, []); + } }; - VariancesOf::new_from_iter( - self, - self.db() - .variances_of(generic_def) - .as_deref() - .unwrap_or_default() - .iter() - .map(|v| v.to_nextsolver(self)), - ) + self.db.variances_of(generic_def) } fn type_of(self, def_id: Self::DefId) -> EarlyBinder { @@ -1160,17 +1127,17 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { (TraitRef::new_from_args(self, trait_def_id.try_into().unwrap(), trait_args), alias_args) } - fn check_args_compatible(self, def_id: Self::DefId, args: Self::GenericArgs) -> bool { + fn check_args_compatible(self, _def_id: Self::DefId, _args: Self::GenericArgs) -> bool { // FIXME true } - fn debug_assert_args_compatible(self, def_id: Self::DefId, args: Self::GenericArgs) {} + fn debug_assert_args_compatible(self, _def_id: Self::DefId, _args: Self::GenericArgs) {} fn debug_assert_existential_args_compatible( self, - def_id: Self::DefId, - args: Self::GenericArgs, + _def_id: Self::DefId, + _args: Self::GenericArgs, ) { } @@ -1211,6 +1178,7 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { | SolverDefId::AdtId(_) | SolverDefId::TraitId(_) | SolverDefId::ImplId(_) + | SolverDefId::EnumVariantId(..) | SolverDefId::Ctor(..) | SolverDefId::InternedOpaqueTyId(..) => panic!(), }; @@ -1238,11 +1206,27 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { } fn coroutine_movability(self, def_id: Self::CoroutineId) -> rustc_ast_ir::Movability { - unimplemented!() + // FIXME: Make this a query? I don't believe this can be accessed from bodies other than + // the current infer query, except with revealed opaques - is it rare enough to not matter? + let InternedCoroutine(owner, expr_id) = def_id.0.loc(self.db); + let body = self.db.body(owner); + let expr = &body[expr_id]; + match *expr { + hir_def::hir::Expr::Closure { closure_kind, .. } => match closure_kind { + hir_def::hir::ClosureKind::Coroutine(movability) => match movability { + hir_def::hir::Movability::Static => rustc_ast_ir::Movability::Static, + hir_def::hir::Movability::Movable => rustc_ast_ir::Movability::Movable, + }, + hir_def::hir::ClosureKind::Async => rustc_ast_ir::Movability::Static, + _ => panic!("unexpected expression for a coroutine: {expr:?}"), + }, + hir_def::hir::Expr::Async { .. } => rustc_ast_ir::Movability::Static, + _ => panic!("unexpected expression for a coroutine: {expr:?}"), + } } - fn coroutine_for_closure(self, def_id: Self::CoroutineId) -> Self::CoroutineId { - unimplemented!() + fn coroutine_for_closure(self, def_id: Self::CoroutineClosureId) -> Self::CoroutineId { + def_id } fn generics_require_sized_self(self, def_id: Self::DefId) -> bool { @@ -1319,7 +1303,7 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { self, def_id: Self::DefId, ) -> EarlyBinder> { - let predicates = self.db().generic_predicates_ns(def_id.try_into().unwrap()); + let predicates = self.db().generic_predicates(def_id.try_into().unwrap()); let predicates: Vec<_> = predicates.iter().cloned().collect(); EarlyBinder::bind(predicates.into_iter()) } @@ -1346,7 +1330,7 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { let predicates: Vec<(Clause<'db>, Span)> = self .db() - .generic_predicates_ns(def_id.0.into()) + .generic_predicates(def_id.0.into()) .iter() .filter(|p| match p.kind().skip_binder() { // rustc has the following assertion: @@ -1380,7 +1364,7 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { let predicates: Vec<(Clause<'db>, Span)> = self .db() - .generic_predicates_ns(def_id.try_into().unwrap()) + .generic_predicates(def_id.try_into().unwrap()) .iter() .filter(|p| match p.kind().skip_binder() { rustc_type_ir::ClauseKind::Trait(it) => is_self_or_assoc(it.self_ty()), @@ -1418,9 +1402,10 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { }) } + #[expect(unreachable_code)] fn const_conditions( self, - def_id: Self::DefId, + _def_id: Self::DefId, ) -> EarlyBinder< Self, impl IntoIterator>>, @@ -1428,7 +1413,7 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { EarlyBinder::bind([unimplemented!()]) } - fn has_target_features(self, def_id: Self::FunctionId) -> bool { + fn has_target_features(self, _def_id: Self::FunctionId) -> bool { false } @@ -1459,7 +1444,7 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { hir_def::lang_item::LangItemTarget::Union(union_id) => union_id.into(), hir_def::lang_item::LangItemTarget::TypeAlias(type_alias_id) => type_alias_id.into(), hir_def::lang_item::LangItemTarget::Trait(trait_id) => trait_id.into(), - hir_def::lang_item::LangItemTarget::EnumVariant(enum_variant_id) => unimplemented!(), + hir_def::lang_item::LangItemTarget::EnumVariant(_) => unimplemented!(), } } @@ -1549,7 +1534,6 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { CoroutineReturn, CoroutineYield, FutureOutput, - AsyncFnOnceOutput, CallRefFuture, CallOnceFuture, AsyncFnOnceOutput, @@ -1593,7 +1577,6 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { AsyncFnMut, AsyncFnOnce, AsyncFnOnceOutput, - AsyncFnOnceOutput, ) } @@ -1633,7 +1616,7 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { }; if fps.is_empty() { - for_trait_impls( + _ = for_trait_impls( self.db(), self.krate.expect("Must have self.krate"), self.block, @@ -1655,7 +1638,7 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { }, ); } else { - for_trait_impls( + _ = for_trait_impls( self.db(), self.krate.expect("Must have self.krate"), self.block, @@ -1695,7 +1678,7 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { } } - fn has_item_definition(self, def_id: Self::DefId) -> bool { + fn has_item_definition(self, _def_id: Self::DefId) -> bool { // FIXME(next-solver): should check if the associated item has a value. true } @@ -1743,13 +1726,13 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { trait_data.flags.contains(TraitFlags::FUNDAMENTAL) } - fn trait_may_be_implemented_via_object(self, trait_def_id: Self::TraitId) -> bool { + fn trait_may_be_implemented_via_object(self, _trait_def_id: Self::TraitId) -> bool { // FIXME(next-solver): should check the `TraitFlags` for // the `#[rustc_do_not_implement_via_object]` flag true } - fn is_impl_trait_in_trait(self, def_id: Self::DefId) -> bool { + fn is_impl_trait_in_trait(self, _def_id: Self::DefId) -> bool { // FIXME(next-solver) false } @@ -1758,23 +1741,39 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { panic!("Bug encountered in next-trait-solver: {}", msg.to_string()) } - fn is_general_coroutine(self, coroutine_def_id: Self::CoroutineId) -> bool { - // FIXME(next-solver) - true + fn is_general_coroutine(self, def_id: Self::CoroutineId) -> bool { + // FIXME: Make this a query? I don't believe this can be accessed from bodies other than + // the current infer query, except with revealed opaques - is it rare enough to not matter? + let InternedCoroutine(owner, expr_id) = def_id.0.loc(self.db); + let body = self.db.body(owner); + matches!( + body[expr_id], + hir_def::hir::Expr::Closure { + closure_kind: hir_def::hir::ClosureKind::Coroutine(_), + .. + } + ) } - fn coroutine_is_async(self, coroutine_def_id: Self::CoroutineId) -> bool { - // FIXME(next-solver) - true + fn coroutine_is_async(self, def_id: Self::CoroutineId) -> bool { + // FIXME: Make this a query? I don't believe this can be accessed from bodies other than + // the current infer query, except with revealed opaques - is it rare enough to not matter? + let InternedCoroutine(owner, expr_id) = def_id.0.loc(self.db); + let body = self.db.body(owner); + matches!( + body[expr_id], + hir_def::hir::Expr::Closure { closure_kind: hir_def::hir::ClosureKind::Async, .. } + | hir_def::hir::Expr::Async { .. } + ) } - fn coroutine_is_gen(self, coroutine_def_id: Self::CoroutineId) -> bool { - // FIXME(next-solver) + fn coroutine_is_gen(self, _coroutine_def_id: Self::CoroutineId) -> bool { + // We don't handle gen coroutines yet. false } - fn coroutine_is_async_gen(self, coroutine_def_id: Self::CoroutineId) -> bool { - // FIXME(next-solver) + fn coroutine_is_async_gen(self, _coroutine_def_id: Self::CoroutineId) -> bool { + // We don't handle gen coroutines yet. false } @@ -1801,7 +1800,7 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { return UnsizingParams(DenseBitSet::new_empty(num_params)); }; - let field_types = self.db().field_types_ns(variant.id()); + let field_types = self.db().field_types(variant.id()); let mut unsizing_params = DenseBitSet::new_empty(num_params); let ty = field_types[tail_field.0]; for arg in ty.instantiate_identity().walk() { @@ -1867,19 +1866,19 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { Binder::bind_with_vars(inner, bound_vars) } - fn opaque_types_defined_by(self, defining_anchor: Self::LocalDefId) -> Self::LocalDefIds { + fn opaque_types_defined_by(self, _defining_anchor: Self::LocalDefId) -> Self::LocalDefIds { // FIXME(next-solver) SolverDefIds::new_from_iter(self, []) } - fn alias_has_const_conditions(self, def_id: Self::DefId) -> bool { + fn alias_has_const_conditions(self, _def_id: Self::DefId) -> bool { // FIXME(next-solver) false } fn explicit_implied_const_bounds( self, - def_id: Self::DefId, + _def_id: Self::DefId, ) -> EarlyBinder< Self, impl IntoIterator>>, @@ -1896,14 +1895,14 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { self.db().function_signature(id).flags.contains(FnFlags::CONST) } - fn impl_is_const(self, def_id: Self::ImplId) -> bool { + fn impl_is_const(self, _def_id: Self::ImplId) -> bool { false } fn opt_alias_variances( self, - kind: impl Into, - def_id: Self::DefId, + _kind: impl Into, + _def_id: Self::DefId, ) -> Option { None } @@ -1915,10 +1914,9 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { match impl_trait_id { crate::ImplTraitId::ReturnTypeImplTrait(func, idx) => { let infer = self.db().infer(func.into()); - EarlyBinder::bind(infer.type_of_rpit[idx.to_nextsolver(self)]) + EarlyBinder::bind(infer.type_of_rpit[idx]) } - crate::ImplTraitId::TypeAliasImplTrait(..) - | crate::ImplTraitId::AsyncBlockTypeImplTrait(_, _) => { + crate::ImplTraitId::TypeAliasImplTrait(..) => { // FIXME(next-solver) EarlyBinder::bind(Ty::new_error(self, ErrorGuaranteed)) } @@ -1930,11 +1928,13 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { fn coroutine_hidden_types( self, - def_id: Self::CoroutineId, - ) -> EarlyBinder>> - { - // FIXME(next-solver) - unimplemented!() + _def_id: Self::CoroutineId, + ) -> EarlyBinder>> { + // FIXME: Actually implement this. + EarlyBinder::bind(Binder::dummy(CoroutineWitnessTypes { + types: Tys::default(), + assumptions: RegionAssumptions::default(), + })) } fn is_default_trait(self, def_id: Self::TraitId) -> bool { @@ -1949,7 +1949,7 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { self.db().trait_signature(trait_.0).flags.contains(TraitFlags::UNSAFE) } - fn impl_self_is_guaranteed_unsized(self, def_id: Self::ImplId) -> bool { + fn impl_self_is_guaranteed_unsized(self, _def_id: Self::ImplId) -> bool { false } @@ -1958,7 +1958,11 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { specializing_impl_def_id: Self::ImplId, parent_impl_def_id: Self::ImplId, ) -> bool { - false + crate::specialization::specializes( + self.db, + specializing_impl_def_id.0, + parent_impl_def_id.0, + ) } fn next_trait_solver_globally(self) -> bool { @@ -1967,10 +1971,9 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { fn opaque_types_and_coroutines_defined_by( self, - defining_anchor: Self::LocalDefId, + _defining_anchor: Self::LocalDefId, ) -> Self::LocalDefIds { - // FIXME(next-solver) - unimplemented!() + Default::default() } type Probe = rustc_type_ir::solve::inspect::Probe>; @@ -1986,6 +1989,13 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> { Self, >(self, canonical_goal) } + + fn is_sizedness_trait(self, def_id: Self::TraitId) -> bool { + matches!( + self.as_trait_lang_item(def_id), + Some(SolverTraitLangItem::Sized | SolverTraitLangItem::MetaSized) + ) + } } impl<'db> DbInterner<'db> { @@ -2273,4 +2283,12 @@ mod tls_cache { }) }) } + + /// Clears the thread-local trait solver cache. + /// + /// Should be called before getting memory usage estimations, as the solver cache + /// is per-revision and usually should be excluded from estimations. + pub fn clear_tls_solver_cache() { + GLOBAL_CACHE.with_borrow_mut(|handle| *handle = None); + } } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ir_print.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ir_print.rs index 69afcf5dde90..dab0fe9e4a90 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ir_print.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ir_print.rs @@ -5,8 +5,6 @@ use std::any::type_name_of_val; use rustc_type_ir::inherent::SliceLike; use rustc_type_ir::{self as ty, ir_print::IrPrint}; -use crate::db::HirDatabase; - use super::SolverDefId; use super::interner::DbInterner; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/mapping.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/mapping.rs deleted file mode 100644 index 1a5982cc00d3..000000000000 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/mapping.rs +++ /dev/null @@ -1,1779 +0,0 @@ -//! Things useful for mapping to/from Chalk and next-trait-solver types. - -use base_db::Crate; -use chalk_ir::{ - CanonicalVarKind, CanonicalVarKinds, FnPointer, InferenceVar, Substitution, TyVariableKind, - WellFormed, cast::Cast, fold::Shift, interner::HasInterner, -}; -use hir_def::{ - CallableDefId, ConstParamId, FunctionId, GeneralConstId, LifetimeParamId, TypeAliasId, - TypeOrConstParamId, TypeParamId, signatures::TraitFlags, -}; -use hir_def::{GenericDefId, GenericParamId}; -use intern::sym; -use rustc_type_ir::{ - AliasTerm, BoundVar, DebruijnIndex, ExistentialProjection, ExistentialTraitRef, Interner as _, - OutlivesPredicate, ProjectionPredicate, TypeFoldable, TypeSuperFoldable, TypeVisitable, - TypeVisitableExt, UniverseIndex, elaborate, - inherent::{BoundVarLike, Clause as _, IntoKind, PlaceholderLike, SliceLike, Ty as _}, - shift_vars, - solve::Goal, -}; -use salsa::plumbing::FromId; -use salsa::{Id, plumbing::AsId}; - -use crate::next_solver::BoundConst; -use crate::{ - ConstScalar, ImplTraitId, Interner, MemoryMap, - db::{ - HirDatabase, InternedClosureId, InternedCoroutineId, InternedLifetimeParamId, - InternedOpaqueTyId, InternedTypeOrConstParamId, - }, - from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id, - mapping::ToChalk, - next_solver::{ - Binder, ClauseKind, ConstBytes, TraitPredicate, UnevaluatedConst, - interner::{AdtDef, BoundVarKind, BoundVarKinds, DbInterner}, - }, - to_assoc_type_id, to_chalk_trait_id, to_foreign_def_id, -}; -use crate::{ - from_placeholder_idx, lt_from_placeholder_idx, lt_to_placeholder_idx, to_placeholder_idx, -}; - -use super::{ - BoundExistentialPredicate, BoundExistentialPredicates, BoundRegion, BoundRegionKind, BoundTy, - BoundTyKind, Canonical, CanonicalVars, Clause, Clauses, Const, Ctor, EarlyParamRegion, - ErrorGuaranteed, ExistentialPredicate, GenericArg, GenericArgs, ParamConst, ParamEnv, ParamTy, - Placeholder, PlaceholderConst, PlaceholderRegion, PlaceholderTy, Predicate, PredicateKind, - Region, SolverDefId, SubtypePredicate, Term, TraitRef, Ty, Tys, ValueConst, VariancesOf, -}; - -// FIXME: This should urgently go (as soon as we finish the migration off Chalk, that is). -pub fn convert_binder_to_early_binder<'db, T: rustc_type_ir::TypeFoldable>>( - interner: DbInterner<'db>, - def: GenericDefId, - binder: rustc_type_ir::Binder, T>, -) -> rustc_type_ir::EarlyBinder, T> { - let mut folder = BinderToEarlyBinder { - interner, - debruijn: rustc_type_ir::DebruijnIndex::ZERO, - params: crate::generics::generics(interner.db, def).iter_id().collect(), - }; - rustc_type_ir::EarlyBinder::bind(binder.skip_binder().fold_with(&mut folder)) -} - -struct BinderToEarlyBinder<'db> { - interner: DbInterner<'db>, - debruijn: rustc_type_ir::DebruijnIndex, - params: Vec, -} - -impl<'db> rustc_type_ir::TypeFolder> for BinderToEarlyBinder<'db> { - fn cx(&self) -> DbInterner<'db> { - self.interner - } - - fn fold_binder( - &mut self, - t: rustc_type_ir::Binder, T>, - ) -> rustc_type_ir::Binder, T> - where - T: TypeFoldable>, - { - self.debruijn.shift_in(1); - let result = t.super_fold_with(self); - self.debruijn.shift_out(1); - result - } - - fn fold_ty(&mut self, t: Ty<'db>) -> Ty<'db> { - match t.kind() { - rustc_type_ir::TyKind::Bound(debruijn, bound_ty) if self.debruijn == debruijn => { - let var: rustc_type_ir::BoundVar = bound_ty.var(); - let GenericParamId::TypeParamId(id) = self.params[bound_ty.var.as_usize()] else { - unreachable!() - }; - Ty::new( - self.cx(), - rustc_type_ir::TyKind::Param(ParamTy { index: var.as_u32(), id }), - ) - } - _ => t.super_fold_with(self), - } - } - - fn fold_region(&mut self, r: Region<'db>) -> Region<'db> { - match r.kind() { - rustc_type_ir::ReBound(debruijn, bound_region) if self.debruijn == debruijn => { - let var: rustc_type_ir::BoundVar = bound_region.var(); - let GenericParamId::LifetimeParamId(id) = self.params[bound_region.var.as_usize()] - else { - unreachable!() - }; - Region::new( - self.cx(), - rustc_type_ir::RegionKind::ReEarlyParam(EarlyParamRegion { - index: var.as_u32(), - id, - }), - ) - } - _ => r, - } - } - - fn fold_const(&mut self, c: Const<'db>) -> Const<'db> { - match c.kind() { - rustc_type_ir::ConstKind::Bound(debruijn, var) if self.debruijn == debruijn => { - let GenericParamId::ConstParamId(id) = self.params[var.var.as_usize()] else { - unreachable!() - }; - Const::new( - self.cx(), - rustc_type_ir::ConstKind::Param(ParamConst { index: var.var.as_u32(), id }), - ) - } - _ => c.super_fold_with(self), - } - } -} - -pub trait ChalkToNextSolver<'db, Out> { - fn to_nextsolver(&self, interner: DbInterner<'db>) -> Out; -} - -impl<'db, A, OutA, B, OutB> ChalkToNextSolver<'db, (OutA, OutB)> for (A, B) -where - A: ChalkToNextSolver<'db, OutA>, - B: ChalkToNextSolver<'db, OutB>, -{ - fn to_nextsolver(&self, interner: DbInterner<'db>) -> (OutA, OutB) { - (self.0.to_nextsolver(interner), self.1.to_nextsolver(interner)) - } -} - -pub trait NextSolverToChalk<'db, Out> { - fn to_chalk(self, interner: DbInterner<'db>) -> Out; -} - -impl<'db, T, Out> NextSolverToChalk<'db, Option> for Option -where - T: NextSolverToChalk<'db, Out>, -{ - fn to_chalk(self, interner: DbInterner<'db>) -> Option { - self.map(|it| it.to_chalk(interner)) - } -} - -impl NextSolverToChalk<'_, chalk_ir::Mutability> for rustc_ast_ir::Mutability { - fn to_chalk(self, interner: DbInterner<'_>) -> chalk_ir::Mutability { - match self { - rustc_ast_ir::Mutability::Not => chalk_ir::Mutability::Not, - rustc_ast_ir::Mutability::Mut => chalk_ir::Mutability::Mut, - } - } -} - -impl NextSolverToChalk<'_, chalk_ir::Safety> for crate::next_solver::abi::Safety { - fn to_chalk(self, interner: DbInterner<'_>) -> chalk_ir::Safety { - match self { - crate::next_solver::abi::Safety::Unsafe => chalk_ir::Safety::Unsafe, - crate::next_solver::abi::Safety::Safe => chalk_ir::Safety::Safe, - } - } -} - -impl<'db> ChalkToNextSolver<'db, Ty<'db>> for chalk_ir::Ty { - fn to_nextsolver(&self, interner: DbInterner<'db>) -> Ty<'db> { - Ty::new( - interner, - match self.kind(Interner) { - chalk_ir::TyKind::Adt(adt_id, substitution) => { - let def = AdtDef::new(adt_id.0, interner); - let args = substitution.to_nextsolver(interner); - rustc_type_ir::TyKind::Adt(def, args) - } - chalk_ir::TyKind::AssociatedType(assoc_type_id, substitution) => { - let def_id = SolverDefId::TypeAliasId(from_assoc_type_id(*assoc_type_id)); - let args: GenericArgs<'db> = substitution.to_nextsolver(interner); - let alias_ty = rustc_type_ir::AliasTy::new(interner, def_id, args.iter()); - rustc_type_ir::TyKind::Alias(rustc_type_ir::AliasTyKind::Projection, alias_ty) - } - chalk_ir::TyKind::Scalar(scalar) => match scalar { - chalk_ir::Scalar::Bool => rustc_type_ir::TyKind::Bool, - chalk_ir::Scalar::Char => rustc_type_ir::TyKind::Char, - chalk_ir::Scalar::Int(chalk_ir::IntTy::Isize) => { - rustc_type_ir::TyKind::Int(rustc_type_ir::IntTy::Isize) - } - chalk_ir::Scalar::Int(chalk_ir::IntTy::I8) => { - rustc_type_ir::TyKind::Int(rustc_type_ir::IntTy::I8) - } - chalk_ir::Scalar::Int(chalk_ir::IntTy::I16) => { - rustc_type_ir::TyKind::Int(rustc_type_ir::IntTy::I16) - } - chalk_ir::Scalar::Int(chalk_ir::IntTy::I32) => { - rustc_type_ir::TyKind::Int(rustc_type_ir::IntTy::I32) - } - chalk_ir::Scalar::Int(chalk_ir::IntTy::I64) => { - rustc_type_ir::TyKind::Int(rustc_type_ir::IntTy::I64) - } - chalk_ir::Scalar::Int(chalk_ir::IntTy::I128) => { - rustc_type_ir::TyKind::Int(rustc_type_ir::IntTy::I128) - } - chalk_ir::Scalar::Uint(chalk_ir::UintTy::Usize) => { - rustc_type_ir::TyKind::Uint(rustc_type_ir::UintTy::Usize) - } - chalk_ir::Scalar::Uint(chalk_ir::UintTy::U8) => { - rustc_type_ir::TyKind::Uint(rustc_type_ir::UintTy::U8) - } - chalk_ir::Scalar::Uint(chalk_ir::UintTy::U16) => { - rustc_type_ir::TyKind::Uint(rustc_type_ir::UintTy::U16) - } - chalk_ir::Scalar::Uint(chalk_ir::UintTy::U32) => { - rustc_type_ir::TyKind::Uint(rustc_type_ir::UintTy::U32) - } - chalk_ir::Scalar::Uint(chalk_ir::UintTy::U64) => { - rustc_type_ir::TyKind::Uint(rustc_type_ir::UintTy::U64) - } - chalk_ir::Scalar::Uint(chalk_ir::UintTy::U128) => { - rustc_type_ir::TyKind::Uint(rustc_type_ir::UintTy::U128) - } - chalk_ir::Scalar::Float(chalk_ir::FloatTy::F16) => { - rustc_type_ir::TyKind::Float(rustc_type_ir::FloatTy::F16) - } - chalk_ir::Scalar::Float(chalk_ir::FloatTy::F32) => { - rustc_type_ir::TyKind::Float(rustc_type_ir::FloatTy::F32) - } - chalk_ir::Scalar::Float(chalk_ir::FloatTy::F64) => { - rustc_type_ir::TyKind::Float(rustc_type_ir::FloatTy::F64) - } - chalk_ir::Scalar::Float(chalk_ir::FloatTy::F128) => { - rustc_type_ir::TyKind::Float(rustc_type_ir::FloatTy::F128) - } - }, - chalk_ir::TyKind::Tuple(_, substitution) => { - let args = substitution.to_nextsolver(interner); - rustc_type_ir::TyKind::Tuple(args) - } - chalk_ir::TyKind::Array(ty, len) => rustc_type_ir::TyKind::Array( - ty.to_nextsolver(interner), - len.to_nextsolver(interner), - ), - chalk_ir::TyKind::Slice(ty) => { - rustc_type_ir::TyKind::Slice(ty.to_nextsolver(interner)) - } - chalk_ir::TyKind::Raw(mutability, ty) => rustc_type_ir::RawPtr( - ty.to_nextsolver(interner), - mutability.to_nextsolver(interner), - ), - chalk_ir::TyKind::Ref(mutability, lifetime, ty) => rustc_type_ir::TyKind::Ref( - lifetime.to_nextsolver(interner), - ty.to_nextsolver(interner), - mutability.to_nextsolver(interner), - ), - chalk_ir::TyKind::OpaqueType(def_id, substitution) => { - let id: InternedOpaqueTyId = (*def_id).into(); - let args: GenericArgs<'db> = substitution.to_nextsolver(interner); - let alias_ty = rustc_type_ir::AliasTy::new(interner, id.into(), args); - rustc_type_ir::TyKind::Alias(rustc_type_ir::AliasTyKind::Opaque, alias_ty) - } - chalk_ir::TyKind::FnDef(fn_def_id, substitution) => { - let def_id = CallableDefId::from_chalk(interner.db(), *fn_def_id); - rustc_type_ir::TyKind::FnDef( - def_id.into(), - substitution.to_nextsolver(interner), - ) - } - chalk_ir::TyKind::Str => rustc_type_ir::TyKind::Str, - chalk_ir::TyKind::Never => rustc_type_ir::TyKind::Never, - chalk_ir::TyKind::Closure(closure_id, substitution) => { - let id: InternedClosureId = (*closure_id).into(); - rustc_type_ir::TyKind::Closure(id.into(), substitution.to_nextsolver(interner)) - } - chalk_ir::TyKind::Coroutine(coroutine_id, substitution) => { - let id: InternedCoroutineId = (*coroutine_id).into(); - rustc_type_ir::TyKind::Coroutine( - id.into(), - substitution.to_nextsolver(interner), - ) - } - chalk_ir::TyKind::CoroutineWitness(coroutine_id, substitution) => { - let id: InternedCoroutineId = (*coroutine_id).into(); - rustc_type_ir::TyKind::CoroutineWitness( - id.into(), - substitution.to_nextsolver(interner), - ) - } - chalk_ir::TyKind::Foreign(foreign_def_id) => rustc_type_ir::TyKind::Foreign( - crate::from_foreign_def_id(*foreign_def_id).into(), - ), - chalk_ir::TyKind::Error => rustc_type_ir::TyKind::Error(ErrorGuaranteed), - chalk_ir::TyKind::Dyn(dyn_ty) => { - // exists { for<...> ^1.0: ... } - let bounds = BoundExistentialPredicates::new_from_iter( - interner, - dyn_ty.bounds.skip_binders().iter(Interner).filter_map(|pred| { - // for<...> ^1.0: ... - let (val, binders) = pred.clone().into_value_and_skipped_binders(); - let bound_vars = binders.to_nextsolver(interner); - let clause = match val { - chalk_ir::WhereClause::Implemented(trait_ref) => { - let trait_id = from_chalk_trait_id(trait_ref.trait_id); - if interner - .db() - .trait_signature(trait_id) - .flags - .contains(TraitFlags::AUTO) - { - ExistentialPredicate::AutoTrait(trait_id.into()) - } else { - let args = GenericArgs::new_from_iter( - interner, - trait_ref - .substitution - .iter(Interner) - .skip(1) - .map(|a| a.clone().shifted_out(Interner).unwrap()) - .map(|a| a.to_nextsolver(interner)), - ); - let trait_ref = ExistentialTraitRef::new_from_args( - interner, trait_id.into(), args, - ); - ExistentialPredicate::Trait(trait_ref) - } - } - chalk_ir::WhereClause::AliasEq(alias_eq) => { - let (def_id, args) = match &alias_eq.alias { - chalk_ir::AliasTy::Projection(projection) => { - let id = - from_assoc_type_id(projection.associated_ty_id); - let def_id = SolverDefId::TypeAliasId(id); - let generics = interner.generics_of(def_id); - let parent_len = generics.parent_count; - let substs = projection.substitution.iter(Interner).skip(1); - - let args = GenericArgs::new_from_iter( - interner, - substs - .map(|a| { - a.clone().shifted_out(Interner).unwrap() - }) - .map(|a| a.to_nextsolver(interner)), - ); - (def_id, args) - } - chalk_ir::AliasTy::Opaque(opaque_ty) => { - panic!("Invalid ExistentialPredicate (opaques can't be named)."); - } - }; - let term = alias_eq - .ty - .clone() - .shifted_out(Interner) - .unwrap() - .to_nextsolver(interner) - .into(); - let projection = ExistentialProjection::new_from_args( - interner, def_id, args, term, - ); - ExistentialPredicate::Projection(projection) - } - chalk_ir::WhereClause::LifetimeOutlives(lifetime_outlives) => { - return None; - } - chalk_ir::WhereClause::TypeOutlives(type_outlives) => return None, - }; - - Some(Binder::bind_with_vars(clause, bound_vars)) - }), - ); - let region = dyn_ty.lifetime.to_nextsolver(interner); - rustc_type_ir::TyKind::Dynamic(bounds, region) - } - chalk_ir::TyKind::Alias(alias_ty) => match alias_ty { - chalk_ir::AliasTy::Projection(projection_ty) => { - let def_id = SolverDefId::TypeAliasId(from_assoc_type_id( - projection_ty.associated_ty_id, - )); - let alias_ty = rustc_type_ir::AliasTy::new_from_args( - interner, - def_id, - projection_ty.substitution.to_nextsolver(interner), - ); - rustc_type_ir::TyKind::Alias( - rustc_type_ir::AliasTyKind::Projection, - alias_ty, - ) - } - chalk_ir::AliasTy::Opaque(opaque_ty) => { - let id: InternedOpaqueTyId = opaque_ty.opaque_ty_id.into(); - let def_id = SolverDefId::InternedOpaqueTyId(id); - let alias_ty = rustc_type_ir::AliasTy::new_from_args( - interner, - def_id, - opaque_ty.substitution.to_nextsolver(interner), - ); - rustc_type_ir::TyKind::Alias(rustc_type_ir::AliasTyKind::Opaque, alias_ty) - } - }, - chalk_ir::TyKind::Function(fn_pointer) => { - let sig_tys = fn_pointer.clone().into_binders(Interner).to_nextsolver(interner); - let header = rustc_type_ir::FnHeader { - abi: fn_pointer.sig.abi, - c_variadic: fn_pointer.sig.variadic, - safety: match fn_pointer.sig.safety { - chalk_ir::Safety::Safe => super::abi::Safety::Safe, - chalk_ir::Safety::Unsafe => super::abi::Safety::Unsafe, - }, - }; - - rustc_type_ir::TyKind::FnPtr(sig_tys, header) - } - // The schema here is quite confusing. - // The new solver, like rustc, uses `Param` and `EarlyBinder` for generic params. It uses `BoundVar` - // and `Placeholder` together with `Binder` for HRTB, which we mostly don't handle. - // Chalk uses `Placeholder` for generic params and `BoundVar` quite liberally, and this is quite a - // problem. `chalk_ir::TyKind::BoundVar` can represent either HRTB or generic params, depending on the - // context. When returned from signature queries, the outer `Binders` represent the generic params. - // But there are also inner `Binders` for HRTB. - // AFAIK there is no way to tell which of the meanings is relevant, so we just use `rustc_type_ir::Bound` - // here, and hope for the best. If you are working with new solver types, therefore, use the new solver - // lower queries. - // Hopefully sooner than later Chalk will be ripped from the codebase and we can avoid that problem. - // For details about the rustc setup, read: https://rustc-dev-guide.rust-lang.org/generic_parameters_summary.html - // and the following chapters. - chalk_ir::TyKind::Placeholder(placeholder_index) => { - let (id, index) = from_placeholder_idx(interner.db, *placeholder_index); - rustc_type_ir::TyKind::Param(ParamTy { - id: TypeParamId::from_unchecked(id), - index, - }) - } - chalk_ir::TyKind::BoundVar(bound_var) => rustc_type_ir::TyKind::Bound( - bound_var.debruijn.to_nextsolver(interner), - BoundTy { - var: rustc_type_ir::BoundVar::from_usize(bound_var.index), - kind: BoundTyKind::Anon, - }, - ), - chalk_ir::TyKind::InferenceVar(inference_var, ty_variable_kind) => { - rustc_type_ir::TyKind::Infer( - (*inference_var, *ty_variable_kind).to_nextsolver(interner), - ) - } - }, - ) - } -} - -impl<'db> NextSolverToChalk<'db, chalk_ir::Ty> for Ty<'db> { - fn to_chalk(self, interner: DbInterner<'db>) -> chalk_ir::Ty { - convert_ty_for_result(interner, self) - } -} - -impl<'db> ChalkToNextSolver<'db, Region<'db>> for chalk_ir::Lifetime { - fn to_nextsolver(&self, interner: DbInterner<'db>) -> Region<'db> { - Region::new( - interner, - match self.data(Interner) { - chalk_ir::LifetimeData::BoundVar(bound_var) => rustc_type_ir::RegionKind::ReBound( - bound_var.debruijn.to_nextsolver(interner), - BoundRegion { - var: rustc_type_ir::BoundVar::from_u32(bound_var.index as u32), - kind: BoundRegionKind::Anon, - }, - ), - chalk_ir::LifetimeData::InferenceVar(inference_var) => { - rustc_type_ir::RegionKind::ReVar(rustc_type_ir::RegionVid::from_u32( - inference_var.index(), - )) - } - chalk_ir::LifetimeData::Placeholder(placeholder_index) => { - let (id, index) = lt_from_placeholder_idx(interner.db, *placeholder_index); - rustc_type_ir::RegionKind::ReEarlyParam(EarlyParamRegion { id, index }) - } - chalk_ir::LifetimeData::Static => rustc_type_ir::RegionKind::ReStatic, - chalk_ir::LifetimeData::Erased => rustc_type_ir::RegionKind::ReErased, - chalk_ir::LifetimeData::Phantom(_, _) => { - unreachable!() - } - chalk_ir::LifetimeData::Error => { - rustc_type_ir::RegionKind::ReError(ErrorGuaranteed) - } - }, - ) - } -} - -impl<'db> NextSolverToChalk<'db, chalk_ir::Lifetime> for Region<'db> { - fn to_chalk(self, interner: DbInterner<'db>) -> chalk_ir::Lifetime { - convert_region_for_result(interner, self) - } -} - -impl<'db> ChalkToNextSolver<'db, Const<'db>> for chalk_ir::Const { - fn to_nextsolver(&self, interner: DbInterner<'db>) -> Const<'db> { - let data = self.data(Interner); - Const::new( - interner, - match &data.value { - chalk_ir::ConstValue::BoundVar(bound_var) => rustc_type_ir::ConstKind::Bound( - bound_var.debruijn.to_nextsolver(interner), - BoundConst { var: rustc_type_ir::BoundVar::from_usize(bound_var.index) }, - ), - chalk_ir::ConstValue::InferenceVar(inference_var) => { - rustc_type_ir::ConstKind::Infer(rustc_type_ir::InferConst::Var( - rustc_type_ir::ConstVid::from_u32(inference_var.index()), - )) - } - chalk_ir::ConstValue::Placeholder(placeholder_index) => { - let (id, index) = from_placeholder_idx(interner.db, *placeholder_index); - rustc_type_ir::ConstKind::Param(ParamConst { - id: ConstParamId::from_unchecked(id), - index, - }) - } - chalk_ir::ConstValue::Concrete(concrete_const) => match &concrete_const.interned { - ConstScalar::Bytes(bytes, memory) => { - rustc_type_ir::ConstKind::Value(ValueConst::new( - data.ty.to_nextsolver(interner), - ConstBytes { memory: bytes.clone(), memory_map: memory.clone() }, - )) - } - ConstScalar::UnevaluatedConst(c, subst) => { - let def = match *c { - GeneralConstId::ConstId(id) => SolverDefId::ConstId(id), - GeneralConstId::StaticId(id) => SolverDefId::StaticId(id), - }; - let args = subst.to_nextsolver(interner); - rustc_type_ir::ConstKind::Unevaluated(UnevaluatedConst::new(def, args)) - } - ConstScalar::Unknown => rustc_type_ir::ConstKind::Error(ErrorGuaranteed), - }, - }, - ) - } -} - -impl<'db> NextSolverToChalk<'db, chalk_ir::Const> for Const<'db> { - fn to_chalk(self, interner: DbInterner<'db>) -> chalk_ir::Const { - convert_const_for_result(interner, self) - } -} - -impl<'db> ChalkToNextSolver<'db, rustc_type_ir::FnSigTys>> - for chalk_ir::FnSubst -{ - fn to_nextsolver(&self, interner: DbInterner<'db>) -> rustc_type_ir::FnSigTys> { - rustc_type_ir::FnSigTys { - inputs_and_output: Tys::new_from_iter( - interner, - self.0.iter(Interner).map(|g| g.assert_ty_ref(Interner).to_nextsolver(interner)), - ), - } - } -} - -impl< - 'db, - U: TypeVisitable>, - T: Clone + ChalkToNextSolver<'db, U> + HasInterner, -> ChalkToNextSolver<'db, rustc_type_ir::Binder, U>> for chalk_ir::Binders -{ - fn to_nextsolver( - &self, - interner: DbInterner<'db>, - ) -> rustc_type_ir::Binder, U> { - let (val, binders) = self.clone().into_value_and_skipped_binders(); - rustc_type_ir::Binder::bind_with_vars( - val.to_nextsolver(interner), - binders.to_nextsolver(interner), - ) - } -} - -impl<'db, T: NextSolverToChalk<'db, U>, U: HasInterner> - NextSolverToChalk<'db, chalk_ir::Binders> for rustc_type_ir::Binder, T> -{ - fn to_chalk(self, interner: DbInterner<'db>) -> chalk_ir::Binders { - chalk_ir::Binders::new( - self.bound_vars().to_chalk(interner), - self.skip_binder().to_chalk(interner), - ) - } -} - -impl<'db> ChalkToNextSolver<'db, BoundVarKinds> for chalk_ir::VariableKinds { - fn to_nextsolver(&self, interner: DbInterner<'db>) -> BoundVarKinds { - BoundVarKinds::new_from_iter( - interner, - self.iter(Interner).map(|v| v.to_nextsolver(interner)), - ) - } -} - -impl<'db> NextSolverToChalk<'db, chalk_ir::VariableKinds> for BoundVarKinds { - fn to_chalk(self, interner: DbInterner<'db>) -> chalk_ir::VariableKinds { - chalk_ir::VariableKinds::from_iter(Interner, self.iter().map(|v| v.to_chalk(interner))) - } -} - -impl<'db> ChalkToNextSolver<'db, BoundVarKind> for chalk_ir::VariableKind { - fn to_nextsolver(&self, interner: DbInterner<'db>) -> BoundVarKind { - match self { - chalk_ir::VariableKind::Ty(_ty_variable_kind) => BoundVarKind::Ty(BoundTyKind::Anon), - chalk_ir::VariableKind::Lifetime => BoundVarKind::Region(BoundRegionKind::Anon), - chalk_ir::VariableKind::Const(_ty) => BoundVarKind::Const, - } - } -} - -impl<'db> NextSolverToChalk<'db, chalk_ir::VariableKind> for BoundVarKind { - fn to_chalk(self, interner: DbInterner<'db>) -> chalk_ir::VariableKind { - match self { - BoundVarKind::Ty(_) => chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General), - BoundVarKind::Region(_) => chalk_ir::VariableKind::Lifetime, - BoundVarKind::Const => { - chalk_ir::VariableKind::Const(chalk_ir::TyKind::Error.intern(Interner)) - } - } - } -} - -impl<'db> ChalkToNextSolver<'db, GenericArg<'db>> for chalk_ir::GenericArg { - fn to_nextsolver(&self, interner: DbInterner<'db>) -> GenericArg<'db> { - match self.data(Interner) { - chalk_ir::GenericArgData::Ty(ty) => ty.to_nextsolver(interner).into(), - chalk_ir::GenericArgData::Lifetime(lifetime) => lifetime.to_nextsolver(interner).into(), - chalk_ir::GenericArgData::Const(const_) => const_.to_nextsolver(interner).into(), - } - } -} - -impl<'db> NextSolverToChalk<'db, crate::GenericArg> for GenericArg<'db> { - fn to_chalk(self, interner: DbInterner<'db>) -> crate::GenericArg { - match self { - GenericArg::Ty(ty) => ty.to_chalk(interner).cast(Interner), - GenericArg::Lifetime(region) => region.to_chalk(interner).cast(Interner), - GenericArg::Const(konst) => konst.to_chalk(interner).cast(Interner), - } - } -} - -impl<'db> ChalkToNextSolver<'db, GenericArgs<'db>> for chalk_ir::Substitution { - fn to_nextsolver(&self, interner: DbInterner<'db>) -> GenericArgs<'db> { - GenericArgs::new_from_iter( - interner, - self.iter(Interner).map(|arg| -> GenericArg<'db> { arg.to_nextsolver(interner) }), - ) - } -} - -impl<'db> ChalkToNextSolver<'db, crate::lower_nextsolver::ImplTraitIdx<'db>> - for crate::ImplTraitIdx -{ - fn to_nextsolver( - &self, - interner: DbInterner<'db>, - ) -> crate::lower_nextsolver::ImplTraitIdx<'db> { - crate::lower_nextsolver::ImplTraitIdx::from_raw(self.into_raw()) - } -} - -impl<'db> NextSolverToChalk<'db, chalk_ir::Substitution> for GenericArgs<'db> { - fn to_chalk(self, interner: DbInterner<'db>) -> chalk_ir::Substitution { - convert_args_for_result(interner, self.as_slice()) - } -} - -impl<'db> ChalkToNextSolver<'db, Tys<'db>> for chalk_ir::Substitution { - fn to_nextsolver(&self, interner: DbInterner<'db>) -> Tys<'db> { - Tys::new_from_iter( - interner, - self.iter(Interner).map(|arg| -> Ty<'db> { - match arg.data(Interner) { - chalk_ir::GenericArgData::Ty(ty) => ty.to_nextsolver(interner), - chalk_ir::GenericArgData::Lifetime(_) => unreachable!(), - chalk_ir::GenericArgData::Const(_) => unreachable!(), - } - }), - ) - } -} - -impl<'db> NextSolverToChalk<'db, crate::Substitution> for Tys<'db> { - fn to_chalk(self, interner: DbInterner<'db>) -> crate::Substitution { - Substitution::from_iter( - Interner, - self.inner().iter().map(|ty| ty.to_chalk(interner).cast(Interner)), - ) - } -} - -impl<'db> ChalkToNextSolver<'db, rustc_type_ir::DebruijnIndex> for chalk_ir::DebruijnIndex { - fn to_nextsolver(&self, _interner: DbInterner<'db>) -> rustc_type_ir::DebruijnIndex { - rustc_type_ir::DebruijnIndex::from_u32(self.depth()) - } -} - -impl<'db> NextSolverToChalk<'db, chalk_ir::DebruijnIndex> for rustc_type_ir::DebruijnIndex { - fn to_chalk(self, _interner: DbInterner<'db>) -> chalk_ir::DebruijnIndex { - chalk_ir::DebruijnIndex::new(self.index() as u32) - } -} - -impl<'db> ChalkToNextSolver<'db, rustc_type_ir::UniverseIndex> for chalk_ir::UniverseIndex { - fn to_nextsolver(&self, _interner: DbInterner<'db>) -> rustc_type_ir::UniverseIndex { - rustc_type_ir::UniverseIndex::from_u32(self.counter as u32) - } -} - -impl<'db> NextSolverToChalk<'db, chalk_ir::UniverseIndex> for rustc_type_ir::UniverseIndex { - fn to_chalk(self, _interner: DbInterner<'db>) -> chalk_ir::UniverseIndex { - chalk_ir::UniverseIndex { counter: self.index() } - } -} - -impl<'db> ChalkToNextSolver<'db, rustc_type_ir::InferTy> - for (chalk_ir::InferenceVar, chalk_ir::TyVariableKind) -{ - fn to_nextsolver(&self, interner: DbInterner<'db>) -> rustc_type_ir::InferTy { - match self.1 { - chalk_ir::TyVariableKind::General => { - rustc_type_ir::InferTy::TyVar(rustc_type_ir::TyVid::from_u32(self.0.index())) - } - chalk_ir::TyVariableKind::Integer => { - rustc_type_ir::InferTy::IntVar(rustc_type_ir::IntVid::from_u32(self.0.index())) - } - chalk_ir::TyVariableKind::Float => { - rustc_type_ir::InferTy::FloatVar(rustc_type_ir::FloatVid::from_u32(self.0.index())) - } - } - } -} - -impl<'db> ChalkToNextSolver<'db, rustc_ast_ir::Mutability> for chalk_ir::Mutability { - fn to_nextsolver(&self, interner: DbInterner<'db>) -> rustc_ast_ir::Mutability { - match self { - chalk_ir::Mutability::Mut => rustc_ast_ir::Mutability::Mut, - chalk_ir::Mutability::Not => rustc_ast_ir::Mutability::Not, - } - } -} - -impl<'db> ChalkToNextSolver<'db, rustc_type_ir::Variance> for crate::Variance { - fn to_nextsolver(&self, interner: DbInterner<'db>) -> rustc_type_ir::Variance { - match self { - crate::Variance::Covariant => rustc_type_ir::Variance::Covariant, - crate::Variance::Invariant => rustc_type_ir::Variance::Invariant, - crate::Variance::Contravariant => rustc_type_ir::Variance::Contravariant, - crate::Variance::Bivariant => rustc_type_ir::Variance::Bivariant, - } - } -} - -impl<'db> ChalkToNextSolver<'db, rustc_type_ir::Variance> for chalk_ir::Variance { - fn to_nextsolver(&self, interner: DbInterner<'db>) -> rustc_type_ir::Variance { - match self { - chalk_ir::Variance::Covariant => rustc_type_ir::Variance::Covariant, - chalk_ir::Variance::Invariant => rustc_type_ir::Variance::Invariant, - chalk_ir::Variance::Contravariant => rustc_type_ir::Variance::Contravariant, - } - } -} - -impl<'db> ChalkToNextSolver<'db, VariancesOf> for chalk_ir::Variances { - fn to_nextsolver(&self, interner: DbInterner<'db>) -> VariancesOf { - VariancesOf::new_from_iter( - interner, - self.as_slice(Interner).iter().map(|v| v.to_nextsolver(interner)), - ) - } -} - -impl<'db> ChalkToNextSolver<'db, Goal, Predicate<'db>>> - for chalk_ir::InEnvironment> -{ - fn to_nextsolver(&self, interner: DbInterner<'db>) -> Goal, Predicate<'db>> { - Goal::new( - interner, - self.environment.to_nextsolver(interner), - self.goal.to_nextsolver(interner), - ) - } -} - -impl<'db> NextSolverToChalk<'db, chalk_ir::InEnvironment>> - for Goal, Predicate<'db>> -{ - fn to_chalk( - self, - interner: DbInterner<'db>, - ) -> chalk_ir::InEnvironment> { - chalk_ir::InEnvironment { - environment: self.param_env.to_chalk(interner), - goal: self.predicate.to_chalk(interner), - } - } -} - -impl<'db, T: HasInterner + ChalkToNextSolver<'db, U>, U> - ChalkToNextSolver<'db, Canonical<'db, U>> for chalk_ir::Canonical -{ - fn to_nextsolver(&self, interner: DbInterner<'db>) -> Canonical<'db, U> { - let variables = CanonicalVars::new_from_iter( - interner, - self.binders.iter(Interner).map(|k| match &k.kind { - chalk_ir::VariableKind::Ty(ty_variable_kind) => match ty_variable_kind { - // FIXME(next-solver): the info is incorrect, but we have no way to store the information in Chalk. - TyVariableKind::General => rustc_type_ir::CanonicalVarKind::Ty { - ui: UniverseIndex::ROOT, - sub_root: BoundVar::from_u32(0), - }, - TyVariableKind::Integer => rustc_type_ir::CanonicalVarKind::Int, - TyVariableKind::Float => rustc_type_ir::CanonicalVarKind::Float, - }, - chalk_ir::VariableKind::Lifetime => { - rustc_type_ir::CanonicalVarKind::Region(UniverseIndex::ROOT) - } - chalk_ir::VariableKind::Const(ty) => { - rustc_type_ir::CanonicalVarKind::Const(UniverseIndex::ROOT) - } - }), - ); - Canonical { - max_universe: UniverseIndex::ROOT, - value: self.value.to_nextsolver(interner), - variables, - } - } -} - -impl<'db, T: NextSolverToChalk<'db, U>, U: HasInterner> - NextSolverToChalk<'db, chalk_ir::Canonical> for Canonical<'db, T> -{ - fn to_chalk(self, interner: DbInterner<'db>) -> chalk_ir::Canonical { - let binders = chalk_ir::CanonicalVarKinds::from_iter( - Interner, - self.variables.iter().map(|v| match v { - rustc_type_ir::CanonicalVarKind::Ty { ui, sub_root: _ } => { - chalk_ir::CanonicalVarKind::new( - chalk_ir::VariableKind::Ty(TyVariableKind::General), - chalk_ir::UniverseIndex { counter: ui.as_usize() }, - ) - } - rustc_type_ir::CanonicalVarKind::Int => chalk_ir::CanonicalVarKind::new( - chalk_ir::VariableKind::Ty(TyVariableKind::Integer), - chalk_ir::UniverseIndex::root(), - ), - rustc_type_ir::CanonicalVarKind::Float => chalk_ir::CanonicalVarKind::new( - chalk_ir::VariableKind::Ty(TyVariableKind::Float), - chalk_ir::UniverseIndex::root(), - ), - rustc_type_ir::CanonicalVarKind::Region(ui) => chalk_ir::CanonicalVarKind::new( - chalk_ir::VariableKind::Lifetime, - chalk_ir::UniverseIndex { counter: ui.as_usize() }, - ), - rustc_type_ir::CanonicalVarKind::Const(ui) => chalk_ir::CanonicalVarKind::new( - chalk_ir::VariableKind::Const(chalk_ir::TyKind::Error.intern(Interner)), - chalk_ir::UniverseIndex { counter: ui.as_usize() }, - ), - rustc_type_ir::CanonicalVarKind::PlaceholderTy(_) => unimplemented!(), - rustc_type_ir::CanonicalVarKind::PlaceholderRegion(_) => unimplemented!(), - rustc_type_ir::CanonicalVarKind::PlaceholderConst(_) => unimplemented!(), - }), - ); - let value = self.value.to_chalk(interner); - chalk_ir::Canonical { binders, value } - } -} - -impl<'db> ChalkToNextSolver<'db, Predicate<'db>> for chalk_ir::Goal { - fn to_nextsolver(&self, interner: DbInterner<'db>) -> Predicate<'db> { - match self.data(Interner) { - chalk_ir::GoalData::Quantified(quantifier_kind, binders) => { - if !binders.binders.is_empty(Interner) { - panic!("Should not be constructed."); - } - let (val, _) = binders.clone().into_value_and_skipped_binders(); - val.shifted_out(Interner).unwrap().to_nextsolver(interner) - } - chalk_ir::GoalData::Implies(program_clauses, goal) => { - panic!("Should not be constructed.") - } - chalk_ir::GoalData::All(goals) => panic!("Should not be constructed."), - chalk_ir::GoalData::Not(goal) => panic!("Should not be constructed."), - chalk_ir::GoalData::EqGoal(eq_goal) => { - let arg_to_term = |g: &chalk_ir::GenericArg| match g.data(Interner) { - chalk_ir::GenericArgData::Ty(ty) => Term::Ty(ty.to_nextsolver(interner)), - chalk_ir::GenericArgData::Const(const_) => { - Term::Const(const_.to_nextsolver(interner)) - } - chalk_ir::GenericArgData::Lifetime(lifetime) => unreachable!(), - }; - let pred_kind = PredicateKind::AliasRelate( - arg_to_term(&eq_goal.a), - arg_to_term(&eq_goal.b), - rustc_type_ir::AliasRelationDirection::Equate, - ); - let pred_kind = - Binder::bind_with_vars(pred_kind, BoundVarKinds::new_from_iter(interner, [])); - Predicate::new(interner, pred_kind) - } - chalk_ir::GoalData::SubtypeGoal(subtype_goal) => { - let subtype_predicate = SubtypePredicate { - a: subtype_goal.a.to_nextsolver(interner), - b: subtype_goal.b.to_nextsolver(interner), - a_is_expected: true, - }; - let pred_kind = PredicateKind::Subtype(subtype_predicate); - let pred_kind = Binder::bind_with_vars( - shift_vars(interner, pred_kind, 1), - BoundVarKinds::new_from_iter(interner, []), - ); - Predicate::new(interner, pred_kind) - } - chalk_ir::GoalData::DomainGoal(domain_goal) => { - let pred_kind = domain_goal.to_nextsolver(interner); - let pred_kind = Binder::bind_with_vars( - shift_vars(interner, pred_kind, 1), - BoundVarKinds::new_from_iter(interner, []), - ); - Predicate::new(interner, pred_kind) - } - chalk_ir::GoalData::CannotProve => panic!("Should not be constructed."), - } - } -} - -impl<'db> NextSolverToChalk<'db, chalk_ir::Goal> for Predicate<'db> { - fn to_chalk(self, interner: DbInterner<'db>) -> chalk_ir::Goal { - chalk_ir::Goal::new(Interner, self.kind().skip_binder().to_chalk(interner)) - } -} - -impl<'db> NextSolverToChalk<'db, crate::ProjectionTy> for crate::next_solver::AliasTy<'db> { - fn to_chalk(self, interner: DbInterner<'db>) -> crate::ProjectionTy { - let SolverDefId::TypeAliasId(assoc_id) = self.def_id else { unreachable!() }; - crate::ProjectionTy { - associated_ty_id: to_assoc_type_id(assoc_id), - substitution: self.args.to_chalk(interner), - } - } -} - -impl<'db> ChalkToNextSolver<'db, ParamEnv<'db>> for chalk_ir::Environment { - fn to_nextsolver(&self, interner: DbInterner<'db>) -> ParamEnv<'db> { - let clauses = Clauses::new_from_iter( - interner, - self.clauses.iter(Interner).map(|c| c.to_nextsolver(interner)), - ); - let clauses = - Clauses::new_from_iter(interner, elaborate::elaborate(interner, clauses.iter())); - ParamEnv { clauses } - } -} - -impl<'db> NextSolverToChalk<'db, chalk_ir::Environment> for ParamEnv<'db> { - fn to_chalk(self, interner: DbInterner<'db>) -> chalk_ir::Environment { - let clauses = chalk_ir::ProgramClauses::from_iter( - Interner, - self.clauses.iter().filter_map(|c| -> Option> { - c.to_chalk(interner) - }), - ); - chalk_ir::Environment { clauses } - } -} - -impl<'db> ChalkToNextSolver<'db, Clause<'db>> for chalk_ir::ProgramClause { - fn to_nextsolver(&self, interner: DbInterner<'db>) -> Clause<'db> { - Clause(Predicate::new(interner, self.data(Interner).0.to_nextsolver(interner))) - } -} - -impl<'db> NextSolverToChalk<'db, Option>> for Clause<'db> { - fn to_chalk(self, interner: DbInterner<'db>) -> Option> { - let value: chalk_ir::ProgramClauseImplication = - as NextSolverToChalk< - 'db, - Option>, - >>::to_chalk(self.0.kind().skip_binder(), interner)?; - Some(chalk_ir::ProgramClause::new( - Interner, - chalk_ir::ProgramClauseData(chalk_ir::Binders::empty(Interner, value)), - )) - } -} - -impl<'db> ChalkToNextSolver<'db, PredicateKind<'db>> - for chalk_ir::ProgramClauseImplication -{ - fn to_nextsolver(&self, interner: DbInterner<'db>) -> PredicateKind<'db> { - assert!(self.conditions.is_empty(Interner)); - assert!(self.constraints.is_empty(Interner)); - self.consequence.to_nextsolver(interner) - } -} - -impl<'db> NextSolverToChalk<'db, Option>> - for PredicateKind<'db> -{ - fn to_chalk( - self, - interner: DbInterner<'db>, - ) -> Option> { - let chalk_ir::GoalData::DomainGoal(consequence) = self.to_chalk(interner) else { - return None; - }; - - Some(chalk_ir::ProgramClauseImplication { - consequence, - conditions: chalk_ir::Goals::empty(Interner), - constraints: chalk_ir::Constraints::empty(Interner), - priority: chalk_ir::ClausePriority::High, - }) - } -} - -impl<'db> ChalkToNextSolver<'db, PredicateKind<'db>> for chalk_ir::DomainGoal { - fn to_nextsolver(&self, interner: DbInterner<'db>) -> PredicateKind<'db> { - match self { - chalk_ir::DomainGoal::Holds(where_clause) => match where_clause { - chalk_ir::WhereClause::Implemented(trait_ref) => { - let predicate = TraitPredicate { - trait_ref: trait_ref.to_nextsolver(interner), - polarity: rustc_type_ir::PredicatePolarity::Positive, - }; - PredicateKind::Clause(ClauseKind::Trait(predicate)) - } - chalk_ir::WhereClause::AliasEq(alias_eq) => match &alias_eq.alias { - chalk_ir::AliasTy::Projection(p) => { - let def_id = - SolverDefId::TypeAliasId(from_assoc_type_id(p.associated_ty_id)); - let args = p.substitution.to_nextsolver(interner); - let term: Ty<'db> = alias_eq.ty.to_nextsolver(interner); - let term: Term<'db> = term.into(); - let predicate = ProjectionPredicate { - projection_term: AliasTerm::new_from_args(interner, def_id, args), - term, - }; - PredicateKind::Clause(ClauseKind::Projection(predicate)) - } - chalk_ir::AliasTy::Opaque(opaque) => { - let id: InternedOpaqueTyId = opaque.opaque_ty_id.into(); - let def_id = SolverDefId::InternedOpaqueTyId(id); - let args = opaque.substitution.to_nextsolver(interner); - let term: Ty<'db> = alias_eq.ty.to_nextsolver(interner); - let term: Term<'db> = term.into(); - let opaque_ty = Ty::new( - interner, - rustc_type_ir::TyKind::Alias( - rustc_type_ir::AliasTyKind::Opaque, - rustc_type_ir::AliasTy::new_from_args(interner, def_id, args), - ), - ) - .into(); - PredicateKind::AliasRelate( - opaque_ty, - term, - rustc_type_ir::AliasRelationDirection::Equate, - ) - } - }, - chalk_ir::WhereClause::LifetimeOutlives(lifetime_outlives) => { - let predicate = OutlivesPredicate( - lifetime_outlives.a.to_nextsolver(interner), - lifetime_outlives.b.to_nextsolver(interner), - ); - PredicateKind::Clause(ClauseKind::RegionOutlives(predicate)) - } - chalk_ir::WhereClause::TypeOutlives(type_outlives) => { - let predicate = OutlivesPredicate( - type_outlives.ty.to_nextsolver(interner), - type_outlives.lifetime.to_nextsolver(interner), - ); - PredicateKind::Clause(ClauseKind::TypeOutlives(predicate)) - } - }, - chalk_ir::DomainGoal::Normalize(normalize) => { - let proj_ty = match &normalize.alias { - chalk_ir::AliasTy::Projection(proj) => proj, - _ => unimplemented!(), - }; - let args: GenericArgs<'db> = proj_ty.substitution.to_nextsolver(interner); - let alias = Ty::new( - interner, - rustc_type_ir::TyKind::Alias( - rustc_type_ir::AliasTyKind::Projection, - rustc_type_ir::AliasTy::new( - interner, - from_assoc_type_id(proj_ty.associated_ty_id).into(), - args, - ), - ), - ) - .into(); - let term = normalize.ty.to_nextsolver(interner).into(); - PredicateKind::AliasRelate( - alias, - term, - rustc_type_ir::AliasRelationDirection::Equate, - ) - } - chalk_ir::DomainGoal::WellFormed(well_formed) => { - let term = match well_formed { - WellFormed::Trait(_) => panic!("Should not be constructed."), - WellFormed::Ty(ty) => Term::Ty(ty.to_nextsolver(interner)), - }; - PredicateKind::Clause(rustc_type_ir::ClauseKind::WellFormed(term)) - } - chalk_ir::DomainGoal::FromEnv(from_env) => match from_env { - chalk_ir::FromEnv::Trait(trait_ref) => { - let predicate = TraitPredicate { - trait_ref: trait_ref.to_nextsolver(interner), - polarity: rustc_type_ir::PredicatePolarity::Positive, - }; - PredicateKind::Clause(ClauseKind::Trait(predicate)) - } - chalk_ir::FromEnv::Ty(ty) => PredicateKind::Clause(ClauseKind::WellFormed( - Term::Ty(ty.to_nextsolver(interner)), - )), - }, - chalk_ir::DomainGoal::IsLocal(ty) => panic!("Should not be constructed."), - chalk_ir::DomainGoal::IsUpstream(ty) => panic!("Should not be constructed."), - chalk_ir::DomainGoal::IsFullyVisible(ty) => panic!("Should not be constructed."), - chalk_ir::DomainGoal::LocalImplAllowed(trait_ref) => { - panic!("Should not be constructed.") - } - chalk_ir::DomainGoal::Compatible => panic!("Should not be constructed."), - chalk_ir::DomainGoal::DownstreamType(ty) => panic!("Should not be constructed."), - chalk_ir::DomainGoal::Reveal => panic!("Should not be constructed."), - chalk_ir::DomainGoal::ObjectSafe(trait_id) => panic!("Should not be constructed."), - } - } -} - -impl<'db> NextSolverToChalk<'db, chalk_ir::GoalData> for PredicateKind<'db> { - fn to_chalk(self, interner: DbInterner<'db>) -> chalk_ir::GoalData { - match self { - rustc_type_ir::PredicateKind::Clause(rustc_type_ir::ClauseKind::Trait(trait_pred)) => { - let trait_ref = trait_pred.trait_ref.to_chalk(interner); - let where_clause = chalk_ir::WhereClause::Implemented(trait_ref); - chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::Holds(where_clause)) - } - rustc_type_ir::PredicateKind::Clause(rustc_type_ir::ClauseKind::Projection( - proj_predicate, - )) => { - let associated_ty_id = match proj_predicate.def_id() { - SolverDefId::TypeAliasId(id) => to_assoc_type_id(id), - _ => unreachable!(), - }; - let substitution = proj_predicate.projection_term.args.to_chalk(interner); - let alias = chalk_ir::AliasTy::Projection(chalk_ir::ProjectionTy { - associated_ty_id, - substitution, - }); - let ty = match proj_predicate.term.kind() { - rustc_type_ir::TermKind::Ty(ty) => ty, - rustc_type_ir::TermKind::Const(_) => unimplemented!(), - }; - let ty = ty.to_chalk(interner); - let alias_eq = chalk_ir::AliasEq { alias, ty }; - let where_clause = chalk_ir::WhereClause::AliasEq(alias_eq); - chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::Holds(where_clause)) - } - rustc_type_ir::PredicateKind::Clause(rustc_type_ir::ClauseKind::TypeOutlives( - outlives, - )) => { - let lifetime = outlives.1.to_chalk(interner); - let ty = outlives.0.to_chalk(interner); - let where_clause = - chalk_ir::WhereClause::TypeOutlives(chalk_ir::TypeOutlives { lifetime, ty }); - chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::Holds(where_clause)) - } - rustc_type_ir::PredicateKind::Clause(rustc_type_ir::ClauseKind::RegionOutlives( - outlives, - )) => { - let a = outlives.0.to_chalk(interner); - let b = outlives.1.to_chalk(interner); - let where_clause = - chalk_ir::WhereClause::LifetimeOutlives(chalk_ir::LifetimeOutlives { a, b }); - chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::Holds(where_clause)) - } - rustc_type_ir::PredicateKind::AliasRelate( - alias_term, - target_term, - alias_relation_direction, - ) => { - let term_to_generic_arg = |term: Term<'db>| match term { - Term::Ty(ty) => chalk_ir::GenericArg::new( - Interner, - chalk_ir::GenericArgData::Ty(ty.to_chalk(interner)), - ), - Term::Const(const_) => chalk_ir::GenericArg::new( - Interner, - chalk_ir::GenericArgData::Const(const_.to_chalk(interner)), - ), - }; - - chalk_ir::GoalData::EqGoal(chalk_ir::EqGoal { - a: term_to_generic_arg(alias_term), - b: term_to_generic_arg(target_term), - }) - } - rustc_type_ir::PredicateKind::Clause(_) => unimplemented!(), - rustc_type_ir::PredicateKind::DynCompatible(_) => unimplemented!(), - rustc_type_ir::PredicateKind::Subtype(_) => unimplemented!(), - rustc_type_ir::PredicateKind::Coerce(_) => unimplemented!(), - rustc_type_ir::PredicateKind::ConstEquate(_, _) => unimplemented!(), - rustc_type_ir::PredicateKind::Ambiguous => unimplemented!(), - rustc_type_ir::PredicateKind::NormalizesTo(_) => unimplemented!(), - } - } -} - -impl<'db> ChalkToNextSolver<'db, TraitRef<'db>> for chalk_ir::TraitRef { - fn to_nextsolver(&self, interner: DbInterner<'db>) -> TraitRef<'db> { - let args = self.substitution.to_nextsolver(interner); - TraitRef::new_from_args(interner, from_chalk_trait_id(self.trait_id).into(), args) - } -} - -impl<'db> NextSolverToChalk<'db, chalk_ir::TraitRef> for TraitRef<'db> { - fn to_chalk(self, interner: DbInterner<'db>) -> chalk_ir::TraitRef { - let trait_id = to_chalk_trait_id(self.def_id.0); - let substitution = self.args.to_chalk(interner); - chalk_ir::TraitRef { trait_id, substitution } - } -} - -impl<'db> ChalkToNextSolver<'db, PredicateKind<'db>> for chalk_ir::WhereClause { - fn to_nextsolver(&self, interner: DbInterner<'db>) -> PredicateKind<'db> { - match self { - chalk_ir::WhereClause::Implemented(trait_ref) => { - let predicate = TraitPredicate { - trait_ref: trait_ref.to_nextsolver(interner), - polarity: rustc_type_ir::PredicatePolarity::Positive, - }; - PredicateKind::Clause(ClauseKind::Trait(predicate)) - } - chalk_ir::WhereClause::AliasEq(alias_eq) => { - let projection = match &alias_eq.alias { - chalk_ir::AliasTy::Projection(p) => p, - _ => unimplemented!(), - }; - let def_id = - SolverDefId::TypeAliasId(from_assoc_type_id(projection.associated_ty_id)); - let args = projection.substitution.to_nextsolver(interner); - let term: Ty<'db> = alias_eq.ty.to_nextsolver(interner); - let term: Term<'db> = term.into(); - let predicate = ProjectionPredicate { - projection_term: AliasTerm::new_from_args(interner, def_id, args), - term, - }; - PredicateKind::Clause(ClauseKind::Projection(predicate)) - } - chalk_ir::WhereClause::TypeOutlives(type_outlives) => { - let ty = type_outlives.ty.to_nextsolver(interner); - let r = type_outlives.lifetime.to_nextsolver(interner); - PredicateKind::Clause(ClauseKind::TypeOutlives(OutlivesPredicate(ty, r))) - } - chalk_ir::WhereClause::LifetimeOutlives(lifetime_outlives) => { - let a = lifetime_outlives.a.to_nextsolver(interner); - let b = lifetime_outlives.b.to_nextsolver(interner); - PredicateKind::Clause(ClauseKind::RegionOutlives(OutlivesPredicate(a, b))) - } - } - } -} - -impl<'db, I> NextSolverToChalk<'db, chalk_ir::ConstrainedSubst> for I -where - I: IntoIterator>, -{ - fn to_chalk(self, interner: DbInterner<'db>) -> chalk_ir::ConstrainedSubst { - chalk_ir::ConstrainedSubst { - constraints: chalk_ir::Constraints::empty(Interner), - subst: GenericArgs::new_from_iter(interner, self).to_chalk(interner), - } - } -} - -impl<'db> NextSolverToChalk<'db, crate::CallableSig> for rustc_type_ir::FnSig> { - fn to_chalk(self, interner: DbInterner<'db>) -> crate::CallableSig { - crate::CallableSig { - abi: self.abi, - is_varargs: self.c_variadic, - safety: match self.safety { - super::abi::Safety::Safe => chalk_ir::Safety::Safe, - super::abi::Safety::Unsafe => chalk_ir::Safety::Unsafe, - }, - params_and_return: triomphe::Arc::from_iter( - self.inputs_and_output.iter().map(|ty| convert_ty_for_result(interner, ty)), - ), - } - } -} - -pub fn convert_canonical_args_for_result<'db>( - interner: DbInterner<'db>, - args: Canonical<'db, Vec>>, -) -> chalk_ir::Canonical> { - args.to_chalk(interner) -} - -pub fn convert_args_for_result<'db>( - interner: DbInterner<'db>, - args: &[GenericArg<'db>], -) -> crate::Substitution { - let mut substs = Vec::with_capacity(args.len()); - for arg in args { - match (*arg).kind() { - rustc_type_ir::GenericArgKind::Type(ty) => { - let ty = convert_ty_for_result(interner, ty); - substs.push(chalk_ir::GenericArgData::Ty(ty).intern(Interner)); - } - rustc_type_ir::GenericArgKind::Lifetime(region) => { - let lifetime = convert_region_for_result(interner, region); - substs.push(chalk_ir::GenericArgData::Lifetime(lifetime).intern(Interner)); - } - rustc_type_ir::GenericArgKind::Const(const_) => { - substs.push( - chalk_ir::GenericArgData::Const(convert_const_for_result(interner, const_)) - .intern(Interner), - ); - } - } - } - Substitution::from_iter(Interner, substs) -} - -pub fn convert_ty_for_result<'db>(interner: DbInterner<'db>, ty: Ty<'db>) -> crate::Ty { - use crate::{Scalar, TyKind}; - use chalk_ir::{FloatTy, IntTy, UintTy}; - match ty.kind() { - rustc_type_ir::TyKind::Bool => TyKind::Scalar(Scalar::Bool), - rustc_type_ir::TyKind::Char => TyKind::Scalar(Scalar::Char), - rustc_type_ir::TyKind::Int(rustc_type_ir::IntTy::I8) => { - TyKind::Scalar(Scalar::Int(IntTy::I8)) - } - rustc_type_ir::TyKind::Int(rustc_type_ir::IntTy::I16) => { - TyKind::Scalar(Scalar::Int(IntTy::I16)) - } - rustc_type_ir::TyKind::Int(rustc_type_ir::IntTy::I32) => { - TyKind::Scalar(Scalar::Int(IntTy::I32)) - } - rustc_type_ir::TyKind::Int(rustc_type_ir::IntTy::I64) => { - TyKind::Scalar(Scalar::Int(IntTy::I64)) - } - rustc_type_ir::TyKind::Int(rustc_type_ir::IntTy::I128) => { - TyKind::Scalar(Scalar::Int(IntTy::I128)) - } - rustc_type_ir::TyKind::Int(rustc_type_ir::IntTy::Isize) => { - TyKind::Scalar(Scalar::Int(IntTy::Isize)) - } - rustc_type_ir::TyKind::Uint(rustc_type_ir::UintTy::U8) => { - TyKind::Scalar(Scalar::Uint(UintTy::U8)) - } - rustc_type_ir::TyKind::Uint(rustc_type_ir::UintTy::U16) => { - TyKind::Scalar(Scalar::Uint(UintTy::U16)) - } - rustc_type_ir::TyKind::Uint(rustc_type_ir::UintTy::U32) => { - TyKind::Scalar(Scalar::Uint(UintTy::U32)) - } - rustc_type_ir::TyKind::Uint(rustc_type_ir::UintTy::U64) => { - TyKind::Scalar(Scalar::Uint(UintTy::U64)) - } - rustc_type_ir::TyKind::Uint(rustc_type_ir::UintTy::U128) => { - TyKind::Scalar(Scalar::Uint(UintTy::U128)) - } - rustc_type_ir::TyKind::Uint(rustc_type_ir::UintTy::Usize) => { - TyKind::Scalar(Scalar::Uint(UintTy::Usize)) - } - rustc_type_ir::TyKind::Float(rustc_type_ir::FloatTy::F16) => { - TyKind::Scalar(Scalar::Float(FloatTy::F16)) - } - rustc_type_ir::TyKind::Float(rustc_type_ir::FloatTy::F32) => { - TyKind::Scalar(Scalar::Float(FloatTy::F32)) - } - rustc_type_ir::TyKind::Float(rustc_type_ir::FloatTy::F64) => { - TyKind::Scalar(Scalar::Float(FloatTy::F64)) - } - rustc_type_ir::TyKind::Float(rustc_type_ir::FloatTy::F128) => { - TyKind::Scalar(Scalar::Float(FloatTy::F128)) - } - rustc_type_ir::TyKind::Str => TyKind::Str, - rustc_type_ir::TyKind::Error(_) => TyKind::Error, - rustc_type_ir::TyKind::Never => TyKind::Never, - - rustc_type_ir::TyKind::Adt(def, args) => { - let adt_id = def.inner().id; - let subst = convert_args_for_result(interner, args.as_slice()); - TyKind::Adt(chalk_ir::AdtId(adt_id), subst) - } - - rustc_type_ir::TyKind::Infer(infer_ty) => { - let (var, kind) = match infer_ty { - rustc_type_ir::InferTy::TyVar(var) => { - (InferenceVar::from(var.as_u32()), TyVariableKind::General) - } - rustc_type_ir::InferTy::IntVar(var) => { - (InferenceVar::from(var.as_u32()), TyVariableKind::Integer) - } - rustc_type_ir::InferTy::FloatVar(var) => { - (InferenceVar::from(var.as_u32()), TyVariableKind::Float) - } - rustc_type_ir::InferTy::FreshFloatTy(..) - | rustc_type_ir::InferTy::FreshIntTy(..) - | rustc_type_ir::InferTy::FreshTy(..) => { - panic!("Freshening shouldn't happen.") - } - }; - TyKind::InferenceVar(var, kind) - } - - rustc_type_ir::TyKind::Ref(r, ty, mutability) => { - let mutability = match mutability { - rustc_ast_ir::Mutability::Mut => chalk_ir::Mutability::Mut, - rustc_ast_ir::Mutability::Not => chalk_ir::Mutability::Not, - }; - let r = convert_region_for_result(interner, r); - let ty = convert_ty_for_result(interner, ty); - TyKind::Ref(mutability, r, ty) - } - - rustc_type_ir::TyKind::Tuple(tys) => { - let size = tys.len(); - let subst = Substitution::from_iter( - Interner, - tys.iter().map(|ty| { - chalk_ir::GenericArgData::Ty(convert_ty_for_result(interner, ty)) - .intern(Interner) - }), - ); - TyKind::Tuple(size, subst) - } - - rustc_type_ir::TyKind::Array(ty, const_) => { - let ty = convert_ty_for_result(interner, ty); - let const_ = convert_const_for_result(interner, const_); - TyKind::Array(ty, const_) - } - - rustc_type_ir::TyKind::Alias(alias_ty_kind, alias_ty) => match alias_ty_kind { - rustc_type_ir::AliasTyKind::Projection => { - let assoc_ty_id = match alias_ty.def_id { - SolverDefId::TypeAliasId(id) => id, - _ => unreachable!(), - }; - let associated_ty_id = to_assoc_type_id(assoc_ty_id); - let substitution = convert_args_for_result(interner, alias_ty.args.as_slice()); - TyKind::Alias(crate::AliasTy::Projection(crate::ProjectionTy { - associated_ty_id, - substitution, - })) - } - rustc_type_ir::AliasTyKind::Opaque => { - let opaque_ty_id = match alias_ty.def_id { - SolverDefId::InternedOpaqueTyId(id) => id, - _ => unreachable!(), - }; - let substitution = convert_args_for_result(interner, alias_ty.args.as_slice()); - TyKind::Alias(chalk_ir::AliasTy::Opaque(chalk_ir::OpaqueTy { - opaque_ty_id: opaque_ty_id.into(), - substitution, - })) - } - rustc_type_ir::AliasTyKind::Inherent => unimplemented!(), - rustc_type_ir::AliasTyKind::Free => unimplemented!(), - }, - - // For `Placeholder`, `Bound` and `Param`, see the comment on the reverse conversion. - rustc_type_ir::TyKind::Placeholder(placeholder) => { - unimplemented!( - "A `rustc_type_ir::TyKind::Placeholder` doesn't have a direct \ - correspondence in Chalk, as it represents a universally instantiated `Bound`.\n\ - It therefore feels safer to leave it panicking, but if you hit this panic \ - feel free to do the same as in `rustc_type_ir::TyKind::Bound` here." - ) - } - rustc_type_ir::TyKind::Bound(debruijn_index, ty) => TyKind::BoundVar(chalk_ir::BoundVar { - debruijn: chalk_ir::DebruijnIndex::new(debruijn_index.as_u32()), - index: ty.var.as_usize(), - }), - rustc_type_ir::TyKind::Param(param) => { - let placeholder = to_placeholder_idx(interner.db, param.id.into(), param.index); - TyKind::Placeholder(placeholder) - } - - rustc_type_ir::TyKind::FnPtr(bound_sig, fn_header) => { - let num_binders = bound_sig.bound_vars().len(); - let sig = chalk_ir::FnSig { - abi: fn_header.abi, - safety: match fn_header.safety { - crate::next_solver::abi::Safety::Safe => chalk_ir::Safety::Safe, - crate::next_solver::abi::Safety::Unsafe => chalk_ir::Safety::Unsafe, - }, - variadic: fn_header.c_variadic, - }; - let args = GenericArgs::new_from_iter( - interner, - bound_sig.skip_binder().inputs_and_output.iter().map(|a| a.into()), - ); - let substitution = convert_args_for_result(interner, args.as_slice()); - let substitution = chalk_ir::FnSubst(substitution); - let fnptr = chalk_ir::FnPointer { num_binders, sig, substitution }; - TyKind::Function(fnptr) - } - - rustc_type_ir::TyKind::Dynamic(preds, region) => { - let self_ty = Ty::new_bound( - interner, - DebruijnIndex::from_u32(1), - BoundTy { kind: BoundTyKind::Anon, var: BoundVar::from_u32(0) }, - ); - let bounds = chalk_ir::QuantifiedWhereClauses::from_iter( - Interner, - preds.iter().map(|p| { - let binders = chalk_ir::VariableKinds::from_iter( - Interner, - p.bound_vars().iter().map(|b| match b { - BoundVarKind::Ty(kind) => { - chalk_ir::VariableKind::Ty(TyVariableKind::General) - } - BoundVarKind::Region(kind) => chalk_ir::VariableKind::Lifetime, - BoundVarKind::Const => { - chalk_ir::VariableKind::Const(crate::TyKind::Error.intern(Interner)) - } - }), - ); - - // Rust and chalk have slightly different - // representation for trait objects. - // - // Chalk uses `for for<'a> T0: Trait<'a>` while rustc - // uses `ExistentialPredicate`s, which do not have a self ty. - // We need to shift escaping bound vars by 1 to accommodate - // the newly introduced `for` binder. - let p = shift_vars(interner, p, 1); - - let where_clause = match p.skip_binder() { - rustc_type_ir::ExistentialPredicate::Trait(trait_ref) => { - let trait_ref = TraitRef::new( - interner, - trait_ref.def_id, - [self_ty.into()].into_iter().chain(trait_ref.args.iter()), - ); - let trait_id = to_chalk_trait_id(trait_ref.def_id.0); - let substitution = - convert_args_for_result(interner, trait_ref.args.as_slice()); - let trait_ref = chalk_ir::TraitRef { trait_id, substitution }; - chalk_ir::WhereClause::Implemented(trait_ref) - } - rustc_type_ir::ExistentialPredicate::AutoTrait(trait_) => { - let trait_id = to_chalk_trait_id(trait_.0); - let substitution = chalk_ir::Substitution::from1( - Interner, - convert_ty_for_result(interner, self_ty), - ); - let trait_ref = chalk_ir::TraitRef { trait_id, substitution }; - chalk_ir::WhereClause::Implemented(trait_ref) - } - rustc_type_ir::ExistentialPredicate::Projection(existential_projection) => { - let projection = ProjectionPredicate { - projection_term: AliasTerm::new( - interner, - existential_projection.def_id, - [self_ty.into()] - .iter() - .chain(existential_projection.args.iter()), - ), - term: existential_projection.term, - }; - let associated_ty_id = match projection.projection_term.def_id { - SolverDefId::TypeAliasId(id) => to_assoc_type_id(id), - _ => unreachable!(), - }; - let substitution = convert_args_for_result( - interner, - projection.projection_term.args.as_slice(), - ); - let alias = chalk_ir::AliasTy::Projection(chalk_ir::ProjectionTy { - associated_ty_id, - substitution, - }); - let ty = match projection.term { - Term::Ty(ty) => ty, - _ => unreachable!(), - }; - let ty = convert_ty_for_result(interner, ty); - let alias_eq = chalk_ir::AliasEq { alias, ty }; - chalk_ir::WhereClause::AliasEq(alias_eq) - } - }; - chalk_ir::Binders::new(binders, where_clause) - }), - ); - let binders = chalk_ir::VariableKinds::from1( - Interner, - chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General), - ); - let bounds = chalk_ir::Binders::new(binders, bounds); - let dyn_ty = - chalk_ir::DynTy { bounds, lifetime: convert_region_for_result(interner, region) }; - TyKind::Dyn(dyn_ty) - } - - rustc_type_ir::TyKind::Slice(ty) => { - let ty = convert_ty_for_result(interner, ty); - TyKind::Slice(ty) - } - - rustc_type_ir::TyKind::Foreign(foreign) => TyKind::Foreign(to_foreign_def_id(foreign.0)), - rustc_type_ir::TyKind::Pat(_, _) => unimplemented!(), - rustc_type_ir::TyKind::RawPtr(ty, mutability) => { - let mutability = match mutability { - rustc_ast_ir::Mutability::Mut => chalk_ir::Mutability::Mut, - rustc_ast_ir::Mutability::Not => chalk_ir::Mutability::Not, - }; - let ty = convert_ty_for_result(interner, ty); - TyKind::Raw(mutability, ty) - } - rustc_type_ir::TyKind::FnDef(def_id, args) => { - let subst = convert_args_for_result(interner, args.as_slice()); - TyKind::FnDef(def_id.0.to_chalk(interner.db()), subst) - } - - rustc_type_ir::TyKind::Closure(def_id, args) => { - let subst = convert_args_for_result(interner, args.as_slice()); - TyKind::Closure(def_id.0.into(), subst) - } - rustc_type_ir::TyKind::CoroutineClosure(_, _) => unimplemented!(), - rustc_type_ir::TyKind::Coroutine(def_id, args) => { - let subst = convert_args_for_result(interner, args.as_slice()); - TyKind::Coroutine(def_id.0.into(), subst) - } - rustc_type_ir::TyKind::CoroutineWitness(def_id, args) => { - let subst = convert_args_for_result(interner, args.as_slice()); - TyKind::CoroutineWitness(def_id.0.into(), subst) - } - - rustc_type_ir::TyKind::UnsafeBinder(_) => unimplemented!(), - } - .intern(Interner) -} - -pub fn convert_const_for_result<'db>( - interner: DbInterner<'db>, - const_: Const<'db>, -) -> crate::Const { - let value: chalk_ir::ConstValue = match const_.kind() { - rustc_type_ir::ConstKind::Infer(rustc_type_ir::InferConst::Var(var)) => { - chalk_ir::ConstValue::InferenceVar(chalk_ir::InferenceVar::from(var.as_u32())) - } - rustc_type_ir::ConstKind::Infer(rustc_type_ir::InferConst::Fresh(fresh)) => { - panic!("Vars should not be freshened.") - } - rustc_type_ir::ConstKind::Param(param) => { - let placeholder = to_placeholder_idx(interner.db, param.id.into(), param.index); - chalk_ir::ConstValue::Placeholder(placeholder) - } - rustc_type_ir::ConstKind::Bound(debruijn_index, var) => { - chalk_ir::ConstValue::BoundVar(chalk_ir::BoundVar::new( - chalk_ir::DebruijnIndex::new(debruijn_index.as_u32()), - var.var.index(), - )) - } - rustc_type_ir::ConstKind::Placeholder(placeholder_const) => { - unimplemented!( - "A `rustc_type_ir::ConstKind::Placeholder` doesn't have a direct \ - correspondence in Chalk, as it represents a universally instantiated `Bound`.\n\ - It therefore feels safer to leave it panicking, but if you hit this panic \ - feel free to do the same as in `rustc_type_ir::ConstKind::Bound` here." - ) - } - rustc_type_ir::ConstKind::Unevaluated(unevaluated_const) => { - let id = match unevaluated_const.def { - SolverDefId::ConstId(id) => GeneralConstId::ConstId(id), - SolverDefId::StaticId(id) => GeneralConstId::StaticId(id), - _ => unreachable!(), - }; - let subst = convert_args_for_result(interner, unevaluated_const.args.as_slice()); - chalk_ir::ConstValue::Concrete(chalk_ir::ConcreteConst { - interned: ConstScalar::UnevaluatedConst(id, subst), - }) - } - rustc_type_ir::ConstKind::Value(value_const) => { - let bytes = value_const.value.inner(); - let value = chalk_ir::ConstValue::Concrete(chalk_ir::ConcreteConst { - // SAFETY: we will never actually use this without a database - interned: ConstScalar::Bytes(bytes.memory.clone(), unsafe { - std::mem::transmute::, MemoryMap<'static>>( - bytes.memory_map.clone(), - ) - }), - }); - return chalk_ir::ConstData { - ty: convert_ty_for_result(interner, value_const.ty), - value, - } - .intern(Interner); - } - rustc_type_ir::ConstKind::Error(_) => { - chalk_ir::ConstValue::Concrete(chalk_ir::ConcreteConst { - interned: ConstScalar::Unknown, - }) - } - rustc_type_ir::ConstKind::Expr(_) => unimplemented!(), - }; - chalk_ir::ConstData { ty: crate::TyKind::Error.intern(Interner), value }.intern(Interner) -} - -pub fn convert_region_for_result<'db>( - interner: DbInterner<'db>, - region: Region<'db>, -) -> crate::Lifetime { - let lifetime = match region.kind() { - rustc_type_ir::RegionKind::ReEarlyParam(early) => { - let placeholder = lt_to_placeholder_idx(interner.db, early.id, early.index); - chalk_ir::LifetimeData::Placeholder(placeholder) - } - rustc_type_ir::RegionKind::ReBound(db, bound) => { - chalk_ir::LifetimeData::BoundVar(chalk_ir::BoundVar::new( - chalk_ir::DebruijnIndex::new(db.as_u32()), - bound.var.as_usize(), - )) - } - rustc_type_ir::RegionKind::RePlaceholder(placeholder) => unimplemented!( - "A `rustc_type_ir::RegionKind::RePlaceholder` doesn't have a direct \ - correspondence in Chalk, as it represents a universally instantiated `Bound`.\n\ - It therefore feels safer to leave it panicking, but if you hit this panic \ - feel free to do the same as in `rustc_type_ir::RegionKind::ReBound` here." - ), - rustc_type_ir::RegionKind::ReLateParam(_) => unimplemented!(), - rustc_type_ir::RegionKind::ReStatic => chalk_ir::LifetimeData::Static, - rustc_type_ir::RegionKind::ReVar(vid) => { - chalk_ir::LifetimeData::InferenceVar(chalk_ir::InferenceVar::from(vid.as_u32())) - } - rustc_type_ir::RegionKind::ReErased => chalk_ir::LifetimeData::Erased, - rustc_type_ir::RegionKind::ReError(_) => chalk_ir::LifetimeData::Error, - }; - chalk_ir::Lifetime::new(Interner, lifetime) -} - -pub trait InferenceVarExt { - fn to_vid(self) -> rustc_type_ir::TyVid; - fn from_vid(vid: rustc_type_ir::TyVid) -> InferenceVar; -} - -impl InferenceVarExt for InferenceVar { - fn to_vid(self) -> rustc_type_ir::TyVid { - rustc_type_ir::TyVid::from_u32(self.index()) - } - fn from_vid(vid: rustc_type_ir::TyVid) -> InferenceVar { - InferenceVar::from(vid.as_u32()) - } -} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/normalize.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/normalize.rs index 2f241f8fecbe..bd678b3e78ff 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/normalize.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/normalize.rs @@ -5,7 +5,6 @@ use rustc_type_ir::{ inherent::{IntoKind, Term as _}, }; -use crate::next_solver::SolverDefId; use crate::next_solver::{ Binder, Const, ConstKind, DbInterner, Goal, ParamEnv, Predicate, PredicateKind, Term, Ty, TyKind, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/obligation_ctxt.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/obligation_ctxt.rs index e85574a8826f..ae92aea85527 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/obligation_ctxt.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/obligation_ctxt.rs @@ -1,14 +1,15 @@ use hir_def::TraitId; -use rustc_type_ir::relate::Relate; use rustc_type_ir::{TypeFoldable, Upcast, Variance}; -use crate::next_solver::fulfill::{FulfillmentCtxt, NextSolverError}; -use crate::next_solver::infer::at::ToTrace; -use crate::next_solver::infer::traits::{ - Obligation, ObligationCause, PredicateObligation, PredicateObligations, +use crate::next_solver::{ + Const, DbInterner, ParamEnv, Term, TraitRef, Ty, TypeError, + fulfill::{FulfillmentCtxt, NextSolverError}, + infer::{ + InferCtxt, InferOk, + at::ToTrace, + traits::{Obligation, ObligationCause, PredicateObligation, PredicateObligations}, + }, }; -use crate::next_solver::infer::{DefineOpaqueTypes, InferCtxt, InferOk, TypeTrace}; -use crate::next_solver::{Const, DbInterner, ParamEnv, Term, TraitRef, Ty, TypeError}; /// Used if you want to have pleasant experience when dealing /// with obligations outside of hir or mir typeck. @@ -69,21 +70,7 @@ impl<'a, 'db> ObligationCtxt<'a, 'db> { ) -> Result<(), TypeError<'db>> { self.infcx .at(cause, param_env) - .eq(DefineOpaqueTypes::Yes, expected, actual) - .map(|infer_ok| self.register_infer_ok_obligations(infer_ok)) - } - - pub fn eq_trace>>( - &mut self, - cause: &ObligationCause, - param_env: ParamEnv<'db>, - trace: TypeTrace<'db>, - expected: T, - actual: T, - ) -> Result<(), TypeError<'db>> { - self.infcx - .at(cause, param_env) - .eq_trace(DefineOpaqueTypes::Yes, trace, expected, actual) + .eq(expected, actual) .map(|infer_ok| self.register_infer_ok_obligations(infer_ok)) } @@ -97,7 +84,7 @@ impl<'a, 'db> ObligationCtxt<'a, 'db> { ) -> Result<(), TypeError<'db>> { self.infcx .at(cause, param_env) - .sub(DefineOpaqueTypes::Yes, expected, actual) + .sub(expected, actual) .map(|infer_ok| self.register_infer_ok_obligations(infer_ok)) } @@ -111,7 +98,7 @@ impl<'a, 'db> ObligationCtxt<'a, 'db> { ) -> Result<(), TypeError<'db>> { self.infcx .at(cause, param_env) - .relate(DefineOpaqueTypes::Yes, expected, variance, actual) + .relate(expected, variance, actual) .map(|infer_ok| self.register_infer_ok_obligations(infer_ok)) } @@ -125,7 +112,7 @@ impl<'a, 'db> ObligationCtxt<'a, 'db> { ) -> Result<(), TypeError<'db>> { self.infcx .at(cause, param_env) - .sup(DefineOpaqueTypes::Yes, expected, actual) + .sup(expected, actual) .map(|infer_ok| self.register_infer_ok_obligations(infer_ok)) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/opaques.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/opaques.rs index 0aee779ed04f..e8f5be2eb598 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/opaques.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/opaques.rs @@ -1,86 +1,18 @@ //! Things related to opaques in the next-trait-solver. -use intern::Interned; use rustc_ast_ir::try_visit; +use rustc_type_ir::inherent::SliceLike; -use crate::next_solver::SolverDefId; - -use super::{CanonicalVarKind, DbInterner, interned_vec_nolifetime_salsa}; +use super::{DbInterner, SolverDefId, Ty, interned_vec_db, interned_vec_nolifetime_salsa}; pub type OpaqueTypeKey<'db> = rustc_type_ir::OpaqueTypeKey>; -pub type PredefinedOpaquesData<'db> = rustc_type_ir::solve::PredefinedOpaquesData>; + +type PredefinedOpaque<'db> = (OpaqueTypeKey<'db>, Ty<'db>); +interned_vec_db!(PredefinedOpaques, PredefinedOpaque); + pub type ExternalConstraintsData<'db> = rustc_type_ir::solve::ExternalConstraintsData>; -#[salsa::interned(constructor = new_, debug)] -pub struct PredefinedOpaques<'db> { - #[returns(ref)] - kind_: rustc_type_ir::solve::PredefinedOpaquesData>, -} - -impl<'db> PredefinedOpaques<'db> { - pub fn new(interner: DbInterner<'db>, data: PredefinedOpaquesData<'db>) -> Self { - PredefinedOpaques::new_(interner.db(), data) - } - - pub fn inner(&self) -> &PredefinedOpaquesData<'db> { - crate::with_attached_db(|db| { - let inner = self.kind_(db); - // SAFETY: ¯\_(ツ)_/¯ - unsafe { std::mem::transmute(inner) } - }) - } -} - -impl<'db> rustc_type_ir::TypeVisitable> for PredefinedOpaques<'db> { - fn visit_with>>( - &self, - visitor: &mut V, - ) -> V::Result { - self.opaque_types.visit_with(visitor) - } -} - -impl<'db> rustc_type_ir::TypeFoldable> for PredefinedOpaques<'db> { - fn try_fold_with>>( - self, - folder: &mut F, - ) -> Result { - Ok(PredefinedOpaques::new( - folder.cx(), - PredefinedOpaquesData { - opaque_types: self - .opaque_types - .iter() - .cloned() - .map(|opaque| opaque.try_fold_with(folder)) - .collect::>()?, - }, - )) - } - fn fold_with>>(self, folder: &mut F) -> Self { - PredefinedOpaques::new( - folder.cx(), - PredefinedOpaquesData { - opaque_types: self - .opaque_types - .iter() - .cloned() - .map(|opaque| opaque.fold_with(folder)) - .collect(), - }, - ) - } -} - -impl<'db> std::ops::Deref for PredefinedOpaques<'db> { - type Target = PredefinedOpaquesData<'db>; - - fn deref(&self) -> &Self::Target { - self.inner() - } -} - interned_vec_nolifetime_salsa!(SolverDefIds, SolverDefId); #[salsa::interned(constructor = new_, debug)] diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/predicate.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/predicate.rs index 9dda9d06da27..3438b755fb9e 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/predicate.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/predicate.rs @@ -2,21 +2,18 @@ use std::cmp::Ordering; -use intern::Interned; use macros::{TypeFoldable, TypeVisitable}; -use rustc_ast_ir::try_visit; use rustc_type_ir::{ self as ty, CollectAndApply, DebruijnIndex, EarlyBinder, FlagComputation, Flags, PredicatePolarity, TypeFlags, TypeFoldable, TypeSuperFoldable, TypeSuperVisitable, - TypeVisitable, Upcast, UpcastFrom, VisitorResult, WithCachedTypeInfo, + TypeVisitable, Upcast, UpcastFrom, WithCachedTypeInfo, elaborate::Elaboratable, error::{ExpectedFound, TypeError}, inherent::{IntoKind, SliceLike}, - relate::Relate, }; -use smallvec::{SmallVec, smallvec}; +use smallvec::SmallVec; -use crate::next_solver::TraitIdWrapper; +use crate::next_solver::{InternedWrapperNoDebug, TraitIdWrapper}; use super::{Binder, BoundVarKinds, DbInterner, Region, Ty, interned_vec_db}; @@ -56,11 +53,11 @@ fn stable_cmp_existential_predicate<'db>( // FIXME: this is actual unstable - see impl in predicate.rs in `rustc_middle` match (a, b) { (ExistentialPredicate::Trait(_), ExistentialPredicate::Trait(_)) => Ordering::Equal, - (ExistentialPredicate::Projection(a), ExistentialPredicate::Projection(b)) => { + (ExistentialPredicate::Projection(_a), ExistentialPredicate::Projection(_b)) => { // Should sort by def path hash Ordering::Equal } - (ExistentialPredicate::AutoTrait(a), ExistentialPredicate::AutoTrait(b)) => { + (ExistentialPredicate::AutoTrait(_a), ExistentialPredicate::AutoTrait(_b)) => { // Should sort by def path hash Ordering::Equal } @@ -174,9 +171,6 @@ impl<'db> rustc_type_ir::relate::Relate> for BoundExistentialPre } } -#[derive(PartialEq, Eq, Hash, PartialOrd, Ord, Clone)] -pub struct InternedWrapperNoDebug(pub(crate) T); - #[salsa::interned(constructor = new_)] pub struct Predicate<'db> { #[returns(ref)] @@ -283,8 +277,6 @@ impl<'db> std::hash::Hash for InternedClausesWrapper<'db> { } } -type InternedClauses<'db> = Interned>; - #[salsa::interned(constructor = new_)] pub struct Clauses<'db> { #[returns(ref)] @@ -647,6 +639,26 @@ impl<'db> UpcastFrom, ty::OutlivesPredicate, Reg PredicateKind::Clause(ClauseKind::RegionOutlives(from)).upcast(interner) } } +impl<'db> UpcastFrom, ty::OutlivesPredicate, Ty<'db>>> + for Clause<'db> +{ + fn upcast_from( + from: ty::OutlivesPredicate, Ty<'db>>, + interner: DbInterner<'db>, + ) -> Self { + Clause(from.upcast(interner)) + } +} +impl<'db> UpcastFrom, ty::OutlivesPredicate, Region<'db>>> + for Clause<'db> +{ + fn upcast_from( + from: ty::OutlivesPredicate, Region<'db>>, + interner: DbInterner<'db>, + ) -> Self { + Clause(from.upcast(interner)) + } +} impl<'db> UpcastFrom, PolyRegionOutlivesPredicate<'db>> for Predicate<'db> { fn upcast_from(from: PolyRegionOutlivesPredicate<'db>, tcx: DbInterner<'db>) -> Self { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/region.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/region.rs index 5e7eb7532bb0..b5f0e6de2910 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/region.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/region.rs @@ -1,10 +1,10 @@ //! Things related to regions. use hir_def::LifetimeParamId; -use intern::{Interned, Symbol}; +use intern::Symbol; use rustc_type_ir::{ - BoundVar, DebruijnIndex, Flags, INNERMOST, RegionVid, TypeFlags, TypeFoldable, TypeVisitable, - VisitorResult, + BoundVar, BoundVarIndexKind, DebruijnIndex, Flags, INNERMOST, RegionVid, TypeFlags, + TypeFoldable, TypeVisitable, inherent::{IntoKind, PlaceholderLike, SliceLike}, relate::Relate, }; @@ -68,7 +68,7 @@ impl<'db> Region<'db> { index: DebruijnIndex, bound: BoundRegion, ) -> Region<'db> { - Region::new(interner, RegionKind::ReBound(index, bound)) + Region::new(interner, RegionKind::ReBound(BoundVarIndexKind::Bound(index), bound)) } pub fn is_placeholder(&self) -> bool { @@ -117,7 +117,11 @@ impl<'db> Region<'db> { RegionKind::ReStatic => { flags |= TypeFlags::HAS_FREE_REGIONS; } - RegionKind::ReBound(..) => { + RegionKind::ReBound(BoundVarIndexKind::Canonical, ..) => { + flags |= TypeFlags::HAS_RE_BOUND; + flags |= TypeFlags::HAS_CANONICAL_BOUND; + } + RegionKind::ReBound(BoundVarIndexKind::Bound(..), ..) => { flags |= TypeFlags::HAS_RE_BOUND; } RegionKind::ReErased => { @@ -294,7 +298,7 @@ impl<'db> Flags for Region<'db> { fn outer_exclusive_binder(&self) -> rustc_type_ir::DebruijnIndex { match &self.inner() { - RegionKind::ReBound(debruijn, _) => debruijn.shifted_in(1), + RegionKind::ReBound(BoundVarIndexKind::Bound(debruijn), _) => debruijn.shifted_in(1), _ => INNERMOST, } } @@ -306,7 +310,7 @@ impl<'db> rustc_type_ir::inherent::Region> for Region<'db> { debruijn: rustc_type_ir::DebruijnIndex, var: BoundRegion, ) -> Self { - Region::new(interner, RegionKind::ReBound(debruijn, var)) + Region::new(interner, RegionKind::ReBound(BoundVarIndexKind::Bound(debruijn), var)) } fn new_anon_bound( @@ -316,7 +320,20 @@ impl<'db> rustc_type_ir::inherent::Region> for Region<'db> { ) -> Self { Region::new( interner, - RegionKind::ReBound(debruijn, BoundRegion { var, kind: BoundRegionKind::Anon }), + RegionKind::ReBound( + BoundVarIndexKind::Bound(debruijn), + BoundRegion { var, kind: BoundRegionKind::Anon }, + ), + ) + } + + fn new_canonical_bound(interner: DbInterner<'db>, var: rustc_type_ir::BoundVar) -> Self { + Region::new( + interner, + RegionKind::ReBound( + BoundVarIndexKind::Canonical, + BoundRegion { var, kind: BoundRegionKind::Anon }, + ), ) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/solver.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/solver.rs index 2457447ee39b..487d164f8691 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/solver.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/solver.rs @@ -1,29 +1,22 @@ //! Defining `SolverContext` for next-trait-solver. -use hir_def::{AssocItemId, GeneralConstId, TypeAliasId}; +use hir_def::{AssocItemId, GeneralConstId}; use rustc_next_trait_solver::delegate::SolverDelegate; use rustc_type_ir::GenericArgKind; use rustc_type_ir::lang_items::SolverTraitLangItem; use rustc_type_ir::{ - InferCtxtLike, Interner, PredicatePolarity, TypeFlags, TypeVisitableExt, UniverseIndex, - inherent::{IntoKind, SliceLike, Span as _, Term as _, Ty as _}, + InferCtxtLike, Interner, PredicatePolarity, TypeFlags, TypeVisitableExt, + inherent::{IntoKind, Term as _, Ty as _}, solve::{Certainty, NoSolution}, }; -use crate::next_solver::mapping::NextSolverToChalk; use crate::next_solver::{CanonicalVarKind, ImplIdWrapper}; -use crate::{ - TraitRefExt, - db::HirDatabase, - next_solver::{ - ClauseKind, CoercePredicate, PredicateKind, SubtypePredicate, mapping::ChalkToNextSolver, - util::sizedness_fast_path, - }, +use crate::next_solver::{ + ClauseKind, CoercePredicate, PredicateKind, SubtypePredicate, util::sizedness_fast_path, }; use super::{ - Canonical, CanonicalVarValues, Const, DbInterner, ErrorGuaranteed, GenericArg, GenericArgs, - ParamEnv, Predicate, SolverDefId, Span, Ty, UnevaluatedConst, + DbInterner, ErrorGuaranteed, GenericArg, SolverDefId, Span, infer::{DbInternerInferExt, InferCtxt, canonical::instantiate::CanonicalExt}, }; @@ -66,7 +59,7 @@ impl<'db> SolverDelegate for SolverContext<'db> { (SolverContext(infcx), value, vars) } - fn fresh_var_for_kind_with_span(&self, arg: GenericArg<'db>, span: Span) -> GenericArg<'db> { + fn fresh_var_for_kind_with_span(&self, arg: GenericArg<'db>, _span: Span) -> GenericArg<'db> { match arg.kind() { GenericArgKind::Lifetime(_) => self.next_region_var().into(), GenericArgKind::Type(_) => self.next_ty_var().into(), @@ -76,15 +69,15 @@ impl<'db> SolverDelegate for SolverContext<'db> { fn leak_check( &self, - max_input_universe: rustc_type_ir::UniverseIndex, + _max_input_universe: rustc_type_ir::UniverseIndex, ) -> Result<(), NoSolution> { Ok(()) } fn well_formed_goals( &self, - param_env: ::ParamEnv, - arg: ::Term, + _param_env: ::ParamEnv, + _arg: ::Term, ) -> Option< Vec< rustc_type_ir::solve::Goal< @@ -123,7 +116,7 @@ impl<'db> SolverDelegate for SolverContext<'db> { fn instantiate_canonical_var( &self, kind: CanonicalVarKind<'db>, - span: ::Span, + _span: ::Span, var_values: &[GenericArg<'db>], universe_map: impl Fn(rustc_type_ir::UniverseIndex) -> rustc_type_ir::UniverseIndex, ) -> GenericArg<'db> { @@ -132,11 +125,11 @@ impl<'db> SolverDelegate for SolverContext<'db> { fn add_item_bounds_for_hidden_type( &self, - def_id: ::DefId, - args: ::GenericArgs, - param_env: ::ParamEnv, - hidden_ty: ::Ty, - goals: &mut Vec< + _def_id: ::DefId, + _args: ::GenericArgs, + _param_env: ::ParamEnv, + _hidden_ty: ::Ty, + _goals: &mut Vec< rustc_type_ir::solve::Goal< Self::Interner, ::Predicate, @@ -148,21 +141,10 @@ impl<'db> SolverDelegate for SolverContext<'db> { fn fetch_eligible_assoc_item( &self, - goal_trait_ref: rustc_type_ir::TraitRef, + _goal_trait_ref: rustc_type_ir::TraitRef, trait_assoc_def_id: SolverDefId, impl_id: ImplIdWrapper, ) -> Result, ErrorGuaranteed> { - let trait_ = self - .0 - .interner - .db() - .impl_trait(impl_id.0) - // ImplIds for impls where the trait ref can't be resolved should never reach solver - .expect("invalid impl passed to next-solver") - .skip_binder() - .def_id - .0; - let trait_data = trait_.trait_items(self.0.interner.db()); let impl_items = impl_id.0.impl_items(self.0.interner.db()); let id = match trait_assoc_def_id { SolverDefId::TypeAliasId(trait_assoc_id) => { @@ -208,16 +190,16 @@ impl<'db> SolverDelegate for SolverContext<'db> { fn is_transmutable( &self, - dst: ::Ty, - src: ::Ty, - assume: ::Const, + _dst: ::Ty, + _src: ::Ty, + _assume: ::Const, ) -> Result { unimplemented!() } fn evaluate_const( &self, - param_env: ::ParamEnv, + _param_env: ::ParamEnv, uv: rustc_type_ir::UnevaluatedConst, ) -> Option<::Const> { let c = match uv.def { @@ -236,7 +218,7 @@ impl<'db> SolverDelegate for SolverContext<'db> { Self::Interner, ::Predicate, >, - span: ::Span, + _span: ::Span, ) -> Option { if let Some(trait_pred) = goal.predicate.as_trait_clause() { if self.shallow_resolve(trait_pred.self_ty().skip_binder()).is_ty_var() @@ -279,8 +261,8 @@ impl<'db> SolverDelegate for SolverContext<'db> { let pred = goal.predicate.kind(); match pred.no_bound_vars()? { - PredicateKind::Clause(ClauseKind::RegionOutlives(outlives)) => Some(Certainty::Yes), - PredicateKind::Clause(ClauseKind::TypeOutlives(outlives)) => Some(Certainty::Yes), + PredicateKind::Clause(ClauseKind::RegionOutlives(_outlives)) => Some(Certainty::Yes), + PredicateKind::Clause(ClauseKind::TypeOutlives(_outlives)) => Some(Certainty::Yes), PredicateKind::Subtype(SubtypePredicate { a, b, .. }) | PredicateKind::Coerce(CoercePredicate { a, b }) => { if self.shallow_resolve(a).is_ty_var() && self.shallow_resolve(b).is_ty_var() { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ty.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ty.rs index 44b85abba0ef..b8406fecda31 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ty.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ty.rs @@ -1,41 +1,37 @@ //! Things related to tys in the next-trait-solver. -use std::iter; use std::ops::ControlFlow; use hir_def::{ - AdtId, DefWithBodyId, GenericDefId, HasModule, TypeOrConstParamId, TypeParamId, + AdtId, HasModule, TypeParamId, hir::generics::{TypeOrConstParamData, TypeParamProvenance}, lang_item::LangItem, }; use hir_def::{TraitId, type_ref::Rawness}; -use intern::{Interned, Symbol, sym}; use rustc_abi::{Float, Integer, Size}; use rustc_ast_ir::{Mutability, try_visit, visit::VisitorResult}; use rustc_type_ir::{ - AliasTyKind, BoundVar, ClosureKind, CollectAndApply, FlagComputation, Flags, FloatTy, FloatVid, - InferTy, IntTy, IntVid, Interner, TyVid, TypeFoldable, TypeSuperFoldable, TypeSuperVisitable, - TypeVisitable, TypeVisitableExt, TypeVisitor, UintTy, Upcast, WithCachedTypeInfo, + AliasTyKind, BoundVar, BoundVarIndexKind, ClosureKind, CoroutineArgs, CoroutineArgsParts, + DebruijnIndex, FlagComputation, Flags, FloatTy, FloatVid, InferTy, IntTy, IntVid, Interner, + TyVid, TypeFoldable, TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, + TypeVisitor, UintTy, Upcast, WithCachedTypeInfo, inherent::{ - Abi, AdtDef as _, BoundExistentialPredicates, BoundVarLike, Const as _, GenericArgs as _, + AdtDef as _, BoundExistentialPredicates, BoundVarLike, Const as _, GenericArgs as _, IntoKind, ParamLike, PlaceholderLike, Safety as _, SliceLike, Ty as _, }, relate::Relate, solve::SizedTraitKind, walk::TypeWalker, }; -use salsa::plumbing::{AsId, FromId}; -use smallvec::SmallVec; use crate::{ - FnAbi, ImplTraitId, - db::HirDatabase, - interner::InternedWrapperNoDebug, + ImplTraitId, + db::{HirDatabase, InternedCoroutine}, next_solver::{ - AdtDef, Binder, CallableIdWrapper, Clause, ClauseKind, ClosureIdWrapper, Const, + AdtDef, AliasTy, Binder, CallableIdWrapper, Clause, ClauseKind, ClosureIdWrapper, Const, CoroutineIdWrapper, FnSig, GenericArg, PolyFnSig, Region, TraitRef, TypeAliasIdWrapper, abi::Safety, - mapping::ChalkToNextSolver, + interner::InternedWrapperNoDebug, util::{CoroutineArgsExt, IntegerTypeExt}, }, }; @@ -83,7 +79,7 @@ impl<'db> Ty<'db> { Ty::new(interner, TyKind::Adt(AdtDef::new(adt_id, interner), args)) } - pub fn new_param(interner: DbInterner<'db>, id: TypeParamId, index: u32, name: Symbol) -> Self { + pub fn new_param(interner: DbInterner<'db>, id: TypeParamId, index: u32) -> Self { Ty::new(interner, TyKind::Param(ParamTy { id, index })) } @@ -404,10 +400,44 @@ impl<'db> Ty<'db> { Some(interner.fn_sig(callable).instantiate(interner, args)) } TyKind::FnPtr(sig, hdr) => Some(sig.with(hdr)), - TyKind::Closure(closure_id, closure_args) => closure_args + TyKind::Closure(_, closure_args) => closure_args .split_closure_args_untupled() .closure_sig_as_fn_ptr_ty .callable_sig(interner), + TyKind::CoroutineClosure(coroutine_id, args) => { + Some(args.as_coroutine_closure().coroutine_closure_sig().map_bound(|sig| { + let unit_ty = Ty::new_unit(interner); + let return_ty = Ty::new_coroutine( + interner, + coroutine_id, + CoroutineArgs::new( + interner, + CoroutineArgsParts { + parent_args: args.as_coroutine_closure().parent_args(), + kind_ty: unit_ty, + resume_ty: unit_ty, + yield_ty: unit_ty, + return_ty: sig.return_ty, + // FIXME: Deduce this from the coroutine closure's upvars. + tupled_upvars_ty: unit_ty, + }, + ) + .args, + ); + FnSig { + inputs_and_output: Tys::new_from_iter( + interner, + sig.tupled_inputs_ty + .tuple_fields() + .iter() + .chain(std::iter::once(return_ty)), + ), + c_variadic: sig.c_variadic, + safety: sig.safety, + abi: sig.abi, + } + })) + } _ => None, } } @@ -535,40 +565,21 @@ impl<'db> Ty<'db> { TyKind::Alias(AliasTyKind::Opaque, opaque_ty) => { match db.lookup_intern_impl_trait_id(opaque_ty.def_id.expect_opaque_ty()) { ImplTraitId::ReturnTypeImplTrait(func, idx) => { - db.return_type_impl_traits_ns(func).map(|it| { - let data = (*it).as_ref().map_bound(|rpit| { - &rpit.impl_traits[idx.to_nextsolver(interner)].predicates - }); + db.return_type_impl_traits(func).map(|it| { + let data = + (*it).as_ref().map_bound(|rpit| &rpit.impl_traits[idx].predicates); data.iter_instantiated_copied(interner, opaque_ty.args.as_slice()) .collect() }) } ImplTraitId::TypeAliasImplTrait(alias, idx) => { - db.type_alias_impl_traits_ns(alias).map(|it| { - let data = (*it).as_ref().map_bound(|rpit| { - &rpit.impl_traits[idx.to_nextsolver(interner)].predicates - }); + db.type_alias_impl_traits(alias).map(|it| { + let data = + (*it).as_ref().map_bound(|rpit| &rpit.impl_traits[idx].predicates); data.iter_instantiated_copied(interner, opaque_ty.args.as_slice()) .collect() }) } - ImplTraitId::AsyncBlockTypeImplTrait(def, _) => { - let krate = def.module(db).krate(); - if let Some(future_trait) = LangItem::Future.resolve_trait(db, krate) { - // This is only used by type walking. - // Parameters will be walked outside, and projection predicate is not used. - // So just provide the Future trait. - let impl_bound = TraitRef::new( - interner, - future_trait.into(), - GenericArgs::new_from_iter(interner, []), - ) - .upcast(interner); - Some(vec![impl_bound]) - } else { - None - } - } } } TyKind::Param(param) => { @@ -579,7 +590,7 @@ impl<'db> Ty<'db> { TypeOrConstParamData::TypeParamData(p) => match p.provenance { TypeParamProvenance::ArgumentImplTrait => { let predicates = db - .generic_predicates_ns(param.id.parent()) + .generic_predicates(param.id.parent()) .instantiate_identity() .into_iter() .flatten() @@ -598,6 +609,24 @@ impl<'db> Ty<'db> { _ => None, } } + TyKind::Coroutine(coroutine_id, _args) => { + let InternedCoroutine(owner, _) = coroutine_id.0.loc(db); + let krate = owner.module(db).krate(); + if let Some(future_trait) = LangItem::Future.resolve_trait(db, krate) { + // This is only used by type walking. + // Parameters will be walked outside, and projection predicate is not used. + // So just provide the Future trait. + let impl_bound = TraitRef::new( + interner, + future_trait.into(), + GenericArgs::new_from_iter(interner, []), + ) + .upcast(interner); + Some(vec![impl_bound]) + } else { + None + } + } _ => None, } } @@ -899,27 +928,28 @@ impl<'db> rustc_type_ir::inherent::Ty> for Ty<'db> { Ty::new(interner, TyKind::Placeholder(param)) } - fn new_bound( - interner: DbInterner<'db>, - debruijn: rustc_type_ir::DebruijnIndex, - var: BoundTy, - ) -> Self { - Ty::new(interner, TyKind::Bound(debruijn, var)) + fn new_bound(interner: DbInterner<'db>, debruijn: DebruijnIndex, var: BoundTy) -> Self { + Ty::new(interner, TyKind::Bound(BoundVarIndexKind::Bound(debruijn), var)) } - fn new_anon_bound( - interner: DbInterner<'db>, - debruijn: rustc_type_ir::DebruijnIndex, - var: BoundVar, - ) -> Self { - Ty::new(interner, TyKind::Bound(debruijn, BoundTy { var, kind: BoundTyKind::Anon })) + fn new_anon_bound(interner: DbInterner<'db>, debruijn: DebruijnIndex, var: BoundVar) -> Self { + Ty::new( + interner, + TyKind::Bound( + BoundVarIndexKind::Bound(debruijn), + BoundTy { var, kind: BoundTyKind::Anon }, + ), + ) } - fn new_alias( - interner: DbInterner<'db>, - kind: rustc_type_ir::AliasTyKind, - alias_ty: rustc_type_ir::AliasTy>, - ) -> Self { + fn new_canonical_bound(interner: DbInterner<'db>, var: BoundVar) -> Self { + Ty::new( + interner, + TyKind::Bound(BoundVarIndexKind::Canonical, BoundTy { var, kind: BoundTyKind::Anon }), + ) + } + + fn new_alias(interner: DbInterner<'db>, kind: AliasTyKind, alias_ty: AliasTy<'db>) -> Self { Ty::new(interner, TyKind::Alias(kind, alias_ty)) } @@ -929,7 +959,7 @@ impl<'db> rustc_type_ir::inherent::Ty> for Ty<'db> { fn new_adt( interner: DbInterner<'db>, - adt_def: as rustc_type_ir::Interner>::AdtDef, + adt_def: as Interner>::AdtDef, args: GenericArgs<'db>, ) -> Self { Ty::new(interner, TyKind::Adt(adt_def, args)) @@ -941,8 +971,8 @@ impl<'db> rustc_type_ir::inherent::Ty> for Ty<'db> { fn new_dynamic( interner: DbInterner<'db>, - preds: as rustc_type_ir::Interner>::BoundExistentialPredicates, - region: as rustc_type_ir::Interner>::Region, + preds: as Interner>::BoundExistentialPredicates, + region: as Interner>::Region, ) -> Self { Ty::new(interner, TyKind::Dynamic(preds, region)) } @@ -950,7 +980,7 @@ impl<'db> rustc_type_ir::inherent::Ty> for Ty<'db> { fn new_coroutine( interner: DbInterner<'db>, def_id: CoroutineIdWrapper, - args: as rustc_type_ir::Interner>::GenericArgs, + args: as Interner>::GenericArgs, ) -> Self { Ty::new(interner, TyKind::Coroutine(def_id, args)) } @@ -958,7 +988,7 @@ impl<'db> rustc_type_ir::inherent::Ty> for Ty<'db> { fn new_coroutine_closure( interner: DbInterner<'db>, def_id: CoroutineIdWrapper, - args: as rustc_type_ir::Interner>::GenericArgs, + args: as Interner>::GenericArgs, ) -> Self { Ty::new(interner, TyKind::CoroutineClosure(def_id, args)) } @@ -966,7 +996,7 @@ impl<'db> rustc_type_ir::inherent::Ty> for Ty<'db> { fn new_closure( interner: DbInterner<'db>, def_id: ClosureIdWrapper, - args: as rustc_type_ir::Interner>::GenericArgs, + args: as Interner>::GenericArgs, ) -> Self { Ty::new(interner, TyKind::Closure(def_id, args)) } @@ -974,7 +1004,7 @@ impl<'db> rustc_type_ir::inherent::Ty> for Ty<'db> { fn new_coroutine_witness( interner: DbInterner<'db>, def_id: CoroutineIdWrapper, - args: as rustc_type_ir::Interner>::GenericArgs, + args: as Interner>::GenericArgs, ) -> Self { Ty::new(interner, TyKind::CoroutineWitness(def_id, args)) } @@ -982,7 +1012,7 @@ impl<'db> rustc_type_ir::inherent::Ty> for Ty<'db> { fn new_coroutine_witness_for_coroutine( interner: DbInterner<'db>, def_id: CoroutineIdWrapper, - coroutine_args: as rustc_type_ir::Interner>::GenericArgs, + coroutine_args: as Interner>::GenericArgs, ) -> Self { // HACK: Coroutine witness types are lifetime erased, so they // never reference any lifetime args from the coroutine. We erase @@ -1010,7 +1040,7 @@ impl<'db> rustc_type_ir::inherent::Ty> for Ty<'db> { fn new_ref( interner: DbInterner<'db>, - region: as rustc_type_ir::Interner>::Region, + region: as Interner>::Region, ty: Self, mutbl: rustc_ast_ir::Mutability, ) -> Self { @@ -1020,7 +1050,7 @@ impl<'db> rustc_type_ir::inherent::Ty> for Ty<'db> { fn new_array_with_const_len( interner: DbInterner<'db>, ty: Self, - len: as rustc_type_ir::Interner>::Const, + len: as Interner>::Const, ) -> Self { Ty::new(interner, TyKind::Array(ty, len)) } @@ -1029,10 +1059,7 @@ impl<'db> rustc_type_ir::inherent::Ty> for Ty<'db> { Ty::new(interner, TyKind::Slice(ty)) } - fn new_tup( - interner: DbInterner<'db>, - tys: &[ as rustc_type_ir::Interner>::Ty], - ) -> Self { + fn new_tup(interner: DbInterner<'db>, tys: &[ as Interner>::Ty]) -> Self { Ty::new(interner, TyKind::Tuple(Tys::new_from_iter(interner, tys.iter().cloned()))) } @@ -1047,7 +1074,7 @@ impl<'db> rustc_type_ir::inherent::Ty> for Ty<'db> { fn new_fn_def( interner: DbInterner<'db>, def_id: CallableIdWrapper, - args: as rustc_type_ir::Interner>::GenericArgs, + args: as Interner>::GenericArgs, ) -> Self { Ty::new(interner, TyKind::FnDef(def_id, args)) } @@ -1063,12 +1090,19 @@ impl<'db> rustc_type_ir::inherent::Ty> for Ty<'db> { fn new_pat( interner: DbInterner<'db>, ty: Self, - pat: as rustc_type_ir::Interner>::Pat, + pat: as Interner>::Pat, ) -> Self { Ty::new(interner, TyKind::Pat(ty, pat)) } - fn tuple_fields(self) -> as rustc_type_ir::Interner>::Tys { + fn new_unsafe_binder( + interner: DbInterner<'db>, + ty: rustc_type_ir::Binder, as Interner>::Ty>, + ) -> Self { + Ty::new(interner, TyKind::UnsafeBinder(ty.into())) + } + + fn tuple_fields(self) -> as Interner>::Tys { match self.kind() { TyKind::Tuple(args) => args, _ => panic!("tuple_fields called on non-tuple: {self:?}"), @@ -1115,10 +1149,11 @@ impl<'db> rustc_type_ir::inherent::Ty> for Ty<'db> { } } - fn discriminant_ty( - self, - interner: DbInterner<'db>, - ) -> as rustc_type_ir::Interner>::Ty { + fn has_unsafe_fields(self) -> bool { + false + } + + fn discriminant_ty(self, interner: DbInterner<'db>) -> as Interner>::Ty { match self.kind() { TyKind::Adt(adt, _) if adt.is_enum() => adt.repr().discr_type().to_ty(interner), TyKind::Coroutine(_, args) => args.as_coroutine().discr_ty(interner), @@ -1172,20 +1207,6 @@ impl<'db> rustc_type_ir::inherent::Ty> for Ty<'db> { TyKind::UnsafeBinder(..) => unimplemented!(), } } - - fn new_unsafe_binder( - interner: DbInterner<'db>, - ty: rustc_type_ir::Binder< - DbInterner<'db>, - as rustc_type_ir::Interner>::Ty, - >, - ) -> Self { - Ty::new(interner, TyKind::UnsafeBinder(ty.into())) - } - - fn has_unsafe_fields(self) -> bool { - false - } } interned_vec_db!(Tys, Ty); @@ -1197,14 +1218,14 @@ impl<'db> Tys<'db> { } impl<'db> rustc_type_ir::inherent::Tys> for Tys<'db> { - fn inputs(self) -> as rustc_type_ir::Interner>::FnInputTys { + fn inputs(self) -> as Interner>::FnInputTys { Tys::new_from_iter( DbInterner::conjure(), self.as_slice().split_last().unwrap().1.iter().copied(), ) } - fn output(self) -> as rustc_type_ir::Interner>::Ty { + fn output(self) -> as Interner>::Ty { *self.as_slice().split_last().unwrap().0 } } @@ -1222,7 +1243,7 @@ pub struct ParamTy { impl ParamTy { pub fn to_ty<'db>(self, interner: DbInterner<'db>) -> Ty<'db> { - Ty::new_param(interner, self.id, self.index, sym::MISSING_NAME.clone()) + Ty::new_param(interner, self.id, self.index) } } @@ -1269,11 +1290,11 @@ impl<'db> TypeVisitable> for ErrorGuaranteed { impl<'db> TypeFoldable> for ErrorGuaranteed { fn try_fold_with>>( self, - folder: &mut F, + _folder: &mut F, ) -> Result { Ok(self) } - fn fold_with>>(self, folder: &mut F) -> Self { + fn fold_with>>(self, _folder: &mut F) -> Self { self } } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/util.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/util.rs index ae240a942f57..d113f76a327d 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/util.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/util.rs @@ -1,50 +1,40 @@ //! Various utilities for the next-trait-solver. -use std::iter; -use std::ops::{self, ControlFlow}; +use std::{ + iter, + ops::{self, ControlFlow}, +}; use base_db::Crate; -use hir_def::lang_item::LangItem; -use hir_def::{BlockId, HasModule, ItemContainerId, Lookup}; -use intern::sym; +use hir_def::{BlockId, HasModule, lang_item::LangItem}; use la_arena::Idx; use rustc_abi::{Float, HasDataLayout, Integer, IntegerType, Primitive, ReprOptions}; -use rustc_type_ir::data_structures::IndexMap; -use rustc_type_ir::inherent::{ - AdtDef, Const as _, GenericArg as _, GenericArgs as _, ParamEnv as _, Region as _, SliceLike, - Ty as _, -}; -use rustc_type_ir::lang_items::SolverTraitLangItem; -use rustc_type_ir::solve::SizedTraitKind; use rustc_type_ir::{ - BoundVar, Canonical, DebruijnIndex, GenericArgKind, INNERMOST, Interner, PredicatePolarity, - TypeFlags, TypeVisitable, TypeVisitableExt, + ConstKind, CoroutineArgs, DebruijnIndex, FloatTy, INNERMOST, IntTy, Interner, + PredicatePolarity, RegionKind, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeSuperVisitable, + TypeVisitableExt, TypeVisitor, UintTy, UniverseIndex, + inherent::{ + AdtDef, GenericArg as _, GenericArgs as _, IntoKind, ParamEnv as _, SliceLike, Ty as _, + }, + lang_items::SolverTraitLangItem, + solve::SizedTraitKind, }; -use rustc_type_ir::{ - ConstKind, CoroutineArgs, FloatTy, IntTy, RegionKind, TypeFolder, TypeSuperFoldable, - TypeSuperVisitable, TypeVisitor, UintTy, UniverseIndex, inherent::IntoKind, -}; -use rustc_type_ir::{InferCtxtLike, TypeFoldable}; -use crate::lower_nextsolver::{LifetimeElisionKind, TyLoweringContext}; -use crate::next_solver::infer::InferCtxt; -use crate::next_solver::{ - BoundConst, CanonicalVarKind, FxIndexMap, ParamEnv, Placeholder, PlaceholderConst, - PlaceholderRegion, TypingMode, -}; use crate::{ db::HirDatabase, - from_foreign_def_id, + lower::{LifetimeElisionKind, TyLoweringContext}, method_resolution::{TraitImpls, TyFingerprint}, + next_solver::{ + BoundConst, FxIndexMap, ParamEnv, Placeholder, PlaceholderConst, PlaceholderRegion, + infer::InferCtxt, + }, }; -use super::fold::{BoundVarReplacer, FnMutDelegate}; -use super::generics::generics; use super::{ - AliasTerm, AliasTy, Binder, BoundRegion, BoundTy, BoundTyKind, BoundVarKind, BoundVarKinds, - CanonicalVars, Clause, ClauseKind, Clauses, Const, DbInterner, EarlyBinder, GenericArg, - GenericArgs, Predicate, PredicateKind, ProjectionPredicate, Region, SolverContext, SolverDefId, - Term, TraitPredicate, TraitRef, Ty, TyKind, + Binder, BoundRegion, BoundTy, Clause, ClauseKind, Clauses, Const, DbInterner, EarlyBinder, + GenericArgs, Predicate, PredicateKind, Region, SolverDefId, TraitPredicate, TraitRef, Ty, + TyKind, + fold::{BoundVarReplacer, FnMutDelegate}, }; #[derive(Clone, Debug)] @@ -514,151 +504,6 @@ pub fn apply_args_to_binder<'db, T: TypeFoldable>>( b.skip_binder().fold_with(&mut instantiate) } -pub(crate) fn mini_canonicalize<'db, T: TypeFoldable>>( - mut context: SolverContext<'db>, - val: T, -) -> Canonical, T> { - let mut canon = MiniCanonicalizer { - context: &mut context, - db: DebruijnIndex::ZERO, - vars: IndexMap::default(), - }; - let canon_val = val.fold_with(&mut canon); - let vars = canon.vars; - Canonical { - value: canon_val, - max_universe: UniverseIndex::from_u32(1), - variables: CanonicalVars::new_from_iter( - context.cx(), - vars.iter().enumerate().map(|(idx, (k, v))| match (*k).kind() { - GenericArgKind::Type(ty) => match ty.kind() { - TyKind::Int(..) | TyKind::Uint(..) => rustc_type_ir::CanonicalVarKind::Int, - TyKind::Float(..) => rustc_type_ir::CanonicalVarKind::Float, - _ => rustc_type_ir::CanonicalVarKind::Ty { - ui: UniverseIndex::ZERO, - sub_root: BoundVar::from_usize(idx), - }, - }, - GenericArgKind::Lifetime(_) => { - rustc_type_ir::CanonicalVarKind::Region(UniverseIndex::ZERO) - } - GenericArgKind::Const(_) => { - rustc_type_ir::CanonicalVarKind::Const(UniverseIndex::ZERO) - } - }), - ), - } -} - -struct MiniCanonicalizer<'a, 'db> { - context: &'a mut SolverContext<'db>, - db: DebruijnIndex, - vars: IndexMap, usize>, -} - -impl<'db> TypeFolder> for MiniCanonicalizer<'_, 'db> { - fn cx(&self) -> DbInterner<'db> { - self.context.cx() - } - - fn fold_binder>>( - &mut self, - t: rustc_type_ir::Binder, T>, - ) -> rustc_type_ir::Binder, T> { - self.db.shift_in(1); - let res = t.map_bound(|t| t.fold_with(self)); - self.db.shift_out(1); - res - } - - fn fold_ty(&mut self, t: Ty<'db>) -> Ty<'db> { - match t.kind() { - rustc_type_ir::TyKind::Bound(db, _) => { - if db >= self.db { - panic!("Unexpected bound var"); - } - t - } - rustc_type_ir::TyKind::Infer(infer) => { - let t = match infer { - rustc_type_ir::InferTy::TyVar(vid) => { - self.context.opportunistic_resolve_ty_var(vid) - } - rustc_type_ir::InferTy::IntVar(vid) => { - self.context.opportunistic_resolve_int_var(vid) - } - rustc_type_ir::InferTy::FloatVar(vid) => { - self.context.opportunistic_resolve_float_var(vid) - } - _ => t, - }; - let len = self.vars.len(); - let var = *self.vars.entry(t.into()).or_insert(len); - Ty::new( - self.cx(), - TyKind::Bound( - self.db, - BoundTy { kind: super::BoundTyKind::Anon, var: BoundVar::from_usize(var) }, - ), - ) - } - _ => t.super_fold_with(self), - } - } - - fn fold_region( - &mut self, - r: as rustc_type_ir::Interner>::Region, - ) -> as rustc_type_ir::Interner>::Region { - match r.kind() { - RegionKind::ReBound(db, _) => { - if db >= self.db { - panic!("Unexpected bound var"); - } - r - } - RegionKind::ReVar(vid) => { - let len = self.vars.len(); - let var = *self.vars.entry(r.into()).or_insert(len); - Region::new( - self.cx(), - RegionKind::ReBound( - self.db, - BoundRegion { - kind: super::BoundRegionKind::Anon, - var: BoundVar::from_usize(var), - }, - ), - ) - } - _ => r, - } - } - - fn fold_const( - &mut self, - c: as rustc_type_ir::Interner>::Const, - ) -> as rustc_type_ir::Interner>::Const { - match c.kind() { - ConstKind::Bound(db, _) => { - if db >= self.db { - panic!("Unexpected bound var"); - } - c - } - ConstKind::Infer(infer) => { - let len = self.vars.len(); - let var = *self.vars.entry(c.into()).or_insert(len); - Const::new( - self.cx(), - ConstKind::Bound(self.db, BoundConst { var: BoundVar::from_usize(var) }), - ) - } - _ => c.super_fold_with(self), - } - } -} - pub fn explicit_item_bounds<'db>( interner: DbInterner<'db>, def_id: SolverDefId, @@ -666,14 +511,8 @@ pub fn explicit_item_bounds<'db>( let db = interner.db(); match def_id { SolverDefId::TypeAliasId(type_alias) => { - let trait_ = match type_alias.lookup(db).container { - ItemContainerId::TraitId(t) => t, - _ => panic!("associated type not in trait"), - }; - // Lower bounds -- we could/should maybe move this to a separate query in `lower` let type_alias_data = db.type_alias_signature(type_alias); - let generic_params = generics(db, type_alias.into()); let resolver = hir_def::resolver::HasResolver::resolver(type_alias, db); let mut ctx = TyLoweringContext::new( db, @@ -723,7 +562,7 @@ pub fn explicit_item_bounds<'db>( match full_id { crate::ImplTraitId::ReturnTypeImplTrait(func, idx) => { let datas = db - .return_type_impl_traits_ns(func) + .return_type_impl_traits(func) .expect("impl trait id without impl traits"); let datas = (*datas).as_ref().skip_binder(); let data = &datas.impl_traits[Idx::from_raw(idx.into_raw())]; @@ -731,104 +570,15 @@ pub fn explicit_item_bounds<'db>( } crate::ImplTraitId::TypeAliasImplTrait(alias, idx) => { let datas = db - .type_alias_impl_traits_ns(alias) + .type_alias_impl_traits(alias) .expect("impl trait id without impl traits"); let datas = (*datas).as_ref().skip_binder(); let data = &datas.impl_traits[Idx::from_raw(idx.into_raw())]; EarlyBinder::bind(Clauses::new_from_iter(interner, data.predicates.clone())) } - crate::ImplTraitId::AsyncBlockTypeImplTrait(..) => { - if let Some((future_trait, future_output)) = LangItem::Future - .resolve_trait(db, interner.krate.expect("Must have interner.krate")) - .and_then(|trait_| { - let alias = trait_.trait_items(db).associated_type_by_name( - &hir_expand::name::Name::new_symbol_root(sym::Output.clone()), - )?; - Some((trait_, alias)) - }) - { - let args = GenericArgs::identity_for_item(interner, def_id); - let out = args.as_slice()[0]; - let mut predicates = vec![]; - - let item_ty = Ty::new_alias( - interner, - rustc_type_ir::AliasTyKind::Opaque, - AliasTy::new_from_args(interner, def_id, args), - ); - - let kind = PredicateKind::Clause(ClauseKind::Trait(TraitPredicate { - polarity: rustc_type_ir::PredicatePolarity::Positive, - trait_ref: TraitRef::new_from_args( - interner, - future_trait.into(), - GenericArgs::new_from_iter(interner, [item_ty.into()]), - ), - })); - predicates.push(Clause(Predicate::new( - interner, - Binder::bind_with_vars( - kind, - BoundVarKinds::new_from_iter( - interner, - [BoundVarKind::Ty(BoundTyKind::Anon)], - ), - ), - ))); - let sized_trait = LangItem::Sized - .resolve_trait(db, interner.krate.expect("Must have interner.krate")); - if let Some(sized_trait_) = sized_trait { - let kind = PredicateKind::Clause(ClauseKind::Trait(TraitPredicate { - polarity: rustc_type_ir::PredicatePolarity::Positive, - trait_ref: TraitRef::new_from_args( - interner, - sized_trait_.into(), - GenericArgs::new_from_iter(interner, [item_ty.into()]), - ), - })); - predicates.push(Clause(Predicate::new( - interner, - Binder::bind_with_vars( - kind, - BoundVarKinds::new_from_iter( - interner, - [BoundVarKind::Ty(BoundTyKind::Anon)], - ), - ), - ))); - } - let kind = - PredicateKind::Clause(ClauseKind::Projection(ProjectionPredicate { - projection_term: AliasTerm::new_from_args( - interner, - future_output.into(), - GenericArgs::new_from_iter(interner, [item_ty.into()]), - ), - term: match out.kind() { - GenericArgKind::Lifetime(lt) => panic!(), - GenericArgKind::Type(ty) => Term::Ty(ty), - GenericArgKind::Const(const_) => Term::Const(const_), - }, - })); - predicates.push(Clause(Predicate::new( - interner, - Binder::bind_with_vars( - kind, - BoundVarKinds::new_from_iter( - interner, - [BoundVarKind::Ty(BoundTyKind::Anon)], - ), - ), - ))); - EarlyBinder::bind(Clauses::new_from_iter(interner, predicates)) - } else { - // If failed to find Symbol’s value as variable is void: Future::Output, return empty bounds as fallback. - EarlyBinder::bind(Clauses::new_from_iter(interner, [])) - } - } } } - _ => panic!("Unexpected GeneridDefId"), + _ => panic!("Unexpected GenericDefId"), } } @@ -993,26 +743,6 @@ impl<'db> TypeFolder> for PlaceholderReplacer<'_, 'db> { } } -pub(crate) fn needs_normalization<'db, T: TypeVisitable>>( - infcx: &InferCtxt<'db>, - value: &T, -) -> bool { - let mut flags = TypeFlags::HAS_ALIAS; - - // Opaques are treated as rigid outside of `TypingMode::PostAnalysis`, - // so we can ignore those. - match infcx.typing_mode() { - // FIXME(#132279): We likely want to reveal opaques during post borrowck analysis - TypingMode::Coherence - | TypingMode::Analysis { .. } - | TypingMode::Borrowck { .. } - | TypingMode::PostBorrowckAnalysis { .. } => flags.remove(TypeFlags::HAS_TY_OPAQUE), - TypingMode::PostAnalysis => {} - } - - value.has_type_flags(flags) -} - pub fn sizedness_fast_path<'db>( tcx: DbInterner<'db>, predicate: Predicate<'db>, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/primitive.rs b/src/tools/rust-analyzer/crates/hir-ty/src/primitive.rs index d2901f7fc53d..9ffb112fe617 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/primitive.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/primitive.rs @@ -1,7 +1,7 @@ //! A few helper functions for dealing with primitives. -pub use chalk_ir::{FloatTy, IntTy, UintTy}; pub use hir_def::builtin_type::{BuiltinFloat, BuiltinInt, BuiltinUint}; +pub use rustc_type_ir::{FloatTy, IntTy, UintTy}; pub fn int_ty_to_string(ty: IntTy) -> &'static str { match ty { @@ -33,68 +33,3 @@ pub fn float_ty_to_string(ty: FloatTy) -> &'static str { FloatTy::F128 => "f128", } } - -pub fn int_ty_to_string_ns(ty: rustc_type_ir::IntTy) -> &'static str { - use rustc_type_ir::IntTy; - match ty { - IntTy::Isize => "isize", - IntTy::I8 => "i8", - IntTy::I16 => "i16", - IntTy::I32 => "i32", - IntTy::I64 => "i64", - IntTy::I128 => "i128", - } -} - -pub fn uint_ty_to_string_ns(ty: rustc_type_ir::UintTy) -> &'static str { - use rustc_type_ir::UintTy; - match ty { - UintTy::Usize => "usize", - UintTy::U8 => "u8", - UintTy::U16 => "u16", - UintTy::U32 => "u32", - UintTy::U64 => "u64", - UintTy::U128 => "u128", - } -} - -pub fn float_ty_to_string_ns(ty: rustc_type_ir::FloatTy) -> &'static str { - use rustc_type_ir::FloatTy; - match ty { - FloatTy::F16 => "f16", - FloatTy::F32 => "f32", - FloatTy::F64 => "f64", - FloatTy::F128 => "f128", - } -} - -pub(super) fn int_ty_from_builtin(t: BuiltinInt) -> IntTy { - match t { - BuiltinInt::Isize => IntTy::Isize, - BuiltinInt::I8 => IntTy::I8, - BuiltinInt::I16 => IntTy::I16, - BuiltinInt::I32 => IntTy::I32, - BuiltinInt::I64 => IntTy::I64, - BuiltinInt::I128 => IntTy::I128, - } -} - -pub(super) fn uint_ty_from_builtin(t: BuiltinUint) -> UintTy { - match t { - BuiltinUint::Usize => UintTy::Usize, - BuiltinUint::U8 => UintTy::U8, - BuiltinUint::U16 => UintTy::U16, - BuiltinUint::U32 => UintTy::U32, - BuiltinUint::U64 => UintTy::U64, - BuiltinUint::U128 => UintTy::U128, - } -} - -pub(super) fn float_ty_from_builtin(t: BuiltinFloat) -> FloatTy { - match t { - BuiltinFloat::F16 => FloatTy::F16, - BuiltinFloat::F32 => FloatTy::F32, - BuiltinFloat::F64 => FloatTy::F64, - BuiltinFloat::F128 => FloatTy::F128, - } -} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/specialization.rs b/src/tools/rust-analyzer/crates/hir-ty/src/specialization.rs new file mode 100644 index 000000000000..611947b96b71 --- /dev/null +++ b/src/tools/rust-analyzer/crates/hir-ty/src/specialization.rs @@ -0,0 +1,150 @@ +//! Impl specialization related things + +use hir_def::{ImplId, nameres::crate_def_map}; +use intern::sym; +use tracing::debug; + +use crate::{ + db::HirDatabase, + next_solver::{ + DbInterner, TypingMode, + infer::{ + DbInternerInferExt, + traits::{Obligation, ObligationCause}, + }, + obligation_ctxt::ObligationCtxt, + }, +}; + +// rustc does not have a cycle handling for the `specializes` query, meaning a cycle is a bug, +// and indeed I was unable to cause cycles even with erroneous code. However, in r-a we can +// create a cycle if there is an error in the impl's where clauses. I believe well formed code +// cannot create a cycle, but a cycle handler is required nevertheless. +fn specializes_cycle( + _db: &dyn HirDatabase, + _specializing_impl_def_id: ImplId, + _parent_impl_def_id: ImplId, +) -> bool { + false +} + +/// Is `specializing_impl_def_id` a specialization of `parent_impl_def_id`? +/// +/// For every type that could apply to `specializing_impl_def_id`, we prove that +/// the `parent_impl_def_id` also applies (i.e. it has a valid impl header and +/// its where-clauses hold). +/// +/// For the purposes of const traits, we also check that the specializing +/// impl is not more restrictive than the parent impl. That is, if the +/// `parent_impl_def_id` is a const impl (conditionally based off of some `[const]` +/// bounds), then `specializing_impl_def_id` must also be const for the same +/// set of types. +#[salsa::tracked(cycle_result = specializes_cycle)] +pub(crate) fn specializes( + db: &dyn HirDatabase, + specializing_impl_def_id: ImplId, + parent_impl_def_id: ImplId, +) -> bool { + let module = specializing_impl_def_id.loc(db).container; + + // We check that the specializing impl comes from a crate that has specialization enabled. + // + // We don't really care if the specialized impl (the parent) is in a crate that has + // specialization enabled, since it's not being specialized. + // + // rustc also checks whether the specializing impls comes from a macro marked + // `#[allow_internal_unstable(specialization)]`, but `#[allow_internal_unstable]` + // is an internal feature, std is not using it for specialization nor is likely to + // ever use it, and we don't have the span information necessary to replicate that. + let def_map = crate_def_map(db, module.krate()); + if !def_map.is_unstable_feature_enabled(&sym::specialization) + && !def_map.is_unstable_feature_enabled(&sym::min_specialization) + { + return false; + } + + let interner = DbInterner::new_with(db, Some(module.krate()), module.containing_block()); + + let specializing_impl_signature = db.impl_signature(specializing_impl_def_id); + let parent_impl_signature = db.impl_signature(parent_impl_def_id); + + // We determine whether there's a subset relationship by: + // + // - replacing bound vars with placeholders in impl1, + // - assuming the where clauses for impl1, + // - instantiating impl2 with fresh inference variables, + // - unifying, + // - attempting to prove the where clauses for impl2 + // + // The last three steps are encapsulated in `fulfill_implication`. + // + // See RFC 1210 for more details and justification. + + // Currently we do not allow e.g., a negative impl to specialize a positive one + if specializing_impl_signature.is_negative() != parent_impl_signature.is_negative() { + return false; + } + + // create a parameter environment corresponding to an identity instantiation of the specializing impl, + // i.e. the most generic instantiation of the specializing impl. + let param_env = db.trait_environment(specializing_impl_def_id.into()).env; + + // Create an infcx, taking the predicates of the specializing impl as assumptions: + let infcx = interner.infer_ctxt().build(TypingMode::non_body_analysis()); + + let specializing_impl_trait_ref = + db.impl_trait(specializing_impl_def_id).unwrap().instantiate_identity(); + let cause = &ObligationCause::dummy(); + debug!( + "fulfill_implication({:?}, trait_ref={:?} |- {:?} applies)", + param_env, specializing_impl_trait_ref, parent_impl_def_id + ); + + // Attempt to prove that the parent impl applies, given all of the above. + + let mut ocx = ObligationCtxt::new(&infcx); + + let parent_args = infcx.fresh_args_for_item(parent_impl_def_id.into()); + let parent_impl_trait_ref = db + .impl_trait(parent_impl_def_id) + .expect("expected source impl to be a trait impl") + .instantiate(interner, parent_args); + + // do the impls unify? If not, no specialization. + let Ok(()) = ocx.eq(cause, param_env, specializing_impl_trait_ref, parent_impl_trait_ref) + else { + return false; + }; + + // Now check that the source trait ref satisfies all the where clauses of the target impl. + // This is not just for correctness; we also need this to constrain any params that may + // only be referenced via projection predicates. + if let Some(predicates) = + db.generic_predicates(parent_impl_def_id.into()).instantiate(interner, parent_args) + { + ocx.register_obligations( + predicates + .map(|predicate| Obligation::new(interner, cause.clone(), param_env, predicate)), + ); + } + + let errors = ocx.evaluate_obligations_error_on_ambiguity(); + if !errors.is_empty() { + // no dice! + debug!( + "fulfill_implication: for impls on {:?} and {:?}, \ + could not fulfill: {:?} given {:?}", + specializing_impl_trait_ref, parent_impl_trait_ref, errors, param_env + ); + return false; + } + + // FIXME: Check impl constness (when we implement const impls). + + debug!( + "fulfill_implication: an impl for {:?} specializes {:?}", + specializing_impl_trait_ref, parent_impl_trait_ref + ); + + true +} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs index 76cd5f7ab330..bc4701970c76 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs @@ -44,7 +44,7 @@ fn foo() -> i32 { "body_shim", "body_with_source_map_shim", "trait_environment_shim", - "return_type_impl_traits_ns_shim", + "return_type_impl_traits_shim", "expr_scopes_shim", "lang_item", "crate_lang_items", @@ -131,7 +131,7 @@ fn baz() -> i32 { "body_shim", "body_with_source_map_shim", "trait_environment_shim", - "return_type_impl_traits_ns_shim", + "return_type_impl_traits_shim", "expr_scopes_shim", "lang_item", "crate_lang_items", @@ -143,7 +143,7 @@ fn baz() -> i32 { "body_shim", "body_with_source_map_shim", "trait_environment_shim", - "return_type_impl_traits_ns_shim", + "return_type_impl_traits_shim", "expr_scopes_shim", "infer_shim", "function_signature_shim", @@ -151,7 +151,7 @@ fn baz() -> i32 { "body_shim", "body_with_source_map_shim", "trait_environment_shim", - "return_type_impl_traits_ns_shim", + "return_type_impl_traits_shim", "expr_scopes_shim", ] "#]], @@ -585,8 +585,8 @@ fn main() { "crate_lang_items", "attrs_shim", "attrs_shim", - "generic_predicates_ns_shim", - "return_type_impl_traits_ns_shim", + "generic_predicates_shim", + "return_type_impl_traits_shim", "infer_shim", "function_signature_shim", "function_signature_with_source_map_shim", @@ -594,7 +594,7 @@ fn main() { "expr_scopes_shim", "struct_signature_shim", "struct_signature_with_source_map_shim", - "generic_predicates_ns_shim", + "generic_predicates_shim", "value_ty_shim", "VariantFields::firewall_", "VariantFields::query_", @@ -608,9 +608,9 @@ fn main() { "trait_impls_in_crate_shim", "impl_trait_with_diagnostics_shim", "impl_self_ty_with_diagnostics_shim", - "generic_predicates_ns_shim", + "generic_predicates_shim", "value_ty_shim", - "generic_predicates_ns_shim", + "generic_predicates_shim", ] "#]], ); @@ -682,13 +682,13 @@ fn main() { "attrs_shim", "attrs_shim", "attrs_shim", - "generic_predicates_ns_shim", - "return_type_impl_traits_ns_shim", + "generic_predicates_shim", + "return_type_impl_traits_shim", "infer_shim", "function_signature_with_source_map_shim", "expr_scopes_shim", "struct_signature_with_source_map_shim", - "generic_predicates_ns_shim", + "generic_predicates_shim", "VariantFields::query_", "inherent_impls_in_crate_shim", "impl_signature_with_source_map_shim", @@ -697,8 +697,8 @@ fn main() { "trait_impls_in_crate_shim", "impl_trait_with_diagnostics_shim", "impl_self_ty_with_diagnostics_shim", - "generic_predicates_ns_shim", - "generic_predicates_ns_shim", + "generic_predicates_shim", + "generic_predicates_shim", ] "#]], ); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression/new_solver.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression/new_solver.rs index 5983ec764790..f8b73cd50551 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression/new_solver.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression/new_solver.rs @@ -472,3 +472,55 @@ where "#, ); } + +#[test] +fn regression_16282() { + check_infer( + r#" +//- minicore: coerce_unsized, dispatch_from_dyn +trait MapLookup { + type MapValue; +} + +impl MapLookup for K { + type MapValue = K; +} + +trait Map: MapLookup<::Key> { + type Key; +} + +impl Map for K { + type Key = K; +} + + +fn main() { + let _ = &() + as &dyn Map; +} +"#, + expect![[r#" + 210..272 '{ ...32>; }': () + 220..221 '_': &'? (dyn Map + '?) + 224..227 '&()': &'? () + 224..269 '&() ...e=u32>': &'? (dyn Map + 'static) + 225..227 '()': () + "#]], + ); +} + +#[test] +fn regression_18692() { + check_no_mismatches( + r#" +//- minicore: coerce_unsized, dispatch_from_dyn, send +trait Trait: Send {} + +fn f(_: *const (dyn Trait + Send)) {} +fn g(it: *const (dyn Trait)) { + f(it); +} +"#, + ); +} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs index 38af7cb7248f..c2392b36baba 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs @@ -3856,9 +3856,9 @@ fn main() { 74..75 'f': F 80..82 '{}': () 94..191 '{ ... }); }': () - 100..113 'async_closure': fn async_closure(impl FnOnce(i32)) + 100..113 'async_closure': fn async_closure(impl AsyncFnOnce(i32)) 100..147 'async_... })': () - 114..146 'async ... }': impl FnOnce(i32) + 114..146 'async ... }': impl AsyncFnOnce(i32) 121..124 'arg': i32 126..146 '{ ... }': () 136..139 'arg': i32 diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs index 0cf723e8514d..f72ca22fd229 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs @@ -85,7 +85,6 @@ async fn test() { } #[test] -#[ignore = "FIXME(next-solver): fix async closures"] fn infer_async_closure() { check_types( r#" @@ -93,7 +92,7 @@ fn infer_async_closure() { async fn test() { let f = async move |x: i32| x + 42; f; -// ^ impl Fn(i32) -> impl Future +// ^ impl AsyncFn(i32) -> i32 let a = f(4); a; // ^ impl Future @@ -102,7 +101,7 @@ async fn test() { // ^ i32 let f = async move || 42; f; -// ^ impl Fn() -> impl Future +// ^ impl AsyncFn() -> i32 let a = f(); a; // ^ impl Future @@ -119,7 +118,7 @@ async fn test() { }; let _: Option = c().await; c; -// ^ impl Fn() -> impl Future> +// ^ impl AsyncFn() -> Option } "#, ); @@ -4930,7 +4929,6 @@ fn main() { #[test] fn async_fn_return_type() { - // FIXME(next-solver): Async closures are lowered as closures currently. We should fix that. check_infer( r#" //- minicore: async_fn @@ -4948,9 +4946,9 @@ fn main() { 46..53 'loop {}': ! 51..53 '{}': () 67..97 '{ ...()); }': () - 73..76 'foo': fn foo(impl Fn()) + 73..76 'foo': fn foo(impl AsyncFn()) 73..94 'foo(as...|| ())': () - 77..93 'async ... || ()': impl Fn() + 77..93 'async ... || ()': impl AsyncFn() 91..93 '()': () "#]], ); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tls.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tls.rs deleted file mode 100644 index fe4cf7a3da52..000000000000 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tls.rs +++ /dev/null @@ -1,155 +0,0 @@ -//! Implementation of Chalk debug helper functions using TLS. -use std::fmt::{self, Display}; - -use itertools::Itertools; -use span::Edition; - -use crate::{ - CallableDefId, Interner, ProjectionTyExt, chalk_db, db::HirDatabase, from_assoc_type_id, - from_chalk_trait_id, mapping::from_chalk, -}; -use hir_def::{AdtId, ItemContainerId, Lookup, TypeAliasId}; - -#[allow(unused)] -pub(crate) use unsafe_tls::{set_current_program, with_current_program}; - -pub(crate) struct DebugContext<'a>(&'a dyn HirDatabase); - -impl DebugContext<'_> { - pub(crate) fn debug_struct_id( - &self, - id: chalk_db::AdtId, - f: &mut fmt::Formatter<'_>, - ) -> Result<(), fmt::Error> { - let name = match id.0 { - AdtId::StructId(it) => self.0.struct_signature(it).name.clone(), - AdtId::UnionId(it) => self.0.union_signature(it).name.clone(), - AdtId::EnumId(it) => self.0.enum_signature(it).name.clone(), - }; - name.display(self.0, Edition::LATEST).fmt(f)?; - Ok(()) - } - - pub(crate) fn debug_trait_id( - &self, - id: chalk_db::TraitId, - f: &mut fmt::Formatter<'_>, - ) -> Result<(), fmt::Error> { - let trait_: hir_def::TraitId = from_chalk_trait_id(id); - let trait_data = self.0.trait_signature(trait_); - trait_data.name.display(self.0, Edition::LATEST).fmt(f)?; - Ok(()) - } - - pub(crate) fn debug_assoc_type_id( - &self, - id: chalk_db::AssocTypeId, - fmt: &mut fmt::Formatter<'_>, - ) -> Result<(), fmt::Error> { - let type_alias: TypeAliasId = from_assoc_type_id(id); - let type_alias_data = self.0.type_alias_signature(type_alias); - let trait_ = match type_alias.lookup(self.0).container { - ItemContainerId::TraitId(t) => t, - _ => panic!("associated type not in trait"), - }; - let trait_data = self.0.trait_signature(trait_); - write!( - fmt, - "{}::{}", - trait_data.name.display(self.0, Edition::LATEST), - type_alias_data.name.display(self.0, Edition::LATEST) - )?; - Ok(()) - } - - pub(crate) fn debug_projection_ty( - &self, - projection_ty: &chalk_ir::ProjectionTy, - fmt: &mut fmt::Formatter<'_>, - ) -> Result<(), fmt::Error> { - let type_alias = from_assoc_type_id(projection_ty.associated_ty_id); - let type_alias_data = self.0.type_alias_signature(type_alias); - let trait_ = match type_alias.lookup(self.0).container { - ItemContainerId::TraitId(t) => t, - _ => panic!("associated type not in trait"), - }; - let trait_name = &self.0.trait_signature(trait_).name; - let trait_ref = projection_ty.trait_ref(self.0); - let trait_params = trait_ref.substitution.as_slice(Interner); - let self_ty = trait_ref.self_type_parameter(Interner); - write!(fmt, "<{self_ty:?} as {}", trait_name.display(self.0, Edition::LATEST))?; - if trait_params.len() > 1 { - write!( - fmt, - "<{}>", - trait_params[1..].iter().format_with(", ", |x, f| f(&format_args!("{x:?}"))), - )?; - } - write!(fmt, ">::{}", type_alias_data.name.display(self.0, Edition::LATEST))?; - - let proj_params = &projection_ty.substitution.as_slice(Interner)[trait_params.len()..]; - if !proj_params.is_empty() { - write!( - fmt, - "<{}>", - proj_params.iter().format_with(", ", |x, f| f(&format_args!("{x:?}"))), - )?; - } - - Ok(()) - } - - pub(crate) fn debug_fn_def_id( - &self, - fn_def_id: chalk_ir::FnDefId, - fmt: &mut fmt::Formatter<'_>, - ) -> Result<(), fmt::Error> { - let def: CallableDefId = from_chalk(self.0, fn_def_id); - let name = match def { - CallableDefId::FunctionId(ff) => self.0.function_signature(ff).name.clone(), - CallableDefId::StructId(s) => self.0.struct_signature(s).name.clone(), - CallableDefId::EnumVariantId(e) => { - let loc = e.lookup(self.0); - loc.parent.enum_variants(self.0).variants[loc.index as usize].1.clone() - } - }; - match def { - CallableDefId::FunctionId(_) => { - write!(fmt, "{{fn {}}}", name.display(self.0, Edition::LATEST)) - } - CallableDefId::StructId(_) | CallableDefId::EnumVariantId(_) => { - write!(fmt, "{{ctor {}}}", name.display(self.0, Edition::LATEST)) - } - } - } -} - -mod unsafe_tls { - use super::DebugContext; - use crate::db::HirDatabase; - use scoped_tls::scoped_thread_local; - - scoped_thread_local!(static PROGRAM: DebugContext<'_>); - - pub(crate) fn with_current_program( - op: impl for<'a> FnOnce(Option<&'a DebugContext<'a>>) -> R, - ) -> R { - if PROGRAM.is_set() { PROGRAM.with(|prog| op(Some(prog))) } else { op(None) } - } - - #[allow(dead_code)] - pub(crate) fn set_current_program(p: &dyn HirDatabase, op: OP) -> R - where - OP: FnOnce() -> R, - { - let ctx = DebugContext(p); - // we're transmuting the lifetime in the DebugContext to static. This is - // fine because we only keep the reference for the lifetime of this - // function, *and* the only way to access the context is through - // `with_current_program`, which hides the lifetime through the `for` - // type. - let static_p: &DebugContext<'static> = - unsafe { std::mem::transmute::<&DebugContext<'_>, &DebugContext<'static>>(&ctx) }; - PROGRAM.set(static_p, op) - } -} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs index cd125f3af864..7f6d4ff17f9f 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs @@ -3,35 +3,26 @@ use core::fmt; use std::hash::Hash; -use chalk_ir::{DebruijnIndex, GoalData, fold::TypeFoldable}; - use base_db::Crate; use hir_def::{BlockId, TraitId, lang_item::LangItem}; use hir_expand::name::Name; use intern::sym; use rustc_next_trait_solver::solve::{HasChanged, SolverDelegateEvalExt}; use rustc_type_ir::{ - InferCtxtLike, TypingMode, - inherent::{IntoKind, SliceLike, Span as _, Ty as _}, + TypingMode, + inherent::{IntoKind, Span as _}, solve::Certainty, }; -use span::Edition; -use stdx::never; use triomphe::Arc; use crate::{ - AliasEq, AliasTy, Canonical, DomainGoal, Goal, InEnvironment, Interner, ProjectionTy, - ProjectionTyExt, TraitRefExt, Ty, TyKind, TypeFlags, WhereClause, db::HirDatabase, - from_assoc_type_id, next_solver::{ - DbInterner, GenericArg, ParamEnv, Predicate, SolverContext, Span, + Canonical, DbInterner, GenericArgs, Goal, ParamEnv, Predicate, SolverContext, Span, Ty, + TyKind, infer::{DbInternerInferExt, InferCtxt, traits::ObligationCause}, - mapping::{ChalkToNextSolver, NextSolverToChalk, convert_canonical_args_for_result}, obligation_ctxt::ObligationCtxt, - util::mini_canonicalize, }, - utils::UnevaluatedConstEvaluatorFolder, }; /// A set of clauses that we assume to be true. E.g. if we are inside this function: @@ -44,7 +35,7 @@ pub struct TraitEnvironment<'db> { pub krate: Crate, pub block: Option, // FIXME make this a BTreeMap - traits_from_clauses: Box<[(crate::next_solver::Ty<'db>, TraitId)]>, + traits_from_clauses: Box<[(Ty<'db>, TraitId)]>, pub env: ParamEnv<'db>, } @@ -61,7 +52,7 @@ impl<'db> TraitEnvironment<'db> { pub fn new( krate: Crate, block: Option, - traits_from_clauses: Box<[(crate::next_solver::Ty<'db>, TraitId)]>, + traits_from_clauses: Box<[(Ty<'db>, TraitId)]>, env: ParamEnv<'db>, ) -> Arc { Arc::new(TraitEnvironment { krate, block, traits_from_clauses, env }) @@ -72,10 +63,7 @@ impl<'db> TraitEnvironment<'db> { Arc::make_mut(this).block = Some(block); } - pub fn traits_in_scope_from_clauses( - &self, - ty: crate::next_solver::Ty<'db>, - ) -> impl Iterator + '_ { + pub fn traits_in_scope_from_clauses(&self, ty: Ty<'db>) -> impl Iterator + '_ { self.traits_from_clauses .iter() .filter_map(move |(self_ty, trait_id)| (*self_ty == ty).then_some(*trait_id)) @@ -85,172 +73,19 @@ impl<'db> TraitEnvironment<'db> { /// This should be used in `hir` only. pub fn structurally_normalize_ty<'db>( infcx: &InferCtxt<'db>, - ty: crate::next_solver::Ty<'db>, + ty: Ty<'db>, env: Arc>, -) -> crate::next_solver::Ty<'db> { - let crate::next_solver::TyKind::Alias(..) = ty.kind() else { return ty }; +) -> Ty<'db> { + let TyKind::Alias(..) = ty.kind() else { return ty }; let mut ocx = ObligationCtxt::new(infcx); let ty = ocx.structurally_normalize_ty(&ObligationCause::dummy(), env.env, ty).unwrap_or(ty); ty.replace_infer_with_error(infcx.interner) } -pub(crate) fn normalize_projection_query<'db>( - db: &'db dyn HirDatabase, - projection: ProjectionTy, - env: Arc>, -) -> Ty { - if projection.substitution.iter(Interner).any(|arg| { - arg.ty(Interner) - .is_some_and(|ty| ty.data(Interner).flags.intersects(TypeFlags::HAS_TY_INFER)) - }) { - never!( - "Invoking `normalize_projection_query` with a projection type containing inference var" - ); - return TyKind::Error.intern(Interner); - } - - let interner = DbInterner::new_with(db, Some(env.krate), env.block); - // FIXME(next-solver): I believe this should use `PostAnalysis` (this is only used for IDE things), - // but this causes some bug because of our incorrect impl of `type_of_opaque_hir_typeck()` for TAIT - // and async blocks. - let infcx = interner.infer_ctxt().build(TypingMode::Analysis { - defining_opaque_types_and_generators: crate::next_solver::SolverDefIds::new_from_iter( - interner, - [], - ), - }); - let alias_ty = crate::next_solver::Ty::new_alias( - interner, - rustc_type_ir::AliasTyKind::Projection, - crate::next_solver::AliasTy::new( - interner, - from_assoc_type_id(projection.associated_ty_id).into(), - >>::to_nextsolver(&projection.substitution, interner), - ), - ); - let mut ctxt = crate::next_solver::obligation_ctxt::ObligationCtxt::new(&infcx); - let normalized = ctxt - .structurally_normalize_ty(&ObligationCause::dummy(), env.env, alias_ty) - .unwrap_or(alias_ty); - normalized.replace_infer_with_error(interner).to_chalk(interner) -} - -fn identity_subst( - binders: chalk_ir::CanonicalVarKinds, -) -> chalk_ir::Canonical> { - let identity_subst = chalk_ir::Substitution::from_iter( - Interner, - binders.iter(Interner).enumerate().map(|(index, c)| { - let index_db = chalk_ir::BoundVar::new(DebruijnIndex::INNERMOST, index); - match &c.kind { - chalk_ir::VariableKind::Ty(_) => { - chalk_ir::GenericArgData::Ty(TyKind::BoundVar(index_db).intern(Interner)) - .intern(Interner) - } - chalk_ir::VariableKind::Lifetime => chalk_ir::GenericArgData::Lifetime( - chalk_ir::LifetimeData::BoundVar(index_db).intern(Interner), - ) - .intern(Interner), - chalk_ir::VariableKind::Const(ty) => chalk_ir::GenericArgData::Const( - chalk_ir::ConstData { - ty: ty.clone(), - value: chalk_ir::ConstValue::BoundVar(index_db), - } - .intern(Interner), - ) - .intern(Interner), - } - }), - ); - chalk_ir::Canonical { binders, value: identity_subst } -} - -/// Solve a trait goal using next trait solver. -pub(crate) fn trait_solve_query( - db: &dyn HirDatabase, - krate: Crate, - block: Option, - goal: Canonical>, -) -> NextTraitSolveResult { - let _p = tracing::info_span!("trait_solve_query", detail = ?match &goal.value.goal.data(Interner) { - GoalData::DomainGoal(DomainGoal::Holds(WhereClause::Implemented(it))) => db - .trait_signature(it.hir_trait_id()) - .name - .display(db, Edition::LATEST) - .to_string(), - GoalData::DomainGoal(DomainGoal::Holds(WhereClause::AliasEq(_))) => "alias_eq".to_owned(), - _ => "??".to_owned(), - }) - .entered(); - - if let GoalData::DomainGoal(DomainGoal::Holds(WhereClause::AliasEq(AliasEq { - alias: AliasTy::Projection(projection_ty), - .. - }))) = &goal.value.goal.data(Interner) - && let TyKind::BoundVar(_) = projection_ty.self_type_parameter(db).kind(Interner) - { - // Hack: don't ask Chalk to normalize with an unknown self type, it'll say that's impossible - return NextTraitSolveResult::Uncertain(identity_subst(goal.binders.clone())); - } - - // Chalk see `UnevaluatedConst` as a unique concrete value, but we see it as an alias for another const. So - // we should get rid of it when talking to chalk. - let goal = goal - .try_fold_with(&mut UnevaluatedConstEvaluatorFolder { db }, DebruijnIndex::INNERMOST) - .unwrap(); - - // We currently don't deal with universes (I think / hope they're not yet - // relevant for our use cases?) - next_trait_solve(db, krate, block, goal) -} - -fn solve_nextsolver<'db>( - db: &'db dyn HirDatabase, - krate: Crate, - block: Option, - goal: &chalk_ir::UCanonical>>, -) -> Result< - (HasChanged, Certainty, rustc_type_ir::Canonical, Vec>>), - rustc_type_ir::solve::NoSolution, -> { - // FIXME: should use analysis_in_body, but that needs GenericDefId::Block - let context = SolverContext( - DbInterner::new_with(db, Some(krate), block) - .infer_ctxt() - .build(TypingMode::non_body_analysis()), - ); - - match goal.canonical.value.goal.data(Interner) { - // FIXME: args here should be...what? not empty - GoalData::All(goals) if goals.is_empty(Interner) => { - return Ok((HasChanged::No, Certainty::Yes, mini_canonicalize(context, vec![]))); - } - _ => {} - } - - let goal = goal.canonical.to_nextsolver(context.cx()); - tracing::info!(?goal); - - let (goal, var_values) = context.instantiate_canonical(&goal); - tracing::info!(?var_values); - - let res = context.evaluate_root_goal(goal, Span::dummy(), None); - - let vars = - var_values.var_values.iter().map(|g| context.0.resolve_vars_if_possible(g)).collect(); - let canonical_var_values = mini_canonicalize(context, vars); - - let res = res.map(|r| (r.has_changed, r.certainty, canonical_var_values)); - - tracing::debug!("solve_nextsolver({:?}) => {:?}", goal, res); - - res -} - #[derive(Clone, Debug, PartialEq)] pub enum NextTraitSolveResult { - Certain(chalk_ir::Canonical>), - Uncertain(chalk_ir::Canonical>), + Certain, + Uncertain, NoSolution, } @@ -260,75 +95,17 @@ impl NextTraitSolveResult { } pub fn certain(&self) -> bool { - matches!(self, NextTraitSolveResult::Certain(..)) + matches!(self, NextTraitSolveResult::Certain) } pub fn uncertain(&self) -> bool { - matches!(self, NextTraitSolveResult::Uncertain(..)) - } -} - -pub fn next_trait_solve( - db: &dyn HirDatabase, - krate: Crate, - block: Option, - goal: Canonical>, -) -> NextTraitSolveResult { - let detail = match &goal.value.goal.data(Interner) { - GoalData::DomainGoal(DomainGoal::Holds(WhereClause::Implemented(it))) => { - db.trait_signature(it.hir_trait_id()).name.display(db, Edition::LATEST).to_string() - } - GoalData::DomainGoal(DomainGoal::Holds(WhereClause::AliasEq(_))) => "alias_eq".to_owned(), - _ => "??".to_owned(), - }; - let _p = tracing::info_span!("next_trait_solve", ?detail).entered(); - tracing::info!("next_trait_solve({:?})", goal.value.goal); - - if let GoalData::DomainGoal(DomainGoal::Holds(WhereClause::AliasEq(AliasEq { - alias: AliasTy::Projection(projection_ty), - .. - }))) = &goal.value.goal.data(Interner) - && let TyKind::BoundVar(_) = projection_ty.self_type_parameter(db).kind(Interner) - { - // Hack: don't ask Chalk to normalize with an unknown self type, it'll say that's impossible - // FIXME - return NextTraitSolveResult::Uncertain(identity_subst(goal.binders.clone())); - } - - // Chalk see `UnevaluatedConst` as a unique concrete value, but we see it as an alias for another const. So - // we should get rid of it when talking to chalk. - let goal = goal - .try_fold_with(&mut UnevaluatedConstEvaluatorFolder { db }, DebruijnIndex::INNERMOST) - .unwrap(); - - // We currently don't deal with universes (I think / hope they're not yet - // relevant for our use cases?) - let u_canonical = chalk_ir::UCanonical { canonical: goal, universes: 1 }; - tracing::info!(?u_canonical); - - let next_solver_res = solve_nextsolver(db, krate, block, &u_canonical); - - match next_solver_res { - Err(_) => NextTraitSolveResult::NoSolution, - Ok((_, Certainty::Yes, args)) => NextTraitSolveResult::Certain( - convert_canonical_args_for_result(DbInterner::new_with(db, Some(krate), block), args), - ), - Ok((_, Certainty::Maybe { .. }, args)) => { - let subst = convert_canonical_args_for_result( - DbInterner::new_with(db, Some(krate), block), - args, - ); - NextTraitSolveResult::Uncertain(chalk_ir::Canonical { - binders: subst.binders, - value: subst.value.subst, - }) - } + matches!(self, NextTraitSolveResult::Uncertain) } } pub fn next_trait_solve_canonical_in_ctxt<'db>( infer_ctxt: &InferCtxt<'db>, - goal: crate::next_solver::Canonical<'db, crate::next_solver::Goal<'db, Predicate<'db>>>, + goal: Canonical<'db, Goal<'db, Predicate<'db>>>, ) -> NextTraitSolveResult { let context = SolverContext(infer_ctxt.clone()); @@ -339,33 +116,21 @@ pub fn next_trait_solve_canonical_in_ctxt<'db>( let res = context.evaluate_root_goal(goal, Span::dummy(), None); - let vars = - var_values.var_values.iter().map(|g| context.0.resolve_vars_if_possible(g)).collect(); - let canonical_var_values = mini_canonicalize(context, vars); - - let res = res.map(|r| (r.has_changed, r.certainty, canonical_var_values)); + let res = res.map(|r| (r.has_changed, r.certainty)); tracing::debug!("solve_nextsolver({:?}) => {:?}", goal, res); match res { Err(_) => NextTraitSolveResult::NoSolution, - Ok((_, Certainty::Yes, args)) => NextTraitSolveResult::Certain( - convert_canonical_args_for_result(infer_ctxt.interner, args), - ), - Ok((_, Certainty::Maybe { .. }, args)) => { - let subst = convert_canonical_args_for_result(infer_ctxt.interner, args); - NextTraitSolveResult::Uncertain(chalk_ir::Canonical { - binders: subst.binders, - value: subst.value.subst, - }) - } + Ok((_, Certainty::Yes)) => NextTraitSolveResult::Certain, + Ok((_, Certainty::Maybe { .. })) => NextTraitSolveResult::Uncertain, } } /// Solve a trait goal using next trait solver. pub fn next_trait_solve_in_ctxt<'db, 'a>( infer_ctxt: &'a InferCtxt<'db>, - goal: crate::next_solver::Goal<'db, crate::next_solver::Predicate<'db>>, + goal: Goal<'db, Predicate<'db>>, ) -> Result<(HasChanged, Certainty), rustc_type_ir::solve::NoSolution> { tracing::info!(?goal); @@ -459,7 +224,7 @@ impl FnTrait { /// This should not be used in `hir-ty`, only in `hir`. pub fn implements_trait_unique<'db>( - ty: crate::next_solver::Ty<'db>, + ty: Ty<'db>, db: &'db dyn HirDatabase, env: Arc>, trait_: TraitId, @@ -474,7 +239,7 @@ pub fn implements_trait_unique_with_args<'db>( db: &'db dyn HirDatabase, env: Arc>, trait_: TraitId, - args: crate::next_solver::GenericArgs<'db>, + args: GenericArgs<'db>, ) -> bool { implements_trait_unique_impl(db, env, trait_, &mut |_| args) } @@ -483,7 +248,7 @@ fn implements_trait_unique_impl<'db>( db: &'db dyn HirDatabase, env: Arc>, trait_: TraitId, - create_args: &mut dyn FnMut(&InferCtxt<'db>) -> crate::next_solver::GenericArgs<'db>, + create_args: &mut dyn FnMut(&InferCtxt<'db>) -> GenericArgs<'db>, ) -> bool { let interner = DbInterner::new_with(db, Some(env.krate), env.block); // FIXME(next-solver): I believe this should be `PostAnalysis`. @@ -491,7 +256,7 @@ fn implements_trait_unique_impl<'db>( let args = create_args(&infcx); let trait_ref = rustc_type_ir::TraitRef::new_from_args(interner, trait_.into(), args); - let goal = crate::next_solver::Goal::new(interner, env.env, trait_ref); + let goal = Goal::new(interner, env.env, trait_ref); let result = crate::traits::next_trait_solve_in_ctxt(&infcx, goal); matches!(result, Ok((_, Certainty::Yes))) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs b/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs index e989e4c006ff..ca5e33fe6ad0 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs @@ -1,41 +1,30 @@ //! Helper functions for working with def, which don't need to be a separate //! query, but can't be computed directly from `*Data` (ie, which need a `db`). -use std::{cell::LazyCell, iter}; +use std::cell::LazyCell; use base_db::{ Crate, target::{self, TargetData}, }; -use chalk_ir::{DebruijnIndex, fold::FallibleTypeFolder}; use hir_def::{ - EnumId, EnumVariantId, FunctionId, Lookup, TraitId, TypeAliasId, TypeOrConstParamId, + EnumId, EnumVariantId, FunctionId, Lookup, TraitId, db::DefDatabase, hir::generics::WherePredicate, lang_item::LangItem, resolver::{HasResolver, TypeNs}, type_ref::{TraitBoundModifier, TypeRef}, }; -use hir_expand::name::Name; use intern::sym; use rustc_abi::TargetDataLayout; -use rustc_hash::FxHashSet; -use rustc_type_ir::inherent::{IntoKind, SliceLike}; use smallvec::{SmallVec, smallvec}; use span::Edition; use crate::{ - ChalkTraitId, Const, ConstScalar, Interner, Substitution, TargetFeatures, TraitRef, - TraitRefExt, Ty, - consteval::unknown_const, + TargetFeatures, db::HirDatabase, layout::{Layout, TagEncoding}, mir::pad16, - next_solver::{ - DbInterner, - mapping::{ChalkToNextSolver, NextSolverToChalk, convert_args_for_result}, - }, - to_chalk_trait_id, }; pub(crate) fn fn_traits(db: &dyn DefDatabase, krate: Crate) -> impl Iterator + '_ { @@ -76,49 +65,6 @@ pub fn all_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> SmallVec<[Trai result } -/// Given a trait ref (`Self: Trait`), builds all the implied trait refs for -/// super traits. The original trait ref will be included. So the difference to -/// `all_super_traits` is that we keep track of type parameters; for example if -/// we have `Self: Trait` and `Trait: OtherTrait` we'll get -/// `Self: OtherTrait`. -pub(super) fn all_super_trait_refs( - db: &dyn HirDatabase, - trait_ref: TraitRef, - cb: impl FnMut(TraitRef) -> Option, -) -> Option { - let seen = iter::once(trait_ref.trait_id).collect(); - SuperTraits { db, seen, stack: vec![trait_ref] }.find_map(cb) -} - -struct SuperTraits<'a> { - db: &'a dyn HirDatabase, - stack: Vec, - seen: FxHashSet, -} - -impl SuperTraits<'_> { - fn elaborate(&mut self, trait_ref: &TraitRef) { - direct_super_trait_refs(self.db, trait_ref, |trait_ref| { - if !self.seen.contains(&trait_ref.trait_id) { - self.stack.push(trait_ref); - } - }); - } -} - -impl Iterator for SuperTraits<'_> { - type Item = TraitRef; - - fn next(&mut self) -> Option { - if let Some(next) = self.stack.pop() { - self.elaborate(&next); - Some(next) - } else { - None - } - } -} - fn direct_super_traits_cb(db: &dyn DefDatabase, trait_: TraitId, cb: impl FnMut(TraitId)) { let resolver = LazyCell::new(|| trait_.resolver(db)); let (generic_params, store) = db.generic_params_and_store(trait_.into()); @@ -149,62 +95,6 @@ fn direct_super_traits_cb(db: &dyn DefDatabase, trait_: TraitId, cb: impl FnMut( .for_each(cb); } -fn direct_super_trait_refs(db: &dyn HirDatabase, trait_ref: &TraitRef, cb: impl FnMut(TraitRef)) { - let interner = DbInterner::new_with(db, None, None); - let generic_params = db.generic_params(trait_ref.hir_trait_id().into()); - let trait_self = match generic_params.trait_self_param() { - Some(p) => TypeOrConstParamId { parent: trait_ref.hir_trait_id().into(), local_id: p }, - None => return, - }; - let trait_ref_args: crate::next_solver::GenericArgs<'_> = - trait_ref.substitution.to_nextsolver(interner); - db.generic_predicates_for_param_ns(trait_self.parent, trait_self, None) - .iter() - .filter_map(|pred| { - let pred = pred.kind(); - // FIXME: how to correctly handle higher-ranked bounds here? - let pred = pred.no_bound_vars().expect("FIXME unexpected higher-ranked trait bound"); - match pred { - rustc_type_ir::ClauseKind::Trait(t) => { - let t = - rustc_type_ir::EarlyBinder::bind(t).instantiate(interner, trait_ref_args); - let trait_id = to_chalk_trait_id(t.def_id().0); - - let substitution = - convert_args_for_result(interner, t.trait_ref.args.as_slice()); - let tr = chalk_ir::TraitRef { trait_id, substitution }; - Some(tr) - } - _ => None, - } - }) - .for_each(cb); -} - -pub(super) fn associated_type_by_name_including_super_traits( - db: &dyn HirDatabase, - trait_ref: TraitRef, - name: &Name, -) -> Option<(TraitRef, TypeAliasId)> { - all_super_trait_refs(db, trait_ref, |t| { - let assoc_type = t.hir_trait_id().trait_items(db).associated_type_by_name(name)?; - Some((t, assoc_type)) - }) -} - -pub(crate) struct ClosureSubst<'a>(pub(crate) &'a Substitution); - -impl<'a> ClosureSubst<'a> { - pub(crate) fn sig_ty(&self, db: &dyn HirDatabase) -> Ty { - let interner = DbInterner::new_with(db, None, None); - let subst = - >>::to_nextsolver( - self.0, interner, - ); - subst.split_closure_args_untupled().closure_sig_as_fn_ptr_ty.to_chalk(interner) - } -} - #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum Unsafety { Safe, @@ -277,41 +167,6 @@ pub fn is_fn_unsafe_to_call( } } -pub(crate) struct UnevaluatedConstEvaluatorFolder<'a> { - pub(crate) db: &'a dyn HirDatabase, -} - -impl FallibleTypeFolder for UnevaluatedConstEvaluatorFolder<'_> { - type Error = (); - - fn as_dyn(&mut self) -> &mut dyn FallibleTypeFolder { - self - } - - fn interner(&self) -> Interner { - Interner - } - - fn try_fold_const( - &mut self, - constant: Const, - _outer_binder: DebruijnIndex, - ) -> Result { - if let chalk_ir::ConstValue::Concrete(c) = &constant.data(Interner).value - && let ConstScalar::UnevaluatedConst(id, subst) = &c.interned - { - let interner = DbInterner::conjure(); - if let Ok(eval) = self.db.const_eval(*id, subst.to_nextsolver(interner), None) { - return Ok(eval.to_chalk(interner)); - } else { - return Ok(unknown_const(constant.data(Interner).ty.to_nextsolver(interner)) - .to_chalk(interner)); - } - } - Ok(constant) - } -} - pub(crate) fn detect_variant_from_bytes<'a>( layout: &'a Layout, db: &dyn HirDatabase, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/variance.rs b/src/tools/rust-analyzer/crates/hir-ty/src/variance.rs index 0ff110106ebe..b57bf03f2472 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/variance.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/variance.rs @@ -13,43 +13,45 @@ //! by the next salsa version. If not, we will likely have to adapt and go with the rustc approach //! while installing firewall per item queries to prevent invalidation issues. -use crate::db::HirDatabase; -use crate::generics::{Generics, generics}; -use crate::next_solver::DbInterner; -use crate::next_solver::mapping::{ChalkToNextSolver, NextSolverToChalk}; -use crate::{ - AliasTy, Const, ConstScalar, DynTyExt, GenericArg, GenericArgData, Interner, Lifetime, - LifetimeData, Ty, TyKind, +use hir_def::{AdtId, GenericDefId, GenericParamId, VariantId, signatures::StructFlags}; +use rustc_ast_ir::Mutability; +use rustc_type_ir::{ + Variance, + inherent::{AdtDef, IntoKind, SliceLike}, }; -use chalk_ir::Mutability; -use hir_def::signatures::StructFlags; -use hir_def::{AdtId, GenericDefId, GenericParamId, VariantId}; -use std::fmt; -use std::ops::Not; use stdx::never; -use triomphe::Arc; -pub(crate) fn variances_of(db: &dyn HirDatabase, def: GenericDefId) -> Option> { +use crate::{ + db::HirDatabase, + generics::{Generics, generics}, + next_solver::{ + Const, ConstKind, DbInterner, ExistentialPredicate, GenericArg, GenericArgs, Region, + RegionKind, Term, Ty, TyKind, VariancesOf, + }, +}; + +pub(crate) fn variances_of(db: &dyn HirDatabase, def: GenericDefId) -> VariancesOf<'_> { tracing::debug!("variances_of(def={:?})", def); + let interner = DbInterner::new_with(db, None, None); match def { GenericDefId::FunctionId(_) => (), GenericDefId::AdtId(adt) => { if let AdtId::StructId(id) = adt { let flags = &db.struct_signature(id).flags; if flags.contains(StructFlags::IS_UNSAFE_CELL) { - return Some(Arc::from_iter(vec![Variance::Invariant; 1])); + return VariancesOf::new_from_iter(interner, [Variance::Invariant]); } else if flags.contains(StructFlags::IS_PHANTOM_DATA) { - return Some(Arc::from_iter(vec![Variance::Covariant; 1])); + return VariancesOf::new_from_iter(interner, [Variance::Covariant]); } } } - _ => return None, + _ => return VariancesOf::new_from_iter(interner, []), } let generics = generics(db, def); let count = generics.len(); if count == 0 { - return None; + return VariancesOf::new_from_iter(interner, []); } let mut variances = Context { generics, variances: vec![Variance::Bivariant; count], db }.solve(); @@ -69,7 +71,7 @@ pub(crate) fn variances_of(db: &dyn HirDatabase, def: GenericDefId) -> Option Option Variance { + // Greatest lower bound of the variance lattice as defined in The Paper: + // + // * + // - + + // o + match (v1, v2) { + (Variance::Invariant, _) | (_, Variance::Invariant) => Variance::Invariant, + + (Variance::Covariant, Variance::Contravariant) => Variance::Invariant, + (Variance::Contravariant, Variance::Covariant) => Variance::Invariant, + + (Variance::Covariant, Variance::Covariant) => Variance::Covariant, + + (Variance::Contravariant, Variance::Contravariant) => Variance::Contravariant, + + (x, Variance::Bivariant) | (Variance::Bivariant, x) => x, + } +} + pub(crate) fn variances_of_cycle_initial( db: &dyn HirDatabase, def: GenericDefId, -) -> Option> { +) -> VariancesOf<'_> { + let interner = DbInterner::new_with(db, None, None); let generics = generics(db, def); let count = generics.len(); - if count == 0 { - return None; - } // FIXME(next-solver): Returns `Invariance` and not `Bivariance` here, see the comment in the main query. - Some(Arc::from(vec![Variance::Invariant; count])) -} - -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] -pub enum Variance { - Covariant, // T <: T iff A <: B -- e.g., function return type - Invariant, // T <: T iff B == A -- e.g., type of mutable cell - Contravariant, // T <: T iff B <: A -- e.g., function param type - Bivariant, // T <: T -- e.g., unused type parameter -} - -impl fmt::Display for Variance { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Variance::Covariant => write!(f, "covariant"), - Variance::Invariant => write!(f, "invariant"), - Variance::Contravariant => write!(f, "contravariant"), - Variance::Bivariant => write!(f, "bivariant"), - } - } -} - -impl Variance { - /// `a.xform(b)` combines the variance of a context with the - /// variance of a type with the following meaning. If we are in a - /// context with variance `a`, and we encounter a type argument in - /// a position with variance `b`, then `a.xform(b)` is the new - /// variance with which the argument appears. - /// - /// Example 1: - /// ```ignore (illustrative) - /// *mut Vec - /// ``` - /// Here, the "ambient" variance starts as covariant. `*mut T` is - /// invariant with respect to `T`, so the variance in which the - /// `Vec` appears is `Covariant.xform(Invariant)`, which - /// yields `Invariant`. Now, the type `Vec` is covariant with - /// respect to its type argument `T`, and hence the variance of - /// the `i32` here is `Invariant.xform(Covariant)`, which results - /// (again) in `Invariant`. - /// - /// Example 2: - /// ```ignore (illustrative) - /// fn(*const Vec, *mut Vec` appears is - /// `Contravariant.xform(Covariant)` or `Contravariant`. The same - /// is true for its `i32` argument. In the `*mut T` case, the - /// variance of `Vec` is `Contravariant.xform(Invariant)`, - /// and hence the outermost type is `Invariant` with respect to - /// `Vec` (and its `i32` argument). - /// - /// Source: Figure 1 of "Taming the Wildcards: - /// Combining Definition- and Use-Site Variance" published in PLDI'11. - fn xform(self, v: Variance) -> Variance { - match (self, v) { - // Figure 1, column 1. - (Variance::Covariant, Variance::Covariant) => Variance::Covariant, - (Variance::Covariant, Variance::Contravariant) => Variance::Contravariant, - (Variance::Covariant, Variance::Invariant) => Variance::Invariant, - (Variance::Covariant, Variance::Bivariant) => Variance::Bivariant, - - // Figure 1, column 2. - (Variance::Contravariant, Variance::Covariant) => Variance::Contravariant, - (Variance::Contravariant, Variance::Contravariant) => Variance::Covariant, - (Variance::Contravariant, Variance::Invariant) => Variance::Invariant, - (Variance::Contravariant, Variance::Bivariant) => Variance::Bivariant, - - // Figure 1, column 3. - (Variance::Invariant, _) => Variance::Invariant, - - // Figure 1, column 4. - (Variance::Bivariant, _) => Variance::Bivariant, - } - } - - fn glb(self, v: Variance) -> Variance { - // Greatest lower bound of the variance lattice as - // defined in The Paper: - // - // * - // - + - // o - match (self, v) { - (Variance::Invariant, _) | (_, Variance::Invariant) => Variance::Invariant, - - (Variance::Covariant, Variance::Contravariant) => Variance::Invariant, - (Variance::Contravariant, Variance::Covariant) => Variance::Invariant, - - (Variance::Covariant, Variance::Covariant) => Variance::Covariant, - - (Variance::Contravariant, Variance::Contravariant) => Variance::Contravariant, - - (x, Variance::Bivariant) | (Variance::Bivariant, x) => x, - } - } - - pub fn invariant(self) -> Self { - self.xform(Variance::Invariant) - } - - pub fn covariant(self) -> Self { - self.xform(Variance::Covariant) - } - - pub fn contravariant(self) -> Self { - self.xform(Variance::Contravariant) - } + VariancesOf::new_from_iter(interner, std::iter::repeat_n(Variance::Invariant, count)) } struct Context<'db> { @@ -213,17 +121,16 @@ struct Context<'db> { variances: Vec, } -impl Context<'_> { +impl<'db> Context<'db> { fn solve(mut self) -> Vec { tracing::debug!("solve(generics={:?})", self.generics); match self.generics.def() { GenericDefId::AdtId(adt) => { let db = self.db; let mut add_constraints_from_variant = |variant| { - let subst = self.generics.placeholder_subst(db); for (_, field) in db.field_types(variant).iter() { self.add_constraints_from_ty( - &field.clone().substitute(Interner, &subst), + field.instantiate_identity(), Variance::Covariant, ); } @@ -239,16 +146,9 @@ impl Context<'_> { } } GenericDefId::FunctionId(f) => { - let subst = self.generics.placeholder_subst(self.db); - let interner = DbInterner::new_with(self.db, None, None); - let args: crate::next_solver::GenericArgs<'_> = subst.to_nextsolver(interner); - let sig = self - .db - .callable_item_signature(f.into()) - .instantiate(interner, args) - .skip_binder() - .to_chalk(interner); - self.add_constraints_from_sig(sig.params_and_return.iter(), Variance::Covariant); + let sig = + self.db.callable_item_signature(f.into()).instantiate_identity().skip_binder(); + self.add_constraints_from_sig(sig.inputs_and_output.iter(), Variance::Covariant); } _ => {} } @@ -276,122 +176,102 @@ impl Context<'_> { /// Adds constraints appropriate for an instance of `ty` appearing /// in a context with the generics defined in `generics` and /// ambient variance `variance` - fn add_constraints_from_ty(&mut self, ty: &Ty, variance: Variance) { + fn add_constraints_from_ty(&mut self, ty: Ty<'db>, variance: Variance) { tracing::debug!("add_constraints_from_ty(ty={:?}, variance={:?})", ty, variance); - match ty.kind(Interner) { - TyKind::Scalar(_) | TyKind::Never | TyKind::Str | TyKind::Foreign(..) => { + match ty.kind() { + TyKind::Int(_) + | TyKind::Uint(_) + | TyKind::Float(_) + | TyKind::Char + | TyKind::Bool + | TyKind::Never + | TyKind::Str + | TyKind::Foreign(..) => { // leaf type -- noop } - TyKind::FnDef(..) | TyKind::Coroutine(..) | TyKind::Closure(..) => { + TyKind::FnDef(..) + | TyKind::Coroutine(..) + | TyKind::CoroutineClosure(..) + | TyKind::Closure(..) => { never!("Unexpected unnameable type in variance computation: {:?}", ty); } - TyKind::Ref(mutbl, lifetime, ty) => { + TyKind::Ref(lifetime, ty, mutbl) => { self.add_constraints_from_region(lifetime, variance); - self.add_constraints_from_mt(ty, *mutbl, variance); + self.add_constraints_from_mt(ty, mutbl, variance); } TyKind::Array(typ, len) => { - self.add_constraints_from_const(len, variance); + self.add_constraints_from_const(len); self.add_constraints_from_ty(typ, variance); } TyKind::Slice(typ) => { self.add_constraints_from_ty(typ, variance); } - TyKind::Raw(mutbl, ty) => { - self.add_constraints_from_mt(ty, *mutbl, variance); + TyKind::RawPtr(ty, mutbl) => { + self.add_constraints_from_mt(ty, mutbl, variance); } - TyKind::Tuple(_, subtys) => { - for subty in subtys.type_parameters(Interner) { - self.add_constraints_from_ty(&subty, variance); + TyKind::Tuple(subtys) => { + for subty in subtys { + self.add_constraints_from_ty(subty, variance); } } TyKind::Adt(def, args) => { - self.add_constraints_from_args(def.0.into(), args.as_slice(Interner), variance); + self.add_constraints_from_args(def.def_id().0.into(), args, variance); } - TyKind::Alias(AliasTy::Opaque(opaque)) => { - self.add_constraints_from_invariant_args( - opaque.substitution.as_slice(Interner), - variance, - ); + TyKind::Alias(_, alias) => { + // FIXME: Probably not correct wrt. opaques. + self.add_constraints_from_invariant_args(alias.args); } - TyKind::Alias(AliasTy::Projection(proj)) => { - self.add_constraints_from_invariant_args( - proj.substitution.as_slice(Interner), - variance, - ); - } - // FIXME: check this - TyKind::AssociatedType(_, subst) => { - self.add_constraints_from_invariant_args(subst.as_slice(Interner), variance); - } - // FIXME: check this - TyKind::OpaqueType(_, subst) => { - self.add_constraints_from_invariant_args(subst.as_slice(Interner), variance); - } - TyKind::Dyn(it) => { + TyKind::Dynamic(bounds, region) => { // The type `dyn Trait +'a` is covariant w/r/t `'a`: - self.add_constraints_from_region(&it.lifetime, variance); + self.add_constraints_from_region(region, variance); - if let Some(trait_ref) = it.principal() { - // Trait are always invariant so we can take advantage of that. - self.add_constraints_from_invariant_args( - trait_ref - .map(|it| it.map(|it| it.substitution.clone())) - .substitute( - Interner, - &[GenericArg::new( - Interner, - chalk_ir::GenericArgData::Ty(TyKind::Error.intern(Interner)), - )], - ) - .skip_binders() - .as_slice(Interner), - variance, - ); + for bound in bounds { + match bound.skip_binder() { + ExistentialPredicate::Trait(trait_ref) => { + self.add_constraints_from_invariant_args(trait_ref.args) + } + ExistentialPredicate::Projection(projection) => { + self.add_constraints_from_invariant_args(projection.args); + match projection.term { + Term::Ty(ty) => { + self.add_constraints_from_ty(ty, Variance::Invariant) + } + Term::Const(konst) => self.add_constraints_from_const(konst), + } + } + ExistentialPredicate::AutoTrait(_) => {} + } } - - // FIXME - // for projection in data.projection_bounds() { - // match projection.skip_binder().term.unpack() { - // TyKind::TermKind::Ty(ty) => { - // self.add_constraints_from_ty( ty, self.invariant); - // } - // TyKind::TermKind::Const(c) => { - // self.add_constraints_from_const( c, self.invariant) - // } - // } - // } } // Chalk has no params, so use placeholders for now? - TyKind::Placeholder(index) => { - let idx = crate::from_placeholder_idx(self.db, *index).0; - let index = self.generics.type_or_const_param_idx(idx).unwrap(); - self.constrain(index, variance); + TyKind::Param(param) => self.constrain(param.index as usize, variance), + TyKind::FnPtr(sig, _) => { + self.add_constraints_from_sig(sig.skip_binder().inputs_and_output.iter(), variance); } - TyKind::Function(f) => { - self.add_constraints_from_sig( - f.substitution.0.iter(Interner).filter_map(move |p| p.ty(Interner)), - variance, - ); - } - TyKind::Error => { + TyKind::Error(_) => { // we encounter this when walking the trait references for object // types, where we use Error as the Self type } - TyKind::CoroutineWitness(..) | TyKind::BoundVar(..) | TyKind::InferenceVar(..) => { + TyKind::Bound(..) => {} + TyKind::CoroutineWitness(..) + | TyKind::Placeholder(..) + | TyKind::Infer(..) + | TyKind::UnsafeBinder(..) + | TyKind::Pat(..) => { never!("unexpected type encountered in variance inference: {:?}", ty) } } } - fn add_constraints_from_invariant_args(&mut self, args: &[GenericArg], variance: Variance) { - let variance_i = variance.invariant(); - - for k in args { - match k.data(Interner) { - GenericArgData::Lifetime(lt) => self.add_constraints_from_region(lt, variance_i), - GenericArgData::Ty(ty) => self.add_constraints_from_ty(ty, variance_i), - GenericArgData::Const(val) => self.add_constraints_from_const(val, variance_i), + fn add_constraints_from_invariant_args(&mut self, args: GenericArgs<'db>) { + for k in args.iter() { + match k { + GenericArg::Lifetime(lt) => { + self.add_constraints_from_region(lt, Variance::Invariant) + } + GenericArg::Ty(ty) => self.add_constraints_from_ty(ty, Variance::Invariant), + GenericArg::Const(val) => self.add_constraints_from_const(val), } } } @@ -401,51 +281,40 @@ impl Context<'_> { fn add_constraints_from_args( &mut self, def_id: GenericDefId, - args: &[GenericArg], + args: GenericArgs<'db>, variance: Variance, ) { - // We don't record `inferred_starts` entries for empty generics. if args.is_empty() { return; } - let Some(variances) = self.db.variances_of(def_id) else { - return; - }; + let variances = self.db.variances_of(def_id); - for (i, k) in args.iter().enumerate() { - match k.data(Interner) { - GenericArgData::Lifetime(lt) => { - self.add_constraints_from_region(lt, variance.xform(variances[i])) - } - GenericArgData::Ty(ty) => { - self.add_constraints_from_ty(ty, variance.xform(variances[i])) - } - GenericArgData::Const(val) => self.add_constraints_from_const(val, variance), + for (k, v) in args.iter().zip(variances) { + match k { + GenericArg::Lifetime(lt) => self.add_constraints_from_region(lt, variance.xform(v)), + GenericArg::Ty(ty) => self.add_constraints_from_ty(ty, variance.xform(v)), + GenericArg::Const(val) => self.add_constraints_from_const(val), } } } /// Adds constraints appropriate for a const expression `val` /// in a context with ambient variance `variance` - fn add_constraints_from_const(&mut self, c: &Const, variance: Variance) { - match &c.data(Interner).value { - chalk_ir::ConstValue::Concrete(c) => { - if let ConstScalar::UnevaluatedConst(_, subst) = &c.interned { - self.add_constraints_from_invariant_args(subst.as_slice(Interner), variance); - } - } + fn add_constraints_from_const(&mut self, c: Const<'db>) { + match c.kind() { + ConstKind::Unevaluated(c) => self.add_constraints_from_invariant_args(c.args), _ => {} } } /// Adds constraints appropriate for a function with signature /// `sig` appearing in a context with ambient variance `variance` - fn add_constraints_from_sig<'a>( + fn add_constraints_from_sig( &mut self, - mut sig_tys: impl DoubleEndedIterator, + mut sig_tys: impl DoubleEndedIterator>, variance: Variance, ) { - let contra = variance.contravariant(); + let contra = variance.xform(Variance::Contravariant); let Some(output) = sig_tys.next_back() else { return never!("function signature has no return type"); }; @@ -457,27 +326,26 @@ impl Context<'_> { /// Adds constraints appropriate for a region appearing in a /// context with ambient variance `variance` - fn add_constraints_from_region(&mut self, region: &Lifetime, variance: Variance) { + fn add_constraints_from_region(&mut self, region: Region<'db>, variance: Variance) { tracing::debug!( "add_constraints_from_region(region={:?}, variance={:?})", region, variance ); - match region.data(Interner) { - LifetimeData::Placeholder(index) => { - let idx = crate::lt_from_placeholder_idx(self.db, *index).0; - let inferred = self.generics.lifetime_idx(idx).unwrap(); - self.constrain(inferred, variance); - } - LifetimeData::Static => {} - LifetimeData::BoundVar(..) => { + match region.kind() { + RegionKind::ReEarlyParam(param) => self.constrain(param.index as usize, variance), + RegionKind::ReStatic => {} + RegionKind::ReBound(..) => { // Either a higher-ranked region inside of a type or a // late-bound function parameter. // // We do not compute constraints for either of these. } - LifetimeData::Error => {} - LifetimeData::Phantom(..) | LifetimeData::InferenceVar(..) | LifetimeData::Erased => { + RegionKind::ReError(_) => {} + RegionKind::ReLateParam(..) + | RegionKind::RePlaceholder(..) + | RegionKind::ReVar(..) + | RegionKind::ReErased => { // We don't expect to see anything but 'static or bound // regions when visiting member types or method types. never!( @@ -491,11 +359,11 @@ impl Context<'_> { /// Adds constraints appropriate for a mutability-type pair /// appearing in a context with ambient variance `variance` - fn add_constraints_from_mt(&mut self, ty: &Ty, mt: Mutability, variance: Variance) { + fn add_constraints_from_mt(&mut self, ty: Ty<'db>, mt: Mutability, variance: Variance) { self.add_constraints_from_ty( ty, match mt { - Mutability::Mut => variance.invariant(), + Mutability::Mut => Variance::Invariant, Mutability::Not => variance, }, ); @@ -508,7 +376,7 @@ impl Context<'_> { self.variances[index], variance ); - self.variances[index] = self.variances[index].glb(variance); + self.variances[index] = glb(self.variances[index], variance); } } @@ -519,6 +387,7 @@ mod tests { AdtId, GenericDefId, ModuleDefId, hir::generics::GenericParamDataRef, src::HasSource, }; use itertools::Itertools; + use rustc_type_ir::{Variance, inherent::SliceLike}; use stdx::format_to; use syntax::{AstNode, ast::HasName}; use test_fixture::WithFixture; @@ -1037,26 +906,21 @@ struct FixedPoint(&'static FixedPoint<(), T, U>, V); let loc = it.lookup(&db); loc.source(&db).value.name().unwrap() } - GenericDefId::TraitId(it) => { - let loc = it.lookup(&db); - loc.source(&db).value.name().unwrap() - } - GenericDefId::TypeAliasId(it) => { - let loc = it.lookup(&db); - loc.source(&db).value.name().unwrap() - } - GenericDefId::ImplId(_) => return None, - GenericDefId::ConstId(_) => return None, - GenericDefId::StaticId(_) => return None, + GenericDefId::TraitId(_) + | GenericDefId::TypeAliasId(_) + | GenericDefId::ImplId(_) + | GenericDefId::ConstId(_) + | GenericDefId::StaticId(_) => return None, }, )) }) .sorted_by_key(|(_, n)| n.syntax().text_range().start()); let mut res = String::new(); for (def, name) in defs { - let Some(variances) = db.variances_of(def) else { + let variances = db.variances_of(def); + if variances.is_empty() { continue; - }; + } format_to!( res, "{name}[{}]\n", @@ -1072,10 +936,16 @@ struct FixedPoint(&'static FixedPoint<(), T, U>, V); &lifetime_param_data.name } }) - .zip_eq(&*variances) + .zip_eq(variances) .format_with(", ", |(name, var), f| f(&format_args!( - "{}: {var}", - name.as_str() + "{}: {}", + name.as_str(), + match var { + Variance::Covariant => "covariant", + Variance::Invariant => "invariant", + Variance::Contravariant => "contravariant", + Variance::Bivariant => "bivariant", + }, ))) ); } diff --git a/src/tools/rust-analyzer/crates/hir/src/display.rs b/src/tools/rust-analyzer/crates/hir/src/display.rs index 49bf843367d3..d61c2eca8347 100644 --- a/src/tools/rust-analyzer/crates/hir/src/display.rs +++ b/src/tools/rust-analyzer/crates/hir/src/display.rs @@ -11,14 +11,15 @@ use hir_def::{ type_ref::{TypeBound, TypeRef, TypeRefId}, }; use hir_ty::{ - AliasEq, AliasTy, Interner, ProjectionTyExt, TraitRefExt, TyBuilder, TyKind, WhereClause, db::HirDatabase, display::{ HirDisplay, HirDisplayError, HirDisplayWithExpressionStore, HirFormatter, SizedByDefault, hir_display_with_store, write_bounds_like_dyn_trait_with_prefix, write_visibility, }, + next_solver::ClauseKind, }; use itertools::Itertools; +use rustc_type_ir::inherent::IntoKind; use crate::{ Adt, AsAssocItem, AssocItem, AssocItemContainer, Const, ConstParam, Crate, Enum, @@ -27,8 +28,8 @@ use crate::{ TypeAlias, TypeNs, TypeOrConstParam, TypeParam, Union, Variant, }; -impl HirDisplay for Function { - fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { +impl<'db> HirDisplay<'db> for Function { + fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> { let db = f.db; let data = db.function_signature(self.id); let container = self.as_assoc_item(db).map(|it| it.container(db)); @@ -184,7 +185,10 @@ impl HirDisplay for Function { } } -fn write_impl_header(impl_: &Impl, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { +fn write_impl_header<'db>( + impl_: &Impl, + f: &mut HirFormatter<'_, 'db>, +) -> Result<(), HirDisplayError> { let db = f.db; f.write_str("impl")?; @@ -202,8 +206,8 @@ fn write_impl_header(impl_: &Impl, f: &mut HirFormatter<'_>) -> Result<(), HirDi Ok(()) } -impl HirDisplay for SelfParam { - fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { +impl<'db> HirDisplay<'db> for SelfParam { + fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> { let data = f.db.function_signature(self.func); let param = *data.params.first().unwrap(); match &data.store[param] { @@ -228,8 +232,8 @@ impl HirDisplay for SelfParam { } } -impl HirDisplay for Adt { - fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { +impl<'db> HirDisplay<'db> for Adt { + fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> { match self { Adt::Struct(it) => it.hir_fmt(f), Adt::Union(it) => it.hir_fmt(f), @@ -238,8 +242,8 @@ impl HirDisplay for Adt { } } -impl HirDisplay for Struct { - fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { +impl<'db> HirDisplay<'db> for Struct { + fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> { let module_id = self.module(f.db).id; // FIXME: Render repr if its set explicitly? write_visibility(module_id, self.visibility(f.db), f)?; @@ -279,8 +283,8 @@ impl HirDisplay for Struct { } } -impl HirDisplay for Enum { - fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { +impl<'db> HirDisplay<'db> for Enum { + fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> { write_visibility(self.module(f.db).id, self.visibility(f.db), f)?; f.write_str("enum ")?; write!(f, "{}", self.name(f.db).display(f.db, f.edition()))?; @@ -296,8 +300,8 @@ impl HirDisplay for Enum { } } -impl HirDisplay for Union { - fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { +impl<'db> HirDisplay<'db> for Union { + fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> { write_visibility(self.module(f.db).id, self.visibility(f.db), f)?; f.write_str("union ")?; write!(f, "{}", self.name(f.db).display(f.db, f.edition()))?; @@ -312,12 +316,12 @@ impl HirDisplay for Union { } } -fn write_fields( +fn write_fields<'db>( fields: &[Field], has_where_clause: bool, limit: usize, in_line: bool, - f: &mut HirFormatter<'_>, + f: &mut HirFormatter<'_, 'db>, ) -> Result<(), HirDisplayError> { let count = fields.len().min(limit); let (indent, separator) = if in_line { ("", ' ') } else { (" ", '\n') }; @@ -346,11 +350,11 @@ fn write_fields( Ok(()) } -fn write_variants( +fn write_variants<'db>( variants: &[Variant], has_where_clause: bool, limit: usize, - f: &mut HirFormatter<'_>, + f: &mut HirFormatter<'_, 'db>, ) -> Result<(), HirDisplayError> { let count = variants.len().min(limit); f.write_char(if !has_where_clause { ' ' } else { '\n' })?; @@ -386,23 +390,23 @@ fn write_variants( Ok(()) } -impl HirDisplay for Field { - fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { +impl<'db> HirDisplay<'db> for Field { + fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> { write_visibility(self.parent.module(f.db).id, self.visibility(f.db), f)?; write!(f, "{}: ", self.name(f.db).display(f.db, f.edition()))?; self.ty(f.db).hir_fmt(f) } } -impl HirDisplay for TupleField { - fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { +impl<'db> HirDisplay<'db> for TupleField { + fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> { write!(f, "pub {}: ", self.name().display(f.db, f.edition()))?; self.ty(f.db).hir_fmt(f) } } -impl HirDisplay for Variant { - fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { +impl<'db> HirDisplay<'db> for Variant { + fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> { write!(f, "{}", self.name(f.db).display(f.db, f.edition()))?; let data = self.id.fields(f.db); match data.shape { @@ -431,20 +435,20 @@ impl HirDisplay for Variant { } } -impl HirDisplay for Type<'_> { - fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { +impl<'db> HirDisplay<'db> for Type<'db> { + fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> { self.ty.hir_fmt(f) } } -impl HirDisplay for TypeNs<'_> { - fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { +impl<'db> HirDisplay<'db> for TypeNs<'db> { + fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> { self.ty.hir_fmt(f) } } -impl HirDisplay for ExternCrateDecl { - fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { +impl<'db> HirDisplay<'db> for ExternCrateDecl { + fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> { write_visibility(self.module(f.db).id, self.visibility(f.db), f)?; f.write_str("extern crate ")?; write!(f, "{}", self.name(f.db).display(f.db, f.edition()))?; @@ -455,8 +459,8 @@ impl HirDisplay for ExternCrateDecl { } } -impl HirDisplay for GenericParam { - fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { +impl<'db> HirDisplay<'db> for GenericParam { + fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> { match self { GenericParam::TypeParam(it) => it.hir_fmt(f), GenericParam::ConstParam(it) => it.hir_fmt(f), @@ -465,8 +469,8 @@ impl HirDisplay for GenericParam { } } -impl HirDisplay for TypeOrConstParam { - fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { +impl<'db> HirDisplay<'db> for TypeOrConstParam { + fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> { match self.split(f.db) { either::Either::Left(it) => it.hir_fmt(f), either::Either::Right(it) => it.hir_fmt(f), @@ -474,27 +478,22 @@ impl HirDisplay for TypeOrConstParam { } } -impl HirDisplay for TypeParam { - fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { +impl<'db> HirDisplay<'db> for TypeParam { + fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> { let params = f.db.generic_params(self.id.parent()); let param_data = ¶ms[self.id.local_id()]; - let substs = TyBuilder::placeholder_subst(f.db, self.id.parent()); let krate = self.id.parent().krate(f.db).id; - let ty = TyKind::Placeholder(hir_ty::to_placeholder_idx_no_index(f.db, self.id.into())) - .intern(Interner); + let ty = self.ty(f.db).ty; let predicates = f.db.generic_predicates(self.id.parent()); let predicates = predicates - .iter() - .cloned() - .map(|pred| pred.substitute(Interner, &substs)) - .filter(|wc| match wc.skip_binders() { - WhereClause::Implemented(tr) => tr.self_type_parameter(Interner) == ty, - WhereClause::AliasEq(AliasEq { alias: AliasTy::Projection(proj), ty: _ }) => { - proj.self_type_parameter(f.db) == ty - } - WhereClause::AliasEq(_) => false, - WhereClause::TypeOutlives(to) => to.ty == ty, - WhereClause::LifetimeOutlives(_) => false, + .instantiate_identity() + .into_iter() + .flatten() + .filter(|wc| match wc.kind().skip_binder() { + ClauseKind::Trait(tr) => tr.self_ty() == ty, + ClauseKind::Projection(proj) => proj.self_ty() == ty, + ClauseKind::TypeOutlives(to) => to.0 == ty, + _ => false, }) .collect::>(); @@ -507,7 +506,7 @@ impl HirDisplay for TypeParam { return write_bounds_like_dyn_trait_with_prefix( f, "impl", - Either::Left(&ty), + Either::Left(ty), &predicates, SizedByDefault::Sized { anchor: krate }, ); @@ -523,23 +522,18 @@ impl HirDisplay for TypeParam { } let sized_trait = LangItem::Sized.resolve_trait(f.db, krate); - let has_only_sized_bound = predicates.iter().all(move |pred| match pred.skip_binders() { - WhereClause::Implemented(it) => Some(it.hir_trait_id()) == sized_trait, - _ => false, - }); + let has_only_sized_bound = + predicates.iter().all(move |pred| match pred.kind().skip_binder() { + ClauseKind::Trait(it) => Some(it.def_id().0) == sized_trait, + _ => false, + }); let has_only_not_sized_bound = predicates.is_empty(); if !has_only_sized_bound || has_only_not_sized_bound { let default_sized = SizedByDefault::Sized { anchor: krate }; write_bounds_like_dyn_trait_with_prefix( f, ":", - Either::Left( - &hir_ty::TyKind::Placeholder(hir_ty::to_placeholder_idx_no_index( - f.db, - self.id.into(), - )) - .intern(Interner), - ), + Either::Left(ty), &predicates, default_sized, )?; @@ -548,22 +542,22 @@ impl HirDisplay for TypeParam { } } -impl HirDisplay for LifetimeParam { - fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { +impl<'db> HirDisplay<'db> for LifetimeParam { + fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> { write!(f, "{}", self.name(f.db).display(f.db, f.edition())) } } -impl HirDisplay for ConstParam { - fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { +impl<'db> HirDisplay<'db> for ConstParam { + fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> { write!(f, "const {}: ", self.name(f.db).display(f.db, f.edition()))?; self.ty(f.db).hir_fmt(f) } } -fn write_generic_params( +fn write_generic_params<'db>( def: GenericDefId, - f: &mut HirFormatter<'_>, + f: &mut HirFormatter<'_, 'db>, ) -> Result<(), HirDisplayError> { let (params, store) = f.db.generic_params_and_store(def); if params.iter_lt().next().is_none() @@ -578,7 +572,7 @@ fn write_generic_params( f.write_char('<')?; let mut first = true; - let mut delim = |f: &mut HirFormatter<'_>| { + let mut delim = |f: &mut HirFormatter<'_, 'db>| { if first { first = false; Ok(()) @@ -622,9 +616,9 @@ fn write_generic_params( Ok(()) } -fn write_where_clause( +fn write_where_clause<'db>( def: GenericDefId, - f: &mut HirFormatter<'_>, + f: &mut HirFormatter<'_, 'db>, ) -> Result { let (params, store) = f.db.generic_params_and_store(def); if !has_disaplayable_predicates(f.db, ¶ms, &store) { @@ -653,10 +647,10 @@ fn has_disaplayable_predicates( }) } -fn write_where_predicates( +fn write_where_predicates<'db>( params: &GenericParams, store: &ExpressionStore, - f: &mut HirFormatter<'_>, + f: &mut HirFormatter<'_, 'db>, ) -> Result<(), HirDisplayError> { use WherePredicate::*; @@ -717,8 +711,8 @@ fn write_where_predicates( Ok(()) } -impl HirDisplay for Const { - fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { +impl<'db> HirDisplay<'db> for Const { + fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> { let db = f.db; let container = self.as_assoc_item(db).map(|it| it.container(db)); let mut module = self.module(db); @@ -738,8 +732,8 @@ impl HirDisplay for Const { } } -impl HirDisplay for Static { - fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { +impl<'db> HirDisplay<'db> for Static { + fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> { write_visibility(self.module(f.db).id, self.visibility(f.db), f)?; let data = f.db.static_signature(self.id); f.write_str("static ")?; @@ -752,14 +746,14 @@ impl HirDisplay for Static { } } -impl HirDisplay for TraitRef<'_> { - fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { +impl<'db> HirDisplay<'db> for TraitRef<'db> { + fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> { self.trait_ref.hir_fmt(f) } } -impl HirDisplay for Trait { - fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { +impl<'db> HirDisplay<'db> for Trait { + fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> { // FIXME(trait-alias) needs special handling to print the equal sign write_trait_header(self, f)?; let def_id = GenericDefId::TraitId(self.id); @@ -798,7 +792,10 @@ impl HirDisplay for Trait { } } -fn write_trait_header(trait_: &Trait, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { +fn write_trait_header<'db>( + trait_: &Trait, + f: &mut HirFormatter<'_, 'db>, +) -> Result<(), HirDisplayError> { write_visibility(trait_.module(f.db).id, trait_.visibility(f.db), f)?; let data = f.db.trait_signature(trait_.id); if data.flags.contains(TraitFlags::UNSAFE) { @@ -812,8 +809,8 @@ fn write_trait_header(trait_: &Trait, f: &mut HirFormatter<'_>) -> Result<(), Hi Ok(()) } -impl HirDisplay for TypeAlias { - fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { +impl<'db> HirDisplay<'db> for TypeAlias { + fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> { write_visibility(self.module(f.db).id, self.visibility(f.db), f)?; let data = f.db.type_alias_signature(self.id); write!(f, "type {}", data.name.display(f.db, f.edition()))?; @@ -835,8 +832,8 @@ impl HirDisplay for TypeAlias { } } -impl HirDisplay for Module { - fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { +impl<'db> HirDisplay<'db> for Module { + fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> { match self.parent(f.db) { Some(m) => write_visibility(m.id, self.visibility(f.db), f)?, None => { @@ -853,8 +850,8 @@ impl HirDisplay for Module { } } -impl HirDisplay for Crate { - fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { +impl<'db> HirDisplay<'db> for Crate { + fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> { match self.display_name(f.db) { Some(name) => write!(f, "extern crate {name}"), None => f.write_str("extern crate {unknown}"), @@ -862,8 +859,8 @@ impl HirDisplay for Crate { } } -impl HirDisplay for Macro { - fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { +impl<'db> HirDisplay<'db> for Macro { + fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> { match self.id { hir_def::MacroId::Macro2Id(_) => f.write_str("macro"), hir_def::MacroId::MacroRulesId(_) => f.write_str("macro_rules!"), diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index 55da27781db1..2bb2f80ecc05 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -36,6 +36,7 @@ pub mod term_search; mod display; use std::{ + fmt, mem::discriminant, ops::{ControlFlow, Not}, }; @@ -74,7 +75,7 @@ use hir_ty::{ TraitEnvironment, TyDefId, TyLoweringDiagnostic, ValueTyDefId, all_super_traits, autoderef, check_orphan_rules, consteval::try_const_usize, - db::InternedClosureId, + db::{InternedClosureId, InternedCoroutineId}, diagnostics::BodyValidationDiagnostic, direct_super_traits, known_const_to_ast, layout::{Layout as TyLayout, RustcEnumVariantIdx, RustcFieldIdx, TagEncoding}, @@ -91,7 +92,7 @@ use itertools::Itertools; use rustc_hash::FxHashSet; use rustc_type_ir::{ AliasTyKind, TypeSuperVisitable, TypeVisitable, TypeVisitor, - inherent::{AdtDef, IntoKind, SliceLike, Term as _, Ty as _}, + inherent::{AdtDef, GenericArgs as _, IntoKind, SliceLike, Term as _, Ty as _}, }; use smallvec::SmallVec; use span::{AstIdNode, Edition, FileId}; @@ -160,7 +161,7 @@ pub use { // FIXME: Properly encapsulate mir hir_ty::mir, hir_ty::{ - CastError, FnAbi, PointerCast, Variance, attach_db, attach_db_allow_change, + CastError, FnAbi, PointerCast, attach_db, attach_db_allow_change, consteval::ConstEvalError, diagnostics::UnsafetyReason, display::{ClosureStyle, DisplayTarget, HirDisplay, HirDisplayError, HirWrite}, @@ -170,6 +171,7 @@ pub use { method_resolution::TyFingerprint, mir::{MirEvalError, MirLowerError}, next_solver::abi::Safety, + next_solver::clear_tls_solver_cache, }, intern::{Symbol, sym}, }; @@ -1270,7 +1272,7 @@ impl<'db> InstantiatedField<'db> { let interner = DbInterner::new_with(db, Some(krate.base()), None); let var_id = self.inner.parent.into(); - let field = db.field_types_ns(var_id)[self.inner.id]; + let field = db.field_types(var_id)[self.inner.id]; let ty = field.instantiate(interner, self.args); TypeNs::new(db, var_id, ty) } @@ -1349,7 +1351,7 @@ impl Field { /// context of the field definition. pub fn ty<'db>(&self, db: &'db dyn HirDatabase) -> TypeNs<'db> { let var_id = self.parent.into(); - let ty = db.field_types_ns(var_id)[self.id].skip_binder(); + let ty = db.field_types(var_id)[self.id].skip_binder(); TypeNs::new(db, var_id, ty) } @@ -1367,7 +1369,7 @@ impl Field { }; let interner = DbInterner::new_with(db, None, None); let args = generic_args_from_tys(interner, def_id.into(), generics.map(|ty| ty.ty)); - let ty = db.field_types_ns(var_id)[self.id].instantiate(interner, args); + let ty = db.field_types(var_id)[self.id].instantiate(interner, args); Type::new(db, var_id, ty) } @@ -1802,7 +1804,7 @@ impl Adt { let env = db.trait_environment(self.into()); let interner = DbInterner::new_with(db, Some(env.krate), env.block); let adt_id = AdtId::from(self); - let args = GenericArgs::for_item_with_defaults(interner, adt_id.into(), |_, _, id, _| { + let args = GenericArgs::for_item_with_defaults(interner, adt_id.into(), |_, id, _| { GenericArg::error_from_id(interner, id) }); db.layout_of_adt(adt_id, args, env) @@ -4110,7 +4112,39 @@ impl GenericParam { GenericParam::ConstParam(_) => return None, GenericParam::LifetimeParam(it) => generics.lifetime_idx(it.id)?, }; - db.variances_of(parent)?.get(index).copied() + db.variances_of(parent).get(index).map(Into::into) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum Variance { + Bivariant, + Covariant, + Contravariant, + Invariant, +} + +impl From for Variance { + #[inline] + fn from(value: rustc_type_ir::Variance) -> Self { + match value { + rustc_type_ir::Variance::Covariant => Variance::Covariant, + rustc_type_ir::Variance::Invariant => Variance::Invariant, + rustc_type_ir::Variance::Contravariant => Variance::Contravariant, + rustc_type_ir::Variance::Bivariant => Variance::Bivariant, + } + } +} + +impl fmt::Display for Variance { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let description = match self { + Variance::Bivariant => "bivariant", + Variance::Covariant => "covariant", + Variance::Contravariant => "contravariant", + Variance::Invariant => "invariant", + }; + f.pad(description) } } @@ -4151,8 +4185,7 @@ impl TypeParam { let resolver = self.id.parent().resolver(db); let interner = DbInterner::new_with(db, None, None); let index = hir_ty::param_idx(db, self.id.into()).unwrap(); - let name = self.name(db).symbol().clone(); - let ty = Ty::new_param(interner, self.id, index as u32, name); + let ty = Ty::new_param(interner, self.id, index as u32); Type::new_with_resolver_inner(db, &resolver, ty) } @@ -4160,7 +4193,7 @@ impl TypeParam { /// parameter, not additional bounds that might be added e.g. by a method if /// the parameter comes from an impl! pub fn trait_bounds(self, db: &dyn HirDatabase) -> Vec { - db.generic_predicates_for_param_ns(self.id.parent(), self.id.into(), None) + db.generic_predicates_for_param(self.id.parent(), self.id.into(), None) .iter() .filter_map(|pred| match &pred.kind().skip_binder() { ClauseKind::Trait(trait_ref) => Some(Trait::from(trait_ref.def_id().0)), @@ -4250,7 +4283,7 @@ impl ConstParam { fn generic_arg_from_param(db: &dyn HirDatabase, id: TypeOrConstParamId) -> Option> { let local_idx = hir_ty::param_idx(db, id)?; - let defaults = db.generic_defaults_ns(id.parent); + let defaults = db.generic_defaults(id.parent); let ty = defaults.get(local_idx)?; // FIXME: This shouldn't be `instantiate_identity()`, we shouldn't leak `TyKind::Param`s. Some(ty.instantiate_identity()) @@ -4525,16 +4558,27 @@ impl<'db> TraitRef<'db> { } } +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +enum AnyClosureId { + ClosureId(InternedClosureId), + CoroutineClosureId(InternedCoroutineId), +} + #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct Closure<'db> { - id: InternedClosureId, + id: AnyClosureId, subst: GenericArgs<'db>, } impl<'db> Closure<'db> { fn as_ty(&self, db: &'db dyn HirDatabase) -> Ty<'db> { let interner = DbInterner::new_with(db, None, None); - Ty::new_closure(interner, self.id.into(), self.subst) + match self.id { + AnyClosureId::ClosureId(id) => Ty::new_closure(interner, id.into(), self.subst), + AnyClosureId::CoroutineClosureId(id) => { + Ty::new_coroutine_closure(interner, id.into(), self.subst) + } + } } pub fn display_with_id(&self, db: &dyn HirDatabase, display_target: DisplayTarget) -> String { @@ -4552,20 +4596,28 @@ impl<'db> Closure<'db> { } pub fn captured_items(&self, db: &'db dyn HirDatabase) -> Vec> { - let owner = db.lookup_intern_closure(self.id).0; + let AnyClosureId::ClosureId(id) = self.id else { + // FIXME: Infer coroutine closures' captures. + return Vec::new(); + }; + let owner = db.lookup_intern_closure(id).0; let infer = db.infer(owner); - let info = infer.closure_info(self.id); + let info = infer.closure_info(id); info.0 .iter() .cloned() - .map(|capture| ClosureCapture { owner, closure: self.id, capture }) + .map(|capture| ClosureCapture { owner, closure: id, capture }) .collect() } pub fn capture_types(&self, db: &'db dyn HirDatabase) -> Vec> { - let owner = db.lookup_intern_closure(self.id).0; + let AnyClosureId::ClosureId(id) = self.id else { + // FIXME: Infer coroutine closures' captures. + return Vec::new(); + }; + let owner = db.lookup_intern_closure(id).0; let infer = db.infer(owner); - let (captures, _) = infer.closure_info(self.id); + let (captures, _) = infer.closure_info(id); let env = db.trait_environment_for_body(owner); captures .iter() @@ -4574,10 +4626,22 @@ impl<'db> Closure<'db> { } pub fn fn_trait(&self, db: &dyn HirDatabase) -> FnTrait { - let owner = db.lookup_intern_closure(self.id).0; - let infer = db.infer(owner); - let info = infer.closure_info(self.id); - info.1 + match self.id { + AnyClosureId::ClosureId(id) => { + let owner = db.lookup_intern_closure(id).0; + let infer = db.infer(owner); + let info = infer.closure_info(id); + info.1 + } + AnyClosureId::CoroutineClosureId(_id) => { + // FIXME: Infer kind for coroutine closures. + match self.subst.as_coroutine_closure().kind() { + rustc_type_ir::ClosureKind::Fn => FnTrait::AsyncFn, + rustc_type_ir::ClosureKind::FnMut => FnTrait::AsyncFnMut, + rustc_type_ir::ClosureKind::FnOnce => FnTrait::AsyncFnOnce, + } + } + } } } @@ -4851,7 +4915,7 @@ impl<'db> Type<'db> { if variant_data.fields().is_empty() { vec![] } else { - let field_types = self.interner.db().field_types_ns(id); + let field_types = self.interner.db().field_types(id); variant_data .fields() .iter() @@ -5091,28 +5155,14 @@ impl<'db> Type<'db> { let interner = DbInterner::new_with(db, None, None); let callee = match self.ty.kind() { TyKind::Closure(id, subst) => Callee::Closure(id.0, subst), + TyKind::CoroutineClosure(id, subst) => Callee::CoroutineClosure(id.0, subst), TyKind::FnPtr(..) => Callee::FnPtr, TyKind::FnDef(id, _) => Callee::Def(id.0), - kind => { - // This will happen when it implements fn or fn mut, since we add an autoborrow adjustment - let (ty, kind) = if let TyKind::Ref(_, ty, _) = kind { - (ty, ty.kind()) - } else { - (self.ty, kind) - }; - if let TyKind::Closure(closure, subst) = kind { - let sig = subst - .split_closure_args_untupled() - .closure_sig_as_fn_ptr_ty - .callable_sig(interner)?; - return Some(Callable { - ty: self.clone(), - sig, - callee: Callee::Closure(closure.0, subst), - is_bound_method: false, - }); - } - let (fn_trait, sig) = hir_ty::callable_sig_from_fn_trait(ty, self.env.clone(), db)?; + // This will happen when it implements fn or fn mut, since we add an autoborrow adjustment + TyKind::Ref(_, inner_ty, _) => return self.derived(inner_ty).as_callable(db), + _ => { + let (fn_trait, sig) = + hir_ty::callable_sig_from_fn_trait(self.ty, self.env.clone(), db)?; return Some(Callable { ty: self.clone(), sig, @@ -5132,7 +5182,12 @@ impl<'db> Type<'db> { pub fn as_closure(&self) -> Option> { match self.ty.kind() { - TyKind::Closure(id, subst) => Some(Closure { id: id.0, subst }), + TyKind::Closure(id, subst) => { + Some(Closure { id: AnyClosureId::ClosureId(id.0), subst }) + } + TyKind::CoroutineClosure(id, subst) => { + Some(Closure { id: AnyClosureId::CoroutineClosureId(id.0), subst }) + } _ => None, } } @@ -5184,7 +5239,7 @@ impl<'db> Type<'db> { _ => return Vec::new(), }; - db.field_types_ns(variant_id) + db.field_types(variant_id) .iter() .map(|(local_id, ty)| { let def = Field { parent: variant_id.into(), id: local_id }; @@ -5791,6 +5846,7 @@ pub struct Callable<'db> { enum Callee<'db> { Def(CallableDefId), Closure(InternedClosureId, GenericArgs<'db>), + CoroutineClosure(InternedCoroutineId, GenericArgs<'db>), FnPtr, FnImpl(FnTrait), } @@ -5812,7 +5868,12 @@ impl<'db> Callable<'db> { Callee::Def(CallableDefId::EnumVariantId(it)) => { CallableKind::TupleEnumVariant(it.into()) } - Callee::Closure(id, ref subst) => CallableKind::Closure(Closure { id, subst: *subst }), + Callee::Closure(id, subst) => { + CallableKind::Closure(Closure { id: AnyClosureId::ClosureId(id), subst }) + } + Callee::CoroutineClosure(id, subst) => { + CallableKind::Closure(Closure { id: AnyClosureId::CoroutineClosureId(id), subst }) + } Callee::FnPtr => CallableKind::FnPtr, Callee::FnImpl(fn_) => CallableKind::FnImpl(fn_), } @@ -6405,7 +6466,7 @@ fn generic_args_from_tys<'db>( args: impl IntoIterator>, ) -> GenericArgs<'db> { let mut args = args.into_iter(); - GenericArgs::for_item(interner, def_id, |_, _, id, _| { + GenericArgs::for_item(interner, def_id, |_, id, _| { if matches!(id, GenericParamId::TypeParamId(_)) && let Some(arg) = args.next() { @@ -6418,7 +6479,7 @@ fn generic_args_from_tys<'db>( fn has_non_default_type_params(db: &dyn HirDatabase, generic_def: GenericDefId) -> bool { let params = db.generic_params(generic_def); - let defaults = db.generic_defaults_ns(generic_def); + let defaults = db.generic_defaults(generic_def); params .iter_type_or_consts() .filter(|(_, param)| matches!(param, TypeOrConstParamData::TypeParamData(_))) diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs index eecca0244091..62ce3daab75d 100644 --- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs +++ b/src/tools/rust-analyzer/crates/hir/src/semantics.rs @@ -1657,14 +1657,11 @@ impl<'db> SemanticsImpl<'db> { ) -> Option { let interner = DbInterner::new_with(self.db, None, None); let mut subst = subst.into_iter(); - let substs = hir_ty::next_solver::GenericArgs::for_item( - interner, - trait_.id.into(), - |_, _, id, _| { + let substs = + hir_ty::next_solver::GenericArgs::for_item(interner, trait_.id.into(), |_, id, _| { assert!(matches!(id, hir_def::GenericParamId::TypeParamId(_)), "expected a type"); subst.next().expect("too few subst").ty.into() - }, - ); + }); assert!(subst.next().is_none(), "too many subst"); Some(self.db.lookup_impl_method(env.env, func.into(), substs).0.into()) } diff --git a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs index 8d2ba7e604e7..15eab14b88df 100644 --- a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs +++ b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs @@ -712,8 +712,7 @@ impl<'db> SourceAnalyzer<'db> { let variant = self.infer()?.variant_resolution_for_expr_or_pat(expr_id)?; let variant_data = variant.fields(db); let field = FieldId { parent: variant, local_id: variant_data.field(&local_name)? }; - let field_ty = - (*db.field_types_ns(variant).get(field.local_id)?).instantiate(interner, subst); + let field_ty = (*db.field_types(variant).get(field.local_id)?).instantiate(interner, subst); Some(( field.into(), local, @@ -735,8 +734,7 @@ impl<'db> SourceAnalyzer<'db> { let variant_data = variant.fields(db); let field = FieldId { parent: variant, local_id: variant_data.field(&field_name)? }; let (adt, subst) = self.infer()?[pat_id.as_pat()?].as_adt()?; - let field_ty = - (*db.field_types_ns(variant).get(field.local_id)?).instantiate(interner, subst); + let field_ty = (*db.field_types(variant).get(field.local_id)?).instantiate(interner, subst); Some(( field.into(), Type::new_with_resolver(db, &self.resolver, field_ty), @@ -802,7 +800,7 @@ impl<'db> SourceAnalyzer<'db> { |variant: VariantId, subst: GenericArgs<'db>, container: &mut _| { let fields = variant.fields(db); let field = fields.field(&field_name.as_name())?; - let field_types = db.field_types_ns(variant); + let field_types = db.field_types(variant); *container = Either::Right(field_types[field].instantiate(interner, subst)); let generic_def = match variant { VariantId::EnumVariantId(it) => it.loc(db).parent.into(), @@ -1255,7 +1253,7 @@ impl<'db> SourceAnalyzer<'db> { missing_fields: Vec, ) -> Vec<(Field, Type<'db>)> { let interner = DbInterner::new_with(db, None, None); - let field_types = db.field_types_ns(variant); + let field_types = db.field_types(variant); missing_fields .into_iter() diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_braces.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_braces.rs index 5af622eaf28b..99ee50fa5848 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_braces.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_braces.rs @@ -1,14 +1,15 @@ use either::Either; use syntax::{ - AstNode, - ast::{self, edit_in_place::Indent, syntax_factory::SyntaxFactory}, + AstNode, T, + ast::{self, edit::AstNodeEdit, syntax_factory::SyntaxFactory}, + match_ast, }; use crate::{AssistContext, AssistId, Assists}; // Assist: add_braces // -// Adds braces to closure bodies and match arm expressions. +// Adds braces to closure bodies, match arm expressions and assignment bodies. // // ``` // fn foo(n: i32) -> i32 { @@ -29,6 +30,20 @@ use crate::{AssistContext, AssistId, Assists}; // } // } // ``` +// --- +// ``` +// fn foo(n: i32) -> i32 { +// let x =$0 n + 2; +// } +// ``` +// -> +// ``` +// fn foo(n: i32) -> i32 { +// let x = { +// n + 2 +// }; +// } +// ``` pub(crate) fn add_braces(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { let (expr_type, expr) = get_replacement_node(ctx)?; @@ -37,16 +52,17 @@ pub(crate) fn add_braces(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<( match expr_type { ParentType::ClosureExpr => "Add braces to this closure body", ParentType::MatchArmExpr => "Add braces to this match arm expression", + ParentType::Assignment => "Add braces to this assignment expression", }, expr.syntax().text_range(), |builder| { let make = SyntaxFactory::with_mappings(); let mut editor = builder.make_editor(expr.syntax()); - let block_expr = make.block_expr(None, Some(expr.clone())); - block_expr.indent(expr.indent_level()); + let new_expr = expr.reset_indent().indent(1.into()); + let block_expr = make.block_expr(None, Some(new_expr)); - editor.replace(expr.syntax(), block_expr.syntax()); + editor.replace(expr.syntax(), block_expr.indent(expr.indent_level()).syntax()); editor.add_mappings(make.finish_with_mappings()); builder.add_file_edits(ctx.vfs_file_id(), editor); @@ -57,29 +73,38 @@ pub(crate) fn add_braces(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<( enum ParentType { MatchArmExpr, ClosureExpr, + Assignment, } fn get_replacement_node(ctx: &AssistContext<'_>) -> Option<(ParentType, ast::Expr)> { - let node = ctx.find_node_at_offset::>()?; - if let Either::Left(match_arm) = &node { + let node = ctx.find_node_at_offset::>(); + let (parent_type, body) = if let Some(eq_token) = ctx.find_token_syntax_at_offset(T![=]) { + let parent = eq_token.parent()?; + let body = match_ast! { + match parent { + ast::LetStmt(it) => it.initializer()?, + ast::LetExpr(it) => it.expr()?, + ast::Static(it) => it.body()?, + ast::Const(it) => it.body()?, + _ => return None, + } + }; + (ParentType::Assignment, body) + } else if let Some(Either::Left(match_arm)) = &node { let match_arm_expr = match_arm.expr()?; - - if matches!(match_arm_expr, ast::Expr::BlockExpr(_)) { - return None; - } - - return Some((ParentType::MatchArmExpr, match_arm_expr)); - } else if let Either::Right(closure_expr) = &node { + (ParentType::MatchArmExpr, match_arm_expr) + } else if let Some(Either::Right(closure_expr)) = &node { let body = closure_expr.body()?; + (ParentType::ClosureExpr, body) + } else { + return None; + }; - if matches!(body, ast::Expr::BlockExpr(_)) { - return None; - } - - return Some((ParentType::ClosureExpr, body)); + if matches!(body, ast::Expr::BlockExpr(_)) { + return None; } - None + Some((parent_type, body)) } #[cfg(test)] @@ -134,6 +159,25 @@ fn foo() { ); } + #[test] + fn suggest_add_braces_for_assignment() { + check_assist( + add_braces, + r#" +fn foo() { + let x =$0 n + 100; +} +"#, + r#" +fn foo() { + let x = { + n + 100 + }; +} +"#, + ); + } + #[test] fn no_assist_for_closures_with_braces() { check_assist_not_applicable( @@ -171,6 +215,41 @@ fn foo() { ); } + #[test] + fn multiple_indent() { + check_assist( + add_braces, + r#" +fn foo() { + { + match n { + Some(n) $0=> foo( + 29, + 30, + ), + _ => () + }; + } +} +"#, + r#" +fn foo() { + { + match n { + Some(n) => { + foo( + 29, + 30, + ) + }, + _ => () + }; + } +} +"#, + ); + } + #[test] fn no_assist_for_match_with_braces() { check_assist_not_applicable( diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs index 8802a54e7f24..7843ab9e8f25 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs @@ -8,8 +8,7 @@ use ide_db::syntax_helpers::suggest_name; use ide_db::{famous_defs::FamousDefs, helpers::mod_path_to_ast}; use itertools::Itertools; use syntax::ToSmolStr; -use syntax::ast::edit::IndentLevel; -use syntax::ast::edit_in_place::Indent; +use syntax::ast::edit::{AstNodeEdit, IndentLevel}; use syntax::ast::syntax_factory::SyntaxFactory; use syntax::ast::{self, AstNode, MatchArmList, MatchExpr, Pat, make}; @@ -261,6 +260,7 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>) true } }) + .map(|arm| arm.reset_indent().indent(IndentLevel(1))) .collect(); let first_new_arm_idx = arms.len(); @@ -300,7 +300,7 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>) }; let mut editor = builder.make_editor(&old_place); - new_match_arm_list.indent(IndentLevel::from_node(&old_place)); + let new_match_arm_list = new_match_arm_list.indent(IndentLevel::from_node(&old_place)); editor.replace(old_place, new_match_arm_list.syntax()); if let Some(cap) = ctx.config.snippet_cap { @@ -917,6 +917,39 @@ fn main() { ); } + #[test] + fn partial_fill_option_with_indentation() { + check_assist( + add_missing_match_arms, + r#" +//- minicore: option +fn main() { + match None$0 { + None => { + foo( + "foo", + "bar", + ); + } + } +} +"#, + r#" +fn main() { + match None { + None => { + foo( + "foo", + "bar", + ); + } + Some(${1:_}) => ${2:todo!()},$0 + } +} +"#, + ); + } + #[test] fn partial_fill_or_pat() { check_assist( diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_closure_to_fn.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_closure_to_fn.rs index 2cda6d6f1c0a..ca142332d97e 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_closure_to_fn.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_closure_to_fn.rs @@ -805,7 +805,6 @@ impl A { ); } - #[ignore = "FIXME(next-solver): Fix async closures"] #[test] fn replaces_async_closure_with_async_fn() { check_assist( diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_named_struct_to_tuple_struct.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_named_struct_to_tuple_struct.rs index 8d27574eb2ca..e518c39dabc2 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_named_struct_to_tuple_struct.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_named_struct_to_tuple_struct.rs @@ -187,6 +187,7 @@ fn process_struct_name_reference( return None; } + // FIXME: Processing RecordPat and RecordExpr for unordered fields, and insert RestPat let parent = full_path.syntax().parent()?; match_ast! { match parent { @@ -202,6 +203,9 @@ fn process_struct_name_reference( .record_pat_field_list()? .fields() .filter_map(|pat| pat.pat()) + .chain(record_struct_pat.record_pat_field_list()? + .rest_pat() + .map(Into::into)) ) .to_string() ); @@ -346,6 +350,37 @@ impl A { ); } + #[test] + fn convert_struct_and_rest_pat() { + check_assist( + convert_named_struct_to_tuple_struct, + r#" +struct Inner; +struct A$0 { inner: Inner } +fn foo(A { .. }: A) {} +"#, + r#" +struct Inner; +struct A(Inner); +fn foo(A(..): A) {} +"#, + ); + + check_assist( + convert_named_struct_to_tuple_struct, + r#" +struct Inner; +struct A$0 { inner: Inner, extra: Inner } +fn foo(A { inner, .. }: A) {} +"#, + r#" +struct Inner; +struct A(Inner, Inner); +fn foo(A(inner, ..): A) {} +"#, + ); + } + #[test] fn convert_simple_struct_cursor_on_visibility_keyword() { check_assist( diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_to_guarded_return.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_to_guarded_return.rs index ae13f83fbc34..7f4fb4c694d7 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_to_guarded_return.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_to_guarded_return.rs @@ -75,8 +75,8 @@ fn if_expr_to_guarded_return( let let_chains = flat_let_chain(cond); - let then_block = if_expr.then_branch()?; - let then_block = then_block.stmt_list()?; + let then_branch = if_expr.then_branch()?; + let then_block = then_branch.stmt_list()?; let parent_block = if_expr.syntax().parent()?.ancestors().find_map(ast::BlockExpr::cast)?; @@ -84,17 +84,8 @@ fn if_expr_to_guarded_return( return None; } - // FIXME: This relies on untyped syntax tree and casts to much. It should be - // rewritten to use strongly-typed APIs. - // check for early return and continue - let first_in_then_block = then_block.syntax().first_child()?; - if ast::ReturnExpr::can_cast(first_in_then_block.kind()) - || ast::ContinueExpr::can_cast(first_in_then_block.kind()) - || first_in_then_block - .children() - .any(|x| ast::ReturnExpr::can_cast(x.kind()) || ast::ContinueExpr::can_cast(x.kind())) - { + if is_early_block(&then_block) || is_never_block(&ctx.sema, &then_branch) { return None; } @@ -255,20 +246,25 @@ fn early_expression( fn flat_let_chain(mut expr: ast::Expr) -> Vec { let mut chains = vec![]; + let mut reduce_cond = |rhs| { + if !matches!(rhs, ast::Expr::LetExpr(_)) + && let Some(last) = chains.pop_if(|last| !matches!(last, ast::Expr::LetExpr(_))) + { + chains.push(make::expr_bin_op(rhs, ast::BinaryOp::LogicOp(ast::LogicOp::And), last)); + } else { + chains.push(rhs); + } + }; while let ast::Expr::BinExpr(bin_expr) = &expr && bin_expr.op_kind() == Some(ast::BinaryOp::LogicOp(ast::LogicOp::And)) && let (Some(lhs), Some(rhs)) = (bin_expr.lhs(), bin_expr.rhs()) { - if let Some(last) = chains.pop_if(|last| !matches!(last, ast::Expr::LetExpr(_))) { - chains.push(make::expr_bin_op(rhs, ast::BinaryOp::LogicOp(ast::LogicOp::And), last)); - } else { - chains.push(rhs); - } + reduce_cond(rhs); expr = lhs; } - chains.push(expr); + reduce_cond(expr); chains.reverse(); chains } @@ -284,6 +280,17 @@ fn clean_stmt_block(block: &ast::BlockExpr) -> ast::BlockExpr { } } +fn is_early_block(then_block: &ast::StmtList) -> bool { + let is_early_expr = + |expr| matches!(expr, ast::Expr::ReturnExpr(_) | ast::Expr::ContinueExpr(_)); + let into_expr = |stmt| match stmt { + ast::Stmt::ExprStmt(expr_stmt) => expr_stmt.expr(), + _ => None, + }; + then_block.tail_expr().is_some_and(is_early_expr) + || then_block.statements().filter_map(into_expr).any(is_early_expr) +} + #[cfg(test)] mod tests { use crate::tests::{check_assist, check_assist_not_applicable}; @@ -552,6 +559,93 @@ fn main() { let Some(y) = Some(8) else { return }; foo(x, y); } +"#, + ); + + check_assist( + convert_to_guarded_return, + r#" +fn main() { + if$0 let Ok(x) = Err(92) + && let Ok(y) = Ok(37) + && x < 30 + && let Some(y) = Some(8) + { + foo(x, y); + } +} +"#, + r#" +fn main() { + let Ok(x) = Err(92) else { return }; + let Ok(y) = Ok(37) else { return }; + if x >= 30 { + return; + } + let Some(y) = Some(8) else { return }; + foo(x, y); +} +"#, + ); + + check_assist( + convert_to_guarded_return, + r#" +fn main() { + if$0 cond + && let Ok(x) = Err(92) + && let Ok(y) = Ok(37) + && x < 30 + && let Some(y) = Some(8) + { + foo(x, y); + } +} +"#, + r#" +fn main() { + if !cond { + return; + } + let Ok(x) = Err(92) else { return }; + let Ok(y) = Ok(37) else { return }; + if x >= 30 { + return; + } + let Some(y) = Some(8) else { return }; + foo(x, y); +} +"#, + ); + + check_assist( + convert_to_guarded_return, + r#" +fn main() { + if$0 cond + && foo() + && let Ok(x) = Err(92) + && let Ok(y) = Ok(37) + && x < 30 + && let Some(y) = Some(8) + { + foo(x, y); + } +} +"#, + r#" +fn main() { + if !(cond && foo()) { + return; + } + let Ok(x) = Err(92) else { return }; + let Ok(y) = Ok(37) else { return }; + if x >= 30 { + return; + } + let Some(y) = Some(8) else { return }; + foo(x, y); +} "#, ); } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs index 3d78895477b3..61d844928a8a 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs @@ -154,14 +154,7 @@ fn edit_struct_references( ast::TupleStructPat(tuple_struct_pat) => { Some(make.record_pat_with_fields( tuple_struct_pat.path()?, - ast::make::record_pat_field_list(tuple_struct_pat.fields().zip(names).map( - |(pat, name)| { - ast::make::record_pat_field( - ast::make::name_ref(&name.to_string()), - pat, - ) - }, - ), None), + generate_record_pat_list(&tuple_struct_pat, names), ).syntax().clone()) }, // for tuple struct creations like Foo(42) @@ -284,6 +277,24 @@ fn generate_names(fields: impl Iterator) -> Vec ast::RecordPatFieldList { + let pure_fields = pat.fields().filter(|p| !matches!(p, ast::Pat::RestPat(_))); + let rest_len = names.len().saturating_sub(pure_fields.clone().count()); + let rest_pat = pat.fields().find_map(|p| ast::RestPat::cast(p.syntax().clone())); + let rest_idx = + pat.fields().position(|p| ast::RestPat::can_cast(p.syntax().kind())).unwrap_or(names.len()); + let before_rest = pat.fields().zip(names).take(rest_idx); + let after_rest = pure_fields.zip(names.iter().skip(rest_len)).skip(rest_idx); + + let fields = before_rest + .chain(after_rest) + .map(|(pat, name)| ast::make::record_pat_field(ast::make::name_ref(&name.text()), pat)); + ast::make::record_pat_field_list(fields, rest_pat) +} + #[cfg(test)] mod tests { use crate::tests::{check_assist, check_assist_not_applicable}; @@ -358,6 +369,43 @@ impl A { ); } + #[test] + fn convert_struct_and_rest_pat() { + check_assist( + convert_tuple_struct_to_named_struct, + r#" +struct Inner; +struct A$0(Inner); +fn foo(A(..): A) {} +"#, + r#" +struct Inner; +struct A { field1: Inner } +fn foo(A { .. }: A) {} +"#, + ); + + check_assist( + convert_tuple_struct_to_named_struct, + r#" +struct A; +struct B; +struct C; +struct D; +struct X$0(A, B, C, D); +fn foo(X(a, .., d): X) {} +"#, + r#" +struct A; +struct B; +struct C; +struct D; +struct X { field1: A, field2: B, field3: C, field4: D } +fn foo(X { field1: a, field4: d, .. }: X) {} +"#, + ); + } + #[test] fn convert_simple_struct_cursor_on_struct_keyword() { check_assist( diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_tuple_binding.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_tuple_binding.rs index f09389f8302f..e2afc0bf130e 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_tuple_binding.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_tuple_binding.rs @@ -7,6 +7,7 @@ use ide_db::{ }; use itertools::Itertools; use syntax::{ + T, ast::{self, AstNode, FieldExpr, HasName, IdentPat, make}, ted, }; @@ -179,6 +180,11 @@ fn edit_tuple_assignment( .map(|name| ast::Pat::from(make::ident_pat(is_ref, is_mut, make::name(name)))); make::tuple_pat(fields).clone_for_update() }; + let is_shorthand_field = ident_pat + .name() + .as_ref() + .and_then(ast::RecordPatField::for_field_name) + .is_some_and(|field| field.colon_token().is_none()); if let Some(cap) = ctx.config.snippet_cap { // place cursor on first tuple name @@ -190,12 +196,13 @@ fn edit_tuple_assignment( } } - AssignmentEdit { ident_pat, tuple_pat, in_sub_pattern } + AssignmentEdit { ident_pat, tuple_pat, in_sub_pattern, is_shorthand_field } } struct AssignmentEdit { ident_pat: ast::IdentPat, tuple_pat: ast::TuplePat, in_sub_pattern: bool, + is_shorthand_field: bool, } impl AssignmentEdit { @@ -203,6 +210,9 @@ impl AssignmentEdit { // with sub_pattern: keep original tuple and add subpattern: `tup @ (_0, _1)` if self.in_sub_pattern { self.ident_pat.set_pat(Some(self.tuple_pat.into())) + } else if self.is_shorthand_field { + ted::insert(ted::Position::after(self.ident_pat.syntax()), self.tuple_pat.syntax()); + ted::insert_raw(ted::Position::after(self.ident_pat.syntax()), make::token(T![:])); } else { ted::replace(self.ident_pat.syntax(), self.tuple_pat.syntax()) } @@ -799,6 +809,48 @@ fn main() { ) } + #[test] + fn in_record_shorthand_field() { + check_assist( + assist, + r#" +struct S { field: (i32, i32) } +fn main() { + let S { $0field } = S { field: (2, 3) }; + let v = field.0 + field.1; +} + "#, + r#" +struct S { field: (i32, i32) } +fn main() { + let S { field: ($0_0, _1) } = S { field: (2, 3) }; + let v = _0 + _1; +} + "#, + ) + } + + #[test] + fn in_record_field() { + check_assist( + assist, + r#" +struct S { field: (i32, i32) } +fn main() { + let S { field: $0t } = S { field: (2, 3) }; + let v = t.0 + t.1; +} + "#, + r#" +struct S { field: (i32, i32) } +fn main() { + let S { field: ($0_0, _1) } = S { field: (2, 3) }; + let v = _0 + _1; +} + "#, + ) + } + #[test] fn in_nested_tuple() { check_assist( diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_module.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_module.rs index dad19bfb8a2c..a17ae4885e62 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_module.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_module.rs @@ -1,4 +1,4 @@ -use std::ops::RangeInclusive; +use std::{iter::once, ops::RangeInclusive}; use hir::{HasSource, ModuleSource}; use ide_db::{ @@ -63,19 +63,6 @@ pub(crate) fn extract_module(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti syntax::NodeOrToken::Token(t) => t.parent()?, }; - //If the selection is inside impl block, we need to place new module outside impl block, - //as impl blocks cannot contain modules - - let mut impl_parent: Option = None; - let mut impl_child_count: usize = 0; - if let Some(parent_assoc_list) = node.parent() - && let Some(parent_impl) = parent_assoc_list.parent() - && let Some(impl_) = ast::Impl::cast(parent_impl) - { - impl_child_count = parent_assoc_list.children().count(); - impl_parent = Some(impl_); - } - let mut curr_parent_module: Option = None; if let Some(mod_syn_opt) = node.ancestors().find(|it| ast::Module::can_cast(it.kind())) { curr_parent_module = ast::Module::cast(mod_syn_opt); @@ -94,7 +81,22 @@ pub(crate) fn extract_module(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti return None; } - let old_item_indent = module.body_items[0].indent_level(); + let mut old_item_indent = module.body_items[0].indent_level(); + let old_items: Vec<_> = module.use_items.iter().chain(&module.body_items).cloned().collect(); + + // If the selection is inside impl block, we need to place new module outside impl block, + // as impl blocks cannot contain modules + + let mut impl_parent: Option = None; + let mut impl_child_count: usize = 0; + if let Some(parent_assoc_list) = module.body_items[0].syntax().parent() + && let Some(parent_impl) = parent_assoc_list.parent() + && let Some(impl_) = ast::Impl::cast(parent_impl) + { + impl_child_count = parent_assoc_list.children().count(); + old_item_indent = impl_.indent_level(); + impl_parent = Some(impl_); + } acc.add( AssistId::refactor_extract("extract_module"), @@ -127,7 +129,7 @@ pub(crate) fn extract_module(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti let import_items = module.resolve_imports(curr_parent_module, ctx); module.change_visibility(record_fields); - let module_def = generate_module_def(&impl_parent, module, old_item_indent).to_string(); + let module_def = generate_module_def(&impl_parent, &module).indent(old_item_indent); let mut usages_to_be_processed_for_cur_file = vec![]; for (file_id, usages) in usages_to_be_processed { @@ -149,27 +151,32 @@ pub(crate) fn extract_module(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti if let Some(impl_) = impl_parent { // Remove complete impl block if it has only one child (as such it will be empty // after deleting that child) - let node_to_be_removed = if impl_child_count == 1 { - impl_.syntax() + let nodes_to_be_removed = if impl_child_count == old_items.len() { + vec![impl_.syntax()] } else { //Remove selected node - &node + old_items.iter().map(|it| it.syntax()).collect() }; - builder.delete(node_to_be_removed.text_range()); - // Remove preceding indentation from node - if let Some(range) = indent_range_before_given_node(node_to_be_removed) { - builder.delete(range); + for node_to_be_removed in nodes_to_be_removed { + builder.delete(node_to_be_removed.text_range()); + // Remove preceding indentation from node + if let Some(range) = indent_range_before_given_node(node_to_be_removed) { + builder.delete(range); + } } - builder.insert(impl_.syntax().text_range().end(), format!("\n\n{module_def}")); + builder.insert( + impl_.syntax().text_range().end(), + format!("\n\n{old_item_indent}{module_def}"), + ); } else { for import_item in import_items { if !module_text_range.contains_range(import_item) { builder.delete(import_item); } } - builder.replace(module_text_range, module_def) + builder.replace(module_text_range, module_def.to_string()) } }, ) @@ -177,34 +184,35 @@ pub(crate) fn extract_module(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti fn generate_module_def( parent_impl: &Option, - module: Module, - old_indent: IndentLevel, + Module { name, body_items, use_items }: &Module, ) -> ast::Module { - let Module { name, body_items, use_items } = module; - let items = if let Some(self_ty) = parent_impl.as_ref().and_then(|imp| imp.self_ty()) { + let items: Vec<_> = if let Some(impl_) = parent_impl.as_ref() + && let Some(self_ty) = impl_.self_ty() + { let assoc_items = body_items - .into_iter() + .iter() .map(|item| item.syntax().clone()) .filter_map(ast::AssocItem::cast) .map(|it| it.indent(IndentLevel(1))) .collect_vec(); - let assoc_item_list = make::assoc_item_list(Some(assoc_items)); - let impl_ = make::impl_(None, None, None, self_ty.clone(), None, Some(assoc_item_list)); + let assoc_item_list = make::assoc_item_list(Some(assoc_items)).clone_for_update(); + let impl_ = impl_.reset_indent(); + ted::replace(impl_.get_or_create_assoc_item_list().syntax(), assoc_item_list.syntax()); // Add the import for enum/struct corresponding to given impl block let use_impl = make_use_stmt_of_node_with_super(self_ty.syntax()); - let mut module_body_items = use_items; - module_body_items.insert(0, use_impl); - module_body_items.push(ast::Item::Impl(impl_)); - module_body_items + once(use_impl) + .chain(use_items.iter().cloned()) + .chain(once(ast::Item::Impl(impl_))) + .collect() } else { - [use_items, body_items].concat() + use_items.iter().chain(body_items).cloned().collect() }; let items = items.into_iter().map(|it| it.reset_indent().indent(IndentLevel(1))).collect_vec(); let module_body = make::item_list(Some(items)); let module_name = make::name(name); - make::mod_(module_name, Some(module_body)).indent(old_indent) + make::mod_(module_name, Some(module_body)) } fn make_use_stmt_of_node_with_super(node_syntax: &SyntaxNode) -> ast::Item { @@ -1400,28 +1408,54 @@ mod modname { fn test_if_inside_impl_block_generate_module_outside() { check_assist( extract_module, - r" - struct A {} + r"struct A {} impl A { -$0fn foo() {}$0 + $0fn foo() {}$0 fn bar() {} } ", - r" - struct A {} + r"struct A {} impl A { fn bar() {} } -mod modname { - use super::A; + mod modname { + use super::A; - impl A { - pub(crate) fn foo() {} - } -} + impl A { + pub(crate) fn foo() {} + } + } + ", + ); + + check_assist( + extract_module, + r"struct A {} + + impl A { + $0fn foo() {} + fn bar() {}$0 + fn baz() {} + } + ", + r"struct A {} + + impl A { + fn baz() {} + } + + mod modname { + use super::A; + + impl A { + pub(crate) fn foo() {} + + pub(crate) fn bar() {} + } + } ", ) } @@ -1430,27 +1464,25 @@ mod modname { fn test_if_inside_impl_block_generate_module_outside_but_impl_block_having_one_child() { check_assist( extract_module, - r" - struct A {} + r"struct A {} struct B {} impl A { $0fn foo(x: B) {}$0 } ", - r" - struct A {} + r"struct A {} struct B {} -mod modname { - use super::A; + mod modname { + use super::A; - use super::B; + use super::B; - impl A { - pub(crate) fn foo(x: B) {} - } -} + impl A { + pub(crate) fn foo(x: B) {} + } + } ", ) } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_binexpr.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_binexpr.rs index 247e8109abc9..8f2306e9037e 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_binexpr.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_binexpr.rs @@ -1,6 +1,7 @@ use syntax::{ SyntaxKind, T, - ast::{self, AstNode, BinExpr, syntax_factory::SyntaxFactory}, + ast::{self, AstNode, BinExpr, RangeItem, syntax_factory::SyntaxFactory}, + syntax_editor::Position, }; use crate::{AssistContext, AssistId, Assists}; @@ -87,6 +88,74 @@ impl From for FlipAction { } } +// Assist: flip_range_expr +// +// Flips operands of a range expression. +// +// ``` +// fn main() { +// let _ = 90..$02; +// } +// ``` +// -> +// ``` +// fn main() { +// let _ = 2..90; +// } +// ``` +// --- +// ``` +// fn main() { +// let _ = 90..$0; +// } +// ``` +// -> +// ``` +// fn main() { +// let _ = ..90; +// } +// ``` +pub(crate) fn flip_range_expr(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { + let range_expr = ctx.find_node_at_offset::()?; + let op = range_expr.op_token()?; + let start = range_expr.start(); + let end = range_expr.end(); + + if !op.text_range().contains_range(ctx.selection_trimmed()) { + return None; + } + if start.is_none() && end.is_none() { + return None; + } + + acc.add( + AssistId::refactor_rewrite("flip_range_expr"), + "Flip range expression", + op.text_range(), + |builder| { + let mut edit = builder.make_editor(range_expr.syntax()); + + match (start, end) { + (Some(start), Some(end)) => { + edit.replace(start.syntax(), end.syntax()); + edit.replace(end.syntax(), start.syntax()); + } + (Some(start), None) => { + edit.delete(start.syntax()); + edit.insert(Position::after(&op), start.syntax().clone_for_update()); + } + (None, Some(end)) => { + edit.delete(end.syntax()); + edit.insert(Position::before(&op), end.syntax().clone_for_update()); + } + (None, None) => (), + } + + builder.add_file_edits(ctx.vfs_file_id(), edit); + }, + ) +} + #[cfg(test)] mod tests { use super::*; diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_single_field_struct_from.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_single_field_struct_from.rs index 6c302a2a6fbd..a1ec76336566 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_single_field_struct_from.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_single_field_struct_from.rs @@ -5,9 +5,10 @@ use ide_db::{ RootDatabase, famous_defs::FamousDefs, helpers::mod_path_to_ast, imports::import_assets::item_for_path_search, use_trivial_constructor::use_trivial_constructor, }; +use syntax::syntax_editor::{Element, Position}; use syntax::{ TokenText, - ast::{self, AstNode, HasAttrs, HasGenericParams, HasName, edit, edit_in_place::Indent}, + ast::{self, AstNode, HasAttrs, HasGenericParams, HasName, edit::AstNodeEdit}, }; use crate::{ @@ -111,9 +112,8 @@ pub(crate) fn generate_single_field_struct_from( false, false, ) - .clone_for_update(); + .indent(1.into()); - fn_.indent(1.into()); let cfg_attrs = strukt .attrs() .filter(|attr| attr.as_simple_call().is_some_and(|(name, _arg)| name == "cfg")); @@ -129,16 +129,25 @@ pub(crate) fn generate_single_field_struct_from( make::ty("From"), ty.clone(), None, - ty_where_clause.map(|wc| edit::AstNodeEdit::reset_indent(&wc)), + ty_where_clause.map(|wc| wc.reset_indent()), None, ) .clone_for_update(); impl_.get_or_create_assoc_item_list().add_item(fn_.into()); + let impl_ = impl_.indent(indent); - impl_.reindent_to(indent); + let mut edit = builder.make_editor(strukt.syntax()); - builder.insert(strukt.syntax().text_range().end(), format!("\n\n{indent}{impl_}")); + edit.insert_all( + Position::after(strukt.syntax()), + vec![ + make::tokens::whitespace(&format!("\n\n{indent}")).syntax_element(), + impl_.syntax().syntax_element(), + ], + ); + + builder.add_file_edits(ctx.vfs_file_id(), edit); }, ) } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/invert_if.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/invert_if.rs index 7576d2fab976..bf82d8df9b58 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/invert_if.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/invert_if.rs @@ -27,7 +27,9 @@ use crate::{ // } // ``` pub(crate) fn invert_if(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { - let if_keyword = ctx.find_token_syntax_at_offset(T![if])?; + let if_keyword = ctx + .find_token_syntax_at_offset(T![if]) + .or_else(|| ctx.find_token_syntax_at_offset(T![else]))?; let expr = ast::IfExpr::cast(if_keyword.parent()?)?; let if_range = if_keyword.text_range(); let cursor_in_range = if_range.contains_range(ctx.selection_trimmed()); @@ -111,6 +113,15 @@ mod tests { ) } + #[test] + fn invert_if_on_else_keyword() { + check_assist( + invert_if, + "fn f() { if cond { 3 * 2 } e$0lse { 1 } }", + "fn f() { if !cond { 1 } else { 3 * 2 } }", + ) + } + #[test] fn invert_if_doesnt_apply_with_cursor_not_on_if() { check_assist_not_applicable(invert_if, "fn f() { if !$0cond { 3 * 2 } else { 1 } }") diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_else_branches.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_else_branches.rs new file mode 100644 index 000000000000..6a02c37015d3 --- /dev/null +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_else_branches.rs @@ -0,0 +1,90 @@ +use syntax::{AstNode, SyntaxKind, T, TextRange, ast}; + +use crate::{AssistContext, AssistId, Assists}; + +// Assist: remove_else_branches +// +// Removes the `else` keyword and else branches. +// +// ``` +// fn main() { +// if true { +// let _ = 2; +// } $0else { +// unreachable!(); +// } +// } +// ``` +// -> +// ``` +// fn main() { +// if true { +// let _ = 2; +// } +// } +// ``` +// --- +// ``` +// fn main() { +// let _x = 2 $0else { unreachable!() }; +// } +// ``` +// -> +// ``` +// fn main() { +// let _x = 2; +// } +// ``` +pub(crate) fn remove_else_branches(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { + let else_token = ctx.find_token_syntax_at_offset(T![else])?; + let else_branches = ctx + .find_node_at_range::() + .and_then(|if_expr| if_expr.else_branch()?.syntax().clone().into()) + .or_else(|| { + ctx.find_node_at_range::()? + .let_else()? + .block_expr()? + .syntax() + .clone() + .into() + })?; + + let target = TextRange::cover(else_token.text_range(), else_branches.text_range()); + acc.add( + AssistId::refactor("remove_else_branches"), + "Remove `else` branches", + target, + |builder| { + let mut editor = builder.make_editor(&else_token.parent().unwrap()); + match else_token.prev_token() { + Some(it) if it.kind() == SyntaxKind::WHITESPACE => editor.delete(it), + _ => (), + } + match else_token.next_token() { + Some(it) if it.kind() == SyntaxKind::WHITESPACE => editor.delete(it), + _ => (), + } + editor.delete(else_token); + editor.delete(else_branches); + builder.add_file_edits(ctx.vfs_file_id(), editor); + }, + ) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::tests::check_assist_not_applicable; + + #[test] + fn test_remove_else_branches_not_on_else_token() { + check_assist_not_applicable( + remove_else_branches, + r#" +fn main() { + let _x = 2 else {$0 unreachable!() }; +} +"#, + ); + } +} diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_is_method_with_if_let_method.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_is_method_with_if_let_method.rs index f507cae1bb0d..c57fd4d439dc 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_is_method_with_if_let_method.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_is_method_with_if_let_method.rs @@ -1,7 +1,7 @@ use ide_db::syntax_helpers::suggest_name; use syntax::ast::{self, AstNode, syntax_factory::SyntaxFactory}; -use crate::{AssistContext, AssistId, Assists}; +use crate::{AssistContext, AssistId, Assists, utils::cover_let_chain}; // Assist: replace_is_some_with_if_let_some // @@ -27,13 +27,11 @@ pub(crate) fn replace_is_method_with_if_let_method( let if_expr = ctx.find_node_at_offset::()?; let cond = if_expr.condition()?; + let cond = cover_let_chain(cond, ctx.selection_trimmed())?; let call_expr = match cond { ast::Expr::MethodCallExpr(call) => call, _ => return None, }; - if ctx.offset() > if_expr.then_branch()?.stmt_list()?.l_curly_token()?.text_range().end() { - return None; - } let name_ref = call_expr.name_ref()?; match name_ref.text().as_str() { @@ -195,6 +193,63 @@ fn main() { ); } + #[test] + fn replace_is_some_with_if_let_some_in_let_chain() { + check_assist( + replace_is_method_with_if_let_method, + r#" +fn main() { + let x = Some(1); + let cond = true; + if cond && x.is_som$0e() {} +} +"#, + r#" +fn main() { + let x = Some(1); + let cond = true; + if cond && let Some(${0:x1}) = x {} +} +"#, + ); + + check_assist( + replace_is_method_with_if_let_method, + r#" +fn main() { + let x = Some(1); + let cond = true; + if x.is_som$0e() && cond {} +} +"#, + r#" +fn main() { + let x = Some(1); + let cond = true; + if let Some(${0:x1}) = x && cond {} +} +"#, + ); + + check_assist( + replace_is_method_with_if_let_method, + r#" +fn main() { + let x = Some(1); + let cond = true; + if cond && x.is_som$0e() && cond {} +} +"#, + r#" +fn main() { + let x = Some(1); + let cond = true; + if cond && let Some(${0:x1}) = x && cond {} +} +"#, + ); + } + #[test] fn replace_is_some_with_if_let_some_not_applicable_after_l_curly() { check_assist_not_applicable( diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs b/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs index 2977f8b8c2e7..e9f2d686465e 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs @@ -201,6 +201,7 @@ mod handlers { mod qualify_path; mod raw_string; mod remove_dbg; + mod remove_else_branches; mod remove_mut; mod remove_parentheses; mod remove_underscore; @@ -284,6 +285,7 @@ mod handlers { extract_type_alias::extract_type_alias, fix_visibility::fix_visibility, flip_binexpr::flip_binexpr, + flip_binexpr::flip_range_expr, flip_comma::flip_comma, flip_or_pattern::flip_or_pattern, flip_trait_bound::flip_trait_bound, @@ -342,6 +344,7 @@ mod handlers { raw_string::remove_hash, remove_dbg::remove_dbg, remove_mut::remove_mut, + remove_else_branches::remove_else_branches, remove_parentheses::remove_parentheses, remove_underscore::remove_underscore, remove_unused_imports::remove_unused_imports, diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs b/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs index c7ae44124f23..a99fe8de333d 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs @@ -27,6 +27,25 @@ fn foo(n: i32) -> i32 { ) } +#[test] +fn doctest_add_braces_1() { + check_doc_test( + "add_braces", + r#####" +fn foo(n: i32) -> i32 { + let x =$0 n + 2; +} +"#####, + r#####" +fn foo(n: i32) -> i32 { + let x = { + n + 2 + }; +} +"#####, + ) +} + #[test] fn doctest_add_explicit_enum_discriminant() { check_doc_test( @@ -1332,6 +1351,40 @@ fn foo() { ) } +#[test] +fn doctest_flip_range_expr() { + check_doc_test( + "flip_range_expr", + r#####" +fn main() { + let _ = 90..$02; +} +"#####, + r#####" +fn main() { + let _ = 2..90; +} +"#####, + ) +} + +#[test] +fn doctest_flip_range_expr_1() { + check_doc_test( + "flip_range_expr", + r#####" +fn main() { + let _ = 90..$0; +} +"#####, + r#####" +fn main() { + let _ = ..90; +} +"#####, + ) +} + #[test] fn doctest_flip_trait_bound() { check_doc_test( @@ -2863,6 +2916,46 @@ fn main() { ) } +#[test] +fn doctest_remove_else_branches() { + check_doc_test( + "remove_else_branches", + r#####" +fn main() { + if true { + let _ = 2; + } $0else { + unreachable!(); + } +} +"#####, + r#####" +fn main() { + if true { + let _ = 2; + } +} +"#####, + ) +} + +#[test] +fn doctest_remove_else_branches_1() { + check_doc_test( + "remove_else_branches", + r#####" +fn main() { + let _x = 2 $0else { unreachable!() }; +} +"#####, + r#####" +fn main() { + let _x = 2; +} +"#####, + ) +} + #[test] fn doctest_remove_hash() { check_doc_test( diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs b/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs index 5a3c5a39dac7..e43516f6b963 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs @@ -1133,6 +1133,28 @@ pub(crate) fn tt_from_syntax(node: SyntaxNode) -> Vec Option { + if !expr.syntax().text_range().contains_range(range) { + return None; + } + loop { + let (chain_expr, rest) = if let ast::Expr::BinExpr(bin_expr) = &expr + && bin_expr.op_kind() == Some(ast::BinaryOp::LogicOp(ast::LogicOp::And)) + { + (bin_expr.rhs(), bin_expr.lhs()) + } else { + (Some(expr), None) + }; + + if let Some(chain_expr) = chain_expr + && chain_expr.syntax().text_range().contains_range(range) + { + break Some(chain_expr); + } + expr = rest?; + } +} + pub fn is_body_const(sema: &Semantics<'_, RootDatabase>, expr: &ast::Expr) -> bool { let mut is_const = true; preorder_expr(expr, &mut |ev| { diff --git a/src/tools/rust-analyzer/crates/ide-completion/Cargo.toml b/src/tools/rust-analyzer/crates/ide-completion/Cargo.toml index 9bad21fc8e90..277d5dfa495c 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/Cargo.toml +++ b/src/tools/rust-analyzer/crates/ide-completion/Cargo.toml @@ -28,6 +28,7 @@ syntax.workspace = true # completions crate should depend only on the top-level `hir` package. if you need # something from some `hir-xxx` subpackage, reexport the API via `hir`. hir.workspace = true +macros.workspace = true [dev-dependencies] expect-test = "1.5.1" diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs index b822f53d7b7b..abae3cb36802 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs @@ -16,6 +16,7 @@ pub(crate) mod lifetime; pub(crate) mod mod_; pub(crate) mod pattern; pub(crate) mod postfix; +pub(crate) mod ra_fixture; pub(crate) mod record; pub(crate) mod snippet; pub(crate) mod r#type; @@ -74,6 +75,10 @@ impl Completions { self.buf.push(item) } + fn add_many(&mut self, items: impl IntoIterator) { + self.buf.extend(items) + } + fn add_opt(&mut self, item: Option) { if let Some(item) = item { self.buf.push(item) @@ -106,6 +111,13 @@ impl Completions { } } + pub(crate) fn add_type_keywords(&mut self, ctx: &CompletionContext<'_>) { + self.add_keyword_snippet(ctx, "fn", "fn($1)"); + self.add_keyword_snippet(ctx, "dyn", "dyn $0"); + self.add_keyword_snippet(ctx, "impl", "impl $0"); + self.add_keyword_snippet(ctx, "for", "for<$1>"); + } + pub(crate) fn add_super_keyword( &mut self, ctx: &CompletionContext<'_>, diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute.rs index e174b0c8922a..297ce3339e02 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute.rs @@ -231,7 +231,7 @@ const fn attr( macro_rules! attrs { // attributes applicable to all items [@ { item $($tt:tt)* } {$($acc:tt)*}] => { - attrs!(@ { $($tt)* } { $($acc)*, "deprecated", "doc", "dochidden", "docalias", "must_use", "no_mangle" }) + attrs!(@ { $($tt)* } { $($acc)*, "deprecated", "doc", "dochidden", "docalias", "docinclude", "must_use", "no_mangle" }) }; // attributes applicable to all adts [@ { adt $($tt:tt)* } {$($acc:tt)*}] => { @@ -345,6 +345,7 @@ const ATTRIBUTES: &[AttrCompletion] = &[ attr(r#"doc = "…""#, Some("doc"), Some(r#"doc = "${0:docs}""#)), attr(r#"doc(alias = "…")"#, Some("docalias"), Some(r#"doc(alias = "${0:docs}")"#)), attr(r#"doc(hidden)"#, Some("dochidden"), Some(r#"doc(hidden)"#)), + attr(r#"doc = include_str!("…")"#, Some("docinclude"), Some(r#"doc = include_str!("$0")"#)), attr("expect(…)", Some("expect"), Some("expect(${0:lint})")), attr( r#"export_name = "…""#, diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs index 72b245ccafd9..511b59385702 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs @@ -25,9 +25,7 @@ pub(crate) fn complete_dot( _ => return, }; - let is_field_access = matches!(dot_access.kind, DotAccessKind::Field { .. }); - let is_method_access_with_parens = - matches!(dot_access.kind, DotAccessKind::Method { has_parens: true }); + let has_parens = matches!(dot_access.kind, DotAccessKind::Method); let traits_in_scope = ctx.traits_in_scope(); // Suggest .await syntax for types that implement Future trait @@ -48,7 +46,7 @@ pub(crate) fn complete_dot( DotAccessKind::Field { receiver_is_ambiguous_float_literal: _ } => { DotAccessKind::Field { receiver_is_ambiguous_float_literal: false } } - it @ DotAccessKind::Method { .. } => *it, + it @ DotAccessKind::Method => *it, }; let dot_access = DotAccess { receiver: dot_access.receiver.clone(), @@ -67,8 +65,7 @@ pub(crate) fn complete_dot( acc.add_field(ctx, &dot_access, Some(await_str.clone()), field, &ty) }, |acc, field, ty| acc.add_tuple_field(ctx, Some(await_str.clone()), field, &ty), - is_field_access, - is_method_access_with_parens, + has_parens, ); complete_methods(ctx, &future_output, &traits_in_scope, |func| { acc.add_method(ctx, &dot_access, func, Some(await_str.clone()), None) @@ -82,8 +79,7 @@ pub(crate) fn complete_dot( receiver_ty, |acc, field, ty| acc.add_field(ctx, dot_access, None, field, &ty), |acc, field, ty| acc.add_tuple_field(ctx, None, field, &ty), - is_field_access, - is_method_access_with_parens, + has_parens, ); complete_methods(ctx, receiver_ty, &traits_in_scope, |func| { acc.add_method(ctx, dot_access, func, None, None) @@ -112,7 +108,7 @@ pub(crate) fn complete_dot( DotAccessKind::Field { receiver_is_ambiguous_float_literal: _ } => { DotAccessKind::Field { receiver_is_ambiguous_float_literal: false } } - it @ DotAccessKind::Method { .. } => *it, + it @ DotAccessKind::Method => *it, }; let dot_access = DotAccess { receiver: dot_access.receiver.clone(), @@ -173,7 +169,6 @@ pub(crate) fn complete_undotted_self( ) }, |acc, field, ty| acc.add_tuple_field(ctx, Some(SmolStr::new_static("self")), field, &ty), - true, false, ); complete_methods(ctx, &ty, &ctx.traits_in_scope(), |func| { @@ -182,7 +177,7 @@ pub(crate) fn complete_undotted_self( &DotAccess { receiver: None, receiver_ty: None, - kind: DotAccessKind::Method { has_parens: false }, + kind: DotAccessKind::Field { receiver_is_ambiguous_float_literal: false }, ctx: DotAccessExprCtx { in_block_expr: expr_ctx.in_block_expr, in_breakable: expr_ctx.in_breakable, @@ -201,15 +196,13 @@ fn complete_fields( receiver: &hir::Type<'_>, mut named_field: impl FnMut(&mut Completions, hir::Field, hir::Type<'_>), mut tuple_index: impl FnMut(&mut Completions, usize, hir::Type<'_>), - is_field_access: bool, - is_method_access_with_parens: bool, + has_parens: bool, ) { let mut seen_names = FxHashSet::default(); for receiver in receiver.autoderef(ctx.db) { for (field, ty) in receiver.fields(ctx.db) { if seen_names.insert(field.name(ctx.db)) - && (is_field_access - || (is_method_access_with_parens && (ty.is_fn() || ty.is_closure()))) + && (!has_parens || ty.is_fn() || ty.is_closure()) { named_field(acc, field, ty); } @@ -218,8 +211,7 @@ fn complete_fields( // Tuples are always the last type in a deref chain, so just check if the name is // already seen without inserting into the hashset. if !seen_names.contains(&hir::Name::new_tuple_field(i)) - && (is_field_access - || (is_method_access_with_parens && (ty.is_fn() || ty.is_closure()))) + && (!has_parens || ty.is_fn() || ty.is_closure()) { // Tuple fields are always public (tuple struct fields are handled above). tuple_index(acc, i, ty); @@ -1364,18 +1356,71 @@ fn foo() { r#" struct Foo { baz: fn() } impl Foo { - fn bar(self, t: T): T { t } + fn bar(self, t: T) -> T { t } } fn baz() { let foo = Foo{ baz: || {} }; - foo.ba$0::<>; + foo.ba$0; } "#, expect![[r#" - me bar(…) fn(self, T) + fd baz fn() + me bar(…) fn(self, T) -> T "#]], ); + + check_edit( + "baz", + r#" +struct Foo { baz: fn() } +impl Foo { + fn bar(self, t: T) -> T { t } +} + +fn baz() { + let foo = Foo{ baz: || {} }; + foo.ba$0; +} +"#, + r#" +struct Foo { baz: fn() } +impl Foo { + fn bar(self, t: T) -> T { t } +} + +fn baz() { + let foo = Foo{ baz: || {} }; + (foo.baz)(); +} +"#, + ); + + check_edit( + "bar", + r#" +struct Foo { baz: fn() } +impl Foo { + fn bar(self, t: T) -> T { t } +} + +fn baz() { + let foo = Foo{ baz: || {} }; + foo.ba$0; +} +"#, + r#" +struct Foo { baz: fn() } +impl Foo { + fn bar(self, t: T) -> T { t } +} + +fn baz() { + let foo = Foo{ baz: || {} }; + foo.bar(${1:t})$0; +} +"#, + ); } #[test] diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/pattern.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/pattern.rs index 0ce81d02b409..dcddc24890ac 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/pattern.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/pattern.rs @@ -42,6 +42,11 @@ pub(crate) fn complete_pattern( } } + if pattern_ctx.after_if_expr { + add_keyword("else", "else {\n $0\n}"); + add_keyword("else if", "else if $1 {\n $0\n}"); + } + if pattern_ctx.record_pat.is_some() { return; } diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs index 73cbe3f0aaab..ab3f619fd7f5 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs @@ -43,7 +43,7 @@ pub(crate) fn complete_postfix( DotAccessKind::Field { receiver_is_ambiguous_float_literal } => { receiver_is_ambiguous_float_literal } - DotAccessKind::Method { .. } => false, + DotAccessKind::Method => false, }, ), _ => return, @@ -460,6 +460,8 @@ pub(crate) fn is_in_condition(it: &ast::Expr) -> bool { ast::MatchGuard(guard) => guard.condition()? == *it, ast::BinExpr(bin_expr) => (bin_expr.op_token()?.kind() == T![&&]) .then(|| is_in_condition(&bin_expr.into()))?, + ast::Expr(expr) => (expr.syntax().text_range().start() == it.syntax().text_range().start()) + .then(|| is_in_condition(&expr))?, _ => return None, } }) }) diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/ra_fixture.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/ra_fixture.rs new file mode 100644 index 000000000000..b44c90757f68 --- /dev/null +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/ra_fixture.rs @@ -0,0 +1,113 @@ +//! Injected completions for `#[rust_analyzer::rust_fixture]`. + +use hir::FilePositionWrapper; +use ide_db::{ + impl_empty_upmap_from_ra_fixture, + ra_fixture::{RaFixtureAnalysis, UpmapFromRaFixture}, +}; +use syntax::ast; + +use crate::{ + CompletionItemKind, CompletionItemRefMode, CompletionRelevance, completions::Completions, + context::CompletionContext, item::CompletionItemLabel, +}; + +pub(crate) fn complete_ra_fixture( + acc: &mut Completions, + ctx: &CompletionContext<'_>, + original: &ast::String, + expanded: &ast::String, +) -> Option<()> { + let analysis = RaFixtureAnalysis::analyze_ra_fixture( + &ctx.sema, + original.clone(), + expanded, + ctx.config.minicore, + &mut |_| {}, + )?; + let (virtual_file_id, virtual_offset) = analysis.map_offset_down(ctx.position.offset)?; + let completions = hir::attach_db_allow_change(&analysis.db, || { + crate::completions( + &analysis.db, + ctx.config, + FilePositionWrapper { file_id: virtual_file_id, offset: virtual_offset }, + ctx.trigger_character, + ) + })?; + let completions = + completions.upmap_from_ra_fixture(&analysis, virtual_file_id, ctx.position.file_id).ok()?; + acc.add_many(completions); + Some(()) +} + +impl_empty_upmap_from_ra_fixture!( + CompletionItemLabel, + CompletionItemKind, + CompletionRelevance, + CompletionItemRefMode, +); + +#[cfg(test)] +mod tests { + use expect_test::expect; + + use crate::tests::check; + + #[test] + fn it_works() { + check( + r##" +fn fixture(#[rust_analyzer::rust_fixture] ra_fixture: &str) {} + +fn foo() { + fixture(r#" +fn complete_me() {} + +fn baz() { + let foo_bar_baz = 123; + f$0 +} + "#); +} + "##, + expect![[r#" + fn baz() fn() + fn complete_me() fn() + lc foo_bar_baz i32 + bt u32 u32 + kw async + kw const + kw crate:: + kw enum + kw extern + kw false + kw fn + kw for + kw if + kw if let + kw impl + kw impl for + kw let + kw letm + kw loop + kw match + kw mod + kw return + kw self:: + kw static + kw struct + kw trait + kw true + kw type + kw union + kw unsafe + kw use + kw while + kw while let + sn macro_rules + sn pd + sn ppd + "#]], + ); + } +} diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/record.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/record.rs index 28b324d61afa..bfa567009c01 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/record.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/record.rs @@ -178,6 +178,33 @@ fn baz() { ) } + #[test] + fn literal_struct_completion_shorthand() { + check_edit( + "FooDesc{}", + r#" +struct FooDesc { pub bar: bool, n: i32 } + +fn create_foo(foo_desc: &FooDesc) -> () { () } + +fn baz() { + let bar = true; + let foo = create_foo(&$0); +} + "#, + r#" +struct FooDesc { pub bar: bool, n: i32 } + +fn create_foo(foo_desc: &FooDesc) -> () { () } + +fn baz() { + let bar = true; + let foo = create_foo(&FooDesc { bar$1, n: ${2:()} }$0); +} + "#, + ) + } + #[test] fn enum_variant_no_snippets() { let conf = CompletionConfig { snippet_cap: SnippetCap::new(false), ..TEST_CONFIG }; diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/type.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/type.rs index 3112462cda4e..3465b73321e9 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/type.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/type.rs @@ -205,6 +205,7 @@ pub(crate) fn complete_type_path( }; acc.add_nameref_keywords_with_colon(ctx); + acc.add_type_keywords(ctx); ctx.process_all_names(&mut |name, def, doc_aliases| { if scope_def_applicable(def) { acc.add_path_resolution(ctx, path_ctx, name, def, doc_aliases); diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/config.rs b/src/tools/rust-analyzer/crates/ide-completion/src/config.rs index b7367cb62f09..5623257a2792 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/config.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/config.rs @@ -6,13 +6,13 @@ use hir::FindPathConfig; use ide_db::{ - SnippetCap, + MiniCore, SnippetCap, imports::{import_assets::ImportPathConfig, insert_use::InsertUseConfig}, }; use crate::{CompletionFieldsToResolve, snippet::Snippet}; -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug)] pub struct CompletionConfig<'a> { pub enable_postfix_completions: bool, pub enable_imports_on_the_fly: bool, @@ -35,6 +35,7 @@ pub struct CompletionConfig<'a> { pub fields_to_resolve: CompletionFieldsToResolve, pub exclude_flyimport: Vec<(String, AutoImportExclusionType)>, pub exclude_traits: &'a [String], + pub minicore: MiniCore<'a>, } #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs index 4032329ac658..2f166b718451 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs @@ -279,6 +279,7 @@ pub(crate) struct PatternContext { pub(crate) param_ctx: Option, pub(crate) has_type_ascription: bool, pub(crate) should_suggest_name: bool, + pub(crate) after_if_expr: bool, pub(crate) parent_pat: Option, pub(crate) ref_token: Option, pub(crate) mut_token: Option, @@ -405,9 +406,7 @@ pub(crate) enum DotAccessKind { /// like `0.$0` receiver_is_ambiguous_float_literal: bool, }, - Method { - has_parens: bool, - }, + Method, } #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -440,6 +439,7 @@ pub(crate) struct CompletionContext<'a> { pub(crate) config: &'a CompletionConfig<'a>, pub(crate) position: FilePosition, + pub(crate) trigger_character: Option, /// The token before the cursor, in the original file. pub(crate) original_token: SyntaxToken, /// The token before the cursor, in the macro-expanded file. @@ -703,6 +703,7 @@ impl<'db> CompletionContext<'db> { db: &'db RootDatabase, position @ FilePosition { file_id, offset }: FilePosition, config: &'db CompletionConfig<'db>, + trigger_character: Option, ) -> Option<(CompletionContext<'db>, CompletionAnalysis<'db>)> { let _p = tracing::info_span!("CompletionContext::new").entered(); let sema = Semantics::new(db); @@ -871,6 +872,7 @@ impl<'db> CompletionContext<'db> { db, config, position, + trigger_character, original_token, token, krate, diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs index 873eceff5f5f..b3d9ff004610 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs @@ -891,44 +891,53 @@ fn classify_name_ref<'db>( return Some(make_res(kind)); } + let field_expr_handle = |receiver, node| { + let receiver = find_opt_node_in_file(original_file, receiver); + let receiver_is_ambiguous_float_literal = match &receiver { + Some(ast::Expr::Literal(l)) => matches! { + l.kind(), + ast::LiteralKind::FloatNumber { .. } if l.syntax().last_token().is_some_and(|it| it.text().ends_with('.')) + }, + _ => false, + }; + + let receiver_is_part_of_indivisible_expression = match &receiver { + Some(ast::Expr::IfExpr(_)) => { + let next_token_kind = + next_non_trivia_token(name_ref.syntax().clone()).map(|t| t.kind()); + next_token_kind == Some(SyntaxKind::ELSE_KW) + } + _ => false, + }; + if receiver_is_part_of_indivisible_expression { + return None; + } + + let mut receiver_ty = receiver.as_ref().and_then(|it| sema.type_of_expr(it)); + if receiver_is_ambiguous_float_literal { + // `123.|` is parsed as a float but should actually be an integer. + always!(receiver_ty.as_ref().is_none_or(|receiver_ty| receiver_ty.original.is_float())); + receiver_ty = + Some(TypeInfo { original: hir::BuiltinType::i32().ty(sema.db), adjusted: None }); + } + + let kind = NameRefKind::DotAccess(DotAccess { + receiver_ty, + kind: DotAccessKind::Field { receiver_is_ambiguous_float_literal }, + receiver, + ctx: DotAccessExprCtx { + in_block_expr: is_in_block(node), + in_breakable: is_in_breakable(node).unzip().0, + }, + }); + Some(make_res(kind)) + }; + let segment = match_ast! { match parent { ast::PathSegment(segment) => segment, ast::FieldExpr(field) => { - let receiver = find_opt_node_in_file(original_file, field.expr()); - let receiver_is_ambiguous_float_literal = match &receiver { - Some(ast::Expr::Literal(l)) => matches! { - l.kind(), - ast::LiteralKind::FloatNumber { .. } if l.syntax().last_token().is_some_and(|it| it.text().ends_with('.')) - }, - _ => false, - }; - - let receiver_is_part_of_indivisible_expression = match &receiver { - Some(ast::Expr::IfExpr(_)) => { - let next_token_kind = next_non_trivia_token(name_ref.syntax().clone()).map(|t| t.kind()); - next_token_kind == Some(SyntaxKind::ELSE_KW) - }, - _ => false - }; - if receiver_is_part_of_indivisible_expression { - return None; - } - - let mut receiver_ty = receiver.as_ref().and_then(|it| sema.type_of_expr(it)); - if receiver_is_ambiguous_float_literal { - // `123.|` is parsed as a float but should actually be an integer. - always!(receiver_ty.as_ref().is_none_or(|receiver_ty| receiver_ty.original.is_float())); - receiver_ty = Some(TypeInfo { original: hir::BuiltinType::i32().ty(sema.db), adjusted: None }); - } - - let kind = NameRefKind::DotAccess(DotAccess { - receiver_ty, - kind: DotAccessKind::Field { receiver_is_ambiguous_float_literal }, - receiver, - ctx: DotAccessExprCtx { in_block_expr: is_in_block(field.syntax()), in_breakable: is_in_breakable(field.syntax()).unzip().0 } - }); - return Some(make_res(kind)); + return field_expr_handle(field.expr(), field.syntax()); }, ast::ExternCrate(_) => { let kind = NameRefKind::ExternCrate; @@ -937,9 +946,12 @@ fn classify_name_ref<'db>( ast::MethodCallExpr(method) => { let receiver = find_opt_node_in_file(original_file, method.receiver()); let has_parens = has_parens(&method); + if !has_parens && let Some(res) = field_expr_handle(method.receiver(), method.syntax()) { + return Some(res) + } let kind = NameRefKind::DotAccess(DotAccess { receiver_ty: receiver.as_ref().and_then(|it| sema.type_of_expr(it)), - kind: DotAccessKind::Method { has_parens }, + kind: DotAccessKind::Method, receiver, ctx: DotAccessExprCtx { in_block_expr: is_in_block(method.syntax()), in_breakable: is_in_breakable(method.syntax()).unzip().0 } }); @@ -987,10 +999,6 @@ fn classify_name_ref<'db>( } } }; - let after_if_expr = |node: SyntaxNode| { - let prev_expr = prev_expr(node); - matches!(prev_expr, Some(ast::Expr::IfExpr(_))) - }; let after_incomplete_let = |node: SyntaxNode| { prev_expr(node).and_then(|it| it.syntax().parent()).and_then(ast::LetStmt::cast) }; @@ -1230,7 +1238,7 @@ fn classify_name_ref<'db>( let it = expr.syntax(); let in_block_expr = is_in_block(it); let (in_loop_body, innermost_breakable) = is_in_breakable(it).unzip(); - let after_if_expr = after_if_expr(it.clone()); + let after_if_expr = is_after_if_expr(it.clone()); let ref_expr_parent = path.as_single_name_ref().and_then(|_| it.parent()).and_then(ast::RefExpr::cast); let after_amp = non_trivia_sibling(it.clone().into(), Direction::Prev) @@ -1751,6 +1759,7 @@ fn pattern_context_for( param_ctx, has_type_ascription, should_suggest_name, + after_if_expr: is_after_if_expr(pat.syntax().clone()), parent_pat: pat.syntax().parent().and_then(ast::Pat::cast), mut_token, ref_token, @@ -1890,11 +1899,49 @@ fn is_in_breakable(node: &SyntaxNode) -> Option<(BreakableKind, SyntaxNode)> { } fn is_in_block(node: &SyntaxNode) -> bool { + if has_in_newline_expr_first(node) { + return true; + }; node.parent() .map(|node| ast::ExprStmt::can_cast(node.kind()) || ast::StmtList::can_cast(node.kind())) .unwrap_or(false) } +/// Similar to `has_parens`, heuristic sensing incomplete statement before ambiguous `Expr` +/// +/// Heuristic: +/// +/// If the `PathExpr` is left part of the `Expr` and there is a newline after the `PathExpr`, +/// it is considered that the `PathExpr` is not part of the `Expr`. +fn has_in_newline_expr_first(node: &SyntaxNode) -> bool { + if ast::PathExpr::can_cast(node.kind()) + && let Some(NodeOrToken::Token(next)) = node.next_sibling_or_token() + && next.kind() == SyntaxKind::WHITESPACE + && next.text().contains('\n') + && let Some(stmt_like) = node + .ancestors() + .take_while(|it| it.text_range().start() == node.text_range().start()) + .filter_map(Either::::cast) + .last() + { + stmt_like.syntax().parent().and_then(ast::StmtList::cast).is_some() + } else { + false + } +} + +fn is_after_if_expr(node: SyntaxNode) -> bool { + let node = match node.parent().and_then(Either::::cast) { + Some(stmt) => stmt.syntax().clone(), + None => node, + }; + let prev_sibling = + non_trivia_sibling(node.into(), Direction::Prev).and_then(NodeOrToken::into_node); + iter::successors(prev_sibling, |it| it.last_child_or_token()?.into_node()) + .find_map(ast::IfExpr::cast) + .is_some() +} + fn next_non_trivia_token(e: impl Into) -> Option { let mut token = match e.into() { SyntaxElement::Node(n) => n.last_token()?, diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context/tests.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context/tests.rs index e798f3b23af4..51d28bd4ff98 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/context/tests.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/context/tests.rs @@ -10,7 +10,7 @@ fn check_expected_type_and_name(#[rust_analyzer::rust_fixture] ra_fixture: &str, let (db, pos) = position(ra_fixture); let config = TEST_CONFIG; let (completion_context, _analysis) = - hir::attach_db(&db, || CompletionContext::new(&db, pos, &config).unwrap()); + hir::attach_db(&db, || CompletionContext::new(&db, pos, &config, None).unwrap()); let ty = completion_context .expected_type diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/item.rs b/src/tools/rust-analyzer/crates/ide-completion/src/item.rs index 5fb9dc93c93d..303c71230d60 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/item.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/item.rs @@ -9,6 +9,7 @@ use ide_db::{ imports::import_assets::LocatedImport, }; use itertools::Itertools; +use macros::UpmapFromRaFixture; use smallvec::SmallVec; use stdx::{format_to, impl_from, never}; use syntax::{Edition, SmolStr, TextRange, TextSize, format_smolstr}; @@ -23,7 +24,7 @@ use crate::{ /// /// It is basically a POD with various properties. To construct a [`CompletionItem`], /// use [`Builder::new`] method and the [`Builder`] struct. -#[derive(Clone)] +#[derive(Clone, UpmapFromRaFixture)] #[non_exhaustive] pub struct CompletionItem { /// Label in the completion pop up which identifies completion. diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs b/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs index a70a1138d2f4..8a0aaf3f0cc2 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs @@ -187,7 +187,7 @@ pub fn completions( position: FilePosition, trigger_character: Option, ) -> Option> { - let (ctx, analysis) = &CompletionContext::new(db, position, config)?; + let (ctx, analysis) = &CompletionContext::new(db, position, config, trigger_character)?; let mut completions = Completions::default(); // prevent `(` from triggering unwanted completion noise @@ -241,6 +241,7 @@ pub fn completions( completions::extern_abi::complete_extern_abi(acc, ctx, expanded); completions::format_string::format_string(acc, ctx, original, expanded); completions::env_vars::complete_cargo_env_vars(acc, ctx, original, expanded); + completions::ra_fixture::complete_ra_fixture(acc, ctx, original, expanded); } CompletionAnalysis::UnexpandedAttrTT { colon_prefix, diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render.rs index 094e679501fc..c0f09e1d950d 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/render.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/render.rs @@ -171,8 +171,7 @@ pub(crate) fn render_field( builder.insert(receiver.syntax().text_range().start(), "(".to_owned()); builder.insert(ctx.source_range().end(), ")".to_owned()); - let is_parens_needed = - !matches!(dot_access.kind, DotAccessKind::Method { has_parens: true }); + let is_parens_needed = !matches!(dot_access.kind, DotAccessKind::Method); if is_parens_needed { builder.insert(ctx.source_range().end(), "()".to_owned()); diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs index c466019f991f..3235323b3a59 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs @@ -93,8 +93,8 @@ fn render( has_call_parens, .. }) => (false, has_call_parens, ctx.completion.config.snippet_cap), - FuncKind::Method(&DotAccess { kind: DotAccessKind::Method { has_parens }, .. }, _) => { - (true, has_parens, ctx.completion.config.snippet_cap) + FuncKind::Method(&DotAccess { kind: DotAccessKind::Method, .. }, _) => { + (true, true, ctx.completion.config.snippet_cap) } FuncKind::Method(DotAccess { kind: DotAccessKind::Field { .. }, .. }, _) => { (true, false, ctx.completion.config.snippet_cap) diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/variant.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/variant.rs index 42324b4290a7..37d0fa18c497 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/render/variant.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/variant.rs @@ -26,14 +26,23 @@ pub(crate) fn render_record_lit( return RenderedLiteral { literal: path.to_owned(), detail: path.to_owned() }; } let completions = fields.iter().enumerate().format_with(", ", |(idx, field), f| { + let mut fmt_field = |fill, tab| { + let field_name = field.name(ctx.db); + + if let Some(local) = ctx.locals.get(&field_name) + && local + .ty(ctx.db) + .could_unify_with_deeply(ctx.db, &field.ty(ctx.db).to_type(ctx.db)) + { + f(&format_args!("{}{tab}", field_name.display(ctx.db, ctx.edition))) + } else { + f(&format_args!("{}: {fill}", field_name.display(ctx.db, ctx.edition))) + } + }; if snippet_cap.is_some() { - f(&format_args!( - "{}: ${{{}:()}}", - field.name(ctx.db).display(ctx.db, ctx.edition), - idx + 1 - )) + fmt_field(format_args!("${{{}:()}}", idx + 1), format_args!("${}", idx + 1)) } else { - f(&format_args!("{}: ()", field.name(ctx.db).display(ctx.db, ctx.edition))) + fmt_field(format_args!("()"), format_args!("")) } }); diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs index ec9cd9fdf378..83606d21f522 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs @@ -29,7 +29,7 @@ use expect_test::Expect; use hir::db::HirDatabase; use hir::{PrefixKind, setup_tracing}; use ide_db::{ - FilePosition, RootDatabase, SnippetCap, + FilePosition, MiniCore, RootDatabase, SnippetCap, imports::insert_use::{ImportGranularity, InsertUseConfig}, }; use itertools::Itertools; @@ -90,6 +90,7 @@ pub(crate) const TEST_CONFIG: CompletionConfig<'_> = CompletionConfig { exclude_traits: &[], enable_auto_await: true, enable_auto_iter: true, + minicore: MiniCore::default(), }; pub(crate) fn completion_list(#[rust_analyzer::rust_fixture] ra_fixture: &str) -> String { @@ -245,11 +246,10 @@ pub(crate) fn check_edit_with_config( let (db, position) = position(ra_fixture_before); let completions: Vec = hir::attach_db(&db, || crate::completions(&db, &config, position, None).unwrap()); - let (completion,) = completions - .iter() - .filter(|it| it.lookup() == what) - .collect_tuple() - .unwrap_or_else(|| panic!("can't find {what:?} completion in {completions:#?}")); + let Some((completion,)) = completions.iter().filter(|it| it.lookup() == what).collect_tuple() + else { + panic!("can't find {what:?} completion in {completions:#?}") + }; let mut actual = db.file_text(position.file_id).text(&db).to_string(); let mut combined_edit = completion.text_edit.clone(); diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/attribute.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/attribute.rs index 1d2a9c7c8d3c..2a6238997b8e 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/attribute.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/attribute.rs @@ -33,6 +33,7 @@ pub struct Foo(#[m$0] i32); at diagnostic::do_not_recommend at diagnostic::on_unimplemented at doc = "…" + at doc = include_str!("…") at doc(alias = "…") at doc(hidden) at expect(…) @@ -85,6 +86,7 @@ struct Foo; at deprecated at derive(…) at doc = "…" + at doc = include_str!("…") at doc(alias = "…") at doc(hidden) at expect(…) @@ -158,6 +160,7 @@ fn attr_on_source_file() { at deny(…) at deprecated at doc = "…" + at doc = include_str!("…") at doc(alias = "…") at doc(hidden) at expect(…) @@ -189,6 +192,7 @@ fn attr_on_module() { at deny(…) at deprecated at doc = "…" + at doc = include_str!("…") at doc(alias = "…") at doc(hidden) at expect(…) @@ -212,6 +216,7 @@ fn attr_on_module() { at deny(…) at deprecated at doc = "…" + at doc = include_str!("…") at doc(alias = "…") at doc(hidden) at expect(…) @@ -238,6 +243,7 @@ fn attr_on_macro_rules() { at deny(…) at deprecated at doc = "…" + at doc = include_str!("…") at doc(alias = "…") at doc(hidden) at expect(…) @@ -264,6 +270,7 @@ fn attr_on_macro_def() { at deny(…) at deprecated at doc = "…" + at doc = include_str!("…") at doc(alias = "…") at doc(hidden) at expect(…) @@ -288,6 +295,7 @@ fn attr_on_extern_crate() { at deny(…) at deprecated at doc = "…" + at doc = include_str!("…") at doc(alias = "…") at doc(hidden) at expect(…) @@ -313,6 +321,7 @@ fn attr_on_use() { at deny(…) at deprecated at doc = "…" + at doc = include_str!("…") at doc(alias = "…") at doc(hidden) at expect(…) @@ -337,6 +346,7 @@ fn attr_on_type_alias() { at deny(…) at deprecated at doc = "…" + at doc = include_str!("…") at doc(alias = "…") at doc(hidden) at expect(…) @@ -368,6 +378,7 @@ struct Foo; at derive(…) at derive_const macro derive_const at doc = "…" + at doc = include_str!("…") at doc(alias = "…") at doc(hidden) at expect(…) @@ -396,6 +407,7 @@ fn attr_on_enum() { at deprecated at derive(…) at doc = "…" + at doc = include_str!("…") at doc(alias = "…") at doc(hidden) at expect(…) @@ -422,6 +434,7 @@ fn attr_on_const() { at deny(…) at deprecated at doc = "…" + at doc = include_str!("…") at doc(alias = "…") at doc(hidden) at expect(…) @@ -446,6 +459,7 @@ fn attr_on_static() { at deny(…) at deprecated at doc = "…" + at doc = include_str!("…") at doc(alias = "…") at doc(hidden) at expect(…) @@ -476,6 +490,7 @@ fn attr_on_trait() { at deprecated at diagnostic::on_unimplemented at doc = "…" + at doc = include_str!("…") at doc(alias = "…") at doc(hidden) at expect(…) @@ -502,6 +517,7 @@ fn attr_on_impl() { at deprecated at diagnostic::do_not_recommend at doc = "…" + at doc = include_str!("…") at doc(alias = "…") at doc(hidden) at expect(…) @@ -522,6 +538,7 @@ fn attr_on_impl() { at deny(…) at deprecated at doc = "…" + at doc = include_str!("…") at doc(alias = "…") at doc(hidden) at expect(…) @@ -548,6 +565,7 @@ fn attr_with_qualifier() { at deprecated at do_not_recommend at doc = "…" + at doc = include_str!("…") at doc(alias = "…") at doc(hidden) at expect(…) @@ -566,6 +584,7 @@ fn attr_with_qualifier() { at deny(…) at deprecated at doc = "…" + at doc = include_str!("…") at doc(alias = "…") at doc(hidden) at expect(…) @@ -616,6 +635,7 @@ fn attr_on_extern_block() { at deny(…) at deprecated at doc = "…" + at doc = include_str!("…") at doc(alias = "…") at doc(hidden) at expect(…) @@ -637,6 +657,7 @@ fn attr_on_extern_block() { at deny(…) at deprecated at doc = "…" + at doc = include_str!("…") at doc(alias = "…") at doc(hidden) at expect(…) @@ -682,6 +703,7 @@ fn attr_on_fn() { at deny(…) at deprecated at doc = "…" + at doc = include_str!("…") at doc(alias = "…") at doc(hidden) at expect(…) @@ -724,6 +746,7 @@ fn attr_in_source_file_end() { at diagnostic::do_not_recommend at diagnostic::on_unimplemented at doc = "…" + at doc = include_str!("…") at doc(alias = "…") at doc(hidden) at expect(…) diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs index 5363a68af723..4033aa5d9c5e 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs @@ -1869,6 +1869,298 @@ fn foo() { let x = if foo {} $0 else if true {} else {}; } sn ppd "#]], ); + check( + r#" +fn foo() { [if foo {} $0]} +"#, + expect![[r#" + fn foo() fn() + bt u32 u32 + kw async + kw const + kw crate:: + kw else + kw else if + kw enum + kw extern + kw false + kw fn + kw for + kw if + kw if let + kw impl + kw impl for + kw let + kw letm + kw loop + kw match + kw mod + kw return + kw self:: + kw static + kw struct + kw trait + kw true + kw type + kw union + kw unsafe + kw use + kw while + kw while let + sn macro_rules + sn pd + sn ppd + "#]], + ); + check( + r#" +fn foo() { [if foo {} el$0]} +"#, + expect![[r#" + fn foo() fn() + bt u32 u32 + kw async + kw const + kw crate:: + kw else + kw else if + kw enum + kw extern + kw false + kw fn + kw for + kw if + kw if let + kw impl + kw impl for + kw let + kw letm + kw loop + kw match + kw mod + kw return + kw self:: + kw static + kw struct + kw trait + kw true + kw type + kw union + kw unsafe + kw use + kw while + kw while let + sn macro_rules + sn pd + sn ppd + "#]], + ); + check( + r#" +fn foo() { 2 + if foo {} $0 } +"#, + expect![[r#" + fn foo() fn() + bt u32 u32 + kw async + kw const + kw crate:: + kw else + kw else if + kw enum + kw extern + kw false + kw fn + kw for + kw if + kw if let + kw impl + kw impl for + kw let + kw letm + kw loop + kw match + kw mod + kw return + kw self:: + kw static + kw struct + kw trait + kw true + kw type + kw union + kw unsafe + kw use + kw while + kw while let + sn macro_rules + sn pd + sn ppd + "#]], + ); + check( + r#" +fn foo() { -if foo {} $0 } +"#, + expect![[r#" + fn foo() fn() + bt u32 u32 + kw async + kw const + kw crate:: + kw else + kw else if + kw enum + kw extern + kw false + kw fn + kw for + kw if + kw if let + kw impl + kw impl for + kw let + kw letm + kw loop + kw match + kw mod + kw return + kw self:: + kw static + kw struct + kw trait + kw true + kw type + kw union + kw unsafe + kw use + kw while + kw while let + sn macro_rules + sn pd + sn ppd + "#]], + ); + check( + r#" +fn foo() { &mut if foo {} $0 } +"#, + expect![[r#" + fn foo() fn() + bt u32 u32 + kw async + kw const + kw crate:: + kw else + kw else if + kw enum + kw extern + kw false + kw fn + kw for + kw if + kw if let + kw impl + kw impl for + kw let + kw letm + kw loop + kw match + kw mod + kw return + kw self:: + kw static + kw struct + kw trait + kw true + kw type + kw union + kw unsafe + kw use + kw while + kw while let + sn macro_rules + sn pd + sn ppd + "#]], + ); + check( + r#" +fn foo() { return if foo {} $0 } +"#, + expect![[r#" + fn foo() fn() + bt u32 u32 + kw async + kw const + kw crate:: + kw else + kw else if + kw enum + kw extern + kw false + kw fn + kw for + kw if + kw if let + kw impl + kw impl for + kw let + kw letm + kw loop + kw match + kw mod + kw return + kw self:: + kw static + kw struct + kw trait + kw true + kw type + kw union + kw unsafe + kw use + kw while + kw while let + sn macro_rules + sn pd + sn ppd + "#]], + ); + check( + r#" +fn foo() { match () { () => if foo {} $0 } } +"#, + expect![[r#" + kw else + kw else if + kw mut + kw ref + "#]], + ); + check( + r#" +fn foo() { match () { () => if foo {} $0, } } +"#, + expect![[r#" + kw else + kw else if + kw mut + kw ref + "#]], + ); + check( + r#" +fn foo() { match () { () => if foo {} $0, _ => (), } } +"#, + expect![[r#" + kw else + kw else if + kw mut + kw ref + "#]], + ); + // FIXME: support else completion after ast::RecordExprField } #[test] @@ -2936,9 +3228,52 @@ fn foo() { ); } +#[test] +fn ambiguous_float_literal_in_ambiguous_method_call() { + check( + r#" +#![rustc_coherence_is_core] + +impl i32 { + pub fn int_method(self) {} +} +impl f64 { + pub fn float_method(self) {} +} + +fn foo() -> (i32, i32) { + 1.$0 + (2, 3) +} + "#, + expect![[r#" + me int_method() fn(self) + sn box Box::new(expr) + sn call function(expr) + sn const const {} + sn dbg dbg!(expr) + sn dbgr dbg!(&expr) + sn deref *expr + sn let let + sn letm let mut + sn match match expr {} + sn ref &expr + sn refm &mut expr + sn return return expr + sn unsafe unsafe {} + "#]], + ); +} + #[test] fn let_in_condition() { check_edit("let", r#"fn f() { if $0 {} }"#, r#"fn f() { if let $1 = $0 {} }"#); + check_edit("let", r#"fn f() { if $0x {} }"#, r#"fn f() { if let $1 = $0x {} }"#); + check_edit( + "let", + r#"fn f() { if $0foo.bar() {} }"#, + r#"fn f() { if let $1 = $0foo.bar() {} }"#, + ); } #[test] @@ -2946,6 +3281,293 @@ fn let_in_let_chain() { check_edit("let", r#"fn f() { if true && $0 {} }"#, r#"fn f() { if true && let $1 = $0 {} }"#); } +#[test] +fn let_in_previous_line_of_ambiguous_expr() { + check_edit( + "let", + r#" + fn f() { + $0 + (1, 2).foo(); + }"#, + r#" + fn f() { + let $1 = $0; + (1, 2).foo(); + }"#, + ); + + check_edit( + "let", + r#" + fn f() { + $0 + (1, 2) + }"#, + r#" + fn f() { + let $1 = $0; + (1, 2) + }"#, + ); + + check_edit( + "let", + r#" + fn f() -> i32 { + $0 + -2 + }"#, + r#" + fn f() -> i32 { + let $1 = $0; + -2 + }"#, + ); + + check_edit( + "let", + r#" + fn f() -> [i32; 2] { + $0 + [1, 2] + }"#, + r#" + fn f() -> [i32; 2] { + let $1 = $0; + [1, 2] + }"#, + ); + + check_edit( + "let", + r#" + fn f() -> [u8; 2] { + $0 + *b"01" + }"#, + r#" + fn f() -> [u8; 2] { + let $1 = $0; + *b"01" + }"#, + ); + + check( + r#" + fn foo() { + $0 + *b"01" + }"#, + expect![[r#" + fn foo() fn() + bt u32 u32 + kw async + kw const + kw crate:: + kw enum + kw extern + kw false + kw fn + kw for + kw if + kw if let + kw impl + kw impl for + kw let + kw letm + kw loop + kw match + kw mod + kw return + kw self:: + kw static + kw struct + kw trait + kw true + kw type + kw union + kw unsafe + kw use + kw while + kw while let + sn macro_rules + sn pd + sn ppd + "#]], + ); + + check( + r#" + fn foo() { + match $0 {} + }"#, + expect![[r#" + fn foo() fn() + bt u32 u32 + kw const + kw crate:: + kw false + kw for + kw if + kw if let + kw loop + kw match + kw return + kw self:: + kw true + kw unsafe + kw while + kw while let + "#]], + ); + + check( + r#" + fn foo() { + $0 *b"01" + }"#, + expect![[r#" + fn foo() fn() + bt u32 u32 + kw const + kw crate:: + kw false + kw for + kw if + kw if let + kw loop + kw match + kw return + kw self:: + kw true + kw unsafe + kw while + kw while let + "#]], + ); +} + +#[test] +fn field_in_previous_line_of_ambiguous_expr() { + check( + r#" + struct Foo { field: i32 } + impl Foo { + fn method(&self) {} + } + fn foo() -> (i32, i32) { + let foo = Foo { field: 4 }; + foo.$0 + (2, 3) + }"#, + expect![[r#" + fd field i32 + me method() fn(&self) + sn box Box::new(expr) + sn call function(expr) + sn const const {} + sn dbg dbg!(expr) + sn dbgr dbg!(&expr) + sn deref *expr + sn let let + sn letm let mut + sn match match expr {} + sn ref &expr + sn refm &mut expr + sn return return expr + sn unsafe unsafe {} + "#]], + ); + + check( + r#" + struct Foo { field: i32 } + impl Foo { + fn method(&self) {} + } + fn foo() -> (i32, i32) { + let foo = Foo { field: 4 }; + foo.a$0 + (2, 3) + }"#, + expect![[r#" + fd field i32 + me method() fn(&self) + sn box Box::new(expr) + sn call function(expr) + sn const const {} + sn dbg dbg!(expr) + sn dbgr dbg!(&expr) + sn deref *expr + sn let let + sn letm let mut + sn match match expr {} + sn ref &expr + sn refm &mut expr + sn return return expr + sn unsafe unsafe {} + "#]], + ); +} + +#[test] +fn fn_field_in_previous_line_of_ambiguous_expr() { + check( + r#" + struct Foo { field: fn() } + impl Foo { + fn method(&self) {} + } + fn foo() -> (i32, i32) { + let foo = Foo { field: || () }; + foo.$0 + (2, 3) + }"#, + expect![[r#" + fd field fn() + me method() fn(&self) + sn box Box::new(expr) + sn call function(expr) + sn const const {} + sn dbg dbg!(expr) + sn dbgr dbg!(&expr) + sn deref *expr + sn let let + sn letm let mut + sn match match expr {} + sn ref &expr + sn refm &mut expr + sn return return expr + sn unsafe unsafe {} + "#]], + ); + + check_edit( + "field", + r#" + struct Foo { field: fn() } + impl Foo { + fn method(&self) {} + } + fn foo() -> (i32, i32) { + let foo = Foo { field: || () }; + foo.a$0 + (2, 3) + }"#, + r#" + struct Foo { field: fn() } + impl Foo { + fn method(&self) {} + } + fn foo() -> (i32, i32) { + let foo = Foo { field: || () }; + (foo.field)() + (2, 3) + }"#, + ); +} + #[test] fn private_inherent_and_public_trait() { check( diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/flyimport.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/flyimport.rs index 2d3ebad9340c..0cd42089b487 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/flyimport.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/flyimport.rs @@ -16,7 +16,8 @@ fn check_with_config( expect: Expect, ) { let (db, position) = crate::tests::position(ra_fixture); - let (ctx, analysis) = crate::context::CompletionContext::new(&db, position, &config).unwrap(); + let (ctx, analysis) = + crate::context::CompletionContext::new(&db, position, &config, None).unwrap(); let mut acc = crate::completions::Completions::default(); hir::attach_db(ctx.db, || { diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/item.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/item.rs index ed87b339fedf..61a9da8c278a 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/item.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/item.rs @@ -23,6 +23,10 @@ impl Tra$0 un Union Union bt u32 u32 kw crate:: + kw dyn + kw fn + kw for + kw impl kw self:: "#]], ) @@ -45,6 +49,10 @@ impl Trait for Str$0 un Union Union bt u32 u32 kw crate:: + kw dyn + kw fn + kw for + kw impl kw self:: "#]], ) diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/predicate.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/predicate.rs index 65036f6a2240..682b8904e550 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/predicate.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/predicate.rs @@ -22,6 +22,10 @@ struct Foo<'lt, T, const C: usize> where $0 {} un Union Union bt u32 u32 kw crate:: + kw dyn + kw fn + kw for + kw impl kw self:: "#]], ); @@ -95,6 +99,10 @@ struct Foo<'lt, T, const C: usize> where for<'a> $0 {} un Union Union bt u32 u32 kw crate:: + kw dyn + kw fn + kw for + kw impl kw self:: "#]], ); @@ -120,6 +128,10 @@ impl Record { un Union Union bt u32 u32 kw crate:: + kw dyn + kw fn + kw for + kw impl kw self:: "#]], ); diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/special.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/special.rs index c438ca788062..59a0c144c893 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/special.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/special.rs @@ -1492,6 +1492,10 @@ fn foo(_: a_$0) { } expect![[r#" bt u32 u32 kw crate:: + kw dyn + kw fn + kw for + kw impl kw self:: "#]], ); @@ -1506,6 +1510,10 @@ fn foo() { tp T bt u32 u32 kw crate:: + kw dyn + kw fn + kw for + kw impl kw self:: "#]], ); @@ -1531,6 +1539,10 @@ fn foo() {} expect![[r#" bt u32 u32 kw crate:: + kw dyn + kw fn + kw for + kw impl kw self:: "#]], ); diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/type_pos.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/type_pos.rs index 125e11e9e358..3bbba18c2b9f 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/type_pos.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/type_pos.rs @@ -25,6 +25,10 @@ struct Foo<'lt, T, const C: usize> { un Union Union bt u32 u32 kw crate:: + kw dyn + kw fn + kw for + kw impl kw self:: "#]], ) @@ -50,6 +54,10 @@ struct Foo<'lt, T, const C: usize>(f$0); un Union Union bt u32 u32 kw crate:: + kw dyn + kw fn + kw for + kw impl kw pub kw pub(crate) kw pub(super) @@ -76,6 +84,37 @@ fn x<'lt, T, const C: usize>() -> $0 un Union Union bt u32 u32 kw crate:: + kw dyn + kw fn + kw for + kw impl + kw self:: + "#]], + ); +} + +#[test] +fn fn_return_type_after_reference() { + check_with_base_items( + r#" +fn x<'lt, T, const C: usize>(_: &()) -> &$0 +"#, + expect![[r#" + en Enum Enum + ma makro!(…) macro_rules! makro + md module + st Record Record + st Tuple Tuple + st Unit Unit + tt Trait + tp T + un Union Union + bt u32 u32 + kw crate:: + kw dyn + kw fn + kw for + kw impl kw self:: "#]], ); @@ -106,6 +145,10 @@ fn foo() -> B$0 { bt u32 u32 it () kw crate:: + kw dyn + kw fn + kw for + kw impl kw self:: "#]], ) @@ -131,6 +174,10 @@ const FOO: $0 = Foo(2); bt u32 u32 it Foo kw crate:: + kw dyn + kw fn + kw for + kw impl kw self:: "#]], ); @@ -157,6 +204,10 @@ fn f2() { bt u32 u32 it i32 kw crate:: + kw dyn + kw fn + kw for + kw impl kw self:: "#]], ); @@ -185,6 +236,10 @@ fn f2() { bt u32 u32 it u64 kw crate:: + kw dyn + kw fn + kw for + kw impl kw self:: "#]], ); @@ -210,6 +265,10 @@ fn f2(x: u64) -> $0 { bt u32 u32 it u64 kw crate:: + kw dyn + kw fn + kw for + kw impl kw self:: "#]], ); @@ -236,6 +295,10 @@ fn f2(x: $0) { bt u32 u32 it i32 kw crate:: + kw dyn + kw fn + kw for + kw impl kw self:: "#]], ); @@ -270,6 +333,10 @@ fn foo<'lt, T, const C: usize>() { bt u32 u32 it a::Foo> kw crate:: + kw dyn + kw fn + kw for + kw impl kw self:: "#]], ); @@ -299,6 +366,10 @@ fn foo<'lt, T, const C: usize>() { bt u32 u32 it Foo kw crate:: + kw dyn + kw fn + kw for + kw impl kw self:: "#]], ); @@ -325,6 +396,10 @@ fn foo<'lt, T, const C: usize>() { un Union Union bt u32 u32 kw crate:: + kw dyn + kw fn + kw for + kw impl kw self:: "#]], ); @@ -392,6 +467,10 @@ fn foo<'lt, T: Trait2<$0>, const CONST_PARAM: usize>(_: T) {} un Union Union bt u32 u32 kw crate:: + kw dyn + kw fn + kw for + kw impl kw self:: "#]], ); @@ -442,6 +521,10 @@ impl Tr<$0 un Union Union bt u32 u32 kw crate:: + kw dyn + kw fn + kw for + kw impl kw self:: "#]], ); @@ -487,6 +570,10 @@ fn f(t: impl MyTrait() { S::; } ct CONST Unit ma makro!(…) macro_rules! makro kw crate:: + kw dyn + kw fn + kw for + kw impl kw self:: "#]], ); @@ -968,6 +1135,10 @@ fn foo<'a>() { S::<'static, 'static, F$0, _>; } ct CONST Unit ma makro!(…) macro_rules! makro kw crate:: + kw dyn + kw fn + kw for + kw impl kw self:: "#]], ); @@ -980,6 +1151,10 @@ fn foo<'a>() { S::<'static, F$0, _, _>; } lt 'a ma makro!(…) macro_rules! makro kw crate:: + kw dyn + kw fn + kw for + kw impl kw self:: "#]], ); diff --git a/src/tools/rust-analyzer/crates/ide-db/Cargo.toml b/src/tools/rust-analyzer/crates/ide-db/Cargo.toml index e065adb0f0ba..b7148160182c 100644 --- a/src/tools/rust-analyzer/crates/ide-db/Cargo.toml +++ b/src/tools/rust-analyzer/crates/ide-db/Cargo.toml @@ -30,6 +30,7 @@ query-group.workspace = true triomphe.workspace = true nohash-hasher.workspace = true bitflags.workspace = true +smallvec.workspace = true # local deps base-db.workspace = true @@ -42,15 +43,15 @@ vfs.workspace = true # ide should depend only on the top-level `hir` package. if you need # something from some `hir-xxx` subpackage, reexport the API via `hir`. hir.workspace = true +macros.workspace = true + +test-utils.workspace = true +test-fixture.workspace = true line-index.workspace = true [dev-dependencies] expect-test = "1.5.1" -# local deps -test-utils.workspace = true -test-fixture.workspace = true - [lints] workspace = true diff --git a/src/tools/rust-analyzer/crates/ide-db/src/lib.rs b/src/tools/rust-analyzer/crates/ide-db/src/lib.rs index 44bccd86d870..7efa97be5573 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/lib.rs @@ -2,6 +2,8 @@ //! //! It is mainly a `HirDatabase` for semantic analysis, plus a `SymbolsDatabase`, for fuzzy search. +extern crate self as ide_db; + mod apply_change; pub mod active_parameter; @@ -14,6 +16,8 @@ pub mod items_locator; pub mod label; pub mod path_transform; pub mod prime_caches; +pub mod ra_fixture; +pub mod range_mapper; pub mod rename; pub mod rust_doc; pub mod search; @@ -364,3 +368,25 @@ pub enum Severity { WeakWarning, Allow, } + +#[derive(Debug, Clone, Copy)] +pub struct MiniCore<'a>(&'a str); + +impl<'a> MiniCore<'a> { + #[inline] + pub fn new(minicore: &'a str) -> Self { + Self(minicore) + } + + #[inline] + pub const fn default() -> Self { + Self(test_utils::MiniCore::RAW_SOURCE) + } +} + +impl<'a> Default for MiniCore<'a> { + #[inline] + fn default() -> Self { + Self::default() + } +} diff --git a/src/tools/rust-analyzer/crates/ide-db/src/ra_fixture.rs b/src/tools/rust-analyzer/crates/ide-db/src/ra_fixture.rs new file mode 100644 index 000000000000..1f056a835bc6 --- /dev/null +++ b/src/tools/rust-analyzer/crates/ide-db/src/ra_fixture.rs @@ -0,0 +1,532 @@ +//! Working with the fixtures in r-a tests, and providing IDE services for them. + +use std::hash::{BuildHasher, Hash}; + +use hir::{CfgExpr, FilePositionWrapper, FileRangeWrapper, Semantics}; +use smallvec::SmallVec; +use span::{TextRange, TextSize}; +use syntax::{ + AstToken, SmolStr, + ast::{self, IsString}, +}; + +use crate::{ + MiniCore, RootDatabase, SymbolKind, active_parameter::ActiveParameter, + documentation::Documentation, range_mapper::RangeMapper, search::ReferenceCategory, +}; + +pub use span::FileId; + +impl RootDatabase { + fn from_ra_fixture( + text: &str, + minicore: MiniCore<'_>, + ) -> Result<(RootDatabase, Vec<(FileId, usize)>, Vec), ()> { + // We don't want a mistake in the fixture to crash r-a, so we wrap this in `catch_unwind()`. + std::panic::catch_unwind(|| { + let mut db = RootDatabase::default(); + let fixture = test_fixture::ChangeFixture::parse_with_proc_macros( + &db, + text, + minicore.0, + Vec::new(), + ); + db.apply_change(fixture.change); + let files = fixture + .files + .into_iter() + .zip(fixture.file_lines) + .map(|(file_id, range)| (file_id.file_id(&db), range)) + .collect(); + (db, files, fixture.sysroot_files) + }) + .map_err(|error| { + tracing::error!( + "cannot crate the crate graph: {}\nCrate graph:\n{}\n", + if let Some(&s) = error.downcast_ref::<&'static str>() { + s + } else if let Some(s) = error.downcast_ref::() { + s.as_str() + } else { + "Box" + }, + text, + ); + }) + } +} + +pub struct RaFixtureAnalysis { + pub db: RootDatabase, + tmp_file_ids: Vec<(FileId, usize)>, + line_offsets: Vec, + virtual_file_id_to_line: Vec, + mapper: RangeMapper, + literal: ast::String, + // `minicore` etc.. + sysroot_files: Vec, + combined_len: TextSize, +} + +impl RaFixtureAnalysis { + pub fn analyze_ra_fixture( + sema: &Semantics<'_, RootDatabase>, + literal: ast::String, + expanded: &ast::String, + minicore: MiniCore<'_>, + on_cursor: &mut dyn FnMut(TextRange), + ) -> Option { + if !literal.is_raw() { + return None; + } + + let active_parameter = ActiveParameter::at_token(sema, expanded.syntax().clone())?; + let has_rust_fixture_attr = active_parameter.attrs().is_some_and(|attrs| { + attrs.filter_map(|attr| attr.as_simple_path()).any(|path| { + path.segments() + .zip(["rust_analyzer", "rust_fixture"]) + .all(|(seg, name)| seg.name_ref().map_or(false, |nr| nr.text() == name)) + }) + }); + if !has_rust_fixture_attr { + return None; + } + let value = literal.value().ok()?; + + let mut mapper = RangeMapper::default(); + + // This is used for the `Injector`, to resolve precise location in the string literal, + // which will then be used to resolve precise location in the enclosing file. + let mut offset_with_indent = TextSize::new(0); + // This is used to resolve the location relative to the virtual file into a location + // relative to the indentation-trimmed file which will then (by the `Injector`) used + // to resolve to a location in the actual file. + // Besides indentation, we also skip `$0` cursors for this, since they are not included + // in the virtual files. + let mut offset_without_indent = TextSize::new(0); + + let mut text = &*value; + if let Some(t) = text.strip_prefix('\n') { + offset_with_indent += TextSize::of("\n"); + text = t; + } + // This stores the offsets of each line, **after we remove indentation**. + let mut line_offsets = Vec::new(); + for mut line in text.split_inclusive('\n') { + line_offsets.push(offset_without_indent); + + if line.starts_with("@@") { + // Introducing `//` into a fixture inside fixture causes all sorts of problems, + // so for testing purposes we escape it as `@@` and replace it here. + mapper.add("//", TextRange::at(offset_with_indent, TextSize::of("@@"))); + line = &line["@@".len()..]; + offset_with_indent += TextSize::of("@@"); + offset_without_indent += TextSize::of("@@"); + } + + // Remove indentation to simplify the mapping with fixture (which de-indents). + // Removing indentation shouldn't affect highlighting. + let mut unindented_line = line.trim_start(); + if unindented_line.is_empty() { + // The whole line was whitespaces, but we need the newline. + unindented_line = "\n"; + } + offset_with_indent += TextSize::of(line) - TextSize::of(unindented_line); + + let marker = "$0"; + match unindented_line.find(marker) { + Some(marker_pos) => { + let (before_marker, after_marker) = unindented_line.split_at(marker_pos); + let after_marker = &after_marker[marker.len()..]; + + mapper.add( + before_marker, + TextRange::at(offset_with_indent, TextSize::of(before_marker)), + ); + offset_with_indent += TextSize::of(before_marker); + offset_without_indent += TextSize::of(before_marker); + + if let Some(marker_range) = literal + .map_range_up(TextRange::at(offset_with_indent, TextSize::of(marker))) + { + on_cursor(marker_range); + } + offset_with_indent += TextSize::of(marker); + + mapper.add( + after_marker, + TextRange::at(offset_with_indent, TextSize::of(after_marker)), + ); + offset_with_indent += TextSize::of(after_marker); + offset_without_indent += TextSize::of(after_marker); + } + None => { + mapper.add( + unindented_line, + TextRange::at(offset_with_indent, TextSize::of(unindented_line)), + ); + offset_with_indent += TextSize::of(unindented_line); + offset_without_indent += TextSize::of(unindented_line); + } + } + } + + let combined = mapper.take_text(); + let combined_len = TextSize::of(&combined); + let (analysis, tmp_file_ids, sysroot_files) = + RootDatabase::from_ra_fixture(&combined, minicore).ok()?; + + // We use a `Vec` because we know the `FileId`s will always be close. + let mut virtual_file_id_to_line = Vec::new(); + for &(file_id, line) in &tmp_file_ids { + virtual_file_id_to_line.resize(file_id.index() as usize + 1, usize::MAX); + virtual_file_id_to_line[file_id.index() as usize] = line; + } + + Some(RaFixtureAnalysis { + db: analysis, + tmp_file_ids, + line_offsets, + virtual_file_id_to_line, + mapper, + literal, + sysroot_files, + combined_len, + }) + } + + pub fn files(&self) -> impl Iterator { + self.tmp_file_ids.iter().map(|(file, _)| *file) + } + + /// This returns `None` for minicore or other sysroot files. + fn virtual_file_id_to_line(&self, file_id: FileId) -> Option { + if self.is_sysroot_file(file_id) { + None + } else { + Some(self.virtual_file_id_to_line[file_id.index() as usize]) + } + } + + pub fn map_offset_down(&self, offset: TextSize) -> Option<(FileId, TextSize)> { + let inside_literal_range = self.literal.map_offset_down(offset)?; + let combined_offset = self.mapper.map_offset_down(inside_literal_range)?; + // There is usually a small number of files, so a linear search is smaller and faster. + let (_, &(file_id, file_line)) = + self.tmp_file_ids.iter().enumerate().find(|&(idx, &(_, file_line))| { + let file_start = self.line_offsets[file_line]; + let file_end = self + .tmp_file_ids + .get(idx + 1) + .map(|&(_, next_file_line)| self.line_offsets[next_file_line]) + .unwrap_or_else(|| self.combined_len); + TextRange::new(file_start, file_end).contains(combined_offset) + })?; + let file_line_offset = self.line_offsets[file_line]; + let file_offset = combined_offset - file_line_offset; + Some((file_id, file_offset)) + } + + pub fn map_range_down(&self, range: TextRange) -> Option<(FileId, TextRange)> { + let (start_file_id, start_offset) = self.map_offset_down(range.start())?; + let (end_file_id, end_offset) = self.map_offset_down(range.end())?; + if start_file_id != end_file_id { + None + } else { + Some((start_file_id, TextRange::new(start_offset, end_offset))) + } + } + + pub fn map_range_up( + &self, + virtual_file: FileId, + range: TextRange, + ) -> impl Iterator { + // This could be `None` if the file is empty. + self.virtual_file_id_to_line(virtual_file) + .and_then(|line| self.line_offsets.get(line)) + .into_iter() + .flat_map(move |&tmp_file_offset| { + // Resolve the offset relative to the virtual file to an offset relative to the combined indentation-trimmed file + let range = range + tmp_file_offset; + // Then resolve that to an offset relative to the real file. + self.mapper.map_range_up(range) + }) + // And finally resolve the offset relative to the literal to relative to the file. + .filter_map(|range| self.literal.map_range_up(range)) + } + + pub fn map_offset_up(&self, virtual_file: FileId, offset: TextSize) -> Option { + self.map_range_up(virtual_file, TextRange::empty(offset)).next().map(|range| range.start()) + } + + pub fn is_sysroot_file(&self, file_id: FileId) -> bool { + self.sysroot_files.contains(&file_id) + } +} + +pub trait UpmapFromRaFixture: Sized { + fn upmap_from_ra_fixture( + self, + analysis: &RaFixtureAnalysis, + virtual_file_id: FileId, + real_file_id: FileId, + ) -> Result; +} + +trait IsEmpty { + fn is_empty(&self) -> bool; +} + +impl IsEmpty for Vec { + fn is_empty(&self) -> bool { + self.is_empty() + } +} + +impl IsEmpty for SmallVec<[T; N]> { + fn is_empty(&self) -> bool { + self.is_empty() + } +} + +#[allow(clippy::disallowed_types)] +impl IsEmpty for std::collections::HashMap { + fn is_empty(&self) -> bool { + self.is_empty() + } +} + +fn upmap_collection( + collection: Collection, + analysis: &RaFixtureAnalysis, + virtual_file_id: FileId, + real_file_id: FileId, +) -> Result +where + T: UpmapFromRaFixture, + Collection: IntoIterator + FromIterator + IsEmpty, +{ + if collection.is_empty() { + // The collection was already empty, don't mark it as failing just because of that. + return Ok(collection); + } + let result = collection + .into_iter() + .filter_map(|item| item.upmap_from_ra_fixture(analysis, virtual_file_id, real_file_id).ok()) + .collect::(); + if result.is_empty() { + // The collection was emptied by the upmapping - all items errored, therefore mark it as erroring as well. + Err(()) + } else { + Ok(result) + } +} + +impl UpmapFromRaFixture for Option { + fn upmap_from_ra_fixture( + self, + analysis: &RaFixtureAnalysis, + virtual_file_id: FileId, + real_file_id: FileId, + ) -> Result { + Ok(match self { + Some(it) => Some(it.upmap_from_ra_fixture(analysis, virtual_file_id, real_file_id)?), + None => None, + }) + } +} + +impl UpmapFromRaFixture for Vec { + fn upmap_from_ra_fixture( + self, + analysis: &RaFixtureAnalysis, + virtual_file_id: FileId, + real_file_id: FileId, + ) -> Result { + upmap_collection(self, analysis, virtual_file_id, real_file_id) + } +} + +impl UpmapFromRaFixture for SmallVec<[T; N]> { + fn upmap_from_ra_fixture( + self, + analysis: &RaFixtureAnalysis, + virtual_file_id: FileId, + real_file_id: FileId, + ) -> Result { + upmap_collection(self, analysis, virtual_file_id, real_file_id) + } +} + +#[allow(clippy::disallowed_types)] +impl + UpmapFromRaFixture for std::collections::HashMap +{ + fn upmap_from_ra_fixture( + self, + analysis: &RaFixtureAnalysis, + virtual_file_id: FileId, + real_file_id: FileId, + ) -> Result { + upmap_collection(self, analysis, virtual_file_id, real_file_id) + } +} + +// A map of `FileId`s is treated as associating the ranges in the values with the keys. +#[allow(clippy::disallowed_types)] +impl UpmapFromRaFixture + for std::collections::HashMap +{ + fn upmap_from_ra_fixture( + self, + analysis: &RaFixtureAnalysis, + _virtual_file_id: FileId, + real_file_id: FileId, + ) -> Result { + if self.is_empty() { + return Ok(self); + } + let result = self + .into_iter() + .filter_map(|(virtual_file_id, value)| { + Some(( + real_file_id, + value.upmap_from_ra_fixture(analysis, virtual_file_id, real_file_id).ok()?, + )) + }) + .collect::>(); + if result.is_empty() { Err(()) } else { Ok(result) } + } +} + +macro_rules! impl_tuple { + () => {}; // Base case. + ( $first:ident, $( $rest:ident, )* ) => { + impl< + $first: UpmapFromRaFixture, + $( $rest: UpmapFromRaFixture, )* + > UpmapFromRaFixture for ( $first, $( $rest, )* ) { + fn upmap_from_ra_fixture( + self, + analysis: &RaFixtureAnalysis, + virtual_file_id: FileId, + real_file_id: FileId, + ) -> Result { + #[allow(non_snake_case)] + let ( $first, $($rest,)* ) = self; + Ok(( + $first.upmap_from_ra_fixture(analysis, virtual_file_id, real_file_id)?, + $( $rest.upmap_from_ra_fixture(analysis, virtual_file_id, real_file_id)?, )* + )) + } + } + + impl_tuple!( $($rest,)* ); + }; +} +impl_tuple!(A, B, C, D, E,); + +impl UpmapFromRaFixture for TextSize { + fn upmap_from_ra_fixture( + self, + analysis: &RaFixtureAnalysis, + virtual_file_id: FileId, + _real_file_id: FileId, + ) -> Result { + analysis.map_offset_up(virtual_file_id, self).ok_or(()) + } +} + +impl UpmapFromRaFixture for TextRange { + fn upmap_from_ra_fixture( + self, + analysis: &RaFixtureAnalysis, + virtual_file_id: FileId, + _real_file_id: FileId, + ) -> Result { + analysis.map_range_up(virtual_file_id, self).next().ok_or(()) + } +} + +// Deliberately do not implement that, as it's easy to get things misbehave and be treated with the wrong FileId: +// +// impl UpmapFromRaFixture for FileId { +// fn upmap_from_ra_fixture( +// self, +// _analysis: &RaFixtureAnalysis, +// _virtual_file_id: FileId, +// real_file_id: FileId, +// ) -> Result { +// Ok(real_file_id) +// } +// } + +impl UpmapFromRaFixture for FilePositionWrapper { + fn upmap_from_ra_fixture( + self, + analysis: &RaFixtureAnalysis, + _virtual_file_id: FileId, + real_file_id: FileId, + ) -> Result { + Ok(FilePositionWrapper { + file_id: real_file_id, + offset: self.offset.upmap_from_ra_fixture(analysis, self.file_id, real_file_id)?, + }) + } +} + +impl UpmapFromRaFixture for FileRangeWrapper { + fn upmap_from_ra_fixture( + self, + analysis: &RaFixtureAnalysis, + _virtual_file_id: FileId, + real_file_id: FileId, + ) -> Result { + Ok(FileRangeWrapper { + file_id: real_file_id, + range: self.range.upmap_from_ra_fixture(analysis, self.file_id, real_file_id)?, + }) + } +} + +#[macro_export] +macro_rules! impl_empty_upmap_from_ra_fixture { + ( $( $ty:ty ),* $(,)? ) => { + $( + impl $crate::ra_fixture::UpmapFromRaFixture for $ty { + fn upmap_from_ra_fixture( + self, + _analysis: &$crate::ra_fixture::RaFixtureAnalysis, + _virtual_file_id: $crate::ra_fixture::FileId, + _real_file_id: $crate::ra_fixture::FileId, + ) -> Result { + Ok(self) + } + } + )* + }; +} + +impl_empty_upmap_from_ra_fixture!( + bool, + i8, + i16, + i32, + i64, + i128, + u8, + u16, + u32, + u64, + u128, + f32, + f64, + &str, + String, + SmolStr, + Documentation, + SymbolKind, + CfgExpr, + ReferenceCategory, +); diff --git a/src/tools/rust-analyzer/crates/ide-db/src/range_mapper.rs b/src/tools/rust-analyzer/crates/ide-db/src/range_mapper.rs new file mode 100644 index 000000000000..ef84888b83b4 --- /dev/null +++ b/src/tools/rust-analyzer/crates/ide-db/src/range_mapper.rs @@ -0,0 +1,65 @@ +//! Maps between ranges in documents. + +use std::cmp::Ordering; + +use stdx::equal_range_by; +use syntax::{TextRange, TextSize}; + +#[derive(Default)] +pub struct RangeMapper { + buf: String, + ranges: Vec<(TextRange, Option)>, +} + +impl RangeMapper { + pub fn add(&mut self, text: &str, source_range: TextRange) { + let len = TextSize::of(text); + assert_eq!(len, source_range.len()); + self.add_impl(text, Some(source_range.start())); + } + + pub fn add_unmapped(&mut self, text: &str) { + self.add_impl(text, None); + } + + fn add_impl(&mut self, text: &str, source: Option) { + let len = TextSize::of(text); + let target_range = TextRange::at(TextSize::of(&self.buf), len); + self.ranges.push((target_range, source.map(|it| TextRange::at(it, len)))); + self.buf.push_str(text); + } + + pub fn take_text(&mut self) -> String { + std::mem::take(&mut self.buf) + } + + pub fn map_range_up(&self, range: TextRange) -> impl Iterator + '_ { + equal_range_by(&self.ranges, |&(r, _)| { + if range.is_empty() && r.contains(range.start()) { + Ordering::Equal + } else { + TextRange::ordering(r, range) + } + }) + .filter_map(move |i| { + let (target_range, source_range) = self.ranges[i]; + let intersection = target_range.intersect(range).unwrap(); + let source_range = source_range?; + Some(intersection - target_range.start() + source_range.start()) + }) + } + + pub fn map_offset_down(&self, offset: TextSize) -> Option { + // Using a binary search here is a bit complicated because of the `None` entries. + // But the number of lines in fixtures is usually low. + let (target_range, source_range) = + self.ranges.iter().find_map(|&(target_range, source_range)| { + let source_range = source_range?; + if !source_range.contains(offset) { + return None; + } + Some((target_range, source_range)) + })?; + Some(offset - source_range.start() + target_range.start()) + } +} diff --git a/src/tools/rust-analyzer/crates/ide-db/src/source_change.rs b/src/tools/rust-analyzer/crates/ide-db/src/source_change.rs index 16c0d8d97a7d..57072bb5ba36 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/source_change.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/source_change.rs @@ -10,6 +10,7 @@ use crate::text_edit::{TextEdit, TextEditBuilder}; use crate::{SnippetCap, assists::Command, syntax_helpers::tree_diff::diff}; use base_db::AnchoredPathBuf; use itertools::Itertools; +use macros::UpmapFromRaFixture; use nohash_hasher::IntMap; use rustc_hash::FxHashMap; use span::FileId; @@ -20,7 +21,7 @@ use syntax::{ }; /// An annotation ID associated with an indel, to describe changes. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, UpmapFromRaFixture)] pub struct ChangeAnnotationId(u32); impl fmt::Display for ChangeAnnotationId { diff --git a/src/tools/rust-analyzer/crates/ide-db/src/text_edit.rs b/src/tools/rust-analyzer/crates/ide-db/src/text_edit.rs index 6e9bd7bdcc21..d2a73710d58b 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/text_edit.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/text_edit.rs @@ -5,6 +5,7 @@ //! rust-analyzer. use itertools::Itertools; +use macros::UpmapFromRaFixture; pub use span::{TextRange, TextSize}; use std::cmp::max; @@ -13,14 +14,14 @@ use crate::source_change::ChangeAnnotationId; /// `InsertDelete` -- a single "atomic" change to text /// /// Must not overlap with other `InDel`s -#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, Hash, UpmapFromRaFixture)] pub struct Indel { pub insert: String, /// Refers to offsets in the original text pub delete: TextRange, } -#[derive(Default, Debug, Clone)] +#[derive(Default, Debug, Clone, UpmapFromRaFixture)] pub struct TextEdit { /// Invariant: disjoint and sorted by `delete`. indels: Vec, diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mismatched_arg_count.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mismatched_arg_count.rs index 25c1e633ba3b..4ed71f0d3fb8 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mismatched_arg_count.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mismatched_arg_count.rs @@ -485,6 +485,29 @@ fn foo((): (), (): ()) { foo(1); // ^ error: expected 2 arguments, found 1 } +"#, + ); + } + + #[test] + fn regression_17233() { + check_diagnostics( + r#" +pub trait A { + type X: B; +} +pub trait B: A { + fn confused_name(self, _: i32); +} + +pub struct Foo; +impl Foo { + pub fn confused_name(&self) {} +} + +pub fn repro() { + Foo.confused_name(); +} "#, ); } diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/non_exhaustive_let.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/non_exhaustive_let.rs index e31367f3b14e..c86ecd2f03b9 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/non_exhaustive_let.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/non_exhaustive_let.rs @@ -152,6 +152,58 @@ impl Deref for Foo { fn test(x: Foo<(i32, bool)>) { let (_a, _b): &(i32, bool) = &x; } +"#, + ); + } + + #[test] + fn uninhabited_variants() { + check_diagnostics( + r#" +//- minicore: result +enum Infallible {} + +trait Foo { + type Bar; +} + +struct Wrapper { + error: T, +} + +struct FooWrapper { + error: T::Bar, +} + +fn foo>(result: Result) -> T { + let Ok(ok) = result; + ok +} + +fn bar>(result: Result) -> T { + let Ok(ok) = result; + ok +} + +fn baz>(result: Result>) -> T { + let Ok(ok) = result; + ok +} + +fn qux>(result: Result>) -> T { + let Ok(ok) = result; + ok +} + +fn quux>(result: Result) -> T { + let Ok(ok) = result; + ok +} + +fn corge>(result: Result) -> T { + let Ok(ok) = result; + ok +} "#, ); } diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/tests.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/tests.rs index 37af05e0d1bb..3dc155efe96b 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/tests.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/tests.rs @@ -311,7 +311,7 @@ fn minicore_smoke_test() { } fn check(minicore: MiniCore) { - let source = minicore.source_code(); + let source = minicore.source_code(MiniCore::RAW_SOURCE); let mut config = DiagnosticsConfig::test_sample(); // This should be ignored since we conditionally remove code which creates single item use with braces config.disabled.insert("unused_braces".to_owned()); @@ -321,7 +321,7 @@ fn minicore_smoke_test() { } // Checks that there is no diagnostic in minicore for each flag. - for flag in MiniCore::available_flags() { + for flag in MiniCore::available_flags(MiniCore::RAW_SOURCE) { if flag == "clone" { // Clone without copy has `moved-out-of-ref`, so ignoring. // FIXME: Maybe we should merge copy and clone in a single flag? @@ -332,5 +332,5 @@ fn minicore_smoke_test() { } // And one time for all flags, to check codes which are behind multiple flags + prevent name collisions eprintln!("Checking all minicore flags"); - check(MiniCore::from_flags(MiniCore::available_flags())) + check(MiniCore::from_flags(MiniCore::available_flags(MiniCore::RAW_SOURCE))) } diff --git a/src/tools/rust-analyzer/crates/ide/Cargo.toml b/src/tools/rust-analyzer/crates/ide/Cargo.toml index 06d2776ebe87..08ffd391c02d 100644 --- a/src/tools/rust-analyzer/crates/ide/Cargo.toml +++ b/src/tools/rust-analyzer/crates/ide/Cargo.toml @@ -42,6 +42,7 @@ span.workspace = true # ide should depend only on the top-level `hir` package. if you need # something from some `hir-xxx` subpackage, reexport the API via `hir`. hir.workspace = true +macros.workspace = true [target.'cfg(not(any(target_arch = "wasm32", target_os = "emscripten")))'.dependencies] toolchain.workspace = true diff --git a/src/tools/rust-analyzer/crates/ide/src/annotations.rs b/src/tools/rust-analyzer/crates/ide/src/annotations.rs index dec1889926da..36c44044bb5d 100644 --- a/src/tools/rust-analyzer/crates/ide/src/annotations.rs +++ b/src/tools/rust-analyzer/crates/ide/src/annotations.rs @@ -1,6 +1,6 @@ use hir::{HasSource, InFile, InRealFile, Semantics}; use ide_db::{ - FileId, FilePosition, FileRange, FxIndexSet, RootDatabase, defs::Definition, + FileId, FilePosition, FileRange, FxIndexSet, MiniCore, RootDatabase, defs::Definition, helpers::visit_file_defs, }; use itertools::Itertools; @@ -11,7 +11,7 @@ use crate::{ annotations::fn_references::find_all_methods, goto_implementation::goto_implementation, navigation_target, - references::find_all_refs, + references::{FindAllRefsConfig, find_all_refs}, runnables::{Runnable, runnables}, }; @@ -36,7 +36,7 @@ pub enum AnnotationKind { HasReferences { pos: FilePosition, data: Option> }, } -pub struct AnnotationConfig { +pub struct AnnotationConfig<'a> { pub binary_target: bool, pub annotate_runnables: bool, pub annotate_impls: bool, @@ -44,6 +44,7 @@ pub struct AnnotationConfig { pub annotate_method_references: bool, pub annotate_enum_variant_references: bool, pub location: AnnotationLocation, + pub minicore: MiniCore<'a>, } pub enum AnnotationLocation { @@ -53,7 +54,7 @@ pub enum AnnotationLocation { pub(crate) fn annotations( db: &RootDatabase, - config: &AnnotationConfig, + config: &AnnotationConfig<'_>, file_id: FileId, ) -> Vec { let mut annotations = FxIndexSet::default(); @@ -196,13 +197,22 @@ pub(crate) fn annotations( .collect() } -pub(crate) fn resolve_annotation(db: &RootDatabase, mut annotation: Annotation) -> Annotation { +pub(crate) fn resolve_annotation( + db: &RootDatabase, + config: &AnnotationConfig<'_>, + mut annotation: Annotation, +) -> Annotation { match annotation.kind { AnnotationKind::HasImpls { pos, ref mut data } => { *data = goto_implementation(db, pos).map(|range| range.info); } AnnotationKind::HasReferences { pos, ref mut data } => { - *data = find_all_refs(&Semantics::new(db), pos, None).map(|result| { + *data = find_all_refs( + &Semantics::new(db), + pos, + &FindAllRefsConfig { search_scope: None, minicore: config.minicore }, + ) + .map(|result| { result .into_iter() .flat_map(|res| res.references) @@ -228,12 +238,13 @@ fn should_skip_runnable(kind: &RunnableKind, binary_target: bool) -> bool { #[cfg(test)] mod tests { use expect_test::{Expect, expect}; + use ide_db::MiniCore; use crate::{Annotation, AnnotationConfig, fixture}; use super::AnnotationLocation; - const DEFAULT_CONFIG: AnnotationConfig = AnnotationConfig { + const DEFAULT_CONFIG: AnnotationConfig<'_> = AnnotationConfig { binary_target: true, annotate_runnables: true, annotate_impls: true, @@ -241,12 +252,13 @@ mod tests { annotate_method_references: true, annotate_enum_variant_references: true, location: AnnotationLocation::AboveName, + minicore: MiniCore::default(), }; fn check_with_config( #[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect, - config: &AnnotationConfig, + config: &AnnotationConfig<'_>, ) { let (analysis, file_id) = fixture::file(ra_fixture); @@ -254,7 +266,7 @@ mod tests { .annotations(config, file_id) .unwrap() .into_iter() - .map(|annotation| analysis.resolve_annotation(annotation).unwrap()) + .map(|annotation| analysis.resolve_annotation(&DEFAULT_CONFIG, annotation).unwrap()) .collect(); expect.assert_debug_eq(&annotations); diff --git a/src/tools/rust-analyzer/crates/ide/src/call_hierarchy.rs b/src/tools/rust-analyzer/crates/ide/src/call_hierarchy.rs index f42cead3501d..aded911a8db1 100644 --- a/src/tools/rust-analyzer/crates/ide/src/call_hierarchy.rs +++ b/src/tools/rust-analyzer/crates/ide/src/call_hierarchy.rs @@ -4,14 +4,16 @@ use std::iter; use hir::Semantics; use ide_db::{ - FileRange, FxIndexMap, RootDatabase, + FileRange, FxIndexMap, MiniCore, RootDatabase, defs::{Definition, NameClass, NameRefClass}, helpers::pick_best_token, search::FileReference, }; use syntax::{AstNode, SyntaxKind::IDENT, ast}; -use crate::{FilePosition, NavigationTarget, RangeInfo, TryToNav, goto_definition}; +use crate::{ + FilePosition, GotoDefinitionConfig, NavigationTarget, RangeInfo, TryToNav, goto_definition, +}; #[derive(Debug, Clone)] pub struct CallItem { @@ -19,22 +21,28 @@ pub struct CallItem { pub ranges: Vec, } -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub struct CallHierarchyConfig { +#[derive(Debug, Clone, Copy)] +pub struct CallHierarchyConfig<'a> { /// Whether to exclude tests from the call hierarchy pub exclude_tests: bool, + pub minicore: MiniCore<'a>, } pub(crate) fn call_hierarchy( db: &RootDatabase, position: FilePosition, + config: &CallHierarchyConfig<'_>, ) -> Option>> { - goto_definition::goto_definition(db, position) + goto_definition::goto_definition( + db, + position, + &GotoDefinitionConfig { minicore: config.minicore }, + ) } pub(crate) fn incoming_calls( db: &RootDatabase, - CallHierarchyConfig { exclude_tests }: CallHierarchyConfig, + config: &CallHierarchyConfig<'_>, FilePosition { file_id, offset }: FilePosition, ) -> Option> { let sema = &Semantics::new(db); @@ -71,7 +79,7 @@ pub(crate) fn incoming_calls( }); if let Some((def, nav)) = def_nav { - if exclude_tests && def.is_test(db) { + if config.exclude_tests && def.is_test(db) { continue; } @@ -89,7 +97,7 @@ pub(crate) fn incoming_calls( pub(crate) fn outgoing_calls( db: &RootDatabase, - CallHierarchyConfig { exclude_tests }: CallHierarchyConfig, + config: &CallHierarchyConfig<'_>, FilePosition { file_id, offset }: FilePosition, ) -> Option> { let sema = Semantics::new(db); @@ -119,7 +127,7 @@ pub(crate) fn outgoing_calls( let callable = sema.type_of_expr(&expr)?.original.as_callable(db)?; match callable.kind() { hir::CallableKind::Function(it) => { - if exclude_tests && it.is_test(db) { + if config.exclude_tests && it.is_test(db) { return None; } it.try_to_nav(&sema) @@ -132,7 +140,7 @@ pub(crate) fn outgoing_calls( } ast::CallableExpr::MethodCall(expr) => { let function = sema.resolve_method_call(&expr)?; - if exclude_tests && function.is_test(db) { + if config.exclude_tests && function.is_test(db) { return None; } function @@ -166,7 +174,7 @@ impl CallLocations { #[cfg(test)] mod tests { use expect_test::{Expect, expect}; - use ide_db::FilePosition; + use ide_db::{FilePosition, MiniCore}; use itertools::Itertools; use crate::fixture; @@ -189,21 +197,20 @@ mod tests { ) } + let config = crate::CallHierarchyConfig { exclude_tests, minicore: MiniCore::default() }; let (analysis, pos) = fixture::position(ra_fixture); - let mut navs = analysis.call_hierarchy(pos).unwrap().unwrap().info; + let mut navs = analysis.call_hierarchy(pos, &config).unwrap().unwrap().info; assert_eq!(navs.len(), 1); let nav = navs.pop().unwrap(); expected_nav.assert_eq(&nav.debug_render()); - let config = crate::CallHierarchyConfig { exclude_tests }; - let item_pos = FilePosition { file_id: nav.file_id, offset: nav.focus_or_full_range().start() }; - let incoming_calls = analysis.incoming_calls(config, item_pos).unwrap().unwrap(); + let incoming_calls = analysis.incoming_calls(&config, item_pos).unwrap().unwrap(); expected_incoming.assert_eq(&incoming_calls.into_iter().map(debug_render).join("\n")); - let outgoing_calls = analysis.outgoing_calls(config, item_pos).unwrap().unwrap(); + let outgoing_calls = analysis.outgoing_calls(&config, item_pos).unwrap().unwrap(); expected_outgoing.assert_eq(&outgoing_calls.into_iter().map(debug_render).join("\n")); } diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_declaration.rs b/src/tools/rust-analyzer/crates/ide/src/goto_declaration.rs index 686dbe241293..375ce94bf644 100644 --- a/src/tools/rust-analyzer/crates/ide/src/goto_declaration.rs +++ b/src/tools/rust-analyzer/crates/ide/src/goto_declaration.rs @@ -6,8 +6,8 @@ use ide_db::{ use syntax::{AstNode, SyntaxKind::*, T, ast, match_ast}; use crate::{ - FilePosition, NavigationTarget, RangeInfo, goto_definition::goto_definition, - navigation_target::TryToNav, + FilePosition, GotoDefinitionConfig, NavigationTarget, RangeInfo, + goto_definition::goto_definition, navigation_target::TryToNav, }; // Feature: Go to Declaration @@ -21,6 +21,7 @@ use crate::{ pub(crate) fn goto_declaration( db: &RootDatabase, position @ FilePosition { file_id, offset }: FilePosition, + config: &GotoDefinitionConfig<'_>, ) -> Option>> { let sema = Semantics::new(db); let file = sema.parse_guess_edition(file_id).syntax().clone(); @@ -69,20 +70,27 @@ pub(crate) fn goto_declaration( .flatten() .collect(); - if info.is_empty() { goto_definition(db, position) } else { Some(RangeInfo::new(range, info)) } + if info.is_empty() { + goto_definition(db, position, config) + } else { + Some(RangeInfo::new(range, info)) + } } #[cfg(test)] mod tests { - use ide_db::FileRange; + use ide_db::{FileRange, MiniCore}; use itertools::Itertools; - use crate::fixture; + use crate::{GotoDefinitionConfig, fixture}; + + const TEST_CONFIG: GotoDefinitionConfig<'_> = + GotoDefinitionConfig { minicore: MiniCore::default() }; fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str) { let (analysis, position, expected) = fixture::annotations(ra_fixture); let navs = analysis - .goto_declaration(position) + .goto_declaration(position, &TEST_CONFIG) .unwrap() .expect("no declaration or definition found") .info; diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs index 2dcb13d9e7aa..0ee9795af580 100644 --- a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs +++ b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs @@ -1,5 +1,6 @@ use std::{iter, mem::discriminant}; +use crate::Analysis; use crate::{ FilePosition, NavigationTarget, RangeInfo, TryToNav, UpmappingResult, doc_links::token_as_doc_comment, @@ -8,6 +9,7 @@ use crate::{ use hir::{ AsAssocItem, AssocItem, CallableKind, FileRange, HasCrate, InFile, ModuleDef, Semantics, sym, }; +use ide_db::{MiniCore, ra_fixture::UpmapFromRaFixture}; use ide_db::{ RootDatabase, SymbolKind, base_db::{AnchoredPath, SourceDatabase}, @@ -25,6 +27,11 @@ use syntax::{ match_ast, }; +#[derive(Debug)] +pub struct GotoDefinitionConfig<'a> { + pub minicore: MiniCore<'a>, +} + // Feature: Go to Definition // // Navigates to the definition of an identifier. @@ -39,6 +46,7 @@ use syntax::{ pub(crate) fn goto_definition( db: &RootDatabase, FilePosition { file_id, offset }: FilePosition, + config: &GotoDefinitionConfig<'_>, ) -> Option>> { let sema = &Semantics::new(db); let file = sema.parse_guess_edition(file_id).syntax().clone(); @@ -83,52 +91,64 @@ pub(crate) fn goto_definition( return Some(RangeInfo::new(original_token.text_range(), navs)); } - let navs = sema - .descend_into_macros_no_opaque(original_token.clone(), false) - .into_iter() - .filter_map(|token| { - if let Some(navs) = find_definition_for_known_blanket_dual_impls(sema, &token.value) { - return Some(navs); - } + let tokens = sema.descend_into_macros_no_opaque(original_token.clone(), false); + let mut navs = Vec::new(); + for token in tokens { + if let Some(n) = find_definition_for_known_blanket_dual_impls(sema, &token.value) { + navs.extend(n); + continue; + } - let parent = token.value.parent()?; + if let Some(token) = ast::String::cast(token.value.clone()) + && let Some(original_token) = ast::String::cast(original_token.clone()) + && let Some((analysis, fixture_analysis)) = + Analysis::from_ra_fixture(sema, original_token, &token, config.minicore) + && let Some((virtual_file_id, file_offset)) = fixture_analysis.map_offset_down(offset) + { + return hir::attach_db_allow_change(&analysis.db, || { + goto_definition( + &analysis.db, + FilePosition { file_id: virtual_file_id, offset: file_offset }, + config, + ) + }) + .and_then(|navs| { + navs.upmap_from_ra_fixture(&fixture_analysis, virtual_file_id, file_id).ok() + }); + } - let token_file_id = token.file_id; - if let Some(token) = ast::String::cast(token.value.clone()) - && let Some(x) = - try_lookup_include_path(sema, InFile::new(token_file_id, token), file_id) - { - return Some(vec![x]); - } + let parent = token.value.parent()?; - if ast::TokenTree::can_cast(parent.kind()) - && let Some(x) = try_lookup_macro_def_in_macro_use(sema, token.value) - { - return Some(vec![x]); - } + let token_file_id = token.file_id; + if let Some(token) = ast::String::cast(token.value.clone()) + && let Some(x) = + try_lookup_include_path(sema, InFile::new(token_file_id, token), file_id) + { + navs.push(x); + continue; + } - Some( - IdentClass::classify_node(sema, &parent)? - .definitions() + if ast::TokenTree::can_cast(parent.kind()) + && let Some(x) = try_lookup_macro_def_in_macro_use(sema, token.value) + { + navs.push(x); + continue; + } + + let Some(ident_class) = IdentClass::classify_node(sema, &parent) else { continue }; + navs.extend(ident_class.definitions().into_iter().flat_map(|(def, _)| { + if let Definition::ExternCrateDecl(crate_def) = def { + return crate_def + .resolved_crate(db) + .map(|it| it.root_module().to_nav(sema.db)) .into_iter() - .flat_map(|(def, _)| { - if let Definition::ExternCrateDecl(crate_def) = def { - return crate_def - .resolved_crate(db) - .map(|it| it.root_module().to_nav(sema.db)) - .into_iter() - .flatten() - .collect(); - } - try_filter_trait_item_definition(sema, &def) - .unwrap_or_else(|| def_to_nav(sema, def)) - }) - .collect(), - ) - }) - .flatten() - .unique() - .collect::>(); + .flatten() + .collect(); + } + try_filter_trait_item_definition(sema, &def).unwrap_or_else(|| def_to_nav(sema, def)) + })); + } + let navs = navs.into_iter().unique().collect(); Some(RangeInfo::new(original_token.text_range(), navs)) } @@ -584,15 +604,22 @@ fn expr_to_nav( #[cfg(test)] mod tests { - use crate::fixture; - use ide_db::FileRange; + use crate::{GotoDefinitionConfig, fixture}; + use ide_db::{FileRange, MiniCore}; use itertools::Itertools; use syntax::SmolStr; + const TEST_CONFIG: GotoDefinitionConfig<'_> = + GotoDefinitionConfig { minicore: MiniCore::default() }; + #[track_caller] fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str) { let (analysis, position, expected) = fixture::annotations(ra_fixture); - let navs = analysis.goto_definition(position).unwrap().expect("no definition found").info; + let navs = analysis + .goto_definition(position, &TEST_CONFIG) + .unwrap() + .expect("no definition found") + .info; let cmp = |&FileRange { file_id, range }: &_| (file_id, range.start()); let navs = navs @@ -611,14 +638,22 @@ mod tests { fn check_unresolved(#[rust_analyzer::rust_fixture] ra_fixture: &str) { let (analysis, position) = fixture::position(ra_fixture); - let navs = analysis.goto_definition(position).unwrap().expect("no definition found").info; + let navs = analysis + .goto_definition(position, &TEST_CONFIG) + .unwrap() + .expect("no definition found") + .info; assert!(navs.is_empty(), "didn't expect this to resolve anywhere: {navs:?}") } fn check_name(expected_name: &str, #[rust_analyzer::rust_fixture] ra_fixture: &str) { let (analysis, position, _) = fixture::annotations(ra_fixture); - let navs = analysis.goto_definition(position).unwrap().expect("no definition found").info; + let navs = analysis + .goto_definition(position, &TEST_CONFIG) + .unwrap() + .expect("no definition found") + .info; assert!(navs.len() < 2, "expected single navigation target but encountered {}", navs.len()); let Some(target) = navs.into_iter().next() else { panic!("expected single navigation target but encountered none"); @@ -3961,4 +3996,87 @@ mod prim_str {} "#, ); } + + #[test] + fn ra_fixture() { + check( + r##" +fn fixture(#[rust_analyzer::rust_fixture] ra_fixture: &str) {} + +fn foo() { + fixture(r#" +fn foo() {} +// ^^^ +fn bar() { + f$0oo(); +} + "#) +} + "##, + ); + } + + #[test] + fn regression_20038() { + check( + r#" +//- minicore: clone, fn +struct Map(Fut, F); + +struct InspectFn(F); + +trait FnOnce1 { + type Output; +} + +trait Future1 { + type Output; +} + +trait FusedFuture1: Future1 { + fn is_terminated(&self) -> bool; + //^^^^^^^^^^^^^ +} + +impl FnOnce1 for T +where + T: FnOnce(A) -> R, +{ + type Output = R; +} + +impl FnOnce1 for InspectFn +where + F: for<'a> FnOnce1<&'a A, Output = ()>, +{ + type Output = A; +} + +impl Future1 for Map +where + Fut: Future1, + F: FnOnce1, +{ + type Output = T; +} + +impl FusedFuture1 for Map +where + Fut: Future1, + F: FnOnce1, +{ + fn is_terminated(&self) -> bool { + false + } +} + +fn overflows(inner: &Map>) +where + Map>: FusedFuture1 +{ + let _x = inner.is_terminated$0(); +} +"#, + ) + } } diff --git a/src/tools/rust-analyzer/crates/ide/src/hover.rs b/src/tools/rust-analyzer/crates/ide/src/hover.rs index c4fb6d1a5b4b..e1d18b0c4116 100644 --- a/src/tools/rust-analyzer/crates/ide/src/hover.rs +++ b/src/tools/rust-analyzer/crates/ide/src/hover.rs @@ -11,29 +11,32 @@ use hir::{ db::DefDatabase, }; use ide_db::{ - FileRange, FxIndexSet, Ranker, RootDatabase, + FileRange, FxIndexSet, MiniCore, Ranker, RootDatabase, defs::{Definition, IdentClass, NameRefClass, OperatorClass}, famous_defs::FamousDefs, helpers::pick_best_token, + ra_fixture::UpmapFromRaFixture, }; use itertools::{Itertools, multizip}; -use span::Edition; +use macros::UpmapFromRaFixture; +use span::{Edition, TextRange}; use syntax::{ - AstNode, + AstNode, AstToken, SyntaxKind::{self, *}, SyntaxNode, T, ast, }; use crate::{ - FileId, FilePosition, NavigationTarget, RangeInfo, Runnable, TryToNav, + Analysis, FileId, FilePosition, NavigationTarget, RangeInfo, Runnable, TryToNav, doc_links::token_as_doc_comment, markdown_remove::remove_markdown, markup::Markup, navigation_target::UpmappingResult, runnables::{runnable_fn, runnable_mod}, }; -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct HoverConfig { + +#[derive(Clone, Debug)] +pub struct HoverConfig<'a> { pub links_in_hover: bool, pub memory_layout: Option, pub documentation: bool, @@ -44,6 +47,7 @@ pub struct HoverConfig { pub max_enum_variants_count: Option, pub max_subst_ty_len: SubstTyLen, pub show_drop_glue: bool, + pub minicore: MiniCore<'a>, } #[derive(Clone, Debug, PartialEq, Eq)] @@ -75,7 +79,7 @@ pub enum HoverDocFormat { PlainText, } -#[derive(Debug, Clone, Hash, PartialEq, Eq)] +#[derive(Debug, Clone, Hash, PartialEq, Eq, UpmapFromRaFixture)] pub enum HoverAction { Runnable(Runnable), Implementation(FilePosition), @@ -108,14 +112,14 @@ impl HoverAction { } } -#[derive(Debug, Clone, Eq, PartialEq, Hash)] +#[derive(Debug, Clone, Eq, PartialEq, Hash, UpmapFromRaFixture)] pub struct HoverGotoTypeData { pub mod_path: String, pub nav: NavigationTarget, } /// Contains the results when hovering over an item -#[derive(Clone, Debug, Default, Hash, PartialEq, Eq)] +#[derive(Clone, Debug, Default, Hash, PartialEq, Eq, UpmapFromRaFixture)] pub struct HoverResult { pub markup: Markup, pub actions: Vec, @@ -130,7 +134,7 @@ pub struct HoverResult { pub(crate) fn hover( db: &RootDatabase, frange @ FileRange { file_id, range }: FileRange, - config: &HoverConfig, + config: &HoverConfig<'_>, ) -> Option> { let sema = &hir::Semantics::new(db); let file = sema.parse_guess_edition(file_id).syntax().clone(); @@ -161,7 +165,7 @@ fn hover_offset( sema: &Semantics<'_, RootDatabase>, FilePosition { file_id, offset }: FilePosition, file: SyntaxNode, - config: &HoverConfig, + config: &HoverConfig<'_>, edition: Edition, display_target: DisplayTarget, ) -> Option> { @@ -219,6 +223,21 @@ fn hover_offset( return Some(RangeInfo::new(range, res)); } + if let Some(literal) = ast::String::cast(original_token.clone()) + && let Some((analysis, fixture_analysis)) = + Analysis::from_ra_fixture(sema, literal.clone(), &literal, config.minicore) + { + let (virtual_file_id, virtual_offset) = fixture_analysis.map_offset_down(offset)?; + return analysis + .hover( + config, + FileRange { file_id: virtual_file_id, range: TextRange::empty(virtual_offset) }, + ) + .ok()?? + .upmap_from_ra_fixture(&fixture_analysis, virtual_file_id, file_id) + .ok(); + } + // prefer descending the same token kind in attribute expansions, in normal macros text // equivalency is more important let mut descended = sema.descend_into_macros(original_token.clone()); @@ -383,9 +402,9 @@ fn hover_offset( fn hover_ranged( sema: &Semantics<'_, RootDatabase>, - FileRange { range, .. }: FileRange, + FileRange { file_id, range }: FileRange, file: SyntaxNode, - config: &HoverConfig, + config: &HoverConfig<'_>, edition: Edition, display_target: DisplayTarget, ) -> Option> { @@ -404,6 +423,20 @@ fn hover_ranged( { render::deref_expr(sema, config, prefix_expr, edition, display_target) } + Either::Left(ast::Expr::Literal(literal)) => { + if let Some(literal) = ast::String::cast(literal.token()) + && let Some((analysis, fixture_analysis)) = + Analysis::from_ra_fixture(sema, literal.clone(), &literal, config.minicore) + { + let (virtual_file_id, virtual_range) = fixture_analysis.map_range_down(range)?; + return analysis + .hover(config, FileRange { file_id: virtual_file_id, range: virtual_range }) + .ok()?? + .upmap_from_ra_fixture(&fixture_analysis, virtual_file_id, file_id) + .ok(); + } + None + } _ => None, }; let res = @@ -426,7 +459,7 @@ pub(crate) fn hover_for_definition( scope_node: &SyntaxNode, macro_arm: Option, render_extras: bool, - config: &HoverConfig, + config: &HoverConfig<'_>, edition: Edition, display_target: DisplayTarget, ) -> HoverResult { diff --git a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs index f29ccc985c18..a1eff3aaee78 100644 --- a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs +++ b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs @@ -35,7 +35,7 @@ use crate::{ pub(super) fn type_info_of( sema: &Semantics<'_, RootDatabase>, - _config: &HoverConfig, + _config: &HoverConfig<'_>, expr_or_pat: &Either, edition: Edition, display_target: DisplayTarget, @@ -49,7 +49,7 @@ pub(super) fn type_info_of( pub(super) fn closure_expr( sema: &Semantics<'_, RootDatabase>, - config: &HoverConfig, + config: &HoverConfig<'_>, c: ast::ClosureExpr, edition: Edition, display_target: DisplayTarget, @@ -60,7 +60,7 @@ pub(super) fn closure_expr( pub(super) fn try_expr( sema: &Semantics<'_, RootDatabase>, - _config: &HoverConfig, + _config: &HoverConfig<'_>, try_expr: &ast::TryExpr, edition: Edition, display_target: DisplayTarget, @@ -155,7 +155,7 @@ pub(super) fn try_expr( pub(super) fn deref_expr( sema: &Semantics<'_, RootDatabase>, - _config: &HoverConfig, + _config: &HoverConfig<'_>, deref_expr: &ast::PrefixExpr, edition: Edition, display_target: DisplayTarget, @@ -219,7 +219,7 @@ pub(super) fn deref_expr( pub(super) fn underscore( sema: &Semantics<'_, RootDatabase>, - config: &HoverConfig, + config: &HoverConfig<'_>, token: &SyntaxToken, edition: Edition, display_target: DisplayTarget, @@ -263,7 +263,7 @@ pub(super) fn underscore( pub(super) fn keyword( sema: &Semantics<'_, RootDatabase>, - config: &HoverConfig, + config: &HoverConfig<'_>, token: &SyntaxToken, edition: Edition, display_target: DisplayTarget, @@ -290,7 +290,7 @@ pub(super) fn keyword( /// i.e. `let S {a, ..} = S {a: 1, b: 2}` pub(super) fn struct_rest_pat( sema: &Semantics<'_, RootDatabase>, - _config: &HoverConfig, + _config: &HoverConfig<'_>, pattern: &ast::RecordPat, edition: Edition, display_target: DisplayTarget, @@ -371,7 +371,7 @@ pub(super) fn process_markup( def: Definition, markup: &Markup, markup_range_map: Option, - config: &HoverConfig, + config: &HoverConfig<'_>, ) -> Markup { let markup = markup.as_str(); let markup = if config.links_in_hover { @@ -481,7 +481,7 @@ pub(super) fn definition( macro_arm: Option, render_extras: bool, subst_types: Option<&Vec<(Symbol, Type<'_>)>>, - config: &HoverConfig, + config: &HoverConfig<'_>, edition: Edition, display_target: DisplayTarget, ) -> (Markup, Option) { @@ -979,7 +979,7 @@ fn render_notable_trait( fn type_info( sema: &Semantics<'_, RootDatabase>, - config: &HoverConfig, + config: &HoverConfig<'_>, ty: TypeInfo<'_>, edition: Edition, display_target: DisplayTarget, @@ -1038,7 +1038,7 @@ fn type_info( fn closure_ty( sema: &Semantics<'_, RootDatabase>, - config: &HoverConfig, + config: &HoverConfig<'_>, TypeInfo { original, adjusted }: &TypeInfo<'_>, edition: Edition, display_target: DisplayTarget, diff --git a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs index df1800616803..91fb4d0a6715 100644 --- a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs +++ b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs @@ -1,5 +1,5 @@ use expect_test::{Expect, expect}; -use ide_db::{FileRange, base_db::SourceDatabase}; +use ide_db::{FileRange, MiniCore, base_db::SourceDatabase}; use syntax::TextRange; use crate::{ @@ -8,7 +8,7 @@ use crate::{ use hir::setup_tracing; -const HOVER_BASE_CONFIG: HoverConfig = HoverConfig { +const HOVER_BASE_CONFIG: HoverConfig<'_> = HoverConfig { links_in_hover: false, memory_layout: Some(MemoryLayoutHoverConfig { size: Some(MemoryLayoutHoverRenderKind::Both), @@ -25,6 +25,7 @@ const HOVER_BASE_CONFIG: HoverConfig = HoverConfig { max_enum_variants_count: Some(5), max_subst_ty_len: super::SubstTyLen::Unlimited, show_drop_glue: true, + minicore: MiniCore::default(), }; fn check_hover_no_result(#[rust_analyzer::rust_fixture] ra_fixture: &str) { diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs index f7b09b43813d..21550d5e6665 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs @@ -8,9 +8,12 @@ use hir::{ ClosureStyle, DisplayTarget, EditionedFileId, HasVisibility, HirDisplay, HirDisplayError, HirWrite, InRealFile, ModuleDef, ModuleDefId, Semantics, sym, }; -use ide_db::{FileRange, RootDatabase, famous_defs::FamousDefs, text_edit::TextEditBuilder}; +use ide_db::{ + FileRange, MiniCore, RootDatabase, famous_defs::FamousDefs, text_edit::TextEditBuilder, +}; use ide_db::{FxHashSet, text_edit::TextEdit}; use itertools::Itertools; +use macros::UpmapFromRaFixture; use smallvec::{SmallVec, smallvec}; use stdx::never; use syntax::{ @@ -37,6 +40,7 @@ mod implicit_static; mod implied_dyn_trait; mod lifetime; mod param_name; +mod ra_fixture; mod range_exclusive; // Feature: Inlay Hints @@ -80,7 +84,7 @@ pub(crate) fn inlay_hints( db: &RootDatabase, file_id: FileId, range_limit: Option, - config: &InlayHintsConfig, + config: &InlayHintsConfig<'_>, ) -> Vec { let _p = tracing::info_span!("inlay_hints").entered(); let sema = Semantics::new(db); @@ -132,7 +136,7 @@ pub(crate) fn inlay_hints_resolve( file_id: FileId, resolve_range: TextRange, hash: u64, - config: &InlayHintsConfig, + config: &InlayHintsConfig<'_>, hasher: impl Fn(&InlayHint) -> u64, ) -> Option { let _p = tracing::info_span!("inlay_hints_resolve").entered(); @@ -208,7 +212,7 @@ fn hints( hints: &mut Vec, ctx: &mut InlayHintCtx, famous_defs @ FamousDefs(sema, _krate): &FamousDefs<'_, '_>, - config: &InlayHintsConfig, + config: &InlayHintsConfig<'_>, file_id: EditionedFileId, display_target: DisplayTarget, node: SyntaxNode, @@ -239,6 +243,7 @@ fn hints( closure_ret::hints(hints, famous_defs, config, display_target, it) }, ast::Expr::RangeExpr(it) => range_exclusive::hints(hints, famous_defs, config, it), + ast::Expr::Literal(it) => ra_fixture::hints(hints, famous_defs.0, file_id, config, it), _ => Some(()), } }, @@ -294,8 +299,8 @@ fn hints( }; } -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct InlayHintsConfig { +#[derive(Clone, Debug)] +pub struct InlayHintsConfig<'a> { pub render_colons: bool, pub type_hints: bool, pub sized_bound: bool, @@ -321,9 +326,10 @@ pub struct InlayHintsConfig { pub max_length: Option, pub closing_brace_hints_min_lines: Option, pub fields_to_resolve: InlayFieldsToResolve, + pub minicore: MiniCore<'a>, } -impl InlayHintsConfig { +impl InlayHintsConfig<'_> { fn lazy_text_edit(&self, finish: impl FnOnce() -> TextEdit) -> LazyProperty { if self.fields_to_resolve.resolve_text_edits { LazyProperty::Lazy @@ -466,7 +472,7 @@ pub enum InlayHintPosition { After, } -#[derive(Debug)] +#[derive(Debug, UpmapFromRaFixture)] pub struct InlayHint { /// The text range this inlay hint applies to. pub range: TextRange, @@ -485,9 +491,10 @@ pub struct InlayHint { } /// A type signaling that a value is either computed, or is available for computation. -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Default, UpmapFromRaFixture)] pub enum LazyProperty { Computed(T), + #[default] Lazy, } @@ -537,7 +544,7 @@ pub enum InlayTooltip { Markdown(String), } -#[derive(Default, Hash)] +#[derive(Default, Hash, UpmapFromRaFixture)] pub struct InlayHintLabel { pub parts: SmallVec<[InlayHintLabelPart; 1]>, } @@ -623,6 +630,7 @@ impl fmt::Debug for InlayHintLabel { } } +#[derive(UpmapFromRaFixture)] pub struct InlayHintLabelPart { pub text: String, /// Source location represented by this label part. The client will use this to fetch the part's @@ -724,7 +732,7 @@ impl InlayHintLabelBuilder<'_> { fn label_of_ty( famous_defs @ FamousDefs(sema, _): &FamousDefs<'_, '_>, - config: &InlayHintsConfig, + config: &InlayHintsConfig<'_>, ty: &hir::Type<'_>, display_target: DisplayTarget, ) -> Option { @@ -734,7 +742,7 @@ fn label_of_ty( mut max_length: Option, ty: &hir::Type<'_>, label_builder: &mut InlayHintLabelBuilder<'_>, - config: &InlayHintsConfig, + config: &InlayHintsConfig<'_>, display_target: DisplayTarget, ) -> Result<(), HirDisplayError> { hir::attach_db(sema.db, || { @@ -829,7 +837,7 @@ fn hint_iterator<'db>( fn ty_to_text_edit( sema: &Semantics<'_, RootDatabase>, - config: &InlayHintsConfig, + config: &InlayHintsConfig<'_>, node_for_hint: &SyntaxNode, ty: &hir::Type<'_>, offset_to_insert_ty: TextSize, @@ -860,6 +868,7 @@ mod tests { use expect_test::Expect; use hir::ClosureStyle; + use ide_db::MiniCore; use itertools::Itertools; use test_utils::extract_annotations; @@ -869,7 +878,7 @@ mod tests { use super::{ClosureReturnTypeHints, GenericParameterHints, InlayFieldsToResolve}; - pub(super) const DISABLED_CONFIG: InlayHintsConfig = InlayHintsConfig { + pub(super) const DISABLED_CONFIG: InlayHintsConfig<'_> = InlayHintsConfig { discriminant_hints: DiscriminantHints::Never, render_colons: false, type_hints: false, @@ -899,8 +908,9 @@ mod tests { fields_to_resolve: InlayFieldsToResolve::empty(), implicit_drop_hints: false, range_exclusive_hints: false, + minicore: MiniCore::default(), }; - pub(super) const TEST_CONFIG: InlayHintsConfig = InlayHintsConfig { + pub(super) const TEST_CONFIG: InlayHintsConfig<'_> = InlayHintsConfig { type_hints: true, parameter_hints: true, chaining_hints: true, @@ -917,7 +927,7 @@ mod tests { #[track_caller] pub(super) fn check_with_config( - config: InlayHintsConfig, + config: InlayHintsConfig<'_>, #[rust_analyzer::rust_fixture] ra_fixture: &str, ) { let (analysis, file_id) = fixture::file(ra_fixture); @@ -936,7 +946,7 @@ mod tests { #[track_caller] pub(super) fn check_expect( - config: InlayHintsConfig, + config: InlayHintsConfig<'_>, #[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect, ) { @@ -951,7 +961,7 @@ mod tests { /// expect test. #[track_caller] pub(super) fn check_edit( - config: InlayHintsConfig, + config: InlayHintsConfig<'_>, #[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect, ) { @@ -974,7 +984,7 @@ mod tests { #[track_caller] pub(super) fn check_no_edit( - config: InlayHintsConfig, + config: InlayHintsConfig<'_>, #[rust_analyzer::rust_fixture] ra_fixture: &str, ) { let (analysis, file_id) = fixture::file(ra_fixture); diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs index 7231a3194d09..ebb0d5752501 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs @@ -23,7 +23,7 @@ use crate::{ pub(super) fn hints( acc: &mut Vec, FamousDefs(sema, _): &FamousDefs<'_, '_>, - config: &InlayHintsConfig, + config: &InlayHintsConfig<'_>, display_target: DisplayTarget, expr: &ast::Expr, ) -> Option<()> { diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs index 121b16b97e87..de207c7821da 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs @@ -20,7 +20,7 @@ use crate::{ pub(super) fn hints( acc: &mut Vec, famous_defs @ FamousDefs(sema, _): &FamousDefs<'_, '_>, - config: &InlayHintsConfig, + config: &InlayHintsConfig<'_>, display_target: DisplayTarget, pat: &ast::IdentPat, ) -> Option<()> { diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/binding_mode.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/binding_mode.rs index 169ab92342ba..e8d305afb3b9 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/binding_mode.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/binding_mode.rs @@ -15,7 +15,7 @@ use crate::{InlayHint, InlayHintLabel, InlayHintPosition, InlayHintsConfig, Inla pub(super) fn hints( acc: &mut Vec, FamousDefs(sema, _): &FamousDefs<'_, '_>, - config: &InlayHintsConfig, + config: &InlayHintsConfig<'_>, pat: &ast::Pat, ) -> Option<()> { if !config.binding_mode_hints { diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bounds.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bounds.rs index 4abd67b91f5e..c9fbdf3ae754 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bounds.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bounds.rs @@ -13,7 +13,7 @@ use crate::{ pub(super) fn hints( acc: &mut Vec, famous_defs @ FamousDefs(sema, _): &FamousDefs<'_, '_>, - config: &InlayHintsConfig, + config: &InlayHintsConfig<'_>, params: ast::GenericParamList, ) -> Option<()> { if !config.sized_bound { diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs index a8bb652fda22..cf3149c9461b 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs @@ -13,7 +13,7 @@ use super::label_of_ty; pub(super) fn hints( acc: &mut Vec, famous_defs @ FamousDefs(sema, _): &FamousDefs<'_, '_>, - config: &InlayHintsConfig, + config: &InlayHintsConfig<'_>, display_target: DisplayTarget, expr: &ast::Expr, ) -> Option<()> { @@ -93,7 +93,7 @@ mod tests { #[track_caller] pub(super) fn check_expect_clear_loc( - config: InlayHintsConfig, + config: InlayHintsConfig<'_>, #[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect, ) { diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closing_brace.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closing_brace.rs index 9d246eda57e0..ab3ce5b05b01 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closing_brace.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closing_brace.rs @@ -19,7 +19,7 @@ use crate::{ pub(super) fn hints( acc: &mut Vec, sema: &Semantics<'_, RootDatabase>, - config: &InlayHintsConfig, + config: &InlayHintsConfig<'_>, display_target: DisplayTarget, InRealFile { file_id, value: node }: InRealFile, ) -> Option<()> { diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_captures.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_captures.rs index 3186a566d2bc..f8d4ddc6eb57 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_captures.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_captures.rs @@ -13,7 +13,7 @@ use crate::{ pub(super) fn hints( acc: &mut Vec, FamousDefs(sema, _): &FamousDefs<'_, '_>, - config: &InlayHintsConfig, + config: &InlayHintsConfig<'_>, closure: ast::ClosureExpr, ) -> Option<()> { if !config.closure_capture_hints { diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_ret.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_ret.rs index fef1cb83c119..7765dc4f087c 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_ret.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_ret.rs @@ -13,7 +13,7 @@ use crate::{ pub(super) fn hints( acc: &mut Vec, famous_defs @ FamousDefs(sema, _): &FamousDefs<'_, '_>, - config: &InlayHintsConfig, + config: &InlayHintsConfig<'_>, display_target: DisplayTarget, closure: ast::ClosureExpr, ) -> Option<()> { diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/discriminant.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/discriminant.rs index a2a702835a79..5b9267126f8a 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/discriminant.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/discriminant.rs @@ -17,7 +17,7 @@ use crate::{ pub(super) fn enum_hints( acc: &mut Vec, FamousDefs(sema, _): &FamousDefs<'_, '_>, - config: &InlayHintsConfig, + config: &InlayHintsConfig<'_>, enum_: ast::Enum, ) -> Option<()> { if let DiscriminantHints::Never = config.discriminant_hints { @@ -41,7 +41,7 @@ pub(super) fn enum_hints( fn variant_hints( acc: &mut Vec, - config: &InlayHintsConfig, + config: &InlayHintsConfig<'_>, sema: &Semantics<'_, RootDatabase>, enum_: &ast::Enum, variant: &ast::Variant, diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/extern_block.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/extern_block.rs index 491018a4dda8..8dd6c4db4c04 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/extern_block.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/extern_block.rs @@ -7,7 +7,7 @@ use crate::{InlayHint, InlayHintsConfig}; pub(super) fn extern_block_hints( acc: &mut Vec, FamousDefs(sema, _): &FamousDefs<'_, '_>, - config: &InlayHintsConfig, + config: &InlayHintsConfig<'_>, extern_block: ast::ExternBlock, ) -> Option<()> { if extern_block.unsafe_token().is_some() { @@ -33,7 +33,7 @@ pub(super) fn extern_block_hints( pub(super) fn fn_hints( acc: &mut Vec, FamousDefs(sema, _): &FamousDefs<'_, '_>, - config: &InlayHintsConfig, + config: &InlayHintsConfig<'_>, fn_: &ast::Fn, extern_block: &ast::ExternBlock, ) -> Option<()> { @@ -51,7 +51,7 @@ pub(super) fn fn_hints( pub(super) fn static_hints( acc: &mut Vec, FamousDefs(sema, _): &FamousDefs<'_, '_>, - config: &InlayHintsConfig, + config: &InlayHintsConfig<'_>, static_: &ast::Static, extern_block: &ast::ExternBlock, ) -> Option<()> { @@ -67,7 +67,7 @@ pub(super) fn static_hints( } fn item_hint( - config: &InlayHintsConfig, + config: &InlayHintsConfig<'_>, extern_block: &ast::ExternBlock, token: SyntaxToken, ) -> InlayHint { diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/generic_param.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/generic_param.rs index 1fddb6fbe01d..27d14f7a73cd 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/generic_param.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/generic_param.rs @@ -16,7 +16,7 @@ use super::param_name::is_argument_similar_to_param_name; pub(crate) fn hints( acc: &mut Vec, FamousDefs(sema, krate): &FamousDefs<'_, '_>, - config: &InlayHintsConfig, + config: &InlayHintsConfig<'_>, node: AnyHasGenericArgs, ) -> Option<()> { let GenericParameterHints { type_hints, lifetime_hints, const_hints } = diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_drop.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_drop.rs index 1e272fe3ba82..951a672d4b79 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_drop.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_drop.rs @@ -23,7 +23,7 @@ use crate::{InlayHint, InlayHintLabel, InlayHintPosition, InlayHintsConfig, Inla pub(super) fn hints( acc: &mut Vec, FamousDefs(sema, _): &FamousDefs<'_, '_>, - config: &InlayHintsConfig, + config: &InlayHintsConfig<'_>, display_target: hir::DisplayTarget, node: &ast::Fn, ) -> Option<()> { @@ -147,7 +147,7 @@ mod tests { inlay_hints::tests::{DISABLED_CONFIG, check_with_config}, }; - const ONLY_DROP_CONFIG: InlayHintsConfig = + const ONLY_DROP_CONFIG: InlayHintsConfig<'_> = InlayHintsConfig { implicit_drop_hints: true, ..DISABLED_CONFIG }; #[test] diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_static.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_static.rs index bddce904dfde..0492991790c8 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_static.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_static.rs @@ -15,7 +15,7 @@ use crate::{InlayHint, InlayHintPosition, InlayHintsConfig, InlayKind, LifetimeE pub(super) fn hints( acc: &mut Vec, FamousDefs(_sema, _): &FamousDefs<'_, '_>, - config: &InlayHintsConfig, + config: &InlayHintsConfig<'_>, statik_or_const: Either, ) -> Option<()> { if config.lifetime_elision_hints != LifetimeElisionHints::Always { diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implied_dyn_trait.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implied_dyn_trait.rs index 0da1785234ae..562eb1e00213 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implied_dyn_trait.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implied_dyn_trait.rs @@ -11,7 +11,7 @@ use crate::{InlayHint, InlayHintLabel, InlayHintPosition, InlayHintsConfig, Inla pub(super) fn hints( acc: &mut Vec, FamousDefs(sema, _): &FamousDefs<'_, '_>, - config: &InlayHintsConfig, + config: &InlayHintsConfig<'_>, path: Either, ) -> Option<()> { let parent = path.syntax().parent()?; diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/lifetime.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/lifetime.rs index a89c53e00b3b..4982b60f1dc8 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/lifetime.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/lifetime.rs @@ -21,7 +21,7 @@ pub(super) fn fn_hints( acc: &mut Vec, ctx: &mut InlayHintCtx, fd: &FamousDefs<'_, '_>, - config: &InlayHintsConfig, + config: &InlayHintsConfig<'_>, func: ast::Fn, ) -> Option<()> { if config.lifetime_elision_hints == LifetimeElisionHints::Never { @@ -70,7 +70,7 @@ pub(super) fn fn_ptr_hints( acc: &mut Vec, ctx: &mut InlayHintCtx, fd: &FamousDefs<'_, '_>, - config: &InlayHintsConfig, + config: &InlayHintsConfig<'_>, func: ast::FnPtrType, ) -> Option<()> { if config.lifetime_elision_hints == LifetimeElisionHints::Never { @@ -135,7 +135,7 @@ pub(super) fn fn_path_hints( acc: &mut Vec, ctx: &mut InlayHintCtx, fd: &FamousDefs<'_, '_>, - config: &InlayHintsConfig, + config: &InlayHintsConfig<'_>, func: &ast::PathType, ) -> Option<()> { if config.lifetime_elision_hints == LifetimeElisionHints::Never { @@ -196,7 +196,7 @@ fn hints_( acc: &mut Vec, ctx: &mut InlayHintCtx, FamousDefs(_, _): &FamousDefs<'_, '_>, - config: &InlayHintsConfig, + config: &InlayHintsConfig<'_>, params: impl Iterator, ast::Type)>, generic_param_list: Option, ret_type: Option, diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs index 754707784055..4122c16d3e38 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs @@ -18,7 +18,7 @@ use crate::{InlayHint, InlayHintLabel, InlayHintPosition, InlayHintsConfig, Inla pub(super) fn hints( acc: &mut Vec, FamousDefs(sema, krate): &FamousDefs<'_, '_>, - config: &InlayHintsConfig, + config: &InlayHintsConfig<'_>, file_id: EditionedFileId, expr: ast::Expr, ) -> Option<()> { @@ -124,12 +124,12 @@ fn should_hide_param_name_hint( // hide when: // - the parameter name is a suffix of the function's name // - the argument is a qualified constructing or call expression where the qualifier is an ADT - // - exact argument<->parameter match(ignoring leading underscore) or parameter is a prefix/suffix - // of argument with _ splitting it off + // - exact argument<->parameter match(ignoring leading and trailing underscore) or + // parameter is a prefix/suffix of argument with _ splitting it off // - param starts with `ra_fixture` // - param is a well known name in a unary function - let param_name = param_name.trim_start_matches('_'); + let param_name = param_name.trim_matches('_'); if param_name.is_empty() { return true; } @@ -540,6 +540,8 @@ fn enum_matches_param_name(completion_kind: CompletionKind) {} fn foo(param: u32) {} fn bar(param_eter: u32) {} fn baz(a_d_e: u32) {} +fn far(loop_: u32) {} +fn faz(r#loop: u32) {} enum CompletionKind { Keyword, @@ -590,6 +592,9 @@ fn main() { let param_eter2 = 0; bar(param_eter2); //^^^^^^^^^^^ param_eter + let loop_level = 0; + far(loop_level); + faz(loop_level); non_ident_pat((0, 0)); diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/ra_fixture.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/ra_fixture.rs new file mode 100644 index 000000000000..bee18416424c --- /dev/null +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/ra_fixture.rs @@ -0,0 +1,32 @@ +//! Injected inlay hints for `#[rust_analyzer::rust_fixture]`. + +use hir::{EditionedFileId, Semantics}; +use ide_db::{RootDatabase, impl_empty_upmap_from_ra_fixture, ra_fixture::UpmapFromRaFixture}; +use syntax::{AstToken, ast}; + +use crate::{Analysis, InlayHint, InlayHintPosition, InlayHintsConfig, InlayKind, InlayTooltip}; + +pub(super) fn hints( + acc: &mut Vec, + sema: &Semantics<'_, RootDatabase>, + file_id: EditionedFileId, + config: &InlayHintsConfig<'_>, + literal: ast::Literal, +) -> Option<()> { + let file_id = file_id.file_id(sema.db); + let literal = ast::String::cast(literal.token())?; + let (analysis, fixture_analysis) = + Analysis::from_ra_fixture(sema, literal.clone(), &literal, config.minicore)?; + for virtual_file_id in fixture_analysis.files() { + acc.extend( + analysis + .inlay_hints(config, virtual_file_id, None) + .ok()? + .upmap_from_ra_fixture(&fixture_analysis, virtual_file_id, file_id) + .ok()?, + ); + } + Some(()) +} + +impl_empty_upmap_from_ra_fixture!(InlayHintPosition, InlayKind, InlayTooltip); diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/range_exclusive.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/range_exclusive.rs index 47bd6d737f82..a446908e736b 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/range_exclusive.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/range_exclusive.rs @@ -11,7 +11,7 @@ use crate::{InlayHint, InlayHintsConfig}; pub(super) fn hints( acc: &mut Vec, FamousDefs(_sema, _): &FamousDefs<'_, '_>, - config: &InlayHintsConfig, + config: &InlayHintsConfig<'_>, range: impl ast::RangeItem, ) -> Option<()> { (config.range_exclusive_hints && range.end().is_some()) diff --git a/src/tools/rust-analyzer/crates/ide/src/lib.rs b/src/tools/rust-analyzer/crates/ide/src/lib.rs index f7d21c947950..857252832ffe 100644 --- a/src/tools/rust-analyzer/crates/ide/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide/src/lib.rs @@ -62,7 +62,7 @@ use std::panic::{AssertUnwindSafe, UnwindSafe}; use cfg::CfgOptions; use fetch_crates::CrateInfo; -use hir::{ChangeWithProcMacros, EditionedFileId, crate_def_map, db::HirDatabase, sym}; +use hir::{ChangeWithProcMacros, EditionedFileId, crate_def_map, sym}; use ide_db::{ FxHashMap, FxIndexSet, LineIndexDatabase, base_db::{ @@ -71,7 +71,9 @@ use ide_db::{ }, prime_caches, symbol_index, }; -use syntax::SourceFile; +use ide_db::{MiniCore, ra_fixture::RaFixtureAnalysis}; +use macros::UpmapFromRaFixture; +use syntax::{SourceFile, ast}; use triomphe::Arc; use view_memory_layout::{RecursiveMemoryLayout, view_memory_layout}; @@ -83,6 +85,7 @@ pub use crate::{ expand_macro::ExpandedMacro, file_structure::{FileStructureConfig, StructureNode, StructureNodeKind}, folding_ranges::{Fold, FoldKind}, + goto_definition::GotoDefinitionConfig, highlight_related::{HighlightRelatedConfig, HighlightedRange}, hover::{ HoverAction, HoverConfig, HoverDocFormat, HoverGotoTypeData, HoverResult, @@ -102,7 +105,7 @@ pub use crate::{ }, move_item::Direction, navigation_target::{NavigationTarget, TryToNav, UpmappingResult}, - references::ReferenceSearchResult, + references::{FindAllRefsConfig, ReferenceSearchResult}, rename::RenameError, runnables::{Runnable, RunnableKind, TestId, UpdateTest}, signature_help::SignatureHelp, @@ -144,7 +147,7 @@ pub use syntax::{TextRange, TextSize}; pub type Cancellable = Result; /// Info associated with a text range. -#[derive(Debug)] +#[derive(Debug, UpmapFromRaFixture)] pub struct RangeInfo { pub range: TextRange, pub info: T, @@ -274,6 +277,28 @@ impl Analysis { (host.analysis(), file_id) } + pub(crate) fn from_ra_fixture( + sema: &Semantics<'_, RootDatabase>, + literal: ast::String, + expanded: &ast::String, + minicore: MiniCore<'_>, + ) -> Option<(Analysis, RaFixtureAnalysis)> { + Self::from_ra_fixture_with_on_cursor(sema, literal, expanded, minicore, &mut |_| {}) + } + + /// Like [`Analysis::from_ra_fixture()`], but also calls `on_cursor` with the cursor position. + pub(crate) fn from_ra_fixture_with_on_cursor( + sema: &Semantics<'_, RootDatabase>, + literal: ast::String, + expanded: &ast::String, + minicore: MiniCore<'_>, + on_cursor: &mut dyn FnMut(TextRange), + ) -> Option<(Analysis, RaFixtureAnalysis)> { + let analysis = + RaFixtureAnalysis::analyze_ra_fixture(sema, literal, expanded, minicore, on_cursor)?; + Some((Analysis { db: analysis.db.clone() }, analysis)) + } + /// Debug info about the current state of the analysis. pub fn status(&self, file_id: Option) -> Cancellable { self.with_db(|db| status::status(db, file_id)) @@ -446,7 +471,7 @@ impl Analysis { /// Returns a list of the places in the file where type hints can be displayed. pub fn inlay_hints( &self, - config: &InlayHintsConfig, + config: &InlayHintsConfig<'_>, file_id: FileId, range: Option, ) -> Cancellable> { @@ -454,7 +479,7 @@ impl Analysis { } pub fn inlay_hints_resolve( &self, - config: &InlayHintsConfig, + config: &InlayHintsConfig<'_>, file_id: FileId, resolve_range: TextRange, hash: u64, @@ -495,16 +520,18 @@ impl Analysis { pub fn goto_definition( &self, position: FilePosition, + config: &GotoDefinitionConfig<'_>, ) -> Cancellable>>> { - self.with_db(|db| goto_definition::goto_definition(db, position)) + self.with_db(|db| goto_definition::goto_definition(db, position, config)) } /// Returns the declaration from the symbol at `position`. pub fn goto_declaration( &self, position: FilePosition, + config: &GotoDefinitionConfig<'_>, ) -> Cancellable>>> { - self.with_db(|db| goto_declaration::goto_declaration(db, position)) + self.with_db(|db| goto_declaration::goto_declaration(db, position, config)) } /// Returns the impls from the symbol at `position`. @@ -526,19 +553,16 @@ impl Analysis { pub fn find_all_refs( &self, position: FilePosition, - search_scope: Option, + config: &FindAllRefsConfig<'_>, ) -> Cancellable>> { - let search_scope = AssertUnwindSafe(search_scope); - self.with_db(|db| { - let _ = &search_scope; - references::find_all_refs(&Semantics::new(db), position, search_scope.0) - }) + let config = AssertUnwindSafe(config); + self.with_db(|db| references::find_all_refs(&Semantics::new(db), position, &config)) } /// Returns a short text describing element at position. pub fn hover( &self, - config: &HoverConfig, + config: &HoverConfig<'_>, range: FileRange, ) -> Cancellable>> { self.with_db(|db| hover::hover(db, range, config)) @@ -576,14 +600,15 @@ impl Analysis { pub fn call_hierarchy( &self, position: FilePosition, + config: &CallHierarchyConfig<'_>, ) -> Cancellable>>> { - self.with_db(|db| call_hierarchy::call_hierarchy(db, position)) + self.with_db(|db| call_hierarchy::call_hierarchy(db, position, config)) } /// Computes incoming calls for the given file position. pub fn incoming_calls( &self, - config: CallHierarchyConfig, + config: &CallHierarchyConfig<'_>, position: FilePosition, ) -> Cancellable>> { self.with_db(|db| call_hierarchy::incoming_calls(db, config, position)) @@ -592,7 +617,7 @@ impl Analysis { /// Computes outgoing calls for the given file position. pub fn outgoing_calls( &self, - config: CallHierarchyConfig, + config: &CallHierarchyConfig<'_>, position: FilePosition, ) -> Cancellable>> { self.with_db(|db| call_hierarchy::outgoing_calls(db, config, position)) @@ -675,28 +700,22 @@ impl Analysis { /// Computes syntax highlighting for the given file pub fn highlight( &self, - highlight_config: HighlightConfig, + highlight_config: HighlightConfig<'_>, file_id: FileId, ) -> Cancellable> { - // highlighting may construct a new database for "speculative" execution, so we can't currently attach the database - // highlighting instead sets up the attach hook where neceesary for the trait solver - Cancelled::catch(|| { - syntax_highlighting::highlight(&self.db, highlight_config, file_id, None) - }) + self.with_db(|db| syntax_highlighting::highlight(db, &highlight_config, file_id, None)) } /// Computes syntax highlighting for the given file range. pub fn highlight_range( &self, - highlight_config: HighlightConfig, + highlight_config: HighlightConfig<'_>, frange: FileRange, ) -> Cancellable> { - // highlighting may construct a new database for "speculative" execution, so we can't currently attach the database - // highlighting instead sets up the attach hook where neceesary for the trait solver - Cancelled::catch(|| { + self.with_db(|db| { syntax_highlighting::highlight( - &self.db, - highlight_config, + db, + &highlight_config, frange.file_id, Some(frange.range), ) @@ -706,22 +725,18 @@ impl Analysis { /// Computes syntax highlighting for the given file. pub fn highlight_as_html_with_config( &self, - config: HighlightConfig, + config: HighlightConfig<'_>, file_id: FileId, rainbow: bool, ) -> Cancellable { - // highlighting may construct a new database for "speculative" execution, so we can't currently attach the database - // highlighting instead sets up the attach hook where neceesary for the trait solver - Cancelled::catch(|| { - syntax_highlighting::highlight_as_html_with_config(&self.db, config, file_id, rainbow) + self.with_db(|db| { + syntax_highlighting::highlight_as_html_with_config(db, &config, file_id, rainbow) }) } /// Computes syntax highlighting for the given file. pub fn highlight_as_html(&self, file_id: FileId, rainbow: bool) -> Cancellable { - // highlighting may construct a new database for "speculative" execution, so we can't currently attach the database - // highlighting instead sets up the attach hook where neceesary for the trait solver - Cancelled::catch(|| syntax_highlighting::highlight_as_html(&self.db, file_id, rainbow)) + self.with_db(|db| syntax_highlighting::highlight_as_html(db, file_id, rainbow)) } /// Computes completions at the given position. @@ -853,14 +868,18 @@ impl Analysis { pub fn annotations( &self, - config: &AnnotationConfig, + config: &AnnotationConfig<'_>, file_id: FileId, ) -> Cancellable> { self.with_db(|db| annotations::annotations(db, config, file_id)) } - pub fn resolve_annotation(&self, annotation: Annotation) -> Cancellable { - self.with_db(|db| annotations::resolve_annotation(db, annotation)) + pub fn resolve_annotation( + &self, + config: &AnnotationConfig<'_>, + annotation: Annotation, + ) -> Cancellable { + self.with_db(|db| annotations::resolve_annotation(db, config, annotation)) } pub fn move_item( @@ -899,12 +918,8 @@ impl Analysis { where F: FnOnce(&RootDatabase) -> T + std::panic::UnwindSafe, { - hir::attach_db(&self.db, || { - // the trait solver code may invoke `as_view` outside of queries, - // so technically we might run into a panic in salsa if the downcaster has not yet been registered. - HirDatabase::zalsa_register_downcaster(&self.db); - Cancelled::catch(|| f(&self.db)) - }) + // We use `attach_db_allow_change()` and not `attach_db()` because fixture injection can change the database. + hir::attach_db_allow_change(&self.db, || Cancelled::catch(|| f(&self.db))) } } diff --git a/src/tools/rust-analyzer/crates/ide/src/markup.rs b/src/tools/rust-analyzer/crates/ide/src/markup.rs index 750d12542605..3eb9986c120f 100644 --- a/src/tools/rust-analyzer/crates/ide/src/markup.rs +++ b/src/tools/rust-analyzer/crates/ide/src/markup.rs @@ -5,6 +5,8 @@ //! what is used by LSP, so let's keep it simple. use std::fmt; +use ide_db::impl_empty_upmap_from_ra_fixture; + #[derive(Clone, Default, Debug, Hash, PartialEq, Eq)] pub struct Markup { text: String, @@ -39,3 +41,5 @@ impl Markup { format!("```text\n{contents}\n```").into() } } + +impl_empty_upmap_from_ra_fixture!(Markup); diff --git a/src/tools/rust-analyzer/crates/ide/src/moniker.rs b/src/tools/rust-analyzer/crates/ide/src/moniker.rs index f1aa03c8f267..4aa9eb98a1e1 100644 --- a/src/tools/rust-analyzer/crates/ide/src/moniker.rs +++ b/src/tools/rust-analyzer/crates/ide/src/moniker.rs @@ -384,7 +384,7 @@ fn def_to_non_local_moniker( }) } -fn display(db: &RootDatabase, module: hir::Module, it: T) -> String { +fn display<'db, T: HirDisplay<'db>>(db: &'db RootDatabase, module: hir::Module, it: T) -> String { match it.display_source_code(db, module.into(), true) { Ok(result) => result, // Fallback on display variant that always succeeds diff --git a/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs b/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs index db1298385b11..b222ff3eec0b 100644 --- a/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs +++ b/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs @@ -14,6 +14,7 @@ use ide_db::{ defs::{Definition, find_std_module}, documentation::{Documentation, HasDocs}, famous_defs::FamousDefs, + ra_fixture::UpmapFromRaFixture, }; use span::Edition; use stdx::never; @@ -78,6 +79,44 @@ impl fmt::Debug for NavigationTarget { } } +impl UpmapFromRaFixture for NavigationTarget { + fn upmap_from_ra_fixture( + self, + analysis: &ide_db::ra_fixture::RaFixtureAnalysis, + _virtual_file_id: FileId, + real_file_id: FileId, + ) -> Result { + let virtual_file_id = self.file_id; + Ok(NavigationTarget { + file_id: real_file_id, + full_range: self.full_range.upmap_from_ra_fixture( + analysis, + virtual_file_id, + real_file_id, + )?, + focus_range: self.focus_range.upmap_from_ra_fixture( + analysis, + virtual_file_id, + real_file_id, + )?, + name: self.name.upmap_from_ra_fixture(analysis, virtual_file_id, real_file_id)?, + kind: self.kind.upmap_from_ra_fixture(analysis, virtual_file_id, real_file_id)?, + container_name: self.container_name.upmap_from_ra_fixture( + analysis, + virtual_file_id, + real_file_id, + )?, + description: self.description.upmap_from_ra_fixture( + analysis, + virtual_file_id, + real_file_id, + )?, + docs: self.docs.upmap_from_ra_fixture(analysis, virtual_file_id, real_file_id)?, + alias: self.alias.upmap_from_ra_fixture(analysis, virtual_file_id, real_file_id)?, + }) + } +} + pub(crate) trait ToNav { fn to_nav(&self, db: &RootDatabase) -> UpmappingResult; } @@ -382,7 +421,7 @@ impl ToNavFromAst for hir::Trait { impl TryToNav for D where - D: HasSource + ToNavFromAst + Copy + HasDocs + HirDisplay + HasCrate, + D: HasSource + ToNavFromAst + Copy + HasDocs + for<'db> HirDisplay<'db> + HasCrate, D::Ast: ast::HasName, { fn try_to_nav( diff --git a/src/tools/rust-analyzer/crates/ide/src/references.rs b/src/tools/rust-analyzer/crates/ide/src/references.rs index 0189939eac31..a53a19299727 100644 --- a/src/tools/rust-analyzer/crates/ide/src/references.rs +++ b/src/tools/rust-analyzer/crates/ide/src/references.rs @@ -19,14 +19,17 @@ use hir::{PathResolution, Semantics}; use ide_db::{ - FileId, RootDatabase, + FileId, MiniCore, RootDatabase, defs::{Definition, NameClass, NameRefClass}, helpers::pick_best_token, + ra_fixture::UpmapFromRaFixture, search::{ReferenceCategory, SearchScope, UsageSearchResult}, }; use itertools::Itertools; +use macros::UpmapFromRaFixture; use nohash_hasher::IntMap; use span::Edition; +use syntax::AstToken; use syntax::{ AstNode, SyntaxKind::*, @@ -35,10 +38,12 @@ use syntax::{ match_ast, }; -use crate::{FilePosition, HighlightedRange, NavigationTarget, TryToNav, highlight_related}; +use crate::{ + Analysis, FilePosition, HighlightedRange, NavigationTarget, TryToNav, highlight_related, +}; /// Result of a reference search operation. -#[derive(Debug, Clone)] +#[derive(Debug, Clone, UpmapFromRaFixture)] pub struct ReferenceSearchResult { /// Information about the declaration site of the searched item. /// For ADTs (structs/enums), this points to the type definition. @@ -54,7 +59,7 @@ pub struct ReferenceSearchResult { } /// Information about the declaration site of a searched item. -#[derive(Debug, Clone)] +#[derive(Debug, Clone, UpmapFromRaFixture)] pub struct Declaration { /// Navigation information to jump to the declaration pub nav: NavigationTarget, @@ -82,6 +87,12 @@ pub struct Declaration { // // ![Find All References](https://user-images.githubusercontent.com/48062697/113020670-b7c34f00-917a-11eb-8003-370ac5f2b3cb.gif) +#[derive(Debug)] +pub struct FindAllRefsConfig<'a> { + pub search_scope: Option, + pub minicore: MiniCore<'a>, +} + /// Find all references to the item at the given position. /// /// # Arguments @@ -110,14 +121,14 @@ pub struct Declaration { pub(crate) fn find_all_refs( sema: &Semantics<'_, RootDatabase>, position: FilePosition, - search_scope: Option, + config: &FindAllRefsConfig<'_>, ) -> Option> { let _p = tracing::info_span!("find_all_refs").entered(); let syntax = sema.parse_guess_edition(position.file_id).syntax().clone(); let make_searcher = |literal_search: bool| { move |def: Definition| { let mut usages = - def.usages(sema).set_scope(search_scope.as_ref()).include_self_refs().all(); + def.usages(sema).set_scope(config.search_scope.as_ref()).include_self_refs().all(); if literal_search { retain_adt_literal_usages(&mut usages, def, sema); } @@ -165,6 +176,20 @@ pub(crate) fn find_all_refs( return Some(vec![res]); } + if let Some(token) = syntax.token_at_offset(position.offset).left_biased() + && let Some(token) = ast::String::cast(token.clone()) + && let Some((analysis, fixture_analysis)) = + Analysis::from_ra_fixture(sema, token.clone(), &token, config.minicore) + && let Some((virtual_file_id, file_offset)) = + fixture_analysis.map_offset_down(position.offset) + { + return analysis + .find_all_refs(FilePosition { file_id: virtual_file_id, offset: file_offset }, config) + .ok()?? + .upmap_from_ra_fixture(&fixture_analysis, virtual_file_id, position.file_id) + .ok(); + } + match name_for_constructor_search(&syntax, position) { Some(name) => { let def = match NameClass::classify(sema, &name)? { @@ -433,10 +458,10 @@ fn handle_control_flow_keywords( mod tests { use expect_test::{Expect, expect}; use hir::EditionedFileId; - use ide_db::{FileId, RootDatabase}; + use ide_db::{FileId, MiniCore, RootDatabase}; use stdx::format_to; - use crate::{SearchScope, fixture}; + use crate::{SearchScope, fixture, references::FindAllRefsConfig}; #[test] fn exclude_tests() { @@ -1513,8 +1538,11 @@ fn main() { expect: Expect, ) { let (analysis, pos) = fixture::position(ra_fixture); - let refs = - analysis.find_all_refs(pos, search_scope.map(|it| it(&analysis.db))).unwrap().unwrap(); + let config = FindAllRefsConfig { + search_scope: search_scope.map(|it| it(&analysis.db)), + minicore: MiniCore::default(), + }; + let refs = analysis.find_all_refs(pos, &config).unwrap().unwrap(); let mut actual = String::new(); for mut refs in refs { diff --git a/src/tools/rust-analyzer/crates/ide/src/runnables.rs b/src/tools/rust-analyzer/crates/ide/src/runnables.rs index cc1bbfbe20d6..494701d97def 100644 --- a/src/tools/rust-analyzer/crates/ide/src/runnables.rs +++ b/src/tools/rust-analyzer/crates/ide/src/runnables.rs @@ -8,6 +8,7 @@ use hir::{ sym, }; use ide_assists::utils::{has_test_related_attribute, test_related_attribute_syn}; +use ide_db::impl_empty_upmap_from_ra_fixture; use ide_db::{ FilePosition, FxHashMap, FxIndexMap, FxIndexSet, RootDatabase, SymbolKind, base_db::RootQueryDb, @@ -17,6 +18,7 @@ use ide_db::{ search::{FileReferenceNode, SearchScope}, }; use itertools::Itertools; +use macros::UpmapFromRaFixture; use smallvec::SmallVec; use span::{Edition, TextSize}; use stdx::format_to; @@ -28,7 +30,7 @@ use syntax::{ use crate::{FileId, NavigationTarget, ToNav, TryToNav, references}; -#[derive(Debug, Clone, Hash, PartialEq, Eq)] +#[derive(Debug, Clone, Hash, PartialEq, Eq, UpmapFromRaFixture)] pub struct Runnable { pub use_name_in_title: bool, pub nav: NavigationTarget, @@ -37,6 +39,8 @@ pub struct Runnable { pub update_test: UpdateTest, } +impl_empty_upmap_from_ra_fixture!(RunnableKind, UpdateTest); + #[derive(Debug, Clone, Hash, PartialEq, Eq)] pub enum TestId { Name(SmolStr), diff --git a/src/tools/rust-analyzer/crates/ide/src/static_index.rs b/src/tools/rust-analyzer/crates/ide/src/static_index.rs index 453d6f537a8b..e261928c413f 100644 --- a/src/tools/rust-analyzer/crates/ide/src/static_index.rs +++ b/src/tools/rust-analyzer/crates/ide/src/static_index.rs @@ -4,7 +4,7 @@ use arrayvec::ArrayVec; use hir::{Crate, Module, Semantics, db::HirDatabase}; use ide_db::{ - FileId, FileRange, FxHashMap, FxHashSet, RootDatabase, + FileId, FileRange, FxHashMap, FxHashSet, MiniCore, RootDatabase, base_db::{RootQueryDb, SourceDatabase, VfsPath}, defs::{Definition, IdentClass}, documentation::Documentation, @@ -184,6 +184,7 @@ impl StaticIndex<'_> { closing_brace_hints_min_lines: Some(25), fields_to_resolve: InlayFieldsToResolve::empty(), range_exclusive_hints: false, + minicore: MiniCore::default(), }, file_id, None, @@ -215,6 +216,7 @@ impl StaticIndex<'_> { max_enum_variants_count: Some(5), max_subst_ty_len: SubstTyLen::Unlimited, show_drop_glue: true, + minicore: MiniCore::default(), }; let tokens = tokens.filter(|token| { matches!( diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs index 0da9ee097ac3..66895cb0b053 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs @@ -1,7 +1,6 @@ pub(crate) mod tags; mod highlights; -mod injector; mod escape; mod format; @@ -16,7 +15,7 @@ use std::ops::ControlFlow; use either::Either; use hir::{DefWithBody, EditionedFileId, InFile, InRealFile, MacroKind, Name, Semantics}; -use ide_db::{FxHashMap, FxHashSet, Ranker, RootDatabase, SymbolKind}; +use ide_db::{FxHashMap, FxHashSet, MiniCore, Ranker, RootDatabase, SymbolKind}; use syntax::{ AstNode, AstToken, NodeOrToken, SyntaxKind::*, @@ -44,8 +43,8 @@ pub struct HlRange { pub binding_hash: Option, } -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub struct HighlightConfig { +#[derive(Copy, Clone, Debug)] +pub struct HighlightConfig<'a> { /// Whether to highlight strings pub strings: bool, /// Whether to highlight comments @@ -64,6 +63,7 @@ pub struct HighlightConfig { pub macro_bang: bool, /// Whether to highlight unresolved things be their syntax pub syntactic_name_ref_highlighting: bool, + pub minicore: MiniCore<'a>, } // Feature: Semantic Syntax Highlighting @@ -191,7 +191,7 @@ pub struct HighlightConfig { // ![Semantic Syntax Highlighting](https://user-images.githubusercontent.com/48062697/113187625-f7f50100-9250-11eb-825e-91c58f236071.png) pub(crate) fn highlight( db: &RootDatabase, - config: HighlightConfig, + config: &HighlightConfig<'_>, file_id: FileId, range_to_highlight: Option, ) -> Vec { @@ -226,7 +226,7 @@ pub(crate) fn highlight( fn traverse( hl: &mut Highlights, sema: &Semantics<'_, RootDatabase>, - config: HighlightConfig, + config: &HighlightConfig<'_>, InRealFile { file_id, value: root }: InRealFile<&SyntaxNode>, krate: Option, range_to_highlight: TextRange, @@ -426,12 +426,9 @@ fn traverse( let edition = descended_element.file_id.edition(sema.db); let (unsafe_ops, bindings_shadow_count) = match current_body { Some(current_body) => { - let (ops, bindings) = per_body_cache.entry(current_body).or_insert_with(|| { - ( - hir::attach_db(sema.db, || sema.get_unsafe_ops(current_body)), - Default::default(), - ) - }); + let (ops, bindings) = per_body_cache + .entry(current_body) + .or_insert_with(|| (sema.get_unsafe_ops(current_body), Default::default())); (&*ops, Some(bindings)) } None => (&empty, None), @@ -494,7 +491,7 @@ fn traverse( fn string_injections( hl: &mut Highlights, sema: &Semantics<'_, RootDatabase>, - config: HighlightConfig, + config: &HighlightConfig<'_>, file_id: EditionedFileId, krate: Option, token: SyntaxToken, @@ -591,7 +588,7 @@ fn descend_token( }) } -fn filter_by_config(highlight: &mut Highlight, config: HighlightConfig) -> bool { +fn filter_by_config(highlight: &mut Highlight, config: &HighlightConfig<'_>) -> bool { match &mut highlight.tag { HlTag::StringLiteral if !config.strings => return false, HlTag::Comment if !config.comments => return false, diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs index d73575fb9549..829d1279a839 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs @@ -137,7 +137,7 @@ fn punctuation( } (T![!], MACRO_RULES) => HlPunct::MacroBang.into(), (T![!], NEVER_TYPE) => HlTag::BuiltinType.into(), - (T![!], PREFIX_EXPR) => HlOperator::Logical.into(), + (T![!], PREFIX_EXPR) => HlOperator::Negation.into(), (T![*], PTR_TYPE) => HlTag::Keyword.into(), (T![*], PREFIX_EXPR) => { let h = HlTag::Operator(HlOperator::Other).into(); diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/html.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/html.rs index 358ac9b4ef35..75e46b8ebfde 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/html.rs +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/html.rs @@ -1,6 +1,7 @@ //! Renders a bit of code as HTML. use hir::{EditionedFileId, Semantics}; +use ide_db::MiniCore; use oorandom::Rand32; use stdx::format_to; use syntax::AstNode; @@ -12,7 +13,7 @@ use crate::{ pub(crate) fn highlight_as_html_with_config( db: &RootDatabase, - config: HighlightConfig, + config: &HighlightConfig<'_>, file_id: FileId, rainbow: bool, ) -> String { @@ -60,7 +61,7 @@ pub(crate) fn highlight_as_html_with_config( pub(crate) fn highlight_as_html(db: &RootDatabase, file_id: FileId, rainbow: bool) -> String { highlight_as_html_with_config( db, - HighlightConfig { + &HighlightConfig { strings: true, comments: true, punctuation: true, @@ -70,6 +71,7 @@ pub(crate) fn highlight_as_html(db: &RootDatabase, file_id: FileId, rainbow: boo inject_doc_comment: true, macro_bang: true, syntactic_name_ref_highlighting: false, + minicore: MiniCore::default(), }, file_id, rainbow, diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs index efc77823a2a4..7955f5ac0de9 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs @@ -4,9 +4,9 @@ use std::mem; use either::Either; use hir::{EditionedFileId, HirFileId, InFile, Semantics, sym}; +use ide_db::range_mapper::RangeMapper; use ide_db::{ - SymbolKind, active_parameter::ActiveParameter, defs::Definition, - documentation::docs_with_rangemap, rust_doc::is_rust_fence, + SymbolKind, defs::Definition, documentation::docs_with_rangemap, rust_doc::is_rust_fence, }; use syntax::{ AstToken, NodeOrToken, SyntaxNode, TextRange, TextSize, @@ -16,85 +16,56 @@ use syntax::{ use crate::{ Analysis, HlMod, HlRange, HlTag, RootDatabase, doc_links::{doc_attributes, extract_definitions_from_docs, resolve_doc_path_for_def}, - syntax_highlighting::{HighlightConfig, highlights::Highlights, injector::Injector}, + syntax_highlighting::{HighlightConfig, highlights::Highlights}, }; pub(super) fn ra_fixture( hl: &mut Highlights, sema: &Semantics<'_, RootDatabase>, - config: HighlightConfig, + config: &HighlightConfig<'_>, literal: &ast::String, expanded: &ast::String, ) -> Option<()> { - let active_parameter = - hir::attach_db(sema.db, || ActiveParameter::at_token(sema, expanded.syntax().clone()))?; - let has_rust_fixture_attr = active_parameter.attrs().is_some_and(|attrs| { - attrs.filter_map(|attr| attr.as_simple_path()).any(|path| { - path.segments() - .zip(["rust_analyzer", "rust_fixture"]) - .all(|(seg, name)| seg.name_ref().map_or(false, |nr| nr.text() == name)) - }) - }); - if !has_rust_fixture_attr { - return None; - } - let value = literal.value().ok()?; + let (analysis, fixture_analysis) = Analysis::from_ra_fixture_with_on_cursor( + sema, + literal.clone(), + expanded, + config.minicore, + &mut |range| { + hl.add(HlRange { + range, + highlight: HlTag::Keyword | HlMod::Injected, + binding_hash: None, + }); + }, + )?; if let Some(range) = literal.open_quote_text_range() { hl.add(HlRange { range, highlight: HlTag::StringLiteral.into(), binding_hash: None }) } - let mut inj = Injector::default(); - - let mut text = &*value; - let mut offset: TextSize = 0.into(); - - while !text.is_empty() { - let marker = "$0"; - let idx = text.find(marker).unwrap_or(text.len()); - let (chunk, next) = text.split_at(idx); - inj.add(chunk, TextRange::at(offset, TextSize::of(chunk))); - - text = next; - offset += TextSize::of(chunk); - - if let Some(next) = text.strip_prefix(marker) { - if let Some(range) = literal.map_range_up(TextRange::at(offset, TextSize::of(marker))) { - hl.add(HlRange { - range, - highlight: HlTag::Keyword | HlMod::Injected, - binding_hash: None, - }); - } - - text = next; - - let marker_len = TextSize::of(marker); - offset += marker_len; - } - } - - let (analysis, tmp_file_id) = Analysis::from_single_file(inj.take_text()); - - for mut hl_range in analysis - .highlight( - HighlightConfig { - syntactic_name_ref_highlighting: false, - comments: true, - punctuation: true, - operator: true, - strings: true, - specialize_punctuation: config.specialize_punctuation, - specialize_operator: config.operator, - inject_doc_comment: config.inject_doc_comment, - macro_bang: config.macro_bang, - }, - tmp_file_id, - ) - .unwrap() - { - for range in inj.map_range_up(hl_range.range) { - if let Some(range) = literal.map_range_up(range) { + for tmp_file_id in fixture_analysis.files() { + for mut hl_range in analysis + .highlight( + HighlightConfig { + syntactic_name_ref_highlighting: false, + comments: true, + punctuation: true, + operator: true, + strings: true, + specialize_punctuation: config.specialize_punctuation, + specialize_operator: config.operator, + inject_doc_comment: config.inject_doc_comment, + macro_bang: config.macro_bang, + // What if there is a fixture inside a fixture? It's fixtures all the way down. + // (In fact, we have a fixture inside a fixture in our test suite!) + minicore: config.minicore, + }, + tmp_file_id, + ) + .unwrap() + { + for range in fixture_analysis.map_range_up(tmp_file_id, hl_range.range) { hl_range.range = range; hl_range.highlight |= HlMod::Injected; hl.add(hl_range); @@ -116,7 +87,7 @@ const RUSTDOC_FENCES: [&str; 2] = ["```", "~~~"]; pub(super) fn doc_comment( hl: &mut Highlights, sema: &Semantics<'_, RootDatabase>, - config: HighlightConfig, + config: &HighlightConfig<'_>, src_file_id: EditionedFileId, node: &SyntaxNode, ) { @@ -128,39 +99,37 @@ pub(super) fn doc_comment( // Extract intra-doc links and emit highlights for them. if let Some((docs, doc_mapping)) = docs_with_rangemap(sema.db, &attributes) { - hir::attach_db(sema.db, || { - extract_definitions_from_docs(&docs) - .into_iter() - .filter_map(|(range, link, ns)| { - doc_mapping - .map(range) - .filter(|(mapping, _)| mapping.file_id == src_file_id) - .and_then(|(InFile { value: mapped_range, .. }, attr_id)| { - Some(mapped_range).zip(resolve_doc_path_for_def( - sema.db, - def, - &link, - ns, - attr_id.is_inner_attr(), - )) - }) - }) - .for_each(|(range, def)| { - hl.add(HlRange { - range, - highlight: module_def_to_hl_tag(def) - | HlMod::Documentation - | HlMod::Injected - | HlMod::IntraDocLink, - binding_hash: None, + extract_definitions_from_docs(&docs) + .into_iter() + .filter_map(|(range, link, ns)| { + doc_mapping + .map(range) + .filter(|(mapping, _)| mapping.file_id == src_file_id) + .and_then(|(InFile { value: mapped_range, .. }, attr_id)| { + Some(mapped_range).zip(resolve_doc_path_for_def( + sema.db, + def, + &link, + ns, + attr_id.is_inner_attr(), + )) }) + }) + .for_each(|(range, def)| { + hl.add(HlRange { + range, + highlight: module_def_to_hl_tag(def) + | HlMod::Documentation + | HlMod::Injected + | HlMod::IntraDocLink, + binding_hash: None, }) - }); + }) } // Extract doc-test sources from the docs and calculate highlighting for them. - let mut inj = Injector::default(); + let mut inj = RangeMapper::default(); inj.add_unmapped("fn doctest() {\n"); let attrs_source_map = attributes.source_map(sema.db); @@ -249,7 +218,7 @@ pub(super) fn doc_comment( if let Ok(ranges) = analysis.with_db(|db| { super::highlight( db, - HighlightConfig { + &HighlightConfig { syntactic_name_ref_highlighting: true, comments: true, punctuation: true, @@ -259,6 +228,7 @@ pub(super) fn doc_comment( specialize_operator: config.operator, inject_doc_comment: config.inject_doc_comment, macro_bang: config.macro_bang, + minicore: config.minicore, }, tmp_file_id, None, diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/injector.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/injector.rs deleted file mode 100644 index c30f79732496..000000000000 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/injector.rs +++ /dev/null @@ -1,77 +0,0 @@ -//! Extracts a subsequence of a text document, remembering the mapping of ranges -//! between original and extracted texts. -use std::ops::{self, Sub}; - -use stdx::equal_range_by; -use syntax::{TextRange, TextSize}; - -#[derive(Default)] -pub(super) struct Injector { - buf: String, - ranges: Vec<(TextRange, Option>)>, -} - -impl Injector { - pub(super) fn add(&mut self, text: &str, source_range: TextRange) { - let len = TextSize::of(text); - assert_eq!(len, source_range.len()); - self.add_impl(text, Some(source_range.start())); - } - - pub(super) fn add_unmapped(&mut self, text: &str) { - self.add_impl(text, None); - } - - fn add_impl(&mut self, text: &str, source: Option) { - let len = TextSize::of(text); - let target_range = TextRange::at(TextSize::of(&self.buf), len); - self.ranges.push((target_range, source.map(|it| Delta::new(target_range.start(), it)))); - self.buf.push_str(text); - } - - pub(super) fn take_text(&mut self) -> String { - std::mem::take(&mut self.buf) - } - - pub(super) fn map_range_up(&self, range: TextRange) -> impl Iterator + '_ { - equal_range_by(&self.ranges, |&(r, _)| TextRange::ordering(r, range)).filter_map(move |i| { - let (target_range, delta) = self.ranges[i]; - let intersection = target_range.intersect(range).unwrap(); - Some(intersection + delta?) - }) - } -} - -#[derive(Clone, Copy)] -enum Delta { - Add(T), - Sub(T), -} - -impl Delta { - fn new(from: T, to: T) -> Delta - where - T: Ord + Sub, - { - if to >= from { Delta::Add(to - from) } else { Delta::Sub(from - to) } - } -} - -impl ops::Add> for TextSize { - type Output = TextSize; - - fn add(self, rhs: Delta) -> TextSize { - match rhs { - Delta::Add(it) => self + it, - Delta::Sub(it) => self - it, - } - } -} - -impl ops::Add> for TextRange { - type Output = TextRange; - - fn add(self, rhs: Delta) -> TextRange { - TextRange::at(self.start() + rhs, self.len()) - } -} diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tags.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tags.rs index 4b8762640c74..456a61298741 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tags.rs +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tags.rs @@ -124,8 +124,10 @@ pub enum HlOperator { Bitwise, /// +, -, *, /, +=, -=, *=, /= Arithmetic, - /// &&, ||, ! + /// &&, || Logical, + /// ! + Negation, /// >, <, ==, >=, <=, != Comparison, /// Other operators @@ -194,6 +196,7 @@ impl HlTag { HlOperator::Arithmetic => "arithmetic", HlOperator::Logical => "logical", HlOperator::Comparison => "comparison", + HlOperator::Negation => "negation", HlOperator::Other => "operator", }, HlTag::StringLiteral => "string_literal", diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_general.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_general.html index d99b29cfb8fa..d058191aef72 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_general.html +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_general.html @@ -148,7 +148,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd let baz = (-42,); let baz = -baz.0; - let _ = !true; + let _ = !true; 'foo: loop { break 'foo; diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html index 3b468ab6dba6..579c6ceadcb8 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html @@ -43,18 +43,19 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd

fn fixture(#[rust_analyzer::rust_fixture] ra_fixture: &str) {}
 
 fn main() {
-    fixture(r#"
-trait Foo {
-    fn foo() {
-        println!("2 + 2 = {}", 4);
-    }
+    fixture(r#"
+@@- minicore: sized
+trait Foo: Sized {
+    fn foo() {
+        println!("2 + 2 = {}", 4);
+    }
 }"#
     );
-    fixture(r"
-fn foo() {
-    foo($0{
-        92
-    }$0)
+    fixture(r"
+fn foo() {
+    foo($0{
+        92
+    }$0)
 }"
     );
 }
\ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_injection_2.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_injection_2.html new file mode 100644 index 000000000000..fc2d9a387016 --- /dev/null +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_injection_2.html @@ -0,0 +1,61 @@ + + +
fn fixture(#[rust_analyzer::rust_fixture] ra_fixture: &str) {}
+
+fn main() {
+    fixture(r#"
+@@- /main.rs crate:main deps:other_crate
+fn test() {
+    let x = other_crate::foo::S::thing();
+    x;
+} //^ i128
+
+@@- /lib.rs crate:other_crate
+pub mod foo {
+    pub struct S;
+    impl S {
+        pub fn thing() -> i128 { 0 }
+    }
+}
+    "#);
+}
\ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_operators.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_operators.html index 9c42401ed077..cceb159c9dd4 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_operators.html +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_operators.html @@ -41,7 +41,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd .unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
fn main() {
-    1 + 1 - 1 * 1 / 1 % 1 | 1 & 1 ! 1 ^ 1 >> 1 << 1;
+    1 + 1 - 1 * 1 / 1 % 1 | 1 & 1 ! 1 ^ 1 >> 1 << 1;
     let mut a = 0;
     a += 1;
     a -= 1;
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs
index 8198701d6843..4e84127c29f8 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs
@@ -1,13 +1,13 @@
 use std::time::Instant;
 
 use expect_test::{ExpectFile, expect_file};
-use ide_db::SymbolKind;
+use ide_db::{MiniCore, SymbolKind};
 use span::Edition;
 use test_utils::{AssertLinear, bench, bench_fixture, skip_slow_tests};
 
 use crate::{FileRange, HighlightConfig, HlTag, TextRange, fixture};
 
-const HL_CONFIG: HighlightConfig = HighlightConfig {
+const HL_CONFIG: HighlightConfig<'_> = HighlightConfig {
     strings: true,
     comments: true,
     punctuation: true,
@@ -17,6 +17,7 @@ const HL_CONFIG: HighlightConfig = HighlightConfig {
     inject_doc_comment: true,
     macro_bang: true,
     syntactic_name_ref_highlighting: false,
+    minicore: MiniCore::default(),
 };
 
 #[test]
@@ -1016,6 +1017,35 @@ impl t for foo {
     )
 }
 
+#[test]
+fn test_injection_2() {
+    check_highlighting(
+        r##"
+fn fixture(#[rust_analyzer::rust_fixture] ra_fixture: &str) {}
+
+fn main() {
+    fixture(r#"
+@@- /main.rs crate:main deps:other_crate
+fn test() {
+    let x = other_crate::foo::S::thing();
+    x;
+} //^ i128
+
+@@- /lib.rs crate:other_crate
+pub mod foo {
+    pub struct S;
+    impl S {
+        pub fn thing() -> i128 { 0 }
+    }
+}
+    "#);
+}
+"##,
+        expect_file!["./test_data/highlight_injection_2.html"],
+        false,
+    );
+}
+
 #[test]
 fn test_injection() {
     check_highlighting(
@@ -1024,7 +1054,8 @@ fn fixture(#[rust_analyzer::rust_fixture] ra_fixture: &str) {}
 
 fn main() {
     fixture(r#"
-trait Foo {
+@@- minicore: sized
+trait Foo: Sized {
     fn foo() {
         println!("2 + 2 = {}", 4);
     }
@@ -1223,7 +1254,7 @@ fn foo(x: &fn(&dyn Trait)) {}
 /// Note that the `snapshot` file is overwritten by the rendered HTML.
 fn check_highlighting_with_config(
     #[rust_analyzer::rust_fixture] ra_fixture: &str,
-    config: HighlightConfig,
+    config: HighlightConfig<'_>,
     expect: ExpectFile,
     rainbow: bool,
 ) {
diff --git a/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs b/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs
index 920bdd9568fc..756377fe56f7 100644
--- a/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs
+++ b/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs
@@ -517,4 +517,6 @@ define_symbols! {
     precision,
     width,
     never_type_fallback,
+    specialization,
+    min_specialization,
 }
diff --git a/src/tools/rust-analyzer/crates/macros/src/lib.rs b/src/tools/rust-analyzer/crates/macros/src/lib.rs
index 8bafcf498c51..3f90ecc8f902 100644
--- a/src/tools/rust-analyzer/crates/macros/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/macros/src/lib.rs
@@ -162,3 +162,42 @@ fn has_ignore_attr(attrs: &[syn::Attribute], name: &'static str, meta: &'static
 
     ignored
 }
+
+decl_derive!(
+    [UpmapFromRaFixture] => upmap_from_ra_fixture
+);
+
+fn upmap_from_ra_fixture(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream {
+    if let syn::Data::Union(_) = s.ast().data {
+        panic!("cannot derive on union")
+    }
+
+    s.add_bounds(synstructure::AddBounds::Generics);
+    s.bind_with(|_| synstructure::BindStyle::Move);
+    let body = s.each_variant(|vi| {
+        let bindings = vi.bindings();
+        vi.construct(|_, index| {
+            let bind = &bindings[index];
+
+            quote! {
+                ::ide_db::ra_fixture::UpmapFromRaFixture::upmap_from_ra_fixture(
+                    #bind, __analysis, __virtual_file_id, __real_file_id,
+                )?
+            }
+        })
+    });
+
+    s.bound_impl(
+        quote!(::ide_db::ra_fixture::UpmapFromRaFixture),
+        quote! {
+            fn upmap_from_ra_fixture(
+                self,
+                __analysis: &::ide_db::ra_fixture::RaFixtureAnalysis,
+                __virtual_file_id: ::ide_db::ra_fixture::FileId,
+                __real_file_id: ::ide_db::ra_fixture::FileId,
+            ) -> Result {
+                Ok(match self { #body })
+            }
+        },
+    )
+}
diff --git a/src/tools/rust-analyzer/crates/parser/Cargo.toml b/src/tools/rust-analyzer/crates/parser/Cargo.toml
index c7da654de6d9..8384d5bec21a 100644
--- a/src/tools/rust-analyzer/crates/parser/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/parser/Cargo.toml
@@ -19,6 +19,7 @@ rustc-literal-escaper.workspace = true
 tracing = { workspace = true, optional = true }
 
 edition.workspace = true
+winnow = { version = "0.7.13", default-features = false }
 
 [dev-dependencies]
 expect-test = "1.5.1"
diff --git a/src/tools/rust-analyzer/crates/parser/src/frontmatter.rs b/src/tools/rust-analyzer/crates/parser/src/frontmatter.rs
new file mode 100644
index 000000000000..2747db4327c5
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/src/frontmatter.rs
@@ -0,0 +1,348 @@
+// Copied from https://github.com/rust-lang/cargo/blob/367fd9f213750cd40317803dd0a5a3ce3f0c676d/src/cargo/util/frontmatter.rs
+#![expect(dead_code)] // avoid editing
+#![expect(unreachable_pub)] // avoid editing
+#![expect(clippy::useless_format)] // avoid editing
+
+type Span = std::ops::Range;
+
+#[derive(Debug)]
+pub struct ScriptSource<'s> {
+    /// The full file
+    raw: &'s str,
+    /// The `#!/usr/bin/env cargo` line, if present
+    shebang: Option,
+    /// The code fence opener (`---`)
+    open: Option,
+    /// Trailing text after `ScriptSource::open` that identifies the meaning of
+    /// `ScriptSource::frontmatter`
+    info: Option,
+    /// The lines between `ScriptSource::open` and `ScriptSource::close`
+    frontmatter: Option,
+    /// The code fence closer (`---`)
+    close: Option,
+    /// All content after the frontmatter and shebang
+    content: Span,
+}
+
+impl<'s> ScriptSource<'s> {
+    pub fn parse(raw: &'s str) -> Result {
+        use winnow::stream::FindSlice as _;
+        use winnow::stream::Location as _;
+        use winnow::stream::Offset as _;
+        use winnow::stream::Stream as _;
+
+        let content_end = raw.len();
+        let mut source = Self {
+            raw,
+            shebang: None,
+            open: None,
+            info: None,
+            frontmatter: None,
+            close: None,
+            content: 0..content_end,
+        };
+
+        let mut input = winnow::stream::LocatingSlice::new(raw);
+
+        if let Some(shebang_end) = strip_shebang(input.as_ref()) {
+            let shebang_start = input.current_token_start();
+            let _ = input.next_slice(shebang_end);
+            let shebang_end = input.current_token_start();
+            source.shebang = Some(shebang_start..shebang_end);
+            source.content = shebang_end..content_end;
+        }
+
+        // Whitespace may precede a frontmatter but must end with a newline
+        if let Some(nl_end) = strip_ws_lines(input.as_ref()) {
+            let _ = input.next_slice(nl_end);
+        }
+
+        // Opens with a line that starts with 3 or more `-` followed by an optional identifier
+        const FENCE_CHAR: char = '-';
+        let fence_length = input
+            .as_ref()
+            .char_indices()
+            .find_map(|(i, c)| (c != FENCE_CHAR).then_some(i))
+            .unwrap_or_else(|| input.eof_offset());
+        let open_start = input.current_token_start();
+        let fence_pattern = input.next_slice(fence_length);
+        let open_end = input.current_token_start();
+        match fence_length {
+            0 => {
+                return Ok(source);
+            }
+            1 | 2 => {
+                // either not a frontmatter or invalid frontmatter opening
+                return Err(FrontmatterError::new(
+                    format!(
+                        "found {fence_length} `{FENCE_CHAR}` in rust frontmatter, expected at least 3"
+                    ),
+                    raw.len()..raw.len(),
+                ).push_visible_span(open_start..open_end));
+            }
+            _ => {}
+        }
+        source.open = Some(open_start..open_end);
+        let Some(info_nl) = input.find_slice("\n") else {
+            return Err(FrontmatterError::new(
+                format!("unclosed frontmatter; expected `{fence_pattern}`"),
+                raw.len()..raw.len(),
+            )
+            .push_visible_span(open_start..open_end));
+        };
+        let info = input.next_slice(info_nl.start);
+        let info = info.strip_suffix('\r').unwrap_or(info); // already excludes `\n`
+        let info = info.trim_matches(is_horizontal_whitespace);
+        if !info.is_empty() {
+            let info_start = info.offset_from(&raw);
+            let info_end = info_start + info.len();
+            source.info = Some(info_start..info_end);
+        }
+
+        // Ends with a line that starts with a matching number of `-` only followed by whitespace
+        let nl_fence_pattern = format!("\n{fence_pattern}");
+        let Some(frontmatter_nl) = input.find_slice(nl_fence_pattern.as_str()) else {
+            for len in (2..(nl_fence_pattern.len() - 1)).rev() {
+                let Some(frontmatter_nl) = input.find_slice(&nl_fence_pattern[0..len]) else {
+                    continue;
+                };
+                let _ = input.next_slice(frontmatter_nl.start + 1);
+                let close_start = input.current_token_start();
+                let _ = input.next_slice(len);
+                let close_end = input.current_token_start();
+                let fewer_dashes = fence_length - len;
+                return Err(FrontmatterError::new(
+                    format!(
+                        "closing code fence has {fewer_dashes} less `-` than the opening fence"
+                    ),
+                    close_start..close_end,
+                )
+                .push_visible_span(open_start..open_end));
+            }
+            return Err(FrontmatterError::new(
+                format!("unclosed frontmatter; expected `{fence_pattern}`"),
+                raw.len()..raw.len(),
+            )
+            .push_visible_span(open_start..open_end));
+        };
+        let frontmatter_start = input.current_token_start() + 1; // skip nl from infostring
+        let _ = input.next_slice(frontmatter_nl.start + 1);
+        let frontmatter_end = input.current_token_start();
+        source.frontmatter = Some(frontmatter_start..frontmatter_end);
+        let close_start = input.current_token_start();
+        let _ = input.next_slice(fence_length);
+        let close_end = input.current_token_start();
+        source.close = Some(close_start..close_end);
+
+        let nl = input.find_slice("\n");
+        let after_closing_fence =
+            input.next_slice(nl.map(|span| span.end).unwrap_or_else(|| input.eof_offset()));
+        let content_start = input.current_token_start();
+        let extra_dashes = after_closing_fence.chars().take_while(|b| *b == FENCE_CHAR).count();
+        if 0 < extra_dashes {
+            let extra_start = close_end;
+            let extra_end = extra_start + extra_dashes;
+            return Err(FrontmatterError::new(
+                format!("closing code fence has {extra_dashes} more `-` than the opening fence"),
+                extra_start..extra_end,
+            )
+            .push_visible_span(open_start..open_end));
+        } else {
+            let after_closing_fence = strip_newline(after_closing_fence);
+            let after_closing_fence = after_closing_fence.trim_matches(is_horizontal_whitespace);
+            if !after_closing_fence.is_empty() {
+                // extra characters beyond the original fence pattern
+                let after_start = after_closing_fence.offset_from(&raw);
+                let after_end = after_start + after_closing_fence.len();
+                return Err(FrontmatterError::new(
+                    format!("unexpected characters after frontmatter close"),
+                    after_start..after_end,
+                )
+                .push_visible_span(open_start..open_end));
+            }
+        }
+
+        source.content = content_start..content_end;
+
+        if let Some(nl_end) = strip_ws_lines(input.as_ref()) {
+            let _ = input.next_slice(nl_end);
+        }
+        let fence_length = input
+            .as_ref()
+            .char_indices()
+            .find_map(|(i, c)| (c != FENCE_CHAR).then_some(i))
+            .unwrap_or_else(|| input.eof_offset());
+        if 0 < fence_length {
+            let fence_start = input.current_token_start();
+            let fence_end = fence_start + fence_length;
+            return Err(FrontmatterError::new(
+                format!("only one frontmatter is supported"),
+                fence_start..fence_end,
+            )
+            .push_visible_span(open_start..open_end)
+            .push_visible_span(close_start..close_end));
+        }
+
+        Ok(source)
+    }
+
+    pub fn shebang(&self) -> Option<&'s str> {
+        self.shebang.clone().map(|span| &self.raw[span])
+    }
+
+    pub fn shebang_span(&self) -> Option {
+        self.shebang.clone()
+    }
+
+    pub fn open_span(&self) -> Option {
+        self.open.clone()
+    }
+
+    pub fn info(&self) -> Option<&'s str> {
+        self.info.clone().map(|span| &self.raw[span])
+    }
+
+    pub fn info_span(&self) -> Option {
+        self.info.clone()
+    }
+
+    pub fn frontmatter(&self) -> Option<&'s str> {
+        self.frontmatter.clone().map(|span| &self.raw[span])
+    }
+
+    pub fn frontmatter_span(&self) -> Option {
+        self.frontmatter.clone()
+    }
+
+    pub fn close_span(&self) -> Option {
+        self.close.clone()
+    }
+
+    pub fn content(&self) -> &'s str {
+        &self.raw[self.content.clone()]
+    }
+
+    pub fn content_span(&self) -> Span {
+        self.content.clone()
+    }
+}
+
+/// Returns the index after the shebang line, if present
+pub fn strip_shebang(input: &str) -> Option {
+    // See rust-lang/rust's compiler/rustc_lexer/src/lib.rs's `strip_shebang`
+    // Shebang must start with `#!` literally, without any preceding whitespace.
+    // For simplicity we consider any line starting with `#!` a shebang,
+    // regardless of restrictions put on shebangs by specific platforms.
+    if let Some(rest) = input.strip_prefix("#!") {
+        // Ok, this is a shebang but if the next non-whitespace token is `[`,
+        // then it may be valid Rust code, so consider it Rust code.
+        //
+        // NOTE: rustc considers line and block comments to be whitespace but to avoid
+        // any more awareness of Rust grammar, we are excluding it.
+        if !rest.trim_start().starts_with('[') {
+            // No other choice than to consider this a shebang.
+            let newline_end = input.find('\n').map(|pos| pos + 1).unwrap_or(input.len());
+            return Some(newline_end);
+        }
+    }
+    None
+}
+
+/// Returns the index after any lines with only whitespace, if present
+pub fn strip_ws_lines(input: &str) -> Option {
+    let ws_end = input.find(|c| !is_whitespace(c)).unwrap_or(input.len());
+    if ws_end == 0 {
+        return None;
+    }
+
+    let nl_start = input[0..ws_end].rfind('\n')?;
+    let nl_end = nl_start + 1;
+    Some(nl_end)
+}
+
+/// True if `c` is considered a whitespace according to Rust language definition.
+/// See [Rust language reference](https://doc.rust-lang.org/reference/whitespace.html)
+/// for definitions of these classes.
+fn is_whitespace(c: char) -> bool {
+    // This is Pattern_White_Space.
+    //
+    // Note that this set is stable (ie, it doesn't change with different
+    // Unicode versions), so it's ok to just hard-code the values.
+
+    matches!(
+        c,
+        // End-of-line characters
+        | '\u{000A}' // line feed (\n)
+        | '\u{000B}' // vertical tab
+        | '\u{000C}' // form feed
+        | '\u{000D}' // carriage return (\r)
+        | '\u{0085}' // next line (from latin1)
+        | '\u{2028}' // LINE SEPARATOR
+        | '\u{2029}' // PARAGRAPH SEPARATOR
+
+        // `Default_Ignorable_Code_Point` characters
+        | '\u{200E}' // LEFT-TO-RIGHT MARK
+        | '\u{200F}' // RIGHT-TO-LEFT MARK
+
+        // Horizontal space characters
+        | '\u{0009}'   // tab (\t)
+        | '\u{0020}' // space
+    )
+}
+
+/// True if `c` is considered horizontal whitespace according to Rust language definition.
+fn is_horizontal_whitespace(c: char) -> bool {
+    // This is Pattern_White_Space.
+    //
+    // Note that this set is stable (ie, it doesn't change with different
+    // Unicode versions), so it's ok to just hard-code the values.
+
+    matches!(
+        c,
+        // Horizontal space characters
+        '\u{0009}'   // tab (\t)
+        | '\u{0020}' // space
+    )
+}
+
+fn strip_newline(text: &str) -> &str {
+    text.strip_suffix("\r\n").or_else(|| text.strip_suffix('\n')).unwrap_or(text)
+}
+
+#[derive(Debug)]
+pub struct FrontmatterError {
+    message: String,
+    primary_span: Span,
+    visible_spans: Vec,
+}
+
+impl FrontmatterError {
+    pub fn new(message: impl Into, span: Span) -> Self {
+        Self { message: message.into(), primary_span: span, visible_spans: Vec::new() }
+    }
+
+    pub fn push_visible_span(mut self, span: Span) -> Self {
+        self.visible_spans.push(span);
+        self
+    }
+
+    pub fn message(&self) -> &str {
+        self.message.as_str()
+    }
+
+    pub fn primary_span(&self) -> Span {
+        self.primary_span.clone()
+    }
+
+    pub fn visible_spans(&self) -> &[Span] {
+        &self.visible_spans
+    }
+}
+
+impl std::fmt::Display for FrontmatterError {
+    fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        self.message.fmt(fmt)
+    }
+}
+
+impl std::error::Error for FrontmatterError {}
diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/expressions.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/expressions.rs
index 41fd72d8d5a2..76d26c1ecdfc 100644
--- a/src/tools/rust-analyzer/crates/parser/src/grammar/expressions.rs
+++ b/src/tools/rust-analyzer/crates/parser/src/grammar/expressions.rs
@@ -430,6 +430,11 @@ fn postfix_expr(
             // }
             T!['('] if allow_calls => call_expr(p, lhs),
             T!['['] if allow_calls => index_expr(p, lhs),
+            // test_err postfix_dot_expr_ambiguity
+            // fn foo() {
+            //     x.
+            //     ()
+            // }
             T![.] => match postfix_dot_expr::(p, lhs) {
                 Ok(it) => it,
                 Err(it) => {
@@ -458,6 +463,7 @@ fn postfix_dot_expr(
 
     if PATH_NAME_REF_KINDS.contains(p.nth(nth1))
         && (p.nth(nth2) == T!['('] || p.nth_at(nth2, T![::]))
+        || p.nth(nth1) == T!['(']
     {
         return Ok(method_call_expr::(p, lhs));
     }
@@ -526,19 +532,26 @@ fn method_call_expr(
     lhs: CompletedMarker,
 ) -> CompletedMarker {
     if FLOAT_RECOVERY {
-        assert!(p.at_ts(PATH_NAME_REF_KINDS) && (p.nth(1) == T!['('] || p.nth_at(1, T![::])));
-    } else {
         assert!(
-            p.at(T![.])
-                && PATH_NAME_REF_KINDS.contains(p.nth(1))
-                && (p.nth(2) == T!['('] || p.nth_at(2, T![::]))
+            p.at_ts(PATH_NAME_REF_KINDS) && (p.nth(1) == T!['('] || p.nth_at(1, T![::]))
+                || p.current() == T!['(']
+        );
+    } else {
+        assert!(p.at(T![.]));
+        assert!(
+            PATH_NAME_REF_KINDS.contains(p.nth(1)) && (p.nth(2) == T!['('] || p.nth_at(2, T![::]))
+                || p.nth(1) == T!['(']
         );
     }
     let m = lhs.precede(p);
     if !FLOAT_RECOVERY {
         p.bump(T![.]);
     }
-    name_ref_mod_path(p);
+    if p.at_ts(PATH_NAME_REF_KINDS) {
+        name_ref_mod_path(p);
+    } else {
+        p.error("expected method name, field name or number");
+    }
     generic_args::opt_generic_arg_list_expr(p);
     if p.at(T!['(']) {
         arg_list(p);
diff --git a/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs b/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs
index edc3f406a67e..7c78ba8faf5f 100644
--- a/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs
+++ b/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs
@@ -37,10 +37,17 @@ impl<'a> LexedStr<'a> {
     pub fn new(edition: Edition, text: &'a str) -> LexedStr<'a> {
         let _p = tracing::info_span!("LexedStr::new").entered();
         let mut conv = Converter::new(edition, text);
-        if let Some(shebang_len) = rustc_lexer::strip_shebang(text) {
-            conv.res.push(SHEBANG, conv.offset);
-            conv.offset = shebang_len;
-        };
+        if let Ok(script) = crate::frontmatter::ScriptSource::parse(text) {
+            if let Some(shebang) = script.shebang_span() {
+                conv.push(SHEBANG, shebang.end - shebang.start, Vec::new());
+            }
+            if script.frontmatter().is_some() {
+                conv.push(FRONTMATTER, script.content_span().start - conv.offset, Vec::new());
+            }
+        } else if let Some(shebang_len) = rustc_lexer::strip_shebang(text) {
+            // Leave error reporting to `rustc_lexer`
+            conv.push(SHEBANG, shebang_len, Vec::new());
+        }
 
         // Re-create the tokenizer from scratch every token because `GuardedStrPrefix` is one token in the lexer
         // but we want to split it to two in edition <2024.
diff --git a/src/tools/rust-analyzer/crates/parser/src/lib.rs b/src/tools/rust-analyzer/crates/parser/src/lib.rs
index 7963f00bb25c..53444ef52cff 100644
--- a/src/tools/rust-analyzer/crates/parser/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/parser/src/lib.rs
@@ -26,6 +26,7 @@ extern crate ra_ap_rustc_lexer as rustc_lexer;
 extern crate rustc_lexer;
 
 mod event;
+mod frontmatter;
 mod grammar;
 mod input;
 mod lexed_str;
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs b/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs
index cd6d433d0efa..9bdbe5633033 100644
--- a/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs
+++ b/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs
@@ -844,6 +844,10 @@ mod err {
         run_and_expect_errors("test_data/parser/inline/err/pointer_type_no_mutability.rs");
     }
     #[test]
+    fn postfix_dot_expr_ambiguity() {
+        run_and_expect_errors("test_data/parser/inline/err/postfix_dot_expr_ambiguity.rs");
+    }
+    #[test]
     fn precise_capturing_invalid() {
         run_and_expect_errors("test_data/parser/inline/err/precise_capturing_invalid.rs");
     }
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/frontmatter.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/frontmatter.rast
new file mode 100644
index 000000000000..2c7d3cdb1227
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/frontmatter.rast
@@ -0,0 +1,12 @@
+FRONTMATTER "\n---\n[dependencies]\nclap = \"4\"\n---\n"
+WHITESPACE "\n"
+FN_KW "fn"
+WHITESPACE " "
+IDENT "main"
+L_PAREN "("
+R_PAREN ")"
+WHITESPACE " "
+L_CURLY "{"
+WHITESPACE "\n"
+R_CURLY "}"
+WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/frontmatter.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/frontmatter.rs
new file mode 100644
index 000000000000..be7bf74fdba2
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/frontmatter.rs
@@ -0,0 +1,8 @@
+
+---
+[dependencies]
+clap = "4"
+---
+
+fn main() {
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/shebang_frontmatter.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/shebang_frontmatter.rast
new file mode 100644
index 000000000000..fb4787f4001f
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/shebang_frontmatter.rast
@@ -0,0 +1,13 @@
+SHEBANG "#!/usr/bin/env cargo\n"
+FRONTMATTER "\n---\n[dependencies]\nclap = \"4\"\n---\n"
+WHITESPACE "\n"
+FN_KW "fn"
+WHITESPACE " "
+IDENT "main"
+L_PAREN "("
+R_PAREN ")"
+WHITESPACE " "
+L_CURLY "{"
+WHITESPACE "\n"
+R_CURLY "}"
+WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/shebang_frontmatter.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/shebang_frontmatter.rs
new file mode 100644
index 000000000000..090b7713feb3
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/shebang_frontmatter.rs
@@ -0,0 +1,9 @@
+#!/usr/bin/env cargo
+
+---
+[dependencies]
+clap = "4"
+---
+
+fn main() {
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/single_line_comments.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/single_line_comments.rast
index a7681e9f5086..c4e531b449f7 100644
--- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/single_line_comments.rast
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/single_line_comments.rast
@@ -1,5 +1,4 @@
-SHEBANG "#!/usr/bin/env bash"
-WHITESPACE "\n"
+SHEBANG "#!/usr/bin/env bash\n"
 COMMENT "// hello"
 WHITESPACE "\n"
 COMMENT "//! World"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0002_duplicate_shebang.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0002_duplicate_shebang.rast
index 3159a15a3b1c..7ee1ecfbb159 100644
--- a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0002_duplicate_shebang.rast
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0002_duplicate_shebang.rast
@@ -1,6 +1,5 @@
 SOURCE_FILE
-  SHEBANG "#!/use/bin/env rusti"
-  WHITESPACE "\n"
+  SHEBANG "#!/use/bin/env rusti\n"
   ATTR
     POUND "#"
     BANG "!"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/postfix_dot_expr_ambiguity.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/postfix_dot_expr_ambiguity.rast
new file mode 100644
index 000000000000..4ee318de2515
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/postfix_dot_expr_ambiguity.rast
@@ -0,0 +1,29 @@
+SOURCE_FILE
+  FN
+    FN_KW "fn"
+    WHITESPACE " "
+    NAME
+      IDENT "foo"
+    PARAM_LIST
+      L_PAREN "("
+      R_PAREN ")"
+    WHITESPACE " "
+    BLOCK_EXPR
+      STMT_LIST
+        L_CURLY "{"
+        WHITESPACE "\n    "
+        METHOD_CALL_EXPR
+          PATH_EXPR
+            PATH
+              PATH_SEGMENT
+                NAME_REF
+                  IDENT "x"
+          DOT "."
+          WHITESPACE "\n    "
+          ARG_LIST
+            L_PAREN "("
+            R_PAREN ")"
+        WHITESPACE "\n"
+        R_CURLY "}"
+  WHITESPACE "\n"
+error 17: expected method name, field name or number
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/postfix_dot_expr_ambiguity.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/postfix_dot_expr_ambiguity.rs
new file mode 100644
index 000000000000..c1aed3034288
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/postfix_dot_expr_ambiguity.rs
@@ -0,0 +1,4 @@
+fn foo() {
+    x.
+    ()
+}
diff --git a/src/tools/rust-analyzer/crates/project-model/src/build_dependencies.rs b/src/tools/rust-analyzer/crates/project-model/src/build_dependencies.rs
index 5eda5af3ace0..3a682d5a4d83 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/build_dependencies.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/build_dependencies.rs
@@ -142,7 +142,7 @@ impl WorkspaceBuildScripts {
                 if let Some(&(package, workspace)) = by_id.get(package) {
                     cb(&workspaces[workspace][package].name, &mut res[workspace].outputs[package]);
                 } else {
-                    never!("Received compiler message for unknown package: {}", package);
+                    tracing::error!("Received compiler message for unknown package: {}", package);
                 }
             },
             progress,
diff --git a/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs b/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs
index 04fb2275893c..76ba01f3a263 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs
@@ -49,8 +49,9 @@ pub struct CargoWorkspace {
     is_virtual_workspace: bool,
     /// Whether this workspace represents the sysroot workspace.
     is_sysroot: bool,
-    /// Environment variables set in the `.cargo/config` file.
-    config_env: Env,
+    /// Environment variables set in the `.cargo/config` file and the extraEnv
+    /// configuration option.
+    env: Env,
     requires_rustc_private: bool,
 }
 
@@ -325,7 +326,7 @@ impl CargoWorkspace {
     pub fn new(
         mut meta: cargo_metadata::Metadata,
         ws_manifest_path: ManifestPath,
-        cargo_config_env: Env,
+        cargo_env: Env,
         is_sysroot: bool,
     ) -> CargoWorkspace {
         let mut pkg_by_id = FxHashMap::default();
@@ -498,7 +499,7 @@ impl CargoWorkspace {
             is_virtual_workspace,
             requires_rustc_private,
             is_sysroot,
-            config_env: cargo_config_env,
+            env: cargo_env,
         }
     }
 
@@ -589,7 +590,7 @@ impl CargoWorkspace {
     }
 
     pub fn env(&self) -> &Env {
-        &self.config_env
+        &self.env
     }
 
     pub fn is_sysroot(&self) -> bool {
diff --git a/src/tools/rust-analyzer/crates/project-model/src/env.rs b/src/tools/rust-analyzer/crates/project-model/src/env.rs
index d281492fc98c..ae0458af7aa7 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/env.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/env.rs
@@ -1,6 +1,7 @@
 //! Cargo-like environment variables injection.
 use base_db::Env;
 use paths::Utf8Path;
+use rustc_hash::FxHashMap;
 use toolchain::Tool;
 
 use crate::{ManifestPath, PackageData, TargetKind, cargo_config_file::CargoConfigFile};
@@ -60,8 +61,14 @@ pub(crate) fn inject_rustc_tool_env(env: &mut Env, cargo_name: &str, kind: Targe
     env.set("CARGO_CRATE_NAME", cargo_name.replace('-', "_"));
 }
 
-pub(crate) fn cargo_config_env(manifest: &ManifestPath, config: &Option) -> Env {
+pub(crate) fn cargo_config_env(
+    manifest: &ManifestPath,
+    config: &Option,
+    extra_env: &FxHashMap>,
+) -> Env {
     let mut env = Env::default();
+    env.extend(extra_env.iter().filter_map(|(k, v)| v.as_ref().map(|v| (k.clone(), v.clone()))));
+
     let Some(serde_json::Value::Object(env_json)) = config.as_ref().and_then(|c| c.get("env"))
     else {
         return env;
@@ -72,22 +79,34 @@ pub(crate) fn cargo_config_env(manifest: &ManifestPath, config: &Option>::as_ref(manifest.parent());
 
     for (key, entry) in env_json {
-        let serde_json::Value::Object(entry) = entry else {
-            continue;
-        };
-        let Some(value) = entry.get("value").and_then(|v| v.as_str()) else {
-            continue;
+        let value = match entry {
+            serde_json::Value::String(s) => s.clone(),
+            serde_json::Value::Object(entry) => {
+                // Each entry MUST have a `value` key.
+                let Some(value) = entry.get("value").and_then(|v| v.as_str()) else {
+                    continue;
+                };
+                // If the entry already exists in the environment AND the `force` key is not set to
+                // true, then don't overwrite the value.
+                if extra_env.get(key).is_some_and(Option::is_some)
+                    && !entry.get("force").and_then(|v| v.as_bool()).unwrap_or(false)
+                {
+                    continue;
+                }
+
+                if entry
+                    .get("relative")
+                    .and_then(|v| v.as_bool())
+                    .is_some_and(std::convert::identity)
+                {
+                    base.join(value).to_string()
+                } else {
+                    value.to_owned()
+                }
+            }
+            _ => continue,
         };
 
-        let value = if entry
-            .get("relative")
-            .and_then(|v| v.as_bool())
-            .is_some_and(std::convert::identity)
-        {
-            base.join(value).to_string()
-        } else {
-            value.to_owned()
-        };
         env.insert(key, value);
     }
 
@@ -113,7 +132,19 @@ fn parse_output_cargo_config_env_works() {
     },
     "TEST": {
       "value": "test"
-    }
+    },
+    "FORCED": {
+      "value": "test",
+      "force": true
+    },
+    "UNFORCED": {
+      "value": "test",
+      "force": false
+    },
+    "OVERWRITTEN": {
+      "value": "test"
+    },
+    "NOT_AN_OBJECT": "value"
   }
 }
 "#;
@@ -121,9 +152,22 @@ fn parse_output_cargo_config_env_works() {
     let cwd = paths::Utf8PathBuf::try_from(std::env::current_dir().unwrap()).unwrap();
     let manifest = paths::AbsPathBuf::assert(cwd.join("Cargo.toml"));
     let manifest = ManifestPath::try_from(manifest).unwrap();
-    let env = cargo_config_env(&manifest, &Some(config));
+    let extra_env = [
+        ("FORCED", Some("ignored")),
+        ("UNFORCED", Some("newvalue")),
+        ("OVERWRITTEN", Some("newvalue")),
+        ("TEST", None),
+    ]
+    .iter()
+    .map(|(k, v)| (k.to_string(), v.map(ToString::to_string)))
+    .collect();
+    let env = cargo_config_env(&manifest, &Some(config), &extra_env);
     assert_eq!(env.get("CARGO_WORKSPACE_DIR").as_deref(), Some(cwd.join("").as_str()));
     assert_eq!(env.get("RELATIVE").as_deref(), Some(cwd.join("../relative").as_str()));
     assert_eq!(env.get("INVALID").as_deref(), Some("../relative"));
     assert_eq!(env.get("TEST").as_deref(), Some("test"));
+    assert_eq!(env.get("FORCED").as_deref(), Some("test"));
+    assert_eq!(env.get("UNFORCED").as_deref(), Some("newvalue"));
+    assert_eq!(env.get("OVERWRITTEN").as_deref(), Some("newvalue"));
+    assert_eq!(env.get("NOT_AN_OBJECT").as_deref(), Some("value"));
 }
diff --git a/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs b/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs
index c0a5009afba3..5cc399bfe76d 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs
@@ -30,7 +30,7 @@ pub struct Sysroot {
 
 #[derive(Debug, Clone, Eq, PartialEq)]
 pub enum RustLibSrcWorkspace {
-    Workspace(CargoWorkspace),
+    Workspace { ws: CargoWorkspace, metadata_err: Option },
     Json(ProjectJson),
     Stitched(stitched::Stitched),
     Empty,
@@ -39,7 +39,9 @@ pub enum RustLibSrcWorkspace {
 impl fmt::Display for RustLibSrcWorkspace {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match self {
-            RustLibSrcWorkspace::Workspace(ws) => write!(f, "workspace {}", ws.workspace_root()),
+            RustLibSrcWorkspace::Workspace { ws, .. } => {
+                write!(f, "workspace {}", ws.workspace_root())
+            }
             RustLibSrcWorkspace::Json(json) => write!(f, "json {}", json.manifest_or_root()),
             RustLibSrcWorkspace::Stitched(stitched) => {
                 write!(f, "stitched with {} crates", stitched.crates.len())
@@ -74,7 +76,7 @@ impl Sysroot {
 
     pub fn is_rust_lib_src_empty(&self) -> bool {
         match &self.workspace {
-            RustLibSrcWorkspace::Workspace(ws) => ws.packages().next().is_none(),
+            RustLibSrcWorkspace::Workspace { ws, .. } => ws.packages().next().is_none(),
             RustLibSrcWorkspace::Json(project_json) => project_json.n_crates() == 0,
             RustLibSrcWorkspace::Stitched(stitched) => stitched.crates.is_empty(),
             RustLibSrcWorkspace::Empty => true,
@@ -85,9 +87,16 @@ impl Sysroot {
         self.error.as_deref()
     }
 
+    pub fn metadata_error(&self) -> Option<&str> {
+        match &self.workspace {
+            RustLibSrcWorkspace::Workspace { metadata_err, .. } => metadata_err.as_deref(),
+            _ => None,
+        }
+    }
+
     pub fn num_packages(&self) -> usize {
         match &self.workspace {
-            RustLibSrcWorkspace::Workspace(ws) => ws.packages().count(),
+            RustLibSrcWorkspace::Workspace { ws, .. } => ws.packages().count(),
             RustLibSrcWorkspace::Json(project_json) => project_json.n_crates(),
             RustLibSrcWorkspace::Stitched(stitched) => stitched.crates.len(),
             RustLibSrcWorkspace::Empty => 0,
@@ -210,7 +219,6 @@ impl Sysroot {
         &self,
         sysroot_source_config: &RustSourceWorkspaceConfig,
         no_deps: bool,
-        current_dir: &AbsPath,
         target_dir: &Utf8Path,
         progress: &dyn Fn(String),
     ) -> Option {
@@ -224,7 +232,7 @@ impl Sysroot {
             if fs::metadata(&library_manifest).is_ok() {
                 match self.load_library_via_cargo(
                     &library_manifest,
-                    current_dir,
+                    src_root,
                     target_dir,
                     cargo_config,
                     no_deps,
@@ -294,7 +302,9 @@ impl Sysroot {
             && let Some(src_root) = &self.rust_lib_src_root
         {
             let has_core = match &self.workspace {
-                RustLibSrcWorkspace::Workspace(ws) => ws.packages().any(|p| ws[p].name == "core"),
+                RustLibSrcWorkspace::Workspace { ws: workspace, .. } => {
+                    workspace.packages().any(|p| workspace[p].name == "core")
+                }
                 RustLibSrcWorkspace::Json(project_json) => project_json
                     .crates()
                     .filter_map(|(_, krate)| krate.display_name.clone())
@@ -333,7 +343,7 @@ impl Sysroot {
 
         // Make sure we never attempt to write to the sysroot
         let locked = true;
-        let (mut res, _) =
+        let (mut res, err) =
             FetchMetadata::new(library_manifest, current_dir, &cargo_config, self, no_deps)
                 .exec(target_dir, locked, progress)?;
 
@@ -388,7 +398,10 @@ impl Sysroot {
 
         let cargo_workspace =
             CargoWorkspace::new(res, library_manifest.clone(), Default::default(), true);
-        Ok(RustLibSrcWorkspace::Workspace(cargo_workspace))
+        Ok(RustLibSrcWorkspace::Workspace {
+            ws: cargo_workspace,
+            metadata_err: err.map(|e| format!("{e:#}")),
+        })
     }
 }
 
diff --git a/src/tools/rust-analyzer/crates/project-model/src/tests.rs b/src/tools/rust-analyzer/crates/project-model/src/tests.rs
index 987d381fac63..711cdd11b9a8 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/tests.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/tests.rs
@@ -241,7 +241,6 @@ fn smoke_test_real_sysroot_cargo() {
     let loaded_sysroot = sysroot.load_workspace(
         &RustSourceWorkspaceConfig::default_cargo(),
         false,
-        &cwd,
         &Utf8PathBuf::default(),
         &|_| (),
     );
@@ -249,7 +248,7 @@ fn smoke_test_real_sysroot_cargo() {
         sysroot.set_workspace(loaded_sysroot);
     }
     assert!(
-        matches!(sysroot.workspace(), RustLibSrcWorkspace::Workspace(_)),
+        matches!(sysroot.workspace(), RustLibSrcWorkspace::Workspace { .. }),
         "got {}",
         sysroot.workspace()
     );
diff --git a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs
index 0649ce9eeb9d..b88db419574d 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs
@@ -383,41 +383,40 @@ impl ProjectWorkspace {
                         toolchain.clone(),
                     )),
                     config.no_deps,
-                    workspace_dir,
                     &target_dir,
                     progress,
                 )
             });
-            let cargo_config_extra_env =
-                s.spawn(move || cargo_config_env(cargo_toml, &config_file));
+            let cargo_env =
+                s.spawn(move || cargo_config_env(cargo_toml, &config_file, &config.extra_env));
             thread::Result::Ok((
                 rustc_cfg.join()?,
                 target_data.join()?,
                 rustc_dir.join()?,
                 loaded_sysroot.join()?,
                 cargo_metadata.join()?,
-                cargo_config_extra_env.join()?,
+                cargo_env.join()?,
             ))
         });
 
-        let (
-            rustc_cfg,
-            data_layout,
-            mut rustc,
-            loaded_sysroot,
-            cargo_metadata,
-            cargo_config_extra_env,
-        ) = match join {
-            Ok(it) => it,
-            Err(e) => std::panic::resume_unwind(e),
-        };
+        let (rustc_cfg, data_layout, mut rustc, loaded_sysroot, cargo_metadata, mut cargo_env) =
+            match join {
+                Ok(it) => it,
+                Err(e) => std::panic::resume_unwind(e),
+            };
+
+        for (key, value) in config.extra_env.iter() {
+            if let Some(value) = value {
+                cargo_env.insert(key.clone(), value.clone());
+            }
+        }
 
         let (meta, error) = cargo_metadata.with_context(|| {
             format!(
                 "Failed to read Cargo metadata from Cargo.toml file {cargo_toml}, {toolchain:?}",
             )
         })?;
-        let cargo = CargoWorkspace::new(meta, cargo_toml.clone(), cargo_config_extra_env, false);
+        let cargo = CargoWorkspace::new(meta, cargo_toml.clone(), cargo_env, false);
         if let Some(loaded_sysroot) = loaded_sysroot {
             tracing::info!(src_root = ?sysroot.rust_lib_src_root(), root = %loaded_sysroot, "Loaded sysroot");
             sysroot.set_workspace(loaded_sysroot);
@@ -487,7 +486,6 @@ impl ProjectWorkspace {
                     sysroot.load_workspace(
                         &RustSourceWorkspaceConfig::Json(*sysroot_project),
                         config.no_deps,
-                        project_root,
                         &target_dir,
                         progress,
                     )
@@ -499,7 +497,6 @@ impl ProjectWorkspace {
                             toolchain.clone(),
                         )),
                         config.no_deps,
-                        project_root,
                         &target_dir,
                         progress,
                     )
@@ -561,7 +558,6 @@ impl ProjectWorkspace {
                 toolchain.clone(),
             )),
             config.no_deps,
-            dir,
             &target_dir,
             &|_| (),
         );
@@ -590,7 +586,8 @@ impl ProjectWorkspace {
             .unwrap_or_else(|| dir.join("target").into());
         let cargo_script =
             fetch_metadata.exec(&target_dir, false, &|_| ()).ok().map(|(ws, error)| {
-                let cargo_config_extra_env = cargo_config_env(detached_file, &config_file);
+                let cargo_config_extra_env =
+                    cargo_config_env(detached_file, &config_file, &config.extra_env);
                 (
                     CargoWorkspace::new(ws, detached_file.clone(), cargo_config_extra_env, false),
                     WorkspaceBuildScripts::default(),
@@ -747,7 +744,7 @@ impl ProjectWorkspace {
     pub fn to_roots(&self) -> Vec {
         let mk_sysroot = || {
             let mut r = match self.sysroot.workspace() {
-                RustLibSrcWorkspace::Workspace(ws) => ws
+                RustLibSrcWorkspace::Workspace { ws, .. } => ws
                     .packages()
                     .filter_map(|pkg| {
                         if ws[pkg].is_local {
@@ -1093,7 +1090,13 @@ fn project_json_to_crate_graph(
                 },
                 file_id,
             )| {
-                let env = env.clone().into_iter().collect();
+                let mut env = env.clone().into_iter().collect::();
+                // Override existing env vars with those from `extra_env`
+                env.extend(
+                    extra_env
+                        .iter()
+                        .filter_map(|(k, v)| v.as_ref().map(|v| (k.clone(), v.clone()))),
+                );
 
                 let target_cfgs = match target.as_deref() {
                     Some(target) => cfg_cache.entry(target).or_insert_with(|| {
@@ -1735,7 +1738,7 @@ fn sysroot_to_crate_graph(
 ) -> (SysrootPublicDeps, Option) {
     let _p = tracing::info_span!("sysroot_to_crate_graph").entered();
     match sysroot.workspace() {
-        RustLibSrcWorkspace::Workspace(cargo) => {
+        RustLibSrcWorkspace::Workspace { ws: cargo, .. } => {
             let (sysroot_cg, sysroot_pm) = cargo_to_crate_graph(
                 load,
                 None,
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs
index 2a9ef981291e..de24bc09ff0f 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs
@@ -25,7 +25,7 @@ use ide::{
     InlayHintsConfig, LineCol, RootDatabase,
 };
 use ide_db::{
-    EditionedFileId, LineIndexDatabase, SnippetCap,
+    EditionedFileId, LineIndexDatabase, MiniCore, SnippetCap,
     base_db::{SourceDatabase, salsa::Database},
 };
 use itertools::Itertools;
@@ -345,6 +345,8 @@ impl flags::AnalysisStats {
             self.run_term_search(&workspace, db, &vfs, &file_ids, verbosity);
         }
 
+        hir::clear_tls_solver_cache();
+
         let db = host.raw_database_mut();
         db.trigger_lru_eviction();
 
@@ -1194,6 +1196,7 @@ impl flags::AnalysisStats {
                     closing_brace_hints_min_lines: Some(20),
                     fields_to_resolve: InlayFieldsToResolve::empty(),
                     range_exclusive_hints: true,
+                    minicore: MiniCore::default(),
                 },
                 analysis.editioned_file_id_to_vfs(file_id),
                 None,
@@ -1203,26 +1206,25 @@ impl flags::AnalysisStats {
         bar.finish_and_clear();
 
         let mut bar = create_bar();
+        let annotation_config = AnnotationConfig {
+            binary_target: true,
+            annotate_runnables: true,
+            annotate_impls: true,
+            annotate_references: false,
+            annotate_method_references: false,
+            annotate_enum_variant_references: false,
+            location: ide::AnnotationLocation::AboveName,
+            minicore: MiniCore::default(),
+        };
         for &file_id in file_ids {
             let msg = format!("annotations: {}", vfs.file_path(file_id.file_id(db)));
             bar.set_message(move || msg.clone());
             analysis
-                .annotations(
-                    &AnnotationConfig {
-                        binary_target: true,
-                        annotate_runnables: true,
-                        annotate_impls: true,
-                        annotate_references: false,
-                        annotate_method_references: false,
-                        annotate_enum_variant_references: false,
-                        location: ide::AnnotationLocation::AboveName,
-                    },
-                    analysis.editioned_file_id_to_vfs(file_id),
-                )
+                .annotations(&annotation_config, analysis.editioned_file_id_to_vfs(file_id))
                 .unwrap()
                 .into_iter()
                 .for_each(|annotation| {
-                    _ = analysis.resolve_annotation(annotation);
+                    _ = analysis.resolve_annotation(&annotation_config, annotation);
                 });
             bar.inc(1);
         }
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs
index 609ebf2b514f..20567149bb4b 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs
@@ -78,7 +78,6 @@ impl Tester {
         let loaded_sysroot = sysroot.load_workspace(
             &RustSourceWorkspaceConfig::default_cargo(),
             false,
-            &path,
             &Utf8PathBuf::default(),
             &|_| (),
         );
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
index 96b65838ae42..652c2e32ffa6 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
@@ -8,14 +8,14 @@ use std::{env, fmt, iter, ops::Not, sync::OnceLock};
 use cfg::{CfgAtom, CfgDiff};
 use hir::Symbol;
 use ide::{
-    AssistConfig, CallHierarchyConfig, CallableSnippets, CompletionConfig,
-    CompletionFieldsToResolve, DiagnosticsConfig, GenericParameterHints, HighlightConfig,
-    HighlightRelatedConfig, HoverConfig, HoverDocFormat, InlayFieldsToResolve, InlayHintsConfig,
-    JoinLinesConfig, MemoryLayoutHoverConfig, MemoryLayoutHoverRenderKind, Snippet, SnippetScope,
-    SourceRootId,
+    AnnotationConfig, AssistConfig, CallHierarchyConfig, CallableSnippets, CompletionConfig,
+    CompletionFieldsToResolve, DiagnosticsConfig, GenericParameterHints, GotoDefinitionConfig,
+    HighlightConfig, HighlightRelatedConfig, HoverConfig, HoverDocFormat, InlayFieldsToResolve,
+    InlayHintsConfig, JoinLinesConfig, MemoryLayoutHoverConfig, MemoryLayoutHoverRenderKind,
+    Snippet, SnippetScope, SourceRootId,
 };
 use ide_db::{
-    SnippetCap,
+    MiniCore, SnippetCap,
     assists::ExprFillDefaultMode,
     imports::insert_use::{ImportGranularity, InsertUseConfig, PrefixKind},
 };
@@ -1454,6 +1454,23 @@ impl LensConfig {
     pub fn references(&self) -> bool {
         self.method_refs || self.refs_adt || self.refs_trait || self.enum_variant_refs
     }
+
+    pub fn into_annotation_config<'a>(
+        self,
+        binary_target: bool,
+        minicore: MiniCore<'a>,
+    ) -> AnnotationConfig<'a> {
+        AnnotationConfig {
+            binary_target,
+            annotate_runnables: self.runnable(),
+            annotate_impls: self.implementations,
+            annotate_references: self.refs_adt,
+            annotate_method_references: self.method_refs,
+            annotate_enum_variant_references: self.enum_variant_refs,
+            location: self.location.into(),
+            minicore,
+        }
+    }
 }
 
 #[derive(Clone, Debug, PartialEq, Eq)]
@@ -1688,11 +1705,15 @@ impl Config {
         }
     }
 
-    pub fn call_hierarchy(&self) -> CallHierarchyConfig {
-        CallHierarchyConfig { exclude_tests: self.references_excludeTests().to_owned() }
+    pub fn call_hierarchy<'a>(&self, minicore: MiniCore<'a>) -> CallHierarchyConfig<'a> {
+        CallHierarchyConfig { exclude_tests: self.references_excludeTests().to_owned(), minicore }
     }
 
-    pub fn completion(&self, source_root: Option) -> CompletionConfig<'_> {
+    pub fn completion<'a>(
+        &'a self,
+        source_root: Option,
+        minicore: MiniCore<'a>,
+    ) -> CompletionConfig<'a> {
         let client_capability_fields = self.completion_resolve_support_properties();
         CompletionConfig {
             enable_postfix_completions: self.completion_postfix_enable(source_root).to_owned(),
@@ -1746,6 +1767,7 @@ impl Config {
                 })
                 .collect(),
             exclude_traits: self.completion_excludeTraits(source_root),
+            minicore,
         }
     }
 
@@ -1820,7 +1842,7 @@ impl Config {
         }
     }
 
-    pub fn hover(&self) -> HoverConfig {
+    pub fn hover<'a>(&self, minicore: MiniCore<'a>) -> HoverConfig<'a> {
         let mem_kind = |kind| match kind {
             MemoryLayoutHoverRenderKindDef::Both => MemoryLayoutHoverRenderKind::Both,
             MemoryLayoutHoverRenderKindDef::Decimal => MemoryLayoutHoverRenderKind::Decimal,
@@ -1853,10 +1875,15 @@ impl Config {
                 None => ide::SubstTyLen::Unlimited,
             },
             show_drop_glue: *self.hover_dropGlue_enable(),
+            minicore,
         }
     }
 
-    pub fn inlay_hints(&self) -> InlayHintsConfig {
+    pub fn goto_definition<'a>(&self, minicore: MiniCore<'a>) -> GotoDefinitionConfig<'a> {
+        GotoDefinitionConfig { minicore }
+    }
+
+    pub fn inlay_hints<'a>(&self, minicore: MiniCore<'a>) -> InlayHintsConfig<'a> {
         let client_capability_fields = self.inlay_hint_resolve_support_properties();
 
         InlayHintsConfig {
@@ -1938,6 +1965,7 @@ impl Config {
             ),
             implicit_drop_hints: self.inlayHints_implicitDrops_enable().to_owned(),
             range_exclusive_hints: self.inlayHints_rangeExclusiveHints_enable().to_owned(),
+            minicore,
         }
     }
 
@@ -1975,7 +2003,7 @@ impl Config {
         self.semanticHighlighting_nonStandardTokens().to_owned()
     }
 
-    pub fn highlighting_config(&self) -> HighlightConfig {
+    pub fn highlighting_config<'a>(&self, minicore: MiniCore<'a>) -> HighlightConfig<'a> {
         HighlightConfig {
             strings: self.semanticHighlighting_strings_enable().to_owned(),
             comments: self.semanticHighlighting_comments_enable().to_owned(),
@@ -1990,6 +2018,7 @@ impl Config {
                 .to_owned(),
             inject_doc_comment: self.semanticHighlighting_doc_comment_inject_enable().to_owned(),
             syntactic_name_ref_highlighting: false,
+            minicore,
         }
     }
 
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs
index b545106fe1cf..73a51bba3d9a 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs
@@ -12,7 +12,7 @@ use cargo_metadata::PackageId;
 use crossbeam_channel::{Receiver, Sender, select_biased, unbounded};
 use ide_db::FxHashSet;
 use itertools::Itertools;
-use paths::{AbsPath, AbsPathBuf, Utf8PathBuf};
+use paths::{AbsPath, AbsPathBuf, Utf8Path, Utf8PathBuf};
 use rustc_hash::FxHashMap;
 use serde::Deserialize as _;
 use serde_derive::Deserialize;
@@ -432,8 +432,10 @@ impl FlycheckActor {
                                 options
                                     .target_dir
                                     .as_deref()
-                                    .unwrap_or("target".as_ref())
-                                    .join(format!("rust-analyzer/flycheck{}", self.id)),
+                                    .unwrap_or(
+                                        Utf8Path::new("target").join("rust-analyzer").as_path(),
+                                    )
+                                    .join(format!("flycheck{}", self.id)),
                             ),
                             _ => None,
                         },
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs
index ce6644f725ca..f557dd5cb092 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs
@@ -13,7 +13,10 @@ use cargo_metadata::PackageId;
 use crossbeam_channel::{Receiver, Sender, unbounded};
 use hir::ChangeWithProcMacros;
 use ide::{Analysis, AnalysisHost, Cancellable, FileId, SourceRootId};
-use ide_db::base_db::{Crate, ProcMacroPaths, SourceDatabase};
+use ide_db::{
+    MiniCore,
+    base_db::{Crate, ProcMacroPaths, SourceDatabase},
+};
 use itertools::Itertools;
 use load_cargo::SourceRootConfig;
 use lsp_types::{SemanticTokens, Url};
@@ -188,6 +191,14 @@ pub(crate) struct GlobalState {
     /// This is marked true if we failed to load a crate root file at crate graph creation,
     /// which will usually end up causing a bunch of incorrect diagnostics on startup.
     pub(crate) incomplete_crate_graph: bool,
+
+    pub(crate) minicore: MiniCoreRustAnalyzerInternalOnly,
+}
+
+// FIXME: This should move to the VFS once the rewrite is done.
+#[derive(Debug, Clone, Default)]
+pub(crate) struct MiniCoreRustAnalyzerInternalOnly {
+    pub(crate) minicore_text: Option,
 }
 
 /// An immutable snapshot of the world's state at a point in time.
@@ -204,6 +215,7 @@ pub(crate) struct GlobalStateSnapshot {
     // FIXME: Can we derive this from somewhere else?
     pub(crate) proc_macros_loaded: bool,
     pub(crate) flycheck: Arc<[FlycheckHandle]>,
+    minicore: MiniCoreRustAnalyzerInternalOnly,
 }
 
 impl std::panic::UnwindSafe for GlobalStateSnapshot {}
@@ -304,6 +316,8 @@ impl GlobalState {
 
             deferred_task_queue: task_queue,
             incomplete_crate_graph: false,
+
+            minicore: MiniCoreRustAnalyzerInternalOnly::default(),
         };
         // Apply any required database inputs from the config.
         this.update_configuration(config);
@@ -550,6 +564,7 @@ impl GlobalState {
             workspaces: Arc::clone(&self.workspaces),
             analysis: self.analysis_host.analysis(),
             vfs: Arc::clone(&self.vfs),
+            minicore: self.minicore.clone(),
             check_fixes: Arc::clone(&self.diagnostics.check_fixes),
             mem_docs: self.mem_docs.clone(),
             semantic_tokens_cache: Arc::clone(&self.semantic_tokens_cache),
@@ -838,6 +853,14 @@ impl GlobalStateSnapshot {
     pub(crate) fn file_exists(&self, file_id: FileId) -> bool {
         self.vfs.read().0.exists(file_id)
     }
+
+    #[inline]
+    pub(crate) fn minicore(&self) -> MiniCore<'_> {
+        match &self.minicore.minicore_text {
+            Some(minicore) => MiniCore::new(minicore),
+            None => MiniCore::default(),
+        }
+    }
 }
 
 pub(crate) fn file_id_to_url(vfs: &vfs::Vfs, id: FileId) -> Url {
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs
index 6cb28aecf748..55d092f30f6b 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs
@@ -7,8 +7,8 @@ use anyhow::Context;
 
 use base64::{Engine, prelude::BASE64_STANDARD};
 use ide::{
-    AnnotationConfig, AssistKind, AssistResolveStrategy, Cancellable, CompletionFieldsToResolve,
-    FilePosition, FileRange, FileStructureConfig, HoverAction, HoverGotoTypeData,
+    AssistKind, AssistResolveStrategy, Cancellable, CompletionFieldsToResolve, FilePosition,
+    FileRange, FileStructureConfig, FindAllRefsConfig, HoverAction, HoverGotoTypeData,
     InlayFieldsToResolve, Query, RangeInfo, ReferenceCategory, Runnable, RunnableKind,
     SingleResolve, SourceChange, TextEdit,
 };
@@ -811,7 +811,8 @@ pub(crate) fn handle_goto_definition(
     let _p = tracing::info_span!("handle_goto_definition").entered();
     let position =
         try_default!(from_proto::file_position(&snap, params.text_document_position_params)?);
-    let nav_info = match snap.analysis.goto_definition(position)? {
+    let config = snap.config.goto_definition(snap.minicore());
+    let nav_info = match snap.analysis.goto_definition(position, &config)? {
         None => return Ok(None),
         Some(it) => it,
     };
@@ -829,7 +830,8 @@ pub(crate) fn handle_goto_declaration(
         &snap,
         params.text_document_position_params.clone()
     )?);
-    let nav_info = match snap.analysis.goto_declaration(position)? {
+    let config = snap.config.goto_definition(snap.minicore());
+    let nav_info = match snap.analysis.goto_declaration(position, &config)? {
         None => return handle_goto_definition(snap, params),
         Some(it) => it,
     };
@@ -1106,7 +1108,7 @@ pub(crate) fn handle_completion(
         context.and_then(|ctx| ctx.trigger_character).and_then(|s| s.chars().next());
 
     let source_root = snap.analysis.source_root_id(position.file_id)?;
-    let completion_config = &snap.config.completion(Some(source_root));
+    let completion_config = &snap.config.completion(Some(source_root), snap.minicore());
     // FIXME: We should fix up the position when retrying the cancelled request instead
     position.offset = position.offset.min(line_index.index.len());
     let items = match snap.analysis.completions(
@@ -1160,7 +1162,8 @@ pub(crate) fn handle_completion_resolve(
     };
     let source_root = snap.analysis.source_root_id(file_id)?;
 
-    let mut forced_resolve_completions_config = snap.config.completion(Some(source_root));
+    let mut forced_resolve_completions_config =
+        snap.config.completion(Some(source_root), snap.minicore());
     forced_resolve_completions_config.fields_to_resolve = CompletionFieldsToResolve::empty();
 
     let position = FilePosition { file_id, offset };
@@ -1274,7 +1277,7 @@ pub(crate) fn handle_hover(
     };
     let file_range = try_default!(from_proto::file_range(&snap, ¶ms.text_document, range)?);
 
-    let hover = snap.config.hover();
+    let hover = snap.config.hover(snap.minicore());
     let info = match snap.analysis.hover(&hover, file_range)? {
         None => return Ok(None),
         Some(info) => info,
@@ -1360,7 +1363,11 @@ pub(crate) fn handle_references(
     let exclude_imports = snap.config.find_all_refs_exclude_imports();
     let exclude_tests = snap.config.find_all_refs_exclude_tests();
 
-    let Some(refs) = snap.analysis.find_all_refs(position, None)? else {
+    let Some(refs) = snap.analysis.find_all_refs(
+        position,
+        &FindAllRefsConfig { search_scope: None, minicore: snap.minicore() },
+    )?
+    else {
         return Ok(None);
     };
 
@@ -1615,8 +1622,8 @@ pub(crate) fn handle_code_lens(
     let target_spec = TargetSpec::for_file(&snap, file_id)?;
 
     let annotations = snap.analysis.annotations(
-        &AnnotationConfig {
-            binary_target: target_spec
+        &lens_config.into_annotation_config(
+            target_spec
                 .map(|spec| {
                     matches!(
                         spec.target_kind(),
@@ -1624,13 +1631,8 @@ pub(crate) fn handle_code_lens(
                     )
                 })
                 .unwrap_or(false),
-            annotate_runnables: lens_config.runnable(),
-            annotate_impls: lens_config.implementations,
-            annotate_references: lens_config.refs_adt,
-            annotate_method_references: lens_config.method_refs,
-            annotate_enum_variant_references: lens_config.enum_variant_refs,
-            location: lens_config.location.into(),
-        },
+            snap.minicore(),
+        ),
         file_id,
     )?;
 
@@ -1653,7 +1655,8 @@ pub(crate) fn handle_code_lens_resolve(
     let Some(annotation) = from_proto::annotation(&snap, code_lens.range, resolve)? else {
         return Ok(code_lens);
     };
-    let annotation = snap.analysis.resolve_annotation(annotation)?;
+    let config = snap.config.lens().into_annotation_config(false, snap.minicore());
+    let annotation = snap.analysis.resolve_annotation(&config, annotation)?;
 
     let mut acc = Vec::new();
     to_proto::code_lens(&mut acc, &snap, annotation)?;
@@ -1736,7 +1739,7 @@ pub(crate) fn handle_inlay_hints(
         range.end().min(line_index.index.len()),
     );
 
-    let inlay_hints_config = snap.config.inlay_hints();
+    let inlay_hints_config = snap.config.inlay_hints(snap.minicore());
     Ok(Some(
         snap.analysis
             .inlay_hints(&inlay_hints_config, file_id, Some(range))?
@@ -1777,7 +1780,7 @@ pub(crate) fn handle_inlay_hints_resolve(
     let line_index = snap.file_line_index(file_id)?;
     let range = from_proto::text_range(&line_index, resolve_data.resolve_range)?;
 
-    let mut forced_resolve_inlay_hints_config = snap.config.inlay_hints();
+    let mut forced_resolve_inlay_hints_config = snap.config.inlay_hints(snap.minicore());
     forced_resolve_inlay_hints_config.fields_to_resolve = InlayFieldsToResolve::empty();
     let resolve_hints = snap.analysis.inlay_hints_resolve(
         &forced_resolve_inlay_hints_config,
@@ -1816,7 +1819,8 @@ pub(crate) fn handle_call_hierarchy_prepare(
     let position =
         try_default!(from_proto::file_position(&snap, params.text_document_position_params)?);
 
-    let nav_info = match snap.analysis.call_hierarchy(position)? {
+    let config = snap.config.call_hierarchy(snap.minicore());
+    let nav_info = match snap.analysis.call_hierarchy(position, &config)? {
         None => return Ok(None),
         Some(it) => it,
     };
@@ -1842,8 +1846,8 @@ pub(crate) fn handle_call_hierarchy_incoming(
     let frange = try_default!(from_proto::file_range(&snap, &doc, item.selection_range)?);
     let fpos = FilePosition { file_id: frange.file_id, offset: frange.range.start() };
 
-    let config = snap.config.call_hierarchy();
-    let call_items = match snap.analysis.incoming_calls(config, fpos)? {
+    let config = snap.config.call_hierarchy(snap.minicore());
+    let call_items = match snap.analysis.incoming_calls(&config, fpos)? {
         None => return Ok(None),
         Some(it) => it,
     };
@@ -1881,8 +1885,8 @@ pub(crate) fn handle_call_hierarchy_outgoing(
     let fpos = FilePosition { file_id: frange.file_id, offset: frange.range.start() };
     let line_index = snap.file_line_index(fpos.file_id)?;
 
-    let config = snap.config.call_hierarchy();
-    let call_items = match snap.analysis.outgoing_calls(config, fpos)? {
+    let config = snap.config.call_hierarchy(snap.minicore());
+    let call_items = match snap.analysis.outgoing_calls(&config, fpos)? {
         None => return Ok(None),
         Some(it) => it,
     };
@@ -1916,7 +1920,7 @@ pub(crate) fn handle_semantic_tokens_full(
     let text = snap.analysis.file_text(file_id)?;
     let line_index = snap.file_line_index(file_id)?;
 
-    let mut highlight_config = snap.config.highlighting_config();
+    let mut highlight_config = snap.config.highlighting_config(snap.minicore());
     // Avoid flashing a bunch of unresolved references when the proc-macro servers haven't been spawned yet.
     highlight_config.syntactic_name_ref_highlighting =
         snap.workspaces.is_empty() || !snap.proc_macros_loaded;
@@ -1946,7 +1950,7 @@ pub(crate) fn handle_semantic_tokens_full_delta(
     let text = snap.analysis.file_text(file_id)?;
     let line_index = snap.file_line_index(file_id)?;
 
-    let mut highlight_config = snap.config.highlighting_config();
+    let mut highlight_config = snap.config.highlighting_config(snap.minicore());
     // Avoid flashing a bunch of unresolved references when the proc-macro servers haven't been spawned yet.
     highlight_config.syntactic_name_ref_highlighting =
         snap.workspaces.is_empty() || !snap.proc_macros_loaded;
@@ -1988,7 +1992,7 @@ pub(crate) fn handle_semantic_tokens_range(
     let text = snap.analysis.file_text(frange.file_id)?;
     let line_index = snap.file_line_index(frange.file_id)?;
 
-    let mut highlight_config = snap.config.highlighting_config();
+    let mut highlight_config = snap.config.highlighting_config(snap.minicore());
     // Avoid flashing a bunch of unresolved references when the proc-macro servers haven't been spawned yet.
     highlight_config.syntactic_name_ref_highlighting =
         snap.workspaces.is_empty() || !snap.proc_macros_loaded;
@@ -2156,7 +2160,13 @@ fn show_ref_command_link(
 ) -> Option {
     if snap.config.hover_actions().references
         && snap.config.client_commands().show_reference
-        && let Some(ref_search_res) = snap.analysis.find_all_refs(*position, None).unwrap_or(None)
+        && let Some(ref_search_res) = snap
+            .analysis
+            .find_all_refs(
+                *position,
+                &FindAllRefsConfig { search_scope: None, minicore: snap.minicore() },
+            )
+            .unwrap_or(None)
     {
         let uri = to_proto::url(snap, position.file_id);
         let line_index = snap.file_line_index(position.file_id).ok()?;
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/integrated_benchmarks.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/integrated_benchmarks.rs
index 84b7888258f8..38ee9cbe7fc8 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/integrated_benchmarks.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/integrated_benchmarks.rs
@@ -16,7 +16,7 @@ use ide::{
     FilePosition, TextSize,
 };
 use ide_db::{
-    SnippetCap,
+    MiniCore, SnippetCap,
     imports::insert_use::{ImportGranularity, InsertUseConfig},
 };
 use project_model::CargoConfig;
@@ -186,6 +186,7 @@ fn integrated_completion_benchmark() {
             exclude_traits: &[],
             enable_auto_await: true,
             enable_auto_iter: true,
+            minicore: MiniCore::default(),
         };
         let position =
             FilePosition { file_id, offset: TextSize::try_from(completion_offset).unwrap() };
@@ -240,6 +241,7 @@ fn integrated_completion_benchmark() {
             exclude_traits: &[],
             enable_auto_await: true,
             enable_auto_iter: true,
+            minicore: MiniCore::default(),
         };
         let position =
             FilePosition { file_id, offset: TextSize::try_from(completion_offset).unwrap() };
@@ -292,6 +294,7 @@ fn integrated_completion_benchmark() {
             exclude_traits: &[],
             enable_auto_await: true,
             enable_auto_iter: true,
+            minicore: MiniCore::default(),
         };
         let position =
             FilePosition { file_id, offset: TextSize::try_from(completion_offset).unwrap() };
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/semantic_tokens.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/semantic_tokens.rs
index 3c21e1992525..828118a0866d 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/semantic_tokens.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/semantic_tokens.rs
@@ -91,6 +91,7 @@ define_semantic_token_types![
         (LIFETIME, "lifetime"),
         (LOGICAL, "logical") => OPERATOR,
         (MACRO_BANG, "macroBang") => MACRO,
+        (NEGATION, "negation") => OPERATOR,
         (PARENTHESIS, "parenthesis"),
         (PROC_MACRO, "procMacro") => MACRO,
         (PUNCTUATION, "punctuation"),
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs
index d51ddb86d197..024c13e1918d 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs
@@ -16,7 +16,9 @@ use ide::{
     SnippetEdit, SourceChange, StructureNodeKind, SymbolKind, TextEdit, TextRange, TextSize,
     UpdateTest,
 };
-use ide_db::{FxHasher, assists, rust_doc::format_docs, source_change::ChangeAnnotationId};
+use ide_db::{
+    FxHasher, MiniCore, assists, rust_doc::format_docs, source_change::ChangeAnnotationId,
+};
 use itertools::Itertools;
 use paths::{Utf8Component, Utf8Prefix};
 use semver::VersionReq;
@@ -270,7 +272,7 @@ pub(crate) fn completion_items(
         );
     }
 
-    if let Some(limit) = config.completion(None).limit {
+    if let Some(limit) = config.completion(None, MiniCore::default()).limit {
         res.sort_by(|item1, item2| item1.sort_text.cmp(&item2.sort_text));
         res.truncate(limit);
     }
@@ -400,16 +402,17 @@ fn completion_item(
 
     set_score(&mut lsp_item, max_relevance, item.relevance);
 
-    let imports =
-        if config.completion(None).enable_imports_on_the_fly && !item.import_to_add.is_empty() {
-            item.import_to_add
-                .clone()
-                .into_iter()
-                .map(|import_path| lsp_ext::CompletionImport { full_import_path: import_path })
-                .collect()
-        } else {
-            Vec::new()
-        };
+    let imports = if config.completion(None, MiniCore::default()).enable_imports_on_the_fly
+        && !item.import_to_add.is_empty()
+    {
+        item.import_to_add
+            .clone()
+            .into_iter()
+            .map(|import_path| lsp_ext::CompletionImport { full_import_path: import_path })
+            .collect()
+    } else {
+        Vec::new()
+    };
     let (ref_resolve_data, resolve_data) = if something_to_resolve || !imports.is_empty() {
         let ref_resolve_data = if ref_match.is_some() {
             let ref_resolve_data = lsp_ext::CompletionResolveData {
@@ -493,8 +496,15 @@ pub(crate) fn signature_help(
                 .parameter_ranges()
                 .iter()
                 .map(|it| {
-                    let start = call_info.signature[..it.start().into()].chars().count() as u32;
-                    let end = call_info.signature[..it.end().into()].chars().count() as u32;
+                    let start = call_info.signature[..it.start().into()]
+                        .chars()
+                        .map(|c| c.len_utf16())
+                        .sum::() as u32;
+                    let end = start
+                        + call_info.signature[it.start().into()..it.end().into()]
+                            .chars()
+                            .map(|c| c.len_utf16())
+                            .sum::() as u32;
                     [start, end]
                 })
                 .map(|label_offsets| lsp_types::ParameterInformation {
@@ -513,9 +523,9 @@ pub(crate) fn signature_help(
                     label.push_str(", ");
                 }
                 first = false;
-                let start = label.chars().count() as u32;
+                let start = label.len() as u32;
                 label.push_str(param);
-                let end = label.chars().count() as u32;
+                let end = label.len() as u32;
                 params.push(lsp_types::ParameterInformation {
                     label: lsp_types::ParameterLabel::LabelOffsets([start, end]),
                     documentation: None,
@@ -837,6 +847,7 @@ fn semantic_token_type_and_modifiers(
             HlOperator::Bitwise => types::BITWISE,
             HlOperator::Arithmetic => types::ARITHMETIC,
             HlOperator::Logical => types::LOGICAL,
+            HlOperator::Negation => types::NEGATION,
             HlOperator::Comparison => types::COMPARISON,
             HlOperator::Other => types::OPERATOR,
         },
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs
index 3e80e8b7bdfb..c0947b2a291e 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs
@@ -847,6 +847,13 @@ impl GlobalState {
                 self.debounce_workspace_fetch();
                 let vfs = &mut self.vfs.write().0;
                 for (path, contents) in files {
+                    if matches!(path.name_and_extension(), Some(("minicore", Some("rs")))) {
+                        // Not a lot of bad can happen from mistakenly identifying `minicore`, so proceed with that.
+                        self.minicore.minicore_text = contents
+                            .as_ref()
+                            .and_then(|contents| String::from_utf8(contents.clone()).ok());
+                    }
+
                     let path = VfsPath::from(path);
                     // if the file is in mem docs, it's managed by the client via notifications
                     // so only set it if its not in there
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs
index ca15e6a98e03..1475f02447d2 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs
@@ -222,6 +222,16 @@ impl GlobalState {
                     message.push_str(err);
                     message.push_str("\n\n");
                 }
+                if let Some(err) = ws.sysroot.metadata_error() {
+                    status.health |= lsp_ext::Health::Warning;
+                    format_to!(
+                        message,
+                        "Failed to read Cargo metadata with dependencies for sysroot of `{}`: ",
+                        ws.manifest_or_root()
+                    );
+                    message.push_str(err);
+                    message.push_str("\n\n");
+                }
                 if let ProjectWorkspaceKind::Cargo { rustc: Err(Some(err)), .. } = &ws.kind {
                     status.health |= lsp_ext::Health::Warning;
                     format_to!(
diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs
index d60196d492fc..6c1dcf336ac5 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs
@@ -2,9 +2,9 @@
 
 #![allow(non_snake_case)]
 use crate::{
-    ast::{self, support, AstChildren, AstNode},
     SyntaxKind::{self, *},
     SyntaxNode, SyntaxToken, T,
+    ast::{self, AstChildren, AstNode, support},
 };
 use std::{fmt, hash};
 pub struct Abi {
@@ -2262,11 +2262,7 @@ impl AstNode for Abi {
     fn can_cast(kind: SyntaxKind) -> bool { kind == ABI }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -2298,11 +2294,7 @@ impl AstNode for ArgList {
     fn can_cast(kind: SyntaxKind) -> bool { kind == ARG_LIST }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -2334,11 +2326,7 @@ impl AstNode for ArrayExpr {
     fn can_cast(kind: SyntaxKind) -> bool { kind == ARRAY_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -2370,11 +2358,7 @@ impl AstNode for ArrayType {
     fn can_cast(kind: SyntaxKind) -> bool { kind == ARRAY_TYPE }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -2406,11 +2390,7 @@ impl AstNode for AsmClobberAbi {
     fn can_cast(kind: SyntaxKind) -> bool { kind == ASM_CLOBBER_ABI }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -2442,11 +2422,7 @@ impl AstNode for AsmConst {
     fn can_cast(kind: SyntaxKind) -> bool { kind == ASM_CONST }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -2478,11 +2454,7 @@ impl AstNode for AsmDirSpec {
     fn can_cast(kind: SyntaxKind) -> bool { kind == ASM_DIR_SPEC }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -2514,11 +2486,7 @@ impl AstNode for AsmExpr {
     fn can_cast(kind: SyntaxKind) -> bool { kind == ASM_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -2550,11 +2518,7 @@ impl AstNode for AsmLabel {
     fn can_cast(kind: SyntaxKind) -> bool { kind == ASM_LABEL }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -2586,11 +2550,7 @@ impl AstNode for AsmOperandExpr {
     fn can_cast(kind: SyntaxKind) -> bool { kind == ASM_OPERAND_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -2622,11 +2582,7 @@ impl AstNode for AsmOperandNamed {
     fn can_cast(kind: SyntaxKind) -> bool { kind == ASM_OPERAND_NAMED }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -2658,11 +2614,7 @@ impl AstNode for AsmOption {
     fn can_cast(kind: SyntaxKind) -> bool { kind == ASM_OPTION }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -2694,11 +2646,7 @@ impl AstNode for AsmOptions {
     fn can_cast(kind: SyntaxKind) -> bool { kind == ASM_OPTIONS }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -2730,11 +2678,7 @@ impl AstNode for AsmRegOperand {
     fn can_cast(kind: SyntaxKind) -> bool { kind == ASM_REG_OPERAND }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -2766,11 +2710,7 @@ impl AstNode for AsmRegSpec {
     fn can_cast(kind: SyntaxKind) -> bool { kind == ASM_REG_SPEC }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -2802,11 +2742,7 @@ impl AstNode for AsmSym {
     fn can_cast(kind: SyntaxKind) -> bool { kind == ASM_SYM }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -2838,11 +2774,7 @@ impl AstNode for AssocItemList {
     fn can_cast(kind: SyntaxKind) -> bool { kind == ASSOC_ITEM_LIST }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -2874,11 +2806,7 @@ impl AstNode for AssocTypeArg {
     fn can_cast(kind: SyntaxKind) -> bool { kind == ASSOC_TYPE_ARG }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -2910,11 +2838,7 @@ impl AstNode for Attr {
     fn can_cast(kind: SyntaxKind) -> bool { kind == ATTR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -2946,11 +2870,7 @@ impl AstNode for AwaitExpr {
     fn can_cast(kind: SyntaxKind) -> bool { kind == AWAIT_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -2982,11 +2902,7 @@ impl AstNode for BecomeExpr {
     fn can_cast(kind: SyntaxKind) -> bool { kind == BECOME_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -3018,11 +2934,7 @@ impl AstNode for BinExpr {
     fn can_cast(kind: SyntaxKind) -> bool { kind == BIN_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -3054,11 +2966,7 @@ impl AstNode for BlockExpr {
     fn can_cast(kind: SyntaxKind) -> bool { kind == BLOCK_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -3090,11 +2998,7 @@ impl AstNode for BoxPat {
     fn can_cast(kind: SyntaxKind) -> bool { kind == BOX_PAT }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -3126,11 +3030,7 @@ impl AstNode for BreakExpr {
     fn can_cast(kind: SyntaxKind) -> bool { kind == BREAK_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -3162,11 +3062,7 @@ impl AstNode for CallExpr {
     fn can_cast(kind: SyntaxKind) -> bool { kind == CALL_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -3198,11 +3094,7 @@ impl AstNode for CastExpr {
     fn can_cast(kind: SyntaxKind) -> bool { kind == CAST_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -3234,11 +3126,7 @@ impl AstNode for ClosureExpr {
     fn can_cast(kind: SyntaxKind) -> bool { kind == CLOSURE_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -3270,11 +3158,7 @@ impl AstNode for Const {
     fn can_cast(kind: SyntaxKind) -> bool { kind == CONST }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -3306,11 +3190,7 @@ impl AstNode for ConstArg {
     fn can_cast(kind: SyntaxKind) -> bool { kind == CONST_ARG }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -3342,11 +3222,7 @@ impl AstNode for ConstBlockPat {
     fn can_cast(kind: SyntaxKind) -> bool { kind == CONST_BLOCK_PAT }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -3378,11 +3254,7 @@ impl AstNode for ConstParam {
     fn can_cast(kind: SyntaxKind) -> bool { kind == CONST_PARAM }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -3414,11 +3286,7 @@ impl AstNode for ContinueExpr {
     fn can_cast(kind: SyntaxKind) -> bool { kind == CONTINUE_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -3450,11 +3318,7 @@ impl AstNode for DynTraitType {
     fn can_cast(kind: SyntaxKind) -> bool { kind == DYN_TRAIT_TYPE }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -3486,11 +3350,7 @@ impl AstNode for Enum {
     fn can_cast(kind: SyntaxKind) -> bool { kind == ENUM }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -3522,11 +3382,7 @@ impl AstNode for ExprStmt {
     fn can_cast(kind: SyntaxKind) -> bool { kind == EXPR_STMT }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -3558,11 +3414,7 @@ impl AstNode for ExternBlock {
     fn can_cast(kind: SyntaxKind) -> bool { kind == EXTERN_BLOCK }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -3594,11 +3446,7 @@ impl AstNode for ExternCrate {
     fn can_cast(kind: SyntaxKind) -> bool { kind == EXTERN_CRATE }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -3630,11 +3478,7 @@ impl AstNode for ExternItemList {
     fn can_cast(kind: SyntaxKind) -> bool { kind == EXTERN_ITEM_LIST }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -3666,11 +3510,7 @@ impl AstNode for FieldExpr {
     fn can_cast(kind: SyntaxKind) -> bool { kind == FIELD_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -3702,11 +3542,7 @@ impl AstNode for Fn {
     fn can_cast(kind: SyntaxKind) -> bool { kind == FN }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -3738,11 +3574,7 @@ impl AstNode for FnPtrType {
     fn can_cast(kind: SyntaxKind) -> bool { kind == FN_PTR_TYPE }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -3774,11 +3606,7 @@ impl AstNode for ForBinder {
     fn can_cast(kind: SyntaxKind) -> bool { kind == FOR_BINDER }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -3810,11 +3638,7 @@ impl AstNode for ForExpr {
     fn can_cast(kind: SyntaxKind) -> bool { kind == FOR_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -3846,11 +3670,7 @@ impl AstNode for ForType {
     fn can_cast(kind: SyntaxKind) -> bool { kind == FOR_TYPE }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -3882,11 +3702,7 @@ impl AstNode for FormatArgsArg {
     fn can_cast(kind: SyntaxKind) -> bool { kind == FORMAT_ARGS_ARG }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -3918,11 +3734,7 @@ impl AstNode for FormatArgsExpr {
     fn can_cast(kind: SyntaxKind) -> bool { kind == FORMAT_ARGS_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -3954,11 +3766,7 @@ impl AstNode for GenericArgList {
     fn can_cast(kind: SyntaxKind) -> bool { kind == GENERIC_ARG_LIST }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -3990,11 +3798,7 @@ impl AstNode for GenericParamList {
     fn can_cast(kind: SyntaxKind) -> bool { kind == GENERIC_PARAM_LIST }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -4026,11 +3830,7 @@ impl AstNode for IdentPat {
     fn can_cast(kind: SyntaxKind) -> bool { kind == IDENT_PAT }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -4062,11 +3862,7 @@ impl AstNode for IfExpr {
     fn can_cast(kind: SyntaxKind) -> bool { kind == IF_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -4098,11 +3894,7 @@ impl AstNode for Impl {
     fn can_cast(kind: SyntaxKind) -> bool { kind == IMPL }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -4134,11 +3926,7 @@ impl AstNode for ImplTraitType {
     fn can_cast(kind: SyntaxKind) -> bool { kind == IMPL_TRAIT_TYPE }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -4170,11 +3958,7 @@ impl AstNode for IndexExpr {
     fn can_cast(kind: SyntaxKind) -> bool { kind == INDEX_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -4206,11 +3990,7 @@ impl AstNode for InferType {
     fn can_cast(kind: SyntaxKind) -> bool { kind == INFER_TYPE }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -4242,11 +4022,7 @@ impl AstNode for ItemList {
     fn can_cast(kind: SyntaxKind) -> bool { kind == ITEM_LIST }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -4278,11 +4054,7 @@ impl AstNode for Label {
     fn can_cast(kind: SyntaxKind) -> bool { kind == LABEL }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -4314,11 +4086,7 @@ impl AstNode for LetElse {
     fn can_cast(kind: SyntaxKind) -> bool { kind == LET_ELSE }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -4350,11 +4118,7 @@ impl AstNode for LetExpr {
     fn can_cast(kind: SyntaxKind) -> bool { kind == LET_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -4386,11 +4150,7 @@ impl AstNode for LetStmt {
     fn can_cast(kind: SyntaxKind) -> bool { kind == LET_STMT }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -4422,11 +4182,7 @@ impl AstNode for Lifetime {
     fn can_cast(kind: SyntaxKind) -> bool { kind == LIFETIME }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -4458,11 +4214,7 @@ impl AstNode for LifetimeArg {
     fn can_cast(kind: SyntaxKind) -> bool { kind == LIFETIME_ARG }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -4494,11 +4246,7 @@ impl AstNode for LifetimeParam {
     fn can_cast(kind: SyntaxKind) -> bool { kind == LIFETIME_PARAM }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -4530,11 +4278,7 @@ impl AstNode for Literal {
     fn can_cast(kind: SyntaxKind) -> bool { kind == LITERAL }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -4566,11 +4310,7 @@ impl AstNode for LiteralPat {
     fn can_cast(kind: SyntaxKind) -> bool { kind == LITERAL_PAT }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -4602,11 +4342,7 @@ impl AstNode for LoopExpr {
     fn can_cast(kind: SyntaxKind) -> bool { kind == LOOP_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -4638,11 +4374,7 @@ impl AstNode for MacroCall {
     fn can_cast(kind: SyntaxKind) -> bool { kind == MACRO_CALL }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -4674,11 +4406,7 @@ impl AstNode for MacroDef {
     fn can_cast(kind: SyntaxKind) -> bool { kind == MACRO_DEF }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -4710,11 +4438,7 @@ impl AstNode for MacroExpr {
     fn can_cast(kind: SyntaxKind) -> bool { kind == MACRO_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -4746,11 +4470,7 @@ impl AstNode for MacroItems {
     fn can_cast(kind: SyntaxKind) -> bool { kind == MACRO_ITEMS }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -4782,11 +4502,7 @@ impl AstNode for MacroPat {
     fn can_cast(kind: SyntaxKind) -> bool { kind == MACRO_PAT }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -4818,11 +4534,7 @@ impl AstNode for MacroRules {
     fn can_cast(kind: SyntaxKind) -> bool { kind == MACRO_RULES }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -4854,11 +4566,7 @@ impl AstNode for MacroStmts {
     fn can_cast(kind: SyntaxKind) -> bool { kind == MACRO_STMTS }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -4890,11 +4598,7 @@ impl AstNode for MacroType {
     fn can_cast(kind: SyntaxKind) -> bool { kind == MACRO_TYPE }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -4926,11 +4630,7 @@ impl AstNode for MatchArm {
     fn can_cast(kind: SyntaxKind) -> bool { kind == MATCH_ARM }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -4962,11 +4662,7 @@ impl AstNode for MatchArmList {
     fn can_cast(kind: SyntaxKind) -> bool { kind == MATCH_ARM_LIST }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -4998,11 +4694,7 @@ impl AstNode for MatchExpr {
     fn can_cast(kind: SyntaxKind) -> bool { kind == MATCH_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -5034,11 +4726,7 @@ impl AstNode for MatchGuard {
     fn can_cast(kind: SyntaxKind) -> bool { kind == MATCH_GUARD }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -5070,11 +4758,7 @@ impl AstNode for Meta {
     fn can_cast(kind: SyntaxKind) -> bool { kind == META }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -5106,11 +4790,7 @@ impl AstNode for MethodCallExpr {
     fn can_cast(kind: SyntaxKind) -> bool { kind == METHOD_CALL_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -5142,11 +4822,7 @@ impl AstNode for Module {
     fn can_cast(kind: SyntaxKind) -> bool { kind == MODULE }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -5178,11 +4854,7 @@ impl AstNode for Name {
     fn can_cast(kind: SyntaxKind) -> bool { kind == NAME }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -5214,11 +4886,7 @@ impl AstNode for NameRef {
     fn can_cast(kind: SyntaxKind) -> bool { kind == NAME_REF }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -5250,11 +4918,7 @@ impl AstNode for NeverType {
     fn can_cast(kind: SyntaxKind) -> bool { kind == NEVER_TYPE }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -5286,11 +4950,7 @@ impl AstNode for OffsetOfExpr {
     fn can_cast(kind: SyntaxKind) -> bool { kind == OFFSET_OF_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -5322,11 +4982,7 @@ impl AstNode for OrPat {
     fn can_cast(kind: SyntaxKind) -> bool { kind == OR_PAT }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -5358,11 +5014,7 @@ impl AstNode for Param {
     fn can_cast(kind: SyntaxKind) -> bool { kind == PARAM }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -5394,11 +5046,7 @@ impl AstNode for ParamList {
     fn can_cast(kind: SyntaxKind) -> bool { kind == PARAM_LIST }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -5430,11 +5078,7 @@ impl AstNode for ParenExpr {
     fn can_cast(kind: SyntaxKind) -> bool { kind == PAREN_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -5466,11 +5110,7 @@ impl AstNode for ParenPat {
     fn can_cast(kind: SyntaxKind) -> bool { kind == PAREN_PAT }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -5502,11 +5142,7 @@ impl AstNode for ParenType {
     fn can_cast(kind: SyntaxKind) -> bool { kind == PAREN_TYPE }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -5538,11 +5174,7 @@ impl AstNode for ParenthesizedArgList {
     fn can_cast(kind: SyntaxKind) -> bool { kind == PARENTHESIZED_ARG_LIST }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -5574,11 +5206,7 @@ impl AstNode for Path {
     fn can_cast(kind: SyntaxKind) -> bool { kind == PATH }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -5610,11 +5238,7 @@ impl AstNode for PathExpr {
     fn can_cast(kind: SyntaxKind) -> bool { kind == PATH_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -5646,11 +5270,7 @@ impl AstNode for PathPat {
     fn can_cast(kind: SyntaxKind) -> bool { kind == PATH_PAT }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -5682,11 +5302,7 @@ impl AstNode for PathSegment {
     fn can_cast(kind: SyntaxKind) -> bool { kind == PATH_SEGMENT }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -5718,11 +5334,7 @@ impl AstNode for PathType {
     fn can_cast(kind: SyntaxKind) -> bool { kind == PATH_TYPE }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -5754,11 +5366,7 @@ impl AstNode for PrefixExpr {
     fn can_cast(kind: SyntaxKind) -> bool { kind == PREFIX_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -5790,11 +5398,7 @@ impl AstNode for PtrType {
     fn can_cast(kind: SyntaxKind) -> bool { kind == PTR_TYPE }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -5826,11 +5430,7 @@ impl AstNode for RangeExpr {
     fn can_cast(kind: SyntaxKind) -> bool { kind == RANGE_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -5862,11 +5462,7 @@ impl AstNode for RangePat {
     fn can_cast(kind: SyntaxKind) -> bool { kind == RANGE_PAT }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -5898,11 +5494,7 @@ impl AstNode for RecordExpr {
     fn can_cast(kind: SyntaxKind) -> bool { kind == RECORD_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -5934,11 +5526,7 @@ impl AstNode for RecordExprField {
     fn can_cast(kind: SyntaxKind) -> bool { kind == RECORD_EXPR_FIELD }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -5970,11 +5558,7 @@ impl AstNode for RecordExprFieldList {
     fn can_cast(kind: SyntaxKind) -> bool { kind == RECORD_EXPR_FIELD_LIST }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -6006,11 +5590,7 @@ impl AstNode for RecordField {
     fn can_cast(kind: SyntaxKind) -> bool { kind == RECORD_FIELD }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -6042,11 +5622,7 @@ impl AstNode for RecordFieldList {
     fn can_cast(kind: SyntaxKind) -> bool { kind == RECORD_FIELD_LIST }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -6078,11 +5654,7 @@ impl AstNode for RecordPat {
     fn can_cast(kind: SyntaxKind) -> bool { kind == RECORD_PAT }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -6114,11 +5686,7 @@ impl AstNode for RecordPatField {
     fn can_cast(kind: SyntaxKind) -> bool { kind == RECORD_PAT_FIELD }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -6150,11 +5718,7 @@ impl AstNode for RecordPatFieldList {
     fn can_cast(kind: SyntaxKind) -> bool { kind == RECORD_PAT_FIELD_LIST }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -6186,11 +5750,7 @@ impl AstNode for RefExpr {
     fn can_cast(kind: SyntaxKind) -> bool { kind == REF_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -6222,11 +5782,7 @@ impl AstNode for RefPat {
     fn can_cast(kind: SyntaxKind) -> bool { kind == REF_PAT }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -6258,11 +5814,7 @@ impl AstNode for RefType {
     fn can_cast(kind: SyntaxKind) -> bool { kind == REF_TYPE }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -6294,11 +5846,7 @@ impl AstNode for Rename {
     fn can_cast(kind: SyntaxKind) -> bool { kind == RENAME }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -6330,11 +5878,7 @@ impl AstNode for RestPat {
     fn can_cast(kind: SyntaxKind) -> bool { kind == REST_PAT }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -6366,11 +5910,7 @@ impl AstNode for RetType {
     fn can_cast(kind: SyntaxKind) -> bool { kind == RET_TYPE }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -6402,11 +5942,7 @@ impl AstNode for ReturnExpr {
     fn can_cast(kind: SyntaxKind) -> bool { kind == RETURN_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -6438,11 +5974,7 @@ impl AstNode for ReturnTypeSyntax {
     fn can_cast(kind: SyntaxKind) -> bool { kind == RETURN_TYPE_SYNTAX }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -6474,11 +6006,7 @@ impl AstNode for SelfParam {
     fn can_cast(kind: SyntaxKind) -> bool { kind == SELF_PARAM }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -6510,11 +6038,7 @@ impl AstNode for SlicePat {
     fn can_cast(kind: SyntaxKind) -> bool { kind == SLICE_PAT }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -6546,11 +6070,7 @@ impl AstNode for SliceType {
     fn can_cast(kind: SyntaxKind) -> bool { kind == SLICE_TYPE }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -6582,11 +6102,7 @@ impl AstNode for SourceFile {
     fn can_cast(kind: SyntaxKind) -> bool { kind == SOURCE_FILE }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -6618,11 +6134,7 @@ impl AstNode for Static {
     fn can_cast(kind: SyntaxKind) -> bool { kind == STATIC }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -6654,11 +6166,7 @@ impl AstNode for StmtList {
     fn can_cast(kind: SyntaxKind) -> bool { kind == STMT_LIST }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -6690,11 +6198,7 @@ impl AstNode for Struct {
     fn can_cast(kind: SyntaxKind) -> bool { kind == STRUCT }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -6726,11 +6230,7 @@ impl AstNode for TokenTree {
     fn can_cast(kind: SyntaxKind) -> bool { kind == TOKEN_TREE }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -6762,11 +6262,7 @@ impl AstNode for Trait {
     fn can_cast(kind: SyntaxKind) -> bool { kind == TRAIT }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -6798,11 +6294,7 @@ impl AstNode for TryExpr {
     fn can_cast(kind: SyntaxKind) -> bool { kind == TRY_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -6834,11 +6326,7 @@ impl AstNode for TupleExpr {
     fn can_cast(kind: SyntaxKind) -> bool { kind == TUPLE_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -6870,11 +6358,7 @@ impl AstNode for TupleField {
     fn can_cast(kind: SyntaxKind) -> bool { kind == TUPLE_FIELD }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -6906,11 +6390,7 @@ impl AstNode for TupleFieldList {
     fn can_cast(kind: SyntaxKind) -> bool { kind == TUPLE_FIELD_LIST }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -6942,11 +6422,7 @@ impl AstNode for TuplePat {
     fn can_cast(kind: SyntaxKind) -> bool { kind == TUPLE_PAT }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -6978,11 +6454,7 @@ impl AstNode for TupleStructPat {
     fn can_cast(kind: SyntaxKind) -> bool { kind == TUPLE_STRUCT_PAT }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -7014,11 +6486,7 @@ impl AstNode for TupleType {
     fn can_cast(kind: SyntaxKind) -> bool { kind == TUPLE_TYPE }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -7050,11 +6518,7 @@ impl AstNode for TypeAlias {
     fn can_cast(kind: SyntaxKind) -> bool { kind == TYPE_ALIAS }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -7086,11 +6550,7 @@ impl AstNode for TypeAnchor {
     fn can_cast(kind: SyntaxKind) -> bool { kind == TYPE_ANCHOR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -7122,11 +6582,7 @@ impl AstNode for TypeArg {
     fn can_cast(kind: SyntaxKind) -> bool { kind == TYPE_ARG }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -7158,11 +6614,7 @@ impl AstNode for TypeBound {
     fn can_cast(kind: SyntaxKind) -> bool { kind == TYPE_BOUND }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -7194,11 +6646,7 @@ impl AstNode for TypeBoundList {
     fn can_cast(kind: SyntaxKind) -> bool { kind == TYPE_BOUND_LIST }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -7230,11 +6678,7 @@ impl AstNode for TypeParam {
     fn can_cast(kind: SyntaxKind) -> bool { kind == TYPE_PARAM }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -7266,11 +6710,7 @@ impl AstNode for UnderscoreExpr {
     fn can_cast(kind: SyntaxKind) -> bool { kind == UNDERSCORE_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -7302,11 +6742,7 @@ impl AstNode for Union {
     fn can_cast(kind: SyntaxKind) -> bool { kind == UNION }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -7338,11 +6774,7 @@ impl AstNode for Use {
     fn can_cast(kind: SyntaxKind) -> bool { kind == USE }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -7374,11 +6806,7 @@ impl AstNode for UseBoundGenericArgs {
     fn can_cast(kind: SyntaxKind) -> bool { kind == USE_BOUND_GENERIC_ARGS }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -7410,11 +6838,7 @@ impl AstNode for UseTree {
     fn can_cast(kind: SyntaxKind) -> bool { kind == USE_TREE }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -7446,11 +6870,7 @@ impl AstNode for UseTreeList {
     fn can_cast(kind: SyntaxKind) -> bool { kind == USE_TREE_LIST }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -7482,11 +6902,7 @@ impl AstNode for Variant {
     fn can_cast(kind: SyntaxKind) -> bool { kind == VARIANT }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -7518,11 +6934,7 @@ impl AstNode for VariantList {
     fn can_cast(kind: SyntaxKind) -> bool { kind == VARIANT_LIST }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -7554,11 +6966,7 @@ impl AstNode for Visibility {
     fn can_cast(kind: SyntaxKind) -> bool { kind == VISIBILITY }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -7590,11 +6998,7 @@ impl AstNode for WhereClause {
     fn can_cast(kind: SyntaxKind) -> bool { kind == WHERE_CLAUSE }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -7626,11 +7030,7 @@ impl AstNode for WherePred {
     fn can_cast(kind: SyntaxKind) -> bool { kind == WHERE_PRED }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -7662,11 +7062,7 @@ impl AstNode for WhileExpr {
     fn can_cast(kind: SyntaxKind) -> bool { kind == WHILE_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -7698,11 +7094,7 @@ impl AstNode for WildcardPat {
     fn can_cast(kind: SyntaxKind) -> bool { kind == WILDCARD_PAT }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -7734,11 +7126,7 @@ impl AstNode for YeetExpr {
     fn can_cast(kind: SyntaxKind) -> bool { kind == YEET_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
@@ -7770,11 +7158,7 @@ impl AstNode for YieldExpr {
     fn can_cast(kind: SyntaxKind) -> bool { kind == YIELD_EXPR }
     #[inline]
     fn cast(syntax: SyntaxNode) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/generated/tokens.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/generated/tokens.rs
index b2f56c0b1dbf..3dca0db82630 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/ast/generated/tokens.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/ast/generated/tokens.rs
@@ -1,9 +1,9 @@
 //! Generated by `cargo xtask codegen grammar`, do not edit by hand.
 
 use crate::{
-    ast::AstToken,
     SyntaxKind::{self, *},
     SyntaxToken,
+    ast::AstToken,
 };
 use std::{fmt, hash};
 pub struct Byte {
@@ -17,11 +17,7 @@ impl std::fmt::Display for Byte {
 impl AstToken for Byte {
     fn can_cast(kind: SyntaxKind) -> bool { kind == BYTE }
     fn cast(syntax: SyntaxToken) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     fn syntax(&self) -> &SyntaxToken { &self.syntax }
 }
@@ -51,11 +47,7 @@ impl std::fmt::Display for ByteString {
 impl AstToken for ByteString {
     fn can_cast(kind: SyntaxKind) -> bool { kind == BYTE_STRING }
     fn cast(syntax: SyntaxToken) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     fn syntax(&self) -> &SyntaxToken { &self.syntax }
 }
@@ -85,11 +77,7 @@ impl std::fmt::Display for CString {
 impl AstToken for CString {
     fn can_cast(kind: SyntaxKind) -> bool { kind == C_STRING }
     fn cast(syntax: SyntaxToken) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     fn syntax(&self) -> &SyntaxToken { &self.syntax }
 }
@@ -119,11 +107,7 @@ impl std::fmt::Display for Char {
 impl AstToken for Char {
     fn can_cast(kind: SyntaxKind) -> bool { kind == CHAR }
     fn cast(syntax: SyntaxToken) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     fn syntax(&self) -> &SyntaxToken { &self.syntax }
 }
@@ -153,11 +137,7 @@ impl std::fmt::Display for Comment {
 impl AstToken for Comment {
     fn can_cast(kind: SyntaxKind) -> bool { kind == COMMENT }
     fn cast(syntax: SyntaxToken) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     fn syntax(&self) -> &SyntaxToken { &self.syntax }
 }
@@ -187,11 +167,7 @@ impl std::fmt::Display for FloatNumber {
 impl AstToken for FloatNumber {
     fn can_cast(kind: SyntaxKind) -> bool { kind == FLOAT_NUMBER }
     fn cast(syntax: SyntaxToken) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     fn syntax(&self) -> &SyntaxToken { &self.syntax }
 }
@@ -221,11 +197,7 @@ impl std::fmt::Display for Ident {
 impl AstToken for Ident {
     fn can_cast(kind: SyntaxKind) -> bool { kind == IDENT }
     fn cast(syntax: SyntaxToken) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     fn syntax(&self) -> &SyntaxToken { &self.syntax }
 }
@@ -255,11 +227,7 @@ impl std::fmt::Display for IntNumber {
 impl AstToken for IntNumber {
     fn can_cast(kind: SyntaxKind) -> bool { kind == INT_NUMBER }
     fn cast(syntax: SyntaxToken) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     fn syntax(&self) -> &SyntaxToken { &self.syntax }
 }
@@ -289,11 +257,7 @@ impl std::fmt::Display for String {
 impl AstToken for String {
     fn can_cast(kind: SyntaxKind) -> bool { kind == STRING }
     fn cast(syntax: SyntaxToken) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     fn syntax(&self) -> &SyntaxToken { &self.syntax }
 }
@@ -323,11 +287,7 @@ impl std::fmt::Display for Whitespace {
 impl AstToken for Whitespace {
     fn can_cast(kind: SyntaxKind) -> bool { kind == WHITESPACE }
     fn cast(syntax: SyntaxToken) -> Option {
-        if Self::can_cast(syntax.kind()) {
-            Some(Self { syntax })
-        } else {
-            None
-        }
+        if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
     }
     fn syntax(&self) -> &SyntaxToken { &self.syntax }
 }
diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/token_ext.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/token_ext.rs
index d9223e8216da..e1a9f3ac0341 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/ast/token_ext.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/ast/token_ext.rs
@@ -201,6 +201,10 @@ pub trait IsString: AstToken {
             None
         }
     }
+    fn map_offset_down(&self, offset: TextSize) -> Option {
+        let contents_range = self.text_range_between_quotes()?;
+        offset.checked_sub(contents_range.start())
+    }
 }
 
 impl IsString for ast::String {
diff --git a/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs b/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs
index a4549794db33..a718b96a8252 100644
--- a/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs
@@ -24,7 +24,7 @@ use paths::AbsPathBuf;
 use span::{Edition, FileId, Span};
 use stdx::itertools::Itertools;
 use test_utils::{
-    CURSOR_MARKER, ESCAPED_CURSOR_MARKER, Fixture, FixtureWithProjectMeta, RangeOrOffset,
+    CURSOR_MARKER, ESCAPED_CURSOR_MARKER, Fixture, FixtureWithProjectMeta, MiniCore, RangeOrOffset,
     extract_range_or_offset,
 };
 use triomphe::Arc;
@@ -69,7 +69,12 @@ pub trait WithFixture: Default + ExpandDatabase + SourceDatabase + 'static {
         proc_macros: Vec<(String, ProcMacro)>,
     ) -> Self {
         let mut db = Self::default();
-        let fixture = ChangeFixture::parse_with_proc_macros(&db, ra_fixture, proc_macros);
+        let fixture = ChangeFixture::parse_with_proc_macros(
+            &db,
+            ra_fixture,
+            MiniCore::RAW_SOURCE,
+            proc_macros,
+        );
         fixture.change.apply(&mut db);
         assert!(fixture.file_position.is_none());
         db
@@ -112,8 +117,10 @@ impl WithFixture for DB
 
 pub struct ChangeFixture {
     pub file_position: Option<(EditionedFileId, RangeOrOffset)>,
+    pub file_lines: Vec,
     pub files: Vec,
     pub change: ChangeWithProcMacros,
+    pub sysroot_files: Vec,
 }
 
 const SOURCE_ROOT_PREFIX: &str = "/";
@@ -123,12 +130,13 @@ impl ChangeFixture {
         db: &dyn salsa::Database,
         #[rust_analyzer::rust_fixture] ra_fixture: &str,
     ) -> ChangeFixture {
-        Self::parse_with_proc_macros(db, ra_fixture, Vec::new())
+        Self::parse_with_proc_macros(db, ra_fixture, MiniCore::RAW_SOURCE, Vec::new())
     }
 
     pub fn parse_with_proc_macros(
         db: &dyn salsa::Database,
         #[rust_analyzer::rust_fixture] ra_fixture: &str,
+        minicore_raw: &str,
         mut proc_macro_defs: Vec<(String, ProcMacro)>,
     ) -> ChangeFixture {
         let FixtureWithProjectMeta {
@@ -149,6 +157,8 @@ impl ChangeFixture {
         let mut source_change = FileChange::default();
 
         let mut files = Vec::new();
+        let mut sysroot_files = Vec::new();
+        let mut file_lines = Vec::new();
         let mut crate_graph = CrateGraphBuilder::default();
         let mut crates = FxIndexMap::default();
         let mut crate_deps = Vec::new();
@@ -173,6 +183,8 @@ impl ChangeFixture {
         let proc_macro_cwd = Arc::new(AbsPathBuf::assert_utf8(std::env::current_dir().unwrap()));
 
         for entry in fixture {
+            file_lines.push(entry.line);
+
             let mut range_or_offset = None;
             let text = if entry.text.contains(CURSOR_MARKER) {
                 if entry.text.contains(ESCAPED_CURSOR_MARKER) {
@@ -240,7 +252,7 @@ impl ChangeFixture {
                 assert!(default_crate_root.is_none());
                 default_crate_root = Some(file_id);
                 default_edition = meta.edition;
-                default_cfg.extend(meta.cfg.into_iter());
+                default_cfg.append(meta.cfg);
                 default_env.extend_from_other(&meta.env);
             }
 
@@ -259,7 +271,9 @@ impl ChangeFixture {
             fs.insert(core_file, VfsPath::new_virtual_path("/sysroot/core/lib.rs".to_owned()));
             roots.push(SourceRoot::new_library(fs));
 
-            source_change.change_file(core_file, Some(mini_core.source_code()));
+            sysroot_files.push(core_file);
+
+            source_change.change_file(core_file, Some(mini_core.source_code(minicore_raw)));
 
             let core_crate = crate_graph.add_crate_root(
                 core_file,
@@ -348,6 +362,8 @@ impl ChangeFixture {
             );
             roots.push(SourceRoot::new_library(fs));
 
+            sysroot_files.push(proc_lib_file);
+
             source_change.change_file(proc_lib_file, Some(source));
 
             let all_crates = crate_graph.iter().collect::>();
@@ -396,7 +412,7 @@ impl ChangeFixture {
         change.source_change.set_roots(roots);
         change.source_change.set_crate_graph(crate_graph);
 
-        ChangeFixture { file_position, files, change }
+        ChangeFixture { file_position, file_lines, files, change, sysroot_files }
     }
 }
 
diff --git a/src/tools/rust-analyzer/crates/test-utils/src/fixture.rs b/src/tools/rust-analyzer/crates/test-utils/src/fixture.rs
index c024089a016f..559894ee6205 100644
--- a/src/tools/rust-analyzer/crates/test-utils/src/fixture.rs
+++ b/src/tools/rust-analyzer/crates/test-utils/src/fixture.rs
@@ -132,13 +132,17 @@ pub struct Fixture {
     pub library: bool,
     /// Actual file contents. All meta comments are stripped.
     pub text: String,
+    /// The line number in the original fixture of the beginning of this fixture.
+    pub line: usize,
 }
 
+#[derive(Debug)]
 pub struct MiniCore {
     activated_flags: Vec,
     valid_flags: Vec,
 }
 
+#[derive(Debug)]
 pub struct FixtureWithProjectMeta {
     pub fixture: Vec,
     pub mini_core: Option,
@@ -184,40 +188,49 @@ impl FixtureWithProjectMeta {
         let mut mini_core = None;
         let mut res: Vec = Vec::new();
         let mut proc_macro_names = vec![];
+        let mut first_row = 0;
 
         if let Some(meta) = fixture.strip_prefix("//- toolchain:") {
+            first_row += 1;
             let (meta, remain) = meta.split_once('\n').unwrap();
             toolchain = Some(meta.trim().to_owned());
             fixture = remain;
         }
 
         if let Some(meta) = fixture.strip_prefix("//- target_data_layout:") {
+            first_row += 1;
             let (meta, remain) = meta.split_once('\n').unwrap();
             meta.trim().clone_into(&mut target_data_layout);
             fixture = remain;
         }
 
         if let Some(meta) = fixture.strip_prefix("//- target_arch:") {
+            first_row += 1;
             let (meta, remain) = meta.split_once('\n').unwrap();
             meta.trim().clone_into(&mut target_arch);
             fixture = remain;
         }
 
         if let Some(meta) = fixture.strip_prefix("//- proc_macros:") {
+            first_row += 1;
             let (meta, remain) = meta.split_once('\n').unwrap();
             proc_macro_names = meta.split(',').map(|it| it.trim().to_owned()).collect();
             fixture = remain;
         }
 
         if let Some(meta) = fixture.strip_prefix("//- minicore:") {
+            first_row += 1;
             let (meta, remain) = meta.split_once('\n').unwrap();
             mini_core = Some(MiniCore::parse(meta));
             fixture = remain;
         }
 
-        let default = if fixture.contains("//-") { None } else { Some("//- /main.rs") };
+        let default =
+            if fixture.contains("//- /") { None } else { Some((first_row - 1, "//- /main.rs")) };
 
-        for (ix, line) in default.into_iter().chain(fixture.split_inclusive('\n')).enumerate() {
+        for (ix, line) in
+            default.into_iter().chain((first_row..).zip(fixture.split_inclusive('\n')))
+        {
             if line.contains("//-") {
                 assert!(
                     line.starts_with("//-"),
@@ -228,7 +241,7 @@ impl FixtureWithProjectMeta {
             }
 
             if let Some(line) = line.strip_prefix("//-") {
-                let meta = Self::parse_meta_line(line);
+                let meta = Self::parse_meta_line(line, (ix + 1).try_into().unwrap());
                 res.push(meta);
             } else {
                 if matches!(line.strip_prefix("// "), Some(l) if l.trim().starts_with('/')) {
@@ -252,7 +265,7 @@ impl FixtureWithProjectMeta {
     }
 
     //- /lib.rs crate:foo deps:bar,baz cfg:foo=a,bar=b env:OUTDIR=path/to,OTHER=foo
-    fn parse_meta_line(meta: &str) -> Fixture {
+    fn parse_meta_line(meta: &str, line: usize) -> Fixture {
         let meta = meta.trim();
         let mut components = meta.split_ascii_whitespace();
 
@@ -317,6 +330,7 @@ impl FixtureWithProjectMeta {
         Fixture {
             path,
             text: String::new(),
+            line,
             krate,
             deps,
             extern_prelude,
@@ -330,7 +344,7 @@ impl FixtureWithProjectMeta {
 }
 
 impl MiniCore {
-    const RAW_SOURCE: &'static str = include_str!("./minicore.rs");
+    pub const RAW_SOURCE: &'static str = include_str!("./minicore.rs");
 
     fn has_flag(&self, flag: &str) -> bool {
         self.activated_flags.iter().any(|it| it == flag)
@@ -363,8 +377,8 @@ impl MiniCore {
         res
     }
 
-    pub fn available_flags() -> impl Iterator {
-        let lines = MiniCore::RAW_SOURCE.split_inclusive('\n');
+    pub fn available_flags(raw_source: &str) -> impl Iterator {
+        let lines = raw_source.split_inclusive('\n');
         lines
             .map_while(|x| x.strip_prefix("//!"))
             .skip_while(|line| !line.contains("Available flags:"))
@@ -375,9 +389,9 @@ impl MiniCore {
     /// Strips parts of minicore.rs which are flagged by inactive flags.
     ///
     /// This is probably over-engineered to support flags dependencies.
-    pub fn source_code(mut self) -> String {
+    pub fn source_code(mut self, raw_source: &str) -> String {
         let mut buf = String::new();
-        let mut lines = MiniCore::RAW_SOURCE.split_inclusive('\n');
+        let mut lines = raw_source.split_inclusive('\n');
 
         let mut implications = Vec::new();
 
diff --git a/src/tools/rust-analyzer/crates/vfs/src/path_interner.rs b/src/tools/rust-analyzer/crates/vfs/src/path_interner.rs
index 64f51976053d..225bfc7218b4 100644
--- a/src/tools/rust-analyzer/crates/vfs/src/path_interner.rs
+++ b/src/tools/rust-analyzer/crates/vfs/src/path_interner.rs
@@ -28,7 +28,7 @@ impl PathInterner {
     /// - Else, returns a newly allocated id.
     pub(crate) fn intern(&mut self, path: VfsPath) -> FileId {
         let (id, _added) = self.map.insert_full(path);
-        assert!(id < u32::MAX as usize);
+        assert!(id < FileId::MAX as usize);
         FileId(id as u32)
     }
 
diff --git a/src/tools/rust-analyzer/editors/code/package-lock.json b/src/tools/rust-analyzer/editors/code/package-lock.json
index e35a159cbc3f..6dd448522379 100644
--- a/src/tools/rust-analyzer/editors/code/package-lock.json
+++ b/src/tools/rust-analyzer/editors/code/package-lock.json
@@ -21,6 +21,7 @@
                 "@stylistic/eslint-plugin": "^4.1.0",
                 "@stylistic/eslint-plugin-js": "^4.1.0",
                 "@tsconfig/strictest": "^2.0.5",
+                "@types/lodash": "^4.17.20",
                 "@types/node": "~22.13.4",
                 "@types/vscode": "~1.93.0",
                 "@typescript-eslint/eslint-plugin": "^8.25.0",
@@ -1388,6 +1389,13 @@
             "dev": true,
             "license": "MIT"
         },
+        "node_modules/@types/lodash": {
+            "version": "4.17.20",
+            "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.20.tgz",
+            "integrity": "sha512-H3MHACvFUEiujabxhaI/ImO6gUrd8oOurg7LQtS7mbwIXA/cUqWrvBsaeJ23aZEPk1TAYkurjfMbSELfoCXlGA==",
+            "dev": true,
+            "license": "MIT"
+        },
         "node_modules/@types/node": {
             "version": "22.13.5",
             "resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.5.tgz",
diff --git a/src/tools/rust-analyzer/editors/code/package.json b/src/tools/rust-analyzer/editors/code/package.json
index 70687238c854..d659421a0299 100644
--- a/src/tools/rust-analyzer/editors/code/package.json
+++ b/src/tools/rust-analyzer/editors/code/package.json
@@ -58,6 +58,7 @@
         "@stylistic/eslint-plugin": "^4.1.0",
         "@stylistic/eslint-plugin-js": "^4.1.0",
         "@tsconfig/strictest": "^2.0.5",
+        "@types/lodash": "^4.17.20",
         "@types/node": "~22.13.4",
         "@types/vscode": "~1.93.0",
         "@typescript-eslint/eslint-plugin": "^8.25.0",
diff --git a/src/tools/rust-analyzer/editors/code/src/client.ts b/src/tools/rust-analyzer/editors/code/src/client.ts
index 073ff2f4703f..cb71a01138b3 100644
--- a/src/tools/rust-analyzer/editors/code/src/client.ts
+++ b/src/tools/rust-analyzer/editors/code/src/client.ts
@@ -13,7 +13,7 @@ import { RaLanguageClient } from "./lang_client";
 export async function createClient(
     traceOutputChannel: vscode.OutputChannel,
     outputChannel: vscode.OutputChannel,
-    initializationOptions: vscode.WorkspaceConfiguration,
+    initializationOptions: lc.LanguageClientOptions["initializationOptions"],
     serverOptions: lc.ServerOptions,
     config: Config,
     unlinkedFiles: vscode.Uri[],
diff --git a/src/tools/rust-analyzer/editors/code/src/config.ts b/src/tools/rust-analyzer/editors/code/src/config.ts
index 3b1b0768d3cf..5dc2c419efa8 100644
--- a/src/tools/rust-analyzer/editors/code/src/config.ts
+++ b/src/tools/rust-analyzer/editors/code/src/config.ts
@@ -4,7 +4,7 @@ import * as path from "path";
 import * as vscode from "vscode";
 import { expectNotUndefined, log, normalizeDriveLetter, unwrapUndefinable } from "./util";
 import type { Env } from "./util";
-import type { Disposable } from "vscode";
+import { cloneDeep, get, pickBy, set } from "lodash";
 
 export type RunnableEnvCfgItem = {
     mask?: string;
@@ -12,13 +12,25 @@ export type RunnableEnvCfgItem = {
     platform?: string | string[];
 };
 
+export type ConfigurationTree = { [key: string]: ConfigurationValue };
+export type ConfigurationValue =
+    | undefined
+    | null
+    | boolean
+    | number
+    | string
+    | ConfigurationValue[]
+    | ConfigurationTree;
+
 type ShowStatusBar = "always" | "never" | { documentSelector: vscode.DocumentSelector };
 
 export class Config {
     readonly extensionId = "rust-lang.rust-analyzer";
-    configureLang: vscode.Disposable | undefined;
 
-    readonly rootSection = "rust-analyzer";
+    configureLang: vscode.Disposable | undefined;
+    workspaceState: vscode.Memento;
+
+    private readonly rootSection = "rust-analyzer";
     private readonly requiresServerReloadOpts = ["server", "files", "showSyntaxTree"].map(
         (opt) => `${this.rootSection}.${opt}`,
     );
@@ -27,8 +39,13 @@ export class Config {
         (opt) => `${this.rootSection}.${opt}`,
     );
 
-    constructor(disposables: Disposable[]) {
-        vscode.workspace.onDidChangeConfiguration(this.onDidChangeConfiguration, this, disposables);
+    constructor(ctx: vscode.ExtensionContext) {
+        this.workspaceState = ctx.workspaceState;
+        vscode.workspace.onDidChangeConfiguration(
+            this.onDidChangeConfiguration,
+            this,
+            ctx.subscriptions,
+        );
         this.refreshLogging();
         this.configureLanguage();
     }
@@ -37,6 +54,44 @@ export class Config {
         this.configureLang?.dispose();
     }
 
+    private readonly extensionConfigurationStateKey = "extensionConfigurations";
+
+    /// Returns the rust-analyzer-specific workspace configuration, incl. any
+    /// configuration items overridden by (present) extensions.
+    get extensionConfigurations(): Record> {
+        return pickBy(
+            this.workspaceState.get>(
+                "extensionConfigurations",
+                {},
+            ),
+            // ignore configurations from disabled/removed extensions
+            (_, extensionId) => vscode.extensions.getExtension(extensionId) !== undefined,
+        );
+    }
+
+    async addExtensionConfiguration(
+        extensionId: string,
+        configuration: Record,
+    ): Promise {
+        const oldConfiguration = this.cfg;
+
+        const extCfgs = this.extensionConfigurations;
+        extCfgs[extensionId] = configuration;
+        await this.workspaceState.update(this.extensionConfigurationStateKey, extCfgs);
+
+        const newConfiguration = this.cfg;
+        const prefix = `${this.rootSection}.`;
+        await this.onDidChangeConfiguration({
+            affectsConfiguration(section: string, _scope?: vscode.ConfigurationScope): boolean {
+                return (
+                    section.startsWith(prefix) &&
+                    get(oldConfiguration, section.slice(prefix.length)) !==
+                        get(newConfiguration, section.slice(prefix.length))
+                );
+            },
+        });
+    }
+
     private refreshLogging() {
         log.info(
             "Extension version:",
@@ -176,10 +231,36 @@ export class Config {
     // We don't do runtime config validation here for simplicity. More on stackoverflow:
     // https://stackoverflow.com/questions/60135780/what-is-the-best-way-to-type-check-the-configuration-for-vscode-extension
 
-    private get cfg(): vscode.WorkspaceConfiguration {
+    // Returns the raw configuration for rust-analyzer as returned by vscode. This
+    // should only be used when modifications to the user/workspace configuration
+    // are required.
+    private get rawCfg(): vscode.WorkspaceConfiguration {
         return vscode.workspace.getConfiguration(this.rootSection);
     }
 
+    // Returns the final configuration to use, with extension configuration overrides merged in.
+    public get cfg(): ConfigurationTree {
+        const finalConfig = cloneDeep(this.rawCfg);
+        for (const [extensionId, items] of Object.entries(this.extensionConfigurations)) {
+            for (const [k, v] of Object.entries(items)) {
+                const i = this.rawCfg.inspect(k);
+                if (
+                    i?.workspaceValue !== undefined ||
+                    i?.workspaceFolderValue !== undefined ||
+                    i?.globalValue !== undefined
+                ) {
+                    log.trace(
+                        `Ignoring configuration override for ${k} from extension ${extensionId}`,
+                    );
+                    continue;
+                }
+                log.trace(`Extension ${extensionId} overrides configuration ${k} to `, v);
+                set(finalConfig, k, v);
+            }
+        }
+        return finalConfig;
+    }
+
     /**
      * Beware that postfix `!` operator erases both `null` and `undefined`.
      * This is why the following doesn't work as expected:
@@ -187,7 +268,6 @@ export class Config {
      * ```ts
      * const nullableNum = vscode
      *  .workspace
-     *  .getConfiguration
      *  .getConfiguration("rust-analyzer")
      *  .get(path)!;
      *
@@ -197,7 +277,7 @@ export class Config {
      * So this getter handles this quirk by not requiring the caller to use postfix `!`
      */
     private get(path: string): T | undefined {
-        return prepareVSCodeConfig(this.cfg.get(path));
+        return prepareVSCodeConfig(get(this.cfg, path)) as T;
     }
 
     get serverPath() {
@@ -223,7 +303,7 @@ export class Config {
     }
 
     async toggleCheckOnSave() {
-        const config = this.cfg.inspect("checkOnSave") ?? { key: "checkOnSave" };
+        const config = this.rawCfg.inspect("checkOnSave") ?? { key: "checkOnSave" };
         let overrideInLanguage;
         let target;
         let value;
@@ -249,7 +329,12 @@ export class Config {
             overrideInLanguage = config.defaultLanguageValue;
             value = config.defaultValue || config.defaultLanguageValue;
         }
-        await this.cfg.update("checkOnSave", !(value || false), target || null, overrideInLanguage);
+        await this.rawCfg.update(
+            "checkOnSave",
+            !(value || false),
+            target || null,
+            overrideInLanguage,
+        );
     }
 
     get problemMatcher(): string[] {
@@ -367,26 +452,24 @@ export class Config {
     }
 
     async setAskBeforeUpdateTest(value: boolean) {
-        await this.cfg.update("runnables.askBeforeUpdateTest", value, true);
+        await this.rawCfg.update("runnables.askBeforeUpdateTest", value, true);
     }
 }
 
-export function prepareVSCodeConfig(resp: T): T {
+export function prepareVSCodeConfig(resp: ConfigurationValue): ConfigurationValue {
     if (Is.string(resp)) {
-        return substituteVSCodeVariableInString(resp) as T;
-        // eslint-disable-next-line @typescript-eslint/no-explicit-any
-    } else if (resp && Is.array(resp)) {
+        return substituteVSCodeVariableInString(resp);
+    } else if (resp && Is.array(resp)) {
         return resp.map((val) => {
             return prepareVSCodeConfig(val);
-        }) as T;
+        });
     } else if (resp && typeof resp === "object") {
-        // eslint-disable-next-line @typescript-eslint/no-explicit-any
-        const res: { [key: string]: any } = {};
+        const res: ConfigurationTree = {};
         for (const key in resp) {
             const val = resp[key];
             res[key] = prepareVSCodeConfig(val);
         }
-        return res as T;
+        return res;
     }
     return resp;
 }
diff --git a/src/tools/rust-analyzer/editors/code/src/ctx.ts b/src/tools/rust-analyzer/editors/code/src/ctx.ts
index e55754fb9f04..a7b7be03b5d8 100644
--- a/src/tools/rust-analyzer/editors/code/src/ctx.ts
+++ b/src/tools/rust-analyzer/editors/code/src/ctx.ts
@@ -125,7 +125,7 @@ export class Ctx implements RustAnalyzerExtensionApi {
         extCtx.subscriptions.push(this);
         this.version = extCtx.extension.packageJSON.version ?? "";
         this._serverVersion = "";
-        this.config = new Config(extCtx.subscriptions);
+        this.config = new Config(extCtx);
         this.statusBar = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left);
         this.updateStatusBarVisibility(vscode.window.activeTextEditor);
         this.statusBarActiveEditorListener = vscode.window.onDidChangeActiveTextEditor((editor) =>
@@ -150,6 +150,13 @@ export class Ctx implements RustAnalyzerExtensionApi {
         });
     }
 
+    async addConfiguration(
+        extensionId: string,
+        configuration: Record,
+    ): Promise {
+        await this.config.addExtensionConfiguration(extensionId, configuration);
+    }
+
     dispose() {
         this.config.dispose();
         this.statusBar.dispose();
@@ -230,7 +237,7 @@ export class Ctx implements RustAnalyzerExtensionApi {
                 debug: run,
             };
 
-            let rawInitializationOptions = vscode.workspace.getConfiguration("rust-analyzer");
+            let rawInitializationOptions = this.config.cfg;
 
             if (this.workspace.kind === "Detached Files") {
                 rawInitializationOptions = {
diff --git a/src/tools/rust-analyzer/editors/code/src/main.ts b/src/tools/rust-analyzer/editors/code/src/main.ts
index 996298524f11..190f5866d0ea 100644
--- a/src/tools/rust-analyzer/editors/code/src/main.ts
+++ b/src/tools/rust-analyzer/editors/code/src/main.ts
@@ -13,6 +13,12 @@ const RUST_PROJECT_CONTEXT_NAME = "inRustProject";
 export interface RustAnalyzerExtensionApi {
     // FIXME: this should be non-optional
     readonly client?: lc.LanguageClient;
+
+    // Allows adding a configuration override from another extension.
+    // `extensionId` is used to only merge configuration override from present
+    // extensions. `configuration` is map of rust-analyzer-specific setting
+    // overrides, e.g., `{"cargo.cfgs": ["foo", "bar"]}`.
+    addConfiguration(extensionId: string, configuration: Record): Promise;
 }
 
 export async function deactivate() {
diff --git a/src/tools/rust-analyzer/rustfmt.toml b/src/tools/rust-analyzer/rustfmt.toml
index 20bf59547b86..3ee7fdabdc21 100644
--- a/src/tools/rust-analyzer/rustfmt.toml
+++ b/src/tools/rust-analyzer/rustfmt.toml
@@ -1,2 +1,3 @@
+edition = "2024"
 reorder_modules = true
 use_small_heuristics = "Max"
diff --git a/src/tools/rust-analyzer/xtask/src/flags.rs b/src/tools/rust-analyzer/xtask/src/flags.rs
index 72f6215d4c3f..8f70a1861893 100644
--- a/src/tools/rust-analyzer/xtask/src/flags.rs
+++ b/src/tools/rust-analyzer/xtask/src/flags.rs
@@ -49,6 +49,9 @@ xflags::xflags! {
             /// build in release with debug info set to 2.
             optional --dev-rel
 
+            /// Make `never!()`, `always!()` etc. panic instead of just logging an error.
+            optional --force-always-assert
+
             /// Apply PGO optimizations
             optional --pgo pgo: PgoTrainingCrate
         }
@@ -124,6 +127,7 @@ pub struct Install {
     pub jemalloc: bool,
     pub proc_macro_server: bool,
     pub dev_rel: bool,
+    pub force_always_assert: bool,
     pub pgo: Option,
 }
 
@@ -300,7 +304,12 @@ impl Install {
         } else {
             Malloc::System
         };
-        Some(ServerOpt { malloc, dev_rel: self.dev_rel, pgo: self.pgo.clone() })
+        Some(ServerOpt {
+            malloc,
+            dev_rel: self.dev_rel,
+            pgo: self.pgo.clone(),
+            force_always_assert: self.force_always_assert,
+        })
     }
     pub(crate) fn proc_macro_server(&self) -> Option {
         if !self.proc_macro_server {
diff --git a/src/tools/rust-analyzer/xtask/src/install.rs b/src/tools/rust-analyzer/xtask/src/install.rs
index b794f53e761e..975e361ba50b 100644
--- a/src/tools/rust-analyzer/xtask/src/install.rs
+++ b/src/tools/rust-analyzer/xtask/src/install.rs
@@ -39,6 +39,18 @@ pub(crate) struct ServerOpt {
     pub(crate) malloc: Malloc,
     pub(crate) dev_rel: bool,
     pub(crate) pgo: Option,
+    pub(crate) force_always_assert: bool,
+}
+
+impl ServerOpt {
+    fn to_features(&self) -> Vec<&'static str> {
+        let mut features = Vec::new();
+        features.extend(self.malloc.to_features());
+        if self.force_always_assert {
+            features.extend(["--features", "force-always-assert"]);
+        }
+        features
+    }
 }
 
 pub(crate) struct ProcMacroServerOpt {
@@ -136,7 +148,7 @@ fn install_client(sh: &Shell, client_opt: ClientOpt) -> anyhow::Result<()> {
 }
 
 fn install_server(sh: &Shell, opts: ServerOpt) -> anyhow::Result<()> {
-    let features = opts.malloc.to_features();
+    let features = &opts.to_features();
     let profile = if opts.dev_rel { "dev-rel" } else { "release" };
 
     let mut install_cmd = cmd!(
@@ -148,7 +160,7 @@ fn install_server(sh: &Shell, opts: ServerOpt) -> anyhow::Result<()> {
         let target = detect_target(sh);
         let build_cmd = cmd!(
             sh,
-            "cargo build --manifest-path ./crates/rust-analyzer/Cargo.toml --bin rust-analyzer --target {target} --profile={profile} --locked --features force-always-assert {features...}"
+            "cargo build --manifest-path ./crates/rust-analyzer/Cargo.toml --bin rust-analyzer --target {target} --profile={profile} --locked {features...}"
         );
 
         let profile = crate::pgo::gather_pgo_profile(sh, build_cmd, &target, train_crate)?;
diff --git a/src/tools/rust-analyzer/xtask/src/release.rs b/src/tools/rust-analyzer/xtask/src/release.rs
index d06a25c8929b..13cb44ebed5a 100644
--- a/src/tools/rust-analyzer/xtask/src/release.rs
+++ b/src/tools/rust-analyzer/xtask/src/release.rs
@@ -43,7 +43,7 @@ impl flags::Release {
             .unwrap_or_default();
 
         let tags = cmd!(sh, "git tag --list").read()?;
-        let prev_tag = tags.lines().filter(|line| is_release_tag(line)).next_back().unwrap();
+        let prev_tag = tags.lines().rfind(|line| is_release_tag(line)).unwrap();
 
         let contents = changelog::get_changelog(sh, changelog_n, &commit, prev_tag, &today)?;
         let path = changelog_dir.join(format!("{today}-changelog-{changelog_n}.adoc"));
diff --git a/src/tools/rust-analyzer/xtask/src/tidy.rs b/src/tools/rust-analyzer/xtask/src/tidy.rs
index 0462835f0675..40997eb93d35 100644
--- a/src/tools/rust-analyzer/xtask/src/tidy.rs
+++ b/src/tools/rust-analyzer/xtask/src/tidy.rs
@@ -259,7 +259,7 @@ impl TidyDocs {
         }
 
         fn is_exclude_file(d: &Path) -> bool {
-            let file_names = ["tests.rs", "famous_defs_fixture.rs"];
+            let file_names = ["tests.rs", "famous_defs_fixture.rs", "frontmatter.rs"];
 
             d.file_name()
                 .unwrap_or_default()
diff --git a/src/tools/rustdoc-js/tester.js b/src/tools/rustdoc-js/tester.js
index ff809d58e907..124839efdd02 100644
--- a/src/tools/rustdoc-js/tester.js
+++ b/src/tools/rustdoc-js/tester.js
@@ -364,10 +364,10 @@ function hasCheck(content, checkName) {
     return content.startsWith(`const ${checkName}`) || content.includes(`\nconst ${checkName}`);
 }
 
-async function runChecks(testFile, doSearch, parseQuery) {
+async function runChecks(testFile, doSearch, parseQuery, revision) {
     let checkExpected = false;
     let checkParsed = false;
-    let testFileContent = readFile(testFile);
+    let testFileContent = `const REVISION = "${revision}";\n${readFile(testFile)}`;
 
     if (testFileContent.indexOf("FILTER_CRATE") !== -1) {
         testFileContent += "exports.FILTER_CRATE = FILTER_CRATE;";
@@ -548,6 +548,7 @@ function parseOptions(args) {
         "doc_folder": "",
         "test_folder": "",
         "test_file": [],
+        "revision": "",
     };
     const correspondences = {
         "--resource-suffix": "resource_suffix",
@@ -555,6 +556,7 @@ function parseOptions(args) {
         "--test-folder": "test_folder",
         "--test-file": "test_file",
         "--crate-name": "crate_name",
+        "--revision": "revision",
     };
 
     for (let i = 0; i < args.length; ++i) {
@@ -611,7 +613,7 @@ async function main(argv) {
     if (opts["test_file"].length !== 0) {
         for (const file of opts["test_file"]) {
             process.stdout.write(`Testing ${file} ... `);
-            errors += await runChecks(file, doSearch, parseAndSearch.parseQuery);
+            errors += await runChecks(file, doSearch, parseAndSearch.parseQuery, opts.revision);
         }
     } else if (opts["test_folder"].length !== 0) {
         for (const file of fs.readdirSync(opts["test_folder"])) {
@@ -619,7 +621,7 @@ async function main(argv) {
                 continue;
             }
             process.stdout.write(`Testing ${file} ... `);
-            errors += await runChecks(path.join(opts["test_folder"], file), doSearch,
+            errors += await runChecks(path.join(opts["test_folder"], file, ""), doSearch,
                     parseAndSearch.parseQuery);
         }
     }
diff --git a/src/version b/src/version
index 7f229af96476..95784efddbc4 100644
--- a/src/version
+++ b/src/version
@@ -1 +1 @@
-1.92.0
+1.93.0
diff --git a/tests/codegen-llvm/addr-of-mutate.rs b/tests/codegen-llvm/addr-of-mutate.rs
index 36d6bf555d15..d59d85af62a9 100644
--- a/tests/codegen-llvm/addr-of-mutate.rs
+++ b/tests/codegen-llvm/addr-of-mutate.rs
@@ -24,7 +24,7 @@ pub unsafe fn second(a_ptr_and_b: (*mut (i32, bool), (i64, bool))) -> bool {
 }
 
 // If going through a deref (and there are no other mutating accesses), then `readonly` is fine.
-// CHECK: i1 @third(ptr{{( dead_on_return)?}} noalias noundef readonly align {{[0-9]+}}{{( captures\(address\))?}} dereferenceable({{[0-9]+}}) %a_ptr_and_b)
+// CHECK: i1 @third(ptr{{( dead_on_return)?}} noalias noundef readonly align {{[0-9]+}}{{( captures\(none\))?}} dereferenceable({{[0-9]+}}) %a_ptr_and_b)
 #[no_mangle]
 pub unsafe fn third(a_ptr_and_b: (*mut (i32, bool), (i64, bool))) -> bool {
     let b_bool_ptr = core::ptr::addr_of!((*a_ptr_and_b.0).1).cast_mut();
diff --git a/tests/codegen-llvm/deduced-param-attrs.rs b/tests/codegen-llvm/deduced-param-attrs.rs
index f99615cbe6d4..eec15a434645 100644
--- a/tests/codegen-llvm/deduced-param-attrs.rs
+++ b/tests/codegen-llvm/deduced-param-attrs.rs
@@ -1,81 +1,180 @@
 //@ compile-flags: -Copt-level=3 -Cno-prepopulate-passes
-
+//@ compile-flags: -Cpanic=abort -Csymbol-mangling-version=v0
+//@ revisions: LLVM21 LLVM20
+//@ [LLVM21] min-llvm-version: 21
+//@ [LLVM20] max-llvm-major-version: 20
+#![feature(custom_mir, core_intrinsics, unboxed_closures)]
 #![crate_type = "lib"]
-#![allow(internal_features)]
-#![feature(unsized_fn_params)]
-
+extern crate core;
+use core::intrinsics::mir::*;
 use std::cell::Cell;
-use std::hint;
+use std::hint::black_box;
+use std::mem::ManuallyDrop;
 
-// Check to make sure that we can deduce the `readonly` attribute from function bodies for
-// parameters passed indirectly.
-
-pub struct BigStruct {
-    blah: [i32; 1024],
+pub struct Big {
+    pub blah: [i32; 1024],
 }
 
-pub struct BigCellContainer {
-    blah: [Cell; 1024],
+pub struct BigCell {
+    pub blah: [Cell; 1024],
 }
 
-// The by-value parameter for this big struct can be marked readonly.
-//
-// CHECK: @use_big_struct_immutably({{.*}} readonly {{.*}} %big_struct)
-#[no_mangle]
-pub fn use_big_struct_immutably(big_struct: BigStruct) {
-    hint::black_box(&big_struct);
+pub struct BigDrop {
+    pub blah: [u8; 1024],
 }
 
-// The by-value parameter for this big struct can't be marked readonly, because we mutate it.
-//
-// CHECK: @use_big_struct_mutably(
+impl Drop for BigDrop {
+    #[inline(never)]
+    fn drop(&mut self) {}
+}
+
+// CHECK-LABEL: @mutate(
 // CHECK-NOT: readonly
-// CHECK-SAME: %big_struct)
-#[no_mangle]
-pub fn use_big_struct_mutably(mut big_struct: BigStruct) {
-    big_struct.blah[987] = 654;
-    hint::black_box(&big_struct);
+// CHECK-SAME: %b)
+#[unsafe(no_mangle)]
+pub fn mutate(mut b: Big) {
+    b.blah[987] = 654;
+    black_box(&b);
 }
 
-// The by-value parameter for this big struct can't be marked readonly, because it contains
-// UnsafeCell.
-//
-// CHECK: @use_big_cell_container(
-// CHECK-NOT: readonly
-// CHECK-SAME: %big_cell_container)
-#[no_mangle]
-pub fn use_big_cell_container(big_cell_container: BigCellContainer) {
-    hint::black_box(&big_cell_container);
+// LLVM21-LABEL: @deref_mut({{.*}}readonly {{.*}}captures(none) {{.*}}%c)
+// LLVM20-LABEL: @deref_mut({{.*}}readonly                      {{.*}}%c)
+#[unsafe(no_mangle)]
+pub fn deref_mut(c: (BigCell, &mut usize)) {
+    *c.1 = 42;
 }
 
-// Make sure that we don't mistakenly mark a big struct as `readonly` when passed through a generic
-// type parameter if it contains UnsafeCell.
+// LLVM21-LABEL: @call_copy_arg(ptr {{.*}}readonly {{.*}}captures(none){{.*}})
+// LLVM20-LABEL: @call_copy_arg(ptr {{.*}}readonly                     {{.*}})
+#[unsafe(no_mangle)]
+#[custom_mir(dialect = "runtime", phase = "optimized")]
+pub fn call_copy_arg(a: Big) {
+    mir! {
+        {
+            Call(RET = call_copy_arg(a), ReturnTo(bb1), UnwindUnreachable())
+        }
+        bb1 = {
+            Return()
+        }
+    }
+}
+
+// CHECK-LABEL: @call_move_arg(
+// CHECK-NOT:   readonly
+// LLVM21-SAME: captures(address)
+// CHECK-SAME:  )
+#[unsafe(no_mangle)]
+#[custom_mir(dialect = "runtime", phase = "optimized")]
+pub fn call_move_arg(a: Big) {
+    mir! {
+        {
+            Call(RET = call_move_arg(Move(a)), ReturnTo(bb1), UnwindUnreachable())
+        }
+        bb1 = {
+            Return()
+        }
+    }
+}
+
+fn shared_borrow(a: T) {
+    black_box(&a);
+}
+
+// Freeze parameter cannot be mutated through a shared borrow.
 //
-// CHECK: @use_something(
-// CHECK-NOT: readonly
-// CHECK-SAME: %something)
-#[no_mangle]
+// CHECK-LABEL: ; deduced_param_attrs::shared_borrow::
+// CHECK-NEXT:  ;
+// LLVM21-NEXT: (ptr {{.*}}readonly {{.*}}captures(address) {{.*}}%a)
+// LLVM20-NEXT: (ptr {{.*}}readonly                         {{.*}}%a)
+pub static A0: fn(Big) = shared_borrow;
+
+// !Freeze parameter can be mutated through a shared borrow.
+//
+// CHECK-LABEL: ; deduced_param_attrs::shared_borrow::
+// CHECK-NEXT:  ;
+// CHECK-NOT:   readonly
+// CHECK-NEXT:  %a)
+pub static A1: fn(BigCell) = shared_borrow;
+
+// The parameter can be mutated through a raw const borrow.
+//
+// CHECK-LABEL: ; deduced_param_attrs::raw_const_borrow
+// CHECK-NOT:   readonly
+// CHECK-NEXT : %a)
 #[inline(never)]
-pub fn use_something(something: T) {
-    hint::black_box(&something);
+pub fn raw_const_borrow(a: Big) {
+    black_box(&raw const a);
 }
 
-// Make sure that we still mark a big `Freeze` struct as `readonly` when passed through a generic
-// type parameter.
+fn consume(_: T) {}
+
+// The parameter doesn't need to be dropped.
 //
-// CHECK: @use_something_freeze(
-// CHECK-SAME: readonly
-// CHECK-SAME: %x)
-#[no_mangle]
-#[inline(never)]
-pub fn use_something_freeze(x: T) {}
+// CHECK-LABEL: ; deduced_param_attrs::consume::
+// CHECK-NEXT:  ;
+// LLVM21-NEXT: (ptr {{.*}}readonly {{.*}}captures(none) {{.*}})
+// LLVM20-NEXT: (ptr {{.*}}readonly                      {{.*}})
+pub static B0: fn(BigCell) = consume;
 
-#[no_mangle]
-pub fn forward_big_cell_container(big_cell_container: BigCellContainer) {
-    use_something(big_cell_container)
+// The parameter needs to be dropped.
+//
+// CHECK-LABEL: ; deduced_param_attrs::consume::
+// CHECK-NEXT:  ;
+// LLVM21-NEXT: (ptr {{.*}}captures(address) {{.*}})
+// LLVM20-NEXT: (ptr                         {{.*}})
+pub static B1: fn(BigDrop) = consume;
+
+fn consume_parts(t: (T, T)) {
+    let (_t0, ..) = t;
 }
 
-#[no_mangle]
-pub fn forward_big_container(big_struct: BigStruct) {
-    use_something_freeze(big_struct)
+// In principle it would be possible to deduce readonly here.
+//
+// CHECK-LABEL: ; deduced_param_attrs::consume_parts::<[u8; 40]>
+// CHECK-NEXT:  ;
+// CHECK-NOT:   readonly
+// CHECK-NEXT:  %t)
+pub static C1: fn(([u8; 40], [u8; 40])) = consume_parts;
+
+// The inner field of ManuallyDrop needs to be dropped.
+//
+// CHECK-LABEL: @manually_drop_field(
+// CHECK-NOT:   readonly
+// CHECK-SAME:  %b)
+#[unsafe(no_mangle)]
+pub fn manually_drop_field(a: fn() -> BigDrop, mut b: ManuallyDrop) {
+    // FIXME(tmiasko) replace with custom MIR, instead of expecting MIR optimizations to turn this
+    // into: drop((_2.0: BigDrop))
+    *b = a();
+    unsafe { core::intrinsics::unreachable() }
 }
+
+// `readonly` is omitted from the return place, even when applicable.
+//
+// CHECK-LABEL: @never_returns(
+// CHECK-NOT:   readonly
+// CHECK-SAME:  %_0)
+#[unsafe(no_mangle)]
+pub fn never_returns() -> [u8; 80] {
+    loop {}
+}
+
+// LLVM21-LABEL: @not_captured_return_place(ptr{{.*}} captures(none) {{.*}}%_0)
+#[unsafe(no_mangle)]
+pub fn not_captured_return_place() -> [u8; 80] {
+    [0u8; 80]
+}
+
+// LLVM21-LABEL: @captured_return_place(ptr{{.*}} captures(address) {{.*}}%_0)
+#[unsafe(no_mangle)]
+pub fn captured_return_place() -> [u8; 80] {
+    black_box([0u8; 80])
+}
+
+// Arguments spread at ABI level are unsupported.
+//
+// CHECK-LABEL: @spread_arg(
+// CHECK-NOT: readonly
+// CHECK-SAME: )
+#[no_mangle]
+pub extern "rust-call" fn spread_arg(_: (Big, Big, Big)) {}
diff --git a/tests/codegen-llvm/function-arguments.rs b/tests/codegen-llvm/function-arguments.rs
index a0744e44c61e..aaa1d57592a8 100644
--- a/tests/codegen-llvm/function-arguments.rs
+++ b/tests/codegen-llvm/function-arguments.rs
@@ -134,7 +134,7 @@ pub fn mutable_notunpin_borrow(_: &mut NotUnpin) {}
 #[no_mangle]
 pub fn notunpin_borrow(_: &NotUnpin) {}
 
-// CHECK: @indirect_struct(ptr{{( dead_on_return)?}} noalias noundef readonly align 4{{( captures\(address\))?}} dereferenceable(32) %_1)
+// CHECK: @indirect_struct(ptr{{( dead_on_return)?}} noalias noundef readonly align 4{{( captures\(none\))?}} dereferenceable(32) %_1)
 #[no_mangle]
 pub fn indirect_struct(_: S) {}
 
@@ -197,7 +197,7 @@ pub fn notunpin_box(x: Box) -> Box {
     x
 }
 
-// CHECK: @struct_return(ptr{{( dead_on_unwind)?}} noalias noundef{{( writable)?}} sret([32 x i8]) align 4{{( captures\(address\))?}} dereferenceable(32){{( %_0)?}})
+// CHECK: @struct_return(ptr{{( dead_on_unwind)?}} noalias noundef{{( writable)?}} sret([32 x i8]) align 4{{( captures\(none\))?}} dereferenceable(32){{( %_0)?}})
 #[no_mangle]
 pub fn struct_return() -> S {
     S { _field: [0, 0, 0, 0, 0, 0, 0, 0] }
diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-paths.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-paths.rs
index f5846713bd53..4ce9c57070a7 100644
--- a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-paths.rs
+++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-paths.rs
@@ -78,9 +78,9 @@ pub fn foo12(_: &Type4, _: &Type4, _: &Type4) {}
 // CHECK: ![[TYPE4]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtNCNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo11{{[{}][{}]}}closure{{[}][}]}}3FooEE"}
 // CHECK: ![[TYPE5]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtNCNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo11{{[{}][{}]}}closure{{[}][}]}}3FooES0_E"}
 // CHECK: ![[TYPE6]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtNCNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo11{{[{}][{}]}}closure{{[}][}]}}3FooES0_S0_E"}
-// CHECK: ![[TYPE7]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtNkNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo12{{[{}][{}]}}constant{{[}][}]}}3FooEE"}
-// CHECK: ![[TYPE8]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtNkNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo12{{[{}][{}]}}constant{{[}][}]}}3FooES0_E"}
-// CHECK: ![[TYPE9]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtNkNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo12{{[{}][{}]}}constant{{[}][}]}}3FooES0_S0_E"}
+// CHECK: ![[TYPE7]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtNKNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo12{{[{}][{}]}}constant{{[}][}]}}3FooEE"}
+// CHECK: ![[TYPE8]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtNKNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo12{{[{}][{}]}}constant{{[}][}]}}3FooES0_E"}
+// CHECK: ![[TYPE9]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtNKNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo12{{[{}][{}]}}constant{{[}][}]}}3FooES0_S0_E"}
 // CHECK: ![[TYPE10]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NvNINvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo8{{[{}][{}]}}impl{{[}][}]}}3barEE"}
 // CHECK: ![[TYPE11]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NvNINvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo8{{[{}][{}]}}impl{{[}][}]}}3barES0_E"}
 // CHECK: ![[TYPE12]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NvNINvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo8{{[{}][{}]}}impl{{[}][}]}}3barES0_S0_E"}
diff --git a/tests/coverage/remap-path-prefix.rs b/tests/coverage/remap-path-prefix.rs
new file mode 100644
index 000000000000..29c5826989c4
--- /dev/null
+++ b/tests/coverage/remap-path-prefix.rs
@@ -0,0 +1,17 @@
+// This test makes sure that the files used in the coverage are remapped by
+// `--remap-path-prefix` and the `coverage` <- `object` scopes.
+//
+// We also test the `macro` scope to make sure it does not affect coverage.
+
+// When coverage paths are remapped, the coverage-run mode can't find source files (because
+// it doesn't know about the remapping), so it produces an empty coverage report. The empty
+// report (i.e. no `.coverage` files) helps to demonstrate that remapping was indeed performed.
+
+//@ revisions: with_remap with_coverage_scope with_object_scope with_macro_scope
+//@ compile-flags: --remap-path-prefix={{src-base}}=remapped
+//
+//@[with_coverage_scope] compile-flags: -Zremap-path-scope=coverage
+//@[with_object_scope] compile-flags: -Zremap-path-scope=object
+//@[with_macro_scope] compile-flags: -Zremap-path-scope=macro
+
+fn main() {}
diff --git a/tests/coverage/remap-path-prefix.with_coverage_scope.cov-map b/tests/coverage/remap-path-prefix.with_coverage_scope.cov-map
new file mode 100644
index 000000000000..35731d71116f
--- /dev/null
+++ b/tests/coverage/remap-path-prefix.with_coverage_scope.cov-map
@@ -0,0 +1,10 @@
+Function name: remap_path_prefix::main
+Raw bytes (14): 0x[01, 01, 00, 02, 01, 11, 01, 00, 0a, 01, 00, 0c, 00, 0d]
+Number of files: 1
+- file 0 => remapped/remap-path-prefix.rs
+Number of expressions: 0
+Number of file 0 mappings: 2
+- Code(Counter(0)) at (prev + 17, 1) to (start + 0, 10)
+- Code(Counter(0)) at (prev + 0, 12) to (start + 0, 13)
+Highest counter ID seen: c0
+
diff --git a/tests/coverage/remap-path-prefix.with_macro_scope.cov-map b/tests/coverage/remap-path-prefix.with_macro_scope.cov-map
new file mode 100644
index 000000000000..551e28676885
--- /dev/null
+++ b/tests/coverage/remap-path-prefix.with_macro_scope.cov-map
@@ -0,0 +1,10 @@
+Function name: remap_path_prefix::main
+Raw bytes (14): 0x[01, 01, 00, 02, 01, 11, 01, 00, 0a, 01, 00, 0c, 00, 0d]
+Number of files: 1
+- file 0 => $DIR/remap-path-prefix.rs
+Number of expressions: 0
+Number of file 0 mappings: 2
+- Code(Counter(0)) at (prev + 17, 1) to (start + 0, 10)
+- Code(Counter(0)) at (prev + 0, 12) to (start + 0, 13)
+Highest counter ID seen: c0
+
diff --git a/tests/coverage/remap-path-prefix.with_macro_scope.coverage b/tests/coverage/remap-path-prefix.with_macro_scope.coverage
new file mode 100644
index 000000000000..63979d8fe15a
--- /dev/null
+++ b/tests/coverage/remap-path-prefix.with_macro_scope.coverage
@@ -0,0 +1,18 @@
+   LL|       |// This test makes sure that the files used in the coverage are remapped by
+   LL|       |// `--remap-path-prefix` and the `coverage` <- `object` scopes.
+   LL|       |//
+   LL|       |// We also test the `macro` scope to make sure it does not affect coverage.
+   LL|       |
+   LL|       |// When coverage paths are remapped, the coverage-run mode can't find source files (because
+   LL|       |// it doesn't know about the remapping), so it produces an empty coverage report. The empty
+   LL|       |// report (i.e. no `.coverage` files) helps to demonstrate that remapping was indeed performed.
+   LL|       |
+   LL|       |//@ revisions: with_remap with_coverage_scope with_object_scope with_macro_scope
+   LL|       |//@ compile-flags: --remap-path-prefix={{src-base}}=remapped
+   LL|       |//
+   LL|       |//@[with_coverage_scope] compile-flags: -Zremap-path-scope=coverage
+   LL|       |//@[with_object_scope] compile-flags: -Zremap-path-scope=object
+   LL|       |//@[with_macro_scope] compile-flags: -Zremap-path-scope=macro
+   LL|       |
+   LL|      1|fn main() {}
+
diff --git a/tests/coverage/remap-path-prefix.with_object_scope.cov-map b/tests/coverage/remap-path-prefix.with_object_scope.cov-map
new file mode 100644
index 000000000000..35731d71116f
--- /dev/null
+++ b/tests/coverage/remap-path-prefix.with_object_scope.cov-map
@@ -0,0 +1,10 @@
+Function name: remap_path_prefix::main
+Raw bytes (14): 0x[01, 01, 00, 02, 01, 11, 01, 00, 0a, 01, 00, 0c, 00, 0d]
+Number of files: 1
+- file 0 => remapped/remap-path-prefix.rs
+Number of expressions: 0
+Number of file 0 mappings: 2
+- Code(Counter(0)) at (prev + 17, 1) to (start + 0, 10)
+- Code(Counter(0)) at (prev + 0, 12) to (start + 0, 13)
+Highest counter ID seen: c0
+
diff --git a/tests/coverage/remap-path-prefix.with_remap.cov-map b/tests/coverage/remap-path-prefix.with_remap.cov-map
new file mode 100644
index 000000000000..35731d71116f
--- /dev/null
+++ b/tests/coverage/remap-path-prefix.with_remap.cov-map
@@ -0,0 +1,10 @@
+Function name: remap_path_prefix::main
+Raw bytes (14): 0x[01, 01, 00, 02, 01, 11, 01, 00, 0a, 01, 00, 0c, 00, 0d]
+Number of files: 1
+- file 0 => remapped/remap-path-prefix.rs
+Number of expressions: 0
+Number of file 0 mappings: 2
+- Code(Counter(0)) at (prev + 17, 1) to (start + 0, 10)
+- Code(Counter(0)) at (prev + 0, 12) to (start + 0, 13)
+Highest counter ID seen: c0
+
diff --git a/tests/debuginfo/macro-stepping.rs b/tests/debuginfo/macro-stepping.rs
index 35bb6de4fef3..e58975764e53 100644
--- a/tests/debuginfo/macro-stepping.rs
+++ b/tests/debuginfo/macro-stepping.rs
@@ -1,5 +1,4 @@
 //@ ignore-android
-//@ ignore-aarch64
 //@ min-lldb-version: 1800
 //@ min-gdb-version: 13.0
 
diff --git a/tests/incremental/issue-54242.rs b/tests/incremental/issue-54242.rs
index 17bbd619a8fb..1bc456e565b5 100644
--- a/tests/incremental/issue-54242.rs
+++ b/tests/incremental/issue-54242.rs
@@ -14,7 +14,7 @@ impl Tr for str {
     type Arr = [u8; 8];
     #[cfg(cfail)]
     type Arr = [u8; Self::C];
-    //[cfail]~^ ERROR cycle detected when caching mir
+    //[cfail]~^ ERROR cycle detected when
 }
 
 fn main() {}
diff --git a/tests/mir-opt/async_drop_live_dead.a-{closure#0}.coroutine_drop_async.0.panic-abort.mir b/tests/mir-opt/async_drop_live_dead.a-{closure#0}.coroutine_drop_async.0.panic-abort.mir
index 541b9b9895b3..435c1532895c 100644
--- a/tests/mir-opt/async_drop_live_dead.a-{closure#0}.coroutine_drop_async.0.panic-abort.mir
+++ b/tests/mir-opt/async_drop_live_dead.a-{closure#0}.coroutine_drop_async.0.panic-abort.mir
@@ -2,7 +2,7 @@
 
 fn a::{closure#0}(_1: Pin<&mut {async fn body of a()}>, _2: &mut Context<'_>) -> Poll<()> {
     debug _task_context => _2;
-    debug x => ((*(_1.0: &mut {async fn body of a()})).0: T);
+    debug x => ((*_20).0: T);
     let mut _0: std::task::Poll<()>;
     let _3: T;
     let mut _4: impl std::future::Future;
@@ -21,12 +21,14 @@ fn a::{closure#0}(_1: Pin<&mut {async fn body of a()}>, _2: &mut Context<'_>)
     let mut _17: isize;
     let mut _18: ();
     let mut _19: u32;
+    let mut _20: &mut {async fn body of a()};
     scope 1 {
-        debug x => (((*(_1.0: &mut {async fn body of a()})) as variant#4).0: T);
+        debug x => (((*_20) as variant#4).0: T);
     }
 
     bb0: {
-        _19 = discriminant((*(_1.0: &mut {async fn body of a()})));
+        _20 = copy (_1.0: &mut {async fn body of a()});
+        _19 = discriminant((*_20));
         switchInt(move _19) -> [0: bb9, 3: bb12, 4: bb13, otherwise: bb14];
     }
 
@@ -43,13 +45,13 @@ fn a::{closure#0}(_1: Pin<&mut {async fn body of a()}>, _2: &mut Context<'_>)
 
     bb3: {
         _0 = Poll::<()>::Pending;
-        discriminant((*(_1.0: &mut {async fn body of a()}))) = 4;
+        discriminant((*_20)) = 4;
         return;
     }
 
     bb4: {
         StorageLive(_16);
-        _15 = &mut (((*(_1.0: &mut {async fn body of a()})) as variant#4).1: impl std::future::Future);
+        _15 = &mut (((*_20) as variant#4).1: impl std::future::Future);
         _16 = Pin::<&mut impl Future>::new_unchecked(move _15) -> [return: bb7, unwind unreachable];
     }
 
@@ -81,7 +83,7 @@ fn a::{closure#0}(_1: Pin<&mut {async fn body of a()}>, _2: &mut Context<'_>)
     }
 
     bb11: {
-        drop(((*(_1.0: &mut {async fn body of a()})).0: T)) -> [return: bb10, unwind unreachable];
+        drop(((*_20).0: T)) -> [return: bb10, unwind unreachable];
     }
 
     bb12: {
diff --git a/tests/mir-opt/async_drop_live_dead.a-{closure#0}.coroutine_drop_async.0.panic-unwind.mir b/tests/mir-opt/async_drop_live_dead.a-{closure#0}.coroutine_drop_async.0.panic-unwind.mir
index f2e1fb099756..1dc1d0813629 100644
--- a/tests/mir-opt/async_drop_live_dead.a-{closure#0}.coroutine_drop_async.0.panic-unwind.mir
+++ b/tests/mir-opt/async_drop_live_dead.a-{closure#0}.coroutine_drop_async.0.panic-unwind.mir
@@ -2,7 +2,7 @@
 
 fn a::{closure#0}(_1: Pin<&mut {async fn body of a()}>, _2: &mut Context<'_>) -> Poll<()> {
     debug _task_context => _2;
-    debug x => ((*(_1.0: &mut {async fn body of a()})).0: T);
+    debug x => ((*_20).0: T);
     let mut _0: std::task::Poll<()>;
     let _3: T;
     let mut _4: impl std::future::Future;
@@ -21,12 +21,14 @@ fn a::{closure#0}(_1: Pin<&mut {async fn body of a()}>, _2: &mut Context<'_>)
     let mut _17: isize;
     let mut _18: ();
     let mut _19: u32;
+    let mut _20: &mut {async fn body of a()};
     scope 1 {
-        debug x => (((*(_1.0: &mut {async fn body of a()})) as variant#4).0: T);
+        debug x => (((*_20) as variant#4).0: T);
     }
 
     bb0: {
-        _19 = discriminant((*(_1.0: &mut {async fn body of a()})));
+        _20 = copy (_1.0: &mut {async fn body of a()});
+        _19 = discriminant((*_20));
         switchInt(move _19) -> [0: bb12, 2: bb18, 3: bb16, 4: bb17, otherwise: bb19];
     }
 
@@ -57,13 +59,13 @@ fn a::{closure#0}(_1: Pin<&mut {async fn body of a()}>, _2: &mut Context<'_>)
 
     bb6: {
         _0 = Poll::<()>::Pending;
-        discriminant((*(_1.0: &mut {async fn body of a()}))) = 4;
+        discriminant((*_20)) = 4;
         return;
     }
 
     bb7: {
         StorageLive(_16);
-        _15 = &mut (((*(_1.0: &mut {async fn body of a()})) as variant#4).1: impl std::future::Future);
+        _15 = &mut (((*_20) as variant#4).1: impl std::future::Future);
         _16 = Pin::<&mut impl Future>::new_unchecked(move _15) -> [return: bb10, unwind: bb15];
     }
 
@@ -95,11 +97,11 @@ fn a::{closure#0}(_1: Pin<&mut {async fn body of a()}>, _2: &mut Context<'_>)
     }
 
     bb14: {
-        drop(((*(_1.0: &mut {async fn body of a()})).0: T)) -> [return: bb13, unwind: bb4];
+        drop(((*_20).0: T)) -> [return: bb13, unwind: bb4];
     }
 
     bb15 (cleanup): {
-        discriminant((*(_1.0: &mut {async fn body of a()}))) = 2;
+        discriminant((*_20)) = 2;
         resume;
     }
 
diff --git a/tests/mir-opt/building/async_await.a-{closure#0}.coroutine_resume.0.mir b/tests/mir-opt/building/async_await.a-{closure#0}.coroutine_resume.0.mir
index 2e2876cb3fcf..6cad5b105d3e 100644
--- a/tests/mir-opt/building/async_await.a-{closure#0}.coroutine_resume.0.mir
+++ b/tests/mir-opt/building/async_await.a-{closure#0}.coroutine_resume.0.mir
@@ -14,9 +14,11 @@ fn a::{closure#0}(_1: Pin<&mut {async fn body of a()}>, _2: &mut Context<'_>) ->
     let mut _0: std::task::Poll<()>;
     let mut _3: ();
     let mut _4: u32;
+    let mut _5: &mut {async fn body of a()};
 
     bb0: {
-        _4 = discriminant((*(_1.0: &mut {async fn body of a()})));
+        _5 = copy (_1.0: &mut {async fn body of a()});
+        _4 = discriminant((*_5));
         switchInt(move _4) -> [0: bb1, 1: bb4, otherwise: bb5];
     }
 
@@ -27,7 +29,7 @@ fn a::{closure#0}(_1: Pin<&mut {async fn body of a()}>, _2: &mut Context<'_>) ->
 
     bb2: {
         _0 = Poll::<()>::Ready(move _3);
-        discriminant((*(_1.0: &mut {async fn body of a()}))) = 1;
+        discriminant((*_5)) = 1;
         return;
     }
 
diff --git a/tests/mir-opt/building/async_await.b-{closure#0}.coroutine_resume.0.mir b/tests/mir-opt/building/async_await.b-{closure#0}.coroutine_resume.0.mir
index 20fc4112ef28..96ee37185db1 100644
--- a/tests/mir-opt/building/async_await.b-{closure#0}.coroutine_resume.0.mir
+++ b/tests/mir-opt/building/async_await.b-{closure#0}.coroutine_resume.0.mir
@@ -86,15 +86,16 @@ fn b::{closure#0}(_1: Pin<&mut {async fn body of b()}>, _2: &mut Context<'_>) ->
     let mut _36: ();
     let mut _37: ();
     let mut _38: u32;
+    let mut _39: &mut {async fn body of b()};
     scope 1 {
-        debug __awaitee => (((*(_1.0: &mut {async fn body of b()})) as variant#3).0: {async fn body of a()});
+        debug __awaitee => (((*_39) as variant#3).0: {async fn body of a()});
         let _17: ();
         scope 2 {
             debug result => _17;
         }
     }
     scope 3 {
-        debug __awaitee => (((*(_1.0: &mut {async fn body of b()})) as variant#4).0: {async fn body of a()});
+        debug __awaitee => (((*_39) as variant#4).0: {async fn body of a()});
         let _33: ();
         scope 4 {
             debug result => _33;
@@ -102,7 +103,8 @@ fn b::{closure#0}(_1: Pin<&mut {async fn body of b()}>, _2: &mut Context<'_>) ->
     }
 
     bb0: {
-        _38 = discriminant((*(_1.0: &mut {async fn body of b()})));
+        _39 = copy (_1.0: &mut {async fn body of b()});
+        _38 = discriminant((*_39));
         switchInt(move _38) -> [0: bb1, 1: bb29, 3: bb27, 4: bb28, otherwise: bb8];
     }
 
@@ -121,7 +123,7 @@ fn b::{closure#0}(_1: Pin<&mut {async fn body of b()}>, _2: &mut Context<'_>) ->
         StorageDead(_5);
         PlaceMention(_4);
         nop;
-        (((*(_1.0: &mut {async fn body of b()})) as variant#3).0: {async fn body of a()}) = move _4;
+        (((*_39) as variant#3).0: {async fn body of a()}) = move _4;
         goto -> bb4;
     }
 
@@ -131,7 +133,7 @@ fn b::{closure#0}(_1: Pin<&mut {async fn body of b()}>, _2: &mut Context<'_>) ->
         StorageLive(_10);
         StorageLive(_11);
         StorageLive(_12);
-        _12 = &mut (((*(_1.0: &mut {async fn body of b()})) as variant#3).0: {async fn body of a()});
+        _12 = &mut (((*_39) as variant#3).0: {async fn body of a()});
         _11 = &mut (*_12);
         _10 = Pin::<&mut {async fn body of a()}>::new_unchecked(move _11) -> [return: bb5, unwind unreachable];
     }
@@ -178,7 +180,7 @@ fn b::{closure#0}(_1: Pin<&mut {async fn body of b()}>, _2: &mut Context<'_>) ->
         StorageDead(_4);
         StorageDead(_19);
         StorageDead(_20);
-        discriminant((*(_1.0: &mut {async fn body of b()}))) = 3;
+        discriminant((*_39)) = 3;
         return;
     }
 
@@ -191,7 +193,7 @@ fn b::{closure#0}(_1: Pin<&mut {async fn body of b()}>, _2: &mut Context<'_>) ->
         StorageDead(_12);
         StorageDead(_9);
         StorageDead(_8);
-        drop((((*(_1.0: &mut {async fn body of b()})) as variant#3).0: {async fn body of a()})) -> [return: bb12, unwind unreachable];
+        drop((((*_39) as variant#3).0: {async fn body of a()})) -> [return: bb12, unwind unreachable];
     }
 
     bb11: {
@@ -223,7 +225,7 @@ fn b::{closure#0}(_1: Pin<&mut {async fn body of b()}>, _2: &mut Context<'_>) ->
         StorageDead(_22);
         PlaceMention(_21);
         nop;
-        (((*(_1.0: &mut {async fn body of b()})) as variant#4).0: {async fn body of a()}) = move _21;
+        (((*_39) as variant#4).0: {async fn body of a()}) = move _21;
         goto -> bb16;
     }
 
@@ -233,7 +235,7 @@ fn b::{closure#0}(_1: Pin<&mut {async fn body of b()}>, _2: &mut Context<'_>) ->
         StorageLive(_26);
         StorageLive(_27);
         StorageLive(_28);
-        _28 = &mut (((*(_1.0: &mut {async fn body of b()})) as variant#4).0: {async fn body of a()});
+        _28 = &mut (((*_39) as variant#4).0: {async fn body of a()});
         _27 = &mut (*_28);
         _26 = Pin::<&mut {async fn body of a()}>::new_unchecked(move _27) -> [return: bb17, unwind unreachable];
     }
@@ -275,7 +277,7 @@ fn b::{closure#0}(_1: Pin<&mut {async fn body of b()}>, _2: &mut Context<'_>) ->
         StorageDead(_21);
         StorageDead(_35);
         StorageDead(_36);
-        discriminant((*(_1.0: &mut {async fn body of b()}))) = 4;
+        discriminant((*_39)) = 4;
         return;
     }
 
@@ -288,7 +290,7 @@ fn b::{closure#0}(_1: Pin<&mut {async fn body of b()}>, _2: &mut Context<'_>) ->
         StorageDead(_28);
         StorageDead(_25);
         StorageDead(_24);
-        drop((((*(_1.0: &mut {async fn body of b()})) as variant#4).0: {async fn body of a()})) -> [return: bb23, unwind unreachable];
+        drop((((*_39) as variant#4).0: {async fn body of a()})) -> [return: bb23, unwind unreachable];
     }
 
     bb22: {
@@ -311,7 +313,7 @@ fn b::{closure#0}(_1: Pin<&mut {async fn body of b()}>, _2: &mut Context<'_>) ->
 
     bb25: {
         _0 = Poll::<()>::Ready(move _37);
-        discriminant((*(_1.0: &mut {async fn body of b()}))) = 1;
+        discriminant((*_39)) = 1;
         return;
     }
 
diff --git a/tests/mir-opt/building/coroutine.main-{closure#0}.StateTransform.after.mir b/tests/mir-opt/building/coroutine.main-{closure#0}.StateTransform.after.mir
index cd776ad7170a..b61215dc28cb 100644
--- a/tests/mir-opt/building/coroutine.main-{closure#0}.StateTransform.after.mir
+++ b/tests/mir-opt/building/coroutine.main-{closure#0}.StateTransform.after.mir
@@ -23,7 +23,7 @@
 } */
 
 fn main::{closure#0}(_1: Pin<&mut {coroutine@$DIR/coroutine.rs:18:5: 18:18}>, _2: String) -> CoroutineState<(&str, String, &Location<'_>), ()> {
-    debug arg => (((*(_1.0: &mut {coroutine@$DIR/coroutine.rs:18:5: 18:18})) as variant#4).0: std::string::String);
+    debug arg => (((*_18) as variant#4).0: std::string::String);
     let mut _0: std::ops::CoroutineState<(&str, std::string::String, &std::panic::Location<'_>), ()>;
     let _3: std::string::String;
     let mut _4: (&str, std::string::String, &std::panic::Location<'_>);
@@ -41,13 +41,6 @@ fn main::{closure#0}(_1: Pin<&mut {coroutine@$DIR/coroutine.rs:18:5: 18:18}>, _2
     let mut _16: ();
     let mut _17: u32;
     let mut _18: &mut {coroutine@$DIR/coroutine.rs:18:5: 18:18};
-    let mut _19: &mut {coroutine@$DIR/coroutine.rs:18:5: 18:18};
-    let mut _20: &mut {coroutine@$DIR/coroutine.rs:18:5: 18:18};
-    let mut _21: &mut {coroutine@$DIR/coroutine.rs:18:5: 18:18};
-    let mut _22: &mut {coroutine@$DIR/coroutine.rs:18:5: 18:18};
-    let mut _23: &mut {coroutine@$DIR/coroutine.rs:18:5: 18:18};
-    let mut _24: &mut {coroutine@$DIR/coroutine.rs:18:5: 18:18};
-    let mut _25: &mut {coroutine@$DIR/coroutine.rs:18:5: 18:18};
 
     bb0: {
         _18 = copy (_1.0: &mut {coroutine@$DIR/coroutine.rs:18:5: 18:18});
@@ -56,14 +49,12 @@ fn main::{closure#0}(_1: Pin<&mut {coroutine@$DIR/coroutine.rs:18:5: 18:18}>, _2
     }
 
     bb1: {
-        _19 = copy (_1.0: &mut {coroutine@$DIR/coroutine.rs:18:5: 18:18});
-        (((*_19) as variant#4).0: std::string::String) = move _2;
+        (((*_18) as variant#4).0: std::string::String) = move _2;
         StorageLive(_3);
         StorageLive(_4);
         StorageLive(_5);
         StorageLive(_6);
-        _20 = copy (_1.0: &mut {coroutine@$DIR/coroutine.rs:18:5: 18:18});
-        _6 = &(((*_20) as variant#4).0: std::string::String);
+        _6 = &(((*_18) as variant#4).0: std::string::String);
         _5 = ::clone(move _6) -> [return: bb2, unwind unreachable];
     }
 
@@ -84,8 +75,7 @@ fn main::{closure#0}(_1: Pin<&mut {coroutine@$DIR/coroutine.rs:18:5: 18:18}>, _2
         _0 = CoroutineState::<(&str, String, &Location<'_>), ()>::Yielded(move _4);
         StorageDead(_3);
         StorageDead(_4);
-        _21 = copy (_1.0: &mut {coroutine@$DIR/coroutine.rs:18:5: 18:18});
-        discriminant((*_21)) = 3;
+        discriminant((*_18)) = 3;
         return;
     }
 
@@ -108,8 +98,7 @@ fn main::{closure#0}(_1: Pin<&mut {coroutine@$DIR/coroutine.rs:18:5: 18:18}>, _2
         _10 = &(*_11);
         StorageLive(_12);
         StorageLive(_13);
-        _22 = copy (_1.0: &mut {coroutine@$DIR/coroutine.rs:18:5: 18:18});
-        _13 = &(((*_22) as variant#4).0: std::string::String);
+        _13 = &(((*_18) as variant#4).0: std::string::String);
         _12 = ::clone(move _13) -> [return: bb8, unwind unreachable];
     }
 
@@ -135,8 +124,7 @@ fn main::{closure#0}(_1: Pin<&mut {coroutine@$DIR/coroutine.rs:18:5: 18:18}>, _2
         StorageDead(_9);
         StorageDead(_11);
         StorageDead(_15);
-        _23 = copy (_1.0: &mut {coroutine@$DIR/coroutine.rs:18:5: 18:18});
-        discriminant((*_23)) = 4;
+        discriminant((*_18)) = 4;
         return;
     }
 
@@ -154,8 +142,7 @@ fn main::{closure#0}(_1: Pin<&mut {coroutine@$DIR/coroutine.rs:18:5: 18:18}>, _2
         StorageDead(_11);
         StorageDead(_8);
         _16 = const ();
-        _24 = copy (_1.0: &mut {coroutine@$DIR/coroutine.rs:18:5: 18:18});
-        drop((((*_24) as variant#4).0: std::string::String)) -> [return: bb14, unwind unreachable];
+        drop((((*_18) as variant#4).0: std::string::String)) -> [return: bb14, unwind unreachable];
     }
 
     bb14: {
@@ -164,8 +151,7 @@ fn main::{closure#0}(_1: Pin<&mut {coroutine@$DIR/coroutine.rs:18:5: 18:18}>, _2
 
     bb15: {
         _0 = CoroutineState::<(&str, String, &Location<'_>), ()>::Complete(move _16);
-        _25 = copy (_1.0: &mut {coroutine@$DIR/coroutine.rs:18:5: 18:18});
-        discriminant((*_25)) = 1;
+        discriminant((*_18)) = 1;
         return;
     }
 
diff --git a/tests/mir-opt/building/coroutine.main-{closure#1}.StateTransform.after.mir b/tests/mir-opt/building/coroutine.main-{closure#1}.StateTransform.after.mir
index 981bc21dc878..aac028a9e6c0 100644
--- a/tests/mir-opt/building/coroutine.main-{closure#1}.StateTransform.after.mir
+++ b/tests/mir-opt/building/coroutine.main-{closure#1}.StateTransform.after.mir
@@ -23,7 +23,7 @@
 } */
 
 fn main::{closure#1}(_1: Pin<&mut {coroutine@$DIR/coroutine.rs:25:5: 25:18}>, _2: String) -> CoroutineState<(&str, String, &Location<'_>), ()> {
-    debug arg => (((*(_1.0: &mut {coroutine@$DIR/coroutine.rs:25:5: 25:18})) as variant#4).0: std::string::String);
+    debug arg => (((*_18) as variant#4).0: std::string::String);
     let mut _0: std::ops::CoroutineState<(&str, std::string::String, &std::panic::Location<'_>), ()>;
     let _3: std::string::String;
     let mut _4: (&str, std::string::String, &std::panic::Location<'_>);
@@ -41,13 +41,6 @@ fn main::{closure#1}(_1: Pin<&mut {coroutine@$DIR/coroutine.rs:25:5: 25:18}>, _2
     let mut _16: ();
     let mut _17: u32;
     let mut _18: &mut {coroutine@$DIR/coroutine.rs:25:5: 25:18};
-    let mut _19: &mut {coroutine@$DIR/coroutine.rs:25:5: 25:18};
-    let mut _20: &mut {coroutine@$DIR/coroutine.rs:25:5: 25:18};
-    let mut _21: &mut {coroutine@$DIR/coroutine.rs:25:5: 25:18};
-    let mut _22: &mut {coroutine@$DIR/coroutine.rs:25:5: 25:18};
-    let mut _23: &mut {coroutine@$DIR/coroutine.rs:25:5: 25:18};
-    let mut _24: &mut {coroutine@$DIR/coroutine.rs:25:5: 25:18};
-    let mut _25: &mut {coroutine@$DIR/coroutine.rs:25:5: 25:18};
 
     bb0: {
         _18 = copy (_1.0: &mut {coroutine@$DIR/coroutine.rs:25:5: 25:18});
@@ -56,14 +49,12 @@ fn main::{closure#1}(_1: Pin<&mut {coroutine@$DIR/coroutine.rs:25:5: 25:18}>, _2
     }
 
     bb1: {
-        _19 = copy (_1.0: &mut {coroutine@$DIR/coroutine.rs:25:5: 25:18});
-        (((*_19) as variant#4).0: std::string::String) = move _2;
+        (((*_18) as variant#4).0: std::string::String) = move _2;
         StorageLive(_3);
         StorageLive(_4);
         StorageLive(_5);
         StorageLive(_6);
-        _20 = copy (_1.0: &mut {coroutine@$DIR/coroutine.rs:25:5: 25:18});
-        _6 = &(((*_20) as variant#4).0: std::string::String);
+        _6 = &(((*_18) as variant#4).0: std::string::String);
         _5 = ::clone(move _6) -> [return: bb2, unwind unreachable];
     }
 
@@ -84,8 +75,7 @@ fn main::{closure#1}(_1: Pin<&mut {coroutine@$DIR/coroutine.rs:25:5: 25:18}>, _2
         _0 = CoroutineState::<(&str, String, &Location<'_>), ()>::Yielded(move _4);
         StorageDead(_3);
         StorageDead(_4);
-        _21 = copy (_1.0: &mut {coroutine@$DIR/coroutine.rs:25:5: 25:18});
-        discriminant((*_21)) = 3;
+        discriminant((*_18)) = 3;
         return;
     }
 
@@ -108,8 +98,7 @@ fn main::{closure#1}(_1: Pin<&mut {coroutine@$DIR/coroutine.rs:25:5: 25:18}>, _2
         _10 = &(*_11);
         StorageLive(_12);
         StorageLive(_13);
-        _22 = copy (_1.0: &mut {coroutine@$DIR/coroutine.rs:25:5: 25:18});
-        _13 = &(((*_22) as variant#4).0: std::string::String);
+        _13 = &(((*_18) as variant#4).0: std::string::String);
         _12 = ::clone(move _13) -> [return: bb8, unwind unreachable];
     }
 
@@ -135,8 +124,7 @@ fn main::{closure#1}(_1: Pin<&mut {coroutine@$DIR/coroutine.rs:25:5: 25:18}>, _2
         StorageDead(_9);
         StorageDead(_11);
         StorageDead(_15);
-        _23 = copy (_1.0: &mut {coroutine@$DIR/coroutine.rs:25:5: 25:18});
-        discriminant((*_23)) = 4;
+        discriminant((*_18)) = 4;
         return;
     }
 
@@ -154,8 +142,7 @@ fn main::{closure#1}(_1: Pin<&mut {coroutine@$DIR/coroutine.rs:25:5: 25:18}>, _2
         StorageDead(_11);
         StorageDead(_8);
         _16 = const ();
-        _24 = copy (_1.0: &mut {coroutine@$DIR/coroutine.rs:25:5: 25:18});
-        drop((((*_24) as variant#4).0: std::string::String)) -> [return: bb14, unwind unreachable];
+        drop((((*_18) as variant#4).0: std::string::String)) -> [return: bb14, unwind unreachable];
     }
 
     bb14: {
@@ -164,8 +151,7 @@ fn main::{closure#1}(_1: Pin<&mut {coroutine@$DIR/coroutine.rs:25:5: 25:18}>, _2
 
     bb15: {
         _0 = CoroutineState::<(&str, String, &Location<'_>), ()>::Complete(move _16);
-        _25 = copy (_1.0: &mut {coroutine@$DIR/coroutine.rs:25:5: 25:18});
-        discriminant((*_25)) = 1;
+        discriminant((*_18)) = 1;
         return;
     }
 
diff --git a/tests/mir-opt/coroutine_tiny.main-{closure#0}.coroutine_resume.0.mir b/tests/mir-opt/coroutine_tiny.main-{closure#0}.coroutine_resume.0.mir
index 9905cc3e00f9..222c7144ef07 100644
--- a/tests/mir-opt/coroutine_tiny.main-{closure#0}.coroutine_resume.0.mir
+++ b/tests/mir-opt/coroutine_tiny.main-{closure#0}.coroutine_resume.0.mir
@@ -32,18 +32,20 @@ fn main::{closure#0}(_1: Pin<&mut {coroutine@$DIR/coroutine_tiny.rs:21:5: 21:13}
     let _8: ();
     let mut _9: ();
     let mut _10: u32;
+    let mut _11: &mut {coroutine@$DIR/coroutine_tiny.rs:21:5: 21:13};
     scope 1 {
-        debug _d => (((*(_1.0: &mut {coroutine@$DIR/coroutine_tiny.rs:21:5: 21:13})) as variant#3).0: HasDrop);
+        debug _d => (((*_11) as variant#3).0: HasDrop);
     }
 
     bb0: {
-        _10 = discriminant((*(_1.0: &mut {coroutine@$DIR/coroutine_tiny.rs:21:5: 21:13})));
+        _11 = copy (_1.0: &mut {coroutine@$DIR/coroutine_tiny.rs:21:5: 21:13});
+        _10 = discriminant((*_11));
         switchInt(move _10) -> [0: bb1, 3: bb5, otherwise: bb6];
     }
 
     bb1: {
         nop;
-        (((*(_1.0: &mut {coroutine@$DIR/coroutine_tiny.rs:21:5: 21:13})) as variant#3).0: HasDrop) = HasDrop;
+        (((*_11) as variant#3).0: HasDrop) = HasDrop;
         StorageLive(_4);
         goto -> bb2;
     }
@@ -56,7 +58,7 @@ fn main::{closure#0}(_1: Pin<&mut {coroutine@$DIR/coroutine_tiny.rs:21:5: 21:13}
         StorageDead(_4);
         StorageDead(_6);
         StorageDead(_7);
-        discriminant((*(_1.0: &mut {coroutine@$DIR/coroutine_tiny.rs:21:5: 21:13}))) = 3;
+        discriminant((*_11)) = 3;
         return;
     }
 
diff --git a/tests/mir-opt/gvn.dereference_indexing.GVN.panic-abort.diff b/tests/mir-opt/gvn.dereference_indexing.GVN.panic-abort.diff
index 1a07638cbafe..cdfbef8e9633 100644
--- a/tests/mir-opt/gvn.dereference_indexing.GVN.panic-abort.diff
+++ b/tests/mir-opt/gvn.dereference_indexing.GVN.panic-abort.diff
@@ -41,6 +41,7 @@
 -         StorageDead(_4);
 +         _3 = &_1[_4];
 +         nop;
+          StorageDead(_6);
           StorageLive(_8);
           StorageLive(_9);
 -         _9 = copy (*_3);
@@ -52,7 +53,6 @@
           StorageDead(_9);
           StorageDead(_8);
           _0 = const ();
-          StorageDead(_6);
           StorageDead(_3);
           return;
       }
diff --git a/tests/mir-opt/gvn.dereference_indexing.GVN.panic-unwind.diff b/tests/mir-opt/gvn.dereference_indexing.GVN.panic-unwind.diff
index 6e67b66e783c..8c817f9d5cf7 100644
--- a/tests/mir-opt/gvn.dereference_indexing.GVN.panic-unwind.diff
+++ b/tests/mir-opt/gvn.dereference_indexing.GVN.panic-unwind.diff
@@ -41,6 +41,7 @@
 -         StorageDead(_4);
 +         _3 = &_1[_4];
 +         nop;
+          StorageDead(_6);
           StorageLive(_8);
           StorageLive(_9);
 -         _9 = copy (*_3);
@@ -52,7 +53,6 @@
           StorageDead(_9);
           StorageDead(_8);
           _0 = const ();
-          StorageDead(_6);
           StorageDead(_3);
           return;
       }
diff --git a/tests/mir-opt/gvn.wide_ptr_same_provenance.GVN.panic-abort.diff b/tests/mir-opt/gvn.wide_ptr_same_provenance.GVN.panic-abort.diff
index 1b305e746f5e..0165136fda4c 100644
--- a/tests/mir-opt/gvn.wide_ptr_same_provenance.GVN.panic-abort.diff
+++ b/tests/mir-opt/gvn.wide_ptr_same_provenance.GVN.panic-abort.diff
@@ -89,6 +89,7 @@
 -         StorageDead(_4);
 +         _3 = copy _4;
 +         nop;
+          StorageDead(_8);
           StorageDead(_7);
           StorageDead(_5);
           StorageLive(_10);
@@ -116,6 +117,7 @@
 -         StorageDead(_11);
 +         _10 = copy _11;
 +         nop;
+          StorageDead(_15);
           StorageDead(_14);
           StorageDead(_12);
           StorageLive(_17);
@@ -251,9 +253,7 @@
           StorageDead(_43);
           StorageDead(_42);
           _0 = const ();
-          StorageDead(_15);
           StorageDead(_10);
-          StorageDead(_8);
           StorageDead(_3);
           StorageDead(_1);
           return;
diff --git a/tests/mir-opt/gvn.wide_ptr_same_provenance.GVN.panic-unwind.diff b/tests/mir-opt/gvn.wide_ptr_same_provenance.GVN.panic-unwind.diff
index e418ecf25bd4..bbaab46b4756 100644
--- a/tests/mir-opt/gvn.wide_ptr_same_provenance.GVN.panic-unwind.diff
+++ b/tests/mir-opt/gvn.wide_ptr_same_provenance.GVN.panic-unwind.diff
@@ -89,6 +89,7 @@
 -         StorageDead(_4);
 +         _3 = copy _4;
 +         nop;
+          StorageDead(_8);
           StorageDead(_7);
           StorageDead(_5);
           StorageLive(_10);
@@ -116,6 +117,7 @@
 -         StorageDead(_11);
 +         _10 = copy _11;
 +         nop;
+          StorageDead(_15);
           StorageDead(_14);
           StorageDead(_12);
           StorageLive(_17);
@@ -251,9 +253,7 @@
           StorageDead(_43);
           StorageDead(_42);
           _0 = const ();
-          StorageDead(_15);
           StorageDead(_10);
-          StorageDead(_8);
           StorageDead(_3);
           StorageDead(_1);
           return;
diff --git a/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-abort.diff b/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-abort.diff
index 4ca8dbbc76f0..4c1b25c786ef 100644
--- a/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-abort.diff
+++ b/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-abort.diff
@@ -41,13 +41,6 @@
 +                 let mut _30: ();
 +                 let mut _31: u32;
 +                 let mut _32: &mut {async fn body of ActionPermit<'_, T>::perform()};
-+                 let mut _33: &mut {async fn body of ActionPermit<'_, T>::perform()};
-+                 let mut _34: &mut {async fn body of ActionPermit<'_, T>::perform()};
-+                 let mut _35: &mut {async fn body of ActionPermit<'_, T>::perform()};
-+                 let mut _36: &mut {async fn body of ActionPermit<'_, T>::perform()};
-+                 let mut _37: &mut {async fn body of ActionPermit<'_, T>::perform()};
-+                 let mut _38: &mut {async fn body of ActionPermit<'_, T>::perform()};
-+                 let mut _39: &mut {async fn body of ActionPermit<'_, T>::perform()};
 +                 scope 7 {
 +                     let mut _15: std::future::Ready<()>;
 +                     scope 8 {
@@ -57,37 +50,37 @@
 +                         scope 12 (inlined Pin::<&mut std::future::Ready<()>>::new_unchecked) {
 +                         }
 +                         scope 13 (inlined  as Future>::poll) {
-+                             let mut _41: ();
-+                             let mut _42: std::option::Option<()>;
-+                             let mut _43: &mut std::option::Option<()>;
-+                             let mut _44: &mut std::future::Ready<()>;
-+                             let mut _45: &mut std::pin::Pin<&mut std::future::Ready<()>>;
++                             let mut _34: ();
++                             let mut _35: std::option::Option<()>;
++                             let mut _36: &mut std::option::Option<()>;
++                             let mut _37: &mut std::future::Ready<()>;
++                             let mut _38: &mut std::pin::Pin<&mut std::future::Ready<()>>;
 +                             scope 14 (inlined > as DerefMut>::deref_mut) {
-+                                 let mut _46: *mut std::pin::helper::PinHelper<&mut std::future::Ready<()>>;
-+                                 let mut _47: *mut std::pin::Pin<&mut std::future::Ready<()>>;
++                                 let mut _39: *mut std::pin::helper::PinHelper<&mut std::future::Ready<()>>;
++                                 let mut _40: *mut std::pin::Pin<&mut std::future::Ready<()>>;
 +                                 scope 15 (inlined > as pin::helper::PinDerefMutHelper>::deref_mut) {
-+                                     let mut _48: &mut &mut std::future::Ready<()>;
++                                     let mut _41: &mut &mut std::future::Ready<()>;
 +                                     scope 16 (inlined <&mut std::future::Ready<()> as DerefMut>::deref_mut) {
 +                                     }
 +                                 }
 +                             }
 +                             scope 17 (inlined Option::<()>::take) {
-+                                 let mut _49: std::option::Option<()>;
++                                 let mut _42: std::option::Option<()>;
 +                                 scope 18 (inlined std::mem::replace::>) {
 +                                     scope 19 {
 +                                     }
 +                                 }
 +                             }
 +                             scope 20 (inlined #[track_caller] Option::<()>::expect) {
-+                                 let mut _50: isize;
-+                                 let mut _51: !;
++                                 let mut _43: isize;
++                                 let mut _44: !;
 +                                 scope 21 {
 +                                 }
 +                             }
 +                         }
 +                     }
 +                     scope 10 (inlined ready::<()>) {
-+                         let mut _40: std::option::Option<()>;
++                         let mut _33: std::option::Option<()>;
 +                     }
 +                     scope 11 (inlined  as IntoFuture>::into_future) {
 +                     }
@@ -132,13 +125,6 @@
 +         StorageLive(_30);
 +         StorageLive(_31);
 +         StorageLive(_32);
-+         StorageLive(_33);
-+         StorageLive(_34);
-+         StorageLive(_35);
-+         StorageLive(_36);
-+         StorageLive(_37);
-+         StorageLive(_38);
-+         StorageLive(_39);
 +         _32 = copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()});
 +         _31 = discriminant((*_32));
 +         switchInt(move _31) -> [0: bb3, 1: bb10, 3: bb9, otherwise: bb5];
@@ -151,13 +137,6 @@
 +     }
 + 
 +     bb2: {
-+         StorageDead(_39);
-+         StorageDead(_38);
-+         StorageDead(_37);
-+         StorageDead(_36);
-+         StorageDead(_35);
-+         StorageDead(_34);
-+         StorageDead(_33);
 +         StorageDead(_32);
 +         StorageDead(_31);
 +         StorageDead(_30);
@@ -175,22 +154,19 @@
       }
   
 +     bb3: {
-+         _33 = copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()});
-+         _34 = copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()});
-+         (((*_33) as variant#3).0: ActionPermit<'_, T>) = move ((*_34).0: ActionPermit<'_, T>);
++         (((*_32) as variant#3).0: ActionPermit<'_, T>) = move ((*_32).0: ActionPermit<'_, T>);
 +         StorageLive(_12);
 +         StorageLive(_13);
 +         StorageLive(_14);
 +         _14 = ();
-+         StorageLive(_40);
-+         _40 = Option::<()>::Some(copy _14);
-+         _13 = std::future::Ready::<()>(move _40);
-+         StorageDead(_40);
++         StorageLive(_33);
++         _33 = Option::<()>::Some(copy _14);
++         _13 = std::future::Ready::<()>(move _33);
++         StorageDead(_33);
 +         StorageDead(_14);
 +         _12 = move _13;
 +         StorageDead(_13);
-+         _35 = copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()});
-+         (((*_35) as variant#3).1: std::future::Ready<()>) = move _12;
++         (((*_32) as variant#3).1: std::future::Ready<()>) = move _12;
 +         goto -> bb4;
 +     }
 + 
@@ -202,8 +178,7 @@
 +         StorageLive(_19);
 +         StorageLive(_20);
 +         StorageLive(_21);
-+         _36 = copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()});
-+         _21 = &mut (((*_36) as variant#3).1: std::future::Ready<()>);
++         _21 = &mut (((*_32) as variant#3).1: std::future::Ready<()>);
 +         _20 = &mut (*_21);
 +         _19 = Pin::<&mut std::future::Ready<()>> { pointer: copy _20 };
 +         StorageDead(_20);
@@ -214,24 +189,24 @@
 +         _23 = move _24;
 +         _22 = &mut (*_23);
 +         StorageDead(_24);
++         StorageLive(_37);
++         StorageLive(_39);
 +         StorageLive(_44);
-+         StorageLive(_46);
-+         StorageLive(_51);
-+         StorageLive(_41);
++         StorageLive(_34);
++         StorageLive(_35);
++         StorageLive(_40);
++         _40 = &raw mut _19;
++         _39 = copy _40 as *mut std::pin::helper::PinHelper<&mut std::future::Ready<()>> (PtrToPtr);
++         StorageDead(_40);
++         _37 = copy ((*_39).0: &mut std::future::Ready<()>);
 +         StorageLive(_42);
-+         StorageLive(_47);
-+         _47 = &raw mut _19;
-+         _46 = copy _47 as *mut std::pin::helper::PinHelper<&mut std::future::Ready<()>> (PtrToPtr);
-+         StorageDead(_47);
-+         _44 = copy ((*_46).0: &mut std::future::Ready<()>);
-+         StorageLive(_49);
-+         _49 = Option::<()>::None;
-+         _42 = copy ((*_44).0: std::option::Option<()>);
-+         ((*_44).0: std::option::Option<()>) = copy _49;
-+         StorageDead(_49);
-+         StorageLive(_50);
-+         _50 = discriminant(_42);
-+         switchInt(move _50) -> [0: bb11, 1: bb12, otherwise: bb5];
++         _42 = Option::<()>::None;
++         _35 = copy ((*_37).0: std::option::Option<()>);
++         ((*_37).0: std::option::Option<()>) = copy _42;
++         StorageDead(_42);
++         StorageLive(_43);
++         _43 = discriminant(_35);
++         switchInt(move _43) -> [0: bb11, 1: bb12, otherwise: bb5];
       }
 + 
 +     bb5: {
@@ -251,8 +226,7 @@
 +         StorageDead(_12);
 +         StorageDead(_28);
 +         StorageDead(_29);
-+         _37 = copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()});
-+         discriminant((*_37)) = 3;
++         discriminant((*_32)) = 3;
 +         goto -> bb2;
 +     }
 + 
@@ -266,14 +240,12 @@
 +         StorageDead(_18);
 +         StorageDead(_17);
 +         StorageDead(_12);
-+         _38 = copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()});
-+         drop((((*_38) as variant#3).0: ActionPermit<'_, T>)) -> [return: bb8, unwind unreachable];
++         drop((((*_32) as variant#3).0: ActionPermit<'_, T>)) -> [return: bb8, unwind unreachable];
 +     }
 + 
 +     bb8: {
 +         _7 = Poll::<()>::Ready(move _30);
-+         _39 = copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()});
-+         discriminant((*_39)) = 1;
++         discriminant((*_32)) = 1;
 +         goto -> bb2;
 +     }
 + 
@@ -294,18 +266,18 @@
 +     }
 + 
 +     bb11: {
-+         _51 = option::expect_failed(const "`Ready` polled after completion") -> unwind unreachable;
++         _44 = option::expect_failed(const "`Ready` polled after completion") -> unwind unreachable;
 +     }
 + 
 +     bb12: {
-+         _41 = move ((_42 as Some).0: ());
-+         StorageDead(_50);
-+         StorageDead(_42);
-+         _18 = Poll::<()>::Ready(move _41);
-+         StorageDead(_41);
-+         StorageDead(_51);
-+         StorageDead(_46);
++         _34 = move ((_35 as Some).0: ());
++         StorageDead(_43);
++         StorageDead(_35);
++         _18 = Poll::<()>::Ready(move _34);
++         StorageDead(_34);
 +         StorageDead(_44);
++         StorageDead(_39);
++         StorageDead(_37);
 +         StorageDead(_22);
 +         StorageDead(_19);
 +         _25 = discriminant(_18);
diff --git a/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff b/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff
index 6ce8693007b9..59417ce64651 100644
--- a/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff
+++ b/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff
@@ -41,15 +41,6 @@
 +                 let mut _30: ();
 +                 let mut _31: u32;
 +                 let mut _32: &mut {async fn body of ActionPermit<'_, T>::perform()};
-+                 let mut _33: &mut {async fn body of ActionPermit<'_, T>::perform()};
-+                 let mut _34: &mut {async fn body of ActionPermit<'_, T>::perform()};
-+                 let mut _35: &mut {async fn body of ActionPermit<'_, T>::perform()};
-+                 let mut _36: &mut {async fn body of ActionPermit<'_, T>::perform()};
-+                 let mut _37: &mut {async fn body of ActionPermit<'_, T>::perform()};
-+                 let mut _38: &mut {async fn body of ActionPermit<'_, T>::perform()};
-+                 let mut _39: &mut {async fn body of ActionPermit<'_, T>::perform()};
-+                 let mut _40: &mut {async fn body of ActionPermit<'_, T>::perform()};
-+                 let mut _41: &mut {async fn body of ActionPermit<'_, T>::perform()};
 +                 scope 7 {
 +                     let mut _15: std::future::Ready<()>;
 +                     scope 8 {
@@ -59,37 +50,37 @@
 +                         scope 12 (inlined Pin::<&mut std::future::Ready<()>>::new_unchecked) {
 +                         }
 +                         scope 13 (inlined  as Future>::poll) {
-+                             let mut _43: ();
-+                             let mut _44: std::option::Option<()>;
-+                             let mut _45: &mut std::option::Option<()>;
-+                             let mut _46: &mut std::future::Ready<()>;
-+                             let mut _47: &mut std::pin::Pin<&mut std::future::Ready<()>>;
++                             let mut _34: ();
++                             let mut _35: std::option::Option<()>;
++                             let mut _36: &mut std::option::Option<()>;
++                             let mut _37: &mut std::future::Ready<()>;
++                             let mut _38: &mut std::pin::Pin<&mut std::future::Ready<()>>;
 +                             scope 14 (inlined > as DerefMut>::deref_mut) {
-+                                 let mut _48: *mut std::pin::helper::PinHelper<&mut std::future::Ready<()>>;
-+                                 let mut _49: *mut std::pin::Pin<&mut std::future::Ready<()>>;
++                                 let mut _39: *mut std::pin::helper::PinHelper<&mut std::future::Ready<()>>;
++                                 let mut _40: *mut std::pin::Pin<&mut std::future::Ready<()>>;
 +                                 scope 15 (inlined > as pin::helper::PinDerefMutHelper>::deref_mut) {
-+                                     let mut _50: &mut &mut std::future::Ready<()>;
++                                     let mut _41: &mut &mut std::future::Ready<()>;
 +                                     scope 16 (inlined <&mut std::future::Ready<()> as DerefMut>::deref_mut) {
 +                                     }
 +                                 }
 +                             }
 +                             scope 17 (inlined Option::<()>::take) {
-+                                 let mut _51: std::option::Option<()>;
++                                 let mut _42: std::option::Option<()>;
 +                                 scope 18 (inlined std::mem::replace::>) {
 +                                     scope 19 {
 +                                     }
 +                                 }
 +                             }
 +                             scope 20 (inlined #[track_caller] Option::<()>::expect) {
-+                                 let mut _52: isize;
-+                                 let mut _53: !;
++                                 let mut _43: isize;
++                                 let mut _44: !;
 +                                 scope 21 {
 +                                 }
 +                             }
 +                         }
 +                     }
 +                     scope 10 (inlined ready::<()>) {
-+                         let mut _42: std::option::Option<()>;
++                         let mut _33: std::option::Option<()>;
 +                     }
 +                     scope 11 (inlined  as IntoFuture>::into_future) {
 +                     }
@@ -134,15 +125,6 @@
 +         StorageLive(_30);
 +         StorageLive(_31);
 +         StorageLive(_32);
-+         StorageLive(_33);
-+         StorageLive(_34);
-+         StorageLive(_35);
-+         StorageLive(_36);
-+         StorageLive(_37);
-+         StorageLive(_38);
-+         StorageLive(_39);
-+         StorageLive(_40);
-+         StorageLive(_41);
 +         _32 = copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()});
 +         _31 = discriminant((*_32));
 +         switchInt(move _31) -> [0: bb5, 1: bb15, 2: bb14, 3: bb13, otherwise: bb7];
@@ -163,15 +145,6 @@
 +     }
 + 
 +     bb4: {
-+         StorageDead(_41);
-+         StorageDead(_40);
-+         StorageDead(_39);
-+         StorageDead(_38);
-+         StorageDead(_37);
-+         StorageDead(_36);
-+         StorageDead(_35);
-+         StorageDead(_34);
-+         StorageDead(_33);
 +         StorageDead(_32);
 +         StorageDead(_31);
 +         StorageDead(_30);
@@ -192,22 +165,19 @@
 -         StorageDead(_2);
 -         return;
 +     bb5: {
-+         _33 = copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()});
-+         _34 = copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()});
-+         (((*_33) as variant#3).0: ActionPermit<'_, T>) = move ((*_34).0: ActionPermit<'_, T>);
++         (((*_32) as variant#3).0: ActionPermit<'_, T>) = move ((*_32).0: ActionPermit<'_, T>);
 +         StorageLive(_12);
 +         StorageLive(_13);
 +         StorageLive(_14);
 +         _14 = ();
-+         StorageLive(_42);
-+         _42 = Option::<()>::Some(copy _14);
-+         _13 = std::future::Ready::<()>(move _42);
-+         StorageDead(_42);
++         StorageLive(_33);
++         _33 = Option::<()>::Some(copy _14);
++         _13 = std::future::Ready::<()>(move _33);
++         StorageDead(_33);
 +         StorageDead(_14);
 +         _12 = move _13;
 +         StorageDead(_13);
-+         _35 = copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()});
-+         (((*_35) as variant#3).1: std::future::Ready<()>) = move _12;
++         (((*_32) as variant#3).1: std::future::Ready<()>) = move _12;
 +         goto -> bb6;
       }
   
@@ -219,8 +189,7 @@
 +         StorageLive(_19);
 +         StorageLive(_20);
 +         StorageLive(_21);
-+         _36 = copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()});
-+         _21 = &mut (((*_36) as variant#3).1: std::future::Ready<()>);
++         _21 = &mut (((*_32) as variant#3).1: std::future::Ready<()>);
 +         _20 = &mut (*_21);
 +         _19 = Pin::<&mut std::future::Ready<()>> { pointer: copy _20 };
 +         StorageDead(_20);
@@ -231,24 +200,24 @@
 +         _23 = move _24;
 +         _22 = &mut (*_23);
 +         StorageDead(_24);
-+         StorageLive(_46);
-+         StorageLive(_48);
-+         StorageLive(_53);
-+         StorageLive(_43);
++         StorageLive(_37);
++         StorageLive(_39);
 +         StorageLive(_44);
-+         StorageLive(_49);
-+         _49 = &raw mut _19;
-+         _48 = copy _49 as *mut std::pin::helper::PinHelper<&mut std::future::Ready<()>> (PtrToPtr);
-+         StorageDead(_49);
-+         _46 = copy ((*_48).0: &mut std::future::Ready<()>);
-+         StorageLive(_51);
-+         _51 = Option::<()>::None;
-+         _44 = copy ((*_46).0: std::option::Option<()>);
-+         ((*_46).0: std::option::Option<()>) = copy _51;
-+         StorageDead(_51);
-+         StorageLive(_52);
-+         _52 = discriminant(_44);
-+         switchInt(move _52) -> [0: bb16, 1: bb17, otherwise: bb7];
++         StorageLive(_34);
++         StorageLive(_35);
++         StorageLive(_40);
++         _40 = &raw mut _19;
++         _39 = copy _40 as *mut std::pin::helper::PinHelper<&mut std::future::Ready<()>> (PtrToPtr);
++         StorageDead(_40);
++         _37 = copy ((*_39).0: &mut std::future::Ready<()>);
++         StorageLive(_42);
++         _42 = Option::<()>::None;
++         _35 = copy ((*_37).0: std::option::Option<()>);
++         ((*_37).0: std::option::Option<()>) = copy _42;
++         StorageDead(_42);
++         StorageLive(_43);
++         _43 = discriminant(_35);
++         switchInt(move _43) -> [0: bb16, 1: bb17, otherwise: bb7];
       }
   
 -     bb6 (cleanup): {
@@ -270,8 +239,7 @@
 +         StorageDead(_12);
 +         StorageDead(_28);
 +         StorageDead(_29);
-+         _37 = copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()});
-+         discriminant((*_37)) = 3;
++         discriminant((*_32)) = 3;
 +         goto -> bb4;
 +     }
 + 
@@ -285,14 +253,12 @@
 +         StorageDead(_18);
 +         StorageDead(_17);
 +         StorageDead(_12);
-+         _38 = copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()});
-+         drop((((*_38) as variant#3).0: ActionPermit<'_, T>)) -> [return: bb10, unwind: bb12];
++         drop((((*_32) as variant#3).0: ActionPermit<'_, T>)) -> [return: bb10, unwind: bb12];
 +     }
 + 
 +     bb10: {
 +         _7 = Poll::<()>::Ready(move _30);
-+         _39 = copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()});
-+         discriminant((*_39)) = 1;
++         discriminant((*_32)) = 1;
 +         goto -> bb4;
 +     }
 + 
@@ -304,13 +270,11 @@
 +         StorageDead(_18);
 +         StorageDead(_17);
 +         StorageDead(_12);
-+         _40 = copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()});
-+         drop((((*_40) as variant#3).0: ActionPermit<'_, T>)) -> [return: bb12, unwind terminate(cleanup)];
++         drop((((*_32) as variant#3).0: ActionPermit<'_, T>)) -> [return: bb12, unwind terminate(cleanup)];
 +     }
 + 
 +     bb12 (cleanup): {
-+         _41 = copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()});
-+         discriminant((*_41)) = 2;
++         discriminant((*_32)) = 2;
 +         goto -> bb2;
 +     }
 + 
@@ -335,18 +299,18 @@
 +     }
 + 
 +     bb16: {
-+         _53 = option::expect_failed(const "`Ready` polled after completion") -> bb11;
++         _44 = option::expect_failed(const "`Ready` polled after completion") -> bb11;
 +     }
 + 
 +     bb17: {
-+         _43 = move ((_44 as Some).0: ());
-+         StorageDead(_52);
-+         StorageDead(_44);
-+         _18 = Poll::<()>::Ready(move _43);
++         _34 = move ((_35 as Some).0: ());
 +         StorageDead(_43);
-+         StorageDead(_53);
-+         StorageDead(_48);
-+         StorageDead(_46);
++         StorageDead(_35);
++         _18 = Poll::<()>::Ready(move _34);
++         StorageDead(_34);
++         StorageDead(_44);
++         StorageDead(_39);
++         StorageDead(_37);
 +         StorageDead(_22);
 +         StorageDead(_19);
 +         _25 = discriminant(_18);
diff --git a/tests/mir-opt/issue_91633.fun.built.after.mir b/tests/mir-opt/issue_91633.fun.built.after.mir
index d2fc438d3e81..7468e591b37b 100644
--- a/tests/mir-opt/issue_91633.fun.built.after.mir
+++ b/tests/mir-opt/issue_91633.fun.built.after.mir
@@ -23,8 +23,8 @@ fn fun(_1: &[T]) -> &T {
     bb1: {
         _2 = &(*_1)[_3];
         FakeRead(ForLet(None), _2);
-        _0 = &(*_2);
         StorageDead(_3);
+        _0 = &(*_2);
         StorageDead(_2);
         return;
     }
diff --git a/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.32bit.mir b/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.32bit.mir
index 42b388033360..c069ce3fdf3c 100644
--- a/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.32bit.mir
+++ b/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.32bit.mir
@@ -5,20 +5,20 @@
 | '?1 | Local | ['?1]
 |
 | Inferred Region Values
-| '?0 | U0 | {bb0[0..=8], bb1[0..=7], bb2[0..=3], bb3[0..=3], bb4[0..=1], bb5[0..=2], bb6[0..=5], bb7[0], '?0, '?1}
-| '?1 | U0 | {bb0[0..=8], bb1[0..=7], bb2[0..=3], bb3[0..=3], bb4[0..=1], bb5[0..=2], bb6[0..=5], bb7[0], '?1}
-| '?2 | U0 | {bb1[0..=7], bb2[0..=2]}
-| '?3 | U0 | {bb1[1..=7], bb2[0..=2]}
-| '?4 | U0 | {bb1[4..=7], bb2[0..=2]}
+| '?0 | U0 | {bb0[0..=8], bb1[0..=8], bb2[0..=3], bb3[0..=3], bb4[0..=1], bb5[0..=2], bb6[0..=4], bb7[0], '?0, '?1}
+| '?1 | U0 | {bb0[0..=8], bb1[0..=8], bb2[0..=3], bb3[0..=3], bb4[0..=1], bb5[0..=2], bb6[0..=4], bb7[0], '?1}
+| '?2 | U0 | {bb1[0..=8], bb2[0..=2]}
+| '?3 | U0 | {bb1[1..=8], bb2[0..=2]}
+| '?4 | U0 | {bb1[5..=8], bb2[0..=2]}
 |
 | Inference Constraints
-| '?0 live at {bb0[0..=8], bb1[0..=7], bb2[0..=3], bb3[0..=3], bb4[0..=1], bb5[0..=2], bb6[0..=5], bb7[0]}
-| '?1 live at {bb0[0..=8], bb1[0..=7], bb2[0..=3], bb3[0..=3], bb4[0..=1], bb5[0..=2], bb6[0..=5], bb7[0]}
+| '?0 live at {bb0[0..=8], bb1[0..=8], bb2[0..=3], bb3[0..=3], bb4[0..=1], bb5[0..=2], bb6[0..=4], bb7[0]}
+| '?1 live at {bb0[0..=8], bb1[0..=8], bb2[0..=3], bb3[0..=3], bb4[0..=1], bb5[0..=2], bb6[0..=4], bb7[0]}
 | '?2 live at {bb1[0]}
-| '?3 live at {bb1[1..=3]}
-| '?4 live at {bb1[4..=7], bb2[0..=2]}
+| '?3 live at {bb1[1..=4]}
+| '?4 live at {bb1[5..=8], bb2[0..=2]}
 | '?2: '?3 due to Assignment at Single(bb1[0]) ($DIR/region_subtyping_basic.rs:19:13: 19:18 (#0)
-| '?3: '?4 due to Assignment at Single(bb1[3]) ($DIR/region_subtyping_basic.rs:20:13: 20:14 (#0)
+| '?3: '?4 due to Assignment at Single(bb1[4]) ($DIR/region_subtyping_basic.rs:20:13: 20:14 (#0)
 |
 | Borrows
 | bw0: issued at bb1[0] in '?2
@@ -59,6 +59,7 @@ fn main() -> () {
     bb1: {
         _2 = &'?2 _1[_3];
         FakeRead(ForLet(None), _2);
+        StorageDead(_3);
         StorageLive(_5);
         _5 = copy _2;
         FakeRead(ForLet(None), _5);
@@ -95,7 +96,6 @@ fn main() -> () {
     bb6: {
         StorageDead(_6);
         StorageDead(_5);
-        StorageDead(_3);
         StorageDead(_2);
         StorageDead(_1);
         return;
diff --git a/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.64bit.mir b/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.64bit.mir
index 15395fd470e9..a866521e7c97 100644
--- a/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.64bit.mir
+++ b/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.64bit.mir
@@ -5,20 +5,20 @@
 | '?1 | Local | ['?1]
 |
 | Inferred Region Values
-| '?0 | U0 | {bb0[0..=8], bb1[0..=7], bb2[0..=3], bb3[0..=3], bb4[0..=1], bb5[0..=2], bb6[0..=5], bb7[0], '?0, '?1}
-| '?1 | U0 | {bb0[0..=8], bb1[0..=7], bb2[0..=3], bb3[0..=3], bb4[0..=1], bb5[0..=2], bb6[0..=5], bb7[0], '?1}
-| '?2 | U0 | {bb1[0..=7], bb2[0..=2]}
-| '?3 | U0 | {bb1[1..=7], bb2[0..=2]}
-| '?4 | U0 | {bb1[4..=7], bb2[0..=2]}
+| '?0 | U0 | {bb0[0..=8], bb1[0..=8], bb2[0..=3], bb3[0..=3], bb4[0..=1], bb5[0..=2], bb6[0..=4], bb7[0], '?0, '?1}
+| '?1 | U0 | {bb0[0..=8], bb1[0..=8], bb2[0..=3], bb3[0..=3], bb4[0..=1], bb5[0..=2], bb6[0..=4], bb7[0], '?1}
+| '?2 | U0 | {bb1[0..=8], bb2[0..=2]}
+| '?3 | U0 | {bb1[1..=8], bb2[0..=2]}
+| '?4 | U0 | {bb1[5..=8], bb2[0..=2]}
 |
 | Inference Constraints
-| '?0 live at {bb0[0..=8], bb1[0..=7], bb2[0..=3], bb3[0..=3], bb4[0..=1], bb5[0..=2], bb6[0..=5], bb7[0]}
-| '?1 live at {bb0[0..=8], bb1[0..=7], bb2[0..=3], bb3[0..=3], bb4[0..=1], bb5[0..=2], bb6[0..=5], bb7[0]}
+| '?0 live at {bb0[0..=8], bb1[0..=8], bb2[0..=3], bb3[0..=3], bb4[0..=1], bb5[0..=2], bb6[0..=4], bb7[0]}
+| '?1 live at {bb0[0..=8], bb1[0..=8], bb2[0..=3], bb3[0..=3], bb4[0..=1], bb5[0..=2], bb6[0..=4], bb7[0]}
 | '?2 live at {bb1[0]}
-| '?3 live at {bb1[1..=3]}
-| '?4 live at {bb1[4..=7], bb2[0..=2]}
+| '?3 live at {bb1[1..=4]}
+| '?4 live at {bb1[5..=8], bb2[0..=2]}
 | '?2: '?3 due to Assignment at Single(bb1[0]) ($DIR/region_subtyping_basic.rs:19:13: 19:18 (#0)
-| '?3: '?4 due to Assignment at Single(bb1[3]) ($DIR/region_subtyping_basic.rs:20:13: 20:14 (#0)
+| '?3: '?4 due to Assignment at Single(bb1[4]) ($DIR/region_subtyping_basic.rs:20:13: 20:14 (#0)
 |
 | Borrows
 | bw0: issued at bb1[0] in '?2
@@ -59,6 +59,7 @@ fn main() -> () {
     bb1: {
         _2 = &'?2 _1[_3];
         FakeRead(ForLet(None), _2);
+        StorageDead(_3);
         StorageLive(_5);
         _5 = copy _2;
         FakeRead(ForLet(None), _5);
@@ -95,7 +96,6 @@ fn main() -> () {
     bb6: {
         StorageDead(_6);
         StorageDead(_5);
-        StorageDead(_3);
         StorageDead(_2);
         StorageDead(_1);
         return;
diff --git a/tests/run-make/emit-shared-files/rmake.rs b/tests/run-make/emit-shared-files/rmake.rs
index 911ceb3adca4..bd868d4fd19e 100644
--- a/tests/run-make/emit-shared-files/rmake.rs
+++ b/tests/run-make/emit-shared-files/rmake.rs
@@ -68,7 +68,7 @@ fn main() {
 
     rustdoc()
         .arg("-Zunstable-options")
-        .arg("--emit=toolchain-shared-resources,unversioned-shared-resources")
+        .arg("--emit=toolchain-shared-resources")
         .out_dir("all-shared")
         .arg("--resource-suffix=-xxx")
         .args(&["--extend-css", "z.css"])
diff --git a/tests/run-make/rustdoc-default-output/output-default.stdout b/tests/run-make/rustdoc-default-output/output-default.stdout
index badbc0b6d15b..3afe0ca3ca8f 100644
--- a/tests/run-make/rustdoc-default-output/output-default.stdout
+++ b/tests/run-make/rustdoc-default-output/output-default.stdout
@@ -150,7 +150,7 @@ Options:
         --generate-redirect-map 
                         Generate JSON file at the top level instead of
                         generating HTML redirection files
-        --emit [unversioned-shared-resources,toolchain-shared-resources,invocation-specific,dep-info]
+        --emit [toolchain-shared-resources,invocation-specific,dep-info]
                         Comma separated list of types of output for rustdoc to
                         emit
         --no-run        Compile doctests without running them
diff --git a/tests/rustdoc-js/auxiliary/merged-dep.rs b/tests/rustdoc-js/auxiliary/merged-dep.rs
new file mode 100644
index 000000000000..fadeb6c65270
--- /dev/null
+++ b/tests/rustdoc-js/auxiliary/merged-dep.rs
@@ -0,0 +1,6 @@
+//@ unique-doc-out-dir
+//@ doc-flags:--merge=none
+//@ doc-flags:--parts-out-dir=info/doc.parts/merged-dep
+//@ doc-flags:-Zunstable-options
+
+pub struct Dep;
diff --git a/tests/rustdoc-js/merged-doc.js b/tests/rustdoc-js/merged-doc.js
new file mode 100644
index 000000000000..4380abb5912e
--- /dev/null
+++ b/tests/rustdoc-js/merged-doc.js
@@ -0,0 +1,15 @@
+const EXPECTED = [
+    {
+        'query': 'merged_doc::Doc',
+        'others': [
+            { 'path': 'merged_doc', 'name': 'Doc' },
+        ],
+    },
+    {
+        'query': 'merged_dep::Dep',
+        'others': REVISION === "nomerge" ? [] :
+            [
+                { 'path': 'merged_dep', 'name': 'Dep' },
+            ],
+    },
+];
diff --git a/tests/rustdoc-js/merged-doc.rs b/tests/rustdoc-js/merged-doc.rs
new file mode 100644
index 000000000000..ef7ce4b1fd36
--- /dev/null
+++ b/tests/rustdoc-js/merged-doc.rs
@@ -0,0 +1,10 @@
+//@ revisions: merge nomerge
+//@ aux-build:merged-dep.rs
+//@ build-aux-docs
+//@[merge] doc-flags:--merge=finalize
+//@[merge] doc-flags:--include-parts-dir=info/doc.parts/merged-dep
+//@[merge] doc-flags:-Zunstable-options
+
+extern crate merged_dep;
+
+pub struct Doc;
diff --git a/tests/rustdoc-ui/deref-generic.rs b/tests/rustdoc-ui/deref/deref-generic.rs
similarity index 100%
rename from tests/rustdoc-ui/deref-generic.rs
rename to tests/rustdoc-ui/deref/deref-generic.rs
diff --git a/tests/rustdoc-ui/ice-blanket-impl-56701.rs b/tests/rustdoc-ui/deref/ice-blanket-impl-56701.rs
similarity index 100%
rename from tests/rustdoc-ui/ice-blanket-impl-56701.rs
rename to tests/rustdoc-ui/deref/ice-blanket-impl-56701.rs
diff --git a/tests/rustdoc-ui/recursive-deref-ice.rs b/tests/rustdoc-ui/deref/recursive-deref-ice.rs
similarity index 100%
rename from tests/rustdoc-ui/recursive-deref-ice.rs
rename to tests/rustdoc-ui/deref/recursive-deref-ice.rs
diff --git a/tests/rustdoc-ui/auxiliary/issue-48414.rs b/tests/rustdoc-ui/intra-doc/auxiliary/issue-48414.rs
similarity index 100%
rename from tests/rustdoc-ui/auxiliary/issue-48414.rs
rename to tests/rustdoc-ui/intra-doc/auxiliary/issue-48414.rs
diff --git a/tests/rustdoc-ui/circular-intra-doc-link-48414.rs b/tests/rustdoc-ui/intra-doc/circular-intra-doc-link-48414.rs
similarity index 100%
rename from tests/rustdoc-ui/circular-intra-doc-link-48414.rs
rename to tests/rustdoc-ui/intra-doc/circular-intra-doc-link-48414.rs
diff --git a/tests/rustdoc-ui/disambiguator-endswith-named-suffix.rs b/tests/rustdoc-ui/intra-doc/disambiguator-endswith-named-suffix.rs
similarity index 100%
rename from tests/rustdoc-ui/disambiguator-endswith-named-suffix.rs
rename to tests/rustdoc-ui/intra-doc/disambiguator-endswith-named-suffix.rs
diff --git a/tests/rustdoc-ui/disambiguator-endswith-named-suffix.stderr b/tests/rustdoc-ui/intra-doc/disambiguator-endswith-named-suffix.stderr
similarity index 100%
rename from tests/rustdoc-ui/disambiguator-endswith-named-suffix.stderr
rename to tests/rustdoc-ui/intra-doc/disambiguator-endswith-named-suffix.stderr
diff --git a/tests/rustdoc-ui/custom_code_classes_in_docs-warning3.rs b/tests/rustdoc-ui/lints/custom_code_classes_in_docs-warning3.rs
similarity index 100%
rename from tests/rustdoc-ui/custom_code_classes_in_docs-warning3.rs
rename to tests/rustdoc-ui/lints/custom_code_classes_in_docs-warning3.rs
diff --git a/tests/rustdoc-ui/custom_code_classes_in_docs-warning3.stderr b/tests/rustdoc-ui/lints/custom_code_classes_in_docs-warning3.stderr
similarity index 100%
rename from tests/rustdoc-ui/custom_code_classes_in_docs-warning3.stderr
rename to tests/rustdoc-ui/lints/custom_code_classes_in_docs-warning3.stderr
diff --git a/tests/rustdoc-ui/diagnostic-width.rs b/tests/rustdoc-ui/lints/diagnostic-width.rs
similarity index 100%
rename from tests/rustdoc-ui/diagnostic-width.rs
rename to tests/rustdoc-ui/lints/diagnostic-width.rs
diff --git a/tests/rustdoc-ui/diagnostic-width.stderr b/tests/rustdoc-ui/lints/diagnostic-width.stderr
similarity index 100%
rename from tests/rustdoc-ui/diagnostic-width.stderr
rename to tests/rustdoc-ui/lints/diagnostic-width.stderr
diff --git a/tests/rustdoc-ui/include-str-bare-urls.rs b/tests/rustdoc-ui/lints/include-str-bare-urls.rs
similarity index 89%
rename from tests/rustdoc-ui/include-str-bare-urls.rs
rename to tests/rustdoc-ui/lints/include-str-bare-urls.rs
index f80e28e8ca70..83539ef62b3d 100644
--- a/tests/rustdoc-ui/include-str-bare-urls.rs
+++ b/tests/rustdoc-ui/lints/include-str-bare-urls.rs
@@ -12,6 +12,6 @@
 // If the stderr file changes, make sure the warning points at the URL!
 
 #![deny(rustdoc::bare_urls)]
-#![doc=include_str!("auxiliary/include-str-bare-urls.md")]
+#![doc=include_str!("../auxiliary/include-str-bare-urls.md")]
 
 //~? ERROR this URL is not a hyperlink
diff --git a/tests/rustdoc-ui/include-str-bare-urls.stderr b/tests/rustdoc-ui/lints/include-str-bare-urls.stderr
similarity index 91%
rename from tests/rustdoc-ui/include-str-bare-urls.stderr
rename to tests/rustdoc-ui/lints/include-str-bare-urls.stderr
index 53da2411874a..7771a051fe1b 100644
--- a/tests/rustdoc-ui/include-str-bare-urls.stderr
+++ b/tests/rustdoc-ui/lints/include-str-bare-urls.stderr
@@ -1,5 +1,5 @@
 error: this URL is not a hyperlink
-  --> $DIR/auxiliary/include-str-bare-urls.md:1:11
+  --> $DIR/../auxiliary/include-str-bare-urls.md:1:11
    |
 LL | HEADS UP! https://example.com MUST SHOW UP IN THE STDERR FILE!
    |           ^^^^^^^^^^^^^^^^^^^
diff --git a/tests/rustdoc-ui/redundant-explicit-links-123677.rs b/tests/rustdoc-ui/lints/redundant-explicit-links-123677.rs
similarity index 100%
rename from tests/rustdoc-ui/redundant-explicit-links-123677.rs
rename to tests/rustdoc-ui/lints/redundant-explicit-links-123677.rs
diff --git a/tests/rustdoc-ui/remap-path-prefix-lint.rs b/tests/rustdoc-ui/lints/remap-path-prefix-lint.rs
similarity index 100%
rename from tests/rustdoc-ui/remap-path-prefix-lint.rs
rename to tests/rustdoc-ui/lints/remap-path-prefix-lint.rs
diff --git a/tests/rustdoc-ui/remap-path-prefix-lint.stderr b/tests/rustdoc-ui/lints/remap-path-prefix-lint.stderr
similarity index 68%
rename from tests/rustdoc-ui/remap-path-prefix-lint.stderr
rename to tests/rustdoc-ui/lints/remap-path-prefix-lint.stderr
index d7c1bb1965d3..e8a88394ffd9 100644
--- a/tests/rustdoc-ui/remap-path-prefix-lint.stderr
+++ b/tests/rustdoc-ui/lints/remap-path-prefix-lint.stderr
@@ -1,11 +1,11 @@
 error: unopened HTML tag `script`
-  --> remapped_path/remap-path-prefix-lint.rs:9:5
+  --> remapped_path/lints/remap-path-prefix-lint.rs:9:5
    |
 LL | /// 
    |     ^^^^^^^^^
    |
 note: the lint level is defined here
-  --> remapped_path/remap-path-prefix-lint.rs:7:9
+  --> remapped_path/lints/remap-path-prefix-lint.rs:7:9
    |
 LL | #![deny(rustdoc::invalid_html_tags)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/rustdoc-ui/unescaped_backticks.rs b/tests/rustdoc-ui/lints/unescaped_backticks.rs
similarity index 100%
rename from tests/rustdoc-ui/unescaped_backticks.rs
rename to tests/rustdoc-ui/lints/unescaped_backticks.rs
diff --git a/tests/rustdoc-ui/unescaped_backticks.stderr b/tests/rustdoc-ui/lints/unescaped_backticks.stderr
similarity index 100%
rename from tests/rustdoc-ui/unescaped_backticks.stderr
rename to tests/rustdoc-ui/lints/unescaped_backticks.stderr
diff --git a/tests/rustdoc/duplicate-cfg.rs b/tests/rustdoc/doc-cfg/duplicate-cfg.rs
similarity index 100%
rename from tests/rustdoc/duplicate-cfg.rs
rename to tests/rustdoc/doc-cfg/duplicate-cfg.rs
diff --git a/tests/ui/abi/c-zst.powerpc-linux.stderr b/tests/ui/abi/c-zst.powerpc-linux.stderr
index e79b3fcec8b9..816addd79576 100644
--- a/tests/ui/abi/c-zst.powerpc-linux.stderr
+++ b/tests/ui/abi/c-zst.powerpc-linux.stderr
@@ -27,7 +27,7 @@ error: fn_abi_of(pass_zst) = FnAbi {
                    },
                    mode: Indirect {
                        attrs: ArgAttributes {
-                           regular: NoAlias | CapturesAddress | NonNull | NoUndef,
+                           regular: CapturesAddress | NoAlias | NonNull | NoUndef,
                            arg_ext: None,
                            pointee_size: Size(0 bytes),
                            pointee_align: Some(
diff --git a/tests/ui/abi/c-zst.s390x-linux.stderr b/tests/ui/abi/c-zst.s390x-linux.stderr
index e79b3fcec8b9..816addd79576 100644
--- a/tests/ui/abi/c-zst.s390x-linux.stderr
+++ b/tests/ui/abi/c-zst.s390x-linux.stderr
@@ -27,7 +27,7 @@ error: fn_abi_of(pass_zst) = FnAbi {
                    },
                    mode: Indirect {
                        attrs: ArgAttributes {
-                           regular: NoAlias | CapturesAddress | NonNull | NoUndef,
+                           regular: CapturesAddress | NoAlias | NonNull | NoUndef,
                            arg_ext: None,
                            pointee_size: Size(0 bytes),
                            pointee_align: Some(
diff --git a/tests/ui/abi/c-zst.sparc64-linux.stderr b/tests/ui/abi/c-zst.sparc64-linux.stderr
index e79b3fcec8b9..816addd79576 100644
--- a/tests/ui/abi/c-zst.sparc64-linux.stderr
+++ b/tests/ui/abi/c-zst.sparc64-linux.stderr
@@ -27,7 +27,7 @@ error: fn_abi_of(pass_zst) = FnAbi {
                    },
                    mode: Indirect {
                        attrs: ArgAttributes {
-                           regular: NoAlias | CapturesAddress | NonNull | NoUndef,
+                           regular: CapturesAddress | NoAlias | NonNull | NoUndef,
                            arg_ext: None,
                            pointee_size: Size(0 bytes),
                            pointee_align: Some(
diff --git a/tests/ui/abi/c-zst.x86_64-pc-windows-gnu.stderr b/tests/ui/abi/c-zst.x86_64-pc-windows-gnu.stderr
index e79b3fcec8b9..816addd79576 100644
--- a/tests/ui/abi/c-zst.x86_64-pc-windows-gnu.stderr
+++ b/tests/ui/abi/c-zst.x86_64-pc-windows-gnu.stderr
@@ -27,7 +27,7 @@ error: fn_abi_of(pass_zst) = FnAbi {
                    },
                    mode: Indirect {
                        attrs: ArgAttributes {
-                           regular: NoAlias | CapturesAddress | NonNull | NoUndef,
+                           regular: CapturesAddress | NoAlias | NonNull | NoUndef,
                            arg_ext: None,
                            pointee_size: Size(0 bytes),
                            pointee_align: Some(
diff --git a/tests/ui/abi/debug.generic.stderr b/tests/ui/abi/debug.generic.stderr
index fd4c43591425..04d6f50872a3 100644
--- a/tests/ui/abi/debug.generic.stderr
+++ b/tests/ui/abi/debug.generic.stderr
@@ -454,7 +454,7 @@ error: ABIs are not compatible
                    },
                    mode: Indirect {
                        attrs: ArgAttributes {
-                           regular: NoAlias | CapturesAddress | NonNull | NoUndef,
+                           regular: CapturesAddress | NoAlias | NonNull | NoUndef,
                            arg_ext: None,
                            pointee_size: Size(32 bytes),
                            pointee_align: Some(
@@ -527,7 +527,7 @@ error: ABIs are not compatible
                    },
                    mode: Indirect {
                        attrs: ArgAttributes {
-                           regular: NoAlias | CapturesAddress | NonNull | NoUndef,
+                           regular: CapturesAddress | NoAlias | NonNull | NoUndef,
                            arg_ext: None,
                            pointee_size: Size(128 bytes),
                            pointee_align: Some(
@@ -939,7 +939,7 @@ error: fn_abi_of(assoc_test) = FnAbi {
                    },
                    mode: Direct(
                        ArgAttributes {
-                           regular: NoAlias | NonNull | ReadOnly | NoUndef | CapturesReadOnly,
+                           regular: CapturesReadOnly | NoAlias | NonNull | ReadOnly | NoUndef,
                            arg_ext: None,
                            pointee_size: Size(2 bytes),
                            pointee_align: Some(
diff --git a/tests/ui/abi/debug.loongarch64.stderr b/tests/ui/abi/debug.loongarch64.stderr
index 95351b42092a..85c888c4fae0 100644
--- a/tests/ui/abi/debug.loongarch64.stderr
+++ b/tests/ui/abi/debug.loongarch64.stderr
@@ -454,7 +454,7 @@ error: ABIs are not compatible
                    },
                    mode: Indirect {
                        attrs: ArgAttributes {
-                           regular: NoAlias | CapturesAddress | NonNull | NoUndef,
+                           regular: CapturesAddress | NoAlias | NonNull | NoUndef,
                            arg_ext: None,
                            pointee_size: Size(32 bytes),
                            pointee_align: Some(
@@ -527,7 +527,7 @@ error: ABIs are not compatible
                    },
                    mode: Indirect {
                        attrs: ArgAttributes {
-                           regular: NoAlias | CapturesAddress | NonNull | NoUndef,
+                           regular: CapturesAddress | NoAlias | NonNull | NoUndef,
                            arg_ext: None,
                            pointee_size: Size(128 bytes),
                            pointee_align: Some(
@@ -939,7 +939,7 @@ error: fn_abi_of(assoc_test) = FnAbi {
                    },
                    mode: Direct(
                        ArgAttributes {
-                           regular: NoAlias | NonNull | ReadOnly | NoUndef | CapturesReadOnly,
+                           regular: CapturesReadOnly | NoAlias | NonNull | ReadOnly | NoUndef,
                            arg_ext: None,
                            pointee_size: Size(2 bytes),
                            pointee_align: Some(
diff --git a/tests/ui/abi/debug.riscv64.stderr b/tests/ui/abi/debug.riscv64.stderr
index 95351b42092a..85c888c4fae0 100644
--- a/tests/ui/abi/debug.riscv64.stderr
+++ b/tests/ui/abi/debug.riscv64.stderr
@@ -454,7 +454,7 @@ error: ABIs are not compatible
                    },
                    mode: Indirect {
                        attrs: ArgAttributes {
-                           regular: NoAlias | CapturesAddress | NonNull | NoUndef,
+                           regular: CapturesAddress | NoAlias | NonNull | NoUndef,
                            arg_ext: None,
                            pointee_size: Size(32 bytes),
                            pointee_align: Some(
@@ -527,7 +527,7 @@ error: ABIs are not compatible
                    },
                    mode: Indirect {
                        attrs: ArgAttributes {
-                           regular: NoAlias | CapturesAddress | NonNull | NoUndef,
+                           regular: CapturesAddress | NoAlias | NonNull | NoUndef,
                            arg_ext: None,
                            pointee_size: Size(128 bytes),
                            pointee_align: Some(
@@ -939,7 +939,7 @@ error: fn_abi_of(assoc_test) = FnAbi {
                    },
                    mode: Direct(
                        ArgAttributes {
-                           regular: NoAlias | NonNull | ReadOnly | NoUndef | CapturesReadOnly,
+                           regular: CapturesReadOnly | NoAlias | NonNull | ReadOnly | NoUndef,
                            arg_ext: None,
                            pointee_size: Size(2 bytes),
                            pointee_align: Some(
diff --git a/tests/ui/annotate-snippet/missing-type.stderr b/tests/ui/annotate-snippet/missing-type.stderr
index c16f022a77fa..5cc9cc9529f4 100644
--- a/tests/ui/annotate-snippet/missing-type.stderr
+++ b/tests/ui/annotate-snippet/missing-type.stderr
@@ -4,3 +4,18 @@ error[E0412]: cannot find type `Iter` in this scope
 LL |     let x: Iter;
    |            ^^^^ not found in this scope
    |
+help: consider importing one of these structs
+   |
+LL + use std::collections::binary_heap::Iter;
+   |
+LL + use std::collections::btree_map::Iter;
+   |
+LL + use std::collections::btree_set::Iter;
+   |
+LL + use std::collections::hash_map::Iter;
+   |
+   = and 9 other candidates
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0412`.
diff --git a/tests/ui/annotate-snippet/multiple-files.stderr b/tests/ui/annotate-snippet/multiple-files.stderr
index 4236ec811d04..ffdc9482bbf2 100644
--- a/tests/ui/annotate-snippet/multiple-files.stderr
+++ b/tests/ui/annotate-snippet/multiple-files.stderr
@@ -7,5 +7,8 @@ LL |     other_file::WithPrivateMethod.private_method();
   ::: $DIR/auxiliary/other_file.rs:5:5
    |
 LL |     fn private_method(&self) {}
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^ private method defined here
-   |
+   |     ------------------------ private method defined here
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0624`.
diff --git a/tests/ui/annotate-snippet/multispan.stderr b/tests/ui/annotate-snippet/multispan.stderr
index baed54c59a4e..8acb60e27a19 100644
--- a/tests/ui/annotate-snippet/multispan.stderr
+++ b/tests/ui/annotate-snippet/multispan.stderr
@@ -4,39 +4,90 @@ error: hello to you, too!
 LL |     hello!(hi);
    |     ^^^^^^^^^^
    |
+note: found these 'hi's
+  --> $DIR/multispan.rs:15:12
+   |
+LL |     hello!(hi);
+   |            ^^
+   = note: this error originates in the macro `hello` (in Nightly builds, run with -Z macro-backtrace for more info)
+
 error: hello to you, too!
   --> $DIR/multispan.rs:18:5
    |
 LL |     hello!(hi hi);
    |     ^^^^^^^^^^^^^
    |
+note: found these 'hi's
+  --> $DIR/multispan.rs:18:12
+   |
+LL |     hello!(hi hi);
+   |            ^^ ^^
+   = note: this error originates in the macro `hello` (in Nightly builds, run with -Z macro-backtrace for more info)
+
 error: hello to you, too!
   --> $DIR/multispan.rs:21:5
    |
 LL |     hello!(hi hi hi);
    |     ^^^^^^^^^^^^^^^^
    |
+note: found these 'hi's
+  --> $DIR/multispan.rs:21:12
+   |
+LL |     hello!(hi hi hi);
+   |            ^^ ^^ ^^
+   = note: this error originates in the macro `hello` (in Nightly builds, run with -Z macro-backtrace for more info)
+
 error: hello to you, too!
   --> $DIR/multispan.rs:24:5
    |
 LL |     hello!(hi hey hi yo hi beep beep hi hi);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
+note: found these 'hi's
+  --> $DIR/multispan.rs:24:12
+   |
+LL |     hello!(hi hey hi yo hi beep beep hi hi);
+   |            ^^     ^^    ^^           ^^ ^^
+   = note: this error originates in the macro `hello` (in Nightly builds, run with -Z macro-backtrace for more info)
+
 error: hello to you, too!
   --> $DIR/multispan.rs:25:5
    |
 LL |     hello!(hi there, hi how are you? hi... hi.);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
+note: found these 'hi's
+  --> $DIR/multispan.rs:25:12
+   |
+LL |     hello!(hi there, hi how are you? hi... hi.);
+   |            ^^        ^^              ^^    ^^
+   = note: this error originates in the macro `hello` (in Nightly builds, run with -Z macro-backtrace for more info)
+
 error: hello to you, too!
   --> $DIR/multispan.rs:26:5
    |
 LL |     hello!(whoah. hi di hi di ho);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
+note: found these 'hi's
+  --> $DIR/multispan.rs:26:19
+   |
+LL |     hello!(whoah. hi di hi di ho);
+   |                   ^^    ^^
+   = note: this error originates in the macro `hello` (in Nightly builds, run with -Z macro-backtrace for more info)
+
 error: hello to you, too!
   --> $DIR/multispan.rs:27:5
    |
 LL |     hello!(hi good hi and good bye);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
+note: found these 'hi's
+  --> $DIR/multispan.rs:27:12
+   |
+LL |     hello!(hi good hi and good bye);
+   |            ^^      ^^
+   = note: this error originates in the macro `hello` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 7 previous errors
+
diff --git a/tests/ui/array-slice-vec/vec-res-add.stderr b/tests/ui/array-slice-vec/vec-res-add.stderr
index 34fd69426a8b..4e13dbd0366d 100644
--- a/tests/ui/array-slice-vec/vec-res-add.stderr
+++ b/tests/ui/array-slice-vec/vec-res-add.stderr
@@ -6,10 +6,10 @@ LL |     let k = i + j;
    |             |
    |             Vec
    |
-note: the foreign item type `Vec` doesn't implement `Add`
+note: `Vec` does not implement `Add`
   --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
    |
-   = note: not implement `Add`
+   = note: `Vec` is defined in another crate
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/asm/aarch64/arm64ec-sve.rs b/tests/ui/asm/aarch64/arm64ec-sve.rs
index f11b9de375ef..651bb5c088c7 100644
--- a/tests/ui/asm/aarch64/arm64ec-sve.rs
+++ b/tests/ui/asm/aarch64/arm64ec-sve.rs
@@ -1,6 +1,5 @@
 //@ add-core-stubs
 //@ compile-flags: --target arm64ec-pc-windows-msvc
-//@ needs-asm-support
 //@ needs-llvm-components: aarch64
 //@ ignore-backends: gcc
 
diff --git a/tests/ui/asm/aarch64/arm64ec-sve.stderr b/tests/ui/asm/aarch64/arm64ec-sve.stderr
index cbae807e804a..d654eb4ba1a1 100644
--- a/tests/ui/asm/aarch64/arm64ec-sve.stderr
+++ b/tests/ui/asm/aarch64/arm64ec-sve.stderr
@@ -1,11 +1,11 @@
 error: cannot use register `p0`: x13, x14, x23, x24, x28, v16-v31, p*, ffr cannot be used for Arm64EC
-  --> $DIR/arm64ec-sve.rs:19:18
+  --> $DIR/arm64ec-sve.rs:18:18
    |
 LL |         asm!("", out("p0") _);
    |                  ^^^^^^^^^^^
 
 error: cannot use register `ffr`: x13, x14, x23, x24, x28, v16-v31, p*, ffr cannot be used for Arm64EC
-  --> $DIR/arm64ec-sve.rs:21:18
+  --> $DIR/arm64ec-sve.rs:20:18
    |
 LL |         asm!("", out("ffr") _);
    |                  ^^^^^^^^^^^^
diff --git a/tests/ui/asm/inline-syntax.arm.stderr b/tests/ui/asm/inline-syntax.arm.stderr
index 14e32c38884c..5b4eb3cc1409 100644
--- a/tests/ui/asm/inline-syntax.arm.stderr
+++ b/tests/ui/asm/inline-syntax.arm.stderr
@@ -15,7 +15,7 @@ LL | .intel_syntax noprefix
    | ^
 
 error: unknown directive
-  --> $DIR/inline-syntax.rs:22:15
+  --> $DIR/inline-syntax.rs:21:15
    |
 LL |         asm!(".intel_syntax noprefix", "nop");
    |               ^^^^^^^^^^^^^^^^^^^^^^
@@ -27,7 +27,7 @@ LL |     .intel_syntax noprefix
    |     ^
 
 error: unknown directive
-  --> $DIR/inline-syntax.rs:25:15
+  --> $DIR/inline-syntax.rs:24:15
    |
 LL |         asm!(".intel_syntax aaa noprefix", "nop");
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -39,7 +39,7 @@ LL |     .intel_syntax aaa noprefix
    |     ^
 
 error: unknown directive
-  --> $DIR/inline-syntax.rs:28:15
+  --> $DIR/inline-syntax.rs:27:15
    |
 LL |         asm!(".att_syntax noprefix", "nop");
    |               ^^^^^^^^^^^^^^^^^^^^
@@ -51,7 +51,7 @@ LL |     .att_syntax noprefix
    |     ^
 
 error: unknown directive
-  --> $DIR/inline-syntax.rs:31:15
+  --> $DIR/inline-syntax.rs:30:15
    |
 LL |         asm!(".att_syntax bbb noprefix", "nop");
    |               ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -63,7 +63,7 @@ LL |     .att_syntax bbb noprefix
    |     ^
 
 error: unknown directive
-  --> $DIR/inline-syntax.rs:34:15
+  --> $DIR/inline-syntax.rs:33:15
    |
 LL |         asm!(".intel_syntax noprefix; nop");
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -75,7 +75,7 @@ LL |     .intel_syntax noprefix; nop
    |     ^
 
 error: unknown directive
-  --> $DIR/inline-syntax.rs:40:13
+  --> $DIR/inline-syntax.rs:39:13
    |
 LL |             .intel_syntax noprefix
    |             ^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/asm/inline-syntax.rs b/tests/ui/asm/inline-syntax.rs
index dae70094e711..4ac0087d5b78 100644
--- a/tests/ui/asm/inline-syntax.rs
+++ b/tests/ui/asm/inline-syntax.rs
@@ -7,7 +7,6 @@
 //@[arm] compile-flags: --target armv7-unknown-linux-gnueabihf
 //@[arm] build-fail
 //@[arm] needs-llvm-components: arm
-//@ needs-asm-support
 //@ ignore-backends: gcc
 
 #![feature(no_core)]
diff --git a/tests/ui/asm/inline-syntax.x86_64.stderr b/tests/ui/asm/inline-syntax.x86_64.stderr
index 76f4cc054ef9..2d8091c20441 100644
--- a/tests/ui/asm/inline-syntax.x86_64.stderr
+++ b/tests/ui/asm/inline-syntax.x86_64.stderr
@@ -1,5 +1,5 @@
 warning: avoid using `.intel_syntax`, Intel syntax is the default
-  --> $DIR/inline-syntax.rs:48:14
+  --> $DIR/inline-syntax.rs:47:14
    |
 LL | global_asm!(".intel_syntax noprefix", "nop");
    |              ^^^^^^^^^^^^^^^^^^^^^^
@@ -7,37 +7,37 @@ LL | global_asm!(".intel_syntax noprefix", "nop");
    = note: `#[warn(bad_asm_style)]` on by default
 
 warning: avoid using `.intel_syntax`, Intel syntax is the default
-  --> $DIR/inline-syntax.rs:22:15
+  --> $DIR/inline-syntax.rs:21:15
    |
 LL |         asm!(".intel_syntax noprefix", "nop");
    |               ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: avoid using `.intel_syntax`, Intel syntax is the default
-  --> $DIR/inline-syntax.rs:25:15
+  --> $DIR/inline-syntax.rs:24:15
    |
 LL |         asm!(".intel_syntax aaa noprefix", "nop");
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: avoid using `.att_syntax`, prefer using `options(att_syntax)` instead
-  --> $DIR/inline-syntax.rs:28:15
+  --> $DIR/inline-syntax.rs:27:15
    |
 LL |         asm!(".att_syntax noprefix", "nop");
    |               ^^^^^^^^^^^^^^^^^^^^
 
 warning: avoid using `.att_syntax`, prefer using `options(att_syntax)` instead
-  --> $DIR/inline-syntax.rs:31:15
+  --> $DIR/inline-syntax.rs:30:15
    |
 LL |         asm!(".att_syntax bbb noprefix", "nop");
    |               ^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: avoid using `.intel_syntax`, Intel syntax is the default
-  --> $DIR/inline-syntax.rs:34:15
+  --> $DIR/inline-syntax.rs:33:15
    |
 LL |         asm!(".intel_syntax noprefix; nop");
    |               ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: avoid using `.intel_syntax`, Intel syntax is the default
-  --> $DIR/inline-syntax.rs:40:13
+  --> $DIR/inline-syntax.rs:39:13
    |
 LL |             .intel_syntax noprefix
    |             ^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/asm/issue-92378.rs b/tests/ui/asm/issue-92378.rs
index 8f9c91373f9a..1bdaef5a1af7 100644
--- a/tests/ui/asm/issue-92378.rs
+++ b/tests/ui/asm/issue-92378.rs
@@ -1,7 +1,6 @@
 //@ add-core-stubs
 //@ compile-flags: --target armv5te-unknown-linux-gnueabi
 //@ needs-llvm-components: arm
-//@ needs-asm-support
 //@ build-pass
 //@ ignore-backends: gcc
 
diff --git a/tests/ui/asm/issue-99071.rs b/tests/ui/asm/issue-99071.rs
index 6eb179daa788..fc7baa677240 100644
--- a/tests/ui/asm/issue-99071.rs
+++ b/tests/ui/asm/issue-99071.rs
@@ -1,7 +1,6 @@
 //@ add-core-stubs
 //@ compile-flags: --target thumbv6m-none-eabi
 //@ needs-llvm-components: arm
-//@ needs-asm-support
 //@ ignore-backends: gcc
 
 #![feature(no_core)]
diff --git a/tests/ui/asm/issue-99071.stderr b/tests/ui/asm/issue-99071.stderr
index b869f9a70b4c..1a8074b01d66 100644
--- a/tests/ui/asm/issue-99071.stderr
+++ b/tests/ui/asm/issue-99071.stderr
@@ -1,5 +1,5 @@
 error: cannot use register `r8`: high registers (r8+) can only be used as clobbers in Thumb-1 code
-  --> $DIR/issue-99071.rs:16:18
+  --> $DIR/issue-99071.rs:15:18
    |
 LL |         asm!("", in("r8") 0);
    |                  ^^^^^^^^^^
diff --git a/tests/ui/asm/loongarch/bad-reg.loongarch32_ilp32d.stderr b/tests/ui/asm/loongarch/bad-reg.loongarch32_ilp32d.stderr
index 8742d4bd82cd..c67c913d2a60 100644
--- a/tests/ui/asm/loongarch/bad-reg.loongarch32_ilp32d.stderr
+++ b/tests/ui/asm/loongarch/bad-reg.loongarch32_ilp32d.stderr
@@ -1,35 +1,35 @@
 error: invalid register `$r0`: constant zero cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:27:18
+  --> $DIR/bad-reg.rs:26:18
    |
 LL |         asm!("", out("$r0") _);
    |                  ^^^^^^^^^^^^
 
 error: invalid register `$tp`: reserved for TLS
-  --> $DIR/bad-reg.rs:29:18
+  --> $DIR/bad-reg.rs:28:18
    |
 LL |         asm!("", out("$tp") _);
    |                  ^^^^^^^^^^^^
 
 error: invalid register `$sp`: the stack pointer cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:31:18
+  --> $DIR/bad-reg.rs:30:18
    |
 LL |         asm!("", out("$sp") _);
    |                  ^^^^^^^^^^^^
 
 error: invalid register `$r21`: reserved by the ABI
-  --> $DIR/bad-reg.rs:33:18
+  --> $DIR/bad-reg.rs:32:18
    |
 LL |         asm!("", out("$r21") _);
    |                  ^^^^^^^^^^^^^
 
 error: invalid register `$fp`: the frame pointer cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:35:18
+  --> $DIR/bad-reg.rs:34:18
    |
 LL |         asm!("", out("$fp") _);
    |                  ^^^^^^^^^^^^
 
 error: invalid register `$r31`: $r31 is used internally by LLVM and cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:37:18
+  --> $DIR/bad-reg.rs:36:18
    |
 LL |         asm!("", out("$r31") _);
    |                  ^^^^^^^^^^^^^
diff --git a/tests/ui/asm/loongarch/bad-reg.loongarch32_ilp32s.stderr b/tests/ui/asm/loongarch/bad-reg.loongarch32_ilp32s.stderr
index e6cb6e40c701..99c071919acf 100644
--- a/tests/ui/asm/loongarch/bad-reg.loongarch32_ilp32s.stderr
+++ b/tests/ui/asm/loongarch/bad-reg.loongarch32_ilp32s.stderr
@@ -1,59 +1,59 @@
 error: invalid register `$r0`: constant zero cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:27:18
+  --> $DIR/bad-reg.rs:26:18
    |
 LL |         asm!("", out("$r0") _);
    |                  ^^^^^^^^^^^^
 
 error: invalid register `$tp`: reserved for TLS
-  --> $DIR/bad-reg.rs:29:18
+  --> $DIR/bad-reg.rs:28:18
    |
 LL |         asm!("", out("$tp") _);
    |                  ^^^^^^^^^^^^
 
 error: invalid register `$sp`: the stack pointer cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:31:18
+  --> $DIR/bad-reg.rs:30:18
    |
 LL |         asm!("", out("$sp") _);
    |                  ^^^^^^^^^^^^
 
 error: invalid register `$r21`: reserved by the ABI
-  --> $DIR/bad-reg.rs:33:18
+  --> $DIR/bad-reg.rs:32:18
    |
 LL |         asm!("", out("$r21") _);
    |                  ^^^^^^^^^^^^^
 
 error: invalid register `$fp`: the frame pointer cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:35:18
+  --> $DIR/bad-reg.rs:34:18
    |
 LL |         asm!("", out("$fp") _);
    |                  ^^^^^^^^^^^^
 
 error: invalid register `$r31`: $r31 is used internally by LLVM and cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:37:18
+  --> $DIR/bad-reg.rs:36:18
    |
 LL |         asm!("", out("$r31") _);
    |                  ^^^^^^^^^^^^^
 
 error: register class `freg` requires at least one of the following target features: d, f
-  --> $DIR/bad-reg.rs:41:26
+  --> $DIR/bad-reg.rs:40:26
    |
 LL |         asm!("/* {} */", in(freg) f);
    |                          ^^^^^^^^^^
 
 error: register class `freg` requires at least one of the following target features: d, f
-  --> $DIR/bad-reg.rs:43:26
+  --> $DIR/bad-reg.rs:42:26
    |
 LL |         asm!("/* {} */", out(freg) _);
    |                          ^^^^^^^^^^^
 
 error: register class `freg` requires at least one of the following target features: d, f
-  --> $DIR/bad-reg.rs:45:26
+  --> $DIR/bad-reg.rs:44:26
    |
 LL |         asm!("/* {} */", in(freg) d);
    |                          ^^^^^^^^^^
 
 error: register class `freg` requires at least one of the following target features: d, f
-  --> $DIR/bad-reg.rs:47:26
+  --> $DIR/bad-reg.rs:46:26
    |
 LL |         asm!("/* {} */", out(freg) d);
    |                          ^^^^^^^^^^^
diff --git a/tests/ui/asm/loongarch/bad-reg.loongarch64_lp64d.stderr b/tests/ui/asm/loongarch/bad-reg.loongarch64_lp64d.stderr
index 8742d4bd82cd..c67c913d2a60 100644
--- a/tests/ui/asm/loongarch/bad-reg.loongarch64_lp64d.stderr
+++ b/tests/ui/asm/loongarch/bad-reg.loongarch64_lp64d.stderr
@@ -1,35 +1,35 @@
 error: invalid register `$r0`: constant zero cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:27:18
+  --> $DIR/bad-reg.rs:26:18
    |
 LL |         asm!("", out("$r0") _);
    |                  ^^^^^^^^^^^^
 
 error: invalid register `$tp`: reserved for TLS
-  --> $DIR/bad-reg.rs:29:18
+  --> $DIR/bad-reg.rs:28:18
    |
 LL |         asm!("", out("$tp") _);
    |                  ^^^^^^^^^^^^
 
 error: invalid register `$sp`: the stack pointer cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:31:18
+  --> $DIR/bad-reg.rs:30:18
    |
 LL |         asm!("", out("$sp") _);
    |                  ^^^^^^^^^^^^
 
 error: invalid register `$r21`: reserved by the ABI
-  --> $DIR/bad-reg.rs:33:18
+  --> $DIR/bad-reg.rs:32:18
    |
 LL |         asm!("", out("$r21") _);
    |                  ^^^^^^^^^^^^^
 
 error: invalid register `$fp`: the frame pointer cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:35:18
+  --> $DIR/bad-reg.rs:34:18
    |
 LL |         asm!("", out("$fp") _);
    |                  ^^^^^^^^^^^^
 
 error: invalid register `$r31`: $r31 is used internally by LLVM and cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:37:18
+  --> $DIR/bad-reg.rs:36:18
    |
 LL |         asm!("", out("$r31") _);
    |                  ^^^^^^^^^^^^^
diff --git a/tests/ui/asm/loongarch/bad-reg.loongarch64_lp64s.stderr b/tests/ui/asm/loongarch/bad-reg.loongarch64_lp64s.stderr
index e6cb6e40c701..99c071919acf 100644
--- a/tests/ui/asm/loongarch/bad-reg.loongarch64_lp64s.stderr
+++ b/tests/ui/asm/loongarch/bad-reg.loongarch64_lp64s.stderr
@@ -1,59 +1,59 @@
 error: invalid register `$r0`: constant zero cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:27:18
+  --> $DIR/bad-reg.rs:26:18
    |
 LL |         asm!("", out("$r0") _);
    |                  ^^^^^^^^^^^^
 
 error: invalid register `$tp`: reserved for TLS
-  --> $DIR/bad-reg.rs:29:18
+  --> $DIR/bad-reg.rs:28:18
    |
 LL |         asm!("", out("$tp") _);
    |                  ^^^^^^^^^^^^
 
 error: invalid register `$sp`: the stack pointer cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:31:18
+  --> $DIR/bad-reg.rs:30:18
    |
 LL |         asm!("", out("$sp") _);
    |                  ^^^^^^^^^^^^
 
 error: invalid register `$r21`: reserved by the ABI
-  --> $DIR/bad-reg.rs:33:18
+  --> $DIR/bad-reg.rs:32:18
    |
 LL |         asm!("", out("$r21") _);
    |                  ^^^^^^^^^^^^^
 
 error: invalid register `$fp`: the frame pointer cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:35:18
+  --> $DIR/bad-reg.rs:34:18
    |
 LL |         asm!("", out("$fp") _);
    |                  ^^^^^^^^^^^^
 
 error: invalid register `$r31`: $r31 is used internally by LLVM and cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:37:18
+  --> $DIR/bad-reg.rs:36:18
    |
 LL |         asm!("", out("$r31") _);
    |                  ^^^^^^^^^^^^^
 
 error: register class `freg` requires at least one of the following target features: d, f
-  --> $DIR/bad-reg.rs:41:26
+  --> $DIR/bad-reg.rs:40:26
    |
 LL |         asm!("/* {} */", in(freg) f);
    |                          ^^^^^^^^^^
 
 error: register class `freg` requires at least one of the following target features: d, f
-  --> $DIR/bad-reg.rs:43:26
+  --> $DIR/bad-reg.rs:42:26
    |
 LL |         asm!("/* {} */", out(freg) _);
    |                          ^^^^^^^^^^^
 
 error: register class `freg` requires at least one of the following target features: d, f
-  --> $DIR/bad-reg.rs:45:26
+  --> $DIR/bad-reg.rs:44:26
    |
 LL |         asm!("/* {} */", in(freg) d);
    |                          ^^^^^^^^^^
 
 error: register class `freg` requires at least one of the following target features: d, f
-  --> $DIR/bad-reg.rs:47:26
+  --> $DIR/bad-reg.rs:46:26
    |
 LL |         asm!("/* {} */", out(freg) d);
    |                          ^^^^^^^^^^^
diff --git a/tests/ui/asm/loongarch/bad-reg.rs b/tests/ui/asm/loongarch/bad-reg.rs
index 5c20f9de5472..c39756d7cb1a 100644
--- a/tests/ui/asm/loongarch/bad-reg.rs
+++ b/tests/ui/asm/loongarch/bad-reg.rs
@@ -1,5 +1,4 @@
 //@ add-core-stubs
-//@ needs-asm-support
 //@ revisions: loongarch32_ilp32d loongarch32_ilp32s loongarch64_lp64d loongarch64_lp64s
 //@[loongarch32_ilp32d] compile-flags: --target loongarch32-unknown-none
 //@[loongarch32_ilp32d] needs-llvm-components: loongarch
diff --git a/tests/ui/asm/naked-functions-instruction-set.rs b/tests/ui/asm/naked-functions-instruction-set.rs
index 9a2437389d60..4ee82cfcbb3d 100644
--- a/tests/ui/asm/naked-functions-instruction-set.rs
+++ b/tests/ui/asm/naked-functions-instruction-set.rs
@@ -1,7 +1,6 @@
 //@ add-core-stubs
 //@ compile-flags: --target armv5te-unknown-linux-gnueabi
 //@ needs-llvm-components: arm
-//@ needs-asm-support
 //@ build-pass
 //@ ignore-backends: gcc
 
diff --git a/tests/ui/asm/powerpc/bad-reg.aix64.stderr b/tests/ui/asm/powerpc/bad-reg.aix64.stderr
index fb3ed07f5c65..67ad0a5d2c45 100644
--- a/tests/ui/asm/powerpc/bad-reg.aix64.stderr
+++ b/tests/ui/asm/powerpc/bad-reg.aix64.stderr
@@ -1,137 +1,137 @@
 error: invalid register `sp`: the stack pointer cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:37:18
+  --> $DIR/bad-reg.rs:36:18
    |
 LL |         asm!("", out("sp") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `r2`: r2 is a system reserved register and cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:39:18
+  --> $DIR/bad-reg.rs:38:18
    |
 LL |         asm!("", out("r2") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `r29`: r29 is used internally by LLVM and cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:43:18
+  --> $DIR/bad-reg.rs:42:18
    |
 LL |         asm!("", out("r29") _);
    |                  ^^^^^^^^^^^^
 
 error: invalid register `r30`: r30 is used internally by LLVM and cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:45:18
+  --> $DIR/bad-reg.rs:44:18
    |
 LL |         asm!("", out("r30") _);
    |                  ^^^^^^^^^^^^
 
 error: invalid register `fp`: the frame pointer cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:47:18
+  --> $DIR/bad-reg.rs:46:18
    |
 LL |         asm!("", out("fp") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `vrsave`: the vrsave register cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:49:18
+  --> $DIR/bad-reg.rs:48:18
    |
 LL |         asm!("", out("vrsave") _);
    |                  ^^^^^^^^^^^^^^^
 
 error: register class `cr` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:138:18
+  --> $DIR/bad-reg.rs:137:18
    |
 LL |         asm!("", in("cr") x);
    |                  ^^^^^^^^^^
 
 error: register class `cr` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:141:18
+  --> $DIR/bad-reg.rs:140:18
    |
 LL |         asm!("", out("cr") x);
    |                  ^^^^^^^^^^^
 
 error: register class `cr` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:144:26
+  --> $DIR/bad-reg.rs:143:26
    |
 LL |         asm!("/* {} */", in(cr) x);
    |                          ^^^^^^^^
 
 error: register class `cr` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:147:26
+  --> $DIR/bad-reg.rs:146:26
    |
 LL |         asm!("/* {} */", out(cr) _);
    |                          ^^^^^^^^^
 
 error: register class `ctr` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:151:18
+  --> $DIR/bad-reg.rs:150:18
    |
 LL |         asm!("", in("ctr") x);
    |                  ^^^^^^^^^^^
 
 error: register class `ctr` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:154:18
+  --> $DIR/bad-reg.rs:153:18
    |
 LL |         asm!("", out("ctr") x);
    |                  ^^^^^^^^^^^^
 
 error: register class `ctr` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:157:26
+  --> $DIR/bad-reg.rs:156:26
    |
 LL |         asm!("/* {} */", in(ctr) x);
    |                          ^^^^^^^^^
 
 error: register class `ctr` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:160:26
+  --> $DIR/bad-reg.rs:159:26
    |
 LL |         asm!("/* {} */", out(ctr) _);
    |                          ^^^^^^^^^^
 
 error: register class `lr` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:164:18
+  --> $DIR/bad-reg.rs:163:18
    |
 LL |         asm!("", in("lr") x);
    |                  ^^^^^^^^^^
 
 error: register class `lr` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:167:18
+  --> $DIR/bad-reg.rs:166:18
    |
 LL |         asm!("", out("lr") x);
    |                  ^^^^^^^^^^^
 
 error: register class `lr` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:170:26
+  --> $DIR/bad-reg.rs:169:26
    |
 LL |         asm!("/* {} */", in(lr) x);
    |                          ^^^^^^^^
 
 error: register class `lr` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:173:26
+  --> $DIR/bad-reg.rs:172:26
    |
 LL |         asm!("/* {} */", out(lr) _);
    |                          ^^^^^^^^^
 
 error: register class `xer` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:177:18
+  --> $DIR/bad-reg.rs:176:18
    |
 LL |         asm!("", in("xer") x);
    |                  ^^^^^^^^^^^
 
 error: register class `xer` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:180:18
+  --> $DIR/bad-reg.rs:179:18
    |
 LL |         asm!("", out("xer") x);
    |                  ^^^^^^^^^^^^
 
 error: register class `xer` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:183:26
+  --> $DIR/bad-reg.rs:182:26
    |
 LL |         asm!("/* {} */", in(xer) x);
    |                          ^^^^^^^^^
 
 error: register class `xer` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:186:26
+  --> $DIR/bad-reg.rs:185:26
    |
 LL |         asm!("/* {} */", out(xer) _);
    |                          ^^^^^^^^^^
 
 error: register `cr0` conflicts with register `cr`
-  --> $DIR/bad-reg.rs:190:31
+  --> $DIR/bad-reg.rs:189:31
    |
 LL |         asm!("", out("cr") _, out("cr0") _);
    |                  -----------  ^^^^^^^^^^^^ register `cr0`
@@ -139,7 +139,7 @@ LL |         asm!("", out("cr") _, out("cr0") _);
    |                  register `cr`
 
 error: register `cr1` conflicts with register `cr`
-  --> $DIR/bad-reg.rs:192:31
+  --> $DIR/bad-reg.rs:191:31
    |
 LL |         asm!("", out("cr") _, out("cr1") _);
    |                  -----------  ^^^^^^^^^^^^ register `cr1`
@@ -147,7 +147,7 @@ LL |         asm!("", out("cr") _, out("cr1") _);
    |                  register `cr`
 
 error: register `cr2` conflicts with register `cr`
-  --> $DIR/bad-reg.rs:194:31
+  --> $DIR/bad-reg.rs:193:31
    |
 LL |         asm!("", out("cr") _, out("cr2") _);
    |                  -----------  ^^^^^^^^^^^^ register `cr2`
@@ -155,7 +155,7 @@ LL |         asm!("", out("cr") _, out("cr2") _);
    |                  register `cr`
 
 error: register `cr3` conflicts with register `cr`
-  --> $DIR/bad-reg.rs:196:31
+  --> $DIR/bad-reg.rs:195:31
    |
 LL |         asm!("", out("cr") _, out("cr3") _);
    |                  -----------  ^^^^^^^^^^^^ register `cr3`
@@ -163,7 +163,7 @@ LL |         asm!("", out("cr") _, out("cr3") _);
    |                  register `cr`
 
 error: register `cr4` conflicts with register `cr`
-  --> $DIR/bad-reg.rs:198:31
+  --> $DIR/bad-reg.rs:197:31
    |
 LL |         asm!("", out("cr") _, out("cr4") _);
    |                  -----------  ^^^^^^^^^^^^ register `cr4`
@@ -171,7 +171,7 @@ LL |         asm!("", out("cr") _, out("cr4") _);
    |                  register `cr`
 
 error: register `cr5` conflicts with register `cr`
-  --> $DIR/bad-reg.rs:200:31
+  --> $DIR/bad-reg.rs:199:31
    |
 LL |         asm!("", out("cr") _, out("cr5") _);
    |                  -----------  ^^^^^^^^^^^^ register `cr5`
@@ -179,7 +179,7 @@ LL |         asm!("", out("cr") _, out("cr5") _);
    |                  register `cr`
 
 error: register `cr6` conflicts with register `cr`
-  --> $DIR/bad-reg.rs:202:31
+  --> $DIR/bad-reg.rs:201:31
    |
 LL |         asm!("", out("cr") _, out("cr6") _);
    |                  -----------  ^^^^^^^^^^^^ register `cr6`
@@ -187,7 +187,7 @@ LL |         asm!("", out("cr") _, out("cr6") _);
    |                  register `cr`
 
 error: register `cr7` conflicts with register `cr`
-  --> $DIR/bad-reg.rs:204:31
+  --> $DIR/bad-reg.rs:203:31
    |
 LL |         asm!("", out("cr") _, out("cr7") _);
    |                  -----------  ^^^^^^^^^^^^ register `cr7`
@@ -195,7 +195,7 @@ LL |         asm!("", out("cr") _, out("cr7") _);
    |                  register `cr`
 
 error: register `vs0` conflicts with register `f0`
-  --> $DIR/bad-reg.rs:207:31
+  --> $DIR/bad-reg.rs:206:31
    |
 LL |         asm!("", out("f0") _, out("vs0") _);
    |                  -----------  ^^^^^^^^^^^^ register `vs0`
@@ -203,7 +203,7 @@ LL |         asm!("", out("f0") _, out("vs0") _);
    |                  register `f0`
 
 error: register `vs1` conflicts with register `f1`
-  --> $DIR/bad-reg.rs:209:31
+  --> $DIR/bad-reg.rs:208:31
    |
 LL |         asm!("", out("f1") _, out("vs1") _);
    |                  -----------  ^^^^^^^^^^^^ register `vs1`
@@ -211,7 +211,7 @@ LL |         asm!("", out("f1") _, out("vs1") _);
    |                  register `f1`
 
 error: register `vs2` conflicts with register `f2`
-  --> $DIR/bad-reg.rs:211:31
+  --> $DIR/bad-reg.rs:210:31
    |
 LL |         asm!("", out("f2") _, out("vs2") _);
    |                  -----------  ^^^^^^^^^^^^ register `vs2`
@@ -219,7 +219,7 @@ LL |         asm!("", out("f2") _, out("vs2") _);
    |                  register `f2`
 
 error: register `vs3` conflicts with register `f3`
-  --> $DIR/bad-reg.rs:213:31
+  --> $DIR/bad-reg.rs:212:31
    |
 LL |         asm!("", out("f3") _, out("vs3") _);
    |                  -----------  ^^^^^^^^^^^^ register `vs3`
@@ -227,7 +227,7 @@ LL |         asm!("", out("f3") _, out("vs3") _);
    |                  register `f3`
 
 error: register `vs4` conflicts with register `f4`
-  --> $DIR/bad-reg.rs:215:31
+  --> $DIR/bad-reg.rs:214:31
    |
 LL |         asm!("", out("f4") _, out("vs4") _);
    |                  -----------  ^^^^^^^^^^^^ register `vs4`
@@ -235,7 +235,7 @@ LL |         asm!("", out("f4") _, out("vs4") _);
    |                  register `f4`
 
 error: register `vs5` conflicts with register `f5`
-  --> $DIR/bad-reg.rs:217:31
+  --> $DIR/bad-reg.rs:216:31
    |
 LL |         asm!("", out("f5") _, out("vs5") _);
    |                  -----------  ^^^^^^^^^^^^ register `vs5`
@@ -243,7 +243,7 @@ LL |         asm!("", out("f5") _, out("vs5") _);
    |                  register `f5`
 
 error: register `vs6` conflicts with register `f6`
-  --> $DIR/bad-reg.rs:219:31
+  --> $DIR/bad-reg.rs:218:31
    |
 LL |         asm!("", out("f6") _, out("vs6") _);
    |                  -----------  ^^^^^^^^^^^^ register `vs6`
@@ -251,7 +251,7 @@ LL |         asm!("", out("f6") _, out("vs6") _);
    |                  register `f6`
 
 error: register `vs7` conflicts with register `f7`
-  --> $DIR/bad-reg.rs:221:31
+  --> $DIR/bad-reg.rs:220:31
    |
 LL |         asm!("", out("f7") _, out("vs7") _);
    |                  -----------  ^^^^^^^^^^^^ register `vs7`
@@ -259,7 +259,7 @@ LL |         asm!("", out("f7") _, out("vs7") _);
    |                  register `f7`
 
 error: register `vs8` conflicts with register `f8`
-  --> $DIR/bad-reg.rs:223:31
+  --> $DIR/bad-reg.rs:222:31
    |
 LL |         asm!("", out("f8") _, out("vs8") _);
    |                  -----------  ^^^^^^^^^^^^ register `vs8`
@@ -267,7 +267,7 @@ LL |         asm!("", out("f8") _, out("vs8") _);
    |                  register `f8`
 
 error: register `vs9` conflicts with register `f9`
-  --> $DIR/bad-reg.rs:225:31
+  --> $DIR/bad-reg.rs:224:31
    |
 LL |         asm!("", out("f9") _, out("vs9") _);
    |                  -----------  ^^^^^^^^^^^^ register `vs9`
@@ -275,7 +275,7 @@ LL |         asm!("", out("f9") _, out("vs9") _);
    |                  register `f9`
 
 error: register `vs10` conflicts with register `f10`
-  --> $DIR/bad-reg.rs:227:32
+  --> $DIR/bad-reg.rs:226:32
    |
 LL |         asm!("", out("f10") _, out("vs10") _);
    |                  ------------  ^^^^^^^^^^^^^ register `vs10`
@@ -283,7 +283,7 @@ LL |         asm!("", out("f10") _, out("vs10") _);
    |                  register `f10`
 
 error: register `vs11` conflicts with register `f11`
-  --> $DIR/bad-reg.rs:229:32
+  --> $DIR/bad-reg.rs:228:32
    |
 LL |         asm!("", out("f11") _, out("vs11") _);
    |                  ------------  ^^^^^^^^^^^^^ register `vs11`
@@ -291,7 +291,7 @@ LL |         asm!("", out("f11") _, out("vs11") _);
    |                  register `f11`
 
 error: register `vs12` conflicts with register `f12`
-  --> $DIR/bad-reg.rs:231:32
+  --> $DIR/bad-reg.rs:230:32
    |
 LL |         asm!("", out("f12") _, out("vs12") _);
    |                  ------------  ^^^^^^^^^^^^^ register `vs12`
@@ -299,7 +299,7 @@ LL |         asm!("", out("f12") _, out("vs12") _);
    |                  register `f12`
 
 error: register `vs13` conflicts with register `f13`
-  --> $DIR/bad-reg.rs:233:32
+  --> $DIR/bad-reg.rs:232:32
    |
 LL |         asm!("", out("f13") _, out("vs13") _);
    |                  ------------  ^^^^^^^^^^^^^ register `vs13`
@@ -307,7 +307,7 @@ LL |         asm!("", out("f13") _, out("vs13") _);
    |                  register `f13`
 
 error: register `vs14` conflicts with register `f14`
-  --> $DIR/bad-reg.rs:235:32
+  --> $DIR/bad-reg.rs:234:32
    |
 LL |         asm!("", out("f14") _, out("vs14") _);
    |                  ------------  ^^^^^^^^^^^^^ register `vs14`
@@ -315,7 +315,7 @@ LL |         asm!("", out("f14") _, out("vs14") _);
    |                  register `f14`
 
 error: register `vs15` conflicts with register `f15`
-  --> $DIR/bad-reg.rs:237:32
+  --> $DIR/bad-reg.rs:236:32
    |
 LL |         asm!("", out("f15") _, out("vs15") _);
    |                  ------------  ^^^^^^^^^^^^^ register `vs15`
@@ -323,7 +323,7 @@ LL |         asm!("", out("f15") _, out("vs15") _);
    |                  register `f15`
 
 error: register `vs16` conflicts with register `f16`
-  --> $DIR/bad-reg.rs:239:32
+  --> $DIR/bad-reg.rs:238:32
    |
 LL |         asm!("", out("f16") _, out("vs16") _);
    |                  ------------  ^^^^^^^^^^^^^ register `vs16`
@@ -331,7 +331,7 @@ LL |         asm!("", out("f16") _, out("vs16") _);
    |                  register `f16`
 
 error: register `vs17` conflicts with register `f17`
-  --> $DIR/bad-reg.rs:241:32
+  --> $DIR/bad-reg.rs:240:32
    |
 LL |         asm!("", out("f17") _, out("vs17") _);
    |                  ------------  ^^^^^^^^^^^^^ register `vs17`
@@ -339,7 +339,7 @@ LL |         asm!("", out("f17") _, out("vs17") _);
    |                  register `f17`
 
 error: register `vs18` conflicts with register `f18`
-  --> $DIR/bad-reg.rs:243:32
+  --> $DIR/bad-reg.rs:242:32
    |
 LL |         asm!("", out("f18") _, out("vs18") _);
    |                  ------------  ^^^^^^^^^^^^^ register `vs18`
@@ -347,7 +347,7 @@ LL |         asm!("", out("f18") _, out("vs18") _);
    |                  register `f18`
 
 error: register `vs19` conflicts with register `f19`
-  --> $DIR/bad-reg.rs:245:32
+  --> $DIR/bad-reg.rs:244:32
    |
 LL |         asm!("", out("f19") _, out("vs19") _);
    |                  ------------  ^^^^^^^^^^^^^ register `vs19`
@@ -355,7 +355,7 @@ LL |         asm!("", out("f19") _, out("vs19") _);
    |                  register `f19`
 
 error: register `vs20` conflicts with register `f20`
-  --> $DIR/bad-reg.rs:247:32
+  --> $DIR/bad-reg.rs:246:32
    |
 LL |         asm!("", out("f20") _, out("vs20") _);
    |                  ------------  ^^^^^^^^^^^^^ register `vs20`
@@ -363,7 +363,7 @@ LL |         asm!("", out("f20") _, out("vs20") _);
    |                  register `f20`
 
 error: register `vs21` conflicts with register `f21`
-  --> $DIR/bad-reg.rs:249:32
+  --> $DIR/bad-reg.rs:248:32
    |
 LL |         asm!("", out("f21") _, out("vs21") _);
    |                  ------------  ^^^^^^^^^^^^^ register `vs21`
@@ -371,7 +371,7 @@ LL |         asm!("", out("f21") _, out("vs21") _);
    |                  register `f21`
 
 error: register `vs22` conflicts with register `f22`
-  --> $DIR/bad-reg.rs:251:32
+  --> $DIR/bad-reg.rs:250:32
    |
 LL |         asm!("", out("f22") _, out("vs22") _);
    |                  ------------  ^^^^^^^^^^^^^ register `vs22`
@@ -379,7 +379,7 @@ LL |         asm!("", out("f22") _, out("vs22") _);
    |                  register `f22`
 
 error: register `vs23` conflicts with register `f23`
-  --> $DIR/bad-reg.rs:253:32
+  --> $DIR/bad-reg.rs:252:32
    |
 LL |         asm!("", out("f23") _, out("vs23") _);
    |                  ------------  ^^^^^^^^^^^^^ register `vs23`
@@ -387,7 +387,7 @@ LL |         asm!("", out("f23") _, out("vs23") _);
    |                  register `f23`
 
 error: register `vs24` conflicts with register `f24`
-  --> $DIR/bad-reg.rs:255:32
+  --> $DIR/bad-reg.rs:254:32
    |
 LL |         asm!("", out("f24") _, out("vs24") _);
    |                  ------------  ^^^^^^^^^^^^^ register `vs24`
@@ -395,7 +395,7 @@ LL |         asm!("", out("f24") _, out("vs24") _);
    |                  register `f24`
 
 error: register `vs25` conflicts with register `f25`
-  --> $DIR/bad-reg.rs:257:32
+  --> $DIR/bad-reg.rs:256:32
    |
 LL |         asm!("", out("f25") _, out("vs25") _);
    |                  ------------  ^^^^^^^^^^^^^ register `vs25`
@@ -403,7 +403,7 @@ LL |         asm!("", out("f25") _, out("vs25") _);
    |                  register `f25`
 
 error: register `vs26` conflicts with register `f26`
-  --> $DIR/bad-reg.rs:259:32
+  --> $DIR/bad-reg.rs:258:32
    |
 LL |         asm!("", out("f26") _, out("vs26") _);
    |                  ------------  ^^^^^^^^^^^^^ register `vs26`
@@ -411,7 +411,7 @@ LL |         asm!("", out("f26") _, out("vs26") _);
    |                  register `f26`
 
 error: register `vs27` conflicts with register `f27`
-  --> $DIR/bad-reg.rs:261:32
+  --> $DIR/bad-reg.rs:260:32
    |
 LL |         asm!("", out("f27") _, out("vs27") _);
    |                  ------------  ^^^^^^^^^^^^^ register `vs27`
@@ -419,7 +419,7 @@ LL |         asm!("", out("f27") _, out("vs27") _);
    |                  register `f27`
 
 error: register `vs28` conflicts with register `f28`
-  --> $DIR/bad-reg.rs:263:32
+  --> $DIR/bad-reg.rs:262:32
    |
 LL |         asm!("", out("f28") _, out("vs28") _);
    |                  ------------  ^^^^^^^^^^^^^ register `vs28`
@@ -427,7 +427,7 @@ LL |         asm!("", out("f28") _, out("vs28") _);
    |                  register `f28`
 
 error: register `vs29` conflicts with register `f29`
-  --> $DIR/bad-reg.rs:265:32
+  --> $DIR/bad-reg.rs:264:32
    |
 LL |         asm!("", out("f29") _, out("vs29") _);
    |                  ------------  ^^^^^^^^^^^^^ register `vs29`
@@ -435,7 +435,7 @@ LL |         asm!("", out("f29") _, out("vs29") _);
    |                  register `f29`
 
 error: register `vs30` conflicts with register `f30`
-  --> $DIR/bad-reg.rs:267:32
+  --> $DIR/bad-reg.rs:266:32
    |
 LL |         asm!("", out("f30") _, out("vs30") _);
    |                  ------------  ^^^^^^^^^^^^^ register `vs30`
@@ -443,7 +443,7 @@ LL |         asm!("", out("f30") _, out("vs30") _);
    |                  register `f30`
 
 error: register `vs31` conflicts with register `f31`
-  --> $DIR/bad-reg.rs:269:32
+  --> $DIR/bad-reg.rs:268:32
    |
 LL |         asm!("", out("f31") _, out("vs31") _);
    |                  ------------  ^^^^^^^^^^^^^ register `vs31`
@@ -451,7 +451,7 @@ LL |         asm!("", out("f31") _, out("vs31") _);
    |                  register `f31`
 
 error: register `v0` conflicts with register `vs32`
-  --> $DIR/bad-reg.rs:271:33
+  --> $DIR/bad-reg.rs:270:33
    |
 LL |         asm!("", out("vs32") _, out("v0") _);
    |                  -------------  ^^^^^^^^^^^ register `v0`
@@ -459,7 +459,7 @@ LL |         asm!("", out("vs32") _, out("v0") _);
    |                  register `vs32`
 
 error: register `v1` conflicts with register `vs33`
-  --> $DIR/bad-reg.rs:273:33
+  --> $DIR/bad-reg.rs:272:33
    |
 LL |         asm!("", out("vs33") _, out("v1") _);
    |                  -------------  ^^^^^^^^^^^ register `v1`
@@ -467,7 +467,7 @@ LL |         asm!("", out("vs33") _, out("v1") _);
    |                  register `vs33`
 
 error: register `v2` conflicts with register `vs34`
-  --> $DIR/bad-reg.rs:275:33
+  --> $DIR/bad-reg.rs:274:33
    |
 LL |         asm!("", out("vs34") _, out("v2") _);
    |                  -------------  ^^^^^^^^^^^ register `v2`
@@ -475,7 +475,7 @@ LL |         asm!("", out("vs34") _, out("v2") _);
    |                  register `vs34`
 
 error: register `v3` conflicts with register `vs35`
-  --> $DIR/bad-reg.rs:277:33
+  --> $DIR/bad-reg.rs:276:33
    |
 LL |         asm!("", out("vs35") _, out("v3") _);
    |                  -------------  ^^^^^^^^^^^ register `v3`
@@ -483,7 +483,7 @@ LL |         asm!("", out("vs35") _, out("v3") _);
    |                  register `vs35`
 
 error: register `v4` conflicts with register `vs36`
-  --> $DIR/bad-reg.rs:279:33
+  --> $DIR/bad-reg.rs:278:33
    |
 LL |         asm!("", out("vs36") _, out("v4") _);
    |                  -------------  ^^^^^^^^^^^ register `v4`
@@ -491,7 +491,7 @@ LL |         asm!("", out("vs36") _, out("v4") _);
    |                  register `vs36`
 
 error: register `v5` conflicts with register `vs37`
-  --> $DIR/bad-reg.rs:281:33
+  --> $DIR/bad-reg.rs:280:33
    |
 LL |         asm!("", out("vs37") _, out("v5") _);
    |                  -------------  ^^^^^^^^^^^ register `v5`
@@ -499,7 +499,7 @@ LL |         asm!("", out("vs37") _, out("v5") _);
    |                  register `vs37`
 
 error: register `v6` conflicts with register `vs38`
-  --> $DIR/bad-reg.rs:283:33
+  --> $DIR/bad-reg.rs:282:33
    |
 LL |         asm!("", out("vs38") _, out("v6") _);
    |                  -------------  ^^^^^^^^^^^ register `v6`
@@ -507,7 +507,7 @@ LL |         asm!("", out("vs38") _, out("v6") _);
    |                  register `vs38`
 
 error: register `v7` conflicts with register `vs39`
-  --> $DIR/bad-reg.rs:285:33
+  --> $DIR/bad-reg.rs:284:33
    |
 LL |         asm!("", out("vs39") _, out("v7") _);
    |                  -------------  ^^^^^^^^^^^ register `v7`
@@ -515,7 +515,7 @@ LL |         asm!("", out("vs39") _, out("v7") _);
    |                  register `vs39`
 
 error: register `v8` conflicts with register `vs40`
-  --> $DIR/bad-reg.rs:287:33
+  --> $DIR/bad-reg.rs:286:33
    |
 LL |         asm!("", out("vs40") _, out("v8") _);
    |                  -------------  ^^^^^^^^^^^ register `v8`
@@ -523,7 +523,7 @@ LL |         asm!("", out("vs40") _, out("v8") _);
    |                  register `vs40`
 
 error: register `v9` conflicts with register `vs41`
-  --> $DIR/bad-reg.rs:289:33
+  --> $DIR/bad-reg.rs:288:33
    |
 LL |         asm!("", out("vs41") _, out("v9") _);
    |                  -------------  ^^^^^^^^^^^ register `v9`
@@ -531,7 +531,7 @@ LL |         asm!("", out("vs41") _, out("v9") _);
    |                  register `vs41`
 
 error: register `v10` conflicts with register `vs42`
-  --> $DIR/bad-reg.rs:291:33
+  --> $DIR/bad-reg.rs:290:33
    |
 LL |         asm!("", out("vs42") _, out("v10") _);
    |                  -------------  ^^^^^^^^^^^^ register `v10`
@@ -539,7 +539,7 @@ LL |         asm!("", out("vs42") _, out("v10") _);
    |                  register `vs42`
 
 error: register `v11` conflicts with register `vs43`
-  --> $DIR/bad-reg.rs:293:33
+  --> $DIR/bad-reg.rs:292:33
    |
 LL |         asm!("", out("vs43") _, out("v11") _);
    |                  -------------  ^^^^^^^^^^^^ register `v11`
@@ -547,7 +547,7 @@ LL |         asm!("", out("vs43") _, out("v11") _);
    |                  register `vs43`
 
 error: register `v12` conflicts with register `vs44`
-  --> $DIR/bad-reg.rs:295:33
+  --> $DIR/bad-reg.rs:294:33
    |
 LL |         asm!("", out("vs44") _, out("v12") _);
    |                  -------------  ^^^^^^^^^^^^ register `v12`
@@ -555,7 +555,7 @@ LL |         asm!("", out("vs44") _, out("v12") _);
    |                  register `vs44`
 
 error: register `v13` conflicts with register `vs45`
-  --> $DIR/bad-reg.rs:297:33
+  --> $DIR/bad-reg.rs:296:33
    |
 LL |         asm!("", out("vs45") _, out("v13") _);
    |                  -------------  ^^^^^^^^^^^^ register `v13`
@@ -563,7 +563,7 @@ LL |         asm!("", out("vs45") _, out("v13") _);
    |                  register `vs45`
 
 error: register `v14` conflicts with register `vs46`
-  --> $DIR/bad-reg.rs:299:33
+  --> $DIR/bad-reg.rs:298:33
    |
 LL |         asm!("", out("vs46") _, out("v14") _);
    |                  -------------  ^^^^^^^^^^^^ register `v14`
@@ -571,7 +571,7 @@ LL |         asm!("", out("vs46") _, out("v14") _);
    |                  register `vs46`
 
 error: register `v15` conflicts with register `vs47`
-  --> $DIR/bad-reg.rs:301:33
+  --> $DIR/bad-reg.rs:300:33
    |
 LL |         asm!("", out("vs47") _, out("v15") _);
    |                  -------------  ^^^^^^^^^^^^ register `v15`
@@ -579,7 +579,7 @@ LL |         asm!("", out("vs47") _, out("v15") _);
    |                  register `vs47`
 
 error: register `v16` conflicts with register `vs48`
-  --> $DIR/bad-reg.rs:303:33
+  --> $DIR/bad-reg.rs:302:33
    |
 LL |         asm!("", out("vs48") _, out("v16") _);
    |                  -------------  ^^^^^^^^^^^^ register `v16`
@@ -587,7 +587,7 @@ LL |         asm!("", out("vs48") _, out("v16") _);
    |                  register `vs48`
 
 error: register `v17` conflicts with register `vs49`
-  --> $DIR/bad-reg.rs:305:33
+  --> $DIR/bad-reg.rs:304:33
    |
 LL |         asm!("", out("vs49") _, out("v17") _);
    |                  -------------  ^^^^^^^^^^^^ register `v17`
@@ -595,7 +595,7 @@ LL |         asm!("", out("vs49") _, out("v17") _);
    |                  register `vs49`
 
 error: register `v18` conflicts with register `vs50`
-  --> $DIR/bad-reg.rs:307:33
+  --> $DIR/bad-reg.rs:306:33
    |
 LL |         asm!("", out("vs50") _, out("v18") _);
    |                  -------------  ^^^^^^^^^^^^ register `v18`
@@ -603,7 +603,7 @@ LL |         asm!("", out("vs50") _, out("v18") _);
    |                  register `vs50`
 
 error: register `v19` conflicts with register `vs51`
-  --> $DIR/bad-reg.rs:309:33
+  --> $DIR/bad-reg.rs:308:33
    |
 LL |         asm!("", out("vs51") _, out("v19") _);
    |                  -------------  ^^^^^^^^^^^^ register `v19`
@@ -611,7 +611,7 @@ LL |         asm!("", out("vs51") _, out("v19") _);
    |                  register `vs51`
 
 error: register `v20` conflicts with register `vs52`
-  --> $DIR/bad-reg.rs:311:33
+  --> $DIR/bad-reg.rs:310:33
    |
 LL |         asm!("", out("vs52") _, out("v20") _);
    |                  -------------  ^^^^^^^^^^^^ register `v20`
@@ -619,7 +619,7 @@ LL |         asm!("", out("vs52") _, out("v20") _);
    |                  register `vs52`
 
 error: register `v21` conflicts with register `vs53`
-  --> $DIR/bad-reg.rs:313:33
+  --> $DIR/bad-reg.rs:312:33
    |
 LL |         asm!("", out("vs53") _, out("v21") _);
    |                  -------------  ^^^^^^^^^^^^ register `v21`
@@ -627,7 +627,7 @@ LL |         asm!("", out("vs53") _, out("v21") _);
    |                  register `vs53`
 
 error: register `v22` conflicts with register `vs54`
-  --> $DIR/bad-reg.rs:315:33
+  --> $DIR/bad-reg.rs:314:33
    |
 LL |         asm!("", out("vs54") _, out("v22") _);
    |                  -------------  ^^^^^^^^^^^^ register `v22`
@@ -635,7 +635,7 @@ LL |         asm!("", out("vs54") _, out("v22") _);
    |                  register `vs54`
 
 error: register `v23` conflicts with register `vs55`
-  --> $DIR/bad-reg.rs:317:33
+  --> $DIR/bad-reg.rs:316:33
    |
 LL |         asm!("", out("vs55") _, out("v23") _);
    |                  -------------  ^^^^^^^^^^^^ register `v23`
@@ -643,7 +643,7 @@ LL |         asm!("", out("vs55") _, out("v23") _);
    |                  register `vs55`
 
 error: register `v24` conflicts with register `vs56`
-  --> $DIR/bad-reg.rs:319:33
+  --> $DIR/bad-reg.rs:318:33
    |
 LL |         asm!("", out("vs56") _, out("v24") _);
    |                  -------------  ^^^^^^^^^^^^ register `v24`
@@ -651,7 +651,7 @@ LL |         asm!("", out("vs56") _, out("v24") _);
    |                  register `vs56`
 
 error: register `v25` conflicts with register `vs57`
-  --> $DIR/bad-reg.rs:321:33
+  --> $DIR/bad-reg.rs:320:33
    |
 LL |         asm!("", out("vs57") _, out("v25") _);
    |                  -------------  ^^^^^^^^^^^^ register `v25`
@@ -659,7 +659,7 @@ LL |         asm!("", out("vs57") _, out("v25") _);
    |                  register `vs57`
 
 error: register `v26` conflicts with register `vs58`
-  --> $DIR/bad-reg.rs:323:33
+  --> $DIR/bad-reg.rs:322:33
    |
 LL |         asm!("", out("vs58") _, out("v26") _);
    |                  -------------  ^^^^^^^^^^^^ register `v26`
@@ -667,7 +667,7 @@ LL |         asm!("", out("vs58") _, out("v26") _);
    |                  register `vs58`
 
 error: register `v27` conflicts with register `vs59`
-  --> $DIR/bad-reg.rs:325:33
+  --> $DIR/bad-reg.rs:324:33
    |
 LL |         asm!("", out("vs59") _, out("v27") _);
    |                  -------------  ^^^^^^^^^^^^ register `v27`
@@ -675,7 +675,7 @@ LL |         asm!("", out("vs59") _, out("v27") _);
    |                  register `vs59`
 
 error: register `v28` conflicts with register `vs60`
-  --> $DIR/bad-reg.rs:327:33
+  --> $DIR/bad-reg.rs:326:33
    |
 LL |         asm!("", out("vs60") _, out("v28") _);
    |                  -------------  ^^^^^^^^^^^^ register `v28`
@@ -683,7 +683,7 @@ LL |         asm!("", out("vs60") _, out("v28") _);
    |                  register `vs60`
 
 error: register `v29` conflicts with register `vs61`
-  --> $DIR/bad-reg.rs:329:33
+  --> $DIR/bad-reg.rs:328:33
    |
 LL |         asm!("", out("vs61") _, out("v29") _);
    |                  -------------  ^^^^^^^^^^^^ register `v29`
@@ -691,7 +691,7 @@ LL |         asm!("", out("vs61") _, out("v29") _);
    |                  register `vs61`
 
 error: register `v30` conflicts with register `vs62`
-  --> $DIR/bad-reg.rs:331:33
+  --> $DIR/bad-reg.rs:330:33
    |
 LL |         asm!("", out("vs62") _, out("v30") _);
    |                  -------------  ^^^^^^^^^^^^ register `v30`
@@ -699,7 +699,7 @@ LL |         asm!("", out("vs62") _, out("v30") _);
    |                  register `vs62`
 
 error: register `v31` conflicts with register `vs63`
-  --> $DIR/bad-reg.rs:333:33
+  --> $DIR/bad-reg.rs:332:33
    |
 LL |         asm!("", out("vs63") _, out("v31") _);
    |                  -------------  ^^^^^^^^^^^^ register `v31`
@@ -707,13 +707,13 @@ LL |         asm!("", out("vs63") _, out("v31") _);
    |                  register `vs63`
 
 error: cannot use register `r13`: r13 is a reserved register on this target
-  --> $DIR/bad-reg.rs:41:18
+  --> $DIR/bad-reg.rs:40:18
    |
 LL |         asm!("", out("r13") _);
    |                  ^^^^^^^^^^^^
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:64:27
+  --> $DIR/bad-reg.rs:63:27
    |
 LL |         asm!("", in("v0") x); // FIXME: should be ok if vsx is available
    |                           ^
@@ -721,7 +721,7 @@ LL |         asm!("", in("v0") x); // FIXME: should be ok if vsx is available
    = note: register class `vreg` supports these types: i8x16, i16x8, i32x4, f32x4, f32, f64, i64x2, f64x2
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:67:28
+  --> $DIR/bad-reg.rs:66:28
    |
 LL |         asm!("", out("v0") x); // FIXME: should be ok if vsx is available
    |                            ^
@@ -729,7 +729,7 @@ LL |         asm!("", out("v0") x); // FIXME: should be ok if vsx is available
    = note: register class `vreg` supports these types: i8x16, i16x8, i32x4, f32x4, f32, f64, i64x2, f64x2
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:75:35
+  --> $DIR/bad-reg.rs:74:35
    |
 LL |         asm!("/* {} */", in(vreg) x); // FIXME: should be ok if vsx is available
    |                                   ^
@@ -737,7 +737,7 @@ LL |         asm!("/* {} */", in(vreg) x); // FIXME: should be ok if vsx is avai
    = note: register class `vreg` supports these types: i8x16, i16x8, i32x4, f32x4, f32, f64, i64x2, f64x2
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:105:28
+  --> $DIR/bad-reg.rs:104:28
    |
 LL |         asm!("", in("vs0") x); // FIXME: should be ok if vsx is available
    |                            ^
@@ -745,7 +745,7 @@ LL |         asm!("", in("vs0") x); // FIXME: should be ok if vsx is available
    = note: register class `vsreg` supports these types: f32, f64, i8x16, i16x8, i32x4, i64x2, f32x4, f64x2
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:108:29
+  --> $DIR/bad-reg.rs:107:29
    |
 LL |         asm!("", out("vs0") x); // FIXME: should be ok if vsx is available
    |                             ^
@@ -753,7 +753,7 @@ LL |         asm!("", out("vs0") x); // FIXME: should be ok if vsx is available
    = note: register class `vsreg` supports these types: f32, f64, i8x16, i16x8, i32x4, i64x2, f32x4, f64x2
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:115:36
+  --> $DIR/bad-reg.rs:114:36
    |
 LL |         asm!("/* {} */", in(vsreg) x); // FIXME: should be ok if vsx is available
    |                                    ^
@@ -761,7 +761,7 @@ LL |         asm!("/* {} */", in(vsreg) x); // FIXME: should be ok if vsx is ava
    = note: register class `vsreg` supports these types: f32, f64, i8x16, i16x8, i32x4, i64x2, f32x4, f64x2
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:138:27
+  --> $DIR/bad-reg.rs:137:27
    |
 LL |         asm!("", in("cr") x);
    |                           ^
@@ -769,7 +769,7 @@ LL |         asm!("", in("cr") x);
    = note: register class `cr` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:141:28
+  --> $DIR/bad-reg.rs:140:28
    |
 LL |         asm!("", out("cr") x);
    |                            ^
@@ -777,7 +777,7 @@ LL |         asm!("", out("cr") x);
    = note: register class `cr` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:144:33
+  --> $DIR/bad-reg.rs:143:33
    |
 LL |         asm!("/* {} */", in(cr) x);
    |                                 ^
@@ -785,7 +785,7 @@ LL |         asm!("/* {} */", in(cr) x);
    = note: register class `cr` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:151:28
+  --> $DIR/bad-reg.rs:150:28
    |
 LL |         asm!("", in("ctr") x);
    |                            ^
@@ -793,7 +793,7 @@ LL |         asm!("", in("ctr") x);
    = note: register class `ctr` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:154:29
+  --> $DIR/bad-reg.rs:153:29
    |
 LL |         asm!("", out("ctr") x);
    |                             ^
@@ -801,7 +801,7 @@ LL |         asm!("", out("ctr") x);
    = note: register class `ctr` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:157:34
+  --> $DIR/bad-reg.rs:156:34
    |
 LL |         asm!("/* {} */", in(ctr) x);
    |                                  ^
@@ -809,7 +809,7 @@ LL |         asm!("/* {} */", in(ctr) x);
    = note: register class `ctr` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:164:27
+  --> $DIR/bad-reg.rs:163:27
    |
 LL |         asm!("", in("lr") x);
    |                           ^
@@ -817,7 +817,7 @@ LL |         asm!("", in("lr") x);
    = note: register class `lr` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:167:28
+  --> $DIR/bad-reg.rs:166:28
    |
 LL |         asm!("", out("lr") x);
    |                            ^
@@ -825,7 +825,7 @@ LL |         asm!("", out("lr") x);
    = note: register class `lr` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:170:33
+  --> $DIR/bad-reg.rs:169:33
    |
 LL |         asm!("/* {} */", in(lr) x);
    |                                 ^
@@ -833,7 +833,7 @@ LL |         asm!("/* {} */", in(lr) x);
    = note: register class `lr` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:177:28
+  --> $DIR/bad-reg.rs:176:28
    |
 LL |         asm!("", in("xer") x);
    |                            ^
@@ -841,7 +841,7 @@ LL |         asm!("", in("xer") x);
    = note: register class `xer` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:180:29
+  --> $DIR/bad-reg.rs:179:29
    |
 LL |         asm!("", out("xer") x);
    |                             ^
@@ -849,7 +849,7 @@ LL |         asm!("", out("xer") x);
    = note: register class `xer` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:183:34
+  --> $DIR/bad-reg.rs:182:34
    |
 LL |         asm!("/* {} */", in(xer) x);
    |                                  ^
diff --git a/tests/ui/asm/powerpc/bad-reg.powerpc.stderr b/tests/ui/asm/powerpc/bad-reg.powerpc.stderr
index 1f137b7e180b..64a8f6a3d5b9 100644
--- a/tests/ui/asm/powerpc/bad-reg.powerpc.stderr
+++ b/tests/ui/asm/powerpc/bad-reg.powerpc.stderr
@@ -1,137 +1,137 @@
 error: invalid register `sp`: the stack pointer cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:37:18
+  --> $DIR/bad-reg.rs:36:18
    |
 LL |         asm!("", out("sp") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `r2`: r2 is a system reserved register and cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:39:18
+  --> $DIR/bad-reg.rs:38:18
    |
 LL |         asm!("", out("r2") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `r29`: r29 is used internally by LLVM and cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:43:18
+  --> $DIR/bad-reg.rs:42:18
    |
 LL |         asm!("", out("r29") _);
    |                  ^^^^^^^^^^^^
 
 error: invalid register `r30`: r30 is used internally by LLVM and cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:45:18
+  --> $DIR/bad-reg.rs:44:18
    |
 LL |         asm!("", out("r30") _);
    |                  ^^^^^^^^^^^^
 
 error: invalid register `fp`: the frame pointer cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:47:18
+  --> $DIR/bad-reg.rs:46:18
    |
 LL |         asm!("", out("fp") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `vrsave`: the vrsave register cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:49:18
+  --> $DIR/bad-reg.rs:48:18
    |
 LL |         asm!("", out("vrsave") _);
    |                  ^^^^^^^^^^^^^^^
 
 error: register class `cr` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:138:18
+  --> $DIR/bad-reg.rs:137:18
    |
 LL |         asm!("", in("cr") x);
    |                  ^^^^^^^^^^
 
 error: register class `cr` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:141:18
+  --> $DIR/bad-reg.rs:140:18
    |
 LL |         asm!("", out("cr") x);
    |                  ^^^^^^^^^^^
 
 error: register class `cr` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:144:26
+  --> $DIR/bad-reg.rs:143:26
    |
 LL |         asm!("/* {} */", in(cr) x);
    |                          ^^^^^^^^
 
 error: register class `cr` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:147:26
+  --> $DIR/bad-reg.rs:146:26
    |
 LL |         asm!("/* {} */", out(cr) _);
    |                          ^^^^^^^^^
 
 error: register class `ctr` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:151:18
+  --> $DIR/bad-reg.rs:150:18
    |
 LL |         asm!("", in("ctr") x);
    |                  ^^^^^^^^^^^
 
 error: register class `ctr` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:154:18
+  --> $DIR/bad-reg.rs:153:18
    |
 LL |         asm!("", out("ctr") x);
    |                  ^^^^^^^^^^^^
 
 error: register class `ctr` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:157:26
+  --> $DIR/bad-reg.rs:156:26
    |
 LL |         asm!("/* {} */", in(ctr) x);
    |                          ^^^^^^^^^
 
 error: register class `ctr` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:160:26
+  --> $DIR/bad-reg.rs:159:26
    |
 LL |         asm!("/* {} */", out(ctr) _);
    |                          ^^^^^^^^^^
 
 error: register class `lr` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:164:18
+  --> $DIR/bad-reg.rs:163:18
    |
 LL |         asm!("", in("lr") x);
    |                  ^^^^^^^^^^
 
 error: register class `lr` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:167:18
+  --> $DIR/bad-reg.rs:166:18
    |
 LL |         asm!("", out("lr") x);
    |                  ^^^^^^^^^^^
 
 error: register class `lr` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:170:26
+  --> $DIR/bad-reg.rs:169:26
    |
 LL |         asm!("/* {} */", in(lr) x);
    |                          ^^^^^^^^
 
 error: register class `lr` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:173:26
+  --> $DIR/bad-reg.rs:172:26
    |
 LL |         asm!("/* {} */", out(lr) _);
    |                          ^^^^^^^^^
 
 error: register class `xer` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:177:18
+  --> $DIR/bad-reg.rs:176:18
    |
 LL |         asm!("", in("xer") x);
    |                  ^^^^^^^^^^^
 
 error: register class `xer` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:180:18
+  --> $DIR/bad-reg.rs:179:18
    |
 LL |         asm!("", out("xer") x);
    |                  ^^^^^^^^^^^^
 
 error: register class `xer` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:183:26
+  --> $DIR/bad-reg.rs:182:26
    |
 LL |         asm!("/* {} */", in(xer) x);
    |                          ^^^^^^^^^
 
 error: register class `xer` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:186:26
+  --> $DIR/bad-reg.rs:185:26
    |
 LL |         asm!("/* {} */", out(xer) _);
    |                          ^^^^^^^^^^
 
 error: register `cr0` conflicts with register `cr`
-  --> $DIR/bad-reg.rs:190:31
+  --> $DIR/bad-reg.rs:189:31
    |
 LL |         asm!("", out("cr") _, out("cr0") _);
    |                  -----------  ^^^^^^^^^^^^ register `cr0`
@@ -139,7 +139,7 @@ LL |         asm!("", out("cr") _, out("cr0") _);
    |                  register `cr`
 
 error: register `cr1` conflicts with register `cr`
-  --> $DIR/bad-reg.rs:192:31
+  --> $DIR/bad-reg.rs:191:31
    |
 LL |         asm!("", out("cr") _, out("cr1") _);
    |                  -----------  ^^^^^^^^^^^^ register `cr1`
@@ -147,7 +147,7 @@ LL |         asm!("", out("cr") _, out("cr1") _);
    |                  register `cr`
 
 error: register `cr2` conflicts with register `cr`
-  --> $DIR/bad-reg.rs:194:31
+  --> $DIR/bad-reg.rs:193:31
    |
 LL |         asm!("", out("cr") _, out("cr2") _);
    |                  -----------  ^^^^^^^^^^^^ register `cr2`
@@ -155,7 +155,7 @@ LL |         asm!("", out("cr") _, out("cr2") _);
    |                  register `cr`
 
 error: register `cr3` conflicts with register `cr`
-  --> $DIR/bad-reg.rs:196:31
+  --> $DIR/bad-reg.rs:195:31
    |
 LL |         asm!("", out("cr") _, out("cr3") _);
    |                  -----------  ^^^^^^^^^^^^ register `cr3`
@@ -163,7 +163,7 @@ LL |         asm!("", out("cr") _, out("cr3") _);
    |                  register `cr`
 
 error: register `cr4` conflicts with register `cr`
-  --> $DIR/bad-reg.rs:198:31
+  --> $DIR/bad-reg.rs:197:31
    |
 LL |         asm!("", out("cr") _, out("cr4") _);
    |                  -----------  ^^^^^^^^^^^^ register `cr4`
@@ -171,7 +171,7 @@ LL |         asm!("", out("cr") _, out("cr4") _);
    |                  register `cr`
 
 error: register `cr5` conflicts with register `cr`
-  --> $DIR/bad-reg.rs:200:31
+  --> $DIR/bad-reg.rs:199:31
    |
 LL |         asm!("", out("cr") _, out("cr5") _);
    |                  -----------  ^^^^^^^^^^^^ register `cr5`
@@ -179,7 +179,7 @@ LL |         asm!("", out("cr") _, out("cr5") _);
    |                  register `cr`
 
 error: register `cr6` conflicts with register `cr`
-  --> $DIR/bad-reg.rs:202:31
+  --> $DIR/bad-reg.rs:201:31
    |
 LL |         asm!("", out("cr") _, out("cr6") _);
    |                  -----------  ^^^^^^^^^^^^ register `cr6`
@@ -187,7 +187,7 @@ LL |         asm!("", out("cr") _, out("cr6") _);
    |                  register `cr`
 
 error: register `cr7` conflicts with register `cr`
-  --> $DIR/bad-reg.rs:204:31
+  --> $DIR/bad-reg.rs:203:31
    |
 LL |         asm!("", out("cr") _, out("cr7") _);
    |                  -----------  ^^^^^^^^^^^^ register `cr7`
@@ -195,7 +195,7 @@ LL |         asm!("", out("cr") _, out("cr7") _);
    |                  register `cr`
 
 error: register `vs0` conflicts with register `f0`
-  --> $DIR/bad-reg.rs:207:31
+  --> $DIR/bad-reg.rs:206:31
    |
 LL |         asm!("", out("f0") _, out("vs0") _);
    |                  -----------  ^^^^^^^^^^^^ register `vs0`
@@ -203,7 +203,7 @@ LL |         asm!("", out("f0") _, out("vs0") _);
    |                  register `f0`
 
 error: register `vs1` conflicts with register `f1`
-  --> $DIR/bad-reg.rs:209:31
+  --> $DIR/bad-reg.rs:208:31
    |
 LL |         asm!("", out("f1") _, out("vs1") _);
    |                  -----------  ^^^^^^^^^^^^ register `vs1`
@@ -211,7 +211,7 @@ LL |         asm!("", out("f1") _, out("vs1") _);
    |                  register `f1`
 
 error: register `vs2` conflicts with register `f2`
-  --> $DIR/bad-reg.rs:211:31
+  --> $DIR/bad-reg.rs:210:31
    |
 LL |         asm!("", out("f2") _, out("vs2") _);
    |                  -----------  ^^^^^^^^^^^^ register `vs2`
@@ -219,7 +219,7 @@ LL |         asm!("", out("f2") _, out("vs2") _);
    |                  register `f2`
 
 error: register `vs3` conflicts with register `f3`
-  --> $DIR/bad-reg.rs:213:31
+  --> $DIR/bad-reg.rs:212:31
    |
 LL |         asm!("", out("f3") _, out("vs3") _);
    |                  -----------  ^^^^^^^^^^^^ register `vs3`
@@ -227,7 +227,7 @@ LL |         asm!("", out("f3") _, out("vs3") _);
    |                  register `f3`
 
 error: register `vs4` conflicts with register `f4`
-  --> $DIR/bad-reg.rs:215:31
+  --> $DIR/bad-reg.rs:214:31
    |
 LL |         asm!("", out("f4") _, out("vs4") _);
    |                  -----------  ^^^^^^^^^^^^ register `vs4`
@@ -235,7 +235,7 @@ LL |         asm!("", out("f4") _, out("vs4") _);
    |                  register `f4`
 
 error: register `vs5` conflicts with register `f5`
-  --> $DIR/bad-reg.rs:217:31
+  --> $DIR/bad-reg.rs:216:31
    |
 LL |         asm!("", out("f5") _, out("vs5") _);
    |                  -----------  ^^^^^^^^^^^^ register `vs5`
@@ -243,7 +243,7 @@ LL |         asm!("", out("f5") _, out("vs5") _);
    |                  register `f5`
 
 error: register `vs6` conflicts with register `f6`
-  --> $DIR/bad-reg.rs:219:31
+  --> $DIR/bad-reg.rs:218:31
    |
 LL |         asm!("", out("f6") _, out("vs6") _);
    |                  -----------  ^^^^^^^^^^^^ register `vs6`
@@ -251,7 +251,7 @@ LL |         asm!("", out("f6") _, out("vs6") _);
    |                  register `f6`
 
 error: register `vs7` conflicts with register `f7`
-  --> $DIR/bad-reg.rs:221:31
+  --> $DIR/bad-reg.rs:220:31
    |
 LL |         asm!("", out("f7") _, out("vs7") _);
    |                  -----------  ^^^^^^^^^^^^ register `vs7`
@@ -259,7 +259,7 @@ LL |         asm!("", out("f7") _, out("vs7") _);
    |                  register `f7`
 
 error: register `vs8` conflicts with register `f8`
-  --> $DIR/bad-reg.rs:223:31
+  --> $DIR/bad-reg.rs:222:31
    |
 LL |         asm!("", out("f8") _, out("vs8") _);
    |                  -----------  ^^^^^^^^^^^^ register `vs8`
@@ -267,7 +267,7 @@ LL |         asm!("", out("f8") _, out("vs8") _);
    |                  register `f8`
 
 error: register `vs9` conflicts with register `f9`
-  --> $DIR/bad-reg.rs:225:31
+  --> $DIR/bad-reg.rs:224:31
    |
 LL |         asm!("", out("f9") _, out("vs9") _);
    |                  -----------  ^^^^^^^^^^^^ register `vs9`
@@ -275,7 +275,7 @@ LL |         asm!("", out("f9") _, out("vs9") _);
    |                  register `f9`
 
 error: register `vs10` conflicts with register `f10`
-  --> $DIR/bad-reg.rs:227:32
+  --> $DIR/bad-reg.rs:226:32
    |
 LL |         asm!("", out("f10") _, out("vs10") _);
    |                  ------------  ^^^^^^^^^^^^^ register `vs10`
@@ -283,7 +283,7 @@ LL |         asm!("", out("f10") _, out("vs10") _);
    |                  register `f10`
 
 error: register `vs11` conflicts with register `f11`
-  --> $DIR/bad-reg.rs:229:32
+  --> $DIR/bad-reg.rs:228:32
    |
 LL |         asm!("", out("f11") _, out("vs11") _);
    |                  ------------  ^^^^^^^^^^^^^ register `vs11`
@@ -291,7 +291,7 @@ LL |         asm!("", out("f11") _, out("vs11") _);
    |                  register `f11`
 
 error: register `vs12` conflicts with register `f12`
-  --> $DIR/bad-reg.rs:231:32
+  --> $DIR/bad-reg.rs:230:32
    |
 LL |         asm!("", out("f12") _, out("vs12") _);
    |                  ------------  ^^^^^^^^^^^^^ register `vs12`
@@ -299,7 +299,7 @@ LL |         asm!("", out("f12") _, out("vs12") _);
    |                  register `f12`
 
 error: register `vs13` conflicts with register `f13`
-  --> $DIR/bad-reg.rs:233:32
+  --> $DIR/bad-reg.rs:232:32
    |
 LL |         asm!("", out("f13") _, out("vs13") _);
    |                  ------------  ^^^^^^^^^^^^^ register `vs13`
@@ -307,7 +307,7 @@ LL |         asm!("", out("f13") _, out("vs13") _);
    |                  register `f13`
 
 error: register `vs14` conflicts with register `f14`
-  --> $DIR/bad-reg.rs:235:32
+  --> $DIR/bad-reg.rs:234:32
    |
 LL |         asm!("", out("f14") _, out("vs14") _);
    |                  ------------  ^^^^^^^^^^^^^ register `vs14`
@@ -315,7 +315,7 @@ LL |         asm!("", out("f14") _, out("vs14") _);
    |                  register `f14`
 
 error: register `vs15` conflicts with register `f15`
-  --> $DIR/bad-reg.rs:237:32
+  --> $DIR/bad-reg.rs:236:32
    |
 LL |         asm!("", out("f15") _, out("vs15") _);
    |                  ------------  ^^^^^^^^^^^^^ register `vs15`
@@ -323,7 +323,7 @@ LL |         asm!("", out("f15") _, out("vs15") _);
    |                  register `f15`
 
 error: register `vs16` conflicts with register `f16`
-  --> $DIR/bad-reg.rs:239:32
+  --> $DIR/bad-reg.rs:238:32
    |
 LL |         asm!("", out("f16") _, out("vs16") _);
    |                  ------------  ^^^^^^^^^^^^^ register `vs16`
@@ -331,7 +331,7 @@ LL |         asm!("", out("f16") _, out("vs16") _);
    |                  register `f16`
 
 error: register `vs17` conflicts with register `f17`
-  --> $DIR/bad-reg.rs:241:32
+  --> $DIR/bad-reg.rs:240:32
    |
 LL |         asm!("", out("f17") _, out("vs17") _);
    |                  ------------  ^^^^^^^^^^^^^ register `vs17`
@@ -339,7 +339,7 @@ LL |         asm!("", out("f17") _, out("vs17") _);
    |                  register `f17`
 
 error: register `vs18` conflicts with register `f18`
-  --> $DIR/bad-reg.rs:243:32
+  --> $DIR/bad-reg.rs:242:32
    |
 LL |         asm!("", out("f18") _, out("vs18") _);
    |                  ------------  ^^^^^^^^^^^^^ register `vs18`
@@ -347,7 +347,7 @@ LL |         asm!("", out("f18") _, out("vs18") _);
    |                  register `f18`
 
 error: register `vs19` conflicts with register `f19`
-  --> $DIR/bad-reg.rs:245:32
+  --> $DIR/bad-reg.rs:244:32
    |
 LL |         asm!("", out("f19") _, out("vs19") _);
    |                  ------------  ^^^^^^^^^^^^^ register `vs19`
@@ -355,7 +355,7 @@ LL |         asm!("", out("f19") _, out("vs19") _);
    |                  register `f19`
 
 error: register `vs20` conflicts with register `f20`
-  --> $DIR/bad-reg.rs:247:32
+  --> $DIR/bad-reg.rs:246:32
    |
 LL |         asm!("", out("f20") _, out("vs20") _);
    |                  ------------  ^^^^^^^^^^^^^ register `vs20`
@@ -363,7 +363,7 @@ LL |         asm!("", out("f20") _, out("vs20") _);
    |                  register `f20`
 
 error: register `vs21` conflicts with register `f21`
-  --> $DIR/bad-reg.rs:249:32
+  --> $DIR/bad-reg.rs:248:32
    |
 LL |         asm!("", out("f21") _, out("vs21") _);
    |                  ------------  ^^^^^^^^^^^^^ register `vs21`
@@ -371,7 +371,7 @@ LL |         asm!("", out("f21") _, out("vs21") _);
    |                  register `f21`
 
 error: register `vs22` conflicts with register `f22`
-  --> $DIR/bad-reg.rs:251:32
+  --> $DIR/bad-reg.rs:250:32
    |
 LL |         asm!("", out("f22") _, out("vs22") _);
    |                  ------------  ^^^^^^^^^^^^^ register `vs22`
@@ -379,7 +379,7 @@ LL |         asm!("", out("f22") _, out("vs22") _);
    |                  register `f22`
 
 error: register `vs23` conflicts with register `f23`
-  --> $DIR/bad-reg.rs:253:32
+  --> $DIR/bad-reg.rs:252:32
    |
 LL |         asm!("", out("f23") _, out("vs23") _);
    |                  ------------  ^^^^^^^^^^^^^ register `vs23`
@@ -387,7 +387,7 @@ LL |         asm!("", out("f23") _, out("vs23") _);
    |                  register `f23`
 
 error: register `vs24` conflicts with register `f24`
-  --> $DIR/bad-reg.rs:255:32
+  --> $DIR/bad-reg.rs:254:32
    |
 LL |         asm!("", out("f24") _, out("vs24") _);
    |                  ------------  ^^^^^^^^^^^^^ register `vs24`
@@ -395,7 +395,7 @@ LL |         asm!("", out("f24") _, out("vs24") _);
    |                  register `f24`
 
 error: register `vs25` conflicts with register `f25`
-  --> $DIR/bad-reg.rs:257:32
+  --> $DIR/bad-reg.rs:256:32
    |
 LL |         asm!("", out("f25") _, out("vs25") _);
    |                  ------------  ^^^^^^^^^^^^^ register `vs25`
@@ -403,7 +403,7 @@ LL |         asm!("", out("f25") _, out("vs25") _);
    |                  register `f25`
 
 error: register `vs26` conflicts with register `f26`
-  --> $DIR/bad-reg.rs:259:32
+  --> $DIR/bad-reg.rs:258:32
    |
 LL |         asm!("", out("f26") _, out("vs26") _);
    |                  ------------  ^^^^^^^^^^^^^ register `vs26`
@@ -411,7 +411,7 @@ LL |         asm!("", out("f26") _, out("vs26") _);
    |                  register `f26`
 
 error: register `vs27` conflicts with register `f27`
-  --> $DIR/bad-reg.rs:261:32
+  --> $DIR/bad-reg.rs:260:32
    |
 LL |         asm!("", out("f27") _, out("vs27") _);
    |                  ------------  ^^^^^^^^^^^^^ register `vs27`
@@ -419,7 +419,7 @@ LL |         asm!("", out("f27") _, out("vs27") _);
    |                  register `f27`
 
 error: register `vs28` conflicts with register `f28`
-  --> $DIR/bad-reg.rs:263:32
+  --> $DIR/bad-reg.rs:262:32
    |
 LL |         asm!("", out("f28") _, out("vs28") _);
    |                  ------------  ^^^^^^^^^^^^^ register `vs28`
@@ -427,7 +427,7 @@ LL |         asm!("", out("f28") _, out("vs28") _);
    |                  register `f28`
 
 error: register `vs29` conflicts with register `f29`
-  --> $DIR/bad-reg.rs:265:32
+  --> $DIR/bad-reg.rs:264:32
    |
 LL |         asm!("", out("f29") _, out("vs29") _);
    |                  ------------  ^^^^^^^^^^^^^ register `vs29`
@@ -435,7 +435,7 @@ LL |         asm!("", out("f29") _, out("vs29") _);
    |                  register `f29`
 
 error: register `vs30` conflicts with register `f30`
-  --> $DIR/bad-reg.rs:267:32
+  --> $DIR/bad-reg.rs:266:32
    |
 LL |         asm!("", out("f30") _, out("vs30") _);
    |                  ------------  ^^^^^^^^^^^^^ register `vs30`
@@ -443,7 +443,7 @@ LL |         asm!("", out("f30") _, out("vs30") _);
    |                  register `f30`
 
 error: register `vs31` conflicts with register `f31`
-  --> $DIR/bad-reg.rs:269:32
+  --> $DIR/bad-reg.rs:268:32
    |
 LL |         asm!("", out("f31") _, out("vs31") _);
    |                  ------------  ^^^^^^^^^^^^^ register `vs31`
@@ -451,7 +451,7 @@ LL |         asm!("", out("f31") _, out("vs31") _);
    |                  register `f31`
 
 error: register `v0` conflicts with register `vs32`
-  --> $DIR/bad-reg.rs:271:33
+  --> $DIR/bad-reg.rs:270:33
    |
 LL |         asm!("", out("vs32") _, out("v0") _);
    |                  -------------  ^^^^^^^^^^^ register `v0`
@@ -459,7 +459,7 @@ LL |         asm!("", out("vs32") _, out("v0") _);
    |                  register `vs32`
 
 error: register `v1` conflicts with register `vs33`
-  --> $DIR/bad-reg.rs:273:33
+  --> $DIR/bad-reg.rs:272:33
    |
 LL |         asm!("", out("vs33") _, out("v1") _);
    |                  -------------  ^^^^^^^^^^^ register `v1`
@@ -467,7 +467,7 @@ LL |         asm!("", out("vs33") _, out("v1") _);
    |                  register `vs33`
 
 error: register `v2` conflicts with register `vs34`
-  --> $DIR/bad-reg.rs:275:33
+  --> $DIR/bad-reg.rs:274:33
    |
 LL |         asm!("", out("vs34") _, out("v2") _);
    |                  -------------  ^^^^^^^^^^^ register `v2`
@@ -475,7 +475,7 @@ LL |         asm!("", out("vs34") _, out("v2") _);
    |                  register `vs34`
 
 error: register `v3` conflicts with register `vs35`
-  --> $DIR/bad-reg.rs:277:33
+  --> $DIR/bad-reg.rs:276:33
    |
 LL |         asm!("", out("vs35") _, out("v3") _);
    |                  -------------  ^^^^^^^^^^^ register `v3`
@@ -483,7 +483,7 @@ LL |         asm!("", out("vs35") _, out("v3") _);
    |                  register `vs35`
 
 error: register `v4` conflicts with register `vs36`
-  --> $DIR/bad-reg.rs:279:33
+  --> $DIR/bad-reg.rs:278:33
    |
 LL |         asm!("", out("vs36") _, out("v4") _);
    |                  -------------  ^^^^^^^^^^^ register `v4`
@@ -491,7 +491,7 @@ LL |         asm!("", out("vs36") _, out("v4") _);
    |                  register `vs36`
 
 error: register `v5` conflicts with register `vs37`
-  --> $DIR/bad-reg.rs:281:33
+  --> $DIR/bad-reg.rs:280:33
    |
 LL |         asm!("", out("vs37") _, out("v5") _);
    |                  -------------  ^^^^^^^^^^^ register `v5`
@@ -499,7 +499,7 @@ LL |         asm!("", out("vs37") _, out("v5") _);
    |                  register `vs37`
 
 error: register `v6` conflicts with register `vs38`
-  --> $DIR/bad-reg.rs:283:33
+  --> $DIR/bad-reg.rs:282:33
    |
 LL |         asm!("", out("vs38") _, out("v6") _);
    |                  -------------  ^^^^^^^^^^^ register `v6`
@@ -507,7 +507,7 @@ LL |         asm!("", out("vs38") _, out("v6") _);
    |                  register `vs38`
 
 error: register `v7` conflicts with register `vs39`
-  --> $DIR/bad-reg.rs:285:33
+  --> $DIR/bad-reg.rs:284:33
    |
 LL |         asm!("", out("vs39") _, out("v7") _);
    |                  -------------  ^^^^^^^^^^^ register `v7`
@@ -515,7 +515,7 @@ LL |         asm!("", out("vs39") _, out("v7") _);
    |                  register `vs39`
 
 error: register `v8` conflicts with register `vs40`
-  --> $DIR/bad-reg.rs:287:33
+  --> $DIR/bad-reg.rs:286:33
    |
 LL |         asm!("", out("vs40") _, out("v8") _);
    |                  -------------  ^^^^^^^^^^^ register `v8`
@@ -523,7 +523,7 @@ LL |         asm!("", out("vs40") _, out("v8") _);
    |                  register `vs40`
 
 error: register `v9` conflicts with register `vs41`
-  --> $DIR/bad-reg.rs:289:33
+  --> $DIR/bad-reg.rs:288:33
    |
 LL |         asm!("", out("vs41") _, out("v9") _);
    |                  -------------  ^^^^^^^^^^^ register `v9`
@@ -531,7 +531,7 @@ LL |         asm!("", out("vs41") _, out("v9") _);
    |                  register `vs41`
 
 error: register `v10` conflicts with register `vs42`
-  --> $DIR/bad-reg.rs:291:33
+  --> $DIR/bad-reg.rs:290:33
    |
 LL |         asm!("", out("vs42") _, out("v10") _);
    |                  -------------  ^^^^^^^^^^^^ register `v10`
@@ -539,7 +539,7 @@ LL |         asm!("", out("vs42") _, out("v10") _);
    |                  register `vs42`
 
 error: register `v11` conflicts with register `vs43`
-  --> $DIR/bad-reg.rs:293:33
+  --> $DIR/bad-reg.rs:292:33
    |
 LL |         asm!("", out("vs43") _, out("v11") _);
    |                  -------------  ^^^^^^^^^^^^ register `v11`
@@ -547,7 +547,7 @@ LL |         asm!("", out("vs43") _, out("v11") _);
    |                  register `vs43`
 
 error: register `v12` conflicts with register `vs44`
-  --> $DIR/bad-reg.rs:295:33
+  --> $DIR/bad-reg.rs:294:33
    |
 LL |         asm!("", out("vs44") _, out("v12") _);
    |                  -------------  ^^^^^^^^^^^^ register `v12`
@@ -555,7 +555,7 @@ LL |         asm!("", out("vs44") _, out("v12") _);
    |                  register `vs44`
 
 error: register `v13` conflicts with register `vs45`
-  --> $DIR/bad-reg.rs:297:33
+  --> $DIR/bad-reg.rs:296:33
    |
 LL |         asm!("", out("vs45") _, out("v13") _);
    |                  -------------  ^^^^^^^^^^^^ register `v13`
@@ -563,7 +563,7 @@ LL |         asm!("", out("vs45") _, out("v13") _);
    |                  register `vs45`
 
 error: register `v14` conflicts with register `vs46`
-  --> $DIR/bad-reg.rs:299:33
+  --> $DIR/bad-reg.rs:298:33
    |
 LL |         asm!("", out("vs46") _, out("v14") _);
    |                  -------------  ^^^^^^^^^^^^ register `v14`
@@ -571,7 +571,7 @@ LL |         asm!("", out("vs46") _, out("v14") _);
    |                  register `vs46`
 
 error: register `v15` conflicts with register `vs47`
-  --> $DIR/bad-reg.rs:301:33
+  --> $DIR/bad-reg.rs:300:33
    |
 LL |         asm!("", out("vs47") _, out("v15") _);
    |                  -------------  ^^^^^^^^^^^^ register `v15`
@@ -579,7 +579,7 @@ LL |         asm!("", out("vs47") _, out("v15") _);
    |                  register `vs47`
 
 error: register `v16` conflicts with register `vs48`
-  --> $DIR/bad-reg.rs:303:33
+  --> $DIR/bad-reg.rs:302:33
    |
 LL |         asm!("", out("vs48") _, out("v16") _);
    |                  -------------  ^^^^^^^^^^^^ register `v16`
@@ -587,7 +587,7 @@ LL |         asm!("", out("vs48") _, out("v16") _);
    |                  register `vs48`
 
 error: register `v17` conflicts with register `vs49`
-  --> $DIR/bad-reg.rs:305:33
+  --> $DIR/bad-reg.rs:304:33
    |
 LL |         asm!("", out("vs49") _, out("v17") _);
    |                  -------------  ^^^^^^^^^^^^ register `v17`
@@ -595,7 +595,7 @@ LL |         asm!("", out("vs49") _, out("v17") _);
    |                  register `vs49`
 
 error: register `v18` conflicts with register `vs50`
-  --> $DIR/bad-reg.rs:307:33
+  --> $DIR/bad-reg.rs:306:33
    |
 LL |         asm!("", out("vs50") _, out("v18") _);
    |                  -------------  ^^^^^^^^^^^^ register `v18`
@@ -603,7 +603,7 @@ LL |         asm!("", out("vs50") _, out("v18") _);
    |                  register `vs50`
 
 error: register `v19` conflicts with register `vs51`
-  --> $DIR/bad-reg.rs:309:33
+  --> $DIR/bad-reg.rs:308:33
    |
 LL |         asm!("", out("vs51") _, out("v19") _);
    |                  -------------  ^^^^^^^^^^^^ register `v19`
@@ -611,7 +611,7 @@ LL |         asm!("", out("vs51") _, out("v19") _);
    |                  register `vs51`
 
 error: register `v20` conflicts with register `vs52`
-  --> $DIR/bad-reg.rs:311:33
+  --> $DIR/bad-reg.rs:310:33
    |
 LL |         asm!("", out("vs52") _, out("v20") _);
    |                  -------------  ^^^^^^^^^^^^ register `v20`
@@ -619,7 +619,7 @@ LL |         asm!("", out("vs52") _, out("v20") _);
    |                  register `vs52`
 
 error: register `v21` conflicts with register `vs53`
-  --> $DIR/bad-reg.rs:313:33
+  --> $DIR/bad-reg.rs:312:33
    |
 LL |         asm!("", out("vs53") _, out("v21") _);
    |                  -------------  ^^^^^^^^^^^^ register `v21`
@@ -627,7 +627,7 @@ LL |         asm!("", out("vs53") _, out("v21") _);
    |                  register `vs53`
 
 error: register `v22` conflicts with register `vs54`
-  --> $DIR/bad-reg.rs:315:33
+  --> $DIR/bad-reg.rs:314:33
    |
 LL |         asm!("", out("vs54") _, out("v22") _);
    |                  -------------  ^^^^^^^^^^^^ register `v22`
@@ -635,7 +635,7 @@ LL |         asm!("", out("vs54") _, out("v22") _);
    |                  register `vs54`
 
 error: register `v23` conflicts with register `vs55`
-  --> $DIR/bad-reg.rs:317:33
+  --> $DIR/bad-reg.rs:316:33
    |
 LL |         asm!("", out("vs55") _, out("v23") _);
    |                  -------------  ^^^^^^^^^^^^ register `v23`
@@ -643,7 +643,7 @@ LL |         asm!("", out("vs55") _, out("v23") _);
    |                  register `vs55`
 
 error: register `v24` conflicts with register `vs56`
-  --> $DIR/bad-reg.rs:319:33
+  --> $DIR/bad-reg.rs:318:33
    |
 LL |         asm!("", out("vs56") _, out("v24") _);
    |                  -------------  ^^^^^^^^^^^^ register `v24`
@@ -651,7 +651,7 @@ LL |         asm!("", out("vs56") _, out("v24") _);
    |                  register `vs56`
 
 error: register `v25` conflicts with register `vs57`
-  --> $DIR/bad-reg.rs:321:33
+  --> $DIR/bad-reg.rs:320:33
    |
 LL |         asm!("", out("vs57") _, out("v25") _);
    |                  -------------  ^^^^^^^^^^^^ register `v25`
@@ -659,7 +659,7 @@ LL |         asm!("", out("vs57") _, out("v25") _);
    |                  register `vs57`
 
 error: register `v26` conflicts with register `vs58`
-  --> $DIR/bad-reg.rs:323:33
+  --> $DIR/bad-reg.rs:322:33
    |
 LL |         asm!("", out("vs58") _, out("v26") _);
    |                  -------------  ^^^^^^^^^^^^ register `v26`
@@ -667,7 +667,7 @@ LL |         asm!("", out("vs58") _, out("v26") _);
    |                  register `vs58`
 
 error: register `v27` conflicts with register `vs59`
-  --> $DIR/bad-reg.rs:325:33
+  --> $DIR/bad-reg.rs:324:33
    |
 LL |         asm!("", out("vs59") _, out("v27") _);
    |                  -------------  ^^^^^^^^^^^^ register `v27`
@@ -675,7 +675,7 @@ LL |         asm!("", out("vs59") _, out("v27") _);
    |                  register `vs59`
 
 error: register `v28` conflicts with register `vs60`
-  --> $DIR/bad-reg.rs:327:33
+  --> $DIR/bad-reg.rs:326:33
    |
 LL |         asm!("", out("vs60") _, out("v28") _);
    |                  -------------  ^^^^^^^^^^^^ register `v28`
@@ -683,7 +683,7 @@ LL |         asm!("", out("vs60") _, out("v28") _);
    |                  register `vs60`
 
 error: register `v29` conflicts with register `vs61`
-  --> $DIR/bad-reg.rs:329:33
+  --> $DIR/bad-reg.rs:328:33
    |
 LL |         asm!("", out("vs61") _, out("v29") _);
    |                  -------------  ^^^^^^^^^^^^ register `v29`
@@ -691,7 +691,7 @@ LL |         asm!("", out("vs61") _, out("v29") _);
    |                  register `vs61`
 
 error: register `v30` conflicts with register `vs62`
-  --> $DIR/bad-reg.rs:331:33
+  --> $DIR/bad-reg.rs:330:33
    |
 LL |         asm!("", out("vs62") _, out("v30") _);
    |                  -------------  ^^^^^^^^^^^^ register `v30`
@@ -699,7 +699,7 @@ LL |         asm!("", out("vs62") _, out("v30") _);
    |                  register `vs62`
 
 error: register `v31` conflicts with register `vs63`
-  --> $DIR/bad-reg.rs:333:33
+  --> $DIR/bad-reg.rs:332:33
    |
 LL |         asm!("", out("vs63") _, out("v31") _);
    |                  -------------  ^^^^^^^^^^^^ register `v31`
@@ -707,133 +707,133 @@ LL |         asm!("", out("vs63") _, out("v31") _);
    |                  register `vs63`
 
 error: cannot use register `r13`: r13 is a reserved register on this target
-  --> $DIR/bad-reg.rs:41:18
+  --> $DIR/bad-reg.rs:40:18
    |
 LL |         asm!("", out("r13") _);
    |                  ^^^^^^^^^^^^
 
 error: register class `vreg` requires at least one of the following target features: altivec, vsx
-  --> $DIR/bad-reg.rs:54:18
+  --> $DIR/bad-reg.rs:53:18
    |
 LL |         asm!("", in("v0") v32x4); // requires altivec
    |                  ^^^^^^^^^^^^^^
 
 error: register class `vreg` requires at least one of the following target features: altivec, vsx
-  --> $DIR/bad-reg.rs:56:18
+  --> $DIR/bad-reg.rs:55:18
    |
 LL |         asm!("", out("v0") v32x4); // requires altivec
    |                  ^^^^^^^^^^^^^^^
 
 error: register class `vreg` requires at least one of the following target features: altivec, vsx
-  --> $DIR/bad-reg.rs:58:18
+  --> $DIR/bad-reg.rs:57:18
    |
 LL |         asm!("", in("v0") v64x2); // requires vsx
    |                  ^^^^^^^^^^^^^^
 
 error: register class `vreg` requires at least one of the following target features: altivec, vsx
-  --> $DIR/bad-reg.rs:61:18
+  --> $DIR/bad-reg.rs:60:18
    |
 LL |         asm!("", out("v0") v64x2); // requires vsx
    |                  ^^^^^^^^^^^^^^^
 
 error: register class `vreg` requires at least one of the following target features: altivec, vsx
-  --> $DIR/bad-reg.rs:64:18
+  --> $DIR/bad-reg.rs:63:18
    |
 LL |         asm!("", in("v0") x); // FIXME: should be ok if vsx is available
    |                  ^^^^^^^^^^
 
 error: register class `vreg` requires at least one of the following target features: altivec, vsx
-  --> $DIR/bad-reg.rs:67:18
+  --> $DIR/bad-reg.rs:66:18
    |
 LL |         asm!("", out("v0") x); // FIXME: should be ok if vsx is available
    |                  ^^^^^^^^^^^
 
 error: register class `vreg` requires at least one of the following target features: altivec, vsx
-  --> $DIR/bad-reg.rs:70:26
+  --> $DIR/bad-reg.rs:69:26
    |
 LL |         asm!("/* {} */", in(vreg) v32x4); // requires altivec
    |                          ^^^^^^^^^^^^^^
 
 error: register class `vreg` requires at least one of the following target features: altivec, vsx
-  --> $DIR/bad-reg.rs:72:26
+  --> $DIR/bad-reg.rs:71:26
    |
 LL |         asm!("/* {} */", in(vreg) v64x2); // requires vsx
    |                          ^^^^^^^^^^^^^^
 
 error: register class `vreg` requires at least one of the following target features: altivec, vsx
-  --> $DIR/bad-reg.rs:75:26
+  --> $DIR/bad-reg.rs:74:26
    |
 LL |         asm!("/* {} */", in(vreg) x); // FIXME: should be ok if vsx is available
    |                          ^^^^^^^^^^
 
 error: register class `vreg` requires at least one of the following target features: altivec, vsx
-  --> $DIR/bad-reg.rs:78:26
+  --> $DIR/bad-reg.rs:77:26
    |
 LL |         asm!("/* {} */", out(vreg) _); // requires altivec
    |                          ^^^^^^^^^^^
 
 error: register class `vsreg` requires the `vsx` target feature
-  --> $DIR/bad-reg.rs:97:18
+  --> $DIR/bad-reg.rs:96:18
    |
 LL |         asm!("", in("vs0") v32x4); // requires vsx
    |                  ^^^^^^^^^^^^^^^
 
 error: register class `vsreg` requires the `vsx` target feature
-  --> $DIR/bad-reg.rs:99:18
+  --> $DIR/bad-reg.rs:98:18
    |
 LL |         asm!("", out("vs0") v32x4); // requires vsx
    |                  ^^^^^^^^^^^^^^^^
 
 error: register class `vsreg` requires the `vsx` target feature
-  --> $DIR/bad-reg.rs:101:18
+  --> $DIR/bad-reg.rs:100:18
    |
 LL |         asm!("", in("vs0") v64x2); // requires vsx
    |                  ^^^^^^^^^^^^^^^
 
 error: register class `vsreg` requires the `vsx` target feature
-  --> $DIR/bad-reg.rs:103:18
+  --> $DIR/bad-reg.rs:102:18
    |
 LL |         asm!("", out("vs0") v64x2); // requires vsx
    |                  ^^^^^^^^^^^^^^^^
 
 error: register class `vsreg` requires the `vsx` target feature
-  --> $DIR/bad-reg.rs:105:18
+  --> $DIR/bad-reg.rs:104:18
    |
 LL |         asm!("", in("vs0") x); // FIXME: should be ok if vsx is available
    |                  ^^^^^^^^^^^
 
 error: register class `vsreg` requires the `vsx` target feature
-  --> $DIR/bad-reg.rs:108:18
+  --> $DIR/bad-reg.rs:107:18
    |
 LL |         asm!("", out("vs0") x); // FIXME: should be ok if vsx is available
    |                  ^^^^^^^^^^^^
 
 error: register class `vsreg` requires the `vsx` target feature
-  --> $DIR/bad-reg.rs:111:26
+  --> $DIR/bad-reg.rs:110:26
    |
 LL |         asm!("/* {} */", in(vsreg) v32x4); // requires vsx
    |                          ^^^^^^^^^^^^^^^
 
 error: register class `vsreg` requires the `vsx` target feature
-  --> $DIR/bad-reg.rs:113:26
+  --> $DIR/bad-reg.rs:112:26
    |
 LL |         asm!("/* {} */", in(vsreg) v64x2); // requires vsx
    |                          ^^^^^^^^^^^^^^^
 
 error: register class `vsreg` requires the `vsx` target feature
-  --> $DIR/bad-reg.rs:115:26
+  --> $DIR/bad-reg.rs:114:26
    |
 LL |         asm!("/* {} */", in(vsreg) x); // FIXME: should be ok if vsx is available
    |                          ^^^^^^^^^^^
 
 error: register class `vsreg` requires the `vsx` target feature
-  --> $DIR/bad-reg.rs:118:26
+  --> $DIR/bad-reg.rs:117:26
    |
 LL |         asm!("/* {} */", out(vsreg) _); // requires vsx
    |                          ^^^^^^^^^^^^
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:138:27
+  --> $DIR/bad-reg.rs:137:27
    |
 LL |         asm!("", in("cr") x);
    |                           ^
@@ -841,7 +841,7 @@ LL |         asm!("", in("cr") x);
    = note: register class `cr` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:141:28
+  --> $DIR/bad-reg.rs:140:28
    |
 LL |         asm!("", out("cr") x);
    |                            ^
@@ -849,7 +849,7 @@ LL |         asm!("", out("cr") x);
    = note: register class `cr` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:144:33
+  --> $DIR/bad-reg.rs:143:33
    |
 LL |         asm!("/* {} */", in(cr) x);
    |                                 ^
@@ -857,7 +857,7 @@ LL |         asm!("/* {} */", in(cr) x);
    = note: register class `cr` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:151:28
+  --> $DIR/bad-reg.rs:150:28
    |
 LL |         asm!("", in("ctr") x);
    |                            ^
@@ -865,7 +865,7 @@ LL |         asm!("", in("ctr") x);
    = note: register class `ctr` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:154:29
+  --> $DIR/bad-reg.rs:153:29
    |
 LL |         asm!("", out("ctr") x);
    |                             ^
@@ -873,7 +873,7 @@ LL |         asm!("", out("ctr") x);
    = note: register class `ctr` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:157:34
+  --> $DIR/bad-reg.rs:156:34
    |
 LL |         asm!("/* {} */", in(ctr) x);
    |                                  ^
@@ -881,7 +881,7 @@ LL |         asm!("/* {} */", in(ctr) x);
    = note: register class `ctr` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:164:27
+  --> $DIR/bad-reg.rs:163:27
    |
 LL |         asm!("", in("lr") x);
    |                           ^
@@ -889,7 +889,7 @@ LL |         asm!("", in("lr") x);
    = note: register class `lr` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:167:28
+  --> $DIR/bad-reg.rs:166:28
    |
 LL |         asm!("", out("lr") x);
    |                            ^
@@ -897,7 +897,7 @@ LL |         asm!("", out("lr") x);
    = note: register class `lr` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:170:33
+  --> $DIR/bad-reg.rs:169:33
    |
 LL |         asm!("/* {} */", in(lr) x);
    |                                 ^
@@ -905,7 +905,7 @@ LL |         asm!("/* {} */", in(lr) x);
    = note: register class `lr` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:177:28
+  --> $DIR/bad-reg.rs:176:28
    |
 LL |         asm!("", in("xer") x);
    |                            ^
@@ -913,7 +913,7 @@ LL |         asm!("", in("xer") x);
    = note: register class `xer` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:180:29
+  --> $DIR/bad-reg.rs:179:29
    |
 LL |         asm!("", out("xer") x);
    |                             ^
@@ -921,7 +921,7 @@ LL |         asm!("", out("xer") x);
    = note: register class `xer` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:183:34
+  --> $DIR/bad-reg.rs:182:34
    |
 LL |         asm!("/* {} */", in(xer) x);
    |                                  ^
diff --git a/tests/ui/asm/powerpc/bad-reg.powerpc64.stderr b/tests/ui/asm/powerpc/bad-reg.powerpc64.stderr
index d5ca6e331eda..3315a00cc1ab 100644
--- a/tests/ui/asm/powerpc/bad-reg.powerpc64.stderr
+++ b/tests/ui/asm/powerpc/bad-reg.powerpc64.stderr
@@ -1,137 +1,137 @@
 error: invalid register `sp`: the stack pointer cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:37:18
+  --> $DIR/bad-reg.rs:36:18
    |
 LL |         asm!("", out("sp") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `r2`: r2 is a system reserved register and cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:39:18
+  --> $DIR/bad-reg.rs:38:18
    |
 LL |         asm!("", out("r2") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `r29`: r29 is used internally by LLVM and cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:43:18
+  --> $DIR/bad-reg.rs:42:18
    |
 LL |         asm!("", out("r29") _);
    |                  ^^^^^^^^^^^^
 
 error: invalid register `r30`: r30 is used internally by LLVM and cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:45:18
+  --> $DIR/bad-reg.rs:44:18
    |
 LL |         asm!("", out("r30") _);
    |                  ^^^^^^^^^^^^
 
 error: invalid register `fp`: the frame pointer cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:47:18
+  --> $DIR/bad-reg.rs:46:18
    |
 LL |         asm!("", out("fp") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `vrsave`: the vrsave register cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:49:18
+  --> $DIR/bad-reg.rs:48:18
    |
 LL |         asm!("", out("vrsave") _);
    |                  ^^^^^^^^^^^^^^^
 
 error: register class `cr` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:138:18
+  --> $DIR/bad-reg.rs:137:18
    |
 LL |         asm!("", in("cr") x);
    |                  ^^^^^^^^^^
 
 error: register class `cr` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:141:18
+  --> $DIR/bad-reg.rs:140:18
    |
 LL |         asm!("", out("cr") x);
    |                  ^^^^^^^^^^^
 
 error: register class `cr` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:144:26
+  --> $DIR/bad-reg.rs:143:26
    |
 LL |         asm!("/* {} */", in(cr) x);
    |                          ^^^^^^^^
 
 error: register class `cr` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:147:26
+  --> $DIR/bad-reg.rs:146:26
    |
 LL |         asm!("/* {} */", out(cr) _);
    |                          ^^^^^^^^^
 
 error: register class `ctr` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:151:18
+  --> $DIR/bad-reg.rs:150:18
    |
 LL |         asm!("", in("ctr") x);
    |                  ^^^^^^^^^^^
 
 error: register class `ctr` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:154:18
+  --> $DIR/bad-reg.rs:153:18
    |
 LL |         asm!("", out("ctr") x);
    |                  ^^^^^^^^^^^^
 
 error: register class `ctr` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:157:26
+  --> $DIR/bad-reg.rs:156:26
    |
 LL |         asm!("/* {} */", in(ctr) x);
    |                          ^^^^^^^^^
 
 error: register class `ctr` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:160:26
+  --> $DIR/bad-reg.rs:159:26
    |
 LL |         asm!("/* {} */", out(ctr) _);
    |                          ^^^^^^^^^^
 
 error: register class `lr` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:164:18
+  --> $DIR/bad-reg.rs:163:18
    |
 LL |         asm!("", in("lr") x);
    |                  ^^^^^^^^^^
 
 error: register class `lr` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:167:18
+  --> $DIR/bad-reg.rs:166:18
    |
 LL |         asm!("", out("lr") x);
    |                  ^^^^^^^^^^^
 
 error: register class `lr` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:170:26
+  --> $DIR/bad-reg.rs:169:26
    |
 LL |         asm!("/* {} */", in(lr) x);
    |                          ^^^^^^^^
 
 error: register class `lr` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:173:26
+  --> $DIR/bad-reg.rs:172:26
    |
 LL |         asm!("/* {} */", out(lr) _);
    |                          ^^^^^^^^^
 
 error: register class `xer` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:177:18
+  --> $DIR/bad-reg.rs:176:18
    |
 LL |         asm!("", in("xer") x);
    |                  ^^^^^^^^^^^
 
 error: register class `xer` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:180:18
+  --> $DIR/bad-reg.rs:179:18
    |
 LL |         asm!("", out("xer") x);
    |                  ^^^^^^^^^^^^
 
 error: register class `xer` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:183:26
+  --> $DIR/bad-reg.rs:182:26
    |
 LL |         asm!("/* {} */", in(xer) x);
    |                          ^^^^^^^^^
 
 error: register class `xer` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:186:26
+  --> $DIR/bad-reg.rs:185:26
    |
 LL |         asm!("/* {} */", out(xer) _);
    |                          ^^^^^^^^^^
 
 error: register `cr0` conflicts with register `cr`
-  --> $DIR/bad-reg.rs:190:31
+  --> $DIR/bad-reg.rs:189:31
    |
 LL |         asm!("", out("cr") _, out("cr0") _);
    |                  -----------  ^^^^^^^^^^^^ register `cr0`
@@ -139,7 +139,7 @@ LL |         asm!("", out("cr") _, out("cr0") _);
    |                  register `cr`
 
 error: register `cr1` conflicts with register `cr`
-  --> $DIR/bad-reg.rs:192:31
+  --> $DIR/bad-reg.rs:191:31
    |
 LL |         asm!("", out("cr") _, out("cr1") _);
    |                  -----------  ^^^^^^^^^^^^ register `cr1`
@@ -147,7 +147,7 @@ LL |         asm!("", out("cr") _, out("cr1") _);
    |                  register `cr`
 
 error: register `cr2` conflicts with register `cr`
-  --> $DIR/bad-reg.rs:194:31
+  --> $DIR/bad-reg.rs:193:31
    |
 LL |         asm!("", out("cr") _, out("cr2") _);
    |                  -----------  ^^^^^^^^^^^^ register `cr2`
@@ -155,7 +155,7 @@ LL |         asm!("", out("cr") _, out("cr2") _);
    |                  register `cr`
 
 error: register `cr3` conflicts with register `cr`
-  --> $DIR/bad-reg.rs:196:31
+  --> $DIR/bad-reg.rs:195:31
    |
 LL |         asm!("", out("cr") _, out("cr3") _);
    |                  -----------  ^^^^^^^^^^^^ register `cr3`
@@ -163,7 +163,7 @@ LL |         asm!("", out("cr") _, out("cr3") _);
    |                  register `cr`
 
 error: register `cr4` conflicts with register `cr`
-  --> $DIR/bad-reg.rs:198:31
+  --> $DIR/bad-reg.rs:197:31
    |
 LL |         asm!("", out("cr") _, out("cr4") _);
    |                  -----------  ^^^^^^^^^^^^ register `cr4`
@@ -171,7 +171,7 @@ LL |         asm!("", out("cr") _, out("cr4") _);
    |                  register `cr`
 
 error: register `cr5` conflicts with register `cr`
-  --> $DIR/bad-reg.rs:200:31
+  --> $DIR/bad-reg.rs:199:31
    |
 LL |         asm!("", out("cr") _, out("cr5") _);
    |                  -----------  ^^^^^^^^^^^^ register `cr5`
@@ -179,7 +179,7 @@ LL |         asm!("", out("cr") _, out("cr5") _);
    |                  register `cr`
 
 error: register `cr6` conflicts with register `cr`
-  --> $DIR/bad-reg.rs:202:31
+  --> $DIR/bad-reg.rs:201:31
    |
 LL |         asm!("", out("cr") _, out("cr6") _);
    |                  -----------  ^^^^^^^^^^^^ register `cr6`
@@ -187,7 +187,7 @@ LL |         asm!("", out("cr") _, out("cr6") _);
    |                  register `cr`
 
 error: register `cr7` conflicts with register `cr`
-  --> $DIR/bad-reg.rs:204:31
+  --> $DIR/bad-reg.rs:203:31
    |
 LL |         asm!("", out("cr") _, out("cr7") _);
    |                  -----------  ^^^^^^^^^^^^ register `cr7`
@@ -195,7 +195,7 @@ LL |         asm!("", out("cr") _, out("cr7") _);
    |                  register `cr`
 
 error: register `vs0` conflicts with register `f0`
-  --> $DIR/bad-reg.rs:207:31
+  --> $DIR/bad-reg.rs:206:31
    |
 LL |         asm!("", out("f0") _, out("vs0") _);
    |                  -----------  ^^^^^^^^^^^^ register `vs0`
@@ -203,7 +203,7 @@ LL |         asm!("", out("f0") _, out("vs0") _);
    |                  register `f0`
 
 error: register `vs1` conflicts with register `f1`
-  --> $DIR/bad-reg.rs:209:31
+  --> $DIR/bad-reg.rs:208:31
    |
 LL |         asm!("", out("f1") _, out("vs1") _);
    |                  -----------  ^^^^^^^^^^^^ register `vs1`
@@ -211,7 +211,7 @@ LL |         asm!("", out("f1") _, out("vs1") _);
    |                  register `f1`
 
 error: register `vs2` conflicts with register `f2`
-  --> $DIR/bad-reg.rs:211:31
+  --> $DIR/bad-reg.rs:210:31
    |
 LL |         asm!("", out("f2") _, out("vs2") _);
    |                  -----------  ^^^^^^^^^^^^ register `vs2`
@@ -219,7 +219,7 @@ LL |         asm!("", out("f2") _, out("vs2") _);
    |                  register `f2`
 
 error: register `vs3` conflicts with register `f3`
-  --> $DIR/bad-reg.rs:213:31
+  --> $DIR/bad-reg.rs:212:31
    |
 LL |         asm!("", out("f3") _, out("vs3") _);
    |                  -----------  ^^^^^^^^^^^^ register `vs3`
@@ -227,7 +227,7 @@ LL |         asm!("", out("f3") _, out("vs3") _);
    |                  register `f3`
 
 error: register `vs4` conflicts with register `f4`
-  --> $DIR/bad-reg.rs:215:31
+  --> $DIR/bad-reg.rs:214:31
    |
 LL |         asm!("", out("f4") _, out("vs4") _);
    |                  -----------  ^^^^^^^^^^^^ register `vs4`
@@ -235,7 +235,7 @@ LL |         asm!("", out("f4") _, out("vs4") _);
    |                  register `f4`
 
 error: register `vs5` conflicts with register `f5`
-  --> $DIR/bad-reg.rs:217:31
+  --> $DIR/bad-reg.rs:216:31
    |
 LL |         asm!("", out("f5") _, out("vs5") _);
    |                  -----------  ^^^^^^^^^^^^ register `vs5`
@@ -243,7 +243,7 @@ LL |         asm!("", out("f5") _, out("vs5") _);
    |                  register `f5`
 
 error: register `vs6` conflicts with register `f6`
-  --> $DIR/bad-reg.rs:219:31
+  --> $DIR/bad-reg.rs:218:31
    |
 LL |         asm!("", out("f6") _, out("vs6") _);
    |                  -----------  ^^^^^^^^^^^^ register `vs6`
@@ -251,7 +251,7 @@ LL |         asm!("", out("f6") _, out("vs6") _);
    |                  register `f6`
 
 error: register `vs7` conflicts with register `f7`
-  --> $DIR/bad-reg.rs:221:31
+  --> $DIR/bad-reg.rs:220:31
    |
 LL |         asm!("", out("f7") _, out("vs7") _);
    |                  -----------  ^^^^^^^^^^^^ register `vs7`
@@ -259,7 +259,7 @@ LL |         asm!("", out("f7") _, out("vs7") _);
    |                  register `f7`
 
 error: register `vs8` conflicts with register `f8`
-  --> $DIR/bad-reg.rs:223:31
+  --> $DIR/bad-reg.rs:222:31
    |
 LL |         asm!("", out("f8") _, out("vs8") _);
    |                  -----------  ^^^^^^^^^^^^ register `vs8`
@@ -267,7 +267,7 @@ LL |         asm!("", out("f8") _, out("vs8") _);
    |                  register `f8`
 
 error: register `vs9` conflicts with register `f9`
-  --> $DIR/bad-reg.rs:225:31
+  --> $DIR/bad-reg.rs:224:31
    |
 LL |         asm!("", out("f9") _, out("vs9") _);
    |                  -----------  ^^^^^^^^^^^^ register `vs9`
@@ -275,7 +275,7 @@ LL |         asm!("", out("f9") _, out("vs9") _);
    |                  register `f9`
 
 error: register `vs10` conflicts with register `f10`
-  --> $DIR/bad-reg.rs:227:32
+  --> $DIR/bad-reg.rs:226:32
    |
 LL |         asm!("", out("f10") _, out("vs10") _);
    |                  ------------  ^^^^^^^^^^^^^ register `vs10`
@@ -283,7 +283,7 @@ LL |         asm!("", out("f10") _, out("vs10") _);
    |                  register `f10`
 
 error: register `vs11` conflicts with register `f11`
-  --> $DIR/bad-reg.rs:229:32
+  --> $DIR/bad-reg.rs:228:32
    |
 LL |         asm!("", out("f11") _, out("vs11") _);
    |                  ------------  ^^^^^^^^^^^^^ register `vs11`
@@ -291,7 +291,7 @@ LL |         asm!("", out("f11") _, out("vs11") _);
    |                  register `f11`
 
 error: register `vs12` conflicts with register `f12`
-  --> $DIR/bad-reg.rs:231:32
+  --> $DIR/bad-reg.rs:230:32
    |
 LL |         asm!("", out("f12") _, out("vs12") _);
    |                  ------------  ^^^^^^^^^^^^^ register `vs12`
@@ -299,7 +299,7 @@ LL |         asm!("", out("f12") _, out("vs12") _);
    |                  register `f12`
 
 error: register `vs13` conflicts with register `f13`
-  --> $DIR/bad-reg.rs:233:32
+  --> $DIR/bad-reg.rs:232:32
    |
 LL |         asm!("", out("f13") _, out("vs13") _);
    |                  ------------  ^^^^^^^^^^^^^ register `vs13`
@@ -307,7 +307,7 @@ LL |         asm!("", out("f13") _, out("vs13") _);
    |                  register `f13`
 
 error: register `vs14` conflicts with register `f14`
-  --> $DIR/bad-reg.rs:235:32
+  --> $DIR/bad-reg.rs:234:32
    |
 LL |         asm!("", out("f14") _, out("vs14") _);
    |                  ------------  ^^^^^^^^^^^^^ register `vs14`
@@ -315,7 +315,7 @@ LL |         asm!("", out("f14") _, out("vs14") _);
    |                  register `f14`
 
 error: register `vs15` conflicts with register `f15`
-  --> $DIR/bad-reg.rs:237:32
+  --> $DIR/bad-reg.rs:236:32
    |
 LL |         asm!("", out("f15") _, out("vs15") _);
    |                  ------------  ^^^^^^^^^^^^^ register `vs15`
@@ -323,7 +323,7 @@ LL |         asm!("", out("f15") _, out("vs15") _);
    |                  register `f15`
 
 error: register `vs16` conflicts with register `f16`
-  --> $DIR/bad-reg.rs:239:32
+  --> $DIR/bad-reg.rs:238:32
    |
 LL |         asm!("", out("f16") _, out("vs16") _);
    |                  ------------  ^^^^^^^^^^^^^ register `vs16`
@@ -331,7 +331,7 @@ LL |         asm!("", out("f16") _, out("vs16") _);
    |                  register `f16`
 
 error: register `vs17` conflicts with register `f17`
-  --> $DIR/bad-reg.rs:241:32
+  --> $DIR/bad-reg.rs:240:32
    |
 LL |         asm!("", out("f17") _, out("vs17") _);
    |                  ------------  ^^^^^^^^^^^^^ register `vs17`
@@ -339,7 +339,7 @@ LL |         asm!("", out("f17") _, out("vs17") _);
    |                  register `f17`
 
 error: register `vs18` conflicts with register `f18`
-  --> $DIR/bad-reg.rs:243:32
+  --> $DIR/bad-reg.rs:242:32
    |
 LL |         asm!("", out("f18") _, out("vs18") _);
    |                  ------------  ^^^^^^^^^^^^^ register `vs18`
@@ -347,7 +347,7 @@ LL |         asm!("", out("f18") _, out("vs18") _);
    |                  register `f18`
 
 error: register `vs19` conflicts with register `f19`
-  --> $DIR/bad-reg.rs:245:32
+  --> $DIR/bad-reg.rs:244:32
    |
 LL |         asm!("", out("f19") _, out("vs19") _);
    |                  ------------  ^^^^^^^^^^^^^ register `vs19`
@@ -355,7 +355,7 @@ LL |         asm!("", out("f19") _, out("vs19") _);
    |                  register `f19`
 
 error: register `vs20` conflicts with register `f20`
-  --> $DIR/bad-reg.rs:247:32
+  --> $DIR/bad-reg.rs:246:32
    |
 LL |         asm!("", out("f20") _, out("vs20") _);
    |                  ------------  ^^^^^^^^^^^^^ register `vs20`
@@ -363,7 +363,7 @@ LL |         asm!("", out("f20") _, out("vs20") _);
    |                  register `f20`
 
 error: register `vs21` conflicts with register `f21`
-  --> $DIR/bad-reg.rs:249:32
+  --> $DIR/bad-reg.rs:248:32
    |
 LL |         asm!("", out("f21") _, out("vs21") _);
    |                  ------------  ^^^^^^^^^^^^^ register `vs21`
@@ -371,7 +371,7 @@ LL |         asm!("", out("f21") _, out("vs21") _);
    |                  register `f21`
 
 error: register `vs22` conflicts with register `f22`
-  --> $DIR/bad-reg.rs:251:32
+  --> $DIR/bad-reg.rs:250:32
    |
 LL |         asm!("", out("f22") _, out("vs22") _);
    |                  ------------  ^^^^^^^^^^^^^ register `vs22`
@@ -379,7 +379,7 @@ LL |         asm!("", out("f22") _, out("vs22") _);
    |                  register `f22`
 
 error: register `vs23` conflicts with register `f23`
-  --> $DIR/bad-reg.rs:253:32
+  --> $DIR/bad-reg.rs:252:32
    |
 LL |         asm!("", out("f23") _, out("vs23") _);
    |                  ------------  ^^^^^^^^^^^^^ register `vs23`
@@ -387,7 +387,7 @@ LL |         asm!("", out("f23") _, out("vs23") _);
    |                  register `f23`
 
 error: register `vs24` conflicts with register `f24`
-  --> $DIR/bad-reg.rs:255:32
+  --> $DIR/bad-reg.rs:254:32
    |
 LL |         asm!("", out("f24") _, out("vs24") _);
    |                  ------------  ^^^^^^^^^^^^^ register `vs24`
@@ -395,7 +395,7 @@ LL |         asm!("", out("f24") _, out("vs24") _);
    |                  register `f24`
 
 error: register `vs25` conflicts with register `f25`
-  --> $DIR/bad-reg.rs:257:32
+  --> $DIR/bad-reg.rs:256:32
    |
 LL |         asm!("", out("f25") _, out("vs25") _);
    |                  ------------  ^^^^^^^^^^^^^ register `vs25`
@@ -403,7 +403,7 @@ LL |         asm!("", out("f25") _, out("vs25") _);
    |                  register `f25`
 
 error: register `vs26` conflicts with register `f26`
-  --> $DIR/bad-reg.rs:259:32
+  --> $DIR/bad-reg.rs:258:32
    |
 LL |         asm!("", out("f26") _, out("vs26") _);
    |                  ------------  ^^^^^^^^^^^^^ register `vs26`
@@ -411,7 +411,7 @@ LL |         asm!("", out("f26") _, out("vs26") _);
    |                  register `f26`
 
 error: register `vs27` conflicts with register `f27`
-  --> $DIR/bad-reg.rs:261:32
+  --> $DIR/bad-reg.rs:260:32
    |
 LL |         asm!("", out("f27") _, out("vs27") _);
    |                  ------------  ^^^^^^^^^^^^^ register `vs27`
@@ -419,7 +419,7 @@ LL |         asm!("", out("f27") _, out("vs27") _);
    |                  register `f27`
 
 error: register `vs28` conflicts with register `f28`
-  --> $DIR/bad-reg.rs:263:32
+  --> $DIR/bad-reg.rs:262:32
    |
 LL |         asm!("", out("f28") _, out("vs28") _);
    |                  ------------  ^^^^^^^^^^^^^ register `vs28`
@@ -427,7 +427,7 @@ LL |         asm!("", out("f28") _, out("vs28") _);
    |                  register `f28`
 
 error: register `vs29` conflicts with register `f29`
-  --> $DIR/bad-reg.rs:265:32
+  --> $DIR/bad-reg.rs:264:32
    |
 LL |         asm!("", out("f29") _, out("vs29") _);
    |                  ------------  ^^^^^^^^^^^^^ register `vs29`
@@ -435,7 +435,7 @@ LL |         asm!("", out("f29") _, out("vs29") _);
    |                  register `f29`
 
 error: register `vs30` conflicts with register `f30`
-  --> $DIR/bad-reg.rs:267:32
+  --> $DIR/bad-reg.rs:266:32
    |
 LL |         asm!("", out("f30") _, out("vs30") _);
    |                  ------------  ^^^^^^^^^^^^^ register `vs30`
@@ -443,7 +443,7 @@ LL |         asm!("", out("f30") _, out("vs30") _);
    |                  register `f30`
 
 error: register `vs31` conflicts with register `f31`
-  --> $DIR/bad-reg.rs:269:32
+  --> $DIR/bad-reg.rs:268:32
    |
 LL |         asm!("", out("f31") _, out("vs31") _);
    |                  ------------  ^^^^^^^^^^^^^ register `vs31`
@@ -451,7 +451,7 @@ LL |         asm!("", out("f31") _, out("vs31") _);
    |                  register `f31`
 
 error: register `v0` conflicts with register `vs32`
-  --> $DIR/bad-reg.rs:271:33
+  --> $DIR/bad-reg.rs:270:33
    |
 LL |         asm!("", out("vs32") _, out("v0") _);
    |                  -------------  ^^^^^^^^^^^ register `v0`
@@ -459,7 +459,7 @@ LL |         asm!("", out("vs32") _, out("v0") _);
    |                  register `vs32`
 
 error: register `v1` conflicts with register `vs33`
-  --> $DIR/bad-reg.rs:273:33
+  --> $DIR/bad-reg.rs:272:33
    |
 LL |         asm!("", out("vs33") _, out("v1") _);
    |                  -------------  ^^^^^^^^^^^ register `v1`
@@ -467,7 +467,7 @@ LL |         asm!("", out("vs33") _, out("v1") _);
    |                  register `vs33`
 
 error: register `v2` conflicts with register `vs34`
-  --> $DIR/bad-reg.rs:275:33
+  --> $DIR/bad-reg.rs:274:33
    |
 LL |         asm!("", out("vs34") _, out("v2") _);
    |                  -------------  ^^^^^^^^^^^ register `v2`
@@ -475,7 +475,7 @@ LL |         asm!("", out("vs34") _, out("v2") _);
    |                  register `vs34`
 
 error: register `v3` conflicts with register `vs35`
-  --> $DIR/bad-reg.rs:277:33
+  --> $DIR/bad-reg.rs:276:33
    |
 LL |         asm!("", out("vs35") _, out("v3") _);
    |                  -------------  ^^^^^^^^^^^ register `v3`
@@ -483,7 +483,7 @@ LL |         asm!("", out("vs35") _, out("v3") _);
    |                  register `vs35`
 
 error: register `v4` conflicts with register `vs36`
-  --> $DIR/bad-reg.rs:279:33
+  --> $DIR/bad-reg.rs:278:33
    |
 LL |         asm!("", out("vs36") _, out("v4") _);
    |                  -------------  ^^^^^^^^^^^ register `v4`
@@ -491,7 +491,7 @@ LL |         asm!("", out("vs36") _, out("v4") _);
    |                  register `vs36`
 
 error: register `v5` conflicts with register `vs37`
-  --> $DIR/bad-reg.rs:281:33
+  --> $DIR/bad-reg.rs:280:33
    |
 LL |         asm!("", out("vs37") _, out("v5") _);
    |                  -------------  ^^^^^^^^^^^ register `v5`
@@ -499,7 +499,7 @@ LL |         asm!("", out("vs37") _, out("v5") _);
    |                  register `vs37`
 
 error: register `v6` conflicts with register `vs38`
-  --> $DIR/bad-reg.rs:283:33
+  --> $DIR/bad-reg.rs:282:33
    |
 LL |         asm!("", out("vs38") _, out("v6") _);
    |                  -------------  ^^^^^^^^^^^ register `v6`
@@ -507,7 +507,7 @@ LL |         asm!("", out("vs38") _, out("v6") _);
    |                  register `vs38`
 
 error: register `v7` conflicts with register `vs39`
-  --> $DIR/bad-reg.rs:285:33
+  --> $DIR/bad-reg.rs:284:33
    |
 LL |         asm!("", out("vs39") _, out("v7") _);
    |                  -------------  ^^^^^^^^^^^ register `v7`
@@ -515,7 +515,7 @@ LL |         asm!("", out("vs39") _, out("v7") _);
    |                  register `vs39`
 
 error: register `v8` conflicts with register `vs40`
-  --> $DIR/bad-reg.rs:287:33
+  --> $DIR/bad-reg.rs:286:33
    |
 LL |         asm!("", out("vs40") _, out("v8") _);
    |                  -------------  ^^^^^^^^^^^ register `v8`
@@ -523,7 +523,7 @@ LL |         asm!("", out("vs40") _, out("v8") _);
    |                  register `vs40`
 
 error: register `v9` conflicts with register `vs41`
-  --> $DIR/bad-reg.rs:289:33
+  --> $DIR/bad-reg.rs:288:33
    |
 LL |         asm!("", out("vs41") _, out("v9") _);
    |                  -------------  ^^^^^^^^^^^ register `v9`
@@ -531,7 +531,7 @@ LL |         asm!("", out("vs41") _, out("v9") _);
    |                  register `vs41`
 
 error: register `v10` conflicts with register `vs42`
-  --> $DIR/bad-reg.rs:291:33
+  --> $DIR/bad-reg.rs:290:33
    |
 LL |         asm!("", out("vs42") _, out("v10") _);
    |                  -------------  ^^^^^^^^^^^^ register `v10`
@@ -539,7 +539,7 @@ LL |         asm!("", out("vs42") _, out("v10") _);
    |                  register `vs42`
 
 error: register `v11` conflicts with register `vs43`
-  --> $DIR/bad-reg.rs:293:33
+  --> $DIR/bad-reg.rs:292:33
    |
 LL |         asm!("", out("vs43") _, out("v11") _);
    |                  -------------  ^^^^^^^^^^^^ register `v11`
@@ -547,7 +547,7 @@ LL |         asm!("", out("vs43") _, out("v11") _);
    |                  register `vs43`
 
 error: register `v12` conflicts with register `vs44`
-  --> $DIR/bad-reg.rs:295:33
+  --> $DIR/bad-reg.rs:294:33
    |
 LL |         asm!("", out("vs44") _, out("v12") _);
    |                  -------------  ^^^^^^^^^^^^ register `v12`
@@ -555,7 +555,7 @@ LL |         asm!("", out("vs44") _, out("v12") _);
    |                  register `vs44`
 
 error: register `v13` conflicts with register `vs45`
-  --> $DIR/bad-reg.rs:297:33
+  --> $DIR/bad-reg.rs:296:33
    |
 LL |         asm!("", out("vs45") _, out("v13") _);
    |                  -------------  ^^^^^^^^^^^^ register `v13`
@@ -563,7 +563,7 @@ LL |         asm!("", out("vs45") _, out("v13") _);
    |                  register `vs45`
 
 error: register `v14` conflicts with register `vs46`
-  --> $DIR/bad-reg.rs:299:33
+  --> $DIR/bad-reg.rs:298:33
    |
 LL |         asm!("", out("vs46") _, out("v14") _);
    |                  -------------  ^^^^^^^^^^^^ register `v14`
@@ -571,7 +571,7 @@ LL |         asm!("", out("vs46") _, out("v14") _);
    |                  register `vs46`
 
 error: register `v15` conflicts with register `vs47`
-  --> $DIR/bad-reg.rs:301:33
+  --> $DIR/bad-reg.rs:300:33
    |
 LL |         asm!("", out("vs47") _, out("v15") _);
    |                  -------------  ^^^^^^^^^^^^ register `v15`
@@ -579,7 +579,7 @@ LL |         asm!("", out("vs47") _, out("v15") _);
    |                  register `vs47`
 
 error: register `v16` conflicts with register `vs48`
-  --> $DIR/bad-reg.rs:303:33
+  --> $DIR/bad-reg.rs:302:33
    |
 LL |         asm!("", out("vs48") _, out("v16") _);
    |                  -------------  ^^^^^^^^^^^^ register `v16`
@@ -587,7 +587,7 @@ LL |         asm!("", out("vs48") _, out("v16") _);
    |                  register `vs48`
 
 error: register `v17` conflicts with register `vs49`
-  --> $DIR/bad-reg.rs:305:33
+  --> $DIR/bad-reg.rs:304:33
    |
 LL |         asm!("", out("vs49") _, out("v17") _);
    |                  -------------  ^^^^^^^^^^^^ register `v17`
@@ -595,7 +595,7 @@ LL |         asm!("", out("vs49") _, out("v17") _);
    |                  register `vs49`
 
 error: register `v18` conflicts with register `vs50`
-  --> $DIR/bad-reg.rs:307:33
+  --> $DIR/bad-reg.rs:306:33
    |
 LL |         asm!("", out("vs50") _, out("v18") _);
    |                  -------------  ^^^^^^^^^^^^ register `v18`
@@ -603,7 +603,7 @@ LL |         asm!("", out("vs50") _, out("v18") _);
    |                  register `vs50`
 
 error: register `v19` conflicts with register `vs51`
-  --> $DIR/bad-reg.rs:309:33
+  --> $DIR/bad-reg.rs:308:33
    |
 LL |         asm!("", out("vs51") _, out("v19") _);
    |                  -------------  ^^^^^^^^^^^^ register `v19`
@@ -611,7 +611,7 @@ LL |         asm!("", out("vs51") _, out("v19") _);
    |                  register `vs51`
 
 error: register `v20` conflicts with register `vs52`
-  --> $DIR/bad-reg.rs:311:33
+  --> $DIR/bad-reg.rs:310:33
    |
 LL |         asm!("", out("vs52") _, out("v20") _);
    |                  -------------  ^^^^^^^^^^^^ register `v20`
@@ -619,7 +619,7 @@ LL |         asm!("", out("vs52") _, out("v20") _);
    |                  register `vs52`
 
 error: register `v21` conflicts with register `vs53`
-  --> $DIR/bad-reg.rs:313:33
+  --> $DIR/bad-reg.rs:312:33
    |
 LL |         asm!("", out("vs53") _, out("v21") _);
    |                  -------------  ^^^^^^^^^^^^ register `v21`
@@ -627,7 +627,7 @@ LL |         asm!("", out("vs53") _, out("v21") _);
    |                  register `vs53`
 
 error: register `v22` conflicts with register `vs54`
-  --> $DIR/bad-reg.rs:315:33
+  --> $DIR/bad-reg.rs:314:33
    |
 LL |         asm!("", out("vs54") _, out("v22") _);
    |                  -------------  ^^^^^^^^^^^^ register `v22`
@@ -635,7 +635,7 @@ LL |         asm!("", out("vs54") _, out("v22") _);
    |                  register `vs54`
 
 error: register `v23` conflicts with register `vs55`
-  --> $DIR/bad-reg.rs:317:33
+  --> $DIR/bad-reg.rs:316:33
    |
 LL |         asm!("", out("vs55") _, out("v23") _);
    |                  -------------  ^^^^^^^^^^^^ register `v23`
@@ -643,7 +643,7 @@ LL |         asm!("", out("vs55") _, out("v23") _);
    |                  register `vs55`
 
 error: register `v24` conflicts with register `vs56`
-  --> $DIR/bad-reg.rs:319:33
+  --> $DIR/bad-reg.rs:318:33
    |
 LL |         asm!("", out("vs56") _, out("v24") _);
    |                  -------------  ^^^^^^^^^^^^ register `v24`
@@ -651,7 +651,7 @@ LL |         asm!("", out("vs56") _, out("v24") _);
    |                  register `vs56`
 
 error: register `v25` conflicts with register `vs57`
-  --> $DIR/bad-reg.rs:321:33
+  --> $DIR/bad-reg.rs:320:33
    |
 LL |         asm!("", out("vs57") _, out("v25") _);
    |                  -------------  ^^^^^^^^^^^^ register `v25`
@@ -659,7 +659,7 @@ LL |         asm!("", out("vs57") _, out("v25") _);
    |                  register `vs57`
 
 error: register `v26` conflicts with register `vs58`
-  --> $DIR/bad-reg.rs:323:33
+  --> $DIR/bad-reg.rs:322:33
    |
 LL |         asm!("", out("vs58") _, out("v26") _);
    |                  -------------  ^^^^^^^^^^^^ register `v26`
@@ -667,7 +667,7 @@ LL |         asm!("", out("vs58") _, out("v26") _);
    |                  register `vs58`
 
 error: register `v27` conflicts with register `vs59`
-  --> $DIR/bad-reg.rs:325:33
+  --> $DIR/bad-reg.rs:324:33
    |
 LL |         asm!("", out("vs59") _, out("v27") _);
    |                  -------------  ^^^^^^^^^^^^ register `v27`
@@ -675,7 +675,7 @@ LL |         asm!("", out("vs59") _, out("v27") _);
    |                  register `vs59`
 
 error: register `v28` conflicts with register `vs60`
-  --> $DIR/bad-reg.rs:327:33
+  --> $DIR/bad-reg.rs:326:33
    |
 LL |         asm!("", out("vs60") _, out("v28") _);
    |                  -------------  ^^^^^^^^^^^^ register `v28`
@@ -683,7 +683,7 @@ LL |         asm!("", out("vs60") _, out("v28") _);
    |                  register `vs60`
 
 error: register `v29` conflicts with register `vs61`
-  --> $DIR/bad-reg.rs:329:33
+  --> $DIR/bad-reg.rs:328:33
    |
 LL |         asm!("", out("vs61") _, out("v29") _);
    |                  -------------  ^^^^^^^^^^^^ register `v29`
@@ -691,7 +691,7 @@ LL |         asm!("", out("vs61") _, out("v29") _);
    |                  register `vs61`
 
 error: register `v30` conflicts with register `vs62`
-  --> $DIR/bad-reg.rs:331:33
+  --> $DIR/bad-reg.rs:330:33
    |
 LL |         asm!("", out("vs62") _, out("v30") _);
    |                  -------------  ^^^^^^^^^^^^ register `v30`
@@ -699,7 +699,7 @@ LL |         asm!("", out("vs62") _, out("v30") _);
    |                  register `vs62`
 
 error: register `v31` conflicts with register `vs63`
-  --> $DIR/bad-reg.rs:333:33
+  --> $DIR/bad-reg.rs:332:33
    |
 LL |         asm!("", out("vs63") _, out("v31") _);
    |                  -------------  ^^^^^^^^^^^^ register `v31`
@@ -707,13 +707,13 @@ LL |         asm!("", out("vs63") _, out("v31") _);
    |                  register `vs63`
 
 error: cannot use register `r13`: r13 is a reserved register on this target
-  --> $DIR/bad-reg.rs:41:18
+  --> $DIR/bad-reg.rs:40:18
    |
 LL |         asm!("", out("r13") _);
    |                  ^^^^^^^^^^^^
 
 error: `vsx` target feature is not enabled
-  --> $DIR/bad-reg.rs:58:27
+  --> $DIR/bad-reg.rs:57:27
    |
 LL |         asm!("", in("v0") v64x2); // requires vsx
    |                           ^^^^^
@@ -721,7 +721,7 @@ LL |         asm!("", in("v0") v64x2); // requires vsx
    = note: this is required to use type `i64x2` with register class `vreg`
 
 error: `vsx` target feature is not enabled
-  --> $DIR/bad-reg.rs:61:28
+  --> $DIR/bad-reg.rs:60:28
    |
 LL |         asm!("", out("v0") v64x2); // requires vsx
    |                            ^^^^^
@@ -729,7 +729,7 @@ LL |         asm!("", out("v0") v64x2); // requires vsx
    = note: this is required to use type `i64x2` with register class `vreg`
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:64:27
+  --> $DIR/bad-reg.rs:63:27
    |
 LL |         asm!("", in("v0") x); // FIXME: should be ok if vsx is available
    |                           ^
@@ -737,7 +737,7 @@ LL |         asm!("", in("v0") x); // FIXME: should be ok if vsx is available
    = note: register class `vreg` supports these types: i8x16, i16x8, i32x4, f32x4, f32, f64, i64x2, f64x2
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:67:28
+  --> $DIR/bad-reg.rs:66:28
    |
 LL |         asm!("", out("v0") x); // FIXME: should be ok if vsx is available
    |                            ^
@@ -745,7 +745,7 @@ LL |         asm!("", out("v0") x); // FIXME: should be ok if vsx is available
    = note: register class `vreg` supports these types: i8x16, i16x8, i32x4, f32x4, f32, f64, i64x2, f64x2
 
 error: `vsx` target feature is not enabled
-  --> $DIR/bad-reg.rs:72:35
+  --> $DIR/bad-reg.rs:71:35
    |
 LL |         asm!("/* {} */", in(vreg) v64x2); // requires vsx
    |                                   ^^^^^
@@ -753,7 +753,7 @@ LL |         asm!("/* {} */", in(vreg) v64x2); // requires vsx
    = note: this is required to use type `i64x2` with register class `vreg`
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:75:35
+  --> $DIR/bad-reg.rs:74:35
    |
 LL |         asm!("/* {} */", in(vreg) x); // FIXME: should be ok if vsx is available
    |                                   ^
@@ -761,67 +761,67 @@ LL |         asm!("/* {} */", in(vreg) x); // FIXME: should be ok if vsx is avai
    = note: register class `vreg` supports these types: i8x16, i16x8, i32x4, f32x4, f32, f64, i64x2, f64x2
 
 error: register class `vsreg` requires the `vsx` target feature
-  --> $DIR/bad-reg.rs:97:18
+  --> $DIR/bad-reg.rs:96:18
    |
 LL |         asm!("", in("vs0") v32x4); // requires vsx
    |                  ^^^^^^^^^^^^^^^
 
 error: register class `vsreg` requires the `vsx` target feature
-  --> $DIR/bad-reg.rs:99:18
+  --> $DIR/bad-reg.rs:98:18
    |
 LL |         asm!("", out("vs0") v32x4); // requires vsx
    |                  ^^^^^^^^^^^^^^^^
 
 error: register class `vsreg` requires the `vsx` target feature
-  --> $DIR/bad-reg.rs:101:18
+  --> $DIR/bad-reg.rs:100:18
    |
 LL |         asm!("", in("vs0") v64x2); // requires vsx
    |                  ^^^^^^^^^^^^^^^
 
 error: register class `vsreg` requires the `vsx` target feature
-  --> $DIR/bad-reg.rs:103:18
+  --> $DIR/bad-reg.rs:102:18
    |
 LL |         asm!("", out("vs0") v64x2); // requires vsx
    |                  ^^^^^^^^^^^^^^^^
 
 error: register class `vsreg` requires the `vsx` target feature
-  --> $DIR/bad-reg.rs:105:18
+  --> $DIR/bad-reg.rs:104:18
    |
 LL |         asm!("", in("vs0") x); // FIXME: should be ok if vsx is available
    |                  ^^^^^^^^^^^
 
 error: register class `vsreg` requires the `vsx` target feature
-  --> $DIR/bad-reg.rs:108:18
+  --> $DIR/bad-reg.rs:107:18
    |
 LL |         asm!("", out("vs0") x); // FIXME: should be ok if vsx is available
    |                  ^^^^^^^^^^^^
 
 error: register class `vsreg` requires the `vsx` target feature
-  --> $DIR/bad-reg.rs:111:26
+  --> $DIR/bad-reg.rs:110:26
    |
 LL |         asm!("/* {} */", in(vsreg) v32x4); // requires vsx
    |                          ^^^^^^^^^^^^^^^
 
 error: register class `vsreg` requires the `vsx` target feature
-  --> $DIR/bad-reg.rs:113:26
+  --> $DIR/bad-reg.rs:112:26
    |
 LL |         asm!("/* {} */", in(vsreg) v64x2); // requires vsx
    |                          ^^^^^^^^^^^^^^^
 
 error: register class `vsreg` requires the `vsx` target feature
-  --> $DIR/bad-reg.rs:115:26
+  --> $DIR/bad-reg.rs:114:26
    |
 LL |         asm!("/* {} */", in(vsreg) x); // FIXME: should be ok if vsx is available
    |                          ^^^^^^^^^^^
 
 error: register class `vsreg` requires the `vsx` target feature
-  --> $DIR/bad-reg.rs:118:26
+  --> $DIR/bad-reg.rs:117:26
    |
 LL |         asm!("/* {} */", out(vsreg) _); // requires vsx
    |                          ^^^^^^^^^^^^
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:138:27
+  --> $DIR/bad-reg.rs:137:27
    |
 LL |         asm!("", in("cr") x);
    |                           ^
@@ -829,7 +829,7 @@ LL |         asm!("", in("cr") x);
    = note: register class `cr` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:141:28
+  --> $DIR/bad-reg.rs:140:28
    |
 LL |         asm!("", out("cr") x);
    |                            ^
@@ -837,7 +837,7 @@ LL |         asm!("", out("cr") x);
    = note: register class `cr` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:144:33
+  --> $DIR/bad-reg.rs:143:33
    |
 LL |         asm!("/* {} */", in(cr) x);
    |                                 ^
@@ -845,7 +845,7 @@ LL |         asm!("/* {} */", in(cr) x);
    = note: register class `cr` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:151:28
+  --> $DIR/bad-reg.rs:150:28
    |
 LL |         asm!("", in("ctr") x);
    |                            ^
@@ -853,7 +853,7 @@ LL |         asm!("", in("ctr") x);
    = note: register class `ctr` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:154:29
+  --> $DIR/bad-reg.rs:153:29
    |
 LL |         asm!("", out("ctr") x);
    |                             ^
@@ -861,7 +861,7 @@ LL |         asm!("", out("ctr") x);
    = note: register class `ctr` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:157:34
+  --> $DIR/bad-reg.rs:156:34
    |
 LL |         asm!("/* {} */", in(ctr) x);
    |                                  ^
@@ -869,7 +869,7 @@ LL |         asm!("/* {} */", in(ctr) x);
    = note: register class `ctr` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:164:27
+  --> $DIR/bad-reg.rs:163:27
    |
 LL |         asm!("", in("lr") x);
    |                           ^
@@ -877,7 +877,7 @@ LL |         asm!("", in("lr") x);
    = note: register class `lr` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:167:28
+  --> $DIR/bad-reg.rs:166:28
    |
 LL |         asm!("", out("lr") x);
    |                            ^
@@ -885,7 +885,7 @@ LL |         asm!("", out("lr") x);
    = note: register class `lr` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:170:33
+  --> $DIR/bad-reg.rs:169:33
    |
 LL |         asm!("/* {} */", in(lr) x);
    |                                 ^
@@ -893,7 +893,7 @@ LL |         asm!("/* {} */", in(lr) x);
    = note: register class `lr` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:177:28
+  --> $DIR/bad-reg.rs:176:28
    |
 LL |         asm!("", in("xer") x);
    |                            ^
@@ -901,7 +901,7 @@ LL |         asm!("", in("xer") x);
    = note: register class `xer` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:180:29
+  --> $DIR/bad-reg.rs:179:29
    |
 LL |         asm!("", out("xer") x);
    |                             ^
@@ -909,7 +909,7 @@ LL |         asm!("", out("xer") x);
    = note: register class `xer` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:183:34
+  --> $DIR/bad-reg.rs:182:34
    |
 LL |         asm!("/* {} */", in(xer) x);
    |                                  ^
diff --git a/tests/ui/asm/powerpc/bad-reg.powerpc64le.stderr b/tests/ui/asm/powerpc/bad-reg.powerpc64le.stderr
index fb3ed07f5c65..67ad0a5d2c45 100644
--- a/tests/ui/asm/powerpc/bad-reg.powerpc64le.stderr
+++ b/tests/ui/asm/powerpc/bad-reg.powerpc64le.stderr
@@ -1,137 +1,137 @@
 error: invalid register `sp`: the stack pointer cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:37:18
+  --> $DIR/bad-reg.rs:36:18
    |
 LL |         asm!("", out("sp") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `r2`: r2 is a system reserved register and cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:39:18
+  --> $DIR/bad-reg.rs:38:18
    |
 LL |         asm!("", out("r2") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `r29`: r29 is used internally by LLVM and cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:43:18
+  --> $DIR/bad-reg.rs:42:18
    |
 LL |         asm!("", out("r29") _);
    |                  ^^^^^^^^^^^^
 
 error: invalid register `r30`: r30 is used internally by LLVM and cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:45:18
+  --> $DIR/bad-reg.rs:44:18
    |
 LL |         asm!("", out("r30") _);
    |                  ^^^^^^^^^^^^
 
 error: invalid register `fp`: the frame pointer cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:47:18
+  --> $DIR/bad-reg.rs:46:18
    |
 LL |         asm!("", out("fp") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `vrsave`: the vrsave register cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:49:18
+  --> $DIR/bad-reg.rs:48:18
    |
 LL |         asm!("", out("vrsave") _);
    |                  ^^^^^^^^^^^^^^^
 
 error: register class `cr` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:138:18
+  --> $DIR/bad-reg.rs:137:18
    |
 LL |         asm!("", in("cr") x);
    |                  ^^^^^^^^^^
 
 error: register class `cr` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:141:18
+  --> $DIR/bad-reg.rs:140:18
    |
 LL |         asm!("", out("cr") x);
    |                  ^^^^^^^^^^^
 
 error: register class `cr` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:144:26
+  --> $DIR/bad-reg.rs:143:26
    |
 LL |         asm!("/* {} */", in(cr) x);
    |                          ^^^^^^^^
 
 error: register class `cr` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:147:26
+  --> $DIR/bad-reg.rs:146:26
    |
 LL |         asm!("/* {} */", out(cr) _);
    |                          ^^^^^^^^^
 
 error: register class `ctr` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:151:18
+  --> $DIR/bad-reg.rs:150:18
    |
 LL |         asm!("", in("ctr") x);
    |                  ^^^^^^^^^^^
 
 error: register class `ctr` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:154:18
+  --> $DIR/bad-reg.rs:153:18
    |
 LL |         asm!("", out("ctr") x);
    |                  ^^^^^^^^^^^^
 
 error: register class `ctr` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:157:26
+  --> $DIR/bad-reg.rs:156:26
    |
 LL |         asm!("/* {} */", in(ctr) x);
    |                          ^^^^^^^^^
 
 error: register class `ctr` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:160:26
+  --> $DIR/bad-reg.rs:159:26
    |
 LL |         asm!("/* {} */", out(ctr) _);
    |                          ^^^^^^^^^^
 
 error: register class `lr` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:164:18
+  --> $DIR/bad-reg.rs:163:18
    |
 LL |         asm!("", in("lr") x);
    |                  ^^^^^^^^^^
 
 error: register class `lr` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:167:18
+  --> $DIR/bad-reg.rs:166:18
    |
 LL |         asm!("", out("lr") x);
    |                  ^^^^^^^^^^^
 
 error: register class `lr` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:170:26
+  --> $DIR/bad-reg.rs:169:26
    |
 LL |         asm!("/* {} */", in(lr) x);
    |                          ^^^^^^^^
 
 error: register class `lr` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:173:26
+  --> $DIR/bad-reg.rs:172:26
    |
 LL |         asm!("/* {} */", out(lr) _);
    |                          ^^^^^^^^^
 
 error: register class `xer` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:177:18
+  --> $DIR/bad-reg.rs:176:18
    |
 LL |         asm!("", in("xer") x);
    |                  ^^^^^^^^^^^
 
 error: register class `xer` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:180:18
+  --> $DIR/bad-reg.rs:179:18
    |
 LL |         asm!("", out("xer") x);
    |                  ^^^^^^^^^^^^
 
 error: register class `xer` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:183:26
+  --> $DIR/bad-reg.rs:182:26
    |
 LL |         asm!("/* {} */", in(xer) x);
    |                          ^^^^^^^^^
 
 error: register class `xer` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:186:26
+  --> $DIR/bad-reg.rs:185:26
    |
 LL |         asm!("/* {} */", out(xer) _);
    |                          ^^^^^^^^^^
 
 error: register `cr0` conflicts with register `cr`
-  --> $DIR/bad-reg.rs:190:31
+  --> $DIR/bad-reg.rs:189:31
    |
 LL |         asm!("", out("cr") _, out("cr0") _);
    |                  -----------  ^^^^^^^^^^^^ register `cr0`
@@ -139,7 +139,7 @@ LL |         asm!("", out("cr") _, out("cr0") _);
    |                  register `cr`
 
 error: register `cr1` conflicts with register `cr`
-  --> $DIR/bad-reg.rs:192:31
+  --> $DIR/bad-reg.rs:191:31
    |
 LL |         asm!("", out("cr") _, out("cr1") _);
    |                  -----------  ^^^^^^^^^^^^ register `cr1`
@@ -147,7 +147,7 @@ LL |         asm!("", out("cr") _, out("cr1") _);
    |                  register `cr`
 
 error: register `cr2` conflicts with register `cr`
-  --> $DIR/bad-reg.rs:194:31
+  --> $DIR/bad-reg.rs:193:31
    |
 LL |         asm!("", out("cr") _, out("cr2") _);
    |                  -----------  ^^^^^^^^^^^^ register `cr2`
@@ -155,7 +155,7 @@ LL |         asm!("", out("cr") _, out("cr2") _);
    |                  register `cr`
 
 error: register `cr3` conflicts with register `cr`
-  --> $DIR/bad-reg.rs:196:31
+  --> $DIR/bad-reg.rs:195:31
    |
 LL |         asm!("", out("cr") _, out("cr3") _);
    |                  -----------  ^^^^^^^^^^^^ register `cr3`
@@ -163,7 +163,7 @@ LL |         asm!("", out("cr") _, out("cr3") _);
    |                  register `cr`
 
 error: register `cr4` conflicts with register `cr`
-  --> $DIR/bad-reg.rs:198:31
+  --> $DIR/bad-reg.rs:197:31
    |
 LL |         asm!("", out("cr") _, out("cr4") _);
    |                  -----------  ^^^^^^^^^^^^ register `cr4`
@@ -171,7 +171,7 @@ LL |         asm!("", out("cr") _, out("cr4") _);
    |                  register `cr`
 
 error: register `cr5` conflicts with register `cr`
-  --> $DIR/bad-reg.rs:200:31
+  --> $DIR/bad-reg.rs:199:31
    |
 LL |         asm!("", out("cr") _, out("cr5") _);
    |                  -----------  ^^^^^^^^^^^^ register `cr5`
@@ -179,7 +179,7 @@ LL |         asm!("", out("cr") _, out("cr5") _);
    |                  register `cr`
 
 error: register `cr6` conflicts with register `cr`
-  --> $DIR/bad-reg.rs:202:31
+  --> $DIR/bad-reg.rs:201:31
    |
 LL |         asm!("", out("cr") _, out("cr6") _);
    |                  -----------  ^^^^^^^^^^^^ register `cr6`
@@ -187,7 +187,7 @@ LL |         asm!("", out("cr") _, out("cr6") _);
    |                  register `cr`
 
 error: register `cr7` conflicts with register `cr`
-  --> $DIR/bad-reg.rs:204:31
+  --> $DIR/bad-reg.rs:203:31
    |
 LL |         asm!("", out("cr") _, out("cr7") _);
    |                  -----------  ^^^^^^^^^^^^ register `cr7`
@@ -195,7 +195,7 @@ LL |         asm!("", out("cr") _, out("cr7") _);
    |                  register `cr`
 
 error: register `vs0` conflicts with register `f0`
-  --> $DIR/bad-reg.rs:207:31
+  --> $DIR/bad-reg.rs:206:31
    |
 LL |         asm!("", out("f0") _, out("vs0") _);
    |                  -----------  ^^^^^^^^^^^^ register `vs0`
@@ -203,7 +203,7 @@ LL |         asm!("", out("f0") _, out("vs0") _);
    |                  register `f0`
 
 error: register `vs1` conflicts with register `f1`
-  --> $DIR/bad-reg.rs:209:31
+  --> $DIR/bad-reg.rs:208:31
    |
 LL |         asm!("", out("f1") _, out("vs1") _);
    |                  -----------  ^^^^^^^^^^^^ register `vs1`
@@ -211,7 +211,7 @@ LL |         asm!("", out("f1") _, out("vs1") _);
    |                  register `f1`
 
 error: register `vs2` conflicts with register `f2`
-  --> $DIR/bad-reg.rs:211:31
+  --> $DIR/bad-reg.rs:210:31
    |
 LL |         asm!("", out("f2") _, out("vs2") _);
    |                  -----------  ^^^^^^^^^^^^ register `vs2`
@@ -219,7 +219,7 @@ LL |         asm!("", out("f2") _, out("vs2") _);
    |                  register `f2`
 
 error: register `vs3` conflicts with register `f3`
-  --> $DIR/bad-reg.rs:213:31
+  --> $DIR/bad-reg.rs:212:31
    |
 LL |         asm!("", out("f3") _, out("vs3") _);
    |                  -----------  ^^^^^^^^^^^^ register `vs3`
@@ -227,7 +227,7 @@ LL |         asm!("", out("f3") _, out("vs3") _);
    |                  register `f3`
 
 error: register `vs4` conflicts with register `f4`
-  --> $DIR/bad-reg.rs:215:31
+  --> $DIR/bad-reg.rs:214:31
    |
 LL |         asm!("", out("f4") _, out("vs4") _);
    |                  -----------  ^^^^^^^^^^^^ register `vs4`
@@ -235,7 +235,7 @@ LL |         asm!("", out("f4") _, out("vs4") _);
    |                  register `f4`
 
 error: register `vs5` conflicts with register `f5`
-  --> $DIR/bad-reg.rs:217:31
+  --> $DIR/bad-reg.rs:216:31
    |
 LL |         asm!("", out("f5") _, out("vs5") _);
    |                  -----------  ^^^^^^^^^^^^ register `vs5`
@@ -243,7 +243,7 @@ LL |         asm!("", out("f5") _, out("vs5") _);
    |                  register `f5`
 
 error: register `vs6` conflicts with register `f6`
-  --> $DIR/bad-reg.rs:219:31
+  --> $DIR/bad-reg.rs:218:31
    |
 LL |         asm!("", out("f6") _, out("vs6") _);
    |                  -----------  ^^^^^^^^^^^^ register `vs6`
@@ -251,7 +251,7 @@ LL |         asm!("", out("f6") _, out("vs6") _);
    |                  register `f6`
 
 error: register `vs7` conflicts with register `f7`
-  --> $DIR/bad-reg.rs:221:31
+  --> $DIR/bad-reg.rs:220:31
    |
 LL |         asm!("", out("f7") _, out("vs7") _);
    |                  -----------  ^^^^^^^^^^^^ register `vs7`
@@ -259,7 +259,7 @@ LL |         asm!("", out("f7") _, out("vs7") _);
    |                  register `f7`
 
 error: register `vs8` conflicts with register `f8`
-  --> $DIR/bad-reg.rs:223:31
+  --> $DIR/bad-reg.rs:222:31
    |
 LL |         asm!("", out("f8") _, out("vs8") _);
    |                  -----------  ^^^^^^^^^^^^ register `vs8`
@@ -267,7 +267,7 @@ LL |         asm!("", out("f8") _, out("vs8") _);
    |                  register `f8`
 
 error: register `vs9` conflicts with register `f9`
-  --> $DIR/bad-reg.rs:225:31
+  --> $DIR/bad-reg.rs:224:31
    |
 LL |         asm!("", out("f9") _, out("vs9") _);
    |                  -----------  ^^^^^^^^^^^^ register `vs9`
@@ -275,7 +275,7 @@ LL |         asm!("", out("f9") _, out("vs9") _);
    |                  register `f9`
 
 error: register `vs10` conflicts with register `f10`
-  --> $DIR/bad-reg.rs:227:32
+  --> $DIR/bad-reg.rs:226:32
    |
 LL |         asm!("", out("f10") _, out("vs10") _);
    |                  ------------  ^^^^^^^^^^^^^ register `vs10`
@@ -283,7 +283,7 @@ LL |         asm!("", out("f10") _, out("vs10") _);
    |                  register `f10`
 
 error: register `vs11` conflicts with register `f11`
-  --> $DIR/bad-reg.rs:229:32
+  --> $DIR/bad-reg.rs:228:32
    |
 LL |         asm!("", out("f11") _, out("vs11") _);
    |                  ------------  ^^^^^^^^^^^^^ register `vs11`
@@ -291,7 +291,7 @@ LL |         asm!("", out("f11") _, out("vs11") _);
    |                  register `f11`
 
 error: register `vs12` conflicts with register `f12`
-  --> $DIR/bad-reg.rs:231:32
+  --> $DIR/bad-reg.rs:230:32
    |
 LL |         asm!("", out("f12") _, out("vs12") _);
    |                  ------------  ^^^^^^^^^^^^^ register `vs12`
@@ -299,7 +299,7 @@ LL |         asm!("", out("f12") _, out("vs12") _);
    |                  register `f12`
 
 error: register `vs13` conflicts with register `f13`
-  --> $DIR/bad-reg.rs:233:32
+  --> $DIR/bad-reg.rs:232:32
    |
 LL |         asm!("", out("f13") _, out("vs13") _);
    |                  ------------  ^^^^^^^^^^^^^ register `vs13`
@@ -307,7 +307,7 @@ LL |         asm!("", out("f13") _, out("vs13") _);
    |                  register `f13`
 
 error: register `vs14` conflicts with register `f14`
-  --> $DIR/bad-reg.rs:235:32
+  --> $DIR/bad-reg.rs:234:32
    |
 LL |         asm!("", out("f14") _, out("vs14") _);
    |                  ------------  ^^^^^^^^^^^^^ register `vs14`
@@ -315,7 +315,7 @@ LL |         asm!("", out("f14") _, out("vs14") _);
    |                  register `f14`
 
 error: register `vs15` conflicts with register `f15`
-  --> $DIR/bad-reg.rs:237:32
+  --> $DIR/bad-reg.rs:236:32
    |
 LL |         asm!("", out("f15") _, out("vs15") _);
    |                  ------------  ^^^^^^^^^^^^^ register `vs15`
@@ -323,7 +323,7 @@ LL |         asm!("", out("f15") _, out("vs15") _);
    |                  register `f15`
 
 error: register `vs16` conflicts with register `f16`
-  --> $DIR/bad-reg.rs:239:32
+  --> $DIR/bad-reg.rs:238:32
    |
 LL |         asm!("", out("f16") _, out("vs16") _);
    |                  ------------  ^^^^^^^^^^^^^ register `vs16`
@@ -331,7 +331,7 @@ LL |         asm!("", out("f16") _, out("vs16") _);
    |                  register `f16`
 
 error: register `vs17` conflicts with register `f17`
-  --> $DIR/bad-reg.rs:241:32
+  --> $DIR/bad-reg.rs:240:32
    |
 LL |         asm!("", out("f17") _, out("vs17") _);
    |                  ------------  ^^^^^^^^^^^^^ register `vs17`
@@ -339,7 +339,7 @@ LL |         asm!("", out("f17") _, out("vs17") _);
    |                  register `f17`
 
 error: register `vs18` conflicts with register `f18`
-  --> $DIR/bad-reg.rs:243:32
+  --> $DIR/bad-reg.rs:242:32
    |
 LL |         asm!("", out("f18") _, out("vs18") _);
    |                  ------------  ^^^^^^^^^^^^^ register `vs18`
@@ -347,7 +347,7 @@ LL |         asm!("", out("f18") _, out("vs18") _);
    |                  register `f18`
 
 error: register `vs19` conflicts with register `f19`
-  --> $DIR/bad-reg.rs:245:32
+  --> $DIR/bad-reg.rs:244:32
    |
 LL |         asm!("", out("f19") _, out("vs19") _);
    |                  ------------  ^^^^^^^^^^^^^ register `vs19`
@@ -355,7 +355,7 @@ LL |         asm!("", out("f19") _, out("vs19") _);
    |                  register `f19`
 
 error: register `vs20` conflicts with register `f20`
-  --> $DIR/bad-reg.rs:247:32
+  --> $DIR/bad-reg.rs:246:32
    |
 LL |         asm!("", out("f20") _, out("vs20") _);
    |                  ------------  ^^^^^^^^^^^^^ register `vs20`
@@ -363,7 +363,7 @@ LL |         asm!("", out("f20") _, out("vs20") _);
    |                  register `f20`
 
 error: register `vs21` conflicts with register `f21`
-  --> $DIR/bad-reg.rs:249:32
+  --> $DIR/bad-reg.rs:248:32
    |
 LL |         asm!("", out("f21") _, out("vs21") _);
    |                  ------------  ^^^^^^^^^^^^^ register `vs21`
@@ -371,7 +371,7 @@ LL |         asm!("", out("f21") _, out("vs21") _);
    |                  register `f21`
 
 error: register `vs22` conflicts with register `f22`
-  --> $DIR/bad-reg.rs:251:32
+  --> $DIR/bad-reg.rs:250:32
    |
 LL |         asm!("", out("f22") _, out("vs22") _);
    |                  ------------  ^^^^^^^^^^^^^ register `vs22`
@@ -379,7 +379,7 @@ LL |         asm!("", out("f22") _, out("vs22") _);
    |                  register `f22`
 
 error: register `vs23` conflicts with register `f23`
-  --> $DIR/bad-reg.rs:253:32
+  --> $DIR/bad-reg.rs:252:32
    |
 LL |         asm!("", out("f23") _, out("vs23") _);
    |                  ------------  ^^^^^^^^^^^^^ register `vs23`
@@ -387,7 +387,7 @@ LL |         asm!("", out("f23") _, out("vs23") _);
    |                  register `f23`
 
 error: register `vs24` conflicts with register `f24`
-  --> $DIR/bad-reg.rs:255:32
+  --> $DIR/bad-reg.rs:254:32
    |
 LL |         asm!("", out("f24") _, out("vs24") _);
    |                  ------------  ^^^^^^^^^^^^^ register `vs24`
@@ -395,7 +395,7 @@ LL |         asm!("", out("f24") _, out("vs24") _);
    |                  register `f24`
 
 error: register `vs25` conflicts with register `f25`
-  --> $DIR/bad-reg.rs:257:32
+  --> $DIR/bad-reg.rs:256:32
    |
 LL |         asm!("", out("f25") _, out("vs25") _);
    |                  ------------  ^^^^^^^^^^^^^ register `vs25`
@@ -403,7 +403,7 @@ LL |         asm!("", out("f25") _, out("vs25") _);
    |                  register `f25`
 
 error: register `vs26` conflicts with register `f26`
-  --> $DIR/bad-reg.rs:259:32
+  --> $DIR/bad-reg.rs:258:32
    |
 LL |         asm!("", out("f26") _, out("vs26") _);
    |                  ------------  ^^^^^^^^^^^^^ register `vs26`
@@ -411,7 +411,7 @@ LL |         asm!("", out("f26") _, out("vs26") _);
    |                  register `f26`
 
 error: register `vs27` conflicts with register `f27`
-  --> $DIR/bad-reg.rs:261:32
+  --> $DIR/bad-reg.rs:260:32
    |
 LL |         asm!("", out("f27") _, out("vs27") _);
    |                  ------------  ^^^^^^^^^^^^^ register `vs27`
@@ -419,7 +419,7 @@ LL |         asm!("", out("f27") _, out("vs27") _);
    |                  register `f27`
 
 error: register `vs28` conflicts with register `f28`
-  --> $DIR/bad-reg.rs:263:32
+  --> $DIR/bad-reg.rs:262:32
    |
 LL |         asm!("", out("f28") _, out("vs28") _);
    |                  ------------  ^^^^^^^^^^^^^ register `vs28`
@@ -427,7 +427,7 @@ LL |         asm!("", out("f28") _, out("vs28") _);
    |                  register `f28`
 
 error: register `vs29` conflicts with register `f29`
-  --> $DIR/bad-reg.rs:265:32
+  --> $DIR/bad-reg.rs:264:32
    |
 LL |         asm!("", out("f29") _, out("vs29") _);
    |                  ------------  ^^^^^^^^^^^^^ register `vs29`
@@ -435,7 +435,7 @@ LL |         asm!("", out("f29") _, out("vs29") _);
    |                  register `f29`
 
 error: register `vs30` conflicts with register `f30`
-  --> $DIR/bad-reg.rs:267:32
+  --> $DIR/bad-reg.rs:266:32
    |
 LL |         asm!("", out("f30") _, out("vs30") _);
    |                  ------------  ^^^^^^^^^^^^^ register `vs30`
@@ -443,7 +443,7 @@ LL |         asm!("", out("f30") _, out("vs30") _);
    |                  register `f30`
 
 error: register `vs31` conflicts with register `f31`
-  --> $DIR/bad-reg.rs:269:32
+  --> $DIR/bad-reg.rs:268:32
    |
 LL |         asm!("", out("f31") _, out("vs31") _);
    |                  ------------  ^^^^^^^^^^^^^ register `vs31`
@@ -451,7 +451,7 @@ LL |         asm!("", out("f31") _, out("vs31") _);
    |                  register `f31`
 
 error: register `v0` conflicts with register `vs32`
-  --> $DIR/bad-reg.rs:271:33
+  --> $DIR/bad-reg.rs:270:33
    |
 LL |         asm!("", out("vs32") _, out("v0") _);
    |                  -------------  ^^^^^^^^^^^ register `v0`
@@ -459,7 +459,7 @@ LL |         asm!("", out("vs32") _, out("v0") _);
    |                  register `vs32`
 
 error: register `v1` conflicts with register `vs33`
-  --> $DIR/bad-reg.rs:273:33
+  --> $DIR/bad-reg.rs:272:33
    |
 LL |         asm!("", out("vs33") _, out("v1") _);
    |                  -------------  ^^^^^^^^^^^ register `v1`
@@ -467,7 +467,7 @@ LL |         asm!("", out("vs33") _, out("v1") _);
    |                  register `vs33`
 
 error: register `v2` conflicts with register `vs34`
-  --> $DIR/bad-reg.rs:275:33
+  --> $DIR/bad-reg.rs:274:33
    |
 LL |         asm!("", out("vs34") _, out("v2") _);
    |                  -------------  ^^^^^^^^^^^ register `v2`
@@ -475,7 +475,7 @@ LL |         asm!("", out("vs34") _, out("v2") _);
    |                  register `vs34`
 
 error: register `v3` conflicts with register `vs35`
-  --> $DIR/bad-reg.rs:277:33
+  --> $DIR/bad-reg.rs:276:33
    |
 LL |         asm!("", out("vs35") _, out("v3") _);
    |                  -------------  ^^^^^^^^^^^ register `v3`
@@ -483,7 +483,7 @@ LL |         asm!("", out("vs35") _, out("v3") _);
    |                  register `vs35`
 
 error: register `v4` conflicts with register `vs36`
-  --> $DIR/bad-reg.rs:279:33
+  --> $DIR/bad-reg.rs:278:33
    |
 LL |         asm!("", out("vs36") _, out("v4") _);
    |                  -------------  ^^^^^^^^^^^ register `v4`
@@ -491,7 +491,7 @@ LL |         asm!("", out("vs36") _, out("v4") _);
    |                  register `vs36`
 
 error: register `v5` conflicts with register `vs37`
-  --> $DIR/bad-reg.rs:281:33
+  --> $DIR/bad-reg.rs:280:33
    |
 LL |         asm!("", out("vs37") _, out("v5") _);
    |                  -------------  ^^^^^^^^^^^ register `v5`
@@ -499,7 +499,7 @@ LL |         asm!("", out("vs37") _, out("v5") _);
    |                  register `vs37`
 
 error: register `v6` conflicts with register `vs38`
-  --> $DIR/bad-reg.rs:283:33
+  --> $DIR/bad-reg.rs:282:33
    |
 LL |         asm!("", out("vs38") _, out("v6") _);
    |                  -------------  ^^^^^^^^^^^ register `v6`
@@ -507,7 +507,7 @@ LL |         asm!("", out("vs38") _, out("v6") _);
    |                  register `vs38`
 
 error: register `v7` conflicts with register `vs39`
-  --> $DIR/bad-reg.rs:285:33
+  --> $DIR/bad-reg.rs:284:33
    |
 LL |         asm!("", out("vs39") _, out("v7") _);
    |                  -------------  ^^^^^^^^^^^ register `v7`
@@ -515,7 +515,7 @@ LL |         asm!("", out("vs39") _, out("v7") _);
    |                  register `vs39`
 
 error: register `v8` conflicts with register `vs40`
-  --> $DIR/bad-reg.rs:287:33
+  --> $DIR/bad-reg.rs:286:33
    |
 LL |         asm!("", out("vs40") _, out("v8") _);
    |                  -------------  ^^^^^^^^^^^ register `v8`
@@ -523,7 +523,7 @@ LL |         asm!("", out("vs40") _, out("v8") _);
    |                  register `vs40`
 
 error: register `v9` conflicts with register `vs41`
-  --> $DIR/bad-reg.rs:289:33
+  --> $DIR/bad-reg.rs:288:33
    |
 LL |         asm!("", out("vs41") _, out("v9") _);
    |                  -------------  ^^^^^^^^^^^ register `v9`
@@ -531,7 +531,7 @@ LL |         asm!("", out("vs41") _, out("v9") _);
    |                  register `vs41`
 
 error: register `v10` conflicts with register `vs42`
-  --> $DIR/bad-reg.rs:291:33
+  --> $DIR/bad-reg.rs:290:33
    |
 LL |         asm!("", out("vs42") _, out("v10") _);
    |                  -------------  ^^^^^^^^^^^^ register `v10`
@@ -539,7 +539,7 @@ LL |         asm!("", out("vs42") _, out("v10") _);
    |                  register `vs42`
 
 error: register `v11` conflicts with register `vs43`
-  --> $DIR/bad-reg.rs:293:33
+  --> $DIR/bad-reg.rs:292:33
    |
 LL |         asm!("", out("vs43") _, out("v11") _);
    |                  -------------  ^^^^^^^^^^^^ register `v11`
@@ -547,7 +547,7 @@ LL |         asm!("", out("vs43") _, out("v11") _);
    |                  register `vs43`
 
 error: register `v12` conflicts with register `vs44`
-  --> $DIR/bad-reg.rs:295:33
+  --> $DIR/bad-reg.rs:294:33
    |
 LL |         asm!("", out("vs44") _, out("v12") _);
    |                  -------------  ^^^^^^^^^^^^ register `v12`
@@ -555,7 +555,7 @@ LL |         asm!("", out("vs44") _, out("v12") _);
    |                  register `vs44`
 
 error: register `v13` conflicts with register `vs45`
-  --> $DIR/bad-reg.rs:297:33
+  --> $DIR/bad-reg.rs:296:33
    |
 LL |         asm!("", out("vs45") _, out("v13") _);
    |                  -------------  ^^^^^^^^^^^^ register `v13`
@@ -563,7 +563,7 @@ LL |         asm!("", out("vs45") _, out("v13") _);
    |                  register `vs45`
 
 error: register `v14` conflicts with register `vs46`
-  --> $DIR/bad-reg.rs:299:33
+  --> $DIR/bad-reg.rs:298:33
    |
 LL |         asm!("", out("vs46") _, out("v14") _);
    |                  -------------  ^^^^^^^^^^^^ register `v14`
@@ -571,7 +571,7 @@ LL |         asm!("", out("vs46") _, out("v14") _);
    |                  register `vs46`
 
 error: register `v15` conflicts with register `vs47`
-  --> $DIR/bad-reg.rs:301:33
+  --> $DIR/bad-reg.rs:300:33
    |
 LL |         asm!("", out("vs47") _, out("v15") _);
    |                  -------------  ^^^^^^^^^^^^ register `v15`
@@ -579,7 +579,7 @@ LL |         asm!("", out("vs47") _, out("v15") _);
    |                  register `vs47`
 
 error: register `v16` conflicts with register `vs48`
-  --> $DIR/bad-reg.rs:303:33
+  --> $DIR/bad-reg.rs:302:33
    |
 LL |         asm!("", out("vs48") _, out("v16") _);
    |                  -------------  ^^^^^^^^^^^^ register `v16`
@@ -587,7 +587,7 @@ LL |         asm!("", out("vs48") _, out("v16") _);
    |                  register `vs48`
 
 error: register `v17` conflicts with register `vs49`
-  --> $DIR/bad-reg.rs:305:33
+  --> $DIR/bad-reg.rs:304:33
    |
 LL |         asm!("", out("vs49") _, out("v17") _);
    |                  -------------  ^^^^^^^^^^^^ register `v17`
@@ -595,7 +595,7 @@ LL |         asm!("", out("vs49") _, out("v17") _);
    |                  register `vs49`
 
 error: register `v18` conflicts with register `vs50`
-  --> $DIR/bad-reg.rs:307:33
+  --> $DIR/bad-reg.rs:306:33
    |
 LL |         asm!("", out("vs50") _, out("v18") _);
    |                  -------------  ^^^^^^^^^^^^ register `v18`
@@ -603,7 +603,7 @@ LL |         asm!("", out("vs50") _, out("v18") _);
    |                  register `vs50`
 
 error: register `v19` conflicts with register `vs51`
-  --> $DIR/bad-reg.rs:309:33
+  --> $DIR/bad-reg.rs:308:33
    |
 LL |         asm!("", out("vs51") _, out("v19") _);
    |                  -------------  ^^^^^^^^^^^^ register `v19`
@@ -611,7 +611,7 @@ LL |         asm!("", out("vs51") _, out("v19") _);
    |                  register `vs51`
 
 error: register `v20` conflicts with register `vs52`
-  --> $DIR/bad-reg.rs:311:33
+  --> $DIR/bad-reg.rs:310:33
    |
 LL |         asm!("", out("vs52") _, out("v20") _);
    |                  -------------  ^^^^^^^^^^^^ register `v20`
@@ -619,7 +619,7 @@ LL |         asm!("", out("vs52") _, out("v20") _);
    |                  register `vs52`
 
 error: register `v21` conflicts with register `vs53`
-  --> $DIR/bad-reg.rs:313:33
+  --> $DIR/bad-reg.rs:312:33
    |
 LL |         asm!("", out("vs53") _, out("v21") _);
    |                  -------------  ^^^^^^^^^^^^ register `v21`
@@ -627,7 +627,7 @@ LL |         asm!("", out("vs53") _, out("v21") _);
    |                  register `vs53`
 
 error: register `v22` conflicts with register `vs54`
-  --> $DIR/bad-reg.rs:315:33
+  --> $DIR/bad-reg.rs:314:33
    |
 LL |         asm!("", out("vs54") _, out("v22") _);
    |                  -------------  ^^^^^^^^^^^^ register `v22`
@@ -635,7 +635,7 @@ LL |         asm!("", out("vs54") _, out("v22") _);
    |                  register `vs54`
 
 error: register `v23` conflicts with register `vs55`
-  --> $DIR/bad-reg.rs:317:33
+  --> $DIR/bad-reg.rs:316:33
    |
 LL |         asm!("", out("vs55") _, out("v23") _);
    |                  -------------  ^^^^^^^^^^^^ register `v23`
@@ -643,7 +643,7 @@ LL |         asm!("", out("vs55") _, out("v23") _);
    |                  register `vs55`
 
 error: register `v24` conflicts with register `vs56`
-  --> $DIR/bad-reg.rs:319:33
+  --> $DIR/bad-reg.rs:318:33
    |
 LL |         asm!("", out("vs56") _, out("v24") _);
    |                  -------------  ^^^^^^^^^^^^ register `v24`
@@ -651,7 +651,7 @@ LL |         asm!("", out("vs56") _, out("v24") _);
    |                  register `vs56`
 
 error: register `v25` conflicts with register `vs57`
-  --> $DIR/bad-reg.rs:321:33
+  --> $DIR/bad-reg.rs:320:33
    |
 LL |         asm!("", out("vs57") _, out("v25") _);
    |                  -------------  ^^^^^^^^^^^^ register `v25`
@@ -659,7 +659,7 @@ LL |         asm!("", out("vs57") _, out("v25") _);
    |                  register `vs57`
 
 error: register `v26` conflicts with register `vs58`
-  --> $DIR/bad-reg.rs:323:33
+  --> $DIR/bad-reg.rs:322:33
    |
 LL |         asm!("", out("vs58") _, out("v26") _);
    |                  -------------  ^^^^^^^^^^^^ register `v26`
@@ -667,7 +667,7 @@ LL |         asm!("", out("vs58") _, out("v26") _);
    |                  register `vs58`
 
 error: register `v27` conflicts with register `vs59`
-  --> $DIR/bad-reg.rs:325:33
+  --> $DIR/bad-reg.rs:324:33
    |
 LL |         asm!("", out("vs59") _, out("v27") _);
    |                  -------------  ^^^^^^^^^^^^ register `v27`
@@ -675,7 +675,7 @@ LL |         asm!("", out("vs59") _, out("v27") _);
    |                  register `vs59`
 
 error: register `v28` conflicts with register `vs60`
-  --> $DIR/bad-reg.rs:327:33
+  --> $DIR/bad-reg.rs:326:33
    |
 LL |         asm!("", out("vs60") _, out("v28") _);
    |                  -------------  ^^^^^^^^^^^^ register `v28`
@@ -683,7 +683,7 @@ LL |         asm!("", out("vs60") _, out("v28") _);
    |                  register `vs60`
 
 error: register `v29` conflicts with register `vs61`
-  --> $DIR/bad-reg.rs:329:33
+  --> $DIR/bad-reg.rs:328:33
    |
 LL |         asm!("", out("vs61") _, out("v29") _);
    |                  -------------  ^^^^^^^^^^^^ register `v29`
@@ -691,7 +691,7 @@ LL |         asm!("", out("vs61") _, out("v29") _);
    |                  register `vs61`
 
 error: register `v30` conflicts with register `vs62`
-  --> $DIR/bad-reg.rs:331:33
+  --> $DIR/bad-reg.rs:330:33
    |
 LL |         asm!("", out("vs62") _, out("v30") _);
    |                  -------------  ^^^^^^^^^^^^ register `v30`
@@ -699,7 +699,7 @@ LL |         asm!("", out("vs62") _, out("v30") _);
    |                  register `vs62`
 
 error: register `v31` conflicts with register `vs63`
-  --> $DIR/bad-reg.rs:333:33
+  --> $DIR/bad-reg.rs:332:33
    |
 LL |         asm!("", out("vs63") _, out("v31") _);
    |                  -------------  ^^^^^^^^^^^^ register `v31`
@@ -707,13 +707,13 @@ LL |         asm!("", out("vs63") _, out("v31") _);
    |                  register `vs63`
 
 error: cannot use register `r13`: r13 is a reserved register on this target
-  --> $DIR/bad-reg.rs:41:18
+  --> $DIR/bad-reg.rs:40:18
    |
 LL |         asm!("", out("r13") _);
    |                  ^^^^^^^^^^^^
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:64:27
+  --> $DIR/bad-reg.rs:63:27
    |
 LL |         asm!("", in("v0") x); // FIXME: should be ok if vsx is available
    |                           ^
@@ -721,7 +721,7 @@ LL |         asm!("", in("v0") x); // FIXME: should be ok if vsx is available
    = note: register class `vreg` supports these types: i8x16, i16x8, i32x4, f32x4, f32, f64, i64x2, f64x2
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:67:28
+  --> $DIR/bad-reg.rs:66:28
    |
 LL |         asm!("", out("v0") x); // FIXME: should be ok if vsx is available
    |                            ^
@@ -729,7 +729,7 @@ LL |         asm!("", out("v0") x); // FIXME: should be ok if vsx is available
    = note: register class `vreg` supports these types: i8x16, i16x8, i32x4, f32x4, f32, f64, i64x2, f64x2
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:75:35
+  --> $DIR/bad-reg.rs:74:35
    |
 LL |         asm!("/* {} */", in(vreg) x); // FIXME: should be ok if vsx is available
    |                                   ^
@@ -737,7 +737,7 @@ LL |         asm!("/* {} */", in(vreg) x); // FIXME: should be ok if vsx is avai
    = note: register class `vreg` supports these types: i8x16, i16x8, i32x4, f32x4, f32, f64, i64x2, f64x2
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:105:28
+  --> $DIR/bad-reg.rs:104:28
    |
 LL |         asm!("", in("vs0") x); // FIXME: should be ok if vsx is available
    |                            ^
@@ -745,7 +745,7 @@ LL |         asm!("", in("vs0") x); // FIXME: should be ok if vsx is available
    = note: register class `vsreg` supports these types: f32, f64, i8x16, i16x8, i32x4, i64x2, f32x4, f64x2
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:108:29
+  --> $DIR/bad-reg.rs:107:29
    |
 LL |         asm!("", out("vs0") x); // FIXME: should be ok if vsx is available
    |                             ^
@@ -753,7 +753,7 @@ LL |         asm!("", out("vs0") x); // FIXME: should be ok if vsx is available
    = note: register class `vsreg` supports these types: f32, f64, i8x16, i16x8, i32x4, i64x2, f32x4, f64x2
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:115:36
+  --> $DIR/bad-reg.rs:114:36
    |
 LL |         asm!("/* {} */", in(vsreg) x); // FIXME: should be ok if vsx is available
    |                                    ^
@@ -761,7 +761,7 @@ LL |         asm!("/* {} */", in(vsreg) x); // FIXME: should be ok if vsx is ava
    = note: register class `vsreg` supports these types: f32, f64, i8x16, i16x8, i32x4, i64x2, f32x4, f64x2
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:138:27
+  --> $DIR/bad-reg.rs:137:27
    |
 LL |         asm!("", in("cr") x);
    |                           ^
@@ -769,7 +769,7 @@ LL |         asm!("", in("cr") x);
    = note: register class `cr` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:141:28
+  --> $DIR/bad-reg.rs:140:28
    |
 LL |         asm!("", out("cr") x);
    |                            ^
@@ -777,7 +777,7 @@ LL |         asm!("", out("cr") x);
    = note: register class `cr` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:144:33
+  --> $DIR/bad-reg.rs:143:33
    |
 LL |         asm!("/* {} */", in(cr) x);
    |                                 ^
@@ -785,7 +785,7 @@ LL |         asm!("/* {} */", in(cr) x);
    = note: register class `cr` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:151:28
+  --> $DIR/bad-reg.rs:150:28
    |
 LL |         asm!("", in("ctr") x);
    |                            ^
@@ -793,7 +793,7 @@ LL |         asm!("", in("ctr") x);
    = note: register class `ctr` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:154:29
+  --> $DIR/bad-reg.rs:153:29
    |
 LL |         asm!("", out("ctr") x);
    |                             ^
@@ -801,7 +801,7 @@ LL |         asm!("", out("ctr") x);
    = note: register class `ctr` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:157:34
+  --> $DIR/bad-reg.rs:156:34
    |
 LL |         asm!("/* {} */", in(ctr) x);
    |                                  ^
@@ -809,7 +809,7 @@ LL |         asm!("/* {} */", in(ctr) x);
    = note: register class `ctr` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:164:27
+  --> $DIR/bad-reg.rs:163:27
    |
 LL |         asm!("", in("lr") x);
    |                           ^
@@ -817,7 +817,7 @@ LL |         asm!("", in("lr") x);
    = note: register class `lr` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:167:28
+  --> $DIR/bad-reg.rs:166:28
    |
 LL |         asm!("", out("lr") x);
    |                            ^
@@ -825,7 +825,7 @@ LL |         asm!("", out("lr") x);
    = note: register class `lr` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:170:33
+  --> $DIR/bad-reg.rs:169:33
    |
 LL |         asm!("/* {} */", in(lr) x);
    |                                 ^
@@ -833,7 +833,7 @@ LL |         asm!("/* {} */", in(lr) x);
    = note: register class `lr` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:177:28
+  --> $DIR/bad-reg.rs:176:28
    |
 LL |         asm!("", in("xer") x);
    |                            ^
@@ -841,7 +841,7 @@ LL |         asm!("", in("xer") x);
    = note: register class `xer` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:180:29
+  --> $DIR/bad-reg.rs:179:29
    |
 LL |         asm!("", out("xer") x);
    |                             ^
@@ -849,7 +849,7 @@ LL |         asm!("", out("xer") x);
    = note: register class `xer` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:183:34
+  --> $DIR/bad-reg.rs:182:34
    |
 LL |         asm!("/* {} */", in(xer) x);
    |                                  ^
diff --git a/tests/ui/asm/powerpc/bad-reg.rs b/tests/ui/asm/powerpc/bad-reg.rs
index d133dae3da62..c09001f27ffe 100644
--- a/tests/ui/asm/powerpc/bad-reg.rs
+++ b/tests/ui/asm/powerpc/bad-reg.rs
@@ -8,7 +8,6 @@
 //@[powerpc64le] needs-llvm-components: powerpc
 //@[aix64] compile-flags: --target powerpc64-ibm-aix
 //@[aix64] needs-llvm-components: powerpc
-//@ needs-asm-support
 //@ ignore-backends: gcc
 // ignore-tidy-linelength
 
diff --git a/tests/ui/asm/riscv/bad-reg.riscv32e.stderr b/tests/ui/asm/riscv/bad-reg.riscv32e.stderr
index 3999f9cf0761..27c8e958e536 100644
--- a/tests/ui/asm/riscv/bad-reg.riscv32e.stderr
+++ b/tests/ui/asm/riscv/bad-reg.riscv32e.stderr
@@ -1,185 +1,185 @@
 error: invalid register `s1`: s1 is used internally by LLVM and cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:34:18
+  --> $DIR/bad-reg.rs:33:18
    |
 LL |         asm!("", out("s1") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `fp`: the frame pointer cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:36:18
+  --> $DIR/bad-reg.rs:35:18
    |
 LL |         asm!("", out("fp") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `sp`: the stack pointer cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:38:18
+  --> $DIR/bad-reg.rs:37:18
    |
 LL |         asm!("", out("sp") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `gp`: the global pointer cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:40:18
+  --> $DIR/bad-reg.rs:39:18
    |
 LL |         asm!("", out("gp") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `tp`: the thread pointer cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:42:18
+  --> $DIR/bad-reg.rs:41:18
    |
 LL |         asm!("", out("tp") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `zero`: the zero register cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:44:18
+  --> $DIR/bad-reg.rs:43:18
    |
 LL |         asm!("", out("zero") _);
    |                  ^^^^^^^^^^^^^
 
 error: register class `vreg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:95:18
+  --> $DIR/bad-reg.rs:94:18
    |
 LL |         asm!("", in("v0") x);
    |                  ^^^^^^^^^^
 
 error: register class `vreg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:98:18
+  --> $DIR/bad-reg.rs:97:18
    |
 LL |         asm!("", out("v0") x);
    |                  ^^^^^^^^^^^
 
 error: register class `vreg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:101:26
+  --> $DIR/bad-reg.rs:100:26
    |
 LL |         asm!("/* {} */", in(vreg) x);
    |                          ^^^^^^^^^^
 
 error: register class `vreg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:104:26
+  --> $DIR/bad-reg.rs:103:26
    |
 LL |         asm!("/* {} */", out(vreg) _);
    |                          ^^^^^^^^^^^
 
 error: cannot use register `x16`: register can't be used with the `e` target feature
-  --> $DIR/bad-reg.rs:47:18
+  --> $DIR/bad-reg.rs:46:18
    |
 LL |         asm!("", out("x16") _);
    |                  ^^^^^^^^^^^^
 
 error: cannot use register `x17`: register can't be used with the `e` target feature
-  --> $DIR/bad-reg.rs:49:18
+  --> $DIR/bad-reg.rs:48:18
    |
 LL |         asm!("", out("x17") _);
    |                  ^^^^^^^^^^^^
 
 error: cannot use register `x18`: register can't be used with the `e` target feature
-  --> $DIR/bad-reg.rs:51:18
+  --> $DIR/bad-reg.rs:50:18
    |
 LL |         asm!("", out("x18") _);
    |                  ^^^^^^^^^^^^
 
 error: cannot use register `x19`: register can't be used with the `e` target feature
-  --> $DIR/bad-reg.rs:53:18
+  --> $DIR/bad-reg.rs:52:18
    |
 LL |         asm!("", out("x19") _);
    |                  ^^^^^^^^^^^^
 
 error: cannot use register `x20`: register can't be used with the `e` target feature
-  --> $DIR/bad-reg.rs:55:18
+  --> $DIR/bad-reg.rs:54:18
    |
 LL |         asm!("", out("x20") _);
    |                  ^^^^^^^^^^^^
 
 error: cannot use register `x21`: register can't be used with the `e` target feature
-  --> $DIR/bad-reg.rs:57:18
+  --> $DIR/bad-reg.rs:56:18
    |
 LL |         asm!("", out("x21") _);
    |                  ^^^^^^^^^^^^
 
 error: cannot use register `x22`: register can't be used with the `e` target feature
-  --> $DIR/bad-reg.rs:59:18
+  --> $DIR/bad-reg.rs:58:18
    |
 LL |         asm!("", out("x22") _);
    |                  ^^^^^^^^^^^^
 
 error: cannot use register `x23`: register can't be used with the `e` target feature
-  --> $DIR/bad-reg.rs:61:18
+  --> $DIR/bad-reg.rs:60:18
    |
 LL |         asm!("", out("x23") _);
    |                  ^^^^^^^^^^^^
 
 error: cannot use register `x24`: register can't be used with the `e` target feature
-  --> $DIR/bad-reg.rs:63:18
+  --> $DIR/bad-reg.rs:62:18
    |
 LL |         asm!("", out("x24") _);
    |                  ^^^^^^^^^^^^
 
 error: cannot use register `x25`: register can't be used with the `e` target feature
-  --> $DIR/bad-reg.rs:65:18
+  --> $DIR/bad-reg.rs:64:18
    |
 LL |         asm!("", out("x25") _);
    |                  ^^^^^^^^^^^^
 
 error: cannot use register `x26`: register can't be used with the `e` target feature
-  --> $DIR/bad-reg.rs:67:18
+  --> $DIR/bad-reg.rs:66:18
    |
 LL |         asm!("", out("x26") _);
    |                  ^^^^^^^^^^^^
 
 error: cannot use register `x27`: register can't be used with the `e` target feature
-  --> $DIR/bad-reg.rs:69:18
+  --> $DIR/bad-reg.rs:68:18
    |
 LL |         asm!("", out("x27") _);
    |                  ^^^^^^^^^^^^
 
 error: cannot use register `x28`: register can't be used with the `e` target feature
-  --> $DIR/bad-reg.rs:71:18
+  --> $DIR/bad-reg.rs:70:18
    |
 LL |         asm!("", out("x28") _);
    |                  ^^^^^^^^^^^^
 
 error: cannot use register `x29`: register can't be used with the `e` target feature
-  --> $DIR/bad-reg.rs:73:18
+  --> $DIR/bad-reg.rs:72:18
    |
 LL |         asm!("", out("x29") _);
    |                  ^^^^^^^^^^^^
 
 error: cannot use register `x30`: register can't be used with the `e` target feature
-  --> $DIR/bad-reg.rs:75:18
+  --> $DIR/bad-reg.rs:74:18
    |
 LL |         asm!("", out("x30") _);
    |                  ^^^^^^^^^^^^
 
 error: cannot use register `x31`: register can't be used with the `e` target feature
-  --> $DIR/bad-reg.rs:77:18
+  --> $DIR/bad-reg.rs:76:18
    |
 LL |         asm!("", out("x31") _);
    |                  ^^^^^^^^^^^^
 
 error: register class `freg` requires at least one of the following target features: d, f
-  --> $DIR/bad-reg.rs:81:26
+  --> $DIR/bad-reg.rs:80:26
    |
 LL |         asm!("/* {} */", in(freg) f);
    |                          ^^^^^^^^^^
 
 error: register class `freg` requires at least one of the following target features: d, f
-  --> $DIR/bad-reg.rs:83:26
+  --> $DIR/bad-reg.rs:82:26
    |
 LL |         asm!("/* {} */", out(freg) _);
    |                          ^^^^^^^^^^^
 
 error: register class `freg` requires at least one of the following target features: d, f
-  --> $DIR/bad-reg.rs:85:26
+  --> $DIR/bad-reg.rs:84:26
    |
 LL |         asm!("/* {} */", in(freg) d);
    |                          ^^^^^^^^^^
 
 error: register class `freg` requires at least one of the following target features: d, f
-  --> $DIR/bad-reg.rs:88:26
+  --> $DIR/bad-reg.rs:87:26
    |
 LL |         asm!("/* {} */", out(freg) d);
    |                          ^^^^^^^^^^^
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:95:27
+  --> $DIR/bad-reg.rs:94:27
    |
 LL |         asm!("", in("v0") x);
    |                           ^
@@ -187,7 +187,7 @@ LL |         asm!("", in("v0") x);
    = note: register class `vreg` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:98:28
+  --> $DIR/bad-reg.rs:97:28
    |
 LL |         asm!("", out("v0") x);
    |                            ^
@@ -195,7 +195,7 @@ LL |         asm!("", out("v0") x);
    = note: register class `vreg` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:101:35
+  --> $DIR/bad-reg.rs:100:35
    |
 LL |         asm!("/* {} */", in(vreg) x);
    |                                   ^
diff --git a/tests/ui/asm/riscv/bad-reg.riscv32gc.stderr b/tests/ui/asm/riscv/bad-reg.riscv32gc.stderr
index 0e458d2a47e2..4ff03d819e60 100644
--- a/tests/ui/asm/riscv/bad-reg.riscv32gc.stderr
+++ b/tests/ui/asm/riscv/bad-reg.riscv32gc.stderr
@@ -1,65 +1,65 @@
 error: invalid register `s1`: s1 is used internally by LLVM and cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:34:18
+  --> $DIR/bad-reg.rs:33:18
    |
 LL |         asm!("", out("s1") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `fp`: the frame pointer cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:36:18
+  --> $DIR/bad-reg.rs:35:18
    |
 LL |         asm!("", out("fp") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `sp`: the stack pointer cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:38:18
+  --> $DIR/bad-reg.rs:37:18
    |
 LL |         asm!("", out("sp") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `gp`: the global pointer cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:40:18
+  --> $DIR/bad-reg.rs:39:18
    |
 LL |         asm!("", out("gp") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `tp`: the thread pointer cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:42:18
+  --> $DIR/bad-reg.rs:41:18
    |
 LL |         asm!("", out("tp") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `zero`: the zero register cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:44:18
+  --> $DIR/bad-reg.rs:43:18
    |
 LL |         asm!("", out("zero") _);
    |                  ^^^^^^^^^^^^^
 
 error: register class `vreg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:95:18
+  --> $DIR/bad-reg.rs:94:18
    |
 LL |         asm!("", in("v0") x);
    |                  ^^^^^^^^^^
 
 error: register class `vreg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:98:18
+  --> $DIR/bad-reg.rs:97:18
    |
 LL |         asm!("", out("v0") x);
    |                  ^^^^^^^^^^^
 
 error: register class `vreg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:101:26
+  --> $DIR/bad-reg.rs:100:26
    |
 LL |         asm!("/* {} */", in(vreg) x);
    |                          ^^^^^^^^^^
 
 error: register class `vreg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:104:26
+  --> $DIR/bad-reg.rs:103:26
    |
 LL |         asm!("/* {} */", out(vreg) _);
    |                          ^^^^^^^^^^^
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:95:27
+  --> $DIR/bad-reg.rs:94:27
    |
 LL |         asm!("", in("v0") x);
    |                           ^
@@ -67,7 +67,7 @@ LL |         asm!("", in("v0") x);
    = note: register class `vreg` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:98:28
+  --> $DIR/bad-reg.rs:97:28
    |
 LL |         asm!("", out("v0") x);
    |                            ^
@@ -75,7 +75,7 @@ LL |         asm!("", out("v0") x);
    = note: register class `vreg` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:101:35
+  --> $DIR/bad-reg.rs:100:35
    |
 LL |         asm!("/* {} */", in(vreg) x);
    |                                   ^
diff --git a/tests/ui/asm/riscv/bad-reg.riscv32i.stderr b/tests/ui/asm/riscv/bad-reg.riscv32i.stderr
index 18af1957d087..fbe63eb0563c 100644
--- a/tests/ui/asm/riscv/bad-reg.riscv32i.stderr
+++ b/tests/ui/asm/riscv/bad-reg.riscv32i.stderr
@@ -1,89 +1,89 @@
 error: invalid register `s1`: s1 is used internally by LLVM and cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:34:18
+  --> $DIR/bad-reg.rs:33:18
    |
 LL |         asm!("", out("s1") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `fp`: the frame pointer cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:36:18
+  --> $DIR/bad-reg.rs:35:18
    |
 LL |         asm!("", out("fp") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `sp`: the stack pointer cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:38:18
+  --> $DIR/bad-reg.rs:37:18
    |
 LL |         asm!("", out("sp") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `gp`: the global pointer cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:40:18
+  --> $DIR/bad-reg.rs:39:18
    |
 LL |         asm!("", out("gp") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `tp`: the thread pointer cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:42:18
+  --> $DIR/bad-reg.rs:41:18
    |
 LL |         asm!("", out("tp") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `zero`: the zero register cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:44:18
+  --> $DIR/bad-reg.rs:43:18
    |
 LL |         asm!("", out("zero") _);
    |                  ^^^^^^^^^^^^^
 
 error: register class `vreg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:95:18
+  --> $DIR/bad-reg.rs:94:18
    |
 LL |         asm!("", in("v0") x);
    |                  ^^^^^^^^^^
 
 error: register class `vreg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:98:18
+  --> $DIR/bad-reg.rs:97:18
    |
 LL |         asm!("", out("v0") x);
    |                  ^^^^^^^^^^^
 
 error: register class `vreg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:101:26
+  --> $DIR/bad-reg.rs:100:26
    |
 LL |         asm!("/* {} */", in(vreg) x);
    |                          ^^^^^^^^^^
 
 error: register class `vreg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:104:26
+  --> $DIR/bad-reg.rs:103:26
    |
 LL |         asm!("/* {} */", out(vreg) _);
    |                          ^^^^^^^^^^^
 
 error: register class `freg` requires at least one of the following target features: d, f
-  --> $DIR/bad-reg.rs:81:26
+  --> $DIR/bad-reg.rs:80:26
    |
 LL |         asm!("/* {} */", in(freg) f);
    |                          ^^^^^^^^^^
 
 error: register class `freg` requires at least one of the following target features: d, f
-  --> $DIR/bad-reg.rs:83:26
+  --> $DIR/bad-reg.rs:82:26
    |
 LL |         asm!("/* {} */", out(freg) _);
    |                          ^^^^^^^^^^^
 
 error: register class `freg` requires at least one of the following target features: d, f
-  --> $DIR/bad-reg.rs:85:26
+  --> $DIR/bad-reg.rs:84:26
    |
 LL |         asm!("/* {} */", in(freg) d);
    |                          ^^^^^^^^^^
 
 error: register class `freg` requires at least one of the following target features: d, f
-  --> $DIR/bad-reg.rs:88:26
+  --> $DIR/bad-reg.rs:87:26
    |
 LL |         asm!("/* {} */", out(freg) d);
    |                          ^^^^^^^^^^^
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:95:27
+  --> $DIR/bad-reg.rs:94:27
    |
 LL |         asm!("", in("v0") x);
    |                           ^
@@ -91,7 +91,7 @@ LL |         asm!("", in("v0") x);
    = note: register class `vreg` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:98:28
+  --> $DIR/bad-reg.rs:97:28
    |
 LL |         asm!("", out("v0") x);
    |                            ^
@@ -99,7 +99,7 @@ LL |         asm!("", out("v0") x);
    = note: register class `vreg` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:101:35
+  --> $DIR/bad-reg.rs:100:35
    |
 LL |         asm!("/* {} */", in(vreg) x);
    |                                   ^
diff --git a/tests/ui/asm/riscv/bad-reg.riscv32imafc.stderr b/tests/ui/asm/riscv/bad-reg.riscv32imafc.stderr
index d3b74d1bd0dc..57664cfe893b 100644
--- a/tests/ui/asm/riscv/bad-reg.riscv32imafc.stderr
+++ b/tests/ui/asm/riscv/bad-reg.riscv32imafc.stderr
@@ -1,65 +1,65 @@
 error: invalid register `s1`: s1 is used internally by LLVM and cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:34:18
+  --> $DIR/bad-reg.rs:33:18
    |
 LL |         asm!("", out("s1") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `fp`: the frame pointer cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:36:18
+  --> $DIR/bad-reg.rs:35:18
    |
 LL |         asm!("", out("fp") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `sp`: the stack pointer cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:38:18
+  --> $DIR/bad-reg.rs:37:18
    |
 LL |         asm!("", out("sp") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `gp`: the global pointer cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:40:18
+  --> $DIR/bad-reg.rs:39:18
    |
 LL |         asm!("", out("gp") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `tp`: the thread pointer cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:42:18
+  --> $DIR/bad-reg.rs:41:18
    |
 LL |         asm!("", out("tp") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `zero`: the zero register cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:44:18
+  --> $DIR/bad-reg.rs:43:18
    |
 LL |         asm!("", out("zero") _);
    |                  ^^^^^^^^^^^^^
 
 error: register class `vreg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:95:18
+  --> $DIR/bad-reg.rs:94:18
    |
 LL |         asm!("", in("v0") x);
    |                  ^^^^^^^^^^
 
 error: register class `vreg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:98:18
+  --> $DIR/bad-reg.rs:97:18
    |
 LL |         asm!("", out("v0") x);
    |                  ^^^^^^^^^^^
 
 error: register class `vreg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:101:26
+  --> $DIR/bad-reg.rs:100:26
    |
 LL |         asm!("/* {} */", in(vreg) x);
    |                          ^^^^^^^^^^
 
 error: register class `vreg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:104:26
+  --> $DIR/bad-reg.rs:103:26
    |
 LL |         asm!("/* {} */", out(vreg) _);
    |                          ^^^^^^^^^^^
 
 error: `d` target feature is not enabled
-  --> $DIR/bad-reg.rs:85:35
+  --> $DIR/bad-reg.rs:84:35
    |
 LL |         asm!("/* {} */", in(freg) d);
    |                                   ^
@@ -67,7 +67,7 @@ LL |         asm!("/* {} */", in(freg) d);
    = note: this is required to use type `f64` with register class `freg`
 
 error: `d` target feature is not enabled
-  --> $DIR/bad-reg.rs:88:36
+  --> $DIR/bad-reg.rs:87:36
    |
 LL |         asm!("/* {} */", out(freg) d);
    |                                    ^
@@ -75,7 +75,7 @@ LL |         asm!("/* {} */", out(freg) d);
    = note: this is required to use type `f64` with register class `freg`
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:95:27
+  --> $DIR/bad-reg.rs:94:27
    |
 LL |         asm!("", in("v0") x);
    |                           ^
@@ -83,7 +83,7 @@ LL |         asm!("", in("v0") x);
    = note: register class `vreg` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:98:28
+  --> $DIR/bad-reg.rs:97:28
    |
 LL |         asm!("", out("v0") x);
    |                            ^
@@ -91,7 +91,7 @@ LL |         asm!("", out("v0") x);
    = note: register class `vreg` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:101:35
+  --> $DIR/bad-reg.rs:100:35
    |
 LL |         asm!("/* {} */", in(vreg) x);
    |                                   ^
diff --git a/tests/ui/asm/riscv/bad-reg.riscv64gc.stderr b/tests/ui/asm/riscv/bad-reg.riscv64gc.stderr
index 0e458d2a47e2..4ff03d819e60 100644
--- a/tests/ui/asm/riscv/bad-reg.riscv64gc.stderr
+++ b/tests/ui/asm/riscv/bad-reg.riscv64gc.stderr
@@ -1,65 +1,65 @@
 error: invalid register `s1`: s1 is used internally by LLVM and cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:34:18
+  --> $DIR/bad-reg.rs:33:18
    |
 LL |         asm!("", out("s1") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `fp`: the frame pointer cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:36:18
+  --> $DIR/bad-reg.rs:35:18
    |
 LL |         asm!("", out("fp") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `sp`: the stack pointer cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:38:18
+  --> $DIR/bad-reg.rs:37:18
    |
 LL |         asm!("", out("sp") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `gp`: the global pointer cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:40:18
+  --> $DIR/bad-reg.rs:39:18
    |
 LL |         asm!("", out("gp") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `tp`: the thread pointer cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:42:18
+  --> $DIR/bad-reg.rs:41:18
    |
 LL |         asm!("", out("tp") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `zero`: the zero register cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:44:18
+  --> $DIR/bad-reg.rs:43:18
    |
 LL |         asm!("", out("zero") _);
    |                  ^^^^^^^^^^^^^
 
 error: register class `vreg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:95:18
+  --> $DIR/bad-reg.rs:94:18
    |
 LL |         asm!("", in("v0") x);
    |                  ^^^^^^^^^^
 
 error: register class `vreg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:98:18
+  --> $DIR/bad-reg.rs:97:18
    |
 LL |         asm!("", out("v0") x);
    |                  ^^^^^^^^^^^
 
 error: register class `vreg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:101:26
+  --> $DIR/bad-reg.rs:100:26
    |
 LL |         asm!("/* {} */", in(vreg) x);
    |                          ^^^^^^^^^^
 
 error: register class `vreg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:104:26
+  --> $DIR/bad-reg.rs:103:26
    |
 LL |         asm!("/* {} */", out(vreg) _);
    |                          ^^^^^^^^^^^
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:95:27
+  --> $DIR/bad-reg.rs:94:27
    |
 LL |         asm!("", in("v0") x);
    |                           ^
@@ -67,7 +67,7 @@ LL |         asm!("", in("v0") x);
    = note: register class `vreg` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:98:28
+  --> $DIR/bad-reg.rs:97:28
    |
 LL |         asm!("", out("v0") x);
    |                            ^
@@ -75,7 +75,7 @@ LL |         asm!("", out("v0") x);
    = note: register class `vreg` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:101:35
+  --> $DIR/bad-reg.rs:100:35
    |
 LL |         asm!("/* {} */", in(vreg) x);
    |                                   ^
diff --git a/tests/ui/asm/riscv/bad-reg.riscv64imac.stderr b/tests/ui/asm/riscv/bad-reg.riscv64imac.stderr
index 18af1957d087..fbe63eb0563c 100644
--- a/tests/ui/asm/riscv/bad-reg.riscv64imac.stderr
+++ b/tests/ui/asm/riscv/bad-reg.riscv64imac.stderr
@@ -1,89 +1,89 @@
 error: invalid register `s1`: s1 is used internally by LLVM and cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:34:18
+  --> $DIR/bad-reg.rs:33:18
    |
 LL |         asm!("", out("s1") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `fp`: the frame pointer cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:36:18
+  --> $DIR/bad-reg.rs:35:18
    |
 LL |         asm!("", out("fp") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `sp`: the stack pointer cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:38:18
+  --> $DIR/bad-reg.rs:37:18
    |
 LL |         asm!("", out("sp") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `gp`: the global pointer cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:40:18
+  --> $DIR/bad-reg.rs:39:18
    |
 LL |         asm!("", out("gp") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `tp`: the thread pointer cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:42:18
+  --> $DIR/bad-reg.rs:41:18
    |
 LL |         asm!("", out("tp") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `zero`: the zero register cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:44:18
+  --> $DIR/bad-reg.rs:43:18
    |
 LL |         asm!("", out("zero") _);
    |                  ^^^^^^^^^^^^^
 
 error: register class `vreg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:95:18
+  --> $DIR/bad-reg.rs:94:18
    |
 LL |         asm!("", in("v0") x);
    |                  ^^^^^^^^^^
 
 error: register class `vreg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:98:18
+  --> $DIR/bad-reg.rs:97:18
    |
 LL |         asm!("", out("v0") x);
    |                  ^^^^^^^^^^^
 
 error: register class `vreg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:101:26
+  --> $DIR/bad-reg.rs:100:26
    |
 LL |         asm!("/* {} */", in(vreg) x);
    |                          ^^^^^^^^^^
 
 error: register class `vreg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:104:26
+  --> $DIR/bad-reg.rs:103:26
    |
 LL |         asm!("/* {} */", out(vreg) _);
    |                          ^^^^^^^^^^^
 
 error: register class `freg` requires at least one of the following target features: d, f
-  --> $DIR/bad-reg.rs:81:26
+  --> $DIR/bad-reg.rs:80:26
    |
 LL |         asm!("/* {} */", in(freg) f);
    |                          ^^^^^^^^^^
 
 error: register class `freg` requires at least one of the following target features: d, f
-  --> $DIR/bad-reg.rs:83:26
+  --> $DIR/bad-reg.rs:82:26
    |
 LL |         asm!("/* {} */", out(freg) _);
    |                          ^^^^^^^^^^^
 
 error: register class `freg` requires at least one of the following target features: d, f
-  --> $DIR/bad-reg.rs:85:26
+  --> $DIR/bad-reg.rs:84:26
    |
 LL |         asm!("/* {} */", in(freg) d);
    |                          ^^^^^^^^^^
 
 error: register class `freg` requires at least one of the following target features: d, f
-  --> $DIR/bad-reg.rs:88:26
+  --> $DIR/bad-reg.rs:87:26
    |
 LL |         asm!("/* {} */", out(freg) d);
    |                          ^^^^^^^^^^^
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:95:27
+  --> $DIR/bad-reg.rs:94:27
    |
 LL |         asm!("", in("v0") x);
    |                           ^
@@ -91,7 +91,7 @@ LL |         asm!("", in("v0") x);
    = note: register class `vreg` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:98:28
+  --> $DIR/bad-reg.rs:97:28
    |
 LL |         asm!("", out("v0") x);
    |                            ^
@@ -99,7 +99,7 @@ LL |         asm!("", out("v0") x);
    = note: register class `vreg` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:101:35
+  --> $DIR/bad-reg.rs:100:35
    |
 LL |         asm!("/* {} */", in(vreg) x);
    |                                   ^
diff --git a/tests/ui/asm/riscv/bad-reg.rs b/tests/ui/asm/riscv/bad-reg.rs
index e2ff311851ba..0acf94c71994 100644
--- a/tests/ui/asm/riscv/bad-reg.rs
+++ b/tests/ui/asm/riscv/bad-reg.rs
@@ -1,5 +1,4 @@
 //@ add-core-stubs
-//@ needs-asm-support
 //@ revisions: riscv32i riscv32imafc riscv32gc riscv32e riscv64imac riscv64gc
 //@[riscv32i] compile-flags: --target riscv32i-unknown-none-elf
 //@[riscv32i] needs-llvm-components: riscv
diff --git a/tests/ui/asm/s390x/bad-reg.rs b/tests/ui/asm/s390x/bad-reg.rs
index 2915e874593e..274f4cd887c1 100644
--- a/tests/ui/asm/s390x/bad-reg.rs
+++ b/tests/ui/asm/s390x/bad-reg.rs
@@ -1,5 +1,4 @@
 //@ add-core-stubs
-//@ needs-asm-support
 //@ revisions: s390x s390x_vector s390x_vector_stable
 //@[s390x] compile-flags: --target s390x-unknown-linux-gnu -C target-feature=-vector
 //@[s390x] needs-llvm-components: systemz
diff --git a/tests/ui/asm/s390x/bad-reg.s390x.stderr b/tests/ui/asm/s390x/bad-reg.s390x.stderr
index c89d43defa39..238419b376b7 100644
--- a/tests/ui/asm/s390x/bad-reg.s390x.stderr
+++ b/tests/ui/asm/s390x/bad-reg.s390x.stderr
@@ -1,149 +1,149 @@
 error: invalid register `r11`: The frame pointer cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:32:18
+  --> $DIR/bad-reg.rs:31:18
    |
 LL |         asm!("", out("r11") _);
    |                  ^^^^^^^^^^^^
 
 error: invalid register `r15`: The stack pointer cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:34:18
+  --> $DIR/bad-reg.rs:33:18
    |
 LL |         asm!("", out("r15") _);
    |                  ^^^^^^^^^^^^
 
 error: invalid register `c0`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:36:18
+  --> $DIR/bad-reg.rs:35:18
    |
 LL |         asm!("", out("c0") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `c1`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:38:18
+  --> $DIR/bad-reg.rs:37:18
    |
 LL |         asm!("", out("c1") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `c2`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:40:18
+  --> $DIR/bad-reg.rs:39:18
    |
 LL |         asm!("", out("c2") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `c3`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:42:18
+  --> $DIR/bad-reg.rs:41:18
    |
 LL |         asm!("", out("c3") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `c4`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:44:18
+  --> $DIR/bad-reg.rs:43:18
    |
 LL |         asm!("", out("c4") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `c5`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:46:18
+  --> $DIR/bad-reg.rs:45:18
    |
 LL |         asm!("", out("c5") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `c6`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:48:18
+  --> $DIR/bad-reg.rs:47:18
    |
 LL |         asm!("", out("c6") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `c7`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:50:18
+  --> $DIR/bad-reg.rs:49:18
    |
 LL |         asm!("", out("c7") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `c8`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:52:18
+  --> $DIR/bad-reg.rs:51:18
    |
 LL |         asm!("", out("c8") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `c9`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:54:18
+  --> $DIR/bad-reg.rs:53:18
    |
 LL |         asm!("", out("c9") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `c10`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:56:18
+  --> $DIR/bad-reg.rs:55:18
    |
 LL |         asm!("", out("c10") _);
    |                  ^^^^^^^^^^^^
 
 error: invalid register `c11`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:58:18
+  --> $DIR/bad-reg.rs:57:18
    |
 LL |         asm!("", out("c11") _);
    |                  ^^^^^^^^^^^^
 
 error: invalid register `c12`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:60:18
+  --> $DIR/bad-reg.rs:59:18
    |
 LL |         asm!("", out("c12") _);
    |                  ^^^^^^^^^^^^
 
 error: invalid register `c13`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:62:18
+  --> $DIR/bad-reg.rs:61:18
    |
 LL |         asm!("", out("c13") _);
    |                  ^^^^^^^^^^^^
 
 error: invalid register `c14`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:64:18
+  --> $DIR/bad-reg.rs:63:18
    |
 LL |         asm!("", out("c14") _);
    |                  ^^^^^^^^^^^^
 
 error: invalid register `c15`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:66:18
+  --> $DIR/bad-reg.rs:65:18
    |
 LL |         asm!("", out("c15") _);
    |                  ^^^^^^^^^^^^
 
 error: invalid register `a0`: a0 and a1 are reserved for system use and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:68:18
+  --> $DIR/bad-reg.rs:67:18
    |
 LL |         asm!("", out("a0") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `a1`: a0 and a1 are reserved for system use and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:70:18
+  --> $DIR/bad-reg.rs:69:18
    |
 LL |         asm!("", out("a1") _);
    |                  ^^^^^^^^^^^
 
 error: register class `areg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:121:18
+  --> $DIR/bad-reg.rs:120:18
    |
 LL |         asm!("", in("a2") x);
    |                  ^^^^^^^^^^
 
 error: register class `areg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:124:18
+  --> $DIR/bad-reg.rs:123:18
    |
 LL |         asm!("", out("a2") x);
    |                  ^^^^^^^^^^^
 
 error: register class `areg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:127:26
+  --> $DIR/bad-reg.rs:126:26
    |
 LL |         asm!("/* {} */", in(areg) x);
    |                          ^^^^^^^^^^
 
 error: register class `areg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:130:26
+  --> $DIR/bad-reg.rs:129:26
    |
 LL |         asm!("/* {} */", out(areg) _);
    |                          ^^^^^^^^^^^
 
 error: register `f0` conflicts with register `v0`
-  --> $DIR/bad-reg.rs:135:31
+  --> $DIR/bad-reg.rs:134:31
    |
 LL |         asm!("", out("v0") _, out("f0") _);
    |                  -----------  ^^^^^^^^^^^ register `f0`
@@ -151,7 +151,7 @@ LL |         asm!("", out("v0") _, out("f0") _);
    |                  register `v0`
 
 error: register `f1` conflicts with register `v1`
-  --> $DIR/bad-reg.rs:137:31
+  --> $DIR/bad-reg.rs:136:31
    |
 LL |         asm!("", out("v1") _, out("f1") _);
    |                  -----------  ^^^^^^^^^^^ register `f1`
@@ -159,7 +159,7 @@ LL |         asm!("", out("v1") _, out("f1") _);
    |                  register `v1`
 
 error: register `f2` conflicts with register `v2`
-  --> $DIR/bad-reg.rs:139:31
+  --> $DIR/bad-reg.rs:138:31
    |
 LL |         asm!("", out("v2") _, out("f2") _);
    |                  -----------  ^^^^^^^^^^^ register `f2`
@@ -167,7 +167,7 @@ LL |         asm!("", out("v2") _, out("f2") _);
    |                  register `v2`
 
 error: register `f3` conflicts with register `v3`
-  --> $DIR/bad-reg.rs:141:31
+  --> $DIR/bad-reg.rs:140:31
    |
 LL |         asm!("", out("v3") _, out("f3") _);
    |                  -----------  ^^^^^^^^^^^ register `f3`
@@ -175,7 +175,7 @@ LL |         asm!("", out("v3") _, out("f3") _);
    |                  register `v3`
 
 error: register `f4` conflicts with register `v4`
-  --> $DIR/bad-reg.rs:143:31
+  --> $DIR/bad-reg.rs:142:31
    |
 LL |         asm!("", out("v4") _, out("f4") _);
    |                  -----------  ^^^^^^^^^^^ register `f4`
@@ -183,7 +183,7 @@ LL |         asm!("", out("v4") _, out("f4") _);
    |                  register `v4`
 
 error: register `f5` conflicts with register `v5`
-  --> $DIR/bad-reg.rs:145:31
+  --> $DIR/bad-reg.rs:144:31
    |
 LL |         asm!("", out("v5") _, out("f5") _);
    |                  -----------  ^^^^^^^^^^^ register `f5`
@@ -191,7 +191,7 @@ LL |         asm!("", out("v5") _, out("f5") _);
    |                  register `v5`
 
 error: register `f6` conflicts with register `v6`
-  --> $DIR/bad-reg.rs:147:31
+  --> $DIR/bad-reg.rs:146:31
    |
 LL |         asm!("", out("v6") _, out("f6") _);
    |                  -----------  ^^^^^^^^^^^ register `f6`
@@ -199,7 +199,7 @@ LL |         asm!("", out("v6") _, out("f6") _);
    |                  register `v6`
 
 error: register `f7` conflicts with register `v7`
-  --> $DIR/bad-reg.rs:149:31
+  --> $DIR/bad-reg.rs:148:31
    |
 LL |         asm!("", out("v7") _, out("f7") _);
    |                  -----------  ^^^^^^^^^^^ register `f7`
@@ -207,7 +207,7 @@ LL |         asm!("", out("v7") _, out("f7") _);
    |                  register `v7`
 
 error: register `f8` conflicts with register `v8`
-  --> $DIR/bad-reg.rs:151:31
+  --> $DIR/bad-reg.rs:150:31
    |
 LL |         asm!("", out("v8") _, out("f8") _);
    |                  -----------  ^^^^^^^^^^^ register `f8`
@@ -215,7 +215,7 @@ LL |         asm!("", out("v8") _, out("f8") _);
    |                  register `v8`
 
 error: register `f9` conflicts with register `v9`
-  --> $DIR/bad-reg.rs:153:31
+  --> $DIR/bad-reg.rs:152:31
    |
 LL |         asm!("", out("v9") _, out("f9") _);
    |                  -----------  ^^^^^^^^^^^ register `f9`
@@ -223,7 +223,7 @@ LL |         asm!("", out("v9") _, out("f9") _);
    |                  register `v9`
 
 error: register `f10` conflicts with register `v10`
-  --> $DIR/bad-reg.rs:155:32
+  --> $DIR/bad-reg.rs:154:32
    |
 LL |         asm!("", out("v10") _, out("f10") _);
    |                  ------------  ^^^^^^^^^^^^ register `f10`
@@ -231,7 +231,7 @@ LL |         asm!("", out("v10") _, out("f10") _);
    |                  register `v10`
 
 error: register `f11` conflicts with register `v11`
-  --> $DIR/bad-reg.rs:157:32
+  --> $DIR/bad-reg.rs:156:32
    |
 LL |         asm!("", out("v11") _, out("f11") _);
    |                  ------------  ^^^^^^^^^^^^ register `f11`
@@ -239,7 +239,7 @@ LL |         asm!("", out("v11") _, out("f11") _);
    |                  register `v11`
 
 error: register `f12` conflicts with register `v12`
-  --> $DIR/bad-reg.rs:159:32
+  --> $DIR/bad-reg.rs:158:32
    |
 LL |         asm!("", out("v12") _, out("f12") _);
    |                  ------------  ^^^^^^^^^^^^ register `f12`
@@ -247,7 +247,7 @@ LL |         asm!("", out("v12") _, out("f12") _);
    |                  register `v12`
 
 error: register `f13` conflicts with register `v13`
-  --> $DIR/bad-reg.rs:161:32
+  --> $DIR/bad-reg.rs:160:32
    |
 LL |         asm!("", out("v13") _, out("f13") _);
    |                  ------------  ^^^^^^^^^^^^ register `f13`
@@ -255,7 +255,7 @@ LL |         asm!("", out("v13") _, out("f13") _);
    |                  register `v13`
 
 error: register `f14` conflicts with register `v14`
-  --> $DIR/bad-reg.rs:163:32
+  --> $DIR/bad-reg.rs:162:32
    |
 LL |         asm!("", out("v14") _, out("f14") _);
    |                  ------------  ^^^^^^^^^^^^ register `f14`
@@ -263,7 +263,7 @@ LL |         asm!("", out("v14") _, out("f14") _);
    |                  register `v14`
 
 error: register `f15` conflicts with register `v15`
-  --> $DIR/bad-reg.rs:165:32
+  --> $DIR/bad-reg.rs:164:32
    |
 LL |         asm!("", out("v15") _, out("f15") _);
    |                  ------------  ^^^^^^^^^^^^ register `f15`
@@ -271,73 +271,73 @@ LL |         asm!("", out("v15") _, out("f15") _);
    |                  register `v15`
 
 error: invalid register `f16`: unknown register
-  --> $DIR/bad-reg.rs:168:32
+  --> $DIR/bad-reg.rs:167:32
    |
 LL |         asm!("", out("v16") _, out("f16") _);
    |                                ^^^^^^^^^^^^
 
 error: register class `vreg` requires the `vector` target feature
-  --> $DIR/bad-reg.rs:75:18
+  --> $DIR/bad-reg.rs:74:18
    |
 LL |         asm!("", in("v0") v); // requires vector & asm_experimental_reg
    |                  ^^^^^^^^^^
 
 error: register class `vreg` requires the `vector` target feature
-  --> $DIR/bad-reg.rs:79:18
+  --> $DIR/bad-reg.rs:78:18
    |
 LL |         asm!("", out("v0") v); // requires vector & asm_experimental_reg
    |                  ^^^^^^^^^^^
 
 error: register class `vreg` requires the `vector` target feature
-  --> $DIR/bad-reg.rs:83:18
+  --> $DIR/bad-reg.rs:82:18
    |
 LL |         asm!("", in("v0") x); // requires vector & asm_experimental_reg
    |                  ^^^^^^^^^^
 
 error: register class `vreg` requires the `vector` target feature
-  --> $DIR/bad-reg.rs:87:18
+  --> $DIR/bad-reg.rs:86:18
    |
 LL |         asm!("", out("v0") x); // requires vector & asm_experimental_reg
    |                  ^^^^^^^^^^^
 
 error: register class `vreg` requires the `vector` target feature
-  --> $DIR/bad-reg.rs:91:18
+  --> $DIR/bad-reg.rs:90:18
    |
 LL |         asm!("", in("v0") b);
    |                  ^^^^^^^^^^
 
 error: register class `vreg` requires the `vector` target feature
-  --> $DIR/bad-reg.rs:96:18
+  --> $DIR/bad-reg.rs:95:18
    |
 LL |         asm!("", out("v0") b);
    |                  ^^^^^^^^^^^
 
 error: register class `vreg` requires the `vector` target feature
-  --> $DIR/bad-reg.rs:101:26
+  --> $DIR/bad-reg.rs:100:26
    |
 LL |         asm!("/* {} */", in(vreg) v); // requires vector & asm_experimental_reg
    |                          ^^^^^^^^^^
 
 error: register class `vreg` requires the `vector` target feature
-  --> $DIR/bad-reg.rs:105:26
+  --> $DIR/bad-reg.rs:104:26
    |
 LL |         asm!("/* {} */", in(vreg) x); // requires vector & asm_experimental_reg
    |                          ^^^^^^^^^^
 
 error: register class `vreg` requires the `vector` target feature
-  --> $DIR/bad-reg.rs:109:26
+  --> $DIR/bad-reg.rs:108:26
    |
 LL |         asm!("/* {} */", in(vreg) b);
    |                          ^^^^^^^^^^
 
 error: register class `vreg` requires the `vector` target feature
-  --> $DIR/bad-reg.rs:114:26
+  --> $DIR/bad-reg.rs:113:26
    |
 LL |         asm!("/* {} */", out(vreg) _); // requires vector & asm_experimental_reg
    |                          ^^^^^^^^^^^
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:121:27
+  --> $DIR/bad-reg.rs:120:27
    |
 LL |         asm!("", in("a2") x);
    |                           ^
@@ -345,7 +345,7 @@ LL |         asm!("", in("a2") x);
    = note: register class `areg` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:124:28
+  --> $DIR/bad-reg.rs:123:28
    |
 LL |         asm!("", out("a2") x);
    |                            ^
@@ -353,7 +353,7 @@ LL |         asm!("", out("a2") x);
    = note: register class `areg` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:127:35
+  --> $DIR/bad-reg.rs:126:35
    |
 LL |         asm!("/* {} */", in(areg) x);
    |                                   ^
diff --git a/tests/ui/asm/s390x/bad-reg.s390x_vector.stderr b/tests/ui/asm/s390x/bad-reg.s390x_vector.stderr
index 3890e1442ccc..897f872ae72a 100644
--- a/tests/ui/asm/s390x/bad-reg.s390x_vector.stderr
+++ b/tests/ui/asm/s390x/bad-reg.s390x_vector.stderr
@@ -1,149 +1,149 @@
 error: invalid register `r11`: The frame pointer cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:32:18
+  --> $DIR/bad-reg.rs:31:18
    |
 LL |         asm!("", out("r11") _);
    |                  ^^^^^^^^^^^^
 
 error: invalid register `r15`: The stack pointer cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:34:18
+  --> $DIR/bad-reg.rs:33:18
    |
 LL |         asm!("", out("r15") _);
    |                  ^^^^^^^^^^^^
 
 error: invalid register `c0`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:36:18
+  --> $DIR/bad-reg.rs:35:18
    |
 LL |         asm!("", out("c0") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `c1`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:38:18
+  --> $DIR/bad-reg.rs:37:18
    |
 LL |         asm!("", out("c1") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `c2`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:40:18
+  --> $DIR/bad-reg.rs:39:18
    |
 LL |         asm!("", out("c2") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `c3`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:42:18
+  --> $DIR/bad-reg.rs:41:18
    |
 LL |         asm!("", out("c3") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `c4`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:44:18
+  --> $DIR/bad-reg.rs:43:18
    |
 LL |         asm!("", out("c4") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `c5`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:46:18
+  --> $DIR/bad-reg.rs:45:18
    |
 LL |         asm!("", out("c5") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `c6`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:48:18
+  --> $DIR/bad-reg.rs:47:18
    |
 LL |         asm!("", out("c6") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `c7`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:50:18
+  --> $DIR/bad-reg.rs:49:18
    |
 LL |         asm!("", out("c7") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `c8`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:52:18
+  --> $DIR/bad-reg.rs:51:18
    |
 LL |         asm!("", out("c8") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `c9`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:54:18
+  --> $DIR/bad-reg.rs:53:18
    |
 LL |         asm!("", out("c9") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `c10`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:56:18
+  --> $DIR/bad-reg.rs:55:18
    |
 LL |         asm!("", out("c10") _);
    |                  ^^^^^^^^^^^^
 
 error: invalid register `c11`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:58:18
+  --> $DIR/bad-reg.rs:57:18
    |
 LL |         asm!("", out("c11") _);
    |                  ^^^^^^^^^^^^
 
 error: invalid register `c12`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:60:18
+  --> $DIR/bad-reg.rs:59:18
    |
 LL |         asm!("", out("c12") _);
    |                  ^^^^^^^^^^^^
 
 error: invalid register `c13`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:62:18
+  --> $DIR/bad-reg.rs:61:18
    |
 LL |         asm!("", out("c13") _);
    |                  ^^^^^^^^^^^^
 
 error: invalid register `c14`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:64:18
+  --> $DIR/bad-reg.rs:63:18
    |
 LL |         asm!("", out("c14") _);
    |                  ^^^^^^^^^^^^
 
 error: invalid register `c15`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:66:18
+  --> $DIR/bad-reg.rs:65:18
    |
 LL |         asm!("", out("c15") _);
    |                  ^^^^^^^^^^^^
 
 error: invalid register `a0`: a0 and a1 are reserved for system use and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:68:18
+  --> $DIR/bad-reg.rs:67:18
    |
 LL |         asm!("", out("a0") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `a1`: a0 and a1 are reserved for system use and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:70:18
+  --> $DIR/bad-reg.rs:69:18
    |
 LL |         asm!("", out("a1") _);
    |                  ^^^^^^^^^^^
 
 error: register class `areg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:121:18
+  --> $DIR/bad-reg.rs:120:18
    |
 LL |         asm!("", in("a2") x);
    |                  ^^^^^^^^^^
 
 error: register class `areg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:124:18
+  --> $DIR/bad-reg.rs:123:18
    |
 LL |         asm!("", out("a2") x);
    |                  ^^^^^^^^^^^
 
 error: register class `areg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:127:26
+  --> $DIR/bad-reg.rs:126:26
    |
 LL |         asm!("/* {} */", in(areg) x);
    |                          ^^^^^^^^^^
 
 error: register class `areg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:130:26
+  --> $DIR/bad-reg.rs:129:26
    |
 LL |         asm!("/* {} */", out(areg) _);
    |                          ^^^^^^^^^^^
 
 error: register `f0` conflicts with register `v0`
-  --> $DIR/bad-reg.rs:135:31
+  --> $DIR/bad-reg.rs:134:31
    |
 LL |         asm!("", out("v0") _, out("f0") _);
    |                  -----------  ^^^^^^^^^^^ register `f0`
@@ -151,7 +151,7 @@ LL |         asm!("", out("v0") _, out("f0") _);
    |                  register `v0`
 
 error: register `f1` conflicts with register `v1`
-  --> $DIR/bad-reg.rs:137:31
+  --> $DIR/bad-reg.rs:136:31
    |
 LL |         asm!("", out("v1") _, out("f1") _);
    |                  -----------  ^^^^^^^^^^^ register `f1`
@@ -159,7 +159,7 @@ LL |         asm!("", out("v1") _, out("f1") _);
    |                  register `v1`
 
 error: register `f2` conflicts with register `v2`
-  --> $DIR/bad-reg.rs:139:31
+  --> $DIR/bad-reg.rs:138:31
    |
 LL |         asm!("", out("v2") _, out("f2") _);
    |                  -----------  ^^^^^^^^^^^ register `f2`
@@ -167,7 +167,7 @@ LL |         asm!("", out("v2") _, out("f2") _);
    |                  register `v2`
 
 error: register `f3` conflicts with register `v3`
-  --> $DIR/bad-reg.rs:141:31
+  --> $DIR/bad-reg.rs:140:31
    |
 LL |         asm!("", out("v3") _, out("f3") _);
    |                  -----------  ^^^^^^^^^^^ register `f3`
@@ -175,7 +175,7 @@ LL |         asm!("", out("v3") _, out("f3") _);
    |                  register `v3`
 
 error: register `f4` conflicts with register `v4`
-  --> $DIR/bad-reg.rs:143:31
+  --> $DIR/bad-reg.rs:142:31
    |
 LL |         asm!("", out("v4") _, out("f4") _);
    |                  -----------  ^^^^^^^^^^^ register `f4`
@@ -183,7 +183,7 @@ LL |         asm!("", out("v4") _, out("f4") _);
    |                  register `v4`
 
 error: register `f5` conflicts with register `v5`
-  --> $DIR/bad-reg.rs:145:31
+  --> $DIR/bad-reg.rs:144:31
    |
 LL |         asm!("", out("v5") _, out("f5") _);
    |                  -----------  ^^^^^^^^^^^ register `f5`
@@ -191,7 +191,7 @@ LL |         asm!("", out("v5") _, out("f5") _);
    |                  register `v5`
 
 error: register `f6` conflicts with register `v6`
-  --> $DIR/bad-reg.rs:147:31
+  --> $DIR/bad-reg.rs:146:31
    |
 LL |         asm!("", out("v6") _, out("f6") _);
    |                  -----------  ^^^^^^^^^^^ register `f6`
@@ -199,7 +199,7 @@ LL |         asm!("", out("v6") _, out("f6") _);
    |                  register `v6`
 
 error: register `f7` conflicts with register `v7`
-  --> $DIR/bad-reg.rs:149:31
+  --> $DIR/bad-reg.rs:148:31
    |
 LL |         asm!("", out("v7") _, out("f7") _);
    |                  -----------  ^^^^^^^^^^^ register `f7`
@@ -207,7 +207,7 @@ LL |         asm!("", out("v7") _, out("f7") _);
    |                  register `v7`
 
 error: register `f8` conflicts with register `v8`
-  --> $DIR/bad-reg.rs:151:31
+  --> $DIR/bad-reg.rs:150:31
    |
 LL |         asm!("", out("v8") _, out("f8") _);
    |                  -----------  ^^^^^^^^^^^ register `f8`
@@ -215,7 +215,7 @@ LL |         asm!("", out("v8") _, out("f8") _);
    |                  register `v8`
 
 error: register `f9` conflicts with register `v9`
-  --> $DIR/bad-reg.rs:153:31
+  --> $DIR/bad-reg.rs:152:31
    |
 LL |         asm!("", out("v9") _, out("f9") _);
    |                  -----------  ^^^^^^^^^^^ register `f9`
@@ -223,7 +223,7 @@ LL |         asm!("", out("v9") _, out("f9") _);
    |                  register `v9`
 
 error: register `f10` conflicts with register `v10`
-  --> $DIR/bad-reg.rs:155:32
+  --> $DIR/bad-reg.rs:154:32
    |
 LL |         asm!("", out("v10") _, out("f10") _);
    |                  ------------  ^^^^^^^^^^^^ register `f10`
@@ -231,7 +231,7 @@ LL |         asm!("", out("v10") _, out("f10") _);
    |                  register `v10`
 
 error: register `f11` conflicts with register `v11`
-  --> $DIR/bad-reg.rs:157:32
+  --> $DIR/bad-reg.rs:156:32
    |
 LL |         asm!("", out("v11") _, out("f11") _);
    |                  ------------  ^^^^^^^^^^^^ register `f11`
@@ -239,7 +239,7 @@ LL |         asm!("", out("v11") _, out("f11") _);
    |                  register `v11`
 
 error: register `f12` conflicts with register `v12`
-  --> $DIR/bad-reg.rs:159:32
+  --> $DIR/bad-reg.rs:158:32
    |
 LL |         asm!("", out("v12") _, out("f12") _);
    |                  ------------  ^^^^^^^^^^^^ register `f12`
@@ -247,7 +247,7 @@ LL |         asm!("", out("v12") _, out("f12") _);
    |                  register `v12`
 
 error: register `f13` conflicts with register `v13`
-  --> $DIR/bad-reg.rs:161:32
+  --> $DIR/bad-reg.rs:160:32
    |
 LL |         asm!("", out("v13") _, out("f13") _);
    |                  ------------  ^^^^^^^^^^^^ register `f13`
@@ -255,7 +255,7 @@ LL |         asm!("", out("v13") _, out("f13") _);
    |                  register `v13`
 
 error: register `f14` conflicts with register `v14`
-  --> $DIR/bad-reg.rs:163:32
+  --> $DIR/bad-reg.rs:162:32
    |
 LL |         asm!("", out("v14") _, out("f14") _);
    |                  ------------  ^^^^^^^^^^^^ register `f14`
@@ -263,7 +263,7 @@ LL |         asm!("", out("v14") _, out("f14") _);
    |                  register `v14`
 
 error: register `f15` conflicts with register `v15`
-  --> $DIR/bad-reg.rs:165:32
+  --> $DIR/bad-reg.rs:164:32
    |
 LL |         asm!("", out("v15") _, out("f15") _);
    |                  ------------  ^^^^^^^^^^^^ register `f15`
@@ -271,13 +271,13 @@ LL |         asm!("", out("v15") _, out("f15") _);
    |                  register `v15`
 
 error: invalid register `f16`: unknown register
-  --> $DIR/bad-reg.rs:168:32
+  --> $DIR/bad-reg.rs:167:32
    |
 LL |         asm!("", out("v16") _, out("f16") _);
    |                                ^^^^^^^^^^^^
 
 error: type `u8` cannot be used with this register class
-  --> $DIR/bad-reg.rs:91:27
+  --> $DIR/bad-reg.rs:90:27
    |
 LL |         asm!("", in("v0") b);
    |                           ^
@@ -285,7 +285,7 @@ LL |         asm!("", in("v0") b);
    = note: register class `vreg` supports these types: i32, f32, i64, f64, i128, f128, i8x16, i16x8, i32x4, i64x2, f32x4, f64x2
 
 error: type `u8` cannot be used with this register class
-  --> $DIR/bad-reg.rs:96:28
+  --> $DIR/bad-reg.rs:95:28
    |
 LL |         asm!("", out("v0") b);
    |                            ^
@@ -293,7 +293,7 @@ LL |         asm!("", out("v0") b);
    = note: register class `vreg` supports these types: i32, f32, i64, f64, i128, f128, i8x16, i16x8, i32x4, i64x2, f32x4, f64x2
 
 error: type `u8` cannot be used with this register class
-  --> $DIR/bad-reg.rs:109:35
+  --> $DIR/bad-reg.rs:108:35
    |
 LL |         asm!("/* {} */", in(vreg) b);
    |                                   ^
@@ -301,7 +301,7 @@ LL |         asm!("/* {} */", in(vreg) b);
    = note: register class `vreg` supports these types: i32, f32, i64, f64, i128, f128, i8x16, i16x8, i32x4, i64x2, f32x4, f64x2
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:121:27
+  --> $DIR/bad-reg.rs:120:27
    |
 LL |         asm!("", in("a2") x);
    |                           ^
@@ -309,7 +309,7 @@ LL |         asm!("", in("a2") x);
    = note: register class `areg` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:124:28
+  --> $DIR/bad-reg.rs:123:28
    |
 LL |         asm!("", out("a2") x);
    |                            ^
@@ -317,7 +317,7 @@ LL |         asm!("", out("a2") x);
    = note: register class `areg` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:127:35
+  --> $DIR/bad-reg.rs:126:35
    |
 LL |         asm!("/* {} */", in(areg) x);
    |                                   ^
diff --git a/tests/ui/asm/s390x/bad-reg.s390x_vector_stable.stderr b/tests/ui/asm/s390x/bad-reg.s390x_vector_stable.stderr
index 20d129ebb387..e2b3eeef4e92 100644
--- a/tests/ui/asm/s390x/bad-reg.s390x_vector_stable.stderr
+++ b/tests/ui/asm/s390x/bad-reg.s390x_vector_stable.stderr
@@ -1,125 +1,125 @@
 error: invalid register `r11`: The frame pointer cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:32:18
+  --> $DIR/bad-reg.rs:31:18
    |
 LL |         asm!("", out("r11") _);
    |                  ^^^^^^^^^^^^
 
 error: invalid register `r15`: The stack pointer cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:34:18
+  --> $DIR/bad-reg.rs:33:18
    |
 LL |         asm!("", out("r15") _);
    |                  ^^^^^^^^^^^^
 
 error: invalid register `c0`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:36:18
+  --> $DIR/bad-reg.rs:35:18
    |
 LL |         asm!("", out("c0") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `c1`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:38:18
+  --> $DIR/bad-reg.rs:37:18
    |
 LL |         asm!("", out("c1") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `c2`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:40:18
+  --> $DIR/bad-reg.rs:39:18
    |
 LL |         asm!("", out("c2") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `c3`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:42:18
+  --> $DIR/bad-reg.rs:41:18
    |
 LL |         asm!("", out("c3") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `c4`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:44:18
+  --> $DIR/bad-reg.rs:43:18
    |
 LL |         asm!("", out("c4") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `c5`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:46:18
+  --> $DIR/bad-reg.rs:45:18
    |
 LL |         asm!("", out("c5") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `c6`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:48:18
+  --> $DIR/bad-reg.rs:47:18
    |
 LL |         asm!("", out("c6") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `c7`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:50:18
+  --> $DIR/bad-reg.rs:49:18
    |
 LL |         asm!("", out("c7") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `c8`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:52:18
+  --> $DIR/bad-reg.rs:51:18
    |
 LL |         asm!("", out("c8") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `c9`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:54:18
+  --> $DIR/bad-reg.rs:53:18
    |
 LL |         asm!("", out("c9") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `c10`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:56:18
+  --> $DIR/bad-reg.rs:55:18
    |
 LL |         asm!("", out("c10") _);
    |                  ^^^^^^^^^^^^
 
 error: invalid register `c11`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:58:18
+  --> $DIR/bad-reg.rs:57:18
    |
 LL |         asm!("", out("c11") _);
    |                  ^^^^^^^^^^^^
 
 error: invalid register `c12`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:60:18
+  --> $DIR/bad-reg.rs:59:18
    |
 LL |         asm!("", out("c12") _);
    |                  ^^^^^^^^^^^^
 
 error: invalid register `c13`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:62:18
+  --> $DIR/bad-reg.rs:61:18
    |
 LL |         asm!("", out("c13") _);
    |                  ^^^^^^^^^^^^
 
 error: invalid register `c14`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:64:18
+  --> $DIR/bad-reg.rs:63:18
    |
 LL |         asm!("", out("c14") _);
    |                  ^^^^^^^^^^^^
 
 error: invalid register `c15`: control registers are reserved by the kernel and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:66:18
+  --> $DIR/bad-reg.rs:65:18
    |
 LL |         asm!("", out("c15") _);
    |                  ^^^^^^^^^^^^
 
 error: invalid register `a0`: a0 and a1 are reserved for system use and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:68:18
+  --> $DIR/bad-reg.rs:67:18
    |
 LL |         asm!("", out("a0") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `a1`: a0 and a1 are reserved for system use and cannot be used as operands for inline asm
-  --> $DIR/bad-reg.rs:70:18
+  --> $DIR/bad-reg.rs:69:18
    |
 LL |         asm!("", out("a1") _);
    |                  ^^^^^^^^^^^
 
 error[E0658]: register class `vreg` can only be used as a clobber in stable
-  --> $DIR/bad-reg.rs:75:18
+  --> $DIR/bad-reg.rs:74:18
    |
 LL |         asm!("", in("v0") v); // requires vector & asm_experimental_reg
    |                  ^^^^^^^^^^
@@ -129,7 +129,7 @@ LL |         asm!("", in("v0") v); // requires vector & asm_experimental_reg
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: register class `vreg` can only be used as a clobber in stable
-  --> $DIR/bad-reg.rs:79:18
+  --> $DIR/bad-reg.rs:78:18
    |
 LL |         asm!("", out("v0") v); // requires vector & asm_experimental_reg
    |                  ^^^^^^^^^^^
@@ -139,7 +139,7 @@ LL |         asm!("", out("v0") v); // requires vector & asm_experimental_reg
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: register class `vreg` can only be used as a clobber in stable
-  --> $DIR/bad-reg.rs:83:18
+  --> $DIR/bad-reg.rs:82:18
    |
 LL |         asm!("", in("v0") x); // requires vector & asm_experimental_reg
    |                  ^^^^^^^^^^
@@ -149,7 +149,7 @@ LL |         asm!("", in("v0") x); // requires vector & asm_experimental_reg
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: register class `vreg` can only be used as a clobber in stable
-  --> $DIR/bad-reg.rs:87:18
+  --> $DIR/bad-reg.rs:86:18
    |
 LL |         asm!("", out("v0") x); // requires vector & asm_experimental_reg
    |                  ^^^^^^^^^^^
@@ -159,7 +159,7 @@ LL |         asm!("", out("v0") x); // requires vector & asm_experimental_reg
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: register class `vreg` can only be used as a clobber in stable
-  --> $DIR/bad-reg.rs:91:18
+  --> $DIR/bad-reg.rs:90:18
    |
 LL |         asm!("", in("v0") b);
    |                  ^^^^^^^^^^
@@ -169,7 +169,7 @@ LL |         asm!("", in("v0") b);
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: register class `vreg` can only be used as a clobber in stable
-  --> $DIR/bad-reg.rs:96:18
+  --> $DIR/bad-reg.rs:95:18
    |
 LL |         asm!("", out("v0") b);
    |                  ^^^^^^^^^^^
@@ -179,7 +179,7 @@ LL |         asm!("", out("v0") b);
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: register class `vreg` can only be used as a clobber in stable
-  --> $DIR/bad-reg.rs:101:26
+  --> $DIR/bad-reg.rs:100:26
    |
 LL |         asm!("/* {} */", in(vreg) v); // requires vector & asm_experimental_reg
    |                          ^^^^^^^^^^
@@ -189,7 +189,7 @@ LL |         asm!("/* {} */", in(vreg) v); // requires vector & asm_experimental
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: register class `vreg` can only be used as a clobber in stable
-  --> $DIR/bad-reg.rs:105:26
+  --> $DIR/bad-reg.rs:104:26
    |
 LL |         asm!("/* {} */", in(vreg) x); // requires vector & asm_experimental_reg
    |                          ^^^^^^^^^^
@@ -199,7 +199,7 @@ LL |         asm!("/* {} */", in(vreg) x); // requires vector & asm_experimental
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: register class `vreg` can only be used as a clobber in stable
-  --> $DIR/bad-reg.rs:109:26
+  --> $DIR/bad-reg.rs:108:26
    |
 LL |         asm!("/* {} */", in(vreg) b);
    |                          ^^^^^^^^^^
@@ -209,7 +209,7 @@ LL |         asm!("/* {} */", in(vreg) b);
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: register class `vreg` can only be used as a clobber in stable
-  --> $DIR/bad-reg.rs:114:26
+  --> $DIR/bad-reg.rs:113:26
    |
 LL |         asm!("/* {} */", out(vreg) _); // requires vector & asm_experimental_reg
    |                          ^^^^^^^^^^^
@@ -219,31 +219,31 @@ LL |         asm!("/* {} */", out(vreg) _); // requires vector & asm_experimenta
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error: register class `areg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:121:18
+  --> $DIR/bad-reg.rs:120:18
    |
 LL |         asm!("", in("a2") x);
    |                  ^^^^^^^^^^
 
 error: register class `areg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:124:18
+  --> $DIR/bad-reg.rs:123:18
    |
 LL |         asm!("", out("a2") x);
    |                  ^^^^^^^^^^^
 
 error: register class `areg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:127:26
+  --> $DIR/bad-reg.rs:126:26
    |
 LL |         asm!("/* {} */", in(areg) x);
    |                          ^^^^^^^^^^
 
 error: register class `areg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:130:26
+  --> $DIR/bad-reg.rs:129:26
    |
 LL |         asm!("/* {} */", out(areg) _);
    |                          ^^^^^^^^^^^
 
 error: register `f0` conflicts with register `v0`
-  --> $DIR/bad-reg.rs:135:31
+  --> $DIR/bad-reg.rs:134:31
    |
 LL |         asm!("", out("v0") _, out("f0") _);
    |                  -----------  ^^^^^^^^^^^ register `f0`
@@ -251,7 +251,7 @@ LL |         asm!("", out("v0") _, out("f0") _);
    |                  register `v0`
 
 error: register `f1` conflicts with register `v1`
-  --> $DIR/bad-reg.rs:137:31
+  --> $DIR/bad-reg.rs:136:31
    |
 LL |         asm!("", out("v1") _, out("f1") _);
    |                  -----------  ^^^^^^^^^^^ register `f1`
@@ -259,7 +259,7 @@ LL |         asm!("", out("v1") _, out("f1") _);
    |                  register `v1`
 
 error: register `f2` conflicts with register `v2`
-  --> $DIR/bad-reg.rs:139:31
+  --> $DIR/bad-reg.rs:138:31
    |
 LL |         asm!("", out("v2") _, out("f2") _);
    |                  -----------  ^^^^^^^^^^^ register `f2`
@@ -267,7 +267,7 @@ LL |         asm!("", out("v2") _, out("f2") _);
    |                  register `v2`
 
 error: register `f3` conflicts with register `v3`
-  --> $DIR/bad-reg.rs:141:31
+  --> $DIR/bad-reg.rs:140:31
    |
 LL |         asm!("", out("v3") _, out("f3") _);
    |                  -----------  ^^^^^^^^^^^ register `f3`
@@ -275,7 +275,7 @@ LL |         asm!("", out("v3") _, out("f3") _);
    |                  register `v3`
 
 error: register `f4` conflicts with register `v4`
-  --> $DIR/bad-reg.rs:143:31
+  --> $DIR/bad-reg.rs:142:31
    |
 LL |         asm!("", out("v4") _, out("f4") _);
    |                  -----------  ^^^^^^^^^^^ register `f4`
@@ -283,7 +283,7 @@ LL |         asm!("", out("v4") _, out("f4") _);
    |                  register `v4`
 
 error: register `f5` conflicts with register `v5`
-  --> $DIR/bad-reg.rs:145:31
+  --> $DIR/bad-reg.rs:144:31
    |
 LL |         asm!("", out("v5") _, out("f5") _);
    |                  -----------  ^^^^^^^^^^^ register `f5`
@@ -291,7 +291,7 @@ LL |         asm!("", out("v5") _, out("f5") _);
    |                  register `v5`
 
 error: register `f6` conflicts with register `v6`
-  --> $DIR/bad-reg.rs:147:31
+  --> $DIR/bad-reg.rs:146:31
    |
 LL |         asm!("", out("v6") _, out("f6") _);
    |                  -----------  ^^^^^^^^^^^ register `f6`
@@ -299,7 +299,7 @@ LL |         asm!("", out("v6") _, out("f6") _);
    |                  register `v6`
 
 error: register `f7` conflicts with register `v7`
-  --> $DIR/bad-reg.rs:149:31
+  --> $DIR/bad-reg.rs:148:31
    |
 LL |         asm!("", out("v7") _, out("f7") _);
    |                  -----------  ^^^^^^^^^^^ register `f7`
@@ -307,7 +307,7 @@ LL |         asm!("", out("v7") _, out("f7") _);
    |                  register `v7`
 
 error: register `f8` conflicts with register `v8`
-  --> $DIR/bad-reg.rs:151:31
+  --> $DIR/bad-reg.rs:150:31
    |
 LL |         asm!("", out("v8") _, out("f8") _);
    |                  -----------  ^^^^^^^^^^^ register `f8`
@@ -315,7 +315,7 @@ LL |         asm!("", out("v8") _, out("f8") _);
    |                  register `v8`
 
 error: register `f9` conflicts with register `v9`
-  --> $DIR/bad-reg.rs:153:31
+  --> $DIR/bad-reg.rs:152:31
    |
 LL |         asm!("", out("v9") _, out("f9") _);
    |                  -----------  ^^^^^^^^^^^ register `f9`
@@ -323,7 +323,7 @@ LL |         asm!("", out("v9") _, out("f9") _);
    |                  register `v9`
 
 error: register `f10` conflicts with register `v10`
-  --> $DIR/bad-reg.rs:155:32
+  --> $DIR/bad-reg.rs:154:32
    |
 LL |         asm!("", out("v10") _, out("f10") _);
    |                  ------------  ^^^^^^^^^^^^ register `f10`
@@ -331,7 +331,7 @@ LL |         asm!("", out("v10") _, out("f10") _);
    |                  register `v10`
 
 error: register `f11` conflicts with register `v11`
-  --> $DIR/bad-reg.rs:157:32
+  --> $DIR/bad-reg.rs:156:32
    |
 LL |         asm!("", out("v11") _, out("f11") _);
    |                  ------------  ^^^^^^^^^^^^ register `f11`
@@ -339,7 +339,7 @@ LL |         asm!("", out("v11") _, out("f11") _);
    |                  register `v11`
 
 error: register `f12` conflicts with register `v12`
-  --> $DIR/bad-reg.rs:159:32
+  --> $DIR/bad-reg.rs:158:32
    |
 LL |         asm!("", out("v12") _, out("f12") _);
    |                  ------------  ^^^^^^^^^^^^ register `f12`
@@ -347,7 +347,7 @@ LL |         asm!("", out("v12") _, out("f12") _);
    |                  register `v12`
 
 error: register `f13` conflicts with register `v13`
-  --> $DIR/bad-reg.rs:161:32
+  --> $DIR/bad-reg.rs:160:32
    |
 LL |         asm!("", out("v13") _, out("f13") _);
    |                  ------------  ^^^^^^^^^^^^ register `f13`
@@ -355,7 +355,7 @@ LL |         asm!("", out("v13") _, out("f13") _);
    |                  register `v13`
 
 error: register `f14` conflicts with register `v14`
-  --> $DIR/bad-reg.rs:163:32
+  --> $DIR/bad-reg.rs:162:32
    |
 LL |         asm!("", out("v14") _, out("f14") _);
    |                  ------------  ^^^^^^^^^^^^ register `f14`
@@ -363,7 +363,7 @@ LL |         asm!("", out("v14") _, out("f14") _);
    |                  register `v14`
 
 error: register `f15` conflicts with register `v15`
-  --> $DIR/bad-reg.rs:165:32
+  --> $DIR/bad-reg.rs:164:32
    |
 LL |         asm!("", out("v15") _, out("f15") _);
    |                  ------------  ^^^^^^^^^^^^ register `f15`
@@ -371,13 +371,13 @@ LL |         asm!("", out("v15") _, out("f15") _);
    |                  register `v15`
 
 error: invalid register `f16`: unknown register
-  --> $DIR/bad-reg.rs:168:32
+  --> $DIR/bad-reg.rs:167:32
    |
 LL |         asm!("", out("v16") _, out("f16") _);
    |                                ^^^^^^^^^^^^
 
 error[E0658]: type `i64x2` cannot be used with this register class in stable
-  --> $DIR/bad-reg.rs:75:27
+  --> $DIR/bad-reg.rs:74:27
    |
 LL |         asm!("", in("v0") v); // requires vector & asm_experimental_reg
    |                           ^
@@ -387,7 +387,7 @@ LL |         asm!("", in("v0") v); // requires vector & asm_experimental_reg
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: type `i64x2` cannot be used with this register class in stable
-  --> $DIR/bad-reg.rs:79:28
+  --> $DIR/bad-reg.rs:78:28
    |
 LL |         asm!("", out("v0") v); // requires vector & asm_experimental_reg
    |                            ^
@@ -397,7 +397,7 @@ LL |         asm!("", out("v0") v); // requires vector & asm_experimental_reg
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: type `i32` cannot be used with this register class in stable
-  --> $DIR/bad-reg.rs:83:27
+  --> $DIR/bad-reg.rs:82:27
    |
 LL |         asm!("", in("v0") x); // requires vector & asm_experimental_reg
    |                           ^
@@ -407,7 +407,7 @@ LL |         asm!("", in("v0") x); // requires vector & asm_experimental_reg
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: type `i32` cannot be used with this register class in stable
-  --> $DIR/bad-reg.rs:87:28
+  --> $DIR/bad-reg.rs:86:28
    |
 LL |         asm!("", out("v0") x); // requires vector & asm_experimental_reg
    |                            ^
@@ -417,7 +417,7 @@ LL |         asm!("", out("v0") x); // requires vector & asm_experimental_reg
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error: type `u8` cannot be used with this register class
-  --> $DIR/bad-reg.rs:91:27
+  --> $DIR/bad-reg.rs:90:27
    |
 LL |         asm!("", in("v0") b);
    |                           ^
@@ -425,7 +425,7 @@ LL |         asm!("", in("v0") b);
    = note: register class `vreg` supports these types: 
 
 error: type `u8` cannot be used with this register class
-  --> $DIR/bad-reg.rs:96:28
+  --> $DIR/bad-reg.rs:95:28
    |
 LL |         asm!("", out("v0") b);
    |                            ^
@@ -433,7 +433,7 @@ LL |         asm!("", out("v0") b);
    = note: register class `vreg` supports these types: 
 
 error[E0658]: type `i64x2` cannot be used with this register class in stable
-  --> $DIR/bad-reg.rs:101:35
+  --> $DIR/bad-reg.rs:100:35
    |
 LL |         asm!("/* {} */", in(vreg) v); // requires vector & asm_experimental_reg
    |                                   ^
@@ -443,7 +443,7 @@ LL |         asm!("/* {} */", in(vreg) v); // requires vector & asm_experimental
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: type `i32` cannot be used with this register class in stable
-  --> $DIR/bad-reg.rs:105:35
+  --> $DIR/bad-reg.rs:104:35
    |
 LL |         asm!("/* {} */", in(vreg) x); // requires vector & asm_experimental_reg
    |                                   ^
@@ -453,7 +453,7 @@ LL |         asm!("/* {} */", in(vreg) x); // requires vector & asm_experimental
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error: type `u8` cannot be used with this register class
-  --> $DIR/bad-reg.rs:109:35
+  --> $DIR/bad-reg.rs:108:35
    |
 LL |         asm!("/* {} */", in(vreg) b);
    |                                   ^
@@ -461,7 +461,7 @@ LL |         asm!("/* {} */", in(vreg) b);
    = note: register class `vreg` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:121:27
+  --> $DIR/bad-reg.rs:120:27
    |
 LL |         asm!("", in("a2") x);
    |                           ^
@@ -469,7 +469,7 @@ LL |         asm!("", in("a2") x);
    = note: register class `areg` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:124:28
+  --> $DIR/bad-reg.rs:123:28
    |
 LL |         asm!("", out("a2") x);
    |                            ^
@@ -477,7 +477,7 @@ LL |         asm!("", out("a2") x);
    = note: register class `areg` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:127:35
+  --> $DIR/bad-reg.rs:126:35
    |
 LL |         asm!("/* {} */", in(areg) x);
    |                                   ^
diff --git a/tests/ui/asm/sparc/bad-reg.rs b/tests/ui/asm/sparc/bad-reg.rs
index 8b6fdc422120..82ac1ebb7afa 100644
--- a/tests/ui/asm/sparc/bad-reg.rs
+++ b/tests/ui/asm/sparc/bad-reg.rs
@@ -6,7 +6,6 @@
 //@[sparcv8plus] needs-llvm-components: sparc
 //@[sparc64] compile-flags: --target sparc64-unknown-linux-gnu
 //@[sparc64] needs-llvm-components: sparc
-//@ needs-asm-support
 //@ ignore-backends: gcc
 
 #![crate_type = "rlib"]
diff --git a/tests/ui/asm/sparc/bad-reg.sparc.stderr b/tests/ui/asm/sparc/bad-reg.sparc.stderr
index 84e56871ecc2..e0580ad3232f 100644
--- a/tests/ui/asm/sparc/bad-reg.sparc.stderr
+++ b/tests/ui/asm/sparc/bad-reg.sparc.stderr
@@ -1,77 +1,77 @@
 error: invalid register `g0`: g0 is always zero and cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:23:18
+  --> $DIR/bad-reg.rs:22:18
    |
 LL |         asm!("", out("g0") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `g1`: reserved by LLVM and cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:26:18
+  --> $DIR/bad-reg.rs:25:18
    |
 LL |         asm!("", out("g1") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `g6`: reserved for system and cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:33:18
+  --> $DIR/bad-reg.rs:32:18
    |
 LL |         asm!("", out("g6") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `g7`: reserved for system and cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:35:18
+  --> $DIR/bad-reg.rs:34:18
    |
 LL |         asm!("", out("g7") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `sp`: the stack pointer cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:37:18
+  --> $DIR/bad-reg.rs:36:18
    |
 LL |         asm!("", out("sp") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `fp`: the frame pointer cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:39:18
+  --> $DIR/bad-reg.rs:38:18
    |
 LL |         asm!("", out("fp") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `i7`: the return address register cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:41:18
+  --> $DIR/bad-reg.rs:40:18
    |
 LL |         asm!("", out("i7") _);
    |                  ^^^^^^^^^^^
 
 error: register class `yreg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:47:18
+  --> $DIR/bad-reg.rs:46:18
    |
 LL |         asm!("", in("y") x);
    |                  ^^^^^^^^^
 
 error: register class `yreg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:50:18
+  --> $DIR/bad-reg.rs:49:18
    |
 LL |         asm!("", out("y") x);
    |                  ^^^^^^^^^^
 
 error: register class `yreg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:53:26
+  --> $DIR/bad-reg.rs:52:26
    |
 LL |         asm!("/* {} */", in(yreg) x);
    |                          ^^^^^^^^^^
 
 error: register class `yreg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:56:26
+  --> $DIR/bad-reg.rs:55:26
    |
 LL |         asm!("/* {} */", out(yreg) _);
    |                          ^^^^^^^^^^^
 
 error: cannot use register `r5`: g5 is reserved for system on SPARC32
-  --> $DIR/bad-reg.rs:31:18
+  --> $DIR/bad-reg.rs:30:18
    |
 LL |         asm!("", out("g5") _);
    |                  ^^^^^^^^^^^
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:47:26
+  --> $DIR/bad-reg.rs:46:26
    |
 LL |         asm!("", in("y") x);
    |                          ^
@@ -79,7 +79,7 @@ LL |         asm!("", in("y") x);
    = note: register class `yreg` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:50:27
+  --> $DIR/bad-reg.rs:49:27
    |
 LL |         asm!("", out("y") x);
    |                           ^
@@ -87,7 +87,7 @@ LL |         asm!("", out("y") x);
    = note: register class `yreg` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:53:35
+  --> $DIR/bad-reg.rs:52:35
    |
 LL |         asm!("/* {} */", in(yreg) x);
    |                                   ^
diff --git a/tests/ui/asm/sparc/bad-reg.sparc64.stderr b/tests/ui/asm/sparc/bad-reg.sparc64.stderr
index 4822eeab00c1..bdeb8c328db6 100644
--- a/tests/ui/asm/sparc/bad-reg.sparc64.stderr
+++ b/tests/ui/asm/sparc/bad-reg.sparc64.stderr
@@ -1,71 +1,71 @@
 error: invalid register `g0`: g0 is always zero and cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:23:18
+  --> $DIR/bad-reg.rs:22:18
    |
 LL |         asm!("", out("g0") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `g1`: reserved by LLVM and cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:26:18
+  --> $DIR/bad-reg.rs:25:18
    |
 LL |         asm!("", out("g1") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `g6`: reserved for system and cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:33:18
+  --> $DIR/bad-reg.rs:32:18
    |
 LL |         asm!("", out("g6") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `g7`: reserved for system and cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:35:18
+  --> $DIR/bad-reg.rs:34:18
    |
 LL |         asm!("", out("g7") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `sp`: the stack pointer cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:37:18
+  --> $DIR/bad-reg.rs:36:18
    |
 LL |         asm!("", out("sp") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `fp`: the frame pointer cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:39:18
+  --> $DIR/bad-reg.rs:38:18
    |
 LL |         asm!("", out("fp") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `i7`: the return address register cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:41:18
+  --> $DIR/bad-reg.rs:40:18
    |
 LL |         asm!("", out("i7") _);
    |                  ^^^^^^^^^^^
 
 error: register class `yreg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:47:18
+  --> $DIR/bad-reg.rs:46:18
    |
 LL |         asm!("", in("y") x);
    |                  ^^^^^^^^^
 
 error: register class `yreg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:50:18
+  --> $DIR/bad-reg.rs:49:18
    |
 LL |         asm!("", out("y") x);
    |                  ^^^^^^^^^^
 
 error: register class `yreg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:53:26
+  --> $DIR/bad-reg.rs:52:26
    |
 LL |         asm!("/* {} */", in(yreg) x);
    |                          ^^^^^^^^^^
 
 error: register class `yreg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:56:26
+  --> $DIR/bad-reg.rs:55:26
    |
 LL |         asm!("/* {} */", out(yreg) _);
    |                          ^^^^^^^^^^^
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:47:26
+  --> $DIR/bad-reg.rs:46:26
    |
 LL |         asm!("", in("y") x);
    |                          ^
@@ -73,7 +73,7 @@ LL |         asm!("", in("y") x);
    = note: register class `yreg` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:50:27
+  --> $DIR/bad-reg.rs:49:27
    |
 LL |         asm!("", out("y") x);
    |                           ^
@@ -81,7 +81,7 @@ LL |         asm!("", out("y") x);
    = note: register class `yreg` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:53:35
+  --> $DIR/bad-reg.rs:52:35
    |
 LL |         asm!("/* {} */", in(yreg) x);
    |                                   ^
diff --git a/tests/ui/asm/sparc/bad-reg.sparcv8plus.stderr b/tests/ui/asm/sparc/bad-reg.sparcv8plus.stderr
index 84e56871ecc2..e0580ad3232f 100644
--- a/tests/ui/asm/sparc/bad-reg.sparcv8plus.stderr
+++ b/tests/ui/asm/sparc/bad-reg.sparcv8plus.stderr
@@ -1,77 +1,77 @@
 error: invalid register `g0`: g0 is always zero and cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:23:18
+  --> $DIR/bad-reg.rs:22:18
    |
 LL |         asm!("", out("g0") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `g1`: reserved by LLVM and cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:26:18
+  --> $DIR/bad-reg.rs:25:18
    |
 LL |         asm!("", out("g1") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `g6`: reserved for system and cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:33:18
+  --> $DIR/bad-reg.rs:32:18
    |
 LL |         asm!("", out("g6") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `g7`: reserved for system and cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:35:18
+  --> $DIR/bad-reg.rs:34:18
    |
 LL |         asm!("", out("g7") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `sp`: the stack pointer cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:37:18
+  --> $DIR/bad-reg.rs:36:18
    |
 LL |         asm!("", out("sp") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `fp`: the frame pointer cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:39:18
+  --> $DIR/bad-reg.rs:38:18
    |
 LL |         asm!("", out("fp") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `i7`: the return address register cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:41:18
+  --> $DIR/bad-reg.rs:40:18
    |
 LL |         asm!("", out("i7") _);
    |                  ^^^^^^^^^^^
 
 error: register class `yreg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:47:18
+  --> $DIR/bad-reg.rs:46:18
    |
 LL |         asm!("", in("y") x);
    |                  ^^^^^^^^^
 
 error: register class `yreg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:50:18
+  --> $DIR/bad-reg.rs:49:18
    |
 LL |         asm!("", out("y") x);
    |                  ^^^^^^^^^^
 
 error: register class `yreg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:53:26
+  --> $DIR/bad-reg.rs:52:26
    |
 LL |         asm!("/* {} */", in(yreg) x);
    |                          ^^^^^^^^^^
 
 error: register class `yreg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:56:26
+  --> $DIR/bad-reg.rs:55:26
    |
 LL |         asm!("/* {} */", out(yreg) _);
    |                          ^^^^^^^^^^^
 
 error: cannot use register `r5`: g5 is reserved for system on SPARC32
-  --> $DIR/bad-reg.rs:31:18
+  --> $DIR/bad-reg.rs:30:18
    |
 LL |         asm!("", out("g5") _);
    |                  ^^^^^^^^^^^
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:47:26
+  --> $DIR/bad-reg.rs:46:26
    |
 LL |         asm!("", in("y") x);
    |                          ^
@@ -79,7 +79,7 @@ LL |         asm!("", in("y") x);
    = note: register class `yreg` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:50:27
+  --> $DIR/bad-reg.rs:49:27
    |
 LL |         asm!("", out("y") x);
    |                           ^
@@ -87,7 +87,7 @@ LL |         asm!("", out("y") x);
    = note: register class `yreg` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:53:35
+  --> $DIR/bad-reg.rs:52:35
    |
 LL |         asm!("/* {} */", in(yreg) x);
    |                                   ^
diff --git a/tests/ui/associated-consts/issue-24949-assoc-const-static-recursion-impl.stderr b/tests/ui/associated-consts/issue-24949-assoc-const-static-recursion-impl.stderr
index bf37f537a497..718854c59f4f 100644
--- a/tests/ui/associated-consts/issue-24949-assoc-const-static-recursion-impl.stderr
+++ b/tests/ui/associated-consts/issue-24949-assoc-const-static-recursion-impl.stderr
@@ -1,36 +1,30 @@
-error[E0391]: cycle detected when simplifying constant for the type system `IMPL_REF_BAR`
+error[E0391]: cycle detected when checking if `IMPL_REF_BAR` is a trivial const
   --> $DIR/issue-24949-assoc-const-static-recursion-impl.rs:7:1
    |
 LL | const IMPL_REF_BAR: u32 = GlobalImplRef::BAR;
    | ^^^^^^^^^^^^^^^^^^^^^^^
    |
-note: ...which requires const-evaluating + checking `IMPL_REF_BAR`...
-  --> $DIR/issue-24949-assoc-const-static-recursion-impl.rs:7:27
+note: ...which requires building MIR for `IMPL_REF_BAR`...
+  --> $DIR/issue-24949-assoc-const-static-recursion-impl.rs:7:1
    |
 LL | const IMPL_REF_BAR: u32 = GlobalImplRef::BAR;
-   |                           ^^^^^^^^^^^^^^^^^^
-note: ...which requires simplifying constant for the type system `::BAR`...
+   | ^^^^^^^^^^^^^^^^^^^^^^^
+note: ...which requires checking if `::BAR` is a trivial const...
   --> $DIR/issue-24949-assoc-const-static-recursion-impl.rs:12:5
    |
 LL |     const BAR: u32 = IMPL_REF_BAR;
    |     ^^^^^^^^^^^^^^
-note: ...which requires const-evaluating + checking `::BAR`...
+note: ...which requires building MIR for `::BAR`...
   --> $DIR/issue-24949-assoc-const-static-recursion-impl.rs:12:5
    |
 LL |     const BAR: u32 = IMPL_REF_BAR;
    |     ^^^^^^^^^^^^^^
-note: ...which requires caching mir of `::BAR` for CTFE...
-  --> $DIR/issue-24949-assoc-const-static-recursion-impl.rs:12:5
+   = note: ...which again requires checking if `IMPL_REF_BAR` is a trivial const, completing the cycle
+note: cycle used when simplifying constant for the type system `IMPL_REF_BAR`
+  --> $DIR/issue-24949-assoc-const-static-recursion-impl.rs:7:1
    |
-LL |     const BAR: u32 = IMPL_REF_BAR;
-   |     ^^^^^^^^^^^^^^
-note: ...which requires elaborating drops for `::BAR`...
-  --> $DIR/issue-24949-assoc-const-static-recursion-impl.rs:12:22
-   |
-LL |     const BAR: u32 = IMPL_REF_BAR;
-   |                      ^^^^^^^^^^^^
-   = note: ...which again requires simplifying constant for the type system `IMPL_REF_BAR`, completing the cycle
-   = note: cycle used when running analysis passes on this crate
+LL | const IMPL_REF_BAR: u32 = GlobalImplRef::BAR;
+   | ^^^^^^^^^^^^^^^^^^^^^^^
    = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
 
 error: aborting due to 1 previous error
diff --git a/tests/ui/attributes/invalid_macro_export_argument.allow.stderr b/tests/ui/attributes/invalid_macro_export_argument.allow.stderr
index 162b315b072a..2db60a689728 100644
--- a/tests/ui/attributes/invalid_macro_export_argument.allow.stderr
+++ b/tests/ui/attributes/invalid_macro_export_argument.allow.stderr
@@ -1,5 +1,5 @@
 Future incompatibility report: Future breakage diagnostic:
-warning: valid forms for the attribute are `#![macro_export(local_inner_macros)]` and `#![macro_export]`
+warning: valid forms for the attribute are `#[macro_export(local_inner_macros)]` and `#[macro_export]`
   --> $DIR/invalid_macro_export_argument.rs:7:1
    |
 LL | #[macro_export(hello, world)]
@@ -9,7 +9,7 @@ LL | #[macro_export(hello, world)]
    = note: for more information, see issue #57571 
 
 Future breakage diagnostic:
-warning: valid forms for the attribute are `#![macro_export(local_inner_macros)]` and `#![macro_export]`
+warning: valid forms for the attribute are `#[macro_export(local_inner_macros)]` and `#[macro_export]`
   --> $DIR/invalid_macro_export_argument.rs:14:1
    |
 LL | #[macro_export(not_local_inner_macros)]
@@ -19,7 +19,7 @@ LL | #[macro_export(not_local_inner_macros)]
    = note: for more information, see issue #57571 
 
 Future breakage diagnostic:
-warning: valid forms for the attribute are `#![macro_export(local_inner_macros)]` and `#![macro_export]`
+warning: valid forms for the attribute are `#[macro_export(local_inner_macros)]` and `#[macro_export]`
   --> $DIR/invalid_macro_export_argument.rs:31:1
    |
 LL | #[macro_export()]
@@ -29,7 +29,7 @@ LL | #[macro_export()]
    = note: for more information, see issue #57571 
 
 Future breakage diagnostic:
-warning: valid forms for the attribute are `#![macro_export(local_inner_macros)]` and `#![macro_export]`
+warning: valid forms for the attribute are `#[macro_export(local_inner_macros)]` and `#[macro_export]`
   --> $DIR/invalid_macro_export_argument.rs:38:1
    |
 LL | #[macro_export("blah")]
diff --git a/tests/ui/attributes/invalid_macro_export_argument.deny.stderr b/tests/ui/attributes/invalid_macro_export_argument.deny.stderr
index ad225ae187b1..fd50b824d0a2 100644
--- a/tests/ui/attributes/invalid_macro_export_argument.deny.stderr
+++ b/tests/ui/attributes/invalid_macro_export_argument.deny.stderr
@@ -1,4 +1,4 @@
-error: valid forms for the attribute are `#![macro_export(local_inner_macros)]` and `#![macro_export]`
+error: valid forms for the attribute are `#[macro_export(local_inner_macros)]` and `#[macro_export]`
   --> $DIR/invalid_macro_export_argument.rs:7:1
    |
 LL | #[macro_export(hello, world)]
@@ -12,7 +12,7 @@ note: the lint level is defined here
 LL | #![cfg_attr(deny, deny(invalid_macro_export_arguments))]
    |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: valid forms for the attribute are `#![macro_export(local_inner_macros)]` and `#![macro_export]`
+error: valid forms for the attribute are `#[macro_export(local_inner_macros)]` and `#[macro_export]`
   --> $DIR/invalid_macro_export_argument.rs:14:1
    |
 LL | #[macro_export(not_local_inner_macros)]
@@ -21,7 +21,7 @@ LL | #[macro_export(not_local_inner_macros)]
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #57571 
 
-error: valid forms for the attribute are `#![macro_export(local_inner_macros)]` and `#![macro_export]`
+error: valid forms for the attribute are `#[macro_export(local_inner_macros)]` and `#[macro_export]`
   --> $DIR/invalid_macro_export_argument.rs:31:1
    |
 LL | #[macro_export()]
@@ -30,7 +30,7 @@ LL | #[macro_export()]
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #57571 
 
-error: valid forms for the attribute are `#![macro_export(local_inner_macros)]` and `#![macro_export]`
+error: valid forms for the attribute are `#[macro_export(local_inner_macros)]` and `#[macro_export]`
   --> $DIR/invalid_macro_export_argument.rs:38:1
    |
 LL | #[macro_export("blah")]
@@ -42,7 +42,7 @@ LL | #[macro_export("blah")]
 error: aborting due to 4 previous errors
 
 Future incompatibility report: Future breakage diagnostic:
-error: valid forms for the attribute are `#![macro_export(local_inner_macros)]` and `#![macro_export]`
+error: valid forms for the attribute are `#[macro_export(local_inner_macros)]` and `#[macro_export]`
   --> $DIR/invalid_macro_export_argument.rs:7:1
    |
 LL | #[macro_export(hello, world)]
@@ -57,7 +57,7 @@ LL | #![cfg_attr(deny, deny(invalid_macro_export_arguments))]
    |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 Future breakage diagnostic:
-error: valid forms for the attribute are `#![macro_export(local_inner_macros)]` and `#![macro_export]`
+error: valid forms for the attribute are `#[macro_export(local_inner_macros)]` and `#[macro_export]`
   --> $DIR/invalid_macro_export_argument.rs:14:1
    |
 LL | #[macro_export(not_local_inner_macros)]
@@ -72,7 +72,7 @@ LL | #![cfg_attr(deny, deny(invalid_macro_export_arguments))]
    |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 Future breakage diagnostic:
-error: valid forms for the attribute are `#![macro_export(local_inner_macros)]` and `#![macro_export]`
+error: valid forms for the attribute are `#[macro_export(local_inner_macros)]` and `#[macro_export]`
   --> $DIR/invalid_macro_export_argument.rs:31:1
    |
 LL | #[macro_export()]
@@ -87,7 +87,7 @@ LL | #![cfg_attr(deny, deny(invalid_macro_export_arguments))]
    |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 Future breakage diagnostic:
-error: valid forms for the attribute are `#![macro_export(local_inner_macros)]` and `#![macro_export]`
+error: valid forms for the attribute are `#[macro_export(local_inner_macros)]` and `#[macro_export]`
   --> $DIR/invalid_macro_export_argument.rs:38:1
    |
 LL | #[macro_export("blah")]
diff --git a/tests/ui/attributes/key-value-expansion-scope-pass.rs b/tests/ui/attributes/key-value-expansion-scope-pass.rs
index 6b1f4e5bd4bf..3a913b92c974 100644
--- a/tests/ui/attributes/key-value-expansion-scope-pass.rs
+++ b/tests/ui/attributes/key-value-expansion-scope-pass.rs
@@ -3,6 +3,7 @@
 //@ check-pass
 //@ edition:2018
 
+#![warn(unused_imports)]
 #![doc = in_root!()]
 
 macro_rules! in_root { () => { "" } }
diff --git a/tests/ui/attributes/malformed-attrs.stderr b/tests/ui/attributes/malformed-attrs.stderr
index c29bd0245bf0..5627cb452a81 100644
--- a/tests/ui/attributes/malformed-attrs.stderr
+++ b/tests/ui/attributes/malformed-attrs.stderr
@@ -701,7 +701,7 @@ error: valid forms for the attribute are `#[macro_use(name1, name2, ...)]` and `
 LL | #[macro_use = 1]
    | ^^^^^^^^^^^^^^^^
 
-error: valid forms for the attribute are `#![macro_export(local_inner_macros)]` and `#![macro_export]`
+error: valid forms for the attribute are `#[macro_export(local_inner_macros)]` and `#[macro_export]`
   --> $DIR/malformed-attrs.rs:221:1
    |
 LL | #[macro_export = 18]
diff --git a/tests/ui/autoref-autoderef/autoderef-box-no-add.stderr b/tests/ui/autoref-autoderef/autoderef-box-no-add.stderr
index 20ef3352831a..d861d103bde4 100644
--- a/tests/ui/autoref-autoderef/autoderef-box-no-add.stderr
+++ b/tests/ui/autoref-autoderef/autoderef-box-no-add.stderr
@@ -6,11 +6,11 @@ LL |     let z: isize = a.x + b.y;
    |                    |
    |                    Box
    |
-note: the foreign item type `Box` doesn't implement `Add`
+note: `Box` does not implement `Add`
   --> $SRC_DIR/alloc/src/boxed.rs:LL:COL
   ::: $SRC_DIR/alloc/src/boxed.rs:LL:COL
    |
-   = note: not implement `Add`
+   = note: `Box` is defined in another crate
 
 error[E0369]: cannot add `Box` to `Box`
   --> $DIR/autoderef-box-no-add.rs:31:33
@@ -20,11 +20,11 @@ LL |     let answer: isize = forty.a + two.a;
    |                         |
    |                         Box
    |
-note: the foreign item type `Box` doesn't implement `Add`
+note: `Box` does not implement `Add`
   --> $SRC_DIR/alloc/src/boxed.rs:LL:COL
   ::: $SRC_DIR/alloc/src/boxed.rs:LL:COL
    |
-   = note: not implement `Add`
+   = note: `Box` is defined in another crate
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/binop/binary-op-not-allowed-issue-125631.stderr b/tests/ui/binop/binary-op-not-allowed-issue-125631.stderr
index 1cf75bbc1a57..d95876659c7a 100644
--- a/tests/ui/binop/binary-op-not-allowed-issue-125631.stderr
+++ b/tests/ui/binop/binary-op-not-allowed-issue-125631.stderr
@@ -11,10 +11,10 @@ note: an implementation of `PartialEq` might be missing for `T1`
    |
 LL | struct T1;
    | ^^^^^^^^^ must implement `PartialEq`
-note: the foreign item type `std::io::Error` doesn't implement `PartialEq`
+note: `std::io::Error` does not implement `PartialEq`
   --> $SRC_DIR/std/src/io/error.rs:LL:COL
    |
-   = note: not implement `PartialEq`
+   = note: `std::io::Error` is defined in another crate
 help: consider annotating `T1` with `#[derive(PartialEq)]`
    |
 LL + #[derive(PartialEq)]
@@ -29,13 +29,14 @@ LL |     (Error::new(ErrorKind::Other, "2"), thread::current())
 LL |         == (Error::new(ErrorKind::Other, "2"), thread::current());
    |         ^^ ------------------------------------------------------ (std::io::Error, Thread)
    |
-note: the foreign item types don't implement required traits for this operation to be valid
-  --> $SRC_DIR/std/src/io/error.rs:LL:COL
-   |
-   = note: not implement `PartialEq`
+note: `Thread` does not implement `PartialEq`
   --> $SRC_DIR/std/src/thread/mod.rs:LL:COL
    |
-   = note: not implement `PartialEq`
+   = note: `Thread` is defined in another crate
+note: `std::io::Error` does not implement `PartialEq`
+  --> $SRC_DIR/std/src/io/error.rs:LL:COL
+   |
+   = note: `std::io::Error` is defined in another crate
 
 error[E0369]: binary operation `==` cannot be applied to type `(std::io::Error, Thread, T1, T2)`
   --> $DIR/binary-op-not-allowed-issue-125631.rs:14:9
@@ -52,13 +53,14 @@ LL | struct T1;
    | ^^^^^^^^^ must implement `PartialEq`
 LL | struct T2;
    | ^^^^^^^^^ must implement `PartialEq`
-note: the foreign item types don't implement required traits for this operation to be valid
-  --> $SRC_DIR/std/src/io/error.rs:LL:COL
-   |
-   = note: not implement `PartialEq`
+note: `Thread` does not implement `PartialEq`
   --> $SRC_DIR/std/src/thread/mod.rs:LL:COL
    |
-   = note: not implement `PartialEq`
+   = note: `Thread` is defined in another crate
+note: `std::io::Error` does not implement `PartialEq`
+  --> $SRC_DIR/std/src/io/error.rs:LL:COL
+   |
+   = note: `std::io::Error` is defined in another crate
 help: consider annotating `T1` with `#[derive(PartialEq)]`
    |
 LL + #[derive(PartialEq)]
diff --git a/tests/ui/binop/binop-bitxor-str.stderr b/tests/ui/binop/binop-bitxor-str.stderr
index d4bb0c17bfa7..014a41f9e3ac 100644
--- a/tests/ui/binop/binop-bitxor-str.stderr
+++ b/tests/ui/binop/binop-bitxor-str.stderr
@@ -6,10 +6,10 @@ LL | fn main() { let x = "a".to_string() ^ "b".to_string(); }
    |                     |
    |                     String
    |
-note: the foreign item type `String` doesn't implement `BitXor`
+note: `String` does not implement `BitXor`
   --> $SRC_DIR/alloc/src/string.rs:LL:COL
    |
-   = note: not implement `BitXor`
+   = note: `String` is defined in another crate
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/conditional-compilation/cfg_attr-attr-syntax-validation.stderr b/tests/ui/conditional-compilation/cfg_attr-attr-syntax-validation.stderr
index 2b7a7da3e33d..fd03fa62864a 100644
--- a/tests/ui/conditional-compilation/cfg_attr-attr-syntax-validation.stderr
+++ b/tests/ui/conditional-compilation/cfg_attr-attr-syntax-validation.stderr
@@ -113,7 +113,7 @@ error[E0539]: malformed `link_section` attribute input
   --> $DIR/cfg_attr-attr-syntax-validation.rs:44:18
    |
 LL | #[cfg_attr(true, link_section)]
-   |                  ^^^^^^^^^^^^ help: must be of the form: `#[link_section = "name"]`
+   |                  ^^^^^^^^^^^^ help: must be of the form: `link_section = "name"`
    |
    = note: for more information, visit 
 
@@ -129,14 +129,12 @@ LL | #[cfg_attr(true, inline())]
 help: try changing it to one of the following valid forms of the attribute
    |
 LL - #[cfg_attr(true, inline())]
-LL + #[cfg_attr(true, #[inline(always)])]
-   |
-LL - #[cfg_attr(true, inline())]
-LL + #[cfg_attr(true, #[inline(never)])]
-   |
-LL - #[cfg_attr(true, inline())]
-LL + #[cfg_attr(true, #[inline])]
+LL + #[cfg_attr(true, inline)]
    |
+LL | #[cfg_attr(true, inline(always))]
+   |                         ++++++
+LL | #[cfg_attr(true, inline(never))]
+   |                         +++++
 
 warning: `#[link_section]` attribute cannot be used on structs
   --> $DIR/cfg_attr-attr-syntax-validation.rs:44:18
diff --git a/tests/ui/contracts/contracts-disabled-side-effect-declarations.rs b/tests/ui/contracts/contracts-disabled-side-effect-declarations.rs
new file mode 100644
index 000000000000..fc07729e9132
--- /dev/null
+++ b/tests/ui/contracts/contracts-disabled-side-effect-declarations.rs
@@ -0,0 +1,17 @@
+//@ run-pass
+#![feature(contracts)]
+//~^ WARN the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features]
+
+extern crate core;
+use core::contracts::requires;
+
+#[requires(*x = 0; true)]
+fn buggy_add(x: &mut u32, y: u32) {
+    *x = *x + y;
+}
+
+fn main() {
+    let mut x = 10;
+    buggy_add(&mut x, 100);
+    assert_eq!(x, 110);
+}
diff --git a/tests/ui/contracts/contracts-disabled-side-effect-declarations.stderr b/tests/ui/contracts/contracts-disabled-side-effect-declarations.stderr
new file mode 100644
index 000000000000..4c8a12538433
--- /dev/null
+++ b/tests/ui/contracts/contracts-disabled-side-effect-declarations.stderr
@@ -0,0 +1,11 @@
+warning: the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/contracts-disabled-side-effect-declarations.rs:2:12
+   |
+LL | #![feature(contracts)]
+   |            ^^^^^^^^^
+   |
+   = note: see issue #128044  for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/contracts/contracts-disabled-side-effect-ensures.rs b/tests/ui/contracts/contracts-disabled-side-effect-ensures.rs
index d234acb8268a..a3a77b0de9a2 100644
--- a/tests/ui/contracts/contracts-disabled-side-effect-ensures.rs
+++ b/tests/ui/contracts/contracts-disabled-side-effect-ensures.rs
@@ -5,7 +5,7 @@
 extern crate core;
 use core::contracts::ensures;
 
-#[ensures({*x = 0; |_ret| true})]
+#[ensures(*x = 0; |_ret| true)]
 fn buggy_add(x: &mut u32, y: u32) {
     *x = *x + y;
 }
diff --git a/tests/ui/contracts/declared-vars-referring-to-params.rs b/tests/ui/contracts/declared-vars-referring-to-params.rs
new file mode 100644
index 000000000000..52885da048e2
--- /dev/null
+++ b/tests/ui/contracts/declared-vars-referring-to-params.rs
@@ -0,0 +1,19 @@
+//@ run-pass
+//@ compile-flags: -Zcontract-checks=yes
+#![feature(contracts)]
+//~^ WARN the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features]
+
+extern crate core;
+use core::contracts::{ensures, requires};
+
+// checks that variable declarations are lowered properly, with the ability to
+// access function parameters
+#[requires(let y = 2 * x; true)]
+#[ensures(move |ret| { *ret == y })]
+fn foo(x: u32) -> u32 {
+    x * 2
+}
+
+fn main() {
+    foo(1);
+}
diff --git a/tests/ui/contracts/declared-vars-referring-to-params.stderr b/tests/ui/contracts/declared-vars-referring-to-params.stderr
new file mode 100644
index 000000000000..0ad9064e8606
--- /dev/null
+++ b/tests/ui/contracts/declared-vars-referring-to-params.stderr
@@ -0,0 +1,11 @@
+warning: the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/declared-vars-referring-to-params.rs:3:12
+   |
+LL | #![feature(contracts)]
+   |            ^^^^^^^^^
+   |
+   = note: see issue #128044  for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/contracts/declared-vars-used-in-ensures.rs b/tests/ui/contracts/declared-vars-used-in-ensures.rs
new file mode 100644
index 000000000000..9703709e2b8e
--- /dev/null
+++ b/tests/ui/contracts/declared-vars-used-in-ensures.rs
@@ -0,0 +1,17 @@
+//@ run-pass
+//@ compile-flags: -Zcontract-checks=yes
+#![feature(contracts)]
+//~^ WARN the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features]
+
+extern crate core;
+use core::contracts::{ensures, requires};
+
+#[requires(let y = 1; true)]
+#[ensures(move |_ret| { y == 1 })]
+fn foo(x: u32) -> u32 {
+    x * 2
+}
+
+fn main() {
+    foo(1);
+}
diff --git a/tests/ui/contracts/declared-vars-used-in-ensures.stderr b/tests/ui/contracts/declared-vars-used-in-ensures.stderr
new file mode 100644
index 000000000000..000a1b239932
--- /dev/null
+++ b/tests/ui/contracts/declared-vars-used-in-ensures.stderr
@@ -0,0 +1,11 @@
+warning: the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/declared-vars-used-in-ensures.rs:3:12
+   |
+LL | #![feature(contracts)]
+   |            ^^^^^^^^^
+   |
+   = note: see issue #128044  for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/contracts/declared-vars-used-in-requires-and-ensures.rs b/tests/ui/contracts/declared-vars-used-in-requires-and-ensures.rs
new file mode 100644
index 000000000000..e066a95314a9
--- /dev/null
+++ b/tests/ui/contracts/declared-vars-used-in-requires-and-ensures.rs
@@ -0,0 +1,19 @@
+//@ run-pass
+//@ compile-flags: -Zcontract-checks=yes
+#![feature(contracts)]
+//~^ WARN the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features]
+
+extern crate core;
+use core::contracts::{ensures, requires};
+
+// checks that variable declarations are lowered properly, with the ability to
+// refer to them *both* in requires and ensures
+#[requires(let y = 2 * x; y > 0)]
+#[ensures(move |ret| { *ret == y })]
+fn foo(x: u32) -> u32 {
+    x * 2
+}
+
+fn main() {
+    foo(1);
+}
diff --git a/tests/ui/contracts/declared-vars-used-in-requires-and-ensures.stderr b/tests/ui/contracts/declared-vars-used-in-requires-and-ensures.stderr
new file mode 100644
index 000000000000..52b163553fba
--- /dev/null
+++ b/tests/ui/contracts/declared-vars-used-in-requires-and-ensures.stderr
@@ -0,0 +1,11 @@
+warning: the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/declared-vars-used-in-requires-and-ensures.rs:3:12
+   |
+LL | #![feature(contracts)]
+   |            ^^^^^^^^^
+   |
+   = note: see issue #128044  for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/contracts/internal_machinery/contract-ast-extensions-nest.rs b/tests/ui/contracts/internal_machinery/contract-ast-extensions-nest.rs
index 4da0480f8bc1..faf0d80adaf3 100644
--- a/tests/ui/contracts/internal_machinery/contract-ast-extensions-nest.rs
+++ b/tests/ui/contracts/internal_machinery/contract-ast-extensions-nest.rs
@@ -19,8 +19,8 @@
 #![feature(contracts_internals)]
 
 fn nest(x: Baz) -> i32
-    contract_requires(|| x.baz > 0)
-    contract_ensures(|ret| *ret > 100)
+    contract_requires { x.baz > 0 }
+    contract_ensures { |ret| *ret > 100 }
 {
     loop {
         return x.baz + 50;
diff --git a/tests/ui/contracts/internal_machinery/contract-ast-extensions-tail.rs b/tests/ui/contracts/internal_machinery/contract-ast-extensions-tail.rs
index f3cf5ce082c0..8095bdd2978b 100644
--- a/tests/ui/contracts/internal_machinery/contract-ast-extensions-tail.rs
+++ b/tests/ui/contracts/internal_machinery/contract-ast-extensions-tail.rs
@@ -19,8 +19,8 @@
 #![feature(contracts_internals)]
 
 fn tail(x: Baz) -> i32
-    contract_requires(|| x.baz > 0)
-    contract_ensures(|ret| *ret > 100)
+    contract_requires { x.baz > 0 }
+    contract_ensures { |ret| *ret > 100 }
 {
     x.baz + 50
 }
diff --git a/tests/ui/contracts/internal_machinery/contracts-lowering-ensures-is-not-inherited-when-nesting.rs b/tests/ui/contracts/internal_machinery/contracts-lowering-ensures-is-not-inherited-when-nesting.rs
index 960ccaed3588..6dd1fae5615a 100644
--- a/tests/ui/contracts/internal_machinery/contracts-lowering-ensures-is-not-inherited-when-nesting.rs
+++ b/tests/ui/contracts/internal_machinery/contracts-lowering-ensures-is-not-inherited-when-nesting.rs
@@ -3,7 +3,7 @@
 #![feature(contracts_internals)]
 
 fn outer() -> i32
-    contract_ensures(|ret| *ret > 0)
+    contract_ensures { |ret| *ret > 0 }
 {
     let inner_closure = || -> i32 { 0 };
     inner_closure();
diff --git a/tests/ui/contracts/internal_machinery/contracts-lowering-requires-is-not-inherited-when-nesting.rs b/tests/ui/contracts/internal_machinery/contracts-lowering-requires-is-not-inherited-when-nesting.rs
index bee703de16a0..42c665694e7a 100644
--- a/tests/ui/contracts/internal_machinery/contracts-lowering-requires-is-not-inherited-when-nesting.rs
+++ b/tests/ui/contracts/internal_machinery/contracts-lowering-requires-is-not-inherited-when-nesting.rs
@@ -5,7 +5,7 @@
 struct Outer { outer: std::cell::Cell }
 
 fn outer(x: Outer)
-    contract_requires(|| x.outer.get() > 0)
+    contract_requires { x.outer.get() > 0 }
 {
     let inner_closure = || { };
     x.outer.set(0);
diff --git a/tests/ui/contracts/internal_machinery/internal-feature-gating.rs b/tests/ui/contracts/internal_machinery/internal-feature-gating.rs
index 48bd376594f2..9d3765bc228d 100644
--- a/tests/ui/contracts/internal_machinery/internal-feature-gating.rs
+++ b/tests/ui/contracts/internal_machinery/internal-feature-gating.rs
@@ -11,8 +11,8 @@ fn main() {
     //~^ ERROR use of unstable library feature `contracts_internals`
 
     // ast extensions are guarded by contracts_internals feature gate
-    fn identity_1() -> i32 contract_requires(|| true) { 10 }
+    fn identity_1() -> i32 contract_requires { true } { 10 }
     //~^ ERROR contract internal machinery is for internal use only
-    fn identity_2() -> i32 contract_ensures(|_| true) { 10 }
+    fn identity_2() -> i32 contract_ensures { |_| true } { 10 }
     //~^ ERROR contract internal machinery is for internal use only
 }
diff --git a/tests/ui/contracts/internal_machinery/internal-feature-gating.stderr b/tests/ui/contracts/internal_machinery/internal-feature-gating.stderr
index c1318fc15a78..0010fca2f96c 100644
--- a/tests/ui/contracts/internal_machinery/internal-feature-gating.stderr
+++ b/tests/ui/contracts/internal_machinery/internal-feature-gating.stderr
@@ -1,7 +1,7 @@
 error[E0658]: contract internal machinery is for internal use only
   --> $DIR/internal-feature-gating.rs:14:28
    |
-LL |     fn identity_1() -> i32 contract_requires(|| true) { 10 }
+LL |     fn identity_1() -> i32 contract_requires { true } { 10 }
    |                            ^^^^^^^^^^^^^^^^^
    |
    = note: see issue #128044  for more information
@@ -11,7 +11,7 @@ LL |     fn identity_1() -> i32 contract_requires(|| true) { 10 }
 error[E0658]: contract internal machinery is for internal use only
   --> $DIR/internal-feature-gating.rs:16:28
    |
-LL |     fn identity_2() -> i32 contract_ensures(|_| true) { 10 }
+LL |     fn identity_2() -> i32 contract_ensures { |_| true } { 10 }
    |                            ^^^^^^^^^^^^^^^^
    |
    = note: see issue #128044  for more information
diff --git a/tests/ui/contracts/internal_machinery/lowering/basics.rs b/tests/ui/contracts/internal_machinery/lowering/basics.rs
new file mode 100644
index 000000000000..9160517a7932
--- /dev/null
+++ b/tests/ui/contracts/internal_machinery/lowering/basics.rs
@@ -0,0 +1,24 @@
+//@ run-pass
+#![feature(contracts, cfg_contract_checks, contracts_internals, core_intrinsics)]
+//~^ WARN the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features]
+
+extern crate core;
+
+// we check here if the "lowered" program behaves as expected before
+// implementing the actual lowering in the compiler
+
+fn foo(x: u32) -> u32 {
+    let post = {
+        let y = 2 * x;
+        // call contract_check_requires here to avoid borrow checker issues
+        // with variables declared in contract requires
+        core::intrinsics::contract_check_requires(|| y > 0);
+        Some(core::contracts::build_check_ensures(move |ret| *ret == y))
+    };
+
+    core::intrinsics::contract_check_ensures(post, { 2 * x })
+}
+
+fn main() {
+    foo(1);
+}
diff --git a/tests/ui/contracts/internal_machinery/lowering/basics.stderr b/tests/ui/contracts/internal_machinery/lowering/basics.stderr
new file mode 100644
index 000000000000..118229694a90
--- /dev/null
+++ b/tests/ui/contracts/internal_machinery/lowering/basics.stderr
@@ -0,0 +1,11 @@
+warning: the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/basics.rs:2:12
+   |
+LL | #![feature(contracts, cfg_contract_checks, contracts_internals, core_intrinsics)]
+   |            ^^^^^^^^^
+   |
+   = note: see issue #128044  for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/contracts/requires-bool-expr-with-semicolon.rs b/tests/ui/contracts/requires-bool-expr-with-semicolon.rs
new file mode 100644
index 000000000000..d0b3ed661ed6
--- /dev/null
+++ b/tests/ui/contracts/requires-bool-expr-with-semicolon.rs
@@ -0,0 +1,18 @@
+//@ dont-require-annotations: NOTE
+//@ compile-flags: -Zcontract-checks=yes
+#![feature(contracts)]
+//~^ WARN the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features]
+
+extern crate core;
+use core::contracts::requires;
+
+#[requires(true;)]
+//~^ ERROR mismatched types [E0308]
+//~| NOTE expected `bool`, found `()`
+fn foo(x: u32) -> u32 {
+    x * 2
+}
+
+fn main() {
+    foo(1);
+}
diff --git a/tests/ui/contracts/requires-bool-expr-with-semicolon.stderr b/tests/ui/contracts/requires-bool-expr-with-semicolon.stderr
new file mode 100644
index 000000000000..fd38fa4edcf5
--- /dev/null
+++ b/tests/ui/contracts/requires-bool-expr-with-semicolon.stderr
@@ -0,0 +1,18 @@
+warning: the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/requires-bool-expr-with-semicolon.rs:3:12
+   |
+LL | #![feature(contracts)]
+   |            ^^^^^^^^^
+   |
+   = note: see issue #128044  for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+error[E0308]: mismatched types
+  --> $DIR/requires-bool-expr-with-semicolon.rs:9:1
+   |
+LL | #[requires(true;)]
+   | ^^^^^^^^^^^^^^^^^^ expected `bool`, found `()`
+
+error: aborting due to 1 previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/contracts/requires-no-final-expression.rs b/tests/ui/contracts/requires-no-final-expression.rs
new file mode 100644
index 000000000000..474b29d63ba6
--- /dev/null
+++ b/tests/ui/contracts/requires-no-final-expression.rs
@@ -0,0 +1,18 @@
+//@ dont-require-annotations: NOTE
+//@ compile-flags: -Zcontract-checks=yes
+#![feature(contracts)]
+//~^ WARN the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features]
+
+extern crate core;
+use core::contracts::requires;
+
+#[requires(let y = 1;)]
+//~^ ERROR mismatched types [E0308]
+//~| NOTE expected `bool`, found `()`
+fn foo(x: u32) -> u32 {
+    x * 2
+}
+
+fn main() {
+    foo(1);
+}
diff --git a/tests/ui/contracts/requires-no-final-expression.stderr b/tests/ui/contracts/requires-no-final-expression.stderr
new file mode 100644
index 000000000000..0db164857394
--- /dev/null
+++ b/tests/ui/contracts/requires-no-final-expression.stderr
@@ -0,0 +1,18 @@
+warning: the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/requires-no-final-expression.rs:3:12
+   |
+LL | #![feature(contracts)]
+   |            ^^^^^^^^^
+   |
+   = note: see issue #128044  for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+error[E0308]: mismatched types
+  --> $DIR/requires-no-final-expression.rs:9:1
+   |
+LL | #[requires(let y = 1;)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found `()`
+
+error: aborting due to 1 previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/dst/dst-object-from-unsized-type.stderr b/tests/ui/dst/dst-object-from-unsized-type.current.stderr
similarity index 90%
rename from tests/ui/dst/dst-object-from-unsized-type.stderr
rename to tests/ui/dst/dst-object-from-unsized-type.current.stderr
index cbb7dc5e9f42..be9966743d4e 100644
--- a/tests/ui/dst/dst-object-from-unsized-type.stderr
+++ b/tests/ui/dst/dst-object-from-unsized-type.current.stderr
@@ -1,5 +1,5 @@
 error[E0277]: the size for values of type `T` cannot be known at compilation time
-  --> $DIR/dst-object-from-unsized-type.rs:8:23
+  --> $DIR/dst-object-from-unsized-type.rs:11:23
    |
 LL | fn test1(t: &T) {
    |          - this type parameter needs to be `Sized`
@@ -14,7 +14,7 @@ LL + fn test1(t: &T) {
    |
 
 error[E0277]: the size for values of type `T` cannot be known at compilation time
-  --> $DIR/dst-object-from-unsized-type.rs:13:23
+  --> $DIR/dst-object-from-unsized-type.rs:17:23
    |
 LL | fn test2(t: &T) {
    |          - this type parameter needs to be `Sized`
@@ -29,7 +29,7 @@ LL + fn test2(t: &T) {
    |
 
 error[E0277]: the size for values of type `str` cannot be known at compilation time
-  --> $DIR/dst-object-from-unsized-type.rs:18:28
+  --> $DIR/dst-object-from-unsized-type.rs:23:28
    |
 LL |     let _: &[&dyn Foo] = &["hi"];
    |                            ^^^^ doesn't have a size known at compile-time
@@ -38,7 +38,7 @@ LL |     let _: &[&dyn Foo] = &["hi"];
    = note: required for the cast from `&'static str` to `&dyn Foo`
 
 error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
-  --> $DIR/dst-object-from-unsized-type.rs:23:23
+  --> $DIR/dst-object-from-unsized-type.rs:29:23
    |
 LL |     let _: &dyn Foo = x as &dyn Foo;
    |                       ^ doesn't have a size known at compile-time
diff --git a/tests/ui/dst/dst-object-from-unsized-type.next.stderr b/tests/ui/dst/dst-object-from-unsized-type.next.stderr
new file mode 100644
index 000000000000..032ba0cb14ae
--- /dev/null
+++ b/tests/ui/dst/dst-object-from-unsized-type.next.stderr
@@ -0,0 +1,57 @@
+error[E0277]: the trait bound `&T: CoerceUnsized<&dyn Foo>` is not satisfied in `T`
+  --> $DIR/dst-object-from-unsized-type.rs:11:23
+   |
+LL | fn test1(t: &T) {
+   |          - this type parameter needs to be `Sized`
+LL |     let u: &dyn Foo = t;
+   |                       ^ within `T`, the trait `Sized` is not implemented for `T`
+   |
+   = note: required because it appears within the type `T`
+   = note: required for `&T` to implement `CoerceUnsized<&dyn Foo>`
+   = note: required for the cast from `&T` to `&dyn Foo`
+help: consider removing the `?Sized` bound to make the type parameter `Sized`
+   |
+LL - fn test1(t: &T) {
+LL + fn test1(t: &T) {
+   |
+
+error[E0277]: the trait bound `&T: CoerceUnsized<&dyn Foo>` is not satisfied in `T`
+  --> $DIR/dst-object-from-unsized-type.rs:17:23
+   |
+LL | fn test2(t: &T) {
+   |          - this type parameter needs to be `Sized`
+LL |     let v: &dyn Foo = t as &dyn Foo;
+   |                       ^ within `T`, the trait `Sized` is not implemented for `T`
+   |
+   = note: required because it appears within the type `T`
+   = note: required for `&T` to implement `CoerceUnsized<&dyn Foo>`
+   = note: required for the cast from `&T` to `&dyn Foo`
+help: consider removing the `?Sized` bound to make the type parameter `Sized`
+   |
+LL - fn test2(t: &T) {
+LL + fn test2(t: &T) {
+   |
+
+error[E0277]: the trait bound `&str: CoerceUnsized<&dyn Foo>` is not satisfied in `str`
+  --> $DIR/dst-object-from-unsized-type.rs:23:28
+   |
+LL |     let _: &[&dyn Foo] = &["hi"];
+   |                            ^^^^ within `str`, the trait `Sized` is not implemented for `str`
+   |
+   = note: `str` is considered to contain a `[u8]` slice for auto trait purposes
+   = note: required for `&str` to implement `CoerceUnsized<&dyn Foo>`
+   = note: required for the cast from `&'static str` to `&dyn Foo`
+
+error[E0277]: the trait bound `&[u8]: CoerceUnsized<&dyn Foo>` is not satisfied in `[u8]`
+  --> $DIR/dst-object-from-unsized-type.rs:29:23
+   |
+LL |     let _: &dyn Foo = x as &dyn Foo;
+   |                       ^ within `[u8]`, the trait `Sized` is not implemented for `[u8]`
+   |
+   = note: required because it appears within the type `[u8]`
+   = note: required for `&[u8]` to implement `CoerceUnsized<&dyn Foo>`
+   = note: required for the cast from `&[u8]` to `&dyn Foo`
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/dst/dst-object-from-unsized-type.rs b/tests/ui/dst/dst-object-from-unsized-type.rs
index 3cd5b1ed6f46..1e6113b3fc6f 100644
--- a/tests/ui/dst/dst-object-from-unsized-type.rs
+++ b/tests/ui/dst/dst-object-from-unsized-type.rs
@@ -1,4 +1,7 @@
 // Test that we cannot create objects from unsized types.
+//@ revisions: current next
+//@ ignore-compare-mode-next-solver (explicit revisions)
+//@[next] compile-flags: -Znext-solver
 
 trait Foo { fn foo(&self) {} }
 impl Foo for str {}
@@ -6,22 +9,26 @@ impl Foo for [u8] {}
 
 fn test1(t: &T) {
     let u: &dyn Foo = t;
-    //~^ ERROR the size for values of type
+    //[current]~^ ERROR the size for values of type
+    //[next]~^^ ERROR the trait bound `&T: CoerceUnsized<&dyn Foo>` is not satisfied in `T`
 }
 
 fn test2(t: &T) {
     let v: &dyn Foo = t as &dyn Foo;
-    //~^ ERROR the size for values of type
+    //[current]~^ ERROR the size for values of type
+    //[next]~^^ ERROR the trait bound `&T: CoerceUnsized<&dyn Foo>` is not satisfied in `T`
 }
 
 fn test3() {
     let _: &[&dyn Foo] = &["hi"];
-    //~^ ERROR the size for values of type
+    //[current]~^ ERROR the size for values of type
+    //[next]~^^ ERROR the trait bound `&str: CoerceUnsized<&dyn Foo>` is not satisfied in `str`
 }
 
 fn test4(x: &[u8]) {
     let _: &dyn Foo = x as &dyn Foo;
-    //~^ ERROR the size for values of type
+    //[current]~^ ERROR the size for values of type
+    //[next]~^^ ERROR the trait bound `&[u8]: CoerceUnsized<&dyn Foo>` is not satisfied in `[u8]`
 }
 
 fn main() { }
diff --git a/tests/ui/error-codes/E0067.stderr b/tests/ui/error-codes/E0067.stderr
index 71b720805442..d350805da834 100644
--- a/tests/ui/error-codes/E0067.stderr
+++ b/tests/ui/error-codes/E0067.stderr
@@ -6,11 +6,11 @@ LL |     LinkedList::new() += 1;
    |     |
    |     cannot use `+=` on type `LinkedList<_>`
    |
-note: the foreign item type `LinkedList<_>` doesn't implement `AddAssign<{integer}>`
+note: `LinkedList<_>` does not implement `AddAssign<{integer}>`
   --> $SRC_DIR/alloc/src/collections/linked_list.rs:LL:COL
   ::: $SRC_DIR/alloc/src/collections/linked_list.rs:LL:COL
    |
-   = note: not implement `AddAssign<{integer}>`
+   = note: `LinkedList<_>` is defined in another crate
 
 error[E0067]: invalid left-hand side of assignment
   --> $DIR/E0067.rs:4:23
diff --git a/tests/ui/feature-gates/feature-gate-asm_experimental_reg.rs b/tests/ui/feature-gates/feature-gate-asm_experimental_reg.rs
index ecb01e816ec1..15d6d4731c8f 100644
--- a/tests/ui/feature-gates/feature-gate-asm_experimental_reg.rs
+++ b/tests/ui/feature-gates/feature-gate-asm_experimental_reg.rs
@@ -1,5 +1,4 @@
 //@ add-core-stubs
-//@ needs-asm-support
 //@ compile-flags: --target s390x-unknown-linux-gnu
 //@ needs-llvm-components: systemz
 //@ ignore-backends: gcc
diff --git a/tests/ui/feature-gates/feature-gate-asm_experimental_reg.stderr b/tests/ui/feature-gates/feature-gate-asm_experimental_reg.stderr
index 6bdb4213f319..6f2ea0ddaec1 100644
--- a/tests/ui/feature-gates/feature-gate-asm_experimental_reg.stderr
+++ b/tests/ui/feature-gates/feature-gate-asm_experimental_reg.stderr
@@ -1,5 +1,5 @@
 error[E0658]: register class `vreg` can only be used as a clobber in stable
-  --> $DIR/feature-gate-asm_experimental_reg.rs:15:14
+  --> $DIR/feature-gate-asm_experimental_reg.rs:14:14
    |
 LL |     asm!("", in("v0") 0);
    |              ^^^^^^^^^^
@@ -9,7 +9,7 @@ LL |     asm!("", in("v0") 0);
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: type `i32` cannot be used with this register class in stable
-  --> $DIR/feature-gate-asm_experimental_reg.rs:15:23
+  --> $DIR/feature-gate-asm_experimental_reg.rs:14:23
    |
 LL |     asm!("", in("v0") 0);
    |                       ^
diff --git a/tests/ui/frontmatter/frontmatter-contains-whitespace.rs b/tests/ui/frontmatter/content-contains-whitespace.rs
similarity index 100%
rename from tests/ui/frontmatter/frontmatter-contains-whitespace.rs
rename to tests/ui/frontmatter/content-contains-whitespace.rs
diff --git a/tests/ui/frontmatter/frontmatter-non-lexible-tokens.rs b/tests/ui/frontmatter/content-non-lexible-tokens.rs
similarity index 100%
rename from tests/ui/frontmatter/frontmatter-non-lexible-tokens.rs
rename to tests/ui/frontmatter/content-non-lexible-tokens.rs
diff --git a/tests/ui/frontmatter/escape.rs b/tests/ui/frontmatter/escape-hyphens-leading.rs
similarity index 100%
rename from tests/ui/frontmatter/escape.rs
rename to tests/ui/frontmatter/escape-hyphens-leading.rs
diff --git a/tests/ui/frontmatter/multifrontmatter-2.rs b/tests/ui/frontmatter/escape-hyphens-nonleading-1.rs
similarity index 100%
rename from tests/ui/frontmatter/multifrontmatter-2.rs
rename to tests/ui/frontmatter/escape-hyphens-nonleading-1.rs
diff --git a/tests/ui/frontmatter/frontmatter-inner-hyphens-1.rs b/tests/ui/frontmatter/escape-hyphens-nonleading-2.rs
similarity index 100%
rename from tests/ui/frontmatter/frontmatter-inner-hyphens-1.rs
rename to tests/ui/frontmatter/escape-hyphens-nonleading-2.rs
diff --git a/tests/ui/frontmatter/frontmatter-inner-hyphens-2.rs b/tests/ui/frontmatter/escape-hyphens-nonleading-3.rs
similarity index 100%
rename from tests/ui/frontmatter/frontmatter-inner-hyphens-2.rs
rename to tests/ui/frontmatter/escape-hyphens-nonleading-3.rs
diff --git a/tests/ui/frontmatter/extra-after-end.rs b/tests/ui/frontmatter/fence-close-extra-after.rs
similarity index 100%
rename from tests/ui/frontmatter/extra-after-end.rs
rename to tests/ui/frontmatter/fence-close-extra-after.rs
diff --git a/tests/ui/frontmatter/extra-after-end.stderr b/tests/ui/frontmatter/fence-close-extra-after.stderr
similarity index 76%
rename from tests/ui/frontmatter/extra-after-end.stderr
rename to tests/ui/frontmatter/fence-close-extra-after.stderr
index c2770fdfd41f..a54a67152f97 100644
--- a/tests/ui/frontmatter/extra-after-end.stderr
+++ b/tests/ui/frontmatter/fence-close-extra-after.stderr
@@ -1,5 +1,5 @@
 error: extra characters after frontmatter close are not allowed
-  --> $DIR/extra-after-end.rs:2:1
+  --> $DIR/fence-close-extra-after.rs:2:1
    |
 LL | ---cargo
    | ^^^^^^^^
diff --git a/tests/ui/frontmatter/frontmatter-whitespace-2.rs b/tests/ui/frontmatter/fence-indented-mismatch.rs
similarity index 100%
rename from tests/ui/frontmatter/frontmatter-whitespace-2.rs
rename to tests/ui/frontmatter/fence-indented-mismatch.rs
diff --git a/tests/ui/frontmatter/frontmatter-whitespace-2.stderr b/tests/ui/frontmatter/fence-indented-mismatch.stderr
similarity index 81%
rename from tests/ui/frontmatter/frontmatter-whitespace-2.stderr
rename to tests/ui/frontmatter/fence-indented-mismatch.stderr
index 2ae63cdc6fe4..d85add165210 100644
--- a/tests/ui/frontmatter/frontmatter-whitespace-2.stderr
+++ b/tests/ui/frontmatter/fence-indented-mismatch.stderr
@@ -1,5 +1,5 @@
 error: unclosed frontmatter
-  --> $DIR/frontmatter-whitespace-2.rs:1:1
+  --> $DIR/fence-indented-mismatch.rs:1:1
    |
 LL | / ---cargo
 ...  |
@@ -7,13 +7,13 @@ LL | |
    | |_^
    |
 note: frontmatter opening here was not closed
-  --> $DIR/frontmatter-whitespace-2.rs:1:1
+  --> $DIR/fence-indented-mismatch.rs:1:1
    |
 LL | ---cargo
    | ^^^
 
 warning: use of a double negation
-  --> $DIR/frontmatter-whitespace-2.rs:9:6
+  --> $DIR/fence-indented-mismatch.rs:9:6
    |
 LL |     ---x
    |      ^^^
diff --git a/tests/ui/frontmatter/frontmatter-whitespace-1.rs b/tests/ui/frontmatter/fence-indented.rs
similarity index 100%
rename from tests/ui/frontmatter/frontmatter-whitespace-1.rs
rename to tests/ui/frontmatter/fence-indented.rs
diff --git a/tests/ui/frontmatter/frontmatter-whitespace-1.stderr b/tests/ui/frontmatter/fence-indented.stderr
similarity index 69%
rename from tests/ui/frontmatter/frontmatter-whitespace-1.stderr
rename to tests/ui/frontmatter/fence-indented.stderr
index f16788fa3992..777db0976d08 100644
--- a/tests/ui/frontmatter/frontmatter-whitespace-1.stderr
+++ b/tests/ui/frontmatter/fence-indented.stderr
@@ -1,17 +1,17 @@
 error: invalid preceding whitespace for frontmatter opening
-  --> $DIR/frontmatter-whitespace-1.rs:1:1
+  --> $DIR/fence-indented.rs:1:1
    |
 LL |   ---
    | ^^^^^
    |
 note: frontmatter opening should not be preceded by whitespace
-  --> $DIR/frontmatter-whitespace-1.rs:1:1
+  --> $DIR/fence-indented.rs:1:1
    |
 LL |   ---
    | ^^
 
 error: unclosed frontmatter
-  --> $DIR/frontmatter-whitespace-1.rs:1:3
+  --> $DIR/fence-indented.rs:1:3
    |
 LL | /   ---
 LL | |
@@ -21,7 +21,7 @@ LL | |
    | |_^
    |
 note: frontmatter opening here was not closed
-  --> $DIR/frontmatter-whitespace-1.rs:1:3
+  --> $DIR/fence-indented.rs:1:3
    |
 LL |   ---
    |   ^^^
diff --git a/tests/ui/frontmatter/mismatch-1.rs b/tests/ui/frontmatter/fence-mismatch-1.rs
similarity index 100%
rename from tests/ui/frontmatter/mismatch-1.rs
rename to tests/ui/frontmatter/fence-mismatch-1.rs
diff --git a/tests/ui/frontmatter/mismatch-1.stderr b/tests/ui/frontmatter/fence-mismatch-1.stderr
similarity index 88%
rename from tests/ui/frontmatter/mismatch-1.stderr
rename to tests/ui/frontmatter/fence-mismatch-1.stderr
index b6e29294d9e1..f971039522cd 100644
--- a/tests/ui/frontmatter/mismatch-1.stderr
+++ b/tests/ui/frontmatter/fence-mismatch-1.stderr
@@ -1,5 +1,5 @@
 error: frontmatter close does not match the opening
-  --> $DIR/mismatch-1.rs:1:1
+  --> $DIR/fence-mismatch-1.rs:1:1
    |
 LL |   ---cargo
    |   ^--
diff --git a/tests/ui/frontmatter/mismatch-2.rs b/tests/ui/frontmatter/fence-mismatch-2.rs
similarity index 100%
rename from tests/ui/frontmatter/mismatch-2.rs
rename to tests/ui/frontmatter/fence-mismatch-2.rs
diff --git a/tests/ui/frontmatter/mismatch-2.stderr b/tests/ui/frontmatter/fence-mismatch-2.stderr
similarity index 84%
rename from tests/ui/frontmatter/mismatch-2.stderr
rename to tests/ui/frontmatter/fence-mismatch-2.stderr
index 90bb7b80bcea..8378ae20901e 100644
--- a/tests/ui/frontmatter/mismatch-2.stderr
+++ b/tests/ui/frontmatter/fence-mismatch-2.stderr
@@ -1,5 +1,5 @@
 error: frontmatter close does not match the opening
-  --> $DIR/mismatch-2.rs:1:1
+  --> $DIR/fence-mismatch-2.rs:1:1
    |
 LL |   ----cargo
    |   ^---
@@ -13,7 +13,7 @@ LL | | ---cargo
    |   ...while the close has 3 dashes
 
 error: extra characters after frontmatter close are not allowed
-  --> $DIR/mismatch-2.rs:3:1
+  --> $DIR/fence-mismatch-2.rs:3:1
    |
 LL | ---cargo
    | ^^^^^^^^
diff --git a/tests/ui/frontmatter/unclosed-1.rs b/tests/ui/frontmatter/fence-unclosed-1.rs
similarity index 100%
rename from tests/ui/frontmatter/unclosed-1.rs
rename to tests/ui/frontmatter/fence-unclosed-1.rs
diff --git a/tests/ui/frontmatter/unclosed-1.stderr b/tests/ui/frontmatter/fence-unclosed-1.stderr
similarity index 73%
rename from tests/ui/frontmatter/unclosed-1.stderr
rename to tests/ui/frontmatter/fence-unclosed-1.stderr
index 04031d128398..f96da8cc6689 100644
--- a/tests/ui/frontmatter/unclosed-1.stderr
+++ b/tests/ui/frontmatter/fence-unclosed-1.stderr
@@ -1,5 +1,5 @@
 error: unclosed frontmatter
-  --> $DIR/unclosed-1.rs:1:1
+  --> $DIR/fence-unclosed-1.rs:1:1
    |
 LL | / ----cargo
 ...  |
@@ -7,7 +7,7 @@ LL | |
    | |_^
    |
 note: frontmatter opening here was not closed
-  --> $DIR/unclosed-1.rs:1:1
+  --> $DIR/fence-unclosed-1.rs:1:1
    |
 LL | ----cargo
    | ^^^^
diff --git a/tests/ui/frontmatter/unclosed-2.rs b/tests/ui/frontmatter/fence-unclosed-2.rs
similarity index 100%
rename from tests/ui/frontmatter/unclosed-2.rs
rename to tests/ui/frontmatter/fence-unclosed-2.rs
diff --git a/tests/ui/frontmatter/unclosed-2.stderr b/tests/ui/frontmatter/fence-unclosed-2.stderr
similarity index 86%
rename from tests/ui/frontmatter/unclosed-2.stderr
rename to tests/ui/frontmatter/fence-unclosed-2.stderr
index 0a4022c1557b..7eeb30bed528 100644
--- a/tests/ui/frontmatter/unclosed-2.stderr
+++ b/tests/ui/frontmatter/fence-unclosed-2.stderr
@@ -1,5 +1,5 @@
 error: unclosed frontmatter
-  --> $DIR/unclosed-2.rs:1:1
+  --> $DIR/fence-unclosed-2.rs:1:1
    |
 LL | / ----cargo
 ...  |
@@ -8,13 +8,13 @@ LL | | }
    | |__^
    |
 note: frontmatter opening here was not closed
-  --> $DIR/unclosed-2.rs:1:1
+  --> $DIR/fence-unclosed-2.rs:1:1
    |
 LL | ----cargo
    | ^^^^
 
 error[E0658]: frontmatters are experimental
-  --> $DIR/unclosed-2.rs:1:1
+  --> $DIR/fence-unclosed-2.rs:1:1
    |
 LL | / ----cargo
 ...  |
diff --git a/tests/ui/frontmatter/unclosed-3.rs b/tests/ui/frontmatter/fence-unclosed-3.rs
similarity index 100%
rename from tests/ui/frontmatter/unclosed-3.rs
rename to tests/ui/frontmatter/fence-unclosed-3.rs
diff --git a/tests/ui/frontmatter/unclosed-3.stderr b/tests/ui/frontmatter/fence-unclosed-3.stderr
similarity index 79%
rename from tests/ui/frontmatter/unclosed-3.stderr
rename to tests/ui/frontmatter/fence-unclosed-3.stderr
index cd69cb000408..aa3e8fa3c01d 100644
--- a/tests/ui/frontmatter/unclosed-3.stderr
+++ b/tests/ui/frontmatter/fence-unclosed-3.stderr
@@ -1,17 +1,17 @@
 error: invalid preceding whitespace for frontmatter close
-  --> $DIR/unclosed-3.rs:12:1
+  --> $DIR/fence-unclosed-3.rs:12:1
    |
 LL |     ---x
    | ^^^^^^^^
    |
 note: frontmatter close should not be preceded by whitespace
-  --> $DIR/unclosed-3.rs:12:1
+  --> $DIR/fence-unclosed-3.rs:12:1
    |
 LL |     ---x
    | ^^^^
 
 error: frontmatter close does not match the opening
-  --> $DIR/unclosed-3.rs:1:1
+  --> $DIR/fence-unclosed-3.rs:1:1
    |
 LL |   ----cargo
    |   ^---
@@ -26,13 +26,13 @@ LL | |     ---x
    |   ...while the close has 3 dashes
 
 error: extra characters after frontmatter close are not allowed
-  --> $DIR/unclosed-3.rs:12:1
+  --> $DIR/fence-unclosed-3.rs:12:1
    |
 LL |     ---x
    | ^^^^^^^^
 
 error: unexpected closing delimiter: `}`
-  --> $DIR/unclosed-3.rs:15:1
+  --> $DIR/fence-unclosed-3.rs:15:1
    |
 LL | }
    | ^ unexpected closing delimiter
diff --git a/tests/ui/frontmatter/unclosed-4.rs b/tests/ui/frontmatter/fence-unclosed-4.rs
similarity index 100%
rename from tests/ui/frontmatter/unclosed-4.rs
rename to tests/ui/frontmatter/fence-unclosed-4.rs
diff --git a/tests/ui/frontmatter/unclosed-4.stderr b/tests/ui/frontmatter/fence-unclosed-4.stderr
similarity index 73%
rename from tests/ui/frontmatter/unclosed-4.stderr
rename to tests/ui/frontmatter/fence-unclosed-4.stderr
index b3ba56937bba..cb597d16de28 100644
--- a/tests/ui/frontmatter/unclosed-4.stderr
+++ b/tests/ui/frontmatter/fence-unclosed-4.stderr
@@ -1,5 +1,5 @@
 error: unclosed frontmatter
-  --> $DIR/unclosed-4.rs:1:1
+  --> $DIR/fence-unclosed-4.rs:1:1
    |
 LL | / ----cargo
 LL | |
@@ -7,7 +7,7 @@ LL | |
    | |_^
    |
 note: frontmatter opening here was not closed
-  --> $DIR/unclosed-4.rs:1:1
+  --> $DIR/fence-unclosed-4.rs:1:1
    |
 LL | ----cargo
    | ^^^^
diff --git a/tests/ui/frontmatter/unclosed-5.rs b/tests/ui/frontmatter/fence-unclosed-5.rs
similarity index 100%
rename from tests/ui/frontmatter/unclosed-5.rs
rename to tests/ui/frontmatter/fence-unclosed-5.rs
diff --git a/tests/ui/frontmatter/unclosed-5.stderr b/tests/ui/frontmatter/fence-unclosed-5.stderr
similarity index 85%
rename from tests/ui/frontmatter/unclosed-5.stderr
rename to tests/ui/frontmatter/fence-unclosed-5.stderr
index e904014a175a..09531f3c0341 100644
--- a/tests/ui/frontmatter/unclosed-5.stderr
+++ b/tests/ui/frontmatter/fence-unclosed-5.stderr
@@ -1,5 +1,5 @@
 error: unclosed frontmatter
-  --> $DIR/unclosed-5.rs:1:1
+  --> $DIR/fence-unclosed-5.rs:1:1
    |
 LL | / ----cargo
 ...  |
@@ -7,13 +7,13 @@ LL | |
    | |_^
    |
 note: frontmatter opening here was not closed
-  --> $DIR/unclosed-5.rs:1:1
+  --> $DIR/fence-unclosed-5.rs:1:1
    |
 LL | ----cargo
    | ^^^^
 
 error[E0658]: frontmatters are experimental
-  --> $DIR/unclosed-5.rs:1:1
+  --> $DIR/fence-unclosed-5.rs:1:1
    |
 LL | / ----cargo
 ...  |
diff --git a/tests/ui/frontmatter/unclosed-6.rs b/tests/ui/frontmatter/fence-unclosed-6.rs
similarity index 100%
rename from tests/ui/frontmatter/unclosed-6.rs
rename to tests/ui/frontmatter/fence-unclosed-6.rs
diff --git a/tests/ui/frontmatter/unclosed-6.stderr b/tests/ui/frontmatter/fence-unclosed-6.stderr
similarity index 75%
rename from tests/ui/frontmatter/unclosed-6.stderr
rename to tests/ui/frontmatter/fence-unclosed-6.stderr
index 01a13e87268c..6b653f0781c6 100644
--- a/tests/ui/frontmatter/unclosed-6.stderr
+++ b/tests/ui/frontmatter/fence-unclosed-6.stderr
@@ -1,5 +1,5 @@
 error: unclosed frontmatter
-  --> $DIR/unclosed-6.rs:1:1
+  --> $DIR/fence-unclosed-6.rs:1:1
    |
 LL | / ---
 LL | |
@@ -10,7 +10,7 @@ LL | |
    | |_^
    |
 note: frontmatter opening here was not closed
-  --> $DIR/unclosed-6.rs:1:1
+  --> $DIR/fence-unclosed-6.rs:1:1
    |
 LL | ---
    | ^^^
diff --git a/tests/ui/frontmatter/frontmatter-whitespace-3.rs b/tests/ui/frontmatter/fence-whitespace-trailing-1.rs
similarity index 100%
rename from tests/ui/frontmatter/frontmatter-whitespace-3.rs
rename to tests/ui/frontmatter/fence-whitespace-trailing-1.rs
diff --git a/tests/ui/frontmatter/frontmatter-whitespace-4.rs b/tests/ui/frontmatter/fence-whitespace-trailing-2.rs
similarity index 100%
rename from tests/ui/frontmatter/frontmatter-whitespace-4.rs
rename to tests/ui/frontmatter/fence-whitespace-trailing-2.rs
diff --git a/tests/ui/frontmatter/infostring-fail.rs b/tests/ui/frontmatter/infostring-comma.rs
similarity index 100%
rename from tests/ui/frontmatter/infostring-fail.rs
rename to tests/ui/frontmatter/infostring-comma.rs
diff --git a/tests/ui/frontmatter/infostring-fail.stderr b/tests/ui/frontmatter/infostring-comma.stderr
similarity index 86%
rename from tests/ui/frontmatter/infostring-fail.stderr
rename to tests/ui/frontmatter/infostring-comma.stderr
index 6b264abc90f1..4463dd414c4f 100644
--- a/tests/ui/frontmatter/infostring-fail.stderr
+++ b/tests/ui/frontmatter/infostring-comma.stderr
@@ -1,5 +1,5 @@
 error: invalid infostring for frontmatter
-  --> $DIR/infostring-fail.rs:1:4
+  --> $DIR/infostring-comma.rs:1:4
    |
 LL | ---cargo,clippy
    |    ^^^^^^^^^^^^
diff --git a/tests/ui/frontmatter/dot-in-infostring-leading.rs b/tests/ui/frontmatter/infostring-dot-leading.rs
similarity index 100%
rename from tests/ui/frontmatter/dot-in-infostring-leading.rs
rename to tests/ui/frontmatter/infostring-dot-leading.rs
diff --git a/tests/ui/frontmatter/dot-in-infostring-leading.stderr b/tests/ui/frontmatter/infostring-dot-leading.stderr
similarity index 83%
rename from tests/ui/frontmatter/dot-in-infostring-leading.stderr
rename to tests/ui/frontmatter/infostring-dot-leading.stderr
index bc86bd80eece..8c15f8f7536e 100644
--- a/tests/ui/frontmatter/dot-in-infostring-leading.stderr
+++ b/tests/ui/frontmatter/infostring-dot-leading.stderr
@@ -1,5 +1,5 @@
 error: invalid infostring for frontmatter
-  --> $DIR/dot-in-infostring-leading.rs:1:4
+  --> $DIR/infostring-dot-leading.rs:1:4
    |
 LL | ---.toml
    |    ^^^^^
diff --git a/tests/ui/frontmatter/dot-in-infostring-non-leading.rs b/tests/ui/frontmatter/infostring-dot-nonleading.rs
similarity index 100%
rename from tests/ui/frontmatter/dot-in-infostring-non-leading.rs
rename to tests/ui/frontmatter/infostring-dot-nonleading.rs
diff --git a/tests/ui/frontmatter/hyphen-in-infostring-leading.rs b/tests/ui/frontmatter/infostring-hyphen-leading.rs
similarity index 100%
rename from tests/ui/frontmatter/hyphen-in-infostring-leading.rs
rename to tests/ui/frontmatter/infostring-hyphen-leading.rs
diff --git a/tests/ui/frontmatter/hyphen-in-infostring-leading.stderr b/tests/ui/frontmatter/infostring-hyphen-leading.stderr
similarity index 82%
rename from tests/ui/frontmatter/hyphen-in-infostring-leading.stderr
rename to tests/ui/frontmatter/infostring-hyphen-leading.stderr
index 167b537d62be..646936b92830 100644
--- a/tests/ui/frontmatter/hyphen-in-infostring-leading.stderr
+++ b/tests/ui/frontmatter/infostring-hyphen-leading.stderr
@@ -1,5 +1,5 @@
 error: invalid infostring for frontmatter
-  --> $DIR/hyphen-in-infostring-leading.rs:1:4
+  --> $DIR/infostring-hyphen-leading.rs:1:4
    |
 LL | --- -toml
    |    ^^^^^^
diff --git a/tests/ui/frontmatter/hyphen-in-infostring-non-leading.rs b/tests/ui/frontmatter/infostring-hyphen-nonleading.rs
similarity index 100%
rename from tests/ui/frontmatter/hyphen-in-infostring-non-leading.rs
rename to tests/ui/frontmatter/infostring-hyphen-nonleading.rs
diff --git a/tests/ui/frontmatter/space-in-infostring.rs b/tests/ui/frontmatter/infostring-space.rs
similarity index 100%
rename from tests/ui/frontmatter/space-in-infostring.rs
rename to tests/ui/frontmatter/infostring-space.rs
diff --git a/tests/ui/frontmatter/space-in-infostring.stderr b/tests/ui/frontmatter/infostring-space.stderr
similarity index 86%
rename from tests/ui/frontmatter/space-in-infostring.stderr
rename to tests/ui/frontmatter/infostring-space.stderr
index b876ddae782e..aa8d08d60904 100644
--- a/tests/ui/frontmatter/space-in-infostring.stderr
+++ b/tests/ui/frontmatter/infostring-space.stderr
@@ -1,5 +1,5 @@
 error: invalid infostring for frontmatter
-  --> $DIR/space-in-infostring.rs:1:4
+  --> $DIR/infostring-space.rs:1:4
    |
 LL | --- cargo clippy
    |    ^^^^^^^^^^^^^
diff --git a/tests/ui/frontmatter/shebang.rs b/tests/ui/frontmatter/location-after-shebang.rs
similarity index 100%
rename from tests/ui/frontmatter/shebang.rs
rename to tests/ui/frontmatter/location-after-shebang.rs
diff --git a/tests/ui/frontmatter/frontmatter-after-tokens.rs b/tests/ui/frontmatter/location-after-tokens.rs
similarity index 100%
rename from tests/ui/frontmatter/frontmatter-after-tokens.rs
rename to tests/ui/frontmatter/location-after-tokens.rs
diff --git a/tests/ui/frontmatter/frontmatter-after-tokens.stderr b/tests/ui/frontmatter/location-after-tokens.stderr
similarity index 84%
rename from tests/ui/frontmatter/frontmatter-after-tokens.stderr
rename to tests/ui/frontmatter/location-after-tokens.stderr
index 919456924d02..b8b38167ace5 100644
--- a/tests/ui/frontmatter/frontmatter-after-tokens.stderr
+++ b/tests/ui/frontmatter/location-after-tokens.stderr
@@ -1,5 +1,5 @@
 error: expected item, found `-`
-  --> $DIR/frontmatter-after-tokens.rs:3:1
+  --> $DIR/location-after-tokens.rs:3:1
    |
 LL | ---
    | ^ expected item
diff --git a/tests/ui/frontmatter/include-in-expr-ctxt.rs b/tests/ui/frontmatter/location-include-in-expr-ctxt.rs
similarity index 100%
rename from tests/ui/frontmatter/include-in-expr-ctxt.rs
rename to tests/ui/frontmatter/location-include-in-expr-ctxt.rs
diff --git a/tests/ui/frontmatter/include-in-item-ctxt.rs b/tests/ui/frontmatter/location-include-in-item-ctxt.rs
similarity index 100%
rename from tests/ui/frontmatter/include-in-item-ctxt.rs
rename to tests/ui/frontmatter/location-include-in-item-ctxt.rs
diff --git a/tests/ui/frontmatter/proc-macro-observer.rs b/tests/ui/frontmatter/location-proc-macro-observer.rs
similarity index 100%
rename from tests/ui/frontmatter/proc-macro-observer.rs
rename to tests/ui/frontmatter/location-proc-macro-observer.rs
diff --git a/tests/ui/issues/issue-17252.stderr b/tests/ui/issues/issue-17252.stderr
index 56bc32b19ab7..b0d9d94e07dd 100644
--- a/tests/ui/issues/issue-17252.stderr
+++ b/tests/ui/issues/issue-17252.stderr
@@ -1,31 +1,39 @@
-error[E0391]: cycle detected when simplifying constant for the type system `FOO`
+error[E0391]: cycle detected when checking if `FOO` is a trivial const
   --> $DIR/issue-17252.rs:1:1
    |
 LL | const FOO: usize = FOO;
    | ^^^^^^^^^^^^^^^^
    |
-note: ...which requires const-evaluating + checking `FOO`...
-  --> $DIR/issue-17252.rs:1:20
+note: ...which requires building MIR for `FOO`...
+  --> $DIR/issue-17252.rs:1:1
    |
 LL | const FOO: usize = FOO;
-   |                    ^^^
-   = note: ...which again requires simplifying constant for the type system `FOO`, completing the cycle
-   = note: cycle used when running analysis passes on this crate
+   | ^^^^^^^^^^^^^^^^
+   = note: ...which again requires checking if `FOO` is a trivial const, completing the cycle
+note: cycle used when simplifying constant for the type system `FOO`
+  --> $DIR/issue-17252.rs:1:1
+   |
+LL | const FOO: usize = FOO;
+   | ^^^^^^^^^^^^^^^^
    = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
 
-error[E0391]: cycle detected when simplifying constant for the type system `main::BAR`
+error[E0391]: cycle detected when checking if `main::BAR` is a trivial const
   --> $DIR/issue-17252.rs:6:9
    |
 LL |         const BAR: usize = BAR;
    |         ^^^^^^^^^^^^^^^^
    |
-note: ...which requires const-evaluating + checking `main::BAR`...
-  --> $DIR/issue-17252.rs:6:28
+note: ...which requires building MIR for `main::BAR`...
+  --> $DIR/issue-17252.rs:6:9
    |
 LL |         const BAR: usize = BAR;
-   |                            ^^^
-   = note: ...which again requires simplifying constant for the type system `main::BAR`, completing the cycle
-   = note: cycle used when running analysis passes on this crate
+   |         ^^^^^^^^^^^^^^^^
+   = note: ...which again requires checking if `main::BAR` is a trivial const, completing the cycle
+note: cycle used when simplifying constant for the type system `main::BAR`
+  --> $DIR/issue-17252.rs:6:9
+   |
+LL |         const BAR: usize = BAR;
+   |         ^^^^^^^^^^^^^^^^
    = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
 
 error: aborting due to 2 previous errors
diff --git a/tests/ui/iterators/collect-into-array.rs b/tests/ui/iterators/collect-into-array.rs
index 99d0d9bd7355..b0d6d48b6b44 100644
--- a/tests/ui/iterators/collect-into-array.rs
+++ b/tests/ui/iterators/collect-into-array.rs
@@ -1,6 +1,7 @@
 fn main() {
     let whatever: [u32; 10] = (0..10).collect();
     //~^ ERROR an array of type `[u32; 10]` cannot be built directly from an iterator
+    //~| NOTE required by a bound introduced by this call
     //~| NOTE try collecting into a `Vec<{integer}>`, then using `.try_into()`
     //~| NOTE required by a bound in `collect`
 }
diff --git a/tests/ui/iterators/collect-into-array.stderr b/tests/ui/iterators/collect-into-array.stderr
index 38e5de803ccf..6b6e8552ed8d 100644
--- a/tests/ui/iterators/collect-into-array.stderr
+++ b/tests/ui/iterators/collect-into-array.stderr
@@ -1,8 +1,10 @@
 error[E0277]: an array of type `[u32; 10]` cannot be built directly from an iterator
-  --> $DIR/collect-into-array.rs:2:39
+  --> $DIR/collect-into-array.rs:2:32
    |
 LL |     let whatever: [u32; 10] = (0..10).collect();
-   |                                       ^^^^^^^ try collecting into a `Vec<{integer}>`, then using `.try_into()`
+   |                                ^^^^^  ------- required by a bound introduced by this call
+   |                                |
+   |                                try collecting into a `Vec<{integer}>`, then using `.try_into()`
    |
    = help: the trait `FromIterator<{integer}>` is not implemented for `[u32; 10]`
 note: required by a bound in `collect`
diff --git a/tests/ui/iterators/collect-into-slice.rs b/tests/ui/iterators/collect-into-slice.rs
index 120e56a6549e..c90cfa4e90d3 100644
--- a/tests/ui/iterators/collect-into-slice.rs
+++ b/tests/ui/iterators/collect-into-slice.rs
@@ -5,6 +5,7 @@ fn process_slice(data: &[i32]) {
 fn main() {
     let some_generated_vec = (0..10).collect();
     //~^ ERROR the size for values of type `[i32]` cannot be known at compilation time
+    //~| NOTE required by a bound introduced by this call
     //~| ERROR the size for values of type `[i32]` cannot be known at compilation time
     //~| ERROR a slice of type `[i32]` cannot be built since `[i32]` has no definite size
     //~| NOTE try explicitly collecting into a `Vec<{integer}>`
@@ -17,6 +18,7 @@ fn main() {
 
     let some_generated_vec = (0..10).collect();
     //~^ ERROR a slice of type `&[i32]` cannot be built since we need to store the elements somewhere
+    //~| NOTE required by a bound introduced by this call
     //~| NOTE try explicitly collecting into a `Vec<{integer}>`
     //~| NOTE required by a bound in `collect`
     process_slice(some_generated_vec);
diff --git a/tests/ui/iterators/collect-into-slice.stderr b/tests/ui/iterators/collect-into-slice.stderr
index e5729a2badc7..b5444a71cc17 100644
--- a/tests/ui/iterators/collect-into-slice.stderr
+++ b/tests/ui/iterators/collect-into-slice.stderr
@@ -1,8 +1,10 @@
 error[E0277]: a slice of type `[i32]` cannot be built since `[i32]` has no definite size
-  --> $DIR/collect-into-slice.rs:6:38
+  --> $DIR/collect-into-slice.rs:6:31
    |
 LL |     let some_generated_vec = (0..10).collect();
-   |                                      ^^^^^^^ try explicitly collecting into a `Vec<{integer}>`
+   |                               ^^^^^  ------- required by a bound introduced by this call
+   |                               |
+   |                               try explicitly collecting into a `Vec<{integer}>`
    |
    = help: the trait `FromIterator<{integer}>` is not implemented for `[i32]`
 note: required by a bound in `collect`
@@ -28,10 +30,12 @@ note: required by an implicit `Sized` bound in `collect`
   --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
 
 error[E0277]: a slice of type `&[i32]` cannot be built since we need to store the elements somewhere
-  --> $DIR/collect-into-slice.rs:18:38
+  --> $DIR/collect-into-slice.rs:19:31
    |
 LL |     let some_generated_vec = (0..10).collect();
-   |                                      ^^^^^^^ try explicitly collecting into a `Vec<{integer}>`
+   |                               ^^^^^  ------- required by a bound introduced by this call
+   |                               |
+   |                               try explicitly collecting into a `Vec<{integer}>`
    |
    = help: the trait `FromIterator<{integer}>` is not implemented for `&[i32]`
 note: required by a bound in `collect`
diff --git a/tests/ui/lint/improper-ctypes/lint-ctypes.rs b/tests/ui/lint/improper-ctypes/lint-ctypes.rs
index 7dc06079fa32..5d90e22e4b49 100644
--- a/tests/ui/lint/improper-ctypes/lint-ctypes.rs
+++ b/tests/ui/lint/improper-ctypes/lint-ctypes.rs
@@ -38,6 +38,7 @@ pub struct TransparentLifetime<'a>(*const u8, PhantomData<&'a ()>);
 #[repr(transparent)]
 pub struct TransparentUnit(f32, PhantomData);
 #[repr(transparent)]
+#[allow(repr_transparent_non_zst_fields)]
 pub struct TransparentCustomZst(i32, ZeroSize);
 
 #[repr(C)]
diff --git a/tests/ui/lint/improper-ctypes/lint-ctypes.stderr b/tests/ui/lint/improper-ctypes/lint-ctypes.stderr
index 6f8b951c53d7..ef23f3ca6c91 100644
--- a/tests/ui/lint/improper-ctypes/lint-ctypes.stderr
+++ b/tests/ui/lint/improper-ctypes/lint-ctypes.stderr
@@ -1,5 +1,5 @@
 error: `extern` block uses type `Foo`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:47:28
+  --> $DIR/lint-ctypes.rs:48:28
    |
 LL |     pub fn ptr_type1(size: *const Foo);
    |                            ^^^^^^^^^^ not FFI-safe
@@ -18,7 +18,7 @@ LL | #![deny(improper_ctypes)]
    |         ^^^^^^^^^^^^^^^
 
 error: `extern` block uses type `Foo`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:48:28
+  --> $DIR/lint-ctypes.rs:49:28
    |
 LL |     pub fn ptr_type2(size: *const Foo);
    |                            ^^^^^^^^^^ not FFI-safe
@@ -32,7 +32,7 @@ LL | pub struct Foo;
    | ^^^^^^^^^^^^^^
 
 error: `extern` block uses type `((),)`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:50:25
+  --> $DIR/lint-ctypes.rs:51:25
    |
 LL |     pub fn ptr_tuple(p: *const ((),));
    |                         ^^^^^^^^^^^^ not FFI-safe
@@ -41,7 +41,7 @@ LL |     pub fn ptr_tuple(p: *const ((),));
    = note: tuples have unspecified layout
 
 error: `extern` block uses type `[u32]`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:51:26
+  --> $DIR/lint-ctypes.rs:52:26
    |
 LL |     pub fn slice_type(p: &[u32]);
    |                          ^^^^^^ not FFI-safe
@@ -50,7 +50,7 @@ LL |     pub fn slice_type(p: &[u32]);
    = note: slices have no C equivalent
 
 error: `extern` block uses type `str`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:52:24
+  --> $DIR/lint-ctypes.rs:53:24
    |
 LL |     pub fn str_type(p: &str);
    |                        ^^^^ not FFI-safe
@@ -59,7 +59,7 @@ LL |     pub fn str_type(p: &str);
    = note: string slices have no C equivalent
 
 error: `extern` block uses type `Box`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:53:24
+  --> $DIR/lint-ctypes.rs:54:24
    |
 LL |     pub fn box_type(p: Box);
    |                        ^^^^^^^^ not FFI-safe
@@ -68,7 +68,7 @@ LL |     pub fn box_type(p: Box);
    = note: this struct has unspecified layout
 
 error: `extern` block uses type `char`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:55:25
+  --> $DIR/lint-ctypes.rs:56:25
    |
 LL |     pub fn char_type(p: char);
    |                         ^^^^ not FFI-safe
@@ -77,7 +77,7 @@ LL |     pub fn char_type(p: char);
    = note: the `char` type has no C equivalent
 
 error: `extern` block uses type `dyn Bar`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:56:26
+  --> $DIR/lint-ctypes.rs:57:26
    |
 LL |     pub fn trait_type(p: &dyn Bar);
    |                          ^^^^^^^^ not FFI-safe
@@ -85,7 +85,7 @@ LL |     pub fn trait_type(p: &dyn Bar);
    = note: trait objects have no C equivalent
 
 error: `extern` block uses type `(i32, i32)`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:57:26
+  --> $DIR/lint-ctypes.rs:58:26
    |
 LL |     pub fn tuple_type(p: (i32, i32));
    |                          ^^^^^^^^^^ not FFI-safe
@@ -94,7 +94,7 @@ LL |     pub fn tuple_type(p: (i32, i32));
    = note: tuples have unspecified layout
 
 error: `extern` block uses type `(i32, i32)`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:58:27
+  --> $DIR/lint-ctypes.rs:59:27
    |
 LL |     pub fn tuple_type2(p: I32Pair);
    |                           ^^^^^^^ not FFI-safe
@@ -103,7 +103,7 @@ LL |     pub fn tuple_type2(p: I32Pair);
    = note: tuples have unspecified layout
 
 error: `extern` block uses type `ZeroSize`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:59:25
+  --> $DIR/lint-ctypes.rs:60:25
    |
 LL |     pub fn zero_size(p: ZeroSize);
    |                         ^^^^^^^^ not FFI-safe
@@ -117,20 +117,20 @@ LL | pub struct ZeroSize;
    | ^^^^^^^^^^^^^^^^^^^
 
 error: `extern` block uses type `ZeroSizeWithPhantomData`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:60:33
+  --> $DIR/lint-ctypes.rs:61:33
    |
 LL |     pub fn zero_size_phantom(p: ZeroSizeWithPhantomData);
    |                                 ^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
    |
    = note: composed only of `PhantomData`
 note: the type is defined here
-  --> $DIR/lint-ctypes.rs:44:1
+  --> $DIR/lint-ctypes.rs:45:1
    |
 LL | pub struct ZeroSizeWithPhantomData(::std::marker::PhantomData);
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `extern` block uses type `PhantomData`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:63:12
+  --> $DIR/lint-ctypes.rs:64:12
    |
 LL |         -> ::std::marker::PhantomData;
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -138,7 +138,7 @@ LL |         -> ::std::marker::PhantomData;
    = note: composed only of `PhantomData`
 
 error: `extern` block uses type `fn()`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:64:23
+  --> $DIR/lint-ctypes.rs:65:23
    |
 LL |     pub fn fn_type(p: RustFn);
    |                       ^^^^^^ not FFI-safe
@@ -147,7 +147,7 @@ LL |     pub fn fn_type(p: RustFn);
    = note: this function pointer has Rust-specific calling convention
 
 error: `extern` block uses type `fn()`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:65:24
+  --> $DIR/lint-ctypes.rs:66:24
    |
 LL |     pub fn fn_type2(p: fn());
    |                        ^^^^ not FFI-safe
@@ -156,7 +156,7 @@ LL |     pub fn fn_type2(p: fn());
    = note: this function pointer has Rust-specific calling convention
 
 error: `extern` block uses type `Box`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:66:28
+  --> $DIR/lint-ctypes.rs:67:28
    |
 LL |     pub fn fn_contained(p: RustBadRet);
    |                            ^^^^^^^^^^ not FFI-safe
@@ -165,7 +165,7 @@ LL |     pub fn fn_contained(p: RustBadRet);
    = note: this struct has unspecified layout
 
 error: `extern` block uses type `str`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:67:31
+  --> $DIR/lint-ctypes.rs:68:31
    |
 LL |     pub fn transparent_str(p: TransparentStr);
    |                               ^^^^^^^^^^^^^^ not FFI-safe
@@ -174,7 +174,7 @@ LL |     pub fn transparent_str(p: TransparentStr);
    = note: string slices have no C equivalent
 
 error: `extern` block uses type `Box`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:68:30
+  --> $DIR/lint-ctypes.rs:69:30
    |
 LL |     pub fn transparent_fn(p: TransparentBadFn);
    |                              ^^^^^^^^^^^^^^^^ not FFI-safe
@@ -183,7 +183,7 @@ LL |     pub fn transparent_fn(p: TransparentBadFn);
    = note: this struct has unspecified layout
 
 error: `extern` block uses type `[u8; 8]`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:69:27
+  --> $DIR/lint-ctypes.rs:70:27
    |
 LL |     pub fn raw_array(arr: [u8; 8]);
    |                           ^^^^^^^ not FFI-safe
@@ -192,7 +192,7 @@ LL |     pub fn raw_array(arr: [u8; 8]);
    = note: passing raw arrays by value is not FFI-safe
 
 error: `extern` block uses type `Option>`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:71:26
+  --> $DIR/lint-ctypes.rs:72:26
    |
 LL |     pub fn no_niche_a(a: Option>);
    |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -201,7 +201,7 @@ LL |     pub fn no_niche_a(a: Option>);
    = note: enum has no representation hint
 
 error: `extern` block uses type `Option>`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:73:26
+  --> $DIR/lint-ctypes.rs:74:26
    |
 LL |     pub fn no_niche_b(b: Option>);
    |                          ^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -211,3 +211,14 @@ LL |     pub fn no_niche_b(b: Option>);
 
 error: aborting due to 21 previous errors
 
+Future incompatibility report: Future breakage diagnostic:
+warning: zero-sized fields in `repr(transparent)` cannot contain `repr(C)` types
+  --> $DIR/lint-ctypes.rs:42:38
+   |
+LL | pub struct TransparentCustomZst(i32, ZeroSize);
+   |                                      ^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #78586 
+   = note: this field contains `ZeroSize`, which is a `#[repr(C)]` type, so it is not guaranteed to be zero-sized on all targets.
+
diff --git a/tests/ui/lint/improper-ctypes/lint-fn.rs b/tests/ui/lint/improper-ctypes/lint-fn.rs
index 0b84098e3906..e71febb493dc 100644
--- a/tests/ui/lint/improper-ctypes/lint-fn.rs
+++ b/tests/ui/lint/improper-ctypes/lint-fn.rs
@@ -54,6 +54,7 @@ pub struct TransparentLifetime<'a>(*const u8, PhantomData<&'a ()>);
 pub struct TransparentUnit(f32, PhantomData);
 
 #[repr(transparent)]
+#[allow(repr_transparent_non_zst_fields)]
 pub struct TransparentCustomZst(i32, ZeroSize);
 
 #[repr(C)]
diff --git a/tests/ui/lint/improper-ctypes/lint-fn.stderr b/tests/ui/lint/improper-ctypes/lint-fn.stderr
index 34e3bd021b92..a0d1ab232c6a 100644
--- a/tests/ui/lint/improper-ctypes/lint-fn.stderr
+++ b/tests/ui/lint/improper-ctypes/lint-fn.stderr
@@ -1,5 +1,5 @@
 error: `extern` fn uses type `[u32]`, which is not FFI-safe
-  --> $DIR/lint-fn.rs:70:33
+  --> $DIR/lint-fn.rs:71:33
    |
 LL | pub extern "C" fn slice_type(p: &[u32]) { }
    |                                 ^^^^^^ not FFI-safe
@@ -13,7 +13,7 @@ LL | #![deny(improper_ctypes_definitions)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `extern` fn uses type `str`, which is not FFI-safe
-  --> $DIR/lint-fn.rs:73:31
+  --> $DIR/lint-fn.rs:74:31
    |
 LL | pub extern "C" fn str_type(p: &str) { }
    |                               ^^^^ not FFI-safe
@@ -22,7 +22,7 @@ LL | pub extern "C" fn str_type(p: &str) { }
    = note: string slices have no C equivalent
 
 error: `extern` fn uses type `Box<[u8]>`, which is not FFI-safe
-  --> $DIR/lint-fn.rs:80:34
+  --> $DIR/lint-fn.rs:81:34
    |
 LL | pub extern "C" fn boxed_slice(p: Box<[u8]>) { }
    |                                  ^^^^^^^^^ not FFI-safe
@@ -30,7 +30,7 @@ LL | pub extern "C" fn boxed_slice(p: Box<[u8]>) { }
    = note: box cannot be represented as a single pointer
 
 error: `extern` fn uses type `Box`, which is not FFI-safe
-  --> $DIR/lint-fn.rs:83:35
+  --> $DIR/lint-fn.rs:84:35
    |
 LL | pub extern "C" fn boxed_string(p: Box) { }
    |                                   ^^^^^^^^ not FFI-safe
@@ -38,7 +38,7 @@ LL | pub extern "C" fn boxed_string(p: Box) { }
    = note: box cannot be represented as a single pointer
 
 error: `extern` fn uses type `Box`, which is not FFI-safe
-  --> $DIR/lint-fn.rs:86:34
+  --> $DIR/lint-fn.rs:87:34
    |
 LL | pub extern "C" fn boxed_trait(p: Box) { }
    |                                  ^^^^^^^^^^^^^^ not FFI-safe
@@ -46,7 +46,7 @@ LL | pub extern "C" fn boxed_trait(p: Box) { }
    = note: box cannot be represented as a single pointer
 
 error: `extern` fn uses type `char`, which is not FFI-safe
-  --> $DIR/lint-fn.rs:89:32
+  --> $DIR/lint-fn.rs:90:32
    |
 LL | pub extern "C" fn char_type(p: char) { }
    |                                ^^^^ not FFI-safe
@@ -55,7 +55,7 @@ LL | pub extern "C" fn char_type(p: char) { }
    = note: the `char` type has no C equivalent
 
 error: `extern` fn uses type `(i32, i32)`, which is not FFI-safe
-  --> $DIR/lint-fn.rs:92:33
+  --> $DIR/lint-fn.rs:93:33
    |
 LL | pub extern "C" fn tuple_type(p: (i32, i32)) { }
    |                                 ^^^^^^^^^^ not FFI-safe
@@ -64,7 +64,7 @@ LL | pub extern "C" fn tuple_type(p: (i32, i32)) { }
    = note: tuples have unspecified layout
 
 error: `extern` fn uses type `(i32, i32)`, which is not FFI-safe
-  --> $DIR/lint-fn.rs:95:34
+  --> $DIR/lint-fn.rs:96:34
    |
 LL | pub extern "C" fn tuple_type2(p: I32Pair) { }
    |                                  ^^^^^^^ not FFI-safe
@@ -73,7 +73,7 @@ LL | pub extern "C" fn tuple_type2(p: I32Pair) { }
    = note: tuples have unspecified layout
 
 error: `extern` fn uses type `ZeroSize`, which is not FFI-safe
-  --> $DIR/lint-fn.rs:98:32
+  --> $DIR/lint-fn.rs:99:32
    |
 LL | pub extern "C" fn zero_size(p: ZeroSize) { }
    |                                ^^^^^^^^ not FFI-safe
@@ -87,20 +87,20 @@ LL | pub struct ZeroSize;
    | ^^^^^^^^^^^^^^^^^^^
 
 error: `extern` fn uses type `ZeroSizeWithPhantomData`, which is not FFI-safe
-  --> $DIR/lint-fn.rs:101:40
+  --> $DIR/lint-fn.rs:102:40
    |
 LL | pub extern "C" fn zero_size_phantom(p: ZeroSizeWithPhantomData) { }
    |                                        ^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
    |
    = note: composed only of `PhantomData`
 note: the type is defined here
-  --> $DIR/lint-fn.rs:60:1
+  --> $DIR/lint-fn.rs:61:1
    |
 LL | pub struct ZeroSizeWithPhantomData(PhantomData);
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `extern` fn uses type `PhantomData`, which is not FFI-safe
-  --> $DIR/lint-fn.rs:104:51
+  --> $DIR/lint-fn.rs:105:51
    |
 LL | pub extern "C" fn zero_size_phantom_toplevel() -> PhantomData {
    |                                                   ^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -108,7 +108,7 @@ LL | pub extern "C" fn zero_size_phantom_toplevel() -> PhantomData {
    = note: composed only of `PhantomData`
 
 error: `extern` fn uses type `fn()`, which is not FFI-safe
-  --> $DIR/lint-fn.rs:109:30
+  --> $DIR/lint-fn.rs:110:30
    |
 LL | pub extern "C" fn fn_type(p: RustFn) { }
    |                              ^^^^^^ not FFI-safe
@@ -117,7 +117,7 @@ LL | pub extern "C" fn fn_type(p: RustFn) { }
    = note: this function pointer has Rust-specific calling convention
 
 error: `extern` fn uses type `fn()`, which is not FFI-safe
-  --> $DIR/lint-fn.rs:112:31
+  --> $DIR/lint-fn.rs:113:31
    |
 LL | pub extern "C" fn fn_type2(p: fn()) { }
    |                               ^^^^ not FFI-safe
@@ -126,7 +126,7 @@ LL | pub extern "C" fn fn_type2(p: fn()) { }
    = note: this function pointer has Rust-specific calling convention
 
 error: `extern` fn uses type `str`, which is not FFI-safe
-  --> $DIR/lint-fn.rs:117:38
+  --> $DIR/lint-fn.rs:118:38
    |
 LL | pub extern "C" fn transparent_str(p: TransparentStr) { }
    |                                      ^^^^^^^^^^^^^^ not FFI-safe
@@ -135,7 +135,7 @@ LL | pub extern "C" fn transparent_str(p: TransparentStr) { }
    = note: string slices have no C equivalent
 
 error: `extern` fn uses type `PhantomData`, which is not FFI-safe
-  --> $DIR/lint-fn.rs:169:43
+  --> $DIR/lint-fn.rs:170:43
    |
 LL | pub extern "C" fn unused_generic2() -> PhantomData {
    |                                           ^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -143,7 +143,7 @@ LL | pub extern "C" fn unused_generic2() -> PhantomData {
    = note: composed only of `PhantomData`
 
 error: `extern` fn uses type `Vec`, which is not FFI-safe
-  --> $DIR/lint-fn.rs:182:39
+  --> $DIR/lint-fn.rs:183:39
    |
 LL | pub extern "C" fn used_generic4(x: Vec) { }
    |                                       ^^^^^^ not FFI-safe
@@ -152,7 +152,7 @@ LL | pub extern "C" fn used_generic4(x: Vec) { }
    = note: this struct has unspecified layout
 
 error: `extern` fn uses type `Vec`, which is not FFI-safe
-  --> $DIR/lint-fn.rs:185:41
+  --> $DIR/lint-fn.rs:186:41
    |
 LL | pub extern "C" fn used_generic5() -> Vec {
    |                                         ^^^^^^ not FFI-safe
@@ -162,3 +162,14 @@ LL | pub extern "C" fn used_generic5() -> Vec {
 
 error: aborting due to 17 previous errors
 
+Future incompatibility report: Future breakage diagnostic:
+warning: zero-sized fields in `repr(transparent)` cannot contain `repr(C)` types
+  --> $DIR/lint-fn.rs:58:38
+   |
+LL | pub struct TransparentCustomZst(i32, ZeroSize);
+   |                                      ^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #78586 
+   = note: this field contains `ZeroSize`, which is a `#[repr(C)]` type, so it is not guaranteed to be zero-sized on all targets.
+
diff --git a/tests/ui/operator-recovery/box-arithmetic-14915.stderr b/tests/ui/operator-recovery/box-arithmetic-14915.stderr
index 1dd80472bb87..5ff73fce2ff8 100644
--- a/tests/ui/operator-recovery/box-arithmetic-14915.stderr
+++ b/tests/ui/operator-recovery/box-arithmetic-14915.stderr
@@ -6,11 +6,11 @@ LL |     println!("{}", x + 1);
    |                    |
    |                    Box
    |
-note: the foreign item type `Box` doesn't implement `Add<{integer}>`
+note: `Box` does not implement `Add<{integer}>`
   --> $SRC_DIR/alloc/src/boxed.rs:LL:COL
   ::: $SRC_DIR/alloc/src/boxed.rs:LL:COL
    |
-   = note: not implement `Add<{integer}>`
+   = note: `Box` is defined in another crate
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/parallel-rustc/cycle_crash-issue-135870.rs b/tests/ui/parallel-rustc/cycle_crash-issue-135870.rs
index 4407e3aca802..d199bc14842a 100644
--- a/tests/ui/parallel-rustc/cycle_crash-issue-135870.rs
+++ b/tests/ui/parallel-rustc/cycle_crash-issue-135870.rs
@@ -3,6 +3,6 @@
 //@ compile-flags: -Z threads=2
 //@ compare-output-by-lines
 
-const FOO: usize = FOO; //~ ERROR cycle detected when simplifying constant for the type system `FOO`
+const FOO: usize = FOO; //~ ERROR cycle detected
 
 fn main() {}
diff --git a/tests/ui/parallel-rustc/cycle_crash-issue-135870.stderr b/tests/ui/parallel-rustc/cycle_crash-issue-135870.stderr
index 6e588d1f8946..b80d0f92fcfa 100644
--- a/tests/ui/parallel-rustc/cycle_crash-issue-135870.stderr
+++ b/tests/ui/parallel-rustc/cycle_crash-issue-135870.stderr
@@ -1,18 +1,12 @@
-error[E0391]: cycle detected when simplifying constant for the type system `FOO`
   --> $DIR/cycle_crash-issue-135870.rs:6:1
    |
 LL | const FOO: usize = FOO;
    | ^^^^^^^^^^^^^^^^
    |
-note: ...which requires const-evaluating + checking `FOO`...
-  --> $DIR/cycle_crash-issue-135870.rs:6:20
    |
 LL | const FOO: usize = FOO;
-   |                    ^^^
-   = note: ...which again requires simplifying constant for the type system `FOO`, completing the cycle
-   = note: cycle used when running analysis passes on this crate
    = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
 
 error: aborting due to 1 previous error
 
-For more information about this error, try `rustc --explain E0391`.
+For more information about this error, try `rustc --explain E0391`.
\ No newline at end of file
diff --git a/tests/ui/pattern/pattern-tyvar-2.stderr b/tests/ui/pattern/pattern-tyvar-2.stderr
index be52fa8b2394..6676d5129872 100644
--- a/tests/ui/pattern/pattern-tyvar-2.stderr
+++ b/tests/ui/pattern/pattern-tyvar-2.stderr
@@ -6,10 +6,10 @@ LL | fn foo(t: Bar) -> isize { match t { Bar::T1(_, Some(x)) => { return x * 3;
    |                                                                     |
    |                                                                     Vec
    |
-note: the foreign item type `Vec` doesn't implement `Mul<{integer}>`
+note: `Vec` does not implement `Mul<{integer}>`
   --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
    |
-   = note: not implement `Mul<{integer}>`
+   = note: `Vec` is defined in another crate
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/recursion/issue-23302-3.stderr b/tests/ui/recursion/issue-23302-3.stderr
index 8a152f589663..ddca746e165b 100644
--- a/tests/ui/recursion/issue-23302-3.stderr
+++ b/tests/ui/recursion/issue-23302-3.stderr
@@ -1,26 +1,30 @@
-error[E0391]: cycle detected when simplifying constant for the type system `A`
+error[E0391]: cycle detected when checking if `A` is a trivial const
   --> $DIR/issue-23302-3.rs:1:1
    |
 LL | const A: i32 = B;
    | ^^^^^^^^^^^^
    |
-note: ...which requires const-evaluating + checking `A`...
-  --> $DIR/issue-23302-3.rs:1:16
+note: ...which requires building MIR for `A`...
+  --> $DIR/issue-23302-3.rs:1:1
    |
 LL | const A: i32 = B;
-   |                ^
-note: ...which requires simplifying constant for the type system `B`...
+   | ^^^^^^^^^^^^
+note: ...which requires checking if `B` is a trivial const...
   --> $DIR/issue-23302-3.rs:3:1
    |
 LL | const B: i32 = A;
    | ^^^^^^^^^^^^
-note: ...which requires const-evaluating + checking `B`...
-  --> $DIR/issue-23302-3.rs:3:16
+note: ...which requires building MIR for `B`...
+  --> $DIR/issue-23302-3.rs:3:1
    |
 LL | const B: i32 = A;
-   |                ^
-   = note: ...which again requires simplifying constant for the type system `A`, completing the cycle
-   = note: cycle used when running analysis passes on this crate
+   | ^^^^^^^^^^^^
+   = note: ...which again requires checking if `A` is a trivial const, completing the cycle
+note: cycle used when simplifying constant for the type system `A`
+  --> $DIR/issue-23302-3.rs:1:1
+   |
+LL | const A: i32 = B;
+   | ^^^^^^^^^^^^
    = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
 
 error: aborting due to 1 previous error
diff --git a/tests/ui/repr/repr-transparent-non-exhaustive-transparent-in-prose.rs b/tests/ui/repr/repr-transparent-non-exhaustive-transparent-in-prose.rs
index 6ab34719f066..8de25ab26629 100644
--- a/tests/ui/repr/repr-transparent-non-exhaustive-transparent-in-prose.rs
+++ b/tests/ui/repr/repr-transparent-non-exhaustive-transparent-in-prose.rs
@@ -2,7 +2,7 @@
 
 #![feature(sync_unsafe_cell)]
 #![allow(unused)]
-#![deny(repr_transparent_external_private_fields)]
+#![deny(repr_transparent_non_zst_fields)]
 
 // https://github.com/rust-lang/rust/issues/129470
 
diff --git a/tests/ui/repr/repr-transparent-non-exhaustive.rs b/tests/ui/repr/repr-transparent-non-exhaustive.rs
index 38bab0163b4c..9188d6df3446 100644
--- a/tests/ui/repr/repr-transparent-non-exhaustive.rs
+++ b/tests/ui/repr/repr-transparent-non-exhaustive.rs
@@ -1,4 +1,4 @@
-#![deny(repr_transparent_external_private_fields)]
+#![deny(repr_transparent_non_zst_fields)]
 
 //@ aux-build: repr-transparent-non-exhaustive.rs
 extern crate repr_transparent_non_exhaustive;
@@ -42,7 +42,7 @@ pub struct T4(Sized, ExternalIndirection<(InternalPrivate, InternalNonExhaustive
 
 #[repr(transparent)]
 pub struct T5(Sized, Private);
-//~^ ERROR zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types
+//~^ ERROR zero-sized fields in `repr(transparent)` cannot contain external types with private fields
 //~| WARN this was previously accepted by the compiler
 
 #[repr(transparent)]
@@ -67,7 +67,7 @@ pub struct T8(Sized, NonExhaustiveVariant);
 
 #[repr(transparent)]
 pub struct T9(Sized, InternalIndirection);
-//~^ ERROR zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types
+//~^ ERROR zero-sized fields in `repr(transparent)` cannot contain external types with private fields
 //~| WARN this was previously accepted by the compiler
 
 #[repr(transparent)]
@@ -87,7 +87,7 @@ pub struct T12(Sized, InternalIndirection);
 
 #[repr(transparent)]
 pub struct T13(Sized, ExternalIndirection);
-//~^ ERROR zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types
+//~^ ERROR zero-sized fields in `repr(transparent)` cannot contain external types with private fields
 //~| WARN this was previously accepted by the compiler
 
 #[repr(transparent)]
@@ -117,7 +117,7 @@ pub struct T18(NonExhaustive, NonExhaustive);
 
 #[repr(transparent)]
 pub struct T19(NonExhaustive, Private);
-//~^ ERROR zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types
+//~^ ERROR zero-sized fields in `repr(transparent)` cannot contain external types with private fields
 //~| WARN this was previously accepted by the compiler
 
 #[repr(transparent)]
diff --git a/tests/ui/repr/repr-transparent-non-exhaustive.stderr b/tests/ui/repr/repr-transparent-non-exhaustive.stderr
index 27ba6e82a539..ac5493bf7e59 100644
--- a/tests/ui/repr/repr-transparent-non-exhaustive.stderr
+++ b/tests/ui/repr/repr-transparent-non-exhaustive.stderr
@@ -1,4 +1,4 @@
-error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types
+error: zero-sized fields in `repr(transparent)` cannot contain external types with private fields
   --> $DIR/repr-transparent-non-exhaustive.rs:44:22
    |
 LL | pub struct T5(Sized, Private);
@@ -6,12 +6,12 @@ LL | pub struct T5(Sized, Private);
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #78586 
-   = note: this struct contains `Private`, which contains private fields, and makes it not a breaking change to become non-zero-sized in the future.
+   = note: this field contains `Private`, which contains private fields, so it could become non-zero-sized in the future.
 note: the lint level is defined here
   --> $DIR/repr-transparent-non-exhaustive.rs:1:9
    |
-LL | #![deny(repr_transparent_external_private_fields)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #![deny(repr_transparent_non_zst_fields)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types
   --> $DIR/repr-transparent-non-exhaustive.rs:49:22
@@ -21,7 +21,7 @@ LL | pub struct T6(Sized, NonExhaustive);
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #78586 
-   = note: this struct contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future.
+   = note: this field contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future.
 
 error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types
   --> $DIR/repr-transparent-non-exhaustive.rs:54:23
@@ -31,7 +31,7 @@ LL | pub struct T6a(Sized, ::Assoc); // normalizes to `NonExhausti
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #78586 
-   = note: this struct contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future.
+   = note: this field contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future.
 
 error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types
   --> $DIR/repr-transparent-non-exhaustive.rs:59:22
@@ -41,7 +41,7 @@ LL | pub struct T7(Sized, NonExhaustiveEnum);
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #78586 
-   = note: this enum contains `NonExhaustiveEnum`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future.
+   = note: this field contains `NonExhaustiveEnum`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future.
 
 error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types
   --> $DIR/repr-transparent-non-exhaustive.rs:64:22
@@ -51,9 +51,9 @@ LL | pub struct T8(Sized, NonExhaustiveVariant);
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #78586 
-   = note: this enum contains `NonExhaustiveVariant`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future.
+   = note: this field contains `NonExhaustiveVariant`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future.
 
-error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types
+error: zero-sized fields in `repr(transparent)` cannot contain external types with private fields
   --> $DIR/repr-transparent-non-exhaustive.rs:69:22
    |
 LL | pub struct T9(Sized, InternalIndirection);
@@ -61,7 +61,7 @@ LL | pub struct T9(Sized, InternalIndirection);
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #78586 
-   = note: this struct contains `Private`, which contains private fields, and makes it not a breaking change to become non-zero-sized in the future.
+   = note: this field contains `Private`, which contains private fields, so it could become non-zero-sized in the future.
 
 error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types
   --> $DIR/repr-transparent-non-exhaustive.rs:74:23
@@ -71,7 +71,7 @@ LL | pub struct T10(Sized, InternalIndirection);
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #78586 
-   = note: this struct contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future.
+   = note: this field contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future.
 
 error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types
   --> $DIR/repr-transparent-non-exhaustive.rs:79:23
@@ -81,7 +81,7 @@ LL | pub struct T11(Sized, InternalIndirection);
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #78586 
-   = note: this enum contains `NonExhaustiveEnum`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future.
+   = note: this field contains `NonExhaustiveEnum`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future.
 
 error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types
   --> $DIR/repr-transparent-non-exhaustive.rs:84:23
@@ -91,9 +91,9 @@ LL | pub struct T12(Sized, InternalIndirection);
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #78586 
-   = note: this enum contains `NonExhaustiveVariant`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future.
+   = note: this field contains `NonExhaustiveVariant`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future.
 
-error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types
+error: zero-sized fields in `repr(transparent)` cannot contain external types with private fields
   --> $DIR/repr-transparent-non-exhaustive.rs:89:23
    |
 LL | pub struct T13(Sized, ExternalIndirection);
@@ -101,7 +101,7 @@ LL | pub struct T13(Sized, ExternalIndirection);
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #78586 
-   = note: this struct contains `Private`, which contains private fields, and makes it not a breaking change to become non-zero-sized in the future.
+   = note: this field contains `Private`, which contains private fields, so it could become non-zero-sized in the future.
 
 error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types
   --> $DIR/repr-transparent-non-exhaustive.rs:94:23
@@ -111,7 +111,7 @@ LL | pub struct T14(Sized, ExternalIndirection);
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #78586 
-   = note: this struct contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future.
+   = note: this field contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future.
 
 error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types
   --> $DIR/repr-transparent-non-exhaustive.rs:99:23
@@ -121,7 +121,7 @@ LL | pub struct T15(Sized, ExternalIndirection);
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #78586 
-   = note: this enum contains `NonExhaustiveEnum`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future.
+   = note: this field contains `NonExhaustiveEnum`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future.
 
 error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types
   --> $DIR/repr-transparent-non-exhaustive.rs:104:23
@@ -131,7 +131,7 @@ LL | pub struct T16(Sized, ExternalIndirection);
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #78586 
-   = note: this enum contains `NonExhaustiveVariant`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future.
+   = note: this field contains `NonExhaustiveVariant`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future.
 
 error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types
   --> $DIR/repr-transparent-non-exhaustive.rs:109:16
@@ -141,7 +141,7 @@ LL | pub struct T17(NonExhaustive, Sized);
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #78586 
-   = note: this struct contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future.
+   = note: this field contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future.
 
 error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types
   --> $DIR/repr-transparent-non-exhaustive.rs:114:31
@@ -151,9 +151,9 @@ LL | pub struct T18(NonExhaustive, NonExhaustive);
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #78586 
-   = note: this struct contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future.
+   = note: this field contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future.
 
-error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types
+error: zero-sized fields in `repr(transparent)` cannot contain external types with private fields
   --> $DIR/repr-transparent-non-exhaustive.rs:119:31
    |
 LL | pub struct T19(NonExhaustive, Private);
@@ -161,7 +161,7 @@ LL | pub struct T19(NonExhaustive, Private);
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #78586 
-   = note: this struct contains `Private`, which contains private fields, and makes it not a breaking change to become non-zero-sized in the future.
+   = note: this field contains `Private`, which contains private fields, so it could become non-zero-sized in the future.
 
 error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types
   --> $DIR/repr-transparent-non-exhaustive.rs:124:32
@@ -171,7 +171,279 @@ LL | pub struct T19Flipped(Private, NonExhaustive);
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #78586 
-   = note: this struct contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future.
+   = note: this field contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future.
 
 error: aborting due to 17 previous errors
 
+Future incompatibility report: Future breakage diagnostic:
+error: zero-sized fields in `repr(transparent)` cannot contain external types with private fields
+  --> $DIR/repr-transparent-non-exhaustive.rs:44:22
+   |
+LL | pub struct T5(Sized, Private);
+   |                      ^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #78586 
+   = note: this field contains `Private`, which contains private fields, so it could become non-zero-sized in the future.
+note: the lint level is defined here
+  --> $DIR/repr-transparent-non-exhaustive.rs:1:9
+   |
+LL | #![deny(repr_transparent_non_zst_fields)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Future breakage diagnostic:
+error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types
+  --> $DIR/repr-transparent-non-exhaustive.rs:49:22
+   |
+LL | pub struct T6(Sized, NonExhaustive);
+   |                      ^^^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #78586 
+   = note: this field contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future.
+note: the lint level is defined here
+  --> $DIR/repr-transparent-non-exhaustive.rs:1:9
+   |
+LL | #![deny(repr_transparent_non_zst_fields)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Future breakage diagnostic:
+error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types
+  --> $DIR/repr-transparent-non-exhaustive.rs:54:23
+   |
+LL | pub struct T6a(Sized, ::Assoc); // normalizes to `NonExhaustive`
+   |                       ^^^^^^^^^^^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #78586 
+   = note: this field contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future.
+note: the lint level is defined here
+  --> $DIR/repr-transparent-non-exhaustive.rs:1:9
+   |
+LL | #![deny(repr_transparent_non_zst_fields)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Future breakage diagnostic:
+error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types
+  --> $DIR/repr-transparent-non-exhaustive.rs:59:22
+   |
+LL | pub struct T7(Sized, NonExhaustiveEnum);
+   |                      ^^^^^^^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #78586 
+   = note: this field contains `NonExhaustiveEnum`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future.
+note: the lint level is defined here
+  --> $DIR/repr-transparent-non-exhaustive.rs:1:9
+   |
+LL | #![deny(repr_transparent_non_zst_fields)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Future breakage diagnostic:
+error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types
+  --> $DIR/repr-transparent-non-exhaustive.rs:64:22
+   |
+LL | pub struct T8(Sized, NonExhaustiveVariant);
+   |                      ^^^^^^^^^^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #78586 
+   = note: this field contains `NonExhaustiveVariant`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future.
+note: the lint level is defined here
+  --> $DIR/repr-transparent-non-exhaustive.rs:1:9
+   |
+LL | #![deny(repr_transparent_non_zst_fields)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Future breakage diagnostic:
+error: zero-sized fields in `repr(transparent)` cannot contain external types with private fields
+  --> $DIR/repr-transparent-non-exhaustive.rs:69:22
+   |
+LL | pub struct T9(Sized, InternalIndirection);
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #78586 
+   = note: this field contains `Private`, which contains private fields, so it could become non-zero-sized in the future.
+note: the lint level is defined here
+  --> $DIR/repr-transparent-non-exhaustive.rs:1:9
+   |
+LL | #![deny(repr_transparent_non_zst_fields)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Future breakage diagnostic:
+error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types
+  --> $DIR/repr-transparent-non-exhaustive.rs:74:23
+   |
+LL | pub struct T10(Sized, InternalIndirection);
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #78586 
+   = note: this field contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future.
+note: the lint level is defined here
+  --> $DIR/repr-transparent-non-exhaustive.rs:1:9
+   |
+LL | #![deny(repr_transparent_non_zst_fields)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Future breakage diagnostic:
+error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types
+  --> $DIR/repr-transparent-non-exhaustive.rs:79:23
+   |
+LL | pub struct T11(Sized, InternalIndirection);
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #78586 
+   = note: this field contains `NonExhaustiveEnum`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future.
+note: the lint level is defined here
+  --> $DIR/repr-transparent-non-exhaustive.rs:1:9
+   |
+LL | #![deny(repr_transparent_non_zst_fields)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Future breakage diagnostic:
+error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types
+  --> $DIR/repr-transparent-non-exhaustive.rs:84:23
+   |
+LL | pub struct T12(Sized, InternalIndirection);
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #78586 
+   = note: this field contains `NonExhaustiveVariant`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future.
+note: the lint level is defined here
+  --> $DIR/repr-transparent-non-exhaustive.rs:1:9
+   |
+LL | #![deny(repr_transparent_non_zst_fields)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Future breakage diagnostic:
+error: zero-sized fields in `repr(transparent)` cannot contain external types with private fields
+  --> $DIR/repr-transparent-non-exhaustive.rs:89:23
+   |
+LL | pub struct T13(Sized, ExternalIndirection);
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #78586 
+   = note: this field contains `Private`, which contains private fields, so it could become non-zero-sized in the future.
+note: the lint level is defined here
+  --> $DIR/repr-transparent-non-exhaustive.rs:1:9
+   |
+LL | #![deny(repr_transparent_non_zst_fields)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Future breakage diagnostic:
+error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types
+  --> $DIR/repr-transparent-non-exhaustive.rs:94:23
+   |
+LL | pub struct T14(Sized, ExternalIndirection);
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #78586 
+   = note: this field contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future.
+note: the lint level is defined here
+  --> $DIR/repr-transparent-non-exhaustive.rs:1:9
+   |
+LL | #![deny(repr_transparent_non_zst_fields)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Future breakage diagnostic:
+error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types
+  --> $DIR/repr-transparent-non-exhaustive.rs:99:23
+   |
+LL | pub struct T15(Sized, ExternalIndirection);
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #78586 
+   = note: this field contains `NonExhaustiveEnum`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future.
+note: the lint level is defined here
+  --> $DIR/repr-transparent-non-exhaustive.rs:1:9
+   |
+LL | #![deny(repr_transparent_non_zst_fields)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Future breakage diagnostic:
+error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types
+  --> $DIR/repr-transparent-non-exhaustive.rs:104:23
+   |
+LL | pub struct T16(Sized, ExternalIndirection);
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #78586 
+   = note: this field contains `NonExhaustiveVariant`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future.
+note: the lint level is defined here
+  --> $DIR/repr-transparent-non-exhaustive.rs:1:9
+   |
+LL | #![deny(repr_transparent_non_zst_fields)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Future breakage diagnostic:
+error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types
+  --> $DIR/repr-transparent-non-exhaustive.rs:109:16
+   |
+LL | pub struct T17(NonExhaustive, Sized);
+   |                ^^^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #78586 
+   = note: this field contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future.
+note: the lint level is defined here
+  --> $DIR/repr-transparent-non-exhaustive.rs:1:9
+   |
+LL | #![deny(repr_transparent_non_zst_fields)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Future breakage diagnostic:
+error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types
+  --> $DIR/repr-transparent-non-exhaustive.rs:114:31
+   |
+LL | pub struct T18(NonExhaustive, NonExhaustive);
+   |                               ^^^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #78586 
+   = note: this field contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future.
+note: the lint level is defined here
+  --> $DIR/repr-transparent-non-exhaustive.rs:1:9
+   |
+LL | #![deny(repr_transparent_non_zst_fields)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Future breakage diagnostic:
+error: zero-sized fields in `repr(transparent)` cannot contain external types with private fields
+  --> $DIR/repr-transparent-non-exhaustive.rs:119:31
+   |
+LL | pub struct T19(NonExhaustive, Private);
+   |                               ^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #78586 
+   = note: this field contains `Private`, which contains private fields, so it could become non-zero-sized in the future.
+note: the lint level is defined here
+  --> $DIR/repr-transparent-non-exhaustive.rs:1:9
+   |
+LL | #![deny(repr_transparent_non_zst_fields)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Future breakage diagnostic:
+error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types
+  --> $DIR/repr-transparent-non-exhaustive.rs:124:32
+   |
+LL | pub struct T19Flipped(Private, NonExhaustive);
+   |                                ^^^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #78586 
+   = note: this field contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future.
+note: the lint level is defined here
+  --> $DIR/repr-transparent-non-exhaustive.rs:1:9
+   |
+LL | #![deny(repr_transparent_non_zst_fields)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
diff --git a/tests/ui/repr/repr-transparent-repr-c.rs b/tests/ui/repr/repr-transparent-repr-c.rs
new file mode 100644
index 000000000000..c887c443f3fc
--- /dev/null
+++ b/tests/ui/repr/repr-transparent-repr-c.rs
@@ -0,0 +1,32 @@
+#![deny(repr_transparent_non_zst_fields)]
+
+#[repr(C)]
+pub struct ReprC1Zst {
+    pub _f: (),
+}
+
+pub type Sized = i32;
+
+#[repr(transparent)]
+pub struct T1(ReprC1Zst);
+#[repr(transparent)]
+pub struct T2((), ReprC1Zst);
+#[repr(transparent)]
+pub struct T3(ReprC1Zst, ());
+
+#[repr(transparent)]
+pub struct T5(Sized, ReprC1Zst);
+//~^ ERROR zero-sized fields in `repr(transparent)` cannot contain `repr(C)` types
+//~| WARN this was previously accepted by the compiler
+
+#[repr(transparent)]
+pub struct T6(ReprC1Zst, Sized);
+//~^ ERROR zero-sized fields in `repr(transparent)` cannot contain `repr(C)` types
+//~| WARN this was previously accepted by the compiler
+
+#[repr(transparent)]
+pub struct T7(T1, Sized); // still wrong, even when the repr(C) is hidden inside another type
+//~^ ERROR zero-sized fields in `repr(transparent)` cannot contain `repr(C)` types
+//~| WARN this was previously accepted by the compiler
+
+fn main() {}
diff --git a/tests/ui/repr/repr-transparent-repr-c.stderr b/tests/ui/repr/repr-transparent-repr-c.stderr
new file mode 100644
index 000000000000..5724845afdc1
--- /dev/null
+++ b/tests/ui/repr/repr-transparent-repr-c.stderr
@@ -0,0 +1,85 @@
+error: zero-sized fields in `repr(transparent)` cannot contain `repr(C)` types
+  --> $DIR/repr-transparent-repr-c.rs:18:22
+   |
+LL | pub struct T5(Sized, ReprC1Zst);
+   |                      ^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #78586 
+   = note: this field contains `ReprC1Zst`, which is a `#[repr(C)]` type, so it is not guaranteed to be zero-sized on all targets.
+note: the lint level is defined here
+  --> $DIR/repr-transparent-repr-c.rs:1:9
+   |
+LL | #![deny(repr_transparent_non_zst_fields)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: zero-sized fields in `repr(transparent)` cannot contain `repr(C)` types
+  --> $DIR/repr-transparent-repr-c.rs:23:15
+   |
+LL | pub struct T6(ReprC1Zst, Sized);
+   |               ^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #78586 
+   = note: this field contains `ReprC1Zst`, which is a `#[repr(C)]` type, so it is not guaranteed to be zero-sized on all targets.
+
+error: zero-sized fields in `repr(transparent)` cannot contain `repr(C)` types
+  --> $DIR/repr-transparent-repr-c.rs:28:15
+   |
+LL | pub struct T7(T1, Sized); // still wrong, even when the repr(C) is hidden inside another type
+   |               ^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #78586 
+   = note: this field contains `ReprC1Zst`, which is a `#[repr(C)]` type, so it is not guaranteed to be zero-sized on all targets.
+
+error: aborting due to 3 previous errors
+
+Future incompatibility report: Future breakage diagnostic:
+error: zero-sized fields in `repr(transparent)` cannot contain `repr(C)` types
+  --> $DIR/repr-transparent-repr-c.rs:18:22
+   |
+LL | pub struct T5(Sized, ReprC1Zst);
+   |                      ^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #78586 
+   = note: this field contains `ReprC1Zst`, which is a `#[repr(C)]` type, so it is not guaranteed to be zero-sized on all targets.
+note: the lint level is defined here
+  --> $DIR/repr-transparent-repr-c.rs:1:9
+   |
+LL | #![deny(repr_transparent_non_zst_fields)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Future breakage diagnostic:
+error: zero-sized fields in `repr(transparent)` cannot contain `repr(C)` types
+  --> $DIR/repr-transparent-repr-c.rs:23:15
+   |
+LL | pub struct T6(ReprC1Zst, Sized);
+   |               ^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #78586 
+   = note: this field contains `ReprC1Zst`, which is a `#[repr(C)]` type, so it is not guaranteed to be zero-sized on all targets.
+note: the lint level is defined here
+  --> $DIR/repr-transparent-repr-c.rs:1:9
+   |
+LL | #![deny(repr_transparent_non_zst_fields)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Future breakage diagnostic:
+error: zero-sized fields in `repr(transparent)` cannot contain `repr(C)` types
+  --> $DIR/repr-transparent-repr-c.rs:28:15
+   |
+LL | pub struct T7(T1, Sized); // still wrong, even when the repr(C) is hidden inside another type
+   |               ^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #78586 
+   = note: this field contains `ReprC1Zst`, which is a `#[repr(C)]` type, so it is not guaranteed to be zero-sized on all targets.
+note: the lint level is defined here
+  --> $DIR/repr-transparent-repr-c.rs:1:9
+   |
+LL | #![deny(repr_transparent_non_zst_fields)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
diff --git a/tests/ui/resolve/private-constructor-self-issue-147343.rs b/tests/ui/resolve/private-constructor-self-issue-147343.rs
new file mode 100644
index 000000000000..3c5ac603933c
--- /dev/null
+++ b/tests/ui/resolve/private-constructor-self-issue-147343.rs
@@ -0,0 +1,16 @@
+mod m {
+    pub struct S(crate::P);
+}
+
+use m::S;
+
+struct P;
+
+impl P {
+    fn foo(self) {
+        S(self);
+        //~^ ERROR cannot initialize a tuple struct which contains private fields [E0423]
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/resolve/private-constructor-self-issue-147343.stderr b/tests/ui/resolve/private-constructor-self-issue-147343.stderr
new file mode 100644
index 000000000000..f9290d7dcb35
--- /dev/null
+++ b/tests/ui/resolve/private-constructor-self-issue-147343.stderr
@@ -0,0 +1,11 @@
+error[E0423]: cannot initialize a tuple struct which contains private fields
+  --> $DIR/private-constructor-self-issue-147343.rs:11:9
+   |
+LL |         S(self);
+   |         ^
+   |
+   = note: constructor is not visible here due to private fields
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0423`.
diff --git a/tests/ui/rustc_public-ir-print/async-closure.stdout b/tests/ui/rustc_public-ir-print/async-closure.stdout
index 550f0512569d..3ec816b657f4 100644
--- a/tests/ui/rustc_public-ir-print/async-closure.stdout
+++ b/tests/ui/rustc_public-ir-print/async-closure.stdout
@@ -42,10 +42,8 @@ fn foo::{closure#0}::{closure#0}(_1: Pin<&mut {async closure body@$DIR/async-clo
     let mut _5: ();
     let mut _6: u32;
     let mut _7: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6};
-    let mut _8: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6};
-    let mut _9: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6};
     debug _task_context => _2;
-    debug y => (*((*(_1.0: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6})).0: &i32));
+    debug y => (*((*_7).0: &i32));
     debug y => _3;
     bb0: {
         _7 = (_1.0: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6});
@@ -54,14 +52,12 @@ fn foo::{closure#0}::{closure#0}(_1: Pin<&mut {async closure body@$DIR/async-clo
     }
     bb1: {
         StorageLive(_3);
-        _8 = (_1.0: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6});
-        _4 = ((*_8).0: &i32);
+        _4 = ((*_7).0: &i32);
         _3 = (*_4);
         _5 = ();
         StorageDead(_3);
         _0 = std::task::Poll::Ready(move _5);
-        _9 = (_1.0: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6});
-        discriminant((*_9)) = 1;
+        discriminant((*_7)) = 1;
         return;
     }
     bb2: {
@@ -78,10 +74,8 @@ fn foo::{closure#0}::{synthetic#0}(_1: Pin<&mut {async closure body@$DIR/async-c
     let mut _5: ();
     let mut _6: u32;
     let mut _7: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6};
-    let mut _8: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6};
-    let mut _9: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6};
     debug _task_context => _2;
-    debug y => (*((*(_1.0: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6})).0: &i32));
+    debug y => (*((*_7).0: &i32));
     debug y => _3;
     bb0: {
         _7 = (_1.0: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6});
@@ -90,14 +84,12 @@ fn foo::{closure#0}::{synthetic#0}(_1: Pin<&mut {async closure body@$DIR/async-c
     }
     bb1: {
         StorageLive(_3);
-        _8 = (_1.0: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6});
-        _4 = ((*_8).0: &i32);
+        _4 = ((*_7).0: &i32);
         _3 = (*_4);
         _5 = ();
         StorageDead(_3);
         _0 = std::task::Poll::Ready(move _5);
-        _9 = (_1.0: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6});
-        discriminant((*_9)) = 1;
+        discriminant((*_7)) = 1;
         return;
     }
     bb2: {
diff --git a/tests/ui/rustc_public-ir-print/operands.stdout b/tests/ui/rustc_public-ir-print/operands.stdout
index a4b1c07f3a0b..b7775416af85 100644
--- a/tests/ui/rustc_public-ir-print/operands.stdout
+++ b/tests/ui/rustc_public-ir-print/operands.stdout
@@ -397,13 +397,6 @@ fn operands(_1: u8) -> () {
         _89 = core::panicking::assert_failed::(move _90, move _91, move _93, move _95) -> unwind unreachable;
     }
 }
-fn operands::{constant#0}() -> usize {
-    let mut _0: usize;
-    bb0: {
-        _0 = 10_usize;
-        return;
-    }
-}
 fn more_operands() -> [Ctors; 3] {
     let mut _0: [Ctors; 3];
     let  _1: Dummy;
@@ -447,13 +440,6 @@ fn more_operands() -> [Ctors; 3] {
         return;
     }
 }
-fn more_operands::{constant#0}() -> usize {
-    let mut _0: usize;
-    bb0: {
-        _0 = 3_usize;
-        return;
-    }
-}
 fn closures(_1: bool, _2: bool) -> {closure@$DIR/operands.rs:47:5: 47:19} {
     let mut _0: {closure@$DIR/operands.rs:47:5: 47:19};
     debug x => _1;
diff --git a/tests/ui/sanitizer/hwaddress.rs b/tests/ui/sanitizer/hwaddress.rs
index 05fcab17506b..8666e7de4492 100644
--- a/tests/ui/sanitizer/hwaddress.rs
+++ b/tests/ui/sanitizer/hwaddress.rs
@@ -1,11 +1,7 @@
 //@ needs-sanitizer-support
 //@ needs-sanitizer-hwaddress
 //
-// FIXME(#83706): this test triggers errors on aarch64-gnu
-//@ ignore-aarch64-unknown-linux-gnu
-//
-// FIXME(#83989): codegen-units=1 triggers linker errors on aarch64-gnu
-//@ compile-flags: -Z sanitizer=hwaddress -O -g -C codegen-units=16 -C unsafe-allow-abi-mismatch=sanitizer
+//@ compile-flags: -Z sanitizer=hwaddress -O -g -C target-feature=+tagged-globals -C unsafe-allow-abi-mismatch=sanitizer
 //
 //@ run-fail
 //@ error-pattern: HWAddressSanitizer: tag-mismatch
@@ -19,3 +15,5 @@ fn main() {
     let code = unsafe { *xs.offset(4) };
     std::process::exit(code);
 }
+
+//~? WARN unknown and unstable feature specified for `-Ctarget-feature`: `tagged-globals`
diff --git a/tests/ui/sanitizer/hwaddress.stderr b/tests/ui/sanitizer/hwaddress.stderr
new file mode 100644
index 000000000000..37afe0bd779e
--- /dev/null
+++ b/tests/ui/sanitizer/hwaddress.stderr
@@ -0,0 +1,7 @@
+warning: unknown and unstable feature specified for `-Ctarget-feature`: `tagged-globals`
+   |
+   = note: it is still passed through to the codegen backend, but use of this feature might be unsound and the behavior of this feature can change in the future
+   = help: consider filing a feature request
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/sized-hierarchy/bound-on-assoc-type-projection.rs b/tests/ui/sized-hierarchy/bound-on-assoc-type-projection.rs
new file mode 100644
index 000000000000..48d17ac9a3af
--- /dev/null
+++ b/tests/ui/sized-hierarchy/bound-on-assoc-type-projection.rs
@@ -0,0 +1,18 @@
+//@ check-pass
+#![crate_type = "lib"]
+#![feature(sized_hierarchy)]
+
+// Tests that a bound on an associated type projection, of a trait with a sizedness bound, will be
+// elaborated.
+
+trait FalseDeref {
+    type Target: std::marker::PointeeSized;
+}
+
+trait Bar {}
+
+fn foo()
+where
+    T::Target: Bar,
+{
+}
diff --git a/tests/ui/sized-hierarchy/default-supertrait.rs b/tests/ui/sized-hierarchy/default-supertrait.rs
index d5bf152b7963..b13f9d90081c 100644
--- a/tests/ui/sized-hierarchy/default-supertrait.rs
+++ b/tests/ui/sized-hierarchy/default-supertrait.rs
@@ -52,14 +52,11 @@ fn with_pointeesized_supertrait() {
     requires_pointeesized::();
 }
 
-// `T` won't inherit the `const MetaSized` implicit supertrait of `Bare`, so there is an error on
-// the bound, which is expected.
+// `T` inherits the `const MetaSized` implicit supertrait of `Bare`.
 fn with_bare_trait() {
-//~^ ERROR the size for values of type `T` cannot be known
     requires_sized::();
     //~^ ERROR the size for values of type `T` cannot be known
     requires_metasized::();
-    //~^ ERROR the size for values of type `T` cannot be known
     requires_pointeesized::();
 }
 
diff --git a/tests/ui/sized-hierarchy/default-supertrait.stderr b/tests/ui/sized-hierarchy/default-supertrait.stderr
index 2a521dce8b6b..35875163774d 100644
--- a/tests/ui/sized-hierarchy/default-supertrait.stderr
+++ b/tests/ui/sized-hierarchy/default-supertrait.stderr
@@ -62,22 +62,6 @@ LL | trait NegPointeeSized: ?PointeeSized { }
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
-error[E0277]: the size for values of type `T` cannot be known
-  --> $DIR/default-supertrait.rs:57:38
-   |
-LL | fn with_bare_trait() {
-   |                                      ^^^^ doesn't have a known size
-   |
-note: required by a bound in `Bare`
-  --> $DIR/default-supertrait.rs:27:1
-   |
-LL | trait Bare {}
-   | ^^^^^^^^^^^^^ required by this bound in `Bare`
-help: consider further restricting type parameter `T` with unstable trait `MetaSized`
-   |
-LL | fn with_bare_trait() {
-   |                                           ++++++++++++++++++++++++
-
 error[E0277]: the size for values of type `T` cannot be known at compilation time
   --> $DIR/default-supertrait.rs:40:22
    |
@@ -123,11 +107,10 @@ LL | fn with_pointeesized_supertrait $DIR/default-supertrait.rs:59:22
+  --> $DIR/default-supertrait.rs:57:22
    |
 LL | fn with_bare_trait() {
    |                    - this type parameter needs to be `Sized`
-LL |
 LL |     requires_sized::();
    |                      ^ doesn't have a size known at compile-time
    |
@@ -137,22 +120,6 @@ note: required by a bound in `requires_sized`
 LL | fn requires_sized() {}
    |                      ^^^^^ required by this bound in `requires_sized`
 
-error[E0277]: the size for values of type `T` cannot be known
-  --> $DIR/default-supertrait.rs:61:26
-   |
-LL |     requires_metasized::();
-   |                          ^ doesn't have a known size
-   |
-note: required by a bound in `requires_metasized`
-  --> $DIR/default-supertrait.rs:30:26
-   |
-LL | fn requires_metasized() {}
-   |                          ^^^^^^^^^ required by this bound in `requires_metasized`
-help: consider further restricting type parameter `T` with unstable trait `MetaSized`
-   |
-LL | fn with_bare_trait() {
-   |                                           ++++++++++++++++++++++++
-
-error: aborting due to 15 previous errors
+error: aborting due to 13 previous errors
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/sized-hierarchy/elaboration-simple.rs b/tests/ui/sized-hierarchy/elaboration-simple.rs
new file mode 100644
index 000000000000..87e100166a29
--- /dev/null
+++ b/tests/ui/sized-hierarchy/elaboration-simple.rs
@@ -0,0 +1,13 @@
+//@ check-pass
+//@ compile-flags: --crate-type=lib
+#![feature(sized_hierarchy)]
+
+// Test demonstrating that elaboration of sizedness bounds works in the simplest cases.
+
+trait Trait {}
+
+fn f() {
+    require_metasized::();
+}
+
+fn require_metasized() {}
diff --git a/tests/ui/sized-hierarchy/trait-alias-elaboration.rs b/tests/ui/sized-hierarchy/trait-alias-elaboration.rs
new file mode 100644
index 000000000000..a5b4443ffddd
--- /dev/null
+++ b/tests/ui/sized-hierarchy/trait-alias-elaboration.rs
@@ -0,0 +1,16 @@
+#![feature(sized_hierarchy, trait_alias)]
+use std::marker::MetaSized;
+
+// Trait aliases also have implicit `MetaSized` bounds, like traits. These are filtered out during
+// elaboration of trait aliases when lowering `dyn TraitAlias` - however, if the user explicitly
+// wrote `MetaSized` in the `dyn Trait` then that should still be an error so as not to accidentally
+// accept this going forwards.
+
+trait Qux = Clone;
+
+type Foo = dyn Qux + MetaSized;
+//~^ ERROR: only auto traits can be used as additional traits in a trait object
+
+type Bar = dyn Qux;
+
+fn main() {}
diff --git a/tests/ui/sized-hierarchy/trait-alias-elaboration.stderr b/tests/ui/sized-hierarchy/trait-alias-elaboration.stderr
new file mode 100644
index 000000000000..394aae6f8e32
--- /dev/null
+++ b/tests/ui/sized-hierarchy/trait-alias-elaboration.stderr
@@ -0,0 +1,17 @@
+error[E0225]: only auto traits can be used as additional traits in a trait object
+  --> $DIR/trait-alias-elaboration.rs:11:16
+   |
+LL | trait Qux = Clone;
+   | ------------------ additional non-auto trait
+LL |
+LL | type Foo = dyn Qux + MetaSized;
+   |                ^^^   --------- first non-auto trait
+   |                |
+   |                second non-auto trait comes from this alias
+   |
+   = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: MetaSized + MetaSized + Clone {}`
+   = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit 
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0225`.
diff --git a/tests/ui/stats/input-stats.stderr b/tests/ui/stats/input-stats.stderr
index 4a73a4747ad0..18862eeef06e 100644
--- a/tests/ui/stats/input-stats.stderr
+++ b/tests/ui/stats/input-stats.stderr
@@ -105,10 +105,10 @@ hir-stats - Semi                      32 (NN.N%)             1
 hir-stats Arm                       80 (NN.N%)             2            40
 hir-stats WherePredicate            72 (NN.N%)             3            24
 hir-stats - BoundPredicate            72 (NN.N%)             3
-hir-stats Local                     72 (NN.N%)             1            72
 hir-stats InlineAsm                 72 (NN.N%)             1            72
 hir-stats Body                      72 (NN.N%)             3            24
 hir-stats Param                     64 (NN.N%)             2            32
+hir-stats Local                     64 (NN.N%)             1            64
 hir-stats GenericArg                64 (NN.N%)             4            16
 hir-stats - Type                      16 (NN.N%)             1
 hir-stats - Lifetime                  48 (NN.N%)             3
@@ -119,5 +119,5 @@ hir-stats TraitItemId                8 (NN.N%)             2             4
 hir-stats ImplItemId                 8 (NN.N%)             2             4
 hir-stats ForeignItemId              4 (NN.N%)             1             4
 hir-stats ----------------------------------------------------------------
-hir-stats Total                  8_624                   173
+hir-stats Total                  8_616                   173
 hir-stats ================================================================
diff --git a/tests/ui/traits/const-traits/const-traits-alloc.rs b/tests/ui/traits/const-traits/const-traits-alloc.rs
index 07725ef02f18..4dfec2f77f1b 100644
--- a/tests/ui/traits/const-traits/const-traits-alloc.rs
+++ b/tests/ui/traits/const-traits/const-traits-alloc.rs
@@ -1,4 +1,4 @@
-//@ run-pass
+//@ check-pass
 #![feature(const_trait_impl, const_default)]
 #![allow(dead_code)]
 // alloc::string
diff --git a/tests/ui/traits/const-traits/const-traits-core.rs b/tests/ui/traits/const-traits/const-traits-core.rs
index 6df53daae137..2cafde4f5bd0 100644
--- a/tests/ui/traits/const-traits/const-traits-core.rs
+++ b/tests/ui/traits/const-traits/const-traits-core.rs
@@ -1,6 +1,13 @@
-//@ run-pass
+//@ check-pass
 #![feature(
-    const_trait_impl, const_default, ptr_alignment_type, ascii_char, f16, f128, sync_unsafe_cell,
+    const_clone,
+    const_default,
+    const_trait_impl,
+    ptr_alignment_type,
+    ascii_char,
+    f16,
+    f128,
+    sync_unsafe_cell,
 )]
 #![allow(dead_code)]
 // core::default
@@ -43,4 +50,8 @@ const REF_CELL: std::cell::RefCell<()> = Default::default();
 const UNSAFE_CELL: std::cell::UnsafeCell<()> = Default::default();
 const SYNC_UNSAFE_CELL: std::cell::SyncUnsafeCell<()> = Default::default();
 
+// `Clone` for tuples
+const BUILTIN_CLONE: () = ().clone();
+const BUILTIN_CLONE_2: (u32, i32) = (42, 100).clone();
+
 fn main() {}
diff --git a/tests/ui/traits/const-traits/unsatisfied-const-trait-bound.stderr b/tests/ui/traits/const-traits/unsatisfied-const-trait-bound.stderr
index 3ed6dc69d0b7..9750d806ce97 100644
--- a/tests/ui/traits/const-traits/unsatisfied-const-trait-bound.stderr
+++ b/tests/ui/traits/const-traits/unsatisfied-const-trait-bound.stderr
@@ -17,27 +17,7 @@ note: ...which requires const-evaluating + checking `accept0::{constant#0}`...
    |
 LL | fn accept0(_: Container<{ T::make() }>) {}
    |                                   ^^^^^^^^^^^^^
-note: ...which requires caching mir of `accept0::{constant#0}` for CTFE...
-  --> $DIR/unsatisfied-const-trait-bound.rs:29:35
-   |
-LL | fn accept0(_: Container<{ T::make() }>) {}
-   |                                   ^^^^^^^^^^^^^
-note: ...which requires elaborating drops for `accept0::{constant#0}`...
-  --> $DIR/unsatisfied-const-trait-bound.rs:29:35
-   |
-LL | fn accept0(_: Container<{ T::make() }>) {}
-   |                                   ^^^^^^^^^^^^^
-note: ...which requires borrow-checking `accept0::{constant#0}`...
-  --> $DIR/unsatisfied-const-trait-bound.rs:29:35
-   |
-LL | fn accept0(_: Container<{ T::make() }>) {}
-   |                                   ^^^^^^^^^^^^^
-note: ...which requires promoting constants in MIR for `accept0::{constant#0}`...
-  --> $DIR/unsatisfied-const-trait-bound.rs:29:35
-   |
-LL | fn accept0(_: Container<{ T::make() }>) {}
-   |                                   ^^^^^^^^^^^^^
-note: ...which requires const checking `accept0::{constant#0}`...
+note: ...which requires checking if `accept0::{constant#0}` is a trivial const...
   --> $DIR/unsatisfied-const-trait-bound.rs:29:35
    |
 LL | fn accept0(_: Container<{ T::make() }>) {}
@@ -70,32 +50,12 @@ LL | fn accept0(_: Container<{ T::make() }>) {}
    |                                   ^^^^^^^^^^^^^
    = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
 
-error[E0391]: cycle detected when caching mir of `accept1::{constant#0}` for CTFE
+error[E0391]: cycle detected when checking if `accept1::{constant#0}` is a trivial const
   --> $DIR/unsatisfied-const-trait-bound.rs:33:49
    |
 LL | const fn accept1(_: Container<{ T::make() }>) {}
    |                                                 ^^^^^^^^^^^^^
    |
-note: ...which requires elaborating drops for `accept1::{constant#0}`...
-  --> $DIR/unsatisfied-const-trait-bound.rs:33:49
-   |
-LL | const fn accept1(_: Container<{ T::make() }>) {}
-   |                                                 ^^^^^^^^^^^^^
-note: ...which requires borrow-checking `accept1::{constant#0}`...
-  --> $DIR/unsatisfied-const-trait-bound.rs:33:49
-   |
-LL | const fn accept1(_: Container<{ T::make() }>) {}
-   |                                                 ^^^^^^^^^^^^^
-note: ...which requires promoting constants in MIR for `accept1::{constant#0}`...
-  --> $DIR/unsatisfied-const-trait-bound.rs:33:49
-   |
-LL | const fn accept1(_: Container<{ T::make() }>) {}
-   |                                                 ^^^^^^^^^^^^^
-note: ...which requires const checking `accept1::{constant#0}`...
-  --> $DIR/unsatisfied-const-trait-bound.rs:33:49
-   |
-LL | const fn accept1(_: Container<{ T::make() }>) {}
-   |                                                 ^^^^^^^^^^^^^
 note: ...which requires building MIR for `accept1::{constant#0}`...
   --> $DIR/unsatisfied-const-trait-bound.rs:33:49
    |
@@ -126,7 +86,7 @@ note: ...which requires const-evaluating + checking `accept1::{constant#0}`...
    |
 LL | const fn accept1(_: Container<{ T::make() }>) {}
    |                                                 ^^^^^^^^^^^^^
-   = note: ...which again requires caching mir of `accept1::{constant#0}` for CTFE, completing the cycle
+   = note: ...which again requires checking if `accept1::{constant#0}` is a trivial const, completing the cycle
 note: cycle used when const-evaluating + checking `accept1::{constant#0}`
   --> $DIR/unsatisfied-const-trait-bound.rs:33:49
    |
diff --git a/tests/ui/traits/generic-cow-inference-regression.rs b/tests/ui/traits/generic-cow-inference-regression.rs
index 6fd4715f85bb..e9dd76d1aea4 100644
--- a/tests/ui/traits/generic-cow-inference-regression.rs
+++ b/tests/ui/traits/generic-cow-inference-regression.rs
@@ -1,3 +1,5 @@
+//@[new] compile-flags: -Znext-solver
+//@ revisions: old new
 //@ run-pass
 
 // regression test for #147964:
diff --git a/tests/ui/traits/next-solver/cycles/coinduction/fixpoint-exponential-growth.stderr b/tests/ui/traits/next-solver/cycles/coinduction/fixpoint-exponential-growth.stderr
index 150100f2c531..8d7d8cee08ae 100644
--- a/tests/ui/traits/next-solver/cycles/coinduction/fixpoint-exponential-growth.stderr
+++ b/tests/ui/traits/next-solver/cycles/coinduction/fixpoint-exponential-growth.stderr
@@ -4,7 +4,6 @@ error[E0275]: overflow evaluating the requirement `W<_>: Trait`
 LL |     impls::>();
    |             ^^^^
    |
-   = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`fixpoint_exponential_growth`)
 note: required by a bound in `impls`
   --> $DIR/fixpoint-exponential-growth.rs:30:13
    |
diff --git a/tests/ui/traits/next-solver/normalize/normalize-param-env-2.stderr b/tests/ui/traits/next-solver/normalize/normalize-param-env-2.stderr
index 8d8909625ffc..d179c8059623 100644
--- a/tests/ui/traits/next-solver/normalize/normalize-param-env-2.stderr
+++ b/tests/ui/traits/next-solver/normalize/normalize-param-env-2.stderr
@@ -19,23 +19,6 @@ error[E0275]: overflow evaluating the requirement `<() as A>::Assoc: A`
 LL |         Self::Assoc: A,
    |                      ^^^^
 
-error[E0275]: overflow evaluating the requirement `<() as A>::Assoc: MetaSized`
-  --> $DIR/normalize-param-env-2.rs:24:22
-   |
-LL |         Self::Assoc: A,
-   |                      ^^^^
-   |
-note: required by a bound in `A`
-  --> $DIR/normalize-param-env-2.rs:9:1
-   |
-LL | / trait A {
-LL | |     type Assoc;
-LL | |
-LL | |     fn f()
-...  |
-LL | | }
-   | |_^ required by this bound in `A`
-
 error[E0275]: overflow evaluating the requirement `<() as A>::Assoc well-formed`
   --> $DIR/normalize-param-env-2.rs:24:22
    |
@@ -63,6 +46,6 @@ LL |     where
 LL |         Self::Assoc: A,
    |                      ^^^^ required by this bound in `A::f`
 
-error: aborting due to 6 previous errors
+error: aborting due to 5 previous errors
 
 For more information about this error, try `rustc --explain E0275`.
diff --git a/tests/ui/traits/next-solver/normalize/normalize-param-env-4.next.stderr b/tests/ui/traits/next-solver/normalize/normalize-param-env-4.next.stderr
index 9f7f74f94664..f5fd9ce9864c 100644
--- a/tests/ui/traits/next-solver/normalize/normalize-param-env-4.next.stderr
+++ b/tests/ui/traits/next-solver/normalize/normalize-param-env-4.next.stderr
@@ -4,20 +4,6 @@ error[E0275]: overflow evaluating the requirement `::Assoc: Trait`
 LL |     ::Assoc: Trait,
    |                          ^^^^^
 
-error[E0275]: overflow evaluating the requirement `::Assoc: MetaSized`
-  --> $DIR/normalize-param-env-4.rs:19:26
-   |
-LL |     ::Assoc: Trait,
-   |                          ^^^^^
-   |
-note: required by a bound in `Trait`
-  --> $DIR/normalize-param-env-4.rs:7:1
-   |
-LL | / trait Trait {
-LL | |     type Assoc;
-LL | | }
-   | |_^ required by this bound in `Trait`
-
-error: aborting due to 2 previous errors
+error: aborting due to 1 previous error
 
 For more information about this error, try `rustc --explain E0275`.
diff --git a/tests/ui/traits/next-solver/opaques/stranded_opaque.rs b/tests/ui/traits/next-solver/opaques/stranded_opaque.rs
new file mode 100644
index 000000000000..f600a1496b99
--- /dev/null
+++ b/tests/ui/traits/next-solver/opaques/stranded_opaque.rs
@@ -0,0 +1,50 @@
+//@ compile-flags: -Znext-solver
+#![feature(type_alias_impl_trait)]
+use std::future::Future;
+
+// Test for https://github.com/rust-lang/trait-system-refactor-initiative/issues/235
+
+// These are cases where an opaque types become "stranded" due to
+// some errors. Make sure we don't ICE in either case.
+
+// Case 1: `impl Send` is stranded
+fn foo() -> impl ?Future {
+    //~^ ERROR bound modifier `?` can only be applied to `Sized`
+    //~| ERROR bound modifier `?` can only be applied to `Sized`
+    ()
+}
+
+// Case 2: `Assoc = impl Trait` is stranded
+trait Trait {}
+impl Trait for i32 {}
+
+fn produce() -> impl Trait {
+    //~^ ERROR associated type `Assoc` not found for `Trait`
+    //~| ERROR associated type `Assoc` not found for `Trait`
+    16
+}
+
+// Case 3: `impl Trait` is stranded
+fn ill_formed_string() -> String {
+    //~^ ERROR struct takes 0 generic arguments but 1 generic argument was supplied
+   String::from("a string")
+}
+
+// Case 4: TAIT variant of Case 1 to 3
+type Foo = impl ?Future;
+//~^ ERROR unconstrained opaque type
+//~| ERROR unconstrained opaque type
+//~| ERROR bound modifier `?` can only be applied to `Sized`
+//~| ERROR bound modifier `?` can only be applied to `Sized`
+
+type Produce =  impl Trait;
+//~^ ERROR unconstrained opaque type
+//~| ERROR unconstrained opaque type
+//~| ERROR associated type `Assoc` not found for `Trait`
+//~| ERROR associated type `Assoc` not found for `Trait`
+
+type IllFormedString =  String;
+//~^ ERROR unconstrained opaque type
+//~| ERROR struct takes 0 generic arguments but 1 generic argument was supplied
+
+fn main() {}
diff --git a/tests/ui/traits/next-solver/opaques/stranded_opaque.stderr b/tests/ui/traits/next-solver/opaques/stranded_opaque.stderr
new file mode 100644
index 000000000000..bcb357eb6953
--- /dev/null
+++ b/tests/ui/traits/next-solver/opaques/stranded_opaque.stderr
@@ -0,0 +1,116 @@
+error: bound modifier `?` can only be applied to `Sized`
+  --> $DIR/stranded_opaque.rs:11:18
+   |
+LL | fn foo() -> impl ?Future {
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0220]: associated type `Assoc` not found for `Trait`
+  --> $DIR/stranded_opaque.rs:21:28
+   |
+LL | fn produce() -> impl Trait {
+   |                            ^^^^^ associated type `Assoc` not found
+
+error[E0107]: struct takes 0 generic arguments but 1 generic argument was supplied
+  --> $DIR/stranded_opaque.rs:28:27
+   |
+LL | fn ill_formed_string() -> String {
+   |                           ^^^^^^------------ help: remove the unnecessary generics
+   |                           |
+   |                           expected 0 generic arguments
+
+error[E0107]: struct takes 0 generic arguments but 1 generic argument was supplied
+  --> $DIR/stranded_opaque.rs:46:25
+   |
+LL | type IllFormedString =  String;
+   |                         ^^^^^^------------ help: remove the unnecessary generics
+   |                         |
+   |                         expected 0 generic arguments
+
+error: bound modifier `?` can only be applied to `Sized`
+  --> $DIR/stranded_opaque.rs:11:18
+   |
+LL | fn foo() -> impl ?Future {
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error[E0220]: associated type `Assoc` not found for `Trait`
+  --> $DIR/stranded_opaque.rs:21:28
+   |
+LL | fn produce() -> impl Trait {
+   |                            ^^^^^ associated type `Assoc` not found
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: unconstrained opaque type
+  --> $DIR/stranded_opaque.rs:34:12
+   |
+LL | type Foo = impl ?Future;
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `Foo` must be used in combination with a concrete type within the same crate
+
+error: bound modifier `?` can only be applied to `Sized`
+  --> $DIR/stranded_opaque.rs:34:17
+   |
+LL | type Foo = impl ?Future;
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: bound modifier `?` can only be applied to `Sized`
+  --> $DIR/stranded_opaque.rs:34:17
+   |
+LL | type Foo = impl ?Future;
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: unconstrained opaque type
+  --> $DIR/stranded_opaque.rs:34:34
+   |
+LL | type Foo = impl ?Future;
+   |                                  ^^^^^^^^^
+   |
+   = note: `Foo` must be used in combination with a concrete type within the same crate
+
+error: unconstrained opaque type
+  --> $DIR/stranded_opaque.rs:40:17
+   |
+LL | type Produce =  impl Trait;
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `Produce` must be used in combination with a concrete type within the same crate
+
+error[E0220]: associated type `Assoc` not found for `Trait`
+  --> $DIR/stranded_opaque.rs:40:28
+   |
+LL | type Produce =  impl Trait;
+   |                            ^^^^^ associated type `Assoc` not found
+
+error[E0220]: associated type `Assoc` not found for `Trait`
+  --> $DIR/stranded_opaque.rs:40:28
+   |
+LL | type Produce =  impl Trait;
+   |                            ^^^^^ associated type `Assoc` not found
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: unconstrained opaque type
+  --> $DIR/stranded_opaque.rs:40:36
+   |
+LL | type Produce =  impl Trait;
+   |                                    ^^^^^^^^^^
+   |
+   = note: `Produce` must be used in combination with a concrete type within the same crate
+
+error: unconstrained opaque type
+  --> $DIR/stranded_opaque.rs:46:32
+   |
+LL | type IllFormedString =  String;
+   |                                ^^^^^^^^^^
+   |
+   = note: `IllFormedString` must be used in combination with a concrete type within the same crate
+
+error: aborting due to 15 previous errors
+
+Some errors have detailed explanations: E0107, E0220.
+For more information about an error, try `rustc --explain E0107`.
diff --git a/tests/ui/traits/next-solver/unsize-goal-mismatch-2.next.stderr b/tests/ui/traits/next-solver/unsize-goal-mismatch-2.next.stderr
new file mode 100644
index 000000000000..b415db33addb
--- /dev/null
+++ b/tests/ui/traits/next-solver/unsize-goal-mismatch-2.next.stderr
@@ -0,0 +1,13 @@
+error[E0283]: type annotations needed: cannot satisfy `dyn Trait<&()>: Unsize>`
+  --> $DIR/unsize-goal-mismatch-2.rs:15:5
+   |
+LL |     x
+   |     ^
+   |
+   = note: cannot satisfy `dyn Trait<&()>: Unsize>`
+   = note: required for `Box>` to implement `CoerceUnsized>>`
+   = note: required for the cast from `Box<(dyn Trait<&'a ()> + 'static)>` to `Box<(dyn Super<&'a ()> + 'static)>`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0283`.
diff --git a/tests/ui/traits/next-solver/unsize-goal-mismatch-2.rs b/tests/ui/traits/next-solver/unsize-goal-mismatch-2.rs
new file mode 100644
index 000000000000..2b174eac5c15
--- /dev/null
+++ b/tests/ui/traits/next-solver/unsize-goal-mismatch-2.rs
@@ -0,0 +1,19 @@
+//@ revisions: current next
+//@ ignore-compare-mode-next-solver (explicit revisions)
+//@[next] compile-flags: -Znext-solver
+//@[current] check-pass
+// Test from trait-system-refactor-initiative#241:
+// Used to ICE in mir typeck because of ambiguity in the new solver.
+// The wrong (first) trait bound was selected.
+// This is fixed with new logic for unsizing coercions
+// that's independent from that of the old solver, which this test verifies.
+
+trait Super {}
+trait Trait: Super + for<'hr> Super<&'hr ()> {}
+
+fn foo<'a>(x: Box>) -> Box> {
+    x
+    //[next]~^ ERROR type annotations needed: cannot satisfy `dyn Trait<&()>: Unsize>`
+}
+
+fn main() {}
diff --git a/tests/ui/traits/next-solver/unsize-goal-mismatch.current.stderr b/tests/ui/traits/next-solver/unsize-goal-mismatch.current.stderr
new file mode 100644
index 000000000000..278a68e15471
--- /dev/null
+++ b/tests/ui/traits/next-solver/unsize-goal-mismatch.current.stderr
@@ -0,0 +1,17 @@
+error[E0283]: type annotations needed: cannot satisfy `Self: Super<'a>`
+  --> $DIR/unsize-goal-mismatch.rs:11:18
+   |
+LL | trait Trait<'a>: Super<'a> + for<'hr> Super<'hr> {}
+   |                  ^^^^^^^^^
+   |
+note: multiple `impl`s or `where` clauses satisfying `Self: Super<'a>` found
+  --> $DIR/unsize-goal-mismatch.rs:10:1
+   |
+LL | trait Super<'a> {}
+   | ^^^^^^^^^^^^^^^
+LL | trait Trait<'a>: Super<'a> + for<'hr> Super<'hr> {}
+   |                              ^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0283`.
diff --git a/tests/ui/traits/next-solver/unsize-goal-mismatch.next.stderr b/tests/ui/traits/next-solver/unsize-goal-mismatch.next.stderr
new file mode 100644
index 000000000000..cfb978240cbc
--- /dev/null
+++ b/tests/ui/traits/next-solver/unsize-goal-mismatch.next.stderr
@@ -0,0 +1,13 @@
+error[E0283]: type annotations needed: cannot satisfy `dyn Trait<'_>: Unsize>`
+  --> $DIR/unsize-goal-mismatch.rs:15:5
+   |
+LL |     x
+   |     ^
+   |
+   = note: cannot satisfy `dyn Trait<'_>: Unsize>`
+   = note: required for `Box>` to implement `CoerceUnsized>>`
+   = note: required for the cast from `Box<(dyn Trait<'a> + 'static)>` to `Box<(dyn Super<'a> + 'static)>`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0283`.
diff --git a/tests/ui/traits/next-solver/unsize-goal-mismatch.rs b/tests/ui/traits/next-solver/unsize-goal-mismatch.rs
new file mode 100644
index 000000000000..f57cceb4096a
--- /dev/null
+++ b/tests/ui/traits/next-solver/unsize-goal-mismatch.rs
@@ -0,0 +1,19 @@
+//@ revisions: current next
+//@ ignore-compare-mode-next-solver (explicit revisions)
+//@[next] compile-flags: -Znext-solver
+// Test from trait-system-refactor-initiative#241:
+// Used to ICE in mir typeck because of ambiguity in the new solver.
+// The wrong (first) trait bound was selected.
+// This is fixed with new logic for unsizing coercions
+// that's independent from that of the old solver, which this test verifies.
+
+trait Super<'a> {}
+trait Trait<'a>: Super<'a> + for<'hr> Super<'hr> {}
+//[current]~^ ERROR type annotations needed: cannot satisfy `Self: Super<'a>`
+
+fn foo<'a>(x: Box>) -> Box> {
+    x
+    //[next]~^ ERROR type annotations needed: cannot satisfy `dyn Trait<'_>: Unsize>
+}
+
+fn main() {}
diff --git a/tests/ui/traits/next-solver/unsize-overflow.rs b/tests/ui/traits/next-solver/unsize-overflow.rs
new file mode 100644
index 000000000000..036be02aaeae
--- /dev/null
+++ b/tests/ui/traits/next-solver/unsize-overflow.rs
@@ -0,0 +1,7 @@
+//@ compile-flags: -Znext-solver
+#![recursion_limit = "8"]
+
+fn main() {
+    let _: Box = Box::new(&&&&&&&1);
+    //~^ ERROR overflow evaluating the requirement `Box<&&&&&&&i32>: CoerceUnsized>
+}
diff --git a/tests/ui/traits/next-solver/unsize-overflow.stderr b/tests/ui/traits/next-solver/unsize-overflow.stderr
new file mode 100644
index 000000000000..ae0f2957243c
--- /dev/null
+++ b/tests/ui/traits/next-solver/unsize-overflow.stderr
@@ -0,0 +1,12 @@
+error[E0275]: overflow evaluating the requirement `Box<&&&&&&&i32>: CoerceUnsized>`
+  --> $DIR/unsize-overflow.rs:5:28
+   |
+LL |     let _: Box = Box::new(&&&&&&&1);
+   |                            ^^^^^^^^^^^^^^^^^^
+   |
+   = help: consider increasing the recursion limit by adding a `#![recursion_limit = "16"]` attribute to your crate (`unsize_overflow`)
+   = note: required for the cast from `Box<&&&&&&&i32>` to `Box`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0275`.
diff --git a/tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ub.next.stderr b/tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ub.next.stderr
index b82f1eef42b5..392680aa5064 100644
--- a/tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ub.next.stderr
+++ b/tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ub.next.stderr
@@ -1,14 +1,13 @@
-error[E0308]: mismatched types
+error[E0277]: the trait bound `&dyn for<'a> Subtrait<'a, 'a>: CoerceUnsized<&dyn for<'a, 'b> Supertrait<'a, 'b>>` is not satisfied
   --> $DIR/higher-ranked-upcasting-ub.rs:22:5
    |
-LL | fn unsound(x: &dyn for<'a> Subtrait<'a, 'a>) -> &dyn for<'a, 'b> Supertrait<'a, 'b> {
-   |                                                 ----------------------------------- expected `&dyn for<'a, 'b> Supertrait<'a, 'b>` because of return type
 LL |     x
-   |     ^ expected trait `Supertrait`, found trait `Subtrait`
+   |     ^ the trait `Unsize Supertrait<'a, 'b>>` is not implemented for `dyn for<'a> Subtrait<'a, 'a>`
    |
-   = note: expected reference `&dyn for<'a, 'b> Supertrait<'a, 'b>`
-              found reference `&dyn for<'a> Subtrait<'a, 'a>`
+   = note: all implementations of `Unsize` are provided automatically by the compiler, see  for more information
+   = note: required for `&dyn for<'a> Subtrait<'a, 'a>` to implement `CoerceUnsized<&dyn for<'a, 'b> Supertrait<'a, 'b>>`
+   = note: required for the cast from `&dyn for<'a> Subtrait<'a, 'a>` to `&dyn for<'a, 'b> Supertrait<'a, 'b>`
 
 error: aborting due to 1 previous error
 
-For more information about this error, try `rustc --explain E0308`.
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ub.rs b/tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ub.rs
index af2594b95f3d..98ca30ca391f 100644
--- a/tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ub.rs
+++ b/tests/ui/traits/trait-upcasting/higher-ranked-upcasting-ub.rs
@@ -19,8 +19,10 @@ impl<'a> Supertrait<'a, 'a> for () {
 }
 impl<'a> Subtrait<'a, 'a> for () {}
 fn unsound(x: &dyn for<'a> Subtrait<'a, 'a>) -> &dyn for<'a, 'b> Supertrait<'a, 'b> {
-    x //~ ERROR mismatched types
+    x
     //[current]~^ ERROR mismatched types
+    //[current]~| ERROR mismatched types
+    //[next]~^^^ ERROR the trait bound `&dyn for<'a> Subtrait<'a, 'a>: CoerceUnsized<&dyn for<'a, 'b> Supertrait<'a, 'b>>` is not satisfied
 }
 
 fn transmute<'a, 'b>(x: &'a str) -> &'b str {
diff --git a/tests/ui/typeck/assign-non-lval-derefmut.stderr b/tests/ui/typeck/assign-non-lval-derefmut.stderr
index f57b5abe2eed..a0ba0eae1e44 100644
--- a/tests/ui/typeck/assign-non-lval-derefmut.stderr
+++ b/tests/ui/typeck/assign-non-lval-derefmut.stderr
@@ -19,10 +19,10 @@ LL |     x.lock().unwrap() += 1;
    |     |
    |     cannot use `+=` on type `std::sync::MutexGuard<'_, usize>`
    |
-note: the foreign item type `std::sync::MutexGuard<'_, usize>` doesn't implement `AddAssign<{integer}>`
+note: `std::sync::MutexGuard<'_, usize>` does not implement `AddAssign<{integer}>`
   --> $SRC_DIR/std/src/sync/poison/mutex.rs:LL:COL
    |
-   = note: not implement `AddAssign<{integer}>`
+   = note: `std::sync::MutexGuard<'_, usize>` is defined in another crate
 help: `+=` can be used on `usize` if you dereference the left-hand side
    |
 LL |     *x.lock().unwrap() += 1;
@@ -51,10 +51,10 @@ LL |     y += 1;
    |     |
    |     cannot use `+=` on type `std::sync::MutexGuard<'_, usize>`
    |
-note: the foreign item type `std::sync::MutexGuard<'_, usize>` doesn't implement `AddAssign<{integer}>`
+note: `std::sync::MutexGuard<'_, usize>` does not implement `AddAssign<{integer}>`
   --> $SRC_DIR/std/src/sync/poison/mutex.rs:LL:COL
    |
-   = note: not implement `AddAssign<{integer}>`
+   = note: `std::sync::MutexGuard<'_, usize>` is defined in another crate
 help: `+=` can be used on `usize` if you dereference the left-hand side
    |
 LL |     *y += 1;
diff --git a/tests/ui/typeck/minus-string.stderr b/tests/ui/typeck/minus-string.stderr
index d2ebcd01ff9c..fee723baff19 100644
--- a/tests/ui/typeck/minus-string.stderr
+++ b/tests/ui/typeck/minus-string.stderr
@@ -4,10 +4,10 @@ error[E0600]: cannot apply unary operator `-` to type `String`
 LL |     -"foo".to_string();
    |     ^^^^^^^^^^^^^^^^^^ cannot apply unary operator `-`
    |
-note: the foreign item type `String` doesn't implement `Neg`
+note: `String` does not implement `Neg`
   --> $SRC_DIR/alloc/src/string.rs:LL:COL
    |
-   = note: not implement `Neg`
+   = note: `String` is defined in another crate
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/wf/range-expr-root-of-constant-issue-40749.rs b/tests/ui/wf/range-expr-root-of-constant-issue-40749.rs
index 7871612dc8b7..bec92448d1c8 100644
--- a/tests/ui/wf/range-expr-root-of-constant-issue-40749.rs
+++ b/tests/ui/wf/range-expr-root-of-constant-issue-40749.rs
@@ -4,4 +4,6 @@ fn main() {
     //~| NOTE expected type `usize`
     //~| NOTE found struct `RangeTo<{integer}>`
     //~| NOTE expected `usize`, found `RangeTo<{integer}>
+    //~| NOTE in this expansion of desugaring of range expression
+    //~| NOTE in this expansion of desugaring of range expression
 }
diff --git a/triagebot.toml b/triagebot.toml
index a0d0b1892e4f..7a4e0bb5f43b 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -644,7 +644,7 @@ trigger_files = [
 zulip_stream = 245100 # #t-compiler/prioritization/alerts
 topic = "#{number} {title}"
 message_on_add = """\
-@*WG-prioritization/alerts* issue #{number} has been requested for prioritization.
+Issue #{number} has been requested for prioritization.
 
 # [Procedure](https://forge.rust-lang.org/compiler/prioritization.html)
 - Priority?
@@ -738,12 +738,12 @@ message_on_reopen = "PR #{number} has been reopened. Pinging @*T-rustdoc*."
 [notify-zulip."beta-nominated".compiler]
 required_labels = ["T-compiler"]
 zulip_stream = 474880 # #t-compiler/backports
-topic = "#{number}: beta-backport nomination"
+topic = "#{number}: beta-nominated"
 message_on_add = [
     """\
-PR #{number} "{title}" fixes a regression.
-{recipients}, please evaluate nominating this PR for backport.
-The following poll is a vibe-check and not binding.
+PR #{number} "{title}" fixes a regression and has been nominated for backport.
+{recipients}, what do you think about it?
+This topic will help T-compiler getting context about it.
 """,
     """\
 /poll Should #{number} be beta backported?
@@ -757,7 +757,7 @@ message_on_remove = "PR #{number}'s beta-nomination has been removed."
 [notify-zulip."beta-accepted".compiler]
 required_labels = ["T-compiler"]
 zulip_stream = 474880 # #t-compiler/backports
-# Put it in the same thread as beta-nominated.
+# Put it in the same Zulip topic as beta-nominated.
 topic = "#{number}: beta-nominated"
 message_on_add = "PR #{number} has been **accepted** for **beta** backport."