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.rs168
1 files changed, 111 insertions, 57 deletions
diff --git a/crates/hir-expand/src/builtin_fn_macro.rs b/crates/hir-expand/src/builtin_fn_macro.rs
index c8f04bfee5..f99a891762 100644
--- a/crates/hir-expand/src/builtin_fn_macro.rs
+++ b/crates/hir-expand/src/builtin_fn_macro.rs
@@ -1,13 +1,11 @@
//! Builtin macro
-use base_db::{
- span::{SpanAnchor, SpanData, SyntaxContextId, ROOT_ERASED_FILE_AST_ID},
- AnchoredPath, Edition, FileId,
-};
+use base_db::{AnchoredPath, Edition, FileId};
use cfg::CfgExpr;
use either::Either;
use itertools::Itertools;
use mbe::{parse_exprs_with_sep, parse_to_token_tree};
+use span::{Span, SpanAnchor, SyntaxContextId, ROOT_ERASED_FILE_AST_ID};
use syntax::{
ast::{self, AstToken},
SmolStr,
@@ -15,10 +13,11 @@ use syntax::{
use crate::{
db::ExpandDatabase,
- hygiene::span_with_def_site_ctxt,
- name, quote,
+ hygiene::{span_with_call_site_ctxt, span_with_def_site_ctxt},
+ name::{self, known},
+ quote,
tt::{self, DelimSpan},
- ExpandError, ExpandResult, HirFileIdExt, MacroCallId, MacroCallLoc,
+ ExpandError, ExpandResult, HirFileIdExt, MacroCallId,
};
macro_rules! register_builtin {
@@ -44,7 +43,7 @@ macro_rules! register_builtin {
$( BuiltinFnLikeExpander::$kind => $expand, )*
};
- let span = db.lookup_intern_macro_call(id).span(db);
+ let span = db.lookup_intern_macro_call(id).call_site;
let span = span_with_def_site_ctxt(db, span, id);
expander(db, id, tt, span)
}
@@ -61,7 +60,7 @@ macro_rules! register_builtin {
$( EagerExpander::$e_kind => $e_expand, )*
};
- let span = db.lookup_intern_macro_call(id).span(db);
+ let span = db.lookup_intern_macro_call(id).call_site;
let span = span_with_def_site_ctxt(db, span, id);
expander(db, id, tt, span)
}
@@ -109,6 +108,7 @@ register_builtin! {
(format_args, FormatArgs) => format_args_expand,
(const_format_args, ConstFormatArgs) => format_args_expand,
(format_args_nl, FormatArgsNl) => format_args_nl_expand,
+ (quote, Quote) => quote_expand,
EAGER:
(compile_error, CompileError) => compile_error_expand,
@@ -122,7 +122,7 @@ register_builtin! {
(option_env, OptionEnv) => option_env_expand
}
-fn mk_pound(span: SpanData) -> tt::Subtree {
+fn mk_pound(span: Span) -> tt::Subtree {
crate::quote::IntoTt::to_subtree(
vec![crate::tt::Leaf::Punct(crate::tt::Punct {
char: '#',
@@ -138,7 +138,7 @@ fn module_path_expand(
_db: &dyn ExpandDatabase,
_id: MacroCallId,
_tt: &tt::Subtree,
- span: SpanData,
+ span: Span,
) -> ExpandResult<tt::Subtree> {
// Just return a dummy result.
ExpandResult::ok(quote! {span =>
@@ -150,13 +150,13 @@ fn line_expand(
_db: &dyn ExpandDatabase,
_id: MacroCallId,
_tt: &tt::Subtree,
- span: SpanData,
+ span: Span,
) -> ExpandResult<tt::Subtree> {
// dummy implementation for type-checking purposes
// Note that `line!` and `column!` will never be implemented properly, as they are by definition
// not incremental
ExpandResult::ok(tt::Subtree {
- delimiter: tt::Delimiter::dummy_invisible(),
+ delimiter: tt::Delimiter::invisible_spanned(span),
token_trees: vec![tt::TokenTree::Leaf(tt::Leaf::Literal(tt::Literal {
text: "0u32".into(),
span,
@@ -168,7 +168,7 @@ fn log_syntax_expand(
_db: &dyn ExpandDatabase,
_id: MacroCallId,
_tt: &tt::Subtree,
- span: SpanData,
+ span: Span,
) -> ExpandResult<tt::Subtree> {
ExpandResult::ok(quote! {span =>})
}
@@ -177,7 +177,7 @@ fn trace_macros_expand(
_db: &dyn ExpandDatabase,
_id: MacroCallId,
_tt: &tt::Subtree,
- span: SpanData,
+ span: Span,
) -> ExpandResult<tt::Subtree> {
ExpandResult::ok(quote! {span =>})
}
@@ -186,7 +186,7 @@ fn stringify_expand(
_db: &dyn ExpandDatabase,
_id: MacroCallId,
tt: &tt::Subtree,
- span: SpanData,
+ span: Span,
) -> ExpandResult<tt::Subtree> {
let pretty = ::tt::pretty(&tt.token_trees);
@@ -198,32 +198,38 @@ fn stringify_expand(
}
fn assert_expand(
- _db: &dyn ExpandDatabase,
- _id: MacroCallId,
+ db: &dyn ExpandDatabase,
+ id: MacroCallId,
tt: &tt::Subtree,
- span: SpanData,
+ span: Span,
) -> ExpandResult<tt::Subtree> {
- let args = parse_exprs_with_sep(tt, ',');
+ let call_site_span = span_with_call_site_ctxt(db, span, id);
+ let args = parse_exprs_with_sep(tt, ',', call_site_span);
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::dummy_invisible(),
+ delimiter: tt::Delimiter::invisible_spanned(call_site_span),
token_trees: vec![tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct {
char: ',',
spacing: tt::Spacing::Alone,
- span,
+ span: call_site_span,
}))],
};
let cond = cond.clone();
let panic_args = itertools::Itertools::intersperse(panic_args.iter().cloned(), comma);
- quote! {span =>{
+ let mac = if use_panic_2021(db, span) {
+ quote! {call_site_span => #dollar_crate::panic::panic_2021!(##panic_args) }
+ } else {
+ quote! {call_site_span => #dollar_crate::panic!(##panic_args) }
+ };
+ quote! {call_site_span =>{
if !(#cond) {
- #dollar_crate::panic!(##panic_args);
+ #mac;
}
}}
}
- [] => quote! {span =>{}},
+ [] => quote! {call_site_span =>{}},
};
ExpandResult::ok(expanded)
@@ -233,7 +239,7 @@ fn file_expand(
_db: &dyn ExpandDatabase,
_id: MacroCallId,
_tt: &tt::Subtree,
- span: SpanData,
+ span: Span,
) -> ExpandResult<tt::Subtree> {
// FIXME: RA purposefully lacks knowledge of absolute file names
// so just return "".
@@ -250,7 +256,7 @@ fn format_args_expand(
db: &dyn ExpandDatabase,
id: MacroCallId,
tt: &tt::Subtree,
- span: SpanData,
+ span: Span,
) -> ExpandResult<tt::Subtree> {
format_args_expand_general(db, id, tt, "", span)
}
@@ -259,7 +265,7 @@ fn format_args_nl_expand(
db: &dyn ExpandDatabase,
id: MacroCallId,
tt: &tt::Subtree,
- span: SpanData,
+ span: Span,
) -> ExpandResult<tt::Subtree> {
format_args_expand_general(db, id, tt, "\\n", span)
}
@@ -270,7 +276,7 @@ fn format_args_expand_general(
tt: &tt::Subtree,
// FIXME: Make use of this so that mir interpretation works properly
_end_string: &str,
- span: SpanData,
+ span: Span,
) -> ExpandResult<tt::Subtree> {
let pound = mk_pound(span);
let mut tt = tt.clone();
@@ -284,7 +290,7 @@ fn asm_expand(
_db: &dyn ExpandDatabase,
_id: MacroCallId,
tt: &tt::Subtree,
- span: SpanData,
+ span: Span,
) -> ExpandResult<tt::Subtree> {
// We expand all assembly snippets to `format_args!` invocations to get format syntax
// highlighting for them.
@@ -314,7 +320,7 @@ fn global_asm_expand(
_db: &dyn ExpandDatabase,
_id: MacroCallId,
_tt: &tt::Subtree,
- span: SpanData,
+ span: Span,
) -> ExpandResult<tt::Subtree> {
// Expand to nothing (at item-level)
ExpandResult::ok(quote! {span =>})
@@ -324,7 +330,7 @@ fn cfg_expand(
db: &dyn ExpandDatabase,
id: MacroCallId,
tt: &tt::Subtree,
- span: SpanData,
+ span: Span,
) -> ExpandResult<tt::Subtree> {
let loc = db.lookup_intern_macro_call(id);
let expr = CfgExpr::parse(tt);
@@ -337,19 +343,25 @@ fn panic_expand(
db: &dyn ExpandDatabase,
id: MacroCallId,
tt: &tt::Subtree,
- span: SpanData,
+ span: Span,
) -> ExpandResult<tt::Subtree> {
- let loc: MacroCallLoc = db.lookup_intern_macro_call(id);
let dollar_crate = tt::Ident { text: SmolStr::new_inline("$crate"), span };
+ let call_site_span = span_with_call_site_ctxt(db, span, id);
+
+ let mac =
+ if use_panic_2021(db, call_site_span) { known::panic_2021 } else { known::panic_2015 };
+
// Expand to a macro call `$crate::panic::panic_{edition}`
- let mut call = if db.crate_graph()[loc.krate].edition >= Edition::Edition2021 {
- quote!(span =>#dollar_crate::panic::panic_2021!)
- } else {
- quote!(span =>#dollar_crate::panic::panic_2015!)
- };
+ let mut call = quote!(call_site_span =>#dollar_crate::panic::#mac!);
// Pass the original arguments
- call.token_trees.push(tt::TokenTree::Subtree(tt.clone()));
+ let mut subtree = tt.clone();
+ subtree.delimiter = tt::Delimiter {
+ open: call_site_span,
+ close: call_site_span,
+ kind: tt::DelimiterKind::Parenthesis,
+ };
+ call.token_trees.push(tt::TokenTree::Subtree(subtree));
ExpandResult::ok(call)
}
@@ -357,22 +369,52 @@ fn unreachable_expand(
db: &dyn ExpandDatabase,
id: MacroCallId,
tt: &tt::Subtree,
- span: SpanData,
+ span: Span,
) -> 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!(span =>#dollar_crate::panic::unreachable_2021!)
+ let call_site_span = span_with_call_site_ctxt(db, span, id);
+
+ let mac = if use_panic_2021(db, call_site_span) {
+ known::unreachable_2021
} else {
- quote!(span =>#dollar_crate::panic::unreachable_2015!)
+ known::unreachable_2015
};
+ // Expand to a macro call `$crate::panic::panic_{edition}`
+ let mut call = quote!(call_site_span =>#dollar_crate::panic::#mac!);
+
// Pass the original arguments
- call.token_trees.push(tt::TokenTree::Subtree(tt.clone()));
+ let mut subtree = tt.clone();
+ subtree.delimiter = tt::Delimiter {
+ open: call_site_span,
+ close: call_site_span,
+ kind: tt::DelimiterKind::Parenthesis,
+ };
+ call.token_trees.push(tt::TokenTree::Subtree(subtree));
ExpandResult::ok(call)
}
+fn use_panic_2021(db: &dyn ExpandDatabase, span: Span) -> bool {
+ // To determine the edition, we check the first span up the expansion
+ // stack that does not have #[allow_internal_unstable(edition_panic)].
+ // (To avoid using the edition of e.g. the assert!() or debug_assert!() definition.)
+ loop {
+ let Some(expn) = db.lookup_intern_syntax_context(span.ctx).outer_expn else {
+ break false;
+ };
+ let expn = db.lookup_intern_macro_call(expn);
+ // FIXME: Record allow_internal_unstable in the macro def (not been done yet because it
+ // would consume quite a bit extra memory for all call locs...)
+ // if let Some(features) = expn.def.allow_internal_unstable {
+ // if features.iter().any(|&f| f == sym::edition_panic) {
+ // span = expn.call_site;
+ // continue;
+ // }
+ // }
+ break expn.def.edition >= Edition::Edition2021;
+ }
+}
+
fn unquote_str(lit: &tt::Literal) -> Option<String> {
let lit = ast::make::tokens::literal(&lit.to_string());
let token = ast::String::cast(lit)?;
@@ -395,7 +437,7 @@ fn compile_error_expand(
_db: &dyn ExpandDatabase,
_id: MacroCallId,
tt: &tt::Subtree,
- span: SpanData,
+ span: Span,
) -> ExpandResult<tt::Subtree> {
let err = match &*tt.token_trees {
[tt::TokenTree::Leaf(tt::Leaf::Literal(it))] => match unquote_str(it) {
@@ -412,7 +454,7 @@ fn concat_expand(
_db: &dyn ExpandDatabase,
_arg_id: MacroCallId,
tt: &tt::Subtree,
- span: SpanData,
+ span: Span,
) -> ExpandResult<tt::Subtree> {
let mut err = None;
let mut text = String::new();
@@ -459,7 +501,7 @@ fn concat_bytes_expand(
_db: &dyn ExpandDatabase,
_arg_id: MacroCallId,
tt: &tt::Subtree,
- span: SpanData,
+ span: Span,
) -> ExpandResult<tt::Subtree> {
let mut bytes = Vec::new();
let mut err = None;
@@ -543,7 +585,7 @@ fn concat_idents_expand(
_db: &dyn ExpandDatabase,
_arg_id: MacroCallId,
tt: &tt::Subtree,
- span: SpanData,
+ span: Span,
) -> ExpandResult<tt::Subtree> {
let mut err = None;
let mut ident = String::new();
@@ -596,7 +638,7 @@ fn include_expand(
db: &dyn ExpandDatabase,
arg_id: MacroCallId,
tt: &tt::Subtree,
- span: SpanData,
+ span: Span,
) -> ExpandResult<tt::Subtree> {
let file_id = match include_input_to_file_id(db, arg_id, tt) {
Ok(it) => it,
@@ -629,11 +671,11 @@ fn include_bytes_expand(
_db: &dyn ExpandDatabase,
_arg_id: MacroCallId,
_tt: &tt::Subtree,
- span: SpanData,
+ span: Span,
) -> ExpandResult<tt::Subtree> {
// FIXME: actually read the file here if the user asked for macro expansion
let res = tt::Subtree {
- delimiter: tt::Delimiter::dummy_invisible(),
+ delimiter: tt::Delimiter::invisible_spanned(span),
token_trees: vec![tt::TokenTree::Leaf(tt::Leaf::Literal(tt::Literal {
text: r#"b"""#.into(),
span,
@@ -646,7 +688,7 @@ fn include_str_expand(
db: &dyn ExpandDatabase,
arg_id: MacroCallId,
tt: &tt::Subtree,
- span: SpanData,
+ span: Span,
) -> ExpandResult<tt::Subtree> {
let path = match parse_string(tt) {
Ok(it) => it,
@@ -681,7 +723,7 @@ fn env_expand(
db: &dyn ExpandDatabase,
arg_id: MacroCallId,
tt: &tt::Subtree,
- span: SpanData,
+ span: Span,
) -> ExpandResult<tt::Subtree> {
let key = match parse_string(tt) {
Ok(it) => it,
@@ -713,7 +755,7 @@ fn option_env_expand(
db: &dyn ExpandDatabase,
arg_id: MacroCallId,
tt: &tt::Subtree,
- span: SpanData,
+ span: Span,
) -> ExpandResult<tt::Subtree> {
let key = match parse_string(tt) {
Ok(it) => it,
@@ -729,3 +771,15 @@ fn option_env_expand(
ExpandResult::ok(expanded)
}
+
+fn quote_expand(
+ _db: &dyn ExpandDatabase,
+ _arg_id: MacroCallId,
+ _tt: &tt::Subtree,
+ span: Span,
+) -> ExpandResult<tt::Subtree> {
+ ExpandResult::new(
+ tt::Subtree::empty(tt::DelimSpan { open: span, close: span }),
+ ExpandError::other("quote! is not implemented"),
+ )
+}