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