From 621e96bd6ad0cf35c4dc4d1cfd8f6bc83096946f Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Mon, 9 Jan 2023 20:47:51 +0100 Subject: [PATCH] Encode one level of cfg_attr in attr_id --- crates/hir-def/src/attr.rs | 2 +- crates/hir-def/src/child_by_source.rs | 2 +- crates/hir-def/src/lib.rs | 6 +- crates/hir-def/src/nameres/collector.rs | 4 +- crates/hir-def/src/nameres/diagnostics.rs | 8 +-- crates/hir-expand/src/attrs.rs | 79 ++++++++++++++++------- crates/hir-expand/src/db.rs | 9 ++- crates/hir-expand/src/hygiene.rs | 2 +- crates/hir-expand/src/lib.rs | 24 ++++--- crates/hir/src/lib.rs | 8 ++- crates/intern/Cargo.toml | 7 +- 11 files changed, 99 insertions(+), 52 deletions(-) diff --git a/crates/hir-def/src/attr.rs b/crates/hir-def/src/attr.rs index eb88a74e448..a0113fd048c 100644 --- a/crates/hir-def/src/attr.rs +++ b/crates/hir-def/src/attr.rs @@ -546,7 +546,7 @@ impl AttrSourceMap { } fn source_of_id(&self, id: AttrId) -> InFile<&Either> { - let ast_idx = id.ast_index as usize; + let ast_idx = id.ast_index(); let file_id = match self.mod_def_site_file_id { Some((file_id, def_site_cut)) if def_site_cut <= ast_idx => file_id, _ => self.file_id, diff --git a/crates/hir-def/src/child_by_source.rs b/crates/hir-def/src/child_by_source.rs index bb13165257b..19d2fe956f0 100644 --- a/crates/hir-def/src/child_by_source.rs +++ b/crates/hir-def/src/child_by_source.rs @@ -117,7 +117,7 @@ impl ChildBySource for ItemScope { let adt = ast_id.to_node(db.upcast()); calls.for_each(|(attr_id, call_id, calls)| { if let Some(Either::Left(attr)) = - adt.doc_comments_and_attrs().nth(attr_id.ast_index as usize) + adt.doc_comments_and_attrs().nth(attr_id.ast_index()) { res[keys::DERIVE_MACRO_CALL].insert(attr, (attr_id, call_id, calls.into())); } diff --git a/crates/hir-def/src/lib.rs b/crates/hir-def/src/lib.rs index cc0ea14d015..8eae2e92f42 100644 --- a/crates/hir-def/src/lib.rs +++ b/crates/hir-def/src/lib.rs @@ -941,7 +941,7 @@ pub fn macro_id_to_def_id(db: &dyn db::DefDatabase, id: MacroId) -> MacroDefId { fn derive_macro_as_call_id( db: &dyn db::DefDatabase, item_attr: &AstIdWithPath, - derive_attr: AttrId, + derive_attr_index: AttrId, derive_pos: u32, krate: CrateId, resolver: impl Fn(path::ModPath) -> Option<(MacroId, MacroDefId)>, @@ -954,7 +954,7 @@ fn derive_macro_as_call_id( MacroCallKind::Derive { ast_id: item_attr.ast_id, derive_index: derive_pos, - derive_attr_index: derive_attr.ast_index, + derive_attr_index, }, ); Ok((macro_id, def_id, call_id)) @@ -982,7 +982,7 @@ fn attr_macro_as_call_id( MacroCallKind::Attr { ast_id: item_attr.ast_id, attr_args: Arc::new(arg), - invoc_attr_index: macro_attr.id.ast_index, + invoc_attr_index: macro_attr.id, is_derive, }, ); diff --git a/crates/hir-def/src/nameres/collector.rs b/crates/hir-def/src/nameres/collector.rs index ad31e9aac2b..33a787fd9f9 100644 --- a/crates/hir-def/src/nameres/collector.rs +++ b/crates/hir-def/src/nameres/collector.rs @@ -452,7 +452,7 @@ impl DefCollector<'_> { MacroCallKind::Attr { ast_id: ast_id.ast_id, attr_args: Default::default(), - invoc_attr_index: attr.id.ast_index, + invoc_attr_index: attr.id, is_derive: false, }, attr.path().clone(), @@ -1407,7 +1407,7 @@ impl DefCollector<'_> { directive.module_id, MacroCallKind::Derive { ast_id: ast_id.ast_id, - derive_attr_index: derive_attr.ast_index, + derive_attr_index: *derive_attr, derive_index: *derive_pos as u32, }, ast_id.path.clone(), diff --git a/crates/hir-def/src/nameres/diagnostics.rs b/crates/hir-def/src/nameres/diagnostics.rs index 74b25f4cc98..b024d7c6777 100644 --- a/crates/hir-def/src/nameres/diagnostics.rs +++ b/crates/hir-def/src/nameres/diagnostics.rs @@ -31,9 +31,9 @@ pub enum DefDiagnosticKind { UnimplementedBuiltinMacro { ast: AstId }, - InvalidDeriveTarget { ast: AstId, id: u32 }, + InvalidDeriveTarget { ast: AstId, id: usize }, - MalformedDerive { ast: AstId, id: u32 }, + MalformedDerive { ast: AstId, id: usize }, } #[derive(Debug, PartialEq, Eq)] @@ -119,7 +119,7 @@ impl DefDiagnostic { ) -> Self { Self { in_module: container, - kind: DefDiagnosticKind::InvalidDeriveTarget { ast, id: id.ast_index }, + kind: DefDiagnosticKind::InvalidDeriveTarget { ast, id: id.ast_index() }, } } @@ -130,7 +130,7 @@ impl DefDiagnostic { ) -> Self { Self { in_module: container, - kind: DefDiagnosticKind::MalformedDerive { ast, id: id.ast_index }, + kind: DefDiagnosticKind::MalformedDerive { ast, id: id.ast_index() }, } } } diff --git a/crates/hir-expand/src/attrs.rs b/crates/hir-expand/src/attrs.rs index 6967d153271..c7135732b8a 100644 --- a/crates/hir-expand/src/attrs.rs +++ b/crates/hir-expand/src/attrs.rs @@ -1,3 +1,4 @@ +//! A higher level attributes based on TokenTree, with also some shortcuts. use std::{fmt, ops, sync::Arc}; use base_db::CrateId; @@ -65,14 +66,16 @@ impl RawAttrs { (None, entries @ Some(_)) => Self { entries }, (Some(entries), None) => Self { entries: Some(entries.clone()) }, (Some(a), Some(b)) => { - let last_ast_index = a.last().map_or(0, |it| it.id.ast_index + 1); + let last_ast_index = a.last().map_or(0, |it| it.id.ast_index() + 1) as u32; Self { entries: Some( a.iter() .cloned() .chain(b.iter().map(|it| { let mut it = it.clone(); - it.id.ast_index += last_ast_index; + it.id.id = it.id.ast_index() as u32 + last_ast_index + | (it.id.cfg_attr_index().unwrap_or(0) as u32) + << AttrId::AST_INDEX_BITS; it })) .collect(), @@ -83,6 +86,7 @@ impl RawAttrs { } /// Processes `cfg_attr`s, returning the resulting semantic `Attrs`. + // FIXME: This should return a different type pub fn filter(self, db: &dyn AstDatabase, krate: CrateId) -> RawAttrs { let has_cfg_attrs = self .iter() @@ -106,27 +110,22 @@ impl RawAttrs { _ => return smallvec![attr.clone()], }; - // Input subtree is: `(cfg, $(attr),+)` - // Split it up into a `cfg` subtree and the `attr` subtrees. - // FIXME: There should be a common API for this. - let mut parts = subtree.token_trees.split(|tt| { - matches!(tt, tt::TokenTree::Leaf(tt::Leaf::Punct(Punct { char: ',', .. }))) - }); - let cfg = match parts.next() { + let (cfg, parts) = match parse_cfg_attr_input(subtree) { Some(it) => it, - None => return smallvec![], + None => return smallvec![attr.clone()], }; - let cfg = Subtree { delimiter: subtree.delimiter, token_trees: cfg.to_vec() }; - let cfg = CfgExpr::parse(&cfg); let index = attr.id; - let attrs = parts.filter(|a| !a.is_empty()).filter_map(|attr| { - let tree = Subtree { delimiter: None, token_trees: attr.to_vec() }; - // FIXME hygiene - let hygiene = Hygiene::new_unhygienic(); - Attr::from_tt(db, &tree, &hygiene, index) - }); + let attrs = + parts.enumerate().take(1 << AttrId::CFG_ATTR_BITS).filter_map(|(idx, attr)| { + let tree = Subtree { delimiter: None, token_trees: attr.to_vec() }; + // FIXME hygiene + let hygiene = Hygiene::new_unhygienic(); + Attr::from_tt(db, &tree, &hygiene, index.with_cfg_attr(idx)) + }); let cfg_options = &crate_graph[krate].cfg_options; + let cfg = Subtree { delimiter: subtree.delimiter, token_trees: cfg.to_vec() }; + let cfg = CfgExpr::parse(&cfg); if cfg_options.check(&cfg) == Some(false) { smallvec![] } else { @@ -143,7 +142,32 @@ impl RawAttrs { #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct AttrId { - pub ast_index: u32, + id: u32, +} + +// FIXME: This only handles a single level of cfg_attr nesting +// that is `#[cfg_attr(all(), cfg_attr(all(), cfg(any())))]` breaks again +impl AttrId { + const CFG_ATTR_BITS: usize = 7; + const AST_INDEX_MASK: usize = 0x00FF_FFFF; + const AST_INDEX_BITS: usize = Self::AST_INDEX_MASK.count_ones() as usize; + const CFG_ATTR_SET_BITS: u32 = 1 << 31; + + pub fn ast_index(&self) -> usize { + self.id as usize & Self::AST_INDEX_MASK + } + + pub fn cfg_attr_index(&self) -> Option { + if self.id & Self::CFG_ATTR_SET_BITS == 0 { + None + } else { + Some(self.id as usize >> Self::AST_INDEX_BITS) + } + } + + pub fn with_cfg_attr(self, idx: usize) -> AttrId { + AttrId { id: self.id | (idx as u32) << Self::AST_INDEX_BITS | Self::CFG_ATTR_SET_BITS } + } } #[derive(Debug, Clone, PartialEq, Eq)] @@ -272,10 +296,7 @@ pub fn collect_attrs( Either::Left(attr) => attr.kind().is_outer(), Either::Right(comment) => comment.is_outer(), }); - outer_attrs - .chain(inner_attrs) - .enumerate() - .map(|(id, attr)| (AttrId { ast_index: id as u32 }, attr)) + outer_attrs.chain(inner_attrs).enumerate().map(|(id, attr)| (AttrId { id: id as u32 }, attr)) } fn inner_attributes( @@ -311,3 +332,15 @@ fn inner_attributes( }); Some(attrs) } + +// Input subtree is: `(cfg, $(attr),+)` +// Split it up into a `cfg` subtree and the `attr` subtrees. +pub fn parse_cfg_attr_input( + subtree: &Subtree, +) -> Option<(&[tt::TokenTree], impl Iterator)> { + let mut parts = subtree + .token_trees + .split(|tt| matches!(tt, tt::TokenTree::Leaf(tt::Leaf::Punct(Punct { char: ',', .. })))); + let cfg = parts.next()?; + Some((cfg, parts.filter(|it| !it.is_empty()))) +} diff --git a/crates/hir-expand/src/db.rs b/crates/hir-expand/src/db.rs index b28e60187de..ec5886824f8 100644 --- a/crates/hir-expand/src/db.rs +++ b/crates/hir-expand/src/db.rs @@ -168,7 +168,9 @@ pub fn expand_speculative( // Attributes may have an input token tree, build the subtree and map for this as well // then try finding a token id for our token if it is inside this input subtree. let item = ast::Item::cast(speculative_args.clone())?; - item.doc_comments_and_attrs().nth(invoc_attr_index as usize).and_then(Either::left) + item.doc_comments_and_attrs() + .nth(invoc_attr_index.ast_index()) + .and_then(Either::left) }?; match attr.token_tree() { Some(token_tree) => { @@ -321,6 +323,7 @@ fn macro_arg( } fn censor_for_macro_input(loc: &MacroCallLoc, node: &SyntaxNode) -> FxHashSet { + // FIXME: handle `cfg_attr` (|| { let censor = match loc.kind { MacroCallKind::FnLike { .. } => return None, @@ -328,7 +331,7 @@ fn censor_for_macro_input(loc: &MacroCallLoc, node: &SyntaxNode) -> FxHashSet FxHashSet { + // FIXME: handle `cfg_attr` let tt = ast_id .to_node(db) .doc_comments_and_attrs() - .nth(invoc_attr_index as usize) + .nth(invoc_attr_index.ast_index()) .and_then(Either::left)? .token_tree()?; Some(InFile::new(ast_id.file_id, tt)) @@ -398,8 +400,7 @@ impl MacroDefId { } } -// FIXME: attribute indices do not account for `cfg_attr`, which means that we'll strip the whole -// `cfg_attr` instead of just one of the attributes it expands to +// FIXME: attribute indices do not account for nested `cfg_attr` impl MacroCallKind { /// Returns the file containing the macro invocation. @@ -420,7 +421,7 @@ impl MacroCallKind { // FIXME: handle `cfg_attr` ast_id.with_value(ast_id.to_node(db)).map(|it| { it.doc_comments_and_attrs() - .nth(*derive_attr_index as usize) + .nth(derive_attr_index.ast_index()) .and_then(|it| match it { Either::Left(attr) => Some(attr.syntax().clone()), Either::Right(_) => None, @@ -432,7 +433,7 @@ impl MacroCallKind { // FIXME: handle `cfg_attr` ast_id.with_value(ast_id.to_node(db)).map(|it| { it.doc_comments_and_attrs() - .nth(*invoc_attr_index as usize) + .nth(invoc_attr_index.ast_index()) .and_then(|it| match it { Either::Left(attr) => Some(attr.syntax().clone()), Either::Right(_) => None, @@ -489,19 +490,21 @@ impl MacroCallKind { MacroCallKind::FnLike { ast_id, .. } => ast_id.to_node(db).syntax().text_range(), MacroCallKind::Derive { ast_id, derive_attr_index, .. } => { // FIXME: should be the range of the macro name, not the whole derive + // FIXME: handle `cfg_attr` ast_id .to_node(db) .doc_comments_and_attrs() - .nth(derive_attr_index as usize) + .nth(derive_attr_index.ast_index()) .expect("missing derive") .expect_left("derive is a doc comment?") .syntax() .text_range() } + // FIXME: handle `cfg_attr` MacroCallKind::Attr { ast_id, invoc_attr_index, .. } => ast_id .to_node(db) .doc_comments_and_attrs() - .nth(invoc_attr_index as usize) + .nth(invoc_attr_index.ast_index()) .expect("missing attribute") .expect_left("attribute macro is a doc comment?") .syntax() @@ -593,9 +596,10 @@ impl ExpansionInfo { let token_range = token.value.text_range(); match &loc.kind { MacroCallKind::Attr { attr_args, invoc_attr_index, is_derive, .. } => { + // FIXME: handle `cfg_attr` let attr = item .doc_comments_and_attrs() - .nth(*invoc_attr_index as usize) + .nth(invoc_attr_index.ast_index()) .and_then(Either::left)?; match attr.token_tree() { Some(token_tree) diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index ad44e240423..ec66660f34a 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -785,7 +785,7 @@ fn precise_macro_call_location( let token = (|| { let derive_attr = node .doc_comments_and_attrs() - .nth(*derive_attr_index as usize) + .nth(derive_attr_index.ast_index()) .and_then(Either::left)?; let token_tree = derive_attr.meta()?.token_tree()?; let group_by = token_tree @@ -813,9 +813,11 @@ fn precise_macro_call_location( let node = ast_id.to_node(db.upcast()); let attr = node .doc_comments_and_attrs() - .nth((*invoc_attr_index) as usize) + .nth(invoc_attr_index.ast_index()) .and_then(Either::left) - .unwrap_or_else(|| panic!("cannot find attribute #{invoc_attr_index}")); + .unwrap_or_else(|| { + panic!("cannot find attribute #{}", invoc_attr_index.ast_index()) + }); ( ast_id.with_value(SyntaxNodePtr::from(AstPtr::new(&attr))), diff --git a/crates/intern/Cargo.toml b/crates/intern/Cargo.toml index dd5110255c5..78007fc860f 100644 --- a/crates/intern/Cargo.toml +++ b/crates/intern/Cargo.toml @@ -1,9 +1,14 @@ [package] name = "intern" version = "0.0.0" +description = "TBD" +license = "MIT OR Apache-2.0" edition = "2021" +rust-version = "1.65" + +[lib] +doctest = false -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] # We need to freeze the version of the crate, as the raw-api feature is considered unstable