Skip to main content

rl_lang/checker/operators/
index_assign.rs

1//! Index-assign type checking (`arr[i] = value`).
2//!
3//! Validates:
4//! - The index is an `int` or `byte`
5//! - The value type matches the array's element type
6//! - `byte` widens to `int` when the array element type is `int`
7//! - Assigning `null` is always allowed (absence of value)
8
9use crate::{
10    ast::{ExprId, statements::TypeAnnotation},
11    checker::structs::{CheckType, TypeChecker},
12    utils::span::Span,
13};
14
15impl TypeChecker {
16    pub fn check_index_assign(
17        &mut self,
18        target: ExprId,
19        index: ExprId,
20        value: ExprId,
21        span: Span,
22    ) -> CheckType {
23        let target_type = self.check_expression(target);
24        let index_type = self.check_expression(index);
25        let value_type = self.check_expression(value);
26        let index_id = self.ast_arena.exprs.get(index);
27
28        // does the value type match the array/map values type?
29        match &target_type {
30            CheckType::Known(TypeAnnotation::Array(inner))
31            | CheckType::Known(TypeAnnotation::CArray(inner)) => {
32                // is the index int? (array-only rule; maps validate their
33                // own key type below instead)
34                if !matches!(
35                    index_type,
36                    CheckType::Known(TypeAnnotation::Int | TypeAnnotation::CInt)
37                        | CheckType::Unknown
38                ) {
39                    self.error(
40                        format!("index must be int, got {}", index_type.info()),
41                        index_id.span,
42                    );
43                }
44
45                let inner_ty = CheckType::Known((**inner).clone());
46
47                if !value_type.matches(&inner_ty) && !value_type.is_null() {
48                    self.error(
49                        format!(
50                            "type mismatch: array is {}, cannot assign {}",
51                            inner_ty.info(),
52                            value_type.info()
53                        ),
54                        span,
55                    );
56                }
57                value_type
58            }
59            CheckType::Known(TypeAnnotation::Set(_))
60            | CheckType::Known(TypeAnnotation::CSet(_)) => {
61                self.error("sets does not support index assigning", span);
62                CheckType::Unknown
63            }
64            CheckType::Known(TypeAnnotation::Map(key_ty, value_ty))
65            | CheckType::Known(TypeAnnotation::CMap(key_ty, value_ty)) => {
66                let expected_key = CheckType::Known((**key_ty).clone());
67                if !index_type.matches(&expected_key) {
68                    self.error(
69                        format!(
70                            "map key type mismatch: expected {}, got {}",
71                            expected_key.info(),
72                            index_type.info()
73                        ),
74                        index_id.span,
75                    );
76                }
77
78                let expected_value = CheckType::Known((**value_ty).clone());
79                if !value_type.matches(&expected_value) && !value_type.is_null() {
80                    self.error(
81                        format!(
82                            "type mismatch: map value is {}, cannot assign {}",
83                            expected_value.info(),
84                            value_type.info()
85                        ),
86                        span,
87                    );
88                }
89                value_type
90            }
91            CheckType::Unknown => CheckType::Unknown,
92            other => {
93                self.error(format!("cannot index-assign into {}", other.info()), span);
94                CheckType::Unknown
95            }
96        }
97    }
98}