mirror of
https://github.com/rust-lang/rust.git
synced 2024-12-12 16:45:37 +00:00
Merge #3179
3179: Introduce AsMacroCall trait r=matklad a=edwin0cheng This PR introduce `AsMacroCall` trait to help convert `ast::MacroCall` to `MacroCallId`. The main goal here is to centralize various conversions to single place and make implementing eager macro calls without further ado. ```rust pub trait AsMacroCall { fn as_call_id( &self, db: &(impl db::DefDatabase + AstDatabase), resolver: impl Fn(path::ModPath) -> Option<MacroDefId>, ) -> Option<MacroCallId>; } ``` Co-authored-by: Edwin Cheng <edwin0cheng@gmail.com>
This commit is contained in:
commit
daffdd8674
@ -15,11 +15,9 @@ use hir_def::{
|
||||
},
|
||||
expr::{ExprId, PatId},
|
||||
resolver::{self, resolver_for_scope, Resolver, TypeNs, ValueNs},
|
||||
DefWithBodyId, TraitId,
|
||||
};
|
||||
use hir_expand::{
|
||||
hygiene::Hygiene, name::AsName, AstId, HirFileId, InFile, MacroCallId, MacroCallKind,
|
||||
AsMacroCall, DefWithBodyId, TraitId,
|
||||
};
|
||||
use hir_expand::{hygiene::Hygiene, name::AsName, HirFileId, InFile, MacroCallId};
|
||||
use hir_ty::{InEnvironment, InferenceResult, TraitEnvironment};
|
||||
use ra_syntax::{
|
||||
ast::{self, AstNode},
|
||||
@ -363,12 +361,10 @@ impl SourceAnalyzer {
|
||||
db: &impl HirDatabase,
|
||||
macro_call: InFile<&ast::MacroCall>,
|
||||
) -> Option<Expansion> {
|
||||
let def = self.resolve_macro_call(db, macro_call)?.id;
|
||||
let ast_id = AstId::new(
|
||||
macro_call.file_id,
|
||||
db.ast_id_map(macro_call.file_id).ast_id(macro_call.value),
|
||||
);
|
||||
Some(Expansion { macro_call_id: def.as_call_id(db, MacroCallKind::FnLike(ast_id)) })
|
||||
let macro_call_id = macro_call.as_call_id(db, |path| {
|
||||
self.resolver.resolve_path_as_macro(db, &path).map(|it| it.into())
|
||||
})?;
|
||||
Some(Expansion { macro_call_id })
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7,9 +7,7 @@ use std::{mem, ops::Index, sync::Arc};
|
||||
|
||||
use drop_bomb::DropBomb;
|
||||
use either::Either;
|
||||
use hir_expand::{
|
||||
ast_id_map::AstIdMap, hygiene::Hygiene, AstId, HirFileId, InFile, MacroCallKind, MacroDefId,
|
||||
};
|
||||
use hir_expand::{ast_id_map::AstIdMap, hygiene::Hygiene, AstId, HirFileId, InFile, MacroDefId};
|
||||
use ra_arena::{map::ArenaMap, Arena};
|
||||
use ra_prof::profile;
|
||||
use ra_syntax::{ast, AstNode, AstPtr};
|
||||
@ -23,7 +21,7 @@ use crate::{
|
||||
nameres::CrateDefMap,
|
||||
path::{ModPath, Path},
|
||||
src::HasSource,
|
||||
DefWithBodyId, HasModule, Lookup, ModuleId,
|
||||
AsMacroCall, DefWithBodyId, HasModule, Lookup, ModuleId,
|
||||
};
|
||||
|
||||
pub(crate) struct Expander {
|
||||
@ -51,30 +49,26 @@ impl Expander {
|
||||
db: &DB,
|
||||
macro_call: ast::MacroCall,
|
||||
) -> Option<(Mark, T)> {
|
||||
let ast_id = AstId::new(
|
||||
self.current_file_id,
|
||||
db.ast_id_map(self.current_file_id).ast_id(¯o_call),
|
||||
);
|
||||
let macro_call = InFile::new(self.current_file_id, ¯o_call);
|
||||
|
||||
if let Some(path) = macro_call.path().and_then(|path| self.parse_mod_path(path)) {
|
||||
if let Some(def) = self.resolve_path_as_macro(db, &path) {
|
||||
let call_id = def.as_call_id(db, MacroCallKind::FnLike(ast_id));
|
||||
let file_id = call_id.as_file();
|
||||
if let Some(node) = db.parse_or_expand(file_id) {
|
||||
if let Some(expr) = T::cast(node) {
|
||||
log::debug!("macro expansion {:#?}", expr.syntax());
|
||||
if let Some(call_id) =
|
||||
macro_call.as_call_id(db, |path| self.resolve_path_as_macro(db, &path))
|
||||
{
|
||||
let file_id = call_id.as_file();
|
||||
if let Some(node) = db.parse_or_expand(file_id) {
|
||||
if let Some(expr) = T::cast(node) {
|
||||
log::debug!("macro expansion {:#?}", expr.syntax());
|
||||
|
||||
let mark = Mark {
|
||||
file_id: self.current_file_id,
|
||||
ast_id_map: mem::take(&mut self.ast_id_map),
|
||||
bomb: DropBomb::new("expansion mark dropped"),
|
||||
};
|
||||
self.hygiene = Hygiene::new(db, file_id);
|
||||
self.current_file_id = file_id;
|
||||
self.ast_id_map = db.ast_id_map(file_id);
|
||||
let mark = Mark {
|
||||
file_id: self.current_file_id,
|
||||
ast_id_map: mem::take(&mut self.ast_id_map),
|
||||
bomb: DropBomb::new("expansion mark dropped"),
|
||||
};
|
||||
self.hygiene = Hygiene::new(db, file_id);
|
||||
self.current_file_id = file_id;
|
||||
self.ast_id_map = db.ast_id_map(file_id);
|
||||
|
||||
return Some((mark, expr));
|
||||
}
|
||||
return Some((mark, expr));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -99,10 +93,6 @@ impl Expander {
|
||||
Path::from_src(path, &self.hygiene)
|
||||
}
|
||||
|
||||
fn parse_mod_path(&mut self, path: ast::Path) -> Option<ModPath> {
|
||||
ModPath::from_src(path, &self.hygiene)
|
||||
}
|
||||
|
||||
fn resolve_path_as_macro(&self, db: &impl DefDatabase, path: &ModPath) -> Option<MacroDefId> {
|
||||
self.crate_def_map
|
||||
.resolve_path(db, self.module.local_id, path, BuiltinShadowMode::Other)
|
||||
|
@ -46,7 +46,10 @@ mod marks;
|
||||
|
||||
use std::hash::Hash;
|
||||
|
||||
use hir_expand::{ast_id_map::FileAstId, AstId, HirFileId, InFile, MacroDefId};
|
||||
use hir_expand::{
|
||||
ast_id_map::FileAstId, db::AstDatabase, hygiene::Hygiene, AstId, HirFileId, InFile,
|
||||
MacroCallId, MacroCallKind, MacroDefId,
|
||||
};
|
||||
use ra_arena::{impl_arena_id, RawId};
|
||||
use ra_db::{impl_intern_key, salsa, CrateId};
|
||||
use ra_syntax::{ast, AstNode};
|
||||
@ -413,3 +416,61 @@ impl HasModule for StaticLoc {
|
||||
self.container.module(db)
|
||||
}
|
||||
}
|
||||
|
||||
/// A helper trait for converting to MacroCallId
|
||||
pub trait AsMacroCall {
|
||||
fn as_call_id(
|
||||
&self,
|
||||
db: &(impl db::DefDatabase + AstDatabase),
|
||||
resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
|
||||
) -> Option<MacroCallId>;
|
||||
}
|
||||
|
||||
impl AsMacroCall for InFile<&ast::MacroCall> {
|
||||
fn as_call_id(
|
||||
&self,
|
||||
db: &(impl db::DefDatabase + AstDatabase),
|
||||
resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
|
||||
) -> Option<MacroCallId> {
|
||||
let ast_id = AstId::new(self.file_id, db.ast_id_map(self.file_id).ast_id(self.value));
|
||||
let h = Hygiene::new(db, self.file_id);
|
||||
let path = path::ModPath::from_src(self.value.path()?, &h)?;
|
||||
|
||||
AstIdWithPath::new(ast_id.file_id, ast_id.value, path).as_call_id(db, resolver)
|
||||
}
|
||||
}
|
||||
|
||||
/// Helper wrapper for `AstId` with `ModPath`
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
struct AstIdWithPath<T: ast::AstNode> {
|
||||
pub ast_id: AstId<T>,
|
||||
pub path: path::ModPath,
|
||||
}
|
||||
|
||||
impl<T: ast::AstNode> AstIdWithPath<T> {
|
||||
pub fn new(file_id: HirFileId, ast_id: FileAstId<T>, path: path::ModPath) -> AstIdWithPath<T> {
|
||||
AstIdWithPath { ast_id: AstId::new(file_id, ast_id), path }
|
||||
}
|
||||
}
|
||||
|
||||
impl AsMacroCall for AstIdWithPath<ast::MacroCall> {
|
||||
fn as_call_id(
|
||||
&self,
|
||||
db: &impl AstDatabase,
|
||||
resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
|
||||
) -> Option<MacroCallId> {
|
||||
let def = resolver(self.path.clone())?;
|
||||
Some(def.as_call_id(db, MacroCallKind::FnLike(self.ast_id.clone())))
|
||||
}
|
||||
}
|
||||
|
||||
impl AsMacroCall for AstIdWithPath<ast::ModuleItem> {
|
||||
fn as_call_id(
|
||||
&self,
|
||||
db: &impl AstDatabase,
|
||||
resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
|
||||
) -> Option<MacroCallId> {
|
||||
let def = resolver(self.path.clone())?;
|
||||
Some(def.as_call_id(db, MacroCallKind::Attr(self.ast_id.clone())))
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ use hir_expand::{
|
||||
builtin_derive::find_builtin_derive,
|
||||
builtin_macro::find_builtin_macro,
|
||||
name::{name, AsName, Name},
|
||||
HirFileId, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind,
|
||||
HirFileId, MacroCallId, MacroDefId, MacroDefKind,
|
||||
};
|
||||
use ra_cfg::CfgOptions;
|
||||
use ra_db::{CrateId, FileId};
|
||||
@ -25,8 +25,9 @@ use crate::{
|
||||
path::{ImportAlias, ModPath, PathKind},
|
||||
per_ns::PerNs,
|
||||
visibility::Visibility,
|
||||
AdtId, AstId, ConstLoc, ContainerId, EnumLoc, EnumVariantId, FunctionLoc, ImplLoc, Intern,
|
||||
LocalModuleId, ModuleDefId, ModuleId, StaticLoc, StructLoc, TraitLoc, TypeAliasLoc, UnionLoc,
|
||||
AdtId, AsMacroCall, AstId, AstIdWithPath, ConstLoc, ContainerId, EnumLoc, EnumVariantId,
|
||||
FunctionLoc, ImplLoc, Intern, LocalModuleId, ModuleDefId, ModuleId, StaticLoc, StructLoc,
|
||||
TraitLoc, TypeAliasLoc, UnionLoc,
|
||||
};
|
||||
|
||||
pub(super) fn collect_defs(db: &impl DefDatabase, mut def_map: CrateDefMap) -> CrateDefMap {
|
||||
@ -99,11 +100,16 @@ struct ImportDirective {
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
struct MacroDirective {
|
||||
module_id: LocalModuleId,
|
||||
ast_id: AstId<ast::MacroCall>,
|
||||
path: ModPath,
|
||||
ast_id: AstIdWithPath<ast::MacroCall>,
|
||||
legacy: Option<MacroCallId>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
struct DeriveDirective {
|
||||
module_id: LocalModuleId,
|
||||
ast_id: AstIdWithPath<ast::ModuleItem>,
|
||||
}
|
||||
|
||||
/// Walks the tree of module recursively
|
||||
struct DefCollector<'a, DB> {
|
||||
db: &'a DB,
|
||||
@ -112,7 +118,7 @@ struct DefCollector<'a, DB> {
|
||||
unresolved_imports: Vec<ImportDirective>,
|
||||
resolved_imports: Vec<ImportDirective>,
|
||||
unexpanded_macros: Vec<MacroDirective>,
|
||||
unexpanded_attribute_macros: Vec<(LocalModuleId, AstId<ast::ModuleItem>, ModPath)>,
|
||||
unexpanded_attribute_macros: Vec<DeriveDirective>,
|
||||
mod_dirs: FxHashMap<LocalModuleId, ModDir>,
|
||||
cfg_options: &'a CfgOptions,
|
||||
}
|
||||
@ -515,16 +521,16 @@ where
|
||||
return false;
|
||||
}
|
||||
|
||||
let resolved_res = self.def_map.resolve_path_fp_with_macro(
|
||||
self.db,
|
||||
ResolveMode::Other,
|
||||
directive.module_id,
|
||||
&directive.path,
|
||||
BuiltinShadowMode::Module,
|
||||
);
|
||||
|
||||
if let Some(def) = resolved_res.resolved_def.take_macros() {
|
||||
let call_id = def.as_call_id(self.db, MacroCallKind::FnLike(directive.ast_id));
|
||||
if let Some(call_id) = directive.ast_id.as_call_id(self.db, |path| {
|
||||
let resolved_res = self.def_map.resolve_path_fp_with_macro(
|
||||
self.db,
|
||||
ResolveMode::Other,
|
||||
directive.module_id,
|
||||
&path,
|
||||
BuiltinShadowMode::Module,
|
||||
);
|
||||
resolved_res.resolved_def.take_macros()
|
||||
}) {
|
||||
resolved.push((directive.module_id, call_id));
|
||||
res = ReachedFixedPoint::No;
|
||||
return false;
|
||||
@ -532,12 +538,11 @@ where
|
||||
|
||||
true
|
||||
});
|
||||
attribute_macros.retain(|(module_id, ast_id, path)| {
|
||||
let resolved_res = self.resolve_attribute_macro(path);
|
||||
|
||||
if let Some(def) = resolved_res {
|
||||
let call_id = def.as_call_id(self.db, MacroCallKind::Attr(*ast_id));
|
||||
resolved.push((*module_id, call_id));
|
||||
attribute_macros.retain(|directive| {
|
||||
if let Some(call_id) =
|
||||
directive.ast_id.as_call_id(self.db, |path| self.resolve_attribute_macro(&path))
|
||||
{
|
||||
resolved.push((directive.module_id, call_id));
|
||||
res = ReachedFixedPoint::No;
|
||||
return false;
|
||||
}
|
||||
@ -833,20 +838,22 @@ where
|
||||
};
|
||||
let path = ModPath::from_tt_ident(ident);
|
||||
|
||||
let ast_id = AstId::new(self.file_id, def.kind.ast_id());
|
||||
self.def_collector.unexpanded_attribute_macros.push((self.module_id, ast_id, path));
|
||||
let ast_id = AstIdWithPath::new(self.file_id, def.kind.ast_id(), path);
|
||||
self.def_collector
|
||||
.unexpanded_attribute_macros
|
||||
.push(DeriveDirective { module_id: self.module_id, ast_id });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn collect_macro(&mut self, mac: &raw::MacroData) {
|
||||
let ast_id = AstId::new(self.file_id, mac.ast_id);
|
||||
let mut ast_id = AstIdWithPath::new(self.file_id, mac.ast_id, mac.path.clone());
|
||||
|
||||
// Case 0: builtin macros
|
||||
if mac.builtin {
|
||||
if let Some(name) = &mac.name {
|
||||
let krate = self.def_collector.def_map.krate;
|
||||
if let Some(macro_id) = find_builtin_macro(name, krate, ast_id) {
|
||||
if let Some(macro_id) = find_builtin_macro(name, krate, ast_id.ast_id) {
|
||||
self.def_collector.define_macro(
|
||||
self.module_id,
|
||||
name.clone(),
|
||||
@ -862,7 +869,7 @@ where
|
||||
if is_macro_rules(&mac.path) {
|
||||
if let Some(name) = &mac.name {
|
||||
let macro_id = MacroDefId {
|
||||
ast_id: Some(ast_id),
|
||||
ast_id: Some(ast_id.ast_id),
|
||||
krate: Some(self.def_collector.def_map.krate),
|
||||
kind: MacroDefKind::Declarative,
|
||||
};
|
||||
@ -872,15 +879,13 @@ where
|
||||
}
|
||||
|
||||
// Case 2: try to resolve in legacy scope and expand macro_rules
|
||||
if let Some(macro_def) = mac.path.as_ident().and_then(|name| {
|
||||
self.def_collector.def_map[self.module_id].scope.get_legacy_macro(&name)
|
||||
if let Some(macro_call_id) = ast_id.as_call_id(self.def_collector.db, |path| {
|
||||
path.as_ident().and_then(|name| {
|
||||
self.def_collector.def_map[self.module_id].scope.get_legacy_macro(&name)
|
||||
})
|
||||
}) {
|
||||
let macro_call_id =
|
||||
macro_def.as_call_id(self.def_collector.db, MacroCallKind::FnLike(ast_id));
|
||||
|
||||
self.def_collector.unexpanded_macros.push(MacroDirective {
|
||||
module_id: self.module_id,
|
||||
path: mac.path.clone(),
|
||||
ast_id,
|
||||
legacy: Some(macro_call_id),
|
||||
});
|
||||
@ -890,14 +895,12 @@ where
|
||||
|
||||
// Case 3: resolve in module scope, expand during name resolution.
|
||||
// We rewrite simple path `macro_name` to `self::macro_name` to force resolve in module scope only.
|
||||
let mut path = mac.path.clone();
|
||||
if path.is_ident() {
|
||||
path.kind = PathKind::Super(0);
|
||||
if ast_id.path.is_ident() {
|
||||
ast_id.path.kind = PathKind::Super(0);
|
||||
}
|
||||
|
||||
self.def_collector.unexpanded_macros.push(MacroDirective {
|
||||
module_id: self.module_id,
|
||||
path,
|
||||
ast_id,
|
||||
legacy: None,
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user