1use super::expr::Expr;
5use super::expr::METHOD_SEP;
6use super::expr::Span;
7use super::expr::UNARY_MINUS_METHOD;
8use super::expr::is_operator_method;
9use super::expr::is_unary_operator_method;
10use super::expr::mangle_method;
11use super::expr::operator_method;
12use super::expr::self_operator_method;
13use super::expr::symbol_of_expr;
14use crate::compiler::FileNamespaces;
15use crate::compiler::Namespace;
16use crate::compiler::SymbolKind;
17use crate::compiler::compiler_data::Ctx;
18use crate::compiler::compiler_data::EnumType;
19use crate::compiler::compiler_data::EnumVariant;
20use crate::compiler::compiler_data::FnGenerics;
21use crate::compiler::compiler_data::Function;
22use crate::compiler::compiler_data::Source;
23use crate::compiler::compiler_data::State;
24use crate::compiler::compiler_data::Struct;
25use crate::compiler::compiler_data::TypeNames;
26use crate::compiler::compiler_data::Variable;
27use crate::compiler::compiler_errors::error_instantiation_depth;
28use crate::compiler::compiler_errors::error_invalid_obj_type;
29use crate::compiler::compiler_errors::error_invalid_type;
30use crate::compiler::compiler_errors::error_missing_return;
31use crate::compiler::compiler_errors::error_op;
32use crate::compiler::compiler_errors::error_operator_method;
33use crate::compiler::compiler_errors::error_struct_default_signature;
34use crate::compiler::compiler_errors::error_struct_unknown_field;
35use crate::compiler::compiler_errors::error_type_arg_count;
36use crate::compiler::compiler_errors::error_type_args_on_plain_function;
37use crate::compiler::compiler_errors::error_type_args_on_plain_type;
38use crate::compiler::compiler_errors::error_type_not_indexable;
39use crate::compiler::compiler_errors::error_unknown_function;
40use crate::compiler::compiler_errors::error_unknown_function_in_namespace;
41use crate::compiler::compiler_errors::error_unknown_namespace;
42use crate::compiler::compiler_errors::error_unknown_struct;
43use crate::compiler::compiler_errors::error_unknown_type;
44use crate::compiler::compiler_errors::error_unknown_type_param;
45use crate::compiler::compiler_errors::error_unknown_type_with_namespace;
46use crate::compiler::compiler_errors::error_unknown_variable;
47use crate::compiler::expr::closure_free_names;
48use crate::compiler::functions::Callee;
49use crate::compiler::functions::reject_default_default;
50use crate::compiler::functions::resolve_callee;
51use crate::compiler::methods::check_receiver;
52use crate::compiler::methods::infer_operator_method;
53use crate::compiler::methods::reject_block_dot_call;
54use crate::compiler::resolve_enum_variant;
55use crate::rt::FnValue;
56use rustc_hash::FxHashMap;
57use rustc_hash::FxHashSet;
58use smol_strc::SmolStr;
59use smol_strc::ToSmolStr;
60use std::cell::RefCell;
61use std::hint::cold_path;
62use std::hint::unreachable_unchecked;
63use std::rc::Rc;
64
65pub use crate::rt::DataType;
66
67pub const ANON_FN_PREFIX: &str = "<anon>";
75
76thread_local! {
79 static RETURN_TYPE_INFERRING: RefCell<FxHashSet<usize>> =
80 RefCell::new(FxHashSet::default());
81}
82
83pub fn reset_inference_state() {
86 RETURN_TYPE_INFERRING.with(|s| s.borrow_mut().clear());
87}
88
89pub type ReturnAnnotation = Option<Box<(TypeExpr, Span)>>;
94
95pub type TypeParams = Box<[SmolStr]>;
98
99#[derive(Debug, PartialEq, Eq, Clone)]
100pub enum TypeExpr {
101 Identifier(SmolStr, Span),
102 NamespacedIdentifier(Box<[SmolStr]>, Span),
103 Generic(Box<GenericType>),
106 Array(Box<Self>),
107 Map(Box<Self>, Box<Self>),
108 Union(Box<[Self]>),
109 Fn(Box<FnTypeExpr>),
113}
114
115#[derive(Debug, PartialEq, Eq, Clone)]
117pub struct FnTypeExpr {
118 pub args: Box<[TypeExpr]>,
119 pub return_type: Option<TypeExpr>,
120 pub span: Span,
121}
122
123#[derive(Debug, PartialEq, Eq, Clone)]
126pub struct GenericType {
127 pub namespace: Box<[SmolStr]>,
131 pub name: SmolStr,
132 pub args: Box<[TypeExpr]>,
133 pub span: Span,
134}
135
136impl TypeExpr {
137 #[must_use]
143 pub fn mentions_any(&self, params: &[SmolStr]) -> bool {
144 match self {
145 Self::Identifier(name, _) => params.contains(name),
146 Self::NamespacedIdentifier(_, _) => false,
147 Self::Fn(sig) => {
148 sig.args.iter().any(|a| a.mentions_any(params))
149 || sig
150 .return_type
151 .as_ref()
152 .is_some_and(|r| r.mentions_any(params))
153 }
154 Self::Generic(generic) => {
155 (generic.namespace.is_empty() && params.contains(&generic.name))
159 || generic.args.iter().any(|a| a.mentions_any(params))
160 }
161 Self::Array(inner) => inner.mentions_any(params),
162 Self::Map(k, val) => k.mentions_any(params) || val.mentions_any(params),
163 Self::Union(poly) => poly.iter().any(|t| t.mentions_any(params)),
164 }
165 }
166
167 #[must_use]
168 pub fn to_datatype(&self, ctx: &mut TypeCtx<'_>) -> DataType {
169 match self {
170 Self::Identifier(s, span) => match s.as_str() {
171 "int" => DataType::Int,
172 "float" => DataType::Float,
173 "bool" => DataType::Bool,
174 "string" => DataType::String,
175 "null" => DataType::Null,
176 "any" => DataType::Unknown,
180 struct_name => {
181 if let Some(bound) = ctx.generics.bound(struct_name) {
182 bound
183 } else if let Some(struct_id) =
184 ctx.scope()
185 .find_struct(&[], struct_name, *span, ctx.file_idx, ctx.sources)
186 {
187 DataType::Struct(struct_id as u16)
188 } else if let Some(enum_id) = ctx.scope().find_enum(&[], struct_name) {
189 DataType::Enum(enum_id as u16)
190 } else if find_template(&[], struct_name, ctx.scope(), ctx.generics).is_some() {
191 DataType::Unknown
195 } else if ctx.generics.in_generic_body() {
196 error_unknown_type_param(
197 *span,
198 ctx.file_idx,
199 struct_name,
200 &ctx.generics.bound_names(),
201 ctx.sources,
202 );
203 } else {
204 error_unknown_type(
205 *span,
206 ctx.file_idx,
207 struct_name,
208 ctx.sources,
209 ctx.scope(),
210 );
211 }
212 }
213 },
214 Self::NamespacedIdentifier(s, span) => {
215 if let Some(struct_id) = ctx.scope().find_struct(
216 &s[..s.len() - 1],
217 unsafe { s.last().unwrap_unchecked() },
218 *span,
219 ctx.file_idx,
220 ctx.sources,
221 ) {
222 DataType::Struct(struct_id as u16)
223 } else if let Some(enum_id) = ctx
224 .scope()
225 .find_enum(&s[..s.len() - 1], unsafe { s.last().unwrap_unchecked() })
226 {
227 DataType::Enum(enum_id as u16)
228 } else {
229 cold_path();
230 error_unknown_type_with_namespace(
231 *span,
232 ctx.file_idx,
233 unsafe { s.last().unwrap_unchecked() },
234 ctx.sources,
235 ctx.scope(),
236 &s[..s.len() - 1],
237 )
238 }
239 }
240 Self::Generic(generic) => {
241 if !generic.namespace.is_empty()
245 && ctx.scope().resolve(&generic.namespace).is_none()
246 {
247 cold_path();
248 error_unknown_namespace(
249 &generic.namespace,
250 generic.span,
251 ctx.scope(),
252 ctx.file_idx,
253 ctx.sources,
254 );
255 }
256 let args: Vec<DataType> = generic.args.iter().map(|a| a.to_datatype(ctx)).collect();
257 instantiate(&generic.namespace, &generic.name, &args, generic.span, ctx)
258 }
259 Self::Array(inner_t) => DataType::Array(Some(Box::new(inner_t.to_datatype(ctx)))),
260 Self::Map(k_t, v_t) => DataType::Map(Box::from((
261 Some(k_t.to_datatype(ctx)),
262 Some(v_t.to_datatype(ctx)),
263 ))),
264 Self::Union(poly) => {
265 DataType::Union(poly.iter().map(|t| t.to_datatype(ctx)).collect()).check_poly()
266 }
267 Self::Fn(sig) => DataType::FnValue(Box::new(FnValue {
268 sig: Some((
269 sig.args.iter().map(|a| a.to_datatype(ctx)).collect(),
270 sig.return_type
271 .as_ref()
272 .map_or(DataType::Null, |r| r.to_datatype(ctx)),
273 )),
274 candidates: Box::from([]),
275 set: None,
276 })),
277 }
278 }
279}
280
281const MAX_INSTANTIATION_DEPTH: u32 = 32;
286
287#[derive(Debug)]
291struct TypeTemplate {
292 name: SmolStr,
293 params: TypeParams,
294 file_idx: u16,
297 body: TemplateBody,
298 defaults: Box<[Option<(Expr, Span)>]>,
301}
302
303#[derive(Debug, Clone)]
306pub struct StructDefaults {
307 pub file_idx: u16,
308 pub values: Box<[Option<(Expr, Span)>]>,
311}
312
313#[derive(Debug)]
318struct Instantiation {
319 template: usize,
320 name: SmolStr,
321 instantiated: DataType,
322 args: Box<[DataType]>,
323}
324
325#[derive(Debug, Clone)]
326enum TemplateBody {
327 Struct(Box<[(SmolStr, TypeExpr, Span)]>),
328 Enum(Box<[(SmolStr, Box<[TypeExpr]>, Span)]>),
329}
330
331#[derive(Debug)]
337pub struct ImplTemplate {
338 pub type_name: SmolStr,
339 pub args: Box<[TypeExpr]>,
340 pub methods: Box<[Expr]>,
343 pub file_idx: u16,
344 pub span: Span,
345}
346
347#[derive(Debug, Default)]
356pub struct BindingFrame {
357 named: Box<[(SmolStr, DataType)]>,
358 unnamed: Box<[SmolStr]>,
359}
360
361impl BindingFrame {
362 #[must_use]
365 pub fn all_named(named: Box<[(SmolStr, DataType)]>) -> Self {
366 Self {
367 named,
368 unnamed: Box::from([]),
369 }
370 }
371
372 fn is_empty(&self) -> bool {
373 self.named.is_empty() && self.unnamed.is_empty()
374 }
375}
376
377#[derive(Debug, Default)]
380pub struct Generics {
381 templates: Vec<TypeTemplate>,
382 impls: Vec<ImplTemplate>,
383 instantiations: Vec<Instantiation>,
389 bindings: Vec<BindingFrame>,
393 depth: u32,
394 struct_defaults: FxHashMap<u16, StructDefaults>,
398 prelude_templates: std::ops::Range<usize>,
402 prelude_files: Vec<u16>,
406}
407
408impl Generics {
409 #[must_use]
411 pub const fn template_count(&self) -> usize {
412 self.templates.len()
413 }
414
415 pub fn mark_prelude_file(&mut self, file_idx: u16) {
417 self.prelude_files.push(file_idx);
418 }
419
420 pub const fn set_prelude_templates(&mut self, range: std::ops::Range<usize>) {
422 self.prelude_templates = range;
423 }
424
425 fn last_template_where(&self, matches: impl Fn(&TypeTemplate) -> bool) -> Option<usize> {
428 let prelude = &self.prelude_templates;
429 self.templates
430 .iter()
431 .enumerate()
432 .rev()
433 .find(|(i, t)| !prelude.contains(i) && matches(t))
434 .or_else(|| {
435 self.templates
436 .iter()
437 .enumerate()
438 .rev()
439 .find(|(i, t)| prelude.contains(i) && matches(t))
440 })
441 .map(|(i, _)| i)
442 }
443
444 #[must_use]
447 pub fn bound(&self, name: &str) -> Option<DataType> {
448 let frame = self.bindings.last()?;
449 frame
450 .named
451 .iter()
452 .find(|(param, _)| param == name)
453 .map(|(_, t)| t.clone())
454 .or_else(|| {
455 frame
456 .unnamed
457 .iter()
458 .any(|param| param == name)
459 .then_some(DataType::Unknown)
460 })
461 }
462
463 #[must_use]
467 pub fn names(&self, name: &str) -> bool {
468 self.bindings
469 .last()
470 .is_some_and(|frame| frame.named.iter().any(|(param, _)| param == name))
471 }
472
473 #[must_use]
476 fn in_generic_body(&self) -> bool {
477 self.bindings.last().is_some_and(|frame| !frame.is_empty())
478 }
479
480 fn bound_names(&self) -> Vec<SmolStr> {
481 self.bindings
482 .last()
483 .map(|frame| {
484 frame
485 .named
486 .iter()
487 .map(|(p, _)| p.clone())
488 .chain(frame.unnamed.iter().cloned())
489 .collect()
490 })
491 .unwrap_or_default()
492 }
493
494 #[must_use]
499 pub fn params_of(&self, name: &str) -> Option<&[SmolStr]> {
500 self.last_template_where(|t| t.name == name)
501 .map(|i| &*self.templates[i].params)
502 }
503
504 pub fn set_struct_defaults(
508 &mut self,
509 id: u16,
510 file_idx: u16,
511 values: Box<[Option<(Expr, Span)>]>,
512 ) {
513 if values.iter().any(Option::is_some) {
514 self.struct_defaults
515 .insert(id, StructDefaults { file_idx, values });
516 } else {
517 self.struct_defaults.remove(&id);
518 }
519 }
520
521 #[must_use]
524 pub fn struct_default(&self, id: u16, field: usize) -> Option<(u16, &Expr, Span)> {
525 let defaults = self.struct_defaults.get(&id)?;
526 defaults
527 .values
528 .get(field)
529 .and_then(Option::as_ref)
530 .map(|(value, span)| (defaults.file_idx, value, *span))
531 }
532
533 #[must_use]
537 pub fn param_fields(&self, template_idx: usize) -> Vec<Option<SmolStr>> {
538 let Some(template) = self.templates.get(template_idx) else {
539 return Vec::new();
540 };
541 let TemplateBody::Struct(fields) = &template.body else {
542 return vec![None; template.params.len()];
543 };
544 template
545 .params
546 .iter()
547 .map(|param| {
548 fields
549 .iter()
550 .find(|(_, field_type, _)| {
551 matches!(field_type, TypeExpr::Identifier(t, _) if t == param)
552 })
553 .map(|(field_name, _, _)| field_name.clone())
554 })
555 .collect()
556 }
557
558 fn last_template_named(&self, name: &str) -> Option<usize> {
568 let in_prelude = |i: usize| self.prelude_files.contains(&self.templates[i].file_idx);
569 let reachable = |i: usize| {
570 self.templates[i].name == name && (i >= self.prelude_templates.start || in_prelude(i))
571 };
572 (0..self.templates.len())
573 .rev()
574 .find(|&i| reachable(i) && !in_prelude(i))
575 .or_else(|| (0..self.templates.len()).rev().find(|&i| reachable(i)))
576 }
577
578 #[must_use]
581 pub fn instantiation_of(&self, t: &DataType) -> Option<(usize, &[DataType])> {
582 if !matches!(t, DataType::Struct(_) | DataType::Enum(_)) {
583 return None;
584 }
585 self.instantiations
586 .iter()
587 .find(|i| &i.instantiated == t)
588 .map(|i| (i.template, &*i.args))
589 }
590
591 #[must_use]
599 pub fn enum_template_with_variant(&self, variant: &str) -> Option<usize> {
600 self.last_template_where(|t| match &t.body {
601 TemplateBody::Enum(variants) => variants.iter().any(|(name, _, _)| name == variant),
602 TemplateBody::Struct(_) => false,
603 })
604 }
605
606 #[must_use]
609 pub fn only_the_prelude_declares(&self, variant: &str) -> bool {
610 self.enum_template_with_variant(variant)
611 .is_some_and(|template| self.prelude_templates.contains(&template))
612 }
613
614 #[must_use]
616 fn variant_payload(&self, template: usize, variant: &str) -> Option<&[TypeExpr]> {
617 let TemplateBody::Enum(variants) = &self.templates[template].body else {
618 return None;
619 };
620 variants
621 .iter()
622 .find(|(name, _, _)| name == variant)
623 .map(|(_, payload, _)| &**payload)
624 }
625
626 #[must_use]
628 fn params(&self, template: usize) -> &[SmolStr] {
629 &self.templates[template].params
630 }
631
632 #[must_use]
634 fn template_name(&self, template: usize) -> &SmolStr {
635 &self.templates[template].name
636 }
637
638 #[must_use]
640 fn template_file(&self, template: usize) -> u16 {
641 self.templates[template].file_idx
642 }
643
644 pub fn add_struct_template(
648 &mut self,
649 name: SmolStr,
650 params: TypeParams,
651 file_idx: u16,
652 fields: Box<[(SmolStr, TypeExpr, Span)]>,
653 defaults: Box<[Option<(Expr, Span)>]>,
654 ) -> u32 {
655 self.templates.push(TypeTemplate {
656 name,
657 params,
658 file_idx,
659 body: TemplateBody::Struct(fields),
660 defaults,
661 });
662 (self.templates.len() - 1) as u32
663 }
664
665 pub fn add_enum_template(
668 &mut self,
669 name: SmolStr,
670 params: TypeParams,
671 file_idx: u16,
672 variants: Box<[(SmolStr, Box<[TypeExpr]>, Span)]>,
673 ) -> u32 {
674 self.templates.push(TypeTemplate {
675 name,
676 params,
677 file_idx,
678 body: TemplateBody::Enum(variants),
679 defaults: Box::from([]),
680 });
681 (self.templates.len() - 1) as u32
682 }
683
684 #[must_use]
689 pub fn defines_operator_methods(&self) -> bool {
690 self.impls.iter().any(|block| {
691 block.methods.iter().any(|method| {
692 matches!(method, Expr::FunctionDecl(name, ..) if operator_method(name).is_some())
693 })
694 })
695 }
696
697 pub fn add_impls(&mut self, impls: Vec<ImplTemplate>, file_idx: u16) {
698 self.impls.extend(impls.into_iter().map(|mut block| {
699 block.file_idx = file_idx;
700 block
701 }));
702 }
703
704 #[must_use]
708 pub fn path_fn_of_template(&self, template: usize, name: &str) -> Option<String> {
709 let decl = &self.templates[template];
710 self.impls
711 .iter()
712 .filter(|block| impl_base_name(&block.type_name) == decl.name.as_str())
713 .flat_map(|block| block.methods.iter())
714 .any(|method| {
715 matches!(method, Expr::FunctionDecl(fn_name, args, ..)
716 if fn_name == name && args.is_empty())
717 })
718 .then(|| format!("{}<{}>::{name}()", decl.name, decl.params.join(", ")))
719 }
720
721 pub fn push_bindings(&mut self, frame: Box<[(SmolStr, DataType)]>) {
725 self.bindings.push(BindingFrame::all_named(frame));
726 }
727
728 pub fn push_frame(&mut self, frame: BindingFrame) {
731 self.bindings.push(frame);
732 }
733
734 pub fn pop_bindings(&mut self) {
735 self.bindings.pop();
736 }
737
738 #[must_use]
758 pub const fn checkpoint(&self) -> GenericsCheckpoint {
759 GenericsCheckpoint {
760 instantiations: self.instantiations.len(),
761 bindings: self.bindings.len(),
762 depth: self.depth,
763 }
764 }
765
766 pub fn rollback_to(&mut self, checkpoint: &GenericsCheckpoint) {
772 self.instantiations.truncate(checkpoint.instantiations);
773 self.bindings.truncate(checkpoint.bindings);
774 self.depth = checkpoint.depth;
775 }
776}
777
778pub struct GenericsCheckpoint {
781 instantiations: usize,
782 bindings: usize,
783 depth: u32,
784}
785
786pub struct TypeCtx<'a> {
789 pub file_idx: u16,
790 pub namespaces: &'a FileNamespaces,
791 pub sources: &'a [Source],
792 pub structs: &'a mut Vec<Struct>,
793 pub enums: &'a mut Vec<EnumType>,
794 pub fns: &'a mut Vec<Function>,
795 pub generics: &'a mut Generics,
796}
797
798impl<'a> TypeCtx<'a> {
799 #[must_use]
801 pub fn scope(&self) -> &'a Namespace {
802 self.namespaces.get(self.file_idx)
803 }
804 pub const fn reborrow(&mut self, file_idx: u16) -> TypeCtx<'_> {
808 TypeCtx {
809 file_idx,
810 namespaces: self.namespaces,
811 sources: self.sources,
812 structs: self.structs,
813 enums: self.enums,
814 fns: self.fns,
815 generics: self.generics,
816 }
817 }
818}
819
820#[must_use]
826fn render_type(t: &DataType, structs: &[Struct], enums: &[EnumType]) -> SmolStr {
827 match t {
828 DataType::Int => SmolStr::new_static("int"),
829 DataType::Float => SmolStr::new_static("float"),
830 DataType::Bool => SmolStr::new_static("bool"),
831 DataType::String => SmolStr::new_static("string"),
832 DataType::Null => SmolStr::new_static("null"),
833 DataType::Unknown => SmolStr::new_static("any"),
834 DataType::FnValue(sig) => sig.to_smolstr(),
835 DataType::Array(inner) => match inner {
836 Some(inner) => format_args!("{}[]", render_type(inner, structs, enums)).to_smolstr(),
837 None => SmolStr::new_static("any[]"),
838 },
839 DataType::Map(m) => format_args!(
840 "{{{}: {}}}",
841 m.0.as_ref().map_or_else(
842 || SmolStr::new_static("any"),
843 |k| render_type(k, structs, enums)
844 ),
845 m.1.as_ref().map_or_else(
846 || SmolStr::new_static("any"),
847 |val| render_type(val, structs, enums)
848 )
849 )
850 .to_smolstr(),
851 DataType::Union(poly) => poly
852 .iter()
853 .map(|t| render_type(t, structs, enums))
854 .collect::<Vec<SmolStr>>()
855 .join("|")
856 .into(),
857 DataType::Struct(id) => structs[*id as usize].name.clone(),
858 DataType::Enum(id) => enums[*id as usize].name.clone(),
859 DataType::Fn(id) => format_args!("fn:{id}").to_smolstr(),
860 }
861}
862
863#[must_use]
871fn render_instantiation(
872 qualifier: Option<&str>,
873 base: &str,
874 args: &[DataType],
875 structs: &[Struct],
876 enums: &[EnumType],
877) -> SmolStr {
878 let rendered = args
879 .iter()
880 .map(|a| render_type(a, structs, enums))
881 .collect::<Vec<SmolStr>>()
882 .join(", ");
883 match qualifier {
884 Some(module) => format_args!("{module}::{base}<{rendered}>").to_smolstr(),
885 None => format_args!("{base}<{rendered}>").to_smolstr(),
886 }
887}
888
889#[must_use]
892fn module_segments(file_idx: u16, sources: &[Source]) -> Vec<&str> {
893 let Some(source) = sources.get(file_idx as usize) else {
894 return Vec::new();
895 };
896 let path: &str = source
897 .filename
898 .strip_suffix(".cdl")
899 .unwrap_or(&source.filename);
900 path.split(['/', '\\']).filter(|s| !s.is_empty()).collect()
901}
902
903#[must_use]
909fn module_qualifier(file_idx: u16, declarers: &[u16], sources: &[Source]) -> SmolStr {
910 let mine = module_segments(file_idx, sources);
911 let others: Vec<Vec<&str>> = declarers
912 .iter()
913 .filter(|other| **other != file_idx)
914 .map(|other| module_segments(*other, sources))
915 .collect();
916 for take in 1..=mine.len() {
917 let tail = &mine[mine.len() - take..];
918 if others
919 .iter()
920 .all(|other| other.len() < take || &other[other.len() - take..] != tail)
921 {
922 return tail.join("::").into();
923 }
924 }
925 mine.join("::").into()
926}
927
928pub fn qualify_duplicate_type_names(
944 structs: &mut [Struct],
945 enums: &mut [EnumType],
946 fns: &mut [Function],
947 struct_files: &[(u16, u16)],
948 enum_files: &[(u16, u16)],
949 namespaces: &FileNamespaces,
950 sources: &[Source],
951) {
952 let mut declarers: FxHashMap<SmolStr, Vec<u16>> = FxHashMap::default();
956 for (name, file_idx) in struct_files
957 .iter()
958 .filter_map(|(id, file_idx)| Some((&structs.get(*id as usize)?.name, *file_idx)))
959 .chain(
960 enum_files
961 .iter()
962 .filter_map(|(id, file_idx)| Some((&enums.get(*id as usize)?.name, *file_idx))),
963 )
964 {
965 declarers.entry(name.clone()).or_default().push(file_idx);
966 }
967 if declarers.values().all(|files| files.len() <= 1) {
968 return;
969 }
970
971 for &(struct_id, file_idx) in struct_files {
972 let Some(declared) = structs.get_mut(struct_id as usize) else {
973 continue;
974 };
975 if let Some(files) = declarers.get(&declared.name)
976 && files.len() > 1
977 {
978 declared.name = qualified_type_name(file_idx, files, &declared.name, sources);
979 }
980 }
981 for &(enum_id, file_idx) in enum_files {
982 let Some(declared) = enums.get_mut(enum_id as usize) else {
983 continue;
984 };
985 if let Some(files) = declarers.get(&declared.name)
986 && files.len() > 1
987 {
988 declared.name = qualified_type_name(file_idx, files, &declared.name, sources);
989 }
990 }
991
992 for func in fns.iter_mut() {
993 let scope = namespaces.get(func.src_file);
994 if let Some(mangled) = requalify_method(&func.name, scope, structs, enums) {
995 func.name = mangled;
996 }
997 for callee in &mut func.direct_calls {
998 if let Some(mangled) = requalify_method(callee, scope, structs, enums) {
999 *callee = mangled;
1000 }
1001 }
1002 }
1003}
1004
1005#[must_use]
1008fn qualified_type_name(
1009 file_idx: u16,
1010 declarers: &[u16],
1011 name: &str,
1012 sources: &[Source],
1013) -> SmolStr {
1014 format_args!("{}::{name}", module_qualifier(file_idx, declarers, sources)).to_smolstr()
1015}
1016
1017#[must_use]
1023fn requalify_method(
1024 name: &str,
1025 scope: &Namespace,
1026 structs: &[Struct],
1027 enums: &[EnumType],
1028) -> Option<SmolStr> {
1029 let (type_name, method) = name.split_once(METHOD_SEP)?;
1030 let declared = scope.symbols.iter().find_map(|(symbol, kind)| {
1031 if symbol.as_str() != type_name {
1032 return None;
1033 }
1034 match kind {
1035 SymbolKind::Struct(id) => structs.get(*id as usize).map(|s| &s.name),
1036 SymbolKind::Enum(id) => enums.get(*id as usize).map(|e| &e.name),
1037 SymbolKind::Fn(_) | SymbolKind::Template(_) => None,
1038 }
1039 })?;
1040 (declared != type_name).then(|| mangle_method(declared, method))
1041}
1042
1043#[must_use]
1054pub fn find_template(
1055 namespace: &[SmolStr],
1056 name: &str,
1057 scope: &Namespace,
1058 generics: &Generics,
1059) -> Option<usize> {
1060 scope.find_template(namespace, name).or_else(|| {
1061 namespace
1062 .is_empty()
1063 .then(|| generics.last_template_named(name))
1064 .flatten()
1065 })
1066}
1067
1068pub fn instantiate(
1075 namespace: &[SmolStr],
1076 base: &str,
1077 args: &[DataType],
1078 span: Span,
1079 ctx: &mut TypeCtx<'_>,
1080) -> DataType {
1081 let Some(template_idx) = find_template(namespace, base, ctx.scope(), ctx.generics) else {
1082 if ctx
1083 .scope()
1084 .find_struct(namespace, base, span, ctx.file_idx, ctx.sources)
1085 .is_some()
1086 || ctx.scope().find_enum(namespace, base).is_some()
1087 {
1088 error_type_args_on_plain_type(span, ctx.file_idx, base, ctx.sources);
1089 }
1090 if !namespace.is_empty() {
1091 error_unknown_type_with_namespace(
1092 span,
1093 ctx.file_idx,
1094 base,
1095 ctx.sources,
1096 ctx.scope(),
1097 namespace,
1098 );
1099 }
1100 error_unknown_type(span, ctx.file_idx, base, ctx.sources, ctx.scope());
1101 };
1102 let declarers: Vec<u16> = ctx
1105 .generics
1106 .templates
1107 .iter()
1108 .filter(|t| t.name == base)
1109 .map(|t| t.file_idx)
1110 .collect();
1111 let qualifier = (declarers.len() > 1).then(|| {
1112 module_qualifier(
1113 ctx.generics.templates[template_idx].file_idx,
1114 &declarers,
1115 ctx.sources,
1116 )
1117 });
1118 let name = render_instantiation(qualifier.as_deref(), base, args, ctx.structs, ctx.enums);
1119 if let Some(existing) = ctx
1120 .generics
1121 .instantiations
1122 .iter()
1123 .find(|i| i.template == template_idx && i.name == name)
1124 {
1125 return existing.instantiated.clone();
1126 }
1127 if ctx.generics.templates[template_idx].params.len() != args.len() {
1128 error_type_arg_count(
1129 span,
1130 ctx.file_idx,
1131 base,
1132 ctx.generics.templates[template_idx].params.len(),
1133 args.len(),
1134 ctx.sources,
1135 );
1136 }
1137 if ctx.generics.depth >= MAX_INSTANTIATION_DEPTH {
1138 error_instantiation_depth(span, ctx.file_idx, base, ctx.sources);
1139 }
1140
1141 let template_file = ctx.generics.templates[template_idx].file_idx;
1142 let frame: Box<[(SmolStr, DataType)]> = ctx.generics.templates[template_idx]
1143 .params
1144 .iter()
1145 .cloned()
1146 .zip(args.iter().cloned())
1147 .collect();
1148
1149 let is_struct = matches!(
1153 ctx.generics.templates[template_idx].body,
1154 TemplateBody::Struct(_)
1155 );
1156 let instantiated = if is_struct {
1157 let id = ctx.structs.len() as u16;
1158 ctx.structs.push(Struct {
1159 name: name.clone(),
1160 fields: Box::from([]),
1161 id,
1162 name_span: span,
1163 });
1164 let defaults = ctx.generics.templates[template_idx].defaults.clone();
1165 ctx.generics
1166 .set_struct_defaults(id, template_file, defaults);
1167 DataType::Struct(id)
1168 } else {
1169 let id = ctx.enums.len() as u16;
1170 ctx.enums.push(EnumType {
1171 name: name.clone(),
1172 variants: Box::from([]),
1173 id,
1174 name_span: span,
1175 });
1176 DataType::Enum(id)
1177 };
1178 ctx.generics.instantiations.push(Instantiation {
1179 template: template_idx,
1180 name: name.clone(),
1181 instantiated: instantiated.clone(),
1182 args: args.into(),
1183 });
1184
1185 let body = ctx.generics.templates[template_idx].body.clone();
1186 ctx.generics.depth += 1;
1187 ctx.generics.push_bindings(frame.clone());
1188 {
1189 let mut inner = ctx.reborrow(template_file);
1190 match body {
1191 TemplateBody::Struct(fields) => {
1192 let resolved = fields
1193 .iter()
1194 .map(|(field_name, field_type, field_span)| {
1195 (
1196 field_name.clone(),
1197 field_type.to_datatype(&mut inner),
1198 *field_span,
1199 )
1200 })
1201 .collect();
1202 if let DataType::Struct(id) = instantiated {
1203 inner.structs[id as usize].fields = resolved;
1204 }
1205 }
1206 TemplateBody::Enum(variants) => {
1207 let resolved = variants
1208 .iter()
1209 .map(|(variant_name, payload, name_span)| EnumVariant {
1210 name: variant_name.clone(),
1211 payload: payload.iter().map(|t| t.to_datatype(&mut inner)).collect(),
1212 name_span: *name_span,
1213 })
1214 .collect();
1215 if let DataType::Enum(id) = instantiated {
1216 inner.enums[id as usize].variants = resolved;
1217 }
1218 }
1219 }
1220 }
1221 ctx.generics.pop_bindings();
1222
1223 lower_impls(template_idx, base, args, &name, &frame, ctx);
1224 ctx.generics.depth -= 1;
1225
1226 instantiated
1227}
1228
1229fn lower_impls(
1236 template_idx: usize,
1237 base: &str,
1238 args: &[DataType],
1239 type_name: &SmolStr,
1240 type_frame: &[(SmolStr, DataType)],
1241 ctx: &mut TypeCtx<'_>,
1242) {
1243 let applicable: Vec<usize> = ctx
1244 .generics
1245 .impls
1246 .iter()
1247 .enumerate()
1248 .filter(|(_, block)| block.type_name == base && block.args.len() == args.len())
1249 .map(|(i, _)| i)
1250 .collect();
1251 for idx in applicable {
1252 let impl_file = ctx.generics.impls[idx].file_idx;
1253 if find_template(&[], base, ctx.namespaces.get(impl_file), ctx.generics)
1257 != Some(template_idx)
1258 {
1259 continue;
1260 }
1261 let header = ctx.generics.impls[idx].args.clone();
1262 let mut frame: Vec<(SmolStr, DataType)> = Vec::with_capacity(header.len());
1263 let mut applies = true;
1264 for (header_arg, arg) in header.iter().zip(args) {
1265 match header_arg {
1266 TypeExpr::Identifier(pname, _) if is_type_parameter(pname, impl_file, ctx) => {
1271 frame.push((pname.clone(), arg.clone()));
1272 }
1273 other => {
1274 let mut inner = ctx.reborrow(impl_file);
1275 inner.generics.push_bindings(Box::from(type_frame));
1276 let pinned = other.to_datatype(&mut inner);
1277 ctx.generics.pop_bindings();
1278 if &pinned != arg {
1279 applies = false;
1280 break;
1281 }
1282 }
1283 }
1284 }
1285 if !applies {
1286 continue;
1287 }
1288 let methods = ctx.generics.impls[idx].methods.clone();
1289 let bindings: Box<[(SmolStr, DataType)]> = Box::from(frame);
1290 for method in methods {
1291 lower_method(&method, type_name, &bindings, impl_file, ctx);
1292 }
1293 }
1294}
1295
1296fn is_type_parameter(name: &SmolStr, file_idx: u16, ctx: &TypeCtx<'_>) -> bool {
1299 if matches!(
1300 name.as_str(),
1301 "int" | "float" | "bool" | "string" | "null" | "any"
1302 ) {
1303 return false;
1304 }
1305 find_template(&[], name, ctx.namespaces.get(file_idx), ctx.generics).is_none()
1306 && !ctx
1307 .namespaces
1308 .get(file_idx)
1309 .symbols
1310 .iter()
1311 .any(|(symbol, kind)| {
1312 symbol == name && matches!(kind, SymbolKind::Struct(_) | SymbolKind::Enum(_))
1313 })
1314}
1315
1316fn impl_base_name(type_name: &str) -> &str {
1319 let without_args = type_name.split('<').next().unwrap_or(type_name);
1320 without_args.rsplit("::").next().unwrap_or(without_args)
1321}
1322
1323fn annotation_base_name(annotation: &TypeExpr) -> Option<&SmolStr> {
1326 match annotation {
1327 TypeExpr::Identifier(name, _) => Some(name),
1328 TypeExpr::NamespacedIdentifier(path, _) => path.last(),
1329 TypeExpr::Generic(generic) => Some(&generic.name),
1330 TypeExpr::Array(_) | TypeExpr::Map(_, _) | TypeExpr::Union(_) | TypeExpr::Fn(_) => None,
1331 }
1332}
1333
1334pub fn check_operator_method(
1342 mangled: &str,
1343 args: &[(SmolStr, Option<TypeExpr>)],
1344 name_span: Span,
1345 file_idx: u16,
1346 sources: &[Source],
1347) {
1348 let Some((type_name, method)) = mangled.split_once(METHOD_SEP) else {
1349 return;
1350 };
1351 if !is_operator_method(method) {
1352 return;
1353 }
1354 let symbol = if method == UNARY_MINUS_METHOD {
1355 "-"
1356 } else {
1357 method
1358 };
1359 if matches!(
1360 type_name,
1361 "int" | "float" | "string" | "bool" | "list" | "map"
1362 ) {
1363 cold_path();
1364 error_operator_method(
1365 "Operator on a built-in type",
1366 &format!("{type_name} does not take a {symbol} method"),
1367 "What an operator means on a built-in type is part of the language. Put the value in a struct of your own and define the operator there.",
1368 "operator_method_on_builtin",
1369 name_span,
1370 file_idx,
1371 sources,
1372 );
1373 }
1374 let wanted = usize::from(!is_unary_operator_method(method)) + 1;
1375 if args.len() != wanted {
1376 cold_path();
1377 error_operator_method(
1378 "Operator method takes the wrong number of parameters",
1379 &format!(
1380 "{symbol} on {type_name} is declared with {} parameter{}",
1381 args.len(),
1382 if args.len() == 1 { "" } else { "s" }
1383 ),
1384 if symbol == "-" {
1385 "- takes the receiver and the value to subtract, or the receiver alone to negate it."
1386 } else if wanted == 1 {
1387 "A unary operator takes the receiver and nothing else."
1388 } else {
1389 "A binary operator takes the receiver and the other operand."
1390 },
1391 "operator_method_arity",
1392 name_span,
1393 file_idx,
1394 sources,
1395 );
1396 }
1397 if let Some((_, Some(annotation))) = args.first() {
1398 let base = impl_base_name(type_name);
1399 if annotation_base_name(annotation).is_none_or(|written| written != base) {
1400 cold_path();
1401 error_operator_method(
1402 "Operator method receives another type",
1403 &format!("The first parameter of {symbol} is not a {base}"),
1404 "The first parameter of a method is the receiver, and its type is the one the impl block names. Leave it un-annotated or annotate it with that type.",
1405 "operator_method_receiver",
1406 name_span,
1407 file_idx,
1408 sources,
1409 );
1410 }
1411 }
1412}
1413
1414pub const STRUCT_DEFAULT_METHOD: &str = "default";
1416
1417#[must_use]
1420pub fn struct_of_default_fn(fn_name: &str, structs: &[Struct]) -> Option<u16> {
1421 let (type_name, method) = fn_name.split_once(METHOD_SEP)?;
1422 if method != STRUCT_DEFAULT_METHOD {
1423 return None;
1424 }
1425 structs.iter().rfind(|s| s.name == type_name).map(|s| s.id)
1426}
1427
1428pub fn check_struct_default_fn(
1439 func: &Function,
1440 struct_id: u16,
1441 returns: Option<(&DataType, Span)>,
1442 sources: &[Source],
1443 types: TypeNames<'_>,
1444) {
1445 let struct_type = DataType::Struct(struct_id);
1446 let struct_name = types.of(&struct_type).to_string();
1447 if !func.args.is_empty() {
1448 cold_path();
1449 error_struct_default_signature(
1450 "Default function takes parameters",
1451 &format!(
1452 "default in impl {struct_name} is declared with {} parameter{}",
1453 func.args.len(),
1454 if func.args.len() == 1 { "" } else { "s" }
1455 ),
1456 &format!(
1457 "{struct_name}::default() and {struct_name} {{ .. }} call it with nothing, so it takes no parameters. A method that takes the value needs another name."
1458 ),
1459 func.name_span,
1460 func.src_file,
1461 sources,
1462 );
1463 }
1464 if let Some((returned, span)) = returns
1465 && *returned != struct_type
1466 {
1467 cold_path();
1468 error_struct_default_signature(
1469 "Default function returns another type",
1470 &format!(
1471 "default in impl {struct_name} returns {}, not {struct_name}",
1472 types.of(returned)
1473 ),
1474 &format!(
1475 "It builds the default of {struct_name}, so its return type is {struct_name}."
1476 ),
1477 span,
1478 func.src_file,
1479 sources,
1480 );
1481 }
1482}
1483
1484fn lower_method(
1487 method: &Expr,
1488 type_name: &SmolStr,
1489 bindings: &[(SmolStr, DataType)],
1490 file_idx: u16,
1491 ctx: &mut TypeCtx<'_>,
1492) {
1493 let Expr::FunctionDecl(method_name, args, code, name_span, return_type, params) = method else {
1494 return;
1495 };
1496 let mangled = mangle_method(type_name, method_name);
1497 check_operator_method(&mangled, args, *name_span, file_idx, ctx.sources);
1498 if let Some(existing) = ctx.fns.iter().find(|f| f.name == mangled) {
1499 crate::compiler::compiler_errors::error_function_already_defined(
1500 existing,
1501 *name_span,
1502 file_idx,
1503 ctx.sources,
1504 );
1505 }
1506 let mut inner = ctx.reborrow(file_idx);
1507 inner.generics.push_bindings(Box::from(bindings));
1508 let resolved_args: Box<[(SmolStr, Option<DataType>)]> = args
1509 .iter()
1510 .map(|(arg_name, arg_type)| {
1511 (
1512 arg_name.clone(),
1513 arg_type
1514 .as_ref()
1515 .filter(|t| !t.mentions_any(params))
1516 .map(|t| t.to_datatype(&mut inner)),
1517 )
1518 })
1519 .collect();
1520 let resolved_return = return_type
1521 .as_deref()
1522 .filter(|(t, _)| !t.mentions_any(params))
1523 .map(|(t, t_span)| (t.to_datatype(&mut inner), *t_span));
1524 ctx.generics.pop_bindings();
1525
1526 let mut callees = Vec::new();
1527 collect_direct_fn_calls(code, Some(type_name.as_str()), &mut callees);
1528 ctx.fns.push(Function {
1529 name: mangled,
1530 args: resolved_args,
1531 code: Rc::clone(code),
1532 impls: Vec::new(),
1533 is_recursive: None,
1534 returns_null: check_if_returns_void(code),
1535 src_file: file_idx,
1536 return_type_cache: Vec::new(),
1537 direct_calls: callees.into_boxed_slice(),
1538 name_span: *name_span,
1539 return_type: resolved_return,
1540 captures: Box::from([]),
1541 generics: Some(Box::new(FnGenerics {
1542 params: params.clone(),
1543 arg_types: args.iter().map(|(_, t)| t.clone()).collect(),
1544 return_type: return_type.clone(),
1545 bindings: Box::from(bindings),
1546 file_idx,
1547 })),
1548 entry_register: None,
1549 });
1550 let func = &ctx.fns[ctx.fns.len() - 1];
1551 if let Some(struct_id) = struct_of_default_fn(&func.name, ctx.structs) {
1552 check_struct_default_fn(
1553 func,
1554 struct_id,
1555 func.return_type.as_ref().map(|(t, span)| (t, *span)),
1556 ctx.sources,
1557 TypeNames {
1558 structs: ctx.structs,
1559 enums: ctx.enums,
1560 },
1561 );
1562 }
1563}
1564
1565pub fn struct_literal_id(
1572 namespace: &[SmolStr],
1573 fields: &[(SmolStr, Expr, Span, Span)],
1574 type_args: &[TypeExpr],
1575 span: Span,
1576 v: &mut Vec<Variable>,
1577 ctx: Ctx,
1578 state: &mut State<'_>,
1579) -> u16 {
1580 let name = namespace[namespace.len() - 1].clone();
1581 let path = &namespace[..namespace.len() - 1];
1582 if !type_args.is_empty() {
1583 let args = resolve_type_args(type_args, ctx, state);
1584 return instantiated_struct_id(path, &name, &args, span, ctx, state);
1585 }
1586 if let Some(template_idx) =
1587 find_template(path, &name, state.scope(ctx.file_idx), state.generics)
1588 {
1589 let param_fields = state.generics.param_fields(template_idx);
1590 let mut args: Vec<DataType> = Vec::with_capacity(param_fields.len());
1591 for field_name in param_fields {
1592 args.push(
1593 field_name
1594 .and_then(|f| fields.iter().find(|(n, _, _, _)| *n == f))
1595 .map_or(DataType::Unknown, |(_, value, _, _)| {
1596 value.infer_type(v, ctx, state)
1597 }),
1598 );
1599 }
1600 return instantiated_struct_id(path, &name, &args, span, ctx, state);
1601 }
1602 state
1603 .scope(ctx.file_idx)
1604 .find_struct(path, &name, span, ctx.file_idx, state.sources)
1605 .unwrap_or_else(|| {
1606 error_unknown_struct(
1607 &name,
1608 span,
1609 state.scope(ctx.file_idx),
1610 state.sources,
1611 ctx.file_idx,
1612 );
1613 }) as u16
1614}
1615
1616pub fn literal_struct_id(
1622 namespace: &[SmolStr],
1623 fields: &[(SmolStr, Expr, Span, Span)],
1624 type_args: &[TypeExpr],
1625 base: Option<&Expr>,
1626 span: Span,
1627 v: &mut Vec<Variable>,
1628 ctx: Ctx,
1629 state: &mut State<'_>,
1630) -> u16 {
1631 if type_args.is_empty()
1632 && let Some(base) = base
1633 && let Some((name, path)) = namespace.split_last()
1634 && let Some(template_idx) =
1635 find_template(path, name, state.scope(ctx.file_idx), state.generics)
1636 && let DataType::Struct(id) = base.infer_type(v, ctx, state)
1637 && state
1638 .generics
1639 .instantiation_of(&DataType::Struct(id))
1640 .is_some_and(|(template, _)| template == template_idx)
1641 {
1642 return id;
1643 }
1644 struct_literal_id(namespace, fields, type_args, span, v, ctx, state)
1645}
1646
1647pub fn struct_default_target(
1653 path: &[SmolStr],
1654 args: &[Expr],
1655 type_args: &[TypeExpr],
1656 span: Span,
1657 ctx: Ctx,
1658 state: &mut State<'_>,
1659) -> Option<u16> {
1660 let [module @ .., type_name, method] = path else {
1661 return None;
1662 };
1663 if method != "default" || !args.is_empty() {
1664 return None;
1665 }
1666 let scope = state.scope(ctx.file_idx);
1667 let is_struct = scope.resolve(module).is_some_and(|ns| {
1668 ns.symbols
1669 .iter()
1670 .any(|(name, kind)| name == type_name && matches!(kind, SymbolKind::Struct(_)))
1671 });
1672 let is_template = find_template(module, type_name, scope, state.generics)
1673 .is_some_and(|idx| matches!(state.generics.templates[idx].body, TemplateBody::Struct(_)));
1674 if !is_struct && !is_template {
1675 return None;
1676 }
1677 let mut type_path = module.to_vec();
1678 type_path.push(type_name.clone());
1679 Some(struct_literal_id(
1680 &type_path,
1681 &[],
1682 type_args,
1683 span,
1684 &mut Vec::new(),
1685 ctx,
1686 state,
1687 ))
1688}
1689
1690fn path_call_type(
1697 module: &[SmolStr],
1698 type_name: &SmolStr,
1699 type_args: &[TypeExpr],
1700 span: Span,
1701 ctx: Ctx,
1702 state: &mut State<'_>,
1703) -> Option<DataType> {
1704 let scope = state.scope(ctx.file_idx);
1705 if let Some(template) = find_template(module, type_name, scope, state.generics) {
1706 let args = if type_args.is_empty() {
1707 vec![DataType::Unknown; state.generics.params(template).len()]
1708 } else {
1709 resolve_type_args(type_args, ctx, state)
1710 };
1711 return Some(instantiate(
1712 module,
1713 type_name,
1714 &args,
1715 span,
1716 &mut state.type_ctx(ctx.file_idx),
1717 ));
1718 }
1719 if !type_args.is_empty() {
1720 return None;
1721 }
1722 scope
1723 .resolve(module)?
1724 .symbols
1725 .iter()
1726 .rev()
1727 .find_map(|(name, kind)| match kind {
1728 SymbolKind::Struct(id) if name == type_name => Some(DataType::Struct(*id)),
1729 SymbolKind::Enum(id) if name == type_name => Some(DataType::Enum(*id)),
1730 _ => None,
1731 })
1732}
1733
1734pub fn path_call_target(
1746 path: &[SmolStr],
1747 type_args: &[TypeExpr],
1748 span: Span,
1749 ctx: Ctx,
1750 state: &mut State<'_>,
1751) -> Option<usize> {
1752 let [module @ .., type_name, method] = path else {
1753 return None;
1754 };
1755 let ty = path_call_type(module, type_name, type_args, span, ctx, state)?;
1756 let registered = match ty {
1757 DataType::Struct(id) => state.structs[id as usize].name.clone(),
1758 DataType::Enum(id) => {
1759 let e = &state.enums[id as usize];
1760 if e.variants.iter().any(|variant| variant.name == *method) {
1761 return None;
1762 }
1763 e.name.clone()
1764 }
1765 _ => return None,
1766 };
1767 let mangled = mangle_method(®istered, method);
1768 let fn_id = state.fns.iter().position(|f| f.name == mangled)?;
1769 if !state.fns[fn_id].args.is_empty() {
1770 cold_path();
1771 crate::compiler::compiler_errors::error_path_call_with_receiver(
1772 method,
1773 ®istered,
1774 span,
1775 (state.fns[fn_id].name_span, state.fns[fn_id].src_file),
1776 ctx.file_idx,
1777 state.sources,
1778 );
1779 }
1780 Some(fn_id)
1781}
1782
1783fn instantiated_struct_id(
1784 namespace: &[SmolStr],
1785 name: &SmolStr,
1786 args: &[DataType],
1787 span: Span,
1788 ctx: Ctx,
1789 state: &mut State<'_>,
1790) -> u16 {
1791 match instantiate(
1792 namespace,
1793 name,
1794 args,
1795 span,
1796 &mut state.type_ctx(ctx.file_idx),
1797 ) {
1798 DataType::Struct(id) => id,
1799 _ => error_unknown_struct(
1800 name,
1801 span,
1802 state.scope(ctx.file_idx),
1803 state.sources,
1804 ctx.file_idx,
1805 ),
1806 }
1807}
1808
1809#[must_use]
1812pub fn resolve_type_args(type_args: &[TypeExpr], ctx: Ctx, state: &mut State<'_>) -> Vec<DataType> {
1813 type_args
1814 .iter()
1815 .map(|t| t.to_datatype(&mut state.type_ctx(ctx.file_idx)))
1816 .collect()
1817}
1818
1819#[must_use]
1829pub fn type_args_name_a_variant(path: &[SmolStr], ctx: Ctx, state: &State<'_>) -> bool {
1830 let Some(base_idx) = path.len().checked_sub(2) else {
1831 return false;
1832 };
1833 let base = &path[base_idx];
1834 find_template(
1835 &path[..base_idx],
1836 base,
1837 state.scope(ctx.file_idx),
1838 state.generics,
1839 )
1840 .is_some()
1841 || state
1842 .scope(ctx.file_idx)
1843 .find_enum(&path[..base_idx], base)
1844 .is_some()
1845}
1846
1847pub fn variant_constructor_at(
1864 path: &[SmolStr],
1865 arg_types: &[DataType],
1866 span: Span,
1867 ctx: Ctx,
1868 state: &mut State<'_>,
1869) -> Option<(u16, u16)> {
1870 if let [variant] = path
1873 && state.generics.only_the_prelude_declares(variant)
1874 && let Some(own) = state.enums.iter().find_map(|e| {
1875 let idx = e.variants.iter().position(|vt| vt.name == *variant)?;
1876 state
1877 .generics
1878 .instantiation_of(&DataType::Enum(e.id))
1879 .is_none()
1880 .then_some((e.id, idx as u16))
1881 })
1882 {
1883 return Some(own);
1884 }
1885 resolve_variant_constructor(path, arg_types, span, ctx, state)
1886 .or_else(|| resolve_enum_variant(path, ctx.file_idx, state))
1887}
1888
1889pub fn resolve_variant_constructor(
1890 path: &[SmolStr],
1891 arg_types: &[DataType],
1892 span: Span,
1893 ctx: Ctx,
1894 state: &mut State<'_>,
1895) -> Option<(u16, u16)> {
1896 let variant = path.last()?.clone();
1897 let (namespace, template) = if path.len() >= 2 {
1898 let namespace = &path[..path.len() - 2];
1899 let base = &path[path.len() - 2];
1900 let template = find_template(namespace, base, state.scope(ctx.file_idx), state.generics)?;
1901 (namespace, template)
1902 } else {
1903 (
1904 &path[..0],
1905 state.generics.enum_template_with_variant(&variant)?,
1906 )
1907 };
1908 let params: Vec<SmolStr> = state.generics.params(template).to_vec();
1909 let payload: Vec<TypeExpr> = state.generics.variant_payload(template, &variant)?.to_vec();
1910 let mut bound: Vec<Option<DataType>> = vec![None; params.len()];
1911 for (declared, found) in payload.iter().zip(arg_types) {
1912 bind_params_from_payload(declared, found, ¶ms, &mut bound);
1913 }
1914 let args: Vec<DataType> = bound
1915 .into_iter()
1916 .map(|b| b.unwrap_or(DataType::Unknown))
1917 .collect();
1918 let base = state.generics.template_name(template).clone();
1919 let namespace: Box<[SmolStr]> = namespace.into();
1920 let DataType::Enum(enum_id) = instantiate(
1921 &namespace,
1922 &base,
1923 &args,
1924 span,
1925 &mut state.type_ctx(ctx.file_idx),
1926 ) else {
1927 return None;
1928 };
1929 let variant_idx = state.enums[enum_id as usize]
1930 .variants
1931 .iter()
1932 .position(|vt| vt.name == variant)? as u16;
1933 Some((enum_id, variant_idx))
1934}
1935
1936fn bind_params_from_payload(
1941 declared: &TypeExpr,
1942 found: &DataType,
1943 params: &[SmolStr],
1944 bound: &mut [Option<DataType>],
1945) {
1946 match declared {
1947 TypeExpr::Identifier(name, _) => {
1948 if *found != DataType::Unknown
1949 && let Some(i) = params.iter().position(|p| p == name)
1950 && bound[i].is_none()
1951 {
1952 bound[i] = Some(found.clone());
1953 }
1954 }
1955 TypeExpr::Array(inner) => {
1956 if let DataType::Array(Some(element)) = found {
1957 bind_params_from_payload(inner, element, params, bound);
1958 }
1959 }
1960 TypeExpr::Map(key, value) => {
1961 if let DataType::Map(entry) = found {
1962 if let Some(t) = &entry.0 {
1963 bind_params_from_payload(key, t, params, bound);
1964 }
1965 if let Some(t) = &entry.1 {
1966 bind_params_from_payload(value, t, params, bound);
1967 }
1968 }
1969 }
1970 _ => {}
1971 }
1972}
1973
1974pub fn resolve_generic_variant(
1977 path: &[SmolStr],
1978 type_args: &[TypeExpr],
1979 span: Span,
1980 ctx: Ctx,
1981 state: &mut State<'_>,
1982) -> (u16, u16) {
1983 let variant = path[path.len() - 1].clone();
1984 let base = path[path.len() - 2].clone();
1985 let namespace = &path[..path.len() - 2];
1986 let args = resolve_type_args(type_args, ctx, state);
1987 let DataType::Enum(enum_id) = instantiate(
1988 namespace,
1989 &base,
1990 &args,
1991 span,
1992 &mut state.type_ctx(ctx.file_idx),
1993 ) else {
1994 crate::compiler::compiler_errors::error_enum(
1995 "Unknown enum",
1996 &format!("{base} does not name an enum"),
1997 span,
1998 ctx.file_idx,
1999 state.sources,
2000 );
2001 };
2002 let Some(variant_idx) = state.enums[enum_id as usize]
2003 .variants
2004 .iter()
2005 .position(|vt| vt.name == variant)
2006 else {
2007 crate::compiler::compiler_errors::error_enum(
2008 "Unknown enum variant",
2009 &format!("{} does not name an enum variant", path.join("::")),
2010 span,
2011 ctx.file_idx,
2012 state.sources,
2013 );
2014 };
2015 (enum_id, variant_idx as u16)
2016}
2017
2018pub fn resolve_generic_call(
2025 namespace: &[SmolStr],
2026 fn_name: &SmolStr,
2027 type_args: &[TypeExpr],
2028 span: Span,
2029 ctx: Ctx,
2030 state: &mut State<'_>,
2031) -> (usize, Vec<DataType>) {
2032 let Some(fn_id) = state.scope(ctx.file_idx).find_function(namespace, fn_name) else {
2033 if !namespace.is_empty() {
2034 error_unknown_function_in_namespace(fn_name, namespace, span, ctx.file_idx, state);
2035 }
2036 error_unknown_function(
2037 fn_name,
2038 span,
2039 state.scope(ctx.file_idx),
2040 ctx.file_idx,
2041 state.sources,
2042 );
2043 };
2044 let args = resolve_call_type_args(fn_id, fn_name, type_args, span, ctx, state);
2045 (fn_id, args)
2046}
2047
2048pub fn resolve_call_type_args(
2054 fn_id: usize,
2055 name: &str,
2056 type_args: &[TypeExpr],
2057 span: Span,
2058 ctx: Ctx,
2059 state: &mut State<'_>,
2060) -> Vec<DataType> {
2061 let params_len = state.fns[fn_id]
2062 .generics
2063 .as_ref()
2064 .map_or(0, |g| g.params.len());
2065 if params_len == 0 {
2066 error_type_args_on_plain_function(span, ctx.file_idx, name, state.sources);
2067 }
2068 if params_len != type_args.len() {
2069 error_type_arg_count(
2070 span,
2071 ctx.file_idx,
2072 name,
2073 params_len,
2074 type_args.len(),
2075 state.sources,
2076 );
2077 }
2078 resolve_type_args(type_args, ctx, state)
2079}
2080
2081fn declared_return_type(namespace: &[SmolStr], state: &State<'_>) -> Option<DataType> {
2089 let fn_name = namespace.last()?;
2090 let block = &namespace[0];
2091 let declared = |is_host: bool| {
2092 state
2093 .dyn_libs
2094 .iter()
2095 .find(|lib| lib.is_host == is_host && lib.name == *block)
2096 .and_then(|lib| lib.fns.iter().find(|f| f.name == *fn_name))
2097 .map(|f| f.return_type.clone())
2098 };
2099 declared(true).or_else(|| declared(false))
2100}
2101
2102fn builtin_fn_return_type(name: &str, in_std: bool) -> Option<DataType> {
2112 if in_std && let Some(t) = std_primitive_return_type(name) {
2113 return Some(t);
2114 }
2115 Some(match name {
2116 "print" | "exit" | "throw" => DataType::Null,
2117 "type" | "string" | "input" => DataType::String,
2118 "float" => DataType::Float,
2119 "int" | "the_answer" => DataType::Int,
2120 "bool" | "[int text]" | "[float text]" => DataType::Bool,
2121 "range" => DataType::Array(Some(Box::from(DataType::Int))),
2122 "argv" => DataType::Array(Some(Box::from(DataType::String))),
2123 _ => return None,
2124 })
2125}
2126
2127#[must_use]
2134pub fn std_primitive_return_type(name: &str) -> Option<DataType> {
2135 Some(match name {
2136 "json_stringify" | "fs_read" => DataType::String,
2137 "json_parse" => DataType::Unknown,
2139 "fs_exists" => DataType::Bool,
2140 "fs_write" | "fs_append" | "fs_delete" | "fs_delete_dir" => DataType::Null,
2141 _ => return None,
2142 })
2143}
2144
2145#[must_use]
2156pub fn format_detailed(t: &DataType, state: &State<'_>) -> SmolStr {
2157 match t {
2158 DataType::Float => SmolStr::new_static("float"),
2159 DataType::Int => SmolStr::new_static("int"),
2160 DataType::Bool => SmolStr::new_static("bool"),
2161 DataType::String => SmolStr::new_static("string"),
2162 DataType::Array(array_type) => match array_type {
2163 Some(array_type) => {
2164 format_args!("{}[]", format_detailed(array_type, state)).to_smolstr()
2165 }
2166 None => SmolStr::new_static("any[]"),
2167 },
2168 DataType::Null => SmolStr::new_static("null"),
2169 DataType::Unknown => SmolStr::new_static("any"),
2170 DataType::FnValue(fn_type) => match &fn_type.sig {
2174 Some((params, returned)) => format_signature(params, returned, state),
2175 None => SmolStr::new_static("function"),
2176 },
2177 DataType::Union(types) => format_args!(
2178 "{}",
2179 types
2180 .into_iter()
2181 .map(|x| format_detailed(x, state))
2182 .collect::<Vec<SmolStr>>()
2183 .join("|")
2184 )
2185 .to_smolstr(),
2186 DataType::Struct(s) => state.structs[*s as usize].name.clone(),
2187 DataType::Enum(e) => state.enums[*e as usize].name.clone(),
2188 DataType::Map(m) => format_args!(
2193 "{{{}: {}}}",
2194 m.0.as_ref()
2195 .map_or_else(|| SmolStr::new_static("any"), |k| format_detailed(k, state)),
2196 m.1.as_ref().map_or_else(
2197 || SmolStr::new_static("any"),
2198 |val| format_detailed(val, state)
2199 )
2200 )
2201 .to_smolstr(),
2202 DataType::Fn(id) => {
2207 let f = &state.fns[*id as usize];
2208 let params: Box<[DataType]> = f
2209 .args
2210 .iter()
2211 .map(|(_, declared)| declared.clone().unwrap_or(DataType::Unknown))
2212 .collect();
2213 let returned = match &f.return_type {
2214 Some((declared, _)) => declared.clone(),
2215 None if f.returns_null => DataType::Null,
2216 None => DataType::Unknown,
2217 };
2218 format_signature(¶ms, &returned, state)
2219 }
2220 }
2221}
2222
2223fn format_signature(params: &[DataType], returned: &DataType, state: &State<'_>) -> SmolStr {
2226 let params = params
2227 .iter()
2228 .map(|param| format_detailed(param, state))
2229 .collect::<Vec<SmolStr>>()
2230 .join(", ");
2231 if matches!(returned, DataType::Null) {
2232 format_args!("fn({params})").to_smolstr()
2233 } else {
2234 format_args!("fn({params}) -> {}", format_detailed(returned, state)).to_smolstr()
2235 }
2236}
2237
2238#[inline(always)]
2253#[must_use]
2254pub fn struct_field_type_matches(
2255 expected: &DataType,
2256 received: &DataType,
2257 generics: &Generics,
2258) -> bool {
2259 if *received == DataType::Unknown {
2260 return *expected == DataType::Unknown;
2261 }
2262 received == &DataType::Null || param_type_matches(expected, received, generics)
2263}
2264
2265#[inline(always)]
2280#[must_use]
2281pub fn param_type_matches(expected: &DataType, received: &DataType, generics: &Generics) -> bool {
2282 *expected == DataType::Unknown
2283 || *received == DataType::Unknown
2284 || expected == received
2285 || instantiations_line_up(expected, received, generics)
2286}
2287
2288#[must_use]
2300pub fn return_type_fits(declared: &DataType, body: &DataType, generics: &Generics) -> bool {
2301 if param_type_matches(declared, body, generics) {
2302 return true;
2303 }
2304 match (declared, body) {
2305 (_, DataType::Union(members)) => members
2306 .iter()
2307 .all(|member| return_type_fits(declared, member, generics)),
2308 (DataType::Union(members), _) => members
2309 .iter()
2310 .any(|member| return_type_fits(member, body, generics)),
2311 (DataType::Array(Some(declared)), DataType::Array(Some(body))) => {
2312 return_type_fits(declared, body, generics)
2313 }
2314 (DataType::Map(declared), DataType::Map(body)) => {
2315 slot_fits(declared.0.as_ref(), body.0.as_ref(), generics)
2316 && slot_fits(declared.1.as_ref(), body.1.as_ref(), generics)
2317 }
2318 _ => false,
2319 }
2320}
2321
2322#[must_use]
2332pub fn let_type_fits(
2333 declared: &DataType,
2334 value: &DataType,
2335 fresh: bool,
2336 generics: &Generics,
2337) -> bool {
2338 match value {
2339 DataType::Unknown => matches!(declared, DataType::Unknown),
2340 DataType::Union(members) => members
2341 .iter()
2342 .all(|member| let_type_fits(declared, member, fresh, generics)),
2343 _ if fresh => return_type_fits(declared, value, generics),
2344 _ => param_type_matches(declared, value, generics),
2345 }
2346}
2347
2348fn slot_fits(declared: Option<&DataType>, body: Option<&DataType>, generics: &Generics) -> bool {
2351 match (declared, body) {
2352 (Some(declared), Some(body)) => return_type_fits(declared, body, generics),
2353 _ => true,
2354 }
2355}
2356
2357#[must_use]
2360pub(crate) fn instantiations_line_up(a: &DataType, b: &DataType, generics: &Generics) -> bool {
2361 let (Some((ta, args_a)), Some((tb, args_b))) =
2362 (generics.instantiation_of(a), generics.instantiation_of(b))
2363 else {
2364 return false;
2365 };
2366 ta == tb
2367 && args_a.len() == args_b.len()
2368 && args_a
2369 .iter()
2370 .zip(args_b)
2371 .all(|(x, y)| param_type_matches(x, y, generics))
2372}
2373
2374fn pin_open_element_types(inferred: &mut DataType, declared: &DataType) {
2387 match (inferred, declared) {
2388 (DataType::Array(element), DataType::Array(Some(declared_element))) => match element {
2389 None => *element = Some(declared_element.clone()),
2390 Some(element) => pin_open_element_types(element, declared_element),
2391 },
2392 (DataType::Map(entry), DataType::Map(declared_entry)) => {
2393 pin_open_slot(&mut entry.0, declared_entry.0.as_ref());
2394 pin_open_slot(&mut entry.1, declared_entry.1.as_ref());
2395 }
2396 _ => {}
2397 }
2398}
2399
2400pub(crate) fn pin_empty_literal_bindings(
2415 args: &[Expr],
2416 declared_arg_types: &[Option<DataType>],
2417 v: &mut [Variable],
2418) {
2419 for (arg, declared) in args.iter().zip(declared_arg_types) {
2420 let (Expr::Var(name, _), Some(declared)) = (arg, declared) else {
2421 continue;
2422 };
2423 let Some(var) = v.iter_mut().rfind(|var| &var.name == name) else {
2424 continue;
2425 };
2426 if is_empty_literal_type(&var.var_type) {
2427 pin_open_element_types(&mut var.var_type, declared);
2428 }
2429 }
2430}
2431
2432pub(crate) fn pin_pushed_element(obj: &Expr, element: &DataType, v: &mut [Variable]) {
2438 let Expr::Var(var_name, _) = obj else {
2439 return;
2440 };
2441 if let Some(var) = v.iter_mut().rfind(|var| &var.name == var_name)
2442 && matches!(var.var_type, DataType::Array(None))
2443 {
2444 var.var_type = DataType::Array(Some(Box::new(element.clone())));
2445 }
2446}
2447
2448pub(crate) fn pin_inserted_entry(obj: &Expr, key: &DataType, value: &DataType, v: &mut [Variable]) {
2455 let Expr::Var(var_name, _) = obj else {
2456 return;
2457 };
2458 if let Some(var) = v.iter_mut().rfind(|var| &var.name == var_name)
2459 && matches!(&var.var_type, DataType::Map(m) if m.0.is_none() && m.1.is_none())
2460 {
2461 var.var_type = DataType::Map(Box::from((Some(key.clone()), Some(value.clone()))));
2462 }
2463}
2464
2465#[must_use]
2470fn is_empty_literal_type(ty: &DataType) -> bool {
2471 match ty {
2472 DataType::Array(element) => element.is_none(),
2473 DataType::Map(entry) => entry.0.is_none() && entry.1.is_none(),
2474 _ => false,
2475 }
2476}
2477
2478fn pin_open_slot(inferred: &mut Option<DataType>, declared: Option<&DataType>) {
2483 let Some(declared) = declared else {
2484 return;
2485 };
2486 match inferred {
2487 None => *inferred = Some(declared.clone()),
2488 Some(inferred) => pin_open_element_types(inferred, declared),
2489 }
2490}
2491
2492#[must_use]
2500pub fn arg_types_specialize_equal(a: &[DataType], b: &[DataType]) -> bool {
2501 a.len() == b.len()
2502 && a.iter().zip(b).all(|(x, y)| match (x, y) {
2503 (DataType::Fn(i), DataType::Fn(j)) => i == j,
2504 (DataType::Fn(_), _) | (_, DataType::Fn(_)) => false,
2505 _ => x == y,
2506 })
2507}
2508
2509pub fn collect_direct_fn_calls(
2527 content: &[Expr],
2528 self_type: Option<&str>,
2529 calls: &mut Vec<SmolStr>,
2530) {
2531 let mut expr_stack: Vec<&Expr> = content.iter().collect();
2532 while let Some(expression) = expr_stack.pop() {
2533 if let Some(type_name) = self_type
2536 && let Some(method) = self_operator_method(expression)
2537 {
2538 calls.push(mangle_method(type_name, method));
2539 }
2540 match expression {
2541 Expr::FunctionCall(args, namespace, _, _, _) => {
2542 let (name, path) = namespace.split_last().unwrap();
2543 if let Some(type_name) = path.last() {
2547 match self_type {
2548 Some(self_type) if impl_base_name(self_type) == type_name.as_str() => {
2549 calls.push(mangle_method(self_type, name));
2550 }
2551 _ => calls.push(mangle_method(type_name, name)),
2552 }
2553 }
2554 calls.push(name.clone());
2555 expr_stack.extend(args.iter());
2556 }
2557 Expr::Condition(x, y, _, _)
2558 | Expr::InlineCondition(x, y, _, _)
2559 | Expr::ElseIfBlock(x, y, _)
2560 | Expr::WhileBlock(x, y, _) => {
2561 expr_stack.push(x);
2562 expr_stack.extend(y.iter());
2563 }
2564 Expr::ObjFunctionCall(obj, args, namespace, _, _, _, _) => {
2565 if let Some(type_name) = self_type
2566 && matches!(&**obj, Expr::Var(name, _) if name == "self")
2567 && let Some(method) = namespace.last()
2568 {
2569 calls.push(mangle_method(type_name, method));
2570 }
2571 expr_stack.push(obj);
2572 expr_stack.extend(args.iter());
2573 }
2574 Expr::CallValue(callee, args, _, _) => {
2575 expr_stack.push(callee);
2576 expr_stack.extend(args.iter());
2577 }
2578 Expr::ElseBlock(x) | Expr::EvalBlock(x) | Expr::LoopBlock(x) => {
2579 expr_stack.extend(x.iter());
2580 }
2581 Expr::ReturnVal(code) => {
2582 if let Some(code) = code.as_ref() {
2583 expr_stack.push(code);
2584 }
2585 }
2586 Expr::FunctionDecl(_, _, x, _, _, _) => expr_stack.extend(x.iter()),
2587 Expr::ArrayGetSlice(x, y, z, _) => {
2588 expr_stack.push(x);
2589 expr_stack.push(y);
2590 if let Some(z) = z {
2591 expr_stack.push(z);
2592 }
2593 }
2594 Expr::VarDeclare(_, x, _)
2595 | Expr::VarAssign(_, x, _, _)
2596 | Expr::Propagate(x, _)
2597 | Expr::Is(x, _, _, _)
2598 | Expr::Cast(x, _, _, _)
2599 | Expr::Neg(x, _, _)
2600 | Expr::BitNot(x, _, _)
2601 | Expr::BoolNeg(x, _, _) => expr_stack.push(x),
2602 Expr::ForLoop(_, _, code, _) => expr_stack.extend(code.iter()),
2603 Expr::IntForLoop(_, start, end, code, _, _) => {
2604 expr_stack.push(start);
2605 expr_stack.push(end);
2606 expr_stack.extend(code.iter());
2607 }
2608 Expr::ArrayModify(array, index, value, _, _) => {
2609 expr_stack.push(array);
2610 expr_stack.push(index);
2611 expr_stack.push(value);
2612 }
2613 Expr::Array(elems, _) => expr_stack.extend(elems.iter()),
2614 Expr::Struct(_, fields, _, _, base) => {
2615 expr_stack.extend(fields.iter().map(|(_, expr, _, _)| expr));
2616 if let Some(base) = base.as_ref().and_then(|b| b.0.base()) {
2617 expr_stack.push(base);
2618 }
2619 }
2620 Expr::GetStructField(expr, _, _, _) => expr_stack.push(expr),
2621 Expr::SetStructField(expr, _, value, _, _, _) => {
2622 expr_stack.push(expr);
2623 expr_stack.push(value);
2624 }
2625 Expr::TryCatchBlock(try_code, _, catch_code) => {
2626 expr_stack.extend(try_code.iter());
2627 expr_stack.extend(catch_code.iter());
2628 }
2629 Expr::Match(scrutinee, arms, wildcard, _, _) => {
2630 expr_stack.push(scrutinee);
2631 for (patterns, body) in arms {
2632 expr_stack.extend(patterns.iter());
2633 expr_stack.extend(body.iter());
2634 }
2635 if let Some(w) = wildcard {
2636 expr_stack.extend(w.iter());
2637 }
2638 }
2639 Expr::ArrayGetIndex(x, y, _)
2640 | Expr::Mul(x, y, _, _)
2641 | Expr::Div(x, y, _, _)
2642 | Expr::Add(x, y, _, _)
2643 | Expr::Sub(x, y, _, _)
2644 | Expr::Mod(x, y, _, _)
2645 | Expr::Pow(x, y, _, _)
2646 | Expr::BitAnd(x, y, _, _)
2647 | Expr::BitOr(x, y, _, _)
2648 | Expr::BitXor(x, y, _, _)
2649 | Expr::Shl(x, y, _, _)
2650 | Expr::Shr(x, y, _, _)
2651 | Expr::Eq(x, y, _, _)
2652 | Expr::NotEq(x, y, _, _)
2653 | Expr::Sup(x, y, _, _)
2654 | Expr::SupEq(x, y, _, _)
2655 | Expr::Inf(x, y, _, _)
2656 | Expr::InfEq(x, y, _, _)
2657 | Expr::BoolAnd(x, y, _, _)
2658 | Expr::BoolOr(x, y, _, _) => {
2659 expr_stack.push(x);
2660 expr_stack.push(y);
2661 }
2662 _ => {}
2663 }
2664 }
2665}
2666
2667pub fn can_reach<S: std::hash::BuildHasher>(
2669 src_fn: &str,
2670 target_fn: &str,
2671 fns: &[Function],
2672 visited: &mut std::collections::HashSet<SmolStr, S>,
2673) -> bool {
2674 if let Some(from_fn) = fns.iter().find(|f| f.name.as_str() == src_fn) {
2675 for callee in &from_fn.direct_calls {
2676 if callee == target_fn {
2677 return true;
2678 }
2679 if visited.insert(callee.clone()) && can_reach(callee, target_fn, fns, visited) {
2680 return true;
2681 }
2682 }
2683 }
2684 false
2685}
2686
2687#[derive(Default)]
2689struct ReturnShapes {
2690 value: bool,
2692 bare: bool,
2694}
2695
2696fn collect_return_shapes(content: &[Expr], shapes: &mut ReturnShapes) {
2697 for content in content {
2698 match content {
2699 Expr::ElseIfBlock(_, code, _)
2700 | Expr::ElseBlock(code)
2701 | Expr::Condition(_, code, _, _)
2702 | Expr::InlineCondition(_, code, _, _)
2703 | Expr::WhileBlock(_, code, _)
2704 | Expr::ForLoop(_, _, code, _)
2705 | Expr::EvalBlock(code)
2706 | Expr::LoopBlock(code)
2707 | Expr::IntForLoop(_, _, _, code, _, _) => collect_return_shapes(code, shapes),
2708 Expr::TryCatchBlock(try_code, _, catch_code) => {
2709 collect_return_shapes(try_code, shapes);
2710 collect_return_shapes(catch_code, shapes);
2711 }
2712 Expr::Match(_, arms, wildcard, _, _) => {
2713 for (_, body) in arms {
2714 collect_return_shapes(body, shapes);
2715 }
2716 if let Some(w) = wildcard {
2717 collect_return_shapes(w, shapes);
2718 }
2719 }
2720 Expr::ReturnVal(value) => {
2721 if value.is_some() {
2722 shapes.value = true;
2723 } else {
2724 shapes.bare = true;
2725 }
2726 }
2727 _ => {}
2728 }
2729 }
2730}
2731
2732#[must_use]
2733pub fn check_if_returns_void(content: &[Expr]) -> bool {
2734 let mut shapes = ReturnShapes::default();
2735 collect_return_shapes(content, &mut shapes);
2736 !shapes.value
2737}
2738
2739macro_rules! extend_return_types {
2740 ($return_types: expr, $new_types: expr, $ctx: expr, $state: expr) => {
2741 for return_type in $new_types {
2742 add_return_type($return_types, return_type, $ctx, $state);
2743 }
2744 };
2745}
2746
2747fn add_return_type(
2756 return_types: &mut Vec<DataType>,
2757 return_type: DataType,
2758 ctx: Ctx,
2759 state: &mut State<'_>,
2760) {
2761 if return_type == DataType::Unknown {
2762 return;
2763 }
2764 if matches!(return_type, DataType::Fn(_) | DataType::FnValue(_))
2769 && let Some(i) = return_types
2770 .iter()
2771 .position(|held| matches!(held, DataType::Fn(_) | DataType::FnValue(_)))
2772 {
2773 if let Some(merged) = merge_fn_types(&[return_types[i].clone(), return_type]) {
2774 return_types[i] = merged;
2775 }
2776 return;
2777 }
2778 if return_types.contains(&return_type) {
2779 return;
2780 }
2781 let mut replacement = None;
2782 for (i, existing) in return_types.iter().enumerate() {
2783 if let Some(merged) = merge_instantiations(existing, &return_type, ctx, state) {
2784 replacement = Some((i, merged));
2785 break;
2786 }
2787 }
2788 if let Some((i, merged)) = replacement {
2789 return_types[i] = merged;
2790 return;
2791 }
2792 return_types.push(return_type);
2793}
2794
2795#[must_use]
2802pub fn propagation_sides(t: &DataType, state: &State<'_>) -> Option<(DataType, u16)> {
2803 let DataType::Enum(enum_id) = t else {
2804 return None;
2805 };
2806 let variants = &state.enums[*enum_id as usize].variants;
2807 let [first, second] = &**variants else {
2808 return None;
2809 };
2810 let (success, failure, failure_idx) = match (first.name.as_str(), second.name.as_str()) {
2811 ("Some", "None") | ("Ok", "Err") => (first, second, 1),
2812 ("None", "Some") | ("Err", "Ok") => (second, first, 0),
2813 _ => return None,
2814 };
2815 let failure_arity = usize::from(failure.name == "Err");
2816 if success.payload.len() != 1 || failure.payload.len() != failure_arity {
2817 return None;
2818 }
2819 Some((success.payload[0].clone(), failure_idx))
2820}
2821
2822fn propagated_failure_type(operand: &DataType, state: &mut State<'_>) -> Option<DataType> {
2827 let (template, args) = state.generics.instantiation_of(operand)?;
2828 let mut args: Vec<DataType> = args.to_vec();
2829 *args.first_mut()? = DataType::Unknown;
2832 let base = state.generics.template_name(template).clone();
2833 let file_idx = state.generics.template_file(template);
2834 Some(instantiate(
2835 &[],
2836 &base,
2837 &args,
2838 (0u32, 0u32).into(),
2839 &mut state.type_ctx(file_idx),
2840 ))
2841}
2842
2843fn merge_instantiations(
2848 a: &DataType,
2849 b: &DataType,
2850 ctx: Ctx,
2851 state: &mut State<'_>,
2852) -> Option<DataType> {
2853 let (template, args_a) = state.generics.instantiation_of(a)?;
2854 let args_a: Vec<DataType> = args_a.to_vec();
2855 let (template_b, args_b) = state.generics.instantiation_of(b)?;
2856 if template != template_b || args_a.len() != args_b.len() {
2857 return None;
2858 }
2859 let mut merged = Vec::with_capacity(args_a.len());
2860 for (x, y) in args_a.iter().zip(args_b) {
2861 merged.push(match (x, y) {
2862 (DataType::Unknown, other) | (other, DataType::Unknown) => other.clone(),
2863 (x, y) if x == y => x.clone(),
2864 _ => return None,
2865 });
2866 }
2867 let base = state.generics.template_name(template).clone();
2868 Some(instantiate(
2869 &[],
2870 &base,
2871 &merged,
2872 (0u32, 0u32).into(),
2873 &mut state.type_ctx(ctx.file_idx),
2874 ))
2875}
2876
2877pub fn track_returns(
2885 content: &[Expr],
2886 v: &mut Vec<Variable>,
2887 ctx: Ctx,
2888 state: &mut State<'_>,
2889 fn_name: &str,
2890 fn_id: usize,
2891) -> Vec<DataType> {
2892 state.propagations.push(Vec::new());
2895 let mut flow = track_return_flow(content, v, ctx, state, fn_name);
2896 let propagated = state.propagations.pop().unwrap_or_default();
2897 let declared = state.fns[fn_id].return_type.is_some()
2900 || state.fns[fn_id]
2901 .generics
2902 .as_ref()
2903 .is_some_and(|g| g.return_type.is_some());
2904 for operand in propagated.into_iter().filter(|_| !declared) {
2905 if let Some(failure) = propagated_failure_type(&operand, state) {
2906 add_return_type(&mut flow.types, failure, ctx, state);
2907 }
2908 }
2909 let mut shapes = ReturnShapes::default();
2910 collect_return_shapes(content, &mut shapes);
2911 if shapes.value && (shapes.bare || !flow.always_returns) {
2912 let func = &state.fns[fn_id];
2915 let declared = (!func.name.starts_with(ANON_FN_PREFIX)).then_some(func.name.as_str());
2916 error_missing_return(declared, func.name_span, ctx.file_idx, state.sources);
2917 }
2918 flow.types
2919}
2920
2921struct FnReturnFlow {
2922 types: Vec<DataType>,
2923 always_returns: bool,
2924}
2925
2926fn track_scoped_returns(
2927 code: &[Expr],
2928 v: &mut Vec<Variable>,
2929 ctx: Ctx,
2930 state: &mut State<'_>,
2931 fn_name: &str,
2932) -> FnReturnFlow {
2933 let v_len = v.len();
2934 let flow = track_return_flow(code, v, ctx, state, fn_name);
2935 v.truncate(v_len);
2936 flow
2937}
2938
2939fn track_condition_returns(
2940 condition: &Expr,
2941 code: &[Expr],
2942 v: &mut Vec<Variable>,
2943 ctx: Ctx,
2944 state: &mut State<'_>,
2945 fn_name: &str,
2946) -> FnReturnFlow {
2947 let mut return_types = Vec::new();
2948 let first_branch_end = code
2949 .iter()
2950 .position(|expr| matches!(expr, Expr::ElseIfBlock(_, _, _) | Expr::ElseBlock(_)))
2951 .unwrap_or(code.len());
2952
2953 let v_len = v.len();
2955 crate::compiler::type_test::declare_condition_facts(condition, v, ctx, state);
2956 let first_flow = track_scoped_returns(&code[..first_branch_end], v, ctx, state, fn_name);
2957 v.truncate(v_len);
2958 let mut all_branches_return = first_flow.always_returns;
2959 let mut has_else = false;
2960 extend_return_types!(&mut return_types, first_flow.types, ctx, state);
2961
2962 for expr in &code[first_branch_end..] {
2963 match expr {
2964 Expr::ElseIfBlock(condition, branch_code, _) => {
2965 crate::compiler::type_test::declare_condition_facts(condition, v, ctx, state);
2966 let flow = track_scoped_returns(branch_code, v, ctx, state, fn_name);
2967 v.truncate(v_len);
2968 all_branches_return &= flow.always_returns;
2969 extend_return_types!(&mut return_types, flow.types, ctx, state);
2970 }
2971 Expr::ElseBlock(branch_code) => {
2972 has_else = true;
2973 let flow = track_scoped_returns(branch_code, v, ctx, state, fn_name);
2974 all_branches_return &= flow.always_returns;
2975 extend_return_types!(&mut return_types, flow.types, ctx, state);
2976 }
2977 _ => {}
2978 }
2979 }
2980
2981 FnReturnFlow {
2982 types: return_types,
2983 always_returns: has_else && all_branches_return,
2984 }
2985}
2986
2987fn track_return_flow(
2988 content: &[Expr],
2989 v: &mut Vec<Variable>,
2990 ctx: Ctx,
2991 state: &mut State<'_>,
2992 fn_name: &str,
2993) -> FnReturnFlow {
2994 let mut return_types: Vec<DataType> = Vec::new();
2995 let mut threw = false;
2996 for expr in content {
2997 match expr {
2998 Expr::Condition(condition, code, _, _)
2999 | Expr::InlineCondition(condition, code, _, _) => {
3000 let flow = track_condition_returns(condition, code, v, ctx, state, fn_name);
3001 extend_return_types!(&mut return_types, flow.types, ctx, state);
3002 if flow.always_returns {
3003 return FnReturnFlow {
3004 types: return_types,
3005 always_returns: true,
3006 };
3007 }
3008 }
3009 Expr::ElseIfBlock(_, code, _) | Expr::ElseBlock(code) | Expr::EvalBlock(code) => {
3010 let flow = track_scoped_returns(code, v, ctx, state, fn_name);
3011 extend_return_types!(&mut return_types, flow.types, ctx, state);
3012 if flow.always_returns {
3013 return FnReturnFlow {
3014 types: return_types,
3015 always_returns: true,
3016 };
3017 }
3018 }
3019 Expr::LoopBlock(code) => {
3024 let flow = track_scoped_returns(code, v, ctx, state, fn_name);
3025 extend_return_types!(&mut return_types, flow.types, ctx, state);
3026 if !block_breaks(code) {
3027 return FnReturnFlow {
3028 types: return_types,
3029 always_returns: true,
3030 };
3031 }
3032 }
3033 Expr::VarDeclare(name, expr, annotation) => {
3034 let declared = annotation
3035 .as_ref()
3036 .map(|a| a.ty.to_datatype(&mut state.type_ctx(ctx.file_idx)));
3037 let var_type = match &declared {
3038 Some(declared) => declared.clone(),
3039 None => expr.infer_type(v, ctx, state),
3040 };
3041 v.push(Variable {
3042 declared,
3043 name: name.clone(),
3044 register_id: 0,
3045 cell: false,
3046 var_type,
3047 });
3048 }
3049 Expr::VarAssign(name, expr, _, _) => {
3050 if v.iter()
3051 .rfind(|var| &var.name == name)
3052 .is_some_and(|var| var.declared.is_none())
3053 {
3054 let var_type = expr.infer_type(v, ctx, state);
3055 if let Some(var) = v.iter_mut().rfind(|var| &var.name == name) {
3056 var.var_type = var_type;
3057 }
3058 }
3059 }
3060 Expr::WhileBlock(condition, code, _) => {
3063 let v_len = v.len();
3064 crate::compiler::type_test::declare_condition_facts(condition, v, ctx, state);
3065 let flow = track_scoped_returns(code, v, ctx, state, fn_name);
3066 v.truncate(v_len);
3067 extend_return_types!(&mut return_types, flow.types, ctx, state);
3068 if matches!(**condition, Expr::Bool(true)) && !block_breaks(code) {
3069 return FnReturnFlow {
3070 types: return_types,
3071 always_returns: true,
3072 };
3073 }
3074 }
3075 Expr::IntForLoop(var_name, _, _, code, _, _) => {
3076 let v_len = v.len();
3077 v.push(Variable {
3078 declared: None,
3079 name: var_name.clone(),
3080 register_id: 0,
3081 cell: false,
3082 var_type: DataType::Int,
3083 });
3084 let flow = track_return_flow(code, v, ctx, state, fn_name);
3085 extend_return_types!(&mut return_types, flow.types, ctx, state);
3086 v.truncate(v_len);
3087 }
3088 Expr::ForLoop(var_name, array_expr, array_code, span) => {
3089 let inferred_collection_type = array_expr.infer_type(v, ctx, state);
3090 let elem_type = match inferred_collection_type {
3091 DataType::Array(inner) => inner.map_or(DataType::Unknown, |t| *t),
3092 DataType::String => DataType::String,
3093 DataType::Unknown => DataType::Unknown,
3094 DataType::Map(m) => m.0.unwrap_or(DataType::Unknown),
3096 t => error_type_not_indexable(
3101 &t,
3102 *span,
3103 true,
3104 ctx.file_idx,
3105 state.sources,
3106 state.type_names(),
3107 ),
3108 };
3109 let v_len = v.len();
3110 if var_name.as_str() != "_" {
3111 v.push(Variable {
3112 declared: None,
3113 name: var_name.clone(),
3114 register_id: 0,
3115 cell: false,
3116 var_type: elem_type,
3117 });
3118 }
3119 let flow = track_return_flow(array_code, v, ctx, state, fn_name);
3120 extend_return_types!(&mut return_types, flow.types, ctx, state);
3121 v.truncate(v_len);
3122 }
3123 Expr::ObjFunctionCall(obj, args, namespace, _, _, _, _)
3129 if namespace.last().unwrap().as_str() == "push" && args.len() == 1 =>
3130 {
3131 let element = args[0].infer_type(v, ctx, state);
3132 pin_pushed_element(obj, &element, v);
3133 }
3134 Expr::ArrayModify(obj, key, value, _, _)
3135 if matches!(obj.infer_type(v, ctx, state), DataType::Map(_)) =>
3136 {
3137 let key = key.infer_type(v, ctx, state);
3138 let value = value.infer_type(v, ctx, state);
3139 pin_inserted_entry(obj, &key, &value, v);
3140 }
3141 Expr::FunctionCall(_, namespace, _, _, _)
3148 if namespace.len() == 1 && matches!(namespace[0].as_str(), "throw" | "exit") =>
3149 {
3150 threw = true;
3151 }
3152 Expr::FunctionCall(args, namespace, _, _, type_args) if type_args.is_empty() => {
3153 let (fn_name, path) = namespace.split_last().unwrap();
3154 if let Some(fn_id) = state.scope(ctx.file_idx).find_function(path, fn_name) {
3155 let declared = specialized_arg_types(fn_id, &[], ctx, state);
3156 pin_empty_literal_bindings(args, &declared, v);
3157 }
3158 }
3159 Expr::Match(scrutinee, arms, wildcard, span, _) => {
3160 let scrut_type = scrutinee.infer_type(v, ctx, state);
3161 let is_enum = matches!(scrut_type, DataType::Enum(_));
3162 if !is_enum {
3163 crate::compiler::check_match_scrutinee_is_enum(
3164 &scrut_type,
3165 arms,
3166 *span,
3167 v,
3168 ctx,
3169 state,
3170 );
3171 }
3172 let mut all_return = true;
3173 for (patterns, body) in arms {
3174 let v_len = v.len();
3175 if let DataType::Enum(enum_id) = scrut_type {
3176 crate::compiler::declare_arm_bindings(
3177 enum_id, patterns, *span, v, ctx, state,
3178 );
3179 }
3180 let flow = track_return_flow(body, v, ctx, state, fn_name);
3181 v.truncate(v_len);
3182 all_return &= flow.always_returns;
3183 extend_return_types!(&mut return_types, flow.types, ctx, state);
3184 }
3185 let exhaustive = if wildcard.is_some() {
3186 if let Some(w) = wildcard {
3187 let flow = track_scoped_returns(w, v, ctx, state, fn_name);
3188 all_return &= flow.always_returns;
3189 extend_return_types!(&mut return_types, flow.types, ctx, state);
3190 }
3191 true
3192 } else {
3193 is_enum
3195 };
3196 if exhaustive && all_return {
3197 return FnReturnFlow {
3198 types: return_types,
3199 always_returns: true,
3200 };
3201 }
3202 }
3203 Expr::TryCatchBlock(try_code, err_var, catch_code) => {
3207 let try_flow = track_scoped_returns(try_code, v, ctx, state, fn_name);
3208 extend_return_types!(&mut return_types, try_flow.types, ctx, state);
3209 let v_len = v.len();
3210 v.push(Variable {
3211 declared: None,
3212 name: err_var.clone(),
3213 register_id: 0,
3214 cell: false,
3215 var_type: DataType::String,
3216 });
3217 let catch_flow = track_return_flow(catch_code, v, ctx, state, fn_name);
3218 v.truncate(v_len);
3219 extend_return_types!(&mut return_types, catch_flow.types, ctx, state);
3220 if try_flow.always_returns && catch_flow.always_returns {
3221 return FnReturnFlow {
3222 types: return_types,
3223 always_returns: true,
3224 };
3225 }
3226 }
3227 Expr::ReturnVal(return_val) => {
3228 if let Some(val) = return_val.as_ref() {
3229 let infered = val.infer_type(v, ctx, state);
3230 let infered = if matches!(infered, DataType::Fn(_)) {
3234 bare_fn_value_type(val, v, ctx, state).unwrap_or(infered)
3235 } else {
3236 infered
3237 };
3238 add_return_type(&mut return_types, infered, ctx, state);
3239 } else {
3240 add_return_type(&mut return_types, DataType::Null, ctx, state);
3241 }
3242 return FnReturnFlow {
3243 types: return_types,
3244 always_returns: true,
3245 };
3246 }
3247 _ => {}
3248 }
3249 }
3250 FnReturnFlow {
3251 types: return_types,
3252 always_returns: threw,
3253 }
3254}
3255
3256fn block_breaks(code: &[Expr]) -> bool {
3260 code.iter().any(|expr| match expr {
3261 Expr::Break => true,
3262 Expr::Condition(_, body, _, _)
3263 | Expr::InlineCondition(_, body, _, _)
3264 | Expr::ElseIfBlock(_, body, _)
3265 | Expr::ElseBlock(body)
3266 | Expr::EvalBlock(body) => block_breaks(body),
3267 Expr::TryCatchBlock(try_code, _, catch_code) => {
3268 block_breaks(try_code) || block_breaks(catch_code)
3269 }
3270 Expr::Match(_, arms, wildcard, _, _) => {
3271 arms.iter().any(|(_, body)| block_breaks(body))
3272 || wildcard.as_ref().is_some_and(|w| block_breaks(w))
3273 }
3274 _ => false,
3275 })
3276}
3277
3278pub fn push_capture_scope(
3293 v: &mut Vec<Variable>,
3294 captures: &[(SmolStr, DataType, Option<DataType>)],
3295) {
3296 for (name, capture_type, declared) in captures {
3297 v.push(Variable {
3298 declared: declared.clone(),
3299 name: name.clone(),
3300 register_id: 0,
3301 cell: true,
3302 var_type: capture_type.clone(),
3303 });
3304 }
3305}
3306
3307pub fn infer_user_fn_return_type(
3308 fn_id: usize,
3309 infered_arg_types: &[DataType],
3310 type_args: &[DataType],
3311 function_name: &str,
3312 v: &mut Vec<Variable>,
3313 ctx: Ctx,
3314 state: &mut State<'_>,
3315) -> DataType {
3316 let pinned = if infered_arg_types.iter().any(has_open_element_type) {
3322 let declared_arg_types = specialized_arg_types(fn_id, type_args, ctx, state);
3323 pinned_arg_types(infered_arg_types, &declared_arg_types)
3324 } else {
3325 None
3326 };
3327 let infered_arg_types = pinned.as_deref().unwrap_or(infered_arg_types);
3328
3329 let key = specialization_key(type_args, infered_arg_types);
3330 if let Some((_, ret)) = state.fns[fn_id]
3332 .return_type_cache
3333 .iter()
3334 .find(|(args, _)| arg_types_specialize_equal(args, &key))
3335 {
3336 return ret.clone();
3337 }
3338
3339 let fn_ctx = Ctx {
3340 file_idx: state.fns[fn_id].src_file,
3341 ..ctx
3342 };
3343 state
3348 .generics
3349 .push_frame(fn_bindings(fn_id, type_args, state));
3350 let declared_return = specialized_return_type(fn_id, fn_ctx, state).map(|(t, _)| t);
3351 state.generics.pop_bindings();
3352
3353 let already_inferring = RETURN_TYPE_INFERRING.with(|s| s.borrow().contains(&fn_id));
3357 if already_inferring {
3358 return declared_return.unwrap_or(DataType::Unknown);
3359 }
3360 if infered_arg_types.len() != state.fns[fn_id].args.len() {
3365 return declared_return.unwrap_or(DataType::Unknown);
3366 }
3367
3368 let func = &state.fns[fn_id];
3369 let fn_args = func.args.clone();
3370 let fn_code = func.code.clone();
3371 let fn_captures = func.captures.clone();
3372 let v_len_before_args = v.len();
3373 push_capture_scope(v, &fn_captures);
3374 for (i, infered_type) in infered_arg_types.iter().cloned().enumerate() {
3375 v.push(Variable {
3377 declared: None,
3378 name: fn_args[i].0.clone(),
3379 register_id: 0,
3380 cell: false,
3381 var_type: infered_type,
3382 });
3383 }
3384
3385 RETURN_TYPE_INFERRING.with(|s| s.borrow_mut().insert(fn_id));
3386
3387 state
3390 .generics
3391 .push_frame(fn_bindings(fn_id, type_args, state));
3392 let fn_type = track_returns(&fn_code, v, fn_ctx, state, function_name, fn_id);
3393 state.generics.pop_bindings();
3394
3395 RETURN_TYPE_INFERRING.with(|s| s.borrow_mut().remove(&fn_id));
3396
3397 v.truncate(v_len_before_args);
3398
3399 let body_type = if fn_type.is_empty() {
3400 if check_if_returns_void(&fn_code) {
3405 DataType::Null
3406 } else {
3407 DataType::Unknown
3408 }
3409 } else {
3410 DataType::Union(Box::from(fn_type)).check_poly()
3412 };
3413 let to_return = call_return_type(declared_return, body_type);
3414
3415 state.fns[fn_id]
3417 .return_type_cache
3418 .push((key, to_return.clone()));
3419
3420 to_return
3421}
3422
3423#[must_use]
3431pub(crate) fn call_return_type(declared: Option<DataType>, body_type: DataType) -> DataType {
3432 match declared {
3433 Some(mut declared) => {
3434 pin_open_element_types(&mut declared, &body_type);
3435 declared
3436 }
3437 None => body_type,
3438 }
3439}
3440
3441pub(crate) fn specialized_return_type(
3448 fn_id: usize,
3449 ctx: Ctx,
3450 state: &mut State<'_>,
3451) -> Option<(DataType, Span)> {
3452 let Some(generics) = state.fns[fn_id].generics.as_ref() else {
3453 return state.fns[fn_id].return_type.clone();
3454 };
3455 let unbound: Vec<SmolStr> = generics
3456 .params
3457 .iter()
3458 .filter(|param| !state.generics.names(param))
3459 .cloned()
3460 .collect();
3461 let generics = state.fns[fn_id].generics.as_ref()?;
3462 let annotation = generics.return_type.as_deref()?;
3463 if annotation.0.mentions_any(&unbound) {
3464 return state.fns[fn_id].return_type.clone();
3465 }
3466 let (return_type, return_span) = annotation.clone();
3467 let file_idx = generics.file_idx;
3468 let mut base = state.type_ctx(ctx.file_idx);
3469 let mut type_ctx = base.reborrow(file_idx);
3470 Some((return_type.to_datatype(&mut type_ctx), return_span))
3471}
3472
3473pub(crate) fn specialized_arg_types(
3480 fn_id: usize,
3481 type_args: &[DataType],
3482 ctx: Ctx,
3483 state: &mut State<'_>,
3484) -> Vec<Option<DataType>> {
3485 let declared = state.fns[fn_id]
3486 .args
3487 .iter()
3488 .map(|(_, t)| t.clone())
3489 .collect::<Vec<Option<DataType>>>();
3490 if type_args.is_empty() {
3491 return declared;
3492 }
3493 let Some(generics) = state.fns[fn_id].generics.as_ref() else {
3494 return declared;
3495 };
3496 let arg_types = generics.arg_types.clone();
3497 let file_idx = generics.file_idx;
3498 let frame = fn_bindings(fn_id, type_args, state);
3499 let mut base = state.type_ctx(ctx.file_idx);
3500 let mut type_ctx = base.reborrow(file_idx);
3501 type_ctx.generics.push_frame(frame);
3502 let resolved = arg_types
3503 .iter()
3504 .map(|t| t.as_ref().map(|t| t.to_datatype(&mut type_ctx)))
3505 .collect();
3506 type_ctx.generics.pop_bindings();
3507 resolved
3508}
3509
3510pub(crate) fn pinned_arg_types(
3517 infered_arg_types: &[DataType],
3518 declared_arg_types: &[Option<DataType>],
3519) -> Option<Vec<DataType>> {
3520 if !infered_arg_types.iter().any(has_open_element_type) {
3521 return None;
3522 }
3523 let mut pinned = infered_arg_types.to_vec();
3524 for (inferred, declared) in pinned.iter_mut().zip(declared_arg_types) {
3525 if let Some(declared) = declared {
3526 pin_open_element_types(inferred, declared);
3527 }
3528 }
3529 Some(pinned)
3530}
3531
3532#[must_use]
3535fn has_open_element_type(ty: &DataType) -> bool {
3536 match ty {
3537 DataType::Array(None) => true,
3538 DataType::Array(Some(element)) => has_open_element_type(element),
3539 DataType::Map(entry) => has_open_slot(entry.0.as_ref()) || has_open_slot(entry.1.as_ref()),
3540 _ => false,
3541 }
3542}
3543
3544#[must_use]
3547fn has_open_slot(slot: Option<&DataType>) -> bool {
3548 slot.is_none_or(has_open_element_type)
3549}
3550
3551#[must_use]
3554pub fn specialization_key(type_args: &[DataType], arg_types: &[DataType]) -> Box<[DataType]> {
3555 let mut key: Vec<DataType> = Vec::with_capacity(type_args.len() + arg_types.len());
3556 key.extend(type_args.iter().cloned());
3557 key.extend(arg_types.iter().cloned());
3558 key.into_boxed_slice()
3559}
3560
3561#[must_use]
3569pub fn fn_bindings(fn_id: usize, type_args: &[DataType], state: &State<'_>) -> BindingFrame {
3570 let Some(generics) = state.fns[fn_id].generics.as_ref() else {
3571 return BindingFrame::default();
3572 };
3573 let mut named: Vec<(SmolStr, DataType)> = generics.bindings.to_vec();
3574 for (param, arg) in generics.params.iter().zip(type_args) {
3575 named.push((param.clone(), arg.clone()));
3576 }
3577 let unnamed: Box<[SmolStr]> = generics
3578 .params
3579 .iter()
3580 .filter(|param| !named.iter().any(|(bound, _)| bound == *param))
3581 .cloned()
3582 .collect();
3583 BindingFrame {
3584 named: named.into_boxed_slice(),
3585 unnamed,
3586 }
3587}
3588
3589fn builtin_method_return(
3596 obj_type: &DataType,
3597 rule: fn(&DataType) -> Option<DataType>,
3598) -> Option<DataType> {
3599 let DataType::Union(members) = obj_type else {
3600 return rule(obj_type);
3601 };
3602 let mut types: Vec<DataType> = Vec::with_capacity(members.len());
3603 for member in members {
3604 let member_type = rule(member)?;
3605 if !types.contains(&member_type) {
3606 types.push(member_type);
3607 }
3608 }
3609 Some(DataType::Union(types.into_boxed_slice()).check_poly())
3610}
3611
3612#[must_use]
3618pub(crate) fn struct_field_holds_fn(struct_id: u16, field: &str, state: &State<'_>) -> bool {
3619 state.structs[struct_id as usize]
3620 .fields
3621 .iter()
3622 .find(|(name, _, _)| name == field)
3623 .is_some_and(|(_, field_type, _)| {
3624 matches!(field_type, DataType::Fn(_) | DataType::FnValue(_))
3625 })
3626}
3627
3628#[allow(clippy::too_many_arguments)]
3635fn operator_result_type(
3636 symbol: &str,
3637 l: &Expr,
3638 r: Option<&Expr>,
3639 t_l: &DataType,
3640 t_r: &DataType,
3641 span_l: Span,
3642 span_r: Span,
3643 v: &mut Vec<Variable>,
3644 ctx: Ctx,
3645 state: &mut State<'_>,
3646) -> DataType {
3647 if let Some(result) =
3648 infer_operator_method(symbol, l, r, t_l, t_r, span_l, span_r, v, ctx, state)
3649 {
3650 return result;
3651 }
3652 let reported = if symbol == UNARY_MINUS_METHOD {
3653 "-"
3654 } else {
3655 symbol
3656 };
3657 let (report_l, report_r) = if r.is_none() {
3658 (&DataType::Null, t_l)
3659 } else {
3660 (t_l, t_r)
3661 };
3662 error_op(
3663 report_l,
3664 report_r,
3665 reported,
3666 span_l,
3667 span_r,
3668 ctx.file_idx,
3669 state.sources,
3670 state.type_names(),
3671 );
3672}
3673
3674impl Expr {
3675 pub fn infer_type(&self, v: &mut Vec<Variable>, ctx: Ctx, state: &mut State<'_>) -> DataType {
3682 match self {
3683 Self::Var(name, span) => {
3684 if let Some(var) = v.iter().rfind(|x| &x.name == name) {
3685 var.var_type.clone()
3686 } else if let Some(fn_id) = state.scope(ctx.file_idx).find_function(&[], name) {
3687 DataType::Fn(fn_id as u16)
3691 } else if let Some((enum_id, _)) =
3692 variant_constructor_at(std::slice::from_ref(name), &[], *span, ctx, state)
3693 {
3694 DataType::Enum(enum_id)
3695 } else {
3696 error_unknown_variable(name, *span, v, ctx.file_idx, state.sources);
3697 }
3698 }
3699 Self::Float(_) => DataType::Float,
3700 Self::Int(_) => DataType::Int,
3701 Self::String(_) => DataType::String,
3702 Self::Bool(_) | Self::Eq(..) | Self::NotEq(..) => DataType::Bool,
3703 Self::Null | Self::Match(_, _, _, _, false) => DataType::Null,
3706 Self::Array(x, _) => DataType::Array(if x.is_empty() {
3707 None
3708 } else {
3709 let elem_types = x
3710 .iter()
3711 .map(|elem| elem.infer_type(v, ctx, state))
3712 .collect::<Vec<DataType>>();
3713 let elem_type = merge_fn_types(&elem_types).unwrap_or_else(|| {
3714 elem_types
3715 .into_iter()
3716 .find(|elem_type| *elem_type != DataType::Unknown)
3717 .unwrap_or(DataType::Unknown)
3718 });
3719 Some(Box::from(elem_type))
3720 }),
3721 Self::Map(kv_pairs, _) => {
3722 if kv_pairs.is_empty() {
3723 DataType::Map(Box::from((None, None)))
3726 } else {
3727 let entry_types = kv_pairs
3728 .iter()
3729 .map(|(key, _, value, _)| {
3730 (
3731 key.infer_type(v, ctx, state),
3732 value.infer_type(v, ctx, state),
3733 )
3734 })
3735 .collect::<Vec<(DataType, DataType)>>();
3736 let value_types = entry_types
3737 .iter()
3738 .map(|(_, val_t)| val_t.clone())
3739 .collect::<Vec<DataType>>();
3740 let kv_type = entry_types
3741 .into_iter()
3742 .find(|(key_t, val_t)| {
3743 key_t != &DataType::Unknown || val_t != &DataType::Unknown
3744 })
3745 .map_or(
3746 (Some(DataType::Unknown), Some(DataType::Unknown)),
3747 |(key_t, val_t)| (Some(key_t), Some(val_t)),
3748 );
3749 let kv_type = match merge_fn_types(&value_types) {
3752 Some(merged) => (kv_type.0, Some(merged)),
3753 None => kv_type,
3754 };
3755 DataType::Map(Box::from(kv_type))
3756 }
3757 }
3758 Self::Add(x, y, span_l, span_r) => {
3759 match (x.infer_type(v, ctx, state), y.infer_type(v, ctx, state)) {
3760 (DataType::Unknown, t) | (t, DataType::Unknown) => t,
3761 (DataType::Float, DataType::Float) => DataType::Float,
3762 (DataType::Int, DataType::Int) => DataType::Int,
3763 (DataType::String, DataType::String) => DataType::String,
3764 (DataType::Array(t1), DataType::Array(t2)) => DataType::Array(t1.or(t2)),
3765 (l, r) => operator_result_type(
3766 "+",
3767 x,
3768 Some(&**y),
3769 &l,
3770 &r,
3771 *span_l,
3772 *span_r,
3773 v,
3774 ctx,
3775 state,
3776 ),
3777 }
3778 }
3779 Self::Mul(x, y, span_l, span_r)
3780 | Self::Div(x, y, span_l, span_r)
3781 | Self::Sub(x, y, span_l, span_r)
3782 | Self::Mod(x, y, span_l, span_r)
3783 | Self::Pow(x, y, span_l, span_r) => {
3784 match (x.infer_type(v, ctx, state), y.infer_type(v, ctx, state)) {
3785 (DataType::Unknown, t) | (t, DataType::Unknown)
3786 if matches!(t, DataType::Float | DataType::Int | DataType::Unknown) =>
3787 {
3788 t
3789 }
3790 (DataType::Float, DataType::Float) => DataType::Float,
3791 (DataType::Int, DataType::Int) => DataType::Int,
3792 (l, r) => operator_result_type(
3793 symbol_of_expr(self),
3794 x,
3795 Some(&**y),
3796 &l,
3797 &r,
3798 *span_l,
3799 *span_r,
3800 v,
3801 ctx,
3802 state,
3803 ),
3804 }
3805 }
3806 Self::BitAnd(x, y, span_l, span_r)
3807 | Self::BitOr(x, y, span_l, span_r)
3808 | Self::BitXor(x, y, span_l, span_r)
3809 | Self::Shl(x, y, span_l, span_r)
3810 | Self::Shr(x, y, span_l, span_r) => {
3811 match (x.infer_type(v, ctx, state), y.infer_type(v, ctx, state)) {
3812 (DataType::Unknown, t) | (t, DataType::Unknown)
3813 if matches!(t, DataType::Int | DataType::Unknown) =>
3814 {
3815 t
3816 }
3817 (DataType::Int, DataType::Int) => DataType::Int,
3818 (l, r) => operator_result_type(
3819 symbol_of_expr(self),
3820 x,
3821 Some(&**y),
3822 &l,
3823 &r,
3824 *span_l,
3825 *span_r,
3826 v,
3827 ctx,
3828 state,
3829 ),
3830 }
3831 }
3832 Self::Sup(x, y, span_l, span_r)
3833 | Self::SupEq(x, y, span_l, span_r)
3834 | Self::Inf(x, y, span_l, span_r)
3835 | Self::InfEq(x, y, span_l, span_r) => {
3836 match (x.infer_type(v, ctx, state), y.infer_type(v, ctx, state)) {
3837 (DataType::Unknown, DataType::Float | DataType::Int)
3838 | (DataType::Float | DataType::Int, DataType::Unknown)
3839 | (DataType::Float, DataType::Float)
3840 | (DataType::Int, DataType::Int)
3841 | (DataType::String, DataType::String) => DataType::Bool,
3842 (l, r) => operator_result_type(
3843 symbol_of_expr(self),
3844 x,
3845 Some(&**y),
3846 &l,
3847 &r,
3848 *span_l,
3849 *span_r,
3850 v,
3851 ctx,
3852 state,
3853 ),
3854 }
3855 }
3856 Self::Is(operand, target, operand_span, target_span) => {
3860 let have = operand.infer_type(v, ctx, state);
3861 crate::compiler::type_test::resolve_test(
3862 &have,
3863 target,
3864 *operand_span,
3865 *target_span,
3866 ctx,
3867 state,
3868 );
3869 DataType::Bool
3870 }
3871 Self::Cast(_, target, _, target_span) => {
3872 crate::compiler::type_test::resolve_type(target, *target_span, ctx, state)
3873 }
3874 Self::BoolAnd(x, y, span_l, span_r) | Self::BoolOr(x, y, span_l, span_r) => {
3875 let x_type = x.infer_type(v, ctx, state);
3878 let v_len = v.len();
3879 if matches!(self, Self::BoolAnd(..)) {
3880 crate::compiler::type_test::declare_condition_facts(x, v, ctx, state);
3881 }
3882 let y_type = y.infer_type(v, ctx, state);
3883 v.truncate(v_len);
3884 match (x_type, y_type) {
3885 (DataType::Unknown | DataType::Bool, DataType::Bool)
3886 | (DataType::Bool, DataType::Unknown) => DataType::Bool,
3887 (l, r) => {
3888 error_op(
3889 &l,
3890 &r,
3891 "&&",
3892 *span_l,
3893 *span_r,
3894 ctx.file_idx,
3895 state.sources,
3896 state.type_names(),
3897 );
3898 }
3899 }
3900 }
3901 Self::Neg(e, span_l, span_r) => match e.infer_type(v, ctx, state) {
3902 DataType::Float => DataType::Float,
3903 DataType::Int => DataType::Int,
3904 DataType::Unknown => DataType::Unknown,
3905 operand_type => operator_result_type(
3906 UNARY_MINUS_METHOD,
3907 e,
3908 None,
3909 &operand_type,
3910 &operand_type,
3911 *span_l,
3912 *span_r,
3913 v,
3914 ctx,
3915 state,
3916 ),
3917 },
3918 Self::BitNot(e, span_l, span_r) => match e.infer_type(v, ctx, state) {
3919 DataType::Int => DataType::Int,
3920 DataType::Unknown => DataType::Unknown,
3921 operand_type => operator_result_type(
3922 "~",
3923 e,
3924 None,
3925 &operand_type,
3926 &operand_type,
3927 *span_l,
3928 *span_r,
3929 v,
3930 ctx,
3931 state,
3932 ),
3933 },
3934 Self::BoolNeg(e, span_l, span_r) => match e.infer_type(v, ctx, state) {
3935 DataType::Bool => DataType::Bool,
3936 operand_type => error_op(
3937 &DataType::Null,
3938 &operand_type,
3939 "!",
3940 *span_l,
3941 *span_r,
3942 ctx.file_idx,
3943 state.sources,
3944 state.type_names(),
3945 ),
3946 },
3947 Self::Propagate(operand, span) => {
3948 let operand_type = operand.infer_type(v, ctx, state);
3949 let Some((success, _)) = propagation_sides(&operand_type, state) else {
3950 crate::compiler::compiler_errors::error_propagate_operand(
3951 &operand_type,
3952 *span,
3953 ctx.file_idx,
3954 state.sources,
3955 state.type_names(),
3956 );
3957 };
3958 if let Some(frame) = state.propagations.last_mut()
3959 && !frame.contains(&operand_type)
3960 {
3961 frame.push(operand_type);
3962 }
3963 success
3964 }
3965 Self::ArrayGetIndex(array, _, span) => match array.infer_type(v, ctx, state) {
3966 DataType::Array(array_type) => array_type.map_or(DataType::Null, |t| *t),
3967 DataType::Map(m) => m.1.unwrap_or(DataType::Unknown),
3969 DataType::String => DataType::String,
3970 DataType::Unknown => DataType::Unknown,
3971 t => error_type_not_indexable(
3972 &t,
3973 *span,
3974 false,
3975 ctx.file_idx,
3976 state.sources,
3977 state.type_names(),
3978 ),
3979 },
3980 Self::GetStructField(s, field, struct_span, field_span) => {
3981 let s = s.infer_type(v, ctx, state);
3982 if let DataType::Struct(s_id) = s {
3983 state.structs[s_id as usize]
3984 .fields
3985 .iter()
3986 .find(|x| &x.0 == field)
3987 .unwrap_or_else(|| {
3988 let s = &state.structs[s_id as usize];
3989 error_struct_unknown_field(
3990 ctx.file_idx,
3991 *field_span,
3992 field,
3993 &s.name,
3994 &s.fields,
3995 state.sources,
3996 )
3997 })
3998 .1
3999 .clone()
4000 } else {
4001 error_invalid_type(
4002 &DataType::Struct(0),
4003 &s,
4004 *struct_span,
4005 None,
4006 None,
4007 ctx.file_idx,
4008 state.sources,
4009 TypeNames {
4010 structs: state.structs,
4011 enums: state.enums,
4012 },
4013 );
4014 }
4015 }
4016 Self::ArrayGetSlice(array, _, _, span) => match array.infer_type(v, ctx, state) {
4017 DataType::Array(array_type) => DataType::Array(array_type),
4018 DataType::String => DataType::String,
4019 DataType::Unknown => DataType::Unknown,
4020 t => error_type_not_indexable(
4021 &t,
4022 *span,
4023 false,
4024 ctx.file_idx,
4025 state.sources,
4026 state.type_names(),
4027 ),
4028 },
4029 Self::CallValue(callee, args, span, _) => {
4033 match resolve_callee(callee, *span, v, ctx, state) {
4034 Callee::Direct(fn_id) => {
4035 let infered_arg_types = args
4036 .iter()
4037 .map(|x| x.infer_type(v, ctx, state))
4038 .collect::<Vec<DataType>>();
4039 let fn_name = state.fns[fn_id].name.clone();
4040 infer_user_fn_return_type(
4041 fn_id,
4042 &infered_arg_types,
4043 &[],
4044 &fn_name,
4045 v,
4046 ctx,
4047 state,
4048 )
4049 }
4050 Callee::Indirect(fn_type) => {
4051 indirect_return_type(&fn_type, args, v, ctx, state)
4052 }
4053 }
4054 }
4055 Self::FunctionCall(args, namespace, span, _, type_args) => {
4056 if let Some(struct_id) =
4059 struct_default_target(namespace, args, type_args, *span, ctx, state)
4060 {
4061 return DataType::Struct(struct_id);
4062 }
4063 reject_default_default(namespace, *span, ctx, state);
4064 if let Some(fn_id) = path_call_target(namespace, type_args, *span, ctx, state) {
4065 let arg_types: Vec<DataType> =
4066 args.iter().map(|a| a.infer_type(v, ctx, state)).collect();
4067 let fn_name = state.fns[fn_id].name.clone();
4068 return infer_user_fn_return_type(
4069 fn_id,
4070 &arg_types,
4071 &[],
4072 &fn_name,
4073 v,
4074 ctx,
4075 state,
4076 );
4077 }
4078 if !type_args.is_empty() {
4083 if type_args_name_a_variant(namespace, ctx, state) {
4084 let (enum_id, _) =
4085 resolve_generic_variant(namespace, type_args, *span, ctx, state);
4086 return DataType::Enum(enum_id);
4087 }
4088 let len = namespace.len() - 1;
4089 let fn_name = namespace[len].clone();
4090 let (fn_id, call_type_args) = resolve_generic_call(
4091 &namespace[..len],
4092 &fn_name,
4093 type_args,
4094 *span,
4095 ctx,
4096 state,
4097 );
4098 let infered_arg_types = args
4099 .iter()
4100 .map(|x| x.infer_type(v, ctx, state))
4101 .collect::<Vec<DataType>>();
4102 return infer_user_fn_return_type(
4103 fn_id,
4104 &infered_arg_types,
4105 &call_type_args,
4106 &fn_name,
4107 v,
4108 ctx,
4109 state,
4110 );
4111 }
4112 if namespace.len() >= 2 {
4116 let arg_types = args
4117 .iter()
4118 .map(|x| x.infer_type(v, ctx, state))
4119 .collect::<Vec<DataType>>();
4120 if let Some((enum_id, _)) =
4121 variant_constructor_at(namespace, &arg_types, *span, ctx, state)
4122 {
4123 return DataType::Enum(enum_id);
4124 }
4125 }
4126 let (fn_name, path) = namespace.split_last().unwrap();
4132 let infered_args = |v: &mut Vec<Variable>, state: &mut State<'_>| {
4133 args.iter()
4134 .map(|x| x.infer_type(v, ctx, state))
4135 .collect::<Vec<DataType>>()
4136 };
4137 if !path.is_empty() {
4138 if let Some(declared) = declared_return_type(namespace, state) {
4142 return declared;
4143 }
4144 let Some(fn_id) = state.scope(ctx.file_idx).find_function(path, fn_name) else {
4145 error_unknown_function_in_namespace(
4146 fn_name,
4147 path,
4148 *span,
4149 ctx.file_idx,
4150 state,
4151 );
4152 };
4153 let infered_arg_types = infered_args(v, state);
4154 return infer_user_fn_return_type(
4155 fn_id,
4156 &infered_arg_types,
4157 &[],
4158 fn_name,
4159 v,
4160 ctx,
4161 state,
4162 );
4163 }
4164 if let Some(DataType::FnValue(fn_type)) = v
4172 .iter()
4173 .rfind(|var| var.name.as_str() == fn_name.as_str())
4174 .map(|var| var.var_type.clone())
4175 {
4176 return indirect_return_type(&fn_type, args, v, ctx, state);
4177 }
4178 if let Some(DataType::Fn(fn_id)) = v
4179 .iter()
4180 .rfind(|var| var.name.as_str() == fn_name.as_str())
4181 .map(|var| var.var_type.clone())
4182 {
4183 let infered_arg_types = infered_args(v, state);
4184 return infer_user_fn_return_type(
4185 fn_id as usize,
4186 &infered_arg_types,
4187 &[],
4188 fn_name,
4189 v,
4190 ctx,
4191 state,
4192 );
4193 }
4194 if let Some(fn_id) = state.scope(ctx.file_idx).find_function(&[], fn_name) {
4195 let infered_arg_types = infered_args(v, state);
4196 return infer_user_fn_return_type(
4197 fn_id,
4198 &infered_arg_types,
4199 &[],
4200 fn_name,
4201 v,
4202 ctx,
4203 state,
4204 );
4205 }
4206 if let Some(return_type) =
4207 builtin_fn_return_type(fn_name, state.namespaces.is_std(ctx.file_idx))
4208 {
4209 return return_type;
4210 }
4211 let arg_types = infered_args(v, state);
4214 if let Some((enum_id, _)) =
4215 variant_constructor_at(namespace, &arg_types, *span, ctx, state)
4216 {
4217 return DataType::Enum(enum_id);
4218 }
4219 error_unknown_function(
4220 fn_name,
4221 *span,
4222 state.scope(ctx.file_idx),
4223 ctx.file_idx,
4224 state.sources,
4225 )
4226 }
4227 Self::ObjFunctionCall(
4228 obj,
4229 args,
4230 namespace,
4231 obj_span,
4232 fn_span,
4233 args_indexes,
4234 type_args,
4235 ) => {
4236 let method = namespace.last().unwrap().as_str();
4237 if namespace.len() == 1 {
4241 reject_block_dot_call(obj, method, v, ctx, state);
4242 }
4243 let obj_type = obj.infer_type(v, ctx, state);
4244 if let DataType::Struct(struct_id) = obj_type {
4251 let struct_name = state.structs[struct_id as usize].name.clone();
4252 let mangled = mangle_method(&struct_name, method);
4253 if let Some(fn_id) = state.fns.iter().position(|f| f.name == mangled) {
4254 check_receiver(fn_id, method, *fn_span, ctx, state);
4255 let mut arg_types: Vec<DataType> = Vec::with_capacity(args.len() + 1);
4256 arg_types.push(DataType::Struct(struct_id));
4257 for a in args {
4258 arg_types.push(a.infer_type(v, ctx, state));
4259 }
4260 let call_type_args = if type_args.is_empty() {
4261 Vec::new()
4262 } else {
4263 resolve_call_type_args(fn_id, method, type_args, *fn_span, ctx, state)
4264 };
4265 return infer_user_fn_return_type(
4266 fn_id,
4267 &arg_types,
4268 &call_type_args,
4269 &mangled,
4270 v,
4271 ctx,
4272 state,
4273 );
4274 }
4275 if struct_field_holds_fn(struct_id, method, state) {
4280 let callee = Self::GetStructField(
4281 Box::new(obj.as_ref().clone()),
4282 SmolStr::new(method),
4283 *obj_span,
4284 *fn_span,
4285 );
4286 return Self::CallValue(
4287 Box::new(callee),
4288 Box::from(args.to_vec()),
4289 *fn_span,
4290 Box::from(args_indexes.to_vec()),
4291 )
4292 .infer_type(v, ctx, state);
4293 }
4294 crate::compiler::compiler_errors::error_no_such_method(
4297 method,
4298 &struct_name,
4299 *fn_span,
4300 ctx.file_idx,
4301 state.sources,
4302 );
4303 }
4304 if let DataType::Enum(enum_id) = obj_type {
4305 let enum_name = state.enums[enum_id as usize].name.clone();
4306 let mangled = mangle_method(&enum_name, method);
4307 if let Some(fn_id) = state.fns.iter().position(|f| f.name == mangled) {
4308 check_receiver(fn_id, method, *fn_span, ctx, state);
4309 let mut arg_types: Vec<DataType> = Vec::with_capacity(args.len() + 1);
4310 arg_types.push(DataType::Enum(enum_id));
4311 for a in args {
4312 arg_types.push(a.infer_type(v, ctx, state));
4313 }
4314 let call_type_args = if type_args.is_empty() {
4315 Vec::new()
4316 } else {
4317 resolve_call_type_args(fn_id, method, type_args, *fn_span, ctx, state)
4318 };
4319 return infer_user_fn_return_type(
4320 fn_id,
4321 &arg_types,
4322 &call_type_args,
4323 &mangled,
4324 v,
4325 ctx,
4326 state,
4327 );
4328 }
4329 crate::compiler::compiler_errors::error_no_such_method(
4330 method,
4331 &enum_name,
4332 *fn_span,
4333 ctx.file_idx,
4334 state.sources,
4335 );
4336 }
4337 if method == "parse" && obj_type == DataType::String {
4338 let parsed =
4339 crate::compiler::methods::parse_call(args, type_args, *fn_span, ctx, state);
4340 let v_len = v.len();
4341 crate::compiler::methods::declare_parse_text(v, 0);
4342 let parsed_type = parsed.infer_type(v, ctx, state);
4343 v.truncate(v_len);
4344 return parsed_type;
4345 }
4346 if let Some(fn_id) = crate::compiler::methods::impl_method_on_builtin(
4351 method, &obj_type, args, *fn_span, v, ctx, state,
4352 ) {
4353 check_receiver(fn_id, method, *fn_span, ctx, state);
4354 let mut arg_types: Vec<DataType> = Vec::with_capacity(args.len() + 1);
4355 arg_types.push(obj_type.clone());
4356 for a in args {
4357 arg_types.push(a.infer_type(v, ctx, state));
4358 }
4359 let call_type_args = if type_args.is_empty() {
4360 Vec::new()
4361 } else {
4362 resolve_call_type_args(fn_id, method, type_args, *fn_span, ctx, state)
4363 };
4364 return infer_user_fn_return_type(
4365 fn_id,
4366 &arg_types,
4367 &call_type_args,
4368 method,
4369 v,
4370 ctx,
4371 state,
4372 );
4373 }
4374 macro_rules! receiver_type {
4380 ($rule:expr, $expected:expr) => {
4381 builtin_method_return(&obj_type, $rule).unwrap_or_else(|| {
4382 error_invalid_obj_type(
4383 $expected,
4384 &obj_type,
4385 method,
4386 *obj_span,
4387 state.sources,
4388 ctx.file_idx,
4389 state.type_names(),
4390 )
4391 })
4392 };
4393 }
4394 match method {
4395 "uppercase" | "lowercase" | "replace" | "trim" | "trim_start" | "trim_end"
4396 | "trim_chars" | "trim_start_chars" | "trim_end_chars" | "join" => {
4397 DataType::String
4398 }
4399 "starts_with" | "ends_with" | "contains" => DataType::Bool,
4400 "len" => DataType::Int,
4401 "index_of" => {
4402 receiver_type!(
4403 |t| matches!(t, DataType::String | DataType::Array(_))
4404 .then_some(DataType::Null),
4405 &[DataType::String, DataType::Array(None)]
4406 );
4407 let v_len = v.len();
4408 crate::compiler::methods::declare_index_found(v, 0);
4409 let found = crate::compiler::methods::index_of_value(*fn_span)
4410 .infer_type(v, ctx, state);
4411 v.truncate(v_len);
4412 found
4413 }
4414 "repeat" => receiver_type!(
4415 |t| match t {
4416 DataType::String => Some(DataType::String),
4417 DataType::Array(element) => Some(DataType::Array(element.clone())),
4418 _ => None,
4419 },
4420 &[DataType::String, DataType::Array(None)]
4421 ),
4422 "reverse" => receiver_type!(
4426 |t| match t {
4427 DataType::String => Some(DataType::String),
4428 DataType::Array(_) => Some(DataType::Null),
4429 _ => None,
4430 },
4431 &[DataType::String, DataType::Array(None)]
4432 ),
4433 "push" | "sort" | "remove" => DataType::Null,
4434 "sqrt" | "round" | "floor" => DataType::Float,
4435 "abs" => receiver_type!(
4436 |t| match t {
4437 DataType::Float => Some(DataType::Float),
4438 DataType::Int => Some(DataType::Int),
4439 _ => None,
4440 },
4441 &[DataType::Int, DataType::Float]
4442 ),
4443 "split" => receiver_type!(
4444 |t| match t {
4445 DataType::String =>
4446 Some(DataType::Array(Some(Box::from(DataType::String)))),
4447 DataType::Array(element) => Some(DataType::Array(Some(Box::from(
4448 DataType::Array(element.clone())
4449 )))),
4450 _ => None,
4451 },
4452 &[DataType::String, DataType::Array(None)]
4453 ),
4454 "keys" => receiver_type!(
4455 |t| match t {
4456 DataType::Map(m) => Some(DataType::Array(m.0.clone().map(Box::new))),
4457 _ => None,
4458 },
4459 &[DataType::Map(Box::from((None, None)))]
4460 ),
4461 "values" => receiver_type!(
4462 |t| match t {
4463 DataType::Map(m) => Some(DataType::Array(m.1.clone().map(Box::new))),
4464 _ => None,
4465 },
4466 &[DataType::Map(Box::from((None, None)))]
4467 ),
4468 _ => crate::compiler::compiler_errors::error_unknown_builtin_method(
4473 method,
4474 crate::compiler::methods::builtin_receiver_name(&obj_type),
4475 *fn_span,
4476 ctx.file_idx,
4477 state.sources,
4478 ),
4479 }
4480 }
4481 Self::Match(scrutinee, arms, wildcard, span, true) => {
4482 let scrut_type = scrutinee.infer_type(v, ctx, state);
4483 let mut types: Vec<DataType> = Vec::with_capacity(arms.len() + 1);
4484 for (patterns, body) in arms {
4485 let v_len = v.len();
4486 if let DataType::Enum(enum_id) = scrut_type {
4487 crate::compiler::declare_arm_bindings(
4488 enum_id, patterns, *span, v, ctx, state,
4489 );
4490 }
4491 types.push(body[body.len() - 1].infer_type(v, ctx, state));
4492 v.truncate(v_len);
4493 }
4494 if let Some(w) = wildcard {
4495 types.push(w[w.len() - 1].infer_type(v, ctx, state));
4496 }
4497 branch_value_type(types, ctx, state)
4498 }
4499 Self::InlineCondition(condition, code, _, _) => {
4500 let mut types: Vec<DataType> = Vec::with_capacity(code.len());
4502 let v_len = v.len();
4503 crate::compiler::type_test::declare_condition_facts(condition, v, ctx, state);
4504 types.push(code[0].infer_type(v, ctx, state));
4505 v.truncate(v_len);
4506 for t in &code[0..] {
4507 if let Self::ElseIfBlock(condition, code, _) = t {
4508 crate::compiler::type_test::declare_condition_facts(
4509 condition, v, ctx, state,
4510 );
4511 types.push(code[0].infer_type(v, ctx, state));
4512 v.truncate(v_len);
4513 } else if let Self::ElseBlock(code) = t {
4514 types.push(code[0].infer_type(v, ctx, state));
4515 }
4516 }
4517 branch_value_type(types, ctx, state)
4518 }
4519 Self::NamespacedRef(path, span, type_args) => {
4520 if !type_args.is_empty() {
4521 let (enum_id, _) = resolve_generic_variant(path, type_args, *span, ctx, state);
4522 return DataType::Enum(enum_id);
4523 }
4524 if let Some((enum_id, _)) = variant_constructor_at(path, &[], *span, ctx, state) {
4525 DataType::Enum(enum_id)
4526 } else {
4527 crate::compiler::compiler_errors::error_enum(
4528 "Unknown enum variant",
4529 &format!("{} does not name an enum variant", path.join("::")),
4530 *span,
4531 ctx.file_idx,
4532 state.sources,
4533 );
4534 }
4535 }
4536 Self::Struct(namespace, fields, span, type_args, base) => {
4537 DataType::Struct(literal_struct_id(
4538 namespace,
4539 fields,
4540 type_args,
4541 base.as_ref().and_then(|b| b.0.base()),
4542 *span,
4543 v,
4544 ctx,
4545 state,
4546 ))
4547 }
4548 Self::StructDefault(struct_id, _) => DataType::Struct(*struct_id),
4549 Self::AnonymousFunction(args, code, span) => {
4550 let fn_name = format_args!(
4558 "{ANON_FN_PREFIX}{}:{}:{}",
4559 ctx.file_idx, span.start, span.end
4560 )
4561 .to_smolstr();
4562 if let Some(id) = state.fns.iter().rposition(|f| f.name == fn_name) {
4563 return DataType::Fn(id as u16);
4564 }
4565 let returns_null = check_if_returns_void(code);
4566 let mut callees = Vec::new();
4567 collect_direct_fn_calls(code, None, &mut callees);
4568 let captures: Box<[(SmolStr, DataType, Option<DataType>)]> =
4575 closure_free_names(args, code)
4576 .into_iter()
4577 .filter_map(|name| {
4578 v.iter()
4579 .rfind(|var| var.name == name)
4580 .map(|var| (name, var.var_type.clone(), var.declared.clone()))
4581 })
4582 .collect();
4583 let id = state.fns.len() as u16;
4584 state.fns.push(Function {
4585 name: fn_name,
4586 args: args.iter().map(|a| (a.clone(), None)).collect(),
4587 code: Rc::from(code.clone()),
4588 impls: Vec::new(),
4589 is_recursive: None,
4590 returns_null,
4591 src_file: ctx.file_idx,
4592 return_type_cache: Vec::new(),
4593 direct_calls: callees.into_boxed_slice(),
4594 name_span: *span,
4595 return_type: None,
4597 generics: None,
4598 captures,
4599 entry_register: None,
4600 });
4601 DataType::Fn(id)
4602 }
4603 _ => unsafe { unreachable_unchecked() },
4604 }
4605 }
4606}
4607
4608fn branch_value_type(types: Vec<DataType>, ctx: Ctx, state: &mut State<'_>) -> DataType {
4621 if let Some(fn_value) = merge_fn_types(&types) {
4622 return fn_value;
4623 }
4624 let mut distinct: Vec<DataType> = Vec::with_capacity(types.len());
4625 for t in types {
4626 if distinct.contains(&t) {
4627 continue;
4628 }
4629 if let Some((i, merged)) = distinct
4630 .iter()
4631 .enumerate()
4632 .find_map(|(i, held)| merge_instantiations(held, &t, ctx, state).map(|m| (i, m)))
4633 {
4634 distinct[i] = merged;
4635 continue;
4636 }
4637 distinct.push(t);
4638 }
4639 DataType::Union(Box::from(distinct)).check_poly()
4640}
4641
4642#[must_use]
4651pub fn declared_fn_value_type(fn_id: u16, state: &State<'_>) -> DataType {
4652 let function = &state.fns[fn_id as usize];
4653 let params: Option<Vec<DataType>> = function
4654 .generics
4655 .is_none()
4656 .then(|| function.args.iter().map(|(_, arg)| arg.clone()).collect())
4657 .flatten();
4658 let return_type = function
4659 .return_type
4660 .as_ref()
4661 .map(|(declared, _)| declared.clone())
4662 .or_else(|| function.returns_null.then_some(DataType::Null));
4663 let sig = match (params, return_type) {
4664 (Some(params), Some(return_type)) => Some((params.into_boxed_slice(), return_type)),
4665 _ => None,
4666 };
4667 DataType::FnValue(Box::new(FnValue {
4668 sig,
4669 candidates: Box::from([fn_id]),
4670 set: None,
4671 }))
4672}
4673
4674#[must_use]
4680pub fn bare_fn_value_type(
4681 expr: &Expr,
4682 v: &[Variable],
4683 ctx: Ctx,
4684 state: &State<'_>,
4685) -> Option<DataType> {
4686 let Expr::Var(name, _) = expr else {
4687 return None;
4688 };
4689 if v.iter().any(|var| var.name == *name) {
4690 return None;
4691 }
4692 let fn_id = state.scope(ctx.file_idx).find_function(&[], name)?;
4693 Some(declared_fn_value_type(fn_id as u16, state))
4694}
4695
4696#[must_use]
4706pub fn merge_fn_types(types: &[DataType]) -> Option<DataType> {
4707 let mut candidates: Vec<u16> = Vec::new();
4708 let mut sig = None;
4709 let mut saw_fn = false;
4710 for t in types {
4711 match t {
4712 DataType::Fn(id) => {
4713 saw_fn = true;
4714 if !candidates.contains(id) {
4715 candidates.push(*id);
4716 }
4717 }
4718 DataType::FnValue(fn_type) => {
4719 saw_fn = true;
4720 if sig.is_none() {
4721 sig.clone_from(&fn_type.sig);
4722 }
4723 for id in &fn_type.candidates {
4724 if !candidates.contains(id) {
4725 candidates.push(*id);
4726 }
4727 }
4728 }
4729 _ => {}
4730 }
4731 }
4732 if !saw_fn || (sig.is_none() && candidates.len() < 2) {
4733 return None;
4734 }
4735 Some(DataType::FnValue(Box::new(FnValue {
4736 sig,
4737 candidates: candidates.into_boxed_slice(),
4738 set: None,
4739 })))
4740}
4741
4742pub fn indirect_return_type(
4748 fn_type: &FnValue,
4749 args: &[Expr],
4750 v: &mut Vec<Variable>,
4751 ctx: Ctx,
4752 state: &mut State<'_>,
4753) -> DataType {
4754 if let Some((_, return_type)) = &fn_type.sig {
4755 return return_type.clone();
4756 }
4757 let infered_arg_types = args
4758 .iter()
4759 .map(|arg| arg.infer_type(v, ctx, state))
4760 .collect::<Vec<DataType>>();
4761 let return_types = state
4762 .fn_value_candidates(fn_type)
4763 .into_iter()
4764 .map(|fn_id| {
4765 let fn_id = fn_id as usize;
4766 let fn_name = state.fns[fn_id].name.clone();
4767 infer_user_fn_return_type(fn_id, &infered_arg_types, &[], &fn_name, v, ctx, state)
4768 })
4769 .collect::<Vec<DataType>>();
4770 let mut return_types = return_types.into_iter();
4771 match return_types.next() {
4772 None => DataType::Unknown,
4773 Some(first) if return_types.len() == 0 => first,
4774 Some(first) => {
4775 let all = std::iter::once(first).chain(return_types).collect();
4776 DataType::Union(all).check_poly()
4777 }
4778 }
4779}