diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2020-11-30 18:22:05 +0000 |
---|---|---|
committer | GitHub <[email protected]> | 2020-11-30 18:22:05 +0000 |
commit | 455a0cfda2121596deb13ca3f40a83c98b32863c (patch) | |
tree | 9c2cf858405e41d753b2060521bbaf6bbc64e2cb /crates/hir_expand/src/builtin_macro.rs | |
parent | 70eb17027151b4e85cbda2765f7289585b26a823 (diff) | |
parent | 92f52c5c9ad5acb104c6ce5a042950349a48c532 (diff) |
Merge #6681
6681: builtin_macro: move to `mbe::ExpandResult` r=jonas-schievink a=jonas-schievink
bors r+
Co-authored-by: Jonas Schievink <[email protected]>
Diffstat (limited to 'crates/hir_expand/src/builtin_macro.rs')
-rw-r--r-- | crates/hir_expand/src/builtin_macro.rs | 129 |
1 files changed, 79 insertions, 50 deletions
diff --git a/crates/hir_expand/src/builtin_macro.rs b/crates/hir_expand/src/builtin_macro.rs index aebbfc4df..7f4db106d 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::FileId; | 7 | use base_db::FileId; |
8 | use either::Either; | 8 | use either::Either; |
9 | use mbe::parse_to_token_tree; | 9 | use mbe::{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 | ||
@@ -28,7 +28,7 @@ macro_rules! register_builtin { | |||
28 | db: &dyn AstDatabase, | 28 | db: &dyn AstDatabase, |
29 | id: LazyMacroId, | 29 | id: LazyMacroId, |
30 | tt: &tt::Subtree, | 30 | tt: &tt::Subtree, |
31 | ) -> Result<tt::Subtree, mbe::ExpandError> { | 31 | ) -> ExpandResult<tt::Subtree> { |
32 | let expander = match *self { | 32 | let expander = match *self { |
33 | $( BuiltinFnLikeExpander::$kind => $expand, )* | 33 | $( BuiltinFnLikeExpander::$kind => $expand, )* |
34 | }; | 34 | }; |
@@ -42,7 +42,7 @@ macro_rules! register_builtin { | |||
42 | db: &dyn AstDatabase, | 42 | db: &dyn AstDatabase, |
43 | arg_id: EagerMacroId, | 43 | arg_id: EagerMacroId, |
44 | tt: &tt::Subtree, | 44 | tt: &tt::Subtree, |
45 | ) -> Result<(tt::Subtree, FragmentKind), mbe::ExpandError> { | 45 | ) -> ExpandResult<Option<(tt::Subtree, FragmentKind)>> { |
46 | let expander = match *self { | 46 | let expander = match *self { |
47 | $( EagerExpander::$e_kind => $e_expand, )* | 47 | $( EagerExpander::$e_kind => $e_expand, )* |
48 | }; | 48 | }; |
@@ -109,25 +109,28 @@ fn line_expand( | |||
109 | _db: &dyn AstDatabase, | 109 | _db: &dyn AstDatabase, |
110 | _id: LazyMacroId, | 110 | _id: LazyMacroId, |
111 | _tt: &tt::Subtree, | 111 | _tt: &tt::Subtree, |
112 | ) -> Result<tt::Subtree, mbe::ExpandError> { | 112 | ) -> ExpandResult<tt::Subtree> { |
113 | // dummy implementation for type-checking purposes | 113 | // dummy implementation for type-checking purposes |
114 | let line_num = 0; | 114 | let line_num = 0; |
115 | let expanded = quote! { | 115 | let expanded = quote! { |
116 | #line_num | 116 | #line_num |
117 | }; | 117 | }; |
118 | 118 | ||
119 | Ok(expanded) | 119 | ExpandResult::ok(expanded) |
120 | } | 120 | } |
121 | 121 | ||
122 | fn stringify_expand( | 122 | fn stringify_expand( |
123 | db: &dyn AstDatabase, | 123 | db: &dyn AstDatabase, |
124 | id: LazyMacroId, | 124 | id: LazyMacroId, |
125 | _tt: &tt::Subtree, | 125 | _tt: &tt::Subtree, |
126 | ) -> Result<tt::Subtree, mbe::ExpandError> { | 126 | ) -> ExpandResult<tt::Subtree> { |
127 | let loc = db.lookup_intern_macro(id); | 127 | let loc = db.lookup_intern_macro(id); |
128 | 128 | ||
129 | let macro_content = { | 129 | let macro_content = { |
130 | let arg = loc.kind.arg(db).ok_or_else(|| mbe::ExpandError::UnexpectedToken)?; | 130 | let arg = match loc.kind.arg(db) { |
131 | Some(arg) => arg, | ||
132 | None => return ExpandResult::only_err(mbe::ExpandError::UnexpectedToken), | ||
133 | }; | ||
131 | let macro_args = arg; | 134 | let macro_args = arg; |
132 | let text = macro_args.text(); | 135 | let text = macro_args.text(); |
133 | let without_parens = TextSize::of('(')..text.len() - TextSize::of(')'); | 136 | let without_parens = TextSize::of('(')..text.len() - TextSize::of(')'); |
@@ -138,28 +141,28 @@ fn stringify_expand( | |||
138 | #macro_content | 141 | #macro_content |
139 | }; | 142 | }; |
140 | 143 | ||
141 | Ok(expanded) | 144 | ExpandResult::ok(expanded) |
142 | } | 145 | } |
143 | 146 | ||
144 | fn column_expand( | 147 | fn column_expand( |
145 | _db: &dyn AstDatabase, | 148 | _db: &dyn AstDatabase, |
146 | _id: LazyMacroId, | 149 | _id: LazyMacroId, |
147 | _tt: &tt::Subtree, | 150 | _tt: &tt::Subtree, |
148 | ) -> Result<tt::Subtree, mbe::ExpandError> { | 151 | ) -> ExpandResult<tt::Subtree> { |
149 | // dummy implementation for type-checking purposes | 152 | // dummy implementation for type-checking purposes |
150 | let col_num = 0; | 153 | let col_num = 0; |
151 | let expanded = quote! { | 154 | let expanded = quote! { |
152 | #col_num | 155 | #col_num |
153 | }; | 156 | }; |
154 | 157 | ||
155 | Ok(expanded) | 158 | ExpandResult::ok(expanded) |
156 | } | 159 | } |
157 | 160 | ||
158 | fn assert_expand( | 161 | fn assert_expand( |
159 | _db: &dyn AstDatabase, | 162 | _db: &dyn AstDatabase, |
160 | _id: LazyMacroId, | 163 | _id: LazyMacroId, |
161 | tt: &tt::Subtree, | 164 | tt: &tt::Subtree, |
162 | ) -> Result<tt::Subtree, mbe::ExpandError> { | 165 | ) -> ExpandResult<tt::Subtree> { |
163 | // A hacky implementation for goto def and hover | 166 | // A hacky implementation for goto def and hover |
164 | // We expand `assert!(cond, arg1, arg2)` to | 167 | // We expand `assert!(cond, arg1, arg2)` to |
165 | // ``` | 168 | // ``` |
@@ -191,14 +194,14 @@ fn assert_expand( | |||
191 | let expanded = quote! { | 194 | let expanded = quote! { |
192 | { { (##arg_tts); } } | 195 | { { (##arg_tts); } } |
193 | }; | 196 | }; |
194 | Ok(expanded) | 197 | ExpandResult::ok(expanded) |
195 | } | 198 | } |
196 | 199 | ||
197 | fn file_expand( | 200 | fn file_expand( |
198 | _db: &dyn AstDatabase, | 201 | _db: &dyn AstDatabase, |
199 | _id: LazyMacroId, | 202 | _id: LazyMacroId, |
200 | _tt: &tt::Subtree, | 203 | _tt: &tt::Subtree, |
201 | ) -> Result<tt::Subtree, mbe::ExpandError> { | 204 | ) -> ExpandResult<tt::Subtree> { |
202 | // FIXME: RA purposefully lacks knowledge of absolute file names | 205 | // FIXME: RA purposefully lacks knowledge of absolute file names |
203 | // so just return "". | 206 | // so just return "". |
204 | let file_name = ""; | 207 | let file_name = ""; |
@@ -207,31 +210,33 @@ fn file_expand( | |||
207 | #file_name | 210 | #file_name |
208 | }; | 211 | }; |
209 | 212 | ||
210 | Ok(expanded) | 213 | ExpandResult::ok(expanded) |
211 | } | 214 | } |
212 | 215 | ||
213 | fn compile_error_expand( | 216 | fn compile_error_expand( |
214 | _db: &dyn AstDatabase, | 217 | _db: &dyn AstDatabase, |
215 | _id: LazyMacroId, | 218 | _id: LazyMacroId, |
216 | tt: &tt::Subtree, | 219 | tt: &tt::Subtree, |
217 | ) -> Result<tt::Subtree, mbe::ExpandError> { | 220 | ) -> ExpandResult<tt::Subtree> { |
218 | if tt.count() == 1 { | 221 | if tt.count() == 1 { |
219 | if let tt::TokenTree::Leaf(tt::Leaf::Literal(it)) = &tt.token_trees[0] { | 222 | if let tt::TokenTree::Leaf(tt::Leaf::Literal(it)) = &tt.token_trees[0] { |
220 | let s = it.text.as_str(); | 223 | let s = it.text.as_str(); |
221 | if s.contains('"') { | 224 | if s.contains('"') { |
222 | return Ok(quote! { loop { #it }}); | 225 | return ExpandResult::ok(quote! { loop { #it }}); |
223 | } | 226 | } |
224 | }; | 227 | }; |
225 | } | 228 | } |
226 | 229 | ||
227 | Err(mbe::ExpandError::BindingError("Must be a string".into())) | 230 | ExpandResult::only_err(mbe::ExpandError::BindingError( |
231 | "`compile_error!` argument be a string".into(), | ||
232 | )) | ||
228 | } | 233 | } |
229 | 234 | ||
230 | fn format_args_expand( | 235 | fn format_args_expand( |
231 | _db: &dyn AstDatabase, | 236 | _db: &dyn AstDatabase, |
232 | _id: LazyMacroId, | 237 | _id: LazyMacroId, |
233 | tt: &tt::Subtree, | 238 | tt: &tt::Subtree, |
234 | ) -> Result<tt::Subtree, mbe::ExpandError> { | 239 | ) -> ExpandResult<tt::Subtree> { |
235 | // We expand `format_args!("", a1, a2)` to | 240 | // We expand `format_args!("", a1, a2)` to |
236 | // ``` | 241 | // ``` |
237 | // std::fmt::Arguments::new_v1(&[], &[ | 242 | // std::fmt::Arguments::new_v1(&[], &[ |
@@ -257,7 +262,7 @@ fn format_args_expand( | |||
257 | args.push(current); | 262 | args.push(current); |
258 | } | 263 | } |
259 | if args.is_empty() { | 264 | if args.is_empty() { |
260 | return Err(mbe::ExpandError::NoMatchingRule); | 265 | return ExpandResult::only_err(mbe::ExpandError::NoMatchingRule); |
261 | } | 266 | } |
262 | let _format_string = args.remove(0); | 267 | let _format_string = args.remove(0); |
263 | let arg_tts = args.into_iter().flat_map(|arg| { | 268 | let arg_tts = args.into_iter().flat_map(|arg| { |
@@ -266,7 +271,7 @@ fn format_args_expand( | |||
266 | let expanded = quote! { | 271 | let expanded = quote! { |
267 | std::fmt::Arguments::new_v1(&[], &[##arg_tts]) | 272 | std::fmt::Arguments::new_v1(&[], &[##arg_tts]) |
268 | }; | 273 | }; |
269 | Ok(expanded) | 274 | ExpandResult::ok(expanded) |
270 | } | 275 | } |
271 | 276 | ||
272 | fn unquote_str(lit: &tt::Literal) -> Option<String> { | 277 | fn unquote_str(lit: &tt::Literal) -> Option<String> { |
@@ -279,19 +284,24 @@ fn concat_expand( | |||
279 | _db: &dyn AstDatabase, | 284 | _db: &dyn AstDatabase, |
280 | _arg_id: EagerMacroId, | 285 | _arg_id: EagerMacroId, |
281 | tt: &tt::Subtree, | 286 | tt: &tt::Subtree, |
282 | ) -> Result<(tt::Subtree, FragmentKind), mbe::ExpandError> { | 287 | ) -> ExpandResult<Option<(tt::Subtree, FragmentKind)>> { |
283 | let mut text = String::new(); | 288 | let mut text = String::new(); |
284 | for (i, t) in tt.token_trees.iter().enumerate() { | 289 | for (i, t) in tt.token_trees.iter().enumerate() { |
285 | match t { | 290 | match t { |
286 | tt::TokenTree::Leaf(tt::Leaf::Literal(it)) if i % 2 == 0 => { | 291 | tt::TokenTree::Leaf(tt::Leaf::Literal(it)) if i % 2 == 0 => { |
287 | text += &unquote_str(&it).ok_or_else(|| mbe::ExpandError::ConversionError)?; | 292 | text += &match unquote_str(&it) { |
293 | Some(s) => s, | ||
294 | None => { | ||
295 | return ExpandResult::only_err(mbe::ExpandError::ConversionError); | ||
296 | } | ||
297 | }; | ||
288 | } | 298 | } |
289 | tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) if i % 2 == 1 && punct.char == ',' => (), | 299 | tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) if i % 2 == 1 && punct.char == ',' => (), |
290 | _ => return Err(mbe::ExpandError::UnexpectedToken), | 300 | _ => return ExpandResult::only_err(mbe::ExpandError::UnexpectedToken), |
291 | } | 301 | } |
292 | } | 302 | } |
293 | 303 | ||
294 | Ok((quote!(#text), FragmentKind::Expr)) | 304 | ExpandResult::ok(Some((quote!(#text), FragmentKind::Expr))) |
295 | } | 305 | } |
296 | 306 | ||
297 | fn relative_file( | 307 | fn relative_file( |
@@ -324,26 +334,35 @@ fn include_expand( | |||
324 | db: &dyn AstDatabase, | 334 | db: &dyn AstDatabase, |
325 | arg_id: EagerMacroId, | 335 | arg_id: EagerMacroId, |
326 | tt: &tt::Subtree, | 336 | tt: &tt::Subtree, |
327 | ) -> Result<(tt::Subtree, FragmentKind), mbe::ExpandError> { | 337 | ) -> ExpandResult<Option<(tt::Subtree, FragmentKind)>> { |
328 | let path = parse_string(tt)?; | 338 | let res = (|| { |
329 | let file_id = relative_file(db, arg_id.into(), &path, false) | 339 | let path = parse_string(tt)?; |
330 | .ok_or_else(|| mbe::ExpandError::ConversionError)?; | 340 | let file_id = relative_file(db, arg_id.into(), &path, false) |
331 | 341 | .ok_or_else(|| mbe::ExpandError::ConversionError)?; | |
332 | // FIXME: | 342 | |
333 | // Handle include as expression | 343 | Ok(parse_to_token_tree(&db.file_text(file_id)) |
334 | let res = parse_to_token_tree(&db.file_text(file_id)) | 344 | .ok_or_else(|| mbe::ExpandError::ConversionError)? |
335 | .ok_or_else(|| mbe::ExpandError::ConversionError)? | 345 | .0) |
336 | .0; | 346 | })(); |
337 | 347 | ||
338 | Ok((res, FragmentKind::Items)) | 348 | match res { |
349 | Ok(res) => { | ||
350 | // FIXME: | ||
351 | // Handle include as expression | ||
352 | ExpandResult::ok(Some((res, FragmentKind::Items))) | ||
353 | } | ||
354 | Err(e) => ExpandResult::only_err(e), | ||
355 | } | ||
339 | } | 356 | } |
340 | 357 | ||
341 | fn include_bytes_expand( | 358 | fn include_bytes_expand( |
342 | _db: &dyn AstDatabase, | 359 | _db: &dyn AstDatabase, |
343 | _arg_id: EagerMacroId, | 360 | _arg_id: EagerMacroId, |
344 | tt: &tt::Subtree, | 361 | tt: &tt::Subtree, |
345 | ) -> Result<(tt::Subtree, FragmentKind), mbe::ExpandError> { | 362 | ) -> ExpandResult<Option<(tt::Subtree, FragmentKind)>> { |
346 | let _path = parse_string(tt)?; | 363 | if let Err(e) = parse_string(tt) { |
364 | return ExpandResult::only_err(e); | ||
365 | } | ||
347 | 366 | ||
348 | // FIXME: actually read the file here if the user asked for macro expansion | 367 | // FIXME: actually read the file here if the user asked for macro expansion |
349 | let res = tt::Subtree { | 368 | let res = tt::Subtree { |
@@ -353,15 +372,18 @@ fn include_bytes_expand( | |||
353 | id: tt::TokenId::unspecified(), | 372 | id: tt::TokenId::unspecified(), |
354 | }))], | 373 | }))], |
355 | }; | 374 | }; |
356 | Ok((res, FragmentKind::Expr)) | 375 | ExpandResult::ok(Some((res, FragmentKind::Expr))) |
357 | } | 376 | } |
358 | 377 | ||
359 | fn include_str_expand( | 378 | fn include_str_expand( |
360 | db: &dyn AstDatabase, | 379 | db: &dyn AstDatabase, |
361 | arg_id: EagerMacroId, | 380 | arg_id: EagerMacroId, |
362 | tt: &tt::Subtree, | 381 | tt: &tt::Subtree, |
363 | ) -> Result<(tt::Subtree, FragmentKind), mbe::ExpandError> { | 382 | ) -> ExpandResult<Option<(tt::Subtree, FragmentKind)>> { |
364 | let path = parse_string(tt)?; | 383 | let path = match parse_string(tt) { |
384 | Ok(it) => it, | ||
385 | Err(e) => return ExpandResult::only_err(e), | ||
386 | }; | ||
365 | 387 | ||
366 | // FIXME: we're not able to read excluded files (which is most of them because | 388 | // FIXME: we're not able to read excluded files (which is most of them because |
367 | // it's unusual to `include_str!` a Rust file), but we can return an empty string. | 389 | // it's unusual to `include_str!` a Rust file), but we can return an empty string. |
@@ -370,14 +392,14 @@ fn include_str_expand( | |||
370 | let file_id = match relative_file(db, arg_id.into(), &path, true) { | 392 | let file_id = match relative_file(db, arg_id.into(), &path, true) { |
371 | Some(file_id) => file_id, | 393 | Some(file_id) => file_id, |
372 | None => { | 394 | None => { |
373 | return Ok((quote!(""), FragmentKind::Expr)); | 395 | return ExpandResult::ok(Some((quote!(""), FragmentKind::Expr))); |
374 | } | 396 | } |
375 | }; | 397 | }; |
376 | 398 | ||
377 | let text = db.file_text(file_id); | 399 | let text = db.file_text(file_id); |
378 | let text = &*text; | 400 | let text = &*text; |
379 | 401 | ||
380 | Ok((quote!(#text), FragmentKind::Expr)) | 402 | ExpandResult::ok(Some((quote!(#text), FragmentKind::Expr))) |
381 | } | 403 | } |
382 | 404 | ||
383 | fn get_env_inner(db: &dyn AstDatabase, arg_id: EagerMacroId, key: &str) -> Option<String> { | 405 | fn get_env_inner(db: &dyn AstDatabase, arg_id: EagerMacroId, key: &str) -> Option<String> { |
@@ -389,8 +411,11 @@ fn env_expand( | |||
389 | db: &dyn AstDatabase, | 411 | db: &dyn AstDatabase, |
390 | arg_id: EagerMacroId, | 412 | arg_id: EagerMacroId, |
391 | tt: &tt::Subtree, | 413 | tt: &tt::Subtree, |
392 | ) -> Result<(tt::Subtree, FragmentKind), mbe::ExpandError> { | 414 | ) -> ExpandResult<Option<(tt::Subtree, FragmentKind)>> { |
393 | let key = parse_string(tt)?; | 415 | let key = match parse_string(tt) { |
416 | Ok(it) => it, | ||
417 | Err(e) => return ExpandResult::only_err(e), | ||
418 | }; | ||
394 | 419 | ||
395 | // FIXME: | 420 | // FIXME: |
396 | // If the environment variable is not defined int rustc, then a compilation error will be emitted. | 421 | // If the environment variable is not defined int rustc, then a compilation error will be emitted. |
@@ -402,21 +427,25 @@ fn env_expand( | |||
402 | let s = get_env_inner(db, arg_id, &key).unwrap_or_else(|| "__RA_UNIMPLEMENTED__".to_string()); | 427 | let s = get_env_inner(db, arg_id, &key).unwrap_or_else(|| "__RA_UNIMPLEMENTED__".to_string()); |
403 | let expanded = quote! { #s }; | 428 | let expanded = quote! { #s }; |
404 | 429 | ||
405 | Ok((expanded, FragmentKind::Expr)) | 430 | ExpandResult::ok(Some((expanded, FragmentKind::Expr))) |
406 | } | 431 | } |
407 | 432 | ||
408 | fn option_env_expand( | 433 | fn option_env_expand( |
409 | db: &dyn AstDatabase, | 434 | db: &dyn AstDatabase, |
410 | arg_id: EagerMacroId, | 435 | arg_id: EagerMacroId, |
411 | tt: &tt::Subtree, | 436 | tt: &tt::Subtree, |
412 | ) -> Result<(tt::Subtree, FragmentKind), mbe::ExpandError> { | 437 | ) -> ExpandResult<Option<(tt::Subtree, FragmentKind)>> { |
413 | let key = parse_string(tt)?; | 438 | let key = match parse_string(tt) { |
439 | Ok(it) => it, | ||
440 | Err(e) => return ExpandResult::only_err(e), | ||
441 | }; | ||
442 | |||
414 | let expanded = match get_env_inner(db, arg_id, &key) { | 443 | let expanded = match get_env_inner(db, arg_id, &key) { |
415 | None => quote! { std::option::Option::None::<&str> }, | 444 | None => quote! { std::option::Option::None::<&str> }, |
416 | Some(s) => quote! { std::option::Some(#s) }, | 445 | Some(s) => quote! { std::option::Some(#s) }, |
417 | }; | 446 | }; |
418 | 447 | ||
419 | Ok((expanded, FragmentKind::Expr)) | 448 | ExpandResult::ok(Some((expanded, FragmentKind::Expr))) |
420 | } | 449 | } |
421 | 450 | ||
422 | #[cfg(test)] | 451 | #[cfg(test)] |
@@ -485,7 +514,7 @@ mod tests { | |||
485 | } | 514 | } |
486 | }); | 515 | }); |
487 | 516 | ||
488 | let (subtree, fragment) = expander.expand(&db, arg_id, &parsed_args).unwrap(); | 517 | let (subtree, fragment) = expander.expand(&db, arg_id, &parsed_args).value.unwrap(); |
489 | let eager = EagerCallLoc { | 518 | let eager = EagerCallLoc { |
490 | def, | 519 | def, |
491 | fragment, | 520 | fragment, |