Change:
<!-- Thank you for filing a bug report! Please provide a short summary of the bug, along with any information you feel relevant to replicating the bug. If you cannot produce a minimal reproduction case (something that would work in isolation), please provide the steps or even link to a repository that causes the problematic output to occur. --Given the following code: The current output is: <!-- The following is not always necessary. --Ideally the output should look like: <!-- If the problem is not self-explanatory, please provide a rationale for the change. --<!-- If dramatically different output is caused by small changes, consider also adding them here. If you're using the stable version of the compiler, you should also check if the bug also exists in the beta or nightly versions. The output might also be different depending on the Edition. --<!-- TRIAGEBOTSTART --<!-- TRIAGEBOTASSIGNSTART --<!-- TRIAGEBOTASSIGNDATASTARTTRIAGEBOTASSIGNDATAEND --<!-- TRIAGEBOTASSIGNEND --<!-- TRIAGEBOTEND --
Other test cases,
Thank you for filing this! I'm going to have a look and see if I can figure it out. claim label +C-enhancement +D-newcomer-roadblock
This is surprisingly complicated in a bunch of ways. The relevant function, at least for the base case, is . At first glance, all you've gotta do is handle the case where there's a token next in the queue. Now for the problems. First off, implementing this cleanly requires adding at least one new feature to . Currently, the way you check if a token is next up is to call the , which logs whatever token it's checking for as an expected token. This token isn't expected. It being logged as an expected token messes up the error message for other cases. The solution is to add versions of and that do not log the token as expected. Adding these alternate versions is probably a good idea anyway, since . Then there's the whole context sensitivity thing. Dealing with this the way Esteban suggested is way above my pay grade. But you've got to do something, or you can't even handle simple cases like . What I could realistically do is look for without any spaces separating the two . That isn't the right way to handle it, but it would work for most cases. However, even that requires another change to . It would need to log the of the token before the present token. That's somewhat reasonable, as it already logs the previous token itself. Still, it's a bit much as a change to make to implement something in a quick but dirty way. I'm open to advice on whether a minimalist approach might be acceptable, but I'm currently inclined to leave this for someone who actually knows what they're doing.
you don't have to add a new method, you use . That function doesn't affect the "expected token" list and won't cause any effects to existing error messages. As for the context sensitive checks, you can also use to see if the next thing is something that looks like a range, a literal or an identifier and use that, as well as checking 's against the 's to see if they touch or not (differentiating between and . The case will need to be dealt with in a different part of the parser I think, and should recover in such a way as if you had written. Now, we don't need to address all the cases, we can work incrementally, starting on the low hanging fruit and eventually getting to the "perfect output from the compiler reading my mind". :)
Thanks, That's extraordinarily helpful. I've implemented this, limited to the case (so not or ). I'm going to wait till is merged, since that will simplify my implementation substantially and they'd merge conflict anyway. I'll you when I open the PR. Now to try this again: claim label +C-enhancement +D-newcomer-roadblock
Wow, well done Over time I hope that I can improve things myself. Nice work!

Discussion:
let span = self.mk_expr_sp(&lhs, lhs.span, rhs_span); let limits = if op == AssocOp::DotDot { RangeLimits::HalfOpen } else { RangeLimits::Closed }; <del> Ok(self.mk_expr(span, self.mk_range(Some(lhs), rhs, limits), AttrVec::new())) </del> <ins> let range = self.mk_range(Some(lhs), rhs, limits); Ok(self.mk_expr(span, range, AttrVec::new())) </ins> } fn is_at_start_of_range_notation_rhs(&self) -> bool {

} else { (lo, None) }; <del> Ok(this.mk_expr(span, this.mk_range(None, opt_end, limits), attrs.into())) </del> <ins> let range = this.mk_range(None, opt_end, limits); Ok(this.mk_expr(span, range, attrs.into())) </ins> }) }

} fn mk_range( <del> &self, </del> <ins> &mut self, </ins> start: Option<P<Expr>>, end: Option<P<Expr>>, limits: RangeLimits, ) -> ExprKind { if end.is_none() && limits == RangeLimits::Closed { <del> self.error_inclusive_range_with_no_end(self.prev_token.span); </del> <ins> self.inclusive_range_with_incorrect_end(self.prev_token.span); </ins> ExprKind::Err } else { ExprKind::Range(start, end, limits)

// Parsing e.g. `X..`. if let RangeEnd::Included(_) = re.node { // FIXME(Centril): Consider semantic errors instead in `ast_validation`. <del> // Possibly also do this for `X..=` in *expression* contexts. self.error_inclusive_range_with_no_end(re.span); </del> <ins> self.inclusive_range_with_incorrect_end(re.span); </ins> } None }; Ok(PatKind::Range(Some(begin), end, re)) } <del> pub(super) fn error_inclusive_range_with_no_end(&self, span: Span) { </del> <ins> 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) { </ins> struct_span_err!(self.sess.span_diagnostic, span, E0586, "inclusive range with no end") .span_suggestion_short( span,

<ins> // 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 } </ins>

<ins> 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 </ins>