diff --git a/src/librustc_parse/lexer/mod.rs b/src/librustc_parse/lexer/mod.rs index ac58cbb9e8dae..0f0c34682a636 100644 --- a/src/librustc_parse/lexer/mod.rs +++ b/src/librustc_parse/lexer/mod.rs @@ -182,7 +182,7 @@ impl<'a> StringReader<'a> { /// Turns simple `rustc_lexer::TokenKind` enum into a rich /// `librustc_ast::TokenKind`. This turns strings into interned /// symbols and runs additional validation. - fn cook_lexer_token(&self, token: rustc_lexer::TokenKind, start: BytePos) -> TokenKind { + fn cook_lexer_token(&mut self, token: rustc_lexer::TokenKind, start: BytePos) -> TokenKind { match token { rustc_lexer::TokenKind::LineComment => { let string = self.str_from(start); @@ -323,7 +323,7 @@ impl<'a> StringReader<'a> { } fn cook_lexer_literal( - &self, + &mut self, start: BytePos, suffix_start: BytePos, kind: rustc_lexer::LiteralKind, @@ -440,6 +440,16 @@ impl<'a> StringReader<'a> { _ => (), } + // tuple.0.0 + // ^^^ we truncate this "float" literal at the dot. + if self.ends_with(start, ".") && !self.ends_with(start, "..") { + if let Some(dot) = self.str_from(start).find('.') { + self.pos = start + BytePos(dot as u32); + let id = self.symbol_from(start); + return (token::Integer, id); + } + } + let id = self.symbol_from_to(start, suffix_start); (token::Float, id) } @@ -474,6 +484,11 @@ impl<'a> StringReader<'a> { &self.src[self.src_index(start)..self.src_index(end)] } + /// Whether the source text leading up to position `pos` ends with `suffix`. + fn ends_with(&self, pos: BytePos, suffix: &str) -> bool { + self.src[..self.src_index(pos)].ends_with(suffix) + } + fn forbid_bare_cr(&self, start: BytePos, s: &str, errmsg: &str) { let mut idx = 0; loop { diff --git a/src/librustc_parse/parser/expr.rs b/src/librustc_parse/parser/expr.rs index b205a4b322229..d4663fc88e09b 100644 --- a/src/librustc_parse/parser/expr.rs +++ b/src/librustc_parse/parser/expr.rs @@ -767,9 +767,6 @@ impl<'a> Parser<'a> { token::Literal(token::Lit { kind: token::Integer, symbol, suffix }) => { Ok(self.parse_tuple_field_access_expr(lo, base, symbol, suffix)) } - token::Literal(token::Lit { kind: token::Float, symbol, .. }) => { - self.recover_field_access_by_float_lit(lo, base, symbol) - } _ => { self.error_unexpected_after_dot(); Ok(base) @@ -777,51 +774,15 @@ impl<'a> Parser<'a> { } } - fn error_unexpected_after_dot(&self) { + fn error_unexpected_after_dot(&mut self) { // FIXME Could factor this out into non_fatal_unexpected or something. let actual = pprust::token_to_string(&self.token); self.struct_span_err(self.token.span, &format!("unexpected token: `{}`", actual)).emit(); - } - - fn recover_field_access_by_float_lit( - &mut self, - lo: Span, - base: P, - sym: Symbol, - ) -> PResult<'a, P> { - self.bump(); - - let fstr = sym.as_str(); - let msg = format!("unexpected token: `{}`", sym); - let mut err = self.struct_span_err(self.prev_token.span, &msg); - err.span_label(self.prev_token.span, "unexpected token"); - - if fstr.chars().all(|x| "0123456789.".contains(x)) { - let float = match fstr.parse::() { - Ok(f) => f, - Err(_) => { - err.emit(); - return Ok(base); - } - }; - let sugg = pprust::to_string(|s| { - s.popen(); - s.print_expr(&base); - s.s.word("."); - s.print_usize(float.trunc() as usize); - s.pclose(); - s.s.word("."); - s.s.word(fstr.splitn(2, '.').last().unwrap().to_string()) - }); - err.span_suggestion( - lo.to(self.prev_token.span), - "try parenthesizing the first index", - sugg, - Applicability::MachineApplicable, - ); + // Recover `tuple. 0.0`. + if let token::Literal(token::Lit { kind: token::Float, .. }) = self.token.kind { + self.bump(); } - Err(err) } fn parse_tuple_field_access_expr( diff --git a/src/test/ui/tuple/index-float.rs b/src/test/ui/tuple/index-float.rs new file mode 100644 index 0000000000000..673d32e4d4351 --- /dev/null +++ b/src/test/ui/tuple/index-float.rs @@ -0,0 +1,7 @@ +fn main() { + let tuple = (((),),); + + let _ = tuple. 0.0; //~ ERROR unexpected token: `0.0` + + let _ = tuple./*special cases*/0.0; //~ ERROR unexpected token: `0.0` +} diff --git a/src/test/ui/tuple/index-float.stderr b/src/test/ui/tuple/index-float.stderr new file mode 100644 index 0000000000000..505b91e5bbba5 --- /dev/null +++ b/src/test/ui/tuple/index-float.stderr @@ -0,0 +1,14 @@ +error: unexpected token: `0.0` + --> $DIR/index-float.rs:4:20 + | +LL | let _ = tuple. 0.0; + | ^^^ + +error: unexpected token: `0.0` + --> $DIR/index-float.rs:6:36 + | +LL | let _ = tuple./*special cases*/0.0; + | ^^^ + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/tuple/index-invalid.rs b/src/test/ui/tuple/index-invalid.rs new file mode 100644 index 0000000000000..d36f6cfe3df7f --- /dev/null +++ b/src/test/ui/tuple/index-invalid.rs @@ -0,0 +1,7 @@ +fn main() { + let _ = (((),),).1.0; //~ ERROR no field `1` on type `(((),),)` + + let _ = (((),),).0.1; //~ ERROR no field `1` on type `((),)` + + let _ = (((),),).000.000; //~ ERROR no field `000` on type `(((),),)` +} diff --git a/src/test/ui/tuple/index-invalid.stderr b/src/test/ui/tuple/index-invalid.stderr new file mode 100644 index 0000000000000..8d22f458a6c6e --- /dev/null +++ b/src/test/ui/tuple/index-invalid.stderr @@ -0,0 +1,21 @@ +error[E0609]: no field `1` on type `(((),),)` + --> $DIR/index-invalid.rs:2:22 + | +LL | let _ = (((),),).1.0; + | ^ + +error[E0609]: no field `1` on type `((),)` + --> $DIR/index-invalid.rs:4:24 + | +LL | let _ = (((),),).0.1; + | ^ + +error[E0609]: no field `000` on type `(((),),)` + --> $DIR/index-invalid.rs:6:22 + | +LL | let _ = (((),),).000.000; + | ^^^ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0609`. diff --git a/src/test/ui/tuple/indexing-in-macro.rs b/src/test/ui/tuple/indexing-in-macro.rs new file mode 100644 index 0000000000000..89696cd7fcf44 --- /dev/null +++ b/src/test/ui/tuple/indexing-in-macro.rs @@ -0,0 +1,9 @@ +// Broken by https://github.com/rust-lang/rust/pull/70420. + +macro_rules! m { + (.$l:literal) => {}; +} + +m!(.0.0); //~ ERROR no rules expected the token `.` + +fn main() {} diff --git a/src/test/ui/tuple/indexing-in-macro.stderr b/src/test/ui/tuple/indexing-in-macro.stderr new file mode 100644 index 0000000000000..78879262b0177 --- /dev/null +++ b/src/test/ui/tuple/indexing-in-macro.stderr @@ -0,0 +1,11 @@ +error: no rules expected the token `.` + --> $DIR/indexing-in-macro.rs:7:6 + | +LL | macro_rules! m { + | -------------- when calling this macro +... +LL | m!(.0.0); + | ^ no rules expected this token in macro call + +error: aborting due to previous error + diff --git a/src/test/ui/tuple/nested-index.rs b/src/test/ui/tuple/nested-index.rs new file mode 100644 index 0000000000000..a3232d6fc361e --- /dev/null +++ b/src/test/ui/tuple/nested-index.rs @@ -0,0 +1,12 @@ +// run-pass + +fn main () { + let n = (1, (2, 3)).1.1; + assert_eq!(n, 3); + + let n = (1, (2, (3, 4))).1.1.1; + assert_eq!(n, 4); + + // This is a range expression, not nested indexing. + let _ = 0.0..1.1; +} diff --git a/src/test/ui/tuple/tuple-float-index.fixed b/src/test/ui/tuple/tuple-float-index.fixed deleted file mode 100644 index cd1a85a9d2442..0000000000000 --- a/src/test/ui/tuple/tuple-float-index.fixed +++ /dev/null @@ -1,5 +0,0 @@ -// run-rustfix - -fn main () { - ((1, (2, 3)).1).1; //~ ERROR unexpected token: `1.1` -} diff --git a/src/test/ui/tuple/tuple-float-index.rs b/src/test/ui/tuple/tuple-float-index.rs deleted file mode 100644 index 1faabac2bcdac..0000000000000 --- a/src/test/ui/tuple/tuple-float-index.rs +++ /dev/null @@ -1,5 +0,0 @@ -// run-rustfix - -fn main () { - (1, (2, 3)).1.1; //~ ERROR unexpected token: `1.1` -} diff --git a/src/test/ui/tuple/tuple-float-index.stderr b/src/test/ui/tuple/tuple-float-index.stderr deleted file mode 100644 index a0ea0e0a30a72..0000000000000 --- a/src/test/ui/tuple/tuple-float-index.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error: unexpected token: `1.1` - --> $DIR/tuple-float-index.rs:4:17 - | -LL | (1, (2, 3)).1.1; - | ------------^^^ - | | | - | | unexpected token - | help: try parenthesizing the first index: `((1, (2, 3)).1).1` - -error: aborting due to previous error -