Avoid ICEs after bad patterns, for the other syntactic variants

This commit is contained in:
Maja Kądziołka 2026-01-11 20:10:22 +01:00
parent 1279939b38
commit 1028c7a66a
3 changed files with 128 additions and 9 deletions

View file

@ -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);

View file

@ -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() {}

View file

@ -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`.