Skip to content

Commit 12bc80e

Browse files
committed
Improve suggest construct with literal syntax instead of calling
Signed-off-by: xizheyin <[email protected]>
1 parent c7706c6 commit 12bc80e

File tree

1 file changed

+75
-35
lines changed

1 file changed

+75
-35
lines changed

compiler/rustc_resolve/src/late/diagnostics.rs

+75-35
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ use rustc_session::{Session, lint};
2727
use rustc_span::edit_distance::{edit_distance, find_best_match_for_name};
2828
use rustc_span::edition::Edition;
2929
use rustc_span::hygiene::MacroKind;
30-
use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw, sym};
30+
use rustc_span::{BytePos, DUMMY_SP, Ident, Span, Symbol, kw, sym};
3131
use thin_vec::ThinVec;
3232
use tracing::debug;
3333

@@ -1681,41 +1681,81 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
16811681
// the struct literal syntax at all, as that will cause a subsequent error.
16821682
let fields = this.r.field_idents(def_id);
16831683
let has_fields = fields.as_ref().is_some_and(|f| !f.is_empty());
1684-
let (fields, applicability) = match fields {
1685-
Some(fields) => {
1686-
let fields = if let Some(old_fields) = old_fields {
1687-
fields
1688-
.iter()
1689-
.enumerate()
1690-
.map(|(idx, new)| (new, old_fields.get(idx)))
1691-
.map(|(new, old)| {
1692-
if let Some(Some(old)) = old
1693-
&& new.as_str() != old
1694-
{
1695-
format!("{new}: {old}")
1696-
} else {
1697-
new.to_string()
1698-
}
1699-
})
1700-
.collect::<Vec<String>>()
1701-
} else {
1702-
fields
1703-
.iter()
1704-
.map(|f| format!("{f}{tail}"))
1705-
.collect::<Vec<String>>()
1706-
};
1707-
1708-
(fields.join(", "), applicability)
1709-
}
1710-
None => ("/* fields */".to_string(), Applicability::HasPlaceholders),
1711-
};
1712-
let pad = if has_fields { " " } else { "" };
1713-
err.span_suggestion(
1684+
1685+
if let PathSource::Expr(Some(Expr {
1686+
kind: ExprKind::Call(path, args),
17141687
span,
1715-
format!("use struct {descr} syntax instead"),
1716-
format!("{path_str} {{{pad}{fields}{pad}}}"),
1717-
applicability,
1718-
);
1688+
..
1689+
})) = source
1690+
&& !args.is_empty()
1691+
&& let Some(fields) = &fields
1692+
&& args.len() == fields.len()
1693+
// Make sure we have same number of args as fields
1694+
{
1695+
let path_span = path.span;
1696+
let mut parts = Vec::new();
1697+
1698+
// Start with the opening brace
1699+
parts.push((
1700+
Span::with_root_ctxt(path_span.hi(), path_span.hi() + BytePos(1)),
1701+
"{".to_owned(),
1702+
));
1703+
1704+
for (field, arg) in fields.iter().zip(args.iter()) {
1705+
// Add the field name before the argument
1706+
parts.push((arg.span.shrink_to_lo(), format!("{}: ", field)));
1707+
}
1708+
1709+
// Add the closing brace
1710+
parts.push((
1711+
Span::with_root_ctxt(span.hi() - BytePos(1), span.hi()),
1712+
"}".to_owned(),
1713+
));
1714+
1715+
err.multipart_suggestion_verbose(
1716+
format!("use struct {descr} syntax instead of calling"),
1717+
parts,
1718+
applicability,
1719+
);
1720+
} else {
1721+
let (fields, applicability) = match fields {
1722+
Some(fields) => {
1723+
let fields = if let Some(old_fields) = old_fields {
1724+
fields
1725+
.iter()
1726+
.enumerate()
1727+
.map(|(idx, new)| (new, old_fields.get(idx)))
1728+
.map(|(new, old)| {
1729+
if let Some(Some(old)) = old
1730+
&& new.as_str() != old
1731+
{
1732+
format!("{new}: {old}")
1733+
} else {
1734+
new.to_string()
1735+
}
1736+
})
1737+
.collect::<Vec<String>>()
1738+
} else {
1739+
fields
1740+
.iter()
1741+
.map(|f| format!("{f}{tail}"))
1742+
.collect::<Vec<String>>()
1743+
};
1744+
1745+
(fields.join(", "), applicability)
1746+
}
1747+
None => {
1748+
("/* fields */".to_string(), Applicability::HasPlaceholders)
1749+
}
1750+
};
1751+
let pad = if has_fields { " " } else { "" };
1752+
err.span_suggestion(
1753+
span,
1754+
format!("use struct {descr} syntax instead"),
1755+
format!("{path_str} {{{pad}{fields}{pad}}}"),
1756+
applicability,
1757+
);
1758+
}
17191759
}
17201760
if let PathSource::Expr(Some(Expr {
17211761
kind: ExprKind::Call(path, args),

0 commit comments

Comments
 (0)