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