1
Fork 0

Auto merge of #116821 - Nadrieril:fix-opaque-ice, r=compiler-errors

Exhaustiveness: reveal opaque types properly

Previously, exhaustiveness had no clear policy around opaque types. In this PR I propose the following policy: within the body of an item that defines the hidden type of some opaque type, exhaustiveness checking on a value of that opaque type is performed using the concrete hidden type inferred in this body.

I'm not sure how consistent this is with other operations allowed on opaque types; I believe this will require FCP.

From what I can tell, this doesn't change anything for non-empty types.

The observable changes are:
- when the real type is uninhabited, matches within the defining scopes can now rely on that for exhaustiveness, e.g.:

```rust
#[derive(Copy, Clone)]
enum Void {}
fn return_never_rpit(x: Void) -> impl Copy {
    if false {
        match return_never_rpit(x) {}
    }
    x
}
```
- this properly fixes ICEs like https://github.com/rust-lang/rust/issues/117100 that occurred because a same match could have some patterns where the type is revealed and some where it is not.

Bonus subtle point: if `x` is opaque, a match like `match x { ("", "") => {} ... }` will constrain its type ([playground](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=901d715330eac40339b4016ac566d6c3)). This is not the case for `match x {}`: this will not constain the type, and will only compile if something else constrains the type to be empty.

Fixes https://github.com/rust-lang/rust/issues/117100

r? `@oli-obk`

Edited for precision of the wording

[Included](https://github.com/rust-lang/rust/pull/116821#issuecomment-1813171764) in the FCP on this PR is this rule:

> Within the body of an item that defines the hidden type of some opaque type, exhaustiveness checking on a value of that opaque type is performed using the concrete hidden type inferred in this body.
This commit is contained in:
bors 2023-12-22 12:12:12 +00:00
commit c1fc1d18cd
7 changed files with 284 additions and 33 deletions

View file

@ -28,6 +28,7 @@ use rustc_span::hygiene::DesugaringKind;
use rustc_span::Span;
pub(crate) fn check_match(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), ErrorGuaranteed> {
let typeck_results = tcx.typeck(def_id);
let (thir, expr) = tcx.thir_body(def_id)?;
let thir = thir.borrow();
let pattern_arena = TypedArena::default();
@ -35,6 +36,7 @@ pub(crate) fn check_match(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), Err
let mut visitor = MatchVisitor {
tcx,
thir: &*thir,
typeck_results,
param_env: tcx.param_env(def_id),
lint_level: tcx.local_def_id_to_hir_id(def_id),
let_source: LetSource::None,
@ -80,6 +82,7 @@ enum LetSource {
struct MatchVisitor<'thir, 'p, 'tcx> {
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
typeck_results: &'tcx ty::TypeckResults<'tcx>,
thir: &'thir Thir<'tcx>,
lint_level: HirId,
let_source: LetSource,
@ -382,6 +385,7 @@ impl<'thir, 'p, 'tcx> MatchVisitor<'thir, 'p, 'tcx> {
scrutinee.map(|scrut| self.is_known_valid_scrutinee(scrut)).unwrap_or(true);
MatchCheckCtxt {
tcx: self.tcx,
typeck_results: self.typeck_results,
param_env: self.param_env,
module: self.tcx.parent_module(self.lint_level).to_def_id(),
pattern_arena: self.pattern_arena,