Internal: Cleanup proc-macro error handling

This commit is contained in:
Lukas Wirth 2024-07-26 14:36:13 +02:00
parent df15b6f668
commit 7beac14cba
39 changed files with 380 additions and 522 deletions

View file

@ -16,9 +16,7 @@ use span::{Edition, EditionedFileId};
use triomphe::Arc; use triomphe::Arc;
use vfs::{file_set::FileSet, AbsPathBuf, AnchoredPath, FileId, VfsPath}; use vfs::{file_set::FileSet, AbsPathBuf, AnchoredPath, FileId, VfsPath};
// Map from crate id to the name of the crate and path of the proc-macro. If the value is `None`, pub type ProcMacroPaths = FxHashMap<CrateId, Result<(String, AbsPathBuf), String>>;
// then the crate for the proc-macro hasn't been build yet as the build data is missing.
pub type ProcMacroPaths = FxHashMap<CrateId, Result<(Option<String>, AbsPathBuf), String>>;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct SourceRootId(pub u32); pub struct SourceRootId(pub u32);

View file

@ -10,7 +10,7 @@ use std::ops::{Deref, Index};
use base_db::CrateId; use base_db::CrateId;
use cfg::{CfgExpr, CfgOptions}; use cfg::{CfgExpr, CfgOptions};
use hir_expand::{name::Name, InFile}; use hir_expand::{name::Name, ExpandError, InFile};
use la_arena::{Arena, ArenaMap, Idx, RawIdx}; use la_arena::{Arena, ArenaMap, Idx, RawIdx};
use rustc_hash::FxHashMap; use rustc_hash::FxHashMap;
use smallvec::SmallVec; use smallvec::SmallVec;
@ -115,8 +115,7 @@ pub struct SyntheticSyntax;
#[derive(Debug, Eq, PartialEq)] #[derive(Debug, Eq, PartialEq)]
pub enum BodyDiagnostic { pub enum BodyDiagnostic {
InactiveCode { node: InFile<SyntaxNodePtr>, cfg: CfgExpr, opts: CfgOptions }, InactiveCode { node: InFile<SyntaxNodePtr>, cfg: CfgExpr, opts: CfgOptions },
MacroError { node: InFile<AstPtr<ast::MacroCall>>, message: String }, MacroError { node: InFile<AstPtr<ast::MacroCall>>, err: ExpandError },
UnresolvedProcMacro { node: InFile<AstPtr<ast::MacroCall>>, krate: CrateId },
UnresolvedMacroCall { node: InFile<AstPtr<ast::MacroCall>>, path: ModPath }, UnresolvedMacroCall { node: InFile<AstPtr<ast::MacroCall>>, path: ModPath },
UnreachableLabel { node: InFile<AstPtr<ast::Lifetime>>, name: Name }, UnreachableLabel { node: InFile<AstPtr<ast::Lifetime>>, name: Name },
UndeclaredLabel { node: InFile<AstPtr<ast::Lifetime>>, name: Name }, UndeclaredLabel { node: InFile<AstPtr<ast::Lifetime>>, name: Name },

View file

@ -7,7 +7,7 @@ use base_db::CrateId;
use either::Either; use either::Either;
use hir_expand::{ use hir_expand::{
name::{AsName, Name}, name::{AsName, Name},
ExpandError, InFile, InFile,
}; };
use intern::{sym, Interned, Symbol}; use intern::{sym, Interned, Symbol};
use rustc_hash::FxHashMap; use rustc_hash::FxHashMap;
@ -992,21 +992,12 @@ impl ExprCollector<'_> {
} }
}; };
if record_diagnostics { if record_diagnostics {
match &res.err { if let Some(err) = res.err {
Some(ExpandError::UnresolvedProcMacro(krate)) => {
self.source_map.diagnostics.push(BodyDiagnostic::UnresolvedProcMacro {
node: InFile::new(outer_file, syntax_ptr),
krate: *krate,
});
}
Some(err) => {
self.source_map.diagnostics.push(BodyDiagnostic::MacroError { self.source_map.diagnostics.push(BodyDiagnostic::MacroError {
node: InFile::new(outer_file, syntax_ptr), node: InFile::new(outer_file, syntax_ptr),
message: err.to_string(), err,
}); });
} }
None => {}
}
} }
match res.value { match res.value {

View file

@ -657,22 +657,17 @@ impl<'a> AssocItemCollector<'a> {
// crate failed), skip expansion like we would if it was // crate failed), skip expansion like we would if it was
// disabled. This is analogous to the handling in // disabled. This is analogous to the handling in
// `DefCollector::collect_macros`. // `DefCollector::collect_macros`.
if exp.is_dummy() { if let Some(err) = exp.as_expand_error(self.module_id.krate) {
self.diagnostics.push(DefDiagnostic::unresolved_proc_macro( self.diagnostics.push(DefDiagnostic::macro_error(
self.module_id.local_id, self.module_id.local_id,
loc.kind, ast_id,
loc.def.krate, err,
)); ));
continue 'attrs;
}
if exp.is_disabled() {
continue 'attrs; continue 'attrs;
} }
} }
self.macro_calls.push((ast_id, call_id)); self.macro_calls.push((ast_id, call_id));
let res = let res =
self.expander.enter_expand_id::<ast::MacroItems>(self.db, call_id); self.expander.enter_expand_id::<ast::MacroItems>(self.db, call_id);
self.collect_macro_items(res); self.collect_macro_items(res);

View file

@ -179,7 +179,7 @@ impl Expander {
value: match err { value: match err {
// If proc-macro is disabled or unresolved, we want to expand to a missing expression // If proc-macro is disabled or unresolved, we want to expand to a missing expression
// instead of an empty tree which might end up in an empty block. // instead of an empty tree which might end up in an empty block.
Some(ExpandError::UnresolvedProcMacro(_)) => None, Some(ExpandError::MissingProcMacroExpander(_)) => None,
_ => (|| { _ => (|| {
let parse = res.value.0.cast::<T>()?; let parse = res.value.0.cast::<T>()?;

View file

@ -75,9 +75,7 @@ use base_db::{
CrateId, CrateId,
}; };
use hir_expand::{ use hir_expand::{
builtin_attr_macro::BuiltinAttrExpander, builtin::{BuiltinAttrExpander, BuiltinDeriveExpander, BuiltinFnLikeExpander, EagerExpander},
builtin_derive_macro::BuiltinDeriveExpander,
builtin_fn_macro::{BuiltinFnLikeExpander, EagerExpander},
db::ExpandDatabase, db::ExpandDatabase,
eager::expand_eager_macro_input, eager::expand_eager_macro_input,
impl_intern_lookup, impl_intern_lookup,

View file

@ -122,7 +122,7 @@ pub fn identity_when_valid(_attr: TokenStream, item: TokenStream) -> TokenStream
let mut expn_text = String::new(); let mut expn_text = String::new();
if let Some(err) = exp.err { if let Some(err) = exp.err {
format_to!(expn_text, "/* error: {} */", err); format_to!(expn_text, "/* error: {} */", err.render_to_string(&db).0);
} }
let (parse, token_map) = exp.value; let (parse, token_map) = exp.value;
if expect_errors { if expect_errors {

View file

@ -145,8 +145,6 @@ struct DefMapCrateData {
/// Side table for resolving derive helpers. /// Side table for resolving derive helpers.
exported_derives: FxHashMap<MacroDefId, Box<[Name]>>, exported_derives: FxHashMap<MacroDefId, Box<[Name]>>,
fn_proc_macro_mapping: FxHashMap<FunctionId, ProcMacroId>, fn_proc_macro_mapping: FxHashMap<FunctionId, ProcMacroId>,
/// The error that occurred when failing to load the proc-macro dll.
proc_macro_loading_error: Option<Box<str>>,
/// Custom attributes registered with `#![register_attr]`. /// Custom attributes registered with `#![register_attr]`.
registered_attrs: Vec<Symbol>, registered_attrs: Vec<Symbol>,
@ -169,7 +167,6 @@ impl DefMapCrateData {
extern_prelude: FxIndexMap::default(), extern_prelude: FxIndexMap::default(),
exported_derives: FxHashMap::default(), exported_derives: FxHashMap::default(),
fn_proc_macro_mapping: FxHashMap::default(), fn_proc_macro_mapping: FxHashMap::default(),
proc_macro_loading_error: None,
registered_attrs: Vec::new(), registered_attrs: Vec::new(),
registered_tools: PREDEFINED_TOOLS.iter().map(|it| Symbol::intern(it)).collect(), registered_tools: PREDEFINED_TOOLS.iter().map(|it| Symbol::intern(it)).collect(),
unstable_features: FxHashSet::default(), unstable_features: FxHashSet::default(),
@ -189,7 +186,6 @@ impl DefMapCrateData {
registered_attrs, registered_attrs,
registered_tools, registered_tools,
unstable_features, unstable_features,
proc_macro_loading_error: _,
rustc_coherence_is_core: _, rustc_coherence_is_core: _,
no_core: _, no_core: _,
no_std: _, no_std: _,
@ -474,10 +470,6 @@ impl DefMap {
self.data.fn_proc_macro_mapping.get(&id).copied() self.data.fn_proc_macro_mapping.get(&id).copied()
} }
pub fn proc_macro_loading_error(&self) -> Option<&str> {
self.data.proc_macro_loading_error.as_deref()
}
pub fn krate(&self) -> CrateId { pub fn krate(&self) -> CrateId {
self.krate self.krate
} }

View file

@ -10,9 +10,7 @@ use cfg::{CfgExpr, CfgOptions};
use either::Either; use either::Either;
use hir_expand::{ use hir_expand::{
attrs::{Attr, AttrId}, attrs::{Attr, AttrId},
builtin_attr_macro::find_builtin_attr, builtin::{find_builtin_attr, find_builtin_derive, find_builtin_macro},
builtin_derive_macro::find_builtin_derive,
builtin_fn_macro::find_builtin_macro,
name::{AsName, Name}, name::{AsName, Name},
proc_macro::CustomProcMacroExpander, proc_macro::CustomProcMacroExpander,
ExpandTo, HirFileId, InFile, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind, ExpandTo, HirFileId, InFile, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind,
@ -76,34 +74,11 @@ pub(super) fn collect_defs(db: &dyn DefDatabase, def_map: DefMap, tree_id: TreeI
} }
let proc_macros = if krate.is_proc_macro { let proc_macros = if krate.is_proc_macro {
match db.proc_macros().get(&def_map.krate) { db.proc_macros()
Some(Ok(proc_macros)) => Ok({ .for_crate(def_map.krate, db.syntax_context(tree_id.file_id()))
let ctx = db.syntax_context(tree_id.file_id()); .unwrap_or_default()
proc_macros
.iter()
.enumerate()
.map(|(idx, it)| {
let name = Name::new_symbol(it.name.clone(), ctx);
(
name,
if !db.expand_proc_attr_macros() {
CustomProcMacroExpander::dummy()
} else if it.disabled {
CustomProcMacroExpander::disabled()
} else { } else {
CustomProcMacroExpander::new( Default::default()
hir_expand::proc_macro::ProcMacroId::new(idx as u32),
)
},
)
})
.collect()
}),
Some(Err(e)) => Err(e.clone().into_boxed_str()),
None => Err("No proc-macros present for crate".to_owned().into_boxed_str()),
}
} else {
Ok(vec![])
}; };
let mut collector = DefCollector { let mut collector = DefCollector {
@ -252,10 +227,10 @@ struct DefCollector<'a> {
mod_dirs: FxHashMap<LocalModuleId, ModDir>, mod_dirs: FxHashMap<LocalModuleId, ModDir>,
cfg_options: &'a CfgOptions, cfg_options: &'a CfgOptions,
/// List of procedural macros defined by this crate. This is read from the dynamic library /// List of procedural macros defined by this crate. This is read from the dynamic library
/// built by the build system, and is the list of proc. macros we can actually expand. It is /// built by the build system, and is the list of proc-macros we can actually expand. It is
/// empty when proc. macro support is disabled (in which case we still do name resolution for /// empty when proc-macro support is disabled (in which case we still do name resolution for
/// them). /// them). The bool signals whether the proc-macro has been explicitly disabled for name-resolution.
proc_macros: Result<Vec<(Name, CustomProcMacroExpander)>, Box<str>>, proc_macros: Box<[(Name, CustomProcMacroExpander, bool)]>,
is_proc_macro: bool, is_proc_macro: bool,
from_glob_import: PerNsGlobImports, from_glob_import: PerNsGlobImports,
/// If we fail to resolve an attribute on a `ModItem`, we fall back to ignoring the attribute. /// If we fail to resolve an attribute on a `ModItem`, we fall back to ignoring the attribute.
@ -278,10 +253,6 @@ impl DefCollector<'_> {
let attrs = item_tree.top_level_attrs(self.db, self.def_map.krate); let attrs = item_tree.top_level_attrs(self.db, self.def_map.krate);
let crate_data = Arc::get_mut(&mut self.def_map.data).unwrap(); let crate_data = Arc::get_mut(&mut self.def_map.data).unwrap();
if let Err(e) = &self.proc_macros {
crate_data.proc_macro_loading_error = Some(e.clone());
}
let mut process = true; let mut process = true;
// Process other crate-level attributes. // Process other crate-level attributes.
@ -608,10 +579,16 @@ impl DefCollector<'_> {
fn_id: FunctionId, fn_id: FunctionId,
) { ) {
let kind = def.kind.to_basedb_kind(); let kind = def.kind.to_basedb_kind();
let (expander, kind) = let (expander, kind) = match self.proc_macros.iter().find(|(n, _, _)| n == &def.name) {
match self.proc_macros.as_ref().map(|it| it.iter().find(|(n, _)| n == &def.name)) { Some(_)
Ok(Some(&(_, expander))) => (expander, kind), if kind == hir_expand::proc_macro::ProcMacroKind::Attr
_ => (CustomProcMacroExpander::dummy(), kind), && !self.db.expand_proc_attr_macros() =>
{
(CustomProcMacroExpander::disabled_proc_attr(), kind)
}
Some(&(_, _, true)) => (CustomProcMacroExpander::disabled(), kind),
Some(&(_, expander, false)) => (expander, kind),
None => (CustomProcMacroExpander::missing_expander(), kind),
}; };
let proc_macro_id = ProcMacroLoc { let proc_macro_id = ProcMacroLoc {
@ -1338,25 +1315,22 @@ impl DefCollector<'_> {
return recollect_without(self); return recollect_without(self);
} }
let call_id = call_id();
if let MacroDefKind::ProcMacro(_, exp, _) = def.kind { if let MacroDefKind::ProcMacro(_, exp, _) = def.kind {
// If there's no expander for the proc macro (e.g. // If there's no expander for the proc macro (e.g.
// because proc macros are disabled, or building the // because proc macros are disabled, or building the
// proc macro crate failed), report this and skip // proc macro crate failed), report this and skip
// expansion like we would if it was disabled // expansion like we would if it was disabled
if exp.is_dummy() { if let Some(err) = exp.as_expand_error(def.krate) {
self.def_map.diagnostics.push(DefDiagnostic::unresolved_proc_macro( self.def_map.diagnostics.push(DefDiagnostic::macro_error(
directive.module_id, directive.module_id,
self.db.lookup_intern_macro_call(call_id).kind, ast_id,
def.krate, err,
)); ));
return recollect_without(self); return recollect_without(self);
} }
if exp.is_disabled() {
return recollect_without(self);
}
} }
let call_id = call_id();
self.def_map.modules[directive.module_id] self.def_map.modules[directive.module_id]
.scope .scope
.add_attr_macro_invoc(ast_id, call_id); .add_attr_macro_invoc(ast_id, call_id);
@ -1395,7 +1369,6 @@ impl DefCollector<'_> {
} }
let file_id = macro_call_id.as_file(); let file_id = macro_call_id.as_file();
// Then, fetch and process the item tree. This will reuse the expansion result from above.
let item_tree = self.db.file_item_tree(file_id); let item_tree = self.db.file_item_tree(file_id);
let mod_dir = if macro_call_id.as_macro_file().is_include_macro(self.db.upcast()) { let mod_dir = if macro_call_id.as_macro_file().is_include_macro(self.db.upcast()) {
@ -2433,7 +2406,7 @@ mod tests {
unresolved_macros: Vec::new(), unresolved_macros: Vec::new(),
mod_dirs: FxHashMap::default(), mod_dirs: FxHashMap::default(),
cfg_options: &CfgOptions::default(), cfg_options: &CfgOptions::default(),
proc_macros: Ok(vec![]), proc_macros: Default::default(),
from_glob_import: Default::default(), from_glob_import: Default::default(),
skip_attrs: Default::default(), skip_attrs: Default::default(),
is_proc_macro: false, is_proc_macro: false,

View file

@ -2,9 +2,8 @@
use std::ops::Not; use std::ops::Not;
use base_db::CrateId;
use cfg::{CfgExpr, CfgOptions}; use cfg::{CfgExpr, CfgOptions};
use hir_expand::{attrs::AttrId, MacroCallKind}; use hir_expand::{attrs::AttrId, ExpandError, MacroCallKind};
use la_arena::Idx; use la_arena::Idx;
use syntax::ast; use syntax::ast;
@ -17,48 +16,16 @@ use crate::{
#[derive(Debug, PartialEq, Eq)] #[derive(Debug, PartialEq, Eq)]
pub enum DefDiagnosticKind { pub enum DefDiagnosticKind {
UnresolvedModule { UnresolvedModule { ast: AstId<ast::Module>, candidates: Box<[String]> },
ast: AstId<ast::Module>, UnresolvedExternCrate { ast: AstId<ast::ExternCrate> },
candidates: Box<[String]>, UnresolvedImport { id: ItemTreeId<item_tree::Use>, index: Idx<ast::UseTree> },
}, UnconfiguredCode { tree: TreeId, item: AttrOwner, cfg: CfgExpr, opts: CfgOptions },
UnresolvedExternCrate { UnresolvedMacroCall { ast: MacroCallKind, path: ModPath },
ast: AstId<ast::ExternCrate>, UnimplementedBuiltinMacro { ast: AstId<ast::Macro> },
}, InvalidDeriveTarget { ast: AstId<ast::Item>, id: usize },
UnresolvedImport { MalformedDerive { ast: AstId<ast::Adt>, id: usize },
id: ItemTreeId<item_tree::Use>, MacroDefError { ast: AstId<ast::Macro>, message: String },
index: Idx<ast::UseTree>, MacroError { ast: AstId<ast::Item>, err: ExpandError },
},
UnconfiguredCode {
tree: TreeId,
item: AttrOwner,
cfg: CfgExpr,
opts: CfgOptions,
},
/// A proc-macro that is lacking an expander, this might be due to build scripts not yet having
/// run or proc-macro expansion being disabled.
UnresolvedProcMacro {
ast: MacroCallKind,
krate: CrateId,
},
UnresolvedMacroCall {
ast: MacroCallKind,
path: ModPath,
},
UnimplementedBuiltinMacro {
ast: AstId<ast::Macro>,
},
InvalidDeriveTarget {
ast: AstId<ast::Item>,
id: usize,
},
MalformedDerive {
ast: AstId<ast::Adt>,
id: usize,
},
MacroDefError {
ast: AstId<ast::Macro>,
message: String,
},
} }
#[derive(Clone, Debug, PartialEq, Eq)] #[derive(Clone, Debug, PartialEq, Eq)]
@ -115,6 +82,10 @@ impl DefDiagnostic {
Self { in_module: container, kind: DefDiagnosticKind::UnresolvedImport { id, index } } Self { in_module: container, kind: DefDiagnosticKind::UnresolvedImport { id, index } }
} }
pub fn macro_error(container: LocalModuleId, ast: AstId<ast::Item>, err: ExpandError) -> Self {
Self { in_module: container, kind: DefDiagnosticKind::MacroError { ast, err } }
}
pub fn unconfigured_code( pub fn unconfigured_code(
container: LocalModuleId, container: LocalModuleId,
tree: TreeId, tree: TreeId,
@ -128,14 +99,6 @@ impl DefDiagnostic {
} }
} }
pub fn unresolved_proc_macro(
container: LocalModuleId,
ast: MacroCallKind,
krate: CrateId,
) -> Self {
Self { in_module: container, kind: DefDiagnosticKind::UnresolvedProcMacro { ast, krate } }
}
// FIXME: Whats the difference between this and unresolved_proc_macro // FIXME: Whats the difference between this and unresolved_proc_macro
pub(crate) fn unresolved_macro_call( pub(crate) fn unresolved_macro_call(
container: LocalModuleId, container: LocalModuleId,

View file

@ -0,0 +1,14 @@
#[macro_use]
mod quote;
mod attr_macro;
mod derive_macro;
mod fn_macro;
pub use self::{
attr_macro::{find_builtin_attr, pseudo_derive_attr_expansion, BuiltinAttrExpander},
derive_macro::{find_builtin_derive, BuiltinDeriveExpander},
fn_macro::{
find_builtin_macro, include_input_to_file_id, BuiltinFnLikeExpander, EagerExpander,
},
};

View file

@ -9,18 +9,18 @@ use stdx::never;
use tracing::debug; use tracing::debug;
use crate::{ use crate::{
builtin::quote::{dollar_crate, quote},
db::ExpandDatabase,
hygiene::span_with_def_site_ctxt, hygiene::span_with_def_site_ctxt,
name,
name::{AsName, Name}, name::{AsName, Name},
quote::dollar_crate,
span_map::ExpansionSpanMap, span_map::ExpansionSpanMap,
tt, tt, ExpandError, ExpandResult,
}; };
use syntax::ast::{ use syntax::ast::{
self, AstNode, FieldList, HasAttrs, HasGenericParams, HasModuleItem, HasName, HasTypeBounds, self, AstNode, FieldList, HasAttrs, HasGenericParams, HasModuleItem, HasName, HasTypeBounds,
}; };
use crate::{db::ExpandDatabase, name, quote, ExpandError, ExpandResult};
macro_rules! register_builtin { macro_rules! register_builtin {
( $($trait:ident => $expand:ident),* ) => { ( $($trait:ident => $expand:ident),* ) => {
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]

View file

@ -13,10 +13,10 @@ use syntax::{
}; };
use crate::{ use crate::{
builtin::quote::{dollar_crate, quote},
db::ExpandDatabase, db::ExpandDatabase,
hygiene::{span_with_call_site_ctxt, span_with_def_site_ctxt}, hygiene::{span_with_call_site_ctxt, span_with_def_site_ctxt},
name, quote, name,
quote::dollar_crate,
tt::{self, DelimSpan}, tt::{self, DelimSpan},
ExpandError, ExpandResult, HirFileIdExt, Lookup as _, MacroCallId, ExpandError, ExpandResult, HirFileIdExt, Lookup as _, MacroCallId,
}; };
@ -145,7 +145,7 @@ register_builtin! {
} }
fn mk_pound(span: Span) -> tt::Subtree { fn mk_pound(span: Span) -> tt::Subtree {
crate::quote::IntoTt::to_subtree( crate::builtin::quote::IntoTt::to_subtree(
vec![crate::tt::Leaf::Punct(crate::tt::Punct { vec![crate::tt::Leaf::Punct(crate::tt::Punct {
char: '#', char: '#',
spacing: crate::tt::Spacing::Alone, spacing: crate::tt::Spacing::Alone,

View file

@ -17,22 +17,21 @@ pub(crate) fn dollar_crate(span: Span) -> tt::Ident<Span> {
// 2. #()* pattern repetition not supported now // 2. #()* pattern repetition not supported now
// * But we can do it manually, see `test_quote_derive_copy_hack` // * But we can do it manually, see `test_quote_derive_copy_hack`
#[doc(hidden)] #[doc(hidden)]
#[macro_export] macro_rules! quote_impl__ {
macro_rules! __quote {
($span:ident) => { ($span:ident) => {
Vec::<$crate::tt::TokenTree>::new() Vec::<$crate::tt::TokenTree>::new()
}; };
( @SUBTREE($span:ident) $delim:ident $($tt:tt)* ) => { ( @SUBTREE($span:ident) $delim:ident $($tt:tt)* ) => {
{ {
let children = $crate::__quote!($span $($tt)*); let children = $crate::builtin::quote::__quote!($span $($tt)*);
$crate::tt::Subtree { $crate::tt::Subtree {
delimiter: crate::tt::Delimiter { delimiter: crate::tt::Delimiter {
kind: crate::tt::DelimiterKind::$delim, kind: crate::tt::DelimiterKind::$delim,
open: $span, open: $span,
close: $span, close: $span,
}, },
token_trees: $crate::quote::IntoTt::to_tokens(children).into_boxed_slice(), token_trees: $crate::builtin::quote::IntoTt::to_tokens(children).into_boxed_slice(),
} }
} }
}; };
@ -69,9 +68,9 @@ macro_rules! __quote {
// hash variable // hash variable
($span:ident # $first:ident $($tail:tt)* ) => { ($span:ident # $first:ident $($tail:tt)* ) => {
{ {
let token = $crate::quote::ToTokenTree::to_token($first, $span); let token = $crate::builtin::quote::ToTokenTree::to_token($first, $span);
let mut tokens = vec![token.into()]; let mut tokens = vec![token.into()];
let mut tail_tokens = $crate::quote::IntoTt::to_tokens($crate::__quote!($span $($tail)*)); let mut tail_tokens = $crate::builtin::quote::IntoTt::to_tokens($crate::builtin::quote::__quote!($span $($tail)*));
tokens.append(&mut tail_tokens); tokens.append(&mut tail_tokens);
tokens tokens
} }
@ -79,22 +78,22 @@ macro_rules! __quote {
($span:ident ## $first:ident $($tail:tt)* ) => { ($span:ident ## $first:ident $($tail:tt)* ) => {
{ {
let mut tokens = $first.into_iter().map(|it| $crate::quote::ToTokenTree::to_token(it, $span)).collect::<Vec<crate::tt::TokenTree>>(); let mut tokens = $first.into_iter().map(|it| $crate::builtin::quote::ToTokenTree::to_token(it, $span)).collect::<Vec<crate::tt::TokenTree>>();
let mut tail_tokens = $crate::quote::IntoTt::to_tokens($crate::__quote!($span $($tail)*)); let mut tail_tokens = $crate::builtin::quote::IntoTt::to_tokens($crate::builtin::quote::__quote!($span $($tail)*));
tokens.append(&mut tail_tokens); tokens.append(&mut tail_tokens);
tokens tokens
} }
}; };
// Brace // Brace
($span:ident { $($tt:tt)* } ) => { $crate::__quote!(@SUBTREE($span) Brace $($tt)*) }; ($span:ident { $($tt:tt)* } ) => { $crate::builtin::quote::__quote!(@SUBTREE($span) Brace $($tt)*) };
// Bracket // Bracket
($span:ident [ $($tt:tt)* ] ) => { $crate::__quote!(@SUBTREE($span) Bracket $($tt)*) }; ($span:ident [ $($tt:tt)* ] ) => { $crate::builtin::quote::__quote!(@SUBTREE($span) Bracket $($tt)*) };
// Parenthesis // Parenthesis
($span:ident ( $($tt:tt)* ) ) => { $crate::__quote!(@SUBTREE($span) Parenthesis $($tt)*) }; ($span:ident ( $($tt:tt)* ) ) => { $crate::builtin::quote::__quote!(@SUBTREE($span) Parenthesis $($tt)*) };
// Literal // Literal
($span:ident $tt:literal ) => { vec![$crate::quote::ToTokenTree::to_token($tt, $span).into()] }; ($span:ident $tt:literal ) => { vec![$crate::builtin::quote::ToTokenTree::to_token($tt, $span).into()] };
// Ident // Ident
($span:ident $tt:ident ) => { ($span:ident $tt:ident ) => {
vec![ { vec![ {
@ -108,36 +107,37 @@ macro_rules! __quote {
// Puncts // Puncts
// FIXME: Not all puncts are handled // FIXME: Not all puncts are handled
($span:ident -> ) => {$crate::__quote!(@PUNCT($span) '-', '>')}; ($span:ident -> ) => {$crate::builtin::quote::__quote!(@PUNCT($span) '-', '>')};
($span:ident & ) => {$crate::__quote!(@PUNCT($span) '&')}; ($span:ident & ) => {$crate::builtin::quote::__quote!(@PUNCT($span) '&')};
($span:ident , ) => {$crate::__quote!(@PUNCT($span) ',')}; ($span:ident , ) => {$crate::builtin::quote::__quote!(@PUNCT($span) ',')};
($span:ident : ) => {$crate::__quote!(@PUNCT($span) ':')}; ($span:ident : ) => {$crate::builtin::quote::__quote!(@PUNCT($span) ':')};
($span:ident ; ) => {$crate::__quote!(@PUNCT($span) ';')}; ($span:ident ; ) => {$crate::builtin::quote::__quote!(@PUNCT($span) ';')};
($span:ident :: ) => {$crate::__quote!(@PUNCT($span) ':', ':')}; ($span:ident :: ) => {$crate::builtin::quote::__quote!(@PUNCT($span) ':', ':')};
($span:ident . ) => {$crate::__quote!(@PUNCT($span) '.')}; ($span:ident . ) => {$crate::builtin::quote::__quote!(@PUNCT($span) '.')};
($span:ident < ) => {$crate::__quote!(@PUNCT($span) '<')}; ($span:ident < ) => {$crate::builtin::quote::__quote!(@PUNCT($span) '<')};
($span:ident > ) => {$crate::__quote!(@PUNCT($span) '>')}; ($span:ident > ) => {$crate::builtin::quote::__quote!(@PUNCT($span) '>')};
($span:ident ! ) => {$crate::__quote!(@PUNCT($span) '!')}; ($span:ident ! ) => {$crate::builtin::quote::__quote!(@PUNCT($span) '!')};
($span:ident $first:tt $($tail:tt)+ ) => { ($span:ident $first:tt $($tail:tt)+ ) => {
{ {
let mut tokens = $crate::quote::IntoTt::to_tokens($crate::__quote!($span $first )); let mut tokens = $crate::builtin::quote::IntoTt::to_tokens($crate::builtin::quote::__quote!($span $first ));
let mut tail_tokens = $crate::quote::IntoTt::to_tokens($crate::__quote!($span $($tail)*)); let mut tail_tokens = $crate::builtin::quote::IntoTt::to_tokens($crate::builtin::quote::__quote!($span $($tail)*));
tokens.append(&mut tail_tokens); tokens.append(&mut tail_tokens);
tokens tokens
} }
}; };
} }
pub(super) use quote_impl__ as __quote;
/// FIXME: /// FIXME:
/// It probably should implement in proc-macro /// It probably should implement in proc-macro
#[macro_export] macro_rules! quote_impl {
macro_rules! quote {
($span:ident=> $($tt:tt)* ) => { ($span:ident=> $($tt:tt)* ) => {
$crate::quote::IntoTt::to_subtree($crate::__quote!($span $($tt)*), $span) $crate::builtin::quote::IntoTt::to_subtree($crate::builtin::quote::__quote!($span $($tt)*), $span)
} }
} }
pub(super) use quote_impl as quote;
pub(crate) trait IntoTt { pub(crate) trait IntoTt {
fn to_subtree(self, span: Span) -> crate::tt::Subtree; fn to_subtree(self, span: Span) -> crate::tt::Subtree;
@ -232,6 +232,8 @@ mod tests {
use span::{SpanAnchor, SyntaxContextId, ROOT_ERASED_FILE_AST_ID}; use span::{SpanAnchor, SyntaxContextId, ROOT_ERASED_FILE_AST_ID};
use syntax::{TextRange, TextSize}; use syntax::{TextRange, TextSize};
use super::quote;
const DUMMY: tt::Span = tt::Span { const DUMMY: tt::Span = tt::Span {
range: TextRange::empty(TextSize::new(0)), range: TextRange::empty(TextSize::new(0)),
anchor: SpanAnchor { anchor: SpanAnchor {

View file

@ -25,8 +25,7 @@ impl ChangeWithProcMacros {
pub fn apply(self, db: &mut (impl ExpandDatabase + SourceDatabaseExt)) { pub fn apply(self, db: &mut (impl ExpandDatabase + SourceDatabaseExt)) {
self.source_change.apply(db); self.source_change.apply(db);
if let Some(mut proc_macros) = self.proc_macros { if let Some(proc_macros) = self.proc_macros {
proc_macros.shrink_to_fit();
db.set_proc_macros_with_durability(Arc::new(proc_macros), Durability::HIGH); db.set_proc_macros_with_durability(Arc::new(proc_macros), Durability::HIGH);
} }
if let Some(target_data_layouts) = self.target_data_layouts { if let Some(target_data_layouts) = self.target_data_layouts {

View file

@ -11,8 +11,7 @@ use triomphe::Arc;
use crate::{ use crate::{
attrs::{collect_attrs, AttrId}, attrs::{collect_attrs, AttrId},
builtin_attr_macro::pseudo_derive_attr_expansion, builtin::pseudo_derive_attr_expansion,
builtin_fn_macro::EagerExpander,
cfg_process, cfg_process,
declarative::DeclarativeMacroExpander, declarative::DeclarativeMacroExpander,
fixup::{self, SyntaxFixupUndoInfo}, fixup::{self, SyntaxFixupUndoInfo},
@ -20,9 +19,9 @@ use crate::{
proc_macro::ProcMacros, proc_macro::ProcMacros,
span_map::{RealSpanMap, SpanMap, SpanMapRef}, span_map::{RealSpanMap, SpanMap, SpanMapRef},
tt, AstId, BuiltinAttrExpander, BuiltinDeriveExpander, BuiltinFnLikeExpander, tt, AstId, BuiltinAttrExpander, BuiltinDeriveExpander, BuiltinFnLikeExpander,
CustomProcMacroExpander, EagerCallInfo, ExpandError, ExpandResult, ExpandTo, ExpansionSpanMap, CustomProcMacroExpander, EagerCallInfo, EagerExpander, ExpandError, ExpandResult, ExpandTo,
HirFileId, HirFileIdRepr, Lookup, MacroCallId, MacroCallKind, MacroCallLoc, MacroDefId, ExpansionSpanMap, HirFileId, HirFileIdRepr, Lookup, MacroCallId, MacroCallKind, MacroCallLoc,
MacroDefKind, MacroFileId, MacroDefId, MacroDefKind, MacroFileId,
}; };
/// This is just to ensure the types of smart_macro_arg and macro_arg are the same /// This is just to ensure the types of smart_macro_arg and macro_arg are the same
type MacroArgResult = (Arc<tt::Subtree>, SyntaxFixupUndoInfo, Span); type MacroArgResult = (Arc<tt::Subtree>, SyntaxFixupUndoInfo, Span);

View file

@ -6,9 +6,7 @@
#![cfg_attr(feature = "in-rust-tree", feature(rustc_private))] #![cfg_attr(feature = "in-rust-tree", feature(rustc_private))]
pub mod attrs; pub mod attrs;
pub mod builtin_attr_macro; pub mod builtin;
pub mod builtin_derive_macro;
pub mod builtin_fn_macro;
pub mod change; pub mod change;
pub mod db; pub mod db;
pub mod declarative; pub mod declarative;
@ -19,7 +17,6 @@ pub mod inert_attr_macro;
pub mod mod_path; pub mod mod_path;
pub mod name; pub mod name;
pub mod proc_macro; pub mod proc_macro;
pub mod quote;
pub mod span_map; pub mod span_map;
mod cfg_process; mod cfg_process;
@ -29,7 +26,7 @@ use attrs::collect_attrs;
use rustc_hash::FxHashMap; use rustc_hash::FxHashMap;
use triomphe::Arc; use triomphe::Arc;
use std::{fmt, hash::Hash}; use std::hash::Hash;
use base_db::{salsa::InternValueTrivial, CrateId}; use base_db::{salsa::InternValueTrivial, CrateId};
use either::Either; use either::Either;
@ -44,9 +41,10 @@ use syntax::{
use crate::{ use crate::{
attrs::AttrId, attrs::AttrId,
builtin_attr_macro::BuiltinAttrExpander, builtin::{
builtin_derive_macro::BuiltinDeriveExpander, include_input_to_file_id, BuiltinAttrExpander, BuiltinDeriveExpander,
builtin_fn_macro::{BuiltinFnLikeExpander, EagerExpander}, BuiltinFnLikeExpander, EagerExpander,
},
db::ExpandDatabase, db::ExpandDatabase,
mod_path::ModPath, mod_path::ModPath,
proc_macro::{CustomProcMacroExpander, ProcMacroKind}, proc_macro::{CustomProcMacroExpander, ProcMacroKind},
@ -127,7 +125,8 @@ pub type ExpandResult<T> = ValueResult<T, ExpandError>;
#[derive(Debug, PartialEq, Eq, Clone, Hash)] #[derive(Debug, PartialEq, Eq, Clone, Hash)]
pub enum ExpandError { pub enum ExpandError {
UnresolvedProcMacro(CrateId), ProcMacroAttrExpansionDisabled,
MissingProcMacroExpander(CrateId),
/// The macro expansion is disabled. /// The macro expansion is disabled.
MacroDisabled, MacroDisabled,
MacroDefinition, MacroDefinition,
@ -141,6 +140,26 @@ impl ExpandError {
pub fn other(msg: impl Into<Box<str>>) -> Self { pub fn other(msg: impl Into<Box<str>>) -> Self {
ExpandError::Other(Arc::new(msg.into())) ExpandError::Other(Arc::new(msg.into()))
} }
pub fn render_to_string(&self, db: &dyn ExpandDatabase) -> (String, bool) {
match self {
Self::ProcMacroAttrExpansionDisabled => {
("procedural attribute macro expansion is disabled".to_owned(), false)
}
Self::MacroDisabled => ("proc-macro is explicitly disabled".to_owned(), false),
&Self::MissingProcMacroExpander(def_crate) => {
match db.proc_macros().get_error_for_crate(def_crate) {
Some((e, hard_err)) => (e.to_owned(), hard_err),
None => ("missing expander".to_owned(), true),
}
}
Self::MacroDefinition => ("macro definition has parse errors".to_owned(), true),
Self::Mbe(e) => (e.to_string(), true),
Self::RecursionOverflow => ("overflow expanding the original macro".to_owned(), true),
Self::Other(e) => ((***e).to_owned(), true),
Self::ProcMacroPanic(e) => ((***e).to_owned(), true),
}
}
} }
impl From<mbe::ExpandError> for ExpandError { impl From<mbe::ExpandError> for ExpandError {
@ -148,24 +167,6 @@ impl From<mbe::ExpandError> for ExpandError {
Self::Mbe(mbe) Self::Mbe(mbe)
} }
} }
impl fmt::Display for ExpandError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
ExpandError::UnresolvedProcMacro(_) => f.write_str("unresolved proc-macro"),
ExpandError::Mbe(it) => it.fmt(f),
ExpandError::RecursionOverflow => f.write_str("overflow expanding the original macro"),
ExpandError::ProcMacroPanic(it) => {
f.write_str("proc-macro panicked: ")?;
f.write_str(it)
}
ExpandError::Other(it) => f.write_str(it),
ExpandError::MacroDisabled => f.write_str("macro disabled"),
ExpandError::MacroDefinition => f.write_str("macro definition has parse errors"),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct MacroCallLoc { pub struct MacroCallLoc {
pub def: MacroDefId, pub def: MacroDefId,
@ -277,11 +278,9 @@ impl HirFileIdExt for HirFileId {
let loc = db.lookup_intern_macro_call(file.macro_call_id); let loc = db.lookup_intern_macro_call(file.macro_call_id);
if loc.def.is_include() { if loc.def.is_include() {
if let MacroCallKind::FnLike { eager: Some(eager), .. } = &loc.kind { if let MacroCallKind::FnLike { eager: Some(eager), .. } = &loc.kind {
if let Ok(it) = builtin_fn_macro::include_input_to_file_id( if let Ok(it) =
db, include_input_to_file_id(db, file.macro_call_id, &eager.arg)
file.macro_call_id, {
&eager.arg,
) {
break it; break it;
} }
} }
@ -572,9 +571,7 @@ impl MacroCallLoc {
) -> Option<EditionedFileId> { ) -> Option<EditionedFileId> {
if self.def.is_include() { if self.def.is_include() {
if let MacroCallKind::FnLike { eager: Some(eager), .. } = &self.kind { if let MacroCallKind::FnLike { eager: Some(eager), .. } = &self.kind {
if let Ok(it) = if let Ok(it) = include_input_to_file_id(db, macro_call_id, &eager.arg) {
builtin_fn_macro::include_input_to_file_id(db, macro_call_id, &eager.arg)
{
return Some(it); return Some(it);
} }
} }

View file

@ -7,20 +7,10 @@ use base_db::{CrateId, Env};
use intern::Symbol; use intern::Symbol;
use rustc_hash::FxHashMap; use rustc_hash::FxHashMap;
use span::Span; use span::Span;
use stdx::never;
use triomphe::Arc; use triomphe::Arc;
use crate::{db::ExpandDatabase, tt, ExpandError, ExpandResult}; use crate::{db::ExpandDatabase, tt, ExpandError, ExpandResult};
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct ProcMacroId(u32);
impl ProcMacroId {
pub fn new(u32: u32) -> Self {
ProcMacroId(u32)
}
}
#[derive(Copy, Clone, Eq, PartialEq, Debug, Hash)] #[derive(Copy, Clone, Eq, PartialEq, Debug, Hash)]
pub enum ProcMacroKind { pub enum ProcMacroKind {
CustomDerive, CustomDerive,
@ -28,7 +18,10 @@ pub enum ProcMacroKind {
Attr, Attr,
} }
/// A proc-macro expander implementation.
pub trait ProcMacroExpander: fmt::Debug + Send + Sync + RefUnwindSafe { pub trait ProcMacroExpander: fmt::Debug + Send + Sync + RefUnwindSafe {
/// Run the expander with the given input subtree, optional attribute input subtree (for
/// [`ProcMacroKind::Attr`]), environment variables, and span information.
fn expand( fn expand(
&self, &self,
subtree: &tt::Subtree, subtree: &tt::Subtree,
@ -42,57 +35,162 @@ pub trait ProcMacroExpander: fmt::Debug + Send + Sync + RefUnwindSafe {
#[derive(Debug)] #[derive(Debug)]
pub enum ProcMacroExpansionError { pub enum ProcMacroExpansionError {
/// The proc-macro panicked.
Panic(String), Panic(String),
/// Things like "proc macro server was killed by OOM". /// The server itself errored out.
System(String), System(String),
} }
pub type ProcMacroLoadResult = Result<Vec<ProcMacro>, String>; pub type ProcMacroLoadResult = Result<Vec<ProcMacro>, (String, bool)>;
type StoredProcMacroLoadResult = Result<Box<[ProcMacro]>, (Box<str>, bool)>;
pub type ProcMacros = FxHashMap<CrateId, ProcMacroLoadResult>; #[derive(Default, Debug)]
pub struct ProcMacrosBuilder(FxHashMap<CrateId, StoredProcMacroLoadResult>);
impl ProcMacrosBuilder {
pub fn insert(&mut self, proc_macros_crate: CrateId, proc_macro: ProcMacroLoadResult) {
self.0.insert(
proc_macros_crate,
match proc_macro {
Ok(it) => Ok(it.into_boxed_slice()),
Err((e, hard_err)) => Err((e.into_boxed_str(), hard_err)),
},
);
}
pub fn build(mut self) -> ProcMacros {
self.0.shrink_to_fit();
ProcMacros(self.0)
}
}
#[derive(Default, Debug)]
pub struct ProcMacros(FxHashMap<CrateId, StoredProcMacroLoadResult>);
impl FromIterator<(CrateId, ProcMacroLoadResult)> for ProcMacros {
fn from_iter<T: IntoIterator<Item = (CrateId, ProcMacroLoadResult)>>(iter: T) -> Self {
let mut builder = ProcMacrosBuilder::default();
for (k, v) in iter {
builder.insert(k, v);
}
builder.build()
}
}
impl ProcMacros {
fn get(&self, krate: CrateId, idx: u32) -> Result<&ProcMacro, ExpandError> {
let proc_macros = match self.0.get(&krate) {
Some(Ok(proc_macros)) => proc_macros,
Some(Err(_)) | None => {
return Err(ExpandError::other("internal error: no proc macros for crate"));
}
};
proc_macros.get(idx as usize).ok_or_else(|| {
ExpandError::other(
format!(
"internal error: proc-macro index out of bounds: the length is {} but the index is {}",
proc_macros.len(),
idx
)
)
}
)
}
pub fn get_error_for_crate(&self, krate: CrateId) -> Option<(&str, bool)> {
self.0.get(&krate).and_then(|it| it.as_ref().err()).map(|(e, hard_err)| (&**e, *hard_err))
}
/// Fetch the [`CustomProcMacroExpander`]s and their corresponding names for the given crate.
pub fn for_crate(
&self,
krate: CrateId,
def_site_ctx: span::SyntaxContextId,
) -> Option<Box<[(crate::name::Name, CustomProcMacroExpander, bool)]>> {
match self.0.get(&krate) {
Some(Ok(proc_macros)) => Some({
proc_macros
.iter()
.enumerate()
.map(|(idx, it)| {
let name = crate::name::Name::new_symbol(it.name.clone(), def_site_ctx);
(name, CustomProcMacroExpander::new(idx as u32), it.disabled)
})
.collect()
}),
_ => None,
}
}
}
/// A loaded proc-macro.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct ProcMacro { pub struct ProcMacro {
/// The name of the proc macro.
pub name: Symbol, pub name: Symbol,
pub kind: ProcMacroKind, pub kind: ProcMacroKind,
/// The expander handle for this proc macro.
pub expander: sync::Arc<dyn ProcMacroExpander>, pub expander: sync::Arc<dyn ProcMacroExpander>,
/// Whether this proc-macro is disabled for early name resolution. Notably, the
/// [`Self::expander`] is still usable.
pub disabled: bool, pub disabled: bool,
} }
/// A custom proc-macro expander handle. This handle together with its crate resolves to a [`ProcMacro`]
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] #[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
pub struct CustomProcMacroExpander { pub struct CustomProcMacroExpander {
proc_macro_id: ProcMacroId, proc_macro_id: u32,
} }
impl CustomProcMacroExpander { impl CustomProcMacroExpander {
const DUMMY_ID: u32 = !0; const MISSING_EXPANDER: u32 = !0;
const DISABLED_ID: u32 = !1; const DISABLED_ID: u32 = !1;
const PROC_MACRO_ATTR_DISABLED: u32 = !2;
pub fn new(proc_macro_id: ProcMacroId) -> Self { pub fn new(proc_macro_id: u32) -> Self {
assert_ne!(proc_macro_id.0, Self::DUMMY_ID); assert_ne!(proc_macro_id, Self::MISSING_EXPANDER);
assert_ne!(proc_macro_id.0, Self::DISABLED_ID); assert_ne!(proc_macro_id, Self::DISABLED_ID);
assert_ne!(proc_macro_id, Self::PROC_MACRO_ATTR_DISABLED);
Self { proc_macro_id } Self { proc_macro_id }
} }
/// A dummy expander that always errors. This is used for proc-macros that are missing, usually /// An expander that always errors due to the actual proc-macro expander missing.
/// due to them not being built yet. pub const fn missing_expander() -> Self {
pub const fn dummy() -> Self { Self { proc_macro_id: Self::MISSING_EXPANDER }
Self { proc_macro_id: ProcMacroId(Self::DUMMY_ID) }
}
/// The macro was not yet resolved.
pub const fn is_dummy(&self) -> bool {
self.proc_macro_id.0 == Self::DUMMY_ID
} }
/// A dummy expander that always errors. This expander is used for macros that have been disabled. /// A dummy expander that always errors. This expander is used for macros that have been disabled.
pub const fn disabled() -> Self { pub const fn disabled() -> Self {
Self { proc_macro_id: ProcMacroId(Self::DISABLED_ID) } Self { proc_macro_id: Self::DISABLED_ID }
}
/// A dummy expander that always errors. This expander is used for attribute macros when
/// proc-macro attribute expansion is disabled.
pub const fn disabled_proc_attr() -> Self {
Self { proc_macro_id: Self::PROC_MACRO_ATTR_DISABLED }
}
/// The macro-expander is missing or has yet to be build.
pub const fn is_missing(&self) -> bool {
self.proc_macro_id == Self::MISSING_EXPANDER
} }
/// The macro is explicitly disabled and cannot be expanded. /// The macro is explicitly disabled and cannot be expanded.
pub const fn is_disabled(&self) -> bool { pub const fn is_disabled(&self) -> bool {
self.proc_macro_id.0 == Self::DISABLED_ID self.proc_macro_id == Self::DISABLED_ID
}
/// The macro is explicitly disabled due to proc-macro attribute expansion being disabled.
pub const fn is_disabled_proc_attr(&self) -> bool {
self.proc_macro_id == Self::PROC_MACRO_ATTR_DISABLED
}
/// The macro is explicitly disabled due to proc-macro attribute expansion being disabled.
pub const fn as_expand_error(&self, def_crate: CrateId) -> Option<ExpandError> {
match self.proc_macro_id {
Self::PROC_MACRO_ATTR_DISABLED => Some(ExpandError::ProcMacroAttrExpansionDisabled),
Self::DISABLED_ID => Some(ExpandError::MacroDisabled),
Self::MISSING_EXPANDER => Some(ExpandError::MissingProcMacroExpander(def_crate)),
_ => None,
}
} }
pub fn expand( pub fn expand(
@ -107,38 +205,27 @@ impl CustomProcMacroExpander {
mixed_site: Span, mixed_site: Span,
) -> ExpandResult<tt::Subtree> { ) -> ExpandResult<tt::Subtree> {
match self.proc_macro_id { match self.proc_macro_id {
ProcMacroId(Self::DUMMY_ID) => ExpandResult::new( Self::PROC_MACRO_ATTR_DISABLED => ExpandResult::new(
tt::Subtree::empty(tt::DelimSpan { open: call_site, close: call_site }), tt::Subtree::empty(tt::DelimSpan { open: call_site, close: call_site }),
ExpandError::UnresolvedProcMacro(def_crate), ExpandError::ProcMacroAttrExpansionDisabled,
), ),
ProcMacroId(Self::DISABLED_ID) => ExpandResult::new( Self::MISSING_EXPANDER => ExpandResult::new(
tt::Subtree::empty(tt::DelimSpan { open: call_site, close: call_site }),
ExpandError::MissingProcMacroExpander(def_crate),
),
Self::DISABLED_ID => ExpandResult::new(
tt::Subtree::empty(tt::DelimSpan { open: call_site, close: call_site }), tt::Subtree::empty(tt::DelimSpan { open: call_site, close: call_site }),
ExpandError::MacroDisabled, ExpandError::MacroDisabled,
), ),
ProcMacroId(id) => { id => {
let proc_macros = db.proc_macros(); let proc_macros = db.proc_macros();
let proc_macros = match proc_macros.get(&def_crate) { let proc_macro = match proc_macros.get(def_crate, id) {
Some(Ok(proc_macros)) => proc_macros, Ok(proc_macro) => proc_macro,
Some(Err(_)) | None => { Err(e) => {
never!("Non-dummy expander even though there are no proc macros");
return ExpandResult::new( return ExpandResult::new(
tt::Subtree::empty(tt::DelimSpan { open: call_site, close: call_site }), tt::Subtree::empty(tt::DelimSpan { open: call_site, close: call_site }),
ExpandError::other("Internal error"), e,
); )
}
};
let proc_macro = match proc_macros.get(id as usize) {
Some(proc_macro) => proc_macro,
None => {
never!(
"Proc macro index out of bounds: the length is {} but the index is {}",
proc_macros.len(),
id
);
return ExpandResult::new(
tt::Subtree::empty(tt::DelimSpan { open: call_site, close: call_site }),
ExpandError::other("Internal error: proc-macro index out of bounds"),
);
} }
}; };

View file

@ -6,7 +6,6 @@
pub use hir_ty::diagnostics::{CaseType, IncorrectCase}; pub use hir_ty::diagnostics::{CaseType, IncorrectCase};
use hir_ty::{db::HirDatabase, diagnostics::BodyValidationDiagnostic, InferenceDiagnostic}; use hir_ty::{db::HirDatabase, diagnostics::BodyValidationDiagnostic, InferenceDiagnostic};
use base_db::CrateId;
use cfg::{CfgExpr, CfgOptions}; use cfg::{CfgExpr, CfgOptions};
use either::Either; use either::Either;
pub use hir_def::VariantId; pub use hir_def::VariantId;
@ -15,7 +14,7 @@ use hir_expand::{name::Name, HirFileId, InFile};
use syntax::{ast, AstPtr, SyntaxError, SyntaxNodePtr, TextRange}; use syntax::{ast, AstPtr, SyntaxError, SyntaxNodePtr, TextRange};
use triomphe::Arc; use triomphe::Arc;
use crate::{AssocItem, Field, Local, MacroKind, Trait, Type}; use crate::{AssocItem, Field, Local, Trait, Type};
macro_rules! diagnostics { macro_rules! diagnostics {
($($diag:ident,)*) => { ($($diag:ident,)*) => {
@ -90,7 +89,6 @@ diagnostics![
UnresolvedMethodCall, UnresolvedMethodCall,
UnresolvedModule, UnresolvedModule,
UnresolvedIdent, UnresolvedIdent,
UnresolvedProcMacro,
UnusedMut, UnusedMut,
UnusedVariable, UnusedVariable,
]; ];
@ -150,23 +148,12 @@ pub struct InactiveCode {
pub opts: CfgOptions, pub opts: CfgOptions,
} }
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct UnresolvedProcMacro {
pub node: InFile<SyntaxNodePtr>,
/// If the diagnostic can be pinpointed more accurately than via `node`, this is the `TextRange`
/// to use instead.
pub precise_location: Option<TextRange>,
pub macro_name: Option<String>,
pub kind: MacroKind,
/// The crate id of the proc-macro this macro belongs to, or `None` if the proc-macro can't be found.
pub krate: CrateId,
}
#[derive(Debug, Clone, Eq, PartialEq)] #[derive(Debug, Clone, Eq, PartialEq)]
pub struct MacroError { pub struct MacroError {
pub node: InFile<SyntaxNodePtr>, pub node: InFile<SyntaxNodePtr>,
pub precise_location: Option<TextRange>, pub precise_location: Option<TextRange>,
pub message: String, pub message: String,
pub error: bool,
} }
#[derive(Debug, Clone, Eq, PartialEq)] #[derive(Debug, Clone, Eq, PartialEq)]

View file

@ -137,7 +137,7 @@ pub use {
hygiene::{marks_rev, SyntaxContextExt}, hygiene::{marks_rev, SyntaxContextExt},
inert_attr_macro::AttributeTemplate, inert_attr_macro::AttributeTemplate,
name::Name, name::Name,
proc_macro::ProcMacros, proc_macro::{ProcMacros, ProcMacrosBuilder},
tt, ExpandResult, HirFileId, HirFileIdExt, MacroFileId, MacroFileIdExt, tt, ExpandResult, HirFileId, HirFileIdExt, MacroFileId, MacroFileIdExt,
}, },
hir_ty::{ hir_ty::{
@ -833,14 +833,10 @@ fn macro_call_diagnostics(
let ValueResult { value: parse_errors, err } = &*e; let ValueResult { value: parse_errors, err } = &*e;
if let Some(err) = err { if let Some(err) = err {
let loc = db.lookup_intern_macro_call(macro_call_id); let loc = db.lookup_intern_macro_call(macro_call_id);
let (node, precise_location, macro_name, kind) = precise_macro_call_location(&loc.kind, db); let (node, precise_location, _macro_name, _kind) =
let diag = match err { precise_macro_call_location(&loc.kind, db);
&hir_expand::ExpandError::UnresolvedProcMacro(krate) => { let (message, error) = err.render_to_string(db.upcast());
UnresolvedProcMacro { node, precise_location, macro_name, kind, krate }.into() acc.push(MacroError { node, precise_location, message, error }.into());
}
err => MacroError { node, precise_location, message: err.to_string() }.into(),
};
acc.push(diag);
} }
if !parse_errors.is_empty() { if !parse_errors.is_empty() {
@ -895,6 +891,19 @@ fn emit_def_diagnostic_(
acc.push(UnresolvedExternCrate { decl: InFile::new(ast.file_id, item) }.into()); acc.push(UnresolvedExternCrate { decl: InFile::new(ast.file_id, item) }.into());
} }
DefDiagnosticKind::MacroError { ast, err } => {
let item = ast.to_ptr(db.upcast());
let (message, error) = err.render_to_string(db.upcast());
acc.push(
MacroError {
node: InFile::new(ast.file_id, item.syntax_node_ptr()),
precise_location: None,
message,
error,
}
.into(),
)
}
DefDiagnosticKind::UnresolvedImport { id, index } => { DefDiagnosticKind::UnresolvedImport { id, index } => {
let file_id = id.file_id(); let file_id = id.file_id();
let item_tree = id.item_tree(db.upcast()); let item_tree = id.item_tree(db.upcast());
@ -991,13 +1000,6 @@ fn emit_def_diagnostic_(
Some(()) Some(())
})(); })();
} }
DefDiagnosticKind::UnresolvedProcMacro { ast, krate } => {
let (node, precise_location, macro_name, kind) = precise_macro_call_location(ast, db);
acc.push(
UnresolvedProcMacro { node, precise_location, macro_name, kind, krate: *krate }
.into(),
);
}
DefDiagnosticKind::UnresolvedMacroCall { ast, path } => { DefDiagnosticKind::UnresolvedMacroCall { ast, path } => {
let (node, precise_location, _, _) = precise_macro_call_location(ast, db); let (node, precise_location, _, _) = precise_macro_call_location(ast, db);
acc.push( acc.push(
@ -1795,20 +1797,17 @@ impl DefWithBody {
BodyDiagnostic::InactiveCode { node, cfg, opts } => { BodyDiagnostic::InactiveCode { node, cfg, opts } => {
InactiveCode { node: *node, cfg: cfg.clone(), opts: opts.clone() }.into() InactiveCode { node: *node, cfg: cfg.clone(), opts: opts.clone() }.into()
} }
BodyDiagnostic::MacroError { node, message } => MacroError { BodyDiagnostic::MacroError { node, err } => {
let (message, error) = err.render_to_string(db.upcast());
MacroError {
node: (*node).map(|it| it.into()), node: (*node).map(|it| it.into()),
precise_location: None, precise_location: None,
message: message.to_string(), message,
error,
} }
.into(), .into()
BodyDiagnostic::UnresolvedProcMacro { node, krate } => UnresolvedProcMacro {
node: (*node).map(|it| it.into()),
precise_location: None,
macro_name: None,
kind: MacroKind::ProcMacro,
krate: *krate,
} }
.into(),
BodyDiagnostic::UnresolvedMacroCall { node, path } => UnresolvedMacroCall { BodyDiagnostic::UnresolvedMacroCall { node, path } => UnresolvedMacroCall {
macro_call: (*node).map(|ast_ptr| ast_ptr.into()), macro_call: (*node).map(|ast_ptr| ast_ptr.into()),
precise_location: None, precise_location: None,

View file

@ -19,7 +19,7 @@ use hir_def::{
}; };
use hir_expand::{ use hir_expand::{
attrs::collect_attrs, attrs::collect_attrs,
builtin_fn_macro::{BuiltinFnLikeExpander, EagerExpander}, builtin::{BuiltinFnLikeExpander, EagerExpander},
db::ExpandDatabase, db::ExpandDatabase,
files::InRealFile, files::InRealFile,
name::AsName, name::AsName,

View file

@ -7,7 +7,10 @@ pub(crate) fn macro_error(ctx: &DiagnosticsContext<'_>, d: &hir::MacroError) ->
// Use more accurate position if available. // Use more accurate position if available.
let display_range = ctx.resolve_precise_location(&d.node, d.precise_location); let display_range = ctx.resolve_precise_location(&d.node, d.precise_location);
Diagnostic::new( Diagnostic::new(
DiagnosticCode::Ra("macro-error", Severity::Error), DiagnosticCode::Ra(
"macro-error",
if d.error { Severity::Error } else { Severity::WeakWarning },
),
d.message.clone(), d.message.clone(),
display_range, display_range,
) )

View file

@ -1,45 +0,0 @@
use hir::db::DefDatabase;
use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext, Severity};
// Diagnostic: unresolved-proc-macro
//
// This diagnostic is shown when a procedural macro can not be found. This usually means that
// procedural macro support is simply disabled (and hence is only a weak hint instead of an error),
// but can also indicate project setup problems.
//
// If you are seeing a lot of "proc macro not expanded" warnings, you can add this option to the
// `rust-analyzer.diagnostics.disabled` list to prevent them from showing. Alternatively you can
// enable support for procedural macros (see `rust-analyzer.procMacro.attributes.enable`).
pub(crate) fn unresolved_proc_macro(
ctx: &DiagnosticsContext<'_>,
d: &hir::UnresolvedProcMacro,
proc_macros_enabled: bool,
proc_attr_macros_enabled: bool,
) -> Diagnostic {
// Use more accurate position if available.
let display_range = ctx.resolve_precise_location(&d.node, d.precise_location);
let config_enabled = match d.kind {
hir::MacroKind::Attr => proc_macros_enabled && proc_attr_macros_enabled,
_ => proc_macros_enabled,
};
let not_expanded_message = match &d.macro_name {
Some(name) => format!("proc macro `{name}` not expanded"),
None => "proc macro not expanded".to_owned(),
};
let severity = if config_enabled { Severity::Error } else { Severity::WeakWarning };
let def_map = ctx.sema.db.crate_def_map(d.krate);
let message = if config_enabled {
def_map.proc_macro_loading_error().unwrap_or("internal error")
} else {
match d.kind {
hir::MacroKind::Attr if proc_macros_enabled => "attribute macro expansion is disabled",
_ => "proc-macro expansion is disabled",
}
};
let message = format!("{not_expanded_message}: {message}");
Diagnostic::new(DiagnosticCode::Ra("unresolved-proc-macro", severity), message, display_range)
}

View file

@ -62,7 +62,6 @@ mod handlers {
pub(crate) mod unresolved_macro_call; pub(crate) mod unresolved_macro_call;
pub(crate) mod unresolved_method; pub(crate) mod unresolved_method;
pub(crate) mod unresolved_module; pub(crate) mod unresolved_module;
pub(crate) mod unresolved_proc_macro;
pub(crate) mod unused_variables; pub(crate) mod unused_variables;
// The handlers below are unusual, the implement the diagnostics as well. // The handlers below are unusual, the implement the diagnostics as well.
@ -405,7 +404,6 @@ pub fn diagnostics(
AnyDiagnostic::UnresolvedMacroCall(d) => handlers::unresolved_macro_call::unresolved_macro_call(&ctx, &d), AnyDiagnostic::UnresolvedMacroCall(d) => handlers::unresolved_macro_call::unresolved_macro_call(&ctx, &d),
AnyDiagnostic::UnresolvedMethodCall(d) => handlers::unresolved_method::unresolved_method(&ctx, &d), AnyDiagnostic::UnresolvedMethodCall(d) => handlers::unresolved_method::unresolved_method(&ctx, &d),
AnyDiagnostic::UnresolvedModule(d) => handlers::unresolved_module::unresolved_module(&ctx, &d), AnyDiagnostic::UnresolvedModule(d) => handlers::unresolved_module::unresolved_module(&ctx, &d),
AnyDiagnostic::UnresolvedProcMacro(d) => handlers::unresolved_proc_macro::unresolved_proc_macro(&ctx, &d, config.proc_macros_enabled, config.proc_attr_macros_enabled),
AnyDiagnostic::UnusedMut(d) => match handlers::mutability_errors::unused_mut(&ctx, &d) { AnyDiagnostic::UnusedMut(d) => match handlers::mutability_errors::unused_mut(&ctx, &d) {
Some(it) => it, Some(it) => it,
None => continue, None => continue,

View file

@ -43,7 +43,6 @@ mod parent_module;
mod references; mod references;
mod rename; mod rename;
mod runnables; mod runnables;
mod shuffle_crate_graph;
mod signature_help; mod signature_help;
mod ssr; mod ssr;
mod static_index; mod static_index;
@ -202,10 +201,6 @@ impl AnalysisHost {
pub fn raw_database_mut(&mut self) -> &mut RootDatabase { pub fn raw_database_mut(&mut self) -> &mut RootDatabase {
&mut self.db &mut self.db
} }
pub fn shuffle_crate_graph(&mut self) {
shuffle_crate_graph::shuffle_crate_graph(&mut self.db);
}
} }
impl Default for AnalysisHost { impl Default for AnalysisHost {

View file

@ -1,58 +0,0 @@
use hir::{db::ExpandDatabase, ProcMacros};
use ide_db::{
base_db::{salsa::Durability, CrateGraph, SourceDatabase},
FxHashMap, RootDatabase,
};
use triomphe::Arc;
// Feature: Shuffle Crate Graph
//
// Randomizes all crate IDs in the crate graph, for debugging.
//
// |===
// | Editor | Action Name
//
// | VS Code | **rust-analyzer: Shuffle Crate Graph**
// |===
pub(crate) fn shuffle_crate_graph(db: &mut RootDatabase) {
let crate_graph = db.crate_graph();
let proc_macros = db.proc_macros();
let mut shuffled_ids = crate_graph.iter().collect::<Vec<_>>();
let mut rng = oorandom::Rand32::new(stdx::rand::seed());
stdx::rand::shuffle(&mut shuffled_ids, |i| rng.rand_range(0..i as u32) as usize);
let mut new_graph = CrateGraph::default();
let mut new_proc_macros = ProcMacros::default();
let mut map = FxHashMap::default();
for old_id in shuffled_ids.iter().copied() {
let data = &crate_graph[old_id];
let new_id = new_graph.add_crate_root(
data.root_file_id,
data.edition,
data.display_name.clone(),
data.version.clone(),
data.cfg_options.clone(),
data.potential_cfg_options.clone(),
data.env.clone(),
data.is_proc_macro,
data.origin.clone(),
);
new_proc_macros.insert(new_id, proc_macros[&old_id].clone());
map.insert(old_id, new_id);
}
for old_id in shuffled_ids.iter().copied() {
let data = &crate_graph[old_id];
for dep in &data.dependencies {
let mut new_dep = dep.clone();
new_dep.crate_id = map[&dep.crate_id];
new_graph.add_dep(map[&old_id], new_dep).unwrap();
}
}
db.set_crate_graph_with_durability(Arc::new(new_graph), Durability::HIGH);
db.set_proc_macros_with_durability(Arc::new(new_proc_macros), Durability::HIGH);
}

View file

@ -68,11 +68,14 @@ pub fn load_workspace(
let proc_macro_server = match &load_config.with_proc_macro_server { let proc_macro_server = match &load_config.with_proc_macro_server {
ProcMacroServerChoice::Sysroot => ws ProcMacroServerChoice::Sysroot => ws
.find_sysroot_proc_macro_srv() .find_sysroot_proc_macro_srv()
.and_then(|it| ProcMacroServer::spawn(&it, extra_env).map_err(Into::into)), .and_then(|it| ProcMacroServer::spawn(&it, extra_env).map_err(Into::into))
.map_err(|e| (e, true)),
ProcMacroServerChoice::Explicit(path) => { ProcMacroServerChoice::Explicit(path) => {
ProcMacroServer::spawn(path, extra_env).map_err(Into::into) ProcMacroServer::spawn(path, extra_env).map_err(Into::into).map_err(|e| (e, true))
}
ProcMacroServerChoice::None => {
Err((anyhow::format_err!("proc macro server disabled"), false))
} }
ProcMacroServerChoice::None => Err(anyhow::format_err!("proc macro server disabled")),
}; };
let (crate_graph, proc_macros) = ws.to_crate_graph( let (crate_graph, proc_macros) = ws.to_crate_graph(
@ -87,7 +90,7 @@ pub fn load_workspace(
let proc_macros = { let proc_macros = {
let proc_macro_server = match &proc_macro_server { let proc_macro_server = match &proc_macro_server {
Ok(it) => Ok(it), Ok(it) => Ok(it),
Err(e) => Err(e.to_string()), Err((e, hard_err)) => Err((e.to_string(), *hard_err)),
}; };
proc_macros proc_macros
.into_iter() .into_iter()
@ -95,7 +98,7 @@ pub fn load_workspace(
( (
crate_id, crate_id,
path.map_or_else( path.map_or_else(
|_| Err("proc macro crate is missing dylib".to_owned()), |e| Err((e, true)),
|(_, path)| { |(_, path)| {
proc_macro_server.as_ref().map_err(Clone::clone).and_then( proc_macro_server.as_ref().map_err(Clone::clone).and_then(
|proc_macro_server| load_proc_macro(proc_macro_server, &path, &[]), |proc_macro_server| load_proc_macro(proc_macro_server, &path, &[]),
@ -355,8 +358,7 @@ impl SourceRootConfig {
} }
} }
/// Load the proc-macros for the given lib path, replacing all expanders whose names are in `dummy_replace` /// Load the proc-macros for the given lib path, disabling all expanders whose names are in `ignored_macros`.
/// with an identity dummy expander.
pub fn load_proc_macro( pub fn load_proc_macro(
server: &ProcMacroServer, server: &ProcMacroServer,
path: &AbsPath, path: &AbsPath,
@ -383,7 +385,7 @@ pub fn load_proc_macro(
} }
Err(e) => { Err(e) => {
tracing::warn!("proc-macro loading for {path} failed: {e}"); tracing::warn!("proc-macro loading for {path} failed: {e}");
Err(e) Err((e, true))
} }
} }
} }

View file

@ -934,7 +934,10 @@ fn project_json_to_crate_graph(
if *is_proc_macro { if *is_proc_macro {
if let Some(path) = proc_macro_dylib_path.clone() { if let Some(path) = proc_macro_dylib_path.clone() {
let node = Ok(( let node = Ok((
display_name.as_ref().map(|it| it.canonical_name().as_str().to_owned()), display_name
.as_ref()
.map(|it| it.canonical_name().as_str().to_owned())
.unwrap_or_else(|| format!("crate{}", idx.0)),
path, path,
)); ));
proc_macros.insert(crate_graph_crate_id, node); proc_macros.insert(crate_graph_crate_id, node);
@ -1355,8 +1358,8 @@ fn add_target_crate_root(
); );
if let TargetKind::Lib { is_proc_macro: true } = kind { if let TargetKind::Lib { is_proc_macro: true } = kind {
let proc_macro = match build_data.as_ref().map(|it| it.proc_macro_dylib_path.as_ref()) { let proc_macro = match build_data.as_ref().map(|it| it.proc_macro_dylib_path.as_ref()) {
Some(it) => it.cloned().map(|path| Ok((Some(cargo_name.to_owned()), path))), Some(it) => it.cloned().map(|path| Ok((cargo_name.to_owned(), path))),
None => Some(Err("crate has not yet been built".to_owned())), None => Some(Err("proc-macro crate is missing its build data".to_owned())),
}; };
if let Some(proc_macro) = proc_macro { if let Some(proc_macro) = proc_macro {
proc_macros.insert(crate_id, proc_macro); proc_macros.insert(crate_id, proc_macro);

View file

@ -134,11 +134,6 @@ pub(crate) fn handle_memory_usage(state: &mut GlobalState, _: ()) -> anyhow::Res
Ok(out) Ok(out)
} }
pub(crate) fn handle_shuffle_crate_graph(state: &mut GlobalState, _: ()) -> anyhow::Result<()> {
state.analysis_host.shuffle_crate_graph();
Ok(())
}
pub(crate) fn handle_syntax_tree( pub(crate) fn handle_syntax_tree(
snap: GlobalStateSnapshot, snap: GlobalStateSnapshot,
params: lsp_ext::SyntaxTreeParams, params: lsp_ext::SyntaxTreeParams,

View file

@ -75,14 +75,6 @@ impl Request for MemoryUsage {
const METHOD: &'static str = "rust-analyzer/memoryUsage"; const METHOD: &'static str = "rust-analyzer/memoryUsage";
} }
pub enum ShuffleCrateGraph {}
impl Request for ShuffleCrateGraph {
type Params = ();
type Result = ();
const METHOD: &'static str = "rust-analyzer/shuffleCrateGraph";
}
pub enum ReloadWorkspace {} pub enum ReloadWorkspace {}
impl Request for ReloadWorkspace { impl Request for ReloadWorkspace {

View file

@ -1018,7 +1018,6 @@ impl GlobalState {
.on_sync_mut::<lsp_ext::ReloadWorkspace>(handlers::handle_workspace_reload) .on_sync_mut::<lsp_ext::ReloadWorkspace>(handlers::handle_workspace_reload)
.on_sync_mut::<lsp_ext::RebuildProcMacros>(handlers::handle_proc_macros_rebuild) .on_sync_mut::<lsp_ext::RebuildProcMacros>(handlers::handle_proc_macros_rebuild)
.on_sync_mut::<lsp_ext::MemoryUsage>(handlers::handle_memory_usage) .on_sync_mut::<lsp_ext::MemoryUsage>(handlers::handle_memory_usage)
.on_sync_mut::<lsp_ext::ShuffleCrateGraph>(handlers::handle_shuffle_crate_graph)
.on_sync_mut::<lsp_ext::RunTest>(handlers::handle_run_test) .on_sync_mut::<lsp_ext::RunTest>(handlers::handle_run_test)
// Request handlers which are related to the user typing // Request handlers which are related to the user typing
// are run on the main thread to reduce latency: // are run on the main thread to reduce latency:

View file

@ -16,8 +16,7 @@
use std::{iter, mem}; use std::{iter, mem};
use flycheck::{FlycheckConfig, FlycheckHandle}; use flycheck::{FlycheckConfig, FlycheckHandle};
use hir::{db::DefDatabase, ChangeWithProcMacros, ProcMacros}; use hir::{db::DefDatabase, ChangeWithProcMacros, ProcMacros, ProcMacrosBuilder};
use ide::CrateId;
use ide_db::{ use ide_db::{
base_db::{salsa::Durability, CrateGraph, ProcMacroPaths, Version}, base_db::{salsa::Durability, CrateGraph, ProcMacroPaths, Version},
FxHashMap, FxHashMap,
@ -371,43 +370,44 @@ impl GlobalState {
} }
}; };
let mut res = FxHashMap::default(); let mut builder = ProcMacrosBuilder::default();
let chain = proc_macro_clients let chain = proc_macro_clients
.iter() .iter()
.map(|res| res.as_ref().map_err(|e| e.to_string())) .map(|res| res.as_ref().map_err(|e| e.to_string()))
.chain(iter::repeat_with(|| Err("Proc macros servers are not running".into()))); .chain(iter::repeat_with(|| Err("proc-macro-srv is not running".into())));
for (client, paths) in chain.zip(paths) { for (client, paths) in chain.zip(paths) {
res.extend(paths.into_iter().map(move |(crate_id, res)| { paths
.into_iter()
.map(move |(crate_id, res)| {
( (
crate_id, crate_id,
res.map_or_else( res.map_or_else(
|_| Err("proc macro crate is missing dylib".to_owned()), |e| Err((e, true)),
|(crate_name, path)| { |(crate_name, path)| {
progress(path.to_string()); progress(path.to_string());
client.as_ref().map_err(Clone::clone).and_then(|client| { client.as_ref().map_err(|it| (it.clone(), true)).and_then(
|client| {
load_proc_macro( load_proc_macro(
client, client,
&path, &path,
crate_name ignored_proc_macros
.as_deref() .iter()
.and_then(|crate_name| { .find_map(|(name, macros)| {
ignored_proc_macros.iter().find_map( eq_ignore_underscore(name, &crate_name)
|(name, macros)| {
eq_ignore_underscore(name, crate_name)
.then_some(&**macros) .then_some(&**macros)
},
)
}) })
.unwrap_or_default(), .unwrap_or_default(),
) )
}) },
)
}, },
), ),
) )
})); })
.for_each(|(krate, res)| builder.insert(krate, res));
} }
sender.send(Task::LoadProcMacros(ProcMacroProgress::End(res))).unwrap(); sender.send(Task::LoadProcMacros(ProcMacroProgress::End(builder.build()))).unwrap();
}); });
} }
@ -667,10 +667,17 @@ impl GlobalState {
change.set_proc_macros( change.set_proc_macros(
crate_graph crate_graph
.iter() .iter()
.map(|id| (id, Err("Proc-macros have not been built yet".to_owned()))) .map(|id| (id, Err(("proc-macro has not been built yet".to_owned(), true))))
.collect(), .collect(),
); );
self.fetch_proc_macros_queue.request_op(cause, proc_macro_paths); self.fetch_proc_macros_queue.request_op(cause, proc_macro_paths);
} else {
change.set_proc_macros(
crate_graph
.iter()
.map(|id| (id, Err(("proc-macro expansion is disabled".to_owned(), false))))
.collect(),
);
} }
change.set_crate_graph(crate_graph); change.set_crate_graph(crate_graph);
change.set_target_data_layouts(layouts); change.set_target_data_layouts(layouts);
@ -809,12 +816,7 @@ pub fn ws_to_crate_graph(
workspaces: &[ProjectWorkspace], workspaces: &[ProjectWorkspace],
extra_env: &FxHashMap<String, String>, extra_env: &FxHashMap<String, String>,
mut load: impl FnMut(&AbsPath) -> Option<vfs::FileId>, mut load: impl FnMut(&AbsPath) -> Option<vfs::FileId>,
) -> ( ) -> (CrateGraph, Vec<ProcMacroPaths>, Vec<Result<Arc<str>, Arc<str>>>, Vec<Option<Version>>) {
CrateGraph,
Vec<FxHashMap<CrateId, Result<(Option<String>, AbsPathBuf), String>>>,
Vec<Result<Arc<str>, Arc<str>>>,
Vec<Option<Version>>,
) {
let mut crate_graph = CrateGraph::default(); let mut crate_graph = CrateGraph::default();
let mut proc_macro_paths = Vec::default(); let mut proc_macro_paths = Vec::default();
let mut layouts = Vec::default(); let mut layouts = Vec::default();

View file

@ -1,5 +1,5 @@
//! A set of high-level utility fixture methods to use in tests. //! A set of high-level utility fixture methods to use in tests.
use std::{iter, mem, ops::Not, str::FromStr, sync}; use std::{iter, mem, str::FromStr, sync};
use base_db::{ use base_db::{
CrateDisplayName, CrateGraph, CrateId, CrateName, CrateOrigin, Dependency, Env, FileChange, CrateDisplayName, CrateGraph, CrateId, CrateName, CrateOrigin, Dependency, Env, FileChange,
@ -11,7 +11,7 @@ use hir_expand::{
db::ExpandDatabase, db::ExpandDatabase,
files::FilePosition, files::FilePosition,
proc_macro::{ proc_macro::{
ProcMacro, ProcMacroExpander, ProcMacroExpansionError, ProcMacroKind, ProcMacros, ProcMacro, ProcMacroExpander, ProcMacroExpansionError, ProcMacroKind, ProcMacrosBuilder,
}, },
FileRange, FileRange,
}; };
@ -303,7 +303,7 @@ impl ChangeFixture {
} }
} }
let mut proc_macros = ProcMacros::default(); let mut proc_macros = ProcMacrosBuilder::default();
if !proc_macro_names.is_empty() { if !proc_macro_names.is_empty() {
let proc_lib_file = file_id; let proc_lib_file = file_id;
@ -354,7 +354,7 @@ impl ChangeFixture {
let mut change = ChangeWithProcMacros { let mut change = ChangeWithProcMacros {
source_change, source_change,
proc_macros: proc_macros.is_empty().not().then_some(proc_macros), proc_macros: Some(proc_macros.build()),
toolchains: Some(iter::repeat(toolchain).take(crate_graph.len()).collect()), toolchains: Some(iter::repeat(toolchain).take(crate_graph.len()).collect()),
target_data_layouts: Some( target_data_layouts: Some(
iter::repeat(target_data_layout).take(crate_graph.len()).collect(), iter::repeat(target_data_layout).take(crate_graph.len()).collect(),

View file

@ -1,5 +1,5 @@
<!--- <!---
lsp/ext.rs hash: f41950db4c7b3a5a lsp/ext.rs hash: e92e1f12229b0071
If you need to change the above hash to make the test pass, please check if you If you need to change the above hash to make the test pass, please check if you
need to adjust this doc as well and ping this issue: need to adjust this doc as well and ping this issue:
@ -789,14 +789,6 @@ Renders rust-analyzer's crate graph as an SVG image.
If `full` is `true`, the graph includes non-workspace crates (crates.io dependencies as well as sysroot crates). If `full` is `true`, the graph includes non-workspace crates (crates.io dependencies as well as sysroot crates).
## Shuffle Crate Graph
**Method:** `rust-analyzer/shuffleCrateGraph`
**Request:** `null`
Shuffles the crate IDs in the crate graph, for debugging purposes.
## Expand Macro ## Expand Macro
**Method:** `rust-analyzer/expandMacro` **Method:** `rust-analyzer/expandMacro`

View file

@ -136,11 +136,6 @@
"title": "Debug ItemTree", "title": "Debug ItemTree",
"category": "rust-analyzer (debug command)" "category": "rust-analyzer (debug command)"
}, },
{
"command": "rust-analyzer.shuffleCrateGraph",
"title": "Shuffle Crate Graph",
"category": "rust-analyzer (debug command)"
},
{ {
"command": "rust-analyzer.memoryUsage", "command": "rust-analyzer.memoryUsage",
"title": "Memory Usage (Clears Database)", "title": "Memory Usage (Clears Database)",

View file

@ -100,12 +100,6 @@ export function memoryUsage(ctx: CtxInit): Cmd {
}; };
} }
export function shuffleCrateGraph(ctx: CtxInit): Cmd {
return async () => {
return ctx.client.sendRequest(ra.shuffleCrateGraph);
};
}
export function triggerParameterHints(_: CtxInit): Cmd { export function triggerParameterHints(_: CtxInit): Cmd {
return async () => { return async () => {
const parameterHintsEnabled = vscode.workspace const parameterHintsEnabled = vscode.workspace

View file

@ -45,7 +45,6 @@ export const rebuildProcMacros = new lc.RequestType0<null, void>("rust-analyzer/
export const runFlycheck = new lc.NotificationType<{ export const runFlycheck = new lc.NotificationType<{
textDocument: lc.TextDocumentIdentifier | null; textDocument: lc.TextDocumentIdentifier | null;
}>("rust-analyzer/runFlycheck"); }>("rust-analyzer/runFlycheck");
export const shuffleCrateGraph = new lc.RequestType0<null, void>("rust-analyzer/shuffleCrateGraph");
export const syntaxTree = new lc.RequestType<SyntaxTreeParams, string, void>( export const syntaxTree = new lc.RequestType<SyntaxTreeParams, string, void>(
"rust-analyzer/syntaxTree", "rust-analyzer/syntaxTree",
); );

View file

@ -141,7 +141,6 @@ function createCommands(): Record<string, CommandFactory> {
analyzerStatus: { enabled: commands.analyzerStatus }, analyzerStatus: { enabled: commands.analyzerStatus },
memoryUsage: { enabled: commands.memoryUsage }, memoryUsage: { enabled: commands.memoryUsage },
shuffleCrateGraph: { enabled: commands.shuffleCrateGraph },
reloadWorkspace: { enabled: commands.reloadWorkspace }, reloadWorkspace: { enabled: commands.reloadWorkspace },
rebuildProcMacros: { enabled: commands.rebuildProcMacros }, rebuildProcMacros: { enabled: commands.rebuildProcMacros },
matchingBrace: { enabled: commands.matchingBrace }, matchingBrace: { enabled: commands.matchingBrace },