Skip to content

Move to upstream macro_rules! model #6893

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Dec 15, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,5 @@ debug = 0 # Set this to 1 or 2 to get more useful backtraces in debugger.
# chalk-solve = { path = "../chalk/chalk-solve" }
# chalk-ir = { path = "../chalk/chalk-ir" }
# chalk-recursive = { path = "../chalk/chalk-recursive" }

# ungrammar = { path = "../ungrammar" }
6 changes: 3 additions & 3 deletions crates/completion/src/render/macro_.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ mod tests {
use foo::<|>;
//- /foo/lib.rs crate:foo
#[macro_export]
macro_rules frobnicate { () => () }
macro_rules! frobnicate { () => () }
"#,
r#"
use foo::frobnicate;
Expand All @@ -154,11 +154,11 @@ use foo::frobnicate;
check_edit(
"frobnicate!",
r#"
macro_rules frobnicate { () => () }
macro_rules! frobnicate { () => () }
fn main() { frob<|>!(); }
"#,
r#"
macro_rules frobnicate { () => () }
macro_rules! frobnicate { () => () }
fn main() { frobnicate!(); }
"#,
);
Expand Down
4 changes: 2 additions & 2 deletions crates/hir/src/has_source.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,8 @@ impl HasSource for TypeAlias {
}
}
impl HasSource for MacroDef {
type Ast = ast::MacroCall;
fn source(self, db: &dyn HirDatabase) -> InFile<ast::MacroCall> {
type Ast = ast::MacroRules;
fn source(self, db: &dyn HirDatabase) -> InFile<ast::MacroRules> {
InFile {
file_id: self.id.ast_id.expect("MacroDef without ast_id").file_id,
value: self.id.ast_id.expect("MacroDef without ast_id").to_node(db.upcast()),
Expand Down
2 changes: 1 addition & 1 deletion crates/hir/src/semantics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -723,7 +723,7 @@ to_def_impls![
(crate::EnumVariant, ast::Variant, enum_variant_to_def),
(crate::TypeParam, ast::TypeParam, type_param_to_def),
(crate::LifetimeParam, ast::LifetimeParam, lifetime_param_to_def),
(crate::MacroDef, ast::MacroCall, macro_call_to_def), // this one is dubious, not all calls are macros
(crate::MacroDef, ast::MacroRules, macro_rules_to_def),
(crate::Local, ast::IdentPat, bind_pat_to_def),
];

Expand Down
5 changes: 4 additions & 1 deletion crates/hir/src/semantics/source_to_def.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,10 @@ impl SourceToDefCtx<'_, '_> {
}

// FIXME: use DynMap as well?
pub(super) fn macro_call_to_def(&mut self, src: InFile<ast::MacroCall>) -> Option<MacroDefId> {
pub(super) fn macro_rules_to_def(
&mut self,
src: InFile<ast::MacroRules>,
) -> Option<MacroDefId> {
let kind = MacroDefKind::Declarative;
let file_id = src.file_id.original_file(self.db.upcast());
let krate = self.file_to_def(file_id)?.krate;
Expand Down
134 changes: 69 additions & 65 deletions crates/hir_def/src/body/lower.rs
Original file line number Diff line number Diff line change
Expand Up @@ -566,66 +566,52 @@ impl ExprCollector<'_> {
syntax_ptr: AstPtr<ast::Expr>,
mut collector: F,
) {
if let Some(name) = e.is_macro_rules().map(|it| it.as_name()) {
let mac = MacroDefId {
krate: Some(self.expander.module.krate),
ast_id: Some(self.expander.ast_id(&e)),
kind: MacroDefKind::Declarative,
local_inner: false,
};
self.body.item_scope.define_legacy_macro(name, mac);
// File containing the macro call. Expansion errors will be attached here.
let outer_file = self.expander.current_file_id;

// FIXME: do we still need to allocate this as missing ?
collector(self, None);
} else {
// File containing the macro call. Expansion errors will be attached here.
let outer_file = self.expander.current_file_id;

let macro_call = self.expander.to_source(AstPtr::new(&e));
let res = self.expander.enter_expand(self.db, Some(&self.body.item_scope), e);

match &res.err {
Some(ExpandError::UnresolvedProcMacro) => {
self.source_map.diagnostics.push(BodyDiagnostic::UnresolvedProcMacro(
UnresolvedProcMacro {
file: outer_file,
node: syntax_ptr.into(),
precise_location: None,
macro_name: None,
},
));
}
Some(err) => {
self.source_map.diagnostics.push(BodyDiagnostic::MacroError(MacroError {
let macro_call = self.expander.to_source(AstPtr::new(&e));
let res = self.expander.enter_expand(self.db, Some(&self.body.item_scope), e);

match &res.err {
Some(ExpandError::UnresolvedProcMacro) => {
self.source_map.diagnostics.push(BodyDiagnostic::UnresolvedProcMacro(
UnresolvedProcMacro {
file: outer_file,
node: syntax_ptr.into(),
message: err.to_string(),
}));
}
None => {}
precise_location: None,
macro_name: None,
},
));
}
Some(err) => {
self.source_map.diagnostics.push(BodyDiagnostic::MacroError(MacroError {
file: outer_file,
node: syntax_ptr.into(),
message: err.to_string(),
}));
}
None => {}
}

match res.value {
Some((mark, expansion)) => {
// FIXME: Statements are too complicated to recover from error for now.
// It is because we don't have any hygenine for local variable expansion right now.
if T::can_cast(syntax::SyntaxKind::MACRO_STMTS) && res.err.is_some() {
self.expander.exit(self.db, mark);
collector(self, None);
} else {
self.source_map
.expansions
.insert(macro_call, self.expander.current_file_id);
match res.value {
Some((mark, expansion)) => {
// FIXME: Statements are too complicated to recover from error for now.
// It is because we don't have any hygenine for local variable expansion right now.
if T::can_cast(syntax::SyntaxKind::MACRO_STMTS) && res.err.is_some() {
self.expander.exit(self.db, mark);
collector(self, None);
} else {
self.source_map.expansions.insert(macro_call, self.expander.current_file_id);

let item_tree = self.db.item_tree(self.expander.current_file_id);
self.item_trees.insert(self.expander.current_file_id, item_tree);
let item_tree = self.db.item_tree(self.expander.current_file_id);
self.item_trees.insert(self.expander.current_file_id, item_tree);

collector(self, Some(expansion));
self.expander.exit(self.db, mark);
}
let id = collector(self, Some(expansion));
self.expander.exit(self.db, mark);
id
}
None => collector(self, None),
}
None => collector(self, None),
}
}

Expand Down Expand Up @@ -785,26 +771,44 @@ impl ExprCollector<'_> {
| ast::Item::ExternCrate(_)
| ast::Item::Module(_)
| ast::Item::MacroCall(_) => return None,
ast::Item::MacroRules(def) => {
return Some(Either::Right(def));
}
};

Some((def, name))
Some(Either::Left((def, name)))
})
.collect::<Vec<_>>();

for (def, name) in items {
self.body.item_scope.define_def(def);
if let Some(name) = name {
let vis = crate::visibility::Visibility::Public; // FIXME determine correctly
let has_constructor = match def {
ModuleDefId::AdtId(AdtId::StructId(s)) => {
self.db.struct_data(s).variant_data.kind() != StructKind::Record
for either in items {
match either {
Either::Left((def, name)) => {
self.body.item_scope.define_def(def);
if let Some(name) = name {
let vis = crate::visibility::Visibility::Public; // FIXME determine correctly
let has_constructor = match def {
ModuleDefId::AdtId(AdtId::StructId(s)) => {
self.db.struct_data(s).variant_data.kind() != StructKind::Record
}
_ => true,
};
self.body.item_scope.push_res(
name.as_name(),
crate::per_ns::PerNs::from_def(def, vis, has_constructor),
);
}
_ => true,
};
self.body.item_scope.push_res(
name.as_name(),
crate::per_ns::PerNs::from_def(def, vis, has_constructor),
);
}
Either::Right(e) => {
let mac = MacroDefId {
krate: Some(self.expander.module.krate),
ast_id: Some(self.expander.ast_id(&e)),
kind: MacroDefKind::Declarative,
local_inner: false,
};
if let Some(name) = e.name() {
self.body.item_scope.define_legacy_macro(name.as_name(), mac);
}
}
}
}
}
Expand Down
19 changes: 15 additions & 4 deletions crates/hir_def/src/item_tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ impl ItemTree {
type_aliases,
mods,
macro_calls,
macro_rules,
exprs,
vis,
generics,
Expand All @@ -162,6 +163,7 @@ impl ItemTree {
type_aliases.shrink_to_fit();
mods.shrink_to_fit();
macro_calls.shrink_to_fit();
macro_rules.shrink_to_fit();
exprs.shrink_to_fit();

vis.arena.shrink_to_fit();
Expand Down Expand Up @@ -280,6 +282,7 @@ struct ItemTreeData {
type_aliases: Arena<TypeAlias>,
mods: Arena<Mod>,
macro_calls: Arena<MacroCall>,
macro_rules: Arena<MacroRules>,
exprs: Arena<Expr>,

vis: ItemVisibilities,
Expand Down Expand Up @@ -427,6 +430,7 @@ mod_items! {
TypeAlias in type_aliases -> ast::TypeAlias,
Mod in mods -> ast::Module,
MacroCall in macro_calls -> ast::MacroCall,
MacroRules in macro_rules -> ast::MacroRules,
}

macro_rules! impl_index {
Expand Down Expand Up @@ -629,17 +633,22 @@ pub enum ModKind {

#[derive(Debug, Clone, Eq, PartialEq)]
pub struct MacroCall {
/// For `macro_rules!` declarations, this is the name of the declared macro.
pub name: Option<Name>,
/// Path to the called macro.
pub path: ModPath,
pub ast_id: FileAstId<ast::MacroCall>,
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub struct MacroRules {
/// For `macro_rules!` declarations, this is the name of the declared macro.
pub name: Name,
/// Has `#[macro_export]`.
pub is_export: bool,
/// Has `#[macro_export(local_inner_macros)]`.
pub is_local_inner: bool,
/// Has `#[rustc_builtin_macro]`.
pub is_builtin: bool,
pub ast_id: FileAstId<ast::MacroCall>,
pub ast_id: FileAstId<ast::MacroRules>,
}

// NB: There's no `FileAstId` for `Expr`. The only case where this would be useful is for array
Expand Down Expand Up @@ -670,7 +679,8 @@ impl ModItem {
| ModItem::Static(_)
| ModItem::Trait(_)
| ModItem::Impl(_)
| ModItem::Mod(_) => None,
| ModItem::Mod(_)
| ModItem::MacroRules(_) => None,
ModItem::MacroCall(call) => Some(AssocItem::MacroCall(*call)),
ModItem::Const(konst) => Some(AssocItem::Const(*konst)),
ModItem::TypeAlias(alias) => Some(AssocItem::TypeAlias(*alias)),
Expand All @@ -697,6 +707,7 @@ impl ModItem {
ModItem::TypeAlias(it) => tree[it.index].ast_id().upcast(),
ModItem::Mod(it) => tree[it.index].ast_id().upcast(),
ModItem::MacroCall(it) => tree[it.index].ast_id().upcast(),
ModItem::MacroRules(it) => tree[it.index].ast_id().upcast(),
}
}
}
Expand Down
24 changes: 17 additions & 7 deletions crates/hir_def/src/item_tree/lower.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,7 @@ impl Ctx {
| ast::Item::Fn(_)
| ast::Item::TypeAlias(_)
| ast::Item::Const(_)
| ast::Item::Static(_)
| ast::Item::MacroCall(_) => {
| ast::Item::Static(_) => {
// Skip this if we're already collecting inner items. We'll descend into all nodes
// already.
if !inner {
Expand All @@ -98,7 +97,11 @@ impl Ctx {
ast::Item::Trait(_) | ast::Item::Impl(_) | ast::Item::ExternBlock(_) => {}

// These don't have inner items.
ast::Item::Module(_) | ast::Item::ExternCrate(_) | ast::Item::Use(_) => {}
ast::Item::Module(_)
| ast::Item::ExternCrate(_)
| ast::Item::Use(_)
| ast::Item::MacroCall(_)
| ast::Item::MacroRules(_) => {}
};

let attrs = Attrs::new(item, &self.hygiene);
Expand All @@ -118,6 +121,7 @@ impl Ctx {
)),
ast::Item::ExternCrate(ast) => self.lower_extern_crate(ast).map(Into::into),
ast::Item::MacroCall(ast) => self.lower_macro_call(ast).map(Into::into),
ast::Item::MacroRules(ast) => self.lower_macro_rules(ast).map(Into::into),
ast::Item::ExternBlock(ast) => {
Some(ModItems(self.lower_extern_block(ast).into_iter().collect::<SmallVec<_>>()))
}
Expand Down Expand Up @@ -525,9 +529,15 @@ impl Ctx {
}

fn lower_macro_call(&mut self, m: &ast::MacroCall) -> Option<FileItemTreeId<MacroCall>> {
let name = m.name().map(|it| it.as_name());
let attrs = Attrs::new(m, &self.hygiene);
let path = ModPath::from_src(m.path()?, &self.hygiene)?;
let ast_id = self.source_ast_id_map.ast_id(m);
let res = MacroCall { path, ast_id };
Some(id(self.data().macro_calls.alloc(res)))
}

fn lower_macro_rules(&mut self, m: &ast::MacroRules) -> Option<FileItemTreeId<MacroRules>> {
let name = m.name().map(|it| it.as_name())?;
let attrs = Attrs::new(m, &self.hygiene);

let ast_id = self.source_ast_id_map.ast_id(m);

Expand All @@ -547,8 +557,8 @@ impl Ctx {
};

let is_builtin = attrs.by_key("rustc_builtin_macro").exists();
let res = MacroCall { name, path, is_export, is_builtin, is_local_inner, ast_id };
Some(id(self.data().macro_calls.alloc(res)))
let res = MacroRules { name, is_export, is_builtin, is_local_inner, ast_id };
Some(id(self.data().macro_rules.alloc(res)))
}

fn lower_extern_block(&mut self, block: &ast::ExternBlock) -> Vec<ModItem> {
Expand Down
Loading