mirror of
https://github.com/rust-lang/rust.git
synced 2025-02-23 12:23:22 +00:00
Support macros in pattern position
This commit is contained in:
parent
bd675c8a8b
commit
e2c1da36f5
@ -531,8 +531,9 @@ impl ExprCollector<'_> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
ast::Expr::MacroCall(e) => {
|
ast::Expr::MacroCall(e) => {
|
||||||
|
let macro_ptr = AstPtr::new(&e);
|
||||||
let mut ids = vec![];
|
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 {
|
ids.push(match expansion {
|
||||||
Some(it) => this.collect_expr(it),
|
Some(it) => this.collect_expr(it),
|
||||||
None => this.alloc_expr(Expr::Missing, syntax_ptr.clone()),
|
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>(
|
fn collect_macro_call<F: FnMut(&mut Self, Option<T>), T: ast::AstNode>(
|
||||||
&mut self,
|
&mut self,
|
||||||
e: ast::MacroCall,
|
e: ast::MacroCall,
|
||||||
syntax_ptr: AstPtr<ast::Expr>,
|
syntax_ptr: AstPtr<ast::MacroCall>,
|
||||||
is_error_recoverable: bool,
|
is_error_recoverable: bool,
|
||||||
mut collector: F,
|
mut collector: F,
|
||||||
) {
|
) {
|
||||||
@ -643,10 +644,14 @@ impl ExprCollector<'_> {
|
|||||||
|
|
||||||
// Note that macro could be expended to multiple statements
|
// Note that macro could be expended to multiple statements
|
||||||
if let Some(ast::Expr::MacroCall(m)) = stmt.expr() {
|
if let Some(ast::Expr::MacroCall(m)) = stmt.expr() {
|
||||||
|
let macro_ptr = AstPtr::new(&m);
|
||||||
let syntax_ptr = AstPtr::new(&stmt.expr().unwrap());
|
let syntax_ptr = AstPtr::new(&stmt.expr().unwrap());
|
||||||
|
|
||||||
self.collect_macro_call(m, syntax_ptr.clone(), false, |this, expansion| {
|
self.collect_macro_call(
|
||||||
match expansion {
|
m,
|
||||||
|
macro_ptr,
|
||||||
|
false,
|
||||||
|
|this, expansion| match expansion {
|
||||||
Some(expansion) => {
|
Some(expansion) => {
|
||||||
let statements: ast::MacroStmts = expansion;
|
let statements: ast::MacroStmts = expansion;
|
||||||
|
|
||||||
@ -660,8 +665,8 @@ impl ExprCollector<'_> {
|
|||||||
let expr = this.alloc_expr(Expr::Missing, syntax_ptr.clone());
|
let expr = this.alloc_expr(Expr::Missing, syntax_ptr.clone());
|
||||||
this.statements_in_scope.push(Statement::Expr(expr));
|
this.statements_in_scope.push(Statement::Expr(expr));
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
});
|
);
|
||||||
} else {
|
} else {
|
||||||
let expr = self.collect_expr_opt(stmt.expr());
|
let expr = self.collect_expr_opt(stmt.expr());
|
||||||
self.statements_in_scope.push(Statement::Expr(expr));
|
self.statements_in_scope.push(Statement::Expr(expr));
|
||||||
@ -848,8 +853,23 @@ impl ExprCollector<'_> {
|
|||||||
Pat::Missing
|
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
|
// FIXME: implement
|
||||||
ast::Pat::RangePat(_) | ast::Pat::MacroPat(_) => Pat::Missing,
|
ast::Pat::RangePat(_) => Pat::Missing,
|
||||||
};
|
};
|
||||||
let ptr = AstPtr::new(&pat);
|
let ptr = AstPtr::new(&pat);
|
||||||
self.alloc_pat(pattern, Either::Left(ptr))
|
self.alloc_pat(pattern, Either::Left(ptr))
|
||||||
|
@ -99,6 +99,11 @@ impl ItemTree {
|
|||||||
// items.
|
// items.
|
||||||
ctx.lower_macro_stmts(stmts)
|
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) => {
|
ast::Expr(e) => {
|
||||||
// Macros can expand to expressions. We return an empty item tree in this case, but
|
// Macros can expand to expressions. We return an empty item tree in this case, but
|
||||||
// still need to collect inner items.
|
// still need to collect inner items.
|
||||||
|
@ -189,7 +189,7 @@ impl Ctx {
|
|||||||
block_stack.push(self.source_ast_id_map.ast_id(&block));
|
block_stack.push(self.source_ast_id_map.ast_id(&block));
|
||||||
},
|
},
|
||||||
ast::Item(item) => {
|
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 mod_items = self.lower_mod_item(&item, true);
|
||||||
let current_block = block_stack.last();
|
let current_block = block_stack.last();
|
||||||
if let (Some(mod_items), Some(block)) = (mod_items, current_block) {
|
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() {
|
match parent.kind() {
|
||||||
MACRO_ITEMS | SOURCE_FILE => FragmentKind::Items,
|
MACRO_ITEMS | SOURCE_FILE => FragmentKind::Items,
|
||||||
MACRO_STMTS => FragmentKind::Statements,
|
MACRO_STMTS => FragmentKind::Statements,
|
||||||
|
MACRO_PAT => FragmentKind::Pattern,
|
||||||
ITEM_LIST => FragmentKind::Items,
|
ITEM_LIST => FragmentKind::Items,
|
||||||
LET_STMT => {
|
LET_STMT => {
|
||||||
// FIXME: Handle LHS Pattern
|
// FIXME: Handle LHS Pattern
|
||||||
|
@ -1065,11 +1065,11 @@ fn macro_in_arm() {
|
|||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
|
!0..2 '()': ()
|
||||||
51..110 '{ ... }; }': ()
|
51..110 '{ ... }; }': ()
|
||||||
61..62 'x': u32
|
61..62 'x': u32
|
||||||
65..107 'match ... }': u32
|
65..107 'match ... }': u32
|
||||||
71..73 '()': ()
|
71..73 '()': ()
|
||||||
84..91 'unit!()': ()
|
|
||||||
95..100 '92u32': u32
|
95..100 '92u32': u32
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use expect_test::expect;
|
use expect_test::expect;
|
||||||
|
|
||||||
use super::{check_infer, check_infer_with_mismatches};
|
use super::{check_infer, check_infer_with_mismatches, check_types};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn infer_pattern() {
|
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 {
|
pub fn gimme() -> theitem::TheItem {
|
||||||
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 New Issue
Block a user