Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-expand/src/builtin_fn_macro.rs')
-rw-r--r--crates/hir-expand/src/builtin_fn_macro.rs158
1 files changed, 105 insertions, 53 deletions
diff --git a/crates/hir-expand/src/builtin_fn_macro.rs b/crates/hir-expand/src/builtin_fn_macro.rs
index 459d1c868d..726b983536 100644
--- a/crates/hir-expand/src/builtin_fn_macro.rs
+++ b/crates/hir-expand/src/builtin_fn_macro.rs
@@ -1,8 +1,7 @@
//! Builtin macro
-use ::tt::Span;
use base_db::{
- span::{SpanAnchor, ROOT_ERASED_FILE_AST_ID},
+ span::{SpanAnchor, SpanData, SyntaxContextId, ROOT_ERASED_FILE_AST_ID},
AnchoredPath, Edition, FileId,
};
use cfg::CfgExpr;
@@ -15,8 +14,9 @@ use syntax::{
use crate::{
db::ExpandDatabase,
+ hygiene::span_with_def_site_ctxt,
name, quote,
- tt::{self},
+ tt::{self, DelimSpan},
EagerCallInfo, ExpandError, ExpandResult, HirFileIdExt, MacroCallId, MacroCallLoc,
};
@@ -42,7 +42,10 @@ macro_rules! register_builtin {
let expander = match *self {
$( BuiltinFnLikeExpander::$kind => $expand, )*
};
- expander(db, id, tt)
+
+ let span = db.lookup_intern_macro_call(id).span(db);
+ let span = span_with_def_site_ctxt(db, span, id);
+ expander(db, id, tt, span)
}
}
@@ -50,13 +53,16 @@ macro_rules! register_builtin {
pub fn expand(
&self,
db: &dyn ExpandDatabase,
- arg_id: MacroCallId,
+ id: MacroCallId,
tt: &tt::Subtree,
) -> ExpandResult<tt::Subtree> {
let expander = match *self {
$( EagerExpander::$e_kind => $e_expand, )*
};
- expander(db, arg_id, tt)
+
+ let span = db.lookup_intern_macro_call(id).span(db);
+ let span = span_with_def_site_ctxt(db, span, id);
+ expander(db, id, tt, span)
}
}
@@ -115,29 +121,42 @@ register_builtin! {
(option_env, OptionEnv) => option_env_expand
}
-const DOLLAR_CRATE: tt::Ident =
- tt::Ident { text: SmolStr::new_inline("$crate"), span: tt::SpanData::DUMMY };
+fn mk_pound(span: SpanData) -> tt::Subtree {
+ crate::quote::IntoTt::to_subtree(
+ vec![crate::tt::Leaf::Punct(crate::tt::Punct {
+ char: '#',
+ spacing: crate::tt::Spacing::Alone,
+ span: span,
+ })
+ .into()],
+ span,
+ )
+}
fn module_path_expand(
_db: &dyn ExpandDatabase,
_id: MacroCallId,
_tt: &tt::Subtree,
+ span: SpanData,
) -> ExpandResult<tt::Subtree> {
// Just return a dummy result.
- ExpandResult::ok(quote! { "module::path" })
+ ExpandResult::ok(quote! {span =>
+ "module::path"
+ })
}
fn line_expand(
_db: &dyn ExpandDatabase,
_id: MacroCallId,
_tt: &tt::Subtree,
+ span: SpanData,
) -> ExpandResult<tt::Subtree> {
// dummy implementation for type-checking purposes
ExpandResult::ok(tt::Subtree {
- delimiter: tt::Delimiter::unspecified(),
+ delimiter: tt::Delimiter::dummy_invisible(),
token_trees: vec![tt::TokenTree::Leaf(tt::Leaf::Literal(tt::Literal {
text: "0u32".into(),
- span: tt::SpanData::DUMMY,
+ span,
}))],
})
}
@@ -146,26 +165,29 @@ fn log_syntax_expand(
_db: &dyn ExpandDatabase,
_id: MacroCallId,
_tt: &tt::Subtree,
+ span: SpanData,
) -> ExpandResult<tt::Subtree> {
- ExpandResult::ok(quote! {})
+ ExpandResult::ok(quote! {span =>})
}
fn trace_macros_expand(
_db: &dyn ExpandDatabase,
_id: MacroCallId,
_tt: &tt::Subtree,
+ span: SpanData,
) -> ExpandResult<tt::Subtree> {
- ExpandResult::ok(quote! {})
+ ExpandResult::ok(quote! {span =>})
}
fn stringify_expand(
_db: &dyn ExpandDatabase,
_id: MacroCallId,
tt: &tt::Subtree,
+ span: SpanData,
) -> ExpandResult<tt::Subtree> {
let pretty = ::tt::pretty(&tt.token_trees);
- let expanded = quote! {
+ let expanded = quote! {span =>
#pretty
};
@@ -176,27 +198,29 @@ fn assert_expand(
_db: &dyn ExpandDatabase,
_id: MacroCallId,
tt: &tt::Subtree,
+ span: SpanData,
) -> ExpandResult<tt::Subtree> {
let args = parse_exprs_with_sep(tt, ',');
+ let dollar_crate = tt::Ident { text: SmolStr::new_inline("$crate"), span };
let expanded = match &*args {
[cond, panic_args @ ..] => {
let comma = tt::Subtree {
- delimiter: tt::Delimiter::unspecified(),
+ delimiter: tt::Delimiter::dummy_invisible(),
token_trees: vec![tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct {
char: ',',
spacing: tt::Spacing::Alone,
- span: tt::SpanData::DUMMY,
+ span,
}))],
};
let cond = cond.clone();
let panic_args = itertools::Itertools::intersperse(panic_args.iter().cloned(), comma);
- quote! {{
+ quote! {span =>{
if !(#cond) {
- #DOLLAR_CRATE::panic!(##panic_args);
+ #dollar_crate::panic!(##panic_args);
}
}}
}
- [] => quote! {{}},
+ [] => quote! {span =>{}},
};
ExpandResult::ok(expanded)
@@ -206,12 +230,13 @@ fn file_expand(
_db: &dyn ExpandDatabase,
_id: MacroCallId,
_tt: &tt::Subtree,
+ span: SpanData,
) -> ExpandResult<tt::Subtree> {
// FIXME: RA purposefully lacks knowledge of absolute file names
// so just return "".
let file_name = "";
- let expanded = quote! {
+ let expanded = quote! {span =>
#file_name
};
@@ -222,16 +247,18 @@ fn format_args_expand(
db: &dyn ExpandDatabase,
id: MacroCallId,
tt: &tt::Subtree,
+ span: SpanData,
) -> ExpandResult<tt::Subtree> {
- format_args_expand_general(db, id, tt, "")
+ format_args_expand_general(db, id, tt, "", span)
}
fn format_args_nl_expand(
db: &dyn ExpandDatabase,
id: MacroCallId,
tt: &tt::Subtree,
+ span: SpanData,
) -> ExpandResult<tt::Subtree> {
- format_args_expand_general(db, id, tt, "\\n")
+ format_args_expand_general(db, id, tt, "\\n", span)
}
fn format_args_expand_general(
@@ -240,11 +267,12 @@ fn format_args_expand_general(
tt: &tt::Subtree,
// FIXME: Make use of this so that mir interpretation works properly
_end_string: &str,
+ span: SpanData,
) -> ExpandResult<tt::Subtree> {
- let pound = quote! {@PUNCT '#'};
+ let pound = mk_pound(span);
let mut tt = tt.clone();
tt.delimiter.kind = tt::DelimiterKind::Parenthesis;
- return ExpandResult::ok(quote! {
+ return ExpandResult::ok(quote! {span =>
builtin #pound format_args #tt
});
}
@@ -253,25 +281,25 @@ fn asm_expand(
_db: &dyn ExpandDatabase,
_id: MacroCallId,
tt: &tt::Subtree,
+ span: SpanData,
) -> ExpandResult<tt::Subtree> {
// We expand all assembly snippets to `format_args!` invocations to get format syntax
// highlighting for them.
-
let mut literals = Vec::new();
for tt in tt.token_trees.chunks(2) {
match tt {
[tt::TokenTree::Leaf(tt::Leaf::Literal(lit))]
| [tt::TokenTree::Leaf(tt::Leaf::Literal(lit)), tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct { char: ',', span: _, spacing: _ }))] =>
{
- let krate = DOLLAR_CRATE.clone();
- literals.push(quote!(#krate::format_args!(#lit);));
+ let dollar_krate = tt::Ident { text: SmolStr::new_inline("$crate"), span };
+ literals.push(quote!(span=>#dollar_krate::format_args!(#lit);));
}
_ => break,
}
}
- let pound = quote! {@PUNCT '#'};
- let expanded = quote! {
+ let pound = mk_pound(span);
+ let expanded = quote! {span =>
builtin #pound asm (
{##literals}
)
@@ -283,20 +311,22 @@ fn global_asm_expand(
_db: &dyn ExpandDatabase,
_id: MacroCallId,
_tt: &tt::Subtree,
+ span: SpanData,
) -> ExpandResult<tt::Subtree> {
// Expand to nothing (at item-level)
- ExpandResult::ok(quote! {})
+ ExpandResult::ok(quote! {span =>})
}
fn cfg_expand(
db: &dyn ExpandDatabase,
id: MacroCallId,
tt: &tt::Subtree,
+ span: SpanData,
) -> ExpandResult<tt::Subtree> {
let loc = db.lookup_intern_macro_call(id);
let expr = CfgExpr::parse(tt);
let enabled = db.crate_graph()[loc.krate].cfg_options.check(&expr) != Some(false);
- let expanded = if enabled { quote!(true) } else { quote!(false) };
+ let expanded = if enabled { quote!(span=>true) } else { quote!(span=>false) };
ExpandResult::ok(expanded)
}
@@ -304,13 +334,15 @@ fn panic_expand(
db: &dyn ExpandDatabase,
id: MacroCallId,
tt: &tt::Subtree,
+ span: SpanData,
) -> ExpandResult<tt::Subtree> {
let loc: MacroCallLoc = db.lookup_intern_macro_call(id);
+ let dollar_crate = tt::Ident { text: SmolStr::new_inline("$crate"), span };
// Expand to a macro call `$crate::panic::panic_{edition}`
let mut call = if db.crate_graph()[loc.krate].edition >= Edition::Edition2021 {
- quote!(#DOLLAR_CRATE::panic::panic_2021!)
+ quote!(span =>#dollar_crate::panic::panic_2021!)
} else {
- quote!(#DOLLAR_CRATE::panic::panic_2015!)
+ quote!(span =>#dollar_crate::panic::panic_2015!)
};
// Pass the original arguments
@@ -322,13 +354,15 @@ fn unreachable_expand(
db: &dyn ExpandDatabase,
id: MacroCallId,
tt: &tt::Subtree,
+ span: SpanData,
) -> ExpandResult<tt::Subtree> {
let loc: MacroCallLoc = db.lookup_intern_macro_call(id);
// Expand to a macro call `$crate::panic::unreachable_{edition}`
+ let dollar_crate = tt::Ident { text: SmolStr::new_inline("$crate"), span };
let mut call = if db.crate_graph()[loc.krate].edition >= Edition::Edition2021 {
- quote!(#DOLLAR_CRATE::panic::unreachable_2021!)
+ quote!(span =>#dollar_crate::panic::unreachable_2021!)
} else {
- quote!(#DOLLAR_CRATE::panic::unreachable_2015!)
+ quote!(span =>#dollar_crate::panic::unreachable_2015!)
};
// Pass the original arguments
@@ -358,6 +392,7 @@ fn compile_error_expand(
_db: &dyn ExpandDatabase,
_id: MacroCallId,
tt: &tt::Subtree,
+ span: SpanData,
) -> ExpandResult<tt::Subtree> {
let err = match &*tt.token_trees {
[tt::TokenTree::Leaf(tt::Leaf::Literal(it))] => match unquote_str(it) {
@@ -367,13 +402,14 @@ fn compile_error_expand(
_ => ExpandError::other("`compile_error!` argument must be a string"),
};
- ExpandResult { value: quote! {}, err: Some(err) }
+ ExpandResult { value: quote! {span =>}, err: Some(err) }
}
fn concat_expand(
_db: &dyn ExpandDatabase,
_arg_id: MacroCallId,
tt: &tt::Subtree,
+ span: SpanData,
) -> ExpandResult<tt::Subtree> {
let mut err = None;
let mut text = String::new();
@@ -413,13 +449,14 @@ fn concat_expand(
}
}
}
- ExpandResult { value: quote!(#text), err }
+ ExpandResult { value: quote!(span =>#text), err }
}
fn concat_bytes_expand(
_db: &dyn ExpandDatabase,
_arg_id: MacroCallId,
tt: &tt::Subtree,
+ span: SpanData,
) -> ExpandResult<tt::Subtree> {
let mut bytes = Vec::new();
let mut err = None;
@@ -452,8 +489,8 @@ fn concat_bytes_expand(
}
}
}
- let ident = tt::Ident { text: bytes.join(", ").into(), span: tt::SpanData::DUMMY };
- ExpandResult { value: quote!([#ident]), err }
+ let ident = tt::Ident { text: bytes.join(", ").into(), span };
+ ExpandResult { value: quote!(span =>[#ident]), err }
}
fn concat_bytes_expand_subtree(
@@ -486,6 +523,7 @@ fn concat_idents_expand(
_db: &dyn ExpandDatabase,
_arg_id: MacroCallId,
tt: &tt::Subtree,
+ span: SpanData,
) -> ExpandResult<tt::Subtree> {
let mut err = None;
let mut ident = String::new();
@@ -500,8 +538,9 @@ fn concat_idents_expand(
}
}
}
- let ident = tt::Ident { text: ident.into(), span: tt::SpanData::DUMMY };
- ExpandResult { value: quote!(#ident), err }
+ // FIXME merge spans
+ let ident = tt::Ident { text: ident.into(), span };
+ ExpandResult { value: quote!(span =>#ident), err }
}
fn relative_file(
@@ -537,10 +576,11 @@ fn include_expand(
db: &dyn ExpandDatabase,
arg_id: MacroCallId,
_tt: &tt::Subtree,
+ span: SpanData,
) -> ExpandResult<tt::Subtree> {
match db.include_expand(arg_id) {
Ok((res, _)) => ExpandResult::ok(res.as_ref().clone()),
- Err(e) => ExpandResult::new(tt::Subtree::empty(), e),
+ Err(e) => ExpandResult::new(tt::Subtree::empty(DelimSpan { open: span, close: span }), e),
}
}
@@ -559,6 +599,8 @@ pub(crate) fn include_arg_to_tt(
// why are we not going through a SyntaxNode here?
let subtree = parse_to_token_tree(
SpanAnchor { file_id, ast_id: ROOT_ERASED_FILE_AST_ID },
+ // FIXME
+ SyntaxContextId::ROOT,
&db.file_text(file_id),
)
.ok_or(mbe::ExpandError::ConversionError)?;
@@ -569,17 +611,18 @@ fn include_bytes_expand(
_db: &dyn ExpandDatabase,
_arg_id: MacroCallId,
tt: &tt::Subtree,
+ span: SpanData,
) -> ExpandResult<tt::Subtree> {
if let Err(e) = parse_string(tt) {
- return ExpandResult::new(tt::Subtree::empty(), e);
+ return ExpandResult::new(tt::Subtree::empty(DelimSpan { open: span, close: span }), e);
}
// FIXME: actually read the file here if the user asked for macro expansion
let res = tt::Subtree {
- delimiter: tt::Delimiter::unspecified(),
+ delimiter: tt::Delimiter::dummy_invisible(),
token_trees: vec![tt::TokenTree::Leaf(tt::Leaf::Literal(tt::Literal {
text: r#"b"""#.into(),
- span: tt::SpanData::DUMMY,
+ span,
}))],
};
ExpandResult::ok(res)
@@ -589,10 +632,13 @@ fn include_str_expand(
db: &dyn ExpandDatabase,
arg_id: MacroCallId,
tt: &tt::Subtree,
+ span: SpanData,
) -> ExpandResult<tt::Subtree> {
let path = match parse_string(tt) {
Ok(it) => it,
- Err(e) => return ExpandResult::new(tt::Subtree::empty(), e),
+ Err(e) => {
+ return ExpandResult::new(tt::Subtree::empty(DelimSpan { open: span, close: span }), e)
+ }
};
// FIXME: we're not able to read excluded files (which is most of them because
@@ -602,14 +648,14 @@ fn include_str_expand(
let file_id = match relative_file(db, arg_id, &path, true) {
Ok(file_id) => file_id,
Err(_) => {
- return ExpandResult::ok(quote!(""));
+ return ExpandResult::ok(quote!(span =>""));
}
};
let text = db.file_text(file_id);
let text = &*text;
- ExpandResult::ok(quote!(#text))
+ ExpandResult::ok(quote!(span =>#text))
}
fn get_env_inner(db: &dyn ExpandDatabase, arg_id: MacroCallId, key: &str) -> Option<String> {
@@ -621,10 +667,13 @@ fn env_expand(
db: &dyn ExpandDatabase,
arg_id: MacroCallId,
tt: &tt::Subtree,
+ span: SpanData,
) -> ExpandResult<tt::Subtree> {
let key = match parse_string(tt) {
Ok(it) => it,
- Err(e) => return ExpandResult::new(tt::Subtree::empty(), e),
+ Err(e) => {
+ return ExpandResult::new(tt::Subtree::empty(DelimSpan { open: span, close: span }), e)
+ }
};
let mut err = None;
@@ -641,7 +690,7 @@ fn env_expand(
// `include!("foo.rs"), which might go to infinite loop
"UNRESOLVED_ENV_VAR".to_string()
});
- let expanded = quote! { #s };
+ let expanded = quote! {span => #s };
ExpandResult { value: expanded, err }
}
@@ -650,15 +699,18 @@ fn option_env_expand(
db: &dyn ExpandDatabase,
arg_id: MacroCallId,
tt: &tt::Subtree,
+ span: SpanData,
) -> ExpandResult<tt::Subtree> {
let key = match parse_string(tt) {
Ok(it) => it,
- Err(e) => return ExpandResult::new(tt::Subtree::empty(), e),
+ Err(e) => {
+ return ExpandResult::new(tt::Subtree::empty(DelimSpan { open: span, close: span }), e)
+ }
};
// FIXME: Use `DOLLAR_CRATE` when that works in eager macros.
let expanded = match get_env_inner(db, arg_id, &key) {
- None => quote! { ::core::option::Option::None::<&str> },
- Some(s) => quote! { ::core::option::Option::Some(#s) },
+ None => quote! {span => ::core::option::Option::None::<&str> },
+ Some(s) => quote! {span => ::core::option::Option::Some(#s) },
};
ExpandResult::ok(expanded)