mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-26 13:03:31 +00:00
Render matched macro arm on hover of macro calls
This commit is contained in:
parent
062e1b9b81
commit
6bfdd38c69
11 changed files with 133 additions and 65 deletions
|
@ -313,9 +313,10 @@ fn parse_macro_expansion(
|
||||||
let loc = db.lookup_intern_macro_call(macro_file.macro_call_id);
|
let loc = db.lookup_intern_macro_call(macro_file.macro_call_id);
|
||||||
let edition = loc.def.edition;
|
let edition = loc.def.edition;
|
||||||
let expand_to = loc.expand_to();
|
let expand_to = loc.expand_to();
|
||||||
let mbe::ValueResult { value: tt, err } = macro_expand(db, macro_file.macro_call_id, loc);
|
let mbe::ValueResult { value: (tt, matched_arm), err } =
|
||||||
|
macro_expand(db, macro_file.macro_call_id, loc);
|
||||||
|
|
||||||
let (parse, rev_token_map) = token_tree_to_syntax_node(
|
let (parse, mut rev_token_map) = token_tree_to_syntax_node(
|
||||||
match &tt {
|
match &tt {
|
||||||
CowArc::Arc(it) => it,
|
CowArc::Arc(it) => it,
|
||||||
CowArc::Owned(it) => it,
|
CowArc::Owned(it) => it,
|
||||||
|
@ -323,6 +324,7 @@ fn parse_macro_expansion(
|
||||||
expand_to,
|
expand_to,
|
||||||
edition,
|
edition,
|
||||||
);
|
);
|
||||||
|
rev_token_map.matched_arm = matched_arm;
|
||||||
|
|
||||||
ExpandResult { value: (parse, Arc::new(rev_token_map)), err }
|
ExpandResult { value: (parse, Arc::new(rev_token_map)), err }
|
||||||
}
|
}
|
||||||
|
@ -544,11 +546,13 @@ fn macro_expand(
|
||||||
db: &dyn ExpandDatabase,
|
db: &dyn ExpandDatabase,
|
||||||
macro_call_id: MacroCallId,
|
macro_call_id: MacroCallId,
|
||||||
loc: MacroCallLoc,
|
loc: MacroCallLoc,
|
||||||
) -> ExpandResult<CowArc<tt::Subtree>> {
|
) -> ExpandResult<(CowArc<tt::Subtree>, Option<u32>)> {
|
||||||
let _p = tracing::span!(tracing::Level::INFO, "macro_expand").entered();
|
let _p = tracing::span!(tracing::Level::INFO, "macro_expand").entered();
|
||||||
|
|
||||||
let (ExpandResult { value: tt, err }, span) = match loc.def.kind {
|
let (ExpandResult { value: (tt, matched_arm), err }, span) = 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).zip_val(None)
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
let (macro_arg, undo_info, span) =
|
let (macro_arg, undo_info, span) =
|
||||||
db.macro_arg_considering_derives(macro_call_id, &loc.kind);
|
db.macro_arg_considering_derives(macro_call_id, &loc.kind);
|
||||||
|
@ -560,10 +564,10 @@ fn macro_expand(
|
||||||
.decl_macro_expander(loc.def.krate, id)
|
.decl_macro_expander(loc.def.krate, id)
|
||||||
.expand(db, arg.clone(), macro_call_id, span),
|
.expand(db, arg.clone(), macro_call_id, span),
|
||||||
MacroDefKind::BuiltIn(it, _) => {
|
MacroDefKind::BuiltIn(it, _) => {
|
||||||
it.expand(db, macro_call_id, arg, span).map_err(Into::into)
|
it.expand(db, macro_call_id, arg, span).map_err(Into::into).zip_val(None)
|
||||||
}
|
}
|
||||||
MacroDefKind::BuiltInDerive(it, _) => {
|
MacroDefKind::BuiltInDerive(it, _) => {
|
||||||
it.expand(db, macro_call_id, arg, span).map_err(Into::into)
|
it.expand(db, macro_call_id, arg, span).map_err(Into::into).zip_val(None)
|
||||||
}
|
}
|
||||||
MacroDefKind::BuiltInEager(it, _) => {
|
MacroDefKind::BuiltInEager(it, _) => {
|
||||||
// This might look a bit odd, but we do not expand the inputs to eager macros here.
|
// This might look a bit odd, but we do not expand the inputs to eager macros here.
|
||||||
|
@ -574,7 +578,8 @@ 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::ok(CowArc::Arc(macro_arg.clone()));
|
return ExpandResult::ok(CowArc::Arc(macro_arg.clone()))
|
||||||
|
.zip_val(None);
|
||||||
}
|
}
|
||||||
MacroCallKind::FnLike { eager: Some(eager), .. } => Some(&**eager),
|
MacroCallKind::FnLike { eager: Some(eager), .. } => Some(&**eager),
|
||||||
_ => None,
|
_ => None,
|
||||||
|
@ -586,12 +591,12 @@ fn macro_expand(
|
||||||
// FIXME: We should report both errors!
|
// FIXME: We should report both errors!
|
||||||
res.err = error.clone().or(res.err);
|
res.err = error.clone().or(res.err);
|
||||||
}
|
}
|
||||||
res
|
res.zip_val(None)
|
||||||
}
|
}
|
||||||
MacroDefKind::BuiltInAttr(it, _) => {
|
MacroDefKind::BuiltInAttr(it, _) => {
|
||||||
let mut res = it.expand(db, macro_call_id, arg, span);
|
let mut res = it.expand(db, macro_call_id, arg, span);
|
||||||
fixup::reverse_fixups(&mut res.value, &undo_info);
|
fixup::reverse_fixups(&mut res.value, &undo_info);
|
||||||
res
|
res.zip_val(None)
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
|
@ -603,16 +608,18 @@ fn macro_expand(
|
||||||
if !loc.def.is_include() {
|
if !loc.def.is_include() {
|
||||||
// Set a hard limit for the expanded tt
|
// Set a hard limit for the expanded tt
|
||||||
if let Err(value) = check_tt_count(&tt) {
|
if let Err(value) = check_tt_count(&tt) {
|
||||||
return value.map(|()| {
|
return value
|
||||||
CowArc::Owned(tt::Subtree {
|
.map(|()| {
|
||||||
delimiter: tt::Delimiter::invisible_spanned(span),
|
CowArc::Owned(tt::Subtree {
|
||||||
token_trees: Box::new([]),
|
delimiter: tt::Delimiter::invisible_spanned(span),
|
||||||
|
token_trees: Box::new([]),
|
||||||
|
})
|
||||||
})
|
})
|
||||||
});
|
.zip_val(matched_arm);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ExpandResult { value: CowArc::Owned(tt), err }
|
ExpandResult { value: (CowArc::Owned(tt), matched_arm), err }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn proc_macro_span(db: &dyn ExpandDatabase, ast: AstId<ast::Fn>) -> Span {
|
fn proc_macro_span(db: &dyn ExpandDatabase, ast: AstId<ast::Fn>) -> Span {
|
||||||
|
|
|
@ -3,6 +3,7 @@ use std::sync::OnceLock;
|
||||||
|
|
||||||
use base_db::{CrateId, VersionReq};
|
use base_db::{CrateId, VersionReq};
|
||||||
use span::{Edition, MacroCallId, Span, SyntaxContextId};
|
use span::{Edition, MacroCallId, Span, SyntaxContextId};
|
||||||
|
use stdx::TupleExt;
|
||||||
use syntax::{ast, AstNode};
|
use syntax::{ast, AstNode};
|
||||||
use triomphe::Arc;
|
use triomphe::Arc;
|
||||||
|
|
||||||
|
@ -30,7 +31,7 @@ impl DeclarativeMacroExpander {
|
||||||
tt: tt::Subtree,
|
tt: tt::Subtree,
|
||||||
call_id: MacroCallId,
|
call_id: MacroCallId,
|
||||||
span: Span,
|
span: Span,
|
||||||
) -> ExpandResult<tt::Subtree> {
|
) -> ExpandResult<(tt::Subtree, Option<u32>)> {
|
||||||
let loc = db.lookup_intern_macro_call(call_id);
|
let loc = db.lookup_intern_macro_call(call_id);
|
||||||
let toolchain = db.toolchain(loc.def.krate);
|
let toolchain = db.toolchain(loc.def.krate);
|
||||||
let new_meta_vars = toolchain.as_ref().map_or(false, |version| {
|
let new_meta_vars = toolchain.as_ref().map_or(false, |version| {
|
||||||
|
@ -46,7 +47,7 @@ impl DeclarativeMacroExpander {
|
||||||
});
|
});
|
||||||
match self.mac.err() {
|
match self.mac.err() {
|
||||||
Some(_) => ExpandResult::new(
|
Some(_) => ExpandResult::new(
|
||||||
tt::Subtree::empty(tt::DelimSpan { open: span, close: span }),
|
(tt::Subtree::empty(tt::DelimSpan { open: span, close: span }), None),
|
||||||
ExpandError::MacroDefinition,
|
ExpandError::MacroDefinition,
|
||||||
),
|
),
|
||||||
None => self
|
None => self
|
||||||
|
@ -90,6 +91,7 @@ impl DeclarativeMacroExpander {
|
||||||
None => self
|
None => self
|
||||||
.mac
|
.mac
|
||||||
.expand(&tt, |_| (), new_meta_vars, call_site, def_site_edition)
|
.expand(&tt, |_| (), new_meta_vars, call_site, def_site_edition)
|
||||||
|
.map(TupleExt::head)
|
||||||
.map_err(Into::into),
|
.map_err(Into::into),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1246,6 +1246,17 @@ impl<'db> SemanticsImpl<'db> {
|
||||||
.map_or(false, |m| matches!(m.id, MacroId::ProcMacroId(..)))
|
.map_or(false, |m| matches!(m.id, MacroId::ProcMacroId(..)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn resolve_macro_call_arm(&self, macro_call: &ast::MacroCall) -> Option<u32> {
|
||||||
|
let sa = self.analyze(macro_call.syntax())?;
|
||||||
|
self.db
|
||||||
|
.parse_macro_expansion(
|
||||||
|
sa.expand(self.db, self.wrap_node_infile(macro_call.clone()).as_ref())?,
|
||||||
|
)
|
||||||
|
.value
|
||||||
|
.1
|
||||||
|
.matched_arm
|
||||||
|
}
|
||||||
|
|
||||||
pub fn is_unsafe_macro_call(&self, macro_call: &ast::MacroCall) -> bool {
|
pub fn is_unsafe_macro_call(&self, macro_call: &ast::MacroCall) -> bool {
|
||||||
let sa = match self.analyze(macro_call.syntax()) {
|
let sa = match self.analyze(macro_call.syntax()) {
|
||||||
Some(it) => it,
|
Some(it) => it,
|
||||||
|
|
|
@ -14,7 +14,7 @@ use ide_db::{
|
||||||
helpers::pick_best_token,
|
helpers::pick_best_token,
|
||||||
FxIndexSet, RootDatabase,
|
FxIndexSet, RootDatabase,
|
||||||
};
|
};
|
||||||
use itertools::Itertools;
|
use itertools::{multizip, Itertools};
|
||||||
use syntax::{ast, match_ast, AstNode, AstToken, SyntaxKind::*, SyntaxNode, T};
|
use syntax::{ast, match_ast, AstNode, AstToken, SyntaxKind::*, SyntaxNode, T};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -149,7 +149,7 @@ fn hover_simple(
|
||||||
if let Some(doc_comment) = token_as_doc_comment(&original_token) {
|
if let Some(doc_comment) = token_as_doc_comment(&original_token) {
|
||||||
cov_mark::hit!(no_highlight_on_comment_hover);
|
cov_mark::hit!(no_highlight_on_comment_hover);
|
||||||
return doc_comment.get_definition_with_descend_at(sema, offset, |def, node, range| {
|
return doc_comment.get_definition_with_descend_at(sema, offset, |def, node, range| {
|
||||||
let res = hover_for_definition(sema, file_id, def, &node, config);
|
let res = hover_for_definition(sema, file_id, def, &node, None, config);
|
||||||
Some(RangeInfo::new(range, res))
|
Some(RangeInfo::new(range, res))
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -162,6 +162,7 @@ fn hover_simple(
|
||||||
file_id,
|
file_id,
|
||||||
Definition::from(resolution?),
|
Definition::from(resolution?),
|
||||||
&original_token.parent()?,
|
&original_token.parent()?,
|
||||||
|
None,
|
||||||
config,
|
config,
|
||||||
);
|
);
|
||||||
return Some(RangeInfo::new(range, res));
|
return Some(RangeInfo::new(range, res));
|
||||||
|
@ -196,6 +197,29 @@ fn hover_simple(
|
||||||
descended()
|
descended()
|
||||||
.filter_map(|token| {
|
.filter_map(|token| {
|
||||||
let node = token.parent()?;
|
let node = token.parent()?;
|
||||||
|
|
||||||
|
// special case macro calls, we wanna render the invoked arm index
|
||||||
|
if let Some(name) = ast::NameRef::cast(node.clone()) {
|
||||||
|
if let Some(path_seg) =
|
||||||
|
name.syntax().parent().and_then(ast::PathSegment::cast)
|
||||||
|
{
|
||||||
|
if let Some(macro_call) = path_seg
|
||||||
|
.parent_path()
|
||||||
|
.syntax()
|
||||||
|
.parent()
|
||||||
|
.and_then(ast::MacroCall::cast)
|
||||||
|
{
|
||||||
|
if let Some(macro_) = sema.resolve_macro_call(¯o_call) {
|
||||||
|
return Some(vec![(
|
||||||
|
Definition::Macro(macro_),
|
||||||
|
sema.resolve_macro_call_arm(¯o_call),
|
||||||
|
node,
|
||||||
|
)]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
match IdentClass::classify_node(sema, &node)? {
|
match IdentClass::classify_node(sema, &node)? {
|
||||||
// It's better for us to fall back to the keyword hover here,
|
// It's better for us to fall back to the keyword hover here,
|
||||||
// rendering poll is very confusing
|
// rendering poll is very confusing
|
||||||
|
@ -204,20 +228,19 @@ fn hover_simple(
|
||||||
IdentClass::NameRefClass(NameRefClass::ExternCrateShorthand {
|
IdentClass::NameRefClass(NameRefClass::ExternCrateShorthand {
|
||||||
decl,
|
decl,
|
||||||
..
|
..
|
||||||
}) => Some(vec![(Definition::ExternCrateDecl(decl), node)]),
|
}) => Some(vec![(Definition::ExternCrateDecl(decl), None, node)]),
|
||||||
|
|
||||||
class => Some(
|
class => Some(
|
||||||
class
|
multizip((class.definitions(), iter::repeat(None), iter::repeat(node)))
|
||||||
.definitions()
|
|
||||||
.into_iter()
|
|
||||||
.zip(iter::repeat(node))
|
|
||||||
.collect::<Vec<_>>(),
|
.collect::<Vec<_>>(),
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.flatten()
|
.flatten()
|
||||||
.unique_by(|&(def, _)| def)
|
.unique_by(|&(def, _, _)| def)
|
||||||
.map(|(def, node)| hover_for_definition(sema, file_id, def, &node, config))
|
.map(|(def, macro_arm, node)| {
|
||||||
|
hover_for_definition(sema, file_id, def, &node, macro_arm, config)
|
||||||
|
})
|
||||||
.reduce(|mut acc: HoverResult, HoverResult { markup, actions }| {
|
.reduce(|mut acc: HoverResult, HoverResult { markup, actions }| {
|
||||||
acc.actions.extend(actions);
|
acc.actions.extend(actions);
|
||||||
acc.markup = Markup::from(format!("{}\n---\n{markup}", acc.markup));
|
acc.markup = Markup::from(format!("{}\n---\n{markup}", acc.markup));
|
||||||
|
@ -374,6 +397,7 @@ pub(crate) fn hover_for_definition(
|
||||||
file_id: FileId,
|
file_id: FileId,
|
||||||
def: Definition,
|
def: Definition,
|
||||||
scope_node: &SyntaxNode,
|
scope_node: &SyntaxNode,
|
||||||
|
macro_arm: Option<u32>,
|
||||||
config: &HoverConfig,
|
config: &HoverConfig,
|
||||||
) -> HoverResult {
|
) -> HoverResult {
|
||||||
let famous_defs = match &def {
|
let famous_defs = match &def {
|
||||||
|
@ -398,7 +422,8 @@ pub(crate) fn hover_for_definition(
|
||||||
};
|
};
|
||||||
let notable_traits = def_ty.map(|ty| notable_traits(db, &ty)).unwrap_or_default();
|
let notable_traits = def_ty.map(|ty| notable_traits(db, &ty)).unwrap_or_default();
|
||||||
|
|
||||||
let markup = render::definition(sema.db, def, famous_defs.as_ref(), ¬able_traits, config);
|
let markup =
|
||||||
|
render::definition(sema.db, def, famous_defs.as_ref(), ¬able_traits, macro_arm, config);
|
||||||
HoverResult {
|
HoverResult {
|
||||||
markup: render::process_markup(sema.db, def, &markup, config),
|
markup: render::process_markup(sema.db, def, &markup, config),
|
||||||
actions: [
|
actions: [
|
||||||
|
|
|
@ -403,6 +403,7 @@ pub(super) fn definition(
|
||||||
def: Definition,
|
def: Definition,
|
||||||
famous_defs: Option<&FamousDefs<'_, '_>>,
|
famous_defs: Option<&FamousDefs<'_, '_>>,
|
||||||
notable_traits: &[(Trait, Vec<(Option<Type>, Name)>)],
|
notable_traits: &[(Trait, Vec<(Option<Type>, Name)>)],
|
||||||
|
macro_arm: Option<u32>,
|
||||||
config: &HoverConfig,
|
config: &HoverConfig,
|
||||||
) -> Markup {
|
) -> Markup {
|
||||||
let mod_path = definition_mod_path(db, &def);
|
let mod_path = definition_mod_path(db, &def);
|
||||||
|
@ -413,6 +414,13 @@ pub(super) fn definition(
|
||||||
Definition::Adt(Adt::Struct(struct_)) => {
|
Definition::Adt(Adt::Struct(struct_)) => {
|
||||||
struct_.display_limited(db, config.max_struct_field_count).to_string()
|
struct_.display_limited(db, config.max_struct_field_count).to_string()
|
||||||
}
|
}
|
||||||
|
Definition::Macro(it) => {
|
||||||
|
let mut label = it.display(db).to_string();
|
||||||
|
if let Some(macro_arm) = macro_arm {
|
||||||
|
format_to!(label, " // matched arm #{}", macro_arm);
|
||||||
|
}
|
||||||
|
label
|
||||||
|
}
|
||||||
_ => def.label(db),
|
_ => def.label(db),
|
||||||
};
|
};
|
||||||
let docs = def.docs(db, famous_defs);
|
let docs = def.docs(db, famous_defs);
|
||||||
|
|
|
@ -1560,21 +1560,21 @@ fn y() {
|
||||||
fn test_hover_macro_invocation() {
|
fn test_hover_macro_invocation() {
|
||||||
check(
|
check(
|
||||||
r#"
|
r#"
|
||||||
macro_rules! foo { () => {} }
|
macro_rules! foo { (a) => {}; () => {} }
|
||||||
|
|
||||||
fn f() { fo$0o!(); }
|
fn f() { fo$0o!(); }
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
*foo*
|
*foo*
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
test
|
test
|
||||||
```
|
```
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
macro_rules! foo
|
macro_rules! foo // matched arm #1
|
||||||
```
|
```
|
||||||
"#]],
|
"#]],
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1590,22 +1590,22 @@ macro foo() {}
|
||||||
fn f() { fo$0o!(); }
|
fn f() { fo$0o!(); }
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
*foo*
|
*foo*
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
test
|
test
|
||||||
```
|
```
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
macro foo
|
macro foo // matched arm #0
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
foo bar
|
foo bar
|
||||||
|
|
||||||
foo bar baz
|
foo bar baz
|
||||||
"#]],
|
"#]],
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -188,7 +188,14 @@ impl StaticIndex<'_> {
|
||||||
} else {
|
} else {
|
||||||
let it = self.tokens.insert(TokenStaticData {
|
let it = self.tokens.insert(TokenStaticData {
|
||||||
documentation: documentation_for_definition(&sema, def, &node),
|
documentation: documentation_for_definition(&sema, def, &node),
|
||||||
hover: Some(hover_for_definition(&sema, file_id, def, &node, &hover_config)),
|
hover: Some(hover_for_definition(
|
||||||
|
&sema,
|
||||||
|
file_id,
|
||||||
|
def,
|
||||||
|
&node,
|
||||||
|
None,
|
||||||
|
&hover_config,
|
||||||
|
)),
|
||||||
definition: def.try_to_nav(self.db).map(UpmappingResult::call_site).map(|it| {
|
definition: def.try_to_nav(self.db).map(UpmappingResult::call_site).map(|it| {
|
||||||
FileRange { file_id: it.file_id, range: it.focus_or_full_range() }
|
FileRange { file_id: it.file_id, range: it.focus_or_full_range() }
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -48,7 +48,7 @@ fn benchmark_expand_macro_rules() {
|
||||||
.map(|(id, tt)| {
|
.map(|(id, tt)| {
|
||||||
let res = rules[&id].expand(&tt, |_| (), true, DUMMY, Edition::CURRENT);
|
let res = rules[&id].expand(&tt, |_| (), true, DUMMY, Edition::CURRENT);
|
||||||
assert!(res.err.is_none());
|
assert!(res.err.is_none());
|
||||||
res.value.token_trees.len()
|
res.value.0.token_trees.len()
|
||||||
})
|
})
|
||||||
.sum()
|
.sum()
|
||||||
};
|
};
|
||||||
|
|
|
@ -18,9 +18,9 @@ pub(crate) fn expand_rules(
|
||||||
new_meta_vars: bool,
|
new_meta_vars: bool,
|
||||||
call_site: Span,
|
call_site: Span,
|
||||||
def_site_edition: Edition,
|
def_site_edition: Edition,
|
||||||
) -> ExpandResult<tt::Subtree<Span>> {
|
) -> ExpandResult<(tt::Subtree<Span>, Option<u32>)> {
|
||||||
let mut match_: Option<(matcher::Match, &crate::Rule)> = None;
|
let mut match_: Option<(matcher::Match, &crate::Rule, usize)> = None;
|
||||||
for rule in rules {
|
for (idx, rule) in rules.iter().enumerate() {
|
||||||
let new_match = matcher::match_(&rule.lhs, input, def_site_edition);
|
let new_match = matcher::match_(&rule.lhs, input, def_site_edition);
|
||||||
|
|
||||||
if new_match.err.is_none() {
|
if new_match.err.is_none() {
|
||||||
|
@ -35,31 +35,34 @@ pub(crate) fn expand_rules(
|
||||||
call_site,
|
call_site,
|
||||||
);
|
);
|
||||||
if transcribe_err.is_none() {
|
if transcribe_err.is_none() {
|
||||||
return ExpandResult::ok(value);
|
return ExpandResult::ok((value, Some(idx as u32)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Use the rule if we matched more tokens, or bound variables count
|
// Use the rule if we matched more tokens, or bound variables count
|
||||||
if let Some((prev_match, _)) = &match_ {
|
if let Some((prev_match, _, _)) = &match_ {
|
||||||
if (new_match.unmatched_tts, -(new_match.bound_count as i32))
|
if (new_match.unmatched_tts, -(new_match.bound_count as i32))
|
||||||
< (prev_match.unmatched_tts, -(prev_match.bound_count as i32))
|
< (prev_match.unmatched_tts, -(prev_match.bound_count as i32))
|
||||||
{
|
{
|
||||||
match_ = Some((new_match, rule));
|
match_ = Some((new_match, rule, idx));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
match_ = Some((new_match, rule));
|
match_ = Some((new_match, rule, idx));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some((match_, rule)) = match_ {
|
if let Some((match_, rule, idx)) = match_ {
|
||||||
// if we got here, there was no match without errors
|
// if we got here, there was no match without errors
|
||||||
let ExpandResult { value, err: transcribe_err } =
|
let ExpandResult { value, err: transcribe_err } =
|
||||||
transcriber::transcribe(&rule.rhs, &match_.bindings, marker, new_meta_vars, call_site);
|
transcriber::transcribe(&rule.rhs, &match_.bindings, marker, new_meta_vars, call_site);
|
||||||
ExpandResult { value, err: match_.err.or(transcribe_err) }
|
ExpandResult { value: (value, Some(idx as u32)), err: match_.err.or(transcribe_err) }
|
||||||
} else {
|
} else {
|
||||||
ExpandResult::new(
|
ExpandResult::new(
|
||||||
tt::Subtree {
|
(
|
||||||
delimiter: tt::Delimiter::invisible_spanned(call_site),
|
tt::Subtree {
|
||||||
token_trees: Box::new([]),
|
delimiter: tt::Delimiter::invisible_spanned(call_site),
|
||||||
},
|
token_trees: Box::default(),
|
||||||
|
},
|
||||||
|
None,
|
||||||
|
),
|
||||||
ExpandError::NoMatchingRule,
|
ExpandError::NoMatchingRule,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -251,7 +251,7 @@ impl DeclarativeMacro {
|
||||||
new_meta_vars: bool,
|
new_meta_vars: bool,
|
||||||
call_site: Span,
|
call_site: Span,
|
||||||
def_site_edition: Edition,
|
def_site_edition: Edition,
|
||||||
) -> ExpandResult<tt::Subtree<Span>> {
|
) -> ExpandResult<(tt::Subtree<Span>, Option<u32>)> {
|
||||||
expander::expand_rules(&self.rules, tt, marker, new_meta_vars, call_site, def_site_edition)
|
expander::expand_rules(&self.rules, tt, marker, new_meta_vars, call_site, def_site_edition)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -330,6 +330,10 @@ impl<T, E> ValueResult<T, E> {
|
||||||
Self { value: Default::default(), err: Some(err) }
|
Self { value: Default::default(), err: Some(err) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn zip_val<U>(self, other: U) -> ValueResult<(T, U), E> {
|
||||||
|
ValueResult { value: (self.value, other), err: self.err }
|
||||||
|
}
|
||||||
|
|
||||||
pub fn map<U>(self, f: impl FnOnce(T) -> U) -> ValueResult<U, E> {
|
pub fn map<U>(self, f: impl FnOnce(T) -> U) -> ValueResult<U, E> {
|
||||||
ValueResult { value: f(self.value), err: self.err }
|
ValueResult { value: f(self.value), err: self.err }
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,7 @@ use crate::{
|
||||||
#[derive(Debug, PartialEq, Eq, Clone, Hash)]
|
#[derive(Debug, PartialEq, Eq, Clone, Hash)]
|
||||||
pub struct SpanMap<S> {
|
pub struct SpanMap<S> {
|
||||||
spans: Vec<(TextSize, SpanData<S>)>,
|
spans: Vec<(TextSize, SpanData<S>)>,
|
||||||
|
pub matched_arm: Option<u32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S> SpanMap<S>
|
impl<S> SpanMap<S>
|
||||||
|
@ -23,7 +24,7 @@ where
|
||||||
{
|
{
|
||||||
/// Creates a new empty [`SpanMap`].
|
/// Creates a new empty [`SpanMap`].
|
||||||
pub fn empty() -> Self {
|
pub fn empty() -> Self {
|
||||||
Self { spans: Vec::new() }
|
Self { spans: Vec::new(), matched_arm: None }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Finalizes the [`SpanMap`], shrinking its backing storage and validating that the offsets are
|
/// Finalizes the [`SpanMap`], shrinking its backing storage and validating that the offsets are
|
||||||
|
|
Loading…
Reference in a new issue