Skip to main content

cairo_lang_semantic/expr/
objects.rs

1use cairo_lang_debug::DebugWithDb;
2use cairo_lang_defs::ids::{MemberId, NamedLanguageElementId, StatementUseId, VarId};
3use cairo_lang_diagnostics::DiagnosticAdded;
4use cairo_lang_proc_macros::{DebugWithDb, SemanticObject};
5use cairo_lang_syntax::node::ast;
6use cairo_lang_syntax::node::ids::SyntaxStablePtrId;
7use id_arena::{Arena, ArenaBehavior};
8use num_bigint::BigInt;
9use salsa::Database;
10
11use super::fmt::ExprFormatter;
12use crate::items::constant::ConstValueId;
13use crate::{ConcreteStructId, FunctionId, TypeId, semantic};
14
15/// Defines an arena id type and its behavior for usage in an arena.
16macro_rules! define_arena_id {
17    ($id:ident, $behaviour:ident) => {
18        #[derive(Clone, Copy, PartialEq, Eq, Hash)]
19        pub struct $id(u32, usize);
20
21        impl core::fmt::Debug for $id {
22            fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
23                f.debug_tuple(stringify!($id)).field(&self.1).finish()
24            }
25        }
26
27        #[derive(Clone, Debug, PartialEq, Eq)]
28        pub struct $behaviour;
29        impl ArenaBehavior for $behaviour {
30            type Id = $id;
31
32            fn new_id(arena_id: u32, index: usize) -> Self::Id {
33                $id(arena_id, index)
34            }
35
36            fn arena_id(id: Self::Id) -> u32 {
37                id.0
38            }
39
40            fn index(id: Self::Id) -> usize {
41                id.1
42            }
43        }
44    };
45}
46
47define_arena_id!(PatternId, PatternArenaBehavior);
48pub type PatternArena<'db> = Arena<semantic::Pattern<'db>, PatternArenaBehavior>;
49define_arena_id!(ExprId, ExprArenaBehavior);
50pub type ExprArena<'db> = Arena<semantic::Expr<'db>, ExprArenaBehavior>;
51define_arena_id!(StatementId, StatementArenaBehavior);
52pub type StatementArena<'db> = Arena<semantic::Statement<'db>, StatementArenaBehavior>;
53
54#[derive(Clone, Debug, Hash, PartialEq, Eq, DebugWithDb, SemanticObject)]
55#[debug_db(ExprFormatter<'db>)]
56pub enum Statement<'db> {
57    Expr(StatementExpr<'db>),
58    Let(StatementLet<'db>),
59    Continue(StatementContinue<'db>),
60    Return(StatementReturn<'db>),
61    Break(StatementBreak<'db>),
62    Item(StatementItem<'db>),
63}
64impl<'db> Statement<'db> {
65    pub fn stable_ptr(&self) -> ast::StatementPtr<'db> {
66        match self {
67            Statement::Expr(stmt) => stmt.stable_ptr,
68            Statement::Let(stmt) => stmt.stable_ptr,
69            Statement::Continue(stmt) => stmt.stable_ptr,
70            Statement::Return(stmt) => stmt.stable_ptr,
71            Statement::Break(stmt) => stmt.stable_ptr,
72            Statement::Item(stmt) => stmt.stable_ptr,
73        }
74    }
75}
76
77impl<'db> From<&Statement<'db>> for SyntaxStablePtrId<'db> {
78    fn from(statement: &Statement<'db>) -> Self {
79        statement.stable_ptr().into()
80    }
81}
82
83#[derive(Clone, Debug, Hash, PartialEq, Eq, DebugWithDb, SemanticObject)]
84#[debug_db(ExprFormatter<'db>)]
85pub struct StatementExpr<'db> {
86    pub expr: ExprId,
87    #[hide_field_debug_with_db]
88    #[dont_rewrite]
89    pub stable_ptr: ast::StatementPtr<'db>,
90}
91
92#[derive(Clone, Debug, Hash, PartialEq, Eq, DebugWithDb, SemanticObject)]
93#[debug_db(ExprFormatter<'db>)]
94pub struct StatementLet<'db> {
95    pub pattern: PatternId,
96    pub expr: ExprId,
97    pub else_clause: Option<ExprId>,
98    #[hide_field_debug_with_db]
99    #[dont_rewrite]
100    pub stable_ptr: ast::StatementPtr<'db>,
101}
102
103#[derive(Clone, Debug, Hash, PartialEq, Eq, DebugWithDb, SemanticObject)]
104#[debug_db(ExprFormatter<'db>)]
105pub struct StatementContinue<'db> {
106    #[hide_field_debug_with_db]
107    #[dont_rewrite]
108    pub stable_ptr: ast::StatementPtr<'db>,
109}
110
111#[derive(Clone, Debug, Hash, PartialEq, Eq, DebugWithDb, SemanticObject)]
112#[debug_db(ExprFormatter<'db>)]
113pub struct StatementReturn<'db> {
114    pub expr_option: Option<ExprId>,
115    #[hide_field_debug_with_db]
116    #[dont_rewrite]
117    pub stable_ptr: ast::StatementPtr<'db>,
118}
119
120#[derive(Clone, Debug, Hash, PartialEq, Eq, DebugWithDb, SemanticObject)]
121#[debug_db(ExprFormatter<'db>)]
122pub struct StatementBreak<'db> {
123    pub expr_option: Option<ExprId>,
124    #[hide_field_debug_with_db]
125    #[dont_rewrite]
126    pub stable_ptr: ast::StatementPtr<'db>,
127}
128
129#[derive(Clone, Debug, Hash, PartialEq, Eq, DebugWithDb, SemanticObject)]
130#[debug_db(ExprFormatter<'db>)]
131pub struct StatementItem<'db> {
132    #[hide_field_debug_with_db]
133    #[dont_rewrite]
134    pub stable_ptr: ast::StatementPtr<'db>,
135}
136
137// Expressions.
138#[derive(Clone, Debug, Hash, PartialEq, Eq, DebugWithDb, SemanticObject)]
139#[debug_db(ExprFormatter<'db>)]
140pub enum Expr<'db> {
141    Tuple(ExprTuple<'db>),
142    Snapshot(ExprSnapshot<'db>),
143    Desnap(ExprDesnap<'db>),
144    Assignment(ExprAssignment<'db>),
145    LogicalOperator(ExprLogicalOperator<'db>),
146    Block(ExprBlock<'db>),
147    Loop(ExprLoop<'db>),
148    While(ExprWhile<'db>),
149    For(ExprFor<'db>),
150    FunctionCall(ExprFunctionCall<'db>),
151    Match(ExprMatch<'db>),
152    If(ExprIf<'db>),
153    Var(ExprVar<'db>),
154    Literal(ExprNumericLiteral<'db>),
155    StringLiteral(ExprStringLiteral<'db>),
156    MemberAccess(ExprMemberAccess<'db>),
157    StructCtor(ExprStructCtor<'db>),
158    EnumVariantCtor(ExprEnumVariantCtor<'db>),
159    PropagateError(ExprPropagateError<'db>),
160    Constant(ExprConstant<'db>),
161    FixedSizeArray(ExprFixedSizeArray<'db>),
162    ExprClosure(ExprClosure<'db>),
163    Missing(ExprMissing<'db>),
164}
165impl<'db> Expr<'db> {
166    pub fn ty(&self) -> semantic::TypeId<'db> {
167        match self {
168            Expr::Assignment(expr) => expr.ty,
169            Expr::Tuple(expr) => expr.ty,
170            Expr::Snapshot(expr) => expr.ty,
171            Expr::Desnap(expr) => expr.ty,
172            Expr::LogicalOperator(expr) => expr.ty,
173            Expr::Block(expr) => expr.ty,
174            Expr::Loop(expr) => expr.ty,
175            Expr::While(expr) => expr.ty,
176            Expr::For(expr) => expr.ty,
177            Expr::FunctionCall(expr) => expr.ty,
178            Expr::Match(expr) => expr.ty,
179            Expr::If(expr) => expr.ty,
180            Expr::Var(expr) => expr.ty,
181            Expr::Literal(expr) => expr.ty,
182            Expr::StringLiteral(expr) => expr.ty,
183            Expr::MemberAccess(expr) => expr.ty,
184            Expr::StructCtor(expr) => expr.ty,
185            Expr::EnumVariantCtor(expr) => expr.ty,
186            Expr::PropagateError(expr) => expr.ok_variant.ty,
187            Expr::Constant(expr) => expr.ty,
188            Expr::Missing(expr) => expr.ty,
189            Expr::FixedSizeArray(expr) => expr.ty,
190            Expr::ExprClosure(expr) => expr.ty,
191        }
192    }
193    pub fn stable_ptr(&self) -> ast::ExprPtr<'db> {
194        match self {
195            Expr::Assignment(expr) => expr.stable_ptr,
196            Expr::Tuple(expr) => expr.stable_ptr,
197            Expr::Snapshot(expr) => expr.stable_ptr,
198            Expr::Desnap(expr) => expr.stable_ptr,
199            Expr::LogicalOperator(expr) => expr.stable_ptr,
200            Expr::Block(expr) => expr.stable_ptr,
201            Expr::Loop(expr) => expr.stable_ptr,
202            Expr::While(expr) => expr.stable_ptr,
203            Expr::For(expr) => expr.stable_ptr,
204            Expr::FunctionCall(expr) => expr.stable_ptr,
205            Expr::Match(expr) => expr.stable_ptr,
206            Expr::If(expr) => expr.stable_ptr,
207            Expr::Var(expr) => expr.stable_ptr,
208            Expr::Literal(expr) => expr.stable_ptr,
209            Expr::StringLiteral(expr) => expr.stable_ptr,
210            Expr::MemberAccess(expr) => expr.stable_ptr,
211            Expr::StructCtor(expr) => expr.stable_ptr,
212            Expr::EnumVariantCtor(expr) => expr.stable_ptr,
213            Expr::PropagateError(expr) => expr.stable_ptr,
214            Expr::Constant(expr) => expr.stable_ptr,
215            Expr::Missing(expr) => expr.stable_ptr,
216            Expr::FixedSizeArray(expr) => expr.stable_ptr,
217            Expr::ExprClosure(expr) => expr.stable_ptr,
218        }
219    }
220
221    /// Returns the member path of the expression, if it is a variable or a member access.
222    pub fn as_member_path(&self) -> Option<ExprVarMemberPath<'db>> {
223        match self {
224            Expr::Var(expr) => Some(ExprVarMemberPath::Var(expr.clone())),
225            Expr::MemberAccess(expr) => expr.member_path.clone(),
226            _ => None,
227        }
228    }
229}
230
231impl<'db> From<&Expr<'db>> for SyntaxStablePtrId<'db> {
232    fn from(expr: &Expr<'db>) -> Self {
233        expr.stable_ptr().into()
234    }
235}
236
237#[derive(Clone, Debug, Hash, PartialEq, Eq, DebugWithDb, SemanticObject)]
238#[debug_db(ExprFormatter<'db>)]
239pub struct ExprTuple<'db> {
240    pub items: Vec<ExprId>,
241    pub ty: semantic::TypeId<'db>,
242    #[hide_field_debug_with_db]
243    #[dont_rewrite]
244    pub stable_ptr: ast::ExprPtr<'db>,
245}
246
247#[derive(Clone, Debug, Hash, PartialEq, Eq, DebugWithDb, SemanticObject)]
248#[debug_db(ExprFormatter<'db>)]
249pub struct ExprFixedSizeArray<'db> {
250    pub items: FixedSizeArrayItems<'db>,
251    pub ty: semantic::TypeId<'db>,
252    #[hide_field_debug_with_db]
253    #[dont_rewrite]
254    pub stable_ptr: ast::ExprPtr<'db>,
255}
256
257/// Either a vector of items, if all was written in the code i.e. ([10, 11, 12] or [10, 10, 10]), or
258/// a value and a size, if the array was written as ([10; 3]).
259#[derive(Clone, Debug, Hash, PartialEq, Eq, DebugWithDb, SemanticObject)]
260#[debug_db(ExprFormatter<'db>)]
261pub enum FixedSizeArrayItems<'db> {
262    Items(Vec<ExprId>),
263    ValueAndSize(ExprId, ConstValueId<'db>),
264}
265
266#[derive(Clone, Debug, Hash, PartialEq, Eq, DebugWithDb, SemanticObject)]
267#[debug_db(ExprFormatter<'db>)]
268pub struct ExprSnapshot<'db> {
269    pub inner: ExprId,
270    pub ty: semantic::TypeId<'db>,
271    #[hide_field_debug_with_db]
272    #[dont_rewrite]
273    pub stable_ptr: ast::ExprPtr<'db>,
274}
275
276#[derive(Clone, Debug, Hash, PartialEq, Eq, DebugWithDb, SemanticObject)]
277#[debug_db(ExprFormatter<'db>)]
278pub struct ExprDesnap<'db> {
279    pub inner: ExprId,
280    pub ty: semantic::TypeId<'db>,
281    #[hide_field_debug_with_db]
282    #[dont_rewrite]
283    pub stable_ptr: ast::ExprPtr<'db>,
284}
285
286#[derive(Clone, Debug, Hash, PartialEq, Eq, DebugWithDb, SemanticObject)]
287#[debug_db(ExprFormatter<'db>)]
288pub struct ExprBlock<'db> {
289    pub statements: Vec<StatementId>,
290    /// Blocks may end with an expression, without a trailing `;`.
291    /// In this case, `tail` will be Some(expr) with that expression.
292    /// The block expression will evaluate to this tail expression.
293    /// Otherwise, this will be None.
294    pub tail: Option<ExprId>,
295    pub ty: semantic::TypeId<'db>,
296    #[hide_field_debug_with_db]
297    #[dont_rewrite]
298    pub stable_ptr: ast::ExprPtr<'db>,
299}
300
301#[derive(Clone, Debug, Hash, PartialEq, Eq, DebugWithDb, SemanticObject)]
302#[debug_db(ExprFormatter<'db>)]
303pub struct ExprLoop<'db> {
304    pub body: ExprId,
305    pub ty: semantic::TypeId<'db>,
306    #[hide_field_debug_with_db]
307    #[dont_rewrite]
308    pub stable_ptr: ast::ExprPtr<'db>,
309}
310
311#[derive(Clone, Debug, Hash, PartialEq, Eq, DebugWithDb, SemanticObject)]
312#[debug_db(ExprFormatter<'db>)]
313pub struct ExprWhile<'db> {
314    pub condition: Condition,
315    pub body: ExprId,
316    pub ty: semantic::TypeId<'db>,
317    #[hide_field_debug_with_db]
318    #[dont_rewrite]
319    pub stable_ptr: ast::ExprPtr<'db>,
320}
321
322#[derive(Clone, Debug, Hash, PartialEq, Eq, DebugWithDb, SemanticObject)]
323#[debug_db(ExprFormatter<'db>)]
324pub struct ExprFor<'db> {
325    pub into_iter: FunctionId<'db>,
326    pub into_iter_member_path: ExprVarMemberPath<'db>,
327    pub next_function_id: FunctionId<'db>,
328    pub expr_id: ExprId,
329    pub pattern: PatternId,
330    pub body: ExprId,
331    pub ty: semantic::TypeId<'db>,
332    #[hide_field_debug_with_db]
333    #[dont_rewrite]
334    pub stable_ptr: ast::ExprPtr<'db>,
335}
336
337/// A sequence of member accesses of a variable. For example: a, a.b, a.b.c, ...
338#[derive(Clone, Debug, Hash, PartialEq, Eq, SemanticObject, salsa::Update)]
339pub enum ExprVarMemberPath<'db> {
340    Var(ExprVar<'db>),
341    Member {
342        parent: Box<ExprVarMemberPath<'db>>,
343        kind: MemberAccessKind<'db>,
344        #[dont_rewrite]
345        stable_ptr: ast::ExprPtr<'db>,
346        // Type of the member.
347        ty: TypeId<'db>,
348    },
349}
350impl<'db> ExprVarMemberPath<'db> {
351    pub fn base_var(&self) -> VarId<'db> {
352        match self {
353            ExprVarMemberPath::Var(expr) => expr.var,
354            ExprVarMemberPath::Member { parent, .. } => parent.base_var(),
355        }
356    }
357    pub fn ty(&self) -> TypeId<'db> {
358        match self {
359            ExprVarMemberPath::Var(expr) => expr.ty,
360            ExprVarMemberPath::Member { ty, .. } => *ty,
361        }
362    }
363    pub fn stable_ptr(&self) -> ast::ExprPtr<'db> {
364        match self {
365            ExprVarMemberPath::Var(var) => var.stable_ptr,
366            ExprVarMemberPath::Member { stable_ptr, .. } => *stable_ptr,
367        }
368    }
369}
370impl<'db> DebugWithDb<'db> for ExprVarMemberPath<'db> {
371    type Db = dyn Database;
372
373    fn fmt(&self, f: &mut std::fmt::Formatter<'_>, db: &'db dyn Database) -> std::fmt::Result {
374        match self {
375            ExprVarMemberPath::Var(var) => var.fmt(f, db),
376            ExprVarMemberPath::Member { parent, kind, .. } => match kind {
377                MemberAccessKind::Struct { member_id, .. } => {
378                    write!(f, "{:?}::{}", parent.debug(db), member_id.name(db).long(db))
379                }
380                MemberAccessKind::Index { index, .. } => {
381                    write!(f, "{:?}::{}", parent.debug(db), index)
382                }
383            },
384        }
385    }
386}
387#[derive(Clone, Debug, Hash, PartialEq, Eq, DebugWithDb, SemanticObject)]
388#[debug_db(ExprFormatter<'db>)]
389pub struct ExprClosure<'db> {
390    pub body: ExprId,
391    pub params: Vec<semantic::Parameter<'db>>,
392    #[hide_field_debug_with_db]
393    #[dont_rewrite]
394    pub stable_ptr: ast::ExprPtr<'db>,
395    pub ty: TypeId<'db>,
396}
397
398#[derive(Clone, Debug, Hash, PartialEq, Eq, DebugWithDb, SemanticObject)]
399#[debug_db(ExprFormatter<'db>)]
400pub enum ExprFunctionCallArg<'db> {
401    Reference(ExprVarMemberPath<'db>),
402    Value(ExprId),
403    /// An argument for function calls which is an expression result, but expected to be taken as
404    /// reference. Only valid for the first parameter of method calls with `ref self`.
405    TempReference(ExprId),
406}
407
408#[derive(Clone, Debug, Hash, PartialEq, Eq, DebugWithDb, SemanticObject)]
409#[debug_db(ExprFormatter<'db>)]
410pub struct ExprFunctionCall<'db> {
411    pub function: FunctionId<'db>,
412    pub args: Vec<ExprFunctionCallArg<'db>>,
413    /// The `__coupon__` argument of the function call, if used. Attaching a coupon to a function
414    /// means that the coupon is used instead of reducing the cost of the called function from the
415    /// gas wallet. In particular, the cost of such a call is constant.
416    pub coupon_arg: Option<ExprId>,
417    pub ty: semantic::TypeId<'db>,
418    #[hide_field_debug_with_db]
419    #[dont_rewrite]
420    pub stable_ptr: ast::ExprPtr<'db>,
421}
422
423#[derive(Clone, Debug, Hash, PartialEq, Eq, DebugWithDb, SemanticObject)]
424#[debug_db(ExprFormatter<'db>)]
425pub struct ExprMatch<'db> {
426    pub matched_expr: ExprId,
427    pub arms: Vec<MatchArm>,
428    pub ty: semantic::TypeId<'db>,
429    #[hide_field_debug_with_db]
430    #[dont_rewrite]
431    pub stable_ptr: ast::ExprPtr<'db>,
432}
433
434#[derive(Clone, Debug, Hash, PartialEq, Eq, DebugWithDb, SemanticObject)]
435#[debug_db(ExprFormatter<'db>)]
436pub struct ExprIf<'db> {
437    pub conditions: Vec<Condition>,
438    pub if_block: ExprId,
439    pub else_block: Option<ExprId>,
440    pub ty: semantic::TypeId<'db>,
441    #[hide_field_debug_with_db]
442    #[dont_rewrite]
443    pub stable_ptr: ast::ExprPtr<'db>,
444}
445
446#[derive(Clone, Debug, Hash, PartialEq, Eq, DebugWithDb, SemanticObject)]
447#[debug_db(ExprFormatter<'db>)]
448pub enum Condition {
449    BoolExpr(ExprId),
450    Let(ExprId, Vec<PatternId>),
451}
452
453#[derive(Clone, Debug, Hash, PartialEq, Eq, DebugWithDb, SemanticObject)]
454#[debug_db(ExprFormatter<'db>)]
455pub struct MatchArm {
456    pub patterns: Vec<PatternId>,
457    pub expression: ExprId,
458}
459
460#[derive(Clone, Debug, Hash, PartialEq, Eq, DebugWithDb, SemanticObject)]
461#[debug_db(ExprFormatter<'db>)]
462pub struct ExprAssignment<'db> {
463    pub ref_arg: ExprVarMemberPath<'db>,
464    pub rhs: semantic::ExprId,
465    // ExprAssignment is always of unit type.
466    pub ty: semantic::TypeId<'db>,
467    #[hide_field_debug_with_db]
468    #[dont_rewrite]
469    pub stable_ptr: ast::ExprPtr<'db>,
470}
471
472#[derive(Clone, Debug, Eq, Hash, PartialEq)]
473pub enum LogicalOperator {
474    AndAnd,
475    OrOr,
476}
477
478#[derive(Clone, Debug, Hash, PartialEq, Eq, DebugWithDb, SemanticObject)]
479#[debug_db(ExprFormatter<'db>)]
480pub struct ExprLogicalOperator<'db> {
481    pub lhs: semantic::ExprId,
482    #[dont_rewrite]
483    pub op: LogicalOperator,
484    pub rhs: semantic::ExprId,
485    // ExprLogicalOperator is always of bool type.
486    pub ty: semantic::TypeId<'db>,
487    #[hide_field_debug_with_db]
488    #[dont_rewrite]
489    pub stable_ptr: ast::ExprPtr<'db>,
490}
491
492#[derive(Clone, Debug, Hash, PartialEq, Eq, SemanticObject, salsa::Update)]
493pub struct ExprVar<'db> {
494    pub var: VarId<'db>,
495    pub ty: semantic::TypeId<'db>,
496    #[dont_rewrite]
497    pub stable_ptr: ast::ExprPtr<'db>,
498}
499impl<'db> DebugWithDb<'db> for ExprVar<'db> {
500    type Db = dyn Database;
501
502    fn fmt(&self, f: &mut std::fmt::Formatter<'_>, db: &'db dyn Database) -> std::fmt::Result {
503        self.var.fmt(f, db)
504    }
505}
506
507#[derive(Clone, Debug, Hash, PartialEq, Eq, DebugWithDb, SemanticObject, salsa::Update)]
508#[debug_db(ExprFormatter<'db>)]
509pub struct ExprNumericLiteral<'db> {
510    #[dont_rewrite]
511    pub value: BigInt,
512    pub ty: semantic::TypeId<'db>,
513    #[hide_field_debug_with_db]
514    #[dont_rewrite]
515    pub stable_ptr: ast::ExprPtr<'db>,
516}
517
518#[derive(Clone, Debug, Hash, PartialEq, Eq, DebugWithDb, SemanticObject, salsa::Update)]
519#[debug_db(ExprFormatter<'db>)]
520pub struct ExprStringLiteral<'db> {
521    #[dont_rewrite]
522    pub value: String,
523    pub ty: semantic::TypeId<'db>,
524    #[hide_field_debug_with_db]
525    #[dont_rewrite]
526    pub stable_ptr: ast::ExprPtr<'db>,
527}
528
529/// Identifies the accessed member of an aggregate, either a named struct member or a positional
530/// element of a tuple (e.g. `t.0`).
531#[derive(Clone, Debug, Hash, PartialEq, Eq, DebugWithDb, SemanticObject, salsa::Update)]
532#[debug_db(dyn Database)]
533pub enum MemberAccessKind<'db> {
534    /// A named member of a struct.
535    Struct { concrete_struct_id: ConcreteStructId<'db>, member_id: MemberId<'db> },
536    /// A positional element of a tuple, accessed by index (e.g. `t.0`).
537    Index {
538        /// The type of the tuple being accessed.
539        tuple_ty: TypeId<'db>,
540        #[dont_rewrite]
541        index: usize,
542    },
543}
544
545#[derive(Clone, Debug, Hash, PartialEq, Eq, DebugWithDb, SemanticObject)]
546#[debug_db(ExprFormatter<'db>)]
547pub struct ExprMemberAccess<'db> {
548    pub expr: semantic::ExprId,
549    pub kind: MemberAccessKind<'db>,
550    pub ty: semantic::TypeId<'db>,
551    #[hide_field_debug_with_db]
552    pub member_path: Option<ExprVarMemberPath<'db>>,
553    #[hide_field_debug_with_db]
554    #[dont_rewrite]
555    pub n_snapshots: usize,
556    #[hide_field_debug_with_db]
557    #[dont_rewrite]
558    pub stable_ptr: ast::ExprPtr<'db>,
559}
560
561#[derive(Clone, Debug, Hash, PartialEq, Eq, DebugWithDb, SemanticObject)]
562#[debug_db(ExprFormatter<'db>)]
563pub struct ExprStructCtor<'db> {
564    pub concrete_struct_id: ConcreteStructId<'db>,
565    pub members: Vec<(ExprId, MemberId<'db>)>,
566    /// The base struct to copy missing members from if provided.
567    /// For example `let x = MyStruct { a: 1, ..base }`.
568    pub base_struct: Option<ExprId>,
569    pub ty: semantic::TypeId<'db>,
570    #[hide_field_debug_with_db]
571    #[dont_rewrite]
572    pub stable_ptr: ast::ExprPtr<'db>,
573}
574
575#[derive(Clone, Debug, Hash, PartialEq, Eq, DebugWithDb, SemanticObject)]
576#[debug_db(ExprFormatter<'db>)]
577pub struct ExprEnumVariantCtor<'db> {
578    pub variant: semantic::ConcreteVariant<'db>,
579    pub value_expr: ExprId,
580    pub ty: semantic::TypeId<'db>,
581    #[hide_field_debug_with_db]
582    #[dont_rewrite]
583    pub stable_ptr: ast::ExprPtr<'db>,
584}
585
586#[derive(Clone, Debug, Hash, PartialEq, Eq, DebugWithDb, SemanticObject)]
587#[debug_db(ExprFormatter<'db>)]
588pub struct ExprPropagateError<'db> {
589    pub inner: ExprId,
590    pub ok_variant: semantic::ConcreteVariant<'db>,
591    pub err_variant: semantic::ConcreteVariant<'db>,
592    pub func_err_variant: semantic::ConcreteVariant<'db>,
593    #[hide_field_debug_with_db]
594    #[dont_rewrite]
595    pub stable_ptr: ast::ExprPtr<'db>,
596}
597
598#[derive(Clone, Debug, Hash, PartialEq, Eq, DebugWithDb, SemanticObject)]
599#[debug_db(ExprFormatter<'db>)]
600pub struct ExprConstant<'db> {
601    pub const_value_id: ConstValueId<'db>,
602    pub ty: semantic::TypeId<'db>,
603    #[dont_rewrite]
604    #[hide_field_debug_with_db]
605    pub stable_ptr: ast::ExprPtr<'db>,
606}
607
608#[derive(Clone, Debug, Hash, PartialEq, Eq, DebugWithDb, SemanticObject)]
609#[debug_db(ExprFormatter<'db>)]
610pub struct ExprUse<'db> {
611    pub const_value_id: StatementUseId<'db>,
612    pub ty: semantic::TypeId<'db>,
613    #[dont_rewrite]
614    #[hide_field_debug_with_db]
615    pub stable_ptr: ast::ExprPtr<'db>,
616}
617
618#[derive(Clone, Debug, Hash, PartialEq, Eq, DebugWithDb, SemanticObject)]
619#[debug_db(ExprFormatter<'db>)]
620pub struct ExprMissing<'db> {
621    pub ty: semantic::TypeId<'db>,
622    #[hide_field_debug_with_db]
623    #[dont_rewrite]
624    pub stable_ptr: ast::ExprPtr<'db>,
625    #[hide_field_debug_with_db]
626    #[dont_rewrite]
627    pub diag_added: DiagnosticAdded,
628}
629
630/// Arena for semantic expressions, patterns, and statements.
631#[derive(Clone, Debug, Default, PartialEq, Eq, DebugWithDb)]
632#[debug_db(dyn Database)]
633pub struct Arenas<'db> {
634    pub exprs: ExprArena<'db>,
635    pub patterns: PatternArena<'db>,
636    pub statements: StatementArena<'db>,
637}
638
639unsafe impl<'db> salsa::Update for Arenas<'db> {
640    unsafe fn maybe_update(old_pointer: *mut Self, new_value: Self) -> bool {
641        let old_arenas: &mut Arenas<'db> = unsafe { &mut *old_pointer };
642
643        // Next id includes both arena length and arena id.
644        if old_arenas.exprs.next_id() != new_value.exprs.next_id()
645            || old_arenas.patterns.next_id() != new_value.patterns.next_id()
646            || old_arenas.statements.next_id() != new_value.statements.next_id()
647        {
648            *old_arenas = new_value;
649            return true;
650        }
651        false
652    }
653}