Skip to content

Commit

Permalink
Auto merge of #16027 - Veykril:implicit-format-args, r=Veykril
Browse files Browse the repository at this point in the history
feat: Implicit format args support

Fixes #11260
Fixes #11296

![image](https://github.com/rust-lang/rust-analyzer/assets/3757771/14fe2caf-4ea3-40a5-8aa4-ff08ea0ccbde)
Too lazy to make a gif of this right now (would probably be good to show renaming)
  • Loading branch information
bors committed Dec 5, 2023
2 parents afc1ae1 + 9b7ec5e commit 05df6c5
Show file tree
Hide file tree
Showing 45 changed files with 921 additions and 331 deletions.
12 changes: 12 additions & 0 deletions crates/hir-def/src/body.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,8 @@ pub struct BodySourceMap {
field_map_back: FxHashMap<ExprId, FieldSource>,
pat_field_map_back: FxHashMap<PatId, PatFieldSource>,

format_args_template_map: FxHashMap<ExprId, Vec<(syntax::TextRange, Name)>>,

expansions: FxHashMap<InFile<AstPtr<ast::MacroCall>>, HirFileId>,

/// Diagnostics accumulated during body lowering. These contain `AstPtr`s and so are stored in
Expand Down Expand Up @@ -387,6 +389,14 @@ impl BodySourceMap {
self.expr_map.get(&src).copied()
}

pub fn implicit_format_args(
&self,
node: InFile<&ast::FormatArgsExpr>,
) -> Option<&[(syntax::TextRange, Name)]> {
let src = node.map(AstPtr::new).map(AstPtr::upcast::<ast::Expr>);
self.format_args_template_map.get(self.expr_map.get(&src)?).map(std::ops::Deref::deref)
}

/// Get a reference to the body source map's diagnostics.
pub fn diagnostics(&self) -> &[BodyDiagnostic] {
&self.diagnostics
Expand All @@ -403,8 +413,10 @@ impl BodySourceMap {
field_map_back,
pat_field_map_back,
expansions,
format_args_template_map,
diagnostics,
} = self;
format_args_template_map.shrink_to_fit();
expr_map.shrink_to_fit();
expr_map_back.shrink_to_fit();
pat_map.shrink_to_fit();
Expand Down
24 changes: 17 additions & 7 deletions crates/hir-def/src/body/lower.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1597,12 +1597,20 @@ impl ExprCollector<'_> {
});
let template = f.template();
let fmt_snippet = template.as_ref().map(ToString::to_string);
let mut mappings = vec![];
let fmt = match template.and_then(|it| self.expand_macros_to_string(it)) {
Some((s, is_direct_literal)) => {
format_args::parse(&s, fmt_snippet, args, is_direct_literal, |name| {
self.alloc_expr_desugared(Expr::Path(Path::from(name)))
})
}
Some((s, is_direct_literal)) => format_args::parse(
&s,
fmt_snippet,
args,
is_direct_literal,
|name| self.alloc_expr_desugared(Expr::Path(Path::from(name))),
|name, span| {
if let Some(span) = span {
mappings.push((span, name.clone()))
}
},
),
None => FormatArgs { template: Default::default(), arguments: args.finish() },
};

Expand Down Expand Up @@ -1746,14 +1754,16 @@ impl ExprCollector<'_> {
tail: Some(unsafe_arg_new),
});

self.alloc_expr(
let idx = self.alloc_expr(
Expr::Call {
callee: new_v1_formatted,
args: Box::new([lit_pieces, args, format_options, unsafe_arg_new]),
is_assignee_expr: false,
},
syntax_ptr,
)
);
self.source_map.format_args_template_map.insert(idx, mappings);
idx
}

/// Generate a hir expression for a format_args placeholder specification.
Expand Down
6 changes: 3 additions & 3 deletions crates/hir-def/src/body/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ fn main() {
let count = 10;
builtin#lang(Arguments::new_v1_formatted)(
&[
"\"hello ", " ", " friends, we ", " ", "", "\"",
"hello ", " ", " friends, we ", " ", "",
],
&[
builtin#lang(Argument::new_display)(
Expand Down Expand Up @@ -261,7 +261,7 @@ impl SsrError {
_ = $crate::error::SsrError::new(
builtin#lang(Arguments::new_v1_formatted)(
&[
"\"Failed to resolve path `", "`\"",
"Failed to resolve path `", "`",
],
&[
builtin#lang(Argument::new_display)(
Expand Down Expand Up @@ -320,7 +320,7 @@ fn f() {
$crate::panicking::panic_fmt(
builtin#lang(Arguments::new_v1_formatted)(
&[
"\"cc\"",
"cc",
],
&[],
&[],
Expand Down
14 changes: 10 additions & 4 deletions crates/hir-def/src/hir/format_args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use hir_expand::name::Name;
use rustc_dependencies::parse_format as parse;
use syntax::{
ast::{self, IsString},
AstToken, SmolStr, TextRange,
SmolStr, TextRange, TextSize,
};

use crate::hir::ExprId;
Expand Down Expand Up @@ -170,15 +170,18 @@ pub(crate) fn parse(
mut args: FormatArgumentsCollector,
is_direct_literal: bool,
mut synth: impl FnMut(Name) -> ExprId,
mut record_usage: impl FnMut(Name, Option<TextRange>),
) -> FormatArgs {
let text = s.text();
let text = s.text_without_quotes();
let str_style = match s.quote_offsets() {
Some(offsets) => {
let raw = u32::from(offsets.quotes.0.len()) - 1;
(raw != 0).then_some(raw as usize)
// subtract 1 for the `r` prefix
(raw != 0).then(|| raw as usize - 1)
}
None => None,
};

let mut parser =
parse::Parser::new(text, str_style, fmt_snippet, false, parse::ParseMode::Format);

Expand All @@ -199,6 +202,7 @@ pub(crate) fn parse(
let to_span = |inner_span: parse::InnerSpan| {
is_source_literal.then(|| {
TextRange::new(inner_span.start.try_into().unwrap(), inner_span.end.try_into().unwrap())
- TextSize::from(str_style.map(|it| it + 1).unwrap_or(0) as u32 + 1)
})
};

Expand Down Expand Up @@ -230,9 +234,10 @@ pub(crate) fn parse(
Err(index)
}
}
ArgRef::Name(name, _span) => {
ArgRef::Name(name, span) => {
let name = Name::new_text_dont_use(SmolStr::new(name));
if let Some((index, _)) = args.by_name(&name) {
record_usage(name, span);
// Name found in `args`, so we resolve it to its index.
if index < args.explicit_args().len() {
// Mark it as used, if it was an explicit argument.
Expand All @@ -246,6 +251,7 @@ pub(crate) fn parse(
// disabled (see RFC #2795)
// FIXME: Diagnose
}
record_usage(name.clone(), span);
Ok(args.add(FormatArgument {
kind: FormatArgumentKind::Captured(name.clone()),
// FIXME: This is problematic, we might want to synthesize a dummy
Expand Down
2 changes: 0 additions & 2 deletions crates/hir-expand/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -629,8 +629,6 @@ impl ExpansionInfo {
pub fn map_range_down<'a>(
&'a self,
span: SpanData,
// FIXME: use this for range mapping, so that we can resolve inline format args
_relative_token_offset: Option<TextSize>,
) -> Option<impl Iterator<Item = InMacroFile<SyntaxToken>> + 'a> {
let tokens = self
.exp_map
Expand Down
4 changes: 3 additions & 1 deletion crates/hir/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,9 @@ pub use crate::{
attrs::{resolve_doc_path_on, HasAttrs},
diagnostics::*,
has_source::HasSource,
semantics::{PathResolution, Semantics, SemanticsScope, TypeInfo, VisibleTraits},
semantics::{
DescendPreference, PathResolution, Semantics, SemanticsScope, TypeInfo, VisibleTraits,
},
};

// Be careful with these re-exports.
Expand Down
Loading

0 comments on commit 05df6c5

Please sign in to comment.