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.rs | 168 |
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"), + ) +} |