Skip to content

Commit 501c798

Browse files
committed
Auto merge of #153894 - estebank:issue-129792, r=nnethercote
Point at unit structs on foreign crates in type errors when they are the pattern of a binding Consts and unit structs in patterns can be confusing if they are mistaken for new bindings. We already provide some context for unit structs and consts that come from the current crate, we now also point at those from foreign crates, and we properly skip cases where the pattern has type parameters which can't be confused with a new binding. So not suggest making a new binding when other suggestions are already emitted, as the likelihood of the other suggestions being what the user intended is higher. Make new binding suggestion verbose. Fix #129792. ``` error[E0308]: mismatched types --> fi.rs:8:9 | 1 | struct percentage; | ----------------- unit struct defined here ... 8 | let percentage = 4i32; | ^^^^^^^^^^ ---- this expression has type `i32` | | | expected `i32`, found `percentage` | `percentage` is interpreted as a unit struct, not a new binding help: introduce a new binding instead | 8 - let percentage = 4i32; 8 + let other_percentage = 4i32; | ```
2 parents b711f95 + 408066f commit 501c798

File tree

16 files changed

+134
-115
lines changed

16 files changed

+134
-115
lines changed

compiler/rustc_errors/src/lib.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,14 @@ impl Suggestions {
138138
Suggestions::Disabled => Vec::new(),
139139
}
140140
}
141+
142+
pub fn len(&self) -> usize {
143+
match self {
144+
Suggestions::Enabled(suggestions) => suggestions.len(),
145+
Suggestions::Sealed(suggestions) => suggestions.len(),
146+
Suggestions::Disabled => 0,
147+
}
148+
}
141149
}
142150

143151
impl Default for Suggestions {

compiler/rustc_hir_typeck/src/pat.rs

Lines changed: 66 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1636,69 +1636,77 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
16361636
span_bug!(pat_span, "unexpected resolution for path pattern: {resolved_pat:?}");
16371637
};
16381638

1639-
if let Some(span) = self.tcx.hir_res_span(pat_res) {
1639+
let span = match (self.tcx.hir_res_span(pat_res), res.opt_def_id()) {
1640+
(Some(span), _) => span,
1641+
(None, Some(def_id)) => self.tcx.def_span(def_id),
1642+
(None, None) => {
1643+
e.emit();
1644+
return;
1645+
}
1646+
};
1647+
if let [hir::PathSegment { ident, args: None, .. }] = segments
1648+
&& e.suggestions.len() == 0
1649+
{
16401650
e.span_label(span, format!("{} defined here", res.descr()));
1641-
if let [hir::PathSegment { ident, .. }] = segments {
1642-
e.span_label(
1643-
pat_span,
1644-
format!(
1645-
"`{}` is interpreted as {} {}, not a new binding",
1646-
ident,
1647-
res.article(),
1648-
res.descr(),
1649-
),
1650-
);
1651-
match self.tcx.parent_hir_node(hir_id) {
1652-
hir::Node::PatField(..) => {
1651+
e.span_label(
1652+
pat_span,
1653+
format!(
1654+
"`{}` is interpreted as {} {}, not a new binding",
1655+
ident,
1656+
res.article(),
1657+
res.descr(),
1658+
),
1659+
);
1660+
match self.tcx.parent_hir_node(hir_id) {
1661+
hir::Node::PatField(..) => {
1662+
e.span_suggestion_verbose(
1663+
ident.span.shrink_to_hi(),
1664+
"bind the struct field to a different name instead",
1665+
format!(": other_{}", ident.as_str().to_lowercase()),
1666+
Applicability::HasPlaceholders,
1667+
);
1668+
}
1669+
_ => {
1670+
let (type_def_id, item_def_id) = match resolved_pat.ty.kind() {
1671+
ty::Adt(def, _) => match res {
1672+
Res::Def(DefKind::Const { .. }, def_id) => {
1673+
(Some(def.did()), Some(def_id))
1674+
}
1675+
_ => (None, None),
1676+
},
1677+
_ => (None, None),
1678+
};
1679+
1680+
let is_range = matches!(
1681+
type_def_id.and_then(|id| self.tcx.as_lang_item(id)),
1682+
Some(
1683+
LangItem::Range
1684+
| LangItem::RangeFrom
1685+
| LangItem::RangeTo
1686+
| LangItem::RangeFull
1687+
| LangItem::RangeInclusiveStruct
1688+
| LangItem::RangeToInclusive,
1689+
)
1690+
);
1691+
if is_range {
1692+
if !self.maybe_suggest_range_literal(&mut e, item_def_id, *ident) {
1693+
let msg = "constants only support matching by type, \
1694+
if you meant to match against a range of values, \
1695+
consider using a range pattern like `min ..= max` in the match block";
1696+
e.note(msg);
1697+
}
1698+
} else {
1699+
let msg = "introduce a new binding instead";
1700+
let sugg = format!("other_{}", ident.as_str().to_lowercase());
16531701
e.span_suggestion_verbose(
1654-
ident.span.shrink_to_hi(),
1655-
"bind the struct field to a different name instead",
1656-
format!(": other_{}", ident.as_str().to_lowercase()),
1702+
ident.span,
1703+
msg,
1704+
sugg,
16571705
Applicability::HasPlaceholders,
16581706
);
16591707
}
1660-
_ => {
1661-
let (type_def_id, item_def_id) = match resolved_pat.ty.kind() {
1662-
ty::Adt(def, _) => match res {
1663-
Res::Def(DefKind::Const { .. }, def_id) => {
1664-
(Some(def.did()), Some(def_id))
1665-
}
1666-
_ => (None, None),
1667-
},
1668-
_ => (None, None),
1669-
};
1670-
1671-
let is_range = matches!(
1672-
type_def_id.and_then(|id| self.tcx.as_lang_item(id)),
1673-
Some(
1674-
LangItem::Range
1675-
| LangItem::RangeFrom
1676-
| LangItem::RangeTo
1677-
| LangItem::RangeFull
1678-
| LangItem::RangeInclusiveStruct
1679-
| LangItem::RangeToInclusive,
1680-
)
1681-
);
1682-
if is_range {
1683-
if !self.maybe_suggest_range_literal(&mut e, item_def_id, *ident) {
1684-
let msg = "constants only support matching by type, \
1685-
if you meant to match against a range of values, \
1686-
consider using a range pattern like `min ..= max` in the match block";
1687-
e.note(msg);
1688-
}
1689-
} else {
1690-
let msg = "introduce a new binding instead";
1691-
let sugg = format!("other_{}", ident.as_str().to_lowercase());
1692-
e.span_suggestion(
1693-
ident.span,
1694-
msg,
1695-
sugg,
1696-
Applicability::HasPlaceholders,
1697-
);
1698-
}
1699-
}
1700-
};
1701-
}
1708+
}
1709+
};
17021710
}
17031711
e.emit();
17041712
}

tests/ui/blind/blind-item-block-middle.stderr

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,11 @@ LL | let bar = 5;
99
| |
1010
| expected integer, found `bar`
1111
| `bar` is interpreted as a unit struct, not a new binding
12-
| help: introduce a new binding instead: `other_bar`
12+
|
13+
help: introduce a new binding instead
14+
|
15+
LL | let other_bar = 5;
16+
| ++++++
1317

1418
error: aborting due to 1 previous error
1519

tests/ui/consts/const_in_pattern/arrays-and-slices.stderr

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,14 @@ LL | BSTR_SIZED => {}
1111
| |
1212
| expected `&[u8]`, found `&[u8; 3]`
1313
| `BSTR_SIZED` is interpreted as a constant, not a new binding
14-
| help: introduce a new binding instead: `other_bstr_sized`
1514
|
1615
= note: expected reference `&[u8]`
1716
found reference `&'static [u8; 3]`
17+
help: introduce a new binding instead
18+
|
19+
LL - BSTR_SIZED => {}
20+
LL + other_bstr_sized => {}
21+
|
1822

1923
error[E0308]: mismatched types
2024
--> $DIR/arrays-and-slices.rs:23:9
@@ -29,10 +33,14 @@ LL | STRUCT_SIZED => {}
2933
| |
3034
| expected `&SomeStruct<[u8]>`, found `&SomeStruct<[u8; 3]>`
3135
| `STRUCT_SIZED` is interpreted as a constant, not a new binding
32-
| help: introduce a new binding instead: `other_struct_sized`
3336
|
3437
= note: expected reference `&SomeStruct<[u8]>`
3538
found reference `&'static SomeStruct<[u8; 3]>`
39+
help: introduce a new binding instead
40+
|
41+
LL - STRUCT_SIZED => {}
42+
LL + other_struct_sized => {}
43+
|
3644

3745
error[E0308]: mismatched types
3846
--> $DIR/arrays-and-slices.rs:30:9
@@ -47,10 +55,14 @@ LL | BSTR_SIZED => {}
4755
| |
4856
| expected `&[u8]`, found `&[u8; 3]`
4957
| `BSTR_SIZED` is interpreted as a constant, not a new binding
50-
| help: introduce a new binding instead: `other_bstr_sized`
5158
|
5259
= note: expected reference `&[u8]`
5360
found reference `&'static [u8; 3]`
61+
help: introduce a new binding instead
62+
|
63+
LL - BSTR_SIZED => {}
64+
LL + other_bstr_sized => {}
65+
|
5466

5567
error[E0308]: mismatched types
5668
--> $DIR/arrays-and-slices.rs:37:9
@@ -65,10 +77,14 @@ LL | STRUCT_SIZED => {}
6577
| |
6678
| expected `&SomeStruct<[u8]>`, found `&SomeStruct<[u8; 3]>`
6779
| `STRUCT_SIZED` is interpreted as a constant, not a new binding
68-
| help: introduce a new binding instead: `other_struct_sized`
6980
|
7081
= note: expected reference `&SomeStruct<[u8]>`
7182
found reference `&'static SomeStruct<[u8; 3]>`
83+
help: introduce a new binding instead
84+
|
85+
LL - STRUCT_SIZED => {}
86+
LL + other_struct_sized => {}
87+
|
7288

7389
error: cannot use unsized non-slice type `SomeStruct<[u8]>` in constant patterns
7490
--> $DIR/arrays-and-slices.rs:47:9

tests/ui/did_you_mean/compatible-variants-in-pat.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ fn b(s: Option<S>) {
2121
S => {
2222
//~^ ERROR mismatched types
2323
//~| HELP try wrapping
24-
//~| HELP introduce a new binding instead
2524
}
2625
_ => {}
2726
}
@@ -32,7 +31,6 @@ fn c(s: Result<S, S>) {
3231
S => {
3332
//~^ ERROR mismatched types
3433
//~| HELP try wrapping
35-
//~| HELP introduce a new binding instead
3634
}
3735
_ => {}
3836
}

tests/ui/did_you_mean/compatible-variants-in-pat.stderr

Lines changed: 3 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -14,42 +14,25 @@ LL | Foo::Bar(Bar { x }) => {
1414
error[E0308]: mismatched types
1515
--> $DIR/compatible-variants-in-pat.rs:21:9
1616
|
17-
LL | struct S;
18-
| -------- unit struct defined here
19-
...
2017
LL | match s {
2118
| - this expression has type `Option<S>`
2219
LL | S => {
23-
| ^
24-
| |
25-
| expected `Option<S>`, found `S`
26-
| `S` is interpreted as a unit struct, not a new binding
20+
| ^ expected `Option<S>`, found `S`
2721
|
2822
= note: expected enum `Option<S>`
2923
found struct `S`
3024
help: try wrapping the pattern in `Some`
3125
|
3226
LL | Some(S) => {
3327
| +++++ +
34-
help: introduce a new binding instead
35-
|
36-
LL - S => {
37-
LL + other_s => {
38-
|
3928

4029
error[E0308]: mismatched types
41-
--> $DIR/compatible-variants-in-pat.rs:32:9
30+
--> $DIR/compatible-variants-in-pat.rs:31:9
4231
|
43-
LL | struct S;
44-
| -------- unit struct defined here
45-
...
4632
LL | match s {
4733
| - this expression has type `Result<S, S>`
4834
LL | S => {
49-
| ^
50-
| |
51-
| expected `Result<S, S>`, found `S`
52-
| `S` is interpreted as a unit struct, not a new binding
35+
| ^ expected `Result<S, S>`, found `S`
5336
|
5437
= note: expected enum `Result<S, S>`
5538
found struct `S`
@@ -59,11 +42,6 @@ LL | Ok(S) => {
5942
| +++ +
6043
LL | Err(S) => {
6144
| ++++ +
62-
help: introduce a new binding instead
63-
|
64-
LL - S => {
65-
LL + other_s => {
66-
|
6745

6846
error: aborting due to 3 previous errors
6947

tests/ui/issues/issue-33504.stderr

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,12 @@ LL | let Test = 1;
99
| |
1010
| expected integer, found `Test`
1111
| `Test` is interpreted as a unit struct, not a new binding
12-
| help: introduce a new binding instead: `other_test`
12+
|
13+
help: introduce a new binding instead
14+
|
15+
LL - let Test = 1;
16+
LL + let other_test = 1;
17+
|
1318

1419
error: aborting due to 1 previous error
1520

tests/ui/issues/issue-5100.stderr

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
error[E0308]: mismatched types
22
--> $DIR/issue-5100.rs:9:9
33
|
4-
LL | enum A { B, C }
5-
| - unit variant defined here
6-
...
74
LL | match (true, false) {
85
| ------------- this expression has type `(bool, bool)`
96
LL | A::B => (),

tests/ui/match/match-const-tuple-type-mismatch.stderr

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,14 @@ LL | A => (),
1111
| |
1212
| expected integer, found `(isize, isize)`
1313
| `A` is interpreted as a constant, not a new binding
14-
| help: introduce a new binding instead: `other_a`
1514
|
1615
= note: expected type `{integer}`
1716
found tuple `(isize, isize)`
17+
help: introduce a new binding instead
18+
|
19+
LL - A => (),
20+
LL + other_a => (),
21+
|
1822

1923
error: aborting due to 1 previous error
2024

tests/ui/match/match-tag-nullary.stderr

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
error[E0308]: mismatched types
22
--> $DIR/match-tag-nullary.rs:4:40
33
|
4-
LL | enum B { B }
5-
| - unit variant defined here
6-
LL |
74
LL | fn main() { let x: A = A::A; match x { B::B => { } } }
85
| - ^^^^ expected `A`, found `B`
96
| |

0 commit comments

Comments
 (0)