aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_hir/src/marks.rs1
-rw-r--r--crates/ra_hir/src/ty/infer.rs99
-rw-r--r--crates/ra_hir/src/ty/tests.rs54
-rw-r--r--crates/ra_parser/src/grammar/expressions.rs1
-rw-r--r--crates/ra_parser/src/grammar/expressions/atom.rs30
-rw-r--r--crates/ra_syntax/tests/data/parser/err/0032_match_arms_inner_attrs.txt52
-rw-r--r--crates/ra_syntax/tests/data/parser/err/0033_match_arms_outer_attrs.txt28
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0121_match_arms_outer_attributes.txt156
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0048_compound_assignment.rs17
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0048_compound_assignment.txt200
10 files changed, 488 insertions, 150 deletions
diff --git a/crates/ra_hir/src/marks.rs b/crates/ra_hir/src/marks.rs
index bbf57004d..5b6400042 100644
--- a/crates/ra_hir/src/marks.rs
+++ b/crates/ra_hir/src/marks.rs
@@ -8,4 +8,5 @@ test_utils::marks!(
8 glob_enum 8 glob_enum
9 glob_across_crates 9 glob_across_crates
10 std_prelude 10 std_prelude
11 match_ergonomics_ref
11); 12);
diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs
index c9a5bc7a1..735cdecb9 100644
--- a/crates/ra_hir/src/ty/infer.rs
+++ b/crates/ra_hir/src/ty/infer.rs
@@ -63,6 +63,30 @@ enum ExprOrPatId {
63 63
64impl_froms!(ExprOrPatId: ExprId, PatId); 64impl_froms!(ExprOrPatId: ExprId, PatId);
65 65
66/// Binding modes inferred for patterns.
67/// https://doc.rust-lang.org/reference/patterns.html#binding-modes
68#[derive(Copy, Clone, Debug, Eq, PartialEq)]
69enum BindingMode {
70 Move,
71 Ref(Mutability),
72}
73
74impl BindingMode {
75 pub fn convert(annotation: &BindingAnnotation) -> BindingMode {
76 match annotation {
77 BindingAnnotation::Unannotated | BindingAnnotation::Mutable => BindingMode::Move,
78 BindingAnnotation::Ref => BindingMode::Ref(Mutability::Shared),
79 BindingAnnotation::RefMut => BindingMode::Ref(Mutability::Mut),
80 }
81 }
82}
83
84impl Default for BindingMode {
85 fn default() -> Self {
86 BindingMode::Move
87 }
88}
89
66/// The result of type inference: A mapping from expressions and patterns to types. 90/// The result of type inference: A mapping from expressions and patterns to types.
67#[derive(Clone, PartialEq, Eq, Debug)] 91#[derive(Clone, PartialEq, Eq, Debug)]
68pub struct InferenceResult { 92pub struct InferenceResult {
@@ -530,6 +554,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
530 path: Option<&Path>, 554 path: Option<&Path>,
531 subpats: &[PatId], 555 subpats: &[PatId],
532 expected: &Ty, 556 expected: &Ty,
557 default_bm: BindingMode,
533 ) -> Ty { 558 ) -> Ty {
534 let (ty, def) = self.resolve_variant(path); 559 let (ty, def) = self.resolve_variant(path);
535 560
@@ -542,13 +567,19 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
542 .and_then(|d| d.field(self.db, &Name::tuple_field_name(i))) 567 .and_then(|d| d.field(self.db, &Name::tuple_field_name(i)))
543 .map_or(Ty::Unknown, |field| field.ty(self.db)) 568 .map_or(Ty::Unknown, |field| field.ty(self.db))
544 .subst(&substs); 569 .subst(&substs);
545 self.infer_pat(subpat, &expected_ty); 570 self.infer_pat(subpat, &expected_ty, default_bm);
546 } 571 }
547 572
548 ty 573 ty
549 } 574 }
550 575
551 fn infer_struct_pat(&mut self, path: Option<&Path>, subpats: &[FieldPat], expected: &Ty) -> Ty { 576 fn infer_struct_pat(
577 &mut self,
578 path: Option<&Path>,
579 subpats: &[FieldPat],
580 expected: &Ty,
581 default_bm: BindingMode,
582 ) -> Ty {
552 let (ty, def) = self.resolve_variant(path); 583 let (ty, def) = self.resolve_variant(path);
553 584
554 self.unify(&ty, expected); 585 self.unify(&ty, expected);
@@ -559,15 +590,45 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
559 let matching_field = def.and_then(|it| it.field(self.db, &subpat.name)); 590 let matching_field = def.and_then(|it| it.field(self.db, &subpat.name));
560 let expected_ty = 591 let expected_ty =
561 matching_field.map_or(Ty::Unknown, |field| field.ty(self.db)).subst(&substs); 592 matching_field.map_or(Ty::Unknown, |field| field.ty(self.db)).subst(&substs);
562 self.infer_pat(subpat.pat, &expected_ty); 593 self.infer_pat(subpat.pat, &expected_ty, default_bm);
563 } 594 }
564 595
565 ty 596 ty
566 } 597 }
567 598
568 fn infer_pat(&mut self, pat: PatId, expected: &Ty) -> Ty { 599 fn infer_pat(&mut self, pat: PatId, mut expected: &Ty, mut default_bm: BindingMode) -> Ty {
569 let body = Arc::clone(&self.body); // avoid borrow checker problem 600 let body = Arc::clone(&self.body); // avoid borrow checker problem
570 601
602 let is_non_ref_pat = match &body[pat] {
603 Pat::Tuple(..)
604 | Pat::TupleStruct { .. }
605 | Pat::Struct { .. }
606 | Pat::Range { .. }
607 | Pat::Slice { .. } => true,
608 // TODO: Path/Lit might actually evaluate to ref, but inference is unimplemented.
609 Pat::Path(..) | Pat::Lit(..) => true,
610 Pat::Wild | Pat::Bind { .. } | Pat::Ref { .. } | Pat::Missing => false,
611 };
612 if is_non_ref_pat {
613 while let Ty::Ref(inner, mutability) = expected {
614 expected = inner;
615 default_bm = match default_bm {
616 BindingMode::Move => BindingMode::Ref(*mutability),
617 BindingMode::Ref(Mutability::Shared) => BindingMode::Ref(Mutability::Shared),
618 BindingMode::Ref(Mutability::Mut) => BindingMode::Ref(*mutability),
619 }
620 }
621 } else if let Pat::Ref { .. } = &body[pat] {
622 tested_by!(match_ergonomics_ref);
623 // When you encounter a `&pat` pattern, reset to Move.
624 // This is so that `w` is by value: `let (_, &w) = &(1, &2);`
625 default_bm = BindingMode::Move;
626 }
627
628 // Lose mutability.
629 let default_bm = default_bm;
630 let expected = expected;
631
571 let ty = match &body[pat] { 632 let ty = match &body[pat] {
572 Pat::Tuple(ref args) => { 633 Pat::Tuple(ref args) => {
573 let expectations = match *expected { 634 let expectations = match *expected {
@@ -579,7 +640,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
579 let inner_tys = args 640 let inner_tys = args
580 .iter() 641 .iter()
581 .zip(expectations_iter) 642 .zip(expectations_iter)
582 .map(|(&pat, ty)| self.infer_pat(pat, ty)) 643 .map(|(&pat, ty)| self.infer_pat(pat, ty, default_bm))
583 .collect::<Vec<_>>() 644 .collect::<Vec<_>>()
584 .into(); 645 .into();
585 646
@@ -595,14 +656,14 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
595 } 656 }
596 _ => &Ty::Unknown, 657 _ => &Ty::Unknown,
597 }; 658 };
598 let subty = self.infer_pat(*pat, expectation); 659 let subty = self.infer_pat(*pat, expectation, default_bm);
599 Ty::Ref(subty.into(), *mutability) 660 Ty::Ref(subty.into(), *mutability)
600 } 661 }
601 Pat::TupleStruct { path: ref p, args: ref subpats } => { 662 Pat::TupleStruct { path: ref p, args: ref subpats } => {
602 self.infer_tuple_struct_pat(p.as_ref(), subpats, expected) 663 self.infer_tuple_struct_pat(p.as_ref(), subpats, expected, default_bm)
603 } 664 }
604 Pat::Struct { path: ref p, args: ref fields } => { 665 Pat::Struct { path: ref p, args: ref fields } => {
605 self.infer_struct_pat(p.as_ref(), fields, expected) 666 self.infer_struct_pat(p.as_ref(), fields, expected, default_bm)
606 } 667 }
607 Pat::Path(path) => { 668 Pat::Path(path) => {
608 // TODO use correct resolver for the surrounding expression 669 // TODO use correct resolver for the surrounding expression
@@ -610,17 +671,21 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
610 self.infer_path_expr(&resolver, &path, pat.into()).unwrap_or(Ty::Unknown) 671 self.infer_path_expr(&resolver, &path, pat.into()).unwrap_or(Ty::Unknown)
611 } 672 }
612 Pat::Bind { mode, name: _name, subpat } => { 673 Pat::Bind { mode, name: _name, subpat } => {
674 let mode = if mode == &BindingAnnotation::Unannotated {
675 default_bm
676 } else {
677 BindingMode::convert(mode)
678 };
613 let inner_ty = if let Some(subpat) = subpat { 679 let inner_ty = if let Some(subpat) = subpat {
614 self.infer_pat(*subpat, expected) 680 self.infer_pat(*subpat, expected, default_bm)
615 } else { 681 } else {
616 expected.clone() 682 expected.clone()
617 }; 683 };
618 let inner_ty = self.insert_type_vars_shallow(inner_ty); 684 let inner_ty = self.insert_type_vars_shallow(inner_ty);
619 685
620 let bound_ty = match mode { 686 let bound_ty = match mode {
621 BindingAnnotation::Ref => Ty::Ref(inner_ty.clone().into(), Mutability::Shared), 687 BindingMode::Ref(mutability) => Ty::Ref(inner_ty.clone().into(), mutability),
622 BindingAnnotation::RefMut => Ty::Ref(inner_ty.clone().into(), Mutability::Mut), 688 BindingMode::Move => inner_ty.clone(),
623 BindingAnnotation::Mutable | BindingAnnotation::Unannotated => inner_ty.clone(),
624 }; 689 };
625 let bound_ty = self.resolve_ty_as_possible(&mut vec![], bound_ty); 690 let bound_ty = self.resolve_ty_as_possible(&mut vec![], bound_ty);
626 self.write_pat_ty(pat, bound_ty); 691 self.write_pat_ty(pat, bound_ty);
@@ -700,7 +765,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
700 } 765 }
701 Expr::For { iterable, body, pat } => { 766 Expr::For { iterable, body, pat } => {
702 let _iterable_ty = self.infer_expr(*iterable, &Expectation::none()); 767 let _iterable_ty = self.infer_expr(*iterable, &Expectation::none());
703 self.infer_pat(*pat, &Ty::Unknown); 768 self.infer_pat(*pat, &Ty::Unknown, BindingMode::default());
704 self.infer_expr(*body, &Expectation::has_type(Ty::unit())); 769 self.infer_expr(*body, &Expectation::has_type(Ty::unit()));
705 Ty::unit() 770 Ty::unit()
706 } 771 }
@@ -714,7 +779,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
714 } else { 779 } else {
715 Ty::Unknown 780 Ty::Unknown
716 }; 781 };
717 self.infer_pat(*arg_pat, &expected); 782 self.infer_pat(*arg_pat, &expected, BindingMode::default());
718 } 783 }
719 784
720 // TODO: infer lambda type etc. 785 // TODO: infer lambda type etc.
@@ -807,7 +872,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
807 872
808 for arm in arms { 873 for arm in arms {
809 for &pat in &arm.pats { 874 for &pat in &arm.pats {
810 let _pat_ty = self.infer_pat(pat, &input_ty); 875 let _pat_ty = self.infer_pat(pat, &input_ty, BindingMode::default());
811 } 876 }
812 if let Some(guard_expr) = arm.guard { 877 if let Some(guard_expr) = arm.guard {
813 self.infer_expr(guard_expr, &Expectation::has_type(Ty::Bool)); 878 self.infer_expr(guard_expr, &Expectation::has_type(Ty::Bool));
@@ -1007,7 +1072,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
1007 decl_ty 1072 decl_ty
1008 }; 1073 };
1009 1074
1010 self.infer_pat(*pat, &ty); 1075 self.infer_pat(*pat, &ty, BindingMode::default());
1011 } 1076 }
1012 Statement::Expr(expr) => { 1077 Statement::Expr(expr) => {
1013 self.infer_expr(*expr, &Expectation::none()); 1078 self.infer_expr(*expr, &Expectation::none());
@@ -1023,7 +1088,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
1023 for (type_ref, pat) in signature.params().iter().zip(body.params()) { 1088 for (type_ref, pat) in signature.params().iter().zip(body.params()) {
1024 let ty = self.make_ty(type_ref); 1089 let ty = self.make_ty(type_ref);
1025 1090
1026 self.infer_pat(*pat, &ty); 1091 self.infer_pat(*pat, &ty, BindingMode::default());
1027 } 1092 }
1028 self.return_ty = self.make_ty(signature.ret_type()); 1093 self.return_ty = self.make_ty(signature.ret_type());
1029 } 1094 }
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs
index acae71c26..0f2172ddf 100644
--- a/crates/ra_hir/src/ty/tests.rs
+++ b/crates/ra_hir/src/ty/tests.rs
@@ -831,6 +831,60 @@ fn test(x: &i32) {
831} 831}
832 832
833#[test] 833#[test]
834fn infer_pattern_match_ergonomics() {
835 assert_snapshot_matches!(
836 infer(r#"
837struct A<T>(T);
838
839fn test() {
840 let A(n) = &A(1);
841 let A(n) = &mut A(1);
842}
843"#),
844 @r###"
845[28; 79) '{ ...(1); }': ()
846[38; 42) 'A(n)': A<i32>
847[40; 41) 'n': &i32
848[45; 50) '&A(1)': &A<i32>
849[46; 47) 'A': A<i32>(T) -> A<T>
850[46; 50) 'A(1)': A<i32>
851[48; 49) '1': i32
852[60; 64) 'A(n)': A<i32>
853[62; 63) 'n': &mut i32
854[67; 76) '&mut A(1)': &mut A<i32>
855[72; 73) 'A': A<i32>(T) -> A<T>
856[72; 76) 'A(1)': A<i32>
857[74; 75) '1': i32"###
858 );
859}
860
861#[test]
862fn infer_pattern_match_ergonomics_ref() {
863 covers!(match_ergonomics_ref);
864 assert_snapshot_matches!(
865 infer(r#"
866fn test() {
867 let v = &(1, &2);
868 let (_, &w) = v;
869}
870"#),
871 @r###"
872[11; 57) '{ ...= v; }': ()
873[21; 22) 'v': &(i32, &i32)
874[25; 33) '&(1, &2)': &(i32, &i32)
875[26; 33) '(1, &2)': (i32, &i32)
876[27; 28) '1': i32
877[30; 32) '&2': &i32
878[31; 32) '2': i32
879[43; 50) '(_, &w)': (i32, &i32)
880[44; 45) '_': i32
881[47; 49) '&w': &i32
882[48; 49) 'w': i32
883[53; 54) 'v': &(i32, &i32)"###
884 );
885}
886
887#[test]
834fn infer_adt_pattern() { 888fn infer_adt_pattern() {
835 assert_snapshot_matches!( 889 assert_snapshot_matches!(
836 infer(r#" 890 infer(r#"
diff --git a/crates/ra_parser/src/grammar/expressions.rs b/crates/ra_parser/src/grammar/expressions.rs
index 6d3e379a3..ccbc905ab 100644
--- a/crates/ra_parser/src/grammar/expressions.rs
+++ b/crates/ra_parser/src/grammar/expressions.rs
@@ -148,6 +148,7 @@ fn current_op(p: &Parser) -> (u8, Op) {
148 (PLUS, EQ) => return (1, Op::Composite(PLUSEQ, 2)), 148 (PLUS, EQ) => return (1, Op::Composite(PLUSEQ, 2)),
149 (MINUS, EQ) => return (1, Op::Composite(MINUSEQ, 2)), 149 (MINUS, EQ) => return (1, Op::Composite(MINUSEQ, 2)),
150 (STAR, EQ) => return (1, Op::Composite(STAREQ, 2)), 150 (STAR, EQ) => return (1, Op::Composite(STAREQ, 2)),
151 (PERCENT, EQ) => return (1, Op::Composite(PERCENTEQ, 2)),
151 (SLASH, EQ) => return (1, Op::Composite(SLASHEQ, 2)), 152 (SLASH, EQ) => return (1, Op::Composite(SLASHEQ, 2)),
152 (PIPE, EQ) => return (1, Op::Composite(PIPEEQ, 2)), 153 (PIPE, EQ) => return (1, Op::Composite(PIPEEQ, 2)),
153 (AMP, EQ) => return (1, Op::Composite(AMPEQ, 2)), 154 (AMP, EQ) => return (1, Op::Composite(AMPEQ, 2)),
diff --git a/crates/ra_parser/src/grammar/expressions/atom.rs b/crates/ra_parser/src/grammar/expressions/atom.rs
index 53bb26c5f..d933288cd 100644
--- a/crates/ra_parser/src/grammar/expressions/atom.rs
+++ b/crates/ra_parser/src/grammar/expressions/atom.rs
@@ -342,21 +342,6 @@ pub(crate) fn match_arm_list(p: &mut Parser) {
342 continue; 342 continue;
343 } 343 }
344 344
345 // test match_arms_outer_attributes
346 // fn foo() {
347 // match () {
348 // #[cfg(feature = "some")]
349 // _ => (),
350 // #[cfg(feature = "other")]
351 // _ => (),
352 // #[cfg(feature = "many")]
353 // #[cfg(feature = "attributes")]
354 // #[cfg(feature = "before")]
355 // _ => (),
356 // }
357 // }
358 attributes::outer_attributes(p);
359
360 // test match_arms_commas 345 // test match_arms_commas
361 // fn foo() { 346 // fn foo() {
362 // match () { 347 // match () {
@@ -387,6 +372,21 @@ pub(crate) fn match_arm_list(p: &mut Parser) {
387// } 372// }
388fn match_arm(p: &mut Parser) -> BlockLike { 373fn match_arm(p: &mut Parser) -> BlockLike {
389 let m = p.start(); 374 let m = p.start();
375 // test match_arms_outer_attributes
376 // fn foo() {
377 // match () {
378 // #[cfg(feature = "some")]
379 // _ => (),
380 // #[cfg(feature = "other")]
381 // _ => (),
382 // #[cfg(feature = "many")]
383 // #[cfg(feature = "attributes")]
384 // #[cfg(feature = "before")]
385 // _ => (),
386 // }
387 // }
388 attributes::outer_attributes(p);
389
390 patterns::pattern_list_r(p, TokenSet::empty()); 390 patterns::pattern_list_r(p, TokenSet::empty());
391 if p.at(IF_KW) { 391 if p.at(IF_KW) {
392 match_guard(p); 392 match_guard(p);
diff --git a/crates/ra_syntax/tests/data/parser/err/0032_match_arms_inner_attrs.txt b/crates/ra_syntax/tests/data/parser/err/0032_match_arms_inner_attrs.txt
index b7543abc9..ed5735a63 100644
--- a/crates/ra_syntax/tests/data/parser/err/0032_match_arms_inner_attrs.txt
+++ b/crates/ra_syntax/tests/data/parser/err/0032_match_arms_inner_attrs.txt
@@ -33,11 +33,11 @@ SOURCE_FILE@[0; 293)
33 R_PAREN@[40; 41) 33 R_PAREN@[40; 41)
34 COMMA@[41; 42) 34 COMMA@[41; 42)
35 WHITESPACE@[42; 51) 35 WHITESPACE@[42; 51)
36 ATTR@[51; 52) 36 MATCH_ARM@[51; 78)
37 POUND@[51; 52) 37 ATTR@[51; 52)
38 err: `expected `[`` 38 POUND@[51; 52)
39 err: `expected pattern` 39 err: `expected `[``
40 MATCH_ARM@[52; 78) 40 err: `expected pattern`
41 ERROR@[52; 53) 41 ERROR@[52; 53)
42 EXCL@[52; 53) 42 EXCL@[52; 53)
43 err: `expected FAT_ARROW` 43 err: `expected FAT_ARROW`
@@ -103,11 +103,11 @@ SOURCE_FILE@[0; 293)
103 R_PAREN@[149; 150) 103 R_PAREN@[149; 150)
104 COMMA@[150; 151) 104 COMMA@[150; 151)
105 WHITESPACE@[151; 160) 105 WHITESPACE@[151; 160)
106 ATTR@[160; 161) 106 MATCH_ARM@[160; 179)
107 POUND@[160; 161) 107 ATTR@[160; 161)
108 err: `expected `[`` 108 POUND@[160; 161)
109 err: `expected pattern` 109 err: `expected `[``
110 MATCH_ARM@[161; 179) 110 err: `expected pattern`
111 ERROR@[161; 162) 111 ERROR@[161; 162)
112 EXCL@[161; 162) 112 EXCL@[161; 162)
113 err: `expected FAT_ARROW` 113 err: `expected FAT_ARROW`
@@ -138,22 +138,22 @@ SOURCE_FILE@[0; 293)
138 MATCH_ARM_LIST@[200; 290) 138 MATCH_ARM_LIST@[200; 290)
139 L_CURLY@[200; 201) 139 L_CURLY@[200; 201)
140 WHITESPACE@[201; 210) 140 WHITESPACE@[201; 210)
141 ATTR@[210; 222) 141 MATCH_ARM@[210; 250)
142 POUND@[210; 211) 142 ATTR@[210; 222)
143 TOKEN_TREE@[211; 222) 143 POUND@[210; 211)
144 L_BRACK@[211; 212) 144 TOKEN_TREE@[211; 222)
145 IDENT@[212; 215) "cfg" 145 L_BRACK@[211; 212)
146 TOKEN_TREE@[215; 221) 146 IDENT@[212; 215) "cfg"
147 L_PAREN@[215; 216) 147 TOKEN_TREE@[215; 221)
148 IDENT@[216; 220) "test" 148 L_PAREN@[215; 216)
149 R_PAREN@[220; 221) 149 IDENT@[216; 220) "test"
150 R_BRACK@[221; 222) 150 R_PAREN@[220; 221)
151 WHITESPACE@[222; 231) 151 R_BRACK@[221; 222)
152 ATTR@[231; 232) 152 WHITESPACE@[222; 231)
153 POUND@[231; 232) 153 ATTR@[231; 232)
154 err: `expected `[`` 154 POUND@[231; 232)
155 err: `expected pattern` 155 err: `expected `[``
156 MATCH_ARM@[232; 250) 156 err: `expected pattern`
157 ERROR@[232; 233) 157 ERROR@[232; 233)
158 EXCL@[232; 233) 158 EXCL@[232; 233)
159 err: `expected FAT_ARROW` 159 err: `expected FAT_ARROW`
diff --git a/crates/ra_syntax/tests/data/parser/err/0033_match_arms_outer_attrs.txt b/crates/ra_syntax/tests/data/parser/err/0033_match_arms_outer_attrs.txt
index 7f8767001..f540409bc 100644
--- a/crates/ra_syntax/tests/data/parser/err/0033_match_arms_outer_attrs.txt
+++ b/crates/ra_syntax/tests/data/parser/err/0033_match_arms_outer_attrs.txt
@@ -43,21 +43,21 @@ SOURCE_FILE@[0; 89)
43 R_PAREN@[57; 58) 43 R_PAREN@[57; 58)
44 COMMA@[58; 59) 44 COMMA@[58; 59)
45 WHITESPACE@[59; 68) 45 WHITESPACE@[59; 68)
46 ATTR@[68; 80) 46 MATCH_ARM@[68; 80)
47 POUND@[68; 69) 47 ATTR@[68; 80)
48 TOKEN_TREE@[69; 80) 48 POUND@[68; 69)
49 L_BRACK@[69; 70) 49 TOKEN_TREE@[69; 80)
50 IDENT@[70; 73) "cfg" 50 L_BRACK@[69; 70)
51 TOKEN_TREE@[73; 79) 51 IDENT@[70; 73) "cfg"
52 L_PAREN@[73; 74) 52 TOKEN_TREE@[73; 79)
53 IDENT@[74; 78) "test" 53 L_PAREN@[73; 74)
54 R_PAREN@[78; 79) 54 IDENT@[74; 78) "test"
55 R_BRACK@[79; 80) 55 R_PAREN@[78; 79)
56 R_BRACK@[79; 80)
57 err: `expected pattern`
58 err: `expected FAT_ARROW`
59 err: `expected expression`
56 WHITESPACE@[80; 85) 60 WHITESPACE@[80; 85)
57 err: `expected pattern`
58 err: `expected FAT_ARROW`
59 err: `expected expression`
60 MATCH_ARM@[85; 85)
61 R_CURLY@[85; 86) 61 R_CURLY@[85; 86)
62 WHITESPACE@[86; 87) 62 WHITESPACE@[86; 87)
63 R_CURLY@[87; 88) 63 R_CURLY@[87; 88)
diff --git a/crates/ra_syntax/tests/data/parser/inline/ok/0121_match_arms_outer_attributes.txt b/crates/ra_syntax/tests/data/parser/inline/ok/0121_match_arms_outer_attributes.txt
index c888fb8f0..e52a290bf 100644
--- a/crates/ra_syntax/tests/data/parser/inline/ok/0121_match_arms_outer_attributes.txt
+++ b/crates/ra_syntax/tests/data/parser/inline/ok/0121_match_arms_outer_attributes.txt
@@ -21,22 +21,22 @@ SOURCE_FILE@[0; 259)
21 MATCH_ARM_LIST@[24; 256) 21 MATCH_ARM_LIST@[24; 256)
22 L_CURLY@[24; 25) 22 L_CURLY@[24; 25)
23 WHITESPACE@[25; 34) 23 WHITESPACE@[25; 34)
24 ATTR@[34; 58) 24 MATCH_ARM@[34; 74)
25 POUND@[34; 35) 25 ATTR@[34; 58)
26 TOKEN_TREE@[35; 58) 26 POUND@[34; 35)
27 L_BRACK@[35; 36) 27 TOKEN_TREE@[35; 58)
28 IDENT@[36; 39) "cfg" 28 L_BRACK@[35; 36)
29 TOKEN_TREE@[39; 57) 29 IDENT@[36; 39) "cfg"
30 L_PAREN@[39; 40) 30 TOKEN_TREE@[39; 57)
31 IDENT@[40; 47) "feature" 31 L_PAREN@[39; 40)
32 WHITESPACE@[47; 48) 32 IDENT@[40; 47) "feature"
33 EQ@[48; 49) 33 WHITESPACE@[47; 48)
34 WHITESPACE@[49; 50) 34 EQ@[48; 49)
35 STRING@[50; 56) 35 WHITESPACE@[49; 50)
36 R_PAREN@[56; 57) 36 STRING@[50; 56)
37 R_BRACK@[57; 58) 37 R_PAREN@[56; 57)
38 WHITESPACE@[58; 67) 38 R_BRACK@[57; 58)
39 MATCH_ARM@[67; 74) 39 WHITESPACE@[58; 67)
40 PLACEHOLDER_PAT@[67; 68) 40 PLACEHOLDER_PAT@[67; 68)
41 UNDERSCORE@[67; 68) 41 UNDERSCORE@[67; 68)
42 WHITESPACE@[68; 69) 42 WHITESPACE@[68; 69)
@@ -47,22 +47,22 @@ SOURCE_FILE@[0; 259)
47 R_PAREN@[73; 74) 47 R_PAREN@[73; 74)
48 COMMA@[74; 75) 48 COMMA@[74; 75)
49 WHITESPACE@[75; 84) 49 WHITESPACE@[75; 84)
50 ATTR@[84; 109) 50 MATCH_ARM@[84; 125)
51 POUND@[84; 85) 51 ATTR@[84; 109)
52 TOKEN_TREE@[85; 109) 52 POUND@[84; 85)
53 L_BRACK@[85; 86) 53 TOKEN_TREE@[85; 109)
54 IDENT@[86; 89) "cfg" 54 L_BRACK@[85; 86)
55 TOKEN_TREE@[89; 108) 55 IDENT@[86; 89) "cfg"
56 L_PAREN@[89; 90) 56 TOKEN_TREE@[89; 108)
57 IDENT@[90; 97) "feature" 57 L_PAREN@[89; 90)
58 WHITESPACE@[97; 98) 58 IDENT@[90; 97) "feature"
59 EQ@[98; 99) 59 WHITESPACE@[97; 98)
60 WHITESPACE@[99; 100) 60 EQ@[98; 99)
61 STRING@[100; 107) 61 WHITESPACE@[99; 100)
62 R_PAREN@[107; 108) 62 STRING@[100; 107)
63 R_BRACK@[108; 109) 63 R_PAREN@[107; 108)
64 WHITESPACE@[109; 118) 64 R_BRACK@[108; 109)
65 MATCH_ARM@[118; 125) 65 WHITESPACE@[109; 118)
66 PLACEHOLDER_PAT@[118; 119) 66 PLACEHOLDER_PAT@[118; 119)
67 UNDERSCORE@[118; 119) 67 UNDERSCORE@[118; 119)
68 WHITESPACE@[119; 120) 68 WHITESPACE@[119; 120)
@@ -73,52 +73,52 @@ SOURCE_FILE@[0; 259)
73 R_PAREN@[124; 125) 73 R_PAREN@[124; 125)
74 COMMA@[125; 126) 74 COMMA@[125; 126)
75 WHITESPACE@[126; 135) 75 WHITESPACE@[126; 135)
76 ATTR@[135; 159) 76 MATCH_ARM@[135; 249)
77 POUND@[135; 136) 77 ATTR@[135; 159)
78 TOKEN_TREE@[136; 159) 78 POUND@[135; 136)
79 L_BRACK@[136; 137) 79 TOKEN_TREE@[136; 159)
80 IDENT@[137; 140) "cfg" 80 L_BRACK@[136; 137)
81 TOKEN_TREE@[140; 158) 81 IDENT@[137; 140) "cfg"
82 L_PAREN@[140; 141) 82 TOKEN_TREE@[140; 158)
83 IDENT@[141; 148) "feature" 83 L_PAREN@[140; 141)
84 WHITESPACE@[148; 149) 84 IDENT@[141; 148) "feature"
85 EQ@[149; 150) 85 WHITESPACE@[148; 149)
86 WHITESPACE@[150; 151) 86 EQ@[149; 150)
87 STRING@[151; 157) 87 WHITESPACE@[150; 151)
88 R_PAREN@[157; 158) 88 STRING@[151; 157)
89 R_BRACK@[158; 159) 89 R_PAREN@[157; 158)
90 WHITESPACE@[159; 168) 90 R_BRACK@[158; 159)
91 ATTR@[168; 198) 91 WHITESPACE@[159; 168)
92 POUND@[168; 169) 92 ATTR@[168; 198)
93 TOKEN_TREE@[169; 198) 93 POUND@[168; 169)
94 L_BRACK@[169; 170) 94 TOKEN_TREE@[169; 198)
95 IDENT@[170; 173) "cfg" 95 L_BRACK@[169; 170)
96 TOKEN_TREE@[173; 197) 96 IDENT@[170; 173) "cfg"
97 L_PAREN@[173; 174) 97 TOKEN_TREE@[173; 197)
98 IDENT@[174; 181) "feature" 98 L_PAREN@[173; 174)
99 WHITESPACE@[181; 182) 99 IDENT@[174; 181) "feature"
100 EQ@[182; 183) 100 WHITESPACE@[181; 182)
101 WHITESPACE@[183; 184) 101 EQ@[182; 183)
102 STRING@[184; 196) 102 WHITESPACE@[183; 184)
103 R_PAREN@[196; 197) 103 STRING@[184; 196)
104 R_BRACK@[197; 198) 104 R_PAREN@[196; 197)
105 WHITESPACE@[198; 207) 105 R_BRACK@[197; 198)
106 ATTR@[207; 233) 106 WHITESPACE@[198; 207)
107 POUND@[207; 208) 107 ATTR@[207; 233)
108 TOKEN_TREE@[208; 233) 108 POUND@[207; 208)
109 L_BRACK@[208; 209) 109 TOKEN_TREE@[208; 233)
110 IDENT@[209; 212) "cfg" 110 L_BRACK@[208; 209)
111 TOKEN_TREE@[212; 232) 111 IDENT@[209; 212) "cfg"
112 L_PAREN@[212; 213) 112 TOKEN_TREE@[212; 232)
113 IDENT@[213; 220) "feature" 113 L_PAREN@[212; 213)
114 WHITESPACE@[220; 221) 114 IDENT@[213; 220) "feature"
115 EQ@[221; 222) 115 WHITESPACE@[220; 221)
116 WHITESPACE@[222; 223) 116 EQ@[221; 222)
117 STRING@[223; 231) 117 WHITESPACE@[222; 223)
118 R_PAREN@[231; 232) 118 STRING@[223; 231)
119 R_BRACK@[232; 233) 119 R_PAREN@[231; 232)
120 WHITESPACE@[233; 242) 120 R_BRACK@[232; 233)
121 MATCH_ARM@[242; 249) 121 WHITESPACE@[233; 242)
122 PLACEHOLDER_PAT@[242; 243) 122 PLACEHOLDER_PAT@[242; 243)
123 UNDERSCORE@[242; 243) 123 UNDERSCORE@[242; 243)
124 WHITESPACE@[243; 244) 124 WHITESPACE@[243; 244)
diff --git a/crates/ra_syntax/tests/data/parser/ok/0048_compound_assignment.rs b/crates/ra_syntax/tests/data/parser/ok/0048_compound_assignment.rs
new file mode 100644
index 000000000..871720a49
--- /dev/null
+++ b/crates/ra_syntax/tests/data/parser/ok/0048_compound_assignment.rs
@@ -0,0 +1,17 @@
1// https://github.com/rust-analyzer/rust-analyzer/pull/983
2
3fn compound_assignment() {
4 let mut a = 0;
5 a += 1;
6 a -= 2;
7 a *= 3;
8 a %= 4;
9 a /= 5;
10 a |= 6;
11 a &= 7;
12 a ^= 8;
13 a <= 9;
14 a >= 10;
15 a >>= 11;
16 a <<= 12;
17}
diff --git a/crates/ra_syntax/tests/data/parser/ok/0048_compound_assignment.txt b/crates/ra_syntax/tests/data/parser/ok/0048_compound_assignment.txt
new file mode 100644
index 000000000..c5ff06823
--- /dev/null
+++ b/crates/ra_syntax/tests/data/parser/ok/0048_compound_assignment.txt
@@ -0,0 +1,200 @@
1SOURCE_FILE@[0; 257)
2 COMMENT@[0; 58)
3 WHITESPACE@[58; 60)
4 FN_DEF@[60; 256)
5 FN_KW@[60; 62)
6 WHITESPACE@[62; 63)
7 NAME@[63; 82)
8 IDENT@[63; 82) "compound_assignment"
9 PARAM_LIST@[82; 84)
10 L_PAREN@[82; 83)
11 R_PAREN@[83; 84)
12 WHITESPACE@[84; 85)
13 BLOCK@[85; 256)
14 L_CURLY@[85; 86)
15 WHITESPACE@[86; 91)
16 LET_STMT@[91; 105)
17 LET_KW@[91; 94)
18 WHITESPACE@[94; 95)
19 BIND_PAT@[95; 100)
20 MUT_KW@[95; 98)
21 WHITESPACE@[98; 99)
22 NAME@[99; 100)
23 IDENT@[99; 100) "a"
24 WHITESPACE@[100; 101)
25 EQ@[101; 102)
26 WHITESPACE@[102; 103)
27 LITERAL@[103; 104)
28 INT_NUMBER@[103; 104) "0"
29 SEMI@[104; 105)
30 WHITESPACE@[105; 110)
31 EXPR_STMT@[110; 117)
32 BIN_EXPR@[110; 116)
33 PATH_EXPR@[110; 111)
34 PATH@[110; 111)
35 PATH_SEGMENT@[110; 111)
36 NAME_REF@[110; 111)
37 IDENT@[110; 111) "a"
38 WHITESPACE@[111; 112)
39 PLUSEQ@[112; 114)
40 WHITESPACE@[114; 115)
41 LITERAL@[115; 116)
42 INT_NUMBER@[115; 116) "1"
43 SEMI@[116; 117)
44 WHITESPACE@[117; 122)
45 EXPR_STMT@[122; 129)
46 BIN_EXPR@[122; 128)
47 PATH_EXPR@[122; 123)
48 PATH@[122; 123)
49 PATH_SEGMENT@[122; 123)
50 NAME_REF@[122; 123)
51 IDENT@[122; 123) "a"
52 WHITESPACE@[123; 124)
53 MINUSEQ@[124; 126)
54 WHITESPACE@[126; 127)
55 LITERAL@[127; 128)
56 INT_NUMBER@[127; 128) "2"
57 SEMI@[128; 129)
58 WHITESPACE@[129; 134)
59 EXPR_STMT@[134; 141)
60 BIN_EXPR@[134; 140)
61 PATH_EXPR@[134; 135)
62 PATH@[134; 135)
63 PATH_SEGMENT@[134; 135)
64 NAME_REF@[134; 135)
65 IDENT@[134; 135) "a"
66 WHITESPACE@[135; 136)
67 STAREQ@[136; 138)
68 WHITESPACE@[138; 139)
69 LITERAL@[139; 140)
70 INT_NUMBER@[139; 140) "3"
71 SEMI@[140; 141)
72 WHITESPACE@[141; 146)
73 EXPR_STMT@[146; 153)
74 BIN_EXPR@[146; 152)
75 PATH_EXPR@[146; 147)
76 PATH@[146; 147)
77 PATH_SEGMENT@[146; 147)
78 NAME_REF@[146; 147)
79 IDENT@[146; 147) "a"
80 WHITESPACE@[147; 148)
81 PERCENTEQ@[148; 150)
82 WHITESPACE@[150; 151)
83 LITERAL@[151; 152)
84 INT_NUMBER@[151; 152) "4"
85 SEMI@[152; 153)
86 WHITESPACE@[153; 158)
87 EXPR_STMT@[158; 165)
88 BIN_EXPR@[158; 164)
89 PATH_EXPR@[158; 159)
90 PATH@[158; 159)
91 PATH_SEGMENT@[158; 159)
92 NAME_REF@[158; 159)
93 IDENT@[158; 159) "a"
94 WHITESPACE@[159; 160)
95 SLASHEQ@[160; 162)
96 WHITESPACE@[162; 163)
97 LITERAL@[163; 164)
98 INT_NUMBER@[163; 164) "5"
99 SEMI@[164; 165)
100 WHITESPACE@[165; 170)
101 EXPR_STMT@[170; 177)
102 BIN_EXPR@[170; 176)
103 PATH_EXPR@[170; 171)
104 PATH@[170; 171)
105 PATH_SEGMENT@[170; 171)
106 NAME_REF@[170; 171)
107 IDENT@[170; 171) "a"
108 WHITESPACE@[171; 172)
109 PIPEEQ@[172; 174)
110 WHITESPACE@[174; 175)
111 LITERAL@[175; 176)
112 INT_NUMBER@[175; 176) "6"
113 SEMI@[176; 177)
114 WHITESPACE@[177; 182)
115 EXPR_STMT@[182; 189)
116 BIN_EXPR@[182; 188)
117 PATH_EXPR@[182; 183)
118 PATH@[182; 183)
119 PATH_SEGMENT@[182; 183)
120 NAME_REF@[182; 183)
121 IDENT@[182; 183) "a"
122 WHITESPACE@[183; 184)
123 AMPEQ@[184; 186)
124 WHITESPACE@[186; 187)
125 LITERAL@[187; 188)
126 INT_NUMBER@[187; 188) "7"
127 SEMI@[188; 189)
128 WHITESPACE@[189; 194)
129 EXPR_STMT@[194; 201)
130 BIN_EXPR@[194; 200)
131 PATH_EXPR@[194; 195)
132 PATH@[194; 195)
133 PATH_SEGMENT@[194; 195)
134 NAME_REF@[194; 195)
135 IDENT@[194; 195) "a"
136 WHITESPACE@[195; 196)
137 CARETEQ@[196; 198)
138 WHITESPACE@[198; 199)
139 LITERAL@[199; 200)
140 INT_NUMBER@[199; 200) "8"
141 SEMI@[200; 201)
142 WHITESPACE@[201; 206)
143 EXPR_STMT@[206; 213)
144 BIN_EXPR@[206; 212)
145 PATH_EXPR@[206; 207)
146 PATH@[206; 207)
147 PATH_SEGMENT@[206; 207)
148 NAME_REF@[206; 207)
149 IDENT@[206; 207) "a"
150 WHITESPACE@[207; 208)
151 LTEQ@[208; 210)
152 WHITESPACE@[210; 211)
153 LITERAL@[211; 212)
154 INT_NUMBER@[211; 212) "9"
155 SEMI@[212; 213)
156 WHITESPACE@[213; 218)
157 EXPR_STMT@[218; 226)
158 BIN_EXPR@[218; 225)
159 PATH_EXPR@[218; 219)
160 PATH@[218; 219)
161 PATH_SEGMENT@[218; 219)
162 NAME_REF@[218; 219)
163 IDENT@[218; 219) "a"
164 WHITESPACE@[219; 220)
165 GTEQ@[220; 222)
166 WHITESPACE@[222; 223)
167 LITERAL@[223; 225)
168 INT_NUMBER@[223; 225) "10"
169 SEMI@[225; 226)
170 WHITESPACE@[226; 231)
171 EXPR_STMT@[231; 240)
172 BIN_EXPR@[231; 239)
173 PATH_EXPR@[231; 232)
174 PATH@[231; 232)
175 PATH_SEGMENT@[231; 232)
176 NAME_REF@[231; 232)
177 IDENT@[231; 232) "a"
178 WHITESPACE@[232; 233)
179 SHREQ@[233; 236)
180 WHITESPACE@[236; 237)
181 LITERAL@[237; 239)
182 INT_NUMBER@[237; 239) "11"
183 SEMI@[239; 240)
184 WHITESPACE@[240; 245)
185 EXPR_STMT@[245; 254)
186 BIN_EXPR@[245; 253)
187 PATH_EXPR@[245; 246)
188 PATH@[245; 246)
189 PATH_SEGMENT@[245; 246)
190 NAME_REF@[245; 246)
191 IDENT@[245; 246) "a"
192 WHITESPACE@[246; 247)
193 SHLEQ@[247; 250)
194 WHITESPACE@[250; 251)
195 LITERAL@[251; 253)
196 INT_NUMBER@[251; 253) "12"
197 SEMI@[253; 254)
198 WHITESPACE@[254; 255)
199 R_CURLY@[255; 256)
200 WHITESPACE@[256; 257)