Rollup merge of #107425 - clubby789:match-range-missing-space, r=compiler-errors
Check for missing space between fat arrow and range pattern Fixes #107420 Ideally we wouldn't emit an error about expecting `=>` etc., but I'm not sure how to recover from this. `@rustbot` label +A-diagnostics
This commit is contained in:
commit
4e8f7e4fc9
6 changed files with 111 additions and 24 deletions
|
@ -199,6 +199,17 @@ parse_match_arm_body_without_braces = `match` arm body without braces
|
||||||
} with a body
|
} with a body
|
||||||
.suggestion_use_comma_not_semicolon = use a comma to end a `match` arm expression
|
.suggestion_use_comma_not_semicolon = use a comma to end a `match` arm expression
|
||||||
|
|
||||||
|
parse_inclusive_range_extra_equals = unexpected `=` after inclusive range
|
||||||
|
.suggestion_remove_eq = use `..=` instead
|
||||||
|
.note = inclusive ranges end with a single equals sign (`..=`)
|
||||||
|
|
||||||
|
parse_inclusive_range_match_arrow = unexpected `=>` after open range
|
||||||
|
.suggestion_add_space = add a space between the pattern and `=>`
|
||||||
|
|
||||||
|
parse_inclusive_range_no_end = inclusive range with no end
|
||||||
|
.suggestion_open_range = use `..` instead
|
||||||
|
.note = inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
|
||||||
|
|
||||||
parse_struct_literal_not_allowed_here = struct literals are not allowed here
|
parse_struct_literal_not_allowed_here = struct literals are not allowed here
|
||||||
.suggestion = surround the struct literal with parentheses
|
.suggestion = surround the struct literal with parentheses
|
||||||
|
|
||||||
|
|
|
@ -649,6 +649,48 @@ pub(crate) struct MatchArmBodyWithoutBraces {
|
||||||
pub sub: MatchArmBodyWithoutBracesSugg,
|
pub sub: MatchArmBodyWithoutBracesSugg,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
#[diag(parse_inclusive_range_extra_equals)]
|
||||||
|
#[note]
|
||||||
|
pub(crate) struct InclusiveRangeExtraEquals {
|
||||||
|
#[primary_span]
|
||||||
|
#[suggestion(
|
||||||
|
suggestion_remove_eq,
|
||||||
|
style = "short",
|
||||||
|
code = "..=",
|
||||||
|
applicability = "maybe-incorrect"
|
||||||
|
)]
|
||||||
|
pub span: Span,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
#[diag(parse_inclusive_range_match_arrow)]
|
||||||
|
pub(crate) struct InclusiveRangeMatchArrow {
|
||||||
|
#[primary_span]
|
||||||
|
pub span: Span,
|
||||||
|
#[suggestion(
|
||||||
|
suggestion_add_space,
|
||||||
|
style = "verbose",
|
||||||
|
code = " ",
|
||||||
|
applicability = "machine-applicable"
|
||||||
|
)]
|
||||||
|
pub after_pat: Span,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
#[diag(parse_inclusive_range_no_end, code = "E0586")]
|
||||||
|
#[note]
|
||||||
|
pub(crate) struct InclusiveRangeNoEnd {
|
||||||
|
#[primary_span]
|
||||||
|
#[suggestion(
|
||||||
|
suggestion_open_range,
|
||||||
|
code = "..",
|
||||||
|
applicability = "machine-applicable",
|
||||||
|
style = "short"
|
||||||
|
)]
|
||||||
|
pub span: Span,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Subdiagnostic)]
|
#[derive(Subdiagnostic)]
|
||||||
pub(crate) enum MatchArmBodyWithoutBracesSugg {
|
pub(crate) enum MatchArmBodyWithoutBracesSugg {
|
||||||
#[multipart_suggestion(suggestion_add_braces, applicability = "machine-applicable")]
|
#[multipart_suggestion(suggestion_add_braces, applicability = "machine-applicable")]
|
||||||
|
|
|
@ -3168,7 +3168,7 @@ impl<'a> Parser<'a> {
|
||||||
limits: RangeLimits,
|
limits: RangeLimits,
|
||||||
) -> ExprKind {
|
) -> ExprKind {
|
||||||
if end.is_none() && limits == RangeLimits::Closed {
|
if end.is_none() && limits == RangeLimits::Closed {
|
||||||
self.inclusive_range_with_incorrect_end(self.prev_token.span);
|
self.inclusive_range_with_incorrect_end();
|
||||||
ExprKind::Err
|
ExprKind::Err
|
||||||
} else {
|
} else {
|
||||||
ExprKind::Range(start, end, limits)
|
ExprKind::Range(start, end, limits)
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
use super::{ForceCollect, Parser, PathStyle, TrailingToken};
|
use super::{ForceCollect, Parser, PathStyle, TrailingToken};
|
||||||
use crate::errors::RemoveLet;
|
use crate::errors::{
|
||||||
|
InclusiveRangeExtraEquals, InclusiveRangeMatchArrow, InclusiveRangeNoEnd, RemoveLet,
|
||||||
|
};
|
||||||
use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole};
|
use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole};
|
||||||
use rustc_ast::mut_visit::{noop_visit_pat, MutVisitor};
|
use rustc_ast::mut_visit::{noop_visit_pat, MutVisitor};
|
||||||
use rustc_ast::ptr::P;
|
use rustc_ast::ptr::P;
|
||||||
|
@ -9,7 +11,7 @@ use rustc_ast::{
|
||||||
PatField, PatKind, Path, QSelf, RangeEnd, RangeSyntax,
|
PatField, PatKind, Path, QSelf, RangeEnd, RangeSyntax,
|
||||||
};
|
};
|
||||||
use rustc_ast_pretty::pprust;
|
use rustc_ast_pretty::pprust;
|
||||||
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed, PResult};
|
use rustc_errors::{Applicability, DiagnosticBuilder, ErrorGuaranteed, PResult};
|
||||||
use rustc_session::errors::ExprParenthesesNeeded;
|
use rustc_session::errors::ExprParenthesesNeeded;
|
||||||
use rustc_span::source_map::{respan, Span, Spanned};
|
use rustc_span::source_map::{respan, Span, Spanned};
|
||||||
use rustc_span::symbol::{kw, sym, Ident};
|
use rustc_span::symbol::{kw, sym, Ident};
|
||||||
|
@ -746,47 +748,52 @@ impl<'a> Parser<'a> {
|
||||||
// Parsing e.g. `X..`.
|
// Parsing e.g. `X..`.
|
||||||
if let RangeEnd::Included(_) = re.node {
|
if let RangeEnd::Included(_) = re.node {
|
||||||
// FIXME(Centril): Consider semantic errors instead in `ast_validation`.
|
// FIXME(Centril): Consider semantic errors instead in `ast_validation`.
|
||||||
self.inclusive_range_with_incorrect_end(re.span);
|
self.inclusive_range_with_incorrect_end();
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
Ok(PatKind::Range(Some(begin), end, re))
|
Ok(PatKind::Range(Some(begin), end, re))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn inclusive_range_with_incorrect_end(&mut self, span: Span) {
|
pub(super) fn inclusive_range_with_incorrect_end(&mut self) {
|
||||||
let tok = &self.token;
|
let tok = &self.token;
|
||||||
|
let span = self.prev_token.span;
|
||||||
// If the user typed "..==" instead of "..=", we want to give them
|
// If the user typed "..==" instead of "..=", we want to give them
|
||||||
// a specific error message telling them to use "..=".
|
// a specific error message telling them to use "..=".
|
||||||
|
// If they typed "..=>", suggest they use ".. =>".
|
||||||
// Otherwise, we assume that they meant to type a half open exclusive
|
// Otherwise, we assume that they meant to type a half open exclusive
|
||||||
// range and give them an error telling them to do that instead.
|
// range and give them an error telling them to do that instead.
|
||||||
if matches!(tok.kind, token::Eq) && tok.span.lo() == span.hi() {
|
let no_space = tok.span.lo() == span.hi();
|
||||||
let span_with_eq = span.to(tok.span);
|
match tok.kind {
|
||||||
|
token::Eq if no_space => {
|
||||||
|
let span_with_eq = span.to(tok.span);
|
||||||
|
|
||||||
// Ensure the user doesn't receive unhelpful unexpected token errors
|
// Ensure the user doesn't receive unhelpful unexpected token errors
|
||||||
self.bump();
|
self.bump();
|
||||||
if self.is_pat_range_end_start(0) {
|
if self.is_pat_range_end_start(0) {
|
||||||
let _ = self.parse_pat_range_end().map_err(|e| e.cancel());
|
let _ = self.parse_pat_range_end().map_err(|e| e.cancel());
|
||||||
|
}
|
||||||
|
|
||||||
|
self.error_inclusive_range_with_extra_equals(span_with_eq);
|
||||||
}
|
}
|
||||||
|
token::Gt if no_space => {
|
||||||
self.error_inclusive_range_with_extra_equals(span_with_eq);
|
self.error_inclusive_range_match_arrow(span);
|
||||||
} else {
|
}
|
||||||
self.error_inclusive_range_with_no_end(span);
|
_ => self.error_inclusive_range_with_no_end(span),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn error_inclusive_range_with_extra_equals(&self, span: Span) {
|
fn error_inclusive_range_with_extra_equals(&self, span: Span) {
|
||||||
self.struct_span_err(span, "unexpected `=` after inclusive range")
|
self.sess.emit_err(InclusiveRangeExtraEquals { span });
|
||||||
.span_suggestion_short(span, "use `..=` instead", "..=", Applicability::MaybeIncorrect)
|
}
|
||||||
.note("inclusive ranges end with a single equals sign (`..=`)")
|
|
||||||
.emit();
|
fn error_inclusive_range_match_arrow(&self, span: Span) {
|
||||||
|
let after_pat = span.with_hi(span.hi() - rustc_span::BytePos(1)).shrink_to_hi();
|
||||||
|
self.sess.emit_err(InclusiveRangeMatchArrow { span, after_pat });
|
||||||
}
|
}
|
||||||
|
|
||||||
fn error_inclusive_range_with_no_end(&self, span: Span) {
|
fn error_inclusive_range_with_no_end(&self, span: Span) {
|
||||||
struct_span_err!(self.sess.span_diagnostic, span, E0586, "inclusive range with no end")
|
self.sess.emit_err(InclusiveRangeNoEnd { span });
|
||||||
.span_suggestion_short(span, "use `..` instead", "..", Applicability::MachineApplicable)
|
|
||||||
.note("inclusive ranges must be bounded at the end (`..=b` or `a..=b`)")
|
|
||||||
.emit();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse a range-to pattern, `..X` or `..=X` where `X` remains to be parsed.
|
/// Parse a range-to pattern, `..X` or `..=X` where `X` remains to be parsed.
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
fn main() {
|
||||||
|
let x = 42;
|
||||||
|
match x {
|
||||||
|
0..=73 => {},
|
||||||
|
74..=> {}, //~ ERROR unexpected `=>` after open range
|
||||||
|
//~^ ERROR expected one of `=>`, `if`, or `|`, found `>`
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
error: unexpected `=>` after open range
|
||||||
|
--> $DIR/half-open-range-pats-inclusive-match-arrow.rs:5:11
|
||||||
|
|
|
||||||
|
LL | 74..=> {},
|
||||||
|
| ^^^
|
||||||
|
|
|
||||||
|
help: add a space between the pattern and `=>`
|
||||||
|
|
|
||||||
|
LL | 74.. => {},
|
||||||
|
| +
|
||||||
|
|
||||||
|
error: expected one of `=>`, `if`, or `|`, found `>`
|
||||||
|
--> $DIR/half-open-range-pats-inclusive-match-arrow.rs:5:14
|
||||||
|
|
|
||||||
|
LL | 74..=> {},
|
||||||
|
| ^ expected one of `=>`, `if`, or `|`
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue