Skip to content

Commit be5c7ab

Browse files
authored
Rollup merge of #74211 - estebank:struct-pat-as-unit, r=petrochenkov
Structured suggestion when not using struct pattern r? @petrochenkov
2 parents 353df59 + 0429820 commit be5c7ab

23 files changed

+239
-139
lines changed

Diff for: src/librustc_resolve/build_reduced_graph.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -300,9 +300,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
300300
}
301301

302302
fn insert_field_names(&mut self, def_id: DefId, field_names: Vec<Spanned<Symbol>>) {
303-
if !field_names.is_empty() {
304-
self.r.field_names.insert(def_id, field_names);
305-
}
303+
self.r.field_names.insert(def_id, field_names);
306304
}
307305

308306
fn block_needs_anonymous_module(&mut self, block: &Block) -> bool {
@@ -1428,6 +1426,8 @@ impl<'a, 'b> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b> {
14281426
let ctor_kind = CtorKind::from_ast(&variant.data);
14291427
let ctor_res = Res::Def(DefKind::Ctor(CtorOf::Variant, ctor_kind), ctor_def_id);
14301428
self.r.define(parent, ident, ValueNS, (ctor_res, ctor_vis, variant.span, expn_id));
1429+
// Record field names for error reporting.
1430+
self.insert_field_names_local(ctor_def_id, &variant.data);
14311431

14321432
visit::walk_variant(self, variant);
14331433
}

Diff for: src/librustc_resolve/late.rs

+8-8
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@ crate enum PathSource<'a> {
184184
// Paths in struct expressions and patterns `Path { .. }`.
185185
Struct,
186186
// Paths in tuple struct patterns `Path(..)`.
187-
TupleStruct,
187+
TupleStruct(Span),
188188
// `m::A::B` in `<T as m::A>::B::C`.
189189
TraitItem(Namespace),
190190
}
@@ -193,7 +193,7 @@ impl<'a> PathSource<'a> {
193193
fn namespace(self) -> Namespace {
194194
match self {
195195
PathSource::Type | PathSource::Trait(_) | PathSource::Struct => TypeNS,
196-
PathSource::Expr(..) | PathSource::Pat | PathSource::TupleStruct => ValueNS,
196+
PathSource::Expr(..) | PathSource::Pat | PathSource::TupleStruct(_) => ValueNS,
197197
PathSource::TraitItem(ns) => ns,
198198
}
199199
}
@@ -204,7 +204,7 @@ impl<'a> PathSource<'a> {
204204
| PathSource::Expr(..)
205205
| PathSource::Pat
206206
| PathSource::Struct
207-
| PathSource::TupleStruct => true,
207+
| PathSource::TupleStruct(_) => true,
208208
PathSource::Trait(_) | PathSource::TraitItem(..) => false,
209209
}
210210
}
@@ -215,7 +215,7 @@ impl<'a> PathSource<'a> {
215215
PathSource::Trait(_) => "trait",
216216
PathSource::Pat => "unit struct, unit variant or constant",
217217
PathSource::Struct => "struct, variant or union type",
218-
PathSource::TupleStruct => "tuple struct or tuple variant",
218+
PathSource::TupleStruct(_) => "tuple struct or tuple variant",
219219
PathSource::TraitItem(ns) => match ns {
220220
TypeNS => "associated type",
221221
ValueNS => "method or associated constant",
@@ -301,7 +301,7 @@ impl<'a> PathSource<'a> {
301301
| Res::SelfCtor(..) => true,
302302
_ => false,
303303
},
304-
PathSource::TupleStruct => match res {
304+
PathSource::TupleStruct(_) => match res {
305305
Res::Def(DefKind::Ctor(_, CtorKind::Fn), _) | Res::SelfCtor(..) => true,
306306
_ => false,
307307
},
@@ -336,8 +336,8 @@ impl<'a> PathSource<'a> {
336336
(PathSource::Struct, false) => error_code!(E0422),
337337
(PathSource::Expr(..), true) => error_code!(E0423),
338338
(PathSource::Expr(..), false) => error_code!(E0425),
339-
(PathSource::Pat | PathSource::TupleStruct, true) => error_code!(E0532),
340-
(PathSource::Pat | PathSource::TupleStruct, false) => error_code!(E0531),
339+
(PathSource::Pat | PathSource::TupleStruct(_), true) => error_code!(E0532),
340+
(PathSource::Pat | PathSource::TupleStruct(_), false) => error_code!(E0531),
341341
(PathSource::TraitItem(..), true) => error_code!(E0575),
342342
(PathSource::TraitItem(..), false) => error_code!(E0576),
343343
}
@@ -1483,7 +1483,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
14831483
self.r.record_partial_res(pat.id, PartialRes::new(res));
14841484
}
14851485
PatKind::TupleStruct(ref path, ..) => {
1486-
self.smart_resolve_path(pat.id, None, path, PathSource::TupleStruct);
1486+
self.smart_resolve_path(pat.id, None, path, PathSource::TupleStruct(pat.span));
14871487
}
14881488
PatKind::Path(ref qself, ref path) => {
14891489
self.smart_resolve_path(pat.id, qself.as_ref(), path, PathSource::Pat);

Diff for: src/librustc_resolve/late/diagnostics.rs

+57-11
Original file line numberDiff line numberDiff line change
@@ -480,10 +480,12 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> {
480480

481481
let mut bad_struct_syntax_suggestion = |def_id: DefId| {
482482
let (followed_by_brace, closing_brace) = self.followed_by_brace(span);
483-
let mut suggested = false;
483+
484484
match source {
485-
PathSource::Expr(Some(parent)) => {
486-
suggested = path_sep(err, &parent);
485+
PathSource::Expr(Some(
486+
parent @ Expr { kind: ExprKind::Field(..) | ExprKind::MethodCall(..), .. },
487+
)) => {
488+
path_sep(err, &parent);
487489
}
488490
PathSource::Expr(None) if followed_by_brace => {
489491
if let Some(sp) = closing_brace {
@@ -505,15 +507,56 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> {
505507
),
506508
);
507509
}
508-
suggested = true;
509510
}
510-
_ => {}
511-
}
512-
if !suggested {
513-
if let Some(span) = self.r.opt_span(def_id) {
514-
err.span_label(span, &format!("`{}` defined here", path_str));
511+
PathSource::Expr(
512+
None | Some(Expr { kind: ExprKind::Call(..) | ExprKind::Path(..), .. }),
513+
)
514+
| PathSource::TupleStruct(_)
515+
| PathSource::Pat => {
516+
let span = match &source {
517+
PathSource::Expr(Some(Expr {
518+
span, kind: ExprKind::Call(_, _), ..
519+
}))
520+
| PathSource::TupleStruct(span) => {
521+
// We want the main underline to cover the suggested code as well for
522+
// cleaner output.
523+
err.set_span(*span);
524+
*span
525+
}
526+
_ => span,
527+
};
528+
if let Some(span) = self.r.opt_span(def_id) {
529+
err.span_label(span, &format!("`{}` defined here", path_str));
530+
}
531+
let (tail, descr, applicability) = match source {
532+
PathSource::Pat | PathSource::TupleStruct(_) => {
533+
("", "pattern", Applicability::MachineApplicable)
534+
}
535+
_ => (": val", "literal", Applicability::HasPlaceholders),
536+
};
537+
let (fields, applicability) = match self.r.field_names.get(&def_id) {
538+
Some(fields) => (
539+
fields
540+
.iter()
541+
.map(|f| format!("{}{}", f.node, tail))
542+
.collect::<Vec<String>>()
543+
.join(", "),
544+
applicability,
545+
),
546+
None => ("/* fields */".to_string(), Applicability::HasPlaceholders),
547+
};
548+
let pad = match self.r.field_names.get(&def_id) {
549+
Some(fields) if fields.is_empty() => "",
550+
_ => " ",
551+
};
552+
err.span_suggestion(
553+
span,
554+
&format!("use struct {} syntax instead", descr),
555+
format!("{} {{{pad}{}{pad}}}", path_str, fields, pad = pad),
556+
applicability,
557+
);
515558
}
516-
err.span_label(span, format!("did you mean `{} {{ /* fields */ }}`?", path_str));
559+
_ => {}
517560
}
518561
};
519562

@@ -546,7 +589,10 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> {
546589
return false;
547590
}
548591
}
549-
(Res::Def(DefKind::Enum, def_id), PathSource::TupleStruct | PathSource::Expr(..)) => {
592+
(
593+
Res::Def(DefKind::Enum, def_id),
594+
PathSource::TupleStruct(_) | PathSource::Expr(..),
595+
) => {
550596
if let Some(variants) = self.collect_enum_variants(def_id) {
551597
if !variants.is_empty() {
552598
let msg = if variants.len() == 1 {

Diff for: src/test/ui/empty/empty-struct-braces-expr.stderr

+37-23
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,20 @@ LL | struct Empty1 {}
66
...
77
LL | let e1 = Empty1;
88
| ^^^^^^
9-
| |
10-
| did you mean `Empty1 { /* fields */ }`?
11-
| help: a unit struct with a similar name exists: `XEmpty2`
129
|
1310
::: $DIR/auxiliary/empty-struct.rs:2:1
1411
|
1512
LL | pub struct XEmpty2;
1613
| ------------------- similarly named unit struct `XEmpty2` defined here
14+
|
15+
help: a unit struct with a similar name exists
16+
|
17+
LL | let e1 = XEmpty2;
18+
| ^^^^^^^
19+
help: use struct literal syntax instead
20+
|
21+
LL | let e1 = Empty1 {};
22+
| ^^^^^^^^^
1723

1824
error[E0423]: expected function, tuple struct or tuple variant, found struct `Empty1`
1925
--> $DIR/empty-struct-braces-expr.rs:16:14
@@ -22,15 +28,16 @@ LL | struct Empty1 {}
2228
| ---------------- `Empty1` defined here
2329
...
2430
LL | let e1 = Empty1();
25-
| ^^^^^^
26-
| |
27-
| did you mean `Empty1 { /* fields */ }`?
28-
| help: a unit struct with a similar name exists: `XEmpty2`
29-
|
30-
::: $DIR/auxiliary/empty-struct.rs:2:1
31+
| ^^^^^^^^
3132
|
32-
LL | pub struct XEmpty2;
33-
| ------------------- similarly named unit struct `XEmpty2` defined here
33+
help: a unit struct with a similar name exists
34+
|
35+
LL | let e1 = XEmpty2();
36+
| ^^^^^^^
37+
help: use struct literal syntax instead
38+
|
39+
LL | let e1 = Empty1 {};
40+
| ^^^^^^^^^
3441

3542
error[E0423]: expected value, found struct variant `E::Empty3`
3643
--> $DIR/empty-struct-braces-expr.rs:18:14
@@ -39,7 +46,7 @@ LL | Empty3 {}
3946
| --------- `E::Empty3` defined here
4047
...
4148
LL | let e3 = E::Empty3;
42-
| ^^^^^^^^^ did you mean `E::Empty3 { /* fields */ }`?
49+
| ^^^^^^^^^ help: use struct literal syntax instead: `E::Empty3 {}`
4350

4451
error[E0423]: expected function, tuple struct or tuple variant, found struct variant `E::Empty3`
4552
--> $DIR/empty-struct-braces-expr.rs:19:14
@@ -48,35 +55,42 @@ LL | Empty3 {}
4855
| --------- `E::Empty3` defined here
4956
...
5057
LL | let e3 = E::Empty3();
51-
| ^^^^^^^^^ did you mean `E::Empty3 { /* fields */ }`?
58+
| ^^^^^^^^^^^ help: use struct literal syntax instead: `E::Empty3 {}`
5259

5360
error[E0423]: expected value, found struct `XEmpty1`
5461
--> $DIR/empty-struct-braces-expr.rs:22:15
5562
|
5663
LL | let xe1 = XEmpty1;
5764
| ^^^^^^^
58-
| |
59-
| did you mean `XEmpty1 { /* fields */ }`?
60-
| help: a unit struct with a similar name exists: `XEmpty2`
6165
|
6266
::: $DIR/auxiliary/empty-struct.rs:2:1
6367
|
6468
LL | pub struct XEmpty2;
6569
| ------------------- similarly named unit struct `XEmpty2` defined here
70+
|
71+
help: a unit struct with a similar name exists
72+
|
73+
LL | let xe1 = XEmpty2;
74+
| ^^^^^^^
75+
help: use struct literal syntax instead
76+
|
77+
LL | let xe1 = XEmpty1 {};
78+
| ^^^^^^^^^^
6679

6780
error[E0423]: expected function, tuple struct or tuple variant, found struct `XEmpty1`
6881
--> $DIR/empty-struct-braces-expr.rs:23:15
6982
|
7083
LL | let xe1 = XEmpty1();
84+
| ^^^^^^^^^
85+
|
86+
help: a unit struct with a similar name exists
87+
|
88+
LL | let xe1 = XEmpty2();
7189
| ^^^^^^^
72-
| |
73-
| did you mean `XEmpty1 { /* fields */ }`?
74-
| help: a unit struct with a similar name exists: `XEmpty2`
75-
|
76-
::: $DIR/auxiliary/empty-struct.rs:2:1
90+
help: use struct literal syntax instead
7791
|
78-
LL | pub struct XEmpty2;
79-
| ------------------- similarly named unit struct `XEmpty2` defined here
92+
LL | let xe1 = XEmpty1 {};
93+
| ^^^^^^^^^^
8094

8195
error[E0599]: no variant or associated item named `Empty3` found for enum `empty_struct::XE` in the current scope
8296
--> $DIR/empty-struct-braces-expr.rs:25:19

Diff for: src/test/ui/empty/empty-struct-braces-pat-1.stderr

+11-5
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,27 @@ LL | Empty3 {}
55
| --------- `E::Empty3` defined here
66
...
77
LL | E::Empty3 => ()
8-
| ^^^^^^^^^ did you mean `E::Empty3 { /* fields */ }`?
8+
| ^^^^^^^^^ help: use struct pattern syntax instead: `E::Empty3 {}`
99

1010
error[E0532]: expected unit struct, unit variant or constant, found struct variant `XE::XEmpty3`
1111
--> $DIR/empty-struct-braces-pat-1.rs:31:9
1212
|
1313
LL | XE::XEmpty3 => ()
14-
| ^^^^-------
15-
| | |
16-
| | help: a unit variant with a similar name exists: `XEmpty4`
17-
| did you mean `XE::XEmpty3 { /* fields */ }`?
14+
| ^^^^^^^^^^^
1815
|
1916
::: $DIR/auxiliary/empty-struct.rs:7:5
2017
|
2118
LL | XEmpty4,
2219
| ------- similarly named unit variant `XEmpty4` defined here
20+
|
21+
help: a unit variant with a similar name exists
22+
|
23+
LL | XE::XEmpty4 => ()
24+
| ^^^^^^^
25+
help: use struct pattern syntax instead
26+
|
27+
LL | XE::XEmpty3 { /* fields */ } => ()
28+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2329

2430
error: aborting due to 2 previous errors
2531

0 commit comments

Comments
 (0)