aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/assists/src/handlers/pull_assignment_up.rs (renamed from crates/assists/src/handlers/extract_assignment.rs)54
-rw-r--r--crates/assists/src/lib.rs8
-rw-r--r--crates/assists/src/tests/generated.rs58
-rw-r--r--crates/hir/src/code_model.rs38
-rw-r--r--crates/hir_ty/Cargo.toml6
-rw-r--r--crates/hir_ty/src/display.rs2
-rw-r--r--crates/ide/src/display/short_label.rs11
-rw-r--r--crates/ide/src/hover.rs268
-rw-r--r--crates/parser/src/grammar.rs4
-rw-r--r--crates/parser/src/lib.rs2
-rw-r--r--crates/rust-analyzer/src/handlers.rs2
-rw-r--r--crates/ssr/src/parsing.rs1
-rw-r--r--crates/ssr/src/tests.rs44
-rw-r--r--crates/syntax/Cargo.toml2
-rw-r--r--crates/syntax/src/lib.rs7
-rw-r--r--crates/syntax/src/tests.rs9
-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.rast69
-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
44 files changed, 598 insertions, 129 deletions
diff --git a/crates/assists/src/handlers/extract_assignment.rs b/crates/assists/src/handlers/pull_assignment_up.rs
index ae99598c0..560d93e10 100644
--- a/crates/assists/src/handlers/extract_assignment.rs
+++ b/crates/assists/src/handlers/pull_assignment_up.rs
@@ -9,9 +9,9 @@ use crate::{
9 AssistId, AssistKind, 9 AssistId, AssistKind,
10}; 10};
11 11
12// Assist: extract_assignment 12// Assist: pull_assignment_up
13// 13//
14// Extracts variable assigment to outside an if or match statement. 14// Extracts variable assignment to outside an if or match statement.
15// 15//
16// ``` 16// ```
17// fn main() { 17// fn main() {
@@ -36,7 +36,7 @@ use crate::{
36// }; 36// };
37// } 37// }
38// ``` 38// ```
39pub(crate) fn extract_assigment(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { 39pub(crate) fn pull_assignment_up(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
40 let assign_expr = ctx.find_node_at_offset::<ast::BinExpr>()?; 40 let assign_expr = ctx.find_node_at_offset::<ast::BinExpr>()?;
41 let name_expr = if assign_expr.op_kind()? == ast::BinOp::Assignment { 41 let name_expr = if assign_expr.op_kind()? == ast::BinOp::Assignment {
42 assign_expr.lhs()? 42 assign_expr.lhs()?
@@ -61,8 +61,8 @@ pub(crate) fn extract_assigment(acc: &mut Assists, ctx: &AssistContext) -> Optio
61 let expr_stmt = make::expr_stmt(new_stmt); 61 let expr_stmt = make::expr_stmt(new_stmt);
62 62
63 acc.add( 63 acc.add(
64 AssistId("extract_assignment", AssistKind::RefactorExtract), 64 AssistId("pull_assignment_up", AssistKind::RefactorExtract),
65 "Extract assignment", 65 "Pull assignment up",
66 old_stmt.syntax().text_range(), 66 old_stmt.syntax().text_range(),
67 move |edit| { 67 move |edit| {
68 edit.replace(old_stmt.syntax().text_range(), format!("{} = {};", name_expr, expr_stmt)); 68 edit.replace(old_stmt.syntax().text_range(), format!("{} = {};", name_expr, expr_stmt));
@@ -104,7 +104,7 @@ fn exprify_if(
104 ast::ElseBranch::Block(exprify_block(block, sema, name)?) 104 ast::ElseBranch::Block(exprify_block(block, sema, name)?)
105 } 105 }
106 ast::ElseBranch::IfExpr(expr) => { 106 ast::ElseBranch::IfExpr(expr) => {
107 mark::hit!(test_extract_assigment_chained_if); 107 mark::hit!(test_pull_assignment_up_chained_if);
108 ast::ElseBranch::IfExpr(ast::IfExpr::cast( 108 ast::ElseBranch::IfExpr(ast::IfExpr::cast(
109 exprify_if(&expr, sema, name)?.syntax().to_owned(), 109 exprify_if(&expr, sema, name)?.syntax().to_owned(),
110 )?) 110 )?)
@@ -144,7 +144,7 @@ fn is_equivalent(
144) -> bool { 144) -> bool {
145 match (expr0, expr1) { 145 match (expr0, expr1) {
146 (ast::Expr::FieldExpr(field_expr0), ast::Expr::FieldExpr(field_expr1)) => { 146 (ast::Expr::FieldExpr(field_expr0), ast::Expr::FieldExpr(field_expr1)) => {
147 mark::hit!(test_extract_assignment_field_assignment); 147 mark::hit!(test_pull_assignment_up_field_assignment);
148 sema.resolve_field(field_expr0) == sema.resolve_field(field_expr1) 148 sema.resolve_field(field_expr0) == sema.resolve_field(field_expr1)
149 } 149 }
150 (ast::Expr::PathExpr(path0), ast::Expr::PathExpr(path1)) => { 150 (ast::Expr::PathExpr(path0), ast::Expr::PathExpr(path1)) => {
@@ -167,9 +167,9 @@ mod tests {
167 use crate::tests::{check_assist, check_assist_not_applicable}; 167 use crate::tests::{check_assist, check_assist_not_applicable};
168 168
169 #[test] 169 #[test]
170 fn test_extract_assignment_if() { 170 fn test_pull_assignment_up_if() {
171 check_assist( 171 check_assist(
172 extract_assigment, 172 pull_assignment_up,
173 r#" 173 r#"
174fn foo() { 174fn foo() {
175 let mut a = 1; 175 let mut a = 1;
@@ -194,9 +194,9 @@ fn foo() {
194 } 194 }
195 195
196 #[test] 196 #[test]
197 fn test_extract_assignment_match() { 197 fn test_pull_assignment_up_match() {
198 check_assist( 198 check_assist(
199 extract_assigment, 199 pull_assignment_up,
200 r#" 200 r#"
201fn foo() { 201fn foo() {
202 let mut a = 1; 202 let mut a = 1;
@@ -233,9 +233,9 @@ fn foo() {
233 } 233 }
234 234
235 #[test] 235 #[test]
236 fn test_extract_assignment_not_last_not_applicable() { 236 fn test_pull_assignment_up_not_last_not_applicable() {
237 check_assist_not_applicable( 237 check_assist_not_applicable(
238 extract_assigment, 238 pull_assignment_up,
239 r#" 239 r#"
240fn foo() { 240fn foo() {
241 let mut a = 1; 241 let mut a = 1;
@@ -251,10 +251,10 @@ fn foo() {
251 } 251 }
252 252
253 #[test] 253 #[test]
254 fn test_extract_assignment_chained_if() { 254 fn test_pull_assignment_up_chained_if() {
255 mark::check!(test_extract_assigment_chained_if); 255 mark::check!(test_pull_assignment_up_chained_if);
256 check_assist( 256 check_assist(
257 extract_assigment, 257 pull_assignment_up,
258 r#" 258 r#"
259fn foo() { 259fn foo() {
260 let mut a = 1; 260 let mut a = 1;
@@ -283,9 +283,9 @@ fn foo() {
283 } 283 }
284 284
285 #[test] 285 #[test]
286 fn test_extract_assigment_retains_stmts() { 286 fn test_pull_assignment_up_retains_stmts() {
287 check_assist( 287 check_assist(
288 extract_assigment, 288 pull_assignment_up,
289 r#" 289 r#"
290fn foo() { 290fn foo() {
291 let mut a = 1; 291 let mut a = 1;
@@ -314,9 +314,9 @@ fn foo() {
314 } 314 }
315 315
316 #[test] 316 #[test]
317 fn extract_assignment_let_stmt_not_applicable() { 317 fn pull_assignment_up_let_stmt_not_applicable() {
318 check_assist_not_applicable( 318 check_assist_not_applicable(
319 extract_assigment, 319 pull_assignment_up,
320 r#" 320 r#"
321fn foo() { 321fn foo() {
322 let mut a = 1; 322 let mut a = 1;
@@ -331,9 +331,9 @@ fn foo() {
331 } 331 }
332 332
333 #[test] 333 #[test]
334 fn extract_assignment_if_missing_assigment_not_applicable() { 334 fn pull_assignment_up_if_missing_assigment_not_applicable() {
335 check_assist_not_applicable( 335 check_assist_not_applicable(
336 extract_assigment, 336 pull_assignment_up,
337 r#" 337 r#"
338fn foo() { 338fn foo() {
339 let mut a = 1; 339 let mut a = 1;
@@ -346,9 +346,9 @@ fn foo() {
346 } 346 }
347 347
348 #[test] 348 #[test]
349 fn extract_assignment_match_missing_assigment_not_applicable() { 349 fn pull_assignment_up_match_missing_assigment_not_applicable() {
350 check_assist_not_applicable( 350 check_assist_not_applicable(
351 extract_assigment, 351 pull_assignment_up,
352 r#" 352 r#"
353fn foo() { 353fn foo() {
354 let mut a = 1; 354 let mut a = 1;
@@ -367,10 +367,10 @@ fn foo() {
367 } 367 }
368 368
369 #[test] 369 #[test]
370 fn test_extract_assignment_field_assignment() { 370 fn test_pull_assignment_up_field_assignment() {
371 mark::check!(test_extract_assignment_field_assignment); 371 mark::check!(test_pull_assignment_up_field_assignment);
372 check_assist( 372 check_assist(
373 extract_assigment, 373 pull_assignment_up,
374 r#" 374 r#"
375struct A(usize); 375struct A(usize);
376 376
diff --git a/crates/assists/src/lib.rs b/crates/assists/src/lib.rs
index 212464f85..01baa65fe 100644
--- a/crates/assists/src/lib.rs
+++ b/crates/assists/src/lib.rs
@@ -116,7 +116,6 @@ mod handlers {
116 mod convert_integer_literal; 116 mod convert_integer_literal;
117 mod early_return; 117 mod early_return;
118 mod expand_glob_import; 118 mod expand_glob_import;
119 mod extract_assignment;
120 mod extract_module_to_file; 119 mod extract_module_to_file;
121 mod extract_struct_from_enum_variant; 120 mod extract_struct_from_enum_variant;
122 mod extract_variable; 121 mod extract_variable;
@@ -125,8 +124,8 @@ mod handlers {
125 mod flip_binexpr; 124 mod flip_binexpr;
126 mod flip_comma; 125 mod flip_comma;
127 mod flip_trait_bound; 126 mod flip_trait_bound;
128 mod generate_derive;
129 mod generate_default_from_enum_variant; 127 mod generate_default_from_enum_variant;
128 mod generate_derive;
130 mod generate_from_impl_for_enum; 129 mod generate_from_impl_for_enum;
131 mod generate_function; 130 mod generate_function;
132 mod generate_impl; 131 mod generate_impl;
@@ -139,6 +138,7 @@ mod handlers {
139 mod merge_match_arms; 138 mod merge_match_arms;
140 mod move_bounds; 139 mod move_bounds;
141 mod move_guard; 140 mod move_guard;
141 mod pull_assignment_up;
142 mod qualify_path; 142 mod qualify_path;
143 mod raw_string; 143 mod raw_string;
144 mod remove_dbg; 144 mod remove_dbg;
@@ -168,7 +168,6 @@ mod handlers {
168 convert_integer_literal::convert_integer_literal, 168 convert_integer_literal::convert_integer_literal,
169 early_return::convert_to_guarded_return, 169 early_return::convert_to_guarded_return,
170 expand_glob_import::expand_glob_import, 170 expand_glob_import::expand_glob_import,
171 extract_assignment::extract_assigment,
172 extract_module_to_file::extract_module_to_file, 171 extract_module_to_file::extract_module_to_file,
173 extract_struct_from_enum_variant::extract_struct_from_enum_variant, 172 extract_struct_from_enum_variant::extract_struct_from_enum_variant,
174 extract_variable::extract_variable, 173 extract_variable::extract_variable,
@@ -177,8 +176,8 @@ mod handlers {
177 flip_binexpr::flip_binexpr, 176 flip_binexpr::flip_binexpr,
178 flip_comma::flip_comma, 177 flip_comma::flip_comma,
179 flip_trait_bound::flip_trait_bound, 178 flip_trait_bound::flip_trait_bound,
180 generate_derive::generate_derive,
181 generate_default_from_enum_variant::generate_default_from_enum_variant, 179 generate_default_from_enum_variant::generate_default_from_enum_variant,
180 generate_derive::generate_derive,
182 generate_from_impl_for_enum::generate_from_impl_for_enum, 181 generate_from_impl_for_enum::generate_from_impl_for_enum,
183 generate_function::generate_function, 182 generate_function::generate_function,
184 generate_impl::generate_impl, 183 generate_impl::generate_impl,
@@ -192,6 +191,7 @@ mod handlers {
192 move_bounds::move_bounds_to_where_clause, 191 move_bounds::move_bounds_to_where_clause,
193 move_guard::move_arm_cond_to_match_guard, 192 move_guard::move_arm_cond_to_match_guard,
194 move_guard::move_guard_to_arm_body, 193 move_guard::move_guard_to_arm_body,
194 pull_assignment_up::pull_assignment_up,
195 qualify_path::qualify_path, 195 qualify_path::qualify_path,
196 raw_string::add_hash, 196 raw_string::add_hash,
197 raw_string::make_usual_string, 197 raw_string::make_usual_string,
diff --git a/crates/assists/src/tests/generated.rs b/crates/assists/src/tests/generated.rs
index b91a816e8..85e3c6742 100644
--- a/crates/assists/src/tests/generated.rs
+++ b/crates/assists/src/tests/generated.rs
@@ -238,35 +238,6 @@ fn qux(bar: Bar, baz: Baz) {}
238} 238}
239 239
240#[test] 240#[test]
241fn doctest_extract_assignment() {
242 check_doc_test(
243 "extract_assignment",
244 r#####"
245fn main() {
246 let mut foo = 6;
247
248 if true {
249 <|>foo = 5;
250 } else {
251 foo = 4;
252 }
253}
254"#####,
255 r#####"
256fn main() {
257 let mut foo = 6;
258
259 foo = if true {
260 5
261 } else {
262 4
263 };
264}
265"#####,
266 )
267}
268
269#[test]
270fn doctest_extract_module_to_file() { 241fn doctest_extract_module_to_file() {
271 check_doc_test( 242 check_doc_test(
272 "extract_module_to_file", 243 "extract_module_to_file",
@@ -767,6 +738,35 @@ fn handle(action: Action) {
767} 738}
768 739
769#[test] 740#[test]
741fn doctest_pull_assignment_up() {
742 check_doc_test(
743 "pull_assignment_up",
744 r#####"
745fn main() {
746 let mut foo = 6;
747
748 if true {
749 <|>foo = 5;
750 } else {
751 foo = 4;
752 }
753}
754"#####,
755 r#####"
756fn main() {
757 let mut foo = 6;
758
759 foo = if true {
760 5
761 } else {
762 4
763 };
764}
765"#####,
766 )
767}
768
769#[test]
770fn doctest_qualify_path() { 770fn doctest_qualify_path() {
771 check_doc_test( 771 check_doc_test(
772 "qualify_path", 772 "qualify_path",
diff --git a/crates/hir/src/code_model.rs b/crates/hir/src/code_model.rs
index 62eccf475..071e553a8 100644
--- a/crates/hir/src/code_model.rs
+++ b/crates/hir/src/code_model.rs
@@ -5,9 +5,7 @@ use arrayvec::ArrayVec;
5use base_db::{CrateDisplayName, CrateId, Edition, FileId}; 5use base_db::{CrateDisplayName, CrateId, Edition, FileId};
6use either::Either; 6use either::Either;
7use hir_def::{ 7use hir_def::{
8 adt::ReprKind, 8 adt::{ReprKind, StructKind, VariantData},
9 adt::StructKind,
10 adt::VariantData,
11 builtin_type::BuiltinType, 9 builtin_type::BuiltinType,
12 expr::{BindingAnnotation, LabelId, Pat, PatId}, 10 expr::{BindingAnnotation, LabelId, Pat, PatId},
13 import_map, 11 import_map,
@@ -31,7 +29,7 @@ use hir_expand::{
31}; 29};
32use hir_ty::{ 30use hir_ty::{
33 autoderef, 31 autoderef,
34 display::{HirDisplayError, HirFormatter}, 32 display::{write_bounds_like_dyn_trait, HirDisplayError, HirFormatter},
35 method_resolution, 33 method_resolution,
36 traits::{FnTrait, Solution, SolutionVariables}, 34 traits::{FnTrait, Solution, SolutionVariables},
37 ApplicationTy, BoundVar, CallableDefId, Canonical, DebruijnIndex, FnSig, GenericPredicate, 35 ApplicationTy, BoundVar, CallableDefId, Canonical, DebruijnIndex, FnSig, GenericPredicate,
@@ -1278,6 +1276,18 @@ impl TypeParam {
1278 } 1276 }
1279 } 1277 }
1280 1278
1279 pub fn trait_bounds(self, db: &dyn HirDatabase) -> Vec<Trait> {
1280 db.generic_predicates_for_param(self.id)
1281 .into_iter()
1282 .filter_map(|pred| match &pred.value {
1283 hir_ty::GenericPredicate::Implemented(trait_ref) => {
1284 Some(Trait::from(trait_ref.trait_))
1285 }
1286 _ => None,
1287 })
1288 .collect()
1289 }
1290
1281 pub fn default(self, db: &dyn HirDatabase) -> Option<Type> { 1291 pub fn default(self, db: &dyn HirDatabase) -> Option<Type> {
1282 let params = db.generic_defaults(self.id.parent); 1292 let params = db.generic_defaults(self.id.parent);
1283 let local_idx = hir_ty::param_idx(db, self.id)?; 1293 let local_idx = hir_ty::param_idx(db, self.id)?;
@@ -1293,6 +1303,20 @@ impl TypeParam {
1293 } 1303 }
1294} 1304}
1295 1305
1306impl HirDisplay for TypeParam {
1307 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
1308 write!(f, "{}", self.name(f.db))?;
1309 let bounds = f.db.generic_predicates_for_param(self.id);
1310 let substs = Substs::type_params(f.db, self.id.parent);
1311 let predicates = bounds.iter().cloned().map(|b| b.subst(&substs)).collect::<Vec<_>>();
1312 if !(predicates.is_empty() || f.omit_verbose_types()) {
1313 write!(f, ": ")?;
1314 write_bounds_like_dyn_trait(&predicates, f)?;
1315 }
1316 Ok(())
1317 }
1318}
1319
1296#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] 1320#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1297pub struct LifetimeParam { 1321pub struct LifetimeParam {
1298 pub(crate) id: LifetimeParamId, 1322 pub(crate) id: LifetimeParamId,
@@ -1331,6 +1355,12 @@ impl ConstParam {
1331 pub fn parent(self, _db: &dyn HirDatabase) -> GenericDef { 1355 pub fn parent(self, _db: &dyn HirDatabase) -> GenericDef {
1332 self.id.parent.into() 1356 self.id.parent.into()
1333 } 1357 }
1358
1359 pub fn ty(self, db: &dyn HirDatabase) -> Type {
1360 let def = self.id.parent;
1361 let krate = def.module(db.upcast()).krate;
1362 Type::new(db, krate, def, db.const_param_ty(self.id))
1363 }
1334} 1364}
1335 1365
1336#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 1366#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
diff --git a/crates/hir_ty/Cargo.toml b/crates/hir_ty/Cargo.toml
index 3d1778590..b0a453961 100644
--- a/crates/hir_ty/Cargo.toml
+++ b/crates/hir_ty/Cargo.toml
@@ -17,9 +17,9 @@ ena = "0.14.0"
17log = "0.4.8" 17log = "0.4.8"
18rustc-hash = "1.1.0" 18rustc-hash = "1.1.0"
19scoped-tls = "1" 19scoped-tls = "1"
20chalk-solve = { version = "0.45", default-features = false } 20chalk-solve = { version = "0.47", default-features = false }
21chalk-ir = "0.45" 21chalk-ir = "0.47"
22chalk-recursive = "0.45" 22chalk-recursive = "0.47"
23 23
24stdx = { path = "../stdx", version = "0.0.0" } 24stdx = { path = "../stdx", version = "0.0.0" }
25hir_def = { path = "../hir_def", version = "0.0.0" } 25hir_def = { path = "../hir_def", version = "0.0.0" }
diff --git a/crates/hir_ty/src/display.rs b/crates/hir_ty/src/display.rs
index 0e827a29e..a54225c18 100644
--- a/crates/hir_ty/src/display.rs
+++ b/crates/hir_ty/src/display.rs
@@ -595,7 +595,7 @@ impl HirDisplay for FnSig {
595 } 595 }
596} 596}
597 597
598fn write_bounds_like_dyn_trait( 598pub fn write_bounds_like_dyn_trait(
599 predicates: &[GenericPredicate], 599 predicates: &[GenericPredicate],
600 f: &mut HirFormatter, 600 f: &mut HirFormatter,
601) -> Result<(), HirDisplayError> { 601) -> Result<(), HirDisplayError> {
diff --git a/crates/ide/src/display/short_label.rs b/crates/ide/src/display/short_label.rs
index ea49d9f97..990f740b8 100644
--- a/crates/ide/src/display/short_label.rs
+++ b/crates/ide/src/display/short_label.rs
@@ -87,6 +87,17 @@ impl ShortLabel for ast::Variant {
87 } 87 }
88} 88}
89 89
90impl ShortLabel for ast::ConstParam {
91 fn short_label(&self) -> Option<String> {
92 let mut buf = "const ".to_owned();
93 buf.push_str(self.name()?.text().as_str());
94 if let Some(type_ref) = self.ty() {
95 format_to!(buf, ": {}", type_ref.syntax());
96 }
97 Some(buf)
98 }
99}
100
90fn short_label_from_ty<T>(node: &T, ty: Option<ast::Type>, prefix: &str) -> Option<String> 101fn short_label_from_ty<T>(node: &T, ty: Option<ast::Type>, prefix: &str) -> Option<String>
91where 102where
92 T: NameOwner + VisibilityOwner, 103 T: NameOwner + VisibilityOwner,
diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs
index 2737c900f..f2ad95cb6 100644
--- a/crates/ide/src/hover.rs
+++ b/crates/ide/src/hover.rs
@@ -70,7 +70,7 @@ impl HoverConfig {
70#[derive(Debug, Clone)] 70#[derive(Debug, Clone)]
71pub enum HoverAction { 71pub enum HoverAction {
72 Runnable(Runnable), 72 Runnable(Runnable),
73 Implementaion(FilePosition), 73 Implementation(FilePosition),
74 GoToType(Vec<HoverGotoTypeData>), 74 GoToType(Vec<HoverGotoTypeData>),
75} 75}
76 76
@@ -116,12 +116,13 @@ pub(crate) fn hover(
116 }; 116 };
117 if let Some(definition) = definition { 117 if let Some(definition) = definition {
118 if let Some(markup) = hover_for_definition(db, definition) { 118 if let Some(markup) = hover_for_definition(db, definition) {
119 let markup = markup.as_str();
119 let markup = if !markdown { 120 let markup = if !markdown {
120 remove_markdown(&markup.as_str()) 121 remove_markdown(markup)
121 } else if links_in_hover { 122 } else if links_in_hover {
122 rewrite_links(db, &markup.as_str(), &definition) 123 rewrite_links(db, markup, &definition)
123 } else { 124 } else {
124 remove_links(&markup.as_str()) 125 remove_links(markup)
125 }; 126 };
126 res.markup = Markup::from(markup); 127 res.markup = Markup::from(markup);
127 if let Some(action) = show_implementations_action(db, definition) { 128 if let Some(action) = show_implementations_action(db, definition) {
@@ -175,22 +176,24 @@ pub(crate) fn hover(
175 176
176fn show_implementations_action(db: &RootDatabase, def: Definition) -> Option<HoverAction> { 177fn show_implementations_action(db: &RootDatabase, def: Definition) -> Option<HoverAction> {
177 fn to_action(nav_target: NavigationTarget) -> HoverAction { 178 fn to_action(nav_target: NavigationTarget) -> HoverAction {
178 HoverAction::Implementaion(FilePosition { 179 HoverAction::Implementation(FilePosition {
179 file_id: nav_target.file_id, 180 file_id: nav_target.file_id,
180 offset: nav_target.focus_or_full_range().start(), 181 offset: nav_target.focus_or_full_range().start(),
181 }) 182 })
182 } 183 }
183 184
184 match def { 185 let adt = match def {
185 Definition::ModuleDef(it) => match it { 186 Definition::ModuleDef(ModuleDef::Trait(it)) => return it.try_to_nav(db).map(to_action),
186 ModuleDef::Adt(Adt::Struct(it)) => Some(to_action(it.try_to_nav(db)?)), 187 Definition::ModuleDef(ModuleDef::Adt(it)) => Some(it),
187 ModuleDef::Adt(Adt::Union(it)) => Some(to_action(it.try_to_nav(db)?)), 188 Definition::SelfType(it) => it.target_ty(db).as_adt(),
188 ModuleDef::Adt(Adt::Enum(it)) => Some(to_action(it.try_to_nav(db)?)),
189 ModuleDef::Trait(it) => Some(to_action(it.try_to_nav(db)?)),
190 _ => None,
191 },
192 _ => None, 189 _ => None,
190 }?;
191 match adt {
192 Adt::Struct(it) => it.try_to_nav(db),
193 Adt::Union(it) => it.try_to_nav(db),
194 Adt::Enum(it) => it.try_to_nav(db),
193 } 195 }
196 .map(to_action)
194} 197}
195 198
196fn runnable_action( 199fn runnable_action(
@@ -225,45 +228,46 @@ fn runnable_action(
225} 228}
226 229
227fn goto_type_action(db: &RootDatabase, def: Definition) -> Option<HoverAction> { 230fn goto_type_action(db: &RootDatabase, def: Definition) -> Option<HoverAction> {
228 match def { 231 let mut targets: Vec<ModuleDef> = Vec::new();
229 Definition::Local(it) => { 232 let mut push_new_def = |item: ModuleDef| {
230 let mut targets: Vec<ModuleDef> = Vec::new(); 233 if !targets.contains(&item) {
231 let mut push_new_def = |item: ModuleDef| { 234 targets.push(item);
232 if !targets.contains(&item) {
233 targets.push(item);
234 }
235 };
236
237 it.ty(db).walk(db, |t| {
238 if let Some(adt) = t.as_adt() {
239 push_new_def(adt.into());
240 } else if let Some(trait_) = t.as_dyn_trait() {
241 push_new_def(trait_.into());
242 } else if let Some(traits) = t.as_impl_traits(db) {
243 traits.into_iter().for_each(|it| push_new_def(it.into()));
244 } else if let Some(trait_) = t.as_associated_type_parent_trait(db) {
245 push_new_def(trait_.into());
246 }
247 });
248
249 let targets = targets
250 .into_iter()
251 .filter_map(|it| {
252 Some(HoverGotoTypeData {
253 mod_path: render_path(
254 db,
255 it.module(db)?,
256 it.name(db).map(|name| name.to_string()),
257 ),
258 nav: it.try_to_nav(db)?,
259 })
260 })
261 .collect();
262
263 Some(HoverAction::GoToType(targets))
264 } 235 }
265 _ => None, 236 };
237
238 if let Definition::TypeParam(it) = def {
239 it.trait_bounds(db).into_iter().for_each(|it| push_new_def(it.into()));
240 } else {
241 let ty = match def {
242 Definition::Local(it) => it.ty(db),
243 Definition::ConstParam(it) => it.ty(db),
244 _ => return None,
245 };
246
247 ty.walk(db, |t| {
248 if let Some(adt) = t.as_adt() {
249 push_new_def(adt.into());
250 } else if let Some(trait_) = t.as_dyn_trait() {
251 push_new_def(trait_.into());
252 } else if let Some(traits) = t.as_impl_traits(db) {
253 traits.into_iter().for_each(|it| push_new_def(it.into()));
254 } else if let Some(trait_) = t.as_associated_type_parent_trait(db) {
255 push_new_def(trait_.into());
256 }
257 });
266 } 258 }
259
260 let targets = targets
261 .into_iter()
262 .filter_map(|it| {
263 Some(HoverGotoTypeData {
264 mod_path: render_path(db, it.module(db)?, it.name(db).map(|name| name.to_string())),
265 nav: it.try_to_nav(db)?,
266 })
267 })
268 .collect();
269
270 Some(HoverAction::GoToType(targets))
267} 271}
268 272
269fn hover_markup( 273fn hover_markup(
@@ -370,10 +374,8 @@ fn hover_for_definition(db: &RootDatabase, def: Definition) -> Option<Markup> {
370 } 374 }
371 Definition::Label(it) => Some(Markup::fenced_block(&it.name(db))), 375 Definition::Label(it) => Some(Markup::fenced_block(&it.name(db))),
372 Definition::LifetimeParam(it) => Some(Markup::fenced_block(&it.name(db))), 376 Definition::LifetimeParam(it) => Some(Markup::fenced_block(&it.name(db))),
373 Definition::TypeParam(_) | Definition::ConstParam(_) => { 377 Definition::TypeParam(type_param) => Some(Markup::fenced_block(&type_param.display(db))),
374 // FIXME: Hover for generic param 378 Definition::ConstParam(it) => from_def_source(db, it, None),
375 None
376 }
377 }; 379 };
378 380
379 fn from_def_source<A, D>(db: &RootDatabase, def: D, mod_path: Option<String>) -> Option<Markup> 381 fn from_def_source<A, D>(db: &RootDatabase, def: D, mod_path: Option<String>) -> Option<Markup>
@@ -1393,7 +1395,7 @@ fn bar() { fo<|>o(); }
1393 r"unsafe trait foo<|>() {}", 1395 r"unsafe trait foo<|>() {}",
1394 expect![[r#" 1396 expect![[r#"
1395 [ 1397 [
1396 Implementaion( 1398 Implementation(
1397 FilePosition { 1399 FilePosition {
1398 file_id: FileId( 1400 file_id: FileId(
1399 0, 1401 0,
@@ -2105,7 +2107,7 @@ fn foo() { let bar = Bar; bar.fo<|>o(); }
2105 r#"trait foo<|>() {}"#, 2107 r#"trait foo<|>() {}"#,
2106 expect![[r#" 2108 expect![[r#"
2107 [ 2109 [
2108 Implementaion( 2110 Implementation(
2109 FilePosition { 2111 FilePosition {
2110 file_id: FileId( 2112 file_id: FileId(
2111 0, 2113 0,
@@ -2124,7 +2126,7 @@ fn foo() { let bar = Bar; bar.fo<|>o(); }
2124 r"struct foo<|>() {}", 2126 r"struct foo<|>() {}",
2125 expect![[r#" 2127 expect![[r#"
2126 [ 2128 [
2127 Implementaion( 2129 Implementation(
2128 FilePosition { 2130 FilePosition {
2129 file_id: FileId( 2131 file_id: FileId(
2130 0, 2132 0,
@@ -2143,7 +2145,7 @@ fn foo() { let bar = Bar; bar.fo<|>o(); }
2143 r#"union foo<|>() {}"#, 2145 r#"union foo<|>() {}"#,
2144 expect![[r#" 2146 expect![[r#"
2145 [ 2147 [
2146 Implementaion( 2148 Implementation(
2147 FilePosition { 2149 FilePosition {
2148 file_id: FileId( 2150 file_id: FileId(
2149 0, 2151 0,
@@ -2162,7 +2164,7 @@ fn foo() { let bar = Bar; bar.fo<|>o(); }
2162 r"enum foo<|>() { A, B }", 2164 r"enum foo<|>() { A, B }",
2163 expect![[r#" 2165 expect![[r#"
2164 [ 2166 [
2165 Implementaion( 2167 Implementation(
2166 FilePosition { 2168 FilePosition {
2167 file_id: FileId( 2169 file_id: FileId(
2168 0, 2170 0,
@@ -2176,6 +2178,25 @@ fn foo() { let bar = Bar; bar.fo<|>o(); }
2176 } 2178 }
2177 2179
2178 #[test] 2180 #[test]
2181 fn test_hover_self_has_impl_action() {
2182 check_actions(
2183 r#"struct foo where Self<|>:;"#,
2184 expect![[r#"
2185 [
2186 Implementation(
2187 FilePosition {
2188 file_id: FileId(
2189 0,
2190 ),
2191 offset: 7,
2192 },
2193 ),
2194 ]
2195 "#]],
2196 );
2197 }
2198
2199 #[test]
2179 fn test_hover_test_has_action() { 2200 fn test_hover_test_has_action() {
2180 check_actions( 2201 check_actions(
2181 r#" 2202 r#"
@@ -3064,6 +3085,71 @@ fn main() { let s<|>t = test().get(); }
3064 } 3085 }
3065 3086
3066 #[test] 3087 #[test]
3088 fn test_hover_const_param_has_goto_type_action() {
3089 check_actions(
3090 r#"
3091struct Bar;
3092struct Foo<const BAR: Bar>;
3093
3094impl<const BAR: Bar> Foo<BAR<|>> {}
3095"#,
3096 expect![[r#"
3097 [
3098 GoToType(
3099 [
3100 HoverGotoTypeData {
3101 mod_path: "test::Bar",
3102 nav: NavigationTarget {
3103 file_id: FileId(
3104 0,
3105 ),
3106 full_range: 0..11,
3107 focus_range: 7..10,
3108 name: "Bar",
3109 kind: Struct,
3110 description: "struct Bar",
3111 },
3112 },
3113 ],
3114 ),
3115 ]
3116 "#]],
3117 );
3118 }
3119
3120 #[test]
3121 fn test_hover_type_param_has_goto_type_action() {
3122 check_actions(
3123 r#"
3124trait Foo {}
3125
3126fn foo<T: Foo>(t: T<|>){}
3127"#,
3128 expect![[r#"
3129 [
3130 GoToType(
3131 [
3132 HoverGotoTypeData {
3133 mod_path: "test::Foo",
3134 nav: NavigationTarget {
3135 file_id: FileId(
3136 0,
3137 ),
3138 full_range: 0..12,
3139 focus_range: 6..9,
3140 name: "Foo",
3141 kind: Trait,
3142 description: "trait Foo",
3143 },
3144 },
3145 ],
3146 ),
3147 ]
3148 "#]],
3149 );
3150 }
3151
3152 #[test]
3067 fn hover_displays_normalized_crate_names() { 3153 fn hover_displays_normalized_crate_names() {
3068 check( 3154 check(
3069 r#" 3155 r#"
@@ -3257,4 +3343,68 @@ fn foo() {
3257 "#]], 3343 "#]],
3258 ); 3344 );
3259 } 3345 }
3346
3347 #[test]
3348 fn hover_type_param() {
3349 check(
3350 r#"
3351struct Foo<T>(T);
3352trait Copy {}
3353trait Clone {}
3354trait Sized {}
3355impl<T: Copy + Clone> Foo<T<|>> where T: Sized {}
3356"#,
3357 expect![[r#"
3358 *T*
3359
3360 ```rust
3361 T: Copy + Clone + Sized
3362 ```
3363 "#]],
3364 );
3365 check(
3366 r#"
3367struct Foo<T>(T);
3368impl<T> Foo<T<|>> {}
3369"#,
3370 expect![[r#"
3371 *T*
3372
3373 ```rust
3374 T
3375 ```
3376 "#]],
3377 );
3378 // lifetimes aren't being substituted yet
3379 check(
3380 r#"
3381struct Foo<T>(T);
3382impl<T: 'static> Foo<T<|>> {}
3383"#,
3384 expect![[r#"
3385 *T*
3386
3387 ```rust
3388 T: {error}
3389 ```
3390 "#]],
3391 );
3392 }
3393
3394 #[test]
3395 fn hover_const_param() {
3396 check(
3397 r#"
3398struct Foo<const LEN: usize>;
3399impl<const LEN: usize> Foo<LEN<|>> {}
3400"#,
3401 expect![[r#"
3402 *LEN*
3403
3404 ```rust
3405 const LEN: usize
3406 ```
3407 "#]],
3408 );
3409 }
3260} 3410}
diff --git a/crates/parser/src/grammar.rs b/crates/parser/src/grammar.rs
index 63cc90027..bb9ffea8b 100644
--- a/crates/parser/src/grammar.rs
+++ b/crates/parser/src/grammar.rs
@@ -66,6 +66,10 @@ pub(crate) mod fragments {
66 expressions::stmt(p, expressions::StmtWithSemi::No) 66 expressions::stmt(p, expressions::StmtWithSemi::No)
67 } 67 }
68 68
69 pub(crate) fn stmt_optional_semi(p: &mut Parser) {
70 expressions::stmt(p, expressions::StmtWithSemi::Optional)
71 }
72
69 pub(crate) fn opt_visibility(p: &mut Parser) { 73 pub(crate) fn opt_visibility(p: &mut Parser) {
70 let _ = super::opt_visibility(p); 74 let _ = super::opt_visibility(p);
71 } 75 }
diff --git a/crates/parser/src/lib.rs b/crates/parser/src/lib.rs
index 811e740f9..9dfe63028 100644
--- a/crates/parser/src/lib.rs
+++ b/crates/parser/src/lib.rs
@@ -88,6 +88,7 @@ pub enum FragmentKind {
88 Path, 88 Path,
89 Expr, 89 Expr,
90 Statement, 90 Statement,
91 StatementOptionalSemi,
91 Type, 92 Type,
92 Pattern, 93 Pattern,
93 Item, 94 Item,
@@ -118,6 +119,7 @@ pub fn parse_fragment(
118 FragmentKind::Visibility => grammar::fragments::opt_visibility, 119 FragmentKind::Visibility => grammar::fragments::opt_visibility,
119 FragmentKind::MetaItem => grammar::fragments::meta_item, 120 FragmentKind::MetaItem => grammar::fragments::meta_item,
120 FragmentKind::Statement => grammar::fragments::stmt, 121 FragmentKind::Statement => grammar::fragments::stmt,
122 FragmentKind::StatementOptionalSemi => grammar::fragments::stmt_optional_semi,
121 FragmentKind::Items => grammar::fragments::macro_items, 123 FragmentKind::Items => grammar::fragments::macro_items,
122 FragmentKind::Statements => grammar::fragments::macro_stmts, 124 FragmentKind::Statements => grammar::fragments::macro_stmts,
123 FragmentKind::Attr => grammar::fragments::attr, 125 FragmentKind::Attr => grammar::fragments::attr,
diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs
index dd486070b..c21ca044a 100644
--- a/crates/rust-analyzer/src/handlers.rs
+++ b/crates/rust-analyzer/src/handlers.rs
@@ -1648,7 +1648,7 @@ fn prepare_hover_actions(
1648 actions 1648 actions
1649 .iter() 1649 .iter()
1650 .filter_map(|it| match it { 1650 .filter_map(|it| match it {
1651 HoverAction::Implementaion(position) => show_impl_command_link(snap, position), 1651 HoverAction::Implementation(position) => show_impl_command_link(snap, position),
1652 HoverAction::Runnable(r) => runnable_action_links(snap, file_id, r.clone()), 1652 HoverAction::Runnable(r) => runnable_action_links(snap, file_id, r.clone()),
1653 HoverAction::GoToType(targets) => goto_type_action_links(snap, targets), 1653 HoverAction::GoToType(targets) => goto_type_action_links(snap, targets),
1654 }) 1654 })
diff --git a/crates/ssr/src/parsing.rs b/crates/ssr/src/parsing.rs
index f3b084baf..289affe90 100644
--- a/crates/ssr/src/parsing.rs
+++ b/crates/ssr/src/parsing.rs
@@ -78,6 +78,7 @@ impl ParsedRule {
78 builder.try_add(ast::Item::parse(&raw_pattern), raw_template.map(ast::Item::parse)); 78 builder.try_add(ast::Item::parse(&raw_pattern), raw_template.map(ast::Item::parse));
79 builder.try_add(ast::Path::parse(&raw_pattern), raw_template.map(ast::Path::parse)); 79 builder.try_add(ast::Path::parse(&raw_pattern), raw_template.map(ast::Path::parse));
80 builder.try_add(ast::Pat::parse(&raw_pattern), raw_template.map(ast::Pat::parse)); 80 builder.try_add(ast::Pat::parse(&raw_pattern), raw_template.map(ast::Pat::parse));
81 builder.try_add(ast::Stmt::parse(&raw_pattern), raw_template.map(ast::Stmt::parse));
81 builder.build() 82 builder.build()
82 } 83 }
83} 84}
diff --git a/crates/ssr/src/tests.rs b/crates/ssr/src/tests.rs
index 63131f6ca..c4149a849 100644
--- a/crates/ssr/src/tests.rs
+++ b/crates/ssr/src/tests.rs
@@ -160,6 +160,50 @@ fn assert_match_failure_reason(pattern: &str, code: &str, snippet: &str, expecte
160} 160}
161 161
162#[test] 162#[test]
163fn ssr_let_stmt_in_macro_match() {
164 assert_matches(
165 "let a = 0",
166 r#"
167 macro_rules! m1 { ($a:stmt) => {$a}; }
168 fn f() {m1!{ let a = 0 };}"#,
169 // FIXME: Whitespace is not part of the matched block
170 &["leta=0"],
171 );
172}
173
174#[test]
175fn ssr_let_stmt_in_fn_match() {
176 assert_matches("let $a = 10;", "fn main() { let x = 10; x }", &["let x = 10;"]);
177 assert_matches("let $a = $b;", "fn main() { let x = 10; x }", &["let x = 10;"]);
178}
179
180#[test]
181fn ssr_block_expr_match() {
182 assert_matches("{ let $a = $b; }", "fn main() { let x = 10; }", &["{ let x = 10; }"]);
183 assert_matches("{ let $a = $b; $c }", "fn main() { let x = 10; x }", &["{ let x = 10; x }"]);
184}
185
186#[test]
187fn ssr_let_stmt_replace() {
188 // Pattern and template with trailing semicolon
189 assert_ssr_transform(
190 "let $a = $b; ==>> let $a = 11;",
191 "fn main() { let x = 10; x }",
192 expect![["fn main() { let x = 11; x }"]],
193 );
194}
195
196#[test]
197fn ssr_let_stmt_replace_expr() {
198 // Trailing semicolon should be dropped from the new expression
199 assert_ssr_transform(
200 "let $a = $b; ==>> $b",
201 "fn main() { let x = 10; }",
202 expect![["fn main() { 10 }"]],
203 );
204}
205
206#[test]
163fn ssr_function_to_method() { 207fn ssr_function_to_method() {
164 assert_ssr_transform( 208 assert_ssr_transform(
165 "my_function($a, $b) ==>> ($a).my_method($b)", 209 "my_function($a, $b) ==>> ($a).my_method($b)",
diff --git a/crates/syntax/Cargo.toml b/crates/syntax/Cargo.toml
index 181077944..cfeaed9e6 100644
--- a/crates/syntax/Cargo.toml
+++ b/crates/syntax/Cargo.toml
@@ -13,7 +13,7 @@ doctest = false
13[dependencies] 13[dependencies]
14itertools = "0.10.0" 14itertools = "0.10.0"
15rowan = "0.10.0" 15rowan = "0.10.0"
16rustc_lexer = { version = "695.0.0", package = "rustc-ap-rustc_lexer" } 16rustc_lexer = { version = "697.0.0", package = "rustc-ap-rustc_lexer" }
17rustc-hash = "1.1.0" 17rustc-hash = "1.1.0"
18arrayvec = "0.5.1" 18arrayvec = "0.5.1"
19once_cell = "1.3.1" 19once_cell = "1.3.1"
diff --git a/crates/syntax/src/lib.rs b/crates/syntax/src/lib.rs
index 4d272f367..da151e328 100644
--- a/crates/syntax/src/lib.rs
+++ b/crates/syntax/src/lib.rs
@@ -212,6 +212,13 @@ impl ast::Attr {
212 } 212 }
213} 213}
214 214
215impl ast::Stmt {
216 /// Returns `text`, parsed as statement, but only if it has no errors.
217 pub fn parse(text: &str) -> Result<Self, ()> {
218 parsing::parse_text_fragment(text, parser::FragmentKind::StatementOptionalSemi)
219 }
220}
221
215/// Matches a `SyntaxNode` against an `ast` type. 222/// Matches a `SyntaxNode` against an `ast` type.
216/// 223///
217/// # Example: 224/// # Example:
diff --git a/crates/syntax/src/tests.rs b/crates/syntax/src/tests.rs
index 8c217dfe0..9d3433c9d 100644
--- a/crates/syntax/src/tests.rs
+++ b/crates/syntax/src/tests.rs
@@ -103,6 +103,15 @@ fn type_parser_tests() {
103} 103}
104 104
105#[test] 105#[test]
106fn stmt_parser_tests() {
107 fragment_parser_dir_test(
108 &["parser/fragments/stmt/ok"],
109 &["parser/fragments/stmt/err"],
110 crate::ast::Stmt::parse,
111 );
112}
113
114#[test]
106fn parser_fuzz_tests() { 115fn parser_fuzz_tests() {
107 for (_, text) in collect_rust_files(&test_data_dir(), &["parser/fuzz-failures"]) { 116 for (_, text) in collect_rust_files(&test_data_dir(), &["parser/fuzz-failures"]) {
108 fuzz::check_parser(&text) 117 fuzz::check_parser(&text)
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
new file mode 100644
index 000000000..5df7507e2
--- /dev/null
+++ b/crates/syntax/test_data/parser/fragments/stmt/err/0000_attr.rast
@@ -0,0 +1 @@
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
new file mode 100644
index 000000000..988df0705
--- /dev/null
+++ b/crates/syntax/test_data/parser/fragments/stmt/err/0000_attr.rs
@@ -0,0 +1 @@
#[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
new file mode 100644
index 000000000..5df7507e2
--- /dev/null
+++ b/crates/syntax/test_data/parser/fragments/stmt/err/0000_multiple_stmts.rast
@@ -0,0 +1 @@
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
new file mode 100644
index 000000000..7e3b2fd49
--- /dev/null
+++ b/crates/syntax/test_data/parser/fragments/stmt/err/0000_multiple_stmts.rs
@@ -0,0 +1 @@
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
new file mode 100644
index 000000000..5df7507e2
--- /dev/null
+++ b/crates/syntax/test_data/parser/fragments/stmt/err/0000_open_parenthesis.rast
@@ -0,0 +1 @@
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
new file mode 100644
index 000000000..2d06f3766
--- /dev/null
+++ b/crates/syntax/test_data/parser/fragments/stmt/err/0000_open_parenthesis.rs
@@ -0,0 +1 @@
(
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
new file mode 100644
index 000000000..5df7507e2
--- /dev/null
+++ b/crates/syntax/test_data/parser/fragments/stmt/err/0000_semicolon.rast
@@ -0,0 +1 @@
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
new file mode 100644
index 000000000..092bc2b04
--- /dev/null
+++ b/crates/syntax/test_data/parser/fragments/stmt/err/0000_semicolon.rs
@@ -0,0 +1 @@
;
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
new file mode 100644
index 000000000..5df7507e2
--- /dev/null
+++ b/crates/syntax/test_data/parser/fragments/stmt/err/0000_unterminated_expr.rast
@@ -0,0 +1 @@
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
new file mode 100644
index 000000000..ca49acb07
--- /dev/null
+++ b/crates/syntax/test_data/parser/fragments/stmt/err/0000_unterminated_expr.rs
@@ -0,0 +1 @@
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
new file mode 100644
index 000000000..274fdf16d
--- /dev/null
+++ b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_expr.rast
@@ -0,0 +1,9 @@
1[email protected]
2 [email protected]
3 [email protected]
4 [email protected] "1"
5 [email protected] " "
6 [email protected] "+"
7 [email protected] " "
8 [email protected]
9 [email protected] "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
new file mode 100644
index 000000000..8d2f0971e
--- /dev/null
+++ b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_expr.rs
@@ -0,0 +1 @@
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
new file mode 100644
index 000000000..6c946091f
--- /dev/null
+++ b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_expr_block.rast
@@ -0,0 +1,69 @@
1[email protected]
2 [email protected]
3 [email protected] "{"
4 [email protected] "\n "
5 [email protected]
6 [email protected] "let"
7 [email protected] " "
8 [email protected]
9 [email protected]
10 [email protected] "x"
11 [email protected] " "
12 [email protected] "="
13 [email protected] " "
14 [email protected]
15 [email protected]
16 [email protected]
17 [email protected]
18 [email protected]
19 [email protected] "foo"
20 [email protected]
21 [email protected] "("
22 [email protected] ")"
23 [email protected] ";"
24 [email protected] "\n "
25 [email protected]
26 [email protected] "let"
27 [email protected] " "
28 [email protected]
29 [email protected]
30 [email protected] "y"
31 [email protected] " "
32 [email protected] "="
33 [email protected] " "
34 [email protected]
35 [email protected]
36 [email protected]
37 [email protected]
38 [email protected]
39 [email protected] "bar"
40 [email protected]
41 [email protected] "("
42 [email protected] ")"
43 [email protected] ";"
44 [email protected] "\n "
45 [email protected]
46 [email protected]
47 [email protected]
48 [email protected]
49 [email protected]
50 [email protected] "Ok"
51 [email protected]
52 [email protected] "("
53 [email protected]
54 [email protected]
55 [email protected]
56 [email protected]
57 [email protected]
58 [email protected] "x"
59 [email protected] " "
60 [email protected] "+"
61 [email protected] " "
62 [email protected]
63 [email protected]
64 [email protected]
65 [email protected]
66 [email protected] "y"
67 [email protected] ")"
68 [email protected] "\n"
69 [email protected] "}"
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
new file mode 100644
index 000000000..ffa5c1e66
--- /dev/null
+++ b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_expr_block.rs
@@ -0,0 +1,5 @@
1{
2 let x = foo();
3 let y = bar();
4 Ok(x + y)
5}
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
new file mode 100644
index 000000000..8c186da93
--- /dev/null
+++ b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_fn_call.rast
@@ -0,0 +1,11 @@
1[email protected]
2 [email protected]
3 [email protected]
4 [email protected]
5 [email protected]
6 [email protected]
7 [email protected] "foo"
8 [email protected]
9 [email protected] "("
10 [email protected] ")"
11 [email protected] ";"
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
new file mode 100644
index 000000000..a280f9a5c
--- /dev/null
+++ b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_fn_call.rs
@@ -0,0 +1 @@
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
new file mode 100644
index 000000000..8ab38da21
--- /dev/null
+++ b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_let_stmt.rast
@@ -0,0 +1,12 @@
1[email protected]
2 [email protected] "let"
3 [email protected] " "
4 [email protected]
5 [email protected]
6 [email protected] "x"
7 [email protected] " "
8 [email protected] "="
9 [email protected] " "
10 [email protected]
11 [email protected] "10"
12 [email protected] ";"
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
new file mode 100644
index 000000000..de8a7f1fc
--- /dev/null
+++ b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_let_stmt.rs
@@ -0,0 +1 @@
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
new file mode 100644
index 000000000..81d6df29a
--- /dev/null
+++ b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_macro_let_stmt.rast
@@ -0,0 +1,21 @@
1[email protected]
2 [email protected]
3 [email protected]
4 [email protected]
5 [email protected]
6 [email protected] "m1"
7 [email protected] "!"
8 [email protected]
9 [email protected] "{"
10 [email protected] " "
11 [email protected] "let"
12 [email protected] " "
13 [email protected] "a"
14 [email protected] " "
15 [email protected] "="
16 [email protected] " "
17 [email protected] "0"
18 [email protected] ";"
19 [email protected] " "
20 [email protected] "}"
21 [email protected] ";"
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
new file mode 100644
index 000000000..075f30159
--- /dev/null
+++ b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_macro_let_stmt.rs
@@ -0,0 +1 @@
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
new file mode 100644
index 000000000..81d6df29a
--- /dev/null
+++ b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_macro_unterminated_let_stmt.rast
@@ -0,0 +1,21 @@
1[email protected]
2 [email protected]
3 [email protected]
4 [email protected]
5 [email protected]
6 [email protected] "m1"
7 [email protected] "!"
8 [email protected]
9 [email protected] "{"
10 [email protected] " "
11 [email protected] "let"
12 [email protected] " "
13 [email protected] "a"
14 [email protected] " "
15 [email protected] "="
16 [email protected] " "
17 [email protected] "0"
18 [email protected] ";"
19 [email protected] " "
20 [email protected] "}"
21 [email protected] ";"
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
new file mode 100644
index 000000000..075f30159
--- /dev/null
+++ b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_macro_unterminated_let_stmt.rs
@@ -0,0 +1 @@
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
new file mode 100644
index 000000000..64c5d2969
--- /dev/null
+++ b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_struct_item.rast
@@ -0,0 +1,22 @@
1[email protected]
2 [email protected] "struct"
3 [email protected] " "
4 [email protected]
5 [email protected] "Foo"
6 [email protected] " "
7 [email protected]
8 [email protected] "{"
9 [email protected] "\n "
10 [email protected]
11 [email protected]
12 [email protected] "bar"
13 [email protected] ":"
14 [email protected] " "
15 [email protected]
16 [email protected]
17 [email protected]
18 [email protected]
19 [email protected] "u32"
20 [email protected] ","
21 [email protected] "\n"
22 [email protected] "}"
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
new file mode 100644
index 000000000..e5473e3ac
--- /dev/null
+++ b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_struct_item.rs
@@ -0,0 +1,3 @@
1struct Foo {
2 bar: u32,
3}
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
new file mode 100644
index 000000000..9089906bc
--- /dev/null
+++ b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_unterminated_fn_call.rast
@@ -0,0 +1,10 @@
1[email protected]
2 [email protected]
3 [email protected]
4 [email protected]
5 [email protected]
6 [email protected]
7 [email protected] "foo"
8 [email protected]
9 [email protected] "("
10 [email protected] ")"
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
new file mode 100644
index 000000000..eb28ef440
--- /dev/null
+++ b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_unterminated_fn_call.rs
@@ -0,0 +1 @@
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
new file mode 100644
index 000000000..37663671f
--- /dev/null
+++ b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_unterminated_let_stmt.rast
@@ -0,0 +1,11 @@
1[email protected]
2 [email protected] "let"
3 [email protected] " "
4 [email protected]
5 [email protected]
6 [email protected] "x"
7 [email protected] " "
8 [email protected] "="
9 [email protected] " "
10 [email protected]
11 [email protected] "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
new file mode 100644
index 000000000..78364b2a9
--- /dev/null
+++ b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_unterminated_let_stmt.rs
@@ -0,0 +1 @@
let x = 10