about summary refs log tree commit diff
diff options
context:
space:
mode:
authorDavid Tolnay <dtolnay@gmail.com>2024-12-27 14:25:08 -0800
committerDavid Tolnay <dtolnay@gmail.com>2024-12-27 14:33:56 -0800
commit26bb4e64645d3f3e0ed0b2921738e56888f96fd1 (patch)
tree54f6022830fff10d7f50565245b6d531bbbcd2b7
parentc95f9f50de555454cbd931c026814e46793a820a (diff)
downloadrust-26bb4e64645d3f3e0ed0b2921738e56888f96fd1.tar.gz
rust-26bb4e64645d3f3e0ed0b2921738e56888f96fd1.zip
Skip parenthesis around tuple struct field calls
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/state/expr.rs4
-rw-r--r--compiler/rustc_parse/src/parser/diagnostics.rs2
-rw-r--r--compiler/rustc_span/src/symbol.rs6
-rw-r--r--tests/ui-fulldeps/pprust-parenthesis-insertion.rs2
4 files changed, 11 insertions, 3 deletions
diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
index dce76fb1e77..f7d8edc4743 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
@@ -213,7 +213,9 @@ impl<'a> State<'a> {
 
     fn print_expr_call(&mut self, func: &ast::Expr, args: &[P<ast::Expr>], fixup: FixupContext) {
         let needs_paren = match func.kind {
-            ast::ExprKind::Field(..) => true,
+            // In order to call a named field, needs parens: `(self.fun)()`
+            // But not for an unnamed field: `self.0()`
+            ast::ExprKind::Field(_, name) => !name.is_numeric(),
             _ => func.precedence() < ExprPrecedence::Unambiguous,
         };
 
diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs
index aab4e1b1afc..7df7e732925 100644
--- a/compiler/rustc_parse/src/parser/diagnostics.rs
+++ b/compiler/rustc_parse/src/parser/diagnostics.rs
@@ -1336,7 +1336,7 @@ impl<'a> Parser<'a> {
     ) -> bool {
         if let ExprKind::Binary(op, l1, r1) = &inner_op.kind {
             if let ExprKind::Field(_, ident) = l1.kind
-                && ident.as_str().parse::<i32>().is_err()
+                && !ident.is_numeric()
                 && !matches!(r1.kind, ExprKind::Lit(_))
             {
                 // The parser has encountered `foo.bar<baz`, the likelihood of the turbofish
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 3d202f11722..829127e7a62 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -2707,6 +2707,12 @@ impl Ident {
     pub fn is_raw_guess(self) -> bool {
         self.name.can_be_raw() && self.is_reserved()
     }
+
+    /// Whether this would be the identifier for a tuple field like `self.0`, as
+    /// opposed to a named field like `self.thing`.
+    pub fn is_numeric(self) -> bool {
+        !self.name.is_empty() && self.as_str().bytes().all(|b| b.is_ascii_digit())
+    }
 }
 
 /// Collect all the keywords in a given edition into a vector.
diff --git a/tests/ui-fulldeps/pprust-parenthesis-insertion.rs b/tests/ui-fulldeps/pprust-parenthesis-insertion.rs
index fa9b0300743..2697c5f66ce 100644
--- a/tests/ui-fulldeps/pprust-parenthesis-insertion.rs
+++ b/tests/ui-fulldeps/pprust-parenthesis-insertion.rs
@@ -79,7 +79,7 @@ static EXPRS: &[&str] = &[
     "if let _ = (true && false) {}",
     // Parentheses to call a named field, but not an unnamed field.
     "(self.fun)()",
-    "(self.0)()",  // FIXME: no parenthesis needed.
+    "self.0()",
     // Conditions end at the first curly brace, so struct expressions need to be
     // parenthesized. Except in a match guard, where conditions end at arrow.
     "if let _ = (Struct {}) {}",