From f5991a8f5a7dd8950534fe91445bf163c5554f89 Mon Sep 17 00:00:00 2001 From: Wilfred Hughes Date: Tue, 24 Feb 2026 19:29:04 -0500 Subject: [PATCH 01/56] fix: Incorrect flychecks with multiple workspaces When rust-analyzer receives textDocument/didChangeWatchedFiles, we want to trigger a flycheck in all workspaces if we can't find which workspace owns those files. However, since we used .any() instead of .all(), this behaviour was always triggered when the user had more than one workspace. Instead, use .all() so we correctly detect when the file it outside of all workspaces. --- For cargo-based projects, this just made rust-analyzer slower. For projects with a custom check command using $saved_file or {saved_file}, this introduced a race condition that sometimes prevented diagnostics. When we see the following flycheck events in this order: // Created by textDocument/didSave. RequestStateChange(Restart { ... saved_file: Some("foo.rs") }) // Created by textDocument/didChangeWatchedFiles RequestStateChange(Restart { ... saved_file: None }) Then the flycheck debounce takes the last event, we invoke flycheck with saved_file: None, and no flycheck occurs (because we require a value to substitute in $saved_file). Previously the debounce took the first event (until rust-lang/rust-analyzer#21666), but that just meant a race condition when events arrive in the opposite order. --- src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs | 2 +- .../crates/rust-analyzer/src/handlers/notification.rs | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs index cdaf944bbad4..c41696bf3f6a 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs @@ -1021,7 +1021,7 @@ fn from_eof(&self) -> Option { } } -#[derive(Deserialize)] +#[derive(Deserialize, Debug)] #[serde(untagged)] enum JsonMessage { Cargo(cargo_metadata::Message), diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs index 138310b78f62..09b6794e4f43 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs @@ -295,8 +295,9 @@ pub(crate) fn handle_did_change_watched_files( for change in params.changes.iter().unique_by(|&it| &it.uri) { if let Ok(path) = from_proto::abs_path(&change.uri) { if !trigger_flycheck { + // Trigger if no workspaces contain this file. trigger_flycheck = - state.config.workspace_roots().iter().any(|root| !path.starts_with(root)); + state.config.workspace_roots().iter().all(|root| !path.starts_with(root)); } state.loader.handle.invalidate(path); } From abe2502e609709b0dd91a27d917ade5e00e45cb2 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sat, 14 Mar 2026 16:46:25 +0100 Subject: [PATCH 02/56] Implement signature type inference --- .../rust-analyzer/crates/hir-def/src/db.rs | 25 +++- .../crates/hir-def/src/expr_store.rs | 51 ++++++- .../crates/hir-def/src/expr_store/body.rs | 2 +- .../crates/hir-def/src/expr_store/lower.rs | 77 +++++++---- .../hir-def/src/expr_store/lower/generics.rs | 17 ++- .../src/expr_store/lower/path/tests.rs | 2 +- .../crates/hir-def/src/expr_store/scope.rs | 51 ++++++- .../rust-analyzer/crates/hir-def/src/lib.rs | 73 ++++++++++- .../crates/hir-def/src/resolver.rs | 44 ++++--- .../crates/hir-def/src/signatures.rs | 10 +- .../crates/hir-def/src/test_db.rs | 2 +- .../crates/hir-ty/src/consteval.rs | 5 +- .../rust-analyzer/crates/hir-ty/src/db.rs | 10 +- .../crates/hir-ty/src/display.rs | 14 +- .../rust-analyzer/crates/hir-ty/src/drop.rs | 7 +- .../rust-analyzer/crates/hir-ty/src/infer.rs | 124 +++++++++++++++--- .../hir-ty/src/infer/closure/analysis.rs | 2 +- .../crates/hir-ty/src/infer/coerce.rs | 5 +- .../crates/hir-ty/src/infer/pat.rs | 2 +- .../rust-analyzer/crates/hir-ty/src/layout.rs | 5 +- .../rust-analyzer/crates/hir-ty/src/lower.rs | 73 +++++++++-- .../crates/hir-ty/src/mir/borrowck.rs | 11 +- .../crates/hir-ty/src/mir/eval.rs | 8 +- .../crates/hir-ty/src/mir/eval/shim.rs | 5 +- .../crates/hir-ty/src/mir/lower.rs | 14 +- .../crates/hir-ty/src/next_solver/def_id.rs | 17 ++- .../crates/hir-ty/src/next_solver/interner.rs | 52 ++++---- .../crates/hir-ty/src/next_solver/solver.rs | 7 +- .../crates/hir-ty/src/next_solver/ty.rs | 2 +- .../hir-ty/src/tests/closure_captures.rs | 7 +- .../crates/hir-ty/src/tests/incremental.rs | 14 +- .../crates/hir/src/has_source.rs | 5 +- src/tools/rust-analyzer/crates/hir/src/lib.rs | 26 ++-- .../crates/hir/src/source_analyzer.rs | 6 +- .../add_explicit_enum_discriminant.rs | 6 +- .../ide/src/inlay_hints/discriminant.rs | 2 +- .../crates/parser/src/grammar/items/adt.rs | 4 + .../ok/record_field_default_values.rast | 5 +- .../inline/ok/variant_discriminant.rast | 5 +- .../test_data/parser/ok/0019_enums.rast | 5 +- .../rust-analyzer/crates/syntax/rust.ungram | 4 +- .../crates/syntax/src/ast/generated/nodes.rs | 4 +- .../src/ast/syntax_factory/constructors.rs | 6 +- 43 files changed, 632 insertions(+), 184 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/db.rs b/src/tools/rust-analyzer/crates/hir-def/src/db.rs index b0b652a1509c..ba0efe0ff13a 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/db.rs @@ -8,12 +8,13 @@ use triomphe::Arc; use crate::{ - AssocItemId, AttrDefId, BlockId, BlockLoc, ConstId, ConstLoc, DefWithBodyId, EnumId, EnumLoc, - EnumVariantId, EnumVariantLoc, ExternBlockId, ExternBlockLoc, ExternCrateId, ExternCrateLoc, - FunctionId, FunctionLoc, GenericDefId, ImplId, ImplLoc, LocalFieldId, Macro2Id, Macro2Loc, - MacroExpander, MacroId, MacroRulesId, MacroRulesLoc, MacroRulesLocFlags, ProcMacroId, - ProcMacroLoc, StaticId, StaticLoc, StructId, StructLoc, TraitId, TraitLoc, TypeAliasId, - TypeAliasLoc, UnionId, UnionLoc, UseId, UseLoc, VariantId, + AnonConstId, AnonConstLoc, AssocItemId, AttrDefId, BlockId, BlockLoc, ConstId, ConstLoc, + DefWithBodyId, EnumId, EnumLoc, EnumVariantId, EnumVariantLoc, ExpressionStoreOwner, + ExternBlockId, ExternBlockLoc, ExternCrateId, ExternCrateLoc, FunctionId, FunctionLoc, + GenericDefId, ImplId, ImplLoc, LocalFieldId, Macro2Id, Macro2Loc, MacroExpander, MacroId, + MacroRulesId, MacroRulesLoc, MacroRulesLocFlags, ProcMacroId, ProcMacroLoc, StaticId, + StaticLoc, StructId, StructLoc, TraitId, TraitLoc, TypeAliasId, TypeAliasLoc, UnionId, + UnionLoc, UseId, UseLoc, VariantId, attrs::AttrFlags, expr_store::{ Body, BodySourceMap, ExpressionStore, ExpressionStoreSourceMap, scope::ExprScopes, @@ -61,6 +62,9 @@ pub trait InternDatabase: RootQueryDb { #[salsa::interned] fn intern_static(&self, loc: StaticLoc) -> StaticId; + #[salsa::interned] + fn intern_anon_const(&self, loc: AnonConstLoc) -> AnonConstId; + #[salsa::interned] fn intern_trait(&self, loc: TraitLoc) -> TraitId; @@ -212,8 +216,15 @@ fn type_alias_signature_with_source_map( #[salsa::invoke(Body::body_query)] fn body(&self, def: DefWithBodyId) -> Arc; + #[salsa::invoke(ExprScopes::body_expr_scopes_query)] + fn body_expr_scopes(&self, def: DefWithBodyId) -> Arc; + + #[salsa::invoke(ExprScopes::sig_expr_scopes_query)] + fn sig_expr_scopes(&self, def: GenericDefId) -> Arc; + + #[salsa::transparent] #[salsa::invoke(ExprScopes::expr_scopes_query)] - fn expr_scopes(&self, def: DefWithBodyId) -> Arc; + fn expr_scopes(&self, def: ExpressionStoreOwner) -> Arc; #[salsa::transparent] #[salsa::invoke(GenericParams::new)] 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 1ce4c881e7ea..8552c7284532 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 @@ -94,9 +94,24 @@ pub(crate) fn is_root(self) -> bool { pub type LifetimePtr = AstPtr; pub type LifetimeSource = InFile; +/// Describes where a const expression originated from. +/// +/// Used by signature/body inference to determine the expected type for each +/// const expression root. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum ConstExprOrigin { + /// Array length expression: `[T; ]` — expected type is `usize`. + ArrayLength, + /// Const parameter default value: `const N: usize = `. + ConstParam(crate::hir::generics::LocalTypeOrConstParamId), + /// Const generic argument in a path: `SomeType::<{ }>` or `some_fn::<{ }>()`. + /// Determining the expected type requires path resolution, so it is deferred. + GenericArgsPath, +} + // We split the store into types-only and expressions, because most stores (e.g. generics) // don't store any expressions and this saves memory. Same thing for the source map. -#[derive(Debug, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq)] struct ExpressionOnlyStore { exprs: Arena, pats: Arena, @@ -113,9 +128,15 @@ 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, + + /// Maps const expression roots to their origin. + /// + /// Populated during lowering. Used by signature inference to determine expected types, + /// and by `signature_const_expr_roots()` to enumerate roots for scope computation. + const_expr_origins: ThinVec<(ExprId, ConstExprOrigin)>, } -#[derive(Debug, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq)] pub struct ExpressionStore { expr_only: Option>, pub types: Arena, @@ -226,6 +247,7 @@ pub struct ExpressionStoreBuilder { pub types: Arena, block_scopes: Vec, ident_hygiene: FxHashMap, + pub const_expr_origins: 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). @@ -297,6 +319,7 @@ pub fn finish(self) -> (ExpressionStore, ExpressionStoreSourceMap) { mut bindings, mut binding_owners, mut ident_hygiene, + const_expr_origins, mut types, mut lifetimes, @@ -364,6 +387,7 @@ pub fn finish(self) -> (ExpressionStore, ExpressionStoreSourceMap) { binding_owners, block_scopes: block_scopes.into_boxed_slice(), ident_hygiene, + const_expr_origins: const_expr_origins.unwrap_or_default(), })) } else { None @@ -413,6 +437,29 @@ pub fn empty_singleton() -> (Arc, Arc EMPTY.clone() } + /// Returns all const expression root `ExprId`s found in this store. + /// + /// Used to compute expression scopes for signature stores. + pub fn signature_const_expr_roots(&self) -> impl Iterator { + self.const_expr_origins().iter().map(|&(id, _)| id) + } + + /// Like [`Self::signature_const_expr_roots`], but also returns the origin + /// of each const expression. + /// + /// This is used by signature inference to determine the expected type for + /// each root expression. + pub fn signature_const_expr_roots_with_origins( + &self, + ) -> impl Iterator { + self.const_expr_origins().iter().map(|&(id, origin)| (id, origin)) + } + + /// Returns the map of const expression roots to their origins. + pub fn const_expr_origins(&self) -> &[(ExprId, ConstExprOrigin)] { + self.expr_only.as_ref().map_or(&[], |it| &it.const_expr_origins) + } + /// Returns an iterator over all block expressions in this store that define inner items. pub fn blocks<'a>( &'a self, diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/body.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/body.rs index c955393b9cf2..ad8fa73ad839 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/body.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/body.rs @@ -99,7 +99,7 @@ pub(crate) fn body_with_source_map_query( DefWithBodyId::VariantId(v) => { let s = v.lookup(db); let src = s.source(db); - src.map(|it| it.expr()) + src.map(|it| it.const_arg()?.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 1cecd1976b40..67ce5eafc6d8 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 @@ -37,7 +37,7 @@ attrs::AttrFlags, db::DefDatabase, expr_store::{ - Body, BodySourceMap, ExprPtr, ExpressionStore, ExpressionStoreBuilder, + Body, BodySourceMap, ConstExprOrigin, ExprPtr, ExpressionStore, ExpressionStoreBuilder, ExpressionStoreDiagnostics, ExpressionStoreSourceMap, HygieneId, LabelPtr, LifetimePtr, PatPtr, TypePtr, expander::Expander, @@ -79,7 +79,7 @@ pub(super) fn lower_body( let mut self_param = None; let mut source_map_self_param = None; let mut params = vec![]; - let mut collector = ExprCollector::new(db, module, current_file_id); + let mut collector = ExprCollector::body(db, module, current_file_id); let skip_body = AttrFlags::query( db, @@ -186,7 +186,7 @@ pub(crate) fn lower_type_ref( module: ModuleId, type_ref: InFile>, ) -> (ExpressionStore, ExpressionStoreSourceMap, TypeRefId) { - let mut expr_collector = ExprCollector::new(db, module, type_ref.file_id); + let mut expr_collector = ExprCollector::signature(db, module, type_ref.file_id); let type_ref = expr_collector.lower_type_ref_opt(type_ref.value, &mut ExprCollector::impl_trait_allocator); let (store, source_map) = expr_collector.store.finish(); @@ -201,7 +201,7 @@ pub(crate) fn lower_generic_params( param_list: Option, where_clause: Option, ) -> (Arc, Arc, ExpressionStoreSourceMap) { - let mut expr_collector = ExprCollector::new(db, module, file_id); + let mut expr_collector = ExprCollector::signature(db, module, file_id); let mut collector = generics::GenericParamsCollector::new(def); collector.lower(&mut expr_collector, param_list, where_clause); let params = collector.finish(); @@ -215,7 +215,7 @@ pub(crate) fn lower_impl( impl_syntax: InFile, impl_id: ImplId, ) -> (ExpressionStore, ExpressionStoreSourceMap, TypeRefId, Option, Arc) { - let mut expr_collector = ExprCollector::new(db, module, impl_syntax.file_id); + let mut expr_collector = ExprCollector::signature(db, module, impl_syntax.file_id); let self_ty = expr_collector.lower_type_ref_opt_disallow_impl_trait(impl_syntax.value.self_ty()); let trait_ = impl_syntax.value.trait_().and_then(|it| match &it { @@ -243,7 +243,7 @@ pub(crate) fn lower_trait( trait_syntax: InFile, trait_id: TraitId, ) -> (ExpressionStore, ExpressionStoreSourceMap, Arc) { - let mut expr_collector = ExprCollector::new(db, module, trait_syntax.file_id); + let mut expr_collector = ExprCollector::signature(db, module, trait_syntax.file_id); let mut collector = generics::GenericParamsCollector::with_self_param( &mut expr_collector, trait_id.into(), @@ -271,7 +271,7 @@ pub(crate) fn lower_type_alias( Box<[TypeBound]>, Option, ) { - let mut expr_collector = ExprCollector::new(db, module, alias.file_id); + let mut expr_collector = ExprCollector::signature(db, module, alias.file_id); let bounds = alias .value .type_bound_list() @@ -313,7 +313,7 @@ pub(crate) fn lower_function( bool, bool, ) { - let mut expr_collector = ExprCollector::new(db, module, fn_.file_id); + let mut expr_collector = ExprCollector::signature(db, module, fn_.file_id); let mut collector = generics::GenericParamsCollector::new(function_id.into()); collector.lower(&mut expr_collector, fn_.value.generic_param_list(), fn_.value.where_clause()); let mut params = vec![]; @@ -532,7 +532,20 @@ fn check_is_used(&mut self, ec: &mut ExprCollector<'_>, id: BindingId) { } impl<'db> ExprCollector<'db> { - pub fn new( + /// Creates a collector for a signature store, this will populate `const_expr_origins` to any + /// top level const arg roots. + pub fn signature( + db: &dyn DefDatabase, + module: ModuleId, + current_file_id: HirFileId, + ) -> ExprCollector<'_> { + let mut this = Self::body(db, module, current_file_id); + this.store.const_expr_origins = Some(Default::default()); + this + } + + /// Creates a collector for a bidy store. + pub fn body( db: &dyn DefDatabase, module: ModuleId, current_file_id: HirFileId, @@ -577,7 +590,10 @@ pub(crate) fn span_map(&self) -> SpanMapRef<'_> { self.expander.span_map() } - pub fn lower_lifetime_ref(&mut self, lifetime: ast::Lifetime) -> LifetimeRefId { + pub(in crate::expr_store) fn lower_lifetime_ref( + &mut self, + lifetime: ast::Lifetime, + ) -> LifetimeRefId { // FIXME: Keyword check? let lifetime_ref = match &*lifetime.text() { "" | "'" => LifetimeRef::Error, @@ -588,7 +604,10 @@ pub fn lower_lifetime_ref(&mut self, lifetime: ast::Lifetime) -> LifetimeRefId { self.alloc_lifetime_ref(lifetime_ref, AstPtr::new(&lifetime)) } - pub fn lower_lifetime_ref_opt(&mut self, lifetime: Option) -> LifetimeRefId { + pub(in crate::expr_store) fn lower_lifetime_ref_opt( + &mut self, + lifetime: Option, + ) -> LifetimeRefId { match lifetime { Some(lifetime) => self.lower_lifetime_ref(lifetime), None => self.alloc_lifetime_ref_desugared(LifetimeRef::Placeholder), @@ -596,7 +615,7 @@ pub fn lower_lifetime_ref_opt(&mut self, lifetime: Option) -> Lif } /// Converts an `ast::TypeRef` to a `hir::TypeRef`. - pub fn lower_type_ref( + pub(in crate::expr_store) fn lower_type_ref( &mut self, node: ast::Type, impl_trait_lower_fn: ImplTraitLowerFn<'_>, @@ -621,6 +640,9 @@ pub fn lower_type_ref( } ast::Type::ArrayType(inner) => { let len = self.lower_const_arg_opt(inner.const_arg()); + if let Some(const_expr_origins) = &mut self.store.const_expr_origins { + const_expr_origins.push((len.expr, ConstExprOrigin::ArrayLength)); + } TypeRef::Array(ArrayType { ty: self.lower_type_ref_opt(inner.ty(), impl_trait_lower_fn), len, @@ -810,7 +832,7 @@ fn alloc_path(&mut self, path: Path, node: TypePtr) -> PathId { /// Collect `GenericArgs` from the parts of a fn-like path, i.e. `Fn(X, Y) /// -> Z` (which desugars to `Fn<(X, Y), Output=Z>`). - pub fn lower_generic_args_from_fn_path( + pub(in crate::expr_store) fn lower_generic_args_from_fn_path( &mut self, args: Option, ret_type: Option, @@ -905,6 +927,9 @@ pub(super) fn lower_generic_args( } ast::GenericArg::ConstArg(arg) => { let arg = self.lower_const_arg(arg); + if let Some(const_expr_origins) = &mut self.store.const_expr_origins { + const_expr_origins.push((arg.expr, ConstExprOrigin::GenericArgsPath)); + } args.push(GenericArg::Const(arg)) } } @@ -1045,17 +1070,30 @@ fn lower_type_bound( } fn lower_const_arg_opt(&mut self, arg: Option) -> ConstRef { - ConstRef { expr: self.collect_expr_opt(arg.and_then(|it| it.expr())) } + let const_expr_origins = self.store.const_expr_origins.take(); + let r = ConstRef { expr: self.collect_expr_opt(arg.and_then(|it| it.expr())) }; + self.store.const_expr_origins = const_expr_origins; + r } - fn lower_const_arg(&mut self, arg: ast::ConstArg) -> ConstRef { - ConstRef { expr: self.collect_expr_opt(arg.expr()) } + pub fn lower_const_arg(&mut self, arg: ast::ConstArg) -> ConstRef { + let const_expr_origins = self.store.const_expr_origins.take(); + let r = ConstRef { expr: self.collect_expr_opt(arg.expr()) }; + self.store.const_expr_origins = const_expr_origins; + r } fn collect_expr(&mut self, expr: ast::Expr) -> ExprId { self.maybe_collect_expr(expr).unwrap_or_else(|| self.missing_expr()) } + pub(in crate::expr_store) fn collect_expr_opt(&mut self, expr: Option) -> ExprId { + match expr { + Some(expr) => self.collect_expr(expr), + None => self.missing_expr(), + } + } + /// 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); @@ -2065,13 +2103,6 @@ fn collect_macro_call( } } - pub fn collect_expr_opt(&mut self, expr: Option) -> ExprId { - match expr { - Some(expr) => self.collect_expr(expr), - None => self.missing_expr(), - } - } - fn collect_macro_as_stmt( &mut self, statements: &mut Vec, 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 c570df42b2f6..03de7937bad3 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 @@ -141,12 +141,17 @@ fn lower_param_list(&mut self, ec: &mut ExprCollector<'_>, params: ast::GenericP const_param.ty(), &mut ExprCollector::impl_trait_error_allocator, ); - let param = ConstParamData { - name, - ty, - default: const_param.default_val().map(|it| ec.lower_const_arg(it)), - }; - let _idx = self.type_or_consts.alloc(param.into()); + let default = const_param.default_val().map(|it| ec.lower_const_arg(it)); + let param = ConstParamData { name, ty, default }; + let idx = self.type_or_consts.alloc(param.into()); + if let Some(default) = default + && let Some(const_expr_origins) = &mut ec.store.const_expr_origins + { + const_expr_origins.push(( + default.expr, + crate::expr_store::ConstExprOrigin::ConstParam(idx), + )); + } } ast::GenericParam::LifetimeParam(lifetime_param) => { let lifetime = ec.lower_lifetime_ref_opt(lifetime_param.lifetime()); diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/path/tests.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/path/tests.rs index f507841a91bf..6819eb3deb57 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/path/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/path/tests.rs @@ -21,7 +21,7 @@ fn lower_path(path: ast::Path) -> (TestDB, ExpressionStore, Option) { let (db, file_id) = TestDB::with_single_file(""); let krate = db.fetch_test_crate(); let mut ctx = - ExprCollector::new(&db, crate_def_map(&db, krate).root_module_id(), file_id.into()); + ExprCollector::signature(&db, crate_def_map(&db, krate).root_module_id(), file_id.into()); let lowered_path = ctx.lower_path(path, &mut ExprCollector::impl_trait_allocator); let (store, _) = ctx.store.finish(); (db, store, lowered_path) 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 1952dae9d71a..43ce053836c4 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 @@ -4,7 +4,7 @@ use triomphe::Arc; use crate::{ - BlockId, DefWithBodyId, + BlockId, DefWithBodyId, ExpressionStoreOwner, GenericDefId, db::DefDatabase, expr_store::{Body, ExpressionStore, HygieneId}, hir::{Binding, BindingId, Expr, ExprId, Item, LabelId, Pat, PatId, Statement}, @@ -51,13 +51,37 @@ pub struct ScopeData { } impl ExprScopes { - pub(crate) fn expr_scopes_query(db: &dyn DefDatabase, def: DefWithBodyId) -> Arc { + pub(crate) fn expr_scopes_query( + db: &dyn DefDatabase, + def: ExpressionStoreOwner, + ) -> Arc { + match def { + ExpressionStoreOwner::Body(def) => db.body_expr_scopes(def), + ExpressionStoreOwner::Signature(def) => db.sig_expr_scopes(def), + } + } + + pub(crate) fn body_expr_scopes_query( + db: &dyn DefDatabase, + def: DefWithBodyId, + ) -> Arc { let body = db.body(def); let mut scopes = ExprScopes::new_body(&body); scopes.shrink_to_fit(); Arc::new(scopes) } + pub(crate) fn sig_expr_scopes_query( + db: &dyn DefDatabase, + def: GenericDefId, + ) -> Arc { + let (_, store) = db.generic_params_and_store(def); + let roots = store.signature_const_expr_roots(); + let mut scopes = ExprScopes::new_store(&store, roots); + scopes.shrink_to_fit(); + Arc::new(scopes) + } + pub fn entries(&self, scope: ScopeId) -> &[ScopeEntry] { &self.scope_entries[self.scopes[scope].entries.clone()] } @@ -119,6 +143,22 @@ fn new_body(body: &Body) -> ExprScopes { scopes } + fn new_store(store: &ExpressionStore, roots: impl IntoIterator) -> ExprScopes { + let mut scopes = ExprScopes { + scopes: Arena::default(), + scope_entries: Arena::default(), + scope_by_expr: ArenaMap::with_capacity( + store.expr_only.as_ref().map_or(0, |it| it.exprs.len()), + ), + }; + let root = scopes.root_scope(); + for root_expr in roots { + let mut scope = scopes.new_scope(root); + compute_expr_scopes(root_expr, store, &mut scopes, &mut scope); + } + scopes + } + fn root_scope(&mut self) -> ScopeId { self.scopes.alloc(ScopeData { parent: None, @@ -327,7 +367,8 @@ mod tests { use test_utils::{assert_eq_text, extract_offset}; use crate::{ - FunctionId, ModuleDefId, db::DefDatabase, nameres::crate_def_map, test_db::TestDB, + DefWithBodyId, FunctionId, ModuleDefId, db::DefDatabase, nameres::crate_def_map, + test_db::TestDB, }; fn find_function(db: &TestDB, file_id: FileId) -> FunctionId { @@ -363,7 +404,7 @@ fn do_check(#[rust_analyzer::rust_fixture] ra_fixture: &str, expected: &[&str]) let marker: ast::PathExpr = find_node_at_offset(&file_syntax, offset).unwrap(); let function = find_function(&db, file_id); - let scopes = db.expr_scopes(function.into()); + let scopes = db.expr_scopes(DefWithBodyId::from(function).into()); let (_body, source_map) = db.body_with_source_map(function.into()); let expr_id = source_map @@ -522,7 +563,7 @@ fn do_check_local_name(#[rust_analyzer::rust_fixture] ra_fixture: &str, expected let function = find_function(&db, file_id); - let scopes = db.expr_scopes(function.into()); + let scopes = db.expr_scopes(DefWithBodyId::from(function).into()); let (_, source_map) = db.body_with_source_map(function.into()); let expr_scope = { 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 de674be05f64..ffad5fee47ff 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs @@ -86,7 +86,10 @@ builtin_type::BuiltinType, db::DefDatabase, expr_store::ExpressionStoreSourceMap, - hir::generics::{GenericParams, LocalLifetimeParamId, LocalTypeOrConstParamId}, + hir::{ + ExprId, + generics::{GenericParams, LocalLifetimeParamId, LocalTypeOrConstParamId}, + }, nameres::{ LocalDefMap, assoc::{ImplItems, TraitItems}, @@ -306,6 +309,19 @@ pub fn enum_variants_with_diagnostics( pub type StaticLoc = AssocItemLoc; impl_intern!(StaticId, StaticLoc, intern_static, lookup_intern_static); +/// An anonymous const expression that appears in a type position (e.g., array lengths, +/// const generic arguments like `{ N + 1 }`). Unlike named constants, these don't have +/// their own `Body` — their expressions live in the parent's signature `ExpressionStore`. +#[derive(Debug, Hash, PartialEq, Eq, Clone)] +pub struct AnonConstLoc { + /// The owner store containing this expression. + pub owner: ExpressionStoreOwner, + /// The ExprId within the owner's ExpressionStore that is the root + /// of this anonymous const expression. + pub expr: ExprId, +} +impl_intern!(AnonConstId, AnonConstLoc, intern_anon_const, lookup_intern_anon_const); + pub type TraitLoc = ItemLoc; impl_intern!(TraitId, TraitLoc, intern_trait, lookup_intern_trait); @@ -706,15 +722,17 @@ fn from(value: DefWithBodyId) -> Self { pub enum GeneralConstId { ConstId(ConstId), StaticId(StaticId), + AnonConstId(AnonConstId), } -impl_from!(ConstId, StaticId for GeneralConstId); +impl_from!(ConstId, StaticId, AnonConstId for GeneralConstId); impl GeneralConstId { - pub fn generic_def(self, _db: &dyn DefDatabase) -> Option { + pub fn generic_def(self, db: &dyn DefDatabase) -> Option { match self { GeneralConstId::ConstId(it) => Some(it.into()), GeneralConstId::StaticId(it) => Some(it.into()), + GeneralConstId::AnonConstId(it) => Some(it.lookup(db).owner.generic_def(db)), } } @@ -729,6 +747,7 @@ pub fn name(self, db: &dyn DefDatabase) -> String { |name| name.display(db, Edition::CURRENT).to_string(), ) } + GeneralConstId::AnonConstId(_) => "{anon const}".to_owned(), } } } @@ -814,6 +833,45 @@ pub enum GenericDefId { for GenericDefId ); +/// Owner of an expression store - either a body or a signature. +/// This is used for queries that operate on expression stores generically, +/// such as `expr_scopes`. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub enum ExpressionStoreOwner { + Signature(GenericDefId), + Body(DefWithBodyId), +} + +impl ExpressionStoreOwner { + pub fn as_def_with_body(self) -> Option { + if let Self::Body(v) = self { Some(v) } else { None } + } + + pub fn generic_def(self, db: &dyn DefDatabase) -> GenericDefId { + match self { + ExpressionStoreOwner::Signature(generic_def_id) => generic_def_id, + ExpressionStoreOwner::Body(def_with_body_id) => match def_with_body_id { + DefWithBodyId::FunctionId(id) => GenericDefId::FunctionId(id), + DefWithBodyId::StaticId(id) => GenericDefId::StaticId(id), + DefWithBodyId::ConstId(id) => GenericDefId::ConstId(id), + DefWithBodyId::VariantId(it) => it.lookup(db).parent.into(), + }, + } + } +} + +impl From for ExpressionStoreOwner { + fn from(id: GenericDefId) -> Self { + ExpressionStoreOwner::Signature(id) + } +} + +impl From for ExpressionStoreOwner { + fn from(id: DefWithBodyId) -> Self { + ExpressionStoreOwner::Body(id) + } +} + impl GenericDefId { pub fn file_id_and_params_of( self, @@ -1172,6 +1230,15 @@ fn module(&self, db: &dyn DefDatabase) -> ModuleId { } } +impl HasModule for ExpressionStoreOwner { + fn module(&self, db: &dyn DefDatabase) -> ModuleId { + match self { + ExpressionStoreOwner::Signature(def) => def.module(db), + ExpressionStoreOwner::Body(def) => def.module(db), + } + } +} + impl HasModule for GenericDefId { fn module(&self, db: &dyn DefDatabase) -> ModuleId { match self { 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 d32e53fc6bee..392010df8507 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs @@ -16,11 +16,11 @@ use triomphe::Arc; use crate::{ - AdtId, AstIdLoc, ConstId, ConstParamId, DefWithBodyId, EnumId, EnumVariantId, ExternBlockId, - ExternCrateId, FunctionId, FxIndexMap, GenericDefId, GenericParamId, HasModule, ImplId, - ItemContainerId, LifetimeParamId, Lookup, Macro2Id, MacroId, MacroRulesId, ModuleDefId, - ModuleId, ProcMacroId, StaticId, StructId, TraitId, TypeAliasId, TypeOrConstParamId, - TypeParamId, UseId, VariantId, + AdtId, AstIdLoc, ConstId, ConstParamId, DefWithBodyId, EnumId, EnumVariantId, + ExpressionStoreOwner, ExternBlockId, ExternCrateId, FunctionId, FxIndexMap, GenericDefId, + GenericParamId, HasModule, ImplId, ItemContainerId, LifetimeParamId, Lookup, Macro2Id, MacroId, + MacroRulesId, ModuleDefId, ModuleId, ProcMacroId, StaticId, StructId, TraitId, TypeAliasId, + TypeOrConstParamId, TypeParamId, UseId, VariantId, builtin_type::BuiltinType, db::DefDatabase, expr_store::{ @@ -66,7 +66,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { #[derive(Clone)] struct ExprScope { - owner: DefWithBodyId, + owner: ExpressionStoreOwner, expr_scopes: Arc, scope_id: ScopeId, } @@ -738,7 +738,10 @@ pub fn all_generic_params(&self) -> impl Iterator Option { self.scopes().find_map(|scope| match scope { - Scope::ExprScope(it) => Some(it.owner), + Scope::ExprScope(it) => match it.owner { + ExpressionStoreOwner::Body(def) => Some(def), + ExpressionStoreOwner::Signature(_) => None, + }, _ => None, }) } @@ -854,14 +857,15 @@ pub fn rename_will_conflict_with_renamed( pub fn update_to_inner_scope( &mut self, db: &'db dyn DefDatabase, - owner: DefWithBodyId, + owner: impl Into, expr_id: ExprId, ) -> UpdateGuard { + let owner = owner.into(); #[inline(always)] fn append_expr_scope<'db>( db: &'db dyn DefDatabase, resolver: &mut Resolver<'db>, - owner: DefWithBodyId, + owner: ExpressionStoreOwner, expr_scopes: &Arc, scope_id: ScopeId, ) { @@ -1060,12 +1064,13 @@ fn process_names(&self, acc: &mut ScopeNames, db: &'db dyn DefDatabase) { pub fn resolver_for_scope( db: &dyn DefDatabase, - owner: DefWithBodyId, + owner: impl Into + HasResolver, scope_id: Option, ) -> Resolver<'_> { - let r = owner.resolver(db); - let scopes = db.expr_scopes(owner); - resolver_for_scope_(db, scopes, scope_id, r, owner) + let store_owner = owner.into(); + let r = store_owner.resolver(db); + let scopes = db.expr_scopes(store_owner); + resolver_for_scope_(db, scopes, scope_id, r, store_owner) } fn resolver_for_scope_<'db>( @@ -1073,7 +1078,7 @@ fn resolver_for_scope_<'db>( scopes: Arc, scope_id: Option, mut r: Resolver<'db>, - owner: DefWithBodyId, + owner: ExpressionStoreOwner, ) -> Resolver<'db> { let scope_chain = scopes.scope_chain(scope_id).collect::>(); r.scopes.reserve(scope_chain.len()); @@ -1124,7 +1129,7 @@ fn push_block_scope( fn push_expr_scope( self, - owner: DefWithBodyId, + owner: ExpressionStoreOwner, expr_scopes: Arc, scope_id: ScopeId, ) -> Resolver<'db> { @@ -1409,6 +1414,15 @@ fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> { } } +impl HasResolver for ExpressionStoreOwner { + fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> { + match self { + ExpressionStoreOwner::Signature(def) => def.resolver(db), + ExpressionStoreOwner::Body(def) => def.resolver(db), + } + } +} + impl HasResolver for EnumVariantId { fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> { self.lookup(db).parent.resolver(db) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/signatures.rs b/src/tools/rust-analyzer/crates/hir-def/src/signatures.rs index 37c8f762fe5d..ce76158151c3 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/signatures.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/signatures.rs @@ -32,7 +32,7 @@ hir::{ExprId, PatId, generics::GenericParams}, item_tree::{FieldsShape, RawVisibility, visibility_from_ast}, src::HasSource, - type_ref::{TraitRef, TypeBound, TypeRefId}, + type_ref::{ConstRef, TraitRef, TypeBound, TypeRefId}, }; #[inline] @@ -754,7 +754,7 @@ pub struct FieldData { pub type_ref: TypeRefId, pub visibility: RawVisibility, pub is_unsafe: bool, - pub default_value: Option, + pub default_value: Option, } pub type LocalFieldId = Idx; @@ -873,7 +873,7 @@ fn lower_fields( override_visibility: Option>, ) -> Option<(Arena, ExpressionStore, ExpressionStoreSourceMap)> { let cfg_options = module.krate(db).cfg_options(db); - let mut col = ExprCollector::new(db, module, fields.file_id); + let mut col = ExprCollector::signature(db, module, fields.file_id); let override_visibility = override_visibility.map(|vis| { LazyCell::new(|| { let span_map = db.span_map(fields.file_id); @@ -907,9 +907,9 @@ fn lower_fields( // Check if field has default value (only for record fields) let default_value = ast::RecordField::cast(field.syntax().clone()) - .and_then(|rf| rf.eq_token().is_some().then_some(rf.expr())) + .and_then(|rf| rf.eq_token().is_some().then_some(rf.default_val())) .flatten() - .map(|expr| col.collect_expr_opt(Some(expr))); + .map(|expr| col.lower_const_arg(expr)); arena.alloc(FieldData { name, type_ref, visibility, is_unsafe, default_value }); idx += 1; 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 e8377fde4987..d2921db6f4fa 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 @@ -285,7 +285,7 @@ fn block_at_position(&self, def_map: &DefMap, position: FilePosition) -> Option< let (def_with_body, file_id) = fn_def?; let def_with_body = def_with_body.into(); let source_map = self.body_with_source_map(def_with_body).1; - let scopes = self.expr_scopes(def_with_body); + let scopes = self.expr_scopes(def_with_body.into()); let root_syntax_node = self.parse(file_id).syntax_node(); let scope_iter = 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 07e9f70faea6..9ff788c2e218 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs @@ -235,6 +235,7 @@ pub fn try_const_usize<'db>(db: &'db dyn HirDatabase, c: Const<'db>) -> Option None, }, ConstKind::Value(val) => Some(u128::from_le_bytes(pad16(&val.value.inner().memory, false))), ConstKind::Error(_) => None, @@ -258,6 +259,7 @@ pub fn try_const_isize<'db>(db: &'db dyn HirDatabase, c: &Const<'db>) -> Option< let ec = db.const_eval_static(id).ok()?; try_const_isize(db, &ec) } + GeneralConstId::AnonConstId(_) => None, }, ConstKind::Value(val) => Some(i128::from_le_bytes(pad16(&val.value.inner().memory, true))), ConstKind::Error(_) => None, @@ -333,7 +335,8 @@ fn has_closure(body: &Body, expr: ExprId) -> bool { return c; } } - if let Ok(mir_body) = lower_body_to_mir(ctx.db, ctx.owner, ctx.body, &infer, expr) + if let Some(body_owner) = ctx.owner.as_def_with_body() + && let Ok(mir_body) = lower_body_to_mir(ctx.db, body_owner, ctx.body, &infer, expr) && let Ok((Ok(result), _)) = interpret_mir(ctx.db, Arc::new(mir_body), true, None) { return result; 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 70474fc46919..ca5b1b771631 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs @@ -5,9 +5,9 @@ use either::Either; use hir_def::{ AdtId, BuiltinDeriveImplId, CallableDefId, ConstId, ConstParamId, DefWithBodyId, EnumVariantId, - FunctionId, GenericDefId, ImplId, LifetimeParamId, LocalFieldId, StaticId, TraitId, - TypeAliasId, VariantId, builtin_derive::BuiltinDeriveImplMethod, db::DefDatabase, hir::ExprId, - layout::TargetDataLayout, + ExpressionStoreOwner, FunctionId, GenericDefId, ImplId, LifetimeParamId, LocalFieldId, + StaticId, TraitId, TypeAliasId, VariantId, builtin_derive::BuiltinDeriveImplMethod, + db::DefDatabase, hir::ExprId, layout::TargetDataLayout, }; use la_arena::ArenaMap; use salsa::plumbing::AsId; @@ -240,7 +240,7 @@ pub struct InternedOpaqueTyId { } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] -pub struct InternedClosure(pub DefWithBodyId, pub ExprId); +pub struct InternedClosure(pub ExpressionStoreOwner, pub ExprId); #[salsa_macros::interned(no_lifetime, debug, revisions = usize::MAX)] #[derive(PartialOrd, Ord)] @@ -249,7 +249,7 @@ pub struct InternedClosureId { } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] -pub struct InternedCoroutine(pub DefWithBodyId, pub ExprId); +pub struct InternedCoroutine(pub ExpressionStoreOwner, pub ExprId); #[salsa_macros::interned(no_lifetime, debug, revisions = usize::MAX)] #[derive(PartialOrd, Ord)] 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 4e77e8be364b..f4d0ed148492 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs @@ -1336,7 +1336,11 @@ fn hir_fmt(&self, f @ &mut HirFormatter { db, .. }: &mut HirFormatter<'_, 'db>) } let sig = interner.signature_unclosure(substs.as_closure().sig(), Safety::Safe); let sig = sig.skip_binder(); - let InternedClosure(def, _) = db.lookup_intern_closure(id); + let InternedClosure(owner, _) = db.lookup_intern_closure(id); + let Some(def) = owner.as_def_with_body() else { + write!(f, "{{closure}}")?; + return Ok(()); + }; let infer = InferenceResult::for_body(db, def); let (_, kind) = infer.closure_info(id); match f.closure_style { @@ -1526,7 +1530,13 @@ fn hir_fmt(&self, f @ &mut HirFormatter { db, .. }: &mut HirFormatter<'_, 'db>) let InternedCoroutine(owner, expr_id) = coroutine_id.0.loc(db); let CoroutineArgsParts { resume_ty, yield_ty, return_ty, .. } = subst.split_coroutine_args(); - let body = db.body(owner); + let Some(body_owner) = owner.as_def_with_body() else { + write!(f, "impl Future")?; + return Ok(()); + }; + let body = db.body(body_owner); let expr = &body[expr_id]; match expr { hir_def::hir::Expr::Closure { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/drop.rs b/src/tools/rust-analyzer/crates/hir-ty/src/drop.rs index 9d6869eee9b8..1303e08801bd 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/drop.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/drop.rs @@ -132,9 +132,12 @@ fn has_drop_glue_impl<'db>( TyKind::Slice(ty) => has_drop_glue_impl(infcx, ty, env, visited), TyKind::Closure(closure_id, subst) => { let owner = db.lookup_intern_closure(closure_id.0).0; - let infer = InferenceResult::for_body(db, owner); + let Some(body_owner) = owner.as_def_with_body() else { + return DropGlue::None; + }; + let infer = InferenceResult::for_body(db, body_owner); let (captures, _) = infer.closure_info(closure_id.0); - let env = db.trait_environment_for_body(owner); + let env = db.trait_environment_for_body(body_owner); captures .iter() .map(|capture| has_drop_glue_impl(infcx, capture.ty(db, subst), env, visited)) 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 991acda14bc7..a4fcded42b66 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs @@ -33,9 +33,10 @@ use base_db::Crate; use either::Either; use hir_def::{ - AdtId, AssocItemId, ConstId, DefWithBodyId, FieldId, FunctionId, GenericDefId, GenericParamId, - ItemContainerId, LocalFieldId, Lookup, TraitId, TupleFieldId, TupleId, TypeAliasId, VariantId, - expr_store::{Body, ExpressionStore, HygieneId, path::Path}, + AdtId, AnonConstId, AssocItemId, ConstId, ConstParamId, DefWithBodyId, ExpressionStoreOwner, + FieldId, FunctionId, GenericDefId, GenericParamId, ItemContainerId, LocalFieldId, Lookup, + TraitId, TupleFieldId, TupleId, TypeAliasId, TypeOrConstParamId, VariantId, + expr_store::{Body, ConstExprOrigin, ExpressionStore, HygieneId, path::Path}, hir::{BindingAnnotation, BindingId, ExprId, ExprOrPatId, LabelId, PatId}, lang_item::LangItems, layout::Integer, @@ -105,7 +106,7 @@ pub fn infer_query_with_inspect<'db>( let _p = tracing::info_span!("infer_query").entered(); let resolver = def.resolver(db); let body = db.body(def); - let mut ctx = InferenceContext::new(db, def, &body, resolver); + let mut ctx = InferenceContext::new(db, ExpressionStoreOwner::Body(def), &body, resolver); if let Some(inspect) = inspect { ctx.table.infer_ctxt.attach_obligation_inspector(inspect); @@ -179,6 +180,68 @@ fn infer_cycle_result(db: &dyn HirDatabase, _: salsa::Id, _: DefWithBodyId) -> I } } +/// Infer types for all const expressions in an item's signature. +/// +/// This handles const expressions that appear in type positions within a generic +/// item's signature, such as array lengths (`[T; N]`) and const generic arguments +/// (`Foo<{ expr }>`). Each root expression is inferred independently within +/// a shared `InferenceContext`, accumulating results into a single `InferenceResult`. +fn infer_signature_query(db: &dyn HirDatabase, def: GenericDefId) -> InferenceResult { + let _p = tracing::info_span!("infer_signature_query").entered(); + let (_, store) = db.generic_params_and_store(def); + let mut roots = store.signature_const_expr_roots_with_origins().peekable(); + let Some(&(first, _)) = roots.peek() else { + return InferenceResult::new(crate::next_solver::default_types(db).types.error); + }; + + let resolver = def.resolver(db); + let owner = ExpressionStoreOwner::Signature(def); + + // Construct a synthetic `Body` to satisfy `InferenceContext`. + // The `body_expr` is set to the first root as a placeholder; we infer + // each root expression individually below rather than calling `infer_body`. + let body = Body { + // FIXME: Get rid of this clone + store: (*store).clone(), + params: Box::new([]), + self_param: None, + body_expr: first, + }; + + let mut ctx = InferenceContext::new(db, owner, &body, resolver); + + for (root_expr, origin) in roots { + let expected = match origin { + // Array lengths are always `usize`. + ConstExprOrigin::ArrayLength => Expectation::has_type(ctx.types.types.usize), + // Const parameter default: look up the param's declared type. + ConstExprOrigin::ConstParam(local_id) => Expectation::has_type(db.const_param_ty_ns( + ConstParamId::from_unchecked(TypeOrConstParamId { parent: def, local_id }), + )), + // Path const generic args: determining the expected type requires + // path resolution. + // FIXME + ConstExprOrigin::GenericArgsPath => Expectation::None, + }; + ctx.infer_expr(root_expr, &expected, ExprIsRead::Yes); + } + + ctx.type_inference_fallback(); + ctx.table.select_obligations_where_possible(); + ctx.resolve_all() +} + +fn infer_signature_cycle_result( + db: &dyn HirDatabase, + _: salsa::Id, + _: GenericDefId, +) -> InferenceResult { + InferenceResult { + has_errors: true, + ..InferenceResult::new(Ty::new_error(DbInterner::new_no_crate(db), ErrorGuaranteed)) + } +} + /// Binding modes inferred for patterns. /// #[derive(Copy, Clone, Debug, Eq, PartialEq, Default)] @@ -555,9 +618,37 @@ impl InferenceResult { pub fn for_body(db: &dyn HirDatabase, def: DefWithBodyId) -> InferenceResult { infer_query(db, def) } + + /// 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_signature_cycle_result)] + pub fn for_signature(db: &dyn HirDatabase, def: GenericDefId) -> InferenceResult { + infer_signature_query(db, def) + } } impl InferenceResult { + /// Look up inference results for a specific anonymous const in a signature. + /// + /// This delegates to [`Self::for_signature`] on the anon const's owner. + /// The returned `InferenceResult` contains types for *all* expressions in + /// the owner's signature store, not just this anon const's sub-tree. + /// Callers should index into it with `loc.expr` to get the root expression's + /// type. + // FIXME: This function doesn't make sense in that we can't return a full inference result here + // as the anon const is just part of an inference result. + pub fn for_anon_const(db: &dyn HirDatabase, id: AnonConstId) -> &InferenceResult { + match id.lookup(db).owner { + ExpressionStoreOwner::Signature(generic_def_id) => { + Self::for_signature(db, generic_def_id) + } + ExpressionStoreOwner::Body(def_with_body_id) => Self::for_body(db, def_with_body_id), + } + } + fn new(error_ty: Ty<'_>) -> Self { Self { method_resolutions: Default::default(), @@ -754,7 +845,7 @@ pub fn binding_ty<'db>(&self, id: BindingId) -> Ty<'db> { #[derive(Clone, Debug)] pub(crate) struct InferenceContext<'body, 'db> { pub(crate) db: &'db dyn HirDatabase, - pub(crate) owner: DefWithBodyId, + pub(crate) owner: ExpressionStoreOwner, pub(crate) body: &'body Body, /// 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. @@ -855,12 +946,18 @@ fn find_continuable<'a, 'db>( impl<'body, 'db> InferenceContext<'body, 'db> { fn new( db: &'db dyn HirDatabase, - owner: DefWithBodyId, + owner: ExpressionStoreOwner, body: &'body Body, resolver: Resolver<'db>, ) -> Self { - let trait_env = db.trait_environment_for_body(owner); - let table = unify::InferenceTable::new(db, trait_env, resolver.krate(), Some(owner)); + let trait_env = match owner { + ExpressionStoreOwner::Signature(generic_def_id) => db.trait_environment(generic_def_id), + ExpressionStoreOwner::Body(def_with_body_id) => { + db.trait_environment_for_body(def_with_body_id) + } + }; + let table = + unify::InferenceTable::new(db, trait_env, resolver.krate(), owner.as_def_with_body()); let types = crate::next_solver::default_types(db); InferenceContext { result: InferenceResult::new(types.types.error), @@ -878,12 +975,7 @@ fn new( return_coercion: None, db, owner, - generic_def: match owner { - DefWithBodyId::FunctionId(it) => it.into(), - DefWithBodyId::StaticId(it) => it.into(), - DefWithBodyId::ConstId(it) => it.into(), - DefWithBodyId::VariantId(it) => it.lookup(db).parent.into(), - }, + generic_def: owner.generic_def(db), body, traits_in_scope: resolver.traits_in_scope(db), resolver, @@ -908,7 +1000,9 @@ fn krate(&self) -> Crate { fn target_features(&self) -> (&TargetFeatures<'db>, TargetFeatureIsSafeInTarget) { let (target_features, target_feature_is_safe) = self.target_features.get_or_init(|| { let target_features = match self.owner { - DefWithBodyId::FunctionId(id) => TargetFeatures::from_fn(self.db, id), + ExpressionStoreOwner::Body(DefWithBodyId::FunctionId(id)) => { + TargetFeatures::from_fn(self.db, id) + } _ => TargetFeatures::default(), }; let target_feature_is_safe = match &self.krate().workspace_data(self.db).target { 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 5a3eba1a71ae..b4cc2ab4ae5b 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 @@ -866,7 +866,7 @@ fn restrict_precision_for_unsafe(&mut self) { &self.table.infer_ctxt, self.table.param_env, ty, - self.owner.module(self.db).krate(self.db), + self.owner.krate(self.db), ); if ty.is_raw_ptr() || ty.is_union() { capture.kind = CaptureKind::ByRef(BorrowKind::Shared); 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 e79868f4ae6b..47a70492487e 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 @@ -1718,6 +1718,9 @@ fn fold_region(&mut self, r: Region<'db>) -> Region<'db> { fn is_capturing_closure(db: &dyn HirDatabase, closure: InternedClosureId) -> bool { let InternedClosure(owner, expr) = closure.loc(db); - upvars_mentioned(db, owner) + let Some(body_owner) = owner.as_def_with_body() else { + return false; + }; + upvars_mentioned(db, body_owner) .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/pat.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs index 87fd0dace38f..9ba2d634d58a 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 @@ -3,7 +3,7 @@ use std::{cmp, iter}; use hir_def::{ - HasModule, + HasModule as _, expr_store::{Body, path::Path}, hir::{Binding, BindingAnnotation, BindingId, Expr, ExprId, Literal, Pat, PatId}, }; 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 525100439f5b..a325b2e17438 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs @@ -333,7 +333,10 @@ pub fn layout_of_ty_query( } TyKind::Closure(id, args) => { let def = db.lookup_intern_closure(id.0); - let infer = InferenceResult::for_body(db, def.0); + let Some(body_owner) = def.0.as_def_with_body() else { + return Err(LayoutError::HasErrorType); + }; + let infer = InferenceResult::for_body(db, body_owner); let (captures, _) = infer.closure_info(id.0); let fields = captures .iter() 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 49594f34fd73..45500cfd2213 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs @@ -279,11 +279,12 @@ pub fn lower_ty(&mut self, type_ref: TypeRefId) -> Ty<'db> { } pub(crate) fn lower_const(&mut self, const_ref: ConstRef, const_type: Ty<'db>) -> Const<'db> { - let const_ref = &self.store[const_ref.expr]; - match const_ref { - hir_def::hir::Expr::Path(path) => { - self.path_to_const(path).unwrap_or_else(|| unknown_const(const_type)) - } + let expr_id = const_ref.expr; + let expr = &self.store[expr_id]; + match expr { + hir_def::hir::Expr::Path(path) => self + .path_to_const(path) + .unwrap_or_else(|| Const::new(self.interner, ConstKind::Error(ErrorGuaranteed))), hir_def::hir::Expr::Literal(literal) => { intern_const_ref(self.db, literal, const_type, self.resolver.krate()) } @@ -300,20 +301,74 @@ pub(crate) fn lower_const(&mut self, const_ref: ConstRef, const_type: Ty<'db>) - self.resolver.krate(), ) } else { - unknown_const(const_type) + Const::new(self.interner, ConstKind::Error(ErrorGuaranteed)) } } // For unsigned integers, chars, bools, etc., negation is not meaningful - _ => unknown_const(const_type), + _ => Const::new(self.interner, ConstKind::Error(ErrorGuaranteed)), } } else { - unknown_const(const_type) + // Complex negation expression (e.g. `-N` where N is a const param) + self.lower_const_as_unevaluated(expr_id, const_type) } } - _ => unknown_const(const_type), + hir_def::hir::Expr::Underscore => { + Const::new(self.interner, ConstKind::Error(ErrorGuaranteed)) + } + // Any other complex expression becomes an unevaluated anonymous const. + _ => self.lower_const_as_unevaluated(expr_id, const_type), } } + /// Lower a complex const expression to an `UnevaluatedConst` backed by an `AnonConstId`. + /// + /// The `expected_ty_ref` is `None` for array lengths (implicitly `usize`) or + /// `Some(type_ref_id)` for const generic arguments where the expected type comes + /// from the const parameter declaration. + fn lower_const_as_unevaluated( + &mut self, + _expr: hir_def::hir::ExprId, + _expected_ty: Ty<'db>, + ) -> Const<'db> { + // /// Build the identity generic args for the current generic context. + // /// + // /// This maps each generic parameter to itself (as a `ParamTy`, `ParamConst`, + // /// or `EarlyParamRegion`), which is the correct substitution when creating + // /// an `UnevaluatedConst` during type lowering — the anon const inherits the + // /// parent's generics and they haven't been substituted yet. + // fn current_generic_args(&self) -> GenericArgs<'db> { + // let generics = self.generics(); + // let interner = self.interner; + // GenericArgs::new_from_iter( + // interner, + // generics.iter_id().enumerate().map(|(index, id)| match id { + // GenericParamId::TypeParamId(id) => { + // GenericArg::from(Ty::new_param(interner, id, index as u32)) + // } + // GenericParamId::ConstParamId(id) => GenericArg::from(Const::new_param( + // interner, + // ParamConst { id, index: index as u32 }, + // )), + // GenericParamId::LifetimeParamId(id) => GenericArg::from(Region::new_early_param( + // interner, + // EarlyParamRegion { id, index: index as u32 }, + // )), + // }), + // ) + // } + // let loc = AnonConstLoc { owner: self.def, expr }; + // let id = loc.intern(self.db); + // let args = self.current_generic_args(); + // Const::new( + // self.interner, + // ConstKind::Unevaluated(UnevaluatedConst::new( + // GeneralConstId::AnonConstId(id).into(), + // args, + // )), + // ) + Const::new(self.interner, ConstKind::Error(ErrorGuaranteed)) + } + pub(crate) fn path_to_const(&mut self, path: &Path) -> Option> { match self.resolver.resolve_path_in_value_ns_fully(self.db, path, HygieneId::ROOT) { Some(ValueNs::GenericParam(p)) => { 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 dece61a57df5..2dcc2d1062fd 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 @@ -8,7 +8,7 @@ use hir_def::{DefWithBodyId, HasModule}; use la_arena::ArenaMap; use rustc_hash::FxHashMap; -use rustc_type_ir::inherent::GenericArgs as _; +use rustc_type_ir::inherent::{GenericArgs as _, Ty as _}; use stdx::never; use triomphe::Arc; @@ -18,7 +18,7 @@ display::DisplayTarget, mir::OperandKind, next_solver::{ - DbInterner, GenericArgs, ParamEnv, StoredTy, Ty, TypingMode, + DbInterner, ErrorGuaranteed, GenericArgs, ParamEnv, StoredTy, Ty, TypingMode, infer::{DbInternerInferExt, InferCtxt}, }, }; @@ -121,11 +121,14 @@ fn make_fetch_closure_field<'db>( db: &'db dyn HirDatabase, ) -> impl FnOnce(InternedClosureId, GenericArgs<'db>, usize) -> Ty<'db> + use<'db> { |c: InternedClosureId, subst: GenericArgs<'db>, f: usize| { - let InternedClosure(def, _) = db.lookup_intern_closure(c); + let InternedClosure(owner, _) = db.lookup_intern_closure(c); + let interner = DbInterner::new_no_crate(db); + let Some(def) = owner.as_def_with_body() else { + return Ty::new_error(interner, ErrorGuaranteed); + }; let infer = InferenceResult::for_body(db, def); let (captures, _) = infer.closure_info(c); let parent_subst = subst.as_closure().parent_args(); - let interner = DbInterner::new_no_crate(db); captures.get(f).expect("broken closure field").ty.get().instantiate(interner, parent_subst) } } 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 ec0723c3f8c3..a85b3ef50aa5 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 @@ -730,7 +730,10 @@ fn projected_ty(&self, ty: Ty<'db>, proj: PlaceElem) -> Ty<'db> { self.param_env.param_env, ty, |c, subst, f| { - let InternedClosure(def, _) = self.db.lookup_intern_closure(c); + let InternedClosure(owner, _) = self.db.lookup_intern_closure(c); + let Some(def) = owner.as_def_with_body() else { + return Ty::new_error(self.interner(), ErrorGuaranteed); + }; let infer = InferenceResult::for_body(self.db, def); let (captures, _) = infer.closure_info(c); let parent_subst = subst.as_closure().parent_args(); @@ -1954,6 +1957,9 @@ fn allocate_const_in_heap( MirEvalError::ConstEvalError(name, Box::new(e)) })? } + GeneralConstId::AnonConstId(_) => { + not_supported!("anonymous const evaluation") + } }; if let ConstKind::Value(value) = result_owner.kind() { break 'b value; 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 76c8701ea209..a0dd3b5846f4 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 @@ -152,7 +152,10 @@ fn exec_clone( not_supported!("wrong arg count for clone"); }; let addr = Address::from_bytes(arg.get(self)?)?; - let InternedClosure(closure_owner, _) = self.db.lookup_intern_closure(id.0); + let InternedClosure(owner, _) = self.db.lookup_intern_closure(id.0); + let Some(closure_owner) = owner.as_def_with_body() else { + not_supported!("closure in non-body context"); + }; let infer = InferenceResult::for_body(self.db, closure_owner); let (captures, _) = infer.closure_info(id.0); let layout = self.layout(self_ty)?; 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 2e849bcf3a12..269d8729baf3 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 @@ -1546,6 +1546,9 @@ fn lower_const_to_operand( MirLowerError::ConstEvalError(name.into(), Box::new(e)) })? } + GeneralConstId::AnonConstId(_) => { + return Err(MirLowerError::IncompleteExpr); + } } }; let ty = self @@ -1553,6 +1556,7 @@ fn lower_const_to_operand( .value_ty(match const_id { GeneralConstId::ConstId(id) => id.into(), GeneralConstId::StaticId(id) => id.into(), + GeneralConstId::AnonConstId(_) => unreachable!("handled above"), }) .unwrap() .instantiate(self.interner(), subst); @@ -2106,8 +2110,10 @@ pub fn mir_body_for_closure_query<'db>( closure: InternedClosureId, ) -> Result<'db, Arc> { let InternedClosure(owner, expr) = db.lookup_intern_closure(closure); - let body = db.body(owner); - let infer = InferenceResult::for_body(db, owner); + let body_owner = + owner.as_def_with_body().expect("MIR lowering should only happen for body-owned closures"); + let body = db.body(body_owner); + let infer = InferenceResult::for_body(db, body_owner); let Expr::Closure { args, body: root, .. } = &body[expr] else { implementation_error!("closure expression is not closure"); }; @@ -2115,7 +2121,7 @@ pub fn mir_body_for_closure_query<'db>( implementation_error!("closure expression is not closure"); }; let (captures, kind) = infer.closure_info(closure); - let mut ctx = MirLowerCtx::new(db, owner, &body.store, infer); + let mut ctx = MirLowerCtx::new(db, body_owner, &body.store, infer); // 0 is return local ctx.result.locals.alloc(Local { ty: infer.expr_ty(*root).store() }); let closure_local = ctx.result.locals.alloc(Local { @@ -2138,7 +2144,7 @@ pub fn mir_body_for_closure_query<'db>( }); ctx.result.param_locals.push(closure_local); let sig = ctx.interner().signature_unclosure(substs.as_closure().sig(), Safety::Safe); - let resolver_guard = ctx.resolver.update_to_inner_scope(db, owner, expr); + let resolver_guard = ctx.resolver.update_to_inner_scope(db, body_owner, expr); let current = ctx.lower_params_and_bindings( args.iter().zip(sig.skip_binder().inputs().iter()).map(|(it, y)| (*it, *y)), None, 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 aa6caefc4a06..e76ab16fc2c7 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/def_id.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/def_id.rs @@ -1,9 +1,9 @@ //! Definition of `SolverDefId` use hir_def::{ - AdtId, AttrDefId, BuiltinDeriveImplId, CallableDefId, ConstId, DefWithBodyId, EnumId, - EnumVariantId, FunctionId, GeneralConstId, GenericDefId, ImplId, StaticId, StructId, TraitId, - TypeAliasId, UnionId, + AdtId, AnonConstId, AttrDefId, BuiltinDeriveImplId, CallableDefId, ConstId, DefWithBodyId, + EnumId, EnumVariantId, FunctionId, GeneralConstId, GenericDefId, ImplId, StaticId, StructId, + TraitId, TypeAliasId, UnionId, }; use rustc_type_ir::inherent; use stdx::impl_from; @@ -26,6 +26,7 @@ pub enum SolverDefId { ImplId(ImplId), BuiltinDeriveImplId(BuiltinDeriveImplId), StaticId(StaticId), + AnonConstId(AnonConstId), TraitId(TraitId), TypeAliasId(TypeAliasId), InternedClosureId(InternedClosureId), @@ -88,6 +89,7 @@ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { )) .finish() } + SolverDefId::AnonConstId(id) => f.debug_tuple("AnonConstId").field(&id).finish(), SolverDefId::Ctor(Ctor::Struct(id)) => { f.debug_tuple("Ctor").field(&db.struct_signature(id).name.as_str()).finish() } @@ -112,6 +114,7 @@ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { ImplId, BuiltinDeriveImplId, StaticId, + AnonConstId, TraitId, TypeAliasId, InternedClosureId, @@ -142,6 +145,7 @@ fn from(value: GeneralConstId) -> Self { match value { GeneralConstId::ConstId(const_id) => SolverDefId::ConstId(const_id), GeneralConstId::StaticId(static_id) => SolverDefId::StaticId(static_id), + GeneralConstId::AnonConstId(anon_const_id) => SolverDefId::AnonConstId(anon_const_id), } } } @@ -176,7 +180,8 @@ fn try_from(value: SolverDefId) -> Result { SolverDefId::BuiltinDeriveImplId(_) | SolverDefId::InternedClosureId(_) | SolverDefId::InternedCoroutineId(_) - | SolverDefId::InternedOpaqueTyId(_) => Err(()), + | SolverDefId::InternedOpaqueTyId(_) + | SolverDefId::AnonConstId(_) => Err(()), } } } @@ -199,6 +204,7 @@ fn try_from(value: SolverDefId) -> Result { | SolverDefId::InternedClosureId(_) | SolverDefId::InternedCoroutineId(_) | SolverDefId::Ctor(Ctor::Struct(_)) + | SolverDefId::AnonConstId(_) | SolverDefId::AdtId(_) => return Err(()), }; Ok(id) @@ -222,6 +228,7 @@ fn try_from(value: SolverDefId) -> Result { | SolverDefId::InternedOpaqueTyId(_) | SolverDefId::EnumVariantId(_) | SolverDefId::BuiltinDeriveImplId(_) + | SolverDefId::AnonConstId(_) | SolverDefId::Ctor(_) => return Err(()), }) } @@ -343,6 +350,7 @@ fn from(value: GeneralConstIdWrapper) -> SolverDefId { match value.0 { GeneralConstId::ConstId(id) => SolverDefId::ConstId(id), GeneralConstId::StaticId(id) => SolverDefId::StaticId(id), + GeneralConstId::AnonConstId(id) => SolverDefId::AnonConstId(id), } } } @@ -353,6 +361,7 @@ fn try_from(value: SolverDefId) -> Result { match value { SolverDefId::ConstId(it) => Ok(Self(it.into())), SolverDefId::StaticId(it) => Ok(Self(it.into())), + SolverDefId::AnonConstId(it) => Ok(Self(it.into())), _ => Err(()), } } 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 e17bdac68cdd..dba4e74730f1 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 @@ -10,8 +10,8 @@ use base_db::Crate; use hir_def::{ - AdtId, CallableDefId, DefWithBodyId, EnumVariantId, HasModule, ItemContainerId, StructId, - UnionId, VariantId, + AdtId, CallableDefId, DefWithBodyId, EnumVariantId, ExpressionStoreOwner, HasModule, + ItemContainerId, StructId, UnionId, VariantId, attrs::AttrFlags, lang_item::LangItems, signatures::{FieldData, FnFlags, ImplFlags, StructFlags, TraitFlags}, @@ -1193,7 +1193,8 @@ fn variances_of(self, def_id: Self::DefId) -> Self::VariancesOf { | SolverDefId::ImplId(_) | SolverDefId::BuiltinDeriveImplId(_) | SolverDefId::InternedClosureId(_) - | SolverDefId::InternedCoroutineId(_) => { + | SolverDefId::InternedCoroutineId(_) + | SolverDefId::AnonConstId(_) => { return VariancesOf::empty(self); } }; @@ -1260,7 +1261,9 @@ fn alias_term_kind( }, // rustc creates an `AnonConst` for consts, and evaluates them with CTFE (normalizing projections // via selection, similar to ours `find_matching_impl()`, and not with the trait solver), so mimic it. - SolverDefId::ConstId(_) => AliasTermKind::UnevaluatedConst, + SolverDefId::ConstId(_) | SolverDefId::AnonConstId(_) => { + AliasTermKind::UnevaluatedConst + } _ => unimplemented!("Unexpected alias: {:?}", alias.def_id), } } @@ -1308,22 +1311,10 @@ fn parent(self, def_id: Self::DefId) -> Self::DefId { SolverDefId::TypeAliasId(it) => it.lookup(self.db()).container, SolverDefId::ConstId(it) => it.lookup(self.db()).container, SolverDefId::InternedClosureId(it) => { - return self - .db() - .lookup_intern_closure(it) - .0 - .as_generic_def_id(self.db()) - .unwrap() - .into(); + return self.db().lookup_intern_closure(it).0.generic_def(self.db()).into(); } SolverDefId::InternedCoroutineId(it) => { - return self - .db() - .lookup_intern_coroutine(it) - .0 - .as_generic_def_id(self.db()) - .unwrap() - .into(); + return self.db().lookup_intern_coroutine(it).0.generic_def(self.db()).into(); } SolverDefId::StaticId(_) | SolverDefId::AdtId(_) @@ -1332,7 +1323,8 @@ fn parent(self, def_id: Self::DefId) -> Self::DefId { | SolverDefId::BuiltinDeriveImplId(_) | SolverDefId::EnumVariantId(..) | SolverDefId::Ctor(..) - | SolverDefId::InternedOpaqueTyId(..) => panic!(), + | SolverDefId::InternedOpaqueTyId(..) + | SolverDefId::AnonConstId(_) => panic!(), }; match container { @@ -1361,7 +1353,10 @@ fn coroutine_movability(self, def_id: Self::CoroutineId) -> rustc_ast_ir::Movabi // FIXME: Make this a query? I don't believe this can be accessed from bodies other than // the current infer query, except with revealed opaques - is it rare enough to not matter? let InternedCoroutine(owner, expr_id) = def_id.0.loc(self.db); - let body = self.db.body(owner); + let Some(body_owner) = owner.as_def_with_body() else { + return rustc_ast_ir::Movability::Static; + }; + let body = self.db.body(body_owner); let expr = &body[expr_id]; match *expr { hir_def::hir::Expr::Closure { closure_kind, .. } => match closure_kind { @@ -1795,6 +1790,7 @@ fn for_each_relevant_impl( | SolverDefId::InternedCoroutineId(_) | SolverDefId::InternedOpaqueTyId(_) | SolverDefId::EnumVariantId(_) + | SolverDefId::AnonConstId(_) | SolverDefId::Ctor(_) => return None, }; module.block(self.db) @@ -2006,7 +2002,10 @@ fn is_general_coroutine(self, def_id: Self::CoroutineId) -> bool { // FIXME: Make this a query? I don't believe this can be accessed from bodies other than // the current infer query, except with revealed opaques - is it rare enough to not matter? let InternedCoroutine(owner, expr_id) = def_id.0.loc(self.db); - let body = self.db.body(owner); + let Some(body_owner) = owner.as_def_with_body() else { + return false; + }; + let body = self.db.body(body_owner); matches!( body[expr_id], hir_def::hir::Expr::Closure { @@ -2020,7 +2019,10 @@ fn coroutine_is_async(self, def_id: Self::CoroutineId) -> bool { // FIXME: Make this a query? I don't believe this can be accessed from bodies other than // the current infer query, except with revealed opaques - is it rare enough to not matter? let InternedCoroutine(owner, expr_id) = def_id.0.loc(self.db); - let body = self.db.body(owner); + let Some(body_owner) = owner.as_def_with_body() else { + return false; + }; + let body = self.db.body(body_owner); matches!( body[expr_id], hir_def::hir::Expr::Closure { closure_kind: hir_def::hir::ClosureKind::Async, .. } @@ -2154,8 +2156,10 @@ fn opaque_types_and_coroutines_defined_by(self, def_id: Self::LocalDefId) -> Sel .. } ) { - let coroutine = - InternedCoroutineId::new(self.db, InternedCoroutine(def_id, expr_id)); + let coroutine = InternedCoroutineId::new( + self.db, + InternedCoroutine(ExpressionStoreOwner::Body(def_id), expr_id), + ); result.push(coroutine.into()); } }); 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 15d6e2e4516e..54baa8ac41ac 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 @@ -18,7 +18,7 @@ }; use super::{ - DbInterner, ErrorGuaranteed, GenericArg, SolverDefId, Span, + Const, DbInterner, ErrorGuaranteed, GenericArg, SolverDefId, Span, infer::{DbInternerInferExt, InferCtxt, canonical::instantiate::CanonicalExt}, }; @@ -256,6 +256,11 @@ fn evaluate_const( let ec = self.cx().db.const_eval_static(c).ok()?; Some(ec) } + // TODO: Wire up const_eval_anon query in Phase 5. + // For now, return an error const so normalization resolves the + // unevaluated const to Error (matching the old behavior where + // complex expressions produced ConstKind::Error directly). + GeneralConstId::AnonConstId(_) => Some(Const::error(self.cx())), } } 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 1173028a1092..09b1585866b0 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 @@ -714,7 +714,7 @@ pub fn impl_trait_bounds(self, db: &'db dyn HirDatabase) -> Option { let InternedCoroutine(owner, _) = coroutine_id.0.loc(db); - let krate = owner.module(db).krate(db); + let krate = owner.krate(db); if let Some(future_trait) = hir_def::lang_item::lang_items(db, krate).Future { // This is only used by type walking. // Parameters will be walked outside, and projection predicate is not used. 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 f089120cd7b8..6e55641e56f2 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 @@ -40,7 +40,8 @@ fn check_closure_captures(#[rust_analyzer::rust_fixture] ra_fixture: &str, expec captures_info.extend(infer.closure_info.iter().flat_map( |(closure_id, (captures, _))| { let closure = db.lookup_intern_closure(*closure_id); - let source_map = db.body_with_source_map(closure.0).1; + let body_owner = closure.0.as_def_with_body().unwrap(); + let source_map = db.body_with_source_map(body_owner).1; let closure_text_range = source_map .expr_syntax(closure.1) .expect("failed to map closure to SyntaxNode") @@ -56,7 +57,7 @@ fn text_range( } // FIXME: Deduplicate this with hir::Local::sources(). - let (body, source_map) = db.body_with_source_map(closure.0); + let (body, source_map) = db.body_with_source_map(body_owner); let local_text_range = match body.self_param.zip(source_map.self_param_syntax()) { Some((param, source)) if param == capture.local() => { @@ -71,7 +72,7 @@ fn text_range( .map(|it| format!("{it:?}")) .join(", "), }; - let place = capture.display_place(closure.0, db); + let place = capture.display_place(body_owner, db); let capture_ty = capture .ty .get() 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 faa7b80a89c2..0fbf8acf530f 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 @@ -48,7 +48,7 @@ fn foo() -> i32 { "crate_lang_items", "GenericPredicates::query_with_diagnostics_", "ImplTraits::return_type_impl_traits_", - "expr_scopes_shim", + "body_expr_scopes_shim", ] "#]], ); @@ -136,7 +136,7 @@ fn baz() -> i32 { "crate_lang_items", "GenericPredicates::query_with_diagnostics_", "ImplTraits::return_type_impl_traits_", - "expr_scopes_shim", + "body_expr_scopes_shim", "InferenceResult::for_body_", "function_signature_shim", "function_signature_with_source_map_shim", @@ -146,7 +146,7 @@ fn baz() -> i32 { "trait_environment_query", "GenericPredicates::query_with_diagnostics_", "ImplTraits::return_type_impl_traits_", - "expr_scopes_shim", + "body_expr_scopes_shim", "InferenceResult::for_body_", "function_signature_shim", "function_signature_with_source_map_shim", @@ -156,7 +156,7 @@ fn baz() -> i32 { "trait_environment_query", "GenericPredicates::query_with_diagnostics_", "ImplTraits::return_type_impl_traits_", - "expr_scopes_shim", + "body_expr_scopes_shim", ] "#]], ); @@ -204,7 +204,7 @@ fn baz() -> i32 { "body_with_source_map_shim", "body_shim", "InferenceResult::for_body_", - "expr_scopes_shim", + "body_expr_scopes_shim", "AttrFlags::query_", "function_signature_with_source_map_shim", "function_signature_shim", @@ -600,7 +600,7 @@ fn main() { "trait_environment_query", "GenericPredicates::query_with_diagnostics_", "ImplTraits::return_type_impl_traits_", - "expr_scopes_shim", + "body_expr_scopes_shim", "struct_signature_shim", "struct_signature_with_source_map_shim", "AttrFlags::query_", @@ -690,7 +690,7 @@ fn main() { "function_signature_with_source_map_shim", "GenericPredicates::query_with_diagnostics_", "ImplTraits::return_type_impl_traits_", - "expr_scopes_shim", + "body_expr_scopes_shim", "struct_signature_with_source_map_shim", "AttrFlags::query_", "GenericPredicates::query_with_diagnostics_", 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 e032a16989ff..66bb3570665a 100644 --- a/src/tools/rust-analyzer/crates/hir/src/has_source.rs +++ b/src/tools/rust-analyzer/crates/hir/src/has_source.rs @@ -293,7 +293,10 @@ fn source(self, db: &dyn HirDatabase) -> Option> { } Callee::Closure(closure, _) => { let InternedClosure(owner, expr_id) = db.lookup_intern_closure(closure); - let (_, source_map) = db.body_with_source_map(owner); + let Some(body_owner) = owner.as_def_with_body() else { + return None; + }; + let (_, source_map) = db.body_with_source_map(body_owner); let ast @ InFile { file_id, value } = source_map.expr_syntax(expr_id).ok()?; let root = db.parse_or_expand(file_id); match value.to_node(&root) { diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index 0b3515fd0498..6dfb94cbf36b 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -1737,7 +1737,7 @@ pub fn kind(self, db: &dyn HirDatabase) -> StructKind { } pub fn value(self, db: &dyn HirDatabase) -> Option { - self.source(db)?.value.expr() + self.source(db)?.value.const_arg()?.expr() } pub fn eval(self, db: &dyn HirDatabase) -> Result { @@ -2891,11 +2891,12 @@ pub fn as_local(&self, db: &dyn HirDatabase) -> Option { } Callee::Closure(closure, _) => { let c = db.lookup_intern_closure(closure); - let body = db.body(c.0); + let body_owner = c.0.as_def_with_body()?; + let body = db.body(body_owner); if let Expr::Closure { args, .. } = &body[c.1] && let Pat::Bind { id, .. } = &body[args[self.idx]] { - return Some(Local { parent: c.0, binding_id: *id }); + return Some(Local { parent: body_owner, binding_id: *id }); } None } @@ -5012,13 +5013,16 @@ pub fn captured_items(&self, db: &'db dyn HirDatabase) -> Vec Vec> { return Vec::new(); }; let owner = db.lookup_intern_closure(id).0; - let infer = InferenceResult::for_body(db, owner); + let Some(body_owner) = owner.as_def_with_body() else { + return Vec::new(); + }; + let infer = InferenceResult::for_body(db, body_owner); let (captures, _) = infer.closure_info(id); - let env = body_param_env_from_has_crate(db, owner); + let env = body_param_env_from_has_crate(db, body_owner); captures.iter().map(|capture| Type { env, ty: capture.ty(db, self.subst) }).collect() } @@ -5042,7 +5049,10 @@ pub fn fn_trait(&self, db: &dyn HirDatabase) -> FnTrait { match self.id { AnyClosureId::ClosureId(id) => { let owner = db.lookup_intern_closure(id).0; - let infer = InferenceResult::for_body(db, owner); + let Some(body_owner) = owner.as_def_with_body() else { + return FnTrait::FnOnce; + }; + let infer = InferenceResult::for_body(db, body_owner); let info = infer.closure_info(id); info.1.into() } diff --git a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs index c6f2d151f582..18929f82090c 100644 --- a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs +++ b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs @@ -123,7 +123,7 @@ pub(crate) fn new_for_body_( infer: Option<&'db InferenceResult>, ) -> SourceAnalyzer<'db> { let (body, source_map) = db.body_with_source_map(def); - let scopes = db.expr_scopes(def); + let scopes = db.expr_scopes(def.into()); let scope = match offset { None => scope_for(db, &scopes, &source_map, node), Some(offset) => { @@ -1045,7 +1045,7 @@ pub(crate) fn resolve_path( } // FIXME: collectiong here shouldnt be necessary? - let mut collector = ExprCollector::new(db, self.resolver.module(), self.file_id); + let mut collector = ExprCollector::body(db, self.resolver.module(), self.file_id); let hir_path = collector.lower_path(path.clone(), &mut ExprCollector::impl_trait_error_allocator)?; let parent_hir_path = path @@ -1253,7 +1253,7 @@ pub(crate) fn resolve_hir_path_per_ns( db: &dyn HirDatabase, path: &ast::Path, ) -> Option { - let mut collector = ExprCollector::new(db, self.resolver.module(), self.file_id); + let mut collector = ExprCollector::body(db, self.resolver.module(), self.file_id); let hir_path = collector.lower_path(path.clone(), &mut ExprCollector::impl_trait_error_allocator)?; let (store, _) = collector.store.finish(); diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_explicit_enum_discriminant.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_explicit_enum_discriminant.rs index 7960373e6193..75c5f84b8501 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_explicit_enum_discriminant.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_explicit_enum_discriminant.rs @@ -47,7 +47,7 @@ pub(crate) fn add_explicit_enum_discriminant( // Don't offer the assist if the enum has no variants or if all variants already have an // explicit discriminant. - if variant_list.variants().all(|variant_node| variant_node.expr().is_some()) { + if variant_list.variants().all(|variant_node| variant_node.const_arg().is_some()) { return None; } @@ -72,7 +72,9 @@ fn add_variant_discriminant( variant_node: &ast::Variant, radix: &mut Radix, ) { - if let Some(expr) = variant_node.expr() { + if let Some(expr) = variant_node.const_arg() + && let Some(expr) = expr.expr() + { *radix = expr_radix(&expr).unwrap_or(*radix); return; } diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/discriminant.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/discriminant.rs index 5b9267126f8a..e845faec565f 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/discriminant.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/discriminant.rs @@ -46,7 +46,7 @@ fn variant_hints( enum_: &ast::Enum, variant: &ast::Variant, ) -> Option<()> { - if variant.expr().is_some() { + if variant.const_arg().is_some() { return None; } diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/items/adt.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/items/adt.rs index a37569614028..cfba4c3a77b2 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/items/adt.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar/items/adt.rs @@ -96,7 +96,9 @@ fn variant(p: &mut Parser<'_>) { // test variant_discriminant // enum E { X(i32) = 10 } if p.eat(T![=]) { + let m = p.start(); expressions::expr(p); + m.complete(p, CONST_ARG); } m.complete(p, VARIANT); } else { @@ -139,7 +141,9 @@ fn record_field(p: &mut Parser<'_>) { // test record_field_default_values // struct S { f: f32 = 0.0 } if p.eat(T![=]) { + let m = p.start(); expressions::expr(p); + m.complete(p, CONST_ARG); } m.complete(p, RECORD_FIELD); } else { diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/record_field_default_values.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/record_field_default_values.rast index 33088f2cabf3..e53b886bbff8 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/record_field_default_values.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/record_field_default_values.rast @@ -21,8 +21,9 @@ SOURCE_FILE WHITESPACE " " EQ "=" WHITESPACE " " - LITERAL - FLOAT_NUMBER "0.0" + CONST_ARG + LITERAL + FLOAT_NUMBER "0.0" WHITESPACE " " R_CURLY "}" WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/variant_discriminant.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/variant_discriminant.rast index 9f0c5a76108d..3494085e88fa 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/variant_discriminant.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/variant_discriminant.rast @@ -23,8 +23,9 @@ SOURCE_FILE WHITESPACE " " EQ "=" WHITESPACE " " - LITERAL - INT_NUMBER "10" + CONST_ARG + LITERAL + INT_NUMBER "10" WHITESPACE " " R_CURLY "}" WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0019_enums.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0019_enums.rast index dd47e3aa47ad..51837e5372a7 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0019_enums.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0019_enums.rast @@ -78,8 +78,9 @@ SOURCE_FILE WHITESPACE " " EQ "=" WHITESPACE " " - LITERAL - INT_NUMBER "92" + CONST_ARG + LITERAL + INT_NUMBER "92" COMMA "," WHITESPACE "\n " VARIANT diff --git a/src/tools/rust-analyzer/crates/syntax/rust.ungram b/src/tools/rust-analyzer/crates/syntax/rust.ungram index 544053408f73..3113fc74308b 100644 --- a/src/tools/rust-analyzer/crates/syntax/rust.ungram +++ b/src/tools/rust-analyzer/crates/syntax/rust.ungram @@ -245,7 +245,7 @@ RecordFieldList = RecordField = Attr* Visibility? 'unsafe'? - Name ':' Type ('=' Expr)? + Name ':' Type ('=' default_val:ConstArg)? TupleFieldList = '(' fields:(TupleField (',' TupleField)* ','?)? ')' @@ -268,7 +268,7 @@ VariantList = Variant = Attr* Visibility? - Name FieldList? ('=' Expr)? + Name FieldList? ('=' ConstArg)? Union = Attr* Visibility? diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs index c4e72eafa793..7334de0fd96f 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs @@ -1337,7 +1337,7 @@ impl ast::HasName for RecordField {} impl ast::HasVisibility for RecordField {} impl RecordField { #[inline] - pub fn expr(&self) -> Option { support::child(&self.syntax) } + pub fn default_val(&self) -> Option { support::child(&self.syntax) } #[inline] pub fn ty(&self) -> Option { support::child(&self.syntax) } #[inline] @@ -1896,7 +1896,7 @@ impl ast::HasName for Variant {} impl ast::HasVisibility for Variant {} impl Variant { #[inline] - pub fn expr(&self) -> Option { support::child(&self.syntax) } + pub fn const_arg(&self) -> Option { support::child(&self.syntax) } #[inline] pub fn field_list(&self) -> Option { support::child(&self.syntax) } #[inline] diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs index d0f14dafe3f0..90a326ff9eab 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs @@ -1503,8 +1503,10 @@ pub fn variant( } if let Some(discriminant) = discriminant { - builder - .map_node(discriminant.syntax().clone(), ast.expr().unwrap().syntax().clone()); + builder.map_node( + discriminant.syntax().clone(), + ast.const_arg().unwrap().syntax().clone(), + ); } builder.finish(&mut mapping); From 42f4417d1a073c39ad249cf88a05fd67000f92c4 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sun, 15 Mar 2026 20:15:06 +0100 Subject: [PATCH 03/56] Make InferenceResult take an `ExpressionStore` --- .../crates/hir-ty/src/consteval.rs | 17 +++--- .../rust-analyzer/crates/hir-ty/src/infer.rs | 57 +++++++------------ .../hir-ty/src/infer/closure/analysis.rs | 26 ++++----- .../crates/hir-ty/src/infer/expr.rs | 24 ++++---- .../crates/hir-ty/src/infer/mutability.rs | 12 ++-- .../crates/hir-ty/src/infer/pat.rs | 26 ++++----- .../crates/hir-ty/src/infer/path.rs | 4 +- .../hir-ty/src/method_resolution/confirm.rs | 2 +- .../rust-analyzer/crates/hir-ty/src/mir.rs | 8 +-- .../crates/hir/src/has_source.rs | 4 +- 10 files changed, 83 insertions(+), 97 deletions(-) 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 9ff788c2e218..c294238030bd 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs @@ -8,7 +8,7 @@ ConstId, EnumVariantId, GeneralConstId, HasModule, StaticId, attrs::AttrFlags, builtin_type::{BuiltinInt, BuiltinType, BuiltinUint}, - expr_store::Body, + expr_store::ExpressionStore, hir::{Expr, ExprId, Literal}, }; use hir_expand::Lookup; @@ -311,23 +311,23 @@ pub(crate) fn const_eval_discriminant_variant( // and make this function private. See the fixme comment on `InferenceContext::resolve_all`. pub(crate) fn eval_to_const<'db>(expr: ExprId, ctx: &mut InferenceContext<'_, 'db>) -> Const<'db> { let infer = ctx.fixme_resolve_all_clone(); - fn has_closure(body: &Body, expr: ExprId) -> bool { - if matches!(body[expr], Expr::Closure { .. }) { + fn has_closure(store: &ExpressionStore, expr: ExprId) -> bool { + if matches!(store[expr], Expr::Closure { .. }) { return true; } let mut r = false; - body.walk_child_exprs(expr, |idx| r |= has_closure(body, idx)); + store.walk_child_exprs(expr, |idx| r |= has_closure(store, idx)); r } - if has_closure(ctx.body, expr) { + if has_closure(ctx.store, expr) { // Type checking clousres need an isolated body (See the above FIXME). Bail out early to prevent panic. return Const::error(ctx.interner()); } - if let Expr::Path(p) = &ctx.body[expr] { + if let Expr::Path(p) = &ctx.store[expr] { let mut ctx = TyLoweringContext::new( ctx.db, &ctx.resolver, - ctx.body, + ctx.store, ctx.generic_def, LifetimeElisionKind::Infer, ); @@ -336,7 +336,8 @@ fn has_closure(body: &Body, expr: ExprId) -> bool { } } if let Some(body_owner) = ctx.owner.as_def_with_body() - && let Ok(mir_body) = lower_body_to_mir(ctx.db, body_owner, ctx.body, &infer, expr) + && let Ok(mir_body) = + lower_body_to_mir(ctx.db, body_owner, &ctx.db.body(body_owner), &infer, expr) && let Ok((Ok(result), _)) = interpret_mir(ctx.db, Arc::new(mir_body), true, None) { return result; 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 a4fcded42b66..a78d5d8a3051 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs @@ -36,7 +36,7 @@ AdtId, AnonConstId, AssocItemId, ConstId, ConstParamId, DefWithBodyId, ExpressionStoreOwner, FieldId, FunctionId, GenericDefId, GenericParamId, ItemContainerId, LocalFieldId, Lookup, TraitId, TupleFieldId, TupleId, TypeAliasId, TypeOrConstParamId, VariantId, - expr_store::{Body, ConstExprOrigin, ExpressionStore, HygieneId, path::Path}, + expr_store::{ConstExprOrigin, ExpressionStore, HygieneId, path::Path}, hir::{BindingAnnotation, BindingId, ExprId, ExprOrPatId, LabelId, PatId}, lang_item::LangItems, layout::Integer, @@ -106,16 +106,14 @@ pub fn infer_query_with_inspect<'db>( let _p = tracing::info_span!("infer_query").entered(); let resolver = def.resolver(db); let body = db.body(def); - let mut ctx = InferenceContext::new(db, ExpressionStoreOwner::Body(def), &body, resolver); + let mut ctx = InferenceContext::new(db, ExpressionStoreOwner::Body(def), &body.store, resolver); if let Some(inspect) = inspect { ctx.table.infer_ctxt.attach_obligation_inspector(inspect); } match def { - DefWithBodyId::FunctionId(f) => { - ctx.collect_fn(f); - } + DefWithBodyId::FunctionId(f) => ctx.collect_fn(f, body.self_param, &body.params), DefWithBodyId::ConstId(c) => ctx.collect_const(c, &db.const_signature(c)), DefWithBodyId::StaticId(s) => ctx.collect_static(&db.static_signature(s)), DefWithBodyId::VariantId(v) => { @@ -144,9 +142,9 @@ pub fn infer_query_with_inspect<'db>( } } - ctx.infer_body(); + ctx.infer_body(body.body_expr); - ctx.infer_mut_body(); + ctx.infer_mut_body(body.body_expr); ctx.handle_opaque_type_uses(); @@ -190,25 +188,14 @@ fn infer_signature_query(db: &dyn HirDatabase, def: GenericDefId) -> InferenceRe let _p = tracing::info_span!("infer_signature_query").entered(); let (_, store) = db.generic_params_and_store(def); let mut roots = store.signature_const_expr_roots_with_origins().peekable(); - let Some(&(first, _)) = roots.peek() else { + let Some(_) = roots.peek() else { return InferenceResult::new(crate::next_solver::default_types(db).types.error); }; let resolver = def.resolver(db); let owner = ExpressionStoreOwner::Signature(def); - // Construct a synthetic `Body` to satisfy `InferenceContext`. - // The `body_expr` is set to the first root as a placeholder; we infer - // each root expression individually below rather than calling `infer_body`. - let body = Body { - // FIXME: Get rid of this clone - store: (*store).clone(), - params: Box::new([]), - self_param: None, - body_expr: first, - }; - - let mut ctx = InferenceContext::new(db, owner, &body, resolver); + let mut ctx = InferenceContext::new(db, owner, &store, resolver); for (root_expr, origin) in roots { let expected = match origin { @@ -846,7 +833,7 @@ pub fn binding_ty<'db>(&self, id: BindingId) -> Ty<'db> { pub(crate) struct InferenceContext<'body, 'db> { pub(crate) db: &'db dyn HirDatabase, pub(crate) owner: ExpressionStoreOwner, - pub(crate) body: &'body Body, + pub(crate) store: &'body ExpressionStore, /// 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. pub(crate) resolver: Resolver<'db>, @@ -947,7 +934,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> { fn new( db: &'db dyn HirDatabase, owner: ExpressionStoreOwner, - body: &'body Body, + store: &'body ExpressionStore, resolver: Resolver<'db>, ) -> Self { let trait_env = match owner { @@ -976,7 +963,7 @@ fn new( db, owner, generic_def: owner.generic_def(db), - body, + store, traits_in_scope: resolver.traits_in_scope(db), resolver, diverges: Diverges::Maybe, @@ -1196,7 +1183,7 @@ fn collect_static(&mut self, data: &StaticSignature) { self.return_ty = return_ty; } - fn collect_fn(&mut self, func: FunctionId) { + fn collect_fn(&mut self, func: FunctionId, self_param: Option, params: &[PatId]) { let data = self.db.function_signature(func); let mut param_tys = self.with_ty_lowering( &data.store, @@ -1224,13 +1211,13 @@ fn collect_fn(&mut self, func: FunctionId) { param_tys.push(va_list_ty); } let mut param_tys = param_tys.into_iter().chain(iter::repeat(self.table.next_ty_var())); - if let Some(self_param) = self.body.self_param + if let Some(self_param) = self_param && let Some(ty) = param_tys.next() { let ty = self.process_user_written_ty(ty); self.write_binding_ty(self_param, ty); } - for (ty, pat) in param_tys.zip(&*self.body.params) { + for (ty, pat) in param_tys.zip(params) { let ty = self.process_user_written_ty(ty); self.infer_top_pat(*pat, ty, None); @@ -1264,12 +1251,12 @@ pub(crate) fn infcx(&self) -> &InferCtxt<'db> { &self.table.infer_ctxt } - fn infer_body(&mut self) { + fn infer_body(&mut self, body_expr: ExprId) { match self.return_coercion { - Some(_) => self.infer_return(self.body.body_expr), + Some(_) => self.infer_return(body_expr), None => { _ = self.infer_expr_coerce( - self.body.body_expr, + body_expr, &Expectation::has_type(self.return_ty), ExprIsRead::Yes, ) @@ -1376,7 +1363,7 @@ fn with_body_ty_lowering( f: impl FnOnce(&mut TyLoweringContext<'db, '_>) -> R, ) -> R { self.with_ty_lowering( - self.body, + self.store, InferenceTyDiagnosticSource::Body, LifetimeElisionKind::Infer, f, @@ -1418,7 +1405,7 @@ fn make_ty( pub(crate) fn make_body_ty(&mut self, type_ref: TypeRefId) -> Ty<'db> { self.make_ty( type_ref, - self.body, + self.store, InferenceTyDiagnosticSource::Body, LifetimeElisionKind::Infer, ) @@ -1426,7 +1413,7 @@ pub(crate) fn make_body_ty(&mut self, type_ref: TypeRefId) -> Ty<'db> { pub(crate) fn make_body_const(&mut self, const_ref: ConstRef, ty: Ty<'db>) -> Const<'db> { let const_ = self.with_ty_lowering( - self.body, + self.store, InferenceTyDiagnosticSource::Body, LifetimeElisionKind::Infer, |ctx| ctx.lower_const(const_ref, ty), @@ -1436,7 +1423,7 @@ pub(crate) fn make_body_const(&mut self, const_ref: ConstRef, ty: Ty<'db>) -> Co pub(crate) fn make_path_as_body_const(&mut self, path: &Path, ty: Ty<'db>) -> Const<'db> { let const_ = self.with_ty_lowering( - self.body, + self.store, InferenceTyDiagnosticSource::Body, LifetimeElisionKind::Infer, |ctx| ctx.lower_path_as_const(path, ty), @@ -1450,7 +1437,7 @@ fn err_ty(&self) -> Ty<'db> { pub(crate) fn make_body_lifetime(&mut self, lifetime_ref: LifetimeRefId) -> Region<'db> { let lt = self.with_ty_lowering( - self.body, + self.store, InferenceTyDiagnosticSource::Body, LifetimeElisionKind::Infer, |ctx| ctx.lower_lifetime(lifetime_ref), @@ -1665,7 +1652,7 @@ fn resolve_variant( let mut ctx = TyLoweringContext::new( self.db, &self.resolver, - &self.body.store, + self.store, &self.diagnostics, InferenceTyDiagnosticSource::Body, self.generic_def, 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 b4cc2ab4ae5b..2b9d3a7f5dbb 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 @@ -346,7 +346,7 @@ fn path_place(&mut self, path: &Path, id: ExprOrPatId) -> Option { if path.type_anchor().is_some() { return None; } - let hygiene = self.body.expr_or_pat_path_hygiene(id); + let hygiene = self.store.expr_or_pat_path_hygiene(id); self.resolver.resolve_path_in_value_ns_fully(self.db, path, hygiene).and_then(|result| { match result { ValueNs::LocalBinding(binding) => { @@ -365,7 +365,7 @@ fn path_place(&mut self, path: &Path, id: ExprOrPatId) -> Option { /// Changes `current_capture_span_stack` to contain the stack of spans for this expr. fn place_of_expr_without_adjust(&mut self, tgt_expr: ExprId) -> Option { self.current_capture_span_stack.clear(); - match &self.body[tgt_expr] { + match &self.store[tgt_expr] { Expr::Path(p) => { let resolver_guard = self.resolver.update_to_inner_scope(self.db, self.owner, tgt_expr); @@ -416,7 +416,7 @@ fn truncate_capture_spans(&self, capture: &mut CapturedItemWithoutTy, mut trunca let mut actual_truncate_to = 0; for &span in &*span_stack { actual_truncate_to += 1; - if !span.is_ref_span(self.body) { + if !span.is_ref_span(self.store) { remained -= 1; if remained == 0 { break; @@ -424,7 +424,7 @@ fn truncate_capture_spans(&self, capture: &mut CapturedItemWithoutTy, mut trunca } } if actual_truncate_to < span_stack.len() - && span_stack[actual_truncate_to].is_ref_span(self.body) + && span_stack[actual_truncate_to].is_ref_span(self.store) { // Include the ref operator if there is one, we will fix it later (in `strip_captures_ref_span()`) if it's incorrect. actual_truncate_to += 1; @@ -533,7 +533,7 @@ fn walk_expr(&mut self, tgt_expr: ExprId) { } fn walk_expr_without_adjust(&mut self, tgt_expr: ExprId) { - match &self.body[tgt_expr] { + match &self.store[tgt_expr] { Expr::OffsetOf(_) => (), Expr::InlineAsm(e) => e.operands.iter().for_each(|(_, op)| match op { AsmOperand::In { expr, .. } @@ -733,7 +733,7 @@ fn walk_expr_without_adjust(&mut self, tgt_expr: ExprId) { self.consume_with_pat(rhs_place, target); self.inside_assignment = false; } - None => self.body.walk_pats(target, &mut |pat| match &self.body[pat] { + None => self.store.walk_pats(target, &mut |pat| match &self.store[pat] { Pat::Path(path) => self.mutate_path_pat(path, pat), &Pat::Expr(expr) => { let place = self.place_of_expr(expr); @@ -775,7 +775,7 @@ fn walk_pat_inner( update_result: &mut impl FnMut(CaptureKind), mut for_mut: BorrowKind, ) { - match &self.body[p] { + match &self.store[p] { Pat::Ref { .. } | Pat::Box { .. } | Pat::Missing @@ -819,13 +819,13 @@ fn walk_pat_inner( if self.result.pat_adjustments.get(&p).is_some_and(|it| !it.is_empty()) { for_mut = BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture }; } - self.body.walk_pats_shallow(p, |p| self.walk_pat_inner(p, update_result, for_mut)); + self.store.walk_pats_shallow(p, |p| self.walk_pat_inner(p, update_result, for_mut)); } fn is_upvar(&self, place: &HirPlace) -> bool { if let Some(c) = self.current_closure { let InternedClosure(_, root) = self.db.lookup_intern_closure(c); - return self.body.is_binding_upvar(place.local, root); + return self.store.is_binding_upvar(place.local, root); } false } @@ -938,7 +938,7 @@ fn consume_with_pat(&mut self, mut place: HirPlace, tgt_pat: PatId) { self.current_capture_span_stack .extend((0..adjustments_count).map(|_| MirSpan::PatId(tgt_pat))); 'reset_span_stack: { - match &self.body[tgt_pat] { + match &self.store[tgt_pat] { Pat::Missing | Pat::Wild => (), Pat::Tuple { args, ellipsis } => { let (al, ar) = args.split_at(ellipsis.map_or(args.len(), |it| it as usize)); @@ -1089,7 +1089,7 @@ fn closure_kind(&self) -> FnTrait { fn analyze_closure(&mut self, closure: InternedClosureId) -> FnTrait { let InternedClosure(_, root) = self.db.lookup_intern_closure(closure); self.current_closure = Some(closure); - let Expr::Closure { body, capture_by, .. } = &self.body[root] else { + let Expr::Closure { body, capture_by, .. } = &self.store[root] else { unreachable!("Closure expression id is always closure"); }; self.consume_expr(*body); @@ -1133,7 +1133,7 @@ fn strip_captures_ref_span(&mut self) { for capture in &mut captures { if matches!(capture.kind, CaptureKind::ByValue) { for span_stack in &mut capture.span_stacks { - if span_stack[span_stack.len() - 1].is_ref_span(self.body) { + if span_stack[span_stack.len() - 1].is_ref_span(self.store) { span_stack.truncate(span_stack.len() - 1); } } @@ -1149,7 +1149,7 @@ pub(crate) fn infer_closures(&mut self) { let kind = self.analyze_closure(closure); for (derefed_callee, callee_ty, params, expr) in exprs { - if let &Expr::Call { callee, .. } = &self.body[expr] { + if let &Expr::Call { callee, .. } = &self.store[expr] { let mut adjustments = self.result.expr_adjustments.remove(&callee).unwrap_or_default().into_vec(); self.write_fn_trait_method_resolution( 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 45b181eff8f0..2e80bad61414 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 @@ -155,7 +155,7 @@ pub(super) fn expr_guaranteed_to_constitute_read_for_never( /// it is matching against. This is used to determine whether we should /// perform `NeverToAny` coercions. fn pat_guaranteed_to_constitute_read_for_never(&self, pat: PatId) -> bool { - match &self.body[pat] { + match &self.store[pat] { // Does not constitute a read. Pat::Wild => false, @@ -197,25 +197,25 @@ fn pat_guaranteed_to_constitute_read_for_never(&self, pat: PatId) -> bool { // FIXME(tschottdorf): this is problematic as the HIR is being scraped, but // ref bindings are be implicit after #42640 (default match binding modes). See issue #44848. fn contains_explicit_ref_binding(&self, pat: PatId) -> bool { - if let Pat::Bind { id, .. } = self.body[pat] - && matches!(self.body[id].mode, BindingAnnotation::Ref | BindingAnnotation::RefMut) + if let Pat::Bind { id, .. } = self.store[pat] + && matches!(self.store[id].mode, BindingAnnotation::Ref | BindingAnnotation::RefMut) { return true; } let mut result = false; - self.body.walk_pats_shallow(pat, |pat| result |= self.contains_explicit_ref_binding(pat)); + self.store.walk_pats_shallow(pat, |pat| result |= self.contains_explicit_ref_binding(pat)); result } fn is_syntactic_place_expr(&self, expr: ExprId) -> bool { - match &self.body[expr] { + match &self.store[expr] { // Lang item paths cannot currently be local variables or statics. Expr::Path(Path::LangItem(_, _)) => false, Expr::Path(Path::Normal(path)) => path.type_anchor.is_none(), Expr::Path(path) => self .resolver - .resolve_path_in_value_ns_fully(self.db, path, self.body.expr_path_hygiene(expr)) + .resolve_path_in_value_ns_fully(self.db, path, self.store.expr_path_hygiene(expr)) .is_none_or(|res| matches!(res, ValueNs::LocalBinding(_) | ValueNs::StaticId(_))), Expr::Underscore => true, Expr::UnaryOp { op: UnaryOp::Deref, .. } => true, @@ -311,7 +311,7 @@ fn infer_expr_inner( ) -> Ty<'db> { self.db.unwind_if_revision_cancelled(); - let expr = &self.body[tgt_expr]; + let expr = &self.store[tgt_expr]; tracing::trace!(?expr); let ty = match expr { Expr::Missing => self.err_ty(), @@ -717,7 +717,7 @@ fn infer_expr_inner( // instantiations in RHS can be coerced to it. Note that this // cannot happen in destructuring assignments because of how // they are desugared. - let lhs_ty = match &self.body[target] { + let lhs_ty = match &self.store[target] { // LHS of assignment doesn't constitute reads. &Pat::Expr(expr) => { Some(self.infer_expr(expr, &Expectation::none(), ExprIsRead::No)) @@ -728,7 +728,7 @@ fn infer_expr_inner( let resolution = self.resolver.resolve_path_in_value_ns_fully( self.db, path, - self.body.pat_path_hygiene(target), + self.store.pat_path_hygiene(target), ); self.resolver.reset_to_guard(resolver_guard); @@ -1351,7 +1351,7 @@ fn infer_expr_array(&mut self, array: &Array, expected: &Expectation<'db>) -> Ty ExprIsRead::Yes, ); let usize = self.types.types.usize; - let len = match self.body[repeat] { + let len = match self.store[repeat] { Expr::Underscore => { self.write_expr_ty(repeat, usize); self.table.next_const_var() @@ -1491,7 +1491,7 @@ fn infer_block( } else { ExprIsRead::No }; - let ty = if contains_explicit_ref_binding(this.body, *pat) { + let ty = if contains_explicit_ref_binding(this.store, *pat) { this.infer_expr( *expr, &Expectation::has_type(decl_ty), @@ -2117,7 +2117,7 @@ pub(in super::super) fn check_call_arguments( // the return value of an argument-position async block to an argument-position // closure wrapped in a block. // See . - let is_closure = if let Expr::Closure { closure_kind, .. } = self.body[*arg] { + let is_closure = if let Expr::Closure { closure_kind, .. } = self.store[*arg] { !matches!(closure_kind, ClosureKind::Coroutine(_)) } else { false 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 45fa141b6d3d..bfe43fc92827 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 @@ -14,8 +14,8 @@ }; impl<'db> InferenceContext<'_, 'db> { - pub(crate) fn infer_mut_body(&mut self) { - self.infer_mut_expr(self.body.body_expr, Mutability::Not); + pub(crate) fn infer_mut_body(&mut self, body_expr: ExprId) { + self.infer_mut_expr(body_expr, Mutability::Not); } fn infer_mut_expr(&mut self, tgt_expr: ExprId, mut mutability: Mutability) { @@ -52,7 +52,7 @@ fn infer_mut_expr(&mut self, tgt_expr: ExprId, mut mutability: Mutability) { } fn infer_mut_expr_without_adjust(&mut self, tgt_expr: ExprId, mutability: Mutability) { - match &self.body[tgt_expr] { + match &self.store[tgt_expr] { Expr::Missing => (), Expr::InlineAsm(e) => { e.operands.iter().for_each(|(_, op)| match op { @@ -173,7 +173,7 @@ fn infer_mut_expr_without_adjust(&mut self, tgt_expr: ExprId, mutability: Mutabi self.infer_mut_expr(*rhs, Mutability::Not); } &Expr::Assignment { target, value } => { - self.body.walk_pats(target, &mut |pat| match self.body[pat] { + self.store.walk_pats(target, &mut |pat| match self.store[pat] { Pat::Expr(expr) => self.infer_mut_expr(expr, Mutability::Mut), Pat::ConstBlock(block) => self.infer_mut_expr(block, Mutability::Not), _ => {} @@ -220,8 +220,8 @@ fn pat_iter_bound_mutability(&self, mut pat: impl Iterator) -> Mut /// `let (ref x0, ref x1) = *it;` we should use `Deref`. fn pat_bound_mutability(&self, pat: PatId) -> Mutability { let mut r = Mutability::Not; - self.body.walk_bindings_in_pat(pat, |b| { - if self.body[b].mode == BindingAnnotation::RefMut { + self.store.walk_bindings_in_pat(pat, |b| { + if self.store[b].mode == BindingAnnotation::RefMut { r = Mutability::Mut; } }); 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 9ba2d634d58a..0b6c9977f079 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 @@ -4,7 +4,7 @@ use hir_def::{ HasModule as _, - expr_store::{Body, path::Path}, + expr_store::{ExpressionStore, path::Path}, hir::{Binding, BindingAnnotation, BindingId, Expr, ExprId, Literal, Pat, PatId}, }; use hir_expand::name::Name; @@ -260,14 +260,14 @@ fn infer_pat( ) -> Ty<'db> { let mut expected = self.table.structurally_resolve_type(expected); - if matches!(&self.body[pat], Pat::Ref { .. }) || self.inside_assignment { + if matches!(&self.store[pat], Pat::Ref { .. }) || self.inside_assignment { cov_mark::hit!(match_ergonomics_ref); // When you encounter a `&pat` pattern, reset to Move. // This is so that `w` is by value: `let (_, &w) = &(1, &2);` // Destructuring assignments also reset the binding mode and // don't do match ergonomics. default_bm = BindingMode::Move; - } else if self.is_non_ref_pat(self.body, pat) { + } else if self.is_non_ref_pat(self.store, pat) { let mut pat_adjustments = Vec::new(); while let TyKind::Ref(_lifetime, inner, mutability) = expected.kind() { pat_adjustments.push(expected.store()); @@ -289,7 +289,7 @@ fn infer_pat( let default_bm = default_bm; let expected = expected; - let ty = match &self.body[pat] { + let ty = match &self.store[pat] { Pat::Tuple { args, ellipsis } => { self.infer_tuple_pat_like(pat, expected, default_bm, *ellipsis, args, decl) } @@ -485,7 +485,7 @@ fn infer_bind_pat( expected: Ty<'db>, decl: Option, ) -> Ty<'db> { - let Binding { mode, .. } = self.body[binding]; + let Binding { mode, .. } = self.store[binding]; let mode = if mode == BindingAnnotation::Unannotated { default_bm } else { @@ -569,7 +569,7 @@ fn infer_slice_pat( fn infer_lit_pat(&mut self, expr: ExprId, expected: Ty<'db>) -> Ty<'db> { // Like slice patterns, byte string patterns can denote both `&[u8; N]` and `&[u8]`. - if let Expr::Literal(Literal::ByteString(_)) = self.body[expr] + if let Expr::Literal(Literal::ByteString(_)) = self.store[expr] && let TyKind::Ref(_, inner, _) = expected.kind() { let inner = self.table.try_structurally_resolve_type(inner); @@ -590,14 +590,14 @@ fn infer_lit_pat(&mut self, expr: ExprId, expected: Ty<'db>) -> Ty<'db> { self.infer_expr(expr, &Expectation::has_type(expected), ExprIsRead::Yes) } - fn is_non_ref_pat(&mut self, body: &hir_def::expr_store::Body, pat: PatId) -> bool { - match &body[pat] { + fn is_non_ref_pat(&mut self, store: &hir_def::expr_store::ExpressionStore, pat: PatId) -> bool { + match &store[pat] { Pat::Tuple { .. } | Pat::TupleStruct { .. } | Pat::Record { .. } | Pat::Range { .. } | Pat::Slice { .. } => true, - Pat::Or(pats) => pats.iter().all(|p| self.is_non_ref_pat(body, *p)), + Pat::Or(pats) => pats.iter().all(|p| self.is_non_ref_pat(store, *p)), Pat::Path(path) => { // A const is a reference pattern, but other value ns things aren't (see #16131). let resolved = self.resolve_value_path_inner(path, pat.into(), true); @@ -605,7 +605,7 @@ fn is_non_ref_pat(&mut self, body: &hir_def::expr_store::Body, pat: PatId) -> bo } Pat::ConstBlock(..) => false, Pat::Lit(expr) => !matches!( - body[*expr], + store[*expr], Expr::Literal(Literal::String(..) | Literal::CString(..) | Literal::ByteString(..)) ), Pat::Wild @@ -670,10 +670,10 @@ fn pat_is_irrefutable(&self, decl_ctxt: Option) -> bool { } } -pub(super) fn contains_explicit_ref_binding(body: &Body, pat_id: PatId) -> bool { +pub(super) fn contains_explicit_ref_binding(store: &ExpressionStore, pat_id: PatId) -> bool { let mut res = false; - body.walk_pats(pat_id, &mut |pat| { - res |= matches!(body[pat], Pat::Bind { id, .. } if matches!(body[id].mode, BindingAnnotation::Ref | BindingAnnotation::RefMut)); + store.walk_pats(pat_id, &mut |pat| { + res |= matches!(store[pat], Pat::Bind { id, .. } if matches!(store[id].mode, BindingAnnotation::Ref | BindingAnnotation::RefMut)); }); res } 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 40c6fdf3cc88..17d4901123bb 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 @@ -136,7 +136,7 @@ pub(super) fn resolve_value_path_inner( let mut ctx = TyLoweringContext::new( self.db, &self.resolver, - self.body, + self.store, &self.diagnostics, InferenceTyDiagnosticSource::Body, self.generic_def, @@ -159,7 +159,7 @@ pub(super) fn resolve_value_path_inner( 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.body.expr_or_pat_path_hygiene(id); + let hygiene = self.store.expr_or_pat_path_hygiene(id); // FIXME: report error, unresolved first path segment let value_or_partial = path_ctx.resolve_path_in_value_ns(hygiene)?; 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 0024ca16a594..ec589085a88d 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 @@ -456,7 +456,7 @@ fn report_missing_lifetime(&mut self, _def: GenericDefId, _expected_count: u32) substs_from_args_and_bindings( self.db(), - self.ctx.body, + self.ctx.store, generic_args, self.candidate.into(), true, 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 bf17c784682c..a8865cd54e6a 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs @@ -6,7 +6,7 @@ use either::Either; use hir_def::{ DefWithBodyId, FieldId, StaticId, TupleFieldId, UnionId, VariantId, - expr_store::Body, + expr_store::ExpressionStore, hir::{BindingAnnotation, BindingId, Expr, ExprId, Ordering, PatId}, }; use la_arena::{Arena, ArenaMap, Idx, RawIdx}; @@ -1210,12 +1210,12 @@ pub enum MirSpan { } impl MirSpan { - pub fn is_ref_span(&self, body: &Body) -> bool { + pub fn is_ref_span(&self, store: &ExpressionStore) -> bool { match *self { - MirSpan::ExprId(expr) => matches!(body[expr], Expr::Ref { .. }), + MirSpan::ExprId(expr) => matches!(store[expr], Expr::Ref { .. }), // FIXME: Figure out if this is correct wrt. match ergonomics. MirSpan::BindingId(binding) => { - matches!(body[binding].mode, BindingAnnotation::Ref | BindingAnnotation::RefMut) + matches!(store[binding].mode, BindingAnnotation::Ref | BindingAnnotation::RefMut) } MirSpan::PatId(_) | MirSpan::SelfParam | MirSpan::Unknown => false, } 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 66bb3570665a..6a1aeb64f35b 100644 --- a/src/tools/rust-analyzer/crates/hir/src/has_source.rs +++ b/src/tools/rust-analyzer/crates/hir/src/has_source.rs @@ -293,9 +293,7 @@ fn source(self, db: &dyn HirDatabase) -> Option> { } Callee::Closure(closure, _) => { let InternedClosure(owner, expr_id) = db.lookup_intern_closure(closure); - let Some(body_owner) = owner.as_def_with_body() else { - return None; - }; + let body_owner = owner.as_def_with_body()?; let (_, source_map) = db.body_with_source_map(body_owner); let ast @ InFile { file_id, value } = source_map.expr_syntax(expr_id).ok()?; let root = db.parse_or_expand(file_id); From 831a0a7545440538ea0164762420e047e810799c Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Tue, 17 Mar 2026 10:46:04 +0100 Subject: [PATCH 04/56] Add test support --- .../rust-analyzer/crates/hir-ty/src/tests.rs | 97 +++++++++++++++---- .../crates/hir-ty/src/tests/patterns.rs | 2 + .../crates/hir-ty/src/tests/regression.rs | 1 + .../hir-ty/src/tests/regression/new_solver.rs | 8 ++ .../crates/hir-ty/src/tests/simple.rs | 39 ++++++++ .../crates/hir-ty/src/tests/traits.rs | 6 ++ 6 files changed, 133 insertions(+), 20 deletions(-) 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 67ab89f5ec8f..042f0568f3d8 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs @@ -16,9 +16,10 @@ use base_db::{Crate, SourceDatabase}; use expect_test::Expect; use hir_def::{ - AssocItemId, DefWithBodyId, HasModule, Lookup, ModuleDefId, ModuleId, SyntheticSyntax, + AssocItemId, DefWithBodyId, GenericDefId, HasModule, Lookup, ModuleDefId, ModuleId, + SyntheticSyntax, db::DefDatabase, - expr_store::{Body, BodySourceMap}, + expr_store::{Body, BodySourceMap, ExpressionStore, ExpressionStoreSourceMap}, hir::{ExprId, Pat, PatId}, item_scope::ItemScope, nameres::DefMap, @@ -34,7 +35,6 @@ ast::{self, AstNode, HasName}, }; use test_fixture::WithFixture; -use triomphe::Arc; use crate::{ InferenceResult, @@ -321,16 +321,20 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String { let mut buf = String::new(); let mut infer_def = |inference_result: &InferenceResult, - body: Arc, - body_source_map: Arc, + store: &ExpressionStore, + source_map: &ExpressionStoreSourceMap, + self_param: Option<( + hir_def::hir::BindingId, + Option>, + )>, krate: Crate| { let display_target = DisplayTarget::from_crate(&db, krate); let mut types: Vec<(InFile, Ty<'_>)> = Vec::new(); let mut mismatches: Vec<(InFile, &TypeMismatch)> = Vec::new(); - if let Some(self_param) = body.self_param { - let ty = &inference_result.type_of_binding[self_param]; - if let Some(syntax_ptr) = body_source_map.self_param_syntax() { + if let Some((binding_id, syntax_ptr)) = self_param { + let ty = &inference_result.type_of_binding[binding_id]; + if let Some(syntax_ptr) = syntax_ptr { let root = db.parse_or_expand(syntax_ptr.file_id); let node = syntax_ptr.map(|ptr| ptr.to_node(&root).syntax().clone()); types.push((node, ty.as_ref())); @@ -338,10 +342,10 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String { } for (pat, mut ty) in inference_result.type_of_pat.iter() { - if let Pat::Bind { id, .. } = body[pat] { + if let Pat::Bind { id, .. } = store[pat] { ty = &inference_result.type_of_binding[id]; } - let node = match body_source_map.pat_syntax(pat) { + let node = match source_map.pat_syntax(pat) { Ok(sp) => { let root = db.parse_or_expand(sp.file_id); sp.map(|ptr| ptr.to_node(&root).syntax().clone()) @@ -355,7 +359,7 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String { } for (expr, ty) in inference_result.type_of_expr.iter() { - let node = match body_source_map.expr_syntax(expr) { + let node = match source_map.expr_syntax(expr) { Ok(sp) => { let root = db.parse_or_expand(sp.file_id); sp.map(|ptr| ptr.to_node(&root).syntax().clone()) @@ -414,16 +418,56 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String { let def_map = module.def_map(&db); let mut defs: Vec<(DefWithBodyId, Crate)> = Vec::new(); + let mut generic_defs: Vec<(GenericDefId, Crate)> = Vec::new(); visit_module(&db, def_map, module, &mut |it| { - let def = match it { - ModuleDefId::FunctionId(it) => it.into(), - ModuleDefId::EnumVariantId(it) => it.into(), - ModuleDefId::ConstId(it) => it.into(), - ModuleDefId::StaticId(it) => it.into(), - _ => return, - }; - defs.push((def, module.krate(&db))) + let krate = module.krate(&db); + match it { + ModuleDefId::FunctionId(it) => { + defs.push((it.into(), krate)); + generic_defs.push((it.into(), krate)); + } + ModuleDefId::EnumVariantId(it) => { + defs.push((it.into(), krate)); + } + ModuleDefId::ConstId(it) => { + defs.push((it.into(), krate)); + generic_defs.push((it.into(), krate)); + } + ModuleDefId::StaticId(it) => { + defs.push((it.into(), krate)); + generic_defs.push((it.into(), krate)); + } + ModuleDefId::AdtId(it) => { + generic_defs.push((it.into(), krate)); + } + ModuleDefId::TraitId(it) => { + generic_defs.push((it.into(), krate)); + } + ModuleDefId::TypeAliasId(it) => { + generic_defs.push((it.into(), krate)); + } + _ => {} + } }); + // Also collect impls + for impl_id in def_map[module].scope.impls() { + generic_defs.push((impl_id.into(), module.krate(&db))); + let impl_data = impl_id.impl_items(&db); + for &(_, item) in impl_data.items.iter() { + match item { + AssocItemId::FunctionId(it) => { + generic_defs.push((it.into(), module.krate(&db))); + } + AssocItemId::ConstId(it) => { + generic_defs.push((it.into(), module.krate(&db))); + } + AssocItemId::TypeAliasId(it) => { + generic_defs.push((it.into(), module.krate(&db))); + } + } + } + } + defs.sort_by_key(|(def, _)| match def { DefWithBodyId::FunctionId(it) => { let loc = it.lookup(&db); @@ -445,7 +489,20 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String { for (def, krate) in defs { let (body, source_map) = db.body_with_source_map(def); let infer = InferenceResult::for_body(&db, def); - infer_def(infer, body, source_map, krate); + let self_param = body.self_param.map(|id| (id, source_map.self_param_syntax())); + infer_def(infer, &body, &source_map, self_param, krate); + } + + // Also infer signature const expressions (array lengths, const generic args, etc.) + generic_defs.dedup(); + for (def, krate) in generic_defs { + let (_, store, source_map) = db.generic_params_and_store_and_source_map(def); + // Skip if there are no const expressions in the signature + if store.const_expr_origins().is_empty() { + continue; + } + let infer = InferenceResult::for_signature(&db, def); + infer_def(infer, &store, &source_map, None, krate); } buf.truncate(buf.trim_end().len()); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/patterns.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/patterns.rs index 8c7d29f99371..42dc07430935 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/patterns.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/patterns.rs @@ -421,6 +421,8 @@ fn index(&self, index: core::ops::RangeFull) -> &Self::Output { 254..256 '&v': &'? [u8; 3] 255..256 'v': [u8; 3] 257..259 '{}': () + 199..200 '3': usize + 62..63 'N': usize "#]], ); } 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 d88801a57b86..e4fc7e56c6ae 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 @@ -2754,6 +2754,7 @@ fn filter(&self, filter: &Filter) -> Self::Output { 664..680 'filter...ter_fn': dyn Fn(&'? T) -> bool + 'static 691..698 'loop {}': ! 696..698 '{}': () + 512..513 'N': usize "#]], ); } 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 f47a26d429fd..e6b3244cda24 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 @@ -34,6 +34,7 @@ pub trait Space: IntoIterator { 223..227 'iter': IntoIter 230..231 'a': Vec 230..243 'a.into_iter()': IntoIter + 322..323 '1': usize "#]], ); } @@ -472,6 +473,8 @@ fn foo() { 249..257 'to_bytes': fn to_bytes() -> [u8; _] 249..259 'to_bytes()': [u8; _] 249..268 'to_byt..._vec()': Vec<<[u8; _] as Foo>::Item> + 205..206 '_': usize + 156..157 'N': usize "#]], ); } @@ -541,6 +544,11 @@ fn test_at_most() { 617..620 'num': Between<0, 1, char> 623..626 ''9'': char 623..641 ''9'.at...:<1>()': Between<0, 1, char> + 320..335 '{ Consts::MAX }': usize + 322..333 'Consts::MAX': usize + 421..422 '0': i32 + 144..159 '{ Consts::MAX }': usize + 146..157 'Consts::MAX': usize "#]], ); } 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 dab8bdb54b69..3ea21f8265a5 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 @@ -3868,6 +3868,8 @@ fn main() { 208..209 'c': u8 213..214 'a': A 213..221 'a.into()': [u8; 2] + 33..34 '2': usize + 111..112 '3': usize "#]], ); } @@ -4061,6 +4063,8 @@ fn foo() { 248..282 'LazyLo..._LOCK)': &'? [u32; _] 264..281 '&VALUE...Y_LOCK': &'? LazyLock<[u32; _]> 265..281 'VALUES...Y_LOCK': LazyLock<[u32; _]> + 197..202 '{ 0 }': usize + 199..200 '0': usize "#]], ); } @@ -4109,3 +4113,38 @@ fn foo() { "#, ); } + +#[test] +fn signature_inference() { + check_infer( + r#" +trait Trait {} +struct S, const C: f32 = 0.0> +where + (): Trait<2> +{ + field: [(); { C as usize }], + field2: *mut S +} + +struct S2; + +type Alias = S2<0>; +impl S2<0> {} +enum E { + V(S2<0>) = 0, +} +union U { + field: S2<0> +} + "#, + expect![[r#" + 242..243 '0': isize + 46..47 '2': i32 + 65..68 '0.0': f32 + 90..91 '2': i32 + 200..201 '0': i32 + 212..213 '0': i32 + "#]], + ); +} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs index 74e9a8dac0e7..22359d8f1f1d 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 @@ -1271,6 +1271,7 @@ fn bar() { 241..245 'R::B': fn B<(), i32>(i32) -> R<(), i32> 241..248 'R::B(7)': R<(), i32> 246..247 '7': i32 + 46..47 '2': usize "#]], ); } @@ -3781,6 +3782,8 @@ fn main() { 371..373 'v4': usize 376..378 'v3': [u8; 4] 376..389 'v3.do_thing()': usize + 86..87 '4': usize + 192..193 '2': usize "#]], ) } @@ -3820,6 +3823,9 @@ fn main() { 240..242 'v2': [u8; 2] 245..246 'v': [u8; 2] 245..257 'v.do_thing()': [u8; 2] + 130..131 'L': usize + 102..103 'L': usize + 130..131 'L': usize "#]], ) } From b603d0eb80adb3cb25aad0b4c0de42ab50d53491 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Tue, 17 Mar 2026 12:43:05 +0100 Subject: [PATCH 05/56] Hookup semantics --- .../rust-analyzer/crates/hir/src/semantics.rs | 28 +++++-- .../crates/hir/src/source_analyzer.rs | 82 +++++++++++++------ .../test_data/highlight_general.html | 2 +- .../ide/src/syntax_highlighting/tests.rs | 2 +- 4 files changed, 80 insertions(+), 34 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs index c816fe967c54..a231f4aff515 100644 --- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs +++ b/src/tools/rust-analyzer/crates/hir/src/semantics.rs @@ -2149,7 +2149,7 @@ fn analyze_impl( node: InFile<&SyntaxNode>, offset: Option, // replace this, just make the inference result a `LazyCell` - infer_body: bool, + infer: bool, ) -> Option> { let _p = tracing::info_span!("SemanticsImpl::analyze_impl").entered(); @@ -2157,7 +2157,7 @@ fn analyze_impl( let resolver = match container { ChildContainer::DefWithBodyId(def) => { - return Some(if infer_body { + return Some(if infer { SourceAnalyzer::new_for_body(self.db, def, node, offset) } else { SourceAnalyzer::new_for_body_no_infer(self.db, def, node, offset) @@ -2167,16 +2167,32 @@ fn analyze_impl( return Some(SourceAnalyzer::new_variant_body(self.db, def, node, offset)); } ChildContainer::TraitId(it) => { - return Some(SourceAnalyzer::new_generic_def(self.db, it.into(), node, offset)); + return Some(if infer { + SourceAnalyzer::new_generic_def(self.db, it.into(), node, offset) + } else { + SourceAnalyzer::new_generic_def_no_infer(self.db, it.into(), node, offset) + }); } ChildContainer::ImplId(it) => { - return Some(SourceAnalyzer::new_generic_def(self.db, it.into(), node, offset)); + return Some(if infer { + SourceAnalyzer::new_generic_def(self.db, it.into(), node, offset) + } else { + SourceAnalyzer::new_generic_def_no_infer(self.db, it.into(), node, offset) + }); } ChildContainer::EnumId(it) => { - return Some(SourceAnalyzer::new_generic_def(self.db, it.into(), node, offset)); + return Some(if infer { + SourceAnalyzer::new_generic_def(self.db, it.into(), node, offset) + } else { + SourceAnalyzer::new_generic_def_no_infer(self.db, it.into(), node, offset) + }); } ChildContainer::GenericDefId(it) => { - return Some(SourceAnalyzer::new_generic_def(self.db, it, node, offset)); + return Some(if infer { + SourceAnalyzer::new_generic_def(self.db, it, node, offset) + } else { + SourceAnalyzer::new_generic_def_no_infer(self.db, it, node, offset) + }); } ChildContainer::ModuleId(it) => it.resolver(self.db), }; 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 18929f82090c..ad7aea391833 100644 --- a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs +++ b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs @@ -17,7 +17,7 @@ path::Path, scope::{ExprScopes, ScopeId}, }, - hir::{BindingId, Expr, ExprId, ExprOrPatId, Pat, PatId}, + hir::{BindingId, Expr, ExprId, ExprOrPatId, Pat, PatId, generics::GenericParams}, lang_item::LangItems, nameres::MacroSubNs, resolver::{HasResolver, Resolver, TypeNs, ValueNs, resolver_for_scope}, @@ -92,7 +92,9 @@ pub(crate) enum BodyOrSig<'db> { def: GenericDefId, store: Arc, source_map: Arc, - // infer: Option>, + infer: Option<&'db InferenceResult>, + #[expect(dead_code)] + generics: Arc, }, } @@ -147,14 +149,46 @@ pub(crate) fn new_for_body_( pub(crate) fn new_generic_def( db: &'db dyn HirDatabase, def: GenericDefId, - InFile { file_id, .. }: InFile<&SyntaxNode>, - _offset: Option, + node: InFile<&SyntaxNode>, + offset: Option, ) -> SourceAnalyzer<'db> { - let (_params, store, source_map) = db.generic_params_and_store_and_source_map(def); - let resolver = def.resolver(db); + Self::new_generic_def_(db, def, node, offset, Some(InferenceResult::for_signature(db, def))) + } + + pub(crate) fn new_generic_def_no_infer( + db: &'db dyn HirDatabase, + def: GenericDefId, + node: InFile<&SyntaxNode>, + offset: Option, + ) -> SourceAnalyzer<'db> { + Self::new_generic_def_(db, def, node, offset, None) + } + + pub(crate) fn new_generic_def_( + db: &'db dyn HirDatabase, + def: GenericDefId, + node @ InFile { file_id, .. }: InFile<&SyntaxNode>, + offset: Option, + infer: Option<&'db InferenceResult>, + ) -> SourceAnalyzer<'db> { + let (generics, store, source_map) = db.generic_params_and_store_and_source_map(def); + let scopes = db.expr_scopes(def.into()); + let scope = match offset { + None => scope_for(db, &scopes, &source_map, node), + Some(offset) => { + debug_assert!( + node.text_range().contains_inclusive(offset), + "{:?} not in {:?}", + offset, + node.text_range() + ); + scope_for_offset(db, &scopes, &source_map, node.file_id, offset) + } + }; + let resolver = resolver_for_scope(db, def, scope); SourceAnalyzer { resolver, - body_or_sig: Some(BodyOrSig::Sig { def, store, source_map }), + body_or_sig: Some(BodyOrSig::Sig { def, store, source_map, generics, infer }), file_id, } } @@ -197,17 +231,8 @@ fn body_(&self) -> Option<(DefWithBodyId, &Body, &BodySourceMap, Option<&Inferen fn infer(&self) -> Option<&InferenceResult> { self.body_or_sig.as_ref().and_then(|it| match it { - BodyOrSig::Sig { .. } => None, BodyOrSig::VariantFields { .. } => None, - BodyOrSig::Body { infer, .. } => infer.as_deref(), - }) - } - - fn body(&self) -> Option<&Body> { - self.body_or_sig.as_ref().and_then(|it| match it { - BodyOrSig::Sig { .. } => None, - BodyOrSig::VariantFields { .. } => None, - BodyOrSig::Body { body, .. } => Some(&**body), + BodyOrSig::Sig { infer, .. } | BodyOrSig::Body { infer, .. } => infer.as_deref(), }) } @@ -232,11 +257,13 @@ fn param_and<'a>(&self, param_env: ParamEnv<'a>) -> ParamEnvAndCrate<'a> { } fn trait_environment(&self, db: &'db dyn HirDatabase) -> ParamEnvAndCrate<'db> { - self.param_and( - self.body_() - .map(|(def, ..)| def) - .map_or_else(ParamEnv::empty, |def| db.trait_environment_for_body(def)), - ) + self.param_and(self.body_or_sig.as_ref().map_or_else(ParamEnv::empty, |body_or_sig| { + match *body_or_sig { + BodyOrSig::Body { def, .. } => db.trait_environment_for_body(def), + BodyOrSig::VariantFields { .. } => ParamEnv::empty(), + BodyOrSig::Sig { def, .. } => db.trait_environment(def), + } + })) } pub(crate) fn expr_id(&self, expr: ast::Expr) -> Option { @@ -371,7 +398,10 @@ pub(crate) fn type_of_self( db: &'db dyn HirDatabase, _param: &ast::SelfParam, ) -> Option> { - let binding = self.body()?.self_param?; + let binding = match self.body_or_sig.as_ref()? { + BodyOrSig::Sig { .. } | BodyOrSig::VariantFields { .. } => return None, + BodyOrSig::Body { body, .. } => body.self_param?, + }; let ty = self.infer()?.binding_ty(binding); Some(Type::new_with_resolver(db, &self.resolver, ty)) } @@ -1526,7 +1556,7 @@ fn ty_of_expr(&self, expr: ast::Expr) -> Option> { fn scope_for( db: &dyn HirDatabase, scopes: &ExprScopes, - source_map: &BodySourceMap, + source_map: &ExpressionStoreSourceMap, node: InFile<&SyntaxNode>, ) -> Option { node.ancestors_with_macros(db) @@ -1545,7 +1575,7 @@ fn scope_for( fn scope_for_offset( db: &dyn HirDatabase, scopes: &ExprScopes, - source_map: &BodySourceMap, + source_map: &ExpressionStoreSourceMap, from_file: HirFileId, offset: TextSize, ) -> Option { @@ -1579,7 +1609,7 @@ fn scope_for_offset( fn adjust( db: &dyn HirDatabase, scopes: &ExprScopes, - source_map: &BodySourceMap, + source_map: &ExpressionStoreSourceMap, expr_range: TextRange, from_file: HirFileId, offset: TextSize, diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_general.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_general.html index c6dbc435c0e8..1184739cc258 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_general.html +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_general.html @@ -105,7 +105,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd loop {} } -fn const_param<const FOO: usize>() -> usize { +fn const_param<const FOO: usize>() -> usize where [(); FOO]: Sized { const_param::<{ FOO }>(); FOO } 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 c6aebd0b0cd1..aecd1d3fdb56 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 @@ -210,7 +210,7 @@ fn never() -> ! { loop {} } -fn const_param() -> usize { +fn const_param() -> usize where [(); FOO]: Sized { const_param::<{ FOO }>(); FOO } From 69e6a47449df5f937fc2523afcc38eafa2bda560 Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Sun, 22 Mar 2026 11:02:16 +0800 Subject: [PATCH 06/56] internal: extract default_fill_expr to utils --- .../src/handlers/add_missing_match_arms.rs | 19 +----- .../src/handlers/desugar_try_expr.rs | 64 +++++-------------- .../handlers/generate_blanket_trait_impl.rs | 17 ++--- .../src/handlers/generate_function.rs | 21 ++---- .../crates/ide-assists/src/utils.rs | 21 +++--- 5 files changed, 36 insertions(+), 106 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs index 8124fecff629..95712707589e 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs @@ -3,7 +3,6 @@ use either::Either; use hir::{Adt, AsAssocItem, Crate, FindPathConfig, HasAttrs, ModuleDef, Semantics}; use ide_db::RootDatabase; -use ide_db::assists::ExprFillDefaultMode; use ide_db::syntax_helpers::suggest_name; use ide_db::{famous_defs::FamousDefs, helpers::mod_path_to_ast}; use itertools::Itertools; @@ -229,17 +228,7 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>) // filter out hidden patterns because they're handled by the catch-all arm !hidden }) - .map(|(pat, _)| { - make.match_arm( - pat, - None, - match ctx.config.expr_fill_default { - ExprFillDefaultMode::Todo => make::ext::expr_todo(), - ExprFillDefaultMode::Underscore => make::ext::expr_underscore(), - ExprFillDefaultMode::Default => make::ext::expr_todo(), - }, - ) - }); + .map(|(pat, _)| make.match_arm(pat, None, utils::expr_fill_default(ctx.config))); let mut arms: Vec<_> = match_arm_list .arms() @@ -266,11 +255,7 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>) let arm = make.match_arm( make.wildcard_pat().into(), None, - match ctx.config.expr_fill_default { - ExprFillDefaultMode::Todo => make::ext::expr_todo(), - ExprFillDefaultMode::Underscore => make::ext::expr_underscore(), - ExprFillDefaultMode::Default => make::ext::expr_todo(), - }, + utils::expr_fill_default(ctx.config), ); arms.push(arm); } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/desugar_try_expr.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/desugar_try_expr.rs index 402203015932..02879837dc2f 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/desugar_try_expr.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/desugar_try_expr.rs @@ -1,9 +1,6 @@ use std::iter; -use ide_db::{ - assists::{AssistId, ExprFillDefaultMode}, - ty_filter::TryEnum, -}; +use ide_db::{assists::AssistId, ty_filter::TryEnum}; use syntax::{ AstNode, T, ast::{ @@ -80,16 +77,9 @@ pub(crate) fn desugar_try_expr(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op ) .into(), }; - let sad_expr = match try_enum { - TryEnum::Option => make.expr_return(Some(make.expr_path(make.ident_path("None")))), - TryEnum::Result => make.expr_return(Some( - make.expr_call( - make.expr_path(make.ident_path("Err")), - make.arg_list(iter::once(make.expr_path(make.ident_path("err")))), - ) - .into(), - )), - }; + let sad_expr = make.expr_return(Some(sad_expr(try_enum, &make, || { + make.expr_path(make.ident_path("err")) + }))); let happy_arm = make.match_arm( try_enum.happy_pattern(make.ident_pat(false, false, make.name("it")).into()), @@ -123,6 +113,7 @@ pub(crate) fn desugar_try_expr(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op let mut editor = builder.make_editor(let_stmt.syntax()); let indent_level = IndentLevel::from_node(let_stmt.syntax()); + let fill_expr = || crate::utils::expr_fill_default(ctx.config); let new_let_stmt = make.let_else_stmt( try_enum.happy_pattern(pat), let_stmt.ty(), @@ -130,41 +121,7 @@ pub(crate) fn desugar_try_expr(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op make.block_expr( iter::once( make.expr_stmt( - make.expr_return(Some(match try_enum { - TryEnum::Option => make.expr_path(make.ident_path("None")), - TryEnum::Result => make - .expr_call( - make.expr_path(make.ident_path("Err")), - make.arg_list(iter::once( - match ctx.config.expr_fill_default { - ExprFillDefaultMode::Todo => make - .expr_macro( - make.ident_path("todo"), - make.token_tree( - syntax::SyntaxKind::L_PAREN, - [], - ), - ) - .into(), - ExprFillDefaultMode::Underscore => { - make.expr_underscore().into() - } - ExprFillDefaultMode::Default => make - .expr_macro( - make.ident_path("todo"), - make.token_tree( - syntax::SyntaxKind::L_PAREN, - [], - ), - ) - .into(), - }, - )), - ) - .into(), - })) - .indent(indent_level + 1) - .into(), + make.expr_return(Some(sad_expr(try_enum, &make, fill_expr))).into(), ) .into(), ), @@ -181,6 +138,15 @@ pub(crate) fn desugar_try_expr(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op Some(()) } +fn sad_expr(try_enum: TryEnum, make: &SyntaxFactory, err: impl Fn() -> ast::Expr) -> ast::Expr { + match try_enum { + TryEnum::Option => make.expr_path(make.ident_path("None")), + TryEnum::Result => make + .expr_call(make.expr_path(make.ident_path("Err")), make.arg_list(iter::once(err()))) + .into(), + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_blanket_trait_impl.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_blanket_trait_impl.rs index b0fa9e6b3ebb..e022a27e519a 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_blanket_trait_impl.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_blanket_trait_impl.rs @@ -5,15 +5,15 @@ use hir::{HasCrate, Semantics}; use ide_db::{ RootDatabase, - assists::{AssistId, AssistKind, ExprFillDefaultMode}, + assists::{AssistId, AssistKind}, famous_defs::FamousDefs, syntax_helpers::suggest_name, }; use syntax::{ AstNode, ast::{ - self, AssocItem, BlockExpr, GenericParam, HasAttrs, HasGenericParams, HasName, - HasTypeBounds, HasVisibility, edit::AstNodeEdit, make, + self, AssocItem, GenericParam, HasAttrs, HasGenericParams, HasName, HasTypeBounds, + HasVisibility, edit::AstNodeEdit, make, }, syntax_editor::Position, }; @@ -269,7 +269,7 @@ fn todo_fn(f: &ast::Fn, config: &AssistConfig) -> ast::Fn { f.generic_param_list(), f.where_clause(), params, - default_block(config), + make::block_expr(None, Some(crate::utils::expr_fill_default(config))), f.ret_type(), f.async_token().is_some(), f.const_token().is_some(), @@ -278,15 +278,6 @@ fn todo_fn(f: &ast::Fn, config: &AssistConfig) -> ast::Fn { ) } -fn default_block(config: &AssistConfig) -> BlockExpr { - let expr = match config.expr_fill_default { - ExprFillDefaultMode::Todo => make::ext::expr_todo(), - ExprFillDefaultMode::Underscore => make::ext::expr_underscore(), - ExprFillDefaultMode::Default => make::ext::expr_todo(), - }; - make::block_expr(None, Some(expr)) -} - fn cfg_attrs(node: &impl HasAttrs) -> impl Iterator { node.attrs().filter(|attr| attr.as_simple_call().is_some_and(|(name, _arg)| name == "cfg")) } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs index f62eccaf1952..fbf6241e43a3 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs @@ -4,7 +4,6 @@ }; use ide_db::{ FileId, FxHashMap, FxHashSet, RootDatabase, SnippetCap, - assists::ExprFillDefaultMode, defs::{Definition, NameRefClass}, famous_defs::FamousDefs, helpers::is_editable_crate, @@ -24,7 +23,7 @@ use crate::{ AssistContext, AssistId, Assists, - utils::{convert_reference_type, find_struct_impl}, + utils::{convert_reference_type, expr_fill_default, find_struct_impl}, }; // Assist: generate_function @@ -286,11 +285,7 @@ fn from_call( target_module, &mut necessary_generic_params, ); - let placeholder_expr = match ctx.config.expr_fill_default { - ExprFillDefaultMode::Todo => make::ext::expr_todo(), - ExprFillDefaultMode::Underscore => make::ext::expr_underscore(), - ExprFillDefaultMode::Default => make::ext::expr_todo(), - }; + let placeholder_expr = expr_fill_default(ctx.config); fn_body = make::block_expr(vec![], Some(placeholder_expr)); }; @@ -345,11 +340,7 @@ fn from_method_call( let (generic_param_list, where_clause) = fn_generic_params(ctx, necessary_generic_params, &target)?; - let placeholder_expr = match ctx.config.expr_fill_default { - ExprFillDefaultMode::Todo => make::ext::expr_todo(), - ExprFillDefaultMode::Underscore => make::ext::expr_underscore(), - ExprFillDefaultMode::Default => make::ext::expr_todo(), - }; + let placeholder_expr = expr_fill_default(ctx.config); let fn_body = make::block_expr(vec![], Some(placeholder_expr)); Some(Self { @@ -465,11 +456,7 @@ fn make_fn_body_as_new_function( let adt_info = adt_info.as_ref()?; let path_self = make::ext::ident_path("Self"); - let placeholder_expr = match ctx.config.expr_fill_default { - ExprFillDefaultMode::Todo => make::ext::expr_todo(), - ExprFillDefaultMode::Underscore => make::ext::expr_underscore(), - ExprFillDefaultMode::Default => make::ext::expr_todo(), - }; + let placeholder_expr = expr_fill_default(ctx.config); let tail_expr = if let Some(strukt) = adt_info.adt.as_struct() { match strukt.kind(ctx.db()) { StructKind::Record => { 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 0657e7243af0..0f28a202253c 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs @@ -248,17 +248,9 @@ pub fn add_trait_assoc_items_to_impl( .filter_map(|item| match item { ast::AssocItem::Fn(fn_) if fn_.body().is_none() => { let fn_ = fn_.clone_subtree(); - let new_body = &make::block_expr( - None, - Some(match config.expr_fill_default { - ExprFillDefaultMode::Todo => make::ext::expr_todo(), - ExprFillDefaultMode::Underscore => make::ext::expr_underscore(), - ExprFillDefaultMode::Default => make::ext::expr_todo(), - }), - ); - let new_body = AstNodeEdit::indent(new_body, IndentLevel::single()); + let new_body = make::block_expr(None, Some(expr_fill_default(config))); let mut fn_editor = SyntaxEditor::new(fn_.syntax().clone()); - fn_.replace_or_insert_body(&mut fn_editor, new_body); + fn_.replace_or_insert_body(&mut fn_editor, new_body.clone_for_update()); let new_fn_ = fn_editor.finish().new_root().clone(); ast::AssocItem::cast(new_fn_) } @@ -465,6 +457,15 @@ fn check_pat_variant_nested_or_literal_with_depth( } } +pub(crate) fn expr_fill_default(config: &AssistConfig) -> ast::Expr { + let make = SyntaxFactory::without_mappings(); + match config.expr_fill_default { + ExprFillDefaultMode::Todo => make.expr_todo(), + ExprFillDefaultMode::Underscore => make.expr_underscore().into(), + ExprFillDefaultMode::Default => make.expr_todo(), + } +} + // Uses a syntax-driven approach to find any impl blocks for the struct that // exist within the module/file // From ce94a4b92e4354851125912353ca116ae3960f98 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Wed, 18 Mar 2026 14:45:45 +0100 Subject: [PATCH 07/56] Hookup analysis_stats --- .../crates/hir-def/src/expr_store.rs | 5 +- .../crates/hir-def/src/resolver.rs | 10 +- .../rust-analyzer/crates/hir-ty/src/infer.rs | 35 +--- .../crates/hir-ty/src/infer/unify.rs | 4 +- .../crates/hir-ty/src/next_solver/def_id.rs | 18 +- src/tools/rust-analyzer/crates/hir/src/lib.rs | 39 +++++ .../crates/hir/src/source_analyzer.rs | 11 +- .../rust-analyzer/src/cli/analysis_stats.rs | 165 ++++++++++++++---- 8 files changed, 214 insertions(+), 73 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 8552c7284532..b5436f3ba338 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 @@ -319,7 +319,7 @@ pub fn finish(self) -> (ExpressionStore, ExpressionStoreSourceMap) { mut bindings, mut binding_owners, mut ident_hygiene, - const_expr_origins, + mut const_expr_origins, mut types, mut lifetimes, @@ -379,6 +379,9 @@ pub fn finish(self) -> (ExpressionStore, ExpressionStoreSourceMap) { let store = { let expr_only = if has_exprs { + if let Some(const_expr_origins) = &mut const_expr_origins { + const_expr_origins.shrink_to_fit(); + } Some(Box::new(ExpressionOnlyStore { exprs, pats, 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 392010df8507..38b461770cbf 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs @@ -860,7 +860,15 @@ pub fn update_to_inner_scope( owner: impl Into, expr_id: ExprId, ) -> UpdateGuard { - let owner = owner.into(); + self.update_to_inner_scope_(db, owner.into(), expr_id) + } + + fn update_to_inner_scope_( + &mut self, + db: &'db dyn DefDatabase, + owner: ExpressionStoreOwner, + expr_id: ExprId, + ) -> UpdateGuard { #[inline(always)] fn append_expr_scope<'db>( db: &'db dyn DefDatabase, 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 a78d5d8a3051..9d78f5de9e05 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs @@ -33,9 +33,9 @@ use base_db::Crate; use either::Either; use hir_def::{ - AdtId, AnonConstId, AssocItemId, ConstId, ConstParamId, DefWithBodyId, ExpressionStoreOwner, - FieldId, FunctionId, GenericDefId, GenericParamId, ItemContainerId, LocalFieldId, Lookup, - TraitId, TupleFieldId, TupleId, TypeAliasId, TypeOrConstParamId, VariantId, + AdtId, AssocItemId, ConstId, ConstParamId, DefWithBodyId, ExpressionStoreOwner, FieldId, + FunctionId, GenericDefId, GenericParamId, ItemContainerId, LocalFieldId, Lookup, TraitId, + TupleFieldId, TupleId, TypeAliasId, TypeOrConstParamId, VariantId, expr_store::{ConstExprOrigin, ExpressionStore, HygieneId, path::Path}, hir::{BindingAnnotation, BindingId, ExprId, ExprOrPatId, LabelId, PatId}, lang_item::LangItems, @@ -146,6 +146,10 @@ pub fn infer_query_with_inspect<'db>( ctx.infer_mut_body(body.body_expr); + finalize_infer(ctx) +} + +fn finalize_infer(mut ctx: InferenceContext<'_, '_>) -> InferenceResult { ctx.handle_opaque_type_uses(); ctx.type_inference_fallback(); @@ -213,9 +217,7 @@ fn infer_signature_query(db: &dyn HirDatabase, def: GenericDefId) -> InferenceRe ctx.infer_expr(root_expr, &expected, ExprIsRead::Yes); } - ctx.type_inference_fallback(); - ctx.table.select_obligations_where_possible(); - ctx.resolve_all() + finalize_infer(ctx) } fn infer_signature_cycle_result( @@ -618,24 +620,6 @@ pub fn for_signature(db: &dyn HirDatabase, def: GenericDefId) -> InferenceResult } impl InferenceResult { - /// Look up inference results for a specific anonymous const in a signature. - /// - /// This delegates to [`Self::for_signature`] on the anon const's owner. - /// The returned `InferenceResult` contains types for *all* expressions in - /// the owner's signature store, not just this anon const's sub-tree. - /// Callers should index into it with `loc.expr` to get the root expression's - /// type. - // FIXME: This function doesn't make sense in that we can't return a full inference result here - // as the anon const is just part of an inference result. - pub fn for_anon_const(db: &dyn HirDatabase, id: AnonConstId) -> &InferenceResult { - match id.lookup(db).owner { - ExpressionStoreOwner::Signature(generic_def_id) => { - Self::for_signature(db, generic_def_id) - } - ExpressionStoreOwner::Body(def_with_body_id) => Self::for_body(db, def_with_body_id), - } - } - fn new(error_ty: Ty<'_>) -> Self { Self { method_resolutions: Default::default(), @@ -943,8 +927,7 @@ fn new( db.trait_environment_for_body(def_with_body_id) } }; - let table = - unify::InferenceTable::new(db, trait_env, resolver.krate(), owner.as_def_with_body()); + let table = unify::InferenceTable::new(db, trait_env, resolver.krate(), Some(owner)); let types = crate::next_solver::default_types(db); InferenceContext { result: InferenceResult::new(types.types.error), 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 2057159c46d2..77f76c97b8e6 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 @@ -3,7 +3,7 @@ use std::fmt; use base_db::Crate; -use hir_def::{AdtId, DefWithBodyId, GenericParamId}; +use hir_def::{AdtId, ExpressionStoreOwner, GenericParamId}; use hir_expand::name::Name; use intern::sym; use rustc_hash::FxHashSet; @@ -147,7 +147,7 @@ pub(crate) fn new( db: &'db dyn HirDatabase, trait_env: ParamEnv<'db>, krate: Crate, - owner: Option, + owner: Option, ) -> Self { let interner = DbInterner::new_with(db, krate); let typing_mode = match owner { 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 e76ab16fc2c7..f725af320db7 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 @@ -2,8 +2,8 @@ use hir_def::{ AdtId, AnonConstId, AttrDefId, BuiltinDeriveImplId, CallableDefId, ConstId, DefWithBodyId, - EnumId, EnumVariantId, FunctionId, GeneralConstId, GenericDefId, ImplId, StaticId, StructId, - TraitId, TypeAliasId, UnionId, + EnumId, EnumVariantId, ExpressionStoreOwner, FunctionId, GeneralConstId, GenericDefId, ImplId, + StaticId, StructId, TraitId, TypeAliasId, UnionId, }; use rustc_type_ir::inherent; use stdx::impl_from; @@ -12,13 +12,13 @@ use super::DbInterner; -#[derive(Debug, PartialOrd, Ord, Clone, Copy, PartialEq, Eq, Hash, salsa::Supertype)] +#[derive(Debug, PartialOrd, Ord, Clone, Copy, PartialEq, Eq, Hash)] pub enum Ctor { Struct(StructId), Enum(EnumVariantId), } -#[derive(PartialOrd, Ord, Clone, Copy, PartialEq, Eq, Hash, salsa::Supertype)] +#[derive(PartialOrd, Ord, Clone, Copy, PartialEq, Eq, Hash)] pub enum SolverDefId { AdtId(AdtId), ConstId(ConstId), @@ -33,7 +33,6 @@ pub enum SolverDefId { InternedCoroutineId(InternedCoroutineId), InternedOpaqueTyId(InternedOpaqueTyId), EnumVariantId(EnumVariantId), - // FIXME(next-solver): Do we need the separation of `Ctor`? It duplicates some variants. Ctor(Ctor), } @@ -139,6 +138,15 @@ fn from(value: GenericDefId) -> Self { } } +impl From for SolverDefId { + fn from(value: ExpressionStoreOwner) -> Self { + match value { + ExpressionStoreOwner::Signature(generic_def_id) => generic_def_id.into(), + ExpressionStoreOwner::Body(def_with_body_id) => def_with_body_id.into(), + } + } +} + impl From for SolverDefId { #[inline] fn from(value: GeneralConstId) -> Self { diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index 6dfb94cbf36b..34372a4a95a2 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -508,6 +508,21 @@ pub fn as_self_generic_def(self) -> Option { } } + pub fn as_generic_def(self) -> Option { + match self { + ModuleDef::Function(it) => Some(it.into()), + ModuleDef::Adt(it) => Some(it.into()), + ModuleDef::Trait(it) => Some(it.into()), + ModuleDef::TypeAlias(it) => Some(it.into()), + ModuleDef::Static(it) => Some(it.into()), + ModuleDef::Const(it) => Some(it.into()), + ModuleDef::Variant(_) + | ModuleDef::Module(_) + | ModuleDef::BuiltinType(_) + | ModuleDef::Macro(_) => None, + } + } + pub fn attrs(&self, db: &dyn HirDatabase) -> Option { Some(match self { ModuleDef::Module(it) => it.attrs(db), @@ -3972,6 +3987,30 @@ pub enum GenericDef { ); impl GenericDef { + pub fn name(self, db: &dyn HirDatabase) -> Option { + match self { + GenericDef::Function(it) => Some(it.name(db)), + GenericDef::Adt(it) => Some(it.name(db)), + GenericDef::Trait(it) => Some(it.name(db)), + GenericDef::TypeAlias(it) => Some(it.name(db)), + GenericDef::Impl(_) => None, + GenericDef::Const(it) => it.name(db), + GenericDef::Static(it) => Some(it.name(db)), + } + } + + pub fn module(self, db: &dyn HirDatabase) -> Module { + match self { + GenericDef::Function(it) => it.module(db), + GenericDef::Adt(it) => it.module(db), + GenericDef::Trait(it) => it.module(db), + GenericDef::TypeAlias(it) => it.module(db), + GenericDef::Impl(it) => it.module(db), + GenericDef::Const(it) => it.module(db), + GenericDef::Static(it) => it.module(db), + } + } + pub fn params(self, db: &dyn HirDatabase) -> Vec { let Ok(id) = self.try_into() else { // Let's pretend builtin derive impls don't have generic parameters. 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 ad7aea391833..1d3cfc748e95 100644 --- a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs +++ b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs @@ -152,7 +152,7 @@ pub(crate) fn new_generic_def( node: InFile<&SyntaxNode>, offset: Option, ) -> SourceAnalyzer<'db> { - Self::new_generic_def_(db, def, node, offset, Some(InferenceResult::for_signature(db, def))) + Self::new_generic_def_(db, def, node, offset, true) } pub(crate) fn new_generic_def_no_infer( @@ -161,7 +161,7 @@ pub(crate) fn new_generic_def_no_infer( node: InFile<&SyntaxNode>, offset: Option, ) -> SourceAnalyzer<'db> { - Self::new_generic_def_(db, def, node, offset, None) + Self::new_generic_def_(db, def, node, offset, false) } pub(crate) fn new_generic_def_( @@ -169,7 +169,7 @@ pub(crate) fn new_generic_def_( def: GenericDefId, node @ InFile { file_id, .. }: InFile<&SyntaxNode>, offset: Option, - infer: Option<&'db InferenceResult>, + infer: bool, ) -> SourceAnalyzer<'db> { let (generics, store, source_map) = db.generic_params_and_store_and_source_map(def); let scopes = db.expr_scopes(def.into()); @@ -186,6 +186,11 @@ pub(crate) fn new_generic_def_( } }; let resolver = resolver_for_scope(db, def, scope); + let infer = if infer && !Arc::ptr_eq(&store, &ExpressionStore::empty_singleton().0) { + Some(InferenceResult::for_signature(db, def)) + } else { + None + }; SourceAnalyzer { resolver, body_or_sig: Some(BodyOrSig::Sig { def, store, source_map, generics, infer }), 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 ad1cca08cb57..3ee379765461 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 @@ -10,8 +10,8 @@ use cfg::{CfgAtom, CfgDiff}; use hir::{ - Adt, AssocItem, Crate, DefWithBody, FindPathConfig, HasCrate, HasSource, HirDisplay, ModuleDef, - Name, crate_lang_items, + Adt, AssocItem, Crate, DefWithBody, FindPathConfig, GenericDef, HasCrate, HasSource, + HirDisplay, ModuleDef, Name, crate_lang_items, db::{DefDatabase, ExpandDatabase, HirDatabase}, next_solver::{DbInterner, GenericArgs}, }; @@ -229,6 +229,7 @@ pub fn run(self, verbosity: Verbosity) -> anyhow::Result<()> { eprint!(" crates: {num_crates}"); let mut num_decls = 0; let mut bodies = Vec::new(); + let mut signatures = Vec::new(); let mut adts = Vec::new(); let mut file_ids = Vec::new(); @@ -267,24 +268,32 @@ pub fn run(self, verbosity: Verbosity) -> anyhow::Result<()> { }, _ => (), }; + if let Some(g) = decl.as_generic_def() { + signatures.push(g); + } } for impl_def in module.impl_defs(db) { + signatures.push(impl_def.into()); for item in impl_def.items(db) { num_decls += 1; match item { - AssocItem::Function(f) => bodies.push(DefWithBody::from(f)), + AssocItem::Function(f) => { + bodies.push(DefWithBody::from(f)); + signatures.push(f.into()) + } AssocItem::Const(c) => { bodies.push(DefWithBody::from(c)); + signatures.push(c.into()); } - _ => (), + AssocItem::TypeAlias(t) => signatures.push(t.into()), } } } } } eprintln!( - ", mods: {}, decls: {num_decls}, bodies: {}, adts: {}, consts: {}", + ", mods: {}, decls: {num_decls}, bodies: {}, adts: {}, consts: {}, signatures: {}", visited_modules.len(), bodies.len(), adts.len(), @@ -292,6 +301,7 @@ pub fn run(self, verbosity: Verbosity) -> anyhow::Result<()> { .iter() .filter(|it| matches!(it, DefWithBody::Const(_) | DefWithBody::Static(_))) .count(), + signatures.len(), ); eprintln!(" Workspace:"); @@ -327,15 +337,15 @@ pub fn run(self, verbosity: Verbosity) -> anyhow::Result<()> { } if !self.skip_lowering { - self.run_body_lowering(db, &vfs, &bodies, verbosity); + self.run_body_lowering(db, &vfs, &bodies, &signatures, verbosity); } if !self.skip_inference { - self.run_inference(db, &vfs, &bodies, verbosity); + self.run_inference(db, &vfs, &bodies, &signatures, verbosity); } if !self.skip_mir_stats { - self.run_mir_lowering(db, &bodies, verbosity); + self.run_mir_lowering(db, &bodies, &signatures, verbosity); } if !self.skip_data_layout { @@ -343,7 +353,7 @@ pub fn run(self, verbosity: Verbosity) -> anyhow::Result<()> { } if !self.skip_const_eval { - self.run_const_eval(db, &bodies, verbosity); + self.run_const_eval(db, &bodies, &signatures, verbosity); } }); @@ -416,7 +426,13 @@ fn run_data_layout(&self, db: &RootDatabase, adts: &[hir::Adt], verbosity: Verbo report_metric("data layout time", data_layout_time.time.as_millis() as u64, "ms"); } - fn run_const_eval(&self, db: &RootDatabase, bodies: &[DefWithBody], verbosity: Verbosity) { + fn run_const_eval( + &self, + db: &RootDatabase, + bodies: &[DefWithBody], + _signatures: &[GenericDef], + verbosity: Verbosity, + ) { let len = bodies .iter() .filter(|body| matches!(body, DefWithBody::Const(_) | DefWithBody::Static(_))) @@ -431,7 +447,9 @@ fn run_const_eval(&self, db: &RootDatabase, bodies: &[DefWithBody], verbosity: V let mut all = 0; let mut fail = 0; for &b in bodies { - bar.set_message(move || format!("const eval: {}", full_name(db, b, b.module(db)))); + bar.set_message(move || { + format!("const eval: {}", full_name(db, || b.name(db), b.module(db))) + }); let res = match b { DefWithBody::Const(c) => c.eval(db), DefWithBody::Static(s) => s.eval(db), @@ -687,7 +705,13 @@ fn trim(s: &str) -> String { bar.finish_and_clear(); } - fn run_mir_lowering(&self, db: &RootDatabase, bodies: &[DefWithBody], verbosity: Verbosity) { + fn run_mir_lowering( + &self, + db: &RootDatabase, + bodies: &[DefWithBody], + _signatures: &[GenericDef], + verbosity: Verbosity, + ) { let mut bar = match verbosity { Verbosity::Quiet | Verbosity::Spammy => ProgressReport::hidden(), _ if self.parallel || self.output.is_some() => ProgressReport::hidden(), @@ -698,14 +722,14 @@ fn run_mir_lowering(&self, db: &RootDatabase, bodies: &[DefWithBody], verbosity: let mut fail = 0; for &body in bodies { bar.set_message(move || { - format!("mir lowering: {}", full_name(db, body, body.module(db))) + format!("mir lowering: {}", full_name(db, || body.name(db), body.module(db))) }); bar.inc(1); if matches!(body, DefWithBody::Variant(_)) { continue; } let module = body.module(db); - if !self.should_process(db, body, module) { + if !self.should_process(db, || body.name(db), module) { continue; } @@ -743,6 +767,7 @@ fn run_inference( db: &RootDatabase, vfs: &Vfs, bodies: &[DefWithBody], + signatures: &[GenericDef], verbosity: Verbosity, ) { let mut bar = match verbosity { @@ -757,10 +782,19 @@ fn run_inference( bodies .par_iter() .map_with(db.clone(), |snap, &body| { - snap.body(body); InferenceResult::for_body(snap, body); }) .count(); + let signatures = signatures + .iter() + .filter_map(|&signatures| signatures.try_into().ok()) + .collect::>(); + signatures + .par_iter() + .map_with(db.clone(), |snap, &signatures| { + InferenceResult::for_signature(snap, signatures); + }) + .count(); eprintln!("{:<20} {}", "Parallel Inference:", inference_sw.elapsed()); } @@ -782,7 +816,7 @@ fn run_inference( let display_target = module.krate(db).to_display_target(db); if let Some(only_name) = self.only.as_deref() && name.display(db, Edition::LATEST).to_string() != only_name - && full_name(db, body_id, module) != only_name + && full_name(db, || body_id.name(db), module) != only_name { continue; } @@ -800,15 +834,15 @@ fn run_inference( let syntax_range = src.text_range(); format!( "processing: {} ({} {:?})", - full_name(db, body_id, module), + full_name(db, || body_id.name(db), module), path, syntax_range ) } else { - format!("processing: {}", full_name(db, body_id, module)) + format!("processing: {}", full_name(db, || body_id.name(db), module)) } } else { - format!("processing: {}", full_name(db, body_id, module)) + format!("processing: {}", full_name(db, || body_id.name(db), module)) } }; if verbosity.is_spammy() { @@ -822,11 +856,22 @@ fn run_inference( Ok(inference_result) => inference_result, Err(p) => { if let Some(s) = p.downcast_ref::<&str>() { - eprintln!("infer panicked for {}: {}", full_name(db, body_id, module), s); + eprintln!( + "infer panicked for {}: {}", + full_name(db, || body_id.name(db), module), + s + ); } else if let Some(s) = p.downcast_ref::() { - eprintln!("infer panicked for {}: {}", full_name(db, body_id, module), s); + eprintln!( + "infer panicked for {}: {}", + full_name(db, || body_id.name(db), module), + s + ); } else { - eprintln!("infer panicked for {}", full_name(db, body_id, module)); + eprintln!( + "infer panicked for {}", + full_name(db, || body_id.name(db), module) + ); } panics += 1; bar.inc(1); @@ -932,7 +977,7 @@ fn run_inference( if verbosity.is_spammy() { bar.println(format!( "In {}: {} exprs, {} unknown, {} partial", - full_name(db, body_id, module), + full_name(db, || body_id.name(db), module), num_exprs - previous_exprs, num_exprs_unknown - previous_unknown, num_exprs_partially_unknown - previous_partially_unknown @@ -1034,7 +1079,7 @@ fn run_inference( if verbosity.is_spammy() { bar.println(format!( "In {}: {} pats, {} unknown, {} partial", - full_name(db, body_id, module), + full_name(db, || body_id.name(db), module), num_pats - previous_pats, num_pats_unknown - previous_unknown, num_pats_partially_unknown - previous_partially_unknown @@ -1078,20 +1123,65 @@ fn run_body_lowering( db: &RootDatabase, vfs: &Vfs, bodies: &[DefWithBody], + signatures: &[GenericDef], verbosity: Verbosity, ) { let mut bar = match verbosity { Verbosity::Quiet | Verbosity::Spammy => ProgressReport::hidden(), _ if self.output.is_some() => ProgressReport::hidden(), - _ => ProgressReport::new(bodies.len()), + _ => ProgressReport::new(bodies.len() + signatures.len()), }; let mut sw = self.stop_watch(); bar.tick(); + for &signature in signatures { + let Ok(signature_id) = signature.try_into() else { continue }; + let module = signature.module(db); + if !self.should_process(db, || signature.name(db), module) { + continue; + } + let msg = move || { + if verbosity.is_verbose() { + let source = match signature { + GenericDef::Function(it) => it.source(db).map(|it| it.syntax().cloned()), + GenericDef::Static(it) => it.source(db).map(|it| it.syntax().cloned()), + GenericDef::Const(it) => it.source(db).map(|it| it.syntax().cloned()), + GenericDef::Adt(adt) => adt.source(db).map(|it| it.syntax().cloned()), + GenericDef::Trait(it) => it.source(db).map(|it| it.syntax().cloned()), + GenericDef::TypeAlias(type_alias) => { + type_alias.source(db).map(|it| it.syntax().cloned()) + } + GenericDef::Impl(it) => it.source(db).map(|it| it.syntax().cloned()), + }; + if let Some(src) = source { + let original_file = src.file_id.original_file(db); + let path = vfs.file_path(original_file.file_id(db)); + let syntax_range = src.text_range(); + format!( + "processing: {} ({} {:?})", + full_name(db, || signature.name(db), module), + path, + syntax_range + ) + } else { + format!("processing: {}", full_name(db, || signature.name(db), module)) + } + } else { + format!("processing: {}", full_name(db, || signature.name(db), module)) + } + }; + if verbosity.is_spammy() { + bar.println(msg()); + } + bar.set_message(msg); + db.generic_params_and_store(signature_id); + bar.inc(1); + } + for &body_id in bodies { let Ok(body_def_id) = body_id.try_into() else { continue }; let module = body_id.module(db); - if !self.should_process(db, body_id, module) { + if !self.should_process(db, || body_id.name(db), module) { continue; } let msg = move || { @@ -1108,15 +1198,15 @@ fn run_body_lowering( let syntax_range = src.text_range(); format!( "processing: {} ({} {:?})", - full_name(db, body_id, module), + full_name(db, || body_id.name(db), module), path, syntax_range ) } else { - format!("processing: {}", full_name(db, body_id, module)) + format!("processing: {}", full_name(db, || body_id.name(db), module)) } } else { - format!("processing: {}", full_name(db, body_id, module)) + format!("processing: {}", full_name(db, || body_id.name(db), module)) } }; if verbosity.is_spammy() { @@ -1129,7 +1219,7 @@ fn run_body_lowering( bar.finish_and_clear(); let body_lowering_time = sw.elapsed(); - eprintln!("{:<20} {}", "Body lowering:", body_lowering_time); + eprintln!("{:<20} {}", "Expression Store Lowering:", body_lowering_time); report_metric("body lowering time", body_lowering_time.time.as_millis() as u64, "ms"); } @@ -1283,12 +1373,17 @@ fn run_ide_things( eprintln!("{:<20} {} ({} files)", "IDE:", ide_time, file_ids.len()); } - fn should_process(&self, db: &RootDatabase, body_id: DefWithBody, module: hir::Module) -> bool { + fn should_process( + &self, + db: &RootDatabase, + name_fn: impl Fn() -> Option, + module: hir::Module, + ) -> bool { if let Some(only_name) = self.only.as_deref() { - let name = body_id.name(db).unwrap_or_else(Name::missing); + let name = name_fn().unwrap_or_else(Name::missing); if name.display(db, Edition::LATEST).to_string() != only_name - && full_name(db, body_id, module) != only_name + && full_name(db, name_fn, module) != only_name { return false; } @@ -1301,7 +1396,7 @@ fn stop_watch(&self) -> StopWatch { } } -fn full_name(db: &RootDatabase, body_id: DefWithBody, module: hir::Module) -> String { +fn full_name(db: &RootDatabase, name: impl Fn() -> Option, module: hir::Module) -> String { module .krate(db) .display_name(db) @@ -1313,7 +1408,7 @@ fn full_name(db: &RootDatabase, body_id: DefWithBody, module: hir::Module) -> St .into_iter() .filter_map(|it| it.name(db)) .rev() - .chain(Some(body_id.name(db).unwrap_or_else(Name::missing))) + .chain(Some(name().unwrap_or_else(Name::missing))) .map(|it| it.display(db, Edition::LATEST).to_string()), ) .join("::") From e66f61fe070e741cadba7dc7bb9cbb8548c8e9cd Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Mon, 15 Sep 2025 15:27:19 +0800 Subject: [PATCH 08/56] Fix indent for trait_impl_redundant_assoc_item Example --- ```rust trait Foo { } impl Foo for () { $0fn foo(&self); } ``` **Before this PR**: ```rust trait Foo { fn foo(&self) where T: Copy,; } impl Foo for () { fn foo(&self); } ``` **After this PR**: ```rust trait Foo { fn foo(&self) where T: Copy,; } impl Foo for () { fn foo(&self); } ``` --- .../trait_impl_redundant_assoc_item.rs | 97 +++++++++++++++++-- .../rust-analyzer/crates/stdx/src/lib.rs | 19 ++++ 2 files changed, 109 insertions(+), 7 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs index cb3aac3717f8..f4054610f2bd 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs @@ -6,6 +6,7 @@ source_change::SourceChangeBuilder, }; use syntax::ToSmolStr; +use syntax::ast::edit::AstNodeEdit; use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext}; @@ -23,6 +24,7 @@ pub(crate) fn trait_impl_redundant_assoc_item( let default_range = d.impl_.syntax_node_ptr().text_range(); let trait_name = d.trait_.name(db).display_no_db(ctx.edition).to_smolstr(); + let indent_level = d.trait_.source(db).map_or(0, |it| it.value.indent_level().0) + 1; let (redundant_item_name, diagnostic_range, redundant_item_def) = match assoc_item { hir::AssocItem::Function(id) => { @@ -30,7 +32,7 @@ pub(crate) fn trait_impl_redundant_assoc_item( ( format!("`fn {redundant_assoc_item_name}`"), function.source(db).map(|it| it.syntax().text_range()).unwrap_or(default_range), - format!("\n {};", function.display(db, ctx.display_target)), + format!("\n{};", function.display(db, ctx.display_target)), ) } hir::AssocItem::Const(id) => { @@ -38,7 +40,7 @@ pub(crate) fn trait_impl_redundant_assoc_item( ( format!("`const {redundant_assoc_item_name}`"), constant.source(db).map(|it| it.syntax().text_range()).unwrap_or(default_range), - format!("\n {};", constant.display(db, ctx.display_target)), + format!("\n{};", constant.display(db, ctx.display_target)), ) } hir::AssocItem::TypeAlias(id) => { @@ -46,10 +48,8 @@ pub(crate) fn trait_impl_redundant_assoc_item( ( format!("`type {redundant_assoc_item_name}`"), type_alias.source(db).map(|it| it.syntax().text_range()).unwrap_or(default_range), - format!( - "\n type {};", - type_alias.name(ctx.sema.db).display_no_db(ctx.edition).to_smolstr() - ), + // FIXME cannot generate generic parameter and bounds + format!("\ntype {};", type_alias.name(ctx.sema.db).display_no_db(ctx.edition)), ) } }; @@ -65,7 +65,7 @@ pub(crate) fn trait_impl_redundant_assoc_item( .with_fixes(quickfix_for_redundant_assoc_item( ctx, d, - redundant_item_def, + stdx::indent_string(&redundant_item_def, indent_level), diagnostic_range, )) } @@ -191,6 +191,89 @@ impl Marker for Foo { ) } + #[test] + fn quickfix_indentations() { + check_fix( + r#" +mod indent { + trait Marker { + fn boo(); + } + struct Foo; + impl Marker for Foo { + fn$0 bar(_a: i32, _b: T) -> String {} + fn boo() {} + } +} + "#, + r#" +mod indent { + trait Marker { + fn bar(_a: i32, _b: T) -> String + where + T: Copy,; + fn boo(); + } + struct Foo; + impl Marker for Foo { + fn bar(_a: i32, _b: T) -> String {} + fn boo() {} + } +} + "#, + ); + + check_fix( + r#" +mod indent { + trait Marker { + fn foo () {} + } + struct Foo; + impl Marker for Foo { + const FLAG: bool$0 = false; + } +} + "#, + r#" +mod indent { + trait Marker { + const FLAG: bool; + fn foo () {} + } + struct Foo; + impl Marker for Foo { + const FLAG: bool = false; + } +} + "#, + ); + + check_fix( + r#" +mod indent { + trait Marker { + } + struct Foo; + impl Marker for Foo { + type T = i32;$0 + } +} + "#, + r#" +mod indent { + trait Marker { + type T; + } + struct Foo; + impl Marker for Foo { + type T = i32; + } +} + "#, + ); + } + #[test] fn quickfix_dont_work() { check_no_fix( diff --git a/src/tools/rust-analyzer/crates/stdx/src/lib.rs b/src/tools/rust-analyzer/crates/stdx/src/lib.rs index a1af4cc6be5c..275e0e5ac8db 100644 --- a/src/tools/rust-analyzer/crates/stdx/src/lib.rs +++ b/src/tools/rust-analyzer/crates/stdx/src/lib.rs @@ -1,5 +1,6 @@ //! Missing batteries for standard libraries. +use std::borrow::Cow; use std::io as sio; use std::process::Command; use std::{cmp::Ordering, ops, time::Instant}; @@ -250,6 +251,24 @@ pub fn dedent_by(spaces: usize, text: &str) -> String { .collect() } +/// Indent non empty lines, including the first line +#[must_use] +pub fn indent_string(s: &str, indent_level: u8) -> String { + if indent_level == 0 || s.is_empty() { + return s.to_owned(); + } + let indent_str = " ".repeat(indent_level as usize); + s.split_inclusive("\n") + .map(|line| { + if line.trim_end().is_empty() { + Cow::Borrowed(line) + } else { + format!("{indent_str}{line}").into() + } + }) + .collect() +} + pub fn equal_range_by(slice: &[T], mut key: F) -> ops::Range where F: FnMut(&T) -> Ordering, From 0543e4f919140be7e7da31249f9419b4f14b4d85 Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Thu, 6 Nov 2025 19:07:12 +0800 Subject: [PATCH 09/56] Improve tmp iterator variable name for convert_for_to_while_let Example --- ```rust fn main() { let x = vec![1, 2, 3]; for$0 v in x { let y = v * 2; }; } ``` **Before this PR** ```rust fn main() { let x = vec![1, 2, 3]; let mut tmp = x.into_iter(); while let Some(v) = tmp.next() { let y = v * 2; }; } ``` **After this PR** ```rust fn main() { let x = vec![1, 2, 3]; let mut iter = x.into_iter(); while let Some(v) = iter.next() { let y = v * 2; }; } ``` --- .../src/handlers/convert_for_to_while_let.rs | 46 +++++++++---------- .../crates/ide-assists/src/tests/generated.rs | 4 +- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_for_to_while_let.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_for_to_while_let.rs index d409374c16f6..15f324eff329 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_for_to_while_let.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_for_to_while_let.rs @@ -24,8 +24,8 @@ // ``` // fn main() { // let x = vec![1, 2, 3]; -// let mut tmp = x.into_iter(); -// while let Some(v) = tmp.next() { +// let mut iter = x.into_iter(); +// while let Some(v) = iter.next() { // let y = v * 2; // }; // } @@ -71,7 +71,7 @@ pub(crate) fn convert_for_loop_to_while_let( let mut new_name = suggest_name::NameGenerator::new_from_scope_locals( ctx.sema.scope(for_loop.syntax()), ); - let tmp_var = new_name.suggest_name("tmp"); + let tmp_var = new_name.suggest_name("iter"); let mut_expr = make.let_stmt( make.ident_pat(false, true, make.name(&tmp_var)).into(), @@ -188,8 +188,8 @@ fn main() { r" fn main() { let mut x = vec![1, 2, 3]; - let mut tmp = x.into_iter(); - while let Some(v) = tmp.next() { + let mut iter = x.into_iter(); + while let Some(v) = iter.next() { v *= 2; }; }", @@ -211,8 +211,8 @@ fn main() { r" fn main() { let mut x = vec![1, 2, 3]; - let mut tmp = x.into_iter(); - 'a: while let Some(v) = tmp.next() { + let mut iter = x.into_iter(); + 'a: while let Some(v) = iter.next() { v *= 2; break 'a; }; @@ -236,10 +236,10 @@ fn main() { r" fn main() { let mut x = vec![1, 2, 3]; - let mut tmp = x.into_iter(); + let mut iter = x.into_iter(); #[allow(unused)] #[deny(unsafe_code)] - while let Some(v) = tmp.next() { + while let Some(v) = iter.next() { v *= 2; }; }", @@ -275,8 +275,8 @@ fn next(&mut self) -> Option { } fn main() { - let mut tmp = 0..92; - while let Some(x) = tmp.next() { + let mut iter = 0..92; + while let Some(x) = iter.next() { print!("{}", x); } }"#, @@ -330,8 +330,8 @@ fn iter_mut(&mut self) -> Repeat { repeat(92) } fn main() { let x = S; - let mut tmp = x.iter(); - while let Some(v) = tmp.next() { + let mut iter = x.iter(); + while let Some(v) = iter.next() { let a = v * 2; } } @@ -356,8 +356,8 @@ fn main() { struct NoIterMethod; fn main() { let x = NoIterMethod; - let mut tmp = (&x).into_iter(); - while let Some(v) = tmp.next() { + let mut iter = (&x).into_iter(); + while let Some(v) = iter.next() { let a = v * 2; } } @@ -382,8 +382,8 @@ fn main() { struct NoIterMethod; fn main() { let x = NoIterMethod; - let mut tmp = (&mut x).into_iter(); - while let Some(v) = tmp.next() { + let mut iter = (&mut x).into_iter(); + while let Some(v) = iter.next() { let a = v * 2; } } @@ -423,8 +423,8 @@ fn iter_mut(&mut self) -> Repeat { repeat(92) } fn main() { let x = S; - let mut tmp = x.iter_mut(); - while let Some(v) = tmp.next() { + let mut iter = x.iter_mut(); + while let Some(v) = iter.next() { let a = v * 2; } } @@ -448,8 +448,8 @@ fn main() { fn main() { let mut x = vec![1, 2, 3]; let y = &mut x; - let mut tmp = y.into_iter(); - while let Some(v) = tmp.next() { + let mut iter = y.into_iter(); + while let Some(v) = iter.next() { *v *= 2; } }", @@ -471,8 +471,8 @@ fn main() { "#, r#" fn main() { - let mut tmp = core::iter::repeat(92).take(1); - while let Some(a) = tmp.next() { + let mut iter = core::iter::repeat(92).take(1); + while let Some(a) = iter.next() { println!("{}", a); } } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs b/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs index 8ba46799d5ab..66d5cf834f17 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs @@ -507,8 +507,8 @@ fn main() { r#####" fn main() { let x = vec![1, 2, 3]; - let mut tmp = x.into_iter(); - while let Some(v) = tmp.next() { + let mut iter = x.into_iter(); + while let Some(v) = iter.next() { let y = v * 2; }; } From 2258432bf638deb84075fafd40f18fb389d5b98c Mon Sep 17 00:00:00 2001 From: railgun-0402 Date: Mon, 23 Mar 2026 23:19:47 +0900 Subject: [PATCH 10/56] fix: Accept parenthesized paths in asm `sym` operand parser --- .../src/handlers/typed_hole.rs | 26 ++++++++++ .../parser/src/grammar/expressions/atom.rs | 12 ++++- .../parser/test_data/generated/runner.rs | 2 + .../parser/inline/ok/asm_sym_paren.rast | 49 +++++++++++++++++++ .../parser/inline/ok/asm_sym_paren.rs | 3 ++ 5 files changed, 91 insertions(+), 1 deletion(-) create mode 100644 src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/asm_sym_paren.rast create mode 100644 src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/asm_sym_paren.rs diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs index 577c582a2080..fd1674e2a47b 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs @@ -442,4 +442,30 @@ fn rdtscp() -> u64 { }"#, ); } + + #[test] + fn asm_sym_with_macro_expr_fragment() { + // Regression test for issue #21582 + // When `$e:expr` captures a path and is used in `sym $e`, the path gets + // wrapped in parentheses during macro expansion due to invisible delimiters. + // This should not cause false positive typed-hole errors. + check_diagnostics( + r#" +//- minicore: asm +macro_rules! m { + ($e:expr) => { + core::arch::asm!("/*{f}*/", f = sym $e, out("ax") _) + }; +} + +fn generic() {} + +fn main() { + unsafe { + m!(generic::); + } +} +"#, + ); + } } diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/expressions/atom.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/expressions/atom.rs index b75474ee2b86..3214fd90f29a 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/expressions/atom.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar/expressions/atom.rs @@ -407,8 +407,18 @@ pub(crate) fn parse_asm_expr(p: &mut Parser<'_>, m: Marker) -> Option Date: Mon, 23 Mar 2026 20:04:30 +0530 Subject: [PATCH 11/56] add type_bound, type_bound_list and assoc_item_list_empty in syntaxfactory constructor --- .../src/ast/syntax_factory/constructors.rs | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs index 55c80ed16707..24bf9ed3d296 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs @@ -59,6 +59,26 @@ pub fn ty_path(&self, path: ast::Path) -> ast::PathType { ast } + pub fn type_bound(&self, bound: ast::Type) -> ast::TypeBound { + make::type_bound(bound).clone_for_update() + } + + pub fn type_bound_list( + &self, + bounds: impl IntoIterator, + ) -> Option { + let (bounds, input) = iterator_input(bounds); + let ast = make::type_bound_list(bounds)?.clone_for_update(); + + if let Some(mut mapping) = self.mappings() { + let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); + builder.map_children(input, ast.bounds().map(|b| b.syntax().clone())); + builder.finish(&mut mapping); + } + + Some(ast) + } + pub fn type_param( &self, name: ast::Name, @@ -1759,6 +1779,10 @@ pub fn assoc_item_list( ast } + pub fn assoc_item_list_empty(&self) -> ast::AssocItemList { + make::assoc_item_list(None).clone_for_update() + } + pub fn attr_outer(&self, meta: ast::Meta) -> ast::Attr { let ast = make::attr_outer(meta.clone()).clone_for_update(); From 772782a11489d3ca0d1e06d5d99ef9dd35427546 Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Mon, 23 Mar 2026 20:05:50 +0530 Subject: [PATCH 12/56] introduce utils methods syntaxFactory variant and comment those methods as legacy --- .../crates/ide-assists/src/utils.rs | 201 +++++++++++++++++- 1 file changed, 199 insertions(+), 2 deletions(-) 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 0657e7243af0..dc117c6381c0 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs @@ -203,6 +203,9 @@ fn has_def_name(item: &InFile) -> bool { /// [`filter_assoc_items()`]), clones each item for update and applies path transformation to it, /// then inserts into `impl_`. Returns the modified `impl_` and the first associated item that got /// inserted. +/// +/// Legacy: prefer [`add_trait_assoc_items_to_impl_with_factory`] when a [`SyntaxFactory`] is +/// available. #[must_use] pub fn add_trait_assoc_items_to_impl( sema: &Semantics<'_, RootDatabase>, @@ -279,6 +282,79 @@ pub fn add_trait_assoc_items_to_impl( .collect() } +/// [`SyntaxFactory`]-based variant of [`add_trait_assoc_items_to_impl`]. +#[must_use] +pub fn add_trait_assoc_items_to_impl_with_factory( + make: &SyntaxFactory, + sema: &Semantics<'_, RootDatabase>, + config: &AssistConfig, + original_items: &[InFile], + trait_: hir::Trait, + impl_: &ast::Impl, + target_scope: &hir::SemanticsScope<'_>, +) -> Vec { + let new_indent_level = IndentLevel::from_node(impl_.syntax()) + 1; + original_items + .iter() + .map(|InFile { file_id, value: original_item }| { + let mut cloned_item = { + if let Some(macro_file) = file_id.macro_file() { + let span_map = sema.db.expansion_span_map(macro_file); + let item_prettified = prettify_macro_expansion( + sema.db, + original_item.syntax().clone(), + &span_map, + target_scope.krate().into(), + ); + if let Some(formatted) = ast::AssocItem::cast(item_prettified) { + return formatted; + } else { + stdx::never!("formatted `AssocItem` could not be cast back to `AssocItem`"); + } + } + original_item + } + .reset_indent(); + + if let Some(source_scope) = sema.scope(original_item.syntax()) { + let transform = + PathTransform::trait_impl(target_scope, &source_scope, trait_, impl_.clone()); + cloned_item = ast::AssocItem::cast(transform.apply(cloned_item.syntax())).unwrap(); + } + cloned_item.remove_attrs_and_docs(); + cloned_item + }) + .filter_map(|item| match item { + ast::AssocItem::Fn(fn_) if fn_.body().is_none() => { + let fn_ = fn_.clone_subtree(); + let fill_expr: ast::Expr = match config.expr_fill_default { + ExprFillDefaultMode::Todo | ExprFillDefaultMode::Default => make.expr_todo(), + ExprFillDefaultMode::Underscore => make.expr_underscore().into(), + }; + let new_body = make.block_expr(None::, Some(fill_expr)); + let new_body = AstNodeEdit::indent(&new_body, IndentLevel::single()); + let mut fn_editor = SyntaxEditor::new(fn_.syntax().clone()); + fn_.replace_or_insert_body(&mut fn_editor, new_body); + let new_fn_ = fn_editor.finish().new_root().clone(); + ast::AssocItem::cast(new_fn_) + } + ast::AssocItem::TypeAlias(type_alias) => { + let type_alias = type_alias.clone_subtree(); + if let Some(type_bound_list) = type_alias.type_bound_list() { + let mut type_alias_editor = SyntaxEditor::new(type_alias.syntax().clone()); + type_bound_list.remove(&mut type_alias_editor); + let type_alias = type_alias_editor.finish().new_root().clone(); + ast::AssocItem::cast(type_alias) + } else { + Some(ast::AssocItem::TypeAlias(type_alias)) + } + } + item => Some(item), + }) + .map(|item| AstNodeEdit::indent(&item, new_indent_level)) + .collect() +} + pub(crate) fn vis_offset(node: &SyntaxNode) -> TextSize { node.children_with_tokens() .find(|it| !matches!(it.kind(), WHITESPACE | COMMENT | ATTR)) @@ -670,8 +746,13 @@ pub(crate) fn generate_impl(adt: &ast::Adt) -> ast::Impl { /// and lifetime parameters, with `` appended to `impl`'s generic parameters' bounds. /// /// This is useful for traits like `PartialEq`, since `impl PartialEq for U` often requires `T: PartialEq`. -pub(crate) fn generate_trait_impl(is_unsafe: bool, adt: &ast::Adt, trait_: ast::Type) -> ast::Impl { - generate_impl_inner(is_unsafe, adt, Some(trait_), true, None) +pub(crate) fn generate_trait_impl( + make: &SyntaxFactory, + is_unsafe: bool, + adt: &ast::Adt, + trait_: ast::Type, +) -> ast::Impl { + generate_impl_inner_with_factory(make, is_unsafe, adt, Some(trait_), true, None) } /// Generates the corresponding `impl for Type {}` including type @@ -752,6 +833,76 @@ fn generate_impl_inner( .clone_for_update() } +fn generate_impl_inner_with_factory( + make: &SyntaxFactory, + is_unsafe: bool, + adt: &ast::Adt, + trait_: Option, + trait_is_transitive: bool, + body: Option, +) -> ast::Impl { + // Ensure lifetime params are before type & const params + let generic_params = adt.generic_param_list().map(|generic_params| { + let lifetime_params = + generic_params.lifetime_params().map(ast::GenericParam::LifetimeParam); + let ty_or_const_params = generic_params.type_or_const_params().filter_map(|param| { + let param = match param { + ast::TypeOrConstParam::Type(param) => { + // remove defaults since they can't be specified in impls + let mut bounds = + param.type_bound_list().map_or_else(Vec::new, |it| it.bounds().collect()); + if let Some(trait_) = &trait_ { + // Add the current trait to `bounds` if the trait is transitive, + // meaning `impl Trait for U` requires `T: Trait`. + if trait_is_transitive { + bounds.push(make.type_bound(trait_.clone())); + } + }; + // `{ty_param}: {bounds}` + let param = make.type_param(param.name()?, make.type_bound_list(bounds)); + ast::GenericParam::TypeParam(param) + } + ast::TypeOrConstParam::Const(param) => { + // remove defaults since they can't be specified in impls + let param = make.const_param(param.name()?, param.ty()?); + ast::GenericParam::ConstParam(param) + } + }; + Some(param) + }); + + make.generic_param_list(itertools::chain(lifetime_params, ty_or_const_params)) + }); + let generic_args = + generic_params.as_ref().map(|params| params.to_generic_args().clone_for_update()); + let adt_assoc_bounds = + trait_.as_ref().zip(generic_params.as_ref()).and_then(|(trait_, params)| { + generic_param_associated_bounds_with_factory(make, adt, trait_, params) + }); + + let ty: ast::Type = make.ty_path(make.ident_path(&adt.name().unwrap().text())).into(); + + let cfg_attrs = + adt.attrs().filter(|attr| attr.as_simple_call().is_some_and(|(name, _arg)| name == "cfg")); + match trait_ { + Some(trait_) => make.impl_trait( + cfg_attrs, + is_unsafe, + None, + None, + generic_params, + generic_args, + false, + trait_, + ty, + adt_assoc_bounds, + adt.where_clause(), + body, + ), + None => make.impl_(cfg_attrs, generic_params, generic_args, ty, adt.where_clause(), body), + } +} + fn generic_param_associated_bounds( adt: &ast::Adt, trait_: &ast::Type, @@ -797,6 +948,52 @@ fn generic_param_associated_bounds( trait_where_clause.peek().is_some().then(|| make::where_clause(trait_where_clause)) } +fn generic_param_associated_bounds_with_factory( + make: &SyntaxFactory, + adt: &ast::Adt, + trait_: &ast::Type, + generic_params: &ast::GenericParamList, +) -> Option { + let in_type_params = |name: &ast::NameRef| { + generic_params + .generic_params() + .filter_map(|param| match param { + ast::GenericParam::TypeParam(type_param) => type_param.name(), + _ => None, + }) + .any(|param| param.text() == name.text()) + }; + let adt_body = match adt { + ast::Adt::Enum(e) => e.variant_list().map(|it| it.syntax().clone()), + ast::Adt::Struct(s) => s.field_list().map(|it| it.syntax().clone()), + ast::Adt::Union(u) => u.record_field_list().map(|it| it.syntax().clone()), + }; + let mut trait_where_clause = adt_body + .into_iter() + .flat_map(|it| it.descendants()) + .filter_map(ast::Path::cast) + .filter_map(|path| { + let qualifier = path.qualifier()?.as_single_segment()?; + let qualifier = qualifier + .name_ref() + .or_else(|| match qualifier.type_anchor()?.ty()? { + ast::Type::PathType(path_type) => path_type.path()?.as_single_name_ref(), + _ => None, + }) + .filter(in_type_params)?; + Some((qualifier, path.segment()?.name_ref()?)) + }) + .map(|(qualifier, assoc_name)| { + let segments = [qualifier, assoc_name].map(|nr| make.path_segment(nr)); + let path = make.path_from_segments(segments, false); + let bounds = [make.type_bound(trait_.clone())]; + make.where_pred(either::Either::Right(make.ty_path(path).into()), bounds) + }) + .unique_by(|it| it.syntax().to_string()) + .peekable(); + trait_where_clause.peek().is_some().then(|| make.where_clause(trait_where_clause)) +} + pub(crate) fn add_method_to_adt( builder: &mut SourceChangeBuilder, adt: &ast::Adt, From ba063f2ba70c18471f25dec9d4aaa720fc4aac3a Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Mon, 23 Mar 2026 20:06:45 +0530 Subject: [PATCH 13/56] migrate replace_derive_with_manual to use syntax factory instead of make --- .../replace_derive_with_manual_impl.rs | 43 ++++++++++++------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs index 7c024263b4a8..f54f7a02d2b3 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs @@ -4,7 +4,7 @@ use syntax::{ SyntaxKind::WHITESPACE, T, - ast::{self, AstNode, HasName, make}, + ast::{self, AstNode, HasName, syntax_factory::SyntaxFactory}, syntax_editor::{Position, SyntaxEditor}, }; @@ -12,8 +12,8 @@ AssistConfig, AssistId, assist_context::{AssistContext, Assists}, utils::{ - DefaultMethods, IgnoreAssocItems, add_trait_assoc_items_to_impl, filter_assoc_items, - gen_trait_fn_body, generate_trait_impl, + DefaultMethods, IgnoreAssocItems, add_trait_assoc_items_to_impl_with_factory, + filter_assoc_items, gen_trait_fn_body, generate_trait_impl, }, }; @@ -127,6 +127,7 @@ fn add_assist( let label = format!("Convert to manual `impl {replace_trait_path} for {annotated_name}`"); acc.add(AssistId::refactor("replace_derive_with_manual_impl"), label, target, |builder| { + let make = SyntaxFactory::without_mappings(); let insert_after = Position::after(adt.syntax()); let impl_is_unsafe = trait_.map(|s| s.is_unsafe(ctx.db())).unwrap_or(false); let impl_def = impl_def_from_trait( @@ -142,7 +143,7 @@ fn add_assist( let mut editor = builder.make_editor(attr.syntax()); update_attribute(&mut editor, old_derives, old_tree, old_trait_path, attr); - let trait_path = make::ty_path(replace_trait_path.clone()); + let trait_path = make.ty_path(replace_trait_path.clone()).into(); let (impl_def, first_assoc_item) = if let Some(impl_def) = impl_def { ( @@ -150,7 +151,7 @@ fn add_assist( impl_def.assoc_item_list().and_then(|list| list.assoc_items().next()), ) } else { - (generate_trait_impl(impl_is_unsafe, adt, trait_path), None) + (generate_trait_impl(&make, impl_is_unsafe, adt, trait_path), None) }; if let Some(cap) = ctx.config.snippet_cap { @@ -174,7 +175,7 @@ fn add_assist( editor.insert_all( insert_after, - vec![make::tokens::blank_line().into(), impl_def.syntax().clone().into()], + vec![make.whitespace("\n\n").into(), impl_def.syntax().clone().into()], ); builder.add_file_edits(ctx.vfs_file_id(), editor); }) @@ -205,10 +206,19 @@ fn impl_def_from_trait( if trait_items.is_empty() { return None; } - let impl_def = generate_trait_impl(impl_is_unsafe, adt, make::ty_path(trait_path.clone())); + let make = SyntaxFactory::without_mappings(); + let trait_ty = make.ty_path(trait_path.clone()).into(); + let impl_def = generate_trait_impl(&make, impl_is_unsafe, adt, trait_ty); - let assoc_items = - add_trait_assoc_items_to_impl(sema, config, &trait_items, trait_, &impl_def, &target_scope); + let assoc_items = add_trait_assoc_items_to_impl_with_factory( + &make, + sema, + config, + &trait_items, + trait_, + &impl_def, + &target_scope, + ); let assoc_item_list = if let Some((first, other)) = assoc_items.split_first().map(|(first, other)| (first.clone_subtree(), other)) { @@ -222,12 +232,12 @@ fn impl_def_from_trait( } else { Some(first.clone()) }; - let items = first_item.into_iter().chain(other.iter().cloned()).collect(); - make::assoc_item_list(Some(items)) + let items: Vec = + first_item.into_iter().chain(other.iter().cloned()).collect(); + make.assoc_item_list(items) } else { - make::assoc_item_list(None) - } - .clone_for_update(); + make.assoc_item_list_empty() + }; let impl_def = impl_def.clone_subtree(); let mut editor = SyntaxEditor::new(impl_def.syntax().clone()); @@ -243,6 +253,7 @@ fn update_attribute( old_trait_path: &ast::Path, attr: &ast::Attr, ) { + let make = SyntaxFactory::without_mappings(); let new_derives = old_derives .iter() .filter(|t| t.to_string() != old_trait_path.to_string()) @@ -257,13 +268,13 @@ fn update_attribute( .collect::>() }); // ...which are interspersed with ", " - let tt = Itertools::intersperse(tt, vec![make::token(T![,]), make::tokens::single_space()]); + let tt = Itertools::intersperse(tt, vec![make.token(T![,]), make.whitespace(" ")]); // ...wrap them into the appropriate `NodeOrToken` variant let tt = tt.flatten().map(syntax::NodeOrToken::Token); // ...and make them into a flat list of tokens let tt = tt.collect::>(); - let new_tree = make::token_tree(T!['('], tt).clone_for_update(); + let new_tree = make.token_tree(T!['('], tt); editor.replace(old_tree.syntax(), new_tree.syntax()); } else { // Remove the attr and any trailing whitespace From 4e1fd93ab735a64c824e58fb76052b1b6194da18 Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Tue, 6 Jan 2026 17:46:00 +0800 Subject: [PATCH 14/56] Fix not applicable on ambiguous ident pat for merge_match_arms Example --- ```rust enum X { A, B, C, } use X::*; fn main() { match A { $0A => todo!(), B => todo!(), C => todo!(), } } ``` **Before this PR** Assist not applicable **After this PR** ```rust enum X { A, B, C, } use X::*; fn main() { match A { A | B => todo!(), C => todo!(), } } ``` --- .../src/handlers/merge_match_arms.rs | 39 ++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_match_arms.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_match_arms.rs index 08170f81b283..6e84af5f9129 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_match_arms.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_match_arms.rs @@ -160,8 +160,11 @@ fn recurse<'db>( } } ast::Pat::IdentPat(ident_pat) => { - if let Some(name) = ident_pat.name() { + if let Some(name) = ident_pat.name() + && ctx.sema.to_def(ident_pat).is_some() + { let pat_type = ctx.sema.type_of_binding_in_pat(ident_pat); + map.insert(name.text().to_string(), pat_type); } } @@ -212,6 +215,40 @@ fn main() { ); } + #[test] + fn merge_match_arms_ambiguous_ident_patterns() { + check_assist( + merge_match_arms, + r#" +#[derive(Debug)] +enum X { A, B, C } +use X::*; + +fn main() { + let x = A; + let y = match x { + A => { 1i32$0 } + B => { 1i32 } + C => { 2i32 } + } +} +"#, + r#" +#[derive(Debug)] +enum X { A, B, C } +use X::*; + +fn main() { + let x = A; + let y = match x { + A | B => { 1i32 }, + C => { 2i32 } + } +} +"#, + ); + } + #[test] fn merge_match_arms_multiple_patterns() { check_assist( From bb0bc8567ffa39c767650f6603a965001cba94c0 Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Tue, 24 Mar 2026 17:53:31 +0800 Subject: [PATCH 15/56] fix: wrap `Option<>` for desugar_try_expr_let_else Example --- ```rust fn test() { let pat: bool = Some(true)$0?; } ``` **Before this PR** ```rust fn test() { let Some(pat): bool = Some(true) else { return None; }; } ``` **After this PR** ```rust fn test() { let Some(pat): Option = Some(true) else { return None; }; } ``` --- .../src/handlers/desugar_try_expr.rs | 23 ++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/desugar_try_expr.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/desugar_try_expr.rs index 02879837dc2f..e43cf0bc8aae 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/desugar_try_expr.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/desugar_try_expr.rs @@ -116,7 +116,7 @@ pub(crate) fn desugar_try_expr(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op let fill_expr = || crate::utils::expr_fill_default(ctx.config); let new_let_stmt = make.let_else_stmt( try_enum.happy_pattern(pat), - let_stmt.ty(), + let_stmt.ty().map(|ty| make.ty_option(ty).into()), expr, make.block_expr( iter::once( @@ -243,6 +243,27 @@ fn test() { let Ok(pat) = Ok(true) else { return Err(todo!()); }; +} + "#, + "Replace try expression with let else", + ); + } + + #[test] + fn test_desugar_try_expr_option_let_else_with_type() { + check_assist_by_label( + desugar_try_expr, + r#" +//- minicore: try, option +fn test() { + let pat: bool = Some(true)$0?; +} + "#, + r#" +fn test() { + let Some(pat): Option = Some(true) else { + return None; + }; } "#, "Replace try expression with let else", From e20616882af110507162e48b113456eaf5aadac1 Mon Sep 17 00:00:00 2001 From: albab-hasan Date: Tue, 24 Mar 2026 14:58:24 +0600 Subject: [PATCH 16/56] fix: upmap macro-expanded usages in destructure struct/tuple binding MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit when a local binding is used inside a macro call (e.g. write!(s, "{}", x.field) or write!(s, "{}", t.0)), the usage's name node lives in the macro expansion tree while the syntax editor is rooted at the source file tree. passing the expansion node to editor.replace() causes apply_edits to panic when it resolves the SyntaxNodePtr against the wrong tree. instead of skipping macro-expanded usages, map them back to the original source via sema.original_range_opt() and replace the text at the mapped range. this follows the established pattern of upmapping macro code to source code rather than ignoring it. for destructure_struct_binding, macro field accesses like x.y are replaced with the destructured field name y directly in the source. for destructure_tuple_binding, a new TextReplace variant on EditTupleUsage handles text-based replacements for macro-expanded tuple index accesses like x.0 → _0. when original_range_opt cannot map back (e.g. the index originates from the macro body rather than the call site), the code falls back to NoIndex (wrapping in block comments) or skipping, matching previous behavior. this also replaces the MacroStmts ancestor check in destructure_tuple_binding, which only covered macros expanding to multiple statements and missed single-expression macros (MacroExpr). fixes rust-lang/rust-analyzer#20716 --- .../handlers/destructure_struct_binding.rs | 36 +++++++- .../src/handlers/destructure_tuple_binding.rs | 88 +++++++++++-------- 2 files changed, 86 insertions(+), 38 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_struct_binding.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_struct_binding.rs index 0f5ef0548cf5..3f42696fa39f 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_struct_binding.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_struct_binding.rs @@ -17,7 +17,7 @@ use crate::{ assist_context::{AssistContext, Assists, SourceChangeBuilder}, - utils::ref_field_expr::determine_ref_and_parens, + utils::{cover_edit_range, ref_field_expr::determine_ref_and_parens}, }; // Assist: destructure_struct_binding @@ -358,6 +358,7 @@ fn update_usages( data: &StructEditData, field_names: &FxHashMap, ) { + let source = ctx.source_file(); let make = SyntaxFactory::with_mappings(); let edits = data .usages @@ -366,7 +367,9 @@ fn update_usages( .collect_vec(); editor.add_mappings(make.finish_with_mappings()); for (old, new) in edits { - editor.replace(old, new); + if let Some(range) = ctx.sema.original_range_opt(&old) { + editor.replace_all(cover_edit_range(source, range.range), vec![new.into()]); + } } } @@ -1006,4 +1009,33 @@ fn main($0foo: dep::Foo) {} "#, ) } + + #[test] + fn record_struct_usage_in_macro_call() { + // exact repro from #20716: struct field access inside write! must not panic + check_assist( + destructure_struct_binding, + r#" +//- minicore: write, fmt +use core::fmt::Write; +struct Foo { y: i8 } + +fn main() { + let mut s = String::new(); + let $0x = Foo { y: 8 }; + write!(s, "{}", x.y).unwrap(); +} +"#, + r#" +use core::fmt::Write; +struct Foo { y: i8 } + +fn main() { + let mut s = String::new(); + let Foo { y } = Foo { y: 8 }; + write!(s, "{}", y).unwrap(); +} +"#, + ) + } } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_tuple_binding.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_tuple_binding.rs index d51a3a26a3c7..583ba42bf5b8 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_tuple_binding.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_tuple_binding.rs @@ -14,7 +14,7 @@ use crate::{ assist_context::{AssistContext, Assists, SourceChangeBuilder}, - utils::ref_field_expr::determine_ref_and_parens, + utils::{cover_edit_range, ref_field_expr::determine_ref_and_parens}, }; // Assist: destructure_tuple_binding @@ -98,7 +98,9 @@ fn destructure_tuple_edit_impl( assignment_edit.apply(&mut syntax_editor, &syntax_factory); if let Some(usages_edit) = current_file_usages_edit { - usages_edit.into_iter().for_each(|usage_edit| usage_edit.apply(edit, &mut syntax_editor)) + usages_edit + .into_iter() + .for_each(|usage_edit| usage_edit.apply(ctx, edit, &mut syntax_editor)) } syntax_editor.add_mappings(syntax_factory.finish_with_mappings()); @@ -311,14 +313,25 @@ enum EditTupleUsage { } impl EditTupleUsage { - fn apply(self, edit: &mut SourceChangeBuilder, syntax_editor: &mut SyntaxEditor) { + fn apply( + self, + ctx: &AssistContext<'_>, + edit: &mut SourceChangeBuilder, + syntax_editor: &mut SyntaxEditor, + ) { match self { EditTupleUsage::NoIndex(range) => { edit.insert(range.start(), "/*"); edit.insert(range.end(), "*/"); } EditTupleUsage::ReplaceExpr(target_expr, replace_with) => { - syntax_editor.replace(target_expr.syntax(), replace_with.syntax()) + if let Some(range) = ctx.sema.original_range_opt(target_expr.syntax()) { + let source = ctx.source_file(); + syntax_editor.replace_all( + cover_edit_range(source, range.range), + vec![replace_with.syntax().clone().into()], + ); + } } } } @@ -349,24 +362,6 @@ fn detect_tuple_index(usage: &FileReference, data: &TupleData) -> Option range of `field_expr` in applied macro, NOT range in actual file! - if field_expr.syntax().ancestors().any(|a| ast::MacroStmts::can_cast(a.kind())) { - cov_mark::hit!(destructure_tuple_macro_call); - - // issue: cannot differentiate between tuple index passed into macro or tuple index as result of macro: - // ```rust - // macro_rules! m { - // ($t1:expr, $t2:expr) => { $t1; $t2.0 } - // } - // let t = (1,2); - // m!(t.0, t) - // ``` - // -> 2 tuple index usages detected! - // - // -> only handle `t` - return None; - } - Some(TupleIndex { index: idx, field_expr }) } else { // tuple index out of range @@ -1437,7 +1432,6 @@ mod in_macro_call { #[test] fn detect_macro_call() { - cov_mark::check!(destructure_tuple_macro_call); check_in_place_assist( r#" macro_rules! m { @@ -1456,7 +1450,7 @@ macro_rules! m { fn main() { let ($0_0, _1) = (1,2); - m!(/*t*/.0); + m!(_0); } "#, ) @@ -1548,7 +1542,6 @@ fn main() { m!(t.0); } "#, - // FIXME: replace `t.0` with `_0` (cannot detect range of tuple index in macro call) r#" macro_rules! m { ($e:expr) => { "foo"; $e }; @@ -1556,10 +1549,9 @@ macro_rules! m { fn main() { let ($0_0, _1) = (1,2); - m!(/*t*/.0); + m!(_0); } "#, - // FIXME: replace `t.0` with `_0` r#" macro_rules! m { ($e:expr) => { "foo"; $e }; @@ -1567,7 +1559,7 @@ macro_rules! m { fn main() { let t @ ($0_0, _1) = (1,2); - m!(t.0); + m!(_0); } "#, ) @@ -1586,7 +1578,6 @@ fn main() { m!((t).0); } "#, - // FIXME: replace `(t).0` with `_0` r#" macro_rules! m { ($e:expr) => { "foo"; $e }; @@ -1594,10 +1585,9 @@ macro_rules! m { fn main() { let ($0_0, _1) = (1,2); - m!((/*t*/).0); + m!(_0); } "#, - // FIXME: replace `(t).0` with `_0` r#" macro_rules! m { ($e:expr) => { "foo"; $e }; @@ -1605,7 +1595,7 @@ macro_rules! m { fn main() { let t @ ($0_0, _1) = (1,2); - m!((t).0); + m!(_0); } "#, ) @@ -1653,7 +1643,6 @@ fn main() { m!(t, t.0); } "#, - // FIXME: replace `t.0` in macro call (not IN macro) with `_0` r#" macro_rules! m { ($t:expr, $i:expr) => { $t.0 + $i }; @@ -1661,10 +1650,9 @@ macro_rules! m { fn main() { let ($0_0, _1) = (1,2); - m!(/*t*/, /*t*/.0); + m!(t, _0); } "#, - // FIXME: replace `t.0` in macro call with `_0` r#" macro_rules! m { ($t:expr, $i:expr) => { $t.0 + $i }; @@ -1672,13 +1660,41 @@ macro_rules! m { fn main() { let t @ ($0_0, _1) = (1,2); - m!(t, t.0); + m!(t, _0); } "#, ) } } + mod in_macro_expr { + use super::assist::*; + + // exact repro from #20716: tuple index inside write! must not panic + #[test] + fn tuple_index_in_write_macro() { + check_in_place_assist( + r#" +//- minicore: write, fmt +use core::fmt::Write; +fn main() { + let mut s = String::new(); + let $0x = (2i32, 3i32); + write!(s, "{}", x.0).unwrap(); +} +"#, + r#" +use core::fmt::Write; +fn main() { + let mut s = String::new(); + let ($0_0, _1) = (2i32, 3i32); + write!(s, "{}", _0).unwrap(); +} +"#, + ) + } + } + mod refs { use super::assist::*; From 2db5d1ffdb6d7efdfa722221c0b5dd6093e1881d Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Mon, 23 Mar 2026 22:59:16 +0800 Subject: [PATCH 17/56] cover_edit_range uses SyntaxNode instead AstNode --- .../src/handlers/convert_named_struct_to_tuple_struct.rs | 6 +++--- .../src/handlers/convert_tuple_struct_to_named_struct.rs | 8 ++++---- .../src/handlers/destructure_struct_binding.rs | 2 +- .../ide-assists/src/handlers/destructure_tuple_binding.rs | 2 +- src/tools/rust-analyzer/crates/ide-assists/src/utils.rs | 4 ++-- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_named_struct_to_tuple_struct.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_named_struct_to_tuple_struct.rs index 42fceb85336b..4dd2036c024c 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_named_struct_to_tuple_struct.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_named_struct_to_tuple_struct.rs @@ -242,7 +242,7 @@ fn record_to_tuple_struct_like( { let make = SyntaxFactory::without_mappings(); let orig = ctx.sema.original_range_opt(field_list.syntax())?; - let list_range = cover_edit_range(source, orig.range); + let list_range = cover_edit_range(source.syntax(), orig.range); let l_curly = match list_range.start() { NodeOrToken::Node(node) => node.first_token()?, @@ -265,7 +265,7 @@ fn record_to_tuple_struct_like( for name_ref in fields(&field_list) { let Some(orig) = ctx.sema.original_range_opt(name_ref.syntax()) else { continue }; - let name_range = cover_edit_range(source, orig.range); + let name_range = cover_edit_range(source.syntax(), orig.range); if let Some(colon) = next_non_trivia_token(name_range.end().clone()) && colon.kind() == T![:] @@ -306,7 +306,7 @@ fn edit_field_references( // Only edit the field reference if it's part of a `.field` access if name_ref.syntax().parent().and_then(ast::FieldExpr::cast).is_some() { edit.replace_all( - cover_edit_range(&source, r.range), + cover_edit_range(source.syntax(), r.range), vec![make.name_ref(&index.to_string()).syntax().clone().into()], ); } 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 f1eae8386637..270467b14f0c 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 @@ -191,7 +191,7 @@ fn process_struct_name_reference( full_path, generate_record_pat_list(&tuple_struct_pat, names), ); - editor.replace_all(cover_edit_range(source, range), vec![new.syntax().clone().into()]); + editor.replace_all(cover_edit_range(source.syntax(), range), vec![new.syntax().clone().into()]); }, ast::PathExpr(path_expr) => { let call_expr = path_expr.syntax().parent().and_then(ast::CallExpr::cast)?; @@ -207,7 +207,7 @@ fn process_struct_name_reference( let mut first_insert = vec![]; for (expr, name) in arg_list.args().zip(names) { let range = ctx.sema.original_range_opt(expr.syntax())?.range; - let place = cover_edit_range(source, range); + let place = cover_edit_range(source.syntax(), range); let elements = vec![ make.name_ref(&name.text()).syntax().clone().into(), make.token(T![:]).into(), @@ -236,7 +236,7 @@ fn process_delimiter( first_insert: Vec, ) { let Some(range) = ctx.sema.original_range_opt(list.syntax()) else { return }; - let place = cover_edit_range(source, range.range); + let place = cover_edit_range(source.syntax(), range.range); let l_paren = match place.start() { syntax::NodeOrToken::Node(node) => node.first_token(), @@ -290,7 +290,7 @@ fn edit_field_references( && let Some(original) = ctx.sema.original_range_opt(name_ref.syntax()) { editor.replace_all( - cover_edit_range(&source, original.range), + cover_edit_range(source.syntax(), original.range), vec![name.syntax().clone().into()], ); } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_struct_binding.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_struct_binding.rs index 3f42696fa39f..ec4a83b642c0 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_struct_binding.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_struct_binding.rs @@ -358,7 +358,7 @@ fn update_usages( data: &StructEditData, field_names: &FxHashMap, ) { - let source = ctx.source_file(); + let source = ctx.source_file().syntax(); let make = SyntaxFactory::with_mappings(); let edits = data .usages diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_tuple_binding.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_tuple_binding.rs index 583ba42bf5b8..23c11b258c1a 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_tuple_binding.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_tuple_binding.rs @@ -326,7 +326,7 @@ fn apply( } EditTupleUsage::ReplaceExpr(target_expr, replace_with) => { if let Some(range) = ctx.sema.original_range_opt(target_expr.syntax()) { - let source = ctx.source_file(); + let source = ctx.source_file().syntax(); syntax_editor.replace_all( cover_edit_range(source, range.range), vec![replace_with.syntax().clone().into()], 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 0f28a202253c..2f40f889fcce 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs @@ -1219,10 +1219,10 @@ pub(crate) fn cover_let_chain(mut expr: ast::Expr, range: TextRange) -> Option std::ops::RangeInclusive { - let node = match source.syntax().covering_element(range) { + let node = match source.covering_element(range) { NodeOrToken::Node(node) => node, NodeOrToken::Token(t) => t.parent().unwrap(), }; From bf8178627c7140f86387eb94b942d39577642161 Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Wed, 4 Mar 2026 12:02:07 +0800 Subject: [PATCH 18/56] fix: keep comments for 'Fill match arms' Example --- ```rust enum E { A, B, C } fn foo(t: E) -> i32 { match $0t { // variant a E::A => 2 // comment on end } } ``` **Before this PR** ```rust enum E { A, B, C } fn foo(t: E) -> i32 { match t { E::A => 2, E::B => ${1:todo!()}, E::C => ${2:todo!()},$0 } } ``` **After this PR** ```rust enum E { A, B, C } fn foo(t: E) -> i32 { match t { // variant a E::A => 2, // comment on end E::B => ${1:todo!()}, E::C => ${2:todo!()},$0 } } ``` --- .../src/handlers/add_missing_match_arms.rs | 173 ++++++++++++++---- 1 file changed, 137 insertions(+), 36 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs index 95712707589e..947766624234 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs @@ -6,10 +6,11 @@ use ide_db::syntax_helpers::suggest_name; use ide_db::{famous_defs::FamousDefs, helpers::mod_path_to_ast}; use itertools::Itertools; -use syntax::ToSmolStr; -use syntax::ast::edit::{AstNodeEdit, IndentLevel}; +use syntax::ast::edit::IndentLevel; use syntax::ast::syntax_factory::SyntaxFactory; use syntax::ast::{self, AstNode, MatchArmList, MatchExpr, Pat, make}; +use syntax::syntax_editor::{Position, SyntaxEditor}; +use syntax::{SyntaxKind, SyntaxNode, ToSmolStr}; use crate::{AssistContext, AssistId, Assists, utils}; @@ -223,32 +224,13 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>) // having any hidden variants means that we need a catch-all arm needs_catch_all_arm |= has_hidden_variants; - let missing_arms = missing_pats + let mut missing_arms = missing_pats .filter(|(_, hidden)| { // filter out hidden patterns because they're handled by the catch-all arm !hidden }) - .map(|(pat, _)| make.match_arm(pat, None, utils::expr_fill_default(ctx.config))); - - let mut arms: Vec<_> = match_arm_list - .arms() - .filter(|arm| { - if matches!(arm.pat(), Some(ast::Pat::WildcardPat(_))) { - if arm.expr().is_none_or(is_empty_expr) { - false - } else { - cov_mark::hit!(add_missing_match_arms_empty_expr); - true - } - } else { - true - } - }) - .map(|arm| arm.reset_indent().indent(IndentLevel(1))) - .collect(); - - let first_new_arm_idx = arms.len(); - arms.extend(missing_arms); + .map(|(pat, _)| make.match_arm(pat, None, utils::expr_fill_default(ctx.config))) + .collect::>(); if needs_catch_all_arm && !has_catch_all_arm { cov_mark::hit!(added_wildcard_pattern); @@ -257,13 +239,11 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>) None, utils::expr_fill_default(ctx.config), ); - arms.push(arm); + missing_arms.push(arm); } - let new_match_arm_list = make.match_arm_list(arms); - // FIXME: Hack for syntax trees not having great support for macros - // Just replace the element that the original range came from + // Just edit the element that the original range came from let old_place = { // Find the original element let file = ctx.sema.parse(arm_list_range.file_id); @@ -280,25 +260,27 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>) }; let mut editor = builder.make_editor(&old_place); - let new_match_arm_list = new_match_arm_list.indent(IndentLevel::from_node(&old_place)); - editor.replace(old_place, new_match_arm_list.syntax()); + let mut arms_edit = ArmsEdit { match_arm_list, place: old_place, last_arm: None }; + + arms_edit.remove_wildcard_arms(ctx, &mut editor); + arms_edit.add_comma_after_last_arm(ctx, &mut editor); + arms_edit.append_arms(&missing_arms, &mut editor); if let Some(cap) = ctx.config.snippet_cap { - if let Some(it) = new_match_arm_list - .arms() - .nth(first_new_arm_idx) + if let Some(it) = missing_arms + .first() .and_then(|arm| arm.syntax().descendants().find_map(ast::WildcardPat::cast)) { editor.add_annotation(it.syntax(), builder.make_placeholder_snippet(cap)); } - for arm in new_match_arm_list.arms().skip(first_new_arm_idx) { + for arm in &missing_arms { if let Some(expr) = arm.expr() { editor.add_annotation(expr.syntax(), builder.make_placeholder_snippet(cap)); } } - if let Some(arm) = new_match_arm_list.arms().skip(first_new_arm_idx).last() { + if let Some(arm) = missing_arms.last() { editor.add_annotation(arm.syntax(), builder.make_tabstop_after(cap)); } } @@ -357,6 +339,96 @@ fn cursor_at_trivial_match_arm_list( None } +struct ArmsEdit { + match_arm_list: MatchArmList, + place: SyntaxNode, + last_arm: Option, +} + +impl ArmsEdit { + fn remove_wildcard_arms(&mut self, ctx: &AssistContext<'_>, editor: &mut SyntaxEditor) { + for arm in self.match_arm_list.arms() { + if !matches!(arm.pat(), Some(Pat::WildcardPat(_))) { + self.last_arm = Some(arm); + continue; + } + if !arm.expr().is_none_or(is_empty_expr) { + cov_mark::hit!(add_missing_match_arms_empty_expr); + self.last_arm = Some(arm); + continue; + } + let Some(range) = self.cover_edit_range(ctx, &arm) else { continue }; + + let prev = match range.start() { + syntax::NodeOrToken::Node(node) => { + node.first_token().and_then(|it| it.prev_token()) + } + syntax::NodeOrToken::Token(tok) => tok.prev_token(), + }; + if let Some(prev) = prev + && prev.kind() == SyntaxKind::WHITESPACE + { + editor.delete(prev); + } + + editor.delete_all(range); + } + } + + fn append_arms(&self, arms: &[ast::MatchArm], editor: &mut SyntaxEditor) { + let Some(mut before) = self.place.last_token() else { + stdx::never!("match arm list not contain any token"); + return; + }; + if let Some(prev) = before.prev_token() + && prev.kind() == SyntaxKind::WHITESPACE + { + before = prev; + } + let open_curly = + !self.place.text().contains_char('\n') || before.kind() == SyntaxKind::WHITESPACE; + let indent = IndentLevel::from_node(&self.place); + let arm_indent = indent + 1; + let indent = make::tokens::whitespace(&format!("\n{indent}")); + let arm_indent = make::tokens::whitespace(&format!("\n{arm_indent}")); + let elements = arms + .iter() + .flat_map(|arm| [arm_indent.clone().into(), arm.syntax().clone().into()]) + .chain(open_curly.then(|| indent.clone().into())) + .collect(); + + if before.kind() == SyntaxKind::WHITESPACE { + editor.replace_with_many(before, elements); + } else { + editor.insert_all(Position::before(before), elements); + } + } + + fn add_comma_after_last_arm(&self, ctx: &AssistContext<'_>, editor: &mut SyntaxEditor) { + if let Some(last_arm) = &self.last_arm + && last_arm.comma_token().is_none() + && last_arm.expr().is_none_or(|it| !it.is_block_like()) + && let Some(range) = self.cover_edit_range(ctx, last_arm) + { + editor.insert(Position::after(range.end()), make::token(syntax::T![,])); + } + } + + fn cover_edit_range( + &self, + ctx: &AssistContext<'_>, + node: &impl AstNode, + ) -> Option> { + let range = ctx.sema.original_range_opt(node.syntax())?; + + if !self.place.text_range().contains_range(range.range) { + return None; + } + + Some(utils::cover_edit_range(&self.place, range.range)) + } +} + fn is_variant_missing(existing_pats: &[Pat], var: &Pat) -> bool { !existing_pats.iter().any(|pat| does_pat_match_variant(pat, var)) } @@ -1734,7 +1806,7 @@ enum Test { fn foo(t: Test) { m!(match t { - Test::A=>(), + Test::A => (), Test::B => ${1:todo!()}, Test::C => ${2:todo!()},$0 }); @@ -2172,6 +2244,35 @@ fn foo(t: E) { ); } + #[test] + fn keep_comments() { + check_assist( + add_missing_match_arms, + r#" +enum E { A, B, C } + +fn foo(t: E) -> i32 { + match $0t { + // variant a + E::A => 2 + // comment on end + } +}"#, + r#" +enum E { A, B, C } + +fn foo(t: E) -> i32 { + match t { + // variant a + E::A => 2, + // comment on end + E::B => ${1:todo!()}, + E::C => ${2:todo!()},$0 + } +}"#, + ); + } + #[test] fn not_applicable_when_match_arm_list_cannot_be_upmapped() { check_assist_not_applicable( From 86062ebeb0031e892ab006f9af73f83baae31d7f Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Mon, 23 Mar 2026 23:07:43 +0800 Subject: [PATCH 19/56] Uses SyntaxFactory to edit arms --- .../src/handlers/add_missing_match_arms.rs | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs index 947766624234..1749db1e61b4 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs @@ -263,8 +263,8 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>) let mut arms_edit = ArmsEdit { match_arm_list, place: old_place, last_arm: None }; arms_edit.remove_wildcard_arms(ctx, &mut editor); - arms_edit.add_comma_after_last_arm(ctx, &mut editor); - arms_edit.append_arms(&missing_arms, &mut editor); + arms_edit.add_comma_after_last_arm(ctx, &make, &mut editor); + arms_edit.append_arms(&missing_arms, &make, &mut editor); if let Some(cap) = ctx.config.snippet_cap { if let Some(it) = missing_arms @@ -375,7 +375,7 @@ fn remove_wildcard_arms(&mut self, ctx: &AssistContext<'_>, editor: &mut SyntaxE } } - fn append_arms(&self, arms: &[ast::MatchArm], editor: &mut SyntaxEditor) { + fn append_arms(&self, arms: &[ast::MatchArm], make: &SyntaxFactory, editor: &mut SyntaxEditor) { let Some(mut before) = self.place.last_token() else { stdx::never!("match arm list not contain any token"); return; @@ -389,8 +389,8 @@ fn append_arms(&self, arms: &[ast::MatchArm], editor: &mut SyntaxEditor) { !self.place.text().contains_char('\n') || before.kind() == SyntaxKind::WHITESPACE; let indent = IndentLevel::from_node(&self.place); let arm_indent = indent + 1; - let indent = make::tokens::whitespace(&format!("\n{indent}")); - let arm_indent = make::tokens::whitespace(&format!("\n{arm_indent}")); + let indent = make.whitespace(&format!("\n{indent}")); + let arm_indent = make.whitespace(&format!("\n{arm_indent}")); let elements = arms .iter() .flat_map(|arm| [arm_indent.clone().into(), arm.syntax().clone().into()]) @@ -404,13 +404,18 @@ fn append_arms(&self, arms: &[ast::MatchArm], editor: &mut SyntaxEditor) { } } - fn add_comma_after_last_arm(&self, ctx: &AssistContext<'_>, editor: &mut SyntaxEditor) { + fn add_comma_after_last_arm( + &self, + ctx: &AssistContext<'_>, + make: &SyntaxFactory, + editor: &mut SyntaxEditor, + ) { if let Some(last_arm) = &self.last_arm && last_arm.comma_token().is_none() && last_arm.expr().is_none_or(|it| !it.is_block_like()) && let Some(range) = self.cover_edit_range(ctx, last_arm) { - editor.insert(Position::after(range.end()), make::token(syntax::T![,])); + editor.insert(Position::after(range.end()), make.token(syntax::T![,])); } } From 55309b01ef27bee22bdadee0d3d09542ddc5ff8b Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Tue, 24 Mar 2026 18:52:16 +0200 Subject: [PATCH 20/56] Don't trigger GC on slow tests, take 2 Hopefully it really works this time. --- src/tools/rust-analyzer/Cargo.lock | 1 + src/tools/rust-analyzer/crates/intern/Cargo.toml | 3 +++ src/tools/rust-analyzer/crates/intern/src/gc.rs | 4 ++++ .../rust-analyzer/crates/rust-analyzer/Cargo.toml | 2 ++ .../crates/rust-analyzer/src/main_loop.rs | 13 ++----------- 5 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock index f31dda4a107b..5370127ddc8e 100644 --- a/src/tools/rust-analyzer/Cargo.lock +++ b/src/tools/rust-analyzer/Cargo.lock @@ -2315,6 +2315,7 @@ dependencies = [ "ide-db", "ide-ssr", "indexmap", + "intern", "itertools 0.14.0", "load-cargo", "lsp-server 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/src/tools/rust-analyzer/crates/intern/Cargo.toml b/src/tools/rust-analyzer/crates/intern/Cargo.toml index ad73c191c047..39320ebd1cfe 100644 --- a/src/tools/rust-analyzer/crates/intern/Cargo.toml +++ b/src/tools/rust-analyzer/crates/intern/Cargo.toml @@ -22,3 +22,6 @@ rayon.workspace = true [lints] workspace = true + +[features] +prevent-gc = [] diff --git a/src/tools/rust-analyzer/crates/intern/src/gc.rs b/src/tools/rust-analyzer/crates/intern/src/gc.rs index 937de26831e2..f4e8f75e7194 100644 --- a/src/tools/rust-analyzer/crates/intern/src/gc.rs +++ b/src/tools/rust-analyzer/crates/intern/src/gc.rs @@ -110,6 +110,10 @@ pub fn add_slice_storage(&mut self) { /// the added storages must form a DAG. /// - [`GcInternedVisit`] and [`GcInternedSliceVisit`] must mark all values reachable from the node. pub unsafe fn collect(mut self) { + if cfg!(feature = "prevent-gc") { + return; + } + let total_nodes = self.storages.iter().map(|storage| storage.len()).sum(); self.alive.clear(); self.alive.reserve(total_nodes); diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml index d1283ca59e8c..beb83a8173a0 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml +++ b/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml @@ -94,6 +94,8 @@ test-utils.workspace = true test-fixture.workspace = true syntax-bridge.workspace = true +intern = { path = "../intern", features = ["prevent-gc"] } + [features] jemalloc = ["jemallocator", "profile/jemalloc"] force-always-assert = ["stdx/force-always-assert"] 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 83edbc722bd5..dad321137fa6 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 @@ -303,15 +303,6 @@ fn next_event( .map(Some) } - fn trigger_garbage_collection(&mut self) { - if cfg!(test) { - // Slow tests run the main loop in multiple threads, but GC isn't thread safe. - return; - } - - self.analysis_host.trigger_garbage_collection(); - } - fn handle_event(&mut self, event: Event) { let loop_start = Instant::now(); let _p = tracing::info_span!("GlobalState::handle_event", event = %event).entered(); @@ -392,7 +383,7 @@ fn handle_event(&mut self, event: Event) { )); } PrimeCachesProgress::End { cancelled } => { - self.trigger_garbage_collection(); + self.analysis_host.trigger_garbage_collection(); self.prime_caches_queue.op_completed(()); if cancelled { self.prime_caches_queue @@ -551,7 +542,7 @@ fn handle_event(&mut self, event: Event) { && self.fmt_pool.handle.is_empty() && current_revision != self.last_gc_revision { - self.trigger_garbage_collection(); + self.analysis_host.trigger_garbage_collection(); self.last_gc_revision = current_revision; } } From c466d3d6516d053196eeccc269f9ee350e2c6568 Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Wed, 25 Mar 2026 11:02:37 +0530 Subject: [PATCH 21/56] add record_expr_field_list constructor method --- .../src/ast/syntax_factory/constructors.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs index 3e5591d37af2..e99060b683e9 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs @@ -1470,6 +1470,22 @@ pub fn record_expr( ast } + pub fn record_expr_field_list( + &self, + fields: impl IntoIterator, + ) -> ast::RecordExprFieldList { + let (fields, input) = iterator_input(fields); + let ast = make::record_expr_field_list(fields).clone_for_update(); + + if let Some(mut mapping) = self.mappings() { + let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); + builder.map_children(input, ast.fields().map(|f| f.syntax().clone())); + builder.finish(&mut mapping); + } + + ast + } + pub fn record_expr_field( &self, name: ast::NameRef, From ffe74d68abe7d779b934cfef2cd517ceb389bca4 Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Tue, 24 Mar 2026 17:53:31 +0800 Subject: [PATCH 22/56] fix: wrap `Result<>` for desugar_try_expr_let_else Example --- ```rust fn test() { let pat: bool = Ok(true)$0?; } ``` **Before this PR** ```rust fn test() { let Ok(pat): Option = Ok(true) else { return Err(todo!()); }; } ``` **After this PR** ```rust fn test() { let Ok(pat): Result = Ok(true) else { return Err(todo!()); }; } ``` --- .../src/handlers/desugar_try_expr.rs | 26 ++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/desugar_try_expr.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/desugar_try_expr.rs index e43cf0bc8aae..865dc862215f 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/desugar_try_expr.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/desugar_try_expr.rs @@ -116,7 +116,10 @@ pub(crate) fn desugar_try_expr(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op let fill_expr = || crate::utils::expr_fill_default(ctx.config); let new_let_stmt = make.let_else_stmt( try_enum.happy_pattern(pat), - let_stmt.ty().map(|ty| make.ty_option(ty).into()), + let_stmt.ty().map(|ty| match try_enum { + TryEnum::Option => make.ty_option(ty).into(), + TryEnum::Result => make.ty_result(ty, make.ty_infer().into()).into(), + }), expr, make.block_expr( iter::once( @@ -264,6 +267,27 @@ fn test() { let Some(pat): Option = Some(true) else { return None; }; +} + "#, + "Replace try expression with let else", + ); + } + + #[test] + fn test_desugar_try_expr_result_let_else_with_type() { + check_assist_by_label( + desugar_try_expr, + r#" +//- minicore: try, result +fn test() { + let pat: bool = Ok(true)$0?; +} + "#, + r#" +fn test() { + let Ok(pat): Result = Ok(true) else { + return Err(todo!()); + }; } "#, "Replace try expression with let else", From 7553d6c7792e44b91101dd55203098331cb92f50 Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Wed, 25 Mar 2026 11:34:55 +0530 Subject: [PATCH 23/56] fix record_expr_field --- .../syntax/src/ast/syntax_factory/constructors.rs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs index e99060b683e9..fa81dfad1f7f 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs @@ -1496,7 +1496,20 @@ pub fn record_expr_field( if let Some(mut mapping) = self.mappings() { let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); - builder.map_node(name.syntax().clone(), ast.name_ref().unwrap().syntax().clone()); + if let Some(ast_name_ref) = ast.name_ref() { + // NameRef is a direct child + builder.map_node(name.syntax().clone(), ast_name_ref.syntax().clone()); + } else { + // NameRef is nested inside PathExpr > Path > PathSegment. + // map_node requires the output to be a direct child of the builder's parent, so + // we need a separate builder scoped to PathSegment. + let ast::Expr::PathExpr(path_expr) = ast.expr().unwrap() else { unreachable!() }; + let path_segment = path_expr.path().unwrap().segment().unwrap(); + let inner_name_ref = path_segment.name_ref().unwrap(); + let mut inner_builder = SyntaxMappingBuilder::new(path_segment.syntax().clone()); + inner_builder.map_node(name.syntax().clone(), inner_name_ref.syntax().clone()); + inner_builder.finish(&mut mapping); + } if let Some(expr) = expr { builder.map_node(expr.syntax().clone(), ast.expr().unwrap().syntax().clone()); } From bd398d3e110022e2d915511f718eb85606e4a6ef Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Wed, 25 Mar 2026 11:35:22 +0530 Subject: [PATCH 24/56] migrate generate new to use SyntaxFactory --- .../ide-assists/src/handlers/generate_new.rs | 84 ++++++++++--------- .../crates/ide-assists/src/utils.rs | 3 +- 2 files changed, 46 insertions(+), 41 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_new.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_new.rs index 793211a27b47..301d13c09584 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_new.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_new.rs @@ -3,7 +3,10 @@ use_trivial_constructor::use_trivial_constructor, }; use syntax::{ - ast::{self, AstNode, HasName, HasVisibility, StructKind, edit::AstNodeEdit, make}, + ast::{ + self, AstNode, HasName, HasVisibility, StructKind, edit::AstNodeEdit, + syntax_factory::SyntaxFactory, + }, syntax_editor::Position, }; @@ -36,6 +39,7 @@ pub(crate) fn generate_new(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { let strukt = ctx.find_node_at_offset::()?; + let make = SyntaxFactory::without_mappings(); let field_list = match strukt.kind() { StructKind::Record(named) => { named.fields().filter_map(|f| Some((f.name()?, f.ty()?))).collect::>() @@ -55,7 +59,7 @@ pub(crate) fn generate_new(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option Some(name) => name, None => name_generator.suggest_name(&format!("_{i}")), }; - Some((make::name(name.as_str()), f.ty()?)) + Some((make.name(name.as_str()), f.ty()?)) }) .collect::>() } @@ -70,6 +74,7 @@ pub(crate) fn generate_new(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option let target = strukt.syntax().text_range(); acc.add(AssistId::generate("generate_new"), "Generate `new`", target, |builder| { + let make = SyntaxFactory::with_mappings(); let trivial_constructors = field_list .iter() .map(|(name, ty)| { @@ -95,63 +100,63 @@ pub(crate) fn generate_new(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option edition, )?; - Some((make::name_ref(&name.text()), Some(expr))) + Some((make.name_ref(&name.text()), Some(expr))) }) .collect::>(); let params = field_list.iter().enumerate().filter_map(|(i, (name, ty))| { if trivial_constructors[i].is_none() { - Some(make::param(make::ident_pat(false, false, name.clone()).into(), ty.clone())) + Some(make.param(make.ident_pat(false, false, name.clone()).into(), ty.clone())) } else { None } }); - let params = make::param_list(None, params); + let params = make.param_list(None, params); let fields = field_list.iter().enumerate().map(|(i, (name, _))| { if let Some(constructor) = trivial_constructors[i].clone() { constructor } else { - (make::name_ref(&name.text()), None) + (make.name_ref(&name.text()), None) } }); let tail_expr: ast::Expr = match strukt.kind() { StructKind::Record(_) => { - let fields = fields.map(|(name, expr)| make::record_expr_field(name, expr)); - let fields = make::record_expr_field_list(fields); - make::record_expr(make::ext::ident_path("Self"), fields).into() + let fields = fields.map(|(name, expr)| make.record_expr_field(name, expr)); + let fields = make.record_expr_field_list(fields); + make.record_expr(make.ident_path("Self"), fields).into() } StructKind::Tuple(_) => { let args = fields.map(|(arg, expr)| { - let arg = || make::expr_path(make::path_unqualified(make::path_segment(arg))); + let arg = || make.expr_path(make.path_unqualified(make.path_segment(arg))); expr.unwrap_or_else(arg) }); - let arg_list = make::arg_list(args); - make::expr_call(make::expr_path(make::ext::ident_path("Self")), arg_list).into() + let arg_list = make.arg_list(args); + make.expr_call(make.expr_path(make.ident_path("Self")), arg_list).into() } StructKind::Unit => unreachable!(), }; - let body = make::block_expr(None, tail_expr.into()); + let body = make.block_expr(None, tail_expr.into()); - let ret_type = make::ret_type(make::ty_path(make::ext::ident_path("Self"))); + let ret_type = make.ret_type(make.ty_path(make.ident_path("Self")).into()); - let fn_ = make::fn_( - None, - strukt.visibility(), - make::name("new"), - None, - None, - params, - body, - Some(ret_type), - false, - false, - false, - false, - ) - .clone_for_update() - .indent(1.into()); + let fn_ = make + .fn_( + [], + strukt.visibility(), + make.name("new"), + None, + None, + params, + body, + Some(ret_type), + false, + false, + false, + false, + ) + .indent(1.into()); let mut editor = builder.make_editor(strukt.syntax()); @@ -164,32 +169,30 @@ pub(crate) fn generate_new(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option editor.insert_all( Position::after(l_curly), vec![ - make::tokens::whitespace(&format!("\n{}", impl_def.indent_level() + 1)) - .into(), + make.whitespace(&format!("\n{}", impl_def.indent_level() + 1)).into(), fn_.syntax().clone().into(), - make::tokens::whitespace("\n").into(), + make.whitespace("\n").into(), ], ); fn_.syntax().clone() } else { - let items = vec![ast::AssocItem::Fn(fn_)]; - let list = make::assoc_item_list(Some(items)); + let list = make.assoc_item_list([ast::AssocItem::Fn(fn_)]); editor.insert(Position::after(impl_def.syntax()), list.syntax()); list.syntax().clone() } } else { // Generate a new impl to add the method to let indent_level = strukt.indent_level(); - let body = vec![ast::AssocItem::Fn(fn_)]; - let list = make::assoc_item_list(Some(body)); - let impl_def = generate_impl_with_item(&ast::Adt::Struct(strukt.clone()), Some(list)) - .indent(strukt.indent_level()); + let list = make.assoc_item_list([ast::AssocItem::Fn(fn_)]); + let impl_def = + generate_impl_with_item(&make, &ast::Adt::Struct(strukt.clone()), Some(list)) + .indent(strukt.indent_level()); // Insert it after the adt editor.insert_all( Position::after(strukt.syntax()), vec![ - make::tokens::whitespace(&format!("\n\n{indent_level}")).into(), + make.whitespace(&format!("\n\n{indent_level}")).into(), impl_def.syntax().clone().into(), ], ); @@ -233,6 +236,7 @@ pub(crate) fn generate_new(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option } } + editor.add_mappings(make.finish_with_mappings()); builder.add_file_edits(ctx.vfs_file_id(), editor); }) } 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 a85a89efb4a2..4c454fe224c3 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs @@ -733,10 +733,11 @@ fn generate_impl_text_inner( /// Generates the corresponding `impl Type {}` including type and lifetime /// parameters. pub(crate) fn generate_impl_with_item( + make: &SyntaxFactory, adt: &ast::Adt, body: Option, ) -> ast::Impl { - generate_impl_inner(false, adt, None, true, body) + generate_impl_inner_with_factory(make, false, adt, None, true, body) } pub(crate) fn generate_impl(adt: &ast::Adt) -> ast::Impl { From 26421f2802eb425393c7cb0521236f75629fd9b9 Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Wed, 25 Mar 2026 13:17:03 +0530 Subject: [PATCH 25/56] migrate generate_impl to use SyntaxFactory instead of make --- .../ide-assists/src/handlers/generate_impl.rs | 41 ++++++++++++------- .../crates/ide-assists/src/utils.rs | 12 +++++- 2 files changed, 36 insertions(+), 17 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_impl.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_impl.rs index bbd42481ef0f..2d1235792dcf 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_impl.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_impl.rs @@ -1,15 +1,21 @@ use syntax::{ - ast::{self, AstNode, HasGenericParams, HasName, edit::AstNodeEdit, make}, + ast::{ + self, AstNode, HasGenericParams, HasName, edit::AstNodeEdit, syntax_factory::SyntaxFactory, + }, syntax_editor::{Position, SyntaxEditor}, }; use crate::{ AssistContext, AssistId, Assists, - utils::{self, DefaultMethods, IgnoreAssocItems}, + utils::{ + self, DefaultMethods, IgnoreAssocItems, generate_impl_with_factory, + generate_trait_impl_intransitive, + }, }; fn insert_impl( editor: &mut SyntaxEditor, + make: &SyntaxFactory, impl_: &ast::Impl, nominal: &impl AstNodeEdit, ) -> ast::Impl { @@ -20,7 +26,7 @@ fn insert_impl( Position::after(nominal.syntax()), vec![ // Add a blank line after the ADT, and indentation for the impl to match the ADT - make::tokens::whitespace(&format!("\n\n{indent}")).into(), + make.whitespace(&format!("\n\n{indent}")).into(), impl_.syntax().clone().into(), ], ); @@ -59,12 +65,13 @@ pub(crate) fn generate_impl(acc: &mut Assists, ctx: &AssistContext<'_>) -> Optio format!("Generate impl for `{name}`"), target, |edit| { + let make = SyntaxFactory::with_mappings(); // Generate the impl - let impl_ = utils::generate_impl(&nominal); + let impl_ = generate_impl_with_factory(&make, &nominal); let mut editor = edit.make_editor(nominal.syntax()); - let impl_ = insert_impl(&mut editor, &impl_, &nominal); + let impl_ = insert_impl(&mut editor, &make, &impl_, &nominal); // Add a tabstop after the left curly brace if let Some(cap) = ctx.config.snippet_cap && let Some(l_curly) = impl_.assoc_item_list().and_then(|it| it.l_curly_token()) @@ -73,6 +80,7 @@ pub(crate) fn generate_impl(acc: &mut Assists, ctx: &AssistContext<'_>) -> Optio editor.add_annotation(l_curly, tabstop); } + editor.add_mappings(make.finish_with_mappings()); edit.add_file_edits(ctx.vfs_file_id(), editor); }, ) @@ -109,12 +117,13 @@ pub(crate) fn generate_trait_impl(acc: &mut Assists, ctx: &AssistContext<'_>) -> format!("Generate trait impl for `{name}`"), target, |edit| { + let make = SyntaxFactory::with_mappings(); // Generate the impl - let impl_ = utils::generate_trait_impl_intransitive(&nominal, make::ty_placeholder()); + let impl_ = generate_trait_impl_intransitive(&make, &nominal, make.ty_placeholder()); let mut editor = edit.make_editor(nominal.syntax()); - let impl_ = insert_impl(&mut editor, &impl_, &nominal); + let impl_ = insert_impl(&mut editor, &make, &impl_, &nominal); // Make the trait type a placeholder snippet if let Some(cap) = ctx.config.snippet_cap { if let Some(trait_) = impl_.trait_() { @@ -128,6 +137,7 @@ pub(crate) fn generate_trait_impl(acc: &mut Assists, ctx: &AssistContext<'_>) -> } } + editor.add_mappings(make.finish_with_mappings()); edit.add_file_edits(ctx.vfs_file_id(), editor); }, ) @@ -166,9 +176,10 @@ pub(crate) fn generate_impl_trait(acc: &mut Assists, ctx: &AssistContext<'_>) -> format!("Generate `{name}` impl for type"), target, |edit| { + let make = SyntaxFactory::with_mappings(); let mut editor = edit.make_editor(trait_.syntax()); - let holder_arg = ast::GenericArg::TypeArg(make::type_arg(make::ty_placeholder())); + let holder_arg = ast::GenericArg::TypeArg(make.type_arg(make.ty_placeholder())); let missing_items = utils::filter_assoc_items( &ctx.sema, &hir_trait.items(ctx.db()), @@ -177,11 +188,11 @@ pub(crate) fn generate_impl_trait(acc: &mut Assists, ctx: &AssistContext<'_>) -> ); let trait_gen_args = trait_.generic_param_list().map(|list| { - make::generic_arg_list(list.generic_params().map(|_| holder_arg.clone())) + make.generic_arg_list(list.generic_params().map(|_| holder_arg.clone()), false) }); let make_impl_ = |body| { - make::impl_trait( + make.impl_trait( None, trait_.unsafe_token().is_some(), None, @@ -189,13 +200,12 @@ pub(crate) fn generate_impl_trait(acc: &mut Assists, ctx: &AssistContext<'_>) -> None, None, false, - make::ty(&name.text()), - make::ty_placeholder(), + make.ty(&name.text()), + make.ty_placeholder(), None, None, body, ) - .clone_for_update() }; let impl_ = if missing_items.is_empty() { @@ -210,11 +220,12 @@ pub(crate) fn generate_impl_trait(acc: &mut Assists, ctx: &AssistContext<'_>) -> &impl_, &target_scope, ); - let assoc_item_list = make::assoc_item_list(Some(assoc_items)); + let assoc_item_list = make.assoc_item_list(assoc_items); make_impl_(Some(assoc_item_list)) }; - let impl_ = insert_impl(&mut editor, &impl_, &trait_); + let impl_ = insert_impl(&mut editor, &make, &impl_, &trait_); + editor.add_mappings(make.finish_with_mappings()); if let Some(cap) = ctx.config.snippet_cap { if let Some(generics) = impl_.trait_().and_then(|it| it.generic_arg_list()) { 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 a85a89efb4a2..7eec38af7987 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs @@ -739,6 +739,10 @@ pub(crate) fn generate_impl_with_item( generate_impl_inner(false, adt, None, true, body) } +pub(crate) fn generate_impl_with_factory(make: &SyntaxFactory, adt: &ast::Adt) -> ast::Impl { + generate_impl_inner_with_factory(make, false, adt, None, true, None) +} + pub(crate) fn generate_impl(adt: &ast::Adt) -> ast::Impl { generate_impl_inner(false, adt, None, true, None) } @@ -760,8 +764,12 @@ pub(crate) fn generate_trait_impl( /// and lifetime parameters, with `impl`'s generic parameters' bounds kept as-is. /// /// This is useful for traits like `From`, since `impl From for U` doesn't require `T: From`. -pub(crate) fn generate_trait_impl_intransitive(adt: &ast::Adt, trait_: ast::Type) -> ast::Impl { - generate_impl_inner(false, adt, Some(trait_), false, None) +pub(crate) fn generate_trait_impl_intransitive( + make: &SyntaxFactory, + adt: &ast::Adt, + trait_: ast::Type, +) -> ast::Impl { + generate_impl_inner_with_factory(make, false, adt, Some(trait_), false, None) } fn generate_impl_inner( From c516070954696b0d731823164ac3053a98d1c7ee Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Wed, 25 Mar 2026 13:32:11 +0530 Subject: [PATCH 26/56] migrate needs_parens_in_call to use SyntaxFactory --- src/tools/rust-analyzer/crates/ide-assists/src/utils.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) 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 7eec38af7987..cfbb5a17eb17 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs @@ -103,11 +103,11 @@ pub(crate) fn wrap_paren(expr: ast::Expr, make: &SyntaxFactory, prec: ExprPreced } pub(crate) fn wrap_paren_in_call(expr: ast::Expr, make: &SyntaxFactory) -> ast::Expr { - if needs_parens_in_call(&expr) { make.expr_paren(expr).into() } else { expr } + if needs_parens_in_call(make, &expr) { make.expr_paren(expr).into() } else { expr } } -fn needs_parens_in_call(param: &ast::Expr) -> bool { - let call = make::expr_call(make::ext::expr_unit(), make::arg_list(Vec::new())); +fn needs_parens_in_call(make: &SyntaxFactory, param: &ast::Expr) -> bool { + let call = make.expr_call(make.expr_unit(), make.arg_list(Vec::new())); let callable = call.expr().expect("invalid make call"); param.needs_parens_in_place_of(call.syntax(), callable.syntax()) } From 307d7152bc524539b465f9b337a2e036454102df Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Wed, 25 Mar 2026 17:16:37 +0530 Subject: [PATCH 27/56] replace remove-generate-trail-impl-text-intransitive with generate_trait_impl_intransitive_with_item --- .../crates/ide-assists/src/utils.rs | 32 ++++++------------- 1 file changed, 9 insertions(+), 23 deletions(-) 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 cf1c66ab5e74..96e1bbdc7ea9 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs @@ -630,29 +630,6 @@ pub(crate) fn generate_impl_text(adt: &ast::Adt, code: &str) -> String { generate_impl_text_inner(adt, None, true, code) } -/// Generates the surrounding `impl for Type { }` including type -/// and lifetime parameters, with `` appended to `impl`'s generic parameters' bounds. -/// -/// This is useful for traits like `PartialEq`, since `impl PartialEq for U` often requires `T: PartialEq`. -// FIXME: migrate remaining uses to `generate_trait_impl` -#[allow(dead_code)] -pub(crate) fn generate_trait_impl_text(adt: &ast::Adt, trait_text: &str, code: &str) -> String { - generate_impl_text_inner(adt, Some(trait_text), true, code) -} - -/// Generates the surrounding `impl for Type { }` including type -/// and lifetime parameters, with `impl`'s generic parameters' bounds kept as-is. -/// -/// This is useful for traits like `From`, since `impl From for U` doesn't require `T: From`. -// FIXME: migrate remaining uses to `generate_trait_impl_intransitive` -pub(crate) fn generate_trait_impl_text_intransitive( - adt: &ast::Adt, - trait_text: &str, - code: &str, -) -> String { - generate_impl_text_inner(adt, Some(trait_text), false, code) -} - fn generate_impl_text_inner( adt: &ast::Adt, trait_text: Option<&str>, @@ -773,6 +750,15 @@ pub(crate) fn generate_trait_impl_intransitive( generate_impl_inner_with_factory(make, false, adt, Some(trait_), false, None) } +pub(crate) fn generate_trait_impl_intransitive_with_item( + make: &SyntaxFactory, + adt: &ast::Adt, + trait_: ast::Type, + body: ast::AssocItemList, +) -> ast::Impl { + generate_impl_inner_with_factory(make, false, adt, Some(trait_), false, Some(body)) +} + fn generate_impl_inner( is_unsafe: bool, adt: &ast::Adt, From 4b978017b75c550c3a8113380e16516f4146c439 Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Wed, 25 Mar 2026 17:17:30 +0530 Subject: [PATCH 28/56] migrate generate_deref to SyntaxEditor and SyntaxFactory and remove usage of remove-generate-trail-impl-text-intransitive --- .../src/handlers/generate_deref.rs | 124 +++++++++++++----- 1 file changed, 93 insertions(+), 31 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_deref.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_deref.rs index 494c87e6d136..f8974e1e7eca 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_deref.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_deref.rs @@ -1,16 +1,15 @@ -use std::fmt::Display; - use hir::{ModPath, ModuleDef}; -use ide_db::{RootDatabase, famous_defs::FamousDefs}; +use ide_db::{FileId, RootDatabase, famous_defs::FamousDefs}; use syntax::{ - AstNode, Edition, SyntaxNode, - ast::{self, HasName}, + Edition, + ast::{self, AstNode, HasName, edit::AstNodeEdit, syntax_factory::SyntaxFactory}, + syntax_editor::Position, }; use crate::{ AssistId, assist_context::{AssistContext, Assists, SourceChangeBuilder}, - utils::generate_trait_impl_text_intransitive, + utils::generate_trait_impl_intransitive_with_item, }; // Assist: generate_deref @@ -64,6 +63,7 @@ fn generate_record_deref(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<( let field_type = field.ty()?; let field_name = field.name()?; let target = field.syntax().text_range(); + let file_id = ctx.vfs_file_id(); acc.add( AssistId::generate("generate_deref"), format!("Generate `{deref_type_to_generate:?}` impl using `{field_name}`"), @@ -72,9 +72,10 @@ fn generate_record_deref(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<( generate_edit( ctx.db(), edit, + file_id, strukt, - field_type.syntax(), - field_name.syntax(), + field_type, + &field_name.to_string(), deref_type_to_generate, trait_path, module.krate(ctx.db()).edition(ctx.db()), @@ -105,6 +106,7 @@ fn generate_tuple_deref(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<() let field_type = field.ty()?; let target = field.syntax().text_range(); + let file_id = ctx.vfs_file_id(); acc.add( AssistId::generate("generate_deref"), format!("Generate `{deref_type_to_generate:?}` impl using `{field}`"), @@ -113,9 +115,10 @@ fn generate_tuple_deref(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<() generate_edit( ctx.db(), edit, + file_id, strukt, - field_type.syntax(), - field_list_index, + field_type, + &field_list_index.to_string(), deref_type_to_generate, trait_path, module.krate(ctx.db()).edition(ctx.db()), @@ -127,35 +130,94 @@ fn generate_tuple_deref(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<() fn generate_edit( db: &RootDatabase, edit: &mut SourceChangeBuilder, + file_id: FileId, strukt: ast::Struct, - field_type_syntax: &SyntaxNode, - field_name: impl Display, + field_type: ast::Type, + field_name: &str, deref_type: DerefType, trait_path: ModPath, edition: Edition, ) { - let start_offset = strukt.syntax().text_range().end(); - let impl_code = match deref_type { - DerefType::Deref => format!( - r#" type Target = {field_type_syntax}; + let make = SyntaxFactory::with_mappings(); + let strukt_adt = ast::Adt::Struct(strukt.clone()); + let trait_ty = make.ty(&trait_path.display(db, edition).to_string()); - fn deref(&self) -> &Self::Target {{ - &self.{field_name} - }}"#, - ), - DerefType::DerefMut => format!( - r#" fn deref_mut(&mut self) -> &mut Self::Target {{ - &mut self.{field_name} - }}"#, - ), + let assoc_items: Vec = match deref_type { + DerefType::Deref => { + let target_alias = make.ty_alias( + [], + "Target", + None, + None, + None, + Some((field_type, None)), + ); + let ret_ty = + make.ty_ref(make.ty_path(make.path_from_text("Self::Target")).into(), false); + let field_expr = + make.expr_field(make.expr_path(make.ident_path("self")), field_name); + let body = + make.block_expr([], Some(make.expr_ref(field_expr.into(), false))); + let fn_ = make + .fn_( + [], + None, + make.name("deref"), + None, + None, + make.param_list(Some(make.self_param()), []), + body, + Some(make.ret_type(ret_ty)), + false, + false, + false, + false, + ) + .indent(1.into()); + vec![ + ast::AssocItem::TypeAlias(target_alias), + ast::AssocItem::Fn(fn_), + ] + } + DerefType::DerefMut => { + let ret_ty = + make.ty_ref(make.ty_path(make.path_from_text("Self::Target")).into(), true); + let field_expr = + make.expr_field(make.expr_path(make.ident_path("self")), field_name); + let body = + make.block_expr([], Some(make.expr_ref(field_expr.into(), true))); + let fn_ = make + .fn_( + [], + None, + make.name("deref_mut"), + None, + None, + make.param_list(Some(make.mut_self_param()), []), + body, + Some(make.ret_type(ret_ty)), + false, + false, + false, + false, + ) + .indent(1.into()); + vec![ast::AssocItem::Fn(fn_)] + } }; - let strukt_adt = ast::Adt::Struct(strukt); - let deref_impl = generate_trait_impl_text_intransitive( - &strukt_adt, - &trait_path.display(db, edition).to_string(), - &impl_code, + + let body = make.assoc_item_list(assoc_items); + let indent = strukt.indent_level(); + let impl_ = generate_trait_impl_intransitive_with_item(&make, &strukt_adt, trait_ty, body) + .indent(indent); + + let mut editor = edit.make_editor(strukt.syntax()); + editor.insert_all( + Position::after(strukt.syntax()), + vec![make.whitespace(&format!("\n\n{indent}")).into(), impl_.syntax().clone().into()], ); - edit.insert(start_offset, deref_impl); + editor.add_mappings(make.finish_with_mappings()); + edit.add_file_edits(file_id, editor); } fn existing_deref_impl( From 37153280f07ccc1df9ba109bbfaf948897578b19 Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Wed, 25 Mar 2026 17:17:57 +0530 Subject: [PATCH 29/56] migrate generate_from_impl_for_enum to SyntaxEditor and SyntaxFactory and remove usage of remove-generate-trail-impl-text-intransitive --- .../src/handlers/generate_deref.rs | 27 ++---- .../handlers/generate_from_impl_for_enum.rs | 82 +++++++++++++------ 2 files changed, 65 insertions(+), 44 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_deref.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_deref.rs index f8974e1e7eca..5534dc1cd304 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_deref.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_deref.rs @@ -144,20 +144,12 @@ fn generate_edit( let assoc_items: Vec = match deref_type { DerefType::Deref => { - let target_alias = make.ty_alias( - [], - "Target", - None, - None, - None, - Some((field_type, None)), - ); + let target_alias = + make.ty_alias([], "Target", None, None, None, Some((field_type, None))); let ret_ty = make.ty_ref(make.ty_path(make.path_from_text("Self::Target")).into(), false); - let field_expr = - make.expr_field(make.expr_path(make.ident_path("self")), field_name); - let body = - make.block_expr([], Some(make.expr_ref(field_expr.into(), false))); + let field_expr = make.expr_field(make.expr_path(make.ident_path("self")), field_name); + let body = make.block_expr([], Some(make.expr_ref(field_expr.into(), false))); let fn_ = make .fn_( [], @@ -174,18 +166,13 @@ fn generate_edit( false, ) .indent(1.into()); - vec![ - ast::AssocItem::TypeAlias(target_alias), - ast::AssocItem::Fn(fn_), - ] + vec![ast::AssocItem::TypeAlias(target_alias), ast::AssocItem::Fn(fn_)] } DerefType::DerefMut => { let ret_ty = make.ty_ref(make.ty_path(make.path_from_text("Self::Target")).into(), true); - let field_expr = - make.expr_field(make.expr_path(make.ident_path("self")), field_name); - let body = - make.block_expr([], Some(make.expr_ref(field_expr.into(), true))); + let field_expr = make.expr_field(make.expr_path(make.ident_path("self")), field_name); + let body = make.block_expr([], Some(make.expr_ref(field_expr.into(), true))); let fn_ = make .fn_( [], diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_from_impl_for_enum.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_from_impl_for_enum.rs index 24f271ded80b..1adb3f4fe49a 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_from_impl_for_enum.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_from_impl_for_enum.rs @@ -1,10 +1,11 @@ use hir::next_solver::{DbInterner, TypingMode}; use ide_db::{RootDatabase, famous_defs::FamousDefs}; -use syntax::ast::{self, AstNode, HasName}; +use syntax::ast::{self, AstNode, HasName, edit::AstNodeEdit, syntax_factory::SyntaxFactory}; +use syntax::syntax_editor::Position; use crate::{ AssistContext, AssistId, Assists, - utils::{generate_trait_impl_text_intransitive, is_selected}, + utils::{generate_trait_impl_intransitive_with_item, is_selected}, }; // Assist: generate_from_impl_for_enum @@ -33,39 +34,72 @@ pub(crate) fn generate_from_impl_for_enum( let variants = selected_variants(ctx, &variant)?; let target = variant.syntax().text_range(); + let file_id = ctx.vfs_file_id(); acc.add( AssistId::generate("generate_from_impl_for_enum"), "Generate `From` impl for this enum variant(s)", target, |edit| { - let start_offset = variant.parent_enum().syntax().text_range().end(); - let from_impl = variants - .into_iter() - .map(|variant_info| { - let from_trait = format!("From<{}>", variant_info.ty); - let impl_code = generate_impl_code(variant_info); - generate_trait_impl_text_intransitive(&adt, &from_trait, &impl_code) - }) - .collect::(); - edit.insert(start_offset, from_impl); + let make = SyntaxFactory::with_mappings(); + let indent = adt.indent_level(); + let mut elements = Vec::new(); + + for variant_info in variants { + let impl_ = build_from_impl(&make, &adt, variant_info).indent(indent); + elements.push(make.whitespace(&format!("\n\n{indent}")).into()); + elements.push(impl_.syntax().clone().into()); + } + + let mut editor = edit.make_editor(adt.syntax()); + editor.insert_all(Position::after(adt.syntax()), elements); + editor.add_mappings(make.finish_with_mappings()); + edit.add_file_edits(file_id, editor); }, ) } -fn generate_impl_code(VariantInfo { name, field_name, ty }: VariantInfo) -> String { - if let Some(field) = field_name { - format!( - r#" fn from({field}: {ty}) -> Self {{ - Self::{name} {{ {field} }} - }}"# - ) +fn build_from_impl(make: &SyntaxFactory, adt: &ast::Adt, variant_info: VariantInfo) -> ast::Impl { + let VariantInfo { name, field_name, ty } = variant_info; + let trait_ty = make.ty(&format!("From<{ty}>")); + let ret_ty = make.ret_type(make.ty_path(make.ident_path("Self")).into()); + + let (params, body_expr) = if let Some(field) = field_name { + let field_str = field.to_string(); + let param = make.param(make.ident_pat(false, false, make.name(&field_str)).into(), ty); + let field_item = make.record_expr_field(make.name_ref(&field_str), None); + let record = make.record_expr( + make.path_from_text(&format!("Self::{name}")), + make.record_expr_field_list([field_item]), + ); + (make.param_list(None, [param]), ast::Expr::from(record)) } else { - format!( - r#" fn from(v: {ty}) -> Self {{ - Self::{name}(v) - }}"# + let param = make.param(make.ident_pat(false, false, make.name("v")).into(), ty); + let call = make.expr_call( + make.expr_path(make.path_from_text(&format!("Self::{name}"))), + make.arg_list([make.expr_path(make.ident_path("v"))]), + ); + (make.param_list(None, [param]), ast::Expr::from(call)) + }; + + let from_fn = make + .fn_( + [], + None, + make.name("from"), + None, + None, + params, + make.block_expr([], Some(body_expr)), + Some(ret_ty), + false, + false, + false, + false, ) - } + .indent(1.into()); + + let body = make.assoc_item_list([ast::AssocItem::Fn(from_fn)]); + generate_trait_impl_intransitive_with_item(make, adt, trait_ty, body) } struct VariantInfo { From c03b20d198b910394b653f950618cb283fce08bc Mon Sep 17 00:00:00 2001 From: Shoyu Vanilla Date: Sat, 24 Jan 2026 01:03:27 +0900 Subject: [PATCH 30/56] fix: Turn back `TyLoweringContext.store` to self after lowering parent defaults --- .../rust-analyzer/crates/hir-ty/src/lower.rs | 4 +++- .../src/handlers/missing_lifetime.rs | 16 ++++++++++++++++ 2 files changed, 19 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 45500cfd2213..c0bd8975711f 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs @@ -2411,10 +2411,11 @@ pub(crate) fn generic_defaults_with_diagnostics_query( } let resolver = def.resolver(db); + let store_for_self = generic_params.store(); let mut ctx = TyLoweringContext::new( db, &resolver, - generic_params.store(), + store_for_self, def, LifetimeElisionKind::AnonymousReportError, ) @@ -2432,6 +2433,7 @@ pub(crate) fn generic_defaults_with_diagnostics_query( }) .collect::>(); ctx.diagnostics.clear(); // Don't include diagnostics from the parent. + ctx.store = store_for_self; defaults.extend(generic_params.iter_self().map(|(_id, p)| { let (result, has_default) = handle_generic_param(&mut ctx, idx, p); has_any_default |= has_default; diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_lifetime.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_lifetime.rs index 5cb710b66b5f..b10cdaa14ee6 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_lifetime.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_lifetime.rs @@ -115,4 +115,20 @@ struct A<'a, T> { "#, ); } + + // FIXME: Ideally, should emit generic default forbidden as well + #[test] + fn regression_16280() { + check_diagnostics( + r#" +trait Traitor<'a, const M: Traitor = Traitor> { + fn crash(&self) -> Traitor { + // ^^^^^^^ error: missing lifetime specifier + // ^^^^^^^ error: missing lifetime specifier + Traitor + } +} +"#, + ); + } } From ed974ae96d068c6a5be39bd2aba378b320736160 Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Wed, 25 Mar 2026 22:39:42 +0800 Subject: [PATCH 31/56] internal: rename IndentLevel::single to zero --- .../src/handlers/extract_struct_from_enum_variant.rs | 2 +- src/tools/rust-analyzer/crates/ide-assists/src/utils.rs | 2 +- src/tools/rust-analyzer/crates/syntax/src/ast/edit.rs | 2 +- .../rust-analyzer/crates/syntax/src/ast/edit_in_place.rs | 2 +- .../rust-analyzer/crates/syntax/src/syntax_editor/edits.rs | 4 ++-- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs index 386652a42292..e00a2949f2b8 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs @@ -290,7 +290,7 @@ fn create_struct_def( field_list.clone().into() } }; - let field_list = field_list.indent(IndentLevel::single()); + let field_list = field_list.indent(IndentLevel::zero()); let strukt = make::struct_(enum_vis, name, generics, field_list).clone_for_update(); 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 a85a89efb4a2..b976a172277d 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs @@ -324,7 +324,7 @@ pub fn add_trait_assoc_items_to_impl_with_factory( ExprFillDefaultMode::Underscore => make.expr_underscore().into(), }; let new_body = make.block_expr(None::, Some(fill_expr)); - let new_body = AstNodeEdit::indent(&new_body, IndentLevel::single()); + let new_body = AstNodeEdit::indent(&new_body, IndentLevel::zero()); let mut fn_editor = SyntaxEditor::new(fn_.syntax().clone()); fn_.replace_or_insert_body(&mut fn_editor, new_body); let new_fn_ = fn_editor.finish().new_root().clone(); 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 194d06900a48..b706d7f722f4 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/edit.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/edit.rs @@ -50,7 +50,7 @@ fn add_assign(&mut self, rhs: u8) { } impl IndentLevel { - pub fn single() -> IndentLevel { + pub fn zero() -> IndentLevel { IndentLevel(0) } pub fn is_zero(&self) -> bool { diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs index 2b7dc5cd76ab..7f59ae421382 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs @@ -591,7 +591,7 @@ pub fn add_item(&self, item: ast::AssocItem) { normalize_ws_between_braces(self.syntax()); (IndentLevel::from_token(&l_curly) + 1, ted::Position::after(&l_curly), "\n") } - None => (IndentLevel::single(), ted::Position::last_child_of(self.syntax()), "\n"), + None => (IndentLevel::zero(), ted::Position::last_child_of(self.syntax()), "\n"), }, }; let elements: Vec = vec![ diff --git a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edits.rs b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edits.rs index ad08928923be..44f0a8038eca 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edits.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edits.rs @@ -210,7 +210,7 @@ pub fn add_items(&self, editor: &mut SyntaxEditor, items: Vec) { normalize_ws_between_braces(editor, self.syntax()); (IndentLevel::from_token(&l_curly) + 1, Position::after(&l_curly), "\n") } - None => (IndentLevel::single(), Position::last_child_of(self.syntax()), "\n"), + None => (IndentLevel::zero(), Position::last_child_of(self.syntax()), "\n"), }, }; @@ -242,7 +242,7 @@ pub fn add_variant(&self, editor: &mut SyntaxEditor, variant: &ast::Variant) { normalize_ws_between_braces(editor, self.syntax()); (IndentLevel::from_token(&l_curly) + 1, Position::after(&l_curly)) } - None => (IndentLevel::single(), Position::last_child_of(self.syntax())), + None => (IndentLevel::zero(), Position::last_child_of(self.syntax())), }, }; let elements: Vec = vec![ From 082f46a5fc305d26d1f2b03b9433abf899e1b010 Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Wed, 25 Mar 2026 22:42:15 +0800 Subject: [PATCH 32/56] Remove redundant zero indent --- .../src/handlers/extract_struct_from_enum_variant.rs | 5 +---- src/tools/rust-analyzer/crates/ide-assists/src/utils.rs | 1 - 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs index e00a2949f2b8..cbf4e0ec28af 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs @@ -16,9 +16,7 @@ SyntaxKind::*, SyntaxNode, T, ast::{ - self, AstNode, HasAttrs, HasGenericParams, HasName, HasVisibility, - edit::{AstNodeEdit, IndentLevel}, - make, + self, AstNode, HasAttrs, HasGenericParams, HasName, HasVisibility, edit::AstNodeEdit, make, }, match_ast, ted, }; @@ -290,7 +288,6 @@ fn create_struct_def( field_list.clone().into() } }; - let field_list = field_list.indent(IndentLevel::zero()); let strukt = make::struct_(enum_vis, name, generics, field_list).clone_for_update(); 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 b976a172277d..a6c9004ece8b 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs @@ -324,7 +324,6 @@ pub fn add_trait_assoc_items_to_impl_with_factory( ExprFillDefaultMode::Underscore => make.expr_underscore().into(), }; let new_body = make.block_expr(None::, Some(fill_expr)); - let new_body = AstNodeEdit::indent(&new_body, IndentLevel::zero()); let mut fn_editor = SyntaxEditor::new(fn_.syntax().clone()); fn_.replace_or_insert_body(&mut fn_editor, new_body); let new_fn_ = fn_editor.finish().new_root().clone(); From 39fd61e2260abcded8a1c92eeab3130e4ca6143e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 25 Mar 2026 21:46:53 +0000 Subject: [PATCH 33/56] Bump picomatch in /editors/code Bumps and [picomatch](https://github.com/micromatch/picomatch). These dependencies needed to be updated together. Updates `picomatch` from 2.3.1 to 2.3.2 - [Release notes](https://github.com/micromatch/picomatch/releases) - [Changelog](https://github.com/micromatch/picomatch/blob/master/CHANGELOG.md) - [Commits](https://github.com/micromatch/picomatch/compare/2.3.1...2.3.2) Updates `picomatch` from 4.0.2 to 4.0.4 - [Release notes](https://github.com/micromatch/picomatch/releases) - [Changelog](https://github.com/micromatch/picomatch/blob/master/CHANGELOG.md) - [Commits](https://github.com/micromatch/picomatch/compare/2.3.1...2.3.2) --- updated-dependencies: - dependency-name: picomatch dependency-version: 2.3.2 dependency-type: indirect - dependency-name: picomatch dependency-version: 4.0.4 dependency-type: indirect ... Signed-off-by: dependabot[bot] --- .../rust-analyzer/editors/code/package-lock.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/tools/rust-analyzer/editors/code/package-lock.json b/src/tools/rust-analyzer/editors/code/package-lock.json index 047dbba11fcf..06bc64789b6d 100644 --- a/src/tools/rust-analyzer/editors/code/package-lock.json +++ b/src/tools/rust-analyzer/editors/code/package-lock.json @@ -4822,9 +4822,9 @@ } }, "node_modules/micromatch/node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", "dev": true, "license": "MIT", "engines": { @@ -5463,9 +5463,9 @@ "license": "ISC" }, "node_modules/picomatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", - "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", "dev": true, "license": "MIT", "engines": { From bf5fe9fdd37268f78c6ded7c00ac51d1e8d41f03 Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Thu, 26 Mar 2026 07:42:31 +0800 Subject: [PATCH 34/56] Add slice default implement in minicore --- .../rust-analyzer/crates/test-utils/src/minicore.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) 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 c34475bbdf01..86fb08073253 100644 --- a/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs +++ b/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs @@ -1503,6 +1503,19 @@ pub fn len(&self) -> usize { loop {} } } + + // region:default + impl const Default for &[T] { + fn default() -> Self { + &[] + } + } + impl const Default for &mut [T] { + fn default() -> Self { + &mut [] + } + } + // endregion:default } // endregion:slice From ecdb237fd5423452c80f926d32311fc6afda829d Mon Sep 17 00:00:00 2001 From: Weixie Cui Date: Thu, 26 Mar 2026 09:56:37 +0800 Subject: [PATCH 35/56] fix: Correct type_or_const param index bound in debug_assert local_id is used as an index into type/const params; valid indices are 0..len_type_or_consts(). The previous <= check incorrectly allowed idx == len. Assisted by an AI coding tool (see CONTRIBUTING.md). --- src/tools/rust-analyzer/crates/hir-ty/src/generics.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs b/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs index b1500bcdb756..b3c888da8e95 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs @@ -185,7 +185,7 @@ fn find_type_or_const_param(&self, param: TypeOrConstParamId) -> Option { if param.parent == self.def { let idx = param.local_id.into_raw().into_u32() as usize; debug_assert!( - idx <= self.params.len_type_or_consts(), + idx < self.params.len_type_or_consts(), "idx: {} len: {}", idx, self.params.len_type_or_consts() From 99e378390fd7b3f5f20af8d1dbdc55a1914a0aa1 Mon Sep 17 00:00:00 2001 From: Weixie Cui Date: Thu, 26 Mar 2026 09:58:04 +0800 Subject: [PATCH 36/56] fix: Correct internal error message for ptr_guaranteed_cmp shim The missing-args branch reused the wrapping_add error string. Assisted by an AI coding tool (see CONTRIBUTING.md). --- src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 a0dd3b5846f4..86d951060140 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 @@ -843,7 +843,7 @@ fn exec_intrinsic( // cases. let [lhs, rhs] = args else { return Err(MirEvalError::InternalError( - "wrapping_add args are not provided".into(), + "ptr_guaranteed_cmp args are not provided".into(), )); }; let ans = lhs.get(self)? == rhs.get(self)?; From 4a01e40c24625e55b360b9384f22c45ccee929a9 Mon Sep 17 00:00:00 2001 From: The rustc-josh-sync Cronjob Bot Date: Thu, 26 Mar 2026 04:50:46 +0000 Subject: [PATCH 37/56] Prepare for merging from rust-lang/rust This updates the rust-version file to 1174f784096deb8e4ba93f7e4b5ccb7bb4ba2c55. --- src/tools/rust-analyzer/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/rust-version b/src/tools/rust-analyzer/rust-version index db9492636f6a..68f38716dbb0 100644 --- a/src/tools/rust-analyzer/rust-version +++ b/src/tools/rust-analyzer/rust-version @@ -1 +1 @@ -eda4fc7733ee89e484d7120cafbd80dcb2fce66e +1174f784096deb8e4ba93f7e4b5ccb7bb4ba2c55 From 3f155fe96d95655e373c1f809c9674db92de9381 Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Thu, 26 Mar 2026 10:35:18 +0530 Subject: [PATCH 38/56] migrate getter make variant to SyntaxFactory --- .../crates/ide-assists/src/utils.rs | 29 ++++++++++++++----- 1 file changed, 21 insertions(+), 8 deletions(-) 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 96e1bbdc7ea9..5c4bfd79af56 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs @@ -1036,8 +1036,8 @@ enum ReferenceConversionType { } impl<'db> ReferenceConversion<'db> { - pub(crate) fn convert_type(&self, db: &'db dyn HirDatabase, module: hir::Module) -> ast::Type { - let ty = match self.conversion { + fn type_to_string(&self, db: &'db dyn HirDatabase, module: hir::Module) -> String { + match self.conversion { ReferenceConversionType::Copy => self .ty .display_source_code(db, module.into(), true) @@ -1087,25 +1087,38 @@ pub(crate) fn convert_type(&self, db: &'db dyn HirDatabase, module: hir::Module) .unwrap_or_else(|_| "_".to_owned()); format!("Result<&{first_type_argument_name}, &{second_type_argument_name}>") } - }; + } + } + pub(crate) fn convert_type(&self, db: &'db dyn HirDatabase, module: hir::Module) -> ast::Type { + let ty = self.type_to_string(db, module); make::ty(&ty) } - pub(crate) fn getter(&self, field_name: String) -> ast::Expr { - let expr = make::expr_field(make::ext::expr_self(), &field_name); + pub(crate) fn convert_type_with_factory( + &self, + make: &SyntaxFactory, + db: &'db dyn HirDatabase, + module: hir::Module, + ) -> ast::Type { + let ty = self.type_to_string(db, module); + make.ty(&ty) + } + + pub(crate) fn getter(&self, make: &SyntaxFactory, field_name: String) -> ast::Expr { + let expr = make.expr_field(make.expr_self(), &field_name); match self.conversion { - ReferenceConversionType::Copy => expr, + ReferenceConversionType::Copy => expr.into(), ReferenceConversionType::AsRefStr | ReferenceConversionType::AsRefSlice | ReferenceConversionType::Dereferenced | ReferenceConversionType::Option | ReferenceConversionType::Result => { if self.impls_deref { - make::expr_ref(expr, false) + make.expr_ref(expr.into(), false) } else { - make::expr_method_call(expr, make::name_ref("as_ref"), make::arg_list([])) + make.expr_method_call(expr.into(), make.name_ref("as_ref"), make.arg_list([])) .into() } } From 78b1309d3d7506b7bb3e9c94483096a659117da7 Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Thu, 26 Mar 2026 10:35:40 +0530 Subject: [PATCH 39/56] add expr_self in syntax factory constructor --- .../crates/syntax/src/ast/syntax_factory/constructors.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs index fa81dfad1f7f..44114a780295 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs @@ -29,6 +29,10 @@ pub fn expr_todo(&self) -> ast::Expr { make::ext::expr_todo().clone_for_update() } + pub fn expr_self(&self) -> ast::Expr { + make::ext::expr_self().clone_for_update() + } + pub fn lifetime(&self, text: &str) -> ast::Lifetime { make::lifetime(text).clone_for_update() } From b5f884fada6ffef23374db7bbc18865418fdcd7f Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Thu, 26 Mar 2026 10:36:18 +0530 Subject: [PATCH 40/56] remove usage of make variant getter from generate_getter_or_setter --- .../src/handlers/generate_getter_or_setter.rs | 68 +++++++++---------- 1 file changed, 32 insertions(+), 36 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_getter_or_setter.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_getter_or_setter.rs index 92a654743b58..62ffd3d9656b 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_getter_or_setter.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_getter_or_setter.rs @@ -218,14 +218,14 @@ fn generate_getter_from_info( ctx: &AssistContext<'_>, info: &AssistInfo, record_field_info: &RecordFieldInfo, - syntax_factory: &SyntaxFactory, + make: &SyntaxFactory, ) -> ast::Fn { let (ty, body) = if matches!(info.assist_type, AssistType::MutGet) { - let self_expr = syntax_factory.expr_path(syntax_factory.ident_path("self")); + let self_expr = make.expr_path(make.ident_path("self")); ( - syntax_factory.ty_ref(record_field_info.field_ty.clone(), true), - syntax_factory.expr_ref( - syntax_factory.expr_field(self_expr, &record_field_info.field_name.text()).into(), + make.ty_ref(record_field_info.field_ty.clone(), true), + make.expr_ref( + make.expr_field(self_expr, &record_field_info.field_name.text()).into(), true, ), ) @@ -239,21 +239,20 @@ fn generate_getter_from_info( .map(|conversion| { cov_mark::hit!(convert_reference_type); ( - conversion.convert_type(ctx.db(), module), - conversion.getter(record_field_info.field_name.to_string()), + conversion.convert_type_with_factory(make, ctx.db(), module), + conversion.getter(make, record_field_info.field_name.to_string()), ) }) })() .unwrap_or_else(|| { ( - syntax_factory.ty_ref(record_field_info.field_ty.clone(), false), - syntax_factory.expr_ref( - syntax_factory - .expr_field( - syntax_factory.expr_path(syntax_factory.ident_path("self")), - &record_field_info.field_name.text(), - ) - .into(), + make.ty_ref(record_field_info.field_ty.clone(), false), + make.expr_ref( + make.expr_field( + make.expr_path(make.ident_path("self")), + &record_field_info.field_name.text(), + ) + .into(), false, ), ) @@ -261,18 +260,18 @@ fn generate_getter_from_info( }; let self_param = if matches!(info.assist_type, AssistType::MutGet) { - syntax_factory.mut_self_param() + make.mut_self_param() } else { - syntax_factory.self_param() + make.self_param() }; let strukt = &info.strukt; - let fn_name = syntax_factory.name(&record_field_info.fn_name); - let params = syntax_factory.param_list(Some(self_param), []); - let ret_type = Some(syntax_factory.ret_type(ty)); - let body = syntax_factory.block_expr([], Some(body)); + let fn_name = make.name(&record_field_info.fn_name); + let params = make.param_list(Some(self_param), []); + let ret_type = Some(make.ret_type(ty)); + let body = make.block_expr([], Some(body)); - syntax_factory.fn_( + make.fn_( None, strukt.visibility(), fn_name, @@ -291,32 +290,29 @@ fn generate_getter_from_info( fn generate_setter_from_info( info: &AssistInfo, record_field_info: &RecordFieldInfo, - syntax_factory: &SyntaxFactory, + make: &SyntaxFactory, ) -> ast::Fn { let strukt = &info.strukt; let field_name = &record_field_info.fn_name; - let fn_name = syntax_factory.name(&format!("set_{field_name}")); + let fn_name = make.name(&format!("set_{field_name}")); let field_ty = &record_field_info.field_ty; // Make the param list // `(&mut self, $field_name: $field_ty)` - let field_param = syntax_factory.param( - syntax_factory.ident_pat(false, false, syntax_factory.name(field_name)).into(), - field_ty.clone(), - ); - let params = syntax_factory.param_list(Some(syntax_factory.mut_self_param()), [field_param]); + let field_param = + make.param(make.ident_pat(false, false, make.name(field_name)).into(), field_ty.clone()); + let params = make.param_list(Some(make.mut_self_param()), [field_param]); // Make the assignment body // `self.$field_name = $field_name` - let self_expr = syntax_factory.expr_path(syntax_factory.ident_path("self")); - let lhs = syntax_factory.expr_field(self_expr, field_name); - let rhs = syntax_factory.expr_path(syntax_factory.ident_path(field_name)); - let assign_stmt = - syntax_factory.expr_stmt(syntax_factory.expr_assignment(lhs.into(), rhs).into()); - let body = syntax_factory.block_expr([assign_stmt.into()], None); + let self_expr = make.expr_path(make.ident_path("self")); + let lhs = make.expr_field(self_expr, field_name); + let rhs = make.expr_path(make.ident_path(field_name)); + let assign_stmt = make.expr_stmt(make.expr_assignment(lhs.into(), rhs).into()); + let body = make.block_expr([assign_stmt.into()], None); // Make the setter fn - syntax_factory.fn_( + make.fn_( None, strukt.visibility(), fn_name, From 8e4b26db65996879652a2ff8981d53c325f09939 Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Thu, 26 Mar 2026 07:25:25 +0800 Subject: [PATCH 41/56] fix: wrap ty-anchor in non-path type constuctor Example --- ```rust struct TestStruct { r: &'static [i32] } fn test_fn() { let s = TestStruct{ $0 }; } ``` **Before this PR** ```rust struct TestStruct { r: &'static [i32] } fn test_fn() { let s = TestStruct{ r: &'static }; } ``` **After this PR** ```rust struct TestStruct { r: &'static [i32] } fn test_fn() { let s = TestStruct{ r: <&'static [i32]>::default() }; } ``` --- .../ide-diagnostics/src/handlers/missing_fields.rs | 8 ++++---- .../rust-analyzer/crates/syntax/src/ast/make.rs | 12 ++++++++++-- .../rust-analyzer/crates/syntax/src/ast/node_ext.rs | 4 ++++ 3 files changed, 18 insertions(+), 6 deletions(-) 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 d5f25dfaf208..050d5477f62c 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 @@ -588,14 +588,14 @@ fn test_fn() { fn test_fill_struct_fields_default() { check_fix( r#" -//- minicore: default, option +//- minicore: default, option, slice struct TestWithDefault(usize); impl Default for TestWithDefault { pub fn default() -> Self { Self(0) } } -struct TestStruct { one: i32, two: TestWithDefault } +struct TestStruct { one: i32, two: TestWithDefault, r: &'static [i32] } fn test_fn() { let s = TestStruct{ $0 }; @@ -608,10 +608,10 @@ pub fn default() -> Self { Self(0) } } -struct TestStruct { one: i32, two: TestWithDefault } +struct TestStruct { one: i32, two: TestWithDefault, r: &'static [i32] } fn test_fn() { - let s = TestStruct{ one: 0, two: TestWithDefault::default() }; + let s = TestStruct{ one: 0, two: TestWithDefault::default(), r: <&'static [i32]>::default() }; } ", ); diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs index f5d1d009a579..00971569a2ef 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs @@ -74,10 +74,18 @@ pub fn expr_underscore() -> ast::Expr { expr_from_text("_") } pub fn expr_ty_default(ty: &ast::Type) -> ast::Expr { - expr_from_text(&format!("{ty}::default()")) + if !ty.needs_angles_in_path() { + expr_from_text(&format!("{ty}::default()")) + } else { + expr_from_text(&format!("<{ty}>::default()")) + } } pub fn expr_ty_new(ty: &ast::Type) -> ast::Expr { - expr_from_text(&format!("{ty}::new()")) + if !ty.needs_angles_in_path() { + expr_from_text(&format!("{ty}::new()")) + } else { + expr_from_text(&format!("<{ty}>::new()")) + } } pub fn expr_self() -> ast::Expr { expr_from_text("self") diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs index 76cfea9d5bc6..63e4608d0f63 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs @@ -717,6 +717,10 @@ pub fn generic_arg_list(&self) -> Option { None } } + + pub fn needs_angles_in_path(&self) -> bool { + !matches!(self, ast::Type::PathType(_)) || self.generic_arg_list().is_some() + } } #[derive(Debug, Clone, PartialEq, Eq)] From 7b235b5fe16f9417d4e595c4f4c335613f62f7b3 Mon Sep 17 00:00:00 2001 From: Biruk-gebru Date: Wed, 25 Mar 2026 19:45:14 +0300 Subject: [PATCH 42/56] internal: Migrate `generate_default_from_new` assist to `SyntaxEditor` Replace direct text insertion via `builder.insert()` with `SyntaxEditor`-based node insertion. Build the Default impl using `SyntaxFactory` instead of string concatenation with `format_to!`. AI assistance was used for this contribution. Part of rust-lang/rust-analyzer#18285 --- .../src/handlers/generate_default_from_new.rs | 103 +++++++++++------- 1 file changed, 63 insertions(+), 40 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_default_from_new.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_default_from_new.rs index 485184723bdf..2d92bf514622 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_default_from_new.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_default_from_new.rs @@ -1,8 +1,12 @@ use ide_db::famous_defs::FamousDefs; -use stdx::format_to; use syntax::{ AstNode, - ast::{self, HasGenericParams, HasName, HasTypeBounds, Impl, syntax_factory::SyntaxFactory}, + ast::{ + self, HasGenericParams, HasName, HasTypeBounds, Impl, + edit::{AstNodeEdit, IndentLevel}, + syntax_factory::SyntaxFactory, + }, + syntax_editor::Position, }; use crate::{ @@ -62,32 +66,32 @@ pub(crate) fn generate_default_from_new(acc: &mut Assists, ctx: &AssistContext<' return None; } - let insert_location = impl_.syntax().text_range(); + let target = impl_.syntax().text_range(); acc.add( AssistId::generate("generate_default_from_new"), "Generate a Default impl from a new fn", - insert_location, + target, move |builder| { - let default_code = " fn default() -> Self { - Self::new() - }"; let make = SyntaxFactory::without_mappings(); - let code = - generate_trait_impl_text_from_impl(&impl_, self_ty, "Default", default_code, &make); - builder.insert(insert_location.end(), code); + let default_impl = generate_default_impl(&make, &impl_, self_ty); + let indent = IndentLevel::from_node(impl_.syntax()); + let default_impl = default_impl.indent(indent); + + let mut editor = builder.make_editor(impl_.syntax()); + editor.insert_all( + Position::after(impl_.syntax()), + vec![ + make.whitespace(&format!("\n\n{indent}")).into(), + default_impl.syntax().clone().into(), + ], + ); + builder.add_file_edits(ctx.vfs_file_id(), editor); }, ) } -// FIXME: based on from utils::generate_impl_text_inner -fn generate_trait_impl_text_from_impl( - impl_: &ast::Impl, - self_ty: ast::Type, - trait_text: &str, - code: &str, - make: &SyntaxFactory, -) -> String { +fn generate_default_impl(make: &SyntaxFactory, impl_: &ast::Impl, self_ty: ast::Type) -> ast::Impl { let generic_params = impl_.generic_param_list().map(|generic_params| { let lifetime_params = generic_params.lifetime_params().map(ast::GenericParam::LifetimeParam); @@ -109,26 +113,45 @@ fn generate_trait_impl_text_from_impl( make.generic_param_list(itertools::chain(lifetime_params, ty_or_const_params)) }); - let mut buf = String::with_capacity(code.len()); - buf.push_str("\n\n"); + let trait_ty: ast::Type = make.ty_path(make.ident_path("Default")).into(); - // `impl{generic_params} {trait_text} for {impl_.self_ty()}` - buf.push_str("impl"); - if let Some(generic_params) = &generic_params { - format_to!(buf, "{generic_params}") - } - format_to!(buf, " {trait_text} for {self_ty}"); + let self_new_path = make.path_concat(make.ident_path("Self"), make.ident_path("new")); + let self_new_call = + make.expr_call(make.expr_path(self_new_path), make.arg_list(std::iter::empty())); + let fn_body = make.block_expr(std::iter::empty(), Some(self_new_call.into())); + let self_ty_ret: ast::Type = make.ty_path(make.ident_path("Self")).into(); + let default_fn = make + .fn_( + [], + None, + make.name("default"), + None, + None, + make.param_list(None, std::iter::empty()), + fn_body, + Some(make.ret_type(self_ty_ret)), + false, + false, + false, + false, + ) + .indent(1.into()); + let body = make.assoc_item_list(Some(ast::AssocItem::from(default_fn))); - match impl_.where_clause() { - Some(where_clause) => { - format_to!(buf, "\n{where_clause}\n{{\n{code}\n}}"); - } - None => { - format_to!(buf, " {{\n{code}\n}}"); - } - } - - buf + make.impl_trait( + [], + false, + None, + None, + generic_params, + None, + false, + trait_ty, + self_ty, + None, + impl_.where_clause(), + Some(body), + ) } fn is_default_implemented(ctx: &AssistContext<'_>, impl_: &Impl) -> bool { @@ -631,12 +654,12 @@ pub fn new() -> Self { } } -impl Default for Example { - fn default() -> Self { - Self::new() + impl Default for Example { + fn default() -> Self { + Self::new() + } } } -} "#, ); } From f110b38c6f5b81494e0144ae4af5db1e3d8e8736 Mon Sep 17 00:00:00 2001 From: "Eddy (Eduard) Stefes" Date: Fri, 27 Mar 2026 09:47:36 +0100 Subject: [PATCH 43/56] fix a tests that assunes the wrong alignment on s390x on s390x vectors are aligned at 8 bytes not 16 or vector length like on x86. --- .../rust-analyzer/crates/hir-ty/src/layout/tests.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs index 8c91be1d7811..e491c29df3b5 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs @@ -379,6 +379,11 @@ impl Tr for S { #[test] fn simd_types() { + let size = 16; + #[cfg(not(target_arch = "s390x"))] + let align = 16; + #[cfg(target_arch = "s390x")] + let align = 8; check_size_and_align( r#" #[repr(simd)] @@ -386,8 +391,8 @@ fn simd_types() { struct Goal(SimdType); "#, "", - 16, - 16, + size, + align, ); } From 1b724576cfda121debe1b7bdb442980a696d6726 Mon Sep 17 00:00:00 2001 From: Weixie Cui Date: Thu, 26 Mar 2026 09:49:01 +0800 Subject: [PATCH 44/56] fix: Correct Display label for Event::FetchWorkspaces The fmt::Display implementation for Event printed the wrong variant name (Event::SwitchWorkspaces) for FetchWorkspaces events, which was misleading in tracing output. Add a regression test. --- src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 dad321137fa6..7c494de6f73d 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 @@ -92,7 +92,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { Event::DeferredTask(_) => write!(f, "Event::DeferredTask"), Event::TestResult(_) => write!(f, "Event::TestResult"), Event::DiscoverProject(_) => write!(f, "Event::DiscoverProject"), - Event::FetchWorkspaces(_) => write!(f, "Event::SwitchWorkspaces"), + Event::FetchWorkspaces(_) => write!(f, "Event::FetchWorkspaces"), } } } From 12119eccc5c1243843a9efc83d658dcf3ab73a35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Sat, 28 Mar 2026 12:40:12 +0200 Subject: [PATCH 45/56] Bump GitHub actions --- .../.github/workflows/autopublish.yaml | 2 +- .../rust-analyzer/.github/workflows/ci.yaml | 31 ++++++++---------- .../.github/workflows/coverage.yaml | 6 ++-- .../rust-analyzer/.github/workflows/fuzz.yml | 6 ++-- .../.github/workflows/metrics.yaml | 22 ++++++------- .../.github/workflows/publish-libs.yaml | 2 +- .../.github/workflows/release.yaml | 32 +++++++++---------- .../.github/workflows/rustdoc.yaml | 30 ++++++++--------- 8 files changed, 63 insertions(+), 68 deletions(-) diff --git a/src/tools/rust-analyzer/.github/workflows/autopublish.yaml b/src/tools/rust-analyzer/.github/workflows/autopublish.yaml index 6e2be7fd3da5..abb9b521f1a5 100644 --- a/src/tools/rust-analyzer/.github/workflows/autopublish.yaml +++ b/src/tools/rust-analyzer/.github/workflows/autopublish.yaml @@ -16,7 +16,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: fetch-depth: 0 diff --git a/src/tools/rust-analyzer/.github/workflows/ci.yaml b/src/tools/rust-analyzer/.github/workflows/ci.yaml index 04de6d11e3eb..c27d84fb0bc0 100644 --- a/src/tools/rust-analyzer/.github/workflows/ci.yaml +++ b/src/tools/rust-analyzer/.github/workflows/ci.yaml @@ -30,8 +30,8 @@ jobs: outputs: typescript: ${{ steps.filter.outputs.typescript }} steps: - - uses: actions/checkout@v4 - - uses: dorny/paths-filter@1441771bbfdd59dcd748680ee64ebd8faab1a242 + - uses: actions/checkout@v6 + - uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1 id: filter with: filters: | @@ -45,7 +45,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: ref: ${{ github.event.pull_request.head.sha }} @@ -88,7 +88,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: ref: ${{ github.event.pull_request.head.sha }} @@ -136,7 +136,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Install Rust toolchain run: | @@ -164,7 +164,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Install Rust toolchain run: | @@ -180,7 +180,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 # Note that clippy output is currently dependent on whether rust-src is installed, # https://github.com/rust-lang/rust-clippy/issues/14625 @@ -202,7 +202,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Install Rust toolchain run: | @@ -226,12 +226,7 @@ jobs: strategy: matrix: - target: - [ - powerpc-unknown-linux-gnu, - x86_64-unknown-linux-musl, - wasm32-unknown-unknown, - ] + target: [powerpc-unknown-linux-gnu, x86_64-unknown-linux-musl, wasm32-unknown-unknown] include: # The rust-analyzer binary is not expected to compile on WASM, but the IDE # crate should @@ -240,7 +235,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Install Rust toolchain run: | @@ -268,10 +263,10 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Install Nodejs - uses: actions/setup-node@v4 + uses: actions/setup-node@v6 with: node-version: 22 @@ -327,7 +322,7 @@ jobs: run: curl -LsSf https://github.com/crate-ci/typos/releases/download/$TYPOS_VERSION/typos-$TYPOS_VERSION-x86_64-unknown-linux-musl.tar.gz | tar zxf - -C ${CARGO_HOME:-~/.cargo}/bin - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: ref: ${{ github.event.pull_request.head.sha }} diff --git a/src/tools/rust-analyzer/.github/workflows/coverage.yaml b/src/tools/rust-analyzer/.github/workflows/coverage.yaml index bd4edba747ca..9460c6a3c77a 100644 --- a/src/tools/rust-analyzer/.github/workflows/coverage.yaml +++ b/src/tools/rust-analyzer/.github/workflows/coverage.yaml @@ -13,7 +13,7 @@ jobs: coverage: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Install Rust toolchain run: | @@ -34,9 +34,9 @@ jobs: - name: Generate code coverage run: cargo llvm-cov --workspace --lcov --output-path lcov.info - + - name: Upload coverage to Codecov - uses: codecov/codecov-action@v5 + uses: codecov/codecov-action@57e3a136b779b570ffcdbf80b3bdc90e7fab3de2 # v6.0.0 with: files: lcov.info fail_ci_if_error: false diff --git a/src/tools/rust-analyzer/.github/workflows/fuzz.yml b/src/tools/rust-analyzer/.github/workflows/fuzz.yml index 7acfcbe351fe..af0e03598ecf 100644 --- a/src/tools/rust-analyzer/.github/workflows/fuzz.yml +++ b/src/tools/rust-analyzer/.github/workflows/fuzz.yml @@ -2,10 +2,10 @@ name: Fuzz on: schedule: # Once a week - - cron: '0 0 * * 0' + - cron: "0 0 * * 0" push: paths: - - '.github/workflows/fuzz.yml' + - ".github/workflows/fuzz.yml" # Allow manual trigger workflow_dispatch: @@ -27,7 +27,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: ref: ${{ github.event.pull_request.head.sha }} fetch-depth: 1 diff --git a/src/tools/rust-analyzer/.github/workflows/metrics.yaml b/src/tools/rust-analyzer/.github/workflows/metrics.yaml index 860837dd7fd4..a482235105c0 100644 --- a/src/tools/rust-analyzer/.github/workflows/metrics.yaml +++ b/src/tools/rust-analyzer/.github/workflows/metrics.yaml @@ -23,7 +23,7 @@ jobs: rustup component add --toolchain beta rust-src - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Cache cargo uses: actions/cache@v4 @@ -45,7 +45,7 @@ jobs: key: ${{ runner.os }}-target-${{ github.sha }} - name: Upload build metrics - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: build-${{ github.sha }} path: target/build.json @@ -66,7 +66,7 @@ jobs: rustup component add --toolchain beta rust-src - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Restore target cache uses: actions/cache@v4 @@ -78,7 +78,7 @@ jobs: run: cargo xtask metrics "${{ matrix.names }}" - name: Upload metrics - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: ${{ matrix.names }}-${{ github.sha }} path: target/${{ matrix.names }}.json @@ -89,35 +89,35 @@ jobs: needs: [build_metrics, other_metrics] steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Download build metrics - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v8 with: name: build-${{ github.sha }} - name: Download self metrics - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v8 with: name: self-${{ github.sha }} - name: Download ripgrep-13.0.0 metrics - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v8 with: name: ripgrep-13.0.0-${{ github.sha }} - name: Download webrender-2022 metrics - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v8 with: name: webrender-2022-${{ github.sha }} - name: Download diesel-1.4.8 metrics - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v8 with: name: diesel-1.4.8-${{ github.sha }} - name: Download hyper-0.14.18 metrics - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v8 with: name: hyper-0.14.18-${{ github.sha }} diff --git a/src/tools/rust-analyzer/.github/workflows/publish-libs.yaml b/src/tools/rust-analyzer/.github/workflows/publish-libs.yaml index f2c8b6365b66..762b7bda871c 100644 --- a/src/tools/rust-analyzer/.github/workflows/publish-libs.yaml +++ b/src/tools/rust-analyzer/.github/workflows/publish-libs.yaml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: fetch-depth: 0 diff --git a/src/tools/rust-analyzer/.github/workflows/release.yaml b/src/tools/rust-analyzer/.github/workflows/release.yaml index 28914118de94..b35614f91b2d 100644 --- a/src/tools/rust-analyzer/.github/workflows/release.yaml +++ b/src/tools/rust-analyzer/.github/workflows/release.yaml @@ -70,12 +70,12 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: fetch-depth: ${{ env.FETCH_DEPTH }} - name: Install Node.js toolchain - uses: actions/setup-node@v4 + uses: actions/setup-node@v6 with: node-version: 22 @@ -143,7 +143,7 @@ jobs: run: target/${{ matrix.target }}/release/rust-analyzer analysis-stats --with-deps --no-sysroot --no-test $(rustc --print sysroot)/lib/rustlib/src/rust/library/std -q - name: Upload artifacts - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: dist-${{ matrix.target }} path: ./dist @@ -166,7 +166,7 @@ jobs: run: apk add --no-cache git clang lld musl-dev nodejs npm - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: fetch-depth: ${{ env.FETCH_DEPTH }} @@ -189,7 +189,7 @@ jobs: - run: rm -rf editors/code/server - name: Upload artifacts - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: dist-x86_64-unknown-linux-musl path: ./dist @@ -201,7 +201,7 @@ jobs: needs: ["dist", "dist-x86_64-unknown-linux-musl"] steps: - name: Install Nodejs - uses: actions/setup-node@v4 + uses: actions/setup-node@v6 with: node-version: 22 @@ -212,46 +212,46 @@ jobs: - run: 'echo "TAG: $TAG"' - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: fetch-depth: ${{ env.FETCH_DEPTH }} - run: echo "HEAD_SHA=$(git rev-parse HEAD)" >> $GITHUB_ENV - run: 'echo "HEAD_SHA: $HEAD_SHA"' - - uses: actions/download-artifact@v4 + - uses: actions/download-artifact@v8 with: name: dist-aarch64-apple-darwin path: dist - - uses: actions/download-artifact@v4 + - uses: actions/download-artifact@v8 with: name: dist-x86_64-apple-darwin path: dist - - uses: actions/download-artifact@v4 + - uses: actions/download-artifact@v8 with: name: dist-x86_64-unknown-linux-gnu path: dist - - uses: actions/download-artifact@v4 + - uses: actions/download-artifact@v8 with: name: dist-x86_64-unknown-linux-musl path: dist - - uses: actions/download-artifact@v4 + - uses: actions/download-artifact@v8 with: name: dist-aarch64-unknown-linux-gnu path: dist - - uses: actions/download-artifact@v4 + - uses: actions/download-artifact@v8 with: name: dist-arm-unknown-linux-gnueabihf path: dist - - uses: actions/download-artifact@v4 + - uses: actions/download-artifact@v8 with: name: dist-x86_64-pc-windows-msvc path: dist - - uses: actions/download-artifact@v4 + - uses: actions/download-artifact@v8 with: name: dist-i686-pc-windows-msvc path: dist - - uses: actions/download-artifact@v4 + - uses: actions/download-artifact@v8 with: name: dist-aarch64-pc-windows-msvc path: dist diff --git a/src/tools/rust-analyzer/.github/workflows/rustdoc.yaml b/src/tools/rust-analyzer/.github/workflows/rustdoc.yaml index 0cc7ce77ddb6..244eaac2b819 100644 --- a/src/tools/rust-analyzer/.github/workflows/rustdoc.yaml +++ b/src/tools/rust-analyzer/.github/workflows/rustdoc.yaml @@ -1,8 +1,8 @@ name: rustdoc on: push: - branches: - - master + branches: + - master env: CARGO_INCREMENTAL: 0 @@ -17,19 +17,19 @@ jobs: runs-on: ubuntu-latest steps: - - name: Checkout repository - uses: actions/checkout@v4 + - name: Checkout repository + uses: actions/checkout@v6 - - name: Install Rust toolchain - run: rustup update --no-self-update stable + - name: Install Rust toolchain + run: rustup update --no-self-update stable - - name: Build Documentation - run: cargo doc --all --no-deps --document-private-items + - name: Build Documentation + run: cargo doc --all --no-deps --document-private-items - - name: Deploy Docs - uses: peaceiris/actions-gh-pages@4f9cc6602d3f66b9c108549d475ec49e8ef4d45e # v4.0.0 - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - publish_branch: gh-pages - publish_dir: ./target/doc - force_orphan: true + - name: Deploy Docs + uses: peaceiris/actions-gh-pages@4f9cc6602d3f66b9c108549d475ec49e8ef4d45e # v4.0.0 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + publish_branch: gh-pages + publish_dir: ./target/doc + force_orphan: true From 20f97a5f70973b97375fea26fa88909dace095da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Sat, 28 Mar 2026 12:43:29 +0200 Subject: [PATCH 46/56] Allow Node 20 for peaceiris/actions-gh-pages --- src/tools/rust-analyzer/.github/workflows/rustdoc.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tools/rust-analyzer/.github/workflows/rustdoc.yaml b/src/tools/rust-analyzer/.github/workflows/rustdoc.yaml index 244eaac2b819..03fd08317501 100644 --- a/src/tools/rust-analyzer/.github/workflows/rustdoc.yaml +++ b/src/tools/rust-analyzer/.github/workflows/rustdoc.yaml @@ -10,6 +10,7 @@ env: RUSTFLAGS: "-D warnings -W unreachable-pub" RUSTDOCFLAGS: "-D warnings" RUSTUP_MAX_RETRIES: 10 + ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION: true jobs: rustdoc: From a779e16812735e7ff352e9be6c01b410fe480681 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 28 Mar 2026 11:34:47 +0000 Subject: [PATCH 47/56] Bump brace-expansion from 1.1.12 to 1.1.13 in /editors/code Bumps [brace-expansion](https://github.com/juliangruber/brace-expansion) from 1.1.12 to 1.1.13. - [Release notes](https://github.com/juliangruber/brace-expansion/releases) - [Commits](https://github.com/juliangruber/brace-expansion/compare/v1.1.12...v1.1.13) --- updated-dependencies: - dependency-name: brace-expansion dependency-version: 1.1.13 dependency-type: indirect ... Signed-off-by: dependabot[bot] --- .../editors/code/package-lock.json | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/tools/rust-analyzer/editors/code/package-lock.json b/src/tools/rust-analyzer/editors/code/package-lock.json index 047dbba11fcf..c4e362b38b12 100644 --- a/src/tools/rust-analyzer/editors/code/package-lock.json +++ b/src/tools/rust-analyzer/editors/code/package-lock.json @@ -738,9 +738,9 @@ } }, "node_modules/@eslint/config-array/node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.13.tgz", + "integrity": "sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w==", "dev": true, "license": "MIT", "dependencies": { @@ -799,9 +799,9 @@ } }, "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.13.tgz", + "integrity": "sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w==", "dev": true, "license": "MIT", "dependencies": { @@ -1817,9 +1817,9 @@ ] }, "node_modules/@vscode/vsce/node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.13.tgz", + "integrity": "sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w==", "dev": true, "license": "MIT", "dependencies": { @@ -2060,9 +2060,9 @@ "license": "BSD-2-Clause" }, "node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.3.tgz", + "integrity": "sha512-MCV/fYJEbqx68aE58kv2cA/kiky1G8vux3OR6/jbS+jIMe/6fJWa0DTzJU7dqijOWYwHi1t29FlfYI9uytqlpA==", "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" @@ -3416,9 +3416,9 @@ } }, "node_modules/eslint/node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.13.tgz", + "integrity": "sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w==", "dev": true, "license": "MIT", "dependencies": { @@ -3895,9 +3895,9 @@ } }, "node_modules/glob/node_modules/brace-expansion": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz", - "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==", + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz", + "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==", "dev": true, "license": "MIT", "dependencies": { From fcf665077c457661f2a31e69b4a93a6fe4ed4c63 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sun, 22 Mar 2026 09:19:52 +0100 Subject: [PATCH 48/56] Hookup Signature Inference in more places --- .../rust-analyzer/crates/hir-def/src/db.rs | 152 +------ .../crates/hir-def/src/expr_store.rs | 94 +++- .../crates/hir-def/src/expr_store/body.rs | 16 +- .../crates/hir-def/src/expr_store/lower.rs | 7 +- .../crates/hir-def/src/expr_store/pretty.rs | 8 +- .../crates/hir-def/src/expr_store/scope.rs | 65 +-- .../hir-def/src/expr_store/tests/body.rs | 153 +++---- .../src/expr_store/tests/signatures.rs | 5 +- .../crates/hir-def/src/hir/generics.rs | 137 +++--- .../rust-analyzer/crates/hir-def/src/lib.rs | 54 +-- .../hir-def/src/macro_expansion_tests/mod.rs | 3 +- .../crates/hir-def/src/resolver.rs | 65 ++- .../crates/hir-def/src/signatures.rs | 219 +++++++--- .../crates/hir-def/src/test_db.rs | 5 +- .../crates/hir-ty/src/consteval.rs | 22 +- .../crates/hir-ty/src/consteval/tests.rs | 8 +- .../rust-analyzer/crates/hir-ty/src/db.rs | 12 +- .../hir-ty/src/diagnostics/decl_check.rs | 33 +- .../crates/hir-ty/src/diagnostics/expr.rs | 22 +- .../hir-ty/src/diagnostics/match_check.rs | 5 +- .../hir-ty/src/diagnostics/unsafe_check.rs | 12 +- .../crates/hir-ty/src/display.rs | 67 +-- .../rust-analyzer/crates/hir-ty/src/drop.rs | 15 +- .../crates/hir-ty/src/dyn_compatibility.rs | 10 +- .../hir-ty/src/dyn_compatibility/tests.rs | 5 +- .../crates/hir-ty/src/generics.rs | 24 +- .../rust-analyzer/crates/hir-ty/src/infer.rs | 163 +++---- .../crates/hir-ty/src/infer/cast.rs | 9 +- .../hir-ty/src/infer/closure/analysis.rs | 61 ++- .../crates/hir-ty/src/infer/expr.rs | 3 +- .../crates/hir-ty/src/infer/path.rs | 5 +- .../crates/hir-ty/src/infer/unify.rs | 4 +- .../crates/hir-ty/src/lang_items.rs | 8 +- .../rust-analyzer/crates/hir-ty/src/layout.rs | 5 +- .../crates/hir-ty/src/layout/adt.rs | 4 +- .../crates/hir-ty/src/layout/tests.rs | 41 +- .../rust-analyzer/crates/hir-ty/src/lib.rs | 6 +- .../rust-analyzer/crates/hir-ty/src/lower.rs | 77 ++-- .../crates/hir-ty/src/lower/path.rs | 9 +- .../crates/hir-ty/src/method_resolution.rs | 11 +- .../hir-ty/src/method_resolution/probe.rs | 10 +- .../crates/hir-ty/src/mir/borrowck.rs | 13 +- .../crates/hir-ty/src/mir/eval.rs | 43 +- .../crates/hir-ty/src/mir/eval/shim.rs | 7 +- .../crates/hir-ty/src/mir/eval/tests.rs | 6 +- .../crates/hir-ty/src/mir/lower.rs | 30 +- .../crates/hir-ty/src/mir/pretty.rs | 18 +- .../crates/hir-ty/src/next_solver/def_id.rs | 54 +-- .../hir-ty/src/next_solver/fulfill/errors.rs | 3 +- .../crates/hir-ty/src/next_solver/interner.rs | 61 ++- .../crates/hir-ty/src/next_solver/ir_print.rs | 15 +- .../crates/hir-ty/src/next_solver/solver.rs | 96 +++-- .../crates/hir-ty/src/opaques.rs | 14 +- .../crates/hir-ty/src/specialization.rs | 13 +- .../rust-analyzer/crates/hir-ty/src/tests.rs | 87 ++-- .../hir-ty/src/tests/closure_captures.rs | 16 +- .../crates/hir-ty/src/tests/incremental.rs | 140 +++--- .../rust-analyzer/crates/hir-ty/src/traits.rs | 34 +- .../rust-analyzer/crates/hir-ty/src/upvars.rs | 8 +- .../rust-analyzer/crates/hir-ty/src/utils.rs | 3 +- .../crates/hir-ty/src/variance.rs | 9 +- .../rust-analyzer/crates/hir/src/display.rs | 49 ++- .../rust-analyzer/crates/hir/src/from_id.rs | 17 +- .../crates/hir/src/has_source.rs | 9 +- src/tools/rust-analyzer/crates/hir/src/lib.rs | 401 ++++++++++-------- .../rust-analyzer/crates/hir/src/semantics.rs | 66 +-- .../hir/src/semantics/child_by_source.rs | 13 +- .../crates/hir/src/semantics/source_to_def.rs | 83 ++-- .../crates/hir/src/source_analyzer.rs | 98 +++-- .../rust-analyzer/crates/hir/src/symbols.rs | 10 +- .../crates/hir/src/term_search/tactics.rs | 2 +- .../src/handlers/add_missing_match_arms.rs | 12 +- .../rust-analyzer/crates/ide-db/src/defs.rs | 21 +- .../rust-analyzer/crates/ide-db/src/search.rs | 48 ++- .../ide/src/inlay_hints/implicit_drop.rs | 4 +- .../rust-analyzer/crates/ide/src/rename.rs | 4 +- .../rust-analyzer/src/cli/analysis_stats.rs | 47 +- 77 files changed, 1707 insertions(+), 1481 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/db.rs b/src/tools/rust-analyzer/crates/hir-def/src/db.rs index ba0efe0ff13a..9c7f4943db97 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/db.rs @@ -9,24 +9,16 @@ use crate::{ AnonConstId, AnonConstLoc, AssocItemId, AttrDefId, BlockId, BlockLoc, ConstId, ConstLoc, - DefWithBodyId, EnumId, EnumLoc, EnumVariantId, EnumVariantLoc, ExpressionStoreOwner, - ExternBlockId, ExternBlockLoc, ExternCrateId, ExternCrateLoc, FunctionId, FunctionLoc, - GenericDefId, ImplId, ImplLoc, LocalFieldId, Macro2Id, Macro2Loc, MacroExpander, MacroId, - MacroRulesId, MacroRulesLoc, MacroRulesLocFlags, ProcMacroId, ProcMacroLoc, StaticId, - StaticLoc, StructId, StructLoc, TraitId, TraitLoc, TypeAliasId, TypeAliasLoc, UnionId, - UnionLoc, UseId, UseLoc, VariantId, + EnumId, EnumLoc, EnumVariantId, EnumVariantLoc, ExternBlockId, ExternBlockLoc, ExternCrateId, + ExternCrateLoc, FunctionId, FunctionLoc, GenericDefId, ImplId, ImplLoc, LocalFieldId, Macro2Id, + Macro2Loc, MacroExpander, MacroId, MacroRulesId, MacroRulesLoc, MacroRulesLocFlags, + ProcMacroId, ProcMacroLoc, StaticId, StaticLoc, StructId, StructLoc, TraitId, TraitLoc, + TypeAliasId, TypeAliasLoc, UnionId, UnionLoc, UseId, UseLoc, VariantId, attrs::AttrFlags, - expr_store::{ - Body, BodySourceMap, ExpressionStore, ExpressionStoreSourceMap, scope::ExprScopes, - }, hir::generics::GenericParams, import_map::ImportMap, item_tree::{ItemTree, file_item_tree_query}, nameres::crate_def_map, - signatures::{ - ConstSignature, EnumSignature, FunctionSignature, ImplSignature, StaticSignature, - StructSignature, TraitSignature, TypeAliasSignature, UnionSignature, - }, visibility::{self, Visibility}, }; @@ -106,144 +98,10 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + SourceDatabase { #[salsa::invoke(macro_def)] fn macro_def(&self, m: MacroId) -> MacroDefId; - // region:data - - #[salsa::tracked] - fn trait_signature(&self, trait_: TraitId) -> Arc { - self.trait_signature_with_source_map(trait_).0 - } - - #[salsa::tracked] - fn impl_signature(&self, impl_: ImplId) -> Arc { - self.impl_signature_with_source_map(impl_).0 - } - - #[salsa::tracked] - fn struct_signature(&self, struct_: StructId) -> Arc { - self.struct_signature_with_source_map(struct_).0 - } - - #[salsa::tracked] - fn union_signature(&self, union_: UnionId) -> Arc { - self.union_signature_with_source_map(union_).0 - } - - #[salsa::tracked] - fn enum_signature(&self, e: EnumId) -> Arc { - self.enum_signature_with_source_map(e).0 - } - - #[salsa::tracked] - fn const_signature(&self, e: ConstId) -> Arc { - self.const_signature_with_source_map(e).0 - } - - #[salsa::tracked] - fn static_signature(&self, e: StaticId) -> Arc { - self.static_signature_with_source_map(e).0 - } - - #[salsa::tracked] - fn function_signature(&self, e: FunctionId) -> Arc { - self.function_signature_with_source_map(e).0 - } - - #[salsa::tracked] - fn type_alias_signature(&self, e: TypeAliasId) -> Arc { - self.type_alias_signature_with_source_map(e).0 - } - - #[salsa::invoke(TraitSignature::query)] - fn trait_signature_with_source_map( - &self, - trait_: TraitId, - ) -> (Arc, Arc); - - #[salsa::invoke(ImplSignature::query)] - fn impl_signature_with_source_map( - &self, - impl_: ImplId, - ) -> (Arc, Arc); - - #[salsa::invoke(StructSignature::query)] - fn struct_signature_with_source_map( - &self, - struct_: StructId, - ) -> (Arc, Arc); - - #[salsa::invoke(UnionSignature::query)] - fn union_signature_with_source_map( - &self, - union_: UnionId, - ) -> (Arc, Arc); - - #[salsa::invoke(EnumSignature::query)] - fn enum_signature_with_source_map( - &self, - e: EnumId, - ) -> (Arc, Arc); - - #[salsa::invoke(ConstSignature::query)] - fn const_signature_with_source_map( - &self, - e: ConstId, - ) -> (Arc, Arc); - - #[salsa::invoke(StaticSignature::query)] - fn static_signature_with_source_map( - &self, - e: StaticId, - ) -> (Arc, Arc); - - #[salsa::invoke(FunctionSignature::query)] - fn function_signature_with_source_map( - &self, - e: FunctionId, - ) -> (Arc, Arc); - - #[salsa::invoke(TypeAliasSignature::query)] - fn type_alias_signature_with_source_map( - &self, - e: TypeAliasId, - ) -> (Arc, Arc); - - // endregion:data - - #[salsa::invoke(Body::body_with_source_map_query)] - #[salsa::lru(512)] - fn body_with_source_map(&self, def: DefWithBodyId) -> (Arc, Arc); - - #[salsa::invoke(Body::body_query)] - fn body(&self, def: DefWithBodyId) -> Arc; - - #[salsa::invoke(ExprScopes::body_expr_scopes_query)] - fn body_expr_scopes(&self, def: DefWithBodyId) -> Arc; - - #[salsa::invoke(ExprScopes::sig_expr_scopes_query)] - fn sig_expr_scopes(&self, def: GenericDefId) -> Arc; - - #[salsa::transparent] - #[salsa::invoke(ExprScopes::expr_scopes_query)] - fn expr_scopes(&self, def: ExpressionStoreOwner) -> Arc; - #[salsa::transparent] #[salsa::invoke(GenericParams::new)] fn generic_params(&self, def: GenericDefId) -> Arc; - #[salsa::transparent] - #[salsa::invoke(GenericParams::generic_params_and_store)] - fn generic_params_and_store( - &self, - def: GenericDefId, - ) -> (Arc, Arc); - - #[salsa::transparent] - #[salsa::invoke(GenericParams::generic_params_and_store_and_source_map)] - fn generic_params_and_store_and_source_map( - &self, - def: GenericDefId, - ) -> (Arc, Arc, Arc); - #[salsa::invoke(ImportMap::import_map_query)] fn import_map(&self, krate: Crate) -> Arc; 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 b5436f3ba338..1ae89e170d9c 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 @@ -9,10 +9,7 @@ #[cfg(test)] mod tests; -use std::{ - ops::{Deref, Index}, - sync::LazyLock, -}; +use std::ops::{Deref, Index}; use cfg::{CfgExpr, CfgOptions}; use either::Either; @@ -23,11 +20,10 @@ use span::{Edition, SyntaxContext}; use syntax::{AstPtr, SyntaxNodePtr, ast}; use thin_vec::ThinVec; -use triomphe::Arc; use tt::TextRange; use crate::{ - BlockId, SyntheticSyntax, + AdtId, BlockId, ExpressionStoreOwnerId, GenericDefId, SyntheticSyntax, db::DefDatabase, expr_store::path::Path, hir::{ @@ -431,13 +427,85 @@ pub fn finish(self) -> (ExpressionStore, ExpressionStoreSourceMap) { } impl ExpressionStore { - pub fn empty_singleton() -> (Arc, Arc) { - static EMPTY: LazyLock<(Arc, Arc)> = - LazyLock::new(|| { - let (store, source_map) = ExpressionStoreBuilder::default().finish(); - (Arc::new(store), Arc::new(source_map)) - }); - EMPTY.clone() + pub fn of(db: &dyn DefDatabase, def: ExpressionStoreOwnerId) -> &ExpressionStore { + match def { + ExpressionStoreOwnerId::Signature(def) => { + use crate::signatures::{ + ConstSignature, EnumSignature, FunctionSignature, ImplSignature, + StaticSignature, StructSignature, TraitSignature, TypeAliasSignature, + UnionSignature, + }; + match def { + GenericDefId::AdtId(AdtId::EnumId(id)) => &EnumSignature::of(db, id).store, + GenericDefId::AdtId(AdtId::StructId(id)) => &StructSignature::of(db, id).store, + GenericDefId::AdtId(AdtId::UnionId(id)) => &UnionSignature::of(db, id).store, + GenericDefId::ConstId(id) => &ConstSignature::of(db, id).store, + GenericDefId::FunctionId(id) => &FunctionSignature::of(db, id).store, + GenericDefId::ImplId(id) => &ImplSignature::of(db, id).store, + GenericDefId::StaticId(id) => &StaticSignature::of(db, id).store, + GenericDefId::TraitId(id) => &TraitSignature::of(db, id).store, + GenericDefId::TypeAliasId(id) => &TypeAliasSignature::of(db, id).store, + } + } + ExpressionStoreOwnerId::Body(body) => &Body::of(db, body).store, + } + } + + pub fn with_source_map( + db: &dyn DefDatabase, + def: ExpressionStoreOwnerId, + ) -> (&ExpressionStore, &ExpressionStoreSourceMap) { + match def { + ExpressionStoreOwnerId::Signature(def) => { + use crate::signatures::{ + ConstSignature, EnumSignature, FunctionSignature, ImplSignature, + StaticSignature, StructSignature, TraitSignature, TypeAliasSignature, + UnionSignature, + }; + match def { + GenericDefId::AdtId(AdtId::EnumId(id)) => { + let sig = EnumSignature::with_source_map(db, id); + (&sig.0.store, &sig.1) + } + GenericDefId::AdtId(AdtId::StructId(id)) => { + let sig = StructSignature::with_source_map(db, id); + (&sig.0.store, &sig.1) + } + GenericDefId::AdtId(AdtId::UnionId(id)) => { + let sig = UnionSignature::with_source_map(db, id); + (&sig.0.store, &sig.1) + } + GenericDefId::ConstId(id) => { + let sig = ConstSignature::with_source_map(db, id); + (&sig.0.store, &sig.1) + } + GenericDefId::FunctionId(id) => { + let sig = FunctionSignature::with_source_map(db, id); + (&sig.0.store, &sig.1) + } + GenericDefId::ImplId(id) => { + let sig = ImplSignature::with_source_map(db, id); + (&sig.0.store, &sig.1) + } + GenericDefId::StaticId(id) => { + let sig = StaticSignature::with_source_map(db, id); + (&sig.0.store, &sig.1) + } + GenericDefId::TraitId(id) => { + let sig = TraitSignature::with_source_map(db, id); + (&sig.0.store, &sig.1) + } + GenericDefId::TypeAliasId(id) => { + let sig = TypeAliasSignature::with_source_map(db, id); + (&sig.0.store, &sig.1) + } + } + } + ExpressionStoreOwnerId::Body(body) => { + let (store, sm) = Body::with_source_map(db, body); + (&store.store, &sm.store) + } + } } /// Returns all const expression root `ExprId`s found in this store. diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/body.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/body.rs index ad8fa73ad839..60aaba5b84db 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/body.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/body.rs @@ -68,11 +68,10 @@ fn deref(&self) -> &Self::Target { } } +#[salsa::tracked] impl Body { - pub(crate) fn body_with_source_map_query( - db: &dyn DefDatabase, - def: DefWithBodyId, - ) -> (Arc, Arc) { + #[salsa::tracked(lru = 512, returns(ref))] + pub fn with_source_map(db: &dyn DefDatabase, def: DefWithBodyId) -> (Arc, BodySourceMap) { let _p = tracing::info_span!("body_with_source_map_query").entered(); let mut params = None; @@ -106,13 +105,16 @@ pub(crate) fn body_with_source_map_query( let module = def.module(db); let (body, source_map) = lower_body(db, def, file_id, module, params, body, is_async_fn); - (Arc::new(body), Arc::new(source_map)) + (Arc::new(body), source_map) } - pub(crate) fn body_query(db: &dyn DefDatabase, def: DefWithBodyId) -> Arc { - db.body_with_source_map(def).0 + #[salsa::tracked(returns(deref))] + pub fn of(db: &dyn DefDatabase, def: DefWithBodyId) -> Arc { + Self::with_source_map(db, def).0.clone() } +} +impl Body { pub fn pretty_print( &self, db: &dyn DefDatabase, 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 67ce5eafc6d8..3ed1b587411c 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 @@ -53,6 +53,7 @@ item_tree::FieldsShape, lang_item::{LangItemTarget, LangItems}, nameres::{DefMap, LocalDefMap, MacroSubNs, block_def_map}, + signatures::StructSignature, type_ref::{ ArrayType, ConstRef, FnType, LifetimeRef, LifetimeRefId, Mutability, PathId, Rawness, RefType, TraitBoundModifier, TraitRef, TypeBound, TypeRef, TypeRefId, UseArgRef, @@ -200,13 +201,13 @@ pub(crate) fn lower_generic_params( file_id: HirFileId, param_list: Option, where_clause: Option, -) -> (Arc, Arc, ExpressionStoreSourceMap) { +) -> (ExpressionStore, Arc, ExpressionStoreSourceMap) { let mut expr_collector = ExprCollector::signature(db, module, file_id); let mut collector = generics::GenericParamsCollector::new(def); collector.lower(&mut expr_collector, param_list, where_clause); let params = collector.finish(); let (store, source_map) = expr_collector.store.finish(); - (Arc::new(store), params, source_map) + (store, params, source_map) } pub(crate) fn lower_impl( @@ -2363,7 +2364,7 @@ fn collect_pat(&mut self, pat: ast::Pat, binding_list: &mut BindingList) -> PatI } Some(ModuleDefId::AdtId(AdtId::StructId(s))) // FIXME: This can cause a cycle if the user is writing invalid code - if self.db.struct_signature(s).shape != FieldsShape::Record => + if StructSignature::of(self.db, s).shape != FieldsShape::Record => { (None, Pat::Path(name.into())) } 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 35f3cd114e36..405ebe9b7bc9 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 @@ -168,8 +168,8 @@ pub fn print_signature(db: &dyn DefDatabase, owner: GenericDefId, edition: Editi match owner { GenericDefId::AdtId(id) => match id { AdtId::StructId(id) => { - let signature = db.struct_signature(id); - print_struct(db, id, &signature, edition) + let signature = StructSignature::of(db, id); + print_struct(db, id, signature, edition) } AdtId::UnionId(id) => { format!("unimplemented {id:?}") @@ -180,8 +180,8 @@ pub fn print_signature(db: &dyn DefDatabase, owner: GenericDefId, edition: Editi }, GenericDefId::ConstId(id) => format!("unimplemented {id:?}"), GenericDefId::FunctionId(id) => { - let signature = db.function_signature(id); - print_function(db, id, &signature, edition) + let signature = FunctionSignature::of(db, id); + print_function(db, id, signature, edition) } GenericDefId::ImplId(id) => format!("unimplemented {id:?}"), GenericDefId::StaticId(id) => format!("unimplemented {id:?}"), 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 43ce053836c4..2250cf5f1638 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 @@ -1,13 +1,15 @@ //! Name resolution for expressions. use hir_expand::{MacroDefId, name::Name}; use la_arena::{Arena, ArenaMap, Idx, IdxRange, RawIdx}; -use triomphe::Arc; use crate::{ - BlockId, DefWithBodyId, ExpressionStoreOwner, GenericDefId, + BlockId, DefWithBodyId, ExpressionStoreOwnerId, GenericDefId, db::DefDatabase, expr_store::{Body, ExpressionStore, HygieneId}, - hir::{Binding, BindingId, Expr, ExprId, Item, LabelId, Pat, PatId, Statement}, + hir::{ + Binding, BindingId, Expr, ExprId, Item, LabelId, Pat, PatId, Statement, + generics::GenericParams, + }, }; pub type ScopeId = Idx; @@ -50,36 +52,33 @@ pub struct ScopeData { entries: IdxRange, } +#[salsa::tracked] impl ExprScopes { - pub(crate) fn expr_scopes_query( - db: &dyn DefDatabase, - def: ExpressionStoreOwner, - ) -> Arc { - match def { - ExpressionStoreOwner::Body(def) => db.body_expr_scopes(def), - ExpressionStoreOwner::Signature(def) => db.sig_expr_scopes(def), - } - } - - pub(crate) fn body_expr_scopes_query( - db: &dyn DefDatabase, - def: DefWithBodyId, - ) -> Arc { - let body = db.body(def); - let mut scopes = ExprScopes::new_body(&body); + #[salsa::tracked(returns(ref))] + pub fn body_expr_scopes(db: &dyn DefDatabase, def: DefWithBodyId) -> ExprScopes { + let body = Body::of(db, def); + let mut scopes = ExprScopes::new_body(body); scopes.shrink_to_fit(); - Arc::new(scopes) + scopes } - pub(crate) fn sig_expr_scopes_query( - db: &dyn DefDatabase, - def: GenericDefId, - ) -> Arc { - let (_, store) = db.generic_params_and_store(def); + #[salsa::tracked(returns(ref))] + pub fn sig_expr_scopes(db: &dyn DefDatabase, def: GenericDefId) -> ExprScopes { + let (_, store) = GenericParams::of(db, def); let roots = store.signature_const_expr_roots(); - let mut scopes = ExprScopes::new_store(&store, roots); + let mut scopes = ExprScopes::new_store(store, roots); scopes.shrink_to_fit(); - Arc::new(scopes) + scopes + } +} + +impl ExprScopes { + #[inline] + pub fn of(db: &dyn DefDatabase, def: impl Into) -> &ExprScopes { + match def.into() { + ExpressionStoreOwnerId::Body(def) => Self::body_expr_scopes(db, def), + ExpressionStoreOwnerId::Signature(def) => Self::sig_expr_scopes(db, def), + } } pub fn entries(&self, scope: ScopeId) -> &[ScopeEntry] { @@ -367,7 +366,9 @@ mod tests { use test_utils::{assert_eq_text, extract_offset}; use crate::{ - DefWithBodyId, FunctionId, ModuleDefId, db::DefDatabase, nameres::crate_def_map, + DefWithBodyId, FunctionId, ModuleDefId, + expr_store::{Body, scope::ExprScopes}, + nameres::crate_def_map, test_db::TestDB, }; @@ -404,8 +405,8 @@ fn do_check(#[rust_analyzer::rust_fixture] ra_fixture: &str, expected: &[&str]) let marker: ast::PathExpr = find_node_at_offset(&file_syntax, offset).unwrap(); let function = find_function(&db, file_id); - let scopes = db.expr_scopes(DefWithBodyId::from(function).into()); - let (_body, source_map) = db.body_with_source_map(function.into()); + let scopes = ExprScopes::of(&db, DefWithBodyId::from(function)); + let (_body, source_map) = Body::with_source_map(&db, function.into()); let expr_id = source_map .node_expr(InFile { file_id: editioned_file_id.into(), value: &marker.into() }) @@ -563,8 +564,8 @@ fn do_check_local_name(#[rust_analyzer::rust_fixture] ra_fixture: &str, expected let function = find_function(&db, file_id); - let scopes = db.expr_scopes(DefWithBodyId::from(function).into()); - let (_, source_map) = db.body_with_source_map(function.into()); + let scopes = ExprScopes::body_expr_scopes(&db, DefWithBodyId::from(function)); + let (_, source_map) = Body::with_source_map(&db, function.into()); let expr_scope = { let expr_ast = name_ref.syntax().ancestors().find_map(ast::Expr::cast).unwrap(); 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 8f857aeeff95..985cd9666267 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 @@ -4,11 +4,10 @@ use expect_test::{Expect, expect}; use la_arena::RawIdx; use test_fixture::WithFixture; -use triomphe::Arc; use super::super::*; -fn lower(#[rust_analyzer::rust_fixture] ra_fixture: &str) -> (TestDB, Arc, DefWithBodyId) { +fn lower(#[rust_analyzer::rust_fixture] ra_fixture: &str) -> (TestDB, DefWithBodyId) { let db = TestDB::with_files(ra_fixture); let krate = db.fetch_test_crate(); @@ -24,8 +23,27 @@ fn lower(#[rust_analyzer::rust_fixture] ra_fixture: &str) -> (TestDB, Arc, } let fn_def = fn_def.unwrap().into(); - let body = db.body(fn_def); - (db, body, fn_def) + Body::of(&db, fn_def); + (db, fn_def) +} + +fn pretty_print(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) { + let db = TestDB::with_files(ra_fixture); + + let krate = db.fetch_test_crate(); + let def_map = crate_def_map(&db, krate); + let mut fn_def = None; + 'outer: for (_, module) in def_map.modules() { + for decl in module.scope.declarations() { + if let ModuleDefId::FunctionId(it) = decl { + fn_def = Some(it); + break 'outer; + } + } + } + let fn_def = fn_def.unwrap().into(); + + expect.assert_eq(&Body::of(&db, fn_def).pretty_print(&db, fn_def, Edition::CURRENT)); } fn def_map_at(#[rust_analyzer::rust_fixture] ra_fixture: &str) -> String { @@ -144,7 +162,7 @@ fn outer() { #[test] fn desugar_for_loop() { - let (db, body, def) = lower( + pretty_print( r#" //- minicore: iterator fn main() { @@ -154,9 +172,7 @@ fn main() { } } "#, - ); - - expect![[r#" + expect![[r#" fn main() { match builtin#lang(into_iter)( 0..10, @@ -173,13 +189,13 @@ fn main() { } }, } - }"#]] - .assert_eq(&body.pretty_print(&db, def, Edition::CURRENT)) + }"#]], + ); } #[test] fn desugar_builtin_format_args_before_1_89_0() { - let (db, body, def) = lower( + pretty_print( r#" //- minicore: fmt_before_1_89_0 fn main() { @@ -188,9 +204,7 @@ fn main() { builtin#format_args("\u{1b}hello {count:02} {} friends, we {are:?} {0}{last}", "fancy", orphan = (), last = "!"); } "#, - ); - - expect![[r#" + expect![[r#" fn main() { let are = "are"; let count = 10; @@ -256,13 +270,13 @@ fn main() { } }, ); - }"#]] - .assert_eq(&body.pretty_print(&db, def, Edition::CURRENT)) + }"#]], + ) } #[test] fn desugar_builtin_format_args_before_1_93_0() { - let (db, body, def) = lower( + pretty_print( r#" //- minicore: fmt_before_1_93_0 fn main() { @@ -271,9 +285,7 @@ fn main() { builtin#format_args("\u{1b}hello {count:02} {} friends, we {are:?} {0}{last}", "fancy", orphan = (), last = "!"); } "#, - ); - - expect![[r#" + expect![[r#" fn main() { let are = "are"; let count = 10; @@ -339,13 +351,13 @@ fn main() { ) } }; - }"#]] - .assert_eq(&body.pretty_print(&db, def, Edition::CURRENT)) + }"#]], + ) } #[test] fn desugar_builtin_format_args() { - let (db, body, def) = lower( + pretty_print( r#" //- minicore: fmt fn main() { @@ -356,9 +368,7 @@ fn main() { builtin#format_args("hello world", orphan = ()); } "#, - ); - - expect![[r#" + expect![[r#" fn main() { let are = "are"; let count = 10; @@ -392,13 +402,13 @@ fn main() { "hello world", ) }; - }"#]] - .assert_eq(&body.pretty_print(&db, def, Edition::CURRENT)) + }"#]], + ) } #[test] fn test_macro_hygiene() { - let (db, body, def) = lower( + pretty_print( r##" //- minicore: fmt, from //- /main.rs @@ -428,10 +438,7 @@ pub(crate) fn new(message: impl Into) -> SsrError { } } "##, - ); - - assert_eq!(db.body_with_source_map(def).1.diagnostics(), &[]); - expect![[r#" + expect![[r#" fn main() { _ = ra_test_fixture::error::SsrError::new( { @@ -449,13 +456,13 @@ fn main() { } }, ); - }"#]] - .assert_eq(&body.pretty_print(&db, def, Edition::CURRENT)) + }"#]], + ) } #[test] fn regression_10300() { - let (db, body, def) = lower( + pretty_print( r#" //- minicore: concat, panic, fmt_before_1_89_0 mod private { @@ -472,16 +479,7 @@ fn f(a: i32, b: u32) -> String { m!(); } "#, - ); - - let (_, source_map) = db.body_with_source_map(def); - assert_eq!(source_map.diagnostics(), &[]); - - for (_, def_map) in body.blocks(&db) { - assert_eq!(def_map.diagnostics(), &[]); - } - - expect![[r#" + expect![[r#" fn f(a, b) { { core::panicking::panic_fmt( @@ -497,8 +495,8 @@ fn f(a, b) { ), ); }; - }"#]] - .assert_eq(&body.pretty_print(&db, def, Edition::CURRENT)) + }"#]], + ) } #[test] @@ -507,7 +505,7 @@ fn destructuring_assignment_tuple_macro() { // but in destructuring assignment it is valid, because `m!()()` is a valid expression, and destructuring // assignments start their lives as expressions. So we have to do the same. - let (db, body, def) = lower( + pretty_print( r#" struct Bar(); @@ -519,25 +517,16 @@ fn foo() { m!()() = Bar(); } "#, - ); - - let (_, source_map) = db.body_with_source_map(def); - assert_eq!(source_map.diagnostics(), &[]); - - for (_, def_map) in body.blocks(&db) { - assert_eq!(def_map.diagnostics(), &[]); - } - - expect![[r#" + expect![[r#" fn foo() { Bar() = Bar(); - }"#]] - .assert_eq(&body.pretty_print(&db, def, Edition::CURRENT)) + }"#]], + ) } #[test] fn shadowing_record_variant() { - let (_, body, _) = lower( + let (db, def) = lower( r#" enum A { B { field: i32 }, @@ -550,6 +539,7 @@ fn f() { } "#, ); + let body = Body::of(&db, def); assert_eq!(body.assert_expr_only().bindings.len(), 1, "should have a binding for `B`"); assert_eq!( body[BindingId::from_raw(RawIdx::from_u32(0))].name.as_str(), @@ -560,39 +550,35 @@ fn f() { #[test] fn regression_pretty_print_bind_pat() { - let (db, body, owner) = lower( + pretty_print( r#" fn foo() { let v @ u = 123; } "#, - ); - let printed = body.pretty_print(&db, owner, Edition::CURRENT); - - expect![[r#" + expect![[r#" fn foo() { let v @ u = 123; - }"#]] - .assert_eq(&printed); + }"#]], + ); } #[test] fn skip_skips_body() { - let (db, body, owner) = lower( + pretty_print( r#" #[rust_analyzer::skip] async fn foo(a: (), b: i32) -> u32 { 0 + 1 + b() } "#, + expect!["fn foo(�, �) �"], ); - let printed = body.pretty_print(&db, owner, Edition::CURRENT); - expect!["fn foo(�, �) �"].assert_eq(&printed); } #[test] fn range_bounds_are_hir_exprs() { - let (_, body, _) = lower( + let (db, body) = lower( r#" pub const L: i32 = 6; mod x { @@ -607,6 +593,7 @@ const fn f(x: i32) -> i32 { }"#, ); + let body = Body::of(&db, body); let mtch_arms = body .assert_expr_only() .exprs @@ -635,7 +622,7 @@ const fn f(x: i32) -> i32 { #[test] fn print_hir_precedences() { - let (db, body, def) = lower( + pretty_print( r#" fn main() { _ = &(1 - (2 - 3) + 4 * 5 * (6 + 7)); @@ -646,9 +633,7 @@ fn main() { let _ = &mut (*r as i32) } "#, - ); - - expect![[r#" + expect![[r#" fn main() { _ = &((1 - (2 - 3)) + (4 * 5) * (6 + 7)); _ = 1 + 2 < 3 && true && 4 < 5 && (a || b || c) || d && e; @@ -656,24 +641,22 @@ fn main() { break a && b || (return) || (return 2); let r = &2; let _ = &mut (*r as i32); - }"#]] - .assert_eq(&body.pretty_print(&db, def, Edition::CURRENT)) + }"#]], + ) } #[test] fn async_fn_weird_param_patterns() { - let (db, body, def) = lower( + pretty_print( r#" async fn main(&self, param1: i32, ref mut param2: i32, _: i32, param4 @ _: i32, 123: i32) {} "#, - ); - - expect![[r#" + expect![[r#" fn main(self, param1, mut param2, mut 0, param4 @ _, mut 1) async { let ref mut param2 = param2; let _ = 0; let 123 = 1; {} - }"#]] - .assert_eq(&body.pretty_print(&db, def, Edition::CURRENT)) + }"#]], + ) } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/signatures.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/signatures.rs index f1db00cf6a67..5e0184dfad82 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/signatures.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/signatures.rs @@ -2,6 +2,7 @@ GenericDefId, ModuleDefId, expr_store::pretty::{print_function, print_struct}, nameres::crate_def_map, + signatures::{FunctionSignature, StructSignature}, test_db::TestDB, }; use expect_test::{Expect, expect}; @@ -41,7 +42,7 @@ fn lower_and_print(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expe out += &print_struct( &db, struct_id, - &db.struct_signature(struct_id), + StructSignature::of(&db, struct_id), Edition::CURRENT, ); } @@ -53,7 +54,7 @@ fn lower_and_print(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expe out += &print_function( &db, function_id, - &db.function_signature(function_id), + FunctionSignature::of(&db, function_id), Edition::CURRENT, ) } 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 022f8adfdb06..41767131fc3b 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 @@ -11,6 +11,10 @@ AdtId, ConstParamId, GenericDefId, LifetimeParamId, TypeOrConstParamId, TypeParamId, db::DefDatabase, expr_store::{ExpressionStore, ExpressionStoreSourceMap}, + signatures::{ + ConstSignature, EnumSignature, FunctionSignature, ImplSignature, StaticSignature, + StructSignature, TraitSignature, TypeAliasSignature, UnionSignature, + }, type_ref::{ConstRef, LifetimeRefId, TypeBound, TypeRefId}, }; @@ -188,111 +192,90 @@ impl GenericParams { LocalTypeOrConstParamId::from_raw(RawIdx::from_u32(0)); pub fn new(db: &dyn DefDatabase, def: GenericDefId) -> Arc { + Self::of(db, def).0 + } + + pub fn of(db: &dyn DefDatabase, def: GenericDefId) -> (Arc, &ExpressionStore) { match def { - GenericDefId::AdtId(AdtId::EnumId(it)) => db.enum_signature(it).generic_params.clone(), - GenericDefId::AdtId(AdtId::StructId(it)) => { - db.struct_signature(it).generic_params.clone() + GenericDefId::AdtId(AdtId::EnumId(id)) => { + let sig = EnumSignature::of(db, id); + (sig.generic_params.clone(), &sig.store) } - GenericDefId::AdtId(AdtId::UnionId(it)) => { - db.union_signature(it).generic_params.clone() + GenericDefId::AdtId(AdtId::StructId(id)) => { + let sig = StructSignature::of(db, id); + (sig.generic_params.clone(), &sig.store) } - GenericDefId::ConstId(_) => EMPTY.clone(), - GenericDefId::FunctionId(function_id) => { - db.function_signature(function_id).generic_params.clone() + GenericDefId::AdtId(AdtId::UnionId(id)) => { + let sig = UnionSignature::of(db, id); + (sig.generic_params.clone(), &sig.store) } - GenericDefId::ImplId(impl_id) => db.impl_signature(impl_id).generic_params.clone(), - GenericDefId::StaticId(_) => EMPTY.clone(), - GenericDefId::TraitId(trait_id) => db.trait_signature(trait_id).generic_params.clone(), - GenericDefId::TypeAliasId(type_alias_id) => { - db.type_alias_signature(type_alias_id).generic_params.clone() + GenericDefId::FunctionId(id) => { + let sig = FunctionSignature::of(db, id); + (sig.generic_params.clone(), &sig.store) + } + GenericDefId::ImplId(id) => { + let sig = ImplSignature::of(db, id); + (sig.generic_params.clone(), &sig.store) + } + GenericDefId::TraitId(id) => { + let sig = TraitSignature::of(db, id); + (sig.generic_params.clone(), &sig.store) + } + GenericDefId::TypeAliasId(id) => { + let sig = TypeAliasSignature::of(db, id); + (sig.generic_params.clone(), &sig.store) + } + GenericDefId::ConstId(id) => { + let sig = ConstSignature::of(db, id); + (EMPTY.clone(), &sig.store) + } + GenericDefId::StaticId(id) => { + let sig = StaticSignature::of(db, id); + (EMPTY.clone(), &sig.store) } } } - pub fn generic_params_and_store( + pub fn with_source_map( db: &dyn DefDatabase, def: GenericDefId, - ) -> (Arc, Arc) { + ) -> (Arc, &ExpressionStore, &ExpressionStoreSourceMap) { match def { GenericDefId::AdtId(AdtId::EnumId(id)) => { - let sig = db.enum_signature(id); - (sig.generic_params.clone(), sig.store.clone()) + let (sig, sm) = EnumSignature::with_source_map(db, id); + (sig.generic_params.clone(), &sig.store, sm) } GenericDefId::AdtId(AdtId::StructId(id)) => { - let sig = db.struct_signature(id); - (sig.generic_params.clone(), sig.store.clone()) + let (sig, sm) = StructSignature::with_source_map(db, id); + (sig.generic_params.clone(), &sig.store, sm) } GenericDefId::AdtId(AdtId::UnionId(id)) => { - let sig = db.union_signature(id); - (sig.generic_params.clone(), sig.store.clone()) + let (sig, sm) = UnionSignature::with_source_map(db, id); + (sig.generic_params.clone(), &sig.store, sm) } GenericDefId::ConstId(id) => { - let sig = db.const_signature(id); - (EMPTY.clone(), sig.store.clone()) + let (sig, sm) = ConstSignature::with_source_map(db, id); + (EMPTY.clone(), &sig.store, sm) } GenericDefId::FunctionId(id) => { - let sig = db.function_signature(id); - (sig.generic_params.clone(), sig.store.clone()) + let (sig, sm) = FunctionSignature::with_source_map(db, id); + (sig.generic_params.clone(), &sig.store, sm) } GenericDefId::ImplId(id) => { - let sig = db.impl_signature(id); - (sig.generic_params.clone(), sig.store.clone()) + let (sig, sm) = ImplSignature::with_source_map(db, id); + (sig.generic_params.clone(), &sig.store, sm) } GenericDefId::StaticId(id) => { - let sig = db.static_signature(id); - (EMPTY.clone(), sig.store.clone()) + let (sig, sm) = StaticSignature::with_source_map(db, id); + (EMPTY.clone(), &sig.store, sm) } GenericDefId::TraitId(id) => { - let sig = db.trait_signature(id); - (sig.generic_params.clone(), sig.store.clone()) + let (sig, sm) = TraitSignature::with_source_map(db, id); + (sig.generic_params.clone(), &sig.store, sm) } GenericDefId::TypeAliasId(id) => { - let sig = db.type_alias_signature(id); - (sig.generic_params.clone(), sig.store.clone()) - } - } - } - - pub fn generic_params_and_store_and_source_map( - db: &dyn DefDatabase, - def: GenericDefId, - ) -> (Arc, Arc, Arc) { - match def { - GenericDefId::AdtId(AdtId::EnumId(id)) => { - let (sig, sm) = db.enum_signature_with_source_map(id); - (sig.generic_params.clone(), sig.store.clone(), sm) - } - GenericDefId::AdtId(AdtId::StructId(id)) => { - let (sig, sm) = db.struct_signature_with_source_map(id); - (sig.generic_params.clone(), sig.store.clone(), sm) - } - GenericDefId::AdtId(AdtId::UnionId(id)) => { - let (sig, sm) = db.union_signature_with_source_map(id); - (sig.generic_params.clone(), sig.store.clone(), sm) - } - GenericDefId::ConstId(id) => { - let (sig, sm) = db.const_signature_with_source_map(id); - (EMPTY.clone(), sig.store.clone(), sm) - } - GenericDefId::FunctionId(id) => { - let (sig, sm) = db.function_signature_with_source_map(id); - (sig.generic_params.clone(), sig.store.clone(), sm) - } - GenericDefId::ImplId(id) => { - let (sig, sm) = db.impl_signature_with_source_map(id); - (sig.generic_params.clone(), sig.store.clone(), sm) - } - GenericDefId::StaticId(id) => { - let (sig, sm) = db.static_signature_with_source_map(id); - (EMPTY.clone(), sig.store.clone(), sm) - } - GenericDefId::TraitId(id) => { - let (sig, sm) = db.trait_signature_with_source_map(id); - (sig.generic_params.clone(), sig.store.clone(), sm) - } - GenericDefId::TypeAliasId(id) => { - let (sig, sm) = db.type_alias_signature_with_source_map(id); - (sig.generic_params.clone(), sig.store.clone(), sm) + let (sig, sm) = TypeAliasSignature::with_source_map(db, id); + (sig.generic_params.clone(), &sig.store, sm) } } } 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 ffad5fee47ff..4387ef055fdd 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs @@ -49,7 +49,6 @@ use intern::{Interned, Symbol}; pub use rustc_abi as layout; use thin_vec::ThinVec; -use triomphe::Arc; pub use crate::signatures::LocalFieldId; @@ -96,7 +95,9 @@ block_def_map, crate_def_map, crate_local_def_map, diagnostics::DefDiagnostics, }, - signatures::{EnumVariants, InactiveEnumVariantCode, VariantFields}, + signatures::{ + ConstSignature, EnumVariants, InactiveEnumVariantCode, StaticSignature, VariantFields, + }, }; type FxIndexMap = indexmap::IndexMap; @@ -264,8 +265,9 @@ pub fn fields(self, db: &dyn DefDatabase) -> &VariantFields { pub fn fields_with_source_map( self, db: &dyn DefDatabase, - ) -> (Arc, Arc) { - VariantFields::query(db, self.into()) + ) -> (&VariantFields, &ExpressionStoreSourceMap) { + let r = VariantFields::with_source_map(db, self.into()); + (&r.0, &r.1) } } @@ -280,8 +282,9 @@ pub fn fields(self, db: &dyn DefDatabase) -> &VariantFields { pub fn fields_with_source_map( self, db: &dyn DefDatabase, - ) -> (Arc, Arc) { - VariantFields::query(db, self.into()) + ) -> (&VariantFields, &ExpressionStoreSourceMap) { + let r = VariantFields::with_source_map(db, self.into()); + (&r.0, &r.1) } } @@ -315,7 +318,7 @@ pub fn enum_variants_with_diagnostics( #[derive(Debug, Hash, PartialEq, Eq, Clone)] pub struct AnonConstLoc { /// The owner store containing this expression. - pub owner: ExpressionStoreOwner, + pub owner: ExpressionStoreOwnerId, /// The ExprId within the owner's ExpressionStore that is the root /// of this anonymous const expression. pub expr: ExprId, @@ -399,8 +402,9 @@ pub fn fields(self, db: &dyn DefDatabase) -> &VariantFields { pub fn fields_with_source_map( self, db: &dyn DefDatabase, - ) -> (Arc, Arc) { - VariantFields::query(db, self.into()) + ) -> (&VariantFields, &ExpressionStoreSourceMap) { + let r = VariantFields::with_source_map(db, self.into()); + (&r.0, &r.1) } } @@ -739,10 +743,10 @@ pub fn generic_def(self, db: &dyn DefDatabase) -> Option { pub fn name(self, db: &dyn DefDatabase) -> String { match self { GeneralConstId::StaticId(it) => { - db.static_signature(it).name.display(db, Edition::CURRENT).to_string() + StaticSignature::of(db, it).name.display(db, Edition::CURRENT).to_string() } GeneralConstId::ConstId(const_id) => { - db.const_signature(const_id).name.as_ref().map_or_else( + ConstSignature::of(db, const_id).name.as_ref().map_or_else( || "_".to_owned(), |name| name.display(db, Edition::CURRENT).to_string(), ) @@ -837,20 +841,21 @@ pub enum GenericDefId { /// This is used for queries that operate on expression stores generically, /// such as `expr_scopes`. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] -pub enum ExpressionStoreOwner { +pub enum ExpressionStoreOwnerId { Signature(GenericDefId), Body(DefWithBodyId), } -impl ExpressionStoreOwner { +impl ExpressionStoreOwnerId { + // FIXME: Check callers of this, this method likely can be removed pub fn as_def_with_body(self) -> Option { if let Self::Body(v) = self { Some(v) } else { None } } pub fn generic_def(self, db: &dyn DefDatabase) -> GenericDefId { match self { - ExpressionStoreOwner::Signature(generic_def_id) => generic_def_id, - ExpressionStoreOwner::Body(def_with_body_id) => match def_with_body_id { + ExpressionStoreOwnerId::Signature(generic_def_id) => generic_def_id, + ExpressionStoreOwnerId::Body(def_with_body_id) => match def_with_body_id { DefWithBodyId::FunctionId(id) => GenericDefId::FunctionId(id), DefWithBodyId::StaticId(id) => GenericDefId::StaticId(id), DefWithBodyId::ConstId(id) => GenericDefId::ConstId(id), @@ -860,15 +865,15 @@ pub fn generic_def(self, db: &dyn DefDatabase) -> GenericDefId { } } -impl From for ExpressionStoreOwner { +impl From for ExpressionStoreOwnerId { fn from(id: GenericDefId) -> Self { - ExpressionStoreOwner::Signature(id) + ExpressionStoreOwnerId::Signature(id) } } -impl From for ExpressionStoreOwner { +impl From for ExpressionStoreOwnerId { fn from(id: DefWithBodyId) -> Self { - ExpressionStoreOwner::Body(id) + ExpressionStoreOwnerId::Body(id) } } @@ -1028,8 +1033,9 @@ pub fn fields(self, db: &dyn DefDatabase) -> &VariantFields { pub fn fields_with_source_map( self, db: &dyn DefDatabase, - ) -> (Arc, Arc) { - VariantFields::query(db, self) + ) -> (&VariantFields, &ExpressionStoreSourceMap) { + let r = VariantFields::with_source_map(db, self); + (&r.0, &r.1) } pub fn file_id(self, db: &dyn DefDatabase) -> HirFileId { @@ -1230,11 +1236,11 @@ fn module(&self, db: &dyn DefDatabase) -> ModuleId { } } -impl HasModule for ExpressionStoreOwner { +impl HasModule for ExpressionStoreOwnerId { fn module(&self, db: &dyn DefDatabase) -> ModuleId { match self { - ExpressionStoreOwner::Signature(def) => def.module(db), - ExpressionStoreOwner::Body(def) => def.module(db), + ExpressionStoreOwnerId::Signature(def) => def.module(db), + ExpressionStoreOwnerId::Body(def) => def.module(db), } } } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs index 8ee93dcaa32d..8317c56caf76 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs @@ -45,6 +45,7 @@ use crate::{ AdtId, Lookup, ModuleDefId, db::DefDatabase, + expr_store::Body, nameres::{DefMap, ModuleSource, crate_def_map}, src::HasSource, test_db::TestDB, @@ -276,7 +277,7 @@ fn resolve_macro_call_id( _ => continue, }; - let (body, sm) = db.body_with_source_map(body); + let (body, sm) = Body::with_source_map(db, body); if let Some(it) = body .blocks(db) .find_map(|block| resolve_macro_call_id(db, block.1, ast_id, ast_ptr)) 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 38b461770cbf..9ffa80346c2f 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs @@ -17,7 +17,7 @@ use crate::{ AdtId, AstIdLoc, ConstId, ConstParamId, DefWithBodyId, EnumId, EnumVariantId, - ExpressionStoreOwner, ExternBlockId, ExternCrateId, FunctionId, FxIndexMap, GenericDefId, + ExpressionStoreOwnerId, ExternBlockId, ExternCrateId, FunctionId, FxIndexMap, GenericDefId, GenericParamId, HasModule, ImplId, ItemContainerId, LifetimeParamId, Lookup, Macro2Id, MacroId, MacroRulesId, ModuleDefId, ModuleId, ProcMacroId, StaticId, StructId, TraitId, TypeAliasId, TypeOrConstParamId, TypeParamId, UseId, VariantId, @@ -36,6 +36,7 @@ lang_item::LangItemTarget, nameres::{DefMap, LocalDefMap, MacroSubNs, ResolvePathResultPrefixInfo, block_def_map}, per_ns::PerNs, + signatures::ImplSignature, src::HasSource, type_ref::LifetimeRef, visibility::{RawVisibility, Visibility}, @@ -65,13 +66,13 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { } #[derive(Clone)] -struct ExprScope { - owner: ExpressionStoreOwner, - expr_scopes: Arc, +struct ExprScope<'db> { + owner: ExpressionStoreOwnerId, + expr_scopes: &'db ExprScopes, scope_id: ScopeId, } -impl fmt::Debug for ExprScope { +impl fmt::Debug for ExprScope<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("ExprScope") .field("owner", &self.owner) @@ -88,7 +89,7 @@ enum Scope<'db> { /// generic for ADTs and impls. GenericParams { def: GenericDefId, params: Arc }, /// Local bindings - ExprScope(ExprScope), + ExprScope(ExprScope<'db>), /// Macro definition inside bodies that affects all paths after it in the same block. MacroDefScope(MacroDefId), } @@ -653,7 +654,7 @@ pub fn traits_in_scope(&self, db: &dyn DefDatabase) -> FxHashSet { match scope { Scope::BlockScope(m) => traits.extend(m.def_map[m.module_id].scope.traits()), &Scope::GenericParams { def: GenericDefId::ImplId(impl_), .. } => { - let impl_data = db.impl_signature(impl_); + let impl_data = ImplSignature::of(db, impl_); if let Some(target_trait) = impl_data.target_trait && let Some(TypeNs::TraitId(trait_)) = self .resolve_path_in_type_ns_fully(db, &impl_data.store[target_trait.path]) @@ -736,12 +737,9 @@ pub fn all_generic_params(&self) -> impl Iterator Option { + pub fn expression_store_owner(&self) -> Option { self.scopes().find_map(|scope| match scope { - Scope::ExprScope(it) => match it.owner { - ExpressionStoreOwner::Body(def) => Some(def), - ExpressionStoreOwner::Signature(_) => None, - }, + Scope::ExprScope(it) => Some(it.owner), _ => None, }) } @@ -857,7 +855,7 @@ pub fn rename_will_conflict_with_renamed( pub fn update_to_inner_scope( &mut self, db: &'db dyn DefDatabase, - owner: impl Into, + owner: impl Into, expr_id: ExprId, ) -> UpdateGuard { self.update_to_inner_scope_(db, owner.into(), expr_id) @@ -866,25 +864,21 @@ pub fn update_to_inner_scope( fn update_to_inner_scope_( &mut self, db: &'db dyn DefDatabase, - owner: ExpressionStoreOwner, + owner: ExpressionStoreOwnerId, expr_id: ExprId, ) -> UpdateGuard { #[inline(always)] fn append_expr_scope<'db>( db: &'db dyn DefDatabase, resolver: &mut Resolver<'db>, - owner: ExpressionStoreOwner, - expr_scopes: &Arc, + owner: ExpressionStoreOwnerId, + expr_scopes: &'db ExprScopes, scope_id: ScopeId, ) { if let Some(macro_id) = expr_scopes.macro_def(scope_id) { resolver.scopes.push(Scope::MacroDefScope(**macro_id)); } - resolver.scopes.push(Scope::ExprScope(ExprScope { - owner, - expr_scopes: expr_scopes.clone(), - scope_id, - })); + resolver.scopes.push(Scope::ExprScope(ExprScope { owner, expr_scopes, scope_id })); if let Some(block) = expr_scopes.block(scope_id) { let def_map = block_def_map(db, block); let local_def_map = block.lookup(db).module.only_local_def_map(db); @@ -902,21 +896,20 @@ fn append_expr_scope<'db>( let start = self.scopes.len(); let innermost_scope = self.scopes().find(|scope| !matches!(scope, Scope::MacroDefScope(_))); match innermost_scope { - Some(&Scope::ExprScope(ExprScope { scope_id, ref expr_scopes, owner })) => { - let expr_scopes = expr_scopes.clone(); + Some(&Scope::ExprScope(ExprScope { scope_id, expr_scopes, owner })) => { let scope_chain = expr_scopes .scope_chain(expr_scopes.scope_for(expr_id)) .take_while(|&it| it != scope_id); for scope_id in scope_chain { - append_expr_scope(db, self, owner, &expr_scopes, scope_id); + append_expr_scope(db, self, owner, expr_scopes, scope_id); } } _ => { - let expr_scopes = db.expr_scopes(owner); + let expr_scopes = ExprScopes::of(db, owner); let scope_chain = expr_scopes.scope_chain(expr_scopes.scope_for(expr_id)); for scope_id in scope_chain { - append_expr_scope(db, self, owner, &expr_scopes, scope_id); + append_expr_scope(db, self, owner, expr_scopes, scope_id); } } } @@ -1072,21 +1065,21 @@ fn process_names(&self, acc: &mut ScopeNames, db: &'db dyn DefDatabase) { pub fn resolver_for_scope( db: &dyn DefDatabase, - owner: impl Into + HasResolver, + owner: impl Into + HasResolver, scope_id: Option, ) -> Resolver<'_> { let store_owner = owner.into(); let r = store_owner.resolver(db); - let scopes = db.expr_scopes(store_owner); + let scopes = ExprScopes::of(db, store_owner); resolver_for_scope_(db, scopes, scope_id, r, store_owner) } fn resolver_for_scope_<'db>( db: &'db dyn DefDatabase, - scopes: Arc, + scopes: &'db ExprScopes, scope_id: Option, mut r: Resolver<'db>, - owner: ExpressionStoreOwner, + owner: ExpressionStoreOwnerId, ) -> Resolver<'db> { let scope_chain = scopes.scope_chain(scope_id).collect::>(); r.scopes.reserve(scope_chain.len()); @@ -1106,7 +1099,7 @@ fn resolver_for_scope_<'db>( r = r.push_scope(Scope::MacroDefScope(**macro_id)); } - r = r.push_expr_scope(owner, Arc::clone(&scopes), scope); + r = r.push_expr_scope(owner, scopes, scope); } r } @@ -1137,8 +1130,8 @@ fn push_block_scope( fn push_expr_scope( self, - owner: ExpressionStoreOwner, - expr_scopes: Arc, + owner: ExpressionStoreOwnerId, + expr_scopes: &'db ExprScopes, scope_id: ScopeId, ) -> Resolver<'db> { self.push_scope(Scope::ExprScope(ExprScope { owner, expr_scopes, scope_id })) @@ -1422,11 +1415,11 @@ fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> { } } -impl HasResolver for ExpressionStoreOwner { +impl HasResolver for ExpressionStoreOwnerId { fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> { match self { - ExpressionStoreOwner::Signature(def) => def.resolver(db), - ExpressionStoreOwner::Body(def) => def.resolver(db), + ExpressionStoreOwnerId::Signature(def) => def.resolver(db), + ExpressionStoreOwnerId::Body(def) => def.resolver(db), } } } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/signatures.rs b/src/tools/rust-analyzer/crates/hir-def/src/signatures.rs index ce76158151c3..7862049f993e 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/signatures.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/signatures.rs @@ -24,7 +24,7 @@ attrs::AttrFlags, db::DefDatabase, expr_store::{ - ExpressionStore, ExpressionStoreSourceMap, + Body, ExpressionStore, ExpressionStoreBuilder, ExpressionStoreSourceMap, lower::{ ExprCollector, lower_function, lower_generic_params, lower_trait, lower_type_alias, }, @@ -44,7 +44,7 @@ fn as_name_opt(name: Option) -> Name { pub struct StructSignature { pub name: Name, pub generic_params: Arc, - pub store: Arc, + pub store: ExpressionStore, pub flags: StructFlags, pub shape: FieldsShape, } @@ -71,8 +71,18 @@ pub struct StructFlags: u8 { } } +#[salsa::tracked] impl StructSignature { - pub fn query(db: &dyn DefDatabase, id: StructId) -> (Arc, Arc) { + #[salsa::tracked(returns(deref))] + pub fn of(db: &dyn DefDatabase, id: StructId) -> Arc { + Self::with_source_map(db, id).0.clone() + } + + #[salsa::tracked(returns(ref))] + pub fn with_source_map( + db: &dyn DefDatabase, + id: StructId, + ) -> (Arc, ExpressionStoreSourceMap) { let loc = id.lookup(db); let InFile { file_id, value: source } = loc.source(db); let attrs = AttrFlags::query(db, id.into()); @@ -115,10 +125,12 @@ pub fn query(db: &dyn DefDatabase, id: StructId) -> (Arc, Arc Option { if self.flags.contains(StructFlags::HAS_REPR) { @@ -142,12 +154,22 @@ fn adt_shape(adt_kind: ast::StructKind) -> FieldsShape { pub struct UnionSignature { pub name: Name, pub generic_params: Arc, - pub store: Arc, + pub store: ExpressionStore, pub flags: StructFlags, } +#[salsa::tracked] impl UnionSignature { - pub fn query(db: &dyn DefDatabase, id: UnionId) -> (Arc, Arc) { + #[salsa::tracked(returns(deref))] + pub fn of(db: &dyn DefDatabase, id: UnionId) -> Arc { + Self::with_source_map(db, id).0.clone() + } + + #[salsa::tracked(returns(ref))] + pub fn with_source_map( + db: &dyn DefDatabase, + id: UnionId, + ) -> (Arc, ExpressionStoreSourceMap) { let loc = id.lookup(db); let attrs = AttrFlags::query(db, id.into()); let mut flags = StructFlags::empty(); @@ -177,7 +199,7 @@ pub fn query(db: &dyn DefDatabase, id: UnionId) -> (Arc, Arc, - pub store: Arc, + pub store: ExpressionStore, pub flags: EnumFlags, } +#[salsa::tracked] impl EnumSignature { - pub fn query(db: &dyn DefDatabase, id: EnumId) -> (Arc, Arc) { + #[salsa::tracked(returns(deref))] + pub fn of(db: &dyn DefDatabase, id: EnumId) -> Arc { + Self::with_source_map(db, id).0.clone() + } + + #[salsa::tracked(returns(ref))] + pub fn with_source_map( + db: &dyn DefDatabase, + id: EnumId, + ) -> (Arc, ExpressionStoreSourceMap) { let loc = id.lookup(db); let attrs = AttrFlags::query(db, id.into()); let mut flags = EnumFlags::empty(); @@ -229,10 +261,12 @@ pub fn query(db: &dyn DefDatabase, id: EnumId) -> (Arc, Arc IntegerType { match AttrFlags::repr(db, id.into()) { Some(ReprOptions { int: Some(builtin), .. }) => builtin, @@ -257,13 +291,23 @@ pub struct ConstFlags: u8 { pub struct ConstSignature { pub name: Option, // generic_params: Arc, - pub store: Arc, + pub store: ExpressionStore, pub type_ref: TypeRefId, pub flags: ConstFlags, } +#[salsa::tracked] impl ConstSignature { - pub fn query(db: &dyn DefDatabase, id: ConstId) -> (Arc, Arc) { + #[salsa::tracked(returns(deref))] + pub fn of(db: &dyn DefDatabase, id: ConstId) -> Arc { + Self::with_source_map(db, id).0.clone() + } + + #[salsa::tracked(returns(ref))] + pub fn with_source_map( + db: &dyn DefDatabase, + id: ConstId, + ) -> (Arc, ExpressionStoreSourceMap) { let loc = id.lookup(db); let module = loc.container.module(db); @@ -282,15 +326,17 @@ pub fn query(db: &dyn DefDatabase, id: ConstId) -> (Arc, Arc bool { self.flags.contains(ConstFlags::HAS_BODY) } @@ -313,12 +359,23 @@ pub struct StaticSignature { pub name: Name, // generic_params: Arc, - pub store: Arc, + pub store: ExpressionStore, pub type_ref: TypeRefId, pub flags: StaticFlags, } + +#[salsa::tracked] impl StaticSignature { - pub fn query(db: &dyn DefDatabase, id: StaticId) -> (Arc, Arc) { + #[salsa::tracked(returns(deref))] + pub fn of(db: &dyn DefDatabase, id: StaticId) -> Arc { + Self::with_source_map(db, id).0.clone() + } + + #[salsa::tracked(returns(ref))] + pub fn with_source_map( + db: &dyn DefDatabase, + id: StaticId, + ) -> (Arc, ExpressionStoreSourceMap) { let loc = id.lookup(db); let module = loc.container.module(db); @@ -351,12 +408,12 @@ pub fn query(db: &dyn DefDatabase, id: StaticId) -> (Arc, Arc, - pub store: Arc, + pub store: ExpressionStore, pub self_ty: TypeRefId, pub target_trait: Option, pub flags: ImplFlags, } +#[salsa::tracked] impl ImplSignature { - pub fn query(db: &dyn DefDatabase, id: ImplId) -> (Arc, Arc) { + #[salsa::tracked(returns(deref))] + pub fn of(db: &dyn DefDatabase, id: ImplId) -> Arc { + Self::with_source_map(db, id).0.clone() + } + + #[salsa::tracked(returns(ref))] + pub fn with_source_map( + db: &dyn DefDatabase, + id: ImplId, + ) -> (Arc, ExpressionStoreSourceMap) { let loc = id.lookup(db); let mut flags = ImplFlags::empty(); @@ -399,17 +466,13 @@ pub fn query(db: &dyn DefDatabase, id: ImplId) -> (Arc, Arc bool { self.flags.contains(ImplFlags::NEGATIVE) @@ -440,12 +503,22 @@ pub struct TraitFlags: u16 { pub struct TraitSignature { pub name: Name, pub generic_params: Arc, - pub store: Arc, + pub store: ExpressionStore, pub flags: TraitFlags, } +#[salsa::tracked] impl TraitSignature { - pub fn query(db: &dyn DefDatabase, id: TraitId) -> (Arc, Arc) { + #[salsa::tracked(returns(deref))] + pub fn of(db: &dyn DefDatabase, id: TraitId) -> Arc { + Self::with_source_map(db, id).0.clone() + } + + #[salsa::tracked(returns(ref))] + pub fn with_source_map( + db: &dyn DefDatabase, + id: TraitId, + ) -> (Arc, ExpressionStoreSourceMap) { let loc = id.lookup(db); let mut flags = TraitFlags::empty(); @@ -483,10 +556,7 @@ pub fn query(db: &dyn DefDatabase, id: TraitId) -> (Arc, Arc, - pub store: Arc, + pub store: ExpressionStore, pub params: Box<[TypeRefId]>, pub ret_type: Option, pub abi: Option, pub flags: FnFlags, } +#[salsa::tracked] impl FunctionSignature { - pub fn query( + #[salsa::tracked(returns(deref))] + pub fn of(db: &dyn DefDatabase, id: FunctionId) -> Arc { + Self::with_source_map(db, id).0.clone() + } + + #[salsa::tracked(returns(ref))] + pub fn with_source_map( db: &dyn DefDatabase, id: FunctionId, - ) -> (Arc, Arc) { + ) -> (Arc, ExpressionStoreSourceMap) { let loc = id.lookup(db); let module = loc.container.module(db); @@ -589,17 +666,19 @@ pub fn query( ( Arc::new(FunctionSignature { generic_params, - store: Arc::new(store), + store, params, ret_type, abi, flags, name, }), - Arc::new(source_map), + source_map, ) } +} +impl FunctionSignature { pub fn has_body(&self) -> bool { self.flags.contains(FnFlags::HAS_BODY) } @@ -656,7 +735,7 @@ pub fn legacy_const_generics_indices<'db>( } pub fn is_intrinsic(db: &dyn DefDatabase, id: FunctionId) -> bool { - let data = db.function_signature(id); + let data = FunctionSignature::of(db, id); data.flags.contains(FnFlags::RUSTC_INTRINSIC) // Keep this around for a bit until extern "rustc-intrinsic" abis are no longer used || match &data.abi { @@ -684,17 +763,24 @@ pub struct TypeAliasFlags: u8 { pub struct TypeAliasSignature { pub name: Name, pub generic_params: Arc, - pub store: Arc, + pub store: ExpressionStore, pub bounds: Box<[TypeBound]>, pub ty: Option, pub flags: TypeAliasFlags, } +#[salsa::tracked] impl TypeAliasSignature { - pub fn query( + #[salsa::tracked(returns(deref))] + pub fn of(db: &dyn DefDatabase, id: TypeAliasId) -> Arc { + Self::with_source_map(db, id).0.clone() + } + + #[salsa::tracked(returns(ref))] + pub fn with_source_map( db: &dyn DefDatabase, id: TypeAliasId, - ) -> (Arc, Arc) { + ) -> (Arc, ExpressionStoreSourceMap) { let loc = id.lookup(db); let mut flags = TypeAliasFlags::empty(); @@ -714,28 +800,21 @@ pub fn query( lower_type_alias(db, loc.container.module(db), source, id); ( - Arc::new(TypeAliasSignature { - store: Arc::new(store), - generic_params, - flags, - bounds, - name, - ty, - }), - Arc::new(source_map), + Arc::new(TypeAliasSignature { store, generic_params, flags, bounds, name, ty }), + source_map, ) } } #[derive(Debug, PartialEq, Eq)] pub struct FunctionBody { - pub store: Arc, + pub store: ExpressionStore, pub parameters: Box<[PatId]>, } #[derive(Debug, PartialEq, Eq)] pub struct SimpleBody { - pub store: Arc, + pub store: ExpressionStore, } pub type StaticBody = SimpleBody; pub type ConstBody = SimpleBody; @@ -743,7 +822,7 @@ pub struct SimpleBody { #[derive(Debug, PartialEq, Eq)] pub struct VariantFieldsBody { - pub store: Arc, + pub store: ExpressionStore, pub fields: Box<[Option]>, } @@ -762,17 +841,17 @@ pub struct FieldData { #[derive(Debug, Clone, PartialEq, Eq)] pub struct VariantFields { fields: Arena, - pub store: Arc, + pub store: ExpressionStore, pub shape: FieldsShape, } #[salsa::tracked] impl VariantFields { - #[salsa::tracked(returns(clone))] - pub(crate) fn query( + #[salsa::tracked(returns(ref))] + pub(crate) fn with_source_map( db: &dyn DefDatabase, id: VariantId, - ) -> (Arc, Arc) { + ) -> (Arc, ExpressionStoreSourceMap) { let (shape, result) = match id { VariantId::EnumVariantId(id) => { let loc = id.lookup(db); @@ -809,20 +888,26 @@ pub(crate) fn query( } }; match result { - Some((fields, store, source_map)) => ( - Arc::new(VariantFields { fields, store: Arc::new(store), shape }), - Arc::new(source_map), - ), + Some((fields, store, source_map)) => { + (Arc::new(VariantFields { fields, store, shape }), source_map) + } None => { - let (store, source_map) = ExpressionStore::empty_singleton(); - (Arc::new(VariantFields { fields: Arena::default(), store, shape }), source_map) + let source_map = ExpressionStoreSourceMap::default(); + ( + Arc::new(VariantFields { + fields: Arena::default(), + store: ExpressionStoreBuilder::default().finish().0, + shape, + }), + source_map, + ) } } } #[salsa::tracked(returns(deref))] pub(crate) fn firewall(db: &dyn DefDatabase, id: VariantId) -> Arc { - Self::query(db, id).0 + Self::with_source_map(db, id).0.clone() } } @@ -1014,7 +1099,7 @@ pub fn is_payload_free(&self, db: &dyn DefDatabase) -> bool { } // The outer if condition is whether this variant has const ctor or not if !matches!(variant.shape, FieldsShape::Unit) { - let body = db.body(v.into()); + let body = Body::of(db, v.into()); // A variant with explicit discriminant if !matches!(body[body.body_expr], crate::hir::Expr::Missing) { return false; 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 d2921db6f4fa..0d260279f98c 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 @@ -15,6 +15,7 @@ use crate::{ Lookup, ModuleDefId, ModuleId, db::DefDatabase, + expr_store::{Body, scope::ExprScopes}, nameres::{DefMap, ModuleSource, block_def_map, crate_def_map}, src::HasSource, }; @@ -284,8 +285,8 @@ fn block_at_position(&self, def_map: &DefMap, position: FilePosition) -> Option< // Find the innermost block expression that has a `DefMap`. let (def_with_body, file_id) = fn_def?; let def_with_body = def_with_body.into(); - let source_map = self.body_with_source_map(def_with_body).1; - let scopes = self.expr_scopes(def_with_body.into()); + let source_map = &Body::with_source_map(self, def_with_body).1; + let scopes = ExprScopes::body_expr_scopes(self, def_with_body); let root_syntax_node = self.parse(file_id).syntax_node(); let scope_iter = 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 c294238030bd..673d00d956ad 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs @@ -5,10 +5,11 @@ use base_db::Crate; use hir_def::{ - ConstId, EnumVariantId, GeneralConstId, HasModule, StaticId, + ConstId, EnumVariantId, ExpressionStoreOwnerId, GeneralConstId, GenericDefId, HasModule, + StaticId, attrs::AttrFlags, builtin_type::{BuiltinInt, BuiltinType, BuiltinUint}, - expr_store::ExpressionStore, + expr_store::{Body, ExpressionStore}, hir::{Expr, ExprId, Literal}, }; use hir_expand::Lookup; @@ -273,7 +274,7 @@ pub(crate) fn const_eval_discriminant_variant( ) -> Result { let interner = DbInterner::new_no_crate(db); let def = variant_id.into(); - let body = db.body(def); + let body = Body::of(db, def); let loc = variant_id.lookup(db); if matches!(body[body.body_expr], Expr::Missing) { let prev_idx = loc.index.checked_sub(1); @@ -294,7 +295,7 @@ pub(crate) fn const_eval_discriminant_variant( let mir_body = db.monomorphized_mir_body( def, GenericArgs::empty(interner).store(), - ParamEnvAndCrate { param_env: db.trait_environment_for_body(def), krate: def.krate(db) } + ParamEnvAndCrate { param_env: db.trait_environment(def.into()), krate: def.krate(db) } .store(), )?; let c = interpret_mir(db, mir_body, false, None)?.0?; @@ -337,7 +338,7 @@ fn has_closure(store: &ExpressionStore, expr: ExprId) -> bool { } if let Some(body_owner) = ctx.owner.as_def_with_body() && let Ok(mir_body) = - lower_body_to_mir(ctx.db, body_owner, &ctx.db.body(body_owner), &infer, expr) + lower_body_to_mir(ctx.db, body_owner, Body::of(ctx.db, body_owner), &infer, expr) && let Ok((Ok(result), _)) = interpret_mir(ctx.db, Arc::new(mir_body), true, None) { return result; @@ -374,8 +375,12 @@ pub(crate) fn const_eval_query<'db>( let body = db.monomorphized_mir_body( def.into(), subst, - ParamEnvAndCrate { param_env: db.trait_environment(def.into()), krate: def.krate(db) } - .store(), + ParamEnvAndCrate { + param_env: db + .trait_environment(ExpressionStoreOwnerId::from(GenericDefId::from(def))), + krate: def.krate(db), + } + .store(), )?; let c = interpret_mir(db, body, false, trait_env.as_ref().map(|env| env.as_ref()))?.0?; Ok(c.store()) @@ -411,7 +416,8 @@ pub(crate) fn const_eval_static_query<'db>( def.into(), GenericArgs::empty(interner).store(), ParamEnvAndCrate { - param_env: db.trait_environment_for_body(def.into()), + param_env: db + .trait_environment(ExpressionStoreOwnerId::from(GenericDefId::from(def))), krate: def.krate(db), } .store(), 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 5f6bcb4a602c..31cf86476f9a 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 @@ -1,5 +1,5 @@ use base_db::RootQueryDb; -use hir_def::db::DefDatabase; +use hir_def::signatures::ConstSignature; use hir_expand::EditionedFileId; use rustc_apfloat::{ Float, @@ -131,7 +131,11 @@ fn eval_goal(db: &TestDB, file_id: EditionedFileId) -> Result, ConstEv .declarations() .find_map(|x| match x { hir_def::ModuleDefId::ConstId(x) => { - if db.const_signature(x).name.as_ref()?.display(db, file_id.edition(db)).to_string() + if ConstSignature::of(db, x) + .name + .as_ref()? + .display(db, file_id.edition(db)) + .to_string() == "GOAL" { Some(x) 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 ca5b1b771631..a0fb75397a23 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs @@ -5,7 +5,7 @@ use either::Either; use hir_def::{ AdtId, BuiltinDeriveImplId, CallableDefId, ConstId, ConstParamId, DefWithBodyId, EnumVariantId, - ExpressionStoreOwner, FunctionId, GenericDefId, ImplId, LifetimeParamId, LocalFieldId, + ExpressionStoreOwnerId, FunctionId, GenericDefId, ImplId, LifetimeParamId, LocalFieldId, StaticId, TraitId, TypeAliasId, VariantId, builtin_derive::BuiltinDeriveImplMethod, db::DefDatabase, hir::ExprId, layout::TargetDataLayout, }; @@ -178,13 +178,9 @@ fn callable_item_signature<'db>( def: CallableDefId, ) -> EarlyBinder<'db, PolyFnSig<'db>>; - #[salsa::invoke(crate::lower::trait_environment_for_body_query)] - #[salsa::transparent] - fn trait_environment_for_body<'db>(&'db self, def: DefWithBodyId) -> ParamEnv<'db>; - #[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: ExpressionStoreOwnerId) -> ParamEnv<'db>; #[salsa::invoke(crate::lower::generic_defaults_with_diagnostics_query)] #[salsa::cycle(cycle_result = crate::lower::generic_defaults_with_diagnostics_cycle_result)] @@ -240,7 +236,7 @@ pub struct InternedOpaqueTyId { } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] -pub struct InternedClosure(pub ExpressionStoreOwner, pub ExprId); +pub struct InternedClosure(pub ExpressionStoreOwnerId, pub ExprId); #[salsa_macros::interned(no_lifetime, debug, revisions = usize::MAX)] #[derive(PartialOrd, Ord)] @@ -249,7 +245,7 @@ pub struct InternedClosureId { } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] -pub struct InternedCoroutine(pub ExpressionStoreOwner, pub ExprId); +pub struct InternedCoroutine(pub ExpressionStoreOwnerId, pub ExprId); #[salsa_macros::interned(no_lifetime, debug, revisions = usize::MAX)] #[derive(PartialOrd, Ord)] diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs index 0931b859656f..89d8c0e91d18 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs @@ -17,8 +17,17 @@ use hir_def::{ AdtId, ConstId, EnumId, EnumVariantId, FunctionId, HasModule, ItemContainerId, Lookup, - ModuleDefId, ModuleId, StaticId, StructId, TraitId, TypeAliasId, UnionId, attrs::AttrFlags, - db::DefDatabase, hir::Pat, item_tree::FieldsShape, signatures::StaticFlags, src::HasSource, + ModuleDefId, ModuleId, StaticId, StructId, TraitId, TypeAliasId, UnionId, + attrs::AttrFlags, + db::DefDatabase, + expr_store::Body, + hir::Pat, + item_tree::FieldsShape, + signatures::{ + ConstSignature, EnumSignature, FunctionSignature, StaticFlags, StaticSignature, + StructSignature, TraitSignature, TypeAliasSignature, UnionSignature, + }, + src::HasSource, }; use hir_expand::{ HirFileId, @@ -178,7 +187,7 @@ fn validate_module(&mut self, module_id: ModuleId) { fn validate_trait(&mut self, trait_id: TraitId) { // Check the trait name. - let data = self.db.trait_signature(trait_id); + let data = TraitSignature::of(self.db, trait_id); self.create_incorrect_case_diagnostic_for_item_name( trait_id, &data.name, @@ -197,7 +206,7 @@ fn validate_func(&mut self, func: FunctionId) { // Check the function name. // Skipped if function is an associated item of a trait implementation. if !self.is_trait_impl_container(container) { - let data = self.db.function_signature(func); + let data = FunctionSignature::of(self.db, func); // Don't run the lint on extern "[not Rust]" fn items with the // #[no_mangle] attribute. @@ -223,7 +232,7 @@ fn validate_func(&mut self, func: FunctionId) { /// Check incorrect names for patterns inside the function body. /// This includes function parameters except for trait implementation associated functions. fn validate_func_body(&mut self, func: FunctionId) { - let body = self.db.body(func.into()); + let body = Body::of(self.db, func.into()); let edition = self.edition(func); let mut pats_replacements = body .pats() @@ -250,7 +259,7 @@ fn validate_func_body(&mut self, func: FunctionId) { return; } - let source_map = self.db.body_with_source_map(func.into()).1; + let source_map = &Body::with_source_map(self.db, func.into()).1; for (id, replacement) in pats_replacements { let Ok(source_ptr) = source_map.pat_syntax(id) else { continue; @@ -292,7 +301,7 @@ fn edition(&self, id: impl HasModule) -> span::Edition { fn validate_struct(&mut self, struct_id: StructId) { // Check the structure name. - let data = self.db.struct_signature(struct_id); + let data = StructSignature::of(self.db, struct_id); // rustc implementation excuses repr(C) since C structs predominantly don't // use camel case. @@ -385,7 +394,7 @@ fn validate_struct_fields(&mut self, struct_id: StructId) { fn validate_union(&mut self, union_id: UnionId) { // Check the union name. - let data = self.db.union_signature(union_id); + let data = UnionSignature::of(self.db, union_id); // rustc implementation excuses repr(C) since C unions predominantly don't // use camel case. @@ -473,7 +482,7 @@ fn validate_union_fields(&mut self, union_id: UnionId) { fn validate_enum(&mut self, enum_id: EnumId) { // Check the enum name. - let data = self.db.enum_signature(enum_id); + let data = EnumSignature::of(self.db, enum_id); // rustc implementation excuses repr(C) since C structs predominantly don't // use camel case. @@ -644,7 +653,7 @@ fn validate_const(&mut self, const_id: ConstId) { return; } - let data = self.db.const_signature(const_id); + let data = ConstSignature::of(self.db, const_id); let Some(name) = &data.name else { return; }; @@ -657,7 +666,7 @@ fn validate_const(&mut self, const_id: ConstId) { } fn validate_static(&mut self, static_id: StaticId) { - let data = self.db.static_signature(static_id); + let data = StaticSignature::of(self.db, static_id); if data.flags.contains(StaticFlags::EXTERN) { cov_mark::hit!(extern_static_incorrect_case_ignored); return; @@ -683,7 +692,7 @@ fn validate_type_alias(&mut self, type_alias_id: TypeAliasId) { } // Check the type alias name. - let data = self.db.type_alias_signature(type_alias_id); + let data = TypeAliasSignature::of(self.db, type_alias_id); self.create_incorrect_case_diagnostic_for_item_name( type_alias_id, &data.name, 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 4e1bb6f4c533..e227be6995d0 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 @@ -21,7 +21,7 @@ ast::{self, UnaryOp}, }; use tracing::debug; -use triomphe::Arc; + use typed_arena::Arena; use crate::{ @@ -76,9 +76,9 @@ pub fn collect( validate_lints: bool, ) -> Vec { let _p = tracing::info_span!("BodyValidationDiagnostic::collect").entered(); - let infer = InferenceResult::for_body(db, owner); - let body = db.body(owner); - let env = db.trait_environment_for_body(owner); + let infer = InferenceResult::of(db, owner); + let body = Body::of(db, owner); + let env = db.trait_environment(owner.into()); let interner = DbInterner::new_with(db, owner.krate(db)); let infcx = interner.infer_ctxt().build(TypingMode::typeck_for_body(interner, owner.into())); @@ -98,7 +98,7 @@ pub fn collect( struct ExprValidator<'db> { owner: DefWithBodyId, - body: Arc, + body: &'db Body, infer: &'db InferenceResult, env: ParamEnv<'db>, diagnostics: Vec, @@ -116,10 +116,10 @@ fn validate_body(&mut self) { let db = self.db(); let mut filter_map_next_checker = None; // we'll pass &mut self while iterating over body.exprs, so they need to be disjoint - let body = Arc::clone(&self.body); + let body = self.body; if matches!(self.owner, DefWithBodyId::FunctionId(_)) { - self.check_for_trailing_return(body.body_expr, &body); + self.check_for_trailing_return(body.body_expr, body); } for (id, expr) in body.exprs() { @@ -141,7 +141,7 @@ fn validate_body(&mut self) { self.validate_call(id, expr, &mut filter_map_next_checker); } Expr::Closure { body: body_expr, .. } => { - self.check_for_trailing_return(*body_expr, &body); + self.check_for_trailing_return(*body_expr, body); } Expr::If { .. } => { self.check_for_unnecessary_else(id, expr); @@ -240,7 +240,7 @@ fn validate_match(&mut self, match_expr: ExprId, scrutinee_expr: ExprId, arms: & .as_reference() .map(|(match_expr_ty, ..)| match_expr_ty == pat_ty) .unwrap_or(false)) - && types_of_subpatterns_do_match(arm.pat, &self.body, self.infer) + && types_of_subpatterns_do_match(arm.pat, self.body, self.infer) { // If we had a NotUsefulMatchArm diagnostic, we could // check the usefulness of each pattern as we added it @@ -388,7 +388,7 @@ fn lower_pattern<'a>( pat: PatId, have_errors: &mut bool, ) -> DeconstructedPat<'a, 'db> { - let mut patcx = match_check::PatCtxt::new(self.db(), self.infer, &self.body); + let mut patcx = match_check::PatCtxt::new(self.db(), self.infer, self.body); let pattern = patcx.lower_pattern(pat); let pattern = cx.lower_pat(&pattern); if !patcx.errors.is_empty() { @@ -451,7 +451,7 @@ fn check_for_unnecessary_else(&mut self, id: ExprId, expr: &Expr) { && last_then_expr_ty.is_never() { // Only look at sources if the then branch diverges and we have an else branch. - let source_map = self.db().body_with_source_map(self.owner).1; + let source_map = &Body::with_source_map(self.db(), self.owner).1; let Ok(source_ptr) = source_map.expr_syntax(id) else { return; }; 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 8e6101e6a0e3..f559c26bf57e 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 @@ -14,6 +14,7 @@ expr_store::{Body, path::Path}, hir::PatId, item_tree::FieldsShape, + signatures::{StructSignature, UnionSignature}, }; use hir_expand::name::Name; use rustc_type_ir::inherent::IntoKind; @@ -340,12 +341,12 @@ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> VariantId::StructId(s) => write!( f, "{}", - f.db.struct_signature(s).name.display(f.db, f.edition()) + StructSignature::of(f.db, s).name.display(f.db, f.edition()) )?, VariantId::UnionId(u) => write!( f, "{}", - f.db.union_signature(u).name.display(f.db, f.edition()) + UnionSignature::of(f.db, u).name.display(f.db, f.edition()) )?, }; 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 21f263723bb1..ba9b7416b76c 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 @@ -9,7 +9,7 @@ expr_store::{Body, path::Path}, hir::{AsmOperand, Expr, ExprId, ExprOrPatId, InlineAsmKind, Pat, PatId, Statement, UnaryOp}, resolver::{HasResolver, ResolveValueResult, Resolver, ValueNs}, - signatures::StaticFlags, + signatures::{FunctionSignature, StaticFlags, StaticSignature}, type_ref::Rawness, }; use rustc_type_ir::inherent::IntoKind; @@ -34,15 +34,15 @@ pub fn missing_unsafe(db: &dyn HirDatabase, def: DefWithBodyId) -> MissingUnsafe let _p = tracing::info_span!("missing_unsafe").entered(); let is_unsafe = match def { - DefWithBodyId::FunctionId(it) => db.function_signature(it).is_unsafe(), + DefWithBodyId::FunctionId(it) => FunctionSignature::of(db, it).is_unsafe(), DefWithBodyId::StaticId(_) | DefWithBodyId::ConstId(_) | DefWithBodyId::VariantId(_) => { false } }; let mut res = MissingUnsafeResult { fn_is_unsafe: is_unsafe, ..MissingUnsafeResult::default() }; - let body = db.body(def); - let infer = InferenceResult::for_body(db, def); + let body = Body::of(db, def); + let infer = InferenceResult::of(db, def); let mut callback = |diag| match diag { UnsafeDiagnostic::UnsafeOperation { node, inside_unsafe_block, reason } => { if inside_unsafe_block == InsideUnsafeBlock::No { @@ -55,7 +55,7 @@ pub fn missing_unsafe(db: &dyn HirDatabase, def: DefWithBodyId) -> MissingUnsafe } } }; - let mut visitor = UnsafeVisitor::new(db, infer, &body, def, &mut callback); + let mut visitor = UnsafeVisitor::new(db, infer, body, def, &mut callback); visitor.walk_expr(body.body_expr); if !is_unsafe { @@ -431,7 +431,7 @@ fn mark_unsafe_path(&mut self, node: ExprOrPatId, path: &Path) { let hygiene = self.body.expr_or_pat_path_hygiene(node); let value_or_partial = self.resolver.resolve_path_in_value_ns(self.db, path, hygiene); if let Some(ResolveValueResult::ValueNs(ValueNs::StaticId(id))) = value_or_partial { - let static_data = self.db.static_signature(id); + let static_data = StaticSignature::of(self.db, id); if static_data.flags.contains(StaticFlags::MUTABLE) { self.on_unsafe_op(node, UnsafetyReason::MutableStatic); } else if static_data.flags.contains(StaticFlags::EXTERN) 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 f4d0ed148492..54cd750de6c8 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs @@ -10,15 +10,18 @@ use base_db::{Crate, FxIndexMap}; use either::Either; use hir_def::{ - FindPathConfig, GenericDefId, GenericParamId, HasModule, LocalFieldId, Lookup, ModuleDefId, - ModuleId, TraitId, + ExpressionStoreOwnerId, FindPathConfig, GenericDefId, GenericParamId, HasModule, LocalFieldId, + Lookup, ModuleDefId, ModuleId, TraitId, expr_store::{ExpressionStore, path::Path}, find_path::{self, PrefixKind}, hir::generics::{TypeOrConstParamData, TypeParamProvenance, WherePredicate}, item_scope::ItemInNs, item_tree::FieldsShape, lang_item::LangItems, - signatures::VariantFields, + signatures::{ + EnumSignature, FunctionSignature, StructSignature, TraitSignature, TypeAliasSignature, + UnionSignature, VariantFields, + }, type_ref::{ ConstRef, LifetimeRef, LifetimeRefId, TraitBoundModifier, TypeBound, TypeRef, TypeRefId, UseArgRef, @@ -671,7 +674,9 @@ fn write_projection<'db>( write!( f, ">::{}", - f.db.type_alias_signature(alias.def_id.expect_type_alias()).name.display(f.db, f.edition()) + TypeAliasSignature::of(f.db, alias.def_id.expect_type_alias()) + .name + .display(f.db, f.edition()) )?; let proj_params = &alias.args.as_slice()[trait_ref.args.len()..]; hir_fmt_generics(f, proj_params, None, None) @@ -853,7 +858,7 @@ fn render_const_scalar_inner<'db>( } TyKind::Adt(adt, _) if b.len() == 2 * size_of::() => match adt.def_id().0 { hir_def::AdtId::StructId(s) => { - let data = f.db.struct_signature(s); + let data = StructSignature::of(f.db, s); write!(f, "&{}", data.name.display(f.db, f.edition()))?; Ok(()) } @@ -911,14 +916,16 @@ fn render_const_scalar_inner<'db>( }; match def { hir_def::AdtId::StructId(s) => { - let data = f.db.struct_signature(s); + let data = StructSignature::of(f.db, s); write!(f, "{}", data.name.display(f.db, f.edition()))?; let field_types = f.db.field_types(s.into()); render_variant_after_name( s.fields(f.db), f, field_types, - f.db.trait_environment(def.into()), + f.db.trait_environment(ExpressionStoreOwnerId::from(GenericDefId::from( + def, + ))), &layout, args, b, @@ -926,7 +933,7 @@ fn render_const_scalar_inner<'db>( ) } hir_def::AdtId::UnionId(u) => { - write!(f, "{}", f.db.union_signature(u).name.display(f.db, f.edition())) + write!(f, "{}", UnionSignature::of(f.db, u).name.display(f.db, f.edition())) } hir_def::AdtId::EnumId(e) => { let Ok(target_data_layout) = f.db.target_data_layout(f.krate()) else { @@ -950,7 +957,9 @@ fn render_const_scalar_inner<'db>( var_id.fields(f.db), f, field_types, - f.db.trait_environment(def.into()), + f.db.trait_environment(ExpressionStoreOwnerId::from(GenericDefId::from( + def, + ))), var_layout, args, b, @@ -1152,11 +1161,13 @@ fn hir_fmt(&self, f @ &mut HirFormatter { db, .. }: &mut HirFormatter<'_, 'db>) write!(f, "fn ")?; f.start_location_link(def.into()); match def { - CallableDefId::FunctionId(ff) => { - write!(f, "{}", db.function_signature(ff).name.display(f.db, f.edition()))? - } + CallableDefId::FunctionId(ff) => write!( + f, + "{}", + FunctionSignature::of(db, ff).name.display(f.db, f.edition()) + )?, CallableDefId::StructId(s) => { - write!(f, "{}", db.struct_signature(s).name.display(f.db, f.edition()))? + write!(f, "{}", StructSignature::of(db, s).name.display(f.db, f.edition()))? } CallableDefId::EnumVariantId(e) => { let loc = e.lookup(db); @@ -1235,9 +1246,11 @@ fn hir_fmt(&self, f @ &mut HirFormatter { db, .. }: &mut HirFormatter<'_, 'db>) match f.display_kind { DisplayKind::Diagnostics | DisplayKind::Test => { let name = match def_id { - hir_def::AdtId::StructId(it) => db.struct_signature(it).name.clone(), - hir_def::AdtId::UnionId(it) => db.union_signature(it).name.clone(), - hir_def::AdtId::EnumId(it) => db.enum_signature(it).name.clone(), + hir_def::AdtId::StructId(it) => { + StructSignature::of(db, it).name.clone() + } + hir_def::AdtId::UnionId(it) => UnionSignature::of(db, it).name.clone(), + hir_def::AdtId::EnumId(it) => EnumSignature::of(db, it).name.clone(), }; write!(f, "{}", name.display(f.db, f.edition()))?; } @@ -1272,7 +1285,7 @@ fn hir_fmt(&self, f @ &mut HirFormatter { db, .. }: &mut HirFormatter<'_, 'db>) write_projection(f, &alias_ty, trait_bounds_need_parens)? } TyKind::Foreign(alias) => { - let type_alias = db.type_alias_signature(alias.0); + let type_alias = TypeAliasSignature::of(db, alias.0); f.start_location_link(alias.0.into()); write!(f, "{}", type_alias.name.display(f.db, f.edition()))?; f.end_location_link(); @@ -1337,11 +1350,7 @@ fn hir_fmt(&self, f @ &mut HirFormatter { db, .. }: &mut HirFormatter<'_, 'db>) let sig = interner.signature_unclosure(substs.as_closure().sig(), Safety::Safe); let sig = sig.skip_binder(); let InternedClosure(owner, _) = db.lookup_intern_closure(id); - let Some(def) = owner.as_def_with_body() else { - write!(f, "{{closure}}")?; - return Ok(()); - }; - let infer = InferenceResult::for_body(db, def); + let infer = InferenceResult::of(db, owner); let (_, kind) = infer.closure_info(id); match f.closure_style { ClosureStyle::ImplFn => write!(f, "impl {kind:?}(")?, @@ -1530,13 +1539,7 @@ fn hir_fmt(&self, f @ &mut HirFormatter { db, .. }: &mut HirFormatter<'_, 'db>) let InternedCoroutine(owner, expr_id) = coroutine_id.0.loc(db); let CoroutineArgsParts { resume_ty, yield_ty, return_ty, .. } = subst.split_coroutine_args(); - let Some(body_owner) = owner.as_def_with_body() else { - write!(f, "impl Future")?; - return Ok(()); - }; - let body = db.body(body_owner); + let body = ExpressionStore::of(db, owner); let expr = &body[expr_id]; match expr { hir_def::hir::Expr::Closure { @@ -1877,7 +1880,7 @@ fn write_bounds_like_dyn_trait<'db>( // existential) here, which is the only thing that's // possible in actual Rust, and hence don't print it f.start_location_link(trait_.into()); - write!(f, "{}", f.db.trait_signature(trait_).name.display(f.db, f.edition()))?; + write!(f, "{}", TraitSignature::of(f.db, trait_).name.display(f.db, f.edition()))?; f.end_location_link(); if is_fn_trait { if let [_self, params @ ..] = trait_ref.trait_ref.args.as_slice() @@ -1940,7 +1943,7 @@ fn write_bounds_like_dyn_trait<'db>( angle_open = true; } let assoc_ty_id = projection.def_id().expect_type_alias(); - let type_alias = f.db.type_alias_signature(assoc_ty_id); + let type_alias = TypeAliasSignature::of(f.db, assoc_ty_id); f.start_location_link(assoc_ty_id.into()); write!(f, "{}", type_alias.name.display(f.db, f.edition()))?; f.end_location_link(); @@ -2031,7 +2034,7 @@ impl<'db> HirDisplay<'db> for TraitRef<'db> { fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result { let trait_ = self.def_id.0; f.start_location_link(trait_.into()); - write!(f, "{}", f.db.trait_signature(trait_).name.display(f.db, f.edition()))?; + write!(f, "{}", TraitSignature::of(f.db, trait_).name.display(f.db, f.edition()))?; f.end_location_link(); let substs = self.args.as_slice(); hir_fmt_generic_args(f, &substs[1..], None, Some(self.self_ty())) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/drop.rs b/src/tools/rust-analyzer/crates/hir-ty/src/drop.rs index 1303e08801bd..ddc4e4ce85ef 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/drop.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/drop.rs @@ -1,6 +1,9 @@ //! Utilities for computing drop info about types. -use hir_def::{AdtId, signatures::StructFlags}; +use hir_def::{ + AdtId, + signatures::{StructFlags, StructSignature}, +}; use rustc_hash::FxHashSet; use rustc_type_ir::inherent::{AdtDef, IntoKind}; use stdx::never; @@ -73,8 +76,7 @@ fn has_drop_glue_impl<'db>( } match adt_id { AdtId::StructId(id) => { - if db - .struct_signature(id) + if StructSignature::of(db, id) .flags .intersects(StructFlags::IS_MANUALLY_DROP | StructFlags::IS_PHANTOM_DATA) { @@ -132,12 +134,9 @@ fn has_drop_glue_impl<'db>( TyKind::Slice(ty) => has_drop_glue_impl(infcx, ty, env, visited), TyKind::Closure(closure_id, subst) => { let owner = db.lookup_intern_closure(closure_id.0).0; - let Some(body_owner) = owner.as_def_with_body() else { - return DropGlue::None; - }; - let infer = InferenceResult::for_body(db, body_owner); + let infer = InferenceResult::of(db, owner); let (captures, _) = infer.closure_info(closure_id.0); - let env = db.trait_environment_for_body(body_owner); + let env = db.trait_environment(owner); captures .iter() .map(|capture| has_drop_glue_impl(infcx, capture.ty(db, subst), env, visited)) 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 59cfd3fdc98c..d8093b3eb1c8 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 @@ -4,8 +4,10 @@ use hir_def::{ AssocItemId, ConstId, FunctionId, GenericDefId, HasModule, TraitId, TypeAliasId, - TypeOrConstParamId, TypeParamId, hir::generics::LocalTypeOrConstParamId, - nameres::crate_def_map, signatures::TraitFlags, + TypeOrConstParamId, TypeParamId, + hir::generics::LocalTypeOrConstParamId, + nameres::crate_def_map, + signatures::{FunctionSignature, TraitFlags, TraitSignature}, }; use rustc_hash::FxHashSet; use rustc_type_ir::{ @@ -318,7 +320,7 @@ fn virtual_call_violations_for_method( where F: FnMut(MethodViolationCode) -> ControlFlow<()>, { - let func_data = db.function_signature(func); + let func_data = FunctionSignature::of(db, func); if !func_data.has_self_param() { cb(MethodViolationCode::StaticMethod)?; } @@ -371,7 +373,7 @@ fn virtual_call_violations_for_method( trait_ref: pred_trait_ref, polarity: PredicatePolarity::Positive, }) = pred - && let trait_data = db.trait_signature(pred_trait_ref.def_id.0) + && let trait_data = TraitSignature::of(db, pred_trait_ref.def_id.0) && trait_data.flags.contains(TraitFlags::AUTO) && let rustc_type_ir::TyKind::Param(ParamTy { index: 0, .. }) = pred_trait_ref.self_ty().kind() diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility/tests.rs index 5c9b06e39a70..a70f98a0fe7b 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility/tests.rs @@ -1,6 +1,6 @@ use std::ops::ControlFlow; -use hir_def::db::DefDatabase; +use hir_def::signatures::TraitSignature; use rustc_hash::{FxHashMap, FxHashSet}; use syntax::ToSmolStr; use test_fixture::WithFixture; @@ -40,8 +40,7 @@ fn check_dyn_compatibility<'a>( .declarations() .filter_map(|def| { if let hir_def::ModuleDefId::TraitId(trait_id) = def { - let name = db - .trait_signature(trait_id) + let name = TraitSignature::of(&db, trait_id) .name .display_no_db(file_id.edition(&db)) .to_smolstr(); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs b/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs index b3c888da8e95..57fe4d749b2d 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs @@ -22,22 +22,22 @@ use itertools::chain; use triomphe::Arc; -pub fn generics(db: &dyn DefDatabase, def: GenericDefId) -> Generics { +pub fn generics(db: &dyn DefDatabase, def: GenericDefId) -> Generics<'_> { let parent_generics = parent_generic_def(db, def).map(|def| Box::new(generics(db, def))); - let (params, store) = db.generic_params_and_store(def); + let (params, store) = GenericParams::of(db, def); let has_trait_self_param = params.trait_self_param().is_some(); Generics { def, params, parent_generics, has_trait_self_param, store } } #[derive(Clone, Debug)] -pub struct Generics { +pub struct Generics<'db> { def: GenericDefId, params: Arc, - store: Arc, - parent_generics: Option>, + store: &'db ExpressionStore, + parent_generics: Option>>, has_trait_self_param: bool, } -impl ops::Index for Generics +impl ops::Index for Generics<'_> where GenericParams: ops::Index, { @@ -47,13 +47,13 @@ fn index(&self, index: T) -> &Self::Output { } } -impl Generics { +impl<'db> Generics<'db> { pub(crate) fn def(&self) -> GenericDefId { self.def } pub(crate) fn store(&self) -> &ExpressionStore { - &self.store + self.store } pub(crate) fn where_predicates(&self) -> impl Iterator { @@ -97,7 +97,7 @@ pub(crate) fn iter_parents_with_store( ) -> impl Iterator), &ExpressionStore)> + '_ { self.iter_parent() - .zip(self.parent_generics().into_iter().flat_map(|it| std::iter::repeat(&*it.store))) + .zip(self.parent_generics().into_iter().flat_map(|it| std::iter::repeat(it.store))) } /// Iterate over the params without parent params. @@ -219,7 +219,7 @@ fn find_lifetime(&self, lifetime: LifetimeParamId) -> Option { } } - pub(crate) fn parent_generics(&self) -> Option<&Generics> { + pub(crate) fn parent_generics(&self) -> Option<&Generics<'db>> { self.parent_generics.as_deref() } } @@ -243,7 +243,7 @@ pub(crate) fn parent_generic_def(db: &dyn DefDatabase, def: GenericDefId) -> Opt } fn from_toc_id<'a>( - it: &'a Generics, + it: &'a Generics<'a>, ) -> impl Fn( (LocalTypeOrConstParamId, &'a TypeOrConstParamData), ) -> (GenericParamId, GenericParamDataRef<'a>) { @@ -263,7 +263,7 @@ fn from_toc_id<'a>( } fn from_lt_id<'a>( - it: &'a Generics, + it: &'a Generics<'a>, ) -> impl Fn((LocalLifetimeParamId, &'a LifetimeParamData)) -> (GenericParamId, GenericParamDataRef<'a>) { move |(local_id, p): (_, _)| { 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 9d78f5de9e05..52edbc899ffa 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs @@ -33,15 +33,15 @@ use base_db::Crate; use either::Either; use hir_def::{ - AdtId, AssocItemId, ConstId, ConstParamId, DefWithBodyId, ExpressionStoreOwner, FieldId, + AdtId, AssocItemId, ConstId, ConstParamId, DefWithBodyId, ExpressionStoreOwnerId, FieldId, FunctionId, GenericDefId, GenericParamId, ItemContainerId, LocalFieldId, Lookup, TraitId, TupleFieldId, TupleId, TypeAliasId, TypeOrConstParamId, VariantId, - expr_store::{ConstExprOrigin, ExpressionStore, HygieneId, path::Path}, + expr_store::{Body, ConstExprOrigin, ExpressionStore, HygieneId, path::Path}, hir::{BindingAnnotation, BindingId, ExprId, ExprOrPatId, LabelId, PatId}, lang_item::LangItems, layout::Integer, resolver::{HasResolver, ResolveValueResult, Resolver, TypeNs, ValueNs}, - signatures::{ConstSignature, EnumSignature, StaticSignature}, + signatures::{ConstSignature, EnumSignature, FunctionSignature, StaticSignature}, type_ref::{ConstRef, LifetimeRefId, TypeRef, TypeRefId}, }; use hir_expand::{mod_path::ModPath, name::Name}; @@ -105,8 +105,9 @@ pub fn infer_query_with_inspect<'db>( ) -> InferenceResult { let _p = tracing::info_span!("infer_query").entered(); let resolver = def.resolver(db); - let body = db.body(def); - let mut ctx = InferenceContext::new(db, ExpressionStoreOwner::Body(def), &body.store, resolver); + let body = Body::of(db, def); + let mut ctx = + InferenceContext::new(db, ExpressionStoreOwnerId::Body(def), &body.store, resolver); if let Some(inspect) = inspect { ctx.table.infer_ctxt.attach_obligation_inspector(inspect); @@ -114,8 +115,8 @@ pub fn infer_query_with_inspect<'db>( match def { DefWithBodyId::FunctionId(f) => ctx.collect_fn(f, body.self_param, &body.params), - DefWithBodyId::ConstId(c) => ctx.collect_const(c, &db.const_signature(c)), - DefWithBodyId::StaticId(s) => ctx.collect_static(&db.static_signature(s)), + DefWithBodyId::ConstId(c) => ctx.collect_const(c, ConstSignature::of(db, c)), + DefWithBodyId::StaticId(s) => ctx.collect_static(StaticSignature::of(db, s)), DefWithBodyId::VariantId(v) => { ctx.return_ty = match EnumSignature::variant_body_type(db, v.lookup(db).parent) { hir_def::layout::IntegerType::Pointer(signed) => match signed { @@ -146,10 +147,66 @@ pub fn infer_query_with_inspect<'db>( ctx.infer_mut_body(body.body_expr); - finalize_infer(ctx) + infer_finalize(ctx) } -fn finalize_infer(mut ctx: InferenceContext<'_, '_>) -> InferenceResult { +fn infer_cycle_result(db: &dyn HirDatabase, _: salsa::Id, _: DefWithBodyId) -> InferenceResult { + InferenceResult { + has_errors: true, + ..InferenceResult::new(Ty::new_error(DbInterner::new_no_crate(db), ErrorGuaranteed)) + } +} + +/// Infer types for all const expressions in an item's signature. +/// +/// This handles const expressions that appear in type positions within a generic +/// item's signature, such as array lengths (`[T; N]`) and const generic arguments +/// (`Foo<{ expr }>`). Each root expression is inferred independently within +/// a shared `InferenceContext`, accumulating results into a single `InferenceResult`. +fn infer_signature_query(db: &dyn HirDatabase, def: GenericDefId) -> InferenceResult { + let _p = tracing::info_span!("infer_signature_query").entered(); + let store = ExpressionStore::of(db, def.into()); + let mut roots = store.signature_const_expr_roots_with_origins().peekable(); + let Some(_) = roots.peek() else { + return InferenceResult::new(crate::next_solver::default_types(db).types.error); + }; + + let resolver = def.resolver(db); + let owner = ExpressionStoreOwnerId::Signature(def); + + let mut ctx = InferenceContext::new(db, owner, store, resolver); + + for (root_expr, origin) in roots { + let expected = match origin { + // Array lengths are always `usize`. + ConstExprOrigin::ArrayLength => Expectation::has_type(ctx.types.types.usize), + // Const parameter default: look up the param's declared type. + ConstExprOrigin::ConstParam(local_id) => Expectation::has_type(db.const_param_ty_ns( + ConstParamId::from_unchecked(TypeOrConstParamId { parent: def, local_id }), + )), + // Path const generic args: determining the expected type requires + // path resolution. + // FIXME + ConstExprOrigin::GenericArgsPath => Expectation::None, + }; + ctx.infer_expr(root_expr, &expected, ExprIsRead::Yes); + } + + infer_finalize(ctx) +} + +fn infer_signature_cycle_result( + db: &dyn HirDatabase, + _: salsa::Id, + _: GenericDefId, +) -> InferenceResult { + InferenceResult { + has_errors: true, + ..InferenceResult::new(Ty::new_error(DbInterner::new_no_crate(db), ErrorGuaranteed)) + } +} + +fn infer_finalize(mut ctx: InferenceContext<'_, '_>) -> InferenceResult { ctx.handle_opaque_type_uses(); ctx.type_inference_fallback(); @@ -174,63 +231,6 @@ fn finalize_infer(mut ctx: InferenceContext<'_, '_>) -> InferenceResult { ctx.resolve_all() } - -fn infer_cycle_result(db: &dyn HirDatabase, _: salsa::Id, _: DefWithBodyId) -> InferenceResult { - InferenceResult { - has_errors: true, - ..InferenceResult::new(Ty::new_error(DbInterner::new_no_crate(db), ErrorGuaranteed)) - } -} - -/// Infer types for all const expressions in an item's signature. -/// -/// This handles const expressions that appear in type positions within a generic -/// item's signature, such as array lengths (`[T; N]`) and const generic arguments -/// (`Foo<{ expr }>`). Each root expression is inferred independently within -/// a shared `InferenceContext`, accumulating results into a single `InferenceResult`. -fn infer_signature_query(db: &dyn HirDatabase, def: GenericDefId) -> InferenceResult { - let _p = tracing::info_span!("infer_signature_query").entered(); - let (_, store) = db.generic_params_and_store(def); - let mut roots = store.signature_const_expr_roots_with_origins().peekable(); - let Some(_) = roots.peek() else { - return InferenceResult::new(crate::next_solver::default_types(db).types.error); - }; - - let resolver = def.resolver(db); - let owner = ExpressionStoreOwner::Signature(def); - - let mut ctx = InferenceContext::new(db, owner, &store, resolver); - - for (root_expr, origin) in roots { - let expected = match origin { - // Array lengths are always `usize`. - ConstExprOrigin::ArrayLength => Expectation::has_type(ctx.types.types.usize), - // Const parameter default: look up the param's declared type. - ConstExprOrigin::ConstParam(local_id) => Expectation::has_type(db.const_param_ty_ns( - ConstParamId::from_unchecked(TypeOrConstParamId { parent: def, local_id }), - )), - // Path const generic args: determining the expected type requires - // path resolution. - // FIXME - ConstExprOrigin::GenericArgsPath => Expectation::None, - }; - ctx.infer_expr(root_expr, &expected, ExprIsRead::Yes); - } - - finalize_infer(ctx) -} - -fn infer_signature_cycle_result( - db: &dyn HirDatabase, - _: salsa::Id, - _: GenericDefId, -) -> InferenceResult { - InferenceResult { - has_errors: true, - ..InferenceResult::new(Ty::new_error(DbInterner::new_no_crate(db), ErrorGuaranteed)) - } -} - /// Binding modes inferred for patterns. /// #[derive(Copy, Clone, Debug, Eq, PartialEq, Default)] @@ -604,7 +604,7 @@ pub struct InferenceResult { #[salsa::tracked] impl InferenceResult { #[salsa::tracked(returns(ref), cycle_result = infer_cycle_result)] - pub fn for_body(db: &dyn HirDatabase, def: DefWithBodyId) -> InferenceResult { + fn for_body(db: &dyn HirDatabase, def: DefWithBodyId) -> InferenceResult { infer_query(db, def) } @@ -614,12 +614,21 @@ pub fn for_body(db: &dyn HirDatabase, def: DefWithBodyId) -> InferenceResult { /// const generic arguments, and other const expressions appearing in type /// positions within the item's signature. #[salsa::tracked(returns(ref), cycle_result = infer_signature_cycle_result)] - pub fn for_signature(db: &dyn HirDatabase, def: GenericDefId) -> InferenceResult { + fn for_signature(db: &dyn HirDatabase, def: GenericDefId) -> InferenceResult { infer_signature_query(db, def) } } impl InferenceResult { + pub fn of(db: &dyn HirDatabase, def: impl Into) -> &InferenceResult { + match def.into() { + ExpressionStoreOwnerId::Signature(generic_def_id) => { + Self::for_signature(db, generic_def_id) + } + ExpressionStoreOwnerId::Body(def_with_body_id) => Self::for_body(db, def_with_body_id), + } + } + fn new(error_ty: Ty<'_>) -> Self { Self { method_resolutions: Default::default(), @@ -816,7 +825,7 @@ pub fn binding_ty<'db>(&self, id: BindingId) -> Ty<'db> { #[derive(Clone, Debug)] pub(crate) struct InferenceContext<'body, 'db> { pub(crate) db: &'db dyn HirDatabase, - pub(crate) owner: ExpressionStoreOwner, + pub(crate) owner: ExpressionStoreOwnerId, pub(crate) store: &'body ExpressionStore, /// 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. @@ -917,14 +926,16 @@ fn find_continuable<'a, 'db>( impl<'body, 'db> InferenceContext<'body, 'db> { fn new( db: &'db dyn HirDatabase, - owner: ExpressionStoreOwner, + owner: ExpressionStoreOwnerId, store: &'body ExpressionStore, resolver: Resolver<'db>, ) -> Self { let trait_env = match owner { - ExpressionStoreOwner::Signature(generic_def_id) => db.trait_environment(generic_def_id), - ExpressionStoreOwner::Body(def_with_body_id) => { - db.trait_environment_for_body(def_with_body_id) + ExpressionStoreOwnerId::Signature(generic_def_id) => { + db.trait_environment(ExpressionStoreOwnerId::from(generic_def_id)) + } + ExpressionStoreOwnerId::Body(def_with_body_id) => { + db.trait_environment(ExpressionStoreOwnerId::Body(def_with_body_id)) } }; let table = unify::InferenceTable::new(db, trait_env, resolver.krate(), Some(owner)); @@ -970,7 +981,7 @@ fn krate(&self) -> Crate { fn target_features(&self) -> (&TargetFeatures<'db>, TargetFeatureIsSafeInTarget) { let (target_features, target_feature_is_safe) = self.target_features.get_or_init(|| { let target_features = match self.owner { - ExpressionStoreOwner::Body(DefWithBodyId::FunctionId(id)) => { + ExpressionStoreOwnerId::Body(DefWithBodyId::FunctionId(id)) => { TargetFeatures::from_fn(self.db, id) } _ => TargetFeatures::default(), @@ -1167,11 +1178,11 @@ fn collect_static(&mut self, data: &StaticSignature) { } fn collect_fn(&mut self, func: FunctionId, self_param: Option, params: &[PatId]) { - let data = self.db.function_signature(func); + let data = FunctionSignature::of(self.db, func); let mut param_tys = self.with_ty_lowering( &data.store, InferenceTyDiagnosticSource::Signature, - LifetimeElisionKind::for_fn_params(&data), + LifetimeElisionKind::for_fn_params(data), |ctx| data.params.iter().map(|&type_ref| ctx.lower_ty(type_ref)).collect::>(), ); 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 fc38361d7e41..e5ee73447471 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 @@ -1,6 +1,10 @@ //! Type cast logic. Basically coercion + additional casts. -use hir_def::{AdtId, hir::ExprId, signatures::TraitFlags}; +use hir_def::{ + AdtId, + hir::ExprId, + signatures::{TraitFlags, TraitSignature}, +}; use rustc_ast_ir::Mutability; use rustc_hash::FxHashSet; use rustc_type_ir::{ @@ -383,8 +387,7 @@ fn check_ptr_ptr_cast( .chain( elaborate::supertrait_def_ids(ctx.interner(), src_principal) .filter(|trait_| { - ctx.db - .trait_signature(trait_.0) + TraitSignature::of(ctx.db, trait_.0) .flags .contains(TraitFlags::AUTO) }), 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 2b9d3a7f5dbb..913d54e9697d 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 @@ -4,8 +4,8 @@ use base_db::Crate; use hir_def::{ - DefWithBodyId, FieldId, HasModule, VariantId, - expr_store::path::Path, + ExpressionStoreOwnerId, FieldId, HasModule, VariantId, + expr_store::{Body, ExpressionStore, path::Path}, hir::{ Array, AsmOperand, BinaryOp, BindingId, CaptureBy, Expr, ExprId, ExprOrPatId, Pat, PatId, RecordSpread, Statement, UnaryOp, @@ -179,9 +179,22 @@ pub fn kind(&self) -> CaptureKind { } /// Converts the place to a name that can be inserted into source code. - pub fn place_to_name(&self, owner: DefWithBodyId, db: &dyn HirDatabase) -> String { - let body = db.body(owner); - let mut result = body[self.place.local].name.as_str().to_owned(); + pub fn place_to_name(&self, owner: ExpressionStoreOwnerId, db: &dyn HirDatabase) -> String { + let krate = owner.krate(db); + let edition = krate.data(db).edition; + let mut result = match owner { + ExpressionStoreOwnerId::Signature(generic_def_id) => { + ExpressionStore::of(db, generic_def_id.into())[self.place.local] + .name + .display(db, edition) + .to_string() + } + ExpressionStoreOwnerId::Body(def_with_body_id) => Body::of(db, def_with_body_id) + [self.place.local] + .name + .display(db, edition) + .to_string(), + }; for proj in &self.place.projections { match proj { HirPlaceProjection::Deref => {} @@ -213,11 +226,26 @@ pub fn place_to_name(&self, owner: DefWithBodyId, db: &dyn HirDatabase) -> Strin result } - pub fn display_place_source_code(&self, owner: DefWithBodyId, db: &dyn HirDatabase) -> String { - let body = db.body(owner); + pub fn display_place_source_code( + &self, + owner: ExpressionStoreOwnerId, + db: &dyn HirDatabase, + ) -> String { let krate = owner.krate(db); let edition = krate.data(db).edition; - let mut result = body[self.place.local].name.display(db, edition).to_string(); + let mut result = match owner { + ExpressionStoreOwnerId::Signature(generic_def_id) => { + ExpressionStore::of(db, generic_def_id.into())[self.place.local] + .name + .display(db, edition) + .to_string() + } + ExpressionStoreOwnerId::Body(def_with_body_id) => Body::of(db, def_with_body_id) + [self.place.local] + .name + .display(db, edition) + .to_string(), + }; for proj in &self.place.projections { match proj { // In source code autoderef kicks in. @@ -258,11 +286,22 @@ pub fn display_place_source_code(&self, owner: DefWithBodyId, db: &dyn HirDataba result } - pub fn display_place(&self, owner: DefWithBodyId, db: &dyn HirDatabase) -> String { - let body = db.body(owner); + pub fn display_place(&self, owner: ExpressionStoreOwnerId, db: &dyn HirDatabase) -> String { let krate = owner.krate(db); let edition = krate.data(db).edition; - let mut result = body[self.place.local].name.display(db, edition).to_string(); + let mut result = match owner { + ExpressionStoreOwnerId::Signature(generic_def_id) => { + ExpressionStore::of(db, generic_def_id.into())[self.place.local] + .name + .display(db, edition) + .to_string() + } + ExpressionStoreOwnerId::Body(def_with_body_id) => Body::of(db, def_with_body_id) + [self.place.local] + .name + .display(db, edition) + .to_string(), + }; let mut field_need_paren = false; for proj in &self.place.projections { match proj { 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 2e80bad61414..c4c217b010ee 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 @@ -11,6 +11,7 @@ InlineAsmKind, LabelId, Literal, Pat, PatId, RecordSpread, Statement, UnaryOp, }, resolver::ValueNs, + signatures::FunctionSignature, }; use hir_def::{FunctionId, hir::ClosureKind}; use hir_expand::name::Name; @@ -2194,7 +2195,7 @@ fn check_legacy_const_generics(&mut self, callee: Ty<'db>, args: &[ExprId]) -> B _ => return Default::default(), }; - let data = self.db.function_signature(func); + let data = FunctionSignature::of(self.db, func); let Some(legacy_const_generics_indices) = data.legacy_const_generics_indices(self.db, func) else { return Default::default(); 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 17d4901123bb..71d68ccd47a6 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 @@ -4,6 +4,7 @@ AdtId, AssocItemId, GenericDefId, ItemContainerId, Lookup, expr_store::path::{Path, PathSegment}, resolver::{ResolveValueResult, TypeNs, ValueNs}, + signatures::{ConstSignature, FunctionSignature}, }; use hir_expand::name::Name; use rustc_type_ir::inherent::{SliceLike, Ty as _}; @@ -263,7 +264,7 @@ fn resolve_trait_assoc_item( trait_.trait_items(self.db).items.iter().map(|(_name, id)| *id).find_map(|item| { match item { AssocItemId::FunctionId(func) => { - if segment.name == &self.db.function_signature(func).name { + if segment.name == &FunctionSignature::of(self.db, func).name { Some(CandidateId::FunctionId(func)) } else { None @@ -271,7 +272,7 @@ fn resolve_trait_assoc_item( } AssocItemId::ConstId(konst) => { - if self.db.const_signature(konst).name.as_ref() == Some(segment.name) { + if ConstSignature::of(self.db, konst).name.as_ref() == Some(segment.name) { Some(CandidateId::ConstId(konst)) } else { None 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 77f76c97b8e6..d093412b4210 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 @@ -3,7 +3,7 @@ use std::fmt; use base_db::Crate; -use hir_def::{AdtId, ExpressionStoreOwner, GenericParamId}; +use hir_def::{AdtId, ExpressionStoreOwnerId, GenericParamId}; use hir_expand::name::Name; use intern::sym; use rustc_hash::FxHashSet; @@ -147,7 +147,7 @@ pub(crate) fn new( db: &'db dyn HirDatabase, trait_env: ParamEnv<'db>, krate: Crate, - owner: Option, + owner: Option, ) -> Self { let interner = DbInterner::new_with(db, krate); let typing_mode = match owner { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lang_items.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lang_items.rs index 18feb0f46a32..ae53276f56a5 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lang_items.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lang_items.rs @@ -1,13 +1,17 @@ //! Functions to detect special lang items -use hir_def::{AdtId, TraitId, lang_item::LangItems, signatures::StructFlags}; +use hir_def::{ + AdtId, TraitId, + lang_item::LangItems, + signatures::{StructFlags, StructSignature}, +}; use intern::{Symbol, sym}; use crate::db::HirDatabase; pub fn is_box(db: &dyn HirDatabase, adt: AdtId) -> bool { let AdtId::StructId(id) = adt else { return false }; - db.struct_signature(id).flags.contains(StructFlags::IS_BOX) + StructSignature::of(db, id).flags.contains(StructFlags::IS_BOX) } pub fn lang_items_for_bin_op( 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 a325b2e17438..54332122d0e4 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs @@ -333,10 +333,7 @@ pub fn layout_of_ty_query( } TyKind::Closure(id, args) => { let def = db.lookup_intern_closure(id.0); - let Some(body_owner) = def.0.as_def_with_body() else { - return Err(LayoutError::HasErrorType); - }; - let infer = InferenceResult::for_body(db, body_owner); + let infer = InferenceResult::of(db, def.0); let (captures, _) = infer.closure_info(id.0); let fields = captures .iter() diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout/adt.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout/adt.rs index d2495917187e..6090ddfd45cc 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/layout/adt.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout/adt.rs @@ -5,7 +5,7 @@ use hir_def::{ AdtId, VariantId, attrs::AttrFlags, - signatures::{StructFlags, VariantFields}, + signatures::{StructFlags, StructSignature, VariantFields}, }; use rustc_abi::{Integer, ReprOptions, TargetDataLayout}; use rustc_index::IndexVec; @@ -41,7 +41,7 @@ pub fn layout_of_adt_query( }; let (variants, repr, is_special_no_niche) = match def { AdtId::StructId(s) => { - let sig = db.struct_signature(s); + let sig = StructSignature::of(db, s); let mut r = SmallVec::<[_; 1]>::new(); r.push(handle_variant(s.into(), s.fields(db))?); ( diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs index e491c29df3b5..484ecebba534 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs @@ -1,6 +1,12 @@ use base_db::target::TargetData; use either::Either; -use hir_def::{HasModule, db::DefDatabase}; +use hir_def::{ + DefWithBodyId, ExpressionStoreOwnerId, GenericDefId, HasModule, + expr_store::Body, + signatures::{ + EnumSignature, FunctionSignature, StructSignature, TypeAliasSignature, UnionSignature, + }, +}; use project_model::{Sysroot, toolchain_info::QueryConfig}; use rustc_hash::FxHashMap; use rustc_type_ir::inherent::GenericArgs as _; @@ -49,18 +55,15 @@ fn eval_goal( let adt_or_type_alias_id = scope.declarations().find_map(|x| match x { hir_def::ModuleDefId::AdtId(x) => { let name = match x { - hir_def::AdtId::StructId(x) => db - .struct_signature(x) + hir_def::AdtId::StructId(x) => StructSignature::of(&db, x) .name .display_no_db(file_id.edition(&db)) .to_smolstr(), - hir_def::AdtId::UnionId(x) => db - .union_signature(x) + hir_def::AdtId::UnionId(x) => UnionSignature::of(&db, x) .name .display_no_db(file_id.edition(&db)) .to_smolstr(), - hir_def::AdtId::EnumId(x) => db - .enum_signature(x) + hir_def::AdtId::EnumId(x) => EnumSignature::of(&db, x) .name .display_no_db(file_id.edition(&db)) .to_smolstr(), @@ -68,8 +71,7 @@ fn eval_goal( (name == "Goal").then_some(Either::Left(x)) } hir_def::ModuleDefId::TypeAliasId(x) => { - let name = db - .type_alias_signature(x) + let name = TypeAliasSignature::of(&db, x) .name .display_no_db(file_id.edition(&db)) .to_smolstr(); @@ -90,10 +92,13 @@ fn eval_goal( ), Either::Right(ty_id) => db.ty(ty_id.into()).instantiate_identity(), }; - let param_env = db.trait_environment(match adt_or_type_alias_id { - Either::Left(adt) => hir_def::GenericDefId::AdtId(adt), - Either::Right(ty) => hir_def::GenericDefId::TypeAliasId(ty), - }); + let param_env = db.trait_environment( + match adt_or_type_alias_id { + Either::Left(adt) => hir_def::GenericDefId::AdtId(adt), + Either::Right(ty) => hir_def::GenericDefId::TypeAliasId(ty), + } + .into(), + ); let krate = match adt_or_type_alias_id { Either::Left(it) => it.krate(&db), Either::Right(it) => it.krate(&db), @@ -123,8 +128,7 @@ fn eval_expr( .declarations() .find_map(|x| match x { hir_def::ModuleDefId::FunctionId(x) => { - let name = db - .function_signature(x) + let name = FunctionSignature::of(&db, x) .name .display_no_db(file_id.edition(&db)) .to_smolstr(); @@ -133,15 +137,16 @@ fn eval_expr( _ => None, }) .unwrap(); - let hir_body = db.body(function_id.into()); + let hir_body = Body::of(&db, function_id.into()); let b = hir_body .bindings() .find(|x| x.1.name.display_no_db(file_id.edition(&db)).to_smolstr() == "goal") .unwrap() .0; - let infer = InferenceResult::for_body(&db, function_id.into()); + let infer = InferenceResult::of(&db, DefWithBodyId::from(function_id)); let goal_ty = infer.type_of_binding[b].clone(); - let param_env = db.trait_environment(function_id.into()); + let param_env = + db.trait_environment(ExpressionStoreOwnerId::from(GenericDefId::from(function_id))); let krate = function_id.krate(&db); db.layout_of_ty(goal_ty, ParamEnvAndCrate { param_env, krate }.store()) }) 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 8d87276a0b15..e6b8329ca861 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs @@ -61,8 +61,8 @@ use std::{hash::Hash, ops::ControlFlow}; use hir_def::{ - CallableDefId, GenericDefId, TypeAliasId, TypeOrConstParamId, TypeParamId, - hir::generics::GenericParams, resolver::TypeNs, type_ref::Rawness, + CallableDefId, ExpressionStoreOwnerId, GenericDefId, TypeAliasId, TypeOrConstParamId, + TypeParamId, hir::generics::GenericParams, resolver::TypeNs, type_ref::Rawness, }; use hir_expand::name::Name; use indexmap::{IndexMap, map::Entry}; @@ -507,7 +507,7 @@ pub fn associated_type_shorthand_candidates( let mut dedup_map = FxHashSet::default(); let param_ty = Ty::new_param(interner, param, param_idx(db, param.into()).unwrap() as u32); // We use the ParamEnv and not the predicates because the ParamEnv elaborates bounds. - let param_env = db.trait_environment(def); + let param_env = db.trait_environment(ExpressionStoreOwnerId::from(def)); for clause in param_env.clauses { let ClauseKind::Trait(trait_clause) = clause.kind().skip_binder() else { continue }; if trait_clause.self_ty() != param_ty { 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 c0bd8975711f..3ed563315e5e 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs @@ -13,10 +13,10 @@ use arrayvec::ArrayVec; use either::Either; use hir_def::{ - AdtId, AssocItemId, CallableDefId, ConstId, ConstParamId, DefWithBodyId, EnumId, EnumVariantId, - FunctionId, GeneralConstId, GenericDefId, GenericParamId, HasModule, ImplId, ItemContainerId, - LifetimeParamId, LocalFieldId, Lookup, StaticId, StructId, TraitId, TypeAliasId, - TypeOrConstParamId, TypeParamId, UnionId, VariantId, + AdtId, AssocItemId, CallableDefId, ConstId, ConstParamId, EnumId, EnumVariantId, + ExpressionStoreOwnerId, FunctionId, GeneralConstId, GenericDefId, GenericParamId, HasModule, + ImplId, ItemContainerId, LifetimeParamId, LocalFieldId, Lookup, StaticId, StructId, TraitId, + TypeAliasId, TypeOrConstParamId, TypeParamId, UnionId, VariantId, builtin_type::BuiltinType, expr_store::{ExpressionStore, HygieneId, path::Path}, hir::generics::{ @@ -26,7 +26,10 @@ item_tree::FieldsShape, lang_item::LangItems, resolver::{HasResolver, LifetimeNs, Resolver, TypeNs, ValueNs}, - signatures::{FunctionSignature, TraitFlags, TypeAliasFlags}, + signatures::{ + ConstSignature, FunctionSignature, ImplSignature, StaticSignature, StructSignature, + TraitFlags, TraitSignature, TypeAliasFlags, TypeAliasSignature, + }, type_ref::{ ConstRef, FnType, LifetimeRefId, PathId, TraitBoundModifier, TraitRef as HirTraitRef, TypeBound, TypeRef, TypeRefId, @@ -178,7 +181,7 @@ pub struct TyLoweringContext<'db, 'a> { resolver: &'a Resolver<'db>, store: &'a ExpressionStore, def: GenericDefId, - generics: OnceCell, + generics: OnceCell>, in_binders: DebruijnIndex, impl_trait_mode: ImplTraitLoweringState, /// Tracks types with explicit `?Sized` bounds. @@ -404,7 +407,7 @@ pub(crate) fn lower_path_as_const(&mut self, path: &Path, const_type: Ty<'db>) - self.path_to_const(path).unwrap_or_else(|| unknown_const(const_type)) } - fn generics(&self) -> &Generics { + fn generics(&self) -> &Generics<'db> { self.generics.get_or_init(|| generics(self.db, self.def)) } @@ -782,7 +785,8 @@ fn lower_dyn_trait(&mut self, bounds: &[TypeBound]) -> Ty<'db> { match b.kind().skip_binder() { rustc_type_ir::ClauseKind::Trait(t) => { let id = t.def_id(); - let is_auto = db.trait_signature(id.0).flags.contains(TraitFlags::AUTO); + let is_auto = + TraitSignature::of(db, id.0).flags.contains(TraitFlags::AUTO); if is_auto { auto_traits.push(t.def_id().0); } else { @@ -1166,7 +1170,7 @@ pub(crate) fn impl_trait_with_diagnostics_query<'db>( db: &'db dyn HirDatabase, impl_id: ImplId, ) -> Option<(StoredEarlyBinder<(TraitId, StoredGenericArgs)>, Diagnostics)> { - let impl_data = db.impl_signature(impl_id); + let impl_data = ImplSignature::of(db, impl_id); let resolver = impl_id.resolver(db); let mut ctx = TyLoweringContext::new( db, @@ -1251,7 +1255,7 @@ pub(crate) fn return_type_impl_traits( def: hir_def::FunctionId, ) -> Option>> { // FIXME unify with fn_sig_for_fn instead of doing lowering twice, maybe - let data = db.function_signature(def); + let data = FunctionSignature::of(db, def); let resolver = def.resolver(db); let mut ctx_ret = TyLoweringContext::new( db, @@ -1279,7 +1283,7 @@ pub(crate) fn type_alias_impl_traits( db: &dyn HirDatabase, def: hir_def::TypeAliasId, ) -> Option>> { - let data = db.type_alias_signature(def); + let data = TypeAliasSignature::of(db, def); let resolver = def.resolver(db); let mut ctx = TyLoweringContext::new( db, @@ -1369,7 +1373,7 @@ fn type_for_fn(db: &dyn HirDatabase, def: FunctionId) -> StoredEarlyBinder StoredEarlyBinder { let resolver = def.resolver(db); - let data = db.const_signature(def); + let data = ConstSignature::of(db, def); let parent = def.loc(db).container; let mut ctx = TyLoweringContext::new( db, @@ -1385,7 +1389,7 @@ fn type_for_const(db: &dyn HirDatabase, def: ConstId) -> StoredEarlyBinder StoredEarlyBinder { let resolver = def.resolver(db); - let data = db.static_signature(def); + let data = StaticSignature::of(db, def); let mut ctx = TyLoweringContext::new( db, &resolver, @@ -1402,7 +1406,7 @@ fn type_for_struct_constructor( db: &dyn HirDatabase, def: StructId, ) -> Option> { - let struct_data = db.struct_signature(def); + let struct_data = StructSignature::of(db, def); match struct_data.shape { FieldsShape::Record => None, FieldsShape::Unit => Some(type_for_adt(db, def.into())), @@ -1477,7 +1481,7 @@ pub(crate) fn type_for_type_alias_with_diagnostics_query<'db>( db: &'db dyn HirDatabase, t: TypeAliasId, ) -> (StoredEarlyBinder, Diagnostics) { - let type_alias_data = db.type_alias_signature(t); + let type_alias_data = TypeAliasSignature::of(db, t); let mut diags = None; let resolver = t.resolver(db); let interner = DbInterner::new_no_crate(db); @@ -1540,7 +1544,7 @@ pub(crate) fn impl_self_ty_with_diagnostics_query<'db>( ) -> (StoredEarlyBinder, Diagnostics) { let resolver = impl_id.resolver(db); - let impl_data = db.impl_signature(impl_id); + let impl_data = ImplSignature::of(db, impl_id); let mut ctx = TyLoweringContext::new( db, &resolver, @@ -1586,14 +1590,14 @@ pub(crate) fn const_param_ty_with_diagnostics_query<'db>( _: (), def: ConstParamId, ) -> (StoredTy, Diagnostics) { - let (parent_data, store) = db.generic_params_and_store(def.parent()); + let (parent_data, store) = GenericParams::of(db, def.parent()); let data = &parent_data[def.local_id()]; let resolver = def.parent().resolver(db); let interner = DbInterner::new_no_crate(db); let mut ctx = TyLoweringContext::new( db, &resolver, - &store, + store, def.parent(), LifetimeElisionKind::AnonymousReportError, ); @@ -1684,7 +1688,7 @@ fn supertraits_info(db: &dyn HirDatabase, trait_: TraitId) -> SupertraitsInfo { )); let resolver = trait_.resolver(db); - let signature = db.trait_signature(trait_); + 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 @@ -1955,7 +1959,7 @@ pub fn type_alias_bounds_with_diagnostics_query<'db>( db: &'db dyn HirDatabase, type_alias: TypeAliasId, ) -> (TypeAliasBounds>, Diagnostics) { - let type_alias_data = db.type_alias_signature(type_alias); + let type_alias_data = TypeAliasSignature::of(db, type_alias); let resolver = hir_def::resolver::HasResolver::resolver(type_alias, db); let mut ctx = TyLoweringContext::new( db, @@ -2134,16 +2138,6 @@ pub fn explicit_implied_predicates(&self) -> EarlyBinder<'_, &[Clause<'_>]> { } } -pub(crate) fn trait_environment_for_body_query( - db: &dyn HirDatabase, - def: DefWithBodyId, -) -> ParamEnv<'_> { - let Some(def) = def.as_generic_def_id(db) else { - return ParamEnv::empty(); - }; - db.trait_environment(def) -} - pub(crate) fn param_env_from_predicates<'db>( interner: DbInterner<'db>, predicates: &'db GenericPredicates, @@ -2158,7 +2152,18 @@ pub(crate) fn param_env_from_predicates<'db>( ParamEnv { clauses } } -pub(crate) fn trait_environment<'db>(db: &'db dyn HirDatabase, def: GenericDefId) -> ParamEnv<'db> { +pub(crate) fn trait_environment<'db>( + db: &'db dyn HirDatabase, + def: ExpressionStoreOwnerId, +) -> ParamEnv<'db> { + let def = match def { + ExpressionStoreOwnerId::Signature(def) => def, + ExpressionStoreOwnerId::Body(def) => match def.as_generic_def_id(db) { + Some(def) => def, + None => return ParamEnv::empty(), + }, + }; + return ParamEnv { clauses: trait_environment_query(db, def).as_ref() }; #[salsa::tracked(returns(ref))] @@ -2358,7 +2363,7 @@ fn implicit_trait_predicate<'db>( fn push_const_arg_has_type_predicates<'db>( db: &'db dyn HirDatabase, predicates: &mut Vec>, - generics: &Generics, + generics: &Generics<'db>, ) { let interner = DbInterner::new_no_crate(db); let const_params_offset = generics.len_parent() + generics.len_lifetimes_self(); @@ -2504,7 +2509,7 @@ pub(crate) fn callable_item_signature_query<'db>( } fn fn_sig_for_fn(db: &dyn HirDatabase, def: FunctionId) -> StoredEarlyBinder { - let data = db.function_signature(def); + let data = FunctionSignature::of(db, def); let resolver = def.resolver(db); let interner = DbInterner::new_no_crate(db); let mut ctx_params = TyLoweringContext::new( @@ -2512,7 +2517,7 @@ fn fn_sig_for_fn(db: &dyn HirDatabase, def: FunctionId) -> StoredEarlyBinder( db: &'db dyn HirDatabase, type_alias: TypeAliasId, ) -> EarlyBinder<'db, BoundExistentialPredicates<'db>> { - let type_alias_data = db.type_alias_signature(type_alias); + let type_alias_data = TypeAliasSignature::of(db, type_alias); let resolver = hir_def::resolver::HasResolver::resolver(type_alias, db); let interner = DbInterner::new_no_crate(db); let mut ctx = TyLoweringContext::new( @@ -2612,7 +2617,7 @@ pub(crate) fn associated_ty_item_bounds<'db>( .map_bound(|c| match c { rustc_type_ir::ClauseKind::Trait(t) => { let id = t.def_id(); - let is_auto = db.trait_signature(id.0).flags.contains(TraitFlags::AUTO); + let is_auto = TraitSignature::of(db, id.0).flags.contains(TraitFlags::AUTO); if is_auto { Some(ExistentialPredicate::AutoTrait(t.def_id())) } else { 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 81a944128d23..889f0792d347 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 @@ -14,7 +14,7 @@ GenericParamDataRef, TypeOrConstParamData, TypeParamData, TypeParamProvenance, }, resolver::{ResolveValueResult, TypeNs, ValueNs}, - signatures::TraitFlags, + signatures::{TraitFlags, TraitSignature}, type_ref::{TypeRef, TypeRefId}, }; use rustc_type_ir::{ @@ -625,10 +625,7 @@ pub(crate) fn substs_from_path_segment( GenericDefId::TraitId(trait_) => { // RTN is prohibited anyways if we got here. let is_rtn = args.parenthesized == GenericArgsParentheses::ReturnTypeNotation; - let is_fn_trait = self - .ctx - .db - .trait_signature(trait_) + let is_fn_trait = TraitSignature::of(self.ctx.db, trait_) .flags .contains(TraitFlags::RUSTC_PAREN_SUGAR); is_rtn || !is_fn_trait @@ -1024,7 +1021,7 @@ fn inferred_kind( fn check_generic_args_len<'db>( args_and_bindings: Option<&HirGenericArgs>, def: GenericDefId, - def_generics: &Generics, + def_generics: &Generics<'db>, infer_args: bool, lifetime_elision: &LifetimeElisionKind<'db>, lowering_assoc_type_generics: bool, 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 ad4d79e68a9f..e058a254205e 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 @@ -17,11 +17,12 @@ ImplId, ItemContainerId, ModuleId, TraitId, attrs::AttrFlags, builtin_derive::BuiltinDeriveImplMethod, - expr_store::path::GenericArgs as HirGenericArgs, + expr_store::{Body, path::GenericArgs as HirGenericArgs}, hir::ExprId, lang_item::LangItems, nameres::{DefMap, block_def_map, crate_def_map}, resolver::Resolver, + signatures::{ConstSignature, FunctionSignature}, }; use intern::{Symbol, sym}; use rustc_hash::{FxHashMap, FxHashSet}; @@ -366,7 +367,7 @@ pub fn lookup_impl_const<'db>( }; let trait_ref = TraitRef::new_from_args(interner, trait_id.into(), subs); - let const_signature = db.const_signature(const_id); + let const_signature = ConstSignature::of(db, const_id); let name = match const_signature.name.as_ref() { Some(name) => name, None => return (const_id, subs), @@ -439,7 +440,7 @@ pub(crate) fn lookup_impl_method_query<'db>( GenericArgs::new_from_slice(&fn_subst[..trait_params]), ); - let name = &db.function_signature(func).name; + let name = &FunctionSignature::of(db, func).name; let Some((impl_fn, impl_subst)) = lookup_impl_assoc_item_for_trait_ref(&infcx, trait_ref, env.param_env, name).and_then( |(assoc, impl_args)| { @@ -623,7 +624,7 @@ fn collect( // To better support custom derives, collect impls in all unnamed const items. // const _: () = { ... }; for konst in module_data.scope.unnamed_consts() { - let body = db.body(konst.into()); + let body = Body::of(db, konst.into()); for (_, block_def_map) in body.blocks(db) { collect(db, block_def_map, map); } @@ -766,7 +767,7 @@ fn collect( // To better support custom derives, collect impls in all unnamed const items. // const _: () = { ... }; for konst in module_data.scope.unnamed_consts() { - let body = db.body(konst.into()); + let body = Body::of(db, konst.into()); for (_, block_def_map) in body.blocks(db) { collect(db, block_def_map, lang_items, map); } 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 fc2bd87ee429..e2a53cc830e3 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 @@ -5,7 +5,7 @@ use hir_def::{ AssocItemId, FunctionId, GenericParamId, ImplId, ItemContainerId, TraitId, - signatures::TraitFlags, + signatures::{FunctionSignature, TraitFlags, TraitSignature}, }; use hir_expand::name::Name; use rustc_ast_ir::Mutability; @@ -1605,7 +1605,8 @@ fn consider_probe( // Some trait methods are excluded for arrays before 2021. // (`array.into_iter()` wants a slice iterator for compatibility.) if self_ty.is_array() && !self.ctx.edition.at_least_2021() { - let trait_signature = self.db().trait_signature(poly_trait_ref.def_id().0); + let trait_signature = + TraitSignature::of(self.db(), poly_trait_ref.def_id().0); if trait_signature .flags .contains(TraitFlags::SKIP_ARRAY_DURING_METHOD_DISPATCH) @@ -1619,7 +1620,8 @@ fn consider_probe( if self_ty.boxed_ty().is_some_and(Ty::is_slice) && !self.ctx.edition.at_least_2024() { - let trait_signature = self.db().trait_signature(poly_trait_ref.def_id().0); + let trait_signature = + TraitSignature::of(self.db(), poly_trait_ref.def_id().0); if trait_signature .flags .contains(TraitFlags::SKIP_BOXED_SLICE_DURING_METHOD_DISPATCH) @@ -1963,7 +1965,7 @@ fn has_applicable_self(&self, item: CandidateId) -> bool { // associated value (i.e., methods, constants). match item { CandidateId::FunctionId(id) if self.mode == Mode::MethodCall => { - self.db().function_signature(id).has_self_param() + FunctionSignature::of(self.db(), id).has_self_param() } _ => true, } 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 2dcc2d1062fd..3ff2db15aaf5 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 @@ -5,10 +5,10 @@ use std::iter; -use hir_def::{DefWithBodyId, HasModule}; +use hir_def::{DefWithBodyId, ExpressionStoreOwnerId, HasModule}; use la_arena::ArenaMap; use rustc_hash::FxHashMap; -use rustc_type_ir::inherent::{GenericArgs as _, Ty as _}; +use rustc_type_ir::inherent::GenericArgs as _; use stdx::never; use triomphe::Arc; @@ -18,7 +18,7 @@ display::DisplayTarget, mir::OperandKind, next_solver::{ - DbInterner, ErrorGuaranteed, GenericArgs, ParamEnv, StoredTy, Ty, TypingMode, + DbInterner, GenericArgs, ParamEnv, StoredTy, Ty, TypingMode, infer::{DbInternerInferExt, InferCtxt}, }, }; @@ -99,7 +99,7 @@ pub fn borrowck_query( let _p = tracing::info_span!("borrowck_query").entered(); let module = def.module(db); let interner = DbInterner::new_with(db, module.krate(db)); - let env = db.trait_environment_for_body(def); + let env = db.trait_environment(ExpressionStoreOwnerId::from(def)); let mut res = vec![]; // This calculates opaques defining scope which is a bit costly therefore is put outside `all_mir_bodies()`. let typing_mode = TypingMode::borrowck(interner, def.into()); @@ -123,10 +123,7 @@ fn make_fetch_closure_field<'db>( |c: InternedClosureId, subst: GenericArgs<'db>, f: usize| { let InternedClosure(owner, _) = db.lookup_intern_closure(c); let interner = DbInterner::new_no_crate(db); - let Some(def) = owner.as_def_with_body() else { - return Ty::new_error(interner, ErrorGuaranteed); - }; - let infer = InferenceResult::for_body(db, def); + let infer = InferenceResult::of(db, owner); let (captures, _) = infer.closure_info(c); let parent_subst = subst.as_closure().parent_args(); captures.get(f).expect("broken closure field").ty.get().instantiate(interner, parent_subst) 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 a85b3ef50aa5..c013e78d81b8 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 @@ -5,14 +5,17 @@ use base_db::{Crate, target::TargetLoadError}; use either::Either; use hir_def::{ - AdtId, DefWithBodyId, EnumVariantId, FunctionId, GeneralConstId, HasModule, ItemContainerId, - Lookup, StaticId, VariantId, - expr_store::HygieneId, + AdtId, DefWithBodyId, EnumVariantId, ExpressionStoreOwnerId, FunctionId, GeneralConstId, + HasModule, ItemContainerId, Lookup, StaticId, VariantId, + expr_store::{Body, HygieneId}, item_tree::FieldsShape, lang_item::LangItems, layout::{TagEncoding, Variants}, resolver::{HasResolver, TypeNs, ValueNs}, - signatures::{StaticFlags, StructFlags}, + signatures::{ + EnumSignature, FunctionSignature, StaticFlags, StaticSignature, StructFlags, + StructSignature, TraitSignature, + }, }; use hir_expand::{InFile, mod_path::path, name::Name}; use intern::sym; @@ -386,7 +389,7 @@ pub fn pretty_print( for (func, span, def) in stack.iter().take(30).rev() { match func { Either::Left(func) => { - let function_name = db.function_signature(*func); + let function_name = FunctionSignature::of(db, *func); writeln!( f, "In function {} ({:?})", @@ -398,7 +401,7 @@ pub fn pretty_print( writeln!(f, "In {closure:?}")?; } } - let source_map = db.body_with_source_map(*def).1; + let source_map = &Body::with_source_map(db, *def).1; let span: InFile = match span { MirSpan::ExprId(e) => match source_map.expr_syntax(*e) { Ok(s) => s.map(|it| it.into()), @@ -441,7 +444,7 @@ pub fn pretty_print( )?; } MirEvalError::MirLowerError(func, err) => { - let function_name = db.function_signature(*func); + let function_name = FunctionSignature::of(db, *func); let self_ = match func.lookup(db).container { ItemContainerId::ImplId(impl_id) => Some({ db.impl_self_ty(impl_id) @@ -450,7 +453,10 @@ pub fn pretty_print( .to_string() }), ItemContainerId::TraitId(it) => Some( - db.trait_signature(it).name.display(db, display_target.edition).to_string(), + TraitSignature::of(db, it) + .name + .display(db, display_target.edition) + .to_string(), ), _ => None, }; @@ -660,7 +666,7 @@ pub fn new( db, random_state: oorandom::Rand64::new(0), param_env: trait_env.unwrap_or_else(|| ParamEnvAndCrate { - param_env: db.trait_environment_for_body(owner), + param_env: db.trait_environment(ExpressionStoreOwnerId::from(owner)), krate: crate_id, }), crate_id, @@ -731,10 +737,7 @@ fn projected_ty(&self, ty: Ty<'db>, proj: PlaceElem) -> Ty<'db> { ty, |c, subst, f| { let InternedClosure(owner, _) = self.db.lookup_intern_closure(c); - let Some(def) = owner.as_def_with_body() else { - return Ty::new_error(self.interner(), ErrorGuaranteed); - }; - let infer = InferenceResult::for_body(self.db, def); + let infer = InferenceResult::of(self.db, owner); let (captures, _) = infer.closure_info(c); let parent_subst = subst.as_closure().parent_args(); captures @@ -896,8 +899,8 @@ fn operand_ty(&self, o: &Operand, locals: &Locals) -> Result<'db, Ty<'db>> { OperandKind::Copy(p) | OperandKind::Move(p) => self.place_ty(p, locals)?, OperandKind::Constant { konst: _, ty } => ty.as_ref(), &OperandKind::Static(s) => { - let ty = InferenceResult::for_body(self.db, s.into()) - .expr_ty(self.db.body(s.into()).body_expr); + let ty = InferenceResult::of(self.db, DefWithBodyId::from(s)) + .expr_ty(Body::of(self.db, s.into()).body_expr); Ty::new_ref( self.interner(), Region::new_static(self.interner()), @@ -2824,15 +2827,15 @@ fn eval_static(&mut self, st: StaticId, locals: &Locals) -> Result<'db, Address> if let Some(o) = self.static_locations.get(&st) { return Ok(*o); }; - let static_data = self.db.static_signature(st); + let static_data = StaticSignature::of(self.db, st); let result = if !static_data.flags.contains(StaticFlags::EXTERN) { let konst = self.db.const_eval_static(st).map_err(|e| { MirEvalError::ConstEvalError(static_data.name.as_str().to_owned(), Box::new(e)) })?; self.allocate_const_in_heap(locals, konst)? } else { - let ty = InferenceResult::for_body(self.db, st.into()) - .expr_ty(self.db.body(st.into()).body_expr); + let ty = InferenceResult::of(self.db, DefWithBodyId::from(st)) + .expr_ty(Body::of(self.db, st.into()).body_expr); let Some((size, align)) = self.size_align_of(ty, locals)? else { not_supported!("unsized extern static"); }; @@ -2855,7 +2858,7 @@ fn const_eval_discriminant(&self, variant: EnumVariantId) -> Result<'db, i128> { let edition = self.crate_id.data(self.db).edition; let name = format!( "{}::{}", - self.db.enum_signature(loc.parent).name.display(db, edition), + EnumSignature::of(self.db, loc.parent).name.display(db, edition), loc.parent .enum_variants(self.db) .variant_name_by_id(variant) @@ -2915,7 +2918,7 @@ fn run_drop_glue_deep( let id = adt_def.def_id().0; match id { AdtId::StructId(s) => { - let data = self.db.struct_signature(s); + let data = StructSignature::of(self.db, s); if data.flags.contains(StructFlags::IS_MANUALLY_DROP) { return Ok(()); } 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 86d951060140..ff6c99ca53b3 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 @@ -45,7 +45,7 @@ pub(super) fn detect_and_exec_special_function( return Ok(false); } - let function_data = self.db.function_signature(def); + let function_data = FunctionSignature::of(self.db, def); let attrs = AttrFlags::query(self.db, def.into()); let is_intrinsic = FunctionSignature::is_intrinsic(self.db, def); @@ -153,10 +153,7 @@ fn exec_clone( }; let addr = Address::from_bytes(arg.get(self)?)?; let InternedClosure(owner, _) = self.db.lookup_intern_closure(id.0); - let Some(closure_owner) = owner.as_def_with_body() else { - not_supported!("closure in non-body context"); - }; - let infer = InferenceResult::for_body(self.db, closure_owner); + let infer = InferenceResult::of(self.db, owner); let (captures, _) = infer.closure_info(id.0); let layout = self.layout(self_ty)?; let db = self.db; 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 61dd7757c90b..6bf966c3ef1d 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 @@ -1,4 +1,4 @@ -use hir_def::{HasModule, db::DefDatabase}; +use hir_def::{GenericDefId, HasModule, signatures::FunctionSignature}; use hir_expand::EditionedFileId; use span::Edition; use syntax::{TextRange, TextSize}; @@ -25,7 +25,7 @@ fn eval_main(db: &TestDB, file_id: EditionedFileId) -> Result<(String, String), .declarations() .find_map(|x| match x { hir_def::ModuleDefId::FunctionId(x) => { - if db.function_signature(x).name.display(db, Edition::CURRENT).to_string() + if FunctionSignature::of(db, x).name.display(db, Edition::CURRENT).to_string() == "main" { Some(x) @@ -41,7 +41,7 @@ fn eval_main(db: &TestDB, file_id: EditionedFileId) -> Result<(String, String), func_id.into(), GenericArgs::empty(interner).store(), crate::ParamEnvAndCrate { - param_env: db.trait_environment(func_id.into()), + param_env: db.trait_environment(GenericDefId::from(func_id).into()), krate: func_id.krate(db), } .store(), 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 269d8729baf3..8d85e2412f3b 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 @@ -4,8 +4,8 @@ use base_db::Crate; use hir_def::{ - AdtId, DefWithBodyId, EnumVariantId, GeneralConstId, GenericParamId, HasModule, - ItemContainerId, LocalFieldId, Lookup, TraitId, TupleId, + AdtId, DefWithBodyId, EnumVariantId, ExpressionStoreOwnerId, GeneralConstId, GenericParamId, + HasModule, ItemContainerId, LocalFieldId, Lookup, TraitId, TupleId, expr_store::{Body, ExpressionStore, HygieneId, path::Path}, hir::{ ArithOp, Array, BinaryOp, BindingAnnotation, BindingId, ExprId, LabelId, Literal, MatchArm, @@ -14,6 +14,7 @@ item_tree::FieldsShape, lang_item::LangItems, resolver::{HasResolver, ResolveValueResult, Resolver, ValueNs}, + signatures::{ConstSignature, EnumSignature, FunctionSignature, StaticSignature}, }; use hir_expand::name::Name; use la_arena::ArenaMap; @@ -185,7 +186,7 @@ pub fn pretty_print( } } MirLowerError::MissingFunctionDefinition(owner, it) => { - let body = db.body(*owner); + let body = Body::of(db, *owner); writeln!( f, "Missing function definition for {}", @@ -307,7 +308,7 @@ fn new( closures: vec![], }; let resolver = owner.resolver(db); - let env = db.trait_environment_for_body(owner); + let env = db.trait_environment(ExpressionStoreOwnerId::from(owner)); let interner = DbInterner::new_with(db, resolver.krate()); // FIXME(next-solver): Is `non_body_analysis()` correct here? Don't we want to reveal opaque types defined by this body? let infcx = interner.infer_ctxt().build(TypingMode::non_body_analysis()); @@ -472,7 +473,7 @@ fn lower_expr_to_place_without_adjust( if let DefWithBodyId::FunctionId(f) = self.owner { let assoc = f.lookup(self.db); if let ItemContainerId::TraitId(t) = assoc.container { - let name = &self.db.function_signature(f).name; + let name = &FunctionSignature::of(self.db, f).name; return Err(MirLowerError::TraitFunctionDefinition(t, name.clone())); } } @@ -1993,7 +1994,7 @@ fn const_eval_discriminant(&self, variant: EnumVariantId) -> Result<'db, i128> { let loc = variant.lookup(db); let name = format!( "{}::{}", - self.db.enum_signature(loc.parent).name.display(db, edition), + EnumSignature::of(db, loc.parent).name.display(db, edition), loc.parent .enum_variants(self.db) .variant_name_by_id(variant) @@ -2112,8 +2113,8 @@ pub fn mir_body_for_closure_query<'db>( let InternedClosure(owner, expr) = db.lookup_intern_closure(closure); let body_owner = owner.as_def_with_body().expect("MIR lowering should only happen for body-owned closures"); - let body = db.body(body_owner); - let infer = InferenceResult::for_body(db, body_owner); + let body = Body::of(db, body_owner); + let infer = InferenceResult::of(db, body_owner); let Expr::Closure { args, body: root, .. } = &body[expr] else { implementation_error!("closure expression is not closure"); }; @@ -2228,13 +2229,12 @@ pub fn mir_body_query<'db>( let edition = krate.data(db).edition; let detail = match def { DefWithBodyId::FunctionId(it) => { - db.function_signature(it).name.display(db, edition).to_string() + FunctionSignature::of(db, it).name.display(db, edition).to_string() } DefWithBodyId::StaticId(it) => { - db.static_signature(it).name.display(db, edition).to_string() + StaticSignature::of(db, it).name.display(db, edition).to_string() } - DefWithBodyId::ConstId(it) => db - .const_signature(it) + DefWithBodyId::ConstId(it) => ConstSignature::of(db, it) .name .clone() .unwrap_or_else(Name::missing) @@ -2249,9 +2249,9 @@ pub fn mir_body_query<'db>( } }; let _p = tracing::info_span!("mir_body_query", ?detail).entered(); - let body = db.body(def); - let infer = InferenceResult::for_body(db, def); - let mut result = lower_body_to_mir(db, def, &body, infer, body.body_expr)?; + let body = Body::of(db, def); + let infer = InferenceResult::of(db, def); + let mut result = lower_body_to_mir(db, def, body, infer, body.body_expr)?; result.shrink_to_fit(); Ok(Arc::new(result)) } 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 96b90a3f4074..4b654a0fbe08 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 @@ -6,7 +6,11 @@ }; use either::Either; -use hir_def::{expr_store::Body, hir::BindingId}; +use hir_def::{ + expr_store::Body, + hir::BindingId, + signatures::{ConstSignature, EnumSignature, FunctionSignature, StaticSignature}, +}; use hir_expand::{Lookup, name::Name}; use la_arena::ArenaMap; @@ -38,19 +42,19 @@ macro_rules! wln { impl MirBody { pub fn pretty_print(&self, db: &dyn HirDatabase, display_target: DisplayTarget) -> String { - let hir_body = db.body(self.owner); - let mut ctx = MirPrettyCtx::new(self, &hir_body, db, display_target); + let hir_body = Body::of(db, self.owner); + let mut ctx = MirPrettyCtx::new(self, hir_body, db, display_target); ctx.for_body(|this| match ctx.body.owner { hir_def::DefWithBodyId::FunctionId(id) => { - let data = db.function_signature(id); + let data = FunctionSignature::of(db, id); w!(this, "fn {}() ", data.name.display(db, this.display_target.edition)); } hir_def::DefWithBodyId::StaticId(id) => { - let data = db.static_signature(id); + let data = StaticSignature::of(db, id); w!(this, "static {}: _ = ", data.name.display(db, this.display_target.edition)); } hir_def::DefWithBodyId::ConstId(id) => { - let data = db.const_signature(id); + let data = ConstSignature::of(db, id); w!( this, "const {}: _ = ", @@ -66,7 +70,7 @@ pub fn pretty_print(&self, db: &dyn HirDatabase, display_target: DisplayTarget) w!( this, "enum {}::{} = ", - db.enum_signature(loc.parent).name.display(db, edition), + EnumSignature::of(db, loc.parent).name.display(db, edition), loc.parent .enum_variants(db) .variant_name_by_id(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 f725af320db7..5d122ce446ad 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 @@ -2,8 +2,12 @@ use hir_def::{ AdtId, AnonConstId, AttrDefId, BuiltinDeriveImplId, CallableDefId, ConstId, DefWithBodyId, - EnumId, EnumVariantId, ExpressionStoreOwner, FunctionId, GeneralConstId, GenericDefId, ImplId, - StaticId, StructId, TraitId, TypeAliasId, UnionId, + EnumId, EnumVariantId, ExpressionStoreOwnerId, FunctionId, GeneralConstId, GenericDefId, + ImplId, StaticId, StructId, TraitId, TypeAliasId, UnionId, + signatures::{ + ConstSignature, EnumSignature, FunctionSignature, StaticSignature, StructSignature, + TraitSignature, TypeAliasSignature, UnionSignature, + }, }; use rustc_type_ir::inherent; use stdx::impl_from; @@ -42,32 +46,33 @@ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let db = interner.db; match *self { SolverDefId::AdtId(AdtId::StructId(id)) => { - f.debug_tuple("AdtId").field(&db.struct_signature(id).name.as_str()).finish() + f.debug_tuple("AdtId").field(&StructSignature::of(db, id).name.as_str()).finish() } SolverDefId::AdtId(AdtId::EnumId(id)) => { - f.debug_tuple("AdtId").field(&db.enum_signature(id).name.as_str()).finish() + f.debug_tuple("AdtId").field(&EnumSignature::of(db, id).name.as_str()).finish() } SolverDefId::AdtId(AdtId::UnionId(id)) => { - f.debug_tuple("AdtId").field(&db.union_signature(id).name.as_str()).finish() + f.debug_tuple("AdtId").field(&UnionSignature::of(db, id).name.as_str()).finish() } SolverDefId::ConstId(id) => f .debug_tuple("ConstId") - .field(&db.const_signature(id).name.as_ref().map_or("_", |name| name.as_str())) + .field(&ConstSignature::of(db, id).name.as_ref().map_or("_", |name| name.as_str())) + .finish(), + SolverDefId::FunctionId(id) => f + .debug_tuple("FunctionId") + .field(&FunctionSignature::of(db, id).name.as_str()) .finish(), - SolverDefId::FunctionId(id) => { - f.debug_tuple("FunctionId").field(&db.function_signature(id).name.as_str()).finish() - } SolverDefId::ImplId(id) => f.debug_tuple("ImplId").field(&id).finish(), SolverDefId::BuiltinDeriveImplId(id) => f.debug_tuple("ImplId").field(&id).finish(), SolverDefId::StaticId(id) => { - f.debug_tuple("StaticId").field(&db.static_signature(id).name.as_str()).finish() + f.debug_tuple("StaticId").field(&StaticSignature::of(db, id).name.as_str()).finish() } SolverDefId::TraitId(id) => { - f.debug_tuple("TraitId").field(&db.trait_signature(id).name.as_str()).finish() + f.debug_tuple("TraitId").field(&TraitSignature::of(db, id).name.as_str()).finish() } SolverDefId::TypeAliasId(id) => f .debug_tuple("TypeAliasId") - .field(&db.type_alias_signature(id).name.as_str()) + .field(&TypeAliasSignature::of(db, id).name.as_str()) .finish(), SolverDefId::InternedClosureId(id) => { f.debug_tuple("InternedClosureId").field(&id).finish() @@ -83,21 +88,21 @@ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_tuple("EnumVariantId") .field(&format_args!( "\"{}::{}\"", - db.enum_signature(parent_enum).name.as_str(), + EnumSignature::of(db, parent_enum).name.as_str(), parent_enum.enum_variants(db).variant_name_by_id(id).unwrap().as_str() )) .finish() } SolverDefId::AnonConstId(id) => f.debug_tuple("AnonConstId").field(&id).finish(), SolverDefId::Ctor(Ctor::Struct(id)) => { - f.debug_tuple("Ctor").field(&db.struct_signature(id).name.as_str()).finish() + f.debug_tuple("Ctor").field(&StructSignature::of(db, id).name.as_str()).finish() } SolverDefId::Ctor(Ctor::Enum(id)) => { let parent_enum = id.loc(db).parent; f.debug_tuple("Ctor") .field(&format_args!( "\"{}::{}\"", - db.enum_signature(parent_enum).name.as_str(), + EnumSignature::of(db, parent_enum).name.as_str(), parent_enum.enum_variants(db).variant_name_by_id(id).unwrap().as_str() )) .finish() @@ -138,15 +143,6 @@ fn from(value: GenericDefId) -> Self { } } -impl From for SolverDefId { - fn from(value: ExpressionStoreOwner) -> Self { - match value { - ExpressionStoreOwner::Signature(generic_def_id) => generic_def_id.into(), - ExpressionStoreOwner::Body(def_with_body_id) => def_with_body_id.into(), - } - } -} - impl From for SolverDefId { #[inline] fn from(value: GeneralConstId) -> Self { @@ -170,6 +166,16 @@ fn from(value: DefWithBodyId) -> Self { } } +impl From for SolverDefId { + #[inline] + fn from(value: ExpressionStoreOwnerId) -> Self { + match value { + ExpressionStoreOwnerId::Body(body_id) => body_id.into(), + ExpressionStoreOwnerId::Signature(sig_id) => sig_id.into(), + } + } +} + impl TryFrom for AttrDefId { type Error = (); #[inline] diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/fulfill/errors.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/fulfill/errors.rs index 8f798b4ade24..0e8218b33aaa 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/fulfill/errors.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/fulfill/errors.rs @@ -617,6 +617,7 @@ pub fn to_debuggable_error(&self, infcx: &InferCtxt<'db>) -> FulfillmentError<'d } mod wf { + use hir_def::signatures::ImplSignature; use hir_def::{GeneralConstId, ItemContainerId}; use rustc_type_ir::inherent::{ AdtDef, BoundExistentialPredicates, GenericArgs as _, IntoKind, SliceLike, Term as _, @@ -1054,7 +1055,7 @@ fn visit_const(&mut self, c: Const<'db>) -> Self::Result { if let GeneralConstId::ConstId(uv_def) = uv.def.0 && let ItemContainerId::ImplId(impl_) = uv_def.loc(self.interner().db).container - && self.interner().db.impl_signature(impl_).target_trait.is_none() + && ImplSignature::of(self.interner().db, impl_).target_trait.is_none() { return; // Subtree is handled by above function } else { 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 dba4e74730f1..5b81c7675dbb 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 @@ -10,11 +10,15 @@ use base_db::Crate; use hir_def::{ - AdtId, CallableDefId, DefWithBodyId, EnumVariantId, ExpressionStoreOwner, HasModule, + AdtId, CallableDefId, DefWithBodyId, EnumVariantId, ExpressionStoreOwnerId, HasModule, ItemContainerId, StructId, UnionId, VariantId, attrs::AttrFlags, + expr_store::{Body, ExpressionStore}, lang_item::LangItems, - signatures::{FieldData, FnFlags, ImplFlags, StructFlags, TraitFlags}, + signatures::{ + EnumSignature, FieldData, FnFlags, FunctionSignature, ImplFlags, ImplSignature, + StructFlags, StructSignature, TraitFlags, TraitSignature, UnionSignature, + }, }; use la_arena::Idx; use rustc_abi::{ReprFlags, ReprOptions}; @@ -548,7 +552,7 @@ pub fn new<'db>(def_id: AdtId, interner: DbInterner<'db>) -> Self { let db = interner.db(); let (flags, variants, repr) = match def_id { AdtId::StructId(struct_id) => { - let data = db.struct_signature(struct_id); + let data = StructSignature::of(db, struct_id); let flags = AdtFlags { is_enum: false, @@ -775,15 +779,15 @@ impl fmt::Debug for AdtDef { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { crate::with_attached_db(|db| match self.inner().id { AdtId::StructId(struct_id) => { - let data = db.struct_signature(struct_id); + let data = StructSignature::of(db, struct_id); f.write_str(data.name.as_str()) } AdtId::UnionId(union_id) => { - let data = db.union_signature(union_id); + let data = UnionSignature::of(db, union_id); f.write_str(data.name.as_str()) } AdtId::EnumId(enum_id) => { - let data = db.enum_signature(enum_id); + let data = EnumSignature::of(db, enum_id); f.write_str(data.name.as_str()) } }) @@ -1231,7 +1235,7 @@ fn alias_ty_kind(self, alias: rustc_type_ir::AliasTy) -> AliasTyKind { SolverDefId::InternedOpaqueTyId(_) => AliasTyKind::Opaque, SolverDefId::TypeAliasId(type_alias) => match type_alias.loc(self.db).container { ItemContainerId::ImplId(impl_) - if self.db.impl_signature(impl_).target_trait.is_none() => + if ImplSignature::of(self.db, impl_).target_trait.is_none() => { AliasTyKind::Inherent } @@ -1250,7 +1254,7 @@ fn alias_term_kind( SolverDefId::InternedOpaqueTyId(_) => AliasTermKind::OpaqueTy, SolverDefId::TypeAliasId(type_alias) => match type_alias.loc(self.db).container { ItemContainerId::ImplId(impl_) - if self.db.impl_signature(impl_).target_trait.is_none() => + if ImplSignature::of(self.db, impl_).target_trait.is_none() => { AliasTermKind::InherentTy } @@ -1353,11 +1357,8 @@ fn coroutine_movability(self, def_id: Self::CoroutineId) -> rustc_ast_ir::Movabi // FIXME: Make this a query? I don't believe this can be accessed from bodies other than // the current infer query, except with revealed opaques - is it rare enough to not matter? let InternedCoroutine(owner, expr_id) = def_id.0.loc(self.db); - let Some(body_owner) = owner.as_def_with_body() else { - return rustc_ast_ir::Movability::Static; - }; - let body = self.db.body(body_owner); - let expr = &body[expr_id]; + let store = ExpressionStore::of(self.db, owner); + let expr = &store[expr_id]; match *expr { hir_def::hir::Expr::Closure { closure_kind, .. } => match closure_kind { hir_def::hir::ClosureKind::Coroutine(movability) => match movability { @@ -1929,7 +1930,7 @@ fn has_item_definition(self, _def_id: Self::DefId) -> bool { fn impl_is_default(self, impl_def_id: Self::ImplId) -> bool { match impl_def_id { - AnyImplId::ImplId(impl_id) => self.db.impl_signature(impl_id).is_default(), + AnyImplId::ImplId(impl_id) => ImplSignature::of(self.db, impl_id).is_default(), AnyImplId::BuiltinDeriveImplId(_) => false, } } @@ -1956,7 +1957,7 @@ fn impl_polarity(self, impl_id: Self::ImplId) -> rustc_type_ir::ImplPolarity { let AnyImplId::ImplId(impl_id) = impl_id else { return ImplPolarity::Positive; }; - let impl_data = self.db().impl_signature(impl_id); + let impl_data = ImplSignature::of(self.db(), impl_id); if impl_data.flags.contains(ImplFlags::NEGATIVE) { ImplPolarity::Negative } else { @@ -1965,12 +1966,12 @@ fn impl_polarity(self, impl_id: Self::ImplId) -> rustc_type_ir::ImplPolarity { } fn trait_is_auto(self, trait_: Self::TraitId) -> bool { - let trait_data = self.db().trait_signature(trait_.0); + let trait_data = TraitSignature::of(self.db(), trait_.0); trait_data.flags.contains(TraitFlags::AUTO) } fn trait_is_alias(self, trait_: Self::TraitId) -> bool { - let trait_data = self.db().trait_signature(trait_.0); + let trait_data = TraitSignature::of(self.db(), trait_.0); trait_data.flags.contains(TraitFlags::ALIAS) } @@ -1979,7 +1980,7 @@ fn trait_is_dyn_compatible(self, trait_: Self::TraitId) -> bool { } fn trait_is_fundamental(self, trait_: Self::TraitId) -> bool { - let trait_data = self.db().trait_signature(trait_.0); + let trait_data = TraitSignature::of(self.db(), trait_.0); trait_data.flags.contains(TraitFlags::FUNDAMENTAL) } @@ -2002,12 +2003,9 @@ fn is_general_coroutine(self, def_id: Self::CoroutineId) -> bool { // FIXME: Make this a query? I don't believe this can be accessed from bodies other than // the current infer query, except with revealed opaques - is it rare enough to not matter? let InternedCoroutine(owner, expr_id) = def_id.0.loc(self.db); - let Some(body_owner) = owner.as_def_with_body() else { - return false; - }; - let body = self.db.body(body_owner); + let store = ExpressionStore::of(self.db, owner); matches!( - body[expr_id], + store[expr_id], hir_def::hir::Expr::Closure { closure_kind: hir_def::hir::ClosureKind::Coroutine(_), .. @@ -2019,12 +2017,9 @@ fn coroutine_is_async(self, def_id: Self::CoroutineId) -> bool { // FIXME: Make this a query? I don't believe this can be accessed from bodies other than // the current infer query, except with revealed opaques - is it rare enough to not matter? let InternedCoroutine(owner, expr_id) = def_id.0.loc(self.db); - let Some(body_owner) = owner.as_def_with_body() else { - return false; - }; - let body = self.db.body(body_owner); + let store = ExpressionStore::of(self.db, owner); matches!( - body[expr_id], + store[expr_id], hir_def::hir::Expr::Closure { closure_kind: hir_def::hir::ClosureKind::Async, .. } | hir_def::hir::Expr::Async { .. } ) @@ -2145,7 +2140,7 @@ fn opaque_types_and_coroutines_defined_by(self, def_id: Self::LocalDefId) -> Sel crate::opaques::opaque_types_defined_by(self.db, def_id, &mut result); // Collect coroutines. - let body = self.db.body(def_id); + let body = Body::of(self.db, def_id); body.exprs().for_each(|(expr_id, expr)| { if matches!( expr, @@ -2158,7 +2153,7 @@ fn opaque_types_and_coroutines_defined_by(self, def_id: Self::LocalDefId) -> Sel ) { let coroutine = InternedCoroutineId::new( self.db, - InternedCoroutine(ExpressionStoreOwner::Body(def_id), expr_id), + InternedCoroutine(ExpressionStoreOwnerId::Body(def_id), expr_id), ); result.push(coroutine.into()); } @@ -2188,7 +2183,7 @@ fn fn_is_const(self, id: Self::FunctionId) -> bool { CallableDefId::FunctionId(id) => id, _ => return false, }; - self.db().function_signature(id).flags.contains(FnFlags::CONST) + FunctionSignature::of(self.db(), id).flags.contains(FnFlags::CONST) } fn impl_is_const(self, _def_id: Self::ImplId) -> bool { @@ -2236,11 +2231,11 @@ fn is_default_trait(self, def_id: Self::TraitId) -> bool { } fn trait_is_coinductive(self, trait_: Self::TraitId) -> bool { - self.db().trait_signature(trait_.0).flags.contains(TraitFlags::COINDUCTIVE) + TraitSignature::of(self.db(), trait_.0).flags.contains(TraitFlags::COINDUCTIVE) } fn trait_is_unsafe(self, trait_: Self::TraitId) -> bool { - self.db().trait_signature(trait_.0).flags.contains(TraitFlags::UNSAFE) + TraitSignature::of(self.db(), trait_.0).flags.contains(TraitFlags::UNSAFE) } fn impl_self_is_guaranteed_unsized(self, _def_id: Self::ImplId) -> bool { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ir_print.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ir_print.rs index 65931549db02..e0732b347374 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ir_print.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ir_print.rs @@ -1,5 +1,6 @@ //! Things related to IR printing in the next-trait-solver. +use hir_def::signatures::{TraitSignature, TypeAliasSignature}; use rustc_type_ir::{self as ty, ir_print::IrPrint}; use super::SolverDefId; @@ -14,7 +15,7 @@ fn print_debug(t: &ty::AliasTy, fmt: &mut std::fmt::Formatter<'_>) -> std: crate::with_attached_db(|db| match t.def_id { SolverDefId::TypeAliasId(id) => fmt.write_str(&format!( "AliasTy({:?}[{:?}])", - db.type_alias_signature(id).name.as_str(), + TypeAliasSignature::of(db, id).name.as_str(), t.args )), SolverDefId::InternedOpaqueTyId(id) => { @@ -34,7 +35,7 @@ fn print_debug(t: &ty::AliasTerm, fmt: &mut std::fmt::Formatter<'_>) -> st crate::with_attached_db(|db| match t.def_id { SolverDefId::TypeAliasId(id) => fmt.write_str(&format!( "AliasTerm({:?}[{:?}])", - db.type_alias_signature(id).name.as_str(), + TypeAliasSignature::of(db, id).name.as_str(), t.args )), SolverDefId::InternedOpaqueTyId(id) => { @@ -58,13 +59,13 @@ fn print_debug(t: &ty::TraitRef, fmt: &mut std::fmt::Formatter<'_>) -> std fmt.write_str(&format!( "{:?}: {}", self_ty, - db.trait_signature(trait_).name.as_str() + TraitSignature::of(db, trait_).name.as_str() )) } else { fmt.write_str(&format!( "{:?}: {}<{:?}>", self_ty, - db.trait_signature(trait_).name.as_str(), + TraitSignature::of(db, trait_).name.as_str(), trait_args )) } @@ -121,7 +122,7 @@ fn print_debug( let trait_ = t.def_id.0; fmt.write_str(&format!( "ExistentialTraitRef({:?}[{:?}])", - db.trait_signature(trait_).name.as_str(), + TraitSignature::of(db, trait_).name.as_str(), t.args )) }) @@ -146,7 +147,7 @@ fn print_debug( }; fmt.write_str(&format!( "ExistentialProjection(({:?}[{:?}]) -> {:?})", - db.type_alias_signature(id).name.as_str(), + TypeAliasSignature::of(db, id).name.as_str(), t.args, t.term )) @@ -172,7 +173,7 @@ fn print_debug( }; fmt.write_str(&format!( "ProjectionPredicate(({:?}[{:?}]) -> {:?})", - db.type_alias_signature(id).name.as_str(), + TypeAliasSignature::of(db, id).name.as_str(), t.projection_term.args, t.term )) 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 54baa8ac41ac..848bb110af2d 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/solver.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/solver.rs @@ -1,6 +1,9 @@ //! Defining `SolverContext` for next-trait-solver. -use hir_def::{AssocItemId, GeneralConstId}; +use hir_def::{ + AssocItemId, GeneralConstId, + signatures::{ConstSignature, TypeAliasSignature}, +}; use rustc_next_trait_solver::delegate::SolverDelegate; use rustc_type_ir::{ AliasTyKind, GenericArgKind, InferCtxtLike, Interner, PredicatePolarity, TypeFlags, @@ -181,52 +184,53 @@ fn fetch_eligible_assoc_item( return Ok(None); }; let impl_items = impl_id.impl_items(self.0.interner.db()); - let id = - match trait_assoc_def_id { - SolverDefId::TypeAliasId(trait_assoc_id) => { - let trait_assoc_data = self.0.interner.db.type_alias_signature(trait_assoc_id); - impl_items - .items - .iter() - .find_map(|(impl_assoc_name, impl_assoc_id)| { - if let AssocItemId::TypeAliasId(impl_assoc_id) = *impl_assoc_id - && *impl_assoc_name == trait_assoc_data.name - { - Some(impl_assoc_id) - } else { - None - } - }) - .or_else(|| { - if trait_assoc_data.ty.is_some() { Some(trait_assoc_id) } else { None } - }) - .map(SolverDefId::TypeAliasId) - } - SolverDefId::ConstId(trait_assoc_id) => { - let trait_assoc_data = self.0.interner.db.const_signature(trait_assoc_id); - let trait_assoc_name = trait_assoc_data - .name - .as_ref() - .expect("unnamed consts should not get passed to the solver"); - impl_items - .items - .iter() - .find_map(|(impl_assoc_name, impl_assoc_id)| { - if let AssocItemId::ConstId(impl_assoc_id) = *impl_assoc_id - && impl_assoc_name == trait_assoc_name - { - Some(impl_assoc_id) - } else { - None - } - }) - .or_else(|| { + let id = match trait_assoc_def_id { + SolverDefId::TypeAliasId(trait_assoc_id) => { + let trait_assoc_data = TypeAliasSignature::of(self.0.interner.db, trait_assoc_id); + impl_items + .items + .iter() + .find_map(|(impl_assoc_name, impl_assoc_id)| { + if let AssocItemId::TypeAliasId(impl_assoc_id) = *impl_assoc_id + && *impl_assoc_name == trait_assoc_data.name + { + Some(impl_assoc_id) + } else { + None + } + }) + .or_else(|| { + if trait_assoc_data.ty.is_some() { Some(trait_assoc_id) } else { None } + }) + .map(SolverDefId::TypeAliasId) + } + SolverDefId::ConstId(trait_assoc_id) => { + let trait_assoc_data = ConstSignature::of(self.0.interner.db, trait_assoc_id); + let trait_assoc_name = trait_assoc_data + .name + .as_ref() + .expect("unnamed consts should not get passed to the solver"); + impl_items + .items + .iter() + .find_map(|(impl_assoc_name, impl_assoc_id)| { + if let AssocItemId::ConstId(impl_assoc_id) = *impl_assoc_id + && impl_assoc_name == trait_assoc_name + { + Some(impl_assoc_id) + } else { + None + } + }) + .or_else( + || { if trait_assoc_data.has_body() { Some(trait_assoc_id) } else { None } - }) - .map(SolverDefId::ConstId) - } - _ => panic!("Unexpected SolverDefId"), - }; + }, + ) + .map(SolverDefId::ConstId) + } + _ => panic!("Unexpected SolverDefId"), + }; Ok(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 27ae5e39d55b..ce93a334221c 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/opaques.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/opaques.rs @@ -1,7 +1,8 @@ //! Handling of opaque types, detection of defining scope and hidden type. use hir_def::{ - AssocItemId, AssocItemLoc, DefWithBodyId, FunctionId, HasModule, ItemContainerId, TypeAliasId, + AssocItemId, AssocItemLoc, DefWithBodyId, ExpressionStoreOwnerId, FunctionId, GenericDefId, + HasModule, ItemContainerId, TypeAliasId, signatures::ImplSignature, }; use hir_expand::name::Name; use la_arena::ArenaMap; @@ -55,7 +56,7 @@ pub(crate) fn opaque_types_defined_by( }; let extend_with_atpit_from_container = |container| match container { ItemContainerId::ImplId(impl_id) => { - if db.impl_signature(impl_id).target_trait.is_some() { + if ImplSignature::of(db, impl_id).target_trait.is_some() { extend_with_atpit_from_assoc_items(&impl_id.impl_items(db).items); } } @@ -94,7 +95,7 @@ pub(crate) fn rpit_hidden_types<'db>( db: &'db dyn HirDatabase, function: FunctionId, ) -> ArenaMap> { - let infer = InferenceResult::for_body(db, function.into()); + let infer = InferenceResult::of(db, DefWithBodyId::from(function)); let mut result = ArenaMap::new(); for (opaque, hidden_type) in infer.return_position_impl_trait_types(db) { result.insert(opaque, StoredEarlyBinder::bind(hidden_type.store())); @@ -122,13 +123,14 @@ pub(crate) fn tait_hidden_types<'db>( let infcx = interner.infer_ctxt().build(TypingMode::non_body_analysis()); let mut ocx = ObligationCtxt::new(&infcx); let cause = ObligationCause::dummy(); - let param_env = db.trait_environment(type_alias.into()); + let param_env = + db.trait_environment(ExpressionStoreOwnerId::from(GenericDefId::from(type_alias))); let defining_bodies = tait_defining_bodies(db, &loc); let mut result = ArenaMap::with_capacity(taits_count); for defining_body in defining_bodies { - let infer = InferenceResult::for_body(db, defining_body); + let infer = InferenceResult::of(db, defining_body); for (&opaque, hidden_type) in &infer.type_of_opaque { let ImplTraitId::TypeAliasImplTrait(opaque_owner, opaque_idx) = opaque.loc(db) else { continue; @@ -195,7 +197,7 @@ fn tait_defining_bodies( }; match loc.container { ItemContainerId::ImplId(impl_id) => { - if db.impl_signature(impl_id).target_trait.is_some() { + if ImplSignature::of(db, impl_id).target_trait.is_some() { return from_assoc_items(&impl_id.impl_items(db).items); } } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/specialization.rs b/src/tools/rust-analyzer/crates/hir-ty/src/specialization.rs index d97a35549ca4..90cbcfea6abe 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/specialization.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/specialization.rs @@ -1,6 +1,9 @@ //! Impl specialization related things -use hir_def::{HasModule, ImplId, nameres::crate_def_map}; +use hir_def::{ + ExpressionStoreOwnerId, GenericDefId, HasModule, ImplId, nameres::crate_def_map, + signatures::ImplSignature, +}; use intern::sym; use tracing::debug; @@ -45,11 +48,13 @@ fn specializes_query( specializing_impl_def_id: ImplId, parent_impl_def_id: ImplId, ) -> bool { - let trait_env = db.trait_environment(specializing_impl_def_id.into()); + let trait_env = db.trait_environment(ExpressionStoreOwnerId::from(GenericDefId::from( + specializing_impl_def_id, + ))); let interner = DbInterner::new_with(db, specializing_impl_def_id.krate(db)); - let specializing_impl_signature = db.impl_signature(specializing_impl_def_id); - let parent_impl_signature = db.impl_signature(parent_impl_def_id); + let specializing_impl_signature = ImplSignature::of(db, specializing_impl_def_id); + let parent_impl_signature = ImplSignature::of(db, parent_impl_def_id); // We determine whether there's a subset relationship by: // 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 042f0568f3d8..430a570444d8 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs @@ -18,7 +18,6 @@ use hir_def::{ AssocItemId, DefWithBodyId, GenericDefId, HasModule, Lookup, ModuleDefId, ModuleId, SyntheticSyntax, - db::DefDatabase, expr_store::{Body, BodySourceMap, ExpressionStore, ExpressionStoreSourceMap}, hir::{ExprId, Pat, PatId}, item_scope::ItemScope, @@ -146,15 +145,15 @@ fn check_impl( let mut unexpected_type_mismatches = String::new(); for (def, krate) in defs { let display_target = DisplayTarget::from_crate(&db, krate); - let (body, body_source_map) = db.body_with_source_map(def); - let inference_result = InferenceResult::for_body(&db, def); + let (body, body_source_map) = Body::with_source_map(&db, def); + let inference_result = InferenceResult::of(&db, def); for (pat, ty) in inference_result.type_of_pat.iter() { let mut ty = ty.as_ref(); if let Pat::Bind { id, .. } = body[pat] { ty = inference_result.type_of_binding[id].as_ref(); } - let node = match pat_node(&body_source_map, pat, &db) { + let node = match pat_node(body_source_map, pat, &db) { Some(value) => value, None => continue, }; @@ -171,7 +170,7 @@ fn check_impl( for (expr, ty) in inference_result.type_of_expr.iter() { let ty = ty.as_ref(); - let node = match expr_node(&body_source_map, expr, &db) { + let node = match expr_node(body_source_map, expr, &db) { Some(value) => value, None => continue, }; @@ -202,9 +201,9 @@ fn check_impl( for (expr_or_pat, mismatch) in inference_result.type_mismatches() { let Some(node) = (match expr_or_pat { hir_def::hir::ExprOrPatId::ExprId(expr) => { - expr_node(&body_source_map, expr, &db) + expr_node(body_source_map, expr, &db) } - hir_def::hir::ExprOrPatId::PatId(pat) => pat_node(&body_source_map, pat, &db), + hir_def::hir::ExprOrPatId::PatId(pat) => pat_node(body_source_map, pat, &db), }) else { continue; }; @@ -223,7 +222,7 @@ fn check_impl( } for (type_ref, ty) in inference_result.placeholder_types() { - let node = match type_node(&body_source_map, type_ref, &db) { + let node = match type_node(body_source_map, type_ref, &db) { Some(value) => value, None => continue, }; @@ -487,22 +486,22 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String { } }); for (def, krate) in defs { - let (body, source_map) = db.body_with_source_map(def); - let infer = InferenceResult::for_body(&db, def); + let (body, source_map) = Body::with_source_map(&db, def); + let infer = InferenceResult::of(&db, def); let self_param = body.self_param.map(|id| (id, source_map.self_param_syntax())); - infer_def(infer, &body, &source_map, self_param, krate); + infer_def(infer, body, source_map, self_param, krate); } // Also infer signature const expressions (array lengths, const generic args, etc.) generic_defs.dedup(); for (def, krate) in generic_defs { - let (_, store, source_map) = db.generic_params_and_store_and_source_map(def); + let (store, source_map) = ExpressionStore::with_source_map(&db, def.into()); // Skip if there are no const expressions in the signature if store.const_expr_origins().is_empty() { continue; } - let infer = InferenceResult::for_signature(&db, def); - infer_def(infer, &store, &source_map, None, krate); + let infer = InferenceResult::of(&db, def); + infer_def(infer, store, source_map, None, krate); } buf.truncate(buf.trim_end().len()); @@ -522,14 +521,14 @@ pub(crate) fn visit_module( for &(_, item) in impl_data.items.iter() { match item { AssocItemId::FunctionId(it) => { - let body = db.body(it.into()); + let body = Body::of(db, it.into()); cb(it.into()); - visit_body(db, &body, cb); + visit_body(db, body, cb); } AssocItemId::ConstId(it) => { - let body = db.body(it.into()); + let body = Body::of(db, it.into()); cb(it.into()); - visit_body(db, &body, cb); + visit_body(db, body, cb); } AssocItemId::TypeAliasId(it) => { cb(it.into()); @@ -548,22 +547,22 @@ fn visit_scope( cb(decl); match decl { ModuleDefId::FunctionId(it) => { - let body = db.body(it.into()); - visit_body(db, &body, cb); + let body = Body::of(db, it.into()); + visit_body(db, body, cb); } ModuleDefId::ConstId(it) => { - let body = db.body(it.into()); - visit_body(db, &body, cb); + let body = Body::of(db, it.into()); + visit_body(db, body, cb); } ModuleDefId::StaticId(it) => { - let body = db.body(it.into()); - visit_body(db, &body, cb); + let body = Body::of(db, it.into()); + visit_body(db, body, cb); } ModuleDefId::AdtId(hir_def::AdtId::EnumId(it)) => { it.enum_variants(db).variants.iter().for_each(|&(it, _, _)| { - let body = db.body(it.into()); + let body = Body::of(db, it.into()); cb(it.into()); - visit_body(db, &body, cb); + visit_body(db, body, cb); }); } ModuleDefId::TraitId(it) => { @@ -653,16 +652,14 @@ fn main() { let module = db.module_for_file(pos.file_id.file_id(&db)); let crate_def_map = module.def_map(&db); visit_module(&db, crate_def_map, module, &mut |def| { - InferenceResult::for_body( - &db, - match def { - ModuleDefId::FunctionId(it) => it.into(), - ModuleDefId::EnumVariantId(it) => it.into(), - ModuleDefId::ConstId(it) => it.into(), - ModuleDefId::StaticId(it) => it.into(), - _ => return, - }, - ); + let body_def: DefWithBodyId = match def { + ModuleDefId::FunctionId(it) => it.into(), + ModuleDefId::EnumVariantId(it) => it.into(), + ModuleDefId::ConstId(it) => it.into(), + ModuleDefId::StaticId(it) => it.into(), + _ => return, + }; + InferenceResult::of(&db, body_def); }); }); @@ -697,16 +694,14 @@ fn main() { let module = db.module_for_file(pos.file_id.file_id(&db)); let crate_def_map = module.def_map(&db); visit_module(&db, crate_def_map, module, &mut |def| { - InferenceResult::for_body( - &db, - match def { - ModuleDefId::FunctionId(it) => it.into(), - ModuleDefId::EnumVariantId(it) => it.into(), - ModuleDefId::ConstId(it) => it.into(), - ModuleDefId::StaticId(it) => it.into(), - _ => return, - }, - ); + let body_def: DefWithBodyId = match def { + ModuleDefId::FunctionId(it) => it.into(), + ModuleDefId::EnumVariantId(it) => it.into(), + ModuleDefId::ConstId(it) => it.into(), + ModuleDefId::StaticId(it) => it.into(), + _ => return, + }; + InferenceResult::of(&db, body_def); }); }) } 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 6e55641e56f2..9e687568216d 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 @@ -1,5 +1,8 @@ use expect_test::{Expect, expect}; -use hir_def::db::DefDatabase; +use hir_def::{ + DefWithBodyId, + expr_store::{Body, ExpressionStore}, +}; use hir_expand::{HirFileId, files::InFileWrapper}; use itertools::Itertools; use span::TextRange; @@ -28,20 +31,20 @@ fn check_closure_captures(#[rust_analyzer::rust_fixture] ra_fixture: &str, expec let mut captures_info = Vec::new(); for def in defs { - let def = match def { + let def: DefWithBodyId = match def { hir_def::ModuleDefId::FunctionId(it) => it.into(), hir_def::ModuleDefId::EnumVariantId(it) => it.into(), hir_def::ModuleDefId::ConstId(it) => it.into(), hir_def::ModuleDefId::StaticId(it) => it.into(), _ => continue, }; - let infer = InferenceResult::for_body(&db, def); + let infer = InferenceResult::of(&db, def); let db = &db; captures_info.extend(infer.closure_info.iter().flat_map( |(closure_id, (captures, _))| { let closure = db.lookup_intern_closure(*closure_id); - let body_owner = closure.0.as_def_with_body().unwrap(); - let source_map = db.body_with_source_map(body_owner).1; + let body_owner = closure.0; + let source_map = ExpressionStore::with_source_map(db, body_owner).1; let closure_text_range = source_map .expr_syntax(closure.1) .expect("failed to map closure to SyntaxNode") @@ -57,7 +60,8 @@ fn text_range( } // FIXME: Deduplicate this with hir::Local::sources(). - let (body, source_map) = db.body_with_source_map(body_owner); + let (body, source_map) = + Body::with_source_map(db, body_owner.as_def_with_body().unwrap()); let local_text_range = match body.self_param.zip(source_map.self_param_syntax()) { Some((param, source)) if param == capture.local() => { 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 0fbf8acf530f..3e8089c9c13e 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 @@ -24,7 +24,7 @@ fn foo() -> i32 { let crate_def_map = module.def_map(&db); visit_module(&db, crate_def_map, module, &mut |def| { if let ModuleDefId::FunctionId(it) = def { - InferenceResult::for_body(&db, it.into()); + InferenceResult::of(&db, DefWithBodyId::from(it)); } }); }, @@ -38,17 +38,17 @@ fn foo() -> i32 { "parse_shim", "real_span_map_shim", "InferenceResult::for_body_", - "function_signature_shim", - "function_signature_with_source_map_shim", + "FunctionSignature::of_", + "FunctionSignature::with_source_map_", "AttrFlags::query_", - "body_shim", - "body_with_source_map_shim", + "Body::of_", + "Body::with_source_map_", "trait_environment_query", "lang_items", "crate_lang_items", "GenericPredicates::query_with_diagnostics_", "ImplTraits::return_type_impl_traits_", - "body_expr_scopes_shim", + "ExprScopes::body_expr_scopes_", ] "#]], ); @@ -69,7 +69,7 @@ fn foo() -> i32 { let crate_def_map = module.def_map(&db); visit_module(&db, crate_def_map, module, &mut |def| { if let ModuleDefId::FunctionId(it) = def { - InferenceResult::for_body(&db, it.into()); + InferenceResult::of(&db, DefWithBodyId::from(it)); } }); }, @@ -81,10 +81,10 @@ fn foo() -> i32 { "file_item_tree_query", "real_span_map_shim", "AttrFlags::query_", - "function_signature_with_source_map_shim", - "function_signature_shim", - "body_with_source_map_shim", - "body_shim", + "FunctionSignature::with_source_map_", + "FunctionSignature::of_", + "Body::with_source_map_", + "Body::of_", ] "#]], ); @@ -112,7 +112,7 @@ fn baz() -> i32 { let crate_def_map = module.def_map(&db); visit_module(&db, crate_def_map, module, &mut |def| { if let ModuleDefId::FunctionId(it) = def { - InferenceResult::for_body(&db, it.into()); + InferenceResult::of(&db, DefWithBodyId::from(it)); } }); }, @@ -126,37 +126,37 @@ fn baz() -> i32 { "parse_shim", "real_span_map_shim", "InferenceResult::for_body_", - "function_signature_shim", - "function_signature_with_source_map_shim", + "FunctionSignature::of_", + "FunctionSignature::with_source_map_", "AttrFlags::query_", - "body_shim", - "body_with_source_map_shim", + "Body::of_", + "Body::with_source_map_", "trait_environment_query", "lang_items", "crate_lang_items", "GenericPredicates::query_with_diagnostics_", "ImplTraits::return_type_impl_traits_", - "body_expr_scopes_shim", + "ExprScopes::body_expr_scopes_", "InferenceResult::for_body_", - "function_signature_shim", - "function_signature_with_source_map_shim", + "FunctionSignature::of_", + "FunctionSignature::with_source_map_", "AttrFlags::query_", - "body_shim", - "body_with_source_map_shim", + "Body::of_", + "Body::with_source_map_", "trait_environment_query", "GenericPredicates::query_with_diagnostics_", "ImplTraits::return_type_impl_traits_", - "body_expr_scopes_shim", + "ExprScopes::body_expr_scopes_", "InferenceResult::for_body_", - "function_signature_shim", - "function_signature_with_source_map_shim", + "FunctionSignature::of_", + "FunctionSignature::with_source_map_", "AttrFlags::query_", - "body_shim", - "body_with_source_map_shim", + "Body::of_", + "Body::with_source_map_", "trait_environment_query", "GenericPredicates::query_with_diagnostics_", "ImplTraits::return_type_impl_traits_", - "body_expr_scopes_shim", + "ExprScopes::body_expr_scopes_", ] "#]], ); @@ -182,7 +182,7 @@ fn baz() -> i32 { let crate_def_map = module.def_map(&db); visit_module(&db, crate_def_map, module, &mut |def| { if let ModuleDefId::FunctionId(it) = def { - InferenceResult::for_body(&db, it.into()); + InferenceResult::of(&db, DefWithBodyId::from(it)); } }); }, @@ -194,22 +194,22 @@ fn baz() -> i32 { "file_item_tree_query", "real_span_map_shim", "AttrFlags::query_", - "function_signature_with_source_map_shim", - "function_signature_shim", - "body_with_source_map_shim", - "body_shim", + "FunctionSignature::with_source_map_", + "FunctionSignature::of_", + "Body::with_source_map_", + "Body::of_", "AttrFlags::query_", - "function_signature_with_source_map_shim", - "function_signature_shim", - "body_with_source_map_shim", - "body_shim", + "FunctionSignature::with_source_map_", + "FunctionSignature::of_", + "Body::with_source_map_", + "Body::of_", "InferenceResult::for_body_", - "body_expr_scopes_shim", + "ExprScopes::body_expr_scopes_", "AttrFlags::query_", - "function_signature_with_source_map_shim", - "function_signature_shim", - "body_with_source_map_shim", - "body_shim", + "FunctionSignature::with_source_map_", + "FunctionSignature::of_", + "Body::with_source_map_", + "Body::of_", ] "#]], ); @@ -562,7 +562,7 @@ fn main() { }); for def in defs { - let _inference_result = InferenceResult::for_body(&db, def); + let _inference_result = InferenceResult::of(&db, def); } }, &[("trait_solve_shim", 0)], @@ -575,19 +575,19 @@ fn main() { "parse_shim", "real_span_map_shim", "TraitItems::query_with_diagnostics_", - "body_shim", - "body_with_source_map_shim", + "Body::of_", + "Body::with_source_map_", "AttrFlags::query_", "ImplItems::of_", "InferenceResult::for_body_", - "trait_signature_shim", - "trait_signature_with_source_map_shim", + "TraitSignature::of_", + "TraitSignature::with_source_map_", "AttrFlags::query_", - "function_signature_shim", - "function_signature_with_source_map_shim", + "FunctionSignature::of_", + "FunctionSignature::with_source_map_", "AttrFlags::query_", - "body_shim", - "body_with_source_map_shim", + "Body::of_", + "Body::with_source_map_", "trait_environment_query", "lang_items", "crate_lang_items", @@ -595,14 +595,14 @@ fn main() { "GenericPredicates::query_with_diagnostics_", "ImplTraits::return_type_impl_traits_", "InferenceResult::for_body_", - "function_signature_shim", - "function_signature_with_source_map_shim", + "FunctionSignature::of_", + "FunctionSignature::with_source_map_", "trait_environment_query", "GenericPredicates::query_with_diagnostics_", "ImplTraits::return_type_impl_traits_", - "body_expr_scopes_shim", - "struct_signature_shim", - "struct_signature_with_source_map_shim", + "ExprScopes::body_expr_scopes_", + "StructSignature::of_", + "StructSignature::with_source_map_", "AttrFlags::query_", "GenericPredicates::query_with_diagnostics_", "value_ty_query", @@ -611,8 +611,8 @@ fn main() { "TraitImpls::for_crate_and_deps_", "TraitImpls::for_crate_", "impl_trait_with_diagnostics_query", - "impl_signature_shim", - "impl_signature_with_source_map_shim", + "ImplSignature::of_", + "ImplSignature::with_source_map_", "impl_self_ty_with_diagnostics_query", "AttrFlags::query_", "GenericPredicates::query_with_diagnostics_", @@ -658,7 +658,7 @@ fn main() { }); for def in defs { - let _inference_result = InferenceResult::for_body(&db, def); + let _inference_result = InferenceResult::of(&db, def); } }, &[("trait_solve_shim", 0)], @@ -670,35 +670,35 @@ fn main() { "real_span_map_shim", "crate_local_def_map", "TraitItems::query_with_diagnostics_", - "body_with_source_map_shim", + "Body::with_source_map_", "AttrFlags::query_", - "body_shim", + "Body::of_", "ImplItems::of_", "InferenceResult::for_body_", "AttrFlags::query_", - "trait_signature_with_source_map_shim", + "TraitSignature::with_source_map_", "AttrFlags::query_", - "function_signature_with_source_map_shim", - "function_signature_shim", - "body_with_source_map_shim", - "body_shim", + "FunctionSignature::with_source_map_", + "FunctionSignature::of_", + "Body::with_source_map_", + "Body::of_", "crate_lang_items", "GenericPredicates::query_with_diagnostics_", "GenericPredicates::query_with_diagnostics_", "ImplTraits::return_type_impl_traits_", "InferenceResult::for_body_", - "function_signature_with_source_map_shim", + "FunctionSignature::with_source_map_", "GenericPredicates::query_with_diagnostics_", "ImplTraits::return_type_impl_traits_", - "body_expr_scopes_shim", - "struct_signature_with_source_map_shim", + "ExprScopes::body_expr_scopes_", + "StructSignature::with_source_map_", "AttrFlags::query_", "GenericPredicates::query_with_diagnostics_", "InherentImpls::for_crate_", "callable_item_signature_query", "TraitImpls::for_crate_", - "impl_signature_with_source_map_shim", - "impl_signature_shim", + "ImplSignature::with_source_map_", + "ImplSignature::of_", "impl_trait_with_diagnostics_query", "impl_self_ty_with_diagnostics_query", "AttrFlags::query_", 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 fb598fe5acb0..878696c72129 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs @@ -7,7 +7,11 @@ AdtId, AssocItemId, HasModule, ImplId, Lookup, TraitId, lang_item::LangItems, nameres::DefMap, - signatures::{ConstFlags, EnumFlags, FnFlags, StructFlags, TraitFlags, TypeAliasFlags}, + signatures::{ + ConstFlags, ConstSignature, EnumFlags, EnumSignature, FnFlags, FunctionSignature, + StructFlags, StructSignature, TraitFlags, TraitSignature, TypeAliasFlags, + TypeAliasSignature, UnionSignature, + }, }; use hir_expand::name::Name; use intern::sym; @@ -279,21 +283,18 @@ pub fn is_inherent_impl_coherent(db: &dyn HirDatabase, def_map: &DefMap, impl_id | TyKind::Float(_) => true, TyKind::Adt(adt_def, _) => match adt_def.def_id().0 { - hir_def::AdtId::StructId(id) => db - .struct_signature(id) + hir_def::AdtId::StructId(id) => StructSignature::of(db, id) .flags .contains(StructFlags::RUSTC_HAS_INCOHERENT_INHERENT_IMPLS), - hir_def::AdtId::UnionId(id) => db - .union_signature(id) + hir_def::AdtId::UnionId(id) => UnionSignature::of(db, id) .flags .contains(StructFlags::RUSTC_HAS_INCOHERENT_INHERENT_IMPLS), - hir_def::AdtId::EnumId(it) => db - .enum_signature(it) + hir_def::AdtId::EnumId(it) => EnumSignature::of(db, it) .flags .contains(EnumFlags::RUSTC_HAS_INCOHERENT_INHERENT_IMPLS), }, TyKind::Dynamic(it, _) => it.principal_def_id().is_some_and(|trait_id| { - db.trait_signature(trait_id.0) + TraitSignature::of(db, trait_id.0) .flags .contains(TraitFlags::RUSTC_HAS_INCOHERENT_INHERENT_IMPLS) }), @@ -304,14 +305,13 @@ pub fn is_inherent_impl_coherent(db: &dyn HirDatabase, def_map: &DefMap, impl_id rustc_has_incoherent_inherent_impls && !items.items.is_empty() && items.items.iter().all(|&(_, assoc)| match assoc { - AssocItemId::FunctionId(it) => { - db.function_signature(it).flags.contains(FnFlags::RUSTC_ALLOW_INCOHERENT_IMPL) - } - AssocItemId::ConstId(it) => { - db.const_signature(it).flags.contains(ConstFlags::RUSTC_ALLOW_INCOHERENT_IMPL) - } - AssocItemId::TypeAliasId(it) => db - .type_alias_signature(it) + AssocItemId::FunctionId(it) => FunctionSignature::of(db, it) + .flags + .contains(FnFlags::RUSTC_ALLOW_INCOHERENT_IMPL), + AssocItemId::ConstId(it) => ConstSignature::of(db, it) + .flags + .contains(ConstFlags::RUSTC_ALLOW_INCOHERENT_IMPL), + AssocItemId::TypeAliasId(it) => TypeAliasSignature::of(db, it) .flags .contains(TypeAliasFlags::RUSTC_ALLOW_INCOHERENT_IMPL), }) @@ -350,7 +350,7 @@ pub fn check_orphan_rules<'db>(db: &'db dyn HirDatabase, impl_: ImplId) -> bool let AdtId::StructId(s) = adt_def.def_id().0 else { break ty; }; - let struct_signature = db.struct_signature(s); + let struct_signature = StructSignature::of(db, s); if struct_signature.flags.contains(StructFlags::FUNDAMENTAL) { let next = subs.types().next(); match next { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/upvars.rs b/src/tools/rust-analyzer/crates/hir-ty/src/upvars.rs index ee864ab068d2..d19fbbc18793 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/upvars.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/upvars.rs @@ -44,10 +44,10 @@ pub fn upvars_mentioned( db: &dyn HirDatabase, owner: DefWithBodyId, ) -> Option>> { - let body = db.body(owner); + let body = Body::of(db, owner); let mut resolver = owner.resolver(db); let mut result = FxHashMap::default(); - handle_expr_outside_closure(db, &mut resolver, owner, &body, body.body_expr, &mut result); + handle_expr_outside_closure(db, &mut resolver, owner, body, body.body_expr, &mut result); return if result.is_empty() { None } else { @@ -198,7 +198,7 @@ fn resolve_maybe_upvar<'db>( #[cfg(test)] mod tests { use expect_test::{Expect, expect}; - use hir_def::{ModuleDefId, db::DefDatabase, nameres::crate_def_map}; + use hir_def::{ModuleDefId, expr_store::Body, nameres::crate_def_map}; use itertools::Itertools; use span::Edition; use test_fixture::WithFixture; @@ -219,7 +219,7 @@ fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str, expectation: Expect) { }) .exactly_one() .unwrap_or_else(|_| panic!("expected one function")); - let (body, source_map) = db.body_with_source_map(func.into()); + let (body, source_map) = Body::with_source_map(&db, func.into()); let Some(upvars) = upvars_mentioned(&db, func.into()) else { expectation.assert_eq(""); return; 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 be64f55ea550..509109543cd6 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs @@ -4,6 +4,7 @@ use base_db::target::{self, TargetData}; use hir_def::{ EnumId, EnumVariantId, FunctionId, Lookup, TraitId, attrs::AttrFlags, lang_item::LangItems, + signatures::FunctionSignature, }; use intern::sym; use rustc_abi::TargetDataLayout; @@ -79,7 +80,7 @@ pub fn is_fn_unsafe_to_call( call_edition: Edition, target_feature_is_safe: TargetFeatureIsSafeInTarget, ) -> Unsafety { - let data = db.function_signature(func); + let data = FunctionSignature::of(db, func); if data.is_unsafe() { return Unsafety::Unsafe; } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/variance.rs b/src/tools/rust-analyzer/crates/hir-ty/src/variance.rs index 6f415a5289c9..1945b04bb3cc 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/variance.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/variance.rs @@ -13,7 +13,10 @@ //! by the next salsa version. If not, we will likely have to adapt and go with the rustc approach //! while installing firewall per item queries to prevent invalidation issues. -use hir_def::{AdtId, GenericDefId, GenericParamId, VariantId, signatures::StructFlags}; +use hir_def::{ + AdtId, GenericDefId, GenericParamId, VariantId, + signatures::{StructFlags, StructSignature}, +}; use rustc_ast_ir::Mutability; use rustc_type_ir::{ Variance, @@ -45,7 +48,7 @@ fn variances_of_query(db: &dyn HirDatabase, def: GenericDefId) -> StoredVariance GenericDefId::FunctionId(_) => (), GenericDefId::AdtId(adt) => { if let AdtId::StructId(id) = adt { - let flags = &db.struct_signature(id).flags; + let flags = &StructSignature::of(db, id).flags; let types = || crate::next_solver::default_types(db); if flags.contains(StructFlags::IS_UNSAFE_CELL) { return types().one_invariant.store(); @@ -113,7 +116,7 @@ pub(crate) fn variances_of_cycle_initial( struct Context<'db> { db: &'db dyn HirDatabase, - generics: Generics, + generics: Generics<'db>, variances: Box<[Variance]>, } diff --git a/src/tools/rust-analyzer/crates/hir/src/display.rs b/src/tools/rust-analyzer/crates/hir/src/display.rs index 91fdcb8e6369..826b8d5f808c 100644 --- a/src/tools/rust-analyzer/crates/hir/src/display.rs +++ b/src/tools/rust-analyzer/crates/hir/src/display.rs @@ -4,10 +4,13 @@ use hir_def::{ AdtId, BuiltinDeriveImplId, FunctionId, GenericDefId, ImplId, ItemContainerId, builtin_derive::BuiltinDeriveImplMethod, - expr_store::ExpressionStore, + expr_store::{Body, ExpressionStore}, hir::generics::{GenericParams, TypeOrConstParamData, TypeParamProvenance, WherePredicate}, item_tree::FieldsShape, - signatures::{StaticFlags, TraitFlags}, + signatures::{ + ConstSignature, FunctionSignature, ImplSignature, StaticFlags, StaticSignature, TraitFlags, + TraitSignature, TypeAliasSignature, + }, type_ref::{TypeBound, TypeRef, TypeRefId}, }; use hir_expand::name::Name; @@ -38,7 +41,7 @@ fn write_builtin_derive_impl_method<'db>( ) -> Result { let db = f.db; let loc = impl_.loc(db); - let (adt_params, _adt_params_store) = db.generic_params_and_store(loc.adt.into()); + let (adt_params, _adt_params_store) = GenericParams::of(db, loc.adt.into()); if f.show_container_bounds() && !adt_params.is_empty() { f.write_str("impl")?; @@ -94,22 +97,22 @@ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result { // Write container (trait or impl) let container_params = match container { ItemContainerId::TraitId(trait_) => { - let (params, params_store) = f.db.generic_params_and_store(trait_.into()); + let (params, params_store) = GenericParams::of(f.db, trait_.into()); if f.show_container_bounds() && !params.is_empty() { write_trait_header(trait_.into(), f)?; f.write_char('\n')?; - has_disaplayable_predicates(f.db, ¶ms, ¶ms_store) + has_disaplayable_predicates(f.db, ¶ms, params_store) .then_some((params, params_store)) } else { None } } ItemContainerId::ImplId(impl_) => { - let (params, params_store) = f.db.generic_params_and_store(impl_.into()); + let (params, params_store) = GenericParams::of(f.db, impl_.into()); if f.show_container_bounds() && !params.is_empty() { write_impl_header(impl_, f)?; f.write_char('\n')?; - has_disaplayable_predicates(f.db, ¶ms, ¶ms_store) + has_disaplayable_predicates(f.db, ¶ms, params_store) .then_some((params, params_store)) } else { None @@ -131,7 +134,7 @@ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result { _ => unreachable!(), }; write!(f, "\n // Bounds from {container_name}:",)?; - write_where_predicates(&container_params, &container_params_store, f)?; + write_where_predicates(&container_params, container_params_store, f)?; } Ok(()) } @@ -140,7 +143,7 @@ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result { fn write_function<'db>(f: &mut HirFormatter<'_, 'db>, func_id: FunctionId) -> Result { let db = f.db; let func = Function::from(func_id); - let data = db.function_signature(func_id); + let data = FunctionSignature::of(db, func_id); let mut module = func.module(db); // Block-local impls are "hoisted" to the nearest (non-block) module. @@ -189,7 +192,7 @@ fn write_function<'db>(f: &mut HirFormatter<'_, 'db>, func_id: FunctionId) -> Re let comma = if too_long_param { ",\n " } else { ", " }; // FIXME: Use resolved `param.ty` once we no longer discard lifetimes - let body = db.body(func_id.into()); + let body = Body::of(db, func_id.into()); for (type_ref, param) in data.params.iter().zip(func.assoc_fn_params(db)).skip(skip_self) { if !first { f.write_str(comma)?; @@ -268,7 +271,7 @@ fn write_impl_header<'db>(impl_: ImplId, f: &mut HirFormatter<'_, 'db>) -> Resul let def_id = GenericDefId::ImplId(impl_); write_generic_params(def_id, f)?; - let impl_data = db.impl_signature(impl_); + let impl_data = ImplSignature::of(db, impl_); if let Some(target_trait) = &impl_data.target_trait { f.write_char(' ')?; hir_display_with_store(&impl_data.store[target_trait.path], &impl_data.store).hir_fmt(f)?; @@ -297,7 +300,7 @@ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result { } }, }; - let data = f.db.function_signature(func); + let data = FunctionSignature::of(f.db, func); let param = *data.params.first().unwrap(); match &data.store[param] { TypeRef::Path(p) if p.is_self_type() => f.write_str("self"), @@ -657,7 +660,7 @@ fn write_generic_params_or_args<'db>( f: &mut HirFormatter<'_, 'db>, include_defaults: bool, ) -> Result { - let (params, store) = f.db.generic_params_and_store(def); + let (params, store) = GenericParams::of(f.db, def); if params.iter_lt().next().is_none() && params.iter_type_or_consts().all(|it| it.1.const_param().is_none()) && params @@ -693,17 +696,17 @@ fn write_generic_params_or_args<'db>( write!(f, "{}", name.display(f.db, f.edition()))?; if include_defaults && let Some(default) = &ty.default { f.write_str(" = ")?; - default.hir_fmt(f, &store)?; + default.hir_fmt(f, store)?; } } TypeOrConstParamData::ConstParamData(c) => { delim(f)?; write!(f, "const {}: ", name.display(f.db, f.edition()))?; - c.ty.hir_fmt(f, &store)?; + c.ty.hir_fmt(f, store)?; if include_defaults && let Some(default) = &c.default { f.write_str(" = ")?; - default.hir_fmt(f, &store)?; + default.hir_fmt(f, store)?; } } } @@ -715,13 +718,13 @@ fn write_generic_params_or_args<'db>( } fn write_where_clause<'db>(def: GenericDefId, f: &mut HirFormatter<'_, 'db>) -> Result { - let (params, store) = f.db.generic_params_and_store(def); - if !has_disaplayable_predicates(f.db, ¶ms, &store) { + let (params, store) = GenericParams::of(f.db, def); + if !has_disaplayable_predicates(f.db, ¶ms, store) { return Ok(false); } f.write_str("\nwhere")?; - write_where_predicates(¶ms, &store, f)?; + write_where_predicates(¶ms, store, f)?; Ok(true) } @@ -816,7 +819,7 @@ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result { module = module.nearest_non_block_module(db); } write_visibility(module.id, self.visibility(db), f)?; - let data = db.const_signature(self.id); + let data = ConstSignature::of(db, self.id); f.write_str("const ")?; match &data.name { Some(name) => write!(f, "{}: ", name.display(f.db, f.edition()))?, @@ -830,7 +833,7 @@ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result { impl<'db> HirDisplay<'db> for Static { fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result { write_visibility(self.module(f.db).id, self.visibility(f.db), f)?; - let data = f.db.static_signature(self.id); + let data = StaticSignature::of(f.db, self.id); f.write_str("static ")?; if data.flags.contains(StaticFlags::MUTABLE) { f.write_str("mut ")?; @@ -889,7 +892,7 @@ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result { fn write_trait_header<'db>(trait_: Trait, f: &mut HirFormatter<'_, 'db>) -> Result { write_visibility(trait_.module(f.db).id, trait_.visibility(f.db), f)?; - let data = f.db.trait_signature(trait_.id); + let data = TraitSignature::of(f.db, trait_.id); if data.flags.contains(TraitFlags::UNSAFE) { f.write_str("unsafe ")?; } @@ -904,7 +907,7 @@ fn write_trait_header<'db>(trait_: Trait, f: &mut HirFormatter<'_, 'db>) -> Resu impl<'db> HirDisplay<'db> for TypeAlias { fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result { write_visibility(self.module(f.db).id, self.visibility(f.db), f)?; - let data = f.db.type_alias_signature(self.id); + let data = TypeAliasSignature::of(f.db, self.id); write!(f, "type {}", data.name.display(f.db, f.edition()))?; let def_id = GenericDefId::TypeAliasId(self.id); write_generic_params(def_id, 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 fc20f4b46bb9..1aeed874af45 100644 --- a/src/tools/rust-analyzer/crates/hir/src/from_id.rs +++ b/src/tools/rust-analyzer/crates/hir/src/from_id.rs @@ -4,8 +4,8 @@ //! are splitting the hir. use hir_def::{ - AdtId, AssocItemId, BuiltinDeriveImplId, DefWithBodyId, EnumVariantId, FieldId, GenericDefId, - GenericParamId, ModuleDefId, VariantId, + AdtId, AssocItemId, BuiltinDeriveImplId, DefWithBodyId, EnumVariantId, ExpressionStoreOwnerId, + FieldId, GenericDefId, GenericParamId, ModuleDefId, VariantId, hir::{BindingId, LabelId}, }; use hir_ty::next_solver::AnyImplId; @@ -255,14 +255,19 @@ fn try_from(item: AssocItem) -> Result { } } -impl From<(DefWithBodyId, BindingId)> for Local { - fn from((parent, binding_id): (DefWithBodyId, BindingId)) -> Self { +impl From<(ExpressionStoreOwnerId, BindingId)> for Local { + fn from((parent, binding_id): (ExpressionStoreOwnerId, BindingId)) -> Self { Local { parent, binding_id } } } +impl From<(DefWithBodyId, BindingId)> for Local { + fn from((parent, binding_id): (DefWithBodyId, BindingId)) -> Self { + Local { parent: parent.into(), binding_id } + } +} -impl From<(DefWithBodyId, LabelId)> for Label { - fn from((parent, label_id): (DefWithBodyId, LabelId)) -> Self { +impl From<(ExpressionStoreOwnerId, LabelId)> for Label { + fn from((parent, label_id): (ExpressionStoreOwnerId, LabelId)) -> Self { Label { parent, label_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 6a1aeb64f35b..752c4f3173e6 100644 --- a/src/tools/rust-analyzer/crates/hir/src/has_source.rs +++ b/src/tools/rust-analyzer/crates/hir/src/has_source.rs @@ -3,6 +3,7 @@ use either::Either; use hir_def::{ CallableDefId, Lookup, MacroId, VariantId, + expr_store::ExpressionStore, nameres::{ModuleOrigin, ModuleSource}, src::{HasChildSource, HasSource as _}, }; @@ -293,8 +294,7 @@ fn source(self, db: &dyn HirDatabase) -> Option> { } Callee::Closure(closure, _) => { let InternedClosure(owner, expr_id) = db.lookup_intern_closure(closure); - let body_owner = owner.as_def_with_body()?; - let (_, source_map) = db.body_with_source_map(body_owner); + let (_, source_map) = ExpressionStore::with_source_map(db, owner); let ast @ InFile { file_id, value } = source_map.expr_syntax(expr_id).ok()?; let root = db.parse_or_expand(file_id); match value.to_node(&root) { @@ -328,8 +328,7 @@ impl HasSource for Label { type Ast = ast::Label; fn source(self, db: &dyn HirDatabase) -> Option> { - let (_body, source_map) = db.body_with_source_map(self.parent); - let src = source_map.label_syntax(self.label_id); + let src = ExpressionStore::with_source_map(db, self.parent).1.label_syntax(self.label_id); let root = src.file_syntax(db); src.map(|ast| ast.to_node(&root).left()).transpose() } @@ -346,7 +345,7 @@ fn source(self, db: &dyn HirDatabase) -> Option> { impl HasSource for InlineAsmOperand { type Ast = ast::AsmOperandNamed; fn source(self, db: &dyn HirDatabase) -> Option> { - let source_map = db.body_with_source_map(self.owner).1; + let (_, source_map) = ExpressionStore::with_source_map(db, self.owner); if let Ok(src) = source_map.expr_syntax(self.expr) { let root = src.file_syntax(db); return src diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index 34372a4a95a2..4d4482b1afa3 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -49,13 +49,13 @@ use either::Either; use hir_def::{ AdtId, AssocItemId, AssocItemLoc, BuiltinDeriveImplId, CallableDefId, ConstId, ConstParamId, - DefWithBodyId, EnumId, EnumVariantId, ExternBlockId, ExternCrateId, FunctionId, GenericDefId, - HasModule, ImplId, ItemContainerId, LifetimeParamId, LocalFieldId, Lookup, MacroExpander, - MacroId, StaticId, StructId, SyntheticSyntax, TupleId, TypeAliasId, TypeOrConstParamId, - TypeParamId, UnionId, + DefWithBodyId, EnumId, EnumVariantId, ExpressionStoreOwnerId, ExternBlockId, ExternCrateId, + FunctionId, GenericDefId, HasModule, ImplId, ItemContainerId, LifetimeParamId, LocalFieldId, + Lookup, MacroExpander, MacroId, StaticId, StructId, SyntheticSyntax, TupleId, TypeAliasId, + TypeOrConstParamId, TypeParamId, UnionId, attrs::AttrFlags, builtin_derive::BuiltinDeriveImplMethod, - expr_store::{ExpressionStoreDiagnostics, ExpressionStoreSourceMap}, + expr_store::{ExpressionStore, ExpressionStoreDiagnostics, ExpressionStoreSourceMap}, hir::{ BindingAnnotation, BindingId, Expr, ExprId, ExprOrPatId, LabelId, Pat, generics::{LifetimeParamData, TypeOrConstParamData, TypeParamProvenance}, @@ -69,7 +69,11 @@ }, per_ns::PerNs, resolver::{HasResolver, Resolver}, - signatures::{EnumSignature, ImplFlags, StaticFlags, StructFlags, TraitFlags, VariantFields}, + signatures::{ + ConstSignature, EnumSignature, FunctionSignature, ImplFlags, ImplSignature, StaticFlags, + StaticSignature, StructFlags, StructSignature, TraitFlags, TraitSignature, + TypeAliasSignature, UnionSignature, VariantFields, + }, src::HasSource as _, visibility::visibility_from_ast, }; @@ -141,6 +145,7 @@ Complete, FindPathConfig, attrs::{Docs, IsInnerDoc}, + expr_store::Body, find_path::PrefixKind, import_map, lang_item::{LangItemEnum as LangItem, crate_lang_items}, @@ -729,8 +734,8 @@ pub fn diagnostics<'db>( ModuleDef::Adt(adt) => { match adt { Adt::Struct(s) => { - let source_map = db.struct_signature_with_source_map(s.id).1; - expr_store_diagnostics(db, acc, &source_map); + let source_map = &StructSignature::with_source_map(db, s.id).1; + expr_store_diagnostics(db, acc, source_map); let source_map = &s.id.fields_with_source_map(db).1; expr_store_diagnostics(db, acc, source_map); push_ty_diagnostics( @@ -741,8 +746,8 @@ pub fn diagnostics<'db>( ); } Adt::Union(u) => { - let source_map = db.union_signature_with_source_map(u.id).1; - expr_store_diagnostics(db, acc, &source_map); + let source_map = &UnionSignature::with_source_map(db, u.id).1; + expr_store_diagnostics(db, acc, source_map); let source_map = &u.id.fields_with_source_map(db).1; expr_store_diagnostics(db, acc, source_map); push_ty_diagnostics( @@ -753,8 +758,8 @@ pub fn diagnostics<'db>( ); } Adt::Enum(e) => { - let source_map = db.enum_signature_with_source_map(e.id).1; - expr_store_diagnostics(db, acc, &source_map); + let source_map = &EnumSignature::with_source_map(db, e.id).1; + expr_store_diagnostics(db, acc, source_map); let (variants, diagnostics) = e.id.enum_variants_with_diagnostics(db); let file = e.id.lookup(db).id.file_id; let ast_id_map = db.ast_id_map(file); @@ -789,13 +794,13 @@ pub fn diagnostics<'db>( } ModuleDef::Macro(m) => emit_macro_def_diagnostics(db, acc, m), ModuleDef::TypeAlias(type_alias) => { - let source_map = db.type_alias_signature_with_source_map(type_alias.id).1; - expr_store_diagnostics(db, acc, &source_map); + let source_map = &TypeAliasSignature::with_source_map(db, type_alias.id).1; + expr_store_diagnostics(db, acc, source_map); push_ty_diagnostics( db, acc, db.type_for_type_alias_with_diagnostics(type_alias.id).1, - &source_map, + source_map, ); acc.extend(def.diagnostics(db, style_lints)); } @@ -815,8 +820,8 @@ pub fn diagnostics<'db>( continue; }; let loc = impl_id.lookup(db); - let (impl_signature, source_map) = db.impl_signature_with_source_map(impl_id); - expr_store_diagnostics(db, acc, &source_map); + let (impl_signature, source_map) = ImplSignature::with_source_map(db, impl_id); + expr_store_diagnostics(db, acc, source_map); let file_id = loc.id.file_id; if file_id.macro_file().is_some_and(|it| it.kind(db) == MacroKind::DeriveBuiltIn) { @@ -888,9 +893,9 @@ pub fn diagnostics<'db>( if let (false, Some(trait_)) = (impl_is_negative, trait_) { let items = &trait_.id.trait_items(db).items; let required_items = items.iter().filter(|&(_, assoc)| match *assoc { - AssocItemId::FunctionId(it) => !db.function_signature(it).has_body(), - AssocItemId::ConstId(id) => !db.const_signature(id).has_body(), - AssocItemId::TypeAliasId(it) => db.type_alias_signature(it).ty.is_none(), + AssocItemId::FunctionId(it) => !FunctionSignature::of(db, it).has_body(), + AssocItemId::ConstId(id) => !ConstSignature::of(db, id).has_body(), + AssocItemId::TypeAliasId(it) => TypeAliasSignature::of(db, it).ty.is_none(), }); impl_assoc_items_scratch.extend(impl_id.impl_items(db).items.iter().cloned()); @@ -928,7 +933,7 @@ pub fn diagnostics<'db>( let self_ty = structurally_normalize_ty( &infcx, self_ty, - db.trait_environment(impl_id.into()), + db.trait_environment(GenericDefId::from(impl_id).into()), ); let self_ty_is_guaranteed_unsized = matches!( self_ty.kind(), @@ -983,7 +988,7 @@ pub fn diagnostics<'db>( continue; } - if db.function_signature(*fn_).is_default() { + if FunctionSignature::of(db, *fn_).is_default() { return false; } } @@ -1007,12 +1012,12 @@ pub fn diagnostics<'db>( impl_assoc_items_scratch.clear(); } - push_ty_diagnostics(db, acc, db.impl_self_ty_with_diagnostics(impl_id).1, &source_map); + push_ty_diagnostics(db, acc, db.impl_self_ty_with_diagnostics(impl_id).1, source_map); push_ty_diagnostics( db, acc, db.impl_trait_with_diagnostics(impl_id).and_then(|it| it.1), - &source_map, + source_map, ); for &(_, item) in impl_id.impl_items(db).items.iter() { @@ -1331,7 +1336,7 @@ pub fn name(&self) -> Name { pub fn ty<'db>(&self, db: &'db dyn HirDatabase) -> Type<'db> { let interner = DbInterner::new_no_crate(db); - let ty = InferenceResult::for_body(db, self.owner) + let ty = InferenceResult::of(db, self.owner) .tuple_field_access_type(self.tuple) .as_slice() .get(self.index as usize) @@ -1455,7 +1460,7 @@ pub fn module(self, db: &dyn HirDatabase) -> Module { } pub fn name(self, db: &dyn HirDatabase) -> Name { - db.struct_signature(self.id).name.clone() + StructSignature::of(db, self.id).name.clone() } pub fn fields(self, db: &dyn HirDatabase) -> Vec { @@ -1548,7 +1553,7 @@ pub struct Union { impl Union { pub fn name(self, db: &dyn HirDatabase) -> Name { - db.union_signature(self.id).name.clone() + UnionSignature::of(db, self.id).name.clone() } pub fn module(self, db: &dyn HirDatabase) -> Module { @@ -1607,7 +1612,7 @@ pub fn module(self, db: &dyn HirDatabase) -> Module { } pub fn name(self, db: &dyn HirDatabase) -> Name { - db.enum_signature(self.id).name.clone() + EnumSignature::of(db, self.id).name.clone() } pub fn variants(self, db: &dyn HirDatabase) -> Vec { @@ -1962,6 +1967,44 @@ pub fn name(&self, db: &dyn HirDatabase) -> Name { } } +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum ExpressionStoreOwner { + Body(DefWithBody), + Signature(GenericDef), +} + +impl From for ExpressionStoreOwner { + fn from(v: GenericDef) -> Self { + Self::Signature(v) + } +} + +impl From for ExpressionStoreOwner { + fn from(v: DefWithBody) -> Self { + Self::Body(v) + } +} + +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()), + } + } +} + +impl ExpressionStoreOwner { + pub fn module(self, db: &dyn HirDatabase) -> Module { + match self { + Self::Body(body) => body.module(db), + Self::Signature(generic_def) => generic_def.module(db), + } + } +} + /// The defs which have a body. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum DefWithBody { @@ -2018,7 +2061,7 @@ pub fn debug_hir(self, db: &dyn HirDatabase) -> String { let Some(id) = self.id() else { return String::new(); }; - let body = db.body(id); + let body = Body::of(db, id); body.pretty_print(db, id, Edition::CURRENT) } @@ -2045,17 +2088,17 @@ pub fn diagnostics<'db>( }; let krate = self.module(db).id.krate(db); - let (body, source_map) = db.body_with_source_map(id); + let (body, source_map) = Body::with_source_map(db, id); let sig_source_map = match self { DefWithBody::Function(id) => match id.id { - AnyFunctionId::FunctionId(id) => db.function_signature_with_source_map(id).1, + AnyFunctionId::FunctionId(id) => &FunctionSignature::with_source_map(db, id).1, AnyFunctionId::BuiltinDeriveImplMethod { .. } => return, }, - DefWithBody::Static(id) => db.static_signature_with_source_map(id.into()).1, - DefWithBody::Const(id) => db.const_signature_with_source_map(id.into()).1, + DefWithBody::Static(id) => &StaticSignature::with_source_map(db, id.into()).1, + DefWithBody::Const(id) => &ConstSignature::with_source_map(db, id.into()).1, DefWithBody::Variant(variant) => { let enum_id = variant.parent_enum(db).id; - db.enum_signature_with_source_map(enum_id).1 + &EnumSignature::with_source_map(db, enum_id).1 } }; @@ -2063,17 +2106,11 @@ pub fn diagnostics<'db>( Module { id: def_map.root_module_id() }.diagnostics(db, acc, style_lints); } - expr_store_diagnostics(db, acc, &source_map); + expr_store_diagnostics(db, acc, source_map); - let infer = InferenceResult::for_body(db, id); + let infer = InferenceResult::of(db, id); for d in infer.diagnostics() { - acc.extend(AnyDiagnostic::inference_diagnostic( - db, - id, - d, - &source_map, - &sig_source_map, - )); + acc.extend(AnyDiagnostic::inference_diagnostic(db, id, d, source_map, sig_source_map)); } for (pat_or_expr, mismatch) in infer.type_mismatches() { @@ -2195,7 +2232,7 @@ pub fn diagnostics<'db>( { need_mut = &mir::MutabilityReason::Not; } - let local = Local { parent: id, binding_id }; + let local = Local { parent: id.into(), binding_id }; let is_mut = body[binding_id].mode == BindingAnnotation::Mutable; match (need_mut, is_mut) { @@ -2252,7 +2289,7 @@ pub fn diagnostics<'db>( } for diagnostic in BodyValidationDiagnostic::collect(db, id, style_lints) { - acc.extend(AnyDiagnostic::body_validation_diagnostic(db, diagnostic, &source_map)); + acc.extend(AnyDiagnostic::body_validation_diagnostic(db, diagnostic, source_map)); } for diag in hir_ty::diagnostics::incorrect_case(db, id.into()) { @@ -2266,7 +2303,7 @@ pub fn expression_types<'db>( db: &'db dyn HirDatabase, ) -> impl Iterator> { self.id().into_iter().flat_map(move |def_id| { - let infer = InferenceResult::for_body(db, def_id); + let infer = InferenceResult::of(db, def_id); let resolver = def_id.resolver(db); infer.expression_types().map(move |(_, ty)| Type::new_with_resolver(db, &resolver, ty)) @@ -2276,7 +2313,7 @@ pub fn expression_types<'db>( /// Returns an iterator over the inferred types of all patterns in this body. pub fn pattern_types<'db>(self, db: &'db dyn HirDatabase) -> impl Iterator> { self.id().into_iter().flat_map(move |def_id| { - let infer = InferenceResult::for_body(db, def_id); + let infer = InferenceResult::of(db, def_id); let resolver = def_id.resolver(db); infer.pattern_types().map(move |(_, ty)| Type::new_with_resolver(db, &resolver, ty)) @@ -2286,7 +2323,7 @@ pub fn pattern_types<'db>(self, db: &'db dyn HirDatabase) -> impl Iterator(self, db: &'db dyn HirDatabase) -> impl Iterator> { self.id().into_iter().flat_map(move |def_id| { - let infer = InferenceResult::for_body(db, def_id); + let infer = InferenceResult::of(db, def_id); let resolver = def_id.resolver(db); infer.binding_types().map(move |(_, ty)| Type::new_with_resolver(db, &resolver, ty)) @@ -2354,7 +2391,7 @@ pub fn module(self, db: &dyn HirDatabase) -> Module { pub fn name(self, db: &dyn HirDatabase) -> Name { match self.id { - AnyFunctionId::FunctionId(id) => db.function_signature(id).name.clone(), + AnyFunctionId::FunctionId(id) => FunctionSignature::of(db, id).name.clone(), AnyFunctionId::BuiltinDeriveImplMethod { method, .. } => { Name::new_symbol_root(method.name()) } @@ -2556,7 +2593,7 @@ pub fn async_ret_type<'db>(self, db: &'db dyn HirDatabase) -> Option> pub fn has_self_param(self, db: &dyn HirDatabase) -> bool { match self.id { - AnyFunctionId::FunctionId(id) => db.function_signature(id).has_self_param(), + AnyFunctionId::FunctionId(id) => FunctionSignature::of(db, id).has_self_param(), AnyFunctionId::BuiltinDeriveImplMethod { method, .. } => match method { BuiltinDeriveImplMethod::clone | BuiltinDeriveImplMethod::fmt @@ -2591,7 +2628,7 @@ pub fn assoc_fn_params(self, db: &dyn HirDatabase) -> Vec> { pub fn num_params(self, db: &dyn HirDatabase) -> usize { match self.id { - AnyFunctionId::FunctionId(id) => db.function_signature(id).params.len(), + AnyFunctionId::FunctionId(id) => FunctionSignature::of(db, id).params.len(), AnyFunctionId::BuiltinDeriveImplMethod { .. } => { self.fn_sig(db).1.skip_binder().inputs().len() } @@ -2635,21 +2672,21 @@ pub fn params_without_self_with_args<'db>( pub fn is_const(self, db: &dyn HirDatabase) -> bool { match self.id { - AnyFunctionId::FunctionId(id) => db.function_signature(id).is_const(), + AnyFunctionId::FunctionId(id) => FunctionSignature::of(db, id).is_const(), AnyFunctionId::BuiltinDeriveImplMethod { .. } => false, } } pub fn is_async(self, db: &dyn HirDatabase) -> bool { match self.id { - AnyFunctionId::FunctionId(id) => db.function_signature(id).is_async(), + AnyFunctionId::FunctionId(id) => FunctionSignature::of(db, id).is_async(), AnyFunctionId::BuiltinDeriveImplMethod { .. } => false, } } pub fn is_varargs(self, db: &dyn HirDatabase) -> bool { match self.id { - AnyFunctionId::FunctionId(id) => db.function_signature(id).is_varargs(), + AnyFunctionId::FunctionId(id) => FunctionSignature::of(db, id).is_varargs(), AnyFunctionId::BuiltinDeriveImplMethod { .. } => false, } } @@ -2702,7 +2739,7 @@ pub fn is_main(self, db: &dyn HirDatabase) -> bool { AnyFunctionId::FunctionId(id) => { self.exported_main(db) || self.module(db).is_crate_root(db) - && db.function_signature(id).name == sym::main + && FunctionSignature::of(db, id).name == sym::main } AnyFunctionId::BuiltinDeriveImplMethod { .. } => false, } @@ -2779,7 +2816,7 @@ pub fn is_unsafe_to_call( /// This is false in the case of required (not provided) trait methods. pub fn has_body(self, db: &dyn HirDatabase) -> bool { match self.id { - AnyFunctionId::FunctionId(id) => db.function_signature(id).has_body(), + AnyFunctionId::FunctionId(id) => FunctionSignature::of(db, id).has_body(), AnyFunctionId::BuiltinDeriveImplMethod { .. } => true, } } @@ -2807,7 +2844,7 @@ pub fn eval( id.into(), GenericArgs::empty(interner).store(), ParamEnvAndCrate { - param_env: db.trait_environment(id.into()), + param_env: db.trait_environment(GenericDefId::from(id).into()), krate: id.module(db).krate(db), } .store(), @@ -2893,23 +2930,24 @@ pub fn as_local(&self, db: &dyn HirDatabase) -> Option { match self.func { Callee::Def(CallableDefId::FunctionId(it)) => { let parent = DefWithBodyId::FunctionId(it); - let body = db.body(parent); + let body = Body::of(db, parent); if let Some(self_param) = body.self_param.filter(|_| self.idx == 0) { - Some(Local { parent, binding_id: self_param }) + Some(Local { parent: parent.into(), binding_id: self_param }) } else if let Pat::Bind { id, .. } = &body[body.params[self.idx - body.self_param.is_some() as usize]] { - Some(Local { parent, binding_id: *id }) + Some(Local { parent: parent.into(), binding_id: *id }) } else { None } } Callee::Closure(closure, _) => { let c = db.lookup_intern_closure(closure); - let body_owner = c.0.as_def_with_body()?; - let body = db.body(body_owner); - if let Expr::Closure { args, .. } = &body[c.1] - && let Pat::Bind { id, .. } = &body[args[self.idx]] + let body_owner = c.0; + let store = ExpressionStore::of(db, c.0); + + if let Expr::Closure { args, .. } = &store[c.1] + && let Pat::Bind { id, .. } = &store[args[self.idx]] { return Some(Local { parent: body_owner, binding_id: *id }); } @@ -2933,7 +2971,7 @@ impl SelfParam { pub fn access(self, db: &dyn HirDatabase) -> Access { match self.func.id { AnyFunctionId::FunctionId(id) => { - let func_data = db.function_signature(id); + let func_data = FunctionSignature::of(db, id); func_data .params .first() @@ -3062,7 +3100,7 @@ pub fn module(self, db: &dyn HirDatabase) -> Module { } pub fn name(self, db: &dyn HirDatabase) -> Option { - db.const_signature(self.id).name.clone() + ConstSignature::of(db, self.id).name.clone() } pub fn value(self, db: &dyn HirDatabase) -> Option { @@ -3135,11 +3173,11 @@ pub fn module(self, db: &dyn HirDatabase) -> Module { } pub fn name(self, db: &dyn HirDatabase) -> Name { - db.static_signature(self.id).name.clone() + StaticSignature::of(db, self.id).name.clone() } pub fn is_mut(self, db: &dyn HirDatabase) -> bool { - db.static_signature(self.id).flags.contains(StaticFlags::MUTABLE) + StaticSignature::of(db, self.id).flags.contains(StaticFlags::MUTABLE) } pub fn value(self, db: &dyn HirDatabase) -> Option { @@ -3195,7 +3233,7 @@ pub fn module(self, db: &dyn HirDatabase) -> Module { } pub fn name(self, db: &dyn HirDatabase) -> Name { - db.trait_signature(self.id).name.clone() + TraitSignature::of(db, self.id).name.clone() } pub fn direct_supertraits(self, db: &dyn HirDatabase) -> Vec { @@ -3225,11 +3263,11 @@ pub fn items_with_supertraits(self, db: &dyn HirDatabase) -> Vec { } pub fn is_auto(self, db: &dyn HirDatabase) -> bool { - db.trait_signature(self.id).flags.contains(TraitFlags::AUTO) + TraitSignature::of(db, self.id).flags.contains(TraitFlags::AUTO) } pub fn is_unsafe(&self, db: &dyn HirDatabase) -> bool { - db.trait_signature(self.id).flags.contains(TraitFlags::UNSAFE) + TraitSignature::of(db, self.id).flags.contains(TraitFlags::UNSAFE) } pub fn type_or_const_param_count( @@ -3305,7 +3343,7 @@ pub fn ty_params(self, db: &dyn HirDatabase) -> Type<'_> { } pub fn name(self, db: &dyn HirDatabase) -> Name { - db.type_alias_signature(self.id).name.clone() + TypeAliasSignature::of(db, self.id).name.clone() } } @@ -3752,6 +3790,17 @@ fn as_assoc_item(self, db: &dyn HirDatabase) -> Option { } } +impl AsAssocItem for GenericDef { + fn as_assoc_item(self, db: &dyn HirDatabase) -> Option { + match self { + GenericDef::Function(it) => it.as_assoc_item(db), + GenericDef::Const(it) => it.as_assoc_item(db), + GenericDef::TypeAlias(it) => it.as_assoc_item(db), + _ => None, + } + } +} + fn as_assoc_item<'db, ID, DEF, LOC>( db: &(dyn HirDatabase + 'db), ctor: impl FnOnce(DEF) -> AssocItem, @@ -3934,7 +3983,7 @@ pub fn diagnostics<'db>( db, acc, db.type_for_type_alias_with_diagnostics(type_alias.id).1, - &db.type_alias_signature_with_source_map(type_alias.id).1, + &TypeAliasSignature::with_source_map(db, type_alias.id).1, ); for diag in hir_ty::diagnostics::incorrect_case(db, type_alias.id.into()) { acc.push(diag.into()); @@ -4085,24 +4134,24 @@ pub fn diagnostics<'db>(self, db: &'db dyn HirDatabase, acc: &mut Vec db.enum_signature_with_source_map(it).1, - GenericDefId::AdtId(AdtId::StructId(it)) => db.struct_signature_with_source_map(it).1, - GenericDefId::AdtId(AdtId::UnionId(it)) => db.union_signature_with_source_map(it).1, + GenericDefId::AdtId(AdtId::EnumId(it)) => &EnumSignature::with_source_map(db, it).1, + GenericDefId::AdtId(AdtId::StructId(it)) => &StructSignature::with_source_map(db, it).1, + GenericDefId::AdtId(AdtId::UnionId(it)) => &UnionSignature::with_source_map(db, it).1, GenericDefId::ConstId(_) => return, - GenericDefId::FunctionId(it) => db.function_signature_with_source_map(it).1, - GenericDefId::ImplId(it) => db.impl_signature_with_source_map(it).1, + GenericDefId::FunctionId(it) => &FunctionSignature::with_source_map(db, it).1, + GenericDefId::ImplId(it) => &ImplSignature::with_source_map(db, it).1, GenericDefId::StaticId(_) => return, - GenericDefId::TraitId(it) => db.trait_signature_with_source_map(it).1, - GenericDefId::TypeAliasId(it) => db.type_alias_signature_with_source_map(it).1, + GenericDefId::TraitId(it) => &TraitSignature::with_source_map(db, it).1, + GenericDefId::TypeAliasId(it) => &TypeAliasSignature::with_source_map(db, it).1, }; - expr_store_diagnostics(db, acc, &source_map); - push_ty_diagnostics(db, acc, db.generic_defaults_with_diagnostics(def).1, &source_map); + expr_store_diagnostics(db, acc, source_map); + push_ty_diagnostics(db, acc, db.generic_defaults_with_diagnostics(def).1, source_map); push_ty_diagnostics( db, acc, GenericPredicates::query_with_diagnostics(db, def).1.clone(), - &source_map, + source_map, ); for (param_id, param) in generics.iter_type_or_consts() { if let TypeOrConstParamData::ConstParamData(_) = param { @@ -4113,7 +4162,7 @@ pub fn diagnostics<'db>(self, db: &'db dyn HirDatabase, acc: &mut Vec Vec<(Symbol, Type<'db>)> { /// A single local definition. #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub struct Local { - pub(crate) parent: DefWithBodyId, + pub(crate) parent: ExpressionStoreOwnerId, pub(crate) binding_id: BindingId, } @@ -4272,7 +4321,7 @@ pub fn is_param(self, db: &dyn HirDatabase) -> bool { pub fn as_self_param(self, db: &dyn HirDatabase) -> Option { match self.parent { - DefWithBodyId::FunctionId(func) if self.is_self(db) => { + ExpressionStoreOwnerId::Body(DefWithBodyId::FunctionId(func)) if self.is_self(db) => { Some(SelfParam { func: func.into() }) } _ => None, @@ -4280,8 +4329,7 @@ pub fn as_self_param(self, db: &dyn HirDatabase) -> Option { } pub fn name(self, db: &dyn HirDatabase) -> Name { - let body = db.body(self.parent); - body[self.binding_id].name.clone() + ExpressionStore::of(db, self.parent)[self.binding_id].name.clone() } pub fn is_self(self, db: &dyn HirDatabase) -> bool { @@ -4289,16 +4337,17 @@ pub fn is_self(self, db: &dyn HirDatabase) -> bool { } pub fn is_mut(self, db: &dyn HirDatabase) -> bool { - let body = db.body(self.parent); - body[self.binding_id].mode == BindingAnnotation::Mutable + ExpressionStore::of(db, self.parent)[self.binding_id].mode == BindingAnnotation::Mutable } pub fn is_ref(self, db: &dyn HirDatabase) -> bool { - let body = db.body(self.parent); - matches!(body[self.binding_id].mode, BindingAnnotation::Ref | BindingAnnotation::RefMut) + matches!( + ExpressionStore::of(db, self.parent)[self.binding_id].mode, + BindingAnnotation::Ref | BindingAnnotation::RefMut + ) } - pub fn parent(self, _db: &dyn HirDatabase) -> DefWithBody { + pub fn parent(self, _db: &dyn HirDatabase) -> ExpressionStoreOwner { self.parent.into() } @@ -4312,67 +4361,89 @@ pub fn as_id(self) -> u32 { pub fn ty(self, db: &dyn HirDatabase) -> Type<'_> { let def = self.parent; - let infer = InferenceResult::for_body(db, def); + let infer = InferenceResult::of(db, def); let ty = infer.binding_ty(self.binding_id); Type::new(db, def, ty) } /// All definitions for this local. Example: `let (a$0, _) | (_, a$0) = it;` pub fn sources(self, db: &dyn HirDatabase) -> Vec { - let (body, source_map) = db.body_with_source_map(self.parent); - match body.self_param.zip(source_map.self_param_syntax()) { - Some((param, source)) if param == self.binding_id => { - let root = source.file_syntax(db); - vec![LocalSource { - local: self, - source: source.map(|ast| Either::Right(ast.to_node(&root))), - }] + let b; + let s; + let (_, source_map) = match self.parent { + ExpressionStoreOwnerId::Signature(generic_def_id) => { + s = ExpressionStore::with_source_map(db, generic_def_id.into()); + (s.0, s.1) } - _ => source_map - .patterns_for_binding(self.binding_id) - .iter() - .map(|&definition| { - let src = source_map.pat_syntax(definition).unwrap(); // Hmm... - let root = src.file_syntax(db); - LocalSource { + ExpressionStoreOwnerId::Body(def_with_body_id) => { + b = Body::with_source_map(db, def_with_body_id); + if let Some((param, source)) = b.0.self_param.zip(b.1.self_param_syntax()) + && param == self.binding_id + { + let root = source.file_syntax(db); + return vec![LocalSource { local: self, - source: src.map(|ast| match ast.to_node(&root) { - Either::Right(ast::Pat::IdentPat(it)) => Either::Left(it), - _ => unreachable!("local with non ident-pattern"), - }), - } - }) - .collect(), - } + source: source.map(|ast| Either::Right(ast.to_node(&root))), + }]; + } + (&b.0.store, &b.1.store) + } + }; + source_map + .patterns_for_binding(self.binding_id) + .iter() + .map(|&definition| { + let src = source_map.pat_syntax(definition).unwrap(); // Hmm... + let root = src.file_syntax(db); + LocalSource { + local: self, + source: src.map(|ast| match ast.to_node(&root) { + Either::Right(ast::Pat::IdentPat(it)) => Either::Left(it), + _ => unreachable!("local with non ident-pattern"), + }), + } + }) + .collect() } /// The leftmost definition for this local. Example: `let (a$0, _) | (_, a) = it;` pub fn primary_source(self, db: &dyn HirDatabase) -> LocalSource { - let (body, source_map) = db.body_with_source_map(self.parent); - match body.self_param.zip(source_map.self_param_syntax()) { - Some((param, source)) if param == self.binding_id => { - let root = source.file_syntax(db); + let b; + let s; + let (_, source_map) = match self.parent { + ExpressionStoreOwnerId::Signature(generic_def_id) => { + s = ExpressionStore::with_source_map(db, generic_def_id.into()); + (s.0, s.1) + } + ExpressionStoreOwnerId::Body(def_with_body_id) => { + b = Body::with_source_map(db, def_with_body_id); + if let Some((param, source)) = b.0.self_param.zip(b.1.self_param_syntax()) + && param == self.binding_id + { + let root = source.file_syntax(db); + return LocalSource { + local: self, + source: source.map(|ast| Either::Right(ast.to_node(&root))), + }; + } + (&b.0.store, &b.1.store) + } + }; + source_map + .patterns_for_binding(self.binding_id) + .first() + .map(|&definition| { + let src = source_map.pat_syntax(definition).unwrap(); // Hmm... + let root = src.file_syntax(db); LocalSource { local: self, - source: source.map(|ast| Either::Right(ast.to_node(&root))), + source: src.map(|ast| match ast.to_node(&root) { + Either::Right(ast::Pat::IdentPat(it)) => Either::Left(it), + _ => unreachable!("local with non ident-pattern"), + }), } - } - _ => source_map - .patterns_for_binding(self.binding_id) - .first() - .map(|&definition| { - let src = source_map.pat_syntax(definition).unwrap(); // Hmm... - let root = src.file_syntax(db); - LocalSource { - local: self, - source: src.map(|ast| match ast.to_node(&root) { - Either::Right(ast::Pat::IdentPat(it)) => Either::Left(it), - _ => unreachable!("local with non ident-pattern"), - }), - } - }) - .unwrap(), - } + }) + .unwrap() } } @@ -4457,7 +4528,7 @@ pub fn krate(&self) -> Crate { #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub struct Label { - pub(crate) parent: DefWithBodyId, + pub(crate) parent: ExpressionStoreOwnerId, pub(crate) label_id: LabelId, } @@ -4466,13 +4537,12 @@ pub fn module(self, db: &dyn HirDatabase) -> Module { self.parent(db).module(db) } - pub fn parent(self, _db: &dyn HirDatabase) -> DefWithBody { + pub fn parent(self, _db: &dyn HirDatabase) -> ExpressionStoreOwner { self.parent.into() } pub fn name(self, db: &dyn HirDatabase) -> Name { - let body = db.body(self.parent); - body[self.label_id].name.clone() + ExpressionStore::of(db, self.parent)[self.label_id].name.clone() } } @@ -4781,7 +4851,7 @@ fn extend_with_def_map(db: &dyn HirDatabase, def_map: &DefMap, result: &mut Vec< result.extend(module.scope.builtin_derive_impls().map(Impl::from)); for unnamed_const in module.scope.unnamed_consts() { - for (_, block_def_map) in db.body(unnamed_const.into()).blocks(db) { + for (_, block_def_map) in Body::of(db, unnamed_const.into()).blocks(db) { extend_with_def_map(db, block_def_map, result); } } @@ -4938,14 +5008,14 @@ pub fn items(self, db: &dyn HirDatabase) -> Vec { pub fn is_negative(self, db: &dyn HirDatabase) -> bool { match self.id { - AnyImplId::ImplId(id) => db.impl_signature(id).flags.contains(ImplFlags::NEGATIVE), + AnyImplId::ImplId(id) => ImplSignature::of(db, id).flags.contains(ImplFlags::NEGATIVE), AnyImplId::BuiltinDeriveImplId(_) => false, } } pub fn is_unsafe(self, db: &dyn HirDatabase) -> bool { match self.id { - AnyImplId::ImplId(id) => db.impl_signature(id).flags.contains(ImplFlags::UNSAFE), + AnyImplId::ImplId(id) => ImplSignature::of(db, id).flags.contains(ImplFlags::UNSAFE), AnyImplId::BuiltinDeriveImplId(_) => false, } } @@ -5052,16 +5122,13 @@ pub fn captured_items(&self, db: &'db dyn HirDatabase) -> Vec Vec> { let Some(body_owner) = owner.as_def_with_body() else { return Vec::new(); }; - let infer = InferenceResult::for_body(db, body_owner); + let infer = InferenceResult::of(db, body_owner); let (captures, _) = infer.closure_info(id); let env = body_param_env_from_has_crate(db, body_owner); captures.iter().map(|capture| Type { env, ty: capture.ty(db, self.subst) }).collect() @@ -5091,7 +5158,7 @@ pub fn fn_trait(&self, db: &dyn HirDatabase) -> FnTrait { let Some(body_owner) = owner.as_def_with_body() else { return FnTrait::FnOnce; }; - let infer = InferenceResult::for_body(db, body_owner); + let infer = InferenceResult::of(db, body_owner); let info = infer.closure_info(id); info.1.into() } @@ -5174,7 +5241,7 @@ pub fn get_id(self, db: &dyn HirDatabase, krate: Crate) -> Option { #[derive(Clone, Debug, PartialEq, Eq)] pub struct ClosureCapture<'db> { - owner: DefWithBodyId, + owner: ExpressionStoreOwnerId, closure: InternedClosureId, capture: hir_ty::CapturedItem, _marker: PhantomCovariantLifetime<'db>, @@ -5233,17 +5300,16 @@ pub enum CaptureKind { #[derive(Debug, Clone)] pub struct CaptureUsages { - parent: DefWithBodyId, + parent: ExpressionStoreOwnerId, spans: SmallVec<[mir::MirSpan; 3]>, } impl CaptureUsages { pub fn sources(&self, db: &dyn HirDatabase) -> Vec { - let (body, source_map) = db.body_with_source_map(self.parent); - + let (body, source_map) = ExpressionStore::with_source_map(db, self.parent); let mut result = Vec::with_capacity(self.spans.len()); for &span in self.spans.iter() { - let is_ref = span.is_ref_span(&body); + let is_ref = span.is_ref_span(body); match span { mir::MirSpan::ExprId(expr) => { if let Ok(expr) = source_map.expr_syntax(expr) { @@ -5411,7 +5477,7 @@ pub fn contains_reference(&self, db: &'db dyn HirDatabase) -> bool { fn is_phantom_data(db: &dyn HirDatabase, adt_id: AdtId) -> bool { match adt_id { AdtId::StructId(s) => { - let flags = db.struct_signature(s).flags; + let flags = StructSignature::of(db, s).flags; flags.contains(StructFlags::IS_PHANTOM_DATA) } AdtId::UnionId(_) | AdtId::EnumId(_) => false, @@ -6005,8 +6071,8 @@ fn with_method_resolution( // for a nicer IDE experience. However, method resolution is always done on real code (either // existing code or code to be inserted), and there using PostAnalysis is dangerous - we may // suggest invalid methods. So we're using the TypingMode of the body we're in. - let typing_mode = if let Some(body_owner) = resolver.body_owner() { - TypingMode::analysis_in_body(interner, body_owner.into()) + let typing_mode = if let Some(store_owner) = resolver.expression_store_owner() { + TypingMode::analysis_in_body(interner, store_owner.into()) } else { TypingMode::non_body_analysis() }; @@ -6411,18 +6477,19 @@ pub fn is_bool(&self) -> bool { #[derive(Debug, PartialEq, Eq, Copy, Clone, Hash)] pub struct InlineAsmOperand { - owner: DefWithBodyId, + owner: ExpressionStoreOwnerId, expr: ExprId, index: usize, } impl InlineAsmOperand { - pub fn parent(self, _db: &dyn HirDatabase) -> DefWithBody { + pub fn parent(self, _db: &dyn HirDatabase) -> ExpressionStoreOwner { self.owner.into() } pub fn name(&self, db: &dyn HirDatabase) -> Option { - match &db.body(self.owner)[self.expr] { + let body = ExpressionStore::of(db, self.owner); + match &body[self.expr] { hir_def::hir::Expr::InlineAsm(e) => e.operands.get(self.index)?.0.clone(), _ => None, } @@ -7183,7 +7250,7 @@ fn param_env_from_resolver<'db>( ParamEnvAndCrate { param_env: resolver .generic_def() - .map_or_else(ParamEnv::empty, |generic_def| db.trait_environment(generic_def)), + .map_or_else(ParamEnv::empty, |generic_def| db.trait_environment(generic_def.into())), krate: resolver.krate(), } } @@ -7192,14 +7259,14 @@ fn param_env_from_has_crate<'db>( db: &'db dyn HirDatabase, id: impl hir_def::HasModule + Into + Copy, ) -> ParamEnvAndCrate<'db> { - ParamEnvAndCrate { param_env: db.trait_environment(id.into()), krate: id.krate(db) } + ParamEnvAndCrate { param_env: db.trait_environment(id.into().into()), krate: id.krate(db) } } fn body_param_env_from_has_crate<'db>( db: &'db dyn HirDatabase, id: impl hir_def::HasModule + Into + Copy, ) -> ParamEnvAndCrate<'db> { - ParamEnvAndCrate { param_env: db.trait_environment_for_body(id.into()), krate: id.krate(db) } + ParamEnvAndCrate { param_env: db.trait_environment(id.into().into()), krate: id.krate(db) } } fn empty_param_env<'db>(krate: base_db::Crate) -> ParamEnvAndCrate<'db> { diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs index a231f4aff515..f1aabb59337a 100644 --- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs +++ b/src/tools/rust-analyzer/crates/hir/src/semantics.rs @@ -13,7 +13,8 @@ use base_db::FxIndexSet; use either::Either; use hir_def::{ - BuiltinDeriveImplId, DefWithBodyId, HasModule, MacroId, StructId, TraitId, VariantId, + BuiltinDeriveImplId, DefWithBodyId, ExpressionStoreOwnerId, HasModule, MacroId, StructId, + TraitId, VariantId, attrs::parse_extra_crate_attrs, expr_store::{Body, ExprOrPatSource, HygieneId, path::Path}, hir::{BindingId, Expr, ExprId, ExprOrPatId, Pat}, @@ -54,10 +55,10 @@ use crate::{ Adjust, Adjustment, Adt, AnyFunctionId, AutoBorrow, BindingMode, BuiltinAttr, Callable, Const, - ConstParam, Crate, DefWithBody, DeriveHelper, Enum, Field, Function, GenericSubstitution, - HasSource, Impl, InFile, InlineAsmOperand, ItemInNs, Label, LifetimeParam, Local, Macro, - Module, ModuleDef, Name, OverloadedDeref, ScopeDef, Static, Struct, ToolModule, Trait, - TupleField, Type, TypeAlias, TypeParam, Union, Variant, VariantDef, + ConstParam, Crate, DefWithBody, DeriveHelper, Enum, ExpressionStoreOwner, Field, Function, + GenericSubstitution, HasSource, Impl, InFile, InlineAsmOperand, ItemInNs, Label, LifetimeParam, + Local, Macro, Module, ModuleDef, Name, OverloadedDeref, ScopeDef, Static, Struct, ToolModule, + Trait, TupleField, Type, TypeAlias, TypeParam, Union, Variant, VariantDef, db::HirDatabase, semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx}, source_analyzer::{SourceAnalyzer, resolve_hir_path}, @@ -785,16 +786,20 @@ pub fn speculative_expand_derive_as_pseudo_attr_macro( /// 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 { - let body = self.db.body(to_be_renamed.parent); + // FIXME: signatures + let Some(def) = to_be_renamed.parent.as_def_with_body() else { + return Vec::new(); + }; + let body = Body::of(self.db, def); let resolver = to_be_renamed.parent.resolver(self.db); let starting_expr = body.binding_owner(to_be_renamed.binding_id).unwrap_or(body.body_expr); let mut visitor = RenameConflictsVisitor { - body: &body, + body, conflicts: FxHashSet::default(), db: self.db, new_name: new_name.symbol().clone(), old_name: to_be_renamed.name(self.db).symbol().clone(), - owner: to_be_renamed.parent, + owner: def, to_be_renamed: to_be_renamed.binding_id, resolver, }; @@ -1917,10 +1922,10 @@ pub fn get_unsafe_ops(&self, def: DefWithBody) -> FxHashSet { let Ok(def) = DefWithBodyId::try_from(def) else { return FxHashSet::default(); }; - let (body, source_map) = self.db.body_with_source_map(def); - let infer = InferenceResult::for_body(self.db, def); + let (body, source_map) = Body::with_source_map(self.db, def); + let infer = InferenceResult::of(self.db, def); let mut res = FxHashSet::default(); - unsafe_operations_for_body(self.db, infer, def, &body, &mut |node| { + unsafe_operations_for_body(self.db, infer, def, body, &mut |node| { if let Ok(node) = source_map.expr_or_pat_syntax(node) { res.insert(node); } @@ -1935,13 +1940,13 @@ pub fn get_unsafe_ops_for_unsafe_block(&self, block: ast::BlockExpr) -> Vec bool { let Some(def) = def else { return false }; let enclosing_node = enclosing_item.as_ref().either(|i| i.syntax(), |v| v.syntax()); - let (body, source_map) = self.db.body_with_source_map(def); + let (body, source_map) = Body::with_source_map(self.db, def); let file_id = self.find_file(expr.syntax()).file_id; @@ -2326,7 +2331,7 @@ pub fn locals_used( let sa = self.analyze(element.either(|e| e.syntax(), |s| s.syntax()))?; let store = sa.store()?; let mut resolver = sa.resolver.clone(); - let def = resolver.body_owner()?; + let def = resolver.expression_store_owner()?; let is_not_generated = |path: &Path| { !path.mod_path().and_then(|path| path.as_ident()).is_some_and(Name::is_generated) @@ -2576,13 +2581,18 @@ pub fn krate(&self) -> Crate { Crate { id: self.resolver.krate() } } + // FIXME: This is a weird function, we shouldn't have this? pub fn containing_function(&self) -> Option { - self.resolver.body_owner().and_then(|owner| match owner { - DefWithBodyId::FunctionId(id) => Some(id.into()), + self.resolver.expression_store_owner().and_then(|owner| match owner { + ExpressionStoreOwnerId::Body(DefWithBodyId::FunctionId(id)) => Some(id.into()), _ => None, }) } + pub fn expression_store_owner(&self) -> Option { + self.resolver.expression_store_owner().map(Into::into) + } + pub(crate) fn resolver(&self) -> &Resolver<'db> { &self.resolver } @@ -2604,14 +2614,18 @@ pub fn process_all_names(&self, f: &mut dyn FnMut(Name, ScopeDef)) { resolver::ScopeDef::ImplSelfType(it) => ScopeDef::ImplSelfType(it.into()), resolver::ScopeDef::AdtSelfType(it) => ScopeDef::AdtSelfType(it.into()), resolver::ScopeDef::GenericParam(id) => ScopeDef::GenericParam(id.into()), - resolver::ScopeDef::Local(binding_id) => match self.resolver.body_owner() { - Some(parent) => ScopeDef::Local(Local { parent, binding_id }), - None => continue, - }, - resolver::ScopeDef::Label(label_id) => match self.resolver.body_owner() { - Some(parent) => ScopeDef::Label(Label { parent, label_id }), - None => continue, - }, + resolver::ScopeDef::Local(binding_id) => { + match self.resolver.expression_store_owner() { + Some(parent) => ScopeDef::Local(Local { parent, binding_id }), + None => continue, + } + } + resolver::ScopeDef::Label(label_id) => { + match self.resolver.expression_store_owner() { + Some(parent) => ScopeDef::Label(Label { parent, label_id }), + None => continue, + } + } }; f(name.clone(), def) } diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics/child_by_source.rs b/src/tools/rust-analyzer/crates/hir/src/semantics/child_by_source.rs index 143cc14c3377..f6d1bec5754c 100644 --- a/src/tools/rust-analyzer/crates/hir/src/semantics/child_by_source.rs +++ b/src/tools/rust-analyzer/crates/hir/src/semantics/child_by_source.rs @@ -18,8 +18,10 @@ DynMap, keys::{self, Key}, }, + expr_store::Body, hir::generics::GenericParams, item_scope::ItemScope, + signatures::{EnumSignature, ImplSignature, TraitSignature}, src::{HasChildSource, HasSource}, }; @@ -49,7 +51,7 @@ fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap, file_id: Hi data.items.iter().for_each(|&(_, item)| { add_assoc_item(db, res, file_id, item); }); - let (_, source_map) = db.trait_signature_with_source_map(*self); + let (_, source_map) = TraitSignature::with_source_map(db, *self); source_map.expansions().filter(|(ast, _)| ast.file_id == file_id).for_each( |(ast, &exp_id)| { res[keys::MACRO_CALL].insert(ast.value, exp_id); @@ -74,7 +76,7 @@ fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap, file_id: Hi data.items.iter().for_each(|&(_, item)| { add_assoc_item(db, res, file_id, item); }); - let (_, source_map) = db.impl_signature_with_source_map(*self); + let (_, source_map) = ImplSignature::with_source_map(db, *self); source_map.expansions().filter(|(ast, _)| ast.file_id == file_id).for_each( |(ast, &exp_id)| { res[keys::MACRO_CALL].insert(ast.value, exp_id); @@ -204,7 +206,7 @@ fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap, file_id: Hi self.enum_variants(db).variants.iter().for_each(|&(variant, _, _)| { res[keys::ENUM_VARIANT].insert(ast_id_map.get(variant.lookup(db).id.value), variant); }); - let (_, source_map) = db.enum_signature_with_source_map(*self); + let (_, source_map) = EnumSignature::with_source_map(db, *self); source_map .expansions() .filter(|(ast, _)| ast.file_id == file_id) @@ -214,7 +216,7 @@ fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap, file_id: Hi impl ChildBySource for DefWithBodyId { fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap, file_id: HirFileId) { - let (body, sm) = db.body_with_source_map(*self); + let (body, sm) = Body::with_source_map(db, *self); if let &DefWithBodyId::VariantId(v) = self { VariantId::EnumVariantId(v).child_by_source_to(db, res, file_id) } @@ -239,8 +241,7 @@ fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap, file_id: Hi return; } - let (generic_params, _, source_map) = - GenericParams::generic_params_and_store_and_source_map(db, *self); + let (generic_params, _, source_map) = GenericParams::with_source_map(db, *self); let mut toc_idx_iter = generic_params.iter_type_or_consts().map(|(idx, _)| idx); let lts_idx_iter = generic_params.iter_lt().map(|(idx, _)| idx); 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 d222c3dc7ed1..8c398728b08a 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 @@ -88,13 +88,14 @@ use either::Either; use hir_def::{ AdtId, BlockId, BuiltinDeriveImplId, ConstId, ConstParamId, DefWithBodyId, EnumId, - EnumVariantId, ExternBlockId, ExternCrateId, FieldId, FunctionId, GenericDefId, GenericParamId, - ImplId, LifetimeParamId, Lookup, MacroId, ModuleId, StaticId, StructId, TraitId, TypeAliasId, - TypeParamId, UnionId, UseId, VariantId, + EnumVariantId, ExpressionStoreOwnerId, ExternBlockId, ExternCrateId, FieldId, FunctionId, + GenericDefId, GenericParamId, ImplId, LifetimeParamId, Lookup, MacroId, ModuleId, StaticId, + StructId, TraitId, TypeAliasId, TypeParamId, UnionId, UseId, VariantId, dyn_map::{ DynMap, keys::{self, Key}, }, + expr_store::{Body, ExpressionStore}, hir::{BindingId, Expr, LabelId}, nameres::{block_def_map, crate_def_map}, }; @@ -334,8 +335,8 @@ pub(super) fn asm_operand_to_def( _ => None, }) .position(|it| it == *src.value)?; - let container = self.find_pat_or_label_container(src.syntax_ref())?; - let source_map = self.db.body_with_source_map(container).1; + let container = self.find_container(src.syntax_ref())?.as_expression_store_owner()?; + let (_, source_map) = ExpressionStore::with_source_map(self.db, container); let expr = source_map.node_expr(src.with_value(&ast::Expr::AsmExpr(asm)))?.as_expr()?; Some(InlineAsmOperand { owner: container, expr, index }) } @@ -343,13 +344,13 @@ pub(super) fn asm_operand_to_def( pub(super) fn bind_pat_to_def( &mut self, src: InFile<&ast::IdentPat>, - ) -> Option<(DefWithBodyId, BindingId)> { - let container = self.find_pat_or_label_container(src.syntax_ref())?; - let (body, source_map) = self.db.body_with_source_map(container); + ) -> Option<(ExpressionStoreOwnerId, BindingId)> { + 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); 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, .. } = body[pat_id.as_pat()?] { + if let crate::Pat::Bind { id, .. } = store[pat_id.as_pat()?] { Some((container, id)) } else { None @@ -359,17 +360,19 @@ pub(super) fn self_param_to_def( &mut self, src: InFile<&ast::SelfParam>, ) -> Option<(DefWithBodyId, BindingId)> { - let container = self.find_pat_or_label_container(src.syntax_ref())?; - let body = self.db.body(container); + let container = self + .find_container(src.syntax_ref())? + .as_expression_store_owner()? + .as_def_with_body()?; + let body = Body::of(self.db, container); Some((container, body.self_param?)) } pub(super) fn label_to_def( &mut self, src: InFile<&ast::Label>, - ) -> Option<(DefWithBodyId, LabelId)> { - let container = self.find_pat_or_label_container(src.syntax_ref())?; - let source_map = self.db.body_with_source_map(container).1; - + ) -> Option<(ExpressionStoreOwnerId, LabelId)> { + let container = self.find_container(src.syntax_ref())?.as_expression_store_owner()?; + let (_, source_map) = ExpressionStore::with_source_map(self.db, container); let label_id = source_map.node_label(src)?; Some((container, label_id)) } @@ -377,13 +380,14 @@ pub(super) fn label_to_def( pub(super) fn label_ref_to_def( &mut self, src: InFile<&ast::Lifetime>, - ) -> Option<(DefWithBodyId, LabelId)> { + ) -> Option<(ExpressionStoreOwnerId, LabelId)> { let break_or_continue = ast::Expr::cast(src.value.syntax().parent()?)?; - let container = self.find_pat_or_label_container(src.syntax_ref())?; - let (body, source_map) = self.db.body_with_source_map(container); + let container = self.find_container(src.syntax_ref())?.as_expression_store_owner()?; + let (store, source_map) = ExpressionStore::with_source_map(self.db, container); let break_or_continue = source_map.node_expr(src.with_value(&break_or_continue))?.as_expr()?; - let (Expr::Break { label, .. } | Expr::Continue { label }) = body[break_or_continue] else { + let (Expr::Break { label, .. } | Expr::Continue { label }) = store[break_or_continue] + else { return None; }; Some((container, label?)) @@ -557,29 +561,6 @@ fn find_generic_param_container(&mut self, src: InFile<&SyntaxNode>) -> Option) -> Option { - self.parent_ancestors_with_macros(src, |this, InFile { file_id, value }, _| { - let item = match ast::Item::cast(value.clone()) { - Some(it) => it, - None => { - let variant = ast::Variant::cast(value)?; - return this - .enum_variant_to_def(InFile::new(file_id, &variant)) - .map(Into::into); - } - }; - match &item { - ast::Item::Fn(it) => this.fn_to_def(InFile::new(file_id, it)).map(Into::into), - ast::Item::Const(it) => this.const_to_def(InFile::new(file_id, it)).map(Into::into), - ast::Item::Static(it) => { - this.static_to_def(InFile::new(file_id, it)).map(Into::into) - } - _ => None, - } - }) - } - /// Skips the attributed item that caused the macro invocation we are climbing up fn parent_ancestors_with_macros( &mut self, @@ -756,4 +737,22 @@ fn child_by_source(self, db: &dyn HirDatabase, file_id: HirFileId) -> DynMap { ChildContainer::GenericDefId(it) => it.child_by_source(db, file_id), } } + + fn as_expression_store_owner(self) -> Option { + match self { + ChildContainer::DefWithBodyId(it) => Some(it.into()), + ChildContainer::ModuleId(_) => None, + ChildContainer::TraitId(it) => { + Some(ExpressionStoreOwnerId::Signature(GenericDefId::TraitId(it))) + } + ChildContainer::EnumId(it) => { + Some(ExpressionStoreOwnerId::Signature(GenericDefId::AdtId(it.into()))) + } + ChildContainer::ImplId(it) => { + Some(ExpressionStoreOwnerId::Signature(GenericDefId::ImplId(it))) + } + ChildContainer::VariantId(_) => None, + ChildContainer::GenericDefId(it) => Some(it.into()), + } + } } diff --git a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs index 1d3cfc748e95..bd77347e93eb 100644 --- a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs +++ b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs @@ -9,8 +9,8 @@ use either::Either; use hir_def::{ - AdtId, AssocItemId, CallableDefId, ConstId, DefWithBodyId, FieldId, FunctionId, GenericDefId, - LocalFieldId, ModuleDefId, StructId, TraitId, VariantId, + AdtId, AssocItemId, CallableDefId, ConstId, DefWithBodyId, ExpressionStoreOwnerId, FieldId, + FunctionId, GenericDefId, LocalFieldId, ModuleDefId, StructId, TraitId, VariantId, expr_store::{ Body, BodySourceMap, ExpressionStore, ExpressionStoreSourceMap, HygieneId, lower::ExprCollector, @@ -78,20 +78,20 @@ pub(crate) struct SourceAnalyzer<'db> { pub(crate) enum BodyOrSig<'db> { Body { def: DefWithBodyId, - body: Arc, - source_map: Arc, + body: &'db Body, + source_map: &'db BodySourceMap, infer: Option<&'db InferenceResult>, }, // To be folded into body once it is considered one VariantFields { def: VariantId, - store: Arc, - source_map: Arc, + store: &'db ExpressionStore, + source_map: &'db ExpressionStoreSourceMap, }, Sig { def: GenericDefId, - store: Arc, - source_map: Arc, + store: &'db ExpressionStore, + source_map: &'db ExpressionStoreSourceMap, infer: Option<&'db InferenceResult>, #[expect(dead_code)] generics: Arc, @@ -105,7 +105,7 @@ pub(crate) fn new_for_body( node: InFile<&SyntaxNode>, offset: Option, ) -> SourceAnalyzer<'db> { - Self::new_for_body_(db, def, node, offset, Some(InferenceResult::for_body(db, def))) + Self::new_for_body_(db, def, node, offset, Some(InferenceResult::of(db, def))) } pub(crate) fn new_for_body_no_infer( @@ -124,10 +124,10 @@ pub(crate) fn new_for_body_( offset: Option, infer: Option<&'db InferenceResult>, ) -> SourceAnalyzer<'db> { - let (body, source_map) = db.body_with_source_map(def); - let scopes = db.expr_scopes(def.into()); + let (body, source_map) = Body::with_source_map(db, def); + let scopes = ExprScopes::of(db, def); let scope = match offset { - None => scope_for(db, &scopes, &source_map, node), + None => scope_for(db, scopes, source_map, node), Some(offset) => { debug_assert!( node.text_range().contains_inclusive(offset), @@ -135,7 +135,7 @@ pub(crate) fn new_for_body_( offset, node.text_range() ); - scope_for_offset(db, &scopes, &source_map, node.file_id, offset) + scope_for_offset(db, scopes, source_map, node.file_id, offset) } }; let resolver = resolver_for_scope(db, def, scope); @@ -171,10 +171,10 @@ pub(crate) fn new_generic_def_( offset: Option, infer: bool, ) -> SourceAnalyzer<'db> { - let (generics, store, source_map) = db.generic_params_and_store_and_source_map(def); - let scopes = db.expr_scopes(def.into()); + let (generics, store, source_map) = GenericParams::with_source_map(db, def); + let scopes = ExprScopes::of(db, def); let scope = match offset { - None => scope_for(db, &scopes, &source_map, node), + None => scope_for(db, scopes, source_map, node), Some(offset) => { debug_assert!( node.text_range().contains_inclusive(offset), @@ -182,15 +182,11 @@ pub(crate) fn new_generic_def_( offset, node.text_range() ); - scope_for_offset(db, &scopes, &source_map, node.file_id, offset) + scope_for_offset(db, scopes, source_map, node.file_id, offset) } }; let resolver = resolver_for_scope(db, def, scope); - let infer = if infer && !Arc::ptr_eq(&store, &ExpressionStore::empty_singleton().0) { - Some(InferenceResult::for_signature(db, def)) - } else { - None - }; + let infer = if infer { Some(InferenceResult::of(db, def)) } else { None }; SourceAnalyzer { resolver, body_or_sig: Some(BodyOrSig::Sig { def, store, source_map, generics, infer }), @@ -208,11 +204,7 @@ pub(crate) fn new_variant_body( let resolver = def.resolver(db); SourceAnalyzer { resolver, - body_or_sig: Some(BodyOrSig::VariantFields { - def, - store: fields.store.clone(), - source_map: source_map.clone(), - }), + body_or_sig: Some(BodyOrSig::VariantFields { def, store: &fields.store, source_map }), file_id, } } @@ -241,6 +233,18 @@ fn infer(&self) -> Option<&InferenceResult> { }) } + pub(crate) fn def( + &self, + ) -> Option<(ExpressionStoreOwnerId, &ExpressionStore, &ExpressionStoreSourceMap)> { + self.body_or_sig.as_ref().and_then(|it| match it { + BodyOrSig::VariantFields { .. } => None, + &BodyOrSig::Sig { def, store, source_map, .. } => Some((def.into(), store, source_map)), + BodyOrSig::Body { def, body, source_map, .. } => { + Some(((*def).into(), &body.store, source_map)) + } + }) + } + pub(crate) fn store(&self) -> Option<&ExpressionStore> { self.body_or_sig.as_ref().map(|it| match it { BodyOrSig::Sig { store, .. } => &**store, @@ -264,9 +268,9 @@ fn param_and<'a>(&self, param_env: ParamEnv<'a>) -> ParamEnvAndCrate<'a> { fn trait_environment(&self, db: &'db dyn HirDatabase) -> ParamEnvAndCrate<'db> { self.param_and(self.body_or_sig.as_ref().map_or_else(ParamEnv::empty, |body_or_sig| { match *body_or_sig { - BodyOrSig::Body { def, .. } => db.trait_environment_for_body(def), + BodyOrSig::Body { def, .. } => db.trait_environment(def.into()), BodyOrSig::VariantFields { .. } => ParamEnv::empty(), - BodyOrSig::Sig { def, .. } => db.trait_environment(def), + BodyOrSig::Sig { def, .. } => db.trait_environment(def.into()), } })) } @@ -806,7 +810,7 @@ pub(crate) fn resolve_record_field( name_hygiene(db, InFile::new(self.file_id, ast_name.syntax())), ) { Some(ValueNs::LocalBinding(binding_id)) => { - Some(Local { binding_id, parent: self.resolver.body_owner()? }) + Some(Local { binding_id, parent: self.resolver.expression_store_owner()? }) } _ => None, } @@ -866,8 +870,8 @@ pub(crate) fn resolve_bind_pat_to_const( }, }; - let body_owner = self.resolver.body_owner(); - let res = resolve_hir_value_path(db, &self.resolver, body_owner, path, HygieneId::ROOT)?; + let store_owner = self.resolver.expression_store_owner(); + let res = resolve_hir_value_path(db, &self.resolver, store_owner, path, HygieneId::ROOT)?; match res { PathResolution::Def(def) => Some(def), _ => None, @@ -1435,7 +1439,7 @@ pub(crate) fn resolve_offset_in_format_args( resolve_hir_value_path( db, &self.resolver, - self.resolver.body_owner(), + self.resolver.expression_store_owner(), &Path::from_known_path_with_no_generic(ModPath::from_segments( PathKind::Plain, Some(name.clone()), @@ -1451,9 +1455,9 @@ pub(crate) fn resolve_offset_in_asm_template( asm: InFile<&ast::AsmExpr>, line: usize, offset: TextSize, - ) -> Option<(DefWithBodyId, (ExprId, TextRange, usize))> { - let (def, _, body_source_map, _) = self.body_()?; - let (expr, args) = body_source_map.asm_template_args(asm)?; + ) -> Option<(ExpressionStoreOwnerId, (ExprId, TextRange, usize))> { + let (def, _, sm) = self.def()?; + let (expr, args) = sm.asm_template_args(asm)?; Some(def).zip( args.get(line)? .iter() @@ -1474,7 +1478,7 @@ pub(crate) fn as_format_args_parts<'a>( resolve_hir_value_path( db, &self.resolver, - self.resolver.body_owner(), + self.resolver.expression_store_owner(), &Path::from_known_path_with_no_generic(ModPath::from_segments( PathKind::Plain, Some(name.clone()), @@ -1488,9 +1492,9 @@ pub(crate) fn as_format_args_parts<'a>( pub(crate) fn as_asm_parts( &self, asm: InFile<&ast::AsmExpr>, - ) -> Option<(DefWithBodyId, (ExprId, &[Vec<(TextRange, usize)>]))> { - let (def, _, body_source_map, _) = self.body_()?; - Some(def).zip(body_source_map.asm_template_args(asm)) + ) -> Option<(ExpressionStoreOwnerId, (ExprId, &[Vec<(TextRange, usize)>]))> { + let (def, _, sm) = self.def()?; + Some(def).zip(sm.asm_template_args(asm)) } fn resolve_impl_method_or_trait_def( @@ -1508,11 +1512,11 @@ fn resolve_impl_method_or_trait_def_with_subst( func: FunctionId, substs: GenericArgs<'db>, ) -> (Function, GenericArgs<'db>) { - let owner = match self.resolver.body_owner() { + let owner = match self.resolver.expression_store_owner() { Some(it) => it, None => return (func.into(), substs), }; - let env = self.param_and(db.trait_environment_for_body(owner)); + let env = self.param_and(db.trait_environment(owner)); let (func, args) = db.lookup_impl_method(env, func, substs); match func { Either::Left(func) => (func.into(), args), @@ -1528,11 +1532,11 @@ fn resolve_impl_const_or_trait_def_with_subst( const_id: ConstId, subs: GenericArgs<'db>, ) -> (ConstId, GenericArgs<'db>) { - let owner = match self.resolver.body_owner() { + let owner = match self.resolver.expression_store_owner() { Some(it) => it, None => return (const_id, subs), }; - let env = self.param_and(db.trait_environment_for_body(owner)); + let env = self.param_and(db.trait_environment(owner)); let interner = DbInterner::new_with(db, env.krate); let infcx = interner.infer_ctxt().build(TypingMode::PostAnalysis); method_resolution::lookup_impl_const(&infcx, env.param_env, const_id, subs) @@ -1743,7 +1747,7 @@ fn resolve_hir_path_( } }; - let body_owner = resolver.body_owner(); + let body_owner = resolver.expression_store_owner(); let values = || resolve_hir_value_path(db, resolver, body_owner, path, hygiene); let items = || { @@ -1789,14 +1793,14 @@ fn resolve_hir_path_( fn resolve_hir_value_path( db: &dyn HirDatabase, resolver: &Resolver<'_>, - body_owner: Option, + store_owner: Option, path: &Path, hygiene: HygieneId, ) -> Option { resolver.resolve_path_in_value_ns_fully(db, path, hygiene).and_then(|val| { let res = match val { ValueNs::LocalBinding(binding_id) => { - let var = Local { parent: body_owner?, binding_id }; + let var = Local { parent: store_owner?, binding_id }; PathResolution::Local(var) } ValueNs::FunctionId(it) => PathResolution::Def(Function::from(it).into()), diff --git a/src/tools/rust-analyzer/crates/hir/src/symbols.rs b/src/tools/rust-analyzer/crates/hir/src/symbols.rs index c088f3aa0cc0..ff56544d82e0 100644 --- a/src/tools/rust-analyzer/crates/hir/src/symbols.rs +++ b/src/tools/rust-analyzer/crates/hir/src/symbols.rs @@ -8,9 +8,11 @@ AdtId, AssocItemId, AstIdLoc, Complete, DefWithBodyId, ExternCrateId, HasModule, ImplId, Lookup, MacroId, ModuleDefId, ModuleId, TraitId, db::DefDatabase, + expr_store::Body, item_scope::{ImportId, ImportOrExternCrate, ImportOrGlob}, nameres::crate_def_map, per_ns::Item, + signatures::{EnumSignature, ImplSignature, TraitSignature}, src::{HasChildSource, HasSource}, visibility::{Visibility, VisibilityExplicitness}, }; @@ -185,7 +187,7 @@ fn collect_from_module(&mut self, module_id: ModuleId) { } ModuleDefId::AdtId(AdtId::EnumId(id)) => { this.push_decl(id, name, false, None); - let enum_name = Symbol::intern(this.db.enum_signature(id).name.as_str()); + let enum_name = Symbol::intern(EnumSignature::of(this.db, id).name.as_str()); this.with_container_name(Some(enum_name), |this| { let variants = id.enum_variants(this.db); for (variant_id, variant_name, _) in &variants.variants { @@ -386,7 +388,7 @@ fn collect_from_body(&mut self, body_id: impl Into, name: Option< return; } let body_id = body_id.into(); - let body = self.db.body(body_id); + let body = Body::of(self.db, body_id); // Descend into the blocks and enqueue collection of all modules within. for (_, def_map) in body.blocks(self.db) { @@ -397,7 +399,7 @@ fn collect_from_body(&mut self, body_id: impl Into, name: Option< } fn collect_from_impl(&mut self, impl_id: ImplId) { - let impl_data = self.db.impl_signature(impl_id); + let impl_data = ImplSignature::of(self.db, impl_id); let impl_name = Some( hir_display_with_store(impl_data.self_ty, &impl_data.store) .display( @@ -419,7 +421,7 @@ fn collect_from_impl(&mut self, impl_id: ImplId) { } fn collect_from_trait(&mut self, trait_id: TraitId, trait_do_not_complete: Complete) { - let trait_data = self.db.trait_signature(trait_id); + let trait_data = TraitSignature::of(self.db, trait_id); self.with_container_name(Some(Symbol::intern(trait_data.name.as_str())), |s| { for &(ref name, assoc_item_id) in &trait_id.trait_items(self.db).items { s.push_assoc_item(assoc_item_id, name, Some(trait_do_not_complete)); 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 8622aa1378b3..c7ef4e5d5deb 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 @@ -53,7 +53,7 @@ pub(super) fn trivial<'a, 'lt, 'db, DB: HirDatabase>( ScopeDef::GenericParam(GenericParam::ConstParam(it)) => Some(Expr::ConstParam(*it)), ScopeDef::Local(it) => { if ctx.config.enable_borrowcheck { - let borrowck = db.borrowck(it.parent).ok()?; + let borrowck = db.borrowck(it.parent.as_def_with_body()?).ok()?; let invalid = borrowck.iter().any(|b| { b.partially_moved.iter().any(|moved| { diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs index 1749db1e61b4..3c3f71aea6cf 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs @@ -80,9 +80,15 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>) let module = scope.module(); let cfg = ctx.config.find_path_config(ctx.sema.is_nightly(scope.krate())); let self_ty = if ctx.config.prefer_self_ty { - scope - .containing_function() - .and_then(|function| function.as_assoc_item(ctx.db())?.implementing_ty(ctx.db())) + scope.expression_store_owner().and_then(|def| { + match def { + hir::ExpressionStoreOwner::Body(def_with_body) => { + def_with_body.as_assoc_item(ctx.db()) + } + hir::ExpressionStoreOwner::Signature(def) => def.as_assoc_item(ctx.db()), + }? + .implementing_ty(ctx.db()) + }) } else { None }; 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 788f9b73fa19..6ee4c97c873f 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/defs.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/defs.rs @@ -14,11 +14,12 @@ use either::Either; use hir::{ Adt, AsAssocItem, AsExternAssocItem, AssocItem, AttributeTemplate, BuiltinAttr, BuiltinType, - Const, Crate, DefWithBody, DeriveHelper, DisplayTarget, DocLinkDef, ExternAssocItem, - ExternCrateDecl, Field, Function, GenericDef, GenericParam, GenericSubstitution, HasContainer, - HasVisibility, HirDisplay, Impl, InlineAsmOperand, ItemContainer, Label, Local, Macro, Module, - ModuleDef, Name, PathResolution, Semantics, Static, StaticLifetime, Struct, ToolModule, Trait, - TupleField, TypeAlias, Variant, VariantDef, Visibility, + Const, Crate, DefWithBody, DeriveHelper, DisplayTarget, DocLinkDef, ExpressionStoreOwner, + ExternAssocItem, ExternCrateDecl, Field, Function, GenericDef, GenericParam, + GenericSubstitution, HasContainer, HasVisibility, HirDisplay, Impl, InlineAsmOperand, + ItemContainer, Label, Local, Macro, Module, ModuleDef, Name, PathResolution, Semantics, Static, + StaticLifetime, Struct, ToolModule, Trait, TupleField, TypeAlias, Variant, VariantDef, + Visibility, }; use span::Edition; use stdx::{format_to, impl_from}; @@ -1020,6 +1021,16 @@ fn from(def: GenericDef) -> Self { } } +impl TryFrom for Definition { + type Error = (); + fn try_from(def: ExpressionStoreOwner) -> Result { + match def { + ExpressionStoreOwner::Body(def_with_body) => def_with_body.try_into(), + ExpressionStoreOwner::Signature(generic_def) => Ok(generic_def.into()), + } + } +} + impl TryFrom for GenericDef { type Error = (); fn try_from(def: Definition) -> Result { 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 3822eaae2cc7..2cf4627ac892 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/search.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/search.rs @@ -10,9 +10,9 @@ use base_db::{RootQueryDb, SourceDatabase}; use either::Either; use hir::{ - Adt, AsAssocItem, DefWithBody, EditionedFileId, FileRange, FileRangeWrapper, HasAttrs, - HasContainer, HasSource, InFile, InFileWrapper, InRealFile, InlineAsmOperand, ItemContainer, - ModuleSource, PathResolution, Semantics, Visibility, + Adt, AsAssocItem, DefWithBody, EditionedFileId, ExpressionStoreOwner, FileRange, + FileRangeWrapper, HasAttrs, HasContainer, HasSource, InFile, InFileWrapper, InRealFile, + InlineAsmOperand, ItemContainer, ModuleSource, PathResolution, Semantics, Visibility, }; use memchr::memmem::Finder; use parser::SyntaxKind; @@ -310,10 +310,23 @@ fn search_scope(&self, db: &RootDatabase) -> SearchScope { if let Definition::Local(var) = self { let def = match var.parent(db) { - DefWithBody::Function(f) => f.source(db).map(|src| src.syntax().cloned()), - DefWithBody::Const(c) => c.source(db).map(|src| src.syntax().cloned()), - DefWithBody::Static(s) => s.source(db).map(|src| src.syntax().cloned()), - DefWithBody::Variant(v) => v.source(db).map(|src| src.syntax().cloned()), + ExpressionStoreOwner::Body(def) => match def { + DefWithBody::Function(f) => f.source(db).map(|src| src.syntax().cloned()), + DefWithBody::Const(c) => c.source(db).map(|src| src.syntax().cloned()), + DefWithBody::Static(s) => s.source(db).map(|src| src.syntax().cloned()), + DefWithBody::Variant(v) => v.source(db).map(|src| src.syntax().cloned()), + }, + ExpressionStoreOwner::Signature(def) => match def { + hir::GenericDef::Function(it) => it.source(db).map(|src| src.syntax().cloned()), + hir::GenericDef::Adt(it) => it.source(db).map(|src| src.syntax().cloned()), + hir::GenericDef::Trait(it) => it.source(db).map(|src| src.syntax().cloned()), + hir::GenericDef::TypeAlias(it) => { + it.source(db).map(|src| src.syntax().cloned()) + } + hir::GenericDef::Impl(it) => it.source(db).map(|src| src.syntax().cloned()), + hir::GenericDef::Const(it) => it.source(db).map(|src| src.syntax().cloned()), + hir::GenericDef::Static(it) => it.source(db).map(|src| src.syntax().cloned()), + }, }; return match def { Some(def) => SearchScope::file_range( @@ -325,10 +338,23 @@ fn search_scope(&self, db: &RootDatabase) -> SearchScope { if let Definition::InlineAsmOperand(op) = self { let def = match op.parent(db) { - DefWithBody::Function(f) => f.source(db).map(|src| src.syntax().cloned()), - DefWithBody::Const(c) => c.source(db).map(|src| src.syntax().cloned()), - DefWithBody::Static(s) => s.source(db).map(|src| src.syntax().cloned()), - DefWithBody::Variant(v) => v.source(db).map(|src| src.syntax().cloned()), + ExpressionStoreOwner::Body(def) => match def { + DefWithBody::Function(f) => f.source(db).map(|src| src.syntax().cloned()), + DefWithBody::Const(c) => c.source(db).map(|src| src.syntax().cloned()), + DefWithBody::Static(s) => s.source(db).map(|src| src.syntax().cloned()), + DefWithBody::Variant(v) => v.source(db).map(|src| src.syntax().cloned()), + }, + ExpressionStoreOwner::Signature(def) => match def { + hir::GenericDef::Function(it) => it.source(db).map(|src| src.syntax().cloned()), + hir::GenericDef::Adt(it) => it.source(db).map(|src| src.syntax().cloned()), + hir::GenericDef::Trait(it) => it.source(db).map(|src| src.syntax().cloned()), + hir::GenericDef::TypeAlias(it) => { + it.source(db).map(|src| src.syntax().cloned()) + } + hir::GenericDef::Impl(it) => it.source(db).map(|src| src.syntax().cloned()), + hir::GenericDef::Const(it) => it.source(db).map(|src| src.syntax().cloned()), + hir::GenericDef::Static(it) => it.source(db).map(|src| src.syntax().cloned()), + }, }; return match def { Some(def) => SearchScope::file_range( diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_drop.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_drop.rs index e5e4c899ec03..3af529e8c56d 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_drop.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_drop.rs @@ -7,7 +7,7 @@ //! ``` use hir::{ DefWithBody, - db::{DefDatabase as _, HirDatabase as _}, + db::HirDatabase as _, mir::{MirSpan, TerminatorKind}, }; use ide_db::{FileRange, famous_defs::FamousDefs}; @@ -35,7 +35,7 @@ pub(super) fn hints( let def: DefWithBody = def.into(); let def = def.try_into().ok()?; - let (hir, source_map) = sema.db.body_with_source_map(def); + let (hir, source_map) = hir::Body::with_source_map(sema.db, def); let mir = sema.db.mir_body(def).ok()?; diff --git a/src/tools/rust-analyzer/crates/ide/src/rename.rs b/src/tools/rust-analyzer/crates/ide/src/rename.rs index ae19e7750968..900a885a64de 100644 --- a/src/tools/rust-analyzer/crates/ide/src/rename.rs +++ b/src/tools/rust-analyzer/crates/ide/src/rename.rs @@ -480,7 +480,7 @@ fn rename_to_self( } let fn_def = match local.parent(sema.db) { - hir::DefWithBody::Function(func) => func, + hir::ExpressionStoreOwner::Body(hir::DefWithBody::Function(func)) => func, _ => bail!("Cannot rename local to self outside of function"), }; @@ -743,7 +743,7 @@ fn rename_self_to_param( } let fn_def = match local.parent(sema.db) { - hir::DefWithBody::Function(func) => func, + hir::ExpressionStoreOwner::Body(hir::DefWithBody::Function(func)) => func, _ => bail!("Cannot rename local to self outside of function"), }; 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 3ee379765461..43e73175c820 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 @@ -16,8 +16,8 @@ next_solver::{DbInterner, GenericArgs}, }; use hir_def::{ - SyntheticSyntax, - expr_store::BodySourceMap, + DefWithBodyId, ExpressionStoreOwnerId, GenericDefId, SyntheticSyntax, + expr_store::{Body, BodySourceMap, ExpressionStore}, hir::{ExprId, PatId}, }; use hir_ty::InferenceResult; @@ -406,7 +406,7 @@ fn run_data_layout(&self, db: &RootDatabase, adts: &[hir::Adt], verbosity: Verbo hir_def::AdtId::from(a), GenericArgs::empty(interner).store(), hir_ty::ParamEnvAndCrate { - param_env: db.trait_environment(a.into()), + param_env: db.trait_environment(GenericDefId::from(a).into()), krate: a.krate(db).into(), } .store(), @@ -778,21 +778,24 @@ fn run_inference( if self.parallel { let mut inference_sw = self.stop_watch(); - let bodies = bodies.iter().filter_map(|&body| body.try_into().ok()).collect::>(); + let bodies = bodies + .iter() + .filter_map(|&body| body.try_into().ok()) + .collect::>(); bodies .par_iter() .map_with(db.clone(), |snap, &body| { - InferenceResult::for_body(snap, body); + InferenceResult::of(snap, body); }) .count(); let signatures = signatures .iter() .filter_map(|&signatures| signatures.try_into().ok()) - .collect::>(); + .collect::>(); signatures .par_iter() .map_with(db.clone(), |snap, &signatures| { - InferenceResult::for_signature(snap, signatures); + InferenceResult::of(snap, signatures); }) .count(); eprintln!("{:<20} {}", "Parallel Inference:", inference_sw.elapsed()); @@ -849,9 +852,9 @@ fn run_inference( bar.println(msg()); } bar.set_message(msg); - let body = db.body(body_def_id); + let body = Body::of(db, body_def_id); let inference_result = - catch_unwind(AssertUnwindSafe(|| InferenceResult::for_body(db, body_def_id))); + catch_unwind(AssertUnwindSafe(|| InferenceResult::of(db, body_def_id))); let inference_result = match inference_result { Ok(inference_result) => inference_result, Err(p) => { @@ -879,7 +882,7 @@ fn run_inference( } }; // This query is LRU'd, so actually calling it will skew the timing results. - let sm = || db.body_with_source_map(body_def_id).1; + let sm = || &Body::with_source_map(db, body_def_id).1; // region:expressions let (previous_exprs, previous_unknown, previous_partially_unknown) = @@ -890,7 +893,7 @@ fn run_inference( let unknown_or_partial = if ty.is_ty_error() { num_exprs_unknown += 1; if verbosity.is_spammy() { - if let Some((path, start, end)) = expr_syntax_range(db, vfs, &sm(), expr_id) + if let Some((path, start, end)) = expr_syntax_range(db, vfs, sm(), expr_id) { bar.println(format!( "{} {}:{}-{}:{}: Unknown type", @@ -917,7 +920,7 @@ fn run_inference( }; if self.only.is_some() && verbosity.is_spammy() { // in super-verbose mode for just one function, we print every single expression - if let Some((_, start, end)) = expr_syntax_range(db, vfs, &sm(), expr_id) { + if let Some((_, start, end)) = expr_syntax_range(db, vfs, sm(), expr_id) { bar.println(format!( "{}:{}-{}:{}: {}", start.line + 1, @@ -936,14 +939,14 @@ fn run_inference( if unknown_or_partial && self.output == Some(OutputFormat::Csv) { println!( r#"{},type,"{}""#, - location_csv_expr(db, vfs, &sm(), expr_id), + location_csv_expr(db, vfs, sm(), expr_id), ty.display(db, display_target) ); } if let Some(mismatch) = inference_result.type_mismatch_for_expr(expr_id) { num_expr_type_mismatches += 1; if verbosity.is_verbose() { - if let Some((path, start, end)) = expr_syntax_range(db, vfs, &sm(), expr_id) + if let Some((path, start, end)) = expr_syntax_range(db, vfs, sm(), expr_id) { bar.println(format!( "{} {}:{}-{}:{}: Expected {}, got {}", @@ -967,7 +970,7 @@ fn run_inference( if self.output == Some(OutputFormat::Csv) { println!( r#"{},mismatch,"{}","{}""#, - location_csv_expr(db, vfs, &sm(), expr_id), + location_csv_expr(db, vfs, sm(), expr_id), mismatch.expected.as_ref().display(db, display_target), mismatch.actual.as_ref().display(db, display_target) ); @@ -994,7 +997,7 @@ fn run_inference( let unknown_or_partial = if ty.is_ty_error() { num_pats_unknown += 1; if verbosity.is_spammy() { - if let Some((path, start, end)) = pat_syntax_range(db, vfs, &sm(), pat_id) { + if let Some((path, start, end)) = pat_syntax_range(db, vfs, sm(), pat_id) { bar.println(format!( "{} {}:{}-{}:{}: Unknown type", path, @@ -1020,7 +1023,7 @@ fn run_inference( }; if self.only.is_some() && verbosity.is_spammy() { // in super-verbose mode for just one function, we print every single pattern - if let Some((_, start, end)) = pat_syntax_range(db, vfs, &sm(), pat_id) { + if let Some((_, start, end)) = pat_syntax_range(db, vfs, sm(), pat_id) { bar.println(format!( "{}:{}-{}:{}: {}", start.line + 1, @@ -1039,14 +1042,14 @@ fn run_inference( if unknown_or_partial && self.output == Some(OutputFormat::Csv) { println!( r#"{},type,"{}""#, - location_csv_pat(db, vfs, &sm(), pat_id), + location_csv_pat(db, vfs, sm(), pat_id), ty.display(db, display_target) ); } if let Some(mismatch) = inference_result.type_mismatch_for_pat(pat_id) { num_pat_type_mismatches += 1; if verbosity.is_verbose() { - if let Some((path, start, end)) = pat_syntax_range(db, vfs, &sm(), pat_id) { + if let Some((path, start, end)) = pat_syntax_range(db, vfs, sm(), pat_id) { bar.println(format!( "{} {}:{}-{}:{}: Expected {}, got {}", path, @@ -1069,7 +1072,7 @@ fn run_inference( if self.output == Some(OutputFormat::Csv) { println!( r#"{},mismatch,"{}","{}""#, - location_csv_pat(db, vfs, &sm(), pat_id), + location_csv_pat(db, vfs, sm(), pat_id), mismatch.expected.as_ref().display(db, display_target), mismatch.actual.as_ref().display(db, display_target) ); @@ -1174,7 +1177,7 @@ fn run_body_lowering( bar.println(msg()); } bar.set_message(msg); - db.generic_params_and_store(signature_id); + ExpressionStore::of(db, ExpressionStoreOwnerId::Signature(signature_id)); bar.inc(1); } @@ -1213,7 +1216,7 @@ fn run_body_lowering( bar.println(msg()); } bar.set_message(msg); - db.body(body_def_id); + Body::of(db, body_def_id); bar.inc(1); } From a9966ba4cd694f2e79a284a2c1e54a95de7843f5 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sat, 28 Mar 2026 14:05:14 +0100 Subject: [PATCH 49/56] Remove `Arc` from `GenericParams` --- .../rust-analyzer/crates/hir-def/src/attrs.rs | 2 +- .../rust-analyzer/crates/hir-def/src/db.rs | 13 +-- .../crates/hir-def/src/expr_store/lower.rs | 18 ++-- .../hir-def/src/expr_store/lower/generics.rs | 23 +---- .../crates/hir-def/src/expr_store/pretty.rs | 4 +- .../crates/hir-def/src/expr_store/scope.rs | 2 +- .../crates/hir-def/src/hir/generics.rs | 84 +++++++++---------- .../crates/hir-def/src/resolver.rs | 13 ++- .../crates/hir-def/src/signatures.rs | 18 ++-- .../rust-analyzer/crates/hir-def/src/src.rs | 6 +- .../crates/hir-ty/src/builtin_derive.rs | 6 +- .../crates/hir-ty/src/display.rs | 6 +- .../crates/hir-ty/src/dyn_compatibility.rs | 6 +- .../crates/hir-ty/src/generics.rs | 5 +- .../rust-analyzer/crates/hir-ty/src/lower.rs | 2 +- .../crates/hir-ty/src/method_resolution.rs | 6 +- .../hir-ty/src/method_resolution/probe.rs | 3 +- .../crates/hir-ty/src/mir/lower.rs | 8 +- .../crates/hir-ty/src/next_solver/generics.rs | 2 +- .../crates/hir-ty/src/next_solver/ty.rs | 4 +- .../crates/hir-ty/src/representability.rs | 4 +- .../rust-analyzer/crates/hir/src/attrs.rs | 3 +- .../rust-analyzer/crates/hir/src/display.rs | 16 ++-- src/tools/rust-analyzer/crates/hir/src/lib.rs | 32 +++---- .../crates/hir/src/source_analyzer.rs | 5 +- .../rust-analyzer/src/cli/analysis_stats.rs | 4 +- 26 files changed, 134 insertions(+), 161 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/attrs.rs b/src/tools/rust-analyzer/crates/hir-def/src/attrs.rs index 0b8f65687218..e3e1aac7090a 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/attrs.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/attrs.rs @@ -894,7 +894,7 @@ pub fn query_generic_params( def: GenericDefId, ) -> &(ArenaMap, ArenaMap) { - let generic_params = GenericParams::new(db, def); + let generic_params = GenericParams::of(db, def); let params_count_excluding_self = generic_params.len() - usize::from(generic_params.trait_self_param().is_some()); if params_count_excluding_self == 0 { diff --git a/src/tools/rust-analyzer/crates/hir-def/src/db.rs b/src/tools/rust-analyzer/crates/hir-def/src/db.rs index 9c7f4943db97..0451523390e3 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/db.rs @@ -10,12 +10,11 @@ use crate::{ AnonConstId, AnonConstLoc, AssocItemId, AttrDefId, BlockId, BlockLoc, ConstId, ConstLoc, EnumId, EnumLoc, EnumVariantId, EnumVariantLoc, ExternBlockId, ExternBlockLoc, ExternCrateId, - ExternCrateLoc, FunctionId, FunctionLoc, GenericDefId, ImplId, ImplLoc, LocalFieldId, Macro2Id, - Macro2Loc, MacroExpander, MacroId, MacroRulesId, MacroRulesLoc, MacroRulesLocFlags, - ProcMacroId, ProcMacroLoc, StaticId, StaticLoc, StructId, StructLoc, TraitId, TraitLoc, - TypeAliasId, TypeAliasLoc, UnionId, UnionLoc, UseId, UseLoc, VariantId, + ExternCrateLoc, FunctionId, FunctionLoc, ImplId, ImplLoc, LocalFieldId, Macro2Id, Macro2Loc, + MacroExpander, MacroId, MacroRulesId, MacroRulesLoc, MacroRulesLocFlags, ProcMacroId, + ProcMacroLoc, StaticId, StaticLoc, StructId, StructLoc, TraitId, TraitLoc, TypeAliasId, + TypeAliasLoc, UnionId, UnionLoc, UseId, UseLoc, VariantId, attrs::AttrFlags, - hir::generics::GenericParams, import_map::ImportMap, item_tree::{ItemTree, file_item_tree_query}, nameres::crate_def_map, @@ -98,10 +97,6 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + SourceDatabase { #[salsa::invoke(macro_def)] fn macro_def(&self, m: MacroId) -> MacroDefId; - #[salsa::transparent] - #[salsa::invoke(GenericParams::new)] - fn generic_params(&self, def: GenericDefId) -> Arc; - #[salsa::invoke(ImportMap::import_map_query)] fn import_map(&self, krate: Crate) -> Arc; 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 3ed1b587411c..de1f7463afbe 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 @@ -28,7 +28,6 @@ }, }; use thin_vec::ThinVec; -use triomphe::Arc; use tt::TextRange; use crate::{ @@ -201,7 +200,7 @@ pub(crate) fn lower_generic_params( file_id: HirFileId, param_list: Option, where_clause: Option, -) -> (ExpressionStore, Arc, ExpressionStoreSourceMap) { +) -> (ExpressionStore, GenericParams, ExpressionStoreSourceMap) { let mut expr_collector = ExprCollector::signature(db, module, file_id); let mut collector = generics::GenericParamsCollector::new(def); collector.lower(&mut expr_collector, param_list, where_clause); @@ -215,7 +214,7 @@ pub(crate) fn lower_impl( module: ModuleId, impl_syntax: InFile, impl_id: ImplId, -) -> (ExpressionStore, ExpressionStoreSourceMap, TypeRefId, Option, Arc) { +) -> (ExpressionStore, ExpressionStoreSourceMap, TypeRefId, Option, GenericParams) { let mut expr_collector = ExprCollector::signature(db, module, impl_syntax.file_id); let self_ty = expr_collector.lower_type_ref_opt_disallow_impl_trait(impl_syntax.value.self_ty()); @@ -243,7 +242,7 @@ pub(crate) fn lower_trait( module: ModuleId, trait_syntax: InFile, trait_id: TraitId, -) -> (ExpressionStore, ExpressionStoreSourceMap, Arc) { +) -> (ExpressionStore, ExpressionStoreSourceMap, GenericParams) { let mut expr_collector = ExprCollector::signature(db, module, trait_syntax.file_id); let mut collector = generics::GenericParamsCollector::with_self_param( &mut expr_collector, @@ -265,13 +264,8 @@ pub(crate) fn lower_type_alias( module: ModuleId, alias: InFile, type_alias_id: TypeAliasId, -) -> ( - ExpressionStore, - ExpressionStoreSourceMap, - Arc, - Box<[TypeBound]>, - Option, -) { +) -> (ExpressionStore, ExpressionStoreSourceMap, GenericParams, Box<[TypeBound]>, Option) +{ let mut expr_collector = ExprCollector::signature(db, module, alias.file_id); let bounds = alias .value @@ -308,7 +302,7 @@ pub(crate) fn lower_function( ) -> ( ExpressionStore, ExpressionStoreSourceMap, - Arc, + GenericParams, Box<[TypeRefId]>, Option, bool, 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 03de7937bad3..7c7b6971647e 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 @@ -3,15 +3,12 @@ //! generic parameters. See also the `Generics` type and the `generics_of` query //! in rustc. -use std::sync::LazyLock; - use either::Either; use hir_expand::name::{AsName, Name}; use intern::sym; use la_arena::Arena; use syntax::ast::{self, HasName, HasTypeBounds}; use thin_vec::ThinVec; -use triomphe::Arc; use crate::{ GenericDefId, TypeOrConstParamId, TypeParamId, @@ -84,28 +81,16 @@ pub(crate) fn collect_impl_trait( ) } - pub(crate) fn finish(self) -> Arc { - let Self { mut lifetimes, mut type_or_consts, mut where_predicates, parent: _ } = self; - - if lifetimes.is_empty() && type_or_consts.is_empty() && where_predicates.is_empty() { - static EMPTY: LazyLock> = LazyLock::new(|| { - Arc::new(GenericParams { - lifetimes: Arena::new(), - type_or_consts: Arena::new(), - where_predicates: Box::default(), - }) - }); - return Arc::clone(&EMPTY); - } + pub(crate) fn finish(self) -> GenericParams { + let Self { mut lifetimes, mut type_or_consts, where_predicates, parent: _ } = self; lifetimes.shrink_to_fit(); type_or_consts.shrink_to_fit(); - where_predicates.shrink_to_fit(); - Arc::new(GenericParams { + GenericParams { type_or_consts, lifetimes, where_predicates: where_predicates.into_boxed_slice(), - }) + } } fn lower_param_list(&mut self, ec: &mut ExprCollector<'_>, params: ast::GenericParamList) { 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 405ebe9b7bc9..39e0153ded37 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 @@ -1212,7 +1212,7 @@ pub(crate) fn print_generic_arg(&mut self, arg: &GenericArg) { } pub(crate) fn print_type_param(&mut self, param: TypeParamId) { - let generic_params = self.db.generic_params(param.parent()); + let generic_params = GenericParams::of(self.db, param.parent()); match generic_params[param.local_id()].name() { Some(name) => w!(self, "{}", name.display(self.db, self.edition)), @@ -1221,7 +1221,7 @@ pub(crate) fn print_type_param(&mut self, param: TypeParamId) { } pub(crate) fn print_lifetime_param(&mut self, param: LifetimeParamId) { - let generic_params = self.db.generic_params(param.parent); + let generic_params = GenericParams::of(self.db, param.parent); w!(self, "{}", generic_params[param.local_id].name.display(self.db, self.edition)) } 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 2250cf5f1638..22a3a7b07900 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 @@ -64,7 +64,7 @@ pub fn body_expr_scopes(db: &dyn DefDatabase, def: DefWithBodyId) -> ExprScopes #[salsa::tracked(returns(ref))] pub fn sig_expr_scopes(db: &dyn DefDatabase, def: GenericDefId) -> ExprScopes { - let (_, store) = GenericParams::of(db, def); + let (_, store) = GenericParams::with_store(db, def); let roots = store.signature_const_expr_roots(); let mut scopes = ExprScopes::new_store(store, roots); scopes.shrink_to_fit(); 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 41767131fc3b..43dd7d1c54cd 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 @@ -5,7 +5,6 @@ use la_arena::{Arena, Idx, RawIdx}; use stdx::impl_from; use thin_vec::ThinVec; -use triomphe::Arc; use crate::{ AdtId, ConstParamId, GenericDefId, LifetimeParamId, TypeOrConstParamId, TypeParamId, @@ -146,7 +145,7 @@ pub enum GenericParamDataRef<'a> { } /// Data about the generic parameters of a function, struct, impl, etc. -#[derive(Clone, PartialEq, Eq, Debug, Hash)] +#[derive(PartialEq, Eq, Debug, Hash, Default)] pub struct GenericParams { pub(crate) type_or_consts: Arena, pub(crate) lifetimes: Arena, @@ -178,12 +177,10 @@ pub enum WherePredicate { ForLifetime { lifetimes: ThinVec, target: TypeRefId, bound: TypeBound }, } -static EMPTY: LazyLock> = LazyLock::new(|| { - Arc::new(GenericParams { - type_or_consts: Arena::default(), - lifetimes: Arena::default(), - where_predicates: Box::default(), - }) +static EMPTY: LazyLock = LazyLock::new(|| GenericParams { + type_or_consts: Arena::default(), + lifetimes: Arena::default(), + where_predicates: Box::default(), }); impl GenericParams { @@ -191,47 +188,50 @@ impl GenericParams { pub const SELF_PARAM_ID_IN_SELF: la_arena::Idx = LocalTypeOrConstParamId::from_raw(RawIdx::from_u32(0)); - pub fn new(db: &dyn DefDatabase, def: GenericDefId) -> Arc { - Self::of(db, def).0 + pub fn of(db: &dyn DefDatabase, def: GenericDefId) -> &GenericParams { + Self::with_store(db, def).0 } - pub fn of(db: &dyn DefDatabase, def: GenericDefId) -> (Arc, &ExpressionStore) { + pub fn with_store( + db: &dyn DefDatabase, + def: GenericDefId, + ) -> (&GenericParams, &ExpressionStore) { match def { GenericDefId::AdtId(AdtId::EnumId(id)) => { let sig = EnumSignature::of(db, id); - (sig.generic_params.clone(), &sig.store) + (&sig.generic_params, &sig.store) } GenericDefId::AdtId(AdtId::StructId(id)) => { let sig = StructSignature::of(db, id); - (sig.generic_params.clone(), &sig.store) + (&sig.generic_params, &sig.store) } GenericDefId::AdtId(AdtId::UnionId(id)) => { let sig = UnionSignature::of(db, id); - (sig.generic_params.clone(), &sig.store) - } - GenericDefId::FunctionId(id) => { - let sig = FunctionSignature::of(db, id); - (sig.generic_params.clone(), &sig.store) - } - GenericDefId::ImplId(id) => { - let sig = ImplSignature::of(db, id); - (sig.generic_params.clone(), &sig.store) - } - GenericDefId::TraitId(id) => { - let sig = TraitSignature::of(db, id); - (sig.generic_params.clone(), &sig.store) - } - GenericDefId::TypeAliasId(id) => { - let sig = TypeAliasSignature::of(db, id); - (sig.generic_params.clone(), &sig.store) + (&sig.generic_params, &sig.store) } GenericDefId::ConstId(id) => { let sig = ConstSignature::of(db, id); - (EMPTY.clone(), &sig.store) + (&EMPTY, &sig.store) + } + GenericDefId::FunctionId(id) => { + let sig = FunctionSignature::of(db, id); + (&sig.generic_params, &sig.store) + } + GenericDefId::ImplId(id) => { + let sig = ImplSignature::of(db, id); + (&sig.generic_params, &sig.store) } GenericDefId::StaticId(id) => { let sig = StaticSignature::of(db, id); - (EMPTY.clone(), &sig.store) + (&EMPTY, &sig.store) + } + GenericDefId::TraitId(id) => { + let sig = TraitSignature::of(db, id); + (&sig.generic_params, &sig.store) + } + GenericDefId::TypeAliasId(id) => { + let sig = TypeAliasSignature::of(db, id); + (&sig.generic_params, &sig.store) } } } @@ -239,43 +239,43 @@ pub fn of(db: &dyn DefDatabase, def: GenericDefId) -> (Arc, &Expr pub fn with_source_map( db: &dyn DefDatabase, def: GenericDefId, - ) -> (Arc, &ExpressionStore, &ExpressionStoreSourceMap) { + ) -> (&GenericParams, &ExpressionStore, &ExpressionStoreSourceMap) { match def { GenericDefId::AdtId(AdtId::EnumId(id)) => { let (sig, sm) = EnumSignature::with_source_map(db, id); - (sig.generic_params.clone(), &sig.store, sm) + (&sig.generic_params, &sig.store, sm) } GenericDefId::AdtId(AdtId::StructId(id)) => { let (sig, sm) = StructSignature::with_source_map(db, id); - (sig.generic_params.clone(), &sig.store, sm) + (&sig.generic_params, &sig.store, sm) } GenericDefId::AdtId(AdtId::UnionId(id)) => { let (sig, sm) = UnionSignature::with_source_map(db, id); - (sig.generic_params.clone(), &sig.store, sm) + (&sig.generic_params, &sig.store, sm) } GenericDefId::ConstId(id) => { let (sig, sm) = ConstSignature::with_source_map(db, id); - (EMPTY.clone(), &sig.store, sm) + (&EMPTY, &sig.store, sm) } GenericDefId::FunctionId(id) => { let (sig, sm) = FunctionSignature::with_source_map(db, id); - (sig.generic_params.clone(), &sig.store, sm) + (&sig.generic_params, &sig.store, sm) } GenericDefId::ImplId(id) => { let (sig, sm) = ImplSignature::with_source_map(db, id); - (sig.generic_params.clone(), &sig.store, sm) + (&sig.generic_params, &sig.store, sm) } GenericDefId::StaticId(id) => { let (sig, sm) = StaticSignature::with_source_map(db, id); - (EMPTY.clone(), &sig.store, sm) + (&EMPTY, &sig.store, sm) } GenericDefId::TraitId(id) => { let (sig, sm) = TraitSignature::with_source_map(db, id); - (sig.generic_params.clone(), &sig.store, sm) + (&sig.generic_params, &sig.store, sm) } GenericDefId::TypeAliasId(id) => { let (sig, sm) = TypeAliasSignature::with_source_map(db, id); - (sig.generic_params.clone(), &sig.store, sm) + (&sig.generic_params, &sig.store, sm) } } } 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 9ffa80346c2f..1a0e6a46f174 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs @@ -13,7 +13,6 @@ use smallvec::{SmallVec, smallvec}; use span::SyntaxContext; use syntax::ast::HasName; -use triomphe::Arc; use crate::{ AdtId, AstIdLoc, ConstId, ConstParamId, DefWithBodyId, EnumId, EnumVariantId, @@ -87,7 +86,7 @@ enum Scope<'db> { BlockScope(ModuleItemMap<'db>), /// Brings the generic parameters of an item into scope as well as the `Self` type alias / /// generic for ADTs and impls. - GenericParams { def: GenericDefId, params: Arc }, + GenericParams { def: GenericDefId, params: &'db GenericParams }, /// Local bindings ExprScope(ExprScope<'db>), /// Macro definition inside bodies that affects all paths after it in the same block. @@ -725,14 +724,14 @@ pub fn generic_def(&self) -> Option { pub fn generic_params(&self) -> Option<&GenericParams> { self.scopes().find_map(|scope| match scope { - Scope::GenericParams { params, .. } => Some(&**params), + &Scope::GenericParams { params, .. } => Some(params), _ => None, }) } - pub fn all_generic_params(&self) -> impl Iterator { + pub fn all_generic_params(&self) -> impl Iterator { self.scopes().filter_map(|scope| match scope { - Scope::GenericParams { params, def } => Some((&**params, def)), + &Scope::GenericParams { params, def } => Some((params, def)), _ => None, }) } @@ -1031,7 +1030,7 @@ fn process_names(&self, acc: &mut ScopeNames, db: &'db dyn DefDatabase) { for (local_id, param) in params.iter_type_or_consts() { if let Some(name) = ¶m.name() { let id = TypeOrConstParamId { parent, local_id }; - let data = &db.generic_params(parent)[local_id]; + let data = &GenericParams::of(db, parent)[local_id]; acc.add( name, ScopeDef::GenericParam(match data { @@ -1115,7 +1114,7 @@ fn push_generic_params_scope( db: &'db dyn DefDatabase, def: GenericDefId, ) -> Resolver<'db> { - let params = db.generic_params(def); + let params = GenericParams::of(db, def); self.push_scope(Scope::GenericParams { def, params }) } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/signatures.rs b/src/tools/rust-analyzer/crates/hir-def/src/signatures.rs index 7862049f993e..c16ca6d0b432 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/signatures.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/signatures.rs @@ -43,7 +43,7 @@ fn as_name_opt(name: Option) -> Name { #[derive(Debug, PartialEq, Eq)] pub struct StructSignature { pub name: Name, - pub generic_params: Arc, + pub generic_params: GenericParams, pub store: ExpressionStore, pub flags: StructFlags, pub shape: FieldsShape, @@ -153,7 +153,7 @@ fn adt_shape(adt_kind: ast::StructKind) -> FieldsShape { #[derive(Debug, PartialEq, Eq)] pub struct UnionSignature { pub name: Name, - pub generic_params: Arc, + pub generic_params: GenericParams, pub store: ExpressionStore, pub flags: StructFlags, } @@ -217,7 +217,7 @@ pub struct EnumFlags: u8 { #[derive(Debug, PartialEq, Eq)] pub struct EnumSignature { pub name: Name, - pub generic_params: Arc, + pub generic_params: GenericParams, pub store: ExpressionStore, pub flags: EnumFlags, } @@ -290,7 +290,7 @@ pub struct ConstFlags: u8 { #[derive(Debug, PartialEq, Eq)] pub struct ConstSignature { pub name: Option, - // generic_params: Arc, + // generic_params: GenericParams, pub store: ExpressionStore, pub type_ref: TypeRefId, pub flags: ConstFlags, @@ -358,7 +358,7 @@ pub struct StaticFlags: u8 { pub struct StaticSignature { pub name: Name, - // generic_params: Arc, + // generic_params: GenericParams, pub store: ExpressionStore, pub type_ref: TypeRefId, pub flags: StaticFlags, @@ -429,7 +429,7 @@ pub struct ImplFlags: u8 { #[derive(Debug, PartialEq, Eq)] pub struct ImplSignature { - pub generic_params: Arc, + pub generic_params: GenericParams, pub store: ExpressionStore, pub self_ty: TypeRefId, pub target_trait: Option, @@ -502,7 +502,7 @@ pub struct TraitFlags: u16 { #[derive(Debug, PartialEq, Eq)] pub struct TraitSignature { pub name: Name, - pub generic_params: Arc, + pub generic_params: GenericParams, pub store: ExpressionStore, pub flags: TraitFlags, } @@ -586,7 +586,7 @@ pub struct FnFlags: u16 { #[derive(Debug, PartialEq, Eq)] pub struct FunctionSignature { pub name: Name, - pub generic_params: Arc, + pub generic_params: GenericParams, pub store: ExpressionStore, pub params: Box<[TypeRefId]>, pub ret_type: Option, @@ -762,7 +762,7 @@ pub struct TypeAliasFlags: u8 { #[derive(Debug, PartialEq, Eq)] pub struct TypeAliasSignature { pub name: Name, - pub generic_params: Arc, + pub generic_params: GenericParams, pub store: ExpressionStore, pub bounds: Box<[TypeBound]>, pub ty: Option, diff --git a/src/tools/rust-analyzer/crates/hir-def/src/src.rs b/src/tools/rust-analyzer/crates/hir-def/src/src.rs index 6fe016f1e680..e33fd95908b9 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/src.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/src.rs @@ -7,7 +7,7 @@ use crate::{ AstIdLoc, GenericDefId, LocalFieldId, LocalLifetimeParamId, LocalTypeOrConstParamId, Lookup, - UseId, VariantId, attrs::AttrFlags, db::DefDatabase, + UseId, VariantId, attrs::AttrFlags, db::DefDatabase, hir::generics::GenericParams, }; pub trait HasSource { @@ -76,7 +76,7 @@ fn child_source( &self, db: &dyn DefDatabase, ) -> InFile> { - let generic_params = db.generic_params(*self); + let generic_params = GenericParams::of(db, *self); let mut idx_iter = generic_params.iter_type_or_consts().map(|(idx, _)| idx); let (file_id, generic_params_list) = self.file_id_and_params_of(db); @@ -110,7 +110,7 @@ fn child_source( &self, db: &dyn DefDatabase, ) -> InFile> { - let generic_params = db.generic_params(*self); + let generic_params = GenericParams::of(db, *self); let idx_iter = generic_params.iter_lt().map(|(idx, _)| idx); let (file_id, generic_params_list) = self.file_id_and_params_of(db); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/builtin_derive.rs b/src/tools/rust-analyzer/crates/hir-ty/src/builtin_derive.rs index 5a93c2b53606..6cdc07e430b6 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/builtin_derive.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/builtin_derive.rs @@ -80,7 +80,7 @@ pub(crate) fn generics_of<'db>(interner: DbInterner<'db>, id: BuiltinDeriveImplI pub fn generic_params_count(db: &dyn HirDatabase, id: BuiltinDeriveImplId) -> usize { let loc = id.loc(db); - let adt_params = GenericParams::new(db, loc.adt.into()); + let adt_params = GenericParams::of(db, loc.adt.into()); let extra_params_count = match loc.trait_ { BuiltinDeriveImplTrait::Copy | BuiltinDeriveImplTrait::Clone @@ -128,7 +128,7 @@ pub fn impl_trait<'db>( )) } BuiltinDeriveImplTrait::CoerceUnsized | BuiltinDeriveImplTrait::DispatchFromDyn => { - let generic_params = GenericParams::new(db, loc.adt.into()); + let generic_params = GenericParams::of(db, loc.adt.into()); let interner = DbInterner::new_no_crate(db); let args = GenericArgs::identity_for_item(interner, loc.adt.into()); let self_ty = Ty::new_adt(interner, loc.adt, args); @@ -152,7 +152,7 @@ pub fn impl_trait<'db>( #[salsa::tracked(returns(ref))] pub fn predicates<'db>(db: &'db dyn HirDatabase, impl_: BuiltinDeriveImplId) -> GenericPredicates { let loc = impl_.loc(db); - let generic_params = GenericParams::new(db, loc.adt.into()); + let generic_params = GenericParams::of(db, loc.adt.into()); let interner = DbInterner::new_with(db, loc.module(db).krate(db)); let adt_predicates = GenericPredicates::query(db, loc.adt.into()); let trait_id = loc 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 54cd750de6c8..d68058864564 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs @@ -14,7 +14,7 @@ Lookup, ModuleDefId, ModuleId, TraitId, expr_store::{ExpressionStore, path::Path}, find_path::{self, PrefixKind}, - hir::generics::{TypeOrConstParamData, TypeParamProvenance, WherePredicate}, + hir::generics::{GenericParams, TypeOrConstParamData, TypeParamProvenance, WherePredicate}, item_scope::ItemInNs, item_tree::FieldsShape, lang_item::LangItems, @@ -2141,7 +2141,7 @@ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>, store: &ExpressionStore) -> Res LifetimeRef::Placeholder => write!(f, "'_"), LifetimeRef::Error => write!(f, "'{{error}}"), &LifetimeRef::Param(lifetime_param_id) => { - let generic_params = f.db.generic_params(lifetime_param_id.parent); + let generic_params = GenericParams::of(f.db, lifetime_param_id.parent); write!( f, "{}", @@ -2157,7 +2157,7 @@ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>, store: &ExpressionStore) -> Res match &store[*self] { TypeRef::Never => write!(f, "!")?, TypeRef::TypeParam(param) => { - let generic_params = f.db.generic_params(param.parent()); + let generic_params = GenericParams::of(f.db, param.parent()); match generic_params[param.local_id()].name() { Some(name) => write!(f, "{}", name.display(f.db, f.edition()))?, None => { 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 d8093b3eb1c8..4c300affd8a2 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 @@ -5,7 +5,7 @@ use hir_def::{ AssocItemId, ConstId, FunctionId, GenericDefId, HasModule, TraitId, TypeAliasId, TypeOrConstParamId, TypeParamId, - hir::generics::LocalTypeOrConstParamId, + hir::generics::{GenericParams, LocalTypeOrConstParamId}, nameres::crate_def_map, signatures::{FunctionSignature, TraitFlags, TraitSignature}, }; @@ -300,7 +300,7 @@ fn dyn_compatibility_violation_for_assoc_item( if def_map.is_unstable_feature_enabled(&intern::sym::generic_associated_type_extended) { ControlFlow::Continue(()) } else { - let generic_params = db.generic_params(item.into()); + let generic_params = GenericParams::of(db, item.into()); if !generic_params.is_empty() { cb(DynCompatibilityViolation::GAT(it)) } else { @@ -351,7 +351,7 @@ fn virtual_call_violations_for_method( cb(mvc)?; } - let generic_params = db.generic_params(func.into()); + let generic_params = GenericParams::of(db, func.into()); if generic_params.len_type_or_consts() > 0 { cb(MethodViolationCode::Generic)?; } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs b/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs index 57fe4d749b2d..822942eec37d 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs @@ -20,18 +20,17 @@ }, }; use itertools::chain; -use triomphe::Arc; pub fn generics(db: &dyn DefDatabase, def: GenericDefId) -> Generics<'_> { let parent_generics = parent_generic_def(db, def).map(|def| Box::new(generics(db, def))); - let (params, store) = GenericParams::of(db, def); + let (params, store) = GenericParams::with_store(db, def); let has_trait_self_param = params.trait_self_param().is_some(); Generics { def, params, parent_generics, has_trait_self_param, store } } #[derive(Clone, Debug)] pub struct Generics<'db> { def: GenericDefId, - params: Arc, + params: &'db GenericParams, store: &'db ExpressionStore, parent_generics: Option>>, has_trait_self_param: bool, 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 3ed563315e5e..5eee025f2c00 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs @@ -1590,7 +1590,7 @@ pub(crate) fn const_param_ty_with_diagnostics_query<'db>( _: (), def: ConstParamId, ) -> (StoredTy, Diagnostics) { - let (parent_data, store) = GenericParams::of(db, def.parent()); + let (parent_data, store) = GenericParams::with_store(db, def.parent()); let data = &parent_data[def.local_id()]; let resolver = def.parent().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 e058a254205e..05b9ea5d748f 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 @@ -18,7 +18,7 @@ attrs::AttrFlags, builtin_derive::BuiltinDeriveImplMethod, expr_store::{Body, path::GenericArgs as HirGenericArgs}, - hir::ExprId, + hir::{ExprId, generics::GenericParams}, lang_item::LangItems, nameres::{DefMap, block_def_map, crate_def_map}, resolver::Resolver, @@ -397,7 +397,7 @@ pub fn is_dyn_method<'db>( let ItemContainerId::TraitId(trait_id) = func.loc(db).container else { return None; }; - let trait_params = db.generic_params(trait_id.into()).len(); + let trait_params = GenericParams::of(db, trait_id.into()).len(); let fn_params = fn_subst.len() - trait_params; let trait_ref = TraitRef::new_from_args( interner, @@ -433,7 +433,7 @@ pub(crate) fn lookup_impl_method_query<'db>( let ItemContainerId::TraitId(trait_id) = func.loc(db).container else { return (Either::Left(func), fn_subst); }; - let trait_params = db.generic_params(trait_id.into()).len(); + let trait_params = GenericParams::of(db, trait_id.into()).len(); let trait_ref = TraitRef::new_from_args( interner, trait_id.into(), 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 e2a53cc830e3..8c76bfbc076b 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 @@ -5,6 +5,7 @@ use hir_def::{ AssocItemId, FunctionId, GenericParamId, ImplId, ItemContainerId, TraitId, + hir::generics::GenericParams, signatures::{FunctionSignature, TraitFlags, TraitSignature}, }; use hir_expand::name::Name; @@ -2010,7 +2011,7 @@ fn xform_method_sig(&self, method: FunctionId, args: &[GenericArg<'db>]) -> FnSi // we are given do not include type/lifetime parameters for the // method yet. So create fresh variables here for those too, // if there are any. - let generics = self.db().generic_params(method.into()); + let generics = GenericParams::of(self.db(), method.into()); let xform_fn_sig = if generics.is_empty() { fn_sig.instantiate(self.interner(), args) 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 8d85e2412f3b..675fc371c619 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 @@ -9,7 +9,7 @@ expr_store::{Body, ExpressionStore, HygieneId, path::Path}, hir::{ ArithOp, Array, BinaryOp, BindingAnnotation, BindingId, ExprId, LabelId, Literal, MatchArm, - Pat, PatId, RecordFieldPat, RecordLitField, RecordSpread, + Pat, PatId, RecordFieldPat, RecordLitField, RecordSpread, generics::GenericParams, }, item_tree::FieldsShape, lang_item::LangItems, @@ -203,13 +203,13 @@ pub fn pretty_print( MirLowerError::GenericArgNotProvided(id, subst) => { let param_name = match *id { GenericParamId::TypeParamId(id) => { - db.generic_params(id.parent())[id.local_id()].name().cloned() + GenericParams::of(db, id.parent())[id.local_id()].name().cloned() } GenericParamId::ConstParamId(id) => { - db.generic_params(id.parent())[id.local_id()].name().cloned() + GenericParams::of(db, id.parent())[id.local_id()].name().cloned() } GenericParamId::LifetimeParamId(id) => { - Some(db.generic_params(id.parent)[id.local_id].name.clone()) + Some(GenericParams::of(db, id.parent)[id.local_id].name.clone()) } }; writeln!( 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 a8288b4e8259..f31de21796fe 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 @@ -55,7 +55,7 @@ pub(crate) fn generics(interner: DbInterner<'_>, def: SolverDefId) -> Generics { let (parent, own_params) = match (def.try_into(), def) { (Ok(def), _) => ( parent_generic_def(db, def), - own_params_for_generic_params(def, &db.generic_params(def)), + own_params_for_generic_params(def, GenericParams::of(db, def)), ), (_, SolverDefId::InternedOpaqueTyId(id)) => { match db.lookup_intern_impl_trait_id(id) { 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 09b1585866b0..192cdb70aee5 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 @@ -4,7 +4,7 @@ use hir_def::{ AdtId, HasModule, TypeParamId, - hir::generics::{TypeOrConstParamData, TypeParamProvenance}, + hir::generics::{GenericParams, TypeOrConstParamData, TypeParamProvenance}, }; use hir_def::{TraitId, type_ref::Rawness}; use intern::{Interned, InternedRef, impl_internable}; @@ -690,7 +690,7 @@ pub fn impl_trait_bounds(self, db: &'db dyn HirDatabase) -> Option { // FIXME: We shouldn't use `param.id` here. - let generic_params = db.generic_params(param.id.parent()); + let generic_params = GenericParams::of(db, param.id.parent()); let param_data = &generic_params[param.id.local_id()]; match param_data { TypeOrConstParamData::TypeParamData(p) => match p.provenance { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/representability.rs b/src/tools/rust-analyzer/crates/hir-ty/src/representability.rs index 7e40f2d7ac75..bae204c4ef7c 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/representability.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/representability.rs @@ -1,6 +1,6 @@ //! Detecting whether a type is infinitely-sized. -use hir_def::{AdtId, VariantId}; +use hir_def::{AdtId, VariantId, hir::generics::GenericParams}; use rustc_type_ir::inherent::{AdtDef, IntoKind}; use crate::{ @@ -88,7 +88,7 @@ fn representability_adt_ty<'db>( } fn params_in_repr(db: &dyn HirDatabase, def_id: AdtId) -> Box<[bool]> { - let generics = db.generic_params(def_id.into()); + let generics = GenericParams::of(db, def_id.into()); let mut params_in_repr = (0..generics.len_lifetimes() + generics.len_type_or_consts()) .map(|_| false) .collect::>(); diff --git a/src/tools/rust-analyzer/crates/hir/src/attrs.rs b/src/tools/rust-analyzer/crates/hir/src/attrs.rs index cfb95e07c362..4efb7fcb6f2b 100644 --- a/src/tools/rust-analyzer/crates/hir/src/attrs.rs +++ b/src/tools/rust-analyzer/crates/hir/src/attrs.rs @@ -7,6 +7,7 @@ TraitId, TypeOrConstParamId, attrs::{AttrFlags, Docs, IsInnerDoc}, expr_store::path::Path, + hir::generics::GenericParams, item_scope::ItemInNs, per_ns::Namespace, resolver::{HasResolver, Resolver, TypeNs}, @@ -377,7 +378,7 @@ fn resolve_assoc_or_field( let ty = match base_def { TypeNs::SelfType(id) => Impl::from(id).self_ty(db), TypeNs::GenericParam(param) => { - let generic_params = db.generic_params(param.parent()); + let generic_params = GenericParams::of(db, param.parent()); if generic_params[param.local_id()].is_trait_self() { // `Self::assoc` in traits should refer to the trait itself. let parent_trait = |container| match container { diff --git a/src/tools/rust-analyzer/crates/hir/src/display.rs b/src/tools/rust-analyzer/crates/hir/src/display.rs index 826b8d5f808c..aa34177b89a1 100644 --- a/src/tools/rust-analyzer/crates/hir/src/display.rs +++ b/src/tools/rust-analyzer/crates/hir/src/display.rs @@ -41,7 +41,7 @@ fn write_builtin_derive_impl_method<'db>( ) -> Result { let db = f.db; let loc = impl_.loc(db); - let (adt_params, _adt_params_store) = GenericParams::of(db, loc.adt.into()); + let adt_params = GenericParams::of(db, loc.adt.into()); if f.show_container_bounds() && !adt_params.is_empty() { f.write_str("impl")?; @@ -97,7 +97,7 @@ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result { // Write container (trait or impl) let container_params = match container { ItemContainerId::TraitId(trait_) => { - let (params, params_store) = GenericParams::of(f.db, trait_.into()); + let (params, params_store) = GenericParams::with_store(f.db, trait_.into()); if f.show_container_bounds() && !params.is_empty() { write_trait_header(trait_.into(), f)?; f.write_char('\n')?; @@ -108,7 +108,7 @@ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result { } } ItemContainerId::ImplId(impl_) => { - let (params, params_store) = GenericParams::of(f.db, impl_.into()); + let (params, params_store) = GenericParams::with_store(f.db, impl_.into()); if f.show_container_bounds() && !params.is_empty() { write_impl_header(impl_, f)?; f.write_char('\n')?; @@ -572,7 +572,7 @@ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result { impl<'db> HirDisplay<'db> for TypeParam { fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result { - let params = f.db.generic_params(self.id.parent()); + let params = GenericParams::of(f.db, self.id.parent()); let param_data = ¶ms[self.id.local_id()]; let krate = self.id.parent().krate(f.db).id; let ty = self.ty(f.db).ty; @@ -660,7 +660,7 @@ fn write_generic_params_or_args<'db>( f: &mut HirFormatter<'_, 'db>, include_defaults: bool, ) -> Result { - let (params, store) = GenericParams::of(f.db, def); + let (params, store) = GenericParams::with_store(f.db, def); if params.iter_lt().next().is_none() && params.iter_type_or_consts().all(|it| it.1.const_param().is_none()) && params @@ -718,7 +718,7 @@ fn write_generic_params_or_args<'db>( } fn write_where_clause<'db>(def: GenericDefId, f: &mut HirFormatter<'_, 'db>) -> Result { - let (params, store) = GenericParams::of(f.db, def); + let (params, store) = GenericParams::with_store(f.db, def); if !has_disaplayable_predicates(f.db, ¶ms, store) { return Ok(false); } @@ -739,7 +739,7 @@ fn has_disaplayable_predicates( pred, WherePredicate::TypeBound { target, .. } if matches!(store[*target], - TypeRef::TypeParam(id) if db.generic_params(id.parent())[id.local_id()].name().is_none() + TypeRef::TypeParam(id) if GenericParams::of(db,id.parent())[id.local_id()].name().is_none() ) ) }) @@ -755,7 +755,7 @@ fn write_where_predicates<'db>( // unnamed type targets are displayed inline with the argument itself, e.g. `f: impl Y`. let is_unnamed_type_target = |target: TypeRefId| { matches!(store[target], - TypeRef::TypeParam(id) if f.db.generic_params(id.parent())[id.local_id()].name().is_none() + TypeRef::TypeParam(id) if GenericParams::of(f.db,id.parent())[id.local_id()].name().is_none() ) }; diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index 4d4482b1afa3..67527150bd45 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -58,7 +58,7 @@ expr_store::{ExpressionStore, ExpressionStoreDiagnostics, ExpressionStoreSourceMap}, hir::{ BindingAnnotation, BindingId, Expr, ExprId, ExprOrPatId, LabelId, Pat, - generics::{LifetimeParamData, TypeOrConstParamData, TypeParamProvenance}, + generics::{GenericParams, LifetimeParamData, TypeOrConstParamData, TypeParamProvenance}, }, item_tree::ImportAlias, lang_item::LangItemTarget, @@ -3275,7 +3275,7 @@ pub fn type_or_const_param_count( db: &dyn HirDatabase, count_required_only: bool, ) -> usize { - db.generic_params(self.id.into()) + GenericParams::of(db,self.id.into()) .iter_type_or_consts() .filter(|(_, ty)| !matches!(ty, TypeOrConstParamData::TypeParamData(ty) if ty.provenance != TypeParamProvenance::TypeParamList)) .filter(|(_, ty)| !count_required_only || !ty.has_default()) @@ -4065,7 +4065,7 @@ pub fn params(self, db: &dyn HirDatabase) -> Vec { // Let's pretend builtin derive impls don't have generic parameters. return Vec::new(); }; - let generics = db.generic_params(id); + let generics = GenericParams::of(db, id); let ty_params = generics.iter_type_or_consts().map(|(local_id, _)| { let toc = TypeOrConstParam { id: TypeOrConstParamId { parent: id, local_id } }; match toc.split(db) { @@ -4085,7 +4085,7 @@ pub fn lifetime_params(self, db: &dyn HirDatabase) -> Vec { // Let's pretend builtin derive impls don't have generic parameters. return Vec::new(); }; - let generics = db.generic_params(id); + let generics = GenericParams::of(db, id); generics .iter_lt() .map(|(local_id, _)| LifetimeParam { id: LifetimeParamId { parent: id, local_id } }) @@ -4097,7 +4097,7 @@ pub fn type_or_const_params(self, db: &dyn HirDatabase) -> Vec // Let's pretend builtin derive impls don't have generic parameters. return Vec::new(); }; - let generics = db.generic_params(id); + let generics = GenericParams::of(db, id); generics .iter_type_or_consts() .map(|(local_id, _)| TypeOrConstParam { @@ -4127,7 +4127,7 @@ fn id(self) -> Option { pub fn diagnostics<'db>(self, db: &'db dyn HirDatabase, acc: &mut Vec>) { let Some(def) = self.id() else { return }; - let generics = db.generic_params(def); + let generics = GenericParams::of(db, def); if generics.is_empty() && generics.has_no_predicates() { return; @@ -4223,7 +4223,7 @@ pub fn types(&self, db: &'db dyn HirDatabase) -> Vec<(Symbol, Type<'db>)> { _ => None, }) .map(|container| { - db.generic_params(container) + GenericParams::of(db, container) .iter_type_or_consts() .filter_map(|param| match param.1 { TypeOrConstParamData::TypeParamData(param) => Some(param.name.clone()), @@ -4231,7 +4231,7 @@ pub fn types(&self, db: &'db dyn HirDatabase) -> Vec<(Symbol, Type<'db>)> { }) .collect::>() }); - let generics = db.generic_params(self.def); + let generics = GenericParams::of(db, self.def); let type_params = generics.iter_type_or_consts().filter_map(|param| match param.1 { TypeOrConstParamData::TypeParamData(param) => Some(param.name.clone()), TypeOrConstParamData::ConstParamData(_) => None, @@ -4653,7 +4653,7 @@ pub fn module(self, db: &dyn HirDatabase) -> Module { /// Is this type parameter implicitly introduced (eg. `Self` in a trait or an `impl Trait` /// argument)? pub fn is_implicit(self, db: &dyn HirDatabase) -> bool { - let params = db.generic_params(self.id.parent()); + let params = GenericParams::of(db, self.id.parent()); let data = ¶ms[self.id.local_id()]; match data.type_param().unwrap().provenance { TypeParamProvenance::TypeParamList => false, @@ -4708,7 +4708,7 @@ pub struct LifetimeParam { impl LifetimeParam { pub fn name(self, db: &dyn HirDatabase) -> Name { - let params = db.generic_params(self.id.parent); + let params = GenericParams::of(db, self.id.parent); params[self.id.local_id].name.clone() } @@ -4732,7 +4732,7 @@ pub fn merge(self) -> TypeOrConstParam { } pub fn name(self, db: &dyn HirDatabase) -> Name { - let params = db.generic_params(self.id.parent()); + let params = GenericParams::of(db, self.id.parent()); match params[self.id.local_id()].name() { Some(it) => it.clone(), None => { @@ -4779,7 +4779,7 @@ pub struct TypeOrConstParam { impl TypeOrConstParam { pub fn name(self, db: &dyn HirDatabase) -> Name { - let params = db.generic_params(self.id.parent); + let params = GenericParams::of(db, self.id.parent); match params[self.id.local_id].name() { Some(n) => n.clone(), _ => Name::missing(), @@ -4795,7 +4795,7 @@ pub fn parent(self, _db: &dyn HirDatabase) -> GenericDef { } pub fn split(self, db: &dyn HirDatabase) -> Either { - let params = db.generic_params(self.id.parent); + let params = GenericParams::of(db, self.id.parent); match ¶ms[self.id.local_id] { TypeOrConstParamData::TypeParamData(_) => { Either::Right(TypeParam { id: TypeParamId::from_unchecked(self.id) }) @@ -4814,7 +4814,7 @@ pub fn ty(self, db: &dyn HirDatabase) -> Type<'_> { } pub fn as_type_param(self, db: &dyn HirDatabase) -> Option { - let params = db.generic_params(self.id.parent); + let params = GenericParams::of(db, self.id.parent); match ¶ms[self.id.local_id] { TypeOrConstParamData::TypeParamData(_) => { Some(TypeParam { id: TypeParamId::from_unchecked(self.id) }) @@ -4824,7 +4824,7 @@ pub fn as_type_param(self, db: &dyn HirDatabase) -> Option { } pub fn as_const_param(self, db: &dyn HirDatabase) -> Option { - let params = db.generic_params(self.id.parent); + let params = GenericParams::of(db, self.id.parent); match ¶ms[self.id.local_id] { TypeOrConstParamData::TypeParamData(_) => None, TypeOrConstParamData::ConstParamData(_) => { @@ -7229,7 +7229,7 @@ fn generic_args_from_tys<'db>( } fn has_non_default_type_params(db: &dyn HirDatabase, generic_def: GenericDefId) -> bool { - let params = db.generic_params(generic_def); + let params = GenericParams::of(db, generic_def); let defaults = db.generic_defaults(generic_def); params .iter_type_or_consts() 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 bd77347e93eb..1b41c78892d6 100644 --- a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs +++ b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs @@ -55,7 +55,6 @@ SyntaxKind, SyntaxNode, TextRange, TextSize, ast::{self, AstNode, RangeItem, RangeOp}, }; -use triomphe::Arc; use crate::{ Adt, AnyFunctionId, AssocItem, BindingMode, BuiltinAttr, BuiltinType, Callable, Const, @@ -94,7 +93,7 @@ pub(crate) enum BodyOrSig<'db> { source_map: &'db ExpressionStoreSourceMap, infer: Option<&'db InferenceResult>, #[expect(dead_code)] - generics: Arc, + generics: &'db GenericParams, }, } @@ -882,7 +881,7 @@ pub(crate) fn resolve_use_type_arg(&self, name: &ast::NameRef) -> Option Date: Sat, 28 Mar 2026 14:20:33 +0100 Subject: [PATCH 50/56] Remove `Arc` from `AstIdMap` --- .../rust-analyzer/crates/hir-def/src/db.rs | 4 -- .../crates/hir-def/src/expr_store/expander.rs | 33 +++++---- .../crates/hir-def/src/expr_store/lower.rs | 2 +- .../crates/hir-def/src/find_path.rs | 3 +- .../crates/hir-def/src/import_map.rs | 25 ++++--- .../crates/hir-def/src/item_tree.rs | 33 ++------- .../crates/hir-def/src/item_tree/lower.rs | 15 ++-- .../crates/hir-def/src/nameres/assoc.rs | 17 +++-- .../hir-def/src/nameres/tests/incremental.rs | 68 +++++++++---------- .../crates/hir-def/src/resolver.rs | 2 +- .../rust-analyzer/crates/hir-expand/src/db.rs | 9 +-- .../crates/hir-ty/src/builtin_derive.rs | 8 +-- .../crates/hir-ty/src/tests/incremental.rs | 30 ++++---- .../rust-analyzer/crates/hir/src/display.rs | 10 +-- .../crates/ide-db/src/prime_caches.rs | 4 +- 15 files changed, 121 insertions(+), 142 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/db.rs b/src/tools/rust-analyzer/crates/hir-def/src/db.rs index 0451523390e3..2f2889ec6611 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/db.rs @@ -15,7 +15,6 @@ ProcMacroLoc, StaticId, StaticLoc, StructId, StructLoc, TraitId, TraitLoc, TypeAliasId, TypeAliasLoc, UnionId, UnionLoc, UseId, UseLoc, VariantId, attrs::AttrFlags, - import_map::ImportMap, item_tree::{ItemTree, file_item_tree_query}, nameres::crate_def_map, visibility::{self, Visibility}, @@ -97,9 +96,6 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + SourceDatabase { #[salsa::invoke(macro_def)] fn macro_def(&self, m: MacroId) -> MacroDefId; - #[salsa::invoke(ImportMap::import_map_query)] - fn import_map(&self, krate: Crate) -> Arc; - // region:visibilities #[salsa::invoke(visibility::field_visibilities_query)] diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/expander.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/expander.rs index d34ec9bbc182..2fffa02c1314 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/expander.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/expander.rs @@ -14,7 +14,6 @@ use span::{AstIdMap, SyntaxContext}; use syntax::ast::HasAttrs; use syntax::{AstNode, Parse, ast}; -use triomphe::Arc; use tt::TextRange; use crate::{ @@ -23,21 +22,21 @@ }; #[derive(Debug)] -pub(super) struct Expander { +pub(super) struct Expander<'db> { span_map: SpanMap, current_file_id: HirFileId, - ast_id_map: Arc, + ast_id_map: &'db AstIdMap, /// `recursion_depth == usize::MAX` indicates that the recursion limit has been reached. recursion_depth: u32, recursion_limit: usize, } -impl Expander { +impl<'db> Expander<'db> { pub(super) fn new( - db: &dyn DefDatabase, + db: &'db dyn DefDatabase, current_file_id: HirFileId, - def_map: &DefMap, - ) -> Expander { + def_map: &'db DefMap, + ) -> Expander<'db> { let recursion_limit = def_map.recursion_limit() as usize; let recursion_limit = if cfg!(test) { // Without this, `body::tests::your_stack_belongs_to_me` stack-overflows in debug @@ -77,12 +76,12 @@ pub(super) fn is_cfg_enabled( pub(super) fn enter_expand( &mut self, - db: &dyn DefDatabase, + db: &'db dyn DefDatabase, macro_call: ast::MacroCall, krate: Crate, resolver: impl Fn(&ModPath) -> Option, eager_callback: EagerCallBackFn<'_>, - ) -> Result>)>>, UnresolvedMacro> { + ) -> Result, Option>)>>, UnresolvedMacro> { // FIXME: within_limit should support this, instead of us having to extract the error let mut unresolved_macro_err = None; @@ -130,13 +129,13 @@ pub(super) fn enter_expand( pub(super) fn enter_expand_id( &mut self, - db: &dyn DefDatabase, + db: &'db dyn DefDatabase, call_id: MacroCallId, - ) -> ExpandResult>)>> { + ) -> ExpandResult, Option>)>> { self.within_limit(db, |_this| ExpandResult::ok(Some(call_id))) } - pub(super) fn exit(&mut self, Mark { file_id, span_map, ast_id_map, mut bomb }: Mark) { + pub(super) fn exit(&mut self, Mark { file_id, span_map, ast_id_map, mut bomb }: Mark<'db>) { self.span_map = span_map; self.current_file_id = file_id; self.ast_id_map = ast_id_map; @@ -162,9 +161,9 @@ pub(super) fn current_file_id(&self) -> HirFileId { fn within_limit( &mut self, - db: &dyn DefDatabase, + db: &'db dyn DefDatabase, op: F, - ) -> ExpandResult>)>> + ) -> ExpandResult, Option>)>> where F: FnOnce(&mut Self) -> ExpandResult>, { @@ -219,7 +218,7 @@ fn within_limit( #[inline] pub(super) fn ast_id_map(&self) -> &AstIdMap { - &self.ast_id_map + self.ast_id_map } #[inline] @@ -229,9 +228,9 @@ pub(super) fn span_map(&self) -> SpanMapRef<'_> { } #[derive(Debug)] -pub(super) struct Mark { +pub(super) struct Mark<'db> { file_id: HirFileId, span_map: SpanMap, - ast_id_map: Arc, + ast_id_map: &'db AstIdMap, bomb: DropBomb, } 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 de1f7463afbe..afa1c7fcfd5b 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 @@ -414,7 +414,7 @@ pub(crate) fn lower_function( pub struct ExprCollector<'db> { db: &'db dyn DefDatabase, cfg_options: &'db CfgOptions, - expander: Expander, + expander: Expander<'db>, def_map: &'db DefMap, local_def_map: &'db LocalDefMap, module: ModuleId, 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 5d1cac8e93c4..830820369336 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 @@ -14,6 +14,7 @@ use crate::{ FindPathConfig, ModuleDefId, ModuleId, db::DefDatabase, + import_map::ImportMap, item_scope::ItemInNs, nameres::DefMap, visibility::{Visibility, VisibilityExplicitness}, @@ -426,7 +427,7 @@ fn find_in_dep( best_choice: &mut Option, dep: Crate, ) { - let import_map = ctx.db.import_map(dep); + let import_map = ImportMap::of(ctx.db, dep); let Some(import_info_for) = import_map.import_info_for(item) else { return; }; diff --git a/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs b/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs index 6c5d226cac1b..0014e1af5c0d 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs @@ -10,7 +10,6 @@ use smallvec::SmallVec; use span::Edition; use stdx::format_to; -use triomphe::Arc; use crate::{ AssocItemId, AttrDefId, Complete, FxIndexMap, ModuleDefId, ModuleId, TraitId, @@ -63,6 +62,14 @@ enum IsTraitAssocItem { type ImportMapIndex = FxIndexMap, IsTraitAssocItem)>; +#[salsa::tracked] +impl ImportMap { + #[salsa::tracked(returns(ref))] + pub fn of(db: &dyn DefDatabase, krate: Crate) -> Self { + Self::import_map_query_impl(db, krate) + } +} + impl ImportMap { pub fn dump(&self, db: &dyn DefDatabase) -> String { let mut out = String::new(); @@ -76,7 +83,7 @@ pub fn dump(&self, db: &dyn DefDatabase) -> String { out } - pub(crate) fn import_map_query(db: &dyn DefDatabase, krate: Crate) -> Arc { + fn import_map_query_impl(db: &dyn DefDatabase, krate: Crate) -> Self { let _p = tracing::info_span!("import_map_query").entered(); let map = Self::collect_import_map(db, krate); @@ -120,7 +127,7 @@ pub(crate) fn import_map_query(db: &dyn DefDatabase, krate: Crate) -> Arc } let importables = importables.into_iter().map(|(item, _, idx)| (item, idx)).collect(); - Arc::new(ImportMap { item_to_info_map: map, fst: builder.into_map(), importables }) + ImportMap { item_to_info_map: map, fst: builder.into_map(), importables } } pub fn import_info_for(&self, item: ItemInNs) -> Option<&[ImportInfo]> { @@ -424,7 +431,7 @@ pub fn search_dependencies( let _p = tracing::info_span!("search_dependencies", ?query).entered(); let import_maps: Vec<_> = - krate.data(db).dependencies.iter().map(|dep| db.import_map(dep.crate_id)).collect(); + krate.data(db).dependencies.iter().map(|dep| ImportMap::of(db, dep.crate_id)).collect(); let mut op = fst::map::OpBuilder::new(); @@ -458,7 +465,7 @@ pub fn search_dependencies( fn search_maps( _db: &dyn DefDatabase, - import_maps: &[Arc], + import_maps: &[&ImportMap], mut stream: fst::map::Union<'_>, query: &Query, ) -> FxHashSet<(ItemInNs, Complete)> { @@ -467,7 +474,7 @@ fn search_maps( for &IndexedValue { index: import_map_idx, value } in indexed_values { let end = (value & 0xFFFF_FFFF) as usize; let start = (value >> 32) as usize; - let ImportMap { item_to_info_map, importables, .. } = &*import_maps[import_map_idx]; + let ImportMap { item_to_info_map, importables, .. } = import_maps[import_map_idx]; let importables = &importables[start..end]; let iter = importables @@ -546,9 +553,9 @@ fn check_search( .into_iter() .filter_map(|(dependency, _)| { let dependency_krate = dependency.krate(&db)?; - let dependency_imports = db.import_map(dependency_krate); + let dependency_imports = ImportMap::of(&db, dependency_krate); - let (path, mark) = match assoc_item_path(&db, &dependency_imports, dependency) { + let (path, mark) = match assoc_item_path(&db, dependency_imports, dependency) { Some(assoc_item_path) => (assoc_item_path, "a"), None => ( render_path(&db, &dependency_imports.import_info_for(dependency)?[0]), @@ -618,7 +625,7 @@ fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) { let cdata = &krate.extra_data(&db); let name = cdata.display_name.as_ref()?; - let map = db.import_map(krate); + let map = ImportMap::of(&db, krate); Some(format!("{name}:\n{}\n", map.fmt_for_test(&db))) }) 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 9825dbfe1cd2..e7ab2b390f26 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 @@ -192,45 +192,22 @@ pub(crate) fn file_item_tree_query( } } -#[salsa_macros::tracked(returns(deref))] +#[salsa_macros::tracked(returns(ref))] pub(crate) fn block_item_tree_query( db: &dyn DefDatabase, block: BlockId, krate: Crate, -) -> Arc { +) -> ItemTree { let _p = tracing::info_span!("block_item_tree_query", ?block).entered(); - static EMPTY: OnceLock> = OnceLock::new(); - let loc = block.lookup(db); let block = loc.ast_id.to_node(db); let ctx = lower::Ctx::new(db, loc.ast_id.file_id, krate); let mut item_tree = ctx.lower_block(&block); - let ItemTree { top_level, top_attrs, attrs, vis, big_data, small_data } = &item_tree; - if small_data.is_empty() - && big_data.is_empty() - && top_level.is_empty() - && attrs.is_empty() - && top_attrs.is_empty() - && vis.arena.is_empty() - { - EMPTY - .get_or_init(|| { - Arc::new(ItemTree { - top_level: Box::new([]), - attrs: FxHashMap::default(), - small_data: FxHashMap::default(), - big_data: FxHashMap::default(), - top_attrs: AttrsOrCfg::empty(), - vis: ItemVisibilities { arena: ThinVec::new() }, - }) - }) - .clone() - } else { - item_tree.shrink_to_fit(); - Arc::new(item_tree) - } + item_tree.shrink_to_fit(); + item_tree } + /// The item tree of a source file. #[derive(Debug, Default, Eq, PartialEq)] pub struct ItemTree { diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs index 31c6ef867d2c..31e409d86e49 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs @@ -16,7 +16,6 @@ AstNode, ast::{self, HasModuleItem, HasName}, }; -use triomphe::Arc; use crate::{ db::DefDatabase, @@ -29,20 +28,20 @@ }, }; -pub(super) struct Ctx<'a> { - pub(super) db: &'a dyn DefDatabase, +pub(super) struct Ctx<'db> { + pub(super) db: &'db dyn DefDatabase, tree: ItemTree, - source_ast_id_map: Arc, + source_ast_id_map: &'db AstIdMap, span_map: OnceCell, file: HirFileId, - cfg_options: OnceCell<&'a CfgOptions>, + cfg_options: OnceCell<&'db CfgOptions>, krate: Crate, top_level: Vec, visibilities: FxIndexSet, } -impl<'a> Ctx<'a> { - pub(super) fn new(db: &'a dyn DefDatabase, file: HirFileId, krate: Crate) -> Self { +impl<'db> Ctx<'db> { + pub(super) fn new(db: &'db dyn DefDatabase, file: HirFileId, krate: Crate) -> Self { Self { db, tree: ItemTree::default(), @@ -57,7 +56,7 @@ pub(super) fn new(db: &'a dyn DefDatabase, file: HirFileId, krate: Crate) -> Sel } #[inline] - pub(super) fn cfg_options(&self) -> &'a CfgOptions { + pub(super) fn cfg_options(&self) -> &'db CfgOptions { self.cfg_options.get_or_init(|| self.krate.cfg_options(self.db)) } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/assoc.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/assoc.rs index 9d2b2109fbcb..f5a852b39c8d 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/assoc.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/assoc.rs @@ -17,7 +17,6 @@ ast::{self, HasModuleItem, HasName}, }; use thin_vec::ThinVec; -use triomphe::Arc; use crate::{ AssocItemId, AstIdWithPath, ConstLoc, FunctionId, FunctionLoc, ImplId, ItemContainerId, @@ -133,14 +132,14 @@ pub fn macro_calls(&self) -> impl Iterator, MacroCallId } } -struct AssocItemCollector<'a> { - db: &'a dyn DefDatabase, +struct AssocItemCollector<'db> { + db: &'db dyn DefDatabase, module_id: ModuleId, - def_map: &'a DefMap, - local_def_map: &'a LocalDefMap, - ast_id_map: Arc, + def_map: &'db DefMap, + local_def_map: &'db LocalDefMap, + ast_id_map: &'db AstIdMap, span_map: SpanMap, - cfg_options: &'a CfgOptions, + cfg_options: &'db CfgOptions, file_id: HirFileId, diagnostics: Vec, container: ItemContainerId, @@ -150,9 +149,9 @@ struct AssocItemCollector<'a> { macro_calls: ThinVec<(AstId, MacroCallId)>, } -impl<'a> AssocItemCollector<'a> { +impl<'db> AssocItemCollector<'db> { fn new( - db: &'a dyn DefDatabase, + db: &'db dyn DefDatabase, module_id: ModuleId, container: ItemContainerId, file_id: HirFileId, 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 7fedfa03bbd9..5b75c078ecfa 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 @@ -166,15 +166,15 @@ fn no() {} [ "crate_local_def_map", "file_item_tree_query", - "ast_id_map_shim", + "ast_id_map", "parse_shim", "real_span_map_shim", "file_item_tree_query", - "ast_id_map_shim", + "ast_id_map", "parse_shim", "real_span_map_shim", "file_item_tree_query", - "ast_id_map_shim", + "ast_id_map", "parse_shim", "real_span_map_shim", "EnumVariants::of_", @@ -183,7 +183,7 @@ fn no() {} expect![[r#" [ "parse_shim", - "ast_id_map_shim", + "ast_id_map", "file_item_tree_query", "real_span_map_shim", "EnumVariants::of_", @@ -224,21 +224,21 @@ pub struct S {} [ "crate_local_def_map", "file_item_tree_query", - "ast_id_map_shim", + "ast_id_map", "parse_shim", "real_span_map_shim", "decl_macro_expander_shim", "file_item_tree_query", - "ast_id_map_shim", + "ast_id_map", "parse_shim", "real_span_map_shim", "file_item_tree_query", - "ast_id_map_shim", + "ast_id_map", "parse_shim", "real_span_map_shim", "macro_def_shim", "file_item_tree_query", - "ast_id_map_shim", + "ast_id_map", "parse_macro_expansion_shim", "macro_arg_shim", ] @@ -246,12 +246,12 @@ pub struct S {} expect![[r#" [ "parse_shim", - "ast_id_map_shim", + "ast_id_map", "file_item_tree_query", "real_span_map_shim", "macro_arg_shim", "parse_macro_expansion_shim", - "ast_id_map_shim", + "ast_id_map", "file_item_tree_query", ] "#]], @@ -282,26 +282,26 @@ fn f() { foo } [ "crate_local_def_map", "file_item_tree_query", - "ast_id_map_shim", + "ast_id_map", "parse_shim", "real_span_map_shim", "crate_local_def_map", "proc_macros_for_crate_shim", "file_item_tree_query", - "ast_id_map_shim", + "ast_id_map", "parse_shim", "real_span_map_shim", "file_item_tree_query", - "ast_id_map_shim", + "ast_id_map", "parse_shim", "real_span_map_shim", "file_item_tree_query", - "ast_id_map_shim", + "ast_id_map", "parse_shim", "real_span_map_shim", "macro_def_shim", "file_item_tree_query", - "ast_id_map_shim", + "ast_id_map", "parse_macro_expansion_shim", "expand_proc_macro_shim", "macro_arg_shim", @@ -311,13 +311,13 @@ fn f() { foo } expect![[r#" [ "parse_shim", - "ast_id_map_shim", + "ast_id_map", "file_item_tree_query", "real_span_map_shim", "macro_arg_shim", "expand_proc_macro_shim", "parse_macro_expansion_shim", - "ast_id_map_shim", + "ast_id_map", "file_item_tree_query", ] "#]], @@ -406,38 +406,38 @@ pub struct S {} [ "crate_local_def_map", "file_item_tree_query", - "ast_id_map_shim", + "ast_id_map", "parse_shim", "real_span_map_shim", "crate_local_def_map", "proc_macros_for_crate_shim", "file_item_tree_query", - "ast_id_map_shim", + "ast_id_map", "parse_shim", "real_span_map_shim", "decl_macro_expander_shim", "file_item_tree_query", - "ast_id_map_shim", + "ast_id_map", "parse_shim", "real_span_map_shim", "file_item_tree_query", - "ast_id_map_shim", + "ast_id_map", "parse_shim", "real_span_map_shim", "macro_def_shim", "file_item_tree_query", - "ast_id_map_shim", + "ast_id_map", "parse_macro_expansion_shim", "macro_arg_shim", "decl_macro_expander_shim", "macro_def_shim", "file_item_tree_query", - "ast_id_map_shim", + "ast_id_map", "parse_macro_expansion_shim", "macro_arg_shim", "macro_def_shim", "file_item_tree_query", - "ast_id_map_shim", + "ast_id_map", "parse_macro_expansion_shim", "expand_proc_macro_shim", "macro_arg_shim", @@ -447,7 +447,7 @@ pub struct S {} expect![[r#" [ "parse_shim", - "ast_id_map_shim", + "ast_id_map", "file_item_tree_query", "real_span_map_shim", "macro_arg_shim", @@ -523,29 +523,29 @@ fn quux() { 1$0 } [ "crate_local_def_map", "file_item_tree_query", - "ast_id_map_shim", + "ast_id_map", "parse_shim", "real_span_map_shim", "decl_macro_expander_shim", "file_item_tree_query", - "ast_id_map_shim", + "ast_id_map", "parse_shim", "real_span_map_shim", "file_item_tree_query", - "ast_id_map_shim", + "ast_id_map", "parse_shim", "real_span_map_shim", "macro_def_shim", "file_item_tree_query", - "ast_id_map_shim", + "ast_id_map", "parse_macro_expansion_shim", "macro_arg_shim", "file_item_tree_query", - "ast_id_map_shim", + "ast_id_map", "parse_macro_expansion_shim", "macro_arg_shim", "file_item_tree_query", - "ast_id_map_shim", + "ast_id_map", "parse_macro_expansion_shim", "macro_arg_shim", ] @@ -572,7 +572,7 @@ fn quux() { 92 } expect![[r#" [ "parse_shim", - "ast_id_map_shim", + "ast_id_map", "file_item_tree_query", "real_span_map_shim", "macro_arg_shim", @@ -610,7 +610,7 @@ impl Tr for () {} expect![[r#" [ "file_item_tree_query", - "ast_id_map_shim", + "ast_id_map", "parse_shim", "real_span_map_shim", ] @@ -630,7 +630,7 @@ impl Tr for () {} expect![[r#" [ "parse_shim", - "ast_id_map_shim", + "ast_id_map", "file_item_tree_query", "real_span_map_shim", ] 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 1a0e6a46f174..dee7800e8428 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs @@ -1020,7 +1020,7 @@ fn process_names(&self, acc: &mut ScopeNames, db: &'db dyn DefDatabase) { }) }); } - &Scope::GenericParams { ref params, def: parent } => { + &Scope::GenericParams { params, def: parent } => { if let GenericDefId::ImplId(impl_) = parent { acc.add(&Name::new_symbol_root(sym::Self_), ScopeDef::ImplSelfType(impl_)); } else if let GenericDefId::AdtId(adt) = parent { diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/db.rs b/src/tools/rust-analyzer/crates/hir-expand/src/db.rs index 363465fdda35..020731cf9aca 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/db.rs @@ -58,8 +58,8 @@ pub trait ExpandDatabase: RootQueryDb { fn proc_macros_for_crate(&self, krate: Crate) -> Option>; #[salsa::invoke(ast_id_map)] - #[salsa::lru(1024)] - fn ast_id_map(&self, file_id: HirFileId) -> Arc; + #[salsa::transparent] + fn ast_id_map(&self, file_id: HirFileId) -> &AstIdMap; #[salsa::transparent] fn resolve_span(&self, span: Span) -> FileRange; @@ -334,8 +334,9 @@ pub fn expand_speculative( Some((node.syntax_node(), token)) } -fn ast_id_map(db: &dyn ExpandDatabase, file_id: HirFileId) -> triomphe::Arc { - triomphe::Arc::new(AstIdMap::from_source(&db.parse_or_expand(file_id))) +#[salsa::tracked(lru = 1024, returns(ref))] +fn ast_id_map(db: &dyn ExpandDatabase, file_id: HirFileId) -> AstIdMap { + AstIdMap::from_source(&db.parse_or_expand(file_id)) } /// Main public API -- parses a hir file, not caring whether it's a real diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/builtin_derive.rs b/src/tools/rust-analyzer/crates/hir-ty/src/builtin_derive.rs index 6cdc07e430b6..92629b7a0532 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/builtin_derive.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/builtin_derive.rs @@ -133,7 +133,7 @@ pub fn impl_trait<'db>( let args = GenericArgs::identity_for_item(interner, loc.adt.into()); let self_ty = Ty::new_adt(interner, loc.adt, args); let Some((pointee_param_idx, _, new_param_ty)) = - coerce_pointee_params(interner, loc, &generic_params, trait_id) + coerce_pointee_params(interner, loc, generic_params, trait_id) else { // Malformed derive. return EarlyBinder::bind(TraitRef::new( @@ -168,7 +168,7 @@ pub fn predicates<'db>(db: &'db dyn HirDatabase, impl_: BuiltinDeriveImplId) -> | BuiltinDeriveImplTrait::PartialOrd | BuiltinDeriveImplTrait::Eq | BuiltinDeriveImplTrait::PartialEq => { - simple_trait_predicates(interner, loc, &generic_params, adt_predicates, trait_id) + simple_trait_predicates(interner, loc, generic_params, adt_predicates, trait_id) } BuiltinDeriveImplTrait::Default => { if matches!(loc.adt, AdtId::EnumId(_)) { @@ -178,12 +178,12 @@ pub fn predicates<'db>(db: &'db dyn HirDatabase, impl_: BuiltinDeriveImplId) -> .store(), )) } else { - simple_trait_predicates(interner, loc, &generic_params, adt_predicates, trait_id) + simple_trait_predicates(interner, loc, generic_params, adt_predicates, trait_id) } } BuiltinDeriveImplTrait::CoerceUnsized | BuiltinDeriveImplTrait::DispatchFromDyn => { let Some((pointee_param_idx, pointee_param_id, new_param_ty)) = - coerce_pointee_params(interner, loc, &generic_params, trait_id) + coerce_pointee_params(interner, loc, generic_params, trait_id) else { // Malformed derive. return GenericPredicates::from_explicit_own_predicates(StoredEarlyBinder::bind( 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 3e8089c9c13e..e806999cb44e 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 @@ -34,7 +34,7 @@ fn foo() -> i32 { "source_root_crates_shim", "crate_local_def_map", "file_item_tree_query", - "ast_id_map_shim", + "ast_id_map", "parse_shim", "real_span_map_shim", "InferenceResult::for_body_", @@ -77,7 +77,7 @@ fn foo() -> i32 { expect_test::expect![[r#" [ "parse_shim", - "ast_id_map_shim", + "ast_id_map", "file_item_tree_query", "real_span_map_shim", "AttrFlags::query_", @@ -122,7 +122,7 @@ fn baz() -> i32 { "source_root_crates_shim", "crate_local_def_map", "file_item_tree_query", - "ast_id_map_shim", + "ast_id_map", "parse_shim", "real_span_map_shim", "InferenceResult::for_body_", @@ -190,7 +190,7 @@ fn baz() -> i32 { expect_test::expect![[r#" [ "parse_shim", - "ast_id_map_shim", + "ast_id_map", "file_item_tree_query", "real_span_map_shim", "AttrFlags::query_", @@ -242,7 +242,7 @@ fn bar() -> f32 { "source_root_crates_shim", "crate_local_def_map", "file_item_tree_query", - "ast_id_map_shim", + "ast_id_map", "parse_shim", "real_span_map_shim", "TraitImpls::for_crate_", @@ -279,7 +279,7 @@ pub struct NewStruct { expect_test::expect![[r#" [ "parse_shim", - "ast_id_map_shim", + "ast_id_map", "file_item_tree_query", "real_span_map_shim", "crate_local_def_map", @@ -317,7 +317,7 @@ fn bar() -> f32 { "source_root_crates_shim", "crate_local_def_map", "file_item_tree_query", - "ast_id_map_shim", + "ast_id_map", "parse_shim", "real_span_map_shim", "TraitImpls::for_crate_", @@ -355,7 +355,7 @@ pub enum SomeEnum { expect_test::expect![[r#" [ "parse_shim", - "ast_id_map_shim", + "ast_id_map", "file_item_tree_query", "real_span_map_shim", "crate_local_def_map", @@ -393,7 +393,7 @@ fn bar() -> f32 { "source_root_crates_shim", "crate_local_def_map", "file_item_tree_query", - "ast_id_map_shim", + "ast_id_map", "parse_shim", "real_span_map_shim", "TraitImpls::for_crate_", @@ -428,7 +428,7 @@ fn bar() -> f32 { expect_test::expect![[r#" [ "parse_shim", - "ast_id_map_shim", + "ast_id_map", "file_item_tree_query", "real_span_map_shim", "crate_local_def_map", @@ -470,7 +470,7 @@ pub struct SomeStruct { "source_root_crates_shim", "crate_local_def_map", "file_item_tree_query", - "ast_id_map_shim", + "ast_id_map", "parse_shim", "real_span_map_shim", "TraitImpls::for_crate_", @@ -513,7 +513,7 @@ pub fn new(value: i32) -> Self { expect_test::expect![[r#" [ "parse_shim", - "ast_id_map_shim", + "ast_id_map", "file_item_tree_query", "real_span_map_shim", "crate_local_def_map", @@ -571,7 +571,7 @@ fn main() { "source_root_crates_shim", "crate_local_def_map", "file_item_tree_query", - "ast_id_map_shim", + "ast_id_map", "parse_shim", "real_span_map_shim", "TraitItems::query_with_diagnostics_", @@ -665,7 +665,7 @@ fn main() { expect_test::expect![[r#" [ "parse_shim", - "ast_id_map_shim", + "ast_id_map", "file_item_tree_query", "real_span_map_shim", "crate_local_def_map", @@ -716,6 +716,7 @@ fn execute_assert_events( ) { crate::attach_db(db, || { let (executed, events) = db.log_executed(f); + expect.assert_debug_eq(&executed); for (event, count) in required { let n = executed.iter().filter(|it| it.contains(event)).count(); assert_eq!( @@ -731,6 +732,5 @@ fn execute_assert_events( .collect::>(), ); } - expect.assert_debug_eq(&executed); }); } diff --git a/src/tools/rust-analyzer/crates/hir/src/display.rs b/src/tools/rust-analyzer/crates/hir/src/display.rs index aa34177b89a1..ef885f0be8a2 100644 --- a/src/tools/rust-analyzer/crates/hir/src/display.rs +++ b/src/tools/rust-analyzer/crates/hir/src/display.rs @@ -101,7 +101,7 @@ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result { if f.show_container_bounds() && !params.is_empty() { write_trait_header(trait_.into(), f)?; f.write_char('\n')?; - has_disaplayable_predicates(f.db, ¶ms, params_store) + has_disaplayable_predicates(f.db, params, params_store) .then_some((params, params_store)) } else { None @@ -112,7 +112,7 @@ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result { if f.show_container_bounds() && !params.is_empty() { write_impl_header(impl_, f)?; f.write_char('\n')?; - has_disaplayable_predicates(f.db, ¶ms, params_store) + has_disaplayable_predicates(f.db, params, params_store) .then_some((params, params_store)) } else { None @@ -134,7 +134,7 @@ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result { _ => unreachable!(), }; write!(f, "\n // Bounds from {container_name}:",)?; - write_where_predicates(&container_params, container_params_store, f)?; + write_where_predicates(container_params, container_params_store, f)?; } Ok(()) } @@ -719,12 +719,12 @@ fn write_generic_params_or_args<'db>( fn write_where_clause<'db>(def: GenericDefId, f: &mut HirFormatter<'_, 'db>) -> Result { let (params, store) = GenericParams::with_store(f.db, def); - if !has_disaplayable_predicates(f.db, ¶ms, store) { + if !has_disaplayable_predicates(f.db, params, store) { return Ok(false); } f.write_str("\nwhere")?; - write_where_predicates(¶ms, store, f)?; + write_where_predicates(params, store, f)?; Ok(true) } 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 015b06e8e0b2..d264428212cb 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,7 +4,7 @@ //! various caches, it's not really advanced at the moment. use std::panic::AssertUnwindSafe; -use hir::{Symbol, db::DefDatabase}; +use hir::{Symbol, import_map::ImportMap}; use rustc_hash::FxHashMap; use salsa::{Cancelled, Database}; @@ -123,7 +123,7 @@ enum ParallelPrimeCacheWorkerProgress { Ok::<_, crossbeam_channel::SendError<_>>(()) }; let handle_import_map = |crate_id| { - let cancelled = Cancelled::catch(|| _ = db.import_map(crate_id)); + let cancelled = Cancelled::catch(|| _ = ImportMap::of(&db, crate_id)); match cancelled { Ok(()) => { From b451c258ba8a2c374fdce8a857bd869adc8d2804 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sat, 28 Mar 2026 15:11:29 +0100 Subject: [PATCH 51/56] Remove another `Arc` --- .../rust-analyzer/crates/hir-def/src/db.rs | 12 ++---- .../rust-analyzer/crates/hir-def/src/lib.rs | 8 ++-- .../crates/hir-def/src/signatures.rs | 2 +- .../crates/hir-def/src/visibility.rs | 39 ++++++++++--------- .../diagnostics/match_check/pat_analysis.rs | 4 +- .../crates/hir-ty/src/infer/expr.rs | 7 ++-- .../crates/hir-ty/src/infer/pat.rs | 5 ++- .../crates/hir-ty/src/inhabitedness.rs | 10 ++++- 8 files changed, 48 insertions(+), 39 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/db.rs b/src/tools/rust-analyzer/crates/hir-def/src/db.rs index 2f2889ec6611..5d5d43539822 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/db.rs @@ -4,16 +4,15 @@ EditionedFileId, HirFileId, InFile, Lookup, MacroCallId, MacroDefId, MacroDefKind, db::ExpandDatabase, }; -use la_arena::ArenaMap; use triomphe::Arc; use crate::{ AnonConstId, AnonConstLoc, AssocItemId, AttrDefId, BlockId, BlockLoc, ConstId, ConstLoc, EnumId, EnumLoc, EnumVariantId, EnumVariantLoc, ExternBlockId, ExternBlockLoc, ExternCrateId, - ExternCrateLoc, FunctionId, FunctionLoc, ImplId, ImplLoc, LocalFieldId, Macro2Id, Macro2Loc, - MacroExpander, MacroId, MacroRulesId, MacroRulesLoc, MacroRulesLocFlags, ProcMacroId, - ProcMacroLoc, StaticId, StaticLoc, StructId, StructLoc, TraitId, TraitLoc, TypeAliasId, - TypeAliasLoc, UnionId, UnionLoc, UseId, UseLoc, VariantId, + ExternCrateLoc, FunctionId, FunctionLoc, ImplId, ImplLoc, Macro2Id, Macro2Loc, MacroExpander, + MacroId, MacroRulesId, MacroRulesLoc, MacroRulesLocFlags, ProcMacroId, ProcMacroLoc, StaticId, + StaticLoc, StructId, StructLoc, TraitId, TraitLoc, TypeAliasId, TypeAliasLoc, UnionId, + UnionLoc, UseId, UseLoc, attrs::AttrFlags, item_tree::{ItemTree, file_item_tree_query}, nameres::crate_def_map, @@ -98,9 +97,6 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + SourceDatabase { // region:visibilities - #[salsa::invoke(visibility::field_visibilities_query)] - fn field_visibilities(&self, var: VariantId) -> Arc>; - #[salsa::invoke(visibility::assoc_visibility_query)] fn assoc_visibility(&self, def: AssocItemId) -> Visibility; 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 4387ef055fdd..800c08aa2c96 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs @@ -259,7 +259,7 @@ fn module(&self, db: &dyn DefDatabase) -> ModuleId { impl StructId { pub fn fields(self, db: &dyn DefDatabase) -> &VariantFields { - VariantFields::firewall(db, self.into()) + VariantFields::of(db, self.into()) } pub fn fields_with_source_map( @@ -276,7 +276,7 @@ pub fn fields_with_source_map( impl UnionId { pub fn fields(self, db: &dyn DefDatabase) -> &VariantFields { - VariantFields::firewall(db, self.into()) + VariantFields::of(db, self.into()) } pub fn fields_with_source_map( @@ -396,7 +396,7 @@ pub struct EnumVariantLoc { impl EnumVariantId { pub fn fields(self, db: &dyn DefDatabase) -> &VariantFields { - VariantFields::firewall(db, self.into()) + VariantFields::of(db, self.into()) } pub fn fields_with_source_map( @@ -1027,7 +1027,7 @@ pub enum VariantId { impl VariantId { pub fn fields(self, db: &dyn DefDatabase) -> &VariantFields { - VariantFields::firewall(db, self) + VariantFields::of(db, self) } pub fn fields_with_source_map( diff --git a/src/tools/rust-analyzer/crates/hir-def/src/signatures.rs b/src/tools/rust-analyzer/crates/hir-def/src/signatures.rs index c16ca6d0b432..9d988c821ab7 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/signatures.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/signatures.rs @@ -906,7 +906,7 @@ pub(crate) fn with_source_map( } #[salsa::tracked(returns(deref))] - pub(crate) fn firewall(db: &dyn DefDatabase, id: VariantId) -> Arc { + pub(crate) fn of(db: &dyn DefDatabase, id: VariantId) -> Arc { Self::with_source_map(db, id).0.clone() } } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs b/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs index cb5eed1b8b6c..81a61ec20f17 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs @@ -6,11 +6,11 @@ use hir_expand::{InFile, Lookup}; use la_arena::ArenaMap; use syntax::ast::{self, HasVisibility}; -use triomphe::Arc; use crate::{ AssocItemId, HasModule, ItemContainerId, LocalFieldId, ModuleId, TraitId, VariantId, - db::DefDatabase, nameres::DefMap, resolver::HasResolver, src::HasSource, + db::DefDatabase, nameres::DefMap, resolver::HasResolver, signatures::VariantFields, + src::HasSource, }; pub use crate::item_tree::{RawVisibility, VisibilityExplicitness}; @@ -277,23 +277,26 @@ pub(crate) fn min( } } -/// Resolve visibility of all specific fields of a struct or union variant. -pub(crate) fn field_visibilities_query( - db: &dyn DefDatabase, - variant_id: VariantId, -) -> Arc> { - let variant_fields = variant_id.fields(db); - let fields = variant_fields.fields(); - if fields.is_empty() { - return Arc::default(); +#[salsa::tracked] +impl VariantFields { + /// Resolve visibility of all specific fields of a struct or union variant. + #[salsa::tracked(returns(ref))] + pub fn field_visibilities( + db: &dyn DefDatabase, + variant_id: VariantId, + ) -> ArenaMap { + let variant_fields = variant_id.fields(db); + let fields = variant_fields.fields(); + if fields.is_empty() { + return ArenaMap::default(); + } + let resolver = variant_id.module(db).resolver(db); + let mut res = ArenaMap::with_capacity(fields.len()); + for (field_id, field_data) in fields.iter() { + res.insert(field_id, Visibility::resolve(db, &resolver, &field_data.visibility)); + } + res } - let resolver = variant_id.module(db).resolver(db); - let mut res = ArenaMap::default(); - for (field_id, field_data) in fields.iter() { - res.insert(field_id, Visibility::resolve(db, &resolver, &field_data.visibility)); - } - res.shrink_to_fit(); - Arc::new(res) } pub fn visibility_from_ast( diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs index eda7e7e249b3..bc3d9bbec6fa 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs @@ -4,6 +4,7 @@ use hir_def::{ EnumId, EnumVariantId, HasModule, LocalFieldId, ModuleId, VariantId, attrs::AttrFlags, + signatures::VariantFields, }; use intern::sym; use rustc_pattern_analysis::{ @@ -363,7 +364,8 @@ fn ctor_sub_tys( let adt = adt_def.def_id().0; let variant = Self::variant_id_for_adt(self.db, ctor, adt).unwrap(); - let visibilities = LazyCell::new(|| self.db.field_visibilities(variant)); + let visibilities = + LazyCell::new(|| VariantFields::field_visibilities(self.db, variant)); self.list_variant_fields(*ty, variant) .map(move |(fid, ty)| { 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 c4c217b010ee..dc57b1d1c215 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 @@ -11,7 +11,7 @@ InlineAsmKind, LabelId, Literal, Pat, PatId, RecordSpread, Statement, UnaryOp, }, resolver::ValueNs, - signatures::FunctionSignature, + signatures::{FunctionSignature, VariantFields}, }; use hir_def::{FunctionId, hir::ClosureKind}; use hir_expand::name::Name; @@ -609,7 +609,7 @@ fn infer_expr_inner( Some(def) => { let field_types = self.db.field_types(def); let variant_data = def.fields(self.db); - let visibilities = self.db.field_visibilities(def); + let visibilities = VariantFields::field_visibilities(self.db, def); for field in fields.iter() { let field_def = { match variant_data.field(&field.name) { @@ -1625,7 +1625,8 @@ fn lookup_field( }, _ => return None, }; - let is_visible = self.db.field_visibilities(field_id.parent)[field_id.local_id] + let is_visible = VariantFields::field_visibilities(self.db, field_id.parent) + [field_id.local_id] .is_visible_from(self.db, self.resolver.module()); if !is_visible { if private_field.is_none() { 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 0b6c9977f079..8033680dcc5c 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 @@ -6,6 +6,7 @@ HasModule as _, expr_store::{ExpressionStore, path::Path}, hir::{Binding, BindingAnnotation, BindingId, Expr, ExprId, Literal, Pat, PatId}, + signatures::VariantFields, }; use hir_expand::name::Name; use rustc_ast_ir::Mutability; @@ -60,7 +61,7 @@ pub(super) fn infer_tuple_struct_pat_like( Some(def) => { let field_types = self.db.field_types(def); let variant_data = def.fields(self.db); - let visibilities = self.db.field_visibilities(def); + let visibilities = VariantFields::field_visibilities(self.db, def); let (pre, post) = match ellipsis { Some(idx) => subs.split_at(idx as usize), @@ -129,7 +130,7 @@ pub(super) fn infer_record_pat_like( Some(def) => { let field_types = self.db.field_types(def); let variant_data = def.fields(self.db); - let visibilities = self.db.field_visibilities(def); + let visibilities = VariantFields::field_visibilities(self.db, def); let substs = ty.as_adt().map(TupleExt::tail); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/inhabitedness.rs b/src/tools/rust-analyzer/crates/hir-ty/src/inhabitedness.rs index 402e9ce96971..74d66123ea53 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/inhabitedness.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/inhabitedness.rs @@ -1,7 +1,9 @@ //! Type inhabitedness logic. use std::ops::ControlFlow::{self, Break, Continue}; -use hir_def::{AdtId, EnumVariantId, ModuleId, VariantId, visibility::Visibility}; +use hir_def::{ + AdtId, EnumVariantId, ModuleId, VariantId, signatures::VariantFields, visibility::Visibility, +}; use rustc_hash::FxHashSet; use rustc_type_ir::{ TypeSuperVisitable, TypeVisitable, TypeVisitor, @@ -151,7 +153,11 @@ fn visit_variant( let is_enum = matches!(variant, VariantId::EnumVariantId(..)); let field_tys = self.db().field_types(variant); - let field_vis = if is_enum { None } else { Some(self.db().field_visibilities(variant)) }; + let field_vis = if is_enum { + None + } else { + Some(VariantFields::field_visibilities(self.db(), variant)) + }; for (fid, _) in fields.iter() { self.visit_field(field_vis.as_ref().map(|it| it[fid]), &field_tys[fid].get(), subst)?; From d30c76d2c00a83843da04d0b81cb3f1139f3eb08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Sat, 28 Mar 2026 16:56:45 +0200 Subject: [PATCH 52/56] Replace truncate(0) with clear() --- .../rust-analyzer/crates/hir-ty/src/infer/closure/analysis.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 913d54e9697d..d720295d934b 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 @@ -897,7 +897,7 @@ fn restrict_precision_for_unsafe(&mut self) { if ty.is_raw_ptr() || ty.is_union() { capture.kind = CaptureKind::ByRef(BorrowKind::Shared); self.truncate_capture_spans(capture, 0); - capture.place.projections.truncate(0); + capture.place.projections.clear(); continue; } for (i, p) in capture.place.projections.iter().enumerate() { From 412b4fff350a2458850800bf5e73190709f88f9f Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sat, 28 Mar 2026 18:09:55 +0100 Subject: [PATCH 53/56] Fully implement `VariantFields` expression support --- .../crates/hir-def/src/expr_store.rs | 46 +++--- .../crates/hir-def/src/expr_store/body.rs | 6 +- .../crates/hir-def/src/expr_store/lower.rs | 29 ++-- .../hir-def/src/expr_store/lower/generics.rs | 4 +- .../crates/hir-def/src/expr_store/pretty.rs | 2 +- .../crates/hir-def/src/expr_store/scope.rs | 19 ++- .../rust-analyzer/crates/hir-def/src/lib.rs | 35 +++-- .../crates/hir-def/src/resolver.rs | 1 + .../crates/hir-def/src/signatures.rs | 6 +- .../crates/hir-ty/src/consteval.rs | 2 +- .../crates/hir-ty/src/diagnostics/expr.rs | 2 +- .../hir-ty/src/diagnostics/unsafe_check.rs | 30 ++-- .../rust-analyzer/crates/hir-ty/src/infer.rs | 68 ++++++++- .../hir-ty/src/infer/closure/analysis.rs | 13 ++ .../rust-analyzer/crates/hir-ty/src/lower.rs | 8 +- .../crates/hir-ty/src/mir/eval.rs | 4 +- .../crates/hir-ty/src/mir/lower.rs | 4 +- .../crates/hir-ty/src/next_solver/def_id.rs | 14 +- .../rust-analyzer/crates/hir-ty/src/upvars.rs | 2 +- .../rust-analyzer/crates/hir/src/attrs.rs | 14 +- .../rust-analyzer/crates/hir/src/display.rs | 10 +- .../rust-analyzer/crates/hir/src/from_id.rs | 91 ++++++++---- .../crates/hir/src/has_source.rs | 16 +-- src/tools/rust-analyzer/crates/hir/src/lib.rs | 133 +++++++++--------- .../rust-analyzer/crates/hir/src/semantics.rs | 67 ++++----- .../crates/hir/src/semantics/source_to_def.rs | 2 +- .../crates/hir/src/source_analyzer.rs | 113 ++++++++++----- .../crates/hir/src/term_search/expr.rs | 8 +- .../src/handlers/add_missing_match_arms.rs | 3 +- .../ide-assists/src/handlers/auto_import.rs | 2 +- .../src/handlers/convert_bool_then.rs | 10 +- .../convert_named_struct_to_tuple_struct.rs | 4 +- .../convert_tuple_struct_to_named_struct.rs | 4 +- .../src/handlers/expand_glob_import.rs | 4 +- .../src/handlers/expand_rest_pattern.rs | 2 +- .../src/handlers/extract_module.rs | 2 +- .../extract_struct_from_enum_variant.rs | 8 +- .../src/handlers/extract_variable.rs | 2 +- .../src/handlers/fix_visibility.rs | 2 +- .../replace_qualified_name_with_use.rs | 2 +- .../crates/ide-completion/src/completions.rs | 14 +- .../ide-completion/src/completions/pattern.rs | 4 +- .../ide-completion/src/completions/type.rs | 4 +- .../crates/ide-completion/src/context.rs | 4 +- .../ide-completion/src/context/analysis.rs | 8 +- .../crates/ide-completion/src/render.rs | 8 +- .../ide-completion/src/render/literal.rs | 4 +- .../ide-completion/src/render/pattern.rs | 2 +- .../crates/ide-db/src/active_parameter.rs | 4 +- .../rust-analyzer/crates/ide-db/src/defs.rs | 39 ++--- .../crates/ide-db/src/documentation.rs | 18 ++- .../rust-analyzer/crates/ide-db/src/lib.rs | 2 +- .../crates/ide-db/src/path_transform.rs | 2 +- .../rust-analyzer/crates/ide-db/src/rename.rs | 2 +- .../rust-analyzer/crates/ide-db/src/search.rs | 10 +- .../test_symbol_index_collection.txt | 8 +- .../src/handlers/no_such_field.rs | 8 +- .../rust-analyzer/crates/ide/src/doc_links.rs | 10 +- .../crates/ide/src/doc_links/tests.rs | 2 +- .../crates/ide/src/hover/render.rs | 16 +-- .../crates/ide/src/inlay_hints/param_name.rs | 2 +- .../rust-analyzer/crates/ide/src/moniker.rs | 2 +- .../crates/ide/src/navigation_target.rs | 8 +- .../crates/ide/src/references.rs | 4 +- .../rust-analyzer/crates/ide/src/runnables.rs | 2 +- .../crates/ide/src/signature_help.rs | 4 +- .../crates/ide/src/syntax_highlighting.rs | 37 ++--- .../ide/src/syntax_highlighting/highlight.rs | 2 +- .../ide/src/syntax_highlighting/inject.rs | 2 +- .../rust-analyzer/src/cli/analysis_stats.rs | 86 +++++++++-- 70 files changed, 693 insertions(+), 419 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 1ae89e170d9c..ca523622ec84 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 @@ -31,6 +31,7 @@ PatId, RecordFieldPat, RecordSpread, Statement, }, nameres::{DefMap, block_def_map}, + signatures::VariantFields, type_ref::{LifetimeRef, LifetimeRefId, PathId, TypeRef, TypeRefId}, }; @@ -95,7 +96,7 @@ pub(crate) fn is_root(self) -> bool { /// Used by signature/body inference to determine the expected type for each /// const expression root. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub enum ConstExprOrigin { +pub enum RootExprOrigin { /// Array length expression: `[T; ]` — expected type is `usize`. ArrayLength, /// Const parameter default value: `const N: usize = `. @@ -103,6 +104,8 @@ pub enum ConstExprOrigin { /// Const generic argument in a path: `SomeType::<{ }>` or `some_fn::<{ }>()`. /// Determining the expected type requires path resolution, so it is deferred. GenericArgsPath, + /// The root expression of a body. + BodyRoot, } // We split the store into types-only and expressions, because most stores (e.g. generics) @@ -125,11 +128,8 @@ struct ExpressionOnlyStore { /// to variables and have hygiene (some refer to items, we don't know at this stage). ident_hygiene: FxHashMap, - /// Maps const expression roots to their origin. - /// - /// Populated during lowering. Used by signature inference to determine expected types, - /// and by `signature_const_expr_roots()` to enumerate roots for scope computation. - const_expr_origins: ThinVec<(ExprId, ConstExprOrigin)>, + /// Maps expression roots to their origin. + expr_roots: SmallVec<[(ExprId, RootExprOrigin); 1]>, } #[derive(Debug, Clone, PartialEq, Eq)] @@ -243,7 +243,7 @@ pub struct ExpressionStoreBuilder { pub types: Arena, block_scopes: Vec, ident_hygiene: FxHashMap, - pub const_expr_origins: Option>, + pub 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). @@ -315,7 +315,7 @@ pub fn finish(self) -> (ExpressionStore, ExpressionStoreSourceMap) { mut bindings, mut binding_owners, mut ident_hygiene, - mut const_expr_origins, + inference_roots: mut expr_roots, mut types, mut lifetimes, @@ -375,7 +375,7 @@ pub fn finish(self) -> (ExpressionStore, ExpressionStoreSourceMap) { let store = { let expr_only = if has_exprs { - if let Some(const_expr_origins) = &mut const_expr_origins { + if let Some(const_expr_origins) = &mut expr_roots { const_expr_origins.shrink_to_fit(); } Some(Box::new(ExpressionOnlyStore { @@ -386,7 +386,7 @@ pub fn finish(self) -> (ExpressionStore, ExpressionStoreSourceMap) { binding_owners, block_scopes: block_scopes.into_boxed_slice(), ident_hygiene, - const_expr_origins: const_expr_origins.unwrap_or_default(), + expr_roots: expr_roots.unwrap_or_default(), })) } else { None @@ -448,6 +448,9 @@ pub fn of(db: &dyn DefDatabase, def: ExpressionStoreOwnerId) -> &ExpressionStore } } ExpressionStoreOwnerId::Body(body) => &Body::of(db, body).store, + ExpressionStoreOwnerId::VariantFields(variant_id) => { + &VariantFields::of(db, variant_id).store + } } } @@ -505,30 +508,27 @@ pub fn with_source_map( let (store, sm) = Body::with_source_map(db, body); (&store.store, &sm.store) } + ExpressionStoreOwnerId::VariantFields(variant_id) => { + let (store, sm) = VariantFields::with_source_map(db, variant_id); + (&store.store, sm) + } } } - /// Returns all const expression root `ExprId`s found in this store. - /// - /// Used to compute expression scopes for signature stores. - pub fn signature_const_expr_roots(&self) -> impl Iterator { + /// Returns all expression root `ExprId`s found in this store. + pub fn expr_roots(&self) -> impl Iterator { self.const_expr_origins().iter().map(|&(id, _)| id) } /// Like [`Self::signature_const_expr_roots`], but also returns the origin - /// of each const expression. - /// - /// This is used by signature inference to determine the expected type for - /// each root expression. - pub fn signature_const_expr_roots_with_origins( - &self, - ) -> impl Iterator { + /// of each expression. + pub fn expr_roots_with_origins(&self) -> impl Iterator { self.const_expr_origins().iter().map(|&(id, origin)| (id, origin)) } /// Returns the map of const expression roots to their origins. - pub fn const_expr_origins(&self) -> &[(ExprId, ConstExprOrigin)] { - self.expr_only.as_ref().map_or(&[], |it| &it.const_expr_origins) + pub fn const_expr_origins(&self) -> &[(ExprId, RootExprOrigin)] { + self.expr_only.as_ref().map_or(&[], |it| &it.expr_roots) } /// Returns an iterator over all block expressions in this store that define inner items. diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/body.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/body.rs index 60aaba5b84db..0c8320369f66 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/body.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/body.rs @@ -29,8 +29,6 @@ pub struct Body { /// empty. pub params: Box<[PatId]>, pub self_param: Option, - /// The `ExprId` of the actual body expression. - pub body_expr: ExprId, } impl ops::Deref for Body { @@ -115,6 +113,10 @@ pub fn of(db: &dyn DefDatabase, def: DefWithBodyId) -> Arc { } impl Body { + pub fn root_expr(&self) -> ExprId { + self.store.expr_roots().next().unwrap() + } + pub fn pretty_print( &self, db: &dyn DefDatabase, 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 afa1c7fcfd5b..74006c603703 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 @@ -18,6 +18,7 @@ }; use intern::{Symbol, sym}; use rustc_hash::FxHashMap; +use smallvec::smallvec; use stdx::never; use syntax::{ AstNode, AstPtr, SyntaxNodePtr, @@ -36,9 +37,9 @@ attrs::AttrFlags, db::DefDatabase, expr_store::{ - Body, BodySourceMap, ConstExprOrigin, ExprPtr, ExpressionStore, ExpressionStoreBuilder, + Body, BodySourceMap, ExprPtr, ExpressionStore, ExpressionStoreBuilder, ExpressionStoreDiagnostics, ExpressionStoreSourceMap, HygieneId, LabelPtr, LifetimePtr, - PatPtr, TypePtr, + PatPtr, RootExprOrigin, TypePtr, expander::Expander, lower::generics::ImplTraitLowerFn, path::{AssociatedTypeBinding, GenericArg, GenericArgs, GenericArgsParentheses, Path}, @@ -117,9 +118,10 @@ pub(super) fn lower_body( params = (0..count).map(|_| collector.missing_pat()).collect(); }; let body_expr = collector.missing_expr(); + collector.store.inference_roots = Some(smallvec![(body_expr, RootExprOrigin::BodyRoot)]); let (store, source_map) = collector.store.finish(); return ( - Body { store, params: params.into_boxed_slice(), self_param, body_expr }, + Body { store, params: params.into_boxed_slice(), self_param }, BodySourceMap { self_param: source_map_self_param, store: source_map }, ); } @@ -173,10 +175,11 @@ pub(super) fn lower_body( } }, ); + collector.store.inference_roots = Some(smallvec![(body_expr, RootExprOrigin::BodyRoot)]); let (store, source_map) = collector.store.finish(); ( - Body { store, params: params.into_boxed_slice(), self_param, body_expr }, + Body { store, params: params.into_boxed_slice(), self_param }, BodySourceMap { self_param: source_map_self_param, store: source_map }, ) } @@ -535,7 +538,7 @@ pub fn signature( current_file_id: HirFileId, ) -> ExprCollector<'_> { let mut this = Self::body(db, module, current_file_id); - this.store.const_expr_origins = Some(Default::default()); + this.store.inference_roots = Some(Default::default()); this } @@ -635,8 +638,8 @@ pub(in crate::expr_store) fn lower_type_ref( } ast::Type::ArrayType(inner) => { let len = self.lower_const_arg_opt(inner.const_arg()); - if let Some(const_expr_origins) = &mut self.store.const_expr_origins { - const_expr_origins.push((len.expr, ConstExprOrigin::ArrayLength)); + if let Some(const_expr_origins) = &mut self.store.inference_roots { + const_expr_origins.push((len.expr, RootExprOrigin::ArrayLength)); } TypeRef::Array(ArrayType { ty: self.lower_type_ref_opt(inner.ty(), impl_trait_lower_fn), @@ -922,8 +925,8 @@ pub(super) fn lower_generic_args( } ast::GenericArg::ConstArg(arg) => { let arg = self.lower_const_arg(arg); - if let Some(const_expr_origins) = &mut self.store.const_expr_origins { - const_expr_origins.push((arg.expr, ConstExprOrigin::GenericArgsPath)); + if let Some(const_expr_origins) = &mut self.store.inference_roots { + const_expr_origins.push((arg.expr, RootExprOrigin::GenericArgsPath)); } args.push(GenericArg::Const(arg)) } @@ -1065,16 +1068,16 @@ fn lower_type_bound( } fn lower_const_arg_opt(&mut self, arg: Option) -> ConstRef { - let const_expr_origins = self.store.const_expr_origins.take(); + let const_expr_origins = self.store.inference_roots.take(); let r = ConstRef { expr: self.collect_expr_opt(arg.and_then(|it| it.expr())) }; - self.store.const_expr_origins = const_expr_origins; + self.store.inference_roots = const_expr_origins; r } pub fn lower_const_arg(&mut self, arg: ast::ConstArg) -> ConstRef { - let const_expr_origins = self.store.const_expr_origins.take(); + let const_expr_origins = self.store.inference_roots.take(); let r = ConstRef { expr: self.collect_expr_opt(arg.expr()) }; - self.store.const_expr_origins = const_expr_origins; + self.store.inference_roots = const_expr_origins; r } 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 7c7b6971647e..5ffc4f5851d3 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 @@ -130,11 +130,11 @@ fn lower_param_list(&mut self, ec: &mut ExprCollector<'_>, params: ast::GenericP let param = ConstParamData { name, ty, default }; let idx = self.type_or_consts.alloc(param.into()); if let Some(default) = default - && let Some(const_expr_origins) = &mut ec.store.const_expr_origins + && let Some(const_expr_origins) = &mut ec.store.inference_roots { const_expr_origins.push(( default.expr, - crate::expr_store::ConstExprOrigin::ConstParam(idx), + crate::expr_store::RootExprOrigin::ConstParam(idx), )); } } 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 39e0153ded37..9c9c4db3b208 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 @@ -105,7 +105,7 @@ pub fn print_body_hir( p.buf.push(')'); p.buf.push(' '); } - p.print_expr(body.body_expr); + p.print_expr(body.root_expr()); if matches!(owner, DefWithBodyId::StaticId(_) | DefWithBodyId::ConstId(_)) { p.buf.push(';'); } 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 22a3a7b07900..40ae0b7de462 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 @@ -3,13 +3,14 @@ use la_arena::{Arena, ArenaMap, Idx, IdxRange, RawIdx}; use crate::{ - BlockId, DefWithBodyId, ExpressionStoreOwnerId, GenericDefId, + BlockId, DefWithBodyId, ExpressionStoreOwnerId, GenericDefId, VariantId, db::DefDatabase, expr_store::{Body, ExpressionStore, HygieneId}, hir::{ Binding, BindingId, Expr, ExprId, Item, LabelId, Pat, PatId, Statement, generics::GenericParams, }, + signatures::VariantFields, }; pub type ScopeId = Idx; @@ -65,11 +66,20 @@ pub fn body_expr_scopes(db: &dyn DefDatabase, def: DefWithBodyId) -> ExprScopes #[salsa::tracked(returns(ref))] pub fn sig_expr_scopes(db: &dyn DefDatabase, def: GenericDefId) -> ExprScopes { let (_, store) = GenericParams::with_store(db, def); - let roots = store.signature_const_expr_roots(); + let roots = store.expr_roots(); let mut scopes = ExprScopes::new_store(store, roots); scopes.shrink_to_fit(); scopes } + + #[salsa::tracked(returns(ref))] + pub fn variant_scopes(db: &dyn DefDatabase, def: VariantId) -> ExprScopes { + let fields = VariantFields::of(db, def); + let roots = fields.store.expr_roots(); + let mut scopes = ExprScopes::new_store(&fields.store, roots); + scopes.shrink_to_fit(); + scopes + } } impl ExprScopes { @@ -78,6 +88,9 @@ pub fn of(db: &dyn DefDatabase, def: impl Into) -> &Expr match def.into() { ExpressionStoreOwnerId::Body(def) => Self::body_expr_scopes(db, def), ExpressionStoreOwnerId::Signature(def) => Self::sig_expr_scopes(db, def), + ExpressionStoreOwnerId::VariantFields(variant_id) => { + Self::variant_scopes(db, variant_id) + } } } @@ -138,7 +151,7 @@ fn new_body(body: &Body) -> ExprScopes { scopes.add_bindings(body, root, self_param, body.binding_hygiene(self_param)); } scopes.add_params_bindings(body, root, &body.params); - compute_expr_scopes(body.body_expr, body, &mut scopes, &mut root); + compute_expr_scopes(body.root_expr(), body, &mut scopes, &mut root); scopes } 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 800c08aa2c96..9a7fbc812f87 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs @@ -756,19 +756,17 @@ pub fn name(self, db: &dyn DefDatabase) -> String { } } -/// The defs which have a body (have root expressions for type inference). +/// The defs which have a body. #[derive(Debug, PartialOrd, Ord, Clone, Copy, PartialEq, Eq, Hash, salsa_macros::Supertype)] pub enum DefWithBodyId { + /// A function body. FunctionId(FunctionId), + /// A static item initializer. StaticId(StaticId), + /// A const item initializer ConstId(ConstId), + /// An enum variant discrimiant VariantId(EnumVariantId), - // /// All fields of a variant are inference roots - // VariantId(VariantId), - // /// The signature can contain inference roots in a bunch of places - // /// like const parameters or const arguments in paths - // This should likely be kept on its own with a separate query - // GenericDefId(GenericDefId), } impl_from!(FunctionId, ConstId, StaticId for DefWithBodyId); @@ -840,10 +838,15 @@ pub enum GenericDefId { /// Owner of an expression store - either a body or a signature. /// This is used for queries that operate on expression stores generically, /// such as `expr_scopes`. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] +// NOTE: This type cannot be `salsa::Supertype` as its variants are overlapping. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord /* !salsa::Supertype */)] pub enum ExpressionStoreOwnerId { Signature(GenericDefId), + /// A body, something with a root expression. + /// + /// An enum variant's body is considered its discriminant initializer. Body(DefWithBodyId), + VariantFields(VariantId), } impl ExpressionStoreOwnerId { @@ -861,6 +864,11 @@ pub fn generic_def(self, db: &dyn DefDatabase) -> GenericDefId { DefWithBodyId::ConstId(id) => GenericDefId::ConstId(id), DefWithBodyId::VariantId(it) => it.lookup(db).parent.into(), }, + ExpressionStoreOwnerId::VariantFields(variant_id) => match variant_id { + VariantId::EnumVariantId(it) => it.lookup(db).parent.into(), + VariantId::StructId(it) => it.into(), + VariantId::UnionId(it) => it.into(), + }, } } } @@ -877,6 +885,12 @@ fn from(id: DefWithBodyId) -> Self { } } +impl From for ExpressionStoreOwnerId { + fn from(id: VariantId) -> Self { + ExpressionStoreOwnerId::VariantFields(id) + } +} + impl GenericDefId { pub fn file_id_and_params_of( self, @@ -1017,7 +1031,9 @@ fn from(vid: VariantId) -> Self { } } -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, salsa_macros::Supertype, salsa::Update)] +#[derive( + Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, salsa_macros::Supertype, salsa::Update, +)] pub enum VariantId { EnumVariantId(EnumVariantId), StructId(StructId), @@ -1241,6 +1257,7 @@ fn module(&self, db: &dyn DefDatabase) -> ModuleId { match self { ExpressionStoreOwnerId::Signature(def) => def.module(db), ExpressionStoreOwnerId::Body(def) => def.module(db), + ExpressionStoreOwnerId::VariantFields(variant_id) => variant_id.module(db), } } } 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 dee7800e8428..bb292ac1a6bc 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs @@ -1419,6 +1419,7 @@ fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> { match self { ExpressionStoreOwnerId::Signature(def) => def.resolver(db), ExpressionStoreOwnerId::Body(def) => def.resolver(db), + ExpressionStoreOwnerId::VariantFields(variant_id) => variant_id.resolver(db), } } } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/signatures.rs b/src/tools/rust-analyzer/crates/hir-def/src/signatures.rs index 9d988c821ab7..6d704274f45d 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/signatures.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/signatures.rs @@ -848,7 +848,7 @@ pub struct VariantFields { #[salsa::tracked] impl VariantFields { #[salsa::tracked(returns(ref))] - pub(crate) fn with_source_map( + pub fn with_source_map( db: &dyn DefDatabase, id: VariantId, ) -> (Arc, ExpressionStoreSourceMap) { @@ -906,7 +906,7 @@ pub(crate) fn with_source_map( } #[salsa::tracked(returns(deref))] - pub(crate) fn of(db: &dyn DefDatabase, id: VariantId) -> Arc { + pub fn of(db: &dyn DefDatabase, id: VariantId) -> Arc { Self::with_source_map(db, id).0.clone() } } @@ -1101,7 +1101,7 @@ pub fn is_payload_free(&self, db: &dyn DefDatabase) -> bool { if !matches!(variant.shape, FieldsShape::Unit) { let body = Body::of(db, v.into()); // A variant with explicit discriminant - if !matches!(body[body.body_expr], crate::hir::Expr::Missing) { + if !matches!(body[body.root_expr()], crate::hir::Expr::Missing) { return false; } } 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 673d00d956ad..928396c63aaf 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs @@ -276,7 +276,7 @@ pub(crate) fn const_eval_discriminant_variant( let def = variant_id.into(); let body = Body::of(db, def); let loc = variant_id.lookup(db); - if matches!(body[body.body_expr], Expr::Missing) { + if matches!(body[body.root_expr()], Expr::Missing) { let prev_idx = loc.index.checked_sub(1); let value = match prev_idx { Some(prev_idx) => { 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 e227be6995d0..33d9dd538dd3 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 @@ -119,7 +119,7 @@ fn validate_body(&mut self) { let body = self.body; if matches!(self.owner, DefWithBodyId::FunctionId(_)) { - self.check_for_trailing_return(body.body_expr, body); + self.check_for_trailing_return(body.root_expr(), body); } for (id, expr) in body.exprs() { 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 ba9b7416b76c..09c648139c45 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs @@ -5,8 +5,9 @@ use either::Either; use hir_def::{ - AdtId, CallableDefId, DefWithBodyId, FieldId, FunctionId, VariantId, - expr_store::{Body, path::Path}, + AdtId, CallableDefId, DefWithBodyId, ExpressionStoreOwnerId, FieldId, FunctionId, GenericDefId, + VariantId, + expr_store::{Body, ExpressionStore, path::Path}, hir::{AsmOperand, Expr, ExprId, ExprOrPatId, InlineAsmKind, Pat, PatId, Statement, UnaryOp}, resolver::{HasResolver, ResolveValueResult, Resolver, ValueNs}, signatures::{FunctionSignature, StaticFlags, StaticSignature}, @@ -55,8 +56,8 @@ pub fn missing_unsafe(db: &dyn HirDatabase, def: DefWithBodyId) -> MissingUnsafe } } }; - let mut visitor = UnsafeVisitor::new(db, infer, body, def, &mut callback); - visitor.walk_expr(body.body_expr); + let mut visitor = UnsafeVisitor::new(db, infer, body, def.into(), &mut callback); + visitor.walk_expr(body.root_expr()); if !is_unsafe { // Unsafety in function parameter patterns (that can only be union destructuring) @@ -109,8 +110,8 @@ pub fn unsafe_operations_for_body( callback(node); } }; - let mut visitor = UnsafeVisitor::new(db, infer, body, def, &mut visitor_callback); - visitor.walk_expr(body.body_expr); + let mut visitor = UnsafeVisitor::new(db, infer, body, def.into(), &mut visitor_callback); + visitor.walk_expr(body.root_expr()); for ¶m in &body.params { visitor.walk_pat(param); } @@ -119,8 +120,8 @@ pub fn unsafe_operations_for_body( pub fn unsafe_operations( db: &dyn HirDatabase, infer: &InferenceResult, - def: DefWithBodyId, - body: &Body, + def: ExpressionStoreOwnerId, + body: &ExpressionStore, current: ExprId, callback: &mut dyn FnMut(ExprOrPatId, InsideUnsafeBlock), ) { @@ -137,9 +138,9 @@ pub fn unsafe_operations( struct UnsafeVisitor<'db> { db: &'db dyn HirDatabase, infer: &'db InferenceResult, - body: &'db Body, + body: &'db ExpressionStore, resolver: Resolver<'db>, - def: DefWithBodyId, + def: ExpressionStoreOwnerId, inside_unsafe_block: InsideUnsafeBlock, inside_assignment: bool, inside_union_destructure: bool, @@ -156,13 +157,16 @@ impl<'db> UnsafeVisitor<'db> { fn new( db: &'db dyn HirDatabase, infer: &'db InferenceResult, - body: &'db Body, - def: DefWithBodyId, + body: &'db ExpressionStore, + def: ExpressionStoreOwnerId, unsafe_expr_cb: &'db mut dyn FnMut(UnsafeDiagnostic), ) -> Self { let resolver = def.resolver(db); let def_target_features = match def { - DefWithBodyId::FunctionId(func) => TargetFeatures::from_fn(db, func), + ExpressionStoreOwnerId::Body(DefWithBodyId::FunctionId(func)) + | ExpressionStoreOwnerId::Signature(GenericDefId::FunctionId(func)) => { + TargetFeatures::from_fn(db, func) + } _ => TargetFeatures::default(), }; let krate = resolver.krate(); 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 52edbc899ffa..d14e9d652654 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs @@ -36,7 +36,7 @@ AdtId, AssocItemId, ConstId, ConstParamId, DefWithBodyId, ExpressionStoreOwnerId, FieldId, FunctionId, GenericDefId, GenericParamId, ItemContainerId, LocalFieldId, Lookup, TraitId, TupleFieldId, TupleId, TypeAliasId, TypeOrConstParamId, VariantId, - expr_store::{Body, ConstExprOrigin, ExpressionStore, HygieneId, path::Path}, + expr_store::{Body, ExpressionStore, HygieneId, RootExprOrigin, path::Path}, hir::{BindingAnnotation, BindingId, ExprId, ExprOrPatId, LabelId, PatId}, lang_item::LangItems, layout::Integer, @@ -143,9 +143,9 @@ pub fn infer_query_with_inspect<'db>( } } - ctx.infer_body(body.body_expr); + ctx.infer_body(body.root_expr()); - ctx.infer_mut_body(body.body_expr); + ctx.infer_mut_body(body.root_expr()); infer_finalize(ctx) } @@ -166,7 +166,7 @@ fn infer_cycle_result(db: &dyn HirDatabase, _: salsa::Id, _: DefWithBodyId) -> I fn infer_signature_query(db: &dyn HirDatabase, def: GenericDefId) -> InferenceResult { let _p = tracing::info_span!("infer_signature_query").entered(); let store = ExpressionStore::of(db, def.into()); - let mut roots = store.signature_const_expr_roots_with_origins().peekable(); + let mut roots = store.expr_roots_with_origins().peekable(); let Some(_) = roots.peek() else { return InferenceResult::new(crate::next_solver::default_types(db).types.error); }; @@ -179,15 +179,47 @@ fn infer_signature_query(db: &dyn HirDatabase, def: GenericDefId) -> InferenceRe for (root_expr, origin) in roots { let expected = match origin { // Array lengths are always `usize`. - ConstExprOrigin::ArrayLength => Expectation::has_type(ctx.types.types.usize), + RootExprOrigin::ArrayLength => Expectation::has_type(ctx.types.types.usize), // Const parameter default: look up the param's declared type. - ConstExprOrigin::ConstParam(local_id) => Expectation::has_type(db.const_param_ty_ns( + RootExprOrigin::ConstParam(local_id) => Expectation::has_type(db.const_param_ty_ns( ConstParamId::from_unchecked(TypeOrConstParamId { parent: def, local_id }), )), // Path const generic args: determining the expected type requires // path resolution. // FIXME - ConstExprOrigin::GenericArgsPath => Expectation::None, + RootExprOrigin::GenericArgsPath => Expectation::None, + RootExprOrigin::BodyRoot => Expectation::None, + }; + ctx.infer_expr(root_expr, &expected, ExprIsRead::Yes); + } + + infer_finalize(ctx) +} + +fn infer_variant_fields_query(db: &dyn HirDatabase, def: VariantId) -> InferenceResult { + let _p = tracing::info_span!("infer_variant_fields_query").entered(); + let store = ExpressionStore::of(db, def.into()); + let mut roots = store.expr_roots_with_origins().peekable(); + let Some(_) = roots.peek() else { + return InferenceResult::new(crate::next_solver::default_types(db).types.error); + }; + + let resolver = def.resolver(db); + let owner = ExpressionStoreOwnerId::VariantFields(def); + + let mut ctx = InferenceContext::new(db, owner, store, resolver); + + for (root_expr, origin) in roots { + let expected = match origin { + // Array lengths are always `usize`. + RootExprOrigin::ArrayLength => Expectation::has_type(ctx.types.types.usize), + // unreachable + RootExprOrigin::ConstParam(_) => Expectation::None, + // Path const generic args: determining the expected type requires + // path resolution. + // FIXME + RootExprOrigin::GenericArgsPath => Expectation::None, + RootExprOrigin::BodyRoot => Expectation::None, }; ctx.infer_expr(root_expr, &expected, ExprIsRead::Yes); } @@ -206,6 +238,17 @@ fn infer_signature_cycle_result( } } +fn infer_variant_fields_cycle_result( + db: &dyn HirDatabase, + _: salsa::Id, + _: VariantId, +) -> InferenceResult { + InferenceResult { + has_errors: true, + ..InferenceResult::new(Ty::new_error(DbInterner::new_no_crate(db), ErrorGuaranteed)) + } +} + fn infer_finalize(mut ctx: InferenceContext<'_, '_>) -> InferenceResult { ctx.handle_opaque_type_uses(); @@ -617,6 +660,11 @@ fn for_body(db: &dyn HirDatabase, def: DefWithBodyId) -> InferenceResult { fn for_signature(db: &dyn HirDatabase, def: GenericDefId) -> InferenceResult { infer_signature_query(db, def) } + + #[salsa::tracked(returns(ref), cycle_result = infer_variant_fields_cycle_result)] + fn for_variant_fields(db: &dyn HirDatabase, def: VariantId) -> InferenceResult { + infer_variant_fields_query(db, def) + } } impl InferenceResult { @@ -626,6 +674,9 @@ pub fn of(db: &dyn HirDatabase, def: impl Into) -> &Infe Self::for_signature(db, generic_def_id) } ExpressionStoreOwnerId::Body(def_with_body_id) => Self::for_body(db, def_with_body_id), + ExpressionStoreOwnerId::VariantFields(variant_id) => { + Self::for_variant_fields(db, variant_id) + } } } @@ -937,6 +988,9 @@ fn new( ExpressionStoreOwnerId::Body(def_with_body_id) => { db.trait_environment(ExpressionStoreOwnerId::Body(def_with_body_id)) } + ExpressionStoreOwnerId::VariantFields(variant_id) => { + db.trait_environment(ExpressionStoreOwnerId::VariantFields(variant_id)) + } }; let table = unify::InferenceTable::new(db, trait_env, resolver.krate(), Some(owner)); let types = crate::next_solver::default_types(db); 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 913d54e9697d..5abb96978dad 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 @@ -12,6 +12,7 @@ }, item_tree::FieldsShape, resolver::ValueNs, + signatures::VariantFields, }; use rustc_ast_ir::Mutability; use rustc_hash::{FxHashMap, FxHashSet}; @@ -194,6 +195,10 @@ pub fn place_to_name(&self, owner: ExpressionStoreOwnerId, db: &dyn HirDatabase) .name .display(db, edition) .to_string(), + ExpressionStoreOwnerId::VariantFields(variant_id) => { + let fields = VariantFields::of(db, variant_id); + fields.store[self.place.local].name.display(db, edition).to_string() + } }; for proj in &self.place.projections { match proj { @@ -245,6 +250,10 @@ pub fn display_place_source_code( .name .display(db, edition) .to_string(), + ExpressionStoreOwnerId::VariantFields(variant_id) => { + let fields = VariantFields::of(db, variant_id); + fields.store[self.place.local].name.display(db, edition).to_string() + } }; for proj in &self.place.projections { match proj { @@ -301,6 +310,10 @@ pub fn display_place(&self, owner: ExpressionStoreOwnerId, db: &dyn HirDatabase) .name .display(db, edition) .to_string(), + ExpressionStoreOwnerId::VariantFields(variant_id) => { + let fields = VariantFields::of(db, variant_id); + fields.store[self.place.local].name.display(db, edition).to_string() + } }; let mut field_need_paren = false; for proj in &self.place.projections { 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 5eee025f2c00..7259099107ca 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs @@ -2156,13 +2156,7 @@ pub(crate) fn trait_environment<'db>( db: &'db dyn HirDatabase, def: ExpressionStoreOwnerId, ) -> ParamEnv<'db> { - let def = match def { - ExpressionStoreOwnerId::Signature(def) => def, - ExpressionStoreOwnerId::Body(def) => match def.as_generic_def_id(db) { - Some(def) => def, - None => return ParamEnv::empty(), - }, - }; + let def = def.generic_def(db); return ParamEnv { clauses: trait_environment_query(db, def).as_ref() }; 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 c013e78d81b8..505db1776f28 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 @@ -900,7 +900,7 @@ fn operand_ty(&self, o: &Operand, locals: &Locals) -> Result<'db, Ty<'db>> { OperandKind::Constant { konst: _, ty } => ty.as_ref(), &OperandKind::Static(s) => { let ty = InferenceResult::of(self.db, DefWithBodyId::from(s)) - .expr_ty(Body::of(self.db, s.into()).body_expr); + .expr_ty(Body::of(self.db, s.into()).root_expr()); Ty::new_ref( self.interner(), Region::new_static(self.interner()), @@ -2835,7 +2835,7 @@ fn eval_static(&mut self, st: StaticId, locals: &Locals) -> Result<'db, Address> self.allocate_const_in_heap(locals, konst)? } else { let ty = InferenceResult::of(self.db, DefWithBodyId::from(st)) - .expr_ty(Body::of(self.db, st.into()).body_expr); + .expr_ty(Body::of(self.db, st.into()).root_expr()); let Some((size, align)) = self.size_align_of(ty, locals)? else { not_supported!("unsized extern static"); }; 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 675fc371c619..44785d948a49 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 @@ -2251,7 +2251,7 @@ pub fn mir_body_query<'db>( let _p = tracing::info_span!("mir_body_query", ?detail).entered(); let body = Body::of(db, def); let infer = InferenceResult::of(db, def); - let mut result = lower_body_to_mir(db, def, body, infer, body.body_expr)?; + let mut result = lower_body_to_mir(db, def, body, infer, body.root_expr())?; result.shrink_to_fit(); Ok(Arc::new(result)) } @@ -2275,7 +2275,7 @@ pub fn lower_body_to_mir<'db>( // but this is currently also used for `X` in `[(); X]` which live in the same expression store root_expr: ExprId, ) -> Result<'db, MirBody> { - let is_root = root_expr == body.body_expr; + let is_root = root_expr == body.root_expr(); // Extract params and self_param only when lowering the body's root expression for a function. if is_root && let DefWithBodyId::FunctionId(fid) = owner { let callable_sig = 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 5d122ce446ad..00161d6d0825 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 @@ -3,7 +3,7 @@ use hir_def::{ AdtId, AnonConstId, AttrDefId, BuiltinDeriveImplId, CallableDefId, ConstId, DefWithBodyId, EnumId, EnumVariantId, ExpressionStoreOwnerId, FunctionId, GeneralConstId, GenericDefId, - ImplId, StaticId, StructId, TraitId, TypeAliasId, UnionId, + ImplId, StaticId, StructId, TraitId, TypeAliasId, UnionId, VariantId, signatures::{ ConstSignature, EnumSignature, FunctionSignature, StaticSignature, StructSignature, TraitSignature, TypeAliasSignature, UnionSignature, @@ -166,12 +166,24 @@ fn from(value: DefWithBodyId) -> Self { } } +impl From for SolverDefId { + #[inline] + fn from(value: VariantId) -> Self { + match value { + VariantId::EnumVariantId(id) => id.into(), + VariantId::StructId(id) => id.into(), + VariantId::UnionId(id) => id.into(), + } + } +} + impl From for SolverDefId { #[inline] fn from(value: ExpressionStoreOwnerId) -> Self { match value { ExpressionStoreOwnerId::Body(body_id) => body_id.into(), ExpressionStoreOwnerId::Signature(sig_id) => sig_id.into(), + ExpressionStoreOwnerId::VariantFields(variant_id) => variant_id.into(), } } } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/upvars.rs b/src/tools/rust-analyzer/crates/hir-ty/src/upvars.rs index d19fbbc18793..489895fe3cb7 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/upvars.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/upvars.rs @@ -47,7 +47,7 @@ pub fn upvars_mentioned( let body = Body::of(db, owner); let mut resolver = owner.resolver(db); let mut result = FxHashMap::default(); - handle_expr_outside_closure(db, &mut resolver, owner, body, body.body_expr, &mut result); + handle_expr_outside_closure(db, &mut resolver, owner, body, body.root_expr(), &mut result); return if result.is_empty() { None } else { diff --git a/src/tools/rust-analyzer/crates/hir/src/attrs.rs b/src/tools/rust-analyzer/crates/hir/src/attrs.rs index 4efb7fcb6f2b..27e798514610 100644 --- a/src/tools/rust-analyzer/crates/hir/src/attrs.rs +++ b/src/tools/rust-analyzer/crates/hir/src/attrs.rs @@ -27,9 +27,9 @@ use stdx::never; use crate::{ - Adt, AsAssocItem, AssocItem, BuiltinType, Const, ConstParam, DocLinkDef, Enum, ExternCrateDecl, - Field, Function, GenericParam, HasCrate, Impl, LangItem, LifetimeParam, Macro, Module, - ModuleDef, Static, Struct, Trait, Type, TypeAlias, TypeParam, Union, Variant, VariantDef, + Adt, AsAssocItem, AssocItem, BuiltinType, Const, ConstParam, DocLinkDef, Enum, EnumVariant, + ExternCrateDecl, Field, Function, GenericParam, HasCrate, Impl, LangItem, LifetimeParam, Macro, + Module, ModuleDef, Static, Struct, Trait, Type, TypeAlias, TypeParam, Union, Variant, }; #[derive(Debug, Clone, Copy)] @@ -200,7 +200,7 @@ fn attr_id(self, _db: &dyn HirDatabase) -> AttrsOwner { } impl_has_attrs![ - (Variant, EnumVariantId), + (EnumVariant, EnumVariantId), (Static, StaticId), (Const, ConstId), (Trait, TraitId), @@ -407,7 +407,7 @@ fn resolve_assoc_or_field( TypeNs::AdtId(id) | TypeNs::AdtSelfType(id) => Adt::from(id).ty(db), TypeNs::EnumVariantId(id) => { // Enum variants don't have path candidates. - let variant = Variant::from(id); + let variant = EnumVariant::from(id); return resolve_field(db, variant.into(), name, ns); } TypeNs::TypeAliasId(id) => { @@ -444,7 +444,7 @@ fn resolve_assoc_or_field( .id .enum_variants(db) .variant(&name) - .map(|variant| DocLinkDef::ModuleDef(ModuleDef::Variant(variant.into()))); + .map(|variant| DocLinkDef::ModuleDef(ModuleDef::EnumVariant(variant.into()))); } }; resolve_field(db, variant_def, name, ns) @@ -506,7 +506,7 @@ fn resolve_impl_trait_item<'db>( fn resolve_field( db: &dyn HirDatabase, - def: VariantDef, + def: Variant, name: Name, ns: Option, ) -> Option { diff --git a/src/tools/rust-analyzer/crates/hir/src/display.rs b/src/tools/rust-analyzer/crates/hir/src/display.rs index ef885f0be8a2..4bfdd239f937 100644 --- a/src/tools/rust-analyzer/crates/hir/src/display.rs +++ b/src/tools/rust-analyzer/crates/hir/src/display.rs @@ -29,9 +29,9 @@ use crate::{ Adt, AnyFunctionId, AsAssocItem, AssocItem, AssocItemContainer, Const, ConstParam, Crate, Enum, - ExternCrateDecl, Field, Function, GenericParam, HasCrate, HasVisibility, Impl, LifetimeParam, - Macro, Module, SelfParam, Static, Struct, StructKind, Trait, TraitRef, TupleField, Type, - TypeAlias, TypeNs, TypeOrConstParam, TypeParam, Union, Variant, + EnumVariant, ExternCrateDecl, Field, Function, GenericParam, HasCrate, HasVisibility, Impl, + LifetimeParam, Macro, Module, SelfParam, Static, Struct, StructKind, Trait, TraitRef, + TupleField, Type, TypeAlias, TypeNs, TypeOrConstParam, TypeParam, Union, }; fn write_builtin_derive_impl_method<'db>( @@ -443,7 +443,7 @@ fn write_fields<'db>( } fn write_variants<'db>( - variants: &[Variant], + variants: &[EnumVariant], has_where_clause: bool, limit: usize, f: &mut HirFormatter<'_, 'db>, @@ -497,7 +497,7 @@ fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result { } } -impl<'db> HirDisplay<'db> for Variant { +impl<'db> HirDisplay<'db> for EnumVariant { fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result { write!(f, "{}", self.name(f.db).display(f.db, f.edition()))?; let data = self.id.fields(f.db); 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 1aeed874af45..0a48be5473d2 100644 --- a/src/tools/rust-analyzer/crates/hir/src/from_id.rs +++ b/src/tools/rust-analyzer/crates/hir/src/from_id.rs @@ -5,14 +5,14 @@ use hir_def::{ AdtId, AssocItemId, BuiltinDeriveImplId, DefWithBodyId, EnumVariantId, ExpressionStoreOwnerId, - FieldId, GenericDefId, GenericParamId, ModuleDefId, VariantId, + FieldId, FunctionId, GenericDefId, GenericParamId, ImplId, ModuleDefId, VariantId, hir::{BindingId, LabelId}, }; use hir_ty::next_solver::AnyImplId; use crate::{ - Adt, AnyFunctionId, AssocItem, BuiltinType, DefWithBody, Field, GenericDef, GenericParam, - ItemInNs, Label, Local, ModuleDef, Variant, VariantDef, + Adt, AnyFunctionId, AssocItem, BuiltinType, DefWithBody, EnumVariant, ExpressionStoreOwner, + Field, Function, GenericDef, GenericParam, Impl, ItemInNs, Label, Local, ModuleDef, Variant, }; macro_rules! from_id { @@ -71,6 +71,15 @@ fn from(id: Adt) -> Self { } } +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 for GenericParam { fn from(id: GenericParamId) -> Self { match id { @@ -91,14 +100,14 @@ fn from(id: GenericParam) -> Self { } } -impl From for Variant { +impl From for EnumVariant { fn from(id: EnumVariantId) -> Self { - Variant { id } + EnumVariant { id } } } -impl From for EnumVariantId { - fn from(def: Variant) -> Self { +impl From for EnumVariantId { + fn from(def: EnumVariant) -> Self { def.id } } @@ -109,7 +118,7 @@ fn from(id: ModuleDefId) -> Self { 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::Variant(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()), @@ -130,7 +139,7 @@ fn try_from(id: ModuleDef) -> Result { AnyFunctionId::BuiltinDeriveImplMethod { .. } => return Err(()), }, ModuleDef::Adt(it) => ModuleDefId::AdtId(it.into()), - ModuleDef::Variant(it) => ModuleDefId::EnumVariantId(it.into()), + ModuleDef::EnumVariant(it) => ModuleDefId::EnumVariantId(it.into()), ModuleDef::Const(it) => ModuleDefId::ConstId(it.into()), ModuleDef::Static(it) => ModuleDefId::StaticId(it.into()), ModuleDef::Trait(it) => ModuleDefId::TraitId(it.into()), @@ -151,7 +160,7 @@ fn try_from(def: DefWithBody) -> Result { }, DefWithBody::Static(it) => DefWithBodyId::StaticId(it.id), DefWithBody::Const(it) => DefWithBodyId::ConstId(it.id), - DefWithBody::Variant(it) => DefWithBodyId::VariantId(it.into()), + DefWithBody::EnumVariant(it) => DefWithBodyId::VariantId(it.into()), }) } } @@ -162,7 +171,7 @@ fn from(def: DefWithBodyId) -> Self { 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::Variant(it.into()), + DefWithBodyId::VariantId(it) => DefWithBody::EnumVariant(it.into()), } } } @@ -209,22 +218,12 @@ fn from(id: Adt) -> Self { } } -impl From for VariantDef { - fn from(def: VariantId) -> Self { +impl From for VariantId { + fn from(def: Variant) -> Self { match def { - VariantId::StructId(it) => VariantDef::Struct(it.into()), - VariantId::EnumVariantId(it) => VariantDef::Variant(it.into()), - VariantId::UnionId(it) => VariantDef::Union(it.into()), - } - } -} - -impl From for VariantId { - fn from(def: VariantDef) -> Self { - match def { - VariantDef::Struct(it) => VariantId::StructId(it.id), - VariantDef::Variant(it) => VariantId::EnumVariantId(it.into()), - VariantDef::Union(it) => VariantId::UnionId(it.id), + Variant::Struct(it) => VariantId::StructId(it.id), + Variant::EnumVariant(it) => VariantId::EnumVariantId(it.into()), + Variant::Union(it) => VariantId::UnionId(it.id), } } } @@ -322,3 +321,43 @@ fn from(value: hir_def::FunctionId) -> Self { crate::Function { id: AnyFunctionId::FunctionId(value) } } } + +impl TryFrom for ExpressionStoreOwnerId { + type Error = (); + + fn try_from(v: ExpressionStoreOwner) -> Result { + match v { + ExpressionStoreOwner::Signature(generic_def_id) => { + Ok(Self::Signature(generic_def_id.try_into()?)) + } + ExpressionStoreOwner::Body(def_with_body_id) => { + Ok(Self::Body(def_with_body_id.try_into()?)) + } + ExpressionStoreOwner::VariantFields(variant_id) => { + Ok(Self::VariantFields(variant_id.into())) + } + } + } +} + +impl TryFrom for FunctionId { + type Error = (); + + fn try_from(v: Function) -> Result { + match v.id { + AnyFunctionId::FunctionId(id) => Ok(id), + _ => Err(()), + } + } +} + +impl TryFrom for ImplId { + type Error = (); + + fn try_from(v: Impl) -> Result { + match v.id { + AnyImplId::ImplId(id) => Ok(id), + _ => Err(()), + } + } +} 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 752c4f3173e6..f9badc0b7901 100644 --- a/src/tools/rust-analyzer/crates/hir/src/has_source.rs +++ b/src/tools/rust-analyzer/crates/hir/src/has_source.rs @@ -13,9 +13,9 @@ use tt::TextRange; use crate::{ - Adt, AnyFunctionId, Callee, Const, Enum, ExternCrateDecl, Field, FieldSource, Function, Impl, - InlineAsmOperand, Label, LifetimeParam, LocalSource, Macro, Module, Param, SelfParam, Static, - Struct, Trait, TypeAlias, TypeOrConstParam, Union, Variant, VariantDef, db::HirDatabase, + Adt, AnyFunctionId, Callee, Const, Enum, EnumVariant, ExternCrateDecl, Field, FieldSource, + Function, Impl, InlineAsmOperand, Label, LifetimeParam, LocalSource, Macro, Module, Param, + SelfParam, Static, Struct, Trait, TypeAlias, TypeOrConstParam, Union, Variant, db::HirDatabase, }; pub trait HasSource: Sized { @@ -124,13 +124,13 @@ fn source(self, db: &dyn HirDatabase) -> Option> { } } } -impl HasSource for VariantDef { +impl HasSource for Variant { type Ast = ast::VariantDef; fn source(self, db: &dyn HirDatabase) -> Option> { match self { - VariantDef::Struct(s) => Some(s.source(db)?.map(ast::VariantDef::Struct)), - VariantDef::Union(u) => Some(u.source(db)?.map(ast::VariantDef::Union)), - VariantDef::Variant(v) => Some(v.source(db)?.map(ast::VariantDef::Variant)), + Variant::Struct(s) => Some(s.source(db)?.map(ast::VariantDef::Struct)), + Variant::Union(u) => Some(u.source(db)?.map(ast::VariantDef::Union)), + Variant::EnumVariant(v) => Some(v.source(db)?.map(ast::VariantDef::Variant)), } } } @@ -152,7 +152,7 @@ fn source(self, db: &dyn HirDatabase) -> Option> { Some(self.id.lookup(db).source(db)) } } -impl HasSource for Variant { +impl HasSource for EnumVariant { type Ast = ast::Variant; fn source(self, db: &dyn HirDatabase) -> Option> { Some(self.id.lookup(db).source(db)) diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index 67527150bd45..bc5e16483054 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -356,8 +356,7 @@ pub enum ModuleDef { Function(Function), Adt(Adt), // Can't be directly declared, but can be imported. - // FIXME: Rename to `EnumVariant` - Variant(Variant), + EnumVariant(EnumVariant), Const(Const), Static(Static), Trait(Trait), @@ -369,7 +368,7 @@ pub enum ModuleDef { Module, Function, Adt(Struct, Enum, Union), - Variant, + EnumVariant, Const, Static, Trait, @@ -379,12 +378,12 @@ pub enum ModuleDef { for ModuleDef ); -impl From for ModuleDef { - fn from(var: VariantDef) -> Self { +impl From for ModuleDef { + fn from(var: Variant) -> Self { match var { - VariantDef::Struct(t) => Adt::from(t).into(), - VariantDef::Union(t) => Adt::from(t).into(), - VariantDef::Variant(t) => t.into(), + Variant::Struct(t) => Adt::from(t).into(), + Variant::Union(t) => Adt::from(t).into(), + Variant::EnumVariant(t) => t.into(), } } } @@ -395,7 +394,7 @@ pub fn module(self, db: &dyn HirDatabase) -> Option { ModuleDef::Module(it) => it.parent(db), ModuleDef::Function(it) => Some(it.module(db)), ModuleDef::Adt(it) => Some(it.module(db)), - ModuleDef::Variant(it) => Some(it.module(db)), + ModuleDef::EnumVariant(it) => Some(it.module(db)), ModuleDef::Const(it) => Some(it.module(db)), ModuleDef::Static(it) => Some(it.module(db)), ModuleDef::Trait(it) => Some(it.module(db)), @@ -428,7 +427,7 @@ pub fn name(self, db: &dyn HirDatabase) -> Option { ModuleDef::Adt(it) => it.name(db), ModuleDef::Trait(it) => it.name(db), ModuleDef::Function(it) => it.name(db), - ModuleDef::Variant(it) => it.name(db), + ModuleDef::EnumVariant(it) => it.name(db), ModuleDef::TypeAlias(it) => it.name(db), ModuleDef::Static(it) => it.name(db), ModuleDef::Macro(it) => it.name(db), @@ -457,7 +456,7 @@ pub fn diagnostics<'db>( ModuleDef::Module(it) => it.id.into(), ModuleDef::Const(it) => it.id.into(), ModuleDef::Static(it) => it.id.into(), - ModuleDef::Variant(it) => it.id.into(), + ModuleDef::EnumVariant(it) => it.id.into(), ModuleDef::BuiltinType(_) | ModuleDef::Macro(_) => return Vec::new(), }; @@ -486,7 +485,7 @@ pub fn as_def_with_body(self) -> Option { ModuleDef::Function(it) => Some(it.into()), ModuleDef::Const(it) => Some(it.into()), ModuleDef::Static(it) => Some(it.into()), - ModuleDef::Variant(it) => Some(it.into()), + ModuleDef::EnumVariant(it) => Some(it.into()), ModuleDef::Module(_) | ModuleDef::Adt(_) @@ -505,7 +504,7 @@ pub fn as_self_generic_def(self) -> Option { ModuleDef::Trait(it) => Some(it.into()), ModuleDef::TypeAlias(it) => Some(it.into()), ModuleDef::Module(_) - | ModuleDef::Variant(_) + | ModuleDef::EnumVariant(_) | ModuleDef::Static(_) | ModuleDef::Const(_) | ModuleDef::BuiltinType(_) @@ -521,7 +520,7 @@ pub fn as_generic_def(self) -> Option { ModuleDef::TypeAlias(it) => Some(it.into()), ModuleDef::Static(it) => Some(it.into()), ModuleDef::Const(it) => Some(it.into()), - ModuleDef::Variant(_) + ModuleDef::EnumVariant(_) | ModuleDef::Module(_) | ModuleDef::BuiltinType(_) | ModuleDef::Macro(_) => None, @@ -533,7 +532,7 @@ pub fn attrs(&self, db: &dyn HirDatabase) -> Option { ModuleDef::Module(it) => it.attrs(db), ModuleDef::Function(it) => HasAttrs::attrs(*it, db), ModuleDef::Adt(it) => it.attrs(db), - ModuleDef::Variant(it) => it.attrs(db), + ModuleDef::EnumVariant(it) => it.attrs(db), ModuleDef::Const(it) => it.attrs(db), ModuleDef::Static(it) => it.attrs(db), ModuleDef::Trait(it) => it.attrs(db), @@ -563,7 +562,7 @@ fn visibility(&self, db: &dyn HirDatabase) -> Visibility { ModuleDef::Static(it) => it.visibility(db), ModuleDef::Trait(it) => it.visibility(db), ModuleDef::TypeAlias(it) => it.visibility(db), - ModuleDef::Variant(it) => it.visibility(db), + ModuleDef::EnumVariant(it) => it.visibility(db), ModuleDef::Macro(it) => it.visibility(db), ModuleDef::BuiltinType(_) => Visibility::Public, } @@ -1300,7 +1299,7 @@ fn visibility(&self, db: &dyn HirDatabase) -> Visibility { #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct Field { - pub(crate) parent: VariantDef, + pub(crate) parent: Variant, pub(crate) id: LocalFieldId, } @@ -1324,7 +1323,7 @@ pub fn ty(&self, db: &'db dyn HirDatabase) -> TypeNs<'db> { #[derive(Debug, PartialEq, Eq, Copy, Clone, Hash)] pub struct TupleField { - pub owner: DefWithBodyId, + pub owner: ExpressionStoreOwnerId, pub tuple: TupleId, pub index: u32, } @@ -1406,9 +1405,9 @@ pub fn ty_with_args<'db>( ) -> Type<'db> { let var_id = self.parent.into(); let def_id: AdtId = match self.parent { - VariantDef::Struct(it) => it.id.into(), - VariantDef::Union(it) => it.id.into(), - VariantDef::Variant(it) => it.parent_enum(db).id.into(), + Variant::Struct(it) => it.id.into(), + Variant::Union(it) => it.id.into(), + Variant::EnumVariant(it) => it.parent_enum(db).id.into(), }; let interner = DbInterner::new_no_crate(db); let args = generic_args_from_tys(interner, def_id.into(), generics.map(|ty| ty.ty)); @@ -1434,7 +1433,7 @@ pub fn layout(&self, db: &dyn HirDatabase) -> Result { .map(|layout| Layout(layout, db.target_data_layout(self.krate(db).into()).unwrap())) } - pub fn parent_def(&self, _db: &dyn HirDatabase) -> VariantDef { + pub fn parent_def(&self, _db: &dyn HirDatabase) -> Variant { self.parent } } @@ -1615,8 +1614,8 @@ pub fn name(self, db: &dyn HirDatabase) -> Name { EnumSignature::of(db, self.id).name.clone() } - pub fn variants(self, db: &dyn HirDatabase) -> Vec { - self.id.enum_variants(db).variants.iter().map(|&(id, _, _)| Variant { id }).collect() + pub fn variants(self, db: &dyn HirDatabase) -> Vec { + self.id.enum_variants(db).variants.iter().map(|&(id, _, _)| EnumVariant { id }).collect() } pub fn num_variants(self, db: &dyn HirDatabase) -> usize { @@ -1708,19 +1707,18 @@ pub fn ty(self, db: &'db dyn HirDatabase) -> TypeNs<'db> { } } -impl From<&Variant> for DefWithBodyId { - fn from(&v: &Variant) -> Self { +impl From<&EnumVariant> for DefWithBodyId { + fn from(&v: &EnumVariant) -> Self { DefWithBodyId::VariantId(v.into()) } } -// FIXME: Rename to `EnumVariant` #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct Variant { +pub struct EnumVariant { pub(crate) id: EnumVariantId, } -impl Variant { +impl EnumVariant { pub fn module(self, db: &dyn HirDatabase) -> Module { Module { id: self.id.module(db) } } @@ -1794,7 +1792,7 @@ pub fn instantiate_infer<'db>(self, infer_ctxt: &InferCtxt<'db>) -> Instantiated // FIXME: Rename to `EnumVariant` #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct InstantiatedVariant<'db> { - pub(crate) inner: Variant, + pub(crate) inner: EnumVariant, pub(crate) args: GenericArgs<'db>, } @@ -1825,7 +1823,7 @@ pub enum StructKind { } /// Variants inherit visibility from the parent enum. -impl HasVisibility for Variant { +impl HasVisibility for EnumVariant { fn visibility(&self, db: &dyn HirDatabase) -> Visibility { self.parent_enum(db).visibility(db) } @@ -1934,35 +1932,35 @@ fn visibility(&self, db: &dyn HirDatabase) -> Visibility { } #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub enum VariantDef { +pub enum Variant { Struct(Struct), Union(Union), - Variant(Variant), + EnumVariant(EnumVariant), } -impl_from!(Struct, Union, Variant for VariantDef); +impl_from!(Struct, Union, EnumVariant for Variant); -impl VariantDef { +impl Variant { pub fn fields(self, db: &dyn HirDatabase) -> Vec { match self { - VariantDef::Struct(it) => it.fields(db), - VariantDef::Union(it) => it.fields(db), - VariantDef::Variant(it) => it.fields(db), + Variant::Struct(it) => it.fields(db), + Variant::Union(it) => it.fields(db), + Variant::EnumVariant(it) => it.fields(db), } } pub fn module(self, db: &dyn HirDatabase) -> Module { match self { - VariantDef::Struct(it) => it.module(db), - VariantDef::Union(it) => it.module(db), - VariantDef::Variant(it) => it.module(db), + Variant::Struct(it) => it.module(db), + Variant::Union(it) => it.module(db), + Variant::EnumVariant(it) => it.module(db), } } pub fn name(&self, db: &dyn HirDatabase) -> Name { match self { - VariantDef::Struct(s) => (*s).name(db), - VariantDef::Union(u) => (*u).name(db), - VariantDef::Variant(e) => (*e).name(db), + Variant::Struct(s) => (*s).name(db), + Variant::Union(u) => (*u).name(db), + Variant::EnumVariant(e) => (*e).name(db), } } } @@ -1971,6 +1969,7 @@ pub fn name(&self, db: &dyn HirDatabase) -> Name { pub enum ExpressionStoreOwner { Body(DefWithBody), Signature(GenericDef), + VariantFields(Variant), } impl From for ExpressionStoreOwner { @@ -1992,6 +1991,9 @@ fn from(v: ExpressionStoreOwnerId) -> Self { 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()) + } } } } @@ -2001,6 +2003,7 @@ pub fn module(self, db: &dyn HirDatabase) -> Module { match self { Self::Body(body) => body.module(db), Self::Signature(generic_def) => generic_def.module(db), + Self::VariantFields(variant) => variant.module(db), } } } @@ -2011,9 +2014,9 @@ pub enum DefWithBody { Function(Function), Static(Static), Const(Const), - Variant(Variant), + EnumVariant(EnumVariant), } -impl_from!(Function, Const, Static, Variant for DefWithBody); +impl_from!(Function, Const, Static, EnumVariant for DefWithBody); impl DefWithBody { pub fn module(self, db: &dyn HirDatabase) -> Module { @@ -2021,7 +2024,7 @@ pub fn module(self, db: &dyn HirDatabase) -> Module { DefWithBody::Const(c) => c.module(db), DefWithBody::Function(f) => f.module(db), DefWithBody::Static(s) => s.module(db), - DefWithBody::Variant(v) => v.module(db), + DefWithBody::EnumVariant(v) => v.module(db), } } @@ -2030,7 +2033,7 @@ pub fn name(self, db: &dyn HirDatabase) -> Option { DefWithBody::Function(f) => Some(f.name(db)), DefWithBody::Static(s) => Some(s.name(db)), DefWithBody::Const(c) => c.name(db), - DefWithBody::Variant(v) => Some(v.name(db)), + DefWithBody::EnumVariant(v) => Some(v.name(db)), } } @@ -2040,7 +2043,7 @@ pub fn body_type(self, db: &dyn HirDatabase) -> Type<'_> { DefWithBody::Function(it) => it.ret_type(db), DefWithBody::Static(it) => it.ty(db), DefWithBody::Const(it) => it.ty(db), - DefWithBody::Variant(it) => it.parent_enum(db).variant_body_ty(db), + DefWithBody::EnumVariant(it) => it.parent_enum(db).variant_body_ty(db), } } @@ -2052,7 +2055,7 @@ fn id(&self) -> Option { }, DefWithBody::Static(it) => it.id.into(), DefWithBody::Const(it) => it.id.into(), - DefWithBody::Variant(it) => it.into(), + DefWithBody::EnumVariant(it) => it.into(), }) } @@ -2096,7 +2099,7 @@ pub fn diagnostics<'db>( }, DefWithBody::Static(id) => &StaticSignature::with_source_map(db, id.into()).1, DefWithBody::Const(id) => &ConstSignature::with_source_map(db, id.into()).1, - DefWithBody::Variant(variant) => { + DefWithBody::EnumVariant(variant) => { let enum_id = variant.parent_enum(db).id; &EnumSignature::with_source_map(db, enum_id).1 } @@ -3785,7 +3788,7 @@ fn as_assoc_item(self, db: &dyn HirDatabase) -> Option { match self { DefWithBody::Function(it) => it.as_assoc_item(db), DefWithBody::Const(it) => it.as_assoc_item(db), - DefWithBody::Static(_) | DefWithBody::Variant(_) => None, + DefWithBody::Static(_) | DefWithBody::EnumVariant(_) => None, } } } @@ -4369,11 +4372,9 @@ pub fn ty(self, db: &dyn HirDatabase) -> Type<'_> { /// All definitions for this local. Example: `let (a$0, _) | (_, a$0) = it;` pub fn sources(self, db: &dyn HirDatabase) -> Vec { let b; - let s; let (_, source_map) = match self.parent { ExpressionStoreOwnerId::Signature(generic_def_id) => { - s = ExpressionStore::with_source_map(db, generic_def_id.into()); - (s.0, s.1) + ExpressionStore::with_source_map(db, generic_def_id.into()) } ExpressionStoreOwnerId::Body(def_with_body_id) => { b = Body::with_source_map(db, def_with_body_id); @@ -4388,6 +4389,9 @@ pub fn sources(self, db: &dyn HirDatabase) -> Vec { } (&b.0.store, &b.1.store) } + ExpressionStoreOwnerId::VariantFields(def) => { + ExpressionStore::with_source_map(db, def.into()) + } }; source_map .patterns_for_binding(self.binding_id) @@ -4409,11 +4413,9 @@ pub fn sources(self, db: &dyn HirDatabase) -> Vec { /// The leftmost definition for this local. Example: `let (a$0, _) | (_, a) = it;` pub fn primary_source(self, db: &dyn HirDatabase) -> LocalSource { let b; - let s; let (_, source_map) = match self.parent { ExpressionStoreOwnerId::Signature(generic_def_id) => { - s = ExpressionStore::with_source_map(db, generic_def_id.into()); - (s.0, s.1) + ExpressionStore::with_source_map(db, generic_def_id.into()) } ExpressionStoreOwnerId::Body(def_with_body_id) => { b = Body::with_source_map(db, def_with_body_id); @@ -4428,6 +4430,9 @@ pub fn primary_source(self, db: &dyn HirDatabase) -> LocalSource { } (&b.0.store, &b.1.store) } + ExpressionStoreOwnerId::VariantFields(def) => { + ExpressionStore::with_source_map(db, def.into()) + } }; source_map .patterns_for_binding(self.binding_id) @@ -6519,7 +6524,7 @@ enum Callee<'db> { pub enum CallableKind<'db> { Function(Function), TupleStruct(Struct), - TupleEnumVariant(Variant), + TupleEnumVariant(EnumVariant), Closure(Closure<'db>), FnPtr, FnImpl(FnTrait), @@ -6869,7 +6874,7 @@ fn krate(&self, db: &dyn HirDatabase) -> Crate { } } -impl HasCrate for Variant { +impl HasCrate for EnumVariant { fn krate(&self, db: &dyn HirDatabase) -> Crate { self.module(db).krate(db) } @@ -7038,9 +7043,9 @@ fn name(&self, db: &dyn HirDatabase) -> Option { Struct, Union, Enum, - Variant, + EnumVariant, Adt, - VariantDef, + Variant, DefWithBody, Function, ExternCrateDecl, @@ -7264,9 +7269,9 @@ fn param_env_from_has_crate<'db>( fn body_param_env_from_has_crate<'db>( db: &'db dyn HirDatabase, - id: impl hir_def::HasModule + Into + Copy, + id: impl hir_def::HasModule + Into + Copy, ) -> ParamEnvAndCrate<'db> { - ParamEnvAndCrate { param_env: db.trait_environment(id.into().into()), krate: id.krate(db) } + ParamEnvAndCrate { param_env: db.trait_environment(id.into()), krate: id.krate(db) } } fn empty_param_env<'db>(krate: base_db::Crate) -> ParamEnvAndCrate<'db> { diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs index f1aabb59337a..4e9e3c44be11 100644 --- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs +++ b/src/tools/rust-analyzer/crates/hir/src/semantics.rs @@ -16,7 +16,7 @@ BuiltinDeriveImplId, DefWithBodyId, ExpressionStoreOwnerId, HasModule, MacroId, StructId, TraitId, VariantId, attrs::parse_extra_crate_attrs, - expr_store::{Body, ExprOrPatSource, HygieneId, path::Path}, + expr_store::{Body, ExprOrPatSource, ExpressionStore, HygieneId, path::Path}, hir::{BindingId, Expr, ExprId, ExprOrPatId, Pat}, nameres::{ModuleOrigin, crate_def_map}, resolver::{self, HasResolver, Resolver, TypeNs, ValueNs}, @@ -32,7 +32,7 @@ }; use hir_ty::{ InferenceResult, - diagnostics::{unsafe_operations, unsafe_operations_for_body}, + diagnostics::unsafe_operations, infer_query_with_inspect, next_solver::{ AnyImplId, DbInterner, Span, @@ -55,10 +55,10 @@ use crate::{ Adjust, Adjustment, Adt, AnyFunctionId, AutoBorrow, BindingMode, BuiltinAttr, Callable, Const, - ConstParam, Crate, DefWithBody, DeriveHelper, Enum, ExpressionStoreOwner, Field, Function, + ConstParam, Crate, DeriveHelper, Enum, EnumVariant, ExpressionStoreOwner, Field, Function, GenericSubstitution, HasSource, Impl, InFile, InlineAsmOperand, ItemInNs, Label, LifetimeParam, Local, Macro, Module, ModuleDef, Name, OverloadedDeref, ScopeDef, Static, Struct, ToolModule, - Trait, TupleField, Type, TypeAlias, TypeParam, Union, Variant, VariantDef, + Trait, TupleField, Type, TypeAlias, TypeParam, Union, Variant, db::HirDatabase, semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx}, source_analyzer::{SourceAnalyzer, resolve_hir_path}, @@ -91,7 +91,7 @@ pub(crate) fn in_type_ns(&self) -> Option { } PathResolution::Def( ModuleDef::Const(_) - | ModuleDef::Variant(_) + | ModuleDef::EnumVariant(_) | ModuleDef::Macro(_) | ModuleDef::Function(_) | ModuleDef::Module(_) @@ -368,8 +368,8 @@ pub fn resolve_try_expr(&self, try_expr: &ast::TryExpr) -> Option { self.imp.resolve_try_expr(try_expr) } - pub fn resolve_variant(&self, record_lit: ast::RecordExpr) -> Option { - self.imp.resolve_variant(record_lit).map(VariantDef::from) + pub fn resolve_variant(&self, record_lit: ast::RecordExpr) -> Option { + self.imp.resolve_variant(record_lit).map(Variant::from) } pub fn file_to_module_def(&self, file: impl Into) -> Option { @@ -410,7 +410,7 @@ pub fn to_enum_def(&self, e: &ast::Enum) -> Option { self.imp.to_def(e) } - pub fn to_enum_variant_def(&self, v: &ast::Variant) -> Option { + pub fn to_enum_variant_def(&self, v: &ast::Variant) -> Option { self.imp.to_def(v) } @@ -792,7 +792,8 @@ pub fn rename_conflicts(&self, to_be_renamed: &Local, new_name: &Name) -> Vec Option self.db.parse_macro_expansion(file_id).value.1.matched_arm } - pub fn get_unsafe_ops(&self, def: DefWithBody) -> FxHashSet { - let Ok(def) = DefWithBodyId::try_from(def) else { - return FxHashSet::default(); - }; - let (body, source_map) = Body::with_source_map(self.db, def); + pub fn get_unsafe_ops(&self, def: ExpressionStoreOwner) -> FxHashSet { + let Ok(def) = ExpressionStoreOwnerId::try_from(def) else { return Default::default() }; + let (body, source_map) = ExpressionStore::with_source_map(self.db, def); let infer = InferenceResult::of(self.db, def); let mut res = FxHashSet::default(); - unsafe_operations_for_body(self.db, infer, def, body, &mut |node| { - if let Ok(node) = source_map.expr_or_pat_syntax(node) { - res.insert(node); - } - }); + for root in body.expr_roots() { + unsafe_operations(self.db, infer, def, body, root, &mut |node, _| { + if let Ok(node) = source_map.expr_or_pat_syntax(node) { + res.insert(node); + } + }); + } res } pub fn get_unsafe_ops_for_unsafe_block(&self, block: ast::BlockExpr) -> Vec { always!(block.unsafe_token().is_some()); + let Some(sa) = self.analyze(block.syntax()) else { return vec![] }; + let Some((def, store, sm, Some(infer))) = sa.def() else { return vec![] }; let block = self.wrap_node_infile(ast::Expr::from(block)); - let Some(def) = self.body_for(block.syntax()) else { return Vec::new() }; - let Ok(def) = def.try_into() else { - return Vec::new(); - }; - let (body, source_map) = Body::with_source_map(self.db, def); - let infer = InferenceResult::of(self.db, def); - let Some(ExprOrPatId::ExprId(block)) = source_map.node_expr(block.as_ref()) else { + let Some(ExprOrPatId::ExprId(block)) = sm.node_expr(block.as_ref()) else { return Vec::new(); }; let mut res = Vec::default(); - unsafe_operations(self.db, infer, def, body, block, &mut |node, _| { - if let Ok(node) = source_map.expr_or_pat_syntax(node) { + unsafe_operations(self.db, infer, def, store, block, &mut |node, _| { + if let Ok(node) = sm.expr_or_pat_syntax(node) { res.push(node); } }); @@ -1999,7 +1996,7 @@ pub fn resolve_use_type_arg(&self, name: &ast::NameRef) -> Option { pub fn resolve_offset_of_field( &self, name_ref: &ast::NameRef, - ) -> Option<(Either, GenericSubstitution<'db>)> { + ) -> Option<(Either, GenericSubstitution<'db>)> { self.analyze_no_infer(name_ref.syntax())?.resolve_offset_of_field(self.db, name_ref) } @@ -2119,13 +2116,9 @@ pub fn source_with_range( Some(res) } - pub fn body_for(&self, node: InFile<&SyntaxNode>) -> Option { + pub fn store_owner_for(&self, node: InFile<&SyntaxNode>) -> Option { let container = self.with_ctx(|ctx| ctx.find_container(node))?; - - match container { - ChildContainer::DefWithBodyId(def) => Some(def.into()), - _ => None, - } + container.as_expression_store_owner().map(|id| id.into()) } /// Returns none if the file of the node is not part of a crate. @@ -2169,7 +2162,7 @@ fn analyze_impl( }); } ChildContainer::VariantId(def) => { - return Some(SourceAnalyzer::new_variant_body(self.db, def, node, offset)); + return Some(SourceAnalyzer::new_variant_body(self.db, def, node, offset, infer)); } ChildContainer::TraitId(it) => { return Some(if infer { @@ -2522,7 +2515,7 @@ fn to_def(sema: &SemanticsImpl<'_>, src: InFile<&Self>) -> Option { (crate::Function, ast::Fn, fn_to_def), (crate::Field, ast::RecordField, record_field_to_def), (crate::Field, ast::TupleField, tuple_field_to_def), - (crate::Variant, ast::Variant, enum_variant_to_def), + (crate::EnumVariant, ast::Variant, enum_variant_to_def), (crate::TypeParam, ast::TypeParam, type_param_to_def), (crate::LifetimeParam, ast::LifetimeParam, lifetime_param_to_def), (crate::ConstParam, ast::ConstParam, const_param_to_def), 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 8c398728b08a..a9a779a287d6 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 @@ -738,7 +738,7 @@ fn child_by_source(self, db: &dyn HirDatabase, file_id: HirFileId) -> DynMap { } } - fn as_expression_store_owner(self) -> Option { + pub(crate) fn as_expression_store_owner(self) -> Option { match self { ChildContainer::DefWithBodyId(it) => Some(it.into()), ChildContainer::ModuleId(_) => None, 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 1b41c78892d6..1a34fa913425 100644 --- a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs +++ b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs @@ -20,7 +20,7 @@ hir::{BindingId, Expr, ExprId, ExprOrPatId, Pat, PatId, generics::GenericParams}, lang_item::LangItems, nameres::MacroSubNs, - resolver::{HasResolver, Resolver, TypeNs, ValueNs, resolver_for_scope}, + resolver::{Resolver, TypeNs, ValueNs, resolver_for_scope}, type_ref::{Mutability, TypeRef, TypeRefId}, }; use hir_expand::{ @@ -58,8 +58,8 @@ use crate::{ Adt, AnyFunctionId, AssocItem, BindingMode, BuiltinAttr, BuiltinType, Callable, Const, - DeriveHelper, Field, Function, GenericSubstitution, Local, Macro, ModuleDef, Static, Struct, - ToolModule, Trait, TupleField, Type, TypeAlias, Variant, + DeriveHelper, EnumVariant, Field, Function, GenericSubstitution, Local, Macro, ModuleDef, + Static, Struct, ToolModule, Trait, TupleField, Type, TypeAlias, db::HirDatabase, semantics::{PathResolution, PathResolutionPerNs}, }; @@ -81,11 +81,11 @@ pub(crate) enum BodyOrSig<'db> { source_map: &'db BodySourceMap, infer: Option<&'db InferenceResult>, }, - // To be folded into body once it is considered one VariantFields { def: VariantId, store: &'db ExpressionStore, source_map: &'db ExpressionStoreSourceMap, + infer: Option<&'db InferenceResult>, }, Sig { def: GenericDefId, @@ -196,14 +196,34 @@ pub(crate) fn new_generic_def_( pub(crate) fn new_variant_body( db: &'db dyn HirDatabase, def: VariantId, - InFile { file_id, .. }: InFile<&SyntaxNode>, - _offset: Option, + node @ InFile { file_id, .. }: InFile<&SyntaxNode>, + offset: Option, + infer: bool, ) -> SourceAnalyzer<'db> { let (fields, source_map) = def.fields_with_source_map(db); - let resolver = def.resolver(db); + let scopes = ExprScopes::of(db, def); + let scope = match offset { + None => scope_for(db, scopes, source_map, node), + Some(offset) => { + debug_assert!( + node.text_range().contains_inclusive(offset), + "{:?} not in {:?}", + offset, + node.text_range() + ); + scope_for_offset(db, scopes, source_map, node.file_id, offset) + } + }; + let resolver = resolver_for_scope(db, def, scope); + let infer = if infer { Some(InferenceResult::of(db, def)) } else { None }; SourceAnalyzer { resolver, - body_or_sig: Some(BodyOrSig::VariantFields { def, store: &fields.store, source_map }), + body_or_sig: Some(BodyOrSig::VariantFields { + def, + store: &fields.store, + source_map, + infer, + }), file_id, } } @@ -215,31 +235,39 @@ pub(crate) fn new_for_resolver( SourceAnalyzer { resolver, body_or_sig: None, file_id: node.file_id } } - // FIXME: Remove this - fn body_(&self) -> Option<(DefWithBodyId, &Body, &BodySourceMap, Option<&InferenceResult>)> { - self.body_or_sig.as_ref().and_then(|it| match it { - BodyOrSig::Body { def, body, source_map, infer } => { - Some((*def, &**body, &**source_map, infer.as_deref())) - } - _ => None, + fn owner(&self) -> Option { + self.body_or_sig.as_ref().map(|it| match *it { + BodyOrSig::VariantFields { def, .. } => def.into(), + BodyOrSig::Sig { def, .. } => def.into(), + BodyOrSig::Body { def, .. } => def.into(), }) } fn infer(&self) -> Option<&InferenceResult> { self.body_or_sig.as_ref().and_then(|it| match it { - BodyOrSig::VariantFields { .. } => None, - BodyOrSig::Sig { infer, .. } | BodyOrSig::Body { infer, .. } => infer.as_deref(), + BodyOrSig::VariantFields { infer, .. } + | BodyOrSig::Sig { infer, .. } + | BodyOrSig::Body { infer, .. } => infer.as_deref(), }) } pub(crate) fn def( &self, - ) -> Option<(ExpressionStoreOwnerId, &ExpressionStore, &ExpressionStoreSourceMap)> { - self.body_or_sig.as_ref().and_then(|it| match it { - BodyOrSig::VariantFields { .. } => None, - &BodyOrSig::Sig { def, store, source_map, .. } => Some((def.into(), store, source_map)), - BodyOrSig::Body { def, body, source_map, .. } => { - Some(((*def).into(), &body.store, source_map)) + ) -> Option<( + ExpressionStoreOwnerId, + &ExpressionStore, + &ExpressionStoreSourceMap, + Option<&InferenceResult>, + )> { + self.body_or_sig.as_ref().map(|it| match *it { + BodyOrSig::VariantFields { def, store, source_map, infer, .. } => { + (def.into(), store, source_map, infer) + } + BodyOrSig::Sig { def, store, source_map, infer, .. } => { + (def.into(), store, source_map, infer) + } + BodyOrSig::Body { def, body, source_map, infer, .. } => { + (def.into(), &body.store, &source_map.store, infer) } }) } @@ -268,7 +296,7 @@ fn trait_environment(&self, db: &'db dyn HirDatabase) -> ParamEnvAndCrate<'db> { self.param_and(self.body_or_sig.as_ref().map_or_else(ParamEnv::empty, |body_or_sig| { match *body_or_sig { BodyOrSig::Body { def, .. } => db.trait_environment(def.into()), - BodyOrSig::VariantFields { .. } => ParamEnv::empty(), + BodyOrSig::VariantFields { def, .. } => db.trait_environment(def.into()), BodyOrSig::Sig { def, .. } => db.trait_environment(def.into()), } })) @@ -510,7 +538,7 @@ pub(crate) fn resolve_field( &self, field: &ast::FieldExpr, ) -> Option> { - let (def, ..) = self.body_()?; + let def = self.owner()?; let expr_id = self.expr_id(field.clone().into())?.as_expr()?; self.infer()?.field_resolution(expr_id).map(|it| { it.map_either(Into::into, |f| TupleField { owner: def, tuple: f.tuple, index: f.index }) @@ -537,7 +565,7 @@ pub(crate) fn resolve_field_fallback( field: &ast::FieldExpr, ) -> Option<(Either, Function>, Option>)> { - let (def, ..) = self.body_()?; + let def = self.owner()?; let expr_id = self.expr_id(field.clone().into())?.as_expr()?; let inference_result = self.infer()?; match inference_result.field_resolution(expr_id) { @@ -889,7 +917,7 @@ pub(crate) fn resolve_offset_of_field( &self, db: &'db dyn HirDatabase, name_ref: &ast::NameRef, - ) -> Option<(Either, GenericSubstitution<'db>)> { + ) -> Option<(Either, GenericSubstitution<'db>)> { let offset_of_expr = ast::OffsetOfExpr::cast(name_ref.syntax().parent()?)?; let container = offset_of_expr.ty()?; let container = self.type_of_type(db, &container)?; @@ -940,7 +968,7 @@ pub(crate) fn resolve_offset_of_field( let variants = id.enum_variants(db); let variant = variants.variant(&field_name.as_name())?; container = Either::Left((variant, subst)); - (Either::Left(Variant { id: variant }), id.into(), subst) + (Either::Left(EnumVariant { id: variant }), id.into(), subst) } }, _ => return None, @@ -1020,7 +1048,10 @@ pub(crate) fn resolve_path( if let Some(VariantId::EnumVariantId(variant)) = infer.variant_resolution_for_expr_or_pat(expr_id) { - return Some((PathResolution::Def(ModuleDef::Variant(variant.into())), None)); + return Some(( + PathResolution::Def(ModuleDef::EnumVariant(variant.into())), + None, + )); } prefer_value_ns = true; } else if let Some(path_pat) = parent().and_then(ast::PathPat::cast) { @@ -1052,14 +1083,20 @@ pub(crate) fn resolve_path( if let Some(VariantId::EnumVariantId(variant)) = infer.variant_resolution_for_expr_or_pat(expr_or_pat_id) { - return Some((PathResolution::Def(ModuleDef::Variant(variant.into())), None)); + return Some(( + PathResolution::Def(ModuleDef::EnumVariant(variant.into())), + None, + )); } } else if let Some(rec_lit) = parent().and_then(ast::RecordExpr::cast) { let expr_id = self.expr_id(rec_lit.into())?; if let Some(VariantId::EnumVariantId(variant)) = infer.variant_resolution_for_expr_or_pat(expr_id) { - return Some((PathResolution::Def(ModuleDef::Variant(variant.into())), None)); + return Some(( + PathResolution::Def(ModuleDef::EnumVariant(variant.into())), + None, + )); } } else { let record_pat = parent().and_then(ast::RecordPat::cast).map(ast::Pat::from); @@ -1070,7 +1107,7 @@ pub(crate) fn resolve_path( let variant_res_for_pat = infer.variant_resolution_for_pat(pat_id.as_pat()?); if let Some(VariantId::EnumVariantId(variant)) = variant_res_for_pat { return Some(( - PathResolution::Def(ModuleDef::Variant(variant.into())), + PathResolution::Def(ModuleDef::EnumVariant(variant.into())), None, )); } @@ -1404,7 +1441,7 @@ pub(crate) fn is_unsafe_macro_call_expr( db: &'db dyn HirDatabase, macro_expr: InFile<&ast::MacroExpr>, ) -> bool { - if let Some((def, body, sm, Some(infer))) = self.body_() + if let Some((def, body, sm, Some(infer))) = self.def() && let Some(expanded_expr) = sm.macro_expansion_expr(macro_expr) { let mut is_unsafe = false; @@ -1455,7 +1492,7 @@ pub(crate) fn resolve_offset_in_asm_template( line: usize, offset: TextSize, ) -> Option<(ExpressionStoreOwnerId, (ExprId, TextRange, usize))> { - let (def, _, sm) = self.def()?; + let (def, _, sm, _) = self.def()?; let (expr, args) = sm.asm_template_args(asm)?; Some(def).zip( args.get(line)? @@ -1492,7 +1529,7 @@ pub(crate) fn as_asm_parts( &self, asm: InFile<&ast::AsmExpr>, ) -> Option<(ExpressionStoreOwnerId, (ExprId, &[Vec<(TextRange, usize)>]))> { - let (def, _, sm) = self.def()?; + let (def, _, sm, _) = self.def()?; Some(def).zip(sm.asm_template_args(asm)) } @@ -1722,7 +1759,7 @@ fn resolve_hir_path_( TypeNs::AdtSelfType(it) | TypeNs::AdtId(it) => { PathResolution::Def(Adt::from(it).into()) } - TypeNs::EnumVariantId(it) => PathResolution::Def(Variant::from(it).into()), + TypeNs::EnumVariantId(it) => PathResolution::Def(EnumVariant::from(it).into()), TypeNs::TypeAliasId(it) => PathResolution::Def(TypeAlias::from(it).into()), TypeNs::BuiltinType(it) => PathResolution::Def(BuiltinType::from(it).into()), TypeNs::TraitId(it) => PathResolution::Def(Trait::from(it).into()), @@ -1806,7 +1843,7 @@ fn resolve_hir_value_path( ValueNs::ConstId(it) => PathResolution::Def(Const::from(it).into()), ValueNs::StaticId(it) => PathResolution::Def(Static::from(it).into()), ValueNs::StructId(it) => PathResolution::Def(Struct::from(it).into()), - ValueNs::EnumVariantId(it) => PathResolution::Def(Variant::from(it).into()), + ValueNs::EnumVariantId(it) => PathResolution::Def(EnumVariant::from(it).into()), ValueNs::ImplSelf(impl_id) => PathResolution::SelfType(impl_id.into()), ValueNs::GenericParam(id) => PathResolution::ConstParam(id.into()), }; @@ -1871,7 +1908,7 @@ fn resolve_hir_path_qualifier( TypeNs::AdtSelfType(it) | TypeNs::AdtId(it) => { PathResolution::Def(Adt::from(it).into()) } - TypeNs::EnumVariantId(it) => PathResolution::Def(Variant::from(it).into()), + TypeNs::EnumVariantId(it) => PathResolution::Def(EnumVariant::from(it).into()), TypeNs::TypeAliasId(it) => PathResolution::Def(TypeAlias::from(it).into()), TypeNs::BuiltinType(it) => PathResolution::Def(BuiltinType::from(it).into()), TypeNs::TraitId(it) => PathResolution::Def(Trait::from(it).into()), 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 e56f9e91e3f3..e3d0121e4912 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 @@ -10,8 +10,8 @@ use span::Edition; use crate::{ - Adt, AsAssocItem, AssocItemContainer, Const, ConstParam, Field, Function, Local, ModuleDef, - SemanticsScope, Static, Struct, StructKind, Trait, Type, Variant, + Adt, AsAssocItem, AssocItemContainer, Const, ConstParam, EnumVariant, Field, Function, Local, + ModuleDef, SemanticsScope, Static, Struct, StructKind, Trait, Type, }; /// Helper function to get path to `ModuleDef` @@ -80,7 +80,7 @@ pub enum Expr<'db> { params: Vec>, }, /// Enum variant construction - Variant { variant: Variant, generics: Vec>, params: Vec> }, + Variant { variant: EnumVariant, generics: Vec>, params: Vec> }, /// Struct construction Struct { strukt: Struct, generics: Vec>, params: Vec> }, /// Tuple construction @@ -222,7 +222,7 @@ pub fn gen_source_code( StructKind::Unit => String::new(), }; - let prefix = mod_item_path_str(sema_scope, &ModuleDef::Variant(*variant))?; + let prefix = mod_item_path_str(sema_scope, &ModuleDef::EnumVariant(*variant))?; Ok(format!("{prefix}{inner}")) } Expr::Struct { strukt, params, .. } => { diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs index 3c3f71aea6cf..b063e5ffce87 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs @@ -86,6 +86,7 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>) def_with_body.as_assoc_item(ctx.db()) } hir::ExpressionStoreOwner::Signature(def) => def.as_assoc_item(ctx.db()), + hir::ExpressionStoreOwner::VariantFields(_) => None, }? .implementing_ty(ctx.db()) }) @@ -477,7 +478,7 @@ enum ExtendedEnum { enum ExtendedVariant { True, False, - Variant { variant: hir::Variant, use_self: bool }, + Variant { variant: hir::EnumVariant, use_self: bool }, } impl ExtendedVariant { diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/auto_import.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/auto_import.rs index da5c12395771..de5dfdf4d954 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/auto_import.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/auto_import.rs @@ -268,7 +268,7 @@ pub(crate) fn relevance_score( hir::Adt::Union(it) => it.ty(ctx.db()), hir::Adt::Enum(it) => it.ty(ctx.db()), }), - hir::ModuleDef::Variant(variant) => Some(variant.constructor_ty(ctx.db())), + hir::ModuleDef::EnumVariant(variant) => Some(variant.constructor_ty(ctx.db())), hir::ModuleDef::Const(it) => Some(it.ty(ctx.db())), hir::ModuleDef::Static(it) => Some(it.ty(ctx.db())), hir::ModuleDef::TypeAlias(it) => Some(it.ty(ctx.db())), diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_then.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_then.rs index 236436989e15..b3bfe5b8c41a 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_then.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_then.rs @@ -237,7 +237,7 @@ pub(crate) fn convert_bool_then_to_if(acc: &mut Assists, ctx: &AssistContext<'_> fn option_variants( sema: &Semantics<'_, RootDatabase>, expr: &SyntaxNode, -) -> Option<(hir::Variant, hir::Variant)> { +) -> Option<(hir::EnumVariant, hir::EnumVariant)> { let fam = FamousDefs(sema, sema.scope(expr)?.krate()); let option_variants = fam.core_option_Option()?.variants(sema.db); match &*option_variants { @@ -254,7 +254,7 @@ fn option_variants( /// If any of these conditions are met it is impossible to rewrite this as a `bool::then` call. fn is_invalid_body( sema: &Semantics<'_, RootDatabase>, - some_variant: hir::Variant, + some_variant: hir::EnumVariant, expr: &ast::Expr, ) -> bool { let mut invalid = false; @@ -277,7 +277,7 @@ fn is_invalid_body( && let Some(ast::Expr::PathExpr(p)) = call.expr() { let res = p.path().and_then(|p| sema.resolve_path(&p)); - if let Some(hir::PathResolution::Def(hir::ModuleDef::Variant(v))) = res { + if let Some(hir::PathResolution::Def(hir::ModuleDef::EnumVariant(v))) = res { return invalid |= v != some_variant; } } @@ -290,11 +290,11 @@ fn is_invalid_body( fn block_is_none_variant( sema: &Semantics<'_, RootDatabase>, block: &ast::BlockExpr, - none_variant: hir::Variant, + none_variant: hir::EnumVariant, ) -> bool { block_as_lone_tail(block).and_then(|e| match e { ast::Expr::PathExpr(pat) => match sema.resolve_path(&pat.path()?)? { - hir::PathResolution::Def(hir::ModuleDef::Variant(v)) => Some(v), + hir::PathResolution::Def(hir::ModuleDef::EnumVariant(v)) => Some(v), _ => None, }, _ => None, diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_named_struct_to_tuple_struct.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_named_struct_to_tuple_struct.rs index 4dd2036c024c..aaf727058cf1 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_named_struct_to_tuple_struct.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_named_struct_to_tuple_struct.rs @@ -158,11 +158,11 @@ fn edit_struct_def( fn edit_struct_references( ctx: &AssistContext<'_>, builder: &mut SourceChangeBuilder, - strukt: Either, + strukt: Either, ) { let strukt_def = match strukt { Either::Left(s) => Definition::Adt(hir::Adt::Struct(s)), - Either::Right(v) => Definition::Variant(v), + Either::Right(v) => Definition::EnumVariant(v), }; let usages = strukt_def.usages(&ctx.sema).include_self_refs().all(); 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 270467b14f0c..ae41e6c015ce 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 @@ -142,12 +142,12 @@ fn edit_struct_def( fn edit_struct_references( ctx: &AssistContext<'_>, edit: &mut SourceChangeBuilder, - strukt: Either, + strukt: Either, names: &[ast::Name], ) { let strukt_def = match strukt { Either::Left(s) => Definition::Adt(hir::Adt::Struct(s)), - Either::Right(v) => Definition::Variant(v), + Either::Right(v) => Definition::EnumVariant(v), }; let usages = strukt_def.usages(&ctx.sema).include_self_refs().all(); 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 7eca4d3f2a09..6c5c21bfc90f 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 @@ -317,7 +317,7 @@ fn find_refs_in_mod( .into_iter() .map(|v| Ref { visible_name: v.name(ctx.db()), - def: Definition::Variant(v), + def: Definition::EnumVariant(v), is_pub: true, }) .collect(), @@ -379,7 +379,7 @@ fn find_imported_defs(ctx: &AssistContext<'_>, use_item: Use) -> Vec | Definition::Module(_) | Definition::Function(_) | Definition::Adt(_) - | Definition::Variant(_) + | Definition::EnumVariant(_) | Definition::Const(_) | Definition::Static(_) | Definition::Trait(_) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_rest_pattern.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_rest_pattern.rs index 867ac4851864..a7e78dfc9c94 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_rest_pattern.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_rest_pattern.rs @@ -102,7 +102,7 @@ fn expand_tuple_struct_rest_pattern( let fields = match ctx.sema.type_of_pat(&pat.clone().into())?.original.as_adt()? { hir::Adt::Struct(s) if s.kind(ctx.sema.db) == StructKind::Tuple => s.fields(ctx.sema.db), hir::Adt::Enum(_) => match ctx.sema.resolve_path(&path)? { - PathResolution::Def(hir::ModuleDef::Variant(v)) + PathResolution::Def(hir::ModuleDef::EnumVariant(v)) if v.kind(ctx.sema.db) == StructKind::Tuple => { v.fields(ctx.sema.db) 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 a17ae4885e62..dcbeaefa21f4 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 @@ -728,7 +728,7 @@ macro_rules! check_item { } Definition::Function(x) => check_item!(x), Definition::Adt(x) => check_item!(x), - Definition::Variant(x) => check_item!(x), + Definition::EnumVariant(x) => check_item!(x), Definition::Const(x) => check_item!(x), Definition::Static(x) => check_item!(x), Definition::Trait(x) => check_item!(x), diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs index cbf4e0ec28af..4c46a51bef58 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs @@ -1,7 +1,7 @@ use std::iter; use either::Either; -use hir::{HasCrate, Module, ModuleDef, Name, Variant}; +use hir::{EnumVariant, HasCrate, Module, ModuleDef, Name}; use ide_db::{ FxHashSet, RootDatabase, defs::Definition, @@ -61,7 +61,7 @@ pub(crate) fn extract_struct_from_enum_variant( let edition = enum_hir.krate(ctx.db()).edition(ctx.db()); let variant_hir_name = variant_hir.name(ctx.db()); let enum_module_def = ModuleDef::from(enum_hir); - let usages = Definition::Variant(variant_hir).usages(&ctx.sema).all(); + let usages = Definition::EnumVariant(variant_hir).usages(&ctx.sema).all(); let mut visited_modules_set = FxHashSet::default(); let current_module = enum_hir.module(ctx.db()); @@ -161,7 +161,7 @@ fn extract_field_list_if_applicable( } } -fn existing_definition(db: &RootDatabase, variant_name: &ast::Name, variant: &Variant) -> bool { +fn existing_definition(db: &RootDatabase, variant_name: &ast::Name, variant: &EnumVariant) -> bool { variant .parent_enum(db) .module(db) @@ -173,7 +173,7 @@ fn existing_definition(db: &RootDatabase, variant_name: &ast::Name, variant: &Va def, ModuleDef::Module(_) | ModuleDef::Adt(_) - | ModuleDef::Variant(_) + | ModuleDef::EnumVariant(_) | ModuleDef::Trait(_) | ModuleDef::TypeAlias(_) | ModuleDef::BuiltinType(_) 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 7071106970a1..e5ce02cf5357 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 @@ -465,7 +465,7 @@ fn like_const_value(ctx: &AssistContext<'_>, path_resolution: hir::PathResolutio match path_resolution { hir::PathResolution::Def(def) => match def { hir::ModuleDef::Adt(adt) => adt_like_const_value(Some(adt)), - hir::ModuleDef::Variant(variant) => variant.kind(db) == hir::StructKind::Unit, + hir::ModuleDef::EnumVariant(variant) => variant.kind(db) == hir::StructKind::Unit, hir::ModuleDef::TypeAlias(ty) => adt_like_const_value(ty.ty(db).as_adt()), hir::ModuleDef::Const(_) | hir::ModuleDef::Static(_) => true, hir::ModuleDef::Trait(_) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/fix_visibility.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/fix_visibility.rs index 5134b98f1b2f..440f2d5f17ca 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/fix_visibility.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/fix_visibility.rs @@ -173,7 +173,7 @@ fn offset_target_and_file_id( // FIXME hir::ModuleDef::Macro(_) => return None, // Enum variants can't be private, we can't modify builtin types - hir::ModuleDef::Variant(_) | hir::ModuleDef::BuiltinType(_) => return None, + hir::ModuleDef::EnumVariant(_) | hir::ModuleDef::BuiltinType(_) => return None, }; Some((offset, target, target_file, target_name)) 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 009fc077ce6c..cdf20586ef15 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 @@ -102,7 +102,7 @@ fn target_path(ctx: &AssistContext<'_>, mut original_path: ast::Path) -> Option< } match ctx.sema.resolve_path(&original_path)? { - PathResolution::Def(ModuleDef::Variant(_)) if on_first => original_path.qualifier(), + PathResolution::Def(ModuleDef::EnumVariant(_)) if on_first => original_path.qualifier(), PathResolution::Def(def) if def.as_assoc_item(ctx.db()).is_some() => { on_first.then_some(original_path.qualifier()?) } 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 355687b2032b..1fb1fd4e579d 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs @@ -26,7 +26,7 @@ use std::iter; -use hir::{HasAttrs, Name, ScopeDef, Variant, sym}; +use hir::{EnumVariant, HasAttrs, Name, ScopeDef, sym}; use ide_db::{RootDatabase, SymbolKind, imports::import_assets::LocatedImport}; use syntax::{SmolStr, ToSmolStr, ast}; @@ -426,7 +426,7 @@ pub(crate) fn add_qualified_enum_variant( &mut self, ctx: &CompletionContext<'_>, path_ctx: &PathCompletionCtx<'_>, - variant: hir::Variant, + variant: hir::EnumVariant, path: hir::ModPath, ) { if !ctx.check_stability_and_hidden(variant) { @@ -443,7 +443,7 @@ pub(crate) fn add_enum_variant( &mut self, ctx: &CompletionContext<'_>, path_ctx: &PathCompletionCtx<'_>, - variant: hir::Variant, + variant: hir::EnumVariant, local_name: Option, ) { if !ctx.check_stability_and_hidden(variant) { @@ -569,7 +569,7 @@ pub(crate) fn add_variant_pat( ctx: &CompletionContext<'_>, pattern_ctx: &PatternContext, path_ctx: Option<&PathCompletionCtx<'_>>, - variant: hir::Variant, + variant: hir::EnumVariant, local_name: Option, ) { if !ctx.check_stability_and_hidden(variant) { @@ -589,7 +589,7 @@ pub(crate) fn add_qualified_variant_pat( &mut self, ctx: &CompletionContext<'_>, pattern_ctx: &PatternContext, - variant: hir::Variant, + variant: hir::EnumVariant, path: hir::ModPath, ) { if !ctx.check_stability_and_hidden(variant) { @@ -644,9 +644,9 @@ fn enum_variants_with_paths( ctx: &CompletionContext<'_>, enum_: hir::Enum, impl_: Option<&ast::Impl>, - cb: impl Fn(&mut Completions, &CompletionContext<'_>, hir::Variant, hir::ModPath), + cb: impl Fn(&mut Completions, &CompletionContext<'_>, hir::EnumVariant, hir::ModPath), ) { - let mut process_variant = |variant: Variant| { + let mut process_variant = |variant: EnumVariant| { let self_path = hir::ModPath::from_segments( hir::PathKind::Plain, iter::once(Name::new_symbol_root(sym::Self_)).chain(iter::once(variant.name(ctx.db))), diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/pattern.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/pattern.rs index 6e9328165d95..e7597bf95c80 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/pattern.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/pattern.rs @@ -91,7 +91,7 @@ pub(crate) fn complete_pattern( acc.add_struct_pat(ctx, pattern_ctx, strukt, Some(name.clone())); true } - hir::ModuleDef::Variant(variant) + hir::ModuleDef::EnumVariant(variant) if refutable || single_variant_enum(variant.parent_enum(ctx.db)) => { acc.add_variant_pat(ctx, pattern_ctx, None, variant, Some(name.clone())); @@ -190,7 +190,7 @@ pub(crate) fn complete_pattern_path( let add_completion = match res { ScopeDef::ModuleDef(hir::ModuleDef::Macro(mac)) => mac.is_fn_like(ctx.db), ScopeDef::ModuleDef(hir::ModuleDef::Adt(_)) => true, - ScopeDef::ModuleDef(hir::ModuleDef::Variant(_)) => true, + ScopeDef::ModuleDef(hir::ModuleDef::EnumVariant(_)) => true, ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) => true, ScopeDef::ImplSelfType(_) => true, _ => false, 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 abcf9fca6f29..8ff9c3258e8e 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 @@ -23,7 +23,9 @@ pub(crate) fn complete_type_path( ScopeDef::GenericParam(LifetimeParam(_)) => location.complete_lifetimes(), ScopeDef::Label(_) => false, // no values in type places - ScopeDef::ModuleDef(Function(_) | Variant(_) | Static(_)) | ScopeDef::Local(_) => false, + ScopeDef::ModuleDef(Function(_) | EnumVariant(_) | Static(_)) | ScopeDef::Local(_) => { + false + } // unless its a constant in a generic arg list position ScopeDef::ModuleDef(Const(_)) | ScopeDef::GenericParam(ConstParam(_)) => { location.complete_consts() 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 97afd07b0086..4fd0348156a5 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs @@ -288,7 +288,7 @@ pub(crate) struct PatternContext { pub(crate) record_pat: Option, pub(crate) impl_or_trait: Option>, /// List of missing variants in a match expr - pub(crate) missing_variants: Vec, + pub(crate) missing_variants: Vec, } #[derive(Debug, Clone, PartialEq, Eq)] @@ -527,7 +527,7 @@ pub(crate) fn def_is_visible(&self, item: &ScopeDef) -> Visible { hir::ModuleDef::Module(it) => self.is_visible(it), hir::ModuleDef::Function(it) => self.is_visible(it), hir::ModuleDef::Adt(it) => self.is_visible(it), - hir::ModuleDef::Variant(it) => self.is_visible(it), + hir::ModuleDef::EnumVariant(it) => self.is_visible(it), hir::ModuleDef::Const(it) => self.is_visible(it), hir::ModuleDef::Static(it) => self.is_visible(it), hir::ModuleDef::Trait(it) => self.is_visible(it), 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 bf899539a20b..a3494b964f89 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 @@ -1,7 +1,7 @@ //! Module responsible for analyzing the code surrounding the cursor for completion. use std::iter; -use hir::{ExpandResult, InFile, Semantics, Type, TypeInfo, Variant}; +use hir::{EnumVariant, ExpandResult, InFile, Semantics, Type, TypeInfo}; use ide_db::{ RootDatabase, active_parameter::ActiveParameter, syntax_helpers::node_ext::find_loops, }; @@ -781,7 +781,7 @@ fn expected_type_and_name<'db>( ast::TupleStructPat(it) => { let fields = it.path().and_then(|path| match sema.resolve_path(&path)? { hir::PathResolution::Def(hir::ModuleDef::Adt(adt)) => Some(adt.as_struct()?.fields(sema.db)), - hir::PathResolution::Def(hir::ModuleDef::Variant(variant)) => Some(variant.fields(sema.db)), + hir::PathResolution::Def(hir::ModuleDef::EnumVariant(variant)) => Some(variant.fields(sema.db)), _ => None, }); let nr = it.fields().take_while(|it| it.syntax().text_range().end() <= token.text_range().start()).count(); @@ -1149,7 +1149,7 @@ fn classify_name_ref<'db>( hir::ModuleDef::Adt(adt) => { sema.source(adt)?.value.generic_param_list() } - hir::ModuleDef::Variant(variant) => { + hir::ModuleDef::EnumVariant(variant) => { sema.source(variant.parent_enum(sema.db))?.value.generic_param_list() } hir::ModuleDef::Trait(trait_) => { @@ -1825,7 +1825,7 @@ fn pattern_context_for( }); (!variant_already_present).then_some(*variant) - }).collect::>()) + }).collect::>()) }); if let Some(missing_variants_) = missing_variants_opt { 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 765304d8187d..d77e79329541 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/render.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/render.rs @@ -408,7 +408,7 @@ fn render_resolution_path( let ctx = ctx.import_to_add(import_to_add); return render_fn(ctx, path_ctx, Some(local_name), func); } - ScopeDef::ModuleDef(Variant(var)) => { + ScopeDef::ModuleDef(EnumVariant(var)) => { let ctx = ctx.clone().import_to_add(import_to_add.clone()); if let Some(item) = render_variant_lit(ctx, path_ctx, Some(local_name.clone()), var, None) @@ -476,7 +476,7 @@ fn render_resolution_path( } // Filtered out above ScopeDef::ModuleDef( - ModuleDef::Function(_) | ModuleDef::Variant(_) | ModuleDef::Macro(_), + ModuleDef::Function(_) | ModuleDef::EnumVariant(_) | ModuleDef::Macro(_), ) => (), ScopeDef::ModuleDef(ModuleDef::Const(konst)) => set_item_relevance(konst.ty(db)), ScopeDef::ModuleDef(ModuleDef::Static(stat)) => set_item_relevance(stat.ty(db)), @@ -528,7 +528,7 @@ fn res_to_kind(resolution: ScopeDef) -> CompletionItemKind { match resolution { ScopeDef::Unknown => CompletionItemKind::UnresolvedReference, ScopeDef::ModuleDef(Function(_)) => CompletionItemKind::SymbolKind(SymbolKind::Function), - ScopeDef::ModuleDef(Variant(_)) => CompletionItemKind::SymbolKind(SymbolKind::Variant), + ScopeDef::ModuleDef(EnumVariant(_)) => CompletionItemKind::SymbolKind(SymbolKind::Variant), ScopeDef::ModuleDef(Macro(_)) => CompletionItemKind::SymbolKind(SymbolKind::Macro), ScopeDef::ModuleDef(Module(..)) => CompletionItemKind::SymbolKind(SymbolKind::Module), ScopeDef::ModuleDef(Adt(adt)) => CompletionItemKind::SymbolKind(match adt { @@ -559,7 +559,7 @@ fn scope_def_docs(db: &RootDatabase, resolution: ScopeDef) -> Option it.docs(db), ScopeDef::ModuleDef(Adt(it)) => it.docs(db), - ScopeDef::ModuleDef(Variant(it)) => it.docs(db), + ScopeDef::ModuleDef(EnumVariant(it)) => it.docs(db), ScopeDef::ModuleDef(Const(it)) => it.docs(db), ScopeDef::ModuleDef(Static(it)) => it.docs(db), ScopeDef::ModuleDef(Trait(it)) => it.docs(db), diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/literal.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/literal.rs index 8b14f05b72b2..6e49af980aea 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/render/literal.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/literal.rs @@ -23,7 +23,7 @@ pub(crate) fn render_variant_lit( ctx: RenderContext<'_>, path_ctx: &PathCompletionCtx<'_>, local_name: Option, - variant: hir::Variant, + variant: hir::EnumVariant, path: Option, ) -> Option { let _p = tracing::info_span!("render_variant_lit").entered(); @@ -150,7 +150,7 @@ fn render( #[derive(Clone, Copy)] enum Variant { Struct(hir::Struct), - EnumVariant(hir::Variant), + EnumVariant(hir::EnumVariant), } impl Variant { diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/pattern.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/pattern.rs index 60474a31b4d3..fb35d7b9b671 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/render/pattern.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/pattern.rs @@ -47,7 +47,7 @@ pub(crate) fn render_variant_pat( ctx: RenderContext<'_>, pattern_ctx: &PatternContext, path_ctx: Option<&PathCompletionCtx<'_>>, - variant: hir::Variant, + variant: hir::EnumVariant, local_name: Option, path: Option<&hir::ModPath>, ) -> Option { diff --git a/src/tools/rust-analyzer/crates/ide-db/src/active_parameter.rs b/src/tools/rust-analyzer/crates/ide-db/src/active_parameter.rs index f5a5b76c336a..8bd4c6c46b85 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/active_parameter.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/active_parameter.rs @@ -113,7 +113,7 @@ pub fn generic_def_for_node( sema: &Semantics<'_, RootDatabase>, generic_arg_list: &ast::GenericArgList, token: &SyntaxToken, -) -> Option<(hir::GenericDef, usize, bool, Option)> { +) -> Option<(hir::GenericDef, usize, bool, Option)> { let parent = generic_arg_list.syntax().parent()?; let mut variant = None; let def = match_ast! { @@ -125,7 +125,7 @@ pub fn generic_def_for_node( hir::PathResolution::Def(hir::ModuleDef::Function(it)) => it.into(), hir::PathResolution::Def(hir::ModuleDef::Trait(it)) => it.into(), hir::PathResolution::Def(hir::ModuleDef::TypeAlias(it)) => it.into(), - hir::PathResolution::Def(hir::ModuleDef::Variant(it)) => { + hir::PathResolution::Def(hir::ModuleDef::EnumVariant(it)) => { variant = Some(it); it.parent_enum(sema.db).into() }, 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 6ee4c97c873f..82cff372963a 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/defs.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/defs.rs @@ -14,11 +14,11 @@ use either::Either; use hir::{ Adt, AsAssocItem, AsExternAssocItem, AssocItem, AttributeTemplate, BuiltinAttr, BuiltinType, - Const, Crate, DefWithBody, DeriveHelper, DisplayTarget, DocLinkDef, ExpressionStoreOwner, - ExternAssocItem, ExternCrateDecl, Field, Function, GenericDef, GenericParam, - GenericSubstitution, HasContainer, HasVisibility, HirDisplay, Impl, InlineAsmOperand, - ItemContainer, Label, Local, Macro, Module, ModuleDef, Name, PathResolution, Semantics, Static, - StaticLifetime, Struct, ToolModule, Trait, TupleField, TypeAlias, Variant, VariantDef, + Const, Crate, DefWithBody, DeriveHelper, DisplayTarget, DocLinkDef, EnumVariant, + ExpressionStoreOwner, ExternAssocItem, ExternCrateDecl, Field, Function, GenericDef, + GenericParam, GenericSubstitution, HasContainer, HasVisibility, HirDisplay, Impl, + InlineAsmOperand, ItemContainer, Label, Local, Macro, Module, ModuleDef, Name, PathResolution, + Semantics, Static, StaticLifetime, Struct, ToolModule, Trait, TupleField, TypeAlias, Variant, Visibility, }; use span::Edition; @@ -39,7 +39,7 @@ pub enum Definition { Crate(Crate), Function(Function), Adt(Adt), - Variant(Variant), + EnumVariant(EnumVariant), Const(Const), Static(Static), Trait(Trait), @@ -86,7 +86,7 @@ pub fn module(&self, db: &RootDatabase) -> Option { Definition::Static(it) => it.module(db), Definition::Trait(it) => it.module(db), Definition::TypeAlias(it) => it.module(db), - Definition::Variant(it) => it.module(db), + Definition::EnumVariant(it) => it.module(db), Definition::SelfType(it) => it.module(db), Definition::Local(it) => it.module(db), Definition::GenericParam(it) => it.module(db), @@ -124,7 +124,7 @@ fn container_to_definition(container: ItemContainer) -> Option { Definition::Static(it) => container_to_definition(it.container(db)), Definition::Trait(it) => container_to_definition(it.container(db)), Definition::TypeAlias(it) => container_to_definition(it.container(db)), - Definition::Variant(it) => Some(Adt::Enum(it.parent_enum(db)).into()), + Definition::EnumVariant(it) => Some(Adt::Enum(it.parent_enum(db)).into()), Definition::SelfType(it) => Some(it.module(db).into()), Definition::Local(it) => it.parent(db).try_into().ok(), Definition::GenericParam(it) => Some(it.parent().into()), @@ -152,7 +152,7 @@ pub fn visibility(&self, db: &RootDatabase) -> Option { Definition::Static(it) => it.visibility(db), Definition::Trait(it) => it.visibility(db), Definition::TypeAlias(it) => it.visibility(db), - Definition::Variant(it) => it.visibility(db), + Definition::EnumVariant(it) => it.visibility(db), Definition::ExternCrateDecl(it) => it.visibility(db), Definition::Macro(it) => it.visibility(db), Definition::BuiltinType(_) | Definition::TupleField(_) => Visibility::Public, @@ -180,7 +180,7 @@ pub fn name(&self, db: &RootDatabase) -> Option { } Definition::Function(it) => it.name(db), Definition::Adt(it) => it.name(db), - Definition::Variant(it) => it.name(db), + Definition::EnumVariant(it) => it.name(db), Definition::Const(it) => it.name(db)?, Definition::Static(it) => it.name(db), Definition::Trait(it) => it.name(db), @@ -228,7 +228,7 @@ pub fn docs_with_rangemap<'db>( Definition::Crate(it) => it.docs_with_rangemap(db), Definition::Function(it) => it.docs_with_rangemap(db), Definition::Adt(it) => it.docs_with_rangemap(db), - Definition::Variant(it) => it.docs_with_rangemap(db), + Definition::EnumVariant(it) => it.docs_with_rangemap(db), Definition::Const(it) => it.docs_with_rangemap(db), Definition::Static(it) => it.docs_with_rangemap(db), Definition::Trait(it) => it.docs_with_rangemap(db), @@ -316,7 +316,7 @@ pub fn label(&self, db: &RootDatabase, display_target: DisplayTarget) -> String Definition::Crate(it) => it.display(db, display_target).to_string(), Definition::Function(it) => it.display(db, display_target).to_string(), Definition::Adt(it) => it.display(db, display_target).to_string(), - Definition::Variant(it) => it.display(db, display_target).to_string(), + Definition::EnumVariant(it) => it.display(db, display_target).to_string(), Definition::Const(it) => it.display(db, display_target).to_string(), Definition::Static(it) => it.display(db, display_target).to_string(), Definition::Trait(it) => it.display(db, display_target).to_string(), @@ -557,7 +557,7 @@ pub fn classify( ast::Rename(it) => classify_rename(sema, it)?, ast::SelfParam(it) => Definition::Local(sema.to_def(&it)?), ast::RecordField(it) => Definition::Field(sema.to_def(&it)?), - ast::Variant(it) => Definition::Variant(sema.to_def(&it)?), + ast::Variant(it) => Definition::EnumVariant(sema.to_def(&it)?), ast::TypeParam(it) => Definition::GenericParam(sema.to_def(&it)?.into()), ast::ConstParam(it) => Definition::GenericParam(sema.to_def(&it)?.into()), ast::AsmOperandNamed(it) => Definition::InlineAsmOperand(sema.to_def(&it)?), @@ -849,7 +849,7 @@ pub fn classify( ast::OffsetOfExpr(_) => { let (def, subst) = sema.resolve_offset_of_field(name_ref)?; let def = match def { - Either::Left(variant) => Definition::Variant(variant), + Either::Left(variant) => Definition::EnumVariant(variant), Either::Right(field) => Definition::Field(field), }; Some(NameRefClass::Definition(def, Some(subst))) @@ -892,7 +892,7 @@ pub fn classify_lifetime( } impl_from!( - Field, Module, Function, Adt, Variant, Const, Static, Trait, TypeAlias, BuiltinType, Local, + Field, Module, Function, Adt, EnumVariant, Const, Static, Trait, TypeAlias, BuiltinType, Local, GenericParam, Label, Macro, ExternCrateDecl for Definition ); @@ -968,7 +968,7 @@ fn from(def: ModuleDef) -> Self { ModuleDef::Module(it) => Definition::Module(it), ModuleDef::Function(it) => Definition::Function(it), ModuleDef::Adt(it) => Definition::Adt(it), - ModuleDef::Variant(it) => Definition::Variant(it), + ModuleDef::EnumVariant(it) => Definition::EnumVariant(it), ModuleDef::Const(it) => Definition::Const(it), ModuleDef::Static(it) => Definition::Static(it), ModuleDef::Trait(it) => Definition::Trait(it), @@ -989,8 +989,8 @@ fn from(def: DocLinkDef) -> Self { } } -impl From for Definition { - fn from(def: VariantDef) -> Self { +impl From for Definition { + fn from(def: Variant) -> Self { ModuleDef::from(def).into() } } @@ -1002,7 +1002,7 @@ fn try_from(def: DefWithBody) -> Result { DefWithBody::Function(it) => Ok(it.into()), DefWithBody::Static(it) => Ok(it.into()), DefWithBody::Const(it) => Ok(it.into()), - DefWithBody::Variant(it) => Ok(it.into()), + DefWithBody::EnumVariant(it) => Ok(it.into()), } } } @@ -1027,6 +1027,7 @@ fn try_from(def: ExpressionStoreOwner) -> Result { match def { ExpressionStoreOwner::Body(def_with_body) => def_with_body.try_into(), ExpressionStoreOwner::Signature(generic_def) => Ok(generic_def.into()), + ExpressionStoreOwner::VariantFields(it) => Ok(it.into()), } } } diff --git a/src/tools/rust-analyzer/crates/ide-db/src/documentation.rs b/src/tools/rust-analyzer/crates/ide-db/src/documentation.rs index 4c4691cca2ca..407049f4b362 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/documentation.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/documentation.rs @@ -58,8 +58,22 @@ impl HasDocs for hir::$def {} } impl_has_docs![ - Variant, Field, Static, Const, Trait, TypeAlias, Macro, Function, Adt, Module, Impl, Crate, - AssocItem, Struct, Union, Enum, + EnumVariant, + Field, + Static, + Const, + Trait, + TypeAlias, + Macro, + Function, + Adt, + Module, + Impl, + Crate, + AssocItem, + Struct, + Union, + Enum, ]; impl HasDocs for hir::ExternCrateDecl { 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 023b32b36195..cde0705d8ac2 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/lib.rs @@ -312,7 +312,7 @@ impl SymbolKind { pub fn from_module_def(db: &dyn HirDatabase, it: hir::ModuleDef) -> Self { match it { hir::ModuleDef::Const(..) => SymbolKind::Const, - hir::ModuleDef::Variant(..) => SymbolKind::Variant, + hir::ModuleDef::EnumVariant(..) => SymbolKind::Variant, hir::ModuleDef::Function(..) => SymbolKind::Function, hir::ModuleDef::Macro(mac) if mac.is_proc_macro() => SymbolKind::ProcMacro, hir::ModuleDef::Macro(..) => SymbolKind::Macro, diff --git a/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs b/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs index 01a326a0dc63..508f841340b1 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs @@ -580,7 +580,7 @@ fn transform_ident_pat( } } - if let hir::ModuleDef::Variant(v) = def + if let hir::ModuleDef::EnumVariant(v) = def && v.kind(self.source_scope.db) != hir::StructKind::Unit { return None; 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 b03a5b6efb6a..b18ed69d80fe 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/rename.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/rename.rs @@ -170,7 +170,7 @@ pub fn range_for_rename(self, sema: &Semantics<'_, RootDatabase>) -> Option name_range(it, sema).and_then(syn_ctx_is_root), hir::Adt::Enum(it) => name_range(it, sema).and_then(syn_ctx_is_root), }, - Definition::Variant(it) => name_range(it, sema).and_then(syn_ctx_is_root), + Definition::EnumVariant(it) => name_range(it, sema).and_then(syn_ctx_is_root), Definition::Const(it) => name_range(it, sema).and_then(syn_ctx_is_root), Definition::Static(it) => name_range(it, sema).and_then(syn_ctx_is_root), Definition::Trait(it) => name_range(it, sema).and_then(syn_ctx_is_root), 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 2cf4627ac892..25acb47f7b4c 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/search.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/search.rs @@ -314,7 +314,7 @@ fn search_scope(&self, db: &RootDatabase) -> SearchScope { DefWithBody::Function(f) => f.source(db).map(|src| src.syntax().cloned()), DefWithBody::Const(c) => c.source(db).map(|src| src.syntax().cloned()), DefWithBody::Static(s) => s.source(db).map(|src| src.syntax().cloned()), - DefWithBody::Variant(v) => v.source(db).map(|src| src.syntax().cloned()), + DefWithBody::EnumVariant(v) => v.source(db).map(|src| src.syntax().cloned()), }, ExpressionStoreOwner::Signature(def) => match def { hir::GenericDef::Function(it) => it.source(db).map(|src| src.syntax().cloned()), @@ -327,6 +327,9 @@ fn search_scope(&self, db: &RootDatabase) -> SearchScope { hir::GenericDef::Const(it) => it.source(db).map(|src| src.syntax().cloned()), hir::GenericDef::Static(it) => it.source(db).map(|src| src.syntax().cloned()), }, + ExpressionStoreOwner::VariantFields(it) => { + it.source(db).map(|src| src.syntax().cloned()) + } }; return match def { Some(def) => SearchScope::file_range( @@ -342,7 +345,7 @@ fn search_scope(&self, db: &RootDatabase) -> SearchScope { DefWithBody::Function(f) => f.source(db).map(|src| src.syntax().cloned()), DefWithBody::Const(c) => c.source(db).map(|src| src.syntax().cloned()), DefWithBody::Static(s) => s.source(db).map(|src| src.syntax().cloned()), - DefWithBody::Variant(v) => v.source(db).map(|src| src.syntax().cloned()), + DefWithBody::EnumVariant(v) => v.source(db).map(|src| src.syntax().cloned()), }, ExpressionStoreOwner::Signature(def) => match def { hir::GenericDef::Function(it) => it.source(db).map(|src| src.syntax().cloned()), @@ -355,6 +358,9 @@ fn search_scope(&self, db: &RootDatabase) -> SearchScope { hir::GenericDef::Const(it) => it.source(db).map(|src| src.syntax().cloned()), hir::GenericDef::Static(it) => it.source(db).map(|src| src.syntax().cloned()), }, + ExpressionStoreOwner::VariantFields(it) => { + it.source(db).map(|src| src.syntax().cloned()) + } }; return match def { Some(def) => SearchScope::file_range( 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 46d938b5a503..02a023038a61 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 @@ -8,8 +8,8 @@ [ FileSymbol { name: "A", - def: Variant( - Variant { + def: EnumVariant( + EnumVariant { id: EnumVariantId( 7c00, ), @@ -80,8 +80,8 @@ }, FileSymbol { name: "B", - def: Variant( - Variant { + def: EnumVariant( + EnumVariant { id: EnumVariantId( 7c01, ), 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 619bb2307cd4..944622bb1d58 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 @@ -64,20 +64,20 @@ fn missing_record_expr_field_fixes( let module; let def_file_id; let record_fields = match def_id { - hir::VariantDef::Struct(s) => { + hir::Variant::Struct(s) => { module = s.module(sema.db); let source = s.source(sema.db)?; def_file_id = source.file_id; let fields = source.value.field_list()?; record_field_list(fields)? } - hir::VariantDef::Union(u) => { + hir::Variant::Union(u) => { module = u.module(sema.db); let source = u.source(sema.db)?; def_file_id = source.file_id; source.value.record_field_list()? } - hir::VariantDef::Variant(e) => { + hir::Variant::EnumVariant(e) => { module = e.module(sema.db); let source = e.source(sema.db)?; def_file_id = source.file_id; @@ -116,7 +116,7 @@ fn missing_record_expr_field_fixes( let mut new_field = new_field.to_string(); // FIXME: check submodule instead of FileId - if usage_file_id != def_file_id && !matches!(def_id, hir::VariantDef::Variant(_)) { + if usage_file_id != def_file_id && !matches!(def_id, hir::Variant::EnumVariant(_)) { new_field = format!("pub(crate) {new_field}"); } new_field = format!("\n{indent}{new_field}{postfix}"); 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 d854c1c45044..33bed9501a39 100644 --- a/src/tools/rust-analyzer/crates/ide/src/doc_links.rs +++ b/src/tools/rust-analyzer/crates/ide/src/doc_links.rs @@ -219,7 +219,7 @@ pub(crate) fn resolve_doc_path_for_def( Definition::Crate(it) => it.resolve_doc_path(db, link, ns, is_inner_doc), Definition::Function(it) => it.resolve_doc_path(db, link, ns, is_inner_doc), Definition::Adt(it) => it.resolve_doc_path(db, link, ns, is_inner_doc), - Definition::Variant(it) => it.resolve_doc_path(db, link, ns, is_inner_doc), + Definition::EnumVariant(it) => it.resolve_doc_path(db, link, ns, is_inner_doc), Definition::Const(it) => it.resolve_doc_path(db, link, ns, is_inner_doc), Definition::Static(it) => it.resolve_doc_path(db, link, ns, is_inner_doc), Definition::Trait(it) => it.resolve_doc_path(db, link, ns, is_inner_doc), @@ -678,7 +678,7 @@ fn filename_and_frag_for_def( Definition::Function(f) => { format!("fn.{}.html", f.name(db).as_str()) } - Definition::Variant(ev) => { + Definition::EnumVariant(ev) => { let def = Definition::Adt(ev.parent_enum(db).into()); let (_, file, _) = filename_and_frag_for_def(db, def)?; return Some((def, file, Some(format!("variant.{}", ev.name(db).as_str())))); @@ -703,9 +703,9 @@ fn filename_and_frag_for_def( }, Definition::Field(field) => { let def = match field.parent_def(db) { - hir::VariantDef::Struct(it) => Definition::Adt(it.into()), - hir::VariantDef::Union(it) => Definition::Adt(it.into()), - hir::VariantDef::Variant(it) => Definition::Variant(it), + hir::Variant::Struct(it) => Definition::Adt(it.into()), + hir::Variant::Union(it) => Definition::Adt(it.into()), + hir::Variant::EnumVariant(it) => Definition::EnumVariant(it), }; let (_, file, _) = filename_and_frag_for_def(db, def)?; return Some((def, file, Some(format!("structfield.{}", field.name(db).as_str())))); 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 a61a6c677f65..509c55a31e58 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 @@ -113,7 +113,7 @@ fn node_to_def<'db>( ast::Struct(it) => sema.to_def(&it).map(|def| (def.docs_with_rangemap(sema.db), Definition::Adt(hir::Adt::Struct(def)))), ast::Union(it) => sema.to_def(&it).map(|def| (def.docs_with_rangemap(sema.db), Definition::Adt(hir::Adt::Union(def)))), ast::Enum(it) => sema.to_def(&it).map(|def| (def.docs_with_rangemap(sema.db), Definition::Adt(hir::Adt::Enum(def)))), - ast::Variant(it) => sema.to_def(&it).map(|def| (def.docs_with_rangemap(sema.db), Definition::Variant(def))), + ast::Variant(it) => sema.to_def(&it).map(|def| (def.docs_with_rangemap(sema.db), Definition::EnumVariant(def))), ast::Trait(it) => sema.to_def(&it).map(|def| (def.docs_with_rangemap(sema.db), Definition::Trait(def))), ast::Static(it) => sema.to_def(&it).map(|def| (def.docs_with_rangemap(sema.db), Definition::Static(def))), ast::Const(it) => sema.to_def(&it).map(|def| (def.docs_with_rangemap(sema.db), Definition::Const(def))), 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 cf5f137cdd03..af78e9a40c9f 100644 --- a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs +++ b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs @@ -5,7 +5,7 @@ use hir::{ Adt, AsAssocItem, AsExternAssocItem, CaptureKind, DisplayTarget, DropGlue, DynCompatibilityViolation, HasCrate, HasSource, HirDisplay, Layout, LayoutError, - MethodViolationCode, Name, Semantics, Symbol, Trait, Type, TypeInfo, VariantDef, + MethodViolationCode, Name, Semantics, Symbol, Trait, Type, TypeInfo, Variant, db::ExpandDatabase, }; use ide_db::{ @@ -366,14 +366,14 @@ fn definition_owner_name(db: &RootDatabase, def: Definition, edition: Edition) - let parent_name = parent.name(db); let parent_name = parent_name.display(db, edition).to_string(); return match parent { - VariantDef::Variant(variant) => { + Variant::EnumVariant(variant) => { let enum_name = variant.parent_enum(db).name(db); Some(format!("{}::{parent_name}", enum_name.display(db, edition))) } _ => Some(parent_name), }; } - Definition::Variant(e) => Some(e.parent_enum(db).name(db)), + Definition::EnumVariant(e) => Some(e.parent_enum(db).name(db)), Definition::GenericParam(generic_param) => match generic_param.parent() { hir::GenericDef::Adt(it) => Some(it.name(db)), hir::GenericDef::Trait(it) => Some(it.name(db)), @@ -470,7 +470,7 @@ pub(super) fn definition( Definition::Adt(adt @ (Adt::Struct(_) | Adt::Union(_))) => { adt.display_limited(db, config.max_fields_count, display_target).to_string() } - Definition::Variant(variant) => { + Definition::EnumVariant(variant) => { variant.display_limited(db, config.max_fields_count, display_target).to_string() } Definition::Adt(adt @ Adt::Enum(_)) => { @@ -499,7 +499,7 @@ pub(super) fn definition( }; let docs = def.docs_with_rangemap(db, famous_defs, display_target); let value = || match def { - Definition::Variant(it) => { + Definition::EnumVariant(it) => { if !it.parent_enum(db).is_data_carrying(db) { match it.eval(db) { Ok(it) => { @@ -596,7 +596,7 @@ pub(super) fn definition( |_| { let var_def = it.parent_def(db); match var_def { - hir::VariantDef::Struct(s) => { + hir::Variant::Struct(s) => { Adt::from(s).layout(db).ok().and_then(|layout| layout.field_offset(it)) } _ => None, @@ -627,7 +627,7 @@ pub(super) fn definition( |_| None, |_| None, ), - Definition::Variant(it) => render_memory_layout( + Definition::EnumVariant(it) => render_memory_layout( config.memory_layout, || it.layout(db), |_| None, @@ -710,7 +710,7 @@ pub(super) fn definition( has_dtor: Some(enum_drop_glue > fields_drop_glue), } } - Definition::Variant(variant) => { + Definition::EnumVariant(variant) => { let fields_drop_glue = variant .fields(db) .iter() diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs index f1e62a5ab8ac..08588bbed090 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs @@ -374,7 +374,7 @@ fn is_adt_constructor_similar_to_param_name( hir::PathResolution::Def(hir::ModuleDef::Adt(_)) => { Some(to_lower_snake_case(&path.segment()?.name_ref()?.text()) == param_name) } - hir::PathResolution::Def(hir::ModuleDef::Function(_) | hir::ModuleDef::Variant(_)) => { + hir::PathResolution::Def(hir::ModuleDef::Function(_) | hir::ModuleDef::EnumVariant(_)) => { if to_lower_snake_case(&path.segment()?.name_ref()?.text()) == param_name { return Some(true); } diff --git a/src/tools/rust-analyzer/crates/ide/src/moniker.rs b/src/tools/rust-analyzer/crates/ide/src/moniker.rs index 1c1389ca7a15..335e1b5b13ca 100644 --- a/src/tools/rust-analyzer/crates/ide/src/moniker.rs +++ b/src/tools/rust-analyzer/crates/ide/src/moniker.rs @@ -205,7 +205,7 @@ pub(crate) fn def_to_kind(db: &RootDatabase, def: Definition) -> SymbolInformati Definition::Adt(Adt::Struct(..)) => Struct, Definition::Adt(Adt::Union(..)) => Union, Definition::Adt(Adt::Enum(..)) => Enum, - Definition::Variant(..) => EnumMember, + Definition::EnumVariant(..) => EnumMember, Definition::Const(..) => Constant, Definition::Static(..) => StaticVariable, Definition::Trait(..) => Trait, 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 185df92e2d39..92020321f453 100644 --- a/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs +++ b/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs @@ -276,7 +276,7 @@ fn try_to_nav( Some(it.display(db, display_target).to_string()) } hir::ModuleDef::Adt(it) => Some(it.display(db, display_target).to_string()), - hir::ModuleDef::Variant(it) => { + hir::ModuleDef::EnumVariant(it) => { Some(it.display(db, display_target).to_string()) } hir::ModuleDef::Const(it) => { @@ -319,7 +319,7 @@ fn try_to_nav( Definition::GenericParam(it) => it.try_to_nav(sema), Definition::Function(it) => it.try_to_nav(sema), Definition::Adt(it) => it.try_to_nav(sema), - Definition::Variant(it) => it.try_to_nav(sema), + Definition::EnumVariant(it) => it.try_to_nav(sema), Definition::Const(it) => it.try_to_nav(sema), Definition::Static(it) => it.try_to_nav(sema), Definition::Trait(it) => it.try_to_nav(sema), @@ -347,7 +347,7 @@ fn try_to_nav( hir::ModuleDef::Module(it) => Some(it.to_nav(sema.db)), hir::ModuleDef::Function(it) => it.try_to_nav(sema), hir::ModuleDef::Adt(it) => it.try_to_nav(sema), - hir::ModuleDef::Variant(it) => it.try_to_nav(sema), + hir::ModuleDef::EnumVariant(it) => it.try_to_nav(sema), hir::ModuleDef::Const(it) => it.try_to_nav(sema), hir::ModuleDef::Static(it) => it.try_to_nav(sema), hir::ModuleDef::Trait(it) => it.try_to_nav(sema), @@ -406,7 +406,7 @@ fn container_name(self, db: &RootDatabase) -> Option { container_name(db, self) } } -impl ToNavFromAst for hir::Variant { +impl ToNavFromAst for hir::EnumVariant { const KIND: SymbolKind = SymbolKind::Variant; } impl ToNavFromAst for hir::Union { diff --git a/src/tools/rust-analyzer/crates/ide/src/references.rs b/src/tools/rust-analyzer/crates/ide/src/references.rs index 6464c477160b..9392651c1794 100644 --- a/src/tools/rust-analyzer/crates/ide/src/references.rs +++ b/src/tools/rust-analyzer/crates/ide/src/references.rs @@ -299,7 +299,7 @@ fn retain_adt_literal_usages( }); usages.references.retain(|_, it| !it.is_empty()); } - Definition::Adt(_) | Definition::Variant(_) => { + Definition::Adt(_) | Definition::EnumVariant(_) => { refs.for_each(|it| { it.retain(|reference| reference.name.as_name_ref().is_some_and(is_lit_name_ref)) }); @@ -377,7 +377,7 @@ fn is_enum_lit_name_ref( let path_is_variant_of_enum = |path: ast::Path| { matches!( sema.resolve_path(&path), - Some(PathResolution::Def(hir::ModuleDef::Variant(variant))) + Some(PathResolution::Def(hir::ModuleDef::EnumVariant(variant))) if variant.parent_enum(sema.db) == enum_ ) }; diff --git a/src/tools/rust-analyzer/crates/ide/src/runnables.rs b/src/tools/rust-analyzer/crates/ide/src/runnables.rs index 42efa7142b50..a0a6a245592c 100644 --- a/src/tools/rust-analyzer/crates/ide/src/runnables.rs +++ b/src/tools/rust-analyzer/crates/ide/src/runnables.rs @@ -494,7 +494,7 @@ fn module_def_doctest(sema: &Semantics<'_, RootDatabase>, def: Definition) -> Op Definition::Module(it) => it.attrs(db), Definition::Function(it) => it.attrs(db), Definition::Adt(it) => it.attrs(db), - Definition::Variant(it) => it.attrs(db), + Definition::EnumVariant(it) => it.attrs(db), Definition::Const(it) => it.attrs(db), Definition::Static(it) => it.attrs(db), Definition::Trait(it) => it.attrs(db), diff --git a/src/tools/rust-analyzer/crates/ide/src/signature_help.rs b/src/tools/rust-analyzer/crates/ide/src/signature_help.rs index f86974b4ec76..9eb01b12f2bd 100644 --- a/src/tools/rust-analyzer/crates/ide/src/signature_help.rs +++ b/src/tools/rust-analyzer/crates/ide/src/signature_help.rs @@ -497,7 +497,7 @@ fn signature_help_for_tuple_struct_pat( }; let db = sema.db; - let fields: Vec<_> = if let PathResolution::Def(ModuleDef::Variant(variant)) = path_res { + let fields: Vec<_> = if let PathResolution::Def(ModuleDef::EnumVariant(variant)) = path_res { let en = variant.parent_enum(db); res.doc = en.docs(db).map(Documentation::into_owned); @@ -623,7 +623,7 @@ fn signature_help_for_record_<'db>( let db = sema.db; let path_res = sema.resolve_path(path)?; - if let PathResolution::Def(ModuleDef::Variant(variant)) = path_res { + if let PathResolution::Def(ModuleDef::EnumVariant(variant)) = path_res { fields = variant.fields(db); let en = variant.parent_enum(db); diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs index ce1df6a1e7dc..217b13b4ef95 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs @@ -14,7 +14,9 @@ use std::ops::ControlFlow; use either::Either; -use hir::{DefWithBody, EditionedFileId, InFile, InRealFile, MacroKind, Semantics}; +use hir::{ + DefWithBody, EditionedFileId, ExpressionStoreOwner, InFile, InRealFile, MacroKind, Semantics, +}; use ide_db::{FxHashMap, FxHashSet, MiniCore, Ranker, RootDatabase, SymbolKind}; use syntax::{ AstNode, AstToken, NodeOrToken, @@ -256,8 +258,8 @@ fn item(&self) -> &ast::Item { let mut inside_attribute = false; // FIXME: accommodate range highlighting - let mut body_stack: Vec> = vec![]; - let mut per_body_cache: FxHashMap> = FxHashMap::default(); + let mut body_stack: Vec> = vec![]; + let mut per_body_cache: FxHashMap> = FxHashMap::default(); // Walk all nodes, keeping track of whether we are inside a macro or not. // If in macro, expand it first and highlight the expanded code. @@ -288,19 +290,18 @@ fn item(&self) -> &ast::Item { inside_attribute = false } Enter(NodeOrToken::Node(node)) => { + // FIXME: ExpressionStore signatures and variant fields + // Maybe we can re-use child container stuff here if let Some(item) = >::cast(node.clone()) { match item { Either::Left(item) => { match &item { - ast::Item::Fn(it) => { - body_stack.push(sema.to_def(it).map(Into::into)) - } - ast::Item::Const(it) => { - body_stack.push(sema.to_def(it).map(Into::into)) - } - ast::Item::Static(it) => { - body_stack.push(sema.to_def(it).map(Into::into)) - } + ast::Item::Fn(it) => body_stack + .push(sema.to_def(it).map(DefWithBody::from).map(Into::into)), + ast::Item::Const(it) => body_stack + .push(sema.to_def(it).map(DefWithBody::from).map(Into::into)), + ast::Item::Static(it) => body_stack + .push(sema.to_def(it).map(DefWithBody::from).map(Into::into)), _ => (), } @@ -329,7 +330,9 @@ fn item(&self) -> &ast::Item { } } } - Either::Right(it) => body_stack.push(sema.to_def(&it).map(Into::into)), + Either::Right(it) => { + body_stack.push(sema.to_def(&it).map(DefWithBody::from).map(Into::into)) + } } } } @@ -392,11 +395,11 @@ fn item(&self) -> &ast::Item { let descended = descend_token(sema, InRealFile::new(file_id, token)); let body = match &descended.value { NodeOrToken::Node(n) => { - sema.body_for(InFile::new(descended.file_id, n.syntax())) - } - NodeOrToken::Token(t) => { - t.parent().and_then(|it| sema.body_for(InFile::new(descended.file_id, &it))) + sema.store_owner_for(InFile::new(descended.file_id, n.syntax())) } + NodeOrToken::Token(t) => t + .parent() + .and_then(|it| sema.store_owner_for(InFile::new(descended.file_id, &it))), }; (descended, body) } 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 a94bbc9f041d..0e101ab235f5 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 @@ -538,7 +538,7 @@ pub(super) fn highlight_def( (Highlight::new(h), Some(adt.attrs(sema.db))) } - Definition::Variant(variant) => { + Definition::EnumVariant(variant) => { (Highlight::new(HlTag::Symbol(SymbolKind::Variant)), Some(variant.attrs(sema.db))) } Definition::Const(konst) => { 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 291333f09cf8..74a8d93dfe82 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 @@ -209,7 +209,7 @@ fn module_def_to_hl_tag(db: &dyn HirDatabase, def: Definition) -> HlTag { Definition::Adt(hir::Adt::Struct(_)) => SymbolKind::Struct, Definition::Adt(hir::Adt::Enum(_)) => SymbolKind::Enum, Definition::Adt(hir::Adt::Union(_)) => SymbolKind::Union, - Definition::Variant(_) => SymbolKind::Variant, + Definition::EnumVariant(_) => SymbolKind::Variant, Definition::Const(_) => SymbolKind::Const, Definition::Static(_) => SymbolKind::Static, Definition::Trait(_) => SymbolKind::Trait, 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 7541a41b20eb..74828cba02ed 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 @@ -11,7 +11,7 @@ use cfg::{CfgAtom, CfgDiff}; use hir::{ Adt, AssocItem, Crate, DefWithBody, FindPathConfig, GenericDef, HasCrate, HasSource, - HirDisplay, ModuleDef, Name, crate_lang_items, + HirDisplay, ModuleDef, Name, Variant, VariantId, crate_lang_items, db::{DefDatabase, ExpandDatabase, HirDatabase}, next_solver::{DbInterner, GenericArgs}, }; @@ -230,6 +230,7 @@ pub fn run(self, verbosity: Verbosity) -> anyhow::Result<()> { let mut num_decls = 0; let mut bodies = Vec::new(); let mut signatures = Vec::new(); + let mut variants = Vec::new(); let mut adts = Vec::new(); let mut file_ids = Vec::new(); @@ -247,10 +248,15 @@ pub fn run(self, verbosity: Verbosity) -> anyhow::Result<()> { match decl { ModuleDef::Function(f) => bodies.push(DefWithBody::from(f)), ModuleDef::Adt(a) => { - if let Adt::Enum(e) = a { - for v in e.variants(db) { - bodies.push(DefWithBody::from(v)); + match a { + Adt::Enum(e) => { + for v in e.variants(db) { + bodies.push(DefWithBody::from(v)); + variants.push(Variant::EnumVariant(v)); + } } + Adt::Struct(it) => variants.push(Variant::Struct(it)), + Adt::Union(it) => variants.push(Variant::Union(it)), } adts.push(a) } @@ -293,7 +299,7 @@ pub fn run(self, verbosity: Verbosity) -> anyhow::Result<()> { } } eprintln!( - ", mods: {}, decls: {num_decls}, bodies: {}, adts: {}, consts: {}, signatures: {}", + ", mods: {}, decls: {num_decls}, bodies: {}, adts: {}, consts: {}, signatures: {}, variants: {}", visited_modules.len(), bodies.len(), adts.len(), @@ -302,6 +308,7 @@ pub fn run(self, verbosity: Verbosity) -> anyhow::Result<()> { .filter(|it| matches!(it, DefWithBody::Const(_) | DefWithBody::Static(_))) .count(), signatures.len(), + variants.len() ); eprintln!(" Workspace:"); @@ -337,15 +344,15 @@ pub fn run(self, verbosity: Verbosity) -> anyhow::Result<()> { } if !self.skip_lowering { - self.run_body_lowering(db, &vfs, &bodies, &signatures, verbosity); + self.run_body_lowering(db, &vfs, &bodies, &signatures, &variants, verbosity); } if !self.skip_inference { - self.run_inference(db, &vfs, &bodies, &signatures, verbosity); + self.run_inference(db, &vfs, &bodies, &signatures, &variants, verbosity); } if !self.skip_mir_stats { - self.run_mir_lowering(db, &bodies, &signatures, verbosity); + self.run_mir_lowering(db, &bodies, &signatures, &variants, verbosity); } if !self.skip_data_layout { @@ -353,7 +360,7 @@ pub fn run(self, verbosity: Verbosity) -> anyhow::Result<()> { } if !self.skip_const_eval { - self.run_const_eval(db, &bodies, &signatures, verbosity); + self.run_const_eval(db, &bodies, &signatures, &variants, verbosity); } }); @@ -431,6 +438,7 @@ fn run_const_eval( db: &RootDatabase, bodies: &[DefWithBody], _signatures: &[GenericDef], + _variants: &[Variant], verbosity: Verbosity, ) { let len = bodies @@ -710,6 +718,7 @@ fn run_mir_lowering( db: &RootDatabase, bodies: &[DefWithBody], _signatures: &[GenericDef], + _variants: &[Variant], verbosity: Verbosity, ) { let mut bar = match verbosity { @@ -725,7 +734,7 @@ fn run_mir_lowering( format!("mir lowering: {}", full_name(db, || body.name(db), body.module(db))) }); bar.inc(1); - if matches!(body, DefWithBody::Variant(_)) { + if matches!(body, DefWithBody::EnumVariant(_)) { continue; } let module = body.module(db); @@ -768,6 +777,7 @@ fn run_inference( vfs: &Vfs, bodies: &[DefWithBody], signatures: &[GenericDef], + variants: &[Variant], verbosity: Verbosity, ) { let mut bar = match verbosity { @@ -798,6 +808,13 @@ fn run_inference( InferenceResult::of(snap, signatures); }) .count(); + let variants = variants.iter().copied().map(Into::into).collect::>(); + variants + .par_iter() + .map_with(db.clone(), |snap, &variants| { + InferenceResult::of(snap, variants); + }) + .count(); eprintln!("{:<20} {}", "Parallel Inference:", inference_sw.elapsed()); } @@ -829,7 +846,9 @@ fn run_inference( DefWithBody::Function(it) => it.source(db).map(|it| it.syntax().cloned()), DefWithBody::Static(it) => it.source(db).map(|it| it.syntax().cloned()), DefWithBody::Const(it) => it.source(db).map(|it| it.syntax().cloned()), - DefWithBody::Variant(it) => it.source(db).map(|it| it.syntax().cloned()), + DefWithBody::EnumVariant(it) => { + it.source(db).map(|it| it.syntax().cloned()) + } }; if let Some(src) = source { let original_file = src.file_id.original_file(db); @@ -1127,12 +1146,13 @@ fn run_body_lowering( vfs: &Vfs, bodies: &[DefWithBody], signatures: &[GenericDef], + variants: &[Variant], verbosity: Verbosity, ) { let mut bar = match verbosity { Verbosity::Quiet | Verbosity::Spammy => ProgressReport::hidden(), _ if self.output.is_some() => ProgressReport::hidden(), - _ => ProgressReport::new(bodies.len() + signatures.len()), + _ => ProgressReport::new(bodies.len() + signatures.len() + variants.len()), }; let mut sw = self.stop_watch(); @@ -1181,6 +1201,44 @@ fn run_body_lowering( bar.inc(1); } + for &variant in variants { + let variant_id = variant.into(); + let module = variant.module(db); + if !self.should_process(db, || Some(variant.name(db)), module) { + continue; + } + let msg = move || { + if verbosity.is_verbose() { + let source = match variant { + Variant::EnumVariant(it) => it.source(db).map(|it| it.syntax().cloned()), + Variant::Struct(it) => it.source(db).map(|it| it.syntax().cloned()), + Variant::Union(it) => it.source(db).map(|it| it.syntax().cloned()), + }; + if let Some(src) = source { + let original_file = src.file_id.original_file(db); + let path = vfs.file_path(original_file.file_id(db)); + let syntax_range = src.text_range(); + format!( + "processing: {} ({} {:?})", + full_name(db, || Some(variant.name(db)), module), + path, + syntax_range + ) + } else { + format!("processing: {}", full_name(db, || Some(variant.name(db)), module)) + } + } else { + format!("processing: {}", full_name(db, || Some(variant.name(db)), module)) + } + }; + if verbosity.is_spammy() { + bar.println(msg()); + } + bar.set_message(msg); + ExpressionStore::of(db, ExpressionStoreOwnerId::VariantFields(variant_id)); + bar.inc(1); + } + for &body_id in bodies { let Ok(body_def_id) = body_id.try_into() else { continue }; let module = body_id.module(db); @@ -1193,7 +1251,9 @@ fn run_body_lowering( DefWithBody::Function(it) => it.source(db).map(|it| it.syntax().cloned()), DefWithBody::Static(it) => it.source(db).map(|it| it.syntax().cloned()), DefWithBody::Const(it) => it.source(db).map(|it| it.syntax().cloned()), - DefWithBody::Variant(it) => it.source(db).map(|it| it.syntax().cloned()), + DefWithBody::EnumVariant(it) => { + it.source(db).map(|it| it.syntax().cloned()) + } }; if let Some(src) = source { let original_file = src.file_id.original_file(db); From 8c2516c0799e44ae177c125c24681fb0c974485d Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sat, 28 Mar 2026 19:45:29 +0100 Subject: [PATCH 54/56] Only allocate item blocks if they actually contain items or statement macros --- .../rust-analyzer/crates/span/src/ast_id.rs | 70 ++++++++++++++----- 1 file changed, 52 insertions(+), 18 deletions(-) diff --git a/src/tools/rust-analyzer/crates/span/src/ast_id.rs b/src/tools/rust-analyzer/crates/span/src/ast_id.rs index f52604e13917..bae461e5a8de 100644 --- a/src/tools/rust-analyzer/crates/span/src/ast_id.rs +++ b/src/tools/rust-analyzer/crates/span/src/ast_id.rs @@ -206,6 +206,11 @@ fn kind(self) -> u32 { self.0 >> (HASH_BITS + INDEX_BITS) } + #[inline] + pub fn is_root(self) -> bool { + self.kind() == ErasedFileAstIdKind::Root as u32 + } + fn ast_id_for( node: &SyntaxNode, index_map: &mut ErasedAstIdNextIndexMap, @@ -220,14 +225,16 @@ fn ast_id_for( .or_else(|| asm_expr_ast_id(node, index_map)) } - fn should_alloc(node: &SyntaxNode) -> bool { + fn should_alloc(node: &SyntaxNode) -> Option { let kind = node.kind(); should_alloc_has_name(kind) - || should_alloc_assoc_item(kind) - || ast::ExternBlock::can_cast(kind) - || ast::Use::can_cast(kind) - || ast::Impl::can_cast(kind) - || ast::AsmExpr::can_cast(kind) + .or_else(|| should_alloc_assoc_item(kind)) + .or_else(|| { + ast::ExternBlock::can_cast(kind).then_some(ErasedFileAstIdKind::ExternBlock) + }) + .or_else(|| ast::Use::can_cast(kind).then_some(ErasedFileAstIdKind::Use)) + .or_else(|| ast::Impl::can_cast(kind).then_some(ErasedFileAstIdKind::Impl)) + .or_else(|| ast::AsmExpr::can_cast(kind).then_some(ErasedFileAstIdKind::AsmExpr)) } #[inline] @@ -478,8 +485,8 @@ fn has_name_ast_id(node: &SyntaxNode, index_map: &mut ErasedAstIdNextIndexMap) - } } - fn should_alloc_has_name(kind: SyntaxKind) -> bool { - false $( || ast::$ident::can_cast(kind) )* + fn should_alloc_has_name(kind: SyntaxKind) -> Option { + $( if ast::$ident::can_cast(kind) { Some(ErasedFileAstIdKind::$ident) } else )* { None } } }; } @@ -528,8 +535,8 @@ fn assoc_item_ast_id( } } - fn should_alloc_assoc_item(kind: SyntaxKind) -> bool { - false $( || ast::$ident::can_cast(kind) )* + fn should_alloc_assoc_item(kind: SyntaxKind) -> Option { + $( if ast::$ident::can_cast(kind) { Some(ErasedFileAstIdKind::$ident) } else )* { None } } }; } @@ -612,22 +619,49 @@ pub fn from_source(node: &SyntaxNode) -> AstIdMap { syntax::WalkEvent::Enter(node) => { if ast::BlockExpr::can_cast(node.kind()) { blocks.push((node, ContainsItems::No)); - } else if ErasedFileAstId::should_alloc(&node) { + } else if let Some(kind) = ErasedFileAstId::should_alloc(&node) { // Allocate blocks on-demand, only if they have items. // We don't associate items with blocks, only with items, since block IDs can be quite unstable. // FIXME: Is this the correct thing to do? Macro calls might actually be more incremental if // associated with blocks (not sure). Either way it's not a big deal. + let is_item = matches!( + kind, + ErasedFileAstIdKind::Enum + | ErasedFileAstIdKind::Struct + | ErasedFileAstIdKind::Union + | ErasedFileAstIdKind::ExternCrate + | ErasedFileAstIdKind::MacroDef + | ErasedFileAstIdKind::MacroRules + | ErasedFileAstIdKind::Module + | ErasedFileAstIdKind::Static + | ErasedFileAstIdKind::Trait + | ErasedFileAstIdKind::Const + | ErasedFileAstIdKind::Fn + | ErasedFileAstIdKind::TypeAlias + | ErasedFileAstIdKind::ExternBlock + | ErasedFileAstIdKind::Use + | ErasedFileAstIdKind::Impl + ); if let Some(( last_block_node, already_allocated @ ContainsItems::No, )) = blocks.last_mut() + && (is_item + || (kind == ErasedFileAstIdKind::MacroCall && { + let mut anc = node.ancestors(); + _ = anc.next(); + anc.next().is_some_and(|it| { + it.kind() == SyntaxKind::MACRO_EXPR + }) && anc.next().is_some_and(|it| { + it.kind() == SyntaxKind::EXPR_STMT + || it.kind() == SyntaxKind::STMT_LIST + }) + })) { - let block_ast_id = block_expr_ast_id( - last_block_node, - &mut index_map, - parent_of(parent_idx, &res), - ) - .expect("not a BlockExpr"); + let parent = parent_of(parent_idx, &res); + let block_ast_id = + block_expr_ast_id(last_block_node, &mut index_map, parent) + .expect("not a BlockExpr"); res.arena .alloc((SyntaxNodePtr::new(last_block_node), block_ast_id)); *already_allocated = ContainsItems::Yes; @@ -644,7 +678,7 @@ pub fn from_source(node: &SyntaxNode) -> AstIdMap { } } syntax::WalkEvent::Leave(node) => { - if ast::BlockExpr::can_cast(node.kind()) { + if cfg!(debug_assertions) && ast::BlockExpr::can_cast(node.kind()) { assert_eq!( blocks.pop().map(|it| it.0), Some(node), From afe522a7545a14c741a0aea05663a4cb130e44fd Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Sun, 29 Mar 2026 08:47:40 +0800 Subject: [PATCH 55/56] fix: don't panic unmerge arm on trailing pipe Example --- ```rust fn main() { let y = match 0 { 0 |$0 => { 1i32 } 1 => { 2i32 } }; } ``` **Before this PR** Panic on apply **After this PR** Assist not applicable --- .../src/handlers/unmerge_match_arm.rs | 26 ++++++++++++++++--- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unmerge_match_arm.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unmerge_match_arm.rs index 7b0f2dc65a78..c4c03d3e35f5 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unmerge_match_arm.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unmerge_match_arm.rs @@ -38,11 +38,18 @@ pub(crate) fn unmerge_match_arm(acc: &mut Assists, ctx: &AssistContext<'_>) -> O } let match_arm = ast::MatchArm::cast(or_pat.syntax().parent()?)?; let match_arm_body = match_arm.expr()?; + let pats_after = pipe_token + .siblings_with_tokens(Direction::Next) + .filter_map(|it| ast::Pat::cast(it.into_node()?)) + .collect::>(); // We don't need to check for leading pipe because it is directly under `MatchArm` // without `OrPat`. let new_parent = match_arm.syntax().parent()?; + if pats_after.is_empty() { + return None; + } acc.add( AssistId::refactor_rewrite("unmerge_match_arm"), @@ -51,10 +58,6 @@ pub(crate) fn unmerge_match_arm(acc: &mut Assists, ctx: &AssistContext<'_>) -> O |edit| { let make = SyntaxFactory::with_mappings(); let mut editor = edit.make_editor(&new_parent); - let pats_after = pipe_token - .siblings_with_tokens(Direction::Next) - .filter_map(|it| ast::Pat::cast(it.into_node()?)) - .collect::>(); // It is guaranteed that `pats_after` has at least one element let new_pat = if pats_after.len() == 1 { pats_after[0].clone() @@ -190,6 +193,21 @@ fn main() { ); } + #[test] + fn unmerge_match_arm_trailing_pipe() { + check_assist_not_applicable( + unmerge_match_arm, + r#" +fn main() { + let y = match 0 { + 0 |$0 => { 1i32 } + 1 => { 2i32 } + }; +} +"#, + ); + } + #[test] fn unmerge_match_arm_multiple_pipes() { check_assist( From de6826beff7cbfc52be0f1efecea6449e2df295d Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sun, 29 Mar 2026 11:12:27 +0200 Subject: [PATCH 56/56] fix: Fix block lowering in ast id map --- src/tools/rust-analyzer/crates/span/src/ast_id.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/tools/rust-analyzer/crates/span/src/ast_id.rs b/src/tools/rust-analyzer/crates/span/src/ast_id.rs index bae461e5a8de..f6500a9b4dbe 100644 --- a/src/tools/rust-analyzer/crates/span/src/ast_id.rs +++ b/src/tools/rust-analyzer/crates/span/src/ast_id.rs @@ -678,9 +678,10 @@ pub fn from_source(node: &SyntaxNode) -> AstIdMap { } } syntax::WalkEvent::Leave(node) => { - if cfg!(debug_assertions) && ast::BlockExpr::can_cast(node.kind()) { - assert_eq!( - blocks.pop().map(|it| it.0), + if ast::BlockExpr::can_cast(node.kind()) { + let block = blocks.pop(); + debug_assert_eq!( + block.map(|it| it.0), Some(node), "left a BlockExpr we never entered" );