about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--crates/hir/src/attrs.rs16
-rw-r--r--crates/hir_def/src/attr.rs3
-rw-r--r--crates/hir_expand/src/builtin_derive_macro.rs2
-rw-r--r--crates/hir_expand/src/db.rs10
-rw-r--r--crates/hir_expand/src/eager.rs2
-rw-r--r--crates/ide_assists/src/handlers/remove_dbg.rs5
-rw-r--r--crates/ide_completion/src/completions/attribute.rs2
-rw-r--r--crates/ide_completion/src/snippet.rs13
-rw-r--r--crates/ide_db/src/helpers.rs13
-rw-r--r--crates/ide_ssr/src/fragments.rs58
-rw-r--r--crates/ide_ssr/src/lib.rs1
-rw-r--r--crates/ide_ssr/src/parsing.rs37
-rw-r--r--crates/ide_ssr/src/replacing.rs12
-rw-r--r--crates/ide_ssr/src/tests.rs22
-rw-r--r--crates/mbe/src/expander/matcher.rs52
-rw-r--r--crates/mbe/src/lib.rs2
-rw-r--r--crates/mbe/src/syntax_bridge.rs10
-rw-r--r--crates/mbe/src/tt_iter.rs6
-rw-r--r--crates/parser/src/grammar.rs102
-rw-r--r--crates/parser/src/lib.rs126
-rw-r--r--crates/parser/src/shortcuts.rs7
-rw-r--r--crates/parser/src/tests.rs4
-rw-r--r--crates/syntax/src/hacks.rs15
-rw-r--r--crates/syntax/src/lib.rs56
-rw-r--r--crates/syntax/src/parsing.rs29
-rw-r--r--crates/syntax/src/parsing/reparsing.rs2
-rw-r--r--crates/syntax/src/tests.rs72
-rw-r--r--crates/syntax/test_data/parser/fragments/expr/err/0000_truncated_add.rast1
-rw-r--r--crates/syntax/test_data/parser/fragments/expr/err/0000_truncated_add.rs1
-rw-r--r--crates/syntax/test_data/parser/fragments/expr/ok/0000_add.rast8
-rw-r--r--crates/syntax/test_data/parser/fragments/expr/ok/0000_add.rs1
-rw-r--r--crates/syntax/test_data/parser/fragments/item/err/0000_extra_keyword.rast1
-rw-r--r--crates/syntax/test_data/parser/fragments/item/err/0000_extra_keyword.rs1
-rw-r--r--crates/syntax/test_data/parser/fragments/item/ok/0000_fn.rast13
-rw-r--r--crates/syntax/test_data/parser/fragments/item/ok/0000_fn.rs1
-rw-r--r--crates/syntax/test_data/parser/fragments/path/err/0000_reserved_word.rast1
-rw-r--r--crates/syntax/test_data/parser/fragments/path/err/0000_reserved_word.rs1
-rw-r--r--crates/syntax/test_data/parser/fragments/path/err/0001_expression.rast1
-rw-r--r--crates/syntax/test_data/parser/fragments/path/err/0001_expression.rs1
-rw-r--r--crates/syntax/test_data/parser/fragments/path/ok/0000_single_ident.rast4
-rw-r--r--crates/syntax/test_data/parser/fragments/path/ok/0000_single_ident.rs1
-rw-r--r--crates/syntax/test_data/parser/fragments/path/ok/0001_multipart.rast14
-rw-r--r--crates/syntax/test_data/parser/fragments/path/ok/0001_multipart.rs1
-rw-r--r--crates/syntax/test_data/parser/fragments/pattern/err/0000_reserved_word.rast1
-rw-r--r--crates/syntax/test_data/parser/fragments/pattern/err/0000_reserved_word.rs1
-rw-r--r--crates/syntax/test_data/parser/fragments/pattern/err/0001_missing_paren.rast1
-rw-r--r--crates/syntax/test_data/parser/fragments/pattern/err/0001_missing_paren.rs1
-rw-r--r--crates/syntax/test_data/parser/fragments/pattern/ok/0000_enum.rast10
-rw-r--r--crates/syntax/test_data/parser/fragments/pattern/ok/0000_enum.rs1
-rw-r--r--crates/syntax/test_data/parser/fragments/stmt/err/0000_attr.rast1
-rw-r--r--crates/syntax/test_data/parser/fragments/stmt/err/0000_attr.rs1
-rw-r--r--crates/syntax/test_data/parser/fragments/stmt/err/0000_multiple_stmts.rast1
-rw-r--r--crates/syntax/test_data/parser/fragments/stmt/err/0000_multiple_stmts.rs1
-rw-r--r--crates/syntax/test_data/parser/fragments/stmt/err/0000_open_parenthesis.rast1
-rw-r--r--crates/syntax/test_data/parser/fragments/stmt/err/0000_open_parenthesis.rs1
-rw-r--r--crates/syntax/test_data/parser/fragments/stmt/err/0000_semicolon.rast1
-rw-r--r--crates/syntax/test_data/parser/fragments/stmt/err/0000_semicolon.rs1
-rw-r--r--crates/syntax/test_data/parser/fragments/stmt/err/0000_unterminated_expr.rast1
-rw-r--r--crates/syntax/test_data/parser/fragments/stmt/err/0000_unterminated_expr.rs1
-rw-r--r--crates/syntax/test_data/parser/fragments/stmt/ok/0000_expr.rast9
-rw-r--r--crates/syntax/test_data/parser/fragments/stmt/ok/0000_expr.rs1
-rw-r--r--crates/syntax/test_data/parser/fragments/stmt/ok/0000_expr_block.rast70
-rw-r--r--crates/syntax/test_data/parser/fragments/stmt/ok/0000_expr_block.rs5
-rw-r--r--crates/syntax/test_data/parser/fragments/stmt/ok/0000_fn_call.rast11
-rw-r--r--crates/syntax/test_data/parser/fragments/stmt/ok/0000_fn_call.rs1
-rw-r--r--crates/syntax/test_data/parser/fragments/stmt/ok/0000_let_stmt.rast12
-rw-r--r--crates/syntax/test_data/parser/fragments/stmt/ok/0000_let_stmt.rs1
-rw-r--r--crates/syntax/test_data/parser/fragments/stmt/ok/0000_macro_let_stmt.rast21
-rw-r--r--crates/syntax/test_data/parser/fragments/stmt/ok/0000_macro_let_stmt.rs1
-rw-r--r--crates/syntax/test_data/parser/fragments/stmt/ok/0000_macro_unterminated_let_stmt.rast21
-rw-r--r--crates/syntax/test_data/parser/fragments/stmt/ok/0000_macro_unterminated_let_stmt.rs1
-rw-r--r--crates/syntax/test_data/parser/fragments/stmt/ok/0000_struct_item.rast22
-rw-r--r--crates/syntax/test_data/parser/fragments/stmt/ok/0000_struct_item.rs3
-rw-r--r--crates/syntax/test_data/parser/fragments/stmt/ok/0000_unterminated_fn_call.rast10
-rw-r--r--crates/syntax/test_data/parser/fragments/stmt/ok/0000_unterminated_fn_call.rs1
-rw-r--r--crates/syntax/test_data/parser/fragments/stmt/ok/0000_unterminated_let_stmt.rast11
-rw-r--r--crates/syntax/test_data/parser/fragments/stmt/ok/0000_unterminated_let_stmt.rs1
-rw-r--r--crates/syntax/test_data/parser/fragments/type/err/0000_missing_close.rast1
-rw-r--r--crates/syntax/test_data/parser/fragments/type/err/0000_missing_close.rs1
-rw-r--r--crates/syntax/test_data/parser/fragments/type/ok/0000_result.rast22
-rw-r--r--crates/syntax/test_data/parser/fragments/type/ok/0000_result.rs1
81 files changed, 331 insertions, 651 deletions
diff --git a/crates/hir/src/attrs.rs b/crates/hir/src/attrs.rs
index 54e95cf7c3d..46e9c54dad6 100644
--- a/crates/hir/src/attrs.rs
+++ b/crates/hir/src/attrs.rs
@@ -11,7 +11,7 @@ use hir_def::{
 };
 use hir_expand::{hygiene::Hygiene, MacroDefId};
 use hir_ty::db::HirDatabase;
-use syntax::ast;
+use syntax::{ast, AstNode};
 
 use crate::{
     Adt, AssocItem, Const, ConstParam, Enum, Field, Function, GenericParam, Impl, LifetimeParam,
@@ -147,8 +147,18 @@ fn resolve_doc_path(
         // FIXME
         AttrDefId::MacroDefId(_) => return None,
     };
-    let path = ast::Path::parse(link).ok()?;
-    let modpath = ModPath::from_src(db.upcast(), path, &Hygiene::new_unhygienic())?;
+
+    let modpath = {
+        let ast_path = ast::SourceFile::parse(&format!("type T = {};", link))
+            .syntax_node()
+            .descendants()
+            .find_map(ast::Path::cast)?;
+        if ast_path.to_string() != link {
+            return None;
+        }
+        ModPath::from_src(db.upcast(), ast_path, &Hygiene::new_unhygienic())?
+    };
+
     let resolved = resolver.resolve_module_path_in_items(db.upcast(), &modpath);
     let resolved = if resolved == PerNs::none() {
         resolver.resolve_module_path_in_trait_assoc_items(db.upcast(), &modpath)?
diff --git a/crates/hir_def/src/attr.rs b/crates/hir_def/src/attr.rs
index 36e46a103c1..383ad7f0c83 100644
--- a/crates/hir_def/src/attr.rs
+++ b/crates/hir_def/src/attr.rs
@@ -714,8 +714,7 @@ impl Attr {
         hygiene: &Hygiene,
         id: AttrId,
     ) -> Option<Attr> {
-        let (parse, _) =
-            mbe::token_tree_to_syntax_node(tt, mbe::ParserEntryPoint::MetaItem).ok()?;
+        let (parse, _) = mbe::token_tree_to_syntax_node(tt, mbe::TopEntryPoint::MetaItem).ok()?;
         let ast = ast::Meta::cast(parse.syntax_node())?;
 
         Self::from_src(db, ast, hygiene, id)
diff --git a/crates/hir_expand/src/builtin_derive_macro.rs b/crates/hir_expand/src/builtin_derive_macro.rs
index c20dae8e6f7..c1542f48f0e 100644
--- a/crates/hir_expand/src/builtin_derive_macro.rs
+++ b/crates/hir_expand/src/builtin_derive_macro.rs
@@ -72,7 +72,7 @@ struct BasicAdtInfo {
 }
 
 fn parse_adt(tt: &tt::Subtree) -> Result<BasicAdtInfo, mbe::ExpandError> {
-    let (parsed, token_map) = mbe::token_tree_to_syntax_node(tt, mbe::ParserEntryPoint::Items)?; // FragmentKind::Items doesn't parse attrs?
+    let (parsed, token_map) = mbe::token_tree_to_syntax_node(tt, mbe::TopEntryPoint::MacroItems)?; // FragmentKind::Items doesn't parse attrs?
     let macro_items = ast::MacroItems::cast(parsed.syntax_node()).ok_or_else(|| {
         debug!("derive node didn't parse");
         mbe::ExpandError::UnexpectedToken
diff --git a/crates/hir_expand/src/db.rs b/crates/hir_expand/src/db.rs
index 747a19a5092..3369e3e5fed 100644
--- a/crates/hir_expand/src/db.rs
+++ b/crates/hir_expand/src/db.rs
@@ -497,11 +497,11 @@ fn token_tree_to_syntax_node(
     expand_to: ExpandTo,
 ) -> Result<(Parse<SyntaxNode>, mbe::TokenMap), ExpandError> {
     let entry_point = match expand_to {
-        ExpandTo::Statements => mbe::ParserEntryPoint::Statements,
-        ExpandTo::Items => mbe::ParserEntryPoint::Items,
-        ExpandTo::Pattern => mbe::ParserEntryPoint::Pattern,
-        ExpandTo::Type => mbe::ParserEntryPoint::Type,
-        ExpandTo::Expr => mbe::ParserEntryPoint::Expr,
+        ExpandTo::Statements => mbe::TopEntryPoint::MacroStmts,
+        ExpandTo::Items => mbe::TopEntryPoint::MacroItems,
+        ExpandTo::Pattern => mbe::TopEntryPoint::Pattern,
+        ExpandTo::Type => mbe::TopEntryPoint::Type,
+        ExpandTo::Expr => mbe::TopEntryPoint::Expr,
     };
     mbe::token_tree_to_syntax_node(tt, entry_point)
 }
diff --git a/crates/hir_expand/src/eager.rs b/crates/hir_expand/src/eager.rs
index ea57c2c4101..1d29ad26307 100644
--- a/crates/hir_expand/src/eager.rs
+++ b/crates/hir_expand/src/eager.rs
@@ -131,7 +131,7 @@ pub fn expand_eager_macro(
     let arg_file_id = arg_id;
 
     let parsed_args = diagnostic_sink
-        .result(mbe::token_tree_to_syntax_node(&parsed_args, mbe::ParserEntryPoint::Expr))?
+        .result(mbe::token_tree_to_syntax_node(&parsed_args, mbe::TopEntryPoint::Expr))?
         .0;
     let result = eager_macro_recur(
         db,
diff --git a/crates/ide_assists/src/handlers/remove_dbg.rs b/crates/ide_assists/src/handlers/remove_dbg.rs
index b860a3b6da8..07dcfd96717 100644
--- a/crates/ide_assists/src/handlers/remove_dbg.rs
+++ b/crates/ide_assists/src/handlers/remove_dbg.rs
@@ -36,9 +36,8 @@ pub(crate) fn remove_dbg(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
     let input_expressions = input_expressions
         .into_iter()
         .filter_map(|(is_sep, group)| (!is_sep).then(|| group))
-        .map(|mut tokens| ast::Expr::parse(&tokens.join("")))
-        .collect::<Result<Vec<ast::Expr>, _>>()
-        .ok()?;
+        .map(|mut tokens| syntax::hacks::parse_expr_from_str(&tokens.join("")))
+        .collect::<Option<Vec<ast::Expr>>>()?;
 
     let parent = macro_call.syntax().parent()?;
     let (range, text) = match &*input_expressions {
diff --git a/crates/ide_completion/src/completions/attribute.rs b/crates/ide_completion/src/completions/attribute.rs
index d763878834f..f67d7d56d81 100644
--- a/crates/ide_completion/src/completions/attribute.rs
+++ b/crates/ide_completion/src/completions/attribute.rs
@@ -309,7 +309,7 @@ fn parse_comma_sep_expr(input: ast::TokenTree) -> Option<Vec<ast::Expr>> {
         input_expressions
             .into_iter()
             .filter_map(|(is_sep, group)| (!is_sep).then(|| group))
-            .filter_map(|mut tokens| ast::Expr::parse(&tokens.join("")).ok())
+            .filter_map(|mut tokens| syntax::hacks::parse_expr_from_str(&tokens.join("")))
             .collect::<Vec<ast::Expr>>(),
     )
 }
diff --git a/crates/ide_completion/src/snippet.rs b/crates/ide_completion/src/snippet.rs
index c5e2b009c7c..98cd3f8f337 100644
--- a/crates/ide_completion/src/snippet.rs
+++ b/crates/ide_completion/src/snippet.rs
@@ -212,15 +212,14 @@ fn validate_snippet(
 ) -> Option<(Box<[GreenNode]>, String, Option<Box<str>>)> {
     let mut imports = Vec::with_capacity(requires.len());
     for path in requires.iter() {
-        let path = ast::Path::parse(path).ok()?;
-        let valid_use_path = path.segments().all(|seg| {
-            matches!(seg.kind(), Some(ast::PathSegmentKind::Name(_)))
-                || seg.generic_arg_list().is_none()
-        });
-        if !valid_use_path {
+        let use_path = ast::SourceFile::parse(&format!("use {};", path))
+            .syntax_node()
+            .descendants()
+            .find_map(ast::Path::cast)?;
+        if use_path.syntax().text() != path.as_str() {
             return None;
         }
-        let green = path.syntax().green().into_owned();
+        let green = use_path.syntax().green().into_owned();
         imports.push(green);
     }
     let snippet = snippet.iter().join("\n");
diff --git a/crates/ide_db/src/helpers.rs b/crates/ide_db/src/helpers.rs
index e4199898bfc..e589940dae2 100644
--- a/crates/ide_db/src/helpers.rs
+++ b/crates/ide_db/src/helpers.rs
@@ -67,7 +67,11 @@ pub fn get_path_at_cursor_in_tt(cursor: &ast::Ident) -> Option<ast::Path> {
         .filter_map(SyntaxElement::into_token)
         .take_while(|tok| tok != cursor);
 
-    ast::Path::parse(&path_tokens.chain(iter::once(cursor.clone())).join("")).ok()
+    syntax::hacks::parse_expr_from_str(&path_tokens.chain(iter::once(cursor.clone())).join(""))
+        .and_then(|expr| match expr {
+            ast::Expr::PathExpr(it) => it.path(),
+            _ => None,
+        })
 }
 
 /// Parses and resolves the path at the cursor position in the given attribute, if it is a derive.
@@ -323,7 +327,12 @@ pub fn parse_tt_as_comma_sep_paths(input: ast::TokenTree) -> Option<Vec<ast::Pat
     let paths = input_expressions
         .into_iter()
         .filter_map(|(is_sep, group)| (!is_sep).then(|| group))
-        .filter_map(|mut tokens| ast::Path::parse(&tokens.join("")).ok())
+        .filter_map(|mut tokens| {
+            syntax::hacks::parse_expr_from_str(&tokens.join("")).and_then(|expr| match expr {
+                ast::Expr::PathExpr(it) => it.path(),
+                _ => None,
+            })
+        })
         .collect();
     Some(paths)
 }
diff --git a/crates/ide_ssr/src/fragments.rs b/crates/ide_ssr/src/fragments.rs
new file mode 100644
index 00000000000..503754afe7c
--- /dev/null
+++ b/crates/ide_ssr/src/fragments.rs
@@ -0,0 +1,58 @@
+//! When specifying SSR rule, you generally want to map one *kind* of thing to
+//! the same kind of thing: path to path, expression to expression, type to
+//! type.
+//!
+//! The problem is, while this *kind* is generally obvious to the human, the ide
+//! needs to determine it somehow. We do this in a stupid way -- by pasting SSR
+//! rule into different contexts and checking what works.
+
+use syntax::{ast, AstNode, SyntaxNode};
+
+pub(crate) fn ty(s: &str) -> Result<SyntaxNode, ()> {
+    fragment::<ast::Type>("type T = {};", s)
+}
+
+pub(crate) fn item(s: &str) -> Result<SyntaxNode, ()> {
+    fragment::<ast::Item>("{}", s)
+}
+
+pub(crate) fn pat(s: &str) -> Result<SyntaxNode, ()> {
+    fragment::<ast::Pat>("const _: () = {let {} = ();};", s)
+}
+
+pub(crate) fn expr(s: &str) -> Result<SyntaxNode, ()> {
+    fragment::<ast::Expr>("const _: () = {};", s)
+}
+
+pub(crate) fn stmt(s: &str) -> Result<SyntaxNode, ()> {
+    let template = "const _: () = { {}; };";
+    let input = template.replace("{}", s);
+    let parse = syntax::SourceFile::parse(&input);
+    if !parse.errors().is_empty() {
+        return Err(());
+    }
+    let mut node =
+        parse.tree().syntax().descendants().skip(2).find_map(ast::Stmt::cast).ok_or(())?;
+    if !s.ends_with(';') && node.to_string().ends_with(';') {
+        node = node.clone_for_update();
+        node.syntax().last_token().map(|it| it.detach());
+    }
+    if node.to_string() != s {
+        return Err(());
+    }
+    Ok(node.syntax().clone_subtree())
+}
+
+fn fragment<T: AstNode>(template: &str, s: &str) -> Result<SyntaxNode, ()> {
+    let s = s.trim();
+    let input = template.replace("{}", s);
+    let parse = syntax::SourceFile::parse(&input);
+    if !parse.errors().is_empty() {
+        return Err(());
+    }
+    let node = parse.tree().syntax().descendants().find_map(T::cast).ok_or(())?;
+    if node.syntax().text() != s {
+        return Err(());
+    }
+    Ok(node.syntax().clone_subtree())
+}
diff --git a/crates/ide_ssr/src/lib.rs b/crates/ide_ssr/src/lib.rs
index 2fe1f5b616e..d56bc12b680 100644
--- a/crates/ide_ssr/src/lib.rs
+++ b/crates/ide_ssr/src/lib.rs
@@ -71,6 +71,7 @@ mod from_comment;
 mod matching;
 mod nester;
 mod parsing;
+mod fragments;
 mod replacing;
 mod resolving;
 mod search;
diff --git a/crates/ide_ssr/src/parsing.rs b/crates/ide_ssr/src/parsing.rs
index ae7d5b4bf15..aaaee576b52 100644
--- a/crates/ide_ssr/src/parsing.rs
+++ b/crates/ide_ssr/src/parsing.rs
@@ -4,12 +4,12 @@
 //! placeholders, which start with `$`. For replacement templates, this is the final form. For
 //! search patterns, we go further and parse the pattern as each kind of thing that we can match.
 //! e.g. expressions, type references etc.
-
-use crate::errors::bail;
-use crate::{SsrError, SsrPattern, SsrRule};
 use rustc_hash::{FxHashMap, FxHashSet};
 use std::{fmt::Display, str::FromStr};
-use syntax::{ast, AstNode, SmolStr, SyntaxKind, SyntaxNode, T};
+use syntax::{SmolStr, SyntaxKind, SyntaxNode, T};
+
+use crate::errors::bail;
+use crate::{fragments, SsrError, SsrPattern, SsrRule};
 
 #[derive(Debug)]
 pub(crate) struct ParsedRule {
@@ -73,17 +73,16 @@ impl ParsedRule {
             rules: Vec::new(),
         };
 
-        let raw_template_stmt = raw_template.map(ast::Stmt::parse);
-        if let raw_template_expr @ Some(Ok(_)) = raw_template.map(ast::Expr::parse) {
-            builder.try_add(ast::Expr::parse(&raw_pattern), raw_template_expr);
+        let raw_template_stmt = raw_template.map(fragments::stmt);
+        if let raw_template_expr @ Some(Ok(_)) = raw_template.map(fragments::expr) {
+            builder.try_add(fragments::expr(&raw_pattern), raw_template_expr);
         } else {
-            builder.try_add(ast::Expr::parse(&raw_pattern), raw_template_stmt.clone());
+            builder.try_add(fragments::expr(&raw_pattern), raw_template_stmt.clone());
         }
-        builder.try_add(ast::Type::parse(&raw_pattern), raw_template.map(ast::Type::parse));
-        builder.try_add(ast::Item::parse(&raw_pattern), raw_template.map(ast::Item::parse));
-        builder.try_add(ast::Path::parse(&raw_pattern), raw_template.map(ast::Path::parse));
-        builder.try_add(ast::Pat::parse(&raw_pattern), raw_template.map(ast::Pat::parse));
-        builder.try_add(ast::Stmt::parse(&raw_pattern), raw_template_stmt);
+        builder.try_add(fragments::ty(&raw_pattern), raw_template.map(fragments::ty));
+        builder.try_add(fragments::item(&raw_pattern), raw_template.map(fragments::item));
+        builder.try_add(fragments::pat(&raw_pattern), raw_template.map(fragments::pat));
+        builder.try_add(fragments::stmt(&raw_pattern), raw_template_stmt);
         builder.build()
     }
 }
@@ -94,20 +93,20 @@ struct RuleBuilder {
 }
 
 impl RuleBuilder {
-    fn try_add<T: AstNode, T2: AstNode>(
+    fn try_add(
         &mut self,
-        pattern: Result<T, ()>,
-        template: Option<Result<T2, ()>>,
+        pattern: Result<SyntaxNode, ()>,
+        template: Option<Result<SyntaxNode, ()>>,
     ) {
         match (pattern, template) {
             (Ok(pattern), Some(Ok(template))) => self.rules.push(ParsedRule {
                 placeholders_by_stand_in: self.placeholders_by_stand_in.clone(),
-                pattern: pattern.syntax().clone(),
-                template: Some(template.syntax().clone()),
+                pattern,
+                template: Some(template),
             }),
             (Ok(pattern), None) => self.rules.push(ParsedRule {
                 placeholders_by_stand_in: self.placeholders_by_stand_in.clone(),
-                pattern: pattern.syntax().clone(),
+                pattern,
                 template: None,
             }),
             _ => {}
diff --git a/crates/ide_ssr/src/replacing.rs b/crates/ide_ssr/src/replacing.rs
index 9265af7c13a..6d21bad1eb3 100644
--- a/crates/ide_ssr/src/replacing.rs
+++ b/crates/ide_ssr/src/replacing.rs
@@ -1,5 +1,6 @@
 //! Code for applying replacement templates for matches that have previously been found.
 
+use crate::fragments;
 use crate::{resolving::ResolvedRule, Match, SsrMatches};
 use itertools::Itertools;
 use rustc_hash::{FxHashMap, FxHashSet};
@@ -225,12 +226,13 @@ fn token_is_method_call_receiver(token: &SyntaxToken) -> bool {
 
 fn parse_as_kind(code: &str, kind: SyntaxKind) -> Option<SyntaxNode> {
     if ast::Expr::can_cast(kind) {
-        if let Ok(expr) = ast::Expr::parse(code) {
-            return Some(expr.syntax().clone());
+        if let Ok(expr) = fragments::expr(code) {
+            return Some(expr);
         }
-    } else if ast::Item::can_cast(kind) {
-        if let Ok(item) = ast::Item::parse(code) {
-            return Some(item.syntax().clone());
+    }
+    if ast::Item::can_cast(kind) {
+        if let Ok(item) = fragments::item(code) {
+            return Some(item);
         }
     }
     None
diff --git a/crates/ide_ssr/src/tests.rs b/crates/ide_ssr/src/tests.rs
index 0b0c1111c46..30eda9d56cb 100644
--- a/crates/ide_ssr/src/tests.rs
+++ b/crates/ide_ssr/src/tests.rs
@@ -332,6 +332,15 @@ fn ssr_struct_lit() {
 }
 
 #[test]
+fn ssr_struct_def() {
+    assert_ssr_transform(
+        "struct Foo { $f: $t } ==>> struct Foo($t);",
+        r#"struct Foo { field: i32 }"#,
+        expect![[r#"struct Foo(i32);"#]],
+    )
+}
+
+#[test]
 fn ignores_whitespace() {
     assert_matches("1+2", "fn f() -> i32 {1  +  2}", &["1  +  2"]);
     assert_matches("1 + 2", "fn f() -> i32 {1+2}", &["1+2"]);
@@ -792,6 +801,19 @@ fn replace_type() {
             "struct Result<T, E> {} struct Option<T> {} fn f1() -> Option<Vec<Error>> {foo()}"
         ]],
     );
+    assert_ssr_transform(
+        "dyn Trait<$a> ==>> DynTrait<$a>",
+        r#"
+trait Trait<T> {}
+struct DynTrait<T> {}
+fn f1() -> dyn Trait<Vec<Error>> {foo()}
+"#,
+        expect![[r#"
+trait Trait<T> {}
+struct DynTrait<T> {}
+fn f1() -> DynTrait<Vec<Error>> {foo()}
+"#]],
+    );
 }
 
 #[test]
diff --git a/crates/mbe/src/expander/matcher.rs b/crates/mbe/src/expander/matcher.rs
index b2d3f038f54..bcda2381a48 100644
--- a/crates/mbe/src/expander/matcher.rs
+++ b/crates/mbe/src/expander/matcher.rs
@@ -61,18 +61,16 @@
 
 use std::rc::Rc;
 
+use smallvec::{smallvec, SmallVec};
+use syntax::SmolStr;
+
 use crate::{
-    expander::{Binding, Bindings, Fragment},
+    expander::{Binding, Bindings, ExpandResult, Fragment},
     parser::{Op, RepeatKind, Separator},
     tt_iter::TtIter,
     ExpandError, MetaTemplate,
 };
 
-use super::ExpandResult;
-use parser::ParserEntryPoint::*;
-use smallvec::{smallvec, SmallVec};
-use syntax::SmolStr;
-
 impl Bindings {
     fn push_optional(&mut self, name: &SmolStr) {
         // FIXME: Do we have a better way to represent an empty token ?
@@ -691,14 +689,21 @@ fn match_leaf(lhs: &tt::Leaf, src: &mut TtIter) -> Result<(), ExpandError> {
 
 fn match_meta_var(kind: &str, input: &mut TtIter) -> ExpandResult<Option<Fragment>> {
     let fragment = match kind {
-        "path" => Path,
-        "expr" => Expr,
-        "ty" => Type,
-        "pat" | "pat_param" => Pattern, // FIXME: edition2021
-        "stmt" => Statement,
-        "block" => Block,
-        "meta" => MetaItem,
-        "item" => Item,
+        "path" => parser::PrefixEntryPoint::Path,
+        "ty" => parser::PrefixEntryPoint::Ty,
+        // FIXME: These two should actually behave differently depending on the edition.
+        //
+        // https://doc.rust-lang.org/edition-guide/rust-2021/or-patterns-macro-rules.html
+        "pat" | "pat_param" => parser::PrefixEntryPoint::Pat,
+        "stmt" => parser::PrefixEntryPoint::Stmt,
+        "block" => parser::PrefixEntryPoint::Block,
+        "meta" => parser::PrefixEntryPoint::MetaItem,
+        "item" => parser::PrefixEntryPoint::Item,
+        "expr" => {
+            return input
+                .expect_fragment(parser::PrefixEntryPoint::Expr)
+                .map(|tt| tt.map(Fragment::Expr))
+        }
         _ => {
             let tt_result = match kind {
                 "ident" => input
@@ -726,17 +731,13 @@ fn match_meta_var(kind: &str, input: &mut TtIter) -> ExpandResult<Option<Fragmen
                         .map_err(|()| err!())
                 }
                 // `vis` is optional
-                "vis" => match input.eat_vis() {
-                    Some(vis) => Ok(Some(vis)),
-                    None => Ok(None),
-                },
+                "vis" => Ok(input.expect_fragment(parser::PrefixEntryPoint::Vis).value),
                 _ => Err(ExpandError::UnexpectedToken),
             };
             return tt_result.map(|it| it.map(Fragment::Tokens)).into();
         }
     };
-    let result = input.expect_fragment(fragment);
-    result.map(|tt| if kind == "expr" { tt.map(Fragment::Expr) } else { tt.map(Fragment::Tokens) })
+    input.expect_fragment(fragment).map(|it| it.map(Fragment::Tokens))
 }
 
 fn collect_vars(buf: &mut Vec<SmolStr>, pattern: &MetaTemplate) {
@@ -898,17 +899,6 @@ impl<'a> TtIter<'a> {
         .into())
     }
 
-    fn eat_vis(&mut self) -> Option<tt::TokenTree> {
-        let mut fork = self.clone();
-        match fork.expect_fragment(Visibility) {
-            ExpandResult { value: tt, err: None } => {
-                *self = fork;
-                tt
-            }
-            ExpandResult { value: _, err: Some(_) } => None,
-        }
-    }
-
     fn eat_char(&mut self, c: char) -> Option<tt::TokenTree> {
         let mut fork = self.clone();
         match fork.expect_char(c) {
diff --git a/crates/mbe/src/lib.rs b/crates/mbe/src/lib.rs
index 5e14a3fb590..62e7509eb37 100644
--- a/crates/mbe/src/lib.rs
+++ b/crates/mbe/src/lib.rs
@@ -24,7 +24,7 @@ use crate::{
 };
 
 // FIXME: we probably should re-think  `token_tree_to_syntax_node` interfaces
-pub use ::parser::ParserEntryPoint;
+pub use ::parser::TopEntryPoint;
 pub use tt::{Delimiter, DelimiterKind, Punct};
 
 #[derive(Debug, PartialEq, Eq, Clone)]
diff --git a/crates/mbe/src/syntax_bridge.rs b/crates/mbe/src/syntax_bridge.rs
index f0c1f806ffa..8bdc5e6e946 100644
--- a/crates/mbe/src/syntax_bridge.rs
+++ b/crates/mbe/src/syntax_bridge.rs
@@ -9,9 +9,7 @@ use syntax::{
 };
 use tt::buffer::{Cursor, TokenBuffer};
 
-use crate::{
-    to_parser_input::to_parser_input, tt_iter::TtIter, ExpandError, ParserEntryPoint, TokenMap,
-};
+use crate::{to_parser_input::to_parser_input, tt_iter::TtIter, ExpandError, TokenMap};
 
 /// Convert the syntax node to a `TokenTree` (what macro
 /// will consume).
@@ -46,7 +44,7 @@ pub fn syntax_node_to_token_tree_censored(
 
 pub fn token_tree_to_syntax_node(
     tt: &tt::Subtree,
-    entry_point: ParserEntryPoint,
+    entry_point: parser::TopEntryPoint,
 ) -> Result<(Parse<SyntaxNode>, TokenMap), ExpandError> {
     let buffer = match tt {
         tt::Subtree { delimiter: None, token_trees } => {
@@ -55,7 +53,7 @@ pub fn token_tree_to_syntax_node(
         _ => TokenBuffer::from_subtree(tt),
     };
     let parser_input = to_parser_input(&buffer);
-    let parser_output = parser::parse(&parser_input, entry_point);
+    let parser_output = entry_point.parse(&parser_input);
     let mut tree_sink = TtTreeSink::new(buffer.begin());
     for event in parser_output.iter() {
         match event {
@@ -106,7 +104,7 @@ pub fn parse_exprs_with_sep(tt: &tt::Subtree, sep: char) -> Vec<tt::Subtree> {
     let mut res = Vec::new();
 
     while iter.peek_n(0).is_some() {
-        let expanded = iter.expect_fragment(ParserEntryPoint::Expr);
+        let expanded = iter.expect_fragment(parser::PrefixEntryPoint::Expr);
 
         res.push(match expanded.value {
             None => break,
diff --git a/crates/mbe/src/tt_iter.rs b/crates/mbe/src/tt_iter.rs
index 2d2dbd8994f..6c9f615c7a9 100644
--- a/crates/mbe/src/tt_iter.rs
+++ b/crates/mbe/src/tt_iter.rs
@@ -1,7 +1,7 @@
 //! A "Parser" structure for token trees. We use this when parsing a declarative
 //! macro definition into a list of patterns and templates.
 
-use crate::{to_parser_input::to_parser_input, ExpandError, ExpandResult, ParserEntryPoint};
+use crate::{to_parser_input::to_parser_input, ExpandError, ExpandResult};
 
 use syntax::SyntaxKind;
 use tt::buffer::TokenBuffer;
@@ -91,11 +91,11 @@ impl<'a> TtIter<'a> {
 
     pub(crate) fn expect_fragment(
         &mut self,
-        entry_point: ParserEntryPoint,
+        entry_point: parser::PrefixEntryPoint,
     ) -> ExpandResult<Option<tt::TokenTree>> {
         let buffer = TokenBuffer::from_tokens(self.inner.as_slice());
         let parser_input = to_parser_input(&buffer);
-        let tree_traversal = parser::parse(&parser_input, entry_point);
+        let tree_traversal = entry_point.parse(&parser_input);
 
         let mut cursor = buffer.begin();
         let mut error = false;
diff --git a/crates/parser/src/grammar.rs b/crates/parser/src/grammar.rs
index 25178ddd775..42426a1df28 100644
--- a/crates/parser/src/grammar.rs
+++ b/crates/parser/src/grammar.rs
@@ -44,72 +44,76 @@ use crate::{
     TokenSet, T,
 };
 
-pub(crate) mod entry_points {
+pub(crate) mod entry {
     use super::*;
 
-    pub(crate) fn source_file(p: &mut Parser) {
-        let m = p.start();
-        p.eat(SHEBANG);
-        items::mod_contents(p, false);
-        m.complete(p, SOURCE_FILE);
-    }
-
-    pub(crate) use expressions::block_expr;
-
-    pub(crate) use paths::type_path as path;
+    pub(crate) mod prefix {
+        use super::*;
 
-    pub(crate) use patterns::pattern_single as pattern;
-
-    pub(crate) use types::type_;
+        pub(crate) fn vis(p: &mut Parser) {
+            let _ = opt_visibility(p, false);
+        }
 
-    pub(crate) fn expr(p: &mut Parser) {
-        let _ = expressions::expr(p);
-    }
+        pub(crate) fn block(p: &mut Parser) {
+            expressions::block_expr(p);
+        }
 
-    pub(crate) fn stmt(p: &mut Parser) {
-        expressions::stmt(p, expressions::StmtWithSemi::No, true);
-    }
+        pub(crate) fn stmt(p: &mut Parser) {
+            expressions::stmt(p, expressions::StmtWithSemi::No, true);
+        }
 
-    pub(crate) fn stmt_optional_semi(p: &mut Parser) {
-        expressions::stmt(p, expressions::StmtWithSemi::Optional, false);
-    }
+        pub(crate) fn pat(p: &mut Parser) {
+            patterns::pattern_single(p);
+        }
 
-    pub(crate) fn visibility(p: &mut Parser) {
-        let _ = opt_visibility(p, false);
+        pub(crate) fn ty(p: &mut Parser) {
+            types::type_(p);
+        }
+        pub(crate) fn expr(p: &mut Parser) {
+            let _ = expressions::expr(p);
+        }
+        pub(crate) fn path(p: &mut Parser) {
+            let _ = paths::type_path(p);
+        }
+        pub(crate) fn item(p: &mut Parser) {
+            items::item_or_macro(p, true);
+        }
+        // Parse a meta item , which excluded [], e.g : #[ MetaItem ]
+        pub(crate) fn meta_item(p: &mut Parser) {
+            attributes::meta(p);
+        }
     }
 
-    // Parse a meta item , which excluded [], e.g : #[ MetaItem ]
-    pub(crate) fn meta_item(p: &mut Parser) {
-        attributes::meta(p);
-    }
+    pub(crate) mod top {
+        use super::*;
 
-    pub(crate) fn item(p: &mut Parser) {
-        items::item_or_macro(p, true);
-    }
+        pub(crate) fn source_file(p: &mut Parser) {
+            let m = p.start();
+            p.eat(SHEBANG);
+            items::mod_contents(p, false);
+            m.complete(p, SOURCE_FILE);
+        }
 
-    pub(crate) fn macro_items(p: &mut Parser) {
-        let m = p.start();
-        items::mod_contents(p, false);
-        m.complete(p, MACRO_ITEMS);
-    }
+        pub(crate) fn macro_stmts(p: &mut Parser) {
+            let m = p.start();
 
-    pub(crate) fn macro_stmts(p: &mut Parser) {
-        let m = p.start();
+            while !p.at(EOF) {
+                if p.at(T![;]) {
+                    p.bump(T![;]);
+                    continue;
+                }
 
-        while !p.at(EOF) {
-            if p.at(T![;]) {
-                p.bump(T![;]);
-                continue;
+                expressions::stmt(p, expressions::StmtWithSemi::Optional, true);
             }
 
-            expressions::stmt(p, expressions::StmtWithSemi::Optional, true);
+            m.complete(p, MACRO_STMTS);
         }
 
-        m.complete(p, MACRO_STMTS);
-    }
-
-    pub(crate) fn attr(p: &mut Parser) {
-        attributes::outer_attrs(p);
+        pub(crate) fn macro_items(p: &mut Parser) {
+            let m = p.start();
+            items::mod_contents(p, false);
+            m.complete(p, MACRO_ITEMS);
+        }
     }
 }
 
diff --git a/crates/parser/src/lib.rs b/crates/parser/src/lib.rs
index 841d2aa4e94..c5014be6c33 100644
--- a/crates/parser/src/lib.rs
+++ b/crates/parser/src/lib.rs
@@ -41,63 +41,95 @@ pub use crate::{
     syntax_kind::SyntaxKind,
 };
 
-/// rust-analyzer parser allows you to choose one of the possible entry points.
+/// Parse a prefix of the input as a given syntactic construct.
 ///
-/// The primary consumer of this API are declarative macros, `$x:expr` matchers
-/// are implemented by calling into the parser with non-standard entry point.
-#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
-pub enum ParserEntryPoint {
-    SourceFile,
-    Path,
+/// This is used by macro-by-example parser to implement things like `$i:item`
+/// and the naming of variants follows the naming of macro fragments.
+///
+/// Note that this is generally non-optional -- the result is intentionally not
+/// `Option<Output>`. The way MBE work, by the time we *try* to parse `$e:expr`
+/// we already commit to expression. In other words, this API by design can't be
+/// used to implement "rollback and try another alternative" logic.
+#[derive(Debug)]
+pub enum PrefixEntryPoint {
+    Vis,
+    Block,
+    Stmt,
+    Pat,
+    Ty,
     Expr,
-    Statement,
-    StatementOptionalSemi,
-    Type,
-    Pattern,
+    Path,
     Item,
-    Block,
-    Visibility,
     MetaItem,
-    Items,
-    Statements,
-    Attr,
 }
 
-/// Parse given tokens into the given sink as a rust file.
-pub fn parse_source_file(inp: &Input) -> Output {
-    parse(inp, ParserEntryPoint::SourceFile)
+impl PrefixEntryPoint {
+    pub fn parse(&self, input: &Input) -> Output {
+        let entry_point: fn(&'_ mut parser::Parser) = match self {
+            PrefixEntryPoint::Vis => grammar::entry::prefix::vis,
+            PrefixEntryPoint::Block => grammar::entry::prefix::block,
+            PrefixEntryPoint::Stmt => grammar::entry::prefix::stmt,
+            PrefixEntryPoint::Pat => grammar::entry::prefix::pat,
+            PrefixEntryPoint::Ty => grammar::entry::prefix::ty,
+            PrefixEntryPoint::Expr => grammar::entry::prefix::expr,
+            PrefixEntryPoint::Path => grammar::entry::prefix::path,
+            PrefixEntryPoint::Item => grammar::entry::prefix::item,
+            PrefixEntryPoint::MetaItem => grammar::entry::prefix::meta_item,
+        };
+        let mut p = parser::Parser::new(input);
+        entry_point(&mut p);
+        let events = p.finish();
+        event::process(events)
+    }
 }
 
-/// Parses the given [`Input`] into [`Output`] assuming that the top-level
-/// syntactic construct is the given [`ParserEntryPoint`].
+/// Parse the whole of the input as a given syntactic construct.
+///
+/// This covers two main use-cases:
+///
+///   * Parsing a Rust file.
+///   * Parsing a result of macro expansion.
 ///
-/// Both input and output here are fairly abstract. The overall flow is that the
-/// caller has some "real" tokens, converts them to [`Input`], parses them to
-/// [`Output`], and then converts that into a "real" tree. The "real" tree is
-/// made of "real" tokens, so this all hinges on rather tight coordination of
-/// indices between the four stages.
-pub fn parse(inp: &Input, entry_point: ParserEntryPoint) -> Output {
-    let entry_point: fn(&'_ mut parser::Parser) = match entry_point {
-        ParserEntryPoint::SourceFile => grammar::entry_points::source_file,
-        ParserEntryPoint::Path => grammar::entry_points::path,
-        ParserEntryPoint::Expr => grammar::entry_points::expr,
-        ParserEntryPoint::Type => grammar::entry_points::type_,
-        ParserEntryPoint::Pattern => grammar::entry_points::pattern,
-        ParserEntryPoint::Item => grammar::entry_points::item,
-        ParserEntryPoint::Block => grammar::entry_points::block_expr,
-        ParserEntryPoint::Visibility => grammar::entry_points::visibility,
-        ParserEntryPoint::MetaItem => grammar::entry_points::meta_item,
-        ParserEntryPoint::Statement => grammar::entry_points::stmt,
-        ParserEntryPoint::StatementOptionalSemi => grammar::entry_points::stmt_optional_semi,
-        ParserEntryPoint::Items => grammar::entry_points::macro_items,
-        ParserEntryPoint::Statements => grammar::entry_points::macro_stmts,
-        ParserEntryPoint::Attr => grammar::entry_points::attr,
-    };
+/// That is, for something like
+///
+/// ```
+/// quick_check! {
+///    fn prop() {}
+/// }
+/// ```
+///
+/// the input to the macro will be parsed with [`PrefixEntryPoint::Item`], and
+/// the result will be [`TopEntryPoint::Items`].
+///
+/// This *should* (but currently doesn't) guarantee that all input is consumed.
+#[derive(Debug)]
+pub enum TopEntryPoint {
+    SourceFile,
+    MacroStmts,
+    MacroItems,
+    Pattern,
+    Type,
+    Expr,
+    MetaItem,
+}
 
-    let mut p = parser::Parser::new(inp);
-    entry_point(&mut p);
-    let events = p.finish();
-    event::process(events)
+impl TopEntryPoint {
+    pub fn parse(&self, input: &Input) -> Output {
+        let entry_point: fn(&'_ mut parser::Parser) = match self {
+            TopEntryPoint::SourceFile => grammar::entry::top::source_file,
+            TopEntryPoint::MacroStmts => grammar::entry::top::macro_stmts,
+            TopEntryPoint::MacroItems => grammar::entry::top::macro_items,
+            // FIXME
+            TopEntryPoint::Pattern => grammar::entry::prefix::pat,
+            TopEntryPoint::Type => grammar::entry::prefix::ty,
+            TopEntryPoint::Expr => grammar::entry::prefix::expr,
+            TopEntryPoint::MetaItem => grammar::entry::prefix::meta_item,
+        };
+        let mut p = parser::Parser::new(input);
+        entry_point(&mut p);
+        let events = p.finish();
+        event::process(events)
+    }
 }
 
 /// A parsing function for a specific braced-block.
diff --git a/crates/parser/src/shortcuts.rs b/crates/parser/src/shortcuts.rs
index 15387a85cc1..3d28f814c9f 100644
--- a/crates/parser/src/shortcuts.rs
+++ b/crates/parser/src/shortcuts.rs
@@ -52,14 +52,10 @@ impl<'a> LexedStr<'a> {
     pub fn intersperse_trivia(
         &self,
         output: &crate::Output,
-        synthetic_root: bool,
         sink: &mut dyn FnMut(StrStep),
     ) -> bool {
         let mut builder = Builder { lexed: self, pos: 0, state: State::PendingEnter, sink };
 
-        if synthetic_root {
-            builder.enter(SyntaxKind::SOURCE_FILE);
-        }
         for event in output.iter() {
             match event {
                 Step::Token { kind, n_input_tokens: n_raw_tokens } => {
@@ -73,9 +69,6 @@ impl<'a> LexedStr<'a> {
                 }
             }
         }
-        if synthetic_root {
-            builder.exit();
-        }
 
         match mem::replace(&mut builder.state, State::Normal) {
             State::PendingExit => {
diff --git a/crates/parser/src/tests.rs b/crates/parser/src/tests.rs
index 7a6230eaf8b..512f7ddb95b 100644
--- a/crates/parser/src/tests.rs
+++ b/crates/parser/src/tests.rs
@@ -80,12 +80,12 @@ fn parse_inline_err() {
 fn parse(text: &str) -> (String, bool) {
     let lexed = LexedStr::new(text);
     let input = lexed.to_input();
-    let output = crate::parse_source_file(&input);
+    let output = crate::TopEntryPoint::SourceFile.parse(&input);
 
     let mut buf = String::new();
     let mut errors = Vec::new();
     let mut indent = String::new();
-    lexed.intersperse_trivia(&output, false, &mut |step| match step {
+    lexed.intersperse_trivia(&output, &mut |step| match step {
         crate::StrStep::Token { kind, text } => {
             write!(buf, "{}", indent).unwrap();
             write!(buf, "{:?} {:?}\n", kind, text).unwrap();
diff --git a/crates/syntax/src/hacks.rs b/crates/syntax/src/hacks.rs
new file mode 100644
index 00000000000..a047f61fa03
--- /dev/null
+++ b/crates/syntax/src/hacks.rs
@@ -0,0 +1,15 @@
+//! Things which exist to solve practial issues, but which shouldn't exist.
+//!
+//! Please avoid adding new usages of the functions in this module
+
+use crate::{ast, AstNode};
+
+pub fn parse_expr_from_str(s: &str) -> Option<ast::Expr> {
+    let s = s.trim();
+    let file = ast::SourceFile::parse(&format!("const _: () = {};", s));
+    let expr = file.syntax_node().descendants().find_map(ast::Expr::cast)?;
+    if expr.syntax().text() != s {
+        return None;
+    }
+    Some(expr)
+}
diff --git a/crates/syntax/src/lib.rs b/crates/syntax/src/lib.rs
index 65a6b7ac4e4..d6b1cce45ff 100644
--- a/crates/syntax/src/lib.rs
+++ b/crates/syntax/src/lib.rs
@@ -40,6 +40,7 @@ pub mod ast;
 pub mod fuzz;
 pub mod utils;
 pub mod ted;
+pub mod hacks;
 
 use std::{marker::PhantomData, sync::Arc};
 
@@ -167,61 +168,6 @@ impl SourceFile {
     }
 }
 
-// FIXME: `parse` functions shouldn't hang directly from AST nodes, and they
-// shouldn't return `Result`.
-//
-// We need a dedicated module for parser entry points, and they should always
-// return `Parse`.
-
-impl ast::Path {
-    /// Returns `text`, parsed as a path, but only if it has no errors.
-    pub fn parse(text: &str) -> Result<Self, ()> {
-        parsing::parse_text_as(text, parser::ParserEntryPoint::Path)
-    }
-}
-
-impl ast::Pat {
-    /// Returns `text`, parsed as a pattern, but only if it has no errors.
-    pub fn parse(text: &str) -> Result<Self, ()> {
-        parsing::parse_text_as(text, parser::ParserEntryPoint::Pattern)
-    }
-}
-
-impl ast::Expr {
-    /// Returns `text`, parsed as an expression, but only if it has no errors.
-    pub fn parse(text: &str) -> Result<Self, ()> {
-        parsing::parse_text_as(text, parser::ParserEntryPoint::Expr)
-    }
-}
-
-impl ast::Item {
-    /// Returns `text`, parsed as an item, but only if it has no errors.
-    pub fn parse(text: &str) -> Result<Self, ()> {
-        parsing::parse_text_as(text, parser::ParserEntryPoint::Item)
-    }
-}
-
-impl ast::Type {
-    /// Returns `text`, parsed as an type reference, but only if it has no errors.
-    pub fn parse(text: &str) -> Result<Self, ()> {
-        parsing::parse_text_as(text, parser::ParserEntryPoint::Type)
-    }
-}
-
-impl ast::Attr {
-    /// Returns `text`, parsed as an attribute, but only if it has no errors.
-    pub fn parse(text: &str) -> Result<Self, ()> {
-        parsing::parse_text_as(text, parser::ParserEntryPoint::Attr)
-    }
-}
-
-impl ast::Stmt {
-    /// Returns `text`, parsed as statement, but only if it has no errors.
-    pub fn parse(text: &str) -> Result<Self, ()> {
-        parsing::parse_text_as(text, parser::ParserEntryPoint::StatementOptionalSemi)
-    }
-}
-
 /// Matches a `SyntaxNode` against an `ast` type.
 ///
 /// # Example:
diff --git a/crates/syntax/src/parsing.rs b/crates/syntax/src/parsing.rs
index 971fa2700d2..047e670c9f4 100644
--- a/crates/syntax/src/parsing.rs
+++ b/crates/syntax/src/parsing.rs
@@ -5,46 +5,25 @@ mod reparsing;
 
 use rowan::TextRange;
 
-use crate::{syntax_node::GreenNode, AstNode, SyntaxError, SyntaxNode, SyntaxTreeBuilder};
+use crate::{syntax_node::GreenNode, SyntaxError, SyntaxTreeBuilder};
 
 pub(crate) use crate::parsing::reparsing::incremental_reparse;
 
 pub(crate) fn parse_text(text: &str) -> (GreenNode, Vec<SyntaxError>) {
     let lexed = parser::LexedStr::new(text);
     let parser_input = lexed.to_input();
-    let parser_output = parser::parse_source_file(&parser_input);
-    let (node, errors, _eof) = build_tree(lexed, parser_output, false);
+    let parser_output = parser::TopEntryPoint::SourceFile.parse(&parser_input);
+    let (node, errors, _eof) = build_tree(lexed, parser_output);
     (node, errors)
 }
 
-/// Returns `text` parsed as a `T` provided there are no parse errors.
-pub(crate) fn parse_text_as<T: AstNode>(
-    text: &str,
-    entry_point: parser::ParserEntryPoint,
-) -> Result<T, ()> {
-    let lexed = parser::LexedStr::new(text);
-    if lexed.errors().next().is_some() {
-        return Err(());
-    }
-    let parser_input = lexed.to_input();
-    let parser_output = parser::parse(&parser_input, entry_point);
-    let (node, errors, eof) = build_tree(lexed, parser_output, true);
-
-    if !errors.is_empty() || !eof {
-        return Err(());
-    }
-
-    SyntaxNode::new_root(node).first_child().and_then(T::cast).ok_or(())
-}
-
 pub(crate) fn build_tree(
     lexed: parser::LexedStr<'_>,
     parser_output: parser::Output,
-    synthetic_root: bool,
 ) -> (GreenNode, Vec<SyntaxError>, bool) {
     let mut builder = SyntaxTreeBuilder::default();
 
-    let is_eof = lexed.intersperse_trivia(&parser_output, synthetic_root, &mut |step| match step {
+    let is_eof = lexed.intersperse_trivia(&parser_output, &mut |step| match step {
         parser::StrStep::Token { kind, text } => builder.token(kind, text),
         parser::StrStep::Enter { kind } => builder.start_node(kind),
         parser::StrStep::Exit => builder.finish_node(),
diff --git a/crates/syntax/src/parsing/reparsing.rs b/crates/syntax/src/parsing/reparsing.rs
index dd2e01bfc4c..701e6232d58 100644
--- a/crates/syntax/src/parsing/reparsing.rs
+++ b/crates/syntax/src/parsing/reparsing.rs
@@ -96,7 +96,7 @@ fn reparse_block(
 
     let tree_traversal = reparser.parse(&parser_input);
 
-    let (green, new_parser_errors, _eof) = build_tree(lexed, tree_traversal, false);
+    let (green, new_parser_errors, _eof) = build_tree(lexed, tree_traversal);
 
     Some((node.replace_with(green), new_parser_errors, node.text_range()))
 }
diff --git a/crates/syntax/src/tests.rs b/crates/syntax/src/tests.rs
index 04105dedc9e..0611143e2af 100644
--- a/crates/syntax/src/tests.rs
+++ b/crates/syntax/src/tests.rs
@@ -60,60 +60,6 @@ fn validation_tests() {
 }
 
 #[test]
-fn expr_parser_tests() {
-    fragment_parser_dir_test(
-        &["parser/fragments/expr/ok"],
-        &["parser/fragments/expr/err"],
-        crate::ast::Expr::parse,
-    );
-}
-
-#[test]
-fn path_parser_tests() {
-    fragment_parser_dir_test(
-        &["parser/fragments/path/ok"],
-        &["parser/fragments/path/err"],
-        crate::ast::Path::parse,
-    );
-}
-
-#[test]
-fn pattern_parser_tests() {
-    fragment_parser_dir_test(
-        &["parser/fragments/pattern/ok"],
-        &["parser/fragments/pattern/err"],
-        crate::ast::Pat::parse,
-    );
-}
-
-#[test]
-fn item_parser_tests() {
-    fragment_parser_dir_test(
-        &["parser/fragments/item/ok"],
-        &["parser/fragments/item/err"],
-        crate::ast::Item::parse,
-    );
-}
-
-#[test]
-fn type_parser_tests() {
-    fragment_parser_dir_test(
-        &["parser/fragments/type/ok"],
-        &["parser/fragments/type/err"],
-        crate::ast::Type::parse,
-    );
-}
-
-#[test]
-fn stmt_parser_tests() {
-    fragment_parser_dir_test(
-        &["parser/fragments/stmt/ok"],
-        &["parser/fragments/stmt/err"],
-        crate::ast::Stmt::parse,
-    );
-}
-
-#[test]
 fn parser_fuzz_tests() {
     for (_, text) in collect_rust_files(&test_data_dir(), &["parser/fuzz-failures"]) {
         fuzz::check_parser(&text)
@@ -172,24 +118,6 @@ fn assert_errors_are_present(errors: &[SyntaxError], path: &Path) {
     assert!(!errors.is_empty(), "There should be errors in the file {:?}", path.display());
 }
 
-fn fragment_parser_dir_test<T, F>(ok_paths: &[&str], err_paths: &[&str], f: F)
-where
-    T: crate::AstNode,
-    F: Fn(&str) -> Result<T, ()>,
-{
-    dir_tests(&test_data_dir(), ok_paths, "rast", |text, path| match f(text) {
-        Ok(node) => format!("{:#?}", crate::ast::AstNode::syntax(&node)),
-        Err(_) => panic!("Failed to parse '{:?}'", path),
-    });
-    dir_tests(&test_data_dir(), err_paths, "rast", |text, path| {
-        if f(text).is_ok() {
-            panic!("'{:?}' successfully parsed when it should have errored", path);
-        } else {
-            "ERROR\n".to_owned()
-        }
-    });
-}
-
 /// Calls callback `f` with input code and file paths for each `.rs` file in `test_data_dir`
 /// subdirectories defined by `paths`.
 ///
diff --git a/crates/syntax/test_data/parser/fragments/expr/err/0000_truncated_add.rast b/crates/syntax/test_data/parser/fragments/expr/err/0000_truncated_add.rast
deleted file mode 100644
index 5df7507e2de..00000000000
--- a/crates/syntax/test_data/parser/fragments/expr/err/0000_truncated_add.rast
+++ /dev/null
@@ -1 +0,0 @@
-ERROR
diff --git a/crates/syntax/test_data/parser/fragments/expr/err/0000_truncated_add.rs b/crates/syntax/test_data/parser/fragments/expr/err/0000_truncated_add.rs
deleted file mode 100644
index ca49acb079e..00000000000
--- a/crates/syntax/test_data/parser/fragments/expr/err/0000_truncated_add.rs
+++ /dev/null
@@ -1 +0,0 @@
-1 +
diff --git a/crates/syntax/test_data/parser/fragments/expr/ok/0000_add.rast b/crates/syntax/test_data/parser/fragments/expr/ok/0000_add.rast
deleted file mode 100644
index fa78a02a6bf..00000000000
--- a/crates/syntax/test_data/parser/fragments/expr/ok/0000_add.rast
+++ /dev/null
@@ -1,8 +0,0 @@
-BIN_EXPR@0..5
-  LITERAL@0..1
-    INT_NUMBER@0..1 "1"
-  WHITESPACE@1..2 " "
-  PLUS@2..3 "+"
-  WHITESPACE@3..4 " "
-  LITERAL@4..5
-    INT_NUMBER@4..5 "2"
diff --git a/crates/syntax/test_data/parser/fragments/expr/ok/0000_add.rs b/crates/syntax/test_data/parser/fragments/expr/ok/0000_add.rs
deleted file mode 100644
index e0ef5840209..00000000000
--- a/crates/syntax/test_data/parser/fragments/expr/ok/0000_add.rs
+++ /dev/null
@@ -1 +0,0 @@
-1 + 2
diff --git a/crates/syntax/test_data/parser/fragments/item/err/0000_extra_keyword.rast b/crates/syntax/test_data/parser/fragments/item/err/0000_extra_keyword.rast
deleted file mode 100644
index 5df7507e2de..00000000000
--- a/crates/syntax/test_data/parser/fragments/item/err/0000_extra_keyword.rast
+++ /dev/null
@@ -1 +0,0 @@
-ERROR
diff --git a/crates/syntax/test_data/parser/fragments/item/err/0000_extra_keyword.rs b/crates/syntax/test_data/parser/fragments/item/err/0000_extra_keyword.rs
deleted file mode 100644
index dc32389bbb7..00000000000
--- a/crates/syntax/test_data/parser/fragments/item/err/0000_extra_keyword.rs
+++ /dev/null
@@ -1 +0,0 @@
-fn fn foo() {}
diff --git a/crates/syntax/test_data/parser/fragments/item/ok/0000_fn.rast b/crates/syntax/test_data/parser/fragments/item/ok/0000_fn.rast
deleted file mode 100644
index 4ff9967beac..00000000000
--- a/crates/syntax/test_data/parser/fragments/item/ok/0000_fn.rast
+++ /dev/null
@@ -1,13 +0,0 @@
-FN@0..11
-  FN_KW@0..2 "fn"
-  WHITESPACE@2..3 " "
-  NAME@3..6
-    IDENT@3..6 "foo"
-  PARAM_LIST@6..8
-    L_PAREN@6..7 "("
-    R_PAREN@7..8 ")"
-  WHITESPACE@8..9 " "
-  BLOCK_EXPR@9..11
-    STMT_LIST@9..11
-      L_CURLY@9..10 "{"
-      R_CURLY@10..11 "}"
diff --git a/crates/syntax/test_data/parser/fragments/item/ok/0000_fn.rs b/crates/syntax/test_data/parser/fragments/item/ok/0000_fn.rs
deleted file mode 100644
index 8f3b7ef112a..00000000000
--- a/crates/syntax/test_data/parser/fragments/item/ok/0000_fn.rs
+++ /dev/null
@@ -1 +0,0 @@
-fn foo() {}
diff --git a/crates/syntax/test_data/parser/fragments/path/err/0000_reserved_word.rast b/crates/syntax/test_data/parser/fragments/path/err/0000_reserved_word.rast
deleted file mode 100644
index 5df7507e2de..00000000000
--- a/crates/syntax/test_data/parser/fragments/path/err/0000_reserved_word.rast
+++ /dev/null
@@ -1 +0,0 @@
-ERROR
diff --git a/crates/syntax/test_data/parser/fragments/path/err/0000_reserved_word.rs b/crates/syntax/test_data/parser/fragments/path/err/0000_reserved_word.rs
deleted file mode 100644
index 2046de04929..00000000000
--- a/crates/syntax/test_data/parser/fragments/path/err/0000_reserved_word.rs
+++ /dev/null
@@ -1 +0,0 @@
-struct
diff --git a/crates/syntax/test_data/parser/fragments/path/err/0001_expression.rast b/crates/syntax/test_data/parser/fragments/path/err/0001_expression.rast
deleted file mode 100644
index 5df7507e2de..00000000000
--- a/crates/syntax/test_data/parser/fragments/path/err/0001_expression.rast
+++ /dev/null
@@ -1 +0,0 @@
-ERROR
diff --git a/crates/syntax/test_data/parser/fragments/path/err/0001_expression.rs b/crates/syntax/test_data/parser/fragments/path/err/0001_expression.rs
deleted file mode 100644
index 745e8d376f7..00000000000
--- a/crates/syntax/test_data/parser/fragments/path/err/0001_expression.rs
+++ /dev/null
@@ -1 +0,0 @@
-a + b
diff --git a/crates/syntax/test_data/parser/fragments/path/ok/0000_single_ident.rast b/crates/syntax/test_data/parser/fragments/path/ok/0000_single_ident.rast
deleted file mode 100644
index 0c5d4360fa8..00000000000
--- a/crates/syntax/test_data/parser/fragments/path/ok/0000_single_ident.rast
+++ /dev/null
@@ -1,4 +0,0 @@
-PATH@0..3
-  PATH_SEGMENT@0..3
-    NAME_REF@0..3
-      IDENT@0..3 "foo"
diff --git a/crates/syntax/test_data/parser/fragments/path/ok/0000_single_ident.rs b/crates/syntax/test_data/parser/fragments/path/ok/0000_single_ident.rs
deleted file mode 100644
index 257cc5642cb..00000000000
--- a/crates/syntax/test_data/parser/fragments/path/ok/0000_single_ident.rs
+++ /dev/null
@@ -1 +0,0 @@
-foo
diff --git a/crates/syntax/test_data/parser/fragments/path/ok/0001_multipart.rast b/crates/syntax/test_data/parser/fragments/path/ok/0001_multipart.rast
deleted file mode 100644
index 4a2b45e6a96..00000000000
--- a/crates/syntax/test_data/parser/fragments/path/ok/0001_multipart.rast
+++ /dev/null
@@ -1,14 +0,0 @@
-PATH@0..13
-  PATH@0..8
-    PATH@0..3
-      PATH_SEGMENT@0..3
-        NAME_REF@0..3
-          IDENT@0..3 "foo"
-    COLON2@3..5 "::"
-    PATH_SEGMENT@5..8
-      NAME_REF@5..8
-        IDENT@5..8 "bar"
-  COLON2@8..10 "::"
-  PATH_SEGMENT@10..13
-    NAME_REF@10..13
-      IDENT@10..13 "baz"
diff --git a/crates/syntax/test_data/parser/fragments/path/ok/0001_multipart.rs b/crates/syntax/test_data/parser/fragments/path/ok/0001_multipart.rs
deleted file mode 100644
index 81e0b21cd41..00000000000
--- a/crates/syntax/test_data/parser/fragments/path/ok/0001_multipart.rs
+++ /dev/null
@@ -1 +0,0 @@
-foo::bar::baz
diff --git a/crates/syntax/test_data/parser/fragments/pattern/err/0000_reserved_word.rast b/crates/syntax/test_data/parser/fragments/pattern/err/0000_reserved_word.rast
deleted file mode 100644
index 5df7507e2de..00000000000
--- a/crates/syntax/test_data/parser/fragments/pattern/err/0000_reserved_word.rast
+++ /dev/null
@@ -1 +0,0 @@
-ERROR
diff --git a/crates/syntax/test_data/parser/fragments/pattern/err/0000_reserved_word.rs b/crates/syntax/test_data/parser/fragments/pattern/err/0000_reserved_word.rs
deleted file mode 100644
index ae26fc45566..00000000000
--- a/crates/syntax/test_data/parser/fragments/pattern/err/0000_reserved_word.rs
+++ /dev/null
@@ -1 +0,0 @@
-fn
diff --git a/crates/syntax/test_data/parser/fragments/pattern/err/0001_missing_paren.rast b/crates/syntax/test_data/parser/fragments/pattern/err/0001_missing_paren.rast
deleted file mode 100644
index 5df7507e2de..00000000000
--- a/crates/syntax/test_data/parser/fragments/pattern/err/0001_missing_paren.rast
+++ /dev/null
@@ -1 +0,0 @@
-ERROR
diff --git a/crates/syntax/test_data/parser/fragments/pattern/err/0001_missing_paren.rs b/crates/syntax/test_data/parser/fragments/pattern/err/0001_missing_paren.rs
deleted file mode 100644
index 61a391d0846..00000000000
--- a/crates/syntax/test_data/parser/fragments/pattern/err/0001_missing_paren.rs
+++ /dev/null
@@ -1 +0,0 @@
-Some(x
diff --git a/crates/syntax/test_data/parser/fragments/pattern/ok/0000_enum.rast b/crates/syntax/test_data/parser/fragments/pattern/ok/0000_enum.rast
deleted file mode 100644
index dcf102339aa..00000000000
--- a/crates/syntax/test_data/parser/fragments/pattern/ok/0000_enum.rast
+++ /dev/null
@@ -1,10 +0,0 @@
-TUPLE_STRUCT_PAT@0..7
-  PATH@0..4
-    PATH_SEGMENT@0..4
-      NAME_REF@0..4
-        IDENT@0..4 "Some"
-  L_PAREN@4..5 "("
-  IDENT_PAT@5..6
-    NAME@5..6
-      IDENT@5..6 "x"
-  R_PAREN@6..7 ")"
diff --git a/crates/syntax/test_data/parser/fragments/pattern/ok/0000_enum.rs b/crates/syntax/test_data/parser/fragments/pattern/ok/0000_enum.rs
deleted file mode 100644
index 87114dd7881..00000000000
--- a/crates/syntax/test_data/parser/fragments/pattern/ok/0000_enum.rs
+++ /dev/null
@@ -1 +0,0 @@
-Some(x)
diff --git a/crates/syntax/test_data/parser/fragments/stmt/err/0000_attr.rast b/crates/syntax/test_data/parser/fragments/stmt/err/0000_attr.rast
deleted file mode 100644
index 5df7507e2de..00000000000
--- a/crates/syntax/test_data/parser/fragments/stmt/err/0000_attr.rast
+++ /dev/null
@@ -1 +0,0 @@
-ERROR
diff --git a/crates/syntax/test_data/parser/fragments/stmt/err/0000_attr.rs b/crates/syntax/test_data/parser/fragments/stmt/err/0000_attr.rs
deleted file mode 100644
index 988df070597..00000000000
--- a/crates/syntax/test_data/parser/fragments/stmt/err/0000_attr.rs
+++ /dev/null
@@ -1 +0,0 @@
-#[foo]
diff --git a/crates/syntax/test_data/parser/fragments/stmt/err/0000_multiple_stmts.rast b/crates/syntax/test_data/parser/fragments/stmt/err/0000_multiple_stmts.rast
deleted file mode 100644
index 5df7507e2de..00000000000
--- a/crates/syntax/test_data/parser/fragments/stmt/err/0000_multiple_stmts.rast
+++ /dev/null
@@ -1 +0,0 @@
-ERROR
diff --git a/crates/syntax/test_data/parser/fragments/stmt/err/0000_multiple_stmts.rs b/crates/syntax/test_data/parser/fragments/stmt/err/0000_multiple_stmts.rs
deleted file mode 100644
index 7e3b2fd4936..00000000000
--- a/crates/syntax/test_data/parser/fragments/stmt/err/0000_multiple_stmts.rs
+++ /dev/null
@@ -1 +0,0 @@
-a(); b(); c()
diff --git a/crates/syntax/test_data/parser/fragments/stmt/err/0000_open_parenthesis.rast b/crates/syntax/test_data/parser/fragments/stmt/err/0000_open_parenthesis.rast
deleted file mode 100644
index 5df7507e2de..00000000000
--- a/crates/syntax/test_data/parser/fragments/stmt/err/0000_open_parenthesis.rast
+++ /dev/null
@@ -1 +0,0 @@
-ERROR
diff --git a/crates/syntax/test_data/parser/fragments/stmt/err/0000_open_parenthesis.rs b/crates/syntax/test_data/parser/fragments/stmt/err/0000_open_parenthesis.rs
deleted file mode 100644
index 2d06f376636..00000000000
--- a/crates/syntax/test_data/parser/fragments/stmt/err/0000_open_parenthesis.rs
+++ /dev/null
@@ -1 +0,0 @@
-(
diff --git a/crates/syntax/test_data/parser/fragments/stmt/err/0000_semicolon.rast b/crates/syntax/test_data/parser/fragments/stmt/err/0000_semicolon.rast
deleted file mode 100644
index 5df7507e2de..00000000000
--- a/crates/syntax/test_data/parser/fragments/stmt/err/0000_semicolon.rast
+++ /dev/null
@@ -1 +0,0 @@
-ERROR
diff --git a/crates/syntax/test_data/parser/fragments/stmt/err/0000_semicolon.rs b/crates/syntax/test_data/parser/fragments/stmt/err/0000_semicolon.rs
deleted file mode 100644
index 092bc2b0412..00000000000
--- a/crates/syntax/test_data/parser/fragments/stmt/err/0000_semicolon.rs
+++ /dev/null
@@ -1 +0,0 @@
-;
diff --git a/crates/syntax/test_data/parser/fragments/stmt/err/0000_unterminated_expr.rast b/crates/syntax/test_data/parser/fragments/stmt/err/0000_unterminated_expr.rast
deleted file mode 100644
index 5df7507e2de..00000000000
--- a/crates/syntax/test_data/parser/fragments/stmt/err/0000_unterminated_expr.rast
+++ /dev/null
@@ -1 +0,0 @@
-ERROR
diff --git a/crates/syntax/test_data/parser/fragments/stmt/err/0000_unterminated_expr.rs b/crates/syntax/test_data/parser/fragments/stmt/err/0000_unterminated_expr.rs
deleted file mode 100644
index ca49acb079e..00000000000
--- a/crates/syntax/test_data/parser/fragments/stmt/err/0000_unterminated_expr.rs
+++ /dev/null
@@ -1 +0,0 @@
-1 +
diff --git a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_expr.rast b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_expr.rast
deleted file mode 100644
index 274fdf16deb..00000000000
--- a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_expr.rast
+++ /dev/null
@@ -1,9 +0,0 @@
-EXPR_STMT@0..5
-  BIN_EXPR@0..5
-    LITERAL@0..1
-      INT_NUMBER@0..1 "1"
-    WHITESPACE@1..2 " "
-    PLUS@2..3 "+"
-    WHITESPACE@3..4 " "
-    LITERAL@4..5
-      INT_NUMBER@4..5 "1"
diff --git a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_expr.rs b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_expr.rs
deleted file mode 100644
index 8d2f0971e2c..00000000000
--- a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_expr.rs
+++ /dev/null
@@ -1 +0,0 @@
-1 + 1
diff --git a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_expr_block.rast b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_expr_block.rast
deleted file mode 100644
index a2d4f18988a..00000000000
--- a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_expr_block.rast
+++ /dev/null
@@ -1,70 +0,0 @@
-EXPR_STMT@0..55
-  BLOCK_EXPR@0..55
-    STMT_LIST@0..55
-      L_CURLY@0..1 "{"
-      WHITESPACE@1..6 "\n    "
-      LET_STMT@6..20
-        LET_KW@6..9 "let"
-        WHITESPACE@9..10 " "
-        IDENT_PAT@10..11
-          NAME@10..11
-            IDENT@10..11 "x"
-        WHITESPACE@11..12 " "
-        EQ@12..13 "="
-        WHITESPACE@13..14 " "
-        CALL_EXPR@14..19
-          PATH_EXPR@14..17
-            PATH@14..17
-              PATH_SEGMENT@14..17
-                NAME_REF@14..17
-                  IDENT@14..17 "foo"
-          ARG_LIST@17..19
-            L_PAREN@17..18 "("
-            R_PAREN@18..19 ")"
-        SEMICOLON@19..20 ";"
-      WHITESPACE@20..25 "\n    "
-      LET_STMT@25..39
-        LET_KW@25..28 "let"
-        WHITESPACE@28..29 " "
-        IDENT_PAT@29..30
-          NAME@29..30
-            IDENT@29..30 "y"
-        WHITESPACE@30..31 " "
-        EQ@31..32 "="
-        WHITESPACE@32..33 " "
-        CALL_EXPR@33..38
-          PATH_EXPR@33..36
-            PATH@33..36
-              PATH_SEGMENT@33..36
-                NAME_REF@33..36
-                  IDENT@33..36 "bar"
-          ARG_LIST@36..38
-            L_PAREN@36..37 "("
-            R_PAREN@37..38 ")"
-        SEMICOLON@38..39 ";"
-      WHITESPACE@39..44 "\n    "
-      CALL_EXPR@44..53
-        PATH_EXPR@44..46
-          PATH@44..46
-            PATH_SEGMENT@44..46
-              NAME_REF@44..46
-                IDENT@44..46 "Ok"
-        ARG_LIST@46..53
-          L_PAREN@46..47 "("
-          BIN_EXPR@47..52
-            PATH_EXPR@47..48
-              PATH@47..48
-                PATH_SEGMENT@47..48
-                  NAME_REF@47..48
-                    IDENT@47..48 "x"
-            WHITESPACE@48..49 " "
-            PLUS@49..50 "+"
-            WHITESPACE@50..51 " "
-            PATH_EXPR@51..52
-              PATH@51..52
-                PATH_SEGMENT@51..52
-                  NAME_REF@51..52
-                    IDENT@51..52 "y"
-          R_PAREN@52..53 ")"
-      WHITESPACE@53..54 "\n"
-      R_CURLY@54..55 "}"
diff --git a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_expr_block.rs b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_expr_block.rs
deleted file mode 100644
index ffa5c1e66ef..00000000000
--- a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_expr_block.rs
+++ /dev/null
@@ -1,5 +0,0 @@
-{
-    let x = foo();
-    let y = bar();
-    Ok(x + y)
-}
diff --git a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_fn_call.rast b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_fn_call.rast
deleted file mode 100644
index 8c186da93ee..00000000000
--- a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_fn_call.rast
+++ /dev/null
@@ -1,11 +0,0 @@
-EXPR_STMT@0..6
-  CALL_EXPR@0..5
-    PATH_EXPR@0..3
-      PATH@0..3
-        PATH_SEGMENT@0..3
-          NAME_REF@0..3
-            IDENT@0..3 "foo"
-    ARG_LIST@3..5
-      L_PAREN@3..4 "("
-      R_PAREN@4..5 ")"
-  SEMICOLON@5..6 ";"
diff --git a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_fn_call.rs b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_fn_call.rs
deleted file mode 100644
index a280f9a5cce..00000000000
--- a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_fn_call.rs
+++ /dev/null
@@ -1 +0,0 @@
-foo();
diff --git a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_let_stmt.rast b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_let_stmt.rast
deleted file mode 100644
index 8ab38da21cb..00000000000
--- a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_let_stmt.rast
+++ /dev/null
@@ -1,12 +0,0 @@
-LET_STMT@0..11
-  LET_KW@0..3 "let"
-  WHITESPACE@3..4 " "
-  IDENT_PAT@4..5
-    NAME@4..5
-      IDENT@4..5 "x"
-  WHITESPACE@5..6 " "
-  EQ@6..7 "="
-  WHITESPACE@7..8 " "
-  LITERAL@8..10
-    INT_NUMBER@8..10 "10"
-  SEMICOLON@10..11 ";"
diff --git a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_let_stmt.rs b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_let_stmt.rs
deleted file mode 100644
index de8a7f1fc6c..00000000000
--- a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_let_stmt.rs
+++ /dev/null
@@ -1 +0,0 @@
-let x = 10;
diff --git a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_macro_let_stmt.rast b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_macro_let_stmt.rast
deleted file mode 100644
index 81d6df29a5f..00000000000
--- a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_macro_let_stmt.rast
+++ /dev/null
@@ -1,21 +0,0 @@
-EXPR_STMT@0..18
-  MACRO_CALL@0..17
-    PATH@0..2
-      PATH_SEGMENT@0..2
-        NAME_REF@0..2
-          IDENT@0..2 "m1"
-    BANG@2..3 "!"
-    TOKEN_TREE@3..17
-      L_CURLY@3..4 "{"
-      WHITESPACE@4..5 " "
-      LET_KW@5..8 "let"
-      WHITESPACE@8..9 " "
-      IDENT@9..10 "a"
-      WHITESPACE@10..11 " "
-      EQ@11..12 "="
-      WHITESPACE@12..13 " "
-      INT_NUMBER@13..14 "0"
-      SEMICOLON@14..15 ";"
-      WHITESPACE@15..16 " "
-      R_CURLY@16..17 "}"
-  SEMICOLON@17..18 ";"
diff --git a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_macro_let_stmt.rs b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_macro_let_stmt.rs
deleted file mode 100644
index 075f30159b2..00000000000
--- a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_macro_let_stmt.rs
+++ /dev/null
@@ -1 +0,0 @@
-m1!{ let a = 0; };
diff --git a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_macro_unterminated_let_stmt.rast b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_macro_unterminated_let_stmt.rast
deleted file mode 100644
index 81d6df29a5f..00000000000
--- a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_macro_unterminated_let_stmt.rast
+++ /dev/null
@@ -1,21 +0,0 @@
-EXPR_STMT@0..18
-  MACRO_CALL@0..17
-    PATH@0..2
-      PATH_SEGMENT@0..2
-        NAME_REF@0..2
-          IDENT@0..2 "m1"
-    BANG@2..3 "!"
-    TOKEN_TREE@3..17
-      L_CURLY@3..4 "{"
-      WHITESPACE@4..5 " "
-      LET_KW@5..8 "let"
-      WHITESPACE@8..9 " "
-      IDENT@9..10 "a"
-      WHITESPACE@10..11 " "
-      EQ@11..12 "="
-      WHITESPACE@12..13 " "
-      INT_NUMBER@13..14 "0"
-      SEMICOLON@14..15 ";"
-      WHITESPACE@15..16 " "
-      R_CURLY@16..17 "}"
-  SEMICOLON@17..18 ";"
diff --git a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_macro_unterminated_let_stmt.rs b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_macro_unterminated_let_stmt.rs
deleted file mode 100644
index 075f30159b2..00000000000
--- a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_macro_unterminated_let_stmt.rs
+++ /dev/null
@@ -1 +0,0 @@
-m1!{ let a = 0; };
diff --git a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_struct_item.rast b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_struct_item.rast
deleted file mode 100644
index 64c5d296911..00000000000
--- a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_struct_item.rast
+++ /dev/null
@@ -1,22 +0,0 @@
-STRUCT@0..28
-  STRUCT_KW@0..6 "struct"
-  WHITESPACE@6..7 " "
-  NAME@7..10
-    IDENT@7..10 "Foo"
-  WHITESPACE@10..11 " "
-  RECORD_FIELD_LIST@11..28
-    L_CURLY@11..12 "{"
-    WHITESPACE@12..17 "\n    "
-    RECORD_FIELD@17..25
-      NAME@17..20
-        IDENT@17..20 "bar"
-      COLON@20..21 ":"
-      WHITESPACE@21..22 " "
-      PATH_TYPE@22..25
-        PATH@22..25
-          PATH_SEGMENT@22..25
-            NAME_REF@22..25
-              IDENT@22..25 "u32"
-    COMMA@25..26 ","
-    WHITESPACE@26..27 "\n"
-    R_CURLY@27..28 "}"
diff --git a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_struct_item.rs b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_struct_item.rs
deleted file mode 100644
index e5473e3ac8d..00000000000
--- a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_struct_item.rs
+++ /dev/null
@@ -1,3 +0,0 @@
-struct Foo {
-    bar: u32,
-}
diff --git a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_unterminated_fn_call.rast b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_unterminated_fn_call.rast
deleted file mode 100644
index 9089906bcea..00000000000
--- a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_unterminated_fn_call.rast
+++ /dev/null
@@ -1,10 +0,0 @@
-EXPR_STMT@0..5
-  CALL_EXPR@0..5
-    PATH_EXPR@0..3
-      PATH@0..3
-        PATH_SEGMENT@0..3
-          NAME_REF@0..3
-            IDENT@0..3 "foo"
-    ARG_LIST@3..5
-      L_PAREN@3..4 "("
-      R_PAREN@4..5 ")"
diff --git a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_unterminated_fn_call.rs b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_unterminated_fn_call.rs
deleted file mode 100644
index eb28ef4401b..00000000000
--- a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_unterminated_fn_call.rs
+++ /dev/null
@@ -1 +0,0 @@
-foo()
diff --git a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_unterminated_let_stmt.rast b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_unterminated_let_stmt.rast
deleted file mode 100644
index 37663671faf..00000000000
--- a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_unterminated_let_stmt.rast
+++ /dev/null
@@ -1,11 +0,0 @@
-LET_STMT@0..10
-  LET_KW@0..3 "let"
-  WHITESPACE@3..4 " "
-  IDENT_PAT@4..5
-    NAME@4..5
-      IDENT@4..5 "x"
-  WHITESPACE@5..6 " "
-  EQ@6..7 "="
-  WHITESPACE@7..8 " "
-  LITERAL@8..10
-    INT_NUMBER@8..10 "10"
diff --git a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_unterminated_let_stmt.rs b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_unterminated_let_stmt.rs
deleted file mode 100644
index 78364b2a96e..00000000000
--- a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_unterminated_let_stmt.rs
+++ /dev/null
@@ -1 +0,0 @@
-let x = 10
diff --git a/crates/syntax/test_data/parser/fragments/type/err/0000_missing_close.rast b/crates/syntax/test_data/parser/fragments/type/err/0000_missing_close.rast
deleted file mode 100644
index 5df7507e2de..00000000000
--- a/crates/syntax/test_data/parser/fragments/type/err/0000_missing_close.rast
+++ /dev/null
@@ -1 +0,0 @@
-ERROR
diff --git a/crates/syntax/test_data/parser/fragments/type/err/0000_missing_close.rs b/crates/syntax/test_data/parser/fragments/type/err/0000_missing_close.rs
deleted file mode 100644
index caa4d7c0927..00000000000
--- a/crates/syntax/test_data/parser/fragments/type/err/0000_missing_close.rs
+++ /dev/null
@@ -1 +0,0 @@
-Result<Foo, Bar
diff --git a/crates/syntax/test_data/parser/fragments/type/ok/0000_result.rast b/crates/syntax/test_data/parser/fragments/type/ok/0000_result.rast
deleted file mode 100644
index 38c15b5815e..00000000000
--- a/crates/syntax/test_data/parser/fragments/type/ok/0000_result.rast
+++ /dev/null
@@ -1,22 +0,0 @@
-PATH_TYPE@0..16
-  PATH@0..16
-    PATH_SEGMENT@0..16
-      NAME_REF@0..6
-        IDENT@0..6 "Result"
-      GENERIC_ARG_LIST@6..16
-        L_ANGLE@6..7 "<"
-        TYPE_ARG@7..10
-          PATH_TYPE@7..10
-            PATH@7..10
-              PATH_SEGMENT@7..10
-                NAME_REF@7..10
-                  IDENT@7..10 "Foo"
-        COMMA@10..11 ","
-        WHITESPACE@11..12 " "
-        TYPE_ARG@12..15
-          PATH_TYPE@12..15
-            PATH@12..15
-              PATH_SEGMENT@12..15
-                NAME_REF@12..15
-                  IDENT@12..15 "Bar"
-        R_ANGLE@15..16 ">"
diff --git a/crates/syntax/test_data/parser/fragments/type/ok/0000_result.rs b/crates/syntax/test_data/parser/fragments/type/ok/0000_result.rs
deleted file mode 100644
index b50b3bb3bfd..00000000000
--- a/crates/syntax/test_data/parser/fragments/type/ok/0000_result.rs
+++ /dev/null
@@ -1 +0,0 @@
-Result<Foo, Bar>