diff --git a/crates/hir-def/src/expr_store/lower/format_args.rs b/crates/hir-def/src/expr_store/lower/format_args.rs index 5552213aba55..ad548c6758c1 100644 --- a/crates/hir-def/src/expr_store/lower/format_args.rs +++ b/crates/hir-def/src/expr_store/lower/format_args.rs @@ -1,10 +1,13 @@ //! Lowering of `format_args!()`. use base_db::FxIndexSet; -use hir_expand::name::Name; +use hir_expand::name::{AsName, Name}; use intern::{Symbol, sym}; use span::SyntaxContext; -use syntax::{AstPtr, AstToken as _, ast}; +use syntax::{ + AstPtr, AstToken as _, + ast::{self, HasName}, +}; use crate::{ expr_store::{HygieneId, lower::ExprCollector, path::Path}, @@ -29,8 +32,8 @@ impl<'db> ExprCollector<'db> { f.args().for_each(|arg| { let expr = arg.expr(); args.add(FormatArgument { - kind: match arg.arg_name() { - Some(name) => FormatArgumentKind::Named(Name::new_root(name.name().text())), + kind: match arg.name() { + Some(name) => FormatArgumentKind::Named(name.as_name()), None => FormatArgumentKind::Normal, }, syntax: expr.as_ref().map(AstPtr::new), diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html b/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html index da553cebb6b7..b5ace7287d89 100644 --- a/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html +++ b/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html @@ -101,18 +101,18 @@ println!("Hello, {}!", "world"); // => "Hello, world!" println!("The number is {}", 1); // => "The number is 1" println!("{:?}", (3, 4)); // => "(3, 4)" - println!("{value}", value=4); // => "4" + println!("{value}", value=4); // => "4" println!("{} {}", 1, 2); // => "1 2" println!("{:04}", 42); // => "0042" with leading zerosV println!("{1} {} {0} {}", 1, 2); // => "2 1 1 2" - println!("{argument}", argument = "test"); // => "test" - println!("{name} {}", 1, name = 2); // => "2 1" - println!("{a} {c} {b}", a="a", b='b', c=3); // => "a 3 b" + println!("{argument}", argument = "test"); // => "test" + println!("{name} {}", 1, name = 2); // => "2 1" + println!("{a} {c} {b}", a="a", b='b', c=3); // => "a 3 b" println!("{{{}}}", 2); // => "{2}" println!("Hello {:5}!", "x"); println!("Hello {:1$}!", "x", 5); println!("Hello {1:0$}!", 5, "x"); - println!("Hello {:width$}!", "x", width = 5); + println!("Hello {:width$}!", "x", width = 5); println!("Hello {:<5}!", "x"); println!("Hello {:-<5}!", "x"); println!("Hello {:^5}!", "x"); @@ -127,10 +127,10 @@ println!("Hello {0} is {2:.1$}", "x", 5, 0.01); println!("Hello {} is {:.*}", "x", 5, 0.01); println!("Hello {} is {2:.*}", "x", 5, 0.01); - println!("Hello {} is {number:.prec$}", "x", prec = 5, number = 0.01); - println!("{}, `{name:.*}` has 3 fractional digits", "Hello", 3, name=1234.56); - println!("{}, `{name:.*}` has 3 characters", "Hello", 3, name="1234.56"); - println!("{}, `{name:>8.*}` has 3 right-aligned characters", "Hello", 3, name="1234.56"); + println!("Hello {} is {number:.prec$}", "x", prec = 5, number = 0.01); + println!("{}, `{name:.*}` has 3 fractional digits", "Hello", 3, name=1234.56); + println!("{}, `{name:.*}` has 3 characters", "Hello", 3, name="1234.56"); + println!("{}, `{name:>8.*}` has 3 right-aligned characters", "Hello", 3, name="1234.56"); let _ = "{}" let _ = "{{}}"; @@ -154,8 +154,8 @@ let _ = c"\u{FF}\xFF"; // valid bytes, valid unicodes let backslash = r"\\"; - println!("{\x41}", A = 92); - println!("{ничоси}", ничоси = 92); + println!("{\x41}", A = 92); + println!("{ничоси}", ничоси = 92); println!("{:x?} {} ", thingy, n2); panic!("{}", 0); diff --git a/crates/parser/src/grammar.rs b/crates/parser/src/grammar.rs index 0623e7ea19ab..0305733af2d4 100644 --- a/crates/parser/src/grammar.rs +++ b/crates/parser/src/grammar.rs @@ -343,6 +343,12 @@ fn name(p: &mut Parser<'_>) { name_r(p, TokenSet::EMPTY); } +fn name_any_identifier(p: &mut Parser<'_>) { + let m = p.start(); + p.bump_remap_any_ident(); + m.complete(p, NAME); +} + fn name_ref_or_self(p: &mut Parser<'_>) { if matches!(p.current(), T![ident] | T![self]) { let m = p.start(); diff --git a/crates/parser/src/grammar/expressions/atom.rs b/crates/parser/src/grammar/expressions/atom.rs index 7ce1fc2c4895..d1f4d4553b77 100644 --- a/crates/parser/src/grammar/expressions/atom.rs +++ b/crates/parser/src/grammar/expressions/atom.rs @@ -291,10 +291,8 @@ fn builtin_expr(p: &mut Parser<'_>) -> Option { while !p.at(EOF) && !p.at(T![')']) { let m = p.start(); if p.current().is_any_identifier() && p.nth_at(1, T![=]) && !p.nth_at(2, T![=]) { - let m = p.start(); - p.bump_any(); + name_any_identifier(p); p.bump(T![=]); - m.complete(p, FORMAT_ARGS_ARG_NAME); } if expr(p).is_none() { m.abandon(p); @@ -376,8 +374,12 @@ pub(crate) fn parse_asm_expr(p: &mut Parser<'_>, m: Marker) -> Option Parser<'t> { true } + /// This consumes the next token as an identifier, even if it is a strict keyword. + pub(crate) fn bump_remap_any_ident(&mut self) { + assert!(self.current().is_any_identifier()); + self.bump_remap(T![ident]); + } + fn at_composite2(&self, n: usize, k1: SyntaxKind, k2: SyntaxKind) -> bool { self.inp.kind(self.pos + n) == k1 && self.inp.kind(self.pos + n + 1) == k2 diff --git a/crates/parser/src/syntax_kind/generated.rs b/crates/parser/src/syntax_kind/generated.rs index 1c4fcf080f4a..5604da5026e9 100644 --- a/crates/parser/src/syntax_kind/generated.rs +++ b/crates/parser/src/syntax_kind/generated.rs @@ -214,7 +214,6 @@ pub enum SyntaxKind { FN, FN_PTR_TYPE, FORMAT_ARGS_ARG, - FORMAT_ARGS_ARG_NAME, FORMAT_ARGS_EXPR, FOR_BINDER, FOR_EXPR, @@ -402,7 +401,6 @@ impl SyntaxKind { | FN | FN_PTR_TYPE | FORMAT_ARGS_ARG - | FORMAT_ARGS_ARG_NAME | FORMAT_ARGS_EXPR | FOR_BINDER | FOR_EXPR diff --git a/crates/parser/test_data/generated/runner.rs b/crates/parser/test_data/generated/runner.rs index 22b568458125..f559c8ee2ff5 100644 --- a/crates/parser/test_data/generated/runner.rs +++ b/crates/parser/test_data/generated/runner.rs @@ -21,6 +21,10 @@ mod ok { #[test] fn asm_expr() { run_and_expect_no_errors("test_data/parser/inline/ok/asm_expr.rs"); } #[test] + fn asm_keyword_name() { + run_and_expect_no_errors("test_data/parser/inline/ok/asm_keyword_name.rs"); + } + #[test] fn asm_kinds() { run_and_expect_no_errors("test_data/parser/inline/ok/asm_kinds.rs"); } #[test] fn asm_label() { run_and_expect_no_errors("test_data/parser/inline/ok/asm_label.rs"); } diff --git a/crates/parser/test_data/parser/inline/ok/asm_keyword_name.rast b/crates/parser/test_data/parser/inline/ok/asm_keyword_name.rast new file mode 100644 index 000000000000..4c97562f9a43 --- /dev/null +++ b/crates/parser/test_data/parser/inline/ok/asm_keyword_name.rast @@ -0,0 +1,42 @@ +SOURCE_FILE + FN + FN_KW "fn" + WHITESPACE " " + NAME + IDENT "foo" + PARAM_LIST + L_PAREN "(" + R_PAREN ")" + WHITESPACE " " + BLOCK_EXPR + STMT_LIST + L_CURLY "{" + WHITESPACE "\n " + EXPR_STMT + ASM_EXPR + BUILTIN_KW "builtin" + WHITESPACE " " + POUND "#" + WHITESPACE " " + ASM_KW "asm" + L_PAREN "(" + LITERAL + STRING "\"\"" + COMMA "," + WHITESPACE " " + ASM_OPERAND_NAMED + NAME + IDENT "fn" + WHITESPACE " " + EQ "=" + WHITESPACE " " + ASM_CONST + CONST_KW "const" + WHITESPACE " " + LITERAL + INT_NUMBER "0" + R_PAREN ")" + SEMICOLON ";" + WHITESPACE "\n" + R_CURLY "}" + WHITESPACE "\n" diff --git a/crates/parser/test_data/parser/inline/ok/asm_keyword_name.rs b/crates/parser/test_data/parser/inline/ok/asm_keyword_name.rs new file mode 100644 index 000000000000..a8f1ab285868 --- /dev/null +++ b/crates/parser/test_data/parser/inline/ok/asm_keyword_name.rs @@ -0,0 +1,3 @@ +fn foo() { + builtin # asm("", fn = const 0); +} diff --git a/crates/parser/test_data/parser/inline/ok/builtin_expr.rast b/crates/parser/test_data/parser/inline/ok/builtin_expr.rast index 78c3bee4c88a..19a84ac54096 100644 --- a/crates/parser/test_data/parser/inline/ok/builtin_expr.rast +++ b/crates/parser/test_data/parser/inline/ok/builtin_expr.rast @@ -44,10 +44,10 @@ SOURCE_FILE COMMA "," WHITESPACE " " FORMAT_ARGS_ARG - FORMAT_ARGS_ARG_NAME + NAME IDENT "a" - WHITESPACE " " - EQ "=" + WHITESPACE " " + EQ "=" WHITESPACE " " BIN_EXPR LITERAL diff --git a/crates/parser/test_data/parser/inline/ok/format_args_named_arg_keyword.rast b/crates/parser/test_data/parser/inline/ok/format_args_named_arg_keyword.rast index 03bc2ecf7c21..50b9208b3e54 100644 --- a/crates/parser/test_data/parser/inline/ok/format_args_named_arg_keyword.rast +++ b/crates/parser/test_data/parser/inline/ok/format_args_named_arg_keyword.rast @@ -23,9 +23,9 @@ SOURCE_FILE COMMA "," WHITESPACE " " FORMAT_ARGS_ARG - FORMAT_ARGS_ARG_NAME - TYPE_KW "type" - EQ "=" + NAME + IDENT "type" + EQ "=" LITERAL INT_NUMBER "1" R_PAREN ")" diff --git a/crates/syntax/rust.ungram b/crates/syntax/rust.ungram index 05df8b9b1488..7a24b32c87cf 100644 --- a/crates/syntax/rust.ungram +++ b/crates/syntax/rust.ungram @@ -488,10 +488,7 @@ FormatArgsExpr = ')' FormatArgsArg = - arg_name:FormatArgsArgName? Expr - -FormatArgsArgName = - '=' // This also has a name, but it's any token and we can't put it here + (Name '=')? Expr MacroExpr = MacroCall diff --git a/crates/syntax/src/ast/generated/nodes.rs b/crates/syntax/src/ast/generated/nodes.rs index e0992ab9cfba..5fa56cf33c5d 100644 --- a/crates/syntax/src/ast/generated/nodes.rs +++ b/crates/syntax/src/ast/generated/nodes.rs @@ -723,16 +723,10 @@ impl ForType { pub struct FormatArgsArg { pub(crate) syntax: SyntaxNode, } +impl ast::HasName for FormatArgsArg {} impl FormatArgsArg { - #[inline] - pub fn arg_name(&self) -> Option { support::child(&self.syntax) } #[inline] pub fn expr(&self) -> Option { support::child(&self.syntax) } -} -pub struct FormatArgsArgName { - pub(crate) syntax: SyntaxNode, -} -impl FormatArgsArgName { #[inline] pub fn eq_token(&self) -> Option { support::token(&self.syntax, T![=]) } } @@ -4105,38 +4099,6 @@ impl fmt::Debug for FormatArgsArg { f.debug_struct("FormatArgsArg").field("syntax", &self.syntax).finish() } } -impl AstNode for FormatArgsArgName { - #[inline] - fn kind() -> SyntaxKind - where - Self: Sized, - { - FORMAT_ARGS_ARG_NAME - } - #[inline] - fn can_cast(kind: SyntaxKind) -> bool { kind == FORMAT_ARGS_ARG_NAME } - #[inline] - fn cast(syntax: SyntaxNode) -> Option { - if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None } - } - #[inline] - fn syntax(&self) -> &SyntaxNode { &self.syntax } -} -impl hash::Hash for FormatArgsArgName { - fn hash(&self, state: &mut H) { self.syntax.hash(state); } -} -impl Eq for FormatArgsArgName {} -impl PartialEq for FormatArgsArgName { - fn eq(&self, other: &Self) -> bool { self.syntax == other.syntax } -} -impl Clone for FormatArgsArgName { - fn clone(&self) -> Self { Self { syntax: self.syntax.clone() } } -} -impl fmt::Debug for FormatArgsArgName { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("FormatArgsArgName").field("syntax", &self.syntax).finish() - } -} impl AstNode for FormatArgsExpr { #[inline] fn kind() -> SyntaxKind @@ -9810,6 +9772,7 @@ impl AstNode for AnyHasName { | CONST_PARAM | ENUM | FN + | FORMAT_ARGS_ARG | IDENT_PAT | MACRO_DEF | MACRO_RULES @@ -9868,6 +9831,10 @@ impl From for AnyHasName { #[inline] fn from(node: Fn) -> AnyHasName { AnyHasName { syntax: node.syntax } } } +impl From for AnyHasName { + #[inline] + fn from(node: FormatArgsArg) -> AnyHasName { AnyHasName { syntax: node.syntax } } +} impl From for AnyHasName { #[inline] fn from(node: IdentPat) -> AnyHasName { AnyHasName { syntax: node.syntax } } @@ -10434,11 +10401,6 @@ impl std::fmt::Display for FormatArgsArg { std::fmt::Display::fmt(self.syntax(), f) } } -impl std::fmt::Display for FormatArgsArgName { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - std::fmt::Display::fmt(self.syntax(), f) - } -} impl std::fmt::Display for FormatArgsExpr { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) diff --git a/crates/syntax/src/ast/node_ext.rs b/crates/syntax/src/ast/node_ext.rs index 43bca6ed9e63..672e2fd233e4 100644 --- a/crates/syntax/src/ast/node_ext.rs +++ b/crates/syntax/src/ast/node_ext.rs @@ -1169,15 +1169,6 @@ impl From for ast::AnyHasAttrs { } } -impl ast::FormatArgsArgName { - /// This is not a [`ast::Name`], because the name may be a keyword. - pub fn name(&self) -> SyntaxToken { - let name = self.syntax.first_token().unwrap(); - assert!(name.kind().is_any_identifier()); - name - } -} - impl ast::OrPat { pub fn leading_pipe(&self) -> Option { self.syntax