rl_lang/checker/scope/
assign.rs1use crate::{
4 checker::structs::{CheckType, TypeChecker},
5 utils::{span::Span, suggest::closest_match},
6};
7
8impl TypeChecker {
9 pub fn assign(&mut self, name: &str, value_type: CheckType, span: Span) {
16 let mut const_error: Option<String> = None;
17 let mut type_error: Option<String> = None;
18 let mut found = false;
19
20 for scope in self.scopes.iter_mut().rev() {
21 if let Some(item) = scope.get_mut(name) {
22 found = true;
23
24 if item.is_const {
25 const_error = Some(format!("cannot assign to constant '{}'", name));
26 } else if !value_type.matches(&item.type_annotation) && !value_type.is_null() {
27 type_error = Some(format!(
28 "cannot assign {} to variable '{}' declared as {}",
29 value_type.info(),
30 name,
31 item.type_annotation.info(),
32 ));
33 }
34 break;
35 }
36 }
37
38 if let Some(msg) = const_error.or(type_error) {
39 self.error(msg, span);
40 return;
41 }
42
43 if !found {
44 let all_keys: Vec<String> = self
45 .scopes
46 .iter()
47 .flat_map(|s| s.keys().cloned().collect::<Vec<_>>())
48 .collect();
49 let suggestion = closest_match(name, all_keys.iter().map(|s| s.as_str()));
50
51 self.error_with_help(format!("undefined variable '{}'", name), span, suggestion);
52 }
53 }
54}