mirror of
https://github.com/rust-lang/rust.git
synced 2025-06-04 19:29:07 +00:00
Typecheck never patterns
This commit is contained in:
parent
a947c4c2c3
commit
d8b72e796e
@ -178,8 +178,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
|
|
||||||
let ty = match pat.kind {
|
let ty = match pat.kind {
|
||||||
PatKind::Wild | PatKind::Err(_) => expected,
|
PatKind::Wild | PatKind::Err(_) => expected,
|
||||||
// FIXME(never_patterns): check the type is uninhabited. If that is not possible within
|
// We allow any type here; we ensure that the type is uninhabited during match checking.
|
||||||
// typeck, do that in a later phase.
|
|
||||||
PatKind::Never => expected,
|
PatKind::Never => expected,
|
||||||
PatKind::Lit(lt) => self.check_pat_lit(pat.span, lt, expected, ti),
|
PatKind::Lit(lt) => self.check_pat_lit(pat.span, lt, expected, ti),
|
||||||
PatKind::Range(lhs, rhs, _) => self.check_pat_range(pat.span, lhs, rhs, expected, ti),
|
PatKind::Range(lhs, rhs, _) => self.check_pat_range(pat.span, lhs, rhs, expected, ti),
|
||||||
|
@ -234,6 +234,11 @@ mir_build_mutation_of_layout_constrained_field_requires_unsafe_unsafe_op_in_unsa
|
|||||||
|
|
||||||
mir_build_non_const_path = runtime values cannot be referenced in patterns
|
mir_build_non_const_path = runtime values cannot be referenced in patterns
|
||||||
|
|
||||||
|
mir_build_non_empty_never_pattern =
|
||||||
|
mismatched types
|
||||||
|
.label = a never pattern must be used on an uninhabited type
|
||||||
|
.note = the matched value is of type `{$ty}`
|
||||||
|
|
||||||
mir_build_non_exhaustive_match_all_arms_guarded =
|
mir_build_non_exhaustive_match_all_arms_guarded =
|
||||||
match arms with guards don't count towards exhaustivity
|
match arms with guards don't count towards exhaustivity
|
||||||
|
|
||||||
|
@ -788,6 +788,16 @@ pub struct FloatPattern;
|
|||||||
#[diag(mir_build_pointer_pattern)]
|
#[diag(mir_build_pointer_pattern)]
|
||||||
pub struct PointerPattern;
|
pub struct PointerPattern;
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
#[diag(mir_build_non_empty_never_pattern)]
|
||||||
|
#[note]
|
||||||
|
pub struct NonEmptyNeverPattern<'tcx> {
|
||||||
|
#[primary_span]
|
||||||
|
#[label]
|
||||||
|
pub span: Span,
|
||||||
|
pub ty: Ty<'tcx>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(LintDiagnostic)]
|
#[derive(LintDiagnostic)]
|
||||||
#[diag(mir_build_indirect_structural_match)]
|
#[diag(mir_build_indirect_structural_match)]
|
||||||
#[note(mir_build_type_not_structural_tip)]
|
#[note(mir_build_type_not_structural_tip)]
|
||||||
|
@ -276,10 +276,13 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
|
|||||||
} else {
|
} else {
|
||||||
// Check the pattern for some things unrelated to exhaustiveness.
|
// Check the pattern for some things unrelated to exhaustiveness.
|
||||||
let refutable = if cx.refutable { Refutable } else { Irrefutable };
|
let refutable = if cx.refutable { Refutable } else { Irrefutable };
|
||||||
|
let mut err = Ok(());
|
||||||
pat.walk_always(|pat| {
|
pat.walk_always(|pat| {
|
||||||
check_borrow_conflicts_in_at_patterns(self, pat);
|
check_borrow_conflicts_in_at_patterns(self, pat);
|
||||||
check_for_bindings_named_same_as_variants(self, pat, refutable);
|
check_for_bindings_named_same_as_variants(self, pat, refutable);
|
||||||
|
err = err.and(check_never_pattern(cx, pat));
|
||||||
});
|
});
|
||||||
|
err?;
|
||||||
Ok(cx.pattern_arena.alloc(cx.lower_pat(pat)))
|
Ok(cx.pattern_arena.alloc(cx.lower_pat(pat)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -811,6 +814,19 @@ fn check_for_bindings_named_same_as_variants(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Check that never patterns are only used on inhabited types.
|
||||||
|
fn check_never_pattern<'tcx>(
|
||||||
|
cx: &MatchCheckCtxt<'_, 'tcx>,
|
||||||
|
pat: &Pat<'tcx>,
|
||||||
|
) -> Result<(), ErrorGuaranteed> {
|
||||||
|
if let PatKind::Never = pat.kind {
|
||||||
|
if !cx.is_uninhabited(pat.ty) {
|
||||||
|
return Err(cx.tcx.dcx().emit_err(NonEmptyNeverPattern { span: pat.span, ty: pat.ty }));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn report_irrefutable_let_patterns(
|
fn report_irrefutable_let_patterns(
|
||||||
tcx: TyCtxt<'_>,
|
tcx: TyCtxt<'_>,
|
||||||
id: HirId,
|
id: HirId,
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
// check-pass
|
|
||||||
#![feature(never_patterns)]
|
#![feature(never_patterns)]
|
||||||
#![feature(exhaustive_patterns)]
|
#![feature(exhaustive_patterns)]
|
||||||
#![allow(incomplete_features)]
|
#![allow(incomplete_features)]
|
||||||
@ -17,40 +16,48 @@ fn safe_unwrap_result<T: Copy>(res: Result<T, Void>) {
|
|||||||
|
|
||||||
// Check we only accept `!` where we want to.
|
// Check we only accept `!` where we want to.
|
||||||
fn never_pattern_typeck(void: Void) {
|
fn never_pattern_typeck(void: Void) {
|
||||||
// FIXME(never_patterns): Don't accept on a non-empty type.
|
// Don't accept on a non-empty type.
|
||||||
match () {
|
match () {
|
||||||
!,
|
!,
|
||||||
|
//~^ ERROR: mismatched types
|
||||||
}
|
}
|
||||||
match (0, false) {
|
match (0, false) {
|
||||||
!,
|
!,
|
||||||
|
//~^ ERROR: mismatched types
|
||||||
}
|
}
|
||||||
match (0, false) {
|
match (0, false) {
|
||||||
(_, !),
|
(_, !),
|
||||||
|
//~^ ERROR: mismatched types
|
||||||
}
|
}
|
||||||
match Some(0) {
|
match Some(0) {
|
||||||
None => {}
|
None => {}
|
||||||
Some(!),
|
Some(!),
|
||||||
|
//~^ ERROR: mismatched types
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME(never_patterns): Don't accept on an arbitrary type, even if there are no more branches.
|
// Don't accept on an arbitrary type, even if there are no more branches.
|
||||||
match () {
|
match () {
|
||||||
() => {}
|
() => {}
|
||||||
!,
|
!,
|
||||||
|
//~^ ERROR: mismatched types
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME(never_patterns): Don't accept even on an empty branch.
|
// Don't accept even on an empty branch.
|
||||||
match None::<Void> {
|
match None::<Void> {
|
||||||
None => {}
|
None => {}
|
||||||
!,
|
!,
|
||||||
|
//~^ ERROR: mismatched types
|
||||||
}
|
}
|
||||||
match (&[] as &[Void]) {
|
match (&[] as &[Void]) {
|
||||||
[] => {}
|
[] => {}
|
||||||
!,
|
!,
|
||||||
|
//~^ ERROR: mismatched types
|
||||||
}
|
}
|
||||||
// FIXME(never_patterns): Let alone if the emptiness is behind a reference.
|
// Let alone if the emptiness is behind a reference.
|
||||||
match None::<&Void> {
|
match None::<&Void> {
|
||||||
None => {}
|
None => {}
|
||||||
!,
|
!,
|
||||||
|
//~^ ERROR: mismatched types
|
||||||
}
|
}
|
||||||
|
|
||||||
// Participate in match ergonomics.
|
// Participate in match ergonomics.
|
||||||
|
66
tests/ui/rfcs/rfc-0000-never_patterns/typeck.stderr
Normal file
66
tests/ui/rfcs/rfc-0000-never_patterns/typeck.stderr
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
error: mismatched types
|
||||||
|
--> $DIR/typeck.rs:21:9
|
||||||
|
|
|
||||||
|
LL | !,
|
||||||
|
| ^ a never pattern must be used on an uninhabited type
|
||||||
|
|
|
||||||
|
= note: the matched value is of type `()`
|
||||||
|
|
||||||
|
error: mismatched types
|
||||||
|
--> $DIR/typeck.rs:25:9
|
||||||
|
|
|
||||||
|
LL | !,
|
||||||
|
| ^ a never pattern must be used on an uninhabited type
|
||||||
|
|
|
||||||
|
= note: the matched value is of type `(i32, bool)`
|
||||||
|
|
||||||
|
error: mismatched types
|
||||||
|
--> $DIR/typeck.rs:29:13
|
||||||
|
|
|
||||||
|
LL | (_, !),
|
||||||
|
| ^ a never pattern must be used on an uninhabited type
|
||||||
|
|
|
||||||
|
= note: the matched value is of type `bool`
|
||||||
|
|
||||||
|
error: mismatched types
|
||||||
|
--> $DIR/typeck.rs:34:14
|
||||||
|
|
|
||||||
|
LL | Some(!),
|
||||||
|
| ^ a never pattern must be used on an uninhabited type
|
||||||
|
|
|
||||||
|
= note: the matched value is of type `i32`
|
||||||
|
|
||||||
|
error: mismatched types
|
||||||
|
--> $DIR/typeck.rs:41:9
|
||||||
|
|
|
||||||
|
LL | !,
|
||||||
|
| ^ a never pattern must be used on an uninhabited type
|
||||||
|
|
|
||||||
|
= note: the matched value is of type `()`
|
||||||
|
|
||||||
|
error: mismatched types
|
||||||
|
--> $DIR/typeck.rs:48:9
|
||||||
|
|
|
||||||
|
LL | !,
|
||||||
|
| ^ a never pattern must be used on an uninhabited type
|
||||||
|
|
|
||||||
|
= note: the matched value is of type `Option<Void>`
|
||||||
|
|
||||||
|
error: mismatched types
|
||||||
|
--> $DIR/typeck.rs:53:9
|
||||||
|
|
|
||||||
|
LL | !,
|
||||||
|
| ^ a never pattern must be used on an uninhabited type
|
||||||
|
|
|
||||||
|
= note: the matched value is of type `[Void]`
|
||||||
|
|
||||||
|
error: mismatched types
|
||||||
|
--> $DIR/typeck.rs:59:9
|
||||||
|
|
|
||||||
|
LL | !,
|
||||||
|
| ^ a never pattern must be used on an uninhabited type
|
||||||
|
|
|
||||||
|
= note: the matched value is of type `Option<&Void>`
|
||||||
|
|
||||||
|
error: aborting due to 8 previous errors
|
||||||
|
|
Loading…
Reference in New Issue
Block a user