Skip to content

Commit 4648650

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

File tree

2 files changed

+89
-36
lines changed

2 files changed

+89
-36
lines changed

Diff for: compiler/rustc_resolve/src/late/diagnostics.rs

+74-34
Original file line numberDiff line numberDiff line change
@@ -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+
path_span.shrink_to_hi().until(args[0].span),
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+
args.last().unwrap().span.shrink_to_hi().until(span.shrink_to_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),

Diff for: tests/ui/structs/struct-construct-with-call-issue-138931.stderr

+15-2
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,13 @@ LL | | }
77
| |_- `PersonOnlyName` defined here
88
...
99
LL | let wilfred = PersonOnlyName("Name1".to_owned());
10-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use struct literal syntax instead: `PersonOnlyName { name: val }`
10+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
11+
|
12+
help: use struct literal syntax instead of calling
13+
|
14+
LL - let wilfred = PersonOnlyName("Name1".to_owned());
15+
LL + let wilfred = PersonOnlyName{name: "Name1".to_owned()};
16+
|
1117

1218
error[E0423]: expected function, tuple struct or tuple variant, found struct `PersonWithAge`
1319
--> $DIR/struct-construct-with-call-issue-138931.rs:17:16
@@ -25,7 +31,14 @@ LL | | "Name2".to_owned(),
2531
LL | | 20,
2632
LL | | 180,
2733
LL | | );
28-
| |_____^ help: use struct literal syntax instead: `PersonWithAge { name: val, age: val, height: val }`
34+
| |_____^
35+
|
36+
help: use struct literal syntax instead of calling
37+
|
38+
LL ~ let bill = PersonWithAge{name: "Name2".to_owned(),
39+
LL ~ age: 20,
40+
LL ~ height: 180};
41+
|
2942

3043
error[E0423]: expected function, tuple struct or tuple variant, found struct `PersonWithAge`
3144
--> $DIR/struct-construct-with-call-issue-138931.rs:23:18

0 commit comments

Comments
 (0)