Disallow guards on never patterns

This commit is contained in:
Nadrieril 2023-11-27 03:47:49 +01:00
parent a2dcb3a6d9
commit 06a8ed10b6
7 changed files with 47 additions and 43 deletions

View File

@ -108,6 +108,10 @@ ast_lowering_misplaced_impl_trait =
ast_lowering_misplaced_relax_trait_bound = ast_lowering_misplaced_relax_trait_bound =
`?Trait` bounds are only permitted at the point where a type parameter is declared `?Trait` bounds are only permitted at the point where a type parameter is declared
ast_lowering_never_pattern_with_guard =
a guard on a never pattern will never be run
.suggestion = remove this guard
ast_lowering_not_supported_for_lifetime_binder_async_closure = ast_lowering_not_supported_for_lifetime_binder_async_closure =
`for<...>` binders on `async` closures are not currently supported `for<...>` binders on `async` closures are not currently supported

View File

@ -349,6 +349,14 @@ pub struct MatchArmWithNoBody {
pub suggestion: Span, pub suggestion: Span,
} }
#[derive(Diagnostic)]
#[diag(ast_lowering_never_pattern_with_guard)]
pub struct NeverPatternWithGuard {
#[primary_span]
#[suggestion(code = "", applicability = "maybe-incorrect")]
pub span: Span,
}
#[derive(Diagnostic, Clone, Copy)] #[derive(Diagnostic, Clone, Copy)]
#[diag(ast_lowering_arbitrary_expression_in_pattern)] #[diag(ast_lowering_arbitrary_expression_in_pattern)]
pub struct ArbitraryExpressionInPattern { pub struct ArbitraryExpressionInPattern {

View File

@ -2,7 +2,7 @@ use super::errors::{
AsyncCoroutinesNotSupported, AsyncNonMoveClosureNotSupported, AwaitOnlyInAsyncFnAndBlocks, AsyncCoroutinesNotSupported, AsyncNonMoveClosureNotSupported, AwaitOnlyInAsyncFnAndBlocks,
BaseExpressionDoubleDot, ClosureCannotBeStatic, CoroutineTooManyParameters, BaseExpressionDoubleDot, ClosureCannotBeStatic, CoroutineTooManyParameters,
FunctionalRecordUpdateDestructuringAssignment, InclusiveRangeWithNoEnd, MatchArmWithNoBody, FunctionalRecordUpdateDestructuringAssignment, InclusiveRangeWithNoEnd, MatchArmWithNoBody,
NotSupportedForLifetimeBinderAsyncClosure, UnderscoreExprLhsAssign, NeverPatternWithGuard, NotSupportedForLifetimeBinderAsyncClosure, UnderscoreExprLhsAssign,
}; };
use super::ResolverAstLoweringExt; use super::ResolverAstLoweringExt;
use super::{ImplTraitContext, LoweringContext, ParamMode, ParenthesizedGenericArgs}; use super::{ImplTraitContext, LoweringContext, ParamMode, ParenthesizedGenericArgs};
@ -550,7 +550,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
fn lower_arm(&mut self, arm: &Arm) -> hir::Arm<'hir> { fn lower_arm(&mut self, arm: &Arm) -> hir::Arm<'hir> {
let pat = self.lower_pat(&arm.pat); let pat = self.lower_pat(&arm.pat);
let guard = arm.guard.as_ref().map(|cond| { let mut guard = arm.guard.as_ref().map(|cond| {
if let ExprKind::Let(pat, scrutinee, span, is_recovered) = &cond.kind { if let ExprKind::Let(pat, scrutinee, span, is_recovered) = &cond.kind {
hir::Guard::IfLet(self.arena.alloc(hir::Let { hir::Guard::IfLet(self.arena.alloc(hir::Let {
hir_id: self.next_id(), hir_id: self.next_id(),
@ -575,6 +575,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
self.tcx self.tcx
.sess .sess
.emit_err(MatchArmWithNoBody { span, suggestion: span.shrink_to_hi() }); .emit_err(MatchArmWithNoBody { span, suggestion: span.shrink_to_hi() });
} else if let Some(g) = &arm.guard {
self.tcx.sess.emit_err(NeverPatternWithGuard { span: g.span });
guard = None;
} }
// An arm without a body, meant for never patterns. // An arm without a body, meant for never patterns.

View File

@ -15,12 +15,11 @@ fn no_arms_or_guards(x: Void) {
None => {} None => {}
} }
match None::<Void> { match None::<Void> {
//~^ ERROR non-exhaustive
Some(!) if true, Some(!) if true,
//~^ ERROR guard on a never pattern
None => {} None => {}
} }
match None::<Void> { match None::<Void> {
//~^ ERROR non-exhaustive
Some(!) if true => {} Some(!) if true => {}
None => {} None => {}
} }

View File

@ -1,39 +1,8 @@
error[E0004]: non-exhaustive patterns: `Some(_)` not covered error: a guard on a never pattern will never be run
--> $DIR/check.rs:17:11 --> $DIR/check.rs:18:20
|
LL | match None::<Void> {
| ^^^^^^^^^^^^ pattern `Some(_)` not covered
|
note: `Option<Void>` defined here
--> $SRC_DIR/core/src/option.rs:LL:COL
::: $SRC_DIR/core/src/option.rs:LL:COL
|
= note: not covered
= note: the matched value is of type `Option<Void>`
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 ~ None => {},
LL + Some(_) => todo!()
| |
LL | Some(!) if true,
| ^^^^ help: remove this guard
error[E0004]: non-exhaustive patterns: `Some(_)` not covered error: aborting due to 1 previous error
--> $DIR/check.rs:22:11
|
LL | match None::<Void> {
| ^^^^^^^^^^^^ pattern `Some(_)` not covered
|
note: `Option<Void>` defined here
--> $SRC_DIR/core/src/option.rs:LL:COL
::: $SRC_DIR/core/src/option.rs:LL:COL
|
= note: not covered
= note: the matched value is of type `Option<Void>`
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 ~ None => {},
LL + Some(_) => todo!()
|
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0004`.

View File

@ -30,10 +30,12 @@ fn parse(x: Void) {
match None::<Void> { match None::<Void> {
Some(!) if true Some(!) if true
//~^ ERROR expected `,` following `match` arm //~^ ERROR expected `,` following `match` arm
//~| ERROR guard on a never pattern
None => {} None => {}
} }
match None::<Void> { match None::<Void> {
Some(!) if true, Some(!) if true,
//~^ ERROR guard on a never pattern
None => {} None => {}
} }
match None::<Void> { match None::<Void> {
@ -45,6 +47,7 @@ fn parse(x: Void) {
} }
match x { match x {
never!() if true, never!() if true,
//~^ ERROR guard on a never pattern
} }
match x { match x {
never!() never!()

View File

@ -11,16 +11,34 @@ LL | Some(!) if true
| ^ help: missing a comma here to end this `match` arm: `,` | ^ help: missing a comma here to end this `match` arm: `,`
error: expected one of `,`, `=>`, `if`, `|`, or `}`, found `<=` error: expected one of `,`, `=>`, `if`, `|`, or `}`, found `<=`
--> $DIR/parse.rs:40:17 --> $DIR/parse.rs:42:17
| |
LL | Some(!) <= LL | Some(!) <=
| ^^ expected one of `,`, `=>`, `if`, `|`, or `}` | ^^ expected one of `,`, `=>`, `if`, `|`, or `}`
error: top-level or-patterns are not allowed in `let` bindings error: top-level or-patterns are not allowed in `let` bindings
--> $DIR/parse.rs:64:9 --> $DIR/parse.rs:67:9
| |
LL | let Ok(_) | Err(!) = &res; // Disallowed; see #82048. LL | let Ok(_) | Err(!) = &res; // Disallowed; see #82048.
| ^^^^^^^^^^^^^^ help: wrap the pattern in parentheses: `(Ok(_) | Err(!))` | ^^^^^^^^^^^^^^ help: wrap the pattern in parentheses: `(Ok(_) | Err(!))`
error: aborting due to 4 previous errors error: a guard on a never pattern will never be run
--> $DIR/parse.rs:31:20
|
LL | Some(!) if true
| ^^^^ help: remove this guard
error: a guard on a never pattern will never be run
--> $DIR/parse.rs:37:20
|
LL | Some(!) if true,
| ^^^^ help: remove this guard
error: a guard on a never pattern will never be run
--> $DIR/parse.rs:49:21
|
LL | never!() if true,
| ^^^^ help: remove this guard
error: aborting due to 7 previous errors