]> git.lizzy.rs Git - rust.git/commitdiff
internal: Record unresolved derive invocations in hir
authorLukas Wirth <lukastw97@gmail.com>
Sat, 1 Jan 2022 19:31:04 +0000 (20:31 +0100)
committerLukas Wirth <lukastw97@gmail.com>
Sat, 1 Jan 2022 19:43:25 +0000 (20:43 +0100)
crates/hir/src/semantics.rs
crates/hir/src/semantics/source_to_def.rs
crates/hir_def/src/child_by_source.rs
crates/hir_def/src/item_scope.rs
crates/hir_def/src/keys.rs
crates/hir_def/src/nameres/collector.rs
crates/ide_completion/src/completions/attribute/derive.rs

index 1070a26c26efa632f45ffd3e1510d37bc33036b1..645b10f8534e11fb0c173152aef7bd50c2ada83f 100644 (file)
@@ -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<SyntaxNode> {
         self.imp.expand_attr_macro(item)
     }
 
-    pub fn resolve_derive_macro(&self, derive: &ast::Attr) -> Option<Vec<MacroDef>> {
+    pub fn resolve_derive_macro(&self, derive: &ast::Attr) -> Option<Vec<Option<MacroDef>>> {
         self.imp.resolve_derive_macro(derive)
     }
 
@@ -447,14 +447,11 @@ fn expand_attr_macro(&self, item: &ast::Item) -> Option<SyntaxNode> {
         Some(node)
     }
 
-    fn resolve_derive_macro(&self, attr: &ast::Attr) -> Option<Vec<MacroDef>> {
+    fn resolve_derive_macro(&self, attr: &ast::Attr) -> Option<Vec<Option<MacroDef>>> {
         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<Vec<MacroDef>> {
     fn expand_derive_macro(&self, attr: &ast::Attr) -> Option<Vec<SyntaxNode>> {
         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<Vec<SyntaxNode>> {
         Some(res)
     }
 
-    fn derive_macro_calls(&self, attr: &ast::Attr) -> Option<Vec<MacroCallId>> {
+    fn derive_macro_calls(&self, attr: &ast::Attr) -> Option<Vec<Option<MacroCallId>>> {
         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);
index dd83f1c86e019fc30cf21e06222c2267c55e715d..495c84e65f43e0a73a9a5d48f6beff778084523a 100644 (file)
@@ -248,7 +248,7 @@ pub(super) fn attr_to_derive_macro_call(
         &mut self,
         item: InFile<&ast::Item>,
         src: InFile<ast::Attr>,
-    ) -> Option<&[MacroCallId]> {
+    ) -> Option<&[Option<MacroCallId>]> {
         let map = self.dyn_map(item)?;
         map[keys::DERIVE_MACRO].get(&src).map(AsRef::as_ref)
     }
index 1baf74c512b55a300e142118c6e91df4e0f3d1ee..5ab236aa3d3b6098c949316c36cf76782b60c13e 100644 (file)
@@ -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());
                 }
index 37599371f61fee8f13a6ddae18172740f0061e39..25369fdb268cbd3ed819db9f55a7d8a50d0b046e 100644 (file)
@@ -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<Name, MacroDefId>,
     attr_macros: FxHashMap<AstId<ast::Item>, MacroCallId>,
-    derive_macros: FxHashMap<AstId<ast::Item>, 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<AstId<ast::Item>, SmallVec<[(AttrId, SmallVec<[Option<MacroCallId>; 1]>); 1]>>,
 }
 
 pub(crate) static BUILTIN_SCOPE: Lazy<FxHashMap<Name, PerNs>> = 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<ast::Item>,
         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<ast::Item>,
+        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<Item = (AstId<ast::Item>, &[(AttrId, MacroCallId)])> + '_ {
-        self.derive_macros.iter().map(|(k, v)| (*k, v.as_ref()))
+    ) -> impl Iterator<
+        Item = (AstId<ast::Item>, impl Iterator<Item = (AttrId, &[Option<MacroCallId>])>),
+    > + '_ {
+        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<Visibility> {
index 07c4d083d63266043d9e221822fd4923e36e5a5c..6a7dc13ff17d976502a2d1f41b56886e647f8b0b 100644 (file)
@@ -33,7 +33,7 @@
 
 pub const MACRO: Key<ast::Macro, MacroDefId> = Key::new();
 pub const ATTR_MACRO: Key<ast::Item, MacroCallId> = Key::new();
-pub const DERIVE_MACRO: Key<ast::Attr, Box<[MacroCallId]>> = Key::new();
+pub const DERIVE_MACRO: Key<ast::Attr, Box<[Option<MacroCallId>]>> = Key::new();
 
 /// XXX: AST Nodes and SyntaxNodes have identity equality semantics: nodes are
 /// equal if they point to exactly the same object.
index 8c0ba3c0564896e9b2698c6275353986defe5126..ca8afe8cbfd762633b0bba56cb083fa8add5cd85 100644 (file)
@@ -219,7 +219,7 @@ struct MacroDirective {
 #[derive(Clone, Debug, Eq, PartialEq)]
 enum MacroDirectiveKind {
     FnLike { ast_id: AstIdWithPath<ast::MacroCall>, expand_to: ExpandTo },
-    Derive { ast_id: AstIdWithPath<ast::Item>, derive_attr: AttrId },
+    Derive { ast_id: AstIdWithPath<ast::Item>, derive_attr: AttrId, derive_pos: usize },
     Attr { ast_id: AstIdWithPath<ast::Item>, 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(
index 8aaade350f0b5ca5c131f818a04e124adf48ae07..5b22408a2cb13831ee9687c66f85b1c38fb43ea3 100644 (file)
@@ -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) {