summaryrefslogtreecommitdiffstats
path: root/src/tools/rust-analyzer/crates/hir-expand
diff options
context:
space:
mode:
Diffstat (limited to 'src/tools/rust-analyzer/crates/hir-expand')
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs9
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs170
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/hygiene.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/lib.rs19
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/name.rs25
5 files changed, 47 insertions, 178 deletions
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs b/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs
index 4c918e55b..0ec2422b3 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs
@@ -342,14 +342,7 @@ fn inner_attributes(
ast::Impl(it) => it.assoc_item_list()?.syntax().clone(),
ast::Module(it) => it.item_list()?.syntax().clone(),
ast::BlockExpr(it) => {
- use syntax::SyntaxKind::{BLOCK_EXPR , EXPR_STMT};
- // Block expressions accept outer and inner attributes, but only when they are the outer
- // expression of an expression statement or the final expression of another block expression.
- let may_carry_attributes = matches!(
- it.syntax().parent().map(|it| it.kind()),
- Some(BLOCK_EXPR | EXPR_STMT)
- );
- if !may_carry_attributes {
+ if !it.may_carry_attributes() {
return None
}
syntax.clone()
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs
index 95c6baf42..30b19b6e5 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs
@@ -1,13 +1,9 @@
//! Builtin macro
-use std::mem;
-
-use ::tt::Ident;
use base_db::{AnchoredPath, Edition, FileId};
use cfg::CfgExpr;
use either::Either;
use mbe::{parse_exprs_with_sep, parse_to_token_tree, TokenMap};
-use rustc_hash::FxHashMap;
use syntax::{
ast::{self, AstToken},
SmolStr,
@@ -97,11 +93,11 @@ register_builtin! {
(unreachable, Unreachable) => unreachable_expand,
(log_syntax, LogSyntax) => log_syntax_expand,
(trace_macros, TraceMacros) => trace_macros_expand,
-
- EAGER:
(format_args, FormatArgs) => format_args_expand,
(const_format_args, ConstFormatArgs) => format_args_expand,
(format_args_nl, FormatArgsNl) => format_args_nl_expand,
+
+ EAGER:
(compile_error, CompileError) => compile_error_expand,
(concat, Concat) => concat_expand,
(concat_idents, ConcatIdents) => concat_idents_expand,
@@ -247,151 +243,15 @@ fn format_args_expand_general(
_db: &dyn ExpandDatabase,
_id: MacroCallId,
tt: &tt::Subtree,
- end_string: &str,
+ // FIXME: Make use of this so that mir interpretation works properly
+ _end_string: &str,
) -> ExpandResult<tt::Subtree> {
- let args = parse_exprs_with_sep(tt, ',');
-
- let expand_error =
- ExpandResult::new(tt::Subtree::empty(), mbe::ExpandError::NoMatchingRule.into());
-
- let mut key_args = FxHashMap::default();
- let mut args = args.into_iter().filter_map(|mut arg| {
- // Remove `key =`.
- if matches!(arg.token_trees.get(1), Some(tt::TokenTree::Leaf(tt::Leaf::Punct(p))) if p.char == '=')
- {
- // but not with `==`
- if !matches!(arg.token_trees.get(2), Some(tt::TokenTree::Leaf(tt::Leaf::Punct(p))) if p.char == '=')
- {
- let key = arg.token_trees.drain(..2).next().unwrap();
- key_args.insert(key.to_string(), arg);
- return None;
- }
- }
- Some(arg)
- }).collect::<Vec<_>>().into_iter();
- // ^^^^^^^ we need this collect, to enforce the side effect of the filter_map closure (building the `key_args`)
- let Some(format_subtree) = args.next() else {
- return expand_error;
- };
- let format_string = (|| {
- let token_tree = format_subtree.token_trees.get(0)?;
- match token_tree {
- tt::TokenTree::Leaf(l) => match l {
- tt::Leaf::Literal(l) => {
- if let Some(mut text) = l.text.strip_prefix('r') {
- let mut raw_sharps = String::new();
- while let Some(t) = text.strip_prefix('#') {
- text = t;
- raw_sharps.push('#');
- }
- text =
- text.strip_suffix(&raw_sharps)?.strip_prefix('"')?.strip_suffix('"')?;
- Some((text, l.span, Some(raw_sharps)))
- } else {
- let text = l.text.strip_prefix('"')?.strip_suffix('"')?;
- let span = l.span;
- Some((text, span, None))
- }
- }
- _ => None,
- },
- tt::TokenTree::Subtree(_) => None,
- }
- })();
- let Some((format_string, _format_string_span, raw_sharps)) = format_string else {
- return expand_error;
- };
- let mut format_iter = format_string.chars().peekable();
- let mut parts = vec![];
- let mut last_part = String::new();
- let mut arg_tts = vec![];
- let mut err = None;
- while let Some(c) = format_iter.next() {
- // Parsing the format string. See https://doc.rust-lang.org/std/fmt/index.html#syntax for the grammar and more info
- match c {
- '{' => {
- if format_iter.peek() == Some(&'{') {
- format_iter.next();
- last_part.push('{');
- continue;
- }
- let mut argument = String::new();
- while ![Some(&'}'), Some(&':')].contains(&format_iter.peek()) {
- argument.push(match format_iter.next() {
- Some(c) => c,
- None => return expand_error,
- });
- }
- let format_spec = match format_iter.next().unwrap() {
- '}' => "".to_owned(),
- ':' => {
- let mut s = String::new();
- while let Some(c) = format_iter.next() {
- if c == '}' {
- break;
- }
- s.push(c);
- }
- s
- }
- _ => unreachable!(),
- };
- parts.push(mem::take(&mut last_part));
- let arg_tree = if argument.is_empty() {
- match args.next() {
- Some(it) => it,
- None => {
- err = Some(mbe::ExpandError::NoMatchingRule.into());
- tt::Subtree::empty()
- }
- }
- } else if let Some(tree) = key_args.get(&argument) {
- tree.clone()
- } else {
- // FIXME: we should pick the related substring of the `_format_string_span` as the span. You
- // can use `.char_indices()` instead of `.char()` for `format_iter` to find the substring interval.
- let ident = Ident::new(argument, tt::TokenId::unspecified());
- quote!(#ident)
- };
- let formatter = match &*format_spec {
- "?" => quote!(::core::fmt::Debug::fmt),
- "" => quote!(::core::fmt::Display::fmt),
- _ => {
- // FIXME: implement the rest and return expand error here
- quote!(::core::fmt::Display::fmt)
- }
- };
- arg_tts.push(quote! { ::core::fmt::ArgumentV1::new(&(#arg_tree), #formatter), });
- }
- '}' => {
- if format_iter.peek() == Some(&'}') {
- format_iter.next();
- last_part.push('}');
- } else {
- return expand_error;
- }
- }
- _ => last_part.push(c),
- }
- }
- last_part += end_string;
- if !last_part.is_empty() {
- parts.push(last_part);
- }
- let part_tts = parts.into_iter().map(|it| {
- let text = if let Some(raw) = &raw_sharps {
- format!("r{raw}\"{}\"{raw}", it).into()
- } else {
- format!("\"{}\"", it).into()
- };
- let l = tt::Literal { span: tt::TokenId::unspecified(), text };
- quote!(#l ,)
+ let pound = quote! {@PUNCT '#'};
+ let mut tt = tt.clone();
+ tt.delimiter.kind = tt::DelimiterKind::Parenthesis;
+ return ExpandResult::ok(quote! {
+ builtin #pound format_args #tt
});
- let arg_tts = arg_tts.into_iter().flat_map(|arg| arg.token_trees);
- let expanded = quote! {
- ::core::fmt::Arguments::new_v1(&[##part_tts], &[##arg_tts])
- };
- ExpandResult { value: expanded, err }
}
fn asm_expand(
@@ -415,10 +275,12 @@ fn asm_expand(
}
}
- let expanded = quote! {{
- ##literals
- loop {}
- }};
+ let pound = quote! {@PUNCT '#'};
+ let expanded = quote! {
+ builtin #pound asm (
+ {##literals}
+ )
+ };
ExpandResult::ok(expanded)
}
@@ -692,7 +554,7 @@ pub(crate) fn include_arg_to_tt(
arg_id: MacroCallId,
) -> Result<(triomphe::Arc<(::tt::Subtree<::tt::TokenId>, TokenMap)>, FileId), ExpandError> {
let loc = db.lookup_intern_macro_call(arg_id);
- let Some(EagerCallInfo { arg,arg_id, .. }) = loc.eager.as_deref() else {
+ let Some(EagerCallInfo { arg, arg_id, .. }) = loc.eager.as_deref() else {
panic!("include_arg_to_tt called on non include macro call: {:?}", &loc.eager);
};
let path = parse_string(&arg.0)?;
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/hygiene.rs b/src/tools/rust-analyzer/crates/hir-expand/src/hygiene.rs
index ade4a5928..ca65db113 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/hygiene.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/hygiene.rs
@@ -242,7 +242,7 @@ impl HygieneFrame {
krate,
call_site: None,
def_site: None,
- }
+ };
};
let def_site = info.attr_input_or_mac_def_start.map(|it| db.hygiene_frame(it.file_id));
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs b/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs
index 1f1e20f49..4be55126b 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs
@@ -37,7 +37,7 @@ use either::Either;
use syntax::{
algo::{self, skip_trivia_token},
ast::{self, AstNode, HasDocComments},
- AstPtr, Direction, SyntaxNode, SyntaxNodePtr, SyntaxToken,
+ AstPtr, Direction, SyntaxNode, SyntaxNodePtr, SyntaxToken, TextSize,
};
use crate::{
@@ -544,7 +544,7 @@ impl MacroCallKind {
};
let range = match kind {
- MacroCallKind::FnLike { ast_id, .. } => ast_id.to_node(db).syntax().text_range(),
+ MacroCallKind::FnLike { ast_id, .. } => ast_id.to_ptr(db).text_range(),
MacroCallKind::Derive { ast_id, derive_attr_index, .. } => {
// FIXME: should be the range of the macro name, not the whole derive
// FIXME: handle `cfg_attr`
@@ -642,6 +642,8 @@ impl ExpansionInfo {
db: &dyn db::ExpandDatabase,
item: Option<ast::Item>,
token: InFile<&SyntaxToken>,
+ // FIXME: use this for range mapping, so that we can resolve inline format args
+ _relative_token_offset: Option<TextSize>,
) -> Option<impl Iterator<Item = InFile<SyntaxToken>> + '_> {
assert_eq!(token.file_id, self.arg.file_id);
let token_id_in_attr_input = if let Some(item) = item {
@@ -840,9 +842,6 @@ impl<N: AstIdNode> AstId<N> {
pub type ErasedAstId = InFile<ErasedFileAstId>;
impl ErasedAstId {
- pub fn to_node(&self, db: &dyn db::ExpandDatabase) -> SyntaxNode {
- self.to_ptr(db).to_node(&db.parse_or_expand(self.file_id))
- }
pub fn to_ptr(&self, db: &dyn db::ExpandDatabase) -> SyntaxNodePtr {
db.ast_id_map(self.file_id).get_raw(self.value)
}
@@ -1054,16 +1053,6 @@ impl InFile<SyntaxToken> {
}
}
}
-
- pub fn ancestors_with_macros(
- self,
- db: &dyn db::ExpandDatabase,
- ) -> impl Iterator<Item = InFile<SyntaxNode>> + '_ {
- self.value.parent().into_iter().flat_map({
- let file_id = self.file_id;
- move |parent| InFile::new(file_id, &parent).ancestors_with_macros(db)
- })
- }
}
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/name.rs b/src/tools/rust-analyzer/crates/hir-expand/src/name.rs
index 7c179c0cf..a876f48bd 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/name.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/name.rs
@@ -54,6 +54,12 @@ impl Name {
Name(Repr::Text(text))
}
+ // FIXME: See above, unfortunately some places really need this right now
+ #[doc(hidden)]
+ pub const fn new_text_dont_use(text: SmolStr) -> Name {
+ Name(Repr::Text(text))
+ }
+
pub fn new_tuple_field(idx: usize) -> Name {
Name(Repr::TupleField(idx))
}
@@ -302,6 +308,16 @@ pub mod known {
rust_2018,
rust_2021,
v1,
+ new_display,
+ new_debug,
+ new_lower_exp,
+ new_upper_exp,
+ new_octal,
+ new_pointer,
+ new_binary,
+ new_lower_hex,
+ new_upper_hex,
+ from_usize,
// Components of known path (type name)
Iterator,
IntoIterator,
@@ -327,6 +343,13 @@ pub mod known {
Not,
None,
Index,
+ Left,
+ Right,
+ Center,
+ Unknown,
+ Is,
+ Param,
+ Implied,
// Components of known path (function name)
filter_map,
next,
@@ -335,6 +358,8 @@ pub mod known {
is_empty,
as_str,
new,
+ new_v1_formatted,
+ none,
// Builtin macros
asm,
assert,