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