From 44d61766b57d67e137cfede6a2fbff415d808b58 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sat, 1 Jan 2022 20:31:04 +0100 Subject: [PATCH] internal: Record unresolved derive invocations in hir --- crates/hir/src/semantics.rs | 21 +++++------ crates/hir/src/semantics/source_to_def.rs | 2 +- crates/hir_def/src/child_by_source.rs | 4 +-- crates/hir_def/src/item_scope.rs | 36 +++++++++++++++---- crates/hir_def/src/keys.rs | 2 +- crates/hir_def/src/nameres/collector.rs | 16 ++++++--- .../src/completions/attribute/derive.rs | 2 +- 7 files changed, 55 insertions(+), 28 deletions(-) diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs index 1070a26c26e..645b10f8534 100644 --- a/crates/hir/src/semantics.rs +++ b/crates/hir/src/semantics.rs @@ -10,7 +10,7 @@ resolver::{self, HasResolver, Resolver, TypeNs}, AsMacroCall, FunctionId, TraitId, VariantId, }; -use hir_expand::{name::AsName, ExpansionInfo, MacroCallId, MacroCallLoc}; +use hir_expand::{name::AsName, ExpansionInfo, MacroCallId}; use hir_ty::{associated_type_shorthand_candidates, Interner}; use itertools::Itertools; use rustc_hash::{FxHashMap, FxHashSet}; @@ -160,7 +160,7 @@ pub fn expand_attr_macro(&self, item: &ast::Item) -> Option { self.imp.expand_attr_macro(item) } - pub fn resolve_derive_macro(&self, derive: &ast::Attr) -> Option> { + pub fn resolve_derive_macro(&self, derive: &ast::Attr) -> Option>> { self.imp.resolve_derive_macro(derive) } @@ -447,14 +447,11 @@ fn expand_attr_macro(&self, item: &ast::Item) -> Option { Some(node) } - fn resolve_derive_macro(&self, attr: &ast::Attr) -> Option> { + fn resolve_derive_macro(&self, attr: &ast::Attr) -> Option>> { let res = self .derive_macro_calls(attr)? - .iter() - .map(|&call| { - let loc: MacroCallLoc = self.db.lookup_intern_macro_call(call); - MacroDef { id: loc.def } - }) + .into_iter() + .map(|call| Some(MacroDef { id: self.db.lookup_intern_macro_call(call?).def })) .collect(); Some(res) } @@ -462,9 +459,9 @@ fn resolve_derive_macro(&self, attr: &ast::Attr) -> Option> { fn expand_derive_macro(&self, attr: &ast::Attr) -> Option> { let res: Vec<_> = self .derive_macro_calls(attr)? - .iter() - .map(|call| call.as_file()) - .flat_map(|file_id| { + .into_iter() + .flat_map(|call| { + let file_id = call?.as_file(); let node = self.db.parse_or_expand(file_id)?; self.cache(node.clone(), file_id); Some(node) @@ -473,7 +470,7 @@ fn expand_derive_macro(&self, attr: &ast::Attr) -> Option> { Some(res) } - fn derive_macro_calls(&self, attr: &ast::Attr) -> Option> { + fn derive_macro_calls(&self, attr: &ast::Attr) -> Option>> { let item = attr.syntax().parent().and_then(ast::Item::cast)?; let file_id = self.find_file(item.syntax()).file_id; let item = InFile::new(file_id, &item); diff --git a/crates/hir/src/semantics/source_to_def.rs b/crates/hir/src/semantics/source_to_def.rs index dd83f1c86e0..495c84e65f4 100644 --- a/crates/hir/src/semantics/source_to_def.rs +++ b/crates/hir/src/semantics/source_to_def.rs @@ -248,7 +248,7 @@ pub(super) fn attr_to_derive_macro_call( &mut self, item: InFile<&ast::Item>, src: InFile, - ) -> Option<&[MacroCallId]> { + ) -> Option<&[Option]> { let map = self.dyn_map(item)?; map[keys::DERIVE_MACRO].get(&src).map(AsRef::as_ref) } diff --git a/crates/hir_def/src/child_by_source.rs b/crates/hir_def/src/child_by_source.rs index 1baf74c512b..5ab236aa3d3 100644 --- a/crates/hir_def/src/child_by_source.rs +++ b/crates/hir_def/src/child_by_source.rs @@ -6,7 +6,6 @@ use either::Either; use hir_expand::HirFileId; -use itertools::Itertools; use syntax::ast::HasAttrs; use crate::{ @@ -123,8 +122,7 @@ fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap, file_id: Hi }); self.derive_macro_invocs().for_each(|(ast_id, calls)| { let item = ast_id.to_node(db.upcast()); - let grouped = calls.iter().copied().into_group_map(); - for (attr_id, calls) in grouped { + for (attr_id, calls) in calls { if let Some(attr) = item.attrs().nth(attr_id.ast_index as usize) { res[keys::DERIVE_MACRO].insert(ast_id.with_value(attr), calls.into()); } diff --git a/crates/hir_def/src/item_scope.rs b/crates/hir_def/src/item_scope.rs index 37599371f61..25369fdb268 100644 --- a/crates/hir_def/src/item_scope.rs +++ b/crates/hir_def/src/item_scope.rs @@ -8,7 +8,7 @@ use once_cell::sync::Lazy; use profile::Count; use rustc_hash::{FxHashMap, FxHashSet}; -use smallvec::SmallVec; +use smallvec::{smallvec, SmallVec}; use stdx::format_to; use syntax::ast; @@ -64,7 +64,10 @@ pub struct ItemScope { // be all resolved to the last one defined if shadowing happens. legacy_macros: FxHashMap, attr_macros: FxHashMap, MacroCallId>, - derive_macros: FxHashMap, SmallVec<[(AttrId, MacroCallId); 1]>>, + /// The derive macro invocations in this scope, keyed by the owner item over the actual derive attributes + /// paired with the derive macro invocations for the specific attribute. + derive_macros: + FxHashMap, SmallVec<[(AttrId, SmallVec<[Option; 1]>); 1]>>, } pub(crate) static BUILTIN_SCOPE: Lazy> = Lazy::new(|| { @@ -199,19 +202,40 @@ pub(crate) fn attr_macro_invocs( self.attr_macros.iter().map(|(k, v)| (*k, *v)) } - pub(crate) fn add_derive_macro_invoc( + pub(crate) fn set_derive_macro_invoc( &mut self, item: AstId, call: MacroCallId, attr_id: AttrId, + idx: usize, ) { - self.derive_macros.entry(item).or_default().push((attr_id, call)); + if let Some(derives) = self.derive_macros.get_mut(&item) { + if let Some((_, invocs)) = derives.iter_mut().find(|&&mut (id, _)| id == attr_id) { + invocs[idx] = Some(call); + } + } + } + + /// We are required to set this up front as derive invocation recording happens out of order + /// due to the fixed pointer iteration loop being able to record some derives later than others + /// independent of their indices. + pub(crate) fn init_derive_attribute( + &mut self, + item: AstId, + attr_id: AttrId, + len: usize, + ) { + self.derive_macros.entry(item).or_default().push((attr_id, smallvec![None; len])); } pub(crate) fn derive_macro_invocs( &self, - ) -> impl Iterator, &[(AttrId, MacroCallId)])> + '_ { - self.derive_macros.iter().map(|(k, v)| (*k, v.as_ref())) + ) -> impl Iterator< + Item = (AstId, impl Iterator])>), + > + '_ { + self.derive_macros + .iter() + .map(|(k, v)| (*k, v.iter().map(|(attr_id, invocs)| (*attr_id, &**invocs)))) } pub(crate) fn unnamed_trait_vis(&self, tr: TraitId) -> Option { diff --git a/crates/hir_def/src/keys.rs b/crates/hir_def/src/keys.rs index 07c4d083d63..6a7dc13ff17 100644 --- a/crates/hir_def/src/keys.rs +++ b/crates/hir_def/src/keys.rs @@ -33,7 +33,7 @@ pub const MACRO: Key = Key::new(); pub const ATTR_MACRO: Key = Key::new(); -pub const DERIVE_MACRO: Key> = Key::new(); +pub const DERIVE_MACRO: Key]>> = Key::new(); /// XXX: AST Nodes and SyntaxNodes have identity equality semantics: nodes are /// equal if they point to exactly the same object. diff --git a/crates/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs index 8c0ba3c0564..ca8afe8cbfd 100644 --- a/crates/hir_def/src/nameres/collector.rs +++ b/crates/hir_def/src/nameres/collector.rs @@ -219,7 +219,7 @@ struct MacroDirective { #[derive(Clone, Debug, Eq, PartialEq)] enum MacroDirectiveKind { FnLike { ast_id: AstIdWithPath, expand_to: ExpandTo }, - Derive { ast_id: AstIdWithPath, derive_attr: AttrId }, + Derive { ast_id: AstIdWithPath, derive_attr: AttrId, derive_pos: usize }, Attr { ast_id: AstIdWithPath, attr: Attr, mod_item: ModItem, tree: TreeId }, } @@ -1064,7 +1064,7 @@ fn resolve_macros(&mut self) -> ReachedFixedPoint { return false; } } - MacroDirectiveKind::Derive { ast_id, derive_attr } => { + MacroDirectiveKind::Derive { ast_id, derive_attr, derive_pos } => { let call_id = derive_macro_as_call_id( ast_id, *derive_attr, @@ -1073,10 +1073,11 @@ fn resolve_macros(&mut self) -> ReachedFixedPoint { &resolver, ); if let Ok(call_id) = call_id { - self.def_map.modules[directive.module_id].scope.add_derive_macro_invoc( + self.def_map.modules[directive.module_id].scope.set_derive_macro_invoc( ast_id.ast_id, call_id, *derive_attr, + *derive_pos, ); resolved.push(( @@ -1146,7 +1147,8 @@ fn resolve_macros(&mut self) -> ReachedFixedPoint { match attr.parse_derive() { Some(derive_macros) => { - for path in derive_macros { + let mut len = 0; + for (idx, path) in derive_macros.enumerate() { let ast_id = AstIdWithPath::new(file_id, ast_id.value, path); self.unresolved_macros.push(MacroDirective { module_id: directive.module_id, @@ -1154,10 +1156,16 @@ fn resolve_macros(&mut self) -> ReachedFixedPoint { kind: MacroDirectiveKind::Derive { ast_id, derive_attr: attr.id, + derive_pos: idx, }, container: directive.container, }); + len = idx; } + + self.def_map.modules[directive.module_id] + .scope + .init_derive_attribute(ast_id, attr.id, len + 1); } None => { let diag = DefDiagnostic::malformed_derive( diff --git a/crates/ide_completion/src/completions/attribute/derive.rs b/crates/ide_completion/src/completions/attribute/derive.rs index 8aaade350f0..5b22408a2cb 100644 --- a/crates/ide_completion/src/completions/attribute/derive.rs +++ b/crates/ide_completion/src/completions/attribute/derive.rs @@ -16,7 +16,7 @@ pub(super) fn complete_derive(acc: &mut Completions, ctx: &CompletionContext, attr: &ast::Attr) { let core = ctx.famous_defs().core(); let existing_derives: FxHashSet<_> = - ctx.sema.resolve_derive_macro(attr).into_iter().flatten().collect(); + ctx.sema.resolve_derive_macro(attr).into_iter().flatten().flatten().collect(); for (name, mac) in get_derives_in_scope(ctx) { if existing_derives.contains(&mac) { -- 2.44.0