Skip to main content

lisette_semantics/checker/infer/expressions/
mod.rs

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