Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ use rustc_hir::{MatchSource, Node};
use rustc_middle::traits::{MatchExpressionArmCause, ObligationCause, ObligationCauseCode};
use rustc_middle::ty::error::TypeError;
use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::{self as ty, GenericArgKind, IsSuggestable, Ty, TypeVisitableExt};
use rustc_middle::ty::{
self as ty, GenericArgKind, IsSuggestable, Ty, TypeFlags, TypeVisitableExt,
};
use rustc_span::{Span, sym};
use tracing::debug;

Expand Down Expand Up @@ -89,6 +91,11 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
exp_found: &ty::error::ExpectedFound<Ty<'tcx>>,
diag: &mut Diag<'_>,
) {
// when found is unresolved var, we can't suggest anything
if exp_found.found.has_type_flags(TypeFlags::HAS_INFER_TY_VAR) {
Comment on lines +94 to +95
Copy link
Contributor

@dianne dianne Aug 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you're checking for inference variables on the error path, would it make sense to do so in a way that doesn't require tracking them for all types on the happy path too?

I think the "found" type may also be very likely to have inference variables when it doesn't match the expected type, on account of how pattern type-checking works. The type of the constructor pattern is checked against the type of the scrutinee, without knowledge of what the constructor's type's generic arguments are; I think those are all left for type inference to handle. As such, I think something more targeted may be needed if the suggestion is to support types with generic arguments.

return;
}

// Heavily inspired by `FnCtxt::suggest_compatible_variants`, with
// some modifications due to that being in typeck and this being in infer.
if let ObligationCauseCode::Pattern { .. } = cause.code()
Expand Down
10 changes: 7 additions & 3 deletions compiler/rustc_type_ir/src/flags.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,9 @@ bitflags::bitflags! {

/// Does this type have any coroutines in it?
const HAS_TY_CORO = 1 << 24;

/// Does this type have any Infer(TyVar(_)) in it?
const HAS_INFER_TY_VAR = 1 << 25;
}
}

Expand Down Expand Up @@ -267,9 +270,10 @@ impl<I: Interner> FlagComputation<I> {
ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_) => {
self.add_flags(TypeFlags::HAS_TY_FRESH)
}

ty::TyVar(_) | ty::IntVar(_) | ty::FloatVar(_) => {
self.add_flags(TypeFlags::HAS_TY_INFER)
ty::IntVar(_) | ty::FloatVar(_) => self.add_flags(TypeFlags::HAS_TY_INFER),
ty::TyVar(_) => {
self.add_flags(TypeFlags::HAS_INFER_TY_VAR);
self.add_flags(TypeFlags::HAS_TY_INFER);
}
},

Expand Down
4 changes: 0 additions & 4 deletions tests/ui/issues/issue-3680.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,6 @@ LL | Err(_) => ()
|
= note: expected enum `Option<_>`
found enum `Result<_, _>`
help: try wrapping the pattern in `Some`
|
LL | Some(Err(_)) => ()
| +++++ +

error: aborting due to 1 previous error

Expand Down
4 changes: 0 additions & 4 deletions tests/ui/issues/issue-5358-1.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,6 @@ LL | Either::Right(_) => {}
|
= note: expected struct `S`
found enum `Either<_, _>`
help: try wrapping the pattern in `S`
|
LL | S(Either::Right(_)) => {}
| ++ +
help: you might have meant to use field `0` whose type is `Either<usize, usize>`
|
LL | match S(Either::Left(5)).0 {
Expand Down
8 changes: 0 additions & 8 deletions tests/ui/match/issue-12552.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,6 @@ LL | Some(k) => match k {
|
= note: expected enum `Result<_, {integer}>`
found enum `Option<_>`
help: try wrapping the pattern in `Ok`
|
LL | Ok(Some(k)) => match k {
| +++ +

error[E0308]: mismatched types
--> $DIR/issue-12552.rs:9:5
Expand All @@ -24,10 +20,6 @@ LL | None => ()
|
= note: expected enum `Result<_, {integer}>`
found enum `Option<_>`
help: try wrapping the pattern in `Ok`
|
LL | Ok(None) => ()
| +++ +

error: aborting due to 2 previous errors

Expand Down
9 changes: 9 additions & 0 deletions tests/ui/type/type-mismatch-suggest-wrap-issue-145634.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// We should not suggest wrapping rhs with `Some`
// when the found type is an unresolved type variable
//
// See https://github.com/rust-lang/rust/issues/145634

fn main() {
let foo = Some(&(1, 2));
assert!(matches!(foo, &Some((1, 2)))); //~ ERROR mismatched types [E0308]
}
14 changes: 14 additions & 0 deletions tests/ui/type/type-mismatch-suggest-wrap-issue-145634.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
error[E0308]: mismatched types
--> $DIR/type-mismatch-suggest-wrap-issue-145634.rs:8:27
|
LL | assert!(matches!(foo, &Some((1, 2))));
| --- ^^^^^^^^^^^^^ expected `Option<&({integer}, {integer})>`, found `&_`
| |
| this expression has type `Option<&({integer}, {integer})>`
|
= note: expected enum `Option<&({integer}, {integer})>`
found reference `&_`

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0308`.
Loading