1mod builtins;
2mod convert;
3mod methods;
4mod types;
5
6use rustc_hash::FxHashMap as HashMap;
7
8use stdlib::get_go_stdlib_typedef;
9use syntax::ast::{
10 Annotation, Attribute, AttributeArg, EnumVariant, Expression, FunctionDefinition, Generic,
11 Span, StructKind, Visibility as SyntacticVisibility,
12};
13use syntax::program::{Definition, File, Visibility};
14use syntax::types::Type;
15
16use super::Checker;
17
18pub(super) fn extract_go_name(attributes: &[Attribute]) -> Option<String> {
19 attributes
20 .iter()
21 .filter(|a| a.name == "go")
22 .flat_map(|a| a.args.iter())
23 .find_map(|arg| {
24 if let AttributeArg::String(name) = arg {
25 Some(name.clone())
26 } else {
27 None
28 }
29 })
30}
31
32pub(super) fn extract_attribute_flags(attributes: &[Attribute], name: &str) -> Vec<String> {
33 attributes
34 .iter()
35 .filter(|a| a.name == name)
36 .flat_map(|a| {
37 a.args.iter().filter_map(|arg| {
38 if let AttributeArg::Flag(name) = arg {
39 Some(name.clone())
40 } else {
41 None
42 }
43 })
44 })
45 .collect()
46}
47
48impl Checker<'_, '_> {
49 fn definition_exists(&self, qualified_name: &str) -> bool {
50 self.store
51 .get_module(&self.cursor.module_id)
52 .expect("current module must exist in store")
53 .definitions
54 .contains_key(qualified_name)
55 }
56
57 fn type_definition_exists(&self, qualified_name: &str) -> bool {
58 self.store
59 .get_module(&self.cursor.module_id)
60 .expect("current module must exist in store")
61 .definitions
62 .get(qualified_name)
63 .is_some_and(|d| {
64 matches!(
65 d,
66 Definition::Struct { .. }
67 | Definition::Enum { .. }
68 | Definition::ValueEnum { .. }
69 | Definition::Interface { .. }
70 | Definition::TypeAlias { .. }
71 )
72 })
73 }
74
75 pub fn register_module(&mut self, id: &str) {
76 self.cursor.module_id = id.to_string();
77
78 let type_name_entries = {
79 let module = self
80 .store
81 .get_module(id)
82 .expect("module must exist for declaration");
83 let mut entries = Vec::new();
84 for file in module.files.values() {
85 entries.extend(self.collect_type_name_entries(&file.items, &Visibility::Private));
86 }
87 for file in module.all_typedefs() {
88 entries.extend(self.collect_type_name_entries(&file.items, &Visibility::Private));
89 }
90 entries
91 };
92 let module = self
93 .store
94 .get_module_mut(id)
95 .expect("module must exist for declaration");
96 for (qualified_name, definition) in type_name_entries {
97 module
98 .definitions
99 .entry(qualified_name.into())
100 .or_insert(definition);
101 }
102
103 let file_data: Vec<_> = {
104 let module = self
105 .store
106 .get_module(id)
107 .expect("module must exist for declaration");
108 module
109 .files
110 .iter()
111 .chain(module.typedefs.iter())
112 .map(|(file_id, f)| (*file_id, f.imports()))
113 .collect()
114 };
115
116 for (file_id, imports) in &file_data {
117 self.reset_scopes();
118 self.cursor.file_id = Some(*file_id);
119
120 self.put_prelude_in_scope();
121 self.put_unprefixed_module_in_scope(id);
122 self.put_imported_modules_in_scope(imports);
123
124 let items = std::mem::take(
125 &mut self
126 .store
127 .get_file_mut(*file_id)
128 .expect("file must exist for registration")
129 .items,
130 );
131
132 self.register_types(&items);
133 self.register_values(&items, &Visibility::Private);
134
135 self.store
136 .get_file_mut(*file_id)
137 .expect("file must exist after registration")
138 .items = items;
139 }
140
141 self.cursor.file_id = None;
142
143 let module = self.store.get_module(id).expect("module must exist");
144 let ufcs_entries = crate::call_classification::compute_module_ufcs(module, id);
145 self.ufcs_methods.extend(ufcs_entries);
146 }
147
148 pub fn parse_and_register_go_module(&mut self, module_id: &str, source: &str) {
152 if self.store.is_visited(module_id) {
153 return;
154 }
155
156 self.store.mark_visited(module_id);
157 self.store.add_module(module_id);
158
159 let file_id = self.store.new_file_id();
160 let filename = format!("{}.d.lis", module_id.replace('/', "_"));
161
162 let build_result = syntax::build_ast(source, file_id);
163 if build_result.failed() {
164 for error in &build_result.errors {
165 eprintln!("bindgen: error parsing {}: {:?}", filename, error);
166 }
167 }
168
169 let file = File {
170 id: file_id,
171 module_id: module_id.to_string(),
172 name: filename,
173 source: source.to_string(),
174 items: build_result.ast,
175 };
176
177 let imports = file.imports();
178
179 for import in &imports {
180 if let Some(go_pkg) = import.name.strip_prefix("go:") {
181 let import_module_id = format!("go:{}", go_pkg);
182 if let Some(import_source) = get_go_stdlib_typedef(go_pkg) {
183 self.parse_and_register_go_module(&import_module_id, import_source);
184 }
185 }
186 }
187
188 self.store.store_file(module_id, file);
189
190 let prev_module_id = self.cursor.module_id.clone();
191 self.cursor.module_id = module_id.to_string();
192
193 self.reset_scopes();
194 self.cursor.file_id = Some(file_id);
195 self.put_prelude_in_scope();
196 self.put_imported_modules_in_scope(&imports);
197
198 let items = std::mem::take(
199 &mut self
200 .store
201 .get_file_mut(file_id)
202 .expect("file must exist after store_file")
203 .items,
204 );
205 self.register_types_and_values(&items, &Visibility::Public);
206
207 self.cursor.file_id = None;
208 self.cursor.module_id = prev_module_id;
209 }
210
211 pub fn register_types_and_values(&mut self, items: &[Expression], visibility: &Visibility) {
212 self.register_type_names(items, visibility);
213 self.register_types(items);
214 self.register_values(items, visibility);
215 }
216
217 pub fn register_type_names(&mut self, items: &[Expression], visibility: &Visibility) {
218 let entries = self.collect_type_name_entries(items, visibility);
219 let module = self
220 .store
221 .get_module_mut(&self.cursor.module_id)
222 .expect("current module must exist in store");
223 for (qualified_name, definition) in entries {
224 module
225 .definitions
226 .entry(qualified_name.into())
227 .or_insert(definition);
228 }
229 }
230
231 fn collect_type_name_entries(
232 &self,
233 items: &[Expression],
234 visibility: &Visibility,
235 ) -> Vec<(String, Definition)> {
236 let mut entries = Vec::new();
237
238 for item in items {
239 let (name, generics, syntactic_visibility) = match item {
240 Expression::Enum {
241 name,
242 generics,
243 visibility,
244 ..
245 } => (name, generics, *visibility),
246 Expression::ValueEnum {
247 name, visibility, ..
248 } => (name, &Vec::new() as &Vec<Generic>, *visibility),
249 Expression::Struct {
250 name,
251 generics,
252 visibility,
253 ..
254 } => (name, generics, *visibility),
255 Expression::Interface {
256 name,
257 generics,
258 visibility,
259 ..
260 } => (name, generics, *visibility),
261 Expression::TypeAlias {
262 name,
263 generics,
264 visibility,
265 ..
266 } => (name, generics, *visibility),
267 _ => continue,
268 };
269
270 let qualified_name = self.qualify_name(name);
271 let args: Vec<Type> = generics
272 .iter()
273 .map(|g| Type::Parameter(g.name.clone()))
274 .collect();
275
276 let constructor_ty = Type::Constructor {
277 id: qualified_name.clone().into(),
278 params: args,
279 underlying_ty: None,
280 };
281
282 let ty = if generics.is_empty() {
283 constructor_ty
284 } else {
285 Type::Forall {
286 vars: generics.iter().map(|g| g.name.clone()).collect(),
287 body: Box::new(constructor_ty),
288 }
289 };
290
291 let item_visibility = match visibility {
292 Visibility::Local => Visibility::Local,
293 _ => {
294 if syntactic_visibility == SyntacticVisibility::Public || self.is_d_lis() {
295 Visibility::Public
296 } else {
297 Visibility::Private
298 }
299 }
300 };
301
302 entries.push((
303 qualified_name,
304 Definition::Value {
305 visibility: item_visibility,
306 ty,
307 name_span: None,
308 allowed_lints: vec![],
309 go_hints: vec![],
310 go_name: None,
311 doc: None,
312 },
313 ));
314 }
315
316 entries
317 }
318
319 pub fn register_types(&mut self, items: &[Expression]) {
320 for item in items {
321 match item {
322 Expression::Enum {
323 name,
324 name_span,
325 generics,
326 variants,
327 span,
328 doc,
329 ..
330 } => self.populate_enum(name, name_span, generics, variants, span, doc),
331 Expression::ValueEnum {
332 name,
333 name_span,
334 underlying_ty,
335 variants,
336 doc,
337 ..
338 } => {
339 self.populate_value_enum(name, name_span, underlying_ty.as_ref(), variants, doc)
340 }
341 Expression::Struct {
342 name,
343 name_span,
344 generics,
345 fields,
346 kind,
347 span,
348 doc,
349 ..
350 } => self.populate_struct(name, name_span, generics, fields, *kind, span, doc),
351 Expression::ImplBlock {
352 annotation,
353 methods,
354 generics,
355 span,
356 ..
357 } => self.populate_impl_methods(annotation, generics, methods, span),
358 Expression::Interface {
359 name,
360 name_span,
361 generics,
362 parents,
363 method_signatures,
364 span,
365 doc,
366 ..
367 } => self.populate_interface(
368 name,
369 name_span,
370 generics,
371 parents,
372 method_signatures,
373 span,
374 doc,
375 ),
376 Expression::TypeAlias {
377 name,
378 name_span,
379 generics,
380 annotation,
381 span,
382 doc,
383 ..
384 } => self.populate_type_alias(name, name_span, generics, annotation, span, doc),
385 _ => (),
386 }
387 }
388 }
389
390 fn compute_item_visibility(
391 &self,
392 syntactic: &SyntacticVisibility,
393 scope: &Visibility,
394 ) -> Visibility {
395 match scope {
396 Visibility::Local => Visibility::Local,
397 _ if *syntactic == SyntacticVisibility::Public || self.is_d_lis() => Visibility::Public,
398 _ => Visibility::Private,
399 }
400 }
401
402 pub fn register_values(&mut self, items: &[Expression], visibility: &Visibility) {
403 for item in items {
404 match item {
405 Expression::Function { .. } => self.register_function_value(item, visibility),
406 Expression::Const { .. } => self.register_const_value(item, visibility),
407 Expression::VariableDeclaration { .. } => {
408 self.register_variable_declaration(item, visibility)
409 }
410 Expression::Struct {
411 kind: StructKind::Tuple,
412 ..
413 } => self.register_tuple_struct_constructor(item),
414 _ => (),
415 }
416 }
417 }
418
419 fn register_function_value(&mut self, item: &Expression, visibility: &Visibility) {
420 let Expression::Function {
421 name,
422 name_span,
423 attributes,
424 generics,
425 span,
426 body,
427 visibility: syntactic_visibility,
428 doc,
429 ..
430 } = item
431 else {
432 return;
433 };
434
435 if body.is_noop() && self.is_lis() {
436 self.sink
437 .push(diagnostics::infer::bodyless_function_outside_typedef(*span));
438 }
439
440 let fn_sig = item.to_function_signature();
441 let qualified_name = self.qualify_name(name);
442
443 self.scopes.push();
444 self.put_in_scope(generics);
445
446 let fn_ty = self.extract_function_signature(&fn_sig, span);
447
448 self.scopes.pop();
449
450 let item_visibility = self.compute_item_visibility(syntactic_visibility, visibility);
451
452 if self.is_lis() && self.definition_exists(&qualified_name) {
453 self.sink.push(diagnostics::infer::duplicate_definition(
454 "function", name, *name_span,
455 ));
456 }
457
458 let module = self
459 .store
460 .get_module_mut(&self.cursor.module_id)
461 .expect("current module must exist in store");
462 module.definitions.insert(
463 qualified_name.into(),
464 Definition::Value {
465 visibility: item_visibility,
466 ty: fn_ty,
467 name_span: Some(*name_span),
468 allowed_lints: extract_attribute_flags(attributes, "allow"),
469 go_hints: extract_attribute_flags(attributes, "go"),
470 go_name: extract_go_name(attributes),
471 doc: doc.clone(),
472 },
473 );
474 }
475
476 fn register_const_value(&mut self, item: &Expression, visibility: &Visibility) {
477 let Expression::Const {
478 identifier,
479 identifier_span,
480 annotation: maybe_annotation,
481 expression,
482 span,
483 visibility: syntactic_visibility,
484 doc,
485 ..
486 } = item
487 else {
488 return;
489 };
490
491 let has_value = !expression.is_noop();
492
493 if !has_value && self.is_lis() {
494 self.sink
495 .push(diagnostics::infer::valueless_const_outside_typedef(*span));
496 }
497
498 if !has_value && maybe_annotation.is_none() && self.is_d_lis() {
499 self.sink
500 .push(diagnostics::infer::valueless_const_missing_annotation(
501 *span,
502 ));
503 }
504
505 let qualified_name = self.qualify_name(identifier);
506
507 let const_ty = if let Some(annotation) = maybe_annotation {
508 self.convert_to_type(annotation, span)
509 } else {
510 self.type_from_literal_expression(expression)
511 .unwrap_or_else(|| self.new_type_var())
512 };
513
514 let item_visibility = self.compute_item_visibility(syntactic_visibility, visibility);
515
516 if self.is_lis() && self.definition_exists(&qualified_name) {
517 self.sink.push(diagnostics::infer::duplicate_definition(
518 "constant",
519 identifier,
520 *identifier_span,
521 ));
522 }
523
524 let module = self
525 .store
526 .get_module_mut(&self.cursor.module_id)
527 .expect("current module must exist in store");
528 module.definitions.insert(
529 qualified_name.into(),
530 Definition::Value {
531 visibility: item_visibility,
532 ty: const_ty,
533 name_span: Some(*identifier_span),
534 allowed_lints: vec![],
535 go_hints: vec![],
536 go_name: None,
537 doc: doc.clone(),
538 },
539 );
540 }
541
542 fn register_variable_declaration(&mut self, item: &Expression, visibility: &Visibility) {
543 let Expression::VariableDeclaration {
544 name,
545 name_span,
546 annotation,
547 span,
548 visibility: syntactic_visibility,
549 doc,
550 ..
551 } = item
552 else {
553 return;
554 };
555
556 if self.is_lis() {
557 self.sink
558 .push(diagnostics::infer::variable_declaration_outside_typedef(
559 *span,
560 ));
561 }
562
563 let qualified_name = self.qualify_name(name);
564 let var_ty = self.convert_to_type(annotation, span);
565
566 let item_visibility = self.compute_item_visibility(syntactic_visibility, visibility);
567
568 let module = self
569 .store
570 .get_module_mut(&self.cursor.module_id)
571 .expect("current module must exist in store");
572 module.definitions.insert(
573 qualified_name.into(),
574 Definition::Value {
575 visibility: item_visibility,
576 ty: var_ty,
577 name_span: Some(*name_span),
578 allowed_lints: vec![],
579 go_hints: vec![],
580 go_name: None,
581 doc: doc.clone(),
582 },
583 );
584 }
585
586 fn register_tuple_struct_constructor(&mut self, item: &Expression) {
587 let Expression::Struct {
588 name,
589 generics,
590 fields,
591 kind: StructKind::Tuple,
592 span,
593 ..
594 } = item
595 else {
596 return;
597 };
598
599 let qualified_name = self.qualify_name(name);
600 let struct_ty = self
601 .store
602 .get_type(&qualified_name)
603 .expect("struct type scheme must exist")
604 .clone();
605
606 self.scopes.push();
607 self.put_in_scope(generics);
608
609 let field_types: Vec<Type> = fields
610 .iter()
611 .map(|f| self.convert_to_type(&f.annotation, span))
612 .collect();
613
614 self.scopes.pop();
615
616 let constructor_ty =
617 tuple_struct_constructor_type_from_fields(&field_types, &struct_ty, generics);
618
619 let scope = self.scopes.current_mut();
620 scope
621 .values
622 .insert(qualified_name.clone(), constructor_ty.clone());
623 scope
624 .values
625 .insert(name.to_string(), constructor_ty.clone());
626
627 let module = self
628 .store
629 .get_module_mut(&self.cursor.module_id)
630 .expect("current module must exist in store");
631 if let Some(Definition::Struct { constructor, .. }) =
632 module.definitions.get_mut(qualified_name.as_str())
633 {
634 *constructor = Some(constructor_ty);
635 }
636 }
637
638 pub(crate) fn extract_function_signature(
639 &mut self,
640 function: &FunctionDefinition,
641 span: &Span,
642 ) -> Type {
643 let generics = &function.generics;
644
645 self.scopes.push();
646 self.put_in_scope(generics);
647
648 let mut bounds = vec![];
649
650 for g in generics {
651 let qualified_name = self.qualify_name(&g.name);
652
653 for b in &g.bounds {
654 let bound_ty = self.convert_to_type(b, span);
655
656 self.scopes
657 .current_mut()
658 .trait_bounds
659 .get_or_insert_with(HashMap::default)
660 .entry(qualified_name.clone())
661 .or_default()
662 .push(bound_ty.clone());
663
664 bounds.push(syntax::types::Bound {
665 param_name: g.name.clone(),
666 generic: Type::Parameter(g.name.clone()),
667 ty: bound_ty,
668 });
669 }
670 }
671
672 let param_types: Vec<Type> = function
673 .params
674 .iter()
675 .map(|binding| {
676 binding
677 .annotation
678 .as_ref()
679 .map(|a| self.convert_to_type(a, span))
680 .unwrap_or_else(|| self.new_type_var())
681 })
682 .collect();
683
684 let return_ty = match &function.annotation {
685 Annotation::Unknown => self.type_unit(),
686 _ => self.convert_to_type(&function.annotation, span),
687 };
688
689 self.scopes.pop();
690
691 let param_mutability: Vec<bool> = function.params.iter().map(|b| b.mutable).collect();
692
693 let base_fn_ty = Type::Function {
694 params: param_types,
695 param_mutability,
696 bounds,
697 return_type: return_ty.into(),
698 };
699
700 if generics.is_empty() {
701 base_fn_ty
702 } else {
703 Type::Forall {
704 vars: generics.iter().map(|g| g.name.clone()).collect(),
705 body: Box::new(base_fn_ty),
706 }
707 }
708 }
709}
710
711pub(super) fn enum_variant_constructor_type(
712 enum_variant: &EnumVariant,
713 enum_ty: &Type,
714 generics: &[Generic],
715) -> Type {
716 if enum_variant.fields.is_empty() {
717 return enum_ty.clone();
718 }
719
720 let return_type = match enum_ty {
721 Type::Forall { body, .. } => body.as_ref().clone(),
722 _ => enum_ty.clone(),
723 };
724
725 let fn_ty = Type::Function {
726 param_mutability: vec![false; enum_variant.fields.len()],
727 params: enum_variant.fields.iter().map(|f| f.ty.clone()).collect(),
728 bounds: Default::default(),
729 return_type: return_type.into(),
730 };
731
732 if generics.is_empty() {
733 fn_ty
734 } else {
735 Type::Forall {
736 vars: generics.iter().map(|g| g.name.clone()).collect(),
737 body: Box::new(fn_ty),
738 }
739 }
740}
741
742fn tuple_struct_constructor_type_from_fields(
743 field_types: &[Type],
744 struct_ty: &Type,
745 generics: &[Generic],
746) -> Type {
747 let return_type = match struct_ty {
748 Type::Forall { body, .. } => body.as_ref().clone(),
749 _ => struct_ty.clone(),
750 };
751
752 let fn_ty = Type::Function {
753 param_mutability: vec![false; field_types.len()],
754 params: field_types.to_vec(),
755 bounds: Default::default(),
756 return_type: return_type.into(),
757 };
758
759 if generics.is_empty() {
760 fn_ty
761 } else {
762 Type::Forall {
763 vars: generics.iter().map(|g| g.name.clone()).collect(),
764 body: Box::new(fn_ty),
765 }
766 }
767}
768
769pub(super) fn wrap_with_impl_generics(
770 fn_ty: &Type,
771 generics: &[Generic],
772 impl_bounds: &[syntax::types::Bound],
773) -> Type {
774 if generics.is_empty() {
775 return fn_ty.clone();
776 }
777
778 let impl_vars: Vec<syntax::EcoString> = generics.iter().map(|g| g.name.clone()).collect();
779
780 let add_impl_bounds = |existing_bounds: &[syntax::types::Bound]| -> Vec<syntax::types::Bound> {
781 impl_bounds
782 .iter()
783 .cloned()
784 .chain(existing_bounds.iter().cloned())
785 .collect()
786 };
787
788 match fn_ty {
789 Type::Forall { vars, body } => {
790 let new_body = match body.as_ref() {
791 Type::Function {
792 params,
793 param_mutability,
794 bounds,
795 return_type,
796 } => Type::Function {
797 params: params.clone(),
798 param_mutability: param_mutability.clone(),
799 bounds: add_impl_bounds(bounds),
800 return_type: return_type.clone(),
801 },
802 _ => *body.clone(),
803 };
804 Type::Forall {
805 vars: impl_vars.into_iter().chain(vars.clone()).collect(),
806 body: Box::new(new_body),
807 }
808 }
809 Type::Function {
810 params,
811 param_mutability,
812 bounds,
813 return_type,
814 } => Type::Forall {
815 vars: impl_vars,
816 body: Box::new(Type::Function {
817 params: params.clone(),
818 param_mutability: param_mutability.clone(),
819 bounds: add_impl_bounds(bounds),
820 return_type: return_type.clone(),
821 }),
822 },
823 _ => Type::Forall {
824 vars: impl_vars,
825 body: Box::new(fn_ty.clone()),
826 },
827 }
828}
829
830fn type_contains_constructor(target_id: &str, ty: &Type) -> bool {
831 walk_type(ty, &|id, _| id == target_id)
832}
833
834pub(super) fn has_recursive_instantiation(target_id: &str, ty: &Type) -> bool {
838 walk_type(ty, &|id, params| {
839 id == target_id
840 && params
841 .iter()
842 .any(|p| type_contains_constructor(target_id, p))
843 })
844}
845
846fn walk_type(ty: &Type, predicate: &dyn Fn(&str, &[Type]) -> bool) -> bool {
847 match ty {
848 Type::Constructor { id, params, .. } => {
849 predicate(id, params) || params.iter().any(|p| walk_type(p, predicate))
850 }
851 Type::Function {
852 params,
853 return_type,
854 ..
855 } => params.iter().any(|p| walk_type(p, predicate)) || walk_type(return_type, predicate),
856 Type::Tuple(elems) => elems.iter().any(|e| walk_type(e, predicate)),
857 Type::Forall { body, .. } => walk_type(body, predicate),
858 _ => false,
859 }
860}