Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 7 additions & 6 deletions compiler/rustc_hir_typeck/src/pat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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),
}
}
Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -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);
Expand Down
63 changes: 62 additions & 1 deletion tests/ui/pattern/type_mismatch.rs
Original file line number Diff line number Diff line change
@@ -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.
Expand All @@ -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() {
Expand All @@ -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() {}
61 changes: 59 additions & 2 deletions tests/ui/pattern/type_mismatch.stderr
Original file line number Diff line number Diff line change
@@ -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`.
Loading