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
Changes from 1 commit
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
Next Next commit
Move to upstream macro_rules! model
jonas-schievink committed Dec 15, 2020
commit c1cb5953820f26d4d0a614650bc8c50cbc5a3ce6
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
@@ -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
@@ -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;
@@ -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!(); }
"#,
);
4 changes: 2 additions & 2 deletions crates/hir/src/has_source.rs
Original file line number Diff line number Diff line change
@@ -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()),
2 changes: 1 addition & 1 deletion crates/hir/src/semantics.rs
Original file line number Diff line number Diff line change
@@ -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),
];

5 changes: 4 additions & 1 deletion crates/hir/src/semantics/source_to_def.rs
Original file line number Diff line number Diff line change
@@ -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;
134 changes: 69 additions & 65 deletions crates/hir_def/src/body/lower.rs
Original file line number Diff line number Diff line change
@@ -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),
}
}

@@ -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);
}
}
}
}
}
19 changes: 15 additions & 4 deletions crates/hir_def/src/item_tree.rs
Original file line number Diff line number Diff line change
@@ -142,6 +142,7 @@ impl ItemTree {
type_aliases,
mods,
macro_calls,
macro_rules,
exprs,
vis,
generics,
@@ -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();
@@ -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,
@@ -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 {
@@ -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
@@ -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)),
@@ -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(),
}
}
}
24 changes: 17 additions & 7 deletions crates/hir_def/src/item_tree/lower.rs
Original file line number Diff line number Diff line change
@@ -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 {
@@ -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);
@@ -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<_>>()))
}
@@ -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);

@@ -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> {
Loading