aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.travis.yml2
-rw-r--r--crates/ra_assists/src/assists/apply_demorgan.rs102
-rw-r--r--crates/ra_assists/src/lib.rs2
-rw-r--r--crates/ra_hir/src/ty/infer.rs12
-rw-r--r--crates/ra_hir/src/ty/tests.rs63
-rw-r--r--crates/ra_parser/src/grammar/expressions.rs25
-rw-r--r--crates/ra_parser/src/grammar/expressions/atom.rs10
-rw-r--r--crates/ra_syntax/src/grammar.ron2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0031_while_expr.rs1
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0031_while_expr.txt34
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0064_if_expr.rs1
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0064_if_expr.txt43
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0071_match_expr.rs2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0071_match_expr.txt65
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0080_postfix_range.rs6
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0080_postfix_range.txt107
-rw-r--r--docs/user/README.md16
-rw-r--r--docs/user/features.md14
18 files changed, 449 insertions, 58 deletions
diff --git a/.travis.yml b/.travis.yml
index c198cc5f7..d4cf71ab5 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -58,7 +58,7 @@ deploy:
58 provider: pages 58 provider: pages
59 skip-cleanup: true 59 skip-cleanup: true
60 github-token: $DOCS_TOKEN # Set in the settings page of your repository, as a secure variable 60 github-token: $DOCS_TOKEN # Set in the settings page of your repository, as a secure variable
61 keep-history: true 61 keep-history: false
62 local-dir: target/website/ 62 local-dir: target/website/
63 on: 63 on:
64 branch: master 64 branch: master
diff --git a/crates/ra_assists/src/assists/apply_demorgan.rs b/crates/ra_assists/src/assists/apply_demorgan.rs
new file mode 100644
index 000000000..5f2b0dd18
--- /dev/null
+++ b/crates/ra_assists/src/assists/apply_demorgan.rs
@@ -0,0 +1,102 @@
1//! This contains the functions associated with the demorgan assist.
2//! This assist transforms boolean expressions of the form `!a || !b` into
3//! `!(a && b)`.
4use hir::db::HirDatabase;
5use ra_syntax::ast::{self, AstNode};
6use ra_syntax::SyntaxNode;
7
8use crate::{Assist, AssistCtx, AssistId};
9
10/// Assist for applying demorgan's law
11///
12/// This transforms expressions of the form `!l || !r` into `!(l && r)`.
13/// This also works with `&&`. This assist can only be applied with the cursor
14/// on either `||` or `&&`, with both operands being a negation of some kind.
15/// This means something of the form `!x` or `x != y`.
16pub(crate) fn apply_demorgan(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
17 let expr = ctx.node_at_offset::<ast::BinExpr>()?;
18 let op = expr.op_kind()?;
19 let op_range = expr.op_token()?.text_range();
20 let opposite_op = opposite_logic_op(op)?;
21 let cursor_in_range = ctx.frange.range.is_subrange(&op_range);
22 if !cursor_in_range {
23 return None;
24 }
25 let lhs = expr.lhs()?.syntax().clone();
26 let lhs_range = lhs.text_range();
27 let rhs = expr.rhs()?.syntax().clone();
28 let rhs_range = rhs.text_range();
29 let not_lhs = undo_negation(lhs)?;
30 let not_rhs = undo_negation(rhs)?;
31
32 ctx.add_action(AssistId("apply_demorgan"), "apply demorgan's law", |edit| {
33 edit.target(op_range);
34 edit.replace(op_range, opposite_op);
35 edit.replace(lhs_range, format!("!({}", not_lhs));
36 edit.replace(rhs_range, format!("{})", not_rhs));
37 });
38 ctx.build()
39}
40
41// Return the opposite text for a given logical operator, if it makes sense
42fn opposite_logic_op(kind: ast::BinOp) -> Option<&'static str> {
43 match kind {
44 ast::BinOp::BooleanOr => Some("&&"),
45 ast::BinOp::BooleanAnd => Some("||"),
46 _ => None,
47 }
48}
49
50// This function tries to undo unary negation, or inequality
51fn undo_negation(node: SyntaxNode) -> Option<String> {
52 match ast::Expr::cast(node)? {
53 ast::Expr::BinExpr(bin) => match bin.op_kind()? {
54 ast::BinOp::NegatedEqualityTest => {
55 let lhs = bin.lhs()?.syntax().text();
56 let rhs = bin.rhs()?.syntax().text();
57 Some(format!("{} == {}", lhs, rhs))
58 }
59 _ => None,
60 },
61 ast::Expr::PrefixExpr(pe) => match pe.op_kind()? {
62 ast::PrefixOp::Not => {
63 let child = pe.expr()?.syntax().text();
64 Some(String::from(child))
65 }
66 _ => None,
67 },
68 _ => None,
69 }
70}
71
72#[cfg(test)]
73mod tests {
74 use super::*;
75
76 use crate::helpers::{check_assist, check_assist_not_applicable};
77
78 #[test]
79 fn demorgan_turns_and_into_or() {
80 check_assist(apply_demorgan, "fn f() { !x &&<|> !x }", "fn f() { !(x ||<|> x) }")
81 }
82
83 #[test]
84 fn demorgan_turns_or_into_and() {
85 check_assist(apply_demorgan, "fn f() { !x ||<|> !x }", "fn f() { !(x &&<|> x) }")
86 }
87
88 #[test]
89 fn demorgan_removes_inequality() {
90 check_assist(apply_demorgan, "fn f() { x != x ||<|> !x }", "fn f() { !(x == x &&<|> x) }")
91 }
92
93 #[test]
94 fn demorgan_doesnt_apply_with_cursor_not_on_op() {
95 check_assist_not_applicable(apply_demorgan, "fn f() { <|> !x || !x }")
96 }
97
98 #[test]
99 fn demorgan_doesnt_apply_when_operands_arent_negated_already() {
100 check_assist_not_applicable(apply_demorgan, "fn f() { x ||<|> x }")
101 }
102}
diff --git a/crates/ra_assists/src/lib.rs b/crates/ra_assists/src/lib.rs
index 91b2a1dce..d2376c475 100644
--- a/crates/ra_assists/src/lib.rs
+++ b/crates/ra_assists/src/lib.rs
@@ -92,6 +92,7 @@ mod assists {
92 mod add_derive; 92 mod add_derive;
93 mod add_explicit_type; 93 mod add_explicit_type;
94 mod add_impl; 94 mod add_impl;
95 mod apply_demorgan;
95 mod flip_comma; 96 mod flip_comma;
96 mod flip_binexpr; 97 mod flip_binexpr;
97 mod change_visibility; 98 mod change_visibility;
@@ -113,6 +114,7 @@ mod assists {
113 add_derive::add_derive, 114 add_derive::add_derive,
114 add_explicit_type::add_explicit_type, 115 add_explicit_type::add_explicit_type,
115 add_impl::add_impl, 116 add_impl::add_impl,
117 apply_demorgan::apply_demorgan,
116 change_visibility::change_visibility, 118 change_visibility::change_visibility,
117 fill_match_arms::fill_match_arms, 119 fill_match_arms::fill_match_arms,
118 merge_match_arms::merge_match_arms, 120 merge_match_arms::merge_match_arms,
diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs
index 2e4a489a0..ca9aefc42 100644
--- a/crates/ra_hir/src/ty/infer.rs
+++ b/crates/ra_hir/src/ty/infer.rs
@@ -1602,6 +1602,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
1602 tail: Option<ExprId>, 1602 tail: Option<ExprId>,
1603 expected: &Expectation, 1603 expected: &Expectation,
1604 ) -> Ty { 1604 ) -> Ty {
1605 let mut diverges = false;
1605 for stmt in statements { 1606 for stmt in statements {
1606 match stmt { 1607 match stmt {
1607 Statement::Let { pat, type_ref, initializer } => { 1608 Statement::Let { pat, type_ref, initializer } => {
@@ -1623,16 +1624,23 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
1623 self.infer_pat(*pat, &ty, BindingMode::default()); 1624 self.infer_pat(*pat, &ty, BindingMode::default());
1624 } 1625 }
1625 Statement::Expr(expr) => { 1626 Statement::Expr(expr) => {
1626 self.infer_expr(*expr, &Expectation::none()); 1627 if let ty_app!(TypeCtor::Never) = self.infer_expr(*expr, &Expectation::none()) {
1628 diverges = true;
1629 }
1627 } 1630 }
1628 } 1631 }
1629 } 1632 }
1630 1633
1631 if let Some(expr) = tail { 1634 let ty = if let Some(expr) = tail {
1632 self.infer_expr_coerce(expr, expected) 1635 self.infer_expr_coerce(expr, expected)
1633 } else { 1636 } else {
1634 self.coerce(&Ty::unit(), &expected.ty); 1637 self.coerce(&Ty::unit(), &expected.ty);
1635 Ty::unit() 1638 Ty::unit()
1639 };
1640 if diverges {
1641 Ty::simple(TypeCtor::Never)
1642 } else {
1643 ty
1636 } 1644 }
1637 } 1645 }
1638 1646
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs
index 171aead18..25dad81eb 100644
--- a/crates/ra_hir/src/ty/tests.rs
+++ b/crates/ra_hir/src/ty/tests.rs
@@ -263,7 +263,7 @@ fn test(a: u32, b: isize, c: !, d: &str) {
263 [17; 18) 'b': isize 263 [17; 18) 'b': isize
264 [27; 28) 'c': ! 264 [27; 28) 'c': !
265 [33; 34) 'd': &str 265 [33; 34) 'd': &str
266 [42; 121) '{ ...f32; }': () 266 [42; 121) '{ ...f32; }': !
267 [48; 49) 'a': u32 267 [48; 49) 'a': u32
268 [55; 56) 'b': isize 268 [55; 56) 'b': isize
269 [62; 63) 'c': ! 269 [62; 63) 'c': !
@@ -1026,6 +1026,67 @@ fn main(foo: Foo) {
1026} 1026}
1027 1027
1028#[test] 1028#[test]
1029fn infer_if_match_with_return() {
1030 assert_snapshot!(
1031 infer(r#"
1032fn foo() {
1033 let _x1 = if true {
1034 1
1035 } else {
1036 return;
1037 };
1038 let _x2 = if true {
1039 2
1040 } else {
1041 return
1042 };
1043 let _x3 = match true {
1044 true => 3,
1045 _ => {
1046 return;
1047 }
1048 };
1049 let _x4 = match true {
1050 true => 4,
1051 _ => return
1052 };
1053}"#),
1054 @r###"
1055 [10; 323) '{ ... }; }': ()
1056 [20; 23) '_x1': i32
1057 [26; 80) 'if tru... }': i32
1058 [29; 33) 'true': bool
1059 [34; 51) '{ ... }': i32
1060 [44; 45) '1': i32
1061 [57; 80) '{ ... }': !
1062 [67; 73) 'return': !
1063 [90; 93) '_x2': i32
1064 [96; 149) 'if tru... }': i32
1065 [99; 103) 'true': bool
1066 [104; 121) '{ ... }': i32
1067 [114; 115) '2': i32
1068 [127; 149) '{ ... }': !
1069 [137; 143) 'return': !
1070 [159; 162) '_x3': i32
1071 [165; 247) 'match ... }': i32
1072 [171; 175) 'true': bool
1073 [186; 190) 'true': bool
1074 [194; 195) '3': i32
1075 [205; 206) '_': bool
1076 [210; 241) '{ ... }': !
1077 [224; 230) 'return': !
1078 [257; 260) '_x4': i32
1079 [263; 320) 'match ... }': i32
1080 [269; 273) 'true': bool
1081 [284; 288) 'true': bool
1082 [292; 293) '4': i32
1083 [303; 304) '_': bool
1084 [308; 314) 'return': !
1085 "###
1086 )
1087}
1088
1089#[test]
1029fn infer_inherent_method() { 1090fn infer_inherent_method() {
1030 assert_snapshot!( 1091 assert_snapshot!(
1031 infer(r#" 1092 infer(r#"
diff --git a/crates/ra_parser/src/grammar/expressions.rs b/crates/ra_parser/src/grammar/expressions.rs
index 413ecb278..74b23e2f7 100644
--- a/crates/ra_parser/src/grammar/expressions.rs
+++ b/crates/ra_parser/src/grammar/expressions.rs
@@ -335,7 +335,13 @@ fn lhs(p: &mut Parser, r: Restrictions) -> Option<(CompletedMarker, BlockLike)>
335 // } 335 // }
336 // 336 //
337 let (lhs, blocklike) = atom::atom_expr(p, r)?; 337 let (lhs, blocklike) = atom::atom_expr(p, r)?;
338 return Some(postfix_expr(p, lhs, blocklike, !(r.prefer_stmt && blocklike.is_block()))); 338 return Some(postfix_expr(
339 p,
340 lhs,
341 blocklike,
342 !(r.prefer_stmt && blocklike.is_block()),
343 r.forbid_structs,
344 ));
339 } 345 }
340 }; 346 };
341 expr_bp(p, r, 255); 347 expr_bp(p, r, 255);
@@ -350,6 +356,7 @@ fn postfix_expr(
350 // `while true {break}; ();` 356 // `while true {break}; ();`
351 mut block_like: BlockLike, 357 mut block_like: BlockLike,
352 mut allow_calls: bool, 358 mut allow_calls: bool,
359 forbid_structs: bool,
353) -> (CompletedMarker, BlockLike) { 360) -> (CompletedMarker, BlockLike) {
354 loop { 361 loop {
355 lhs = match p.current() { 362 lhs = match p.current() {
@@ -363,7 +370,7 @@ fn postfix_expr(
363 // } 370 // }
364 T!['('] if allow_calls => call_expr(p, lhs), 371 T!['('] if allow_calls => call_expr(p, lhs),
365 T!['['] if allow_calls => index_expr(p, lhs), 372 T!['['] if allow_calls => index_expr(p, lhs),
366 T![.] => match postfix_dot_expr(p, lhs) { 373 T![.] => match postfix_dot_expr(p, lhs, forbid_structs) {
367 Ok(it) => it, 374 Ok(it) => it,
368 Err(it) => { 375 Err(it) => {
369 lhs = it; 376 lhs = it;
@@ -382,6 +389,7 @@ fn postfix_expr(
382 fn postfix_dot_expr( 389 fn postfix_dot_expr(
383 p: &mut Parser, 390 p: &mut Parser,
384 lhs: CompletedMarker, 391 lhs: CompletedMarker,
392 forbid_structs: bool,
385 ) -> Result<CompletedMarker, CompletedMarker> { 393 ) -> Result<CompletedMarker, CompletedMarker> {
386 assert!(p.at(T![.])); 394 assert!(p.at(T![.]));
387 if p.nth(1) == IDENT && (p.nth(2) == T!['('] || p.nth_at(2, T![::])) { 395 if p.nth(1) == IDENT && (p.nth(2) == T!['('] || p.nth_at(2, T![::])) {
@@ -402,10 +410,17 @@ fn postfix_expr(
402 } 410 }
403 411
404 // test postfix_range 412 // test postfix_range
405 // fn foo() { let x = 1..; } 413 // fn foo() {
406 for &(op, la) in [(T![..=], 3), (T![..], 2)].iter() { 414 // let x = 1..;
415 // match 1.. { _ => () };
416 // match a.b()..S { _ => () };
417 // }
418 for &(op, la) in &[(T![..=], 3), (T![..], 2)] {
407 if p.at(op) { 419 if p.at(op) {
408 return if EXPR_FIRST.contains(p.nth(la)) { 420 let next_token = p.nth(la);
421 let has_trailing_expression =
422 !(forbid_structs && next_token == T!['{']) && EXPR_FIRST.contains(next_token);
423 return if has_trailing_expression {
409 Err(lhs) 424 Err(lhs)
410 } else { 425 } else {
411 let m = lhs.precede(p); 426 let m = lhs.precede(p);
diff --git a/crates/ra_parser/src/grammar/expressions/atom.rs b/crates/ra_parser/src/grammar/expressions/atom.rs
index a52bdb3ea..7454005c4 100644
--- a/crates/ra_parser/src/grammar/expressions/atom.rs
+++ b/crates/ra_parser/src/grammar/expressions/atom.rs
@@ -121,11 +121,7 @@ pub(super) fn atom_expr(p: &mut Parser, r: Restrictions) -> Option<(CompletedMar
121 // break; 121 // break;
122 // } 122 // }
123 // } 123 // }
124 if r.forbid_structs { 124 block_expr(p, None)
125 return None;
126 } else {
127 block_expr(p, None)
128 }
129 } 125 }
130 T![return] => return_expr(p), 126 T![return] => return_expr(p),
131 T![continue] => continue_expr(p), 127 T![continue] => continue_expr(p),
@@ -261,6 +257,7 @@ fn lambda_expr(p: &mut Parser) -> CompletedMarker {
261// if true {} else {}; 257// if true {} else {};
262// if true {} else if false {} else {}; 258// if true {} else if false {} else {};
263// if S {}; 259// if S {};
260// if { true } { } else { };
264// } 261// }
265fn if_expr(p: &mut Parser) -> CompletedMarker { 262fn if_expr(p: &mut Parser) -> CompletedMarker {
266 assert!(p.at(T![if])); 263 assert!(p.at(T![if]));
@@ -309,6 +306,7 @@ fn loop_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker {
309// fn foo() { 306// fn foo() {
310// while true {}; 307// while true {};
311// while let Some(x) = it.next() {}; 308// while let Some(x) = it.next() {};
309// while { true } {};
312// } 310// }
313fn while_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker { 311fn while_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker {
314 assert!(p.at(T![while])); 312 assert!(p.at(T![while]));
@@ -356,6 +354,8 @@ fn cond(p: &mut Parser) {
356// fn foo() { 354// fn foo() {
357// match () { }; 355// match () { };
358// match S {}; 356// match S {};
357// match { } { _ => () };
358// match { S {} } {};
359// } 359// }
360fn match_expr(p: &mut Parser) -> CompletedMarker { 360fn match_expr(p: &mut Parser) -> CompletedMarker {
361 assert!(p.at(T![match])); 361 assert!(p.at(T![match]));
diff --git a/crates/ra_syntax/src/grammar.ron b/crates/ra_syntax/src/grammar.ron
index 5f7d8c3bf..25e6f64ce 100644
--- a/crates/ra_syntax/src/grammar.ron
+++ b/crates/ra_syntax/src/grammar.ron
@@ -1,5 +1,5 @@
1// Stores definitions which must be used in multiple places 1// Stores definitions which must be used in multiple places
2// See `cargo gen-syntax` (defined in crates/tools/src/main.rs) 2// See `cargo gen-syntax` (defined in crates/ra_tools/src/main.rs)
3Grammar( 3Grammar(
4 punct: [ 4 punct: [
5 (";", "SEMI"), 5 (";", "SEMI"),
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0031_while_expr.rs b/crates/ra_syntax/test_data/parser/inline/ok/0031_while_expr.rs
index 293046a04..2f8188160 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0031_while_expr.rs
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0031_while_expr.rs
@@ -1,4 +1,5 @@
1fn foo() { 1fn foo() {
2 while true {}; 2 while true {};
3 while let Some(x) = it.next() {}; 3 while let Some(x) = it.next() {};
4 while { true } {};
4} 5}
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0031_while_expr.txt b/crates/ra_syntax/test_data/parser/inline/ok/0031_while_expr.txt
index 9b43d624c..a6e14a114 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0031_while_expr.txt
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0031_while_expr.txt
@@ -1,5 +1,5 @@
1SOURCE_FILE@[0; 70) 1SOURCE_FILE@[0; 93)
2 FN_DEF@[0; 69) 2 FN_DEF@[0; 92)
3 FN_KW@[0; 2) "fn" 3 FN_KW@[0; 2) "fn"
4 WHITESPACE@[2; 3) " " 4 WHITESPACE@[2; 3) " "
5 NAME@[3; 6) 5 NAME@[3; 6)
@@ -8,8 +8,8 @@ SOURCE_FILE@[0; 70)
8 L_PAREN@[6; 7) "(" 8 L_PAREN@[6; 7) "("
9 R_PAREN@[7; 8) ")" 9 R_PAREN@[7; 8) ")"
10 WHITESPACE@[8; 9) " " 10 WHITESPACE@[8; 9) " "
11 BLOCK_EXPR@[9; 69) 11 BLOCK_EXPR@[9; 92)
12 BLOCK@[9; 69) 12 BLOCK@[9; 92)
13 L_CURLY@[9; 10) "{" 13 L_CURLY@[9; 10) "{"
14 WHITESPACE@[10; 15) "\n " 14 WHITESPACE@[10; 15) "\n "
15 EXPR_STMT@[15; 29) 15 EXPR_STMT@[15; 29)
@@ -64,6 +64,26 @@ SOURCE_FILE@[0; 70)
64 L_CURLY@[64; 65) "{" 64 L_CURLY@[64; 65) "{"
65 R_CURLY@[65; 66) "}" 65 R_CURLY@[65; 66) "}"
66 SEMI@[66; 67) ";" 66 SEMI@[66; 67) ";"
67 WHITESPACE@[67; 68) "\n" 67 WHITESPACE@[67; 72) "\n "
68 R_CURLY@[68; 69) "}" 68 EXPR_STMT@[72; 90)
69 WHITESPACE@[69; 70) "\n" 69 WHILE_EXPR@[72; 89)
70 WHILE_KW@[72; 77) "while"
71 WHITESPACE@[77; 78) " "
72 CONDITION@[78; 86)
73 BLOCK_EXPR@[78; 86)
74 BLOCK@[78; 86)
75 L_CURLY@[78; 79) "{"
76 WHITESPACE@[79; 80) " "
77 LITERAL@[80; 84)
78 TRUE_KW@[80; 84) "true"
79 WHITESPACE@[84; 85) " "
80 R_CURLY@[85; 86) "}"
81 WHITESPACE@[86; 87) " "
82 BLOCK_EXPR@[87; 89)
83 BLOCK@[87; 89)
84 L_CURLY@[87; 88) "{"
85 R_CURLY@[88; 89) "}"
86 SEMI@[89; 90) ";"
87 WHITESPACE@[90; 91) "\n"
88 R_CURLY@[91; 92) "}"
89 WHITESPACE@[92; 93) "\n"
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0064_if_expr.rs b/crates/ra_syntax/test_data/parser/inline/ok/0064_if_expr.rs
index 4b0d9af89..40f227ba3 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0064_if_expr.rs
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0064_if_expr.rs
@@ -3,4 +3,5 @@ fn foo() {
3 if true {} else {}; 3 if true {} else {};
4 if true {} else if false {} else {}; 4 if true {} else if false {} else {};
5 if S {}; 5 if S {};
6 if { true } { } else { };
6} 7}
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0064_if_expr.txt b/crates/ra_syntax/test_data/parser/inline/ok/0064_if_expr.txt
index 14ea91fd2..2ace3c8ee 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0064_if_expr.txt
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0064_if_expr.txt
@@ -1,5 +1,5 @@
1SOURCE_FILE@[0; 107) 1SOURCE_FILE@[0; 137)
2 FN_DEF@[0; 106) 2 FN_DEF@[0; 136)
3 FN_KW@[0; 2) "fn" 3 FN_KW@[0; 2) "fn"
4 WHITESPACE@[2; 3) " " 4 WHITESPACE@[2; 3) " "
5 NAME@[3; 6) 5 NAME@[3; 6)
@@ -8,8 +8,8 @@ SOURCE_FILE@[0; 107)
8 L_PAREN@[6; 7) "(" 8 L_PAREN@[6; 7) "("
9 R_PAREN@[7; 8) ")" 9 R_PAREN@[7; 8) ")"
10 WHITESPACE@[8; 9) " " 10 WHITESPACE@[8; 9) " "
11 BLOCK_EXPR@[9; 106) 11 BLOCK_EXPR@[9; 136)
12 BLOCK@[9; 106) 12 BLOCK@[9; 136)
13 L_CURLY@[9; 10) "{" 13 L_CURLY@[9; 10) "{"
14 WHITESPACE@[10; 15) "\n " 14 WHITESPACE@[10; 15) "\n "
15 EXPR_STMT@[15; 26) 15 EXPR_STMT@[15; 26)
@@ -98,6 +98,35 @@ SOURCE_FILE@[0; 107)
98 L_CURLY@[101; 102) "{" 98 L_CURLY@[101; 102) "{"
99 R_CURLY@[102; 103) "}" 99 R_CURLY@[102; 103) "}"
100 SEMI@[103; 104) ";" 100 SEMI@[103; 104) ";"
101 WHITESPACE@[104; 105) "\n" 101 WHITESPACE@[104; 109) "\n "
102 R_CURLY@[105; 106) "}" 102 EXPR_STMT@[109; 134)
103 WHITESPACE@[106; 107) "\n" 103 IF_EXPR@[109; 133)
104 IF_KW@[109; 111) "if"
105 WHITESPACE@[111; 112) " "
106 CONDITION@[112; 120)
107 BLOCK_EXPR@[112; 120)
108 BLOCK@[112; 120)
109 L_CURLY@[112; 113) "{"
110 WHITESPACE@[113; 114) " "
111 LITERAL@[114; 118)
112 TRUE_KW@[114; 118) "true"
113 WHITESPACE@[118; 119) " "
114 R_CURLY@[119; 120) "}"
115 WHITESPACE@[120; 121) " "
116 BLOCK_EXPR@[121; 124)
117 BLOCK@[121; 124)
118 L_CURLY@[121; 122) "{"
119 WHITESPACE@[122; 123) " "
120 R_CURLY@[123; 124) "}"
121 WHITESPACE@[124; 125) " "
122 ELSE_KW@[125; 129) "else"
123 WHITESPACE@[129; 130) " "
124 BLOCK_EXPR@[130; 133)
125 BLOCK@[130; 133)
126 L_CURLY@[130; 131) "{"
127 WHITESPACE@[131; 132) " "
128 R_CURLY@[132; 133) "}"
129 SEMI@[133; 134) ";"
130 WHITESPACE@[134; 135) "\n"
131 R_CURLY@[135; 136) "}"
132 WHITESPACE@[136; 137) "\n"
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0071_match_expr.rs b/crates/ra_syntax/test_data/parser/inline/ok/0071_match_expr.rs
index c9205dfa3..c4021dc10 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0071_match_expr.rs
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0071_match_expr.rs
@@ -1,4 +1,6 @@
1fn foo() { 1fn foo() {
2 match () { }; 2 match () { };
3 match S {}; 3 match S {};
4 match { } { _ => () };
5 match { S {} } {};
4} 6}
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0071_match_expr.txt b/crates/ra_syntax/test_data/parser/inline/ok/0071_match_expr.txt
index f62b6c6d5..0af668056 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0071_match_expr.txt
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0071_match_expr.txt
@@ -1,5 +1,5 @@
1SOURCE_FILE@[0; 47) 1SOURCE_FILE@[0; 97)
2 FN_DEF@[0; 46) 2 FN_DEF@[0; 96)
3 FN_KW@[0; 2) "fn" 3 FN_KW@[0; 2) "fn"
4 WHITESPACE@[2; 3) " " 4 WHITESPACE@[2; 3) " "
5 NAME@[3; 6) 5 NAME@[3; 6)
@@ -8,8 +8,8 @@ SOURCE_FILE@[0; 47)
8 L_PAREN@[6; 7) "(" 8 L_PAREN@[6; 7) "("
9 R_PAREN@[7; 8) ")" 9 R_PAREN@[7; 8) ")"
10 WHITESPACE@[8; 9) " " 10 WHITESPACE@[8; 9) " "
11 BLOCK_EXPR@[9; 46) 11 BLOCK_EXPR@[9; 96)
12 BLOCK@[9; 46) 12 BLOCK@[9; 96)
13 L_CURLY@[9; 10) "{" 13 L_CURLY@[9; 10) "{"
14 WHITESPACE@[10; 15) "\n " 14 WHITESPACE@[10; 15) "\n "
15 EXPR_STMT@[15; 28) 15 EXPR_STMT@[15; 28)
@@ -40,6 +40,57 @@ SOURCE_FILE@[0; 47)
40 L_CURLY@[41; 42) "{" 40 L_CURLY@[41; 42) "{"
41 R_CURLY@[42; 43) "}" 41 R_CURLY@[42; 43) "}"
42 SEMI@[43; 44) ";" 42 SEMI@[43; 44) ";"
43 WHITESPACE@[44; 45) "\n" 43 WHITESPACE@[44; 49) "\n "
44 R_CURLY@[45; 46) "}" 44 EXPR_STMT@[49; 71)
45 WHITESPACE@[46; 47) "\n" 45 MATCH_EXPR@[49; 70)
46 MATCH_KW@[49; 54) "match"
47 WHITESPACE@[54; 55) " "
48 BLOCK_EXPR@[55; 58)
49 BLOCK@[55; 58)
50 L_CURLY@[55; 56) "{"
51 WHITESPACE@[56; 57) " "
52 R_CURLY@[57; 58) "}"
53 WHITESPACE@[58; 59) " "
54 MATCH_ARM_LIST@[59; 70)
55 L_CURLY@[59; 60) "{"
56 WHITESPACE@[60; 61) " "
57 MATCH_ARM@[61; 68)
58 PLACEHOLDER_PAT@[61; 62)
59 UNDERSCORE@[61; 62) "_"
60 WHITESPACE@[62; 63) " "
61 FAT_ARROW@[63; 65) "=>"
62 WHITESPACE@[65; 66) " "
63 TUPLE_EXPR@[66; 68)
64 L_PAREN@[66; 67) "("
65 R_PAREN@[67; 68) ")"
66 WHITESPACE@[68; 69) " "
67 R_CURLY@[69; 70) "}"
68 SEMI@[70; 71) ";"
69 WHITESPACE@[71; 76) "\n "
70 EXPR_STMT@[76; 94)
71 MATCH_EXPR@[76; 93)
72 MATCH_KW@[76; 81) "match"
73 WHITESPACE@[81; 82) " "
74 BLOCK_EXPR@[82; 90)
75 BLOCK@[82; 90)
76 L_CURLY@[82; 83) "{"
77 WHITESPACE@[83; 84) " "
78 RECORD_LIT@[84; 88)
79 PATH@[84; 85)
80 PATH_SEGMENT@[84; 85)
81 NAME_REF@[84; 85)
82 IDENT@[84; 85) "S"
83 WHITESPACE@[85; 86) " "
84 RECORD_FIELD_LIST@[86; 88)
85 L_CURLY@[86; 87) "{"
86 R_CURLY@[87; 88) "}"
87 WHITESPACE@[88; 89) " "
88 R_CURLY@[89; 90) "}"
89 WHITESPACE@[90; 91) " "
90 MATCH_ARM_LIST@[91; 93)
91 L_CURLY@[91; 92) "{"
92 R_CURLY@[92; 93) "}"
93 SEMI@[93; 94) ";"
94 WHITESPACE@[94; 95) "\n"
95 R_CURLY@[95; 96) "}"
96 WHITESPACE@[96; 97) "\n"
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0080_postfix_range.rs b/crates/ra_syntax/test_data/parser/inline/ok/0080_postfix_range.rs
index c39fe8e68..e7b7cfc6b 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0080_postfix_range.rs
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0080_postfix_range.rs
@@ -1 +1,5 @@
1fn foo() { let x = 1..; } 1fn foo() {
2 let x = 1..;
3 match 1.. { _ => () };
4 match a.b()..S { _ => () };
5}
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0080_postfix_range.txt b/crates/ra_syntax/test_data/parser/inline/ok/0080_postfix_range.txt
index f3c292f5e..9f8a6b0f6 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0080_postfix_range.txt
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0080_postfix_range.txt
@@ -1,5 +1,5 @@
1SOURCE_FILE@[0; 26) 1SOURCE_FILE@[0; 89)
2 FN_DEF@[0; 25) 2 FN_DEF@[0; 88)
3 FN_KW@[0; 2) "fn" 3 FN_KW@[0; 2) "fn"
4 WHITESPACE@[2; 3) " " 4 WHITESPACE@[2; 3) " "
5 NAME@[3; 6) 5 NAME@[3; 6)
@@ -8,24 +8,89 @@ SOURCE_FILE@[0; 26)
8 L_PAREN@[6; 7) "(" 8 L_PAREN@[6; 7) "("
9 R_PAREN@[7; 8) ")" 9 R_PAREN@[7; 8) ")"
10 WHITESPACE@[8; 9) " " 10 WHITESPACE@[8; 9) " "
11 BLOCK_EXPR@[9; 25) 11 BLOCK_EXPR@[9; 88)
12 BLOCK@[9; 25) 12 BLOCK@[9; 88)
13 L_CURLY@[9; 10) "{" 13 L_CURLY@[9; 10) "{"
14 WHITESPACE@[10; 11) " " 14 WHITESPACE@[10; 15) "\n "
15 LET_STMT@[11; 23) 15 LET_STMT@[15; 27)
16 LET_KW@[11; 14) "let" 16 LET_KW@[15; 18) "let"
17 WHITESPACE@[14; 15) " "
18 BIND_PAT@[15; 16)
19 NAME@[15; 16)
20 IDENT@[15; 16) "x"
21 WHITESPACE@[16; 17) " "
22 EQ@[17; 18) "="
23 WHITESPACE@[18; 19) " " 17 WHITESPACE@[18; 19) " "
24 RANGE_EXPR@[19; 22) 18 BIND_PAT@[19; 20)
25 LITERAL@[19; 20) 19 NAME@[19; 20)
26 INT_NUMBER@[19; 20) "1" 20 IDENT@[19; 20) "x"
27 DOTDOT@[20; 22) ".." 21 WHITESPACE@[20; 21) " "
28 SEMI@[22; 23) ";" 22 EQ@[21; 22) "="
29 WHITESPACE@[23; 24) " " 23 WHITESPACE@[22; 23) " "
30 R_CURLY@[24; 25) "}" 24 RANGE_EXPR@[23; 26)
31 WHITESPACE@[25; 26) "\n" 25 LITERAL@[23; 24)
26 INT_NUMBER@[23; 24) "1"
27 DOTDOT@[24; 26) ".."
28 SEMI@[26; 27) ";"
29 WHITESPACE@[27; 32) "\n "
30 EXPR_STMT@[32; 54)
31 MATCH_EXPR@[32; 53)
32 MATCH_KW@[32; 37) "match"
33 WHITESPACE@[37; 38) " "
34 RANGE_EXPR@[38; 41)
35 LITERAL@[38; 39)
36 INT_NUMBER@[38; 39) "1"
37 DOTDOT@[39; 41) ".."
38 WHITESPACE@[41; 42) " "
39 MATCH_ARM_LIST@[42; 53)
40 L_CURLY@[42; 43) "{"
41 WHITESPACE@[43; 44) " "
42 MATCH_ARM@[44; 51)
43 PLACEHOLDER_PAT@[44; 45)
44 UNDERSCORE@[44; 45) "_"
45 WHITESPACE@[45; 46) " "
46 FAT_ARROW@[46; 48) "=>"
47 WHITESPACE@[48; 49) " "
48 TUPLE_EXPR@[49; 51)
49 L_PAREN@[49; 50) "("
50 R_PAREN@[50; 51) ")"
51 WHITESPACE@[51; 52) " "
52 R_CURLY@[52; 53) "}"
53 SEMI@[53; 54) ";"
54 WHITESPACE@[54; 59) "\n "
55 EXPR_STMT@[59; 86)
56 MATCH_EXPR@[59; 85)
57 MATCH_KW@[59; 64) "match"
58 WHITESPACE@[64; 65) " "
59 RANGE_EXPR@[65; 73)
60 METHOD_CALL_EXPR@[65; 70)
61 PATH_EXPR@[65; 66)
62 PATH@[65; 66)
63 PATH_SEGMENT@[65; 66)
64 NAME_REF@[65; 66)
65 IDENT@[65; 66) "a"
66 DOT@[66; 67) "."
67 NAME_REF@[67; 68)
68 IDENT@[67; 68) "b"
69 ARG_LIST@[68; 70)
70 L_PAREN@[68; 69) "("
71 R_PAREN@[69; 70) ")"
72 DOTDOT@[70; 72) ".."
73 PATH_EXPR@[72; 73)
74 PATH@[72; 73)
75 PATH_SEGMENT@[72; 73)
76 NAME_REF@[72; 73)
77 IDENT@[72; 73) "S"
78 WHITESPACE@[73; 74) " "
79 MATCH_ARM_LIST@[74; 85)
80 L_CURLY@[74; 75) "{"
81 WHITESPACE@[75; 76) " "
82 MATCH_ARM@[76; 83)
83 PLACEHOLDER_PAT@[76; 77)
84 UNDERSCORE@[76; 77) "_"
85 WHITESPACE@[77; 78) " "
86 FAT_ARROW@[78; 80) "=>"
87 WHITESPACE@[80; 81) " "
88 TUPLE_EXPR@[81; 83)
89 L_PAREN@[81; 82) "("
90 R_PAREN@[82; 83) ")"
91 WHITESPACE@[83; 84) " "
92 R_CURLY@[84; 85) "}"
93 SEMI@[85; 86) ";"
94 WHITESPACE@[86; 87) "\n"
95 R_CURLY@[87; 88) "}"
96 WHITESPACE@[88; 89) "\n"
diff --git a/docs/user/README.md b/docs/user/README.md
index 9d03cad1c..44d6ee739 100644
--- a/docs/user/README.md
+++ b/docs/user/README.md
@@ -116,6 +116,22 @@ to load path and require it in `init.el`
116[coc-vim-conf]: https://github.com/neoclide/coc.nvim/#example-vim-configuration 116[coc-vim-conf]: https://github.com/neoclide/coc.nvim/#example-vim-configuration
117[coc-rust-analyzer]: https://github.com/fannheyward/coc-rust-analyzer 117[coc-rust-analyzer]: https://github.com/fannheyward/coc-rust-analyzer
118 118
119## Vim and NeoVim Alternative
120
121* Install LanguageClient-neovim by following the instructions [here][lang-client-neovim]
122 - No extra run-time is required as this server is written in Rust
123 - The github project wiki has extra tips on configuration
124
125* Configure by adding this to your vim/neovim config file (replacing the existing rust specific line if it exists):
126
127```
128let g:LanguageClient_serverCommands = {
129\ 'rust': ['ra_lsp_server'],
130\ }
131```
132
133[lang-client-neovim]: https://github.com/autozimu/LanguageClient-neovim
134
119 135
120## Sublime Text 3 136## Sublime Text 3
121 137
diff --git a/docs/user/features.md b/docs/user/features.md
index eb81cba26..0ce8f577b 100644
--- a/docs/user/features.md
+++ b/docs/user/features.md
@@ -166,6 +166,20 @@ impl Foo for S {
166} 166}
167``` 167```
168 168
169- Apply [De Morgan's law](https://en.wikipedia.org/wiki/De_Morgan%27s_laws)
170
171```rust
172// before:
173fn example(x: bool) -> bool {
174 !x || !x
175}
176
177// after:
178fn example(x: bool) -> bool {
179 !(x && x)
180}
181```
182
169- Import path 183- Import path
170 184
171```rust 185```rust