2626: Recursive collect macros in impl items r=matklad a=edwin0cheng



Co-authored-by: Edwin Cheng <edwin0cheng@gmail.com>
This commit is contained in:
bors[bot] 2019-12-21 10:12:18 +00:00 committed by GitHub
commit 3ebf15c9b2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 59 additions and 10 deletions

View file

@ -225,22 +225,48 @@ fn collect_impl_items_in_macros(
let mut expander = Expander::new(db, impl_block.file_id, module_id);
let mut res = Vec::new();
// We set a limit to protect against infinite recursion
let limit = 100;
for m in impl_block.value.syntax().children().filter_map(ast::MacroCall::cast) {
if let Some((mark, items)) = expander.enter_expand(db, m) {
let items: InFile<ast::MacroItems> = expander.to_source(items);
expander.exit(db, mark);
res.extend(collect_impl_items(
db,
items.value.items().filter_map(|it| ImplItem::cast(it.syntax().clone())),
items.file_id,
id,
));
}
res.extend(collect_impl_items_in_macro(db, &mut expander, m, id, limit))
}
res
}
fn collect_impl_items_in_macro(
db: &impl DefDatabase,
expander: &mut Expander,
m: ast::MacroCall,
id: ImplId,
limit: usize,
) -> Vec<AssocItemId> {
if limit == 0 {
return Vec::new();
}
if let Some((mark, items)) = expander.enter_expand(db, m) {
let items: InFile<ast::MacroItems> = expander.to_source(items);
let mut res = collect_impl_items(
db,
items.value.items().filter_map(|it| ImplItem::cast(it.syntax().clone())),
items.file_id,
id,
);
// Recursive collect macros
// Note that ast::ModuleItem do not include ast::MacroCall
// We cannot use ModuleItemOwner::items here
for it in items.value.syntax().children().filter_map(ast::MacroCall::cast) {
res.extend(collect_impl_items_in_macro(db, expander, it, id, limit - 1))
}
expander.exit(db, mark);
res
} else {
Vec::new()
}
}
fn collect_impl_items(
db: &impl DefDatabase,
impl_items: impl Iterator<Item = ImplItem>,

View file

@ -201,6 +201,29 @@ fn test() { S.foo()<|>; }
assert_eq!(t, "u128");
}
#[test]
fn infer_impl_items_generated_by_macros_chain() {
let t = type_at(
r#"
//- /main.rs
macro_rules! m_inner {
() => {fn foo(&self) -> u128 {0}}
}
macro_rules! m {
() => {m_inner!();}
}
struct S;
impl S {
m!();
}
fn test() { S.foo()<|>; }
"#,
);
assert_eq!(t, "u128");
}
#[test]
fn infer_macro_with_dollar_crate_is_correct_in_expr() {
let (db, pos) = TestDB::with_position(