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