aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_def/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir_def/src')
-rw-r--r--crates/ra_hir_def/src/body.rs2
-rw-r--r--crates/ra_hir_def/src/body/lower.rs49
-rw-r--r--crates/ra_hir_def/src/builtin_type.rs86
-rw-r--r--crates/ra_hir_def/src/expr.rs419
-rw-r--r--crates/ra_hir_def/src/lib.rs2
5 files changed, 542 insertions, 16 deletions
diff --git a/crates/ra_hir_def/src/body.rs b/crates/ra_hir_def/src/body.rs
new file mode 100644
index 000000000..7447904ea
--- /dev/null
+++ b/crates/ra_hir_def/src/body.rs
@@ -0,0 +1,2 @@
1//! FIXME: write short doc here
2mod lower;
diff --git a/crates/ra_hir_def/src/body/lower.rs b/crates/ra_hir_def/src/body/lower.rs
new file mode 100644
index 000000000..1a144b1f9
--- /dev/null
+++ b/crates/ra_hir_def/src/body/lower.rs
@@ -0,0 +1,49 @@
1//! FIXME: write short doc here
2
3use ra_syntax::ast;
4
5use crate::expr::{ArithOp, BinaryOp, CmpOp, LogicOp, Ordering};
6
7impl From<ast::BinOp> for BinaryOp {
8 fn from(ast_op: ast::BinOp) -> Self {
9 match ast_op {
10 ast::BinOp::BooleanOr => BinaryOp::LogicOp(LogicOp::Or),
11 ast::BinOp::BooleanAnd => BinaryOp::LogicOp(LogicOp::And),
12 ast::BinOp::EqualityTest => BinaryOp::CmpOp(CmpOp::Eq { negated: false }),
13 ast::BinOp::NegatedEqualityTest => BinaryOp::CmpOp(CmpOp::Eq { negated: true }),
14 ast::BinOp::LesserEqualTest => {
15 BinaryOp::CmpOp(CmpOp::Ord { ordering: Ordering::Less, strict: false })
16 }
17 ast::BinOp::GreaterEqualTest => {
18 BinaryOp::CmpOp(CmpOp::Ord { ordering: Ordering::Greater, strict: false })
19 }
20 ast::BinOp::LesserTest => {
21 BinaryOp::CmpOp(CmpOp::Ord { ordering: Ordering::Less, strict: true })
22 }
23 ast::BinOp::GreaterTest => {
24 BinaryOp::CmpOp(CmpOp::Ord { ordering: Ordering::Greater, strict: true })
25 }
26 ast::BinOp::Addition => BinaryOp::ArithOp(ArithOp::Add),
27 ast::BinOp::Multiplication => BinaryOp::ArithOp(ArithOp::Mul),
28 ast::BinOp::Subtraction => BinaryOp::ArithOp(ArithOp::Sub),
29 ast::BinOp::Division => BinaryOp::ArithOp(ArithOp::Div),
30 ast::BinOp::Remainder => BinaryOp::ArithOp(ArithOp::Rem),
31 ast::BinOp::LeftShift => BinaryOp::ArithOp(ArithOp::Shl),
32 ast::BinOp::RightShift => BinaryOp::ArithOp(ArithOp::Shr),
33 ast::BinOp::BitwiseXor => BinaryOp::ArithOp(ArithOp::BitXor),
34 ast::BinOp::BitwiseOr => BinaryOp::ArithOp(ArithOp::BitOr),
35 ast::BinOp::BitwiseAnd => BinaryOp::ArithOp(ArithOp::BitAnd),
36 ast::BinOp::Assignment => BinaryOp::Assignment { op: None },
37 ast::BinOp::AddAssign => BinaryOp::Assignment { op: Some(ArithOp::Add) },
38 ast::BinOp::DivAssign => BinaryOp::Assignment { op: Some(ArithOp::Div) },
39 ast::BinOp::MulAssign => BinaryOp::Assignment { op: Some(ArithOp::Mul) },
40 ast::BinOp::RemAssign => BinaryOp::Assignment { op: Some(ArithOp::Rem) },
41 ast::BinOp::ShlAssign => BinaryOp::Assignment { op: Some(ArithOp::Shl) },
42 ast::BinOp::ShrAssign => BinaryOp::Assignment { op: Some(ArithOp::Shr) },
43 ast::BinOp::SubAssign => BinaryOp::Assignment { op: Some(ArithOp::Sub) },
44 ast::BinOp::BitOrAssign => BinaryOp::Assignment { op: Some(ArithOp::BitOr) },
45 ast::BinOp::BitAndAssign => BinaryOp::Assignment { op: Some(ArithOp::BitAnd) },
46 ast::BinOp::BitXorAssign => BinaryOp::Assignment { op: Some(ArithOp::BitXor) },
47 }
48 }
49}
diff --git a/crates/ra_hir_def/src/builtin_type.rs b/crates/ra_hir_def/src/builtin_type.rs
index 996e86fd9..5e8157144 100644
--- a/crates/ra_hir_def/src/builtin_type.rs
+++ b/crates/ra_hir_def/src/builtin_type.rs
@@ -56,22 +56,22 @@ impl BuiltinType {
56 (name::BOOL, BuiltinType::Bool), 56 (name::BOOL, BuiltinType::Bool),
57 (name::STR, BuiltinType::Str ), 57 (name::STR, BuiltinType::Str ),
58 58
59 (name::ISIZE, BuiltinType::Int(BuiltinInt { signedness: Signedness::Signed, bitness: IntBitness::Xsize })), 59 (name::ISIZE, BuiltinType::Int(BuiltinInt::ISIZE)),
60 (name::I8, BuiltinType::Int(BuiltinInt { signedness: Signedness::Signed, bitness: IntBitness::X8 })), 60 (name::I8, BuiltinType::Int(BuiltinInt::I8)),
61 (name::I16, BuiltinType::Int(BuiltinInt { signedness: Signedness::Signed, bitness: IntBitness::X16 })), 61 (name::I16, BuiltinType::Int(BuiltinInt::I16)),
62 (name::I32, BuiltinType::Int(BuiltinInt { signedness: Signedness::Signed, bitness: IntBitness::X32 })), 62 (name::I32, BuiltinType::Int(BuiltinInt::I32)),
63 (name::I64, BuiltinType::Int(BuiltinInt { signedness: Signedness::Signed, bitness: IntBitness::X64 })), 63 (name::I64, BuiltinType::Int(BuiltinInt::I64)),
64 (name::I128, BuiltinType::Int(BuiltinInt { signedness: Signedness::Signed, bitness: IntBitness::X128 })), 64 (name::I128, BuiltinType::Int(BuiltinInt::I128)),
65 65
66 (name::USIZE, BuiltinType::Int(BuiltinInt { signedness: Signedness::Unsigned, bitness: IntBitness::Xsize })), 66 (name::USIZE, BuiltinType::Int(BuiltinInt::USIZE)),
67 (name::U8, BuiltinType::Int(BuiltinInt { signedness: Signedness::Unsigned, bitness: IntBitness::X8 })), 67 (name::U8, BuiltinType::Int(BuiltinInt::U8)),
68 (name::U16, BuiltinType::Int(BuiltinInt { signedness: Signedness::Unsigned, bitness: IntBitness::X16 })), 68 (name::U16, BuiltinType::Int(BuiltinInt::U16)),
69 (name::U32, BuiltinType::Int(BuiltinInt { signedness: Signedness::Unsigned, bitness: IntBitness::X32 })), 69 (name::U32, BuiltinType::Int(BuiltinInt::U32)),
70 (name::U64, BuiltinType::Int(BuiltinInt { signedness: Signedness::Unsigned, bitness: IntBitness::X64 })), 70 (name::U64, BuiltinType::Int(BuiltinInt::U64)),
71 (name::U128, BuiltinType::Int(BuiltinInt { signedness: Signedness::Unsigned, bitness: IntBitness::X128 })), 71 (name::U128, BuiltinType::Int(BuiltinInt::U128)),
72 72
73 (name::F32, BuiltinType::Float(BuiltinFloat { bitness: FloatBitness::X32 })), 73 (name::F32, BuiltinType::Float(BuiltinFloat::F32)),
74 (name::F64, BuiltinType::Float(BuiltinFloat { bitness: FloatBitness::X64 })), 74 (name::F64, BuiltinType::Float(BuiltinFloat::F64)),
75 ]; 75 ];
76} 76}
77 77
@@ -104,3 +104,57 @@ impl fmt::Display for BuiltinType {
104 f.write_str(type_name) 104 f.write_str(type_name)
105 } 105 }
106} 106}
107
108#[rustfmt::skip]
109impl BuiltinInt {
110 pub const ISIZE: BuiltinInt = BuiltinInt { signedness: Signedness::Signed, bitness: IntBitness::Xsize };
111 pub const I8 : BuiltinInt = BuiltinInt { signedness: Signedness::Signed, bitness: IntBitness::X8 };
112 pub const I16 : BuiltinInt = BuiltinInt { signedness: Signedness::Signed, bitness: IntBitness::X16 };
113 pub const I32 : BuiltinInt = BuiltinInt { signedness: Signedness::Signed, bitness: IntBitness::X32 };
114 pub const I64 : BuiltinInt = BuiltinInt { signedness: Signedness::Signed, bitness: IntBitness::X64 };
115 pub const I128 : BuiltinInt = BuiltinInt { signedness: Signedness::Signed, bitness: IntBitness::X128 };
116
117 pub const USIZE: BuiltinInt = BuiltinInt { signedness: Signedness::Unsigned, bitness: IntBitness::Xsize };
118 pub const U8 : BuiltinInt = BuiltinInt { signedness: Signedness::Unsigned, bitness: IntBitness::X8 };
119 pub const U16 : BuiltinInt = BuiltinInt { signedness: Signedness::Unsigned, bitness: IntBitness::X16 };
120 pub const U32 : BuiltinInt = BuiltinInt { signedness: Signedness::Unsigned, bitness: IntBitness::X32 };
121 pub const U64 : BuiltinInt = BuiltinInt { signedness: Signedness::Unsigned, bitness: IntBitness::X64 };
122 pub const U128 : BuiltinInt = BuiltinInt { signedness: Signedness::Unsigned, bitness: IntBitness::X128 };
123
124
125 pub fn from_suffix(suffix: &str) -> Option<BuiltinInt> {
126 let res = match suffix {
127 "isize" => Self::ISIZE,
128 "i8" => Self::I8,
129 "i16" => Self::I16,
130 "i32" => Self::I32,
131 "i64" => Self::I64,
132 "i128" => Self::I128,
133
134 "usize" => Self::USIZE,
135 "u8" => Self::U8,
136 "u16" => Self::U16,
137 "u32" => Self::U32,
138 "u64" => Self::U64,
139 "u128" => Self::U128,
140
141 _ => return None,
142 };
143 Some(res)
144 }
145}
146
147#[rustfmt::skip]
148impl BuiltinFloat {
149 pub const F32: BuiltinFloat = BuiltinFloat { bitness: FloatBitness::X32 };
150 pub const F64: BuiltinFloat = BuiltinFloat { bitness: FloatBitness::X64 };
151
152 pub fn from_suffix(suffix: &str) -> Option<BuiltinFloat> {
153 let res = match suffix {
154 "f32" => BuiltinFloat::F32,
155 "f64" => BuiltinFloat::F64,
156 _ => return None,
157 };
158 Some(res)
159 }
160}
diff --git a/crates/ra_hir_def/src/expr.rs b/crates/ra_hir_def/src/expr.rs
new file mode 100644
index 000000000..12eb0da68
--- /dev/null
+++ b/crates/ra_hir_def/src/expr.rs
@@ -0,0 +1,419 @@
1//! This module describes hir-level representation of expressions.
2//!
3//! This representaion is:
4//!
5//! 1. Identity-based. Each expression has an `id`, so we can distinguish
6//! between different `1` in `1 + 1`.
7//! 2. Independent of syntax. Though syntactic provenance information can be
8//! attached separately via id-based side map.
9//! 3. Unresolved. Paths are stored as sequences of names, and not as defs the
10//! names refer to.
11//! 4. Desugared. There's no `if let`.
12
13use hir_expand::name::Name;
14use ra_arena::{impl_arena_id, RawId};
15
16use crate::{
17 builtin_type::{BuiltinFloat, BuiltinInt},
18 path::{GenericArgs, Path},
19 type_ref::{Mutability, TypeRef},
20};
21
22#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
23pub struct ExprId(RawId);
24impl_arena_id!(ExprId);
25
26impl ExprId {
27 pub fn dummy() -> ExprId {
28 ExprId((!0).into())
29 }
30}
31
32#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
33pub struct PatId(RawId);
34impl_arena_id!(PatId);
35
36#[derive(Debug, Clone, Eq, PartialEq)]
37pub enum Literal {
38 String(String),
39 ByteString(Vec<u8>),
40 Char(char),
41 Bool(bool),
42 Int(u64, Option<BuiltinInt>),
43 Float(u64, Option<BuiltinFloat>), // FIXME: f64 is not Eq
44}
45
46#[derive(Debug, Clone, Eq, PartialEq)]
47pub enum Expr {
48 /// This is produced if syntax tree does not have a required expression piece.
49 Missing,
50 Path(Path),
51 If {
52 condition: ExprId,
53 then_branch: ExprId,
54 else_branch: Option<ExprId>,
55 },
56 Block {
57 statements: Vec<Statement>,
58 tail: Option<ExprId>,
59 },
60 Loop {
61 body: ExprId,
62 },
63 While {
64 condition: ExprId,
65 body: ExprId,
66 },
67 For {
68 iterable: ExprId,
69 pat: PatId,
70 body: ExprId,
71 },
72 Call {
73 callee: ExprId,
74 args: Vec<ExprId>,
75 },
76 MethodCall {
77 receiver: ExprId,
78 method_name: Name,
79 args: Vec<ExprId>,
80 generic_args: Option<GenericArgs>,
81 },
82 Match {
83 expr: ExprId,
84 arms: Vec<MatchArm>,
85 },
86 Continue,
87 Break {
88 expr: Option<ExprId>,
89 },
90 Return {
91 expr: Option<ExprId>,
92 },
93 RecordLit {
94 path: Option<Path>,
95 fields: Vec<RecordLitField>,
96 spread: Option<ExprId>,
97 },
98 Field {
99 expr: ExprId,
100 name: Name,
101 },
102 Await {
103 expr: ExprId,
104 },
105 Try {
106 expr: ExprId,
107 },
108 TryBlock {
109 body: ExprId,
110 },
111 Cast {
112 expr: ExprId,
113 type_ref: TypeRef,
114 },
115 Ref {
116 expr: ExprId,
117 mutability: Mutability,
118 },
119 Box {
120 expr: ExprId,
121 },
122 UnaryOp {
123 expr: ExprId,
124 op: UnaryOp,
125 },
126 BinaryOp {
127 lhs: ExprId,
128 rhs: ExprId,
129 op: Option<BinaryOp>,
130 },
131 Index {
132 base: ExprId,
133 index: ExprId,
134 },
135 Lambda {
136 args: Vec<PatId>,
137 arg_types: Vec<Option<TypeRef>>,
138 body: ExprId,
139 },
140 Tuple {
141 exprs: Vec<ExprId>,
142 },
143 Array(Array),
144 Literal(Literal),
145}
146
147#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
148pub enum BinaryOp {
149 LogicOp(LogicOp),
150 ArithOp(ArithOp),
151 CmpOp(CmpOp),
152 Assignment { op: Option<ArithOp> },
153}
154
155#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
156pub enum LogicOp {
157 And,
158 Or,
159}
160
161#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
162pub enum CmpOp {
163 Eq { negated: bool },
164 Ord { ordering: Ordering, strict: bool },
165}
166
167#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
168pub enum Ordering {
169 Less,
170 Greater,
171}
172
173#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
174pub enum ArithOp {
175 Add,
176 Mul,
177 Sub,
178 Div,
179 Rem,
180 Shl,
181 Shr,
182 BitXor,
183 BitOr,
184 BitAnd,
185}
186
187pub use ra_syntax::ast::PrefixOp as UnaryOp;
188#[derive(Debug, Clone, Eq, PartialEq)]
189pub enum Array {
190 ElementList(Vec<ExprId>),
191 Repeat { initializer: ExprId, repeat: ExprId },
192}
193
194#[derive(Debug, Clone, Eq, PartialEq)]
195pub struct MatchArm {
196 pub pats: Vec<PatId>,
197 pub guard: Option<ExprId>,
198 pub expr: ExprId,
199}
200
201#[derive(Debug, Clone, Eq, PartialEq)]
202pub struct RecordLitField {
203 pub name: Name,
204 pub expr: ExprId,
205}
206
207#[derive(Debug, Clone, Eq, PartialEq)]
208pub enum Statement {
209 Let { pat: PatId, type_ref: Option<TypeRef>, initializer: Option<ExprId> },
210 Expr(ExprId),
211}
212
213impl Expr {
214 pub fn walk_child_exprs(&self, mut f: impl FnMut(ExprId)) {
215 match self {
216 Expr::Missing => {}
217 Expr::Path(_) => {}
218 Expr::If { condition, then_branch, else_branch } => {
219 f(*condition);
220 f(*then_branch);
221 if let Some(else_branch) = else_branch {
222 f(*else_branch);
223 }
224 }
225 Expr::Block { statements, tail } => {
226 for stmt in statements {
227 match stmt {
228 Statement::Let { initializer, .. } => {
229 if let Some(expr) = initializer {
230 f(*expr);
231 }
232 }
233 Statement::Expr(e) => f(*e),
234 }
235 }
236 if let Some(expr) = tail {
237 f(*expr);
238 }
239 }
240 Expr::TryBlock { body } => f(*body),
241 Expr::Loop { body } => f(*body),
242 Expr::While { condition, body } => {
243 f(*condition);
244 f(*body);
245 }
246 Expr::For { iterable, body, .. } => {
247 f(*iterable);
248 f(*body);
249 }
250 Expr::Call { callee, args } => {
251 f(*callee);
252 for arg in args {
253 f(*arg);
254 }
255 }
256 Expr::MethodCall { receiver, args, .. } => {
257 f(*receiver);
258 for arg in args {
259 f(*arg);
260 }
261 }
262 Expr::Match { expr, arms } => {
263 f(*expr);
264 for arm in arms {
265 f(arm.expr);
266 }
267 }
268 Expr::Continue => {}
269 Expr::Break { expr } | Expr::Return { expr } => {
270 if let Some(expr) = expr {
271 f(*expr);
272 }
273 }
274 Expr::RecordLit { fields, spread, .. } => {
275 for field in fields {
276 f(field.expr);
277 }
278 if let Some(expr) = spread {
279 f(*expr);
280 }
281 }
282 Expr::Lambda { body, .. } => {
283 f(*body);
284 }
285 Expr::BinaryOp { lhs, rhs, .. } => {
286 f(*lhs);
287 f(*rhs);
288 }
289 Expr::Index { base, index } => {
290 f(*base);
291 f(*index);
292 }
293 Expr::Field { expr, .. }
294 | Expr::Await { expr }
295 | Expr::Try { expr }
296 | Expr::Cast { expr, .. }
297 | Expr::Ref { expr, .. }
298 | Expr::UnaryOp { expr, .. }
299 | Expr::Box { expr } => {
300 f(*expr);
301 }
302 Expr::Tuple { exprs } => {
303 for expr in exprs {
304 f(*expr);
305 }
306 }
307 Expr::Array(a) => match a {
308 Array::ElementList(exprs) => {
309 for expr in exprs {
310 f(*expr);
311 }
312 }
313 Array::Repeat { initializer, repeat } => {
314 f(*initializer);
315 f(*repeat)
316 }
317 },
318 Expr::Literal(_) => {}
319 }
320 }
321}
322
323/// Explicit binding annotations given in the HIR for a binding. Note
324/// that this is not the final binding *mode* that we infer after type
325/// inference.
326#[derive(Clone, PartialEq, Eq, Debug, Copy)]
327pub enum BindingAnnotation {
328 /// No binding annotation given: this means that the final binding mode
329 /// will depend on whether we have skipped through a `&` reference
330 /// when matching. For example, the `x` in `Some(x)` will have binding
331 /// mode `None`; if you do `let Some(x) = &Some(22)`, it will
332 /// ultimately be inferred to be by-reference.
333 Unannotated,
334
335 /// Annotated with `mut x` -- could be either ref or not, similar to `None`.
336 Mutable,
337
338 /// Annotated as `ref`, like `ref x`
339 Ref,
340
341 /// Annotated as `ref mut x`.
342 RefMut,
343}
344
345impl BindingAnnotation {
346 pub fn new(is_mutable: bool, is_ref: bool) -> Self {
347 match (is_mutable, is_ref) {
348 (true, true) => BindingAnnotation::RefMut,
349 (false, true) => BindingAnnotation::Ref,
350 (true, false) => BindingAnnotation::Mutable,
351 (false, false) => BindingAnnotation::Unannotated,
352 }
353 }
354}
355
356#[derive(Debug, Clone, Eq, PartialEq)]
357pub struct RecordFieldPat {
358 pub name: Name,
359 pub pat: PatId,
360}
361
362/// Close relative to rustc's hir::PatKind
363#[derive(Debug, Clone, Eq, PartialEq)]
364pub enum Pat {
365 Missing,
366 Wild,
367 Tuple(Vec<PatId>),
368 Record {
369 path: Option<Path>,
370 args: Vec<RecordFieldPat>,
371 // FIXME: 'ellipsis' option
372 },
373 Range {
374 start: ExprId,
375 end: ExprId,
376 },
377 Slice {
378 prefix: Vec<PatId>,
379 rest: Option<PatId>,
380 suffix: Vec<PatId>,
381 },
382 Path(Path),
383 Lit(ExprId),
384 Bind {
385 mode: BindingAnnotation,
386 name: Name,
387 subpat: Option<PatId>,
388 },
389 TupleStruct {
390 path: Option<Path>,
391 args: Vec<PatId>,
392 },
393 Ref {
394 pat: PatId,
395 mutability: Mutability,
396 },
397}
398
399impl Pat {
400 pub fn walk_child_pats(&self, mut f: impl FnMut(PatId)) {
401 match self {
402 Pat::Range { .. } | Pat::Lit(..) | Pat::Path(..) | Pat::Wild | Pat::Missing => {}
403 Pat::Bind { subpat, .. } => {
404 subpat.iter().copied().for_each(f);
405 }
406 Pat::Tuple(args) | Pat::TupleStruct { args, .. } => {
407 args.iter().copied().for_each(f);
408 }
409 Pat::Ref { pat, .. } => f(*pat),
410 Pat::Slice { prefix, rest, suffix } => {
411 let total_iter = prefix.iter().chain(rest.iter()).chain(suffix.iter());
412 total_iter.copied().for_each(f);
413 }
414 Pat::Record { args, .. } => {
415 args.iter().map(|f| f.pat).for_each(f);
416 }
417 }
418 }
419}
diff --git a/crates/ra_hir_def/src/lib.rs b/crates/ra_hir_def/src/lib.rs
index 239317efe..4a758bb83 100644
--- a/crates/ra_hir_def/src/lib.rs
+++ b/crates/ra_hir_def/src/lib.rs
@@ -14,6 +14,8 @@ pub mod type_ref;
14pub mod builtin_type; 14pub mod builtin_type;
15pub mod adt; 15pub mod adt;
16pub mod diagnostics; 16pub mod diagnostics;
17pub mod expr;
18pub mod body;
17 19
18#[cfg(test)] 20#[cfg(test)]
19mod test_db; 21mod test_db;