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