3692: Introduce `MacroDefKind::CustomDerive` r=matklad a=edwin0cheng

This PR introduce a new `MacroDefKind` `CustomDerive`. And use a new `ProcMacroExpander` for its expanding. And the expander is a dummy for now. 

Related: #3654 

Co-authored-by: Edwin Cheng <edwin0cheng@gmail.com>
This commit is contained in:
bors[bot] 2020-03-25 12:25:46 +00:00 committed by GitHub
commit 8d667bb32e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 144 additions and 28 deletions

View file

@ -475,6 +475,12 @@ impl AsMacroCall for AstIdWithPath<ast::ModuleItem> {
resolver: impl Fn(path::ModPath) -> Option<MacroDefId>, resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
) -> Option<MacroCallId> { ) -> Option<MacroCallId> {
let def = resolver(self.path.clone())?; let def = resolver(self.path.clone())?;
Some(def.as_lazy_macro(db.upcast(), MacroCallKind::Attr(self.ast_id)).into()) Some(
def.as_lazy_macro(
db.upcast(),
MacroCallKind::Attr(self.ast_id, self.path.segments.last()?.to_string()),
)
.into(),
)
} }
} }

View file

@ -7,6 +7,7 @@ use hir_expand::{
builtin_derive::find_builtin_derive, builtin_derive::find_builtin_derive,
builtin_macro::find_builtin_macro, builtin_macro::find_builtin_macro,
name::{name, AsName, Name}, name::{name, AsName, Name},
proc_macro::ProcMacroExpander,
HirFileId, MacroCallId, MacroDefId, MacroDefKind, HirFileId, MacroCallId, MacroDefId, MacroDefKind,
}; };
use ra_cfg::CfgOptions; use ra_cfg::CfgOptions;
@ -64,6 +65,9 @@ pub(super) fn collect_defs(db: &dyn DefDatabase, mut def_map: CrateDefMap) -> Cr
unexpanded_attribute_macros: Vec::new(), unexpanded_attribute_macros: Vec::new(),
mod_dirs: FxHashMap::default(), mod_dirs: FxHashMap::default(),
cfg_options, cfg_options,
// FIXME: pass proc-macro from crate-graph
proc_macros: Default::default(),
}; };
collector.collect(); collector.collect();
collector.finish() collector.finish()
@ -122,6 +126,7 @@ struct DefCollector<'a> {
unexpanded_attribute_macros: Vec<DeriveDirective>, unexpanded_attribute_macros: Vec<DeriveDirective>,
mod_dirs: FxHashMap<LocalModuleId, ModDir>, mod_dirs: FxHashMap<LocalModuleId, ModDir>,
cfg_options: &'a CfgOptions, cfg_options: &'a CfgOptions,
proc_macros: Vec<(Name, ProcMacroExpander)>,
} }
impl DefCollector<'_> { impl DefCollector<'_> {
@ -177,6 +182,24 @@ impl DefCollector<'_> {
for directive in unresolved_imports { for directive in unresolved_imports {
self.record_resolved_import(&directive) self.record_resolved_import(&directive)
} }
// Record proc-macros
self.collect_proc_macro();
}
fn collect_proc_macro(&mut self) {
let proc_macros = std::mem::take(&mut self.proc_macros);
for (name, expander) in proc_macros {
let krate = self.def_map.krate;
let macro_id = MacroDefId {
ast_id: None,
krate: Some(krate),
kind: MacroDefKind::CustomDerive(expander),
};
self.define_proc_macro(name.clone(), macro_id);
}
} }
/// Define a macro with `macro_rules`. /// Define a macro with `macro_rules`.
@ -238,6 +261,18 @@ impl DefCollector<'_> {
self.def_map.modules[module_id].scope.define_legacy_macro(name, mac); self.def_map.modules[module_id].scope.define_legacy_macro(name, mac);
} }
/// Define a proc macro
///
/// A proc macro is similar to normal macro scope, but it would not visiable in legacy textual scoped.
/// And unconditionally exported.
fn define_proc_macro(&mut self, name: Name, macro_: MacroDefId) {
self.update(
self.def_map.root,
&[(name, PerNs::macros(macro_, Visibility::Public))],
Visibility::Public,
);
}
/// Import macros from `#[macro_use] extern crate`. /// Import macros from `#[macro_use] extern crate`.
fn import_macros_from_extern_crate( fn import_macros_from_extern_crate(
&mut self, &mut self,
@ -537,8 +572,9 @@ impl DefCollector<'_> {
true true
}); });
attribute_macros.retain(|directive| { attribute_macros.retain(|directive| {
if let Some(call_id) = if let Some(call_id) = directive
directive.ast_id.as_call_id(self.db, |path| self.resolve_attribute_macro(&path)) .ast_id
.as_call_id(self.db, |path| self.resolve_attribute_macro(&directive, &path))
{ {
resolved.push((directive.module_id, call_id, 0)); resolved.push((directive.module_id, call_id, 0));
res = ReachedFixedPoint::No; res = ReachedFixedPoint::No;
@ -562,9 +598,11 @@ impl DefCollector<'_> {
res res
} }
fn resolve_attribute_macro(&self, path: &ModPath) -> Option<MacroDefId> { fn resolve_attribute_macro(
// FIXME this is currently super hacky, just enough to support the &self,
// built-in derives directive: &DeriveDirective,
path: &ModPath,
) -> Option<MacroDefId> {
if let Some(name) = path.as_ident() { if let Some(name) = path.as_ident() {
// FIXME this should actually be handled with the normal name // FIXME this should actually be handled with the normal name
// resolution; the std lib defines built-in stubs for the derives, // resolution; the std lib defines built-in stubs for the derives,
@ -573,7 +611,15 @@ impl DefCollector<'_> {
return Some(def_id); return Some(def_id);
} }
} }
None 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()
} }
fn collect_macro_expansion( fn collect_macro_expansion(
@ -776,7 +822,6 @@ impl ModCollector<'_, '_> {
// FIXME: check attrs to see if this is an attribute macro invocation; // FIXME: check attrs to see if this is an attribute macro invocation;
// in which case we don't add the invocation, just a single attribute // in which case we don't add the invocation, just a single attribute
// macro invocation // macro invocation
self.collect_derives(attrs, def); self.collect_derives(attrs, def);
let name = def.name.clone(); let name = def.name.clone();
@ -955,6 +1000,7 @@ mod tests {
unexpanded_attribute_macros: Vec::new(), unexpanded_attribute_macros: Vec::new(),
mod_dirs: FxHashMap::default(), mod_dirs: FxHashMap::default(),
cfg_options: &CfgOptions::default(), cfg_options: &CfgOptions::default(),
proc_macros: Default::default(),
}; };
collector.collect(); collector.collect();
collector.def_map collector.def_map

View file

@ -229,9 +229,12 @@ fn partial_ord_expand(
mod tests { mod tests {
use super::*; use super::*;
use crate::{test_db::TestDB, AstId, MacroCallId, MacroCallKind, MacroCallLoc}; use crate::{test_db::TestDB, AstId, MacroCallId, MacroCallKind, MacroCallLoc};
use name::{known, Name};
use ra_db::{fixture::WithFixture, SourceDatabase}; use ra_db::{fixture::WithFixture, SourceDatabase};
fn expand_builtin_derive(s: &str, expander: BuiltinDeriveExpander) -> String { fn expand_builtin_derive(s: &str, name: Name) -> String {
let def = find_builtin_derive(&name).unwrap();
let (db, file_id) = TestDB::with_single_file(&s); let (db, file_id) = TestDB::with_single_file(&s);
let parsed = db.parse(file_id); let parsed = db.parse(file_id);
let items: Vec<_> = let items: Vec<_> =
@ -239,14 +242,9 @@ mod tests {
let ast_id_map = db.ast_id_map(file_id.into()); let ast_id_map = db.ast_id_map(file_id.into());
// the first one should be a macro_rules let attr_id = AstId::new(file_id.into(), ast_id_map.ast_id(&items[0]));
let def =
MacroDefId { krate: None, ast_id: None, kind: MacroDefKind::BuiltInDerive(expander) };
let loc = MacroCallLoc { let loc = MacroCallLoc { def, kind: MacroCallKind::Attr(attr_id, name.to_string()) };
def,
kind: MacroCallKind::Attr(AstId::new(file_id.into(), ast_id_map.ast_id(&items[0]))),
};
let id: MacroCallId = db.intern_macro(loc).into(); let id: MacroCallId = db.intern_macro(loc).into();
let parsed = db.parse_or_expand(id.as_file()).unwrap(); let parsed = db.parse_or_expand(id.as_file()).unwrap();
@ -263,7 +261,7 @@ mod tests {
#[derive(Copy)] #[derive(Copy)]
struct Foo; struct Foo;
"#, "#,
BuiltinDeriveExpander::Copy, known::Copy,
); );
assert_eq!(expanded, "impl< >std::marker::CopyforFoo< >{}"); assert_eq!(expanded, "impl< >std::marker::CopyforFoo< >{}");
@ -276,7 +274,7 @@ mod tests {
#[derive(Copy)] #[derive(Copy)]
struct Foo<A, B>; struct Foo<A, B>;
"#, "#,
BuiltinDeriveExpander::Copy, known::Copy,
); );
assert_eq!( assert_eq!(
@ -292,7 +290,7 @@ mod tests {
#[derive(Copy)] #[derive(Copy)]
struct Foo<A, B, 'a, 'b>; struct Foo<A, B, 'a, 'b>;
"#, "#,
BuiltinDeriveExpander::Copy, known::Copy,
); );
// We currently just ignore lifetimes // We currently just ignore lifetimes
@ -310,7 +308,7 @@ mod tests {
#[derive(Clone)] #[derive(Clone)]
struct Foo<A, B>; struct Foo<A, B>;
"#, "#,
BuiltinDeriveExpander::Clone, known::Clone,
); );
assert_eq!( assert_eq!(

View file

@ -11,7 +11,7 @@ use ra_syntax::{algo::diff, AstNode, Parse, SyntaxKind::*, SyntaxNode};
use crate::{ use crate::{
ast_id_map::AstIdMap, BuiltinDeriveExpander, BuiltinFnLikeExpander, EagerCallLoc, EagerMacroId, ast_id_map::AstIdMap, BuiltinDeriveExpander, BuiltinFnLikeExpander, EagerCallLoc, EagerMacroId,
HirFileId, HirFileIdRepr, LazyMacroId, MacroCallId, MacroCallLoc, MacroDefId, MacroDefKind, HirFileId, HirFileIdRepr, LazyMacroId, MacroCallId, MacroCallLoc, MacroDefId, MacroDefKind,
MacroFile, MacroFile, ProcMacroExpander,
}; };
#[derive(Debug, Clone, Eq, PartialEq)] #[derive(Debug, Clone, Eq, PartialEq)]
@ -19,6 +19,7 @@ pub enum TokenExpander {
MacroRules(mbe::MacroRules), MacroRules(mbe::MacroRules),
Builtin(BuiltinFnLikeExpander), Builtin(BuiltinFnLikeExpander),
BuiltinDerive(BuiltinDeriveExpander), BuiltinDerive(BuiltinDeriveExpander),
ProcMacro(ProcMacroExpander),
} }
impl TokenExpander { impl TokenExpander {
@ -33,6 +34,7 @@ impl TokenExpander {
// FIXME switch these to ExpandResult as well // FIXME switch these to ExpandResult as well
TokenExpander::Builtin(it) => it.expand(db, id, tt).into(), TokenExpander::Builtin(it) => it.expand(db, id, tt).into(),
TokenExpander::BuiltinDerive(it) => it.expand(db, id, tt).into(), TokenExpander::BuiltinDerive(it) => it.expand(db, id, tt).into(),
TokenExpander::ProcMacro(it) => it.expand(db, id, tt).into(),
} }
} }
@ -41,6 +43,7 @@ impl TokenExpander {
TokenExpander::MacroRules(it) => it.map_id_down(id), TokenExpander::MacroRules(it) => it.map_id_down(id),
TokenExpander::Builtin(..) => id, TokenExpander::Builtin(..) => id,
TokenExpander::BuiltinDerive(..) => id, TokenExpander::BuiltinDerive(..) => id,
TokenExpander::ProcMacro(..) => id,
} }
} }
@ -49,6 +52,7 @@ impl TokenExpander {
TokenExpander::MacroRules(it) => it.map_id_up(id), TokenExpander::MacroRules(it) => it.map_id_up(id),
TokenExpander::Builtin(..) => (id, mbe::Origin::Call), TokenExpander::Builtin(..) => (id, mbe::Origin::Call),
TokenExpander::BuiltinDerive(..) => (id, mbe::Origin::Call), TokenExpander::BuiltinDerive(..) => (id, mbe::Origin::Call),
TokenExpander::ProcMacro(..) => (id, mbe::Origin::Call),
} }
} }
} }
@ -130,7 +134,10 @@ pub(crate) fn macro_def(
MacroDefKind::BuiltInDerive(expander) => { MacroDefKind::BuiltInDerive(expander) => {
Some(Arc::new((TokenExpander::BuiltinDerive(expander), mbe::TokenMap::default()))) Some(Arc::new((TokenExpander::BuiltinDerive(expander), mbe::TokenMap::default())))
} }
MacroDefKind::BuiltInEager(_expander) => None, MacroDefKind::BuiltInEager(_) => None,
MacroDefKind::CustomDerive(expander) => {
Some(Arc::new((TokenExpander::ProcMacro(expander), mbe::TokenMap::default())))
}
} }
} }

View file

@ -112,7 +112,8 @@ fn eager_macro_recur(
} }
MacroDefKind::Declarative MacroDefKind::Declarative
| MacroDefKind::BuiltIn(_) | MacroDefKind::BuiltIn(_)
| MacroDefKind::BuiltInDerive(_) => { | MacroDefKind::BuiltInDerive(_)
| MacroDefKind::CustomDerive(_) => {
let expanded = lazy_expand(db, &def, curr.with_value(child.clone()))?; let expanded = lazy_expand(db, &def, curr.with_value(child.clone()))?;
// replace macro inside // replace macro inside
eager_macro_recur(db, expanded, macro_resolver)? eager_macro_recur(db, expanded, macro_resolver)?

View file

@ -30,6 +30,7 @@ impl Hygiene {
MacroDefKind::BuiltIn(_) => None, MacroDefKind::BuiltIn(_) => None,
MacroDefKind::BuiltInDerive(_) => None, MacroDefKind::BuiltInDerive(_) => None,
MacroDefKind::BuiltInEager(_) => None, MacroDefKind::BuiltInEager(_) => None,
MacroDefKind::CustomDerive(_) => None,
} }
} }
MacroCallId::EagerMacro(_id) => None, MacroCallId::EagerMacro(_id) => None,

View file

@ -11,6 +11,7 @@ pub mod hygiene;
pub mod diagnostics; pub mod diagnostics;
pub mod builtin_derive; pub mod builtin_derive;
pub mod builtin_macro; pub mod builtin_macro;
pub mod proc_macro;
pub mod quote; pub mod quote;
pub mod eager; pub mod eager;
@ -27,6 +28,7 @@ use ra_syntax::{
use crate::ast_id_map::FileAstId; use crate::ast_id_map::FileAstId;
use crate::builtin_derive::BuiltinDeriveExpander; use crate::builtin_derive::BuiltinDeriveExpander;
use crate::builtin_macro::{BuiltinFnLikeExpander, EagerExpander}; use crate::builtin_macro::{BuiltinFnLikeExpander, EagerExpander};
use crate::proc_macro::ProcMacroExpander;
#[cfg(test)] #[cfg(test)]
mod test_db; mod test_db;
@ -217,6 +219,7 @@ pub enum MacroDefKind {
// FIXME: maybe just Builtin and rename BuiltinFnLikeExpander to BuiltinExpander // FIXME: maybe just Builtin and rename BuiltinFnLikeExpander to BuiltinExpander
BuiltInDerive(BuiltinDeriveExpander), BuiltInDerive(BuiltinDeriveExpander),
BuiltInEager(EagerExpander), BuiltInEager(EagerExpander),
CustomDerive(ProcMacroExpander),
} }
#[derive(Debug, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Clone, PartialEq, Eq, Hash)]
@ -228,21 +231,23 @@ pub struct MacroCallLoc {
#[derive(Debug, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum MacroCallKind { pub enum MacroCallKind {
FnLike(AstId<ast::MacroCall>), FnLike(AstId<ast::MacroCall>),
Attr(AstId<ast::ModuleItem>), Attr(AstId<ast::ModuleItem>, String),
} }
impl MacroCallKind { impl MacroCallKind {
pub fn file_id(&self) -> HirFileId { pub fn file_id(&self) -> HirFileId {
match self { match self {
MacroCallKind::FnLike(ast_id) => ast_id.file_id, MacroCallKind::FnLike(ast_id) => ast_id.file_id,
MacroCallKind::Attr(ast_id) => ast_id.file_id, MacroCallKind::Attr(ast_id, _) => ast_id.file_id,
} }
} }
pub fn node(&self, db: &dyn db::AstDatabase) -> InFile<SyntaxNode> { pub fn node(&self, db: &dyn db::AstDatabase) -> InFile<SyntaxNode> {
match self { match self {
MacroCallKind::FnLike(ast_id) => ast_id.with_value(ast_id.to_node(db).syntax().clone()), MacroCallKind::FnLike(ast_id) => ast_id.with_value(ast_id.to_node(db).syntax().clone()),
MacroCallKind::Attr(ast_id) => ast_id.with_value(ast_id.to_node(db).syntax().clone()), MacroCallKind::Attr(ast_id, _) => {
ast_id.with_value(ast_id.to_node(db).syntax().clone())
}
} }
} }
@ -251,7 +256,7 @@ impl MacroCallKind {
MacroCallKind::FnLike(ast_id) => { MacroCallKind::FnLike(ast_id) => {
Some(ast_id.to_node(db).token_tree()?.syntax().clone()) Some(ast_id.to_node(db).token_tree()?.syntax().clone())
} }
MacroCallKind::Attr(ast_id) => Some(ast_id.to_node(db).syntax().clone()), MacroCallKind::Attr(ast_id, _) => Some(ast_id.to_node(db).syntax().clone()),
} }
} }
} }

View file

@ -0,0 +1,33 @@
//! Proc Macro Expander stub
use crate::{db::AstDatabase, LazyMacroId, MacroCallKind, MacroCallLoc};
use ra_db::CrateId;
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
pub struct ProcMacroExpander {
krate: CrateId,
}
impl ProcMacroExpander {
pub fn new(krate: CrateId) -> ProcMacroExpander {
ProcMacroExpander { krate }
}
pub fn expand(
&self,
db: &dyn AstDatabase,
id: LazyMacroId,
_tt: &tt::Subtree,
) -> Result<tt::Subtree, mbe::ExpandError> {
let loc: MacroCallLoc = db.lookup_intern_macro(id);
let name = match loc.kind {
MacroCallKind::FnLike(_) => return Err(mbe::ExpandError::ConversionError),
MacroCallKind::Attr(_, name) => name,
};
log::debug!("Proc-macro-expanding name = {}", name);
// Return nothing for now
return Ok(tt::Subtree::default());
}
}

View file

@ -639,3 +639,22 @@ mod clone {
); );
assert_eq!("(Wrapper<S>, {unknown})", type_at_pos(&db, pos)); assert_eq!("(Wrapper<S>, {unknown})", type_at_pos(&db, pos));
} }
#[test]
fn infer_custom_derive_simple() {
// FIXME: this test current now do nothing
let (db, pos) = TestDB::with_position(
r#"
//- /main.rs crate:main
use foo::Foo;
#[derive(Foo)]
struct S{}
fn test() {
S{}<|>;
}
"#,
);
assert_eq!("S", type_at_pos(&db, pos));
}

View file

@ -33,7 +33,7 @@ impl TokenTextRange {
} }
/// Maps `tt::TokenId` to the relative range of the original token. /// Maps `tt::TokenId` to the relative range of the original token.
#[derive(Debug, PartialEq, Eq, Default)] #[derive(Debug, PartialEq, Eq, Clone, Default)]
pub struct TokenMap { pub struct TokenMap {
/// Maps `tt::TokenId` to the *relative* source range. /// Maps `tt::TokenId` to the *relative* source range.
entries: Vec<(tt::TokenId, TokenTextRange)>, entries: Vec<(tt::TokenId, TokenTextRange)>,