Skip to main content

rl_lang/checker/statements/
expression.rs

1//! Expression type checking - walks every [`ExpressionKind`] variant and
2//! returns the static [`CheckType`] of the expression.
3
4use std::rc::Rc;
5
6use crate::{
7    ast::{ExprId, nodes::ExpressionKind, statements::TypeAnnotation},
8    checker::{TypeChecker, structs::CheckType},
9    utils::span::Span,
10};
11
12impl TypeChecker {
13    pub fn check_expression(&mut self, expression: ExprId) -> CheckType {
14        let expr_span = self.ast_arena.exprs.get(expression).span;
15        let expr_kind = self.ast_arena.exprs.get(expression).kind.clone();
16        match expr_kind {
17            // returns as type
18            ExpressionKind::Null => CheckType::Known(TypeAnnotation::Null),
19            ExpressionKind::Integer(_) => CheckType::Known(TypeAnnotation::Int),
20            ExpressionKind::Byte(_) => CheckType::Known(TypeAnnotation::Byte),
21            ExpressionKind::String(_) => CheckType::Known(TypeAnnotation::String),
22            ExpressionKind::Bool(_) => CheckType::Known(TypeAnnotation::Bool),
23            ExpressionKind::Float(_) => CheckType::Known(TypeAnnotation::Float),
24            ExpressionKind::Character(_) => CheckType::Known(TypeAnnotation::Char),
25            // returns the inner type
26            ExpressionKind::Grouping(inner) => self.check_expression(inner),
27            // does this identifier exist?
28            ExpressionKind::Identifier(name) => self.lookup(&name, expr_span),
29            ExpressionKind::MapLiteral(entries) => {
30                let mut key_types = Vec::with_capacity(entries.len());
31                let mut value_types = Vec::with_capacity(entries.len());
32                for (key, value) in entries {
33                    let key_span = self.ast_arena.exprs.get(key).span;
34                    let value_span = self.ast_arena.exprs.get(value).span;
35                    key_types.push((self.check_expression(key), key_span));
36                    value_types.push((self.check_expression(value), value_span));
37                }
38
39                let key_type = key_types
40                    .first()
41                    .map(|(t, _)| Self::to_type_annotation(t))
42                    .unwrap_or(TypeAnnotation::Null);
43                let value_type = value_types
44                    .first()
45                    .map(|(t, _)| Self::to_type_annotation(t))
46                    .unwrap_or(TypeAnnotation::Null);
47
48                if let Some((first_key, _)) = key_types.first().cloned() {
49                    for (kt, span) in key_types.iter().skip(1) {
50                        if !kt.is_null() && !first_key.is_null() && !kt.matches(&first_key) {
51                            self.error(
52                                format!(
53                                    "map key type mismatch: expected {}, got {}",
54                                    first_key.info(),
55                                    kt.info()
56                                ),
57                                *span,
58                            );
59                        }
60                    }
61                }
62                if let Some((first_value, _)) = value_types.first().cloned() {
63                    for (vt, span) in value_types.iter().skip(1) {
64                        if !vt.is_null() && !first_value.is_null() && !vt.matches(&first_value) {
65                            self.error(
66                                format!(
67                                    "map value type mismatch: expected {}, got {}",
68                                    first_value.info(),
69                                    vt.info()
70                                ),
71                                *span,
72                            );
73                        }
74                    }
75                }
76
77                for (kt, span) in &key_types {
78                    if !kt.is_null() && !Self::is_hashable_key_type(&Self::to_type_annotation(kt)) {
79                        self.error(
80                            format!("type {} cannot be used as a map key", kt.info()),
81                            *span,
82                        );
83                    }
84                }
85
86                CheckType::Known(TypeAnnotation::Map(
87                    Box::new(key_type),
88                    Box::new(value_type),
89                ))
90            }
91            // checks array items
92            ExpressionKind::ArrayLiteral(items) => {
93                // checks every item type in items then push it to the new
94                // item_types vec
95                let mut item_types = Vec::with_capacity(items.len());
96                for item in items {
97                    let item_span = self.ast_arena.exprs.get(item).span;
98                    item_types.push((self.check_expression(item), item_span));
99                }
100                // sets the items types to same first item type otherwise null
101                let items_type = item_types
102                    .first()
103                    .map(|(t, _)| Self::to_type_annotation(t))
104                    .unwrap_or(TypeAnnotation::Null);
105
106                // same items type or not?
107                if let Some((first_type, _)) = item_types.first().cloned() {
108                    for (item_type, span) in item_types.iter().skip(1) {
109                        if !item_type.is_null()
110                            && !first_type.is_null()
111                            && !item_type.matches(&first_type)
112                        {
113                            self.error(
114                                format!(
115                                    "array element type mismatch: expected {}, got {}",
116                                    first_type.info(),
117                                    item_type.info()
118                                ),
119                                *span,
120                            );
121                        }
122                    }
123                }
124                // returns the array type
125                CheckType::Known(TypeAnnotation::Array(Box::new(items_type)))
126            }
127
128            ExpressionKind::Index { target, index } => {
129                // is the target (array) null?
130                let target_span = self.ast_arena.exprs.get(target).span;
131                let index_span = self.ast_arena.exprs.get(index).span;
132                let target_type = self.check_expression(target);
133                self.check_is_null(&target_type, target_span);
134                // is the index null??
135                let index_type = self.check_expression(index);
136                self.check_is_null(&index_type, index_span);
137
138                // is it integer? (only enforced for array/tuple targets -
139                // maps validate the index against their declared key type
140                // further down instead)
141                let target_is_map = matches!(
142                    target_type,
143                    CheckType::Known(TypeAnnotation::Map(_, _) | TypeAnnotation::CMap(_, _))
144                );
145                if !target_is_map
146                    && !matches!(
147                        index_type,
148                        CheckType::Known(
149                            TypeAnnotation::Int
150                                | TypeAnnotation::CInt
151                                | TypeAnnotation::Byte
152                                | TypeAnnotation::CByte
153                        ) | CheckType::Unknown
154                    )
155                {
156                    self.error(
157                        format!("invalid index operation: index is {}", index_type.info()),
158                        expr_span,
159                    );
160                }
161
162                // is the target actually an array?
163                // if it is array return its items type
164                match &target_type {
165                    CheckType::Known(TypeAnnotation::Array(inner))
166                    | CheckType::Known(TypeAnnotation::CArray(inner)) => {
167                        CheckType::Known((**inner).clone())
168                    }
169                    CheckType::Known(TypeAnnotation::Set(inner))
170                    | CheckType::Known(TypeAnnotation::CSet(inner)) => {
171                        CheckType::Known((**inner).clone())
172                    }
173                    CheckType::Known(TypeAnnotation::Map(key_ty, value_ty))
174                    | CheckType::Known(TypeAnnotation::CMap(key_ty, value_ty)) => {
175                        let expected_key = CheckType::Known((**key_ty).clone());
176                        if !index_type.matches(&expected_key) {
177                            self.error(
178                                format!(
179                                    "map key type mismatch: expected {}, got {}",
180                                    expected_key.info(),
181                                    index_type.info()
182                                ),
183                                index_span,
184                            );
185                        }
186                        CheckType::Known((**value_ty).clone())
187                    }
188                    CheckType::Unknown | CheckType::Known(TypeAnnotation::Null) => {
189                        CheckType::Unknown
190                    }
191                    CheckType::Known(TypeAnnotation::Tuple(_) | TypeAnnotation::CTuple(_)) => {
192                        CheckType::Unknown
193                    }
194                    other => {
195                        self.error(
196                            format!("invalid index operation: this is {}", other.info()),
197                            expr_span,
198                        );
199                        CheckType::Unknown
200                    }
201                }
202            }
203
204            // offloads to index_assign
205            ExpressionKind::IndexAssign {
206                target,
207                index,
208                value,
209            } => self.check_index_assign(target, index, value, expr_span),
210
211            // offloads to binary
212            ExpressionKind::Binary {
213                left,
214                operator,
215                right,
216            } => {
217                // is the left operand null?
218                let left_type = self.check_expression(left);
219                let left_id = self.ast_arena.exprs.get(left);
220                self.check_is_null(&left_type, left_id.span);
221                // is the right operand null?
222                let right_type = self.check_expression(right);
223                let right_id = self.ast_arena.exprs.get(right);
224                self.check_is_null(&right_type, right_id.span);
225                // is the binary correct?
226                self.check_binary_operator(left_type, right_type, &operator, expr_span)
227            }
228
229            // offloads to unary
230            ExpressionKind::Unary { operator, operand } => {
231                // is the operand null?
232                let operand_span = self.ast_arena.exprs.get(operand).span;
233                let operand_type = self.check_expression(operand);
234                self.check_is_null(&operand_type, operand_span);
235                // is the unary correct?
236                self.check_unary_operator(operand_type, operand_span, &operator, expr_span)
237            }
238
239            // assigns the value to the variable then returns it
240            ExpressionKind::Assign { name, value } => {
241                let value_type = self.check_expression(value);
242                self.assign(&name, value_type.clone(), expr_span);
243                value_type
244            }
245
246            // checks the call path of the function
247            ExpressionKind::Call { path, args } => {
248                let arg_types: Vec<(CheckType, Span)> = args
249                    .iter()
250                    .map(|a| {
251                        let a = *a;
252                        let a_span = self.ast_arena.exprs.get(a).span;
253                        (self.check_expression(a), a_span)
254                    })
255                    .collect();
256                self.check_call_path(&path, &arg_types, expr_span)
257            }
258
259            // checks the call of the function
260            ExpressionKind::CallExpr { callee, args } => {
261                let callee_type = self.check_expression(callee);
262                let arg_types: Vec<(CheckType, Span)> = args
263                    .iter()
264                    .map(|a| {
265                        let a = *a;
266                        let a_span = self.ast_arena.exprs.get(a).span;
267                        (self.check_expression(a), a_span)
268                    })
269                    .collect();
270                self.check_call_value(callee_type, &arg_types, expr_span)
271            }
272
273            // checks the method call
274            ExpressionKind::MethodCall {
275                caller,
276                method,
277                args,
278            } => {
279                let caller_type = self.check_expression(caller);
280                let caller_id = self.ast_arena.exprs.get(caller);
281                let mut arg_types: Vec<(CheckType, Span)> = vec![(caller_type, caller_id.span)];
282                for arg in args {
283                    let arg_span = self.ast_arena.exprs.get(arg).span;
284                    arg_types.push((self.check_expression(arg), arg_span));
285                }
286                self.check_call_path(&method, &arg_types, expr_span)
287            }
288
289            // checks the lambda and transforms it to function type
290            ExpressionKind::Lambda {
291                params,
292                return_type,
293                body,
294            } => {
295                // resolves the return type
296                let resolved_return = return_type.clone().unwrap_or(TypeAnnotation::Null);
297                // add scope level
298                self.push_scope();
299                // declare the params
300                for param in &params {
301                    self.declare(
302                        param.param_name.clone(),
303                        CheckType::Known(param.param_type.clone()),
304                        false,
305                        expr_span,
306                    );
307                }
308                // add the resolved return type as the expected return
309                self.push_return_type(resolved_return.clone());
310                // is the body correct?
311                for statement in &body {
312                    self.check_statement(statement);
313                }
314                // removes return type
315                self.pop_return_type();
316                // remove scope level
317                self.pop_scope();
318
319                CheckType::Function {
320                    params: params.iter().map(|p| p.param_type.clone()).collect(),
321                    return_type: resolved_return,
322                }
323            }
324
325            ExpressionKind::Cast { value, target_type } => {
326                let value_type = self.check_expression(value);
327                let value_id = self.ast_arena.exprs.get(value);
328                self.check_is_null(&value_type, value_id.span);
329
330                let castable = matches!(
331                    &value_type,
332                    CheckType::Known(
333                        TypeAnnotation::CInt
334                            | TypeAnnotation::CByte
335                            | TypeAnnotation::CFloat
336                            | TypeAnnotation::Float
337                            | TypeAnnotation::Int
338                            | TypeAnnotation::Byte
339                    ) | CheckType::Unknown
340                );
341
342                let valid_target = matches!(
343                    target_type,
344                    TypeAnnotation::Int | TypeAnnotation::Float | TypeAnnotation::Byte
345                );
346
347                if !castable || !valid_target {
348                    self.error(
349                        format!(
350                            "invalid cast: cannot cast {} to {:?}",
351                            value_type.info(),
352                            target_type
353                        ),
354                        expr_span,
355                    );
356                }
357                CheckType::Unknown
358            }
359
360            ExpressionKind::TupleLiteral(items) => {
361                let types: Vec<TypeAnnotation> = items
362                    .iter()
363                    .map(|item| {
364                        let t = self.check_expression(*item);
365                        Self::to_type_annotation(&t)
366                    })
367                    .collect();
368                CheckType::Known(TypeAnnotation::Tuple(Rc::new(types)))
369            }
370            ExpressionKind::ErrorLiteral(inner) => {
371                let inner_type = self.check_expression(inner);
372                if matches!(
373                    inner_type,
374                    CheckType::Known(TypeAnnotation::Error | TypeAnnotation::CError)
375                ) {
376                    self.error("error cannot wrap another error", expr_span);
377                }
378                CheckType::Known(TypeAnnotation::Error)
379            }
380            ExpressionKind::OkLiteral(inner) => {
381                let inner_ann = Self::to_type_annotation(&self.check_expression(inner));
382                CheckType::Known(TypeAnnotation::Result(Box::new(inner_ann)))
383            }
384            ExpressionKind::ErrLiteral(inner) => {
385                let inner_ann = Self::to_type_annotation(&self.check_expression(inner));
386                CheckType::Known(TypeAnnotation::Result(Box::new(inner_ann)))
387            }
388
389            ExpressionKind::Propagate(inner) => {
390                self.check_expression(inner);
391                CheckType::Unknown
392            }
393
394            ExpressionKind::StructLiteral { name, fields } => {
395                if let Some(declared_fields) = self.records.get(&name).cloned() {
396                    for (field_name, value) in &fields {
397                        let value_span = self.ast_arena.exprs.get(*value).span;
398                        let value_type = self.check_expression(*value);
399                        match declared_fields.iter().find(|(n, _)| n == field_name) {
400                            Some((_, field_type)) => {
401                                let expected = CheckType::Known(field_type.clone());
402                                if !value_type.matches(&expected) {
403                                    self.error(
404                                        format!(
405                                            "field `{}` of record `{}` expects {}, got {}",
406                                            field_name,
407                                            name,
408                                            expected.info(),
409                                            value_type.info()
410                                        ),
411                                        value_span,
412                                    );
413                                }
414                            }
415                            None => {
416                                self.error(
417                                    format!("record `{}` has no field `{}`", name, field_name),
418                                    value_span,
419                                );
420                            }
421                        }
422                    }
423                    if fields.len() != declared_fields.len() {
424                        self.error(
425                            format!(
426                                "record `{}` expects {} field(s), got {}",
427                                name,
428                                declared_fields.len(),
429                                fields.len()
430                            ),
431                            expr_span,
432                        );
433                    }
434                } else {
435                    self.error(format!("unknown record type `{}`", name), expr_span);
436                    for (_, value) in &fields {
437                        self.check_expression(*value);
438                    }
439                }
440                CheckType::Known(TypeAnnotation::Record(name))
441            }
442
443            ExpressionKind::FieldAccess { target, field } => {
444                let target_type = self.check_expression(target);
445                match &target_type {
446                    CheckType::Known(
447                        TypeAnnotation::Record(name) | TypeAnnotation::CRecord(name),
448                    ) => {
449                        match self.records.get(name).and_then(|fs| {
450                            fs.iter().find(|(n, _)| *n == field).map(|(_, t)| t.clone())
451                        }) {
452                            Some(field_type) => CheckType::Known(field_type),
453                            None => {
454                                self.error(
455                                    format!("record `{}` has no field `{}`", name, field),
456                                    expr_span,
457                                );
458                                CheckType::Unknown
459                            }
460                        }
461                    }
462                    CheckType::Unknown => CheckType::Unknown,
463                    other => {
464                        self.error(
465                            format!("cannot access field `{}` on {}", field, other.info()),
466                            expr_span,
467                        );
468                        CheckType::Unknown
469                    }
470                }
471            }
472
473            ExpressionKind::FieldAssign {
474                target,
475                field,
476                value,
477            } => {
478                let target_type = self.check_expression(target);
479                let value_type = self.check_expression(value);
480                match &target_type {
481                    CheckType::Known(
482                        TypeAnnotation::Record(name) | TypeAnnotation::CRecord(name),
483                    ) => {
484                        match self.records.get(name).and_then(|fs| {
485                            fs.iter().find(|(n, _)| *n == field).map(|(_, t)| t.clone())
486                        }) {
487                            Some(field_type) => {
488                                let expected = CheckType::Known(field_type);
489                                if !value_type.matches(&expected) {
490                                    self.error(
491                                        format!(
492                                            "field `{}` of record `{}` expects {}, got {}",
493                                            field,
494                                            name,
495                                            expected.info(),
496                                            value_type.info()
497                                        ),
498                                        expr_span,
499                                    );
500                                }
501                            }
502                            None => {
503                                self.error(
504                                    format!("record `{}` has no field `{}`", name, field),
505                                    expr_span,
506                                );
507                            }
508                        }
509                    }
510                    CheckType::Unknown => {}
511                    other => {
512                        self.error(
513                            format!("cannot assign field `{}` on {}", field, other.info()),
514                            expr_span,
515                        );
516                    }
517                }
518                value_type
519            }
520
521            ExpressionKind::EnumVariant { enum_name, variant } => {
522                match self.tags.get(&enum_name) {
523                    Some(variants) => {
524                        if !variants.contains(&variant) {
525                            self.error(
526                                format!("tag `{}` has no variant `{}`", enum_name, variant),
527                                expr_span,
528                            );
529                        }
530                    }
531                    None => {
532                        self.error(format!("unknown tag type `{}`", enum_name), expr_span);
533                    }
534                }
535                CheckType::Known(TypeAnnotation::Enum(enum_name))
536            }
537
538            ExpressionKind::SetLiteral(items) => {
539                let mut item_types = Vec::with_capacity(items.len());
540                for item in items {
541                    let item_span = self.ast_arena.exprs.get(item).span;
542                    item_types.push((self.check_expression(item), item_span));
543                }
544
545                let items_type = item_types
546                    .first()
547                    .map(|(t, _)| Self::to_type_annotation(t))
548                    .unwrap_or(TypeAnnotation::Null);
549
550                if let Some((first_type, _)) = item_types.first().cloned() {
551                    for (item_type, span) in item_types.iter().skip(1) {
552                        if !item_type.is_null()
553                            && !first_type.is_null()
554                            && !item_type.matches(&first_type)
555                        {
556                            self.error(
557                                format!(
558                                    "set element type mismatch: expected {}, got {}",
559                                    first_type.info(),
560                                    item_type.info()
561                                ),
562                                *span,
563                            );
564                        }
565                    }
566                }
567
568                CheckType::Known(TypeAnnotation::Set(Box::new(items_type)))
569            }
570
571            _ => CheckType::Unknown,
572        }
573    }
574}