diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2019-12-06 20:59:51 +0000 |
---|---|---|
committer | GitHub <[email protected]> | 2019-12-06 20:59:51 +0000 |
commit | 431836f4a01dda39d10f6275915f9c8e99a28028 (patch) | |
tree | 0cb8ceaa2e07b30da2f841d792e505df6b460d41 /crates/ra_hir_expand | |
parent | f18b7e18c479144325ec150be00837aae3329ae2 (diff) | |
parent | b2c01f446edcbc12b5dd870064cbfc6c1a47eb8b (diff) |
Merge #2489
2489: Implement `format_args` r=flodiebold a=flodiebold
This fixes a huge amount of type mismatches (because every format call was a type mismatch so far); I also hoped to get go to def working within `format!` etc., and the test says it should, but in practice it still doesn't seem to...
Also remove the `len` parameter from `Name::new_inline_ascii`, which I'm assuming was only there because of `const fn` limitations?
cc @edwin0cheng
Co-authored-by: Florian Diebold <[email protected]>
Diffstat (limited to 'crates/ra_hir_expand')
-rw-r--r-- | crates/ra_hir_expand/src/builtin_macro.rs | 58 | ||||
-rw-r--r-- | crates/ra_hir_expand/src/db.rs | 4 | ||||
-rw-r--r-- | crates/ra_hir_expand/src/lib.rs | 39 | ||||
-rw-r--r-- | crates/ra_hir_expand/src/name.rs | 116 |
4 files changed, 157 insertions, 60 deletions
diff --git a/crates/ra_hir_expand/src/builtin_macro.rs b/crates/ra_hir_expand/src/builtin_macro.rs index 35f99b2bc..99303188b 100644 --- a/crates/ra_hir_expand/src/builtin_macro.rs +++ b/crates/ra_hir_expand/src/builtin_macro.rs | |||
@@ -49,7 +49,11 @@ register_builtin! { | |||
49 | (COMPILE_ERROR_MACRO, CompileError) => compile_error_expand, | 49 | (COMPILE_ERROR_MACRO, CompileError) => compile_error_expand, |
50 | (FILE_MACRO, File) => file_expand, | 50 | (FILE_MACRO, File) => file_expand, |
51 | (LINE_MACRO, Line) => line_expand, | 51 | (LINE_MACRO, Line) => line_expand, |
52 | (STRINGIFY_MACRO, Stringify) => stringify_expand | 52 | (STRINGIFY_MACRO, Stringify) => stringify_expand, |
53 | (FORMAT_ARGS_MACRO, FormatArgs) => format_args_expand, | ||
54 | // format_args_nl only differs in that it adds a newline in the end, | ||
55 | // so we use the same stub expansion for now | ||
56 | (FORMAT_ARGS_NL_MACRO, FormatArgsNl) => format_args_expand | ||
53 | } | 57 | } |
54 | 58 | ||
55 | fn to_line_number(db: &dyn AstDatabase, file: HirFileId, pos: TextUnit) -> usize { | 59 | fn to_line_number(db: &dyn AstDatabase, file: HirFileId, pos: TextUnit) -> usize { |
@@ -200,6 +204,41 @@ fn compile_error_expand( | |||
200 | Err(mbe::ExpandError::BindingError("Must be a string".into())) | 204 | Err(mbe::ExpandError::BindingError("Must be a string".into())) |
201 | } | 205 | } |
202 | 206 | ||
207 | fn format_args_expand( | ||
208 | _db: &dyn AstDatabase, | ||
209 | _id: MacroCallId, | ||
210 | tt: &tt::Subtree, | ||
211 | ) -> Result<tt::Subtree, mbe::ExpandError> { | ||
212 | // We expand `format_args!("", arg1, arg2)` to | ||
213 | // `std::fmt::Arguments::new_v1(&[], &[&arg1, &arg2])`, | ||
214 | // which is still not really correct, but close enough for now | ||
215 | let mut args = Vec::new(); | ||
216 | let mut current = Vec::new(); | ||
217 | for tt in tt.token_trees.iter().cloned() { | ||
218 | match tt { | ||
219 | tt::TokenTree::Leaf(tt::Leaf::Punct(p)) if p.char == ',' => { | ||
220 | args.push(tt::Subtree { delimiter: tt::Delimiter::None, token_trees: current }); | ||
221 | current = Vec::new(); | ||
222 | } | ||
223 | _ => { | ||
224 | current.push(tt); | ||
225 | } | ||
226 | } | ||
227 | } | ||
228 | if !current.is_empty() { | ||
229 | args.push(tt::Subtree { delimiter: tt::Delimiter::None, token_trees: current }); | ||
230 | } | ||
231 | if args.is_empty() { | ||
232 | return Err(mbe::ExpandError::NoMatchingRule); | ||
233 | } | ||
234 | let _format_string = args.remove(0); | ||
235 | let arg_tts = args.into_iter().flat_map(|arg| (quote! { & #arg , }).token_trees); | ||
236 | let expanded = quote! { | ||
237 | std::fmt::Arguments::new_v1(&[], &[##arg_tts]) | ||
238 | }; | ||
239 | Ok(expanded) | ||
240 | } | ||
241 | |||
203 | #[cfg(test)] | 242 | #[cfg(test)] |
204 | mod tests { | 243 | mod tests { |
205 | use super::*; | 244 | use super::*; |
@@ -307,4 +346,21 @@ mod tests { | |||
307 | 346 | ||
308 | assert_eq!(expanded, r#"loop{"error!"}"#); | 347 | assert_eq!(expanded, r#"loop{"error!"}"#); |
309 | } | 348 | } |
349 | |||
350 | #[test] | ||
351 | fn test_format_args_expand() { | ||
352 | let expanded = expand_builtin_macro( | ||
353 | r#" | ||
354 | #[rustc_builtin_macro] | ||
355 | macro_rules! format_args { | ||
356 | ($fmt:expr) => ({ /* compiler built-in */ }); | ||
357 | ($fmt:expr, $($args:tt)*) => ({ /* compiler built-in */ }) | ||
358 | } | ||
359 | format_args!("{} {:?}", arg1(a, b, c), arg2); | ||
360 | "#, | ||
361 | BuiltinFnLikeExpander::FormatArgs, | ||
362 | ); | ||
363 | |||
364 | assert_eq!(expanded, r#"std::fmt::Arguments::new_v1(&[] ,&[&arg1(a,b,c),&arg2,])"#); | ||
365 | } | ||
310 | } | 366 | } |
diff --git a/crates/ra_hir_expand/src/db.rs b/crates/ra_hir_expand/src/db.rs index 99dabf3fb..013a6c8ba 100644 --- a/crates/ra_hir_expand/src/db.rs +++ b/crates/ra_hir_expand/src/db.rs | |||
@@ -45,8 +45,8 @@ impl TokenExpander { | |||
45 | pub fn map_id_up(&self, id: tt::TokenId) -> (tt::TokenId, mbe::Origin) { | 45 | pub fn map_id_up(&self, id: tt::TokenId) -> (tt::TokenId, mbe::Origin) { |
46 | match self { | 46 | match self { |
47 | TokenExpander::MacroRules(it) => it.map_id_up(id), | 47 | TokenExpander::MacroRules(it) => it.map_id_up(id), |
48 | TokenExpander::Builtin(..) => (id, mbe::Origin::Def), | 48 | TokenExpander::Builtin(..) => (id, mbe::Origin::Call), |
49 | TokenExpander::BuiltinDerive(..) => (id, mbe::Origin::Def), | 49 | TokenExpander::BuiltinDerive(..) => (id, mbe::Origin::Call), |
50 | } | 50 | } |
51 | } | 51 | } |
52 | } | 52 | } |
diff --git a/crates/ra_hir_expand/src/lib.rs b/crates/ra_hir_expand/src/lib.rs index 59c69b91b..0a5da7e54 100644 --- a/crates/ra_hir_expand/src/lib.rs +++ b/crates/ra_hir_expand/src/lib.rs | |||
@@ -76,6 +76,17 @@ impl HirFileId { | |||
76 | } | 76 | } |
77 | } | 77 | } |
78 | 78 | ||
79 | /// If this is a macro call, returns the syntax node of the call. | ||
80 | pub fn call_node(self, db: &dyn db::AstDatabase) -> Option<InFile<SyntaxNode>> { | ||
81 | match self.0 { | ||
82 | HirFileIdRepr::FileId(_) => None, | ||
83 | HirFileIdRepr::MacroFile(macro_file) => { | ||
84 | let loc = db.lookup_intern_macro(macro_file.macro_call_id); | ||
85 | Some(loc.kind.node(db)) | ||
86 | } | ||
87 | } | ||
88 | } | ||
89 | |||
79 | /// Return expansion information if it is a macro-expansion file | 90 | /// Return expansion information if it is a macro-expansion file |
80 | pub fn expansion_info(self, db: &dyn db::AstDatabase) -> Option<ExpansionInfo> { | 91 | pub fn expansion_info(self, db: &dyn db::AstDatabase) -> Option<ExpansionInfo> { |
81 | match self.0 { | 92 | match self.0 { |
@@ -176,6 +187,13 @@ impl MacroCallKind { | |||
176 | } | 187 | } |
177 | } | 188 | } |
178 | 189 | ||
190 | pub fn node(&self, db: &dyn db::AstDatabase) -> InFile<SyntaxNode> { | ||
191 | match self { | ||
192 | MacroCallKind::FnLike(ast_id) => ast_id.with_value(ast_id.to_node(db).syntax().clone()), | ||
193 | MacroCallKind::Attr(ast_id) => ast_id.with_value(ast_id.to_node(db).syntax().clone()), | ||
194 | } | ||
195 | } | ||
196 | |||
179 | pub fn arg(&self, db: &dyn db::AstDatabase) -> Option<SyntaxNode> { | 197 | pub fn arg(&self, db: &dyn db::AstDatabase) -> Option<SyntaxNode> { |
180 | match self { | 198 | match self { |
181 | MacroCallKind::FnLike(ast_id) => { | 199 | MacroCallKind::FnLike(ast_id) => { |
@@ -283,3 +301,24 @@ impl<T> InFile<T> { | |||
283 | db.parse_or_expand(self.file_id).expect("source created from invalid file") | 301 | db.parse_or_expand(self.file_id).expect("source created from invalid file") |
284 | } | 302 | } |
285 | } | 303 | } |
304 | |||
305 | impl<T: Clone> InFile<&T> { | ||
306 | pub fn cloned(&self) -> InFile<T> { | ||
307 | self.with_value(self.value.clone()) | ||
308 | } | ||
309 | } | ||
310 | |||
311 | impl InFile<SyntaxNode> { | ||
312 | pub fn ancestors_with_macros<'a>( | ||
313 | self, | ||
314 | db: &'a impl crate::db::AstDatabase, | ||
315 | ) -> impl Iterator<Item = InFile<SyntaxNode>> + 'a { | ||
316 | std::iter::successors(Some(self), move |node| match node.value.parent() { | ||
317 | Some(parent) => Some(node.with_value(parent)), | ||
318 | None => { | ||
319 | let parent_node = node.file_id.call_node(db)?; | ||
320 | Some(parent_node) | ||
321 | } | ||
322 | }) | ||
323 | } | ||
324 | } | ||
diff --git a/crates/ra_hir_expand/src/name.rs b/crates/ra_hir_expand/src/name.rs index c5a191160..4f2f702c0 100644 --- a/crates/ra_hir_expand/src/name.rs +++ b/crates/ra_hir_expand/src/name.rs | |||
@@ -38,8 +38,8 @@ impl Name { | |||
38 | } | 38 | } |
39 | 39 | ||
40 | /// Shortcut to create inline plain text name | 40 | /// Shortcut to create inline plain text name |
41 | const fn new_inline_ascii(len: usize, text: &[u8]) -> Name { | 41 | const fn new_inline_ascii(text: &[u8]) -> Name { |
42 | Name::new_text(SmolStr::new_inline_from_ascii(len, text)) | 42 | Name::new_text(SmolStr::new_inline_from_ascii(text.len(), text)) |
43 | } | 43 | } |
44 | 44 | ||
45 | /// Resolve a name from the text of token. | 45 | /// Resolve a name from the text of token. |
@@ -105,68 +105,70 @@ impl AsName for ra_db::Dependency { | |||
105 | } | 105 | } |
106 | 106 | ||
107 | // Primitives | 107 | // Primitives |
108 | pub const ISIZE: Name = Name::new_inline_ascii(5, b"isize"); | 108 | pub const ISIZE: Name = Name::new_inline_ascii(b"isize"); |
109 | pub const I8: Name = Name::new_inline_ascii(2, b"i8"); | 109 | pub const I8: Name = Name::new_inline_ascii(b"i8"); |
110 | pub const I16: Name = Name::new_inline_ascii(3, b"i16"); | 110 | pub const I16: Name = Name::new_inline_ascii(b"i16"); |
111 | pub const I32: Name = Name::new_inline_ascii(3, b"i32"); | 111 | pub const I32: Name = Name::new_inline_ascii(b"i32"); |
112 | pub const I64: Name = Name::new_inline_ascii(3, b"i64"); | 112 | pub const I64: Name = Name::new_inline_ascii(b"i64"); |
113 | pub const I128: Name = Name::new_inline_ascii(4, b"i128"); | 113 | pub const I128: Name = Name::new_inline_ascii(b"i128"); |
114 | pub const USIZE: Name = Name::new_inline_ascii(5, b"usize"); | 114 | pub const USIZE: Name = Name::new_inline_ascii(b"usize"); |
115 | pub const U8: Name = Name::new_inline_ascii(2, b"u8"); | 115 | pub const U8: Name = Name::new_inline_ascii(b"u8"); |
116 | pub const U16: Name = Name::new_inline_ascii(3, b"u16"); | 116 | pub const U16: Name = Name::new_inline_ascii(b"u16"); |
117 | pub const U32: Name = Name::new_inline_ascii(3, b"u32"); | 117 | pub const U32: Name = Name::new_inline_ascii(b"u32"); |
118 | pub const U64: Name = Name::new_inline_ascii(3, b"u64"); | 118 | pub const U64: Name = Name::new_inline_ascii(b"u64"); |
119 | pub const U128: Name = Name::new_inline_ascii(4, b"u128"); | 119 | pub const U128: Name = Name::new_inline_ascii(b"u128"); |
120 | pub const F32: Name = Name::new_inline_ascii(3, b"f32"); | 120 | pub const F32: Name = Name::new_inline_ascii(b"f32"); |
121 | pub const F64: Name = Name::new_inline_ascii(3, b"f64"); | 121 | pub const F64: Name = Name::new_inline_ascii(b"f64"); |
122 | pub const BOOL: Name = Name::new_inline_ascii(4, b"bool"); | 122 | pub const BOOL: Name = Name::new_inline_ascii(b"bool"); |
123 | pub const CHAR: Name = Name::new_inline_ascii(4, b"char"); | 123 | pub const CHAR: Name = Name::new_inline_ascii(b"char"); |
124 | pub const STR: Name = Name::new_inline_ascii(3, b"str"); | 124 | pub const STR: Name = Name::new_inline_ascii(b"str"); |
125 | 125 | ||
126 | // Special names | 126 | // Special names |
127 | pub const SELF_PARAM: Name = Name::new_inline_ascii(4, b"self"); | 127 | pub const SELF_PARAM: Name = Name::new_inline_ascii(b"self"); |
128 | pub const SELF_TYPE: Name = Name::new_inline_ascii(4, b"Self"); | 128 | pub const SELF_TYPE: Name = Name::new_inline_ascii(b"Self"); |
129 | pub const MACRO_RULES: Name = Name::new_inline_ascii(11, b"macro_rules"); | 129 | pub const MACRO_RULES: Name = Name::new_inline_ascii(b"macro_rules"); |
130 | 130 | ||
131 | // Components of known path (value or mod name) | 131 | // Components of known path (value or mod name) |
132 | pub const STD: Name = Name::new_inline_ascii(3, b"std"); | 132 | pub const STD: Name = Name::new_inline_ascii(b"std"); |
133 | pub const ITER: Name = Name::new_inline_ascii(4, b"iter"); | 133 | pub const ITER: Name = Name::new_inline_ascii(b"iter"); |
134 | pub const OPS: Name = Name::new_inline_ascii(3, b"ops"); | 134 | pub const OPS: Name = Name::new_inline_ascii(b"ops"); |
135 | pub const FUTURE: Name = Name::new_inline_ascii(6, b"future"); | 135 | pub const FUTURE: Name = Name::new_inline_ascii(b"future"); |
136 | pub const RESULT: Name = Name::new_inline_ascii(6, b"result"); | 136 | pub const RESULT: Name = Name::new_inline_ascii(b"result"); |
137 | pub const BOXED: Name = Name::new_inline_ascii(5, b"boxed"); | 137 | pub const BOXED: Name = Name::new_inline_ascii(b"boxed"); |
138 | 138 | ||
139 | // Components of known path (type name) | 139 | // Components of known path (type name) |
140 | pub const INTO_ITERATOR_TYPE: Name = Name::new_inline_ascii(12, b"IntoIterator"); | 140 | pub const INTO_ITERATOR_TYPE: Name = Name::new_inline_ascii(b"IntoIterator"); |
141 | pub const ITEM_TYPE: Name = Name::new_inline_ascii(4, b"Item"); | 141 | pub const ITEM_TYPE: Name = Name::new_inline_ascii(b"Item"); |
142 | pub const TRY_TYPE: Name = Name::new_inline_ascii(3, b"Try"); | 142 | pub const TRY_TYPE: Name = Name::new_inline_ascii(b"Try"); |
143 | pub const OK_TYPE: Name = Name::new_inline_ascii(2, b"Ok"); | 143 | pub const OK_TYPE: Name = Name::new_inline_ascii(b"Ok"); |
144 | pub const FUTURE_TYPE: Name = Name::new_inline_ascii(6, b"Future"); | 144 | pub const FUTURE_TYPE: Name = Name::new_inline_ascii(b"Future"); |
145 | pub const RESULT_TYPE: Name = Name::new_inline_ascii(6, b"Result"); | 145 | pub const RESULT_TYPE: Name = Name::new_inline_ascii(b"Result"); |
146 | pub const OUTPUT_TYPE: Name = Name::new_inline_ascii(6, b"Output"); | 146 | pub const OUTPUT_TYPE: Name = Name::new_inline_ascii(b"Output"); |
147 | pub const TARGET_TYPE: Name = Name::new_inline_ascii(6, b"Target"); | 147 | pub const TARGET_TYPE: Name = Name::new_inline_ascii(b"Target"); |
148 | pub const BOX_TYPE: Name = Name::new_inline_ascii(3, b"Box"); | 148 | pub const BOX_TYPE: Name = Name::new_inline_ascii(b"Box"); |
149 | pub const RANGE_FROM_TYPE: Name = Name::new_inline_ascii(9, b"RangeFrom"); | 149 | pub const RANGE_FROM_TYPE: Name = Name::new_inline_ascii(b"RangeFrom"); |
150 | pub const RANGE_FULL_TYPE: Name = Name::new_inline_ascii(9, b"RangeFull"); | 150 | pub const RANGE_FULL_TYPE: Name = Name::new_inline_ascii(b"RangeFull"); |
151 | pub const RANGE_INCLUSIVE_TYPE: Name = Name::new_inline_ascii(14, b"RangeInclusive"); | 151 | pub const RANGE_INCLUSIVE_TYPE: Name = Name::new_inline_ascii(b"RangeInclusive"); |
152 | pub const RANGE_TO_INCLUSIVE_TYPE: Name = Name::new_inline_ascii(16, b"RangeToInclusive"); | 152 | pub const RANGE_TO_INCLUSIVE_TYPE: Name = Name::new_inline_ascii(b"RangeToInclusive"); |
153 | pub const RANGE_TO_TYPE: Name = Name::new_inline_ascii(7, b"RangeTo"); | 153 | pub const RANGE_TO_TYPE: Name = Name::new_inline_ascii(b"RangeTo"); |
154 | pub const RANGE_TYPE: Name = Name::new_inline_ascii(5, b"Range"); | 154 | pub const RANGE_TYPE: Name = Name::new_inline_ascii(b"Range"); |
155 | 155 | ||
156 | // Builtin Macros | 156 | // Builtin Macros |
157 | pub const FILE_MACRO: Name = Name::new_inline_ascii(4, b"file"); | 157 | pub const FILE_MACRO: Name = Name::new_inline_ascii(b"file"); |
158 | pub const COLUMN_MACRO: Name = Name::new_inline_ascii(6, b"column"); | 158 | pub const COLUMN_MACRO: Name = Name::new_inline_ascii(b"column"); |
159 | pub const COMPILE_ERROR_MACRO: Name = Name::new_inline_ascii(13, b"compile_error"); | 159 | pub const COMPILE_ERROR_MACRO: Name = Name::new_inline_ascii(b"compile_error"); |
160 | pub const LINE_MACRO: Name = Name::new_inline_ascii(4, b"line"); | 160 | pub const LINE_MACRO: Name = Name::new_inline_ascii(b"line"); |
161 | pub const STRINGIFY_MACRO: Name = Name::new_inline_ascii(9, b"stringify"); | 161 | pub const STRINGIFY_MACRO: Name = Name::new_inline_ascii(b"stringify"); |
162 | pub const FORMAT_ARGS_MACRO: Name = Name::new_inline_ascii(b"format_args"); | ||
163 | pub const FORMAT_ARGS_NL_MACRO: Name = Name::new_inline_ascii(b"format_args_nl"); | ||
162 | 164 | ||
163 | // Builtin derives | 165 | // Builtin derives |
164 | pub const COPY_TRAIT: Name = Name::new_inline_ascii(4, b"Copy"); | 166 | pub const COPY_TRAIT: Name = Name::new_inline_ascii(b"Copy"); |
165 | pub const CLONE_TRAIT: Name = Name::new_inline_ascii(5, b"Clone"); | 167 | pub const CLONE_TRAIT: Name = Name::new_inline_ascii(b"Clone"); |
166 | pub const DEFAULT_TRAIT: Name = Name::new_inline_ascii(7, b"Default"); | 168 | pub const DEFAULT_TRAIT: Name = Name::new_inline_ascii(b"Default"); |
167 | pub const DEBUG_TRAIT: Name = Name::new_inline_ascii(5, b"Debug"); | 169 | pub const DEBUG_TRAIT: Name = Name::new_inline_ascii(b"Debug"); |
168 | pub const HASH_TRAIT: Name = Name::new_inline_ascii(4, b"Hash"); | 170 | pub const HASH_TRAIT: Name = Name::new_inline_ascii(b"Hash"); |
169 | pub const ORD_TRAIT: Name = Name::new_inline_ascii(3, b"Ord"); | 171 | pub const ORD_TRAIT: Name = Name::new_inline_ascii(b"Ord"); |
170 | pub const PARTIAL_ORD_TRAIT: Name = Name::new_inline_ascii(10, b"PartialOrd"); | 172 | pub const PARTIAL_ORD_TRAIT: Name = Name::new_inline_ascii(b"PartialOrd"); |
171 | pub const EQ_TRAIT: Name = Name::new_inline_ascii(2, b"Eq"); | 173 | pub const EQ_TRAIT: Name = Name::new_inline_ascii(b"Eq"); |
172 | pub const PARTIAL_EQ_TRAIT: Name = Name::new_inline_ascii(9, b"PartialEq"); | 174 | pub const PARTIAL_EQ_TRAIT: Name = Name::new_inline_ascii(b"PartialEq"); |