aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2019-08-17 16:57:02 +0100
committerGitHub <[email protected]>2019-08-17 16:57:02 +0100
commit5a2a97c7e8cfac690a00505d8644be30f7ee863a (patch)
treeeba980071d5c8941fdd3adc11fc5525d243ba2b3
parentd15cf2c9600e0464b9bcd0273e7845efbf7bdeb5 (diff)
parent189d879659f4e44c3343023d6455bed7cdf0e7c9 (diff)
Merge #1694
1694: Implement initial type-inference support for Index r=flodiebold a=matklad This doesn't actually infer indexing types, but at least it walks sub-expressions! Initially, I wanted to make `Index` just a new kind of `BinOp` (b/c indexing is kind of a binary op), so I've refactoring binop handing a bit. However, in the end I've decided to add a separate expr kind for Index, because `foo[0]`, `&foo[1]` and `&mut foo[1]` all seem to need slightly different handing, which is not binop-like r? @flodiebold Co-authored-by: Aleksey Kladov <[email protected]>
-rw-r--r--crates/ra_hir/src/expr.rs101
-rw-r--r--crates/ra_hir/src/ty/infer.rs10
-rw-r--r--crates/ra_hir/src/ty/op.rs92
-rw-r--r--crates/ra_hir/src/ty/tests.rs14
-rw-r--r--crates/ra_syntax/src/ast/expr_extensions.rs82
5 files changed, 186 insertions, 113 deletions
diff --git a/crates/ra_hir/src/expr.rs b/crates/ra_hir/src/expr.rs
index f33676655..a16561d11 100644
--- a/crates/ra_hir/src/expr.rs
+++ b/crates/ra_hir/src/expr.rs
@@ -245,6 +245,10 @@ pub enum Expr {
245 rhs: ExprId, 245 rhs: ExprId,
246 op: Option<BinaryOp>, 246 op: Option<BinaryOp>,
247 }, 247 },
248 Index {
249 base: ExprId,
250 index: ExprId,
251 },
248 Lambda { 252 Lambda {
249 args: Vec<PatId>, 253 args: Vec<PatId>,
250 arg_types: Vec<Option<TypeRef>>, 254 arg_types: Vec<Option<TypeRef>>,
@@ -257,7 +261,46 @@ pub enum Expr {
257 Literal(Literal), 261 Literal(Literal),
258} 262}
259 263
260pub use ra_syntax::ast::BinOp as BinaryOp; 264#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
265pub enum BinaryOp {
266 LogicOp(LogicOp),
267 ArithOp(ArithOp),
268 CmpOp(CmpOp),
269 Assignment { op: Option<ArithOp> },
270}
271
272#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
273pub enum LogicOp {
274 And,
275 Or,
276}
277
278#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
279pub enum CmpOp {
280 Eq { negated: bool },
281 Ord { ordering: Ordering, strict: bool },
282}
283
284#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
285pub enum Ordering {
286 Less,
287 Greater,
288}
289
290#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
291pub enum ArithOp {
292 Add,
293 Mul,
294 Sub,
295 Div,
296 Rem,
297 Shl,
298 Shr,
299 BitXor,
300 BitOr,
301 BitAnd,
302}
303
261pub use ra_syntax::ast::PrefixOp as UnaryOp; 304pub use ra_syntax::ast::PrefixOp as UnaryOp;
262#[derive(Debug, Clone, Eq, PartialEq)] 305#[derive(Debug, Clone, Eq, PartialEq)]
263pub enum Array { 306pub enum Array {
@@ -360,6 +403,10 @@ impl Expr {
360 f(*lhs); 403 f(*lhs);
361 f(*rhs); 404 f(*rhs);
362 } 405 }
406 Expr::Index { base, index } => {
407 f(*base);
408 f(*index);
409 }
363 Expr::Field { expr, .. } 410 Expr::Field { expr, .. }
364 | Expr::Await { expr } 411 | Expr::Await { expr }
365 | Expr::Try { expr } 412 | Expr::Try { expr }
@@ -791,7 +838,7 @@ where
791 ast::ExprKind::BinExpr(e) => { 838 ast::ExprKind::BinExpr(e) => {
792 let lhs = self.collect_expr_opt(e.lhs()); 839 let lhs = self.collect_expr_opt(e.lhs());
793 let rhs = self.collect_expr_opt(e.rhs()); 840 let rhs = self.collect_expr_opt(e.rhs());
794 let op = e.op_kind(); 841 let op = e.op_kind().map(BinaryOp::from);
795 self.alloc_expr(Expr::BinaryOp { lhs, rhs, op }, syntax_ptr) 842 self.alloc_expr(Expr::BinaryOp { lhs, rhs, op }, syntax_ptr)
796 } 843 }
797 ast::ExprKind::TupleExpr(e) => { 844 ast::ExprKind::TupleExpr(e) => {
@@ -848,10 +895,14 @@ where
848 }; 895 };
849 self.alloc_expr(Expr::Literal(lit), syntax_ptr) 896 self.alloc_expr(Expr::Literal(lit), syntax_ptr)
850 } 897 }
898 ast::ExprKind::IndexExpr(e) => {
899 let base = self.collect_expr_opt(e.base());
900 let index = self.collect_expr_opt(e.index());
901 self.alloc_expr(Expr::Index { base, index }, syntax_ptr)
902 }
851 903
852 // FIXME implement HIR for these: 904 // FIXME implement HIR for these:
853 ast::ExprKind::Label(_e) => self.alloc_expr(Expr::Missing, syntax_ptr), 905 ast::ExprKind::Label(_e) => self.alloc_expr(Expr::Missing, syntax_ptr),
854 ast::ExprKind::IndexExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr),
855 ast::ExprKind::RangeExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr), 906 ast::ExprKind::RangeExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr),
856 ast::ExprKind::MacroCall(e) => { 907 ast::ExprKind::MacroCall(e) => {
857 let ast_id = self 908 let ast_id = self
@@ -1038,6 +1089,50 @@ where
1038 } 1089 }
1039} 1090}
1040 1091
1092impl From<ast::BinOp> for BinaryOp {
1093 fn from(ast_op: ast::BinOp) -> Self {
1094 match ast_op {
1095 ast::BinOp::BooleanOr => BinaryOp::LogicOp(LogicOp::Or),
1096 ast::BinOp::BooleanAnd => BinaryOp::LogicOp(LogicOp::And),
1097 ast::BinOp::EqualityTest => BinaryOp::CmpOp(CmpOp::Eq { negated: false }),
1098 ast::BinOp::NegatedEqualityTest => BinaryOp::CmpOp(CmpOp::Eq { negated: true }),
1099 ast::BinOp::LesserEqualTest => {
1100 BinaryOp::CmpOp(CmpOp::Ord { ordering: Ordering::Less, strict: false })
1101 }
1102 ast::BinOp::GreaterEqualTest => {
1103 BinaryOp::CmpOp(CmpOp::Ord { ordering: Ordering::Greater, strict: false })
1104 }
1105 ast::BinOp::LesserTest => {
1106 BinaryOp::CmpOp(CmpOp::Ord { ordering: Ordering::Less, strict: true })
1107 }
1108 ast::BinOp::GreaterTest => {
1109 BinaryOp::CmpOp(CmpOp::Ord { ordering: Ordering::Greater, strict: true })
1110 }
1111 ast::BinOp::Addition => BinaryOp::ArithOp(ArithOp::Add),
1112 ast::BinOp::Multiplication => BinaryOp::ArithOp(ArithOp::Mul),
1113 ast::BinOp::Subtraction => BinaryOp::ArithOp(ArithOp::Sub),
1114 ast::BinOp::Division => BinaryOp::ArithOp(ArithOp::Div),
1115 ast::BinOp::Remainder => BinaryOp::ArithOp(ArithOp::Rem),
1116 ast::BinOp::LeftShift => BinaryOp::ArithOp(ArithOp::Shl),
1117 ast::BinOp::RightShift => BinaryOp::ArithOp(ArithOp::Shr),
1118 ast::BinOp::BitwiseXor => BinaryOp::ArithOp(ArithOp::BitXor),
1119 ast::BinOp::BitwiseOr => BinaryOp::ArithOp(ArithOp::BitOr),
1120 ast::BinOp::BitwiseAnd => BinaryOp::ArithOp(ArithOp::BitAnd),
1121 ast::BinOp::Assignment => BinaryOp::Assignment { op: None },
1122 ast::BinOp::AddAssign => BinaryOp::Assignment { op: Some(ArithOp::Add) },
1123 ast::BinOp::DivAssign => BinaryOp::Assignment { op: Some(ArithOp::Div) },
1124 ast::BinOp::MulAssign => BinaryOp::Assignment { op: Some(ArithOp::Mul) },
1125 ast::BinOp::RemAssign => BinaryOp::Assignment { op: Some(ArithOp::Rem) },
1126 ast::BinOp::ShlAssign => BinaryOp::Assignment { op: Some(ArithOp::Shl) },
1127 ast::BinOp::ShrAssign => BinaryOp::Assignment { op: Some(ArithOp::Shr) },
1128 ast::BinOp::SubAssign => BinaryOp::Assignment { op: Some(ArithOp::Sub) },
1129 ast::BinOp::BitOrAssign => BinaryOp::Assignment { op: Some(ArithOp::BitOr) },
1130 ast::BinOp::BitAndAssign => BinaryOp::Assignment { op: Some(ArithOp::BitAnd) },
1131 ast::BinOp::BitXorAssign => BinaryOp::Assignment { op: Some(ArithOp::BitXor) },
1132 }
1133 }
1134}
1135
1041pub(crate) fn body_with_source_map_query( 1136pub(crate) fn body_with_source_map_query(
1042 db: &impl HirDatabase, 1137 db: &impl HirDatabase,
1043 def: DefWithBody, 1138 def: DefWithBody,
diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs
index 675df4a22..cca59538a 100644
--- a/crates/ra_hir/src/ty/infer.rs
+++ b/crates/ra_hir/src/ty/infer.rs
@@ -1265,9 +1265,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
1265 Expr::BinaryOp { lhs, rhs, op } => match op { 1265 Expr::BinaryOp { lhs, rhs, op } => match op {
1266 Some(op) => { 1266 Some(op) => {
1267 let lhs_expectation = match op { 1267 let lhs_expectation = match op {
1268 BinaryOp::BooleanAnd | BinaryOp::BooleanOr => { 1268 BinaryOp::LogicOp(..) => Expectation::has_type(Ty::simple(TypeCtor::Bool)),
1269 Expectation::has_type(Ty::simple(TypeCtor::Bool))
1270 }
1271 _ => Expectation::none(), 1269 _ => Expectation::none(),
1272 }; 1270 };
1273 let lhs_ty = self.infer_expr(*lhs, &lhs_expectation); 1271 let lhs_ty = self.infer_expr(*lhs, &lhs_expectation);
@@ -1281,6 +1279,12 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
1281 } 1279 }
1282 _ => Ty::Unknown, 1280 _ => Ty::Unknown,
1283 }, 1281 },
1282 Expr::Index { base, index } => {
1283 let _base_ty = self.infer_expr(*base, &Expectation::none());
1284 let _index_ty = self.infer_expr(*index, &Expectation::none());
1285 // FIXME: use `std::ops::Index::Output` to figure out the real return type
1286 Ty::Unknown
1287 }
1284 Expr::Tuple { exprs } => { 1288 Expr::Tuple { exprs } => {
1285 let mut ty_vec = Vec::with_capacity(exprs.len()); 1289 let mut ty_vec = Vec::with_capacity(exprs.len());
1286 for arg in exprs.iter() { 1290 for arg in exprs.iter() {
diff --git a/crates/ra_hir/src/ty/op.rs b/crates/ra_hir/src/ty/op.rs
index 9ba868298..1b30a5b9b 100644
--- a/crates/ra_hir/src/ty/op.rs
+++ b/crates/ra_hir/src/ty/op.rs
@@ -1,37 +1,14 @@
1use super::{InferTy, Ty, TypeCtor}; 1use super::{InferTy, Ty, TypeCtor};
2use crate::{expr::BinaryOp, ty::ApplicationTy}; 2use crate::{
3 expr::{BinaryOp, CmpOp},
4 ty::ApplicationTy,
5};
3 6
4pub(super) fn binary_op_return_ty(op: BinaryOp, rhs_ty: Ty) -> Ty { 7pub(super) fn binary_op_return_ty(op: BinaryOp, rhs_ty: Ty) -> Ty {
5 match op { 8 match op {
6 BinaryOp::BooleanOr 9 BinaryOp::LogicOp(_) | BinaryOp::CmpOp(_) => Ty::simple(TypeCtor::Bool),
7 | BinaryOp::BooleanAnd 10 BinaryOp::Assignment { .. } => Ty::unit(),
8 | BinaryOp::EqualityTest 11 BinaryOp::ArithOp(_) => match rhs_ty {
9 | BinaryOp::NegatedEqualityTest
10 | BinaryOp::LesserEqualTest
11 | BinaryOp::GreaterEqualTest
12 | BinaryOp::LesserTest
13 | BinaryOp::GreaterTest => Ty::simple(TypeCtor::Bool),
14 BinaryOp::Assignment
15 | BinaryOp::AddAssign
16 | BinaryOp::SubAssign
17 | BinaryOp::DivAssign
18 | BinaryOp::MulAssign
19 | BinaryOp::RemAssign
20 | BinaryOp::ShrAssign
21 | BinaryOp::ShlAssign
22 | BinaryOp::BitAndAssign
23 | BinaryOp::BitOrAssign
24 | BinaryOp::BitXorAssign => Ty::unit(),
25 BinaryOp::Addition
26 | BinaryOp::Subtraction
27 | BinaryOp::Multiplication
28 | BinaryOp::Division
29 | BinaryOp::Remainder
30 | BinaryOp::LeftShift
31 | BinaryOp::RightShift
32 | BinaryOp::BitwiseAnd
33 | BinaryOp::BitwiseOr
34 | BinaryOp::BitwiseXor => match rhs_ty {
35 Ty::Apply(ApplicationTy { ctor, .. }) => match ctor { 12 Ty::Apply(ApplicationTy { ctor, .. }) => match ctor {
36 TypeCtor::Int(..) | TypeCtor::Float(..) => rhs_ty, 13 TypeCtor::Int(..) | TypeCtor::Float(..) => rhs_ty,
37 _ => Ty::Unknown, 14 _ => Ty::Unknown,
@@ -39,49 +16,29 @@ pub(super) fn binary_op_return_ty(op: BinaryOp, rhs_ty: Ty) -> Ty {
39 Ty::Infer(InferTy::IntVar(..)) | Ty::Infer(InferTy::FloatVar(..)) => rhs_ty, 16 Ty::Infer(InferTy::IntVar(..)) | Ty::Infer(InferTy::FloatVar(..)) => rhs_ty,
40 _ => Ty::Unknown, 17 _ => Ty::Unknown,
41 }, 18 },
42 BinaryOp::RangeRightOpen | BinaryOp::RangeRightClosed => Ty::Unknown,
43 } 19 }
44} 20}
45 21
46pub(super) fn binary_op_rhs_expectation(op: BinaryOp, lhs_ty: Ty) -> Ty { 22pub(super) fn binary_op_rhs_expectation(op: BinaryOp, lhs_ty: Ty) -> Ty {
47 match op { 23 match op {
48 BinaryOp::BooleanAnd | BinaryOp::BooleanOr => Ty::simple(TypeCtor::Bool), 24 BinaryOp::LogicOp(..) => Ty::simple(TypeCtor::Bool),
49 BinaryOp::Assignment | BinaryOp::EqualityTest => match lhs_ty { 25 BinaryOp::Assignment { op: None } | BinaryOp::CmpOp(CmpOp::Eq { negated: _ }) => {
50 Ty::Apply(ApplicationTy { ctor, .. }) => match ctor { 26 match lhs_ty {
51 TypeCtor::Int(..) 27 Ty::Apply(ApplicationTy { ctor, .. }) => match ctor {
52 | TypeCtor::Float(..) 28 TypeCtor::Int(..)
53 | TypeCtor::Str 29 | TypeCtor::Float(..)
54 | TypeCtor::Char 30 | TypeCtor::Str
55 | TypeCtor::Bool => lhs_ty, 31 | TypeCtor::Char
32 | TypeCtor::Bool => lhs_ty,
33 _ => Ty::Unknown,
34 },
35 Ty::Infer(InferTy::IntVar(..)) | Ty::Infer(InferTy::FloatVar(..)) => lhs_ty,
56 _ => Ty::Unknown, 36 _ => Ty::Unknown,
57 }, 37 }
58 Ty::Infer(InferTy::IntVar(..)) | Ty::Infer(InferTy::FloatVar(..)) => lhs_ty, 38 }
59 _ => Ty::Unknown, 39 BinaryOp::CmpOp(CmpOp::Ord { .. })
60 }, 40 | BinaryOp::Assignment { op: Some(_) }
61 BinaryOp::LesserEqualTest 41 | BinaryOp::ArithOp(_) => match lhs_ty {
62 | BinaryOp::GreaterEqualTest
63 | BinaryOp::LesserTest
64 | BinaryOp::GreaterTest
65 | BinaryOp::AddAssign
66 | BinaryOp::SubAssign
67 | BinaryOp::DivAssign
68 | BinaryOp::MulAssign
69 | BinaryOp::RemAssign
70 | BinaryOp::ShrAssign
71 | BinaryOp::ShlAssign
72 | BinaryOp::BitAndAssign
73 | BinaryOp::BitOrAssign
74 | BinaryOp::BitXorAssign
75 | BinaryOp::Addition
76 | BinaryOp::Subtraction
77 | BinaryOp::Multiplication
78 | BinaryOp::Division
79 | BinaryOp::Remainder
80 | BinaryOp::LeftShift
81 | BinaryOp::RightShift
82 | BinaryOp::BitwiseAnd
83 | BinaryOp::BitwiseOr
84 | BinaryOp::BitwiseXor => match lhs_ty {
85 Ty::Apply(ApplicationTy { ctor, .. }) => match ctor { 42 Ty::Apply(ApplicationTy { ctor, .. }) => match ctor {
86 TypeCtor::Int(..) | TypeCtor::Float(..) => lhs_ty, 43 TypeCtor::Int(..) | TypeCtor::Float(..) => lhs_ty,
87 _ => Ty::Unknown, 44 _ => Ty::Unknown,
@@ -89,6 +46,5 @@ pub(super) fn binary_op_rhs_expectation(op: BinaryOp, lhs_ty: Ty) -> Ty {
89 Ty::Infer(InferTy::IntVar(..)) | Ty::Infer(InferTy::FloatVar(..)) => lhs_ty, 46 Ty::Infer(InferTy::IntVar(..)) | Ty::Infer(InferTy::FloatVar(..)) => lhs_ty,
90 _ => Ty::Unknown, 47 _ => Ty::Unknown,
91 }, 48 },
92 _ => Ty::Unknown,
93 } 49 }
94} 50}
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs
index 28727bb18..6c2d857bc 100644
--- a/crates/ra_hir/src/ty/tests.rs
+++ b/crates/ra_hir/src/ty/tests.rs
@@ -2656,6 +2656,20 @@ fn test() -> u64 {
2656} 2656}
2657 2657
2658#[test] 2658#[test]
2659fn indexing_arrays() {
2660 assert_snapshot_matches!(
2661 infer("fn main() { &mut [9][2]; }"),
2662 @r###"
2663[10; 26) '{ &mut...[2]; }': ()
2664[12; 23) '&mut [9][2]': &mut {unknown}
2665[17; 20) '[9]': [i32;_]
2666[17; 23) '[9][2]': {unknown}
2667[18; 19) '9': i32
2668[21; 22) '2': i32"###
2669 )
2670}
2671
2672#[test]
2659fn infer_macros_expanded() { 2673fn infer_macros_expanded() {
2660 assert_snapshot_matches!( 2674 assert_snapshot_matches!(
2661 infer(r#" 2675 infer(r#"
diff --git a/crates/ra_syntax/src/ast/expr_extensions.rs b/crates/ra_syntax/src/ast/expr_extensions.rs
index 8284f1b25..cf5b6f251 100644
--- a/crates/ra_syntax/src/ast/expr_extensions.rs
+++ b/crates/ra_syntax/src/ast/expr_extensions.rs
@@ -102,10 +102,6 @@ pub enum BinOp {
102 BitwiseOr, 102 BitwiseOr,
103 /// The `&` operator for bitwise AND 103 /// The `&` operator for bitwise AND
104 BitwiseAnd, 104 BitwiseAnd,
105 /// The `..` operator for right-open ranges
106 RangeRightOpen,
107 /// The `..=` operator for right-closed ranges
108 RangeRightClosed,
109 /// The `=` operator for assignment 105 /// The `=` operator for assignment
110 Assignment, 106 Assignment,
111 /// The `+=` operator for assignment after addition 107 /// The `+=` operator for assignment after addition
@@ -132,41 +128,40 @@ pub enum BinOp {
132 128
133impl ast::BinExpr { 129impl ast::BinExpr {
134 fn op_details(&self) -> Option<(SyntaxToken, BinOp)> { 130 fn op_details(&self) -> Option<(SyntaxToken, BinOp)> {
135 self.syntax().children_with_tokens().filter_map(|it| it.into_token()).find_map(|c| match c 131 self.syntax().children_with_tokens().filter_map(|it| it.into_token()).find_map(|c| {
136 .kind() 132 let bin_op = match c.kind() {
137 { 133 T![||] => BinOp::BooleanOr,
138 T![||] => Some((c, BinOp::BooleanOr)), 134 T![&&] => BinOp::BooleanAnd,
139 T![&&] => Some((c, BinOp::BooleanAnd)), 135 T![==] => BinOp::EqualityTest,
140 T![==] => Some((c, BinOp::EqualityTest)), 136 T![!=] => BinOp::NegatedEqualityTest,
141 T![!=] => Some((c, BinOp::NegatedEqualityTest)), 137 T![<=] => BinOp::LesserEqualTest,
142 T![<=] => Some((c, BinOp::LesserEqualTest)), 138 T![>=] => BinOp::GreaterEqualTest,
143 T![>=] => Some((c, BinOp::GreaterEqualTest)), 139 T![<] => BinOp::LesserTest,
144 T![<] => Some((c, BinOp::LesserTest)), 140 T![>] => BinOp::GreaterTest,
145 T![>] => Some((c, BinOp::GreaterTest)), 141 T![+] => BinOp::Addition,
146 T![+] => Some((c, BinOp::Addition)), 142 T![*] => BinOp::Multiplication,
147 T![*] => Some((c, BinOp::Multiplication)), 143 T![-] => BinOp::Subtraction,
148 T![-] => Some((c, BinOp::Subtraction)), 144 T![/] => BinOp::Division,
149 T![/] => Some((c, BinOp::Division)), 145 T![%] => BinOp::Remainder,
150 T![%] => Some((c, BinOp::Remainder)), 146 T![<<] => BinOp::LeftShift,
151 T![<<] => Some((c, BinOp::LeftShift)), 147 T![>>] => BinOp::RightShift,
152 T![>>] => Some((c, BinOp::RightShift)), 148 T![^] => BinOp::BitwiseXor,
153 T![^] => Some((c, BinOp::BitwiseXor)), 149 T![|] => BinOp::BitwiseOr,
154 T![|] => Some((c, BinOp::BitwiseOr)), 150 T![&] => BinOp::BitwiseAnd,
155 T![&] => Some((c, BinOp::BitwiseAnd)), 151 T![=] => BinOp::Assignment,
156 T![..] => Some((c, BinOp::RangeRightOpen)), 152 T![+=] => BinOp::AddAssign,
157 T![..=] => Some((c, BinOp::RangeRightClosed)), 153 T![/=] => BinOp::DivAssign,
158 T![=] => Some((c, BinOp::Assignment)), 154 T![*=] => BinOp::MulAssign,
159 T![+=] => Some((c, BinOp::AddAssign)), 155 T![%=] => BinOp::RemAssign,
160 T![/=] => Some((c, BinOp::DivAssign)), 156 T![>>=] => BinOp::ShrAssign,
161 T![*=] => Some((c, BinOp::MulAssign)), 157 T![<<=] => BinOp::ShlAssign,
162 T![%=] => Some((c, BinOp::RemAssign)), 158 T![-=] => BinOp::SubAssign,
163 T![>>=] => Some((c, BinOp::ShrAssign)), 159 T![|=] => BinOp::BitOrAssign,
164 T![<<=] => Some((c, BinOp::ShlAssign)), 160 T![&=] => BinOp::BitAndAssign,
165 T![-=] => Some((c, BinOp::SubAssign)), 161 T![^=] => BinOp::BitXorAssign,
166 T![|=] => Some((c, BinOp::BitOrAssign)), 162 _ => return None,
167 T![&=] => Some((c, BinOp::BitAndAssign)), 163 };
168 T![^=] => Some((c, BinOp::BitXorAssign)), 164 Some((c, bin_op))
169 _ => None,
170 }) 165 })
171 } 166 }
172 167
@@ -194,6 +189,15 @@ impl ast::BinExpr {
194 } 189 }
195} 190}
196 191
192impl ast::IndexExpr {
193 pub fn base(&self) -> Option<ast::Expr> {
194 children(self).nth(0)
195 }
196 pub fn index(&self) -> Option<ast::Expr> {
197 children(self).nth(1)
198 }
199}
200
197pub enum ArrayExprKind { 201pub enum ArrayExprKind {
198 Repeat { initializer: Option<ast::Expr>, repeat: Option<ast::Expr> }, 202 Repeat { initializer: Option<ast::Expr>, repeat: Option<ast::Expr> },
199 ElementList(AstChildren<ast::Expr>), 203 ElementList(AstChildren<ast::Expr>),