Repository: rust-lang/rust-analyzer
Pull request #12177 (2022-05-06 14:12:18)

fix: fix macro expansion with float tokens
Fixes https://github.com/rust-lang/rust-analyzer/issues/12170

The parser tells us to consume up to 3 tokens, but on the MBE side all float literals are a single `tt::Literal`, so make sure to only consume a single MBE leaf.


Patch:
diff --git a/crates/mbe/src/syntax_bridge.rs b/crates/mbe/src/syntax_bridge.rs
index 79fd1250e0..83d22af923 100644
--- a/crates/mbe/src/syntax_bridge.rs
+++ b/crates/mbe/src/syntax_bridge.rs
@@ -266,11 +266,13 @@ fn convert_tokens<C: TokenConvertor>(conv: &mut C) -> tt::Subtree {
                     let mut text = token.to_text(conv).to_string();
                     if kind == FLOAT_NUMBER_START_1 || kind == FLOAT_NUMBER_START_2 {
                         let (dot, dot_range) = conv.bump().unwrap();
+                        assert_eq!(dot.kind(conv), DOT);
                         text += &*dot.to_text(conv);
                         range = TextRange::new(range.start(), dot_range.end());
 
                         if kind == FLOAT_NUMBER_START_2 {
                             let (tail, tail_range) = conv.bump().unwrap();
+                            assert_eq!(tail.kind(conv), FLOAT_NUMBER_PART);
                             text += &*tail.to_text(conv);
                             range = TextRange::new(range.start(), tail_range.end());
                         }
diff --git a/crates/mbe/src/tt_iter.rs b/crates/mbe/src/tt_iter.rs
index fc5590b718..2dbf1f3198 100644
--- a/crates/mbe/src/tt_iter.rs
+++ b/crates/mbe/src/tt_iter.rs
@@ -90,9 +90,20 @@ impl<'a> TtIter<'a> {
 
         let mut cursor = buffer.begin();
         let mut error = false;
+        let mut float_fragments_to_skip = 0;
         for step in tree_traversal.iter() {
             match step {
                 parser::Step::Token { kind, mut n_input_tokens } => {
+                    if float_fragments_to_skip > 0 {
+                        float_fragments_to_skip -= 1;
+                        n_input_tokens = 0;
+                    }
+                    match kind {
+                        SyntaxKind::LIFETIME_IDENT => n_input_tokens = 2,
+                        SyntaxKind::FLOAT_NUMBER_START_1 => float_fragments_to_skip = 1,
+                        SyntaxKind::FLOAT_NUMBER_START_2 => float_fragments_to_skip = 2,
+                        _ => {}
+                    }
                     if kind == SyntaxKind::LIFETIME_IDENT {
                         n_input_tokens = 2;
                     }


Test patch:
diff --git a/crates/hir-def/src/macro_expansion_tests/mbe/meta_syntax.rs b/crates/hir-def/src/macro_expansion_tests/mbe/meta_syntax.rs
index 2de10ddbdf..66cc2843d6 100644
--- a/crates/hir-def/src/macro_expansion_tests/mbe/meta_syntax.rs
+++ b/crates/hir-def/src/macro_expansion_tests/mbe/meta_syntax.rs
@@ -80,7 +80,7 @@ macro_rules! f3 { ($i:_) => () }
 
 #[test]
 fn test_rustc_issue_57597() {
-    // <https://github.com/rust-lang/rust/blob/master/src/test/ui/issues/issue-57597.rs>
+    // <https://github.com/rust-lang/rust/blob/master/src/test/ui/macros/issue-57597.rs>
     check(
         r#"
 macro_rules! m0 { ($($($i:ident)?)+) => {}; }
diff --git a/crates/hir-def/src/macro_expansion_tests/mbe/tt_conversion.rs b/crates/hir-def/src/macro_expansion_tests/mbe/tt_conversion.rs
index 84cc3f3872..0f606f3cfd 100644
--- a/crates/hir-def/src/macro_expansion_tests/mbe/tt_conversion.rs
+++ b/crates/hir-def/src/macro_expansion_tests/mbe/tt_conversion.rs
@@ -38,6 +38,7 @@ macro_rules! m {
         let _ = 12E+99_f64;
         let _ = "rust1";
         let _ = -92;
+        let _ = -1.3e4f32;
     }
 }
 fn f() {
@@ -52,6 +53,7 @@ macro_rules! m {
         let _ = 12E+99_f64;
         let _ = "rust1";
         let _ = -92;
+        let _ = -1.3e4f32;
     }
 }
 fn f() {
@@ -60,6 +62,7 @@ fn f() {
     let _ = 12E+99_f64;
     let _ = "rust1";
     let _ = -92;
+    let _ = -1.3e4f32;
 }
 "#]],
     );
@@ -148,3 +151,27 @@ $ = ();
 "#]],
     )
 }
+
+#[test]
+fn float_literal_in_output() {
+    check(
+        r#"
+macro_rules! constant {
+    ($e:expr ;) => {$e};
+}
+
+const _: () = constant!(0.0;);
+const _: () = constant!(0.;);
+const _: () = constant!(0e0;);
+"#,
+        expect![[r#"
+macro_rules! constant {
+    ($e:expr ;) => {$e};
+}
+
+const _: () = 0.0;
+const _: () = 0.;
+const _: () = 0e0;
+"#]],
+    );
+}