aboutsummaryrefslogtreecommitdiff
path: root/crates/hir_expand/src/builtin_macro.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/hir_expand/src/builtin_macro.rs')
-rw-r--r--crates/hir_expand/src/builtin_macro.rs74
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(
86register_builtin! { 86register_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
216fn 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
235fn format_args_expand( 216fn 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
264fn 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
283fn concat_expand( 288fn 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
433fn option_env_expand( 446fn 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]