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