Rollup merge of #148872 - ShoyuVanilla:issue-148192, r=chenyukang

fix: Do not ICE when missing match arm with ill-formed subty is met

Fixes rust-lang/rust#148192

The ICE comes from the following line, calling `normalize_erasing_regions` to a projection type whose trait bound is not met:
2fcbda6c1a/compiler/rustc_pattern_analysis/src/rustc.rs (L185-L194)

The above function is called while trying to lint missing match arms, or scrutinize ctors of missing(not necessary error) match arms.

So, the following code can trigger ICEs.
```rust
trait WhereTrait {
    type Type;
}

fn foo(e: Enum) {
    match e {
        Enum::Map(_) => (), // ICE, while trying to lint missing arms
    }

    if let Enum::Map(_) = e {} // ICE, while trying to scrutinize missing ctors (even worse)
}

enum Enum {
    Map(()),
    Map2(<() as WhereTrait>::Type),
}
```

This ICE won't be triggered with the following code, as this is filtered out before `check_match` as the existence of ill-formed type inside the variant marks the body as tainted by error in `hir_typeck`, but for the above code, the `hir_typeck` complains nothing because everything it sees is locally correct.

```rust
fn foo(e: Enum) {
    match e {
        Enum::Map2(_) => (), // No ICE
    }
}
```

I've considered visiting and wf checking for the match scrutinee before entering `check_match`, but that might regress the perf and I think just emitting delayed bug would enough as the normalization failure would be originated by other errors like ill-formdness.
This commit is contained in:
Stuart Cook 2025-11-13 11:57:10 +11:00 committed by GitHub
commit 17c25e4483
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 69 additions and 1 deletions

View file

@ -191,7 +191,18 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
variant.fields.iter().map(move |field| {
let ty = field.ty(self.tcx, args);
// `field.ty()` doesn't normalize after instantiating.
let ty = self.tcx.normalize_erasing_regions(self.typing_env, ty);
let ty =
self.tcx.try_normalize_erasing_regions(self.typing_env, ty).unwrap_or_else(|e| {
self.tcx.dcx().span_delayed_bug(
self.scrut_span,
format!(
"Failed to normalize {:?} in typing_env={:?} while getting variant sub tys for {ty:?}",
e.get_type_for_failure(),
self.typing_env,
),
);
ty
});
let ty = self.reveal_opaque_ty(ty);
(field, ty)
})

View file

@ -0,0 +1,20 @@
trait WhereTrait {
type Type;
}
fn foo(e: Enum) {
if let Enum::Map(_) = e {}
match e {
//~^ ERROR: non-exhaustive patterns: `Enum::Map2(_)` not covered
Enum::Map(_) => (),
}
}
enum Enum {
Map(()),
Map2(<() as WhereTrait>::Type),
//~^ ERROR: the trait bound `(): WhereTrait` is not satisfied
}
fn main() {}

View file

@ -0,0 +1,37 @@
error[E0277]: the trait bound `(): WhereTrait` is not satisfied
--> $DIR/missing-ctor-with-ill-formed-inner-ty-issue-148192.rs:16:10
|
LL | Map2(<() as WhereTrait>::Type),
| ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `WhereTrait` is not implemented for `()`
|
help: this trait has no implementations, consider adding one
--> $DIR/missing-ctor-with-ill-formed-inner-ty-issue-148192.rs:1:1
|
LL | trait WhereTrait {
| ^^^^^^^^^^^^^^^^
error[E0004]: non-exhaustive patterns: `Enum::Map2(_)` not covered
--> $DIR/missing-ctor-with-ill-formed-inner-ty-issue-148192.rs:8:11
|
LL | match e {
| ^ pattern `Enum::Map2(_)` not covered
|
note: `Enum` defined here
--> $DIR/missing-ctor-with-ill-formed-inner-ty-issue-148192.rs:14:6
|
LL | enum Enum {
| ^^^^
LL | Map(()),
LL | Map2(<() as WhereTrait>::Type),
| ---- not covered
= 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 or an explicit pattern as shown
|
LL ~ Enum::Map(_) => (),
LL ~ Enum::Map2(_) => todo!(),
|
error: aborting due to 2 previous errors
Some errors have detailed explanations: E0004, E0277.
For more information about an error, try `rustc --explain E0004`.