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(ExprLiteral<'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        member_id: MemberId<'db>,
344        #[dont_rewrite]
345        stable_ptr: ast::ExprPtr<'db>,
346        concrete_struct_id: ConcreteStructId<'db>,
347        // Type of the member.
348        ty: TypeId<'db>,
349    },
350}
351impl<'db> ExprVarMemberPath<'db> {
352    pub fn base_var(&self) -> VarId<'db> {
353        match self {
354            ExprVarMemberPath::Var(expr) => expr.var,
355            ExprVarMemberPath::Member { parent, .. } => parent.base_var(),
356        }
357    }
358    pub fn ty(&self) -> TypeId<'db> {
359        match self {
360            ExprVarMemberPath::Var(expr) => expr.ty,
361            ExprVarMemberPath::Member { ty, .. } => *ty,
362        }
363    }
364    pub fn stable_ptr(&self) -> ast::ExprPtr<'db> {
365        match self {
366            ExprVarMemberPath::Var(var) => var.stable_ptr,
367            ExprVarMemberPath::Member { stable_ptr, .. } => *stable_ptr,
368        }
369    }
370}
371impl<'db> DebugWithDb<'db> for ExprVarMemberPath<'db> {
372    type Db = dyn Database;
373
374    fn fmt(&self, f: &mut std::fmt::Formatter<'_>, db: &'db dyn Database) -> std::fmt::Result {
375        match self {
376            ExprVarMemberPath::Var(var) => var.fmt(f, db),
377            ExprVarMemberPath::Member { parent, member_id, .. } => {
378                write!(f, "{:?}::{}", parent.debug(db), member_id.name(db).long(db))
379            }
380        }
381    }
382}
383#[derive(Clone, Debug, Hash, PartialEq, Eq, DebugWithDb, SemanticObject)]
384#[debug_db(ExprFormatter<'db>)]
385pub struct ExprClosure<'db> {
386    pub body: ExprId,
387    pub params: Vec<semantic::Parameter<'db>>,
388    #[hide_field_debug_with_db]
389    #[dont_rewrite]
390    pub stable_ptr: ast::ExprPtr<'db>,
391    pub ty: TypeId<'db>,
392}
393
394#[derive(Clone, Debug, Hash, PartialEq, Eq, DebugWithDb, SemanticObject)]
395#[debug_db(ExprFormatter<'db>)]
396pub enum ExprFunctionCallArg<'db> {
397    Reference(ExprVarMemberPath<'db>),
398    Value(ExprId),
399}
400
401#[derive(Clone, Debug, Hash, PartialEq, Eq, DebugWithDb, SemanticObject)]
402#[debug_db(ExprFormatter<'db>)]
403pub struct ExprFunctionCall<'db> {
404    pub function: FunctionId<'db>,
405    pub args: Vec<ExprFunctionCallArg<'db>>,
406    /// The `__coupon__` argument of the function call, if used. Attaching a coupon to a function
407    /// means that the coupon is used instead of reducing the cost of the called function from the
408    /// gas wallet. In particular, the cost of such a call is constant.
409    pub coupon_arg: Option<ExprId>,
410    pub ty: semantic::TypeId<'db>,
411    #[hide_field_debug_with_db]
412    #[dont_rewrite]
413    pub stable_ptr: ast::ExprPtr<'db>,
414}
415
416#[derive(Clone, Debug, Hash, PartialEq, Eq, DebugWithDb, SemanticObject)]
417#[debug_db(ExprFormatter<'db>)]
418pub struct ExprMatch<'db> {
419    pub matched_expr: ExprId,
420    pub arms: Vec<MatchArm>,
421    pub ty: semantic::TypeId<'db>,
422    #[hide_field_debug_with_db]
423    #[dont_rewrite]
424    pub stable_ptr: ast::ExprPtr<'db>,
425}
426
427#[derive(Clone, Debug, Hash, PartialEq, Eq, DebugWithDb, SemanticObject)]
428#[debug_db(ExprFormatter<'db>)]
429pub struct ExprIf<'db> {
430    pub conditions: Vec<Condition>,
431    pub if_block: ExprId,
432    pub else_block: Option<ExprId>,
433    pub ty: semantic::TypeId<'db>,
434    #[hide_field_debug_with_db]
435    #[dont_rewrite]
436    pub stable_ptr: ast::ExprPtr<'db>,
437}
438
439#[derive(Clone, Debug, Hash, PartialEq, Eq, DebugWithDb, SemanticObject)]
440#[debug_db(ExprFormatter<'db>)]
441pub enum Condition {
442    BoolExpr(ExprId),
443    Let(ExprId, Vec<PatternId>),
444}
445
446#[derive(Clone, Debug, Hash, PartialEq, Eq, DebugWithDb, SemanticObject)]
447#[debug_db(ExprFormatter<'db>)]
448pub struct MatchArm {
449    pub patterns: Vec<PatternId>,
450    pub expression: ExprId,
451}
452
453#[derive(Clone, Debug, Hash, PartialEq, Eq, DebugWithDb, SemanticObject)]
454#[debug_db(ExprFormatter<'db>)]
455pub struct ExprAssignment<'db> {
456    pub ref_arg: ExprVarMemberPath<'db>,
457    pub rhs: semantic::ExprId,
458    // ExprAssignment is always of unit type.
459    pub ty: semantic::TypeId<'db>,
460    #[hide_field_debug_with_db]
461    #[dont_rewrite]
462    pub stable_ptr: ast::ExprPtr<'db>,
463}
464
465#[derive(Clone, Debug, Eq, Hash, PartialEq)]
466pub enum LogicalOperator {
467    AndAnd,
468    OrOr,
469}
470
471#[derive(Clone, Debug, Hash, PartialEq, Eq, DebugWithDb, SemanticObject)]
472#[debug_db(ExprFormatter<'db>)]
473pub struct ExprLogicalOperator<'db> {
474    pub lhs: semantic::ExprId,
475    #[dont_rewrite]
476    pub op: LogicalOperator,
477    pub rhs: semantic::ExprId,
478    // ExprLogicalOperator is always of bool type.
479    pub ty: semantic::TypeId<'db>,
480    #[hide_field_debug_with_db]
481    #[dont_rewrite]
482    pub stable_ptr: ast::ExprPtr<'db>,
483}
484
485#[derive(Clone, Debug, Hash, PartialEq, Eq, SemanticObject, salsa::Update)]
486pub struct ExprVar<'db> {
487    pub var: VarId<'db>,
488    pub ty: semantic::TypeId<'db>,
489    #[dont_rewrite]
490    pub stable_ptr: ast::ExprPtr<'db>,
491}
492impl<'db> DebugWithDb<'db> for ExprVar<'db> {
493    type Db = dyn Database;
494
495    fn fmt(&self, f: &mut std::fmt::Formatter<'_>, db: &'db dyn Database) -> std::fmt::Result {
496        self.var.fmt(f, db)
497    }
498}
499
500// TODO(yuval): rename to ExprNumericLiteral.
501#[derive(Clone, Debug, Hash, PartialEq, Eq, DebugWithDb, SemanticObject, salsa::Update)]
502#[debug_db(ExprFormatter<'db>)]
503pub struct ExprLiteral<'db> {
504    #[dont_rewrite]
505    pub value: BigInt,
506    pub ty: semantic::TypeId<'db>,
507    #[hide_field_debug_with_db]
508    #[dont_rewrite]
509    pub stable_ptr: ast::ExprPtr<'db>,
510}
511
512#[derive(Clone, Debug, Hash, PartialEq, Eq, DebugWithDb, SemanticObject, salsa::Update)]
513#[debug_db(ExprFormatter<'db>)]
514pub struct ExprStringLiteral<'db> {
515    #[dont_rewrite]
516    pub value: String,
517    pub ty: semantic::TypeId<'db>,
518    #[hide_field_debug_with_db]
519    #[dont_rewrite]
520    pub stable_ptr: ast::ExprPtr<'db>,
521}
522
523#[derive(Clone, Debug, Hash, PartialEq, Eq, DebugWithDb, SemanticObject)]
524#[debug_db(ExprFormatter<'db>)]
525pub struct ExprMemberAccess<'db> {
526    pub expr: semantic::ExprId,
527    pub concrete_struct_id: ConcreteStructId<'db>,
528    pub member: MemberId<'db>,
529    pub ty: semantic::TypeId<'db>,
530    #[hide_field_debug_with_db]
531    pub member_path: Option<ExprVarMemberPath<'db>>,
532    #[hide_field_debug_with_db]
533    #[dont_rewrite]
534    pub n_snapshots: usize,
535    #[hide_field_debug_with_db]
536    #[dont_rewrite]
537    pub stable_ptr: ast::ExprPtr<'db>,
538}
539
540#[derive(Clone, Debug, Hash, PartialEq, Eq, DebugWithDb, SemanticObject)]
541#[debug_db(ExprFormatter<'db>)]
542pub struct ExprStructCtor<'db> {
543    pub concrete_struct_id: ConcreteStructId<'db>,
544    pub members: Vec<(ExprId, MemberId<'db>)>,
545    /// The base struct to copy missing members from if provided.
546    /// For example `let x = MyStruct { a: 1, ..base }`.
547    pub base_struct: Option<ExprId>,
548    pub ty: semantic::TypeId<'db>,
549    #[hide_field_debug_with_db]
550    #[dont_rewrite]
551    pub stable_ptr: ast::ExprPtr<'db>,
552}
553
554#[derive(Clone, Debug, Hash, PartialEq, Eq, DebugWithDb, SemanticObject)]
555#[debug_db(ExprFormatter<'db>)]
556pub struct ExprEnumVariantCtor<'db> {
557    pub variant: semantic::ConcreteVariant<'db>,
558    pub value_expr: ExprId,
559    pub ty: semantic::TypeId<'db>,
560    #[hide_field_debug_with_db]
561    #[dont_rewrite]
562    pub stable_ptr: ast::ExprPtr<'db>,
563}
564
565#[derive(Clone, Debug, Hash, PartialEq, Eq, DebugWithDb, SemanticObject)]
566#[debug_db(ExprFormatter<'db>)]
567pub struct ExprPropagateError<'db> {
568    pub inner: ExprId,
569    pub ok_variant: semantic::ConcreteVariant<'db>,
570    pub err_variant: semantic::ConcreteVariant<'db>,
571    pub func_err_variant: semantic::ConcreteVariant<'db>,
572    #[hide_field_debug_with_db]
573    #[dont_rewrite]
574    pub stable_ptr: ast::ExprPtr<'db>,
575}
576
577#[derive(Clone, Debug, Hash, PartialEq, Eq, DebugWithDb, SemanticObject)]
578#[debug_db(ExprFormatter<'db>)]
579pub struct ExprConstant<'db> {
580    pub const_value_id: ConstValueId<'db>,
581    pub ty: semantic::TypeId<'db>,
582    #[dont_rewrite]
583    #[hide_field_debug_with_db]
584    pub stable_ptr: ast::ExprPtr<'db>,
585}
586
587#[derive(Clone, Debug, Hash, PartialEq, Eq, DebugWithDb, SemanticObject)]
588#[debug_db(ExprFormatter<'db>)]
589pub struct ExprUse<'db> {
590    pub const_value_id: StatementUseId<'db>,
591    pub ty: semantic::TypeId<'db>,
592    #[dont_rewrite]
593    #[hide_field_debug_with_db]
594    pub stable_ptr: ast::ExprPtr<'db>,
595}
596
597#[derive(Clone, Debug, Hash, PartialEq, Eq, DebugWithDb, SemanticObject)]
598#[debug_db(ExprFormatter<'db>)]
599pub struct ExprMissing<'db> {
600    pub ty: semantic::TypeId<'db>,
601    #[hide_field_debug_with_db]
602    #[dont_rewrite]
603    pub stable_ptr: ast::ExprPtr<'db>,
604    #[hide_field_debug_with_db]
605    #[dont_rewrite]
606    pub diag_added: DiagnosticAdded,
607}
608
609/// Arena for semantic expressions, patterns, and statements.
610#[derive(Clone, Debug, Default, PartialEq, Eq, DebugWithDb)]
611#[debug_db(dyn Database)]
612pub struct Arenas<'db> {
613    pub exprs: ExprArena<'db>,
614    pub patterns: PatternArena<'db>,
615    pub statements: StatementArena<'db>,
616}
617
618unsafe impl<'db> salsa::Update for Arenas<'db> {
619    unsafe fn maybe_update(old_pointer: *mut Self, new_value: Self) -> bool {
620        let old_arenas: &mut Arenas<'db> = unsafe { &mut *old_pointer };
621
622        // Next id includes both arena length and arena id.
623        if old_arenas.exprs.next_id() != new_value.exprs.next_id()
624            || old_arenas.patterns.next_id() != new_value.patterns.next_id()
625            || old_arenas.statements.next_id() != new_value.statements.next_id()
626        {
627            *old_arenas = new_value;
628            return true;
629        }
630        false
631    }
632}