Skip to main content

lisette_semantics/checker/registration/
builtins.rs

1use crate::checker::EnvResolve;
2use syntax::types::{CompoundKind, SimpleKind, Symbol, Type};
3
4use crate::checker::TaskState;
5use crate::store::Store;
6
7impl TaskState<'_> {
8    fn builtin_qualified_name(&mut self, store: &Store, type_name: &str) -> Symbol {
9        self.lookup_qualified_name(store, type_name)
10            .map(Symbol::from)
11            .unwrap_or_else(|| panic!("Builtin type {type_name} not found in store"))
12    }
13
14    fn builtin_type(&mut self, store: &Store, type_name: &str) -> Type {
15        if let Some(ty) = self.builtins.get(type_name) {
16            return ty.clone();
17        }
18
19        let qualified_name = self.builtin_qualified_name(store, type_name);
20
21        let ty = store
22            .get_type(&qualified_name)
23            .unwrap_or_else(|| panic!("Builtin type {type_name} not found in store"));
24
25        let body = match &ty {
26            Type::Forall { body, .. } => body.as_ref().clone(),
27            _ => ty.clone(),
28        };
29
30        self.builtins.insert(type_name.to_string(), body.clone());
31
32        body
33    }
34
35    pub fn type_unit(&self) -> Type {
36        Type::unit()
37    }
38
39    pub fn type_never(&self) -> Type {
40        Type::Never
41    }
42
43    pub fn type_int(&mut self) -> Type {
44        Type::Simple(SimpleKind::Int)
45    }
46
47    pub fn type_float(&mut self) -> Type {
48        Type::Simple(SimpleKind::Float64)
49    }
50
51    pub fn type_string(&mut self) -> Type {
52        Type::Simple(SimpleKind::String)
53    }
54
55    pub fn type_char(&mut self) -> Type {
56        Type::Simple(SimpleKind::Rune)
57    }
58
59    pub fn type_bool(&mut self) -> Type {
60        Type::Simple(SimpleKind::Bool)
61    }
62
63    pub fn type_complex128(&mut self) -> Type {
64        Type::Simple(SimpleKind::Complex128)
65    }
66
67    pub fn type_unknown(&mut self, store: &Store) -> Type {
68        self.builtin_type(store, "Unknown")
69    }
70
71    pub fn type_slice(&mut self, element_type: Type) -> Type {
72        Type::Compound {
73            kind: CompoundKind::Slice,
74            args: vec![element_type],
75        }
76    }
77
78    pub fn type_reference(&mut self, inner_type: Type) -> Type {
79        Type::Compound {
80            kind: CompoundKind::Ref,
81            args: vec![inner_type],
82        }
83    }
84
85    pub fn type_map(&mut self, key_type: Type, value_type: Type) -> Type {
86        Type::Compound {
87            kind: CompoundKind::Map,
88            args: vec![key_type, value_type],
89        }
90    }
91
92    pub fn type_result(&mut self, store: &Store, ok_type: Type, error_type: Type) -> Type {
93        Type::Nominal {
94            id: self.builtin_qualified_name(store, "Result"),
95            params: vec![ok_type, error_type],
96            underlying_ty: None,
97        }
98    }
99
100    pub fn type_option(&mut self, store: &Store, some_type: Type) -> Type {
101        Type::Nominal {
102            id: self.builtin_qualified_name(store, "Option"),
103            params: vec![some_type],
104            underlying_ty: None,
105        }
106    }
107
108    pub fn type_panic_value(&mut self, store: &Store) -> Type {
109        Type::Nominal {
110            id: self.builtin_qualified_name(store, "PanicValue"),
111            params: vec![],
112            underlying_ty: None,
113        }
114    }
115
116    pub fn type_range(&mut self, store: &Store, element_type: Type) -> Type {
117        Type::Nominal {
118            id: self.builtin_qualified_name(store, "Range"),
119            params: vec![element_type],
120            underlying_ty: None,
121        }
122    }
123
124    pub fn type_range_inclusive(&mut self, store: &Store, element_type: Type) -> Type {
125        Type::Nominal {
126            id: self.builtin_qualified_name(store, "RangeInclusive"),
127            params: vec![element_type],
128            underlying_ty: None,
129        }
130    }
131
132    pub fn type_range_from(&mut self, store: &Store, element_type: Type) -> Type {
133        Type::Nominal {
134            id: self.builtin_qualified_name(store, "RangeFrom"),
135            params: vec![element_type],
136            underlying_ty: None,
137        }
138    }
139
140    pub fn type_range_to(&mut self, store: &Store, element_type: Type) -> Type {
141        Type::Nominal {
142            id: self.builtin_qualified_name(store, "RangeTo"),
143            params: vec![element_type],
144            underlying_ty: None,
145        }
146    }
147
148    pub fn type_range_to_inclusive(&mut self, store: &Store, element_type: Type) -> Type {
149        Type::Nominal {
150            id: self.builtin_qualified_name(store, "RangeToInclusive"),
151            params: vec![element_type],
152            underlying_ty: None,
153        }
154    }
155
156    /// Checks if a type is a generic container (Option, Result) whose
157    /// type parameter needs the expected type to flow through for
158    /// codegen: Go interfaces (for method-set satisfaction) or
159    /// Go-imported named types (for Go generic instantiation preserving
160    /// alias names like `tea.Cmd` instead of collapsing to the
161    /// underlying `func() Msg`).
162    pub fn is_generic_container_with_interface(&self, store: &Store, ty: &Type) -> bool {
163        let resolved = ty.resolve_in(&self.env);
164        let Type::Nominal { id, params, .. } = &resolved else {
165            return false;
166        };
167
168        if id != "prelude.Option" && id != "prelude.Result" {
169            return false;
170        }
171
172        params.iter().any(|p| {
173            if let Type::Nominal { id, .. } = p.resolve_in(&self.env) {
174                store.get_interface(&id).is_some() || id.starts_with("go:")
175            } else {
176                false
177            }
178        })
179    }
180}