From a78b70d1cea8cfc9c64c5a37a5d6a73e7d5512cb Mon Sep 17 00:00:00 2001 From: The 8472 Date: Wed, 15 Jul 2026 01:52:07 +0200 Subject: [PATCH 01/76] implement StdioExt for windows --- library/std/src/os/windows/io/mod.rs | 109 ++++++++++++++++++ library/std/src/os/windows/io/raw.rs | 2 +- .../std/src/sys/pal/windows/c/bindings.txt | 1 + .../std/src/sys/pal/windows/c/windows_sys.rs | 1 + 4 files changed, 112 insertions(+), 1 deletion(-) diff --git a/library/std/src/os/windows/io/mod.rs b/library/std/src/os/windows/io/mod.rs index 3d3ae38788639..db0ec8f2fbb2e 100644 --- a/library/std/src/os/windows/io/mod.rs +++ b/library/std/src/os/windows/io/mod.rs @@ -65,5 +65,114 @@ pub use raw::*; #[stable(feature = "io_safety", since = "1.63.0")] pub use socket::*; +use crate::io::{self, Stderr, StderrLock, Stdin, StdinLock, Stdout, StdoutLock, Write}; +use crate::ptr; +#[cfg(not(doc))] +use crate::sys::c; + #[cfg(test)] mod tests; + +#[unstable(feature = "stdio_swap", issue = "150667", reason = "recently added")] +pub impl(self) trait StdioExt { + /// Sets the stdio console handle to `handle`, or `NULL` if it is `None`. + /// The old handle, if any, will not be closed, i.e. it is leaked because + /// console handles are shared global resources. + /// + /// Rust std::io write buffers (if any) are flushed, but other runtimes + /// (e.g. C stdio) or libraries that acquire a clone of the file handle + /// will not be aware of this change. + /// + /// ``` + /// #![feature(stdio_swap)] + /// use std::io::{self, Read, Write}; + /// use std::os::windows::io::StdioExt; + /// + /// fn main() -> io::Result<()> { + /// let (reader, mut writer) = io::pipe()?; + /// let mut stdin = io::stdin(); + /// stdin.set_handle(Some(reader))?; + /// writer.write_all(b"Hello, world!")?; + /// let mut buffer = vec![0; 13]; + /// assert_eq!(stdin.read(&mut buffer)?, 13); + /// assert_eq!(&buffer, b"Hello, world!"); + /// Ok(()) + /// } + /// ``` + fn set_handle>(&mut self, handle: Option) -> io::Result<()>; + + /// Sets the stdio console handle to `replace_with`. The previous handle is returned, or + /// `None` if it was `NULL`. + /// + /// The returned handle is a `BorrowedHandle<'static>` because console handles are shared global resources + /// and may have been obtained by other functions or threads. + /// Only if you have ensured that no other part of the program has borrowed this handle you can convert it into + /// an `OwnedHandle` and drop that to close it. + /// + /// Like `set_handle()`, Rust std::io write buffers (if any) are flushed. + fn replace_handle>( + &mut self, + replace_with: T, + ) -> io::Result>>; + + /// Sets the stdio console handle to `NULL` and returns the old one + /// + /// See [`set_handle()`] for additional details. + /// + /// [`set_handle()`]: StdioExt::set_handle + fn take_handle(&mut self) -> io::Result>>; +} + +macro io_ext_impl($stdio_ty:ty, $stdio_lock_ty:ty, $handle:path, $writer:literal) { + #[unstable(feature = "stdio_swap", issue = "150667", reason = "recently added")] + impl StdioExt for $stdio_ty { + fn set_handle>(&mut self, handle: Option) -> io::Result<()> { + self.lock().set_handle(handle) + } + + fn replace_handle>( + &mut self, + replace_with: T, + ) -> io::Result>> { + self.lock().replace_handle(replace_with) + } + + fn take_handle(&mut self) -> io::Result>> { + self.lock().take_handle() + } + } + + #[unstable(feature = "stdio_swap", issue = "150667", reason = "recently added")] + impl StdioExt for $stdio_lock_ty { + fn set_handle>(&mut self, handle: Option) -> io::Result<()> { + #[cfg($writer)] + self.flush()?; + let raw = handle.map(|h| h.into().into_raw_handle()).unwrap_or(ptr::null_mut()); + unsafe { c::SetStdHandle($handle, raw) }; + Ok(()) + } + + fn replace_handle>( + &mut self, + replace_with: T, + ) -> io::Result>> { + let old = unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) }; + self.set_handle(Some(replace_with))?; + let handle = if old.as_raw_handle().is_null() { None } else { Some(old) }; + Ok(handle) + } + + fn take_handle(&mut self) -> io::Result>> { + let old = unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) }; + #[cfg($writer)] + self.flush()?; + unsafe { c::SetStdHandle($handle, ptr::null_mut()) }; + let handle = if old.as_raw_handle().is_null() { None } else { Some(old) }; + Ok(handle) + } + } +} + +io_ext_impl!(Stdout, StdoutLock<'_>, c::STD_OUTPUT_HANDLE, true); +io_ext_impl!(Stdin, StdinLock<'_>, c::STD_INPUT_HANDLE, false); +io_ext_impl!(Stderr, StderrLock<'_>, c::STD_ERROR_HANDLE, true); diff --git a/library/std/src/os/windows/io/raw.rs b/library/std/src/os/windows/io/raw.rs index 0d3f24005f369..d050c28832517 100644 --- a/library/std/src/os/windows/io/raw.rs +++ b/library/std/src/os/windows/io/raw.rs @@ -142,7 +142,7 @@ impl<'a> AsRawHandle for io::StderrLock<'a> { // Translate a handle returned from `GetStdHandle` into a handle to return to // the user. -fn stdio_handle(raw: RawHandle) -> RawHandle { +pub(super) fn stdio_handle(raw: RawHandle) -> RawHandle { // `GetStdHandle` isn't expected to actually fail, so when it returns // `INVALID_HANDLE_VALUE`, it means we were launched from a parent which // didn't provide us with stdio handles, such as a parent with a detached diff --git a/library/std/src/sys/pal/windows/c/bindings.txt b/library/std/src/sys/pal/windows/c/bindings.txt index ac1603020312f..dd252a026ad70 100644 --- a/library/std/src/sys/pal/windows/c/bindings.txt +++ b/library/std/src/sys/pal/windows/c/bindings.txt @@ -2390,6 +2390,7 @@ SetFileTime SetHandleInformation SetLastError setsockopt +SetStdHandle SetThreadStackGuarantee SetWaitableTimer shutdown diff --git a/library/std/src/sys/pal/windows/c/windows_sys.rs b/library/std/src/sys/pal/windows/c/windows_sys.rs index 2348f890d8a1d..6d0e417b11381 100644 --- a/library/std/src/sys/pal/windows/c/windows_sys.rs +++ b/library/std/src/sys/pal/windows/c/windows_sys.rs @@ -100,6 +100,7 @@ windows_link::link!("kernel32.dll" "system" fn SetFilePointerEx(hfile : HANDLE, windows_link::link!("kernel32.dll" "system" fn SetFileTime(hfile : HANDLE, lpcreationtime : *const FILETIME, lplastaccesstime : *const FILETIME, lplastwritetime : *const FILETIME) -> BOOL); windows_link::link!("kernel32.dll" "system" fn SetHandleInformation(hobject : HANDLE, dwmask : u32, dwflags : HANDLE_FLAGS) -> BOOL); windows_link::link!("kernel32.dll" "system" fn SetLastError(dwerrcode : WIN32_ERROR)); +windows_link::link!("kernel32.dll" "system" fn SetStdHandle(nstdhandle : STD_HANDLE, hhandle : HANDLE) -> BOOL); windows_link::link!("kernel32.dll" "system" fn SetThreadStackGuarantee(stacksizeinbytes : *mut u32) -> BOOL); windows_link::link!("kernel32.dll" "system" fn SetWaitableTimer(htimer : HANDLE, lpduetime : *const i64, lperiod : i32, pfncompletionroutine : PTIMERAPCROUTINE, lpargtocompletionroutine : *const core::ffi::c_void, fresume : BOOL) -> BOOL); windows_link::link!("kernel32.dll" "system" fn Sleep(dwmilliseconds : u32)); From 5e53b072c38c04c93b17b1d3871488f395e214ca Mon Sep 17 00:00:00 2001 From: edragain Date: Sat, 18 Jul 2026 08:11:04 +0000 Subject: [PATCH 02/76] fix: fix syntax bridge panic when spilting float --- .../crates/syntax-bridge/src/lib.rs | 15 +++++- .../crates/syntax-bridge/src/tests.rs | 51 ++++++++++++++++++- 2 files changed, 64 insertions(+), 2 deletions(-) diff --git a/src/tools/rust-analyzer/crates/syntax-bridge/src/lib.rs b/src/tools/rust-analyzer/crates/syntax-bridge/src/lib.rs index 0dcf18a4ad97a..181f9a14e764d 100644 --- a/src/tools/rust-analyzer/crates/syntax-bridge/src/lib.rs +++ b/src/tools/rust-analyzer/crates/syntax-bridge/src/lib.rs @@ -903,7 +903,20 @@ impl TtTreeSink<'_> { } self.text_pos += TextSize::of(text); } - None => unreachable!(), + None => { + self.error("illegal float literal".to_owned()); + self.inner.start_node(SyntaxKind::ERROR); + self.inner.token(SyntaxKind::FLOAT_NUMBER, text); + self.token_map.push(self.text_pos + TextSize::of(text), span); + self.inner.finish_node(); + self.inner.finish_node(); + + if !has_pseudo_dot { + self.inner.finish_node(); + } + + self.text_pos += TextSize::of(text); + } } self.cursor.bump(); } diff --git a/src/tools/rust-analyzer/crates/syntax-bridge/src/tests.rs b/src/tools/rust-analyzer/crates/syntax-bridge/src/tests.rs index 16f2498bf357c..691084d8b0965 100644 --- a/src/tools/rust-analyzer/crates/syntax-bridge/src/tests.rs +++ b/src/tools/rust-analyzer/crates/syntax-bridge/src/tests.rs @@ -1,3 +1,4 @@ +use expect_test::expect; use rustc_hash::FxHashMap; use span::Span; use syntax::{AstNode, ast}; @@ -7,7 +8,7 @@ use tt::{Leaf, Punct, Spacing, buffer::Cursor}; use crate::{ DocCommentDesugarMode, dummy_test_span_utils::{DUMMY, DummyTestSpanMap}, - syntax_node_to_token_tree, + parse_to_token_tree_static_span, syntax_node_to_token_tree, token_tree_to_syntax_node, }; fn check_punct_spacing(fixture: &str) { @@ -97,3 +98,51 @@ fn main() { "#, ); } + +#[test] +fn scientific_notation_field_access_recovers() { + let tt = parse_to_token_tree_static_span( + span::Edition::CURRENT, + DUMMY, + r#" +fn main() { + s.00E+10; +} +"#, + ) + .unwrap(); + + let (parse, _) = token_tree_to_syntax_node(&tt, parser::TopEntryPoint::SourceFile, &mut |_| { + span::Edition::CURRENT + }); + let parse = parse.cast::().unwrap(); + + expect![[r#" + SOURCE_FILE@0..19 + FN@0..19 + FN_KW@0..2 "fn" + NAME@2..6 + IDENT@2..6 "main" + PARAM_LIST@6..8 + L_PAREN@6..7 "(" + R_PAREN@7..8 ")" + BLOCK_EXPR@8..19 + STMT_LIST@8..19 + L_CURLY@8..9 "{" + EXPR_STMT@9..18 + FIELD_EXPR@9..17 + FIELD_EXPR@9..17 + PATH_EXPR@9..10 + PATH@9..10 + PATH_SEGMENT@9..10 + NAME_REF@9..10 + IDENT@9..10 "s" + DOT@10..11 "." + ERROR@11..17 + FLOAT_NUMBER@11..17 "00E+10" + SEMICOLON@17..18 ";" + R_CURLY@18..19 "}" + error 11..11: illegal float literal + "#]] + .assert_eq(&parse.debug_dump()); +} From f1dc71fe96591fd1a7855edb617f35d75f072af7 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Sun, 19 Jul 2026 00:29:32 +0300 Subject: [PATCH 03/76] Eagerly normalize `.await`'s `IntoFuture::Output` The lack of this has caused an error when it diverges, because `shallow_resolve(ty).is_never()` was false. Given that we should switch to eager normalization anyway, like rustc, this makes sense to do. Also switch the `shallow_resolve(ty).is_never()` to `resolve_vars_with_obligations(ty).is_never()`, because rustc uses this function. And three drive-by changes: - Change referrals to Chalk in logging into next-solver; - In `setup_tracing()`, do not cache the existence of the env var. This function is not perf-sensitive, and caching it means it's more complicated than necessary to change it mid-execution. - Rearrange `expr_guaranteed_to_constitute_read_for_never()` a bit. --- .../crates/hir-ty/src/infer/expr.rs | 33 ++++++++---------- .../rust-analyzer/crates/hir-ty/src/lib.rs | 8 +---- .../crates/hir-ty/src/tests/never_type.rs | 16 +++++++++ .../crates/rust-analyzer/src/bin/main.rs | 2 +- .../rust-analyzer/src/tracing/config.rs | 34 ++++++++++--------- .../rust-analyzer/tests/slow-tests/support.rs | 2 +- 6 files changed, 51 insertions(+), 44 deletions(-) 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 3356c4d78ae88..1e917719da26c 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 @@ -143,29 +143,22 @@ impl<'db> InferenceContext<'_, 'db> { expr: ExprId, is_read: ExprIsRead, ) -> bool { - // rustc does the place expr check first, but since we are feeding - // readness of the `expr` as a given value, we just can short-circuit - // the place expr check if it's true(see codes and comments below) - if is_read == ExprIsRead::Yes { - return true; - } - - // We only care about place exprs. Anything else returns an immediate - // which would constitute a read. We don't care about distinguishing - // "syntactic" place exprs since if the base of a field projection is - // not a place then it would've been UB to read from it anyways since - // that constitutes a read. - if !self.is_syntactic_place_expr(expr) { - return true; - } - // rustc queries parent hir node of `expr` here and determine whether // the current `expr` is read of value per its parent. // But since we don't have hir node, we cannot follow such "bottom-up" // method. // So, we pass down such readness from the parent expression through the // recursive `infer_expr*` calls in a "top-down" manner. + // rustc does the place expr check first, but since we are feeding + // readness of the `expr` as a given value, we just can short-circuit + // the place expr check if it's true(see codes and comments below) is_read == ExprIsRead::Yes + // We only care about place exprs. Anything else returns an immediate + // which would constitute a read. We don't care about distinguishing + // "syntactic" place exprs since if the base of a field projection is + // not a place then it would've been UB to read from it anyways since + // that constitutes a read. + || !self.is_syntactic_place_expr(expr) } /// Whether this pattern constitutes a read of value of the scrutinee that @@ -904,7 +897,7 @@ impl<'db> InferenceContext<'_, 'db> { }; let ty = self.insert_type_vars_shallow(ty); self.write_expr_ty(tgt_expr, ty); - if self.shallow_resolve(ty).is_never() + if self.table.resolve_vars_with_obligations(ty).is_never() && self.expr_guaranteed_to_constitute_read_for_never(tgt_expr, is_read) { // Any expression that produces a value of type `!` must have diverged @@ -969,8 +962,10 @@ impl<'db> InferenceContext<'_, 'db> { return self.types.types.error; }; self.table.register_bound(awaitee_ty, into_future, ObligationCause::new(expr)); - // Do not eagerly normalize. - Ty::new_projection(self.interner(), into_future_output.into(), [awaitee_ty]) + self.table.try_structurally_resolve_type( + expr.into(), + Ty::new_projection(self.interner(), into_future_output.into(), [awaitee_ty]), + ) } fn infer_record_expr( 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 778dbb0ff227d..1161d52e7f930 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs @@ -631,17 +631,11 @@ impl InferBodyId { pub fn setup_tracing() -> Option { use std::env; - use std::sync::LazyLock; use tracing_subscriber::{Registry, layer::SubscriberExt}; use tracing_tree::HierarchicalLayer; - static ENABLE: LazyLock = LazyLock::new(|| env::var("CHALK_DEBUG").is_ok()); - if !*ENABLE { - return None; - } - let filter: tracing_subscriber::filter::Targets = - env::var("CHALK_DEBUG").ok().and_then(|it| it.parse().ok()).unwrap_or_default(); + env::var("SOLVER_DEBUG").ok().and_then(|it| it.parse().ok()).unwrap_or_default(); let layer = HierarchicalLayer::default() .with_indent_lines(true) .with_ansi(false) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/never_type.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/never_type.rs index fd21286d50835..9d98218107106 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/never_type.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/never_type.rs @@ -901,3 +901,19 @@ fn example() -> Struct { "#, ); } + +#[test] +fn never_await() { + check_no_mismatches( + r#" +//- minicore: future +async fn test() -> ! { + loop {} +} + +pub async fn test1() -> ! { + test().await; +} + "#, + ); +} diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs index e05385528a052..6bd27c2621978 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs @@ -157,7 +157,7 @@ fn setup_logging(log_file_flag: Option) -> anyhow::Result<()> { // Deliberately enable all `warn` logs if the user has not set RA_LOG, as there is usually // useful information in there for debugging. filter: env::var("RA_LOG").ok().unwrap_or_else(|| "warn".to_owned()), - chalk_filter: env::var("CHALK_DEBUG").ok(), + solver_filter: env::var("SOLVER_DEBUG").ok(), profile_filter: env::var("RA_PROFILE").ok(), json_profile_filter: std::env::var("RA_PROFILE_JSON").ok(), } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/tracing/config.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/tracing/config.rs index 2bc9f3c34a5ba..9c6648916a259 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/tracing/config.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/tracing/config.rs @@ -20,16 +20,16 @@ use crate::tracing::json; pub struct Config { pub writer: T, pub filter: String, - /// The meaning of CHALK_DEBUG is to tell chalk crates - /// (i.e. chalk-solve, chalk-ir, chalk-recursive) how to filter tracing + /// The meaning of SOLVER_DEBUG is to tell the solver crates + /// (i.e. rustc_type_ir, rustc_next_trait_solver) how to filter tracing /// logs. But now we can only have just one filter, which means we have to - /// merge chalk filter to our main filter (from RA_LOG env). + /// merge the solver filter to our main filter (from RA_LOG env). /// - /// The acceptable syntax of CHALK_DEBUG is `target[span{field=value}]=level`. + /// The acceptable syntax of SOLVER_DEBUG is `target[span{field=value}]=level`. /// As the value should only affect chalk crates, we'd better manually - /// specify the target. And for simplicity, CHALK_DEBUG only accept the value + /// specify the target. And for simplicity, SOLVER_DEBUG only accept the value /// that specify level. - pub chalk_filter: Option, + pub solver_filter: Option, /// Filtering syntax, set in a shell: /// ```text /// env RA_PROFILE=* // dump everything @@ -75,22 +75,24 @@ where } .with_filter(targets_filter); - let chalk_layer = match self.chalk_filter { - Some(chalk_filter) => { + let solver_layer = match self.solver_filter { + Some(solver_filter) => { let level: LevelFilter = - chalk_filter.parse().with_context(|| "invalid chalk log filter")?; - - let chalk_filter = Targets::new() - .with_target("chalk_solve", level) - .with_target("chalk_ir", level) - .with_target("chalk_recursive", level); + solver_filter.parse().with_context(|| "invalid solver log filter")?; + + // Once with `ra_ap_` and once without; in-tree r-a uses without, out-of-tree uses with. + let solver_filter = Targets::new() + .with_target("ra_ap_rustc_type_ir", level) + .with_target("rustc_type_ir", level) + .with_target("ra_ap_rustc_next_trait_solver", level) + .with_target("rustc_next_trait_solver", level); // TODO: remove `.with_filter(LevelFilter::OFF)` on the `None` branch. HierarchicalLayer::default() .with_indent_lines(true) .with_ansi(false) .with_indent_amount(2) .with_writer(io::stderr) - .with_filter(chalk_filter) + .with_filter(solver_filter) .boxed() } None => None::.with_filter(LevelFilter::OFF).boxed(), @@ -122,7 +124,7 @@ where .with(ra_fmt_layer) .with(json_profiler_layer) .with(profiler_layer) - .with(chalk_layer); + .with(solver_layer); tracing::subscriber::set_global_default(subscriber)?; diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs index c3568ce950fd7..2a469a5bfb80f 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs @@ -170,7 +170,7 @@ impl Project<'_> { // Deliberately enable all `error` logs if the user has not set RA_LOG, as there is usually // useful information in there for debugging. filter: std::env::var("RA_LOG").ok().unwrap_or_else(|| "error".to_owned()), - chalk_filter: std::env::var("CHALK_DEBUG").ok(), + solver_filter: std::env::var("SOLVER_DEBUG").ok(), profile_filter: std::env::var("RA_PROFILE").ok(), json_profile_filter: std::env::var("RA_PROFILE_JSON").ok(), } From 3e7c36b9534031e5866c227e19a5e3b375004880 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 17 Jul 2026 17:45:50 +0200 Subject: [PATCH 04/76] Record obligation chain for unimplemented trait diagnostics --- .../hir-ty/src/next_solver/infer/errors.rs | 130 ++++++++++++------ .../crates/hir-ty/src/solver_errors.rs | 27 ++-- .../crates/hir/src/diagnostics.rs | 23 ++-- .../src/handlers/unimplemented_trait.rs | 30 ++-- .../crates/test-utils/src/lib.rs | 10 +- 5 files changed, 142 insertions(+), 78 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/errors.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/errors.rs index 7d3f111f668fa..c5eccdafd5e59 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/errors.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/errors.rs @@ -15,7 +15,7 @@ use crate::{ db::GeneralConstId, next_solver::{ AliasTerm, AnyImplId, Binder, ClauseKind, Const, ConstKind, DbInterner, - HostEffectPredicate, PolyTraitPredicate, PredicateKind, SolverContext, Term, + HostEffectPredicate, PolyTraitPredicate, Predicate, PredicateKind, SolverContext, Term, TraitPredicate, Ty, TyKind, TypeError, fulfill::NextSolverError, infer::{ @@ -32,10 +32,7 @@ use crate::{ pub struct FulfillmentError<'db> { pub obligation: PredicateObligation<'db>, pub code: FulfillmentErrorCode<'db>, - /// Diagnostics only: the 'root' obligation which resulted in - /// the failure to process `obligation`. This is the obligation - /// that was initially passed to `register_predicate_obligation` - pub root_obligation: PredicateObligation<'db>, + pub trait_obligation_chain: Vec>, } impl<'db> FulfillmentError<'db> { @@ -44,7 +41,8 @@ impl<'db> FulfillmentError<'db> { code: FulfillmentErrorCode<'db>, root_obligation: PredicateObligation<'db>, ) -> FulfillmentError<'db> { - FulfillmentError { obligation, code, root_obligation } + let trait_obligation_chain = trait_obligation_chain(&root_obligation, &obligation); + FulfillmentError { obligation, code, trait_obligation_chain } } pub fn is_true_error(&self) -> bool { @@ -130,7 +128,8 @@ fn fulfillment_error_for_no_solution<'db>( ) -> FulfillmentError<'db> { let interner = infcx.interner; let db = interner.db; - let obligation = find_best_leaf_obligation(infcx, &root_obligation, false); + let (obligation, trait_obligation_chain) = + find_best_leaf_obligation(infcx, &root_obligation, false); let code = match obligation.predicate.kind().skip_binder() { PredicateKind::Clause(ClauseKind::Projection(_)) => { @@ -189,7 +188,7 @@ fn fulfillment_error_for_no_solution<'db>( } }; - FulfillmentError { obligation, code, root_obligation } + FulfillmentError { obligation, code, trait_obligation_chain } } fn fulfillment_error_for_stalled<'db>( @@ -239,25 +238,27 @@ fn fulfillment_error_for_stalled<'db>( } }); - FulfillmentError { - obligation: if refine_obligation { - find_best_leaf_obligation(infcx, &root_obligation, true) - } else { - root_obligation.clone() - }, - code, - root_obligation, - } + let (obligation, trait_obligation_chain) = if refine_obligation { + find_best_leaf_obligation(infcx, &root_obligation, true) + } else { + let obligation = root_obligation.clone(); + let trait_obligation_chain = trait_obligation_chain(&root_obligation, &obligation); + (obligation, trait_obligation_chain) + }; + + FulfillmentError { obligation, code, trait_obligation_chain } } fn fulfillment_error_for_overflow<'db>( infcx: &InferCtxt<'db>, root_obligation: PredicateObligation<'db>, ) -> FulfillmentError<'db> { + let (obligation, trait_obligation_chain) = + find_best_leaf_obligation(infcx, &root_obligation, true); FulfillmentError { - obligation: find_best_leaf_obligation(infcx, &root_obligation, true), + obligation, code: FulfillmentErrorCode::Ambiguity { overflow: Some(true) }, - root_obligation, + trait_obligation_chain, } } @@ -266,34 +267,62 @@ fn find_best_leaf_obligation<'db>( infcx: &InferCtxt<'db>, obligation: &PredicateObligation<'db>, consider_ambiguities: bool, -) -> PredicateObligation<'db> { +) -> (PredicateObligation<'db>, Vec>) { let obligation = infcx.resolve_vars_if_possible(obligation.clone()); // FIXME: we use a probe here as the `BestObligation` visitor does not // check whether it uses candidates which get shadowed by where-bounds. // // We should probably fix the visitor to not do so instead, as this also // means the leaf obligation may be incorrect. - let obligation = infcx + let (obligation, trait_obligation_chain) = infcx .fudge_inference_if_ok(|| { + let mut visitor = BestObligation { + obligation: obligation.clone(), + consider_ambiguities, + trait_obligation_chain: trait_obligation_chain(&obligation, &obligation), + }; infcx - .visit_proof_tree( - obligation.as_goal(), - &mut BestObligation { obligation: obligation.clone(), consider_ambiguities }, - ) + .visit_proof_tree(obligation.as_goal(), &mut visitor) .break_value() .ok_or(()) // walk around the fact that the cause in `Obligation` is ignored by folders so that // we can properly fudge the infer vars in cause code. - .map(|o| (o.cause, o)) + .map(|(obligation, trait_obligation_chain)| { + (obligation.cause, obligation, trait_obligation_chain) + }) + }) + .map(|(cause, obligation, trait_obligation_chain)| { + (PredicateObligation { cause, ..obligation }, trait_obligation_chain) }) - .map(|(cause, o)| PredicateObligation { cause, ..o }) - .unwrap_or(obligation); - deeply_normalize_for_diagnostics(infcx, obligation.param_env, obligation) + .unwrap_or_else(|()| { + let trait_obligation_chain = trait_obligation_chain(&obligation, &obligation); + (obligation, trait_obligation_chain) + }); + let trait_obligation_chain = + deeply_normalize_for_diagnostics(infcx, obligation.param_env, trait_obligation_chain); + let obligation = deeply_normalize_for_diagnostics(infcx, obligation.param_env, obligation); + (obligation, trait_obligation_chain) +} + +fn trait_obligation_chain<'db>( + root_obligation: &PredicateObligation<'db>, + obligation: &PredicateObligation<'db>, +) -> Vec> { + let mut chain = Vec::new(); + if root_obligation.predicate.as_trait_clause().is_none() { + return chain; + } + chain.push(root_obligation.predicate); + if chain.last() != Some(&obligation.predicate) { + chain.push(obligation.predicate); + } + chain } struct BestObligation<'db> { obligation: PredicateObligation<'db>, consider_ambiguities: bool, + trait_obligation_chain: Vec>, } impl<'db> BestObligation<'db> { @@ -302,10 +331,25 @@ impl<'db> BestObligation<'db> { derived_obligation: PredicateObligation<'db>, and_then: impl FnOnce(&mut Self) -> >::Result, ) -> >::Result { + let should_push = derived_obligation.predicate.as_trait_clause().is_some() + && self.trait_obligation_chain.last() != Some(&derived_obligation.predicate); + if should_push { + self.trait_obligation_chain.push(derived_obligation.predicate); + } let old_obligation = std::mem::replace(&mut self.obligation, derived_obligation); - let res = and_then(self); + let result = and_then(self); self.obligation = old_obligation; - res + if should_push { + self.trait_obligation_chain.pop(); + } + result + } + + fn break_with_current_obligation(&mut self) -> >::Result { + ControlFlow::Break(( + self.obligation.clone(), + std::mem::take(&mut self.trait_obligation_chain), + )) } /// Filter out the candidates that aren't interesting to visit for the @@ -360,7 +404,7 @@ impl<'db> BestObligation<'db> { &mut self, candidate: &inspect::InspectCandidate<'_, 'db>, term: Term<'db>, - ) -> ControlFlow> { + ) -> >::Result { let _ = (candidate, term); // FIXME: rustc does this, but we don't process WF obligations yet: // let infcx = candidate.goal().infcx(); @@ -386,7 +430,7 @@ impl<'db> BestObligation<'db> { // self.with_derived_obligation(obligation, |this| nested_goal.visit_with(this))?; // } - ControlFlow::Break(self.obligation.clone()) + self.break_with_current_obligation() } /// If a normalization of an associated item or a trait goal fails without trying any @@ -396,7 +440,7 @@ impl<'db> BestObligation<'db> { &mut self, goal: &inspect::InspectGoal<'_, 'db>, self_ty: Ty<'db>, - ) -> ControlFlow> { + ) -> >::Result { assert!(!self.consider_ambiguities); let interner = goal.infcx().interner; if let TyKind::Alias(..) = self_ty.kind() { @@ -430,7 +474,7 @@ impl<'db> BestObligation<'db> { fn detect_trait_error_in_higher_ranked_projection( &mut self, goal: &inspect::InspectGoal<'_, 'db>, - ) -> ControlFlow> { + ) -> >::Result { let interner = goal.infcx().interner; if let Some(projection_clause) = goal.goal().predicate.as_projection_clause() && !projection_clause.bound_vars().is_empty() @@ -464,7 +508,7 @@ impl<'db> BestObligation<'db> { &mut self, goal: &inspect::InspectGoal<'_, 'db>, alias: AliasTerm<'db>, - ) -> ControlFlow> { + ) -> >::Result { let interner = goal.infcx().interner; let obligation = Obligation::new( interner, @@ -486,7 +530,7 @@ impl<'db> BestObligation<'db> { fn detect_error_from_empty_candidates( &mut self, goal: &inspect::InspectGoal<'_, 'db>, - ) -> ControlFlow> { + ) -> >::Result { let interner = goal.infcx().interner; let pred_kind = goal.goal().predicate.kind(); @@ -504,12 +548,12 @@ impl<'db> BestObligation<'db> { Some(_) | None => {} } - ControlFlow::Break(self.obligation.clone()) + self.break_with_current_obligation() } } impl<'db> ProofTreeVisitor<'db> for BestObligation<'db> { - type Result = ControlFlow>; + type Result = ControlFlow<(PredicateObligation<'db>, Vec>)>; fn span(&self) -> Span { self.obligation.cause.span() @@ -531,7 +575,7 @@ impl<'db> ProofTreeVisitor<'db> for BestObligation<'db> { let candidate = match candidates.as_slice() { [candidate] => candidate, [] => return self.detect_error_from_empty_candidates(goal), - _ => return ControlFlow::Break(self.obligation.clone()), + _ => return self.break_with_current_obligation(), }; // Don't walk into impls that have `do_not_recommend`. @@ -544,7 +588,7 @@ impl<'db> ProofTreeVisitor<'db> for BestObligation<'db> { .contains(AttrFlags::DIAGNOSTIC_DO_NOT_RECOMMEND) { trace!("#[diagnostic::do_not_recommend] -> exit"); - return ControlFlow::Break(self.obligation.clone()); + return self.break_with_current_obligation(); } // FIXME: Also, what about considering >1 layer up the stack? May be necessary @@ -587,7 +631,7 @@ impl<'db> ProofTreeVisitor<'db> for BestObligation<'db> { && Some(poly_trait_pred.def_id().0) == interner.lang_items().FnPtrTrait && let Err(NoSolution) = nested_goal.result() { - return ControlFlow::Break(self.obligation.clone()); + return self.break_with_current_obligation(); } } @@ -661,7 +705,7 @@ impl<'db> ProofTreeVisitor<'db> for BestObligation<'db> { self.detect_trait_error_in_higher_ranked_projection(goal)?; - ControlFlow::Break(self.obligation.clone()) + self.break_with_current_obligation() } } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/solver_errors.rs b/src/tools/rust-analyzer/crates/hir-ty/src/solver_errors.rs index e4e76fa67bacb..75f1de32881b6 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/solver_errors.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/solver_errors.rs @@ -29,7 +29,7 @@ pub struct SolverDiagnostic { pub enum SolverDiagnosticKind { TraitUnimplemented { trait_predicate: StoredTraitPredicate, - root_trait_predicate: Option, + parent_trait_predicates: Vec, }, } @@ -78,13 +78,22 @@ fn handle_trait_unimplemented<'db>( polarity: trait_pred.polarity, }; - let root_trait_predicate = match error.root_obligation.predicate.kind().skip_binder() { - PredicateKind::Clause(ClauseKind::Trait(trait_pred)) => Some(StoredTraitPredicate { - trait_ref: StoredTraitRef::new(trait_pred.trait_ref), - polarity: trait_pred.polarity, - }), - _ => None, - }; + let mut parent_trait_predicates = error + .trait_obligation_chain + .iter() + .filter_map(|predicate| predicate.as_trait_clause()) + .map(|trait_predicate| { + let trait_predicate = trait_predicate.skip_binder(); + StoredTraitPredicate { + trait_ref: StoredTraitRef::new(trait_predicate.trait_ref), + polarity: trait_predicate.polarity, + } + }) + .collect::>(); + if parent_trait_predicates.last() == Some(&trait_predicate) { + parent_trait_predicates.pop(); + } + parent_trait_predicates.reverse(); - Some(SolverDiagnosticKind::TraitUnimplemented { trait_predicate, root_trait_predicate }) + Some(SolverDiagnosticKind::TraitUnimplemented { trait_predicate, parent_trait_predicates }) } diff --git a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs index b921a5eef14a9..586786e81acac 100644 --- a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs +++ b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs @@ -677,7 +677,7 @@ pub struct PatternArgInExternFn { pub struct UnimplementedTrait<'db> { pub span: SpanSyntax, pub trait_predicate: crate::TraitPredicate<'db>, - pub root_trait_predicate: Option>, + pub parent_trait_predicates: Vec>, } #[derive(Debug)] @@ -1152,19 +1152,22 @@ impl<'db> AnyDiagnostic<'db> { ) -> Option> { let interner = DbInterner::new_no_crate(db); Some(match d { - SolverDiagnosticKind::TraitUnimplemented { trait_predicate, root_trait_predicate } => { + SolverDiagnosticKind::TraitUnimplemented { + trait_predicate, + parent_trait_predicates, + } => { let trait_predicate = crate::TraitPredicate { inner: trait_predicate.get(interner), owner: type_owner, }; - let root_trait_predicate = - root_trait_predicate.as_ref().map(|root_trait_predicate| { - crate::TraitPredicate { - inner: root_trait_predicate.get(interner), - owner: type_owner, - } - }); - UnimplementedTrait { span, trait_predicate, root_trait_predicate }.into() + let parent_trait_predicates = parent_trait_predicates + .iter() + .map(|trait_predicate| crate::TraitPredicate { + inner: trait_predicate.get(interner), + owner: type_owner, + }) + .collect(); + UnimplementedTrait { span, trait_predicate, parent_trait_predicates }.into() } }) } diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unimplemented_trait.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unimplemented_trait.rs index 4a253bc8310c0..702f9fa7c9976 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unimplemented_trait.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unimplemented_trait.rs @@ -9,18 +9,19 @@ pub(crate) fn unimplemented_trait<'db>( ctx: &DiagnosticsContext<'_, 'db>, d: &hir::UnimplementedTrait<'db>, ) -> Diagnostic { - let message = match &d.root_trait_predicate { - Some(root_predicate) if *root_predicate != d.trait_predicate => format!( - "the trait bound `{}` is not satisfied\n\ - required by the bound `{}`\n", - d.trait_predicate.display(ctx.db(), ctx.display_target), - root_predicate.display(ctx.db(), ctx.display_target), - ), - _ => format!( - "the trait bound `{}` is not satisfied", - d.trait_predicate.display(ctx.db(), ctx.display_target), - ), - }; + let mut message = format!( + "the trait bound `{}` is not satisfied", + d.trait_predicate.display(ctx.db(), ctx.display_target), + ); + for parent_predicate in &d.parent_trait_predicates { + message.push_str(&format!( + "\nrequired by the bound `{}`", + parent_predicate.display(ctx.db(), ctx.display_target), + )); + } + if !d.parent_trait_predicates.is_empty() { + message.push('\n'); + } Diagnostic::new_with_syntax_node_ptr( ctx, DiagnosticCode::RustcHardError("E0277"), @@ -46,6 +47,10 @@ fn bar() { foo([1]); // ^^^ error: the trait bound `i32: Trait` is not satisfied // | required by the bound `[i32; 1]: Trait` + foo([[1]]); + // ^^^ error: the trait bound `i32: Trait` is not satisfied + // | required by the bound `[i32; 1]: Trait` + // | required by the bound `[[i32; 1]; 1]: Trait` } "#, ); @@ -77,7 +82,6 @@ fn foo() { //- minicore: iterator fn foo() { for _ in () {} - // ^^ error: the trait bound `(): Iterator` is not satisfied // ^^ error: the trait bound `(): Iterator` is not satisfied // | required by the bound `(): IntoIterator` } diff --git a/src/tools/rust-analyzer/crates/test-utils/src/lib.rs b/src/tools/rust-analyzer/crates/test-utils/src/lib.rs index 4eab7f4b18424..cf75017572580 100644 --- a/src/tools/rust-analyzer/crates/test-utils/src/lib.rs +++ b/src/tools/rust-analyzer/crates/test-utils/src/lib.rs @@ -261,9 +261,12 @@ pub fn extract_annotations(text: &str) -> Vec<(TextRange, String)> { .iter() .find(|&&(off, _idx)| off == offset) .expect("annotation continuation not found"); - res[idx].1.push('\n'); + if !res[idx].1.ends_with('\n') { + res[idx].1.push('\n'); + } res[idx].1.push_str(&content); res[idx].1.push('\n'); + this_line_annotations.push((offset, idx)); } } } @@ -352,6 +355,7 @@ fn main() { zoo + 1 } //^^^ type: // | i32 + // | u32 // ^file "#, @@ -363,9 +367,9 @@ fn main() { assert_eq!( res[..3], - [("x", "def".into()), ("y", "def".into()), ("zoo", "type:\ni32\n".into())] + [("x", "def".into()), ("y", "def".into()), ("zoo", "type:\ni32\nu32\n".into())] ); - assert_eq!(res[3].0.len(), 115); + assert_eq!(res[3].0.len(), 127); } #[test] From 87f2ae3946c2cd10ec5677c2cbbaad05426ae0bc Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sun, 19 Jul 2026 10:28:55 +0200 Subject: [PATCH 05/76] Simplify --- .../hir-ty/src/next_solver/infer/errors.rs | 80 ++++++------------- .../crates/hir-ty/src/solver_errors.rs | 5 +- 2 files changed, 27 insertions(+), 58 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/errors.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/errors.rs index c5eccdafd5e59..c3e9caa1c6766 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/errors.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/errors.rs @@ -32,19 +32,10 @@ use crate::{ pub struct FulfillmentError<'db> { pub obligation: PredicateObligation<'db>, pub code: FulfillmentErrorCode<'db>, - pub trait_obligation_chain: Vec>, + pub parent_trait_obligations: Vec>, } -impl<'db> FulfillmentError<'db> { - pub fn new( - obligation: PredicateObligation<'db>, - code: FulfillmentErrorCode<'db>, - root_obligation: PredicateObligation<'db>, - ) -> FulfillmentError<'db> { - let trait_obligation_chain = trait_obligation_chain(&root_obligation, &obligation); - FulfillmentError { obligation, code, trait_obligation_chain } - } - +impl FulfillmentError<'_> { pub fn is_true_error(&self) -> bool { match self.code { FulfillmentErrorCode::Select(_) @@ -128,7 +119,7 @@ fn fulfillment_error_for_no_solution<'db>( ) -> FulfillmentError<'db> { let interner = infcx.interner; let db = interner.db; - let (obligation, trait_obligation_chain) = + let (obligation, parent_trait_obligations) = find_best_leaf_obligation(infcx, &root_obligation, false); let code = match obligation.predicate.kind().skip_binder() { @@ -188,7 +179,7 @@ fn fulfillment_error_for_no_solution<'db>( } }; - FulfillmentError { obligation, code, trait_obligation_chain } + FulfillmentError { obligation, code, parent_trait_obligations } } fn fulfillment_error_for_stalled<'db>( @@ -238,27 +229,25 @@ fn fulfillment_error_for_stalled<'db>( } }); - let (obligation, trait_obligation_chain) = if refine_obligation { + let (obligation, parent_trait_obligations) = if refine_obligation { find_best_leaf_obligation(infcx, &root_obligation, true) } else { - let obligation = root_obligation.clone(); - let trait_obligation_chain = trait_obligation_chain(&root_obligation, &obligation); - (obligation, trait_obligation_chain) + (root_obligation, Vec::new()) }; - FulfillmentError { obligation, code, trait_obligation_chain } + FulfillmentError { obligation, code, parent_trait_obligations } } fn fulfillment_error_for_overflow<'db>( infcx: &InferCtxt<'db>, root_obligation: PredicateObligation<'db>, ) -> FulfillmentError<'db> { - let (obligation, trait_obligation_chain) = + let (obligation, parent_trait_obligations) = find_best_leaf_obligation(infcx, &root_obligation, true); FulfillmentError { obligation, code: FulfillmentErrorCode::Ambiguity { overflow: Some(true) }, - trait_obligation_chain, + parent_trait_obligations, } } @@ -274,12 +263,12 @@ fn find_best_leaf_obligation<'db>( // // We should probably fix the visitor to not do so instead, as this also // means the leaf obligation may be incorrect. - let (obligation, trait_obligation_chain) = infcx + let (obligation, parent_trait_obligations) = infcx .fudge_inference_if_ok(|| { let mut visitor = BestObligation { obligation: obligation.clone(), consider_ambiguities, - trait_obligation_chain: trait_obligation_chain(&obligation, &obligation), + parent_trait_obligations: Vec::new(), }; infcx .visit_proof_tree(obligation.as_goal(), &mut visitor) @@ -287,42 +276,24 @@ fn find_best_leaf_obligation<'db>( .ok_or(()) // walk around the fact that the cause in `Obligation` is ignored by folders so that // we can properly fudge the infer vars in cause code. - .map(|(obligation, trait_obligation_chain)| { - (obligation.cause, obligation, trait_obligation_chain) + .map(|(obligation, parent_trait_obligations)| { + (obligation.cause, obligation, parent_trait_obligations) }) }) - .map(|(cause, obligation, trait_obligation_chain)| { - (PredicateObligation { cause, ..obligation }, trait_obligation_chain) + .map(|(cause, obligation, parent_trait_obligations)| { + (PredicateObligation { cause, ..obligation }, parent_trait_obligations) }) - .unwrap_or_else(|()| { - let trait_obligation_chain = trait_obligation_chain(&obligation, &obligation); - (obligation, trait_obligation_chain) - }); - let trait_obligation_chain = - deeply_normalize_for_diagnostics(infcx, obligation.param_env, trait_obligation_chain); + .unwrap_or((obligation, Vec::new())); + let parent_trait_obligations = + deeply_normalize_for_diagnostics(infcx, obligation.param_env, parent_trait_obligations); let obligation = deeply_normalize_for_diagnostics(infcx, obligation.param_env, obligation); - (obligation, trait_obligation_chain) -} - -fn trait_obligation_chain<'db>( - root_obligation: &PredicateObligation<'db>, - obligation: &PredicateObligation<'db>, -) -> Vec> { - let mut chain = Vec::new(); - if root_obligation.predicate.as_trait_clause().is_none() { - return chain; - } - chain.push(root_obligation.predicate); - if chain.last() != Some(&obligation.predicate) { - chain.push(obligation.predicate); - } - chain + (obligation, parent_trait_obligations) } struct BestObligation<'db> { obligation: PredicateObligation<'db>, consider_ambiguities: bool, - trait_obligation_chain: Vec>, + parent_trait_obligations: Vec>, } impl<'db> BestObligation<'db> { @@ -331,16 +302,17 @@ impl<'db> BestObligation<'db> { derived_obligation: PredicateObligation<'db>, and_then: impl FnOnce(&mut Self) -> >::Result, ) -> >::Result { - let should_push = derived_obligation.predicate.as_trait_clause().is_some() - && self.trait_obligation_chain.last() != Some(&derived_obligation.predicate); + let parent_predicate = self.obligation.predicate; + let should_push = parent_predicate.as_trait_clause().is_some() + && self.parent_trait_obligations.last() != Some(&parent_predicate); if should_push { - self.trait_obligation_chain.push(derived_obligation.predicate); + self.parent_trait_obligations.push(parent_predicate); } let old_obligation = std::mem::replace(&mut self.obligation, derived_obligation); let result = and_then(self); self.obligation = old_obligation; if should_push { - self.trait_obligation_chain.pop(); + self.parent_trait_obligations.pop(); } result } @@ -348,7 +320,7 @@ impl<'db> BestObligation<'db> { fn break_with_current_obligation(&mut self) -> >::Result { ControlFlow::Break(( self.obligation.clone(), - std::mem::take(&mut self.trait_obligation_chain), + std::mem::take(&mut self.parent_trait_obligations), )) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/solver_errors.rs b/src/tools/rust-analyzer/crates/hir-ty/src/solver_errors.rs index 75f1de32881b6..ab2dca0455aa8 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/solver_errors.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/solver_errors.rs @@ -79,7 +79,7 @@ fn handle_trait_unimplemented<'db>( }; let mut parent_trait_predicates = error - .trait_obligation_chain + .parent_trait_obligations .iter() .filter_map(|predicate| predicate.as_trait_clause()) .map(|trait_predicate| { @@ -90,9 +90,6 @@ fn handle_trait_unimplemented<'db>( } }) .collect::>(); - if parent_trait_predicates.last() == Some(&trait_predicate) { - parent_trait_predicates.pop(); - } parent_trait_predicates.reverse(); Some(SolverDiagnosticKind::TraitUnimplemented { trait_predicate, parent_trait_predicates }) From cf3dfb909d30255cbd24765a6184eabc8bbe7f5b Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sun, 19 Jul 2026 11:46:31 +0200 Subject: [PATCH 06/76] fix: Fix `InferenceContext:identity_args` using the wrong DefId --- src/tools/rust-analyzer/crates/hir-ty/src/infer.rs | 2 +- .../crates/hir-ty/src/tests/regression.rs | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) 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 ebcc0bd3f6f57..64d0e2a86406d 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs @@ -1994,7 +1994,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> { fn identity_args(&self) -> GenericArgs<'db> { *self.identity_args.get_or_init(|| { - GenericArgs::identity_for_item(self.interner(), self.store_owner.into()) + GenericArgs::identity_for_item(self.interner(), self.generic_def.into()) }) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs index dc882311871fb..0d08c75aad738 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs @@ -6,6 +6,16 @@ use crate::tests::check; use super::{check_infer, check_no_mismatches, check_types}; +#[test] +fn closure_in_enum_discriminant_does_not_panic() { + check( + r#" + enum Enum { X = || {} } + // ^^^^^ expected isize, got impl Fn() + "#, + ); +} + #[test] fn bug_484() { check_infer( From aea3da03b34f6243efcf6e8fb151372808e494dd Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sun, 19 Jul 2026 11:48:21 +0200 Subject: [PATCH 07/76] Improve AGENTS.md --- src/tools/rust-analyzer/CLAUDE.md | 78 +++++++++++++++++++------------ 1 file changed, 49 insertions(+), 29 deletions(-) diff --git a/src/tools/rust-analyzer/CLAUDE.md b/src/tools/rust-analyzer/CLAUDE.md index e8f699d92813a..4e536234ba100 100644 --- a/src/tools/rust-analyzer/CLAUDE.md +++ b/src/tools/rust-analyzer/CLAUDE.md @@ -1,40 +1,60 @@ -**Reminder: All AI usage must be disclosed in commit messages, see -CONTRIBUTING.md for more details.** +## AI Policy -## Build Commands +Follow `AI_POLICY.md`. In particular: -```bash -cargo build # Build all crates -cargo test # Run all tests -cargo test -p # Run tests for a specific crate (e.g., cargo test -p hir-ty) -cargo lint # Run clippy on all targets -cargo xtask codegen # Run code generation -cargo xtask tidy # Run tidy checks -UPDATE_EXPECT=1 cargo test # Update test expectations (snapshot tests) -RUN_SLOW_TESTS=1 cargo test # Run heavy/slow tests -``` +- Do not use AI to author issue/PR comments or replies to maintainers. +- Do not autonomously open issues or pull requests. +- Do not author code for issues labeled both `E-easy` and `E-has-instructions`. +- The human contributor must understand the changes and disclose AI use as required by the policy. -## Key Architectural Invariants -- Typing in a function body never invalidates global derived data -- Parser/syntax tree is built per-file to enable parallel parsing -- The server is stateless (HTTP-like); context must be re-created from request parameters -- Cancellation uses salsa's cancellation mechanism; computations panic with a `Cancelled` payload +## Repository Guides -### Code Generation +- Architecture and crate ownership: `docs/book/src/contributing/architecture.md` +- Rust style: `docs/book/src/contributing/style.md` +- Testing conventions and fixture syntax: `docs/book/src/contributing/testing.md` +- Contributor workflows: `docs/book/src/contributing/README.md` +- AI restrictions: `AI_POLICY.md` -Generated code is committed to the repo. Grammar and AST are generated from `ungrammar`. Run `cargo test -p xtask` after adding inline parser tests (`// test test_name` comments). +Read the relevant sections before making architectural, generated-code, protocol, or test-harness changes. + +## Change Workflow + +- Find the nearest existing implementation and its tests before adding new code. +- Extend existing helpers and test harnesses instead of creating parallel abstractions. +- Keep changes focused and prefer the smallest change that fits the existing design. +- When fixing a bug, add the smallest fixture that reproduces it and test the behavior through the existing interface. + +## Scope and Dependencies + +- Treat new `pub` items, public re-exports, and Cargo dependencies as architectural changes, not routine implementation details. +- Prefer keeping functionality inside the crate that owns the relevant data. +- Be conservative with crates.io dependencies. Reuse existing dependencies or `stdx`; do not add small helper crates without strong justification. + +## Key Invariants + +- User-provided Rust code, malformed syntax, broken builds, and proc-macro failures must not cause ordinary IDE features to panic. +- Assert invariants liberally. For impossible conditions from which the server can recover, prefer `stdx::never!` or `stdx::always!` and return a safe fallback instead of panicking. ## Testing -Tests are snapshot-based using `expect-test`. Test fixtures use a mini-language: -- `$0` marks cursor position -- `// ^^^^` labels attach to the line above -- `//- minicore: sized, fn` includes parts of minicore (minimal core library) -- `//- /path/to/file.rs crate:name deps:dep1,dep2` declares files/crates +- Many feature tests use Rust-code fixtures and `expect-test` snapshots. Follow the nearest existing test helper and fixture convention rather than introducing a new test harness. +- Before planning or writing fixture-based tests, review `docs/book/src/contributing/testing.md` for fixture annotations, `minicore`, and multi-file/multi-crate syntax. +- Keep Rust fixtures minimal; remove syntax unrelated to the behavior under test. +- Use unindented multiline raw strings, matching nearby tests. +- For regressions, first reproduce the failure with a focused test, then implement the fix. + +## Generated Code + +- Generated files are committed. Edit the generator rather than generated output. +- Run `cargo xtask codegen` after changing grammar, generated AST definitions, configuration schemas, or other codegen inputs. +- After adding parser inline tests (`// test name`), run `cargo test -p xtask`, update the relevant expectations, and inspect the generated diff. -## Style Notes +## Validation -- Use `stdx::never!` and `stdx::always!` instead of `assert!` for recoverable invariants -- Use `T![fn]` macro instead of `SyntaxKind::FN_KW` -- Use keyword name mangling over underscore prefixing for identifiers: `crate` → `krate`, `fn` → `func`, `struct` → `strukt`, `type` → `ty` +- Start with the narrowest relevant test: `cargo test -p ` or `cargo test -p `. +- After Rust changes, run the affected crate's tests and `cargo clippy -p --all-targets -- --cap-lints warn`; broaden validation when the change crosses crates. +- Use `cargo lint` to run Clippy on all workspace targets. +- Run `cargo xtask tidy` for repository-wide structural or generated-code changes. +- When updating snapshots with `UPDATE_EXPECT=1`, inspect the expectation diff rather than accepting it blindly. +- Use `RUN_SLOW_TESTS=1 cargo test` when the affected area has slow tests. From 79f049db67fe6e3757c3ef8ed05da2a3f36cd686 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sun, 19 Jul 2026 11:48:21 +0200 Subject: [PATCH 08/76] fix: Handle enum variants in next-solver `generics` --- src/tools/rust-analyzer/crates/hir-ty/src/lower.rs | 8 +++++--- .../crates/hir-ty/src/next_solver/def_id.rs | 11 +++++++++++ .../crates/hir-ty/src/next_solver/generics.rs | 8 +++++--- .../rust-analyzer/crates/hir-ty/src/tests/traits.rs | 12 ++++++------ 4 files changed, 27 insertions(+), 12 deletions(-) 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 e251fa84ed1a1..ccc3356686b89 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs @@ -1673,9 +1673,10 @@ fn type_for_struct_constructor<'db>( FieldsShape::Unit => Some(type_for_adt(db, def.into())), FieldsShape::Tuple => { let interner = DbInterner::new_no_crate(db); + let def = CallableDefId::StructId(def); Some(EarlyBinder::bind(Ty::new_fn_def( interner, - CallableDefId::StructId(def).into(), + def.into(), GenericArgs::identity_for_item(interner, def.into()), ))) } @@ -1693,10 +1694,11 @@ fn type_for_enum_variant_constructor<'db>( FieldsShape::Unit => Some(type_for_adt(db, def.loc(db).parent.into())), FieldsShape::Tuple => { let interner = DbInterner::new_no_crate(db); + let def = CallableDefId::EnumVariantId(def); Some(EarlyBinder::bind(Ty::new_fn_def( interner, - CallableDefId::EnumVariantId(def).into(), - GenericArgs::identity_for_item(interner, def.loc(db).parent.into()), + def.into(), + GenericArgs::identity_for_item(interner, def.into()), ))) } } 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 63337b297dc7a..ce66dbc77c7eb 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 @@ -165,6 +165,17 @@ impl From for SolverDefId { } } +impl From for SolverDefId { + #[inline] + fn from(value: CallableDefId) -> Self { + match value { + CallableDefId::FunctionId(id) => id.into(), + CallableDefId::StructId(id) => id.into(), + CallableDefId::EnumVariantId(id) => id.into(), + } + } +} + impl From for SolverDefId { #[inline] fn from(value: DefWithBodyId) -> Self { 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 49dbbcb06bcc8..9ae9a66674dca 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 @@ -7,9 +7,7 @@ use hir_def::{ use crate::db::HirDatabase; -use super::SolverDefId; - -use super::DbInterner; +use super::{Ctor, DbInterner, SolverDefId}; pub(crate) fn generics(interner: DbInterner<'_>, def: SolverDefId) -> Generics<'_> { let db = interner.db; @@ -24,6 +22,10 @@ pub(crate) fn generics(interner: DbInterner<'_>, def: SolverDefId) -> Generics<' (_, SolverDefId::BuiltinDeriveImplId(id)) => { return crate::builtin_derive::generics_of(interner, id); } + (_, SolverDefId::EnumVariantId(id) | SolverDefId::Ctor(Ctor::Enum(id))) => { + (id.loc(db).parent.into(), false) + } + (_, SolverDefId::Ctor(Ctor::Struct(id))) => (id.into(), false), (_, SolverDefId::AnonConstId(id)) => { let loc = id.loc(db); let generic_def = loc.owner.generic_def(db); 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 6e61fcaa5d70b..04cdedad9d757 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 @@ -2241,13 +2241,13 @@ fn tuple_struct_constructor_as_fn_trait() { check_types( r#" //- minicore: fn -struct S(u32, u64); +struct S(T, U); -fn takes_fn S>(f: F) -> S { f(1, 2) } +fn takes_fn S>(f: F) -> S { f(1, 2) } fn test() { takes_fn(S); - //^^^^^^^^^^^ S + //^^^^^^^^^^^ S } "#, ); @@ -2258,13 +2258,13 @@ fn enum_variant_constructor_as_fn_trait() { check_types( r#" //- minicore: fn -enum E { A(u32) } +enum E { A(T) } -fn takes_fn E>(f: F) -> E { f(1) } +fn takes_fn E>(f: F) -> E { f(1) } fn test() { takes_fn(E::A); - //^^^^^^^^^^^^^^ E + //^^^^^^^^^^^^^^ E } "#, ); From b5ec4b1973d561aeb8bef42427bd73801da75faf Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Mon, 8 Jun 2026 14:43:18 +0200 Subject: [PATCH 09/76] Unleash more lifetimes --- src/tools/rust-analyzer/Cargo.lock | 6 + src/tools/rust-analyzer/Cargo.toml | 1 + .../crates/base-db/src/editioned_file_id.rs | 57 +-- .../rust-analyzer/crates/base-db/src/lib.rs | 59 +-- .../hir-def/src/nameres/tests/incremental.rs | 48 +-- .../crates/hir-ty/src/autoderef.rs | 14 +- .../crates/hir-ty/src/consteval.rs | 83 ++-- .../crates/hir-ty/src/consteval/tests.rs | 8 +- .../rust-analyzer/crates/hir-ty/src/db.rs | 182 +++++---- .../crates/hir-ty/src/diagnostics/expr.rs | 18 +- .../hir-ty/src/diagnostics/match_check.rs | 4 +- .../hir-ty/src/diagnostics/unsafe_check.rs | 8 +- .../rust-analyzer/crates/hir-ty/src/infer.rs | 138 ++++--- .../crates/hir-ty/src/infer/callee.rs | 8 +- .../crates/hir-ty/src/infer/cast.rs | 16 +- .../crates/hir-ty/src/infer/closure.rs | 2 +- .../hir-ty/src/infer/closure/analysis.rs | 16 +- .../closure/analysis/expr_use_visitor.rs | 38 +- .../crates/hir-ty/src/infer/coerce.rs | 18 +- .../crates/hir-ty/src/infer/diagnostics.rs | 6 +- .../crates/hir-ty/src/infer/expr.rs | 4 +- .../crates/hir-ty/src/infer/fallback.rs | 2 +- .../crates/hir-ty/src/infer/mutability.rs | 2 +- .../crates/hir-ty/src/infer/op.rs | 2 +- .../crates/hir-ty/src/infer/opaques.rs | 4 +- .../crates/hir-ty/src/infer/pat.rs | 2 +- .../crates/hir-ty/src/infer/path.rs | 2 +- .../crates/hir-ty/src/infer/place_op.rs | 4 +- .../crates/hir-ty/src/infer/unify.rs | 6 +- .../rust-analyzer/crates/hir-ty/src/layout.rs | 12 +- .../rust-analyzer/crates/hir-ty/src/lib.rs | 47 ++- .../rust-analyzer/crates/hir-ty/src/lower.rs | 142 ++++--- .../crates/hir-ty/src/method_resolution.rs | 103 ++--- .../hir-ty/src/method_resolution/confirm.rs | 20 +- .../hir-ty/src/method_resolution/probe.rs | 2 +- .../rust-analyzer/crates/hir-ty/src/mir.rs | 18 +- .../crates/hir-ty/src/mir/borrowck.rs | 75 ++-- .../crates/hir-ty/src/mir/eval.rs | 192 ++++----- .../crates/hir-ty/src/mir/eval/shim.rs | 20 +- .../crates/hir-ty/src/mir/eval/shim/simd.rs | 4 +- .../crates/hir-ty/src/mir/eval/tests.rs | 4 +- .../crates/hir-ty/src/mir/lower.rs | 60 +-- .../crates/hir-ty/src/mir/monomorphization.rs | 48 +-- .../crates/hir-ty/src/mir/pretty.rs | 8 +- .../crates/hir-ty/src/next_solver.rs | 2 +- .../crates/hir-ty/src/next_solver/binder.rs | 5 +- .../crates/hir-ty/src/next_solver/def_id.rs | 386 ++++++++++++++---- .../crates/hir-ty/src/next_solver/fold.rs | 2 +- .../crates/hir-ty/src/next_solver/fulfill.rs | 2 +- .../hir-ty/src/next_solver/generic_arg.rs | 6 +- .../crates/hir-ty/src/next_solver/generics.rs | 2 +- .../hir-ty/src/next_solver/infer/context.rs | 2 +- .../hir-ty/src/next_solver/infer/mod.rs | 12 +- .../next_solver/infer/relate/generalize.rs | 2 +- .../src/next_solver/infer/relate/lattice.rs | 2 +- .../crates/hir-ty/src/next_solver/interner.rs | 50 +-- .../crates/hir-ty/src/next_solver/opaques.rs | 4 +- .../crates/hir-ty/src/next_solver/region.rs | 4 +- .../crates/hir-ty/src/next_solver/ty.rs | 12 +- .../crates/hir-ty/src/next_solver/util.rs | 4 +- .../crates/hir-ty/src/opaques.rs | 6 +- .../rust-analyzer/crates/hir-ty/src/tests.rs | 2 +- .../crates/hir-ty/src/tests/incremental.rs | 97 ++--- .../rust-analyzer/crates/hir-ty/src/traits.rs | 8 +- .../rust-analyzer/crates/hir-ty/src/utils.rs | 20 - src/tools/rust-analyzer/crates/hir/Cargo.toml | 1 + .../crates/hir/src/diagnostics.rs | 22 +- .../rust-analyzer/crates/hir/src/display.rs | 2 +- .../rust-analyzer/crates/hir/src/from_id.rs | 2 +- .../crates/hir/src/has_source.rs | 2 +- src/tools/rust-analyzer/crates/hir/src/lib.rs | 182 +++++---- .../rust-analyzer/crates/hir/src/semantics.rs | 106 ++--- .../crates/hir/src/semantics/source_to_def.rs | 6 +- .../crates/hir/src/source_analyzer.rs | 108 ++--- .../rust-analyzer/crates/hir/src/symbols.rs | 32 +- .../crates/hir/src/term_search/expr.rs | 2 +- .../crates/hir/src/term_search/tactics.rs | 18 +- .../src/handlers/convert_bool_to_enum.rs | 10 +- .../convert_tuple_struct_to_named_struct.rs | 2 +- .../src/handlers/expand_glob_import.rs | 33 +- .../src/handlers/extract_function.rs | 60 +-- .../src/handlers/extract_module.rs | 14 +- .../src/handlers/extract_variable.rs | 2 +- .../ide-assists/src/handlers/inline_call.rs | 6 +- .../src/handlers/remove_unused_imports.rs | 10 +- .../replace_named_generic_with_impl.rs | 6 +- .../src/handlers/unnecessary_async.rs | 6 +- .../crates/ide-completion/src/completions.rs | 12 +- .../ide-completion/src/completions/expr.rs | 6 +- .../ide-completion/src/completions/type.rs | 6 +- .../crates/ide-completion/src/context.rs | 14 +- .../crates/ide-completion/src/item.rs | 6 +- .../crates/ide-completion/src/render.rs | 47 ++- .../rust-analyzer/crates/ide-db/src/defs.rs | 119 +++--- .../crates/ide-db/src/famous_defs.rs | 2 +- .../crates/ide-db/src/helpers.rs | 12 +- .../ide-db/src/imports/import_assets.rs | 2 +- .../rust-analyzer/crates/ide-db/src/rename.rs | 20 +- .../rust-analyzer/crates/ide-db/src/search.rs | 17 +- .../crates/ide-db/src/symbol_index.rs | 34 +- .../ide-db/src/test_data/test_doc_alias.txt | 7 - .../test_symbol_index_collection.txt | 33 -- .../test_symbols_exclude_imports.txt | 1 - .../test_data/test_symbols_with_imports.txt | 2 - .../rust-analyzer/crates/ide-db/src/traits.rs | 14 +- .../src/handlers/mutability_errors.rs | 7 +- .../src/handlers/unused_variables.rs | 2 +- .../crates/ide-ssr/src/resolving.rs | 12 +- .../crates/ide-ssr/src/search.rs | 24 +- .../rust-analyzer/crates/ide/src/doc_links.rs | 42 +- .../crates/ide/src/doc_links/tests.rs | 4 +- .../crates/ide/src/goto_definition.rs | 4 +- .../crates/ide/src/goto_type_definition.rs | 2 +- .../crates/ide/src/highlight_related.rs | 5 +- .../rust-analyzer/crates/ide/src/hover.rs | 10 +- .../crates/ide/src/hover/render.rs | 12 +- .../rust-analyzer/crates/ide/src/interpret.rs | 2 +- .../rust-analyzer/crates/ide/src/moniker.rs | 10 +- .../crates/ide/src/navigation_target.rs | 6 +- .../crates/ide/src/references.rs | 14 +- .../rust-analyzer/crates/ide/src/rename.rs | 21 +- .../rust-analyzer/crates/ide/src/runnables.rs | 2 +- .../crates/ide/src/static_index.rs | 12 +- .../ide/src/syntax_highlighting/highlight.rs | 4 +- .../ide/src/syntax_highlighting/inject.rs | 2 +- 125 files changed, 1862 insertions(+), 1464 deletions(-) diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock index b2dc4ceeddca6..aa3fe4b1000ec 100644 --- a/src/tools/rust-analyzer/Cargo.lock +++ b/src/tools/rust-analyzer/Cargo.lock @@ -825,6 +825,7 @@ dependencies = [ "la-arena 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "ra-ap-rustc_type_ir", "rustc-hash 2.1.2", + "salsa", "serde_json", "smallvec", "span", @@ -2484,6 +2485,7 @@ dependencies = [ "smallvec", "thin-vec", "tracing", + "triomphe", "typeid", ] @@ -3089,6 +3091,10 @@ name = "triomphe" version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd69c5aa8f924c7519d6372789a74eac5b94fb0f8fcf0d4a97eb0bfc3e785f39" +dependencies = [ + "serde", + "stable_deref_trait", +] [[package]] name = "tt" diff --git a/src/tools/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/Cargo.toml index 96ddbbb5cad9c..2a219c3ea485c 100644 --- a/src/tools/rust-analyzer/Cargo.toml +++ b/src/tools/rust-analyzer/Cargo.toml @@ -131,6 +131,7 @@ salsa = { version = "0.27.0", default-features = false, features = [ "salsa_unstable", "macros", "inventory", + "triomphe" ] } salsa-macros = "0.27.0" semver = "1.0.26" diff --git a/src/tools/rust-analyzer/crates/base-db/src/editioned_file_id.rs b/src/tools/rust-analyzer/crates/base-db/src/editioned_file_id.rs index a77b45f8ae68a..f674c5df956d5 100644 --- a/src/tools/rust-analyzer/crates/base-db/src/editioned_file_id.rs +++ b/src/tools/rust-analyzer/crates/base-db/src/editioned_file_id.rs @@ -16,57 +16,24 @@ pub struct EditionedFileId { field: span::EditionedFileId, } -// Currently does not work due to a salsa bug -// #[salsa::tracked] -// impl EditionedFileId { -// #[salsa::tracked(lru = 128)] -// pub fn parse(self, db: &dyn SourceDatabase) -> syntax::Parse { -// let _p = tracing::info_span!("parse", ?self).entered(); -// let (file_id, edition) = self.unpack(db); -// let text = db.file_text(file_id).text(db); -// ast::SourceFile::parse(text, edition) -// } - -// // firewall query -// #[salsa::tracked(returns(as_deref))] -// pub fn parse_errors(self, db: &dyn SourceDatabase) -> Option> { -// let errors = self.parse(db).errors(); -// match &*errors { -// [] => None, -// [..] => Some(errors.into()), -// } -// } -// } - +#[salsa::tracked] impl EditionedFileId { + #[salsa::tracked(lru = 128)] pub fn parse(self, db: &dyn SourceDatabase) -> syntax::Parse { - #[salsa::tracked(lru = 128)] - pub fn parse( - db: &dyn SourceDatabase, - file_id: EditionedFileId, - ) -> syntax::Parse { - let _p = tracing::info_span!("parse", ?file_id).entered(); - let (file_id, edition) = file_id.unpack(db); - let text = db.file_text(file_id).text(db); - ast::SourceFile::parse(text, edition) - } - parse(db, self) + let _p = tracing::info_span!("parse", ?self).entered(); + let (file_id, edition) = self.unpack(db); + let text = db.file_text(file_id).text(db); + ast::SourceFile::parse(text, edition) } // firewall query - pub fn parse_errors(self, db: &dyn SourceDatabase) -> Option<&[SyntaxError]> { - #[salsa::tracked(returns(as_deref))] - pub fn parse_errors( - db: &dyn SourceDatabase, - file_id: EditionedFileId, - ) -> Option> { - let errors = file_id.parse(db).errors(); - match &*errors { - [] => None, - [..] => Some(errors.into()), - } + #[salsa::tracked(returns(as_deref))] + pub fn parse_errors(self, db: &dyn SourceDatabase) -> Option> { + let errors = self.parse(db).errors(); + match &*errors { + [] => None, + [..] => Some(errors.into()), } - parse_errors(db, self) } } diff --git a/src/tools/rust-analyzer/crates/base-db/src/lib.rs b/src/tools/rust-analyzer/crates/base-db/src/lib.rs index 94d9d08e50ff4..b3c7f8424965e 100644 --- a/src/tools/rust-analyzer/crates/base-db/src/lib.rs +++ b/src/tools/rust-analyzer/crates/base-db/src/lib.rs @@ -1,15 +1,48 @@ //! base_db defines basic database traits. The concrete DB is defined by ide. +// FIXME: Rename this crate, base db is non descriptive #![cfg_attr(feature = "in-rust-tree", feature(rustc_private))] #[cfg(feature = "in-rust-tree")] extern crate rustc_driver as _; -pub use salsa; +pub mod salsa { + pub use salsa::*; + + // Adjusted from `salsa::update_fallback` to work with database owned T + /// "Fallback" for maybe-update that is suitable for database owned T + /// that implement `Eq`. In this version, we update only if the new value + /// is not `Eq` to the old one. Note that given `Eq` impls that are not just + /// structurally comparing fields, this may cause us not to update even if + /// the value has changed (presumably because this change is not semantically + /// significant). + /// + /// # Safety + /// + /// See `Update::maybe_update`, additionally, `'db` is required to be `'static` or the lifetime + /// of the database `T` belongs to. + pub unsafe fn update_fallback_db<'db, T>(old_pointer: *mut T, new_value: T) -> bool + where + T: 'db + PartialEq, + { + // SAFETY: Because everything is owned, this ref is simply a valid `&mut` + let old_ref: &mut T = unsafe { &mut *old_pointer }; + + if *old_ref != new_value { + *old_ref = new_value; + true + } else { + // Subtle but important: Eq impls can be buggy or define equality + // in surprising ways. If it says that the value has not changed, + // we do not modify the existing value, and thus do not have to + // update the revision, as downstream code will not see the new value. + false + } + } +} pub use salsa_macros; use span::TextSize; -// FIXME: Rename this crate, base db is non descriptive mod change; mod editioned_file_id; mod input; @@ -65,28 +98,6 @@ macro_rules! impl_intern_key { }; } -/// # SAFETY -/// -/// `old_pointer` must be valid for unique writes -pub unsafe fn unsafe_update_eq(old_pointer: *mut T, new_value: T) -> bool -where - T: PartialEq, -{ - // SAFETY: Caller obligation - let old_ref: &mut T = unsafe { &mut *old_pointer }; - - if *old_ref != new_value { - *old_ref = new_value; - true - } else { - // Subtle but important: Eq impls can be buggy or define equality - // in surprising ways. If it says that the value has not changed, - // we do not modify the existing value, and thus do not have to - // update the revision, as downstream code will not see the new value. - false - } -} - pub const DEFAULT_FILE_TEXT_LRU_CAP: u16 = 16; pub const DEFAULT_PARSE_LRU_CAP: u16 = 128; pub const DEFAULT_BORROWCK_LRU_CAP: u16 = 2024; diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs index 49d94b969d06f..5cd70955ab3e6 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs @@ -167,22 +167,22 @@ fn no() {} "crate_local_def_map", "file_item_tree_query", "HirFileId::ast_id_map_", - "parse", + "EditionedFileId::parse_", "real_span_map", "file_item_tree_query", "HirFileId::ast_id_map_", - "parse", + "EditionedFileId::parse_", "real_span_map", "file_item_tree_query", "HirFileId::ast_id_map_", - "parse", + "EditionedFileId::parse_", "real_span_map", "EnumVariants::of_", ] "#]], expect![[r#" [ - "parse", + "EditionedFileId::parse_", "HirFileId::ast_id_map_", "file_item_tree_query", "real_span_map", @@ -225,16 +225,16 @@ pub struct S {} "crate_local_def_map", "file_item_tree_query", "HirFileId::ast_id_map_", - "parse", + "EditionedFileId::parse_", "real_span_map", "AstId < ast :: Macro >::decl_macro_expander_", "file_item_tree_query", "HirFileId::ast_id_map_", - "parse", + "EditionedFileId::parse_", "real_span_map", "file_item_tree_query", "HirFileId::ast_id_map_", - "parse", + "EditionedFileId::parse_", "real_span_map", "MacroId::definition_", "file_item_tree_query", @@ -245,7 +245,7 @@ pub struct S {} "#]], expect![[r#" [ - "parse", + "EditionedFileId::parse_", "HirFileId::ast_id_map_", "file_item_tree_query", "real_span_map", @@ -283,21 +283,21 @@ fn f() { foo } "crate_local_def_map", "file_item_tree_query", "HirFileId::ast_id_map_", - "parse", + "EditionedFileId::parse_", "real_span_map", "crate_local_def_map", "ProcMacros::get_for_crate_", "file_item_tree_query", "HirFileId::ast_id_map_", - "parse", + "EditionedFileId::parse_", "real_span_map", "file_item_tree_query", "HirFileId::ast_id_map_", - "parse", + "EditionedFileId::parse_", "real_span_map", "file_item_tree_query", "HirFileId::ast_id_map_", - "parse", + "EditionedFileId::parse_", "real_span_map", "MacroId::definition_", "file_item_tree_query", @@ -310,7 +310,7 @@ fn f() { foo } "#]], expect![[r#" [ - "parse", + "EditionedFileId::parse_", "HirFileId::ast_id_map_", "file_item_tree_query", "real_span_map", @@ -407,22 +407,22 @@ pub struct S {} "crate_local_def_map", "file_item_tree_query", "HirFileId::ast_id_map_", - "parse", + "EditionedFileId::parse_", "real_span_map", "crate_local_def_map", "ProcMacros::get_for_crate_", "file_item_tree_query", "HirFileId::ast_id_map_", - "parse", + "EditionedFileId::parse_", "real_span_map", "AstId < ast :: Macro >::decl_macro_expander_", "file_item_tree_query", "HirFileId::ast_id_map_", - "parse", + "EditionedFileId::parse_", "real_span_map", "file_item_tree_query", "HirFileId::ast_id_map_", - "parse", + "EditionedFileId::parse_", "real_span_map", "MacroId::definition_", "file_item_tree_query", @@ -446,7 +446,7 @@ pub struct S {} "#]], expect![[r#" [ - "parse", + "EditionedFileId::parse_", "HirFileId::ast_id_map_", "file_item_tree_query", "real_span_map", @@ -524,16 +524,16 @@ m!(Z); "crate_local_def_map", "file_item_tree_query", "HirFileId::ast_id_map_", - "parse", + "EditionedFileId::parse_", "real_span_map", "AstId < ast :: Macro >::decl_macro_expander_", "file_item_tree_query", "HirFileId::ast_id_map_", - "parse", + "EditionedFileId::parse_", "real_span_map", "file_item_tree_query", "HirFileId::ast_id_map_", - "parse", + "EditionedFileId::parse_", "real_span_map", "MacroId::definition_", "file_item_tree_query", @@ -571,7 +571,7 @@ m!(Z); &[("file_item_tree_query", 1), ("parse_macro_expansion", 0)], expect![[r#" [ - "parse", + "EditionedFileId::parse_", "HirFileId::ast_id_map_", "file_item_tree_query", "real_span_map", @@ -611,7 +611,7 @@ pub type Ty = (); [ "file_item_tree_query", "HirFileId::ast_id_map_", - "parse", + "EditionedFileId::parse_", "real_span_map", ] "#]], @@ -629,7 +629,7 @@ pub type Ty = (); &[("file_item_tree_query", 1), ("parse", 1)], expect![[r#" [ - "parse", + "EditionedFileId::parse_", "HirFileId::ast_id_map_", "file_item_tree_query", "real_span_map", diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs b/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs index c9d3a87e96501..4fab468dfd8e7 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs @@ -130,8 +130,8 @@ impl<'db> AutoderefCtx<'db> for DefaultAutoderefCtx<'_, 'db> { } } -pub(crate) struct InferenceContextAutoderefCtx<'a, 'b, 'db>(&'a mut InferenceContext<'b, 'db>); -impl<'db> AutoderefCtx<'db> for InferenceContextAutoderefCtx<'_, '_, 'db> { +pub(crate) struct InferenceContextAutoderefCtx<'a, 'db>(&'a mut InferenceContext<'db>); +impl<'db> AutoderefCtx<'db> for InferenceContextAutoderefCtx<'_, 'db> { #[inline] fn infcx(&self) -> &InferCtxt<'db> { &self.0.table.infer_ctxt @@ -162,8 +162,8 @@ pub(crate) struct GeneralAutoderef<'db, Ctx, Steps = Vec<(Ty<'db>, AutoderefKind pub(crate) type Autoderef<'a, 'db, Steps = Vec<(Ty<'db>, AutoderefKind)>> = GeneralAutoderef<'db, DefaultAutoderefCtx<'a, 'db>, Steps>; -pub(crate) type InferenceContextAutoderef<'a, 'b, 'db, Steps = Vec<(Ty<'db>, AutoderefKind)>> = - GeneralAutoderef<'db, InferenceContextAutoderefCtx<'a, 'b, 'db>, Steps>; +pub(crate) type InferenceContextAutoderef<'a, 'db, Steps = Vec<(Ty<'db>, AutoderefKind)>> = + GeneralAutoderef<'db, InferenceContextAutoderefCtx<'a, 'db>, Steps>; impl<'db, Ctx, Steps> Iterator for GeneralAutoderef<'db, Ctx, Steps> where @@ -240,10 +240,10 @@ impl<'a, 'db> Autoderef<'a, 'db> { } } -impl<'a, 'b, 'db> InferenceContextAutoderef<'a, 'b, 'db> { +impl<'a, 'db> InferenceContextAutoderef<'a, 'db> { #[inline] pub(crate) fn new_from_inference_context( - ctx: &'a mut InferenceContext<'b, 'db>, + ctx: &'a mut InferenceContext<'db>, base_ty: Ty<'db>, span: Span, ) -> Self { @@ -251,7 +251,7 @@ impl<'a, 'b, 'db> InferenceContextAutoderef<'a, 'b, 'db> { } #[inline] - pub(crate) fn ctx(&mut self) -> &mut InferenceContext<'b, 'db> { + pub(crate) fn ctx(&mut self) -> &mut InferenceContext<'db> { self.ctx.0 } } 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 e58a22332cf81..15dd530312067 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs @@ -16,6 +16,7 @@ use rustc_abi::Size; use rustc_apfloat::Float; use rustc_ast_ir::Mutability; use rustc_type_ir::inherent::{Const as _, GenericArgs as _, IntoKind, Ty as _}; +use salsa::Update; use stdx::never; use crate::{ @@ -35,13 +36,13 @@ use crate::{ use super::mir::interpret_mir; -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum ConstEvalError { - MirLowerError(MirLowerError), - MirEvalError(MirEvalError), +#[derive(Debug, Clone, PartialEq, Eq, Update)] +pub enum ConstEvalError<'db> { + MirLowerError(MirLowerError<'db>), + MirEvalError(MirEvalError<'db>), } -impl ConstEvalError { +impl ConstEvalError<'_> { pub fn pretty_print( &self, f: &mut String, @@ -60,8 +61,8 @@ impl ConstEvalError { } } -impl From for ConstEvalError { - fn from(value: MirLowerError) -> Self { +impl<'db> From> for ConstEvalError<'db> { + fn from(value: MirLowerError<'db>) -> Self { match value { MirLowerError::ConstEvalError(_, e) => *e, _ => ConstEvalError::MirLowerError(value), @@ -69,8 +70,8 @@ impl From for ConstEvalError { } } -impl From for ConstEvalError { - fn from(value: MirEvalError) -> Self { +impl<'db> From> for ConstEvalError<'db> { + fn from(value: MirEvalError<'db>) -> Self { ConstEvalError::MirEvalError(value) } } @@ -414,10 +415,10 @@ pub(crate) fn create_anon_const<'a, 'db>( } #[salsa::tracked(cycle_result = const_eval_discriminant_cycle_result)] -pub(crate) fn const_eval_discriminant_variant( - db: &dyn HirDatabase, +pub(crate) fn const_eval_discriminant_variant<'db>( + db: &'db dyn HirDatabase, variant_id: EnumVariantId, -) -> Result { +) -> Result> { let interner = DbInterner::new_no_crate(db); let def = variant_id.into(); let body = Body::of(db, def); @@ -450,11 +451,11 @@ pub(crate) fn const_eval_discriminant_variant( Ok(c) } -fn const_eval_discriminant_cycle_result( - _: &dyn HirDatabase, +fn const_eval_discriminant_cycle_result<'db>( + _: &'db dyn HirDatabase, _: salsa::Id, _: EnumVariantId, -) -> Result { +) -> Result> { Err(ConstEvalError::MirLowerError(MirLowerError::Loop)) } @@ -463,58 +464,58 @@ pub(crate) fn const_eval<'db>( def: ConstId, subst: GenericArgs<'db>, trait_env: Option>, -) -> Result, ConstEvalError> { +) -> Result, ConstEvalError<'db>> { return match const_eval_query(db, def, subst.store(), trait_env.map(|env| env.store())) { Ok(konst) => Ok(konst.as_ref()), Err(err) => Err(err.clone()), }; #[salsa::tracked(returns(ref), cycle_result = const_eval_cycle_result)] - pub(crate) fn const_eval_query( - db: &dyn HirDatabase, + pub(crate) fn const_eval_query<'db>( + db: &'db dyn HirDatabase, def: ConstId, subst: StoredGenericArgs, trait_env: Option, - ) -> Result { + ) -> Result> { let body = db.monomorphized_mir_body( def.into(), subst, ParamEnvAndCrate { param_env: db.trait_environment(def.into()), krate: def.krate(db) } .store(), )?; - let c = interpret_mir(db, body, false, trait_env.as_ref().map(|env| env.as_ref()))?.0?; + let c = interpret_mir(db, body, false, trait_env.as_ref().map(|env| env.as_ref(db)))?.0?; Ok(c.store()) } - pub(crate) fn const_eval_cycle_result( - _: &dyn HirDatabase, + pub(crate) fn const_eval_cycle_result<'db>( + _: &'db dyn HirDatabase, _: salsa::Id, _: ConstId, _: StoredGenericArgs, _: Option, - ) -> Result { + ) -> Result> { Err(ConstEvalError::MirLowerError(MirLowerError::Loop)) } } pub(crate) fn anon_const_eval<'db>( db: &'db dyn HirDatabase, - def: AnonConstId, + def: AnonConstId<'db>, subst: GenericArgs<'db>, trait_env: Option>, -) -> Result, ConstEvalError> { +) -> Result, ConstEvalError<'db>> { return match anon_const_eval_query(db, def, subst.store(), trait_env.map(|env| env.store())) { Ok(konst) => Ok(konst.as_ref()), Err(err) => Err(err.clone()), }; #[salsa::tracked(returns(ref), cycle_result = anon_const_eval_cycle_result)] - pub(crate) fn anon_const_eval_query( - db: &dyn HirDatabase, - def: AnonConstId, + pub(crate) fn anon_const_eval_query<'db>( + db: &'db dyn HirDatabase, + def: AnonConstId<'db>, subst: StoredGenericArgs, trait_env: Option, - ) -> Result { + ) -> Result> { let body = db.monomorphized_mir_body( def.into(), subst, @@ -524,17 +525,17 @@ pub(crate) fn anon_const_eval<'db>( } .store(), )?; - let c = interpret_mir(db, body, false, trait_env.as_ref().map(|env| env.as_ref()))?.0?; + let c = interpret_mir(db, body, false, trait_env.as_ref().map(|env| env.as_ref(db)))?.0?; Ok(c.store()) } - pub(crate) fn anon_const_eval_cycle_result( - _: &dyn HirDatabase, + pub(crate) fn anon_const_eval_cycle_result<'db>( + _: &'db dyn HirDatabase, _: salsa::Id, - _: AnonConstId, + _: AnonConstId<'db>, _: StoredGenericArgs, _: Option, - ) -> Result { + ) -> Result> { Err(ConstEvalError::MirLowerError(MirLowerError::Loop)) } } @@ -542,17 +543,17 @@ pub(crate) fn anon_const_eval<'db>( pub(crate) fn const_eval_static<'db>( db: &'db dyn HirDatabase, def: StaticId, -) -> Result, ConstEvalError> { +) -> Result, ConstEvalError<'db>> { return match const_eval_static_query(db, def) { Ok(konst) => Ok(konst.as_ref()), Err(err) => Err(err.clone()), }; #[salsa::tracked(returns(ref), cycle_result = const_eval_static_cycle_result)] - pub(crate) fn const_eval_static_query( - db: &dyn HirDatabase, + pub(crate) fn const_eval_static_query<'db>( + db: &'db dyn HirDatabase, def: StaticId, - ) -> Result { + ) -> Result> { let interner = DbInterner::new_no_crate(db); let body = db.monomorphized_mir_body( def.into(), @@ -564,11 +565,11 @@ pub(crate) fn const_eval_static<'db>( Ok(c.store()) } - pub(crate) fn const_eval_static_cycle_result( - _: &dyn HirDatabase, + pub(crate) fn const_eval_static_cycle_result<'db>( + _: &'db dyn HirDatabase, _: salsa::Id, _: StaticId, - ) -> Result { + ) -> Result> { Err(ConstEvalError::MirLowerError(MirLowerError::Loop)) } } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs index 546238f9bb309..95ebdbd4091e8 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs @@ -26,7 +26,7 @@ use super::{ mod intrinsics; -fn simplify(e: ConstEvalError) -> ConstEvalError { +fn simplify(e: ConstEvalError<'_>) -> ConstEvalError<'_> { match e { ConstEvalError::MirEvalError(MirEvalError::InFunction(e, _)) => { simplify(ConstEvalError::MirEvalError(*e)) @@ -38,7 +38,7 @@ fn simplify(e: ConstEvalError) -> ConstEvalError { #[track_caller] fn check_fail( #[rust_analyzer::rust_fixture] ra_fixture: &str, - error: impl FnOnce(ConstEvalError) -> bool, + error: impl FnOnce(ConstEvalError<'_>) -> bool, ) { let (db, file_id) = TestDB::with_single_file(ra_fixture); crate::attach_db(&db, || match eval_goal(&db, file_id) { @@ -101,7 +101,7 @@ fn check_answer( }); } -fn pretty_print_err(e: ConstEvalError, db: &TestDB) -> String { +fn pretty_print_err(e: ConstEvalError<'_>, db: &TestDB) -> String { let mut err = String::new(); let span_formatter = |file, range| format!("{file:?} {range:?}"); let display_target = @@ -118,7 +118,7 @@ fn pretty_print_err(e: ConstEvalError, db: &TestDB) -> String { err } -fn eval_goal(db: &TestDB, file_id: EditionedFileId) -> Result, ConstEvalError> { +fn eval_goal(db: &TestDB, file_id: EditionedFileId) -> Result, ConstEvalError<'_>> { let _tracing = setup_tracing(); let interner = DbInterner::new_no_crate(db); let module_id = db.module_for_file(file_id.file_id(db)); 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 c74ac51b61028..73b1183cb2209 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs @@ -16,8 +16,8 @@ use hir_def::{ signatures::{ConstSignature, StaticSignature}, }; use la_arena::ArenaMap; +use salsa::Update; use span::Edition; -use stdx::impl_from; use triomphe::Arc; use crate::{ @@ -43,32 +43,38 @@ pub trait HirDatabase: SourceDatabase + std::fmt::Debug { // FIXME: Collapse `mir_body_for_closure` into `mir_body` // and `monomorphized_mir_body_for_closure` into `monomorphized_mir_body` #[salsa::transparent] - fn mir_body(&self, def: InferBodyId) -> Result<&MirBody, MirLowerError> { + fn mir_body<'db>( + &'db self, + def: InferBodyId<'db>, + ) -> Result<&'db MirBody<'db>, MirLowerError<'db>> { crate::mir::mir_body_query(self, def).map_err(|err| err.clone()) } #[salsa::transparent] - fn mir_body_for_closure(&self, def: InternedClosureId) -> Result<&MirBody, MirLowerError> { + fn mir_body_for_closure<'db>( + &'db self, + def: InternedClosureId<'db>, + ) -> Result<&'db MirBody<'db>, MirLowerError<'db>> { crate::mir::mir_body_for_closure_query(self, def).map_err(|err| err.clone()) } #[salsa::transparent] - fn monomorphized_mir_body( - &self, - def: InferBodyId, + fn monomorphized_mir_body<'db>( + &'db self, + def: InferBodyId<'db>, subst: StoredGenericArgs, env: StoredParamEnvAndCrate, - ) -> Result<&MirBody, MirLowerError> { + ) -> Result<&'db MirBody<'db>, MirLowerError<'db>> { crate::mir::monomorphized_mir_body_query(self, def, subst, env).map_err(|err| err.clone()) } #[salsa::transparent] - fn monomorphized_mir_body_for_closure( - &self, - def: InternedClosureId, + fn monomorphized_mir_body_for_closure<'db>( + &'db self, + def: InternedClosureId<'db>, subst: StoredGenericArgs, env: StoredParamEnvAndCrate, - ) -> Result<&MirBody, MirLowerError> { + ) -> Result<&'db MirBody<'db>, MirLowerError<'db>> { crate::mir::monomorphized_mir_body_for_closure_query(self, def, subst, env) .map_err(|err| err.clone()) } @@ -80,24 +86,30 @@ pub trait HirDatabase: SourceDatabase + std::fmt::Debug { def: ConstId, subst: GenericArgs<'db>, trait_env: Option>, - ) -> Result, ConstEvalError>; + ) -> Result, ConstEvalError<'db>>; #[salsa::invoke(crate::consteval::anon_const_eval)] #[salsa::transparent] fn anon_const_eval<'db>( &'db self, - def: AnonConstId, + def: AnonConstId<'db>, subst: GenericArgs<'db>, trait_env: Option>, - ) -> Result, ConstEvalError>; + ) -> Result, ConstEvalError<'db>>; #[salsa::invoke(crate::consteval::const_eval_static)] #[salsa::transparent] - fn const_eval_static<'db>(&'db self, def: StaticId) -> Result, ConstEvalError>; + fn const_eval_static<'db>( + &'db self, + def: StaticId, + ) -> Result, ConstEvalError<'db>>; #[salsa::invoke(crate::consteval::const_eval_discriminant_variant)] #[salsa::transparent] - fn const_eval_discriminant(&self, def: EnumVariantId) -> Result; + fn const_eval_discriminant<'db>( + &'db self, + def: EnumVariantId, + ) -> Result>; #[salsa::invoke(crate::method_resolution::lookup_impl_method_query)] #[salsa::transparent] @@ -141,10 +153,10 @@ pub trait HirDatabase: SourceDatabase + std::fmt::Debug { #[salsa::invoke(crate::lower::type_for_type_alias_with_diagnostics)] #[salsa::transparent] - fn type_for_type_alias_with_diagnostics( - &self, + fn type_for_type_alias_with_diagnostics<'db>( + &'db self, def: TypeAliasId, - ) -> &TyLoweringResult>; + ) -> &'db TyLoweringResult<'db, StoredEarlyBinder>; /// Returns the type of the value of the given constant, or `None` if the `ValueTyDefId` is /// a `StructId` or `EnumVariantId` with a record constructor. @@ -158,10 +170,10 @@ pub trait HirDatabase: SourceDatabase + std::fmt::Debug { #[salsa::invoke(crate::lower::type_for_const_with_diagnostics)] #[salsa::transparent] - fn type_for_const_with_diagnostics( - &self, + fn type_for_const_with_diagnostics<'db>( + &'db self, def: ConstId, - ) -> &TyLoweringResult>; + ) -> &'db TyLoweringResult<'db, StoredEarlyBinder>; #[salsa::invoke(crate::lower::type_for_static)] #[salsa::transparent] @@ -169,17 +181,17 @@ pub trait HirDatabase: SourceDatabase + std::fmt::Debug { #[salsa::invoke(crate::lower::type_for_static_with_diagnostics)] #[salsa::transparent] - fn type_for_static_with_diagnostics( - &self, + fn type_for_static_with_diagnostics<'db>( + &'db self, def: StaticId, - ) -> &TyLoweringResult>; + ) -> &'db TyLoweringResult<'db, StoredEarlyBinder>; #[salsa::invoke(crate::lower::impl_self_ty_with_diagnostics)] #[salsa::transparent] - fn impl_self_ty_with_diagnostics( - &self, + fn impl_self_ty_with_diagnostics<'db>( + &'db self, def: ImplId, - ) -> &TyLoweringResult>; + ) -> &'db TyLoweringResult<'db, StoredEarlyBinder>; #[salsa::invoke(crate::lower::impl_self_ty_query)] #[salsa::transparent] @@ -187,10 +199,10 @@ pub trait HirDatabase: SourceDatabase + std::fmt::Debug { #[salsa::invoke(crate::lower::const_param_types_with_diagnostics)] #[salsa::transparent] - fn const_param_types_with_diagnostics( - &self, + fn const_param_types_with_diagnostics<'db>( + &'db self, def: GenericDefId, - ) -> &TyLoweringResult>; + ) -> &'db TyLoweringResult<'db, ArenaMap>; #[salsa::invoke(crate::lower::const_param_types)] #[salsa::transparent] @@ -202,10 +214,10 @@ pub trait HirDatabase: SourceDatabase + std::fmt::Debug { #[salsa::invoke(crate::lower::impl_trait_with_diagnostics)] #[salsa::transparent] - fn impl_trait_with_diagnostics( - &self, + fn impl_trait_with_diagnostics<'db>( + &'db self, def: ImplId, - ) -> &Option>>; + ) -> &'db Option>>; #[salsa::invoke(crate::lower::impl_trait_query)] #[salsa::transparent] @@ -213,10 +225,10 @@ pub trait HirDatabase: SourceDatabase + std::fmt::Debug { #[salsa::invoke(crate::lower::field_types_with_diagnostics)] #[salsa::transparent] - fn field_types_with_diagnostics( - &self, + fn field_types_with_diagnostics<'db>( + &'db self, var: VariantId, - ) -> &TyLoweringResult>; + ) -> &'db TyLoweringResult<'db, ArenaMap>; #[salsa::invoke(crate::lower::field_types_query)] #[salsa::transparent] @@ -231,10 +243,10 @@ pub trait HirDatabase: SourceDatabase + std::fmt::Debug { #[salsa::invoke(crate::lower::callable_item_signature_with_diagnostics)] #[salsa::transparent] - fn callable_item_signature_with_diagnostics( - &self, + fn callable_item_signature_with_diagnostics<'db>( + &'db self, def: CallableDefId, - ) -> &TyLoweringResult>; + ) -> &'db TyLoweringResult<'db, StoredEarlyBinder>; #[salsa::invoke(crate::lower::trait_environment)] #[salsa::transparent] @@ -242,10 +254,10 @@ pub trait HirDatabase: SourceDatabase + std::fmt::Debug { #[salsa::invoke(crate::lower::generic_defaults_with_diagnostics)] #[salsa::transparent] - fn generic_defaults_with_diagnostics( - &self, + fn generic_defaults_with_diagnostics<'db>( + &'db self, def: GenericDefId, - ) -> &TyLoweringResult; + ) -> &'db TyLoweringResult<'db, GenericDefaults>; /// This returns an empty list if no parameter has default. /// @@ -256,10 +268,10 @@ pub trait HirDatabase: SourceDatabase + std::fmt::Debug { #[salsa::invoke(crate::lower::type_alias_bounds_with_diagnostics)] #[salsa::transparent] - fn type_alias_bounds_with_diagnostics( - &self, + fn type_alias_bounds_with_diagnostics<'db>( + &'db self, type_alias: TypeAliasId, - ) -> &TyLoweringResult>>; + ) -> &'db TyLoweringResult<'db, TypeAliasBounds>>; #[salsa::invoke(crate::lower::type_alias_bounds)] #[salsa::transparent] @@ -291,22 +303,22 @@ pub struct InternedOpaqueTyId { pub loc: ImplTraitId, } -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct InternedClosure { - pub owner: InferBodyId, +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Update)] +pub struct InternedClosure<'db> { + pub owner: InferBodyId<'db>, pub expr: ExprId, pub kind: ClosureKind, } -#[salsa_macros::interned(constructor = new_impl, no_lifetime, debug, revisions = usize::MAX)] +#[salsa_macros::interned(constructor = new_impl, debug, revisions = usize::MAX)] #[derive(PartialOrd, Ord)] -pub struct InternedClosureId { - pub loc: InternedClosure, +pub struct InternedClosureId<'db> { + pub loc: InternedClosure<'db>, } -impl InternedClosureId { +impl<'db> InternedClosureId<'db> { #[inline] - pub fn new(db: &dyn HirDatabase, loc: InternedClosure) -> Self { + pub fn new(db: &'db dyn HirDatabase, loc: InternedClosure<'db>) -> Self { if cfg!(debug_assertions) { let store = ExpressionStore::of(db, loc.owner.expression_store_owner(db)); let expr = &store[loc.expr]; @@ -326,15 +338,15 @@ impl InternedClosureId { } } -#[salsa_macros::interned(constructor = new_impl, no_lifetime, debug, revisions = usize::MAX)] +#[salsa_macros::interned(constructor = new_impl, debug, revisions = usize::MAX)] #[derive(PartialOrd, Ord)] -pub struct InternedCoroutineId { - pub loc: InternedClosure, +pub struct InternedCoroutineId<'db> { + pub loc: InternedClosure<'db>, } -impl InternedCoroutineId { +impl<'db> InternedCoroutineId<'db> { #[inline] - pub fn new(db: &dyn HirDatabase, loc: InternedClosure) -> Self { + pub fn new(db: &'db dyn HirDatabase, loc: InternedClosure<'db>) -> Self { if cfg!(debug_assertions) { let store = ExpressionStore::of(db, loc.owner.expression_store_owner(db)); let expr = &store[loc.expr]; @@ -355,15 +367,15 @@ impl InternedCoroutineId { } } -#[salsa_macros::interned(constructor = new_impl, no_lifetime, debug, revisions = usize::MAX)] +#[salsa_macros::interned(constructor = new_impl, debug, revisions = usize::MAX)] #[derive(PartialOrd, Ord)] -pub struct InternedCoroutineClosureId { - pub loc: InternedClosure, +pub struct InternedCoroutineClosureId<'db> { + pub loc: InternedClosure<'db>, } -impl InternedCoroutineClosureId { +impl<'db> InternedCoroutineClosureId<'db> { #[inline] - pub fn new(db: &dyn HirDatabase, loc: InternedClosure) -> Self { + pub fn new(db: &'db dyn HirDatabase, loc: InternedClosure<'db>) -> Self { if cfg!(debug_assertions) { let store = ExpressionStore::of(db, loc.owner.expression_store_owner(db)); let expr = &store[loc.expr]; @@ -399,16 +411,16 @@ pub struct AnonConstLoc { pub(crate) allow_using_generic_params: bool, } -#[salsa_macros::interned(debug, no_lifetime, revisions = usize::MAX, constructor = new_)] +#[salsa_macros::interned(debug, revisions = usize::MAX, constructor = new_)] #[derive(PartialOrd, Ord)] pub struct AnonConstId { #[returns(ref)] pub loc: AnonConstLoc, } -impl AnonConstId { +impl<'db> AnonConstId<'db> { pub(crate) fn new( - db: &dyn SourceDatabase, + db: &'db dyn SourceDatabase, loc: AnonConstLoc, token: TrackedStructToken, ) -> Self { @@ -417,23 +429,23 @@ impl AnonConstId { } } -impl HasModule for AnonConstId { +impl HasModule for AnonConstId<'_> { fn module(&self, db: &dyn SourceDatabase) -> ModuleId { self.loc(db).owner.module(db) } } -impl HasResolver for AnonConstId { +impl HasResolver for AnonConstId<'_> { fn resolver(self, db: &dyn SourceDatabase) -> Resolver<'_> { self.loc(db).owner.resolver(db) } } -impl AnonConstId { +impl<'db> AnonConstId<'db> { pub fn all_from_signature( - db: &dyn HirDatabase, + db: &'db dyn HirDatabase, def: GenericDefId, - ) -> ArrayVec<&[AnonConstId], 5> { + ) -> ArrayVec<&'db [Self], 5> { let mut result = ArrayVec::new(); // Queries common to all generic defs: @@ -470,16 +482,30 @@ impl AnonConstId { /// A constant, which might appears as a const item, an anonymous const block in expressions /// or patterns, or as a constant in types with const generics. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, salsa_macros::Supertype)] -pub enum GeneralConstId { +pub enum GeneralConstId<'db> { ConstId(ConstId), StaticId(StaticId), - AnonConstId(AnonConstId), + AnonConstId(AnonConstId<'db>), } -impl_from!(ConstId, StaticId, AnonConstId for GeneralConstId); +impl<'db> From for GeneralConstId<'db> { + fn from(it: ConstId) -> GeneralConstId<'db> { + GeneralConstId::ConstId(it) + } +} +impl<'db> From for GeneralConstId<'db> { + fn from(it: StaticId) -> GeneralConstId<'db> { + GeneralConstId::StaticId(it) + } +} +impl<'db> From> for GeneralConstId<'db> { + fn from(it: AnonConstId<'db>) -> GeneralConstId<'db> { + GeneralConstId::AnonConstId(it) + } +} -impl GeneralConstId { - pub fn generic_def(self, db: &dyn HirDatabase) -> Option { +impl<'db> GeneralConstId<'db> { + pub fn generic_def(self, db: &'db dyn HirDatabase) -> Option { match self { GeneralConstId::ConstId(it) => Some(it.into()), GeneralConstId::StaticId(it) => Some(it.into()), @@ -487,7 +513,7 @@ impl GeneralConstId { } } - pub fn name(self, db: &dyn SourceDatabase) -> String { + pub fn name(self, db: &'db dyn SourceDatabase) -> String { match self { GeneralConstId::StaticId(it) => { StaticSignature::of(db, it).name.display(db, Edition::CURRENT).to_string() 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 d04419c5e58b8..fd8d7e02a512e 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 @@ -104,7 +104,7 @@ impl<'db> BodyValidationDiagnostic<'db> { struct ExprValidator<'db> { owner: DefWithBodyId, body: &'db Body, - infer: &'db InferenceResult, + infer: &'db InferenceResult<'db>, env: ParamEnv<'db>, diagnostics: Vec>, validate_lints: bool, @@ -633,9 +633,9 @@ impl<'db> FilterMapNextChecker<'db> { } } -pub fn record_literal_missing_fields( - db: &dyn HirDatabase, - infer: &InferenceResult, +pub fn record_literal_missing_fields<'db>( + db: &'db dyn HirDatabase, + infer: &InferenceResult<'db>, id: ExprId, expr: &Expr, ) -> Option<(VariantId, Vec)> { @@ -676,9 +676,9 @@ pub fn record_literal_missing_fields( Some((variant_def, missed_fields)) } -pub fn record_pattern_missing_fields( - db: &dyn HirDatabase, - infer: &InferenceResult, +pub fn record_pattern_missing_fields<'db>( + db: &'db dyn HirDatabase, + infer: &InferenceResult<'db>, id: PatId, pat: &Pat, ) -> Option<(VariantId, Vec)> { @@ -713,8 +713,8 @@ pub fn record_pattern_missing_fields( Some((variant_def, missed_fields)) } -fn types_of_subpatterns_do_match(pat: PatId, body: &Body, infer: &InferenceResult) -> bool { - fn walk(pat: PatId, body: &Body, infer: &InferenceResult, has_type_mismatches: &mut bool) { +fn types_of_subpatterns_do_match(pat: PatId, body: &Body, infer: &InferenceResult<'_>) -> bool { + fn walk(pat: PatId, body: &Body, infer: &InferenceResult<'_>, has_type_mismatches: &mut bool) { match infer.pat_has_type_mismatch(pat) { true => *has_type_mismatches = true, false if *has_type_mismatches => (), 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 14bff65220702..613912e0901bf 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 @@ -97,7 +97,7 @@ pub(crate) enum PatKind<'db> { pub(crate) struct PatCtxt<'a, 'db> { db: &'db dyn HirDatabase, - infer: &'db InferenceResult, + infer: &'db InferenceResult<'db>, body: &'a Body, pub(crate) errors: Vec, } @@ -105,7 +105,7 @@ pub(crate) struct PatCtxt<'a, 'db> { impl<'a, 'db> PatCtxt<'a, 'db> { pub(crate) fn new( db: &'db dyn HirDatabase, - infer: &'db InferenceResult, + infer: &'db InferenceResult<'db>, body: &'a Body, ) -> Self { Self { db, infer, body, errors: Vec::new() } 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 88a44d2e6a2f8..3021de68f3fdf 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 @@ -100,7 +100,7 @@ enum UnsafeDiagnostic { pub fn unsafe_operations_for_body( db: &dyn HirDatabase, - infer: &InferenceResult, + infer: &InferenceResult<'_>, def: DefWithBodyId, body: &Body, callback: &mut dyn FnMut(ExprOrPatId), @@ -119,7 +119,7 @@ pub fn unsafe_operations_for_body( pub fn unsafe_operations( db: &dyn HirDatabase, - infer: &InferenceResult, + infer: &InferenceResult<'_>, def: ExpressionStoreOwnerId, body: &ExpressionStore, current: ExprId, @@ -137,7 +137,7 @@ pub fn unsafe_operations( struct UnsafeVisitor<'db> { db: &'db dyn HirDatabase, - infer: &'db InferenceResult, + infer: &'db InferenceResult<'db>, body: &'db ExpressionStore, resolver: Resolver<'db>, def: ExpressionStoreOwnerId, @@ -156,7 +156,7 @@ struct UnsafeVisitor<'db> { impl<'db> UnsafeVisitor<'db> { fn new( db: &'db dyn HirDatabase, - infer: &'db InferenceResult, + infer: &'db InferenceResult<'db>, body: &'db ExpressionStore, def: ExpressionStoreOwnerId, unsafe_expr_cb: &'db mut dyn FnMut(UnsafeDiagnostic), 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 64d0e2a86406d..6b551775d5b69 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs @@ -65,6 +65,7 @@ use rustc_type_ir::{ AliasTyKind, TypeFoldable, TypeVisitableExt, inherent::{GenericArgs as _, IntoKind, Ty as _}, }; +use salsa::Update; use smallvec::SmallVec; use span::Edition; use stdx::never; @@ -118,7 +119,7 @@ pub use unify::{could_unify, could_unify_deeply}; use cast::{CastCheck, CastError}; /// The entry point of type inference. -fn infer_query(db: &dyn HirDatabase, def: DefWithBodyId) -> InferenceResult { +fn infer_query<'db>(db: &'db dyn HirDatabase, def: DefWithBodyId) -> InferenceResult<'db> { infer_query_with_inspect(db, def, None, LoweringMode::Analysis) } @@ -127,7 +128,7 @@ pub fn infer_query_with_inspect<'db>( def: DefWithBodyId, inspect: Option>, lowering_mode: LoweringMode, -) -> InferenceResult { +) -> InferenceResult<'db> { let _p = tracing::info_span!("infer_query").entered(); let resolver = def.resolver(db); let body = Body::of(db, def); @@ -185,7 +186,11 @@ pub fn infer_query_with_inspect<'db>( infer_finalize(ctx) } -fn infer_cycle_result(db: &dyn HirDatabase, _: salsa::Id, _: DefWithBodyId) -> InferenceResult { +fn infer_cycle_result<'db>( + db: &'db dyn HirDatabase, + _: salsa::Id, + _: DefWithBodyId, +) -> InferenceResult<'db> { InferenceResult { has_errors: true, ..InferenceResult::new(Ty::new_error(DbInterner::new_no_crate(db), ErrorGuaranteed)) @@ -193,7 +198,10 @@ fn infer_cycle_result(db: &dyn HirDatabase, _: salsa::Id, _: DefWithBodyId) -> I } /// Infer types for an anonymous const expression. -fn infer_anon_const_query(db: &dyn HirDatabase, def: AnonConstId) -> InferenceResult { +fn infer_anon_const_query<'db>( + db: &'db dyn HirDatabase, + def: AnonConstId<'db>, +) -> InferenceResult<'db> { let _p = tracing::info_span!("infer_anon_const_query").entered(); let loc = def.loc(db); let store_owner = loc.owner; @@ -221,18 +229,18 @@ fn infer_anon_const_query(db: &dyn HirDatabase, def: AnonConstId) -> InferenceRe infer_finalize(ctx) } -fn infer_anon_const_cycle_result( - db: &dyn HirDatabase, +fn infer_anon_const_cycle_result<'db>( + db: &'db dyn HirDatabase, _: salsa::Id, - _: AnonConstId, -) -> InferenceResult { + _: AnonConstId<'db>, +) -> InferenceResult<'db> { InferenceResult { has_errors: true, ..InferenceResult::new(Ty::new_error(DbInterner::new_no_crate(db), ErrorGuaranteed)) } } -fn infer_finalize(mut ctx: InferenceContext<'_, '_>) -> InferenceResult { +fn infer_finalize<'db>(mut ctx: InferenceContext<'db>) -> InferenceResult<'db> { ctx.handle_opaque_type_uses(); ctx.type_inference_fallback(); @@ -736,8 +744,8 @@ pub enum PatAdjust { /// When you add a field that stores types (including `Substitution` and the like), don't forget /// `resolve_completely()`'ing them in `InferenceContext::resolve_all()`. Inference variables must /// not appear in the final inference result. -#[derive(Clone, PartialEq, Eq, Debug)] -pub struct InferenceResult { +#[derive(Clone, PartialEq, Eq, Debug, Update)] +pub struct InferenceResult<'db> { /// For each method call expr, records the function it resolves to. method_resolutions: FxHashMap, /// For each field access expr, records the field it resolves to. @@ -801,7 +809,7 @@ pub struct InferenceResult { pub closures_data: FxHashMap, - defined_anon_consts: ThinVec, + defined_anon_consts: ThinVec>, } #[derive(Clone, PartialEq, Eq, Debug, Default)] @@ -1022,24 +1030,32 @@ pub enum UpvarCapture { } #[salsa::tracked] -impl InferenceResult { +impl<'db> InferenceResult<'db> { #[salsa::tracked(returns(ref), cycle_result = infer_cycle_result)] - fn for_body(db: &dyn HirDatabase, def: DefWithBodyId) -> InferenceResult { + fn for_body(db: &dyn HirDatabase, def: DefWithBodyId) -> InferenceResult<'_> { infer_query(db, def) } +} +#[salsa::tracked] +impl<'db> InferenceResult<'db> { /// Infer types for all const expressions in an item's signature. /// /// Returns an `InferenceResult` containing type information for array lengths, /// const generic arguments, and other const expressions appearing in type /// positions within the item's signature. #[salsa::tracked(returns(ref), cycle_result = infer_anon_const_cycle_result)] - fn for_anon_const(db: &dyn HirDatabase, def: AnonConstId) -> InferenceResult { + fn for_anon_const(db: &'db dyn HirDatabase, def: AnonConstId<'db>) -> InferenceResult<'db> { infer_anon_const_query(db, def) } +} +impl<'db> InferenceResult<'db> { #[inline] - pub fn of(db: &dyn HirDatabase, def: impl Into) -> &InferenceResult { + pub fn of( + db: &'db dyn HirDatabase, + def: impl Into>, + ) -> &'db InferenceResult<'db> { match def.into() { InferBodyId::DefWithBodyId(it) => InferenceResult::for_body(db, it), InferBodyId::AnonConstId(it) => InferenceResult::for_anon_const(db, it), @@ -1047,7 +1063,7 @@ impl InferenceResult { } } -impl InferenceResult { +impl<'db> InferenceResult<'db> { fn new(error_ty: Ty<'_>) -> Self { Self { method_resolutions: Default::default(), @@ -1074,7 +1090,7 @@ impl InferenceResult { } } - pub fn method_resolution<'db>(&self, expr: ExprId) -> Option<(FunctionId, GenericArgs<'db>)> { + pub fn method_resolution(&self, expr: ExprId) -> Option<(FunctionId, GenericArgs<'db>)> { self.method_resolutions.get(&expr).map(|(func, args)| (*func, args.as_ref())) } pub fn field_resolution(&self, expr: ExprId) -> Option> { @@ -1092,22 +1108,22 @@ impl InferenceResult { ExprOrPatId::PatId(id) => self.variant_resolution_for_pat(id), } } - pub fn assoc_resolutions_for_expr<'db>( + pub fn assoc_resolutions_for_expr<'a>( &self, id: ExprId, - ) -> Option<(CandidateId, GenericArgs<'db>)> { + ) -> Option<(CandidateId, GenericArgs<'a>)> { self.assoc_resolutions.get(&id.into()).map(|(assoc, args)| (*assoc, args.as_ref())) } - pub fn assoc_resolutions_for_pat<'db>( + pub fn assoc_resolutions_for_pat<'a>( &self, id: PatId, - ) -> Option<(CandidateId, GenericArgs<'db>)> { + ) -> Option<(CandidateId, GenericArgs<'a>)> { self.assoc_resolutions.get(&id.into()).map(|(assoc, args)| (*assoc, args.as_ref())) } - pub fn assoc_resolutions_for_expr_or_pat<'db>( + pub fn assoc_resolutions_for_expr_or_pat<'a>( &self, id: ExprOrPatId, - ) -> Option<(CandidateId, GenericArgs<'db>)> { + ) -> Option<(CandidateId, GenericArgs<'a>)> { match id { ExprOrPatId::ExprId(id) => self.assoc_resolutions_for_expr(id), ExprOrPatId::PatId(id) => self.assoc_resolutions_for_pat(id), @@ -1130,19 +1146,19 @@ impl InferenceResult { pub fn has_type_mismatches(&self) -> bool { self.nodes_with_type_mismatches.is_some() } - pub fn placeholder_types<'db>(&self) -> impl Iterator)> { + pub fn placeholder_types<'a>(&self) -> impl Iterator)> { self.type_of_type_placeholder.iter().map(|(&type_ref, ty)| (type_ref, ty.as_ref())) } - pub fn type_of_type_placeholder<'db>(&self, type_ref: TypeRefId) -> Option> { + pub fn type_of_type_placeholder<'a>(&self, type_ref: TypeRefId) -> Option> { self.type_of_type_placeholder.get(&type_ref).map(|ty| ty.as_ref()) } - pub fn type_of_expr_or_pat<'db>(&self, id: ExprOrPatId) -> Option> { + pub fn type_of_expr_or_pat<'a>(&self, id: ExprOrPatId) -> Option> { match id { ExprOrPatId::ExprId(id) => self.type_of_expr.get(id).map(|it| it.as_ref()), ExprOrPatId::PatId(id) => self.type_of_pat.get(id).map(|it| it.as_ref()), } } - pub fn type_of_expr_with_adjust<'db>(&self, id: ExprId) -> Option> { + pub fn type_of_expr_with_adjust<'a>(&self, id: ExprId) -> Option> { match self.expr_adjustments.get(&id).and_then(|adjustments| { adjustments.iter().rfind(|adj| { // https://github.com/rust-lang/rust/blob/67819923ac8ea353aaa775303f4c3aacbf41d010/compiler/rustc_mir_build/src/thir/cx/expr.rs#L140 @@ -1159,7 +1175,7 @@ impl InferenceResult { None => self.type_of_expr.get(id).map(|it| it.as_ref()), } } - pub fn type_of_pat_with_adjust<'db>(&self, id: PatId) -> Ty<'db> { + pub fn type_of_pat_with_adjust<'a>(&self, id: PatId) -> Ty<'a> { match self.pat_adjustments.get(&id).and_then(|adjustments| adjustments.last()) { Some(adjusted) => adjusted.source.as_ref(), None => self.pat_ty(id), @@ -1173,7 +1189,7 @@ impl InferenceResult { &self.diagnostics } - pub fn tuple_field_access_type<'db>(&self, id: TupleId) -> Tys<'db> { + pub fn tuple_field_access_type<'a>(&self, id: TupleId) -> Tys<'a> { self.tuple_field_access_types[id.0 as usize].as_ref() } @@ -1190,25 +1206,25 @@ impl InferenceResult { } // This method is consumed by external tools to run rust-analyzer as a library. Don't remove, please. - pub fn expression_types<'db>(&self) -> impl Iterator)> { + pub fn expression_types<'a>(&self) -> impl Iterator)> { self.type_of_expr.iter().map(|(k, v)| (k, v.as_ref())) } // This method is consumed by external tools to run rust-analyzer as a library. Don't remove, please. - pub fn pattern_types<'db>(&self) -> impl Iterator)> { + pub fn pattern_types<'a>(&self) -> impl Iterator)> { self.type_of_pat.iter().map(|(k, v)| (k, v.as_ref())) } // This method is consumed by external tools to run rust-analyzer as a library. Don't remove, please. - pub fn binding_types<'db>(&self) -> impl Iterator)> { + pub fn binding_types<'a>(&self) -> impl Iterator)> { self.type_of_binding.iter().map(|(k, v)| (k, v.as_ref())) } // This method is consumed by external tools to run rust-analyzer as a library. Don't remove, please. - pub fn return_position_impl_trait_types<'db>( - &'db self, - db: &'db dyn HirDatabase, - ) -> impl Iterator)> { + pub fn return_position_impl_trait_types<'a>( + &'a self, + db: &'a dyn HirDatabase, + ) -> impl Iterator)> { self.type_of_opaque.iter().filter_map(move |(&id, ty)| { let ImplTraitId::ReturnTypeImplTrait(_, rpit_idx) = id.loc(db) else { return None; @@ -1217,24 +1233,24 @@ impl InferenceResult { }) } - pub fn expr_ty<'db>(&self, id: ExprId) -> Ty<'db> { + pub fn expr_ty<'a>(&self, id: ExprId) -> Ty<'a> { self.type_of_expr.get(id).map_or(self.error_ty.as_ref(), |it| it.as_ref()) } - pub fn pat_ty<'db>(&self, id: PatId) -> Ty<'db> { + pub fn pat_ty<'a>(&self, id: PatId) -> Ty<'a> { self.type_of_pat.get(id).map_or(self.error_ty.as_ref(), |it| it.as_ref()) } - pub fn expr_or_pat_ty<'db>(&self, id: ExprOrPatId) -> Ty<'db> { + pub fn expr_or_pat_ty<'a>(&self, id: ExprOrPatId) -> Ty<'a> { self.type_of_expr_or_pat(id).unwrap_or(self.error_ty.as_ref()) } - pub fn binding_ty<'db>(&self, id: BindingId) -> Ty<'db> { + pub fn binding_ty<'a>(&self, id: BindingId) -> Ty<'a> { self.type_of_binding.get(id).map_or(self.error_ty.as_ref(), |it| it.as_ref()) } /// This does not deduplicate, which means you'll get the types once per capture. - pub fn closure_captures_tys<'db>(&self, closure: ExprId) -> impl Iterator> { + pub fn closure_captures_tys<'a>(&self, closure: ExprId) -> impl Iterator> { self.closures_data[&closure] .min_captures .values() @@ -1242,11 +1258,11 @@ impl InferenceResult { } /// Like [`Self::closure_captures_tys()`], but using [`CapturedPlace::captured_ty()`]. - pub fn closure_captures_captured_tys<'db>( + pub fn closure_captures_captured_tys<'a>( &self, - db: &'db dyn HirDatabase, + db: &'a dyn HirDatabase, closure: ExprId, - ) -> impl Iterator> { + ) -> impl Iterator> { self.closures_data[&closure] .min_captures .values() @@ -1266,12 +1282,12 @@ enum DerefPatBorrowMode { /// The inference context contains all information needed during type inference. #[derive(Debug)] -pub(crate) struct InferenceContext<'body, 'db> { +pub(crate) struct InferenceContext<'db> { pub(crate) db: &'db dyn HirDatabase, - pub(crate) owner: InferBodyId, + pub(crate) owner: InferBodyId<'db>, pub(crate) store_owner: ExpressionStoreOwnerId, pub(crate) generic_def: GenericDefId, - pub(crate) store: &'body ExpressionStore, + pub(crate) store: &'db ExpressionStore, pub(crate) lowering_mode: LoweringMode, /// Generally you should not resolve things via this resolver. Instead create a TyLoweringContext /// and resolve the path via its methods. This will ensure proper error reporting. @@ -1286,7 +1302,7 @@ pub(crate) struct InferenceContext<'body, 'db> { pub(crate) features: &'db UnstableFeatures, /// The traits in scope, disregarding block modules. This is used for caching purposes. traits_in_scope: FxHashSet, - pub(crate) result: InferenceResult, + pub(crate) result: InferenceResult<'db>, tuple_field_accesses_rev: IndexSet, std::hash::BuildHasherDefault>, /// The return type of the function being inferred, the closure or async block if we're @@ -1316,7 +1332,7 @@ pub(crate) struct InferenceContext<'body, 'db> { diagnostics: Diagnostics, vars_emitted_type_must_be_known_for: FxHashSet>, - defined_anon_consts: RefCell>, + defined_anon_consts: RefCell>>, } #[derive(Clone, Debug)] @@ -1363,13 +1379,13 @@ fn find_continuable<'a, 'db>( } } -impl<'body, 'db> InferenceContext<'body, 'db> { +impl<'db> InferenceContext<'db> { fn new( db: &'db dyn HirDatabase, - owner: InferBodyId, + owner: InferBodyId<'db>, store_owner: ExpressionStoreOwnerId, generic_def: GenericDefId, - store: &'body ExpressionStore, + store: &'db ExpressionStore, resolver: Resolver<'db>, allow_using_generic_params: bool, lowering_mode: LoweringMode, @@ -1411,7 +1427,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> { } } - fn merge(&mut self, other: &InferenceResult) { + fn merge(&mut self, other: &InferenceResult<'db>) { let InferenceResult { method_resolutions, field_resolutions, @@ -1566,7 +1582,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> { // `InferenceResult` in the middle of inference. See the fixme comment in `consteval::eval_to_const`. If you // used this function for another workaround, mention it here. If you really need this function and believe that // there is no problem in it being `pub(crate)`, remove this comment. - fn resolve_all(self) -> InferenceResult { + fn resolve_all(self) -> InferenceResult<'db> { let InferenceContext { table, mut result, @@ -1699,7 +1715,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> { result } - fn collect_const(&mut self, id: ConstId, data: &ConstSignature) { + fn collect_const(&mut self, id: ConstId, data: &'db ConstSignature) { let return_ty = self.make_ty( data.type_ref, &data.store, @@ -1711,7 +1727,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> { self.return_ty = return_ty; } - fn collect_static(&mut self, id: StaticId, data: &StaticSignature) { + fn collect_static(&mut self, id: StaticId, data: &'db StaticSignature) { let return_ty = self.make_ty( data.type_ref, &data.store, @@ -1920,7 +1936,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> { fn with_ty_lowering( &mut self, - store: &ExpressionStore, + store: &'db ExpressionStore, types_source: InferenceTyDiagnosticSource, store_owner: ExpressionStoreOwnerId, lifetime_elision: LifetimeElisionKind<'db>, @@ -1967,7 +1983,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> { fn make_ty( &mut self, type_ref: TypeRefId, - store: &ExpressionStore, + store: &'db ExpressionStore, type_source: InferenceTyDiagnosticSource, store_owner: ExpressionStoreOwnerId, lifetime_elision: LifetimeElisionKind<'db>, @@ -2555,7 +2571,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> { }; fn forbid_unresolved_segments<'db>( - ctx: &InferenceContext<'_, 'db>, + ctx: &InferenceContext<'db>, result: (Ty<'db>, Option), unresolved: Option, ) -> (Ty<'db>, Option) { @@ -2725,7 +2741,7 @@ impl<'db> Expectation<'db> { /// which still is useful, because it informs integer literals and the like. /// See the test case `test/ui/coerce-expect-unsized.rs` and #20169 /// for examples of where this comes up,. - fn rvalue_hint(ctx: &mut InferenceContext<'_, 'db>, ty: Ty<'db>) -> Self { + fn rvalue_hint(ctx: &mut InferenceContext<'db>, ty: Ty<'db>) -> Self { match ctx.struct_tail_without_normalization(ty).kind() { TyKind::Slice(_) | TyKind::Str | TyKind::Dynamic(..) => { Expectation::RValueLikeUnsized(ty) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/callee.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/callee.rs index e5304582ca412..7331f7a8a4d27 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/callee.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/callee.rs @@ -33,7 +33,7 @@ enum CallStep<'db> { Overloaded(MethodCallee<'db>), } -impl<'db> InferenceContext<'_, 'db> { +impl<'db> InferenceContext<'db> { pub(crate) fn infer_call( &mut self, call_expr: ExprId, @@ -106,7 +106,7 @@ impl<'db> InferenceContext<'_, 'db> { call_expr: ExprId, callee_expr: ExprId, arg_exprs: &[ExprId], - autoderef: &mut InferenceContextAutoderef<'_, '_, 'db>, + autoderef: &mut InferenceContextAutoderef<'_, 'db>, error_reported: &mut bool, ) -> Option> { let final_ty = autoderef.final_ty(); @@ -540,8 +540,8 @@ pub(crate) struct DeferredCallResolution<'db> { fn_sig: FnSig<'db>, } -impl<'a, 'db> DeferredCallResolution<'db> { - pub(crate) fn resolve(self, ctx: &mut InferenceContext<'a, 'db>) { +impl<'db> DeferredCallResolution<'db> { + pub(crate) fn resolve(self, ctx: &mut InferenceContext<'db>) { debug!("DeferredCallResolution::resolve() {:?}", self); // we should not be invoked until the closure kind has been 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 da996ccbea86a..dc08139081947 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 @@ -123,7 +123,7 @@ impl<'db> CastCheck<'db> { pub(super) fn check( &mut self, - ctx: &mut InferenceContext<'_, 'db>, + ctx: &mut InferenceContext<'db>, ) -> Result<(), InferenceDiagnostic> { self.expr_ty = ctx.table.try_structurally_resolve_type(self.source_expr.into(), self.expr_ty); @@ -159,7 +159,7 @@ impl<'db> CastCheck<'db> { self.do_check(ctx).map_err(|e| e.into_diagnostic(self.expr, self.expr_ty, self.cast_ty)) } - fn do_check(&self, ctx: &mut InferenceContext<'_, 'db>) -> Result<(), CastError> { + fn do_check(&self, ctx: &mut InferenceContext<'db>) -> Result<(), CastError> { let (t_from, t_cast) = match (CastTy::from_ty(ctx.db, self.expr_ty), CastTy::from_ty(ctx.db, self.cast_ty)) { (Some(t_from), Some(t_cast)) => (t_from, t_cast), @@ -258,7 +258,7 @@ impl<'db> CastCheck<'db> { fn check_ref_cast( &self, - ctx: &mut InferenceContext<'_, 'db>, + ctx: &mut InferenceContext<'db>, t_expr: Ty<'db>, m_expr: Mutability, t_cast: Ty<'db>, @@ -304,7 +304,7 @@ impl<'db> CastCheck<'db> { fn check_ptr_ptr_cast( &self, - ctx: &mut InferenceContext<'_, 'db>, + ctx: &mut InferenceContext<'db>, src: Ty<'db>, dst: Ty<'db>, ) -> Result<(), CastError> { @@ -456,7 +456,7 @@ impl<'db> CastCheck<'db> { fn check_ptr_addr_cast( &self, - ctx: &mut InferenceContext<'_, 'db>, + ctx: &mut InferenceContext<'db>, expr_ty: Ty<'db>, ) -> Result<(), CastError> { match pointer_kind(self.expr, expr_ty, ctx).map_err(|_| CastError::Unknown)? { @@ -470,7 +470,7 @@ impl<'db> CastCheck<'db> { fn check_addr_ptr_cast( &self, - ctx: &mut InferenceContext<'_, 'db>, + ctx: &mut InferenceContext<'db>, cast_ty: Ty<'db>, ) -> Result<(), CastError> { match pointer_kind(self.expr, cast_ty, ctx).map_err(|_| CastError::Unknown)? { @@ -486,7 +486,7 @@ impl<'db> CastCheck<'db> { fn check_fptr_ptr_cast( &self, - ctx: &mut InferenceContext<'_, 'db>, + ctx: &mut InferenceContext<'db>, cast_ty: Ty<'db>, ) -> Result<(), CastError> { match pointer_kind(self.expr, cast_ty, ctx).map_err(|_| CastError::Unknown)? { @@ -520,7 +520,7 @@ enum PointerKind<'db> { fn pointer_kind<'db>( expr: ExprId, ty: Ty<'db>, - ctx: &mut InferenceContext<'_, 'db>, + ctx: &mut InferenceContext<'db>, ) -> Result>, ()> { let ty = ctx.table.try_structurally_resolve_type(expr.into(), ty); 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 2a5567dfae544..e2948a81ac7d9 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 @@ -47,7 +47,7 @@ struct ClosureSignatures<'db> { liberated_sig: FnSig<'db>, } -impl<'db> InferenceContext<'_, 'db> { +impl<'db> InferenceContext<'db> { fn poll_option_ty(&mut self, item_ty: Ty<'db>) -> Ty<'db> { let interner = self.interner(); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure/analysis.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure/analysis.rs index 5ea43bc03ca86..e6c449cfe315e 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure/analysis.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure/analysis.rs @@ -194,7 +194,7 @@ enum PlaceAncestryRelation { /// analysis pass. type InferredCaptureInformation = Vec<(Place, CaptureInfo)>; -impl<'a, 'db> InferenceContext<'a, 'db> { +impl<'db> InferenceContext<'db> { pub(crate) fn closure_analyze(&mut self) { let upvars = crate::upvars::upvars_mentioned(self.db, self.store_owner) .unwrap_or(const { &FxHashMap::with_hasher(FxBuildHasher) }); @@ -1202,7 +1202,7 @@ impl<'db> euv::Delegate<'db> for InferBorrowKind { &mut self, place_with_id: PlaceWithOrigin, cause: FakeReadCause, - ctx: &mut InferenceContext<'_, 'db>, + ctx: &mut InferenceContext<'db>, ) { let PlaceBase::Upvar { .. } = place_with_id.place.base else { return }; @@ -1222,7 +1222,7 @@ impl<'db> euv::Delegate<'db> for InferBorrowKind { } #[instrument(skip(self), level = "debug")] - fn consume(&mut self, place_with_id: PlaceWithOrigin, ctx: &mut InferenceContext<'_, 'db>) { + fn consume(&mut self, place_with_id: PlaceWithOrigin, ctx: &mut InferenceContext<'db>) { let PlaceBase::Upvar { closure: upvar_closure, .. } = place_with_id.place.base else { return; }; @@ -1237,7 +1237,7 @@ impl<'db> euv::Delegate<'db> for InferBorrowKind { } #[instrument(skip(self), level = "debug")] - fn use_cloned(&mut self, place_with_id: PlaceWithOrigin, ctx: &mut InferenceContext<'_, 'db>) { + fn use_cloned(&mut self, place_with_id: PlaceWithOrigin, ctx: &mut InferenceContext<'db>) { let PlaceBase::Upvar { closure: upvar_closure, .. } = place_with_id.place.base else { return; }; @@ -1256,7 +1256,7 @@ impl<'db> euv::Delegate<'db> for InferBorrowKind { &mut self, place_with_id: PlaceWithOrigin, bk: BorrowKind, - ctx: &mut InferenceContext<'_, 'db>, + ctx: &mut InferenceContext<'db>, ) { let PlaceBase::Upvar { closure: upvar_closure, .. } = place_with_id.place.base else { return; @@ -1284,15 +1284,15 @@ impl<'db> euv::Delegate<'db> for InferBorrowKind { } #[instrument(skip(self), level = "debug")] - fn mutate(&mut self, assignee_place: PlaceWithOrigin, ctx: &mut InferenceContext<'_, 'db>) { + fn mutate(&mut self, assignee_place: PlaceWithOrigin, ctx: &mut InferenceContext<'db>) { self.borrow(assignee_place, BorrowKind::Mutable, ctx); } } /// Rust doesn't permit moving fields out of a type that implements drop #[instrument(skip(fcx), ret, level = "debug")] -fn restrict_precision_for_drop_types<'a, 'db>( - fcx: &mut InferenceContext<'a, 'db>, +fn restrict_precision_for_drop_types<'db>( + fcx: &mut InferenceContext<'db>, mut place: Place, capture_info: &mut CaptureInfo, ) -> Place { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure/analysis/expr_use_visitor.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure/analysis/expr_use_visitor.rs index d8a8cceee6583..7f4b112b688ca 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure/analysis/expr_use_visitor.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure/analysis/expr_use_visitor.rs @@ -301,7 +301,7 @@ pub(crate) trait Delegate<'db> { /// diagnostics. Around pattern matching such as `let pat = expr`, the diagnostic /// id will be the id of the expression `expr` but the place itself will have /// the id of the binding in the pattern `pat`. - fn consume(&mut self, place_with_id: PlaceWithOrigin, ctx: &mut InferenceContext<'_, 'db>); + fn consume(&mut self, place_with_id: PlaceWithOrigin, ctx: &mut InferenceContext<'db>); /// The value found at `place` is used, depending /// on `mode`. Where `diag_expr_id` is the id used for diagnostics for `place`. @@ -316,7 +316,7 @@ pub(crate) trait Delegate<'db> { /// diagnostics. Around pattern matching such as `let pat = expr`, the diagnostic /// id will be the id of the expression `expr` but the place itself will have /// the id of the binding in the pattern `pat`. - fn use_cloned(&mut self, place_with_id: PlaceWithOrigin, ctx: &mut InferenceContext<'_, 'db>); + fn use_cloned(&mut self, place_with_id: PlaceWithOrigin, ctx: &mut InferenceContext<'db>); /// The value found at `place` is being borrowed with kind `bk`. /// `diag_expr_id` is the id used for diagnostics (see `consume` for more details). @@ -324,7 +324,7 @@ pub(crate) trait Delegate<'db> { &mut self, place_with_id: PlaceWithOrigin, bk: BorrowKind, - ctx: &mut InferenceContext<'_, 'db>, + ctx: &mut InferenceContext<'db>, ); /// The value found at `place` is being copied. @@ -333,7 +333,7 @@ pub(crate) trait Delegate<'db> { /// If an implementation is not provided, use of a `Copy` type in a ByValue context is instead /// considered a use by `ImmBorrow` and `borrow` is called instead. This is because a shared /// borrow is the "minimum access" that would be needed to perform a copy. - fn copy(&mut self, place_with_id: PlaceWithOrigin, ctx: &mut InferenceContext<'_, 'db>) { + fn copy(&mut self, place_with_id: PlaceWithOrigin, ctx: &mut InferenceContext<'db>) { // In most cases, copying data from `x` is equivalent to doing `*&x`, so by default // we treat a copy of `x` as a borrow of `x`. self.borrow(place_with_id, BorrowKind::Immutable, ctx) @@ -341,12 +341,12 @@ pub(crate) trait Delegate<'db> { /// The path at `assignee_place` is being assigned to. /// `diag_expr_id` is the id used for diagnostics (see `consume` for more details). - fn mutate(&mut self, assignee_place: PlaceWithOrigin, ctx: &mut InferenceContext<'_, 'db>); + fn mutate(&mut self, assignee_place: PlaceWithOrigin, ctx: &mut InferenceContext<'db>); /// The path at `binding_place` is a binding that is being initialized. /// /// This covers cases such as `let x = 42;` - fn bind(&mut self, binding_place: PlaceWithOrigin, ctx: &mut InferenceContext<'_, 'db>) { + fn bind(&mut self, binding_place: PlaceWithOrigin, ctx: &mut InferenceContext<'db>) { // Bindings can normally be treated as a regular assignment, so by default we // forward this to the mutate callback. self.mutate(binding_place, ctx) @@ -357,16 +357,16 @@ pub(crate) trait Delegate<'db> { &mut self, place_with_id: PlaceWithOrigin, cause: FakeReadCause, - ctx: &mut InferenceContext<'_, 'db>, + ctx: &mut InferenceContext<'db>, ); } impl<'db, D: Delegate<'db>> Delegate<'db> for &mut D { - fn consume(&mut self, place_with_id: PlaceWithOrigin, ctx: &mut InferenceContext<'_, 'db>) { + fn consume(&mut self, place_with_id: PlaceWithOrigin, ctx: &mut InferenceContext<'db>) { (**self).consume(place_with_id, ctx) } - fn use_cloned(&mut self, place_with_id: PlaceWithOrigin, ctx: &mut InferenceContext<'_, 'db>) { + fn use_cloned(&mut self, place_with_id: PlaceWithOrigin, ctx: &mut InferenceContext<'db>) { (**self).use_cloned(place_with_id, ctx) } @@ -374,20 +374,20 @@ impl<'db, D: Delegate<'db>> Delegate<'db> for &mut D { &mut self, place_with_id: PlaceWithOrigin, bk: BorrowKind, - ctx: &mut InferenceContext<'_, 'db>, + ctx: &mut InferenceContext<'db>, ) { (**self).borrow(place_with_id, bk, ctx) } - fn copy(&mut self, place_with_id: PlaceWithOrigin, ctx: &mut InferenceContext<'_, 'db>) { + fn copy(&mut self, place_with_id: PlaceWithOrigin, ctx: &mut InferenceContext<'db>) { (**self).copy(place_with_id, ctx) } - fn mutate(&mut self, assignee_place: PlaceWithOrigin, ctx: &mut InferenceContext<'_, 'db>) { + fn mutate(&mut self, assignee_place: PlaceWithOrigin, ctx: &mut InferenceContext<'db>) { (**self).mutate(assignee_place, ctx) } - fn bind(&mut self, binding_place: PlaceWithOrigin, ctx: &mut InferenceContext<'_, 'db>) { + fn bind(&mut self, binding_place: PlaceWithOrigin, ctx: &mut InferenceContext<'db>) { (**self).bind(binding_place, ctx) } @@ -395,7 +395,7 @@ impl<'db, D: Delegate<'db>> Delegate<'db> for &mut D { &mut self, place_with_id: PlaceWithOrigin, cause: FakeReadCause, - ctx: &mut InferenceContext<'_, 'db>, + ctx: &mut InferenceContext<'db>, ) { (**self).fake_read(place_with_id, cause, ctx) } @@ -404,21 +404,21 @@ impl<'db, D: Delegate<'db>> Delegate<'db> for &mut D { /// A visitor that reports how each expression is being used. /// /// See [module-level docs][self] and [`Delegate`] for details. -pub(crate) struct ExprUseVisitor<'a, 'b, 'db, D: Delegate<'db>> { - cx: &'a mut InferenceContext<'b, 'db>, +pub(crate) struct ExprUseVisitor<'a, 'db, D: Delegate<'db>> { + cx: &'a mut InferenceContext<'db>, delegate: D, closure_expr: ExprId, upvars: UpvarsRef<'db>, } -impl<'a, 'b, 'db, D: Delegate<'db>> ExprUseVisitor<'a, 'b, 'db, D> { +impl<'a, 'db, D: Delegate<'db>> ExprUseVisitor<'a, 'db, D> { /// Creates the ExprUseVisitor, configuring it with the various options provided: /// /// - `delegate` -- who receives the callbacks /// - `param_env` --- parameter environment for trait lookups (esp. pertaining to `Copy`) /// - `typeck_results` --- typeck results for the code being analyzed pub(crate) fn new( - cx: &'a mut InferenceContext<'b, 'db>, + cx: &'a mut InferenceContext<'db>, closure_expr: ExprId, upvars: UpvarsRef<'db>, delegate: D, @@ -1165,7 +1165,7 @@ impl_from!(PatId for CatPatternPat); /// example, auto-derefs are explicit. Also, an index `a[b]` is decomposed into /// two operations: a dereference to reach the array data and then an index to /// jump forward to the relevant item. -impl<'db, D: Delegate<'db>> ExprUseVisitor<'_, '_, 'db, D> { +impl<'db, D: Delegate<'db>> ExprUseVisitor<'_, 'db, D> { fn expect_and_resolve_type(&mut self, ty: Option>) -> Result> { match ty { Some(ty) => { 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 343919f5babbc..85d8142335dd3 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 @@ -793,7 +793,7 @@ where fn coerce_closure_to_fn( &mut self, a: Ty<'db>, - closure_def_id_a: InternedClosureId, + closure_def_id_a: InternedClosureId<'db>, args_a: GenericArgs<'db>, b: Ty<'db>, ) -> CoerceResult<'db> { @@ -856,9 +856,9 @@ where } } -struct InferenceCoercionDelegate<'a, 'b, 'db>(&'a mut InferenceContext<'b, 'db>); +struct InferenceCoercionDelegate<'a, 'db>(&'a mut InferenceContext<'db>); -impl<'db> CoerceDelegate<'db> for InferenceCoercionDelegate<'_, '_, 'db> { +impl<'db> CoerceDelegate<'db> for InferenceCoercionDelegate<'_, 'db> { #[inline] fn infcx(&self) -> &InferCtxt<'db> { &self.0.table.infer_ctxt @@ -884,7 +884,7 @@ impl<'db> CoerceDelegate<'db> for InferenceCoercionDelegate<'_, '_, 'db> { } } -impl<'db> InferenceContext<'_, 'db> { +impl<'db> InferenceContext<'db> { /// Attempt to coerce an expression to a type, and return the /// adjusted type of the expression, if successful. /// Adjustments are only recorded if the coercion succeeded. @@ -1242,7 +1242,7 @@ impl<'db, 'exprs> CoerceMany<'db, 'exprs> { /// if necessary. pub(crate) fn coerce( &mut self, - icx: &mut InferenceContext<'_, 'db>, + icx: &mut InferenceContext<'db>, cause: &ObligationCause, expression: ExprId, expression_ty: Ty<'db>, @@ -1265,7 +1265,7 @@ impl<'db, 'exprs> CoerceMany<'db, 'exprs> { /// removing a `;`). pub(crate) fn coerce_forced_unit( &mut self, - icx: &mut InferenceContext<'_, 'db>, + icx: &mut InferenceContext<'db>, expr: ExprId, cause: &ObligationCause, label_unit_as_expected: bool, @@ -1287,7 +1287,7 @@ impl<'db, 'exprs> CoerceMany<'db, 'exprs> { /// `Nil`. pub(crate) fn coerce_inner( &mut self, - icx: &mut InferenceContext<'_, 'db>, + icx: &mut InferenceContext<'db>, cause: &ObligationCause, expression: ExprId, mut expression_ty: Ty<'db>, @@ -1403,7 +1403,7 @@ impl<'db, 'exprs> CoerceMany<'db, 'exprs> { self.pushed += 1; } - pub(crate) fn complete(self, icx: &mut InferenceContext<'_, 'db>) -> Ty<'db> { + pub(crate) fn complete(self, icx: &mut InferenceContext<'db>) -> Ty<'db> { if let Some(final_ty) = self.final_ty { final_ty } else { @@ -1597,7 +1597,7 @@ fn coerce<'db>( Ok((adjustments, ty)) } -fn is_capturing_closure(db: &dyn HirDatabase, closure: InternedClosureId) -> bool { +fn is_capturing_closure(db: &dyn HirDatabase, closure: InternedClosureId<'_>) -> bool { let InternedClosure { owner, expr, .. } = closure.loc(db); upvars_mentioned(db, owner.expression_store_owner(db)) .is_some_and(|upvars| upvars.get(&expr).is_some_and(|upvars| !upvars.is_empty())) 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 e871edd265c16..676317ffba1f9 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 @@ -90,7 +90,7 @@ pub(super) struct InferenceTyLoweringContext<'db, 'a> { ctx: TyLoweringContext<'db, 'a>, diagnostics: &'a Diagnostics, source: InferenceTyDiagnosticSource, - defined_anon_consts: &'a RefCell>, + defined_anon_consts: &'a RefCell>>, } impl<'db, 'a> InferenceTyLoweringContext<'db, 'a> { @@ -98,7 +98,7 @@ impl<'db, 'a> InferenceTyLoweringContext<'db, 'a> { pub(super) fn new( db: &'db dyn HirDatabase, resolver: &'a Resolver<'db>, - store: &'a ExpressionStore, + store: &'db ExpressionStore, diagnostics: &'a Diagnostics, source: InferenceTyDiagnosticSource, def: ExpressionStoreOwnerId, @@ -107,7 +107,7 @@ impl<'db, 'a> InferenceTyLoweringContext<'db, 'a> { lifetime_elision: LifetimeElisionKind<'db>, allow_using_generic_params: bool, infer_vars: Option<&'a mut dyn TyLoweringInferVarsCtx<'db>>, - defined_anon_consts: &'a RefCell>, + defined_anon_consts: &'a RefCell>>, lifetime_lowering_mode: LifetimeLoweringMode, ) -> Self { let mut ctx = TyLoweringContext::new( 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 40465e39520f7..b730c9552d608 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 @@ -53,7 +53,7 @@ pub(crate) enum ExprIsRead { No, } -impl<'db> InferenceContext<'_, 'db> { +impl<'db> InferenceContext<'db> { pub(crate) fn infer_expr( &mut self, tgt_expr: ExprId, @@ -2097,7 +2097,7 @@ impl<'db> InferenceContext<'_, 'db> { // We introduce a helper function to demand that a given argument satisfy a given input // This is more complicated than just checking type equality, as arguments could be coerced // This version writes those types back so further type checking uses the narrowed types - let demand_compatible = |this: &mut InferenceContext<'_, 'db>, idx| { + let demand_compatible = |this: &mut InferenceContext<'db>, idx| { let formal_input_ty: Ty<'db> = formal_input_tys[idx]; let expected_input_ty: Ty<'db> = expected_input_tys[idx]; let provided_arg = provided_args[idx]; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/fallback.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/fallback.rs index 3744a434d2199..0498ea8fd00a5 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/fallback.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/fallback.rs @@ -27,7 +27,7 @@ pub(crate) enum DivergingFallbackBehavior { ToNever, } -impl<'db> InferenceContext<'_, 'db> { +impl<'db> InferenceContext<'db> { pub(super) fn type_inference_fallback(&mut self) { debug!( "type-inference-fallback start obligations: {:#?}", 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 4fa1b71ad4a94..9ec297f5f5e4e 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 @@ -13,7 +13,7 @@ use crate::{ lower::lower_mutability, }; -impl<'db> InferenceContext<'_, 'db> { +impl<'db> InferenceContext<'db> { pub(crate) fn infer_mut_body(&mut self, body_expr: ExprId) { self.infer_mut_expr(body_expr, Mutability::Not); } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/op.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/op.rs index 85801358d4441..5fd4e830fb172 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/op.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/op.rs @@ -20,7 +20,7 @@ use crate::{ }, }; -impl<'a, 'db> InferenceContext<'a, 'db> { +impl<'db> InferenceContext<'db> { /// Checks a `a = b` pub(crate) fn infer_assign_op_expr( &mut self, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/opaques.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/opaques.rs index 63149deb82b77..2d64f9567b375 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/opaques.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/opaques.rs @@ -12,7 +12,7 @@ use crate::{ }, }; -impl<'db> InferenceContext<'_, 'db> { +impl<'db> InferenceContext<'db> { /// This takes all the opaque type uses during HIR typeck. It first computes /// the concrete hidden type by iterating over all defining uses. /// @@ -63,7 +63,7 @@ impl<'db> UsageKind<'db> { } } -impl<'db> InferenceContext<'_, 'db> { +impl<'db> InferenceContext<'db> { fn compute_definition_site_hidden_types( &mut self, mut opaque_types: Vec<(OpaqueTypeKey<'db>, OpaqueHiddenType<'db>)>, 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 1e539d24c18a8..bab4e79700aa2 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 @@ -237,7 +237,7 @@ impl<'db> ResolvedPat<'db> { } } -impl<'a, 'db> InferenceContext<'a, 'db> { +impl<'db> InferenceContext<'db> { /// Experimental pattern feature: after matching against a shared reference, do we limit the /// default binding mode in subpatterns to be `ref` when it would otherwise be `ref mut`? /// This corresponds to Rule 3 of RFC 3627. 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 ecc81f9de0232..56a503f2d200a 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 @@ -25,7 +25,7 @@ use crate::{ use super::{ExprOrPatId, InferenceContext, InferenceTyDiagnosticSource}; -impl<'db> InferenceContext<'_, 'db> { +impl<'db> InferenceContext<'db> { pub(super) fn infer_path( &mut self, path: &Path, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/place_op.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/place_op.rs index bbf047b8bacfb..b226e5ca85de0 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/place_op.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/place_op.rs @@ -25,7 +25,7 @@ pub(super) enum PlaceOp { Index, } -impl<'a, 'db> InferenceContext<'a, 'db> { +impl<'db> InferenceContext<'db> { pub(super) fn try_overloaded_deref( &self, expr: ExprId, @@ -107,7 +107,7 @@ impl<'a, 'db> InferenceContext<'a, 'db> { expr: ExprId, base_expr: ExprId, index_expr: ExprId, - autoderef: &mut InferenceContextAutoderef<'_, 'a, 'db>, + autoderef: &mut InferenceContextAutoderef<'_, 'db>, index_ty: Ty<'db>, ) -> Option<(/*index type*/ Ty<'db>, /*element type*/ Ty<'db>)> { let ty = autoderef.final_ty(); 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 4c808714d9506..6157f51500d9e 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 @@ -314,7 +314,11 @@ impl<'db> InferenceTable<'db> { } /// Create a `GenericArgs` full of infer vars for `def`. - pub(crate) fn fresh_args_for_item(&self, span: Span, def: SolverDefId) -> GenericArgs<'db> { + pub(crate) fn fresh_args_for_item( + &self, + span: Span, + def: SolverDefId<'db>, + ) -> GenericArgs<'db> { self.infer_ctxt.fresh_args_for_item(span, def) } 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 adba047042cb6..db1f7b874e95b 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs @@ -176,7 +176,7 @@ pub fn layout_of_ty_query( let infer_ctxt = interner.infer_ctxt().build(TypingMode::PostAnalysis); let cause = ObligationCause::dummy(); let ty = infer_ctxt - .at(&cause, trait_env.param_env()) + .at(&cause, trait_env.param_env(db)) .deeply_normalize(ty.as_ref()) .unwrap_or(ty.as_ref()); let result = match ty.kind() { @@ -190,7 +190,7 @@ pub fn layout_of_ty_query( s, repr.packed(), &args, - trait_env.as_ref(), + trait_env.as_ref(db), target, ); } @@ -355,11 +355,11 @@ pub fn layout_of_ty_query( PatternKind::Range { start, end } => { if let BackendRepr::Scalar(scalar) = &mut layout.backend_repr { scalar.valid_range_mut().start = extract_const_value(start)? - .try_to_bits(db, trait_env.as_ref()) + .try_to_bits(db, trait_env.as_ref(db)) .ok_or(LayoutError::Unknown)?; scalar.valid_range_mut().end = extract_const_value(end)? - .try_to_bits(db, trait_env.as_ref()) + .try_to_bits(db, trait_env.as_ref(db)) .ok_or(LayoutError::Unknown)?; // FIXME(pattern_types): create implied bounds from pattern types in signatures @@ -419,10 +419,10 @@ pub fn layout_of_ty_query( .map(|pat| match pat.kind() { PatternKind::Range { start, end } => Ok::<_, LayoutError>(( extract_const_value(start)? - .try_to_bits(db, trait_env.as_ref()) + .try_to_bits(db, trait_env.as_ref(db)) .ok_or(LayoutError::Unknown)?, extract_const_value(end)? - .try_to_bits(db, trait_env.as_ref()) + .try_to_bits(db, trait_env.as_ref(db)) .ok_or(LayoutError::Unknown)?, )), PatternKind::NotNull | PatternKind::Or(_) => { 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 120c265fdc84a..d217024b56910 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs @@ -81,6 +81,7 @@ use rustc_type_ir::{ BoundVarIndexKind, TypeSuperVisitable, TypeVisitableExt, inherent::{IntoKind, Ty as _}, }; +use salsa::Update; use stdx::impl_from; use syntax::ast::{ConstArg, make}; use traits::FnTrait; @@ -165,7 +166,7 @@ impl ComplexMemoryMap<'_> { } impl<'db> MemoryMap<'db> { - pub fn vtable_ty(&self, id: usize) -> Result, MirEvalError> { + 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), @@ -181,8 +182,8 @@ impl<'db> MemoryMap<'db> { /// allocator function as `f` and it will return a mapping of old addresses to new addresses. fn transform_addresses( &self, - mut f: impl FnMut(&[u8], usize) -> Result, - ) -> Result, MirEvalError> { + mut f: impl FnMut(&[u8], usize) -> Result>, + ) -> Result, MirEvalError<'db>> { let mut transform = |(addr, val): (&usize, &[u8])| { let addr = *addr; let align = if addr == 0 { 64 } else { (addr - (addr & (addr - 1))).min(64) }; @@ -553,19 +554,43 @@ impl Span { } /// A [`DefWithBodyId`], or an anon const. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, salsa::Supertype)] -pub enum InferBodyId { +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, salsa::Supertype, Update)] +pub enum InferBodyId<'db> { DefWithBodyId(DefWithBodyId), - AnonConstId(AnonConstId), + AnonConstId(AnonConstId<'db>), } -impl_from!(DefWithBodyId(FunctionId, ConstId, StaticId), AnonConstId for InferBodyId); -impl From for InferBodyId { +impl<'db> From for InferBodyId<'db> { + fn from(it: DefWithBodyId) -> InferBodyId<'db> { + InferBodyId::DefWithBodyId(it) + } +} +impl<'db> From for InferBodyId<'db> { + fn from(it: FunctionId) -> InferBodyId<'db> { + InferBodyId::DefWithBodyId(it.into()) + } +} +impl<'db> From for InferBodyId<'db> { + fn from(it: ConstId) -> InferBodyId<'db> { + InferBodyId::DefWithBodyId(it.into()) + } +} +impl<'db> From for InferBodyId<'db> { + fn from(it: StaticId) -> InferBodyId<'db> { + InferBodyId::DefWithBodyId(it.into()) + } +} +impl<'db> From> for InferBodyId<'db> { + fn from(it: AnonConstId<'db>) -> InferBodyId<'db> { + InferBodyId::AnonConstId(it) + } +} +impl<'db> From for InferBodyId<'db> { fn from(id: EnumVariantId) -> Self { InferBodyId::DefWithBodyId(DefWithBodyId::VariantId(id)) } } -impl HasModule for InferBodyId { +impl HasModule for InferBodyId<'_> { fn module(&self, db: &dyn SourceDatabase) -> ModuleId { match self { InferBodyId::DefWithBodyId(id) => id.module(db), @@ -574,7 +599,7 @@ impl HasModule for InferBodyId { } } -impl HasResolver for InferBodyId { +impl HasResolver for InferBodyId<'_> { fn resolver(self, db: &dyn SourceDatabase) -> Resolver<'_> { match self { InferBodyId::DefWithBodyId(id) => id.resolver(db), @@ -583,7 +608,7 @@ impl HasResolver for InferBodyId { } } -impl InferBodyId { +impl InferBodyId<'_> { pub fn expression_store_owner(self, db: &dyn HirDatabase) -> ExpressionStoreOwnerId { match self { InferBodyId::DefWithBodyId(id) => id.into(), 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 ccc3356686b89..7450a0d29356a 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs @@ -10,6 +10,7 @@ pub(crate) mod path; use std::{cell::OnceCell, iter, mem, sync::OnceLock}; +use base_db::salsa::update_fallback_db; use either::Either; use hir_def::{ AdtId, AssocItemId, CallableDefId, ConstId, ConstParamId, EnumId, EnumVariantId, @@ -50,6 +51,7 @@ use rustc_type_ir::{ TypeVisitableExt, Upcast, UpcastFrom, elaborate, inherent::{Clause as _, GenericArgs as _, IntoKind as _, Region as _, Ty as _}, }; +use salsa::Update; use smallvec::SmallVec; use stdx::{impl_from, never}; use thin_vec::ThinVec; @@ -210,7 +212,7 @@ pub struct TyLoweringContext<'db, 'a> { types: &'db crate::next_solver::DefaultAny<'db>, lang_items: &'db LangItems, resolver: &'a Resolver<'db>, - store: &'a ExpressionStore, + store: &'db ExpressionStore, def: ExpressionStoreOwnerId, generic_def: GenericDefId, generics: &'a OnceCell>, @@ -223,7 +225,7 @@ pub struct TyLoweringContext<'db, 'a> { lifetime_elision: LifetimeElisionKind<'db>, forbid_params_after: Option, forbid_params_after_reason: ForbidParamsAfterReason, - pub(crate) defined_anon_consts: ThinVec, + pub(crate) defined_anon_consts: ThinVec>, infer_vars: Option<&'a mut dyn TyLoweringInferVarsCtx<'db>>, is_lowering_impl_trait_bounds: bool, bound_vars: Vec>, // FIXME: HRTB and other for lifetime doesn't change it now @@ -234,7 +236,7 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { pub fn new( db: &'db dyn HirDatabase, resolver: &'a Resolver<'db>, - store: &'a ExpressionStore, + store: &'db ExpressionStore, def: ExpressionStoreOwnerId, generic_def: GenericDefId, generics: &'a OnceCell>, @@ -1295,13 +1297,21 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { } } -#[derive(Clone, PartialEq, Eq)] -pub struct TyLoweringResult { +#[derive(Clone, PartialEq, Eq, Update)] +pub struct TyLoweringResult<'db, T> { + #[update(fallback)] pub value: T, - info: Option, ThinVec)>>, + #[update(bounds(TyLoweringResultInfo<'db>: Update), unsafe(with(update_fallback_db::<'db, _>)))] + info: Option>>, } -impl std::fmt::Debug for TyLoweringResult { +#[derive(Clone, PartialEq, Eq, Update)] +struct TyLoweringResultInfo<'db> { + diagnostics: ThinVec, + anon_consts: ThinVec>, +} + +impl std::fmt::Debug for TyLoweringResult<'_, T> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let mut debug = f.debug_struct("TyLoweringResult"); debug.field("value", &self.value); @@ -1317,23 +1327,23 @@ impl std::fmt::Debug for TyLoweringResult { } } -impl TyLoweringResult { +impl<'db, T> TyLoweringResult<'db, T> { fn new( value: T, mut diagnostics: ThinVec, - mut defined_anon_consts: ThinVec, + mut defined_anon_consts: ThinVec>, ) -> Self { let info = if diagnostics.is_empty() && defined_anon_consts.is_empty() { None } else { diagnostics.shrink_to_fit(); defined_anon_consts.shrink_to_fit(); - Some(Box::new((diagnostics, defined_anon_consts))) + Some(Box::new(TyLoweringResultInfo { diagnostics, anon_consts: defined_anon_consts })) }; Self { value, info } } - fn from_ctx(value: T, ctx: TyLoweringContext<'_, '_>) -> Self { + fn from_ctx(value: T, ctx: TyLoweringContext<'db, '_>) -> Self { Self::new(value, ctx.diagnostics, ctx.defined_anon_consts) } @@ -1344,15 +1354,15 @@ impl TyLoweringResult { #[inline] pub fn diagnostics(&self) -> &[TyLoweringDiagnostic] { match &self.info { - Some(info) => &info.0, + Some(info) => &info.diagnostics, None => &[], } } #[inline] - pub fn defined_anon_consts(&self) -> &[AnonConstId] { + pub fn defined_anon_consts(&self) -> &[AnonConstId<'db>] { match &self.info { - Some(info) => &info.1, + Some(info) => &info.anon_consts, None => &[], } } @@ -1390,10 +1400,10 @@ pub(crate) fn impl_trait_query<'db>( } #[salsa::tracked(returns(ref))] -pub(crate) fn impl_trait_with_diagnostics( - db: &dyn HirDatabase, +pub(crate) fn impl_trait_with_diagnostics<'db>( + db: &'db dyn HirDatabase, impl_id: ImplId, -) -> Option>> { +) -> Option>> { let impl_data = ImplSignature::of(db, impl_id); let resolver = impl_id.resolver(db); let generics = OnceCell::new(); @@ -1608,10 +1618,10 @@ pub(crate) fn type_for_const<'db>( /// Build the declared type of a const. #[salsa_macros::tracked(returns(ref))] -pub(crate) fn type_for_const_with_diagnostics( - db: &dyn HirDatabase, +pub(crate) fn type_for_const_with_diagnostics<'db>( + db: &'db dyn HirDatabase, def: ConstId, -) -> TyLoweringResult> { +) -> TyLoweringResult<'db, StoredEarlyBinder> { let resolver = def.resolver(db); let data = ConstSignature::of(db, def); let parent = def.loc(db).container; @@ -1640,10 +1650,10 @@ pub(crate) fn type_for_static<'db>( /// Build the declared type of a static. #[salsa_macros::tracked(returns(ref))] -pub(crate) fn type_for_static_with_diagnostics( - db: &dyn HirDatabase, +pub(crate) fn type_for_static_with_diagnostics<'db>( + db: &'db dyn HirDatabase, def: StaticId, -) -> TyLoweringResult> { +) -> TyLoweringResult<'db, StoredEarlyBinder> { let resolver = def.resolver(db); let data = StaticSignature::of(db, def); let generics = OnceCell::new(); @@ -1719,10 +1729,10 @@ pub(crate) fn value_ty<'db>( } #[salsa::tracked(returns(ref), cycle_result = type_for_type_alias_with_diagnostics_cycle_result)] -pub(crate) fn type_for_type_alias_with_diagnostics( - db: &dyn HirDatabase, +pub(crate) fn type_for_type_alias_with_diagnostics<'db>( + db: &'db dyn HirDatabase, t: TypeAliasId, -) -> TyLoweringResult> { +) -> TyLoweringResult<'db, StoredEarlyBinder> { let type_alias_data = TypeAliasSignature::of(db, t); let interner = DbInterner::new_no_crate(db); if type_alias_data.flags.contains(TypeAliasFlags::IS_EXTERN) { @@ -1754,11 +1764,11 @@ pub(crate) fn type_for_type_alias_with_diagnostics( } } -pub(crate) fn type_for_type_alias_with_diagnostics_cycle_result( - db: &dyn HirDatabase, +pub(crate) fn type_for_type_alias_with_diagnostics_cycle_result<'db>( + db: &'db dyn HirDatabase, _: salsa::Id, _adt: TypeAliasId, -) -> TyLoweringResult> { +) -> TyLoweringResult<'db, StoredEarlyBinder> { TyLoweringResult::empty(StoredEarlyBinder::bind( Ty::new_error(DbInterner::new_no_crate(db), ErrorGuaranteed).store(), )) @@ -1772,10 +1782,10 @@ pub(crate) fn impl_self_ty_query<'db>( } #[salsa::tracked(returns(ref), cycle_result = impl_self_ty_with_diagnostics_cycle_result)] -pub(crate) fn impl_self_ty_with_diagnostics( - db: &dyn HirDatabase, +pub(crate) fn impl_self_ty_with_diagnostics<'db>( + db: &'db dyn HirDatabase, impl_id: ImplId, -) -> TyLoweringResult> { +) -> TyLoweringResult<'db, StoredEarlyBinder> { let resolver = impl_id.resolver(db); let generics = OnceCell::new(); let impl_data = ImplSignature::of(db, impl_id); @@ -1794,11 +1804,11 @@ pub(crate) fn impl_self_ty_with_diagnostics( TyLoweringResult::from_ctx(StoredEarlyBinder::bind(ty.store()), ctx) } -pub(crate) fn impl_self_ty_with_diagnostics_cycle_result( - db: &dyn HirDatabase, +pub(crate) fn impl_self_ty_with_diagnostics_cycle_result<'db>( + db: &'db dyn HirDatabase, _: salsa::Id, _impl_id: ImplId, -) -> TyLoweringResult> { +) -> TyLoweringResult<'db, StoredEarlyBinder> { TyLoweringResult::empty(StoredEarlyBinder::bind( Ty::new_error(DbInterner::new_no_crate(db), ErrorGuaranteed).store(), )) @@ -1820,10 +1830,10 @@ pub(crate) fn const_param_types( } #[salsa::tracked(returns(ref), cycle_result = const_param_types_with_diagnostics_cycle_result)] -pub(crate) fn const_param_types_with_diagnostics( - db: &dyn HirDatabase, +pub(crate) fn const_param_types_with_diagnostics<'db>( + db: &'db dyn HirDatabase, def: GenericDefId, -) -> TyLoweringResult> { +) -> TyLoweringResult<'db, ArenaMap> { let mut result = ArenaMap::new(); let (data, store) = GenericParams::with_store(db, def); let resolver = def.resolver(db); @@ -1848,11 +1858,11 @@ pub(crate) fn const_param_types_with_diagnostics( TyLoweringResult::from_ctx(result, ctx) } -fn const_param_types_with_diagnostics_cycle_result( - _db: &dyn HirDatabase, +fn const_param_types_with_diagnostics_cycle_result<'db>( + _db: &'db dyn HirDatabase, _: salsa::Id, _def: GenericDefId, -) -> TyLoweringResult> { +) -> TyLoweringResult<'db, ArenaMap> { TyLoweringResult::empty(ArenaMap::default()) } @@ -1883,10 +1893,10 @@ impl FieldType { /// Build the type of all specific fields of a struct or enum variant. #[salsa::tracked(returns(ref))] -pub(crate) fn field_types_with_diagnostics( - db: &dyn HirDatabase, +pub(crate) fn field_types_with_diagnostics<'db>( + db: &'db dyn HirDatabase, variant_id: VariantId, -) -> TyLoweringResult> { +) -> TyLoweringResult<'db, ArenaMap> { let var_data = variant_id.fields(db); let fields = var_data.fields(); if fields.is_empty() { @@ -2215,10 +2225,10 @@ pub struct TypeAliasBounds { } #[salsa::tracked(returns(ref))] -pub(crate) fn type_alias_bounds_with_diagnostics( - db: &dyn HirDatabase, +pub(crate) fn type_alias_bounds_with_diagnostics<'db>( + db: &'db dyn HirDatabase, type_alias: TypeAliasId, -) -> TyLoweringResult>> { +) -> TyLoweringResult<'db, TypeAliasBounds>> { let type_alias_data = TypeAliasSignature::of(db, type_alias); let resolver = type_alias.resolver(db); let generics = OnceCell::new(); @@ -2302,17 +2312,17 @@ impl<'db> GenericPredicates { pub fn query_with_diagnostics( db: &'db dyn HirDatabase, def: GenericDefId, - ) -> TyLoweringResult { + ) -> TyLoweringResult<'db, GenericPredicates> { generic_predicates(db, def) } } /// A cycle can occur from malformed code. -fn generic_predicates_cycle_result( - db: &dyn HirDatabase, +fn generic_predicates_cycle_result<'db>( + db: &'db dyn HirDatabase, _: salsa::Id, _def: GenericDefId, -) -> TyLoweringResult { +) -> TyLoweringResult<'db, GenericPredicates> { TyLoweringResult::empty(GenericPredicates::from_explicit_own_predicates( StoredEarlyBinder::bind(Clauses::empty(DbInterner::new_no_crate(db)).store()), )) @@ -2452,10 +2462,10 @@ pub(crate) fn trait_environment<'db>(db: &'db dyn HirDatabase, def: GenericDefId /// Resolve the where clause(s) of an item with generics, /// with a given filter #[tracing::instrument(skip(db), ret)] -fn generic_predicates( - db: &dyn HirDatabase, +fn generic_predicates<'db>( + db: &'db dyn HirDatabase, def: GenericDefId, -) -> TyLoweringResult { +) -> TyLoweringResult<'db, GenericPredicates> { let generics = generics(db, def); let store = generics.store(); let generics = &OnceCell::from(generics); @@ -2667,10 +2677,10 @@ pub(crate) fn generic_defaults(db: &dyn HirDatabase, def: GenericDefId) -> Gener /// /// Diagnostics are only returned for this `GenericDefId` (returned defaults include parents). #[salsa_macros::tracked(returns(ref), cycle_result = generic_defaults_with_diagnostics_cycle_result)] -pub(crate) fn generic_defaults_with_diagnostics( - db: &dyn HirDatabase, +pub(crate) fn generic_defaults_with_diagnostics<'db>( + db: &'db dyn HirDatabase, def: GenericDefId, -) -> TyLoweringResult { +) -> TyLoweringResult<'db, GenericDefaults> { let generics = generics(db, def); if generics.has_no_params() { return TyLoweringResult::empty(GenericDefaults(ThinVec::new())); @@ -2731,11 +2741,11 @@ pub(crate) fn generic_defaults_with_diagnostics( } } -fn generic_defaults_with_diagnostics_cycle_result( - _db: &dyn HirDatabase, +fn generic_defaults_with_diagnostics_cycle_result<'db>( + _db: &'db dyn HirDatabase, _: salsa::Id, _def: GenericDefId, -) -> TyLoweringResult { +) -> TyLoweringResult<'db, GenericDefaults> { TyLoweringResult::empty(GenericDefaults(ThinVec::new())) } @@ -2748,10 +2758,10 @@ pub(crate) fn callable_item_signature<'db>( } #[salsa::tracked(returns(ref))] -pub(crate) fn callable_item_signature_with_diagnostics( - db: &dyn HirDatabase, +pub(crate) fn callable_item_signature_with_diagnostics<'db>( + db: &'db dyn HirDatabase, def: CallableDefId, -) -> TyLoweringResult> { +) -> TyLoweringResult<'db, StoredEarlyBinder> { match def { CallableDefId::FunctionId(f) => fn_sig_for_fn(db, f), CallableDefId::StructId(s) => TyLoweringResult::empty(fn_sig_for_struct_constructor(db, s)), @@ -2761,10 +2771,10 @@ pub(crate) fn callable_item_signature_with_diagnostics( } } -fn fn_sig_for_fn( - db: &dyn HirDatabase, +fn fn_sig_for_fn<'db>( + db: &'db dyn HirDatabase, def: FunctionId, -) -> TyLoweringResult> { +) -> TyLoweringResult<'db, StoredEarlyBinder> { let data = FunctionSignature::of(db, def); let resolver = def.resolver(db); let interner = DbInterner::new_no_crate(db); 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 c5868ab6b5271..e8702bf2c99de 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 @@ -11,10 +11,11 @@ mod probe; use either::Either; use hir_expand::name::Name; +use salsa::Update; use span::Edition; use tracing::{debug, instrument}; -use base_db::Crate; +use base_db::{Crate, salsa::update_fallback_db}; use hir_def::{ AssocItemId, BlockIdLt, BuiltinDeriveImplId, ConstId, FunctionId, GenericParamId, HasModule, ImplId, ItemContainerId, ModuleId, TraitId, @@ -125,7 +126,7 @@ pub enum CandidateSource { Trait(TraitId), } -impl<'a, 'db> InferenceContext<'a, 'db> { +impl<'db> InferenceContext<'db> { /// Performs method lookup. If lookup is successful, it will return the callee /// and store an appropriate adjustment for the self-expr. In some cases it may /// report an error (e.g., invoking the `drop` method). @@ -522,10 +523,10 @@ fn crates_containing_incoherent_inherent_impls(db: &dyn HirDatabase, krate: Crat krate.transitive_deps(db).into_iter().filter(|krate| krate.data(db).origin.is_lang()).collect() } -pub fn with_incoherent_inherent_impls( - db: &dyn HirDatabase, +pub fn with_incoherent_inherent_impls<'db>( + db: &'db dyn HirDatabase, krate: Crate, - self_ty: &SimplifiedType, + self_ty: &SimplifiedType<'db>, mut callback: impl FnMut(&[ImplId]), ) { let has_incoherent_impls = match self_ty.def() { @@ -547,7 +548,7 @@ pub fn with_incoherent_inherent_impls( } } -pub fn simplified_type_module(db: &dyn HirDatabase, ty: &SimplifiedType) -> Option { +pub fn simplified_type_module(db: &dyn HirDatabase, ty: &SimplifiedType<'_>) -> Option { match ty.def()? { SolverDefId::AdtId(id) => Some(id.module(db)), SolverDefId::TypeAliasId(id) => Some(id.module(db)), @@ -556,15 +557,16 @@ pub fn simplified_type_module(db: &dyn HirDatabase, ty: &SimplifiedType) -> Opti } } -#[derive(Debug, PartialEq, Eq)] -pub struct InherentImpls { - map: FxHashMap>, +#[derive(Debug, PartialEq, Eq, Update)] +pub struct InherentImpls<'db> { + #[update(bounds(SolverDefId<'db>: Update), unsafe(with(update_fallback_db::<'db, _>)))] + map: FxHashMap, Box<[ImplId]>>, } #[salsa::tracked] -impl<'db> InherentImpls { +impl<'db> InherentImpls<'db> { #[salsa::tracked(returns(ref))] - pub fn for_crate(db: &'db dyn HirDatabase, krate: Crate) -> Self { + pub fn for_crate(db: &'db dyn HirDatabase, krate: Crate) -> InherentImpls<'db> { let _p = tracing::info_span!("inherent_impls_in_crate_query", ?krate).entered(); let crate_def_map = crate_def_map(db, krate); @@ -573,7 +575,10 @@ impl<'db> InherentImpls { } #[salsa::tracked(returns(ref))] - pub fn for_block(db: &'db dyn HirDatabase, block: BlockIdLt<'db>) -> Option> { + pub fn for_block( + db: &'db dyn HirDatabase, + block: BlockIdLt<'db>, + ) -> Option>> { let _p = tracing::info_span!("inherent_impls_in_block_query").entered(); let block_def_map = block_def_map(db, block); @@ -582,8 +587,8 @@ impl<'db> InherentImpls { } } -impl InherentImpls { - fn collect_def_map(db: &dyn HirDatabase, def_map: &DefMap) -> Self { +impl<'db> InherentImpls<'db> { + fn collect_def_map(db: &'db dyn HirDatabase, def_map: &'db DefMap) -> Self { let mut map = FxHashMap::default(); collect(db, def_map, &mut map); let mut map = map @@ -593,10 +598,10 @@ impl InherentImpls { map.shrink_to_fit(); return Self { map }; - fn collect( - db: &dyn HirDatabase, + fn collect<'db>( + db: &'db dyn HirDatabase, def_map: &DefMap, - map: &mut FxHashMap>, + map: &mut FxHashMap, Vec>, ) { for (_module_id, module_data) in def_map.modules() { for impl_id in module_data.scope.inherent_impls() { @@ -622,15 +627,15 @@ impl InherentImpls { } } - pub fn for_self_ty(&self, self_ty: &SimplifiedType) -> &[ImplId] { + pub fn for_self_ty(&self, self_ty: &SimplifiedType<'db>) -> &[ImplId] { self.map.get(self_ty).map(|it| &**it).unwrap_or_default() } - pub fn for_each_crate_and_block<'db>( + pub fn for_each_crate_and_block( db: &'db dyn HirDatabase, krate: Crate, block: Option>, - for_each: &mut dyn FnMut(&InherentImpls), + for_each: &mut dyn FnMut(&InherentImpls<'db>), ) { let blocks = std::iter::successors(block, |block| block.module(db).block(db)); blocks.filter_map(|block| Self::for_block(db, block).as_deref()).for_each(&mut *for_each); @@ -638,20 +643,21 @@ impl InherentImpls { } } -#[derive(Debug, PartialEq)] -struct OneTraitImpls { - non_blanket_impls: FxHashMap, Box<[BuiltinDeriveImplId]>)>, +#[derive(Debug, PartialEq, Update)] +struct OneTraitImpls<'db> { + #[update(bounds(SolverDefId<'db>: Update), unsafe(with(update_fallback_db::<'db, _>)))] + non_blanket_impls: FxHashMap, (Box<[ImplId]>, Box<[BuiltinDeriveImplId]>)>, blanket_impls: Box<[ImplId]>, } #[derive(Default)] -struct OneTraitImplsBuilder { - non_blanket_impls: FxHashMap, Vec)>, +struct OneTraitImplsBuilder<'db> { + non_blanket_impls: FxHashMap, (Vec, Vec)>, blanket_impls: Vec, } -impl OneTraitImplsBuilder { - fn finish(self) -> OneTraitImpls { +impl<'db> OneTraitImplsBuilder<'db> { + fn finish(self) -> OneTraitImpls<'db> { let mut non_blanket_impls = self .non_blanket_impls .into_iter() @@ -665,15 +671,15 @@ impl OneTraitImplsBuilder { } } -#[derive(Debug, PartialEq)] -pub struct TraitImpls { - map: FxHashMap, +#[derive(Debug, PartialEq, Update)] +pub struct TraitImpls<'db> { + map: FxHashMap>, } #[salsa::tracked] -impl<'db> TraitImpls { +impl<'db> TraitImpls<'db> { #[salsa::tracked(returns(ref))] - pub fn for_crate(db: &'db dyn HirDatabase, krate: Crate) -> Arc { + pub fn for_crate(db: &'db dyn HirDatabase, krate: Crate) -> Arc> { let _p = tracing::info_span!("inherent_impls_in_crate_query", ?krate).entered(); let crate_def_map = crate_def_map(db, krate); @@ -682,7 +688,10 @@ impl<'db> TraitImpls { } #[salsa::tracked(returns(as_deref))] - pub fn for_block(db: &'db dyn HirDatabase, block: BlockIdLt<'db>) -> Option> { + pub fn for_block( + db: &'db dyn HirDatabase, + block: BlockIdLt<'db>, + ) -> Option>> { let _p = tracing::info_span!("inherent_impls_in_block_query").entered(); let block_def_map = block_def_map(db, block); @@ -696,8 +705,8 @@ impl<'db> TraitImpls { } } -impl TraitImpls { - fn collect_def_map(db: &dyn HirDatabase, def_map: &DefMap) -> Self { +impl<'db> TraitImpls<'db> { + fn collect_def_map(db: &'db dyn HirDatabase, def_map: &DefMap) -> Self { let lang_items = hir_def::lang_item::lang_items(db, def_map.krate()); let mut map = FxHashMap::default(); collect(db, def_map, lang_items, &mut map); @@ -708,11 +717,11 @@ impl TraitImpls { map.shrink_to_fit(); return Self { map }; - fn collect( - db: &dyn HirDatabase, + fn collect<'db>( + db: &'db dyn HirDatabase, def_map: &DefMap, lang_items: &LangItems, - map: &mut FxHashMap, + map: &mut FxHashMap>, ) { for (_module_id, module_data) in def_map.modules() { for impl_id in module_data.scope.trait_impls() { @@ -779,7 +788,7 @@ impl TraitImpls { pub fn has_impls_for_trait_and_self_ty( &self, trait_: TraitId, - self_ty: &SimplifiedType, + self_ty: &SimplifiedType<'db>, ) -> bool { self.map.get(&trait_).is_some_and(|trait_impls| { trait_impls.non_blanket_impls.contains_key(self_ty) @@ -788,10 +797,10 @@ impl TraitImpls { } pub fn for_trait_and_self_ty( - &self, + &'db self, trait_: TraitId, - self_ty: &SimplifiedType, - ) -> (&[ImplId], &[BuiltinDeriveImplId]) { + self_ty: &SimplifiedType<'db>, + ) -> (&'db [ImplId], &'db [BuiltinDeriveImplId]) { self.map .get(&trait_) .and_then(|map| map.non_blanket_impls.get(self_ty)) @@ -815,7 +824,7 @@ impl TraitImpls { pub fn for_self_ty( &self, - self_ty: &SimplifiedType, + self_ty: &SimplifiedType<'db>, mut callback: impl FnMut(Either<&[ImplId], &[BuiltinDeriveImplId]>), ) { for for_trait in self.map.values() { @@ -826,11 +835,11 @@ impl TraitImpls { } } - pub fn for_each_crate_and_block<'db>( + pub fn for_each_crate_and_block( db: &'db dyn HirDatabase, krate: Crate, block: Option>, - for_each: &mut dyn FnMut(&TraitImpls), + for_each: &mut dyn FnMut(&TraitImpls<'db>), ) { let blocks = std::iter::successors(block, |block| block.module(db).block(db)); blocks.filter_map(|block| Self::for_block(db, block)).for_each(&mut *for_each); @@ -838,12 +847,12 @@ impl TraitImpls { } /// Like [`Self::for_each_crate_and_block()`], but takes in account two blocks, one for a trait and one for a self type. - pub fn for_each_crate_and_block_trait_and_type<'db>( + pub fn for_each_crate_and_block_trait_and_type( db: &'db dyn HirDatabase, krate: Crate, type_block: Option>, trait_block: Option>, - for_each: &mut dyn FnMut(&TraitImpls), + for_each: &mut dyn FnMut(&TraitImpls<'db>), ) { let in_self_and_deps = TraitImpls::for_crate_and_deps(db, krate); in_self_and_deps.iter().for_each(|impls| for_each(impls)); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution/confirm.rs b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution/confirm.rs index d960a6547d462..6d948464b1c03 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution/confirm.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution/confirm.rs @@ -36,8 +36,8 @@ use crate::{ }, }; -struct ConfirmContext<'a, 'b, 'db> { - ctx: &'a mut InferenceContext<'b, 'db>, +struct ConfirmContext<'a, 'db> { + ctx: &'a mut InferenceContext<'db>, candidate: FunctionId, call_expr: ExprId, } @@ -49,7 +49,7 @@ pub(crate) struct ConfirmResult<'db> { pub(crate) adjustments: Box<[Adjustment]>, } -impl<'a, 'db> InferenceContext<'a, 'db> { +impl<'db> InferenceContext<'db> { pub(crate) fn confirm_method( &mut self, pick: &probe::Pick<'db>, @@ -70,12 +70,12 @@ impl<'a, 'db> InferenceContext<'a, 'db> { } } -impl<'a, 'b, 'db> ConfirmContext<'a, 'b, 'db> { +impl<'a, 'db> ConfirmContext<'a, 'db> { fn new( - ctx: &'a mut InferenceContext<'b, 'db>, + ctx: &'a mut InferenceContext<'db>, candidate: FunctionId, call_expr: ExprId, - ) -> ConfirmContext<'a, 'b, 'db> { + ) -> ConfirmContext<'a, 'db> { ConfirmContext { ctx, candidate, call_expr } } @@ -312,7 +312,7 @@ impl<'a, 'b, 'db> ConfirmContext<'a, 'b, 'db> { fn extract_existential_trait_ref(&self, self_ty: Ty<'db>, mut closure: F) -> R where - F: FnMut(&ConfirmContext<'a, 'b, 'db>, Ty<'db>, PolyExistentialTraitRef<'db>) -> R, + F: FnMut(&ConfirmContext<'a, 'db>, Ty<'db>, PolyExistentialTraitRef<'db>) -> R, { // If we specified that this is an object method, then the // self-type ought to be something that can be dereferenced to @@ -348,13 +348,13 @@ impl<'a, 'b, 'db> ConfirmContext<'a, 'b, 'db> { generic_args: Option<&HirGenericArgs>, parent_args: GenericArgs<'db>, ) -> GenericArgs<'db> { - struct LowererCtx<'a, 'b, 'db> { - ctx: &'a mut InferenceContext<'b, 'db>, + struct LowererCtx<'a, 'db> { + ctx: &'a mut InferenceContext<'db>, expr: ExprId, parent_args: &'a [GenericArg<'db>], } - impl<'db> GenericArgsLowerer<'db> for LowererCtx<'_, '_, 'db> { + impl<'db> GenericArgsLowerer<'db> for LowererCtx<'_, 'db> { fn report_len_mismatch( &mut self, def: GenericDefId, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution/probe.rs b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution/probe.rs index 3be9afdf45437..0a47e031b720f 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution/probe.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution/probe.rs @@ -993,7 +993,7 @@ impl<'a, 'db, Choice: ProbeChoice<'db>> ProbeContext<'a, 'db, Choice> { fn assemble_inherent_impl_candidates_for_type( &mut self, - self_ty: &SimplifiedType, + self_ty: &SimplifiedType<'db>, receiver_steps: usize, ) { let Some(module) = simplified_type_module(self.db(), self_ty) else { 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 2fa3f5e797b5e..976f88601ed73 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs @@ -15,6 +15,7 @@ use rustc_type_ir::{ CollectAndApply, GenericTypeVisitable, inherent::{GenericArgs as _, IntoKind, Ty as _}, }; +use salsa::Update; use smallvec::{SmallVec, smallvec}; use stdx::impl_from; @@ -318,7 +319,12 @@ impl<'db> PlaceRef<'db> { pub fn store(&self) -> Place { Place { local: self.local, projection: self.projection.store() } } - pub fn ty(&self, body: &MirBody, infcx: &InferCtxt<'db>, env: ParamEnv<'db>) -> PlaceTy<'db> { + pub fn ty( + &self, + body: &MirBody<'db>, + infcx: &InferCtxt<'db>, + env: ParamEnv<'db>, + ) -> PlaceTy<'db> { PlaceTy::from_ty(body.locals[self.local].ty.as_ref()).multi_projection_ty( infcx, env, @@ -1059,21 +1065,21 @@ pub struct BasicBlock { pub is_cleanup: bool, } -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct MirBody { +#[derive(Debug, Clone, PartialEq, Eq, Update)] +pub struct MirBody<'db> { pub basic_blocks: Arena, pub locals: Arena, pub start_block: BasicBlockId, - pub owner: InferBodyId, + pub owner: InferBodyId<'db>, pub binding_locals: ArenaMap, pub upvar_locals: FxHashMap>, pub param_locals: Vec, /// This field stores the closures directly owned by this body. It is used /// in traversing every mir body. - pub closures: Vec, + pub closures: Vec>, } -impl MirBody { +impl MirBody<'_> { pub fn local_to_binding_map(&self) -> ArenaMap { self.binding_locals.iter().map(|(it, y)| (*y, it)).collect() } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/borrowck.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/borrowck.rs index a9271675a0745..c568209541d08 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/borrowck.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/borrowck.rs @@ -9,6 +9,7 @@ use either::Either; use hir_def::HasModule; use la_arena::ArenaMap; use rustc_hash::FxHashMap; +use salsa::Update; use stdx::never; use crate::{ @@ -56,17 +57,17 @@ pub struct BorrowRegion { pub places: Vec, } -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct BorrowckResult { - owner: Either, +#[derive(Debug, Clone, PartialEq, Eq, Update)] +pub struct BorrowckResult<'db> { + owner: Either, InternedClosureId<'db>>, pub mutability_of_locals: ArenaMap, pub moved_out_of_ref: Vec, pub partially_moved: Vec, pub borrow_regions: Vec, } -impl BorrowckResult { - pub fn mir_body<'db>(&self, db: &'db dyn HirDatabase) -> &'db MirBody { +impl<'db> BorrowckResult<'db> { + pub fn mir_body(&self, db: &'db dyn HirDatabase) -> &'db MirBody<'db> { match self.owner { Either::Left(it) => db.mir_body(it).unwrap(), Either::Right(it) => db.mir_body_for_closure(it).unwrap(), @@ -76,23 +77,29 @@ impl BorrowckResult { fn all_mir_bodies<'db>( db: &'db dyn HirDatabase, - def: InferBodyId, - mut cb: impl FnMut(&'db MirBody, Either) -> BorrowckResult, + def: InferBodyId<'db>, + mut cb: impl FnMut( + &'db MirBody<'db>, + Either, InternedClosureId<'db>>, + ) -> BorrowckResult<'db>, mut merge_from_closures: impl FnMut( - (&mut BorrowckResult, &'db MirBody), - (&BorrowckResult, &'db MirBody), + (&mut BorrowckResult<'db>, &'db MirBody<'db>), + (&BorrowckResult<'db>, &'db MirBody<'db>), ), -) -> Result, MirLowerError> { +) -> Result]>, MirLowerError<'db>> { fn for_closure<'db>( db: &'db dyn HirDatabase, - c: InternedClosureId, - results: &mut Vec<(BorrowckResult, &'db MirBody)>, - cb: &mut impl FnMut(&'db MirBody, Either) -> BorrowckResult, + c: InternedClosureId<'db>, + results: &mut Vec<(BorrowckResult<'db>, &'db MirBody<'db>)>, + cb: &mut impl FnMut( + &'db MirBody<'db>, + Either, InternedClosureId<'db>>, + ) -> BorrowckResult<'db>, merge_from_closures: &mut impl FnMut( - (&mut BorrowckResult, &'db MirBody), - (&BorrowckResult, &'db MirBody), + (&mut BorrowckResult<'db>, &'db MirBody<'db>), + (&BorrowckResult<'db>, &'db MirBody<'db>), ), - ) -> Result<(), MirLowerError> { + ) -> Result<(), MirLowerError<'db>> { match db.mir_body_for_closure(c) { Ok(body) => { let parent_index = results.len(); @@ -108,8 +115,11 @@ fn all_mir_bodies<'db>( } fn merge<'db>( - results: &mut [(BorrowckResult, &'db MirBody)], - merge: &mut impl FnMut((&mut BorrowckResult, &'db MirBody), (&BorrowckResult, &'db MirBody)), + results: &mut [(BorrowckResult<'db>, &'db MirBody<'db>)], + merge: &mut impl FnMut( + (&mut BorrowckResult<'db>, &'db MirBody<'db>), + (&BorrowckResult<'db>, &'db MirBody<'db>), + ), parent_index: usize, ) { let (parent_and_before, children) = results.split_at_mut(parent_index + 1); @@ -133,15 +143,18 @@ fn all_mir_bodies<'db>( } } -impl InferBodyId { - pub fn borrowck(self, db: &dyn HirDatabase) -> Result<&[BorrowckResult], MirLowerError> { +impl<'db> InferBodyId<'db> { + pub fn borrowck( + self, + db: &'db dyn HirDatabase, + ) -> Result<&'db [BorrowckResult<'db>], MirLowerError<'db>> { return borrowck_query(db, self).map_err(|e| e.clone()); #[salsa::tracked(returns(as_deref), lru = 2024)] - fn borrowck_query( - db: &dyn HirDatabase, - def: InferBodyId, - ) -> Result, MirLowerError> { + fn borrowck_query<'db>( + db: &'db dyn HirDatabase, + def: InferBodyId<'db>, + ) -> Result]>, MirLowerError<'db>> { let _p = tracing::info_span!("InferBodyId::borrowck").entered(); let module = def.module(db); let interner = DbInterner::new_with(db, module.krate(db)); @@ -198,7 +211,7 @@ impl InferBodyId { fn moved_out_of_ref<'db>( infcx: &InferCtxt<'db>, env: ParamEnv<'db>, - body: &MirBody, + body: &MirBody<'db>, ) -> Vec { let db = infcx.interner.db; let mut result = vec![]; @@ -293,7 +306,7 @@ fn moved_out_of_ref<'db>( fn partially_moved<'db>( infcx: &InferCtxt<'db>, env: ParamEnv<'db>, - body: &MirBody, + body: &MirBody<'db>, ) -> Vec { let db = infcx.interner.db; let mut result = vec![]; @@ -375,7 +388,7 @@ fn partially_moved<'db>( result } -fn borrow_regions(db: &dyn HirDatabase, body: &MirBody) -> Vec { +fn borrow_regions<'db>(db: &'db dyn HirDatabase, body: &MirBody<'db>) -> Vec { let mut borrows = FxHashMap::default(); for (_, block) in body.basic_blocks.iter() { db.unwind_if_revision_cancelled(); @@ -428,7 +441,7 @@ enum ProjectionCase { fn place_case<'db>( infcx: &InferCtxt<'db>, env: ParamEnv<'db>, - body: &MirBody, + body: &MirBody<'db>, lvalue: &Place, ) -> ProjectionCase { let mut is_part_of = false; @@ -455,13 +468,13 @@ fn place_case<'db>( /// `Uninit` and `drop` and similar after initialization. fn ever_initialized_map( db: &dyn HirDatabase, - body: &MirBody, + body: &MirBody<'_>, ) -> ArenaMap> { let mut result: ArenaMap> = body.basic_blocks.iter().map(|it| (it.0, ArenaMap::default())).collect(); fn dfs( db: &dyn HirDatabase, - body: &MirBody, + body: &MirBody<'_>, l: LocalId, stack: &mut Vec, result: &mut ArenaMap>, @@ -574,7 +587,7 @@ fn record_usage_for_operand(arg: &Operand, result: &mut ArenaMap( infcx: &InferCtxt<'db>, env: ParamEnv<'db>, - body: &MirBody, + body: &MirBody<'db>, ) -> ArenaMap { let db = infcx.interner.db; let mut result: ArenaMap = 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 b968f33e81d0d..ab60e81646c26 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 @@ -2,7 +2,7 @@ use std::{borrow::Cow, cell::RefCell, fmt::Write, iter, mem, ops::Range}; -use base_db::{Crate, target::TargetLoadError}; +use base_db::{Crate, salsa::update_fallback_db, target::TargetLoadError}; use either::Either; use hir_def::{ AdtId, DefWithBodyId, EnumVariantId, FunctionId, HasModule, ItemContainerId, Lookup, StaticId, @@ -31,6 +31,7 @@ use rustc_type_ir::{ AliasTyKind, inherent::{GenericArgs as _, IntoKind, Region as _, SliceLike, Ty as _}, }; +use salsa::Update; use span::FileId; use stdx::never; use syntax::{SyntaxNodePtr, TextRange}; @@ -155,16 +156,16 @@ impl TlsData { } } -struct StackFrame<'a> { - locals: Locals<'a>, +struct StackFrame<'a, 'db> { + locals: Locals<'a, 'db>, destination: Option, prev_stack_ptr: usize, - span: (MirSpan, InferBodyId), + span: (MirSpan, InferBodyId<'db>), } #[derive(Clone)] -enum MirOrDynIndex<'a> { - Mir(&'a MirBody), +enum MirOrDynIndex<'db> { + Mir(&'db MirBody<'db>), Dyn(usize), } @@ -174,7 +175,7 @@ pub struct Evaluator<'a, 'db> { target_data_layout: &'db TargetDataLayout, stack: Vec, heap: Vec, - code_stack: Vec>, + code_stack: Vec>, /// Stores the global location of the statics. We const evaluate every static first time we need it /// and see it's missing, then we add it to this to reuse. static_locations: FxHashMap, @@ -189,11 +190,11 @@ pub struct Evaluator<'a, 'db> { layout_cache: RefCell, Arc>>, projected_ty_cache: RefCell, PlaceElem), PlaceTy<'db>>>, not_special_fn_cache: RefCell>, - mir_or_dyn_index_cache: RefCell), MirOrDynIndex<'a>>>, + mir_or_dyn_index_cache: RefCell), MirOrDynIndex<'db>>>, /// Constantly dropping and creating `Locals` is very costly. We store /// old locals that we normally want to drop here, to reuse their allocations /// later. - unused_locals_store: RefCell>>>, + unused_locals_store: RefCell, Vec>>>, cached_ptr_size: usize, cached_fn_trait_func: Option, cached_fn_mut_trait_func: Option, @@ -236,11 +237,11 @@ impl Interval { Self { addr, size } } - fn get<'b, 'a, 'db: 'a>(&self, memory: &'b Evaluator<'a, 'db>) -> Result<'db, &'b [u8]> { + fn get<'b, 'a, 'db>(&self, memory: &'b Evaluator<'a, 'db>) -> Result<'db, &'b [u8]> { memory.read_memory(self.addr, self.size) } - fn write_from_bytes<'a, 'db: 'a>( + fn write_from_bytes<'a, 'db>( &self, memory: &mut Evaluator<'a, 'db>, bytes: &[u8], @@ -248,7 +249,7 @@ impl Interval { memory.write_memory(self.addr, bytes) } - fn write_from_interval<'a, 'db: 'a>( + fn write_from_interval<'a, 'db>( &self, memory: &mut Evaluator<'a, 'db>, interval: Interval, @@ -262,10 +263,7 @@ impl Interval { } impl<'db> IntervalAndTy<'db> { - fn get<'b, 'a>(&self, memory: &'b Evaluator<'a, 'db>) -> Result<'db, &'b [u8]> - where - 'db: 'a, - { + fn get<'b, 'a>(&self, memory: &'b Evaluator<'a, 'db>) -> Result<'db, &'b [u8]> { memory.read_memory(self.interval.addr, self.interval.size) } @@ -273,11 +271,8 @@ impl<'db> IntervalAndTy<'db> { addr: Address, ty: Ty<'db>, evaluator: &Evaluator<'a, 'db>, - locals: &Locals<'a>, - ) -> Result<'db, IntervalAndTy<'db>> - where - 'db: 'a, - { + locals: &Locals<'a, 'db>, + ) -> Result<'db, IntervalAndTy<'db>> { let size = evaluator.size_of_sized(ty, locals, "type of interval")?; Ok(IntervalAndTy { interval: Interval { addr, size }, ty }) } @@ -295,7 +290,7 @@ impl From for IntervalOrOwned { } impl IntervalOrOwned { - fn get<'b, 'a, 'db: 'a>(&'b self, memory: &'b Evaluator<'a, 'db>) -> Result<'db, &'b [u8]> { + fn get<'b, 'a, 'db>(&'b self, memory: &'b Evaluator<'a, 'db>) -> Result<'db, &'b [u8]> { Ok(match self { IntervalOrOwned::Owned(o) => o, IntervalOrOwned::Borrowed(b) => b.get(memory)?, @@ -354,9 +349,9 @@ impl Address { } } -#[derive(Clone, PartialEq, Eq)] -pub enum MirEvalError { - ConstEvalError(String, Box), +#[derive(Clone, PartialEq, Eq, Update)] +pub enum MirEvalError<'db> { + ConstEvalError(String, Box>), LayoutError(LayoutError, StoredTy), TargetDataLayoutNotAvailable(TargetLoadError), /// Means that code had undefined behavior. We don't try to actively detect UB, but if it was detected @@ -364,14 +359,15 @@ pub enum MirEvalError { UndefinedBehavior(String), Panic(String), // FIXME: This should be folded into ConstEvalError? - MirLowerError(FunctionId, MirLowerError), - MirLowerErrorForClosure(InternedClosureId, MirLowerError), + MirLowerError(FunctionId, MirLowerError<'db>), + MirLowerErrorForClosure(InternedClosureId<'db>, MirLowerError<'db>), TypeIsUnsized(StoredTy, &'static str), NotSupported(String), InvalidConst, InFunction( - Box, - Vec<(Either, MirSpan, InferBodyId)>, + Box>, + #[update(bounds(InternedClosureId<'db>: Update), unsafe(with(update_fallback_db::<'db, _>)))] + Vec<(Either>, MirSpan, InferBodyId<'db>)>, ), ExecutionLimitExceeded, StackOverflow, @@ -383,7 +379,7 @@ pub enum MirEvalError { InternalError(Box), } -impl MirEvalError { +impl MirEvalError<'_> { pub fn pretty_print( &self, f: &mut String, @@ -420,18 +416,18 @@ impl MirEvalError { (store, None) } }; - let span: InFile = match span { - MirSpan::ExprId(e) => match source_map.expr_syntax(*e) { + let span: InFile = match *span { + MirSpan::ExprId(e) => match source_map.expr_syntax(e) { Ok(s) => s.map(|it| it.into()), Err(_) => continue, }, - MirSpan::PatId(p) => match source_map.pat_syntax(*p) { + MirSpan::PatId(p) => match source_map.pat_syntax(p) { Ok(s) => s.map(|it| it.syntax_node_ptr()), Err(_) => continue, }, MirSpan::BindingId(b) => { match source_map - .patterns_for_binding(*b) + .patterns_for_binding(b) .iter() .find_map(|p| source_map.pat_syntax(*p).ok()) { @@ -525,7 +521,7 @@ impl MirEvalError { } } -impl std::fmt::Debug for MirEvalError { +impl std::fmt::Debug for MirEvalError<'_> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Self::ConstEvalError(arg0, arg1) => { @@ -564,7 +560,7 @@ impl std::fmt::Debug for MirEvalError { } } -type Result<'db, T> = std::result::Result; +type Result<'db, T> = std::result::Result>; #[derive(Debug, Default)] struct DropFlags<'db> { @@ -595,9 +591,9 @@ impl<'db> DropFlags<'db> { } #[derive(Debug)] -struct Locals<'a> { +struct Locals<'a, 'db> { ptr: ArenaMap, - body: &'a MirBody, + body: &'db MirBody<'db>, drop_flags: DropFlags<'a>, } @@ -615,9 +611,9 @@ impl MirOutput { } } -pub fn interpret_mir<'a, 'db: 'a>( +pub fn interpret_mir<'db>( db: &'db dyn HirDatabase, - body: &MirBody, + body: &'db MirBody<'db>, // FIXME: This is workaround. Ideally, const generics should have a separate body (issue #7434), but now // they share their body with their parent, so in MIR lowering we have locals of the parent body, which // might have placeholders. With this argument, we (wrongly) assume that every placeholder type has @@ -657,10 +653,10 @@ const EXECUTION_LIMIT: usize = 100_000; #[cfg(not(test))] const EXECUTION_LIMIT: usize = 10_000_000; -impl<'a, 'db: 'a> Evaluator<'a, 'db> { +impl<'a, 'db> Evaluator<'a, 'db> { pub fn new( db: &'db dyn HirDatabase, - owner: InferBodyId, + owner: InferBodyId<'db>, assert_placeholder_ty_is_unused: bool, trait_env: Option>, ) -> Result<'db, Evaluator<'a, 'db>> { @@ -718,11 +714,11 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { self.infcx.interner.lang_items() } - fn place_addr(&self, p: &Place, locals: &Locals<'a>) -> Result<'db, Address> { + fn place_addr(&self, p: &Place, locals: &Locals<'a, 'db>) -> Result<'db, Address> { Ok(self.place_addr_and_ty_and_metadata(p, locals)?.0) } - fn place_interval(&self, p: &Place, locals: &Locals<'a>) -> Result<'db, Interval> { + fn place_interval(&self, p: &Place, locals: &Locals<'a, 'db>) -> Result<'db, Interval> { let place_addr_and_ty = self.place_addr_and_ty_and_metadata(p, locals)?; Ok(Interval { addr: place_addr_and_ty.0, @@ -738,7 +734,7 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { self.cached_ptr_size } - fn caller_location_fields(&self, owner: InferBodyId, span: MirSpan) -> (String, u32, u32) { + fn caller_location_fields(&self, owner: InferBodyId<'db>, span: MirSpan) -> (String, u32, u32) { let Some((file_id, text_range)) = self.resolve_mir_span(owner, span) else { return (String::new(), 0, 0); }; @@ -749,7 +745,11 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { (path.unwrap_or_default(), line + 1, col + 1) } - fn resolve_mir_span(&self, owner: InferBodyId, span: MirSpan) -> Option<(FileId, TextRange)> { + fn resolve_mir_span( + &self, + owner: InferBodyId<'db>, + span: MirSpan, + ) -> Option<(FileId, TextRange)> { let (source_map, self_param_syntax) = match owner { InferBodyId::DefWithBodyId(def) => { let body = &Body::with_source_map(self.db, def).1; @@ -788,7 +788,7 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { fn place_addr_and_ty_and_metadata<'b>( &'b self, p: &Place, - locals: &'b Locals<'a>, + locals: &'b Locals<'a, 'db>, ) -> Result<'db, (Address, Ty<'db>, Option)> { let mut addr = locals.ptr[p.local].addr; let mut ty = PlaceTy::from_ty(locals.body.locals[p.local].ty.as_ref()); @@ -909,11 +909,11 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { self.layout(Ty::new_adt(self.interner(), adt, subst)) } - fn place_ty<'b>(&'b self, p: &Place, locals: &'b Locals<'a>) -> Result<'db, Ty<'db>> { + fn place_ty<'b>(&'b self, p: &Place, locals: &'b Locals<'a, 'db>) -> Result<'db, Ty<'db>> { Ok(self.place_addr_and_ty_and_metadata(p, locals)?.1) } - fn operand_ty(&self, o: &Operand, locals: &Locals<'a>) -> Result<'db, Ty<'db>> { + fn operand_ty(&self, o: &Operand, locals: &Locals<'a, 'db>) -> Result<'db, Ty<'db>> { Ok(match &o.kind { OperandKind::Copy(p) | OperandKind::Move(p) => self.place_ty(p, locals)?, OperandKind::Constant { konst: _, ty } => ty.as_ref(), @@ -934,7 +934,7 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { fn operand_ty_and_eval( &mut self, o: &Operand, - locals: &mut Locals<'a>, + locals: &mut Locals<'a, 'db>, ) -> Result<'db, IntervalAndTy<'db>> { Ok(IntervalAndTy { interval: self.eval_operand(o, locals)?, @@ -944,7 +944,7 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { fn interpret_mir( &mut self, - body: &'a MirBody, + body: &'db MirBody<'db>, args: impl Iterator, ) -> Result<'db, Interval> { if let Some(it) = self.stack_depth_limit.checked_sub(1) { @@ -1106,8 +1106,8 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { fn fill_locals_for_body( &mut self, - body: &MirBody, - locals: &mut Locals<'a>, + body: &'db MirBody<'db>, + locals: &mut Locals<'a, 'db>, args: impl Iterator, ) -> Result<'db, ()> { let mut remain_args = body.param_locals.len(); @@ -1130,9 +1130,9 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { fn create_locals_for_body( &mut self, - body: &'a MirBody, + body: &'db MirBody<'db>, destination: Option, - ) -> Result<'db, (Locals<'a>, usize)> { + ) -> Result<'db, (Locals<'a, 'db>, usize)> { let mut locals = match self.unused_locals_store.borrow_mut().entry(body.owner).or_default().pop() { None => Locals { ptr: ArenaMap::new(), body, drop_flags: DropFlags::default() }, @@ -1175,7 +1175,11 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { Ok((locals, prev_stack_pointer)) } - fn eval_rvalue(&mut self, r: &Rvalue, locals: &mut Locals<'a>) -> Result<'db, IntervalOrOwned> { + fn eval_rvalue( + &mut self, + r: &Rvalue, + locals: &mut Locals<'a, 'db>, + ) -> Result<'db, IntervalOrOwned> { use IntervalOrOwned::*; Ok(match r { Rvalue::Use(it) => Borrowed(self.eval_operand(it, locals)?), @@ -1840,7 +1844,7 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { &mut self, it: VariantId, subst: GenericArgs<'db>, - locals: &Locals<'a>, + locals: &Locals<'a, 'db>, ) -> Result<'db, (usize, Arc, Option<(usize, usize, i128)>)> { let adt = it.adt_id(self.db); if let Some(f) = locals.body.owner.as_variant() @@ -1933,7 +1937,11 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { Ok(result) } - fn eval_operand(&mut self, it: &Operand, locals: &mut Locals<'a>) -> Result<'db, Interval> { + fn eval_operand( + &mut self, + it: &Operand, + locals: &mut Locals<'a, 'db>, + ) -> Result<'db, Interval> { Ok(match &it.kind { OperandKind::Copy(p) | OperandKind::Move(p) => { locals.drop_flags.remove_place(p.as_ref()); @@ -2096,7 +2104,7 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { #[allow(clippy::double_parens)] fn allocate_const_in_heap( &mut self, - locals: &Locals<'a>, + locals: &Locals<'a, 'db>, konst: Const<'db>, ) -> Result<'db, Interval> { match konst.kind() { @@ -2138,7 +2146,7 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { fn allocate_allocation_in_heap( &mut self, - locals: &Locals<'a>, + locals: &Locals<'a, 'db>, allocation: Allocation<'db>, ) -> Result<'db, Interval> { let AllocationData { ty, memory: ref v, ref memory_map } = *allocation; @@ -2177,7 +2185,7 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { Ok(Interval::new(addr, size)) } - fn eval_place(&mut self, p: &Place, locals: &Locals<'a>) -> Result<'db, Interval> { + fn eval_place(&mut self, p: &Place, locals: &Locals<'a, 'db>) -> Result<'db, Interval> { let addr = self.place_addr(p, locals)?; Ok(Interval::new( addr, @@ -2280,7 +2288,7 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { fn size_align_of( &self, ty: Ty<'db>, - locals: &Locals<'a>, + locals: &Locals<'a, 'db>, ) -> Result<'db, Option<(usize, usize)>> { if let Some(layout) = self.layout_cache.borrow().get(&ty) { return Ok(layout @@ -2310,7 +2318,7 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { fn size_of_sized( &self, ty: Ty<'db>, - locals: &Locals<'a>, + locals: &Locals<'a, 'db>, what: &'static str, ) -> Result<'db, usize> { match self.size_align_of(ty, locals)? { @@ -2324,7 +2332,7 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { fn size_align_of_sized( &self, ty: Ty<'db>, - locals: &Locals<'a>, + locals: &Locals<'a, 'db>, what: &'static str, ) -> Result<'db, (usize, usize)> { match self.size_align_of(ty, locals)? { @@ -2365,13 +2373,13 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { &self, bytes: &[u8], ty: Ty<'db>, - locals: &Locals<'a>, + locals: &Locals<'a, 'db>, ) -> Result<'db, ComplexMemoryMap<'db>> { - fn rec<'a, 'db: 'a>( + fn rec<'a, 'db>( this: &Evaluator<'a, 'db>, bytes: &[u8], ty: Ty<'db>, - locals: &Locals<'a>, + locals: &Locals<'a, 'db>, mm: &mut ComplexMemoryMap<'db>, stack_depth_limit: usize, ) -> Result<'db, ()> { @@ -2546,7 +2554,7 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { ty_of_bytes: impl Fn(&[u8]) -> Result<'db, Ty<'db>> + Copy, addr: Address, ty: Ty<'db>, - locals: &Locals<'a>, + locals: &Locals<'a, 'db>, ) -> Result<'db, ()> { // FIXME: support indirect references let layout = self.layout(ty)?; @@ -2678,10 +2686,10 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { bytes: Interval, destination: Interval, args: &[IntervalAndTy<'db>], - locals: &Locals<'a>, + locals: &Locals<'a, 'db>, target_bb: Option, span: MirSpan, - ) -> Result<'db, Option>> { + ) -> Result<'db, Option>> { let id = from_bytes!(usize, bytes.get(self)?); let next_ty = self.vtable_map.ty(id)?; use rustc_type_ir::TyKind; @@ -2704,14 +2712,14 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { fn exec_closure( &mut self, - closure: InternedClosureId, + closure: InternedClosureId<'db>, closure_data: Interval, generic_args: GenericArgs<'db>, destination: Interval, args: &[IntervalAndTy<'db>], - locals: &Locals<'a>, + locals: &Locals<'a, 'db>, span: MirSpan, - ) -> Result<'db, Option>> { + ) -> Result<'db, Option>> { let mir_body = self .db .monomorphized_mir_body_for_closure( @@ -2747,10 +2755,10 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { generic_args: GenericArgs<'db>, destination: Interval, args: &[IntervalAndTy<'db>], - locals: &Locals<'a>, + locals: &Locals<'a, 'db>, target_bb: Option, span: MirSpan, - ) -> Result<'db, Option>> { + ) -> Result<'db, Option>> { match def { CallableDefId::FunctionId(def) => { if self.detect_fn_trait(def).is_some() { @@ -2805,9 +2813,9 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { &self, def: FunctionId, generic_args: GenericArgs<'db>, - locals: &Locals<'a>, + locals: &Locals<'a, 'db>, span: MirSpan, - ) -> Result<'db, MirOrDynIndex<'a>> { + ) -> Result<'db, MirOrDynIndex<'db>> { let pair = (def, generic_args); if let Some(r) = self.mir_or_dyn_index_cache.borrow().get(&pair) { return Ok(r.clone()); @@ -2847,11 +2855,11 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { mut def: FunctionId, args: &[IntervalAndTy<'db>], generic_args: GenericArgs<'db>, - locals: &Locals<'a>, + locals: &Locals<'a, 'db>, destination: Interval, target_bb: Option, span: MirSpan, - ) -> Result<'db, Option>> { + ) -> Result<'db, Option>> { if self.detect_and_exec_special_function( def, args, @@ -2913,20 +2921,20 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { fn exec_looked_up_function( &mut self, - mir_body: &'a MirBody, - locals: &Locals<'a>, + mir_body: &'db MirBody<'db>, + locals: &Locals<'a, 'db>, def: FunctionId, arg_bytes: impl Iterator, span: MirSpan, destination: Interval, target_bb: Option, - ) -> Result<'db, Option>> { - Ok(if let Some(target_bb) = target_bb { + ) -> Result<'db, Option>> { + if let Some(target_bb) = target_bb { let (mut locals, prev_stack_ptr) = self.create_locals_for_body(mir_body, Some(destination))?; self.fill_locals_for_body(mir_body, &mut locals, arg_bytes.into_iter())?; let span = (span, locals.body.owner); - Some(StackFrame { locals, destination: Some(target_bb), prev_stack_ptr, span }) + Ok(Some(StackFrame { locals, destination: Some(target_bb), prev_stack_ptr, span })) } else { let result = self.interpret_mir(mir_body, arg_bytes).map_err(|e| { MirEvalError::InFunction( @@ -2935,8 +2943,8 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { ) })?; destination.write_from_interval(self, result)?; - None - }) + Ok(None) + } } fn exec_fn_trait( @@ -2944,11 +2952,11 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { def: FunctionId, args: &[IntervalAndTy<'db>], generic_args: GenericArgs<'db>, - locals: &Locals<'a>, + locals: &Locals<'a, 'db>, destination: Interval, target_bb: Option, span: MirSpan, - ) -> Result<'db, Option>> { + ) -> Result<'db, Option>> { let func = args .first() .ok_or_else(|| MirEvalError::InternalError("fn trait with no arg".into()))?; @@ -3013,7 +3021,7 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { } } - fn eval_static(&mut self, st: StaticId, locals: &Locals<'a>) -> Result<'db, Address> { + fn eval_static(&mut self, st: StaticId, locals: &Locals<'a, 'db>) -> Result<'db, Address> { if let Some(o) = self.static_locations.get(&st) { return Ok(*o); }; @@ -3063,7 +3071,7 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { fn drop_place( &mut self, place: &Place, - locals: &mut Locals<'a>, + locals: &mut Locals<'a, 'db>, span: MirSpan, ) -> Result<'db, ()> { let (addr, ty, metadata) = self.place_addr_and_ty_and_metadata(place, locals)?; @@ -3080,7 +3088,7 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { fn run_drop_glue_deep( &mut self, ty: Ty<'db>, - locals: &Locals<'a>, + locals: &Locals<'a, 'db>, addr: Address, metadata: &[u8], span: MirSpan, @@ -3199,7 +3207,7 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { pub fn render_const_using_debug_impl<'db>( db: &'db dyn HirDatabase, - owner: InferBodyId, + owner: InferBodyId<'db>, c: Allocation<'db>, ty: Ty<'db>, ) -> Result<'db, String> { 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 d2a74f20a5626..9db6b365886c1 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 @@ -28,13 +28,13 @@ enum EvalLangItem { DropInPlace, } -impl<'a, 'db: 'a> Evaluator<'a, 'db> { +impl<'a, 'db> Evaluator<'a, 'db> { pub(super) fn detect_and_exec_special_function( &mut self, def: FunctionId, args: &[IntervalAndTy<'db>], generic_args: GenericArgs<'db>, - locals: &Locals<'a>, + locals: &Locals<'a, 'db>, destination: Interval, span: MirSpan, ) -> Result<'db, bool> { @@ -133,7 +133,7 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { def: FunctionId, args: &[IntervalAndTy<'db>], self_ty: Ty<'db>, - locals: &Locals<'a>, + locals: &Locals<'a, 'db>, destination: Interval, span: MirSpan, ) -> Result<'db, ()> { @@ -191,7 +191,7 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { layout: Arc, addr: Address, def: FunctionId, - locals: &Locals<'a>, + locals: &Locals<'a, 'db>, destination: Interval, span: MirSpan, ) -> Result<'db, ()> { @@ -297,7 +297,7 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { it: EvalLangItem, generic_args: GenericArgs<'db>, args: &[IntervalAndTy<'db>], - locals: &Locals<'a>, + locals: &Locals<'a, 'db>, span: MirSpan, ) -> Result<'db, Vec> { use EvalLangItem::*; @@ -369,7 +369,7 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { id: i64, args: &[IntervalAndTy<'db>], destination: Interval, - _locals: &Locals<'a>, + _locals: &Locals<'a, 'db>, _span: MirSpan, ) -> Result<'db, ()> { match id { @@ -400,7 +400,7 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { args: &[IntervalAndTy<'db>], _generic_args: GenericArgs<'db>, destination: Interval, - locals: &Locals<'a>, + locals: &Locals<'a, 'db>, span: MirSpan, ) -> Result<'db, ()> { match as_str { @@ -564,7 +564,7 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { args: &[IntervalAndTy<'db>], generic_args: GenericArgs<'db>, destination: Interval, - locals: &Locals<'a>, + locals: &Locals<'a, 'db>, span: MirSpan, needs_override: bool, ) -> Result<'db, bool> { @@ -1425,7 +1425,7 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { &mut self, ty: Ty<'db>, metadata: Interval, - locals: &Locals<'a>, + locals: &Locals<'a, 'db>, ) -> Result<'db, (usize, usize)> { Ok(match ty.kind() { TyKind::Str => (from_bytes!(usize, metadata.get(self)?), 1), @@ -1485,7 +1485,7 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { args: &[IntervalAndTy<'db>], generic_args: GenericArgs<'db>, destination: Interval, - locals: &Locals<'a>, + locals: &Locals<'a, 'db>, _span: MirSpan, ) -> Result<'db, ()> { // We are a single threaded runtime with no UB checking and no optimization, so 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 a9d0bee623254..ff16ea68704d6 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 @@ -6,7 +6,7 @@ use crate::consteval::try_const_usize; use super::*; -impl<'a, 'db: 'a> Evaluator<'a, 'db> { +impl<'a, 'db> Evaluator<'a, 'db> { fn detect_simd_ty(&self, ty: Ty<'db>) -> Result<'db, (usize, Ty<'db>)> { match ty.kind() { TyKind::Adt(adt_def, subst) => { @@ -54,7 +54,7 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { args: &[IntervalAndTy<'db>], _generic_args: GenericArgs<'db>, destination: Interval, - _locals: &Locals<'a>, + _locals: &Locals<'a, 'db>, _span: MirSpan, ) -> Result<'db, ()> { match name { 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 622519445c69b..68d19769d4811 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 @@ -15,7 +15,7 @@ use crate::{ use super::{MirEvalError, interpret_mir}; -fn eval_main(db: &TestDB, file_id: EditionedFileId) -> Result<(String, String), MirEvalError> { +fn eval_main(db: &TestDB, file_id: EditionedFileId) -> Result<(String, String), MirEvalError<'_>> { crate::attach_db(db, || { let interner = DbInterner::new_no_crate(db); let module_id = db.module_for_file(file_id.file_id(db)); @@ -123,7 +123,7 @@ fn check_panic(#[rust_analyzer::rust_fixture] ra_fixture: &str, expected_panic: fn check_error_with( #[rust_analyzer::rust_fixture] ra_fixture: &str, - expect_err: impl FnOnce(MirEvalError) -> bool, + expect_err: impl FnOnce(MirEvalError<'_>) -> bool, ) { let (db, file_ids) = TestDB::with_many_files(ra_fixture); crate::attach_db(&db, || { 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 8cc59ecd0c1eb..b105cc7ba25e4 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 @@ -23,6 +23,7 @@ use la_arena::{ArenaMap, RawIdx}; use rustc_apfloat::Float; use rustc_hash::FxHashMap; use rustc_type_ir::inherent::{Const as _, GenericArgs as _, IntoKind, Ty as _}; +use salsa::Update; use span::{Edition, FileId}; use syntax::TextRange; @@ -80,15 +81,15 @@ struct DropScope { } struct MirLowerCtx<'a, 'db> { - result: MirBody, - owner: InferBodyId, + result: MirBody<'db>, + owner: InferBodyId<'db>, store_owner: ExpressionStoreOwnerId, current_loop_blocks: Option, labeled_loop_blocks: FxHashMap, discr_temp: Option, db: &'db dyn HirDatabase, store: &'a ExpressionStore, - infer: &'a InferenceResult, + infer: &'a InferenceResult<'db>, types: &'db crate::next_solver::DefaultAny<'db>, resolver: Resolver<'db>, drop_scopes: Vec, @@ -97,9 +98,9 @@ struct MirLowerCtx<'a, 'db> { } // FIXME: Make this smaller, its stored in database queries -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum MirLowerError { - ConstEvalError(Box, Box), +#[derive(Debug, Clone, PartialEq, Eq, Update)] +pub enum MirLowerError<'db> { + ConstEvalError(Box, Box>), LayoutError(LayoutError), IncompleteExpr, IncompletePattern, @@ -110,7 +111,7 @@ pub enum MirLowerError { UnresolvedMethod(String), UnresolvedField, UnsizedTemporary(StoredTy), - MissingFunctionDefinition(InferBodyId, ExprId), + MissingFunctionDefinition(InferBodyId<'db>, ExprId), HasErrors, /// This should never happen. Type mismatch should catch everything. TypeError(&'static str), @@ -168,7 +169,7 @@ impl Drop for DropScopeToken { // } // } -impl MirLowerError { +impl MirLowerError<'_> { pub fn pretty_print( &self, f: &mut String, @@ -265,13 +266,13 @@ macro_rules! implementation_error { }}; } -impl From for MirLowerError { +impl From for MirLowerError<'_> { fn from(value: LayoutError) -> Self { MirLowerError::LayoutError(value) } } -impl MirLowerError { +impl MirLowerError<'_> { fn unresolved_path( db: &dyn HirDatabase, p: &Path, @@ -285,14 +286,14 @@ impl MirLowerError { } } -type Result<'db, T> = std::result::Result; +type Result<'db, T> = std::result::Result>; impl<'a, 'db> MirLowerCtx<'a, 'db> { fn new( db: &'db dyn HirDatabase, - owner: InferBodyId, + owner: InferBodyId<'db>, store: &'a ExpressionStore, - infer: &'a InferenceResult, + infer: &'a InferenceResult<'db>, ) -> Self { let mut basic_blocks = Arena::new(); let start_block = basic_blocks.alloc(BasicBlock { @@ -1525,7 +1526,7 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { fn lower_const( &mut self, - const_id: GeneralConstId, + const_id: GeneralConstId<'db>, prev_block: BasicBlockId, place: PlaceRef<'db>, subst: GenericArgs<'db>, @@ -1539,7 +1540,7 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { fn lower_const_to_operand( &mut self, subst: GenericArgs<'db>, - const_id: GeneralConstId, + const_id: GeneralConstId<'db>, ) -> Result<'db, Operand> { let konst = Const::new_unevaluated( self.interner(), @@ -2126,8 +2127,8 @@ fn cast_kind<'db>( #[salsa_macros::tracked(returns(as_ref), cycle_result = mir_body_for_closure_cycle_result)] pub fn mir_body_for_closure_query<'db>( db: &'db dyn HirDatabase, - closure: InternedClosureId, -) -> Result<'db, MirBody> { + closure: InternedClosureId<'db>, +) -> Result<'db, MirBody<'db>> { let InternedClosure { owner: body_owner, expr, .. } = closure.loc(db); let store = ExpressionStore::of(db, body_owner.expression_store_owner(db)); let infer = InferenceResult::of(db, body_owner); @@ -2283,7 +2284,10 @@ pub fn mir_body_for_closure_query<'db>( } #[salsa_macros::tracked(returns(as_ref), cycle_result = mir_body_cycle_result)] -pub fn mir_body_query<'db>(db: &'db dyn HirDatabase, def: InferBodyId) -> Result<'db, MirBody> { +pub fn mir_body_query<'db>( + db: &'db dyn HirDatabase, + def: InferBodyId<'db>, +) -> Result<'db, MirBody<'db>> { let krate = def.krate(db); let edition = krate.data(db).edition; let detail = match def { @@ -2326,16 +2330,16 @@ pub fn mir_body_query<'db>(db: &'db dyn HirDatabase, def: InferBodyId) -> Result fn mir_body_cycle_result<'db>( _db: &'db dyn HirDatabase, _: salsa::Id, - _def: InferBodyId, -) -> Result<'db, MirBody> { + _def: InferBodyId<'db>, +) -> Result<'db, MirBody<'db>> { Err(MirLowerError::Loop) } fn mir_body_for_closure_cycle_result<'db>( _db: &'db dyn HirDatabase, _: salsa::Id, - _def: InternedClosureId, -) -> Result<'db, MirBody> { + _def: InternedClosureId<'db>, +) -> Result<'db, MirBody<'db>> { Err(MirLowerError::Loop) } @@ -2343,13 +2347,13 @@ fn mir_body_for_closure_cycle_result<'db>( /// then delegates to [`lower_to_mir_with_store`]. pub fn lower_body_to_mir<'db>( db: &'db dyn HirDatabase, - owner: InferBodyId, + owner: InferBodyId<'db>, store: &ExpressionStore, - infer: &InferenceResult, + infer: &InferenceResult<'db>, root_expr: ExprId, self_param: Option, params: &[Param], -) -> Result<'db, MirBody> { +) -> Result<'db, MirBody<'db>> { // Extract params and self_param only when lowering the body's root expression for a function. if let Some(fid) = owner.as_function() { let callable_sig = { @@ -2383,13 +2387,13 @@ pub fn lower_body_to_mir<'db>( /// const (picks bindings owned by `root_expr`). pub fn lower_to_mir_with_store<'db>( db: &'db dyn HirDatabase, - owner: InferBodyId, + owner: InferBodyId<'db>, store: &ExpressionStore, - infer: &InferenceResult, + infer: &InferenceResult<'db>, root_expr: ExprId, params: impl Iterator)> + Clone, self_param: Option<(BindingId, Ty<'db>)>, -) -> Result<'db, MirBody> { +) -> Result<'db, MirBody<'db>> { if infer.has_type_mismatches() || infer.is_erroneous() { return Err(MirLowerError::HasErrors); } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/monomorphization.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/monomorphization.rs index bcc86ba4bfd79..042dd076be75b 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/monomorphization.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/monomorphization.rs @@ -39,7 +39,7 @@ struct Filler<'db> { } impl<'db> FallibleTypeFolder> for Filler<'db> { - type Error = MirLowerError; + type Error = MirLowerError<'db>; fn cx(&self) -> DbInterner<'db> { self.infcx.interner @@ -106,7 +106,7 @@ impl<'db> Filler<'db> { Self { infcx, trait_env: env, subst } } - fn fill_ty(&mut self, t: &mut StoredTy) -> Result<(), MirLowerError> { + fn fill_ty(&mut self, t: &mut StoredTy) -> Result<(), MirLowerError<'db>> { // Can't deep normalized as that'll try to normalize consts and fail. *t = t.as_ref().try_fold_with(self)?.store(); if references_non_lt_error(&t.as_ref()) { @@ -116,7 +116,7 @@ impl<'db> Filler<'db> { } } - fn fill_const(&mut self, t: &mut StoredConst) -> Result<(), MirLowerError> { + fn fill_const(&mut self, t: &mut StoredConst) -> Result<(), MirLowerError<'db>> { // Can't deep normalized as that'll try to normalize consts and fail. *t = t.as_ref().try_fold_with(self)?.store(); if references_non_lt_error(&t.as_ref()) { @@ -126,7 +126,7 @@ impl<'db> Filler<'db> { } } - fn fill_args(&mut self, t: &mut StoredGenericArgs) -> Result<(), MirLowerError> { + fn fill_args(&mut self, t: &mut StoredGenericArgs) -> Result<(), MirLowerError<'db>> { // Can't deep normalized as that'll try to normalize consts and fail. *t = t.as_ref().try_fold_with(self)?.store(); if references_non_lt_error(&t.as_ref()) { @@ -136,7 +136,7 @@ impl<'db> Filler<'db> { } } - fn fill_operand(&mut self, op: &mut Operand) -> Result<(), MirLowerError> { + fn fill_operand(&mut self, op: &mut Operand) -> Result<(), MirLowerError<'db>> { match &mut op.kind { OperandKind::Constant { konst, ty } => { self.fill_const(konst)?; @@ -159,7 +159,7 @@ impl<'db> Filler<'db> { Ok(()) } - fn fill_body(&mut self, body: &mut MirBody) -> Result<(), MirLowerError> { + fn fill_body(&mut self, body: &mut MirBody<'db>) -> Result<(), MirLowerError<'db>> { for (_, l) in body.locals.iter_mut() { self.fill_ty(&mut l.ty)?; } @@ -239,49 +239,49 @@ impl<'db> Filler<'db> { } #[salsa_macros::tracked(returns(as_ref), cycle_result = monomorphized_mir_body_cycle_result)] -pub fn monomorphized_mir_body_query( - db: &dyn HirDatabase, - owner: InferBodyId, +pub fn monomorphized_mir_body_query<'db>( + db: &'db dyn HirDatabase, + owner: InferBodyId<'db>, subst: StoredGenericArgs, trait_env: StoredParamEnvAndCrate, -) -> Result { - let mut filler = Filler::new(db, trait_env.as_ref(), subst.as_ref()); +) -> Result, MirLowerError<'db>> { + let mut filler = Filler::new(db, trait_env.as_ref(db), subst.as_ref()); let body = db.mir_body(owner)?; let mut body = (*body).clone(); filler.fill_body(&mut body)?; Ok(body) } -fn monomorphized_mir_body_cycle_result( - _db: &dyn HirDatabase, +fn monomorphized_mir_body_cycle_result<'db>( + _db: &'db dyn HirDatabase, _: salsa::Id, - _: InferBodyId, + _: InferBodyId<'db>, _: StoredGenericArgs, _: StoredParamEnvAndCrate, -) -> Result { +) -> Result, MirLowerError<'db>> { Err(MirLowerError::Loop) } #[salsa_macros::tracked(returns(as_ref), cycle_result = monomorphized_mir_body_for_closure_cycle_result)] -pub fn monomorphized_mir_body_for_closure_query( - db: &dyn HirDatabase, - closure: InternedClosureId, +pub fn monomorphized_mir_body_for_closure_query<'db>( + db: &'db dyn HirDatabase, + closure: InternedClosureId<'db>, subst: StoredGenericArgs, trait_env: StoredParamEnvAndCrate, -) -> Result { - let mut filler = Filler::new(db, trait_env.as_ref(), subst.as_ref()); +) -> Result, MirLowerError<'db>> { + let mut filler = Filler::new(db, trait_env.as_ref(db), subst.as_ref()); let body = db.mir_body_for_closure(closure)?; let mut body = (*body).clone(); filler.fill_body(&mut body)?; Ok(body) } -fn monomorphized_mir_body_for_closure_cycle_result( - _db: &dyn HirDatabase, +fn monomorphized_mir_body_for_closure_cycle_result<'db>( + _db: &'db dyn HirDatabase, _: salsa::Id, - _: InternedClosureId, + _: InternedClosureId<'db>, _: StoredGenericArgs, _: StoredParamEnvAndCrate, -) -> Result { +) -> Result, MirLowerError<'db>> { Err(MirLowerError::Loop) } 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 3e414544241c4..8893069f0c0a2 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 @@ -43,7 +43,7 @@ macro_rules! wln { }; } -impl MirBody { +impl MirBody<'_> { pub fn pretty_print(&self, db: &dyn HirDatabase, display_target: DisplayTarget) -> String { let hir_body = ExpressionStore::of(db, self.owner.expression_store_owner(db)); let mut ctx = MirPrettyCtx::new(self, hir_body, db, display_target); @@ -100,7 +100,7 @@ impl MirBody { } struct MirPrettyCtx<'a, 'db> { - body: &'a MirBody, + body: &'a MirBody<'db>, hir_body: &'a ExpressionStore, db: &'db dyn HirDatabase, result: String, @@ -153,7 +153,7 @@ impl<'a, 'db> MirPrettyCtx<'a, 'db> { } } - fn for_closure(&mut self, closure: InternedClosureId) { + fn for_closure(&mut self, closure: InternedClosureId<'db>) { let body = match self.db.mir_body_for_closure(closure) { Ok(it) => it, Err(e) => { @@ -187,7 +187,7 @@ impl<'a, 'db> MirPrettyCtx<'a, 'db> { } fn new( - body: &'a MirBody, + body: &'a MirBody<'db>, hir_body: &'a ExpressionStore, db: &'db dyn HirDatabase, display_target: DisplayTarget, 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 f0d33ad2ddafc..42fd31f2594da 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 @@ -143,7 +143,7 @@ impl std::fmt::Debug for DefaultAny<'_> { } #[inline] -pub fn default_types<'a, 'db>(db: &'db dyn HirDatabase) -> &'a DefaultAny<'db> { +pub fn default_types<'db>(db: &'db dyn HirDatabase) -> &'db DefaultAny<'db> { static TYPES: OnceLock> = OnceLock::new(); let interner = DbInterner::new_no_crate(db); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/binder.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/binder.rs index 95f437165d045..9585cced6b114 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/binder.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/binder.rs @@ -1,5 +1,6 @@ use hir_def::TraitId; use macros::{TypeFoldable, TypeVisitable}; +use salsa::Update; use crate::next_solver::{ Binder, Clauses, DbInterner, EarlyBinder, FnSig, FnSigKind, GenericArg, PolyFnSig, @@ -7,7 +8,7 @@ use crate::next_solver::{ TraitRef, Ty, }; -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Update)] pub struct StoredEarlyBinder(T); impl StoredEarlyBinder { @@ -102,7 +103,7 @@ impl StoredPolyFnSig { } } -#[derive(Debug, Clone, PartialEq, Eq, Hash, TypeVisitable, TypeFoldable)] +#[derive(Debug, Clone, PartialEq, Eq, Hash, TypeVisitable, TypeFoldable, Update)] pub struct StoredTraitRef { #[type_visitable(ignore)] def_id: TraitId, 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 ce66dbc77c7eb..09b999ae5fe7a 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 @@ -10,6 +10,7 @@ use hir_def::{ }, }; use rustc_type_ir::inherent; +use salsa::Update; use stdx::impl_from; use crate::{ @@ -28,26 +29,26 @@ pub enum Ctor { Enum(EnumVariantId), } -#[derive(PartialOrd, Ord, Clone, Copy, PartialEq, Eq, Hash)] -pub enum SolverDefId { +#[derive(PartialOrd, Ord, Clone, Copy, PartialEq, Eq, Hash, Update)] +pub enum SolverDefId<'db> { AdtId(AdtId), ConstId(ConstId), FunctionId(FunctionId), ImplId(ImplId), BuiltinDeriveImplId(BuiltinDeriveImplId), StaticId(StaticId), - AnonConstId(AnonConstId), + AnonConstId(AnonConstId<'db>), TraitId(TraitId), TypeAliasId(TypeAliasId), - InternedClosureId(InternedClosureId), - InternedCoroutineId(InternedCoroutineId), - InternedCoroutineClosureId(InternedCoroutineClosureId), + InternedClosureId(InternedClosureId<'db>), + InternedCoroutineId(InternedCoroutineId<'db>), + InternedCoroutineClosureId(InternedCoroutineClosureId<'db>), InternedOpaqueTyId(InternedOpaqueTyId), EnumVariantId(EnumVariantId), Ctor(Ctor), } -impl std::fmt::Debug for SolverDefId { +impl std::fmt::Debug for SolverDefId<'_> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let interner = DbInterner::conjure(); let db = interner.db; @@ -121,26 +122,98 @@ impl std::fmt::Debug for SolverDefId { } } -impl_from!( - AdtId(StructId, EnumId, UnionId), - ConstId, - FunctionId, - ImplId, - BuiltinDeriveImplId, - StaticId, - AnonConstId, - TraitId, - TypeAliasId, - InternedClosureId, - InternedCoroutineId, - InternedCoroutineClosureId, - InternedOpaqueTyId, - EnumVariantId, - Ctor - for SolverDefId -); - -impl From for SolverDefId { +impl<'db> From for SolverDefId<'db> { + fn from(it: AdtId) -> SolverDefId<'db> { + SolverDefId::AdtId(it) + } +} +impl<'db> From for SolverDefId<'db> { + fn from(it: StructId) -> SolverDefId<'db> { + SolverDefId::AdtId(AdtId::StructId(it)) + } +} +impl<'db> From for SolverDefId<'db> { + fn from(it: EnumId) -> SolverDefId<'db> { + SolverDefId::AdtId(AdtId::EnumId(it)) + } +} +impl<'db> From for SolverDefId<'db> { + fn from(it: UnionId) -> SolverDefId<'db> { + SolverDefId::AdtId(AdtId::UnionId(it)) + } +} +impl<'db> From for SolverDefId<'db> { + fn from(it: ConstId) -> SolverDefId<'db> { + SolverDefId::ConstId(it) + } +} +impl<'db> From for SolverDefId<'db> { + fn from(it: FunctionId) -> SolverDefId<'db> { + SolverDefId::FunctionId(it) + } +} +impl<'db> From for SolverDefId<'db> { + fn from(it: ImplId) -> SolverDefId<'db> { + SolverDefId::ImplId(it) + } +} +impl<'db> From for SolverDefId<'db> { + fn from(it: BuiltinDeriveImplId) -> SolverDefId<'db> { + SolverDefId::BuiltinDeriveImplId(it) + } +} +impl<'db> From for SolverDefId<'db> { + fn from(it: StaticId) -> SolverDefId<'db> { + SolverDefId::StaticId(it) + } +} +impl<'db> From> for SolverDefId<'db> { + fn from(it: AnonConstId<'db>) -> SolverDefId<'db> { + SolverDefId::AnonConstId(it) + } +} +impl<'db> From for SolverDefId<'db> { + fn from(it: TraitId) -> SolverDefId<'db> { + SolverDefId::TraitId(it) + } +} +impl<'db> From for SolverDefId<'db> { + fn from(it: TypeAliasId) -> SolverDefId<'db> { + SolverDefId::TypeAliasId(it) + } +} +impl<'db> From> for SolverDefId<'db> { + fn from(it: InternedClosureId<'db>) -> SolverDefId<'db> { + SolverDefId::InternedClosureId(it) + } +} +impl<'db> From> for SolverDefId<'db> { + fn from(it: InternedCoroutineId<'db>) -> SolverDefId<'db> { + SolverDefId::InternedCoroutineId(it) + } +} +impl<'db> From> for SolverDefId<'db> { + fn from(it: InternedCoroutineClosureId<'db>) -> SolverDefId<'db> { + SolverDefId::InternedCoroutineClosureId(it) + } +} +impl<'db> From for SolverDefId<'db> { + fn from(it: InternedOpaqueTyId) -> SolverDefId<'db> { + SolverDefId::InternedOpaqueTyId(it) + } +} +impl<'db> From for SolverDefId<'db> { + fn from(it: EnumVariantId) -> SolverDefId<'db> { + SolverDefId::EnumVariantId(it) + } +} +impl<'db> From for SolverDefId<'db> { + fn from(it: Ctor) -> SolverDefId<'db> { + SolverDefId::Ctor(it) + } +} + +impl<'db> From for SolverDefId<'db> { fn from(value: GenericDefId) -> Self { match value { GenericDefId::AdtId(adt_id) => SolverDefId::AdtId(adt_id), @@ -154,9 +227,9 @@ impl From for SolverDefId { } } -impl From for SolverDefId { +impl<'db> From> for SolverDefId<'db> { #[inline] - fn from(value: GeneralConstId) -> Self { + fn from(value: GeneralConstId<'db>) -> Self { match value { GeneralConstId::ConstId(const_id) => SolverDefId::ConstId(const_id), GeneralConstId::StaticId(static_id) => SolverDefId::StaticId(static_id), @@ -165,7 +238,7 @@ impl From for SolverDefId { } } -impl From for SolverDefId { +impl<'db> From for SolverDefId<'db> { #[inline] fn from(value: CallableDefId) -> Self { match value { @@ -176,7 +249,7 @@ impl From for SolverDefId { } } -impl From for SolverDefId { +impl<'db> From for SolverDefId<'db> { #[inline] fn from(value: DefWithBodyId) -> Self { match value { @@ -188,9 +261,9 @@ impl From for SolverDefId { } } -impl From for SolverDefId { +impl<'db> From> for SolverDefId<'db> { #[inline] - fn from(value: InferBodyId) -> Self { + fn from(value: InferBodyId<'db>) -> Self { match value { InferBodyId::DefWithBodyId(id) => id.into(), InferBodyId::AnonConstId(id) => id.into(), @@ -198,7 +271,7 @@ impl From for SolverDefId { } } -impl From for SolverDefId { +impl<'db> From for SolverDefId<'db> { #[inline] fn from(value: VariantId) -> Self { match value { @@ -209,7 +282,7 @@ impl From for SolverDefId { } } -impl From for SolverDefId { +impl<'db> From for SolverDefId<'db> { #[inline] fn from(value: ExpressionStoreOwnerId) -> Self { match value { @@ -220,10 +293,10 @@ impl From for SolverDefId { } } -impl TryFrom for AttrDefId { +impl TryFrom> for AttrDefId { type Error = (); #[inline] - fn try_from(value: SolverDefId) -> Result { + fn try_from(value: SolverDefId<'_>) -> Result { match value { SolverDefId::AdtId(it) => Ok(it.into()), SolverDefId::ConstId(it) => Ok(it.into()), @@ -245,11 +318,11 @@ impl TryFrom for AttrDefId { } } -impl TryFrom for DefWithBodyId { +impl TryFrom> for DefWithBodyId { type Error = (); #[inline] - fn try_from(value: SolverDefId) -> Result { + fn try_from(value: SolverDefId<'_>) -> Result { let id = match value { SolverDefId::ConstId(id) => id.into(), SolverDefId::FunctionId(id) => id.into(), @@ -271,11 +344,11 @@ impl TryFrom for DefWithBodyId { } } -impl TryFrom for InferBodyId { +impl<'db> TryFrom> for InferBodyId<'db> { type Error = (); #[inline] - fn try_from(value: SolverDefId) -> Result { + fn try_from(value: SolverDefId<'db>) -> Result { let id = match value { SolverDefId::ConstId(id) => id.into(), SolverDefId::FunctionId(id) => id.into(), @@ -297,10 +370,10 @@ impl TryFrom for InferBodyId { } } -impl TryFrom for GenericDefId { +impl TryFrom> for GenericDefId { type Error = (); - fn try_from(value: SolverDefId) -> Result { + fn try_from(value: SolverDefId<'_>) -> Result { Ok(match value { SolverDefId::AdtId(adt_id) => GenericDefId::AdtId(adt_id), SolverDefId::ConstId(const_id) => GenericDefId::ConstId(const_id), @@ -321,8 +394,8 @@ impl TryFrom for GenericDefId { } } -impl<'db> inherent::DefId> for SolverDefId { - fn as_local(self) -> Option { +impl<'db> inherent::DefId> for SolverDefId<'db> { + fn as_local(self) -> Option> { Some(self) } fn is_local(self) -> bool { @@ -332,17 +405,17 @@ impl<'db> inherent::DefId> for SolverDefId { macro_rules! declare_id_wrapper { ($name:ident, $wraps:ident) => { - declare_id_wrapper!($name, $wraps, SolverDefId); + declare_id_wrapper!($name, $wraps, SolverDefId<'db>); }; - ($name:ident, $wraps:ident, $local:ident) => { + ($name:ident, $wraps:ident, $local:ty) => { declare_id_wrapper!($name, $wraps, $local, no_try_from); - impl TryFrom for $name { + impl TryFrom> for $name { type Error = (); #[inline] - fn try_from(value: SolverDefId) -> Result { + fn try_from(value: SolverDefId<'_>) -> Result { match value { SolverDefId::$wraps(it) => Ok(Self(it)), _ => Err(()), @@ -351,7 +424,7 @@ macro_rules! declare_id_wrapper { } }; - ($name:ident, $wraps:ident, $local:ident, no_try_from) => { + ($name:ident, $wraps:ident, $local:ty, no_try_from) => { #[derive(Clone, Copy, PartialEq, Eq, Hash)] pub struct $name(pub $wraps); @@ -375,9 +448,9 @@ macro_rules! declare_id_wrapper { } } - impl From<$name> for SolverDefId { + impl<'db> From<$name> for SolverDefId<'db> { #[inline] - fn from(value: $name) -> SolverDefId { + fn from(value: $name) -> SolverDefId<'db> { value.0.into() } } @@ -395,9 +468,158 @@ macro_rules! declare_id_wrapper { declare_id_wrapper!(TraitIdWrapper, TraitId); declare_id_wrapper!(TypeAliasIdWrapper, TypeAliasId); -declare_id_wrapper!(ClosureIdWrapper, InternedClosureId); -declare_id_wrapper!(CoroutineIdWrapper, InternedCoroutineId); -declare_id_wrapper!(CoroutineClosureIdWrapper, InternedCoroutineClosureId); +#[derive(Clone, Copy, PartialEq, Eq, Hash)] +pub struct ClosureIdWrapper<'db>(pub InternedClosureId<'db>); + +impl std::fmt::Debug for ClosureIdWrapper<'_> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Debug::fmt(&SolverDefId::from(self.0), f) + } +} + +impl<'db> From> for InternedClosureId<'db> { + #[inline] + fn from(value: ClosureIdWrapper<'db>) -> InternedClosureId<'db> { + value.0 + } +} + +impl<'db> From> for ClosureIdWrapper<'db> { + #[inline] + fn from(value: InternedClosureId<'db>) -> ClosureIdWrapper<'db> { + Self(value) + } +} + +impl<'db> From> for SolverDefId<'db> { + #[inline] + fn from(value: ClosureIdWrapper<'db>) -> SolverDefId<'db> { + value.0.into() + } +} + +impl<'db> TryFrom> for ClosureIdWrapper<'db> { + type Error = (); + + #[inline] + fn try_from(value: SolverDefId<'db>) -> Result { + match value { + SolverDefId::InternedClosureId(it) => Ok(Self(it)), + _ => Err(()), + } + } +} + +impl<'db> inherent::DefId, SolverDefId<'db>> for ClosureIdWrapper<'db> { + fn as_local(self) -> Option> { + Some(self.into()) + } + fn is_local(self) -> bool { + true + } +} + +#[derive(Clone, Copy, PartialEq, Eq, Hash)] +pub struct CoroutineIdWrapper<'db>(pub InternedCoroutineId<'db>); + +impl std::fmt::Debug for CoroutineIdWrapper<'_> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Debug::fmt(&SolverDefId::from(self.0), f) + } +} + +impl<'db> From> for InternedCoroutineId<'db> { + #[inline] + fn from(value: CoroutineIdWrapper<'db>) -> InternedCoroutineId<'db> { + value.0 + } +} + +impl<'db> From> for CoroutineIdWrapper<'db> { + #[inline] + fn from(value: InternedCoroutineId<'db>) -> CoroutineIdWrapper<'db> { + Self(value) + } +} + +impl<'db> From> for SolverDefId<'db> { + #[inline] + fn from(value: CoroutineIdWrapper<'db>) -> SolverDefId<'db> { + value.0.into() + } +} + +impl<'db> TryFrom> for CoroutineIdWrapper<'db> { + type Error = (); + + #[inline] + fn try_from(value: SolverDefId<'db>) -> Result { + match value { + SolverDefId::InternedCoroutineId(it) => Ok(Self(it)), + _ => Err(()), + } + } +} + +impl<'db> inherent::DefId, SolverDefId<'db>> for CoroutineIdWrapper<'db> { + fn as_local(self) -> Option> { + Some(self.into()) + } + fn is_local(self) -> bool { + true + } +} + +#[derive(Clone, Copy, PartialEq, Eq, Hash)] +pub struct CoroutineClosureIdWrapper<'db>(pub InternedCoroutineClosureId<'db>); + +impl std::fmt::Debug for CoroutineClosureIdWrapper<'_> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Debug::fmt(&SolverDefId::from(self.0), f) + } +} + +impl<'db> From> for InternedCoroutineClosureId<'db> { + #[inline] + fn from(value: CoroutineClosureIdWrapper<'db>) -> InternedCoroutineClosureId<'db> { + value.0 + } +} + +impl<'db> From> for CoroutineClosureIdWrapper<'db> { + #[inline] + fn from(value: InternedCoroutineClosureId<'db>) -> CoroutineClosureIdWrapper<'db> { + Self(value) + } +} + +impl<'db> From> for SolverDefId<'db> { + #[inline] + fn from(value: CoroutineClosureIdWrapper<'db>) -> SolverDefId<'db> { + value.0.into() + } +} + +impl<'db> TryFrom> for CoroutineClosureIdWrapper<'db> { + type Error = (); + + #[inline] + fn try_from(value: SolverDefId<'db>) -> Result { + match value { + SolverDefId::InternedCoroutineClosureId(it) => Ok(Self(it)), + _ => Err(()), + } + } +} + +impl<'db> inherent::DefId, SolverDefId<'db>> for CoroutineClosureIdWrapper<'db> { + fn as_local(self) -> Option> { + Some(self.into()) + } + fn is_local(self) -> bool { + true + } +} declare_id_wrapper!(AdtIdWrapper, AdtId); declare_id_wrapper!(OpaqueTyIdWrapper, InternedOpaqueTyId, OpaqueTyIdWrapper); @@ -405,13 +627,13 @@ macro_rules! declare_ty_const_pair { ( $ty_id_name:ident, $const_id_name:ident, $term_id_name:ident ) => { declare_id_wrapper!($ty_id_name, TypeAliasId); declare_id_wrapper!($const_id_name, ConstId); - declare_id_wrapper!($term_id_name, TermId, SolverDefId, no_try_from); + declare_id_wrapper!($term_id_name, TermId, SolverDefId<'db>, no_try_from); - impl TryFrom for $term_id_name { + impl TryFrom> for $term_id_name { type Error = (); #[inline] - fn try_from(value: SolverDefId) -> Result { + fn try_from(value: SolverDefId<'_>) -> Result { match value { SolverDefId::TypeAliasId(it) => Ok(Self(TermId::TypeAliasId(it))), SolverDefId::ConstId(it) => Ok(Self(TermId::ConstId(it))), @@ -454,7 +676,7 @@ macro_rules! declare_ty_const_pair { } } - impl From<$const_id_name> for GeneralConstIdWrapper { + impl<'db> From<$const_id_name> for GeneralConstIdWrapper<'db> { fn from(value: $const_id_name) -> Self { GeneralConstIdWrapper(GeneralConstId::ConstId(value.0)) } @@ -474,7 +696,7 @@ pub enum TermId { } impl_from!(TypeAliasId, ConstId for TermId); -impl From for SolverDefId { +impl<'db> From for SolverDefId<'db> { fn from(value: TermId) -> Self { match value { TermId::TypeAliasId(id) => id.into(), @@ -484,28 +706,28 @@ impl From for SolverDefId { } #[derive(Clone, Copy, PartialEq, Eq, Hash)] -pub struct GeneralConstIdWrapper(pub GeneralConstId); +pub struct GeneralConstIdWrapper<'db>(pub GeneralConstId<'db>); -impl std::fmt::Debug for GeneralConstIdWrapper { +impl std::fmt::Debug for GeneralConstIdWrapper<'_> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Debug::fmt(&self.0, f) } } -impl From for GeneralConstId { +impl<'db> From> for GeneralConstId<'db> { #[inline] - fn from(value: GeneralConstIdWrapper) -> GeneralConstId { + fn from(value: GeneralConstIdWrapper<'db>) -> GeneralConstId<'db> { value.0 } } -impl From for GeneralConstIdWrapper { +impl<'db> From> for GeneralConstIdWrapper<'db> { #[inline] - fn from(value: GeneralConstId) -> GeneralConstIdWrapper { + fn from(value: GeneralConstId<'db>) -> GeneralConstIdWrapper<'db> { Self(value) } } -impl From for SolverDefId { +impl<'db> From> for SolverDefId<'db> { #[inline] - fn from(value: GeneralConstIdWrapper) -> SolverDefId { + fn from(value: GeneralConstIdWrapper<'db>) -> SolverDefId<'db> { match value.0 { GeneralConstId::ConstId(id) => SolverDefId::ConstId(id), GeneralConstId::StaticId(id) => SolverDefId::StaticId(id), @@ -513,10 +735,10 @@ impl From for SolverDefId { } } } -impl TryFrom for GeneralConstIdWrapper { +impl<'db> TryFrom> for GeneralConstIdWrapper<'db> { type Error = (); #[inline] - fn try_from(value: SolverDefId) -> Result { + fn try_from(value: SolverDefId<'db>) -> Result { match value { SolverDefId::ConstId(it) => Ok(Self(it.into())), SolverDefId::StaticId(it) => Ok(Self(it.into())), @@ -525,8 +747,8 @@ impl TryFrom for GeneralConstIdWrapper { } } } -impl<'db> inherent::DefId> for GeneralConstIdWrapper { - fn as_local(self) -> Option { +impl<'db> inherent::DefId> for GeneralConstIdWrapper<'db> { + fn as_local(self) -> Option> { Some(self.into()) } fn is_local(self) -> bool { @@ -554,9 +776,9 @@ impl From for CallableIdWrapper { Self(value) } } -impl From for SolverDefId { +impl<'db> From for SolverDefId<'db> { #[inline] - fn from(value: CallableIdWrapper) -> SolverDefId { + fn from(value: CallableIdWrapper) -> SolverDefId<'db> { match value.0 { CallableDefId::FunctionId(it) => it.into(), CallableDefId::StructId(it) => Ctor::Struct(it).into(), @@ -564,10 +786,10 @@ impl From for SolverDefId { } } } -impl TryFrom for CallableIdWrapper { +impl TryFrom> for CallableIdWrapper { type Error = (); #[inline] - fn try_from(value: SolverDefId) -> Result { + fn try_from(value: SolverDefId<'_>) -> Result { match value { SolverDefId::FunctionId(it) => Ok(Self(it.into())), SolverDefId::Ctor(Ctor::Struct(it)) => Ok(Self(it.into())), @@ -577,7 +799,7 @@ impl TryFrom for CallableIdWrapper { } } impl<'db> inherent::DefId> for CallableIdWrapper { - fn as_local(self) -> Option { + fn as_local(self) -> Option> { Some(self.into()) } fn is_local(self) -> bool { @@ -593,19 +815,19 @@ pub enum AnyImplId { impl_from!(ImplId, BuiltinDeriveImplId for AnyImplId); -impl From for SolverDefId { +impl<'db> From for SolverDefId<'db> { #[inline] - fn from(value: AnyImplId) -> SolverDefId { + fn from(value: AnyImplId) -> SolverDefId<'db> { match value { AnyImplId::ImplId(it) => it.into(), AnyImplId::BuiltinDeriveImplId(it) => it.into(), } } } -impl TryFrom for AnyImplId { +impl TryFrom> for AnyImplId { type Error = (); #[inline] - fn try_from(value: SolverDefId) -> Result { + fn try_from(value: SolverDefId<'_>) -> Result { match value { SolverDefId::ImplId(it) => Ok(it.into()), SolverDefId::BuiltinDeriveImplId(it) => Ok(it.into()), @@ -614,7 +836,7 @@ impl TryFrom for AnyImplId { } } impl<'db> inherent::DefId> for AnyImplId { - fn as_local(self) -> Option { + fn as_local(self) -> Option> { Some(self.into()) } fn is_local(self) -> bool { 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 0a41874374c21..826f234bf6d9f 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 @@ -225,7 +225,7 @@ impl<'db> DbInterner<'db> { /// free variants attached to `all_outlive_scope`. pub fn liberate_late_bound_regions( self, - all_outlive_scope: SolverDefId, + all_outlive_scope: SolverDefId<'db>, value: Binder<'db, T>, ) -> T where 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 33dd33cb1d806..e422f75a02073 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 @@ -287,7 +287,7 @@ impl<'db> FulfillmentCtxt<'db> { /// This function can be also return false positives, which will lead to poor diagnostics /// so we want to keep this visitor *precise* too. pub struct StalledOnCoroutines<'a, 'db> { - pub stalled_coroutines: &'a [SolverDefId], + pub stalled_coroutines: &'a [SolverDefId<'db>], pub span: Span, pub cache: FxHashSet>, } 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 4e5f3c8c49c13..22b34b379dd86 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 @@ -553,7 +553,7 @@ impl<'db> GenericArgs<'db> { /// replace defaults of generic parameters. pub fn for_item( interner: DbInterner<'db>, - def_id: SolverDefId, + def_id: SolverDefId<'db>, mk_kind: F, ) -> GenericArgs<'db> where @@ -579,7 +579,7 @@ impl<'db> GenericArgs<'db> { } /// Creates an all-error `GenericArgs`. - pub fn error_for_item(interner: DbInterner<'db>, def_id: SolverDefId) -> GenericArgs<'db> { + pub fn error_for_item(interner: DbInterner<'db>, def_id: SolverDefId<'db>) -> GenericArgs<'db> { GenericArgs::for_item(interner, def_id, |_, id, _, _| { GenericArg::error_from_id(interner, id) }) @@ -606,7 +606,7 @@ impl<'db> GenericArgs<'db> { /// Like `for_item()`, but calls first uses the args from `first`. pub fn fill_rest( interner: DbInterner<'db>, - def_id: SolverDefId, + def_id: SolverDefId<'db>, first: impl IntoIterator>, mut fallback: F, ) -> GenericArgs<'db> 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 9ae9a66674dca..e0a69a6602f3a 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 @@ -9,7 +9,7 @@ use crate::db::HirDatabase; use super::{Ctor, DbInterner, SolverDefId}; -pub(crate) fn generics(interner: DbInterner<'_>, def: SolverDefId) -> Generics<'_> { +pub(crate) fn generics<'db>(interner: DbInterner<'db>, def: SolverDefId<'db>) -> Generics<'db> { let db = interner.db; let (def, consider_late_bound) = match (def.try_into(), def) { (Ok(def), _) => (def, false), 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 1e2a3ff0c2b33..270bc73d5f53f 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 @@ -158,7 +158,7 @@ impl<'db> rustc_type_ir::InferCtxtLike for InferCtxt<'db> { self.next_const_var(Span::Dummy) } - fn fresh_args_for_item(&self, def_id: SolverDefId) -> GenericArgs<'db> { + fn fresh_args_for_item(&self, def_id: SolverDefId<'db>) -> GenericArgs<'db> { self.fresh_args_for_item(Span::Dummy, def_id) } 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 3fdf0480ebc2d..7c419147d2143 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 @@ -296,7 +296,7 @@ pub struct TypeTrace<'db> { /// Times when we replace bound regions with existentials: #[derive(Clone, Copy, Debug)] -pub enum BoundRegionConversionTime { +pub enum BoundRegionConversionTime<'db> { /// when a fn is called FnCall, @@ -304,7 +304,7 @@ pub enum BoundRegionConversionTime { HigherRankedType, /// when projecting an associated type - AssocTypeProjection(SolverDefId), + AssocTypeProjection(SolverDefId<'db>), } /// See the `region_obligations` field for more information. @@ -839,7 +839,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, span: Span, def_id: SolverDefId) -> GenericArgs<'db> { + pub fn fresh_args_for_item(&self, span: Span, def_id: SolverDefId<'db>) -> GenericArgs<'db> { GenericArgs::for_item(self.interner, def_id, |_index, kind, _, _| { self.var_for_def(kind, span) }) @@ -849,7 +849,7 @@ impl<'db> InferCtxt<'db> { pub fn fill_rest_fresh_args( &self, span: Span, - def_id: SolverDefId, + def_id: SolverDefId<'db>, first: impl IntoIterator>, ) -> GenericArgs<'db> { GenericArgs::fill_rest(self.interner, def_id, first, |_index, kind, _| { @@ -903,7 +903,7 @@ impl<'db> InferCtxt<'db> { } #[inline(always)] - pub fn can_define_opaque_ty(&self, id: impl Into) -> bool { + pub fn can_define_opaque_ty(&self, id: impl Into>) -> bool { match self.typing_mode_raw().assert_not_erased() { TypingMode::Analysis { defining_opaque_types_and_generators } => { defining_opaque_types_and_generators.contains(&id.into()) @@ -1102,7 +1102,7 @@ impl<'db> InferCtxt<'db> { pub fn instantiate_binder_with_fresh_vars( &self, span: Span, - _lbrct: BoundRegionConversionTime, + _lbrct: BoundRegionConversionTime<'db>, value: Binder<'db, T>, ) -> T where 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 e55e43a4cdb32..3b957c9c72894 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 @@ -394,7 +394,7 @@ impl<'db> TypeRelation> for Generalizer<'_, 'db> { &mut self, a_ty: Ty<'db>, _: Ty<'db>, - def_id: SolverDefId, + def_id: SolverDefId<'db>, a_args: GenericArgs<'db>, b_args: GenericArgs<'db>, mk: impl FnOnce(GenericArgs<'db>) -> Ty<'db>, 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 f3af697febcb2..f34afead74ffe 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 @@ -91,7 +91,7 @@ impl<'db> TypeRelation> for LatticeOp<'_, 'db> { &mut self, a_ty: Ty<'db>, b_ty: Ty<'db>, - def_id: SolverDefId, + def_id: SolverDefId<'db>, a_args: GenericArgs<'db>, b_args: GenericArgs<'db>, mk: impl FnOnce(GenericArgs<'db>) -> Ty<'db>, 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 3e8fab9313185..ab6ce31256897 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 @@ -201,6 +201,7 @@ macro_rules! impl_stored_interned_slice { Self { interned: it.interned.to_owned() } } + // FIXME: This transmute is not safe as is! #[inline] pub fn as_ref<'a, 'db>(&'a self) -> $name<'db> { let it = $name { interned: self.interned.as_ref() }; @@ -212,7 +213,7 @@ macro_rules! impl_stored_interned_slice { unsafe impl salsa::Update for $stored_name { unsafe fn maybe_update(old_pointer: *mut Self, new_value: Self) -> bool { // SAFETY: Comparing by (pointer) equality is safe. - unsafe { crate::utils::unsafe_update_eq(old_pointer, new_value) } + unsafe { salsa::update_fallback(old_pointer, new_value) } } } @@ -285,7 +286,7 @@ macro_rules! impl_stored_interned { unsafe impl salsa::Update for $stored_name { unsafe fn maybe_update(old_pointer: *mut Self, new_value: Self) -> bool { - unsafe { crate::utils::unsafe_update_eq(old_pointer, new_value) } + unsafe { salsa::update_fallback(old_pointer, new_value) } } } @@ -378,7 +379,7 @@ impl<'db> DbInterner<'db> { } #[inline] - pub fn default_types<'a>(&self) -> &'a crate::next_solver::DefaultAny<'db> { + pub fn default_types(&self) -> &'db crate::next_solver::DefaultAny<'db> { crate::next_solver::default_types(self.db) } @@ -878,18 +879,18 @@ macro_rules! is_lang_item { } impl<'db> Interner for DbInterner<'db> { - type DefId = SolverDefId; - type LocalDefId = SolverDefId; + type DefId = SolverDefId<'db>; + type LocalDefId = SolverDefId<'db>; type LocalDefIds = SolverDefIds<'db>; type TraitId = TraitIdWrapper; type ForeignId = TypeAliasIdWrapper; type FunctionId = CallableIdWrapper; - type ClosureId = ClosureIdWrapper; - type CoroutineClosureId = CoroutineClosureIdWrapper; - type CoroutineId = CoroutineIdWrapper; + type ClosureId = ClosureIdWrapper<'db>; + type CoroutineClosureId = CoroutineClosureIdWrapper<'db>; + type CoroutineId = CoroutineIdWrapper<'db>; type AdtId = AdtIdWrapper; type ImplId = AnyImplId; - type UnevaluatedConstId = GeneralConstIdWrapper; + type UnevaluatedConstId = GeneralConstIdWrapper<'db>; type TraitAssocTyId = TraitAssocTyId; type TraitAssocConstId = TraitAssocConstId; type TraitAssocTermId = TraitAssocTermId; @@ -1105,7 +1106,7 @@ impl<'db> Interner for DbInterner<'db> { AdtDef::new(def_id.0, self) } - fn alias_term_kind_from_def_id(self, def_id: SolverDefId) -> AliasTermKind<'db> { + fn alias_term_kind_from_def_id(self, def_id: SolverDefId<'db>) -> AliasTermKind<'db> { match def_id { SolverDefId::InternedOpaqueTyId(def_id) => { AliasTermKind::OpaqueTy { def_id: def_id.into() } @@ -1608,7 +1609,7 @@ impl<'db> Interner for DbInterner<'db> { ) { let krate = self.krate.expect("trait solving requires setting `DbInterner::krate`"); let trait_block = trait_def_id.0.loc(self.db).container.block(self.db); - let mut consider_impls_for_simplified_type = |simp: SimplifiedType| { + let mut consider_impls_for_simplified_type = |simp: SimplifiedType<'_>| { let type_block = simp.def().and_then(|def_id| { let module = match def_id { SolverDefId::AdtId(AdtId::StructId(id)) => id.module(self.db), @@ -1973,14 +1974,14 @@ impl<'db> Interner for DbInterner<'db> { return SolverDefIds::new_from_slice(&result); - struct CoroutinesVisitor<'a> { - db: &'a dyn HirDatabase, - owner: InferBodyId, - store: &'a ExpressionStore, - coroutines: &'a mut Vec, + struct CoroutinesVisitor<'a, 'db> { + db: &'db dyn HirDatabase, + owner: InferBodyId<'db>, + store: &'db ExpressionStore, + coroutines: &'a mut Vec>, } - impl StoreVisitor for CoroutinesVisitor<'_> { + impl<'db> StoreVisitor for CoroutinesVisitor<'_, 'db> { fn on_expr(&mut self, expr: ExprId) { if let hir_def::hir::Expr::Closure { closure_kind: @@ -2266,7 +2267,10 @@ impl<'db> DbInterner<'db> { } } -fn predicates_of(db: &dyn HirDatabase, def_id: SolverDefId) -> &GenericPredicates { +fn predicates_of<'db>( + db: &'db dyn HirDatabase, + def_id: SolverDefId<'db>, +) -> &'db GenericPredicates { match def_id { SolverDefId::BuiltinDeriveImplId(impl_) => crate::builtin_derive::predicates(db, impl_), SolverDefId::AnonConstId(anon_const) => { @@ -2321,13 +2325,13 @@ macro_rules! TrivialTypeTraversalImpls { } TrivialTypeTraversalImpls! { - SolverDefId, + SolverDefId<'_>, TraitIdWrapper, TypeAliasIdWrapper, CallableIdWrapper, - ClosureIdWrapper, - CoroutineIdWrapper, - CoroutineClosureIdWrapper, + ClosureIdWrapper<'_>, + CoroutineIdWrapper<'_>, + CoroutineClosureIdWrapper<'_>, AdtIdWrapper, TraitAssocTyId, TraitAssocConstId, @@ -2343,7 +2347,7 @@ TrivialTypeTraversalImpls! { InherentAssocTermId, OpaqueTyIdWrapper, AnyImplId, - GeneralConstIdWrapper, + GeneralConstIdWrapper<'_>, Safety, Span, ParamConst, 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 bdb3f3087103e..dd5f72979515f 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 @@ -30,8 +30,8 @@ interned_slice!( SolverDefIds, StoredSolverDefIds, def_ids, - SolverDefId, - SolverDefId, + SolverDefId<'db>, + SolverDefId<'static>, ); impl_foldable_for_interned_slice!(SolverDefIds); 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 dc753a1b47667..a6facff7623d8 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 @@ -77,7 +77,7 @@ impl<'db> Region<'db> { pub fn new_late_param( interner: DbInterner<'db>, - scope: SolverDefId, + scope: SolverDefId<'db>, bound_region: BoundRegion<'db>, ) -> Region<'db> { let late_bound_region = LateParamRegion { scope, bound_region }; @@ -169,7 +169,7 @@ pub struct EarlyParamRegion { /// This denotes some region at least as big as `scope`. It is similar to a placeholder region /// created when entering a binder, except it always lives in the root universe. pub struct LateParamRegion<'db> { - pub scope: SolverDefId, + pub scope: SolverDefId<'db>, pub bound_region: BoundRegion<'db>, } 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 d57d824e325fe..397db9375b940 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 @@ -43,7 +43,7 @@ use super::{ util::{FloatExt, IntegerExt}, }; -pub type SimplifiedType = rustc_type_ir::fast_reject::SimplifiedType; +pub type SimplifiedType<'db> = rustc_type_ir::fast_reject::SimplifiedType>; pub type TyKind<'db> = rustc_type_ir::TyKind>; pub type FnHeader<'db> = rustc_type_ir::FnHeader>; pub type AliasTyKind<'db> = rustc_type_ir::AliasTyKind>; @@ -1186,7 +1186,7 @@ impl<'db> rustc_type_ir::inherent::Ty> for Ty<'db> { fn new_coroutine( interner: DbInterner<'db>, - def_id: CoroutineIdWrapper, + def_id: CoroutineIdWrapper<'db>, args: as Interner>::GenericArgs, ) -> Self { Ty::new(interner, TyKind::Coroutine(def_id, args)) @@ -1194,7 +1194,7 @@ impl<'db> rustc_type_ir::inherent::Ty> for Ty<'db> { fn new_coroutine_closure( interner: DbInterner<'db>, - def_id: CoroutineClosureIdWrapper, + def_id: CoroutineClosureIdWrapper<'db>, args: as Interner>::GenericArgs, ) -> Self { Ty::new(interner, TyKind::CoroutineClosure(def_id, args)) @@ -1202,7 +1202,7 @@ impl<'db> rustc_type_ir::inherent::Ty> for Ty<'db> { fn new_closure( interner: DbInterner<'db>, - def_id: ClosureIdWrapper, + def_id: ClosureIdWrapper<'db>, args: as Interner>::GenericArgs, ) -> Self { Ty::new(interner, TyKind::Closure(def_id, args)) @@ -1210,7 +1210,7 @@ impl<'db> rustc_type_ir::inherent::Ty> for Ty<'db> { fn new_coroutine_witness( interner: DbInterner<'db>, - def_id: CoroutineIdWrapper, + def_id: CoroutineIdWrapper<'db>, args: as Interner>::GenericArgs, ) -> Self { Ty::new(interner, TyKind::CoroutineWitness(def_id, args)) @@ -1218,7 +1218,7 @@ impl<'db> rustc_type_ir::inherent::Ty> for Ty<'db> { fn new_coroutine_witness_for_coroutine( interner: DbInterner<'db>, - def_id: CoroutineIdWrapper, + def_id: CoroutineIdWrapper<'db>, coroutine_args: as Interner>::GenericArgs, ) -> Self { // HACK: Coroutine witness types are lifetime erased, so they 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 fb3bd18bf48ac..7e40e3c17d517 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 @@ -456,7 +456,7 @@ pub fn apply_args_to_binder<'db, T: TypeFoldable>>( pub fn explicit_item_bounds<'db>( interner: DbInterner<'db>, - def_id: SolverDefId, + def_id: SolverDefId<'db>, ) -> EarlyBinder<'db, impl DoubleEndedIterator> + ExactSizeIterator> { let db = interner.db(); let clauses = match def_id { @@ -469,7 +469,7 @@ pub fn explicit_item_bounds<'db>( pub fn explicit_item_self_bounds<'db>( interner: DbInterner<'db>, - def_id: SolverDefId, + def_id: SolverDefId<'db>, ) -> EarlyBinder<'db, impl DoubleEndedIterator> + ExactSizeIterator> { let db = interner.db(); let clauses = match def_id { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/opaques.rs b/src/tools/rust-analyzer/crates/hir-ty/src/opaques.rs index dfd1fd96c6564..1d7cd1b05dfea 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/opaques.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/opaques.rs @@ -22,8 +22,8 @@ use crate::{ pub(crate) fn opaque_types_defined_by( db: &dyn HirDatabase, - def_id: InferBodyId, - result: &mut Vec, + def_id: InferBodyId<'_>, + result: &mut Vec>, ) { if let Some(func) = def_id.as_function() { // A function may define its own RPITs. @@ -83,7 +83,7 @@ pub(crate) fn opaque_types_defined_by( db: &dyn HirDatabase, opaques: &Option>>, mut make_impl_trait: impl FnMut(ImplTraitIdx) -> ImplTraitId, - result: &mut Vec, + result: &mut Vec>, ) { if let Some(opaques) = opaques { for (opaque_idx, _) in (**opaques).as_ref().skip_binder().impl_traits.iter() { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs index febd2a833a6a7..5aed9227c0347 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs @@ -324,7 +324,7 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String { crate::attach_db(&db, || { let mut buf = String::new(); - let mut infer_def = |inference_result: &InferenceResult, + let mut infer_def = |inference_result: &InferenceResult<'_>, store: &ExpressionStore, source_map: &ExpressionStoreSourceMap, self_param: Option<( 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 3432d47b2f54c..08efef10ee78a 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 @@ -28,16 +28,16 @@ fn foo() -> i32 { } }); }, - &[("InferenceResult::for_body_", 1)], + &[("InferenceResult < 'db >::for_body_", 1)], expect_test::expect![[r#" [ "source_root_crates", "crate_local_def_map", "file_item_tree_query", "HirFileId::ast_id_map_", - "parse", + "EditionedFileId::parse_", "real_span_map", - "InferenceResult::for_body_", + "InferenceResult < 'db >::for_body_", "FunctionSignature::of_", "FunctionSignature::with_source_map_", "AttrFlags::query_", @@ -74,10 +74,10 @@ fn foo() -> i32 { } }); }, - &[("InferenceResult::for_body_", 0)], + &[("InferenceResult < 'db >::for_body_", 0)], expect_test::expect![[r#" [ - "parse", + "EditionedFileId::parse_", "HirFileId::ast_id_map_", "file_item_tree_query", "real_span_map", @@ -117,16 +117,16 @@ fn baz() -> i32 { } }); }, - &[("InferenceResult::for_body_", 3)], + &[("InferenceResult < 'db >::for_body_", 3)], expect_test::expect![[r#" [ "source_root_crates", "crate_local_def_map", "file_item_tree_query", "HirFileId::ast_id_map_", - "parse", + "EditionedFileId::parse_", "real_span_map", - "InferenceResult::for_body_", + "InferenceResult < 'db >::for_body_", "FunctionSignature::of_", "FunctionSignature::with_source_map_", "AttrFlags::query_", @@ -139,7 +139,7 @@ fn baz() -> i32 { "ImplTraits::return_type_impl_traits_", "ExprScopes::body_expr_scopes_", "body_upvars_mentioned", - "InferenceResult::for_body_", + "InferenceResult < 'db >::for_body_", "FunctionSignature::of_", "FunctionSignature::with_source_map_", "AttrFlags::query_", @@ -150,7 +150,7 @@ fn baz() -> i32 { "ImplTraits::return_type_impl_traits_", "ExprScopes::body_expr_scopes_", "body_upvars_mentioned", - "InferenceResult::for_body_", + "InferenceResult < 'db >::for_body_", "FunctionSignature::of_", "FunctionSignature::with_source_map_", "AttrFlags::query_", @@ -190,10 +190,10 @@ fn baz() -> i32 { } }); }, - &[("InferenceResult::for_body_", 1)], + &[("InferenceResult < 'db >::for_body_", 1)], expect_test::expect![[r#" [ - "parse", + "EditionedFileId::parse_", "HirFileId::ast_id_map_", "file_item_tree_query", "real_span_map", @@ -207,7 +207,7 @@ fn baz() -> i32 { "FunctionSignature::of_", "Body::with_source_map_", "Body::of_", - "InferenceResult::for_body_", + "InferenceResult < 'db >::for_body_", "ExprScopes::body_expr_scopes_", "body_upvars_mentioned", "AttrFlags::query_", @@ -241,16 +241,16 @@ $0", let _crate_def_map = module.def_map(&db); TraitImpls::for_crate(&db, module.krate(&db)); }, - &[("TraitImpls::for_crate_", 1)], + &[("TraitImpls < 'db >::for_crate_", 1)], expect_test::expect![[r#" [ "source_root_crates", "crate_local_def_map", "file_item_tree_query", "HirFileId::ast_id_map_", - "parse", + "EditionedFileId::parse_", "real_span_map", - "TraitImpls::for_crate_", + "TraitImpls < 'db >::for_crate_", "lang_items", "crate_lang_items", ] @@ -280,15 +280,15 @@ pub struct NewStruct { let _crate_def_map = module.def_map(&db); TraitImpls::for_crate(&db, module.krate(&db)); }, - &[("TraitImpls::for_crate_", 1)], + &[("TraitImpls < 'db >::for_crate_", 1)], expect_test::expect![[r#" [ - "parse", + "EditionedFileId::parse_", "HirFileId::ast_id_map_", "file_item_tree_query", "real_span_map", "crate_local_def_map", - "TraitImpls::for_crate_", + "TraitImpls < 'db >::for_crate_", "crate_lang_items", ] "#]], @@ -316,16 +316,16 @@ $0", let _crate_def_map = module.def_map(&db); TraitImpls::for_crate(&db, module.krate(&db)); }, - &[("TraitImpls::for_crate_", 1)], + &[("TraitImpls < 'db >::for_crate_", 1)], expect_test::expect![[r#" [ "source_root_crates", "crate_local_def_map", "file_item_tree_query", "HirFileId::ast_id_map_", - "parse", + "EditionedFileId::parse_", "real_span_map", - "TraitImpls::for_crate_", + "TraitImpls < 'db >::for_crate_", "lang_items", "crate_lang_items", ] @@ -356,15 +356,15 @@ pub enum SomeEnum { let _crate_def_map = module.def_map(&db); TraitImpls::for_crate(&db, module.krate(&db)); }, - &[("TraitImpls::for_crate_", 1)], + &[("TraitImpls < 'db >::for_crate_", 1)], expect_test::expect![[r#" [ - "parse", + "EditionedFileId::parse_", "HirFileId::ast_id_map_", "file_item_tree_query", "real_span_map", "crate_local_def_map", - "TraitImpls::for_crate_", + "TraitImpls < 'db >::for_crate_", "crate_lang_items", ] "#]], @@ -392,16 +392,16 @@ $0", let _crate_def_map = module.def_map(&db); TraitImpls::for_crate(&db, module.krate(&db)); }, - &[("TraitImpls::for_crate_", 1)], + &[("TraitImpls < 'db >::for_crate_", 1)], expect_test::expect![[r#" [ "source_root_crates", "crate_local_def_map", "file_item_tree_query", "HirFileId::ast_id_map_", - "parse", + "EditionedFileId::parse_", "real_span_map", - "TraitImpls::for_crate_", + "TraitImpls < 'db >::for_crate_", "lang_items", "crate_lang_items", ] @@ -429,15 +429,15 @@ fn bar() -> f32 { let _crate_def_map = module.def_map(&db); TraitImpls::for_crate(&db, module.krate(&db)); }, - &[("TraitImpls::for_crate_", 1)], + &[("TraitImpls < 'db >::for_crate_", 1)], expect_test::expect![[r#" [ - "parse", + "EditionedFileId::parse_", "HirFileId::ast_id_map_", "file_item_tree_query", "real_span_map", "crate_local_def_map", - "TraitImpls::for_crate_", + "TraitImpls < 'db >::for_crate_", "crate_lang_items", ] "#]], @@ -469,16 +469,16 @@ $0", let _crate_def_map = module.def_map(&db); TraitImpls::for_crate(&db, module.krate(&db)); }, - &[("TraitImpls::for_crate_", 1)], + &[("TraitImpls < 'db >::for_crate_", 1)], expect_test::expect![[r#" [ "source_root_crates", "crate_local_def_map", "file_item_tree_query", "HirFileId::ast_id_map_", - "parse", + "EditionedFileId::parse_", "real_span_map", - "TraitImpls::for_crate_", + "TraitImpls < 'db >::for_crate_", "lang_items", "crate_lang_items", ] @@ -514,15 +514,15 @@ impl SomeStruct { let _crate_def_map = module.def_map(&db); TraitImpls::for_crate(&db, module.krate(&db)); }, - &[("TraitImpls::for_crate_", 1)], + &[("TraitImpls < 'db >::for_crate_", 1)], expect_test::expect![[r#" [ - "parse", + "EditionedFileId::parse_", "HirFileId::ast_id_map_", "file_item_tree_query", "real_span_map", "crate_local_def_map", - "TraitImpls::for_crate_", + "TraitImpls < 'db >::for_crate_", "crate_lang_items", ] "#]], @@ -570,6 +570,7 @@ fn main() { let _inference_result = InferenceResult::of(&db, def); } }, + // FIXME: What does this test check for now? trait_solve_shim is no longer a query &[("trait_solve_shim", 0)], expect_test::expect![[r#" [ @@ -577,14 +578,14 @@ fn main() { "crate_local_def_map", "file_item_tree_query", "HirFileId::ast_id_map_", - "parse", + "EditionedFileId::parse_", "real_span_map", "TraitItems::query_with_diagnostics_", "Body::of_", "Body::with_source_map_", "AttrFlags::query_", "ImplItems::of_", - "InferenceResult::for_body_", + "InferenceResult < 'db >::for_body_", "TraitSignature::of_", "TraitSignature::with_source_map_", "AttrFlags::query_", @@ -600,7 +601,7 @@ fn main() { "GenericPredicates::query_with_diagnostics_", "ImplTraits::return_type_impl_traits_", "body_upvars_mentioned", - "InferenceResult::for_body_", + "InferenceResult < 'db >::for_body_", "FunctionSignature::of_", "FunctionSignature::with_source_map_", "trait_environment_query", @@ -611,10 +612,10 @@ fn main() { "StructSignature::with_source_map_", "AttrFlags::query_", "GenericPredicates::query_with_diagnostics_", - "InherentImpls::for_crate_", + "InherentImpls < 'db >::for_crate_", "callable_item_signature_with_diagnostics", - "TraitImpls::for_crate_and_deps_", - "TraitImpls::for_crate_", + "TraitImpls < 'db >::for_crate_and_deps_", + "TraitImpls < 'db >::for_crate_", "impl_trait_with_diagnostics", "ImplSignature::of_", "ImplSignature::with_source_map_", @@ -670,7 +671,7 @@ fn main() { &[("trait_solve_shim", 0)], expect_test::expect![[r#" [ - "parse", + "EditionedFileId::parse_", "HirFileId::ast_id_map_", "file_item_tree_query", "real_span_map", @@ -680,7 +681,7 @@ fn main() { "AttrFlags::query_", "Body::of_", "ImplItems::of_", - "InferenceResult::for_body_", + "InferenceResult < 'db >::for_body_", "AttrFlags::query_", "TraitSignature::with_source_map_", "AttrFlags::query_", @@ -693,7 +694,7 @@ fn main() { "GenericPredicates::query_with_diagnostics_", "ImplTraits::return_type_impl_traits_", "body_upvars_mentioned", - "InferenceResult::for_body_", + "InferenceResult < 'db >::for_body_", "FunctionSignature::with_source_map_", "GenericPredicates::query_with_diagnostics_", "ImplTraits::return_type_impl_traits_", @@ -701,9 +702,9 @@ fn main() { "StructSignature::with_source_map_", "AttrFlags::query_", "GenericPredicates::query_with_diagnostics_", - "InherentImpls::for_crate_", + "InherentImpls < 'db >::for_crate_", "callable_item_signature_with_diagnostics", - "TraitImpls::for_crate_", + "TraitImpls < 'db >::for_crate_", "ImplSignature::with_source_map_", "ImplSignature::of_", "impl_trait_with_diagnostics", 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 935f541841d26..108e3e07a666a 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs @@ -61,13 +61,13 @@ pub struct StoredParamEnvAndCrate { impl StoredParamEnvAndCrate { #[inline] - pub fn param_env(&self) -> ParamEnv<'_> { + pub fn param_env<'db>(&self, _db: &'db dyn HirDatabase) -> ParamEnv<'db> { ParamEnv { clauses: self.param_env.as_ref() } } #[inline] - pub fn as_ref(&self) -> ParamEnvAndCrate<'_> { - ParamEnvAndCrate { param_env: self.param_env(), krate: self.krate } + pub fn as_ref<'db>(&self, db: &'db dyn HirDatabase) -> ParamEnvAndCrate<'db> { + ParamEnvAndCrate { param_env: self.param_env(db), krate: self.krate } } } @@ -175,7 +175,7 @@ pub enum WherePredicateEvaluation { pub fn where_predicate_must_hold<'db>( db: &'db dyn HirDatabase, resolver: &Resolver<'db>, - store: &ExpressionStore, + store: &'db ExpressionStore, def: ExpressionStoreOwnerId, generic_def: GenericDefId, env: ParamEnvAndCrate<'db>, 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 764d02ccf1d88..53d7231562819 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs @@ -19,26 +19,6 @@ use crate::{ mir::pad16, }; -/// SAFETY: `old_pointer` must be valid for unique writes -pub(crate) unsafe fn unsafe_update_eq(old_pointer: *mut T, new_value: T) -> bool -where - T: PartialEq, -{ - // SAFETY: Caller obligation - let old_ref: &mut T = unsafe { &mut *old_pointer }; - - if *old_ref != new_value { - *old_ref = new_value; - true - } else { - // Subtle but important: Eq impls can be buggy or define equality - // in surprising ways. If it says that the value has not changed, - // we do not modify the existing value, and thus do not have to - // update the revision, as downstream code will not see the new value. - false - } -} - pub(crate) fn fn_traits(lang_items: &LangItems) -> impl Iterator + '_ { [lang_items.Fn, lang_items.FnMut, lang_items.FnOnce].into_iter().flatten() } diff --git a/src/tools/rust-analyzer/crates/hir/Cargo.toml b/src/tools/rust-analyzer/crates/hir/Cargo.toml index 89021441892c6..a9575a93dbeee 100644 --- a/src/tools/rust-analyzer/crates/hir/Cargo.toml +++ b/src/tools/rust-analyzer/crates/hir/Cargo.toml @@ -22,6 +22,7 @@ smallvec.workspace = true tracing = { workspace = true, features = ["attributes"] } triomphe.workspace = true la-arena.workspace = true +salsa.workspace = true ra-ap-rustc_type_ir.workspace = true diff --git a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs index b921a5eef14a9..e2a9c46a83b30 100644 --- a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs +++ b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs @@ -137,7 +137,7 @@ diagnostics![AnyDiagnostic<'db> -> MovedOutOfRef<'db>, MutRefInImmRefPat, MutableRefBinding, - NeedMut, + NeedMut<'db>, NonExhaustiveLet, NonExhaustiveRecordExpr, NonExhaustiveRecordPat, @@ -168,8 +168,8 @@ diagnostics![AnyDiagnostic<'db> -> UnresolvedMethodCall<'db>, UnresolvedModule, UnresolvedIdent, - UnusedMut, - UnusedVariable, + UnusedMut<'db>, + UnusedVariable<'db>, GenericArgsProhibited, ParenthesizedGenericArgsWithoutFnTrait, BadRtn, @@ -474,19 +474,19 @@ pub struct TypeMismatch<'db> { } #[derive(Debug)] -pub struct NeedMut { - pub local: Local, +pub struct NeedMut<'db> { + pub local: Local<'db>, pub span: InFile, } #[derive(Debug)] -pub struct UnusedMut { - pub local: Local, +pub struct UnusedMut<'db> { + pub local: Local<'db>, } #[derive(Debug)] -pub struct UnusedVariable { - pub local: Local, +pub struct UnusedVariable<'db> { + pub local: Local<'db>, } #[derive(Debug)] @@ -835,7 +835,7 @@ impl<'db> AnyDiagnostic<'db> { d: &'db InferenceDiagnostic, source_map: &hir_def::expr_store::BodySourceMap, sig_map: &hir_def::expr_store::ExpressionStoreSourceMap, - type_owner: TypeOwnerId, + type_owner: TypeOwnerId<'db>, ) -> Option> { let expr_syntax = |expr| Self::expr_syntax(expr, source_map); let pat_syntax = |pat| Self::pat_syntax(pat, source_map); @@ -1148,7 +1148,7 @@ impl<'db> AnyDiagnostic<'db> { db: &'db dyn HirDatabase, d: &'db SolverDiagnosticKind, span: SpanSyntax, - type_owner: TypeOwnerId, + type_owner: TypeOwnerId<'db>, ) -> Option> { let interner = DbInterner::new_no_crate(db); Some(match d { diff --git a/src/tools/rust-analyzer/crates/hir/src/display.rs b/src/tools/rust-analyzer/crates/hir/src/display.rs index 06fa91804ddee..6f7615ed18337 100644 --- a/src/tools/rust-analyzer/crates/hir/src/display.rs +++ b/src/tools/rust-analyzer/crates/hir/src/display.rs @@ -532,7 +532,7 @@ impl<'db> HirDisplay<'db> for Field { } } -impl<'db> HirDisplay<'db> for TupleField { +impl<'db> HirDisplay<'db> for TupleField<'db> { fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result { write!(f, "pub {}: ", self.name().display(f.db, f.edition()))?; self.ty(f.db).hir_fmt(f) diff --git a/src/tools/rust-analyzer/crates/hir/src/from_id.rs b/src/tools/rust-analyzer/crates/hir/src/from_id.rs index 219eb9c3b9268..e94279bc4583e 100644 --- a/src/tools/rust-analyzer/crates/hir/src/from_id.rs +++ b/src/tools/rust-analyzer/crates/hir/src/from_id.rs @@ -254,7 +254,7 @@ impl TryFrom for GenericDefId { } } -impl From<(DefWithBodyId, BindingId)> for Local { +impl<'db> From<(DefWithBodyId, BindingId)> for Local<'db> { fn from((parent, binding_id): (DefWithBodyId, BindingId)) -> Self { Local { parent: parent.into(), parent_infer: parent.into(), binding_id } } diff --git a/src/tools/rust-analyzer/crates/hir/src/has_source.rs b/src/tools/rust-analyzer/crates/hir/src/has_source.rs index 9248aaec02097..3a6e19636a0b5 100644 --- a/src/tools/rust-analyzer/crates/hir/src/has_source.rs +++ b/src/tools/rust-analyzer/crates/hir/src/has_source.rs @@ -265,7 +265,7 @@ impl HasSource for LifetimeParam { } } -impl HasSource for LocalSource { +impl HasSource for LocalSource<'_> { type Ast = Either; fn source(self, _: &dyn HirDatabase) -> Option> { diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index 1ba73c180c319..fd00480c0a9fb 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -706,7 +706,7 @@ impl Module { self, db: &dyn HirDatabase, visible_from: Option, - ) -> Vec<(Name, ScopeDef)> { + ) -> Vec<(Name, ScopeDef<'_>)> { self.id.def_map(db)[self.id] .scope .entries() @@ -1367,18 +1367,18 @@ pub struct Field { } #[derive(Debug, PartialEq, Eq, Copy, Clone, Hash)] -pub struct TupleField { - pub owner: InferBodyId, +pub struct TupleField<'db> { + pub owner: InferBodyId<'db>, pub tuple: TupleId, pub index: u32, } -impl TupleField { +impl<'db> TupleField<'db> { pub fn name(&self) -> Name { Name::new_tuple_field(self.index as usize) } - pub fn ty<'db>(&self, db: &'db dyn HirDatabase) -> Type<'db> { + pub fn ty(&self, db: &'db dyn HirDatabase) -> Type<'db> { let interner = DbInterner::new_no_crate(db); let ty = InferenceResult::of(db, self.owner) .tuple_field_access_type(self.tuple) @@ -1703,7 +1703,7 @@ impl EnumVariant { self.source(db)?.value.const_arg()?.expr() } - pub fn eval(self, db: &dyn HirDatabase) -> Result { + pub fn eval(self, db: &dyn HirDatabase) -> Result> { db.const_eval_discriminant(self.into()) } @@ -1870,21 +1870,24 @@ impl Variant { } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct AnonConst { - id: AnonConstId, +pub struct AnonConst<'db> { + id: AnonConstId<'db>, } -impl AnonConst { +impl<'db> AnonConst<'db> { pub fn owner(self, db: &dyn HirDatabase) -> ExpressionStoreOwner { self.id.loc(db).owner.into() } - pub fn ty<'db>(self, db: &'db dyn HirDatabase) -> Type<'db> { + pub fn ty(self, db: &'db dyn HirDatabase) -> Type<'db> { let loc = self.id.loc(db); Type { owner: self.id.into(), ty: loc.ty.get() } } - pub fn eval(self, db: &dyn HirDatabase) -> Result, ConstEvalError> { + pub fn eval( + self, + db: &'db dyn HirDatabase, + ) -> Result, ConstEvalError<'db>> { let interner = DbInterner::new_no_crate(db); let ty = self.id.loc(db).ty.get().instantiate_identity().skip_norm_wip(); db.anon_const_eval(self.id, GenericArgs::empty(interner), None).map(|it| EvaluatedConst { @@ -1896,9 +1899,9 @@ impl AnonConst { } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub enum InferBody { +pub enum InferBody<'db> { Body(DefWithBody), - AnonConst(AnonConst), + AnonConst(AnonConst<'db>), } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] @@ -1996,7 +1999,7 @@ impl DefWithBody { } #[deprecated = "you should really not use this, this is exported for analysis-stats only"] - pub fn run_mir_body(self, db: &dyn HirDatabase) -> Result<(), MirLowerError> { + pub fn run_mir_body(self, db: &dyn HirDatabase) -> Result<(), MirLowerError<'_>> { let Some(id) = self.id() else { return Ok(()) }; db.mir_body(id.into()).map(drop) } @@ -2375,7 +2378,7 @@ impl Function { } } - fn fn_sig<'db>(self, db: &'db dyn HirDatabase) -> (TypeOwnerId, PolyFnSig<'db>) { + fn fn_sig<'db>(self, db: &'db dyn HirDatabase) -> (TypeOwnerId<'db>, PolyFnSig<'db>) { let fn_ptr = self.fn_ptr_type(db); let TyKind::FnPtr(sig_tys, hdr) = fn_ptr.ty.skip_binder().kind() else { unreachable!(); @@ -2383,7 +2386,7 @@ impl Function { (fn_ptr.owner, sig_tys.with(hdr)) } - fn erased_fn_sig<'db>(self, db: &'db dyn HirDatabase) -> (TypeOwnerId, FnSig<'db>) { + fn erased_fn_sig<'db>(self, db: &'db dyn HirDatabase) -> (TypeOwnerId<'db>, FnSig<'db>) { let (owner, sig) = self.fn_sig(db); let sig = DbInterner::new_no_crate(db).instantiate_bound_regions_with_erased(sig); (owner, sig) @@ -2646,7 +2649,7 @@ impl Function { self, db: &dyn HirDatabase, span_formatter: impl Fn(FileId, TextRange) -> String, - ) -> Result { + ) -> Result> { let AnyFunctionId::FunctionId(id) = self.id else { return Err(ConstEvalError::MirEvalError(MirEvalError::NotSupported( "evaluation of builtin derive impl methods is not supported".to_owned(), @@ -2739,7 +2742,7 @@ impl<'db> Param<'db> { Some(self.as_local(db)?.name(db)) } - pub fn as_local(&self, db: &dyn HirDatabase) -> Option { + pub fn as_local(&self, db: &'db dyn HirDatabase) -> Option> { match self.func { Callee::Def(CallableDefId::FunctionId(it)) => { let parent = DefWithBodyId::FunctionId(it); @@ -2926,7 +2929,7 @@ impl Const { } /// Evaluate the constant. - pub fn eval(self, db: &dyn HirDatabase) -> Result, ConstEvalError> { + pub fn eval(self, db: &dyn HirDatabase) -> Result, ConstEvalError<'_>> { let interner = DbInterner::new_no_crate(db); let ty = db.value_ty(self.id.into()).unwrap().instantiate_identity().skip_norm_wip(); db.const_eval(self.id, GenericArgs::empty(interner), None).map(|it| EvaluatedConst { @@ -2944,7 +2947,7 @@ impl HasVisibility for Const { } pub struct EvaluatedConst<'db> { - def: InferBodyId, + def: InferBodyId<'db>, allocation: hir_ty::next_solver::Allocation<'db>, ty: Ty<'db>, } @@ -2954,7 +2957,7 @@ impl<'db> EvaluatedConst<'db> { format!("{}", self.allocation.display(db, display_target)) } - pub fn render_debug(&self, db: &'db dyn HirDatabase) -> Result { + pub fn render_debug(&self, db: &'db dyn HirDatabase) -> Result> { let ty = self.allocation.ty.kind(); if let TyKind::Int(_) | TyKind::Uint(_) = ty { let b = &self.allocation.memory; @@ -3007,7 +3010,7 @@ impl Static { } /// Evaluate the static initializer. - pub fn eval(self, db: &dyn HirDatabase) -> Result, ConstEvalError> { + pub fn eval(self, db: &dyn HirDatabase) -> Result, ConstEvalError<'_>> { let ty = db.value_ty(self.id.into()).unwrap().instantiate_identity().skip_norm_wip(); db.const_eval_static(self.id).map(|it| EvaluatedConst { allocation: it, @@ -4011,17 +4014,21 @@ impl GenericDef { // We cannot call this `Substitution` unfortunately... #[derive(Debug)] pub struct GenericSubstitution<'db> { - owner: TypeOwnerId, + owner: TypeOwnerId<'db>, def: GenericDefId, subst: GenericArgs<'db>, } impl<'db> GenericSubstitution<'db> { - fn new(def: GenericDefId, subst: GenericArgs<'db>, owner: TypeOwnerId) -> Self { + fn new(def: GenericDefId, subst: GenericArgs<'db>, owner: TypeOwnerId<'db>) -> Self { Self { owner, def, subst } } - fn new_from_fn(def: Function, subst: GenericArgs<'db>, owner: TypeOwnerId) -> Option { + fn new_from_fn( + def: Function, + subst: GenericArgs<'db>, + owner: TypeOwnerId<'db>, + ) -> Option { match def.id { AnyFunctionId::FunctionId(def) => Some(Self::new(def.into(), subst, owner)), AnyFunctionId::BuiltinDeriveImplMethod { .. } => None, @@ -4082,18 +4089,18 @@ impl<'db> GenericSubstitution<'db> { /// A single local definition. #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct Local { +pub struct Local<'db> { pub(crate) parent: ExpressionStoreOwnerId, - pub(crate) parent_infer: InferBodyId, + pub(crate) parent_infer: InferBodyId<'db>, pub(crate) binding_id: BindingId, } -pub struct LocalSource { - pub local: Local, +pub struct LocalSource<'db> { + pub local: Local<'db>, pub source: InFile>, } -impl LocalSource { +impl<'db> LocalSource<'db> { pub fn as_ident_pat(&self) -> Option<&ast::IdentPat> { match &self.source.value { Either::Left(it) => Some(it), @@ -4129,7 +4136,7 @@ impl LocalSource { } } -impl Local { +impl<'db> Local<'db> { pub fn is_param(self, db: &dyn HirDatabase) -> bool { // FIXME: This parses! let src = self.primary_source(db); @@ -4184,7 +4191,7 @@ impl Local { self.binding_id.into_raw().into_u32() } - pub fn ty(self, db: &dyn HirDatabase) -> Type<'_> { + pub fn ty(self, db: &'db dyn HirDatabase) -> Type<'db> { let def = self.parent; let infer = InferenceResult::of(db, self.parent_infer); let ty = infer.binding_ty(self.binding_id); @@ -4192,7 +4199,7 @@ impl Local { } /// All definitions for this local. Example: `let (a$0, _) | (_, a$0) = it;` - pub fn sources(self, db: &dyn HirDatabase) -> Vec { + pub fn sources(self, db: &dyn HirDatabase) -> Vec> { let b; let (_, source_map) = match self.parent { ExpressionStoreOwnerId::Signature(generic_def_id) => { @@ -4233,7 +4240,7 @@ impl Local { } /// The leftmost definition for this local. Example: `let (a$0, _) | (_, a) = it;` - pub fn primary_source(self, db: &dyn HirDatabase) -> LocalSource { + pub fn primary_source(self, db: &dyn HirDatabase) -> LocalSource<'db> { let b; let (_, source_map) = match self.parent { ExpressionStoreOwnerId::Signature(generic_def_id) => { @@ -4274,13 +4281,13 @@ impl Local { } } -impl PartialOrd for Local { +impl PartialOrd for Local<'_> { fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } -impl Ord for Local { +impl Ord for Local<'_> { fn cmp(&self, other: &Self) -> std::cmp::Ordering { self.binding_id.cmp(&other.binding_id) } @@ -4743,7 +4750,7 @@ impl Impl { pub fn all_for_trait(db: &dyn HirDatabase, trait_: Trait) -> Vec { let module = trait_.module(db).id; let mut all = Vec::new(); - let mut handle_impls = |impls: &TraitImpls| { + let mut handle_impls = |impls: &TraitImpls<'_>| { impls.for_trait(trait_.id, |impls| match impls { Either::Left(impls) => all.extend(impls.iter().copied().map(Impl::from)), Either::Right(impls) => all.extend(impls.iter().copied().map(Impl::from)), @@ -4867,7 +4874,7 @@ impl Impl { #[derive(Clone, PartialEq, Eq, Debug, Hash)] pub struct TraitRef<'db> { - owner: TypeOwnerId, + owner: TypeOwnerId<'db>, trait_ref: hir_ty::next_solver::TraitRef<'db>, } @@ -4898,15 +4905,15 @@ impl<'db> TraitRef<'db> { } #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -enum AnyClosureId { - ClosureId(InternedClosureId), - CoroutineClosureId(InternedCoroutineClosureId), +enum AnyClosureId<'db> { + ClosureId(InternedClosureId<'db>), + CoroutineClosureId(InternedCoroutineClosureId<'db>), } #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct Closure<'db> { - owner: TypeOwnerId, - id: AnyClosureId, + owner: TypeOwnerId<'db>, + id: AnyClosureId<'db>, subst: GenericArgs<'db>, } @@ -4961,20 +4968,20 @@ impl<'db> Closure<'db> { /// A coroutine expression, including async, generator, and async-generator coroutines. #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct Coroutine { - id: InternedCoroutineId, +pub struct Coroutine<'db> { + id: InternedCoroutineId<'db>, } -impl Coroutine { +impl<'db> Coroutine<'db> { /// Returns the values captured by this coroutine. - pub fn captured_items<'db>(&self, db: &'db dyn HirDatabase) -> Vec> { + pub fn captured_items(&self, db: &'db dyn HirDatabase) -> Vec> { captured_items(db, self.id.loc(db)) } } fn captured_items<'db>( db: &'db dyn HirDatabase, - closure: InternedClosure, + closure: InternedClosure<'db>, ) -> Vec> { let InternedClosure { owner: infer_owner, expr: closure, .. } = closure; let infer = InferenceResult::of(db, infer_owner); @@ -5055,13 +5062,13 @@ impl FnTrait { #[derive(Clone, Debug, PartialEq, Eq)] pub struct ClosureCapture<'db> { owner: ExpressionStoreOwnerId, - infer_owner: InferBodyId, + infer_owner: InferBodyId<'db>, closure: ExprId, capture: &'db hir_ty::closure_analysis::CapturedPlace, } impl<'db> ClosureCapture<'db> { - pub fn local(&self) -> Local { + pub fn local(&self) -> Local<'db> { Local { parent: self.owner, parent_infer: self.infer_owner, @@ -5249,16 +5256,33 @@ impl CaptureUsageSource { } #[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)] -enum TypeOwnerId { +enum TypeOwnerId<'db> { GenericDefId(GenericDefId), BuiltinDeriveImplId(BuiltinDeriveImplId), - AnonConstId(AnonConstId), + AnonConstId(AnonConstId<'db>), // FIXME: What do when we unify two different crates? Currently we just randomly keep one. NoParams(base_db::Crate), } -impl_from!(GenericDefId, BuiltinDeriveImplId, AnonConstId for TypeOwnerId); -impl TypeOwnerId { +impl<'db> From for TypeOwnerId<'db> { + fn from(it: GenericDefId) -> TypeOwnerId<'db> { + TypeOwnerId::GenericDefId(it) + } +} + +impl<'db> From for TypeOwnerId<'db> { + fn from(it: BuiltinDeriveImplId) -> TypeOwnerId<'db> { + TypeOwnerId::BuiltinDeriveImplId(it) + } +} + +impl<'db> From> for TypeOwnerId<'db> { + fn from(it: AnonConstId<'db>) -> TypeOwnerId<'db> { + TypeOwnerId::AnonConstId(it) + } +} + +impl TypeOwnerId<'_> { fn unify(self, other: Self) -> Option { match (self, other) { (TypeOwnerId::NoParams(_), owner) => Some(owner), @@ -5324,7 +5348,7 @@ impl TypeOwnerId { /// with types of different origins will cause errors or panics. Instead, use the `instantiate` methods. #[derive(Clone, Debug)] pub struct Type<'db> { - owner: TypeOwnerId, + owner: TypeOwnerId<'db>, ty: EarlyBinder<'db, Ty<'db>>, } @@ -5519,7 +5543,7 @@ impl<'db> Type<'db> { tys: impl IntoIterator>>, ) -> Self { let interner = DbInterner::new_no_crate(db); - let mut owner = None::; + let mut owner = None::>; let ty = EarlyBinder::bind(Ty::new_tup_from_iter( interner, tys.into_iter().map(|ty| { @@ -5976,7 +6000,7 @@ impl<'db> Type<'db> { } /// Returns this type as a coroutine. - pub fn as_coroutine(&self) -> Option { + pub fn as_coroutine(&self) -> Option> { match self.ty.skip_binder().kind() { TyKind::Coroutine(id, _) => Some(Coroutine { id: id.0 }), _ => None, @@ -6070,7 +6094,10 @@ impl<'db> Type<'db> { } // FIXME: We should probably remove this. - pub fn fingerprint_for_trait_impl(&self, db: &'db dyn HirDatabase) -> Option { + pub fn fingerprint_for_trait_impl( + &self, + db: &'db dyn HirDatabase, + ) -> Option> { fast_reject::simplify_type( DbInterner::new_no_crate(db), self.ty.skip_binder(), @@ -6573,7 +6600,7 @@ impl<'db> Type<'db> { pub fn walk(&self, db: &'db dyn HirDatabase, callback: impl FnMut(Type<'db>)) { struct Visitor<'db, F> { db: &'db dyn HirDatabase, - owner: TypeOwnerId, + owner: TypeOwnerId<'db>, callback: F, visited: FxHashSet>, } @@ -6706,8 +6733,8 @@ pub struct Callable<'db> { #[derive(Clone, PartialEq, Eq, Hash, Debug)] enum Callee<'db> { Def(CallableDefId), - Closure(InternedClosureId, GenericArgs<'db>), - CoroutineClosure(InternedCoroutineClosureId, GenericArgs<'db>), + Closure(InternedClosureId<'db>, GenericArgs<'db>), + CoroutineClosure(InternedCoroutineClosureId<'db>, GenericArgs<'db>), FnPtr, FnImpl(traits::FnTrait), BuiltinDeriveImplMethod { method: BuiltinDeriveImplMethod, impl_: BuiltinDeriveImplId }, @@ -6915,17 +6942,17 @@ pub enum BindingMode { /// For IDE only #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] -pub enum ScopeDef { +pub enum ScopeDef<'db> { ModuleDef(ModuleDef), GenericParam(GenericParam), ImplSelfType(Impl), AdtSelfType(Adt), - Local(Local), + Local(Local<'db>), Label(Label), Unknown, } -impl ScopeDef { +impl ScopeDef<'_> { pub fn all_items(def: PerNs) -> ArrayVec { let mut items = ArrayVec::new(); @@ -6982,7 +7009,7 @@ impl ScopeDef { } } -impl From for ScopeDef { +impl From for ScopeDef<'_> { fn from(item: ItemInNs) -> Self { match item { ItemInNs::Types(id) => ScopeDef::ModuleDef(id), @@ -7040,7 +7067,7 @@ pub enum PredicatePolarity { #[derive(Debug, Clone, PartialEq, Eq)] pub struct TraitPredicate<'db> { inner: hir_ty::next_solver::TraitPredicate<'db>, - owner: TypeOwnerId, + owner: TypeOwnerId<'db>, } impl<'db> TraitPredicate<'db> { @@ -7163,7 +7190,7 @@ impl HasCrate for Module { } } -impl HasCrate for AnonConst { +impl<'db> HasCrate for AnonConst<'db> { fn krate(&self, db: &dyn HirDatabase) -> Crate { hir_def::HasModule::krate(&self.id.loc(db).owner, db).into() } @@ -7285,7 +7312,6 @@ impl_has_name!( Macro, ExternAssocItem, AssocItem, - Local, DeriveHelper, ToolModule, Label, @@ -7309,7 +7335,19 @@ macro_rules! impl_has_name_no_db { }; } -impl_has_name_no_db!(TupleField, StaticLifetime, BuiltinType, BuiltinAttr); +impl_has_name_no_db!(StaticLifetime, BuiltinType, BuiltinAttr); + +impl HasName for Local<'_> { + fn name(&self, db: &dyn HirDatabase) -> Option { + (*self).name(db).into() + } +} + +impl HasName for TupleField<'_> { + fn name(&self, _db: &dyn HirDatabase) -> Option { + (*self).name().into() + } +} impl HasName for Param<'_> { fn name(&self, db: &dyn HirDatabase) -> Option { @@ -7445,10 +7483,10 @@ fn as_name_opt(name: Option) -> Name { #[track_caller] fn generic_args_from_tys<'db>( interner: DbInterner<'db>, - def_id: SolverDefId, + def_id: SolverDefId<'db>, args: impl IntoIterator>>, -) -> (GenericArgs<'db>, TypeOwnerId) { - let mut owner = None::; +) -> (GenericArgs<'db>, TypeOwnerId<'db>) { + let mut owner = None::>; let mut args = args.into_iter(); let args = GenericArgs::for_item(interner, def_id, |_, id, _, _| { if matches!(id, GenericParamId::TypeParamId(_)) diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs index e9e6ec3a01249..fee6ae3d49527 100644 --- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs +++ b/src/tools/rust-analyzer/crates/hir/src/semantics.rs @@ -67,11 +67,11 @@ use crate::{ const CONTINUE_NO_BREAKS: ControlFlow = ControlFlow::Continue(()); #[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub enum PathResolution { +pub enum PathResolution<'db> { /// An item Def(ModuleDef), /// A local binding (only value namespace) - Local(Local), + Local(Local<'db>), /// A type parameter TypeParam(TypeParam), /// A const parameter @@ -82,7 +82,7 @@ pub enum PathResolution { DeriveHelper(DeriveHelper), } -impl PathResolution { +impl<'db> PathResolution<'db> { pub(crate) fn in_type_ns(&self) -> Option { match self { PathResolution::Def(ModuleDef::Adt(adt)) => Some(TypeNs::AdtId((*adt).into())), @@ -116,21 +116,21 @@ impl PathResolution { } #[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub struct PathResolutionPerNs { - pub type_ns: Option, - pub value_ns: Option, - pub macro_ns: Option, +pub struct PathResolutionPerNs<'db> { + pub type_ns: Option>, + pub value_ns: Option>, + pub macro_ns: Option>, } -impl PathResolutionPerNs { +impl<'db> PathResolutionPerNs<'db> { pub fn new( - type_ns: Option, - value_ns: Option, - macro_ns: Option, + type_ns: Option>, + value_ns: Option>, + macro_ns: Option>, ) -> Self { PathResolutionPerNs { type_ns, value_ns, macro_ns } } - pub fn any(&self) -> Option { + pub fn any(&self) -> Option> { self.type_ns.or(self.value_ns).or(self.macro_ns) } } @@ -165,8 +165,8 @@ pub struct Semantics<'db, DB: ?Sized> { } type DefWithoutBodyWithAnonConsts = Either; -type ExprToAnonConst = FxHashMap; -type DefAnonConstsMap = FxHashMap; +type ExprToAnonConst<'db> = FxHashMap>; +type DefAnonConstsMap<'db> = FxHashMap>; pub struct SemanticsImpl<'db> { pub db: &'db dyn HirDatabase, @@ -174,7 +174,7 @@ pub struct SemanticsImpl<'db> { /// MacroCall to its expansion's MacroCallId cache macro_call_cache: RefCell, MacroCallId>>, /// All anon consts defined by a *signature* (not a body). - signature_anon_consts_cache: RefCell, + signature_anon_consts_cache: RefCell>, } impl fmt::Debug for Semantics<'_, DB> { @@ -783,7 +783,11 @@ impl<'db> SemanticsImpl<'db> { /// Checks if renaming `renamed` to `new_name` may introduce conflicts with other locals, /// and returns the conflicting locals. - pub fn rename_conflicts(&self, to_be_renamed: &Local, new_name: &Name) -> Vec { + pub fn rename_conflicts<'a>( + &self, + to_be_renamed: &Local<'a>, + new_name: &Name, + ) -> Vec> { let (store, root_expr) = to_be_renamed.parent_infer.store_and_root_expr(self.db); let resolver = to_be_renamed.parent.resolver(self.db); let starting_expr = store.binding_owner(to_be_renamed.binding_id).unwrap_or(root_expr); @@ -813,7 +817,7 @@ impl<'db> SemanticsImpl<'db> { pub fn as_format_args_parts( &self, string: &ast::String, - ) -> Option>)>> { + ) -> Option, InlineAsmOperand>>)>> { let string_start = string.syntax().text_range().start(); let token = self.wrap_token_infile(string.syntax().clone()); self.descend_into_macros_breakable(token, |token, _| { @@ -870,7 +874,7 @@ impl<'db> SemanticsImpl<'db> { TextRange, HirFileRange, ast::String, - Option>, + Option, InlineAsmOperand>>, )> { let original_token = self.wrap_token_infile(original_token).map(ast::String::cast).transpose()?; @@ -892,7 +896,7 @@ impl<'db> SemanticsImpl<'db> { TextRange, HirFileRange, ast::String, - Option>, + Option, InlineAsmOperand>>, )> { let relative_offset = offset.checked_sub(original_token.value.syntax().text_range().start())?; @@ -924,13 +928,13 @@ impl<'db> SemanticsImpl<'db> { &self, InFile { value: string, file_id }: InFile<&ast::String>, offset: TextSize, - ) -> Option<(TextRange, Option>)> { + ) -> Option<(TextRange, Option, InlineAsmOperand>>)> { debug_assert!(offset <= string.syntax().text_range().len()); let literal = string.syntax().parent().filter(|it| it.kind() == SyntaxKind::LITERAL)?; let parent = literal.parent()?; if let Some(format_args) = ast::FormatArgsExpr::cast(parent.clone()) { let source_analyzer = - &self.analyze_impl(InFile::new(file_id, format_args.syntax()), None, false)?; + self.analyze_impl(InFile::new(file_id, format_args.syntax()), None, false)?; source_analyzer .resolve_offset_in_format_args(self.db, InFile::new(file_id, &format_args), offset) .map(|(range, res)| (range, res.map(Either::Left))) @@ -1899,14 +1903,14 @@ impl<'db> SemanticsImpl<'db> { self.analyze(call.syntax())?.resolve_method_call_as_callable(self.db, call) } - pub fn resolve_field(&self, field: &ast::FieldExpr) -> Option> { + pub fn resolve_field(&self, field: &ast::FieldExpr) -> Option>> { self.analyze(field.syntax())?.resolve_field(field) } pub fn resolve_field_fallback( &self, field: &ast::FieldExpr, - ) -> Option<(Either, Function>, Option>)> + ) -> Option<(Either>, Function>, Option>)> { self.analyze(field.syntax())?.resolve_field_fallback(self.db, field) } @@ -1914,7 +1918,7 @@ impl<'db> SemanticsImpl<'db> { pub fn resolve_record_field( &self, field: &ast::RecordExprField, - ) -> Option<(Field, Option, Type<'db>)> { + ) -> Option<(Field, Option>, Type<'db>)> { self.resolve_record_field_with_substitution(field) .map(|(field, local, ty, _)| (field, local, ty)) } @@ -1922,7 +1926,7 @@ impl<'db> SemanticsImpl<'db> { pub fn resolve_record_field_with_substitution( &self, field: &ast::RecordExprField, - ) -> Option<(Field, Option, Type<'db>, GenericSubstitution<'db>)> { + ) -> Option<(Field, Option>, Type<'db>, GenericSubstitution<'db>)> { self.analyze(field.syntax())?.resolve_record_field(self.db, field) } @@ -2026,18 +2030,18 @@ impl<'db> SemanticsImpl<'db> { Some(Macro { id }) } - pub fn resolve_path(&self, path: &ast::Path) -> Option { + pub fn resolve_path(&self, path: &ast::Path) -> Option> { self.resolve_path_with_subst(path).map(|(it, _)| it) } - pub fn resolve_path_per_ns(&self, path: &ast::Path) -> Option { + pub fn resolve_path_per_ns(&self, path: &ast::Path) -> Option> { self.analyze(path.syntax())?.resolve_hir_path_per_ns(self.db, path) } pub fn resolve_path_with_subst( &self, path: &ast::Path, - ) -> Option<(PathResolution, Option>)> { + ) -> Option<(PathResolution<'db>, Option>)> { self.analyze(path.syntax())?.resolve_path(self.db, path) } @@ -2106,17 +2110,17 @@ impl<'db> SemanticsImpl<'db> { .unwrap_or_default() } - fn with_ctx) -> T, T>(&self, f: F) -> T { + fn with_ctx) -> T, T>(&self, f: F) -> T { let mut ctx = SourceToDefCtx { db: self.db, cache: &mut self.s2d_cache.borrow_mut() }; f(&mut ctx) } - pub fn to_def(&self, src: &T) -> Option { + pub fn to_def>(&self, src: &T) -> Option { let src = self.find_file(src.syntax()).with_value(src); T::to_def(self, src) } - pub fn to_def2(&self, src: InFile<&T>) -> Option { + pub fn to_def2>(&self, src: InFile<&T>) -> Option { T::to_def(self, src) } @@ -2179,9 +2183,9 @@ impl<'db> SemanticsImpl<'db> { fn populate_anon_const_cache_for<'a>( &self, - cache: &'a mut DefAnonConstsMap, + cache: &'a mut DefAnonConstsMap<'db>, def: DefWithoutBodyWithAnonConsts, - ) -> &'a ExprToAnonConst { + ) -> &'a ExprToAnonConst<'db> { cache.entry(def).or_insert_with(|| match def { Either::Left(def) => { let all_anon_consts = @@ -2204,7 +2208,7 @@ impl<'db> SemanticsImpl<'db> { &self, def: DefWithoutBodyWithAnonConsts, root_expr: ExprId, - ) -> Option { + ) -> Option> { let mut cache = self.signature_anon_consts_cache.borrow_mut(); let anon_consts_map = self.populate_anon_const_cache_for(&mut cache, def); anon_consts_map.get(&root_expr).copied() @@ -2215,7 +2219,7 @@ impl<'db> SemanticsImpl<'db> { def: ExpressionStoreOwnerId, store: &ExpressionStore, node: ExprOrPatId, - ) -> Option { + ) -> Option> { let handle_def_without_body = |def| { let root_expr = match node { ExprOrPatId::ExprId(expr) => store.find_root_for_expr(expr), @@ -2236,7 +2240,7 @@ impl<'db> SemanticsImpl<'db> { fn with_all_infers_for_store( &self, owner: ExpressionStoreOwnerId, - callback: &mut dyn FnMut(&'db InferenceResult), + callback: &mut dyn FnMut(&'db InferenceResult<'db>), ) { let mut handle_def_without_body = |def| { let mut cache = self.signature_anon_consts_cache.borrow_mut(); @@ -2457,7 +2461,7 @@ impl<'db> SemanticsImpl<'db> { &self, element: Either<&ast::Expr, &ast::StmtList>, text_range: TextRange, - ) -> Option> { + ) -> Option>> { let sa = self.analyze(element.either(|e| e.syntax(), |s| s.syntax()))?; let infer_body = sa.infer_body?; let store = sa.store()?; @@ -2506,7 +2510,7 @@ impl<'db> SemanticsImpl<'db> { let mut exprs: Vec<_> = exprs.into_iter().filter_map(|e| sa.expr_id(e).and_then(|e| e.as_expr())).collect(); - let mut locals: FxIndexSet = FxIndexSet::default(); + let mut locals: FxIndexSet> = FxIndexSet::default(); let mut add_to_locals_used = |id, parent_expr| { let path = match id { ExprOrPatId::ExprId(expr_id) => { @@ -2637,16 +2641,16 @@ fn macro_call_to_macro_id( } } -pub trait ToDef: AstNode + Clone { +pub trait ToDef<'db>: AstNode + Clone { type Def; - fn to_def(sema: &SemanticsImpl<'_>, src: InFile<&Self>) -> Option; + fn to_def(sema: &SemanticsImpl<'db>, src: InFile<&Self>) -> Option; } macro_rules! to_def_impls { - ($(($def:path, $ast:path, $meth:ident)),* ,) => {$( - impl ToDef for $ast { + ($(($def:ty, $ast:path, $meth:ident)),* ,) => {$( + impl<'db> ToDef<'db> for $ast { type Def = $def; - fn to_def(sema: &SemanticsImpl<'_>, src: InFile<&Self>) -> Option { + fn to_def(sema: &SemanticsImpl<'db>, src: InFile<&Self>) -> Option { sema.with_ctx(|ctx| ctx.$meth(src)).map(<$def>::from) } } @@ -2673,7 +2677,7 @@ to_def_impls![ (crate::ConstParam, ast::ConstParam, const_param_to_def), (crate::GenericParam, ast::GenericParam, generic_param_to_def), (crate::Macro, ast::Macro, macro_to_def), - (crate::Local, ast::SelfParam, self_param_to_def), + (crate::Local<'db>, ast::SelfParam, self_param_to_def), (crate::Label, ast::Label, label_to_def), (crate::Adt, ast::Adt, adt_to_def), (crate::ExternCrateDecl, ast::ExternCrate, extern_crate_to_def), @@ -2682,10 +2686,10 @@ to_def_impls![ (MacroCallId, ast::MacroCall, macro_call_to_macro_call), ]; -impl ToDef for ast::IdentPat { - type Def = crate::Local; +impl<'db> ToDef<'db> for ast::IdentPat { + type Def = crate::Local<'db>; - fn to_def(sema: &SemanticsImpl<'_>, src: InFile<&Self>) -> Option { + fn to_def(sema: &SemanticsImpl<'db>, src: InFile<&Self>) -> Option { sema.with_ctx(|ctx| ctx.bind_pat_to_def(src, sema)) } } @@ -2712,7 +2716,7 @@ impl ToDef for ast::IdentPat { #[derive(Debug)] pub struct SemanticsScope<'db> { pub db: &'db dyn HirDatabase, - infer_body: Option, + infer_body: Option>, file_id: HirFileId, resolver: Resolver<'db>, } @@ -2753,7 +2757,7 @@ impl<'db> SemanticsScope<'db> { } /// Calls the passed closure `f` on all names in scope. - pub fn process_all_names(&self, f: &mut dyn FnMut(Name, ScopeDef)) { + pub fn process_all_names(&self, f: &mut dyn FnMut(Name, ScopeDef<'db>)) { let scope = self.resolver.names_in_scope(self.db); for (name, entries) in scope { for entry in entries { @@ -2790,7 +2794,7 @@ impl<'db> SemanticsScope<'db> { /// Resolve a path as-if it was written at the given scope. This is /// necessary a heuristic, as it doesn't take hygiene into account. - pub fn speculative_resolve(&self, ast_path: &ast::Path) -> Option { + pub fn speculative_resolve(&self, ast_path: &ast::Path) -> Option> { let mut kind = PathKind::Plain; let mut segments = vec![]; let mut first = true; @@ -2838,7 +2842,7 @@ impl<'db> SemanticsScope<'db> { /// `Ty::Assoc` syntax). pub fn assoc_type_shorthand_candidates( &self, - resolution: &PathResolution, + resolution: &PathResolution<'db>, mut cb: impl FnMut(TypeAlias), ) { let (Some(def), Some(resolution)) = (self.resolver.generic_def(), resolution.in_type_ns()) diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs b/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs index f7528d3db10b2..fa66339208da0 100644 --- a/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs +++ b/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs @@ -178,7 +178,7 @@ pub(super) struct SourceToDefCtx<'db, 'cache> { pub(super) cache: &'cache mut SourceToDefCache<'db>, } -impl SourceToDefCtx<'_, '_> { +impl<'db> SourceToDefCtx<'db, '_> { pub(super) fn file_to_def(&mut self, file: FileId) -> &SmallVec<[ModuleId; 1]> { let _p = tracing::info_span!("SourceToDefCtx::file_to_def").entered(); self.cache.file_to_def_cache.entry(file).or_insert_with(|| { @@ -347,8 +347,8 @@ impl SourceToDefCtx<'_, '_> { pub(super) fn bind_pat_to_def( &mut self, src: InFile<&ast::IdentPat>, - semantics: &SemanticsImpl<'_>, - ) -> Option { + semantics: &SemanticsImpl<'db>, + ) -> Option> { let container = self.find_container(src.syntax_ref())?.as_expression_store_owner()?; let (store, source_map) = ExpressionStore::with_source_map(self.db, container); let src = src.cloned().map(ast::Pat::from); 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 db4e92098e81f..fb27f9dec45ac 100644 --- a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs +++ b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs @@ -77,8 +77,8 @@ pub(crate) struct SourceAnalyzer<'db> { pub(crate) file_id: HirFileId, pub(crate) resolver: Resolver<'db>, pub(crate) body_or_sig: Option>, - pub(crate) type_owner: TypeOwnerId, - pub(crate) infer_body: Option, + pub(crate) type_owner: TypeOwnerId<'db>, + pub(crate) infer_body: Option>, } #[derive(Debug)] @@ -87,19 +87,19 @@ pub(crate) enum BodyOrSig<'db> { def: DefWithBodyId, body: &'db Body, source_map: &'db BodySourceMap, - infer: Option<&'db InferenceResult>, + infer: Option<&'db InferenceResult<'db>>, }, VariantFields { def: VariantId, store: &'db ExpressionStore, source_map: &'db ExpressionStoreSourceMap, - infer: Option<&'db InferenceResult>, + infer: Option<&'db InferenceResult<'db>>, }, Sig { def: GenericDefId, store: &'db ExpressionStore, source_map: &'db ExpressionStoreSourceMap, - infer: Option<&'db InferenceResult>, + infer: Option<&'db InferenceResult<'db>>, #[expect(dead_code)] generics: &'db GenericParams, }, @@ -129,7 +129,7 @@ impl<'db> SourceAnalyzer<'db> { def: DefWithBodyId, node @ InFile { file_id, .. }: InFile<&SyntaxNode>, offset: Option, - infer: Option<&'db InferenceResult>, + infer: Option<&'db InferenceResult<'db>>, ) -> SourceAnalyzer<'db> { let (body, source_map) = Body::with_source_map(db, def); let scopes = ExprScopes::of(db, def); @@ -295,11 +295,11 @@ impl<'db> SourceAnalyzer<'db> { }) } - fn infer(&self) -> Option<&InferenceResult> { - self.body_or_sig.as_ref().and_then(|it| match it { + fn infer(&self) -> Option<&'db InferenceResult<'db>> { + self.body_or_sig.as_ref().and_then(|it| match *it { BodyOrSig::VariantFields { infer, .. } | BodyOrSig::Sig { infer, .. } - | BodyOrSig::Body { infer, .. } => infer.as_deref(), + | BodyOrSig::Body { infer, .. } => infer, }) } @@ -311,9 +311,9 @@ impl<'db> SourceAnalyzer<'db> { &self, ) -> Option<( ExpressionStoreOwnerId, - &ExpressionStore, - &ExpressionStoreSourceMap, - Option<&InferenceResult>, + &'db ExpressionStore, + &'db ExpressionStoreSourceMap, + Option<&'db InferenceResult<'db>>, )> { self.body_or_sig.as_ref().map(|it| match *it { BodyOrSig::VariantFields { def, store, source_map, infer, .. } => { @@ -328,18 +328,18 @@ impl<'db> SourceAnalyzer<'db> { }) } - pub(crate) fn store(&self) -> Option<&ExpressionStore> { - self.body_or_sig.as_ref().map(|it| match it { - BodyOrSig::Sig { store, .. } => &**store, - BodyOrSig::VariantFields { store, .. } => &**store, + pub(crate) fn store(&self) -> Option<&'db ExpressionStore> { + self.body_or_sig.as_ref().map(|it| match *it { + BodyOrSig::Sig { store, .. } => store, + BodyOrSig::VariantFields { store, .. } => store, BodyOrSig::Body { body, .. } => &body.store, }) } - pub(crate) fn store_sm(&self) -> Option<&ExpressionStoreSourceMap> { - self.body_or_sig.as_ref().map(|it| match it { - BodyOrSig::Sig { source_map, .. } => &**source_map, - BodyOrSig::VariantFields { source_map, .. } => &**source_map, + pub(crate) fn store_sm(&self) -> Option<&'db ExpressionStoreSourceMap> { + self.body_or_sig.as_ref().map(|it| match *it { + BodyOrSig::Sig { source_map, .. } => source_map, + BodyOrSig::VariantFields { source_map, .. } => source_map, BodyOrSig::Body { source_map, .. } => &source_map.store, }) } @@ -476,8 +476,8 @@ impl<'db> SourceAnalyzer<'db> { .lower_ty(type_ref); struct VarsCtx<'a, 'db> { - types: &'db DefaultAny<'db>, - infer: Option<&'a InferenceResult>, + types: &'a DefaultAny<'db>, + infer: Option<&'a InferenceResult<'db>>, } impl<'db> TyLoweringInferVarsCtx<'db> for VarsCtx<'_, 'db> { @@ -516,7 +516,7 @@ impl<'db> SourceAnalyzer<'db> { fn expr_id_is_diverging( &self, store: &ExpressionStore, - infer: &InferenceResult, + infer: &InferenceResult<'_>, expr_id: ExprOrPatId, ) -> bool { // FIXME: This is an approximation, perhaps we need to store a set of diverging exprs in inference? @@ -690,7 +690,7 @@ impl<'db> SourceAnalyzer<'db> { pub(crate) fn resolve_field( &self, field: &ast::FieldExpr, - ) -> Option> { + ) -> Option>> { let def = self.infer_body?; let expr_id = self.expr_id(field.clone().into())?.as_expr()?; self.infer()?.field_resolution(expr_id).map(|it| { @@ -701,7 +701,7 @@ impl<'db> SourceAnalyzer<'db> { fn field_subst( &self, field_expr: ExprId, - infer: &InferenceResult, + infer: &InferenceResult<'_>, _db: &'db dyn HirDatabase, ) -> Option> { let body = self.store()?; @@ -716,7 +716,7 @@ impl<'db> SourceAnalyzer<'db> { &self, db: &'db dyn HirDatabase, field: &ast::FieldExpr, - ) -> Option<(Either, Function>, Option>)> + ) -> Option<(Either>, Function>, Option>)> { let def = self.infer_body?; let expr_id = self.expr_id(field.clone().into())?.as_expr()?; @@ -949,7 +949,7 @@ impl<'db> SourceAnalyzer<'db> { &self, db: &'db dyn HirDatabase, field: &ast::RecordExprField, - ) -> Option<(Field, Option, Type<'db>, GenericSubstitution<'db>)> { + ) -> Option<(Field, Option>, Type<'db>, GenericSubstitution<'db>)> { let record_expr = ast::RecordExpr::cast(field.syntax().parent().and_then(|p| p.parent())?)?; let expr = ast::Expr::from(record_expr); let expr_id = self.store_sm()?.node_expr(InFile::new(self.file_id, &expr))?; @@ -1160,7 +1160,7 @@ impl<'db> SourceAnalyzer<'db> { &self, db: &'db dyn HirDatabase, path: &ast::Path, - ) -> Option<(PathResolution, Option>)> { + ) -> Option<(PathResolution<'db>, Option>)> { let parent = path.syntax().parent(); let parent = || parent.clone(); @@ -1486,9 +1486,9 @@ impl<'db> SourceAnalyzer<'db> { pub(crate) fn resolve_hir_path_per_ns( &self, - db: &dyn HirDatabase, + db: &'db dyn HirDatabase, path: &ast::Path, - ) -> Option { + ) -> Option> { let mut collector = ExprCollector::new(db, self.resolver.module(), self.file_id, LoweringMode::Ide); let hir_path = @@ -1628,7 +1628,7 @@ impl<'db> SourceAnalyzer<'db> { db: &'db dyn HirDatabase, format_args: InFile<&ast::FormatArgsExpr>, offset: TextSize, - ) -> Option<(TextRange, Option)> { + ) -> Option<(TextRange, Option>)> { let (hygiene, implicits) = self.store_sm()?.implicit_format_args(format_args)?; implicits.iter().find(|(range, _)| range.contains_inclusive(offset)).map(|(range, name)| { ( @@ -1666,9 +1666,9 @@ impl<'db> SourceAnalyzer<'db> { pub(crate) fn as_format_args_parts<'a>( &'a self, - db: &'a dyn HirDatabase, + db: &'db dyn HirDatabase, format_args: InFile<&ast::FormatArgsExpr>, - ) -> Option)> + 'a> { + ) -> Option>)> + 'a> { let (hygiene, names) = self.store_sm()?.implicit_format_args(format_args)?; Some(names.iter().map(move |(range, name)| { ( @@ -1846,14 +1846,14 @@ fn adjust( } #[inline] -pub(crate) fn resolve_hir_path( - db: &dyn HirDatabase, - resolver: &Resolver<'_>, - infer_body: Option, +pub(crate) fn resolve_hir_path<'db>( + db: &'db dyn HirDatabase, + resolver: &Resolver<'db>, + infer_body: Option>, path: &Path, hygiene: HygieneId, store: Option<&ExpressionStore>, -) -> Option { +) -> Option> { resolve_hir_path_(db, resolver, infer_body, path, false, hygiene, store, false).any() } @@ -1869,16 +1869,16 @@ pub(crate) fn resolve_hir_path_as_attr_macro( .map(Into::into) } -fn resolve_hir_path_( - db: &dyn HirDatabase, - resolver: &Resolver<'_>, - infer_body: Option, +fn resolve_hir_path_<'db>( + db: &'db dyn HirDatabase, + resolver: &Resolver<'db>, + infer_body: Option>, path: &Path, prefer_value_ns: bool, hygiene: HygieneId, store: Option<&ExpressionStore>, resolve_per_ns: bool, -) -> PathResolutionPerNs { +) -> PathResolutionPerNs<'db> { let types = || { let (ty, unresolved) = match path.type_anchor() { Some(type_ref) => resolver.generic_def().and_then(|def| { @@ -1993,14 +1993,14 @@ fn resolve_hir_path_( } } -fn resolve_hir_value_path( - db: &dyn HirDatabase, - resolver: &Resolver<'_>, +fn resolve_hir_value_path<'db>( + db: &'db dyn HirDatabase, + resolver: &Resolver<'db>, store_owner: Option, - infer_body: Option, + infer_body: Option>, path: &Path, hygiene: HygieneId, -) -> Option { +) -> Option> { resolver.resolve_path_in_value_ns_fully(db, path, hygiene).and_then(|val| { let res = match val { ValueNs::LocalBinding(binding_id) => { @@ -2032,12 +2032,12 @@ fn resolve_hir_value_path( /// } /// ``` /// then we know that `foo` in `my::foo::Bar` refers to the module, not the function. -fn resolve_hir_path_qualifier( - db: &dyn HirDatabase, - resolver: &Resolver<'_>, +fn resolve_hir_path_qualifier<'db>( + db: &'db dyn HirDatabase, + resolver: &Resolver<'db>, path: &Path, store: &ExpressionStore, -) -> Option { +) -> Option> { (|| { let (ty, unresolved) = match path.type_anchor() { Some(type_ref) => resolver.generic_def().and_then(|def| { @@ -2127,7 +2127,7 @@ pub(crate) fn name_hygiene(db: &dyn HirDatabase, name: InFile<&SyntaxNode>) -> H fn record_literal_matched_fields( db: &dyn HirDatabase, - infer: &InferenceResult, + infer: &InferenceResult<'_>, id: ExprId, expr: &Expr, ) -> Option<(VariantId, Vec)> { @@ -2159,7 +2159,7 @@ fn record_literal_matched_fields( fn record_pattern_matched_fields( db: &dyn HirDatabase, - infer: &InferenceResult, + infer: &InferenceResult<'_>, id: PatId, pat: &Pat, ) -> Option<(VariantId, Vec)> { diff --git a/src/tools/rust-analyzer/crates/hir/src/symbols.rs b/src/tools/rust-analyzer/crates/hir/src/symbols.rs index 021a20ae1b71e..79a075ef8bc72 100644 --- a/src/tools/rust-analyzer/crates/hir/src/symbols.rs +++ b/src/tools/rust-analyzer/crates/hir/src/symbols.rs @@ -2,7 +2,7 @@ use std::marker::PhantomData; -use base_db::FxIndexSet; +use base_db::{FxIndexSet, salsa::Update}; use either::Either; use hir_def::{ AdtId, AssocItemId, AstIdLoc, Complete, DefWithBodyId, ExternCrateId, HasModule, ImplId, @@ -28,7 +28,7 @@ use crate::{Crate, HasCrate, Module, ModuleDef, Semantics}; /// The actual data that is stored in the index. It should be as compact as /// possible. -#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[derive(Clone, PartialEq, Eq, Hash, Update)] pub struct FileSymbol<'db> { pub name: Symbol, pub def: ModuleDef, @@ -39,7 +39,33 @@ pub struct FileSymbol<'db> { pub is_assoc: bool, pub is_import: bool, pub do_not_complete: Complete, - _marker: PhantomData<&'db ()>, + _marker: PhantomData &'db ()>, +} + +impl<'db> std::fmt::Debug for FileSymbol<'db> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let FileSymbol { + name, + def, + loc, + container_name, + is_alias, + is_assoc, + is_import, + do_not_complete, + _marker: _, + } = self; + f.debug_struct("FileSymbol") + .field("name", name) + .field("def", def) + .field("loc", loc) + .field("container_name", container_name) + .field("is_alias", is_alias) + .field("is_assoc", is_assoc) + .field("is_import", is_import) + .field("do_not_complete", do_not_complete) + .finish() + } } #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] diff --git a/src/tools/rust-analyzer/crates/hir/src/term_search/expr.rs b/src/tools/rust-analyzer/crates/hir/src/term_search/expr.rs index a824c8bdca5d9..07994268696eb 100644 --- a/src/tools/rust-analyzer/crates/hir/src/term_search/expr.rs +++ b/src/tools/rust-analyzer/crates/hir/src/term_search/expr.rs @@ -65,7 +65,7 @@ pub enum Expr<'db> { /// Static variable Static(Static), /// Local variable - Local(Local), + Local(Local<'db>), /// Constant generic parameter ConstParam(ConstParam), /// Well known type (such as `true` for bool) diff --git a/src/tools/rust-analyzer/crates/hir/src/term_search/tactics.rs b/src/tools/rust-analyzer/crates/hir/src/term_search/tactics.rs index 8e107afc9e3d2..c0cfe18e6efd6 100644 --- a/src/tools/rust-analyzer/crates/hir/src/term_search/tactics.rs +++ b/src/tools/rust-analyzer/crates/hir/src/term_search/tactics.rs @@ -37,7 +37,7 @@ use super::{LookupTable, NewTypesKey, TermSearchCtx}; /// depend on the current state of `lookup`_ pub(super) fn trivial<'a, 'lt, 'db, DB: HirDatabase>( ctx: &'a TermSearchCtx<'_, 'db, DB>, - defs: &'a FxHashSet, + defs: &'a FxHashSet>, lookup: &'lt mut LookupTable<'db>, ) -> impl Iterator> + use<'a, 'db, 'lt, DB> { let db = ctx.sema.db; @@ -102,7 +102,7 @@ pub(super) fn trivial<'a, 'lt, 'db, DB: HirDatabase>( /// depend on the current state of `lookup`_ pub(super) fn assoc_const<'a, 'lt, 'db, DB: HirDatabase>( ctx: &'a TermSearchCtx<'_, 'db, DB>, - defs: &'a FxHashSet, + defs: &'a FxHashSet>, lookup: &'lt mut LookupTable<'db>, ) -> impl Iterator> + use<'a, 'db, 'lt, DB> { let db = ctx.sema.db; @@ -150,7 +150,7 @@ pub(super) fn assoc_const<'a, 'lt, 'db, DB: HirDatabase>( /// * `should_continue` - Function that indicates when to stop iterating pub(super) fn data_constructor<'a, 'lt, 'db, DB: HirDatabase>( ctx: &'a TermSearchCtx<'_, 'db, DB>, - _defs: &'a FxHashSet, + _defs: &'a FxHashSet>, lookup: &'lt mut LookupTable<'db>, should_continue: &'a dyn std::ops::Fn() -> bool, ) -> impl Iterator> + use<'a, 'db, 'lt, DB> { @@ -303,7 +303,7 @@ pub(super) fn data_constructor<'a, 'lt, 'db, DB: HirDatabase>( /// * `should_continue` - Function that indicates when to stop iterating pub(super) fn free_function<'a, 'lt, 'db, DB: HirDatabase>( ctx: &'a TermSearchCtx<'_, 'db, DB>, - defs: &'a FxHashSet, + defs: &'a FxHashSet>, lookup: &'lt mut LookupTable<'db>, should_continue: &'a dyn std::ops::Fn() -> bool, ) -> impl Iterator> + use<'a, 'db, 'lt, DB> { @@ -440,7 +440,7 @@ pub(super) fn free_function<'a, 'lt, 'db, DB: HirDatabase>( /// * `should_continue` - Function that indicates when to stop iterating pub(super) fn impl_method<'a, 'lt, 'db, DB: HirDatabase>( ctx: &'a TermSearchCtx<'_, 'db, DB>, - _defs: &'a FxHashSet, + _defs: &'a FxHashSet>, lookup: &'lt mut LookupTable<'db>, should_continue: &'a dyn std::ops::Fn() -> bool, ) -> impl Iterator> + use<'a, 'db, 'lt, DB> { @@ -561,7 +561,7 @@ pub(super) fn impl_method<'a, 'lt, 'db, DB: HirDatabase>( /// * `should_continue` - Function that indicates when to stop iterating pub(super) fn struct_projection<'a, 'lt, 'db, DB: HirDatabase>( ctx: &'a TermSearchCtx<'_, 'db, DB>, - _defs: &'a FxHashSet, + _defs: &'a FxHashSet>, lookup: &'lt mut LookupTable<'db>, should_continue: &'a dyn std::ops::Fn() -> bool, ) -> impl Iterator> + use<'a, 'db, 'lt, DB> { @@ -605,7 +605,7 @@ pub(super) fn struct_projection<'a, 'lt, 'db, DB: HirDatabase>( /// * `lookup` - Lookup table for types pub(super) fn famous_types<'a, 'lt, 'db, DB: HirDatabase>( ctx: &'a TermSearchCtx<'_, 'db, DB>, - _defs: &'a FxHashSet, + _defs: &'a FxHashSet>, lookup: &'lt mut LookupTable<'db>, ) -> impl Iterator> + use<'a, 'db, 'lt, DB> { let db = ctx.sema.db; @@ -637,7 +637,7 @@ pub(super) fn famous_types<'a, 'lt, 'db, DB: HirDatabase>( /// * `should_continue` - Function that indicates when to stop iterating pub(super) fn impl_static_method<'a, 'lt, 'db, DB: HirDatabase>( ctx: &'a TermSearchCtx<'_, 'db, DB>, - _defs: &'a FxHashSet, + _defs: &'a FxHashSet>, lookup: &'lt mut LookupTable<'db>, should_continue: &'a dyn std::ops::Fn() -> bool, ) -> impl Iterator> + use<'a, 'db, 'lt, DB> { @@ -745,7 +745,7 @@ pub(super) fn impl_static_method<'a, 'lt, 'db, DB: HirDatabase>( /// * `should_continue` - Function that indicates when to stop iterating pub(super) fn make_tuple<'a, 'lt, 'db, DB: HirDatabase>( ctx: &'a TermSearchCtx<'_, 'db, DB>, - _defs: &'a FxHashSet, + _defs: &'a FxHashSet>, lookup: &'lt mut LookupTable<'db>, should_continue: &'a dyn std::ops::Fn() -> bool, ) -> impl Iterator> + use<'a, 'db, 'lt, DB> { diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_to_enum.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_to_enum.rs index 4c3168219fc63..865995def013e 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_to_enum.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_to_enum.rs @@ -95,16 +95,16 @@ pub(crate) fn convert_bool_to_enum(acc: &mut Assists, ctx: &AssistContext<'_, '_ ) } -struct BoolNodeData { +struct BoolNodeData<'db> { target_node: SyntaxNode, name: ast::Name, ty_annotation: Option, initializer: Option, - definition: Definition, + definition: Definition<'db>, } /// Attempts to find an appropriate node to apply the action to. -fn find_bool_node(ctx: &AssistContext<'_, '_>) -> Option { +fn find_bool_node<'db>(ctx: &AssistContext<'_, 'db>) -> Option> { let name = ctx.find_node_at_offset::()?; if let Some(ident_pat) = name.syntax().parent().and_then(ast::IdentPat::cast) { @@ -213,7 +213,7 @@ fn replace_usages( edit: &mut SourceChangeBuilder, ctx: &AssistContext<'_, '_>, usages: UsageSearchResult, - target_definition: Definition, + target_definition: Definition<'_>, target_module: &hir::Module, delayed_mutations: &mut Vec<(FileId, ImportScope, ast::Path)>, make: &SyntaxFactory, @@ -427,7 +427,7 @@ fn find_negated_usage(name: &ast::NameLike) -> Option<(ast::PrefixExpr, ast::Exp fn find_record_expr_usage( name: &ast::NameLike, got_field: hir::Field, - target_definition: Definition, + target_definition: Definition<'_>, ) -> Option<(ast::RecordExprField, ast::Expr)> { let name_ref = name.as_name_ref()?; let record_field = ast::RecordExprField::for_field_name(name_ref)?; 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 fb7dcdf37179a..eb74e9107581b 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 @@ -169,7 +169,7 @@ fn process_struct_name_reference( r: FileReference, editor: &SyntaxEditor, source: &ast::SourceFile, - strukt_def: &Definition, + strukt_def: &Definition<'_>, names: &[ast::Name], ) -> Option<()> { let make = editor.make(); diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_glob_import.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_glob_import.rs index f5d2a6cfc5198..a2b15fd4c252d 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_glob_import.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_glob_import.rs @@ -238,24 +238,24 @@ fn find_parent_and_path( } } -fn def_is_referenced_in(def: Definition, ctx: &AssistContext<'_, '_>) -> bool { +fn def_is_referenced_in<'db>(def: Definition<'db>, ctx: &AssistContext<'_, 'db>) -> bool { let search_scope = SearchScope::single_file(ctx.file_id()); def.usages(&ctx.sema).in_scope(&search_scope).at_least_one() } #[derive(Debug, Clone)] -struct Ref { +struct Ref<'db> { // could be alias visible_name: Name, - def: Definition, + def: Definition<'db>, is_pub: bool, } -impl Ref { +impl<'db> Ref<'db> { fn from_scope_def( - ctx: &AssistContext<'_, '_>, + ctx: &AssistContext<'_, 'db>, name: Name, - scope_def: ScopeDef, + scope_def: ScopeDef<'db>, ) -> Option { match scope_def { ScopeDef::ModuleDef(def) => Some(Ref { @@ -269,10 +269,10 @@ impl Ref { } #[derive(Debug, Clone)] -struct Refs(Vec); +struct Refs<'db>(Vec>); -impl Refs { - fn used_refs(&self, ctx: &AssistContext<'_, '_>) -> Refs { +impl<'db> Refs<'db> { + fn used_refs(&self, ctx: &AssistContext<'_, 'db>) -> Refs<'db> { Refs( self.0 .clone() @@ -296,18 +296,18 @@ impl Refs { ) } - fn filter_out_by_defs(&self, defs: Vec) -> Refs { + fn filter_out_by_defs(&self, defs: Vec>) -> Refs<'db> { Refs(self.0.clone().into_iter().filter(|r| !defs.contains(&r.def)).collect()) } } -fn find_refs_in_mod( - ctx: &AssistContext<'_, '_>, +fn find_refs_in_mod<'db>( + ctx: &AssistContext<'_, 'db>, expandable: Expandable, current_module: Module, visible_from: Module, must_be_pub: bool, -) -> Refs { +) -> Refs<'db> { match expandable { Expandable::Module(module) => { let module_scope = module.scope(ctx.db(), Some(visible_from)); @@ -376,7 +376,7 @@ fn is_visible_from(ctx: &AssistContext<'_, '_>, expandable: &Expandable, from: M // use foo::*$0; // use baz::Baz; // ↑ --------------- -fn find_imported_defs(ctx: &AssistContext<'_, '_>, use_item: Use) -> Vec { +fn find_imported_defs<'db>(ctx: &AssistContext<'_, 'db>, use_item: Use) -> Vec> { [Direction::Prev, Direction::Next] .into_iter() .flat_map(|dir| { @@ -401,7 +401,10 @@ fn find_imported_defs(ctx: &AssistContext<'_, '_>, use_item: Use) -> Vec) -> Vec { +fn find_names_to_import<'db>( + refs_in_target: Refs<'db>, + imported_defs: Vec>, +) -> Vec { let final_refs = refs_in_target.filter_out_by_defs(imported_defs); final_refs.0.iter().map(|r| r.visible_name.clone()).collect() } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs index f8572dcd3a85f..c2eb49dde5695 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs @@ -324,7 +324,7 @@ struct Function<'db> { control_flow: ControlFlow<'db>, ret_ty: RetType<'db>, body: FunctionBody, - outliving_locals: Vec, + outliving_locals: Vec>, /// Whether at least one of the container's tail expr is contained in the range we're extracting. contains_tail_expr: bool, mods: ContainerInfo<'db>, @@ -332,7 +332,7 @@ struct Function<'db> { #[derive(Debug)] struct Param<'db> { - var: Local, + var: Local<'db>, ty: hir::Type<'db>, move_local: bool, requires_mut: bool, @@ -441,8 +441,8 @@ enum FunctionBody { } #[derive(Debug)] -struct OutlivedLocal { - local: Local, +struct OutlivedLocal<'db> { + local: Local<'db>, mut_usage_outside_body: bool, } @@ -452,7 +452,7 @@ struct OutlivedLocal { struct LocalUsages(ide_db::search::UsageSearchResult); impl LocalUsages { - fn find_local_usages(ctx: &AssistContext<'_, '_>, var: Local) -> Self { + fn find_local_usages<'db>(ctx: &AssistContext<'_, 'db>, var: Local<'db>) -> Self { Self( Definition::Local(var) .usages(&ctx.sema) @@ -807,10 +807,10 @@ impl FunctionBody { impl FunctionBody { /// Analyzes a function body, returning the used local variables that are referenced in it as well as /// whether it contains an await expression. - fn analyze( + fn analyze<'db>( &self, - sema: &Semantics<'_, RootDatabase>, - ) -> (FxIndexSet, Option) { + sema: &Semantics<'db, RootDatabase>, + ) -> (FxIndexSet>, Option) { let mut self_param = None; let mut res = FxIndexSet::default(); @@ -819,7 +819,7 @@ impl FunctionBody { FunctionBody::Span { parent, text_range, .. } => (*text_range, Either::Right(parent)), }; - let mut add_name_if_local = |local_ref: Local| { + let mut add_name_if_local = |local_ref: Local<'db>| { // locals defined inside macros are not relevant to us let InFile { file_id, value } = local_ref.primary_source(sema.db).source; if !file_id.is_macro() { @@ -965,10 +965,10 @@ impl FunctionBody { } /// Local variables defined inside `body` that are accessed outside of it - fn ret_values<'a>( + fn ret_values<'a, 'db>( &self, - ctx: &'a AssistContext<'_, '_>, - ) -> impl Iterator + 'a { + ctx: &'a AssistContext<'_, 'db>, + ) -> impl Iterator> + 'a { let range = self.text_range(); locals_defined_in_body(&ctx.sema, self) .into_iter() @@ -1070,7 +1070,7 @@ impl FunctionBody { &self, ctx: &AssistContext<'_, 'db>, container_info: &ContainerInfo<'db>, - locals: FxIndexSet, + locals: FxIndexSet>, ) -> Vec> { locals .into_iter() @@ -1254,10 +1254,10 @@ fn path_element_of(reference: &FileReference) -> Option { } /// list local variables defined inside `body` -fn locals_defined_in_body( - sema: &Semantics<'_, RootDatabase>, +fn locals_defined_in_body<'db>( + sema: &Semantics<'db, RootDatabase>, body: &FunctionBody, -) -> FxIndexSet { +) -> FxIndexSet> { // FIXME: this doesn't work well with macros // see https://github.com/rust-lang/rust-analyzer/pull/7535#discussion_r570048550 let mut res = FxIndexSet::default(); @@ -1272,11 +1272,11 @@ fn locals_defined_in_body( } /// Returns usage details if local variable is used after(outside of) body -fn local_outlives_body( - ctx: &AssistContext<'_, '_>, +fn local_outlives_body<'db>( + ctx: &AssistContext<'_, 'db>, body_range: TextRange, - local: Local, -) -> Option { + local: Local<'db>, +) -> Option> { let usages = LocalUsages::find_local_usages(ctx, local); let mut has_mut_usages = false; let mut any_outlives = false; @@ -1299,7 +1299,7 @@ fn local_outlives_body( fn is_defined_outside_of_body( ctx: &AssistContext<'_, '_>, body: &FunctionBody, - src: &LocalSource, + src: &LocalSource<'_>, ) -> bool { src.original_file(ctx.db()) == ctx.file_id() && !body.contains_node(src.syntax()) } @@ -1547,7 +1547,7 @@ impl<'db> FlowHandler<'db> { fn path_expr_from_local( make: &SyntaxFactory, ctx: &AssistContext<'_, '_>, - var: Local, + var: Local<'_>, edition: Edition, ) -> ast::Expr { let name = var.name(ctx.db()).display(ctx.db(), edition).to_string(); @@ -2012,10 +2012,10 @@ fn make_ty( make.ty(&ty_str) } -fn rewrite_body_segment( - ctx: &AssistContext<'_, '_>, +fn rewrite_body_segment<'db>( + ctx: &AssistContext<'_, 'db>, to_this_param: Option, - params: &[Param<'_>], + params: &[Param<'db>], handler: &FlowHandler<'_>, syntax: &SyntaxNode, ) -> SyntaxNode { @@ -2030,15 +2030,15 @@ fn rewrite_body_segment( } /// change all usages to account for added `&`/`&mut` for some params -fn fix_param_usages( +fn fix_param_usages<'db>( editor: &SyntaxEditor, source_syntax: &SyntaxNode, syntax: &SyntaxNode, - ctx: &AssistContext<'_, '_>, - to_this_param: Option, - params: &[Param<'_>], + ctx: &AssistContext<'_, 'db>, + to_this_param: Option>, + params: &[Param<'db>], ) { - let mut usages_for_param: Vec<(&Param<'_>, Vec)> = Vec::new(); + let mut usages_for_param: Vec<(&Param<'db>, Vec)> = Vec::new(); let mut usages_for_self_param: Vec = Vec::new(); let source_range = source_syntax.text_range(); let syntax_offset = source_range.start() - syntax.text_range().start(); 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 40c54e98820a8..60a1c7ab44eb0 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 @@ -362,11 +362,11 @@ impl Module { (refs, adt_fields, use_stmts_to_be_inserted) } - fn expand_and_group_usages_file_wise( + fn expand_and_group_usages_file_wise<'db>( &self, - ctx: &AssistContext<'_, '_>, + ctx: &AssistContext<'_, 'db>, replace_range: TextRange, - node_def: Definition, + node_def: Definition<'db>, refs_in_files: &mut FxHashMap>, use_stmts_to_be_inserted: &mut FxHashMap, ) { @@ -535,12 +535,12 @@ impl Module { imports_to_remove } - fn process_def_in_sel( + fn process_def_in_sel<'db>( &mut self, - def: Definition, + def: Definition<'db>, use_node: &SyntaxNode, curr_parent_module: &Option, - ctx: &AssistContext<'_, '_>, + ctx: &AssistContext<'_, 'db>, make: &SyntaxFactory, ) -> Option { //We only need to find in the current file @@ -738,7 +738,7 @@ fn check_intersection_and_push( } fn check_def_in_mod_and_out_sel( - def: Definition, + def: Definition<'_>, ctx: &AssistContext<'_, '_>, curr_parent_module: &Option, selection_range: TextRange, diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs index b75e7d4802d0a..c2c50b16de76f 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs @@ -530,7 +530,7 @@ impl Anchor { } } -fn like_const_value(ctx: &AssistContext<'_, '_>, path_resolution: hir::PathResolution) -> bool { +fn like_const_value(ctx: &AssistContext<'_, '_>, path_resolution: hir::PathResolution<'_>) -> bool { let db = ctx.db(); let adt_like_const_value = |adt: Option| matches!(adt, Some(hir::Adt::Struct(s)) if s.kind(db) == hir::StructKind::Unit); match path_resolution { diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs index 438966a1d67dd..fd67617be45dc 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs @@ -335,12 +335,12 @@ fn get_fn_params<'db>( Some(params) } -fn inline( - sema: &Semantics<'_, RootDatabase>, +fn inline<'db>( + sema: &Semantics<'db, RootDatabase>, function_def_file_id: EditionedFileId, function: hir::Function, fn_body: &ast::BlockExpr, - params: &[(ast::Pat, Option, hir::Param<'_>)], + params: &[(ast::Pat, Option, hir::Param<'db>)], CallInfo { node, arguments, generic_arg_list, krate }: &CallInfo, file_editor: &SyntaxEditor, ) -> ast::Expr { diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_unused_imports.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_unused_imports.rs index 2958acc4783ab..d6582a9559129 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_unused_imports.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_unused_imports.rs @@ -140,7 +140,7 @@ fn is_path_per_ns_unused_in_scope( ctx: &AssistContext<'_, '_>, u: &ast::UseTree, scope: &mut Vec, - path: &PathResolutionPerNs, + path: &PathResolutionPerNs<'_>, ) -> bool { if let Some(PathResolution::Def(ModuleDef::Trait(ref t))) = path.type_ns { if is_trait_unused_in_scope(ctx, u, scope, t) { @@ -159,7 +159,7 @@ fn is_path_unused_in_scope( ctx: &AssistContext<'_, '_>, u: &ast::UseTree, scope: &mut Vec, - path: &[Option], + path: &[Option>], ) -> bool { !path .iter() @@ -182,9 +182,9 @@ fn is_trait_unused_in_scope( .any(|(d, rename)| used_once_in_scope(ctx, d, rename, scope)) } -fn used_once_in_scope( - ctx: &AssistContext<'_, '_>, - def: Definition, +fn used_once_in_scope<'db>( + ctx: &AssistContext<'_, 'db>, + def: Definition<'db>, rename: Option, scopes: &Vec, ) -> bool { diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_named_generic_with_impl.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_named_generic_with_impl.rs index 979f832978632..2be8dd1fbda8e 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_named_generic_with_impl.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_named_generic_with_impl.rs @@ -155,10 +155,10 @@ fn find_path_type( } /// Returns all usage references for the given type parameter definition. -fn find_usages( - sema: &Semantics<'_, RootDatabase>, +fn find_usages<'db>( + sema: &Semantics<'db, RootDatabase>, fn_: &ast::Fn, - type_param_def: Definition, + type_param_def: Definition<'db>, file_id: EditionedFileId, ) -> UsageSearchResult { let file_range = FileRange { file_id, range: fn_.syntax().text_range() }; diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unnecessary_async.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unnecessary_async.rs index 5542180362e16..8bfc3439f4966 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unnecessary_async.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unnecessary_async.rs @@ -90,9 +90,9 @@ pub(crate) fn unnecessary_async(acc: &mut Assists, ctx: &AssistContext<'_, '_>) ) } -fn find_all_references( - ctx: &AssistContext<'_, '_>, - def: &Definition, +fn find_all_references<'db>( + ctx: &AssistContext<'_, 'db>, + def: &Definition<'db>, ) -> impl Iterator { def.usages(&ctx.sema).all().into_iter().flat_map(|(file_id, references)| { references.into_iter().map(move |reference| (file_id, reference)) 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 20048ea97b2c8..f1a34f15d0a5b 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs @@ -222,12 +222,12 @@ impl Completions { }); } - pub(crate) fn add_path_resolution( + pub(crate) fn add_path_resolution<'db>( &mut self, - ctx: &CompletionContext<'_, '_>, + ctx: &CompletionContext<'_, 'db>, path_ctx: &PathCompletionCtx<'_>, local_name: hir::Name, - resolution: hir::ScopeDef, + resolution: hir::ScopeDef<'db>, doc_aliases: Vec, ) { let is_private_editable = match ctx.def_is_visible(&resolution) { @@ -244,12 +244,12 @@ impl Completions { .add_to(self, ctx.db); } - pub(crate) fn add_pattern_resolution( + pub(crate) fn add_pattern_resolution<'db>( &mut self, - ctx: &CompletionContext<'_, '_>, + ctx: &CompletionContext<'_, 'db>, pattern_ctx: &PatternContext, local_name: hir::Name, - resolution: hir::ScopeDef, + resolution: hir::ScopeDef<'db>, ) { let is_private_editable = match ctx.def_is_visible(&resolution) { Visible::Yes => false, diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs index 8d906064c0244..889beeac081ee 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs @@ -44,9 +44,9 @@ where } } -pub(crate) fn complete_expr_path( +pub(crate) fn complete_expr_path<'db>( acc: &mut Completions, - ctx: &CompletionContext<'_, '_>, + ctx: &CompletionContext<'_, 'db>, path_ctx @ PathCompletionCtx { qualified, .. }: &PathCompletionCtx<'_>, expr_ctx: &PathExprCtx<'_>, ) { @@ -87,7 +87,7 @@ pub(crate) fn complete_expr_path( false }; - let scope_def_applicable = |def| match def { + let scope_def_applicable = |def: ScopeDef<'db>| match def { ScopeDef::GenericParam(hir::GenericParam::LifetimeParam(_)) | ScopeDef::Label(_) => false, ScopeDef::ModuleDef(hir::ModuleDef::Macro(mac)) => mac.is_fn_like(ctx.db), _ => true, 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 0b2b6682aaabe..c07c02e28538f 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 @@ -9,15 +9,15 @@ use crate::{ render::render_type_inference, }; -pub(crate) fn complete_type_path( +pub(crate) fn complete_type_path<'db>( acc: &mut Completions, - ctx: &CompletionContext<'_, '_>, + ctx: &CompletionContext<'_, 'db>, path_ctx @ PathCompletionCtx { qualified, .. }: &PathCompletionCtx<'_>, location: &TypeLocation, ) { let _p = tracing::info_span!("complete_type_path").entered(); - let scope_def_applicable = |def| { + let scope_def_applicable = |def: ScopeDef<'db>| { use hir::{GenericParam::*, ModuleDef::*}; match def { ScopeDef::GenericParam(LifetimeParam(_)) => location.complete_lifetimes(), 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 507ecaff0dca0..705305f557e9c 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs @@ -273,7 +273,7 @@ pub(crate) enum Qualified<'db> { No, With { path: ast::Path, - resolution: Option, + resolution: Option>, /// How many `super` segments are present in the path /// /// This would be None, if path is not solely made of @@ -491,7 +491,7 @@ pub(crate) struct CompletionContext<'a, 'db> { pub(crate) qualifier_ctx: QualifierCtx, - pub(crate) locals: FxHashMap, + pub(crate) locals: FxHashMap>, /// The module depth of the current module of the cursor position. /// - crate-root @@ -545,7 +545,7 @@ impl<'db> CompletionContext<'_, 'db> { } /// Checks if an item is visible and not `doc(hidden)` at the completion site. - pub(crate) fn def_is_visible(&self, item: &ScopeDef) -> Visible { + pub(crate) fn def_is_visible(&self, item: &ScopeDef<'db>) -> Visible { match item { ScopeDef::ModuleDef(def) => match def { hir::ModuleDef::Module(it) => self.is_visible(it), @@ -664,7 +664,7 @@ impl<'db> CompletionContext<'_, 'db> { /// A version of [`SemanticsScope::process_all_names`] that filters out `#[doc(hidden)]` items and /// passes all doc-aliases along, to funnel it into `Completions::add_path_resolution`. - pub(crate) fn process_all_names(&self, f: &mut dyn FnMut(Name, ScopeDef, Vec)) { + pub(crate) fn process_all_names(&self, f: &mut dyn FnMut(Name, ScopeDef<'db>, Vec)) { let _p = tracing::info_span!("CompletionContext::process_all_names").entered(); self.scope.process_all_names(&mut |name, def| { if self.is_scope_def_hidden(def) { @@ -675,12 +675,12 @@ impl<'db> CompletionContext<'_, 'db> { }); } - pub(crate) fn process_all_names_raw(&self, f: &mut dyn FnMut(Name, ScopeDef)) { + pub(crate) fn process_all_names_raw(&self, f: &mut dyn FnMut(Name, ScopeDef<'db>)) { let _p = tracing::info_span!("CompletionContext::process_all_names_raw").entered(); self.scope.process_all_names(f); } - fn is_scope_def_hidden(&self, scope_def: ScopeDef) -> bool { + fn is_scope_def_hidden(&self, scope_def: ScopeDef<'db>) -> bool { if let (Some(attrs), Some(krate)) = (scope_def.attrs(self.db), scope_def.krate(self.db)) { return self.is_doc_hidden(&attrs, krate); } @@ -722,7 +722,7 @@ impl<'db> CompletionContext<'_, 'db> { self.krate != defining_crate && attrs.is_doc_hidden() } - pub(crate) fn doc_aliases_in_scope(&self, scope_def: ScopeDef) -> Vec { + pub(crate) fn doc_aliases_in_scope(&self, scope_def: ScopeDef<'db>) -> Vec { if let Some(attrs) = scope_def.attrs(self.db) { attrs.doc_aliases(self.db).iter().map(|it| it.as_str().into()).collect() } else { 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 61281f8cfb8f1..2ff726c6d03e3 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/item.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/item.rs @@ -551,11 +551,11 @@ pub(crate) struct Builder { } impl Builder { - pub(crate) fn from_resolution( - ctx: &CompletionContext<'_, '_>, + pub(crate) fn from_resolution<'db>( + ctx: &CompletionContext<'_, 'db>, path_ctx: &PathCompletionCtx<'_>, local_name: hir::Name, - resolution: hir::ScopeDef, + resolution: hir::ScopeDef<'db>, ) -> Self { let doc_aliases = ctx.doc_aliases_in_scope(resolution); render_path_resolution( 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 7cb1eaa061f3c..9f8a2f71f18c8 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/render.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/render.rs @@ -253,20 +253,20 @@ pub(crate) fn render_type_inference( builder.build(ctx.db) } -pub(crate) fn render_path_resolution( - ctx: RenderContext<'_, '_>, +pub(crate) fn render_path_resolution<'db>( + ctx: RenderContext<'_, 'db>, path_ctx: &PathCompletionCtx<'_>, local_name: hir::Name, - resolution: ScopeDef, + resolution: ScopeDef<'db>, ) -> Builder { render_resolution_path(ctx, path_ctx, local_name, None, resolution) } -pub(crate) fn render_pattern_resolution( - ctx: RenderContext<'_, '_>, +pub(crate) fn render_pattern_resolution<'db>( + ctx: RenderContext<'_, 'db>, pattern_ctx: &PatternContext, local_name: hir::Name, - resolution: ScopeDef, + resolution: ScopeDef<'db>, ) -> Builder { render_resolution_pat(ctx, pattern_ctx, local_name, None, resolution) } @@ -356,9 +356,9 @@ pub(crate) fn render_expr<'db>( Some(item) } -fn get_import_name( - resolution: ScopeDef, - ctx: &RenderContext<'_, '_>, +fn get_import_name<'db>( + resolution: ScopeDef<'db>, + ctx: &RenderContext<'_, 'db>, import_edit: &LocatedImport, ) -> Option { // FIXME: Temporary workaround for handling aliased import. @@ -374,9 +374,9 @@ fn get_import_name( } } -fn scope_def_to_name( - resolution: ScopeDef, - ctx: &RenderContext<'_, '_>, +fn scope_def_to_name<'db>( + resolution: ScopeDef<'db>, + ctx: &RenderContext<'_, 'db>, import_edit: &LocatedImport, ) -> Option { Some(match resolution { @@ -387,12 +387,12 @@ fn scope_def_to_name( }) } -fn render_resolution_pat( - ctx: RenderContext<'_, '_>, +fn render_resolution_pat<'db>( + ctx: RenderContext<'_, 'db>, pattern_ctx: &PatternContext, local_name: hir::Name, import_to_add: Option, - resolution: ScopeDef, + resolution: ScopeDef<'db>, ) -> Builder { let _p = tracing::info_span!("render_resolution_pat").entered(); use hir::ModuleDef::*; @@ -410,7 +410,7 @@ fn render_resolution_path<'db>( path_ctx: &PathCompletionCtx<'_>, local_name: hir::Name, import_to_add: Option, - resolution: ScopeDef, + resolution: ScopeDef<'db>, ) -> Builder { let _p = tracing::info_span!("render_resolution_path").entered(); use hir::ModuleDef::*; @@ -528,11 +528,11 @@ fn render_resolution_path<'db>( item } -fn render_resolution_simple_( - ctx: RenderContext<'_, '_>, +fn render_resolution_simple_<'db>( + ctx: RenderContext<'_, 'db>, local_name: &hir::Name, import_to_add: Option, - resolution: ScopeDef, + resolution: ScopeDef<'db>, ) -> Builder { let _p = tracing::info_span!("render_resolution_simple_").entered(); @@ -558,7 +558,7 @@ fn render_resolution_simple_( item } -fn res_to_kind(resolution: ScopeDef) -> CompletionItemKind { +fn res_to_kind(resolution: ScopeDef<'_>) -> CompletionItemKind { use hir::ModuleDef::*; match resolution { ScopeDef::Unknown => CompletionItemKind::UnresolvedReference, @@ -589,7 +589,10 @@ fn res_to_kind(resolution: ScopeDef) -> CompletionItemKind { } } -fn scope_def_docs(db: &RootDatabase, resolution: ScopeDef) -> Option> { +fn scope_def_docs<'db>( + db: &'db RootDatabase, + resolution: ScopeDef<'db>, +) -> Option> { use hir::ModuleDef::*; match resolution { ScopeDef::ModuleDef(Module(it)) => it.docs(db), @@ -603,7 +606,7 @@ fn scope_def_docs(db: &RootDatabase, resolution: ScopeDef) -> Option, resolution: ScopeDef) -> bool { +fn scope_def_is_deprecated(ctx: &RenderContext<'_, '_>, resolution: ScopeDef<'_>) -> bool { let db = ctx.db(); match resolution { ScopeDef::ModuleDef(hir::ModuleDef::EnumVariant(it)) => ctx.is_variant_deprecated(it), diff --git a/src/tools/rust-analyzer/crates/ide-db/src/defs.rs b/src/tools/rust-analyzer/crates/ide-db/src/defs.rs index 82cff372963a9..52cd66400007e 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/defs.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/defs.rs @@ -22,7 +22,7 @@ use hir::{ Visibility, }; use span::Edition; -use stdx::{format_to, impl_from}; +use stdx::format_to; use syntax::{ SyntaxKind, SyntaxNode, SyntaxToken, ast::{self, AstNode}, @@ -31,10 +31,10 @@ use syntax::{ // FIXME: a more precise name would probably be `Symbol`? #[derive(Debug, PartialEq, Eq, Copy, Clone, Hash)] -pub enum Definition { +pub enum Definition<'db> { Macro(Macro), Field(Field), - TupleField(TupleField), + TupleField(TupleField<'db>), Module(Module), Crate(Crate), Function(Function), @@ -46,7 +46,7 @@ pub enum Definition { TypeAlias(TypeAlias), SelfType(Impl), GenericParam(GenericParam), - Local(Local), + Local(Local<'db>), Label(Label), DeriveHelper(DeriveHelper), BuiltinType(BuiltinType), @@ -58,7 +58,7 @@ pub enum Definition { InlineAsmOperand(InlineAsmOperand), } -impl Definition { +impl<'db> Definition<'db> { pub fn canonical_module_path(&self, db: &RootDatabase) -> Option> { self.module(db).map(|it| it.path_to_root(db).into_iter().rev()) } @@ -104,8 +104,8 @@ impl Definition { Some(module) } - pub fn enclosing_definition(&self, db: &RootDatabase) -> Option { - fn container_to_definition(container: ItemContainer) -> Option { + pub fn enclosing_definition(&self, db: &RootDatabase) -> Option> { + fn container_to_definition<'db>(container: ItemContainer) -> Option> { match container { ItemContainer::Trait(it) => Some(it.into()), ItemContainer::Impl(it) => Some(it.into()), @@ -202,12 +202,12 @@ impl Definition { Some(name) } - pub fn docs<'db>( + pub fn docs<'a>( &self, - db: &'db RootDatabase, + db: &'a RootDatabase, famous_defs: Option<&FamousDefs<'_, '_>>, display_target: DisplayTarget, - ) -> Option> { + ) -> Option> { self.docs_with_rangemap(db, famous_defs, display_target).map(|docs| match docs { Either::Left(Cow::Borrowed(docs)) => Documentation::new_borrowed(docs.docs()), Either::Left(Cow::Owned(docs)) => Documentation::new_owned(docs.into_docs()), @@ -215,12 +215,12 @@ impl Definition { }) } - pub fn docs_with_rangemap<'db>( + pub fn docs_with_rangemap<'a>( &self, - db: &'db RootDatabase, + db: &'a RootDatabase, famous_defs: Option<&FamousDefs<'_, '_>>, display_target: DisplayTarget, - ) -> Option, Documentation<'db>>> { + ) -> Option, Documentation<'a>>> { let docs = match self { Definition::Macro(it) => it.docs_with_rangemap(db), Definition::Field(it) => it.docs_with_rangemap(db), @@ -432,7 +432,7 @@ impl<'db> IdentClass<'db> { .or_else(|| NameClass::classify_lifetime(sema, lifetime).map(IdentClass::NameClass)) } - pub fn definitions(self) -> ArrayVec<(Definition, Option>), 2> { + pub fn definitions(self) -> ArrayVec<(Definition<'db>, Option>), 2> { let mut res = ArrayVec::new(); match self { IdentClass::NameClass(NameClass::Definition(it) | NameClass::ConstReference(it)) => { @@ -473,7 +473,7 @@ impl<'db> IdentClass<'db> { res } - pub fn definitions_no_ops(self) -> ArrayVec { + pub fn definitions_no_ops(self) -> ArrayVec, 2> { let mut res = ArrayVec::new(); match self { IdentClass::NameClass(NameClass::Definition(it) | NameClass::ConstReference(it)) => { @@ -517,14 +517,14 @@ impl<'db> IdentClass<'db> { /// A model special case is `None` constant in pattern. #[derive(Debug)] pub enum NameClass<'db> { - Definition(Definition), + Definition(Definition<'db>), /// `None` in `if let None = Some(82) {}`. /// Syntactically, it is a name, but semantically it is a reference. - ConstReference(Definition), + ConstReference(Definition<'db>), /// `field` in `if let Foo { field } = foo`. Here, `ast::Name` both introduces /// a definition into a local scope, and refers to an existing definition. PatFieldShorthand { - local_def: Local, + local_def: Local<'db>, field_ref: Field, adt_subst: GenericSubstitution<'db>, }, @@ -532,7 +532,7 @@ pub enum NameClass<'db> { impl<'db> NameClass<'db> { /// `Definition` defined by this name. - pub fn defined(self) -> Option { + pub fn defined(self) -> Option> { let res = match self { NameClass::Definition(it) => it, NameClass::ConstReference(_) => return None, @@ -566,10 +566,10 @@ impl<'db> NameClass<'db> { }; return Some(NameClass::Definition(definition)); - fn classify_item( - sema: &Semantics<'_, RootDatabase>, + fn classify_item<'db>( + sema: &Semantics<'db, RootDatabase>, item: ast::Item, - ) -> Option { + ) -> Option> { let definition = match item { ast::Item::MacroRules(it) => { Definition::Macro(sema.to_def(&ast::Macro::MacroRules(it))?) @@ -621,10 +621,10 @@ impl<'db> NameClass<'db> { Some(NameClass::Definition(Definition::Local(local))) } - fn classify_rename( - sema: &Semantics<'_, RootDatabase>, + fn classify_rename<'db>( + sema: &Semantics<'db, RootDatabase>, rename: ast::Rename, - ) -> Option { + ) -> Option> { if let Some(use_tree) = rename.syntax().parent().and_then(ast::UseTree::cast) { let path = use_tree.path()?; sema.resolve_path(&path).map(Definition::from) @@ -722,9 +722,9 @@ impl OperatorClass { /// reference to point to two different defs. #[derive(Debug)] pub enum NameRefClass<'db> { - Definition(Definition, Option>), + Definition(Definition<'db>, Option>), FieldShorthand { - local_ref: Local, + local_ref: Local<'db>, field_ref: Field, adt_subst: GenericSubstitution<'db>, }, @@ -891,31 +891,54 @@ impl<'db> NameRefClass<'db> { } } -impl_from!( - Field, Module, Function, Adt, EnumVariant, Const, Static, Trait, TypeAlias, BuiltinType, Local, - GenericParam, Label, Macro, ExternCrateDecl - for Definition +macro_rules! impl_from_definition { + ($($variant:ident: $ty:ty),* $(,)?) => {$( + impl<'db> From<$ty> for Definition<'db> { + fn from(it: $ty) -> Self { + Definition::$variant(it) + } + } + )*}; +} + +impl_from_definition!( + Field: Field, + TupleField: TupleField<'db>, + Module: Module, + Function: Function, + Adt: Adt, + EnumVariant: EnumVariant, + Const: Const, + Static: Static, + Trait: Trait, + TypeAlias: TypeAlias, + BuiltinType: BuiltinType, + Local: Local<'db>, + GenericParam: GenericParam, + Label: Label, + Macro: Macro, + ExternCrateDecl: ExternCrateDecl, ); -impl From for Definition { +impl<'db> From for Definition<'db> { fn from(impl_: Impl) -> Self { Definition::SelfType(impl_) } } -impl From for Definition { +impl<'db> From for Definition<'db> { fn from(value: InlineAsmOperand) -> Self { Definition::InlineAsmOperand(value) } } -impl From> for Definition { - fn from(value: Either) -> Self { +impl<'db> From, InlineAsmOperand>> for Definition<'db> { + fn from(value: Either, InlineAsmOperand>) -> Self { value.either(Definition::from, Definition::from) } } -impl AsAssocItem for Definition { +impl AsAssocItem for Definition<'_> { fn as_assoc_item(self, db: &dyn hir::db::HirDatabase) -> Option { match self { Definition::Function(it) => it.as_assoc_item(db), @@ -926,7 +949,7 @@ impl AsAssocItem for Definition { } } -impl AsExternAssocItem for Definition { +impl AsExternAssocItem for Definition<'_> { fn as_extern_assoc_item(self, db: &dyn hir::db::HirDatabase) -> Option { match self { Definition::Function(it) => it.as_extern_assoc_item(db), @@ -937,7 +960,7 @@ impl AsExternAssocItem for Definition { } } -impl From for Definition { +impl<'db> From for Definition<'db> { fn from(assoc_item: AssocItem) -> Self { match assoc_item { AssocItem::Function(it) => Definition::Function(it), @@ -947,8 +970,8 @@ impl From for Definition { } } -impl From for Definition { - fn from(path_resolution: PathResolution) -> Self { +impl<'db> From> for Definition<'db> { + fn from(path_resolution: PathResolution<'db>) -> Self { match path_resolution { PathResolution::Def(def) => def.into(), PathResolution::Local(local) => Definition::Local(local), @@ -962,7 +985,7 @@ impl From for Definition { } } -impl From for Definition { +impl<'db> From for Definition<'db> { fn from(def: ModuleDef) -> Self { match def { ModuleDef::Module(it) => Definition::Module(it), @@ -979,7 +1002,7 @@ impl From for Definition { } } -impl From for Definition { +impl<'db> From for Definition<'db> { fn from(def: DocLinkDef) -> Self { match def { DocLinkDef::ModuleDef(it) => it.into(), @@ -989,13 +1012,13 @@ impl From for Definition { } } -impl From for Definition { +impl<'db> From for Definition<'db> { fn from(def: Variant) -> Self { ModuleDef::from(def).into() } } -impl TryFrom for Definition { +impl<'db> TryFrom for Definition<'db> { type Error = (); fn try_from(def: DefWithBody) -> Result { match def { @@ -1007,7 +1030,7 @@ impl TryFrom for Definition { } } -impl From for Definition { +impl<'db> From for Definition<'db> { fn from(def: GenericDef) -> Self { match def { GenericDef::Function(it) => it.into(), @@ -1021,7 +1044,7 @@ impl From for Definition { } } -impl TryFrom for Definition { +impl<'db> TryFrom for Definition<'db> { type Error = (); fn try_from(def: ExpressionStoreOwner) -> Result { match def { @@ -1032,9 +1055,9 @@ impl TryFrom for Definition { } } -impl TryFrom for GenericDef { +impl TryFrom> for GenericDef { type Error = (); - fn try_from(def: Definition) -> Result { + fn try_from(def: Definition<'_>) -> Result { match def { Definition::Function(it) => Ok(it.into()), Definition::Adt(it) => Ok(it.into()), diff --git a/src/tools/rust-analyzer/crates/ide-db/src/famous_defs.rs b/src/tools/rust-analyzer/crates/ide-db/src/famous_defs.rs index f28ce53e91c03..b5f62c8fd7365 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/famous_defs.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/famous_defs.rs @@ -222,7 +222,7 @@ impl FamousDefs<'_, '_> { Some(res) } - fn find_def(&self, path: &str) -> Option { + fn find_def(&self, path: &str) -> Option> { let db = self.0.db; let mut path = path.split(':'); let trait_ = path.next_back()?; diff --git a/src/tools/rust-analyzer/crates/ide-db/src/helpers.rs b/src/tools/rust-analyzer/crates/ide-db/src/helpers.rs index 838aac2283f12..00e81b3ef4300 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/helpers.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/helpers.rs @@ -83,10 +83,10 @@ pub fn mod_path_to_ast_with_factory( } /// Iterates all `ModuleDef`s and `Impl` blocks of the given file. -pub fn visit_file_defs( - sema: &Semantics<'_, RootDatabase>, +pub fn visit_file_defs<'db>( + sema: &Semantics<'db, RootDatabase>, file_id: FileId, - cb: &mut dyn FnMut(Definition), + cb: &mut dyn FnMut(Definition<'db>), ) { let db = sema.db; let module = match sema.file_to_module_def(file_id) { @@ -139,10 +139,10 @@ pub fn is_editable_crate(krate: Crate, db: &RootDatabase) -> bool { } // FIXME: This is a weird function -pub fn get_definition( - sema: &Semantics<'_, RootDatabase>, +pub fn get_definition<'db>( + sema: &Semantics<'db, RootDatabase>, token: SyntaxToken, -) -> Option { +) -> Option> { for token in sema.descend_into_macros_exact(token) { let def = IdentClass::classify_token(sema, &token).map(IdentClass::definitions_no_ops); if let Some(&[x]) = def.as_deref() { diff --git a/src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs b/src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs index 6edc550b331a1..f5dff47acf9ab 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs @@ -461,7 +461,7 @@ impl<'db> ImportAssets<'db> { .into_iter() } - fn scope_definitions(&self, sema: &Semantics<'_, RootDatabase>) -> FxHashSet { + fn scope_definitions<'a>(&self, sema: &Semantics<'a, RootDatabase>) -> FxHashSet> { let _p = tracing::info_span!("ImportAssets::scope_definitions").entered(); let mut scope_definitions = FxHashSet::default(); if let Some(scope) = sema.scope(&self.candidate_node) { diff --git a/src/tools/rust-analyzer/crates/ide-db/src/rename.rs b/src/tools/rust-analyzer/crates/ide-db/src/rename.rs index ff4d5a28866c4..b89c2fdf4ad87 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/rename.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/rename.rs @@ -82,10 +82,10 @@ pub enum RenameDefinition { No, } -impl Definition { +impl<'db> Definition<'db> { pub fn rename( &self, - sema: &Semantics<'_, RootDatabase>, + sema: &Semantics<'db, RootDatabase>, new_name: &str, rename_definition: RenameDefinition, config: &RenameConfig, @@ -345,9 +345,9 @@ fn rename_mod( Ok(source_change) } -fn rename_reference( - sema: &Semantics<'_, RootDatabase>, - def: Definition, +fn rename_reference<'db>( + sema: &Semantics<'db, RootDatabase>, + def: Definition<'db>, new_name: &str, rename_definition: RenameDefinition, edition: Edition, @@ -523,7 +523,7 @@ fn rename_field_constructors( pub fn source_edit_from_references( db: &RootDatabase, references: &[FileReference], - def: Definition, + def: Definition<'_>, new_name: &Name, edition: Edition, ) -> TextEdit { @@ -579,7 +579,7 @@ fn source_edit_from_name_ref( edit: &mut TextEditBuilder, name_ref: &ast::NameRef, new_name: &dyn Display, - def: Definition, + def: Definition<'_>, ) -> bool { if name_ref.super_token().is_some() { return true; @@ -670,10 +670,10 @@ fn source_edit_from_name_ref( false } -fn source_edit_from_def( - sema: &Semantics<'_, RootDatabase>, +fn source_edit_from_def<'db>( + sema: &Semantics<'db, RootDatabase>, config: &RenameConfig, - def: Definition, + def: Definition<'db>, new_name: &Name, source_change: &mut SourceChange, ) -> Result<(FileId, TextEdit)> { diff --git a/src/tools/rust-analyzer/crates/ide-db/src/search.rs b/src/tools/rust-analyzer/crates/ide-db/src/search.rs index d59df3601fbbb..b688cb188d58d 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/search.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/search.rs @@ -286,7 +286,7 @@ impl IntoIterator for SearchScope { } } -impl Definition { +impl<'db> Definition<'db> { fn search_scope(&self, db: &RootDatabase) -> SearchScope { let _p = tracing::info_span!("search_scope").entered(); @@ -440,7 +440,7 @@ impl Definition { } } - pub fn usages<'a, 'db>(self, sema: &'a Semantics<'db, RootDatabase>) -> FindUsages<'a, 'db> { + pub fn usages<'a>(self, sema: &'a Semantics<'db, RootDatabase>) -> FindUsages<'a, 'db> { FindUsages { def: self, rename: None, @@ -457,7 +457,7 @@ impl Definition { #[derive(Clone)] pub struct FindUsages<'a, 'db> { - def: Definition, + def: Definition<'db>, rename: Option<&'a Rename>, sema: &'a Semantics<'db, RootDatabase>, scope: Option<&'a SearchScope>, @@ -678,7 +678,7 @@ impl<'a, 'db> FindUsages<'a, 'db> { db: &RootDatabase, to_process: &mut Vec<(SmolStr, SearchScope)>, alias_name: &str, - def: Definition, + def: Definition<'_>, ) { let alias = alias_name.trim_start_matches("r#").to_smolstr(); tracing::debug!("found alias: {alias}"); @@ -1211,7 +1211,7 @@ impl<'a, 'db> FindUsages<'a, 'db> { file_id: EditionedFileId, range: TextRange, token: ast::String, - res: Either, + res: Either, InlineAsmOperand>, sink: &mut dyn FnMut(EditionedFileId, FileReference) -> bool, ) -> bool { let def = res.either(Definition::from, Definition::from); @@ -1393,7 +1393,10 @@ impl<'a, 'db> FindUsages<'a, 'db> { } } -fn def_to_ty<'db>(sema: &Semantics<'db, RootDatabase>, def: &Definition) -> Option> { +fn def_to_ty<'db>( + sema: &Semantics<'db, RootDatabase>, + def: &Definition<'db>, +) -> Option> { match def { Definition::Adt(adt) => Some(adt.ty(sema.db)), Definition::TypeAlias(it) => Some(it.ty(sema.db)), @@ -1406,7 +1409,7 @@ fn def_to_ty<'db>(sema: &Semantics<'db, RootDatabase>, def: &Definition) -> Opti impl ReferenceCategory { fn new( sema: &Semantics<'_, RootDatabase>, - def: &Definition, + def: &Definition<'_>, r: &ast::NameRef, ) -> ReferenceCategory { let mut result = ReferenceCategory::empty(); diff --git a/src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs b/src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs index 55acf5abf868d..edec86285ba68 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs @@ -29,7 +29,7 @@ use std::{ use base_db::{ CrateOrigin, InternedSourceRootId, LangCrateOrigin, LibraryRoots, LocalRoots, SourceRootId, - source_root_crates, + salsa::Update, source_root_crates, }; use fst::{Automaton, Streamer, raw::IndexedValue}; use hir::{ @@ -40,7 +40,6 @@ use hir::{ }; use itertools::Itertools; use rayon::prelude::*; -use salsa::Update; use crate::RootDatabase; @@ -366,6 +365,25 @@ pub struct SymbolIndex<'db> { map: fst::Map>, } +// SAFETY: +// - It is safe to compare a `SymbolIndex` from a previous revision to a new one. +// - FileSymbol<'db>: Update +unsafe impl<'db> Update for SymbolIndex<'db> +where + FileSymbol<'db>: Update, +{ + unsafe fn maybe_update(old_pointer: *mut Self, new_value: Self) -> bool { + // SAFETY: Safe to dereference as per `salsa::Update` contract. + let this = unsafe { &mut *old_pointer }; + if *this != new_value { + *this = new_value; + true + } else { + false + } + } +} + impl<'db> SymbolIndex<'db> { /// The symbol index for a given source root within library_roots. pub fn library_symbols( @@ -475,18 +493,6 @@ impl Hash for SymbolIndex<'_> { } } -unsafe impl Update for SymbolIndex<'_> { - unsafe fn maybe_update(old_pointer: *mut Self, new_value: Self) -> bool { - let this = unsafe { &mut *old_pointer }; - if *this == new_value { - false - } else { - *this = new_value; - true - } - } -} - impl<'db> SymbolIndex<'db> { fn new(mut symbols: Box<[FileSymbol<'db>]>) -> SymbolIndex<'db> { fn cmp(lhs: &FileSymbol<'_>, rhs: &FileSymbol<'_>) -> Ordering { diff --git a/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_doc_alias.txt b/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_doc_alias.txt index 12eb7e8e0a551..7a59abf36b588 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_doc_alias.txt +++ b/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_doc_alias.txt @@ -41,7 +41,6 @@ is_assoc: false, is_import: false, do_not_complete: Yes, - _marker: PhantomData<&()>, }, FileSymbol { name: "Struct", @@ -78,7 +77,6 @@ is_assoc: false, is_import: false, do_not_complete: Yes, - _marker: PhantomData<&()>, }, FileSymbol { name: "mul1", @@ -115,7 +113,6 @@ is_assoc: false, is_import: false, do_not_complete: Yes, - _marker: PhantomData<&()>, }, FileSymbol { name: "mul2", @@ -152,7 +149,6 @@ is_assoc: false, is_import: false, do_not_complete: Yes, - _marker: PhantomData<&()>, }, FileSymbol { name: "s1", @@ -189,7 +185,6 @@ is_assoc: false, is_import: false, do_not_complete: Yes, - _marker: PhantomData<&()>, }, FileSymbol { name: "s1", @@ -226,7 +221,6 @@ is_assoc: false, is_import: false, do_not_complete: Yes, - _marker: PhantomData<&()>, }, FileSymbol { name: "s2", @@ -263,7 +257,6 @@ is_assoc: false, is_import: false, do_not_complete: Yes, - _marker: PhantomData<&()>, }, ], ), diff --git a/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbol_index_collection.txt b/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbol_index_collection.txt index 0ef19eb493f7c..d0619761c095d 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbol_index_collection.txt +++ b/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbol_index_collection.txt @@ -41,7 +41,6 @@ is_assoc: false, is_import: false, do_not_complete: Yes, - _marker: PhantomData<&()>, }, FileSymbol { name: "Alias", @@ -76,7 +75,6 @@ is_assoc: false, is_import: false, do_not_complete: Yes, - _marker: PhantomData<&()>, }, FileSymbol { name: "B", @@ -113,7 +111,6 @@ is_assoc: false, is_import: false, do_not_complete: Yes, - _marker: PhantomData<&()>, }, FileSymbol { name: "CONST", @@ -148,7 +145,6 @@ is_assoc: false, is_import: false, do_not_complete: Yes, - _marker: PhantomData<&()>, }, FileSymbol { name: "CONST_WITH_INNER", @@ -183,7 +179,6 @@ is_assoc: false, is_import: false, do_not_complete: Yes, - _marker: PhantomData<&()>, }, FileSymbol { name: "Enum", @@ -220,7 +215,6 @@ is_assoc: false, is_import: false, do_not_complete: Yes, - _marker: PhantomData<&()>, }, FileSymbol { name: "ItemLikeMacro", @@ -257,7 +251,6 @@ is_assoc: false, is_import: true, do_not_complete: Yes, - _marker: PhantomData<&()>, }, FileSymbol { name: "Macro", @@ -294,7 +287,6 @@ is_assoc: false, is_import: false, do_not_complete: Yes, - _marker: PhantomData<&()>, }, FileSymbol { name: "STATIC", @@ -329,7 +321,6 @@ is_assoc: false, is_import: false, do_not_complete: Yes, - _marker: PhantomData<&()>, }, FileSymbol { name: "Struct", @@ -366,7 +357,6 @@ is_assoc: false, is_import: false, do_not_complete: Yes, - _marker: PhantomData<&()>, }, FileSymbol { name: "StructFromMacro", @@ -403,7 +393,6 @@ is_assoc: false, is_import: false, do_not_complete: Yes, - _marker: PhantomData<&()>, }, FileSymbol { name: "StructInFn", @@ -442,7 +431,6 @@ is_assoc: false, is_import: false, do_not_complete: Yes, - _marker: PhantomData<&()>, }, FileSymbol { name: "StructInNamedConst", @@ -481,7 +469,6 @@ is_assoc: false, is_import: false, do_not_complete: Yes, - _marker: PhantomData<&()>, }, FileSymbol { name: "StructInUnnamedConst", @@ -518,7 +505,6 @@ is_assoc: false, is_import: false, do_not_complete: Yes, - _marker: PhantomData<&()>, }, FileSymbol { name: "StructT", @@ -555,7 +541,6 @@ is_assoc: false, is_import: false, do_not_complete: Yes, - _marker: PhantomData<&()>, }, FileSymbol { name: "Trait", @@ -590,7 +575,6 @@ is_assoc: false, is_import: false, do_not_complete: Yes, - _marker: PhantomData<&()>, }, FileSymbol { name: "Trait", @@ -627,7 +611,6 @@ is_assoc: false, is_import: true, do_not_complete: Yes, - _marker: PhantomData<&()>, }, FileSymbol { name: "Union", @@ -664,7 +647,6 @@ is_assoc: false, is_import: false, do_not_complete: Yes, - _marker: PhantomData<&()>, }, FileSymbol { name: "a_mod", @@ -699,7 +681,6 @@ is_assoc: false, is_import: false, do_not_complete: Yes, - _marker: PhantomData<&()>, }, FileSymbol { name: "b_mod", @@ -734,7 +715,6 @@ is_assoc: false, is_import: false, do_not_complete: Yes, - _marker: PhantomData<&()>, }, FileSymbol { name: "define_struct", @@ -771,7 +751,6 @@ is_assoc: false, is_import: false, do_not_complete: Yes, - _marker: PhantomData<&()>, }, FileSymbol { name: "generic_impl_fn", @@ -808,7 +787,6 @@ is_assoc: true, is_import: false, do_not_complete: Yes, - _marker: PhantomData<&()>, }, FileSymbol { name: "impl_fn", @@ -845,7 +823,6 @@ is_assoc: true, is_import: false, do_not_complete: Yes, - _marker: PhantomData<&()>, }, FileSymbol { name: "macro_rules_macro", @@ -882,7 +859,6 @@ is_assoc: false, is_import: false, do_not_complete: Yes, - _marker: PhantomData<&()>, }, FileSymbol { name: "main", @@ -917,7 +893,6 @@ is_assoc: false, is_import: false, do_not_complete: Yes, - _marker: PhantomData<&()>, }, FileSymbol { name: "really_define_struct", @@ -954,7 +929,6 @@ is_assoc: false, is_import: true, do_not_complete: Yes, - _marker: PhantomData<&()>, }, FileSymbol { name: "trait_fn", @@ -991,7 +965,6 @@ is_assoc: true, is_import: false, do_not_complete: Yes, - _marker: PhantomData<&()>, }, ], ), @@ -1037,7 +1010,6 @@ is_assoc: false, is_import: false, do_not_complete: Yes, - _marker: PhantomData<&()>, }, ], ), @@ -1081,7 +1053,6 @@ is_assoc: false, is_import: true, do_not_complete: Yes, - _marker: PhantomData<&()>, }, FileSymbol { name: "IsThisJustATrait", @@ -1118,7 +1089,6 @@ is_assoc: false, is_import: true, do_not_complete: Yes, - _marker: PhantomData<&()>, }, FileSymbol { name: "StructInModB", @@ -1155,7 +1125,6 @@ is_assoc: false, is_import: false, do_not_complete: Yes, - _marker: PhantomData<&()>, }, FileSymbol { name: "SuperItemLikeMacro", @@ -1192,7 +1161,6 @@ is_assoc: false, is_import: true, do_not_complete: Yes, - _marker: PhantomData<&()>, }, FileSymbol { name: "ThisStruct", @@ -1229,7 +1197,6 @@ is_assoc: false, is_import: true, do_not_complete: Yes, - _marker: PhantomData<&()>, }, ], ), diff --git a/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbols_exclude_imports.txt b/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbols_exclude_imports.txt index b03d926efe66f..20b162b7cd8c7 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbols_exclude_imports.txt +++ b/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbols_exclude_imports.txt @@ -34,6 +34,5 @@ is_assoc: false, is_import: false, do_not_complete: Yes, - _marker: PhantomData<&()>, }, ] diff --git a/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbols_with_imports.txt b/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbols_with_imports.txt index 84bb6670d7eca..1d475ab005ad7 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbols_with_imports.txt +++ b/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbols_with_imports.txt @@ -34,7 +34,6 @@ is_assoc: false, is_import: false, do_not_complete: Yes, - _marker: PhantomData<&()>, }, FileSymbol { name: "Foo", @@ -71,6 +70,5 @@ is_assoc: false, is_import: true, do_not_complete: Yes, - _marker: PhantomData<&()>, }, ] diff --git a/src/tools/rust-analyzer/crates/ide-db/src/traits.rs b/src/tools/rust-analyzer/crates/ide-db/src/traits.rs index 994427ac76f89..4a560d30ba3ce 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/traits.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/traits.rs @@ -86,7 +86,10 @@ pub fn get_missing_assoc_items( } /// Converts associated trait impl items to their trait definition counterpart -pub(crate) fn convert_to_def_in_trait(db: &dyn HirDatabase, def: Definition) -> Definition { +pub(crate) fn convert_to_def_in_trait<'db>( + db: &'db dyn HirDatabase, + def: Definition<'db>, +) -> Definition<'db> { (|| { let assoc = def.as_assoc_item(db)?; let trait_ = assoc.implemented_trait(db)?; @@ -96,7 +99,10 @@ pub(crate) fn convert_to_def_in_trait(db: &dyn HirDatabase, def: Definition) -> } /// If this is an trait (impl) assoc item, returns the assoc item of the corresponding trait definition. -pub(crate) fn as_trait_assoc_def(db: &dyn HirDatabase, def: Definition) -> Option { +pub(crate) fn as_trait_assoc_def<'db>( + db: &dyn HirDatabase, + def: Definition<'db>, +) -> Option> { let assoc = def.as_assoc_item(db)?; let trait_ = match assoc.container(db) { hir::AssocItemContainer::Trait(_) => return Some(def), @@ -105,11 +111,11 @@ pub(crate) fn as_trait_assoc_def(db: &dyn HirDatabase, def: Definition) -> Optio assoc_item_of_trait(db, assoc, trait_) } -fn assoc_item_of_trait( +fn assoc_item_of_trait<'db>( db: &dyn HirDatabase, assoc: hir::AssocItem, trait_: hir::Trait, -) -> Option { +) -> Option> { use hir::AssocItem::*; let name = match assoc { Function(it) => it.name(db), diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs index e4ee0666534f5..5c6c979416da6 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs @@ -7,7 +7,10 @@ use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext, fix}; // Diagnostic: need-mut // // This diagnostic is triggered on mutating an immutable variable. -pub(crate) fn need_mut(ctx: &DiagnosticsContext<'_, '_>, d: &hir::NeedMut) -> Option { +pub(crate) fn need_mut( + ctx: &DiagnosticsContext<'_, '_>, + d: &hir::NeedMut<'_>, +) -> Option { let root = d.span.file_id.parse_or_expand(ctx.sema.db); let node = d.span.value.to_node(&root); let mut span = d.span; @@ -64,7 +67,7 @@ pub(crate) fn need_mut(ctx: &DiagnosticsContext<'_, '_>, d: &hir::NeedMut) -> Op // This diagnostic is triggered when a mutable variable isn't actually mutated. pub(crate) fn unused_mut( ctx: &DiagnosticsContext<'_, '_>, - d: &hir::UnusedMut, + d: &hir::UnusedMut<'_>, ) -> Option { let ast = d.local.primary_source(ctx.sema.db).syntax_ptr(); let fixes = (|| { diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unused_variables.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unused_variables.rs index dede3b4aad5af..9e5150cf5247c 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unused_variables.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unused_variables.rs @@ -15,7 +15,7 @@ use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext}; // This diagnostic is triggered when a local variable is not used. pub(crate) fn unused_variables( ctx: &DiagnosticsContext<'_, '_>, - d: &hir::UnusedVariable, + d: &hir::UnusedVariable<'_>, ) -> Option { let ast = d.local.primary_source(ctx.sema.db).syntax_ptr(); if ast.file_id.macro_file().is_some() { diff --git a/src/tools/rust-analyzer/crates/ide-ssr/src/resolving.rs b/src/tools/rust-analyzer/crates/ide-ssr/src/resolving.rs index 461de4092e30a..3dbba0ff2dab4 100644 --- a/src/tools/rust-analyzer/crates/ide-ssr/src/resolving.rs +++ b/src/tools/rust-analyzer/crates/ide-ssr/src/resolving.rs @@ -25,13 +25,13 @@ pub(crate) struct ResolvedPattern<'db> { pub(crate) placeholders_by_stand_in: FxHashMap, pub(crate) node: SyntaxNode, // Paths in `node` that we've resolved. - pub(crate) resolved_paths: FxHashMap, + pub(crate) resolved_paths: FxHashMap>, pub(crate) ufcs_function_calls: FxHashMap>, pub(crate) contains_self: bool, } -pub(crate) struct ResolvedPath { - pub(crate) resolution: hir::PathResolution, +pub(crate) struct ResolvedPath<'db> { + pub(crate) resolution: hir::PathResolution<'db>, /// The depth of the ast::Path that was resolved within the pattern. pub(crate) depth: u32, } @@ -120,7 +120,7 @@ impl<'db> Resolver<'_, 'db> { &self, node: SyntaxNode, depth: u32, - resolved_paths: &mut FxHashMap, + resolved_paths: &mut FxHashMap>, ) -> Result<(), SsrError> { use syntax::ast::AstNode; if let Some(path) = ast::Path::cast(node.clone()) { @@ -165,7 +165,7 @@ impl<'db> Resolver<'_, 'db> { false } - fn ok_to_use_path_resolution(&self, resolution: &hir::PathResolution) -> bool { + fn ok_to_use_path_resolution(&self, resolution: &hir::PathResolution<'db>) -> bool { match resolution { hir::PathResolution::Def(hir::ModuleDef::Function(function)) if function.as_assoc_item(self.resolution_scope.scope.db).is_some() => @@ -215,7 +215,7 @@ impl<'db> ResolutionScope<'db> { self.node.ancestors().find(|node| node.kind() == SyntaxKind::FN) } - fn resolve_path(&self, path: &ast::Path) -> Option { + fn resolve_path(&self, path: &ast::Path) -> Option> { // First try resolving the whole path. This will work for things like // `std::collections::HashMap`, but will fail for things like // `std::collections::HashMap::new`. diff --git a/src/tools/rust-analyzer/crates/ide-ssr/src/search.rs b/src/tools/rust-analyzer/crates/ide-ssr/src/search.rs index 51e4951cf662b..c6a1d69672119 100644 --- a/src/tools/rust-analyzer/crates/ide-ssr/src/search.rs +++ b/src/tools/rust-analyzer/crates/ide-ssr/src/search.rs @@ -17,8 +17,8 @@ use syntax::{AstNode, SyntaxKind, SyntaxNode, ast}; /// and as a pattern. In each, the usages of `foo::Bar` are the same and we'd like to avoid finding /// them more than once. #[derive(Default)] -pub(crate) struct UsageCache { - usages: Vec<(Definition, UsageSearchResult)>, +pub(crate) struct UsageCache<'db> { + usages: Vec<(Definition<'db>, UsageSearchResult)>, } impl<'db> MatchFinder<'db> { @@ -28,7 +28,7 @@ impl<'db> MatchFinder<'db> { pub(crate) fn find_matches_for_rule( &self, rule: &ResolvedRule<'db>, - usage_cache: &mut UsageCache, + usage_cache: &mut UsageCache<'db>, matches_out: &mut Vec, ) { if rule.pattern.contains_self { @@ -51,11 +51,11 @@ impl<'db> MatchFinder<'db> { &self, rule: &ResolvedRule<'db>, pattern: &ResolvedPattern<'db>, - usage_cache: &mut UsageCache, + usage_cache: &mut UsageCache<'db>, matches_out: &mut Vec, ) { if let Some(resolved_path) = pick_path_for_usages(pattern) { - let definition: Definition = resolved_path.resolution.into(); + let definition: Definition<'db> = resolved_path.resolution.into(); for file_range in self.find_usages(usage_cache, definition).file_ranges() { for node_to_match in self.find_nodes_to_match(resolved_path, file_range) { if !is_search_permitted_ancestors(&node_to_match) { @@ -70,7 +70,7 @@ impl<'db> MatchFinder<'db> { fn find_nodes_to_match( &self, - resolved_path: &ResolvedPath, + resolved_path: &ResolvedPath<'db>, file_range: FileRange, ) -> Vec { let file = self.sema.parse(file_range.file_id); @@ -112,8 +112,8 @@ impl<'db> MatchFinder<'db> { fn find_usages<'a>( &self, - usage_cache: &'a mut UsageCache, - definition: Definition, + usage_cache: &'a mut UsageCache<'db>, + definition: Definition<'db>, ) -> &'a UsageSearchResult { // Logically if a lookup succeeds we should just return it. Unfortunately returning it would // extend the lifetime of the borrow, then we wouldn't be able to do the insertion on a @@ -252,8 +252,8 @@ fn is_search_permitted(node: &SyntaxNode) -> bool { node.kind() != SyntaxKind::USE } -impl UsageCache { - fn find(&mut self, definition: &Definition) -> Option<&UsageSearchResult> { +impl<'db> UsageCache<'db> { + fn find(&mut self, definition: &Definition<'db>) -> Option<&UsageSearchResult> { // We expect a very small number of cache entries (generally 1), so a linear scan should be // fast enough and avoids the need to implement Hash for Definition. for (d, refs) in &self.usages { @@ -268,7 +268,9 @@ impl UsageCache { /// Returns a path that's suitable for path resolution. We exclude builtin types, since they aren't /// something that we can find references to. We then somewhat arbitrarily pick the path that is the /// longest as this is hopefully more likely to be less common, making it faster to find. -fn pick_path_for_usages<'a>(pattern: &'a ResolvedPattern<'_>) -> Option<&'a ResolvedPath> { +fn pick_path_for_usages<'a, 'db>( + pattern: &'a ResolvedPattern<'db>, +) -> Option<&'a ResolvedPath<'db>> { // FIXME: Take the scope of the resolved path into account. e.g. if there are any paths that are // private to the current module, then we definitely would want to pick them over say a path // from std. Possibly we should go further than this and intersect the search scopes for all diff --git a/src/tools/rust-analyzer/crates/ide/src/doc_links.rs b/src/tools/rust-analyzer/crates/ide/src/doc_links.rs index fd462d003d7dd..70d05cd3b5dcc 100644 --- a/src/tools/rust-analyzer/crates/ide/src/doc_links.rs +++ b/src/tools/rust-analyzer/crates/ide/src/doc_links.rs @@ -53,7 +53,7 @@ const MARKDOWN_OPTIONS: Options = pub(crate) fn rewrite_links( db: &RootDatabase, markdown: &str, - definition: Definition, + definition: Definition<'_>, range_map: Option<&hir::Docs>, ) -> String { let mut cb = broken_link_clone_cb; @@ -207,13 +207,13 @@ pub(crate) fn extract_definitions_from_docs( .collect() } -pub(crate) fn resolve_doc_path_for_def( +pub(crate) fn resolve_doc_path_for_def<'db>( db: &dyn HirDatabase, - def: Definition, + def: Definition<'db>, link: &str, ns: Option, is_inner_doc: hir::IsInnerDoc, -) -> Option { +) -> Option> { match def { Definition::Module(it) => it.resolve_doc_path(db, link, ns, is_inner_doc), Definition::Crate(it) => it.resolve_doc_path(db, link, ns, is_inner_doc), @@ -243,10 +243,10 @@ pub(crate) fn resolve_doc_path_for_def( .map(Definition::from) } -pub(crate) fn doc_attributes( - sema: &Semantics<'_, RootDatabase>, +pub(crate) fn doc_attributes<'db>( + sema: &Semantics<'db, RootDatabase>, node: &SyntaxNode, -) -> Option<(hir::AttrsWithOwner, Definition)> { +) -> Option<(hir::AttrsWithOwner, Definition<'db>)> { match_ast! { match node { ast::SourceFile(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::from(def))), @@ -293,12 +293,12 @@ pub(crate) fn token_as_doc_comment(doc_token: &SyntaxToken) -> Option( + pub(crate) fn get_definition_with_descend_at<'db, T>( self, - sema: &Semantics<'_, RootDatabase>, + sema: &Semantics<'db, RootDatabase>, offset: TextSize, // Definition, CommentOwner, range of intra doc link in original file - mut cb: impl FnMut(Definition, SyntaxNode, TextRange) -> Option, + mut cb: impl FnMut(Definition<'db>, SyntaxNode, TextRange) -> Option, ) -> Option { let DocCommentToken { prefix_len, doc_token } = self; // offset relative to the comments contents @@ -346,11 +346,11 @@ impl DocCommentToken { /// //! [`S$0`] /// } /// ``` - fn doc_attributes( - sema: &Semantics<'_, RootDatabase>, + fn doc_attributes<'db>( + sema: &Semantics<'db, RootDatabase>, node: &SyntaxNode, is_inner_doc: bool, - ) -> Option<(AttrsWithOwner, Definition)> { + ) -> Option<(AttrsWithOwner, Definition<'db>)> { if is_inner_doc && node.kind() != SOURCE_FILE { let parent = node.parent()?; doc_attributes(sema, &parent).or(doc_attributes(sema, &parent.parent()?)) @@ -373,7 +373,7 @@ fn broken_link_clone_cb(link: BrokenLink<'_>) -> Option<(CowStr<'_>, CowStr<'_>) // https://github.com/rust-lang/rfcs/pull/2988 fn get_doc_links( db: &RootDatabase, - def: Definition, + def: Definition<'_>, target_dir: Option<&str>, sysroot: Option<&str>, ) -> DocumentationLinks { @@ -411,7 +411,7 @@ fn get_doc_links( fn rewrite_intra_doc_link( db: &RootDatabase, - def: Definition, + def: Definition<'_>, target: &str, title: &str, is_inner_doc: hir::IsInnerDoc, @@ -455,7 +455,7 @@ fn rewrite_intra_doc_link( } /// Try to resolve path to local documentation via path-based links (i.e. `../gateway/struct.Shard.html`). -fn rewrite_url_link(db: &RootDatabase, def: Definition, target: &str) -> Option { +fn rewrite_url_link(db: &RootDatabase, def: Definition<'_>, target: &str) -> Option { if !(target.contains('#') || target.contains(".html")) { return None; } @@ -472,7 +472,7 @@ fn rewrite_url_link(db: &RootDatabase, def: Definition, target: &str) -> Option< url.join(target).ok().map(Into::into) } -fn mod_path_of_def(db: &RootDatabase, def: Definition) -> Option { +fn mod_path_of_def(db: &RootDatabase, def: Definition<'_>) -> Option { def.canonical_module_path(db).map(|it| { let mut path = String::new(); it.flat_map(|it| it.name(db)).for_each(|name| format_to!(path, "{}/", name.as_str())); @@ -540,7 +540,7 @@ fn map_links<'e>( /// ``` fn get_doc_base_urls( db: &RootDatabase, - def: Definition, + def: Definition<'_>, target_dir: Option<&str>, sysroot: Option<&str>, ) -> (Option, Option) { @@ -632,10 +632,10 @@ fn get_doc_base_urls( /// https://doc.rust-lang.org/std/iter/trait.Iterator.html#tymethod.next /// ^^^^^^^^^^^^^^^^^^^ /// ``` -fn filename_and_frag_for_def( +fn filename_and_frag_for_def<'db>( db: &dyn HirDatabase, - def: Definition, -) -> Option<(Definition, String, Option)> { + def: Definition<'db>, +) -> Option<(Definition<'db>, String, Option)> { if let Some(assoc_item) = def.as_assoc_item(db) { let def = match assoc_item.container(db) { AssocItemContainer::Trait(t) => t.into(), diff --git a/src/tools/rust-analyzer/crates/ide/src/doc_links/tests.rs b/src/tools/rust-analyzer/crates/ide/src/doc_links/tests.rs index 509c55a31e58d..720528d0b52f2 100644 --- a/src/tools/rust-analyzer/crates/ide/src/doc_links/tests.rs +++ b/src/tools/rust-analyzer/crates/ide/src/doc_links/tests.rs @@ -86,7 +86,7 @@ fn check_doc_links(#[rust_analyzer::rust_fixture] ra_fixture: &str) { fn def_under_cursor<'db>( sema: &Semantics<'db, RootDatabase>, position: &FilePosition, -) -> (Definition, Cow<'db, hir::Docs>) { +) -> (Definition<'db>, Cow<'db, hir::Docs>) { let (docs, def) = sema .parse_guess_edition(position.file_id) .syntax() @@ -104,7 +104,7 @@ fn def_under_cursor<'db>( fn node_to_def<'db>( sema: &Semantics<'db, RootDatabase>, node: &SyntaxNode, -) -> Option>, Definition)>> { +) -> Option>, Definition<'db>)>> { Some(match_ast! { match node { ast::SourceFile(it) => sema.to_def(&it).map(|def| (def.docs_with_rangemap(sema.db), Definition::Module(def))), 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 b6d1689437ff1..b778066f42728 100644 --- a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs +++ b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs @@ -399,7 +399,7 @@ fn try_lookup_macro_def_in_macro_use( /// ``` fn try_filter_trait_item_definition( sema: &Semantics<'_, RootDatabase>, - def: &Definition, + def: &Definition<'_>, ) -> Option> { let db = sema.db; let assoc = def.as_assoc_item(db)?; @@ -653,7 +653,7 @@ fn nav_for_break_points( Some(navs) } -fn def_to_nav(sema: &Semantics<'_, RootDatabase>, def: Definition) -> Vec { +fn def_to_nav(sema: &Semantics<'_, RootDatabase>, def: Definition<'_>) -> Vec { def.try_to_nav(sema).map(|it| it.collect()).unwrap_or_default() } diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_type_definition.rs b/src/tools/rust-analyzer/crates/ide/src/goto_type_definition.rs index ffd144a827e34..9de956be5ed19 100644 --- a/src/tools/rust-analyzer/crates/ide/src/goto_type_definition.rs +++ b/src/tools/rust-analyzer/crates/ide/src/goto_type_definition.rs @@ -29,7 +29,7 @@ pub(crate) fn goto_type_definition( })?; let mut res = Vec::new(); - let mut push = |def: Definition| { + let mut push = |def: Definition<'_>| { if let Some(navs) = def.try_to_nav(&sema) { for nav in navs { if !res.contains(&nav) { diff --git a/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs b/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs index db5464a1fe93a..dfe8dcaa7745a 100644 --- a/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs +++ b/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs @@ -668,7 +668,10 @@ fn cover_range(r0: Option, r1: Option) -> Option, token: SyntaxToken) -> FxHashSet { +fn find_defs<'db>( + sema: &Semantics<'db, RootDatabase>, + token: SyntaxToken, +) -> FxHashSet> { sema.descend_into_macros_exact(token) .into_iter() .filter_map(|token| IdentClass::classify_token(sema, &token)) diff --git a/src/tools/rust-analyzer/crates/ide/src/hover.rs b/src/tools/rust-analyzer/crates/ide/src/hover.rs index 28e1dc72bf4cd..3d73b5b0f24d4 100644 --- a/src/tools/rust-analyzer/crates/ide/src/hover.rs +++ b/src/tools/rust-analyzer/crates/ide/src/hover.rs @@ -450,7 +450,7 @@ fn hover_ranged( pub(crate) fn hover_for_definition( sema: &Semantics<'_, RootDatabase>, file_id: FileId, - def: Definition, + def: Definition<'_>, subst: Option>, scope_node: &SyntaxNode, macro_arm: Option, @@ -568,7 +568,7 @@ fn notable_traits<'db>( fn show_implementations_action( sema: &Semantics<'_, RootDatabase>, - def: Definition, + def: Definition<'_>, ) -> Option { fn to_action(nav_target: NavigationTarget) -> HoverAction { HoverAction::Implementation(FilePosition { @@ -590,7 +590,7 @@ fn show_implementations_action( fn show_fn_references_action( sema: &Semantics<'_, RootDatabase>, - def: Definition, + def: Definition<'_>, ) -> Option { match def { Definition::Function(it) => { @@ -607,7 +607,7 @@ fn show_fn_references_action( fn runnable_action( sema: &hir::Semantics<'_, RootDatabase>, - def: Definition, + def: Definition<'_>, file_id: FileId, ) -> Option { match def { @@ -628,7 +628,7 @@ fn runnable_action( fn goto_type_action_for_def( sema: &Semantics<'_, RootDatabase>, - def: Definition, + def: Definition<'_>, notable_traits: &[(hir::Trait, Vec<(Option>, hir::Name)>)], subst_types: Option)>>, edition: Edition, 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 638ea6bdb9773..88d21b23e849a 100644 --- a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs +++ b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs @@ -338,7 +338,7 @@ pub(super) fn try_for_lint(attr: &ast::Attr, token: &SyntaxToken) -> Option, markup: &Markup, markup_range_map: Option, config: &HoverConfig<'_>, @@ -352,7 +352,11 @@ pub(super) fn process_markup( Markup::from(markup) } -fn definition_owner_name(db: &RootDatabase, def: Definition, edition: Edition) -> Option { +fn definition_owner_name( + db: &RootDatabase, + def: Definition<'_>, + edition: Edition, +) -> Option { match def { Definition::Field(f) => { let parent = f.parent_def(db); @@ -445,7 +449,7 @@ pub(super) fn path( pub(super) fn definition( db: &RootDatabase, - def: Definition, + def: Definition<'_>, famous_defs: Option<&FamousDefs<'_, '_>>, notable_traits: &[(Trait, Vec<(Option>, Name)>)], macro_arm: Option, @@ -1077,7 +1081,7 @@ fn closure_ty( Some(res) } -fn definition_path(db: &RootDatabase, &def: &Definition, edition: Edition) -> Option { +fn definition_path(db: &RootDatabase, &def: &Definition<'_>, edition: Edition) -> Option { if matches!( def, Definition::TupleField(_) diff --git a/src/tools/rust-analyzer/crates/ide/src/interpret.rs b/src/tools/rust-analyzer/crates/ide/src/interpret.rs index 994d325cccde6..f8e8d874492c3 100644 --- a/src/tools/rust-analyzer/crates/ide/src/interpret.rs +++ b/src/tools/rust-analyzer/crates/ide/src/interpret.rs @@ -60,7 +60,7 @@ fn find_and_interpret(db: &RootDatabase, position: FilePosition) -> Option<(Dura pub(crate) fn render_const_eval_error( db: &RootDatabase, - e: ConstEvalError, + e: ConstEvalError<'_>, display_target: DisplayTarget, ) -> String { let span_formatter = |file_id, text_range: TextRange| { diff --git a/src/tools/rust-analyzer/crates/ide/src/moniker.rs b/src/tools/rust-analyzer/crates/ide/src/moniker.rs index 335e1b5b13caa..c92f2bbace84a 100644 --- a/src/tools/rust-analyzer/crates/ide/src/moniker.rs +++ b/src/tools/rust-analyzer/crates/ide/src/moniker.rs @@ -118,7 +118,7 @@ pub enum MonikerResult { } impl MonikerResult { - pub fn from_def(db: &RootDatabase, def: Definition, from_crate: Crate) -> Option { + pub fn from_def(db: &RootDatabase, def: Definition<'_>, from_crate: Crate) -> Option { def_to_moniker(db, def, from_crate) } } @@ -178,7 +178,7 @@ pub(crate) fn moniker( Some(RangeInfo::new(original_token.text_range(), navs)) } -pub(crate) fn def_to_kind(db: &RootDatabase, def: Definition) -> SymbolInformationKind { +pub(crate) fn def_to_kind(db: &RootDatabase, def: Definition<'_>) -> SymbolInformationKind { use SymbolInformationKind::*; match def { @@ -250,7 +250,7 @@ pub(crate) fn def_to_kind(db: &RootDatabase, def: Definition) -> SymbolInformati /// definitions. pub(crate) fn def_to_moniker( db: &RootDatabase, - definition: Definition, + definition: Definition<'_>, from_crate: Crate, ) -> Option { match definition { @@ -266,7 +266,7 @@ pub(crate) fn def_to_moniker( fn enclosing_def_to_moniker( db: &RootDatabase, - mut def: Definition, + mut def: Definition<'_>, from_crate: Crate, ) -> Option { loop { @@ -280,7 +280,7 @@ fn enclosing_def_to_moniker( fn def_to_non_local_moniker( db: &RootDatabase, - definition: Definition, + definition: Definition<'_>, from_crate: Crate, ) -> Option { let module = match definition { 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 fd6c8263f9d8c..125b2f495acca 100644 --- a/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs +++ b/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs @@ -296,7 +296,7 @@ impl<'db> TryToNav for FileSymbol<'db> { } } -impl TryToNav for Definition { +impl TryToNav for Definition<'_> { fn try_to_nav( &self, sema: &Semantics<'_, RootDatabase>, @@ -640,7 +640,7 @@ impl TryToNav for hir::GenericParam { } } -impl ToNav for LocalSource { +impl ToNav for LocalSource<'_> { fn to_nav(&self, db: &RootDatabase) -> UpmappingResult { let InFile { file_id, value } = &self.source; let file_id = *file_id; @@ -675,7 +675,7 @@ impl ToNav for LocalSource { } } -impl ToNav for hir::Local { +impl ToNav for hir::Local<'_> { fn to_nav(&self, db: &RootDatabase) -> UpmappingResult { self.primary_source(db).to_nav(db) } diff --git a/src/tools/rust-analyzer/crates/ide/src/references.rs b/src/tools/rust-analyzer/crates/ide/src/references.rs index 34286c4790b7d..d85e01af41d65 100644 --- a/src/tools/rust-analyzer/crates/ide/src/references.rs +++ b/src/tools/rust-analyzer/crates/ide/src/references.rs @@ -121,8 +121,8 @@ pub struct FindAllRefsConfig<'a> { /// - `;` after unit struct: Shows unit literal initializations /// - Type name in definition: Shows all initialization usages /// In these cases, other kinds of references (like type references) are filtered out. -pub(crate) fn find_all_refs( - sema: &Semantics<'_, RootDatabase>, +pub(crate) fn find_all_refs<'db>( + sema: &Semantics<'db, RootDatabase>, position: FilePosition, config: &FindAllRefsConfig<'_>, ) -> Option> { @@ -130,7 +130,7 @@ pub(crate) fn find_all_refs( let syntax = sema.parse_guess_edition(position.file_id).syntax().clone(); let exclude_library_refs = !is_library_file(sema.db, position.file_id); let make_searcher = |literal_search: bool| { - move |def: Definition| { + move |def: Definition<'db>| { let mut included_categories = ReferenceCategory::all(); if config.exclude_imports { included_categories.remove(ReferenceCategory::IMPORT); @@ -228,11 +228,11 @@ fn is_library_file(db: &RootDatabase, file_id: FileId) -> bool { db.source_root(source_root).source_root(db).is_library } -pub(crate) fn find_defs( - sema: &Semantics<'_, RootDatabase>, +pub(crate) fn find_defs<'db>( + sema: &Semantics<'db, RootDatabase>, syntax: &SyntaxNode, offset: TextSize, -) -> Option> { +) -> Option>> { if let Some(token) = syntax.token_at_offset(offset).left_biased() && let Some(doc_comment) = token_as_doc_comment(&token) { @@ -304,7 +304,7 @@ pub(crate) fn find_defs( /// Filter out all non-literal usages for adt-defs fn retain_adt_literal_usages( usages: &mut UsageSearchResult, - def: Definition, + def: Definition<'_>, sema: &Semantics<'_, RootDatabase>, ) { let refs = usages.references.values_mut(); diff --git a/src/tools/rust-analyzer/crates/ide/src/rename.rs b/src/tools/rust-analyzer/crates/ide/src/rename.rs index 185815fa73197..4a2cc5f551b6e 100644 --- a/src/tools/rust-analyzer/crates/ide/src/rename.rs +++ b/src/tools/rust-analyzer/crates/ide/src/rename.rs @@ -274,13 +274,14 @@ fn alias_fallback( Some(builder.finish()) } -fn find_definitions( - sema: &Semantics<'_, RootDatabase>, +fn find_definitions<'db>( + sema: &Semantics<'db, RootDatabase>, syntax: &SyntaxNode, FilePosition { file_id, offset }: FilePosition, new_name: &Name, -) -> RenameResult> -{ +) -> RenameResult< + impl Iterator, Name, RenameDefinition)>, +> { let maybe_format_args = syntax.token_at_offset(offset).find(|t| matches!(t.kind(), SyntaxKind::STRING)); @@ -492,9 +493,9 @@ fn transform_assoc_fn_into_method_call( } } -fn rename_to_self( - sema: &Semantics<'_, RootDatabase>, - local: hir::Local, +fn rename_to_self<'db>( + sema: &Semantics<'db, RootDatabase>, + local: hir::Local<'db>, ) -> RenameResult { if never!(local.is_self(sema.db)) { bail!("rename_to_self invoked on self"); @@ -749,9 +750,9 @@ fn transform_method_call_into_assoc_fn( } } -fn rename_self_to_param( - sema: &Semantics<'_, RootDatabase>, - local: hir::Local, +fn rename_self_to_param<'db>( + sema: &Semantics<'db, RootDatabase>, + local: hir::Local<'db>, self_param: hir::SelfParam, new_name: &Name, identifier_kind: IdentifierKind, diff --git a/src/tools/rust-analyzer/crates/ide/src/runnables.rs b/src/tools/rust-analyzer/crates/ide/src/runnables.rs index ce4e5cf97fb24..77d1d5a23f5a5 100644 --- a/src/tools/rust-analyzer/crates/ide/src/runnables.rs +++ b/src/tools/rust-analyzer/crates/ide/src/runnables.rs @@ -487,7 +487,7 @@ fn runnable_mod_outline_definition( }) } -fn module_def_doctest(sema: &Semantics<'_, RootDatabase>, def: Definition) -> Option { +fn module_def_doctest(sema: &Semantics<'_, RootDatabase>, def: Definition<'_>) -> Option { let db = sema.db; let attrs = match def { Definition::Module(it) => it.attrs(db), 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 db24c8dd0687c..9e8d772cb3d12 100644 --- a/src/tools/rust-analyzer/crates/ide/src/static_index.rs +++ b/src/tools/rust-analyzer/crates/ide/src/static_index.rs @@ -31,7 +31,7 @@ pub struct StaticIndex<'a> { pub tokens: TokenStore, analysis: &'a Analysis, db: &'a RootDatabase, - def_map: FxHashMap, + def_map: FxHashMap, TokenId>, } #[derive(Debug)] @@ -131,7 +131,7 @@ fn all_modules(db: &dyn HirDatabase) -> Vec { fn documentation_for_definition( sema: &Semantics<'_, RootDatabase>, - def: Definition, + def: Definition<'_>, scope_node: &SyntaxNode, ) -> Option> { let famous_defs = match &def { @@ -147,7 +147,7 @@ fn documentation_for_definition( fn get_definitions<'db>( sema: &Semantics<'db, RootDatabase>, token: SyntaxToken, -) -> Option>), 2>> { +) -> Option, Option>), 2>> { for token in sema.descend_into_macros_exact(token) { let def = IdentClass::classify_token(sema, &token).map(IdentClass::definitions); if let Some(defs) = def @@ -164,7 +164,7 @@ pub enum VendoredLibrariesConfig<'a> { Excluded, } -impl StaticIndex<'_> { +impl<'a> StaticIndex<'a> { fn add_file(&mut self, file_id: FileId) { let current_crate = crates_for(self.db, file_id).pop().map(Into::into); let folds = self.analysis.folding_ranges(file_id, true).unwrap(); @@ -195,7 +195,7 @@ impl StaticIndex<'_> { }; let mut result = StaticIndexedFile { file_id, folds, tokens: vec![] }; - let mut add_token = |def: Definition, range: TextRange, scope_node: &SyntaxNode| { + let mut add_token = |def: Definition<'a>, range: TextRange, scope_node: &SyntaxNode| { let id = if let Some(it) = self.def_map.get(&def) { *it } else { @@ -265,7 +265,7 @@ impl StaticIndex<'_> { self.files.push(result); } - pub fn compute<'a>( + pub fn compute( analysis: &'a Analysis, vendored_libs_config: VendoredLibrariesConfig<'_>, ) -> StaticIndex<'a> { 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 6823736d12730..92daacd6d314f 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 @@ -457,7 +457,7 @@ fn highlight_name( pub(super) fn highlight_def( sema: &Semantics<'_, RootDatabase>, krate: Option, - def: Definition, + def: Definition<'_>, edition: Edition, is_ref: bool, ) -> Highlight { @@ -864,7 +864,7 @@ fn highlight_name_ref_by_syntax( } } -fn is_consumed_lvalue(node: &SyntaxNode, local: &hir::Local, db: &RootDatabase) -> bool { +fn is_consumed_lvalue(node: &SyntaxNode, local: &hir::Local<'_>, db: &RootDatabase) -> bool { // When lvalues are passed as arguments and they're not Copy, then mark them as Consuming. parents_match(node.clone().into(), &[PATH_SEGMENT, PATH, PATH_EXPR, ARG_LIST]) && !local.ty(db).is_copy(db) 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 9af6d67b59803..56020b401780a 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 @@ -211,7 +211,7 @@ pub(super) fn doc_comment( } } -fn module_def_to_hl_tag(db: &dyn HirDatabase, def: Definition) -> HlTag { +fn module_def_to_hl_tag(db: &dyn HirDatabase, def: Definition<'_>) -> HlTag { let symbol = match def { Definition::Crate(_) | Definition::ExternCrateDecl(_) => SymbolKind::CrateRoot, Definition::Module(m) if m.is_crate_root(db) => SymbolKind::CrateRoot, From e7077ffe68d0e03700f1a8e8f994b2ebd0401d1b Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sun, 19 Jul 2026 13:25:19 +0200 Subject: [PATCH 10/76] internal: Pack `ExprOrPatId` when stored --- .../crates/hir-def/src/expr_store.rs | 28 ++++--- .../rust-analyzer/crates/hir-def/src/hir.rs | 84 +++++++++++++++++-- .../rust-analyzer/crates/hir-ty/src/infer.rs | 63 +++++++------- .../hir-ty/src/infer/closure/analysis.rs | 4 +- .../closure/analysis/expr_use_visitor.rs | 26 +++--- .../crates/hir-ty/src/infer/diagnostics.rs | 13 +-- .../crates/hir-ty/src/infer/expr.rs | 8 +- .../crates/hir-ty/src/infer/pat.rs | 6 +- .../crates/hir-ty/src/infer/path.rs | 19 +++-- .../rust-analyzer/crates/hir-ty/src/lib.rs | 8 +- .../crates/hir-ty/src/mir/lower.rs | 2 +- .../rust-analyzer/crates/hir-ty/src/tests.rs | 2 +- .../hir-ty/src/tests/closure_captures.rs | 2 +- .../crates/hir/src/diagnostics.rs | 16 ++-- src/tools/rust-analyzer/crates/hir/src/lib.rs | 4 +- .../crates/hir/src/semantics/source_to_def.rs | 6 +- 16 files changed, 191 insertions(+), 100 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store.rs index dec911f7161da..fdb3296b17e6d 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store.rs @@ -30,9 +30,9 @@ use crate::{ AdtId, BlockId, ExpressionStoreOwnerId, GenericDefId, SyntheticSyntax, expr_store::path::{AssociatedTypeBinding, GenericArg, GenericArgs, NormalPath, Path}, hir::{ - Array, AsmOperand, Binding, BindingId, Expr, ExprId, ExprOrPatId, InlineAsm, Label, - LabelId, MatchArm, OffsetOf, Pat, PatId, RecordFieldPat, RecordLitField, RecordSpread, - Statement, + Array, AsmOperand, Binding, BindingId, Expr, ExprId, ExprOrPatId, ExprOrPatIdPacked, + InlineAsm, Label, LabelId, MatchArm, OffsetOf, Pat, PatId, RecordFieldPat, RecordLitField, + RecordSpread, Statement, }, nameres::{DefMap, block_def_map}, signatures::VariantFields, @@ -127,7 +127,7 @@ struct ExpressionOnlyStore { /// /// Expressions (and destructuing patterns) that can be recorded here are single segment path, although not all single segments path refer /// to variables and have hygiene (some refer to items, we don't know at this stage). - ident_hygiene: FxHashMap, + ident_hygiene: FxHashMap, /// Maps expression roots to their origin. /// @@ -171,10 +171,10 @@ pub struct ExpressionStore { struct ExpressionOnlySourceMap { // AST expressions can create patterns in destructuring assignments. Therefore, `ExprSource` can also map // to `PatId`, and `PatId` can also map to `ExprSource` (the other way around is unaffected). - expr_map: FxHashMap, + expr_map: FxHashMap, expr_map_back: ArenaMap, - pat_map: FxHashMap, + pat_map: FxHashMap, pat_map_back: ArenaMap, label_map: FxHashMap, @@ -270,15 +270,15 @@ pub struct ExpressionStoreBuilder { pub binding_owners: FxHashMap, pub types: Arena, block_scopes: Vec, - ident_hygiene: FxHashMap, + ident_hygiene: FxHashMap, inference_roots: Option>, // AST expressions can create patterns in destructuring assignments. Therefore, `ExprSource` can also map // to `PatId`, and `PatId` can also map to `ExprSource` (the other way around is unaffected). - expr_map: FxHashMap, + expr_map: FxHashMap, expr_map_back: ArenaMap, - pat_map: FxHashMap, + pat_map: FxHashMap, pat_map_back: ArenaMap, label_map: FxHashMap, @@ -1175,7 +1175,7 @@ impl ExpressionStoreSourceMap { pub fn node_expr(&self, node: InFile<&ast::Expr>) -> Option { let src = node.map(AstPtr::new); - self.expr_only()?.expr_map.get(&src).cloned() + self.expr_only()?.expr_map.get(&src).cloned().map(ExprOrPatIdPacked::unpack) } pub fn node_macro_file(&self, node: InFile<&ast::MacroCall>) -> Option { @@ -1192,7 +1192,11 @@ impl ExpressionStoreSourceMap { } pub fn node_pat(&self, node: InFile<&ast::Pat>) -> Option { - self.expr_only()?.pat_map.get(&node.map(AstPtr::new)).cloned() + self.expr_only()? + .pat_map + .get(&node.map(AstPtr::new)) + .cloned() + .map(ExprOrPatIdPacked::unpack) } pub fn type_syntax(&self, id: TypeRefId) -> Result { @@ -1226,7 +1230,7 @@ impl ExpressionStoreSourceMap { pub fn macro_expansion_expr(&self, node: InFile<&ast::MacroExpr>) -> Option { let src = node.map(AstPtr::new).map(AstPtr::upcast::).map(AstPtr::upcast); - self.expr_only()?.expr_map.get(&src).copied() + self.expr_only()?.expr_map.get(&src).copied().map(ExprOrPatIdPacked::unpack) } pub fn expansions(&self) -> impl Iterator, &MacroCallId)> { diff --git a/src/tools/rust-analyzer/crates/hir-def/src/hir.rs b/src/tools/rust-analyzer/crates/hir-def/src/hir.rs index a80056904402a..f701b7d61e97d 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/hir.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/hir.rs @@ -16,11 +16,11 @@ pub mod format_args; pub mod generics; pub mod type_ref; -use std::fmt; +use std::{fmt, mem}; use hir_expand::{MacroDefId, name::Name}; use intern::Symbol; -use la_arena::Idx; +use la_arena::{Idx, RawIdx}; use rustc_apfloat::ieee::{Double, Half, Quad, Single}; use syntax::ast; use type_ref::TypeRefId; @@ -43,9 +43,7 @@ pub type ExprId = Idx; pub type PatId = Idx; -// FIXME: Encode this as a single u32, we won't ever reach all 32 bits especially given these counts -// are local to the body. -#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, salsa::Update)] +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub enum ExprOrPatId { ExprId(ExprId), PatId(PatId), @@ -74,7 +72,81 @@ impl ExprOrPatId { matches!(self, Self::PatId(_)) } } -stdx::impl_from!(ExprId, PatId for ExprOrPatId); + +#[derive(Copy, Clone, Hash, PartialEq, Eq, salsa::Update)] +pub struct ExprOrPatIdPacked(u32); + +const _: () = assert!(mem::size_of::() == mem::size_of::()); + +impl ExprOrPatIdPacked { + const PAT_BIT: u32 = 1 << (u32::BITS - 1); + const INDEX_MASK: u32 = !Self::PAT_BIT; + + pub fn unpack(self) -> ExprOrPatId { + match self.is_expr() { + true => ExprOrPatId::ExprId(ExprId::from_raw(RawIdx::from_u32(self.0))), + false => ExprOrPatId::PatId(PatId::from_raw(RawIdx::from_u32(self.0))), + } + } + + #[inline] + pub fn as_expr(self) -> Option { + self.is_expr().then(|| ExprId::from_raw(RawIdx::from_u32(self.0))) + } + + #[inline] + pub fn is_expr(&self) -> bool { + self.0 & Self::PAT_BIT == 0 + } + + #[inline] + pub fn as_pat(self) -> Option { + self.is_pat().then(|| PatId::from_raw(RawIdx::from_u32(self.0 & Self::INDEX_MASK))) + } + + #[inline] + pub fn is_pat(&self) -> bool { + self.0 & Self::PAT_BIT != 0 + } +} + +impl fmt::Debug for ExprOrPatIdPacked { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self.unpack() { + ExprOrPatId::ExprId(id) => f.debug_tuple("ExprId").field(&id).finish(), + ExprOrPatId::PatId(id) => f.debug_tuple("PatId").field(&id).finish(), + } + } +} + +impl From for ExprOrPatIdPacked { + fn from(value: ExprId) -> Self { + let value = value.into_raw().into_u32(); + // virtually impossible to have IDs that high + debug_assert_eq!(value & Self::PAT_BIT, 0); + Self(value) + } +} + +impl From for ExprOrPatId { + fn from(value: PatId) -> Self { + ExprOrPatId::PatId(value) + } +} +impl From for ExprOrPatId { + fn from(value: ExprId) -> Self { + ExprOrPatId::ExprId(value) + } +} + +impl From for ExprOrPatIdPacked { + fn from(value: PatId) -> Self { + let value = value.into_raw().into_u32(); + // virtually impossible to have IDs that high + debug_assert_eq!(value & Self::PAT_BIT, 0); + Self(value | Self::PAT_BIT) + } +} #[derive(Debug, Clone, Eq, PartialEq)] pub struct Label { 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 64d0e2a86406d..3b9e168d54321 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs @@ -47,7 +47,7 @@ use hir_def::{ TupleFieldId, TupleId, VariantId, attrs::AttrFlags, expr_store::{Body, ExpressionStore, HygieneId, body::Param, path::Path}, - hir::{BindingId, ExprId, ExprOrPatId, LabelId, PatId}, + hir::{BindingId, ExprId, ExprOrPatId, ExprOrPatIdPacked, LabelId, PatId}, lang_item::LangItems, layout::Integer, resolver::{HasResolver, ResolveValueResult, Resolver, TypeNs, ValueNs}, @@ -289,7 +289,7 @@ pub enum InferenceTyDiagnosticSource { pub enum InferenceDiagnostic { NoSuchField { #[type_visitable(ignore)] - field: ExprOrPatId, + field: ExprOrPatIdPacked, #[type_visitable(ignore)] private: Option, #[type_visitable(ignore)] @@ -320,7 +320,7 @@ pub enum InferenceDiagnostic { }, DuplicateField { #[type_visitable(ignore)] - field: ExprOrPatId, + field: ExprOrPatIdPacked, #[type_visitable(ignore)] variant: VariantId, }, @@ -332,7 +332,7 @@ pub enum InferenceDiagnostic { }, PrivateAssocItem { #[type_visitable(ignore)] - id: ExprOrPatId, + id: ExprOrPatIdPacked, #[type_visitable(ignore)] item: AssocItemId, }, @@ -358,11 +358,11 @@ pub enum InferenceDiagnostic { }, UnresolvedAssocItem { #[type_visitable(ignore)] - id: ExprOrPatId, + id: ExprOrPatIdPacked, }, UnresolvedIdent { #[type_visitable(ignore)] - id: ExprOrPatId, + id: ExprOrPatIdPacked, }, // FIXME: This should be emitted in body lowering BreakOutsideOfLoop { @@ -461,7 +461,7 @@ pub enum InferenceDiagnostic { }, PathDiagnostic { #[type_visitable(ignore)] - node: ExprOrPatId, + node: ExprOrPatIdPacked, #[type_visitable(ignore)] diag: PathLoweringDiagnostic, }, @@ -507,7 +507,7 @@ pub enum InferenceDiagnostic { }, TypeMismatch { #[type_visitable(ignore)] - node: ExprOrPatId, + node: ExprOrPatIdPacked, expected: StoredTy, found: StoredTy, }, @@ -541,7 +541,7 @@ pub enum ReturnKind { #[derive(Debug, PartialEq, Eq, Clone)] pub enum ExplicitDropMethodUseKind { MethodCall(ExprId), - Path(ExprOrPatId), + Path(ExprOrPatIdPacked), } /// Represents coercing a value to a different type of value. @@ -743,9 +743,9 @@ pub struct InferenceResult { /// For each field access expr, records the field it resolves to. field_resolutions: FxHashMap>, /// For each struct literal or pattern, records the variant it resolves to. - variant_resolutions: FxHashMap, + variant_resolutions: FxHashMap, /// For each associated item record what it resolves to - assoc_resolutions: FxHashMap, + assoc_resolutions: FxHashMap, /// Whenever a tuple field expression access a tuple field, we allocate a tuple id in /// [`InferenceContext`] and store the tuples substitution there. This map is the reverse of /// that which allows us to resolve a [`TupleFieldId`]s type. @@ -769,7 +769,7 @@ pub struct InferenceResult { /// During inference this field is empty and [`InferenceContext::diagnostics`] is filled instead. diagnostics: ThinVec, // FIXME: Remove this, change it to be in `InferenceContext`: - nodes_with_type_mismatches: Option>>, + nodes_with_type_mismatches: Option>>, /// Interned `Error` type to return references to. // FIXME: Remove this. @@ -897,9 +897,9 @@ pub struct CaptureSourceStack(CaptureSourceStackRepr); #[derive(Clone)] enum CaptureSourceStackRepr { - One(ExprOrPatId), - Two([ExprOrPatId; 2]), - Many(ThinVec), + One(ExprOrPatIdPacked), + Two([ExprOrPatIdPacked; 2]), + Many(ThinVec), } impl PartialEq for CaptureSourceStack { @@ -916,10 +916,11 @@ impl std::hash::Hash for CaptureSourceStack { } } +#[cfg(target_pointer_width = "64")] const _: () = assert!(size_of::() == 16); impl Deref for CaptureSourceStack { - type Target = [ExprOrPatId]; + type Target = [ExprOrPatIdPacked]; #[inline] fn deref(&self) -> &Self::Target { @@ -948,16 +949,16 @@ impl CaptureSourceStack { } #[inline] - pub(crate) fn from_single(id: ExprOrPatId) -> Self { + pub(crate) fn from_single(id: ExprOrPatIdPacked) -> Self { Self(CaptureSourceStackRepr::One(id)) } #[inline] - pub fn final_source(&self) -> ExprOrPatId { + pub fn final_source(&self) -> ExprOrPatIdPacked { *self.last().expect("should always have a final source") } - pub fn push(&mut self, new_id: ExprOrPatId) { + pub fn push(&mut self, new_id: ExprOrPatIdPacked) { match &mut self.0 { CaptureSourceStackRepr::One(old_id) => { self.0 = CaptureSourceStackRepr::Two([*old_id, new_id]) @@ -1113,7 +1114,7 @@ impl InferenceResult { ExprOrPatId::PatId(id) => self.assoc_resolutions_for_pat(id), } } - pub fn expr_or_pat_has_type_mismatch(&self, node: ExprOrPatId) -> bool { + pub fn expr_or_pat_has_type_mismatch(&self, node: ExprOrPatIdPacked) -> bool { self.nodes_with_type_mismatches.as_ref().is_some_and(|it| it.contains(&node)) } pub fn expr_has_type_mismatch(&self, expr: ExprId) -> bool { @@ -1878,13 +1879,13 @@ impl<'body, 'db> InferenceContext<'body, 'db> { self.result.method_resolutions.insert(expr, (func, subst.store())); } - fn write_variant_resolution(&mut self, id: ExprOrPatId, variant: VariantId) { + fn write_variant_resolution(&mut self, id: ExprOrPatIdPacked, variant: VariantId) { self.result.variant_resolutions.insert(id, variant); } fn write_assoc_resolution( &mut self, - id: ExprOrPatId, + id: ExprOrPatIdPacked, item: CandidateId, subs: GenericArgs<'db>, ) { @@ -2140,14 +2141,18 @@ impl<'body, 'db> InferenceContext<'body, 'db> { self.table.resolve_vars_if_possible(t) } - pub(crate) fn structurally_resolve_type(&mut self, node: ExprOrPatId, ty: Ty<'db>) -> Ty<'db> { + pub(crate) fn structurally_resolve_type( + &mut self, + node: ExprOrPatIdPacked, + ty: Ty<'db>, + ) -> Ty<'db> { let result = self.table.try_structurally_resolve_type(node.into(), ty); if result.is_ty_var() { self.type_must_be_known_at_this_point(node, ty) } else { result } } pub(crate) fn emit_type_mismatch( &mut self, - node: ExprOrPatId, + node: ExprOrPatIdPacked, expected: Ty<'db>, found: Ty<'db>, ) { @@ -2162,7 +2167,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> { fn demand_eqtype( &mut self, - id: ExprOrPatId, + id: ExprOrPatIdPacked, expected: Ty<'db>, actual: Ty<'db>, ) -> Result<(), ()> { @@ -2192,7 +2197,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> { fn demand_suptype( &mut self, - id: ExprOrPatId, + id: ExprOrPatIdPacked, expected: Ty<'db>, actual: Ty<'db>, ) -> Result<(), ()> { @@ -2224,7 +2229,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> { pub(crate) fn type_must_be_known_at_this_point( &mut self, - node: ExprOrPatId, + node: ExprOrPatIdPacked, ty: Ty<'db>, ) -> Ty<'db> { if self.vars_emitted_type_must_be_known_for.insert(ty.into()) { @@ -2260,7 +2265,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> { fn resolve_variant( &mut self, - node: ExprOrPatId, + node: ExprOrPatIdPacked, path: &Path, value_ns: bool, ) -> (Ty<'db>, Option) { @@ -2570,7 +2575,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> { fn resolve_variant_on_alias( &mut self, - node: ExprOrPatId, + node: ExprOrPatIdPacked, ty: Ty<'db>, unresolved: Option, path: &ModPath, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure/analysis.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure/analysis.rs index 5ea43bc03ca86..b2bbbd9548420 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure/analysis.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure/analysis.rs @@ -35,7 +35,7 @@ use std::{iter, mem}; use hir_def::{ expr_store::ExpressionStore, hir::{ - BindingAnnotation, BindingId, CaptureBy, CoroutineSource, Expr, ExprId, ExprOrPatId, Pat, + BindingAnnotation, BindingId, CaptureBy, CoroutineSource, Expr, ExprId, ExprOrPatIdPacked, Pat, PatId, Statement, }, resolver::ValueNs, @@ -1461,7 +1461,7 @@ fn determine_capture_info(capture_info_a: &mut CaptureInfo, capture_info_b: &mut fn determine_capture_sources( capture_info_a: &mut CaptureInfo, capture_info_b: &mut CaptureInfo, - dedup_sources_scratch: &mut FxHashMap, + dedup_sources_scratch: &mut FxHashMap, ) -> SmallVec<[CaptureSourceStack; 2]> { dedup_sources_scratch.clear(); dedup_sources_scratch.extend( diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure/analysis/expr_use_visitor.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure/analysis/expr_use_visitor.rs index d8a8cceee6583..f02a85c29364a 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure/analysis/expr_use_visitor.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure/analysis/expr_use_visitor.rs @@ -9,8 +9,8 @@ use hir_def::{ AdtId, HasModule, VariantId, attrs::AttrFlags, hir::{ - Array, AsmOperand, BindingId, Expr, ExprId, ExprOrPatId, MatchArm, Pat, PatId, - RecordLitField, RecordSpread, Statement, + Array, AsmOperand, BindingId, Expr, ExprId, ExprOrPatId, ExprOrPatIdPacked, MatchArm, Pat, + PatId, RecordLitField, RecordSpread, Statement, }, resolver::ValueNs, }; @@ -144,7 +144,7 @@ pub(crate) struct PlaceWithOrigin { impl PlaceWithOrigin { fn new_no_projections<'db>( - origin: impl Into, + origin: impl Into, base_ty: Ty<'db>, base: PlaceBase, ) -> PlaceWithOrigin { @@ -166,7 +166,7 @@ impl PlaceWithOrigin { PlaceWithOrigin { origins, place: Place { base_ty: base_ty.store(), base, projections } } } - fn push_projection(&mut self, projection: Projection, origin: ExprOrPatId) { + fn push_projection(&mut self, projection: Projection, origin: ExprOrPatIdPacked) { self.place.projections.push(projection); for origin_stack in &mut self.origins { origin_stack.push(origin); @@ -1392,7 +1392,7 @@ impl<'db, D: Delegate<'db>> ExprUseVisitor<'_, '_, 'db, D> { fn cat_local( &mut self, - id: ExprOrPatId, + id: ExprOrPatIdPacked, expr_ty: Ty<'db>, var_id: BindingId, ) -> Result { @@ -1408,7 +1408,11 @@ impl<'db, D: Delegate<'db>> ExprUseVisitor<'_, '_, 'db, D> { /// Note: the actual upvar access contains invisible derefs of closure /// environment and upvar reference as appropriate. Only regionck cares /// about these dereferences, so we let it compute them as needed. - fn cat_upvar(&mut self, hir_id: ExprOrPatId, var_id: BindingId) -> Result { + fn cat_upvar( + &mut self, + hir_id: ExprOrPatIdPacked, + var_id: BindingId, + ) -> Result { let var_ty = self.expect_and_resolve_type( self.cx.result.type_of_binding.get(var_id).map(|it| it.as_ref()), )?; @@ -1420,13 +1424,13 @@ impl<'db, D: Delegate<'db>> ExprUseVisitor<'_, '_, 'db, D> { )) } - fn cat_rvalue(&self, hir_id: ExprOrPatId, expr_ty: Ty<'db>) -> PlaceWithOrigin { + fn cat_rvalue(&self, hir_id: ExprOrPatIdPacked, expr_ty: Ty<'db>) -> PlaceWithOrigin { PlaceWithOrigin::new_no_projections(hir_id, expr_ty, PlaceBase::Rvalue) } fn cat_projection( &self, - node: ExprOrPatId, + node: ExprOrPatIdPacked, mut base_place: PlaceWithOrigin, ty: Ty<'db>, kind: ProjectionKind, @@ -1455,7 +1459,7 @@ impl<'db, D: Delegate<'db>> ExprUseVisitor<'_, '_, 'db, D> { fn cat_deref( &mut self, - node: ExprOrPatId, + node: ExprOrPatIdPacked, mut base_place: PlaceWithOrigin, ) -> Result { let base_curr_ty = base_place.place.ty(); @@ -1712,7 +1716,7 @@ impl<'db, D: Delegate<'db>> ExprUseVisitor<'_, '_, 'db, D> { /// Represents the place matched on by a deref pattern's interior. fn pat_deref_place( &mut self, - node: ExprOrPatId, + node: ExprOrPatIdPacked, base_place: PlaceWithOrigin, inner: PatId, target_ty: Ty<'db>, @@ -1746,7 +1750,7 @@ impl<'db, D: Delegate<'db>> ExprUseVisitor<'_, '_, 'db, D> { /// FIXME(never_patterns): update this comment once the aforementioned MIR builder /// code is changed to be insensitive to inhhabitedness. #[instrument(skip(self), level = "debug")] - fn is_multivariant_adt(&mut self, node: ExprOrPatId, ty: Ty<'db>) -> bool { + fn is_multivariant_adt(&mut self, node: ExprOrPatIdPacked, ty: Ty<'db>) -> bool { if let TyKind::Adt(def, _) = self.cx.structurally_resolve_type(node, ty).kind() { // Note that if a non-exhaustive SingleVariant is defined in another crate, we need // to assume that more cases will be added to the variant in the future. This mean 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 e871edd265c16..481a5e9cfcde4 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 @@ -9,8 +9,11 @@ use either::Either; use hir_def::expr_store::path::Path; use hir_def::{ExpressionStoreOwnerId, GenericDefId}; use hir_def::{expr_store::ExpressionStore, type_ref::TypeRefId}; -use hir_def::{hir::ExprOrPatId, resolver::Resolver}; -use la_arena::{Idx, RawIdx}; +use hir_def::{ + hir::{ExprId, ExprOrPatIdPacked}, + resolver::Resolver, +}; +use la_arena::RawIdx; use rustc_hash::FxHashMap; use thin_vec::ThinVec; @@ -55,7 +58,7 @@ impl Diagnostics { } pub(crate) struct PathDiagnosticCallbackData<'a> { - node: ExprOrPatId, + node: ExprOrPatIdPacked, diagnostics: &'a Diagnostics, } @@ -131,7 +134,7 @@ impl<'db, 'a> InferenceTyLoweringContext<'db, 'a> { pub(super) fn at_path<'b>( &'b mut self, path: &'b Path, - node: ExprOrPatId, + node: ExprOrPatIdPacked, ) -> PathLoweringContext<'b, 'a, 'db> { let on_diagnostic = PathDiagnosticCallback { data: Either::Right(PathDiagnosticCallbackData { diagnostics: self.diagnostics, node }), @@ -152,7 +155,7 @@ impl<'db, 'a> InferenceTyLoweringContext<'db, 'a> { let on_diagnostic = PathDiagnosticCallback { data: Either::Right(PathDiagnosticCallbackData { diagnostics: self.diagnostics, - node: ExprOrPatId::ExprId(Idx::from_raw(RawIdx::from_u32(0))), + node: ExprOrPatIdPacked::from(ExprId::from_raw(RawIdx::from_u32(0))), }), callback: |_data, _, _diag| {}, }; 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 40465e39520f7..d265e1ed775af 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 @@ -7,9 +7,9 @@ use hir_def::{ AdtId, FieldId, TupleFieldId, TupleId, VariantId, expr_store::path::{GenericArgs as HirGenericArgs, Path}, hir::{ - Array, AsmOperand, AsmOptions, BinaryOp, BindingAnnotation, Expr, ExprId, ExprOrPatId, - InlineAsmKind, LabelId, LoopSource, Pat, PatId, RecordLitField, RecordSpread, Statement, - UnaryOp, + Array, AsmOperand, AsmOptions, BinaryOp, BindingAnnotation, Expr, ExprId, + ExprOrPatIdPacked, InlineAsmKind, LabelId, LoopSource, Pat, PatId, RecordLitField, + RecordSpread, Statement, UnaryOp, }, resolver::ValueNs, signatures::VariantFields, @@ -1274,7 +1274,7 @@ impl<'db> InferenceContext<'_, 'db> { } } - fn infer_expr_path(&mut self, path: &Path, id: ExprOrPatId, scope_id: ExprId) -> Ty<'db> { + fn infer_expr_path(&mut self, path: &Path, id: ExprOrPatIdPacked, scope_id: ExprId) -> Ty<'db> { let g = self.resolver.update_to_inner_scope(self.db, self.store_owner, scope_id); let ty = match self.infer_path(path, id) { Some((_, ty)) => ty, 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 1e539d24c18a8..7654ad77cd140 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 @@ -10,7 +10,7 @@ use hir_def::{ AdtId, LocalFieldId, VariantId, expr_store::path::Path, hir::{ - BindingAnnotation, BindingId, Expr, ExprId, ExprOrPatId, Literal, Pat, PatId, + BindingAnnotation, BindingId, Expr, ExprId, ExprOrPatIdPacked, Literal, Pat, PatId, RecordFieldPat, }, resolver::ValueNs, @@ -853,7 +853,7 @@ impl<'a, 'db> InferenceContext<'a, 'db> { // Subtyping doesn't matter here, as the value is some kind of scalar. let mut demand_eqtype = |x: &mut _| { if let Some((_, x_ty, x_expr)) = *x { - _ = self.demand_eqtype(ExprOrPatId::from(x_expr), expected, x_ty); + _ = self.demand_eqtype(ExprOrPatIdPacked::from(x_expr), expected, x_ty); } }; demand_eqtype(&mut lhs); @@ -868,7 +868,7 @@ impl<'a, 'db> InferenceContext<'a, 'db> { // We require types to be resolved here so that we emit inference failure // rather than "_ is not a char or numeric". let ty = self.structurally_resolve_type( - lhs_expr.or(rhs_expr).map(ExprOrPatId::ExprId).unwrap_or(pat.into()), + lhs_expr.or(rhs_expr).map(ExprOrPatIdPacked::from).unwrap_or(pat.into()), expected, ); if !(ty.is_numeric() || ty.is_char() || ty.references_error()) { 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 ecc81f9de0232..1b1d0e1ff6fb8 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 @@ -3,6 +3,7 @@ use hir_def::{ AdtId, AssocItemId, GenericDefId, ItemContainerId, Lookup, expr_store::path::{Path, PathSegment}, + hir::ExprOrPatIdPacked, resolver::{ResolveValueResult, TypeNs, ValueNs}, signatures::{ConstSignature, FunctionSignature}, }; @@ -23,13 +24,13 @@ use crate::{ }, }; -use super::{ExprOrPatId, InferenceContext, InferenceTyDiagnosticSource}; +use super::{InferenceContext, InferenceTyDiagnosticSource}; impl<'db> InferenceContext<'_, 'db> { pub(super) fn infer_path( &mut self, path: &Path, - id: ExprOrPatId, + id: ExprOrPatIdPacked, ) -> Option<(ValueNs, Ty<'db>)> { let (value, self_subst) = self.resolve_value_path_inner(path, id, false)?; @@ -60,7 +61,7 @@ impl<'db> InferenceContext<'_, 'db> { fn resolve_value_path( &mut self, path: &Path, - id: ExprOrPatId, + id: ExprOrPatIdPacked, value: ValueNs, self_subst: Option>, ) -> Option> { @@ -145,7 +146,7 @@ impl<'db> InferenceContext<'_, 'db> { pub(super) fn resolve_value_path_inner( &mut self, path: &Path, - id: ExprOrPatId, + id: ExprOrPatIdPacked, no_diagnostics: bool, ) -> Option<(ValueNs, Option>)> { // Don't use `self.make_ty()` here as we need `orig_ns`. @@ -185,7 +186,7 @@ impl<'db> InferenceContext<'_, 'db> { let ty = self.table.process_user_written_ty(ty); self.resolve_ty_assoc_item(ty, last.name, id).map(|(it, substs)| (it, Some(substs)))? } else { - let hygiene = self.store.expr_or_pat_path_hygiene(id); + let hygiene = self.store.expr_or_pat_path_hygiene(id.unpack()); // FIXME: report error, unresolved first path segment let value_or_partial = path_ctx.resolve_path_in_value_ns(hygiene)?; @@ -273,7 +274,7 @@ impl<'db> InferenceContext<'_, 'db> { pub(super) fn add_required_obligations_for_value_path( &mut self, - node: ExprOrPatId, + node: ExprOrPatIdPacked, def: GenericDefId, subst: GenericArgs<'db>, ) { @@ -293,7 +294,7 @@ impl<'db> InferenceContext<'_, 'db> { &mut self, trait_ref: TraitRef<'db>, segment: PathSegment<'_>, - id: ExprOrPatId, + id: ExprOrPatIdPacked, ) -> Option<(ValueNs, GenericArgs<'db>)> { let trait_ = trait_ref.def_id.0; let item = @@ -330,7 +331,7 @@ impl<'db> InferenceContext<'_, 'db> { &mut self, ty: Ty<'db>, name: &Name, - id: ExprOrPatId, + id: ExprOrPatIdPacked, ) -> Option<(ValueNs, GenericArgs<'db>)> { if ty.is_ty_error() { return None; @@ -399,7 +400,7 @@ impl<'db> InferenceContext<'_, 'db> { &mut self, ty: Ty<'db>, name: &Name, - id: ExprOrPatId, + id: ExprOrPatIdPacked, ) -> Option<(ValueNs, GenericArgs<'db>)> { let ty = self.table.try_structurally_resolve_type(id.into(), ty); let (enum_id, subst) = match ty.as_adt() { 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 120c265fdc84a..b6cf47fe62b17 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs @@ -67,7 +67,7 @@ use hir_def::{ GenericDefId, HasModule, LifetimeParamId, ModuleId, StaticId, TypeAliasId, TypeOrConstParamId, TypeParamId, expr_store::{Body, ExpressionStore}, - hir::{BindingId, ExprId, ExprOrPatId, PatId}, + hir::{BindingId, ExprId, ExprOrPatId, ExprOrPatIdPacked, PatId}, resolver::{HasResolver, Resolver, TypeNs}, type_ref::{Rawness, TypeRefId}, }; @@ -531,9 +531,9 @@ pub enum Span { } impl_from!(ExprId, PatId, BindingId, TypeRefId for Span); -impl From for Span { - fn from(value: ExprOrPatId) -> Self { - match value { +impl From for Span { + fn from(value: ExprOrPatIdPacked) -> Self { + match value.unpack() { ExprOrPatId::ExprId(idx) => idx.into(), ExprOrPatId::PatId(idx) => idx.into(), } 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 8cc59ecd0c1eb..8292ea2cf7aff 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 @@ -1253,7 +1253,7 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { let span = |sources: &[CaptureSourceStack]| match sources .first() - .map(|it| it.final_source()) + .map(|it| it.final_source().unpack()) { Some(ExprOrPatId::ExprId(it)) => it.into(), Some(ExprOrPatId::PatId(it)) => it.into(), diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs index febd2a833a6a7..70099945b566f 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs @@ -204,7 +204,7 @@ fn check_impl( _ => None, }); for (expr_or_pat, expected, actual) in type_mismatches { - let Some(node) = (match expr_or_pat { + let Some(node) = (match expr_or_pat.unpack() { hir_def::hir::ExprOrPatId::ExprId(expr) => { expr_node(body_source_map, expr, &db) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/closure_captures.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/closure_captures.rs index 1fc556d04d019..c951a5481c460 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/closure_captures.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/closure_captures.rs @@ -125,7 +125,7 @@ fn check_closure_captures(#[rust_analyzer::rust_fixture] ra_fixture: &str, expec .info .sources .iter() - .flat_map(|span| match span.final_source() { + .flat_map(|span| match span.final_source().unpack() { ExprOrPatId::ExprId(expr) => { vec![text_range(db, source_map.expr_syntax(expr).unwrap())] } diff --git a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs index b921a5eef14a9..422b37c67a261 100644 --- a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs +++ b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs @@ -847,7 +847,7 @@ impl<'db> AnyDiagnostic<'db> { let span_syntax = |span| Self::span_syntax(span, source_map); Some(match d { &InferenceDiagnostic::NoSuchField { field: expr, private, variant } => { - let expr_or_pat = match expr { + let expr_or_pat = match expr.unpack() { ExprOrPatId::ExprId(expr) => { source_map.field_syntax(expr).map(AstPtr::wrap_left) } @@ -877,7 +877,7 @@ impl<'db> AnyDiagnostic<'db> { InvalidRangePatType { pat }.into() } &InferenceDiagnostic::DuplicateField { field: expr, variant } => { - let expr_or_pat = match expr { + let expr_or_pat = match expr.unpack() { ExprOrPatId::ExprId(expr) => { source_map.field_syntax(expr).map(AstPtr::wrap_left) } @@ -894,7 +894,7 @@ impl<'db> AnyDiagnostic<'db> { PrivateField { expr, field }.into() } &InferenceDiagnostic::PrivateAssocItem { id, item } => { - let expr_or_pat = expr_or_pat_syntax(id)?; + let expr_or_pat = expr_or_pat_syntax(id.unpack())?; let item = item.into(); PrivateAssocItem { expr_or_pat, item }.into() } @@ -937,11 +937,11 @@ impl<'db> AnyDiagnostic<'db> { .into() } &InferenceDiagnostic::UnresolvedAssocItem { id } => { - let expr_or_pat = expr_or_pat_syntax(id)?; + let expr_or_pat = expr_or_pat_syntax(id.unpack())?; UnresolvedAssocItem { expr_or_pat }.into() } &InferenceDiagnostic::UnresolvedIdent { id } => { - let node = match id { + let node = match id.unpack() { ExprOrPatId::ExprId(id) => match source_map.expr_syntax(id) { Ok(syntax) => syntax.map(|it| (it, None)), Err(SyntheticSyntax) => source_map @@ -1019,7 +1019,7 @@ impl<'db> AnyDiagnostic<'db> { Self::ty_diagnostic(diag, source_map, db)? } InferenceDiagnostic::PathDiagnostic { node, diag } => { - let source = expr_or_pat_syntax(*node)?; + let source = expr_or_pat_syntax(node.unpack())?; let syntax = source.value.to_node(&source.file_id.parse_or_expand(db)); let path = match_ast! { match (syntax.syntax()) { @@ -1100,7 +1100,7 @@ impl<'db> AnyDiagnostic<'db> { UnionExprMustHaveExactlyOneField { expr }.into() } InferenceDiagnostic::TypeMismatch { node, expected, found } => { - let expr_or_pat = expr_or_pat_syntax(*node)?; + let expr_or_pat = expr_or_pat_syntax(node.unpack())?; TypeMismatch { expr_or_pat, expected: Type { owner: type_owner, ty: EarlyBinder::bind(expected.as_ref()) }, @@ -1120,7 +1120,7 @@ impl<'db> AnyDiagnostic<'db> { Either::Left(expr) } ExplicitDropMethodUseKind::Path(path_expr_id) => { - let syntax = expr_or_pat_syntax(*path_expr_id)?; + let syntax = expr_or_pat_syntax(path_expr_id.unpack())?; let file_id = syntax.file_id; let syntax = syntax.with_value(syntax.value.cast::()?).to_node(db); diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index 1ba73c180c319..951728617d572 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -5210,8 +5210,8 @@ impl CaptureUsages<'_> { let mut result = Vec::with_capacity(self.sources.len()); for source in self.sources { let source = source.final_source(); - let is_ref = Self::is_ref(store, source); - match source { + let is_ref = Self::is_ref(store, source.unpack()); + match source.unpack() { ExprOrPatId::ExprId(expr) => { if let Ok(expr) = source_map.expr_syntax(expr) { result.push(CaptureUsageSource { is_ref, source: expr }) diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs b/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs index f7528d3db10b2..084b5d77d630a 100644 --- a/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs +++ b/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs @@ -354,8 +354,10 @@ impl SourceToDefCtx<'_, '_> { let src = src.cloned().map(ast::Pat::from); let pat_id = source_map.node_pat(src.as_ref())?; // the pattern could resolve to a constant, verify that this is not the case - if let crate::Pat::Bind { id, .. } = store[pat_id.as_pat()?] { - let parent_infer = semantics.infer_body_for_expr_or_pat(container, store, pat_id)?; + let pat_id = pat_id.as_pat()?; + if let crate::Pat::Bind { id, .. } = store[pat_id] { + let parent_infer = + semantics.infer_body_for_expr_or_pat(container, store, pat_id.into())?; Some(crate::Local { parent: container, parent_infer, binding_id: id }) } else { None From 4874f310924e6184dbeef8106636efea3c17b75d Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sun, 19 Jul 2026 14:31:52 +0200 Subject: [PATCH 11/76] Record expressions in types in ExprScope --- .../crates/hir-def/src/expr_store.rs | 3 - .../crates/hir-def/src/expr_store/scope.rs | 77 ++++++++++++++++++- 2 files changed, 73 insertions(+), 7 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store.rs index dec911f7161da..2750e93d15bd9 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store.rs @@ -154,9 +154,6 @@ struct ExpressionOnlyStore { /// and it does not bother us because we use this list for two things: constructing `ExprScopes`, which /// works fine with nested exprs, and retrieving inference results, and we copy the inner const's inference /// into the outer const. - // FIXME: Array repeat is not problematic indeed, but this could still break with exprs in types, - // which we do not visit for `ExprScopes` (they're fine for inference though). We either need to visit them, - // or use a more complicated search. expr_roots: SmallVec<[ExprRoot; 1]>, } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/scope.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/scope.rs index c881a961b14b5..34ac1f7630775 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/scope.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/scope.rs @@ -5,12 +5,13 @@ use la_arena::{Arena, ArenaMap, Idx, IdxRange, RawIdx}; use crate::{ BlockId, DefWithBodyId, ExpressionStoreOwnerId, GenericDefId, VariantId, - expr_store::{Body, ExpressionStore, HygieneId, body::Param}, + expr_store::{Body, ExpressionStore, HygieneId, StoreVisitor, body::Param}, hir::{ Array, Binding, BindingId, Expr, ExprId, Item, LabelId, Pat, PatId, Statement, generics::GenericParams, }, signatures::VariantFields, + type_ref::TypeRefId, }; pub type ScopeId = Idx; @@ -260,6 +261,42 @@ impl ExprScopes { } } +struct ExprScopeVisitor<'a> { + store: &'a ExpressionStore, + scopes: &'a mut ExprScopes, + scope: &'a mut ScopeId, + const_scope: &'a mut ScopeId, +} + +impl StoreVisitor for ExprScopeVisitor<'_> { + fn on_expr(&mut self, expr: ExprId) { + compute_expr_scopes(expr, self.store, self.scopes, self.scope, self.const_scope); + } + + fn on_anon_const_expr(&mut self, expr: ExprId) { + let mut scope = *self.const_scope; + compute_expr_scopes(expr, self.store, self.scopes, &mut scope, self.const_scope); + } + + fn on_pat(&mut self, pat: PatId) { + self.store.visit_pat_children(pat, &mut *self); + } + + fn on_type(&mut self, ty: TypeRefId) { + self.store.visit_type_ref_children(ty, &mut *self); + } +} + +fn compute_type_scopes( + ty: TypeRefId, + store: &ExpressionStore, + scopes: &mut ExprScopes, + const_scope: &mut ScopeId, +) { + let mut scope = *const_scope; + ExprScopeVisitor { store, scopes, scope: &mut scope, const_scope }.on_type(ty); +} + fn compute_block_scopes( statements: &[Statement], tail: Option, @@ -270,7 +307,10 @@ fn compute_block_scopes( ) { for stmt in statements { match stmt { - Statement::Let { pat, initializer, else_branch, .. } => { + Statement::Let { pat, initializer, else_branch, type_ref } => { + if let Some(type_ref) = type_ref { + compute_type_scopes(*type_ref, store, scopes, const_scope); + } if let Some(expr) = initializer { compute_expr_scopes(*expr, store, scopes, scope, const_scope); } @@ -350,7 +390,21 @@ fn compute_expr_scopes( let mut scope = scopes.new_labeled_scope(*scope, make_label(*label)); compute_expr_scopes(scopes, *body_expr, &mut scope, const_scope); } - Expr::Closure { args, body: body_expr, .. } => { + Expr::Closure { + args, + arg_types, + ret_type, + body: body_expr, + capture_by: _, + closure_kind: _, + } => { + arg_types + .iter() + .flatten() + .for_each(|type_ref| compute_type_scopes(*type_ref, store, scopes, const_scope)); + if let Some(type_ref) = ret_type { + compute_type_scopes(*type_ref, store, scopes, const_scope); + } let mut scope = scopes.new_scope(*scope); args.iter().for_each(|arg| scopes.add_pat_bindings(store, scope, *arg)); compute_expr_scopes(scopes, *body_expr, &mut scope, const_scope); @@ -380,7 +434,9 @@ fn compute_expr_scopes( *scope = scopes.new_scope(*scope); scopes.add_pat_bindings(store, *scope, pat); } - _ => store.walk_child_exprs(expr, |e| compute_expr_scopes(scopes, e, scope, const_scope)), + _ => { + store.visit_expr_children(expr, ExprScopeVisitor { store, scopes, scope, const_scope }) + } }; } @@ -452,6 +508,19 @@ mod tests { assert_eq_text!(&expected, &actual); } + #[test] + fn type_anon_const_scope() { + do_check( + r#" +fn f(param: usize) { + let local = 0; + let _: [(); $0] = []; +} +"#, + &["param"], + ); + } + #[test] fn test_lambda_scope() { do_check( From 9d832f28400cd8631de2d5013ccb1c6e7cefab61 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sun, 19 Jul 2026 14:02:12 +0200 Subject: [PATCH 12/76] Shrink ScopeData by 16 bytes --- .../crates/hir-def/src/expr_store/scope.rs | 70 +++++++++++-------- .../rust-analyzer/crates/hir-def/src/hir.rs | 4 +- .../crates/hir-def/src/resolver.rs | 9 ++- .../hir-ty/src/infer/closure/analysis.rs | 4 +- 4 files changed, 52 insertions(+), 35 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/scope.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/scope.rs index c881a961b14b5..3ce0ed44da9a9 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/scope.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/scope.rs @@ -46,13 +46,18 @@ impl ScopeEntry { #[derive(Debug, PartialEq, Eq)] pub struct ScopeData { parent: Option, - block: Option, - label: Option<(LabelId, Name)>, - // FIXME: We can compress this with an enum for this and `label`/`block` if memory usage matters. - macro_def: Option>, + kind: ScopeKind, entries: IdxRange, } +#[derive(Debug, PartialEq, Eq)] +enum ScopeKind { + None, + Block { id: BlockId, label: Option }, + Label(LabelId), + MacroDef(Box), +} + #[salsa::tracked] impl ExprScopes { #[salsa::tracked(returns(ref))] @@ -100,18 +105,28 @@ impl ExprScopes { /// If `scope` refers to a block expression scope, returns the corresponding `BlockId`. pub fn block(&self, scope: ScopeId) -> Option { - self.scopes[scope].block + match self.scopes[scope].kind { + ScopeKind::Block { id, label: _ } => Some(id), + ScopeKind::None | ScopeKind::Label(_) | ScopeKind::MacroDef(_) => None, + } } /// If `scope` refers to a macro def scope, returns the corresponding `MacroId`. #[allow(clippy::borrowed_box)] // If we return `&MacroDefId` we need to move it, this way we just clone the `Box`. pub fn macro_def(&self, scope: ScopeId) -> Option<&Box> { - self.scopes[scope].macro_def.as_ref() + match &self.scopes[scope].kind { + ScopeKind::MacroDef(macro_def) => Some(macro_def), + ScopeKind::None | ScopeKind::Block { id: _, label: _ } | ScopeKind::Label(_) => None, + } } /// If `scope` refers to a labeled expression scope, returns the corresponding `Label`. - pub fn label(&self, scope: ScopeId) -> Option<(LabelId, Name)> { - self.scopes[scope].label.clone() + pub fn label(&self, scope: ScopeId) -> Option { + match &self.scopes[scope].kind { + &ScopeKind::Block { id: _, label } => label, + &ScopeKind::Label(label) => Some(label), + ScopeKind::None | ScopeKind::MacroDef(_) => None, + } } /// Returns the scopes in ascending order. @@ -174,9 +189,7 @@ impl ExprScopes { fn root_scope(&mut self) -> ScopeId { self.scopes.alloc(ScopeData { parent: None, - block: None, - label: None, - macro_def: None, + kind: ScopeKind::None, entries: empty_entries(self.scope_entries.len()), }) } @@ -184,19 +197,19 @@ impl ExprScopes { fn new_scope(&mut self, parent: ScopeId) -> ScopeId { self.scopes.alloc(ScopeData { parent: Some(parent), - block: None, - label: None, - macro_def: None, + kind: ScopeKind::None, entries: empty_entries(self.scope_entries.len()), }) } - fn new_labeled_scope(&mut self, parent: ScopeId, label: Option<(LabelId, Name)>) -> ScopeId { + fn new_labeled_scope(&mut self, parent: ScopeId, label: Option) -> ScopeId { + let kind = match label { + Some(label) => ScopeKind::Label(label), + None => ScopeKind::None, + }; self.scopes.alloc(ScopeData { parent: Some(parent), - block: None, - label, - macro_def: None, + kind, entries: empty_entries(self.scope_entries.len()), }) } @@ -205,13 +218,16 @@ impl ExprScopes { &mut self, parent: ScopeId, block: Option, - label: Option<(LabelId, Name)>, + label: Option, ) -> ScopeId { + let kind = match (block, label) { + (Some(id), label) => ScopeKind::Block { id, label }, + (None, Some(label)) => ScopeKind::Label(label), + (None, None) => ScopeKind::None, + }; self.scopes.alloc(ScopeData { parent: Some(parent), - block, - label, - macro_def: None, + kind, entries: empty_entries(self.scope_entries.len()), }) } @@ -219,9 +235,7 @@ impl ExprScopes { fn new_macro_def_scope(&mut self, parent: ScopeId, macro_id: Box) -> ScopeId { self.scopes.alloc(ScopeData { parent: Some(parent), - block: None, - label: None, - macro_def: Some(macro_id), + kind: ScopeKind::MacroDef(macro_id), entries: empty_entries(self.scope_entries.len()), }) } @@ -303,8 +317,6 @@ fn compute_expr_scopes( scope: &mut ScopeId, const_scope: &mut ScopeId, ) { - let make_label = |label: Option| label.map(|label| (label, store[label].name.clone())); - let compute_expr_scopes = |scopes: &mut ExprScopes, expr: ExprId, scope: &mut ScopeId, const_scope: &mut ScopeId| { compute_expr_scopes(expr, store, scopes, scope, const_scope) @@ -316,7 +328,7 @@ fn compute_expr_scopes( scopes: &mut ExprScopes, scope: &mut ScopeId, const_scope: &mut ScopeId| { - let mut scope = scopes.new_block_scope(*scope, id, make_label(label)); + let mut scope = scopes.new_block_scope(*scope, id, label); let mut const_scope = if id.is_some() { scopes.new_block_scope(*const_scope, id, None) } else { @@ -347,7 +359,7 @@ fn compute_expr_scopes( handle_block(*id, statements, *tail, None, scopes, scope, const_scope); } Expr::Loop { body: body_expr, label, source: _ } => { - let mut scope = scopes.new_labeled_scope(*scope, make_label(*label)); + let mut scope = scopes.new_labeled_scope(*scope, *label); compute_expr_scopes(scopes, *body_expr, &mut scope, const_scope); } Expr::Closure { args, body: body_expr, .. } => { diff --git a/src/tools/rust-analyzer/crates/hir-def/src/hir.rs b/src/tools/rust-analyzer/crates/hir-def/src/hir.rs index f701b7d61e97d..dcb2227d9f4fc 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/hir.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/hir.rs @@ -85,7 +85,9 @@ impl ExprOrPatIdPacked { pub fn unpack(self) -> ExprOrPatId { match self.is_expr() { true => ExprOrPatId::ExprId(ExprId::from_raw(RawIdx::from_u32(self.0))), - false => ExprOrPatId::PatId(PatId::from_raw(RawIdx::from_u32(self.0))), + false => { + ExprOrPatId::PatId(PatId::from_raw(RawIdx::from_u32(self.0 & Self::INDEX_MASK))) + } } } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs index fc639133d4c27..724926f824282 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs @@ -22,7 +22,7 @@ use crate::{ TypeOrConstParamId, TypeParamId, UseId, VariantId, builtin_type::BuiltinType, expr_store::{ - HygieneId, + ExpressionStore, HygieneId, path::Path, scope::{ExprScopes, ScopeId}, }, @@ -1071,8 +1071,11 @@ impl<'db> Scope<'db> { } } Scope::ExprScope(scope) => { - if let Some((label, name)) = scope.expr_scopes.label(scope.scope_id) { - acc.add(&name, ScopeDef::Label(label)) + if let Some(label) = scope.expr_scopes.label(scope.scope_id) { + acc.add( + &ExpressionStore::of(db, scope.owner)[label].name, + ScopeDef::Label(label), + ) } scope.expr_scopes.entries(scope.scope_id).iter().for_each(|e| { acc.add_local(e.name(), e.binding()); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure/analysis.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure/analysis.rs index b2bbbd9548420..9dce343cae901 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure/analysis.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure/analysis.rs @@ -35,8 +35,8 @@ use std::{iter, mem}; use hir_def::{ expr_store::ExpressionStore, hir::{ - BindingAnnotation, BindingId, CaptureBy, CoroutineSource, Expr, ExprId, ExprOrPatIdPacked, Pat, - PatId, Statement, + BindingAnnotation, BindingId, CaptureBy, CoroutineSource, Expr, ExprId, ExprOrPatIdPacked, + Pat, PatId, Statement, }, resolver::ValueNs, }; From 4d0f57ea8c32196fb7538a942ef9aed505a196c4 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sun, 19 Jul 2026 13:30:07 +0200 Subject: [PATCH 13/76] Support lifetimes in `impl_from` macro --- .../crates/hir-def/src/item_scope.rs | 31 +--- .../rust-analyzer/crates/hir-def/src/lib.rs | 68 +++---- .../rust-analyzer/crates/hir-ty/src/db.rs | 17 +- .../rust-analyzer/crates/hir-ty/src/lib.rs | 31 +--- .../crates/hir-ty/src/next_solver/def_id.rs | 129 +++---------- .../rust-analyzer/crates/hir/src/from_id.rs | 174 +++++++----------- src/tools/rust-analyzer/crates/hir/src/lib.rs | 106 ++++------- .../rust-analyzer/crates/ide-db/src/defs.rs | 55 +++--- .../rust-analyzer/crates/stdx/src/macros.rs | 82 ++++++++- 9 files changed, 267 insertions(+), 426 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs index ac1d2fd2a4660..1443d3ea4be4c 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs @@ -12,7 +12,7 @@ use la_arena::Idx; use rustc_hash::{FxHashMap, FxHashSet}; use smallvec::SmallVec; use span::Edition; -use stdx::format_to; +use stdx::{format_to, impl_from}; use syntax::ast; use thin_vec::ThinVec; @@ -37,14 +37,7 @@ pub enum ImportOrExternCrate { ExternCrate(ExternCrateId), } -impl From for ImportOrExternCrate { - fn from(value: ImportOrGlob) -> Self { - match value { - ImportOrGlob::Glob(it) => ImportOrExternCrate::Glob(it), - ImportOrGlob::Import(it) => ImportOrExternCrate::Import(it), - } - } -} +impl_from!(ImportOrGlob { Glob, Import } for ImportOrExternCrate); impl ImportOrExternCrate { pub fn import_or_glob(self) -> Option { @@ -101,24 +94,8 @@ pub enum ImportOrDef { Def(ModuleDefId), } -impl From for ImportOrDef { - fn from(value: ImportOrExternCrate) -> Self { - match value { - ImportOrExternCrate::Import(it) => ImportOrDef::Import(it), - ImportOrExternCrate::Glob(it) => ImportOrDef::Glob(it), - ImportOrExternCrate::ExternCrate(it) => ImportOrDef::ExternCrate(it), - } - } -} - -impl From for ImportOrDef { - fn from(value: ImportOrGlob) -> Self { - match value { - ImportOrGlob::Import(it) => ImportOrDef::Import(it), - ImportOrGlob::Glob(it) => ImportOrDef::Glob(it), - } - } -} +impl_from!(ImportOrExternCrate { Import, Glob, ExternCrate } for ImportOrDef); +impl_from!(ImportOrGlob { Import, Glob } for ImportOrDef); #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)] pub struct ImportId { diff --git a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs index 8b93fe5e2f01b..f2a3c1b091fec 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs @@ -896,15 +896,14 @@ pub enum AssocItemId { // casting them, and somehow making the constructors private, which would be annoying. impl_from!(FunctionId, ConstId, TypeAliasId for AssocItemId); -impl From for ModuleDefId { - fn from(item: AssocItemId) -> Self { - match item { - AssocItemId::FunctionId(f) => f.into(), - AssocItemId::ConstId(c) => c.into(), - AssocItemId::TypeAliasId(t) => t.into(), - } +impl_from!( + AssocItemId { + FunctionId => FunctionId, + ConstId => ConstId, + TypeAliasId => TypeAliasId, } -} + for ModuleDefId +); #[derive(Debug, PartialOrd, Ord, Clone, Copy, PartialEq, Eq, Hash, salsa_macros::Supertype)] pub enum GenericDefId { @@ -1044,15 +1043,14 @@ impl GenericDefId { } } -impl From for GenericDefId { - fn from(item: AssocItemId) -> Self { - match item { - AssocItemId::FunctionId(f) => f.into(), - AssocItemId::ConstId(c) => c.into(), - AssocItemId::TypeAliasId(t) => t.into(), - } +impl_from!( + AssocItemId { + FunctionId => FunctionId, + ConstId => ConstId, + TypeAliasId => TypeAliasId, } -} + for GenericDefId +); #[derive(Debug, PartialOrd, Ord, Clone, Copy, PartialEq, Eq, Hash, salsa_macros::Supertype)] pub enum CallableDefId { @@ -1062,15 +1060,14 @@ pub enum CallableDefId { } impl_from!(FunctionId, StructId, EnumVariantId for CallableDefId); -impl From for ModuleDefId { - fn from(def: CallableDefId) -> ModuleDefId { - match def { - CallableDefId::FunctionId(f) => ModuleDefId::FunctionId(f), - CallableDefId::StructId(s) => ModuleDefId::AdtId(AdtId::StructId(s)), - CallableDefId::EnumVariantId(e) => ModuleDefId::EnumVariantId(e), - } +impl_from!( + CallableDefId { + FunctionId => FunctionId, + StructId => AdtId, + EnumVariantId => EnumVariantId, } -} + for ModuleDefId +); impl CallableDefId { pub fn krate(self, db: &dyn SourceDatabase) -> Crate { @@ -1114,24 +1111,11 @@ impl_from!( for AttrDefId ); -impl From for AttrDefId { - fn from(assoc: AssocItemId) -> Self { - match assoc { - AssocItemId::FunctionId(it) => AttrDefId::FunctionId(it), - AssocItemId::ConstId(it) => AttrDefId::ConstId(it), - AssocItemId::TypeAliasId(it) => AttrDefId::TypeAliasId(it), - } - } -} -impl From for AttrDefId { - fn from(vid: VariantId) -> Self { - match vid { - VariantId::EnumVariantId(id) => id.into(), - VariantId::StructId(id) => id.into(), - VariantId::UnionId(id) => id.into(), - } - } -} +impl_from!(AssocItemId { FunctionId, ConstId, TypeAliasId } for AttrDefId); +impl_from!( + VariantId { EnumVariantId => EnumVariantId, StructId => AdtId, UnionId => AdtId } + for AttrDefId +); #[derive( Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, salsa_macros::Supertype, salsa::Update, 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 73b1183cb2209..7e66e938a00fc 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs @@ -18,6 +18,7 @@ use hir_def::{ use la_arena::ArenaMap; use salsa::Update; use span::Edition; +use stdx::impl_from; use triomphe::Arc; use crate::{ @@ -488,21 +489,7 @@ pub enum GeneralConstId<'db> { AnonConstId(AnonConstId<'db>), } -impl<'db> From for GeneralConstId<'db> { - fn from(it: ConstId) -> GeneralConstId<'db> { - GeneralConstId::ConstId(it) - } -} -impl<'db> From for GeneralConstId<'db> { - fn from(it: StaticId) -> GeneralConstId<'db> { - GeneralConstId::StaticId(it) - } -} -impl<'db> From> for GeneralConstId<'db> { - fn from(it: AnonConstId<'db>) -> GeneralConstId<'db> { - GeneralConstId::AnonConstId(it) - } -} +impl_from!(impl<'db> ConstId, StaticId, AnonConstId<'db> for GeneralConstId<'db>); impl<'db> GeneralConstId<'db> { pub fn generic_def(self, db: &'db dyn HirDatabase) -> Option { 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 d217024b56910..0ab29db377994 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs @@ -559,31 +559,12 @@ pub enum InferBodyId<'db> { DefWithBodyId(DefWithBodyId), AnonConstId(AnonConstId<'db>), } -impl<'db> From for InferBodyId<'db> { - fn from(it: DefWithBodyId) -> InferBodyId<'db> { - InferBodyId::DefWithBodyId(it) - } -} -impl<'db> From for InferBodyId<'db> { - fn from(it: FunctionId) -> InferBodyId<'db> { - InferBodyId::DefWithBodyId(it.into()) - } -} -impl<'db> From for InferBodyId<'db> { - fn from(it: ConstId) -> InferBodyId<'db> { - InferBodyId::DefWithBodyId(it.into()) - } -} -impl<'db> From for InferBodyId<'db> { - fn from(it: StaticId) -> InferBodyId<'db> { - InferBodyId::DefWithBodyId(it.into()) - } -} -impl<'db> From> for InferBodyId<'db> { - fn from(it: AnonConstId<'db>) -> InferBodyId<'db> { - InferBodyId::AnonConstId(it) - } -} +impl_from!( + impl<'db> + DefWithBodyId(FunctionId, ConstId, StaticId), + AnonConstId<'db> + for InferBodyId<'db> +); impl<'db> From for InferBodyId<'db> { fn from(id: EnumVariantId) -> Self { InferBodyId::DefWithBodyId(DefWithBodyId::VariantId(id)) 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 09b999ae5fe7a..f7d831d7fc227 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 @@ -122,110 +122,31 @@ impl std::fmt::Debug for SolverDefId<'_> { } } -impl<'db> From for SolverDefId<'db> { - fn from(it: AdtId) -> SolverDefId<'db> { - SolverDefId::AdtId(it) - } -} -impl<'db> From for SolverDefId<'db> { - fn from(it: StructId) -> SolverDefId<'db> { - SolverDefId::AdtId(AdtId::StructId(it)) - } -} -impl<'db> From for SolverDefId<'db> { - fn from(it: EnumId) -> SolverDefId<'db> { - SolverDefId::AdtId(AdtId::EnumId(it)) - } -} -impl<'db> From for SolverDefId<'db> { - fn from(it: UnionId) -> SolverDefId<'db> { - SolverDefId::AdtId(AdtId::UnionId(it)) - } -} -impl<'db> From for SolverDefId<'db> { - fn from(it: ConstId) -> SolverDefId<'db> { - SolverDefId::ConstId(it) - } -} -impl<'db> From for SolverDefId<'db> { - fn from(it: FunctionId) -> SolverDefId<'db> { - SolverDefId::FunctionId(it) - } -} -impl<'db> From for SolverDefId<'db> { - fn from(it: ImplId) -> SolverDefId<'db> { - SolverDefId::ImplId(it) - } -} -impl<'db> From for SolverDefId<'db> { - fn from(it: BuiltinDeriveImplId) -> SolverDefId<'db> { - SolverDefId::BuiltinDeriveImplId(it) - } -} -impl<'db> From for SolverDefId<'db> { - fn from(it: StaticId) -> SolverDefId<'db> { - SolverDefId::StaticId(it) - } -} -impl<'db> From> for SolverDefId<'db> { - fn from(it: AnonConstId<'db>) -> SolverDefId<'db> { - SolverDefId::AnonConstId(it) - } -} -impl<'db> From for SolverDefId<'db> { - fn from(it: TraitId) -> SolverDefId<'db> { - SolverDefId::TraitId(it) - } -} -impl<'db> From for SolverDefId<'db> { - fn from(it: TypeAliasId) -> SolverDefId<'db> { - SolverDefId::TypeAliasId(it) - } -} -impl<'db> From> for SolverDefId<'db> { - fn from(it: InternedClosureId<'db>) -> SolverDefId<'db> { - SolverDefId::InternedClosureId(it) - } -} -impl<'db> From> for SolverDefId<'db> { - fn from(it: InternedCoroutineId<'db>) -> SolverDefId<'db> { - SolverDefId::InternedCoroutineId(it) - } -} -impl<'db> From> for SolverDefId<'db> { - fn from(it: InternedCoroutineClosureId<'db>) -> SolverDefId<'db> { - SolverDefId::InternedCoroutineClosureId(it) - } -} -impl<'db> From for SolverDefId<'db> { - fn from(it: InternedOpaqueTyId) -> SolverDefId<'db> { - SolverDefId::InternedOpaqueTyId(it) - } -} -impl<'db> From for SolverDefId<'db> { - fn from(it: EnumVariantId) -> SolverDefId<'db> { - SolverDefId::EnumVariantId(it) - } -} -impl<'db> From for SolverDefId<'db> { - fn from(it: Ctor) -> SolverDefId<'db> { - SolverDefId::Ctor(it) - } -} - -impl<'db> From for SolverDefId<'db> { - fn from(value: GenericDefId) -> Self { - match value { - GenericDefId::AdtId(adt_id) => SolverDefId::AdtId(adt_id), - GenericDefId::ConstId(const_id) => SolverDefId::ConstId(const_id), - GenericDefId::FunctionId(function_id) => SolverDefId::FunctionId(function_id), - GenericDefId::ImplId(impl_id) => SolverDefId::ImplId(impl_id), - GenericDefId::StaticId(static_id) => SolverDefId::StaticId(static_id), - GenericDefId::TraitId(trait_id) => SolverDefId::TraitId(trait_id), - GenericDefId::TypeAliasId(type_alias_id) => SolverDefId::TypeAliasId(type_alias_id), - } - } -} +impl_from!( + impl<'db> + AdtId(StructId, EnumId, UnionId), + ConstId, + FunctionId, + ImplId, + BuiltinDeriveImplId, + StaticId, + AnonConstId<'db>, + TraitId, + TypeAliasId, + InternedClosureId<'db>, + InternedCoroutineId<'db>, + InternedCoroutineClosureId<'db>, + InternedOpaqueTyId, + EnumVariantId, + Ctor + for SolverDefId<'db> +); + +impl_from!( + impl<'db> + GenericDefId { AdtId, ConstId, FunctionId, ImplId, StaticId, TraitId, TypeAliasId } + for SolverDefId<'db> +); impl<'db> From> for SolverDefId<'db> { #[inline] diff --git a/src/tools/rust-analyzer/crates/hir/src/from_id.rs b/src/tools/rust-analyzer/crates/hir/src/from_id.rs index e94279bc4583e..9b07aa494e448 100644 --- a/src/tools/rust-analyzer/crates/hir/src/from_id.rs +++ b/src/tools/rust-analyzer/crates/hir/src/from_id.rs @@ -7,8 +7,10 @@ use hir_def::{ AdtId, AssocItemId, BuiltinDeriveImplId, DefWithBodyId, EnumVariantId, ExpressionStoreOwnerId, FieldId, FunctionId, GenericDefId, GenericParamId, ImplId, ModuleDefId, VariantId, hir::{BindingId, LabelId}, + item_scope::ItemInNs as ItemInNsId, }; use hir_ty::next_solver::AnyImplId; +use stdx::impl_from; use crate::{ Adt, AnyFunctionId, AssocItem, BuiltinType, DefWithBody, EnumVariant, ExpressionStoreOwner, @@ -51,54 +53,28 @@ from_id![ (hir_def::ExternBlockId, crate::ExternBlock), ]; -impl From for Adt { - fn from(id: AdtId) -> Self { - match id { - AdtId::StructId(it) => Adt::Struct(it.into()), - AdtId::UnionId(it) => Adt::Union(it.into()), - AdtId::EnumId(it) => Adt::Enum(it.into()), - } - } -} - -impl From for AdtId { - fn from(id: Adt) -> Self { - match id { - Adt::Struct(it) => AdtId::StructId(it.id), - Adt::Union(it) => AdtId::UnionId(it.id), - Adt::Enum(it) => AdtId::EnumId(it.id), - } - } -} - -impl From for Variant { - fn from(v: VariantId) -> Self { - match v { - VariantId::EnumVariantId(it) => Variant::EnumVariant(it.into()), - VariantId::StructId(it) => Variant::Struct(it.into()), - VariantId::UnionId(it) => Variant::Union(it.into()), - } +impl_from!(AdtId { StructId => Struct, UnionId => Union, EnumId => Enum } for Adt); +impl_from!(Adt { Struct => StructId, Union => UnionId, Enum => EnumId } for AdtId); +impl_from!( + VariantId { EnumVariantId => EnumVariant, StructId => Struct, UnionId => Union } + for Variant +); +impl_from!( + GenericParamId { + TypeParamId => TypeParam, + ConstParamId => ConstParam, + LifetimeParamId => LifetimeParam, } -} -impl From for GenericParam { - fn from(id: GenericParamId) -> Self { - match id { - GenericParamId::TypeParamId(it) => GenericParam::TypeParam(it.into()), - GenericParamId::ConstParamId(it) => GenericParam::ConstParam(it.into()), - GenericParamId::LifetimeParamId(it) => GenericParam::LifetimeParam(it.into()), - } + for GenericParam +); +impl_from!( + GenericParam { + LifetimeParam => LifetimeParamId, + ConstParam => ConstParamId, + TypeParam => TypeParamId, } -} - -impl From for GenericParamId { - fn from(id: GenericParam) -> Self { - match id { - GenericParam::LifetimeParam(it) => GenericParamId::LifetimeParamId(it.id), - GenericParam::ConstParam(it) => GenericParamId::ConstParamId(it.id), - GenericParam::TypeParam(it) => GenericParamId::TypeParamId(it.id), - } - } -} + for GenericParamId +); impl From for EnumVariant { fn from(id: EnumVariantId) -> Self { @@ -112,22 +88,21 @@ impl From for EnumVariantId { } } -impl From for ModuleDef { - fn from(id: ModuleDefId) -> Self { - match id { - ModuleDefId::ModuleId(it) => ModuleDef::Module(it.into()), - ModuleDefId::FunctionId(it) => ModuleDef::Function(it.into()), - ModuleDefId::AdtId(it) => ModuleDef::Adt(it.into()), - ModuleDefId::EnumVariantId(it) => ModuleDef::EnumVariant(it.into()), - ModuleDefId::ConstId(it) => ModuleDef::Const(it.into()), - ModuleDefId::StaticId(it) => ModuleDef::Static(it.into()), - ModuleDefId::TraitId(it) => ModuleDef::Trait(it.into()), - ModuleDefId::TypeAliasId(it) => ModuleDef::TypeAlias(it.into()), - ModuleDefId::BuiltinType(it) => ModuleDef::BuiltinType(it.into()), - ModuleDefId::MacroId(it) => ModuleDef::Macro(it.into()), - } +impl_from!( + ModuleDefId { + ModuleId => Module, + FunctionId => Function, + AdtId => Adt, + EnumVariantId => EnumVariant, + ConstId => Const, + StaticId => Static, + TraitId => Trait, + TypeAliasId => TypeAlias, + BuiltinType => BuiltinType, + MacroId => Macro, } -} + for ModuleDef +); impl TryFrom for ModuleDefId { type Error = (); @@ -165,26 +140,19 @@ impl TryFrom for DefWithBodyId { } } -impl From for DefWithBody { - fn from(def: DefWithBodyId) -> Self { - match def { - DefWithBodyId::FunctionId(it) => DefWithBody::Function(it.into()), - DefWithBodyId::StaticId(it) => DefWithBody::Static(it.into()), - DefWithBodyId::ConstId(it) => DefWithBody::Const(it.into()), - DefWithBodyId::VariantId(it) => DefWithBody::EnumVariant(it.into()), - } +impl_from!( + DefWithBodyId { + FunctionId => Function, + StaticId => Static, + ConstId => Const, + VariantId => EnumVariant, } -} - -impl From for AssocItem { - fn from(def: AssocItemId) -> Self { - match def { - AssocItemId::FunctionId(it) => AssocItem::Function(it.into()), - AssocItemId::TypeAliasId(it) => AssocItem::TypeAlias(it.into()), - AssocItemId::ConstId(it) => AssocItem::Const(it.into()), - } - } -} + for DefWithBody +); +impl_from!( + AssocItemId { FunctionId => Function, TypeAliasId => TypeAlias, ConstId => Const } + for AssocItem +); impl TryFrom for GenericDefId { type Error = (); @@ -194,19 +162,18 @@ impl TryFrom for GenericDefId { } } -impl From for GenericDef { - fn from(def: GenericDefId) -> Self { - match def { - GenericDefId::FunctionId(it) => GenericDef::Function(it.into()), - GenericDefId::AdtId(it) => GenericDef::Adt(it.into()), - GenericDefId::TraitId(it) => GenericDef::Trait(it.into()), - GenericDefId::TypeAliasId(it) => GenericDef::TypeAlias(it.into()), - GenericDefId::ImplId(it) => GenericDef::Impl(it.into()), - GenericDefId::ConstId(it) => GenericDef::Const(it.into()), - GenericDefId::StaticId(it) => GenericDef::Static(it.into()), - } +impl_from!( + GenericDefId { + FunctionId => Function, + AdtId => Adt, + TraitId => Trait, + TypeAliasId => TypeAlias, + ImplId => Impl, + ConstId => Const, + StaticId => Static, } -} + for GenericDef +); impl From for GenericDefId { fn from(id: Adt) -> Self { @@ -218,15 +185,10 @@ impl From for GenericDefId { } } -impl From for VariantId { - fn from(def: Variant) -> Self { - match def { - Variant::Struct(it) => VariantId::StructId(it.id), - Variant::EnumVariant(it) => VariantId::EnumVariantId(it.into()), - Variant::Union(it) => VariantId::UnionId(it.id), - } - } -} +impl_from!( + Variant { Struct => StructId, EnumVariant => EnumVariantId, Union => UnionId } + for VariantId +); impl From for FieldId { fn from(def: Field) -> Self { @@ -266,15 +228,7 @@ impl From<(ExpressionStoreOwnerId, LabelId)> for Label { } } -impl From for ItemInNs { - fn from(it: hir_def::item_scope::ItemInNs) -> Self { - match it { - hir_def::item_scope::ItemInNs::Types(it) => ItemInNs::Types(it.into()), - hir_def::item_scope::ItemInNs::Values(it) => ItemInNs::Values(it.into()), - hir_def::item_scope::ItemInNs::Macros(it) => ItemInNs::Macros(it.into()), - } - } -} +impl_from!(ItemInNsId { Types => Types, Values => Values, Macros => Macros } for ItemInNs); impl TryFrom for hir_def::item_scope::ItemInNs { type Error = (); diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index fd00480c0a9fb..9fde9abf66095 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -416,15 +416,10 @@ impl_from!( for ModuleDef ); -impl From for ModuleDef { - fn from(var: Variant) -> Self { - match var { - Variant::Struct(t) => Adt::from(t).into(), - Variant::Union(t) => Adt::from(t).into(), - Variant::EnumVariant(t) => t.into(), - } - } -} +impl_from!( + Variant { Struct => Adt, Union => Adt, EnumVariant => EnumVariant } + for ModuleDef +); impl ModuleDef { pub fn module(self, db: &dyn HirDatabase) -> Option { @@ -1923,19 +1918,14 @@ impl From for ExpressionStoreOwner { } } -impl From for ExpressionStoreOwner { - fn from(v: ExpressionStoreOwnerId) -> Self { - match v { - ExpressionStoreOwnerId::Signature(generic_def_id) => { - Self::Signature(generic_def_id.into()) - } - ExpressionStoreOwnerId::Body(def_with_body_id) => Self::Body(def_with_body_id.into()), - ExpressionStoreOwnerId::VariantFields(variant_id) => { - Self::VariantFields(variant_id.into()) - } - } +impl_from!( + ExpressionStoreOwnerId { + Signature => Signature, + Body => Body, + VariantFields => VariantFields, } -} + for ExpressionStoreOwner +); impl ExpressionStoreOwner { pub fn module(self, db: &dyn HirDatabase) -> Module { @@ -3478,17 +3468,21 @@ impl From for ItemInNs { } } -impl From for ItemInNs { - fn from(module_def: ModuleDef) -> Self { - match module_def { - ModuleDef::Static(_) | ModuleDef::Const(_) | ModuleDef::Function(_) => { - ItemInNs::Values(module_def) - } - ModuleDef::Macro(it) => ItemInNs::Macros(it), - _ => ItemInNs::Types(module_def), - } - } -} +impl_from!( + ModuleDef { + Module => Types, + Function => Values, + Adt => Types, + EnumVariant => Types, + Const => Values, + Static => Values, + Trait => Types, + TypeAlias => Types, + BuiltinType => Types, + Macro => Macros, + } + for ItemInNs +); impl ItemInNs { pub fn into_module_def(self) -> ModuleDef { @@ -3831,15 +3825,7 @@ impl HasVisibility for AssocItem { } } -impl From for ModuleDef { - fn from(assoc: AssocItem) -> Self { - match assoc { - AssocItem::Function(it) => ModuleDef::Function(it), - AssocItem::Const(it) => ModuleDef::Const(it), - AssocItem::TypeAlias(it) => ModuleDef::TypeAlias(it), - } - } -} +impl_from!(AssocItem { Function, Const, TypeAlias } for ModuleDef); #[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)] pub enum GenericDef { @@ -5264,23 +5250,13 @@ enum TypeOwnerId<'db> { NoParams(base_db::Crate), } -impl<'db> From for TypeOwnerId<'db> { - fn from(it: GenericDefId) -> TypeOwnerId<'db> { - TypeOwnerId::GenericDefId(it) - } -} - -impl<'db> From for TypeOwnerId<'db> { - fn from(it: BuiltinDeriveImplId) -> TypeOwnerId<'db> { - TypeOwnerId::BuiltinDeriveImplId(it) - } -} - -impl<'db> From> for TypeOwnerId<'db> { - fn from(it: AnonConstId<'db>) -> TypeOwnerId<'db> { - TypeOwnerId::AnonConstId(it) - } -} +impl_from!( + impl<'db> + GenericDefId, + BuiltinDeriveImplId, + AnonConstId<'db> + for TypeOwnerId<'db> +); impl TypeOwnerId<'_> { fn unify(self, other: Self) -> Option { @@ -7009,15 +6985,11 @@ impl ScopeDef<'_> { } } -impl From for ScopeDef<'_> { - fn from(item: ItemInNs) -> Self { - match item { - ItemInNs::Types(id) => ScopeDef::ModuleDef(id), - ItemInNs::Values(id) => ScopeDef::ModuleDef(id), - ItemInNs::Macros(id) => ScopeDef::ModuleDef(ModuleDef::Macro(id)), - } - } -} +impl_from!( + impl<'db> + ItemInNs { Types => ModuleDef, Values => ModuleDef, Macros => ModuleDef } + for ScopeDef<'db> +); #[derive(Clone, Debug, PartialEq, Eq)] pub struct Adjustment<'db> { diff --git a/src/tools/rust-analyzer/crates/ide-db/src/defs.rs b/src/tools/rust-analyzer/crates/ide-db/src/defs.rs index 52cd66400007e..c1fd002b3467b 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/defs.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/defs.rs @@ -22,7 +22,7 @@ use hir::{ Visibility, }; use span::Edition; -use stdx::format_to; +use stdx::{format_to, impl_from}; use syntax::{ SyntaxKind, SyntaxNode, SyntaxToken, ast::{self, AstNode}, @@ -891,33 +891,26 @@ impl<'db> NameRefClass<'db> { } } -macro_rules! impl_from_definition { - ($($variant:ident: $ty:ty),* $(,)?) => {$( - impl<'db> From<$ty> for Definition<'db> { - fn from(it: $ty) -> Self { - Definition::$variant(it) - } - } - )*}; -} - -impl_from_definition!( - Field: Field, - TupleField: TupleField<'db>, - Module: Module, - Function: Function, - Adt: Adt, - EnumVariant: EnumVariant, - Const: Const, - Static: Static, - Trait: Trait, - TypeAlias: TypeAlias, - BuiltinType: BuiltinType, - Local: Local<'db>, - GenericParam: GenericParam, - Label: Label, - Macro: Macro, - ExternCrateDecl: ExternCrateDecl, +impl_from!( + impl<'db> + Field, + TupleField<'db>, + Module, + Function, + Adt, + EnumVariant, + Const, + Static, + Trait, + TypeAlias, + BuiltinType, + Local<'db>, + GenericParam, + Label, + Macro, + ExternCrateDecl, + InlineAsmOperand + for Definition<'db> ); impl<'db> From for Definition<'db> { @@ -926,12 +919,6 @@ impl<'db> From for Definition<'db> { } } -impl<'db> From for Definition<'db> { - fn from(value: InlineAsmOperand) -> Self { - Definition::InlineAsmOperand(value) - } -} - impl<'db> From, InlineAsmOperand>> for Definition<'db> { fn from(value: Either, InlineAsmOperand>) -> Self { value.either(Definition::from, Definition::from) diff --git a/src/tools/rust-analyzer/crates/stdx/src/macros.rs b/src/tools/rust-analyzer/crates/stdx/src/macros.rs index 880e2da70fc39..907746888f63f 100644 --- a/src/tools/rust-analyzer/crates/stdx/src/macros.rs +++ b/src/tools/rust-analyzer/crates/stdx/src/macros.rs @@ -30,15 +30,93 @@ macro_rules! format_to_acc { }; } -/// Generates `From` impls for `Enum E { Foo(Foo), Bar(Bar) }` enums +/// Generates `From` impls that wrap values in, or map variants between, enums. /// -/// # Example +/// Enum mappings with `Source => Target` rename the variant and convert its payload with `.into()`. +/// +/// # Examples /// /// ```ignore /// impl_from!(Struct, Union, Enum for Adt); +/// impl_from!(impl<'db> Item, InternedItem<'db> for ItemId<'db>); +/// impl_from!(AssocItem { Function, Const, TypeAlias } for Item); +/// impl_from!(AdtId { StructId => Struct, EnumId => Enum } for Adt); /// ``` #[macro_export] macro_rules! impl_from { + ( + impl<$lifetime:lifetime> + $source:ident $(<$source_lifetime:lifetime>)? + { $($source_variant:ident $(=> $target_variant:ident)?),* $(,)? } + for $target:ident<$target_lifetime:lifetime> + ) => { + impl<$lifetime> From<$source$(<$source_lifetime>)?> for $target<$target_lifetime> { + fn from(value: $source$(<$source_lifetime>)?) -> Self { + match value { + $( + $source::$source_variant(value) => $crate::impl_from!( + @map_enum_variant $target, value, $source_variant + $(=> $target_variant)? + ), + )* + } + } + } + }; + ( + $source:ident + { $($source_variant:ident $(=> $target_variant:ident)?),* $(,)? } + for $target:ident + ) => { + impl From<$source> for $target { + fn from(value: $source) -> Self { + match value { + $( + $source::$source_variant(value) => $crate::impl_from!( + @map_enum_variant $target, value, $source_variant + $(=> $target_variant)? + ), + )* + } + } + } + }; + (@map_enum_variant $target:ident, $value:ident, $variant:ident) => { + $target::$variant($value) + }; + ( + @map_enum_variant $target:ident, $value:ident, + $source_variant:ident => $target_variant:ident + ) => { + $target::$target_variant($value.into()) + }; + ( + impl<$lifetime:lifetime> + $( + $variant:ident $(<$variant_lifetime:lifetime>)? + $(($($sub_variant:ident $(<$sub_variant_lifetime:lifetime>)?),*))? + ),* + for $enum:ident<$enum_lifetime:lifetime> + ) => { + $( + impl<$lifetime> From<$variant$(<$variant_lifetime>)?> for $enum<$enum_lifetime> { + fn from(it: $variant$(<$variant_lifetime>)?) -> $enum<$enum_lifetime> { + $enum::$variant(it) + } + } + $($( + impl<$lifetime> From<$sub_variant$(<$sub_variant_lifetime>)?> + for $enum<$enum_lifetime> + { + fn from( + it: $sub_variant$(<$sub_variant_lifetime>)?, + ) -> $enum<$enum_lifetime> { + $enum::$variant($variant::$sub_variant(it)) + } + } + )*)? + )* + }; ($($variant:ident $(($($sub_variant:ident),*))?),* for $enum:ident) => { $( impl From<$variant> for $enum { From 00afadf13c2711536d5993ccfd8e4e709b3792ac Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sun, 19 Jul 2026 15:12:47 +0200 Subject: [PATCH 14/76] internal: Shrink hir::Expr from 64 to 48 bytes --- .../rust-analyzer/crates/hir-def/src/expr_store/lower.rs | 4 ++-- .../crates/hir-def/src/expr_store/lower/format_args.rs | 7 ++++++- src/tools/rust-analyzer/crates/hir-def/src/hir.rs | 6 +++++- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs index 0320f6b93b973..fd5b25ca2ffba 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs @@ -1310,10 +1310,10 @@ impl<'db> ExprCollector<'db> { /// Returns `None` if and only if the expression is `#[cfg]`d out. fn maybe_collect_expr(&mut self, expr: ast::Expr) -> Option { - let syntax_ptr = AstPtr::new(&expr); if !self.check_cfg(&expr) { return None; } + let syntax_ptr = AstPtr::new(&expr); // FIXME: Move some of these arms out into separate methods for clarity Some(match expr { @@ -1589,7 +1589,7 @@ impl<'db> ExprCollector<'db> { }; Expr::RecordLit { path, fields, spread } } else { - Expr::RecordLit { path, fields: Box::default(), spread: RecordSpread::None } + Expr::RecordLit { path, fields: ThinVec::default(), spread: RecordSpread::None } }; self.alloc_expr(record_lit, syntax_ptr) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/format_args.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/format_args.rs index b058ad6d9ab8b..1ecd18fb53aec 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/format_args.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/format_args.rs @@ -5,6 +5,7 @@ use hir_expand::name::Name; use intern::{Symbol, sym}; use span::SyntaxContext; use syntax::{AstPtr, AstToken as _, ast}; +use thin_vec::ThinVec; use crate::{ builtin_type::BuiltinUint, @@ -875,7 +876,11 @@ impl<'db> ExprCollector<'db> { match self.lang_path(lang_items.FormatPlaceholder) { Some(path) => self.alloc_expr_desugared(Expr::RecordLit { path, - fields: Box::new([position, flags, precision, width]), + fields: { + let mut fields = ThinVec::with_capacity(4); + fields.extend([position, flags, precision, width]); + fields + }, spread: RecordSpread::None, }), None => self.missing_expr(), diff --git a/src/tools/rust-analyzer/crates/hir-def/src/hir.rs b/src/tools/rust-analyzer/crates/hir-def/src/hir.rs index a80056904402a..df30137372410 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/hir.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/hir.rs @@ -23,6 +23,7 @@ use intern::Symbol; use la_arena::Idx; use rustc_apfloat::ieee::{Double, Half, Quad, Single}; use syntax::ast; +use thin_vec::ThinVec; use type_ref::TypeRefId; use crate::{ @@ -261,7 +262,7 @@ pub enum Expr { }, RecordLit { path: Path, - fields: Box<[RecordLitField]>, + fields: ThinVec, spread: RecordSpread, }, Field { @@ -326,6 +327,9 @@ pub enum Expr { IncludeBytes, } +#[cfg(target_pointer_width = "64")] +const _: () = assert!(std::mem::size_of::() == 48); + impl Expr { pub fn precedence(&self) -> ast::prec::ExprPrecedence { use ast::prec::ExprPrecedence; From a8a8a1cb30d1348599f8c3c215a66f63f5c35f25 Mon Sep 17 00:00:00 2001 From: dfireBird Date: Wed, 20 May 2026 20:59:37 +0530 Subject: [PATCH 15/76] feat: implement lowering of HRTB --- .../crates/hir-def/src/expr_store.rs | 2 +- .../crates/hir-def/src/expr_store/lower.rs | 38 ++- .../crates/hir-def/src/expr_store/pretty.rs | 11 + .../crates/hir-def/src/hir/type_ref.rs | 1 + .../rust-analyzer/crates/hir-def/src/lib.rs | 6 + .../crates/hir-ty/src/display.rs | 8 + .../rust-analyzer/crates/hir-ty/src/lower.rs | 298 +++++++++++------- .../crates/hir-ty/src/lower/path.rs | 4 +- .../hir-ty/src/tests/display_source_code.rs | 2 +- .../crates/hir-ty/src/tests/simple.rs | 79 +++++ .../crates/hir-ty/src/tests/traits.rs | 38 +++ 11 files changed, 353 insertions(+), 134 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store.rs index dec911f7161da..7897d22ca0ba0 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store.rs @@ -874,7 +874,7 @@ impl ExpressionStore { visitor.on_anon_const_expr(*len); } TypeRef::Fn(fn_type) => { - let FnType { params, is_varargs: _, is_unsafe: _, abi: _ } = &**fn_type; + let FnType { params, is_varargs: _, is_unsafe: _, abi: _, binder: _ } = &**fn_type; params.iter().for_each(|(_, param_ty)| visitor.on_type(*param_ty)); } TypeRef::ImplTrait(bounds) | TypeRef::DynTrait(bounds) => { diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs index 5cbcfe5f239c1..181312bc0f659 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs @@ -26,8 +26,8 @@ use stdx::never; use syntax::{ AstNode, AstPtr, SyntaxNodePtr, ast::{ - self, ArrayExprKind, AstChildren, BlockExpr, HasArgList, HasAttrs, HasGenericArgs, - HasGenericParams, HasLoopBody, HasName, HasTypeBounds, IsString, RangeItem, + self, ArrayExprKind, AstChildren, BlockExpr, ForBinder, HasArgList, HasAttrs, + HasGenericArgs, HasGenericParams, HasLoopBody, HasName, HasTypeBounds, IsString, RangeItem, SlicePatComponents, }, }; @@ -465,6 +465,8 @@ pub struct ExprCollector<'db> { is_lowering_coroutine: bool, + for_type_binder: Option>, + /// Legacy (`macro_rules!`) macros can have multiple definitions and shadow each other, /// and we need to find the current definition. So we track the number of definitions we saw. current_block_legacy_macro_defs_count: FxHashMap, @@ -636,6 +638,7 @@ impl<'db> ExprCollector<'db> { krate, name_generator_index: 0, named_lifetime_store: NamedLifetimeStore::default(), + for_type_binder: None, }; result.store.inference_roots = Some(SmallVec::new()); result @@ -758,16 +761,23 @@ impl<'db> ExprCollector<'db> { let abi = inner.abi().map(lower_abi).unwrap_or(ExternAbi::Rust); params.push((None, ret_ty)); + + let binder = self.for_type_binder.take().map(|b| b.into()); TypeRef::Fn(Box::new(FnType { is_varargs, is_unsafe: inner.unsafe_token().is_some(), abi, params: params.into_boxed_slice(), + binder, })) } // for types are close enough for our purposes to the inner type for now... ast::Type::ForType(inner) => { - return self.lower_type_ref_opt(inner.ty(), impl_trait_lower_fn); + let binder = self.lower_for_binder_opt(inner.for_binder()); + let old_for_binder = self.for_type_binder.replace(binder); + let ty = self.lower_type_ref_opt(inner.ty(), impl_trait_lower_fn); + self.for_type_binder = old_for_binder; + return ty; } ast::Type::ImplTraitType(inner) => { if self.outer_impl_trait { @@ -1245,13 +1255,7 @@ impl<'db> ExprCollector<'db> { let Some(kind) = node.kind() else { return TypeBound::Error }; match kind { ast::TypeBoundKind::PathType(binder, path_type) => { - let binder = match binder.and_then(|it| it.generic_param_list()) { - Some(gpl) => gpl - .lifetime_params() - .flat_map(|lp| lp.lifetime().map(|lt| Name::new_lifetime(<.text()))) - .collect(), - None => ThinVec::default(), - }; + let binder = self.lower_for_binder_opt(binder); let m = match node.question_mark_token() { Some(_) => TraitBoundModifier::Maybe, None => TraitBoundModifier::None, @@ -1283,6 +1287,20 @@ impl<'db> ExprCollector<'db> { } } + fn lower_for_binder_opt(&mut self, binder: Option) -> ThinVec { + binder.map(|b| self.lower_for_binder(b)).unwrap_or_default() + } + + fn lower_for_binder(&mut self, binder: ForBinder) -> ThinVec { + match binder.generic_param_list() { + Some(gpl) => gpl + .lifetime_params() + .flat_map(|lp| lp.lifetime().map(|lt| Name::new_lifetime(<.text()))) + .collect(), + None => ThinVec::default(), + } + } + fn lower_const_arg_opt(&mut self, arg: Option) -> ConstRef { ConstRef { expr: self.with_fresh_binding_expr_root(|this| { diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/pretty.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/pretty.rs index 0058ddc1e4a44..bc16a9e97968b 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/pretty.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/pretty.rs @@ -1331,6 +1331,17 @@ impl Printer<'_> { TypeRef::Fn(fn_) => { let ((_, return_type), args) = fn_.params.split_last().expect("TypeRef::Fn is missing return type"); + if let Some(binder) = &fn_.binder { + w!( + self, + "for<{}> ", + binder + .iter() + .map(|it| it.display(self.db, self.edition)) + .format(", ") + .to_string() + ); + } if fn_.is_unsafe { w!(self, "unsafe "); } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/hir/type_ref.rs b/src/tools/rust-analyzer/crates/hir-def/src/hir/type_ref.rs index 6cd8377b5fc6f..8e29268c1c219 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/hir/type_ref.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/hir/type_ref.rs @@ -94,6 +94,7 @@ pub struct TraitRef { #[derive(Clone, PartialEq, Eq, Hash, Debug)] pub struct FnType { + pub binder: Option>, pub params: Box<[(Option, TypeRefId)]>, pub is_varargs: bool, pub is_unsafe: bool, diff --git a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs index 8b93fe5e2f01b..ce171d2734df6 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs @@ -712,6 +712,12 @@ pub struct LifetimeParamId { pub local_id: LocalLifetimeParamId, } +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct HrtbLifetimeParamId { + pub scope: GenericDefId, + pub local_id: usize, +} + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, salsa_macros::Supertype)] pub enum ItemContainerId { ExternBlockId(ExternBlockId), 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 c5ce3af3a9ac9..ff7f849d304b3 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs @@ -2522,6 +2522,14 @@ impl<'db> HirDisplayWithExpressionStore<'db> for TypeRefId { write!(f, "]")?; } TypeRef::Fn(fn_) => { + if let Some(binder) = &fn_.binder { + let edition = f.edition(); + write!( + f, + "for<{}> ", + binder.iter().map(|it| it.display(f.db, edition)).format(", ") + )?; + } if fn_.is_unsafe { write!(f, "unsafe ")?; } 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 e251fa84ed1a1..19d550f91c216 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs @@ -33,8 +33,8 @@ use hir_def::{ TraitFlags, TraitSignature, TypeAliasFlags, TypeAliasSignature, }, type_ref::{ - ConstRef, FnType, LifetimeRefId, PathId, TraitBoundModifier, TraitRef as HirTraitRef, - TypeBound, TypeRef, TypeRefId, + ConstRef, FnType, LifetimeRef, LifetimeRefId, PathId, TraitBoundModifier, + TraitRef as HirTraitRef, TypeBound, TypeRef, TypeRefId, }, }; use hir_expand::name::Name; @@ -44,10 +44,10 @@ use rustc_abi::ExternAbi; use rustc_ast_ir::Mutability; use rustc_hash::FxHashSet; use rustc_type_ir::{ - AliasTyKind, BoundRegion, BoundRegionKind, BoundTyKind, BoundVar, BoundVarIndexKind, - BoundVariableKind, DebruijnIndex, ExistentialPredicate, ExistentialProjection, - ExistentialTraitRef, FnSig, Interner, OutlivesPredicate, TermKind, TyKind, TypeFoldable, - TypeVisitableExt, Upcast, UpcastFrom, elaborate, + AliasTyKind, BoundRegion, BoundRegionKind, BoundTyKind, BoundVar, BoundVariableKind, + DebruijnIndex, ExistentialPredicate, ExistentialProjection, ExistentialTraitRef, FnSig, + Interner, OutlivesPredicate, TermKind, TyKind, TypeFoldable, TypeVisitableExt, Upcast, + UpcastFrom, elaborate, inherent::{Clause as _, GenericArgs as _, IntoKind as _, Region as _, Ty as _}, }; use smallvec::SmallVec; @@ -226,7 +226,7 @@ pub struct TyLoweringContext<'db, 'a> { pub(crate) defined_anon_consts: ThinVec, infer_vars: Option<&'a mut dyn TyLoweringInferVarsCtx<'db>>, is_lowering_impl_trait_bounds: bool, - bound_vars: Vec>, // FIXME: HRTB and other for lifetime doesn't change it now + bound_vars: Vec<(Vec, BoundVarKinds<'db>)>, lifetime_lowering_mode: LifetimeLoweringMode, } @@ -244,7 +244,8 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { let impl_trait_mode = ImplTraitLoweringState::new(ImplTraitLoweringMode::Disallowed); let in_binders = DebruijnIndex::ZERO; let interner = DbInterner::new_with(db, resolver.krate()); - let bound_vars = vec![BoundVarKinds::empty(interner)]; + let bound_vars = + vec![(Vec::new(), TyLoweringContext::bound_vars(db, interner, generic_def, generics))]; Self { db, // Can provide no block since we don't use it for trait solving. @@ -299,10 +300,13 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { pub(crate) fn with_shifted_in( &mut self, - debruijn: DebruijnIndex, + binder: &[Name], f: impl FnOnce(&mut TyLoweringContext<'db, '_>) -> T, - ) -> T { - self.with_debruijn(self.in_binders.shifted_in(debruijn.as_u32()), f) + ) -> (T, BoundVarKinds<'db>) { + self.push_bound_vars(binder); + let res = self.with_debruijn(self.in_binders.shifted_in(1), f); + let bound_vars = self.pop_bound_vars(); + (res, bound_vars) } pub(crate) fn with_impl_trait_mode(self, impl_trait_mode: ImplTraitLoweringMode) -> Self { @@ -372,8 +376,22 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { } } + fn push_bound_vars(&mut self, binder: &[Name]) { + let bound_vars = BoundVarKinds::new_from_iter( + self.interner, + binder.iter().map(|_| { + BoundVariableKind::Region(BoundRegionKind::Named(self.generic_def.into())) + }), + ); + self.bound_vars.push((binder.to_vec(), bound_vars)); + } + + fn pop_bound_vars(&mut self) -> BoundVarKinds<'db> { + self.bound_vars.pop().unwrap().1 + } + fn peek_bound_vars(&self) -> BoundVarKinds<'db> { - *self.bound_vars.last().unwrap() + self.bound_vars.last().unwrap().1 } fn bound_vars( @@ -504,32 +522,50 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { self.types.regions.error } else { if is_late_bound { - if self.lifetime_lowering_mode == LifetimeLoweringMode::Bound { - Region::new_bound( - self.interner, - self.in_binders, - BoundRegion { - var: BoundVar::from_u32(index), - kind: BoundRegionKind::Named(id.parent.into()), - }, - ) - } else { - let solver_def_id = id.parent.into(); - Region::new_late_param( - self.interner, - solver_def_id, - BoundRegion { - var: BoundVar::from_u32(index), - kind: BoundRegionKind::Named(solver_def_id), - }, - ) - } + self.hrtb_region_param( + index, + DebruijnIndex::from_usize(self.in_binders.as_usize()), + id.parent, + ) } else { Region::new_early_param(self.interner, EarlyParamRegion { id, index }) } } } + fn hrtb_region_param( + &self, + index: u32, + debruijn: DebruijnIndex, + parent: GenericDefId, + ) -> Region<'db> { + if self.param_index_is_disallowed(index) { + // FIXME: Report an error. + self.types.regions.error + } else { + if self.lifetime_lowering_mode == LifetimeLoweringMode::Bound { + Region::new_bound( + self.interner, + debruijn, + BoundRegion { + var: BoundVar::from_u32(index), + kind: BoundRegionKind::Named(parent.into()), + }, + ) + } else { + let solver_def_id = parent.into(); + Region::new_late_param( + self.interner, + solver_def_id, + BoundRegion { + var: BoundVar::from_u32(index), + kind: BoundRegionKind::Named(solver_def_id), + }, + ) + } + } + } + #[tracing::instrument(skip(self), ret)] pub fn lower_ty_ext(&mut self, type_ref_id: TypeRefId) -> (Ty<'db>, Option) { let interner = self.interner; @@ -714,7 +750,8 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { let (params, ret_ty) = fn_.split_params_and_ret(); let old_lifetime_elision = self.lifetime_elision; let mut args = Vec::with_capacity(fn_.params.len()); - self.with_shifted_in(DebruijnIndex::from_u32(1), |ctx: &mut TyLoweringContext<'_, '_>| { + let binder = fn_.binder.as_ref().map(|b| b.as_ref()).unwrap_or_default(); + let (_, binder) = self.with_shifted_in(binder, |ctx: &mut TyLoweringContext<'_, '_>| { ctx.lifetime_elision = LifetimeElisionKind::AnonymousCreateParameter { report_in_path: false }; args.extend(params.iter().map(|&(_, tr)| ctx.lower_ty(tr))); @@ -723,8 +760,6 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { }); self.lifetime_elision = old_lifetime_elision; - // FIXME: When we don't drop HRTB lifetimes, use those here. - let binder = BoundVarKinds::empty(interner); Ty::new_fn_ptr( interner, Binder::bind_with_vars( @@ -850,12 +885,19 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { where_predicate: &'b WherePredicate, ignore_bindings: bool, ) -> impl Iterator, GenericPredicateSource)> + use<'a, 'b, 'db> { + let lower_type_outlives = |ctx: &mut TyLoweringContext<'db, '_>, + target: &TypeRefId, + bound| { + let self_ty = ctx.lower_ty(*target); + let clause = ctx.lower_type_bound(bound, self_ty, ignore_bindings).collect::>(); + Either::Left(clause.into_iter()) + }; + match where_predicate { - WherePredicate::ForLifetime { target, bound, .. } - | WherePredicate::TypeBound { target, bound } => { - let self_ty = self.lower_ty(*target); - Either::Left(self.lower_type_bound(bound, self_ty, ignore_bindings)) + WherePredicate::ForLifetime { target, bound, lifetimes } => { + self.with_shifted_in(lifetimes, |ctx| lower_type_outlives(ctx, target, bound)).0 } + WherePredicate::TypeBound { target, bound } => lower_type_outlives(self, target, bound), &WherePredicate::Lifetime { bound, target } => Either::Right(iter::once(( Clause(Predicate::new( self.interner, @@ -881,42 +923,48 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { let interner = self.interner; let meta_sized = self.lang_items.MetaSized; let pointee_sized = self.lang_items.PointeeSized; + let mut assoc_bounds = None; let mut clause = None; - match bound { - &TypeBound::Path(path, TraitBoundModifier::None) | &TypeBound::ForLifetime(_, path) => { - let binder = self.peek_bound_vars(); - // 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. - 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, - path.type_ref().into(), - ); - } - clause = Some(Clause(Predicate::new( - interner, - Binder::bind_with_vars( - rustc_type_ir::PredicateKind::Clause( - rustc_type_ir::ClauseKind::Trait(TraitPredicate { - trait_ref, - polarity: rustc_type_ir::PredicatePolarity::Positive, - }), - ), - binder, - ), - ))); + + let mut lower_path_bound = |ctx: &mut TyLoweringContext<'db, '_>, path| { + let binder = ctx.peek_bound_vars(); + + if let Some((trait_ref, mut ctx)) = ctx.lower_trait_ref_from_path(path, self_ty) { + // FIXME(sized-hierarchy): Remove this bound modifications once we have implemented + // sized-hierarchy correctly. + 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, path.type_ref().into()) + .map(|iter| iter.collect::>()); } + clause = Some(Clause(Predicate::new( + interner, + Binder::bind_with_vars( + rustc_type_ir::PredicateKind::Clause(rustc_type_ir::ClauseKind::Trait( + TraitPredicate { + trait_ref, + polarity: rustc_type_ir::PredicatePolarity::Positive, + }, + )), + binder, + ), + ))); } } + }; + + match bound { + &TypeBound::ForLifetime(ref binder, path) => { + self.with_shifted_in(binder, |ctx| lower_path_bound(ctx, path)).0 + } + &TypeBound::Path(path, TraitBoundModifier::None) => lower_path_bound(self, path), &TypeBound::Path(path, TraitBoundModifier::Maybe) => { let sized_trait = self.lang_items.Sized; // Don't lower associated type bindings as the only possible relaxed trait bound @@ -961,15 +1009,15 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { // 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 bounds = self.with_shifted_in(DebruijnIndex::from_u32(1), |ctx| { + let bounds = 'bounds: { let mut principal = None; let mut auto_traits = SmallVec::<[_; 3]>::new(); let mut projections = Vec::new(); let mut had_error = false; for b in bounds { - let db = ctx.db; - ctx.lower_type_bound(b, dummy_self_ty, false).for_each(|(b, _)| { + let db = self.db; + self.lower_type_bound(b, dummy_self_ty, false).for_each(|(b, _)| { match b.kind().skip_binder() { rustc_type_ir::ClauseKind::Trait(t) => { let id = t.def_id(); @@ -1006,12 +1054,12 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { } if had_error { - return None; + break 'bounds None; } if principal.is_none() && auto_traits.is_empty() { // No traits is not allowed. - return None; + break 'bounds None; } // `Send + Sync` is the same as `Sync + Send`. @@ -1200,20 +1248,11 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { interner, principal.into_iter().chain(projections).chain(auto_traits), )) - }); + }; if let Some(bounds) = bounds { let region = match region { - 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(1)), - var, - ) - } - _ => it, - }, + Some(it) => it, None => Region::new_static(self.interner), }; Ty::new_dynamic(self.interner, bounds, region) @@ -1234,44 +1273,41 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { ); let prev_is_lowering_impl_trait_bounds = mem::replace(&mut self.is_lowering_impl_trait_bounds, true); - let (predicates, assoc_ty_bounds_start) = - self.with_shifted_in(DebruijnIndex::from_u32(1), |ctx| { - let mut predicates = Vec::new(); - let mut assoc_ty_bounds = Vec::new(); - for b in bounds { - for (pred, source) in ctx.lower_type_bound(b, self_ty, false) { - match source { - GenericPredicateSource::SelfOnly => predicates.push(pred), - GenericPredicateSource::AssocTyBound => assoc_ty_bounds.push(pred), - } - } - } - if !ctx.unsized_types.contains(&self_ty) { - let sized_trait = self.lang_items.Sized; - let sized_clause = sized_trait.map(|trait_id| { - let trait_ref = TraitRef::new_from_args( - interner, - trait_id.into(), - GenericArgs::new_from_slice(&[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); + let mut predicates = Vec::new(); + let mut assoc_ty_bounds = Vec::new(); + for b in bounds { + for (pred, source) in self.lower_type_bound(b, self_ty, false) { + match source { + GenericPredicateSource::SelfOnly => predicates.push(pred), + GenericPredicateSource::AssocTyBound => assoc_ty_bounds.push(pred), } + } + } - let assoc_ty_bounds_start = predicates.len() as u32; - predicates.extend(assoc_ty_bounds); - (predicates, assoc_ty_bounds_start) + if !self.unsized_types.contains(&self_ty) { + let sized_trait = self.lang_items.Sized; + let sized_clause = sized_trait.map(|trait_id| { + let trait_ref = TraitRef::new_from_args( + interner, + trait_id.into(), + GenericArgs::new_from_slice(&[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); + } + + let assoc_ty_bounds_start = predicates.len() as u32; + predicates.extend(assoc_ty_bounds); self.is_lowering_impl_trait_bounds = prev_is_lowering_impl_trait_bounds; ImplTrait { @@ -1281,6 +1317,10 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { } pub(crate) fn lower_lifetime(&mut self, lifetime: LifetimeRefId) -> Region<'db> { + if let Some(region) = self.find_and_lower_hrtb_lifetime(lifetime) { + return region; + }; + match self.resolver.resolve_lifetime(&self.store[lifetime]) { Some(resolution) => match resolution { LifetimeNs::Static => Region::new_static(self.interner), @@ -1293,6 +1333,24 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { None => Region::error(self.interner), } } + + fn find_and_lower_hrtb_lifetime(&mut self, lifetime: LifetimeRefId) -> Option> { + if let LifetimeRef::Named(lt_name) = &self.store[lifetime] { + self.bound_vars.iter().rev().enumerate().find_map(|(debruijn, (binder, _))| { + binder.iter().enumerate().find_map(|(index, l)| { + (l == lt_name).then(|| { + self.hrtb_region_param( + index as u32, + DebruijnIndex::from_usize(debruijn), + self.generic_def, + ) + }) + }) + }) + } else { + None + } + } } #[derive(Clone, PartialEq, Eq)] 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 27d52881c6471..77037c5b12d13 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 @@ -890,11 +890,11 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> { ) } - pub(super) fn assoc_type_bindings_from_type_bound<'c>( + pub(super) fn assoc_type_bindings_from_type_bound( mut self, trait_ref: TraitRef<'db>, span: Span, - ) -> Option, GenericPredicateSource)> + use<'a, 'b, 'c, 'db>> + ) -> Option, GenericPredicateSource)> + use<'a, 'b, 'db>> { let interner = self.ctx.interner; self.current_or_prev_segment.args_and_bindings.map(|args_and_bindings| { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/display_source_code.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/display_source_code.rs index 5a4a6562ad3e9..fe7327134903e 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/display_source_code.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/display_source_code.rs @@ -85,7 +85,7 @@ fn render_dyn_for_ty() { trait Foo<'a> {} fn foo(foo: &dyn for<'a> Foo<'a>) {} - // ^^^ &(dyn Foo<'?> + 'static) + // ^^^ &(dyn Foo<'_> + 'static) "#, ); } 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 d7b7e4783978e..0c57d050f383f 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 @@ -4359,3 +4359,82 @@ fn check() { "#]], ); } + +#[test] +fn hrtb_fn_ptr() { + check_infer( + r#" +//- minicore: fn + +fn foo<'b>(f: for <'a> fn(&'a u32, &'b u32)) {} +"#, + expect![[r#" + 12..13 'f': fn(&'_ u32, &'_ u32) + 46..48 '{}': () + "#]], + ); +} + +#[test] +fn hrtb_with_where_predicate() { + check_no_mismatches( + r#" +trait Echo<'a> { + fn echo(&self, s: &'a str) -> &'a str; +} + +struct Bot; + +// Implement Echo<'b> for &'a Bot — independent of both 'a and 'b +impl<'a, 'b> Echo<'b> for &'a Bot { + fn echo(&self, s: &'b str) -> &'b str { + s + } +} + +fn foo(val: T) +where + for<'a, 'b> &'a T: Echo<'b>, +{ + let owned = String::from(" hello "); + let v = (&val).echo(&owned)); +} +"#, + ); +} + +#[test] +fn nested() { + check_no_mismatches( + r#" +//- minicore: fn +#![feature(lang_items)] +#[lang = "owned_box"] +struct Box(T); + +fn execute_nested_closures(f: F) +where + for<'a> F: Fn(&'a str) -> Box Fn(&'b str) + 'a>, +{ +} +"#, + ); +} + +#[test] +fn diff_nested() { + check_no_mismatches( + r#" +//- minicore: fn +#![feature(lang_items)] +#[lang = "owned_box"] +struct Box(T); + +fn foo_fn(f: F) +where + F: for<'a> Fn(&'a str) -> Box Fn(&'a &'b str) + 'a>, +{ +} +"#, + ); +} 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 6e61fcaa5d70b..d0b38c0ceb5a3 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 @@ -5339,3 +5339,41 @@ fn foo() { "#, ); } + +#[test] +fn hrtb_impl_trait() { + check_infer( + r#" +trait Trait<'a> {} + +struct Foo; + +impl<'a> Trait<'a> for Bot {} + +fn impl_fn(val: impl for<'a> Trait<'a>) {} +"#, + expect![[r#" + 75..78 'val': impl Trait<'?0.0> + ?Sized + 104..106 '{}': () + "#]], + ); +} + +#[test] +fn hrtb_dyn_trait() { + check_infer( + r#" +trait Trait<'a, 'b> {} + +struct Foo; + +impl<'a, 'b> Trait<'a, 'b> for Foo {} + +fn run_dyn<'b>(val: &dyn for<'a> Trait<'a, 'b>) {} +"#, + expect![[r#" + 91..94 'val': &'? (dyn Trait<'_, '_> + 'static) + 124..126 '{}': () + "#]], + ); +} From 7f6e92f26ae4694c2d6db963d871d92c4bcca829 Mon Sep 17 00:00:00 2001 From: Max Zargov Date: Sun, 19 Jul 2026 20:30:11 +0500 Subject: [PATCH 16/76] fix: Spawn proc-macro servers on requests clearing the client cache --- src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 c72f6782052f0..a6b8bd3952d4f 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs @@ -659,7 +659,7 @@ impl GlobalState { Config::user_config_dir_path().as_deref(), ); - if !same_workspaces && self.config.expand_proc_macros() { + if (self.proc_macro_clients.is_empty() || !same_workspaces) && self.config.expand_proc_macros() { info!("Spawning proc-macro servers"); // Workspaces referring to the same proc-macro server executable (i.e. the same From 28c81c49c8dae48da4aafe1ea1fee0103342a49f Mon Sep 17 00:00:00 2001 From: Max Zargov Date: Sun, 19 Jul 2026 20:46:03 +0500 Subject: [PATCH 17/76] Fix formatting --- src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) 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 a6b8bd3952d4f..3bf3cd5622550 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs @@ -659,7 +659,9 @@ impl GlobalState { Config::user_config_dir_path().as_deref(), ); - if (self.proc_macro_clients.is_empty() || !same_workspaces) && self.config.expand_proc_macros() { + if (self.proc_macro_clients.is_empty() || !same_workspaces) + && self.config.expand_proc_macros() + { info!("Spawning proc-macro servers"); // Workspaces referring to the same proc-macro server executable (i.e. the same From fb9e2e46487e572c24d5094f527a28de59901012 Mon Sep 17 00:00:00 2001 From: dfireBird Date: Mon, 20 Jul 2026 08:42:27 +0530 Subject: [PATCH 18/76] feat: merge `WherePredicate::ForLifetimes` into `WherePredicate::TypeBound` --- .../hir-def/src/expr_store/lower/generics.rs | 18 ++++++------- .../crates/hir-def/src/expr_store/pretty.rs | 25 ++++++++----------- .../crates/hir-def/src/hir/generics.rs | 3 +-- .../crates/hir-ty/src/display.rs | 3 +-- .../rust-analyzer/crates/hir-ty/src/lower.rs | 18 ++++++------- .../rust-analyzer/crates/hir/src/display.rs | 22 ++++++---------- 6 files changed, 37 insertions(+), 52 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/generics.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/generics.rs index 2119f19c065d2..ce6e73670cba4 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/generics.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/generics.rs @@ -220,13 +220,10 @@ impl GenericParamsCollector { ); let predicate = match (target, bound) { (_, TypeBound::Error | TypeBound::Use(_)) => return, - (Either::Left(type_ref), bound) => match hrtb_lifetimes { - Some(hrtb_lifetimes) => WherePredicate::ForLifetime { - lifetimes: ThinVec::from_iter(hrtb_lifetimes.iter().cloned()), - target: type_ref, - bound, - }, - None => WherePredicate::TypeBound { target: type_ref, bound }, + (Either::Left(type_ref), bound) => WherePredicate::TypeBound { + lifetimes: hrtb_lifetimes.map(|h| ThinVec::from_iter(h.iter().cloned())), + target: type_ref, + bound, }, (Either::Right(lifetime), TypeBound::Lifetime(bound)) => { WherePredicate::Lifetime { target: lifetime, bound } @@ -257,8 +254,11 @@ impl GenericParamsCollector { })); let type_ref = ec.alloc_type_ref(param_id, ptr); for bound in impl_trait_bounds { - where_predicates - .push(WherePredicate::TypeBound { target: type_ref, bound: bound.clone() }); + where_predicates.push(WherePredicate::TypeBound { + lifetimes: None, + target: type_ref, + bound: bound.clone(), + }); } type_ref } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/pretty.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/pretty.rs index bc16a9e97968b..67eb0814c7488 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/pretty.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/pretty.rs @@ -338,7 +338,17 @@ fn print_where_clauses( w!(p, ",\n"); } match pred { - WherePredicate::TypeBound { target, bound } => { + WherePredicate::TypeBound { lifetimes, target, bound } => { + if let Some(lifetimes) = lifetimes { + w!(p, "for<"); + for (i, lifetime) in lifetimes.iter().enumerate() { + if i != 0 { + w!(p, ", "); + } + w!(p, "{}", lifetime.display(db, p.edition)); + } + w!(p, "> "); + } p.print_type_ref(*target); w!(p, ": "); p.print_type_bounds(std::slice::from_ref(bound)); @@ -348,19 +358,6 @@ fn print_where_clauses( w!(p, ": "); p.print_lifetime_ref(*bound); } - WherePredicate::ForLifetime { lifetimes, target, bound } => { - w!(p, "for<"); - for (i, lifetime) in lifetimes.iter().enumerate() { - if i != 0 { - w!(p, ", "); - } - w!(p, "{}", lifetime.display(db, p.edition)); - } - w!(p, "> "); - p.print_type_ref(*target); - w!(p, ": "); - p.print_type_bounds(std::slice::from_ref(bound)); - } } } }); diff --git a/src/tools/rust-analyzer/crates/hir-def/src/hir/generics.rs b/src/tools/rust-analyzer/crates/hir-def/src/hir/generics.rs index b6e9fc28207ac..039b229429cf0 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/hir/generics.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/hir/generics.rs @@ -185,9 +185,8 @@ impl ops::Index for GenericParams { /// associated type bindings like `Iterator`. #[derive(Clone, PartialEq, Eq, Debug, Hash)] pub enum WherePredicate { - TypeBound { target: TypeRefId, bound: TypeBound }, + TypeBound { lifetimes: Option>, target: TypeRefId, bound: TypeBound }, Lifetime { target: LifetimeRefId, bound: LifetimeRefId }, - ForLifetime { lifetimes: ThinVec, target: TypeRefId, bound: TypeBound }, } static EMPTY: LazyLock = LazyLock::new(|| GenericParams { 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 ff7f849d304b3..dc20eb930e815 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs @@ -2461,8 +2461,7 @@ impl<'db> HirDisplayWithExpressionStore<'db> for TypeRefId { .where_predicates() .iter() .filter_map(|it| match it { - WherePredicate::TypeBound { target, bound } - | WherePredicate::ForLifetime { lifetimes: _, target, bound } + WherePredicate::TypeBound { lifetimes: _, target, bound } if matches!( store[*target], TypeRef::TypeParam(t) if t == *param 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 19d550f91c216..2ac1551390693 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs @@ -894,10 +894,12 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { }; match where_predicate { - WherePredicate::ForLifetime { target, bound, lifetimes } => { - self.with_shifted_in(lifetimes, |ctx| lower_type_outlives(ctx, target, bound)).0 - } - WherePredicate::TypeBound { target, bound } => lower_type_outlives(self, target, bound), + WherePredicate::TypeBound { lifetimes, target, bound } => match lifetimes { + Some(lifetimes) => { + self.with_shifted_in(lifetimes, |ctx| lower_type_outlives(ctx, target, bound)).0 + } + None => lower_type_outlives(self, target, bound), + }, &WherePredicate::Lifetime { bound, target } => Either::Right(iter::once(( Clause(Predicate::new( self.interner, @@ -2010,9 +2012,7 @@ impl SupertraitsInfo { let resolver = trait_.resolver(db); let signature = TraitSignature::of(db, trait_); for pred in signature.generic_params.where_predicates() { - let (WherePredicate::TypeBound { target, bound } - | WherePredicate::ForLifetime { lifetimes: _, target, bound }) = pred - else { + let WherePredicate::TypeBound { lifetimes: _, target, bound } = pred else { continue; }; let (TypeBound::Path(bounded_trait, TraitBoundModifier::None) @@ -2128,9 +2128,7 @@ fn resolve_type_param_assoc_type_shorthand( for maybe_parent_generics in generics.iter_owners().rev() { ctx.set_owner(maybe_parent_generics); for pred in maybe_parent_generics.where_predicates() { - let (WherePredicate::TypeBound { target, bound } - | WherePredicate::ForLifetime { lifetimes: _, target, bound }) = pred - else { + let WherePredicate::TypeBound { lifetimes: _, target, bound } = pred else { continue; }; let (TypeBound::Path(bounded_trait_path, TraitBoundModifier::None) diff --git a/src/tools/rust-analyzer/crates/hir/src/display.rs b/src/tools/rust-analyzer/crates/hir/src/display.rs index 06fa91804ddee..d93f92628db0e 100644 --- a/src/tools/rust-analyzer/crates/hir/src/display.rs +++ b/src/tools/rust-analyzer/crates/hir/src/display.rs @@ -806,10 +806,6 @@ fn write_where_predicates<'db>( let check_same_target = |pred1: &WherePredicate, pred2: &WherePredicate| match (pred1, pred2) { (TypeBound { target: t1, .. }, TypeBound { target: t2, .. }) => t1 == t2, (Lifetime { target: t1, .. }, Lifetime { target: t2, .. }) => t1 == t2, - ( - ForLifetime { lifetimes: l1, target: t1, .. }, - ForLifetime { lifetimes: l2, target: t2, .. }, - ) => l1 == l2 && t1 == t2, _ => false, }; @@ -821,7 +817,12 @@ fn write_where_predicates<'db>( f.write_str("\n ")?; match pred { - TypeBound { target, bound } => { + TypeBound { lifetimes, target, bound } => { + if let Some(lifetimes) = lifetimes { + let lifetimes = + lifetimes.iter().map(|it| it.display(f.db, f.edition())).join(", "); + write!(f, "for<{lifetimes}> ")?; + } target.hir_fmt(f, owner, store)?; f.write_str(": ")?; bound.hir_fmt(f, owner, store)?; @@ -831,21 +832,12 @@ fn write_where_predicates<'db>( write!(f, ": ")?; bound.hir_fmt(f, owner, store)?; } - ForLifetime { lifetimes, target, bound } => { - let lifetimes = lifetimes.iter().map(|it| it.display(f.db, f.edition())).join(", "); - write!(f, "for<{lifetimes}> ")?; - target.hir_fmt(f, owner, store)?; - f.write_str(": ")?; - bound.hir_fmt(f, owner, store)?; - } } while let Some(nxt) = iter.next_if(|nxt| check_same_target(pred, nxt)) { f.write_str(" + ")?; match nxt { - TypeBound { bound, .. } | ForLifetime { bound, .. } => { - bound.hir_fmt(f, owner, store)? - } + TypeBound { bound, .. } => bound.hir_fmt(f, owner, store)?, Lifetime { bound, .. } => bound.hir_fmt(f, owner, store)?, } } From 1da5a09b71818fd22d99bdcb9512fd901fac600f Mon Sep 17 00:00:00 2001 From: Ada Alakbarova Date: Mon, 20 Jul 2026 07:37:06 +0200 Subject: [PATCH 19/76] fix `hir-def` crate description --- src/tools/rust-analyzer/crates/hir-def/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/crates/hir-def/Cargo.toml b/src/tools/rust-analyzer/crates/hir-def/Cargo.toml index 038ddecdb5d7d..b5e519695018a 100644 --- a/src/tools/rust-analyzer/crates/hir-def/Cargo.toml +++ b/src/tools/rust-analyzer/crates/hir-def/Cargo.toml @@ -2,7 +2,7 @@ name = "hir-def" version = "0.0.0" repository.workspace = true -description = "RPC Api for the `proc-macro-srv` crate of rust-analyzer." +description = "Early name and import resolution for rust-analyzer." authors.workspace = true edition.workspace = true From 770d9ceaa495d85a73a431e978b763d7b10dcff9 Mon Sep 17 00:00:00 2001 From: Ada Alakbarova Date: Thu, 9 Jul 2026 12:52:44 +0200 Subject: [PATCH 20/76] misc improvements - don't `push_ty_diagnostics` with an empty list - use `lookup_resolver` --- .../rust-analyzer/crates/hir-def/src/resolver.rs | 4 ++-- src/tools/rust-analyzer/crates/hir/src/lib.rs | 12 +++--------- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs index 724926f824282..63ff384de021a 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs @@ -1379,7 +1379,7 @@ impl HasResolver for TypeAliasId { impl HasResolver for ImplId { fn resolver(self, db: &dyn SourceDatabase) -> Resolver<'_> { - self.lookup(db).container.resolver(db).push_generic_params_scope(db, self.into()) + lookup_resolver(db, self).push_generic_params_scope(db, self.into()) } } @@ -1450,7 +1450,7 @@ impl HasResolver for ExpressionStoreOwnerId { impl HasResolver for EnumVariantId { fn resolver(self, db: &dyn SourceDatabase) -> Resolver<'_> { - self.lookup(db).parent.resolver(db) + lookup_resolver(db, self) } } diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index a029ed403140e..ab7d88eeefb16 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -1065,15 +1065,9 @@ impl Module { db.impl_self_ty_with_diagnostics(impl_id).diagnostics(), source_map, ); - push_ty_diagnostics( - db, - acc, - db.impl_trait_with_diagnostics(impl_id) - .as_ref() - .map(|it| it.diagnostics()) - .unwrap_or_default(), - source_map, - ); + if let Some(it) = db.impl_trait_with_diagnostics(impl_id) { + push_ty_diagnostics(db, acc, it.diagnostics(), source_map); + } for &(_, item) in impl_id.impl_items(db).items.iter() { AssocItem::from(item).diagnostics(db, acc, style_lints); From 2912f668c70f52ef9442d2ac86ef5bec4dd1e0a8 Mon Sep 17 00:00:00 2001 From: Ada Alakbarova Date: Tue, 14 Jul 2026 17:49:41 +0200 Subject: [PATCH 21/76] push `Debug` bound from `HirDatabase` down to `SourceDatabase` The next commit would require us to `impl HirDatabase for dyn SourceDatabase + Debug`, but that wouldn't work, as trait objects can't specify multiple (non-auto) traits. Since we're going to change all the users of `dyn HirDatabase` to `dyn SourceDatabase` anyway, we can push the `Debug` bound down to the latter. --- src/tools/rust-analyzer/crates/base-db/src/lib.rs | 2 +- src/tools/rust-analyzer/crates/hir-ty/src/db.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tools/rust-analyzer/crates/base-db/src/lib.rs b/src/tools/rust-analyzer/crates/base-db/src/lib.rs index b3c7f8424965e..916e8c9830a43 100644 --- a/src/tools/rust-analyzer/crates/base-db/src/lib.rs +++ b/src/tools/rust-analyzer/crates/base-db/src/lib.rs @@ -265,7 +265,7 @@ pub struct SourceRootInput { } #[salsa_macros::db] -pub trait SourceDatabase: salsa::Database { +pub trait SourceDatabase: salsa::Database + std::fmt::Debug { /// Text of the file. fn file_text(&self, file_id: vfs::FileId) -> FileText; 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 7e66e938a00fc..bd42772fdcb86 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs @@ -38,7 +38,7 @@ use crate::{ }; #[query_group::query_group] -pub trait HirDatabase: SourceDatabase + std::fmt::Debug { +pub trait HirDatabase: SourceDatabase { // region:mir // FIXME: Collapse `mir_body_for_closure` into `mir_body` From f6576214b2046e7c9abf0d3b61c9ded56a0a3235 Mon Sep 17 00:00:00 2001 From: Ada Alakbarova Date: Wed, 15 Jul 2026 20:33:56 +0200 Subject: [PATCH 22/76] move `#[salsa::tracked]` to the underlying queries --- src/tools/rust-analyzer/crates/hir-ty/src/db.rs | 1 + src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs | 1 + 2 files changed, 2 insertions(+) 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 bd42772fdcb86..c42e5cd4a83fd 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs @@ -146,6 +146,7 @@ pub trait HirDatabase: SourceDatabase { } #[salsa::invoke(crate::dyn_compatibility::dyn_compatibility_of_trait_query)] + #[salsa::transparent] fn dyn_compatibility_of_trait(&self, trait_: TraitId) -> Option; #[salsa::invoke(crate::lower::ty_query)] 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 9ee39b3abe649..3920a84639bd5 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 @@ -122,6 +122,7 @@ where ControlFlow::Continue(()) } +#[salsa::tracked] pub fn dyn_compatibility_of_trait_query( db: &dyn HirDatabase, trait_: TraitId, From 0821217d50bec7c3b809d0648f1daa6bd60057ed Mon Sep 17 00:00:00 2001 From: Ada Alakbarova Date: Tue, 14 Jul 2026 18:15:47 +0200 Subject: [PATCH 23/76] turn `HirDatabase` into an extension trait The remaining methods in the query group didn't really have a good place to migrate them to, as they were all defined on `hir-def` types. Therefore, we basically left them inside `HirDatabase`, but changed the latter from a `#[query_group]` to an extension trait on `SourceDatabase`. When working with a concrete `TestDB`/`RootDatabase`, one needs to first explicitly cast it to a `&dyn HirDatabase`. For that, `HirDatabase::as_dyn` should be used. --- .../rust-analyzer/crates/hir-ty/src/db.rs | 269 ++++++++++-------- .../crates/hir-ty/src/mir/lower/tests.rs | 6 +- 2 files changed, 161 insertions(+), 114 deletions(-) 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 c42e5cd4a83fd..9944079cd3073 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs @@ -37,261 +37,308 @@ use crate::{ traits::{ParamEnvAndCrate, StoredParamEnvAndCrate}, }; -#[query_group::query_group] -pub trait HirDatabase: SourceDatabase { +#[salsa::db] +pub trait HirDatabase: SourceDatabase + 'static { + /// Manual implementation of upcasting from `dyn SourceDatabase` to `dyn HirDatabase`. + /// + /// This function is needed because Rust can't perform this upcasting automatically + /// in the general case, as `Self` could be unsized. + fn as_dyn(&self) -> &dyn HirDatabase; + // region:mir // FIXME: Collapse `mir_body_for_closure` into `mir_body` // and `monomorphized_mir_body_for_closure` into `monomorphized_mir_body` - #[salsa::transparent] fn mir_body<'db>( &'db self, def: InferBodyId<'db>, ) -> Result<&'db MirBody<'db>, MirLowerError<'db>> { - crate::mir::mir_body_query(self, def).map_err(|err| err.clone()) + let db = self.as_dyn(); + crate::mir::mir_body_query(db, def).map_err(|err| err.clone()) } - #[salsa::transparent] fn mir_body_for_closure<'db>( &'db self, def: InternedClosureId<'db>, ) -> Result<&'db MirBody<'db>, MirLowerError<'db>> { - crate::mir::mir_body_for_closure_query(self, def).map_err(|err| err.clone()) + let db = self.as_dyn(); + crate::mir::mir_body_for_closure_query(db, def).map_err(|err| err.clone()) } - #[salsa::transparent] fn monomorphized_mir_body<'db>( &'db self, def: InferBodyId<'db>, subst: StoredGenericArgs, env: StoredParamEnvAndCrate, ) -> Result<&'db MirBody<'db>, MirLowerError<'db>> { - crate::mir::monomorphized_mir_body_query(self, def, subst, env).map_err(|err| err.clone()) + let db = self.as_dyn(); + crate::mir::monomorphized_mir_body_query(db, def, subst, env).map_err(|err| err.clone()) } - #[salsa::transparent] fn monomorphized_mir_body_for_closure<'db>( &'db self, def: InternedClosureId<'db>, subst: StoredGenericArgs, env: StoredParamEnvAndCrate, ) -> Result<&'db MirBody<'db>, MirLowerError<'db>> { - crate::mir::monomorphized_mir_body_for_closure_query(self, def, subst, env) + let db = self.as_dyn(); + crate::mir::monomorphized_mir_body_for_closure_query(db, def, subst, env) .map_err(|err| err.clone()) } - #[salsa::invoke(crate::consteval::const_eval)] - #[salsa::transparent] fn const_eval<'db>( &'db self, def: ConstId, subst: GenericArgs<'db>, trait_env: Option>, - ) -> Result, ConstEvalError<'db>>; + ) -> Result, ConstEvalError<'db>> { + let db = self.as_dyn(); + crate::consteval::const_eval(db, def, subst, trait_env) + } - #[salsa::invoke(crate::consteval::anon_const_eval)] - #[salsa::transparent] fn anon_const_eval<'db>( &'db self, def: AnonConstId<'db>, subst: GenericArgs<'db>, trait_env: Option>, - ) -> Result, ConstEvalError<'db>>; + ) -> Result, ConstEvalError<'db>> { + let db = self.as_dyn(); + crate::consteval::anon_const_eval(db, def, subst, trait_env) + } - #[salsa::invoke(crate::consteval::const_eval_static)] - #[salsa::transparent] fn const_eval_static<'db>( &'db self, def: StaticId, - ) -> Result, ConstEvalError<'db>>; + ) -> Result, ConstEvalError<'db>> { + let db = self.as_dyn(); + crate::consteval::const_eval_static(db, def) + } - #[salsa::invoke(crate::consteval::const_eval_discriminant_variant)] - #[salsa::transparent] fn const_eval_discriminant<'db>( &'db self, def: EnumVariantId, - ) -> Result>; + ) -> Result> { + let db = self.as_dyn(); + crate::consteval::const_eval_discriminant_variant(db, def) + } - #[salsa::invoke(crate::method_resolution::lookup_impl_method_query)] - #[salsa::transparent] fn lookup_impl_method<'db>( &'db self, env: ParamEnvAndCrate<'db>, func: FunctionId, fn_subst: GenericArgs<'db>, - ) -> (Either, GenericArgs<'db>); + ) -> (Either, GenericArgs<'db>) + { + let db = self.as_dyn(); + crate::method_resolution::lookup_impl_method_query(db, env, func, fn_subst) + } // endregion:mir - #[salsa::invoke(crate::layout::layout_of_adt_query)] - #[salsa::transparent] fn layout_of_adt( &self, def: AdtId, args: StoredGenericArgs, trait_env: StoredParamEnvAndCrate, - ) -> Result, LayoutError>; + ) -> Result, LayoutError> { + let db = self.as_dyn(); + crate::layout::layout_of_adt_query(db, def, args, trait_env) + } - #[salsa::invoke(crate::layout::layout_of_ty_query)] - #[salsa::transparent] fn layout_of_ty( &self, ty: StoredTy, env: StoredParamEnvAndCrate, - ) -> Result, LayoutError>; + ) -> Result, LayoutError> { + let db = self.as_dyn(); + crate::layout::layout_of_ty_query(db, ty, env) + } - #[salsa::transparent] fn target_data_layout(&self, krate: Crate) -> Result<&TargetDataLayout, TargetLoadError> { - crate::layout::target_data_layout_query(self, krate).map_err(|err| err.clone()) + let db = self.as_dyn(); + crate::layout::target_data_layout_query(db, krate).map_err(|err| err.clone()) } - #[salsa::invoke(crate::dyn_compatibility::dyn_compatibility_of_trait_query)] - #[salsa::transparent] - fn dyn_compatibility_of_trait(&self, trait_: TraitId) -> Option; + fn dyn_compatibility_of_trait(&self, trait_: TraitId) -> Option { + let db = self.as_dyn(); + crate::dyn_compatibility::dyn_compatibility_of_trait_query(db, trait_) + } - #[salsa::invoke(crate::lower::ty_query)] - #[salsa::transparent] - fn ty<'db>(&'db self, def: TyDefId) -> EarlyBinder<'db, Ty<'db>>; + fn ty<'db>(&'db self, def: TyDefId) -> EarlyBinder<'db, Ty<'db>> { + let db = self.as_dyn(); + crate::lower::ty_query(db, def) + } - #[salsa::invoke(crate::lower::type_for_type_alias_with_diagnostics)] - #[salsa::transparent] fn type_for_type_alias_with_diagnostics<'db>( &'db self, def: TypeAliasId, - ) -> &'db TyLoweringResult<'db, StoredEarlyBinder>; + ) -> &'db TyLoweringResult<'db, StoredEarlyBinder> { + let db = self.as_dyn(); + crate::lower::type_for_type_alias_with_diagnostics(db, def) + } /// 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::value_ty)] - #[salsa::transparent] - fn value_ty<'db>(&'db self, def: ValueTyDefId) -> Option>>; + fn value_ty<'db>(&'db self, def: ValueTyDefId) -> Option>> { + let db = self.as_dyn(); + crate::lower::value_ty(db, def) + } - #[salsa::invoke(crate::lower::type_for_const)] - #[salsa::transparent] - fn type_for_const<'db>(&'db self, def: ConstId) -> EarlyBinder<'db, Ty<'db>>; + fn type_for_const<'db>(&'db self, def: ConstId) -> EarlyBinder<'db, Ty<'db>> { + let db = self.as_dyn(); + crate::lower::type_for_const(db, def) + } - #[salsa::invoke(crate::lower::type_for_const_with_diagnostics)] - #[salsa::transparent] fn type_for_const_with_diagnostics<'db>( &'db self, def: ConstId, - ) -> &'db TyLoweringResult<'db, StoredEarlyBinder>; + ) -> &'db TyLoweringResult<'db, StoredEarlyBinder> { + let db = self.as_dyn(); + crate::lower::type_for_const_with_diagnostics(db, def) + } - #[salsa::invoke(crate::lower::type_for_static)] - #[salsa::transparent] - fn type_for_static<'db>(&'db self, def: StaticId) -> EarlyBinder<'db, Ty<'db>>; + fn type_for_static<'db>(&'db self, def: StaticId) -> EarlyBinder<'db, Ty<'db>> { + let db = self.as_dyn(); + crate::lower::type_for_static(db, def) + } - #[salsa::invoke(crate::lower::type_for_static_with_diagnostics)] - #[salsa::transparent] fn type_for_static_with_diagnostics<'db>( &'db self, def: StaticId, - ) -> &'db TyLoweringResult<'db, StoredEarlyBinder>; + ) -> &'db TyLoweringResult<'db, StoredEarlyBinder> { + let db = self.as_dyn(); + crate::lower::type_for_static_with_diagnostics(db, def) + } - #[salsa::invoke(crate::lower::impl_self_ty_with_diagnostics)] - #[salsa::transparent] fn impl_self_ty_with_diagnostics<'db>( &'db self, def: ImplId, - ) -> &'db TyLoweringResult<'db, StoredEarlyBinder>; + ) -> &'db TyLoweringResult<'db, StoredEarlyBinder> { + let db = self.as_dyn(); + crate::lower::impl_self_ty_with_diagnostics(db, def) + } - #[salsa::invoke(crate::lower::impl_self_ty_query)] - #[salsa::transparent] - fn impl_self_ty<'db>(&'db self, def: ImplId) -> EarlyBinder<'db, Ty<'db>>; + fn impl_self_ty<'db>(&'db self, def: ImplId) -> EarlyBinder<'db, Ty<'db>> { + let db = self.as_dyn(); + crate::lower::impl_self_ty_query(db, def) + } - #[salsa::invoke(crate::lower::const_param_types_with_diagnostics)] - #[salsa::transparent] fn const_param_types_with_diagnostics<'db>( &'db self, def: GenericDefId, - ) -> &'db TyLoweringResult<'db, ArenaMap>; + ) -> &'db TyLoweringResult<'db, ArenaMap> { + let db = self.as_dyn(); + crate::lower::const_param_types_with_diagnostics(db, def) + } - #[salsa::invoke(crate::lower::const_param_types)] - #[salsa::transparent] - fn const_param_types(&self, def: GenericDefId) -> &ArenaMap; + fn const_param_types(&self, def: GenericDefId) -> &ArenaMap { + let db = self.as_dyn(); + crate::lower::const_param_types(db, def) + } - #[salsa::invoke(crate::lower::const_param_ty)] - #[salsa::transparent] - fn const_param_ty<'db>(&'db self, def: ConstParamId) -> Ty<'db>; + fn const_param_ty<'db>(&'db self, def: ConstParamId) -> Ty<'db> { + let db = self.as_dyn(); + crate::lower::const_param_ty(db, def) + } - #[salsa::invoke(crate::lower::impl_trait_with_diagnostics)] - #[salsa::transparent] fn impl_trait_with_diagnostics<'db>( &'db self, def: ImplId, - ) -> &'db Option>>; + ) -> &'db Option>> { + let db = self.as_dyn(); + crate::lower::impl_trait_with_diagnostics(db, def) + } - #[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>> { + let db = self.as_dyn(); + crate::lower::impl_trait_query(db, def) + } - #[salsa::invoke(crate::lower::field_types_with_diagnostics)] - #[salsa::transparent] fn field_types_with_diagnostics<'db>( &'db self, var: VariantId, - ) -> &'db TyLoweringResult<'db, ArenaMap>; + ) -> &'db TyLoweringResult<'db, ArenaMap> { + let db = self.as_dyn(); + crate::lower::field_types_with_diagnostics(db, var) + } - #[salsa::invoke(crate::lower::field_types_query)] - #[salsa::transparent] - fn field_types(&self, var: VariantId) -> &ArenaMap; + fn field_types(&self, var: VariantId) -> &ArenaMap { + let db = self.as_dyn(); + crate::lower::field_types_query(db, var) + } - #[salsa::invoke(crate::lower::callable_item_signature)] - #[salsa::transparent] fn callable_item_signature<'db>( &'db self, def: CallableDefId, - ) -> EarlyBinder<'db, PolyFnSig<'db>>; + ) -> EarlyBinder<'db, PolyFnSig<'db>> { + let db = self.as_dyn(); + crate::lower::callable_item_signature(db, def) + } - #[salsa::invoke(crate::lower::callable_item_signature_with_diagnostics)] - #[salsa::transparent] fn callable_item_signature_with_diagnostics<'db>( &'db self, def: CallableDefId, - ) -> &'db TyLoweringResult<'db, StoredEarlyBinder>; + ) -> &'db TyLoweringResult<'db, StoredEarlyBinder> { + let db = self.as_dyn(); + crate::lower::callable_item_signature_with_diagnostics(db, def) + } - #[salsa::invoke(crate::lower::trait_environment)] - #[salsa::transparent] - fn trait_environment<'db>(&'db self, def: GenericDefId) -> ParamEnv<'db>; + fn trait_environment<'db>(&'db self, def: GenericDefId) -> ParamEnv<'db> { + let db = self.as_dyn(); + crate::lower::trait_environment(db, def) + } - #[salsa::invoke(crate::lower::generic_defaults_with_diagnostics)] - #[salsa::transparent] fn generic_defaults_with_diagnostics<'db>( &'db self, def: GenericDefId, - ) -> &'db TyLoweringResult<'db, GenericDefaults>; + ) -> &'db TyLoweringResult<'db, GenericDefaults> { + let db = self.as_dyn(); + crate::lower::generic_defaults_with_diagnostics(db, def) + } /// 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)] - #[salsa::transparent] - fn generic_defaults(&self, def: GenericDefId) -> GenericDefaultsRef<'_>; + fn generic_defaults(&self, def: GenericDefId) -> GenericDefaultsRef<'_> { + let db = self.as_dyn(); + crate::lower::generic_defaults(db, def) + } - #[salsa::invoke(crate::lower::type_alias_bounds_with_diagnostics)] - #[salsa::transparent] fn type_alias_bounds_with_diagnostics<'db>( &'db self, type_alias: TypeAliasId, - ) -> &'db TyLoweringResult<'db, TypeAliasBounds>>; + ) -> &'db TyLoweringResult<'db, TypeAliasBounds>> { + let db = self.as_dyn(); + crate::lower::type_alias_bounds_with_diagnostics(db, type_alias) + } - #[salsa::invoke(crate::lower::type_alias_bounds)] - #[salsa::transparent] fn type_alias_bounds<'db>( &'db self, type_alias: TypeAliasId, - ) -> EarlyBinder<'db, &'db [Clause<'db>]>; + ) -> EarlyBinder<'db, &'db [Clause<'db>]> { + let db = self.as_dyn(); + crate::lower::type_alias_bounds(db, type_alias) + } - #[salsa::invoke(crate::lower::type_alias_self_bounds)] - #[salsa::transparent] fn type_alias_self_bounds<'db>( &'db self, type_alias: TypeAliasId, - ) -> EarlyBinder<'db, &'db [Clause<'db>]>; + ) -> EarlyBinder<'db, &'db [Clause<'db>]> { + let db = self.as_dyn(); + crate::lower::type_alias_self_bounds(db, type_alias) + } - #[salsa::invoke(crate::variance::variances_of)] - #[salsa::transparent] - fn variances_of<'db>(&'db self, def: GenericDefId) -> VariancesOf<'db>; + fn variances_of<'db>(&'db self, def: GenericDefId) -> VariancesOf<'db> { + let db = self.as_dyn(); + crate::variance::variances_of(db, def) + } +} + +#[salsa::db] +impl HirDatabase for T { + fn as_dyn(&self) -> &dyn HirDatabase { + self + } } #[test] diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/tests.rs index d42072afa4b7c..8eb0a02694ce7 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/tests.rs @@ -6,7 +6,7 @@ use crate::{InferBodyId, db::HirDatabase, setup_tracing, test_db::TestDB}; fn lower_mir(#[rust_analyzer::rust_fixture] ra_fixture: &str) { let _tracing = setup_tracing(); let (db, file_ids) = TestDB::with_many_files(ra_fixture); - crate::attach_db(&db, || { + crate::attach_db(db.as_dyn(), || { let file_id = *file_ids.last().unwrap(); let module_id = db.module_for_file(file_id.file_id(&db)); let def_map = module_id.def_map(&db); @@ -54,7 +54,7 @@ fn foo() { fn check_borrowck(#[rust_analyzer::rust_fixture] ra_fixture: &str) { let _tracing = setup_tracing(); let (db, file_ids) = TestDB::with_many_files(ra_fixture); - crate::attach_db(&db, || { + crate::attach_db(db.as_dyn(), || { let file_id = *file_ids.last().unwrap(); let module_id = db.module_for_file(file_id.file_id(&db)); let def_map = module_id.def_map(&db); @@ -78,7 +78,7 @@ fn check_borrowck(#[rust_analyzer::rust_fixture] ra_fixture: &str) { } for body in bodies { - let _ = InferBodyId::from(body).borrowck(&db); + let _ = InferBodyId::from(body).borrowck(db.as_dyn()); } }) } From 47827ff4ccbaade725e9427fae033883a60fde9c Mon Sep 17 00:00:00 2001 From: Ada Alakbarova Date: Wed, 15 Jul 2026 14:53:12 +0200 Subject: [PATCH 24/76] remove `query-group-macro` --- src/tools/rust-analyzer/Cargo.lock | 14 - .../rust-analyzer/crates/base-db/Cargo.toml | 1 - .../rust-analyzer/crates/base-db/src/lib.rs | 1 - .../rust-analyzer/crates/hir-ty/Cargo.toml | 1 - .../crates/query-group-macro/Cargo.toml | 24 -- .../crates/query-group-macro/src/lib.rs | 256 ------------------ .../crates/query-group-macro/src/queries.rs | 111 -------- .../query-group-macro/tests/hello_world.rs | 54 ---- .../query-group-macro/tests/logger_db.rs | 68 ----- .../query-group-macro/tests/multiple_dbs.rs | 27 -- .../query-group-macro/tests/old_and_new.rs | 109 -------- .../crates/query-group-macro/tests/result.rs | 41 --- .../query-group-macro/tests/supertrait.rs | 20 -- .../crates/query-group-macro/tests/tuples.rs | 32 --- 14 files changed, 759 deletions(-) delete mode 100644 src/tools/rust-analyzer/crates/query-group-macro/Cargo.toml delete mode 100644 src/tools/rust-analyzer/crates/query-group-macro/src/lib.rs delete mode 100644 src/tools/rust-analyzer/crates/query-group-macro/src/queries.rs delete mode 100644 src/tools/rust-analyzer/crates/query-group-macro/tests/hello_world.rs delete mode 100644 src/tools/rust-analyzer/crates/query-group-macro/tests/logger_db.rs delete mode 100644 src/tools/rust-analyzer/crates/query-group-macro/tests/multiple_dbs.rs delete mode 100644 src/tools/rust-analyzer/crates/query-group-macro/tests/old_and_new.rs delete mode 100644 src/tools/rust-analyzer/crates/query-group-macro/tests/result.rs delete mode 100644 src/tools/rust-analyzer/crates/query-group-macro/tests/supertrait.rs delete mode 100644 src/tools/rust-analyzer/crates/query-group-macro/tests/tuples.rs diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock index aa3fe4b1000ec..0e12d80b7e180 100644 --- a/src/tools/rust-analyzer/Cargo.lock +++ b/src/tools/rust-analyzer/Cargo.lock @@ -95,7 +95,6 @@ dependencies = [ "indexmap", "intern", "la-arena 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "query-group-macro", "rustc-hash 2.1.2", "salsa", "salsa-macros", @@ -926,7 +925,6 @@ dependencies = [ "oorandom", "petgraph", "project-model", - "query-group-macro", "ra-ap-rustc_abi", "ra-ap-rustc_ast_ir", "ra-ap-rustc_index", @@ -2038,18 +2036,6 @@ dependencies = [ "pulldown-cmark", ] -[[package]] -name = "query-group-macro" -version = "0.0.0" -dependencies = [ - "expect-test", - "proc-macro2", - "quote", - "salsa", - "salsa-macros", - "syn", -] - [[package]] name = "quick-error" version = "1.2.3" diff --git a/src/tools/rust-analyzer/crates/base-db/Cargo.toml b/src/tools/rust-analyzer/crates/base-db/Cargo.toml index 55dfcbc7e508a..fe0c288441f11 100644 --- a/src/tools/rust-analyzer/crates/base-db/Cargo.toml +++ b/src/tools/rust-analyzer/crates/base-db/Cargo.toml @@ -17,7 +17,6 @@ la-arena.workspace = true dashmap.workspace = true salsa.workspace = true salsa-macros.workspace = true -query-group.workspace = true rustc-hash.workspace = true triomphe.workspace = true semver.workspace = true diff --git a/src/tools/rust-analyzer/crates/base-db/src/lib.rs b/src/tools/rust-analyzer/crates/base-db/src/lib.rs index 916e8c9830a43..7f915827b5f8e 100644 --- a/src/tools/rust-analyzer/crates/base-db/src/lib.rs +++ b/src/tools/rust-analyzer/crates/base-db/src/lib.rs @@ -66,7 +66,6 @@ pub use crate::{ }, }; use dashmap::{DashMap, mapref::entry::Entry}; -pub use query_group; use rustc_hash::{FxHashSet, FxHasher}; use salsa::{Durability, Setter}; pub use semver::{BuildMetadata, Prerelease, Version, VersionReq}; diff --git a/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml b/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml index e8eda74e40017..7c5ad21bc714f 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml +++ b/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml @@ -29,7 +29,6 @@ triomphe.workspace = true typed-arena = "2.0.2" indexmap.workspace = true rustc_apfloat = "0.2.3" -query-group.workspace = true salsa.workspace = true salsa-macros.workspace = true petgraph.workspace = true diff --git a/src/tools/rust-analyzer/crates/query-group-macro/Cargo.toml b/src/tools/rust-analyzer/crates/query-group-macro/Cargo.toml deleted file mode 100644 index 5991120a30d83..0000000000000 --- a/src/tools/rust-analyzer/crates/query-group-macro/Cargo.toml +++ /dev/null @@ -1,24 +0,0 @@ -[package] -name = "query-group-macro" -version = "0.0.0" -repository.workspace = true -description = "A macro mimicking the `#[salsa::query_group]` macro for migrating to new Salsa" - -authors.workspace = true -edition.workspace = true -license.workspace = true -rust-version.workspace = true - -[lib] -doctest = false -proc-macro = true - -[dependencies] -proc-macro2 = "1.0" -quote = "1.0" -syn = { version = "2.0", features = ["full", "extra-traits", "visit-mut"] } - -[dev-dependencies] -expect-test = "1.5.1" -salsa.workspace = true -salsa-macros.workspace = true diff --git a/src/tools/rust-analyzer/crates/query-group-macro/src/lib.rs b/src/tools/rust-analyzer/crates/query-group-macro/src/lib.rs deleted file mode 100644 index 9f7459066d908..0000000000000 --- a/src/tools/rust-analyzer/crates/query-group-macro/src/lib.rs +++ /dev/null @@ -1,256 +0,0 @@ -//! A macro that mimics the old Salsa-style `#[query_group]` macro. - -use std::vec; - -use proc_macro::TokenStream; -use proc_macro2::Span; -use queries::{Queries, TrackedQuery, Transparent}; -use quote::{ToTokens, format_ident, quote}; -use syn::parse::ParseStream; -use syn::spanned::Spanned; -use syn::visit_mut::VisitMut; -use syn::{Attribute, FnArg, ItemTrait, Path, TraitItem, parse_quote, parse_quote_spanned}; - -mod queries; - -#[proc_macro_attribute] -pub fn query_group(args: TokenStream, input: TokenStream) -> TokenStream { - match query_group_impl(args, input.clone()) { - Ok(tokens) => tokens, - Err(e) => token_stream_with_error(input, e), - } -} - -struct SalsaAttr { - name: String, - tts: TokenStream, - span: Span, -} - -impl std::fmt::Debug for SalsaAttr { - fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(fmt, "{:?}", self.name) - } -} - -impl TryFrom for SalsaAttr { - type Error = syn::Attribute; - - fn try_from(attr: syn::Attribute) -> Result { - if is_not_salsa_attr_path(attr.path()) { - return Err(attr); - } - - let span = attr.span(); - - let name = attr.path().segments[1].ident.to_string(); - let tts = match attr.meta { - syn::Meta::Path(path) => path.into_token_stream(), - syn::Meta::List(ref list) => { - let tts = list - .into_token_stream() - .into_iter() - .skip(attr.path().to_token_stream().into_iter().count()); - proc_macro2::TokenStream::from_iter(tts) - } - syn::Meta::NameValue(nv) => nv.into_token_stream(), - } - .into(); - - Ok(SalsaAttr { name, tts, span }) - } -} - -fn is_not_salsa_attr_path(path: &syn::Path) -> bool { - path.segments.first().map(|s| s.ident != "salsa").unwrap_or(true) || path.segments.len() != 2 -} - -fn filter_attrs(attrs: Vec) -> (Vec, Vec) { - let mut other = vec![]; - let mut salsa = vec![]; - // Leave non-salsa attributes untouched. These are - // attributes that don't start with `salsa::` or don't have - // exactly two segments in their path. - for attr in attrs { - match SalsaAttr::try_from(attr) { - Ok(it) => salsa.push(it), - Err(it) => other.push(it), - } - } - (other, salsa) -} - -#[derive(Debug, Clone, PartialEq, Eq)] -enum QueryKind { - TrackedWithSalsaStruct, - Transparent, -} - -pub(crate) fn query_group_impl( - _args: proc_macro::TokenStream, - input: proc_macro::TokenStream, -) -> Result { - let mut item_trait = syn::parse::(input)?; - - let supertraits = &item_trait.supertraits; - - let db_attr: Attribute = parse_quote! { - #[salsa_macros::db] - }; - item_trait.attrs.push(db_attr); - - let trait_name_ident = &item_trait.ident.clone(); - let input_struct_name = format_ident!("{}Data", trait_name_ident); - let create_data_ident = format_ident!("create_data_{}", trait_name_ident); - - let mut trait_methods = vec![]; - - for item in &mut item_trait.items { - if let syn::TraitItem::Fn(method) = item { - let signature = &method.sig; - - let (_attrs, salsa_attrs) = filter_attrs(method.attrs.clone()); - - let mut query_kind = QueryKind::TrackedWithSalsaStruct; - let mut invoke = None; - - let params: Vec = signature.inputs.clone().into_iter().collect(); - let pat_and_tys = params - .into_iter() - .filter(|fn_arg| matches!(fn_arg, FnArg::Typed(_))) - .map(|fn_arg| match fn_arg { - FnArg::Typed(pat_type) => pat_type, - FnArg::Receiver(_) => unreachable!("this should have been filtered out"), - }) - .collect::>(); - - for SalsaAttr { name, tts, span } in salsa_attrs { - match name.as_str() { - "invoke" => { - let path = syn::parse::>(tts)?; - invoke = Some(path.0.clone()); - if query_kind != QueryKind::Transparent { - query_kind = QueryKind::TrackedWithSalsaStruct; - } - } - "tracked" if method.default.is_some() => { - query_kind = QueryKind::TrackedWithSalsaStruct; - } - "transparent" => { - query_kind = QueryKind::Transparent; - } - _ => return Err(syn::Error::new(span, format!("unknown attribute `{name}`"))), - } - } - - let syn::ReturnType::Type(_, _) = signature.output.clone() else { - return Err(syn::Error::new(signature.span(), "Queries must have a return type")); - }; - - if let Some(block) = &mut method.default { - SelfToDbRewriter.visit_block_mut(block); - } - - match (query_kind, invoke) { - (QueryKind::TrackedWithSalsaStruct, invoke) => { - let method = TrackedQuery { - trait_name: trait_name_ident.clone(), - signature: signature.clone(), - pat_and_tys: pat_and_tys.clone(), - invoke, - default: method.default.take(), - }; - - trait_methods.push(Queries::TrackedQuery(method)) - } - (QueryKind::Transparent, invoke) => { - let method = Transparent { - signature: method.sig.clone(), - pat_and_tys: pat_and_tys.clone(), - invoke, - default: method.default.take(), - }; - trait_methods.push(Queries::Transparent(method)); - } - } - } - } - - let input_struct = quote! { - #[salsa_macros::input] - pub(crate) struct #input_struct_name {} - }; - - let create_data_method = quote! { - #[allow(non_snake_case)] - #[salsa_macros::tracked] - fn #create_data_ident(db: &dyn #trait_name_ident) -> #input_struct_name { - #input_struct_name::new(db) - } - }; - - let trait_impl = quote! { - #[salsa_macros::db] - impl #trait_name_ident for DB - where - DB: #supertraits, - { - #(#trait_methods)* - } - }; - RemoveAttrsFromTraitMethods.visit_item_trait_mut(&mut item_trait); - - let out = quote! { - #item_trait - - #trait_impl - - #input_struct - - #create_data_method - } - .into(); - - Ok(out) -} - -/// Parenthesis helper -pub(crate) struct Parenthesized(pub(crate) T); - -impl syn::parse::Parse for Parenthesized -where - T: syn::parse::Parse, -{ - fn parse(input: ParseStream<'_>) -> syn::Result { - let content; - syn::parenthesized!(content in input); - content.parse::().map(Parenthesized) - } -} - -struct RemoveAttrsFromTraitMethods; - -impl VisitMut for RemoveAttrsFromTraitMethods { - fn visit_item_trait_mut(&mut self, i: &mut syn::ItemTrait) { - for item in &mut i.items { - if let TraitItem::Fn(trait_item_fn) = item { - trait_item_fn.attrs = vec![]; - } - } - } -} - -pub(crate) fn token_stream_with_error(mut tokens: TokenStream, error: syn::Error) -> TokenStream { - tokens.extend(TokenStream::from(error.into_compile_error())); - tokens -} - -struct SelfToDbRewriter; - -impl VisitMut for SelfToDbRewriter { - fn visit_expr_path_mut(&mut self, i: &mut syn::ExprPath) { - if i.path.is_ident("self") { - i.path = parse_quote_spanned!(i.path.span() => db); - } - } -} diff --git a/src/tools/rust-analyzer/crates/query-group-macro/src/queries.rs b/src/tools/rust-analyzer/crates/query-group-macro/src/queries.rs deleted file mode 100644 index 935d65bb24581..0000000000000 --- a/src/tools/rust-analyzer/crates/query-group-macro/src/queries.rs +++ /dev/null @@ -1,111 +0,0 @@ -//! The IR of the `#[query_group]` macro. - -use quote::{ToTokens, format_ident, quote, quote_spanned}; -use syn::{Ident, PatType, Path, spanned::Spanned}; - -pub(crate) struct TrackedQuery { - pub(crate) trait_name: Ident, - pub(crate) signature: syn::Signature, - pub(crate) pat_and_tys: Vec, - pub(crate) invoke: Option, - pub(crate) default: Option, -} - -impl ToTokens for TrackedQuery { - fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) { - let sig = &self.signature; - let trait_name = &self.trait_name; - - let ret = &sig.output; - - let invoke = match &self.invoke { - Some(path) => path.to_token_stream(), - None => sig.ident.to_token_stream(), - }; - - let fn_ident = &sig.ident; - let shim: Ident = format_ident!("{}_shim", fn_ident); - - let pat_and_tys = &self.pat_and_tys; - let params = self - .pat_and_tys - .iter() - .map(|pat_type| pat_type.pat.clone()) - .collect::>>(); - - let invoke_block = match &self.default { - Some(default) => quote! { #default }, - None => { - let invoke_params: proc_macro2::TokenStream = quote! {db, #(#params),*}; - quote_spanned! { invoke.span() => {#invoke(#invoke_params)}} - } - }; - - let method = quote! { - #sig { - #[salsa_macros::tracked] - fn #shim<'db>( - db: &'db dyn #trait_name, - #(#pat_and_tys),* - ) #ret - #invoke_block - - #shim(self, #(#params),*) - } - }; - - method.to_tokens(tokens); - } -} - -pub(crate) struct Transparent { - pub(crate) signature: syn::Signature, - pub(crate) pat_and_tys: Vec, - pub(crate) invoke: Option, - pub(crate) default: Option, -} - -impl ToTokens for Transparent { - fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) { - let sig = &self.signature; - - let ty = self - .pat_and_tys - .iter() - .map(|pat_type| pat_type.pat.clone()) - .collect::>>(); - - let invoke = match &self.invoke { - Some(path) => path.to_token_stream(), - None => sig.ident.to_token_stream(), - }; - - let method = match &self.default { - Some(default) => quote! { - #sig { let db = self; #default } - }, - None => quote! { - #sig { - #invoke(self, #(#ty),*) - } - }, - }; - - method.to_tokens(tokens); - } -} - -#[allow(clippy::large_enum_variant)] -pub(crate) enum Queries { - TrackedQuery(TrackedQuery), - Transparent(Transparent), -} - -impl ToTokens for Queries { - fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) { - match self { - Queries::TrackedQuery(tracked_query) => tracked_query.to_tokens(tokens), - Queries::Transparent(transparent) => transparent.to_tokens(tokens), - } - } -} diff --git a/src/tools/rust-analyzer/crates/query-group-macro/tests/hello_world.rs b/src/tools/rust-analyzer/crates/query-group-macro/tests/hello_world.rs deleted file mode 100644 index 9e99b6d7fd0df..0000000000000 --- a/src/tools/rust-analyzer/crates/query-group-macro/tests/hello_world.rs +++ /dev/null @@ -1,54 +0,0 @@ -use expect_test::expect; -use query_group_macro::query_group; - -mod logger_db; -use logger_db::LoggerDb; - -#[salsa::input(singleton)] -struct InputString { - inner: String, -} - -#[query_group] -pub trait HelloWorldDatabase: salsa::Database { - // unadorned query - fn length_query_with_no_params(&self) -> usize; - - // not a query. should not invoked - #[salsa::transparent] - fn transparent_length(&self, key: ()) -> usize; -} - -fn length_query_with_no_params(db: &dyn HelloWorldDatabase) -> usize { - InputString::get(db).inner(db).len() -} - -fn transparent_length(db: &dyn HelloWorldDatabase, _key: ()) -> usize { - InputString::get(db).inner(db).len() -} - -#[test] -fn unadorned_query() { - let db = LoggerDb::default(); - - InputString::new(&db, String::from("Hello, world!")); - let len = db.length_query_with_no_params(); - - assert_eq!(len, 13); - db.assert_logs(expect![[r#" - [ - "salsa_event(WillCheckCancellation)", - "salsa_event(WillExecute { database_key: length_query_with_no_params_shim(Id(400)) })", - ]"#]]); -} - -#[test] -fn transparent() { - let db = LoggerDb::default(); - - InputString::new(&db, String::from("Hello, world!")); - let len = db.transparent_length(()); - - assert_eq!(len, 13); - db.assert_logs(expect!["[]"]); -} diff --git a/src/tools/rust-analyzer/crates/query-group-macro/tests/logger_db.rs b/src/tools/rust-analyzer/crates/query-group-macro/tests/logger_db.rs deleted file mode 100644 index 71af63a0d3b8b..0000000000000 --- a/src/tools/rust-analyzer/crates/query-group-macro/tests/logger_db.rs +++ /dev/null @@ -1,68 +0,0 @@ -use std::sync::{Arc, Mutex}; - -#[salsa_macros::db] -#[derive(Clone)] -pub(crate) struct LoggerDb { - storage: salsa::Storage, - logger: Logger, -} - -impl Default for LoggerDb { - fn default() -> Self { - let logger = Logger::default(); - Self { - storage: salsa::Storage::new(Some(Box::new({ - let logger = logger.clone(); - move |event| match event.kind { - salsa::EventKind::WillExecute { .. } - | salsa::EventKind::WillCheckCancellation - | salsa::EventKind::DidValidateMemoizedValue { .. } - | salsa::EventKind::WillDiscardStaleOutput { .. } - | salsa::EventKind::DidDiscard { .. } => { - logger.logs.lock().unwrap().push(format!("salsa_event({:?})", event.kind)); - } - _ => {} - } - }))), - logger, - } - } -} - -#[derive(Default, Clone)] -struct Logger { - logs: Arc>>, -} - -#[salsa_macros::db] -impl salsa::Database for LoggerDb {} - -impl LoggerDb { - /// Log an event from inside a tracked function. - pub(crate) fn push_log(&self, string: String) { - self.logger.logs.lock().unwrap().push(string); - } - - /// Asserts what the (formatted) logs should look like, - /// clearing the logged events. This takes `&mut self` because - /// it is meant to be run from outside any tracked functions. - pub(crate) fn assert_logs(&self, expected: expect_test::Expect) { - let logs = std::mem::take(&mut *self.logger.logs.lock().unwrap()); - expected.assert_eq(&format!("{logs:#?}")); - } -} - -/// Test the logger database. -/// -/// This test isn't very interesting, but it *does* remove a dead code warning. -#[test] -fn test_logger_db() { - let db = LoggerDb::default(); - db.push_log("test".to_string()); - db.assert_logs(expect_test::expect![ - r#" - [ - "test", - ]"# - ]); -} diff --git a/src/tools/rust-analyzer/crates/query-group-macro/tests/multiple_dbs.rs b/src/tools/rust-analyzer/crates/query-group-macro/tests/multiple_dbs.rs deleted file mode 100644 index 678a7ce5d74d0..0000000000000 --- a/src/tools/rust-analyzer/crates/query-group-macro/tests/multiple_dbs.rs +++ /dev/null @@ -1,27 +0,0 @@ -use query_group_macro::query_group; - -#[salsa::input(singleton)] -struct InputString { - inner: String, -} - -#[query_group] -pub trait DatabaseOne: salsa::Database { - // unadorned query - #[salsa::transparent] - fn length(&self, key: ()) -> usize; -} - -#[query_group] -pub trait DatabaseTwo: DatabaseOne { - #[salsa::transparent] - fn second_length(&self, key: ()) -> usize; -} - -fn length(db: &dyn DatabaseOne, _key: ()) -> usize { - InputString::get(db).inner(db).len() -} - -fn second_length(db: &dyn DatabaseTwo, _key: ()) -> usize { - InputString::get(db).inner(db).len() -} diff --git a/src/tools/rust-analyzer/crates/query-group-macro/tests/old_and_new.rs b/src/tools/rust-analyzer/crates/query-group-macro/tests/old_and_new.rs deleted file mode 100644 index cc57ba78455fa..0000000000000 --- a/src/tools/rust-analyzer/crates/query-group-macro/tests/old_and_new.rs +++ /dev/null @@ -1,109 +0,0 @@ -use expect_test::expect; - -mod logger_db; -use logger_db::LoggerDb; -use query_group_macro::query_group; - -#[salsa_macros::input] -struct Input { - str: String, -} - -#[query_group] -trait PartialMigrationDatabase: salsa::Database { - fn length_query(&self, input: Input) -> usize; - - // renamed/invoke query - #[salsa::invoke(invoke_length_query_actual)] - fn invoke_length_query(&self, input: Input) -> usize; - - // invoke tracked function - #[salsa::invoke(invoke_length_tracked_actual)] - fn invoke_length_tracked(&self, input: Input) -> usize; -} - -fn length_query(db: &dyn PartialMigrationDatabase, input: Input) -> usize { - input.str(db).len() -} - -fn invoke_length_query_actual(db: &dyn PartialMigrationDatabase, input: Input) -> usize { - input.str(db).len() -} - -#[salsa_macros::tracked] -fn invoke_length_tracked_actual(db: &dyn PartialMigrationDatabase, input: Input) -> usize { - input.str(db).len() -} - -#[test] -fn unadorned_query() { - let db = LoggerDb::default(); - - let input = Input::new(&db, String::from("Hello, world!")); - let len = db.length_query(input); - - assert_eq!(len, 13); - db.assert_logs(expect![[r#" - [ - "salsa_event(WillCheckCancellation)", - "salsa_event(WillExecute { database_key: length_query_shim(Id(0)) })", - ]"#]]); -} - -#[test] -fn invoke_query() { - let db = LoggerDb::default(); - - let input = Input::new(&db, String::from("Hello, world!")); - let len = db.invoke_length_query(input); - - assert_eq!(len, 13); - db.assert_logs(expect![[r#" - [ - "salsa_event(WillCheckCancellation)", - "salsa_event(WillExecute { database_key: invoke_length_query_shim(Id(0)) })", - ]"#]]); -} - -// todo: does this even make sense? -#[test] -fn invoke_tracked_query() { - let db = LoggerDb::default(); - - let input = Input::new(&db, String::from("Hello, world!")); - let len = db.invoke_length_tracked(input); - - assert_eq!(len, 13); - db.assert_logs(expect![[r#" - [ - "salsa_event(WillCheckCancellation)", - "salsa_event(WillExecute { database_key: invoke_length_tracked_shim(Id(0)) })", - "salsa_event(WillCheckCancellation)", - "salsa_event(WillExecute { database_key: invoke_length_tracked_actual(Id(0)) })", - ]"#]]); -} - -#[test] -fn new_salsa_baseline() { - let db = LoggerDb::default(); - - #[salsa_macros::input] - struct Input { - str: String, - } - - #[salsa_macros::tracked] - fn new_salsa_length_query(db: &dyn PartialMigrationDatabase, input: Input) -> usize { - input.str(db).len() - } - - let input = Input::new(&db, String::from("Hello, world!")); - let len = new_salsa_length_query(&db, input); - - assert_eq!(len, 13); - db.assert_logs(expect![[r#" - [ - "salsa_event(WillCheckCancellation)", - "salsa_event(WillExecute { database_key: new_salsa_length_query(Id(0)) })", - ]"#]]); -} diff --git a/src/tools/rust-analyzer/crates/query-group-macro/tests/result.rs b/src/tools/rust-analyzer/crates/query-group-macro/tests/result.rs deleted file mode 100644 index 7e5e8d3a5b75f..0000000000000 --- a/src/tools/rust-analyzer/crates/query-group-macro/tests/result.rs +++ /dev/null @@ -1,41 +0,0 @@ -mod logger_db; -use expect_test::expect; -use logger_db::LoggerDb; - -use query_group_macro::query_group; - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct Error; - -#[salsa::input(singleton)] -struct InputString { - inner: String, -} - -#[query_group] -pub trait ResultDatabase: salsa::Database { - #[salsa::transparent] - fn length(&self, key: ()) -> Result; - - #[salsa::transparent] - fn length2(&self, key: ()) -> Result; -} - -fn length(db: &dyn ResultDatabase, _key: ()) -> Result { - Ok(InputString::get(db).inner(db).len()) -} - -fn length2(db: &dyn ResultDatabase, _key: ()) -> Result { - Ok(InputString::get(db).inner(db).len()) -} - -#[test] -fn test_queries_with_results() { - let db = LoggerDb::default(); - let input = "hello"; - _ = InputString::new(&db, input.to_owned()); - assert_eq!(db.length(()), Ok(input.len())); - assert_eq!(db.length2(()), Ok(input.len())); - - db.assert_logs(expect!["[]"]); -} diff --git a/src/tools/rust-analyzer/crates/query-group-macro/tests/supertrait.rs b/src/tools/rust-analyzer/crates/query-group-macro/tests/supertrait.rs deleted file mode 100644 index 63a5dbd16c5f7..0000000000000 --- a/src/tools/rust-analyzer/crates/query-group-macro/tests/supertrait.rs +++ /dev/null @@ -1,20 +0,0 @@ -use query_group_macro::query_group; - -#[salsa_macros::db] -pub trait SourceDb: salsa::Database { - /// Text of the file. - fn file_text(&self, id: usize) -> String; -} - -#[query_group] -pub trait RootDb: SourceDb { - #[salsa::transparent] - fn parse(&self, id: usize) -> String; -} - -fn parse(db: &dyn RootDb, id: usize) -> String { - // this is the test: does the following compile? - db.file_text(id); - - String::new() -} diff --git a/src/tools/rust-analyzer/crates/query-group-macro/tests/tuples.rs b/src/tools/rust-analyzer/crates/query-group-macro/tests/tuples.rs deleted file mode 100644 index ab9d1746f731b..0000000000000 --- a/src/tools/rust-analyzer/crates/query-group-macro/tests/tuples.rs +++ /dev/null @@ -1,32 +0,0 @@ -use query_group_macro::query_group; - -mod logger_db; -use expect_test::expect; -use logger_db::LoggerDb; - -#[salsa::input(singleton)] -struct InputString { - inner: String, -} - -#[query_group] -pub trait HelloWorldDatabase: salsa::Database { - #[salsa::transparent] - fn length_query(&self, key: ()) -> (usize, usize); -} - -fn length_query(db: &dyn HelloWorldDatabase, _key: ()) -> (usize, usize) { - let len = InputString::get(db).inner(db).len(); - (len, len) -} - -#[test] -fn query() { - let db = LoggerDb::default(); - - _ = InputString::new(&db, String::from("Hello, world!")); - let len = db.length_query(()); - - assert_eq!(len, (13, 13)); - db.assert_logs(expect!["[]"]); -} From c9187322d4a7e05e08584cf2c452ab59505c853c Mon Sep 17 00:00:00 2001 From: Ada Alakbarova Date: Wed, 17 Jun 2026 14:51:04 +0200 Subject: [PATCH 25/76] add `declare_id_wrapper_with_lt` --- .../crates/hir-ty/src/next_solver/def_id.rs | 195 +++++------------- 1 file changed, 55 insertions(+), 140 deletions(-) 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 f7d831d7fc227..dd6b19a84ba0d 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 @@ -387,160 +387,75 @@ macro_rules! declare_id_wrapper { }; } -declare_id_wrapper!(TraitIdWrapper, TraitId); -declare_id_wrapper!(TypeAliasIdWrapper, TypeAliasId); -#[derive(Clone, Copy, PartialEq, Eq, Hash)] -pub struct ClosureIdWrapper<'db>(pub InternedClosureId<'db>); - -impl std::fmt::Debug for ClosureIdWrapper<'_> { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - std::fmt::Debug::fmt(&SolverDefId::from(self.0), f) - } -} - -impl<'db> From> for InternedClosureId<'db> { - #[inline] - fn from(value: ClosureIdWrapper<'db>) -> InternedClosureId<'db> { - value.0 - } -} - -impl<'db> From> for ClosureIdWrapper<'db> { - #[inline] - fn from(value: InternedClosureId<'db>) -> ClosureIdWrapper<'db> { - Self(value) - } -} +/// This is similar to [`declare_id_wrapper`], but handles ids which have the `'db` lifetime. +macro_rules! declare_id_wrapper_with_lt { + ($name:ident, $wraps:ident) => { + declare_id_wrapper_with_lt!($name, $wraps, SolverDefId<'db>); + }; -impl<'db> From> for SolverDefId<'db> { - #[inline] - fn from(value: ClosureIdWrapper<'db>) -> SolverDefId<'db> { - value.0.into() - } -} + ($name:ident, $wraps:ident, $local:ty) => { + declare_id_wrapper_with_lt!($name, $wraps, $local, no_try_from); -impl<'db> TryFrom> for ClosureIdWrapper<'db> { - type Error = (); + impl<'db> TryFrom> for $name<'db> { + type Error = (); - #[inline] - fn try_from(value: SolverDefId<'db>) -> Result { - match value { - SolverDefId::InternedClosureId(it) => Ok(Self(it)), - _ => Err(()), + #[inline] + fn try_from(value: SolverDefId<'db>) -> Result { + match value { + SolverDefId::$wraps(it) => Ok(Self(it)), + _ => Err(()), + } + } } - } -} - -impl<'db> inherent::DefId, SolverDefId<'db>> for ClosureIdWrapper<'db> { - fn as_local(self) -> Option> { - Some(self.into()) - } - fn is_local(self) -> bool { - true - } -} - -#[derive(Clone, Copy, PartialEq, Eq, Hash)] -pub struct CoroutineIdWrapper<'db>(pub InternedCoroutineId<'db>); - -impl std::fmt::Debug for CoroutineIdWrapper<'_> { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - std::fmt::Debug::fmt(&SolverDefId::from(self.0), f) - } -} - -impl<'db> From> for InternedCoroutineId<'db> { - #[inline] - fn from(value: CoroutineIdWrapper<'db>) -> InternedCoroutineId<'db> { - value.0 - } -} - -impl<'db> From> for CoroutineIdWrapper<'db> { - #[inline] - fn from(value: InternedCoroutineId<'db>) -> CoroutineIdWrapper<'db> { - Self(value) - } -} - -impl<'db> From> for SolverDefId<'db> { - #[inline] - fn from(value: CoroutineIdWrapper<'db>) -> SolverDefId<'db> { - value.0.into() - } -} + }; -impl<'db> TryFrom> for CoroutineIdWrapper<'db> { - type Error = (); + ($name:ident, $wraps:ident, $local:ty, no_try_from) => { + #[derive(Clone, Copy, PartialEq, Eq, Hash)] + pub struct $name<'db>(pub $wraps<'db>); - #[inline] - fn try_from(value: SolverDefId<'db>) -> Result { - match value { - SolverDefId::InternedCoroutineId(it) => Ok(Self(it)), - _ => Err(()), + impl std::fmt::Debug for $name<'_> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Debug::fmt(&SolverDefId::from(self.0), f) + } } - } -} -impl<'db> inherent::DefId, SolverDefId<'db>> for CoroutineIdWrapper<'db> { - fn as_local(self) -> Option> { - Some(self.into()) - } - fn is_local(self) -> bool { - true - } -} - -#[derive(Clone, Copy, PartialEq, Eq, Hash)] -pub struct CoroutineClosureIdWrapper<'db>(pub InternedCoroutineClosureId<'db>); - -impl std::fmt::Debug for CoroutineClosureIdWrapper<'_> { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - std::fmt::Debug::fmt(&SolverDefId::from(self.0), f) - } -} - -impl<'db> From> for InternedCoroutineClosureId<'db> { - #[inline] - fn from(value: CoroutineClosureIdWrapper<'db>) -> InternedCoroutineClosureId<'db> { - value.0 - } -} - -impl<'db> From> for CoroutineClosureIdWrapper<'db> { - #[inline] - fn from(value: InternedCoroutineClosureId<'db>) -> CoroutineClosureIdWrapper<'db> { - Self(value) - } -} + impl<'db> From<$name<'db>> for $wraps<'db> { + #[inline] + fn from(value: $name<'db>) -> $wraps<'db> { + value.0 + } + } -impl<'db> From> for SolverDefId<'db> { - #[inline] - fn from(value: CoroutineClosureIdWrapper<'db>) -> SolverDefId<'db> { - value.0.into() - } -} + impl<'db> From<$wraps<'db>> for $name<'db> { + #[inline] + fn from(value: $wraps<'db>) -> $name<'db> { + Self(value) + } + } -impl<'db> TryFrom> for CoroutineClosureIdWrapper<'db> { - type Error = (); + impl<'db> From<$name<'db>> for SolverDefId<'db> { + #[inline] + fn from(value: $name<'db>) -> SolverDefId<'db> { + value.0.into() + } + } - #[inline] - fn try_from(value: SolverDefId<'db>) -> Result { - match value { - SolverDefId::InternedCoroutineClosureId(it) => Ok(Self(it)), - _ => Err(()), + impl<'db> inherent::DefId, $local> for $name<'db> { + fn as_local(self) -> Option<$local> { + Some(self.into()) + } + fn is_local(self) -> bool { + true + } } - } + }; } -impl<'db> inherent::DefId, SolverDefId<'db>> for CoroutineClosureIdWrapper<'db> { - fn as_local(self) -> Option> { - Some(self.into()) - } - fn is_local(self) -> bool { - true - } -} +declare_id_wrapper!(TraitIdWrapper, TraitId); +declare_id_wrapper!(TypeAliasIdWrapper, TypeAliasId); +declare_id_wrapper_with_lt!(ClosureIdWrapper, InternedClosureId); +declare_id_wrapper_with_lt!(CoroutineIdWrapper, InternedCoroutineId); +declare_id_wrapper_with_lt!(CoroutineClosureIdWrapper, InternedCoroutineClosureId); declare_id_wrapper!(AdtIdWrapper, AdtId); declare_id_wrapper!(OpaqueTyIdWrapper, InternedOpaqueTyId, OpaqueTyIdWrapper); From cda60096ee51a1ba4d4ac91d7015abad77a79719 Mon Sep 17 00:00:00 2001 From: Ada Alakbarova Date: Wed, 17 Jun 2026 14:23:56 +0200 Subject: [PATCH 26/76] add lifetime to `InternedOpaqueTyId` --- src/tools/rust-analyzer/crates/hir-ty/src/db.rs | 2 +- .../crates/hir-ty/src/dyn_compatibility.rs | 4 ++-- src/tools/rust-analyzer/crates/hir-ty/src/infer.rs | 2 +- src/tools/rust-analyzer/crates/hir-ty/src/lower.rs | 8 ++++++-- .../crates/hir-ty/src/next_solver/def_id.rs | 6 +++--- .../crates/hir-ty/src/next_solver/infer/select.rs | 2 +- .../crates/hir-ty/src/next_solver/interner.rs | 6 +++--- .../crates/hir-ty/src/next_solver/solver.rs | 2 +- .../crates/hir-ty/src/next_solver/ty.rs | 2 +- src/tools/rust-analyzer/crates/hir-ty/src/opaques.rs | 12 ++++++------ 10 files changed, 25 insertions(+), 21 deletions(-) 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 9944079cd3073..2954af0b52366 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs @@ -346,7 +346,7 @@ fn hir_database_is_dyn_compatible() { fn _assert_dyn_compatible(_: &dyn HirDatabase) {} } -#[salsa_macros::interned(no_lifetime, debug, revisions = usize::MAX)] +#[salsa_macros::interned(debug, revisions = usize::MAX)] #[derive(PartialOrd, Ord)] pub struct InternedOpaqueTyId { pub loc: ImplTraitId, 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 3920a84639bd5..751e1424ab679 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 @@ -498,9 +498,9 @@ fn contains_illegal_impl_trait_in_trait<'db>( db: &'db dyn HirDatabase, sig: &EarlyBinder<'db, Binder<'db, rustc_type_ir::FnSig>>>, ) -> Option { - struct OpaqueTypeCollector(FxHashSet); + struct OpaqueTypeCollector<'db>(FxHashSet>); - impl<'db> rustc_type_ir::TypeVisitor> for OpaqueTypeCollector { + impl<'db> rustc_type_ir::TypeVisitor> for OpaqueTypeCollector<'db> { type Result = ControlFlow<()>; fn visit_ty( 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 462f81a30496f..5db5be0fd1fa0 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs @@ -767,7 +767,7 @@ pub struct InferenceResult<'db> { pub(crate) type_of_pat: ArenaMap, pub(crate) type_of_binding: ArenaMap, pub(crate) type_of_type_placeholder: FxHashMap, - pub(crate) type_of_opaque: FxHashMap, + pub(crate) type_of_opaque: FxHashMap, StoredTy>, /// Whether there are any type-mismatching errors in the result. // FIXME: This isn't as useful as initially thought due to us falling back placeholders to 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 f68358af9486a..edc92b1e09989 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs @@ -1267,7 +1267,11 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { } } - fn lower_impl_trait(&mut self, def_id: InternedOpaqueTyId, bounds: &[TypeBound]) -> ImplTrait { + fn lower_impl_trait( + &mut self, + def_id: InternedOpaqueTyId<'db>, + bounds: &[TypeBound], + ) -> ImplTrait { let interner = self.interner; cov_mark::hit!(lower_rpit); let args = GenericArgs::identity_for_item(interner, def_id.into()); @@ -1526,7 +1530,7 @@ impl ImplTraitId { } } -impl InternedOpaqueTyId { +impl InternedOpaqueTyId<'_> { #[inline] pub fn predicates<'db>(self, db: &'db dyn HirDatabase) -> EarlyBinder<'db, &'db [Clause<'db>]> { self.loc(db).predicates(db) 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 dd6b19a84ba0d..b122a8cddc410 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 @@ -43,7 +43,7 @@ pub enum SolverDefId<'db> { InternedClosureId(InternedClosureId<'db>), InternedCoroutineId(InternedCoroutineId<'db>), InternedCoroutineClosureId(InternedCoroutineClosureId<'db>), - InternedOpaqueTyId(InternedOpaqueTyId), + InternedOpaqueTyId(InternedOpaqueTyId<'db>), EnumVariantId(EnumVariantId), Ctor(Ctor), } @@ -136,7 +136,7 @@ impl_from!( InternedClosureId<'db>, InternedCoroutineId<'db>, InternedCoroutineClosureId<'db>, - InternedOpaqueTyId, + InternedOpaqueTyId<'db>, EnumVariantId, Ctor for SolverDefId<'db> @@ -457,7 +457,7 @@ declare_id_wrapper_with_lt!(ClosureIdWrapper, InternedClosureId); declare_id_wrapper_with_lt!(CoroutineIdWrapper, InternedCoroutineId); declare_id_wrapper_with_lt!(CoroutineClosureIdWrapper, InternedCoroutineClosureId); declare_id_wrapper!(AdtIdWrapper, AdtId); -declare_id_wrapper!(OpaqueTyIdWrapper, InternedOpaqueTyId, OpaqueTyIdWrapper); +declare_id_wrapper_with_lt!(OpaqueTyIdWrapper, InternedOpaqueTyId, OpaqueTyIdWrapper<'db>); macro_rules! declare_ty_const_pair { ( $ty_id_name:ident, $const_id_name:ident, $term_id_name:ident ) => { 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 d6f0379c111a2..1462f292058ee 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 @@ -40,7 +40,7 @@ pub enum SelectionError<'db> { /// Computing an opaque type's hidden type caused an error (e.g. a cycle error). /// We can thus not know whether the hidden type implements an auto trait, so /// we should not presume anything about it. - OpaqueTypeAutoTraitLeakageUnknown(InternedOpaqueTyId), + OpaqueTypeAutoTraitLeakageUnknown(InternedOpaqueTyId<'db>), /// Error for a `ConstArgHasType` goal ConstArgHasWrongType { ct: Const<'db>, ct_ty: Ty<'db>, expected_ty: Ty<'db> }, } 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 ab6ce31256897..a7216a034cc56 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 @@ -894,8 +894,8 @@ impl<'db> Interner for DbInterner<'db> { type TraitAssocTyId = TraitAssocTyId; type TraitAssocConstId = TraitAssocConstId; type TraitAssocTermId = TraitAssocTermId; - type OpaqueTyId = OpaqueTyIdWrapper; - type LocalOpaqueTyId = OpaqueTyIdWrapper; + type OpaqueTyId = OpaqueTyIdWrapper<'db>; + type LocalOpaqueTyId = OpaqueTyIdWrapper<'db>; type FreeTyAliasId = FreeTyAliasId; type FreeConstAliasId = FreeConstAliasId; type FreeTermAliasId = FreeTermAliasId; @@ -2345,7 +2345,7 @@ TrivialTypeTraversalImpls! { InherentAssocTyId, InherentAssocConstId, InherentAssocTermId, - OpaqueTyIdWrapper, + OpaqueTyIdWrapper<'_>, AnyImplId, GeneralConstIdWrapper<'_>, Safety, 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 b1b3a0e0dc78a..5486a565815de 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 @@ -130,7 +130,7 @@ impl<'db> SolverDelegate for SolverContext<'db> { fn add_item_bounds_for_hidden_type( &self, - opaque_id: OpaqueTyIdWrapper, + opaque_id: OpaqueTyIdWrapper<'_>, args: GenericArgs<'db>, param_env: ParamEnv<'db>, hidden_ty: Ty<'db>, 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 397db9375b940..05f559c0349e9 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 @@ -176,7 +176,7 @@ impl<'db> Ty<'db> { pub fn new_opaque( interner: DbInterner<'db>, - def_id: InternedOpaqueTyId, + def_id: InternedOpaqueTyId<'db>, args: GenericArgs<'db>, ) -> Self { Ty::new_alias( diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/opaques.rs b/src/tools/rust-analyzer/crates/hir-ty/src/opaques.rs index 1d7cd1b05dfea..9cb0022ca6bfc 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/opaques.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/opaques.rs @@ -20,10 +20,10 @@ use crate::{ }, }; -pub(crate) fn opaque_types_defined_by( - db: &dyn HirDatabase, +pub(crate) fn opaque_types_defined_by<'db>( + db: &'db dyn HirDatabase, def_id: InferBodyId<'_>, - result: &mut Vec>, + result: &mut Vec>, ) { if let Some(func) = def_id.as_function() { // A function may define its own RPITs. @@ -79,11 +79,11 @@ pub(crate) fn opaque_types_defined_by( // FIXME: Collect opaques from `#[define_opaque]`. - fn extend_with_opaques( - db: &dyn HirDatabase, + fn extend_with_opaques<'db>( + db: &'db dyn HirDatabase, opaques: &Option>>, mut make_impl_trait: impl FnMut(ImplTraitIdx) -> ImplTraitId, - result: &mut Vec>, + result: &mut Vec>, ) { if let Some(opaques) = opaques { for (opaque_idx, _) in (**opaques).as_ref().skip_binder().impl_traits.iter() { From 67252fe416a603923196475a4d4fa5c7ccbd9973 Mon Sep 17 00:00:00 2001 From: Yuki Okamoto Date: Sun, 21 Jun 2026 16:50:37 +0900 Subject: [PATCH 27/76] fix: defer const normalize in coherence mode --- ...herence-overlap-const-projection-157937.rs | 33 +++++++++++++++++++ ...nce-overlap-const-projection-157937.stderr | 12 +++++++ 2 files changed, 45 insertions(+) create mode 100644 tests/ui/const-generics/generic_const_exprs/coherence-overlap-const-projection-157937.rs create mode 100644 tests/ui/const-generics/generic_const_exprs/coherence-overlap-const-projection-157937.stderr diff --git a/tests/ui/const-generics/generic_const_exprs/coherence-overlap-const-projection-157937.rs b/tests/ui/const-generics/generic_const_exprs/coherence-overlap-const-projection-157937.rs new file mode 100644 index 0000000000000..7f7766dbf035e --- /dev/null +++ b/tests/ui/const-generics/generic_const_exprs/coherence-overlap-const-projection-157937.rs @@ -0,0 +1,33 @@ +// Cited from [#157937](https://github.com/rust-lang/rust/issues/157937) + +#![feature(generic_const_exprs)] +trait Trait { + const CONST: usize; +} +struct A { + _marker: T, +} +impl Trait for [i8; N] { + const CONST: usize = N; +} +impl From for A<[i8; N]> { + fn from(_: usize) -> Self { + todo!() + } +} +impl From> for A { +//~^ ERROR: conflicting implementations of trait `From>` for type `A<[i8; _]>` [E0119] + fn from(_: A<[i8; T::CONST]>) -> Self { + todo!() + } +} +fn f() -> A +where + [(); T::CONST]:, +{ + let a = A::from(0); + A::from(a) +} +fn main() { + f::<[i8; 1]>(); +} diff --git a/tests/ui/const-generics/generic_const_exprs/coherence-overlap-const-projection-157937.stderr b/tests/ui/const-generics/generic_const_exprs/coherence-overlap-const-projection-157937.stderr new file mode 100644 index 0000000000000..8d72acec7da52 --- /dev/null +++ b/tests/ui/const-generics/generic_const_exprs/coherence-overlap-const-projection-157937.stderr @@ -0,0 +1,12 @@ +error[E0119]: conflicting implementations of trait `From>` for type `A<[i8; _]>` + --> $DIR/coherence-overlap-const-projection-157937.rs:18:1 + | +LL | impl From> for A { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: conflicting implementation in crate `core`: + - impl From for T; + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0119`. From 32a1b51f541af9832124d8ba321c82ad2085ed6e Mon Sep 17 00:00:00 2001 From: Yuki Okamoto Date: Mon, 20 Jul 2026 18:52:36 +0900 Subject: [PATCH 28/76] fix(test): remove the test that should not be passed and will be deleted (GCE) --- tests/ui/const-generics/issues/issue-89304.rs | 20 ------------------- 1 file changed, 20 deletions(-) delete mode 100644 tests/ui/const-generics/issues/issue-89304.rs diff --git a/tests/ui/const-generics/issues/issue-89304.rs b/tests/ui/const-generics/issues/issue-89304.rs deleted file mode 100644 index d5cbfc9300b1c..0000000000000 --- a/tests/ui/const-generics/issues/issue-89304.rs +++ /dev/null @@ -1,20 +0,0 @@ -//@ check-pass - -#![feature(generic_const_exprs)] -#![allow(incomplete_features)] - -struct GenericStruct { val: i64 } - -impl From> for GenericStruct<{T + 1}> { - fn from(other: GenericStruct) -> Self { - Self { val: other.val } - } -} - -impl From> for GenericStruct { - fn from(other: GenericStruct<{T + 1}>) -> Self { - Self { val: other.val } - } -} - -fn main() {} From b882493aad5cc171c47dc443a6be683cd45eb5c2 Mon Sep 17 00:00:00 2001 From: Yuki Okamoto Date: Mon, 20 Jul 2026 18:54:00 +0900 Subject: [PATCH 29/76] fix: check whether next_trait_solver which does not support GCE --- compiler/rustc_infer/src/infer/relate/generalize.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_infer/src/infer/relate/generalize.rs b/compiler/rustc_infer/src/infer/relate/generalize.rs index 88d0c20b178fa..36eb4c9f59370 100644 --- a/compiler/rustc_infer/src/infer/relate/generalize.rs +++ b/compiler/rustc_infer/src/infer/relate/generalize.rs @@ -752,7 +752,7 @@ impl<'tcx> TypeRelation> for Generalizer<'_, 'tcx> { // Hack: Fall back to old behavior if GCE is enabled (it used to just be the Yes // path), as doing this new No path breaks some GCE things. I expect GCE to be // ripped out soon so this shouldn't matter soon. - if !tcx.features().generic_const_exprs() { + if self.infcx.next_trait_solver() || !tcx.features().generic_const_exprs() { self.generalize_alias_term(alias_const.into()).map(|v| v.expect_const()) } else { let ty::AliasConst { kind, args, .. } = alias_const; From 7e186a8c08b0281e9b5a288a211079377936e5d8 Mon Sep 17 00:00:00 2001 From: Yuki Okamoto Date: Mon, 20 Jul 2026 19:13:00 +0900 Subject: [PATCH 30/76] chore(test): remove problematic test from issues.txt in tidy --- src/tools/tidy/src/issues.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt index bb251a6823ac6..c15bc3af026e5 100644 --- a/src/tools/tidy/src/issues.txt +++ b/src/tools/tidy/src/issues.txt @@ -623,7 +623,6 @@ ui/const-generics/issues/issue-88119.rs ui/const-generics/issues/issue-88468.rs ui/const-generics/issues/issue-88997.rs ui/const-generics/issues/issue-89146.rs -ui/const-generics/issues/issue-89304.rs ui/const-generics/issues/issue-89320.rs ui/const-generics/issues/issue-89334.rs ui/const-generics/issues/issue-90318.rs From 5dab5cbc11832bc09af85b9b412ad9b06285b8e3 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Tue, 21 Jul 2026 18:32:42 +0300 Subject: [PATCH 31/76] Change unsupported toolchain version to match reality Since https://github.com/rust-lang/rust-analyzer/pull/22784. --- src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs index e953ea2136297..9eee516c3a2d7 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs @@ -22,7 +22,7 @@ extern crate ra_ap_rustc_type_ir as rustc_type_ir; /// Any toolchain less than this version will likely not work with rust-analyzer built from this revision. pub const MINIMUM_SUPPORTED_TOOLCHAIN_VERSION: semver::Version = semver::Version { major: 1, - minor: 78, + minor: 94, patch: 0, pre: semver::Prerelease::EMPTY, build: semver::BuildMetadata::EMPTY, From 19551c2bf66ebc2b4bde3b263b3b0dcf7d0859b3 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Tue, 21 Jul 2026 20:58:57 +0300 Subject: [PATCH 32/76] Do not detect `#[rust_analyzer]` as `#[rust_analyzer::rust_fixture]` --- .../rust-analyzer/crates/ide-db/src/ra_fixture.rs | 11 ++++++++--- .../test_data/highlight_injection.html | 4 ++++ .../crates/ide/src/syntax_highlighting/tests.rs | 4 ++++ 3 files changed, 16 insertions(+), 3 deletions(-) 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 index 2f4d319ec8218..c8607a8099b91 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/ra_fixture.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/ra_fixture.rs @@ -3,6 +3,7 @@ use std::hash::{BuildHasher, Hash}; use hir::{CfgExpr, FilePositionWrapper, FileRangeWrapper, Semantics, Symbol}; +use itertools::Itertools; use smallvec::SmallVec; use span::{TextRange, TextSize}; use syntax::{ @@ -96,9 +97,13 @@ impl RaFixtureAnalysis { 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)) + let Some([Some(segment1), Some(segment2)]) = + path.segments().map(|seg| seg.name_ref()).collect_array() + else { + return false; + }; + segment1.text_non_mutable() == "rust_analyzer" + && segment2.text_non_mutable() == "rust_fixture" }) }); if !has_rust_fixture_attr { 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 22f3ba9ed8314..ad829d9e99c2c 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,6 +43,8 @@
fn fixture(#[rust_analyzer::rust_fixture] ra_fixture: &str) {}
 
+fn non_fixture(#[rust_analyzer] ra_fixture: &str) {}
+
 fn main() {
     fixture(r#"
 @@- minicore: sized
@@ -59,4 +61,6 @@
     }$0)
 }"
     );
+
+    non_fixture(r"@@- ");
 }
\ No newline at end of file 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 c0a923afbe6a3..15e48feceeb97 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 @@ -1066,6 +1066,8 @@ fn test_injection() { r##" fn fixture(#[rust_analyzer::rust_fixture] ra_fixture: &str) {} +fn non_fixture(#[rust_analyzer] ra_fixture: &str) {} + fn main() { fixture(r#" @@- minicore: sized @@ -1082,6 +1084,8 @@ fn foo() { }\$0) }" ); + + non_fixture(r"@@- "); } "##, expect_file!["./test_data/highlight_injection.html"], From 80db819591df7cc1d063686ed8c09fd98dab9ef2 Mon Sep 17 00:00:00 2001 From: Stan Yolo Date: Tue, 21 Jul 2026 20:44:03 +0300 Subject: [PATCH 33/76] internal: add `Module::path_segments`, dedup the path-to-root name walk MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Five call sites spelled out the same walk by hand — `path_to_root`, reverse, `filter_map` the names — before rendering it as `::`-joined text: `ModuleDef::canonical_path`, `cli::full_name_of_item`, two in `analysis_stats`, and hover's path rendering. `Module::path_segments` names that walk once and returns `Name`s rather than a finished `String`: the call sites disagree on the edition to display with (the CLI ones pin `Edition::LATEST`, hover takes it as a parameter), so joining inside the helper would have fit none of them. `ModuleDef::canonical_module_path` is the nearby sibling that yields the `Module`s themselves; it does not serve these sites. Four of the five hold only a `Module`, and it hangs off `ModuleDef` — while routing the fifth, `canonical_path`, through it would put the `filter_map` this change removes straight back. The two are cross-referenced in the docs instead. Left alone: the two walks in `runnables`, which display each segment with its own module's edition and so need the `Module`, not just its name. No behavior change, with one wrinkle: `canonical_path` now renders each segment into a `String` before joining. The iterator is lazy and owns its `Name`s, so a borrowed `impl Display` cannot escape the closure — the old code got away with it by collecting into a `Vec` first. The other four sites already did this. This change was written with the assistance of an AI coding agent (Claude); a human directed and reviewed the work. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/tools/rust-analyzer/crates/hir/src/lib.rs | 23 ++++++++++++++----- .../crates/ide/src/hover/render.rs | 6 +---- .../crates/rust-analyzer/src/cli.rs | 5 +--- .../rust-analyzer/src/cli/analysis_stats.rs | 10 ++------ 4 files changed, 21 insertions(+), 23 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index ab7d88eeefb16..70e2d3faf1602 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -438,12 +438,9 @@ impl ModuleDef { } pub fn canonical_path(&self, db: &dyn HirDatabase, edition: Edition) -> Option { - let mut segments = vec![self.name(db)?]; - for m in self.module(db)?.path_to_root(db) { - segments.extend(m.name(db)) - } - segments.reverse(); - Some(segments.iter().map(|it| it.display(db, edition)).join("::")) + let name = self.name(db)?; + let segments = self.module(db)?.path_segments(db).chain(Some(name)); + Some(segments.map(|it| it.display(db, edition).to_string()).join("::")) } pub fn canonical_module_path( @@ -679,6 +676,20 @@ impl Module { res } + /// Names of the modules enclosing `self`, crate root first, `self` last. + /// + /// Nameless modules — the crate root, and block modules — drop out, so this is + /// generally shorter than [`Module::path_to_root`]. Segments stay `Name`s rather + /// than rendered text because callers disagree on the edition to display with, + /// and some need to take the path apart rather than print it. + /// + /// [`ModuleDef::canonical_module_path`] is the same walk yielding the `Module`s + /// themselves, for callers that need more than the name — each module's own + /// edition, say. + pub fn path_segments(self, db: &dyn HirDatabase) -> impl Iterator { + self.path_to_root(db).into_iter().rev().filter_map(|it| it.name(db)) + } + pub fn modules_in_scope(&self, db: &dyn HirDatabase, pub_only: bool) -> Vec<(Name, Module)> { let def_map = self.id.def_map(db); let scope = &def_map[self.id].scope; 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 88d21b23e849a..f26b99292929e 100644 --- a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs +++ b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs @@ -439,11 +439,7 @@ pub(super) fn path( edition: Edition, ) -> String { let crate_name = module.krate(db).display_name(db).as_ref().map(|it| it.to_string()); - let module_path = module - .path_to_root(db) - .into_iter() - .rev() - .flat_map(|it| it.name(db).map(|name| name.display(db, edition).to_string())); + let module_path = module.path_segments(db).map(|it| it.display(db, edition).to_string()); crate_name.into_iter().chain(module_path).chain(item_name).join("::") } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli.rs index 6643037220ae4..cc0efe9ee9389 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli.rs @@ -82,10 +82,7 @@ fn print_memory_usage(mut host: AnalysisHost, vfs: Vfs) { fn full_name_of_item(db: &dyn HirDatabase, module: Module, name: Name) -> String { module - .path_to_root(db) - .into_iter() - .rev() - .filter_map(|it| it.name(db)) + .path_segments(db) .chain(Some(name)) .map(|it| it.display(db, Edition::LATEST).to_string()) .join("::") 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 ae9a0cf094cae..87790ce2bca17 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 @@ -753,10 +753,7 @@ impl flags::AnalysisStats { }; if verbosity.is_spammy() { let full_name = module - .path_to_root(db) - .into_iter() - .rev() - .filter_map(|it| it.name(db)) + .path_segments(db) .chain(Some(body.name(db).unwrap_or_else(Name::missing))) .map(|it| it.display(db, Edition::LATEST).to_string()) .join("::"); @@ -1487,10 +1484,7 @@ fn full_name(db: &RootDatabase, name: impl Fn() -> Option, module: hir::Mo .into_iter() .chain( module - .path_to_root(db) - .into_iter() - .filter_map(|it| it.name(db)) - .rev() + .path_segments(db) .chain(Some(name().unwrap_or_else(Name::missing))) .map(|it| it.display(db, Edition::LATEST).to_string()), ) From b14606e2be1532634d1a16ba6ccaec1d24d0b187 Mon Sep 17 00:00:00 2001 From: TheDoctor314 <64731940+TheDoctor314@users.noreply.github.com> Date: Sun, 19 Jul 2026 01:40:36 +0530 Subject: [PATCH 34/76] Emit existing `MissingFields` diagnostic for incomplete struct patterns --- .../crates/hir-ty/src/diagnostics/expr.rs | 12 ----- .../rust-analyzer/crates/hir-ty/src/infer.rs | 8 ++++ .../crates/hir-ty/src/infer/pat.rs | 10 ++-- .../crates/hir/src/diagnostics.rs | 46 +++++++++++++++++++ .../src/handlers/missing_fields.rs | 4 +- 5 files changed, 63 insertions(+), 17 deletions(-) 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 fd8d7e02a512e..0947f456adeae 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 @@ -157,18 +157,6 @@ impl<'db> ExprValidator<'db> { _ => {} } } - - for (id, pat) in body.pats() { - if let Some((variant, missed_fields)) = - record_pattern_missing_fields(db, self.infer, id, pat) - { - self.diagnostics.push(BodyValidationDiagnostic::RecordMissingFields { - record: Either::Right(id), - variant, - missed_fields, - }); - } - } } fn validate_call( 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 5db5be0fd1fa0..2cb6666672856 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs @@ -538,6 +538,14 @@ pub enum InferenceDiagnostic { #[type_visitable(ignore)] kind: ReturnKind, }, + RecordMissingFields { + #[type_visitable(ignore)] + record: ExprOrPatId, + #[type_visitable(ignore)] + variant: VariantId, + #[type_visitable(ignore)] + missed_fields: Vec, + }, } #[derive(Debug, PartialEq, Eq, Clone, Copy)] 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 91e0619fd3ff9..f464de06cd30f 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 @@ -10,8 +10,8 @@ use hir_def::{ AdtId, LocalFieldId, VariantId, expr_store::path::Path, hir::{ - BindingAnnotation, BindingId, Expr, ExprId, ExprOrPatIdPacked, Literal, Pat, PatId, - RecordFieldPat, + BindingAnnotation, BindingId, Expr, ExprId, ExprOrPatId, ExprOrPatIdPacked, Literal, Pat, + PatId, RecordFieldPat, }, resolver::ValueNs, signatures::VariantFields, @@ -1248,7 +1248,11 @@ impl<'db> InferenceContext<'db> { self.push_diagnostic(InferenceDiagnostic::UnionPatHasRest { pat }); } } else if !unmentioned_fields.is_empty() && !has_rest_pat { - // FIXME: Emit an error. + self.push_diagnostic(InferenceDiagnostic::RecordMissingFields { + record: ExprOrPatId::PatId(pat), + variant, + missed_fields: unmentioned_fields.into_iter().map(|f| f.0).collect(), + }) } } diff --git a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs index 2edcc63c44d72..91bb7b481f5e3 100644 --- a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs +++ b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs @@ -1141,6 +1141,52 @@ impl<'db> AnyDiagnostic<'db> { &InferenceDiagnostic::ReturnOutsideFunction { expr, kind } => { ReturnOutsideFunction { expr: expr_syntax(expr)?, kind }.into() } + &InferenceDiagnostic::RecordMissingFields { record, variant, ref missed_fields } => { + let record = expr_or_pat_syntax(record)?; + let file = record.file_id; + let root = record.file_syntax(db); + let variant_data = variant.fields(db); + let missed_fields = missed_fields + .iter() + .map(|&idx| { + ( + variant_data.fields()[idx].name.clone(), + Field { parent: variant.into(), id: idx }, + ) + }) + .collect(); + match record.value.to_node(&root) { + Either::Left(ast::Expr::RecordExpr(record_expr)) + if record_expr.record_expr_field_list().is_some() => + { + let field_list_parent_path = + record_expr.path().map(|path| AstPtr::new(&path)); + return Some( + MissingFields { + file, + field_list_parent: AstPtr::new(&Either::Left(record_expr)), + field_list_parent_path, + missed_fields, + } + .into(), + ); + } + Either::Right(ast::Pat::RecordPat(record_pat)) + if record_pat.record_pat_field_list().is_some() => + { + let field_list_parent_path = + record_pat.path().map(|path| AstPtr::new(&path)); + MissingFields { + file, + field_list_parent: AstPtr::new(&Either::Right(record_pat)), + field_list_parent_path, + missed_fields, + } + .into() + } + _ => return None, + } + } }) } diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs index 2030be436887a..639be5e85a59c 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs @@ -274,7 +274,7 @@ fn get_default_constructor( #[cfg(test)] mod tests { - use crate::tests::{check_diagnostics, check_fix, check_no_fix}; + use crate::tests::{check_diagnostics, check_fix, check_has_fix, check_no_fix}; #[test] fn missing_record_pat_field_diagnostic() { @@ -829,7 +829,7 @@ fn f() { #[test] fn test_fill_struct_pat_fields_partial() { - check_fix( + check_has_fix( r#" struct S { a: &'static str, b: i32 } From 6df48f48f83e577e3b4a16b18c86a4be6a4ea1c0 Mon Sep 17 00:00:00 2001 From: Ada Alakbarova Date: Wed, 22 Jul 2026 10:24:07 +0200 Subject: [PATCH 35/76] internal: refer to salsa macros using `salsa::` Sometimes it's `salsa_macros::`, sometimes it's `salsa::` -- the inconsistency was annoying. --- .../rust-analyzer/crates/base-db/src/input.rs | 2 +- .../rust-analyzer/crates/base-db/src/lib.rs | 10 ++++----- .../crates/hir-def/src/item_tree.rs | 4 ++-- .../crates/hir-def/src/lang_item.rs | 4 ++-- .../rust-analyzer/crates/hir-def/src/lib.rs | 22 +++++++++---------- .../crates/hir-def/src/nameres.rs | 6 ++--- .../crates/hir-def/src/test_db.rs | 6 ++--- .../crates/hir-expand/src/lib.rs | 4 ++-- .../crates/hir-expand/src/span_map.rs | 2 +- .../rust-analyzer/crates/hir-ty/src/db.rs | 12 +++++----- .../crates/hir-ty/src/layout/target.rs | 2 +- .../rust-analyzer/crates/hir-ty/src/lower.rs | 8 +++---- .../crates/hir-ty/src/mir/lower.rs | 4 ++-- .../crates/hir-ty/src/mir/monomorphization.rs | 4 ++-- .../crates/hir-ty/src/test_db.rs | 6 ++--- .../rust-analyzer/crates/ide-db/src/lib.rs | 6 ++--- 16 files changed, 51 insertions(+), 51 deletions(-) diff --git a/src/tools/rust-analyzer/crates/base-db/src/input.rs b/src/tools/rust-analyzer/crates/base-db/src/input.rs index 38f9c5a5a14c4..1e32ee69804c7 100644 --- a/src/tools/rust-analyzer/crates/base-db/src/input.rs +++ b/src/tools/rust-analyzer/crates/base-db/src/input.rs @@ -447,7 +447,7 @@ impl BuiltDependency { pub type CratesIdMap = FxHashMap; -#[salsa_macros::input] +#[salsa::input] #[derive(Debug, PartialOrd, Ord)] pub struct Crate { #[returns(ref)] diff --git a/src/tools/rust-analyzer/crates/base-db/src/lib.rs b/src/tools/rust-analyzer/crates/base-db/src/lib.rs index 7f915827b5f8e..4beeae9508652 100644 --- a/src/tools/rust-analyzer/crates/base-db/src/lib.rs +++ b/src/tools/rust-analyzer/crates/base-db/src/lib.rs @@ -79,7 +79,7 @@ pub type FxIndexMap = #[macro_export] macro_rules! impl_intern_key { ($id:ident, $loc:ident) => { - #[salsa_macros::interned(no_lifetime, revisions = usize::MAX)] + #[salsa::interned(no_lifetime, revisions = usize::MAX)] #[derive(PartialOrd, Ord)] pub struct $id { #[returns(ref)] @@ -246,24 +246,24 @@ pub struct LocalRoots { pub roots: FxHashSet, } -#[salsa_macros::input(debug)] +#[salsa::input(debug)] pub struct FileText { #[returns(ref)] pub text: Arc, pub file_id: vfs::FileId, } -#[salsa_macros::input(debug)] +#[salsa::input(debug)] pub struct FileSourceRootInput { pub source_root_id: SourceRootId, } -#[salsa_macros::input(debug)] +#[salsa::input(debug)] pub struct SourceRootInput { pub source_root: Arc, } -#[salsa_macros::db] +#[salsa::db] pub trait SourceDatabase: salsa::Database + std::fmt::Debug { /// Text of the file. fn file_text(&self, file_id: vfs::FileId) -> FileText; diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs index cb6941aaa4cd4..423ffd5d408d8 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs @@ -138,7 +138,7 @@ pub fn file_item_tree(db: &dyn SourceDatabase, file_id: HirFileId, krate: Crate) } } -#[salsa_macros::tracked(returns(ref))] +#[salsa::tracked(returns(ref))] fn file_item_tree_query( db: &dyn SourceDatabase, file_id: HirFileId, @@ -197,7 +197,7 @@ fn file_item_tree_query( } } -#[salsa_macros::tracked(returns(ref))] +#[salsa::tracked(returns(ref))] pub(crate) fn block_item_tree_query( db: &dyn SourceDatabase, block: BlockId, diff --git a/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs b/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs index 14e559200f01c..534a9c31cd531 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs @@ -34,7 +34,7 @@ impl_from!( ); /// Salsa query. This will look for lang items in a specific crate. -#[salsa_macros::tracked(returns(as_deref))] +#[salsa::tracked(returns(as_deref))] pub fn crate_lang_items(db: &dyn SourceDatabase, krate: Crate) -> Option> { let _p = tracing::info_span!("crate_lang_items_query").entered(); @@ -112,7 +112,7 @@ pub fn crate_lang_items(db: &dyn SourceDatabase, krate: Crate) -> Option LangItems { let _p = tracing::info_span!("lang_items_query").entered(); diff --git a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs index c1519a3b0df93..bed38d38e0117 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs @@ -492,7 +492,7 @@ mod tracked_struct_token { } } -#[salsa_macros::tracked(constructor = new_)] +#[salsa::tracked(constructor = new_)] #[derive(PartialOrd, Ord)] pub struct BlockIdLt<'db> { pub ast_id: AstId, @@ -534,7 +534,7 @@ impl BlockId { } } -#[salsa_macros::tracked(debug)] +#[salsa::tracked(debug)] #[derive(PartialOrd, Ord)] pub struct ModuleIdLt<'db> { /// The crate this module belongs to. @@ -718,7 +718,7 @@ pub struct HrtbLifetimeParamId { pub local_id: usize, } -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, salsa_macros::Supertype)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, salsa::Supertype)] pub enum ItemContainerId { ExternBlockId(ExternBlockId), ModuleId(ModuleId), @@ -728,7 +728,7 @@ pub enum ItemContainerId { impl_from!(ModuleId for ItemContainerId); /// A Data Type -#[derive(Debug, PartialOrd, Ord, Clone, Copy, PartialEq, Eq, Hash, salsa_macros::Supertype)] +#[derive(Debug, PartialOrd, Ord, Clone, Copy, PartialEq, Eq, Hash, salsa::Supertype)] pub enum AdtId { StructId(StructId), UnionId(UnionId), @@ -737,7 +737,7 @@ pub enum AdtId { impl_from!(StructId, UnionId, EnumId for AdtId); /// A macro -#[derive(Debug, PartialOrd, Ord, Clone, Copy, PartialEq, Eq, Hash, salsa_macros::Supertype)] +#[derive(Debug, PartialOrd, Ord, Clone, Copy, PartialEq, Eq, Hash, salsa::Supertype)] pub enum MacroId { Macro2Id(Macro2Id), MacroRulesId(MacroRulesId), @@ -859,7 +859,7 @@ impl From for ModuleDefId { } /// The defs which have a body. -#[derive(Debug, PartialOrd, Ord, Clone, Copy, PartialEq, Eq, Hash, salsa_macros::Supertype)] +#[derive(Debug, PartialOrd, Ord, Clone, Copy, PartialEq, Eq, Hash, salsa::Supertype)] pub enum DefWithBodyId { /// A function body. FunctionId(FunctionId), @@ -889,7 +889,7 @@ impl DefWithBodyId { } } -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, salsa_macros::Supertype)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, salsa::Supertype)] pub enum AssocItemId { FunctionId(FunctionId), ConstId(ConstId), @@ -911,7 +911,7 @@ impl_from!( for ModuleDefId ); -#[derive(Debug, PartialOrd, Ord, Clone, Copy, PartialEq, Eq, Hash, salsa_macros::Supertype)] +#[derive(Debug, PartialOrd, Ord, Clone, Copy, PartialEq, Eq, Hash, salsa::Supertype)] pub enum GenericDefId { AdtId(AdtId), // consts can have type parameters from their parents (i.e. associated consts of traits) @@ -1058,7 +1058,7 @@ impl_from!( for GenericDefId ); -#[derive(Debug, PartialOrd, Ord, Clone, Copy, PartialEq, Eq, Hash, salsa_macros::Supertype)] +#[derive(Debug, PartialOrd, Ord, Clone, Copy, PartialEq, Eq, Hash, salsa::Supertype)] pub enum CallableDefId { FunctionId(FunctionId), StructId(StructId), @@ -1085,7 +1085,7 @@ impl CallableDefId { } } -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, salsa_macros::Supertype)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, salsa::Supertype)] pub enum AttrDefId { ModuleId(ModuleId), AdtId(AdtId), @@ -1124,7 +1124,7 @@ impl_from!( ); #[derive( - Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, salsa_macros::Supertype, salsa::Update, + Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, salsa::Supertype, salsa::Update, )] pub enum VariantId { EnumVariantId(EnumVariantId), diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs index 4b7856e0c1494..c1daad5b3f6a2 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs @@ -381,7 +381,7 @@ pub fn crate_def_map(db: &dyn SourceDatabase, crate_id: Crate) -> &DefMap { crate_local_def_map(db, crate_id).def_map(db) } -#[salsa_macros::tracked] +#[salsa::tracked] pub(crate) struct DefMapPair<'db> { #[tracked] #[returns(ref)] @@ -390,7 +390,7 @@ pub(crate) struct DefMapPair<'db> { pub(crate) local: LocalDefMap, } -#[salsa_macros::tracked(returns(ref))] +#[salsa::tracked(returns(ref))] pub(crate) fn crate_local_def_map(db: &dyn SourceDatabase, crate_id: Crate) -> DefMapPair<'_> { let krate = crate_id.data(db); let _p = tracing::info_span!( @@ -424,7 +424,7 @@ pub(crate) fn crate_local_def_map(db: &dyn SourceDatabase, crate_id: Crate) -> D DefMapPair::new(db, def_map, local_def_map) } -#[salsa_macros::tracked(returns(ref))] +#[salsa::tracked(returns(ref))] pub fn block_def_map<'db>(db: &'db dyn SourceDatabase, block_id: BlockIdLt<'db>) -> DefMap { let block_id = unsafe { block_id.to_static() }; let ast_id = block_id.ast_id(db); diff --git a/src/tools/rust-analyzer/crates/hir-def/src/test_db.rs b/src/tools/rust-analyzer/crates/hir-def/src/test_db.rs index 0598ab4a0435c..4433522c1832f 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/test_db.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/test_db.rs @@ -20,7 +20,7 @@ use crate::{ src::HasSource, }; -#[salsa_macros::db] +#[salsa::db] pub(crate) struct TestDB { storage: salsa::Storage, files: Arc, @@ -73,7 +73,7 @@ impl Clone for TestDB { } } -#[salsa_macros::db] +#[salsa::db] impl salsa::Database for TestDB {} impl fmt::Debug for TestDB { @@ -84,7 +84,7 @@ impl fmt::Debug for TestDB { impl panic::RefUnwindSafe for TestDB {} -#[salsa_macros::db] +#[salsa::db] impl SourceDatabase for TestDB { fn file_text(&self, file_id: base_db::FileId) -> FileText { self.files.file_text(file_id) diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs b/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs index 511b94d7418f1..58ab0e537f693 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs @@ -1544,7 +1544,7 @@ impl ExpandTo { /// /// We encode macro definitions into ids of macro calls, this what allows us /// to be incremental. -#[salsa_macros::interned(no_lifetime, debug, revisions = usize::MAX)] +#[salsa::interned(no_lifetime, debug, revisions = usize::MAX)] #[doc(alias = "MacroFileId")] pub struct MacroCallId { #[returns(ref)] @@ -1565,7 +1565,7 @@ impl From for span::MacroCallId { } } -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, salsa_macros::Supertype)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, salsa::Supertype)] pub enum HirFileId { FileId(EditionedFileId), MacroFile(MacroCallId), diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/span_map.rs b/src/tools/rust-analyzer/crates/hir-expand/src/span_map.rs index 7b1a04de732bb..192a3c06e5e2d 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/span_map.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/span_map.rs @@ -50,7 +50,7 @@ impl HirFileId { /// This is an implementation detail of [`HirFileId::span_map`]. Outside this crate, use /// `HirFileId::from(file_id).span_map(db)` instead of `real_span_map(db, file_id)`. -#[salsa_macros::tracked(returns(ref))] +#[salsa::tracked(returns(ref))] pub(crate) fn real_span_map( db: &dyn SourceDatabase, editioned_file_id: base_db::EditionedFileId, 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 2954af0b52366..8e7e55a77b349 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs @@ -346,7 +346,7 @@ fn hir_database_is_dyn_compatible() { fn _assert_dyn_compatible(_: &dyn HirDatabase) {} } -#[salsa_macros::interned(debug, revisions = usize::MAX)] +#[salsa::interned(debug, revisions = usize::MAX)] #[derive(PartialOrd, Ord)] pub struct InternedOpaqueTyId { pub loc: ImplTraitId, @@ -359,7 +359,7 @@ pub struct InternedClosure<'db> { pub kind: ClosureKind, } -#[salsa_macros::interned(constructor = new_impl, debug, revisions = usize::MAX)] +#[salsa::interned(constructor = new_impl, debug, revisions = usize::MAX)] #[derive(PartialOrd, Ord)] pub struct InternedClosureId<'db> { pub loc: InternedClosure<'db>, @@ -387,7 +387,7 @@ impl<'db> InternedClosureId<'db> { } } -#[salsa_macros::interned(constructor = new_impl, debug, revisions = usize::MAX)] +#[salsa::interned(constructor = new_impl, debug, revisions = usize::MAX)] #[derive(PartialOrd, Ord)] pub struct InternedCoroutineId<'db> { pub loc: InternedClosure<'db>, @@ -416,7 +416,7 @@ impl<'db> InternedCoroutineId<'db> { } } -#[salsa_macros::interned(constructor = new_impl, debug, revisions = usize::MAX)] +#[salsa::interned(constructor = new_impl, debug, revisions = usize::MAX)] #[derive(PartialOrd, Ord)] pub struct InternedCoroutineClosureId<'db> { pub loc: InternedClosure<'db>, @@ -460,7 +460,7 @@ pub struct AnonConstLoc { pub(crate) allow_using_generic_params: bool, } -#[salsa_macros::interned(debug, revisions = usize::MAX, constructor = new_)] +#[salsa::interned(debug, revisions = usize::MAX, constructor = new_)] #[derive(PartialOrd, Ord)] pub struct AnonConstId { #[returns(ref)] @@ -530,7 +530,7 @@ impl<'db> AnonConstId<'db> { /// A constant, which might appears as a const item, an anonymous const block in expressions /// or patterns, or as a constant in types with const generics. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, salsa_macros::Supertype)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, salsa::Supertype)] pub enum GeneralConstId<'db> { ConstId(ConstId), StaticId(StaticId), diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout/target.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout/target.rs index cf92c18f8ccd8..4ff5eb7690624 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/layout/target.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout/target.rs @@ -6,7 +6,7 @@ use rustc_abi::{AddressSpace, AlignFromBytesError, TargetDataLayoutError}; use crate::db::HirDatabase; -#[salsa_macros::tracked(returns(as_ref))] +#[salsa::tracked(returns(as_ref))] pub fn target_data_layout_query( db: &dyn HirDatabase, krate: Crate, 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 edc92b1e09989..35cddf109a8e4 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs @@ -1621,7 +1621,7 @@ pub enum TyDefId { } impl_from!(BuiltinType, AdtId(StructId, EnumId, UnionId), TypeAliasId for TyDefId); -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, salsa_macros::Supertype)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, salsa::Supertype)] pub enum ValueTyDefId { FunctionId(FunctionId), StructId(StructId), @@ -1681,7 +1681,7 @@ pub(crate) fn type_for_const<'db>( } /// Build the declared type of a const. -#[salsa_macros::tracked(returns(ref))] +#[salsa::tracked(returns(ref))] pub(crate) fn type_for_const_with_diagnostics<'db>( db: &'db dyn HirDatabase, def: ConstId, @@ -1713,7 +1713,7 @@ pub(crate) fn type_for_static<'db>( } /// Build the declared type of a static. -#[salsa_macros::tracked(returns(ref))] +#[salsa::tracked(returns(ref))] pub(crate) fn type_for_static_with_diagnostics<'db>( db: &'db dyn HirDatabase, def: StaticId, @@ -2736,7 +2736,7 @@ pub(crate) fn generic_defaults(db: &dyn HirDatabase, def: GenericDefId) -> Gener /// Resolve the default type params from generics. /// /// Diagnostics are only returned for this `GenericDefId` (returned defaults include parents). -#[salsa_macros::tracked(returns(ref), cycle_result = generic_defaults_with_diagnostics_cycle_result)] +#[salsa::tracked(returns(ref), cycle_result = generic_defaults_with_diagnostics_cycle_result)] pub(crate) fn generic_defaults_with_diagnostics<'db>( db: &'db dyn HirDatabase, def: GenericDefId, 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 3a0fe6e2495ff..ed7279790c548 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 @@ -2124,7 +2124,7 @@ fn cast_kind<'db>( }) } -#[salsa_macros::tracked(returns(as_ref), cycle_result = mir_body_for_closure_cycle_result)] +#[salsa::tracked(returns(as_ref), cycle_result = mir_body_for_closure_cycle_result)] pub fn mir_body_for_closure_query<'db>( db: &'db dyn HirDatabase, closure: InternedClosureId<'db>, @@ -2283,7 +2283,7 @@ pub fn mir_body_for_closure_query<'db>( Ok(ctx.result) } -#[salsa_macros::tracked(returns(as_ref), cycle_result = mir_body_cycle_result)] +#[salsa::tracked(returns(as_ref), cycle_result = mir_body_cycle_result)] pub fn mir_body_query<'db>( db: &'db dyn HirDatabase, def: InferBodyId<'db>, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/monomorphization.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/monomorphization.rs index 042dd076be75b..93d1aa515a99c 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/monomorphization.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/monomorphization.rs @@ -238,7 +238,7 @@ impl<'db> Filler<'db> { } } -#[salsa_macros::tracked(returns(as_ref), cycle_result = monomorphized_mir_body_cycle_result)] +#[salsa::tracked(returns(as_ref), cycle_result = monomorphized_mir_body_cycle_result)] pub fn monomorphized_mir_body_query<'db>( db: &'db dyn HirDatabase, owner: InferBodyId<'db>, @@ -262,7 +262,7 @@ fn monomorphized_mir_body_cycle_result<'db>( Err(MirLowerError::Loop) } -#[salsa_macros::tracked(returns(as_ref), cycle_result = monomorphized_mir_body_for_closure_cycle_result)] +#[salsa::tracked(returns(as_ref), cycle_result = monomorphized_mir_body_for_closure_cycle_result)] pub fn monomorphized_mir_body_for_closure_query<'db>( db: &'db dyn HirDatabase, closure: InternedClosureId<'db>, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/test_db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/test_db.rs index 7bf22b93f7753..59fda51781d21 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/test_db.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/test_db.rs @@ -16,7 +16,7 @@ use syntax::TextRange; use test_utils::extract_annotations; use triomphe::Arc; -#[salsa_macros::db] +#[salsa::db] pub(crate) struct TestDB { storage: salsa::Storage, files: Arc, @@ -75,7 +75,7 @@ impl fmt::Debug for TestDB { } } -#[salsa_macros::db] +#[salsa::db] impl SourceDatabase for TestDB { fn file_text(&self, file_id: base_db::FileId) -> FileText { self.files.file_text(file_id) @@ -138,7 +138,7 @@ impl SourceDatabase for TestDB { } } -#[salsa_macros::db] +#[salsa::db] impl salsa::Database for TestDB {} impl panic::RefUnwindSafe for TestDB {} 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 c6b4d28169fe3..930cb993e1d3a 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/lib.rs @@ -78,7 +78,7 @@ pub use span::{self, FileId}; pub type FilePosition = FilePositionWrapper; pub type FileRange = FileRangeWrapper; -#[salsa_macros::db] +#[salsa::db] pub struct RootDatabase { // FIXME: Revisit this commit now that we migrated to the new salsa, given we store arcs in this // db directly now @@ -94,7 +94,7 @@ pub struct RootDatabase { impl std::panic::RefUnwindSafe for RootDatabase {} -#[salsa_macros::db] +#[salsa::db] impl salsa::Database for RootDatabase {} impl Drop for RootDatabase { @@ -120,7 +120,7 @@ impl fmt::Debug for RootDatabase { } } -#[salsa_macros::db] +#[salsa::db] impl SourceDatabase for RootDatabase { fn file_text(&self, file_id: vfs::FileId) -> FileText { self.files.file_text(file_id) From 6756f203bd16f95cfabffcd929279a27ffcf0af9 Mon Sep 17 00:00:00 2001 From: Ada Alakbarova Date: Wed, 22 Jul 2026 10:24:07 +0200 Subject: [PATCH 36/76] remove the no longer needed `salsa-macros` deps --- src/tools/rust-analyzer/crates/hir-def/Cargo.toml | 1 - src/tools/rust-analyzer/crates/hir-expand/Cargo.toml | 1 - src/tools/rust-analyzer/crates/hir-ty/Cargo.toml | 1 - src/tools/rust-analyzer/crates/ide-db/Cargo.toml | 1 - 4 files changed, 4 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-def/Cargo.toml b/src/tools/rust-analyzer/crates/hir-def/Cargo.toml index b5e519695018a..eb1e774b8f41b 100644 --- a/src/tools/rust-analyzer/crates/hir-def/Cargo.toml +++ b/src/tools/rust-analyzer/crates/hir-def/Cargo.toml @@ -28,7 +28,6 @@ smallvec.workspace = true triomphe.workspace = true rustc_apfloat = "0.2.3" salsa.workspace = true -salsa-macros.workspace = true ra-ap-rustc_parse_format.workspace = true ra-ap-rustc_abi.workspace = true diff --git a/src/tools/rust-analyzer/crates/hir-expand/Cargo.toml b/src/tools/rust-analyzer/crates/hir-expand/Cargo.toml index 9af75a0d8a6c1..fe41d093606e6 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/Cargo.toml +++ b/src/tools/rust-analyzer/crates/hir-expand/Cargo.toml @@ -21,7 +21,6 @@ itertools.workspace = true smallvec.workspace = true triomphe.workspace = true salsa.workspace = true -salsa-macros.workspace = true thin-vec.workspace = true # local deps diff --git a/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml b/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml index 7c5ad21bc714f..c55ad5bacfe95 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml +++ b/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml @@ -30,7 +30,6 @@ typed-arena = "2.0.2" indexmap.workspace = true rustc_apfloat = "0.2.3" salsa.workspace = true -salsa-macros.workspace = true petgraph.workspace = true bitflags.workspace = true diff --git a/src/tools/rust-analyzer/crates/ide-db/Cargo.toml b/src/tools/rust-analyzer/crates/ide-db/Cargo.toml index 2c0919a183709..501579277bbd5 100644 --- a/src/tools/rust-analyzer/crates/ide-db/Cargo.toml +++ b/src/tools/rust-analyzer/crates/ide-db/Cargo.toml @@ -24,7 +24,6 @@ itertools.workspace = true arrayvec.workspace = true memchr = "2.7.5" salsa.workspace = true -salsa-macros.workspace = true triomphe.workspace = true nohash-hasher.workspace = true bitflags.workspace = true From 38efdf32fbff4971d8834a361ed2afddf9ae1250 Mon Sep 17 00:00:00 2001 From: Wilfred Hughes Date: Wed, 22 Jul 2026 14:10:56 +0100 Subject: [PATCH 37/76] fix: no_such_field should ignore non-editable crates no_such_field offers a fix where the struct is defined, but if that crate isn't editable, we shouldn't offer the assist. AI disclosure: Written with help by GPT-5.6. --- .../src/handlers/no_such_field.rs | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs index f6fe83177fba9..6fb8702c53eb7 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs @@ -1,7 +1,9 @@ use either::Either; use hir::{HasSource, HirDisplay, Semantics, VariantId}; use ide_db::text_edit::TextEdit; -use ide_db::{EditionedFileId, RootDatabase, source_change::SourceChange}; +use ide_db::{ + EditionedFileId, RootDatabase, helpers::is_editable_crate, source_change::SourceChange, +}; use syntax::{ AstNode, ast::{self, edit::IndentLevel, make}, @@ -87,6 +89,10 @@ fn missing_record_expr_field_fixes( }; let def_file_id = def_file_id.original_file(sema.db); + if !is_editable_crate(module.krate(sema.db), sema.db) { + return None; + } + let new_field_type = sema.type_of_expr(&record_expr_field.expr()?)?.adjusted(); if new_field_type.is_unknown() { return None; @@ -449,6 +455,18 @@ fn main() { ) } + #[test] + fn no_such_field_no_fix_for_struct_in_library_crate() { + check_no_fix( + r#" +//- /lib.rs crate:lib new_source_root:library +pub struct S { pub a: i32 } +//- /main.rs crate:main deps:lib new_source_root:local +fn f() { let _ = lib::S { a: 1, b$0: false }; } +"#, + ) + } + #[test] fn test_struct_field_private() { check_diagnostics( From 6ac189d53603ba74c18e5577151d1b28a04d9b35 Mon Sep 17 00:00:00 2001 From: Wilfred Hughes Date: Wed, 22 Jul 2026 14:11:42 +0100 Subject: [PATCH 38/76] fix: no_such_field panic with macros The no_such_field assist offers to add a field to a struct definition when the user write a struct literal `Foo { no_such_field_yet: 1 }`. However, if the struct is defined in a macro, we would look for the struct definition using the offset computed from the expansion. This produced changes at the wrong offset in the file. It also caused "invalid offset" panics if the file with the definition site of the macro was bigger than the file with the call site of the macro. Instead, map the macro position back to the relevant source file position. AI disclosure: Written with help by GPT-5.6. --- .../src/handlers/no_such_field.rs | 89 ++++++++++++++++++- 1 file changed, 85 insertions(+), 4 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs index 6fb8702c53eb7..e3364c1a3785a 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs @@ -1,11 +1,11 @@ use either::Either; -use hir::{HasSource, HirDisplay, Semantics, VariantId}; +use hir::{HasSource, HirDisplay, InMacroFile, Semantics, VariantId}; use ide_db::text_edit::TextEdit; use ide_db::{ EditionedFileId, RootDatabase, helpers::is_editable_crate, source_change::SourceChange, }; use syntax::{ - AstNode, + AstNode, TextSize, ast::{self, edit::IndentLevel, make}, }; @@ -87,7 +87,6 @@ fn missing_record_expr_field_fixes( record_field_list(fields)? } }; - let def_file_id = def_file_id.original_file(sema.db); if !is_editable_crate(module.krate(sema.db), sema.db) { return None; @@ -103,13 +102,19 @@ fn missing_record_expr_field_fixes( make::ty(&new_field_type.display_source_code(sema.db, module.into(), true).ok()?), ); - let (indent, offset, postfix, needs_comma) = + let (mut indent, offset, postfix, needs_comma) = if let Some(last_field) = record_fields.fields().last() { let indent = IndentLevel::from_node(last_field.syntax()); let offset = last_field.syntax().text_range().end(); let needs_comma = !last_field.to_string().ends_with(','); (indent, offset, String::new(), needs_comma) } else { + // We don't have enough whitespace information in a macro-defined empty struct + // to compute the correct indent. + if def_file_id.is_macro() { + return None; + } + let indent = IndentLevel::from_node(record_fields.syntax()); let offset = record_fields.l_curly_token()?.text_range().end(); let postfix = if record_fields.syntax().text().contains_char('\n') { @@ -119,6 +124,20 @@ fn missing_record_expr_field_fixes( }; (indent + 1, offset, postfix, false) }; + let (def_file_id, offset) = if let Some(macro_file) = def_file_id.macro_file() { + // Map the preceding token so the source insertion uses the end of that token. + let (range, _) = + InMacroFile::new(macro_file, offset - TextSize::new(1)).original_file_range(sema.db); + let anchor = sema + .parse(range.file_id) + .syntax() + .token_at_offset(range.range.start()) + .right_biased()?; + indent = IndentLevel::from_token(&anchor); + (range.file_id, range.range.end()) + } else { + (def_file_id.file_id()?, offset) + }; let mut new_field = new_field.to_string(); // FIXME: check submodule instead of FileId @@ -455,6 +474,68 @@ fn main() { ) } + #[test] + fn test_add_field_macro_defined_struct() { + check_fix( + r#" +macro_rules! identity { ($($t:tt)*) => { $($t)* }; } +identity! { + struct S { + a: i32 + } +} +fn f() { let _ = S { a: 1, b$0: false }; } +"#, + r#" +macro_rules! identity { ($($t:tt)*) => { $($t)* }; } +identity! { + struct S { + a: i32, + b: bool + } +} +fn f() { let _ = S { a: 1, b: false }; } +"#, + ); + } + + #[test] + fn test_add_field_macro_defined_struct_large_offset() { + // Regression test: we should handle macro definitions whose offset is larger than + // the max position in main.rs. + check_fix( + r#" +//- /main.rs +#[macro_use] +mod m; +make_items!(); +fn f() { let _ = S { a: 1, bbb$0: 2 }; } +//- /m.rs +macro_rules! make_items { + () => { + pub struct Padding { + pub p0: i32, pub p1: i32, pub p2: i32, + pub p3: i32, pub p4: i32, pub p5: i32, + } + pub struct S { pub a: i32 } + }; +} +"#, + r#" +macro_rules! make_items { + () => { + pub struct Padding { + pub p0: i32, pub p1: i32, pub p2: i32, + pub p3: i32, pub p4: i32, pub p5: i32, + } + pub struct S { pub a: i32, + pub(crate) bbb: i32 } + }; +} +"#, + ) + } + #[test] fn no_such_field_no_fix_for_struct_in_library_crate() { check_no_fix( From c5a5964d30c024f6b64e809042e40eedd2ad5118 Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Thu, 23 Jul 2026 04:02:14 +0800 Subject: [PATCH 39/76] Use token-based implements --- .../src/handlers/no_such_field.rs | 63 +++++++------------ 1 file changed, 21 insertions(+), 42 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs index e3364c1a3785a..cc900808b5bc5 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs @@ -1,11 +1,11 @@ use either::Either; -use hir::{HasSource, HirDisplay, InMacroFile, Semantics, VariantId}; +use hir::{HasSource, HirDisplay, InFile, Semantics, VariantId}; use ide_db::text_edit::TextEdit; use ide_db::{ EditionedFileId, RootDatabase, helpers::is_editable_crate, source_change::SourceChange, }; use syntax::{ - AstNode, TextSize, + AstNode, ast::{self, edit::IndentLevel, make}, }; @@ -102,56 +102,35 @@ fn missing_record_expr_field_fixes( make::ty(&new_field_type.display_source_code(sema.db, module.into(), true).ok()?), ); - let (mut indent, offset, postfix, needs_comma) = - if let Some(last_field) = record_fields.fields().last() { - let indent = IndentLevel::from_node(last_field.syntax()); - let offset = last_field.syntax().text_range().end(); - let needs_comma = !last_field.to_string().ends_with(','); - (indent, offset, String::new(), needs_comma) - } else { - // We don't have enough whitespace information in a macro-defined empty struct - // to compute the correct indent. - if def_file_id.is_macro() { - return None; - } - - let indent = IndentLevel::from_node(record_fields.syntax()); - let offset = record_fields.l_curly_token()?.text_range().end(); - let postfix = if record_fields.syntax().text().contains_char('\n') { - ",".into() - } else { - format!(",\n{indent}") - }; - (indent + 1, offset, postfix, false) - }; - let (def_file_id, offset) = if let Some(macro_file) = def_file_id.macro_file() { - // Map the preceding token so the source insertion uses the end of that token. - let (range, _) = - InMacroFile::new(macro_file, offset - TextSize::new(1)).original_file_range(sema.db); - let anchor = sema - .parse(range.file_id) - .syntax() - .token_at_offset(range.range.start()) - .right_biased()?; - indent = IndentLevel::from_token(&anchor); - (range.file_id, range.range.end()) + let after = if let Some(last_field) = record_fields.fields().last() { + last_field.syntax().last_token()? } else { - (def_file_id.file_id()?, offset) + record_fields.l_curly_token()? + }; + let hir::FileRange { file_id, range } = + InFile::new(def_file_id, after.text_range()).original_node_file_range_opt(sema.db)?.0; + let origin = sema.parse(file_id).syntax().covering_element(range); + let indent = IndentLevel::from_element(&origin); + + let (comma, indent, postfix) = match after.kind() { + syntax::SyntaxKind::L_CURLY => { + let newline = !after.next_token().is_some_and(|it| it.text().contains('\n')); + ("", indent + 1, if newline { format!(",\n{indent}") } else { ",".into() }) + } + _ => (",", indent, String::new()), }; - let mut new_field = new_field.to_string(); // FIXME: check submodule instead of FileId - let vis = if usage_file_id != def_file_id && !matches!(def_id, hir::Variant::EnumVariant(_)) { + let vis = if usage_file_id != file_id && !matches!(def_id, hir::Variant::EnumVariant(_)) { "pub(crate) " } else { "" }; - let comma = if needs_comma { "," } else { "" }; - new_field = format!("{comma}\n{indent}{vis}{new_field}{postfix}"); + let new_field = format!("{comma}\n{indent}{vis}{new_field}{postfix}"); let source_change = SourceChange::from_text_edit( - def_file_id.file_id(sema.db), - TextEdit::insert(offset, new_field), + file_id.file_id(sema.db), + TextEdit::insert(range.end(), new_field), ); return Some(vec![fix( From e2e925856fdaf0059118ef58c47a44cd251bc5f2 Mon Sep 17 00:00:00 2001 From: Wilfred Hughes Date: Wed, 22 Jul 2026 20:16:34 +0100 Subject: [PATCH 40/76] fix: merge_imports panic on invalid paths When computing code actions, rust-analyzer would previously panic if a path had malformed segments. We already fixed empty path segments in 343d5ff383, which is the most frequent case, but I've seen crashes with malformed paths too (most commonly a trailing `:` or `#`). Ensure that handle invalid path segments too, and add a test. AI disclosure: Code partly written by GPT-5.6 Sol --- .../crates/ide-assists/src/handlers/merge_imports.rs | 11 +++++++++++ .../crates/ide-db/src/imports/merge_imports.rs | 4 +++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_imports.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_imports.rs index 2d3b1b05400c3..a4edb556d4577 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_imports.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_imports.rs @@ -835,6 +835,17 @@ use top::{a::A, b::{B as D, B as C}}; r" use foo::bar; use foo::$0; +", + ); + } + + #[test] + fn test_merge_with_malformed_colon_path_segment() { + check_assist_not_applicable( + merge_imports, + r" +use foo::bar; +use foo::$0:; ", ); } diff --git a/src/tools/rust-analyzer/crates/ide-db/src/imports/merge_imports.rs b/src/tools/rust-analyzer/crates/ide-db/src/imports/merge_imports.rs index 17fae61da6131..59099056f5c5b 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/imports/merge_imports.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/imports/merge_imports.rs @@ -828,7 +828,9 @@ fn split_prefix( } } else { let suffix_segments: Vec<_> = path.segments().skip(prefix.segments().count()).collect(); - if suffix_segments.is_empty() { + if suffix_segments.is_empty() + || suffix_segments.iter().any(|segment| segment.kind().is_none()) + { return None; } let suffix_path = make.path_from_segments(suffix_segments, false); From 49a5d6da34e8840bbf6436e089051c63fdd4b672 Mon Sep 17 00:00:00 2001 From: Amirhossein Akhlaghpour Date: Thu, 23 Jul 2026 16:04:48 +0330 Subject: [PATCH 41/76] fix: lowering of resolved const inference variables Signed-off-by: Amirhossein Akhlaghpour --- compiler/rustc_infer/src/infer/context.rs | 5 ++- .../src/canonical/mod.rs | 8 ++-- ...er-universe-resolved-const-issue-159703.rs | 19 +++++++++ ...niverse-resolved-const-issue-159703.stderr | 40 +++++++++++++++++++ 4 files changed, 66 insertions(+), 6 deletions(-) create mode 100644 tests/ui/traits/next-solver/lower-universe-resolved-const-issue-159703.rs create mode 100644 tests/ui/traits/next-solver/lower-universe-resolved-const-issue-159703.stderr diff --git a/compiler/rustc_infer/src/infer/context.rs b/compiler/rustc_infer/src/infer/context.rs index d1d864246b9ff..9d5b51491e5e6 100644 --- a/compiler/rustc_infer/src/infer/context.rs +++ b/compiler/rustc_infer/src/infer/context.rs @@ -521,7 +521,10 @@ impl<'a, 'tcx> ty::TypeFolder> for LowerUniverseFolder<'a, 'tcx> { match c.kind() { ty::ConstKind::Infer(ty::InferConst::Var(vid)) => { let vid = self.infcx.root_const_var(vid); - let universe = self.infcx.try_resolve_const_var(vid).unwrap_err(); + let universe = match self.infcx.try_resolve_const_var(vid) { + Ok(value) => return value.fold_with(self), + Err(universe) => universe, + }; if self.for_universe.can_name(universe) { c } else { diff --git a/compiler/rustc_next_trait_solver/src/canonical/mod.rs b/compiler/rustc_next_trait_solver/src/canonical/mod.rs index f325862102318..2adb6a19cb6c3 100644 --- a/compiler/rustc_next_trait_solver/src/canonical/mod.rs +++ b/compiler/rustc_next_trait_solver/src/canonical/mod.rs @@ -392,12 +392,10 @@ where } let infcx = self.infcx; - // FIXME: make this a debug_assert. - // Currently proof tree evaluation can unify infer vars in original - // vars while not resolving them. - // See `tests/ui/traits/next-solver/transmute-from-async-closure.rs` + // Proof tree evaluation can unify inference variables in the original + // values without eagerly resolving them. let a = infcx.shallow_resolve_const(a); - debug_assert_eq!(b, infcx.shallow_resolve_const(b)); + let b = infcx.shallow_resolve_const(b); match (a.kind(), b.kind()) { ( ty::ConstKind::Infer(ty::InferConst::Var(a_vid)), diff --git a/tests/ui/traits/next-solver/lower-universe-resolved-const-issue-159703.rs b/tests/ui/traits/next-solver/lower-universe-resolved-const-issue-159703.rs new file mode 100644 index 0000000000000..56aff9211f789 --- /dev/null +++ b/tests/ui/traits/next-solver/lower-universe-resolved-const-issue-159703.rs @@ -0,0 +1,19 @@ +//@ compile-flags: -Znext-solver=globally +//@ edition: 2015 + +#![allow(bare_trait_objects)] + +trait Foo {} + +struct BarType; + +impl Foo for BarType {} +//~^ ERROR missing generics for struct `BarType` + +fn a(x: &Foo) { + let bar = BarType; + a(bar); + //~^ ERROR mismatched types +} + +fn main() {} diff --git a/tests/ui/traits/next-solver/lower-universe-resolved-const-issue-159703.stderr b/tests/ui/traits/next-solver/lower-universe-resolved-const-issue-159703.stderr new file mode 100644 index 0000000000000..3324d2a037c22 --- /dev/null +++ b/tests/ui/traits/next-solver/lower-universe-resolved-const-issue-159703.stderr @@ -0,0 +1,40 @@ +error[E0107]: missing generics for struct `BarType` + --> $DIR/lower-universe-resolved-const-issue-159703.rs:10:30 + | +LL | impl Foo for BarType {} + | ^^^^^^^ expected 1 generic argument + | +note: struct defined here, with 1 generic parameter: `N` + --> $DIR/lower-universe-resolved-const-issue-159703.rs:8:8 + | +LL | struct BarType; + | ^^^^^^^ -------------- +help: add missing generic argument + | +LL | impl Foo for BarType {} + | +++ + +error[E0308]: mismatched types + --> $DIR/lower-universe-resolved-const-issue-159703.rs:15:7 + | +LL | a(bar); + | - ^^^ expected `&dyn Foo`, found `BarType<_>` + | | + | arguments to this function are incorrect + | + = note: expected reference `&dyn Foo` + found struct `BarType<_>` +note: function defined here + --> $DIR/lower-universe-resolved-const-issue-159703.rs:13:4 + | +LL | fn a(x: &Foo) { + | ^ ------- +help: consider borrowing here + | +LL | a(&bar); + | + + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0107, E0308. +For more information about an error, try `rustc --explain E0107`. From ae29b3762ba170691e76c187fe852254571bf68c Mon Sep 17 00:00:00 2001 From: Abhinav Srivastav Date: Mon, 6 Jul 2026 23:05:52 +0530 Subject: [PATCH 42/76] bootstrap: pass /Brepro to MSVC linker when building rustc --- src/bootstrap/src/core/build_steps/compile.rs | 8 ++ .../run-make/brepro-msvc-determinism/main.rs | 3 + .../run-make/brepro-msvc-determinism/rmake.rs | 73 +++++++++++++++++++ 3 files changed, 84 insertions(+) create mode 100644 tests/run-make/brepro-msvc-determinism/main.rs create mode 100644 tests/run-make/brepro-msvc-determinism/rmake.rs diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 68a4f928464f1..c1b2c8e041d75 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -1248,6 +1248,14 @@ pub fn rustc_cargo( // . cargo.rustflag("-Zon-broken-pipe=kill"); + // /Brepro tells the MSVC linker to omit non-deterministic COFF data + // (namely the PE timestamp) from the produced binary. Only applied when + // building rustc itself via bootstrap. See discussion: + // https://github.com/rust-lang/rust/pull/158873 + if target.is_msvc() { + cargo.rustflag("-Clink-arg=/Brepro"); + } + // Building with protected visibility reduces the number of dynamic relocations needed, giving // us a faster startup time. However GNU ld < 2.40 will error if we try to link a shared object // with direct references to protected symbols, so for now we only use protected symbols if diff --git a/tests/run-make/brepro-msvc-determinism/main.rs b/tests/run-make/brepro-msvc-determinism/main.rs new file mode 100644 index 0000000000000..31610b59e57d4 --- /dev/null +++ b/tests/run-make/brepro-msvc-determinism/main.rs @@ -0,0 +1,3 @@ +fn main() { + println!("brepro"); +} diff --git a/tests/run-make/brepro-msvc-determinism/rmake.rs b/tests/run-make/brepro-msvc-determinism/rmake.rs new file mode 100644 index 0000000000000..a6562fec541d6 --- /dev/null +++ b/tests/run-make/brepro-msvc-determinism/rmake.rs @@ -0,0 +1,73 @@ +use std::path::PathBuf; + +use object::pod::slice_from_all_bytes; +use object::read::pe::{ImageNtHeaders, PeFile, PeFile32, PeFile64}; +use object::{FileKind, Object, pe}; +use run_make_support::{bin_name, is_windows_msvc, object, rfs, rustc}; + +// Returns the TimeDateStamp values from every IMAGE_DEBUG_DIRECTORY entry +// in a parsed PE image. +// Shared by both PE32 and PE32+ binaries. +fn timestamps(obj: &PeFile<'_, Pe>) -> Vec { + let data_dir = + obj.data_directory(pe::IMAGE_DIRECTORY_ENTRY_DEBUG).expect("no debug directory found"); + + let debug_data = + data_dir.data(obj.data(), &obj.section_table()).expect("failed to read debug directory"); + + let debug_dirs = slice_from_all_bytes::(debug_data) + .expect("invalid IMAGE_DEBUG_DIRECTORY"); + + let mut stamps = Vec::new(); + + // COFF file header TimeDateStamp. + stamps.push(obj.nt_headers().file_header().time_date_stamp.get(object::LittleEndian)); + + // IMAGE_DEBUG_DIRECTORY TimeDateStamp values. + stamps.extend(debug_dirs.iter().map(|d| d.time_date_stamp.get(object::LittleEndian))); + + stamps +} + +fn main() { + if !is_windows_msvc() { + return; + } + + // Compile the test crate and collect the + // IMAGE_DEBUG_DIRECTORY timestamps from the resulting executable. + let build = || -> Vec { + rustc().input("main.rs").arg("-Clink-arg=/Brepro").output(bin_name("brepro-test")).run(); + + let bytes = rfs::read(bin_name("brepro-test")); + + // Parse the generated executable according to its PE format so the + // test works for both 32-bit and 64-bit MSVC targets. + match FileKind::parse(bytes.as_slice()).unwrap() { + FileKind::Pe32 => { + let obj = PeFile32::parse(bytes.as_slice()).unwrap(); + timestamps(&obj) + } + FileKind::Pe64 => { + let obj = PeFile64::parse(bytes.as_slice()).unwrap(); + timestamps(&obj) + } + kind => panic!("unexpected file kind: {kind:?}"), + } + }; + + // First build. + let stamps_a = build(); + + // Remove the generated PDB so the second build starts fresh. + rfs::remove_file(PathBuf::from(bin_name("brepro-test")).with_extension("pdb")); + + // Second build. + let stamps_b = build(); + + assert!(!stamps_a.is_empty(), "no IMAGE_DEBUG_DIRECTORY entries found"); + + // /Brepro should make the linker emit deterministic timestamps across + // identical builds. + assert_eq!(stamps_a, stamps_b, "TimeDateStamp differs between identical builds"); +} From 8768e748117a3d45ef12771993eea3fa2b78ae38 Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Fri, 24 Jul 2026 11:25:55 +0800 Subject: [PATCH 43/76] fix: uses bool instead pat ty in guard Example --- ```rust enum E { V } fn foo() { match E::V { _ if a$0 => {} } } ``` **Before this PR** ```rust ty: E, name: ? ``` **After this PR** ```rust ty: bool, name: ? ``` --- .../crates/ide-completion/src/context/analysis.rs | 4 ++++ .../crates/ide-completion/src/context/tests.rs | 15 +++++++++++++++ 2 files changed, 19 insertions(+) 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 b2ee94d49cbfe..b06f52c113459 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 @@ -794,6 +794,10 @@ fn expected_type_and_name<'db>( }.map(TypeInfo::original); (ty, None) }, + ast::MatchGuard(it) => { + let ty = it.condition().and_then(|e| sema.type_of_expr(&e)).map(TypeInfo::original); + (ty, None) + }, ast::IdentPat(it) => { cov_mark::hit!(expected_type_if_let_with_leading_char); cov_mark::hit!(expected_type_match_arm_with_leading_char); 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 1d1a55c6fe144..c5fba82de4802 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 @@ -409,6 +409,21 @@ fn foo() { ); } +#[test] +fn expected_type_guard_condition() { + check_expected_type_and_name( + r#" +enum E { V } +fn foo() { + match E::V { + _ if a$0 => {} + } +} +"#, + expect![[r#"ty: bool, name: ?"#]], + ); +} + #[test] fn expected_type_if_body() { check_expected_type_and_name( From d05f397c2b5c96adb7c4777c8af665d637649660 Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Fri, 24 Jul 2026 12:40:05 +0800 Subject: [PATCH 44/76] fix: add parentheses for invert general expression Example --- ```rust fn f() { i$0f cond as bool { 3 * 2 } else { 1 } } ``` **Before this PR** ```rust fn f() { if !cond { 1 } else { 3 * 2 } } ``` **After this PR** ```rust fn f() { if !(cond as bool) { 1 } else { 3 * 2 } } ``` --- .../crates/ide-assists/src/handlers/invert_if.rs | 9 +++++++++ src/tools/rust-analyzer/crates/ide-assists/src/utils.rs | 4 +++- 2 files changed, 12 insertions(+), 1 deletion(-) 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 9dda4bbb966b6..f50ccc3e1136d 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 @@ -114,6 +114,15 @@ mod tests { ) } + #[test] + fn invert_if_general_case_needs_paren() { + check_assist( + invert_if, + "fn f() { i$0f cond as bool { 3 * 2 } else { 1 } }", + "fn f() { if !(cond as bool) { 1 } else { 3 * 2 } }", + ) + } + #[test] fn invert_if_on_else_keyword() { check_assist( 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 344beb32ae0e9..670a030255cfc 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs @@ -303,7 +303,9 @@ pub(crate) fn vis_offset(node: &SyntaxNode) -> TextSize { } pub(crate) fn invert_boolean_expression(make: &SyntaxFactory, expr: ast::Expr) -> ast::Expr { - invert_special_case(make, &expr).unwrap_or_else(|| make.expr_prefix(T![!], expr).into()) + invert_special_case(make, &expr).unwrap_or_else(|| { + make.expr_prefix(T![!], wrap_paren(expr, make, ExprPrecedence::Prefix)).into() + }) } fn invert_special_case(make: &SyntaxFactory, expr: &ast::Expr) -> Option { From 59510056b79567514b5ec9c3418a923145298871 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 10 Jul 2026 15:37:49 +0200 Subject: [PATCH 45/76] Introduce types module for types shared between libunwind and wasm --- library/unwind/src/lib.rs | 2 ++ library/unwind/src/libunwind.rs | 57 +------------------------------ library/unwind/src/types.rs | 59 +++++++++++++++++++++++++++++++++ library/unwind/src/wasm.rs | 31 +---------------- 4 files changed, 63 insertions(+), 86 deletions(-) create mode 100644 library/unwind/src/types.rs diff --git a/library/unwind/src/lib.rs b/library/unwind/src/lib.rs index dce3ea8c7e007..3725375a713dc 100644 --- a/library/unwind/src/lib.rs +++ b/library/unwind/src/lib.rs @@ -37,8 +37,10 @@ cfg_select! { ) => { mod libunwind; pub use libunwind::*; + mod types; } target_family = "wasm" => { + mod types; mod wasm; pub use wasm::*; } diff --git a/library/unwind/src/libunwind.rs b/library/unwind/src/libunwind.rs index aee03879dd0a6..9b5a6b4afc792 100644 --- a/library/unwind/src/libunwind.rs +++ b/library/unwind/src/libunwind.rs @@ -8,69 +8,14 @@ pub use unwinding::custom_eh_frame_finder::{ EhFrameFinder, FrameInfo, FrameInfoKind, set_custom_eh_frame_finder, }; -#[repr(C)] -#[derive(Debug, Copy, Clone, PartialEq)] -pub enum _Unwind_Reason_Code { - _URC_NO_REASON = 0, - _URC_FOREIGN_EXCEPTION_CAUGHT = 1, - _URC_FATAL_PHASE2_ERROR = 2, - _URC_FATAL_PHASE1_ERROR = 3, - _URC_NORMAL_STOP = 4, - _URC_END_OF_STACK = 5, - _URC_HANDLER_FOUND = 6, - _URC_INSTALL_CONTEXT = 7, - _URC_CONTINUE_UNWIND = 8, - _URC_FAILURE = 9, // used only by ARM EHABI -} -pub use _Unwind_Reason_Code::*; +pub use crate::types::*; -pub type _Unwind_Exception_Class = u64; -pub type _Unwind_Word = *const u8; pub type _Unwind_Ptr = *const u8; pub type _Unwind_Trace_Fn = extern "C" fn(ctx: *mut _Unwind_Context, arg: *mut c_void) -> _Unwind_Reason_Code; -pub const unwinder_private_data_size: usize = cfg_select! { - target_arch = "x86" => 5, - all(target_arch = "x86_64", not(any(target_os = "windows", target_os = "cygwin"))) => 2, - all(target_arch = "x86_64", any(target_os = "windows", target_os = "cygwin")) => 6, - all(target_arch = "arm", not(target_vendor = "apple")) => 20, - all(target_arch = "arm", target_vendor = "apple") => 5, - all(target_arch = "aarch64", target_pointer_width = "64", not(target_os = "windows")) => 2, - all(target_arch = "aarch64", target_pointer_width = "64", target_os = "windows") => 6, - all(target_arch = "aarch64", target_pointer_width = "32") => 5, - target_arch = "m68k" => 2, - any(target_arch = "mips", target_arch = "mips32r6") => 2, - target_arch = "csky" => 2, - any(target_arch = "mips64", target_arch = "mips64r6") => 2, - any(target_arch = "powerpc", target_arch = "powerpc64") => 2, - target_arch = "s390x" => 2, - any(target_arch = "sparc", target_arch = "sparc64") => 2, - any(target_arch = "riscv64", target_arch = "riscv32") => 2, - all(target_family = "wasm", target_os = "emscripten") => 20, - all(target_arch = "wasm32", any(target_os = "linux", target_os = "wasi")) => 2, - target_arch = "hexagon" => 5, - any(target_arch = "loongarch32", target_arch = "loongarch64") => 2, -}; - -#[repr(C)] -pub struct _Unwind_Exception { - pub exception_class: _Unwind_Exception_Class, - pub exception_cleanup: _Unwind_Exception_Cleanup_Fn, - pub private: [_Unwind_Word; unwinder_private_data_size], -} - -// Check the size of _Unwind_Exception against the source of thruth when using the unwinding crate. -#[cfg(target_os = "xous")] -const _: () = { - assert!(size_of::() == size_of::<_Unwind_Exception>()); -}; - pub enum _Unwind_Context {} -pub type _Unwind_Exception_Cleanup_Fn = - Option; - // FIXME: The `#[link]` attributes on `extern "C"` block marks those symbols declared in // the block are reexported in dylib build of std. This is needed when build rustc with // feature `llvm-libunwind`, as no other cdylib will provided those _Unwind_* symbols. diff --git a/library/unwind/src/types.rs b/library/unwind/src/types.rs new file mode 100644 index 0000000000000..413cd677fe7e0 --- /dev/null +++ b/library/unwind/src/types.rs @@ -0,0 +1,59 @@ +#![allow(nonstandard_style)] + +#[repr(C)] +#[derive(Debug, Copy, Clone, PartialEq)] +pub enum _Unwind_Reason_Code { + _URC_NO_REASON = 0, + _URC_FOREIGN_EXCEPTION_CAUGHT = 1, + _URC_FATAL_PHASE2_ERROR = 2, + _URC_FATAL_PHASE1_ERROR = 3, + _URC_NORMAL_STOP = 4, + _URC_END_OF_STACK = 5, + _URC_HANDLER_FOUND = 6, + _URC_INSTALL_CONTEXT = 7, + _URC_CONTINUE_UNWIND = 8, + _URC_FAILURE = 9, // used only by ARM EHABI +} +pub use _Unwind_Reason_Code::*; + +pub type _Unwind_Exception_Class = u64; +pub type _Unwind_Word = *const u8; + +pub const unwinder_private_data_size: usize = cfg_select! { + target_arch = "x86" => 5, + all(target_arch = "x86_64", not(any(target_os = "windows", target_os = "cygwin"))) => 2, + all(target_arch = "x86_64", any(target_os = "windows", target_os = "cygwin")) => 6, + all(target_arch = "arm", not(target_vendor = "apple")) => 20, + all(target_arch = "arm", target_vendor = "apple") => 5, + all(target_arch = "aarch64", target_pointer_width = "64", not(target_os = "windows")) => 2, + all(target_arch = "aarch64", target_pointer_width = "64", target_os = "windows") => 6, + all(target_arch = "aarch64", target_pointer_width = "32") => 5, + target_arch = "m68k" => 2, + any(target_arch = "mips", target_arch = "mips32r6") => 2, + target_arch = "csky" => 2, + any(target_arch = "mips64", target_arch = "mips64r6") => 2, + any(target_arch = "powerpc", target_arch = "powerpc64") => 2, + target_arch = "s390x" => 2, + any(target_arch = "sparc", target_arch = "sparc64") => 2, + any(target_arch = "riscv64", target_arch = "riscv32") => 2, + all(target_family = "wasm", target_os = "emscripten") => 20, + target_family = "wasm" => 2, + target_arch = "hexagon" => 5, + any(target_arch = "loongarch32", target_arch = "loongarch64") => 2, +}; + +#[repr(C)] +pub struct _Unwind_Exception { + pub exception_class: _Unwind_Exception_Class, + pub exception_cleanup: _Unwind_Exception_Cleanup_Fn, + pub private: [_Unwind_Word; unwinder_private_data_size], +} + +// Check the size of _Unwind_Exception against the source of truth when using the unwinding crate. +#[cfg(target_os = "xous")] +const _: () = { + assert!(size_of::() == size_of::<_Unwind_Exception>()); +}; + +pub type _Unwind_Exception_Cleanup_Fn = + Option; diff --git a/library/unwind/src/wasm.rs b/library/unwind/src/wasm.rs index 37d93bdbb67dd..ef961ae6410a4 100644 --- a/library/unwind/src/wasm.rs +++ b/library/unwind/src/wasm.rs @@ -26,36 +26,7 @@ core::arch::global_asm!( "__cpp_exception:", ); -#[repr(C)] -#[derive(Debug, Copy, Clone, PartialEq)] -pub enum _Unwind_Reason_Code { - _URC_NO_REASON = 0, - _URC_FOREIGN_EXCEPTION_CAUGHT = 1, - _URC_FATAL_PHASE2_ERROR = 2, - _URC_FATAL_PHASE1_ERROR = 3, - _URC_NORMAL_STOP = 4, - _URC_END_OF_STACK = 5, - _URC_HANDLER_FOUND = 6, - _URC_INSTALL_CONTEXT = 7, - _URC_CONTINUE_UNWIND = 8, - _URC_FAILURE = 9, // used only by ARM EHABI -} -pub use _Unwind_Reason_Code::*; - -pub type _Unwind_Exception_Class = u64; -pub type _Unwind_Word = *const u8; - -pub const unwinder_private_data_size: usize = 2; - -#[repr(C)] -pub struct _Unwind_Exception { - pub exception_class: _Unwind_Exception_Class, - pub exception_cleanup: _Unwind_Exception_Cleanup_Fn, - pub private: [_Unwind_Word; unwinder_private_data_size], -} - -pub type _Unwind_Exception_Cleanup_Fn = - Option; +pub use crate::types::*; pub unsafe fn _Unwind_DeleteException(exception: *mut _Unwind_Exception) { if let Some(exception_cleanup) = unsafe { (*exception).exception_cleanup } { From 46b319e95f5f21666b5390deaf03d5a573a5b02d Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 10 Jul 2026 16:07:04 +0200 Subject: [PATCH 46/76] Remove a cfg_select! where the api doesn't change --- library/unwind/src/libunwind.rs | 52 +++++++++++++++------------------ 1 file changed, 24 insertions(+), 28 deletions(-) diff --git a/library/unwind/src/libunwind.rs b/library/unwind/src/libunwind.rs index 9b5a6b4afc792..33ca95a1cf6f7 100644 --- a/library/unwind/src/libunwind.rs +++ b/library/unwind/src/libunwind.rs @@ -188,34 +188,30 @@ cfg_select! { } } -cfg_select! { - all(target_vendor = "apple", not(target_os = "watchos"), target_arch = "arm") => { - // 32-bit ARM Apple (except for watchOS armv7k specifically) uses SjLj and - // does not provide _Unwind_Backtrace() - unsafe extern "C-unwind" { - pub fn _Unwind_SjLj_RaiseException(e: *mut _Unwind_Exception) -> _Unwind_Reason_Code; - } - - pub use _Unwind_SjLj_RaiseException as _Unwind_RaiseException; - } - _ => { - #[cfg_attr( - all(feature = "llvm-libunwind", any(target_os = "fuchsia", target_os = "linux")), - link(name = "unwind", kind = "static", modifiers = "-bundle") - )] - unsafe extern "C-unwind" { - pub fn _Unwind_RaiseException(exception: *mut _Unwind_Exception) -> _Unwind_Reason_Code; - } - #[cfg_attr( - all(feature = "llvm-libunwind", any(target_os = "fuchsia", target_os = "linux")), - link(name = "unwind", kind = "static", modifiers = "-bundle") - )] - unsafe extern "C" { - pub fn _Unwind_Backtrace(trace: _Unwind_Trace_Fn, - trace_argument: *mut c_void) - -> _Unwind_Reason_Code; - } - } +#[cfg_attr( + all(feature = "llvm-libunwind", any(target_os = "fuchsia", target_os = "linux")), + link(name = "unwind", kind = "static", modifiers = "-bundle") +)] +unsafe extern "C-unwind" { + // 32-bit ARM Apple (except for watchOS armv7k specifically) uses SjLj + #[cfg_attr( + all(target_vendor = "apple", not(target_os = "watchos"), target_arch = "arm"), + link_name = "_Unwind_SjLj_RaiseException" + )] + pub fn _Unwind_RaiseException(exception: *mut _Unwind_Exception) -> _Unwind_Reason_Code; +} +#[cfg_attr( + all(feature = "llvm-libunwind", any(target_os = "fuchsia", target_os = "linux")), + link(name = "unwind", kind = "static", modifiers = "-bundle") +)] +unsafe extern "C" { + // 32-bit ARM Apple (except for watchOS armv7k specifically) does not + // provide _Unwind_Backtrace() + #[cfg(not(all(target_vendor = "apple", not(target_os = "watchos"), target_arch = "arm")))] + pub fn _Unwind_Backtrace( + trace: _Unwind_Trace_Fn, + trace_argument: *mut c_void, + ) -> _Unwind_Reason_Code; } cfg_select! { From f5260df9d61e89194708ce07dfbc5a1e5d24979d Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 19 Jul 2026 18:53:21 +0200 Subject: [PATCH 47/76] Remove aborting Emscripten personality function The wasm case below already handles this for us. --- library/std/src/sys/personality/emcc.rs | 21 --------------------- library/std/src/sys/personality/mod.rs | 3 --- 2 files changed, 24 deletions(-) delete mode 100644 library/std/src/sys/personality/emcc.rs diff --git a/library/std/src/sys/personality/emcc.rs b/library/std/src/sys/personality/emcc.rs deleted file mode 100644 index d374e3ad4c8f6..0000000000000 --- a/library/std/src/sys/personality/emcc.rs +++ /dev/null @@ -1,21 +0,0 @@ -//! On Emscripten Rust panics are wrapped in C++ exceptions, so we just forward -//! to `__gxx_personality_v0` which is provided by Emscripten. - -use unwind as uw; - -use crate::ffi::c_int; - -// This is required by the compiler to exist (e.g., it's a lang item), but it's -// never actually called by the compiler. Emscripten EH doesn't use a -// personality function at all, it instead uses __cxa_find_matching_catch. -// Wasm error handling would use __gxx_personality_wasm0. -#[lang = "eh_personality"] -unsafe extern "C" fn rust_eh_personality( - _version: c_int, - _actions: uw::_Unwind_Action, - _exception_class: uw::_Unwind_Exception_Class, - _exception_object: *mut uw::_Unwind_Exception, - _context: *mut uw::_Unwind_Context, -) -> uw::_Unwind_Reason_Code { - core::intrinsics::abort() -} diff --git a/library/std/src/sys/personality/mod.rs b/library/std/src/sys/personality/mod.rs index eabef92244d01..3b363aa2d024c 100644 --- a/library/std/src/sys/personality/mod.rs +++ b/library/std/src/sys/personality/mod.rs @@ -14,9 +14,6 @@ mod dwarf; #[cfg(not(any(test, doctest)))] cfg_select! { - target_os = "emscripten" => { - mod emcc; - } any(target_env = "msvc", target_family = "wasm", target_os = "motor") => { // This is required by the compiler to exist (e.g., it's a lang item), // but it's never actually called by the compiler because From 0ccc68e87968e5db50f30edc5a25124b93889cac Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 19 Jul 2026 18:50:14 +0200 Subject: [PATCH 48/76] Remove a bunch of unused bindings from the unwind crate --- library/unwind/src/libunwind.rs | 37 +++++---------------------------- 1 file changed, 5 insertions(+), 32 deletions(-) diff --git a/library/unwind/src/libunwind.rs b/library/unwind/src/libunwind.rs index 33ca95a1cf6f7..8e45e0cf543d3 100644 --- a/library/unwind/src/libunwind.rs +++ b/library/unwind/src/libunwind.rs @@ -11,8 +11,6 @@ pub use unwinding::custom_eh_frame_finder::{ pub use crate::types::*; pub type _Unwind_Ptr = *const u8; -pub type _Unwind_Trace_Fn = - extern "C" fn(ctx: *mut _Unwind_Context, arg: *mut c_void) -> _Unwind_Reason_Code; pub enum _Unwind_Context {} @@ -55,10 +53,10 @@ cfg_select! { pub type _Unwind_Action = c_int; pub const _UA_SEARCH_PHASE: c_int = 1; - pub const _UA_CLEANUP_PHASE: c_int = 2; - pub const _UA_HANDLER_FRAME: c_int = 4; + //pub const _UA_CLEANUP_PHASE: c_int = 2; + //pub const _UA_HANDLER_FRAME: c_int = 4; pub const _UA_FORCE_UNWIND: c_int = 8; - pub const _UA_END_OF_STACK: c_int = 16; + //pub const _UA_END_OF_STACK: c_int = 16; #[cfg_attr( all(feature = "llvm-libunwind", any(target_os = "fuchsia", target_os = "linux")), @@ -67,11 +65,9 @@ cfg_select! { unsafe extern "C" { pub fn _Unwind_GetGR(ctx: *mut _Unwind_Context, reg_index: c_int) -> _Unwind_Word; pub fn _Unwind_SetGR(ctx: *mut _Unwind_Context, reg_index: c_int, value: _Unwind_Word); - pub fn _Unwind_GetIP(ctx: *mut _Unwind_Context) -> _Unwind_Word; pub fn _Unwind_SetIP(ctx: *mut _Unwind_Context, value: _Unwind_Word); pub fn _Unwind_GetIPInfo(ctx: *mut _Unwind_Context, ip_before_insn: *mut c_int) -> _Unwind_Word; - pub fn _Unwind_FindEnclosingFunction(pc: *mut c_void) -> *mut c_void; } } @@ -158,12 +154,6 @@ cfg_select! { (&raw mut value) as *mut c_void); } } - pub unsafe fn _Unwind_GetIP(ctx: *mut _Unwind_Context) - -> _Unwind_Word { - let val = unsafe { _Unwind_GetGR(ctx, UNWIND_IP_REG) }; - val.map_addr(|v| v & !1) - } - pub unsafe fn _Unwind_SetIP(ctx: *mut _Unwind_Context, value: _Unwind_Word) { // Propagate thumb bit to instruction pointer @@ -177,14 +167,10 @@ cfg_select! { -> _Unwind_Word { unsafe { *ip_before_insn = 0; - _Unwind_GetIP(ctx) + let val = unsafe { _Unwind_GetGR(ctx, UNWIND_IP_REG) }; + val.map_addr(|v| v & !1) } } - - // This function also doesn't exist on Android or ARM/Linux, so make it a no-op - pub unsafe fn _Unwind_FindEnclosingFunction(pc: *mut c_void) -> *mut c_void { - pc - } } } @@ -200,19 +186,6 @@ unsafe extern "C-unwind" { )] pub fn _Unwind_RaiseException(exception: *mut _Unwind_Exception) -> _Unwind_Reason_Code; } -#[cfg_attr( - all(feature = "llvm-libunwind", any(target_os = "fuchsia", target_os = "linux")), - link(name = "unwind", kind = "static", modifiers = "-bundle") -)] -unsafe extern "C" { - // 32-bit ARM Apple (except for watchOS armv7k specifically) does not - // provide _Unwind_Backtrace() - #[cfg(not(all(target_vendor = "apple", not(target_os = "watchos"), target_arch = "arm")))] - pub fn _Unwind_Backtrace( - trace: _Unwind_Trace_Fn, - trace_argument: *mut c_void, - ) -> _Unwind_Reason_Code; -} cfg_select! { any( From 6936c08bb5ec89b349618735872e03752dcb9f54 Mon Sep 17 00:00:00 2001 From: Till Adam Date: Fri, 24 Jul 2026 19:33:23 +0200 Subject: [PATCH 49/76] fix: attach db on worker threads in parallel analysis-stats inference The next-generation trait solver stores the `HirDatabase` in a thread-local, set via `hir::attach_db`. `analysis-stats` attaches it once on the main thread, but the `--parallel` inference path runs `InferenceResult::of` on rayon worker threads that never attach it, so every parallel run panicked with "Try to use attached db, but not db is attached" at `next_solver/interner.rs`. Wrap the per-body inference in `hir::attach_db` so each worker has the database attached. Claude-Session: https://claude.ai/code/session_01RVkhEnTji2EUTKbwmQtJYR --- .../crates/rust-analyzer/src/cli/analysis_stats.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) 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 87790ce2bca17..79016921bfaaa 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 @@ -794,7 +794,9 @@ impl flags::AnalysisStats { bodies .par_iter() .map_with(db.clone(), |snap, &body| { - InferenceResult::of(snap, body); + hir::attach_db(snap, || { + InferenceResult::of(snap, body); + }); }) .count(); let _signatures = signatures From dd32b4f64ad8f09f2941886e9dac82236e832f90 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sat, 25 Jul 2026 10:45:53 +0200 Subject: [PATCH 50/76] Fix stale lock file --- src/tools/rust-analyzer/Cargo.lock | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock index 0e12d80b7e180..e02b9e157bc5f 100644 --- a/src/tools/rust-analyzer/Cargo.lock +++ b/src/tools/rust-analyzer/Cargo.lock @@ -863,7 +863,6 @@ dependencies = [ "rustc-hash 2.1.2", "rustc_apfloat", "salsa", - "salsa-macros", "smallvec", "span", "stdx", @@ -892,7 +891,6 @@ dependencies = [ "parser", "rustc-hash 2.1.2", "salsa", - "salsa-macros", "smallvec", "span", "stdx", @@ -934,7 +932,6 @@ dependencies = [ "rustc-hash 2.1.2", "rustc_apfloat", "salsa", - "salsa-macros", "serde", "serde_derive", "smallvec", @@ -1135,7 +1132,6 @@ dependencies = [ "rayon", "rustc-hash 2.1.2", "salsa", - "salsa-macros", "smallvec", "span", "stdx", From 1fbf6ff59ead42948f526825aea2f4a280d85e99 Mon Sep 17 00:00:00 2001 From: Till Adam Date: Sat, 13 Jun 2026 19:45:56 +0200 Subject: [PATCH 51/76] internal: scoped cache priming --- .../crates/ide-db/src/prime_caches.rs | 42 +++-- src/tools/rust-analyzer/crates/ide/src/lib.rs | 14 +- .../ide/src/syntax_highlighting/tests.rs | 2 +- .../crates/load-cargo/src/lib.rs | 3 +- .../crates/project-model/src/project_json.rs | 2 +- .../rust-analyzer/src/cli/prime_caches.rs | 3 +- .../crates/rust-analyzer/src/global_state.rs | 77 +++++++- .../crates/rust-analyzer/src/lib.rs | 1 + .../crates/rust-analyzer/src/main_loop.rs | 5 +- .../crates/rust-analyzer/src/priming_scope.rs | 166 ++++++++++++++++++ 10 files changed, 294 insertions(+), 21 deletions(-) create mode 100644 src/tools/rust-analyzer/crates/rust-analyzer/src/priming_scope.rs diff --git a/src/tools/rust-analyzer/crates/ide-db/src/prime_caches.rs b/src/tools/rust-analyzer/crates/ide-db/src/prime_caches.rs index fb7edb1acd2f2..518387514c887 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/prime_caches.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/prime_caches.rs @@ -4,9 +4,8 @@ //! various caches, it's not really advanced at the moment. use std::panic::AssertUnwindSafe; -use base_db::all_crates; use hir::{Symbol, import_map::ImportMap, sym}; -use rustc_hash::FxHashMap; +use rustc_hash::{FxHashMap, FxHashSet}; use salsa::{Cancelled, Database}; use crate::{FxIndexMap, RootDatabase, base_db::Crate, symbol_index::SymbolIndex}; @@ -23,12 +22,22 @@ pub struct ParallelPrimeCachesProgress { pub work_type: &'static str, } +/// Warm caches for `scope`. +/// +/// `scope` must be closed under transitive dependencies: the scheduler only +/// follows reverse-dep edges within `scope`. Out-of-scope crates can still be +/// primed by salsa on demand when a scope crate's queries reach into them. +/// Callers that want to prime everything pass `&all_crates(db)`. pub fn parallel_prime_caches( db: &RootDatabase, + scope: &[Crate], num_worker_threads: usize, cb: &(dyn Fn(ParallelPrimeCachesProgress) + Sync), ) { - let _p = tracing::info_span!("parallel_prime_caches").entered(); + if scope.is_empty() { + return; + } + let _p = tracing::info_span!("parallel_prime_caches", scope_size = scope.len()).entered(); enum ParallelPrimeCacheWorkerProgress { BeginCrateDefMap { crate_id: Crate, crate_name: Symbol }, @@ -52,17 +61,30 @@ pub fn parallel_prime_caches( // Such def map will just block on the dependency, which is just wasted time. So better // to compute the symbols/import map of an already computed def map in that time. + let scope_set: FxHashSet = scope.iter().copied().collect(); + let (reverse_deps, mut to_be_done_deps) = { - let all_crates = all_crates(db); - let to_be_done_deps = all_crates + // Only count in-scope deps — otherwise an out-of-scope dep would + // leave the scheduler waiting on a crate it never enqueued. + let to_be_done_deps = scope .iter() - .map(|&krate| (krate, krate.data(db).dependencies.len() as u32)) + .map(|&krate| { + let count = krate + .data(db) + .dependencies + .iter() + .filter(|dep| scope_set.contains(&dep.crate_id)) + .count() as u32; + (krate, count) + }) .collect::>(); let mut reverse_deps = - all_crates.iter().map(|&krate| (krate, Vec::new())).collect::>(); - for &krate in &*all_crates { + scope.iter().map(|&krate| (krate, Vec::new())).collect::>(); + for &krate in scope { for dep in &krate.data(db).dependencies { - reverse_deps.get_mut(&dep.crate_id).unwrap().push(krate); + if let Some(rev) = reverse_deps.get_mut(&dep.crate_id) { + rev.push(krate); + } } } (reverse_deps, to_be_done_deps) @@ -197,7 +219,7 @@ pub fn parallel_prime_caches( ) }; - let crate_def_maps_total = all_crates(db).len(); + let crate_def_maps_total = scope.len(); let mut crate_def_maps_done = 0; let (mut crate_import_maps_total, mut crate_import_maps_done) = (0usize, 0usize); let (mut module_symbols_total, mut module_symbols_done) = (0usize, 0usize); diff --git a/src/tools/rust-analyzer/crates/ide/src/lib.rs b/src/tools/rust-analyzer/crates/ide/src/lib.rs index dded01520ffbc..c4a3ec1e8eae9 100644 --- a/src/tools/rust-analyzer/crates/ide/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide/src/lib.rs @@ -333,11 +333,21 @@ impl Analysis { }) } - pub fn parallel_prime_caches(&self, num_worker_threads: usize, cb: F) -> Cancellable<()> + /// Warm caches for the given `scope`. `scope` must be closed under + /// transitive dependencies; callers that want to prime everything pass + /// `&base_db::all_crates(db)`. + pub fn parallel_prime_caches( + &self, + scope: &[Crate], + num_worker_threads: usize, + cb: F, + ) -> Cancellable<()> where F: Fn(ParallelPrimeCachesProgress) + Sync + std::panic::UnwindSafe, { - self.with_db(move |db| prime_caches::parallel_prime_caches(db, num_worker_threads, &cb)) + self.with_db(move |db| { + prime_caches::parallel_prime_caches(db, scope, num_worker_threads, &cb) + }) } /// Gets the text of the source file. 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 15e48feceeb97..f4b103902499c 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 @@ -447,7 +447,7 @@ macro_rules! void_2024 { } "#, - expect_file![format!("./test_data/highlight_keywords_macros.html")], + expect_file!["./test_data/highlight_keywords_macros.html"], false, ); } diff --git a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs index f5c5cb432d559..bf2331a40f9b6 100644 --- a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs +++ b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs @@ -197,7 +197,8 @@ pub fn load_workspace_into_db( ); if load_config.prefill_caches { - prime_caches::parallel_prime_caches(db, load_config.num_worker_threads, &|_| ()); + let all = ide_db::base_db::all_crates(db); + prime_caches::parallel_prime_caches(db, &all, load_config.num_worker_threads, &|_| ()); } Ok((vfs, proc_macro_server.and_then(Result::ok))) diff --git a/src/tools/rust-analyzer/crates/project-model/src/project_json.rs b/src/tools/rust-analyzer/crates/project-model/src/project_json.rs index 4ea136afbb455..4e2c1e846ce30 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/project_json.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/project_json.rs @@ -267,7 +267,7 @@ pub struct Crate { // Extra crate-level attributes, without the surrounding `#![]`. pub(crate) crate_attrs: Vec, pub(crate) proc_macro_dylib_path: Option, - pub(crate) is_workspace_member: bool, + pub is_workspace_member: bool, pub(crate) include: Vec, pub(crate) exclude: Vec, pub(crate) is_proc_macro: bool, diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/prime_caches.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/prime_caches.rs index beedcfae4ed85..782b0bda0a9ae 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/prime_caches.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/prime_caches.rs @@ -55,7 +55,8 @@ impl flags::PrimeCaches { ); let threads = self.num_threads.unwrap_or_else(num_cpus::get_physical); - ide_db::prime_caches::parallel_prime_caches(&db, threads, &|_| ()); + let all = ide_db::base_db::all_crates(&db); + ide_db::prime_caches::parallel_prime_caches(&db, &all, threads, &|_| ()); let elapsed = stop_watch.elapsed(); eprintln!( 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 5388f68f02194..76a79ae08d897 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 @@ -14,7 +14,7 @@ use hir::ChangeWithProcMacros; use ide::{Analysis, AnalysisHost, Cancellable, FileId, SourceRootId}; use ide_db::{ MiniCore, - base_db::{Crate, ProcMacroPaths, SourceDatabase, salsa::Revision}, + base_db::{Crate, ProcMacroPaths, SourceDatabase, all_crates, salsa::Revision}, }; use itertools::Itertools; use load_cargo::SourceRootConfig; @@ -24,7 +24,9 @@ use parking_lot::{ RwLockWriteGuard, }; use proc_macro_api::ProcMacroClient; -use project_model::{ManifestPath, ProjectWorkspace, ProjectWorkspaceKind, WorkspaceBuildScripts}; +use project_model::{ + ManifestPath, ProjectWorkspace, ProjectWorkspaceKind, TargetKind, WorkspaceBuildScripts, +}; use rustc_hash::{FxHashMap, FxHashSet}; use stdx::thread; use tracing::{Level, span, trace}; @@ -42,7 +44,7 @@ use crate::{ main_loop::Task, mem_docs::MemDocs, op_queue::{Cause, OpQueue}, - reload, + priming_scope, reload, target_spec::{CargoTargetSpec, ProjectJsonTargetSpec, TargetSpec}, task_pool::{DeferredTaskQueue, TaskPool}, test_runner::{CargoTestHandle, CargoTestMessage}, @@ -738,6 +740,75 @@ impl GlobalState { *fetch_receiver = crossbeam_channel::after(Duration::from_millis(100)); } } + + /// Set of crates to prime: the transitive-dependency closure of every + /// local Cargo workspace `lib`/`bin` target, `rust-project.json` workspace + /// member, and detached file. Computed once when the server becomes + /// quiescent. + /// + /// Test, example, and benchmark members are deliberately excluded — they're + /// leaves, so not priming them costs no parallelism on dependency work. + /// `bin` targets are kept because they're the crate the user is most likely + /// editing. + pub(crate) fn compute_priming_scope(&self) -> Arc<[Crate]> { + let db = self.analysis_host.raw_database(); + let all = all_crates(db); + + // Map each crate-root path to its crate(s) so target roots resolve to + // `Crate` ids. The vfs read lock is held only for this build. + let root_to_crate: FxHashMap> = { + let vfs = self.vfs.read(); + let mut root_to_crate: FxHashMap> = FxHashMap::default(); + for &krate in &*all { + let root_file = krate.data(db).root_file_id; + let path = vfs.0.file_path(root_file); + let Some(path) = path.as_path() else { + continue; + }; + root_to_crate.entry(path.to_path_buf()).or_default().push(krate); + } + root_to_crate + }; + + let mut seed: FxHashSet = FxHashSet::default(); + for workspace in self.workspaces.iter() { + match &workspace.kind { + ProjectWorkspaceKind::Cargo { cargo, .. } + | ProjectWorkspaceKind::DetachedFile { cargo: Some((cargo, ..)), .. } => { + for pkg in cargo.packages() { + if !cargo[pkg].is_local { + continue; + } + for &target in &cargo[pkg].targets { + if !matches!( + cargo[target].kind, + TargetKind::Lib { .. } | TargetKind::Bin + ) { + continue; + } + if let Some(krates) = root_to_crate.get(&*cargo[target].root) { + seed.extend(krates.iter().copied()); + } + } + } + } + ProjectWorkspaceKind::Json(project_json) => seed.extend( + project_json + .crates() + .filter(|(_, krate)| krate.is_workspace_member) + .filter_map(|(_, krate)| root_to_crate.get(&krate.root_module)) + .flat_map(|it| it.iter().copied()), + ), + ProjectWorkspaceKind::DetachedFile { file, cargo: None } => { + if let Some(krates) = root_to_crate.get(&**file) { + seed.extend(krates.iter().copied()); + } + } + } + } + + priming_scope::compute(db, seed) + } } impl Drop for GlobalState { diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs index 9eee516c3a2d7..48db8e38e988c 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs @@ -38,6 +38,7 @@ mod line_index; mod main_loop; mod mem_docs; mod op_queue; +mod priming_scope; mod reload; mod target_spec; mod task_pool; 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 c73be92a90906..56490061a74f6 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 @@ -647,14 +647,15 @@ impl GlobalState { } fn prime_caches(&mut self, cause: String) { - tracing::debug!(%cause, "will prime caches"); + let scope = self.compute_priming_scope(); + tracing::debug!(%cause, scope_size = scope.len(), "will prime caches"); let num_worker_threads = self.config.prime_caches_num_threads(); self.task_pool.handle.spawn_with_sender(ThreadIntent::Worker, { let analysis = AssertUnwindSafe(self.snapshot().analysis); move |sender| { sender.send(Task::PrimeCaches(PrimeCachesProgress::Begin)).unwrap(); - let res = analysis.parallel_prime_caches(num_worker_threads, |progress| { + let res = analysis.parallel_prime_caches(&scope, num_worker_threads, |progress| { let report = PrimeCachesProgress::Report(progress); sender.send(Task::PrimeCaches(report)).unwrap(); }); diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/priming_scope.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/priming_scope.rs new file mode 100644 index 0000000000000..f3d9d89bd27c3 --- /dev/null +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/priming_scope.rs @@ -0,0 +1,166 @@ +//! Scope computation for cache priming. + +use ide_db::{RootDatabase, base_db::Crate}; +use rustc_hash::FxHashSet; +use triomphe::Arc; + +/// Close `seeds` under transitive dependencies. +pub(crate) fn compute(db: &RootDatabase, seeds: impl IntoIterator) -> Arc<[Crate]> { + let mut closure: FxHashSet = FxHashSet::default(); + let mut worklist: Vec = seeds.into_iter().collect(); + while let Some(krate) = worklist.pop() { + if !closure.insert(krate) { + continue; + } + worklist.extend(krate.data(db).dependencies.iter().map(|dep| dep.crate_id)); + } + closure.into_iter().collect() +} + +#[cfg(test)] +mod tests { + use ide_db::{ + RootDatabase, + base_db::{ + CrateGraphBuilder, CrateName, CrateOrigin, CrateWorkspaceData, CratesIdMap, + DependencyBuilder, Env, LangCrateOrigin, + }, + span::{Edition, FileId}, + }; + use rustc_hash::FxHashMap; + use triomphe::Arc as TriompheArc; + use vfs::AbsPathBuf; + + use super::*; + + fn empty_ws_data() -> TriompheArc { + TriompheArc::new(CrateWorkspaceData { target: Err("".into()), toolchain: None }) + } + + /// Builds a synthetic crate graph in a fresh `RootDatabase` and returns + /// the resolved `Crate` IDs keyed by the symbolic names used in `crates`. + /// + /// `crates` is a list of `(name, origin, deps)`. The crate root file id + /// is derived from the crate's index. Dependencies must refer to crates + /// declared earlier in the list. + fn build(crates: &[(&str, CrateOrigin, &[&str])]) -> (RootDatabase, FxHashMap) { + let mut db = RootDatabase::default(); + let mut graph = CrateGraphBuilder::default(); + let proc_macro_cwd = + TriompheArc::new(AbsPathBuf::assert_utf8(std::env::current_dir().unwrap())); + + let mut ids = Vec::with_capacity(crates.len()); + for (i, (name, origin, _)) in crates.iter().enumerate() { + let id = graph.add_crate_root( + FileId::from_raw((i + 1) as u32), + Edition::Edition2021, + None, + None, + Default::default(), + Default::default(), + Env::default(), + origin.clone(), + Vec::new(), + false, + proc_macro_cwd.clone(), + empty_ws_data(), + ); + ids.push((name.to_string(), id)); + } + + for (i, (_, _, deps)) in crates.iter().enumerate() { + for dep_name in *deps { + let from = ids[i].1; + let to = ids + .iter() + .find(|(n, _)| n == dep_name) + .unwrap_or_else(|| panic!("unknown dep `{dep_name}`")) + .1; + graph + .add_dep(from, DependencyBuilder::new(CrateName::new(dep_name).unwrap(), to)) + .unwrap(); + } + } + + let resolved: CratesIdMap = graph.set_in_db(&mut db); + let by_name = ids.into_iter().map(|(n, id)| (n, resolved[&id])).collect(); + (db, by_name) + } + + fn lang(name: &str) -> CrateOrigin { + CrateOrigin::Lang(LangCrateOrigin::from(name)) + } + + fn local() -> CrateOrigin { + CrateOrigin::Local { repo: None, name: None } + } + + fn library(name: &str) -> CrateOrigin { + CrateOrigin::Library { repo: None, name: CrateName::new(name).unwrap().symbol().clone() } + } + + fn primed(scope: &Arc<[Crate]>, by_name: &FxHashMap) -> Vec { + let lookup: FxHashMap = + by_name.iter().map(|(n, c)| (*c, n.as_str())).collect(); + let mut names: Vec = scope.iter().map(|c| lookup[c].to_owned()).collect(); + names.sort(); + names + } + + #[test] + fn closes_seeds_under_deps() { + // core ← lib_a ← lib_b ← bin_c + // ↖ test_d + let (db, by) = build(&[ + ("core", lang("core"), &[]), + ("lib_a", local(), &["core"]), + ("lib_b", local(), &["lib_a"]), + ("bin_c", local(), &["lib_b"]), + ("test_d", local(), &["lib_b"]), + ]); + + let scope = compute(&db, [by["lib_a"], by["lib_b"]]); + assert_eq!(primed(&scope, &by), vec!["core", "lib_a", "lib_b"]); + } + + #[test] + fn active_seed_pulls_transitive_deps() { + let (db, by) = build(&[ + ("core", lang("core"), &[]), + ("lib_a", local(), &["core"]), + ("lib_b", local(), &["lib_a"]), + ("bin_c", local(), &["lib_b"]), + ]); + + let scope = compute(&db, [by["bin_c"]]); + assert_eq!(primed(&scope, &by), vec!["bin_c", "core", "lib_a", "lib_b"]); + } + + #[test] + fn does_not_pull_reverse_deps() { + // Seeding only the leaf must not warm crates that depend on it. + let (db, by) = build(&[ + ("core", lang("core"), &[]), + ("lib_leaf", local(), &["core"]), + ("dependent_a", local(), &["lib_leaf"]), + ("dependent_b", local(), &["lib_leaf"]), + ]); + + let scope = compute(&db, [by["lib_leaf"]]); + assert_eq!(primed(&scope, &by), vec!["core", "lib_leaf"]); + } + + #[test] + fn pulls_library_dep_via_seeded_crate() { + // A `Library` (non-workspace-member) origin behaves like any other — + // dep walk is origin-agnostic, only the seed selection cares. + let (db, by) = build(&[ + ("core", lang("core"), &[]), + ("ext", library("serde"), &["core"]), + ("lib_a", local(), &["ext"]), + ]); + + let scope = compute(&db, [by["lib_a"]]); + assert_eq!(primed(&scope, &by), vec!["core", "ext", "lib_a"]); + } +} From ebf114b1d94547cbca2a8fb54d6a8f716f96c99f Mon Sep 17 00:00:00 2001 From: Amirhossein Akhlaghpour Date: Sat, 25 Jul 2026 16:37:32 +0330 Subject: [PATCH 52/76] tests: add regression test for issue 159894 Signed-off-by: Amirhossein Akhlaghpour --- ...er-universe-resolved-const-issue-159894.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 tests/ui/traits/next-solver/lower-universe-resolved-const-issue-159894.rs diff --git a/tests/ui/traits/next-solver/lower-universe-resolved-const-issue-159894.rs b/tests/ui/traits/next-solver/lower-universe-resolved-const-issue-159894.rs new file mode 100644 index 0000000000000..1885e177a6b60 --- /dev/null +++ b/tests/ui/traits/next-solver/lower-universe-resolved-const-issue-159894.rs @@ -0,0 +1,19 @@ +//@ check-pass +//@ compile-flags: -Znext-solver=globally + +pub struct IndexMap { + #[expect(dead_code)] + build_hasher: S, +} + +struct Guard<'a, S, const N: usize>( + #[expect(dead_code)] &'a mut IndexMap, +); + +impl IndexMap { + pub fn clear(&mut self) { + let _ = Guard(self); + } +} + +fn main() {} From 70847a5bc39e70decb27ddf526375d6febe61d54 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Sat, 25 Jul 2026 23:33:29 +0300 Subject: [PATCH 53/76] Remove format_args lowering for toolchains prior to 1.94.0 We don't support them now since https://github.com/rust-lang/rust-analyzer/pull/22784. --- .../src/expr_store/lower/format_args.rs | 564 +----------------- .../hir-def/src/expr_store/tests/body.rs | 187 +----- .../src/handlers/missing_unsafe.rs | 11 - .../crates/ide/src/references.rs | 2 +- .../crates/test-utils/src/minicore.rs | 106 ---- 5 files changed, 16 insertions(+), 854 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/format_args.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/format_args.rs index 1ecd18fb53aec..5552213aba55d 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/format_args.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/format_args.rs @@ -5,18 +5,14 @@ use hir_expand::name::Name; use intern::{Symbol, sym}; use span::SyntaxContext; use syntax::{AstPtr, AstToken as _, ast}; -use thin_vec::ThinVec; use crate::{ - builtin_type::BuiltinUint, expr_store::{HygieneId, lower::ExprCollector, path::Path}, hir::{ - Array, BindingAnnotation, Expr, ExprId, Literal, Pat, RecordLitField, RecordSpread, - Statement, + Array, BindingAnnotation, Expr, ExprId, Literal, Pat, Statement, format_args::{ self, FormatAlignment, FormatArgs, FormatArgsPiece, FormatArgument, FormatArgumentKind, - FormatArgumentsCollector, FormatCount, FormatDebugHex, FormatOptions, - FormatPlaceholder, FormatSign, FormatTrait, + FormatArgumentsCollector, FormatCount, FormatDebugHex, FormatSign, FormatTrait, }, }, lang_item::LangItemTarget, @@ -96,11 +92,7 @@ impl<'db> ExprCollector<'db> { ), }; - let idx = if self.lang_items().FormatCount.is_none() { - self.collect_format_args_after_1_93_0_impl(syntax_ptr, fmt) - } else { - self.collect_format_args_before_1_93_0_impl(syntax_ptr, fmt) - }; + let idx = self.collect_format_args_impl(syntax_ptr, fmt); self.store .template_map @@ -110,7 +102,9 @@ impl<'db> ExprCollector<'db> { idx } - fn collect_format_args_after_1_93_0_impl( + // This is in separate functions because historically, changes in format_args lowering have forced us to change this + // function but not its caller, and for some time support both versions. + fn collect_format_args_impl( &mut self, syntax_ptr: AstPtr, fmt: FormatArgs, @@ -433,552 +427,6 @@ impl<'db> ExprCollector<'db> { } } - fn collect_format_args_before_1_93_0_impl( - &mut self, - syntax_ptr: AstPtr, - fmt: FormatArgs, - ) -> ExprId { - // Create a list of all _unique_ (argument, format trait) combinations. - // E.g. "{0} {0:x} {0} {1}" -> [(0, Display), (0, LowerHex), (1, Display)] - let mut argmap = FxIndexSet::default(); - for piece in fmt.template.iter() { - let FormatArgsPiece::Placeholder(placeholder) = piece else { continue }; - if let Ok(index) = placeholder.argument.index { - argmap.insert((index, ArgumentType::Format(placeholder.format_trait))); - } - } - - let lit_pieces = fmt - .template - .iter() - .enumerate() - .filter_map(|(i, piece)| { - match piece { - FormatArgsPiece::Literal(s) => { - Some(self.alloc_expr_desugared(Expr::Literal(Literal::String(s.clone())))) - } - &FormatArgsPiece::Placeholder(_) => { - // Inject empty string before placeholders when not already preceded by a literal piece. - if i == 0 || matches!(fmt.template[i - 1], FormatArgsPiece::Placeholder(_)) - { - Some(self.alloc_expr_desugared(Expr::Literal(Literal::String( - Symbol::empty(), - )))) - } else { - None - } - } - } - }) - .collect(); - let lit_pieces = - self.alloc_expr_desugared(Expr::Array(Array::ElementList { elements: lit_pieces })); - let lit_pieces = self.alloc_expr_desugared(Expr::Ref { - expr: lit_pieces, - rawness: Rawness::Ref, - mutability: Mutability::Shared, - }); - let format_options = { - // Generate: - // &[format_spec_0, format_spec_1, format_spec_2] - let elements = fmt - .template - .iter() - .filter_map(|piece| { - let FormatArgsPiece::Placeholder(placeholder) = piece else { return None }; - Some(self.make_format_spec(placeholder, &mut argmap)) - }) - .collect(); - let array = self.alloc_expr_desugared(Expr::Array(Array::ElementList { elements })); - self.alloc_expr_desugared(Expr::Ref { - expr: array, - rawness: Rawness::Ref, - mutability: Mutability::Shared, - }) - }; - - // Assume that rustc version >= 1.89.0 iff lang item `format_arguments` exists - // but `format_unsafe_arg` does not - let lang_items = self.lang_items(); - let fmt_args = lang_items.FormatArguments; - let fmt_unsafe_arg = lang_items.FormatUnsafeArg; - let use_format_args_since_1_89_0 = fmt_args.is_some() && fmt_unsafe_arg.is_none(); - - if use_format_args_since_1_89_0 { - self.collect_format_args_after_1_89_0_impl( - syntax_ptr, - fmt, - argmap, - lit_pieces, - format_options, - ) - } else { - self.collect_format_args_before_1_89_0_impl( - syntax_ptr, - fmt, - argmap, - lit_pieces, - format_options, - ) - } - } - - /// `format_args!` expansion implementation for rustc versions < `1.89.0` - fn collect_format_args_before_1_89_0_impl( - &mut self, - syntax_ptr: AstPtr, - fmt: FormatArgs, - argmap: FxIndexSet<(usize, ArgumentType)>, - lit_pieces: ExprId, - format_options: ExprId, - ) -> ExprId { - let arguments = &*fmt.arguments.arguments; - - let args = if arguments.is_empty() { - let expr = self - .alloc_expr_desugared(Expr::Array(Array::ElementList { elements: Box::default() })); - self.alloc_expr_desugared(Expr::Ref { - expr, - rawness: Rawness::Ref, - mutability: Mutability::Shared, - }) - } else { - // Generate: - // &match (&arg0, &arg1, &…) { - // args => [ - // ::new_display(args.0), - // ::new_lower_hex(args.1), - // ::new_debug(args.0), - // … - // ] - // } - let args = argmap - .iter() - .map(|&(arg_index, ty)| { - let arg = self.alloc_expr_desugared(Expr::Ref { - expr: arguments[arg_index].expr, - rawness: Rawness::Ref, - mutability: Mutability::Shared, - }); - let arg_ptr = arguments.get(arg_index).and_then(|it| it.syntax); - self.make_argument(arg_ptr, arg, ty) - }) - .collect(); - let array = - self.alloc_expr_desugared(Expr::Array(Array::ElementList { elements: args })); - self.alloc_expr_desugared(Expr::Ref { - expr: array, - rawness: Rawness::Ref, - mutability: Mutability::Shared, - }) - }; - - // Generate: - // ::new_v1_formatted( - // lit_pieces, - // args, - // format_options, - // unsafe { ::core::fmt::UnsafeArg::new() } - // ) - - let lang_items = self.lang_items(); - let new_v1_formatted = - self.ty_rel_lang_path_desugared_expr(lang_items.FormatArguments, sym::new_v1_formatted); - let unsafe_arg_new = - self.ty_rel_lang_path_desugared_expr(lang_items.FormatUnsafeArg, sym::new); - let unsafe_arg_new = - self.alloc_expr_desugared(Expr::Call { callee: unsafe_arg_new, args: Box::default() }); - let mut unsafe_arg_new = self.alloc_expr_desugared(Expr::Unsafe { - id: None, - statements: Box::new([]), - tail: Some(unsafe_arg_new), - }); - if !fmt.orphans.is_empty() { - unsafe_arg_new = self.alloc_expr_desugared(Expr::Block { - id: None, - // We collect the unused expressions here so that we still infer them instead of - // dropping them out of the expression tree. We cannot store them in the `Unsafe` - // block because then unsafe blocks within them will get a false "unused unsafe" - // diagnostic (rustc has a notion of builtin unsafe blocks, but we don't). - statements: fmt - .orphans - .into_iter() - .map(|expr| Statement::Expr { expr, has_semi: true }) - .collect(), - tail: Some(unsafe_arg_new), - label: None, - }); - } - - self.alloc_expr( - Expr::Call { - callee: new_v1_formatted, - args: Box::new([lit_pieces, args, format_options, unsafe_arg_new]), - }, - syntax_ptr, - ) - } - - /// `format_args!` expansion implementation for rustc versions >= `1.89.0`, - /// especially since [this PR](https://github.com/rust-lang/rust/pull/140748) - fn collect_format_args_after_1_89_0_impl( - &mut self, - syntax_ptr: AstPtr, - fmt: FormatArgs, - argmap: FxIndexSet<(usize, ArgumentType)>, - lit_pieces: ExprId, - format_options: ExprId, - ) -> ExprId { - let arguments = &*fmt.arguments.arguments; - - let (let_stmts, args) = if arguments.is_empty() { - ( - // Generate: - // [] - vec![], - self.alloc_expr_desugared(Expr::Array(Array::ElementList { - elements: Box::default(), - })), - ) - } else if argmap.len() == 1 && arguments.len() == 1 { - // Only one argument, so we don't need to make the `args` tuple. - // - // Generate: - // super let args = [::new_display(&arg)]; - let args = argmap - .iter() - .map(|&(arg_index, ty)| { - let ref_arg = self.alloc_expr_desugared(Expr::Ref { - expr: arguments[arg_index].expr, - rawness: Rawness::Ref, - mutability: Mutability::Shared, - }); - let arg_ptr = arguments.get(arg_index).and_then(|it| it.syntax); - self.make_argument(arg_ptr, ref_arg, ty) - }) - .collect(); - let args = - self.alloc_expr_desugared(Expr::Array(Array::ElementList { elements: args })); - let args_name = self.generate_new_name(); - let args_binding = self.alloc_binding( - args_name.clone(), - BindingAnnotation::Unannotated, - HygieneId::ROOT, - ); - let args_pat = self.alloc_pat_desugared(Pat::Bind { id: args_binding, subpat: None }); - self.add_definition_to_binding(args_binding, args_pat); - // TODO: We don't have `super let` yet. - let let_stmt = Statement::Let { - pat: args_pat, - type_ref: None, - initializer: Some(args), - else_branch: None, - }; - (vec![let_stmt], self.alloc_expr_desugared(Expr::Path(args_name.into()))) - } else { - // Generate: - // super let args = (&arg0, &arg1, &...); - let args_name = self.generate_new_name(); - let args_binding = self.alloc_binding( - args_name.clone(), - BindingAnnotation::Unannotated, - HygieneId::ROOT, - ); - let args_pat = self.alloc_pat_desugared(Pat::Bind { id: args_binding, subpat: None }); - self.add_definition_to_binding(args_binding, args_pat); - let elements = arguments - .iter() - .map(|arg| { - self.alloc_expr_desugared(Expr::Ref { - expr: arg.expr, - rawness: Rawness::Ref, - mutability: Mutability::Shared, - }) - }) - .collect(); - let args_tuple = self.alloc_expr_desugared(Expr::Tuple { exprs: elements }); - // TODO: We don't have `super let` yet - let let_stmt1 = Statement::Let { - pat: args_pat, - type_ref: None, - initializer: Some(args_tuple), - else_branch: None, - }; - - // Generate: - // super let args = [ - // ::new_display(args.0), - // ::new_lower_hex(args.1), - // ::new_debug(args.0), - // … - // ]; - let args = argmap - .iter() - .map(|&(arg_index, ty)| { - let args_ident_expr = - self.alloc_expr_desugared(Expr::Path(args_name.clone().into())); - let arg = self.alloc_expr_desugared(Expr::Field { - expr: args_ident_expr, - name: Name::new_tuple_field(arg_index), - }); - let arg_ptr = arguments.get(arg_index).and_then(|it| it.syntax); - self.make_argument(arg_ptr, arg, ty) - }) - .collect(); - let array = - self.alloc_expr_desugared(Expr::Array(Array::ElementList { elements: args })); - let args_binding = self.alloc_binding( - args_name.clone(), - BindingAnnotation::Unannotated, - HygieneId::ROOT, - ); - let args_pat = self.alloc_pat_desugared(Pat::Bind { id: args_binding, subpat: None }); - self.add_definition_to_binding(args_binding, args_pat); - let let_stmt2 = Statement::Let { - pat: args_pat, - type_ref: None, - initializer: Some(array), - else_branch: None, - }; - (vec![let_stmt1, let_stmt2], self.alloc_expr_desugared(Expr::Path(args_name.into()))) - }; - - // Generate: - // &args - let args = self.alloc_expr_desugared(Expr::Ref { - expr: args, - rawness: Rawness::Ref, - mutability: Mutability::Shared, - }); - - let call_block = { - // Generate: - // unsafe { - // ::new_v1_formatted( - // lit_pieces, - // args, - // format_options, - // ) - // } - - let new_v1_formatted = self.ty_rel_lang_path_desugared_expr( - self.lang_items().FormatArguments, - sym::new_v1_formatted, - ); - let args = [lit_pieces, args, format_options]; - let call = self - .alloc_expr_desugared(Expr::Call { callee: new_v1_formatted, args: args.into() }); - - Expr::Unsafe { id: None, statements: Box::default(), tail: Some(call) } - }; - - if !let_stmts.is_empty() { - // Generate: - // { - // super let … - // super let … - // ::new_…(…) - // } - let call = self.alloc_expr_desugared(call_block); - self.alloc_expr( - Expr::Block { - id: None, - statements: let_stmts.into(), - tail: Some(call), - label: None, - }, - syntax_ptr, - ) - } else { - self.alloc_expr(call_block, syntax_ptr) - } - } - - /// Generate a hir expression for a format_args placeholder specification. - /// - /// Generates - /// - /// ```text - /// ::…, // alignment - /// …u32, // flags - /// , // width - /// , // precision - /// ) - /// ``` - fn make_format_spec( - &mut self, - placeholder: &FormatPlaceholder, - argmap: &mut FxIndexSet<(usize, ArgumentType)>, - ) -> ExprId { - let lang_items = self.lang_items(); - let position = match placeholder.argument.index { - Ok(arg_index) => { - let (i, _) = - argmap.insert_full((arg_index, ArgumentType::Format(placeholder.format_trait))); - self.alloc_expr_desugared(Expr::Literal(Literal::Uint( - i as u128, - Some(BuiltinUint::Usize), - ))) - } - Err(_) => self.missing_expr(), - }; - let &FormatOptions { - ref width, - ref precision, - alignment, - fill, - sign, - alternate, - zero_pad, - debug_hex, - } = &placeholder.format_options; - - let precision_expr = self.make_count_before_1_93_0(precision, argmap); - let width_expr = self.make_count_before_1_93_0(width, argmap); - - if self.krate.workspace_data(self.db).is_atleast_187() { - // These need to match the constants in library/core/src/fmt/rt.rs. - let align = match alignment { - Some(FormatAlignment::Left) => 0, - Some(FormatAlignment::Right) => 1, - Some(FormatAlignment::Center) => 2, - None => 3, - }; - // This needs to match `Flag` in library/core/src/fmt/rt.rs. - let flags = fill.unwrap_or(' ') as u32 - | ((sign == Some(FormatSign::Plus)) as u32) << 21 - | ((sign == Some(FormatSign::Minus)) as u32) << 22 - | (alternate as u32) << 23 - | (zero_pad as u32) << 24 - | ((debug_hex == Some(FormatDebugHex::Lower)) as u32) << 25 - | ((debug_hex == Some(FormatDebugHex::Upper)) as u32) << 26 - | (width.is_some() as u32) << 27 - | (precision.is_some() as u32) << 28 - | align << 29 - | 1 << 31; // Highest bit always set. - let flags = self.alloc_expr_desugared(Expr::Literal(Literal::Uint( - flags as u128, - Some(BuiltinUint::U32), - ))); - - let position = - RecordLitField { name: Name::new_symbol_root(sym::position), expr: position }; - let flags = RecordLitField { name: Name::new_symbol_root(sym::flags), expr: flags }; - let precision = RecordLitField { - name: Name::new_symbol_root(sym::precision), - expr: precision_expr, - }; - let width = - RecordLitField { name: Name::new_symbol_root(sym::width), expr: width_expr }; - match self.lang_path(lang_items.FormatPlaceholder) { - Some(path) => self.alloc_expr_desugared(Expr::RecordLit { - path, - fields: { - let mut fields = ThinVec::with_capacity(4); - fields.extend([position, flags, precision, width]); - fields - }, - spread: RecordSpread::None, - }), - None => self.missing_expr(), - } - } else { - let format_placeholder_new = - self.ty_rel_lang_path_desugared_expr(lang_items.FormatPlaceholder, sym::new); - // This needs to match `Flag` in library/core/src/fmt/rt.rs. - let flags: u32 = ((sign == Some(FormatSign::Plus)) as u32) - | (((sign == Some(FormatSign::Minus)) as u32) << 1) - | ((alternate as u32) << 2) - | ((zero_pad as u32) << 3) - | (((debug_hex == Some(FormatDebugHex::Lower)) as u32) << 4) - | (((debug_hex == Some(FormatDebugHex::Upper)) as u32) << 5); - let flags = self.alloc_expr_desugared(Expr::Literal(Literal::Uint( - flags as u128, - Some(BuiltinUint::U32), - ))); - let fill = self.alloc_expr_desugared(Expr::Literal(Literal::Char(fill.unwrap_or(' ')))); - let align = self.ty_rel_lang_path_desugared_expr( - lang_items.FormatAlignment, - match alignment { - Some(FormatAlignment::Left) => sym::Left, - Some(FormatAlignment::Right) => sym::Right, - Some(FormatAlignment::Center) => sym::Center, - None => sym::Unknown, - }, - ); - self.alloc_expr_desugared(Expr::Call { - callee: format_placeholder_new, - args: Box::new([position, fill, align, flags, precision_expr, width_expr]), - }) - } - } - - /// Generate a hir expression for a format_args Count. - /// - /// Generates: - /// - /// ```text - /// ::Is(…) - /// ``` - /// - /// or - /// - /// ```text - /// ::Param(…) - /// ``` - /// - /// or - /// - /// ```text - /// ::Implied - /// ``` - fn make_count_before_1_93_0( - &mut self, - count: &Option, - argmap: &mut FxIndexSet<(usize, ArgumentType)>, - ) -> ExprId { - let lang_items = self.lang_items(); - match count { - Some(FormatCount::Literal(n)) => { - let args = self.alloc_expr_desugared(Expr::Literal(Literal::Uint( - *n as u128, - // FIXME: Change this to Some(BuiltinUint::U16) once we drop support for toolchains < 1.88 - None, - ))); - let count_is = - self.ty_rel_lang_path_desugared_expr(lang_items.FormatCount, sym::Is); - self.alloc_expr_desugared(Expr::Call { callee: count_is, args: Box::new([args]) }) - } - Some(FormatCount::Argument(arg)) => { - if let Ok(arg_index) = arg.index { - let (i, _) = argmap.insert_full((arg_index, ArgumentType::Usize)); - - let args = self.alloc_expr_desugared(Expr::Literal(Literal::Uint( - i as u128, - Some(BuiltinUint::Usize), - ))); - let count_param = - self.ty_rel_lang_path_desugared_expr(lang_items.FormatCount, sym::Param); - self.alloc_expr_desugared(Expr::Call { - callee: count_param, - args: Box::new([args]), - }) - } else { - // FIXME: This drops arg causing it to potentially not be resolved/type checked - // when typing? - self.missing_expr() - } - } - None => match self.ty_rel_lang_path(lang_items.FormatCount, sym::Implied) { - Some(count_param) => self.alloc_expr_desugared(Expr::Path(count_param)), - None => self.missing_expr(), - }, - } - } - /// Generate a hir expression representing an argument to a format_args invocation. /// /// Generates: diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body.rs index c7b9edf3939fa..f199ef4f9fdba 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body.rs @@ -193,168 +193,6 @@ fn main() { ); } -#[test] -fn desugar_builtin_format_args_before_1_89_0() { - pretty_print( - r#" -//- minicore: fmt_before_1_89_0 -fn main() { - let are = "are"; - let count = 10; - builtin#format_args("\u{1b}hello {count:02} {} friends, we {are:?} {0}{last}", "fancy", orphan = (), last = "!"); -} -"#, - expect![[r#" - fn main() { - let are = "are"; - let count = 10; - builtin#lang(Arguments::new_v1_formatted)( - &[ - "\u{1b}hello ", " ", " friends, we ", " ", "", - ], - &[ - builtin#lang(Argument::new_display)( - &count, - ), builtin#lang(Argument::new_display)( - &"fancy", - ), builtin#lang(Argument::new_debug)( - &are, - ), builtin#lang(Argument::new_display)( - &"!", - ), - ], - &[ - builtin#lang(Placeholder::new)( - 0usize, - ' ', - builtin#lang(Alignment::Unknown), - 8u32, - builtin#lang(Count::Implied), - builtin#lang(Count::Is)( - 2, - ), - ), builtin#lang(Placeholder::new)( - 1usize, - ' ', - builtin#lang(Alignment::Unknown), - 0u32, - builtin#lang(Count::Implied), - builtin#lang(Count::Implied), - ), builtin#lang(Placeholder::new)( - 2usize, - ' ', - builtin#lang(Alignment::Unknown), - 0u32, - builtin#lang(Count::Implied), - builtin#lang(Count::Implied), - ), builtin#lang(Placeholder::new)( - 1usize, - ' ', - builtin#lang(Alignment::Unknown), - 0u32, - builtin#lang(Count::Implied), - builtin#lang(Count::Implied), - ), builtin#lang(Placeholder::new)( - 3usize, - ' ', - builtin#lang(Alignment::Unknown), - 0u32, - builtin#lang(Count::Implied), - builtin#lang(Count::Implied), - ), - ], - { - (); - unsafe { - builtin#lang(UnsafeArg::new)() - } - }, - ); - }"#]], - ) -} - -#[test] -fn desugar_builtin_format_args_before_1_93_0() { - pretty_print( - r#" -//- minicore: fmt_before_1_93_0 -fn main() { - let are = "are"; - let count = 10; - builtin#format_args("\u{1b}hello {count:02} {} friends, we {are:?} {0}{last}", "fancy", orphan = (), last = "!"); -} -"#, - expect![[r#" - fn main() { - let are = "are"; - let count = 10; - { - let 0 = (&"fancy", &(), &"!", &count, &are, ); - let 0 = [ - builtin#lang(Argument::new_display)( - 0.3, - ), builtin#lang(Argument::new_display)( - 0.0, - ), builtin#lang(Argument::new_debug)( - 0.4, - ), builtin#lang(Argument::new_display)( - 0.2, - ), - ]; - unsafe { - builtin#lang(Arguments::new_v1_formatted)( - &[ - "\u{1b}hello ", " ", " friends, we ", " ", "", - ], - &0, - &[ - builtin#lang(Placeholder::new)( - 0usize, - ' ', - builtin#lang(Alignment::Unknown), - 8u32, - builtin#lang(Count::Implied), - builtin#lang(Count::Is)( - 2, - ), - ), builtin#lang(Placeholder::new)( - 1usize, - ' ', - builtin#lang(Alignment::Unknown), - 0u32, - builtin#lang(Count::Implied), - builtin#lang(Count::Implied), - ), builtin#lang(Placeholder::new)( - 2usize, - ' ', - builtin#lang(Alignment::Unknown), - 0u32, - builtin#lang(Count::Implied), - builtin#lang(Count::Implied), - ), builtin#lang(Placeholder::new)( - 1usize, - ' ', - builtin#lang(Alignment::Unknown), - 0u32, - builtin#lang(Count::Implied), - builtin#lang(Count::Implied), - ), builtin#lang(Placeholder::new)( - 3usize, - ' ', - builtin#lang(Alignment::Unknown), - 0u32, - builtin#lang(Count::Implied), - builtin#lang(Count::Implied), - ), - ], - ) - } - }; - }"#]], - ) -} - #[test] fn desugar_builtin_format_args() { pretty_print( @@ -464,7 +302,7 @@ impl SsrError { fn regression_10300() { pretty_print( r#" -//- minicore: concat, panic, fmt_before_1_89_0 +//- minicore: concat, panic, fmt mod private { pub use core::concat; } @@ -480,22 +318,15 @@ fn f(a: i32, b: u32) -> String { } "#, expect![[r#" - fn f(a, b) { - { - core::panicking::panic_fmt( - builtin#lang(Arguments::new_v1_formatted)( - &[ + fn f(a, b) { + { + core::panicking::panic_fmt( + builtin#lang(Arguments::from_str)( "cc", - ], - &[], - &[], - unsafe { - builtin#lang(UnsafeArg::new)() - }, - ), - ); - }; - }"#]], + ), + ); + }; + }"#]], ) } diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs index 808b76e08211e..18859c0db1e60 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs @@ -674,17 +674,6 @@ fn main() { #[test] fn orphan_unsafe_format_args() { // Checks that we don't place orphan arguments for formatting under an unsafe block. - check_diagnostics( - r#" -//- minicore: fmt_before_1_89_0 -fn foo() { - let p = 0xDEADBEEF as *const i32; - format_args!("", *p); - // ^^ error: dereference of raw pointer is unsafe and requires an unsafe function or block -} - "#, - ); - check_diagnostics( r#" //- minicore: fmt diff --git a/src/tools/rust-analyzer/crates/ide/src/references.rs b/src/tools/rust-analyzer/crates/ide/src/references.rs index d85e01af41d65..bb79fc2aa0858 100644 --- a/src/tools/rust-analyzer/crates/ide/src/references.rs +++ b/src/tools/rust-analyzer/crates/ide/src/references.rs @@ -600,7 +600,7 @@ fn main() { false, false, expect![[r#" - Some Variant FileId(1) 6737..6769 6762..6766 + Some Variant FileId(1) 6734..6766 6759..6763 FileId(0) 46..50 "#]], diff --git a/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs b/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs index f3a460b9ac3da..ca2d824f2c2b4 100644 --- a/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs +++ b/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs @@ -37,8 +37,6 @@ //! error: fmt //! float_consts: //! fmt: option, result, transmute, coerce_unsized, copy, clone, derive -//! fmt_before_1_93_0: fmt -//! fmt_before_1_89_0: fmt_before_1_93_0 //! fn: sized, tuple //! from: sized, result //! future: pin @@ -1428,111 +1426,8 @@ pub mod fmt { Center, Unknown, } - - // region:fmt_before_1_93_0 - #[lang = "format_count"] - pub enum Count { - Is(usize), - Param(usize), - Implied, - } - - #[lang = "format_placeholder"] - pub struct Placeholder { - pub position: usize, - pub fill: char, - pub align: Alignment, - pub flags: u32, - pub precision: Count, - pub width: Count, - } - - impl Placeholder { - pub const fn new( - position: usize, - fill: char, - align: Alignment, - flags: u32, - precision: Count, - width: Count, - ) -> Self { - Placeholder { position, fill, align, flags, precision, width } - } - } - // endregion:fmt_before_1_93_0 - - // region:fmt_before_1_89_0 - #[lang = "format_unsafe_arg"] - pub struct UnsafeArg { - _private: (), - } - - impl UnsafeArg { - pub unsafe fn new() -> Self { - UnsafeArg { _private: () } - } - } - // endregion:fmt_before_1_89_0 - } - - // region:fmt_before_1_93_0 - #[derive(Copy, Clone)] - #[lang = "format_arguments"] - pub struct Arguments<'a> { - pieces: &'a [&'static str], - fmt: Option<&'a [rt::Placeholder]>, - args: &'a [rt::Argument<'a>], - } - - impl<'a> Arguments<'a> { - pub const fn new_v1(pieces: &'a [&'static str], args: &'a [Argument<'a>]) -> Arguments<'a> { - Arguments { pieces, fmt: None, args } - } - - pub const fn new_const(pieces: &'a [&'static str]) -> Arguments<'a> { - Arguments { pieces, fmt: None, args: &[] } - } - - // region:fmt_before_1_89_0 - pub fn new_v1_formatted( - pieces: &'a [&'static str], - args: &'a [rt::Argument<'a>], - fmt: &'a [rt::Placeholder], - _unsafe_arg: rt::UnsafeArg, - ) -> Arguments<'a> { - Arguments { pieces, fmt: Some(fmt), args } - } - // endregion:fmt_before_1_89_0 - - // region:!fmt_before_1_89_0 - pub unsafe fn new_v1_formatted( - pieces: &'a [&'static str], - args: &'a [rt::Argument<'a>], - fmt: &'a [rt::Placeholder], - ) -> Arguments<'a> { - Arguments { pieces, fmt: Some(fmt), args } - } - // endregion:!fmt_before_1_89_0 - - pub fn from_str_nonconst(s: &'static str) -> Arguments<'a> { - Self::from_str(s) - } - - pub const fn from_str(s: &'static str) -> Arguments<'a> { - Arguments { pieces: &[s], fmt: None, args: &[] } - } - - pub const fn as_str(&self) -> Option<&'static str> { - match (self.pieces, self.args) { - ([], []) => Some(""), - ([s], []) => Some(s), - _ => None, - } - } } - // endregion:fmt_before_1_93_0 - // region:!fmt_before_1_93_0 #[lang = "format_arguments"] #[derive(Copy, Clone)] pub struct Arguments<'a> { @@ -1564,7 +1459,6 @@ pub mod fmt { } } } - // endregion:!fmt_before_1_93_0 // region:derive pub(crate) mod derive { From 5e63626cd24427e56bb166afe3a9e74373a1abe6 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Sat, 25 Jul 2026 23:37:04 +0300 Subject: [PATCH 54/76] Remove lockfile-path support for Cargo versions below 1.94.0 --- .../crates/project-model/src/build_dependencies.rs | 4 ---- .../crates/project-model/src/cargo_config_file.rs | 13 ------------- .../crates/project-model/src/cargo_workspace.rs | 4 ---- 3 files changed, 21 deletions(-) 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 9f84f632d5e44..926a9e327e8c4 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 @@ -473,10 +473,6 @@ impl WorkspaceBuildScripts { if let Some(lockfile_copy) = &lockfile_copy { requires_unstable_options = true; match lockfile_copy.usage { - LockfileUsage::WithFlag => { - cmd.arg("--lockfile-path"); - cmd.arg(lockfile_copy.path.as_str()); - } LockfileUsage::WithEnvVarUnstable => { cmd.arg("-Zlockfile-path"); cmd.env( diff --git a/src/tools/rust-analyzer/crates/project-model/src/cargo_config_file.rs b/src/tools/rust-analyzer/crates/project-model/src/cargo_config_file.rs index defd9f96ab5fb..a6bfea8200c53 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/cargo_config_file.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/cargo_config_file.rs @@ -143,8 +143,6 @@ pub(crate) struct LockfileCopy { } pub(crate) enum LockfileUsage { - /// Rust [1.82.0, 1.95.0). `cargo --lockfile-path ` - WithFlag, /// Rust [1.95.0, 1.97.0). `CARGO_RESOLVER_LOCKFILE_PATH= cargo -Zlockfile-path ` WithEnvVarUnstable, /// Rust >= 1.97.0. `CARGO_RESOLVER_LOCKFILE_PATH= cargo ` @@ -155,15 +153,6 @@ pub(crate) fn make_lockfile_copy( toolchain_version: &semver::Version, lockfile_path: &Utf8Path, ) -> Option { - const MINIMUM_TOOLCHAIN_VERSION_SUPPORTING_LOCKFILE_PATH_FLAG: semver::Version = - semver::Version { - major: 1, - minor: 82, - patch: 0, - pre: semver::Prerelease::EMPTY, - build: semver::BuildMetadata::EMPTY, - }; - const MINIMUM_TOOLCHAIN_VERSION_SUPPORTING_LOCKFILE_PATH_ENV_UNSTABLE: semver::Version = semver::Version { major: 1, @@ -187,8 +176,6 @@ pub(crate) fn make_lockfile_copy( } else if *toolchain_version >= MINIMUM_TOOLCHAIN_VERSION_SUPPORTING_LOCKFILE_PATH_ENV_UNSTABLE { LockfileUsage::WithEnvVarUnstable - } else if *toolchain_version >= MINIMUM_TOOLCHAIN_VERSION_SUPPORTING_LOCKFILE_PATH_FLAG { - LockfileUsage::WithFlag } else { return None; }; 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 97375fe9ddd1a..3db5a0fffce7f 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 @@ -767,10 +767,6 @@ impl FetchMetadata { let mut using_lockfile_copy = false; if let Some(lockfile_copy) = &lockfile_copy { match lockfile_copy.usage { - LockfileUsage::WithFlag => { - other_options.push("--lockfile-path".to_owned()); - other_options.push(lockfile_copy.path.to_string()); - } LockfileUsage::WithEnvVarUnstable => { other_options.push("-Zlockfile-path".to_owned()); command.env("CARGO_RESOLVER_LOCKFILE_PATH", lockfile_copy.path.as_os_str()); From 3ce7165e31134cfd789ad502d442cebee941362c Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Sat, 25 Jul 2026 23:59:45 +0300 Subject: [PATCH 55/76] Remove support for `#[rustc_box]` It was replaced with an intrinsic in https://github.com/rust-lang/rust/pull/135046, released in 1.86.0. And add MIR eval support for the intrinsic. --- .../crates/hir-def/src/expr_store.rs | 1 - .../crates/hir-def/src/expr_store/lower.rs | 26 ++++------- .../crates/hir-def/src/expr_store/pretty.rs | 4 -- .../rust-analyzer/crates/hir-def/src/hir.rs | 7 +-- .../crates/hir-ty/src/consteval/tests.rs | 7 ++- .../rust-analyzer/crates/hir-ty/src/infer.rs | 5 --- .../closure/analysis/expr_use_visitor.rs | 2 +- .../crates/hir-ty/src/infer/expr.rs | 25 +---------- .../crates/hir-ty/src/infer/mutability.rs | 1 - .../rust-analyzer/crates/hir-ty/src/mir.rs | 14 +----- .../crates/hir-ty/src/mir/borrowck.rs | 9 +--- .../crates/hir-ty/src/mir/eval.rs | 8 ---- .../crates/hir-ty/src/mir/eval/shim.rs | 9 ++++ .../crates/hir-ty/src/mir/lower.rs | 16 ------- .../crates/hir-ty/src/mir/monomorphization.rs | 3 -- .../crates/hir-ty/src/mir/pretty.rs | 6 --- .../crates/hir-ty/src/tests/simple.rs | 44 +++++++++++-------- .../src/handlers/mutability_errors.rs | 7 ++- 18 files changed, 59 insertions(+), 135 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store.rs index ca3ca39754bc0..32d16957ae5fa 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store.rs @@ -776,7 +776,6 @@ impl ExpressionStore { | Expr::Await { expr } | Expr::Ref { expr, mutability: _, rawness: _ } | Expr::UnaryOp { expr, op: _ } - | Expr::Box { expr } | Expr::Const(expr) => { visitor.on_expr(*expr); } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs index f5cf1180eb6e5..df4fc6e531466 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs @@ -26,8 +26,8 @@ use stdx::never; use syntax::{ AstNode, AstPtr, SyntaxNodePtr, ast::{ - self, ArrayExprKind, AstChildren, BlockExpr, ForBinder, HasArgList, HasAttrs, - HasGenericArgs, HasGenericParams, HasLoopBody, HasName, HasTypeBounds, IsString, RangeItem, + self, ArrayExprKind, AstChildren, BlockExpr, ForBinder, HasArgList, HasGenericArgs, + HasGenericParams, HasLoopBody, HasName, HasTypeBounds, IsString, RangeItem, SlicePatComponents, }, }; @@ -1460,23 +1460,13 @@ impl<'db> ExprCollector<'db> { ast::Expr::WhileExpr(e) => self.collect_while_loop(syntax_ptr, e), ast::Expr::ForExpr(e) => self.collect_for_loop(syntax_ptr, e), ast::Expr::CallExpr(e) => { - // FIXME(MINIMUM_SUPPORTED_TOOLCHAIN_VERSION): Remove this once we drop support for <1.86, https://github.com/rust-lang/rust/commit/ac9cb908ac4301dfc25e7a2edee574320022ae2c - let is_rustc_box = { - let attrs = e.attrs(); - attrs.filter_map(|it| it.as_simple_atom()).any(|it| it == "rustc_box") - }; - if is_rustc_box { - let expr = self.collect_expr_opt(e.arg_list().and_then(|it| it.args().next())); - self.alloc_expr(Expr::Box { expr }, syntax_ptr) + let callee = self.collect_expr_opt(e.expr()); + let args = if let Some(arg_list) = e.arg_list() { + arg_list.args().filter_map(|e| self.maybe_collect_expr(e)).collect() } else { - let callee = self.collect_expr_opt(e.expr()); - let args = if let Some(arg_list) = e.arg_list() { - arg_list.args().filter_map(|e| self.maybe_collect_expr(e)).collect() - } else { - Box::default() - }; - self.alloc_expr(Expr::Call { callee, args }, syntax_ptr) - } + Box::default() + }; + self.alloc_expr(Expr::Call { callee, args }, syntax_ptr) } ast::Expr::MethodCallExpr(e) => { let receiver = self.collect_expr_opt(e.receiver()); diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/pretty.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/pretty.rs index 67eb0814c7488..1c70922467e12 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/pretty.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/pretty.rs @@ -727,10 +727,6 @@ impl Printer<'_> { } self.print_expr_in(prec, *expr); } - Expr::Box { expr } => { - w!(self, "box "); - self.print_expr_in(prec, *expr); - } Expr::UnaryOp { expr, op } => { let op = match op { ast::UnaryOp::Deref => "*", diff --git a/src/tools/rust-analyzer/crates/hir-def/src/hir.rs b/src/tools/rust-analyzer/crates/hir-def/src/hir.rs index 75da190dc7e10..7e56282feb002 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/hir.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/hir.rs @@ -355,9 +355,6 @@ pub enum Expr { rawness: Rawness, mutability: Mutability, }, - Box { - expr: ExprId, - }, UnaryOp { expr: ExprId, op: UnaryOp, @@ -432,9 +429,7 @@ impl Expr { | Expr::Index { .. } | Expr::MethodCall { .. } => ExprPrecedence::Postfix, - Expr::Box { .. } | Expr::Let { .. } | Expr::UnaryOp { .. } | Expr::Ref { .. } => { - ExprPrecedence::Prefix - } + Expr::Let { .. } | Expr::UnaryOp { .. } | Expr::Ref { .. } => ExprPrecedence::Prefix, Expr::Cast { .. } => ExprPrecedence::Cast, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs index 95ebdbd4091e8..4eb8c11fac6ba 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs @@ -2217,14 +2217,17 @@ fn boxes() { use core::ops::{Deref, DerefMut}; use core::{marker::Unsize, ops::CoerceUnsized}; +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub fn box_new(_x: T) -> Box; + #[lang = "owned_box"] pub struct Box { inner: *mut T, } impl Box { fn new(t: T) -> Self { - #[rustc_box] - Box::new(t) + box_new(t) } } 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 5db5be0fd1fa0..d5ebe1ac42cda 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs @@ -2629,11 +2629,6 @@ impl<'db> InferenceContext<'db> { } } - fn resolve_boxed_box(&self) -> Option { - let struct_ = self.lang_items.OwnedBox?; - Some(struct_.into()) - } - fn resolve_range_full(&self) -> Option { let struct_ = self.lang_items.RangeFull?; Some(struct_.into()) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure/analysis/expr_use_visitor.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure/analysis/expr_use_visitor.rs index 2b771c521608c..4d300f5048a55 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure/analysis/expr_use_visitor.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure/analysis/expr_use_visitor.rs @@ -648,7 +648,7 @@ impl<'a, 'db, D: Delegate<'db>> ExprUseVisitor<'a, 'db, D> { } } - Expr::Become { expr } | Expr::Await { expr } | Expr::Box { expr } => { + Expr::Become { expr } | Expr::Await { expr } => { self.consume_expr(expr)?; } 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 b92a83ab7f8d4..20cfc9008a9e1 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 @@ -20,7 +20,7 @@ use rustc_ast_ir::Mutability; use rustc_hash::FxHashMap; use rustc_type_ir::{ InferTy, Interner, - inherent::{GenericArgs as _, IntoKind, Ty as _}, + inherent::{IntoKind, Ty as _}, }; use stdx::never; use syntax::ast::RangeOp; @@ -259,7 +259,6 @@ impl<'db> InferenceContext<'db> { | Expr::Await { .. } | Expr::Ref { .. } | Expr::Range { .. } - | Expr::Box { .. } | Expr::RecordLit { .. } | Expr::Yeet { .. } | Expr::Missing @@ -621,7 +620,6 @@ impl<'db> InferenceContext<'db> { expected, tgt_expr, ), - &Expr::Box { expr } => self.infer_expr_box(expr, expected), Expr::UnaryOp { expr, op } => self.infer_unop_expr(*op, *expr, expected, tgt_expr), Expr::BinaryOp { lhs, rhs, op } => match op { Some(BinaryOp::Assignment { op: Some(op) }) => { @@ -1485,27 +1483,6 @@ impl<'db> InferenceContext<'db> { self.types.types.never } - fn infer_expr_box(&mut self, inner_expr: ExprId, expected: &Expectation<'db>) -> Ty<'db> { - if let Some(box_id) = self.resolve_boxed_box() { - let table = &mut self.table; - let inner_exp = expected - .to_option(table) - .as_ref() - .and_then(|e| e.as_adt()) - .filter(|(e_adt, _)| e_adt == &box_id) - .map(|(_, subts)| { - let g = subts.type_at(0); - Expectation::rvalue_hint(self, g) - }) - .unwrap_or_else(Expectation::none); - - let inner_ty = self.infer_expr_inner(inner_expr, &inner_exp, ExprIsRead::Yes); - Ty::new_box(self.interner(), inner_ty) - } else { - self.err_ty() - } - } - fn infer_block( &mut self, expr: ExprId, 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 9ec297f5f5e4e..7d285a3a21028 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 @@ -159,7 +159,6 @@ impl<'db> InferenceContext<'db> { | Expr::Range { lhs: Some(expr), rhs: None, range_type: _ } | Expr::Range { rhs: Some(expr), lhs: None, range_type: _ } | Expr::Await { expr } - | Expr::Box { expr } | Expr::Loop { body: expr, label: _, source: _ } | Expr::Cast { expr, type_ref: _ } => { self.infer_mut_expr(*expr, Mutability::Not); 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 976f88601ed73..fe4b383fbe672 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs @@ -994,16 +994,6 @@ pub enum Rvalue { /// coroutine lowering, `Coroutine` aggregate kinds are disallowed too. Aggregate(AggregateKind, Box<[Operand]>), - /// Transmutes a `*mut u8` into shallow-initialized `Box`. - /// - /// This is different from a normal transmute because dataflow analysis will treat the box as - /// initialized but its content as uninitialized. Like other pointer casts, this in general - /// affects alias analysis. - ShallowInitBox(Operand, StoredTy), - - /// NON STANDARD: allocates memory with the type's layout, and shallow init the box with the resulting pointer. - ShallowInitBoxWithAlloc(StoredTy), - /// A CopyForDeref is equivalent to a read from a place at the /// codegen level, but is treated specially by drop elaboration. When such a read happens, it /// is guaranteed (via nature of the mir_opt `Derefer` in rustc_mir_transform/src/deref_separator) @@ -1101,9 +1091,7 @@ impl MirBody<'_> { StatementKind::Assign(p, r) => { f(p); match r { - Rvalue::ShallowInitBoxWithAlloc(_) => (), - Rvalue::ShallowInitBox(o, _) - | Rvalue::UnaryOp(_, o) + Rvalue::UnaryOp(_, o) | Rvalue::Cast(_, o, _) | Rvalue::Repeat(o, _) | Rvalue::Use(o) => for_operand(o, &mut f), diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/borrowck.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/borrowck.rs index c568209541d08..e860ae8d3e01f 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/borrowck.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/borrowck.rs @@ -239,9 +239,7 @@ fn moved_out_of_ref<'db>( for statement in &block.statements { match &statement.kind { StatementKind::Assign(_, r) => match r { - Rvalue::ShallowInitBoxWithAlloc(_) => (), - Rvalue::ShallowInitBox(o, _) - | Rvalue::UnaryOp(_, o) + Rvalue::UnaryOp(_, o) | Rvalue::Cast(_, o, _) | Rvalue::Repeat(o, _) | Rvalue::Use(o) => for_operand(o, statement.span), @@ -324,9 +322,7 @@ fn partially_moved<'db>( for statement in &block.statements { match &statement.kind { StatementKind::Assign(_, r) => match r { - Rvalue::ShallowInitBoxWithAlloc(_) => (), - Rvalue::ShallowInitBox(o, _) - | Rvalue::UnaryOp(_, o) + Rvalue::UnaryOp(_, o) | Rvalue::Cast(_, o, _) | Rvalue::Repeat(o, _) | Rvalue::Use(o) => for_operand(o, statement.span), @@ -636,7 +632,6 @@ fn mutability_of_locals<'db>( record_usage_for_operand(arg, &mut result); } } - Rvalue::ShallowInitBox(_, _) | Rvalue::ShallowInitBoxWithAlloc(_) => (), Rvalue::ThreadLocalRef(n) | Rvalue::AddressOf(n) | Rvalue::BinaryOp(n) 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 ab60e81646c26..e968da5111add 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 @@ -1479,14 +1479,6 @@ impl<'a, 'db> Evaluator<'a, 'db> { let size = len * val.len(); Owned(val.iter().copied().cycle().take(size).collect()) } - Rvalue::ShallowInitBox(_, _) => not_supported!("shallow init box"), - Rvalue::ShallowInitBoxWithAlloc(ty) => { - let Some((size, align)) = self.size_align_of(ty.as_ref(), locals)? else { - not_supported!("unsized box initialization"); - }; - let addr = self.heap_allocate(size, align)?; - Owned(addr.to_bytes().to_vec()) - } Rvalue::CopyForDeref(_) => not_supported!("copy for deref"), Rvalue::Aggregate(kind, values) => { let values = values 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 9db6b365886c1..a6fb6d764f8af 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 @@ -1415,6 +1415,15 @@ impl<'a, 'db> Evaluator<'a, 'db> { self.write_memory(location_addr, &location)?; destination.write_from_bytes(self, &location_addr.to_bytes()[..ptr_size]) } + "box_new" => { + let ty = generic_args.type_at(0); + let Some((size, align)) = self.size_align_of(ty, locals)? else { + not_supported!("unsized box initialization"); + }; + let addr = self.heap_allocate(size, align)?; + self.copy_from_interval(addr, args[0].interval)?; + destination.write_from_bytes(self, &addr.to_bytes()[..self.ptr_size()]) + } _ if needs_override => not_supported!("intrinsic {name} is not implemented"), _ => return Ok(false), } 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 3a0fe6e2495ff..21c8e83bceb35 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 @@ -999,22 +999,6 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { self.push_assignment(current, place, Rvalue::Ref(bk, p.store()), expr_id.into()); Ok(Some(current)) } - Expr::Box { expr } => { - let ty = self.expr_ty_after_adjustments(*expr); - self.push_assignment( - current, - place, - Rvalue::ShallowInitBoxWithAlloc(ty.store()), - expr_id.into(), - ); - let Some((operand, current)) = self.lower_expr_to_some_operand(*expr, current)? - else { - return Ok(None); - }; - let p = place.project(ProjectionElem::Deref); - self.push_assignment(current, p, operand.into(), expr_id.into()); - Ok(Some(current)) - } Expr::Field { .. } | Expr::Index { .. } | Expr::UnaryOp { op: hir_def::hir::UnaryOp::Deref, .. } => { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/monomorphization.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/monomorphization.rs index 042dd076be75b..bb192a3856f51 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/monomorphization.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/monomorphization.rs @@ -179,9 +179,6 @@ impl<'db> Filler<'db> { super::AggregateKind::Union(_, _) => (), } } - Rvalue::ShallowInitBox(_, ty) | Rvalue::ShallowInitBoxWithAlloc(ty) => { - self.fill_ty(ty)?; - } Rvalue::Use(op) => { self.fill_operand(op)?; } 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 8893069f0c0a2..4a51b5113a436 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 @@ -490,12 +490,6 @@ impl<'a, 'db> MirPrettyCtx<'a, 'db> { self.place(p); w!(self, ")"); } - Rvalue::ShallowInitBoxWithAlloc(_) => w!(self, "ShallowInitBoxWithAlloc"), - Rvalue::ShallowInitBox(op, _) => { - w!(self, "ShallowInitBox("); - self.operand(op); - w!(self, ")"); - } Rvalue::CopyForDeref(p) => { w!(self, "CopyForDeref("); self.place(p); 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 0c57d050f383f..e8f378db3228a 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 @@ -2879,6 +2879,10 @@ unsafe impl Allocator for Global {} #[fundamental] pub struct Box(T, A); +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub fn box_new(_x: T) -> Box; + impl, U: ?Sized, A: Allocator> CoerceUnsized> for Box {} pub struct Vec(T, A); @@ -2895,8 +2899,8 @@ impl [T] { } fn test() { - let vec = <[_]>::into_vec(#[rustc_box] Box::new([1i32])); - let v: Vec> = <[_]> :: into_vec(#[rustc_box] Box::new([#[rustc_box] Box::new(Astruct)])); + let vec = <[_]>::into_vec(box_new([1i32])); + let v: Vec> = <[_]> :: into_vec(box_new([box_new(Astruct)])); } trait B{} @@ -2904,22 +2908,26 @@ struct Astruct; impl B for Astruct {} "#, expect![[r#" - 639..643 'self': Box<[T], A> - 672..704 '{ ... }': Vec - 718..888 '{ ...])); }': () - 728..731 'vec': Vec - 734..749 '<[_]>::into_vec': fn into_vec(Box<[i32], Global>) -> Vec - 734..780 '<[_]>:...i32]))': Vec - 750..779 '#[rust...1i32])': Box<[i32; 1], Global> - 772..778 '[1i32]': [i32; 1] - 773..777 '1i32': i32 - 790..791 'v': Vec, Global> - 811..828 '<[_]> ...to_vec': fn into_vec, Global>(Box<[Box], Global>) -> Vec, Global> - 811..885 '<[_]> ...ct)]))': Vec, Global> - 829..884 '#[rust...uct)])': Box<[Box; 1], Global> - 851..883 '[#[rus...ruct)]': [Box; 1] - 852..882 '#[rust...truct)': Box - 874..881 'Astruct': Astruct + 428..430 '_x': T + 733..737 'self': Box<[T], A> + 766..798 '{ ... }': Vec + 812..940 '{ ...])); }': () + 822..825 'vec': Vec + 828..843 '<[_]>::into_vec': fn into_vec(Box<[i32], Global>) -> Vec + 828..860 '<[_]>:...i32]))': Vec + 844..851 'box_new': fn box_new<[i32; 1]>([i32; 1]) -> Box<[i32; 1], Global> + 844..859 'box_new([1i32])': Box<[i32; 1], Global> + 852..858 '[1i32]': [i32; 1] + 853..857 '1i32': i32 + 870..871 'v': Vec, Global> + 891..908 '<[_]> ...to_vec': fn into_vec, Global>(Box<[Box], Global>) -> Vec, Global> + 891..937 '<[_]> ...ct)]))': Vec, Global> + 909..916 'box_new': fn box_new<[Box; 1]>([Box; 1]) -> Box<[Box; 1], Global> + 909..936 'box_ne...uct)])': Box<[Box; 1], Global> + 917..935 '[box_n...ruct)]': [Box; 1] + 918..925 'box_new': fn box_new(Astruct) -> Box + 918..934 'box_ne...truct)': Box + 926..933 'Astruct': Astruct "#]], ) } diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs index 5c6c979416da6..fa9a69c996718 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs @@ -1096,14 +1096,17 @@ fn x(t: &[u8]) { use core::ops::{Deref, DerefMut}; use core::{marker::Unsize, ops::CoerceUnsized}; +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub fn box_new(_x: T) -> Box; + #[lang = "owned_box"] pub struct Box { inner: *mut T, } impl Box { fn new(t: T) -> Self { - #[rustc_box] - Box::new(t) + box_new(t) } } From 222ac699593574fb85233e7d02948a731de1e4f1 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Sun, 26 Jul 2026 00:04:46 +0300 Subject: [PATCH 56/76] Require `MetaSized` Required since 1.88.0. --- .../crates/hir-ty/src/dyn_compatibility.rs | 18 ++---- .../hir-ty/src/tests/regression/new_solver.rs | 57 ------------------- 2 files changed, 6 insertions(+), 69 deletions(-) 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 751e1424ab679..bf7970d629d2d 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 @@ -426,15 +426,9 @@ fn receiver_is_dispatchable<'db>( return false; }; - let meta_sized_did = lang_items.MetaSized; - - // TODO: This is for supporting dyn compatibility for toolchains doesn't contain `MetaSized` - // trait. Uncomment and short circuit here once `MINIMUM_SUPPORTED_TOOLCHAIN_VERSION` - // become > 1.88.0 - // - // let Some(meta_sized_did) = meta_sized_did else { - // return false; - // }; + let Some(meta_sized_did) = lang_items.MetaSized else { + return false; + }; // Type `U` // FIXME: That seems problematic to fake a generic param like that? @@ -455,8 +449,8 @@ fn receiver_is_dispatchable<'db>( }); let trait_predicate = TraitRef::new_from_args(interner, trait_.into(), args); - let meta_sized_predicate = meta_sized_did - .map(|did| TraitRef::new(interner, did.into(), [unsized_self_ty]).upcast(interner)); + let meta_sized_predicate = + TraitRef::new(interner, meta_sized_did.into(), [unsized_self_ty]).upcast(interner); ParamEnv { clauses: Clauses::new_from_iter( @@ -465,7 +459,7 @@ fn receiver_is_dispatchable<'db>( .iter_identity() .map(Unnormalized::skip_norm_wip) .chain([unsize_predicate.upcast(interner), trait_predicate.upcast(interner)]) - .chain(meta_sized_predicate), + .chain(std::iter::once(meta_sized_predicate)), ), } }; 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 121e3959ce23a..154cddf40fdf1 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 @@ -275,63 +275,6 @@ fn debug(_: &dyn Foo) {} impl Foo for i32 {} -fn main() { - debug(&1); -}"#, - ); - - // toolchains <= 1.88.0, before sized-hierarchy. - check_no_mismatches( - r#" -#![feature(lang_items)] -#[lang = "sized"] -pub trait Sized {} - -#[lang = "unsize"] -pub trait Unsize {} - -#[lang = "coerce_unsized"] -pub trait CoerceUnsized {} - -impl<'a, T: ?Sized + Unsize, U: ?Sized> CoerceUnsized<&'a mut U> for &'a mut T {} - -impl<'a, 'b: 'a, T: ?Sized + Unsize, U: ?Sized> CoerceUnsized<&'a U> for &'b mut T {} - -impl<'a, T: ?Sized + Unsize, U: ?Sized> CoerceUnsized<*mut U> for &'a mut T {} - -impl<'a, T: ?Sized + Unsize, U: ?Sized> CoerceUnsized<*const U> for &'a mut T {} - -impl<'a, 'b: 'a, T: ?Sized + Unsize, U: ?Sized> CoerceUnsized<&'a U> for &'b T {} - -impl<'a, T: ?Sized + Unsize, U: ?Sized> CoerceUnsized<*const U> for &'a T {} - -impl, U: ?Sized> CoerceUnsized<*mut U> for *mut T {} - -impl, U: ?Sized> CoerceUnsized<*const U> for *mut T {} - -impl, U: ?Sized> CoerceUnsized<*const U> for *const T {} - -#[lang = "dispatch_from_dyn"] -pub trait DispatchFromDyn {} - -impl<'a, T: ?Sized + Unsize, U: ?Sized> DispatchFromDyn<&'a U> for &'a T {} - -impl<'a, T: ?Sized + Unsize, U: ?Sized> DispatchFromDyn<&'a mut U> for &'a mut T {} - -impl, U: ?Sized> DispatchFromDyn<*const U> for *const T {} - -impl, U: ?Sized> DispatchFromDyn<*mut U> for *mut T {} - -trait Foo { - fn bar(&self) -> u32 { - 0xCAFE - } -} - -fn debug(_: &dyn Foo) {} - -impl Foo for i32 {} - fn main() { debug(&1); }"#, From 9f6fa9b49734f21afdaa1384adfae77ca41b5507 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Sun, 26 Jul 2026 00:05:52 +0300 Subject: [PATCH 57/76] Remove `min_align_of[_val]()` intrinsic Renamed to `align_of[_val]()` in 1.89.0. --- .../rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) 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 a6fb6d764f8af..e569b32bd779f 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 @@ -733,9 +733,7 @@ impl<'a, 'db> Evaluator<'a, 'db> { let size = self.size_of_sized(ty, locals, "size_of arg")?; destination.write_from_bytes(self, &size.to_le_bytes()[0..destination.size]) } - // FIXME: `min_align_of` was renamed to `align_of` in Rust 1.89 - // (https://github.com/rust-lang/rust/pull/142410) - "min_align_of" | "align_of" => { + "align_of" => { let Some(ty) = generic_args.as_slice().first().and_then(|it| it.ty()) else { return Err(MirEvalError::InternalError( "align_of generic arg is not provided".into(), @@ -763,9 +761,7 @@ impl<'a, 'db> Evaluator<'a, 'db> { destination.write_from_bytes(self, &size.to_le_bytes()) } } - // FIXME: `min_align_of_val` was renamed to `align_of_val` in Rust 1.89 - // (https://github.com/rust-lang/rust/pull/142410) - "min_align_of_val" | "align_of_val" => { + "align_of_val" => { let Some(ty) = generic_args.as_slice().first().and_then(|it| it.ty()) else { return Err(MirEvalError::InternalError( "align_of_val generic arg is not provided".into(), From b93869f9764e5ee2e31dd658a54ba867ce067a62 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Sun, 26 Jul 2026 00:12:09 +0300 Subject: [PATCH 58/76] Remove support for `None` `Op::Count` in MBE --- .../crates/mbe/src/expander/transcriber.rs | 2 +- .../rust-analyzer/crates/mbe/src/parser.rs | 48 ++++--------------- 2 files changed, 11 insertions(+), 39 deletions(-) diff --git a/src/tools/rust-analyzer/crates/mbe/src/expander/transcriber.rs b/src/tools/rust-analyzer/crates/mbe/src/expander/transcriber.rs index e135291d89dfe..440e75eb7e1b7 100644 --- a/src/tools/rust-analyzer/crates/mbe/src/expander/transcriber.rs +++ b/src/tools/rust-analyzer/crates/mbe/src/expander/transcriber.rs @@ -275,7 +275,7 @@ fn expand_subtree( } } - let res = count(binding, 0, depth.unwrap_or(0)); + let res = count(binding, 0, *depth); builder.push(tt::Leaf::Literal(tt::Literal { text_and_suffix: sym::Integer::get(res), diff --git a/src/tools/rust-analyzer/crates/mbe/src/parser.rs b/src/tools/rust-analyzer/crates/mbe/src/parser.rs index 9fbd06cf88626..7c3d451d04650 100644 --- a/src/tools/rust-analyzer/crates/mbe/src/parser.rs +++ b/src/tools/rust-analyzer/crates/mbe/src/parser.rs @@ -92,39 +92,14 @@ impl MetaTemplate { #[derive(Clone, Debug, PartialEq, Eq)] pub(crate) enum Op { - Var { - name: Symbol, - kind: Option, - id: Span, - }, - Ignore { - name: Symbol, - id: Span, - }, - Index { - depth: usize, - }, - Len { - depth: usize, - }, - Count { - name: Symbol, - // FIXME: `usize` once we drop support for 1.76 - depth: Option, - }, - Concat { - elements: Box<[ConcatMetaVarExprElem]>, - span: Span, - }, - Repeat { - tokens: MetaTemplate, - kind: RepeatKind, - separator: Option>, - }, - Subtree { - tokens: MetaTemplate, - delimiter: tt::Delimiter, - }, + Var { name: Symbol, kind: Option, id: Span }, + Ignore { name: Symbol, id: Span }, + Index { depth: usize }, + Len { depth: usize }, + Count { name: Symbol, depth: usize }, + Concat { elements: Box<[ConcatMetaVarExprElem]>, span: Span }, + Repeat { tokens: MetaTemplate, kind: RepeatKind, separator: Option> }, + Subtree { tokens: MetaTemplate, delimiter: tt::Delimiter }, Literal(tt::Literal), Punct(Box>), Ident(tt::Ident), @@ -432,11 +407,8 @@ fn parse_metavar_expr(src: &mut TtIter<'_>) -> Result { s if sym::count == *s => { args_iter.expect_dollar()?; let ident = args_iter.expect_ident()?; - let depth = if try_eat_comma(&mut args_iter) { - Some(parse_depth(&mut args_iter)?) - } else { - None - }; + let depth = + if try_eat_comma(&mut args_iter) { parse_depth(&mut args_iter)? } else { 0 }; Op::Count { name: ident.sym.clone(), depth } } s if sym::concat == *s => { From 679271e9bc41ede89af3dfb9a783d23e8249eed8 Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Sun, 26 Jul 2026 06:02:43 +0530 Subject: [PATCH 59/76] replace detach with delete in edit --- src/tools/rust-analyzer/crates/syntax/src/ast/edit.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/edit.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/edit.rs index eaa36903bf26f..080f9a7c6b175 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/edit.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/edit.rs @@ -200,7 +200,7 @@ impl ast::IdentPat { if let Some(last) = self.syntax().last_token().filter(|it| it.kind() == WHITESPACE) { - last.detach(); + editor.delete(last); } } } From 641ff3c225de0529081911c46939b27f5aa0eb7f Mon Sep 17 00:00:00 2001 From: shulaoda <165626830+shulaoda@users.noreply.github.com> Date: Sun, 26 Jul 2026 15:04:24 +0800 Subject: [PATCH 60/76] fix: don't offer `replace_qualified_name_with_use` on an unqualified path --- .../replace_qualified_name_with_use.rs | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_qualified_name_with_use.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_qualified_name_with_use.rs index 0bd1ec12d06c2..d7f00bf669cce 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_qualified_name_with_use.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_qualified_name_with_use.rs @@ -40,6 +40,12 @@ pub(crate) fn replace_qualified_name_with_use( let original_path = target_path(ctx, original_path)?; + // There is no qualifier to replace, so there is nothing for this assist to do + if original_path.qualifier().is_none() { + cov_mark::hit!(not_applicable_for_unqualified_path); + return None; + } + // then search for an import for the first path segment of what we want to replace // that way it is less likely that we import the item from a different location due re-exports let module = match ctx.sema.resolve_path(&original_path.first_qualifier_or_self())? { @@ -250,6 +256,22 @@ fs::Path check_assist_not_applicable(replace_qualified_name_with_use, r"use std::fmt$0;"); } + #[test] + fn test_replace_not_applicable_for_unqualified_path() { + cov_mark::check!(not_applicable_for_unqualified_path); + check_assist_not_applicable( + replace_qualified_name_with_use, + r" +//- /main.rs crate:main deps:sub +fn main() { + su$0b(); +} +//- /sub.rs crate:sub +pub fn sub() {} +", + ); + } + #[test] fn replaces_all_affected_paths() { check_assist( From 3aaba953a47093cb617dd2e041545f63ed9e52b4 Mon Sep 17 00:00:00 2001 From: shulaoda <165626830+shulaoda@users.noreply.github.com> Date: Sun, 26 Jul 2026 17:11:09 +0800 Subject: [PATCH 61/76] fix: prefer `alloc` over `std` paths when `preferNoStd` is set --- .../crates/hir-def/src/find_path.rs | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs b/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs index 2f502e49157c2..daece7fc5d566 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs @@ -407,6 +407,10 @@ fn find_in_sysroot<'db>( if matches!(best_choice, Some(Choice { stability: Stable, .. })) { return; } + search(LangCrateOrigin::Alloc, best_choice); + if matches!(best_choice, Some(Choice { stability: Stable, .. })) { + return; + } search(LangCrateOrigin::Std, best_choice); if matches!(best_choice, Some(Choice { stability: Stable, .. })) { return; @@ -420,6 +424,10 @@ fn find_in_sysroot<'db>( if matches!(best_choice, Some(Choice { stability: Stable, .. })) { return; } + search(LangCrateOrigin::Alloc, best_choice); + if matches!(best_choice, Some(Choice { stability: Stable, .. })) { + return; + } } dependencies .iter() @@ -1570,6 +1578,43 @@ pub mod sync { //- /zzz.rs crate:alloc +pub mod sync { + pub struct Arc; +} + "#, + "alloc::sync::Arc", + expect![[r#" + Plain (imports ✔): alloc::sync::Arc + Plain (imports ✖): alloc::sync::Arc + ByCrate(imports ✔): alloc::sync::Arc + ByCrate(imports ✖): alloc::sync::Arc + BySelf (imports ✔): alloc::sync::Arc + BySelf (imports ✖): alloc::sync::Arc + "#]], + ); + } + + #[test] + fn prefer_alloc_paths_over_std_with_extern_crate_std() { + check_found_path( + r#" +//- /main.rs crate:main deps:alloc,std +#![no_std] + +extern crate alloc; + +extern crate std; + +$0 + +//- /std.rs crate:std deps:alloc + +pub mod sync { + pub use alloc::sync::Arc; +} + +//- /zzz.rs crate:alloc + pub mod sync { pub struct Arc; } From 5d1d4b368c8fdf613f57dc71c35e03ffb537c85f Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sun, 26 Jul 2026 16:43:20 +0200 Subject: [PATCH 62/76] fix: Fix `.zip(None)` call --- .../crates/hir-ty/src/next_solver/generics.rs | 2 +- .../crates/hir-ty/src/tests/coercion.rs | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) 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 e0a69a6602f3a..9558a8b2b3128 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 @@ -96,7 +96,7 @@ impl<'db> Generics<'db> { (id, None) } }) - .chain(self.additional_param.zip(None)) + .chain(self.additional_param.map(|param| (param, None))) } } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/coercion.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/coercion.rs index db06d55278b2b..6d4ad930702df 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/coercion.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/coercion.rs @@ -87,6 +87,24 @@ fn test(a: A<[u8; 2]>, b: B<[u8; 2]>, c: C<[u8; 2]>) { ); } +#[test] +fn coerce_pointee_derive() { + check_no_mismatches( + r#" +//- minicore: coerce_pointee +use core::marker::CoercePointee; + +#[derive(CoercePointee)] +#[repr(transparent)] +struct Pointer(*const T); + +fn coerce(value: Pointer<[u8; 1]>) -> Pointer<[u8]> { + value +} +"#, + ); +} + #[test] fn unsized_from_keeps_type_info() { check_types( From 573bd7d4ada3677648942e644f0894de7d22ac14 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sun, 26 Jul 2026 16:59:05 +0200 Subject: [PATCH 63/76] Add regression test for rust-lang/rust-analyzer#22913 --- .../hir-ty/src/tests/regression/new_solver.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) 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 121e3959ce23a..7cb0ec3586f52 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 @@ -10,6 +10,23 @@ use crate::{ tests::{check_infer, check_no_mismatches, check_types}, }; +#[test] +fn nested_argument_position_impl_trait_captures_lifetime() { + check_no_mismatches( + r#" +//- minicore: iterator +trait Trait<'a> {} + +fn f<'a>(_values: impl IntoIterator>) {} + +fn crash<'a>(expr: &'a (), values: impl IntoIterator>) -> &'a () { + f(values); + expr +} +"#, + ); +} + #[test] fn liberating_distinct_late_bound_lifetimes_preserves_identity() { let (db, file_id) = TestDB::with_single_file( From 04e90a4ae8435eaccbd0361ee18fd31b8cc56cb4 Mon Sep 17 00:00:00 2001 From: shulaoda <165626830+shulaoda@users.noreply.github.com> Date: Mon, 27 Jul 2026 00:35:27 +0800 Subject: [PATCH 64/76] fix: give `impl_trait_with_diagnostics` a cycle result --- src/tools/rust-analyzer/crates/hir-ty/src/lower.rs | 10 +++++++++- .../crates/hir-ty/src/tests/regression.rs | 13 +++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) 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 35cddf109a8e4..bdb882b70b259 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs @@ -1463,7 +1463,7 @@ pub(crate) fn impl_trait_query<'db>( .map(|it| it.value.get(DbInterner::new_no_crate(db))) } -#[salsa::tracked(returns(ref))] +#[salsa::tracked(returns(ref), cycle_result = impl_trait_with_diagnostics_cycle_result)] pub(crate) fn impl_trait_with_diagnostics<'db>( db: &'db dyn HirDatabase, impl_id: ImplId, @@ -1487,6 +1487,14 @@ pub(crate) fn impl_trait_with_diagnostics<'db>( Some(TyLoweringResult::from_ctx(StoredEarlyBinder::bind(StoredTraitRef::new(trait_ref)), ctx)) } +pub(crate) fn impl_trait_with_diagnostics_cycle_result<'db>( + _db: &'db dyn HirDatabase, + _: salsa::Id, + _impl_id: ImplId, +) -> Option>> { + None +} + impl ImplTraitId { #[inline] pub fn predicates<'db>(self, db: &'db dyn HirDatabase) -> EarlyBinder<'db, &'db [Clause<'db>]> { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs index 0d08c75aad738..c580841244f1b 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs @@ -3003,3 +3003,16 @@ fn f() {[_; || ()]} "#, ); } + +#[test] +fn regression_22795() { + check_no_mismatches( + r#" +trait T { fn m(&self); } +impl T for Self::Self {} +struct S; +impl T for S { fn m(&self) {} } +fn f(s: S) { s.m(); } + "#, + ); +} From 02a54aa3edbec5c1bdec33d16095be2ebf9be846 Mon Sep 17 00:00:00 2001 From: panstromek Date: Sun, 26 Jul 2026 18:51:04 +0200 Subject: [PATCH 65/76] update thinvec to latest version --- Cargo.lock | 4 ++-- compiler/rustc_ast/Cargo.toml | 2 +- compiler/rustc_ast_lowering/Cargo.toml | 2 +- compiler/rustc_ast_pretty/Cargo.toml | 2 +- compiler/rustc_attr_parsing/Cargo.toml | 2 +- compiler/rustc_builtin_macros/Cargo.toml | 2 +- compiler/rustc_data_structures/Cargo.toml | 2 +- compiler/rustc_expand/Cargo.toml | 2 +- compiler/rustc_hir/Cargo.toml | 2 +- compiler/rustc_infer/Cargo.toml | 2 +- compiler/rustc_middle/Cargo.toml | 2 +- compiler/rustc_parse/Cargo.toml | 2 +- compiler/rustc_resolve/Cargo.toml | 2 +- compiler/rustc_serialize/Cargo.toml | 2 +- compiler/rustc_trait_selection/Cargo.toml | 2 +- compiler/rustc_type_ir/Cargo.toml | 2 +- 16 files changed, 17 insertions(+), 17 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f55daf9e01c5f..0c2124cb19649 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5574,9 +5574,9 @@ dependencies = [ [[package]] name = "thin-vec" -version = "0.2.18" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0f7e269b48f0a7dd0146680fa24b50cc67fc0373f086a5b2f99bd084639b482" +checksum = "79def32ffcd477db1ff26f76dab9e3a91f0bd42a85ca96577089b24623056f9d" [[package]] name = "thiserror" diff --git a/compiler/rustc_ast/Cargo.toml b/compiler/rustc_ast/Cargo.toml index c60f666d3bfad..fc9118f593ce5 100644 --- a/compiler/rustc_ast/Cargo.toml +++ b/compiler/rustc_ast/Cargo.toml @@ -15,6 +15,6 @@ rustc_macros = { path = "../rustc_macros" } rustc_serialize = { path = "../rustc_serialize" } rustc_span = { path = "../rustc_span" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } -thin-vec = "0.2.18" +thin-vec = "0.2.19" tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_ast_lowering/Cargo.toml b/compiler/rustc_ast_lowering/Cargo.toml index 0fefc0d9220a3..f7128e66193a8 100644 --- a/compiler/rustc_ast_lowering/Cargo.toml +++ b/compiler/rustc_ast_lowering/Cargo.toml @@ -22,6 +22,6 @@ rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } -thin-vec = "0.2.18" +thin-vec = "0.2.19" tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_ast_pretty/Cargo.toml b/compiler/rustc_ast_pretty/Cargo.toml index b33f41eb302c0..690d1cfd6f0f5 100644 --- a/compiler/rustc_ast_pretty/Cargo.toml +++ b/compiler/rustc_ast_pretty/Cargo.toml @@ -13,5 +13,5 @@ rustc_span = { path = "../rustc_span" } [dev-dependencies] # tidy-alphabetical-start -thin-vec = "0.2.18" +thin-vec = "0.2.19" # tidy-alphabetical-end diff --git a/compiler/rustc_attr_parsing/Cargo.toml b/compiler/rustc_attr_parsing/Cargo.toml index 2e8c912609b2e..7542cb4bbec26 100644 --- a/compiler/rustc_attr_parsing/Cargo.toml +++ b/compiler/rustc_attr_parsing/Cargo.toml @@ -20,5 +20,5 @@ rustc_parse_format = { path = "../rustc_parse_format" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } -thin-vec = "0.2.18" +thin-vec = "0.2.19" # tidy-alphabetical-end diff --git a/compiler/rustc_builtin_macros/Cargo.toml b/compiler/rustc_builtin_macros/Cargo.toml index f5dbc4a0d7cbe..624f4ffea6ffc 100644 --- a/compiler/rustc_builtin_macros/Cargo.toml +++ b/compiler/rustc_builtin_macros/Cargo.toml @@ -29,7 +29,7 @@ rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } -thin-vec = "0.2.18" +thin-vec = "0.2.19" tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml index 6db3a624500a9..f8d26f8773018 100644 --- a/compiler/rustc_data_structures/Cargo.toml +++ b/compiler/rustc_data_structures/Cargo.toml @@ -30,7 +30,7 @@ smallvec = { version = "1.8.1", features = [ ] } stacker = "0.1.17" tempfile = "3.2" -thin-vec = "0.2.18" +thin-vec = "0.2.19" tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_expand/Cargo.toml b/compiler/rustc_expand/Cargo.toml index 068c84da719a3..2b8dc55012616 100644 --- a/compiler/rustc_expand/Cargo.toml +++ b/compiler/rustc_expand/Cargo.toml @@ -30,6 +30,6 @@ rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } scoped-tls = "1.0" smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } -thin-vec = "0.2.18" +thin-vec = "0.2.19" tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_hir/Cargo.toml b/compiler/rustc_hir/Cargo.toml index 5765163af6e41..0d4a8c73e971e 100644 --- a/compiler/rustc_hir/Cargo.toml +++ b/compiler/rustc_hir/Cargo.toml @@ -23,6 +23,6 @@ rustc_serialize = { path = "../rustc_serialize" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } -thin-vec = "0.2.18" +thin-vec = "0.2.19" tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_infer/Cargo.toml b/compiler/rustc_infer/Cargo.toml index 33f7e2f38f765..e9c007f5e1829 100644 --- a/compiler/rustc_infer/Cargo.toml +++ b/compiler/rustc_infer/Cargo.toml @@ -17,6 +17,6 @@ rustc_middle = { path = "../rustc_middle" } rustc_span = { path = "../rustc_span" } rustc_type_ir = { path = "../rustc_type_ir" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } -thin-vec = "0.2.18" +thin-vec = "0.2.19" tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_middle/Cargo.toml b/compiler/rustc_middle/Cargo.toml index 6ead1c5ea46a3..f624fcee78f59 100644 --- a/compiler/rustc_middle/Cargo.toml +++ b/compiler/rustc_middle/Cargo.toml @@ -33,7 +33,7 @@ rustc_target = { path = "../rustc_target" } rustc_thread_pool = { path = "../rustc_thread_pool" } rustc_type_ir = { path = "../rustc_type_ir" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } -thin-vec = "0.2.18" +thin-vec = "0.2.19" tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_parse/Cargo.toml b/compiler/rustc_parse/Cargo.toml index 768a9546cccd4..f6bff621d7db8 100644 --- a/compiler/rustc_parse/Cargo.toml +++ b/compiler/rustc_parse/Cargo.toml @@ -17,7 +17,7 @@ rustc_lexer = { path = "../rustc_lexer" } rustc_macros = { path = "../rustc_macros" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } -thin-vec = "0.2.18" +thin-vec = "0.2.19" tracing = "0.1" unicode-normalization = "0.1.25" unicode-width = "0.2.2" diff --git a/compiler/rustc_resolve/Cargo.toml b/compiler/rustc_resolve/Cargo.toml index a1d61d0d9f2f0..bafff3ec66022 100644 --- a/compiler/rustc_resolve/Cargo.toml +++ b/compiler/rustc_resolve/Cargo.toml @@ -26,6 +26,6 @@ rustc_middle = { path = "../rustc_middle" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } -thin-vec = "0.2.18" +thin-vec = "0.2.19" tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_serialize/Cargo.toml b/compiler/rustc_serialize/Cargo.toml index 4e11d8726c84f..e1b14360f1262 100644 --- a/compiler/rustc_serialize/Cargo.toml +++ b/compiler/rustc_serialize/Cargo.toml @@ -8,7 +8,7 @@ edition = "2024" indexmap = "2.0.0" rustc_hashes = { path = "../rustc_hashes" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } -thin-vec = "0.2.18" +thin-vec = "0.2.19" # tidy-alphabetical-end [dev-dependencies] diff --git a/compiler/rustc_trait_selection/Cargo.toml b/compiler/rustc_trait_selection/Cargo.toml index 0cd9128762cbc..ae231c217977d 100644 --- a/compiler/rustc_trait_selection/Cargo.toml +++ b/compiler/rustc_trait_selection/Cargo.toml @@ -19,6 +19,6 @@ rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } rustc_transmute = { path = "../rustc_transmute", features = ["rustc"] } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } -thin-vec = "0.2.18" +thin-vec = "0.2.19" tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_type_ir/Cargo.toml b/compiler/rustc_type_ir/Cargo.toml index 97cddd857af18..19afebe4e2a07 100644 --- a/compiler/rustc_type_ir/Cargo.toml +++ b/compiler/rustc_type_ir/Cargo.toml @@ -23,7 +23,7 @@ rustc_type_ir_macros = { path = "../rustc_type_ir_macros" } smallvec = { version = "1.8.1", default-features = false, features = [ "const_generics", ] } -thin-vec = "0.2.18" +thin-vec = "0.2.19" tracing = "0.1" # tidy-alphabetical-end From 4a7d5c8abd02bbba1322e52ffacc1d08af278a25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 27 Jul 2026 08:17:24 +0000 Subject: [PATCH 66/76] On many bindings with move error, limit the number of `Span`s When a "can't move out of" error would point at too many places, limit the number of spans so that we don't span the terminal. ``` error[E0507]: cannot move out of `f` as enum variant `Foo1` which is behind a shared reference --> $DIR/borrowck-move-error-many-places.rs:15:11 | LL | match *f { | ^^ LL | Foo::Foo1(num1, | ---- data moved here LL | num2) => (), | ---- ...and here LL | Foo::Foo2(num) => (), | --- ...and here LL | Foo::Foo3(num) => (), | --- ...and here LL | Foo::Foo4(num) => (), | --- ...and here | = note: ...and 4 other places = note: move occurs because these variables have types that don't implement the `Copy` trait help: consider removing the dereference here | LL - match *f { LL + match f { | ``` --- .../src/diagnostics/move_errors.rs | 3 ++ .../borrowck-move-error-many-places.rs | 28 +++++++++++++++++++ .../borrowck-move-error-many-places.stderr | 27 ++++++++++++++++++ 3 files changed, 58 insertions(+) create mode 100644 tests/ui/borrowck/borrowck-move-error-many-places.rs create mode 100644 tests/ui/borrowck/borrowck-move-error-many-places.stderr diff --git a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs index 360df2e609a8a..ed4e25f009aed 100644 --- a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs @@ -1243,6 +1243,9 @@ impl<'diag, 'tcx> MirBorrowckCtxt<'_, 'diag, 'tcx> { } } else if j == 0 { err.span_label(binding_span, "data moved here"); + } else if j == 5 && binds_to.len() > 6 && !self.infcx.tcx.sess.opts.verbose { + err.note(format!("...and {} other places", binds_to.len() - 5)); + break; } else { err.span_label(binding_span, "...and here"); } diff --git a/tests/ui/borrowck/borrowck-move-error-many-places.rs b/tests/ui/borrowck/borrowck-move-error-many-places.rs new file mode 100644 index 0000000000000..db504ea20c2d2 --- /dev/null +++ b/tests/ui/borrowck/borrowck-move-error-many-places.rs @@ -0,0 +1,28 @@ +#![allow(unused)] +enum Foo { + Foo1(Box, Box), + Foo2(Box), + Foo3(Box), + Foo4(Box), + Foo5(Box), + Foo6(Box), + Foo7(Box), + Foo8(Box), +} + +fn blah() { + let f = &Foo::Foo1(Box::new(1), Box::new(2)); + match *f { //~ ERROR cannot move out of + Foo::Foo1(num1, + num2) => (), + Foo::Foo2(num) => (), + Foo::Foo3(num) => (), + Foo::Foo4(num) => (), + Foo::Foo5(num) => (), + Foo::Foo6(num) => (), + Foo::Foo7(num) => (), + Foo::Foo8(num) => (), + } +} + +fn main() {} diff --git a/tests/ui/borrowck/borrowck-move-error-many-places.stderr b/tests/ui/borrowck/borrowck-move-error-many-places.stderr new file mode 100644 index 0000000000000..a35f5f7e410dc --- /dev/null +++ b/tests/ui/borrowck/borrowck-move-error-many-places.stderr @@ -0,0 +1,27 @@ +error[E0507]: cannot move out of `f` as enum variant `Foo1` which is behind a shared reference + --> $DIR/borrowck-move-error-many-places.rs:15:11 + | +LL | match *f { + | ^^ +LL | Foo::Foo1(num1, + | ---- data moved here +LL | num2) => (), + | ---- ...and here +LL | Foo::Foo2(num) => (), + | --- ...and here +LL | Foo::Foo3(num) => (), + | --- ...and here +LL | Foo::Foo4(num) => (), + | --- ...and here + | + = note: ...and 4 other places + = note: move occurs because these variables have types that don't implement the `Copy` trait +help: consider removing the dereference here + | +LL - match *f { +LL + match f { + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0507`. From 326568154571b526633eaa77ed9247778866e46c Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 27 Jul 2026 11:32:43 +0200 Subject: [PATCH 67/76] Fix lint warning --- library/unwind/src/libunwind.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/library/unwind/src/libunwind.rs b/library/unwind/src/libunwind.rs index 8e45e0cf543d3..bfa6b1b33008f 100644 --- a/library/unwind/src/libunwind.rs +++ b/library/unwind/src/libunwind.rs @@ -165,11 +165,9 @@ cfg_select! { pub unsafe fn _Unwind_GetIPInfo(ctx: *mut _Unwind_Context, ip_before_insn: *mut c_int) -> _Unwind_Word { - unsafe { - *ip_before_insn = 0; - let val = unsafe { _Unwind_GetGR(ctx, UNWIND_IP_REG) }; - val.map_addr(|v| v & !1) - } + unsafe { *ip_before_insn = 0 }; + let val = unsafe { _Unwind_GetGR(ctx, UNWIND_IP_REG) }; + val.map_addr(|v| v & !1) } } } From 4c61167ed3d15ff21484b629e2988b5fa0740a5b Mon Sep 17 00:00:00 2001 From: Amirhossein Akhlaghpour Date: Mon, 27 Jul 2026 13:32:09 +0330 Subject: [PATCH 68/76] tests: use explicit dyn trait object Signed-off-by: Amirhossein Akhlaghpour --- .../lower-universe-resolved-const-issue-159703.rs | 5 +---- ...lower-universe-resolved-const-issue-159703.stderr | 12 ++++++------ 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/tests/ui/traits/next-solver/lower-universe-resolved-const-issue-159703.rs b/tests/ui/traits/next-solver/lower-universe-resolved-const-issue-159703.rs index 56aff9211f789..6a28115ad32f0 100644 --- a/tests/ui/traits/next-solver/lower-universe-resolved-const-issue-159703.rs +++ b/tests/ui/traits/next-solver/lower-universe-resolved-const-issue-159703.rs @@ -1,7 +1,4 @@ //@ compile-flags: -Znext-solver=globally -//@ edition: 2015 - -#![allow(bare_trait_objects)] trait Foo {} @@ -10,7 +7,7 @@ struct BarType; impl Foo for BarType {} //~^ ERROR missing generics for struct `BarType` -fn a(x: &Foo) { +fn a(x: &dyn Foo) { let bar = BarType; a(bar); //~^ ERROR mismatched types diff --git a/tests/ui/traits/next-solver/lower-universe-resolved-const-issue-159703.stderr b/tests/ui/traits/next-solver/lower-universe-resolved-const-issue-159703.stderr index 3324d2a037c22..d3658748846c6 100644 --- a/tests/ui/traits/next-solver/lower-universe-resolved-const-issue-159703.stderr +++ b/tests/ui/traits/next-solver/lower-universe-resolved-const-issue-159703.stderr @@ -1,11 +1,11 @@ error[E0107]: missing generics for struct `BarType` - --> $DIR/lower-universe-resolved-const-issue-159703.rs:10:30 + --> $DIR/lower-universe-resolved-const-issue-159703.rs:7:30 | LL | impl Foo for BarType {} | ^^^^^^^ expected 1 generic argument | note: struct defined here, with 1 generic parameter: `N` - --> $DIR/lower-universe-resolved-const-issue-159703.rs:8:8 + --> $DIR/lower-universe-resolved-const-issue-159703.rs:5:8 | LL | struct BarType; | ^^^^^^^ -------------- @@ -15,7 +15,7 @@ LL | impl Foo for BarType {} | +++ error[E0308]: mismatched types - --> $DIR/lower-universe-resolved-const-issue-159703.rs:15:7 + --> $DIR/lower-universe-resolved-const-issue-159703.rs:12:7 | LL | a(bar); | - ^^^ expected `&dyn Foo`, found `BarType<_>` @@ -25,10 +25,10 @@ LL | a(bar); = note: expected reference `&dyn Foo` found struct `BarType<_>` note: function defined here - --> $DIR/lower-universe-resolved-const-issue-159703.rs:13:4 + --> $DIR/lower-universe-resolved-const-issue-159703.rs:10:4 | -LL | fn a(x: &Foo) { - | ^ ------- +LL | fn a(x: &dyn Foo) { + | ^ ----------- help: consider borrowing here | LL | a(&bar); From 87a3711bee27e618388a0f8cb4ca0ee20a529eac Mon Sep 17 00:00:00 2001 From: Evgenii Zheltonozhskii Date: Mon, 27 Jul 2026 14:23:23 +0300 Subject: [PATCH 69/76] Fix the const impl suggestion --- .../traits/fulfillment_errors.rs | 6 ++-- tests/ui/comptime/comptime_impl.stderr | 8 ++--- .../const-traits/assoc-type.current.stderr | 4 +-- .../const-traits/assoc-type.next.stderr | 4 +-- .../call-const-closure.next.stderr | 4 +-- .../call-const-closure.old.stderr | 4 +-- .../call-const-trait-method-fail.rs | 30 +++++++++++++++++++ .../call-const-trait-method-fail.stderr | 19 +++++++++--- .../call-generic-method-nonconst.stderr | 4 +-- .../const-closure-trait-method-fail.stderr | 4 +-- .../const-default-method-bodies.stderr | 4 +-- .../const-drop-fail-2.precise.stderr | 4 +-- .../const-drop-fail-2.stock.stderr | 4 +-- .../const-traits/const-opaque.no.stderr | 8 ++--- ...-method-body-is-const-body-checking.stderr | 4 +-- ...-method-body-is-const-same-trait-ck.stderr | 4 +-- .../item-bound-entailment-fails.stderr | 4 +-- .../const-traits/minicore-deref-fail.stderr | 4 +-- .../const-traits/minicore-fn-fail.stderr | 4 +-- .../no-explicit-const-params.stderr | 4 +-- .../specializing-constness-2.stderr | 4 +-- .../const-traits/super-traits-fail.stderr | 4 +-- 22 files changed, 90 insertions(+), 49 deletions(-) diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index 8af061168a865..5f456edb8d7f6 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -949,12 +949,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } } else if let Some(impl_did) = impl_did.as_local() && let item = self.tcx.hir_expect_item(impl_did) - && let hir::ItemKind::Impl(item) = item.kind - && let Some(of_trait) = item.of_trait + && let hir::ItemKind::Impl(impl_) = item.kind + && impl_.of_trait.is_some() { // trait is const, impl is local and not const diag.span_suggestion_verbose( - of_trait.trait_ref.path.span.shrink_to_lo(), + item.span.shrink_to_lo(), format!("make the `impl` of trait `{trait_name}` `const`"), "const ".to_string(), Applicability::MaybeIncorrect, diff --git a/tests/ui/comptime/comptime_impl.stderr b/tests/ui/comptime/comptime_impl.stderr index 4231df305cfc1..4c55736c0bb63 100644 --- a/tests/ui/comptime/comptime_impl.stderr +++ b/tests/ui/comptime/comptime_impl.stderr @@ -14,8 +14,8 @@ LL | Bar.foo(); | help: make the `impl` of trait `Foo` `const` | -LL | impl const Foo for Bar { - | +++++ +LL | const impl Foo for Bar { + | +++++ error[E0277]: the trait bound `Bar: const Foo` is not satisfied --> $DIR/comptime_impl.rs:31:9 @@ -25,8 +25,8 @@ LL | Bar.bar(); | help: make the `impl` of trait `Foo` `const` | -LL | impl const Foo for Bar { - | +++++ +LL | const impl Foo for Bar { + | +++++ error: aborting due to 3 previous errors diff --git a/tests/ui/traits/const-traits/assoc-type.current.stderr b/tests/ui/traits/const-traits/assoc-type.current.stderr index b730fd8ad3662..f66e9e03b0754 100644 --- a/tests/ui/traits/const-traits/assoc-type.current.stderr +++ b/tests/ui/traits/const-traits/assoc-type.current.stderr @@ -11,8 +11,8 @@ LL | type Bar: [const] Add; | ^^^^^^^^^^^ required by this bound in `Foo::Bar` help: make the `impl` of trait `Add` `const` | -LL | impl const Add for NonConstAdd { - | +++++ +LL | const impl Add for NonConstAdd { + | +++++ error: aborting due to 1 previous error diff --git a/tests/ui/traits/const-traits/assoc-type.next.stderr b/tests/ui/traits/const-traits/assoc-type.next.stderr index b730fd8ad3662..f66e9e03b0754 100644 --- a/tests/ui/traits/const-traits/assoc-type.next.stderr +++ b/tests/ui/traits/const-traits/assoc-type.next.stderr @@ -11,8 +11,8 @@ LL | type Bar: [const] Add; | ^^^^^^^^^^^ required by this bound in `Foo::Bar` help: make the `impl` of trait `Add` `const` | -LL | impl const Add for NonConstAdd { - | +++++ +LL | const impl Add for NonConstAdd { + | +++++ error: aborting due to 1 previous error diff --git a/tests/ui/traits/const-traits/call-const-closure.next.stderr b/tests/ui/traits/const-traits/call-const-closure.next.stderr index 9a851a97f186a..bdea41585c666 100644 --- a/tests/ui/traits/const-traits/call-const-closure.next.stderr +++ b/tests/ui/traits/const-traits/call-const-closure.next.stderr @@ -6,8 +6,8 @@ LL | (const || ().foo())(); | help: make the `impl` of trait `Bar` `const` | -LL | impl const Bar for () { - | +++++ +LL | const impl Bar for () { + | +++++ error: aborting due to 1 previous error diff --git a/tests/ui/traits/const-traits/call-const-closure.old.stderr b/tests/ui/traits/const-traits/call-const-closure.old.stderr index 9a851a97f186a..bdea41585c666 100644 --- a/tests/ui/traits/const-traits/call-const-closure.old.stderr +++ b/tests/ui/traits/const-traits/call-const-closure.old.stderr @@ -6,8 +6,8 @@ LL | (const || ().foo())(); | help: make the `impl` of trait `Bar` `const` | -LL | impl const Bar for () { - | +++++ +LL | const impl Bar for () { + | +++++ error: aborting due to 1 previous error diff --git a/tests/ui/traits/const-traits/call-const-trait-method-fail.rs b/tests/ui/traits/const-traits/call-const-trait-method-fail.rs index dd8e3dfde4a3d..4b2165b110481 100644 --- a/tests/ui/traits/const-traits/call-const-trait-method-fail.rs +++ b/tests/ui/traits/const-traits/call-const-trait-method-fail.rs @@ -5,6 +5,11 @@ pub const trait Plus { fn plus(self, rhs: Self) -> Self; } + +pub const unsafe trait Minus { + fn minus(self, rhs: Self) -> Self; +} + const impl Plus for i32 { fn plus(self, rhs: Self) -> Self { self + rhs @@ -17,6 +22,20 @@ impl Plus for u32 { } } + +const unsafe impl Minus for i32 { + fn minus(self, rhs: Self) -> Self { + self - rhs + } +} + +unsafe impl Minus for u32 { + fn minus(self, rhs: Self) -> Self { + self - rhs + } +} + + pub const fn add_i32(a: i32, b: i32) -> i32 { a.plus(b) // ok } @@ -26,4 +45,15 @@ pub const fn add_u32(a: u32, b: u32) -> u32 { //~^ ERROR the trait bound `u32: [const] Plus` } + +pub const unsafe fn sub_i32(a: i32, b: i32) -> i32 { + a.minus(b) // ok +} + +pub const unsafe fn sub_u32(a: u32, b: u32) -> u32 { + a.minus(b) + //~^ ERROR the trait bound `u32: [const] Minus` +} + + fn main() {} diff --git a/tests/ui/traits/const-traits/call-const-trait-method-fail.stderr b/tests/ui/traits/const-traits/call-const-trait-method-fail.stderr index 6e235d9cb6f0c..7ee8a0e935555 100644 --- a/tests/ui/traits/const-traits/call-const-trait-method-fail.stderr +++ b/tests/ui/traits/const-traits/call-const-trait-method-fail.stderr @@ -1,14 +1,25 @@ error[E0277]: the trait bound `u32: [const] Plus` is not satisfied - --> $DIR/call-const-trait-method-fail.rs:25:5 + --> $DIR/call-const-trait-method-fail.rs:44:5 | LL | a.plus(b) | ^ | help: make the `impl` of trait `Plus` `const` | -LL | impl const Plus for u32 { - | +++++ +LL | const impl Plus for u32 { + | +++++ -error: aborting due to 1 previous error +error[E0277]: the trait bound `u32: [const] Minus` is not satisfied + --> $DIR/call-const-trait-method-fail.rs:54:5 + | +LL | a.minus(b) + | ^ + | +help: make the `impl` of trait `Minus` `const` + | +LL | const unsafe impl Minus for u32 { + | +++++ + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/const-traits/call-generic-method-nonconst.stderr b/tests/ui/traits/const-traits/call-generic-method-nonconst.stderr index 91d3918372601..d641e22a9a905 100644 --- a/tests/ui/traits/const-traits/call-generic-method-nonconst.stderr +++ b/tests/ui/traits/const-traits/call-generic-method-nonconst.stderr @@ -13,8 +13,8 @@ LL | const fn equals_self(t: &T) -> bool { | ^^^^^^^^^^^ required by this bound in `equals_self` help: make the `impl` of trait `Foo` `const` | -LL | impl const Foo for S { - | +++++ +LL | const impl Foo for S { + | +++++ error: aborting due to 1 previous error diff --git a/tests/ui/traits/const-traits/const-closure-trait-method-fail.stderr b/tests/ui/traits/const-traits/const-closure-trait-method-fail.stderr index 93563dd12f952..30fbeb72fab9a 100644 --- a/tests/ui/traits/const-traits/const-closure-trait-method-fail.stderr +++ b/tests/ui/traits/const-traits/const-closure-trait-method-fail.stderr @@ -6,8 +6,8 @@ LL | const _: () = assert!(need_const_closure(Tr::a) == 42); | help: make the `impl` of trait `Tr` `const` | -LL | impl const Tr for () { - | +++++ +LL | const impl Tr for () { + | +++++ error: aborting due to 1 previous error diff --git a/tests/ui/traits/const-traits/const-default-method-bodies.stderr b/tests/ui/traits/const-traits/const-default-method-bodies.stderr index 55a12f95a6d19..c5a0c8743fa13 100644 --- a/tests/ui/traits/const-traits/const-default-method-bodies.stderr +++ b/tests/ui/traits/const-traits/const-default-method-bodies.stderr @@ -6,8 +6,8 @@ LL | NonConstImpl.a(); | help: make the `impl` of trait `ConstDefaultFn` `const` | -LL | impl const ConstDefaultFn for NonConstImpl { - | +++++ +LL | const impl ConstDefaultFn for NonConstImpl { + | +++++ error: aborting due to 1 previous error diff --git a/tests/ui/traits/const-traits/const-drop-fail-2.precise.stderr b/tests/ui/traits/const-traits/const-drop-fail-2.precise.stderr index c6d71bde6a368..b43a67667967b 100644 --- a/tests/ui/traits/const-traits/const-drop-fail-2.precise.stderr +++ b/tests/ui/traits/const-traits/const-drop-fail-2.precise.stderr @@ -18,8 +18,8 @@ LL | const fn check(_: T) {} | ^^^^^^^^^^^^^^^^ required by this bound in `check` help: make the `impl` of trait `A` `const` | -LL | impl const A for NonTrivialDrop {} - | +++++ +LL | const impl A for NonTrivialDrop {} + | +++++ error: aborting due to 1 previous error diff --git a/tests/ui/traits/const-traits/const-drop-fail-2.stock.stderr b/tests/ui/traits/const-traits/const-drop-fail-2.stock.stderr index c6d71bde6a368..b43a67667967b 100644 --- a/tests/ui/traits/const-traits/const-drop-fail-2.stock.stderr +++ b/tests/ui/traits/const-traits/const-drop-fail-2.stock.stderr @@ -18,8 +18,8 @@ LL | const fn check(_: T) {} | ^^^^^^^^^^^^^^^^ required by this bound in `check` help: make the `impl` of trait `A` `const` | -LL | impl const A for NonTrivialDrop {} - | +++++ +LL | const impl A for NonTrivialDrop {} + | +++++ error: aborting due to 1 previous error diff --git a/tests/ui/traits/const-traits/const-opaque.no.stderr b/tests/ui/traits/const-traits/const-opaque.no.stderr index 9f17b0d4354d7..d2b83ac2f3636 100644 --- a/tests/ui/traits/const-traits/const-opaque.no.stderr +++ b/tests/ui/traits/const-traits/const-opaque.no.stderr @@ -13,8 +13,8 @@ LL | const fn bar(t: T) -> impl [const] Foo { | ^^^^^^^^^^^ required by this bound in `bar` help: make the `impl` of trait `Foo` `const` | -LL | impl const Foo for () { - | +++++ +LL | const impl Foo for () { + | +++++ error[E0277]: the trait bound `(): const Foo` is not satisfied --> $DIR/const-opaque.rs:32:12 @@ -24,8 +24,8 @@ LL | opaque.method(); | help: make the `impl` of trait `Foo` `const` | -LL | impl const Foo for () { - | +++++ +LL | const impl Foo for () { + | +++++ error: aborting due to 2 previous errors diff --git a/tests/ui/traits/const-traits/default-method-body-is-const-body-checking.stderr b/tests/ui/traits/const-traits/default-method-body-is-const-body-checking.stderr index a436221d75412..7bd1118022647 100644 --- a/tests/ui/traits/const-traits/default-method-body-is-const-body-checking.stderr +++ b/tests/ui/traits/const-traits/default-method-body-is-const-body-checking.stderr @@ -11,8 +11,8 @@ LL | const fn foo() where T: [const] Tr {} | ^^^^^^^^^^ required by this bound in `foo` help: make the `impl` of trait `Tr` `const` | -LL | impl const Tr for () {} - | +++++ +LL | const impl Tr for () {} + | +++++ error: aborting due to 1 previous error diff --git a/tests/ui/traits/const-traits/default-method-body-is-const-same-trait-ck.stderr b/tests/ui/traits/const-traits/default-method-body-is-const-same-trait-ck.stderr index f93e57d5fd6b2..d92297fa7b69f 100644 --- a/tests/ui/traits/const-traits/default-method-body-is-const-same-trait-ck.stderr +++ b/tests/ui/traits/const-traits/default-method-body-is-const-same-trait-ck.stderr @@ -6,8 +6,8 @@ LL | ().a() | help: make the `impl` of trait `Tr` `const` | -LL | impl const Tr for () {} - | +++++ +LL | const impl Tr for () {} + | +++++ error: aborting due to 1 previous error diff --git a/tests/ui/traits/const-traits/item-bound-entailment-fails.stderr b/tests/ui/traits/const-traits/item-bound-entailment-fails.stderr index ffa9679e86ce6..375cb58580490 100644 --- a/tests/ui/traits/const-traits/item-bound-entailment-fails.stderr +++ b/tests/ui/traits/const-traits/item-bound-entailment-fails.stderr @@ -11,8 +11,8 @@ LL | type Assoc: [const] Bar | ^^^^^^^^^^^ required by this bound in `Foo::Assoc` help: make the `impl` of trait `Bar` `const` | -LL | impl const Bar for N where T: Bar {} - | +++++ +LL | const impl Bar for N where T: Bar {} + | +++++ error[E0277]: the trait bound `T: [const] Bar` is not satisfied --> $DIR/item-bound-entailment-fails.rs:24:21 diff --git a/tests/ui/traits/const-traits/minicore-deref-fail.stderr b/tests/ui/traits/const-traits/minicore-deref-fail.stderr index e6c087cb9d822..c64dce93cc562 100644 --- a/tests/ui/traits/const-traits/minicore-deref-fail.stderr +++ b/tests/ui/traits/const-traits/minicore-deref-fail.stderr @@ -6,8 +6,8 @@ LL | *Ty; | help: make the `impl` of trait `Deref` `const` | -LL | impl const Deref for Ty { - | +++++ +LL | const impl Deref for Ty { + | +++++ error: aborting due to 1 previous error diff --git a/tests/ui/traits/const-traits/minicore-fn-fail.stderr b/tests/ui/traits/const-traits/minicore-fn-fail.stderr index 0c260f7f33a77..949a1270b60e1 100644 --- a/tests/ui/traits/const-traits/minicore-fn-fail.stderr +++ b/tests/ui/traits/const-traits/minicore-fn-fail.stderr @@ -13,8 +13,8 @@ LL | const fn call_indirect(t: &T) { t() } | ^^^^^^^^^^^^ required by this bound in `call_indirect` help: make the `impl` of trait `Foo` `const` | -LL | impl const Foo for () {} - | +++++ +LL | const impl Foo for () {} + | +++++ error: aborting due to 1 previous error diff --git a/tests/ui/traits/const-traits/no-explicit-const-params.stderr b/tests/ui/traits/const-traits/no-explicit-const-params.stderr index efd90482f7742..72c64120a3d77 100644 --- a/tests/ui/traits/const-traits/no-explicit-const-params.stderr +++ b/tests/ui/traits/const-traits/no-explicit-const-params.stderr @@ -62,8 +62,8 @@ LL | <() as Bar>::bar(); | help: make the `impl` of trait `Bar` `const` | -LL | impl const Bar for () { - | +++++ +LL | const impl Bar for () { + | +++++ error: aborting due to 5 previous errors diff --git a/tests/ui/traits/const-traits/specialization/specializing-constness-2.stderr b/tests/ui/traits/const-traits/specialization/specializing-constness-2.stderr index bb1c9ac785314..aed032714b6df 100644 --- a/tests/ui/traits/const-traits/specialization/specializing-constness-2.stderr +++ b/tests/ui/traits/const-traits/specialization/specializing-constness-2.stderr @@ -6,8 +6,8 @@ LL | ::a(); | help: make the `impl` of trait `A` `const` | -LL | impl const A for T { - | +++++ +LL | const impl A for T { + | +++++ error: aborting due to 1 previous error diff --git a/tests/ui/traits/const-traits/super-traits-fail.stderr b/tests/ui/traits/const-traits/super-traits-fail.stderr index bb3bc51c44a2c..8b8b84c850f33 100644 --- a/tests/ui/traits/const-traits/super-traits-fail.stderr +++ b/tests/ui/traits/const-traits/super-traits-fail.stderr @@ -6,8 +6,8 @@ LL | const impl Bar for S {} | help: make the `impl` of trait `Foo` `const` | -LL | impl const Foo for S { - | +++++ +LL | const impl Foo for S { + | +++++ error: aborting due to 1 previous error From ab76db556daca7dd37cc8fe7b58eb987d3b501e7 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Mon, 27 Jul 2026 16:40:05 +0300 Subject: [PATCH 70/76] tests/ui: Ignore one query cycle test in parallel frontend mode --- .../next-solver-region-resolution.rs | 1 + .../next-solver-region-resolution.stderr | 12 ++++++------ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/tests/ui/specialization/min_specialization/next-solver-region-resolution.rs b/tests/ui/specialization/min_specialization/next-solver-region-resolution.rs index a49fe6184890f..ba7cae44a0e46 100644 --- a/tests/ui/specialization/min_specialization/next-solver-region-resolution.rs +++ b/tests/ui/specialization/min_specialization/next-solver-region-resolution.rs @@ -1,4 +1,5 @@ //@ compile-flags: -Znext-solver=globally +//@ ignore-parallel-frontend query cycle // ICE regression test for https://github.com/rust-lang/rust/issues/151327 #![feature(min_specialization)] diff --git a/tests/ui/specialization/min_specialization/next-solver-region-resolution.stderr b/tests/ui/specialization/min_specialization/next-solver-region-resolution.stderr index 76d17e33c30ac..2a5e9bd4148fe 100644 --- a/tests/ui/specialization/min_specialization/next-solver-region-resolution.stderr +++ b/tests/ui/specialization/min_specialization/next-solver-region-resolution.stderr @@ -1,27 +1,27 @@ error[E0391]: cycle detected when coherence checking all impls of trait `Foo` - --> $DIR/next-solver-region-resolution.rs:6:1 + --> $DIR/next-solver-region-resolution.rs:7:1 | LL | trait Foo { | ^^^^^^^^^ | = note: ...which requires building specialization graph of trait `Foo`... note: ...which requires computing whether impls specialize one another... - --> $DIR/next-solver-region-resolution.rs:12:1 + --> $DIR/next-solver-region-resolution.rs:13:1 | LL | / impl<'a, T> Foo for &'a T LL | | where LL | | Self::Item: 'a, | |___________________^ -note: ...which requires computing normalized predicates of ``... - --> $DIR/next-solver-region-resolution.rs:18:1 +note: ...which requires computing normalized predicates of ``... + --> $DIR/next-solver-region-resolution.rs:19:1 | LL | / impl<'a, T> Foo for &T LL | | where LL | | Self::Item: Baz, | |____________________^ = note: ...which again requires coherence checking all impls of trait `Foo`, completing the cycle -note: cycle used when checking that `` is well-formed - --> $DIR/next-solver-region-resolution.rs:12:1 +note: cycle used when checking that `` is well-formed + --> $DIR/next-solver-region-resolution.rs:13:1 | LL | / impl<'a, T> Foo for &'a T LL | | where From 6a194beb64de8e1cfc2596a63353587a50098978 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Fri, 24 Jul 2026 14:19:36 +0300 Subject: [PATCH 71/76] ci: Make the `x86_64-gnu-parallel-frontend` job non-optional --- .../Dockerfile | 2 +- ...l-frontend.sh => x86_64-gnu-parallel-frontend.sh} | 0 src/ci/github-actions/jobs.yml | 7 +++---- .../src/tests/x86_64-gnu-parallel-frontend.md | 12 ++++++++++++ 4 files changed, 16 insertions(+), 5 deletions(-) rename src/ci/docker/host-x86_64/{optional-x86_64-gnu-parallel-frontend => x86_64-gnu-parallel-frontend}/Dockerfile (94%) rename src/ci/docker/scripts/{optional-x86_64-gnu-parallel-frontend.sh => x86_64-gnu-parallel-frontend.sh} (100%) create mode 100644 src/doc/rustc-dev-guide/src/tests/x86_64-gnu-parallel-frontend.md diff --git a/src/ci/docker/host-x86_64/optional-x86_64-gnu-parallel-frontend/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-parallel-frontend/Dockerfile similarity index 94% rename from src/ci/docker/host-x86_64/optional-x86_64-gnu-parallel-frontend/Dockerfile rename to src/ci/docker/host-x86_64/x86_64-gnu-parallel-frontend/Dockerfile index d8bfd6f52cb8b..72e06ff41c2f2 100644 --- a/src/ci/docker/host-x86_64/optional-x86_64-gnu-parallel-frontend/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-parallel-frontend/Dockerfile @@ -39,5 +39,5 @@ ENV RUST_CONFIGURE_ARGS \ # Tests are still compiled serially at the moment (intended to be changed in follow-ups). # Running compiletest only tests for parallel frontend, then the rest without compiletest-only # options (i.e. `--parallel-frontend-threads=4 --iteration-count=2`) -COPY ./scripts/optional-x86_64-gnu-parallel-frontend.sh /scripts/ +COPY ./scripts/x86_64-gnu-parallel-frontend.sh /scripts/ ENV SCRIPT="Must specify DOCKER_SCRIPT for this image" diff --git a/src/ci/docker/scripts/optional-x86_64-gnu-parallel-frontend.sh b/src/ci/docker/scripts/x86_64-gnu-parallel-frontend.sh similarity index 100% rename from src/ci/docker/scripts/optional-x86_64-gnu-parallel-frontend.sh rename to src/ci/docker/scripts/x86_64-gnu-parallel-frontend.sh diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index e03ad184842e3..e6e3c1acd853b 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -382,11 +382,10 @@ auto: - name: x86_64-gnu <<: *job-linux-4c - - name: optional-x86_64-gnu-parallel-frontend - # This test can be flaky, so do not cancel CI if it fails, for now. - continue_on_error: true + - name: x86_64-gnu-parallel-frontend + doc_url: https://rustc-dev-guide.rust-lang.org/tests/x86_64-gnu-parallel-frontend.html env: - DOCKER_SCRIPT: optional-x86_64-gnu-parallel-frontend.sh + DOCKER_SCRIPT: x86_64-gnu-parallel-frontend.sh <<: *job-linux-4c # This job ensures commits landing on nightly still pass the full diff --git a/src/doc/rustc-dev-guide/src/tests/x86_64-gnu-parallel-frontend.md b/src/doc/rustc-dev-guide/src/tests/x86_64-gnu-parallel-frontend.md new file mode 100644 index 0000000000000..e8c91044be1d7 --- /dev/null +++ b/src/doc/rustc-dev-guide/src/tests/x86_64-gnu-parallel-frontend.md @@ -0,0 +1,12 @@ +# Parallel frontend testing on CI + +If you see any test failures in `tests/ui` from the CI job `x86_64-gnu-parallel-frontend`, please +add `//@ ignore-parallel-frontend triage` to the failing test, even if your PR is otherwise +entirely unrelated to parallel compiler or its testing. +In some time people from the parallel rustc working group will triage the failing test, make a +tracking issue for it, and try to debug the problem. + +For more context, see: + +* [MCP: Stabilization strategy for rustc parallel frontend](https://github.com/rust-lang/compiler-team/issues/1005) +* Tracking issue: From 2ddda91c10d9ae55a67d6e49e8d9b39885ff0a26 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 27 Jul 2026 16:54:15 +0200 Subject: [PATCH 72/76] compiletest: do not talk about JSON when the user never sees any --- src/tools/compiletest/src/runtest.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index a4fa28e13b911..770734195ed89 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -818,7 +818,7 @@ impl<'test> TestCx<'test> { if !unexpected.is_empty() { writeln!( self.stdout, - "\n{prefix}: {n} diagnostics reported in JSON output but not expected in test file", + "\n{prefix}: {n} diagnostics reported in rustc output but not expected in test file", prefix = self.error_prefix(), n = unexpected.len(), ); @@ -853,7 +853,7 @@ impl<'test> TestCx<'test> { if !not_found.is_empty() { writeln!( self.stdout, - "\n{prefix}: {n} diagnostics expected in test file but not reported in JSON output", + "\n{prefix}: {n} diagnostics expected in test file but not reported in rustc output", prefix = self.error_prefix(), n = not_found.len(), ); From 574ee122de934c517819295f91523884b7a9af99 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 23 Jul 2026 12:07:25 +0200 Subject: [PATCH 73/76] Don't codegen comptime fns --- .../src/back/symbol_export.rs | 6 +++++ compiler/rustc_monomorphize/src/collector.rs | 9 +++++++ compiler/rustc_symbol_mangling/src/lib.rs | 7 ++++- library/core/src/intrinsics/mod.rs | 26 +++++-------------- tests/ui/comptime/link-dead-code.rs | 11 ++++++++ 5 files changed, 38 insertions(+), 21 deletions(-) create mode 100644 tests/ui/comptime/link-dead-code.rs diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs index 42e2b646e4793..aaf26d1896755 100644 --- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs +++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs @@ -3,6 +3,7 @@ use std::collections::hash_map::Entry::*; use rustc_abi::{CanonAbi, X86Call}; use rustc_ast::expand::allocator::{AllocatorKind, NO_ALLOC_SHIM_IS_UNSTABLE, global_fn_name}; use rustc_data_structures::unord::UnordMap; +use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LOCAL_CRATE, LocalDefId}; use rustc_middle::bug; @@ -82,6 +83,11 @@ fn reachable_non_generics_provider(tcx: TyCtxt<'_>, _: LocalCrate) -> DefIdMap + { + return None; + } DefKind::Fn | DefKind::Static { .. } => {} DefKind::AssocFn if tcx.impl_of_assoc(def_id.to_def_id()).is_some() => {} _ => return None, diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index c0059ca2ba852..208a77cc860a7 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -1669,6 +1669,15 @@ impl<'v> RootCollector<'_, 'v> { && match self.strategy { MonoItemCollectionStrategy::Eager => { !matches!(self.tcx.codegen_fn_attrs(def_id).inline, InlineAttr::Force { .. }) + // comptime fns can't be codegenned, so we need to prevent collecting them even + // with link-dead-code. Lazy mode prevents them by them not showing up in + // `is_reachable_non_generic` (and `entry_fn` can't be comptime). + && match self.tcx.def_kind(def_id) { + DefKind::Fn | DefKind::AssocFn => { + self.tcx.constness(def_id) != hir::Constness::Const { always: true } + } + _ => true, + } } MonoItemCollectionStrategy::Lazy => { self.entry_fn.and_then(|(id, _)| id.as_local()) == Some(def_id) diff --git a/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs index d61437212a266..033f918cab185 100644 --- a/compiler/rustc_symbol_mangling/src/lib.rs +++ b/compiler/rustc_symbol_mangling/src/lib.rs @@ -87,6 +87,7 @@ //! virtually impossible. Thus, symbol hash generation exclusively relies on //! DefPaths which are much more robust in the face of changes to the code base. +use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::{CrateNum, LOCAL_CRATE}; use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs}; @@ -240,6 +241,10 @@ fn compute_symbol_name<'tcx>( ) -> String { let def_id = instance.def_id(); let args = instance.args; + let def_kind = tcx.def_kind(instance.def_id()); + if let DefKind::Fn | DefKind::AssocFn = def_kind { + debug_assert!(tcx.constness(instance.def_id()) != hir::Constness::Const { always: true }); + } debug!("symbol_name(def_id={:?}, args={:?})", def_id, args); @@ -254,7 +259,7 @@ fn compute_symbol_name<'tcx>( // visibility) symbol. This means that multiple crates may do the same // and we want to be sure to avoid any symbol conflicts here. let is_globally_shared_function = matches!( - tcx.def_kind(instance.def_id()), + def_kind, DefKind::Fn | DefKind::AssocFn | DefKind::Closure diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index e9875f31fe784..fccb6ee6def22 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -3049,11 +3049,7 @@ pub const unsafe fn align_of_val(ptr: *const T) -> usize; pub fn type_id_vtable( _id: crate::any::TypeId, _trait: crate::any::TypeId, -) -> Option> { - panic!( - "`TypeId::trait_info_of` and `trait_info_of_trait_type_id` can only be called at compile-time" - ) -} +) -> Option>; /// Compute the type information of a concrete type. /// It can only be called at compile time, the backends do @@ -3114,9 +3110,7 @@ pub const fn type_id_eq(a: crate::any::TypeId, b: crate::any::TypeId) -> bool { #[rustc_intrinsic] #[unstable(feature = "core_intrinsics", issue = "none")] #[rustc_comptime] -pub fn size_of_type_id(_id: crate::any::TypeId) -> Option { - panic!("`TypeId::size` can only be called at compile-time") -} +pub fn size_of_type_id(_id: crate::any::TypeId) -> Option; /// Gets the number of variants of the type represented by this `TypeId`. /// @@ -3124,9 +3118,7 @@ pub fn size_of_type_id(_id: crate::any::TypeId) -> Option { #[rustc_intrinsic] #[unstable(feature = "core_intrinsics", issue = "none")] #[rustc_comptime] -pub fn type_id_variants(_id: crate::any::TypeId) -> usize { - panic!("`TypeId::variants` can only be called at compile-time") -} +pub fn type_id_variants(_id: crate::any::TypeId) -> usize; /// Gets the number of fields at the given `variant_index` represented by this `TypeId`. /// @@ -3134,9 +3126,7 @@ pub fn type_id_variants(_id: crate::any::TypeId) -> usize { #[rustc_intrinsic] #[unstable(feature = "core_intrinsics", issue = "none")] #[rustc_comptime] -pub fn type_id_fields(_id: crate::any::TypeId, _variant_index: usize) -> usize { - panic!("`TypeId::fields` can only be called at compile-time") -} +pub fn type_id_fields(_id: crate::any::TypeId, _variant_index: usize) -> usize; /// Gets the [`FieldRepresentingType`]'s `TypeId` at the given index of the type represented by this `TypeId`. /// @@ -3150,9 +3140,7 @@ pub fn type_id_field_representing_type( _id: crate::any::TypeId, _variant_index: usize, _field_index: usize, -) -> crate::any::TypeId { - panic!("`TypeId::field` can only be called at compile-time") -} +) -> crate::any::TypeId; /// Gets the actual field `TypeId` of the [`FieldRepresentingType`]'s `TypeId`. /// @@ -3164,9 +3152,7 @@ pub fn type_id_field_representing_type( #[rustc_comptime] pub fn field_representing_type_actual_type_id( _frt_type_id: crate::any::TypeId, -) -> crate::any::TypeId { - panic!("`FieldId::type_id` can only be called at compile-time") -} +) -> crate::any::TypeId; /// Lowers in MIR to `Rvalue::Aggregate` with `AggregateKind::RawPtr`. /// diff --git a/tests/ui/comptime/link-dead-code.rs b/tests/ui/comptime/link-dead-code.rs new file mode 100644 index 0000000000000..4f359420521f6 --- /dev/null +++ b/tests/ui/comptime/link-dead-code.rs @@ -0,0 +1,11 @@ +//@ build-pass +//@ compile-flags: -Clink-dead-code +//! Check that we don't try to generate assembly for comptime +//! fns, even when link-dead-code is active. + +#![feature(rustc_attrs)] + +#[rustc_comptime] +fn f() {} + +fn main() {} From 4609fbcc59c8d50ebfbb5a550e348463ef28c381 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 23 Jul 2026 17:12:32 +0200 Subject: [PATCH 74/76] Mark some more comptime-only things as comptime --- library/core/src/intrinsics/mod.rs | 26 ++++++++++++------- library/core/src/mem/type_info.rs | 3 ++- .../const-eval-intrinsic-promotion.rs | 4 +-- .../const-eval-intrinsic-promotion.stderr | 8 +++--- 4 files changed, 24 insertions(+), 17 deletions(-) diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index fccb6ee6def22..7210d850c864a 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -873,7 +873,8 @@ pub const unsafe fn transmute_unchecked(src: Src) -> Dst; #[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] -pub const fn needs_drop() -> bool; +#[rustc_comptime] +pub fn needs_drop() -> bool; /// Calculates the offset from a pointer. /// @@ -2945,7 +2946,8 @@ pub unsafe fn vtable_align(ptr: *const ()) -> usize; #[unstable(feature = "core_intrinsics", issue = "none")] #[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] -pub const fn size_of() -> usize; +#[rustc_comptime] +pub fn size_of() -> usize; /// The minimum alignment of a type. /// @@ -2964,7 +2966,8 @@ pub const fn size_of() -> usize; #[unstable(feature = "core_intrinsics", issue = "none")] #[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] -pub const fn align_of() -> usize; +#[rustc_comptime] +pub fn align_of() -> usize; /// The offset of a field inside a type. /// @@ -2984,7 +2987,8 @@ pub const fn align_of() -> usize; #[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] #[lang = "offset_of"] -pub const fn offset_of(variant: u32, field: u32) -> usize; +#[rustc_comptime] +pub fn offset_of(variant: u32, field: u32) -> usize; /// The offset of a field queried by its field representing type. /// @@ -2998,7 +3002,8 @@ pub const fn offset_of(variant: u32, field: u32) -> usize; #[rustc_intrinsic] #[unstable(feature = "field_projections", issue = "145383")] #[rustc_const_unstable(feature = "field_projections", issue = "145383")] -pub const fn field_offset() -> usize; +#[rustc_comptime] +pub fn field_offset() -> usize; /// Returns the number of variants of the type `T` cast to a `usize`; /// if `T` has no variants, returns `0`. Uninhabited variants will be counted. @@ -3012,7 +3017,8 @@ pub const fn field_offset() -> usize; #[rustc_nounwind] #[unstable(feature = "core_intrinsics", issue = "none")] #[rustc_intrinsic] -pub const fn variant_count() -> usize; +#[rustc_comptime] +pub fn variant_count() -> usize; /// The size of the referenced value in bytes. /// @@ -3056,9 +3062,8 @@ pub fn type_id_vtable( /// not implement it. #[rustc_intrinsic] #[unstable(feature = "core_intrinsics", issue = "none")] -pub const fn type_of(_id: crate::any::TypeId) -> crate::mem::type_info::Type { - panic!("`TypeId::info` can only be called at compile-time") -} +#[rustc_comptime] +pub fn type_of(_id: crate::any::TypeId) -> crate::mem::type_info::Type; /// Gets a static string slice containing the name of a type. /// @@ -3071,7 +3076,8 @@ pub const fn type_of(_id: crate::any::TypeId) -> crate::mem::type_info::Type { #[rustc_nounwind] #[unstable(feature = "core_intrinsics", issue = "none")] #[rustc_intrinsic] -pub const fn type_name() -> &'static str; +#[rustc_comptime] +pub fn type_name() -> &'static str; /// Gets an identifier which is globally unique to the specified type. This /// function will return the same value for a type regardless of whichever diff --git a/library/core/src/mem/type_info.rs b/library/core/src/mem/type_info.rs index 7614adbcc532b..75270b2d5b14b 100644 --- a/library/core/src/mem/type_info.rs +++ b/library/core/src/mem/type_info.rs @@ -37,7 +37,8 @@ impl TypeId { /// It can only be called at compile time. #[unstable(feature = "type_info", issue = "146922")] #[rustc_const_unstable(feature = "type_info", issue = "146922")] - pub const fn info(self) -> Type { + #[rustc_comptime] + pub fn info(self) -> Type { type_of(self) } } diff --git a/tests/ui/consts/const-eval/const-eval-intrinsic-promotion.rs b/tests/ui/consts/const-eval/const-eval-intrinsic-promotion.rs index bdcf537859cc4..0de46b3a594ea 100644 --- a/tests/ui/consts/const-eval/const-eval-intrinsic-promotion.rs +++ b/tests/ui/consts/const-eval/const-eval-intrinsic-promotion.rs @@ -1,6 +1,6 @@ #![feature(core_intrinsics)] fn main() { // Test that calls to intrinsics are never promoted - let x: &'static usize = - &std::intrinsics::size_of::(); //~ ERROR temporary value dropped while borrowed + let x: &'static () = + &std::intrinsics::cold_path(); //~ ERROR temporary value dropped while borrowed } diff --git a/tests/ui/consts/const-eval/const-eval-intrinsic-promotion.stderr b/tests/ui/consts/const-eval/const-eval-intrinsic-promotion.stderr index d533dcaa6f6b5..bb36caf64ddd5 100644 --- a/tests/ui/consts/const-eval/const-eval-intrinsic-promotion.stderr +++ b/tests/ui/consts/const-eval/const-eval-intrinsic-promotion.stderr @@ -1,10 +1,10 @@ error[E0716]: temporary value dropped while borrowed --> $DIR/const-eval-intrinsic-promotion.rs:5:10 | -LL | let x: &'static usize = - | -------------- type annotation requires that borrow lasts for `'static` -LL | &std::intrinsics::size_of::(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use +LL | let x: &'static () = + | ----------- type annotation requires that borrow lasts for `'static` +LL | &std::intrinsics::cold_path(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use LL | } | - temporary value is freed at the end of this statement From 960d0a5655288c2aaaf3d8459e39d4ac57e56f08 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Mon, 27 Jul 2026 16:40:05 +0300 Subject: [PATCH 75/76] tests/ui: Ignore one query cycle test in parallel frontend mode --- .../next-solver-region-resolution.rs | 1 + .../next-solver-region-resolution.stderr | 12 ++++++------ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/tests/ui/specialization/min_specialization/next-solver-region-resolution.rs b/tests/ui/specialization/min_specialization/next-solver-region-resolution.rs index a49fe6184890f..ba7cae44a0e46 100644 --- a/tests/ui/specialization/min_specialization/next-solver-region-resolution.rs +++ b/tests/ui/specialization/min_specialization/next-solver-region-resolution.rs @@ -1,4 +1,5 @@ //@ compile-flags: -Znext-solver=globally +//@ ignore-parallel-frontend query cycle // ICE regression test for https://github.com/rust-lang/rust/issues/151327 #![feature(min_specialization)] diff --git a/tests/ui/specialization/min_specialization/next-solver-region-resolution.stderr b/tests/ui/specialization/min_specialization/next-solver-region-resolution.stderr index 76d17e33c30ac..2a5e9bd4148fe 100644 --- a/tests/ui/specialization/min_specialization/next-solver-region-resolution.stderr +++ b/tests/ui/specialization/min_specialization/next-solver-region-resolution.stderr @@ -1,27 +1,27 @@ error[E0391]: cycle detected when coherence checking all impls of trait `Foo` - --> $DIR/next-solver-region-resolution.rs:6:1 + --> $DIR/next-solver-region-resolution.rs:7:1 | LL | trait Foo { | ^^^^^^^^^ | = note: ...which requires building specialization graph of trait `Foo`... note: ...which requires computing whether impls specialize one another... - --> $DIR/next-solver-region-resolution.rs:12:1 + --> $DIR/next-solver-region-resolution.rs:13:1 | LL | / impl<'a, T> Foo for &'a T LL | | where LL | | Self::Item: 'a, | |___________________^ -note: ...which requires computing normalized predicates of ``... - --> $DIR/next-solver-region-resolution.rs:18:1 +note: ...which requires computing normalized predicates of ``... + --> $DIR/next-solver-region-resolution.rs:19:1 | LL | / impl<'a, T> Foo for &T LL | | where LL | | Self::Item: Baz, | |____________________^ = note: ...which again requires coherence checking all impls of trait `Foo`, completing the cycle -note: cycle used when checking that `` is well-formed - --> $DIR/next-solver-region-resolution.rs:12:1 +note: cycle used when checking that `` is well-formed + --> $DIR/next-solver-region-resolution.rs:13:1 | LL | / impl<'a, T> Foo for &'a T LL | | where From 3e2470e9a7617c1bdd0b3e3dc555a91de528d59c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 27 Jul 2026 18:15:09 +0200 Subject: [PATCH 76/76] test suite: add ARM case to ABI-required target feature check for -Ctarget-cpu --- ...t-feature-missing-in-target-cpu.arm.stderr | 7 ++++++ ...ed-target-feature-missing-in-target-cpu.rs | 23 +++++++++++++++++++ ...-feature-missing-in-target-cpu.x86.stderr} | 0 ...arget-cpu-lacks-required-target-feature.rs | 15 ------------ 4 files changed, 30 insertions(+), 15 deletions(-) create mode 100644 tests/ui/target-feature/abi-required-target-feature-missing-in-target-cpu.arm.stderr create mode 100644 tests/ui/target-feature/abi-required-target-feature-missing-in-target-cpu.rs rename tests/ui/target-feature/{target-cpu-lacks-required-target-feature.stderr => abi-required-target-feature-missing-in-target-cpu.x86.stderr} (100%) delete mode 100644 tests/ui/target-feature/target-cpu-lacks-required-target-feature.rs diff --git a/tests/ui/target-feature/abi-required-target-feature-missing-in-target-cpu.arm.stderr b/tests/ui/target-feature/abi-required-target-feature-missing-in-target-cpu.arm.stderr new file mode 100644 index 0000000000000..52862ec5151b3 --- /dev/null +++ b/tests/ui/target-feature/abi-required-target-feature-missing-in-target-cpu.arm.stderr @@ -0,0 +1,7 @@ +warning: target feature `fpregs` must be enabled to ensure that the ABI of the current target can be implemented correctly + | + = note: 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 #116344 + +warning: 1 warning emitted + diff --git a/tests/ui/target-feature/abi-required-target-feature-missing-in-target-cpu.rs b/tests/ui/target-feature/abi-required-target-feature-missing-in-target-cpu.rs new file mode 100644 index 0000000000000..c07479eca0f7b --- /dev/null +++ b/tests/ui/target-feature/abi-required-target-feature-missing-in-target-cpu.rs @@ -0,0 +1,23 @@ +//! Sometimes `-Ctarget-cpu` can *disable* target features that would by default be enabled on the +//! current target. Ensure that we catch the case where those target features are important for the +//! ABI. + +//@ compile-flags: --crate-type=lib +//@ revisions: x86 arm +//@[x86] compile-flags: --target=i686-unknown-linux-gnu -Ctarget-cpu=pentium +//@[x86] needs-llvm-components: x86 +//@[arm] compile-flags: --target=armv8r-none-eabihf -Ctarget-cpu=cortex-r4 +//@[arm] needs-llvm-components: arm + +// For now this is just a warning. +//@ build-pass +//@ ignore-backends: gcc +//@ add-minicore + +#![feature(no_core)] +#![no_core] + +extern crate minicore; +use minicore::*; + +//~? WARN must be enabled to ensure that the ABI of the current target can be implemented correctly diff --git a/tests/ui/target-feature/target-cpu-lacks-required-target-feature.stderr b/tests/ui/target-feature/abi-required-target-feature-missing-in-target-cpu.x86.stderr similarity index 100% rename from tests/ui/target-feature/target-cpu-lacks-required-target-feature.stderr rename to tests/ui/target-feature/abi-required-target-feature-missing-in-target-cpu.x86.stderr diff --git a/tests/ui/target-feature/target-cpu-lacks-required-target-feature.rs b/tests/ui/target-feature/target-cpu-lacks-required-target-feature.rs deleted file mode 100644 index 5e46ea8adf64a..0000000000000 --- a/tests/ui/target-feature/target-cpu-lacks-required-target-feature.rs +++ /dev/null @@ -1,15 +0,0 @@ -//@ compile-flags: --target=i686-unknown-linux-gnu --crate-type=lib -//@ needs-llvm-components: x86 -//@ compile-flags: -Ctarget-cpu=pentium -// For now this is just a warning. -//@ build-pass -//@ ignore-backends: gcc -//@ add-minicore - -#![feature(no_core)] -#![no_core] - -extern crate minicore; -use minicore::*; - -//~? WARN target feature `sse2` must be enabled to ensure that the ABI of the current target can be implemented correctly