From 1028c7a66a718a6421241b3a46268681f79fd597 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maja=20K=C4=85dzio=C5=82ka?= Date: Sun, 11 Jan 2026 20:10:22 +0100 Subject: [PATCH] Avoid ICEs after bad patterns, for the other syntactic variants --- compiler/rustc_hir_typeck/src/pat.rs | 13 +++--- tests/ui/pattern/type_mismatch.rs | 63 ++++++++++++++++++++++++++- tests/ui/pattern/type_mismatch.stderr | 61 +++++++++++++++++++++++++- 3 files changed, 128 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 90e22b2cd381a..b56ab6dcb4ab2 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -1512,11 +1512,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pat_info: PatInfo<'tcx>, ) -> Ty<'tcx> { // Type-check the path. - let _ = self.demand_eqtype_pat(pat.span, expected, pat_ty, &pat_info.top_info); + let had_err = self.demand_eqtype_pat(pat.span, expected, pat_ty, &pat_info.top_info); // Type-check subpatterns. match self.check_struct_pat_fields(pat_ty, pat, variant, fields, has_rest_pat, pat_info) { - Ok(()) => pat_ty, + Ok(()) => match had_err { + Ok(()) => pat_ty, + Err(guar) => Ty::new_error(self.tcx, guar), + }, Err(guar) => Ty::new_error(self.tcx, guar), } } @@ -1764,8 +1767,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; // Type-check the tuple struct pattern against the expected type. - let diag = self.demand_eqtype_pat_diag(pat.span, expected, pat_ty, &pat_info.top_info); - let had_err = diag.map_err(|diag| diag.emit()); + let had_err = self.demand_eqtype_pat(pat.span, expected, pat_ty, &pat_info.top_info); // Type-check subpatterns. if subpats.len() == variant.fields.len() @@ -1989,11 +1991,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let Err(reported) = self.demand_eqtype_pat(span, expected, pat_ty, &pat_info.top_info) { // Walk subpatterns with an expected type of `err` in this case to silence // further errors being emitted when using the bindings. #50333 - let element_tys_iter = (0..max_len).map(|_| Ty::new_error(tcx, reported)); for (_, elem) in elements.iter().enumerate_and_adjust(max_len, ddpos) { self.check_pat(elem, Ty::new_error(tcx, reported), pat_info); } - Ty::new_tup_from_iter(tcx, element_tys_iter) + Ty::new_error(tcx, reported) } else { for (i, elem) in elements.iter().enumerate_and_adjust(max_len, ddpos) { self.check_pat(elem, element_tys[i], pat_info); diff --git a/tests/ui/pattern/type_mismatch.rs b/tests/ui/pattern/type_mismatch.rs index 408ff75884712..39d57301e98fe 100644 --- a/tests/ui/pattern/type_mismatch.rs +++ b/tests/ui/pattern/type_mismatch.rs @@ -1,4 +1,4 @@ -//! This test used to ICE: rust-lang/rust#109812 +//! These tests used to ICE: rust-lang/rust#109812, rust-lang/rust#150507 //! Instead of actually analyzing the erroneous patterns, //! we instead stop after typeck where errors are already //! reported. @@ -8,12 +8,21 @@ enum Either { One(X), Two(X), + Three { a: X }, } struct X(Y); struct Y; +struct Z(*const i32); +unsafe impl Send for Z {} + +enum Meow { + A { a: Z }, + B(Z), +} + fn consume_fnmut(_: impl FnMut()) {} fn move_into_fnmut() { @@ -25,6 +34,58 @@ fn move_into_fnmut() { let X(mut _t) = x; }); + + consume_fnmut(|| { + let Either::Three { a: ref mut _t } = x; + //~^ ERROR: mismatched types + + let X(mut _t) = x; + }); +} + +fn tuple_against_array() { + let variant: [();1] = [()]; + + || match variant { + (2,) => (), + //~^ ERROR: mismatched types + _ => {} + }; + + || { + let ((2,) | _) = variant; + //~^ ERROR: mismatched types + }; +} + +// Reproducer that triggers the compatibility lint more reliably, instead of relying on the fact +// that at the time of writing, an unresolved integer type variable does not implement any +// auto-traits. +// +// The @_ makes this example also reproduce ICE #150507 before PR #138961 +fn arcane() { + let variant: [();1] = [()]; + + || { + match variant { + (Z(y@_),) => {} + //~^ ERROR: mismatched types + } + }; + + || { + match variant { + Meow::A { a: Z(y@_) } => {} + //~^ ERROR: mismatched types + } + }; + + || { + match variant { + Meow::B(Z(y@_)) => {} + //~^ ERROR: mismatched types + } + }; } fn main() {} diff --git a/tests/ui/pattern/type_mismatch.stderr b/tests/ui/pattern/type_mismatch.stderr index b0441b1fadcfe..3f24b2e706942 100644 --- a/tests/ui/pattern/type_mismatch.stderr +++ b/tests/ui/pattern/type_mismatch.stderr @@ -1,11 +1,68 @@ error[E0308]: mismatched types - --> $DIR/type_mismatch.rs:23:13 + --> $DIR/type_mismatch.rs:32:13 | LL | let Either::Two(ref mut _t) = x; | ^^^^^^^^^^^^^^^^^^^^^^^ - this expression has type `X` | | | expected `X`, found `Either` -error: aborting due to 1 previous error +error[E0308]: mismatched types + --> $DIR/type_mismatch.rs:39:13 + | +LL | let Either::Three { a: ref mut _t } = x; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - this expression has type `X` + | | + | expected `X`, found `Either` + +error[E0308]: mismatched types + --> $DIR/type_mismatch.rs:50:9 + | +LL | || match variant { + | ------- this expression has type `[(); 1]` +LL | (2,) => (), + | ^^^^ expected `[(); 1]`, found `(_,)` + | + = note: expected array `[(); 1]` + found tuple `(_,)` + +error[E0308]: mismatched types + --> $DIR/type_mismatch.rs:56:14 + | +LL | let ((2,) | _) = variant; + | ^^^^ ------- this expression has type `[(); 1]` + | | + | expected `[(); 1]`, found `(_,)` + | + = note: expected array `[(); 1]` + found tuple `(_,)` + +error[E0308]: mismatched types + --> $DIR/type_mismatch.rs:71:13 + | +LL | match variant { + | ------- this expression has type `[(); 1]` +LL | (Z(y@_),) => {} + | ^^^^^^^^^ expected `[(); 1]`, found `(_,)` + | + = note: expected array `[(); 1]` + found tuple `(_,)` + +error[E0308]: mismatched types + --> $DIR/type_mismatch.rs:78:13 + | +LL | match variant { + | ------- this expression has type `[(); 1]` +LL | Meow::A { a: Z(y@_) } => {} + | ^^^^^^^^^^^^^^^^^^^^^ expected `[(); 1]`, found `Meow` + +error[E0308]: mismatched types + --> $DIR/type_mismatch.rs:85:13 + | +LL | match variant { + | ------- this expression has type `[(); 1]` +LL | Meow::B(Z(y@_)) => {} + | ^^^^^^^^^^^^^^^ expected `[(); 1]`, found `Meow` + +error: aborting due to 7 previous errors For more information about this error, try `rustc --explain E0308`.