Don't allocate the format_args template string as an expression

This commit is contained in:
Lukas Wirth 2023-09-06 18:52:12 +02:00
parent 3fa0bf0dd3
commit 5046889f43
4 changed files with 31 additions and 46 deletions

View File

@ -32,7 +32,7 @@
hir::{ hir::{
dummy_expr_id, dummy_expr_id,
format_args::{ format_args::{
self, FormatAlignment, FormatArgsPiece, FormatArgument, FormatArgumentKind, self, FormatAlignment, FormatArgs, FormatArgsPiece, FormatArgument, FormatArgumentKind,
FormatArgumentsCollector, FormatCount, FormatDebugHex, FormatOptions, FormatArgumentsCollector, FormatCount, FormatDebugHex, FormatOptions,
FormatPlaceholder, FormatSign, FormatTrait, FormatPlaceholder, FormatSign, FormatTrait,
}, },
@ -1568,6 +1568,24 @@ fn with_opt_labeled_rib<T>(
// endregion: labels // endregion: labels
// region: format // region: format
fn expand_macros_to_string(&mut self, expr: ast::Expr) -> Option<(ast::String, bool)> {
let m = match expr {
ast::Expr::MacroExpr(m) => m,
ast::Expr::Literal(l) => {
return match l.kind() {
ast::LiteralKind::String(s) => Some((s, true)),
_ => None,
}
}
_ => return None,
};
let e = m.macro_call()?;
let macro_ptr = AstPtr::new(&e);
let (exp, _) = self.collect_macro_call(e, macro_ptr, true, |this, expansion| {
expansion.and_then(|it| this.expand_macros_to_string(it))
})?;
Some((exp, false))
}
fn collect_format_args( fn collect_format_args(
&mut self, &mut self,
@ -1586,31 +1604,13 @@ fn collect_format_args(
}); });
let template = f.template(); let template = f.template();
let fmt_snippet = template.as_ref().map(ToString::to_string); let fmt_snippet = template.as_ref().map(ToString::to_string);
let fmt = match template.and_then(|it| self.expand_macros_to_string(it)) {
// FIXME: We shouldn't allocate this one, just resolve and expand the macros to fetch the Some((s, is_direct_literal)) => {
// string literal! format_args::parse(&s, fmt_snippet, args, is_direct_literal, |name| {
let expr = self.collect_expr_opt(template); self.alloc_expr_desugared(Expr::Path(Path::from(name)))
})
let fmt = 'b: {
if let Expr::Literal(Literal::String(_)) = self.body[expr] {
let source = self.source_map.expr_map_back[expr].clone();
let is_direct_literal = source.file_id == self.expander.current_file_id;
if let ast::Expr::Literal(l) =
source.value.to_node(&self.db.parse_or_expand(source.file_id))
{
if let ast::LiteralKind::String(s) = l.kind() {
break 'b format_args::parse(
expr,
&s,
fmt_snippet,
args,
is_direct_literal,
|name| self.alloc_expr_desugared(Expr::Path(Path::from(name))),
);
}
}
} }
return self.missing_expr(); None => FormatArgs { template: Default::default(), arguments: args.finish() },
}; };
// Create a list of all _unique_ (argument, format trait) combinations. // Create a list of all _unique_ (argument, format trait) combinations.

View File

@ -161,7 +161,7 @@ fn main() {
let count = 10; let count = 10;
builtin#lang(Arguments::new_v1_formatted)( builtin#lang(Arguments::new_v1_formatted)(
&[ &[
"\"hello ", " ", " friends, we ", " ", "", "\"", "\"hello ", " ", " friends, we ", " ", "", "\"",
], ],
&[ &[
builtin#lang(Argument::new_display)( builtin#lang(Argument::new_display)(
@ -172,7 +172,7 @@ fn main() {
&are, &are,
), builtin#lang(Argument::new_display)( ), builtin#lang(Argument::new_display)(
&"!", &"!",
), ),
], ],
&[ &[
builtin#lang(Placeholder::new)( builtin#lang(Placeholder::new)(
@ -212,7 +212,7 @@ fn main() {
0u32, 0u32,
builtin#lang(Count::Implied), builtin#lang(Count::Implied),
builtin#lang(Count::Implied), builtin#lang(Count::Implied),
), ),
], ],
unsafe { unsafe {
builtin#lang(UnsafeArg::new)() builtin#lang(UnsafeArg::new)()

View File

@ -1,3 +1,4 @@
//! Parses `format_args` input.
use std::mem; use std::mem;
use hir_expand::name::Name; use hir_expand::name::Name;
@ -12,7 +13,6 @@
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub struct FormatArgs { pub struct FormatArgs {
pub template_expr: ExprId,
pub template: Box<[FormatArgsPiece]>, pub template: Box<[FormatArgsPiece]>,
pub arguments: FormatArguments, pub arguments: FormatArguments,
} }
@ -166,7 +166,6 @@ enum PositionUsedAs {
use PositionUsedAs::*; use PositionUsedAs::*;
pub(crate) fn parse( pub(crate) fn parse(
expr: ExprId,
s: &ast::String, s: &ast::String,
fmt_snippet: Option<String>, fmt_snippet: Option<String>,
mut args: FormatArgumentsCollector, mut args: FormatArgumentsCollector,
@ -195,11 +194,7 @@ pub(crate) fn parse(
let is_source_literal = parser.is_source_literal; let is_source_literal = parser.is_source_literal;
if !parser.errors.is_empty() { if !parser.errors.is_empty() {
// FIXME: Diagnose // FIXME: Diagnose
return FormatArgs { return FormatArgs { template: Default::default(), arguments: args.finish() };
template_expr: expr,
template: Default::default(),
arguments: args.finish(),
};
} }
let to_span = |inner_span: parse::InnerSpan| { let to_span = |inner_span: parse::InnerSpan| {
@ -419,11 +414,7 @@ enum ArgRef<'a> {
// FIXME: Diagnose // FIXME: Diagnose
} }
FormatArgs { FormatArgs { template: template.into_boxed_slice(), arguments: args.finish() }
template_expr: expr,
template: template.into_boxed_slice(),
arguments: args.finish(),
}
} }
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]

View File

@ -34,23 +34,17 @@ pub(crate) fn extract_expressions_from_format_string(
let fmt_string = ctx.find_token_at_offset::<ast::String>()?; let fmt_string = ctx.find_token_at_offset::<ast::String>()?;
let tt = fmt_string.syntax().parent().and_then(ast::TokenTree::cast)?; let tt = fmt_string.syntax().parent().and_then(ast::TokenTree::cast)?;
dbg!();
let expanded_t = ast::String::cast( let expanded_t = ast::String::cast(
ctx.sema.descend_into_macros_with_kind_preference(fmt_string.syntax().clone(), 0.into()), ctx.sema.descend_into_macros_with_kind_preference(fmt_string.syntax().clone(), 0.into()),
)?; )?;
dbg!();
if !is_format_string(&expanded_t) { if !is_format_string(&expanded_t) {
dbg!();
return None; return None;
} }
dbg!();
let (new_fmt, extracted_args) = parse_format_exprs(fmt_string.text()).ok()?; let (new_fmt, extracted_args) = parse_format_exprs(fmt_string.text()).ok()?;
dbg!();
if extracted_args.is_empty() { if extracted_args.is_empty() {
return None; return None;
} }
dbg!();
acc.add( acc.add(
AssistId( AssistId(