Skip to main content

lisette_semantics/checker/infer/expressions/
mod.rs

1pub mod bindings;
2pub mod control_flow;
3pub mod definitions;
4pub mod dot_access;
5pub mod functions;
6pub mod impl_blocks;
7pub mod indexed_access;
8pub mod literals;
9pub mod operators;
10pub mod patterns;
11pub mod primitives;
12pub mod propagate;
13pub mod select;
14pub mod struct_call;
15
16use syntax::ast::Expression;
17use syntax::types::Type;
18
19use super::super::TaskState;
20use crate::store::Store;
21
22impl TaskState<'_> {
23    pub fn infer_expression(
24        &mut self,
25        store: &Store,
26        expression: Expression,
27        expected_ty: &Type,
28    ) -> Expression {
29        // Track sub-expression depth: `infer_block_items` resets this to false
30        // for each top-level statement, so any nested call sees `true`.
31        let parent_is_subexpression = self.scopes.set_in_subexpression(true);
32
33        let result =
34            self.infer_expression_inner(store, expression, expected_ty, parent_is_subexpression);
35
36        self.scopes.set_in_subexpression(parent_is_subexpression);
37        result
38    }
39
40    fn infer_expression_inner(
41        &mut self,
42        store: &Store,
43        expression: Expression,
44        expected_ty: &Type,
45        parent_is_subexpression: bool,
46    ) -> Expression {
47        match expression {
48            Expression::Literal { literal, span, .. } => {
49                self.infer_literal(store, literal, expected_ty, span)
50            }
51
52            Expression::Block { items, span, .. } => {
53                self.infer_block(store, items, span, expected_ty)
54            }
55
56            Expression::Function { .. } => self.infer_function(store, expression, expected_ty),
57
58            Expression::Lambda {
59                params,
60                return_annotation,
61                body,
62                span,
63                ..
64            } => self.infer_lambda(store, params, return_annotation, body, span, expected_ty),
65
66            Expression::Unit { span, .. } => self.infer_unit(store, span, expected_ty),
67
68            Expression::Identifier {
69                ref value, span, ..
70            } => self.infer_identifier(store, value.clone(), span, expected_ty),
71
72            Expression::Let {
73                binding,
74                value,
75                mutable,
76                mut_span,
77                else_block,
78                else_span,
79                span,
80                typed_pattern: _,
81                ty: _,
82            } => self.infer_let_binding(
83                store,
84                *binding,
85                value,
86                mutable,
87                mut_span,
88                else_block,
89                else_span,
90                span,
91                expected_ty,
92            ),
93
94            Expression::Call {
95                expression,
96                args: call_args,
97                spread,
98                type_args,
99                span,
100                ..
101            } => {
102                let is_panic = matches!(&*expression, Expression::Identifier { value, .. } if value == "panic");
103                let result = self.infer_function_call(
104                    store,
105                    expression,
106                    call_args,
107                    spread,
108                    type_args,
109                    span,
110                    expected_ty,
111                );
112                if parent_is_subexpression && is_panic {
113                    self.sink
114                        .push(diagnostics::infer::never_call_in_expression(span));
115                }
116                result
117            }
118
119            Expression::If {
120                condition,
121                consequence,
122                alternative,
123                span,
124                ..
125            } => self.infer_if(
126                store,
127                condition,
128                consequence,
129                alternative,
130                span,
131                expected_ty,
132            ),
133
134            Expression::IfLet { .. } => {
135                unreachable!("IfLet should be desugared to Match before type inference")
136            }
137
138            Expression::Match {
139                subject,
140                arms,
141                origin,
142                span,
143                ..
144            } => self.infer_match(store, subject, arms, origin, span, expected_ty),
145
146            Expression::Tuple { elements, span, .. } => {
147                self.infer_tuple(store, elements, span, expected_ty)
148            }
149
150            Expression::StructCall {
151                name,
152                field_assignments,
153                spread,
154                span,
155                ..
156            } => self.infer_struct_call(store, name, field_assignments, spread, span, expected_ty),
157
158            Expression::DotAccess {
159                expression,
160                member,
161                span,
162                ..
163            } => self.infer_dot_access_or_qualified_path(
164                store,
165                expression,
166                member,
167                span,
168                expected_ty,
169            ),
170
171            Expression::Enum { .. } | Expression::ValueEnum { .. } => expression,
172
173            Expression::Struct { .. } => self.infer_struct_definition(store, expression),
174
175            Expression::TypeAlias { .. } => self.infer_type_alias_definition(store, expression),
176
177            Expression::VariableDeclaration { .. } => expression,
178
179            Expression::ImplBlock {
180                annotation,
181                ty: _,
182                methods,
183                receiver_name,
184                generics,
185                span,
186            } => self.infer_impl_block(store, annotation, methods, receiver_name, generics, span),
187
188            Expression::Interface { .. } => self.infer_interface(store, expression),
189
190            Expression::Assignment {
191                target,
192                value,
193                compound_operator,
194                span,
195            } => self.infer_assignment(store, target, value, compound_operator, span),
196
197            Expression::Return {
198                expression, span, ..
199            } => self.infer_return_statement(store, expression, span, parent_is_subexpression),
200
201            Expression::Propagate {
202                expression, span, ..
203            } => {
204                if parent_is_subexpression {
205                    self.check_failure_propagation_in_subexpression(&expression, span);
206                }
207                self.infer_propagate(store, expression, span, expected_ty)
208            }
209
210            Expression::TryBlock {
211                items,
212                try_keyword_span,
213                span,
214                ..
215            } => self.infer_try_block(store, items, try_keyword_span, span, expected_ty),
216
217            Expression::RecoverBlock {
218                items,
219                recover_keyword_span,
220                span,
221                ..
222            } => self.infer_recover_block(store, items, recover_keyword_span, span, expected_ty),
223
224            Expression::Binary {
225                operator,
226                left,
227                right,
228                span,
229                ..
230            } => self.infer_binary(store, operator, left, right, expected_ty, span),
231
232            Expression::Paren {
233                expression, span, ..
234            } => self.infer_paren(
235                store,
236                expression,
237                span,
238                expected_ty,
239                parent_is_subexpression,
240            ),
241
242            Expression::Unary {
243                operator,
244                expression,
245                span,
246                ..
247            } => self.infer_unary(store, operator, expression, expected_ty, span),
248
249            Expression::Const {
250                doc,
251                annotation,
252                ty: _,
253                expression,
254                span,
255                identifier,
256                identifier_span,
257                visibility,
258            } => self.infer_const_binding(
259                store,
260                doc,
261                annotation,
262                expression,
263                identifier,
264                identifier_span,
265                visibility,
266                span,
267            ),
268
269            Expression::Loop { body, span, .. } => self.infer_loop(store, body, span, expected_ty),
270
271            Expression::While {
272                condition,
273                body,
274                span,
275                ..
276            } => self.infer_while(store, condition, body, span, expected_ty),
277
278            Expression::WhileLet {
279                pattern,
280                scrutinee,
281                body,
282                span,
283                ..
284            } => self.infer_while_let(store, pattern, scrutinee, body, span, expected_ty),
285
286            Expression::For {
287                binding,
288                iterable,
289                body,
290                span,
291                ..
292            } => self.infer_for(store, *binding, iterable, body, span, expected_ty),
293
294            Expression::Reference {
295                expression, span, ..
296            } => self.infer_reference(store, expression, span, expected_ty),
297
298            Expression::IndexedAccess {
299                expression,
300                index,
301                span,
302                from_colon_syntax,
303                ..
304            } => {
305                if from_colon_syntax {
306                    self.infer_colon_subscript(store, expression, index, span)
307                } else {
308                    self.infer_indexed_access(store, expression, index, span, expected_ty)
309                }
310            }
311
312            Expression::Task {
313                expression, span, ..
314            } => {
315                // Only fire the generic ban when the dedicated
316                // `task_in_expression_position` check won't — avoids duplicates.
317                if parent_is_subexpression && !self.scopes.is_value_context() {
318                    self.sink
319                        .push(diagnostics::infer::control_flow_in_expression("task", span));
320                }
321                self.infer_task(store, expression, span, expected_ty)
322            }
323
324            Expression::Defer {
325                expression, span, ..
326            } => {
327                if parent_is_subexpression && !self.scopes.is_value_context() {
328                    self.sink
329                        .push(diagnostics::infer::control_flow_in_expression(
330                            "defer", span,
331                        ));
332                }
333                self.infer_defer(store, expression, span, expected_ty)
334            }
335
336            Expression::Select { arms, span, .. } => {
337                self.infer_select(store, arms, span, expected_ty)
338            }
339
340            Expression::ModuleImport {
341                name,
342                name_span,
343                alias,
344                span,
345            } => Expression::ModuleImport {
346                name,
347                name_span,
348                alias,
349                span,
350            },
351
352            Expression::Range {
353                start,
354                end,
355                inclusive,
356                span,
357                ..
358            } => self.infer_range(store, start, end, inclusive, span, expected_ty),
359
360            Expression::Cast {
361                expression,
362                target_type,
363                span,
364                ..
365            } => self.infer_cast(store, expression, target_type, span, expected_ty),
366
367            Expression::Break { value, span } => {
368                self.infer_break(store, value, span, parent_is_subexpression)
369            }
370            Expression::Continue { span } => self.infer_continue(span, parent_is_subexpression),
371            Expression::RawGo { text } => Expression::RawGo { text },
372            Expression::NoOp => Expression::NoOp,
373        }
374    }
375
376    pub(super) fn with_value_context<F, R>(&mut self, f: F) -> R
377    where
378        F: FnOnce(&mut Self) -> R,
379    {
380        let prev_ctx = self.scopes.set_value_context();
381        let result = f(self);
382        self.scopes.restore_use_context(prev_ctx);
383        result
384    }
385}