1use rustc_hash::{FxHashMap as HashMap, FxHashSet as HashSet};
2use std::sync::atomic::{AtomicU32, Ordering};
3
4use syntax::ast::{EnumVariant, Expression, StructFieldDefinition};
5use syntax::program::{Definition, File, Interface, MethodSignatures, Module, ModuleId};
6use syntax::types::{SubstitutionMap, Symbol, Type, substitute};
7
8pub const ENTRY_MODULE_ID: &str = "_entry_";
9pub const ENTRY_FILE_ID: u32 = 0;
10
11pub struct Store {
12 pub modules: HashMap<String, Module>,
13 pub module_ids: Vec<ModuleId>,
14 pub files: HashMap<u32, String>,
16 pub go_package_names: HashMap<String, String>,
19 visited_modules: HashSet<String>,
20 next_file_id: AtomicU32,
22}
23
24impl Default for Store {
25 fn default() -> Self {
26 Self::new()
27 }
28}
29
30impl Store {
31 pub fn new() -> Self {
32 let prelude_module = Module::new("prelude");
33 let nominal_module = Module::nominal();
34
35 let modules = vec![
36 (prelude_module.id.clone(), prelude_module),
37 (nominal_module.id.clone(), nominal_module),
38 ]
39 .into_iter()
40 .collect();
41
42 let module_ids = vec!["prelude".to_string()];
43
44 Self {
45 files: Default::default(),
46 modules,
47 module_ids,
48 go_package_names: Default::default(),
49 visited_modules: Default::default(),
50 next_file_id: AtomicU32::new(2), }
52 }
53
54 pub fn new_file_id(&self) -> u32 {
55 self.next_file_id.fetch_add(1, Ordering::Relaxed)
56 }
57
58 pub fn register_file(&mut self, file_id: u32, module_id: &str) {
59 self.files.insert(file_id, module_id.to_string());
60 }
61
62 pub fn entry_module_id(&self) -> &'static str {
63 ENTRY_MODULE_ID
64 }
65
66 pub fn init_entry_module(&mut self) {
68 self.add_module(ENTRY_MODULE_ID);
69 self.register_file(ENTRY_FILE_ID, ENTRY_MODULE_ID);
70 }
71
72 pub fn store_entry_file(&mut self, filename: &str, source: &str, ast: Vec<Expression>) {
73 self.store_file(
74 ENTRY_MODULE_ID,
75 File {
76 id: ENTRY_FILE_ID,
77 module_id: ENTRY_MODULE_ID.to_string(),
78 name: filename.to_string(),
79 source: source.to_string(),
80 items: ast,
81 },
82 );
83 }
84
85 pub fn store_module(&mut self, module_id: &str, files: Vec<File>) {
86 self.mark_visited(module_id);
87 self.add_module(module_id);
88
89 for file in files {
90 self.store_file(module_id, file);
91 }
92 }
93
94 pub fn store_file(&mut self, module_id: &str, file: File) {
97 self.files.insert(file.id, module_id.to_string());
98
99 let module = self
100 .get_module_mut(module_id)
101 .expect("module must exist to store file");
102
103 if file.is_d_lis() {
104 module.typedefs.insert(file.id, file);
105 } else {
106 module.files.insert(file.id, file);
107 }
108 }
109
110 pub fn get_file(&self, file_id: u32) -> Option<&File> {
111 let module_id = self.files.get(&file_id)?;
112 let module = self.get_module(module_id)?;
113 module
114 .get_file(file_id)
115 .or_else(|| module.get_typedef_by_id(file_id))
116 }
117
118 pub fn get_file_mut(&mut self, file_id: u32) -> Option<&mut File> {
119 let module_id = self.files.get(&file_id)?.clone();
120 let module = self.modules.get_mut(&module_id)?;
121 module
122 .files
123 .get_mut(&file_id)
124 .or_else(|| module.typedefs.get_mut(&file_id))
125 }
126
127 pub fn get_module(&self, module_id: &str) -> Option<&Module> {
128 self.modules.get(module_id)
129 }
130
131 pub fn has(&self, module_id: &str) -> bool {
132 self.modules.contains_key(module_id)
133 }
134
135 pub fn add_module(&mut self, module_id: &str) {
136 if self.modules.contains_key(module_id) {
137 return;
138 }
139
140 self.modules
141 .insert(module_id.to_string(), Module::new(module_id));
142 self.module_ids.push(module_id.to_string());
143 }
144
145 pub fn get_module_mut(&mut self, module_id: &str) -> Option<&mut Module> {
146 self.modules.get_mut(module_id)
147 }
148
149 pub fn is_visited(&self, module_id: &str) -> bool {
150 self.visited_modules.contains(module_id)
151 }
152
153 pub fn mark_visited(&mut self, module_id: &str) {
154 self.visited_modules.insert(module_id.to_string());
155 }
156
157 pub fn get_definition(&self, qualified_name: &str) -> Option<&Definition> {
158 let module_name = self.module_for_qualified_name(qualified_name)?;
159
160 self.get_module(module_name)?
161 .definitions
162 .get(qualified_name)
163 }
164
165 pub fn module_for_qualified_name<'a>(&'a self, qualified_name: &'a str) -> Option<&'a str> {
166 if !qualified_name.starts_with("go:") || !qualified_name.contains('/') {
167 let (module_name, _) = qualified_name.split_once('.')?;
168 return Some(module_name);
169 }
170
171 let mut best: Option<&str> = None;
172 for module_id in self.modules.keys() {
173 if qualified_name.starts_with(module_id.as_str())
174 && qualified_name.as_bytes().get(module_id.len()) == Some(&b'.')
175 && best
176 .as_ref()
177 .is_none_or(|prev| module_id.len() > prev.len())
178 {
179 best = Some(module_id.as_str());
180 }
181 }
182 best
183 }
184
185 pub fn variants_of(&self, qualified_name: &str) -> Option<&[EnumVariant]> {
186 match self.get_definition(qualified_name)? {
187 Definition::Enum { variants, .. } => Some(variants),
188 _ => None,
189 }
190 }
191
192 pub fn variant_of(&self, enum_qualified: &str, variant_name: &str) -> Option<&EnumVariant> {
193 self.variants_of(enum_qualified)?
194 .iter()
195 .find(|v| v.name == variant_name)
196 }
197
198 pub fn value_variants_of(
199 &self,
200 qualified_name: &str,
201 ) -> Option<&[syntax::ast::ValueEnumVariant]> {
202 match self.get_definition(qualified_name)? {
203 Definition::ValueEnum { variants, .. } => Some(variants),
204 _ => None,
205 }
206 }
207
208 pub fn fields_of(&self, qualified_name: &str) -> Option<&[StructFieldDefinition]> {
209 match self.get_definition(qualified_name)? {
210 Definition::Struct { fields, .. } => Some(fields),
211 _ => None,
212 }
213 }
214
215 pub fn struct_kind(&self, qualified_name: &str) -> Option<syntax::ast::StructKind> {
216 match self.get_definition(qualified_name)? {
217 Definition::Struct { kind, .. } => Some(*kind),
218 _ => None,
219 }
220 }
221
222 pub fn struct_constructor(&self, qualified_name: &str) -> Option<&Type> {
223 match self.get_definition(qualified_name)? {
224 Definition::Struct { constructor, .. } => constructor.as_ref(),
225 _ => None,
226 }
227 }
228
229 pub fn parent_interfaces_of(&self, qualified_name: &str) -> Option<&[Type]> {
230 match self.get_definition(qualified_name)? {
231 Definition::Interface { definition, .. } => Some(&definition.parents),
232 _ => None,
233 }
234 }
235
236 pub fn get_type(&self, qualified_name: &str) -> Option<&Type> {
237 self.get_definition(qualified_name)
238 .map(|definition| definition.ty())
239 }
240
241 pub fn get_interface(&self, qualified_name: &str) -> Option<&Interface> {
242 match self.get_definition(qualified_name)? {
243 Definition::Interface { definition, .. } => Some(definition),
244 _ => None,
245 }
246 }
247
248 pub fn peel_alias(&self, ty: &Type) -> Type {
249 let mut current = ty.clone();
250 while let Type::Nominal {
251 id,
252 underlying_ty: Some(u),
253 ..
254 } = ¤t
255 {
256 if !self
257 .get_definition(id)
258 .is_some_and(|d| matches!(d, Definition::TypeAlias { .. }))
259 {
260 break;
261 }
262 current = *u.clone();
263 }
264 current
265 }
266
267 pub fn get_own_methods(&self, qualified_name: &str) -> Option<&MethodSignatures> {
268 match self.get_definition(qualified_name)? {
269 Definition::Struct { methods, .. } => Some(methods),
270 Definition::TypeAlias { methods, .. } => Some(methods),
271 Definition::Enum { methods, .. } => Some(methods),
272 Definition::ValueEnum { methods, .. } => Some(methods),
273 _ => None,
274 }
275 }
276
277 pub fn get_all_methods(
278 &self,
279 ty: &Type,
280 trait_bounds: &HashMap<Symbol, Vec<Type>>,
281 ) -> MethodSignatures {
282 let stripped = ty.strip_refs();
283 let Some(qualified_name) = method_lookup_key(&stripped) else {
284 return MethodSignatures::default();
285 };
286
287 if let Some(interface) = self.get_interface(&qualified_name) {
288 let mut all_interface_methods = MethodSignatures::default();
289
290 let type_args = ty.get_type_params().unwrap_or_default();
291 let map: SubstitutionMap = interface
292 .generics
293 .iter()
294 .map(|g| g.name.clone())
295 .zip(type_args.iter().cloned())
296 .collect();
297
298 for (name, method_ty) in &interface.methods {
299 let substituted = substitute(method_ty, &map);
300 all_interface_methods.insert(name.clone(), substituted.with_receiver_placeholder());
301 }
302
303 for parent in &interface.parents {
304 for (name, method_ty) in self.get_all_methods(parent, trait_bounds) {
305 all_interface_methods.insert(name, method_ty);
306 }
307 }
308
309 return all_interface_methods;
310 }
311
312 if let Some(bound_types) = trait_bounds.get(&qualified_name) {
313 return bound_types
314 .iter()
315 .flat_map(|interface_ty| self.get_all_methods(interface_ty, trait_bounds))
316 .collect();
317 }
318
319 let mut methods = self
320 .get_own_methods(&qualified_name)
321 .cloned()
322 .unwrap_or_default();
323
324 if let Some(Definition::TypeAlias { ty: alias_ty, .. }) =
326 self.get_definition(&qualified_name)
327 {
328 let underlying = match &alias_ty {
329 Type::Forall { body, .. } => body.as_ref(),
330 other => other,
331 };
332 let underlying_key = match underlying {
333 Type::Nominal { id, .. } => Some(id.as_str().to_string()),
334 Type::Simple(kind) => Some(format!("prelude.{}", kind.leaf_name())),
335 Type::Compound { kind, .. } => Some(format!("prelude.{}", kind.leaf_name())),
336 _ => None,
337 };
338 if let Some(k) = underlying_key
342 && k != qualified_name.as_str()
343 {
344 let alias_ty = alias_ty.clone();
345 for (name, method_ty) in self.get_all_methods(&alias_ty, trait_bounds) {
346 methods.entry(name).or_insert(method_ty);
347 }
348 }
349 }
350
351 methods
352 }
353
354 pub fn get_methods_from_bounds(
355 &self,
356 qualified_name: &str,
357 trait_bounds: &HashMap<Symbol, Vec<Type>>,
358 ) -> MethodSignatures {
359 if let Some(bound_types) = trait_bounds.get(qualified_name) {
360 return bound_types
361 .iter()
362 .flat_map(|interface_ty| self.get_all_methods(interface_ty, trait_bounds))
363 .collect();
364 }
365 MethodSignatures::default()
366 }
367}
368
369fn method_lookup_key(ty: &Type) -> Option<Symbol> {
373 match ty {
374 Type::Nominal { id, .. } => Some(id.clone()),
375 Type::Compound { kind, .. } => Some(Symbol::from_parts("prelude", kind.leaf_name())),
376 Type::Simple(kind) => Some(Symbol::from_parts("prelude", kind.leaf_name())),
377 _ => None,
378 }
379}