]> git.lizzy.rs Git - rust.git/blob - src/tools/rust-analyzer/crates/hir-def/src/expr.rs
Auto merge of #100502 - chenyukang:fix-100478, r=jackh726
[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     Array(Array),
210     Literal(Literal),
211     Underscore,
212 }
213
214 #[derive(Debug, Clone, Eq, PartialEq)]
215 pub enum Array {
216     ElementList { elements: Box<[ExprId]>, is_assignee_expr: bool },
217     Repeat { initializer: ExprId, repeat: ExprId },
218 }
219
220 #[derive(Debug, Clone, Eq, PartialEq)]
221 pub struct MatchArm {
222     pub pat: PatId,
223     pub guard: Option<ExprId>,
224     pub expr: ExprId,
225 }
226
227 #[derive(Debug, Clone, Eq, PartialEq)]
228 pub struct RecordLitField {
229     pub name: Name,
230     pub expr: ExprId,
231 }
232
233 #[derive(Debug, Clone, Eq, PartialEq)]
234 pub enum Statement {
235     Let {
236         pat: PatId,
237         type_ref: Option<Interned<TypeRef>>,
238         initializer: Option<ExprId>,
239         else_branch: Option<ExprId>,
240     },
241     Expr {
242         expr: ExprId,
243         has_semi: bool,
244     },
245 }
246
247 impl Expr {
248     pub fn walk_child_exprs(&self, mut f: impl FnMut(ExprId)) {
249         match self {
250             Expr::Missing => {}
251             Expr::Path(_) => {}
252             Expr::If { condition, then_branch, else_branch } => {
253                 f(*condition);
254                 f(*then_branch);
255                 if let &Some(else_branch) = else_branch {
256                     f(else_branch);
257                 }
258             }
259             Expr::Let { expr, .. } => {
260                 f(*expr);
261             }
262             Expr::Block { statements, tail, .. } => {
263                 for stmt in statements.iter() {
264                     match stmt {
265                         Statement::Let { initializer, .. } => {
266                             if let &Some(expr) = initializer {
267                                 f(expr);
268                             }
269                         }
270                         Statement::Expr { expr: expression, .. } => f(*expression),
271                     }
272                 }
273                 if let &Some(expr) = tail {
274                     f(expr);
275                 }
276             }
277             Expr::TryBlock { body }
278             | Expr::Unsafe { body }
279             | Expr::Async { body }
280             | Expr::Const { body } => f(*body),
281             Expr::Loop { body, .. } => f(*body),
282             Expr::While { condition, body, .. } => {
283                 f(*condition);
284                 f(*body);
285             }
286             Expr::For { iterable, body, .. } => {
287                 f(*iterable);
288                 f(*body);
289             }
290             Expr::Call { callee, args, .. } => {
291                 f(*callee);
292                 args.iter().copied().for_each(f);
293             }
294             Expr::MethodCall { receiver, args, .. } => {
295                 f(*receiver);
296                 args.iter().copied().for_each(f);
297             }
298             Expr::Match { expr, arms } => {
299                 f(*expr);
300                 arms.iter().map(|arm| arm.expr).for_each(f);
301             }
302             Expr::Continue { .. } => {}
303             Expr::Break { expr, .. } | Expr::Return { expr } | Expr::Yield { expr } => {
304                 if let &Some(expr) = expr {
305                     f(expr);
306                 }
307             }
308             Expr::RecordLit { fields, spread, .. } => {
309                 for field in fields.iter() {
310                     f(field.expr);
311                 }
312                 if let &Some(expr) = spread {
313                     f(expr);
314                 }
315             }
316             Expr::Closure { body, .. } => {
317                 f(*body);
318             }
319             Expr::BinaryOp { lhs, rhs, .. } => {
320                 f(*lhs);
321                 f(*rhs);
322             }
323             Expr::Range { lhs, rhs, .. } => {
324                 if let &Some(lhs) = rhs {
325                     f(lhs);
326                 }
327                 if let &Some(rhs) = lhs {
328                     f(rhs);
329                 }
330             }
331             Expr::Index { base, index } => {
332                 f(*base);
333                 f(*index);
334             }
335             Expr::Field { expr, .. }
336             | Expr::Await { expr }
337             | Expr::Try { expr }
338             | Expr::Cast { expr, .. }
339             | Expr::Ref { expr, .. }
340             | Expr::UnaryOp { expr, .. }
341             | Expr::Box { expr } => {
342                 f(*expr);
343             }
344             Expr::Tuple { exprs, .. } => exprs.iter().copied().for_each(f),
345             Expr::Array(a) => match a {
346                 Array::ElementList { elements, .. } => elements.iter().copied().for_each(f),
347                 Array::Repeat { initializer, repeat } => {
348                     f(*initializer);
349                     f(*repeat)
350                 }
351             },
352             Expr::Literal(_) => {}
353             Expr::Underscore => {}
354         }
355     }
356 }
357
358 /// Explicit binding annotations given in the HIR for a binding. Note
359 /// that this is not the final binding *mode* that we infer after type
360 /// inference.
361 #[derive(Clone, PartialEq, Eq, Debug, Copy)]
362 pub enum BindingAnnotation {
363     /// No binding annotation given: this means that the final binding mode
364     /// will depend on whether we have skipped through a `&` reference
365     /// when matching. For example, the `x` in `Some(x)` will have binding
366     /// mode `None`; if you do `let Some(x) = &Some(22)`, it will
367     /// ultimately be inferred to be by-reference.
368     Unannotated,
369
370     /// Annotated with `mut x` -- could be either ref or not, similar to `None`.
371     Mutable,
372
373     /// Annotated as `ref`, like `ref x`
374     Ref,
375
376     /// Annotated as `ref mut x`.
377     RefMut,
378 }
379
380 impl BindingAnnotation {
381     pub fn new(is_mutable: bool, is_ref: bool) -> Self {
382         match (is_mutable, is_ref) {
383             (true, true) => BindingAnnotation::RefMut,
384             (false, true) => BindingAnnotation::Ref,
385             (true, false) => BindingAnnotation::Mutable,
386             (false, false) => BindingAnnotation::Unannotated,
387         }
388     }
389 }
390
391 #[derive(Debug, Clone, Eq, PartialEq)]
392 pub struct RecordFieldPat {
393     pub name: Name,
394     pub pat: PatId,
395 }
396
397 /// Close relative to rustc's hir::PatKind
398 #[derive(Debug, Clone, Eq, PartialEq)]
399 pub enum Pat {
400     Missing,
401     Wild,
402     Tuple { args: Box<[PatId]>, ellipsis: Option<usize> },
403     Or(Box<[PatId]>),
404     Record { path: Option<Box<Path>>, args: Box<[RecordFieldPat]>, ellipsis: bool },
405     Range { start: ExprId, end: ExprId },
406     Slice { prefix: Box<[PatId]>, slice: Option<PatId>, suffix: Box<[PatId]> },
407     Path(Box<Path>),
408     Lit(ExprId),
409     Bind { mode: BindingAnnotation, name: Name, subpat: Option<PatId> },
410     TupleStruct { path: Option<Box<Path>>, args: Box<[PatId]>, ellipsis: Option<usize> },
411     Ref { pat: PatId, mutability: Mutability },
412     Box { inner: PatId },
413     ConstBlock(ExprId),
414 }
415
416 impl Pat {
417     pub fn walk_child_pats(&self, mut f: impl FnMut(PatId)) {
418         match self {
419             Pat::Range { .. }
420             | Pat::Lit(..)
421             | Pat::Path(..)
422             | Pat::ConstBlock(..)
423             | Pat::Wild
424             | Pat::Missing => {}
425             Pat::Bind { subpat, .. } => {
426                 subpat.iter().copied().for_each(f);
427             }
428             Pat::Or(args) | Pat::Tuple { args, .. } | Pat::TupleStruct { args, .. } => {
429                 args.iter().copied().for_each(f);
430             }
431             Pat::Ref { pat, .. } => f(*pat),
432             Pat::Slice { prefix, slice, suffix } => {
433                 let total_iter = prefix.iter().chain(slice.iter()).chain(suffix.iter());
434                 total_iter.copied().for_each(f);
435             }
436             Pat::Record { args, .. } => {
437                 args.iter().map(|f| f.pat).for_each(f);
438             }
439             Pat::Box { inner } => f(*inner),
440         }
441     }
442 }