mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-11-16 01:38:13 +00:00
Merge #8463
8463: Support macros in pattern position r=jonas-schievink a=jonas-schievink This was fairly easy, because patterns are limited to bodies, so almost all changes were inside body lowering. Co-authored-by: Jonas Schievink <jonasschievink@gmail.com>
This commit is contained in:
commit
eccd0efedb
7 changed files with 88 additions and 10 deletions
|
@ -531,8 +531,9 @@ impl ExprCollector<'_> {
|
|||
}
|
||||
}
|
||||
ast::Expr::MacroCall(e) => {
|
||||
let macro_ptr = AstPtr::new(&e);
|
||||
let mut ids = vec![];
|
||||
self.collect_macro_call(e, syntax_ptr.clone(), true, |this, expansion| {
|
||||
self.collect_macro_call(e, macro_ptr, true, |this, expansion| {
|
||||
ids.push(match expansion {
|
||||
Some(it) => this.collect_expr(it),
|
||||
None => this.alloc_expr(Expr::Missing, syntax_ptr.clone()),
|
||||
|
@ -555,7 +556,7 @@ impl ExprCollector<'_> {
|
|||
fn collect_macro_call<F: FnMut(&mut Self, Option<T>), T: ast::AstNode>(
|
||||
&mut self,
|
||||
e: ast::MacroCall,
|
||||
syntax_ptr: AstPtr<ast::Expr>,
|
||||
syntax_ptr: AstPtr<ast::MacroCall>,
|
||||
is_error_recoverable: bool,
|
||||
mut collector: F,
|
||||
) {
|
||||
|
@ -643,10 +644,14 @@ impl ExprCollector<'_> {
|
|||
|
||||
// Note that macro could be expended to multiple statements
|
||||
if let Some(ast::Expr::MacroCall(m)) = stmt.expr() {
|
||||
let macro_ptr = AstPtr::new(&m);
|
||||
let syntax_ptr = AstPtr::new(&stmt.expr().unwrap());
|
||||
|
||||
self.collect_macro_call(m, syntax_ptr.clone(), false, |this, expansion| {
|
||||
match expansion {
|
||||
self.collect_macro_call(
|
||||
m,
|
||||
macro_ptr,
|
||||
false,
|
||||
|this, expansion| match expansion {
|
||||
Some(expansion) => {
|
||||
let statements: ast::MacroStmts = expansion;
|
||||
|
||||
|
@ -660,8 +665,8 @@ impl ExprCollector<'_> {
|
|||
let expr = this.alloc_expr(Expr::Missing, syntax_ptr.clone());
|
||||
this.statements_in_scope.push(Statement::Expr(expr));
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
);
|
||||
} else {
|
||||
let expr = self.collect_expr_opt(stmt.expr());
|
||||
self.statements_in_scope.push(Statement::Expr(expr));
|
||||
|
@ -848,8 +853,23 @@ impl ExprCollector<'_> {
|
|||
Pat::Missing
|
||||
}
|
||||
}
|
||||
ast::Pat::MacroPat(mac) => match mac.macro_call() {
|
||||
Some(call) => {
|
||||
let macro_ptr = AstPtr::new(&call);
|
||||
let mut pat = None;
|
||||
self.collect_macro_call(call, macro_ptr, true, |this, expanded_pat| {
|
||||
pat = Some(this.collect_pat_opt(expanded_pat));
|
||||
});
|
||||
|
||||
match pat {
|
||||
Some(pat) => return pat,
|
||||
None => Pat::Missing,
|
||||
}
|
||||
}
|
||||
None => Pat::Missing,
|
||||
},
|
||||
// FIXME: implement
|
||||
ast::Pat::RangePat(_) | ast::Pat::MacroPat(_) => Pat::Missing,
|
||||
ast::Pat::RangePat(_) => Pat::Missing,
|
||||
};
|
||||
let ptr = AstPtr::new(&pat);
|
||||
self.alloc_pat(pattern, Either::Left(ptr))
|
||||
|
|
|
@ -99,6 +99,11 @@ impl ItemTree {
|
|||
// items.
|
||||
ctx.lower_macro_stmts(stmts)
|
||||
},
|
||||
ast::Pat(_pat) => {
|
||||
// FIXME: This occurs because macros in pattern position are treated as inner
|
||||
// items and expanded during block DefMap computation
|
||||
return Default::default();
|
||||
},
|
||||
ast::Expr(e) => {
|
||||
// Macros can expand to expressions. We return an empty item tree in this case, but
|
||||
// still need to collect inner items.
|
||||
|
|
|
@ -189,7 +189,7 @@ impl Ctx {
|
|||
block_stack.push(self.source_ast_id_map.ast_id(&block));
|
||||
},
|
||||
ast::Item(item) => {
|
||||
// FIXME: This triggers for macro calls in expression position
|
||||
// FIXME: This triggers for macro calls in expression/pattern/type position
|
||||
let mod_items = self.lower_mod_item(&item, true);
|
||||
let current_block = block_stack.last();
|
||||
if let (Some(mod_items), Some(block)) = (mod_items, current_block) {
|
||||
|
|
|
@ -439,6 +439,7 @@ fn to_fragment_kind(db: &dyn AstDatabase, id: MacroCallId) -> FragmentKind {
|
|||
match parent.kind() {
|
||||
MACRO_ITEMS | SOURCE_FILE => FragmentKind::Items,
|
||||
MACRO_STMTS => FragmentKind::Statements,
|
||||
MACRO_PAT => FragmentKind::Pattern,
|
||||
ITEM_LIST => FragmentKind::Items,
|
||||
LET_STMT => {
|
||||
// FIXME: Handle LHS Pattern
|
||||
|
|
|
@ -1065,11 +1065,11 @@ fn macro_in_arm() {
|
|||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
!0..2 '()': ()
|
||||
51..110 '{ ... }; }': ()
|
||||
61..62 'x': u32
|
||||
65..107 'match ... }': u32
|
||||
71..73 '()': ()
|
||||
84..91 'unit!()': ()
|
||||
95..100 '92u32': u32
|
||||
"#]],
|
||||
);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use expect_test::expect;
|
||||
|
||||
use super::{check_infer, check_infer_with_mismatches};
|
||||
use super::{check_infer, check_infer_with_mismatches, check_types};
|
||||
|
||||
#[test]
|
||||
fn infer_pattern() {
|
||||
|
@ -825,3 +825,29 @@ fn foo(foo: Foo) {
|
|||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn macro_pat() {
|
||||
check_types(
|
||||
r#"
|
||||
macro_rules! pat {
|
||||
($name:ident) => { Enum::Variant1($name) }
|
||||
}
|
||||
|
||||
enum Enum {
|
||||
Variant1(u8),
|
||||
Variant2,
|
||||
}
|
||||
|
||||
fn f(e: Enum) {
|
||||
match e {
|
||||
pat!(bind) => {
|
||||
bind;
|
||||
//^^^^ u8
|
||||
}
|
||||
Enum::Variant2 => {}
|
||||
}
|
||||
}
|
||||
"#,
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1185,6 +1185,32 @@ pub mod theitem {
|
|||
pub fn gimme() -> theitem::TheItem {
|
||||
theitem::TheItem
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn goto_ident_from_pat_macro() {
|
||||
check(
|
||||
r#"
|
||||
macro_rules! pat {
|
||||
($name:ident) => { Enum::Variant1($name) }
|
||||
}
|
||||
|
||||
enum Enum {
|
||||
Variant1(u8),
|
||||
Variant2,
|
||||
}
|
||||
|
||||
fn f(e: Enum) {
|
||||
match e {
|
||||
pat!(bind) => {
|
||||
//^^^^
|
||||
bind$0
|
||||
}
|
||||
Enum::Variant2 => {}
|
||||
}
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue