diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2019-08-17 16:57:02 +0100 |
---|---|---|
committer | GitHub <[email protected]> | 2019-08-17 16:57:02 +0100 |
commit | 5a2a97c7e8cfac690a00505d8644be30f7ee863a (patch) | |
tree | eba980071d5c8941fdd3adc11fc5525d243ba2b3 /crates/ra_hir/src | |
parent | d15cf2c9600e0464b9bcd0273e7845efbf7bdeb5 (diff) | |
parent | 189d879659f4e44c3343023d6455bed7cdf0e7c9 (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]>
Diffstat (limited to 'crates/ra_hir/src')
-rw-r--r-- | crates/ra_hir/src/expr.rs | 101 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/infer.rs | 10 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/op.rs | 92 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests.rs | 14 |
4 files changed, 143 insertions, 74 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 | ||
260 | pub use ra_syntax::ast::BinOp as BinaryOp; | 264 | #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] |
265 | pub 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)] | ||
273 | pub enum LogicOp { | ||
274 | And, | ||
275 | Or, | ||
276 | } | ||
277 | |||
278 | #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] | ||
279 | pub enum CmpOp { | ||
280 | Eq { negated: bool }, | ||
281 | Ord { ordering: Ordering, strict: bool }, | ||
282 | } | ||
283 | |||
284 | #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] | ||
285 | pub enum Ordering { | ||
286 | Less, | ||
287 | Greater, | ||
288 | } | ||
289 | |||
290 | #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] | ||
291 | pub enum ArithOp { | ||
292 | Add, | ||
293 | Mul, | ||
294 | Sub, | ||
295 | Div, | ||
296 | Rem, | ||
297 | Shl, | ||
298 | Shr, | ||
299 | BitXor, | ||
300 | BitOr, | ||
301 | BitAnd, | ||
302 | } | ||
303 | |||
261 | pub use ra_syntax::ast::PrefixOp as UnaryOp; | 304 | pub use ra_syntax::ast::PrefixOp as UnaryOp; |
262 | #[derive(Debug, Clone, Eq, PartialEq)] | 305 | #[derive(Debug, Clone, Eq, PartialEq)] |
263 | pub enum Array { | 306 | pub 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 | ||
1092 | impl 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 | |||
1041 | pub(crate) fn body_with_source_map_query( | 1136 | pub(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 @@ | |||
1 | use super::{InferTy, Ty, TypeCtor}; | 1 | use super::{InferTy, Ty, TypeCtor}; |
2 | use crate::{expr::BinaryOp, ty::ApplicationTy}; | 2 | use crate::{ |
3 | expr::{BinaryOp, CmpOp}, | ||
4 | ty::ApplicationTy, | ||
5 | }; | ||
3 | 6 | ||
4 | pub(super) fn binary_op_return_ty(op: BinaryOp, rhs_ty: Ty) -> Ty { | 7 | pub(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 | ||
46 | pub(super) fn binary_op_rhs_expectation(op: BinaryOp, lhs_ty: Ty) -> Ty { | 22 | pub(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] |
2659 | fn 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] | ||
2659 | fn infer_macros_expanded() { | 2673 | fn infer_macros_expanded() { |
2660 | assert_snapshot_matches!( | 2674 | assert_snapshot_matches!( |
2661 | infer(r#" | 2675 | infer(r#" |