cairo_lang_semantic/expr/
pattern.rs

1use cairo_lang_debug::DebugWithDb;
2use cairo_lang_defs::ids::FunctionWithBodyId;
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;
8use smol_str::SmolStr;
9
10use super::fmt::ExprFormatter;
11use crate::db::SemanticGroup;
12use crate::{ConcreteStructId, ExprLiteral, ExprStringLiteral, LocalVariable, PatternId, semantic};
13
14/// Semantic representation of a Pattern.
15///
16/// A pattern is a way to "destructure" values. A pattern may introduce new variables that are bound
17/// to inner values of a specific value. For example, a tuple pattern destructures a tuple
18/// and may result in new variables for an elements of that tuple.
19/// This is used both in let statements and match statements.
20// TODO(spapini): Replace this doc with a reference to the language documentation about patterns,
21// once it is available.
22#[derive(Clone, Debug, PartialEq, Eq, DebugWithDb, SemanticObject)]
23#[debug_db(ExprFormatter<'a>)]
24pub enum Pattern {
25    Literal(PatternLiteral),
26    StringLiteral(PatternStringLiteral),
27    Variable(PatternVariable),
28    Struct(PatternStruct),
29    Tuple(PatternTuple),
30    FixedSizeArray(PatternFixedSizeArray),
31    EnumVariant(PatternEnumVariant),
32    Otherwise(PatternOtherwise),
33    Missing(PatternMissing),
34}
35impl Pattern {
36    pub fn ty(&self) -> semantic::TypeId {
37        match self {
38            Pattern::Literal(literal) => literal.literal.ty,
39            Pattern::StringLiteral(string_literal) => string_literal.string_literal.ty,
40            Pattern::Variable(variable) => variable.var.ty,
41            Pattern::Struct(pattern_struct) => pattern_struct.ty,
42            Pattern::Tuple(pattern_tuple) => pattern_tuple.ty,
43            Pattern::FixedSizeArray(pattern_fixed_size_array) => pattern_fixed_size_array.ty,
44            Pattern::EnumVariant(pattern_enum_variant) => pattern_enum_variant.ty,
45            Pattern::Otherwise(pattern_otherwise) => pattern_otherwise.ty,
46            Pattern::Missing(pattern_missing) => pattern_missing.ty,
47        }
48    }
49
50    pub fn variables(&self, queryable: &dyn PatternVariablesQueryable) -> Vec<PatternVariable> {
51        match self {
52            Pattern::Variable(variable) => vec![variable.clone()],
53            Pattern::Struct(pattern_struct) => pattern_struct
54                .field_patterns
55                .iter()
56                .flat_map(|(_member, pattern)| queryable.query(*pattern))
57                .collect(),
58            Pattern::Tuple(pattern_tuple) => pattern_tuple
59                .field_patterns
60                .iter()
61                .flat_map(|pattern| queryable.query(*pattern))
62                .collect(),
63            Pattern::FixedSizeArray(pattern_fixed_size_array) => pattern_fixed_size_array
64                .elements_patterns
65                .iter()
66                .flat_map(|pattern| queryable.query(*pattern))
67                .collect(),
68            Pattern::EnumVariant(pattern_enum_variant) => {
69                match &pattern_enum_variant.inner_pattern {
70                    Some(pattern) => queryable.query(*pattern),
71                    None => vec![],
72                }
73            }
74            Pattern::Literal(_)
75            | Pattern::StringLiteral(_)
76            | Pattern::Otherwise(_)
77            | Pattern::Missing(_) => vec![],
78        }
79    }
80
81    pub fn stable_ptr(&self) -> ast::PatternPtr {
82        match self {
83            Pattern::Literal(pattern) => pattern.stable_ptr,
84            Pattern::StringLiteral(pattern) => pattern.stable_ptr,
85            Pattern::Variable(pattern) => pattern.stable_ptr,
86            Pattern::Struct(pattern) => pattern.stable_ptr.into(),
87            Pattern::Tuple(pattern) => pattern.stable_ptr.into(),
88            Pattern::FixedSizeArray(pattern) => pattern.stable_ptr.into(),
89            Pattern::EnumVariant(pattern) => pattern.stable_ptr,
90            Pattern::Otherwise(pattern) => pattern.stable_ptr.into(),
91            Pattern::Missing(pattern) => pattern.stable_ptr,
92        }
93    }
94}
95
96impl From<&Pattern> for SyntaxStablePtrId {
97    fn from(pattern: &Pattern) -> Self {
98        pattern.stable_ptr().into()
99    }
100}
101
102/// Polymorphic container of [`Pattern`] objects used for querying pattern variables.
103pub trait PatternVariablesQueryable {
104    /// Lookup the pattern in this container and then get [`Pattern::variables`] from it.
105    fn query(&self, id: PatternId) -> Vec<PatternVariable>;
106}
107
108impl PatternVariablesQueryable for Arena<Pattern> {
109    fn query(&self, id: PatternId) -> Vec<PatternVariable> {
110        self[id].variables(self)
111    }
112}
113
114/// Query a function for variables of patterns defined within it.
115///
116/// This is a wrapper over [`SemanticGroup`] that takes [`FunctionWithBodyId`]
117/// and relays queries to [`SemanticGroup::pattern_semantic`].
118pub struct QueryPatternVariablesFromDb<'a>(
119    pub &'a (dyn SemanticGroup + 'static),
120    pub FunctionWithBodyId,
121);
122
123impl PatternVariablesQueryable for QueryPatternVariablesFromDb<'_> {
124    fn query(&self, id: PatternId) -> Vec<PatternVariable> {
125        self.0.pattern_semantic(self.1, id).variables(self)
126    }
127}
128
129#[derive(Clone, Debug, Hash, PartialEq, Eq, DebugWithDb, SemanticObject)]
130#[debug_db(ExprFormatter<'a>)]
131pub struct PatternLiteral {
132    pub literal: ExprLiteral,
133    #[hide_field_debug_with_db]
134    #[dont_rewrite]
135    pub stable_ptr: ast::PatternPtr,
136}
137
138#[derive(Clone, Debug, Hash, PartialEq, Eq, DebugWithDb, SemanticObject)]
139#[debug_db(ExprFormatter<'a>)]
140pub struct PatternStringLiteral {
141    pub string_literal: ExprStringLiteral,
142    #[hide_field_debug_with_db]
143    #[dont_rewrite]
144    pub stable_ptr: ast::PatternPtr,
145}
146
147/// A pattern that binds the matched value to a variable.
148#[derive(Clone, Debug, Hash, PartialEq, Eq, SemanticObject)]
149pub struct PatternVariable {
150    #[dont_rewrite]
151    pub name: SmolStr,
152    pub var: LocalVariable,
153    #[dont_rewrite]
154    pub stable_ptr: ast::PatternPtr,
155}
156impl DebugWithDb<ExprFormatter<'_>> for PatternVariable {
157    fn fmt(&self, f: &mut std::fmt::Formatter<'_>, _db: &ExprFormatter<'_>) -> std::fmt::Result {
158        write!(f, "{}", self.name)
159    }
160}
161
162/// A pattern that destructures a struct to its fields.
163#[derive(Clone, Debug, PartialEq, Eq, DebugWithDb, SemanticObject)]
164#[debug_db(ExprFormatter<'a>)]
165pub struct PatternStruct {
166    pub concrete_struct_id: ConcreteStructId,
167    // TODO(spapini): This should be ConcreteMember, when available.
168    pub field_patterns: Vec<(semantic::Member, PatternId)>,
169    pub ty: semantic::TypeId,
170    #[dont_rewrite]
171    pub n_snapshots: usize,
172    #[hide_field_debug_with_db]
173    #[dont_rewrite]
174    pub stable_ptr: ast::PatternStructPtr,
175}
176
177/// A pattern that destructures a tuple to its fields.
178#[derive(Clone, Debug, Hash, PartialEq, Eq, DebugWithDb, SemanticObject)]
179#[debug_db(ExprFormatter<'a>)]
180pub struct PatternTuple {
181    pub field_patterns: Vec<PatternId>,
182    pub ty: semantic::TypeId,
183    #[hide_field_debug_with_db]
184    #[dont_rewrite]
185    pub stable_ptr: ast::PatternTuplePtr,
186}
187
188/// A pattern that destructures a fixed size array into its elements.
189#[derive(Clone, Debug, Hash, PartialEq, Eq, DebugWithDb, SemanticObject)]
190#[debug_db(ExprFormatter<'a>)]
191pub struct PatternFixedSizeArray {
192    pub elements_patterns: Vec<PatternId>,
193    pub ty: semantic::TypeId,
194    #[hide_field_debug_with_db]
195    #[dont_rewrite]
196    pub stable_ptr: ast::PatternFixedSizeArrayPtr,
197}
198
199/// A pattern that destructures a specific variant of an enum to its inner value.
200#[derive(Clone, Debug, Hash, PartialEq, Eq, DebugWithDb, SemanticObject)]
201#[debug_db(ExprFormatter<'a>)]
202pub struct PatternEnumVariant {
203    pub variant: semantic::ConcreteVariant,
204    pub inner_pattern: Option<PatternId>,
205    pub ty: semantic::TypeId,
206    #[hide_field_debug_with_db]
207    #[dont_rewrite]
208    pub stable_ptr: ast::PatternPtr,
209}
210
211#[derive(Clone, Debug, Hash, PartialEq, Eq, DebugWithDb, SemanticObject)]
212#[debug_db(ExprFormatter<'a>)]
213pub struct PatternOtherwise {
214    pub ty: semantic::TypeId,
215    #[hide_field_debug_with_db]
216    #[dont_rewrite]
217    pub stable_ptr: ast::TerminalUnderscorePtr,
218}
219
220#[derive(Clone, Debug, Hash, PartialEq, Eq, DebugWithDb, SemanticObject)]
221#[debug_db(ExprFormatter<'a>)]
222pub struct PatternMissing {
223    pub ty: semantic::TypeId,
224    #[hide_field_debug_with_db]
225    #[dont_rewrite]
226    pub stable_ptr: ast::PatternPtr,
227    #[hide_field_debug_with_db]
228    #[dont_rewrite]
229    pub diag_added: DiagnosticAdded,
230}