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