diff --git a/crates/hir-def/src/macro_expansion_tests/mbe/regression.rs b/crates/hir-def/src/macro_expansion_tests/mbe/regression.rs
index d8e4a4dcc7c..b783de4ccc2 100644
--- a/crates/hir-def/src/macro_expansion_tests/mbe/regression.rs
+++ b/crates/hir-def/src/macro_expansion_tests/mbe/regression.rs
@@ -909,3 +909,30 @@ macro_rules! with_std {
 "##]],
     )
 }
+
+#[test]
+fn eager_regression_15403() {
+    check(
+        r#"
+#[rustc_builtin_macro]
+#[macro_export]
+macro_rules! format_args {}
+
+fn main() {
+    format_args /* +errors */ !("{}", line.1.);
+}
+
+"#,
+        expect![[r##"
+#[rustc_builtin_macro]
+#[macro_export]
+macro_rules! format_args {}
+
+fn main() {
+    /* error: expected field name or number *//* parse error: expected field name or number */
+::core::fmt::Arguments::new_v1(&["", ], &[::core::fmt::ArgumentV1::new(&(line.1.), ::core::fmt::Display::fmt), ]);
+}
+
+"##]],
+    );
+}
diff --git a/crates/mbe/src/syntax_bridge.rs b/crates/mbe/src/syntax_bridge.rs
index 62b2accf5cd..7b9bb61e696 100644
--- a/crates/mbe/src/syntax_bridge.rs
+++ b/crates/mbe/src/syntax_bridge.rs
@@ -961,6 +961,7 @@ impl TtTreeSink<'_> {
                 if has_pseudo_dot {
                     assert!(right.is_empty(), "{left}.{right}");
                 } else {
+                    assert!(!right.is_empty(), "{left}.{right}");
                     self.inner.start_node(SyntaxKind::NAME_REF);
                     self.inner.token(SyntaxKind::INT_NUMBER, right);
                     self.inner.finish_node();
diff --git a/crates/parser/src/shortcuts.rs b/crates/parser/src/shortcuts.rs
index 53cdad64992..2c47e3d086d 100644
--- a/crates/parser/src/shortcuts.rs
+++ b/crates/parser/src/shortcuts.rs
@@ -46,12 +46,16 @@ impl LexedStr<'_> {
                     // Tag the token as joint if it is float with a fractional part
                     // we use this jointness to inform the parser about what token split
                     // event to emit when we encounter a float literal in a field access
-                    if kind == SyntaxKind::FLOAT_NUMBER && !self.text(i).ends_with('.') {
-                        res.was_joint();
+                    if kind == SyntaxKind::FLOAT_NUMBER {
+                        if !self.text(i).ends_with('.') {
+                            res.was_joint();
+                        } else {
+                            was_joint = false;
+                        }
+                    } else {
+                        was_joint = true;
                     }
                 }
-
-                was_joint = true;
             }
         }
         res
@@ -204,6 +208,7 @@ impl Builder<'_, '_> {
                     assert!(right.is_empty(), "{left}.{right}");
                     self.state = State::Normal;
                 } else {
+                    assert!(!right.is_empty(), "{left}.{right}");
                     (self.sink)(StrStep::Enter { kind: SyntaxKind::NAME_REF });
                     (self.sink)(StrStep::Token { kind: SyntaxKind::INT_NUMBER, text: right });
                     (self.sink)(StrStep::Exit);
diff --git a/crates/syntax/src/lib.rs b/crates/syntax/src/lib.rs
index 4cd668a0cd5..27c8a13e58d 100644
--- a/crates/syntax/src/lib.rs
+++ b/crates/syntax/src/lib.rs
@@ -195,11 +195,16 @@ impl ast::TokenTree {
                     // Tag the token as joint if it is float with a fractional part
                     // we use this jointness to inform the parser about what token split
                     // event to emit when we encounter a float literal in a field access
-                    if kind == SyntaxKind::FLOAT_NUMBER && !t.text().ends_with('.') {
-                        parser_input.was_joint();
+                    if kind == SyntaxKind::FLOAT_NUMBER {
+                        if !t.text().ends_with('.') {
+                            parser_input.was_joint();
+                        } else {
+                            was_joint = false;
+                        }
+                    } else {
+                        was_joint = true;
                     }
                 }
-                was_joint = true;
             }
         }
 
@@ -250,6 +255,7 @@ impl ast::TokenTree {
                             if has_pseudo_dot {
                                 assert!(right.is_empty(), "{left}.{right}");
                             } else {
+                                assert!(!right.is_empty(), "{left}.{right}");
                                 builder.start_node(SyntaxKind::NAME_REF);
                                 builder.token(SyntaxKind::INT_NUMBER, right);
                                 builder.finish_node();