diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 9b3dba15f55e2..8c57544c54b8f 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -138,6 +138,14 @@ impl Suggestions { Suggestions::Disabled => Vec::new(), } } + + pub fn len(&self) -> usize { + match self { + Suggestions::Enabled(suggestions) => suggestions.len(), + Suggestions::Sealed(suggestions) => suggestions.len(), + Suggestions::Disabled => 0, + } + } } impl Default for Suggestions { diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 7b5f5f3f520e4..26f7d1ccffc93 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -1636,69 +1636,77 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span_bug!(pat_span, "unexpected resolution for path pattern: {resolved_pat:?}"); }; - if let Some(span) = self.tcx.hir_res_span(pat_res) { + let span = match (self.tcx.hir_res_span(pat_res), res.opt_def_id()) { + (Some(span), _) => span, + (None, Some(def_id)) => self.tcx.def_span(def_id), + (None, None) => { + e.emit(); + return; + } + }; + if let [hir::PathSegment { ident, args: None, .. }] = segments + && e.suggestions.len() == 0 + { e.span_label(span, format!("{} defined here", res.descr())); - if let [hir::PathSegment { ident, .. }] = segments { - e.span_label( - pat_span, - format!( - "`{}` is interpreted as {} {}, not a new binding", - ident, - res.article(), - res.descr(), - ), - ); - match self.tcx.parent_hir_node(hir_id) { - hir::Node::PatField(..) => { + e.span_label( + pat_span, + format!( + "`{}` is interpreted as {} {}, not a new binding", + ident, + res.article(), + res.descr(), + ), + ); + match self.tcx.parent_hir_node(hir_id) { + hir::Node::PatField(..) => { + e.span_suggestion_verbose( + ident.span.shrink_to_hi(), + "bind the struct field to a different name instead", + format!(": other_{}", ident.as_str().to_lowercase()), + Applicability::HasPlaceholders, + ); + } + _ => { + let (type_def_id, item_def_id) = match resolved_pat.ty.kind() { + ty::Adt(def, _) => match res { + Res::Def(DefKind::Const { .. }, def_id) => { + (Some(def.did()), Some(def_id)) + } + _ => (None, None), + }, + _ => (None, None), + }; + + let is_range = matches!( + type_def_id.and_then(|id| self.tcx.as_lang_item(id)), + Some( + LangItem::Range + | LangItem::RangeFrom + | LangItem::RangeTo + | LangItem::RangeFull + | LangItem::RangeInclusiveStruct + | LangItem::RangeToInclusive, + ) + ); + if is_range { + if !self.maybe_suggest_range_literal(&mut e, item_def_id, *ident) { + let msg = "constants only support matching by type, \ + if you meant to match against a range of values, \ + consider using a range pattern like `min ..= max` in the match block"; + e.note(msg); + } + } else { + let msg = "introduce a new binding instead"; + let sugg = format!("other_{}", ident.as_str().to_lowercase()); e.span_suggestion_verbose( - ident.span.shrink_to_hi(), - "bind the struct field to a different name instead", - format!(": other_{}", ident.as_str().to_lowercase()), + ident.span, + msg, + sugg, Applicability::HasPlaceholders, ); } - _ => { - let (type_def_id, item_def_id) = match resolved_pat.ty.kind() { - ty::Adt(def, _) => match res { - Res::Def(DefKind::Const { .. }, def_id) => { - (Some(def.did()), Some(def_id)) - } - _ => (None, None), - }, - _ => (None, None), - }; - - let is_range = matches!( - type_def_id.and_then(|id| self.tcx.as_lang_item(id)), - Some( - LangItem::Range - | LangItem::RangeFrom - | LangItem::RangeTo - | LangItem::RangeFull - | LangItem::RangeInclusiveStruct - | LangItem::RangeToInclusive, - ) - ); - if is_range { - if !self.maybe_suggest_range_literal(&mut e, item_def_id, *ident) { - let msg = "constants only support matching by type, \ - if you meant to match against a range of values, \ - consider using a range pattern like `min ..= max` in the match block"; - e.note(msg); - } - } else { - let msg = "introduce a new binding instead"; - let sugg = format!("other_{}", ident.as_str().to_lowercase()); - e.span_suggestion( - ident.span, - msg, - sugg, - Applicability::HasPlaceholders, - ); - } - } - }; - } + } + }; } e.emit(); } diff --git a/tests/ui/blind/blind-item-block-middle.stderr b/tests/ui/blind/blind-item-block-middle.stderr index b2ae169013a62..5c05f31ab8953 100644 --- a/tests/ui/blind/blind-item-block-middle.stderr +++ b/tests/ui/blind/blind-item-block-middle.stderr @@ -9,7 +9,11 @@ LL | let bar = 5; | | | expected integer, found `bar` | `bar` is interpreted as a unit struct, not a new binding - | help: introduce a new binding instead: `other_bar` + | +help: introduce a new binding instead + | +LL | let other_bar = 5; + | ++++++ error: aborting due to 1 previous error diff --git a/tests/ui/consts/const_in_pattern/arrays-and-slices.stderr b/tests/ui/consts/const_in_pattern/arrays-and-slices.stderr index 412caf60f7d85..8aa86c8b05f53 100644 --- a/tests/ui/consts/const_in_pattern/arrays-and-slices.stderr +++ b/tests/ui/consts/const_in_pattern/arrays-and-slices.stderr @@ -11,10 +11,14 @@ LL | BSTR_SIZED => {} | | | expected `&[u8]`, found `&[u8; 3]` | `BSTR_SIZED` is interpreted as a constant, not a new binding - | help: introduce a new binding instead: `other_bstr_sized` | = note: expected reference `&[u8]` found reference `&'static [u8; 3]` +help: introduce a new binding instead + | +LL - BSTR_SIZED => {} +LL + other_bstr_sized => {} + | error[E0308]: mismatched types --> $DIR/arrays-and-slices.rs:23:9 @@ -29,10 +33,14 @@ LL | STRUCT_SIZED => {} | | | expected `&SomeStruct<[u8]>`, found `&SomeStruct<[u8; 3]>` | `STRUCT_SIZED` is interpreted as a constant, not a new binding - | help: introduce a new binding instead: `other_struct_sized` | = note: expected reference `&SomeStruct<[u8]>` found reference `&'static SomeStruct<[u8; 3]>` +help: introduce a new binding instead + | +LL - STRUCT_SIZED => {} +LL + other_struct_sized => {} + | error[E0308]: mismatched types --> $DIR/arrays-and-slices.rs:30:9 @@ -47,10 +55,14 @@ LL | BSTR_SIZED => {} | | | expected `&[u8]`, found `&[u8; 3]` | `BSTR_SIZED` is interpreted as a constant, not a new binding - | help: introduce a new binding instead: `other_bstr_sized` | = note: expected reference `&[u8]` found reference `&'static [u8; 3]` +help: introduce a new binding instead + | +LL - BSTR_SIZED => {} +LL + other_bstr_sized => {} + | error[E0308]: mismatched types --> $DIR/arrays-and-slices.rs:37:9 @@ -65,10 +77,14 @@ LL | STRUCT_SIZED => {} | | | expected `&SomeStruct<[u8]>`, found `&SomeStruct<[u8; 3]>` | `STRUCT_SIZED` is interpreted as a constant, not a new binding - | help: introduce a new binding instead: `other_struct_sized` | = note: expected reference `&SomeStruct<[u8]>` found reference `&'static SomeStruct<[u8; 3]>` +help: introduce a new binding instead + | +LL - STRUCT_SIZED => {} +LL + other_struct_sized => {} + | error: cannot use unsized non-slice type `SomeStruct<[u8]>` in constant patterns --> $DIR/arrays-and-slices.rs:47:9 diff --git a/tests/ui/did_you_mean/compatible-variants-in-pat.rs b/tests/ui/did_you_mean/compatible-variants-in-pat.rs index 09e12dab2d3fc..5633c28be208f 100644 --- a/tests/ui/did_you_mean/compatible-variants-in-pat.rs +++ b/tests/ui/did_you_mean/compatible-variants-in-pat.rs @@ -21,7 +21,6 @@ fn b(s: Option) { S => { //~^ ERROR mismatched types //~| HELP try wrapping - //~| HELP introduce a new binding instead } _ => {} } @@ -32,7 +31,6 @@ fn c(s: Result) { S => { //~^ ERROR mismatched types //~| HELP try wrapping - //~| HELP introduce a new binding instead } _ => {} } diff --git a/tests/ui/did_you_mean/compatible-variants-in-pat.stderr b/tests/ui/did_you_mean/compatible-variants-in-pat.stderr index 09cf094e6bd72..f18965f5d080c 100644 --- a/tests/ui/did_you_mean/compatible-variants-in-pat.stderr +++ b/tests/ui/did_you_mean/compatible-variants-in-pat.stderr @@ -14,16 +14,10 @@ LL | Foo::Bar(Bar { x }) => { error[E0308]: mismatched types --> $DIR/compatible-variants-in-pat.rs:21:9 | -LL | struct S; - | -------- unit struct defined here -... LL | match s { | - this expression has type `Option` LL | S => { - | ^ - | | - | expected `Option`, found `S` - | `S` is interpreted as a unit struct, not a new binding + | ^ expected `Option`, found `S` | = note: expected enum `Option` found struct `S` @@ -31,25 +25,14 @@ help: try wrapping the pattern in `Some` | LL | Some(S) => { | +++++ + -help: introduce a new binding instead - | -LL - S => { -LL + other_s => { - | error[E0308]: mismatched types - --> $DIR/compatible-variants-in-pat.rs:32:9 + --> $DIR/compatible-variants-in-pat.rs:31:9 | -LL | struct S; - | -------- unit struct defined here -... LL | match s { | - this expression has type `Result` LL | S => { - | ^ - | | - | expected `Result`, found `S` - | `S` is interpreted as a unit struct, not a new binding + | ^ expected `Result`, found `S` | = note: expected enum `Result` found struct `S` @@ -59,11 +42,6 @@ LL | Ok(S) => { | +++ + LL | Err(S) => { | ++++ + -help: introduce a new binding instead - | -LL - S => { -LL + other_s => { - | error: aborting due to 3 previous errors diff --git a/tests/ui/issues/issue-33504.stderr b/tests/ui/issues/issue-33504.stderr index f3e1ca08b6fc3..e5a2eea751d0e 100644 --- a/tests/ui/issues/issue-33504.stderr +++ b/tests/ui/issues/issue-33504.stderr @@ -9,7 +9,12 @@ LL | let Test = 1; | | | expected integer, found `Test` | `Test` is interpreted as a unit struct, not a new binding - | help: introduce a new binding instead: `other_test` + | +help: introduce a new binding instead + | +LL - let Test = 1; +LL + let other_test = 1; + | error: aborting due to 1 previous error diff --git a/tests/ui/issues/issue-5100.stderr b/tests/ui/issues/issue-5100.stderr index 24d41a1a8afae..c545f70415c13 100644 --- a/tests/ui/issues/issue-5100.stderr +++ b/tests/ui/issues/issue-5100.stderr @@ -1,9 +1,6 @@ error[E0308]: mismatched types --> $DIR/issue-5100.rs:9:9 | -LL | enum A { B, C } - | - unit variant defined here -... LL | match (true, false) { | ------------- this expression has type `(bool, bool)` LL | A::B => (), diff --git a/tests/ui/match/match-const-tuple-type-mismatch.stderr b/tests/ui/match/match-const-tuple-type-mismatch.stderr index e7dd97c4e9a60..06f65b257069d 100644 --- a/tests/ui/match/match-const-tuple-type-mismatch.stderr +++ b/tests/ui/match/match-const-tuple-type-mismatch.stderr @@ -11,10 +11,14 @@ LL | A => (), | | | expected integer, found `(isize, isize)` | `A` is interpreted as a constant, not a new binding - | help: introduce a new binding instead: `other_a` | = note: expected type `{integer}` found tuple `(isize, isize)` +help: introduce a new binding instead + | +LL - A => (), +LL + other_a => (), + | error: aborting due to 1 previous error diff --git a/tests/ui/match/match-tag-nullary.stderr b/tests/ui/match/match-tag-nullary.stderr index c9446d164337c..2822d715ab319 100644 --- a/tests/ui/match/match-tag-nullary.stderr +++ b/tests/ui/match/match-tag-nullary.stderr @@ -1,9 +1,6 @@ error[E0308]: mismatched types --> $DIR/match-tag-nullary.rs:4:40 | -LL | enum B { B } - | - unit variant defined here -LL | LL | fn main() { let x: A = A::A; match x { B::B => { } } } | - ^^^^ expected `A`, found `B` | | diff --git a/tests/ui/match/mismatched-types-in-match-7867.stderr b/tests/ui/match/mismatched-types-in-match-7867.stderr index e41a61e42f4b0..6f25175209dcc 100644 --- a/tests/ui/match/mismatched-types-in-match-7867.stderr +++ b/tests/ui/match/mismatched-types-in-match-7867.stderr @@ -1,9 +1,6 @@ error[E0308]: mismatched types --> $DIR/mismatched-types-in-match-7867.rs:10:9 | -LL | enum A { B, C } - | - unit variant defined here -... LL | match (true, false) { | ------------- this expression has type `(bool, bool)` LL | A::B => (), diff --git a/tests/ui/privacy/private-unit-struct-assignment.stderr b/tests/ui/privacy/private-unit-struct-assignment.stderr index 8c36a08846d81..110ee19d5ff4d 100644 --- a/tests/ui/privacy/private-unit-struct-assignment.stderr +++ b/tests/ui/privacy/private-unit-struct-assignment.stderr @@ -13,9 +13,6 @@ LL | struct C; error[E0308]: mismatched types --> $DIR/private-unit-struct-assignment.rs:8:5 | -LL | struct C; - | -------- unit struct defined here -... LL | A::C = 1; | ^^^^ - this expression has type `{integer}` | | diff --git a/tests/ui/resolve/name-clash-nullary.stderr b/tests/ui/resolve/name-clash-nullary.stderr index 08e7fe9a678a1..1a3f434b62770 100644 --- a/tests/ui/resolve/name-clash-nullary.stderr +++ b/tests/ui/resolve/name-clash-nullary.stderr @@ -5,9 +5,19 @@ LL | let None: isize = 42; | ^^^^ ----- expected due to this | | | expected `isize`, found `Option<_>` + | `None` is interpreted as a unit variant, not a new binding + | + --> $SRC_DIR/core/src/option.rs:LL:COL + | + = note: unit variant defined here | = note: expected type `isize` found enum `Option<_>` +help: introduce a new binding instead + | +LL - let None: isize = 42; +LL + let other_none: isize = 42; + | error: aborting due to 1 previous error diff --git a/tests/ui/rfcs/rfc-2005-default-binding-mode/const.stderr b/tests/ui/rfcs/rfc-2005-default-binding-mode/const.stderr index 1c8e8d5b0a7db..12b89ba10bfd1 100644 --- a/tests/ui/rfcs/rfc-2005-default-binding-mode/const.stderr +++ b/tests/ui/rfcs/rfc-2005-default-binding-mode/const.stderr @@ -11,7 +11,12 @@ LL | FOO => {}, | | | expected `&Foo`, found `Foo` | `FOO` is interpreted as a constant, not a new binding - | help: introduce a new binding instead: `other_foo` + | +help: introduce a new binding instead + | +LL - FOO => {}, +LL + other_foo => {}, + | error: aborting due to 1 previous error diff --git a/tests/ui/suggestions/field-access.stderr b/tests/ui/suggestions/field-access.stderr index 362dae172c78f..36e126176ee96 100644 --- a/tests/ui/suggestions/field-access.stderr +++ b/tests/ui/suggestions/field-access.stderr @@ -1,9 +1,6 @@ error[E0308]: mismatched types --> $DIR/field-access.rs:20:12 | -LL | Fst, - | --- unit variant defined here -... LL | if let B::Fst = a {}; | ^^^^^^ - this expression has type `A` | | @@ -17,9 +14,6 @@ LL | if let B::Fst = a.b {}; error[E0308]: mismatched types --> $DIR/field-access.rs:25:9 | -LL | Fst, - | --- unit variant defined here -... LL | match a { | - this expression has type `A` ... @@ -34,9 +28,6 @@ LL | match a.b { error[E0308]: mismatched types --> $DIR/field-access.rs:26:9 | -LL | Snd, - | --- unit variant defined here -... LL | match a { | - this expression has type `A` ... diff --git a/tests/ui/type/pattern_types/matching_fail.stderr b/tests/ui/type/pattern_types/matching_fail.stderr index 446180d80f24b..495d739078782 100644 --- a/tests/ui/type/pattern_types/matching_fail.stderr +++ b/tests/ui/type/pattern_types/matching_fail.stderr @@ -33,10 +33,14 @@ LL | THREE => {} | | | expected integer, found `(u32) is 1..` | `THREE` is interpreted as a constant, not a new binding - | help: introduce a new binding instead: `other_three` | = note: expected type `{integer}` found pattern type `(u32) is 1..` +help: introduce a new binding instead + | +LL - THREE => {} +LL + other_three => {} + | error: aborting due to 3 previous errors