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