Skip to content

Add diagnostics for mistyped inclusive range #87071

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jul 18, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions compiler/rustc_parse/src/parser/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -431,7 +431,8 @@ impl<'a> Parser<'a> {
let span = self.mk_expr_sp(&lhs, lhs.span, rhs_span);
let limits =
if op == AssocOp::DotDot { RangeLimits::HalfOpen } else { RangeLimits::Closed };
Ok(self.mk_expr(span, self.mk_range(Some(lhs), rhs, limits), AttrVec::new()))
let range = self.mk_range(Some(lhs), rhs, limits);
Ok(self.mk_expr(span, range, AttrVec::new()))
}

fn is_at_start_of_range_notation_rhs(&self) -> bool {
Expand Down Expand Up @@ -479,7 +480,8 @@ impl<'a> Parser<'a> {
} else {
(lo, None)
};
Ok(this.mk_expr(span, this.mk_range(None, opt_end, limits), attrs.into()))
let range = this.mk_range(None, opt_end, limits);
Ok(this.mk_expr(span, range, attrs.into()))
})
}

Expand Down Expand Up @@ -2517,13 +2519,13 @@ impl<'a> Parser<'a> {
}

fn mk_range(
&self,
&mut self,
start: Option<P<Expr>>,
end: Option<P<Expr>>,
limits: RangeLimits,
) -> ExprKind {
if end.is_none() && limits == RangeLimits::Closed {
self.error_inclusive_range_with_no_end(self.prev_token.span);
self.inclusive_range_with_incorrect_end(self.prev_token.span);
ExprKind::Err
} else {
ExprKind::Range(start, end, limits)
Expand Down
39 changes: 36 additions & 3 deletions compiler/rustc_parse/src/parser/pat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -736,15 +736,48 @@ impl<'a> Parser<'a> {
// Parsing e.g. `X..`.
if let RangeEnd::Included(_) = re.node {
// FIXME(Centril): Consider semantic errors instead in `ast_validation`.
// Possibly also do this for `X..=` in *expression* contexts.
self.error_inclusive_range_with_no_end(re.span);
self.inclusive_range_with_incorrect_end(re.span);
}
None
};
Ok(PatKind::Range(Some(begin), end, re))
}

pub(super) fn error_inclusive_range_with_no_end(&self, span: Span) {
pub(super) fn inclusive_range_with_incorrect_end(&mut self, span: Span) {
let tok = &self.token;

// If the user typed "..==" instead of "..=", we want to give them
// a specific error message telling them to use "..=".
// Otherwise, we assume that they meant to type a half open exclusive
// range and give them an error telling them to do that instead.
if matches!(tok.kind, token::Eq) && tok.span.lo() == span.hi() {
let span_with_eq = span.to(tok.span);

// Ensure the user doesn't receive unhelpful unexpected token errors
self.bump();
if self.is_pat_range_end_start(0) {
let _ = self.parse_pat_range_end();
}

self.error_inclusive_range_with_extra_equals(span_with_eq);
} else {
self.error_inclusive_range_with_no_end(span);
}
}

fn error_inclusive_range_with_extra_equals(&self, span: Span) {
self.struct_span_err(span, "unexpected `=` after inclusive range")
.span_suggestion_short(
span,
"use `..=` instead",
"..=".to_string(),
Applicability::MaybeIncorrect,
)
.note("inclusive ranges end with a single equals sign (`..=`)")
.emit();
}

fn error_inclusive_range_with_no_end(&self, span: Span) {
struct_span_err!(self.sess.span_diagnostic, span, E0586, "inclusive range with no end")
.span_suggestion_short(
span,
Expand Down
10 changes: 10 additions & 0 deletions src/test/ui/parser/range-inclusive-extra-equals.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// Makes sure that a helpful message is shown when someone mistypes
// an inclusive range as `..==` rather than `..=`. This is an
// easy mistake, because of the resemblance to`==`.
// See #86395 for a bit of background.

pub fn main() {
if let 1..==3 = 1 {} //~ERROR unexpected `=` after inclusive range
//~|HELP use `..=` instead
//~|NOTE inclusive ranges end with a single equals sign
}
10 changes: 10 additions & 0 deletions src/test/ui/parser/range-inclusive-extra-equals.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
error: unexpected `=` after inclusive range
--> $DIR/range-inclusive-extra-equals.rs:7:13
|
LL | if let 1..==3 = 1 {}
| ^^^^ help: use `..=` instead
|
= note: inclusive ranges end with a single equals sign (`..=`)

error: aborting due to previous error