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 crate::checker::infer::InferCtx;
20
21impl InferCtx<'_, '_> {
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 = self.scopes.set_in_subexpression(true);
26
27        let result = self.infer_expression_inner(expression, expected_ty, parent_is_subexpression);
28
29        self.scopes.set_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                spread,
87                type_args,
88                span,
89                ..
90            } => {
91                let is_panic = matches!(&*expression, Expression::Identifier { value, .. } if value == "panic");
92                let result = self.infer_function_call(
93                    expression,
94                    call_args,
95                    spread,
96                    type_args,
97                    span,
98                    expected_ty,
99                );
100                if parent_is_subexpression && is_panic {
101                    self.sink
102                        .push(diagnostics::infer::never_call_in_expression(span));
103                }
104                result
105            }
106
107            Expression::If {
108                condition,
109                consequence,
110                alternative,
111                span,
112                ..
113            } => self.infer_if(condition, consequence, alternative, span, expected_ty),
114
115            Expression::IfLet { .. } => {
116                unreachable!("IfLet should be desugared to Match before type inference")
117            }
118
119            Expression::Match {
120                subject,
121                arms,
122                origin,
123                span,
124                ..
125            } => self.infer_match(subject, arms, origin, span, expected_ty),
126
127            Expression::Tuple { elements, span, .. } => {
128                self.infer_tuple(elements, span, expected_ty)
129            }
130
131            Expression::StructCall {
132                name,
133                field_assignments,
134                spread,
135                span,
136                ..
137            } => self.infer_struct_call(name, field_assignments, spread, span, expected_ty),
138
139            Expression::DotAccess {
140                expression,
141                member,
142                span,
143                ..
144            } => self.infer_dot_access_or_qualified_path(expression, member, span, expected_ty),
145
146            Expression::Enum { .. } => expression,
147
148            Expression::Struct { .. } => self.infer_struct_definition(expression),
149
150            Expression::TypeAlias { .. } => self.infer_type_alias_definition(expression),
151
152            Expression::VariableDeclaration { .. } => expression,
153
154            Expression::ImplBlock {
155                annotation,
156                ty: _,
157                methods,
158                receiver_name,
159                generics,
160                span,
161            } => self.infer_impl_block(annotation, methods, receiver_name, generics, span),
162
163            Expression::Interface { .. } => self.infer_interface(expression),
164
165            Expression::Assignment {
166                target,
167                value,
168                compound_operator,
169                span,
170            } => self.infer_assignment(target, value, compound_operator, span),
171
172            Expression::Return {
173                expression, span, ..
174            } => self.infer_return_statement(expression, span, parent_is_subexpression),
175
176            Expression::Propagate {
177                expression, span, ..
178            } => {
179                if parent_is_subexpression {
180                    self.check_failure_propagation_in_subexpression(&expression, span);
181                }
182                self.infer_propagate(expression, span, expected_ty)
183            }
184
185            Expression::TryBlock {
186                items,
187                try_keyword_span,
188                span,
189                ..
190            } => self.infer_try_block(items, try_keyword_span, span, expected_ty),
191
192            Expression::RecoverBlock {
193                items,
194                recover_keyword_span,
195                span,
196                ..
197            } => self.infer_recover_block(items, recover_keyword_span, span, expected_ty),
198
199            Expression::Binary {
200                operator,
201                left,
202                right,
203                span,
204                ..
205            } => self.infer_binary(operator, left, right, expected_ty, span),
206
207            Expression::Paren {
208                expression, span, ..
209            } => self.infer_paren(expression, span, expected_ty, parent_is_subexpression),
210
211            Expression::Unary {
212                operator,
213                expression,
214                span,
215                ..
216            } => self.infer_unary(operator, expression, expected_ty, span),
217
218            Expression::Const {
219                doc,
220                annotation,
221                ty: _,
222                expression,
223                span,
224                identifier,
225                identifier_span,
226                visibility,
227            } => self.infer_const_binding(
228                doc,
229                annotation,
230                expression,
231                identifier,
232                identifier_span,
233                visibility,
234                span,
235            ),
236
237            Expression::Loop { body, span, .. } => self.infer_loop(body, span, expected_ty),
238
239            Expression::While {
240                condition,
241                body,
242                span,
243                ..
244            } => self.infer_while(condition, body, span, expected_ty),
245
246            Expression::WhileLet {
247                pattern,
248                scrutinee,
249                body,
250                span,
251                ..
252            } => self.infer_while_let(pattern, scrutinee, body, span, expected_ty),
253
254            Expression::For {
255                binding,
256                iterable,
257                body,
258                span,
259                ..
260            } => self.infer_for(*binding, iterable, body, span, expected_ty),
261
262            Expression::Reference {
263                expression, span, ..
264            } => self.infer_reference(expression, span, expected_ty),
265
266            Expression::IndexedAccess {
267                expression,
268                index,
269                span,
270                from_colon_syntax,
271                ..
272            } => {
273                if from_colon_syntax {
274                    self.infer_colon_subscript(expression, index, span)
275                } else {
276                    self.infer_indexed_access(expression, index, span, expected_ty)
277                }
278            }
279
280            Expression::Task {
281                expression, span, ..
282            } => {
283                // Only fire the generic ban when the dedicated
284                // `task_in_expression_position` check won't — avoids duplicates.
285                if parent_is_subexpression && !self.scopes.is_value_context() {
286                    self.sink
287                        .push(diagnostics::infer::control_flow_in_expression("task", span));
288                }
289                self.infer_task(expression, span, expected_ty)
290            }
291
292            Expression::Defer {
293                expression, span, ..
294            } => {
295                if parent_is_subexpression && !self.scopes.is_value_context() {
296                    self.sink
297                        .push(diagnostics::infer::control_flow_in_expression(
298                            "defer", span,
299                        ));
300                }
301                self.infer_defer(expression, span, expected_ty)
302            }
303
304            Expression::Select { arms, span, .. } => self.infer_select(arms, span, expected_ty),
305
306            Expression::ModuleImport {
307                name,
308                name_span,
309                alias,
310                span,
311            } => Expression::ModuleImport {
312                name,
313                name_span,
314                alias,
315                span,
316            },
317
318            Expression::Range {
319                start,
320                end,
321                inclusive,
322                span,
323                ..
324            } => self.infer_range(start, end, inclusive, span, expected_ty),
325
326            Expression::Cast {
327                expression,
328                target_type,
329                span,
330                ..
331            } => self.infer_cast(expression, target_type, span, expected_ty),
332
333            Expression::Break { value, span } => {
334                self.infer_break(value, span, parent_is_subexpression)
335            }
336            Expression::Continue { span } => self.infer_continue(span, parent_is_subexpression),
337            Expression::RawGo { text } => Expression::RawGo { text },
338            Expression::NoOp => Expression::NoOp,
339        }
340    }
341
342    pub(super) fn with_value_context<F, R>(&mut self, f: F) -> R
343    where
344        F: FnOnce(&mut Self) -> R,
345    {
346        let prev_ctx = self.scopes.set_value_context();
347        let result = f(self);
348        self.scopes.restore_use_context(prev_ctx);
349        result
350    }
351}