1mod builtins;
2mod convert;
3mod methods;
4mod types;
5
6use std::path::PathBuf;
7
8use rustc_hash::FxHashMap as HashMap;
9
10use deps::TypedefLocator;
11use syntax::ast::{
12 Annotation, Attribute, AttributeArg, EnumVariant, Expression, FunctionDefinition, Generic,
13 Span, StructKind, Visibility as SyntacticVisibility,
14};
15use syntax::program::{Definition, DefinitionBody, File, FileImport, Visibility};
16use syntax::types::{Symbol, Type};
17
18use super::{FileContextKind, TaskState};
19use crate::store::Store;
20
21pub(crate) fn extract_package_directive(source: &str) -> Option<String> {
22 for line in source.lines().take(10) {
23 let line = line.trim_start();
24 if let Some(rest) = line.strip_prefix("// Package:") {
25 let name = rest.trim();
26 if !name.is_empty() {
27 return Some(name.to_string());
28 }
29 }
30 if !line.starts_with("//") && !line.is_empty() {
31 break;
32 }
33 }
34 None
35}
36
37pub(super) fn extract_go_name(attributes: &[Attribute]) -> Option<String> {
38 attributes
39 .iter()
40 .filter(|a| a.name == "go")
41 .flat_map(|a| a.args.iter())
42 .find_map(|arg| {
43 if let AttributeArg::String(name) = arg {
44 Some(name.clone())
45 } else {
46 None
47 }
48 })
49}
50
51pub(super) fn extract_attribute_flags(attributes: &[Attribute], name: &str) -> Vec<String> {
52 attributes
53 .iter()
54 .filter(|a| a.name == name)
55 .flat_map(|a| {
56 a.args.iter().filter_map(|arg| {
57 if let AttributeArg::Flag(name) = arg {
58 Some(name.clone())
59 } else {
60 None
61 }
62 })
63 })
64 .collect()
65}
66
67impl TaskState<'_> {
68 fn definition_exists(&self, store: &Store, qualified_name: &str) -> bool {
69 self.current_module(store)
70 .definitions
71 .contains_key(qualified_name)
72 }
73
74 fn type_definition_exists(&self, store: &Store, qualified_name: &str) -> bool {
75 self.current_module(store)
76 .definitions
77 .get(qualified_name)
78 .is_some_and(|d| {
79 matches!(
80 d.body,
81 DefinitionBody::Struct { .. }
82 | DefinitionBody::Enum { .. }
83 | DefinitionBody::ValueEnum { .. }
84 | DefinitionBody::Interface { .. }
85 | DefinitionBody::TypeAlias { .. }
86 )
87 })
88 }
89
90 pub fn register_module(&mut self, store: &mut Store, id: &str) {
91 let type_name_entries =
92 self.with_module_cursor(id, |this| this.collect_module_type_name_entries(store, id));
93 self.insert_type_name_entries(store, id, type_name_entries);
94
95 let file_data = self.module_file_data(store, id);
96
97 for (file_id, imports) in &file_data {
98 self.register_file_type_definitions(store, id, *file_id, imports);
99 }
100
101 for (file_id, imports) in &file_data {
102 self.register_file_values(store, id, *file_id, imports);
103 }
104
105 let module = store.get_module(id).expect("module must exist");
106 let ufcs_entries = crate::call_classification::compute_module_ufcs(module, id);
107 self.ufcs_methods.extend(ufcs_entries);
108 }
109
110 pub fn parse_and_register_go_module(
115 &mut self,
116 store: &mut Store,
117 module_id: &str,
118 source: &str,
119 cache_path: Option<PathBuf>,
120 locator: &TypedefLocator,
121 ) {
122 if store.is_visited(module_id) {
123 return;
124 }
125
126 store.mark_visited(module_id);
127 store.add_module(module_id);
128
129 if let Some(pkg_name) = extract_package_directive(source)
130 && module_id.rsplit('/').next() != Some(pkg_name.as_str())
131 {
132 store
133 .go_package_names
134 .insert(module_id.to_string(), pkg_name);
135 }
136
137 let file_id = store.new_file_id();
138 let filename = format!("{}.d.lis", module_id.replace('/', "_"));
139
140 let build_result = syntax::build_ast(source, file_id);
141 if build_result.failed() {
142 for error in &build_result.errors {
143 eprintln!("bindgen: error parsing {}: {:?}", filename, error);
144 }
145 }
146
147 let file = File {
148 id: file_id,
149 module_id: module_id.to_string(),
150 name: filename.clone(),
151 display_path: filename,
152 source: source.to_string(),
153 items: build_result.ast,
154 };
155
156 let imports = file.imports();
157
158 for import in &imports {
159 if let Some(go_pkg) = import.name.strip_prefix("go:") {
160 if matches!(import.alias, Some(syntax::ast::ImportAlias::Blank(_))) {
161 continue;
162 }
163
164 let import_module_id = format!("go:{}", go_pkg);
165
166 if store.is_visited(&import_module_id) {
167 continue;
168 }
169
170 match locator.find_typedef_content(go_pkg) {
171 deps::TypedefLocatorResult::Found { content, origin } => {
172 self.parse_and_register_go_module(
173 store,
174 &import_module_id,
175 content.as_ref(),
176 origin.into_cache_path(),
177 locator,
178 );
179 }
180 other => {
181 crate::diagnostics::emit_for_locator_result(
182 &other,
183 &import.name,
184 go_pkg,
185 Some(import.name_span),
186 locator.target(),
187 false,
188 self.sink,
189 );
190 }
191 }
192 }
193 }
194
195 if let Some(path) = cache_path {
196 store.typedef_paths.insert(file_id, path);
197 }
198 store.store_file(module_id, file);
199
200 self.with_file_context_mut(
201 store,
202 module_id,
203 file_id,
204 &imports,
205 FileContextKind::ImportedTypedef,
206 |this, store| {
207 let items = std::mem::take(
208 &mut store
209 .get_file_mut(file_id)
210 .expect("file must exist after store_file")
211 .items,
212 );
213 this.register_types_and_values(store, &items, &Visibility::Public);
214 },
215 );
216 }
217
218 fn collect_module_type_name_entries(
219 &self,
220 store: &Store,
221 module_id: &str,
222 ) -> Vec<(Symbol, Definition)> {
223 let module = store
224 .get_module(module_id)
225 .expect("module must exist for declaration");
226 let mut entries = Vec::new();
227 for file in module.files.values() {
228 entries.extend(self.collect_type_name_entries(
229 &file.items,
230 &Visibility::Private,
231 false,
232 ));
233 }
234 for file in module.all_typedefs() {
235 entries.extend(self.collect_type_name_entries(&file.items, &Visibility::Private, true));
236 }
237 entries
238 }
239
240 fn insert_type_name_entries(
241 &mut self,
242 store: &mut Store,
243 module_id: &str,
244 type_name_entries: Vec<(Symbol, Definition)>,
245 ) {
246 let module = store
247 .get_module_mut(module_id)
248 .expect("module must exist for declaration");
249 for (qualified_name, definition) in type_name_entries {
250 module
251 .definitions
252 .entry(qualified_name)
253 .or_insert(definition);
254 }
255 }
256
257 fn module_file_data(&self, store: &Store, module_id: &str) -> Vec<(u32, Vec<FileImport>)> {
258 let module = store
259 .get_module(module_id)
260 .expect("module must exist for declaration");
261 module
262 .files
263 .iter()
264 .chain(module.typedefs.iter())
265 .map(|(file_id, f)| (*file_id, f.imports()))
266 .collect()
267 }
268
269 fn register_file_type_definitions(
270 &mut self,
271 store: &mut Store,
272 module_id: &str,
273 file_id: u32,
274 imports: &[FileImport],
275 ) {
276 self.with_file_context_mut(
277 store,
278 module_id,
279 file_id,
280 imports,
281 FileContextKind::Standard,
282 |this, store| {
283 let items = std::mem::take(
284 &mut store
285 .get_file_mut(file_id)
286 .expect("file must exist for registration")
287 .items,
288 );
289
290 this.register_type_definitions(store, &items);
291
292 store
293 .get_file_mut(file_id)
294 .expect("file must exist after registration")
295 .items = items;
296 },
297 );
298 }
299
300 fn register_file_values(
301 &mut self,
302 store: &mut Store,
303 module_id: &str,
304 file_id: u32,
305 imports: &[FileImport],
306 ) {
307 self.with_file_context_mut(
308 store,
309 module_id,
310 file_id,
311 imports,
312 FileContextKind::Standard,
313 |this, store| {
314 let items = std::mem::take(
315 &mut store
316 .get_file_mut(file_id)
317 .expect("file must exist for registration")
318 .items,
319 );
320
321 this.register_impl_blocks(store, &items);
322 this.register_values(store, &items, &Visibility::Private);
323
324 store
325 .get_file_mut(file_id)
326 .expect("file must exist after registration")
327 .items = items;
328 },
329 );
330 }
331
332 pub fn register_types_and_values(
333 &mut self,
334 store: &mut Store,
335 items: &[Expression],
336 visibility: &Visibility,
337 ) {
338 self.register_type_names(store, items, visibility);
339 self.register_type_definitions(store, items);
340 self.register_impl_blocks(store, items);
341 self.register_values(store, items, visibility);
342 }
343
344 pub fn register_type_names(
345 &mut self,
346 store: &mut Store,
347 items: &[Expression],
348 visibility: &Visibility,
349 ) {
350 let entries = self.collect_type_name_entries(items, visibility, self.is_d_lis(&*store));
351 let module = self.current_module_mut(store);
352 for (qualified_name, definition) in entries {
353 module
354 .definitions
355 .entry(qualified_name)
356 .or_insert(definition);
357 }
358 }
359
360 fn collect_type_name_entries(
361 &self,
362 items: &[Expression],
363 visibility: &Visibility,
364 is_typedef: bool,
365 ) -> Vec<(Symbol, Definition)> {
366 let mut entries = Vec::new();
367
368 for item in items {
369 let (name, generics, syntactic_visibility) = match item {
370 Expression::Enum {
371 name,
372 generics,
373 visibility,
374 ..
375 } => (name, generics, *visibility),
376 Expression::ValueEnum {
377 name, visibility, ..
378 } => (name, &Vec::new() as &Vec<Generic>, *visibility),
379 Expression::Struct {
380 name,
381 generics,
382 visibility,
383 ..
384 } => (name, generics, *visibility),
385 Expression::Interface {
386 name,
387 generics,
388 visibility,
389 ..
390 } => (name, generics, *visibility),
391 Expression::TypeAlias {
392 name,
393 generics,
394 visibility,
395 ..
396 } => (name, generics, *visibility),
397 _ => continue,
398 };
399
400 let qualified_name = self.qualify_name(name);
401 let args: Vec<Type> = generics
402 .iter()
403 .map(|g| Type::Parameter(g.name.clone()))
404 .collect();
405
406 let canonical_ty = if self.cursor.module_id == "prelude" {
410 if let Some(simple) = syntax::types::SimpleKind::from_name(name) {
411 debug_assert!(args.is_empty(), "simple kinds have no generics");
412 Type::Simple(simple)
413 } else if let Some(compound) = syntax::types::CompoundKind::from_name(name) {
414 Type::Compound {
415 kind: compound,
416 args,
417 }
418 } else {
419 Type::Nominal {
420 id: qualified_name.clone(),
421 params: args,
422 underlying_ty: None,
423 }
424 }
425 } else {
426 Type::Nominal {
427 id: qualified_name.clone(),
428 params: args,
429 underlying_ty: None,
430 }
431 };
432
433 let ty = if generics.is_empty() {
434 canonical_ty
435 } else {
436 Type::Forall {
437 vars: generics.iter().map(|g| g.name.clone()).collect(),
438 body: Box::new(canonical_ty),
439 }
440 };
441
442 let item_visibility = match visibility {
443 Visibility::Local => Visibility::Local,
444 _ => {
445 if syntactic_visibility == SyntacticVisibility::Public || is_typedef {
446 Visibility::Public
447 } else {
448 Visibility::Private
449 }
450 }
451 };
452
453 entries.push((
454 qualified_name,
455 Definition {
456 visibility: item_visibility,
457 ty,
458 name: None,
459 name_span: None,
460 doc: None,
461 body: DefinitionBody::Value {
462 allowed_lints: vec![],
463 go_hints: vec![],
464 go_name: None,
465 },
466 },
467 ));
468 }
469
470 entries
471 }
472
473 pub fn register_type_definitions(&mut self, store: &mut Store, items: &[Expression]) {
474 for item in items {
475 if let Expression::TypeAlias {
476 name,
477 name_span,
478 generics,
479 annotation,
480 span,
481 doc,
482 ..
483 } = item
484 {
485 self.populate_type_alias(store, name, name_span, generics, annotation, span, doc);
486 }
487 }
488
489 for item in items {
490 match item {
491 Expression::Enum {
492 name,
493 name_span,
494 generics,
495 variants,
496 span,
497 doc,
498 ..
499 } => self.populate_enum(store, name, name_span, generics, variants, span, doc),
500 Expression::ValueEnum {
501 name,
502 name_span,
503 underlying_ty,
504 variants,
505 doc,
506 ..
507 } => self.populate_value_enum(
508 store,
509 name,
510 name_span,
511 underlying_ty.as_ref(),
512 variants,
513 doc,
514 ),
515 Expression::Struct {
516 name,
517 name_span,
518 generics,
519 fields,
520 kind,
521 span,
522 doc,
523 ..
524 } => {
525 self.populate_struct(store, name, name_span, generics, fields, *kind, span, doc)
526 }
527 Expression::Interface {
528 name,
529 name_span,
530 generics,
531 parents,
532 method_signatures,
533 span,
534 doc,
535 ..
536 } => self.populate_interface(
537 store,
538 name,
539 name_span,
540 generics,
541 parents,
542 method_signatures,
543 span,
544 doc,
545 ),
546 _ => (),
547 }
548 }
549 }
550
551 pub fn register_impl_blocks(&mut self, store: &mut Store, items: &[Expression]) {
552 for item in items {
553 if let Expression::ImplBlock {
554 annotation,
555 methods,
556 generics,
557 span,
558 ..
559 } = item
560 {
561 self.populate_impl_methods(store, annotation, generics, methods, span);
562 }
563 }
564 }
565
566 fn compute_item_visibility(
567 &self,
568 store: &Store,
569 syntactic: &SyntacticVisibility,
570 scope: &Visibility,
571 ) -> Visibility {
572 match scope {
573 Visibility::Local => Visibility::Local,
574 _ if *syntactic == SyntacticVisibility::Public || self.is_d_lis(store) => {
575 Visibility::Public
576 }
577 _ => Visibility::Private,
578 }
579 }
580
581 pub fn register_values(
582 &mut self,
583 store: &mut Store,
584 items: &[Expression],
585 visibility: &Visibility,
586 ) {
587 for item in items {
588 match item {
589 Expression::Function { .. } => {
590 self.register_function_value(store, item, visibility)
591 }
592 Expression::Const { .. } => self.register_const_value(store, item, visibility),
593 Expression::VariableDeclaration { .. } => {
594 self.register_variable_declaration(store, item, visibility)
595 }
596 Expression::Struct {
597 kind: StructKind::Tuple,
598 ..
599 } => self.register_tuple_struct_constructor(store, item),
600 _ => (),
601 }
602 }
603 }
604
605 fn register_function_value(
606 &mut self,
607 store: &mut Store,
608 item: &Expression,
609 visibility: &Visibility,
610 ) {
611 let Expression::Function {
612 name,
613 name_span,
614 attributes,
615 generics,
616 span,
617 body,
618 visibility: syntactic_visibility,
619 doc,
620 ..
621 } = item
622 else {
623 return;
624 };
625
626 if body.is_noop() && self.is_lis(&*store) {
627 self.sink
628 .push(diagnostics::infer::bodyless_function_outside_typedef(*span));
629 }
630
631 let fn_sig = item.to_function_signature();
632 let qualified_name = self.qualify_name(name);
633
634 self.scopes.push();
635 self.put_in_scope(generics);
636
637 let fn_ty = self.extract_function_signature(store, &fn_sig, span);
638
639 self.scopes.pop();
640
641 let item_visibility =
642 self.compute_item_visibility(&*store, syntactic_visibility, visibility);
643
644 if self.is_lis(&*store) && self.definition_exists(&*store, &qualified_name) {
645 self.sink.push(diagnostics::infer::duplicate_definition(
646 "function", name, *name_span,
647 ));
648 }
649
650 let module = self.current_module_mut(store);
651 module.definitions.insert(
652 qualified_name,
653 Definition {
654 visibility: item_visibility,
655 ty: fn_ty,
656 name: None,
657 name_span: Some(*name_span),
658 doc: doc.clone(),
659 body: DefinitionBody::Value {
660 allowed_lints: extract_attribute_flags(attributes, "allow"),
661 go_hints: extract_attribute_flags(attributes, "go"),
662 go_name: extract_go_name(attributes),
663 },
664 },
665 );
666 }
667
668 fn register_const_value(
669 &mut self,
670 store: &mut Store,
671 item: &Expression,
672 visibility: &Visibility,
673 ) {
674 let Expression::Const {
675 identifier,
676 identifier_span,
677 annotation: maybe_annotation,
678 expression,
679 span,
680 visibility: syntactic_visibility,
681 doc,
682 ..
683 } = item
684 else {
685 return;
686 };
687
688 let has_value = !expression.is_noop();
689
690 if !has_value && self.is_lis(&*store) {
691 self.sink
692 .push(diagnostics::infer::valueless_const_outside_typedef(*span));
693 }
694
695 if !has_value && maybe_annotation.is_none() && self.is_d_lis(&*store) {
696 self.sink
697 .push(diagnostics::infer::valueless_const_missing_annotation(
698 *span,
699 ));
700 }
701
702 let qualified_name = self.qualify_name(identifier);
703
704 let before = self.sink.len();
705 let const_ty = if let Some(annotation) = maybe_annotation {
706 self.convert_to_type(store, annotation, span)
707 } else {
708 self.type_from_literal_expression(expression)
709 .unwrap_or_else(|| self.new_type_var())
710 };
711 self.sink.truncate(before);
712
713 let item_visibility =
714 self.compute_item_visibility(&*store, syntactic_visibility, visibility);
715
716 if self.is_lis(&*store) && self.definition_exists(&*store, &qualified_name) {
717 self.sink.push(diagnostics::infer::duplicate_definition(
718 "constant",
719 identifier,
720 *identifier_span,
721 ));
722 }
723
724 let module = self.current_module_mut(store);
725 module.const_names.insert(qualified_name.clone());
726 module.definitions.insert(
727 qualified_name,
728 Definition {
729 visibility: item_visibility,
730 ty: const_ty,
731 name: None,
732 name_span: Some(*identifier_span),
733 doc: doc.clone(),
734 body: DefinitionBody::Value {
735 allowed_lints: vec![],
736 go_hints: vec![],
737 go_name: None,
738 },
739 },
740 );
741 }
742
743 fn register_variable_declaration(
744 &mut self,
745 store: &mut Store,
746 item: &Expression,
747 visibility: &Visibility,
748 ) {
749 let Expression::VariableDeclaration {
750 name,
751 name_span,
752 annotation,
753 span,
754 visibility: syntactic_visibility,
755 doc,
756 ..
757 } = item
758 else {
759 return;
760 };
761
762 if self.is_lis(&*store) {
763 self.sink
764 .push(diagnostics::infer::variable_declaration_outside_typedef(
765 *span,
766 ));
767 }
768
769 let qualified_name = self.qualify_name(name);
770 let var_ty = self.convert_to_type(&*store, annotation, span);
771
772 let item_visibility =
773 self.compute_item_visibility(&*store, syntactic_visibility, visibility);
774
775 let module = self.current_module_mut(store);
776 module.definitions.insert(
777 qualified_name,
778 Definition {
779 visibility: item_visibility,
780 ty: var_ty,
781 name: None,
782 name_span: Some(*name_span),
783 doc: doc.clone(),
784 body: DefinitionBody::Value {
785 allowed_lints: vec![],
786 go_hints: vec![],
787 go_name: None,
788 },
789 },
790 );
791 }
792
793 fn register_tuple_struct_constructor(&mut self, store: &mut Store, item: &Expression) {
794 let Expression::Struct {
795 name,
796 generics,
797 fields,
798 kind: StructKind::Tuple,
799 span,
800 ..
801 } = item
802 else {
803 return;
804 };
805
806 let qualified_name = self.qualify_name(name);
807 let struct_ty = store
808 .get_type(&qualified_name)
809 .expect("struct type scheme must exist")
810 .clone();
811
812 self.scopes.push();
813 self.put_in_scope(generics);
814
815 let field_types: Vec<Type> = fields
816 .iter()
817 .map(|f| self.convert_to_type(&*store, &f.annotation, span))
818 .collect();
819
820 self.scopes.pop();
821
822 let constructor_ty =
823 tuple_struct_constructor_type_from_fields(&field_types, &struct_ty, generics);
824
825 let scope = self.scopes.current_mut();
826 scope
827 .values
828 .insert(qualified_name.to_string(), constructor_ty.clone());
829 scope
830 .values
831 .insert(name.to_string(), constructor_ty.clone());
832
833 let module = self.current_module_mut(store);
834 if let Some(def) = module.definitions.get_mut(qualified_name.as_str())
835 && let DefinitionBody::Struct { constructor, .. } = &mut def.body
836 {
837 *constructor = Some(constructor_ty);
838 }
839 }
840
841 pub(crate) fn extract_function_signature(
842 &mut self,
843 store: &Store,
844 function: &FunctionDefinition,
845 span: &Span,
846 ) -> Type {
847 let generics = &function.generics;
848
849 self.scopes.push();
850 self.put_in_scope(generics);
851
852 let mut bounds = vec![];
853
854 for g in generics {
855 let qualified_name = self.qualify_name(&g.name);
856
857 for b in &g.bounds {
858 let bound_ty = self.register_bound_annotation(store, b, span);
859
860 self.scopes
861 .current_mut()
862 .trait_bounds
863 .get_or_insert_with(HashMap::default)
864 .entry(qualified_name.clone())
865 .or_default()
866 .push(bound_ty.clone());
867
868 bounds.push(syntax::types::Bound {
869 param_name: g.name.clone(),
870 generic: Type::Parameter(g.name.clone()),
871 ty: bound_ty,
872 });
873 }
874 }
875
876 let before = self.sink.len();
877
878 let param_types: Vec<Type> = function
879 .params
880 .iter()
881 .map(|binding| {
882 binding
883 .annotation
884 .as_ref()
885 .map(|a| self.convert_to_type(store, a, span))
886 .unwrap_or_else(|| self.new_type_var())
887 })
888 .collect();
889
890 let return_ty = match &function.annotation {
891 Annotation::Unknown => self.type_unit(),
892 _ => self.convert_to_type(store, &function.annotation, span),
893 };
894
895 self.sink.truncate(before);
896
897 self.scopes.pop();
898
899 let param_mutability: Vec<bool> = function.params.iter().map(|b| b.mutable).collect();
900
901 let base_fn_ty = Type::Function {
902 params: param_types,
903 param_mutability,
904 bounds,
905 return_type: return_ty.into(),
906 };
907
908 if generics.is_empty() {
909 base_fn_ty
910 } else {
911 Type::Forall {
912 vars: generics.iter().map(|g| g.name.clone()).collect(),
913 body: Box::new(base_fn_ty),
914 }
915 }
916 }
917}
918
919pub(super) fn enum_variant_constructor_type(
920 enum_variant: &EnumVariant,
921 enum_ty: &Type,
922 generics: &[Generic],
923) -> Type {
924 if enum_variant.fields.is_empty() {
925 return enum_ty.clone();
926 }
927
928 let return_type = match enum_ty {
929 Type::Forall { body, .. } => body.as_ref().clone(),
930 _ => enum_ty.clone(),
931 };
932
933 let fn_ty = Type::Function {
934 param_mutability: vec![false; enum_variant.fields.len()],
935 params: enum_variant.fields.iter().map(|f| f.ty.clone()).collect(),
936 bounds: Default::default(),
937 return_type: return_type.into(),
938 };
939
940 if generics.is_empty() {
941 fn_ty
942 } else {
943 Type::Forall {
944 vars: generics.iter().map(|g| g.name.clone()).collect(),
945 body: Box::new(fn_ty),
946 }
947 }
948}
949
950fn tuple_struct_constructor_type_from_fields(
951 field_types: &[Type],
952 struct_ty: &Type,
953 generics: &[Generic],
954) -> Type {
955 let return_type = match struct_ty {
956 Type::Forall { body, .. } => body.as_ref().clone(),
957 _ => struct_ty.clone(),
958 };
959
960 let fn_ty = Type::Function {
961 param_mutability: vec![false; field_types.len()],
962 params: field_types.to_vec(),
963 bounds: Default::default(),
964 return_type: return_type.into(),
965 };
966
967 if generics.is_empty() {
968 fn_ty
969 } else {
970 Type::Forall {
971 vars: generics.iter().map(|g| g.name.clone()).collect(),
972 body: Box::new(fn_ty),
973 }
974 }
975}
976
977pub(super) fn wrap_with_impl_generics(
978 fn_ty: &Type,
979 generics: &[Generic],
980 impl_bounds: &[syntax::types::Bound],
981) -> Type {
982 if generics.is_empty() {
983 return fn_ty.clone();
984 }
985
986 let impl_vars: Vec<syntax::EcoString> = generics.iter().map(|g| g.name.clone()).collect();
987
988 let add_impl_bounds = |existing_bounds: &[syntax::types::Bound]| -> Vec<syntax::types::Bound> {
989 impl_bounds
990 .iter()
991 .cloned()
992 .chain(existing_bounds.iter().cloned())
993 .collect()
994 };
995
996 match fn_ty {
997 Type::Forall { vars, body } => {
998 let new_body = match body.as_ref() {
999 Type::Function {
1000 params,
1001 param_mutability,
1002 bounds,
1003 return_type,
1004 } => Type::Function {
1005 params: params.clone(),
1006 param_mutability: param_mutability.clone(),
1007 bounds: add_impl_bounds(bounds),
1008 return_type: return_type.clone(),
1009 },
1010 _ => *body.clone(),
1011 };
1012 Type::Forall {
1013 vars: impl_vars.into_iter().chain(vars.clone()).collect(),
1014 body: Box::new(new_body),
1015 }
1016 }
1017 Type::Function {
1018 params,
1019 param_mutability,
1020 bounds,
1021 return_type,
1022 } => Type::Forall {
1023 vars: impl_vars,
1024 body: Box::new(Type::Function {
1025 params: params.clone(),
1026 param_mutability: param_mutability.clone(),
1027 bounds: add_impl_bounds(bounds),
1028 return_type: return_type.clone(),
1029 }),
1030 },
1031 _ => Type::Forall {
1032 vars: impl_vars,
1033 body: Box::new(fn_ty.clone()),
1034 },
1035 }
1036}
1037
1038fn type_contains_constructor(target_id: &str, ty: &Type) -> bool {
1039 walk_type(ty, &|id, _| id == target_id)
1040}
1041
1042pub(super) fn has_recursive_instantiation(target_id: &str, ty: &Type) -> bool {
1046 walk_type(ty, &|id, params| {
1047 id == target_id
1048 && params
1049 .iter()
1050 .any(|p| type_contains_constructor(target_id, p))
1051 })
1052}
1053
1054fn walk_type(ty: &Type, predicate: &dyn Fn(&str, &[Type]) -> bool) -> bool {
1055 if let Type::Nominal { id, params, .. } = ty
1056 && predicate(id, params)
1057 {
1058 return true;
1059 }
1060 ty.children().iter().any(|c| walk_type(c, predicate))
1061}