aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_expand
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir_expand')
-rw-r--r--crates/ra_hir_expand/src/ast_id_map.rs12
-rw-r--r--crates/ra_hir_expand/src/builtin_derive.rs301
-rw-r--r--crates/ra_hir_expand/src/builtin_macro.rs37
-rw-r--r--crates/ra_hir_expand/src/db.rs19
-rw-r--r--crates/ra_hir_expand/src/hygiene.rs3
-rw-r--r--crates/ra_hir_expand/src/lib.rs76
-rw-r--r--crates/ra_hir_expand/src/name.rs17
-rw-r--r--crates/ra_hir_expand/src/quote.rs10
8 files changed, 424 insertions, 51 deletions
diff --git a/crates/ra_hir_expand/src/ast_id_map.rs b/crates/ra_hir_expand/src/ast_id_map.rs
index cb464c3ff..a764bdf24 100644
--- a/crates/ra_hir_expand/src/ast_id_map.rs
+++ b/crates/ra_hir_expand/src/ast_id_map.rs
@@ -39,6 +39,16 @@ impl<N: AstNode> Hash for FileAstId<N> {
39 } 39 }
40} 40}
41 41
42impl<N: AstNode> FileAstId<N> {
43 // Can't make this a From implementation because of coherence
44 pub fn upcast<M: AstNode>(self) -> FileAstId<M>
45 where
46 M: From<N>,
47 {
48 FileAstId { raw: self.raw, _ty: PhantomData }
49 }
50}
51
42#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] 52#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
43struct ErasedFileAstId(RawId); 53struct ErasedFileAstId(RawId);
44impl_arena_id!(ErasedFileAstId); 54impl_arena_id!(ErasedFileAstId);
@@ -53,7 +63,7 @@ impl AstIdMap {
53 pub(crate) fn from_source(node: &SyntaxNode) -> AstIdMap { 63 pub(crate) fn from_source(node: &SyntaxNode) -> AstIdMap {
54 assert!(node.parent().is_none()); 64 assert!(node.parent().is_none());
55 let mut res = AstIdMap { arena: Arena::default() }; 65 let mut res = AstIdMap { arena: Arena::default() };
56 // By walking the tree in bread-first order we make sure that parents 66 // By walking the tree in breadth-first order we make sure that parents
57 // get lower ids then children. That is, adding a new child does not 67 // get lower ids then children. That is, adding a new child does not
58 // change parent's id. This means that, say, adding a new function to a 68 // change parent's id. This means that, say, adding a new function to a
59 // trait does not change ids of top-level items, which helps caching. 69 // trait does not change ids of top-level items, which helps caching.
diff --git a/crates/ra_hir_expand/src/builtin_derive.rs b/crates/ra_hir_expand/src/builtin_derive.rs
new file mode 100644
index 000000000..78fa9b09a
--- /dev/null
+++ b/crates/ra_hir_expand/src/builtin_derive.rs
@@ -0,0 +1,301 @@
1//! Builtin derives.
2
3use log::debug;
4
5use ra_parser::FragmentKind;
6use ra_syntax::{
7 ast::{self, AstNode, ModuleItemOwner, NameOwner, TypeParamsOwner},
8 match_ast,
9};
10
11use crate::db::AstDatabase;
12use crate::{name, quote, MacroCallId, MacroDefId, MacroDefKind};
13
14macro_rules! register_builtin {
15 ( $(($name:ident, $kind: ident) => $expand:ident),* ) => {
16 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
17 pub enum BuiltinDeriveExpander {
18 $($kind),*
19 }
20
21 impl BuiltinDeriveExpander {
22 pub fn expand(
23 &self,
24 db: &dyn AstDatabase,
25 id: MacroCallId,
26 tt: &tt::Subtree,
27 ) -> Result<tt::Subtree, mbe::ExpandError> {
28 let expander = match *self {
29 $( BuiltinDeriveExpander::$kind => $expand, )*
30 };
31 expander(db, id, tt)
32 }
33 }
34
35 pub fn find_builtin_derive(ident: &name::Name) -> Option<MacroDefId> {
36 let kind = match ident {
37 $( id if id == &name::$name => BuiltinDeriveExpander::$kind, )*
38 _ => return None,
39 };
40
41 Some(MacroDefId { krate: None, ast_id: None, kind: MacroDefKind::BuiltInDerive(kind) })
42 }
43 };
44}
45
46register_builtin! {
47 (COPY_TRAIT, Copy) => copy_expand,
48 (CLONE_TRAIT, Clone) => clone_expand,
49 (DEFAULT_TRAIT, Default) => default_expand,
50 (DEBUG_TRAIT, Debug) => debug_expand,
51 (HASH_TRAIT, Hash) => hash_expand,
52 (ORD_TRAIT, Ord) => ord_expand,
53 (PARTIAL_ORD_TRAIT, PartialOrd) => partial_ord_expand,
54 (EQ_TRAIT, Eq) => eq_expand,
55 (PARTIAL_EQ_TRAIT, PartialEq) => partial_eq_expand
56}
57
58struct BasicAdtInfo {
59 name: tt::Ident,
60 type_params: usize,
61}
62
63fn parse_adt(tt: &tt::Subtree) -> Result<BasicAdtInfo, mbe::ExpandError> {
64 let (parsed, token_map) = mbe::token_tree_to_syntax_node(tt, FragmentKind::Items)?; // FragmentKind::Items doesn't parse attrs?
65 let macro_items = ast::MacroItems::cast(parsed.syntax_node()).ok_or_else(|| {
66 debug!("derive node didn't parse");
67 mbe::ExpandError::UnexpectedToken
68 })?;
69 let item = macro_items.items().next().ok_or_else(|| {
70 debug!("no module item parsed");
71 mbe::ExpandError::NoMatchingRule
72 })?;
73 let node = item.syntax();
74 let (name, params) = match_ast! {
75 match node {
76 ast::StructDef(it) => { (it.name(), it.type_param_list()) },
77 ast::EnumDef(it) => { (it.name(), it.type_param_list()) },
78 ast::UnionDef(it) => { (it.name(), it.type_param_list()) },
79 _ => {
80 debug!("unexpected node is {:?}", node);
81 return Err(mbe::ExpandError::ConversionError)
82 },
83 }
84 };
85 let name = name.ok_or_else(|| {
86 debug!("parsed item has no name");
87 mbe::ExpandError::NoMatchingRule
88 })?;
89 let name_token_id = token_map.token_by_range(name.syntax().text_range()).ok_or_else(|| {
90 debug!("name token not found");
91 mbe::ExpandError::ConversionError
92 })?;
93 let name_token = tt::Ident { id: name_token_id, text: name.text().clone() };
94 let type_params = params.map_or(0, |type_param_list| type_param_list.type_params().count());
95 Ok(BasicAdtInfo { name: name_token, type_params })
96}
97
98fn make_type_args(n: usize, bound: Vec<tt::TokenTree>) -> Vec<tt::TokenTree> {
99 let mut result = Vec::<tt::TokenTree>::new();
100 result.push(tt::Leaf::Punct(tt::Punct { char: '<', spacing: tt::Spacing::Alone }).into());
101 for i in 0..n {
102 if i > 0 {
103 result
104 .push(tt::Leaf::Punct(tt::Punct { char: ',', spacing: tt::Spacing::Alone }).into());
105 }
106 result.push(
107 tt::Leaf::Ident(tt::Ident {
108 id: tt::TokenId::unspecified(),
109 text: format!("T{}", i).into(),
110 })
111 .into(),
112 );
113 result.extend(bound.iter().cloned());
114 }
115 result.push(tt::Leaf::Punct(tt::Punct { char: '>', spacing: tt::Spacing::Alone }).into());
116 result
117}
118
119fn expand_simple_derive(
120 tt: &tt::Subtree,
121 trait_path: tt::Subtree,
122) -> Result<tt::Subtree, mbe::ExpandError> {
123 let info = parse_adt(tt)?;
124 let name = info.name;
125 let trait_path_clone = trait_path.token_trees.clone();
126 let bound = (quote! { : ##trait_path_clone }).token_trees;
127 let type_params = make_type_args(info.type_params, bound);
128 let type_args = make_type_args(info.type_params, Vec::new());
129 let trait_path = trait_path.token_trees;
130 let expanded = quote! {
131 impl ##type_params ##trait_path for #name ##type_args {}
132 };
133 Ok(expanded)
134}
135
136fn copy_expand(
137 _db: &dyn AstDatabase,
138 _id: MacroCallId,
139 tt: &tt::Subtree,
140) -> Result<tt::Subtree, mbe::ExpandError> {
141 expand_simple_derive(tt, quote! { std::marker::Copy })
142}
143
144fn clone_expand(
145 _db: &dyn AstDatabase,
146 _id: MacroCallId,
147 tt: &tt::Subtree,
148) -> Result<tt::Subtree, mbe::ExpandError> {
149 expand_simple_derive(tt, quote! { std::clone::Clone })
150}
151
152fn default_expand(
153 _db: &dyn AstDatabase,
154 _id: MacroCallId,
155 tt: &tt::Subtree,
156) -> Result<tt::Subtree, mbe::ExpandError> {
157 expand_simple_derive(tt, quote! { std::default::Default })
158}
159
160fn debug_expand(
161 _db: &dyn AstDatabase,
162 _id: MacroCallId,
163 tt: &tt::Subtree,
164) -> Result<tt::Subtree, mbe::ExpandError> {
165 expand_simple_derive(tt, quote! { std::fmt::Debug })
166}
167
168fn hash_expand(
169 _db: &dyn AstDatabase,
170 _id: MacroCallId,
171 tt: &tt::Subtree,
172) -> Result<tt::Subtree, mbe::ExpandError> {
173 expand_simple_derive(tt, quote! { std::hash::Hash })
174}
175
176fn eq_expand(
177 _db: &dyn AstDatabase,
178 _id: MacroCallId,
179 tt: &tt::Subtree,
180) -> Result<tt::Subtree, mbe::ExpandError> {
181 expand_simple_derive(tt, quote! { std::cmp::Eq })
182}
183
184fn partial_eq_expand(
185 _db: &dyn AstDatabase,
186 _id: MacroCallId,
187 tt: &tt::Subtree,
188) -> Result<tt::Subtree, mbe::ExpandError> {
189 expand_simple_derive(tt, quote! { std::cmp::PartialEq })
190}
191
192fn ord_expand(
193 _db: &dyn AstDatabase,
194 _id: MacroCallId,
195 tt: &tt::Subtree,
196) -> Result<tt::Subtree, mbe::ExpandError> {
197 expand_simple_derive(tt, quote! { std::cmp::Ord })
198}
199
200fn partial_ord_expand(
201 _db: &dyn AstDatabase,
202 _id: MacroCallId,
203 tt: &tt::Subtree,
204) -> Result<tt::Subtree, mbe::ExpandError> {
205 expand_simple_derive(tt, quote! { std::cmp::PartialOrd })
206}
207
208#[cfg(test)]
209mod tests {
210 use super::*;
211 use crate::{test_db::TestDB, AstId, MacroCallKind, MacroCallLoc, MacroFileKind};
212 use ra_db::{fixture::WithFixture, SourceDatabase};
213
214 fn expand_builtin_derive(s: &str, expander: BuiltinDeriveExpander) -> String {
215 let (db, file_id) = TestDB::with_single_file(&s);
216 let parsed = db.parse(file_id);
217 let items: Vec<_> =
218 parsed.syntax_node().descendants().filter_map(|it| ast::ModuleItem::cast(it)).collect();
219
220 let ast_id_map = db.ast_id_map(file_id.into());
221
222 // the first one should be a macro_rules
223 let def =
224 MacroDefId { krate: None, ast_id: None, kind: MacroDefKind::BuiltInDerive(expander) };
225
226 let loc = MacroCallLoc {
227 def,
228 kind: MacroCallKind::Attr(AstId::new(file_id.into(), ast_id_map.ast_id(&items[0]))),
229 };
230
231 let id = db.intern_macro(loc);
232 let parsed = db.parse_or_expand(id.as_file(MacroFileKind::Items)).unwrap();
233
234 // FIXME text() for syntax nodes parsed from token tree looks weird
235 // because there's no whitespace, see below
236 parsed.text().to_string()
237 }
238
239 #[test]
240 fn test_copy_expand_simple() {
241 let expanded = expand_builtin_derive(
242 r#"
243 #[derive(Copy)]
244 struct Foo;
245"#,
246 BuiltinDeriveExpander::Copy,
247 );
248
249 assert_eq!(expanded, "impl <>std::marker::CopyforFoo <>{}");
250 }
251
252 #[test]
253 fn test_copy_expand_with_type_params() {
254 let expanded = expand_builtin_derive(
255 r#"
256 #[derive(Copy)]
257 struct Foo<A, B>;
258"#,
259 BuiltinDeriveExpander::Copy,
260 );
261
262 assert_eq!(
263 expanded,
264 "impl<T0:std::marker::Copy,T1:std::marker::Copy>std::marker::CopyforFoo<T0,T1>{}"
265 );
266 }
267
268 #[test]
269 fn test_copy_expand_with_lifetimes() {
270 let expanded = expand_builtin_derive(
271 r#"
272 #[derive(Copy)]
273 struct Foo<A, B, 'a, 'b>;
274"#,
275 BuiltinDeriveExpander::Copy,
276 );
277
278 // We currently just ignore lifetimes
279
280 assert_eq!(
281 expanded,
282 "impl<T0:std::marker::Copy,T1:std::marker::Copy>std::marker::CopyforFoo<T0,T1>{}"
283 );
284 }
285
286 #[test]
287 fn test_clone_expand() {
288 let expanded = expand_builtin_derive(
289 r#"
290 #[derive(Clone)]
291 struct Foo<A, B>;
292"#,
293 BuiltinDeriveExpander::Clone,
294 );
295
296 assert_eq!(
297 expanded,
298 "impl<T0:std::clone::Clone,T1:std::clone::Clone>std::clone::CloneforFoo<T0,T1>{}"
299 );
300 }
301}
diff --git a/crates/ra_hir_expand/src/builtin_macro.rs b/crates/ra_hir_expand/src/builtin_macro.rs
index d370dfb34..35f99b2bc 100644
--- a/crates/ra_hir_expand/src/builtin_macro.rs
+++ b/crates/ra_hir_expand/src/builtin_macro.rs
@@ -39,7 +39,7 @@ macro_rules! register_builtin {
39 _ => return None, 39 _ => return None,
40 }; 40 };
41 41
42 Some(MacroDefId { krate, ast_id, kind: MacroDefKind::BuiltIn(kind) }) 42 Some(MacroDefId { krate: Some(krate), ast_id: Some(ast_id), kind: MacroDefKind::BuiltIn(kind) })
43 } 43 }
44 }; 44 };
45} 45}
@@ -82,10 +82,9 @@ fn line_expand(
82 _tt: &tt::Subtree, 82 _tt: &tt::Subtree,
83) -> Result<tt::Subtree, mbe::ExpandError> { 83) -> Result<tt::Subtree, mbe::ExpandError> {
84 let loc = db.lookup_intern_macro(id); 84 let loc = db.lookup_intern_macro(id);
85 let macro_call = loc.ast_id.to_node(db);
86 85
87 let arg = macro_call.token_tree().ok_or_else(|| mbe::ExpandError::UnexpectedToken)?; 86 let arg = loc.kind.arg(db).ok_or_else(|| mbe::ExpandError::UnexpectedToken)?;
88 let arg_start = arg.syntax().text_range().start(); 87 let arg_start = arg.text_range().start();
89 88
90 let file = id.as_file(MacroFileKind::Expr); 89 let file = id.as_file(MacroFileKind::Expr);
91 let line_num = to_line_number(db, file, arg_start); 90 let line_num = to_line_number(db, file, arg_start);
@@ -103,11 +102,10 @@ fn stringify_expand(
103 _tt: &tt::Subtree, 102 _tt: &tt::Subtree,
104) -> Result<tt::Subtree, mbe::ExpandError> { 103) -> Result<tt::Subtree, mbe::ExpandError> {
105 let loc = db.lookup_intern_macro(id); 104 let loc = db.lookup_intern_macro(id);
106 let macro_call = loc.ast_id.to_node(db);
107 105
108 let macro_content = { 106 let macro_content = {
109 let arg = macro_call.token_tree().ok_or_else(|| mbe::ExpandError::UnexpectedToken)?; 107 let arg = loc.kind.arg(db).ok_or_else(|| mbe::ExpandError::UnexpectedToken)?;
110 let macro_args = arg.syntax().clone(); 108 let macro_args = arg.clone();
111 let text = macro_args.text(); 109 let text = macro_args.text();
112 let without_parens = TextUnit::of_char('(')..text.len() - TextUnit::of_char(')'); 110 let without_parens = TextUnit::of_char('(')..text.len() - TextUnit::of_char(')');
113 text.slice(without_parens).to_string() 111 text.slice(without_parens).to_string()
@@ -148,7 +146,10 @@ fn column_expand(
148 _tt: &tt::Subtree, 146 _tt: &tt::Subtree,
149) -> Result<tt::Subtree, mbe::ExpandError> { 147) -> Result<tt::Subtree, mbe::ExpandError> {
150 let loc = db.lookup_intern_macro(id); 148 let loc = db.lookup_intern_macro(id);
151 let macro_call = loc.ast_id.to_node(db); 149 let macro_call = match loc.kind {
150 crate::MacroCallKind::FnLike(ast_id) => ast_id.to_node(db),
151 _ => panic!("column macro called as attr"),
152 };
152 153
153 let _arg = macro_call.token_tree().ok_or_else(|| mbe::ExpandError::UnexpectedToken)?; 154 let _arg = macro_call.token_tree().ok_or_else(|| mbe::ExpandError::UnexpectedToken)?;
154 let col_start = macro_call.syntax().text_range().start(); 155 let col_start = macro_call.syntax().text_range().start();
@@ -164,15 +165,10 @@ fn column_expand(
164} 165}
165 166
166fn file_expand( 167fn file_expand(
167 db: &dyn AstDatabase, 168 _db: &dyn AstDatabase,
168 id: MacroCallId, 169 _id: MacroCallId,
169 _tt: &tt::Subtree, 170 _tt: &tt::Subtree,
170) -> Result<tt::Subtree, mbe::ExpandError> { 171) -> Result<tt::Subtree, mbe::ExpandError> {
171 let loc = db.lookup_intern_macro(id);
172 let macro_call = loc.ast_id.to_node(db);
173
174 let _ = macro_call.token_tree().ok_or_else(|| mbe::ExpandError::UnexpectedToken)?;
175
176 // FIXME: RA purposefully lacks knowledge of absolute file names 172 // FIXME: RA purposefully lacks knowledge of absolute file names
177 // so just return "". 173 // so just return "".
178 let file_name = ""; 174 let file_name = "";
@@ -207,7 +203,7 @@ fn compile_error_expand(
207#[cfg(test)] 203#[cfg(test)]
208mod tests { 204mod tests {
209 use super::*; 205 use super::*;
210 use crate::{test_db::TestDB, MacroCallLoc}; 206 use crate::{test_db::TestDB, MacroCallKind, MacroCallLoc};
211 use ra_db::{fixture::WithFixture, SourceDatabase}; 207 use ra_db::{fixture::WithFixture, SourceDatabase};
212 208
213 fn expand_builtin_macro(s: &str, expander: BuiltinFnLikeExpander) -> String { 209 fn expand_builtin_macro(s: &str, expander: BuiltinFnLikeExpander) -> String {
@@ -220,14 +216,17 @@ mod tests {
220 216
221 // the first one should be a macro_rules 217 // the first one should be a macro_rules
222 let def = MacroDefId { 218 let def = MacroDefId {
223 krate: CrateId(0), 219 krate: Some(CrateId(0)),
224 ast_id: AstId::new(file_id.into(), ast_id_map.ast_id(&macro_calls[0])), 220 ast_id: Some(AstId::new(file_id.into(), ast_id_map.ast_id(&macro_calls[0]))),
225 kind: MacroDefKind::BuiltIn(expander), 221 kind: MacroDefKind::BuiltIn(expander),
226 }; 222 };
227 223
228 let loc = MacroCallLoc { 224 let loc = MacroCallLoc {
229 def, 225 def,
230 ast_id: AstId::new(file_id.into(), ast_id_map.ast_id(&macro_calls[1])), 226 kind: MacroCallKind::FnLike(AstId::new(
227 file_id.into(),
228 ast_id_map.ast_id(&macro_calls[1]),
229 )),
231 }; 230 };
232 231
233 let id = db.intern_macro(loc); 232 let id = db.intern_macro(loc);
diff --git a/crates/ra_hir_expand/src/db.rs b/crates/ra_hir_expand/src/db.rs
index 8e46fa177..99dabf3fb 100644
--- a/crates/ra_hir_expand/src/db.rs
+++ b/crates/ra_hir_expand/src/db.rs
@@ -9,14 +9,15 @@ use ra_prof::profile;
9use ra_syntax::{AstNode, Parse, SyntaxNode}; 9use ra_syntax::{AstNode, Parse, SyntaxNode};
10 10
11use crate::{ 11use crate::{
12 ast_id_map::AstIdMap, BuiltinFnLikeExpander, HirFileId, HirFileIdRepr, MacroCallId, 12 ast_id_map::AstIdMap, BuiltinDeriveExpander, BuiltinFnLikeExpander, HirFileId, HirFileIdRepr,
13 MacroCallLoc, MacroDefId, MacroDefKind, MacroFile, MacroFileKind, 13 MacroCallId, MacroCallLoc, MacroDefId, MacroDefKind, MacroFile, MacroFileKind,
14}; 14};
15 15
16#[derive(Debug, Clone, Eq, PartialEq)] 16#[derive(Debug, Clone, Eq, PartialEq)]
17pub enum TokenExpander { 17pub enum TokenExpander {
18 MacroRules(mbe::MacroRules), 18 MacroRules(mbe::MacroRules),
19 Builtin(BuiltinFnLikeExpander), 19 Builtin(BuiltinFnLikeExpander),
20 BuiltinDerive(BuiltinDeriveExpander),
20} 21}
21 22
22impl TokenExpander { 23impl TokenExpander {
@@ -29,6 +30,7 @@ impl TokenExpander {
29 match self { 30 match self {
30 TokenExpander::MacroRules(it) => it.expand(tt), 31 TokenExpander::MacroRules(it) => it.expand(tt),
31 TokenExpander::Builtin(it) => it.expand(db, id, tt), 32 TokenExpander::Builtin(it) => it.expand(db, id, tt),
33 TokenExpander::BuiltinDerive(it) => it.expand(db, id, tt),
32 } 34 }
33 } 35 }
34 36
@@ -36,6 +38,7 @@ impl TokenExpander {
36 match self { 38 match self {
37 TokenExpander::MacroRules(it) => it.map_id_down(id), 39 TokenExpander::MacroRules(it) => it.map_id_down(id),
38 TokenExpander::Builtin(..) => id, 40 TokenExpander::Builtin(..) => id,
41 TokenExpander::BuiltinDerive(..) => id,
39 } 42 }
40 } 43 }
41 44
@@ -43,6 +46,7 @@ impl TokenExpander {
43 match self { 46 match self {
44 TokenExpander::MacroRules(it) => it.map_id_up(id), 47 TokenExpander::MacroRules(it) => it.map_id_up(id),
45 TokenExpander::Builtin(..) => (id, mbe::Origin::Def), 48 TokenExpander::Builtin(..) => (id, mbe::Origin::Def),
49 TokenExpander::BuiltinDerive(..) => (id, mbe::Origin::Def),
46 } 50 }
47 } 51 }
48} 52}
@@ -76,7 +80,7 @@ pub(crate) fn macro_def(
76) -> Option<Arc<(TokenExpander, mbe::TokenMap)>> { 80) -> Option<Arc<(TokenExpander, mbe::TokenMap)>> {
77 match id.kind { 81 match id.kind {
78 MacroDefKind::Declarative => { 82 MacroDefKind::Declarative => {
79 let macro_call = id.ast_id.to_node(db); 83 let macro_call = id.ast_id?.to_node(db);
80 let arg = macro_call.token_tree()?; 84 let arg = macro_call.token_tree()?;
81 let (tt, tmap) = mbe::ast_to_token_tree(&arg).or_else(|| { 85 let (tt, tmap) = mbe::ast_to_token_tree(&arg).or_else(|| {
82 log::warn!("fail on macro_def to token tree: {:#?}", arg); 86 log::warn!("fail on macro_def to token tree: {:#?}", arg);
@@ -91,6 +95,10 @@ pub(crate) fn macro_def(
91 MacroDefKind::BuiltIn(expander) => { 95 MacroDefKind::BuiltIn(expander) => {
92 Some(Arc::new((TokenExpander::Builtin(expander.clone()), mbe::TokenMap::default()))) 96 Some(Arc::new((TokenExpander::Builtin(expander.clone()), mbe::TokenMap::default())))
93 } 97 }
98 MacroDefKind::BuiltInDerive(expander) => Some(Arc::new((
99 TokenExpander::BuiltinDerive(expander.clone()),
100 mbe::TokenMap::default(),
101 ))),
94 } 102 }
95} 103}
96 104
@@ -99,9 +107,8 @@ pub(crate) fn macro_arg(
99 id: MacroCallId, 107 id: MacroCallId,
100) -> Option<Arc<(tt::Subtree, mbe::TokenMap)>> { 108) -> Option<Arc<(tt::Subtree, mbe::TokenMap)>> {
101 let loc = db.lookup_intern_macro(id); 109 let loc = db.lookup_intern_macro(id);
102 let macro_call = loc.ast_id.to_node(db); 110 let arg = loc.kind.arg(db)?;
103 let arg = macro_call.token_tree()?; 111 let (tt, tmap) = mbe::syntax_node_to_token_tree(&arg)?;
104 let (tt, tmap) = mbe::ast_to_token_tree(&arg)?;
105 Some(Arc::new((tt, tmap))) 112 Some(Arc::new((tt, tmap)))
106} 113}
107 114
diff --git a/crates/ra_hir_expand/src/hygiene.rs b/crates/ra_hir_expand/src/hygiene.rs
index 64c8b06c6..2e8a533f7 100644
--- a/crates/ra_hir_expand/src/hygiene.rs
+++ b/crates/ra_hir_expand/src/hygiene.rs
@@ -25,8 +25,9 @@ impl Hygiene {
25 HirFileIdRepr::MacroFile(macro_file) => { 25 HirFileIdRepr::MacroFile(macro_file) => {
26 let loc = db.lookup_intern_macro(macro_file.macro_call_id); 26 let loc = db.lookup_intern_macro(macro_file.macro_call_id);
27 match loc.def.kind { 27 match loc.def.kind {
28 MacroDefKind::Declarative => Some(loc.def.krate), 28 MacroDefKind::Declarative => loc.def.krate,
29 MacroDefKind::BuiltIn(_) => None, 29 MacroDefKind::BuiltIn(_) => None,
30 MacroDefKind::BuiltInDerive(_) => None,
30 } 31 }
31 } 32 }
32 }; 33 };
diff --git a/crates/ra_hir_expand/src/lib.rs b/crates/ra_hir_expand/src/lib.rs
index 3be9bdf86..59c69b91b 100644
--- a/crates/ra_hir_expand/src/lib.rs
+++ b/crates/ra_hir_expand/src/lib.rs
@@ -9,6 +9,7 @@ pub mod ast_id_map;
9pub mod name; 9pub mod name;
10pub mod hygiene; 10pub mod hygiene;
11pub mod diagnostics; 11pub mod diagnostics;
12pub mod builtin_derive;
12pub mod builtin_macro; 13pub mod builtin_macro;
13pub mod quote; 14pub mod quote;
14 15
@@ -23,6 +24,7 @@ use ra_syntax::{
23}; 24};
24 25
25use crate::ast_id_map::FileAstId; 26use crate::ast_id_map::FileAstId;
27use crate::builtin_derive::BuiltinDeriveExpander;
26use crate::builtin_macro::BuiltinFnLikeExpander; 28use crate::builtin_macro::BuiltinFnLikeExpander;
27 29
28#[cfg(test)] 30#[cfg(test)]
@@ -69,7 +71,7 @@ impl HirFileId {
69 HirFileIdRepr::FileId(file_id) => file_id, 71 HirFileIdRepr::FileId(file_id) => file_id,
70 HirFileIdRepr::MacroFile(macro_file) => { 72 HirFileIdRepr::MacroFile(macro_file) => {
71 let loc = db.lookup_intern_macro(macro_file.macro_call_id); 73 let loc = db.lookup_intern_macro(macro_file.macro_call_id);
72 loc.ast_id.file_id.original_file(db) 74 loc.kind.file_id().original_file(db)
73 } 75 }
74 } 76 }
75 } 77 }
@@ -81,8 +83,8 @@ impl HirFileId {
81 HirFileIdRepr::MacroFile(macro_file) => { 83 HirFileIdRepr::MacroFile(macro_file) => {
82 let loc: MacroCallLoc = db.lookup_intern_macro(macro_file.macro_call_id); 84 let loc: MacroCallLoc = db.lookup_intern_macro(macro_file.macro_call_id);
83 85
84 let arg_tt = loc.ast_id.to_node(db).token_tree()?; 86 let arg_tt = loc.kind.arg(db)?;
85 let def_tt = loc.def.ast_id.to_node(db).token_tree()?; 87 let def_tt = loc.def.ast_id?.to_node(db).token_tree()?;
86 88
87 let macro_def = db.macro_def(loc.def)?; 89 let macro_def = db.macro_def(loc.def)?;
88 let (parse, exp_map) = db.parse_macro(macro_file)?; 90 let (parse, exp_map) = db.parse_macro(macro_file)?;
@@ -90,8 +92,8 @@ impl HirFileId {
90 92
91 Some(ExpansionInfo { 93 Some(ExpansionInfo {
92 expanded: InFile::new(self, parse.syntax_node()), 94 expanded: InFile::new(self, parse.syntax_node()),
93 arg: InFile::new(loc.ast_id.file_id, arg_tt), 95 arg: InFile::new(loc.kind.file_id(), arg_tt),
94 def: InFile::new(loc.ast_id.file_id, def_tt), 96 def: InFile::new(loc.def.ast_id?.file_id, def_tt),
95 macro_arg, 97 macro_arg,
96 macro_def, 98 macro_def,
97 exp_map, 99 exp_map,
@@ -129,18 +131,20 @@ impl salsa::InternKey for MacroCallId {
129 131
130#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 132#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
131pub struct MacroDefId { 133pub struct MacroDefId {
132 pub krate: CrateId, 134 // FIXME: krate and ast_id are currently optional because we don't have a
133 pub ast_id: AstId<ast::MacroCall>, 135 // definition location for built-in derives. There is one, though: the
136 // standard library defines them. The problem is that it uses the new
137 // `macro` syntax for this, which we don't support yet. As soon as we do
138 // (which will probably require touching this code), we can instead use
139 // that (and also remove the hacks for resolving built-in derives).
140 pub krate: Option<CrateId>,
141 pub ast_id: Option<AstId<ast::MacroCall>>,
134 pub kind: MacroDefKind, 142 pub kind: MacroDefKind,
135} 143}
136 144
137impl MacroDefId { 145impl MacroDefId {
138 pub fn as_call_id( 146 pub fn as_call_id(self, db: &dyn db::AstDatabase, kind: MacroCallKind) -> MacroCallId {
139 self, 147 db.intern_macro(MacroCallLoc { def: self, kind })
140 db: &dyn db::AstDatabase,
141 ast_id: AstId<ast::MacroCall>,
142 ) -> MacroCallId {
143 db.intern_macro(MacroCallLoc { def: self, ast_id })
144 } 148 }
145} 149}
146 150
@@ -148,12 +152,38 @@ impl MacroDefId {
148pub enum MacroDefKind { 152pub enum MacroDefKind {
149 Declarative, 153 Declarative,
150 BuiltIn(BuiltinFnLikeExpander), 154 BuiltIn(BuiltinFnLikeExpander),
155 // FIXME: maybe just Builtin and rename BuiltinFnLikeExpander to BuiltinExpander
156 BuiltInDerive(BuiltinDeriveExpander),
151} 157}
152 158
153#[derive(Debug, Clone, PartialEq, Eq, Hash)] 159#[derive(Debug, Clone, PartialEq, Eq, Hash)]
154pub struct MacroCallLoc { 160pub struct MacroCallLoc {
155 pub(crate) def: MacroDefId, 161 pub(crate) def: MacroDefId,
156 pub(crate) ast_id: AstId<ast::MacroCall>, 162 pub(crate) kind: MacroCallKind,
163}
164
165#[derive(Debug, Clone, PartialEq, Eq, Hash)]
166pub enum MacroCallKind {
167 FnLike(AstId<ast::MacroCall>),
168 Attr(AstId<ast::ModuleItem>),
169}
170
171impl MacroCallKind {
172 pub fn file_id(&self) -> HirFileId {
173 match self {
174 MacroCallKind::FnLike(ast_id) => ast_id.file_id,
175 MacroCallKind::Attr(ast_id) => ast_id.file_id,
176 }
177 }
178
179 pub fn arg(&self, db: &dyn db::AstDatabase) -> Option<SyntaxNode> {
180 match self {
181 MacroCallKind::FnLike(ast_id) => {
182 Some(ast_id.to_node(db).token_tree()?.syntax().clone())
183 }
184 MacroCallKind::Attr(ast_id) => Some(ast_id.to_node(db).syntax().clone()),
185 }
186 }
157} 187}
158 188
159impl MacroCallId { 189impl MacroCallId {
@@ -167,7 +197,7 @@ impl MacroCallId {
167#[derive(Debug, Clone, PartialEq, Eq)] 197#[derive(Debug, Clone, PartialEq, Eq)]
168pub struct ExpansionInfo { 198pub struct ExpansionInfo {
169 expanded: InFile<SyntaxNode>, 199 expanded: InFile<SyntaxNode>,
170 arg: InFile<ast::TokenTree>, 200 arg: InFile<SyntaxNode>,
171 def: InFile<ast::TokenTree>, 201 def: InFile<ast::TokenTree>,
172 202
173 macro_def: Arc<(db::TokenExpander, mbe::TokenMap)>, 203 macro_def: Arc<(db::TokenExpander, mbe::TokenMap)>,
@@ -178,8 +208,7 @@ pub struct ExpansionInfo {
178impl ExpansionInfo { 208impl ExpansionInfo {
179 pub fn map_token_down(&self, token: InFile<&SyntaxToken>) -> Option<InFile<SyntaxToken>> { 209 pub fn map_token_down(&self, token: InFile<&SyntaxToken>) -> Option<InFile<SyntaxToken>> {
180 assert_eq!(token.file_id, self.arg.file_id); 210 assert_eq!(token.file_id, self.arg.file_id);
181 let range = 211 let range = token.value.text_range().checked_sub(self.arg.value.text_range().start())?;
182 token.value.text_range().checked_sub(self.arg.value.syntax().text_range().start())?;
183 let token_id = self.macro_arg.1.token_by_range(range)?; 212 let token_id = self.macro_arg.1.token_by_range(range)?;
184 let token_id = self.macro_def.0.map_id_down(token_id); 213 let token_id = self.macro_def.0.map_id_down(token_id);
185 214
@@ -195,16 +224,15 @@ impl ExpansionInfo {
195 224
196 let (token_id, origin) = self.macro_def.0.map_id_up(token_id); 225 let (token_id, origin) = self.macro_def.0.map_id_up(token_id);
197 let (token_map, tt) = match origin { 226 let (token_map, tt) = match origin {
198 mbe::Origin::Call => (&self.macro_arg.1, &self.arg), 227 mbe::Origin::Call => (&self.macro_arg.1, self.arg.clone()),
199 mbe::Origin::Def => (&self.macro_def.1, &self.def), 228 mbe::Origin::Def => {
229 (&self.macro_def.1, self.def.as_ref().map(|tt| tt.syntax().clone()))
230 }
200 }; 231 };
201 232
202 let range = token_map.range_by_token(token_id)?; 233 let range = token_map.range_by_token(token_id)?;
203 let token = algo::find_covering_element( 234 let token = algo::find_covering_element(&tt.value, range + tt.value.text_range().start())
204 tt.value.syntax(), 235 .into_token()?;
205 range + tt.value.syntax().text_range().start(),
206 )
207 .into_token()?;
208 Some(tt.with_value(token)) 236 Some(tt.with_value(token))
209 } 237 }
210} 238}
diff --git a/crates/ra_hir_expand/src/name.rs b/crates/ra_hir_expand/src/name.rs
index 05ba37070..c5a191160 100644
--- a/crates/ra_hir_expand/src/name.rs
+++ b/crates/ra_hir_expand/src/name.rs
@@ -83,6 +83,12 @@ impl AsName for ast::Name {
83 } 83 }
84} 84}
85 85
86impl AsName for tt::Ident {
87 fn as_name(&self) -> Name {
88 Name::resolve(&self.text)
89 }
90}
91
86impl AsName for ast::FieldKind { 92impl AsName for ast::FieldKind {
87 fn as_name(&self) -> Name { 93 fn as_name(&self) -> Name {
88 match self { 94 match self {
@@ -153,3 +159,14 @@ pub const COLUMN_MACRO: Name = Name::new_inline_ascii(6, b"column");
153pub const COMPILE_ERROR_MACRO: Name = Name::new_inline_ascii(13, b"compile_error"); 159pub const COMPILE_ERROR_MACRO: Name = Name::new_inline_ascii(13, b"compile_error");
154pub const LINE_MACRO: Name = Name::new_inline_ascii(4, b"line"); 160pub const LINE_MACRO: Name = Name::new_inline_ascii(4, b"line");
155pub const STRINGIFY_MACRO: Name = Name::new_inline_ascii(9, b"stringify"); 161pub const STRINGIFY_MACRO: Name = Name::new_inline_ascii(9, b"stringify");
162
163// Builtin derives
164pub const COPY_TRAIT: Name = Name::new_inline_ascii(4, b"Copy");
165pub const CLONE_TRAIT: Name = Name::new_inline_ascii(5, b"Clone");
166pub const DEFAULT_TRAIT: Name = Name::new_inline_ascii(7, b"Default");
167pub const DEBUG_TRAIT: Name = Name::new_inline_ascii(5, b"Debug");
168pub const HASH_TRAIT: Name = Name::new_inline_ascii(4, b"Hash");
169pub const ORD_TRAIT: Name = Name::new_inline_ascii(3, b"Ord");
170pub const PARTIAL_ORD_TRAIT: Name = Name::new_inline_ascii(10, b"PartialOrd");
171pub const EQ_TRAIT: Name = Name::new_inline_ascii(2, b"Eq");
172pub const PARTIAL_EQ_TRAIT: Name = Name::new_inline_ascii(9, b"PartialEq");
diff --git a/crates/ra_hir_expand/src/quote.rs b/crates/ra_hir_expand/src/quote.rs
index 65a35e52f..4f698ff13 100644
--- a/crates/ra_hir_expand/src/quote.rs
+++ b/crates/ra_hir_expand/src/quote.rs
@@ -60,6 +60,15 @@ macro_rules! __quote {
60 } 60 }
61 }; 61 };
62 62
63 ( ## $first:ident $($tail:tt)* ) => {
64 {
65 let mut tokens = $first.into_iter().map($crate::quote::ToTokenTree::to_token).collect::<Vec<tt::TokenTree>>();
66 let mut tail_tokens = $crate::quote::IntoTt::to_tokens($crate::__quote!($($tail)*));
67 tokens.append(&mut tail_tokens);
68 tokens
69 }
70 };
71
63 // Brace 72 // Brace
64 ( { $($tt:tt)* } ) => { $crate::__quote!(@SUBTREE Brace $($tt)*) }; 73 ( { $($tt:tt)* } ) => { $crate::__quote!(@SUBTREE Brace $($tt)*) };
65 // Bracket 74 // Bracket
@@ -85,6 +94,7 @@ macro_rules! __quote {
85 ( & ) => {$crate::__quote!(@PUNCT '&')}; 94 ( & ) => {$crate::__quote!(@PUNCT '&')};
86 ( , ) => {$crate::__quote!(@PUNCT ',')}; 95 ( , ) => {$crate::__quote!(@PUNCT ',')};
87 ( : ) => {$crate::__quote!(@PUNCT ':')}; 96 ( : ) => {$crate::__quote!(@PUNCT ':')};
97 ( :: ) => {$crate::__quote!(@PUNCT ':', ':')};
88 ( . ) => {$crate::__quote!(@PUNCT '.')}; 98 ( . ) => {$crate::__quote!(@PUNCT '.')};
89 99
90 ( $first:tt $($tail:tt)+ ) => { 100 ( $first:tt $($tail:tt)+ ) => {