diff options
Diffstat (limited to 'crates/hir_expand/src')
-rw-r--r-- | crates/hir_expand/src/ast_id_map.rs | 24 | ||||
-rw-r--r-- | crates/hir_expand/src/builtin_derive.rs | 2 | ||||
-rw-r--r-- | crates/hir_expand/src/builtin_macro.rs | 90 | ||||
-rw-r--r-- | crates/hir_expand/src/db.rs | 2 | ||||
-rw-r--r-- | crates/hir_expand/src/name.rs | 12 |
5 files changed, 64 insertions, 66 deletions
diff --git a/crates/hir_expand/src/ast_id_map.rs b/crates/hir_expand/src/ast_id_map.rs index 2401b0cc5..16cf29907 100644 --- a/crates/hir_expand/src/ast_id_map.rs +++ b/crates/hir_expand/src/ast_id_map.rs | |||
@@ -13,7 +13,8 @@ use std::{ | |||
13 | }; | 13 | }; |
14 | 14 | ||
15 | use la_arena::{Arena, Idx}; | 15 | use la_arena::{Arena, Idx}; |
16 | use syntax::{ast, AstNode, AstPtr, SyntaxNode, SyntaxNodePtr}; | 16 | use profile::Count; |
17 | use syntax::{ast, match_ast, AstNode, AstPtr, SyntaxNode, SyntaxNodePtr}; | ||
17 | 18 | ||
18 | /// `AstId` points to an AST node in a specific file. | 19 | /// `AstId` points to an AST node in a specific file. |
19 | pub struct FileAstId<N: AstNode> { | 20 | pub struct FileAstId<N: AstNode> { |
@@ -62,22 +63,31 @@ type ErasedFileAstId = Idx<SyntaxNodePtr>; | |||
62 | #[derive(Debug, PartialEq, Eq, Default)] | 63 | #[derive(Debug, PartialEq, Eq, Default)] |
63 | pub struct AstIdMap { | 64 | pub struct AstIdMap { |
64 | arena: Arena<SyntaxNodePtr>, | 65 | arena: Arena<SyntaxNodePtr>, |
66 | _c: Count<Self>, | ||
65 | } | 67 | } |
66 | 68 | ||
67 | impl AstIdMap { | 69 | impl AstIdMap { |
68 | pub(crate) fn from_source(node: &SyntaxNode) -> AstIdMap { | 70 | pub(crate) fn from_source(node: &SyntaxNode) -> AstIdMap { |
69 | assert!(node.parent().is_none()); | 71 | assert!(node.parent().is_none()); |
70 | let mut res = AstIdMap { arena: Arena::default() }; | 72 | let mut res = AstIdMap::default(); |
71 | // By walking the tree in breadth-first order we make sure that parents | 73 | // By walking the tree in breadth-first order we make sure that parents |
72 | // get lower ids then children. That is, adding a new child does not | 74 | // get lower ids then children. That is, adding a new child does not |
73 | // change parent's id. This means that, say, adding a new function to a | 75 | // change parent's id. This means that, say, adding a new function to a |
74 | // trait does not change ids of top-level items, which helps caching. | 76 | // trait does not change ids of top-level items, which helps caching. |
75 | bdfs(node, |it| match ast::Item::cast(it) { | 77 | bdfs(node, |it| { |
76 | Some(module_item) => { | 78 | match_ast! { |
77 | res.alloc(module_item.syntax()); | 79 | match it { |
78 | true | 80 | ast::Item(module_item) => { |
81 | res.alloc(module_item.syntax()); | ||
82 | true | ||
83 | }, | ||
84 | ast::BlockExpr(block) => { | ||
85 | res.alloc(block.syntax()); | ||
86 | true | ||
87 | }, | ||
88 | _ => false, | ||
89 | } | ||
79 | } | 90 | } |
80 | None => false, | ||
81 | }); | 91 | }); |
82 | res | 92 | res |
83 | } | 93 | } |
diff --git a/crates/hir_expand/src/builtin_derive.rs b/crates/hir_expand/src/builtin_derive.rs index eb257579f..b7f1aae8f 100644 --- a/crates/hir_expand/src/builtin_derive.rs +++ b/crates/hir_expand/src/builtin_derive.rs | |||
@@ -102,7 +102,7 @@ fn parse_adt(tt: &tt::Subtree) -> Result<BasicAdtInfo, mbe::ExpandError> { | |||
102 | debug!("name token not found"); | 102 | debug!("name token not found"); |
103 | mbe::ExpandError::ConversionError | 103 | mbe::ExpandError::ConversionError |
104 | })?; | 104 | })?; |
105 | let name_token = tt::Ident { id: name_token_id, text: name.text().clone() }; | 105 | let name_token = tt::Ident { id: name_token_id, text: name.text().into() }; |
106 | let type_params = params.map_or(0, |type_param_list| type_param_list.type_params().count()); | 106 | let type_params = params.map_or(0, |type_param_list| type_param_list.type_params().count()); |
107 | Ok(BasicAdtInfo { name: name_token, type_params }) | 107 | Ok(BasicAdtInfo { name: name_token, type_params }) |
108 | } | 108 | } |
diff --git a/crates/hir_expand/src/builtin_macro.rs b/crates/hir_expand/src/builtin_macro.rs index 80b60d59f..eb57ea7d6 100644 --- a/crates/hir_expand/src/builtin_macro.rs +++ b/crates/hir_expand/src/builtin_macro.rs | |||
@@ -6,7 +6,7 @@ use crate::{ | |||
6 | 6 | ||
7 | use base_db::{AnchoredPath, FileId}; | 7 | use base_db::{AnchoredPath, FileId}; |
8 | use either::Either; | 8 | use either::Either; |
9 | use mbe::{parse_to_token_tree, ExpandResult}; | 9 | use mbe::{parse_exprs_with_sep, parse_to_token_tree, ExpandResult}; |
10 | use parser::FragmentKind; | 10 | use parser::FragmentKind; |
11 | use syntax::ast::{self, AstToken}; | 11 | use syntax::ast::{self, AstToken}; |
12 | 12 | ||
@@ -182,25 +182,10 @@ fn assert_expand( | |||
182 | // ```, | 182 | // ```, |
183 | // which is wrong but useful. | 183 | // which is wrong but useful. |
184 | 184 | ||
185 | let mut args = Vec::new(); | 185 | let args = parse_exprs_with_sep(tt, ','); |
186 | let mut current = Vec::new(); | ||
187 | for tt in tt.token_trees.iter().cloned() { | ||
188 | match tt { | ||
189 | tt::TokenTree::Leaf(tt::Leaf::Punct(p)) if p.char == ',' => { | ||
190 | args.push(current); | ||
191 | current = Vec::new(); | ||
192 | } | ||
193 | _ => { | ||
194 | current.push(tt); | ||
195 | } | ||
196 | } | ||
197 | } | ||
198 | if !current.is_empty() { | ||
199 | args.push(current); | ||
200 | } | ||
201 | 186 | ||
202 | let arg_tts = args.into_iter().flat_map(|arg| { | 187 | let arg_tts = args.into_iter().flat_map(|arg| { |
203 | quote! { &(##arg), } | 188 | quote! { &(#arg), } |
204 | }.token_trees).collect::<Vec<_>>(); | 189 | }.token_trees).collect::<Vec<_>>(); |
205 | 190 | ||
206 | let expanded = quote! { | 191 | let expanded = quote! { |
@@ -238,35 +223,21 @@ fn format_args_expand( | |||
238 | // ]) | 223 | // ]) |
239 | // ```, | 224 | // ```, |
240 | // which is still not really correct, but close enough for now | 225 | // which is still not really correct, but close enough for now |
241 | let mut args = Vec::new(); | 226 | let mut args = parse_exprs_with_sep(tt, ','); |
242 | let mut current = Vec::new(); | 227 | |
243 | for tt in tt.token_trees.iter().cloned() { | ||
244 | match tt { | ||
245 | tt::TokenTree::Leaf(tt::Leaf::Punct(p)) if p.char == ',' => { | ||
246 | args.push(current); | ||
247 | current = Vec::new(); | ||
248 | } | ||
249 | _ => { | ||
250 | current.push(tt); | ||
251 | } | ||
252 | } | ||
253 | } | ||
254 | if !current.is_empty() { | ||
255 | args.push(current); | ||
256 | } | ||
257 | if args.is_empty() { | 228 | if args.is_empty() { |
258 | return ExpandResult::only_err(mbe::ExpandError::NoMatchingRule); | 229 | return ExpandResult::only_err(mbe::ExpandError::NoMatchingRule); |
259 | } | 230 | } |
260 | for arg in &mut args { | 231 | for arg in &mut args { |
261 | // Remove `key =`. | 232 | // Remove `key =`. |
262 | if matches!(arg.get(1), Some(tt::TokenTree::Leaf(tt::Leaf::Punct(p))) if p.char == '=' && p.spacing != tt::Spacing::Joint) | 233 | if matches!(arg.token_trees.get(1), Some(tt::TokenTree::Leaf(tt::Leaf::Punct(p))) if p.char == '=' && p.spacing != tt::Spacing::Joint) |
263 | { | 234 | { |
264 | arg.drain(..2); | 235 | arg.token_trees.drain(..2); |
265 | } | 236 | } |
266 | } | 237 | } |
267 | let _format_string = args.remove(0); | 238 | let _format_string = args.remove(0); |
268 | let arg_tts = args.into_iter().flat_map(|arg| { | 239 | let arg_tts = args.into_iter().flat_map(|arg| { |
269 | quote! { std::fmt::ArgumentV1::new(&(##arg), std::fmt::Display::fmt), } | 240 | quote! { std::fmt::ArgumentV1::new(&(#arg), std::fmt::Display::fmt), } |
270 | }.token_trees).collect::<Vec<_>>(); | 241 | }.token_trees).collect::<Vec<_>>(); |
271 | let expanded = quote! { | 242 | let expanded = quote! { |
272 | std::fmt::Arguments::new_v1(&[], &[##arg_tts]) | 243 | std::fmt::Arguments::new_v1(&[], &[##arg_tts]) |
@@ -327,17 +298,14 @@ fn concat_expand( | |||
327 | // concat works with string and char literals, so remove any quotes. | 298 | // concat works with string and char literals, so remove any quotes. |
328 | // It also works with integer, float and boolean literals, so just use the rest | 299 | // It also works with integer, float and boolean literals, so just use the rest |
329 | // as-is. | 300 | // as-is. |
330 | 301 | let component = unquote_str(&it).unwrap_or_else(|| it.text.to_string()); | |
331 | text += it | 302 | text.push_str(&component); |
332 | .text | 303 | } |
333 | .trim_start_matches(|c| match c { | 304 | // handle boolean literals |
334 | 'r' | '#' | '\'' | '"' => true, | 305 | tt::TokenTree::Leaf(tt::Leaf::Ident(id)) |
335 | _ => false, | 306 | if i % 2 == 0 && (id.text == "true" || id.text == "false") => |
336 | }) | 307 | { |
337 | .trim_end_matches(|c| match c { | 308 | text.push_str(id.text.as_str()); |
338 | '#' | '\'' | '"' => true, | ||
339 | _ => false, | ||
340 | }); | ||
341 | } | 309 | } |
342 | tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) if i % 2 == 1 && punct.char == ',' => (), | 310 | tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) if i % 2 == 1 && punct.char == ',' => (), |
343 | _ => { | 311 | _ => { |
@@ -345,7 +313,6 @@ fn concat_expand( | |||
345 | } | 313 | } |
346 | } | 314 | } |
347 | } | 315 | } |
348 | |||
349 | ExpandResult { value: Some((quote!(#text), FragmentKind::Expr)), err } | 316 | ExpandResult { value: Some((quote!(#text), FragmentKind::Expr)), err } |
350 | } | 317 | } |
351 | 318 | ||
@@ -724,6 +691,25 @@ mod tests { | |||
724 | } | 691 | } |
725 | 692 | ||
726 | #[test] | 693 | #[test] |
694 | fn test_format_args_expand_with_comma_exprs() { | ||
695 | let expanded = expand_builtin_macro( | ||
696 | r#" | ||
697 | #[rustc_builtin_macro] | ||
698 | macro_rules! format_args { | ||
699 | ($fmt:expr) => ({ /* compiler built-in */ }); | ||
700 | ($fmt:expr, $($args:tt)*) => ({ /* compiler built-in */ }) | ||
701 | } | ||
702 | format_args!("{} {:?}", a::<A,B>(), b); | ||
703 | "#, | ||
704 | ); | ||
705 | |||
706 | assert_eq!( | ||
707 | expanded, | ||
708 | r#"std::fmt::Arguments::new_v1(&[], &[std::fmt::ArgumentV1::new(&(a::<A,B>()),std::fmt::Display::fmt),std::fmt::ArgumentV1::new(&(b),std::fmt::Display::fmt),])"# | ||
709 | ); | ||
710 | } | ||
711 | |||
712 | #[test] | ||
727 | fn test_include_bytes_expand() { | 713 | fn test_include_bytes_expand() { |
728 | let expanded = expand_builtin_macro( | 714 | let expanded = expand_builtin_macro( |
729 | r#" | 715 | r#" |
@@ -745,12 +731,10 @@ mod tests { | |||
745 | r##" | 731 | r##" |
746 | #[rustc_builtin_macro] | 732 | #[rustc_builtin_macro] |
747 | macro_rules! concat {} | 733 | macro_rules! concat {} |
748 | concat!("foo", 0, r#"bar"#); | 734 | concat!("foo", "r", 0, r#"bar"#, false); |
749 | "##, | 735 | "##, |
750 | ); | 736 | ); |
751 | 737 | ||
752 | assert_eq!(expanded, r#""foo0bar""#); | 738 | assert_eq!(expanded, r#""foor0barfalse""#); |
753 | |||
754 | // FIXME: `true`/`false` literals don't work. | ||
755 | } | 739 | } |
756 | } | 740 | } |
diff --git a/crates/hir_expand/src/db.rs b/crates/hir_expand/src/db.rs index 467516eb7..cb6e23320 100644 --- a/crates/hir_expand/src/db.rs +++ b/crates/hir_expand/src/db.rs | |||
@@ -173,7 +173,7 @@ fn macro_arg_text(db: &dyn AstDatabase, id: MacroCallId) -> Option<GreenNode> { | |||
173 | }; | 173 | }; |
174 | let loc = db.lookup_intern_macro(id); | 174 | let loc = db.lookup_intern_macro(id); |
175 | let arg = loc.kind.arg(db)?; | 175 | let arg = loc.kind.arg(db)?; |
176 | Some(arg.green().clone()) | 176 | Some(arg.green().to_owned()) |
177 | } | 177 | } |
178 | 178 | ||
179 | fn macro_arg(db: &dyn AstDatabase, id: MacroCallId) -> Option<Arc<(tt::Subtree, mbe::TokenMap)>> { | 179 | fn macro_arg(db: &dyn AstDatabase, id: MacroCallId) -> Option<Arc<(tt::Subtree, mbe::TokenMap)>> { |
diff --git a/crates/hir_expand/src/name.rs b/crates/hir_expand/src/name.rs index 95d853b6d..c94fb580a 100644 --- a/crates/hir_expand/src/name.rs +++ b/crates/hir_expand/src/name.rs | |||
@@ -38,7 +38,7 @@ impl Name { | |||
38 | } | 38 | } |
39 | 39 | ||
40 | pub fn new_lifetime(lt: &ast::Lifetime) -> Name { | 40 | pub fn new_lifetime(lt: &ast::Lifetime) -> Name { |
41 | Self::new_text(lt.text().clone()) | 41 | Self::new_text(lt.text().into()) |
42 | } | 42 | } |
43 | 43 | ||
44 | /// Shortcut to create inline plain text name | 44 | /// Shortcut to create inline plain text name |
@@ -47,12 +47,12 @@ impl Name { | |||
47 | } | 47 | } |
48 | 48 | ||
49 | /// Resolve a name from the text of token. | 49 | /// Resolve a name from the text of token. |
50 | fn resolve(raw_text: &SmolStr) -> Name { | 50 | fn resolve(raw_text: &str) -> Name { |
51 | let raw_start = "r#"; | 51 | let raw_start = "r#"; |
52 | if raw_text.as_str().starts_with(raw_start) { | 52 | if raw_text.starts_with(raw_start) { |
53 | Name::new_text(SmolStr::new(&raw_text[raw_start.len()..])) | 53 | Name::new_text(SmolStr::new(&raw_text[raw_start.len()..])) |
54 | } else { | 54 | } else { |
55 | Name::new_text(raw_text.clone()) | 55 | Name::new_text(raw_text.into()) |
56 | } | 56 | } |
57 | } | 57 | } |
58 | 58 | ||
@@ -186,6 +186,10 @@ pub mod known { | |||
186 | Neg, | 186 | Neg, |
187 | Not, | 187 | Not, |
188 | Index, | 188 | Index, |
189 | // Components of known path (function name) | ||
190 | filter_map, | ||
191 | next, | ||
192 | iter_mut, | ||
189 | // Builtin macros | 193 | // Builtin macros |
190 | file, | 194 | file, |
191 | column, | 195 | column, |