Skip to content

Commit 0fa3b4f

Browse files
committed
Make E0023 spans even more precise
1 parent d0b482a commit 0fa3b4f

File tree

11 files changed

+132
-150
lines changed

11 files changed

+132
-150
lines changed

compiler/rustc_ty_utils/src/ty.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,18 @@ fn associated_items(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AssocItems<'_> {
223223
}
224224

225225
fn def_ident_span(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Span> {
226-
tcx.hir().get_if_local(def_id).and_then(|node| node.ident()).map(|ident| ident.span)
226+
tcx.hir()
227+
.get_if_local(def_id)
228+
.and_then(|node| match node {
229+
// A `Ctor` doesn't have an identifier itself, but its parent
230+
// struct/variant does. Compare with `hir::Map::opt_span`.
231+
hir::Node::Ctor(ctor) => ctor
232+
.ctor_hir_id()
233+
.and_then(|ctor_id| tcx.hir().find(tcx.hir().get_parent_node(ctor_id)))
234+
.and_then(|parent| parent.ident()),
235+
_ => node.ident(),
236+
})
237+
.map(|ident| ident.span)
227238
}
228239

229240
/// If the given `DefId` describes an item belonging to a trait,

compiler/rustc_typeck/src/check/pat.rs

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use rustc_span::hygiene::DesugaringKind;
1515
use rustc_span::lev_distance::find_best_match_for_name;
1616
use rustc_span::source_map::{Span, Spanned};
1717
use rustc_span::symbol::Ident;
18-
use rustc_span::{BytePos, DUMMY_SP};
18+
use rustc_span::{BytePos, MultiSpan, DUMMY_SP};
1919
use rustc_trait_selection::autoderef::Autoderef;
2020
use rustc_trait_selection::traits::{ObligationCause, Pattern};
2121
use ty::VariantDef;
@@ -990,11 +990,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
990990
) {
991991
let subpats_ending = pluralize!(subpats.len());
992992
let fields_ending = pluralize!(fields.len());
993-
let fields_span = pat_span.trim_start(qpath.span()).unwrap_or(pat_span);
993+
994+
let subpat_spans = if subpats.is_empty() {
995+
vec![pat_span.trim_start(qpath.span()).unwrap_or(pat_span)]
996+
} else {
997+
subpats.iter().map(|p| p.span).collect()
998+
};
999+
let last_subpat_span = *subpat_spans.last().unwrap();
9941000
let res_span = self.tcx.def_span(res.def_id());
1001+
let def_ident_span = self.tcx.def_ident_span(res.def_id()).unwrap_or(res_span);
1002+
let field_def_spans = if fields.is_empty() {
1003+
vec![res_span.trim_start(def_ident_span).unwrap_or(res_span)]
1004+
} else {
1005+
fields.iter().map(|f| f.ident.span).collect()
1006+
};
1007+
let last_field_def_span = *field_def_spans.last().unwrap();
1008+
9951009
let mut err = struct_span_err!(
9961010
self.tcx.sess,
997-
fields_span,
1011+
MultiSpan::from_spans(subpat_spans.clone()),
9981012
E0023,
9991013
"this pattern has {} field{}, but the corresponding {} has {} field{}",
10001014
subpats.len(),
@@ -1004,11 +1018,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
10041018
fields_ending,
10051019
);
10061020
err.span_label(
1007-
fields_span,
1008-
format!("expected {} field{}, found {}", fields.len(), fields_ending, subpats.len(),),
1009-
)
1010-
.span_label(qpath.span(), format!("this {}", res.descr()))
1011-
.span_label(res_span, format!("{} defined here", res.descr()));
1021+
last_subpat_span,
1022+
&format!("expected {} field{}, found {}", fields.len(), fields_ending, subpats.len()),
1023+
);
1024+
err.span_label(qpath.span(), "");
1025+
if self.tcx.sess.source_map().is_multiline(def_ident_span.between(field_def_spans[0])) {
1026+
err.span_label(def_ident_span, format!("{} defined here", res.descr()));
1027+
}
1028+
for span in &field_def_spans[..field_def_spans.len() - 1] {
1029+
err.span_label(*span, "");
1030+
}
1031+
err.span_label(
1032+
last_field_def_span,
1033+
&format!("{} has {} field{}", res.descr(), fields.len(), fields_ending),
1034+
);
10121035

10131036
// Identify the case `Some(x, y)` where the expected type is e.g. `Option<(T, U)>`.
10141037
// More generally, the expected type wants a tuple variant with one field of an

src/test/ui/destructuring-assignment/tuple_struct_destructure_fail.stderr

Lines changed: 12 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -15,26 +15,22 @@ LL | Enum::SingleVariant(a, .., b, ..) = Enum::SingleVariant(0, 1);
1515
| previously used here
1616

1717
error[E0023]: this pattern has 3 fields, but the corresponding tuple struct has 2 fields
18-
--> $DIR/tuple_struct_destructure_fail.rs:30:16
18+
--> $DIR/tuple_struct_destructure_fail.rs:30:17
1919
|
2020
LL | struct TupleStruct<S, T>(S, T);
21-
| ------------------------------- tuple struct defined here
21+
| - - tuple struct has 2 fields
2222
...
2323
LL | TupleStruct(a, a, b) = TupleStruct(1, 2);
24-
| -----------^^^^^^^^^ expected 2 fields, found 3
25-
| |
26-
| this tuple struct
24+
| ----------- ^ ^ ^ expected 2 fields, found 3
2725

2826
error[E0023]: this pattern has 1 field, but the corresponding tuple struct has 2 fields
29-
--> $DIR/tuple_struct_destructure_fail.rs:32:16
27+
--> $DIR/tuple_struct_destructure_fail.rs:32:17
3028
|
3129
LL | struct TupleStruct<S, T>(S, T);
32-
| ------------------------------- tuple struct defined here
30+
| - - tuple struct has 2 fields
3331
...
3432
LL | TupleStruct(_) = TupleStruct(1, 2);
35-
| -----------^^^ expected 2 fields, found 1
36-
| |
37-
| this tuple struct
33+
| ----------- ^ expected 2 fields, found 1
3834
|
3935
help: use `_` to explicitly ignore each field
4036
|
@@ -46,26 +42,22 @@ LL | TupleStruct(..) = TupleStruct(1, 2);
4642
| ~~
4743

4844
error[E0023]: this pattern has 3 fields, but the corresponding tuple variant has 2 fields
49-
--> $DIR/tuple_struct_destructure_fail.rs:34:24
45+
--> $DIR/tuple_struct_destructure_fail.rs:34:25
5046
|
5147
LL | SingleVariant(S, T)
52-
| ------------------- tuple variant defined here
48+
| - - tuple variant has 2 fields
5349
...
5450
LL | Enum::SingleVariant(a, a, b) = Enum::SingleVariant(1, 2);
55-
| -------------------^^^^^^^^^ expected 2 fields, found 3
56-
| |
57-
| this tuple variant
51+
| ------------------- ^ ^ ^ expected 2 fields, found 3
5852

5953
error[E0023]: this pattern has 1 field, but the corresponding tuple variant has 2 fields
60-
--> $DIR/tuple_struct_destructure_fail.rs:36:24
54+
--> $DIR/tuple_struct_destructure_fail.rs:36:25
6155
|
6256
LL | SingleVariant(S, T)
63-
| ------------------- tuple variant defined here
57+
| - - tuple variant has 2 fields
6458
...
6559
LL | Enum::SingleVariant(_) = Enum::SingleVariant(1, 2);
66-
| -------------------^^^ expected 2 fields, found 1
67-
| |
68-
| this tuple variant
60+
| ------------------- ^ expected 2 fields, found 1
6961
|
7062
help: use `_` to explicitly ignore each field
7163
|

src/test/ui/error-codes/E0023.stderr

Lines changed: 13 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,43 @@
11
error[E0023]: this pattern has 1 field, but the corresponding tuple variant has 2 fields
2-
--> $DIR/E0023.rs:11:21
2+
--> $DIR/E0023.rs:11:22
33
|
44
LL | Apple(String, String),
5-
| --------------------- tuple variant defined here
5+
| ------ ------ tuple variant has 2 fields
66
...
77
LL | Fruit::Apple(a) => {},
8-
| ------------^^^ expected 2 fields, found 1
9-
| |
10-
| this tuple variant
8+
| ------------ ^ expected 2 fields, found 1
119
|
1210
help: use `_` to explicitly ignore each field
1311
|
1412
LL | Fruit::Apple(a, _) => {},
1513
| +++
1614

1715
error[E0023]: this pattern has 3 fields, but the corresponding tuple variant has 2 fields
18-
--> $DIR/E0023.rs:12:21
16+
--> $DIR/E0023.rs:12:22
1917
|
2018
LL | Apple(String, String),
21-
| --------------------- tuple variant defined here
19+
| ------ ------ tuple variant has 2 fields
2220
...
2321
LL | Fruit::Apple(a, b, c) => {},
24-
| ------------^^^^^^^^^ expected 2 fields, found 3
25-
| |
26-
| this tuple variant
22+
| ------------ ^ ^ ^ expected 2 fields, found 3
2723

2824
error[E0023]: this pattern has 2 fields, but the corresponding tuple variant has 1 field
29-
--> $DIR/E0023.rs:13:20
25+
--> $DIR/E0023.rs:13:21
3026
|
3127
LL | Pear(u32),
32-
| --------- tuple variant defined here
28+
| --- tuple variant has 1 field
3329
...
3430
LL | Fruit::Pear(1, 2) => {},
35-
| -----------^^^^^^ expected 1 field, found 2
36-
| |
37-
| this tuple variant
31+
| ----------- ^ ^ expected 1 field, found 2
3832

3933
error[E0023]: this pattern has 2 fields, but the corresponding tuple variant has 1 field
40-
--> $DIR/E0023.rs:14:22
34+
--> $DIR/E0023.rs:14:23
4135
|
4236
LL | Orange((String, String)),
43-
| ------------------------ tuple variant defined here
37+
| ---------------- tuple variant has 1 field
4438
...
4539
LL | Fruit::Orange(a, b) => {},
46-
| -------------^^^^^^ expected 1 field, found 2
47-
| |
48-
| this tuple variant
40+
| ------------- ^ ^ expected 1 field, found 2
4941
|
5042
help: missing parentheses
5143
|
@@ -56,12 +48,10 @@ error[E0023]: this pattern has 0 fields, but the corresponding tuple variant has
5648
--> $DIR/E0023.rs:15:22
5749
|
5850
LL | Banana(()),
59-
| ---------- tuple variant defined here
51+
| -- tuple variant has 1 field
6052
...
6153
LL | Fruit::Banana() => {},
6254
| -------------^^ expected 1 field, found 0
63-
| |
64-
| this tuple variant
6555
|
6656
help: missing parentheses
6757
|

src/test/ui/issues/issue-72574-2.stderr

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,13 @@ LL | Binder(_a, _x @ ..) => {}
1919
= note: only allowed in tuple, tuple struct, and slice patterns
2020

2121
error[E0023]: this pattern has 2 fields, but the corresponding tuple struct has 3 fields
22-
--> $DIR/issue-72574-2.rs:6:15
22+
--> $DIR/issue-72574-2.rs:6:16
2323
|
2424
LL | struct Binder(i32, i32, i32);
25-
| ----------------------------- tuple struct defined here
25+
| --- --- --- tuple struct has 3 fields
2626
...
2727
LL | Binder(_a, _x @ ..) => {}
28-
| ------^^^^^^^^^^^^^ expected 3 fields, found 2
29-
| |
30-
| this tuple struct
28+
| ------ ^^ ^^^^^^^ expected 3 fields, found 2
3129
|
3230
help: use `_` to explicitly ignore each field
3331
|

src/test/ui/match/match-pattern-field-mismatch.stderr

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,11 @@
11
error[E0023]: this pattern has 2 fields, but the corresponding tuple variant has 3 fields
2-
--> $DIR/match-pattern-field-mismatch.rs:10:21
2+
--> $DIR/match-pattern-field-mismatch.rs:10:22
33
|
44
LL | Rgb(usize, usize, usize),
5-
| ------------------------ tuple variant defined here
5+
| ----- ----- ----- tuple variant has 3 fields
66
...
77
LL | Color::Rgb(_, _) => { }
8-
| ----------^^^^^^ expected 3 fields, found 2
9-
| |
10-
| this tuple variant
8+
| ---------- ^ ^ expected 3 fields, found 2
119
|
1210
help: use `_` to explicitly ignore each field
1311
|

src/test/ui/pattern/issue-67037-pat-tup-scrut-ty-diff-less-fields.stderr

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,10 @@ error[E0023]: this pattern has 0 fields, but the corresponding tuple struct has
1313
--> $DIR/issue-67037-pat-tup-scrut-ty-diff-less-fields.rs:19:10
1414
|
1515
LL | struct P<T>(T); // 1 type parameter wanted
16-
| --------------- tuple struct defined here
16+
| - tuple struct has 1 field
1717
...
1818
LL | let P() = U {};
1919
| -^^ expected 1 field, found 0
20-
| |
21-
| this tuple struct
2220
|
2321
help: use `_` to explicitly ignore each field
2422
|

src/test/ui/pattern/issue-74539.stderr

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,13 @@ LL | E::A(x @ ..) => {
1919
= note: only allowed in tuple, tuple struct, and slice patterns
2020

2121
error[E0023]: this pattern has 1 field, but the corresponding tuple variant has 2 fields
22-
--> $DIR/issue-74539.rs:8:13
22+
--> $DIR/issue-74539.rs:8:14
2323
|
2424
LL | A(u8, u8),
25-
| --------- tuple variant defined here
25+
| -- -- tuple variant has 2 fields
2626
...
2727
LL | E::A(x @ ..) => {
28-
| ----^^^^^^^^ expected 2 fields, found 1
29-
| |
30-
| this tuple variant
28+
| ---- ^^^^^^ expected 2 fields, found 1
3129
|
3230
help: use `_` to explicitly ignore each field
3331
|

0 commit comments

Comments
 (0)