• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 pub mod type_ref;
16 
17 use std::fmt;
18 
19 use hir_expand::name::Name;
20 use intern::Interned;
21 use la_arena::{Idx, RawIdx};
22 use smallvec::SmallVec;
23 use syntax::ast;
24 
25 use crate::{
26     builtin_type::{BuiltinFloat, BuiltinInt, BuiltinUint},
27     path::{GenericArgs, Path},
28     type_ref::{Mutability, Rawness, TypeRef},
29     BlockId, ConstBlockId,
30 };
31 
32 pub use syntax::ast::{ArithOp, BinaryOp, CmpOp, LogicOp, Ordering, RangeOp, UnaryOp};
33 
34 pub type BindingId = Idx<Binding>;
35 
36 pub type ExprId = Idx<Expr>;
37 
38 /// FIXME: this is a hacky function which should be removed
dummy_expr_id() -> ExprId39 pub(crate) fn dummy_expr_id() -> ExprId {
40     ExprId::from_raw(RawIdx::from(u32::MAX))
41 }
42 
43 pub type PatId = Idx<Pat>;
44 
45 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
46 pub enum ExprOrPatId {
47     ExprId(ExprId),
48     PatId(PatId),
49 }
50 stdx::impl_from!(ExprId, PatId for ExprOrPatId);
51 
52 #[derive(Debug, Clone, Eq, PartialEq)]
53 pub struct Label {
54     pub name: Name,
55 }
56 pub type LabelId = Idx<Label>;
57 
58 // We convert float values into bits and that's how we don't need to deal with f32 and f64.
59 // For PartialEq, bits comparison should work, as ordering is not important
60 // https://github.com/rust-lang/rust-analyzer/issues/12380#issuecomment-1137284360
61 #[derive(Default, Debug, Clone, Copy, Eq, PartialEq)]
62 pub struct FloatTypeWrapper(u64);
63 
64 impl FloatTypeWrapper {
new(value: f64) -> Self65     pub fn new(value: f64) -> Self {
66         Self(value.to_bits())
67     }
68 
into_f64(self) -> f6469     pub fn into_f64(self) -> f64 {
70         f64::from_bits(self.0)
71     }
72 
into_f32(self) -> f3273     pub fn into_f32(self) -> f32 {
74         f64::from_bits(self.0) as f32
75     }
76 }
77 
78 impl fmt::Display for FloatTypeWrapper {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result79     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
80         write!(f, "{:?}", f64::from_bits(self.0))
81     }
82 }
83 
84 #[derive(Debug, Clone, Eq, PartialEq)]
85 pub enum Literal {
86     String(Box<str>),
87     ByteString(Box<[u8]>),
88     CString(Box<str>),
89     Char(char),
90     Bool(bool),
91     Int(i128, Option<BuiltinInt>),
92     Uint(u128, Option<BuiltinUint>),
93     // Here we are using a wrapper around float because f32 and f64 do not implement Eq, so they
94     // could not be used directly here, to understand how the wrapper works go to definition of
95     // FloatTypeWrapper
96     Float(FloatTypeWrapper, Option<BuiltinFloat>),
97 }
98 
99 #[derive(Debug, Clone, Eq, PartialEq)]
100 /// Used in range patterns.
101 pub enum LiteralOrConst {
102     Literal(Literal),
103     Const(Path),
104 }
105 
106 impl Literal {
negate(self) -> Option<Self>107     pub fn negate(self) -> Option<Self> {
108         if let Literal::Int(i, k) = self {
109             Some(Literal::Int(-i, k))
110         } else {
111             None
112         }
113     }
114 }
115 
116 impl From<ast::LiteralKind> for Literal {
from(ast_lit_kind: ast::LiteralKind) -> Self117     fn from(ast_lit_kind: ast::LiteralKind) -> Self {
118         use ast::LiteralKind;
119         match ast_lit_kind {
120             // FIXME: these should have actual values filled in, but unsure on perf impact
121             LiteralKind::IntNumber(lit) => {
122                 if let builtin @ Some(_) = lit.suffix().and_then(BuiltinFloat::from_suffix) {
123                     Literal::Float(
124                         FloatTypeWrapper::new(lit.float_value().unwrap_or(Default::default())),
125                         builtin,
126                     )
127                 } else if let builtin @ Some(_) = lit.suffix().and_then(BuiltinUint::from_suffix) {
128                     Literal::Uint(lit.value().unwrap_or(0), builtin)
129                 } else {
130                     let builtin = lit.suffix().and_then(BuiltinInt::from_suffix);
131                     Literal::Int(lit.value().unwrap_or(0) as i128, builtin)
132                 }
133             }
134             LiteralKind::FloatNumber(lit) => {
135                 let ty = lit.suffix().and_then(BuiltinFloat::from_suffix);
136                 Literal::Float(FloatTypeWrapper::new(lit.value().unwrap_or(Default::default())), ty)
137             }
138             LiteralKind::ByteString(bs) => {
139                 let text = bs.value().map(Box::from).unwrap_or_else(Default::default);
140                 Literal::ByteString(text)
141             }
142             LiteralKind::String(s) => {
143                 let text = s.value().map(Box::from).unwrap_or_else(Default::default);
144                 Literal::String(text)
145             }
146             LiteralKind::CString(s) => {
147                 let text = s.value().map(Box::from).unwrap_or_else(Default::default);
148                 Literal::CString(text)
149             }
150             LiteralKind::Byte(b) => {
151                 Literal::Uint(b.value().unwrap_or_default() as u128, Some(BuiltinUint::U8))
152             }
153             LiteralKind::Char(c) => Literal::Char(c.value().unwrap_or_default()),
154             LiteralKind::Bool(val) => Literal::Bool(val),
155         }
156     }
157 }
158 
159 #[derive(Debug, Clone, Eq, PartialEq)]
160 pub enum Expr {
161     /// This is produced if the syntax tree does not have a required expression piece.
162     Missing,
163     Path(Path),
164     If {
165         condition: ExprId,
166         then_branch: ExprId,
167         else_branch: Option<ExprId>,
168     },
169     Let {
170         pat: PatId,
171         expr: ExprId,
172     },
173     Block {
174         id: Option<BlockId>,
175         statements: Box<[Statement]>,
176         tail: Option<ExprId>,
177         label: Option<LabelId>,
178     },
179     Async {
180         id: Option<BlockId>,
181         statements: Box<[Statement]>,
182         tail: Option<ExprId>,
183     },
184     Const(ConstBlockId),
185     Unsafe {
186         id: Option<BlockId>,
187         statements: Box<[Statement]>,
188         tail: Option<ExprId>,
189     },
190     Loop {
191         body: ExprId,
192         label: Option<LabelId>,
193     },
194     While {
195         condition: ExprId,
196         body: ExprId,
197         label: Option<LabelId>,
198     },
199     Call {
200         callee: ExprId,
201         args: Box<[ExprId]>,
202         is_assignee_expr: bool,
203     },
204     MethodCall {
205         receiver: ExprId,
206         method_name: Name,
207         args: Box<[ExprId]>,
208         generic_args: Option<Box<GenericArgs>>,
209     },
210     Match {
211         expr: ExprId,
212         arms: Box<[MatchArm]>,
213     },
214     Continue {
215         label: Option<LabelId>,
216     },
217     Break {
218         expr: Option<ExprId>,
219         label: Option<LabelId>,
220     },
221     Return {
222         expr: Option<ExprId>,
223     },
224     Yield {
225         expr: Option<ExprId>,
226     },
227     Yeet {
228         expr: Option<ExprId>,
229     },
230     RecordLit {
231         path: Option<Box<Path>>,
232         fields: Box<[RecordLitField]>,
233         spread: Option<ExprId>,
234         ellipsis: bool,
235         is_assignee_expr: bool,
236     },
237     Field {
238         expr: ExprId,
239         name: Name,
240     },
241     Await {
242         expr: ExprId,
243     },
244     Cast {
245         expr: ExprId,
246         type_ref: Interned<TypeRef>,
247     },
248     Ref {
249         expr: ExprId,
250         rawness: Rawness,
251         mutability: Mutability,
252     },
253     Box {
254         expr: ExprId,
255     },
256     UnaryOp {
257         expr: ExprId,
258         op: UnaryOp,
259     },
260     BinaryOp {
261         lhs: ExprId,
262         rhs: ExprId,
263         op: Option<BinaryOp>,
264     },
265     Range {
266         lhs: Option<ExprId>,
267         rhs: Option<ExprId>,
268         range_type: RangeOp,
269     },
270     Index {
271         base: ExprId,
272         index: ExprId,
273     },
274     Closure {
275         args: Box<[PatId]>,
276         arg_types: Box<[Option<Interned<TypeRef>>]>,
277         ret_type: Option<Interned<TypeRef>>,
278         body: ExprId,
279         closure_kind: ClosureKind,
280         capture_by: CaptureBy,
281     },
282     Tuple {
283         exprs: Box<[ExprId]>,
284         is_assignee_expr: bool,
285     },
286     Array(Array),
287     Literal(Literal),
288     Underscore,
289 }
290 
291 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
292 pub enum ClosureKind {
293     Closure,
294     Generator(Movability),
295     Async,
296 }
297 
298 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
299 pub enum CaptureBy {
300     /// `move |x| y + x`.
301     Value,
302     /// `move` keyword was not specified.
303     Ref,
304 }
305 
306 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
307 pub enum Movability {
308     Static,
309     Movable,
310 }
311 
312 #[derive(Debug, Clone, Eq, PartialEq)]
313 pub enum Array {
314     ElementList { elements: Box<[ExprId]>, is_assignee_expr: bool },
315     Repeat { initializer: ExprId, repeat: ExprId },
316 }
317 
318 #[derive(Debug, Clone, Eq, PartialEq)]
319 pub struct MatchArm {
320     pub pat: PatId,
321     pub guard: Option<ExprId>,
322     pub expr: ExprId,
323 }
324 
325 #[derive(Debug, Clone, Eq, PartialEq)]
326 pub struct RecordLitField {
327     pub name: Name,
328     pub expr: ExprId,
329 }
330 
331 #[derive(Debug, Clone, Eq, PartialEq)]
332 pub enum Statement {
333     Let {
334         pat: PatId,
335         type_ref: Option<Interned<TypeRef>>,
336         initializer: Option<ExprId>,
337         else_branch: Option<ExprId>,
338     },
339     Expr {
340         expr: ExprId,
341         has_semi: bool,
342     },
343 }
344 
345 impl Expr {
walk_child_exprs(&self, mut f: impl FnMut(ExprId))346     pub fn walk_child_exprs(&self, mut f: impl FnMut(ExprId)) {
347         match self {
348             Expr::Missing => {}
349             Expr::Path(_) => {}
350             Expr::If { condition, then_branch, else_branch } => {
351                 f(*condition);
352                 f(*then_branch);
353                 if let &Some(else_branch) = else_branch {
354                     f(else_branch);
355                 }
356             }
357             Expr::Let { expr, .. } => {
358                 f(*expr);
359             }
360             Expr::Const(_) => (),
361             Expr::Block { statements, tail, .. }
362             | Expr::Unsafe { statements, tail, .. }
363             | Expr::Async { statements, tail, .. } => {
364                 for stmt in statements.iter() {
365                     match stmt {
366                         Statement::Let { initializer, else_branch, .. } => {
367                             if let &Some(expr) = initializer {
368                                 f(expr);
369                             }
370                             if let &Some(expr) = else_branch {
371                                 f(expr);
372                             }
373                         }
374                         Statement::Expr { expr: expression, .. } => f(*expression),
375                     }
376                 }
377                 if let &Some(expr) = tail {
378                     f(expr);
379                 }
380             }
381             Expr::Loop { body, .. } => f(*body),
382             Expr::While { condition, body, .. } => {
383                 f(*condition);
384                 f(*body);
385             }
386             Expr::Call { callee, args, .. } => {
387                 f(*callee);
388                 args.iter().copied().for_each(f);
389             }
390             Expr::MethodCall { receiver, args, .. } => {
391                 f(*receiver);
392                 args.iter().copied().for_each(f);
393             }
394             Expr::Match { expr, arms } => {
395                 f(*expr);
396                 arms.iter().map(|arm| arm.expr).for_each(f);
397             }
398             Expr::Continue { .. } => {}
399             Expr::Break { expr, .. }
400             | Expr::Return { expr }
401             | Expr::Yield { expr }
402             | Expr::Yeet { expr } => {
403                 if let &Some(expr) = expr {
404                     f(expr);
405                 }
406             }
407             Expr::RecordLit { fields, spread, .. } => {
408                 for field in fields.iter() {
409                     f(field.expr);
410                 }
411                 if let &Some(expr) = spread {
412                     f(expr);
413                 }
414             }
415             Expr::Closure { body, .. } => {
416                 f(*body);
417             }
418             Expr::BinaryOp { lhs, rhs, .. } => {
419                 f(*lhs);
420                 f(*rhs);
421             }
422             Expr::Range { lhs, rhs, .. } => {
423                 if let &Some(lhs) = rhs {
424                     f(lhs);
425                 }
426                 if let &Some(rhs) = lhs {
427                     f(rhs);
428                 }
429             }
430             Expr::Index { base, index } => {
431                 f(*base);
432                 f(*index);
433             }
434             Expr::Field { expr, .. }
435             | Expr::Await { expr }
436             | Expr::Cast { expr, .. }
437             | Expr::Ref { expr, .. }
438             | Expr::UnaryOp { expr, .. }
439             | Expr::Box { expr } => {
440                 f(*expr);
441             }
442             Expr::Tuple { exprs, .. } => exprs.iter().copied().for_each(f),
443             Expr::Array(a) => match a {
444                 Array::ElementList { elements, .. } => elements.iter().copied().for_each(f),
445                 Array::Repeat { initializer, repeat } => {
446                     f(*initializer);
447                     f(*repeat)
448                 }
449             },
450             Expr::Literal(_) => {}
451             Expr::Underscore => {}
452         }
453     }
454 }
455 
456 /// Explicit binding annotations given in the HIR for a binding. Note
457 /// that this is not the final binding *mode* that we infer after type
458 /// inference.
459 #[derive(Clone, PartialEq, Eq, Debug, Copy)]
460 pub enum BindingAnnotation {
461     /// No binding annotation given: this means that the final binding mode
462     /// will depend on whether we have skipped through a `&` reference
463     /// when matching. For example, the `x` in `Some(x)` will have binding
464     /// mode `None`; if you do `let Some(x) = &Some(22)`, it will
465     /// ultimately be inferred to be by-reference.
466     Unannotated,
467 
468     /// Annotated with `mut x` -- could be either ref or not, similar to `None`.
469     Mutable,
470 
471     /// Annotated as `ref`, like `ref x`
472     Ref,
473 
474     /// Annotated as `ref mut x`.
475     RefMut,
476 }
477 
478 impl BindingAnnotation {
new(is_mutable: bool, is_ref: bool) -> Self479     pub fn new(is_mutable: bool, is_ref: bool) -> Self {
480         match (is_mutable, is_ref) {
481             (true, true) => BindingAnnotation::RefMut,
482             (false, true) => BindingAnnotation::Ref,
483             (true, false) => BindingAnnotation::Mutable,
484             (false, false) => BindingAnnotation::Unannotated,
485         }
486     }
487 }
488 
489 #[derive(Debug, Clone, Eq, PartialEq)]
490 pub enum BindingProblems {
491     /// https://doc.rust-lang.org/stable/error_codes/E0416.html
492     BoundMoreThanOnce,
493     /// https://doc.rust-lang.org/stable/error_codes/E0409.html
494     BoundInconsistently,
495     /// https://doc.rust-lang.org/stable/error_codes/E0408.html
496     NotBoundAcrossAll,
497 }
498 
499 #[derive(Debug, Clone, Eq, PartialEq)]
500 pub struct Binding {
501     pub name: Name,
502     pub mode: BindingAnnotation,
503     pub definitions: SmallVec<[PatId; 1]>,
504     pub problems: Option<BindingProblems>,
505 }
506 
507 #[derive(Debug, Clone, Eq, PartialEq)]
508 pub struct RecordFieldPat {
509     pub name: Name,
510     pub pat: PatId,
511 }
512 
513 /// Close relative to rustc's hir::PatKind
514 #[derive(Debug, Clone, Eq, PartialEq)]
515 pub enum Pat {
516     Missing,
517     Wild,
518     Tuple { args: Box<[PatId]>, ellipsis: Option<usize> },
519     Or(Box<[PatId]>),
520     Record { path: Option<Box<Path>>, args: Box<[RecordFieldPat]>, ellipsis: bool },
521     Range { start: Option<Box<LiteralOrConst>>, end: Option<Box<LiteralOrConst>> },
522     Slice { prefix: Box<[PatId]>, slice: Option<PatId>, suffix: Box<[PatId]> },
523     Path(Box<Path>),
524     Lit(ExprId),
525     Bind { id: BindingId, subpat: Option<PatId> },
526     TupleStruct { path: Option<Box<Path>>, args: Box<[PatId]>, ellipsis: Option<usize> },
527     Ref { pat: PatId, mutability: Mutability },
528     Box { inner: PatId },
529     ConstBlock(ExprId),
530 }
531 
532 impl Pat {
walk_child_pats(&self, mut f: impl FnMut(PatId))533     pub fn walk_child_pats(&self, mut f: impl FnMut(PatId)) {
534         match self {
535             Pat::Range { .. }
536             | Pat::Lit(..)
537             | Pat::Path(..)
538             | Pat::ConstBlock(..)
539             | Pat::Wild
540             | Pat::Missing => {}
541             Pat::Bind { subpat, .. } => {
542                 subpat.iter().copied().for_each(f);
543             }
544             Pat::Or(args) | Pat::Tuple { args, .. } | Pat::TupleStruct { args, .. } => {
545                 args.iter().copied().for_each(f);
546             }
547             Pat::Ref { pat, .. } => f(*pat),
548             Pat::Slice { prefix, slice, suffix } => {
549                 let total_iter = prefix.iter().chain(slice.iter()).chain(suffix.iter());
550                 total_iter.copied().for_each(f);
551             }
552             Pat::Record { args, .. } => {
553                 args.iter().map(|f| f.pat).for_each(f);
554             }
555             Pat::Box { inner } => f(*inner),
556         }
557     }
558 }
559