Unnamed repository; edit this file 'description' to name the repository.
fix: Fix float parser hack creating empty NameRef tokens
Lukas Wirth 2023-08-08
parent d9e9ca2 · commit cba39f8
-rw-r--r--crates/hir-def/src/macro_expansion_tests/mbe/regression.rs27
-rw-r--r--crates/mbe/src/syntax_bridge.rs1
-rw-r--r--crates/parser/src/shortcuts.rs13
-rw-r--r--crates/syntax/src/lib.rs12
4 files changed, 46 insertions, 7 deletions
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 d8e4a4dcc7..b783de4ccc 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 62b2accf5c..7b9bb61e69 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 53cdad6499..2c47e3d086 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 4cd668a0cd..27c8a13e58 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();