about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_parse/src/parser/diagnostics.rs25
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs10
-rw-r--r--tests/ui/parser/range-exclusive-dotdotlt.rs43
-rw-r--r--tests/ui/parser/range-exclusive-dotdotlt.stderr46
4 files changed, 117 insertions, 7 deletions
diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs
index a9cf26d991c..dc7a4d5aa38 100644
--- a/compiler/rustc_parse/src/parser/diagnostics.rs
+++ b/compiler/rustc_parse/src/parser/diagnostics.rs
@@ -23,7 +23,7 @@ use crate::parser;
 use crate::parser::attr::InnerAttrPolicy;
 use rustc_ast as ast;
 use rustc_ast::ptr::P;
-use rustc_ast::token::{self, Delimiter, Lit, LitKind, TokenKind};
+use rustc_ast::token::{self, Delimiter, Lit, LitKind, Token, TokenKind};
 use rustc_ast::tokenstream::AttrTokenTree;
 use rustc_ast::util::parser::AssocOp;
 use rustc_ast::{
@@ -448,12 +448,11 @@ impl<'a> Parser<'a> {
             })
         }
 
-        let mut expected = edible
+        self.expected_tokens.extend(edible.iter().chain(inedible).cloned().map(TokenType::Token));
+        let mut expected = self
+            .expected_tokens
             .iter()
-            .chain(inedible)
             .cloned()
-            .map(TokenType::Token)
-            .chain(self.expected_tokens.iter().cloned())
             .filter(|token| {
                 // Filter out suggestions that suggest the same token which was found and deemed incorrect.
                 fn is_ident_eq_keyword(found: &TokenKind, expected: &TokenType) -> bool {
@@ -2927,6 +2926,22 @@ impl<'a> Parser<'a> {
         Ok(())
     }
 
+    /// Check for exclusive ranges written as `..<`
+    pub(crate) fn maybe_err_dotdotlt_syntax(&self, maybe_lt: Token, mut err: PErr<'a>) -> PErr<'a> {
+        if maybe_lt == token::Lt
+            && (self.expected_tokens.contains(&TokenType::Token(token::Gt))
+                || matches!(self.token.kind, token::Literal(..)))
+        {
+            err.span_suggestion(
+                maybe_lt.span,
+                "remove the `<` to write an exclusive range",
+                "",
+                Applicability::MachineApplicable,
+            );
+        }
+        err
+    }
+
     pub fn is_diff_marker(&mut self, long_kind: &TokenKind, short_kind: &TokenKind) -> bool {
         (0..3).all(|i| self.look_ahead(i, |tok| tok == long_kind))
             && self.look_ahead(3, |tok| tok == short_kind)
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index db777266b59..7f4d26b370f 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -483,7 +483,11 @@ impl<'a> Parser<'a> {
         cur_op_span: Span,
     ) -> PResult<'a, P<Expr>> {
         let rhs = if self.is_at_start_of_range_notation_rhs() {
-            Some(self.parse_expr_assoc_with(prec + 1, LhsExpr::NotYetParsed)?)
+            let maybe_lt = self.token.clone();
+            Some(
+                self.parse_expr_assoc_with(prec + 1, LhsExpr::NotYetParsed)
+                    .map_err(|err| self.maybe_err_dotdotlt_syntax(maybe_lt, err))?,
+            )
         } else {
             None
         };
@@ -532,11 +536,13 @@ impl<'a> Parser<'a> {
         let attrs = self.parse_or_use_outer_attributes(attrs)?;
         self.collect_tokens_for_expr(attrs, |this, attrs| {
             let lo = this.token.span;
+            let maybe_lt = this.look_ahead(1, |t| t.clone());
             this.bump();
             let (span, opt_end) = if this.is_at_start_of_range_notation_rhs() {
                 // RHS must be parsed with more associativity than the dots.
                 this.parse_expr_assoc_with(op.unwrap().precedence() + 1, LhsExpr::NotYetParsed)
-                    .map(|x| (lo.to(x.span), Some(x)))?
+                    .map(|x| (lo.to(x.span), Some(x)))
+                    .map_err(|err| this.maybe_err_dotdotlt_syntax(maybe_lt, err))?
             } else {
                 (lo, None)
             };
diff --git a/tests/ui/parser/range-exclusive-dotdotlt.rs b/tests/ui/parser/range-exclusive-dotdotlt.rs
new file mode 100644
index 00000000000..5752566026f
--- /dev/null
+++ b/tests/ui/parser/range-exclusive-dotdotlt.rs
@@ -0,0 +1,43 @@
+fn foo() {
+    let _ = 0..<10;
+    //~^ ERROR: expected type, found `10`
+    //~| HELP: remove the `<` to write an exclusive range
+}
+
+fn bar() {
+    let _ = 0..<foo;
+    //~^ ERROR: expected one of `!`, `(`, `+`, `::`, `<`, `>`, or `as`, found `;`
+    //~| HELP: remove the `<` to write an exclusive range
+}
+
+fn baz() {
+    let _ = <foo>;
+    //~^ ERROR: expected `::`, found `;`
+}
+
+fn qux() {
+    let _ = [1, 2, 3][..<1];
+    //~^ ERROR: expected type, found `1`
+    //~| HELP: remove the `<` to write an exclusive range
+}
+
+fn quux() {
+    let _ = [1, 2, 3][..<foo];
+    //~^ ERROR: expected one of `!`, `(`, `+`, `::`, `<`, `>`, or `as`, found `]`
+    //~| HELP: remove the `<` to write an exclusive range
+}
+
+fn foobar() {
+    let _ = [1, 2, 3][..<foo>];
+    //~^ ERROR: expected `::`, found `]`
+}
+
+fn ok1() {
+    let _ = [1, 2, 3][..<usize>::default()];
+}
+
+fn ok2() {
+    let _ = 0..<i32>::default();
+}
+
+fn main() {}
diff --git a/tests/ui/parser/range-exclusive-dotdotlt.stderr b/tests/ui/parser/range-exclusive-dotdotlt.stderr
new file mode 100644
index 00000000000..af25e1df343
--- /dev/null
+++ b/tests/ui/parser/range-exclusive-dotdotlt.stderr
@@ -0,0 +1,46 @@
+error: expected type, found `10`
+  --> $DIR/range-exclusive-dotdotlt.rs:2:17
+   |
+LL |     let _ = 0..<10;
+   |                -^^ expected type
+   |                |
+   |                help: remove the `<` to write an exclusive range
+
+error: expected one of `!`, `(`, `+`, `::`, `<`, `>`, or `as`, found `;`
+  --> $DIR/range-exclusive-dotdotlt.rs:8:20
+   |
+LL |     let _ = 0..<foo;
+   |                -   ^ expected one of 7 possible tokens
+   |                |
+   |                help: remove the `<` to write an exclusive range
+
+error: expected `::`, found `;`
+  --> $DIR/range-exclusive-dotdotlt.rs:14:18
+   |
+LL |     let _ = <foo>;
+   |                  ^ expected `::`
+
+error: expected type, found `1`
+  --> $DIR/range-exclusive-dotdotlt.rs:19:26
+   |
+LL |     let _ = [1, 2, 3][..<1];
+   |                         -^ expected type
+   |                         |
+   |                         help: remove the `<` to write an exclusive range
+
+error: expected one of `!`, `(`, `+`, `::`, `<`, `>`, or `as`, found `]`
+  --> $DIR/range-exclusive-dotdotlt.rs:25:29
+   |
+LL |     let _ = [1, 2, 3][..<foo];
+   |                         -   ^ expected one of 7 possible tokens
+   |                         |
+   |                         help: remove the `<` to write an exclusive range
+
+error: expected `::`, found `]`
+  --> $DIR/range-exclusive-dotdotlt.rs:31:30
+   |
+LL |     let _ = [1, 2, 3][..<foo>];
+   |                              ^ expected `::`
+
+error: aborting due to 6 previous errors
+