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