Skip to content

Commit

Permalink
Rollup merge of #111624 - cjgillot:private-uninhabited-pattern, r=pet…
Browse files Browse the repository at this point in the history
…rochenkov

Emit diagnostic for privately uninhabited uncovered witnesses.

Fixes #104034

cc `@Nadrieril`
  • Loading branch information
matthiaskrgr committed May 25, 2023
2 parents 87bb7d8 + 9a7ed36 commit 725cadb
Show file tree
Hide file tree
Showing 6 changed files with 33 additions and 1 deletion.
2 changes: 2 additions & 0 deletions compiler/rustc_mir_build/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,8 @@ mir_build_uncovered = {$count ->
*[other] patterns `{$witness_1}`, `{$witness_2}`, `{$witness_3}` and {$remainder} more
} not covered
mir_build_privately_uninhabited = pattern `{$witness_1}` is currently uninhabited, but this variant contains private fields which may become inhabited in the future
mir_build_pattern_not_covered = refutable pattern in {$origin}
.pattern_ty = the matched value is of type `{$pattern_ty}`
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_mir_build/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -781,6 +781,8 @@ pub(crate) struct PatternNotCovered<'s, 'tcx> {
pub interpreted_as_const: Option<InterpretedAsConst>,
#[subdiagnostic]
pub adt_defined_here: Option<AdtDefinedHere<'tcx>>,
#[note(mir_build_privately_uninhabited)]
pub witness_1_is_privately_uninhabited: Option<()>,
#[note(mir_build_pattern_ty)]
pub _p: (),
pub pattern_ty: Ty<'tcx>,
Expand Down
18 changes: 18 additions & 0 deletions compiler/rustc_mir_build/src/thir/pattern/check_match.rs
Original file line number Diff line number Diff line change
Expand Up @@ -479,12 +479,30 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
AdtDefinedHere { adt_def_span, ty, variants }
};

// Emit an extra note if the first uncovered witness is
// visibly uninhabited anywhere in the current crate.
let witness_1_is_privately_uninhabited =
if cx.tcx.features().exhaustive_patterns
&& let Some(witness_1) = witnesses.get(0)
&& let ty::Adt(adt, substs) = witness_1.ty().kind()
&& adt.is_enum()
&& let Constructor::Variant(variant_index) = witness_1.ctor()
{
let variant = adt.variant(*variant_index);
let inhabited = variant.inhabited_predicate(cx.tcx, *adt).subst(cx.tcx, substs);
assert!(inhabited.apply(cx.tcx, cx.param_env, cx.module));
!inhabited.apply_ignore_module(cx.tcx, cx.param_env)
} else {
false
};

self.error = Err(self.tcx.sess.emit_err(PatternNotCovered {
span: pat.span,
origin,
uncovered: Uncovered::new(pat.span, &cx, witnesses),
inform,
interpreted_as_const,
witness_1_is_privately_uninhabited: witness_1_is_privately_uninhabited.then_some(()),
_p: (),
pattern_ty,
let_suggestion,
Expand Down
1 change: 1 addition & 0 deletions tests/ui/never_type/exhaustive_patterns.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ LL | enum Either<A, B> {
LL | A(A),
LL | B(inner::Wrapper<B>),
| - not covered
= note: pattern `Either::B(_)` is currently uninhabited, but this variant contains private fields which may become inhabited in the future
= note: the matched value is of type `Either<(), !>`
help: you might want to use `if let` to ignore the variant that isn't matched
|
Expand Down
7 changes: 7 additions & 0 deletions tests/ui/uninhabited/uninhabited-irrefutable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ struct NotSoSecretlyEmpty {
}

enum Foo {
//~^ NOTE `Foo` defined here
A(foo::SecretlyEmpty),
//~^ NOTE not covered
B(foo::NotSoSecretlyEmpty),
C(NotSoSecretlyEmpty),
D(u32, u32),
Expand All @@ -27,4 +29,9 @@ fn main() {
let Foo::D(_y, _z) = x;
//~^ ERROR refutable pattern in local binding
//~| `Foo::A(_)` not covered
//~| NOTE `let` bindings require an "irrefutable pattern"
//~| NOTE for more information
//~| NOTE pattern `Foo::A(_)` is currently uninhabited
//~| NOTE the matched value is of type `Foo`
//~| HELP you might want to use `let else`
}
4 changes: 3 additions & 1 deletion tests/ui/uninhabited/uninhabited-irrefutable.stderr
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
error[E0005]: refutable pattern in local binding
--> $DIR/uninhabited-irrefutable.rs:27:9
--> $DIR/uninhabited-irrefutable.rs:29:9
|
LL | let Foo::D(_y, _z) = x;
| ^^^^^^^^^^^^^^ pattern `Foo::A(_)` not covered
Expand All @@ -11,8 +11,10 @@ note: `Foo` defined here
|
LL | enum Foo {
| ^^^
LL |
LL | A(foo::SecretlyEmpty),
| - not covered
= note: pattern `Foo::A(_)` is currently uninhabited, but this variant contains private fields which may become inhabited in the future
= note: the matched value is of type `Foo`
help: you might want to use `let else` to handle the variant that isn't matched
|
Expand Down

0 comments on commit 725cadb

Please sign in to comment.