From fea7b59d12ad34f18e03c2c6646cd8971dc2f216 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 26 Feb 2023 20:48:50 +0000 Subject: [PATCH 01/13] Make check_match take a LocalDefId. --- compiler/rustc_interface/src/passes.rs | 2 +- compiler/rustc_middle/src/query/mod.rs | 6 +++--- .../rustc_mir_build/src/thir/pattern/check_match.rs | 10 +++------- 3 files changed, 7 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 413b40ab808e4..8d4892470ac7b 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -765,7 +765,7 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> { parallel!( { sess.time("match_checking", || { - tcx.hir().par_body_owners(|def_id| tcx.ensure().check_match(def_id.to_def_id())) + tcx.hir().par_body_owners(|def_id| tcx.ensure().check_match(def_id)) }); }, { diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 9203dd59a7e63..d31b11f08927b 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1114,9 +1114,9 @@ rustc_queries! { desc { "converting literal to mir constant" } } - query check_match(key: DefId) { - desc { |tcx| "match-checking `{}`", tcx.def_path_str(key) } - cache_on_disk_if { key.is_local() } + query check_match(key: LocalDefId) { + desc { |tcx| "match-checking `{}`", tcx.def_path_str(key.to_def_id()) } + cache_on_disk_if { true } } /// Performs part of the privacy check and computes effective visibilities. diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index 2640ca56b00e9..59a7253ea4999 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -14,7 +14,7 @@ use rustc_errors::{ }; use rustc_hir as hir; use rustc_hir::def::*; -use rustc_hir::def_id::DefId; +use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{HirId, Pat}; use rustc_middle::ty::print::with_no_trimmed_paths; @@ -27,12 +27,8 @@ use rustc_session::Session; use rustc_span::source_map::Spanned; use rustc_span::{BytePos, Span}; -pub(crate) fn check_match(tcx: TyCtxt<'_>, def_id: DefId) { - let body_id = match def_id.as_local() { - None => return, - Some(def_id) => tcx.hir().body_owned_by(def_id), - }; - +pub(crate) fn check_match(tcx: TyCtxt<'_>, def_id: LocalDefId) { + let body_id = tcx.hir().body_owned_by(def_id); let pattern_arena = TypedArena::default(); let mut visitor = MatchVisitor { tcx, From 28d74a9b7286c7e93484541326c92bdddb587f1a Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Mon, 27 Feb 2023 17:39:02 +0000 Subject: [PATCH 02/13] Shrink binding span. --- .../src/thir/pattern/check_match.rs | 25 ++- ...atterns-slice-patterns-box-patterns.stderr | 10 +- ...can-live-while-the-other-survives-1.stderr | 20 +- .../borrowck-pat-at-and-box.stderr | 40 ++-- ...t-by-move-and-ref-inverse-promotion.stderr | 5 +- ...orrowck-pat-by-move-and-ref-inverse.stderr | 125 +++++------- .../borrowck-pat-by-move-and-ref.stderr | 125 +++++------- .../borrowck-pat-ref-mut-and-ref.stderr | 160 ++++++--------- .../borrowck-pat-ref-mut-twice.stderr | 186 +++++++----------- ...inding-modes-both-sides-independent.stderr | 25 +-- .../ui/suggestions/ref-pattern-binding.stderr | 20 +- 11 files changed, 302 insertions(+), 439 deletions(-) diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index 59a7253ea4999..2fee1721f994b 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -879,17 +879,25 @@ fn check_borrow_conflicts_in_at_patterns(cx: &MatchVisitor<'_, '_, '_>, pat: &Pa hir::PatKind::Binding(.., name, Some(sub)) => (*name, sub), _ => return, }; - let binding_span = pat.span.with_hi(name.span.hi()); + let mk_span = |pat_span, ident_span: Span| { + if let Some(ident_span) = ident_span.find_ancestor_inside(pat_span) { + pat_span.with_hi(ident_span.hi()) + } else { + pat_span + } + }; + let binding_span = mk_span(pat.span, name.span); let typeck_results = cx.typeck_results; let sess = cx.tcx.sess; // Get the binding move, extract the mutability if by-ref. - let mut_outer = match typeck_results.extract_binding_mode(sess, pat.hir_id, pat.span) { + let mut_outer = match typeck_results.extract_binding_mode(sess, pat.hir_id, binding_span) { Some(ty::BindByValue(_)) if is_binding_by_move(cx, pat.hir_id) => { // We have `x @ pat` where `x` is by-move. Reject all borrows in `pat`. let mut conflicts_ref = Vec::new(); - sub.each_binding(|_, hir_id, span, _| { + sub.each_binding(|_, hir_id, span, ident| { + let span = mk_span(span, ident.span); match typeck_results.extract_binding_mode(sess, hir_id, span) { Some(ty::BindByValue(_)) | None => {} Some(ty::BindByReference(_)) => conflicts_ref.push(span), @@ -897,7 +905,7 @@ fn check_borrow_conflicts_in_at_patterns(cx: &MatchVisitor<'_, '_, '_>, pat: &Pa }); if !conflicts_ref.is_empty() { sess.emit_err(BorrowOfMovedValue { - span: pat.span, + span: binding_span, binding_span, conflicts_ref, name, @@ -920,6 +928,7 @@ fn check_borrow_conflicts_in_at_patterns(cx: &MatchVisitor<'_, '_, '_>, pat: &Pa let mut conflicts_mut_mut = Vec::new(); let mut conflicts_mut_ref = Vec::new(); sub.each_binding(|_, hir_id, span, name| { + let span = mk_span(span, name.span); match typeck_results.extract_binding_mode(sess, hir_id, span) { Some(ty::BindByReference(mut_inner)) => match (mut_outer, mut_inner) { // Both sides are `ref`. @@ -957,20 +966,20 @@ fn check_borrow_conflicts_in_at_patterns(cx: &MatchVisitor<'_, '_, '_>, pat: &Pa // Report errors if any. if report_mut_mut { // Report mutability conflicts for e.g. `ref mut x @ Some(ref mut y)`. - sess.emit_err(MultipleMutBorrows { span: pat.span, occurences }); + sess.emit_err(MultipleMutBorrows { span: binding_span, occurences }); } else if report_mut_ref { // Report mutability conflicts for e.g. `ref x @ Some(ref mut y)` or the converse. match mut_outer { Mutability::Mut => { - sess.emit_err(AlreadyMutBorrowed { span: pat.span, occurences }); + sess.emit_err(AlreadyMutBorrowed { span: binding_span, occurences }); } Mutability::Not => { - sess.emit_err(AlreadyBorrowed { span: pat.span, occurences }); + sess.emit_err(AlreadyBorrowed { span: binding_span, occurences }); } }; } else if report_move_conflict { // Report by-ref and by-move conflicts, e.g. `ref x @ y`. - sess.emit_err(MovedWhileBorrowed { span: pat.span, occurences }); + sess.emit_err(MovedWhileBorrowed { span: binding_span, occurences }); } } diff --git a/tests/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.stderr b/tests/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.stderr index 5835f06753bb1..0ca14c3f3bc66 100644 --- a/tests/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.stderr +++ b/tests/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.stderr @@ -2,18 +2,16 @@ error: cannot borrow value as mutable because it is also borrowed as immutable --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:36:9 | LL | ref foo @ [.., ref mut bar] => (), - | -------^^^^^^^^-----------^ - | | | - | | value is mutably borrowed by `bar` here + | ^^^^^^^ ----------- value is mutably borrowed by `bar` here + | | | value is borrowed by `foo` here error: cannot borrow value as mutable because it is also borrowed as immutable --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:120:9 | LL | ref foo @ Some(box ref mut s) => (), - | -------^^^^^^^^^^^^---------^ - | | | - | | value is mutably borrowed by `s` here + | ^^^^^^^ --------- value is mutably borrowed by `s` here + | | | value is borrowed by `foo` here error[E0382]: borrow of moved value: `x` diff --git a/tests/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.stderr b/tests/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.stderr index 29cd6c45c34b5..25838fbf0abdc 100644 --- a/tests/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.stderr +++ b/tests/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.stderr @@ -2,18 +2,16 @@ error: cannot move out of value because it is borrowed --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:12:14 | LL | Some(ref _y @ _z) => {} - | ------^^^-- - | | | - | | value is moved into `_z` here + | ^^^^^^ -- value is moved into `_z` here + | | | value is borrowed by `_y` here error: borrow of moved value --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:19:14 | LL | Some(_z @ ref _y) => {} - | --^^^------ - | | | - | | value borrowed here after move + | ^^ ------ value borrowed here after move + | | | value moved into `_z` here | move occurs because `_z` has type `X` which does not implement the `Copy` trait | @@ -26,18 +24,16 @@ error: cannot move out of value because it is borrowed --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:26:14 | LL | Some(ref mut _y @ _z) => {} - | ----------^^^-- - | | | - | | value is moved into `_z` here + | ^^^^^^^^^^ -- value is moved into `_z` here + | | | value is mutably borrowed by `_y` here error: borrow of moved value --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:33:14 | LL | Some(_z @ ref mut _y) => {} - | --^^^---------- - | | | - | | value borrowed here after move + | ^^ ---------- value borrowed here after move + | | | value moved into `_z` here | move occurs because `_z` has type `X` which does not implement the `Copy` trait | diff --git a/tests/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.stderr b/tests/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.stderr index 2c123b01e173e..9305facc406f6 100644 --- a/tests/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.stderr +++ b/tests/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.stderr @@ -2,72 +2,64 @@ error: cannot move out of value because it is borrowed --> $DIR/borrowck-pat-at-and-box.rs:31:9 | LL | let ref a @ box b = Box::new(NC); - | -----^^^^^^^- - | | | - | | value is moved into `b` here + | ^^^^^ - value is moved into `b` here + | | | value is borrowed by `a` here error: cannot borrow value as mutable because it is also borrowed as immutable --> $DIR/borrowck-pat-at-and-box.rs:34:9 | LL | let ref a @ box ref mut b = Box::new(nc()); - | -----^^^^^^^--------- - | | | - | | value is mutably borrowed by `b` here + | ^^^^^ --------- value is mutably borrowed by `b` here + | | | value is borrowed by `a` here error: cannot borrow value as mutable because it is also borrowed as immutable --> $DIR/borrowck-pat-at-and-box.rs:36:9 | LL | let ref a @ box ref mut b = Box::new(NC); - | -----^^^^^^^--------- - | | | - | | value is mutably borrowed by `b` here + | ^^^^^ --------- value is mutably borrowed by `b` here + | | | value is borrowed by `a` here error: cannot borrow value as mutable because it is also borrowed as immutable --> $DIR/borrowck-pat-at-and-box.rs:38:9 | LL | let ref a @ box ref mut b = Box::new(NC); - | -----^^^^^^^--------- - | | | - | | value is mutably borrowed by `b` here + | ^^^^^ --------- value is mutably borrowed by `b` here + | | | value is borrowed by `a` here error: cannot borrow value as mutable because it is also borrowed as immutable --> $DIR/borrowck-pat-at-and-box.rs:42:9 | LL | let ref a @ box ref mut b = Box::new(NC); - | -----^^^^^^^--------- - | | | - | | value is mutably borrowed by `b` here + | ^^^^^ --------- value is mutably borrowed by `b` here + | | | value is borrowed by `a` here error: cannot borrow value as immutable because it is also borrowed as mutable --> $DIR/borrowck-pat-at-and-box.rs:48:9 | LL | let ref mut a @ box ref b = Box::new(NC); - | ---------^^^^^^^----- - | | | - | | value is borrowed by `b` here + | ^^^^^^^^^ ----- value is borrowed by `b` here + | | | value is mutably borrowed by `a` here error: cannot borrow value as immutable because it is also borrowed as mutable --> $DIR/borrowck-pat-at-and-box.rs:62:9 | LL | ref mut a @ box ref b => { - | ---------^^^^^^^----- - | | | - | | value is borrowed by `b` here + | ^^^^^^^^^ ----- value is borrowed by `b` here + | | | value is mutably borrowed by `a` here error: cannot borrow value as immutable because it is also borrowed as mutable --> $DIR/borrowck-pat-at-and-box.rs:54:11 | LL | fn f5(ref mut a @ box ref b: Box) { - | ---------^^^^^^^----- - | | | - | | value is borrowed by `b` here + | ^^^^^^^^^ ----- value is borrowed by `b` here + | | | value is mutably borrowed by `a` here error[E0382]: borrow of moved value diff --git a/tests/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse-promotion.stderr b/tests/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse-promotion.stderr index d6474f1b49fb0..c440f4619f52a 100644 --- a/tests/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse-promotion.stderr +++ b/tests/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse-promotion.stderr @@ -2,9 +2,8 @@ error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse-promotion.rs:6:9 | LL | let a @ ref b = U; - | -^^^----- - | | | - | | value borrowed here after move + | ^ ----- value borrowed here after move + | | | value moved into `a` here | move occurs because `a` has type `U` which does not implement the `Copy` trait | diff --git a/tests/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.stderr b/tests/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.stderr index 389e86e646457..13989ebadcb50 100644 --- a/tests/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.stderr +++ b/tests/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.stderr @@ -2,9 +2,8 @@ error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:22:9 | LL | let a @ ref b = U; - | -^^^----- - | | | - | | value borrowed here after move + | ^ ----- value borrowed here after move + | | | value moved into `a` here | move occurs because `a` has type `U` which does not implement the `Copy` trait | @@ -17,9 +16,8 @@ error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:24:9 | LL | let a @ (mut b @ ref mut c, d @ ref e) = (U, U); - | -^^^^^^^^^^^^---------^^^^^^-----^ - | | | | - | | | value borrowed here after move + | ^ --------- ----- value borrowed here after move + | | | | | value borrowed here after move | value moved into `a` here | move occurs because `a` has type `(U, U)` which does not implement the `Copy` trait @@ -33,9 +31,8 @@ error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:24:14 | LL | let a @ (mut b @ ref mut c, d @ ref e) = (U, U); - | -----^^^--------- - | | | - | | value borrowed here after move + | ^^^^^ --------- value borrowed here after move + | | | value moved into `b` here | move occurs because `b` has type `U` which does not implement the `Copy` trait | @@ -48,9 +45,8 @@ error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:24:33 | LL | let a @ (mut b @ ref mut c, d @ ref e) = (U, U); - | -^^^----- - | | | - | | value borrowed here after move + | ^ ----- value borrowed here after move + | | | value moved into `d` here | move occurs because `d` has type `U` which does not implement the `Copy` trait | @@ -63,9 +59,8 @@ error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:29:9 | LL | let a @ [ref mut b, ref c] = [U, U]; - | -^^^^---------^^-----^ - | | | | - | | | value borrowed here after move + | ^ --------- ----- value borrowed here after move + | | | | | value borrowed here after move | value moved into `a` here | move occurs because `a` has type `[U; 2]` which does not implement the `Copy` trait @@ -79,9 +74,8 @@ error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:31:9 | LL | let a @ ref b = u(); - | -^^^----- - | | | - | | value borrowed here after move + | ^ ----- value borrowed here after move + | | | value moved into `a` here | move occurs because `a` has type `U` which does not implement the `Copy` trait | @@ -94,9 +88,8 @@ error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:33:9 | LL | let a @ (mut b @ ref mut c, d @ ref e) = (u(), u()); - | -^^^^^^^^^^^^---------^^^^^^-----^ - | | | | - | | | value borrowed here after move + | ^ --------- ----- value borrowed here after move + | | | | | value borrowed here after move | value moved into `a` here | move occurs because `a` has type `(U, U)` which does not implement the `Copy` trait @@ -110,9 +103,8 @@ error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:33:14 | LL | let a @ (mut b @ ref mut c, d @ ref e) = (u(), u()); - | -----^^^--------- - | | | - | | value borrowed here after move + | ^^^^^ --------- value borrowed here after move + | | | value moved into `b` here | move occurs because `b` has type `U` which does not implement the `Copy` trait | @@ -125,9 +117,8 @@ error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:33:33 | LL | let a @ (mut b @ ref mut c, d @ ref e) = (u(), u()); - | -^^^----- - | | | - | | value borrowed here after move + | ^ ----- value borrowed here after move + | | | value moved into `d` here | move occurs because `d` has type `U` which does not implement the `Copy` trait | @@ -140,9 +131,8 @@ error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:38:9 | LL | let a @ [ref mut b, ref c] = [u(), u()]; - | -^^^^---------^^-----^ - | | | | - | | | value borrowed here after move + | ^ --------- ----- value borrowed here after move + | | | | | value borrowed here after move | value moved into `a` here | move occurs because `a` has type `[U; 2]` which does not implement the `Copy` trait @@ -156,9 +146,8 @@ error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:42:9 | LL | a @ Some(ref b) => {} - | -^^^^^^^^-----^ - | | | - | | value borrowed here after move + | ^ ----- value borrowed here after move + | | | value moved into `a` here | move occurs because `a` has type `Option` which does not implement the `Copy` trait | @@ -171,9 +160,8 @@ error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:47:9 | LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} - | -^^^^^^^^^^^^^^^^^---------^^^^^^-----^^ - | | | | - | | | value borrowed here after move + | ^ --------- ----- value borrowed here after move + | | | | | value borrowed here after move | value moved into `a` here | move occurs because `a` has type `Option<(U, U)>` which does not implement the `Copy` trait @@ -187,9 +175,8 @@ error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:47:19 | LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} - | -----^^^--------- - | | | - | | value borrowed here after move + | ^^^^^ --------- value borrowed here after move + | | | value moved into `b` here | move occurs because `b` has type `U` which does not implement the `Copy` trait | @@ -202,9 +189,8 @@ error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:47:38 | LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} - | -^^^----- - | | | - | | value borrowed here after move + | ^ ----- value borrowed here after move + | | | value moved into `d` here | move occurs because `d` has type `U` which does not implement the `Copy` trait | @@ -217,9 +203,8 @@ error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:55:9 | LL | mut a @ Some([ref b, ref mut c]) => {} - | -----^^^^^^^^^-----^^---------^^ - | | | | - | | | value borrowed here after move + | ^^^^^ ----- --------- value borrowed here after move + | | | | | value borrowed here after move | value moved into `a` here | move occurs because `a` has type `Option<[U; 2]>` which does not implement the `Copy` trait @@ -233,9 +218,8 @@ error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:61:9 | LL | a @ Some(ref b) => {} - | -^^^^^^^^-----^ - | | | - | | value borrowed here after move + | ^ ----- value borrowed here after move + | | | value moved into `a` here | move occurs because `a` has type `Option` which does not implement the `Copy` trait | @@ -248,9 +232,8 @@ error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:67:9 | LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} - | -^^^^^^^^^^^^^^^^^---------^^^^^^-----^^ - | | | | - | | | value borrowed here after move + | ^ --------- ----- value borrowed here after move + | | | | | value borrowed here after move | value moved into `a` here | move occurs because `a` has type `Option<(U, U)>` which does not implement the `Copy` trait @@ -264,9 +247,8 @@ error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:67:19 | LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} - | -----^^^--------- - | | | - | | value borrowed here after move + | ^^^^^ --------- value borrowed here after move + | | | value moved into `b` here | move occurs because `b` has type `U` which does not implement the `Copy` trait | @@ -279,9 +261,8 @@ error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:67:38 | LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} - | -^^^----- - | | | - | | value borrowed here after move + | ^ ----- value borrowed here after move + | | | value moved into `d` here | move occurs because `d` has type `U` which does not implement the `Copy` trait | @@ -294,9 +275,8 @@ error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:75:9 | LL | mut a @ Some([ref b, ref mut c]) => {} - | -----^^^^^^^^^-----^^---------^^ - | | | | - | | | value borrowed here after move + | ^^^^^ ----- --------- value borrowed here after move + | | | | | value borrowed here after move | value moved into `a` here | move occurs because `a` has type `Option<[U; 2]>` which does not implement the `Copy` trait @@ -310,9 +290,8 @@ error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:11:11 | LL | fn f1(a @ ref b: U) {} - | -^^^----- - | | | - | | value borrowed here after move + | ^ ----- value borrowed here after move + | | | value moved into `a` here | move occurs because `a` has type `U` which does not implement the `Copy` trait | @@ -325,9 +304,8 @@ error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:14:11 | LL | fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {} - | -----^^^^^^^^-----^^^^^^^^^^-----^ - | | | | - | | | value borrowed here after move + | ^^^^^ ----- ----- value borrowed here after move + | | | | | value borrowed here after move | value moved into `a` here | move occurs because `a` has type `(U, U)` which does not implement the `Copy` trait @@ -341,9 +319,8 @@ error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:14:20 | LL | fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {} - | -^^^----- - | | | - | | value borrowed here after move + | ^ ----- value borrowed here after move + | | | value moved into `b` here | move occurs because `b` has type `U` which does not implement the `Copy` trait | @@ -356,9 +333,8 @@ error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:14:31 | LL | fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {} - | -----^^^----- - | | | - | | value borrowed here after move + | ^^^^^ ----- value borrowed here after move + | | | value moved into `d` here | move occurs because `d` has type `U` which does not implement the `Copy` trait | @@ -371,9 +347,8 @@ error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:19:11 | LL | fn f3(a @ [ref mut b, ref c]: [U; 2]) {} - | -^^^^---------^^-----^ - | | | | - | | | value borrowed here after move + | ^ --------- ----- value borrowed here after move + | | | | | value borrowed here after move | value moved into `a` here | move occurs because `a` has type `[U; 2]` which does not implement the `Copy` trait diff --git a/tests/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.stderr b/tests/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.stderr index 4f7fbc9e04b04..00593b2a98f2b 100644 --- a/tests/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.stderr +++ b/tests/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.stderr @@ -2,18 +2,16 @@ error: cannot move out of value because it is borrowed --> $DIR/borrowck-pat-by-move-and-ref.rs:24:9 | LL | let ref a @ b = U; - | -----^^^- - | | | - | | value is moved into `b` here + | ^^^^^ - value is moved into `b` here + | | | value is borrowed by `a` here error: cannot move out of value because it is borrowed --> $DIR/borrowck-pat-by-move-and-ref.rs:26:9 | LL | let ref a @ (ref b @ mut c, ref d @ e) = (U, U); - | -----^^^^^^^^^^^^-----^^^^^^^^^^-^ - | | | | - | | | value is moved into `e` here + | ^^^^^ ----- - value is moved into `e` here + | | | | | value is moved into `c` here | value is borrowed by `a` here @@ -21,27 +19,24 @@ error: cannot move out of value because it is borrowed --> $DIR/borrowck-pat-by-move-and-ref.rs:26:18 | LL | let ref a @ (ref b @ mut c, ref d @ e) = (U, U); - | -----^^^----- - | | | - | | value is moved into `c` here + | ^^^^^ ----- value is moved into `c` here + | | | value is borrowed by `b` here error: cannot move out of value because it is borrowed --> $DIR/borrowck-pat-by-move-and-ref.rs:26:33 | LL | let ref a @ (ref b @ mut c, ref d @ e) = (U, U); - | -----^^^- - | | | - | | value is moved into `e` here + | ^^^^^ - value is moved into `e` here + | | | value is borrowed by `d` here error: cannot move out of value because it is borrowed --> $DIR/borrowck-pat-by-move-and-ref.rs:30:9 | LL | let ref mut a @ [b, mut c] = [U, U]; - | ---------^^^^-^^-----^ - | | | | - | | | value is moved into `c` here + | ^^^^^^^^^ - ----- value is moved into `c` here + | | | | | value is moved into `b` here | value is mutably borrowed by `a` here @@ -49,18 +44,16 @@ error: cannot move out of value because it is borrowed --> $DIR/borrowck-pat-by-move-and-ref.rs:33:9 | LL | let ref a @ b = u(); - | -----^^^- - | | | - | | value is moved into `b` here + | ^^^^^ - value is moved into `b` here + | | | value is borrowed by `a` here error: cannot move out of value because it is borrowed --> $DIR/borrowck-pat-by-move-and-ref.rs:36:9 | LL | let ref a @ (ref b @ mut c, ref d @ e) = (u(), u()); - | -----^^^^^^^^^^^^-----^^^^^^^^^^-^ - | | | | - | | | value is moved into `e` here + | ^^^^^ ----- - value is moved into `e` here + | | | | | value is moved into `c` here | value is borrowed by `a` here @@ -68,27 +61,24 @@ error: cannot move out of value because it is borrowed --> $DIR/borrowck-pat-by-move-and-ref.rs:36:18 | LL | let ref a @ (ref b @ mut c, ref d @ e) = (u(), u()); - | -----^^^----- - | | | - | | value is moved into `c` here + | ^^^^^ ----- value is moved into `c` here + | | | value is borrowed by `b` here error: cannot move out of value because it is borrowed --> $DIR/borrowck-pat-by-move-and-ref.rs:36:33 | LL | let ref a @ (ref b @ mut c, ref d @ e) = (u(), u()); - | -----^^^- - | | | - | | value is moved into `e` here + | ^^^^^ - value is moved into `e` here + | | | value is borrowed by `d` here error: cannot move out of value because it is borrowed --> $DIR/borrowck-pat-by-move-and-ref.rs:42:9 | LL | let ref mut a @ [b, mut c] = [u(), u()]; - | ---------^^^^-^^-----^ - | | | | - | | | value is moved into `c` here + | ^^^^^^^^^ - ----- value is moved into `c` here + | | | | | value is moved into `b` here | value is mutably borrowed by `a` here @@ -96,18 +86,16 @@ error: cannot move out of value because it is borrowed --> $DIR/borrowck-pat-by-move-and-ref.rs:47:9 | LL | ref a @ Some(b) => {} - | -----^^^^^^^^-^ - | | | - | | value is moved into `b` here + | ^^^^^ - value is moved into `b` here + | | | value is borrowed by `a` here error: cannot move out of value because it is borrowed --> $DIR/borrowck-pat-by-move-and-ref.rs:52:9 | LL | ref a @ Some((ref b @ mut c, ref d @ e)) => {} - | -----^^^^^^^^^^^^^^^^^-----^^^^^^^^^^-^^ - | | | | - | | | value is moved into `e` here + | ^^^^^ ----- - value is moved into `e` here + | | | | | value is moved into `c` here | value is borrowed by `a` here @@ -115,27 +103,24 @@ error: cannot move out of value because it is borrowed --> $DIR/borrowck-pat-by-move-and-ref.rs:52:23 | LL | ref a @ Some((ref b @ mut c, ref d @ e)) => {} - | -----^^^----- - | | | - | | value is moved into `c` here + | ^^^^^ ----- value is moved into `c` here + | | | value is borrowed by `b` here error: cannot move out of value because it is borrowed --> $DIR/borrowck-pat-by-move-and-ref.rs:52:38 | LL | ref a @ Some((ref b @ mut c, ref d @ e)) => {} - | -----^^^- - | | | - | | value is moved into `e` here + | ^^^^^ - value is moved into `e` here + | | | value is borrowed by `d` here error: cannot move out of value because it is borrowed --> $DIR/borrowck-pat-by-move-and-ref.rs:59:9 | LL | ref mut a @ Some([b, mut c]) => {} - | ---------^^^^^^^^^-^^-----^^ - | | | | - | | | value is moved into `c` here + | ^^^^^^^^^ - ----- value is moved into `c` here + | | | | | value is moved into `b` here | value is mutably borrowed by `a` here @@ -143,18 +128,16 @@ error: cannot move out of value because it is borrowed --> $DIR/borrowck-pat-by-move-and-ref.rs:64:9 | LL | ref a @ Some(b) => {} - | -----^^^^^^^^-^ - | | | - | | value is moved into `b` here + | ^^^^^ - value is moved into `b` here + | | | value is borrowed by `a` here error: cannot move out of value because it is borrowed --> $DIR/borrowck-pat-by-move-and-ref.rs:69:9 | LL | ref a @ Some((ref b @ mut c, ref d @ e)) => {} - | -----^^^^^^^^^^^^^^^^^-----^^^^^^^^^^-^^ - | | | | - | | | value is moved into `e` here + | ^^^^^ ----- - value is moved into `e` here + | | | | | value is moved into `c` here | value is borrowed by `a` here @@ -162,27 +145,24 @@ error: cannot move out of value because it is borrowed --> $DIR/borrowck-pat-by-move-and-ref.rs:69:23 | LL | ref a @ Some((ref b @ mut c, ref d @ e)) => {} - | -----^^^----- - | | | - | | value is moved into `c` here + | ^^^^^ ----- value is moved into `c` here + | | | value is borrowed by `b` here error: cannot move out of value because it is borrowed --> $DIR/borrowck-pat-by-move-and-ref.rs:69:38 | LL | ref a @ Some((ref b @ mut c, ref d @ e)) => {} - | -----^^^- - | | | - | | value is moved into `e` here + | ^^^^^ - value is moved into `e` here + | | | value is borrowed by `d` here error: cannot move out of value because it is borrowed --> $DIR/borrowck-pat-by-move-and-ref.rs:78:9 | LL | ref mut a @ Some([b, mut c]) => {} - | ---------^^^^^^^^^-^^-----^^ - | | | | - | | | value is moved into `c` here + | ^^^^^^^^^ - ----- value is moved into `c` here + | | | | | value is moved into `b` here | value is mutably borrowed by `a` here @@ -190,18 +170,16 @@ error: cannot move out of value because it is borrowed --> $DIR/borrowck-pat-by-move-and-ref.rs:11:11 | LL | fn f1(ref a @ b: U) {} - | -----^^^- - | | | - | | value is moved into `b` here + | ^^^^^ - value is moved into `b` here + | | | value is borrowed by `a` here error: cannot move out of value because it is borrowed --> $DIR/borrowck-pat-by-move-and-ref.rs:14:11 | LL | fn f2(ref a @ (ref b @ mut c, ref d @ e): (U, U)) {} - | -----^^^^^^^^^^^^-----^^^^^^^^^^-^ - | | | | - | | | value is moved into `e` here + | ^^^^^ ----- - value is moved into `e` here + | | | | | value is moved into `c` here | value is borrowed by `a` here @@ -209,27 +187,24 @@ error: cannot move out of value because it is borrowed --> $DIR/borrowck-pat-by-move-and-ref.rs:14:20 | LL | fn f2(ref a @ (ref b @ mut c, ref d @ e): (U, U)) {} - | -----^^^----- - | | | - | | value is moved into `c` here + | ^^^^^ ----- value is moved into `c` here + | | | value is borrowed by `b` here error: cannot move out of value because it is borrowed --> $DIR/borrowck-pat-by-move-and-ref.rs:14:35 | LL | fn f2(ref a @ (ref b @ mut c, ref d @ e): (U, U)) {} - | -----^^^- - | | | - | | value is moved into `e` here + | ^^^^^ - value is moved into `e` here + | | | value is borrowed by `d` here error: cannot move out of value because it is borrowed --> $DIR/borrowck-pat-by-move-and-ref.rs:20:11 | LL | fn f3(ref mut a @ [b, mut c]: [U; 2]) {} - | ---------^^^^-^^-----^ - | | | | - | | | value is moved into `c` here + | ^^^^^^^^^ - ----- value is moved into `c` here + | | | | | value is moved into `b` here | value is mutably borrowed by `a` here diff --git a/tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr b/tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr index f51b5041858c6..d6409d1b643b9 100644 --- a/tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr +++ b/tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr @@ -2,18 +2,16 @@ error: cannot borrow value as immutable because it is also borrowed as mutable --> $DIR/borrowck-pat-ref-mut-and-ref.rs:8:9 | LL | ref mut z @ &mut Some(ref a) => { - | ---------^^^^^^^^^^^^^-----^ - | | | - | | value is borrowed by `a` here + | ^^^^^^^^^ ----- value is borrowed by `a` here + | | | value is mutably borrowed by `z` here error: cannot borrow value as mutable more than once at a time --> $DIR/borrowck-pat-ref-mut-and-ref.rs:33:9 | LL | let ref mut a @ (ref b @ ref mut c) = u(); // sub-in-sub - | ---------^^^^-----------------^ - | | | | - | | | value is mutably borrowed by `c` here + | ^^^^^^^^^ ----- --------- value is mutably borrowed by `c` here + | | | | | value is borrowed by `b` here | value is mutably borrowed by `a` here @@ -21,36 +19,32 @@ error: cannot borrow value as mutable because it is also borrowed as immutable --> $DIR/borrowck-pat-ref-mut-and-ref.rs:33:22 | LL | let ref mut a @ (ref b @ ref mut c) = u(); // sub-in-sub - | -----^^^--------- - | | | - | | value is mutably borrowed by `c` here + | ^^^^^ --------- value is mutably borrowed by `c` here + | | | value is borrowed by `b` here error: cannot borrow value as mutable because it is also borrowed as immutable --> $DIR/borrowck-pat-ref-mut-and-ref.rs:37:9 | LL | let ref a @ ref mut b = U; - | -----^^^--------- - | | | - | | value is mutably borrowed by `b` here + | ^^^^^ --------- value is mutably borrowed by `b` here + | | | value is borrowed by `a` here error: cannot borrow value as immutable because it is also borrowed as mutable --> $DIR/borrowck-pat-ref-mut-and-ref.rs:39:9 | LL | let ref mut a @ ref b = U; - | ---------^^^----- - | | | - | | value is borrowed by `b` here + | ^^^^^^^^^ ----- value is borrowed by `b` here + | | | value is mutably borrowed by `a` here error: cannot borrow value as mutable because it is also borrowed as immutable --> $DIR/borrowck-pat-ref-mut-and-ref.rs:41:9 | LL | let ref a @ (ref mut b, ref mut c) = (U, U); - | -----^^^^---------^^---------^ - | | | | - | | | value is mutably borrowed by `c` here + | ^^^^^ --------- --------- value is mutably borrowed by `c` here + | | | | | value is mutably borrowed by `b` here | value is borrowed by `a` here @@ -58,9 +52,8 @@ error: cannot borrow value as immutable because it is also borrowed as mutable --> $DIR/borrowck-pat-ref-mut-and-ref.rs:43:9 | LL | let ref mut a @ (ref b, ref c) = (U, U); - | ---------^^^^-----^^-----^ - | | | | - | | | value is borrowed by `c` here + | ^^^^^^^^^ ----- ----- value is borrowed by `c` here + | | | | | value is borrowed by `b` here | value is mutably borrowed by `a` here @@ -68,153 +61,136 @@ error: cannot borrow value as immutable because it is also borrowed as mutable --> $DIR/borrowck-pat-ref-mut-and-ref.rs:46:9 | LL | let ref mut a @ ref b = u(); - | ---------^^^----- - | | | - | | value is borrowed by `b` here + | ^^^^^^^^^ ----- value is borrowed by `b` here + | | | value is mutably borrowed by `a` here error: cannot borrow value as mutable because it is also borrowed as immutable --> $DIR/borrowck-pat-ref-mut-and-ref.rs:51:9 | LL | let ref a @ ref mut b = u(); - | -----^^^--------- - | | | - | | value is mutably borrowed by `b` here + | ^^^^^ --------- value is mutably borrowed by `b` here + | | | value is borrowed by `a` here error: cannot borrow value as immutable because it is also borrowed as mutable --> $DIR/borrowck-pat-ref-mut-and-ref.rs:57:9 | LL | let ref mut a @ ref b = U; - | ---------^^^----- - | | | - | | value is borrowed by `b` here + | ^^^^^^^^^ ----- value is borrowed by `b` here + | | | value is mutably borrowed by `a` here error: cannot borrow value as mutable because it is also borrowed as immutable --> $DIR/borrowck-pat-ref-mut-and-ref.rs:61:9 | LL | let ref a @ ref mut b = U; - | -----^^^--------- - | | | - | | value is mutably borrowed by `b` here + | ^^^^^ --------- value is mutably borrowed by `b` here + | | | value is borrowed by `a` here error: cannot borrow value as immutable because it is also borrowed as mutable --> $DIR/borrowck-pat-ref-mut-and-ref.rs:67:9 | LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) => { - | ---------^^^^^^-----^ - | | | - | | value is borrowed by `b` here + | ^^^^^^^^^ ----- value is borrowed by `b` here + | | | value is mutably borrowed by `a` here error: cannot borrow value as immutable because it is also borrowed as mutable --> $DIR/borrowck-pat-ref-mut-and-ref.rs:67:33 | LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) => { - | ---------^^^^^^^-----^ - | | | - | | value is borrowed by `b` here + | ^^^^^^^^^ ----- value is borrowed by `b` here + | | | value is mutably borrowed by `a` here error: cannot borrow value as mutable because it is also borrowed as immutable --> $DIR/borrowck-pat-ref-mut-and-ref.rs:76:9 | LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) => { - | -----^^^^^^---------^ - | | | - | | value is mutably borrowed by `b` here + | ^^^^^ --------- value is mutably borrowed by `b` here + | | | value is borrowed by `a` here error: cannot borrow value as mutable because it is also borrowed as immutable --> $DIR/borrowck-pat-ref-mut-and-ref.rs:76:33 | LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) => { - | -----^^^^^^^---------^ - | | | - | | value is mutably borrowed by `b` here + | ^^^^^ --------- value is mutably borrowed by `b` here + | | | value is borrowed by `a` here error: cannot borrow value as mutable because it is also borrowed as immutable --> $DIR/borrowck-pat-ref-mut-and-ref.rs:87:9 | LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { *b = U; false } => {} - | -----^^^^^^---------^ - | | | - | | value is mutably borrowed by `b` here + | ^^^^^ --------- value is mutably borrowed by `b` here + | | | value is borrowed by `a` here error: cannot borrow value as mutable because it is also borrowed as immutable --> $DIR/borrowck-pat-ref-mut-and-ref.rs:87:33 | LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { *b = U; false } => {} - | -----^^^^^^^---------^ - | | | - | | value is mutably borrowed by `b` here + | ^^^^^ --------- value is mutably borrowed by `b` here + | | | value is borrowed by `a` here error: cannot borrow value as immutable because it is also borrowed as mutable --> $DIR/borrowck-pat-ref-mut-and-ref.rs:94:9 | LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { *a = Err(U); false } => {} - | ---------^^^^^^-----^ - | | | - | | value is borrowed by `b` here + | ^^^^^^^^^ ----- value is borrowed by `b` here + | | | value is mutably borrowed by `a` here error: cannot borrow value as immutable because it is also borrowed as mutable --> $DIR/borrowck-pat-ref-mut-and-ref.rs:94:33 | LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { *a = Err(U); false } => {} - | ---------^^^^^^^-----^ - | | | - | | value is borrowed by `b` here + | ^^^^^^^^^ ----- value is borrowed by `b` here + | | | value is mutably borrowed by `a` here error: cannot borrow value as mutable because it is also borrowed as immutable --> $DIR/borrowck-pat-ref-mut-and-ref.rs:101:9 | LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { drop(b); false } => {} - | -----^^^^^^---------^ - | | | - | | value is mutably borrowed by `b` here + | ^^^^^ --------- value is mutably borrowed by `b` here + | | | value is borrowed by `a` here error: cannot borrow value as mutable because it is also borrowed as immutable --> $DIR/borrowck-pat-ref-mut-and-ref.rs:101:33 | LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { drop(b); false } => {} - | -----^^^^^^^---------^ - | | | - | | value is mutably borrowed by `b` here + | ^^^^^ --------- value is mutably borrowed by `b` here + | | | value is borrowed by `a` here error: cannot borrow value as immutable because it is also borrowed as mutable --> $DIR/borrowck-pat-ref-mut-and-ref.rs:109:9 | LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { drop(a); false } => {} - | ---------^^^^^^-----^ - | | | - | | value is borrowed by `b` here + | ^^^^^^^^^ ----- value is borrowed by `b` here + | | | value is mutably borrowed by `a` here error: cannot borrow value as immutable because it is also borrowed as mutable --> $DIR/borrowck-pat-ref-mut-and-ref.rs:109:33 | LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { drop(a); false } => {} - | ---------^^^^^^^-----^ - | | | - | | value is borrowed by `b` here + | ^^^^^^^^^ ----- value is borrowed by `b` here + | | | value is mutably borrowed by `a` here error: cannot borrow value as mutable because it is also borrowed as immutable --> $DIR/borrowck-pat-ref-mut-and-ref.rs:117:9 | LL | let ref a @ (ref mut b, ref mut c) = (U, U); - | -----^^^^---------^^---------^ - | | | | - | | | value is mutably borrowed by `c` here + | ^^^^^ --------- --------- value is mutably borrowed by `c` here + | | | | | value is mutably borrowed by `b` here | value is borrowed by `a` here @@ -222,9 +198,8 @@ error: cannot borrow value as mutable because it is also borrowed as immutable --> $DIR/borrowck-pat-ref-mut-and-ref.rs:123:9 | LL | let ref a @ (ref mut b, ref mut c) = (U, U); - | -----^^^^---------^^---------^ - | | | | - | | | value is mutably borrowed by `c` here + | ^^^^^ --------- --------- value is mutably borrowed by `c` here + | | | | | value is mutably borrowed by `b` here | value is borrowed by `a` here @@ -232,9 +207,8 @@ error: cannot borrow value as mutable because it is also borrowed as immutable --> $DIR/borrowck-pat-ref-mut-and-ref.rs:129:9 | LL | let ref a @ (ref mut b, ref mut c) = (U, U); - | -----^^^^---------^^---------^ - | | | | - | | | value is mutably borrowed by `c` here + | ^^^^^ --------- --------- value is mutably borrowed by `c` here + | | | | | value is mutably borrowed by `b` here | value is borrowed by `a` here @@ -242,9 +216,8 @@ error: cannot borrow value as immutable because it is also borrowed as mutable --> $DIR/borrowck-pat-ref-mut-and-ref.rs:134:9 | LL | let ref mut a @ (ref b, ref c) = (U, U); - | ---------^^^^-----^^-----^ - | | | | - | | | value is borrowed by `c` here + | ^^^^^^^^^ ----- ----- value is borrowed by `c` here + | | | | | value is borrowed by `b` here | value is mutably borrowed by `a` here @@ -252,36 +225,32 @@ error: cannot borrow value as mutable because it is also borrowed as immutable --> $DIR/borrowck-pat-ref-mut-and-ref.rs:22:11 | LL | fn f1(ref a @ ref mut b: U) {} - | -----^^^--------- - | | | - | | value is mutably borrowed by `b` here + | ^^^^^ --------- value is mutably borrowed by `b` here + | | | value is borrowed by `a` here error: cannot borrow value as immutable because it is also borrowed as mutable --> $DIR/borrowck-pat-ref-mut-and-ref.rs:24:11 | LL | fn f2(ref mut a @ ref b: U) {} - | ---------^^^----- - | | | - | | value is borrowed by `b` here + | ^^^^^^^^^ ----- value is borrowed by `b` here + | | | value is mutably borrowed by `a` here error: cannot borrow value as mutable because it is also borrowed as immutable --> $DIR/borrowck-pat-ref-mut-and-ref.rs:26:11 | LL | fn f3(ref a @ [ref b, ref mut mid @ .., ref c]: [U; 4]) {} - | -----^^^^^^^^^^^----------------^^^^^^^^ - | | | - | | value is mutably borrowed by `mid` here + | ^^^^^ ----------- value is mutably borrowed by `mid` here + | | | value is borrowed by `a` here error: cannot borrow value as mutable because it is also borrowed as immutable --> $DIR/borrowck-pat-ref-mut-and-ref.rs:28:22 | LL | fn f4_also_moved(ref a @ ref mut b @ c: U) {} - | -----^^^------------- - | | | | - | | | value is moved into `c` here + | ^^^^^ --------- - value is moved into `c` here + | | | | | value is mutably borrowed by `b` here | value is borrowed by `a` here @@ -289,9 +258,8 @@ error: cannot move out of value because it is borrowed --> $DIR/borrowck-pat-ref-mut-and-ref.rs:28:30 | LL | fn f4_also_moved(ref a @ ref mut b @ c: U) {} - | ---------^^^- - | | | - | | value is moved into `c` here + | ^^^^^^^^^ - value is moved into `c` here + | | | value is mutably borrowed by `b` here error[E0502]: cannot borrow value as immutable because it is also borrowed as mutable diff --git a/tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr b/tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr index a0cb04a064e06..24189d0615c70 100644 --- a/tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr +++ b/tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr @@ -2,98 +2,80 @@ error: cannot borrow value as mutable more than once at a time --> $DIR/borrowck-pat-ref-mut-twice.rs:26:9 | LL | let ref mut a @ ref mut b = U; - | ---------^^^--------- - | | | - | | value is mutably borrowed by `b` here + | ^^^^^^^^^ --------- value is mutably borrowed by `b` here + | | | value is mutably borrowed by `a` here error: cannot borrow value as mutable more than once at a time --> $DIR/borrowck-pat-ref-mut-twice.rs:29:9 | LL | let ref mut a @ ref mut b = U; - | ---------^^^--------- - | | | - | | value is mutably borrowed by `b` here + | ^^^^^^^^^ --------- value is mutably borrowed by `b` here + | | | value is mutably borrowed by `a` here error: cannot borrow value as mutable more than once at a time --> $DIR/borrowck-pat-ref-mut-twice.rs:33:9 | LL | let ref mut a @ ref mut b = U; - | ---------^^^--------- - | | | - | | value is mutably borrowed by `b` here + | ^^^^^^^^^ --------- value is mutably borrowed by `b` here + | | | value is mutably borrowed by `a` here error: cannot borrow value as mutable more than once at a time --> $DIR/borrowck-pat-ref-mut-twice.rs:36:9 | LL | let ref mut a @ ref mut b = U; - | ---------^^^--------- - | | | - | | value is mutably borrowed by `b` here + | ^^^^^^^^^ --------- value is mutably borrowed by `b` here + | | | value is mutably borrowed by `a` here error: cannot borrow value as mutable more than once at a time --> $DIR/borrowck-pat-ref-mut-twice.rs:39:9 | LL | let ref mut a @ ref mut b = U; - | ---------^^^--------- - | | | - | | value is mutably borrowed by `b` here + | ^^^^^^^^^ --------- value is mutably borrowed by `b` here + | | | value is mutably borrowed by `a` here error: cannot borrow value as mutable more than once at a time --> $DIR/borrowck-pat-ref-mut-twice.rs:44:9 | -LL | let ref mut a @ ( - | ^-------- - | | - | _________value is mutably borrowed by `a` here - | | -LL | | -LL | | ref mut b, - | | --------- value is mutably borrowed by `b` here -LL | | [ -LL | | ref mut c, - | | --------- value is mutably borrowed by `c` here -LL | | ref mut d, - | | --------- value is mutably borrowed by `d` here -LL | | ref e, - | | ----- value is borrowed by `e` here -LL | | ] -LL | | ) = (U, [U, U, U]); - | |_____^ +LL | let ref mut a @ ( + | ^^^^^^^^^ value is mutably borrowed by `a` here +LL | +LL | ref mut b, + | --------- value is mutably borrowed by `b` here +LL | [ +LL | ref mut c, + | --------- value is mutably borrowed by `c` here +LL | ref mut d, + | --------- value is mutably borrowed by `d` here +LL | ref e, + | ----- value is borrowed by `e` here error: cannot borrow value as mutable more than once at a time --> $DIR/borrowck-pat-ref-mut-twice.rs:54:9 | -LL | let ref mut a @ ( - | ^-------- - | | - | _________value is mutably borrowed by `a` here - | | -LL | | -LL | | ref mut b, - | | --------- value is mutably borrowed by `b` here -LL | | [ -LL | | ref mut c, - | | --------- value is mutably borrowed by `c` here -LL | | ref mut d, - | | --------- value is mutably borrowed by `d` here -LL | | ref e, - | | ----- value is borrowed by `e` here -LL | | ] -LL | | ) = (u(), [u(), u(), u()]); - | |_________^ +LL | let ref mut a @ ( + | ^^^^^^^^^ value is mutably borrowed by `a` here +LL | +LL | ref mut b, + | --------- value is mutably borrowed by `b` here +LL | [ +LL | ref mut c, + | --------- value is mutably borrowed by `c` here +LL | ref mut d, + | --------- value is mutably borrowed by `d` here +LL | ref e, + | ----- value is borrowed by `e` here error: borrow of moved value --> $DIR/borrowck-pat-ref-mut-twice.rs:64:9 | LL | let a @ (ref mut b, ref mut c) = (U, U); - | -^^^^---------^^---------^ - | | | | - | | | value borrowed here after move + | ^ --------- --------- value borrowed here after move + | | | | | value borrowed here after move | value moved into `a` here | move occurs because `a` has type `(U, U)` which does not implement the `Copy` trait @@ -107,9 +89,8 @@ error: borrow of moved value --> $DIR/borrowck-pat-ref-mut-twice.rs:67:9 | LL | let a @ (b, [c, d]) = &mut val; // Same as ^-- - | -^^^^-^^^-^^-^^ - | | | | | - | | | | value borrowed here after move + | ^ - - - value borrowed here after move + | | | | | | | value borrowed here after move | | value borrowed here after move | value moved into `a` here @@ -124,9 +105,8 @@ error: borrow of moved value --> $DIR/borrowck-pat-ref-mut-twice.rs:70:9 | LL | let a @ &mut ref mut b = &mut U; - | -^^^^^^^^--------- - | | | - | | value borrowed here after move + | ^ --------- value borrowed here after move + | | | value moved into `a` here | move occurs because `a` has type `&mut U` which does not implement the `Copy` trait | @@ -139,9 +119,8 @@ error: borrow of moved value --> $DIR/borrowck-pat-ref-mut-twice.rs:72:9 | LL | let a @ &mut (ref mut b, ref mut c) = &mut (U, U); - | -^^^^^^^^^---------^^---------^ - | | | | - | | | value borrowed here after move + | ^ --------- --------- value borrowed here after move + | | | | | value borrowed here after move | value moved into `a` here | move occurs because `a` has type `&mut (U, U)` which does not implement the `Copy` trait @@ -155,117 +134,99 @@ error: cannot borrow value as mutable more than once at a time --> $DIR/borrowck-pat-ref-mut-twice.rs:76:9 | LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { - | ---------^^^^^^---------^ - | | | - | | value is mutably borrowed by `b` here + | ^^^^^^^^^ --------- value is mutably borrowed by `b` here + | | | value is mutably borrowed by `a` here error: cannot borrow value as mutable more than once at a time --> $DIR/borrowck-pat-ref-mut-twice.rs:76:37 | LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { - | ---------^^^^^^^---------^ - | | | - | | value is mutably borrowed by `b` here + | ^^^^^^^^^ --------- value is mutably borrowed by `b` here + | | | value is mutably borrowed by `a` here error: cannot borrow value as mutable more than once at a time --> $DIR/borrowck-pat-ref-mut-twice.rs:82:9 | LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { - | ---------^^^^^^---------^ - | | | - | | value is mutably borrowed by `b` here + | ^^^^^^^^^ --------- value is mutably borrowed by `b` here + | | | value is mutably borrowed by `a` here error: cannot borrow value as mutable more than once at a time --> $DIR/borrowck-pat-ref-mut-twice.rs:82:37 | LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { - | ---------^^^^^^^---------^ - | | | - | | value is mutably borrowed by `b` here + | ^^^^^^^^^ --------- value is mutably borrowed by `b` here + | | | value is mutably borrowed by `a` here error: cannot borrow value as mutable more than once at a time --> $DIR/borrowck-pat-ref-mut-twice.rs:89:9 | LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { - | ---------^^^^^^---------^ - | | | - | | value is mutably borrowed by `b` here + | ^^^^^^^^^ --------- value is mutably borrowed by `b` here + | | | value is mutably borrowed by `a` here error: cannot borrow value as mutable more than once at a time --> $DIR/borrowck-pat-ref-mut-twice.rs:89:37 | LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { - | ---------^^^^^^^---------^ - | | | - | | value is mutably borrowed by `b` here + | ^^^^^^^^^ --------- value is mutably borrowed by `b` here + | | | value is mutably borrowed by `a` here error: cannot borrow value as mutable more than once at a time --> $DIR/borrowck-pat-ref-mut-twice.rs:101:9 | LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { - | ---------^^^^^^---------^ - | | | - | | value is mutably borrowed by `b` here + | ^^^^^^^^^ --------- value is mutably borrowed by `b` here + | | | value is mutably borrowed by `a` here error: cannot borrow value as mutable more than once at a time --> $DIR/borrowck-pat-ref-mut-twice.rs:101:37 | LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { - | ---------^^^^^^^---------^ - | | | - | | value is mutably borrowed by `b` here + | ^^^^^^^^^ --------- value is mutably borrowed by `b` here + | | | value is mutably borrowed by `a` here error: cannot borrow value as mutable more than once at a time --> $DIR/borrowck-pat-ref-mut-twice.rs:8:11 | LL | fn f1(ref mut a @ ref mut b: U) {} - | ---------^^^--------- - | | | - | | value is mutably borrowed by `b` here + | ^^^^^^^^^ --------- value is mutably borrowed by `b` here + | | | value is mutably borrowed by `a` here error: cannot borrow value as mutable more than once at a time --> $DIR/borrowck-pat-ref-mut-twice.rs:10:11 | LL | fn f2(ref mut a @ ref mut b: U) {} - | ---------^^^--------- - | | | - | | value is mutably borrowed by `b` here + | ^^^^^^^^^ --------- value is mutably borrowed by `b` here + | | | value is mutably borrowed by `a` here error: cannot borrow value as mutable more than once at a time --> $DIR/borrowck-pat-ref-mut-twice.rs:13:9 | -LL | ref mut a @ [ - | ^-------- - | | - | _________value is mutably borrowed by `a` here - | | -LL | | -LL | | [ref b @ .., _], - | | ---------- value is borrowed by `b` here -LL | | [_, ref mut mid @ ..], - | | ---------------- value is mutably borrowed by `mid` here -LL | | .., -LL | | [..], -LL | | ] : [[U; 4]; 5] - | |_________^ +LL | ref mut a @ [ + | ^^^^^^^^^ value is mutably borrowed by `a` here +LL | +LL | [ref b @ .., _], + | ----- value is borrowed by `b` here +LL | [_, ref mut mid @ ..], + | ----------- value is mutably borrowed by `mid` here error: cannot borrow value as mutable more than once at a time --> $DIR/borrowck-pat-ref-mut-twice.rs:21:22 | LL | fn f4_also_moved(ref mut a @ ref mut b @ c: U) {} - | ---------^^^------------- - | | | | - | | | value is moved into `c` here + | ^^^^^^^^^ --------- - value is moved into `c` here + | | | | | value is mutably borrowed by `b` here | value is mutably borrowed by `a` here @@ -273,9 +234,8 @@ error: cannot move out of value because it is borrowed --> $DIR/borrowck-pat-ref-mut-twice.rs:21:34 | LL | fn f4_also_moved(ref mut a @ ref mut b @ c: U) {} - | ---------^^^- - | | | - | | value is moved into `c` here + | ^^^^^^^^^ - value is moved into `c` here + | | | value is mutably borrowed by `b` here error[E0499]: cannot borrow value as mutable more than once at a time diff --git a/tests/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.stderr b/tests/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.stderr index 73ebbf48118da..36515c1a29bb5 100644 --- a/tests/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.stderr +++ b/tests/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.stderr @@ -2,36 +2,32 @@ error: cannot move out of value because it is borrowed --> $DIR/default-binding-modes-both-sides-independent.rs:26:9 | LL | let ref a @ b = NotCopy; - | -----^^^- - | | | - | | value is moved into `b` here + | ^^^^^ - value is moved into `b` here + | | | value is borrowed by `a` here error: cannot move out of value because it is borrowed --> $DIR/default-binding-modes-both-sides-independent.rs:29:9 | LL | let ref mut a @ b = NotCopy; - | ---------^^^- - | | | - | | value is moved into `b` here + | ^^^^^^^^^ - value is moved into `b` here + | | | value is mutably borrowed by `a` here error: cannot move out of value because it is borrowed --> $DIR/default-binding-modes-both-sides-independent.rs:34:12 | LL | Ok(ref a @ b) | Err(b @ ref a) => { - | -----^^^- - | | | - | | value is moved into `b` here + | ^^^^^ - value is moved into `b` here + | | | value is borrowed by `a` here error: borrow of moved value --> $DIR/default-binding-modes-both-sides-independent.rs:34:29 | LL | Ok(ref a @ b) | Err(b @ ref a) => { - | -^^^----- - | | | - | | value borrowed here after move + | ^ ----- value borrowed here after move + | | | value moved into `b` here | move occurs because `b` has type `NotCopy` which does not implement the `Copy` trait | @@ -44,9 +40,8 @@ error: cannot move out of value because it is borrowed --> $DIR/default-binding-modes-both-sides-independent.rs:42:9 | LL | ref a @ b => { - | -----^^^- - | | | - | | value is moved into `b` here + | ^^^^^ - value is moved into `b` here + | | | value is borrowed by `a` here error[E0382]: borrow of moved value diff --git a/tests/ui/suggestions/ref-pattern-binding.stderr b/tests/ui/suggestions/ref-pattern-binding.stderr index 7b194259349b8..69ce5d440af81 100644 --- a/tests/ui/suggestions/ref-pattern-binding.stderr +++ b/tests/ui/suggestions/ref-pattern-binding.stderr @@ -2,9 +2,8 @@ error: borrow of moved value --> $DIR/ref-pattern-binding.rs:10:9 | LL | let _moved @ ref _from = String::from("foo"); - | ------^^^--------- - | | | - | | value borrowed here after move + | ^^^^^^ --------- value borrowed here after move + | | | value moved into `_moved` here | move occurs because `_moved` has type `String` which does not implement the `Copy` trait | @@ -17,27 +16,24 @@ error: cannot move out of value because it is borrowed --> $DIR/ref-pattern-binding.rs:11:9 | LL | let ref _moved @ _from = String::from("foo"); - | ----------^^^----- - | | | - | | value is moved into `_from` here + | ^^^^^^^^^^ ----- value is moved into `_from` here + | | | value is borrowed by `_moved` here error: cannot move out of value because it is borrowed --> $DIR/ref-pattern-binding.rs:15:9 | LL | let ref _moved @ S { f } = S { f: String::from("foo") }; - | ----------^^^^^^^-^^ - | | | - | | value is moved into `f` here + | ^^^^^^^^^^ - value is moved into `f` here + | | | value is borrowed by `_moved` here error: borrow of moved value --> $DIR/ref-pattern-binding.rs:18:9 | LL | let _moved @ S { ref f } = S { f: String::from("foo") }; - | ------^^^^^^^-----^^ - | | | - | | value borrowed here after move + | ^^^^^^ ----- value borrowed here after move + | | | value moved into `_moved` here | move occurs because `_moved` has type `S` which does not implement the `Copy` trait | From 3b47cdc4398c8d7b422077372bb65e95ecc637d8 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 26 Feb 2023 21:35:54 +0000 Subject: [PATCH 03/13] Add Span to StmtKind::Let. --- compiler/rustc_middle/src/mir/mod.rs | 7 +++ compiler/rustc_middle/src/thir.rs | 56 ++++++++++++++++++- compiler/rustc_middle/src/thir/visit.rs | 1 + compiler/rustc_mir_build/src/build/block.rs | 2 + compiler/rustc_mir_build/src/thir/cx/block.rs | 5 ++ compiler/rustc_mir_build/src/thir/print.rs | 2 + 6 files changed, 71 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index de7e8bc861d2c..a3dbe931daacd 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -1984,6 +1984,13 @@ impl<'tcx> Rvalue<'tcx> { } impl BorrowKind { + pub fn mutability(&self) -> Mutability { + match *self { + BorrowKind::Shared | BorrowKind::Shallow | BorrowKind::Unique => Mutability::Not, + BorrowKind::Mut { .. } => Mutability::Mut, + } + } + pub fn allows_two_phase_borrow(&self) -> bool { match *self { BorrowKind::Shared | BorrowKind::Shallow | BorrowKind::Unique => false, diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index 82a7cf7851734..7d79a13d3fde3 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -227,6 +227,9 @@ pub enum StmtKind<'tcx> { /// The lint level for this `let` statement. lint_level: LintLevel, + + /// Span of the `let = ` part. + span: Span, }, } @@ -594,6 +597,55 @@ impl<'tcx> Pat<'tcx> { _ => None, } } + + /// Call `f` on every "binding" in a pattern, e.g., on `a` in + /// `match foo() { Some(a) => (), None => () }` + pub fn each_binding(&self, mut f: impl FnMut(Symbol, BindingMode, Ty<'tcx>, Span)) { + self.walk_always(|p| { + if let PatKind::Binding { name, mode, ty, .. } = p.kind { + f(name, mode, ty, p.span); + } + }); + } + + /// Walk the pattern in left-to-right order. + /// + /// If `it(pat)` returns `false`, the children are not visited. + pub fn walk(&self, mut it: impl FnMut(&Pat<'tcx>) -> bool) { + self.walk_(&mut it) + } + + fn walk_(&self, it: &mut impl FnMut(&Pat<'tcx>) -> bool) { + if !it(self) { + return; + } + + use PatKind::*; + match &self.kind { + Wild | Range(..) | Binding { subpattern: None, .. } | Constant { .. } => {} + AscribeUserType { subpattern, .. } + | Binding { subpattern: Some(subpattern), .. } + | Deref { subpattern } => subpattern.walk_(it), + Leaf { subpatterns } | Variant { subpatterns, .. } => { + subpatterns.iter().for_each(|field| field.pattern.walk_(it)) + } + Or { pats } => pats.iter().for_each(|p| p.walk_(it)), + Array { box ref prefix, ref slice, box ref suffix } + | Slice { box ref prefix, ref slice, box ref suffix } => { + prefix.iter().chain(slice.iter()).chain(suffix.iter()).for_each(|p| p.walk_(it)) + } + } + } + + /// Walk the pattern in left-to-right order. + /// + /// If you always want to recurse, prefer this method over `walk`. + pub fn walk_always(&self, mut it: impl FnMut(&Pat<'tcx>)) { + self.walk(|p| { + it(p); + true + }) + } } impl<'tcx> IntoDiagnosticArg for Pat<'tcx> { @@ -879,7 +931,7 @@ mod size_asserts { static_assert_size!(ExprKind<'_>, 40); static_assert_size!(Pat<'_>, 72); static_assert_size!(PatKind<'_>, 56); - static_assert_size!(Stmt<'_>, 48); - static_assert_size!(StmtKind<'_>, 40); + static_assert_size!(Stmt<'_>, 56); + static_assert_size!(StmtKind<'_>, 48); // tidy-alphabetical-end } diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs index 79a0e75aa7c78..5614528c4cb25 100644 --- a/compiler/rustc_middle/src/thir/visit.rs +++ b/compiler/rustc_middle/src/thir/visit.rs @@ -175,6 +175,7 @@ pub fn walk_stmt<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, stmt: &Stm ref pattern, lint_level: _, else_block, + span: _, } => { if let Some(init) = initializer { visitor.visit_expr(&visitor.thir()[*init]); diff --git a/compiler/rustc_mir_build/src/build/block.rs b/compiler/rustc_mir_build/src/build/block.rs index 2643d33cee00a..609ab19289c9a 100644 --- a/compiler/rustc_mir_build/src/build/block.rs +++ b/compiler/rustc_mir_build/src/build/block.rs @@ -115,6 +115,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { initializer: Some(initializer), lint_level, else_block: Some(else_block), + span: _, } => { // When lowering the statement `let = else { };`, // the `` block is nested in the parent scope enclosing this statement. @@ -278,6 +279,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { initializer, lint_level, else_block: None, + span: _, } => { let ignores_expr_result = matches!(pattern.kind, PatKind::Wild); this.block_context.push(BlockFrame::Statement { ignores_expr_result }); diff --git a/compiler/rustc_mir_build/src/thir/cx/block.rs b/compiler/rustc_mir_build/src/thir/cx/block.rs index 321353ca20bae..8aacec53f9459 100644 --- a/compiler/rustc_mir_build/src/thir/cx/block.rs +++ b/compiler/rustc_mir_build/src/thir/cx/block.rs @@ -105,6 +105,10 @@ impl<'tcx> Cx<'tcx> { } } + let span = match local.init { + Some(init) => local.span.with_hi(init.span.hi()), + None => local.span, + }; let stmt = Stmt { kind: StmtKind::Let { remainder_scope, @@ -116,6 +120,7 @@ impl<'tcx> Cx<'tcx> { initializer: local.init.map(|init| self.mirror_expr(init)), else_block, lint_level: LintLevel::Explicit(local.hir_id), + span, }, opt_destruction_scope: opt_dxn_ext, }; diff --git a/compiler/rustc_mir_build/src/thir/print.rs b/compiler/rustc_mir_build/src/thir/print.rs index 8028227aafd2a..ed61d6ee78b1d 100644 --- a/compiler/rustc_mir_build/src/thir/print.rs +++ b/compiler/rustc_mir_build/src/thir/print.rs @@ -151,6 +151,7 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> { initializer, else_block, lint_level, + span, } => { print_indented!(self, "kind: Let {", depth_lvl + 1); print_indented!( @@ -181,6 +182,7 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> { } print_indented!(self, format!("lint_level: {:?}", lint_level), depth_lvl + 2); + print_indented!(self, format!("span: {:?}", span), depth_lvl + 2); print_indented!(self, "}", depth_lvl + 1); } } From 05082f57afbf5d2e8fd7fb67719336d78b58e759 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Mon, 27 Feb 2023 17:43:39 +0000 Subject: [PATCH 04/13] Perform match checking on THIR. --- compiler/rustc_hir/src/pat_util.rs | 11 - compiler/rustc_mir_build/messages.ftl | 12 +- compiler/rustc_mir_build/src/build/mod.rs | 1 + compiler/rustc_mir_build/src/errors.rs | 23 +- .../src/thir/pattern/check_match.rs | 697 ++++++++---------- .../rustc_mir_build/src/thir/pattern/mod.rs | 25 +- tests/ui/chalkify/bugs/async.stderr | 17 +- .../const-eval/const-eval-overflow-2.rs | 1 - .../const-eval/const-eval-overflow-2.stderr | 8 +- .../const-eval/ref_to_int_match.32bit.stderr | 10 +- .../const-eval/ref_to_int_match.64bit.stderr | 10 +- .../ui/consts/const-eval/ref_to_int_match.rs | 1 - .../ui/consts/const-match-check.eval1.stderr | 4 +- .../ui/consts/const-match-check.eval2.stderr | 4 +- .../consts/const-match-check.matchck.stderr | 16 +- tests/ui/consts/const-pattern-irrefutable.rs | 9 +- .../consts/const-pattern-irrefutable.stderr | 49 +- .../const_in_pattern/incomplete-slice.stderr | 2 +- tests/ui/consts/issue-43105.rs | 1 - tests/ui/consts/issue-43105.stderr | 8 +- tests/ui/consts/issue-73976-polymorphic.rs | 2 - .../ui/consts/issue-73976-polymorphic.stderr | 16 +- tests/ui/consts/issue-78655.rs | 1 - tests/ui/consts/issue-78655.stderr | 8 +- tests/ui/consts/issue-79137-toogeneric.rs | 1 - tests/ui/consts/issue-79137-toogeneric.stderr | 8 +- ..._refers_to_static_cross_crate.32bit.stderr | 32 +- ..._refers_to_static_cross_crate.64bit.stderr | 32 +- .../const_refers_to_static_cross_crate.rs | 4 - tests/ui/error-codes/E0004.stderr | 2 +- tests/ui/error-codes/E0030-teach.rs | 1 - tests/ui/error-codes/E0030-teach.stderr | 8 +- tests/ui/error-codes/E0030.rs | 1 - tests/ui/error-codes/E0030.stderr | 8 +- ...on_exhaustive_omitted_patterns_lint.stderr | 2 +- ...-gate-precise_pointer_size_matching.stderr | 4 +- .../half-open-range-pats-thir-lower-empty.rs | 13 - ...lf-open-range-pats-thir-lower-empty.stderr | 102 +-- tests/ui/impl-trait/auto-trait-leak.stderr | 10 + .../inline-const/const-match-pat-generic.rs | 2 - .../const-match-pat-generic.stderr | 16 +- tests/ui/match/match-range-fail-2.rs | 9 +- tests/ui/match/match-range-fail-2.stderr | 24 +- .../ui/never_type/exhaustive_patterns.stderr | 4 +- .../exhaustiveness-non-exhaustive.stderr | 6 +- ...een-expanded-earlier-non-exhaustive.stderr | 6 +- tests/ui/pattern/issue-106552.stderr | 6 +- .../issue-68393-let-pat-assoc-constant.stderr | 12 +- ...e-missing-pattern-excluding-comments.fixed | 2 +- ...-missing-pattern-excluding-comments.stderr | 2 +- .../pattern/usefulness/consts-opaque.stderr | 156 ++-- .../doc-hidden-non-exhaustive.stderr | 10 +- .../empty-match.exhaustive_patterns.stderr | 16 +- .../usefulness/empty-match.normal.stderr | 16 +- tests/ui/pattern/usefulness/floats.stderr | 2 +- tests/ui/pattern/usefulness/guards.stderr | 2 +- .../integer-ranges/exhaustiveness.stderr | 4 +- .../pointer-sized-int.deny.stderr | 6 +- .../precise_pointer_matching-message.stderr | 4 +- tests/ui/pattern/usefulness/issue-2111.stderr | 2 +- .../ui/pattern/usefulness/issue-30240.stderr | 4 +- .../ui/pattern/usefulness/issue-35609.stderr | 14 +- tests/ui/pattern/usefulness/issue-3601.stderr | 2 +- .../ui/pattern/usefulness/issue-50900.stderr | 2 +- .../ui/pattern/usefulness/issue-56379.stderr | 2 +- .../match-byte-array-patterns-2.stderr | 4 +- .../usefulness/match-privately-empty.stderr | 2 +- .../usefulness/match-slice-patterns.stderr | 2 +- .../non-exhaustive-defined-here.stderr | 20 +- .../non-exhaustive-match-nested.stderr | 2 +- .../usefulness/non-exhaustive-match.stderr | 12 +- .../refutable-pattern-errors.stderr | 4 +- .../slice-patterns-exhaustiveness.stderr | 40 +- .../usefulness/stable-gated-patterns.stderr | 4 +- .../struct-like-enum-nonexhaustive.stderr | 2 +- .../usefulness/unstable-gated-patterns.stderr | 2 +- ...range-pattern-out-of-bounds-issue-68972.rs | 2 - ...e-pattern-out-of-bounds-issue-68972.stderr | 16 +- .../slice.stderr | 2 +- .../const-pat-non-exaustive-let-new-var.rs | 5 +- ...const-pat-non-exaustive-let-new-var.stderr | 15 +- 81 files changed, 650 insertions(+), 979 deletions(-) diff --git a/compiler/rustc_hir/src/pat_util.rs b/compiler/rustc_hir/src/pat_util.rs index e870aa543d0b5..838c123f83c8c 100644 --- a/compiler/rustc_hir/src/pat_util.rs +++ b/compiler/rustc_hir/src/pat_util.rs @@ -2,7 +2,6 @@ use crate::def::{CtorOf, DefKind, Res}; use crate::def_id::DefId; use crate::hir::{self, BindingAnnotation, ByRef, HirId, PatKind}; use rustc_data_structures::fx::FxHashSet; -use rustc_span::hygiene::DesugaringKind; use rustc_span::symbol::Ident; use rustc_span::Span; @@ -136,14 +135,4 @@ impl hir::Pat<'_> { }); result } - - /// If the pattern is `Some()` from a desugared for loop, returns the inner pattern - pub fn for_loop_some(&self) -> Option<&Self> { - if self.span.desugaring_kind() == Some(DesugaringKind::ForLoop) { - if let hir::PatKind::Struct(_, [pat_field], _) = self.kind { - return Some(pat_field.pat); - } - } - None - } } diff --git a/compiler/rustc_mir_build/messages.ftl b/compiler/rustc_mir_build/messages.ftl index fcc7cbe0715f5..c8172219267ff 100644 --- a/compiler/rustc_mir_build/messages.ftl +++ b/compiler/rustc_mir_build/messages.ftl @@ -239,19 +239,9 @@ mir_build_trailing_irrefutable_let_patterns = trailing irrefutable {$count -> } into the body mir_build_bindings_with_variant_name = - pattern binding `{$ident}` is named the same as one of the variants of the type `{$ty_path}` + pattern binding `{$name}` is named the same as one of the variants of the type `{$ty_path}` .suggestion = to match on the variant, qualify the path -mir_build_irrefutable_let_patterns_generic_let = irrefutable `let` {$count -> - [one] pattern - *[other] patterns - } - .note = {$count -> - [one] this pattern - *[other] these patterns - } will always match, so the `let` is useless - .help = consider removing `let` - mir_build_irrefutable_let_patterns_if_let = irrefutable `if let` {$count -> [one] pattern *[other] patterns diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index e87e38fd04caf..6303f80ea5b07 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -58,6 +58,7 @@ fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam) -> Body<'_ ty::WithOptConstParam { did, const_param_did: None } => { tcx.ensure_with_value().thir_check_unsafety(did); tcx.ensure_with_value().thir_abstract_const(did); + tcx.ensure_with_value().check_match(did); } } diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs index cbfca77bd25d3..c67a002dce1db 100644 --- a/compiler/rustc_mir_build/src/errors.rs +++ b/compiler/rustc_mir_build/src/errors.rs @@ -10,7 +10,8 @@ use rustc_hir::def::Res; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; use rustc_middle::thir::Pat; use rustc_middle::ty::{self, Ty}; -use rustc_span::{symbol::Ident, Span}; +use rustc_span::symbol::Symbol; +use rustc_span::Span; #[derive(LintDiagnostic)] #[diag(mir_build_unconditional_recursion)] @@ -534,18 +535,10 @@ pub struct TrailingIrrefutableLetPatterns { #[derive(LintDiagnostic)] #[diag(mir_build_bindings_with_variant_name, code = "E0170")] pub struct BindingsWithVariantName { - #[suggestion(code = "{ty_path}::{ident}", applicability = "machine-applicable")] + #[suggestion(code = "{ty_path}::{name}", applicability = "machine-applicable")] pub suggestion: Option, pub ty_path: String, - pub ident: Ident, -} - -#[derive(LintDiagnostic)] -#[diag(mir_build_irrefutable_let_patterns_generic_let)] -#[note] -#[help] -pub struct IrrefutableLetPatternsGenericLet { - pub count: usize, + pub name: Symbol, } #[derive(LintDiagnostic)] @@ -590,7 +583,7 @@ pub struct BorrowOfMovedValue<'tcx> { pub binding_span: Span, #[label(mir_build_value_borrowed_label)] pub conflicts_ref: Vec, - pub name: Ident, + pub name: Symbol, pub ty: Ty<'tcx>, #[suggestion(code = "ref ", applicability = "machine-applicable")] pub suggest_borrowing: Option, @@ -638,19 +631,19 @@ pub enum Conflict { Mut { #[primary_span] span: Span, - name: Ident, + name: Symbol, }, #[label(mir_build_borrow)] Ref { #[primary_span] span: Span, - name: Ident, + name: Symbol, }, #[label(mir_build_moved)] Moved { #[primary_span] span: Span, - name: Ident, + name: Symbol, }, } diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index 2fee1721f994b..b1f85f039893d 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -2,41 +2,48 @@ use super::deconstruct_pat::{Constructor, DeconstructedPat}; use super::usefulness::{ compute_match_usefulness, MatchArm, MatchCheckCtxt, Reachability, UsefulnessReport, }; -use super::{PatCtxt, PatternError}; use crate::errors::*; -use hir::{ExprKind, PatKind}; use rustc_arena::TypedArena; -use rustc_ast::{LitKind, Mutability}; +use rustc_ast::Mutability; +use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::{ struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan, }; use rustc_hir as hir; use rustc_hir::def::*; use rustc_hir::def_id::LocalDefId; -use rustc_hir::intravisit::{self, Visitor}; -use rustc_hir::{HirId, Pat}; +use rustc_hir::HirId; +use rustc_middle::thir::visit::{self, Visitor}; +use rustc_middle::thir::*; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt}; - use rustc_session::lint::builtin::{ BINDINGS_WITH_VARIANT_NAME, IRREFUTABLE_LET_PATTERNS, UNREACHABLE_PATTERNS, }; use rustc_session::Session; -use rustc_span::source_map::Spanned; -use rustc_span::{BytePos, Span}; +use rustc_span::hygiene::DesugaringKind; +use rustc_span::Span; pub(crate) fn check_match(tcx: TyCtxt<'_>, def_id: LocalDefId) { - let body_id = tcx.hir().body_owned_by(def_id); + let Ok((thir, expr)) = tcx.thir_body(ty::WithOptConstParam::unknown(def_id)) else { return }; + let thir = thir.borrow(); let pattern_arena = TypedArena::default(); let mut visitor = MatchVisitor { tcx, - typeck_results: tcx.typeck_body(body_id), + thir: &*thir, param_env: tcx.param_env(def_id), + lint_level: tcx.hir().local_def_id_to_hir_id(def_id), + let_source: LetSource::None, pattern_arena: &pattern_arena, }; - visitor.visit_body(tcx.hir().body(body_id)); + visitor.visit_expr(&thir[expr]); + for param in thir.params.iter() { + if let Some(box ref pattern) = param.pat { + visitor.check_irrefutable(pattern, "function argument", None); + } + } } fn create_e0004( @@ -54,77 +61,132 @@ enum RefutableFlag { } use RefutableFlag::*; +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +enum LetSource { + None, + IfLet, + IfLetGuard, + LetElse, + WhileLet, +} + struct MatchVisitor<'a, 'p, 'tcx> { tcx: TyCtxt<'tcx>, - typeck_results: &'a ty::TypeckResults<'tcx>, param_env: ty::ParamEnv<'tcx>, + thir: &'a Thir<'tcx>, + lint_level: HirId, + let_source: LetSource, pattern_arena: &'p TypedArena>, } -impl<'tcx> Visitor<'tcx> for MatchVisitor<'_, '_, 'tcx> { - fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) { - intravisit::walk_expr(self, ex); - match &ex.kind { - hir::ExprKind::Match(scrut, arms, source) => { - self.check_match(scrut, arms, *source, ex.span) +impl<'a, 'tcx> Visitor<'a, 'tcx> for MatchVisitor<'a, '_, 'tcx> { + fn thir(&self) -> &'a Thir<'tcx> { + self.thir + } + + #[instrument(level = "trace", skip(self))] + fn visit_arm(&mut self, arm: &Arm<'tcx>) { + match arm.guard { + Some(Guard::If(expr)) => { + self.with_let_source(LetSource::IfLetGuard, |this| { + this.visit_expr(&this.thir[expr]) + }); } - hir::ExprKind::Let(hir::Let { pat, init, span, .. }) => { - self.check_let(pat, init, *span) + Some(Guard::IfLet(ref pat, expr)) => { + self.with_let_source(LetSource::IfLetGuard, |this| { + this.check_let(pat, expr, LetSource::IfLetGuard, pat.span); + this.visit_pat(pat); + this.visit_expr(&this.thir[expr]); + }); } - _ => {} + None => {} } + self.visit_pat(&arm.pattern); + self.visit_expr(&self.thir[arm.body]); } - fn visit_local(&mut self, loc: &'tcx hir::Local<'tcx>) { - intravisit::walk_local(self, loc); - let els = loc.els; - if let Some(init) = loc.init && els.is_some() { - // Build a span without the else { ... } as we don't want to underline - // the entire else block in the IDE setting. - let span = loc.span.with_hi(init.span.hi()); - self.check_let(&loc.pat, init, span); - } - - let (msg, sp) = match loc.source { - hir::LocalSource::Normal => ("local binding", Some(loc.span)), - hir::LocalSource::AsyncFn => ("async fn binding", None), - hir::LocalSource::AwaitDesugar => ("`await` future binding", None), - hir::LocalSource::AssignDesugar(_) => ("destructuring assignment binding", None), + #[instrument(level = "trace", skip(self))] + fn visit_expr(&mut self, ex: &Expr<'tcx>) { + match ex.kind { + ExprKind::Scope { value, lint_level, .. } => { + let old_lint_level = self.lint_level; + if let LintLevel::Explicit(hir_id) = lint_level { + self.lint_level = hir_id; + } + self.visit_expr(&self.thir[value]); + self.lint_level = old_lint_level; + return; + } + ExprKind::If { cond, then, else_opt, if_then_scope: _ } => { + // Give a specific `let_source` for the condition. + let let_source = match ex.span.desugaring_kind() { + Some(DesugaringKind::WhileLoop) => LetSource::WhileLet, + _ => LetSource::IfLet, + }; + self.with_let_source(let_source, |this| this.visit_expr(&self.thir[cond])); + self.with_let_source(LetSource::None, |this| { + this.visit_expr(&this.thir[then]); + if let Some(else_) = else_opt { + this.visit_expr(&this.thir[else_]); + } + }); + return; + } + ExprKind::Match { scrutinee, box ref arms } => { + let source = match ex.span.desugaring_kind() { + Some(DesugaringKind::ForLoop) => hir::MatchSource::ForLoopDesugar, + Some(DesugaringKind::QuestionMark) => hir::MatchSource::TryDesugar, + Some(DesugaringKind::Await) => hir::MatchSource::AwaitDesugar, + _ => hir::MatchSource::Normal, + }; + self.check_match(scrutinee, arms, source, ex.span); + } + ExprKind::Let { box ref pat, expr } => { + self.check_let(pat, expr, self.let_source, ex.span); + } + ExprKind::LogicalOp { op: LogicalOp::And, .. } => { + self.check_let_chain(ex, self.let_source); + } + _ => {} }; - if els.is_none() { - self.check_irrefutable(&loc.pat, msg, sp); - } - } - - fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) { - intravisit::walk_param(self, param); - self.check_irrefutable(¶m.pat, "function argument", None); + self.with_let_source(LetSource::None, |this| visit::walk_expr(this, ex)); } -} -impl PatCtxt<'_, '_> { - fn report_inlining_errors(&self) { - for error in &self.errors { - match *error { - PatternError::StaticInPattern(span) => { - self.tcx.sess.emit_err(StaticInPattern { span }); + fn visit_stmt(&mut self, stmt: &Stmt<'tcx>) { + let old_lint_level = self.lint_level; + match stmt.kind { + StmtKind::Let { + box ref pattern, initializer, else_block, lint_level, span, .. + } => { + if let LintLevel::Explicit(lint_level) = lint_level { + self.lint_level = lint_level; } - PatternError::AssocConstInPattern(span) => { - self.tcx.sess.emit_err(AssocConstInPattern { span }); - } - PatternError::ConstParamInPattern(span) => { - self.tcx.sess.emit_err(ConstParamInPattern { span }); + + if let Some(initializer) = initializer && else_block.is_some() { + self.check_let(pattern, initializer, LetSource::LetElse, span); } - PatternError::NonConstPath(span) => { - self.tcx.sess.emit_err(NonConstPath { span }); + + if else_block.is_none() { + self.check_irrefutable(pattern, "local binding", Some(span)); } } + _ => {} } + visit::walk_stmt(self, stmt); + self.lint_level = old_lint_level; } } impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { - fn check_patterns(&self, pat: &Pat<'_>, rf: RefutableFlag) { + #[instrument(level = "trace", skip(self, f))] + fn with_let_source(&mut self, let_source: LetSource, f: impl FnOnce(&mut Self)) { + let old_let_source = self.let_source; + self.let_source = let_source; + ensure_sufficient_stack(|| f(self)); + self.let_source = old_let_source; + } + + fn check_patterns(&self, pat: &Pat<'tcx>, rf: RefutableFlag) { pat.walk_always(|pat| check_borrow_conflicts_in_at_patterns(self, pat)); check_for_bindings_named_same_as_variants(self, pat, rf); } @@ -132,18 +194,9 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { fn lower_pattern( &self, cx: &mut MatchCheckCtxt<'p, 'tcx>, - pat: &'tcx hir::Pat<'tcx>, - have_errors: &mut bool, + pattern: &Pat<'tcx>, ) -> &'p DeconstructedPat<'p, 'tcx> { - let mut patcx = PatCtxt::new(self.tcx, self.param_env, self.typeck_results); - patcx.include_lint_checks(); - let pattern = patcx.lower_pattern(pat); - let pattern: &_ = cx.pattern_arena.alloc(DeconstructedPat::from_pat(cx, &pattern)); - if !patcx.errors.is_empty() { - *have_errors = true; - patcx.report_inlining_errors(); - } - pattern + cx.pattern_arena.alloc(DeconstructedPat::from_pat(cx, &pattern)) } fn new_cx(&self, hir_id: HirId) -> MatchCheckCtxt<'p, 'tcx> { @@ -155,50 +208,48 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { } } - fn check_let(&mut self, pat: &'tcx hir::Pat<'tcx>, scrutinee: &hir::Expr<'_>, span: Span) { + #[instrument(level = "trace", skip(self))] + fn check_let(&mut self, pat: &Pat<'tcx>, scrutinee: ExprId, source: LetSource, span: Span) { + if let LetSource::None = source { + return; + } self.check_patterns(pat, Refutable); - let mut cx = self.new_cx(scrutinee.hir_id); - let tpat = self.lower_pattern(&mut cx, pat, &mut false); - self.check_let_reachability(&mut cx, pat.hir_id, tpat, span); + let mut cx = self.new_cx(self.lint_level); + let tpat = self.lower_pattern(&mut cx, pat); + self.check_let_reachability(&mut cx, self.lint_level, source, tpat, span); } fn check_match( &mut self, - scrut: &hir::Expr<'_>, - hir_arms: &'tcx [hir::Arm<'tcx>], + scrut: ExprId, + arms: &[ArmId], source: hir::MatchSource, expr_span: Span, ) { - let mut cx = self.new_cx(scrut.hir_id); + let mut cx = self.new_cx(self.lint_level); - for arm in hir_arms { + for &arm in arms { // Check the arm for some things unrelated to exhaustiveness. - self.check_patterns(&arm.pat, Refutable); - if let Some(hir::Guard::IfLet(ref let_expr)) = arm.guard { - self.check_patterns(let_expr.pat, Refutable); - let tpat = self.lower_pattern(&mut cx, let_expr.pat, &mut false); - self.check_let_reachability(&mut cx, let_expr.pat.hir_id, tpat, tpat.span()); - } + let arm = &self.thir.arms[arm]; + self.check_patterns(&arm.pattern, Refutable); } - let mut have_errors = false; - - let arms: Vec<_> = hir_arms + let tarms: Vec<_> = arms .iter() - .map(|hir::Arm { pat, guard, .. }| MatchArm { - pat: self.lower_pattern(&mut cx, pat, &mut have_errors), - hir_id: pat.hir_id, - has_guard: guard.is_some(), + .map(|&arm| { + let arm = &self.thir.arms[arm]; + let hir_id = match arm.lint_level { + LintLevel::Explicit(hir_id) => hir_id, + LintLevel::Inherited => self.lint_level, + }; + let pat = self.lower_pattern(&mut cx, &arm.pattern); + MatchArm { pat, hir_id, has_guard: arm.guard.is_some() } }) .collect(); - // Bail out early if lowering failed. - if have_errors { - return; - } - - let scrut_ty = self.typeck_results.expr_ty_adjusted(scrut); - let report = compute_match_usefulness(&cx, &arms, scrut.hir_id, scrut_ty); + let scrut = &self.thir[scrut]; + let scrut_ty = scrut.ty; + let report = compute_match_usefulness(&cx, &tarms, self.lint_level, scrut_ty); match source { // Don't report arm reachability of desugared `match $iter.into_iter() { iter => .. }` @@ -215,12 +266,18 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { // Check if the match is exhaustive. let witnesses = report.non_exhaustiveness_witnesses; if !witnesses.is_empty() { - if source == hir::MatchSource::ForLoopDesugar && hir_arms.len() == 2 { + if source == hir::MatchSource::ForLoopDesugar && arms.len() == 2 { // the for loop pattern is not irrefutable - let pat = hir_arms[1].pat.for_loop_some().unwrap(); - self.check_irrefutable(pat, "`for` loop binding", None); + let pat = &self.thir[arms[1]].pattern; + // `pat` should be `Some()` from a desugared for loop. + debug_assert_eq!(pat.span.desugaring_kind(), Some(DesugaringKind::ForLoop)); + let PatKind::Variant { ref subpatterns, .. } = pat.kind else { bug!() }; + let [pat_field] = &subpatterns[..] else { bug!() }; + self.check_irrefutable(&pat_field.pattern, "`for` loop binding", None); } else { - non_exhaustive_match(&cx, scrut_ty, scrut.span, witnesses, hir_arms, expr_span); + non_exhaustive_match( + &cx, self.thir, scrut_ty, scrut.span, witnesses, arms, expr_span, + ); } } } @@ -229,114 +286,92 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { &mut self, cx: &mut MatchCheckCtxt<'p, 'tcx>, pat_id: HirId, + source: LetSource, pat: &'p DeconstructedPat<'p, 'tcx>, span: Span, ) { - if self.check_let_chain(cx, pat_id) { - return; - } - if is_let_irrefutable(cx, pat_id, pat) { - irrefutable_let_pattern(cx.tcx, pat_id, span); + irrefutable_let_patterns(cx.tcx, pat_id, source, 1, span); } } - fn check_let_chain(&mut self, cx: &mut MatchCheckCtxt<'p, 'tcx>, pat_id: HirId) -> bool { - let hir = self.tcx.hir(); - let parent = hir.parent_id(pat_id); + #[instrument(level = "trace", skip(self))] + fn check_let_chain(&mut self, top_expr: &Expr<'tcx>, let_source: LetSource) { + if let LetSource::None = let_source { + return; + } - // First, figure out if the given pattern is part of a let chain, - // and if so, obtain the top node of the chain. - let mut top = parent; - let mut part_of_chain = false; - loop { - let new_top = hir.parent_id(top); - if let hir::Node::Expr( - hir::Expr { - kind: hir::ExprKind::Binary(Spanned { node: hir::BinOpKind::And, .. }, lhs, rhs), - .. - }, - .., - ) = hir.get(new_top) - { - // If this isn't the first iteration, we need to check - // if there is a let expr before us in the chain, so - // that we avoid doubly checking the let chain. - - // The way a chain of &&s is encoded is ((let ... && let ...) && let ...) && let ... - // as && is left-to-right associative. Thus, we need to check rhs. - if part_of_chain && matches!(rhs.kind, hir::ExprKind::Let(..)) { - return true; - } - // If there is a let at the lhs, and we provide the rhs, we don't do any checking either. - if !part_of_chain && matches!(lhs.kind, hir::ExprKind::Let(..)) && rhs.hir_id == top - { - return true; - } - } else { - // We've reached the top. - break; - } + let ExprKind::LogicalOp { op: LogicalOp::And, mut lhs, rhs } = top_expr.kind else { bug!() }; - // Since this function is called within a let context, it is reasonable to assume that any parent - // `&&` infers a let chain - part_of_chain = true; - top = new_top; - } - if !part_of_chain { - return false; - } + // Lint level enclosing the next `lhs`. + let mut cur_lint_level = self.lint_level; - // Second, obtain the refutabilities of all exprs in the chain, + // Obtain the refutabilities of all exprs in the chain, // and record chain members that aren't let exprs. let mut chain_refutabilities = Vec::new(); - let hir::Node::Expr(top_expr) = hir.get(top) else { - // We ensure right above that it's an Expr - unreachable!() + + let add = |expr: ExprId, mut local_lint_level| { + // `local_lint_level` is the lint level enclosing the pattern inside `expr`. + let mut expr = &self.thir[expr]; + debug!(?expr, ?local_lint_level, "add"); + // Fast-forward through scopes. + while let ExprKind::Scope { value, lint_level, .. } = expr.kind { + if let LintLevel::Explicit(hir_id) = lint_level { + local_lint_level = hir_id + } + expr = &self.thir[value]; + } + debug!(?expr, ?local_lint_level, "after scopes"); + match expr.kind { + ExprKind::Let { box ref pat, expr: _ } => { + let mut ncx = self.new_cx(local_lint_level); + let tpat = self.lower_pattern(&mut ncx, pat); + let refutable = !is_let_irrefutable(&mut ncx, local_lint_level, tpat); + Some((expr.span, refutable)) + } + ExprKind::LogicalOp { op: LogicalOp::And, .. } => { + bug!() + } + _ => None, + } }; - let mut cur_expr = top_expr; + + // Let chains recurse on the left, so we start by adding the rightmost. + chain_refutabilities.push(add(rhs, cur_lint_level)); + loop { - let mut add = |expr: &hir::Expr<'tcx>| { - let refutability = match expr.kind { - hir::ExprKind::Let(hir::Let { pat, init, span, .. }) => { - let mut ncx = self.new_cx(init.hir_id); - let tpat = self.lower_pattern(&mut ncx, pat, &mut false); - - let refutable = !is_let_irrefutable(&mut ncx, pat.hir_id, tpat); - Some((*span, refutable)) - } - _ => None, - }; - chain_refutabilities.push(refutability); - }; - if let hir::Expr { - kind: hir::ExprKind::Binary(Spanned { node: hir::BinOpKind::And, .. }, lhs, rhs), - .. - } = cur_expr + while let ExprKind::Scope { value, lint_level, .. } = self.thir[lhs].kind { + if let LintLevel::Explicit(hir_id) = lint_level { + cur_lint_level = hir_id + } + lhs = value; + } + if let ExprKind::LogicalOp { op: LogicalOp::And, lhs: new_lhs, rhs: expr } = + self.thir[lhs].kind { - add(rhs); - cur_expr = lhs; + chain_refutabilities.push(add(expr, cur_lint_level)); + lhs = new_lhs; } else { - add(cur_expr); + chain_refutabilities.push(add(lhs, cur_lint_level)); break; } } + debug!(?chain_refutabilities); chain_refutabilities.reverse(); // Third, emit the actual warnings. - if chain_refutabilities.iter().all(|r| matches!(*r, Some((_, false)))) { // The entire chain is made up of irrefutable `let` statements - let let_source = let_source_parent(self.tcx, top, None); irrefutable_let_patterns( - cx.tcx, - top, + self.tcx, + self.lint_level, let_source, chain_refutabilities.len(), top_expr.span, ); - return true; + return; } + if let Some(until) = chain_refutabilities.iter().position(|r| !matches!(*r, Some((_, false)))) && until > 0 { // The chain has a non-zero prefix of irrefutable `let` statements. @@ -346,7 +381,6 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { // so can't always be moved out. // FIXME: Add checking whether the bindings are actually used in the prefix, // and lint if they are not. - let let_source = let_source_parent(self.tcx, top, None); if !matches!(let_source, LetSource::WhileLet | LetSource::IfLetGuard) { // Emit the lint let prefix = &chain_refutabilities[..until]; @@ -354,9 +388,10 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { let span_end = prefix.last().unwrap().unwrap().0; let span = span_start.to(span_end); let count = prefix.len(); - cx.tcx.emit_spanned_lint(IRREFUTABLE_LET_PATTERNS, top, span, LeadingIrrefutableLetPatterns { count }); + self.tcx.emit_spanned_lint(IRREFUTABLE_LET_PATTERNS, self.lint_level, span, LeadingIrrefutableLetPatterns { count }); } } + if let Some(from) = chain_refutabilities.iter().rposition(|r| !matches!(*r, Some((_, false)))) && from != (chain_refutabilities.len() - 1) { // The chain has a non-empty suffix of irrefutable `let` statements let suffix = &chain_refutabilities[from + 1..]; @@ -364,18 +399,18 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { let span_end = suffix.last().unwrap().unwrap().0; let span = span_start.to(span_end); let count = suffix.len(); - cx.tcx.emit_spanned_lint(IRREFUTABLE_LET_PATTERNS, top, span, TrailingIrrefutableLetPatterns { count }); + self.tcx.emit_spanned_lint(IRREFUTABLE_LET_PATTERNS, self.lint_level, span, TrailingIrrefutableLetPatterns { count }); } - true } - fn check_irrefutable(&self, pat: &'tcx Pat<'tcx>, origin: &str, sp: Option) { - let mut cx = self.new_cx(pat.hir_id); + #[instrument(level = "trace", skip(self))] + fn check_irrefutable(&self, pat: &Pat<'tcx>, origin: &str, sp: Option) { + let mut cx = self.new_cx(self.lint_level); - let pattern = self.lower_pattern(&mut cx, pat, &mut false); + let pattern = self.lower_pattern(&mut cx, pat); let pattern_ty = pattern.ty(); - let arm = MatchArm { pat: pattern, hir_id: pat.hir_id, has_guard: false }; - let report = compute_match_usefulness(&cx, &[arm], pat.hir_id, pattern_ty); + let arm = MatchArm { pat: pattern, hir_id: self.lint_level, has_guard: false }; + let report = compute_match_usefulness(&cx, &[arm], self.lint_level, pattern_ty); // Note: we ignore whether the pattern is unreachable (i.e. whether the type is empty). We // only care about exhaustiveness here. @@ -386,58 +421,36 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { return; } - let (inform, interpreted_as_const, res_defined_here,let_suggestion, misc_suggestion) = - if let hir::PatKind::Path(hir::QPath::Resolved( - None, - hir::Path { - segments: &[hir::PathSegment { args: None, res, ident, .. }], - .. - }, - )) = &pat.kind + let inform = sp.is_some().then_some(Inform); + let mut let_suggestion = None; + let mut misc_suggestion = None; + if let Some(span) = sp && self.tcx.sess.source_map().is_span_accessible(span) { + let mut bindings= vec![]; + pat.each_binding(|name, _, _, _| { + bindings.push(name); + }); + let semi_span = span.shrink_to_hi(); + let start_span = span.shrink_to_lo(); + let end_span = semi_span.shrink_to_lo(); + let count = witnesses.len(); + + // If the pattern to match is an integer literal: + if bindings.is_empty() + && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(pat.span) + && snippet.chars().all(|c| c.is_digit(10)) { - ( - None, - Some(InterpretedAsConst { - span: pat.span, - article: res.article(), - variable: ident.to_string().to_lowercase(), - res, - }), - try { - ResDefinedHere { - def_span: cx.tcx.hir().res_span(res)?, - res, - } - }, - None, - None, - ) - } else if let Some(span) = sp && self.tcx.sess.source_map().is_span_accessible(span) { - let mut bindings = vec![]; - pat.walk_always(&mut |pat: &hir::Pat<'_>| { - if let hir::PatKind::Binding(_, _, ident, _) = pat.kind { - bindings.push(ident); - } + // Then give a suggestion, the user might've meant to create a binding instead. + misc_suggestion = Some(MiscPatternSuggestion::AttemptedIntegerLiteral { + start_span: pat.span.shrink_to_lo() }); - let semi_span = span.shrink_to_hi().with_lo(span.hi() - BytePos(1)); - let start_span = span.shrink_to_lo(); - let end_span = semi_span.shrink_to_lo(); - let count = witnesses.len(); - - // If the pattern to match is an integer literal: - let int_suggestion = if - let PatKind::Lit(expr) = &pat.kind - && bindings.is_empty() - && let ExprKind::Lit(Spanned { node: LitKind::Int(_, _), span }) = expr.kind { - // Then give a suggestion, the user might've meant to create a binding instead. - Some(MiscPatternSuggestion::AttemptedIntegerLiteral { start_span: span.shrink_to_lo() }) - } else { None }; - - let let_suggestion = if bindings.is_empty() {SuggestLet::If{start_span, semi_span, count}} else{ SuggestLet::Else{end_span, count }}; - (sp.map(|_|Inform), None, None, Some(let_suggestion), int_suggestion) - } else{ - (sp.map(|_|Inform), None, None, None, None) - }; + } + + let_suggestion = Some(if bindings.is_empty() { + SuggestLet::If {start_span, semi_span, count } + } else { + SuggestLet::Else { end_span, count } + }); + }; let adt_defined_here = try { let ty = pattern_ty.peel_refs(); @@ -456,12 +469,12 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { origin, uncovered: Uncovered::new(pat.span, &cx, witnesses), inform, - interpreted_as_const, + interpreted_as_const: None, _p: (), pattern_ty, let_suggestion, misc_suggestion, - res_defined_here, + res_defined_here: None, adt_defined_here, }); } @@ -473,14 +486,18 @@ fn check_for_bindings_named_same_as_variants( rf: RefutableFlag, ) { pat.walk_always(|p| { - if let hir::PatKind::Binding(_, _, ident, None) = p.kind - && let Some(ty::BindByValue(hir::Mutability::Not)) = - cx.typeck_results.extract_binding_mode(cx.tcx.sess, p.hir_id, p.span) - && let pat_ty = cx.typeck_results.pat_ty(p).peel_refs() - && let ty::Adt(edef, _) = pat_ty.kind() + if let PatKind::Binding { + name, + mode: BindingMode::ByValue, + mutability: Mutability::Not, + subpattern: None, + ty, + .. + } = p.kind + && let ty::Adt(edef, _) = ty.peel_refs().kind() && edef.is_enum() && edef.variants().iter().any(|variant| { - variant.ident(cx.tcx) == ident && variant.ctor_kind() == Some(CtorKind::Const) + variant.name == name && variant.ctor_kind() == Some(CtorKind::Const) }) { let variant_count = edef.variants().len(); @@ -489,7 +506,7 @@ fn check_for_bindings_named_same_as_variants( }); cx.tcx.emit_spanned_lint( BINDINGS_WITH_VARIANT_NAME, - p.hir_id, + cx.lint_level, p.span, BindingsWithVariantName { // If this is an irrefutable pattern, and there's > 1 variant, @@ -499,7 +516,7 @@ fn check_for_bindings_named_same_as_variants( Some(p.span) } else { None }, ty_path, - ident, + name, }, ) } @@ -525,11 +542,6 @@ fn unreachable_pattern(tcx: TyCtxt<'_>, span: Span, id: HirId, catchall: Option< ); } -fn irrefutable_let_pattern(tcx: TyCtxt<'_>, id: HirId, span: Span) { - let source = let_source(tcx, id); - irrefutable_let_patterns(tcx, id, source, 1, span); -} - fn irrefutable_let_patterns( tcx: TyCtxt<'_>, id: HirId, @@ -544,7 +556,7 @@ fn irrefutable_let_patterns( } match source { - LetSource::GenericLet => emit_diag!(IrrefutableLetPatternsGenericLet), + LetSource::None => bug!(), LetSource::IfLet => emit_diag!(IrrefutableLetPatternsIfLet), LetSource::IfLetGuard => emit_diag!(IrrefutableLetPatternsIfLetGuard), LetSource::LetElse => emit_diag!(IrrefutableLetPatternsLetElse), @@ -600,10 +612,11 @@ fn report_arm_reachability<'p, 'tcx>( /// Report that a match is not exhaustive. fn non_exhaustive_match<'p, 'tcx>( cx: &MatchCheckCtxt<'p, 'tcx>, + thir: &Thir<'tcx>, scrut_ty: Ty<'tcx>, sp: Span, witnesses: Vec>, - arms: &[hir::Arm<'tcx>], + arms: &[ArmId], expr_span: Span, ) { let is_empty_match = arms.is_empty(); @@ -701,6 +714,7 @@ fn non_exhaustive_match<'p, 'tcx>( )); } [only] => { + let only = &thir[*only]; let (pre_indentation, is_multiline) = if let Some(snippet) = sm.indentation_before(only.span) && let Ok(with_trailing) = sm.span_extend_while(only.span, |c| c.is_whitespace() || c == ',') && sm.is_multiline(with_trailing) @@ -709,8 +723,9 @@ fn non_exhaustive_match<'p, 'tcx>( } else { (" ".to_string(), false) }; - let comma = if matches!(only.body.kind, hir::ExprKind::Block(..)) - && only.span.eq_ctxt(only.body.span) + let only_body = &thir[only.body]; + let comma = if matches!(only_body.kind, ExprKind::Block { .. }) + && only.span.eq_ctxt(only_body.span) && is_multiline { "" @@ -722,24 +737,29 @@ fn non_exhaustive_match<'p, 'tcx>( format!("{}{}{} => todo!()", comma, pre_indentation, pattern), )); } - [.., prev, last] if prev.span.eq_ctxt(last.span) => { - let comma = if matches!(last.body.kind, hir::ExprKind::Block(..)) - && last.span.eq_ctxt(last.body.span) - { - "" - } else { - "," - }; - let spacing = if sm.is_multiline(prev.span.between(last.span)) { - sm.indentation_before(last.span).map(|indent| format!("\n{indent}")) - } else { - Some(" ".to_string()) - }; - if let Some(spacing) = spacing { - suggestion = Some(( - last.span.shrink_to_hi(), - format!("{}{}{} => todo!()", comma, spacing, pattern), - )); + [.., prev, last] => { + let prev = &thir[*prev]; + let last = &thir[*last]; + if prev.span.eq_ctxt(last.span) { + let last_body = &thir[last.body]; + let comma = if matches!(last_body.kind, ExprKind::Block { .. }) + && last.span.eq_ctxt(last_body.span) + { + "" + } else { + "," + }; + let spacing = if sm.is_multiline(prev.span.between(last.span)) { + sm.indentation_before(last.span).map(|indent| format!("\n{indent}")) + } else { + Some(" ".to_string()) + }; + if let Some(spacing) = spacing { + suggestion = Some(( + last.span.shrink_to_hi(), + format!("{}{}{} => todo!()", comma, spacing, pattern), + )); + } } } _ => {} @@ -859,10 +879,6 @@ fn maybe_point_at_variant<'a, 'p: 'a, 'tcx: 'a>( } /// Check if a by-value binding is by-value. That is, check if the binding's type is not `Copy`. -fn is_binding_by_move(cx: &MatchVisitor<'_, '_, '_>, hir_id: HirId) -> bool { - !cx.typeck_results.node_type(hir_id).is_copy_modulo_regions(cx.tcx, cx.param_env) -} - /// Check that there are no borrow or move conflicts in `binding @ subpat` patterns. /// /// For example, this would reject: @@ -873,43 +889,31 @@ fn is_binding_by_move(cx: &MatchVisitor<'_, '_, '_>, hir_id: HirId) -> bool { /// - `x @ Some(ref mut? y)`. /// /// This analysis is *not* subsumed by NLL. -fn check_borrow_conflicts_in_at_patterns(cx: &MatchVisitor<'_, '_, '_>, pat: &Pat<'_>) { +fn check_borrow_conflicts_in_at_patterns<'tcx>(cx: &MatchVisitor<'_, '_, 'tcx>, pat: &Pat<'tcx>) { // Extract `sub` in `binding @ sub`. - let (name, sub) = match &pat.kind { - hir::PatKind::Binding(.., name, Some(sub)) => (*name, sub), - _ => return, - }; - let mk_span = |pat_span, ident_span: Span| { - if let Some(ident_span) = ident_span.find_ancestor_inside(pat_span) { - pat_span.with_hi(ident_span.hi()) - } else { - pat_span - } - }; - let binding_span = mk_span(pat.span, name.span); + let PatKind::Binding { name, mode, ty, subpattern: Some(box ref sub), .. } = pat.kind else { return }; + let binding_span = pat.span; //.with_hi(name.span.hi()); + + let is_binding_by_move = |ty: Ty<'tcx>| !ty.is_copy_modulo_regions(cx.tcx, cx.param_env); - let typeck_results = cx.typeck_results; let sess = cx.tcx.sess; // Get the binding move, extract the mutability if by-ref. - let mut_outer = match typeck_results.extract_binding_mode(sess, pat.hir_id, binding_span) { - Some(ty::BindByValue(_)) if is_binding_by_move(cx, pat.hir_id) => { + let mut_outer = match mode { + BindingMode::ByValue if is_binding_by_move(ty) => { // We have `x @ pat` where `x` is by-move. Reject all borrows in `pat`. let mut conflicts_ref = Vec::new(); - sub.each_binding(|_, hir_id, span, ident| { - let span = mk_span(span, ident.span); - match typeck_results.extract_binding_mode(sess, hir_id, span) { - Some(ty::BindByValue(_)) | None => {} - Some(ty::BindByReference(_)) => conflicts_ref.push(span), - } + sub.each_binding(|_, mode, _, span| match mode { + BindingMode::ByValue => {} + BindingMode::ByRef(_) => conflicts_ref.push(span), }); if !conflicts_ref.is_empty() { sess.emit_err(BorrowOfMovedValue { - span: binding_span, + span: pat.span, binding_span, conflicts_ref, name, - ty: typeck_results.node_type(pat.hir_id), + ty, suggest_borrowing: pat .span .contains(binding_span) @@ -918,8 +922,8 @@ fn check_borrow_conflicts_in_at_patterns(cx: &MatchVisitor<'_, '_, '_>, pat: &Pa } return; } - Some(ty::BindByValue(_)) | None => return, - Some(ty::BindByReference(m)) => m, + BindingMode::ByValue => return, + BindingMode::ByRef(m) => m.mutability(), }; // We now have `ref $mut_outer binding @ sub` (semantically). @@ -927,10 +931,9 @@ fn check_borrow_conflicts_in_at_patterns(cx: &MatchVisitor<'_, '_, '_>, pat: &Pa let mut conflicts_move = Vec::new(); let mut conflicts_mut_mut = Vec::new(); let mut conflicts_mut_ref = Vec::new(); - sub.each_binding(|_, hir_id, span, name| { - let span = mk_span(span, name.span); - match typeck_results.extract_binding_mode(sess, hir_id, span) { - Some(ty::BindByReference(mut_inner)) => match (mut_outer, mut_inner) { + sub.each_binding(|name, mode, ty, span| { + match mode { + BindingMode::ByRef(mut_inner) => match (mut_outer, mut_inner.mutability()) { // Both sides are `ref`. (Mutability::Not, Mutability::Not) => {} // 2x `ref mut`. @@ -944,10 +947,10 @@ fn check_borrow_conflicts_in_at_patterns(cx: &MatchVisitor<'_, '_, '_>, pat: &Pa conflicts_mut_ref.push(Conflict::Ref { span, name }) } }, - Some(ty::BindByValue(_)) if is_binding_by_move(cx, hir_id) => { + BindingMode::ByValue if is_binding_by_move(ty) => { conflicts_move.push(Conflict::Moved { span, name }) // `ref mut?` + by-move conflict. } - Some(ty::BindByValue(_)) | None => {} // `ref mut?` + by-copy is fine. + BindingMode::ByValue => {} // `ref mut?` + by-copy is fine. } }); @@ -966,81 +969,19 @@ fn check_borrow_conflicts_in_at_patterns(cx: &MatchVisitor<'_, '_, '_>, pat: &Pa // Report errors if any. if report_mut_mut { // Report mutability conflicts for e.g. `ref mut x @ Some(ref mut y)`. - sess.emit_err(MultipleMutBorrows { span: binding_span, occurences }); + sess.emit_err(MultipleMutBorrows { span: pat.span, occurences }); } else if report_mut_ref { // Report mutability conflicts for e.g. `ref x @ Some(ref mut y)` or the converse. match mut_outer { Mutability::Mut => { - sess.emit_err(AlreadyMutBorrowed { span: binding_span, occurences }); + sess.emit_err(AlreadyMutBorrowed { span: pat.span, occurences }); } Mutability::Not => { - sess.emit_err(AlreadyBorrowed { span: binding_span, occurences }); + sess.emit_err(AlreadyBorrowed { span: pat.span, occurences }); } }; } else if report_move_conflict { // Report by-ref and by-move conflicts, e.g. `ref x @ y`. - sess.emit_err(MovedWhileBorrowed { span: binding_span, occurences }); + sess.emit_err(MovedWhileBorrowed { span: pat.span, occurences }); } } - -#[derive(Clone, Copy, Debug)] -pub enum LetSource { - GenericLet, - IfLet, - IfLetGuard, - LetElse, - WhileLet, -} - -fn let_source(tcx: TyCtxt<'_>, pat_id: HirId) -> LetSource { - let hir = tcx.hir(); - - let parent = hir.parent_id(pat_id); - let_source_parent(tcx, parent, Some(pat_id)) -} - -fn let_source_parent(tcx: TyCtxt<'_>, parent: HirId, pat_id: Option) -> LetSource { - let hir = tcx.hir(); - - let parent_node = hir.get(parent); - - match parent_node { - hir::Node::Arm(hir::Arm { - guard: Some(hir::Guard::IfLet(&hir::Let { pat: hir::Pat { hir_id, .. }, .. })), - .. - }) if Some(*hir_id) == pat_id => { - return LetSource::IfLetGuard; - } - _ => {} - } - - let parent_parent = hir.parent_id(parent); - let parent_parent_node = hir.get(parent_parent); - match parent_parent_node { - hir::Node::Stmt(hir::Stmt { kind: hir::StmtKind::Local(_), .. }) => { - return LetSource::LetElse; - } - hir::Node::Arm(hir::Arm { guard: Some(hir::Guard::If(_)), .. }) => { - return LetSource::IfLetGuard; - } - _ => {} - } - - let parent_parent_parent = hir.parent_id(parent_parent); - let parent_parent_parent_parent = hir.parent_id(parent_parent_parent); - let parent_parent_parent_parent_node = hir.get(parent_parent_parent_parent); - - if let hir::Node::Expr(hir::Expr { - kind: hir::ExprKind::Loop(_, _, hir::LoopSource::While, _), - .. - }) = parent_parent_parent_parent_node - { - return LetSource::WhileLet; - } - - if let hir::Node::Expr(hir::Expr { kind: hir::ExprKind::If(..), .. }) = parent_parent_node { - return LetSource::IfLet; - } - - LetSource::GenericLet -} diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 9ac92f6e0a611..6e201b771ec6e 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -54,11 +54,9 @@ pub(super) fn pat_from_hir<'a, 'tcx>( pat: &'tcx hir::Pat<'tcx>, ) -> Box> { let mut pcx = PatCtxt::new(tcx, param_env, typeck_results); + pcx.include_lint_checks(); let result = pcx.lower_pattern(pat); - if !pcx.errors.is_empty() { - let msg = format!("encountered errors lowering pattern: {:?}", pcx.errors); - tcx.sess.delay_span_bug(pat.span, &msg); - } + pcx.report_inlining_errors(); debug!("pat_from_hir({:?}) = {:?}", pat, result); result } @@ -77,6 +75,25 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { self } + fn report_inlining_errors(&self) { + for error in &self.errors { + match *error { + PatternError::StaticInPattern(span) => { + self.tcx.sess.emit_err(StaticInPattern { span }); + } + PatternError::AssocConstInPattern(span) => { + self.tcx.sess.emit_err(AssocConstInPattern { span }); + } + PatternError::ConstParamInPattern(span) => { + self.tcx.sess.emit_err(ConstParamInPattern { span }); + } + PatternError::NonConstPath(span) => { + self.tcx.sess.emit_err(NonConstPath { span }); + } + } + } + } + fn lower_pattern(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Box> { // When implicit dereferences have been inserted in this pattern, the unadjusted lowered // pattern has the type that results *after* dereferencing. For example, in this code: diff --git a/tests/ui/chalkify/bugs/async.stderr b/tests/ui/chalkify/bugs/async.stderr index 9c559640b2308..36606fd49f27f 100644 --- a/tests/ui/chalkify/bugs/async.stderr +++ b/tests/ui/chalkify/bugs/async.stderr @@ -14,14 +14,15 @@ LL | async fn foo(x: u32) -> u32 { | ^^^query stack during panic: #0 [typeck] type-checking `foo` #1 [thir_body] building THIR for `foo` -#2 [mir_built] building MIR for `foo` -#3 [unsafety_check_result] unsafety-checking `foo` -#4 [mir_const] preparing `foo` for borrow checking -#5 [mir_promoted] processing MIR for `foo` -#6 [mir_borrowck] borrow-checking `foo` -#7 [type_of] computing type of `foo::{opaque#0}` -#8 [check_mod_item_types] checking item types in top-level module -#9 [analysis] running analysis passes on this crate +#2 [check_match] match-checking `foo` +#3 [mir_built] building MIR for `foo` +#4 [unsafety_check_result] unsafety-checking `foo` +#5 [mir_const] preparing `foo` for borrow checking +#6 [mir_promoted] processing MIR for `foo` +#7 [mir_borrowck] borrow-checking `foo` +#8 [type_of] computing type of `foo::{opaque#0}` +#9 [check_mod_item_types] checking item types in top-level module +#10 [analysis] running analysis passes on this crate end of query stack error: aborting due to 2 previous errors diff --git a/tests/ui/consts/const-eval/const-eval-overflow-2.rs b/tests/ui/consts/const-eval/const-eval-overflow-2.rs index 535d91359163f..c19a0c443ec58 100644 --- a/tests/ui/consts/const-eval/const-eval-overflow-2.rs +++ b/tests/ui/consts/const-eval/const-eval-overflow-2.rs @@ -14,7 +14,6 @@ fn main() { match -128i8 { NEG_NEG_128 => println!("A"), //~^ ERROR could not evaluate constant pattern - //~| ERROR could not evaluate constant pattern _ => println!("B"), } } diff --git a/tests/ui/consts/const-eval/const-eval-overflow-2.stderr b/tests/ui/consts/const-eval/const-eval-overflow-2.stderr index 7b1fe49d4346e..fc0baf11051b7 100644 --- a/tests/ui/consts/const-eval/const-eval-overflow-2.stderr +++ b/tests/ui/consts/const-eval/const-eval-overflow-2.stderr @@ -10,12 +10,6 @@ error: could not evaluate constant pattern LL | NEG_NEG_128 => println!("A"), | ^^^^^^^^^^^ -error: could not evaluate constant pattern - --> $DIR/const-eval-overflow-2.rs:15:9 - | -LL | NEG_NEG_128 => println!("A"), - | ^^^^^^^^^^^ - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-eval/ref_to_int_match.32bit.stderr b/tests/ui/consts/const-eval/ref_to_int_match.32bit.stderr index 032ceb2467c24..eaa2d6b279451 100644 --- a/tests/ui/consts/const-eval/ref_to_int_match.32bit.stderr +++ b/tests/ui/consts/const-eval/ref_to_int_match.32bit.stderr @@ -1,5 +1,5 @@ error[E0080]: evaluation of constant value failed - --> $DIR/ref_to_int_match.rs:25:27 + --> $DIR/ref_to_int_match.rs:24:27 | LL | const BAR: Int = unsafe { Foo { r: &42 }.f }; | ^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes @@ -13,12 +13,6 @@ error: could not evaluate constant pattern LL | 10..=BAR => {}, | ^^^ -error: could not evaluate constant pattern - --> $DIR/ref_to_int_match.rs:7:14 - | -LL | 10..=BAR => {}, - | ^^^ - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-eval/ref_to_int_match.64bit.stderr b/tests/ui/consts/const-eval/ref_to_int_match.64bit.stderr index 032ceb2467c24..eaa2d6b279451 100644 --- a/tests/ui/consts/const-eval/ref_to_int_match.64bit.stderr +++ b/tests/ui/consts/const-eval/ref_to_int_match.64bit.stderr @@ -1,5 +1,5 @@ error[E0080]: evaluation of constant value failed - --> $DIR/ref_to_int_match.rs:25:27 + --> $DIR/ref_to_int_match.rs:24:27 | LL | const BAR: Int = unsafe { Foo { r: &42 }.f }; | ^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes @@ -13,12 +13,6 @@ error: could not evaluate constant pattern LL | 10..=BAR => {}, | ^^^ -error: could not evaluate constant pattern - --> $DIR/ref_to_int_match.rs:7:14 - | -LL | 10..=BAR => {}, - | ^^^ - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-eval/ref_to_int_match.rs b/tests/ui/consts/const-eval/ref_to_int_match.rs index 70c6e7d94ae01..a2dabde25bc8d 100644 --- a/tests/ui/consts/const-eval/ref_to_int_match.rs +++ b/tests/ui/consts/const-eval/ref_to_int_match.rs @@ -5,7 +5,6 @@ fn main() { match n { 0..=10 => {}, 10..=BAR => {}, //~ ERROR could not evaluate constant pattern - //~| ERROR could not evaluate constant pattern _ => {}, } } diff --git a/tests/ui/consts/const-match-check.eval1.stderr b/tests/ui/consts/const-match-check.eval1.stderr index 08fcd1deab1d3..27ff5d4cd5c6b 100644 --- a/tests/ui/consts/const-match-check.eval1.stderr +++ b/tests/ui/consts/const-match-check.eval1.stderr @@ -9,8 +9,8 @@ LL | A = { let 0 = 0; 0 }, = note: the matched value is of type `i32` help: you might want to use `if let` to ignore the variants that aren't matched | -LL | A = { if let 0 = 0 { todo!() } 0 }, - | ++ ~~~~~~~~~~~ +LL | A = { if let 0 = 0 { todo!() }; 0 }, + | ++ +++++++++++ help: alternatively, you could prepend the pattern with an underscore to define a new named variable; identifiers cannot begin with digits | LL | A = { let _0 = 0; 0 }, diff --git a/tests/ui/consts/const-match-check.eval2.stderr b/tests/ui/consts/const-match-check.eval2.stderr index 5d86ca4bfd17b..0c74a7b3dd4d2 100644 --- a/tests/ui/consts/const-match-check.eval2.stderr +++ b/tests/ui/consts/const-match-check.eval2.stderr @@ -9,8 +9,8 @@ LL | let x: [i32; { let 0 = 0; 0 }] = []; = note: the matched value is of type `i32` help: you might want to use `if let` to ignore the variants that aren't matched | -LL | let x: [i32; { if let 0 = 0 { todo!() } 0 }] = []; - | ++ ~~~~~~~~~~~ +LL | let x: [i32; { if let 0 = 0 { todo!() }; 0 }] = []; + | ++ +++++++++++ help: alternatively, you could prepend the pattern with an underscore to define a new named variable; identifiers cannot begin with digits | LL | let x: [i32; { let _0 = 0; 0 }] = []; diff --git a/tests/ui/consts/const-match-check.matchck.stderr b/tests/ui/consts/const-match-check.matchck.stderr index c8f66bb0fc027..bcca4c2a64783 100644 --- a/tests/ui/consts/const-match-check.matchck.stderr +++ b/tests/ui/consts/const-match-check.matchck.stderr @@ -9,8 +9,8 @@ LL | const X: i32 = { let 0 = 0; 0 }; = note: the matched value is of type `i32` help: you might want to use `if let` to ignore the variants that aren't matched | -LL | const X: i32 = { if let 0 = 0 { todo!() } 0 }; - | ++ ~~~~~~~~~~~ +LL | const X: i32 = { if let 0 = 0 { todo!() }; 0 }; + | ++ +++++++++++ help: alternatively, you could prepend the pattern with an underscore to define a new named variable; identifiers cannot begin with digits | LL | const X: i32 = { let _0 = 0; 0 }; @@ -27,8 +27,8 @@ LL | static Y: i32 = { let 0 = 0; 0 }; = note: the matched value is of type `i32` help: you might want to use `if let` to ignore the variants that aren't matched | -LL | static Y: i32 = { if let 0 = 0 { todo!() } 0 }; - | ++ ~~~~~~~~~~~ +LL | static Y: i32 = { if let 0 = 0 { todo!() }; 0 }; + | ++ +++++++++++ help: alternatively, you could prepend the pattern with an underscore to define a new named variable; identifiers cannot begin with digits | LL | static Y: i32 = { let _0 = 0; 0 }; @@ -45,8 +45,8 @@ LL | const X: i32 = { let 0 = 0; 0 }; = note: the matched value is of type `i32` help: you might want to use `if let` to ignore the variants that aren't matched | -LL | const X: i32 = { if let 0 = 0 { todo!() } 0 }; - | ++ ~~~~~~~~~~~ +LL | const X: i32 = { if let 0 = 0 { todo!() }; 0 }; + | ++ +++++++++++ help: alternatively, you could prepend the pattern with an underscore to define a new named variable; identifiers cannot begin with digits | LL | const X: i32 = { let _0 = 0; 0 }; @@ -63,8 +63,8 @@ LL | const X: i32 = { let 0 = 0; 0 }; = note: the matched value is of type `i32` help: you might want to use `if let` to ignore the variants that aren't matched | -LL | const X: i32 = { if let 0 = 0 { todo!() } 0 }; - | ++ ~~~~~~~~~~~ +LL | const X: i32 = { if let 0 = 0 { todo!() }; 0 }; + | ++ +++++++++++ help: alternatively, you could prepend the pattern with an underscore to define a new named variable; identifiers cannot begin with digits | LL | const X: i32 = { let _0 = 0; 0 }; diff --git a/tests/ui/consts/const-pattern-irrefutable.rs b/tests/ui/consts/const-pattern-irrefutable.rs index 61bdf57ffdb94..d7d8e7328397c 100644 --- a/tests/ui/consts/const-pattern-irrefutable.rs +++ b/tests/ui/consts/const-pattern-irrefutable.rs @@ -12,17 +12,14 @@ fn main() { let a = 4; //~^ ERROR refutable pattern in local binding //~| patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered - //~| missing patterns are not covered because `a` is interpreted as a constant pattern, not a new variable - //~| HELP introduce a variable instead + //~| HELP you might want to use `if let` to ignore the variants that aren't matched let c = 4; //~^ ERROR refutable pattern in local binding //~| patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered - //~| missing patterns are not covered because `c` is interpreted as a constant pattern, not a new variable - //~| HELP introduce a variable instead + //~| HELP you might want to use `if let` to ignore the variants that aren't matched let d = 4; //~^ ERROR refutable pattern in local binding //~| patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered - //~| missing patterns are not covered because `d` is interpreted as a constant pattern, not a new variable - //~| HELP introduce a variable instead + //~| HELP you might want to use `if let` to ignore the variants that aren't matched fn f() {} // Check that the `NOTE`s still work with an item here (cf. issue #35115). } diff --git a/tests/ui/consts/const-pattern-irrefutable.stderr b/tests/ui/consts/const-pattern-irrefutable.stderr index c156ea1610c4f..956a97a476c10 100644 --- a/tests/ui/consts/const-pattern-irrefutable.stderr +++ b/tests/ui/consts/const-pattern-irrefutable.stderr @@ -1,47 +1,44 @@ error[E0005]: refutable pattern in local binding --> $DIR/const-pattern-irrefutable.rs:12:9 | -LL | const a: u8 = 2; - | ----------- constant defined here -... LL | let a = 4; - | ^ - | | - | patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered - | missing patterns are not covered because `a` is interpreted as a constant pattern, not a new variable - | help: introduce a variable instead: `a_var` + | ^ patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered | + = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant + = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html = note: the matched value is of type `u8` +help: you might want to use `if let` to ignore the variants that aren't matched + | +LL | if let a = 4 { todo!() }; + | ++ +++++++++++ error[E0005]: refutable pattern in local binding - --> $DIR/const-pattern-irrefutable.rs:17:9 + --> $DIR/const-pattern-irrefutable.rs:16:9 | -LL | pub const b: u8 = 2; - | --------------- constant defined here -... LL | let c = 4; - | ^ - | | - | patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered - | missing patterns are not covered because `c` is interpreted as a constant pattern, not a new variable - | help: introduce a variable instead: `c_var` + | ^ patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered | + = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant + = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html = note: the matched value is of type `u8` +help: you might want to use `if let` to ignore the variants that aren't matched + | +LL | if let c = 4 { todo!() }; + | ++ +++++++++++ error[E0005]: refutable pattern in local binding - --> $DIR/const-pattern-irrefutable.rs:22:9 + --> $DIR/const-pattern-irrefutable.rs:20:9 | -LL | pub const d: u8 = 2; - | --------------- constant defined here -... LL | let d = 4; - | ^ - | | - | patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered - | missing patterns are not covered because `d` is interpreted as a constant pattern, not a new variable - | help: introduce a variable instead: `d_var` + | ^ patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered | + = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant + = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html = note: the matched value is of type `u8` +help: you might want to use `if let` to ignore the variants that aren't matched + | +LL | if let d = 4 { todo!() }; + | ++ +++++++++++ error: aborting due to 3 previous errors diff --git a/tests/ui/consts/const_in_pattern/incomplete-slice.stderr b/tests/ui/consts/const_in_pattern/incomplete-slice.stderr index b005f3220e9c4..be144a87b8b34 100644 --- a/tests/ui/consts/const_in_pattern/incomplete-slice.stderr +++ b/tests/ui/consts/const_in_pattern/incomplete-slice.stderr @@ -19,7 +19,7 @@ LL | match &[][..] { = note: the matched value is of type `&[E]` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | -LL ~ E_SL => {} +LL ~ E_SL => {}, LL + &_ => todo!() | diff --git a/tests/ui/consts/issue-43105.rs b/tests/ui/consts/issue-43105.rs index cac12b90970fe..20b78d64209e1 100644 --- a/tests/ui/consts/issue-43105.rs +++ b/tests/ui/consts/issue-43105.rs @@ -7,7 +7,6 @@ fn main() { match 1 { NUM => unimplemented!(), //~^ ERROR could not evaluate constant pattern - //~| ERROR could not evaluate constant pattern _ => unimplemented!(), } } diff --git a/tests/ui/consts/issue-43105.stderr b/tests/ui/consts/issue-43105.stderr index 2d1174af71c86..856a8f0dab6c0 100644 --- a/tests/ui/consts/issue-43105.stderr +++ b/tests/ui/consts/issue-43105.stderr @@ -12,12 +12,6 @@ error: could not evaluate constant pattern LL | NUM => unimplemented!(), | ^^^ -error: could not evaluate constant pattern - --> $DIR/issue-43105.rs:8:9 - | -LL | NUM => unimplemented!(), - | ^^^ - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/consts/issue-73976-polymorphic.rs b/tests/ui/consts/issue-73976-polymorphic.rs index 787462da9f960..2c576d1f9ef08 100644 --- a/tests/ui/consts/issue-73976-polymorphic.rs +++ b/tests/ui/consts/issue-73976-polymorphic.rs @@ -19,7 +19,6 @@ impl GetTypeId { const fn check_type_id() -> bool { matches!(GetTypeId::::VALUE, GetTypeId::::VALUE) //~^ ERROR constant pattern depends on a generic parameter - //~| ERROR constant pattern depends on a generic parameter } pub struct GetTypeNameLen(T); @@ -31,7 +30,6 @@ impl GetTypeNameLen { const fn check_type_name_len() -> bool { matches!(GetTypeNameLen::::VALUE, GetTypeNameLen::::VALUE) //~^ ERROR constant pattern depends on a generic parameter - //~| ERROR constant pattern depends on a generic parameter } fn main() { diff --git a/tests/ui/consts/issue-73976-polymorphic.stderr b/tests/ui/consts/issue-73976-polymorphic.stderr index 442ad23f2cc42..97a5fbc5747a3 100644 --- a/tests/ui/consts/issue-73976-polymorphic.stderr +++ b/tests/ui/consts/issue-73976-polymorphic.stderr @@ -5,22 +5,10 @@ LL | matches!(GetTypeId::::VALUE, GetTypeId::::VALUE) | ^^^^^^^^^^^^^^^^^^^^^ error: constant pattern depends on a generic parameter - --> $DIR/issue-73976-polymorphic.rs:32:42 + --> $DIR/issue-73976-polymorphic.rs:31:42 | LL | matches!(GetTypeNameLen::::VALUE, GetTypeNameLen::::VALUE) | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: constant pattern depends on a generic parameter - --> $DIR/issue-73976-polymorphic.rs:20:37 - | -LL | matches!(GetTypeId::::VALUE, GetTypeId::::VALUE) - | ^^^^^^^^^^^^^^^^^^^^^ - -error: constant pattern depends on a generic parameter - --> $DIR/issue-73976-polymorphic.rs:32:42 - | -LL | matches!(GetTypeNameLen::::VALUE, GetTypeNameLen::::VALUE) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 4 previous errors +error: aborting due to 2 previous errors diff --git a/tests/ui/consts/issue-78655.rs b/tests/ui/consts/issue-78655.rs index 82d2d7c21d859..cd95ee32c60d2 100644 --- a/tests/ui/consts/issue-78655.rs +++ b/tests/ui/consts/issue-78655.rs @@ -6,5 +6,4 @@ const FOO: *const u32 = { fn main() { let FOO = FOO; //~^ ERROR could not evaluate constant pattern - //~| ERROR could not evaluate constant pattern } diff --git a/tests/ui/consts/issue-78655.stderr b/tests/ui/consts/issue-78655.stderr index 6b83fa0e5a01f..5a38d023d6f16 100644 --- a/tests/ui/consts/issue-78655.stderr +++ b/tests/ui/consts/issue-78655.stderr @@ -17,12 +17,6 @@ error: could not evaluate constant pattern LL | let FOO = FOO; | ^^^ -error: could not evaluate constant pattern - --> $DIR/issue-78655.rs:7:9 - | -LL | let FOO = FOO; - | ^^^ - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0381`. diff --git a/tests/ui/consts/issue-79137-toogeneric.rs b/tests/ui/consts/issue-79137-toogeneric.rs index 456035458cfc5..a80c9f48d7bc9 100644 --- a/tests/ui/consts/issue-79137-toogeneric.rs +++ b/tests/ui/consts/issue-79137-toogeneric.rs @@ -11,7 +11,6 @@ impl GetVariantCount { const fn check_variant_count() -> bool { matches!(GetVariantCount::::VALUE, GetVariantCount::::VALUE) //~^ ERROR constant pattern depends on a generic parameter - //~| ERROR constant pattern depends on a generic parameter } fn main() { diff --git a/tests/ui/consts/issue-79137-toogeneric.stderr b/tests/ui/consts/issue-79137-toogeneric.stderr index 579e6aa09bdbd..efe4fd22e547c 100644 --- a/tests/ui/consts/issue-79137-toogeneric.stderr +++ b/tests/ui/consts/issue-79137-toogeneric.stderr @@ -4,11 +4,5 @@ error: constant pattern depends on a generic parameter LL | matches!(GetVariantCount::::VALUE, GetVariantCount::::VALUE) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: constant pattern depends on a generic parameter - --> $DIR/issue-79137-toogeneric.rs:12:43 - | -LL | matches!(GetVariantCount::::VALUE, GetVariantCount::::VALUE) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 2 previous errors +error: aborting due to previous error diff --git a/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.32bit.stderr b/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.32bit.stderr index 6df2fe3d03b9d..e3a0d93f09b7c 100644 --- a/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.32bit.stderr +++ b/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.32bit.stderr @@ -27,7 +27,7 @@ LL | const U8_MUT: &u8 = { } error: could not evaluate constant pattern - --> $DIR/const_refers_to_static_cross_crate.rs:43:9 + --> $DIR/const_refers_to_static_cross_crate.rs:42:9 | LL | U8_MUT => true, | ^^^^^^ @@ -39,7 +39,7 @@ LL | unsafe { &(*static_cross_crate::ZERO_REF)[0] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constant accesses static error: could not evaluate constant pattern - --> $DIR/const_refers_to_static_cross_crate.rs:54:9 + --> $DIR/const_refers_to_static_cross_crate.rs:52:9 | LL | U8_MUT2 => true, | ^^^^^^^ @@ -51,31 +51,7 @@ LL | unsafe { match static_cross_crate::OPT_ZERO { Some(ref u) => u, None => | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constant accesses static error: could not evaluate constant pattern - --> $DIR/const_refers_to_static_cross_crate.rs:62:9 - | -LL | U8_MUT3 => true, - | ^^^^^^^ - -error: could not evaluate constant pattern - --> $DIR/const_refers_to_static_cross_crate.rs:34:9 - | -LL | SLICE_MUT => true, - | ^^^^^^^^^ - -error: could not evaluate constant pattern - --> $DIR/const_refers_to_static_cross_crate.rs:43:9 - | -LL | U8_MUT => true, - | ^^^^^^ - -error: could not evaluate constant pattern - --> $DIR/const_refers_to_static_cross_crate.rs:54:9 - | -LL | U8_MUT2 => true, - | ^^^^^^^ - -error: could not evaluate constant pattern - --> $DIR/const_refers_to_static_cross_crate.rs:62:9 + --> $DIR/const_refers_to_static_cross_crate.rs:59:9 | LL | U8_MUT3 => true, | ^^^^^^^ @@ -133,6 +109,6 @@ help: skipping check that does not even have a feature gate LL | unsafe { match static_cross_crate::OPT_ZERO { Some(ref u) => u, None => panic!() } } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 12 previous errors; 1 warning emitted +error: aborting due to 8 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.64bit.stderr b/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.64bit.stderr index 8802f3adacae2..a323e9a05f090 100644 --- a/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.64bit.stderr +++ b/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.64bit.stderr @@ -27,7 +27,7 @@ LL | const U8_MUT: &u8 = { } error: could not evaluate constant pattern - --> $DIR/const_refers_to_static_cross_crate.rs:43:9 + --> $DIR/const_refers_to_static_cross_crate.rs:42:9 | LL | U8_MUT => true, | ^^^^^^ @@ -39,7 +39,7 @@ LL | unsafe { &(*static_cross_crate::ZERO_REF)[0] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constant accesses static error: could not evaluate constant pattern - --> $DIR/const_refers_to_static_cross_crate.rs:54:9 + --> $DIR/const_refers_to_static_cross_crate.rs:52:9 | LL | U8_MUT2 => true, | ^^^^^^^ @@ -51,31 +51,7 @@ LL | unsafe { match static_cross_crate::OPT_ZERO { Some(ref u) => u, None => | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constant accesses static error: could not evaluate constant pattern - --> $DIR/const_refers_to_static_cross_crate.rs:62:9 - | -LL | U8_MUT3 => true, - | ^^^^^^^ - -error: could not evaluate constant pattern - --> $DIR/const_refers_to_static_cross_crate.rs:34:9 - | -LL | SLICE_MUT => true, - | ^^^^^^^^^ - -error: could not evaluate constant pattern - --> $DIR/const_refers_to_static_cross_crate.rs:43:9 - | -LL | U8_MUT => true, - | ^^^^^^ - -error: could not evaluate constant pattern - --> $DIR/const_refers_to_static_cross_crate.rs:54:9 - | -LL | U8_MUT2 => true, - | ^^^^^^^ - -error: could not evaluate constant pattern - --> $DIR/const_refers_to_static_cross_crate.rs:62:9 + --> $DIR/const_refers_to_static_cross_crate.rs:59:9 | LL | U8_MUT3 => true, | ^^^^^^^ @@ -133,6 +109,6 @@ help: skipping check that does not even have a feature gate LL | unsafe { match static_cross_crate::OPT_ZERO { Some(ref u) => u, None => panic!() } } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 12 previous errors; 1 warning emitted +error: aborting due to 8 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.rs b/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.rs index bf4f14f4d5a11..bbaa32ddfd1bd 100644 --- a/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.rs +++ b/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.rs @@ -33,7 +33,6 @@ pub fn test(x: &[u8; 1]) -> bool { match x { SLICE_MUT => true, //~^ ERROR could not evaluate constant pattern - //~| ERROR could not evaluate constant pattern &[1..] => false, } } @@ -42,7 +41,6 @@ pub fn test2(x: &u8) -> bool { match x { U8_MUT => true, //~^ ERROR could not evaluate constant pattern - //~| ERROR could not evaluate constant pattern &(1..) => false, } } @@ -53,7 +51,6 @@ pub fn test3(x: &u8) -> bool { match x { U8_MUT2 => true, //~^ ERROR could not evaluate constant pattern - //~| ERROR could not evaluate constant pattern &(1..) => false, } } @@ -61,7 +58,6 @@ pub fn test4(x: &u8) -> bool { match x { U8_MUT3 => true, //~^ ERROR could not evaluate constant pattern - //~| ERROR could not evaluate constant pattern &(1..) => false, } } diff --git a/tests/ui/error-codes/E0004.stderr b/tests/ui/error-codes/E0004.stderr index 4ac8c904f0530..603bc5237ea20 100644 --- a/tests/ui/error-codes/E0004.stderr +++ b/tests/ui/error-codes/E0004.stderr @@ -14,7 +14,7 @@ LL | HastaLaVistaBaby, = note: the matched value is of type `Terminator` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | -LL ~ Terminator::TalkToMyHand => {} +LL ~ Terminator::TalkToMyHand => {}, LL + Terminator::HastaLaVistaBaby => todo!() | diff --git a/tests/ui/error-codes/E0030-teach.rs b/tests/ui/error-codes/E0030-teach.rs index 8caa4f0931d57..388064fb0fae5 100644 --- a/tests/ui/error-codes/E0030-teach.rs +++ b/tests/ui/error-codes/E0030-teach.rs @@ -4,6 +4,5 @@ fn main() { match 5u32 { 1000 ..= 5 => {} //~^ ERROR lower range bound must be less than or equal to upper - //~| ERROR lower range bound must be less than or equal to upper } } diff --git a/tests/ui/error-codes/E0030-teach.stderr b/tests/ui/error-codes/E0030-teach.stderr index 800f66416a813..3f1ad4af3a94e 100644 --- a/tests/ui/error-codes/E0030-teach.stderr +++ b/tests/ui/error-codes/E0030-teach.stderr @@ -6,12 +6,6 @@ LL | 1000 ..= 5 => {} | = note: When matching against a range, the compiler verifies that the range is non-empty. Range patterns include both end-points, so this is equivalent to requiring the start of the range to be less than or equal to the end of the range. -error[E0030]: lower range bound must be less than or equal to upper - --> $DIR/E0030-teach.rs:5:9 - | -LL | 1000 ..= 5 => {} - | ^^^^ lower bound larger than upper bound - -error: aborting due to 2 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0030`. diff --git a/tests/ui/error-codes/E0030.rs b/tests/ui/error-codes/E0030.rs index a5d8f87261b2b..58d856b7c9d23 100644 --- a/tests/ui/error-codes/E0030.rs +++ b/tests/ui/error-codes/E0030.rs @@ -2,6 +2,5 @@ fn main() { match 5u32 { 1000 ..= 5 => {} //~^ ERROR lower range bound must be less than or equal to upper - //~| ERROR lower range bound must be less than or equal to upper } } diff --git a/tests/ui/error-codes/E0030.stderr b/tests/ui/error-codes/E0030.stderr index 8a6114024b630..db8161d8fd5d8 100644 --- a/tests/ui/error-codes/E0030.stderr +++ b/tests/ui/error-codes/E0030.stderr @@ -4,12 +4,6 @@ error[E0030]: lower range bound must be less than or equal to upper LL | 1000 ..= 5 => {} | ^^^^ lower bound larger than upper bound -error[E0030]: lower range bound must be less than or equal to upper - --> $DIR/E0030.rs:3:9 - | -LL | 1000 ..= 5 => {} - | ^^^^ lower bound larger than upper bound - -error: aborting due to 2 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0030`. diff --git a/tests/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.stderr b/tests/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.stderr index 4d79ce3c6594a..fb39c404c207e 100644 --- a/tests/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.stderr +++ b/tests/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.stderr @@ -115,7 +115,7 @@ LL | A, B, C, = note: the matched value is of type `Foo` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | -LL ~ Foo::B => {} +LL ~ Foo::B => {}, LL + Foo::C => todo!() | diff --git a/tests/ui/feature-gates/feature-gate-precise_pointer_size_matching.stderr b/tests/ui/feature-gates/feature-gate-precise_pointer_size_matching.stderr index b5510683328f5..853b57052ace0 100644 --- a/tests/ui/feature-gates/feature-gate-precise_pointer_size_matching.stderr +++ b/tests/ui/feature-gates/feature-gate-precise_pointer_size_matching.stderr @@ -9,7 +9,7 @@ LL | match 0usize { = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | -LL ~ 0..=usize::MAX => {} +LL ~ 0..=usize::MAX => {}, LL + _ => todo!() | @@ -24,7 +24,7 @@ LL | match 0isize { = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | -LL ~ isize::MIN..=isize::MAX => {} +LL ~ isize::MIN..=isize::MAX => {}, LL + _ => todo!() | diff --git a/tests/ui/half-open-range-patterns/half-open-range-pats-thir-lower-empty.rs b/tests/ui/half-open-range-patterns/half-open-range-pats-thir-lower-empty.rs index f55566602dba3..4b14a314e7aea 100644 --- a/tests/ui/half-open-range-patterns/half-open-range-pats-thir-lower-empty.rs +++ b/tests/ui/half-open-range-patterns/half-open-range-pats-thir-lower-empty.rs @@ -10,44 +10,31 @@ macro_rules! m { fn main() { m!(0, ..u8::MIN); //~^ ERROR lower range bound must be less than upper - //~| ERROR lower range bound must be less than upper m!(0, ..u16::MIN); //~^ ERROR lower range bound must be less than upper - //~| ERROR lower range bound must be less than upper m!(0, ..u32::MIN); //~^ ERROR lower range bound must be less than upper - //~| ERROR lower range bound must be less than upper m!(0, ..u64::MIN); //~^ ERROR lower range bound must be less than upper - //~| ERROR lower range bound must be less than upper m!(0, ..u128::MIN); //~^ ERROR lower range bound must be less than upper - //~| ERROR lower range bound must be less than upper m!(0, ..i8::MIN); //~^ ERROR lower range bound must be less than upper - //~| ERROR lower range bound must be less than upper m!(0, ..i16::MIN); //~^ ERROR lower range bound must be less than upper - //~| ERROR lower range bound must be less than upper m!(0, ..i32::MIN); //~^ ERROR lower range bound must be less than upper - //~| ERROR lower range bound must be less than upper m!(0, ..i64::MIN); //~^ ERROR lower range bound must be less than upper - //~| ERROR lower range bound must be less than upper m!(0, ..i128::MIN); //~^ ERROR lower range bound must be less than upper - //~| ERROR lower range bound must be less than upper m!(0f32, ..f32::NEG_INFINITY); //~^ ERROR lower range bound must be less than upper - //~| ERROR lower range bound must be less than upper m!(0f64, ..f64::NEG_INFINITY); //~^ ERROR lower range bound must be less than upper - //~| ERROR lower range bound must be less than upper m!('a', ..'\u{0}'); //~^ ERROR lower range bound must be less than upper - //~| ERROR lower range bound must be less than upper } diff --git a/tests/ui/half-open-range-patterns/half-open-range-pats-thir-lower-empty.stderr b/tests/ui/half-open-range-patterns/half-open-range-pats-thir-lower-empty.stderr index 56b224a8542be..e9702bb380fb3 100644 --- a/tests/ui/half-open-range-patterns/half-open-range-pats-thir-lower-empty.stderr +++ b/tests/ui/half-open-range-patterns/half-open-range-pats-thir-lower-empty.stderr @@ -5,155 +5,77 @@ LL | m!(0, ..u8::MIN); | ^^^^^^^^^ error[E0579]: lower range bound must be less than upper - --> $DIR/half-open-range-pats-thir-lower-empty.rs:14:11 + --> $DIR/half-open-range-pats-thir-lower-empty.rs:13:11 | LL | m!(0, ..u16::MIN); | ^^^^^^^^^^ error[E0579]: lower range bound must be less than upper - --> $DIR/half-open-range-pats-thir-lower-empty.rs:17:11 + --> $DIR/half-open-range-pats-thir-lower-empty.rs:15:11 | LL | m!(0, ..u32::MIN); | ^^^^^^^^^^ -error[E0579]: lower range bound must be less than upper - --> $DIR/half-open-range-pats-thir-lower-empty.rs:20:11 - | -LL | m!(0, ..u64::MIN); - | ^^^^^^^^^^ - -error[E0579]: lower range bound must be less than upper - --> $DIR/half-open-range-pats-thir-lower-empty.rs:23:11 - | -LL | m!(0, ..u128::MIN); - | ^^^^^^^^^^^ - -error[E0579]: lower range bound must be less than upper - --> $DIR/half-open-range-pats-thir-lower-empty.rs:27:11 - | -LL | m!(0, ..i8::MIN); - | ^^^^^^^^^ - -error[E0579]: lower range bound must be less than upper - --> $DIR/half-open-range-pats-thir-lower-empty.rs:30:11 - | -LL | m!(0, ..i16::MIN); - | ^^^^^^^^^^ - -error[E0579]: lower range bound must be less than upper - --> $DIR/half-open-range-pats-thir-lower-empty.rs:33:11 - | -LL | m!(0, ..i32::MIN); - | ^^^^^^^^^^ - -error[E0579]: lower range bound must be less than upper - --> $DIR/half-open-range-pats-thir-lower-empty.rs:36:11 - | -LL | m!(0, ..i64::MIN); - | ^^^^^^^^^^ - -error[E0579]: lower range bound must be less than upper - --> $DIR/half-open-range-pats-thir-lower-empty.rs:39:11 - | -LL | m!(0, ..i128::MIN); - | ^^^^^^^^^^^ - -error[E0579]: lower range bound must be less than upper - --> $DIR/half-open-range-pats-thir-lower-empty.rs:43:14 - | -LL | m!(0f32, ..f32::NEG_INFINITY); - | ^^^^^^^^^^^^^^^^^^^ - -error[E0579]: lower range bound must be less than upper - --> $DIR/half-open-range-pats-thir-lower-empty.rs:46:14 - | -LL | m!(0f64, ..f64::NEG_INFINITY); - | ^^^^^^^^^^^^^^^^^^^ - -error[E0579]: lower range bound must be less than upper - --> $DIR/half-open-range-pats-thir-lower-empty.rs:50:13 - | -LL | m!('a', ..'\u{0}'); - | ^^^^^^^^^ - -error[E0579]: lower range bound must be less than upper - --> $DIR/half-open-range-pats-thir-lower-empty.rs:11:11 - | -LL | m!(0, ..u8::MIN); - | ^^^^^^^^^ - -error[E0579]: lower range bound must be less than upper - --> $DIR/half-open-range-pats-thir-lower-empty.rs:14:11 - | -LL | m!(0, ..u16::MIN); - | ^^^^^^^^^^ - error[E0579]: lower range bound must be less than upper --> $DIR/half-open-range-pats-thir-lower-empty.rs:17:11 | -LL | m!(0, ..u32::MIN); - | ^^^^^^^^^^ - -error[E0579]: lower range bound must be less than upper - --> $DIR/half-open-range-pats-thir-lower-empty.rs:20:11 - | LL | m!(0, ..u64::MIN); | ^^^^^^^^^^ error[E0579]: lower range bound must be less than upper - --> $DIR/half-open-range-pats-thir-lower-empty.rs:23:11 + --> $DIR/half-open-range-pats-thir-lower-empty.rs:19:11 | LL | m!(0, ..u128::MIN); | ^^^^^^^^^^^ error[E0579]: lower range bound must be less than upper - --> $DIR/half-open-range-pats-thir-lower-empty.rs:27:11 + --> $DIR/half-open-range-pats-thir-lower-empty.rs:22:11 | LL | m!(0, ..i8::MIN); | ^^^^^^^^^ error[E0579]: lower range bound must be less than upper - --> $DIR/half-open-range-pats-thir-lower-empty.rs:30:11 + --> $DIR/half-open-range-pats-thir-lower-empty.rs:24:11 | LL | m!(0, ..i16::MIN); | ^^^^^^^^^^ error[E0579]: lower range bound must be less than upper - --> $DIR/half-open-range-pats-thir-lower-empty.rs:33:11 + --> $DIR/half-open-range-pats-thir-lower-empty.rs:26:11 | LL | m!(0, ..i32::MIN); | ^^^^^^^^^^ error[E0579]: lower range bound must be less than upper - --> $DIR/half-open-range-pats-thir-lower-empty.rs:36:11 + --> $DIR/half-open-range-pats-thir-lower-empty.rs:28:11 | LL | m!(0, ..i64::MIN); | ^^^^^^^^^^ error[E0579]: lower range bound must be less than upper - --> $DIR/half-open-range-pats-thir-lower-empty.rs:39:11 + --> $DIR/half-open-range-pats-thir-lower-empty.rs:30:11 | LL | m!(0, ..i128::MIN); | ^^^^^^^^^^^ error[E0579]: lower range bound must be less than upper - --> $DIR/half-open-range-pats-thir-lower-empty.rs:43:14 + --> $DIR/half-open-range-pats-thir-lower-empty.rs:33:14 | LL | m!(0f32, ..f32::NEG_INFINITY); | ^^^^^^^^^^^^^^^^^^^ error[E0579]: lower range bound must be less than upper - --> $DIR/half-open-range-pats-thir-lower-empty.rs:46:14 + --> $DIR/half-open-range-pats-thir-lower-empty.rs:35:14 | LL | m!(0f64, ..f64::NEG_INFINITY); | ^^^^^^^^^^^^^^^^^^^ error[E0579]: lower range bound must be less than upper - --> $DIR/half-open-range-pats-thir-lower-empty.rs:50:13 + --> $DIR/half-open-range-pats-thir-lower-empty.rs:38:13 | LL | m!('a', ..'\u{0}'); | ^^^^^^^^^ -error: aborting due to 26 previous errors +error: aborting due to 13 previous errors For more information about this error, try `rustc --explain E0579`. diff --git a/tests/ui/impl-trait/auto-trait-leak.stderr b/tests/ui/impl-trait/auto-trait-leak.stderr index fd0358421ebf9..e6c750d0e427e 100644 --- a/tests/ui/impl-trait/auto-trait-leak.stderr +++ b/tests/ui/impl-trait/auto-trait-leak.stderr @@ -29,6 +29,11 @@ note: ...which requires building MIR for `cycle1`... | LL | fn cycle1() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires match-checking `cycle1`... + --> $DIR/auto-trait-leak.rs:12:1 + | +LL | fn cycle1() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...which requires building THIR for `cycle1`... --> $DIR/auto-trait-leak.rs:12:1 | @@ -70,6 +75,11 @@ note: ...which requires building MIR for `cycle2`... | LL | fn cycle2() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires match-checking `cycle2`... + --> $DIR/auto-trait-leak.rs:19:1 + | +LL | fn cycle2() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...which requires building THIR for `cycle2`... --> $DIR/auto-trait-leak.rs:19:1 | diff --git a/tests/ui/inline-const/const-match-pat-generic.rs b/tests/ui/inline-const/const-match-pat-generic.rs index 7c0d83516ea29..46e501abf6c2e 100644 --- a/tests/ui/inline-const/const-match-pat-generic.rs +++ b/tests/ui/inline-const/const-match-pat-generic.rs @@ -7,7 +7,6 @@ fn foo() { match 0 { const { V } => {}, //~^ ERROR constant pattern depends on a generic parameter - //~| ERROR constant pattern depends on a generic parameter _ => {}, } } @@ -20,7 +19,6 @@ fn bar() { match 0 { const { f(V) } => {}, //~^ ERROR constant pattern depends on a generic parameter - //~| ERROR constant pattern depends on a generic parameter _ => {}, } } diff --git a/tests/ui/inline-const/const-match-pat-generic.stderr b/tests/ui/inline-const/const-match-pat-generic.stderr index 77267f12fb11a..4ffbde4101d72 100644 --- a/tests/ui/inline-const/const-match-pat-generic.stderr +++ b/tests/ui/inline-const/const-match-pat-generic.stderr @@ -5,22 +5,10 @@ LL | const { V } => {}, | ^^^^^^^^^^^ error: constant pattern depends on a generic parameter - --> $DIR/const-match-pat-generic.rs:21:9 + --> $DIR/const-match-pat-generic.rs:20:9 | LL | const { f(V) } => {}, | ^^^^^^^^^^^^^^ -error: constant pattern depends on a generic parameter - --> $DIR/const-match-pat-generic.rs:8:9 - | -LL | const { V } => {}, - | ^^^^^^^^^^^ - -error: constant pattern depends on a generic parameter - --> $DIR/const-match-pat-generic.rs:21:9 - | -LL | const { f(V) } => {}, - | ^^^^^^^^^^^^^^ - -error: aborting due to 4 previous errors +error: aborting due to 2 previous errors diff --git a/tests/ui/match/match-range-fail-2.rs b/tests/ui/match/match-range-fail-2.rs index 792664e1db82c..4489cf1ab1f2b 100644 --- a/tests/ui/match/match-range-fail-2.rs +++ b/tests/ui/match/match-range-fail-2.rs @@ -3,22 +3,19 @@ fn main() { match 5 { 6 ..= 1 => { } + //~^ ERROR lower range bound must be less than or equal to upper _ => { } }; - //~^^^ ERROR lower range bound must be less than or equal to upper - //~| ERROR lower range bound must be less than or equal to upper match 5 { 0 .. 0 => { } + //~^ ERROR lower range bound must be less than upper _ => { } }; - //~^^^ ERROR lower range bound must be less than upper - //~| ERROR lower range bound must be less than upper match 5u64 { 0xFFFF_FFFF_FFFF_FFFF ..= 1 => { } + //~^ ERROR lower range bound must be less than or equal to upper _ => { } }; - //~^^^ ERROR lower range bound must be less than or equal to upper - //~| ERROR lower range bound must be less than or equal to upper } diff --git a/tests/ui/match/match-range-fail-2.stderr b/tests/ui/match/match-range-fail-2.stderr index 7a0852d7e6ce6..52a2bf2b34aa6 100644 --- a/tests/ui/match/match-range-fail-2.stderr +++ b/tests/ui/match/match-range-fail-2.stderr @@ -5,36 +5,18 @@ LL | 6 ..= 1 => { } | ^ lower bound larger than upper bound error[E0579]: lower range bound must be less than upper - --> $DIR/match-range-fail-2.rs:12:9 + --> $DIR/match-range-fail-2.rs:11:9 | LL | 0 .. 0 => { } | ^ error[E0030]: lower range bound must be less than or equal to upper - --> $DIR/match-range-fail-2.rs:19:9 + --> $DIR/match-range-fail-2.rs:17:9 | LL | 0xFFFF_FFFF_FFFF_FFFF ..= 1 => { } | ^^^^^^^^^^^^^^^^^^^^^ lower bound larger than upper bound -error[E0030]: lower range bound must be less than or equal to upper - --> $DIR/match-range-fail-2.rs:5:9 - | -LL | 6 ..= 1 => { } - | ^ lower bound larger than upper bound - -error[E0579]: lower range bound must be less than upper - --> $DIR/match-range-fail-2.rs:12:9 - | -LL | 0 .. 0 => { } - | ^ - -error[E0030]: lower range bound must be less than or equal to upper - --> $DIR/match-range-fail-2.rs:19:9 - | -LL | 0xFFFF_FFFF_FFFF_FFFF ..= 1 => { } - | ^^^^^^^^^^^^^^^^^^^^^ lower bound larger than upper bound - -error: aborting due to 6 previous errors +error: aborting due to 3 previous errors Some errors have detailed explanations: E0030, E0579. For more information about an error, try `rustc --explain E0030`. diff --git a/tests/ui/never_type/exhaustive_patterns.stderr b/tests/ui/never_type/exhaustive_patterns.stderr index 40c7c1d1067ff..5fed903eb70ae 100644 --- a/tests/ui/never_type/exhaustive_patterns.stderr +++ b/tests/ui/never_type/exhaustive_patterns.stderr @@ -17,8 +17,8 @@ LL | B(inner::Wrapper), = note: the matched value is of type `Either<(), !>` help: you might want to use `if let` to ignore the variant that isn't matched | -LL | if let Either::A(()) = foo() { todo!() } - | ++ ~~~~~~~~~~~ +LL | if let Either::A(()) = foo() { todo!() }; + | ++ +++++++++++ error: aborting due to previous error diff --git a/tests/ui/or-patterns/exhaustiveness-non-exhaustive.stderr b/tests/ui/or-patterns/exhaustiveness-non-exhaustive.stderr index 9aa808e6bc9a6..9f691aea8a79c 100644 --- a/tests/ui/or-patterns/exhaustiveness-non-exhaustive.stderr +++ b/tests/ui/or-patterns/exhaustiveness-non-exhaustive.stderr @@ -7,7 +7,7 @@ LL | match (0u8, 0u8) { = note: the matched value is of type `(u8, u8)` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | -LL ~ (0 | 1, 2 | 3) => {} +LL ~ (0 | 1, 2 | 3) => {}, LL + (2_u8..=u8::MAX, _) => todo!() | @@ -20,7 +20,7 @@ LL | match ((0u8,),) { = note: the matched value is of type `((u8,),)` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | -LL ~ ((0 | 1,) | (2 | 3,),) => {} +LL ~ ((0 | 1,) | (2 | 3,),) => {}, LL + ((4_u8..=u8::MAX)) => todo!() | @@ -33,7 +33,7 @@ LL | match (Some(0u8),) { = note: the matched value is of type `(Option,)` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | -LL ~ (None | Some(0 | 1),) => {} +LL ~ (None | Some(0 | 1),) => {}, LL + (Some(2_u8..=u8::MAX)) => todo!() | diff --git a/tests/ui/or-patterns/issue-69875-should-have-been-expanded-earlier-non-exhaustive.stderr b/tests/ui/or-patterns/issue-69875-should-have-been-expanded-earlier-non-exhaustive.stderr index 4adcf4feee90d..fdb1a9bb4b78e 100644 --- a/tests/ui/or-patterns/issue-69875-should-have-been-expanded-earlier-non-exhaustive.stderr +++ b/tests/ui/or-patterns/issue-69875-should-have-been-expanded-earlier-non-exhaustive.stderr @@ -9,8 +9,8 @@ LL | let (0 | (1 | 2)) = 0; = note: the matched value is of type `i32` help: you might want to use `if let` to ignore the variants that aren't matched | -LL | if let (0 | (1 | 2)) = 0 { todo!() } - | ++ ~~~~~~~~~~~ +LL | if let (0 | (1 | 2)) = 0 { todo!() }; + | ++ +++++++++++ error[E0004]: non-exhaustive patterns: `i32::MIN..=-1_i32` and `3_i32..=i32::MAX` not covered --> $DIR/issue-69875-should-have-been-expanded-earlier-non-exhaustive.rs:3:11 @@ -21,7 +21,7 @@ LL | match 0 { = note: the matched value is of type `i32` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms | -LL ~ 0 | (1 | 2) => {} +LL ~ 0 | (1 | 2) => {}, LL + i32::MIN..=-1_i32 | 3_i32..=i32::MAX => todo!() | diff --git a/tests/ui/pattern/issue-106552.stderr b/tests/ui/pattern/issue-106552.stderr index ed5d40c096850..96f3d68458fa4 100644 --- a/tests/ui/pattern/issue-106552.stderr +++ b/tests/ui/pattern/issue-106552.stderr @@ -9,8 +9,8 @@ LL | let 5 = 6; = note: the matched value is of type `i32` help: you might want to use `if let` to ignore the variants that aren't matched | -LL | if let 5 = 6 { todo!() } - | ++ ~~~~~~~~~~~ +LL | if let 5 = 6 { todo!() }; + | ++ +++++++++++ help: alternatively, you could prepend the pattern with an underscore to define a new named variable; identifiers cannot begin with digits | LL | let _5 = 6; @@ -20,7 +20,7 @@ error[E0005]: refutable pattern in local binding --> $DIR/issue-106552.rs:5:9 | LL | let x @ 5 = 6; - | ^^^^^ patterns `i32::MIN..=4_i32` and `6_i32..=i32::MAX` not covered + | ^ patterns `i32::MIN..=4_i32` and `6_i32..=i32::MAX` not covered | = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html diff --git a/tests/ui/pattern/issue-68393-let-pat-assoc-constant.stderr b/tests/ui/pattern/issue-68393-let-pat-assoc-constant.stderr index 54ecc24981f80..62c90b638d7c3 100644 --- a/tests/ui/pattern/issue-68393-let-pat-assoc-constant.stderr +++ b/tests/ui/pattern/issue-68393-let-pat-assoc-constant.stderr @@ -1,15 +1,15 @@ -error[E0158]: associated consts cannot be referenced in patterns - --> $DIR/issue-68393-let-pat-assoc-constant.rs:20:40 - | -LL | pub fn test(arg: EFoo, A::X: EFoo) { - | ^^^^ - error[E0158]: associated consts cannot be referenced in patterns --> $DIR/issue-68393-let-pat-assoc-constant.rs:22:9 | LL | let A::X = arg; | ^^^^ +error[E0158]: associated consts cannot be referenced in patterns + --> $DIR/issue-68393-let-pat-assoc-constant.rs:20:40 + | +LL | pub fn test(arg: EFoo, A::X: EFoo) { + | ^^^^ + error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0158`. diff --git a/tests/ui/pattern/suggest-adding-appropriate-missing-pattern-excluding-comments.fixed b/tests/ui/pattern/suggest-adding-appropriate-missing-pattern-excluding-comments.fixed index b28dce8810593..b469fade3ea5e 100644 --- a/tests/ui/pattern/suggest-adding-appropriate-missing-pattern-excluding-comments.fixed +++ b/tests/ui/pattern/suggest-adding-appropriate-missing-pattern-excluding-comments.fixed @@ -4,7 +4,7 @@ fn main() { match Some(1) { //~ ERROR non-exhaustive patterns: `None` not covered Some(1) => {} // hello - Some(_) => {} + Some(_) => {}, None => todo!() } } diff --git a/tests/ui/pattern/suggest-adding-appropriate-missing-pattern-excluding-comments.stderr b/tests/ui/pattern/suggest-adding-appropriate-missing-pattern-excluding-comments.stderr index 2a016048f2f7a..5f2c89246e396 100644 --- a/tests/ui/pattern/suggest-adding-appropriate-missing-pattern-excluding-comments.stderr +++ b/tests/ui/pattern/suggest-adding-appropriate-missing-pattern-excluding-comments.stderr @@ -12,7 +12,7 @@ note: `Option` defined here = note: the matched value is of type `Option` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | -LL ~ Some(_) => {} +LL ~ Some(_) => {}, LL + None => todo!() | diff --git a/tests/ui/pattern/usefulness/consts-opaque.stderr b/tests/ui/pattern/usefulness/consts-opaque.stderr index 08e3d76b538bf..3f0b4a9f26a8f 100644 --- a/tests/ui/pattern/usefulness/consts-opaque.stderr +++ b/tests/ui/pattern/usefulness/consts-opaque.stderr @@ -7,21 +7,6 @@ LL | FOO => {} = note: the traits must be derived, manual `impl`s are not sufficient = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details -error: unreachable pattern - --> $DIR/consts-opaque.rs:32:9 - | -LL | FOO => {} - | --- matches any value -LL | -LL | _ => {} // should not be emitting unreachable warning - | ^ unreachable pattern - | -note: the lint level is defined here - --> $DIR/consts-opaque.rs:6:9 - | -LL | #![deny(unreachable_patterns)] - | ^^^^^^^^^^^^^^^^^^^^ - error: to use a constant of type `Foo` in a pattern, `Foo` must be annotated with `#[derive(PartialEq, Eq)]` --> $DIR/consts-opaque.rs:37:9 | @@ -31,15 +16,6 @@ LL | FOO_REF => {} = note: the traits must be derived, manual `impl`s are not sufficient = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details -error: unreachable pattern - --> $DIR/consts-opaque.rs:39:9 - | -LL | FOO_REF => {} - | ------- matches any value -LL | -LL | Foo(_) => {} // should not be emitting unreachable warning - | ^^^^^^ unreachable pattern - warning: to use a constant of type `Foo` in a pattern, `Foo` must be annotated with `#[derive(PartialEq, Eq)]` --> $DIR/consts-opaque.rs:45:9 | @@ -61,6 +37,84 @@ LL | BAR => {} // should not be emitting unreachable warning = note: the traits must be derived, manual `impl`s are not sufficient = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details +error: to use a constant of type `Bar` in a pattern, `Bar` must be annotated with `#[derive(PartialEq, Eq)]` + --> $DIR/consts-opaque.rs:61:9 + | +LL | BAR => {} + | ^^^ + | + = note: the traits must be derived, manual `impl`s are not sufficient + = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details + +error: to use a constant of type `Bar` in a pattern, `Bar` must be annotated with `#[derive(PartialEq, Eq)]` + --> $DIR/consts-opaque.rs:70:9 + | +LL | BAR => {} + | ^^^ + | + = note: the traits must be derived, manual `impl`s are not sufficient + = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details + +error: to use a constant of type `Bar` in a pattern, `Bar` must be annotated with `#[derive(PartialEq, Eq)]` + --> $DIR/consts-opaque.rs:72:9 + | +LL | BAR => {} // should not be emitting unreachable warning + | ^^^ + | + = note: the traits must be derived, manual `impl`s are not sufficient + = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details + +error: to use a constant of type `Baz` in a pattern, `Baz` must be annotated with `#[derive(PartialEq, Eq)]` + --> $DIR/consts-opaque.rs:80:9 + | +LL | BAZ => {} + | ^^^ + | + = note: the traits must be derived, manual `impl`s are not sufficient + = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details + +error: to use a constant of type `Baz` in a pattern, `Baz` must be annotated with `#[derive(PartialEq, Eq)]` + --> $DIR/consts-opaque.rs:90:9 + | +LL | BAZ => {} + | ^^^ + | + = note: the traits must be derived, manual `impl`s are not sufficient + = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details + +error: to use a constant of type `Baz` in a pattern, `Baz` must be annotated with `#[derive(PartialEq, Eq)]` + --> $DIR/consts-opaque.rs:97:9 + | +LL | BAZ => {} + | ^^^ + | + = note: the traits must be derived, manual `impl`s are not sufficient + = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details + +error: unreachable pattern + --> $DIR/consts-opaque.rs:32:9 + | +LL | FOO => {} + | --- matches any value +LL | +LL | _ => {} // should not be emitting unreachable warning + | ^ unreachable pattern + | +note: the lint level is defined here + --> $DIR/consts-opaque.rs:6:9 + | +LL | #![deny(unreachable_patterns)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: unreachable pattern + --> $DIR/consts-opaque.rs:39:9 + | +LL | FOO_REF => {} + | ------- matches any value +LL | +LL | Foo(_) => {} // should not be emitting unreachable warning + | ^^^^^^ unreachable pattern + error: unreachable pattern --> $DIR/consts-opaque.rs:53:9 | @@ -78,15 +132,6 @@ LL | Bar => {} LL | _ => {} | ^ unreachable pattern -error: to use a constant of type `Bar` in a pattern, `Bar` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/consts-opaque.rs:61:9 - | -LL | BAR => {} - | ^^^ - | - = note: the traits must be derived, manual `impl`s are not sufficient - = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details - error: unreachable pattern --> $DIR/consts-opaque.rs:63:9 | @@ -105,24 +150,6 @@ LL | BAR => {} LL | _ => {} | ^ unreachable pattern -error: to use a constant of type `Bar` in a pattern, `Bar` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/consts-opaque.rs:70:9 - | -LL | BAR => {} - | ^^^ - | - = note: the traits must be derived, manual `impl`s are not sufficient - = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details - -error: to use a constant of type `Bar` in a pattern, `Bar` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/consts-opaque.rs:72:9 - | -LL | BAR => {} // should not be emitting unreachable warning - | ^^^ - | - = note: the traits must be derived, manual `impl`s are not sufficient - = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details - error: unreachable pattern --> $DIR/consts-opaque.rs:72:9 | @@ -141,15 +168,6 @@ LL | BAR => {} LL | _ => {} // should not be emitting unreachable warning | ^ unreachable pattern -error: to use a constant of type `Baz` in a pattern, `Baz` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/consts-opaque.rs:80:9 - | -LL | BAZ => {} - | ^^^ - | - = note: the traits must be derived, manual `impl`s are not sufficient - = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details - error: unreachable pattern --> $DIR/consts-opaque.rs:82:9 | @@ -168,15 +186,6 @@ LL | BAZ => {} LL | _ => {} | ^ unreachable pattern -error: to use a constant of type `Baz` in a pattern, `Baz` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/consts-opaque.rs:90:9 - | -LL | BAZ => {} - | ^^^ - | - = note: the traits must be derived, manual `impl`s are not sufficient - = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details - error: unreachable pattern --> $DIR/consts-opaque.rs:92:9 | @@ -186,15 +195,6 @@ LL | LL | _ => {} | ^ unreachable pattern -error: to use a constant of type `Baz` in a pattern, `Baz` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/consts-opaque.rs:97:9 - | -LL | BAZ => {} - | ^^^ - | - = note: the traits must be derived, manual `impl`s are not sufficient - = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details - error: unreachable pattern --> $DIR/consts-opaque.rs:99:9 | diff --git a/tests/ui/pattern/usefulness/doc-hidden-non-exhaustive.stderr b/tests/ui/pattern/usefulness/doc-hidden-non-exhaustive.stderr index 17e1a2304a13c..ff29de03d6b36 100644 --- a/tests/ui/pattern/usefulness/doc-hidden-non-exhaustive.stderr +++ b/tests/ui/pattern/usefulness/doc-hidden-non-exhaustive.stderr @@ -12,7 +12,7 @@ LL | pub enum HiddenEnum { = note: the matched value is of type `HiddenEnum` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | -LL ~ HiddenEnum::B => {} +LL ~ HiddenEnum::B => {}, LL + _ => todo!() | @@ -33,7 +33,7 @@ LL | B, = note: the matched value is of type `HiddenEnum` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | -LL ~ HiddenEnum::C => {} +LL ~ HiddenEnum::C => {}, LL + HiddenEnum::B => todo!() | @@ -54,7 +54,7 @@ LL | B, = note: the matched value is of type `HiddenEnum` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms | -LL ~ HiddenEnum::A => {} +LL ~ HiddenEnum::A => {}, LL + HiddenEnum::B | _ => todo!() | @@ -72,7 +72,7 @@ note: `Option` defined here = note: the matched value is of type `Option` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms | -LL ~ Some(HiddenEnum::A) => {} +LL ~ Some(HiddenEnum::A) => {}, LL + Some(HiddenEnum::B) | Some(_) => todo!() | @@ -93,7 +93,7 @@ LL | C, = note: the matched value is of type `InCrate` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | -LL ~ InCrate::B => {} +LL ~ InCrate::B => {}, LL + InCrate::C => todo!() | diff --git a/tests/ui/pattern/usefulness/empty-match.exhaustive_patterns.stderr b/tests/ui/pattern/usefulness/empty-match.exhaustive_patterns.stderr index 5e12bc1d22f01..5a145efce9489 100644 --- a/tests/ui/pattern/usefulness/empty-match.exhaustive_patterns.stderr +++ b/tests/ui/pattern/usefulness/empty-match.exhaustive_patterns.stderr @@ -162,7 +162,7 @@ LL | match_guarded_arm!(0u8); = note: the matched value is of type `u8` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | -LL ~ _ if false => {} +LL ~ _ if false => {}, LL + _ => todo!() | @@ -180,7 +180,7 @@ LL | struct NonEmptyStruct1; = note: the matched value is of type `NonEmptyStruct1` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | -LL ~ _ if false => {} +LL ~ _ if false => {}, LL + NonEmptyStruct1 => todo!() | @@ -198,7 +198,7 @@ LL | struct NonEmptyStruct2(bool); = note: the matched value is of type `NonEmptyStruct2` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | -LL ~ _ if false => {} +LL ~ _ if false => {}, LL + NonEmptyStruct2(_) => todo!() | @@ -216,7 +216,7 @@ LL | union NonEmptyUnion1 { = note: the matched value is of type `NonEmptyUnion1` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | -LL ~ _ if false => {} +LL ~ _ if false => {}, LL + NonEmptyUnion1 { .. } => todo!() | @@ -234,7 +234,7 @@ LL | union NonEmptyUnion2 { = note: the matched value is of type `NonEmptyUnion2` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | -LL ~ _ if false => {} +LL ~ _ if false => {}, LL + NonEmptyUnion2 { .. } => todo!() | @@ -254,7 +254,7 @@ LL | Foo(bool), = note: the matched value is of type `NonEmptyEnum1` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | -LL ~ _ if false => {} +LL ~ _ if false => {}, LL + NonEmptyEnum1::Foo(_) => todo!() | @@ -276,7 +276,7 @@ LL | Bar, = note: the matched value is of type `NonEmptyEnum2` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms | -LL ~ _ if false => {} +LL ~ _ if false => {}, LL + NonEmptyEnum2::Foo(_) | NonEmptyEnum2::Bar => todo!() | @@ -294,7 +294,7 @@ LL | enum NonEmptyEnum5 { = note: the matched value is of type `NonEmptyEnum5` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms | -LL ~ _ if false => {} +LL ~ _ if false => {}, LL + _ => todo!() | diff --git a/tests/ui/pattern/usefulness/empty-match.normal.stderr b/tests/ui/pattern/usefulness/empty-match.normal.stderr index 5e12bc1d22f01..5a145efce9489 100644 --- a/tests/ui/pattern/usefulness/empty-match.normal.stderr +++ b/tests/ui/pattern/usefulness/empty-match.normal.stderr @@ -162,7 +162,7 @@ LL | match_guarded_arm!(0u8); = note: the matched value is of type `u8` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | -LL ~ _ if false => {} +LL ~ _ if false => {}, LL + _ => todo!() | @@ -180,7 +180,7 @@ LL | struct NonEmptyStruct1; = note: the matched value is of type `NonEmptyStruct1` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | -LL ~ _ if false => {} +LL ~ _ if false => {}, LL + NonEmptyStruct1 => todo!() | @@ -198,7 +198,7 @@ LL | struct NonEmptyStruct2(bool); = note: the matched value is of type `NonEmptyStruct2` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | -LL ~ _ if false => {} +LL ~ _ if false => {}, LL + NonEmptyStruct2(_) => todo!() | @@ -216,7 +216,7 @@ LL | union NonEmptyUnion1 { = note: the matched value is of type `NonEmptyUnion1` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | -LL ~ _ if false => {} +LL ~ _ if false => {}, LL + NonEmptyUnion1 { .. } => todo!() | @@ -234,7 +234,7 @@ LL | union NonEmptyUnion2 { = note: the matched value is of type `NonEmptyUnion2` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | -LL ~ _ if false => {} +LL ~ _ if false => {}, LL + NonEmptyUnion2 { .. } => todo!() | @@ -254,7 +254,7 @@ LL | Foo(bool), = note: the matched value is of type `NonEmptyEnum1` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | -LL ~ _ if false => {} +LL ~ _ if false => {}, LL + NonEmptyEnum1::Foo(_) => todo!() | @@ -276,7 +276,7 @@ LL | Bar, = note: the matched value is of type `NonEmptyEnum2` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms | -LL ~ _ if false => {} +LL ~ _ if false => {}, LL + NonEmptyEnum2::Foo(_) | NonEmptyEnum2::Bar => todo!() | @@ -294,7 +294,7 @@ LL | enum NonEmptyEnum5 { = note: the matched value is of type `NonEmptyEnum5` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms | -LL ~ _ if false => {} +LL ~ _ if false => {}, LL + _ => todo!() | diff --git a/tests/ui/pattern/usefulness/floats.stderr b/tests/ui/pattern/usefulness/floats.stderr index c926e50b3580b..d66d4ba298bea 100644 --- a/tests/ui/pattern/usefulness/floats.stderr +++ b/tests/ui/pattern/usefulness/floats.stderr @@ -7,7 +7,7 @@ LL | match 0.0 { = note: the matched value is of type `f64` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | -LL ~ 0.0..=1.0 => {} +LL ~ 0.0..=1.0 => {}, LL + _ => todo!() | diff --git a/tests/ui/pattern/usefulness/guards.stderr b/tests/ui/pattern/usefulness/guards.stderr index 0c1563c160c1c..fc6748958de5b 100644 --- a/tests/ui/pattern/usefulness/guards.stderr +++ b/tests/ui/pattern/usefulness/guards.stderr @@ -7,7 +7,7 @@ LL | match 0u8 { = note: the matched value is of type `u8` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | -LL ~ 128 ..= 255 if true => {} +LL ~ 128 ..= 255 if true => {}, LL + 128_u8..=u8::MAX => todo!() | diff --git a/tests/ui/pattern/usefulness/integer-ranges/exhaustiveness.stderr b/tests/ui/pattern/usefulness/integer-ranges/exhaustiveness.stderr index f30ba05dff9e4..b585de2062913 100644 --- a/tests/ui/pattern/usefulness/integer-ranges/exhaustiveness.stderr +++ b/tests/ui/pattern/usefulness/integer-ranges/exhaustiveness.stderr @@ -91,7 +91,7 @@ LL | match 0i8 { = note: the matched value is of type `i8` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | -LL ~ 1 ..= i8::MAX => {} +LL ~ 1 ..= i8::MAX => {}, LL + 0_i8 => todo!() | @@ -140,7 +140,7 @@ LL | match (0u8, true) { = note: the matched value is of type `(u8, bool)` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | -LL ~ (0 ..= 255, true) => {} +LL ~ (0 ..= 255, true) => {}, LL + (126_u8..=127_u8, false) => todo!() | diff --git a/tests/ui/pattern/usefulness/integer-ranges/pointer-sized-int.deny.stderr b/tests/ui/pattern/usefulness/integer-ranges/pointer-sized-int.deny.stderr index e3eb98ccdcda5..0e0f0c3e11ee8 100644 --- a/tests/ui/pattern/usefulness/integer-ranges/pointer-sized-int.deny.stderr +++ b/tests/ui/pattern/usefulness/integer-ranges/pointer-sized-int.deny.stderr @@ -9,7 +9,7 @@ LL | match 0usize { = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | -LL ~ 0 ..= usize::MAX => {} +LL ~ 0 ..= usize::MAX => {}, LL + _ => todo!() | @@ -24,7 +24,7 @@ LL | match 0isize { = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | -LL ~ isize::MIN ..= isize::MAX => {} +LL ~ isize::MIN ..= isize::MAX => {}, LL + _ => todo!() | @@ -147,7 +147,7 @@ LL | match 0isize { = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | -LL ~ 1 ..= isize::MAX => {} +LL ~ 1 ..= isize::MAX => {}, LL + _ => todo!() | diff --git a/tests/ui/pattern/usefulness/integer-ranges/precise_pointer_matching-message.stderr b/tests/ui/pattern/usefulness/integer-ranges/precise_pointer_matching-message.stderr index 30492c98206c9..b80411b26b049 100644 --- a/tests/ui/pattern/usefulness/integer-ranges/precise_pointer_matching-message.stderr +++ b/tests/ui/pattern/usefulness/integer-ranges/precise_pointer_matching-message.stderr @@ -9,7 +9,7 @@ LL | match 0usize { = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | -LL ~ 0..=usize::MAX => {} +LL ~ 0..=usize::MAX => {}, LL + _ => todo!() | @@ -24,7 +24,7 @@ LL | match 0isize { = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | -LL ~ isize::MIN..=isize::MAX => {} +LL ~ isize::MIN..=isize::MAX => {}, LL + _ => todo!() | diff --git a/tests/ui/pattern/usefulness/issue-2111.stderr b/tests/ui/pattern/usefulness/issue-2111.stderr index 01890b73cbdd8..7f7c5a0f19def 100644 --- a/tests/ui/pattern/usefulness/issue-2111.stderr +++ b/tests/ui/pattern/usefulness/issue-2111.stderr @@ -7,7 +7,7 @@ LL | match (a, b) { = note: the matched value is of type `(Option, Option)` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms | -LL ~ (Some(_), None) | (None, Some(_)) => {} +LL ~ (Some(_), None) | (None, Some(_)) => {}, LL + (None, None) | (Some(_), Some(_)) => todo!() | diff --git a/tests/ui/pattern/usefulness/issue-30240.stderr b/tests/ui/pattern/usefulness/issue-30240.stderr index 759fdeafe4eb5..ff755d681ac73 100644 --- a/tests/ui/pattern/usefulness/issue-30240.stderr +++ b/tests/ui/pattern/usefulness/issue-30240.stderr @@ -7,7 +7,7 @@ LL | match "world" { = note: the matched value is of type `&str` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | -LL ~ "hello" => {} +LL ~ "hello" => {}, LL + &_ => todo!() | @@ -20,7 +20,7 @@ LL | match "world" { = note: the matched value is of type `&str` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | -LL ~ "hello" => {} +LL ~ "hello" => {}, LL + &_ => todo!() | diff --git a/tests/ui/pattern/usefulness/issue-35609.stderr b/tests/ui/pattern/usefulness/issue-35609.stderr index 12113957d6340..6d5e2f410bc97 100644 --- a/tests/ui/pattern/usefulness/issue-35609.stderr +++ b/tests/ui/pattern/usefulness/issue-35609.stderr @@ -7,7 +7,7 @@ LL | match (A, ()) { = note: the matched value is of type `(Enum, ())` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms | -LL ~ (A, _) => {} +LL ~ (A, _) => {}, LL + _ => todo!() | @@ -20,7 +20,7 @@ LL | match (A, A) { = note: the matched value is of type `(Enum, Enum)` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms | -LL ~ (_, A) => {} +LL ~ (_, A) => {}, LL + _ => todo!() | @@ -33,7 +33,7 @@ LL | match ((A, ()), ()) { = note: the matched value is of type `((Enum, ()), ())` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms | -LL ~ ((A, ()), _) => {} +LL ~ ((A, ()), _) => {}, LL + _ => todo!() | @@ -46,7 +46,7 @@ LL | match ((A, ()), A) { = note: the matched value is of type `((Enum, ()), Enum)` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms | -LL ~ ((A, ()), _) => {} +LL ~ ((A, ()), _) => {}, LL + _ => todo!() | @@ -59,7 +59,7 @@ LL | match ((A, ()), ()) { = note: the matched value is of type `((Enum, ()), ())` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms | -LL ~ ((A, _), _) => {} +LL ~ ((A, _), _) => {}, LL + _ => todo!() | @@ -77,7 +77,7 @@ LL | struct S(Enum, ()); = note: the matched value is of type `S` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms | -LL ~ S(A, _) => {} +LL ~ S(A, _) => {}, LL + _ => todo!() | @@ -95,7 +95,7 @@ LL | struct Sd { x: Enum, y: () } = note: the matched value is of type `Sd` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms | -LL ~ Sd { x: A, y: _ } => {} +LL ~ Sd { x: A, y: _ } => {}, LL + _ => todo!() | diff --git a/tests/ui/pattern/usefulness/issue-3601.stderr b/tests/ui/pattern/usefulness/issue-3601.stderr index 59d7bcd4b5e79..2f6b167d4f8bd 100644 --- a/tests/ui/pattern/usefulness/issue-3601.stderr +++ b/tests/ui/pattern/usefulness/issue-3601.stderr @@ -9,7 +9,7 @@ note: `Box` defined here = note: the matched value is of type `Box` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | -LL ~ box ElementKind::HTMLImageElement(ref d) if d.image.is_some() => { true } +LL ~ box ElementKind::HTMLImageElement(ref d) if d.image.is_some() => { true }, LL + box _ => todo!() | diff --git a/tests/ui/pattern/usefulness/issue-50900.stderr b/tests/ui/pattern/usefulness/issue-50900.stderr index 348246d28aaca..7880c89256714 100644 --- a/tests/ui/pattern/usefulness/issue-50900.stderr +++ b/tests/ui/pattern/usefulness/issue-50900.stderr @@ -12,7 +12,7 @@ LL | pub struct Tag(pub Context, pub u16); = note: the matched value is of type `Tag` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | -LL ~ Tag::ExifIFDPointer => {} +LL ~ Tag::ExifIFDPointer => {}, LL + Tag(Context::Exif, _) => todo!() | diff --git a/tests/ui/pattern/usefulness/issue-56379.stderr b/tests/ui/pattern/usefulness/issue-56379.stderr index 6eed6bfae4c90..b3e40b992399a 100644 --- a/tests/ui/pattern/usefulness/issue-56379.stderr +++ b/tests/ui/pattern/usefulness/issue-56379.stderr @@ -18,7 +18,7 @@ LL | C(bool), = note: the matched value is of type `Foo` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms | -LL ~ Foo::C(true) => {} +LL ~ Foo::C(true) => {}, LL + Foo::A(false) | Foo::B(false) | Foo::C(false) => todo!() | diff --git a/tests/ui/pattern/usefulness/match-byte-array-patterns-2.stderr b/tests/ui/pattern/usefulness/match-byte-array-patterns-2.stderr index a90f32f7aebf3..3c482eef21059 100644 --- a/tests/ui/pattern/usefulness/match-byte-array-patterns-2.stderr +++ b/tests/ui/pattern/usefulness/match-byte-array-patterns-2.stderr @@ -7,7 +7,7 @@ LL | match buf { = note: the matched value is of type `&[u8; 4]` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms | -LL ~ b"AAAA" => {} +LL ~ b"AAAA" => {}, LL + &[0_u8..=64_u8, _, _, _] | &[66_u8..=u8::MAX, _, _, _] => todo!() | @@ -20,7 +20,7 @@ LL | match buf { = note: the matched value is of type `&[u8]` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms | -LL ~ b"AAAA" => {} +LL ~ b"AAAA" => {}, LL + _ => todo!() | diff --git a/tests/ui/pattern/usefulness/match-privately-empty.stderr b/tests/ui/pattern/usefulness/match-privately-empty.stderr index 86f75d15cfde7..45352f09417f0 100644 --- a/tests/ui/pattern/usefulness/match-privately-empty.stderr +++ b/tests/ui/pattern/usefulness/match-privately-empty.stderr @@ -12,7 +12,7 @@ note: `Option` defined here = note: the matched value is of type `Option` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | -LL ~ }) => {} +LL ~ }) => {}, LL + Some(Private { misc: true, .. }) => todo!() | diff --git a/tests/ui/pattern/usefulness/match-slice-patterns.stderr b/tests/ui/pattern/usefulness/match-slice-patterns.stderr index 961dd59011961..63d1f38e9db43 100644 --- a/tests/ui/pattern/usefulness/match-slice-patterns.stderr +++ b/tests/ui/pattern/usefulness/match-slice-patterns.stderr @@ -7,7 +7,7 @@ LL | match list { = note: the matched value is of type `&[Option<()>]` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | -LL ~ &[.., Some(_), _] => {} +LL ~ &[.., Some(_), _] => {}, LL ~ &[_, Some(_), .., None, _] => todo!(), | diff --git a/tests/ui/pattern/usefulness/non-exhaustive-defined-here.stderr b/tests/ui/pattern/usefulness/non-exhaustive-defined-here.stderr index 769d4070fb587..8489e2f14b871 100644 --- a/tests/ui/pattern/usefulness/non-exhaustive-defined-here.stderr +++ b/tests/ui/pattern/usefulness/non-exhaustive-defined-here.stderr @@ -18,7 +18,7 @@ LL | C = note: the matched value is of type `E` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms | -LL ~ E::A => {} +LL ~ E::A => {}, LL + E::B | E::C => todo!() | @@ -44,8 +44,8 @@ LL | C = note: the matched value is of type `E` help: you might want to use `if let` to ignore the variants that aren't matched | -LL | if let E::A = e { todo!() } - | ++ ~~~~~~~~~~~ +LL | if let E::A = e { todo!() }; + | ++ +++++++++++ error[E0004]: non-exhaustive patterns: `&E::B` and `&E::C` not covered --> $DIR/non-exhaustive-defined-here.rs:50:11 @@ -67,7 +67,7 @@ LL | C = note: the matched value is of type `&E` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms | -LL ~ E::A => {} +LL ~ E::A => {}, LL + &E::B | &E::C => todo!() | @@ -93,8 +93,8 @@ LL | C = note: the matched value is of type `&E` help: you might want to use `if let` to ignore the variants that aren't matched | -LL | if let E::A = e { todo!() } - | ++ ~~~~~~~~~~~ +LL | if let E::A = e { todo!() }; + | ++ +++++++++++ error[E0004]: non-exhaustive patterns: `&&mut &E::B` and `&&mut &E::C` not covered --> $DIR/non-exhaustive-defined-here.rs:66:11 @@ -116,7 +116,7 @@ LL | C = note: the matched value is of type `&&mut &E` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms | -LL ~ E::A => {} +LL ~ E::A => {}, LL + &&mut &E::B | &&mut &E::C => todo!() | @@ -142,8 +142,8 @@ LL | C = note: the matched value is of type `&&mut &E` help: you might want to use `if let` to ignore the variants that aren't matched | -LL | if let E::A = e { todo!() } - | ++ ~~~~~~~~~~~ +LL | if let E::A = e { todo!() }; + | ++ +++++++++++ error[E0004]: non-exhaustive patterns: `Opt::None` not covered --> $DIR/non-exhaustive-defined-here.rs:92:11 @@ -162,7 +162,7 @@ LL | None, = note: the matched value is of type `Opt` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | -LL ~ Opt::Some(ref _x) => {} +LL ~ Opt::Some(ref _x) => {}, LL + Opt::None => todo!() | diff --git a/tests/ui/pattern/usefulness/non-exhaustive-match-nested.stderr b/tests/ui/pattern/usefulness/non-exhaustive-match-nested.stderr index 44f327421109a..98e417a17f860 100644 --- a/tests/ui/pattern/usefulness/non-exhaustive-match-nested.stderr +++ b/tests/ui/pattern/usefulness/non-exhaustive-match-nested.stderr @@ -25,7 +25,7 @@ LL | enum T { A(U), B } = note: the matched value is of type `T` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | -LL ~ T::B => { panic!("goodbye"); } +LL ~ T::B => { panic!("goodbye"); }, LL + T::A(U::C) => todo!() | diff --git a/tests/ui/pattern/usefulness/non-exhaustive-match.stderr b/tests/ui/pattern/usefulness/non-exhaustive-match.stderr index e2260f50bfef2..e59e8885e1a48 100644 --- a/tests/ui/pattern/usefulness/non-exhaustive-match.stderr +++ b/tests/ui/pattern/usefulness/non-exhaustive-match.stderr @@ -24,7 +24,7 @@ LL | match true { = note: the matched value is of type `bool` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | -LL ~ true => {} +LL ~ true => {}, LL + false => todo!() | @@ -42,7 +42,7 @@ note: `Option` defined here = note: the matched value is of type `Option` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | -LL ~ None => {} +LL ~ None => {}, LL + Some(_) => todo!() | @@ -55,7 +55,7 @@ LL | match (2, 3, 4) { = note: the matched value is of type `(i32, i32, i32)` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms | -LL ~ (_, _, 4) => {} +LL ~ (_, _, 4) => {}, LL + (_, _, i32::MIN..=3_i32) | (_, _, 5_i32..=i32::MAX) => todo!() | @@ -68,7 +68,7 @@ LL | match (T::A, T::A) { = note: the matched value is of type `(T, T)` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms | -LL ~ (T::B, T::A) => {} +LL ~ (T::B, T::A) => {}, LL + (T::A, T::A) | (T::B, T::B) => todo!() | @@ -86,7 +86,7 @@ LL | enum T { A, B } = note: the matched value is of type `T` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | -LL ~ T::A => {} +LL ~ T::A => {}, LL + T::B => todo!() | @@ -99,7 +99,7 @@ LL | match *vec { = note: the matched value is of type `[Option]` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | -LL ~ [None] => {} +LL ~ [None] => {}, LL + [] => todo!() | diff --git a/tests/ui/pattern/usefulness/refutable-pattern-errors.stderr b/tests/ui/pattern/usefulness/refutable-pattern-errors.stderr index c518de47740dd..beb51a4d45043 100644 --- a/tests/ui/pattern/usefulness/refutable-pattern-errors.stderr +++ b/tests/ui/pattern/usefulness/refutable-pattern-errors.stderr @@ -17,8 +17,8 @@ LL | let (1, (Some(1), 2..=3)) = (1, (None, 2)); = note: the matched value is of type `(i32, (Option, i32))` help: you might want to use `if let` to ignore the variants that aren't matched | -LL | if let (1, (Some(1), 2..=3)) = (1, (None, 2)) { todo!() } - | ++ ~~~~~~~~~~~ +LL | if let (1, (Some(1), 2..=3)) = (1, (None, 2)) { todo!() }; + | ++ +++++++++++ error: aborting due to 2 previous errors diff --git a/tests/ui/pattern/usefulness/slice-patterns-exhaustiveness.stderr b/tests/ui/pattern/usefulness/slice-patterns-exhaustiveness.stderr index 5d1e170ae6c2b..fb6ecda3c4dff 100644 --- a/tests/ui/pattern/usefulness/slice-patterns-exhaustiveness.stderr +++ b/tests/ui/pattern/usefulness/slice-patterns-exhaustiveness.stderr @@ -7,7 +7,7 @@ LL | match s2 { = note: the matched value is of type `&[bool; 2]` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | -LL ~ [true, .., true] => {} +LL ~ [true, .., true] => {}, LL + &[false, _] => todo!() | @@ -20,7 +20,7 @@ LL | match s3 { = note: the matched value is of type `&[bool; 3]` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | -LL ~ [true, .., true] => {} +LL ~ [true, .., true] => {}, LL + &[false, ..] => todo!() | @@ -33,7 +33,7 @@ LL | match s10 { = note: the matched value is of type `&[bool; 10]` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | -LL ~ [true, .., true] => {} +LL ~ [true, .., true] => {}, LL + &[false, ..] => todo!() | @@ -46,7 +46,7 @@ LL | match s2 { = note: the matched value is of type `&[bool; 2]` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | -LL ~ [.., false] => {} +LL ~ [.., false] => {}, LL + &[false, true] => todo!() | @@ -59,7 +59,7 @@ LL | match s3 { = note: the matched value is of type `&[bool; 3]` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | -LL ~ [.., false] => {} +LL ~ [.., false] => {}, LL + &[false, .., true] => todo!() | @@ -72,7 +72,7 @@ LL | match s { = note: the matched value is of type `&[bool]` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | -LL ~ [.., false] => {} +LL ~ [.., false] => {}, LL + &[false, .., true] => todo!() | @@ -85,7 +85,7 @@ LL | match s { = note: the matched value is of type `&[bool]` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | -LL ~ [] => {} +LL ~ [] => {}, LL + &[_, ..] => todo!() | @@ -98,7 +98,7 @@ LL | match s { = note: the matched value is of type `&[bool]` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | -LL ~ [_] => {} +LL ~ [_] => {}, LL + &[_, _, ..] => todo!() | @@ -111,7 +111,7 @@ LL | match s { = note: the matched value is of type `&[bool]` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | -LL ~ [true, ..] => {} +LL ~ [true, ..] => {}, LL + &[false, ..] => todo!() | @@ -124,7 +124,7 @@ LL | match s { = note: the matched value is of type `&[bool]` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | -LL ~ [true, ..] => {} +LL ~ [true, ..] => {}, LL + &[false, _, ..] => todo!() | @@ -137,7 +137,7 @@ LL | match s { = note: the matched value is of type `&[bool]` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | -LL ~ [.., true] => {} +LL ~ [.., true] => {}, LL + &[_, .., false] => todo!() | @@ -150,7 +150,7 @@ LL | match s { = note: the matched value is of type `&[bool]` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | -LL ~ [.., false] => {} +LL ~ [.., false] => {}, LL + &[_, _, .., true] => todo!() | @@ -163,7 +163,7 @@ LL | match s { = note: the matched value is of type `&[bool]` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | -LL ~ [false, .., false] => {} +LL ~ [false, .., false] => {}, LL + &[true, _, .., _] => todo!() | @@ -176,7 +176,7 @@ LL | match s { = note: the matched value is of type `&[bool]` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms | -LL ~ &[true] => {} +LL ~ &[true] => {}, LL + &[] | &[_, _, ..] => todo!() | @@ -189,7 +189,7 @@ LL | match s { = note: the matched value is of type `&[bool]` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms | -LL ~ CONST => {} +LL ~ CONST => {}, LL + &[] | &[_, _, ..] => todo!() | @@ -202,7 +202,7 @@ LL | match s { = note: the matched value is of type `&[bool]` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms | -LL ~ &[false] => {} +LL ~ &[false] => {}, LL + &[] | &[_, _, ..] => todo!() | @@ -215,7 +215,7 @@ LL | match s { = note: the matched value is of type `&[bool]` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms | -LL ~ CONST => {} +LL ~ CONST => {}, LL + &[] | &[_, _, ..] => todo!() | @@ -228,7 +228,7 @@ LL | match s { = note: the matched value is of type `&[bool]` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | -LL ~ CONST => {} +LL ~ CONST => {}, LL + &[_, _, ..] => todo!() | @@ -241,7 +241,7 @@ LL | match s { = note: the matched value is of type `&[bool]` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | -LL ~ &[_, _, ..] => {} +LL ~ &[_, _, ..] => {}, LL + &[false] => todo!() | @@ -254,7 +254,7 @@ LL | match s1 { = note: the matched value is of type `&[bool; 1]` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | -LL ~ CONST1 => {} +LL ~ CONST1 => {}, LL + &[false] => todo!() | diff --git a/tests/ui/pattern/usefulness/stable-gated-patterns.stderr b/tests/ui/pattern/usefulness/stable-gated-patterns.stderr index 7b8588a3c7350..f944c25a905c4 100644 --- a/tests/ui/pattern/usefulness/stable-gated-patterns.stderr +++ b/tests/ui/pattern/usefulness/stable-gated-patterns.stderr @@ -15,7 +15,7 @@ LL | Stable2, = note: the matched value is of type `UnstableEnum` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms | -LL ~ UnstableEnum::Stable => {} +LL ~ UnstableEnum::Stable => {}, LL + UnstableEnum::Stable2 | _ => todo!() | @@ -33,7 +33,7 @@ LL | pub enum UnstableEnum { = note: the matched value is of type `UnstableEnum` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | -LL ~ UnstableEnum::Stable2 => {} +LL ~ UnstableEnum::Stable2 => {}, LL + _ => todo!() | diff --git a/tests/ui/pattern/usefulness/struct-like-enum-nonexhaustive.stderr b/tests/ui/pattern/usefulness/struct-like-enum-nonexhaustive.stderr index 85c97be29d6d7..22425aa0dd4dd 100644 --- a/tests/ui/pattern/usefulness/struct-like-enum-nonexhaustive.stderr +++ b/tests/ui/pattern/usefulness/struct-like-enum-nonexhaustive.stderr @@ -14,7 +14,7 @@ LL | B { x: Option }, = note: the matched value is of type `A` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | -LL ~ A::B { x: None } => {} +LL ~ A::B { x: None } => {}, LL + A::B { x: Some(_) } => todo!() | diff --git a/tests/ui/pattern/usefulness/unstable-gated-patterns.stderr b/tests/ui/pattern/usefulness/unstable-gated-patterns.stderr index 6dc9a40583985..d776249b23181 100644 --- a/tests/ui/pattern/usefulness/unstable-gated-patterns.stderr +++ b/tests/ui/pattern/usefulness/unstable-gated-patterns.stderr @@ -15,7 +15,7 @@ LL | Unstable, = note: the matched value is of type `UnstableEnum` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | -LL ~ UnstableEnum::Stable2 => {} +LL ~ UnstableEnum::Stable2 => {}, LL + UnstableEnum::Unstable => todo!() | diff --git a/tests/ui/range/range-pattern-out-of-bounds-issue-68972.rs b/tests/ui/range/range-pattern-out-of-bounds-issue-68972.rs index d02caff1febd2..206f05d0d3caf 100644 --- a/tests/ui/range/range-pattern-out-of-bounds-issue-68972.rs +++ b/tests/ui/range/range-pattern-out-of-bounds-issue-68972.rs @@ -4,10 +4,8 @@ fn main() { match 0u8 { 251..257 => {} //~^ ERROR literal out of range - //~| ERROR literal out of range 251..=256 => {} //~^ ERROR literal out of range - //~| ERROR literal out of range _ => {} } } diff --git a/tests/ui/range/range-pattern-out-of-bounds-issue-68972.stderr b/tests/ui/range/range-pattern-out-of-bounds-issue-68972.stderr index 7b8309b9bc2a1..4f3f9d1eb3a76 100644 --- a/tests/ui/range/range-pattern-out-of-bounds-issue-68972.stderr +++ b/tests/ui/range/range-pattern-out-of-bounds-issue-68972.stderr @@ -5,22 +5,10 @@ LL | 251..257 => {} | ^^^ this value doesn't fit in `u8` whose maximum value is `255` error: literal out of range for `u8` - --> $DIR/range-pattern-out-of-bounds-issue-68972.rs:8:15 + --> $DIR/range-pattern-out-of-bounds-issue-68972.rs:7:15 | LL | 251..=256 => {} | ^^^ this value doesn't fit in `u8` whose maximum value is `255` -error: literal out of range for `u8` - --> $DIR/range-pattern-out-of-bounds-issue-68972.rs:5:14 - | -LL | 251..257 => {} - | ^^^ this value doesn't fit in `u8` whose maximum value is `255` - -error: literal out of range for `u8` - --> $DIR/range-pattern-out-of-bounds-issue-68972.rs:8:15 - | -LL | 251..=256 => {} - | ^^^ this value doesn't fit in `u8` whose maximum value is `255` - -error: aborting due to 4 previous errors +error: aborting due to 2 previous errors diff --git a/tests/ui/rfc-2005-default-binding-mode/slice.stderr b/tests/ui/rfc-2005-default-binding-mode/slice.stderr index 60c1f5420f62c..5b51dc5acc4e4 100644 --- a/tests/ui/rfc-2005-default-binding-mode/slice.stderr +++ b/tests/ui/rfc-2005-default-binding-mode/slice.stderr @@ -7,7 +7,7 @@ LL | match sl { = note: the matched value is of type `&[u8]` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | -LL ~ [first, remainder @ ..] => {} +LL ~ [first, remainder @ ..] => {}, LL ~ &[] => todo!(), | diff --git a/tests/ui/suggestions/const-pat-non-exaustive-let-new-var.rs b/tests/ui/suggestions/const-pat-non-exaustive-let-new-var.rs index 15f08486f0f0e..0b7eb3ee605b1 100644 --- a/tests/ui/suggestions/const-pat-non-exaustive-let-new-var.rs +++ b/tests/ui/suggestions/const-pat-non-exaustive-let-new-var.rs @@ -2,10 +2,7 @@ fn main() { let A = 3; //~^ ERROR refutable pattern in local binding //~| patterns `i32::MIN..=1_i32` and `3_i32..=i32::MAX` not covered - //~| missing patterns are not covered because `a` is interpreted as a constant pattern, not a new variable - //~| HELP introduce a variable instead - //~| SUGGESTION a_var + //~| HELP you might want to use `if let` to ignore the variants that aren't matched const A: i32 = 2; - //~^ constant defined here } diff --git a/tests/ui/suggestions/const-pat-non-exaustive-let-new-var.stderr b/tests/ui/suggestions/const-pat-non-exaustive-let-new-var.stderr index 1c1cab25fbfaf..b112e3a11757e 100644 --- a/tests/ui/suggestions/const-pat-non-exaustive-let-new-var.stderr +++ b/tests/ui/suggestions/const-pat-non-exaustive-let-new-var.stderr @@ -2,16 +2,15 @@ error[E0005]: refutable pattern in local binding --> $DIR/const-pat-non-exaustive-let-new-var.rs:2:9 | LL | let A = 3; - | ^ - | | - | patterns `i32::MIN..=1_i32` and `3_i32..=i32::MAX` not covered - | missing patterns are not covered because `a` is interpreted as a constant pattern, not a new variable - | help: introduce a variable instead: `a_var` -... -LL | const A: i32 = 2; - | ------------ constant defined here + | ^ patterns `i32::MIN..=1_i32` and `3_i32..=i32::MAX` not covered | + = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant + = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html = note: the matched value is of type `i32` +help: you might want to use `if let` to ignore the variants that aren't matched + | +LL | if let A = 3 { todo!() }; + | ++ +++++++++++ error: aborting due to previous error From 4240a0bed0943cd3fa003e7951d91ab8a37ff8e3 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 26 Feb 2023 20:42:46 +0000 Subject: [PATCH 05/13] Cleanup PatCtxt. --- .../src/thir/pattern/const_to_pat.rs | 33 ++++------ .../rustc_mir_build/src/thir/pattern/mod.rs | 63 ++++--------------- 2 files changed, 23 insertions(+), 73 deletions(-) diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index 2dbef740d1a6e..32d0404bd0739 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -59,8 +59,6 @@ struct ConstToPat<'tcx> { // inference context used for checking `T: Structural` bounds. infcx: InferCtxt<'tcx>, - include_lint_checks: bool, - treat_byte_string_as_slice: bool, } @@ -93,7 +91,6 @@ impl<'tcx> ConstToPat<'tcx> { span, infcx, param_env: pat_ctxt.param_env, - include_lint_checks: pat_ctxt.include_lint_checks, saw_const_match_error: Cell::new(false), saw_const_match_lint: Cell::new(false), behind_reference: Cell::new(false), @@ -134,7 +131,7 @@ impl<'tcx> ConstToPat<'tcx> { }) }); - if self.include_lint_checks && !self.saw_const_match_error.get() { + if !self.saw_const_match_error.get() { // If we were able to successfully convert the const to some pat, // double-check that all types in the const implement `Structural`. @@ -239,21 +236,19 @@ impl<'tcx> ConstToPat<'tcx> { let kind = match cv.ty().kind() { ty::Float(_) => { - if self.include_lint_checks { tcx.emit_spanned_lint( lint::builtin::ILLEGAL_FLOATING_POINT_LITERAL_PATTERN, id, span, FloatPattern, ); - } PatKind::Constant { value: cv } } ty::Adt(adt_def, _) if adt_def.is_union() => { // Matching on union fields is unsafe, we can't hide it in constants self.saw_const_match_error.set(true); let err = UnionPattern { span }; - tcx.sess.create_err(err).emit_unless(!self.include_lint_checks); + tcx.sess.emit_err(err); PatKind::Wild } ty::Adt(..) @@ -267,7 +262,7 @@ impl<'tcx> ConstToPat<'tcx> { { self.saw_const_match_error.set(true); let err = TypeNotStructural { span, non_sm_ty }; - tcx.sess.create_err(err).emit_unless(!self.include_lint_checks); + tcx.sess.emit_err(err); PatKind::Wild } // If the type is not structurally comparable, just emit the constant directly, @@ -280,8 +275,7 @@ impl<'tcx> ConstToPat<'tcx> { // Backwards compatibility hack because we can't cause hard errors on these // types, so we compare them via `PartialEq::eq` at runtime. ty::Adt(..) if !self.type_marked_structural(cv.ty()) && self.behind_reference.get() => { - if self.include_lint_checks - && !self.saw_const_match_error.get() + if !self.saw_const_match_error.get() && !self.saw_const_match_lint.get() { self.saw_const_match_lint.set(true); @@ -305,7 +299,7 @@ impl<'tcx> ConstToPat<'tcx> { ); self.saw_const_match_error.set(true); let err = TypeNotStructural { span, non_sm_ty: cv.ty() }; - tcx.sess.create_err(err).emit_unless(!self.include_lint_checks); + tcx.sess.emit_err(err); PatKind::Wild } ty::Adt(adt_def, substs) if adt_def.is_enum() => { @@ -339,7 +333,7 @@ impl<'tcx> ConstToPat<'tcx> { ty::Dynamic(..) => { self.saw_const_match_error.set(true); let err = InvalidPattern { span, non_sm_ty: cv.ty() }; - tcx.sess.create_err(err).emit_unless(!self.include_lint_checks); + tcx.sess.emit_err(err); PatKind::Wild } // `&str` is represented as `ConstValue::Slice`, let's keep using this @@ -406,8 +400,7 @@ impl<'tcx> ConstToPat<'tcx> { // to figure out how to get a reference again. ty::Adt(_, _) if !self.type_marked_structural(*pointee_ty) => { if self.behind_reference.get() { - if self.include_lint_checks - && !self.saw_const_match_error.get() + if !self.saw_const_match_error.get() && !self.saw_const_match_lint.get() { self.saw_const_match_lint.set(true); @@ -423,7 +416,7 @@ impl<'tcx> ConstToPat<'tcx> { if !self.saw_const_match_error.get() { self.saw_const_match_error.set(true); let err = TypeNotStructural { span, non_sm_ty: *pointee_ty }; - tcx.sess.create_err(err).emit_unless(!self.include_lint_checks); + tcx.sess.emit_err(err); } PatKind::Wild } @@ -437,7 +430,7 @@ impl<'tcx> ConstToPat<'tcx> { // (except slices, which are handled in a separate arm above). let err = UnsizedPattern { span, non_sm_ty: *pointee_ty }; - tcx.sess.create_err(err).emit_unless(!self.include_lint_checks); + tcx.sess.emit_err(err); PatKind::Wild } else { @@ -465,8 +458,7 @@ impl<'tcx> ConstToPat<'tcx> { // compilation choices change the runtime behaviour of the match. // See https://github.com/rust-lang/rust/issues/70861 for examples. ty::FnPtr(..) | ty::RawPtr(..) => { - if self.include_lint_checks - && !self.saw_const_match_error.get() + if !self.saw_const_match_error.get() && !self.saw_const_match_lint.get() { self.saw_const_match_lint.set(true); @@ -482,13 +474,12 @@ impl<'tcx> ConstToPat<'tcx> { _ => { self.saw_const_match_error.set(true); let err = InvalidPattern { span, non_sm_ty: cv.ty() }; - tcx.sess.create_err(err).emit_unless(!self.include_lint_checks); + tcx.sess.emit_err(err); PatKind::Wild } }; - if self.include_lint_checks - && !self.saw_const_match_error.get() + if !self.saw_const_match_error.get() && !self.saw_const_match_lint.get() && mir_structural_match_violation // FIXME(#73448): Find a way to bring const qualification into parity with diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 6e201b771ec6e..70d015a39e4e2 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -31,20 +31,10 @@ use rustc_target::abi::FieldIdx; use std::cmp::Ordering; -#[derive(Clone, Debug)] -enum PatternError { - AssocConstInPattern(Span), - ConstParamInPattern(Span), - StaticInPattern(Span), - NonConstPath(Span), -} - struct PatCtxt<'a, 'tcx> { tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, typeck_results: &'a ty::TypeckResults<'tcx>, - errors: Vec, - include_lint_checks: bool, } pub(super) fn pat_from_hir<'a, 'tcx>( @@ -53,47 +43,13 @@ pub(super) fn pat_from_hir<'a, 'tcx>( typeck_results: &'a ty::TypeckResults<'tcx>, pat: &'tcx hir::Pat<'tcx>, ) -> Box> { - let mut pcx = PatCtxt::new(tcx, param_env, typeck_results); - pcx.include_lint_checks(); + let mut pcx = PatCtxt { tcx, param_env, typeck_results }; let result = pcx.lower_pattern(pat); - pcx.report_inlining_errors(); debug!("pat_from_hir({:?}) = {:?}", pat, result); result } impl<'a, 'tcx> PatCtxt<'a, 'tcx> { - fn new( - tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, - typeck_results: &'a ty::TypeckResults<'tcx>, - ) -> Self { - PatCtxt { tcx, param_env, typeck_results, errors: vec![], include_lint_checks: false } - } - - fn include_lint_checks(&mut self) -> &mut Self { - self.include_lint_checks = true; - self - } - - fn report_inlining_errors(&self) { - for error in &self.errors { - match *error { - PatternError::StaticInPattern(span) => { - self.tcx.sess.emit_err(StaticInPattern { span }); - } - PatternError::AssocConstInPattern(span) => { - self.tcx.sess.emit_err(AssocConstInPattern { span }); - } - PatternError::ConstParamInPattern(span) => { - self.tcx.sess.emit_err(ConstParamInPattern { span }); - } - PatternError::NonConstPath(span) => { - self.tcx.sess.emit_err(NonConstPath { span }); - } - } - } - } - fn lower_pattern(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Box> { // When implicit dereferences have been inserted in this pattern, the unadjusted lowered // pattern has the type that results *after* dereferencing. For example, in this code: @@ -490,12 +446,15 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { | Res::SelfTyAlias { .. } | Res::SelfCtor(..) => PatKind::Leaf { subpatterns }, _ => { - let pattern_error = match res { - Res::Def(DefKind::ConstParam, _) => PatternError::ConstParamInPattern(span), - Res::Def(DefKind::Static(_), _) => PatternError::StaticInPattern(span), - _ => PatternError::NonConstPath(span), + match res { + Res::Def(DefKind::ConstParam, _) => { + self.tcx.sess.emit_err(ConstParamInPattern { span }) + } + Res::Def(DefKind::Static(_), _) => { + self.tcx.sess.emit_err(StaticInPattern { span }) + } + _ => self.tcx.sess.emit_err(NonConstPath { span }), }; - self.errors.push(pattern_error); PatKind::Wild } }; @@ -548,7 +507,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { // It should be assoc consts if there's no error but we cannot resolve it. debug_assert!(is_associated_const); - self.errors.push(PatternError::AssocConstInPattern(span)); + self.tcx.sess.emit_err(AssocConstInPattern { span }); return pat_from_kind(PatKind::Wild); } @@ -626,7 +585,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { match value { mir::ConstantKind::Ty(c) => match c.kind() { ConstKind::Param(_) => { - self.errors.push(PatternError::ConstParamInPattern(span)); + self.tcx.sess.emit_err(ConstParamInPattern { span }); return PatKind::Wild; } ConstKind::Error(_) => { From 5d8161c570ac1d6298ee2d0a78c527d120ab9f02 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Mon, 27 Feb 2023 18:12:16 +0000 Subject: [PATCH 06/13] Hide warning. --- compiler/rustc_middle/src/dep_graph/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_middle/src/dep_graph/mod.rs b/compiler/rustc_middle/src/dep_graph/mod.rs index 84510fe218cf5..0ddbe7d1c2922 100644 --- a/compiler/rustc_middle/src/dep_graph/mod.rs +++ b/compiler/rustc_middle/src/dep_graph/mod.rs @@ -94,7 +94,7 @@ impl<'tcx> DepContext for TyCtxt<'tcx> { } #[inline] - fn dep_kind_info(&self, dep_kind: DepKind) -> &DepKindStruct<'tcx> { - &self.query_kinds[dep_kind as usize] + fn dep_kind_info(&self, dk: DepKind) -> &DepKindStruct<'tcx> { + &self.query_kinds[dk as usize] } } From 4d8ed585f2ba5ce3f5a1208dc19c9b07ba0b0cee Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Mon, 27 Feb 2023 19:09:13 +0000 Subject: [PATCH 07/13] Bless mir-opt. --- ...ic.FOO-promoted[0].SimplifyCfg-elaborate-drops.after.mir | 6 +++--- .../const_promotion_extern_static.FOO.PromoteTemps.diff | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/mir-opt/const_promotion_extern_static.FOO-promoted[0].SimplifyCfg-elaborate-drops.after.mir b/tests/mir-opt/const_promotion_extern_static.FOO-promoted[0].SimplifyCfg-elaborate-drops.after.mir index 41657b53fc12c..19daae86589cd 100644 --- a/tests/mir-opt/const_promotion_extern_static.FOO-promoted[0].SimplifyCfg-elaborate-drops.after.mir +++ b/tests/mir-opt/const_promotion_extern_static.FOO-promoted[0].SimplifyCfg-elaborate-drops.after.mir @@ -7,10 +7,10 @@ promoted[0] in FOO: &[&i32; 1] = { let mut _3: *const i32; // in scope 0 at $DIR/const_promotion_extern_static.rs:+0:42: +0:43 bb0: { - _3 = const {alloc3: *const i32}; // scope 0 at $DIR/const_promotion_extern_static.rs:+0:42: +0:43 + _3 = const {alloc2: *const i32}; // scope 0 at $DIR/const_promotion_extern_static.rs:+0:42: +0:43 // mir::Constant // + span: $DIR/const_promotion_extern_static.rs:13:42: 13:43 - // + literal: Const { ty: *const i32, val: Value(Scalar(alloc3)) } + // + literal: Const { ty: *const i32, val: Value(Scalar(alloc2)) } _2 = &(*_3); // scope 0 at $DIR/const_promotion_extern_static.rs:+0:41: +0:43 _1 = [move _2]; // scope 0 at $DIR/const_promotion_extern_static.rs:+0:31: +0:46 _0 = &_1; // scope 0 at $DIR/const_promotion_extern_static.rs:+0:31: +0:55 @@ -18,4 +18,4 @@ promoted[0] in FOO: &[&i32; 1] = { } } -alloc3 (extern static: X) +alloc2 (extern static: X) diff --git a/tests/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff b/tests/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff index 25ba0face6bd8..5b13d60052fe1 100644 --- a/tests/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff +++ b/tests/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff @@ -18,11 +18,11 @@ - StorageLive(_3); // scope 0 at $DIR/const_promotion_extern_static.rs:+0:31: +0:46 - StorageLive(_4); // scope 0 at $DIR/const_promotion_extern_static.rs:+0:32: +0:45 - StorageLive(_5); // scope 1 at $DIR/const_promotion_extern_static.rs:+0:42: +0:43 -- _5 = const {alloc3: *const i32}; // scope 1 at $DIR/const_promotion_extern_static.rs:+0:42: +0:43 +- _5 = const {alloc2: *const i32}; // scope 1 at $DIR/const_promotion_extern_static.rs:+0:42: +0:43 + _6 = const _; // scope 0 at $DIR/const_promotion_extern_static.rs:+0:31: +0:55 // mir::Constant - // + span: $DIR/const_promotion_extern_static.rs:13:42: 13:43 -- // + literal: Const { ty: *const i32, val: Value(Scalar(alloc3)) } +- // + literal: Const { ty: *const i32, val: Value(Scalar(alloc2)) } - _4 = &(*_5); // scope 1 at $DIR/const_promotion_extern_static.rs:+0:41: +0:43 - _3 = [move _4]; // scope 0 at $DIR/const_promotion_extern_static.rs:+0:31: +0:46 - _2 = &_3; // scope 0 at $DIR/const_promotion_extern_static.rs:+0:31: +0:55 @@ -50,5 +50,5 @@ } } - -- alloc3 (extern static: X) +- alloc2 (extern static: X) From 4f97540432445c7e0dc4eb51e3ac5fd915d225ad Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Mon, 27 Feb 2023 20:50:01 +0000 Subject: [PATCH 08/13] Reinstate confusion note. --- compiler/rustc_mir_build/messages.ftl | 4 +- compiler/rustc_mir_build/src/errors.rs | 13 ------ .../src/thir/pattern/check_match.rs | 42 +++++++++++-------- tests/ui/consts/const-pattern-irrefutable.rs | 9 ++-- .../consts/const-pattern-irrefutable.stderr | 34 +++++++-------- .../refutable-pattern-in-fn-arg.stderr | 4 ++ .../const-pat-non-exaustive-let-new-var.rs | 4 +- ...const-pat-non-exaustive-let-new-var.stderr | 10 ++--- 8 files changed, 61 insertions(+), 59 deletions(-) diff --git a/compiler/rustc_mir_build/messages.ftl b/compiler/rustc_mir_build/messages.ftl index c8172219267ff..f346cd4834702 100644 --- a/compiler/rustc_mir_build/messages.ftl +++ b/compiler/rustc_mir_build/messages.ftl @@ -347,15 +347,13 @@ mir_build_inform_irrefutable = `let` bindings require an "irrefutable pattern", mir_build_more_information = for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html -mir_build_res_defined_here = {$res} defined here - mir_build_adt_defined_here = `{$ty}` defined here mir_build_variant_defined_here = not covered mir_build_interpreted_as_const = introduce a variable instead -mir_build_confused = missing patterns are not covered because `{$variable}` is interpreted as {$article} {$res} pattern, not a new variable +mir_build_confused = missing patterns are not covered because `{$variable}` is interpreted as a constant pattern, not a new variable mir_build_suggest_if_let = you might want to use `if let` to ignore the {$count -> [one] variant that isn't diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs index c67a002dce1db..6a05f35bdf330 100644 --- a/compiler/rustc_mir_build/src/errors.rs +++ b/compiler/rustc_mir_build/src/errors.rs @@ -6,7 +6,6 @@ use rustc_errors::{ error_code, AddToDiagnostic, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, Handler, IntoDiagnostic, MultiSpan, SubdiagnosticMessage, }; -use rustc_hir::def::Res; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; use rustc_middle::thir::Pat; use rustc_middle::ty::{self, Ty}; @@ -795,8 +794,6 @@ pub(crate) struct PatternNotCovered<'s, 'tcx> { pub let_suggestion: Option, #[subdiagnostic] pub misc_suggestion: Option, - #[subdiagnostic] - pub res_defined_here: Option, } #[derive(Subdiagnostic)] @@ -830,14 +827,6 @@ impl<'tcx> AddToDiagnostic for AdtDefinedHere<'tcx> { } } -#[derive(Subdiagnostic)] -#[label(mir_build_res_defined_here)] -pub struct ResDefinedHere { - #[primary_span] - pub def_span: Span, - pub res: Res, -} - #[derive(Subdiagnostic)] #[suggestion( mir_build_interpreted_as_const, @@ -848,9 +837,7 @@ pub struct ResDefinedHere { pub struct InterpretedAsConst { #[primary_span] pub span: Span, - pub article: &'static str, pub variable: String, - pub res: Res, } #[derive(Subdiagnostic)] diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index b1f85f039893d..4fb8e915220a1 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -424,29 +424,38 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { let inform = sp.is_some().then_some(Inform); let mut let_suggestion = None; let mut misc_suggestion = None; - if let Some(span) = sp && self.tcx.sess.source_map().is_span_accessible(span) { - let mut bindings= vec![]; - pat.each_binding(|name, _, _, _| { - bindings.push(name); - }); - let semi_span = span.shrink_to_hi(); - let start_span = span.shrink_to_lo(); - let end_span = semi_span.shrink_to_lo(); - let count = witnesses.len(); - + let mut interpreted_as_const = None; + if let PatKind::Constant { .. } = pat.kind + && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(pat.span) + { // If the pattern to match is an integer literal: - if bindings.is_empty() - && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(pat.span) - && snippet.chars().all(|c| c.is_digit(10)) - { + if snippet.chars().all(|c| c.is_digit(10)) { // Then give a suggestion, the user might've meant to create a binding instead. misc_suggestion = Some(MiscPatternSuggestion::AttemptedIntegerLiteral { start_span: pat.span.shrink_to_lo() }); + } else if snippet.chars().all(|c| c.is_alphanumeric() || c == '_') { + interpreted_as_const = Some(InterpretedAsConst { + span: pat.span, + variable: snippet, + }); } + } + + if let Some(span) = sp + && self.tcx.sess.source_map().is_span_accessible(span) + && interpreted_as_const.is_none() + { + let mut bindings = vec![]; + pat.each_binding(|name, _, _, _| bindings.push(name)); + + let semi_span = span.shrink_to_hi(); + let start_span = span.shrink_to_lo(); + let end_span = semi_span.shrink_to_lo(); + let count = witnesses.len(); let_suggestion = Some(if bindings.is_empty() { - SuggestLet::If {start_span, semi_span, count } + SuggestLet::If { start_span, semi_span, count } } else { SuggestLet::Else { end_span, count } }); @@ -469,12 +478,11 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { origin, uncovered: Uncovered::new(pat.span, &cx, witnesses), inform, - interpreted_as_const: None, + interpreted_as_const, _p: (), pattern_ty, let_suggestion, misc_suggestion, - res_defined_here: None, adt_defined_here, }); } diff --git a/tests/ui/consts/const-pattern-irrefutable.rs b/tests/ui/consts/const-pattern-irrefutable.rs index d7d8e7328397c..61bdf57ffdb94 100644 --- a/tests/ui/consts/const-pattern-irrefutable.rs +++ b/tests/ui/consts/const-pattern-irrefutable.rs @@ -12,14 +12,17 @@ fn main() { let a = 4; //~^ ERROR refutable pattern in local binding //~| patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered - //~| HELP you might want to use `if let` to ignore the variants that aren't matched + //~| missing patterns are not covered because `a` is interpreted as a constant pattern, not a new variable + //~| HELP introduce a variable instead let c = 4; //~^ ERROR refutable pattern in local binding //~| patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered - //~| HELP you might want to use `if let` to ignore the variants that aren't matched + //~| missing patterns are not covered because `c` is interpreted as a constant pattern, not a new variable + //~| HELP introduce a variable instead let d = 4; //~^ ERROR refutable pattern in local binding //~| patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered - //~| HELP you might want to use `if let` to ignore the variants that aren't matched + //~| missing patterns are not covered because `d` is interpreted as a constant pattern, not a new variable + //~| HELP introduce a variable instead fn f() {} // Check that the `NOTE`s still work with an item here (cf. issue #35115). } diff --git a/tests/ui/consts/const-pattern-irrefutable.stderr b/tests/ui/consts/const-pattern-irrefutable.stderr index 956a97a476c10..2aed68bdd6433 100644 --- a/tests/ui/consts/const-pattern-irrefutable.stderr +++ b/tests/ui/consts/const-pattern-irrefutable.stderr @@ -2,43 +2,43 @@ error[E0005]: refutable pattern in local binding --> $DIR/const-pattern-irrefutable.rs:12:9 | LL | let a = 4; - | ^ patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered + | ^ + | | + | patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered + | missing patterns are not covered because `a` is interpreted as a constant pattern, not a new variable + | help: introduce a variable instead: `a_var` | = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html = note: the matched value is of type `u8` -help: you might want to use `if let` to ignore the variants that aren't matched - | -LL | if let a = 4 { todo!() }; - | ++ +++++++++++ error[E0005]: refutable pattern in local binding - --> $DIR/const-pattern-irrefutable.rs:16:9 + --> $DIR/const-pattern-irrefutable.rs:17:9 | LL | let c = 4; - | ^ patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered + | ^ + | | + | patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered + | missing patterns are not covered because `c` is interpreted as a constant pattern, not a new variable + | help: introduce a variable instead: `c_var` | = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html = note: the matched value is of type `u8` -help: you might want to use `if let` to ignore the variants that aren't matched - | -LL | if let c = 4 { todo!() }; - | ++ +++++++++++ error[E0005]: refutable pattern in local binding - --> $DIR/const-pattern-irrefutable.rs:20:9 + --> $DIR/const-pattern-irrefutable.rs:22:9 | LL | let d = 4; - | ^ patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered + | ^ + | | + | patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered + | missing patterns are not covered because `d` is interpreted as a constant pattern, not a new variable + | help: introduce a variable instead: `d_var` | = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html = note: the matched value is of type `u8` -help: you might want to use `if let` to ignore the variants that aren't matched - | -LL | if let d = 4 { todo!() }; - | ++ +++++++++++ error: aborting due to 3 previous errors diff --git a/tests/ui/pattern/usefulness/refutable-pattern-in-fn-arg.stderr b/tests/ui/pattern/usefulness/refutable-pattern-in-fn-arg.stderr index 55f0b2319fb7f..ab3f6f69fb161 100644 --- a/tests/ui/pattern/usefulness/refutable-pattern-in-fn-arg.stderr +++ b/tests/ui/pattern/usefulness/refutable-pattern-in-fn-arg.stderr @@ -5,6 +5,10 @@ LL | let f = |3: isize| println!("hello"); | ^ pattern `_` not covered | = note: the matched value is of type `isize` +help: alternatively, you could prepend the pattern with an underscore to define a new named variable; identifiers cannot begin with digits + | +LL | let f = |_3: isize| println!("hello"); + | + error: aborting due to previous error diff --git a/tests/ui/suggestions/const-pat-non-exaustive-let-new-var.rs b/tests/ui/suggestions/const-pat-non-exaustive-let-new-var.rs index 0b7eb3ee605b1..af47ba8baa3fe 100644 --- a/tests/ui/suggestions/const-pat-non-exaustive-let-new-var.rs +++ b/tests/ui/suggestions/const-pat-non-exaustive-let-new-var.rs @@ -2,7 +2,9 @@ fn main() { let A = 3; //~^ ERROR refutable pattern in local binding //~| patterns `i32::MIN..=1_i32` and `3_i32..=i32::MAX` not covered - //~| HELP you might want to use `if let` to ignore the variants that aren't matched + //~| missing patterns are not covered because `A` is interpreted as a constant pattern, not a new variable + //~| HELP introduce a variable instead + //~| SUGGESTION A_var const A: i32 = 2; } diff --git a/tests/ui/suggestions/const-pat-non-exaustive-let-new-var.stderr b/tests/ui/suggestions/const-pat-non-exaustive-let-new-var.stderr index b112e3a11757e..9ee3e6eb2c827 100644 --- a/tests/ui/suggestions/const-pat-non-exaustive-let-new-var.stderr +++ b/tests/ui/suggestions/const-pat-non-exaustive-let-new-var.stderr @@ -2,15 +2,15 @@ error[E0005]: refutable pattern in local binding --> $DIR/const-pat-non-exaustive-let-new-var.rs:2:9 | LL | let A = 3; - | ^ patterns `i32::MIN..=1_i32` and `3_i32..=i32::MAX` not covered + | ^ + | | + | patterns `i32::MIN..=1_i32` and `3_i32..=i32::MAX` not covered + | missing patterns are not covered because `A` is interpreted as a constant pattern, not a new variable + | help: introduce a variable instead: `A_var` | = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html = note: the matched value is of type `i32` -help: you might want to use `if let` to ignore the variants that aren't matched - | -LL | if let A = 3 { todo!() }; - | ++ +++++++++++ error: aborting due to previous error From e73aeeaeeee456b58f3d45041d4169318c2b7130 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Wed, 1 Mar 2023 21:40:56 +0000 Subject: [PATCH 09/13] Remove redundant field. --- compiler/rustc_mir_build/src/errors.rs | 1 - .../rustc_mir_build/src/thir/pattern/check_match.rs | 13 ++++--------- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs index 6a05f35bdf330..431c3255ab2ac 100644 --- a/compiler/rustc_mir_build/src/errors.rs +++ b/compiler/rustc_mir_build/src/errors.rs @@ -576,7 +576,6 @@ pub struct IrrefutableLetPatternsWhileLet { #[diag(mir_build_borrow_of_moved_value)] pub struct BorrowOfMovedValue<'tcx> { #[primary_span] - pub span: Span, #[label] #[label(mir_build_occurs_because_label)] pub binding_span: Span, diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index 4fb8e915220a1..534d236030b51 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -900,7 +900,6 @@ fn maybe_point_at_variant<'a, 'p: 'a, 'tcx: 'a>( fn check_borrow_conflicts_in_at_patterns<'tcx>(cx: &MatchVisitor<'_, '_, 'tcx>, pat: &Pat<'tcx>) { // Extract `sub` in `binding @ sub`. let PatKind::Binding { name, mode, ty, subpattern: Some(box ref sub), .. } = pat.kind else { return }; - let binding_span = pat.span; //.with_hi(name.span.hi()); let is_binding_by_move = |ty: Ty<'tcx>| !ty.is_copy_modulo_regions(cx.tcx, cx.param_env); @@ -917,15 +916,11 @@ fn check_borrow_conflicts_in_at_patterns<'tcx>(cx: &MatchVisitor<'_, '_, 'tcx>, }); if !conflicts_ref.is_empty() { sess.emit_err(BorrowOfMovedValue { - span: pat.span, - binding_span, + binding_span: pat.span, conflicts_ref, name, ty, - suggest_borrowing: pat - .span - .contains(binding_span) - .then(|| binding_span.shrink_to_lo()), + suggest_borrowing: Some(pat.span.shrink_to_lo()), }); } return; @@ -967,8 +962,8 @@ fn check_borrow_conflicts_in_at_patterns<'tcx>(cx: &MatchVisitor<'_, '_, 'tcx>, let report_move_conflict = !conflicts_move.is_empty(); let mut occurences = match mut_outer { - Mutability::Mut => vec![Conflict::Mut { span: binding_span, name }], - Mutability::Not => vec![Conflict::Ref { span: binding_span, name }], + Mutability::Mut => vec![Conflict::Mut { span: pat.span, name }], + Mutability::Not => vec![Conflict::Ref { span: pat.span, name }], }; occurences.extend(conflicts_mut_mut); occurences.extend(conflicts_mut_ref); From 03fbb3db1e3dd767caebe176a368e0e52aeb68cb Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Wed, 1 Mar 2023 21:43:39 +0000 Subject: [PATCH 10/13] Expand parameters. --- .../src/thir/pattern/check_match.rs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index 534d236030b51..de63e07b7d577 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -144,8 +144,8 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for MatchVisitor<'a, '_, 'tcx> { ExprKind::Let { box ref pat, expr } => { self.check_let(pat, expr, self.let_source, ex.span); } - ExprKind::LogicalOp { op: LogicalOp::And, .. } => { - self.check_let_chain(ex, self.let_source); + ExprKind::LogicalOp { op: LogicalOp::And, lhs, rhs } => { + self.check_let_chain(self.let_source, ex.span, lhs, rhs); } _ => {} }; @@ -296,13 +296,17 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { } #[instrument(level = "trace", skip(self))] - fn check_let_chain(&mut self, top_expr: &Expr<'tcx>, let_source: LetSource) { + fn check_let_chain( + &mut self, + let_source: LetSource, + top_expr_span: Span, + mut lhs: ExprId, + rhs: ExprId, + ) { if let LetSource::None = let_source { return; } - let ExprKind::LogicalOp { op: LogicalOp::And, mut lhs, rhs } = top_expr.kind else { bug!() }; - // Lint level enclosing the next `lhs`. let mut cur_lint_level = self.lint_level; @@ -367,7 +371,7 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { self.lint_level, let_source, chain_refutabilities.len(), - top_expr.span, + top_expr_span, ); return; } From 03a6ef67fe72c58d976c3e83ffab2296179ae8a4 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Mon, 3 Apr 2023 16:13:06 +0000 Subject: [PATCH 11/13] Only emit lint on refutable patterns. --- .../rustc_mir_build/src/thir/pattern/check_match.rs | 11 ++++++----- .../rustc_mir_build/src/thir/pattern/usefulness.rs | 7 ++++--- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index de63e07b7d577..0882b473f1087 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -199,12 +199,13 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { cx.pattern_arena.alloc(DeconstructedPat::from_pat(cx, &pattern)) } - fn new_cx(&self, hir_id: HirId) -> MatchCheckCtxt<'p, 'tcx> { + fn new_cx(&self, hir_id: HirId, refutable: bool) -> MatchCheckCtxt<'p, 'tcx> { MatchCheckCtxt { tcx: self.tcx, param_env: self.param_env, module: self.tcx.parent_module(hir_id).to_def_id(), pattern_arena: &self.pattern_arena, + refutable, } } @@ -214,7 +215,7 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { return; } self.check_patterns(pat, Refutable); - let mut cx = self.new_cx(self.lint_level); + let mut cx = self.new_cx(self.lint_level, true); let tpat = self.lower_pattern(&mut cx, pat); self.check_let_reachability(&mut cx, self.lint_level, source, tpat, span); } @@ -226,7 +227,7 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { source: hir::MatchSource, expr_span: Span, ) { - let mut cx = self.new_cx(self.lint_level); + let mut cx = self.new_cx(self.lint_level, true); for &arm in arms { // Check the arm for some things unrelated to exhaustiveness. @@ -328,7 +329,7 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { debug!(?expr, ?local_lint_level, "after scopes"); match expr.kind { ExprKind::Let { box ref pat, expr: _ } => { - let mut ncx = self.new_cx(local_lint_level); + let mut ncx = self.new_cx(local_lint_level, true); let tpat = self.lower_pattern(&mut ncx, pat); let refutable = !is_let_irrefutable(&mut ncx, local_lint_level, tpat); Some((expr.span, refutable)) @@ -409,7 +410,7 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { #[instrument(level = "trace", skip(self))] fn check_irrefutable(&self, pat: &Pat<'tcx>, origin: &str, sp: Option) { - let mut cx = self.new_cx(self.lint_level); + let mut cx = self.new_cx(self.lint_level, false); let pattern = self.lower_pattern(&mut cx, pat); let pattern_ty = pattern.ty(); diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs index 9edd7967e7a4a..8c89bcb8cec8f 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs @@ -300,7 +300,6 @@ use rustc_arena::TypedArena; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir::def_id::DefId; use rustc_hir::HirId; -use rustc_hir::Node; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_session::lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS; use rustc_span::{Span, DUMMY_SP}; @@ -319,6 +318,8 @@ pub(crate) struct MatchCheckCtxt<'p, 'tcx> { pub(crate) module: DefId, pub(crate) param_env: ty::ParamEnv<'tcx>, pub(crate) pattern_arena: &'p TypedArena>, + /// Only produce `NON_EXHAUSTIVE_OMITTED_PATTERNS` lint on refutable patterns. + pub(crate) refutable: bool, } impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> { @@ -860,6 +861,8 @@ fn is_useful<'p, 'tcx>( // that has the potential to trigger the `non_exhaustive_omitted_patterns` lint. // To understand the workings checkout `Constructor::split` and `SplitWildcard::new/into_ctors` if is_non_exhaustive_and_wild + // Only emit a lint on refutable patterns. + && cx.refutable // We check that the match has a wildcard pattern and that wildcard is useful, // meaning there are variants that are covered by the wildcard. Without the check // for `witness_preference` the lint would trigger on `if let NonExhaustiveEnum::A = foo {}` @@ -868,8 +871,6 @@ fn is_useful<'p, 'tcx>( &ctor, Constructor::Missing { nonexhaustive_enum_missing_real_variants: true } ) - // We don't want to lint patterns which are function arguments or locals - && !matches!(cx.tcx.hir().find_parent(hir_id), Some(Node::Param(_)|Node::Local(_))) { let patterns = { let mut split_wildcard = SplitWildcard::new(pcx); From a8187f8cb136eb5d27f00ec68ef3f7e213f8154d Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Mon, 3 Apr 2023 16:13:24 +0000 Subject: [PATCH 12/13] Rename hir_id to lint_root. --- .../src/thir/pattern/deconstruct_pat.rs | 4 ++-- .../src/thir/pattern/usefulness.rs | 24 ++++++++++++------- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs index e619e095496bc..54bcb2d62c4b0 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs @@ -258,7 +258,7 @@ impl IntRange { pcx: &PatCtxt<'_, 'p, 'tcx>, pats: impl Iterator>, column_count: usize, - hir_id: HirId, + lint_root: HirId, ) { if self.is_singleton() { return; @@ -290,7 +290,7 @@ impl IntRange { if !overlap.is_empty() { pcx.cx.tcx.emit_spanned_lint( lint::builtin::OVERLAPPING_RANGE_ENDPOINTS, - hir_id, + lint_root, pcx.span, OverlappingRangeEndpoints { overlap, range: pcx.span }, ); diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs index 8c89bcb8cec8f..7b06498919d3f 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs @@ -766,13 +766,13 @@ impl<'p, 'tcx> Witness<'p, 'tcx> { /// `is_under_guard` is used to inform if the pattern has a guard. If it /// has one it must not be inserted into the matrix. This shouldn't be /// relied on for soundness. -#[instrument(level = "debug", skip(cx, matrix, hir_id), ret)] +#[instrument(level = "debug", skip(cx, matrix, lint_root), ret)] fn is_useful<'p, 'tcx>( cx: &MatchCheckCtxt<'p, 'tcx>, matrix: &Matrix<'p, 'tcx>, v: &PatStack<'p, 'tcx>, witness_preference: ArmType, - hir_id: HirId, + lint_root: HirId, is_under_guard: bool, is_top_level: bool, ) -> Usefulness<'p, 'tcx> { @@ -805,7 +805,7 @@ fn is_useful<'p, 'tcx>( for v in v.expand_or_pat() { debug!(?v); let usefulness = ensure_sufficient_stack(|| { - is_useful(cx, &matrix, &v, witness_preference, hir_id, is_under_guard, false) + is_useful(cx, &matrix, &v, witness_preference, lint_root, is_under_guard, false) }); debug!(?usefulness); ret.extend(usefulness); @@ -838,7 +838,7 @@ fn is_useful<'p, 'tcx>( pcx, matrix.heads(), matrix.column_count().unwrap_or(0), - hir_id, + lint_root, ) } // We split the head constructor of `v`. @@ -853,7 +853,15 @@ fn is_useful<'p, 'tcx>( let spec_matrix = start_matrix.specialize_constructor(pcx, &ctor); let v = v.pop_head_constructor(pcx, &ctor); let usefulness = ensure_sufficient_stack(|| { - is_useful(cx, &spec_matrix, &v, witness_preference, hir_id, is_under_guard, false) + is_useful( + cx, + &spec_matrix, + &v, + witness_preference, + lint_root, + is_under_guard, + false, + ) }); let usefulness = usefulness.apply_constructor(pcx, start_matrix, &ctor); @@ -897,7 +905,7 @@ fn is_useful<'p, 'tcx>( // NB: The partner lint for structs lives in `compiler/rustc_hir_analysis/src/check/pat.rs`. cx.tcx.emit_spanned_lint( NON_EXHAUSTIVE_OMITTED_PATTERNS, - hir_id, + lint_root, pcx.span, NonExhaustiveOmittedPattern { scrut_ty: pcx.ty, @@ -955,7 +963,7 @@ pub(crate) struct UsefulnessReport<'p, 'tcx> { pub(crate) fn compute_match_usefulness<'p, 'tcx>( cx: &MatchCheckCtxt<'p, 'tcx>, arms: &[MatchArm<'p, 'tcx>], - scrut_hir_id: HirId, + lint_root: HirId, scrut_ty: Ty<'tcx>, ) -> UsefulnessReport<'p, 'tcx> { let mut matrix = Matrix::empty(); @@ -980,7 +988,7 @@ pub(crate) fn compute_match_usefulness<'p, 'tcx>( let wild_pattern = cx.pattern_arena.alloc(DeconstructedPat::wildcard(scrut_ty)); let v = PatStack::from_pattern(wild_pattern); - let usefulness = is_useful(cx, &matrix, &v, FakeExtraWildcard, scrut_hir_id, false, true); + let usefulness = is_useful(cx, &matrix, &v, FakeExtraWildcard, lint_root, false, true); let non_exhaustiveness_witnesses = match usefulness { WithWitnesses(pats) => pats.into_iter().map(|w| w.single_pattern()).collect(), NoWitnesses { .. } => bug!(), From 1dde34b831089a7acbb14e47810b356bbe951301 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Mon, 3 Apr 2023 16:14:27 +0000 Subject: [PATCH 13/13] Bless ui test. --- tests/ui/rfc-2008-non-exhaustive/omitted-patterns.stderr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ui/rfc-2008-non-exhaustive/omitted-patterns.stderr b/tests/ui/rfc-2008-non-exhaustive/omitted-patterns.stderr index 617c629a4fe07..4cdda732a9168 100644 --- a/tests/ui/rfc-2008-non-exhaustive/omitted-patterns.stderr +++ b/tests/ui/rfc-2008-non-exhaustive/omitted-patterns.stderr @@ -188,7 +188,7 @@ error[E0005]: refutable pattern in local binding --> $DIR/omitted-patterns.rs:194:9 | LL | let local_refutable @ NonExhaustiveEnum::Unit = NonExhaustiveEnum::Unit; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `_` not covered + | ^^^^^^^^^^^^^^^ pattern `_` not covered | = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html