Drop eager macro parse errors, they can't crop up

This commit is contained in:
Lukas Wirth 2024-03-15 11:45:51 +01:00
parent 3b1ad2379d
commit 08327e0e5d
2 changed files with 13 additions and 61 deletions

View File

@ -3,7 +3,7 @@
use base_db::{salsa, CrateId, FileId, SourceDatabase}; use base_db::{salsa, CrateId, FileId, SourceDatabase};
use either::Either; use either::Either;
use limit::Limit; use limit::Limit;
use mbe::{syntax_node_to_token_tree, ValueResult}; use mbe::syntax_node_to_token_tree;
use rustc_hash::FxHashSet; use rustc_hash::FxHashSet;
use span::{AstIdMap, Span, SyntaxContextData, SyntaxContextId}; use span::{AstIdMap, Span, SyntaxContextData, SyntaxContextId};
use syntax::{ast, AstNode, Parse, SyntaxElement, SyntaxError, SyntaxNode, SyntaxToken, T}; use syntax::{ast, AstNode, Parse, SyntaxElement, SyntaxError, SyntaxNode, SyntaxToken, T};
@ -98,10 +98,7 @@ fn parse_macro_expansion(
/// Lowers syntactic macro call to a token tree representation. That's a firewall /// Lowers syntactic macro call to a token tree representation. That's a firewall
/// query, only typing in the macro call itself changes the returned /// query, only typing in the macro call itself changes the returned
/// subtree. /// subtree.
fn macro_arg( fn macro_arg(&self, id: MacroCallId) -> (Arc<tt::Subtree>, SyntaxFixupUndoInfo);
&self,
id: MacroCallId,
) -> ValueResult<(Arc<tt::Subtree>, SyntaxFixupUndoInfo), Arc<Box<[SyntaxError]>>>;
/// Fetches the expander for this macro. /// Fetches the expander for this macro.
#[salsa::transparent] #[salsa::transparent]
#[salsa::invoke(TokenExpander::macro_expander)] #[salsa::invoke(TokenExpander::macro_expander)]
@ -341,10 +338,7 @@ pub(crate) fn parse_with_map(
// FIXME: for derive attributes, this will return separate copies of the same structures! Though // FIXME: for derive attributes, this will return separate copies of the same structures! Though
// they may differ in spans due to differing call sites... // they may differ in spans due to differing call sites...
fn macro_arg( fn macro_arg(db: &dyn ExpandDatabase, id: MacroCallId) -> (Arc<tt::Subtree>, SyntaxFixupUndoInfo) {
db: &dyn ExpandDatabase,
id: MacroCallId,
) -> ValueResult<(Arc<tt::Subtree>, SyntaxFixupUndoInfo), Arc<Box<[SyntaxError]>>> {
let loc = db.lookup_intern_macro_call(id); let loc = db.lookup_intern_macro_call(id);
if let MacroCallLoc { if let MacroCallLoc {
@ -353,7 +347,7 @@ fn macro_arg(
.. ..
} = &loc } = &loc
{ {
return ValueResult::ok((eager.arg.clone(), SyntaxFixupUndoInfo::NONE)); return (eager.arg.clone(), SyntaxFixupUndoInfo::NONE);
} }
let (parse, map) = parse_with_map(db, loc.kind.file_id()); let (parse, map) = parse_with_map(db, loc.kind.file_id());
@ -376,15 +370,8 @@ fn macro_arg(
}; };
let node = &ast_id.to_ptr(db).to_node(&root); let node = &ast_id.to_ptr(db).to_node(&root);
let offset = node.syntax().text_range().start();
let Some(tt) = node.token_tree() else { let Some(tt) = node.token_tree() else {
return ValueResult::new( return dummy_tt(tt::DelimiterKind::Invisible);
dummy_tt(tt::DelimiterKind::Invisible),
Arc::new(Box::new([SyntaxError::new_at_offset(
"missing token tree".to_owned(),
offset,
)])),
);
}; };
let first = tt.left_delimiter_token().map(|it| it.kind()).unwrap_or(T!['(']); let first = tt.left_delimiter_token().map(|it| it.kind()).unwrap_or(T!['(']);
let last = tt.right_delimiter_token().map(|it| it.kind()).unwrap_or(T![.]); let last = tt.right_delimiter_token().map(|it| it.kind()).unwrap_or(T![.]);
@ -409,13 +396,7 @@ fn macro_arg(
T!['{'] => tt::DelimiterKind::Brace, T!['{'] => tt::DelimiterKind::Brace,
_ => tt::DelimiterKind::Invisible, _ => tt::DelimiterKind::Invisible,
}; };
return ValueResult::new( return dummy_tt(kind);
dummy_tt(kind),
Arc::new(Box::new([SyntaxError::new_at_offset(
"mismatched delimiters".to_owned(),
offset,
)])),
);
} }
let mut tt = mbe::syntax_node_to_token_tree(tt.syntax(), map.as_ref(), loc.call_site); let mut tt = mbe::syntax_node_to_token_tree(tt.syntax(), map.as_ref(), loc.call_site);
@ -423,19 +404,7 @@ fn macro_arg(
// proc macros expect their inputs without parentheses, MBEs expect it with them included // proc macros expect their inputs without parentheses, MBEs expect it with them included
tt.delimiter.kind = tt::DelimiterKind::Invisible; tt.delimiter.kind = tt::DelimiterKind::Invisible;
} }
let val = (Arc::new(tt), SyntaxFixupUndoInfo::NONE); return (Arc::new(tt), SyntaxFixupUndoInfo::NONE);
return if matches!(loc.def.kind, MacroDefKind::BuiltInEager(..)) {
match parse.errors() {
errors if errors.is_empty() => ValueResult::ok(val),
errors => ValueResult::new(
val,
// Box::<[_]>::from(res.errors()), not stable yet
Arc::new(errors.to_vec().into_boxed_slice()),
),
}
} else {
ValueResult::ok(val)
};
} }
MacroCallKind::Derive { ast_id, derive_attr_index, .. } => { MacroCallKind::Derive { ast_id, derive_attr_index, .. } => {
let node = ast_id.to_ptr(db).to_node(&root); let node = ast_id.to_ptr(db).to_node(&root);
@ -475,7 +444,7 @@ fn macro_arg(
tt.delimiter.kind = tt::DelimiterKind::Invisible; tt.delimiter.kind = tt::DelimiterKind::Invisible;
} }
ValueResult::ok((Arc::new(tt), undo_info)) (Arc::new(tt), undo_info)
} }
// FIXME: Censoring info should be calculated by the caller! Namely by name resolution // FIXME: Censoring info should be calculated by the caller! Namely by name resolution
@ -538,17 +507,7 @@ fn macro_expand(
let ExpandResult { value: tt, err } = match loc.def.kind { let ExpandResult { value: tt, err } = match loc.def.kind {
MacroDefKind::ProcMacro(..) => return db.expand_proc_macro(macro_call_id).map(CowArc::Arc), MacroDefKind::ProcMacro(..) => return db.expand_proc_macro(macro_call_id).map(CowArc::Arc),
_ => { _ => {
let ValueResult { value: (macro_arg, undo_info), err } = db.macro_arg(macro_call_id); let (macro_arg, undo_info) = db.macro_arg(macro_call_id);
let format_parse_err = |err: Arc<Box<[SyntaxError]>>| {
let mut buf = String::new();
for err in &**err {
use std::fmt::Write;
_ = write!(buf, "{}, ", err);
}
buf.pop();
buf.pop();
ExpandError::other(buf)
};
let arg = &*macro_arg; let arg = &*macro_arg;
let res = match loc.def.kind { let res = match loc.def.kind {
@ -570,10 +529,7 @@ fn macro_expand(
// As such we just return the input subtree here. // As such we just return the input subtree here.
let eager = match &loc.kind { let eager = match &loc.kind {
MacroCallKind::FnLike { eager: None, .. } => { MacroCallKind::FnLike { eager: None, .. } => {
return ExpandResult { return ExpandResult::ok(CowArc::Arc(macro_arg.clone()));
value: CowArc::Arc(macro_arg.clone()),
err: err.map(format_parse_err),
};
} }
MacroCallKind::FnLike { eager: Some(eager), .. } => Some(&**eager), MacroCallKind::FnLike { eager: Some(eager), .. } => Some(&**eager),
_ => None, _ => None,
@ -594,11 +550,7 @@ fn macro_expand(
} }
_ => unreachable!(), _ => unreachable!(),
}; };
ExpandResult { ExpandResult { value: res.value, err: res.err }
value: res.value,
// if the arg had parse errors, show them instead of the expansion errors
err: err.map(format_parse_err).or(res.err),
}
} }
}; };
@ -631,7 +583,7 @@ fn proc_macro_span(db: &dyn ExpandDatabase, ast: AstId<ast::Fn>) -> Span {
fn expand_proc_macro(db: &dyn ExpandDatabase, id: MacroCallId) -> ExpandResult<Arc<tt::Subtree>> { fn expand_proc_macro(db: &dyn ExpandDatabase, id: MacroCallId) -> ExpandResult<Arc<tt::Subtree>> {
let loc = db.lookup_intern_macro_call(id); let loc = db.lookup_intern_macro_call(id);
let (macro_arg, undo_info) = db.macro_arg(id).value; let (macro_arg, undo_info) = db.macro_arg(id);
let (expander, ast) = match loc.def.kind { let (expander, ast) = match loc.def.kind {
MacroDefKind::ProcMacro(expander, _, ast) => (expander, ast), MacroDefKind::ProcMacro(expander, _, ast) => (expander, ast),

View File

@ -805,7 +805,7 @@ pub fn new(db: &dyn ExpandDatabase, macro_file: MacroFileId) -> ExpansionInfo {
let (parse, exp_map) = db.parse_macro_expansion(macro_file).value; let (parse, exp_map) = db.parse_macro_expansion(macro_file).value;
let expanded = InMacroFile { file_id: macro_file, value: parse.syntax_node() }; let expanded = InMacroFile { file_id: macro_file, value: parse.syntax_node() };
let (macro_arg, _) = db.macro_arg(macro_file.macro_call_id).value; let (macro_arg, _) = db.macro_arg(macro_file.macro_call_id);
let def = loc.def.ast_id().left().and_then(|id| { let def = loc.def.ast_id().left().and_then(|id| {
let def_tt = match id.to_node(db) { let def_tt = match id.to_node(db) {