diff options
Diffstat (limited to 'crates/hir_expand/src/builtin_macro.rs')
-rw-r--r-- | crates/hir_expand/src/builtin_macro.rs | 74 |
1 files changed, 44 insertions, 30 deletions
diff --git a/crates/hir_expand/src/builtin_macro.rs b/crates/hir_expand/src/builtin_macro.rs index 7f4db106d..16c3c4d69 100644 --- a/crates/hir_expand/src/builtin_macro.rs +++ b/crates/hir_expand/src/builtin_macro.rs | |||
@@ -86,7 +86,6 @@ pub fn find_builtin_macro( | |||
86 | register_builtin! { | 86 | register_builtin! { |
87 | LAZY: | 87 | LAZY: |
88 | (column, Column) => column_expand, | 88 | (column, Column) => column_expand, |
89 | (compile_error, CompileError) => compile_error_expand, | ||
90 | (file, File) => file_expand, | 89 | (file, File) => file_expand, |
91 | (line, Line) => line_expand, | 90 | (line, Line) => line_expand, |
92 | (assert, Assert) => assert_expand, | 91 | (assert, Assert) => assert_expand, |
@@ -97,6 +96,7 @@ register_builtin! { | |||
97 | (format_args_nl, FormatArgsNl) => format_args_expand, | 96 | (format_args_nl, FormatArgsNl) => format_args_expand, |
98 | 97 | ||
99 | EAGER: | 98 | EAGER: |
99 | (compile_error, CompileError) => compile_error_expand, | ||
100 | (concat, Concat) => concat_expand, | 100 | (concat, Concat) => concat_expand, |
101 | (include, Include) => include_expand, | 101 | (include, Include) => include_expand, |
102 | (include_bytes, IncludeBytes) => include_bytes_expand, | 102 | (include_bytes, IncludeBytes) => include_bytes_expand, |
@@ -213,25 +213,6 @@ fn file_expand( | |||
213 | ExpandResult::ok(expanded) | 213 | ExpandResult::ok(expanded) |
214 | } | 214 | } |
215 | 215 | ||
216 | fn compile_error_expand( | ||
217 | _db: &dyn AstDatabase, | ||
218 | _id: LazyMacroId, | ||
219 | tt: &tt::Subtree, | ||
220 | ) -> ExpandResult<tt::Subtree> { | ||
221 | if tt.count() == 1 { | ||
222 | if let tt::TokenTree::Leaf(tt::Leaf::Literal(it)) = &tt.token_trees[0] { | ||
223 | let s = it.text.as_str(); | ||
224 | if s.contains('"') { | ||
225 | return ExpandResult::ok(quote! { loop { #it }}); | ||
226 | } | ||
227 | }; | ||
228 | } | ||
229 | |||
230 | ExpandResult::only_err(mbe::ExpandError::BindingError( | ||
231 | "`compile_error!` argument be a string".into(), | ||
232 | )) | ||
233 | } | ||
234 | |||
235 | fn format_args_expand( | 216 | fn format_args_expand( |
236 | _db: &dyn AstDatabase, | 217 | _db: &dyn AstDatabase, |
237 | _id: LazyMacroId, | 218 | _id: LazyMacroId, |
@@ -280,6 +261,30 @@ fn unquote_str(lit: &tt::Literal) -> Option<String> { | |||
280 | token.value().map(|it| it.into_owned()) | 261 | token.value().map(|it| it.into_owned()) |
281 | } | 262 | } |
282 | 263 | ||
264 | fn compile_error_expand( | ||
265 | _db: &dyn AstDatabase, | ||
266 | _id: EagerMacroId, | ||
267 | tt: &tt::Subtree, | ||
268 | ) -> ExpandResult<Option<(tt::Subtree, FragmentKind)>> { | ||
269 | let err = match &*tt.token_trees { | ||
270 | [tt::TokenTree::Leaf(tt::Leaf::Literal(it))] => { | ||
271 | let text = it.text.as_str(); | ||
272 | if text.starts_with('"') && text.ends_with('"') { | ||
273 | // FIXME: does not handle raw strings | ||
274 | mbe::ExpandError::Other(format!( | ||
275 | "`compile_error!` called: {}", | ||
276 | &text[1..text.len() - 1] | ||
277 | )) | ||
278 | } else { | ||
279 | mbe::ExpandError::BindingError("`compile_error!` argument must be a string".into()) | ||
280 | } | ||
281 | } | ||
282 | _ => mbe::ExpandError::BindingError("`compile_error!` argument must be a string".into()), | ||
283 | }; | ||
284 | |||
285 | ExpandResult { value: Some((quote! {}, FragmentKind::Items)), err: Some(err) } | ||
286 | } | ||
287 | |||
283 | fn concat_expand( | 288 | fn concat_expand( |
284 | _db: &dyn AstDatabase, | 289 | _db: &dyn AstDatabase, |
285 | _arg_id: EagerMacroId, | 290 | _arg_id: EagerMacroId, |
@@ -417,17 +422,25 @@ fn env_expand( | |||
417 | Err(e) => return ExpandResult::only_err(e), | 422 | Err(e) => return ExpandResult::only_err(e), |
418 | }; | 423 | }; |
419 | 424 | ||
420 | // FIXME: | 425 | let mut err = None; |
421 | // If the environment variable is not defined int rustc, then a compilation error will be emitted. | 426 | let s = get_env_inner(db, arg_id, &key).unwrap_or_else(|| { |
422 | // We might do the same if we fully support all other stuffs. | 427 | // The only variable rust-analyzer ever sets is `OUT_DIR`, so only diagnose that to avoid |
423 | // But for now on, we should return some dummy string for better type infer purpose. | 428 | // unnecessary diagnostics for eg. `CARGO_PKG_NAME`. |
424 | // However, we cannot use an empty string here, because for | 429 | if key == "OUT_DIR" { |
425 | // `include!(concat!(env!("OUT_DIR"), "/foo.rs"))` will become | 430 | err = Some(mbe::ExpandError::Other( |
426 | // `include!("foo.rs"), which might go to infinite loop | 431 | r#"`OUT_DIR` not set, enable "load out dirs from check" to fix"#.into(), |
427 | let s = get_env_inner(db, arg_id, &key).unwrap_or_else(|| "__RA_UNIMPLEMENTED__".to_string()); | 432 | )); |
433 | } | ||
434 | |||
435 | // If the variable is unset, still return a dummy string to help type inference along. | ||
436 | // We cannot use an empty string here, because for | ||
437 | // `include!(concat!(env!("OUT_DIR"), "/foo.rs"))` will become | ||
438 | // `include!("foo.rs"), which might go to infinite loop | ||
439 | "__RA_UNIMPLEMENTED__".to_string() | ||
440 | }); | ||
428 | let expanded = quote! { #s }; | 441 | let expanded = quote! { #s }; |
429 | 442 | ||
430 | ExpandResult::ok(Some((expanded, FragmentKind::Expr))) | 443 | ExpandResult { value: Some((expanded, FragmentKind::Expr)), err } |
431 | } | 444 | } |
432 | 445 | ||
433 | fn option_env_expand( | 446 | fn option_env_expand( |
@@ -638,7 +651,8 @@ mod tests { | |||
638 | "#, | 651 | "#, |
639 | ); | 652 | ); |
640 | 653 | ||
641 | assert_eq!(expanded, r#"loop{"error!"}"#); | 654 | // This expands to nothing (since it's in item position), but emits an error. |
655 | assert_eq!(expanded, ""); | ||
642 | } | 656 | } |
643 | 657 | ||
644 | #[test] | 658 | #[test] |