lisette_semantics/checker/infer/
mod.rs1pub(crate) mod addressability;
2mod carry_mut;
3pub(crate) mod expressions;
4mod interface;
5mod unify;
6mod validation;
7
8pub(crate) use unify::BuiltinBound;
9
10use rustc_hash::{FxHashMap as HashMap, FxHashSet as HashSet};
11
12use super::freeze::FreezeFolder;
13use super::{FileContextKind, TaskState};
14use crate::store::Store;
15use syntax::ast::Expression;
16use syntax::program::{File, FileImport};
17
18impl TaskState<'_> {
19 pub fn infer_module(&mut self, store: &Store, module_id: &str, files: Vec<File>) {
21 let items_per_file: Vec<&[Expression]> = files.iter().map(|f| f.items.as_slice()).collect();
22 self.check_const_cycles(store, &items_per_file);
23
24 for file in files {
25 self.infer_file(store, module_id, file);
26 }
27 }
28
29 pub fn take_module_files(&mut self, store: &mut Store, module_id: &str) -> Vec<File> {
31 self.with_module_cursor(module_id, |_this| {
32 let module = store
33 .get_module_mut(module_id)
34 .expect("module must exist for inference");
35 std::mem::take(&mut module.files).into_values().collect()
36 })
37 }
38
39 fn infer_file(&mut self, store: &Store, module_id: &str, file: File) {
40 let file_id = file.id;
41 let imports = file.imports();
42
43 self.with_file_context(
44 store,
45 module_id,
46 file_id,
47 &imports,
48 FileContextKind::Standard,
49 |this, store| {
50 this.check_definition_module_collisions(store, &file.items, &imports);
51
52 let inferred_items: Vec<_> = file
53 .items
54 .into_iter()
55 .map(|item| {
56 let type_var = this.new_type_var();
57 this.infer_expression(store, item, &type_var)
58 })
59 .collect();
60
61 this.check_reference_sibling_aliasing(&inferred_items);
62
63 let folder = FreezeFolder::new(&this.env);
64 folder.freeze_facts(&mut this.facts);
65 let frozen_items = FreezeFolder::new(&this.env).freeze_items(inferred_items);
66
67 let typed_file = File {
68 id: file_id,
69 module_id: file.module_id,
70 name: file.name,
71 display_path: file.display_path,
72 source: file.source,
73 items: frozen_items,
74 };
75
76 this.typed_files.push((module_id.to_string(), typed_file));
77 },
78 );
79 }
80
81 fn check_definition_module_collisions(
82 &mut self,
83 store: &Store,
84 items: &[Expression],
85 imports: &[FileImport],
86 ) {
87 let alias_to_path: HashMap<String, String> = imports
88 .iter()
89 .filter_map(|imp| {
90 imp.effective_alias(&store.go_package_names)
91 .map(|alias| (alias, imp.name.to_string()))
92 })
93 .collect();
94
95 for item in items {
96 let (definition_name, name_span) = match item {
97 Expression::Function {
98 name, name_span, ..
99 } => (name.as_str(), *name_span),
100 Expression::Struct {
101 name, name_span, ..
102 } => (name.as_str(), *name_span),
103 Expression::Enum {
104 name, name_span, ..
105 } => (name.as_str(), *name_span),
106 Expression::ValueEnum {
107 name, name_span, ..
108 } => (name.as_str(), *name_span),
109 Expression::TypeAlias {
110 name, name_span, ..
111 } => (name.as_str(), *name_span),
112 Expression::Const {
113 identifier,
114 identifier_span,
115 ..
116 } => (identifier.as_str(), *identifier_span),
117 Expression::Interface {
118 name, name_span, ..
119 } => (name.as_str(), *name_span),
120 _ => continue,
121 };
122
123 if let Some(import_path) = alias_to_path.get(definition_name) {
124 self.sink
125 .push(diagnostics::infer::definition_shadows_import(
126 definition_name,
127 import_path,
128 name_span,
129 ));
130 }
131 }
132 }
133
134 pub(crate) fn register_block_local_items(&mut self, store: &Store, items: &[Expression]) {
135 for item in items {
136 match item {
137 Expression::Const { .. } => self.register_block_local_const(store, item),
138 Expression::Function { .. } => self.register_block_local_fn(store, item),
139 _ => {}
140 }
141 }
142 }
143
144 fn register_block_local_const(&mut self, store: &Store, item: &Expression) {
145 let Expression::Const {
146 identifier,
147 identifier_span,
148 annotation,
149 expression,
150 span,
151 ..
152 } = item
153 else {
154 return;
155 };
156
157 let qualified_name = self.qualify_name(identifier);
158 let is_duplicate = self.scopes.lookup_const(identifier)
159 || self.is_const_name(store, qualified_name.as_str());
160 if is_duplicate && self.is_lis(store) {
161 self.sink.push(diagnostics::infer::duplicate_definition(
162 "constant",
163 identifier,
164 *identifier_span,
165 ));
166 return;
167 }
168
169 let before = self.sink.len();
170 let const_ty = if let Some(annotation) = annotation {
171 self.convert_to_type(store, annotation, span)
172 } else {
173 self.type_from_literal_expression(expression)
174 .unwrap_or_else(|| self.new_type_var())
175 };
176 self.sink.truncate(before);
177
178 let scope = self.scopes.current_mut();
179 scope.values.insert(identifier.to_string(), const_ty);
180 scope
181 .consts
182 .get_or_insert_with(HashSet::default)
183 .insert(identifier.to_string());
184 }
185
186 fn register_block_local_fn(&mut self, store: &Store, item: &Expression) {
187 let Expression::Function { name, span, .. } = item else {
188 return;
189 };
190
191 let fn_sig = item.to_function_signature();
192
193 let before = self.sink.len();
194 let fn_ty = self.extract_function_signature(store, &fn_sig, span);
195 self.sink.truncate(before);
196
197 let scope = self.scopes.current_mut();
198 scope.values.insert(name.to_string(), fn_ty);
199 }
200}