about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock4
-rw-r--r--crates/cfg/Cargo.toml2
-rw-r--r--crates/hir_def/Cargo.toml2
-rw-r--r--crates/hir_def/src/macro_expansion_tests.rs34
-rw-r--r--crates/hir_def/src/macro_expansion_tests/mbe.rs272
-rw-r--r--crates/hir_def/src/macro_expansion_tests/mbe/matching.rs12
-rw-r--r--crates/hir_def/src/macro_expansion_tests/mbe/meta_syntax.rs6
-rw-r--r--crates/hir_expand/Cargo.toml2
-rw-r--r--crates/hir_ty/Cargo.toml2
-rw-r--r--crates/ide/Cargo.toml2
-rw-r--r--crates/ide_assists/Cargo.toml2
-rw-r--r--crates/ide_completion/Cargo.toml2
-rw-r--r--crates/ide_db/Cargo.toml2
-rw-r--r--crates/ide_diagnostics/Cargo.toml2
-rw-r--r--crates/ide_ssr/Cargo.toml2
-rw-r--r--crates/mbe/Cargo.toml2
-rw-r--r--crates/mbe/src/tests/expand.rs229
-rw-r--r--crates/proc_macro_srv/Cargo.toml2
-rw-r--r--crates/project_model/Cargo.toml2
-rw-r--r--crates/rust-analyzer/Cargo.toml2
-rw-r--r--crates/syntax/Cargo.toml2
-rw-r--r--crates/syntax/src/lib.rs7
22 files changed, 309 insertions, 285 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 5aba6387f0b..68c8536b2f8 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -345,9 +345,9 @@ dependencies = [
 
 [[package]]
 name = "expect-test"
-version = "1.1.0"
+version = "1.2.0-pre.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2300477aab3a378f2ca00a4fbd4dc713654ab7ed790e4017493cb33656280633"
+checksum = "3a2f1664bc69648747878bfe3430ad9b58bc8d9b50b3b1df9f3c081345e33197"
 dependencies = [
  "dissimilar",
  "once_cell",
diff --git a/crates/cfg/Cargo.toml b/crates/cfg/Cargo.toml
index 132505fbf4a..f86199c8c38 100644
--- a/crates/cfg/Cargo.toml
+++ b/crates/cfg/Cargo.toml
@@ -16,7 +16,7 @@ tt = { path = "../tt", version = "0.0.0" }
 [dev-dependencies]
 mbe = { path = "../mbe" }
 syntax = { path = "../syntax" }
-expect-test = "1.1"
+expect-test = "1.2.0-pre.1"
 oorandom = "11"
 # We depend on both individually instead of using `features = ["derive"]` to microoptimize the
 # build graph: if the feature was enabled, syn would be built early on in the graph if `smolstr`
diff --git a/crates/hir_def/Cargo.toml b/crates/hir_def/Cargo.toml
index f5e60a4f54d..9573d5ac352 100644
--- a/crates/hir_def/Cargo.toml
+++ b/crates/hir_def/Cargo.toml
@@ -35,4 +35,4 @@ limit = { path = "../limit", version = "0.0.0" }
 
 [dev-dependencies]
 test_utils = { path = "../test_utils" }
-expect-test = "1.1"
+expect-test = "1.2.0-pre.1"
diff --git a/crates/hir_def/src/macro_expansion_tests.rs b/crates/hir_def/src/macro_expansion_tests.rs
index 96957471c83..c66c75c1436 100644
--- a/crates/hir_def/src/macro_expansion_tests.rs
+++ b/crates/hir_def/src/macro_expansion_tests.rs
@@ -28,7 +28,7 @@ use crate::{
     db::DefDatabase, nameres::ModuleSource, resolver::HasResolver, test_db::TestDB, AsMacroCall,
 };
 
-fn check(ra_fixture: &str, expect: Expect) {
+fn check(ra_fixture: &str, mut expect: Expect) {
     let db = TestDB::with_files(ra_fixture);
     let krate = db.crate_graph().iter().next().unwrap();
     let def_map = db.crate_def_map(krate);
@@ -65,16 +65,29 @@ fn check(ra_fixture: &str, expect: Expect) {
             format_to!(expn_text, "/* error: {} */", err);
         }
         if let Some((parse, _token_map)) = exp.value {
+            assert!(
+                parse.errors().is_empty(),
+                "parse errors in expansion: \n{:#?}",
+                parse.errors()
+            );
             let pp = pretty_print_macro_expansion(parse.syntax_node());
             let indent = IndentLevel::from_node(call.syntax());
             let pp = reindent(indent, pp);
             format_to!(expn_text, "{}", pp);
+            if call.to_string().contains("// +tree") {
+                let tree = format!("{:#?}", parse.syntax_node())
+                    .split_inclusive("\n")
+                    .map(|line| format!("// {}", line))
+                    .collect::<String>();
+                format_to!(expn_text, "\n{}", tree)
+            }
         }
         let range = call.syntax().text_range();
         let range: Range<usize> = range.into();
         expanded_text.replace_range(range, &expn_text)
     }
 
+    expect.indent(false);
     expect.assert_eq(&expanded_text);
 }
 
@@ -97,20 +110,37 @@ fn reindent(indent: IndentLevel, pp: String) -> String {
 fn pretty_print_macro_expansion(expn: SyntaxNode) -> String {
     let mut res = String::new();
     let mut prev_kind = SyntaxKind::EOF;
+    let mut indent_level = 0;
     for token in iter::successors(expn.first_token(), |t| t.next_token()) {
         let curr_kind = token.kind();
         let space = match (prev_kind, curr_kind) {
             _ if prev_kind.is_trivia() || curr_kind.is_trivia() => "",
+            (T!['{'], T!['}']) => "",
             (T![=], _) | (_, T![=]) => " ",
             (_, T!['{']) => " ",
-            (T![;] | T!['}'], _) => "\n",
+            (T![;] | T!['{'] | T!['}'], _) => "\n",
+            (_, T!['}']) => "\n",
             (IDENT | LIFETIME_IDENT, IDENT | LIFETIME_IDENT) => " ",
             (IDENT, _) if curr_kind.is_keyword() => " ",
             (_, IDENT) if prev_kind.is_keyword() => " ",
+            (T![>], IDENT) => " ",
+            (T![>], _) if curr_kind.is_keyword() => " ",
+            (T![->], _) | (_, T![->]) => " ",
+            (T![&&], _) | (_, T![&&]) => " ",
             _ => "",
         };
 
+        match prev_kind {
+            T!['{'] => indent_level += 1,
+            T!['}'] => indent_level -= 1,
+            _ => (),
+        }
+
         res.push_str(space);
+        if space == "\n" {
+            let level = if curr_kind == T!['}'] { indent_level - 1 } else { indent_level };
+            res.push_str(&"    ".repeat(level));
+        }
         prev_kind = curr_kind;
         format_to!(res, "{}", token)
     }
diff --git a/crates/hir_def/src/macro_expansion_tests/mbe.rs b/crates/hir_def/src/macro_expansion_tests/mbe.rs
index c57e9cd838d..384c70028df 100644
--- a/crates/hir_def/src/macro_expansion_tests/mbe.rs
+++ b/crates/hir_def/src/macro_expansion_tests/mbe.rs
@@ -10,6 +10,45 @@ use expect_test::expect;
 use crate::macro_expansion_tests::check;
 
 #[test]
+fn mbe_smoke_test() {
+    check(
+        r#"
+macro_rules! impl_froms {
+    ($e:ident: $($v:ident),*) => {
+        $(
+            impl From<$v> for $e {
+                fn from(it: $v) -> $e { $e::$v(it) }
+            }
+        )*
+    }
+}
+impl_froms!(TokenTree: Leaf, Subtree);
+"#,
+        expect![[r#"
+macro_rules! impl_froms {
+    ($e:ident: $($v:ident),*) => {
+        $(
+            impl From<$v> for $e {
+                fn from(it: $v) -> $e { $e::$v(it) }
+            }
+        )*
+    }
+}
+impl From<Leaf> for TokenTree {
+    fn from(it:Leaf) -> TokenTree {
+        TokenTree::Leaf(it)
+    }
+}
+impl From<Subtree> for TokenTree {
+    fn from(it:Subtree) -> TokenTree {
+        TokenTree::Subtree(it)
+    }
+}
+"#]],
+    );
+}
+
+#[test]
 fn expansion_does_not_parse_as_expression() {
     check(
         r#"
@@ -52,9 +91,9 @@ fn match_by_first_token_literally() {
     check(
         r#"
 macro_rules! m {
-    ($ i:ident) => ( mod $ i {} );
-    (= $ i:ident) => ( fn $ i() {} );
-    (+ $ i:ident) => ( struct $ i; )
+    ($i:ident) => ( mod $i {} );
+    (= $i:ident) => ( fn $i() {} );
+    (+ $i:ident) => ( struct $i; )
 }
 m! { foo }
 m! { = bar }
@@ -62,9 +101,9 @@ m! { + Baz }
 "#,
         expect![[r#"
 macro_rules! m {
-    ($ i:ident) => ( mod $ i {} );
-    (= $ i:ident) => ( fn $ i() {} );
-    (+ $ i:ident) => ( struct $ i; )
+    ($i:ident) => ( mod $i {} );
+    (= $i:ident) => ( fn $i() {} );
+    (+ $i:ident) => ( struct $i; )
 }
 mod foo {}
 fn bar() {}
@@ -78,9 +117,9 @@ fn match_by_last_token_literally() {
     check(
         r#"
 macro_rules! m {
-    ($ i:ident) => ( mod $ i {} );
-    ($ i:ident =) => ( fn $ i() {} );
-    ($ i:ident +) => ( struct $ i; )
+    ($i:ident) => ( mod $i {} );
+    ($i:ident =) => ( fn $i() {} );
+    ($i:ident +) => ( struct $i; )
 }
 m! { foo }
 m! { bar = }
@@ -88,9 +127,9 @@ m! { Baz + }
 "#,
         expect![[r#"
 macro_rules! m {
-    ($ i:ident) => ( mod $ i {} );
-    ($ i:ident =) => ( fn $ i() {} );
-    ($ i:ident +) => ( struct $ i; )
+    ($i:ident) => ( mod $i {} );
+    ($i:ident =) => ( fn $i() {} );
+    ($i:ident +) => ( struct $i; )
 }
 mod foo {}
 fn bar() {}
@@ -104,9 +143,9 @@ fn match_by_ident() {
     check(
         r#"
 macro_rules! m {
-    ($ i:ident) => ( mod $ i {} );
-    (spam $ i:ident) => ( fn $ i() {} );
-    (eggs $ i:ident) => ( struct $ i; )
+    ($i:ident) => ( mod $i {} );
+    (spam $i:ident) => ( fn $i() {} );
+    (eggs $i:ident) => ( struct $i; )
 }
 m! { foo }
 m! { spam bar }
@@ -114,9 +153,9 @@ m! { eggs Baz }
 "#,
         expect![[r#"
 macro_rules! m {
-    ($ i:ident) => ( mod $ i {} );
-    (spam $ i:ident) => ( fn $ i() {} );
-    (eggs $ i:ident) => ( struct $ i; )
+    ($i:ident) => ( mod $i {} );
+    (spam $i:ident) => ( fn $i() {} );
+    (eggs $i:ident) => ( struct $i; )
 }
 mod foo {}
 fn bar() {}
@@ -130,9 +169,9 @@ fn match_by_separator_token() {
     check(
         r#"
 macro_rules! m {
-    ($ ($ i:ident),*) => ($ ( mod $ i {} )*);
-    ($ ($ i:ident)#*) => ($ ( fn $ i() {} )*);
-    ($ i:ident ,# $ j:ident) => ( struct $ i; struct $ j; )
+    ($($i:ident),*) => ($(mod $i {} )*);
+    ($($i:ident)#*) => ($(fn $i() {} )*);
+    ($i:ident ,# $ j:ident) => ( struct $i; struct $ j; )
 }
 
 m! { foo, bar }
@@ -143,9 +182,9 @@ m! { Foo,# Bar }
 "#,
         expect![[r##"
 macro_rules! m {
-    ($ ($ i:ident),*) => ($ ( mod $ i {} )*);
-    ($ ($ i:ident)#*) => ($ ( fn $ i() {} )*);
-    ($ i:ident ,# $ j:ident) => ( struct $ i; struct $ j; )
+    ($($i:ident),*) => ($(mod $i {} )*);
+    ($($i:ident)#*) => ($(fn $i() {} )*);
+    ($i:ident ,# $ j:ident) => ( struct $i; struct $ j; )
 }
 
 mod foo {}
@@ -159,3 +198,188 @@ struct Bar;
 "##]],
     );
 }
+
+#[test]
+fn test_match_group_pattern_with_multiple_defs() {
+    check(
+        r#"
+macro_rules! m {
+    ($($i:ident),*) => ( impl Bar { $(fn $i() {})* } );
+}
+m! { foo, bar }
+"#,
+        expect![[r#"
+macro_rules! m {
+    ($($i:ident),*) => ( impl Bar { $(fn $i() {})* } );
+}
+impl Bar {
+    fn foo() {}
+    fn bar() {}
+}
+"#]],
+    );
+}
+
+#[test]
+fn test_match_group_pattern_with_multiple_statement() {
+    check(
+        r#"
+macro_rules! m {
+    ($($i:ident),*) => ( fn baz() { $($i ();)* } );
+}
+m! { foo, bar }
+"#,
+        expect![[r#"
+macro_rules! m {
+    ($($i:ident),*) => ( fn baz() { $($i ();)* } );
+}
+fn baz() {
+    foo();
+    bar();
+}
+"#]],
+    )
+}
+
+#[test]
+fn test_match_group_pattern_with_multiple_statement_without_semi() {
+    check(
+        r#"
+macro_rules! m {
+    ($($i:ident),*) => ( fn baz() { $($i() );* } );
+}
+m! { foo, bar }
+"#,
+        expect![[r#"
+macro_rules! m {
+    ($($i:ident),*) => ( fn baz() { $($i() );* } );
+}
+fn baz() {
+    foo();
+    bar()
+}
+"#]],
+    )
+}
+
+#[test]
+fn test_match_group_empty_fixed_token() {
+    check(
+        r#"
+macro_rules! m {
+    ($($i:ident)* #abc) => ( fn baz() { $($i ();)* } );
+}
+m!{#abc}
+"#,
+        expect![[r##"
+macro_rules! m {
+    ($($i:ident)* #abc) => ( fn baz() { $($i ();)* } );
+}
+fn baz() {}
+"##]],
+    )
+}
+
+#[test]
+fn test_match_group_in_subtree() {
+    check(
+        r#"
+macro_rules! m {
+    (fn $name:ident { $($i:ident)* } ) => ( fn $name() { $($i ();)* } );
+}
+m! { fn baz { a b } }
+"#,
+        expect![[r#"
+macro_rules! m {
+    (fn $name:ident { $($i:ident)* } ) => ( fn $name() { $($i ();)* } );
+}
+fn baz() {
+    a();
+    b();
+}
+"#]],
+    )
+}
+
+#[test]
+fn test_expr_order() {
+    check(
+        r#"
+macro_rules! m {
+    ($ i:expr) => { fn bar() { $ i * 3; } }
+}
+// +tree
+m! { 1 + 2 }
+"#,
+        expect![[r#"
+macro_rules! m {
+    ($ i:expr) => { fn bar() { $ i * 3; } }
+}
+fn bar() {
+    1+2*3;
+}
+// MACRO_ITEMS@0..15
+//   FN@0..15
+//     FN_KW@0..2 "fn"
+//     NAME@2..5
+//       IDENT@2..5 "bar"
+//     PARAM_LIST@5..7
+//       L_PAREN@5..6 "("
+//       R_PAREN@6..7 ")"
+//     BLOCK_EXPR@7..15
+//       STMT_LIST@7..15
+//         L_CURLY@7..8 "{"
+//         EXPR_STMT@8..14
+//           BIN_EXPR@8..13
+//             BIN_EXPR@8..11
+//               LITERAL@8..9
+//                 INT_NUMBER@8..9 "1"
+//               PLUS@9..10 "+"
+//               LITERAL@10..11
+//                 INT_NUMBER@10..11 "2"
+//             STAR@11..12 "*"
+//             LITERAL@12..13
+//               INT_NUMBER@12..13 "3"
+//           SEMICOLON@13..14 ";"
+//         R_CURLY@14..15 "}"
+
+"#]],
+    )
+}
+
+#[test]
+fn test_match_group_with_multichar_sep() {
+    check(
+        r#"
+macro_rules! m {
+    (fn $name:ident { $($i:literal)* }) => ( fn $name() -> bool { $($i)&&* } );
+}
+m! (fn baz { true false } );
+"#,
+        expect![[r#"
+macro_rules! m {
+    (fn $name:ident { $($i:literal)* }) => ( fn $name() -> bool { $($i)&&* } );
+}
+fn baz() -> bool {
+    true && false
+}
+"#]],
+    );
+
+    check(
+        r#"
+macro_rules! m {
+    (fn $name:ident { $($i:literal)&&* }) => ( fn $name() -> bool { $($i)&&* } );
+}
+m! (fn baz { true && false } );
+"#,
+        expect![[r#"
+macro_rules! m {
+    (fn $name:ident { $($i:literal)&&* }) => ( fn $name() -> bool { $($i)&&* } );
+}
+fn baz() -> bool {
+    true && false
+}
+"#]],
+    );
+}
diff --git a/crates/hir_def/src/macro_expansion_tests/mbe/matching.rs b/crates/hir_def/src/macro_expansion_tests/mbe/matching.rs
index 11317cfa9d5..5bdabfc598b 100644
--- a/crates/hir_def/src/macro_expansion_tests/mbe/matching.rs
+++ b/crates/hir_def/src/macro_expansion_tests/mbe/matching.rs
@@ -8,18 +8,18 @@ use crate::macro_expansion_tests::check;
 fn unary_minus_is_a_literal() {
     check(
         r#"
-macro_rules! m { ($x:literal) => (literal!()); ($x:tt) => (not_a_literal!()); }
+macro_rules! m { ($x:literal) => (literal!();); ($x:tt) => (not_a_literal!();); }
 m!(92);
 m!(-92);
 m!(-9.2);
 m!(--92);
 "#,
         expect![[r#"
-macro_rules! m { ($x:literal) => (literal!()); ($x:tt) => (not_a_literal!()); }
-literal!()
-literal!()
-literal!()
-/* error: leftover tokens */not_a_literal!()
+macro_rules! m { ($x:literal) => (literal!();); ($x:tt) => (not_a_literal!();); }
+literal!();
+literal!();
+literal!();
+/* error: leftover tokens */not_a_literal!();
 "#]],
     )
 }
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 4249c2507e9..d434c882449 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
@@ -16,7 +16,7 @@ macro_rules! m {
     ($($i:ident)*) => ($_);
     ($($true:ident)*) => ($true);
     ($($false:ident)*) => ($false);
-    ($) => ($);
+    ($) => (m!($););
 }
 m!($);
 "#,
@@ -29,9 +29,9 @@ macro_rules! m {
     ($($i:ident)*) => ($_);
     ($($true:ident)*) => ($true);
     ($($false:ident)*) => ($false);
-    ($) => ($);
+    ($) => (m!($););
 }
-$
+m!($);
 "#]],
     )
 }
diff --git a/crates/hir_expand/Cargo.toml b/crates/hir_expand/Cargo.toml
index b39de7cfaee..240193f9cf1 100644
--- a/crates/hir_expand/Cargo.toml
+++ b/crates/hir_expand/Cargo.toml
@@ -25,4 +25,4 @@ mbe = { path = "../mbe", version = "0.0.0" }
 limit = { path = "../limit", version = "0.0.0" }
 
 [dev-dependencies]
-expect-test = "1.1"
+expect-test = "1.2.0-pre.1"
diff --git a/crates/hir_ty/Cargo.toml b/crates/hir_ty/Cargo.toml
index 7566bf687bf..0f1e75958a8 100644
--- a/crates/hir_ty/Cargo.toml
+++ b/crates/hir_ty/Cargo.toml
@@ -33,7 +33,7 @@ limit = { path = "../limit", version = "0.0.0" }
 
 [dev-dependencies]
 test_utils = { path = "../test_utils" }
-expect-test = "1.1"
+expect-test = "1.2.0-pre.1"
 tracing = "0.1"
 tracing-subscriber = { version = "0.2", default-features = false, features = [
     "env-filter",
diff --git a/crates/ide/Cargo.toml b/crates/ide/Cargo.toml
index 804002a4b33..bccadacdb2a 100644
--- a/crates/ide/Cargo.toml
+++ b/crates/ide/Cargo.toml
@@ -38,4 +38,4 @@ hir = { path = "../hir", version = "0.0.0" }
 
 [dev-dependencies]
 test_utils = { path = "../test_utils" }
-expect-test = "1.1"
+expect-test = "1.2.0-pre.1"
diff --git a/crates/ide_assists/Cargo.toml b/crates/ide_assists/Cargo.toml
index c34798d0ea6..629aadb5b12 100644
--- a/crates/ide_assists/Cargo.toml
+++ b/crates/ide_assists/Cargo.toml
@@ -25,4 +25,4 @@ hir = { path = "../hir", version = "0.0.0" }
 [dev-dependencies]
 test_utils = { path = "../test_utils" }
 sourcegen = { path = "../sourcegen" }
-expect-test = "1.1"
+expect-test = "1.2.0-pre.1"
diff --git a/crates/ide_completion/Cargo.toml b/crates/ide_completion/Cargo.toml
index 0d4413978d4..5b2f0b35f98 100644
--- a/crates/ide_completion/Cargo.toml
+++ b/crates/ide_completion/Cargo.toml
@@ -28,7 +28,7 @@ profile = { path = "../profile", version = "0.0.0" }
 hir = { path = "../hir", version = "0.0.0" }
 
 [dev-dependencies]
-expect-test = "1.1"
+expect-test = "1.2.0-pre.1"
 xshell = "0.1"
 
 test_utils = { path = "../test_utils" }
diff --git a/crates/ide_db/Cargo.toml b/crates/ide_db/Cargo.toml
index cdaff0ce397..e3c60edda13 100644
--- a/crates/ide_db/Cargo.toml
+++ b/crates/ide_db/Cargo.toml
@@ -31,4 +31,4 @@ limit = { path = "../limit", version = "0.0.0" }
 
 [dev-dependencies]
 test_utils = { path = "../test_utils" }
-expect-test = "1.1"
+expect-test = "1.2.0-pre.1"
diff --git a/crates/ide_diagnostics/Cargo.toml b/crates/ide_diagnostics/Cargo.toml
index 3389e67d9dc..7e36b1a3bdd 100644
--- a/crates/ide_diagnostics/Cargo.toml
+++ b/crates/ide_diagnostics/Cargo.toml
@@ -23,7 +23,7 @@ hir = { path = "../hir", version = "0.0.0" }
 ide_db = { path = "../ide_db", version = "0.0.0" }
 
 [dev-dependencies]
-expect-test = "1.1"
+expect-test = "1.2.0-pre.1"
 
 test_utils = { path = "../test_utils" }
 sourcegen = { path = "../sourcegen" }
diff --git a/crates/ide_ssr/Cargo.toml b/crates/ide_ssr/Cargo.toml
index 28aacd349ce..275f923f2bc 100644
--- a/crates/ide_ssr/Cargo.toml
+++ b/crates/ide_ssr/Cargo.toml
@@ -21,4 +21,4 @@ hir = { path = "../hir", version = "0.0.0" }
 
 [dev-dependencies]
 test_utils = { path = "../test_utils" }
-expect-test = "1.1"
+expect-test = "1.2.0-pre.1"
diff --git a/crates/mbe/Cargo.toml b/crates/mbe/Cargo.toml
index 22bda576690..5378516e706 100644
--- a/crates/mbe/Cargo.toml
+++ b/crates/mbe/Cargo.toml
@@ -12,7 +12,7 @@ doctest = false
 cov-mark = "2.0.0-pre.1"
 rustc-hash = "1.1.0"
 smallvec = "1.2.0"
-expect-test = "1.1"
+expect-test = "1.2.0-pre.1"
 tracing = "0.1"
 
 syntax = { path = "../syntax", version = "0.0.0" }
diff --git a/crates/mbe/src/tests/expand.rs b/crates/mbe/src/tests/expand.rs
index 7becaa6658f..c08788cda1e 100644
--- a/crates/mbe/src/tests/expand.rs
+++ b/crates/mbe/src/tests/expand.rs
@@ -72,235 +72,6 @@ macro_rules! foobar {
 }
 
 #[test]
-fn test_convert_tt() {
-    parse_macro(r#"
-macro_rules! impl_froms {
-    ($e:ident: $($v:ident),*) => {
-        $(
-            impl From<$v> for $e {
-                fn from(it: $v) -> $e {
-                    $e::$v(it)
-                }
-            }
-        )*
-    }
-}
-"#)
-        .assert_expand_tt(
-            "impl_froms!(TokenTree: Leaf, Subtree);",
-            "impl From <Leaf > for TokenTree {fn from (it : Leaf) -> TokenTree {TokenTree ::Leaf (it)}} \
-             impl From <Subtree > for TokenTree {fn from (it : Subtree) -> TokenTree {TokenTree ::Subtree (it)}}"
-        );
-}
-
-#[test]
-fn test_convert_tt2() {
-    parse_macro(
-        r#"
-macro_rules! impl_froms {
-    ($e:ident: $($v:ident),*) => {
-        $(
-            impl From<$v> for $e {
-                fn from(it: $v) -> $e {
-                    $e::$v(it)
-                }
-            }
-        )*
-    }
-}
-"#,
-    )
-    .assert_expand(
-        "impl_froms!(TokenTree: Leaf, Subtree);",
-        r#"
-SUBTREE $
-  IDENT   impl 20
-  IDENT   From 21
-  PUNCH   < [joint] 22
-  IDENT   Leaf 53
-  PUNCH   > [alone] 25
-  IDENT   for 26
-  IDENT   TokenTree 51
-  SUBTREE {} 29
-    IDENT   fn 30
-    IDENT   from 31
-    SUBTREE () 32
-      IDENT   it 33
-      PUNCH   : [alone] 34
-      IDENT   Leaf 53
-    PUNCH   - [joint] 37
-    PUNCH   > [alone] 38
-    IDENT   TokenTree 51
-    SUBTREE {} 41
-      IDENT   TokenTree 51
-      PUNCH   : [joint] 44
-      PUNCH   : [joint] 45
-      IDENT   Leaf 53
-      SUBTREE () 48
-        IDENT   it 49
-  IDENT   impl 20
-  IDENT   From 21
-  PUNCH   < [joint] 22
-  IDENT   Subtree 55
-  PUNCH   > [alone] 25
-  IDENT   for 26
-  IDENT   TokenTree 51
-  SUBTREE {} 29
-    IDENT   fn 30
-    IDENT   from 31
-    SUBTREE () 32
-      IDENT   it 33
-      PUNCH   : [alone] 34
-      IDENT   Subtree 55
-    PUNCH   - [joint] 37
-    PUNCH   > [alone] 38
-    IDENT   TokenTree 51
-    SUBTREE {} 41
-      IDENT   TokenTree 51
-      PUNCH   : [joint] 44
-      PUNCH   : [joint] 45
-      IDENT   Subtree 55
-      SUBTREE () 48
-        IDENT   it 49
-"#,
-    );
-}
-
-#[test]
-fn test_expr_order() {
-    let expanded = parse_macro(
-        r#"
-        macro_rules! foo {
-            ($ i:expr) => {
-                 fn bar() { $ i * 2; }
-            }
-        }
-"#,
-    )
-    .expand_items("foo! { 1 + 1}");
-
-    let dump = format!("{:#?}", expanded);
-    assert_eq_text!(
-        r#"MACRO_ITEMS@0..15
-  FN@0..15
-    FN_KW@0..2 "fn"
-    NAME@2..5
-      IDENT@2..5 "bar"
-    PARAM_LIST@5..7
-      L_PAREN@5..6 "("
-      R_PAREN@6..7 ")"
-    BLOCK_EXPR@7..15
-      STMT_LIST@7..15
-        L_CURLY@7..8 "{"
-        EXPR_STMT@8..14
-          BIN_EXPR@8..13
-            BIN_EXPR@8..11
-              LITERAL@8..9
-                INT_NUMBER@8..9 "1"
-              PLUS@9..10 "+"
-              LITERAL@10..11
-                INT_NUMBER@10..11 "1"
-            STAR@11..12 "*"
-            LITERAL@12..13
-              INT_NUMBER@12..13 "2"
-          SEMICOLON@13..14 ";"
-        R_CURLY@14..15 "}""#,
-        dump.trim()
-    );
-}
-
-#[test]
-fn test_match_group_pattern_with_multiple_defs() {
-    parse_macro(
-        r#"
-        macro_rules! foo {
-            ($ ($ i:ident),*) => ( struct Bar { $ (
-                fn $ i {}
-            )*} );
-        }
-"#,
-    )
-    .assert_expand_items("foo! { foo, bar }", "struct Bar {fn foo {} fn bar {}}");
-}
-
-#[test]
-fn test_match_group_pattern_with_multiple_statement() {
-    parse_macro(
-        r#"
-        macro_rules! foo {
-            ($ ($ i:ident),*) => ( fn baz { $ (
-                $ i ();
-            )*} );
-        }
-"#,
-    )
-    .assert_expand_items("foo! { foo, bar }", "fn baz {foo () ; bar () ;}");
-}
-
-#[test]
-fn test_match_group_pattern_with_multiple_statement_without_semi() {
-    parse_macro(
-        r#"
-        macro_rules! foo {
-            ($ ($ i:ident),*) => ( fn baz { $ (
-                $i()
-            );*} );
-        }
-"#,
-    )
-    .assert_expand_items("foo! { foo, bar }", "fn baz {foo () ;bar ()}");
-}
-
-#[test]
-fn test_match_group_empty_fixed_token() {
-    parse_macro(
-        r#"
-        macro_rules! foo {
-            ($ ($ i:ident)* #abc) => ( fn baz { $ (
-                $ i ();
-            )*} );
-        }
-"#,
-    )
-    .assert_expand_items("foo! {#abc}", "fn baz {}");
-}
-
-#[test]
-fn test_match_group_in_subtree() {
-    parse_macro(
-        r#"
-        macro_rules! foo {
-            (fn $name:ident {$($i:ident)*} ) => ( fn $name() { $ (
-                $ i ();
-            )*} );
-        }"#,
-    )
-    .assert_expand_items("foo! {fn baz {a b} }", "fn baz () {a () ; b () ;}");
-}
-
-#[test]
-fn test_match_group_with_multichar_sep() {
-    parse_macro(
-        r#"
-        macro_rules! foo {
-            (fn $name:ident {$($i:literal)*} ) => ( fn $name() -> bool { $($i)&&*} );
-        }"#,
-    )
-    .assert_expand_items("foo! (fn baz {true true} );", "fn baz () -> bool {true &&true}");
-}
-
-#[test]
-fn test_match_group_with_multichar_sep2() {
-    parse_macro(
-        r#"
-        macro_rules! foo {
-            (fn $name:ident {$($i:literal)&&*} ) => ( fn $name() -> bool { $($i)&&*} );
-        }"#,
-    )
-    .assert_expand_items("foo! (fn baz {true && true} );", "fn baz () -> bool {true &&true}");
-}
-
-#[test]
 fn test_match_group_zero_match() {
     parse_macro(
         r#"
diff --git a/crates/proc_macro_srv/Cargo.toml b/crates/proc_macro_srv/Cargo.toml
index d0e6bd9990b..6048c5e6cc3 100644
--- a/crates/proc_macro_srv/Cargo.toml
+++ b/crates/proc_macro_srv/Cargo.toml
@@ -25,7 +25,7 @@ paths = { path = "../paths", version = "0.0.0" }
 proc_macro_api = { path = "../proc_macro_api", version = "0.0.0" }
 
 [dev-dependencies]
-expect-test = "1.1.0"
+expect-test = "1.2.0-pre.1"
 
 # used as proc macro test targets
 proc_macro_test = { path = "../proc_macro_test" }
diff --git a/crates/project_model/Cargo.toml b/crates/project_model/Cargo.toml
index cea2c16a638..949325fc823 100644
--- a/crates/project_model/Cargo.toml
+++ b/crates/project_model/Cargo.toml
@@ -16,7 +16,7 @@ semver = "1"
 serde = { version = "1.0.106", features = ["derive"] }
 serde_json = "1.0.48"
 anyhow = "1.0.26"
-expect-test = "1"
+expect-test = "1.2.0-pre.1"
 la-arena = { version = "0.2.0", path = "../../lib/arena" }
 
 cfg = { path = "../cfg", version = "0.0.0" }
diff --git a/crates/rust-analyzer/Cargo.toml b/crates/rust-analyzer/Cargo.toml
index 29a3fbb67e0..8275f6e3d53 100644
--- a/crates/rust-analyzer/Cargo.toml
+++ b/crates/rust-analyzer/Cargo.toml
@@ -67,7 +67,7 @@ winapi = "0.3.8"
 jemallocator = { version = "0.4.1", package = "tikv-jemallocator", optional = true }
 
 [dev-dependencies]
-expect-test = "1.1"
+expect-test = "1.2.0-pre.1"
 xshell = "0.1"
 
 test_utils = { path = "../test_utils" }
diff --git a/crates/syntax/Cargo.toml b/crates/syntax/Cargo.toml
index fba5db9a93e..a34522435a2 100644
--- a/crates/syntax/Cargo.toml
+++ b/crates/syntax/Cargo.toml
@@ -26,7 +26,7 @@ profile = { path = "../profile", version = "0.0.0" }
 
 [dev-dependencies]
 rayon = "1"
-expect-test = "1.1"
+expect-test = "1.2.0-pre.1"
 proc-macro2 = "1.0.8"
 quote = "1.0.2"
 ungrammar = "=1.14.8"
diff --git a/crates/syntax/src/lib.rs b/crates/syntax/src/lib.rs
index 132d300674d..24a099cb3cc 100644
--- a/crates/syntax/src/lib.rs
+++ b/crates/syntax/src/lib.rs
@@ -89,6 +89,9 @@ impl<T> Parse<T> {
     pub fn syntax_node(&self) -> SyntaxNode {
         SyntaxNode::new_root(self.green.clone())
     }
+    pub fn errors(&self) -> &[SyntaxError] {
+        &*self.errors
+    }
 }
 
 impl<T: AstNode> Parse<T> {
@@ -100,10 +103,6 @@ impl<T: AstNode> Parse<T> {
         T::cast(self.syntax_node()).unwrap()
     }
 
-    pub fn errors(&self) -> &[SyntaxError] {
-        &*self.errors
-    }
-
     pub fn ok(self) -> Result<T, Arc<Vec<SyntaxError>>> {
         if self.errors.is_empty() {
             Ok(self.tree())