]> git.lizzy.rs Git - rust.git/blob - src/tools/rust-analyzer/crates/hir-def/src/expr.rs
Rollup merge of #101176 - notriddle:notriddle/rustdoc-table-display, r=jsha
[rust.git] / src / tools / rust-analyzer / crates / hir-def / src / expr.rs
1 //! This module describes hir-level representation of expressions.
2 //!
3 //! This representation 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 //!
13 //! See also a neighboring `body` module.
14
15 use std::fmt;
16
17 use hir_expand::name::Name;
18 use la_arena::{Idx, RawIdx};
19
20 use crate::{
21     builtin_type::{BuiltinFloat, BuiltinInt, BuiltinUint},
22     intern::Interned,
23     path::{GenericArgs, Path},
24     type_ref::{Mutability, Rawness, TypeRef},
25     BlockId,
26 };
27
28 pub use syntax::ast::{ArithOp, BinaryOp, CmpOp, LogicOp, Ordering, RangeOp, UnaryOp};
29
30 pub type ExprId = Idx<Expr>;
31
32 /// FIXME: this is a hacky function which should be removed
33 pub(crate) fn dummy_expr_id() -> ExprId {
34     ExprId::from_raw(RawIdx::from(u32::MAX))
35 }
36
37 pub type PatId = Idx<Pat>;
38
39 #[derive(Debug, Clone, Eq, PartialEq)]
40 pub struct Label {
41     pub name: Name,
42 }
43 pub type LabelId = Idx<Label>;
44
45 // We convert float values into bits and that's how we don't need to deal with f32 and f64.
46 // For PartialEq, bits comparison should work, as ordering is not important
47 // https://github.com/rust-lang/rust-analyzer/issues/12380#issuecomment-1137284360
48 #[derive(Default, Debug, Clone, Eq, PartialEq)]
49 pub struct FloatTypeWrapper(u64);
50
51 impl FloatTypeWrapper {
52     pub fn new(value: f64) -> Self {
53         Self(value.to_bits())
54     }
55 }
56
57 impl fmt::Display for FloatTypeWrapper {
58     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
59         write!(f, "{:?}", f64::from_bits(self.0))
60     }
61 }
62
63 #[derive(Debug, Clone, Eq, PartialEq)]
64 pub enum Literal {
65     String(Box<str>),
66     ByteString(Box<[u8]>),
67     Char(char),
68     Bool(bool),
69     Int(i128, Option<BuiltinInt>),
70     Uint(u128, Option<BuiltinUint>),
71     // Here we are using a wrapper around float because f32 and f64 do not implement Eq, so they
72     // could not be used directly here, to understand how the wrapper works go to definition of
73     // FloatTypeWrapper
74     Float(FloatTypeWrapper, Option<BuiltinFloat>),
75 }
76
77 #[derive(Debug, Clone, Eq, PartialEq)]
78 pub enum Expr {
79     /// This is produced if the syntax tree does not have a required expression piece.
80     Missing,
81     Path(Path),
82     If {
83         condition: ExprId,
84         then_branch: ExprId,
85         else_branch: Option<ExprId>,
86     },
87     Let {
88         pat: PatId,
89         expr: ExprId,
90     },
91     Block {
92         id: BlockId,
93         statements: Box<[Statement]>,
94         tail: Option<ExprId>,
95         label: Option<LabelId>,
96     },
97     Loop {
98         body: ExprId,
99         label: Option<LabelId>,
100     },
101     While {
102         condition: ExprId,
103         body: ExprId,
104         label: Option<LabelId>,
105     },
106     For {
107         iterable: ExprId,
108         pat: PatId,
109         body: ExprId,
110         label: Option<LabelId>,
111     },
112     Call {
113         callee: ExprId,
114         args: Box<[ExprId]>,
115         is_assignee_expr: bool,
116     },
117     MethodCall {
118         receiver: ExprId,
119         method_name: Name,
120         args: Box<[ExprId]>,
121         generic_args: Option<Box<GenericArgs>>,
122     },
123     Match {
124         expr: ExprId,
125         arms: Box<[MatchArm]>,
126     },
127     Continue {
128         label: Option<Name>,
129     },
130     Break {
131         expr: Option<ExprId>,
132         label: Option<Name>,
133     },
134     Return {
135         expr: Option<ExprId>,
136     },
137     Yield {
138         expr: Option<ExprId>,
139     },
140     RecordLit {
141         path: Option<Box<Path>>,
142         fields: Box<[RecordLitField]>,
143         spread: Option<ExprId>,
144         ellipsis: bool,
145         is_assignee_expr: bool,
146     },
147     Field {
148         expr: ExprId,
149         name: Name,
150     },
151     Await {
152         expr: ExprId,
153     },
154     Try {
155         expr: ExprId,
156     },
157     TryBlock {
158         body: ExprId,
159     },
160     Async {
161         body: ExprId,
162     },
163     Const {
164         body: ExprId,
165     },
166     Cast {
167         expr: ExprId,
168         type_ref: Interned<TypeRef>,
169     },
170     Ref {
171         expr: ExprId,
172         rawness: Rawness,
173         mutability: Mutability,
174     },
175     Box {
176         expr: ExprId,
177     },
178     UnaryOp {
179         expr: ExprId,
180         op: UnaryOp,
181     },
182     BinaryOp {
183         lhs: ExprId,
184         rhs: ExprId,
185         op: Option<BinaryOp>,
186     },
187     Range {
188         lhs: Option<ExprId>,
189         rhs: Option<ExprId>,
190         range_type: RangeOp,
191     },
192     Index {
193         base: ExprId,
194         index: ExprId,
195     },
196     Closure {
197         args: Box<[PatId]>,
198         arg_types: Box<[Option<Interned<TypeRef>>]>,
199         ret_type: Option<Interned<TypeRef>>,
200         body: ExprId,
201     },
202     Tuple {
203         exprs: Box<[ExprId]>,
204         is_assignee_expr: bool,
205     },
206     Unsafe {
207         body: ExprId,
208     },
209     MacroStmts {
210         statements: Box<[Statement]>,
211         tail: Option<ExprId>,
212     },
213     Array(Array),
214     Literal(Literal),
215     Underscore,
216 }
217
218 #[derive(Debug, Clone, Eq, PartialEq)]
219 pub enum Array {
220     ElementList { elements: Box<[ExprId]>, is_assignee_expr: bool },
221     Repeat { initializer: ExprId, repeat: ExprId },
222 }
223
224 #[derive(Debug, Clone, Eq, PartialEq)]
225 pub struct MatchArm {
226     pub pat: PatId,
227     pub guard: Option<ExprId>,
228     pub expr: ExprId,
229 }
230
231 #[derive(Debug, Clone, Eq, PartialEq)]
232 pub struct RecordLitField {
233     pub name: Name,
234     pub expr: ExprId,
235 }
236
237 #[derive(Debug, Clone, Eq, PartialEq)]
238 pub enum Statement {
239     Let {
240         pat: PatId,
241         type_ref: Option<Interned<TypeRef>>,
242         initializer: Option<ExprId>,
243         else_branch: Option<ExprId>,
244     },
245     Expr {
246         expr: ExprId,
247         has_semi: bool,
248     },
249 }
250
251 impl Expr {
252     pub fn walk_child_exprs(&self, mut f: impl FnMut(ExprId)) {
253         match self {
254             Expr::Missing => {}
255             Expr::Path(_) => {}
256             Expr::If { condition, then_branch, else_branch } => {
257                 f(*condition);
258                 f(*then_branch);
259                 if let &Some(else_branch) = else_branch {
260                     f(else_branch);
261                 }
262             }
263             Expr::Let { expr, .. } => {
264                 f(*expr);
265             }
266             Expr::MacroStmts { tail, statements } | Expr::Block { statements, tail, .. } => {
267                 for stmt in statements.iter() {
268                     match stmt {
269                         Statement::Let { initializer, .. } => {
270                             if let &Some(expr) = initializer {
271                                 f(expr);
272                             }
273                         }
274                         Statement::Expr { expr: expression, .. } => f(*expression),
275                     }
276                 }
277                 if let &Some(expr) = tail {
278                     f(expr);
279                 }
280             }
281             Expr::TryBlock { body }
282             | Expr::Unsafe { body }
283             | Expr::Async { body }
284             | Expr::Const { body } => f(*body),
285             Expr::Loop { body, .. } => f(*body),
286             Expr::While { condition, body, .. } => {
287                 f(*condition);
288                 f(*body);
289             }
290             Expr::For { iterable, body, .. } => {
291                 f(*iterable);
292                 f(*body);
293             }
294             Expr::Call { callee, args, .. } => {
295                 f(*callee);
296                 args.iter().copied().for_each(f);
297             }
298             Expr::MethodCall { receiver, args, .. } => {
299                 f(*receiver);
300                 args.iter().copied().for_each(f);
301             }
302             Expr::Match { expr, arms } => {
303                 f(*expr);
304                 arms.iter().map(|arm| arm.expr).for_each(f);
305             }
306             Expr::Continue { .. } => {}
307             Expr::Break { expr, .. } | Expr::Return { expr } | Expr::Yield { expr } => {
308                 if let &Some(expr) = expr {
309                     f(expr);
310                 }
311             }
312             Expr::RecordLit { fields, spread, .. } => {
313                 for field in fields.iter() {
314                     f(field.expr);
315                 }
316                 if let &Some(expr) = spread {
317                     f(expr);
318                 }
319             }
320             Expr::Closure { body, .. } => {
321                 f(*body);
322             }
323             Expr::BinaryOp { lhs, rhs, .. } => {
324                 f(*lhs);
325                 f(*rhs);
326             }
327             Expr::Range { lhs, rhs, .. } => {
328                 if let &Some(lhs) = rhs {
329                     f(lhs);
330                 }
331                 if let &Some(rhs) = lhs {
332                     f(rhs);
333                 }
334             }
335             Expr::Index { base, index } => {
336                 f(*base);
337                 f(*index);
338             }
339             Expr::Field { expr, .. }
340             | Expr::Await { expr }
341             | Expr::Try { expr }
342             | Expr::Cast { expr, .. }
343             | Expr::Ref { expr, .. }
344             | Expr::UnaryOp { expr, .. }
345             | Expr::Box { expr } => {
346                 f(*expr);
347             }
348             Expr::Tuple { exprs, .. } => exprs.iter().copied().for_each(f),
349             Expr::Array(a) => match a {
350                 Array::ElementList { elements, .. } => elements.iter().copied().for_each(f),
351                 Array::Repeat { initializer, repeat } => {
352                     f(*initializer);
353                     f(*repeat)
354                 }
355             },
356             Expr::Literal(_) => {}
357             Expr::Underscore => {}
358         }
359     }
360 }
361
362 /// Explicit binding annotations given in the HIR for a binding. Note
363 /// that this is not the final binding *mode* that we infer after type
364 /// inference.
365 #[derive(Clone, PartialEq, Eq, Debug, Copy)]
366 pub enum BindingAnnotation {
367     /// No binding annotation given: this means that the final binding mode
368     /// will depend on whether we have skipped through a `&` reference
369     /// when matching. For example, the `x` in `Some(x)` will have binding
370     /// mode `None`; if you do `let Some(x) = &Some(22)`, it will
371     /// ultimately be inferred to be by-reference.
372     Unannotated,
373
374     /// Annotated with `mut x` -- could be either ref or not, similar to `None`.
375     Mutable,
376
377     /// Annotated as `ref`, like `ref x`
378     Ref,
379
380     /// Annotated as `ref mut x`.
381     RefMut,
382 }
383
384 impl BindingAnnotation {
385     pub fn new(is_mutable: bool, is_ref: bool) -> Self {
386         match (is_mutable, is_ref) {
387             (true, true) => BindingAnnotation::RefMut,
388             (false, true) => BindingAnnotation::Ref,
389             (true, false) => BindingAnnotation::Mutable,
390             (false, false) => BindingAnnotation::Unannotated,
391         }
392     }
393 }
394
395 #[derive(Debug, Clone, Eq, PartialEq)]
396 pub struct RecordFieldPat {
397     pub name: Name,
398     pub pat: PatId,
399 }
400
401 /// Close relative to rustc's hir::PatKind
402 #[derive(Debug, Clone, Eq, PartialEq)]
403 pub enum Pat {
404     Missing,
405     Wild,
406     Tuple { args: Box<[PatId]>, ellipsis: Option<usize> },
407     Or(Box<[PatId]>),
408     Record { path: Option<Box<Path>>, args: Box<[RecordFieldPat]>, ellipsis: bool },
409     Range { start: ExprId, end: ExprId },
410     Slice { prefix: Box<[PatId]>, slice: Option<PatId>, suffix: Box<[PatId]> },
411     Path(Box<Path>),
412     Lit(ExprId),
413     Bind { mode: BindingAnnotation, name: Name, subpat: Option<PatId> },
414     TupleStruct { path: Option<Box<Path>>, args: Box<[PatId]>, ellipsis: Option<usize> },
415     Ref { pat: PatId, mutability: Mutability },
416     Box { inner: PatId },
417     ConstBlock(ExprId),
418 }
419
420 impl Pat {
421     pub fn walk_child_pats(&self, mut f: impl FnMut(PatId)) {
422         match self {
423             Pat::Range { .. }
424             | Pat::Lit(..)
425             | Pat::Path(..)
426             | Pat::ConstBlock(..)
427             | Pat::Wild
428             | Pat::Missing => {}
429             Pat::Bind { subpat, .. } => {
430                 subpat.iter().copied().for_each(f);
431             }
432             Pat::Or(args) | Pat::Tuple { args, .. } | Pat::TupleStruct { args, .. } => {
433                 args.iter().copied().for_each(f);
434             }
435             Pat::Ref { pat, .. } => f(*pat),
436             Pat::Slice { prefix, slice, suffix } => {
437                 let total_iter = prefix.iter().chain(slice.iter()).chain(suffix.iter());
438                 total_iter.copied().for_each(f);
439             }
440             Pat::Record { args, .. } => {
441                 args.iter().map(|f| f.pat).for_each(f);
442             }
443             Pat::Box { inner } => f(*inner),
444         }
445     }
446 }