diff --git a/crates/hir-def/src/item_scope.rs b/crates/hir-def/src/item_scope.rs index 3ed321d189d..2001fb29a9e 100644 --- a/crates/hir-def/src/item_scope.rs +++ b/crates/hir-def/src/item_scope.rs @@ -334,10 +334,6 @@ pub(crate) fn resolutions(&self) -> impl Iterator, PerNs)> ) } - pub(crate) fn collect_legacy_macros(&self) -> FxHashMap> { - self.legacy_macros.clone() - } - /// Marks everything that is not a procedural macro as private to `this_module`. pub(crate) fn censor_non_proc_macros(&mut self, this_module: ModuleId) { self.types diff --git a/crates/hir-def/src/nameres/collector.rs b/crates/hir-def/src/nameres/collector.rs index 97481ea7df7..62fb3c7882c 100644 --- a/crates/hir-def/src/nameres/collector.rs +++ b/crates/hir-def/src/nameres/collector.rs @@ -3,7 +3,7 @@ //! `DefCollector::collect` contains the fixed-point iteration loop which //! resolves imports and expands macros. -use std::{iter, mem}; +use std::{cmp::Ordering, iter, mem}; use base_db::{CrateId, Dependency, Edition, FileId}; use cfg::{CfgExpr, CfgOptions}; @@ -1928,9 +1928,13 @@ fn push_child_module( let modules = &mut def_map.modules; let res = modules.alloc(ModuleData::new(origin, vis)); modules[res].parent = Some(self.module_id); - for (name, mac) in modules[self.module_id].scope.collect_legacy_macros() { - for &mac in &mac { - modules[res].scope.define_legacy_macro(name.clone(), mac); + + if let Some((target, source)) = Self::borrow_modules(modules.as_mut(), res, self.module_id) + { + for (name, macs) in source.scope.legacy_macros() { + for &mac in macs { + target.scope.define_legacy_macro(name.clone(), mac); + } } } modules[self.module_id].children.insert(name.clone(), res); @@ -2226,14 +2230,40 @@ fn collect_macro_call(&mut self, mac: &MacroCall, container: ItemContainerId) { } fn import_all_legacy_macros(&mut self, module_id: LocalModuleId) { - let macros = self.def_collector.def_map[module_id].scope.collect_legacy_macros(); - for (name, macs) in macros { + let Some((source, target)) = Self::borrow_modules(self.def_collector.def_map.modules.as_mut(), module_id, self.module_id) else { + return + }; + + for (name, macs) in source.scope.legacy_macros() { macs.last().map(|&mac| { - self.def_collector.define_legacy_macro(self.module_id, name.clone(), mac) + target.scope.define_legacy_macro(name.clone(), mac); }); } } + /// Mutably borrow two modules at once, retu + fn borrow_modules( + modules: &mut [ModuleData], + a: LocalModuleId, + b: LocalModuleId, + ) -> Option<(&mut ModuleData, &mut ModuleData)> { + let a = a.into_raw().into_u32() as usize; + let b = b.into_raw().into_u32() as usize; + + let (a, b) = match a.cmp(&b) { + Ordering::Equal => return None, + Ordering::Less => { + let (prefix, b) = modules.split_at_mut(b); + (&mut prefix[a], &mut b[0]) + } + Ordering::Greater => { + let (prefix, a) = modules.split_at_mut(a); + (&mut a[0], &mut prefix[b]) + } + }; + Some((a, b)) + } + fn is_cfg_enabled(&self, cfg: &CfgExpr) -> bool { self.def_collector.cfg_options.check(cfg) != Some(false) } diff --git a/crates/ide-assists/src/handlers/generate_delegate_methods.rs b/crates/ide-assists/src/handlers/generate_delegate_methods.rs index 3667fc375b4..b68c766e647 100644 --- a/crates/ide-assists/src/handlers/generate_delegate_methods.rs +++ b/crates/ide-assists/src/handlers/generate_delegate_methods.rs @@ -72,29 +72,27 @@ pub(crate) fn generate_delegate_methods(acc: &mut Assists, ctx: &AssistContext<' let krate = ty.krate(ctx.db()); ty.iterate_assoc_items(ctx.db(), krate, |item| { if let hir::AssocItem::Function(f) = item { + let name = f.name(ctx.db()); if f.self_param(ctx.db()).is_some() && f.is_visible_from(ctx.db(), current_module) - && seen_names.insert(f.name(ctx.db())) + && seen_names.insert(name.clone()) { - methods.push(f) + methods.push((name, f)) } } Option::<()>::None }); } - - for method in methods { + methods.sort_by(|(a, _), (b, _)| a.cmp(b)); + for (name, method) in methods { let adt = ast::Adt::Struct(strukt.clone()); - let name = method.name(ctx.db()).display(ctx.db()).to_string(); + let name = name.display(ctx.db()).to_string(); // if `find_struct_impl` returns None, that means that a function named `name` already exists. - let Some(impl_def) = find_struct_impl(ctx, &adt, &[name]) else { continue; }; + let Some(impl_def) = find_struct_impl(ctx, &adt, std::slice::from_ref(&name)) else { continue; }; acc.add_group( &GroupLabel("Generate delegate methods…".to_owned()), AssistId("generate_delegate_methods", AssistKind::Generate), - format!( - "Generate delegate for `{field_name}.{}()`", - method.name(ctx.db()).display(ctx.db()) - ), + format!("Generate delegate for `{field_name}.{name}()`",), target, |builder| { // Create the function @@ -102,9 +100,8 @@ pub(crate) fn generate_delegate_methods(acc: &mut Assists, ctx: &AssistContext<' Some(source) => source.value, None => return, }; - let method_name = method.name(ctx.db()); let vis = method_source.visibility(); - let name = make::name(&method.name(ctx.db()).display(ctx.db()).to_string()); + let fn_name = make::name(&name); let params = method_source.param_list().unwrap_or_else(|| make::param_list(None, [])); let type_params = method_source.generic_param_list(); @@ -114,7 +111,7 @@ pub(crate) fn generate_delegate_methods(acc: &mut Assists, ctx: &AssistContext<' }; let tail_expr = make::expr_method_call( make::ext::field_from_idents(["self", &field_name]).unwrap(), // This unwrap is ok because we have at least 1 arg in the list - make::name_ref(&method_name.display(ctx.db()).to_string()), + make::name_ref(&name), arg_list, ); let ret_type = method_source.ret_type(); @@ -126,7 +123,7 @@ pub(crate) fn generate_delegate_methods(acc: &mut Assists, ctx: &AssistContext<' let body = make::block_expr([], Some(tail_expr_finished)); let f = make::fn_( vis, - name, + fn_name, type_params, None, params, diff --git a/lib/la-arena/src/lib.rs b/lib/la-arena/src/lib.rs index 5107f294394..f39c3a3e4ca 100644 --- a/lib/la-arena/src/lib.rs +++ b/lib/la-arena/src/lib.rs @@ -451,6 +451,12 @@ fn next_idx(&self) -> Idx { } } +impl AsMut<[T]> for Arena { + fn as_mut(&mut self) -> &mut [T] { + self.data.as_mut() + } +} + impl Default for Arena { fn default() -> Arena { Arena { data: Vec::new() }