internal: Record unresolved derive invocations in hir

This commit is contained in:
Lukas Wirth 2022-01-01 20:31:04 +01:00
parent 0e5d8883cc
commit 44d61766b5
7 changed files with 55 additions and 28 deletions

View file

@ -10,7 +10,7 @@ use hir_def::{
resolver::{self, HasResolver, Resolver, TypeNs}, resolver::{self, HasResolver, Resolver, TypeNs},
AsMacroCall, FunctionId, TraitId, VariantId, 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 hir_ty::{associated_type_shorthand_candidates, Interner};
use itertools::Itertools; use itertools::Itertools;
use rustc_hash::{FxHashMap, FxHashSet}; use rustc_hash::{FxHashMap, FxHashSet};
@ -160,7 +160,7 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
self.imp.expand_attr_macro(item) 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) self.imp.resolve_derive_macro(derive)
} }
@ -447,14 +447,11 @@ impl<'db> SemanticsImpl<'db> {
Some(node) 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 let res = self
.derive_macro_calls(attr)? .derive_macro_calls(attr)?
.iter() .into_iter()
.map(|&call| { .map(|call| Some(MacroDef { id: self.db.lookup_intern_macro_call(call?).def }))
let loc: MacroCallLoc = self.db.lookup_intern_macro_call(call);
MacroDef { id: loc.def }
})
.collect(); .collect();
Some(res) Some(res)
} }
@ -462,9 +459,9 @@ impl<'db> SemanticsImpl<'db> {
fn expand_derive_macro(&self, attr: &ast::Attr) -> Option<Vec<SyntaxNode>> { fn expand_derive_macro(&self, attr: &ast::Attr) -> Option<Vec<SyntaxNode>> {
let res: Vec<_> = self let res: Vec<_> = self
.derive_macro_calls(attr)? .derive_macro_calls(attr)?
.iter() .into_iter()
.map(|call| call.as_file()) .flat_map(|call| {
.flat_map(|file_id| { let file_id = call?.as_file();
let node = self.db.parse_or_expand(file_id)?; let node = self.db.parse_or_expand(file_id)?;
self.cache(node.clone(), file_id); self.cache(node.clone(), file_id);
Some(node) Some(node)
@ -473,7 +470,7 @@ impl<'db> SemanticsImpl<'db> {
Some(res) 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 item = attr.syntax().parent().and_then(ast::Item::cast)?;
let file_id = self.find_file(item.syntax()).file_id; let file_id = self.find_file(item.syntax()).file_id;
let item = InFile::new(file_id, &item); let item = InFile::new(file_id, &item);

View file

@ -248,7 +248,7 @@ impl SourceToDefCtx<'_, '_> {
&mut self, &mut self,
item: InFile<&ast::Item>, item: InFile<&ast::Item>,
src: InFile<ast::Attr>, src: InFile<ast::Attr>,
) -> Option<&[MacroCallId]> { ) -> Option<&[Option<MacroCallId>]> {
let map = self.dyn_map(item)?; let map = self.dyn_map(item)?;
map[keys::DERIVE_MACRO].get(&src).map(AsRef::as_ref) map[keys::DERIVE_MACRO].get(&src).map(AsRef::as_ref)
} }

View file

@ -6,7 +6,6 @@
use either::Either; use either::Either;
use hir_expand::HirFileId; use hir_expand::HirFileId;
use itertools::Itertools;
use syntax::ast::HasAttrs; use syntax::ast::HasAttrs;
use crate::{ use crate::{
@ -123,8 +122,7 @@ impl ChildBySource for ItemScope {
}); });
self.derive_macro_invocs().for_each(|(ast_id, calls)| { self.derive_macro_invocs().for_each(|(ast_id, calls)| {
let item = ast_id.to_node(db.upcast()); let item = ast_id.to_node(db.upcast());
let grouped = calls.iter().copied().into_group_map(); for (attr_id, calls) in calls {
for (attr_id, calls) in grouped {
if let Some(attr) = item.attrs().nth(attr_id.ast_index as usize) { 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()); res[keys::DERIVE_MACRO].insert(ast_id.with_value(attr), calls.into());
} }

View file

@ -8,7 +8,7 @@ use hir_expand::{name::Name, AstId, MacroCallId, MacroDefKind};
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use profile::Count; use profile::Count;
use rustc_hash::{FxHashMap, FxHashSet}; use rustc_hash::{FxHashMap, FxHashSet};
use smallvec::SmallVec; use smallvec::{smallvec, SmallVec};
use stdx::format_to; use stdx::format_to;
use syntax::ast; use syntax::ast;
@ -64,7 +64,10 @@ pub struct ItemScope {
// be all resolved to the last one defined if shadowing happens. // be all resolved to the last one defined if shadowing happens.
legacy_macros: FxHashMap<Name, MacroDefId>, legacy_macros: FxHashMap<Name, MacroDefId>,
attr_macros: FxHashMap<AstId<ast::Item>, MacroCallId>, 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(|| { pub(crate) static BUILTIN_SCOPE: Lazy<FxHashMap<Name, PerNs>> = Lazy::new(|| {
@ -199,19 +202,40 @@ impl ItemScope {
self.attr_macros.iter().map(|(k, v)| (*k, *v)) 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, &mut self,
item: AstId<ast::Item>, item: AstId<ast::Item>,
call: MacroCallId, call: MacroCallId,
attr_id: AttrId, 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( pub(crate) fn derive_macro_invocs(
&self, &self,
) -> impl Iterator<Item = (AstId<ast::Item>, &[(AttrId, MacroCallId)])> + '_ { ) -> impl Iterator<
self.derive_macros.iter().map(|(k, v)| (*k, v.as_ref())) 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> { pub(crate) fn unnamed_trait_vis(&self, tr: TraitId) -> Option<Visibility> {

View file

@ -33,7 +33,7 @@ pub const CONST_PARAM: Key<ast::ConstParam, ConstParamId> = Key::new();
pub const MACRO: Key<ast::Macro, MacroDefId> = Key::new(); pub const MACRO: Key<ast::Macro, MacroDefId> = Key::new();
pub const ATTR_MACRO: Key<ast::Item, MacroCallId> = 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 /// XXX: AST Nodes and SyntaxNodes have identity equality semantics: nodes are
/// equal if they point to exactly the same object. /// equal if they point to exactly the same object.

View file

@ -219,7 +219,7 @@ struct MacroDirective {
#[derive(Clone, Debug, Eq, PartialEq)] #[derive(Clone, Debug, Eq, PartialEq)]
enum MacroDirectiveKind { enum MacroDirectiveKind {
FnLike { ast_id: AstIdWithPath<ast::MacroCall>, expand_to: ExpandTo }, 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 }, Attr { ast_id: AstIdWithPath<ast::Item>, attr: Attr, mod_item: ModItem, tree: TreeId },
} }
@ -1064,7 +1064,7 @@ impl DefCollector<'_> {
return false; return false;
} }
} }
MacroDirectiveKind::Derive { ast_id, derive_attr } => { MacroDirectiveKind::Derive { ast_id, derive_attr, derive_pos } => {
let call_id = derive_macro_as_call_id( let call_id = derive_macro_as_call_id(
ast_id, ast_id,
*derive_attr, *derive_attr,
@ -1073,10 +1073,11 @@ impl DefCollector<'_> {
&resolver, &resolver,
); );
if let Ok(call_id) = call_id { 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, ast_id.ast_id,
call_id, call_id,
*derive_attr, *derive_attr,
*derive_pos,
); );
resolved.push(( resolved.push((
@ -1146,7 +1147,8 @@ impl DefCollector<'_> {
match attr.parse_derive() { match attr.parse_derive() {
Some(derive_macros) => { 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); let ast_id = AstIdWithPath::new(file_id, ast_id.value, path);
self.unresolved_macros.push(MacroDirective { self.unresolved_macros.push(MacroDirective {
module_id: directive.module_id, module_id: directive.module_id,
@ -1154,10 +1156,16 @@ impl DefCollector<'_> {
kind: MacroDirectiveKind::Derive { kind: MacroDirectiveKind::Derive {
ast_id, ast_id,
derive_attr: attr.id, derive_attr: attr.id,
derive_pos: idx,
}, },
container: directive.container, container: directive.container,
}); });
len = idx;
} }
self.def_map.modules[directive.module_id]
.scope
.init_derive_attribute(ast_id, attr.id, len + 1);
} }
None => { None => {
let diag = DefDiagnostic::malformed_derive( let diag = DefDiagnostic::malformed_derive(

View file

@ -16,7 +16,7 @@ use crate::{
pub(super) fn complete_derive(acc: &mut Completions, ctx: &CompletionContext, attr: &ast::Attr) { pub(super) fn complete_derive(acc: &mut Completions, ctx: &CompletionContext, attr: &ast::Attr) {
let core = ctx.famous_defs().core(); let core = ctx.famous_defs().core();
let existing_derives: FxHashSet<_> = 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) { for (name, mac) in get_derives_in_scope(ctx) {
if existing_derives.contains(&mac) { if existing_derives.contains(&mac) {