1use super::expr::Expr;
2use super::expr::Span;
3use super::expr::mangle_method;
4use super::expr::symbol_of_expr;
5use crate::compiler::Namespace;
6use crate::compiler::compiler_data::Ctx;
7use crate::compiler::compiler_data::FnSignature;
8use crate::compiler::compiler_data::Function;
9use crate::compiler::compiler_data::Source;
10use crate::compiler::compiler_data::State;
11use crate::compiler::compiler_data::Variable;
12use crate::compiler::compiler_errors::error_invalid_type;
13use crate::compiler::compiler_errors::error_op;
14use crate::compiler::compiler_errors::error_struct_unknown_field;
15use crate::compiler::compiler_errors::error_unknown_function;
16use crate::compiler::compiler_errors::error_unknown_function_in_namespace;
17use crate::compiler::compiler_errors::error_unknown_struct;
18use crate::compiler::compiler_errors::error_unknown_type;
19use crate::compiler::compiler_errors::error_unknown_type_with_namespace;
20use crate::compiler::compiler_errors::error_unknown_variable;
21use rustc_hash::FxHashSet;
22use smol_strc::SmolStr;
23use smol_strc::ToSmolStr;
24use std::cell::RefCell;
25use std::hint::cold_path;
26use std::hint::unreachable_unchecked;
27use std::rc::Rc;
28
29pub use crate::rt::DataType;
30
31const ANON_FN_PREFIX: &str = "<anon>";
35
36thread_local! {
39 static RETURN_TYPE_INFERRING: RefCell<FxHashSet<usize>> =
40 RefCell::new(FxHashSet::default());
41}
42
43pub fn reset_inference_state() {
46 RETURN_TYPE_INFERRING.with(|s| s.borrow_mut().clear());
47}
48
49#[derive(Debug, PartialEq, Eq, Clone)]
50pub enum TypeExpr {
51 Identifier(SmolStr, Span),
52 NamespacedIdentifier(Box<[SmolStr]>, Span),
53 Array(Box<Self>),
54 Map(Box<Self>, Box<Self>),
55 Union(Box<[Self]>),
56}
57
58impl TypeExpr {
59 #[must_use]
60 pub fn to_datatype(
61 &self,
62 file_idx: u16,
63 namespace: &Namespace,
64 sources: &[Source],
65 ) -> DataType {
66 match self {
67 Self::Identifier(s, span) => match s.as_str() {
68 "int" => DataType::Int,
69 "float" => DataType::Float,
70 "bool" => DataType::Bool,
71 "string" => DataType::String,
72 "null" => DataType::Null,
73 "any" => DataType::Unknown,
77 struct_name => {
78 if let Some(struct_id) =
79 namespace.find_struct(&[], struct_name, *span, file_idx, sources)
80 {
81 DataType::Struct(struct_id as u16)
82 } else if let Some(enum_id) = namespace.find_enum(&[], struct_name) {
83 DataType::Enum(enum_id as u16)
84 } else {
85 error_unknown_type(*span, file_idx, struct_name, sources, namespace);
86 }
87 }
88 },
89 Self::NamespacedIdentifier(s, span) => {
90 if let Some(struct_id) = namespace.find_struct(
91 &s[..s.len() - 1],
92 unsafe { s.last().unwrap_unchecked() },
93 *span,
94 file_idx,
95 sources,
96 ) {
97 DataType::Struct(struct_id as u16)
98 } else if let Some(enum_id) =
99 namespace.find_enum(&s[..s.len() - 1], unsafe { s.last().unwrap_unchecked() })
100 {
101 DataType::Enum(enum_id as u16)
102 } else {
103 cold_path();
104 error_unknown_type_with_namespace(
105 *span,
106 file_idx,
107 unsafe { s.last().unwrap_unchecked() },
108 sources,
109 namespace,
110 &s[..s.len() - 1],
111 )
112 }
113 }
114 Self::Array(inner_t) => DataType::Array(Some(Box::new(
115 inner_t.to_datatype(file_idx, namespace, sources),
116 ))),
117 Self::Map(k_t, v_t) => DataType::Map(Box::from((
118 Some(k_t.to_datatype(file_idx, namespace, sources)),
119 Some(v_t.to_datatype(file_idx, namespace, sources)),
120 ))),
121 Self::Union(poly) => DataType::Union(
122 poly.iter()
123 .map(|t| t.to_datatype(file_idx, namespace, sources))
124 .collect(),
125 )
126 .check_poly(),
127 }
128 }
129}
130
131#[must_use]
138pub fn format_detailed(t: &DataType, state: &State<'_>) -> SmolStr {
139 match t {
140 DataType::Float => SmolStr::new_static("float"),
141 DataType::Int => SmolStr::new_static("int"),
142 DataType::Bool => SmolStr::new_static("bool"),
143 DataType::String => SmolStr::new_static("string"),
144 DataType::Array(array_type) => match array_type {
145 Some(array_type) => {
146 format_args!("{}[]", format_detailed(array_type, state)).to_smolstr()
147 }
148 None => SmolStr::new_static("Unknown[]"),
149 },
150 DataType::Null => SmolStr::new_static("null"),
151 DataType::Unknown => SmolStr::new_static("Unknown"),
152 DataType::Union(types) => format_args!(
153 "{}",
154 types
155 .into_iter()
156 .map(|x| format_detailed(x, state))
157 .collect::<Vec<SmolStr>>()
158 .join("|")
159 )
160 .to_smolstr(),
161 DataType::Struct(s) => {
162 let s = &state.structs[*s as usize];
163 format_args!(
164 "{} {{{}}}",
165 s.name,
166 s.fields
167 .iter()
168 .map(|(n, t, _)| {
169 format_args!("{n}: {}", format_detailed(t, state)).to_smolstr()
170 })
171 .collect::<Vec<SmolStr>>()
172 .join(", ")
173 )
174 .to_smolstr()
175 }
176 DataType::Enum(e) => state.enums[*e as usize].name.clone(),
177 DataType::Map(m) => format_args!(
178 "{{{}: {}}}",
179 m.0.as_ref().unwrap_or(&DataType::Unknown),
180 m.1.as_ref().unwrap_or(&DataType::Unknown)
181 )
182 .to_smolstr(),
183 DataType::Fn(id) => {
184 let f = &state.fns[*id as usize];
185 format_args!(
186 "fn ({})",
187 f.args
188 .iter()
189 .map(|(a, _)| a.clone())
190 .collect::<Vec<SmolStr>>()
191 .join(", ")
192 )
193 .to_smolstr()
194 }
195 }
196}
197
198#[inline(always)]
199#[must_use]
200pub fn struct_field_type_matches(expected: &DataType, received: &DataType) -> bool {
201 received == &DataType::Null || expected == received
202}
203
204#[inline(always)]
213#[must_use]
214pub fn param_type_matches(expected: &DataType, received: &DataType) -> bool {
215 *expected == DataType::Unknown || *received == DataType::Unknown || expected == received
216}
217
218#[must_use]
226pub fn arg_types_specialize_equal(a: &[DataType], b: &[DataType]) -> bool {
227 a.len() == b.len()
228 && a.iter().zip(b).all(|(x, y)| match (x, y) {
229 (DataType::Fn(i), DataType::Fn(j)) => i == j,
230 (DataType::Fn(_), _) | (_, DataType::Fn(_)) => false,
231 _ => x == y,
232 })
233}
234
235pub fn collect_direct_fn_calls(content: &[Expr], calls: &mut Vec<SmolStr>) {
242 let mut expr_stack: Vec<&Expr> = content.iter().collect();
243 while let Some(expression) = expr_stack.pop() {
244 match expression {
245 Expr::FunctionCall(args, namespace, _, _) => {
246 calls.push(namespace.last().unwrap().clone());
247 expr_stack.extend(args.iter());
248 }
249 Expr::Condition(x, y, _)
250 | Expr::InlineCondition(x, y, _)
251 | Expr::ElseIfBlock(x, y)
252 | Expr::WhileBlock(x, y)
253 | Expr::ObjFunctionCall(x, y, _, _, _, _) => {
254 expr_stack.push(x);
255 expr_stack.extend(y.iter());
256 }
257 Expr::ElseBlock(x) | Expr::EvalBlock(x) | Expr::LoopBlock(x) => {
258 expr_stack.extend(x.iter());
259 }
260 Expr::ReturnVal(code) => {
261 if let Some(code) = code.as_ref() {
262 expr_stack.push(code);
263 }
264 }
265 Expr::FunctionDecl(_, _, x, _, _) => expr_stack.extend(x.iter()),
266 Expr::ArrayGetSlice(x, y, z, _) => {
267 expr_stack.push(x);
268 expr_stack.push(y);
269 expr_stack.push(z);
270 }
271 Expr::VarDeclare(_, x)
272 | Expr::VarAssign(_, x, _)
273 | Expr::Neg(x, _, _)
274 | Expr::BoolNeg(x, _, _) => expr_stack.push(x),
275 Expr::ForLoop(_, _, code, _) => expr_stack.extend(code.iter()),
276 Expr::IntForLoop(_, start, end, code, _, _) => {
277 expr_stack.push(start);
278 expr_stack.push(end);
279 expr_stack.extend(code.iter());
280 }
281 Expr::ArrayModify(array, index, value, _, _) => {
282 expr_stack.push(array);
283 expr_stack.push(index);
284 expr_stack.push(value);
285 }
286 Expr::Array(elems, _) => expr_stack.extend(elems.iter()),
287 Expr::Struct(_, fields, _) => {
288 expr_stack.extend(fields.iter().map(|(_, expr, _, _)| expr));
289 }
290 Expr::GetStructField(expr, _, _, _) => expr_stack.push(expr),
291 Expr::SetStructField(expr, _, value, _, _, _) => {
292 expr_stack.push(expr);
293 expr_stack.push(value);
294 }
295 Expr::TryCatchBlock(try_code, _, catch_code) => {
296 expr_stack.extend(try_code.iter());
297 expr_stack.extend(catch_code.iter());
298 }
299 Expr::Match(scrutinee, arms, wildcard, _) => {
300 expr_stack.push(scrutinee);
301 for (pat, body) in arms {
302 expr_stack.push(pat);
303 expr_stack.extend(body.iter());
304 }
305 if let Some(w) = wildcard {
306 expr_stack.extend(w.iter());
307 }
308 }
309 Expr::ArrayGetIndex(x, y, _)
310 | Expr::Mul(x, y, _, _)
311 | Expr::Div(x, y, _, _)
312 | Expr::Add(x, y, _, _)
313 | Expr::Sub(x, y, _, _)
314 | Expr::Mod(x, y, _, _)
315 | Expr::Pow(x, y, _, _)
316 | Expr::Eq(x, y)
317 | Expr::NotEq(x, y)
318 | Expr::Sup(x, y, _, _)
319 | Expr::SupEq(x, y, _, _)
320 | Expr::Inf(x, y, _, _)
321 | Expr::InfEq(x, y, _, _)
322 | Expr::BoolAnd(x, y, _, _)
323 | Expr::BoolOr(x, y, _, _) => {
324 expr_stack.push(x);
325 expr_stack.push(y);
326 }
327 _ => {}
328 }
329 }
330}
331
332pub fn can_reach<S: std::hash::BuildHasher>(
334 src_fn: &str,
335 target_fn: &str,
336 fns: &[Function],
337 visited: &mut std::collections::HashSet<SmolStr, S>,
338) -> bool {
339 if let Some(from_fn) = fns.iter().find(|f| f.name.as_str() == src_fn) {
340 for callee in &from_fn.direct_calls {
341 if callee == target_fn {
342 return true;
343 }
344 if visited.insert(callee.clone()) && can_reach(callee, target_fn, fns, visited) {
345 return true;
346 }
347 }
348 }
349 false
350}
351
352#[must_use]
353pub fn check_if_returns_void(content: &[Expr]) -> bool {
354 for content in content {
355 match content {
356 Expr::ElseIfBlock(_, code)
357 | Expr::ElseBlock(code)
358 | Expr::Condition(_, code, _)
359 | Expr::InlineCondition(_, code, _)
360 | Expr::WhileBlock(_, code)
361 | Expr::ForLoop(_, _, code, _)
362 | Expr::EvalBlock(code)
363 | Expr::LoopBlock(code)
364 | Expr::IntForLoop(_, _, _, code, _, _) => {
365 if !check_if_returns_void(code) {
366 return false;
367 }
368 }
369 Expr::Match(_, arms, wildcard, _) => {
370 for (_, body) in arms {
371 if !check_if_returns_void(body) {
372 return false;
373 }
374 }
375 if let Some(w) = wildcard
376 && !check_if_returns_void(w)
377 {
378 return false;
379 }
380 }
381 Expr::ReturnVal(return_val) if return_val.is_some() => {
382 return false;
383 }
384 _ => {}
385 }
386 }
387 true
388}
389
390macro_rules! add_return_type {
391 ($return_types: expr, $return_type: expr) => {
392 if $return_type != DataType::Unknown && !($return_types).contains(&($return_type)) {
393 ($return_types).push($return_type);
394 }
395 };
396}
397
398macro_rules! extend_return_types {
399 ($return_types: expr, $new_types: expr) => {
400 for return_type in $new_types {
401 add_return_type!($return_types, return_type);
402 }
403 };
404}
405
406pub fn track_returns(
407 content: &[Expr],
408 v: &mut Vec<Variable>,
409 ctx: Ctx,
410 state: &mut State<'_>,
411 fn_name: &str,
412) -> Vec<DataType> {
413 let mut flow = track_return_flow(content, v, ctx, state, fn_name);
414 if !flow.always_returns && !flow.types.is_empty() {
415 add_return_type!(&mut flow.types, DataType::Null);
416 }
417 flow.types
418}
419
420struct FnReturnFlow {
421 types: Vec<DataType>,
422 always_returns: bool,
423}
424
425fn track_scoped_returns(
426 code: &[Expr],
427 v: &mut Vec<Variable>,
428 ctx: Ctx,
429 state: &mut State<'_>,
430 fn_name: &str,
431) -> FnReturnFlow {
432 let v_len = v.len();
433 let flow = track_return_flow(code, v, ctx, state, fn_name);
434 v.truncate(v_len);
435 flow
436}
437
438fn track_condition_returns(
439 code: &[Expr],
440 v: &mut Vec<Variable>,
441 ctx: Ctx,
442 state: &mut State<'_>,
443 fn_name: &str,
444) -> FnReturnFlow {
445 let mut return_types = Vec::new();
446 let first_branch_end = code
447 .iter()
448 .position(|expr| matches!(expr, Expr::ElseIfBlock(_, _) | Expr::ElseBlock(_)))
449 .unwrap_or(code.len());
450
451 let first_flow = track_scoped_returns(&code[..first_branch_end], v, ctx, state, fn_name);
452 let mut all_branches_return = first_flow.always_returns;
453 let mut has_else = false;
454 extend_return_types!(&mut return_types, first_flow.types);
455
456 for expr in &code[first_branch_end..] {
457 match expr {
458 Expr::ElseIfBlock(_, branch_code) => {
459 let flow = track_scoped_returns(branch_code, v, ctx, state, fn_name);
460 all_branches_return &= flow.always_returns;
461 extend_return_types!(&mut return_types, flow.types);
462 }
463 Expr::ElseBlock(branch_code) => {
464 has_else = true;
465 let flow = track_scoped_returns(branch_code, v, ctx, state, fn_name);
466 all_branches_return &= flow.always_returns;
467 extend_return_types!(&mut return_types, flow.types);
468 }
469 _ => {}
470 }
471 }
472
473 FnReturnFlow {
474 types: return_types,
475 always_returns: has_else && all_branches_return,
476 }
477}
478
479fn track_return_flow(
480 content: &[Expr],
481 v: &mut Vec<Variable>,
482 ctx: Ctx,
483 state: &mut State<'_>,
484 fn_name: &str,
485) -> FnReturnFlow {
486 let mut return_types: Vec<DataType> = Vec::new();
487 for expr in content {
488 match expr {
489 Expr::Condition(_, code, _) | Expr::InlineCondition(_, code, _) => {
490 let flow = track_condition_returns(code, v, ctx, state, fn_name);
491 extend_return_types!(&mut return_types, flow.types);
492 if flow.always_returns {
493 return FnReturnFlow {
494 types: return_types,
495 always_returns: true,
496 };
497 }
498 }
499 Expr::ElseIfBlock(_, code)
500 | Expr::ElseBlock(code)
501 | Expr::EvalBlock(code)
502 | Expr::LoopBlock(code) => {
503 let flow = track_scoped_returns(code, v, ctx, state, fn_name);
504 extend_return_types!(&mut return_types, flow.types);
505 if flow.always_returns {
506 return FnReturnFlow {
507 types: return_types,
508 always_returns: true,
509 };
510 }
511 }
512 Expr::VarDeclare(name, expr) => {
513 let var_type = expr.infer_type(v, ctx, state);
514 v.push(Variable {
515 name: name.clone(),
516 register_id: 0,
517 var_type,
518 });
519 }
520 Expr::VarAssign(name, expr, _) => {
521 let var_type = expr.infer_type(v, ctx, state);
522 if let Some(var) = v.iter_mut().rfind(|var| &var.name == name) {
523 var.var_type = var_type;
524 }
525 }
526 Expr::WhileBlock(_, code) => {
527 let flow = track_scoped_returns(code, v, ctx, state, fn_name);
528 extend_return_types!(&mut return_types, flow.types);
529 }
530 Expr::IntForLoop(var_name, _, _, code, _, _) => {
531 let v_len = v.len();
532 v.push(Variable {
533 name: var_name.clone(),
534 register_id: 0,
535 var_type: DataType::Int,
536 });
537 let flow = track_return_flow(code, v, ctx, state, fn_name);
538 extend_return_types!(&mut return_types, flow.types);
539 v.truncate(v_len);
540 }
541 Expr::ForLoop(var_name, array_expr, array_code, _) => {
542 let inferred_collection_type = array_expr.infer_type(v, ctx, state);
543 let elem_type = match inferred_collection_type {
544 DataType::Array(inner) => inner.map_or(DataType::Unknown, |t| *t),
545 DataType::String => DataType::String,
546 DataType::Unknown => DataType::Unknown,
547 DataType::Map(m) => m.0.map_or(DataType::Unknown, |t| t),
549 _ => unsafe { unreachable_unchecked() },
550 };
551 let v_len = v.len();
552 if var_name.as_str() != "_" {
553 v.push(Variable {
554 name: var_name.clone(),
555 register_id: 0,
556 var_type: elem_type,
557 });
558 }
559 let flow = track_return_flow(array_code, v, ctx, state, fn_name);
560 extend_return_types!(&mut return_types, flow.types);
561 v.truncate(v_len);
562 }
563 Expr::ObjFunctionCall(obj, args, namespace, _, _, _)
564 if namespace.last().unwrap().as_str() == "push" =>
565 {
566 if let Expr::Var(var_name, _) = obj.as_ref()
567 && v.iter()
568 .rfind(|var| &var.name == var_name)
569 .is_some_and(|var| var.var_type == DataType::Array(None))
570 {
571 let arg_type = args[0].infer_type(v, ctx, state);
572 if let Some(var) = v.iter_mut().rfind(|var| &var.name == var_name) {
573 var.var_type = DataType::Array(Some(Box::new(arg_type)));
574 }
575 }
576 }
577 Expr::Match(scrutinee, arms, wildcard, span) => {
578 let scrut_type = scrutinee.infer_type(v, ctx, state);
579 let is_enum = matches!(scrut_type, DataType::Enum(_));
580 let mut all_return = true;
581 for (pat, body) in arms {
582 let v_len = v.len();
583 if let DataType::Enum(enum_id) = scrut_type {
584 let (vidx, binders) = crate::compiler::resolve_variant_pattern(
585 enum_id, pat, *span, ctx, state,
586 );
587 for (i, binder) in binders.iter().enumerate() {
588 if binder.as_str() != "_" {
589 let payload_type = state.enums[enum_id as usize].variants
590 [vidx as usize]
591 .payload[i]
592 .clone();
593 v.push(Variable {
594 name: binder.clone(),
595 register_id: 0,
596 var_type: payload_type,
597 });
598 }
599 }
600 }
601 let flow = track_return_flow(body, v, ctx, state, fn_name);
602 v.truncate(v_len);
603 all_return &= flow.always_returns;
604 extend_return_types!(&mut return_types, flow.types);
605 }
606 let exhaustive = if wildcard.is_some() {
607 if let Some(w) = wildcard {
608 let flow = track_scoped_returns(w, v, ctx, state, fn_name);
609 all_return &= flow.always_returns;
610 extend_return_types!(&mut return_types, flow.types);
611 }
612 true
613 } else {
614 is_enum
616 };
617 if exhaustive && all_return {
618 return FnReturnFlow {
619 types: return_types,
620 always_returns: true,
621 };
622 }
623 }
624 Expr::ReturnVal(return_val) => {
625 if let Some(val) = return_val.as_ref() {
626 let infered = val.infer_type(v, ctx, state);
627 add_return_type!(&mut return_types, infered);
628 } else {
629 add_return_type!(&mut return_types, DataType::Null);
630 }
631 return FnReturnFlow {
632 types: return_types,
633 always_returns: true,
634 };
635 }
636 _ => {}
637 }
638 }
639 FnReturnFlow {
640 types: return_types,
641 always_returns: false,
642 }
643}
644
645fn infer_user_fn_return_type(
651 fn_id: usize,
652 infered_arg_types: Vec<DataType>,
653 function_name: &str,
654 v: &mut Vec<Variable>,
655 ctx: Ctx,
656 state: &mut State<'_>,
657) -> DataType {
658 let func = &state.fns[fn_id];
659 if let Some((_, ret)) = func
661 .return_type_cache
662 .iter()
663 .find(|(args, _)| arg_types_specialize_equal(args, &infered_arg_types))
664 {
665 return ret.clone();
666 }
667
668 let fn_args = func.args.clone();
669 let fn_code = func.code.clone();
670 let fn_src_file = func.src_file;
671 let v_len_before_args = v.len();
672 for (i, infered_type) in infered_arg_types.iter().cloned().enumerate() {
673 v.push(Variable {
675 name: fn_args[i].0.clone(),
676 register_id: 0,
677 var_type: infered_type,
678 });
679 }
680
681 let already_inferring = RETURN_TYPE_INFERRING.with(|s| s.borrow().contains(&fn_id));
684 if already_inferring {
685 v.truncate(v_len_before_args);
686 return DataType::Unknown;
687 }
688
689 RETURN_TYPE_INFERRING.with(|s| s.borrow_mut().insert(fn_id));
690
691 let fn_ctx = Ctx {
692 file_idx: fn_src_file,
693 ..ctx
694 };
695 let fn_type = track_returns(&fn_code, v, fn_ctx, state, function_name);
696
697 RETURN_TYPE_INFERRING.with(|s| s.borrow_mut().remove(&fn_id));
698
699 let to_return = if fn_type.is_empty() {
700 if check_if_returns_void(&fn_code) {
705 DataType::Null
706 } else {
707 DataType::Unknown
708 }
709 } else {
710 DataType::Union(Box::from(fn_type)).check_poly()
712 };
713
714 v.truncate(v_len_before_args);
715
716 state.fns[fn_id]
718 .return_type_cache
719 .push((Box::from(infered_arg_types), to_return.clone()));
720
721 to_return
722}
723
724impl Expr {
725 pub fn infer_type(&self, v: &mut Vec<Variable>, ctx: Ctx, state: &mut State<'_>) -> DataType {
732 match self {
733 Self::Var(name, span) => {
734 if let Some(var) = v.iter().rfind(|x| &x.name == name) {
735 var.var_type.clone()
736 } else if let Some(fn_id) =
737 state
738 .namespace
739 .find_function(&[], name, *span, ctx.file_idx, state.sources)
740 {
741 DataType::Fn(fn_id as u16)
745 } else if let Some((enum_id, _)) =
746 crate::compiler::resolve_enum_variant(std::slice::from_ref(name), state)
747 {
748 DataType::Enum(enum_id)
749 } else {
750 error_unknown_variable(name, *span, v, ctx.file_idx, state.sources);
751 }
752 }
753 Self::Float(_) => DataType::Float,
754 Self::Int(_) => DataType::Int,
755 Self::String(_) => DataType::String,
756 Self::Bool(_) | Self::Eq(_, _) | Self::NotEq(_, _) => DataType::Bool,
757 Self::Null => DataType::Null,
758 Self::Array(x, _) => DataType::Array(if x.is_empty() {
759 None
760 } else {
761 let elem_type = x
762 .iter()
763 .map(|elem| elem.infer_type(v, ctx, state))
764 .find(|elem_type| *elem_type != DataType::Unknown)
765 .unwrap_or(DataType::Unknown);
766 Some(Box::from(elem_type))
767 }),
768 Self::Map(kv_pairs, _) => {
769 if kv_pairs.is_empty() {
770 DataType::Map(Box::from((None, None)))
773 } else {
774 let kv_type = kv_pairs
775 .iter()
776 .map(|(key, _, value, _)| {
777 (
778 key.infer_type(v, ctx, state),
779 value.infer_type(v, ctx, state),
780 )
781 })
782 .find(|(key_t, val_t)| {
783 key_t != &DataType::Unknown || val_t != &DataType::Unknown
784 })
785 .map_or(
786 (Some(DataType::Unknown), Some(DataType::Unknown)),
787 |(key_t, val_t)| (Some(key_t), Some(val_t)),
788 );
789 DataType::Map(Box::from(kv_type))
790 }
791 }
792 Self::Add(x, y, span_l, span_r) => {
793 match (x.infer_type(v, ctx, state), y.infer_type(v, ctx, state)) {
794 (DataType::Unknown, t) | (t, DataType::Unknown) => t,
795 (DataType::Float, DataType::Float) => DataType::Float,
796 (DataType::Int, DataType::Int) => DataType::Int,
797 (DataType::String, DataType::String) => DataType::String,
798 (DataType::Array(t1), DataType::Array(t2)) => DataType::Array(t1.or(t2)),
799 (l, r) => {
800 error_op(&l, &r, "+", *span_l, *span_r, ctx.file_idx, state.sources);
801 }
802 }
803 }
804 Self::Mul(x, y, span_l, span_r)
805 | Self::Div(x, y, span_l, span_r)
806 | Self::Sub(x, y, span_l, span_r)
807 | Self::Mod(x, y, span_l, span_r)
808 | Self::Pow(x, y, span_l, span_r) => {
809 match (x.infer_type(v, ctx, state), y.infer_type(v, ctx, state)) {
810 (DataType::Unknown, t) | (t, DataType::Unknown)
811 if matches!(t, DataType::Float | DataType::Int | DataType::Unknown) =>
812 {
813 t
814 }
815 (DataType::Float, DataType::Float) => DataType::Float,
816 (DataType::Int, DataType::Int) => DataType::Int,
817 (l, r) => {
818 error_op(
819 &l,
820 &r,
821 symbol_of_expr(self),
822 *span_l,
823 *span_r,
824 ctx.file_idx,
825 state.sources,
826 );
827 }
828 }
829 }
830 Self::Sup(x, y, span_l, span_r)
831 | Self::SupEq(x, y, span_l, span_r)
832 | Self::Inf(x, y, span_l, span_r)
833 | Self::InfEq(x, y, span_l, span_r) => {
834 match (x.infer_type(v, ctx, state), y.infer_type(v, ctx, state)) {
835 (DataType::Unknown, DataType::Float | DataType::Int)
836 | (DataType::Float | DataType::Int, DataType::Unknown)
837 | (DataType::Float, DataType::Float)
838 | (DataType::Int, DataType::Int) => DataType::Bool,
839 (l, r) => error_op(
840 &l,
841 &r,
842 symbol_of_expr(self),
843 *span_l,
844 *span_r,
845 ctx.file_idx,
846 state.sources,
847 ),
848 }
849 }
850 Self::BoolAnd(x, y, span_l, span_r) | Self::BoolOr(x, y, span_l, span_r) => {
851 match (x.infer_type(v, ctx, state), y.infer_type(v, ctx, state)) {
852 (DataType::Unknown | DataType::Bool, DataType::Bool)
853 | (DataType::Bool, DataType::Unknown) => DataType::Bool,
854 (l, r) => {
855 error_op(&l, &r, "&&", *span_l, *span_r, ctx.file_idx, state.sources);
856 }
857 }
858 }
859 Self::Neg(e, span_l, span_r) => match e.infer_type(v, ctx, state) {
860 DataType::Float => DataType::Float,
861 DataType::Int => DataType::Int,
862 DataType::Unknown => DataType::Unknown,
863 operand_type => error_op(
864 &DataType::Null,
865 &operand_type,
866 "-",
867 *span_l,
868 *span_r,
869 ctx.file_idx,
870 state.sources,
871 ),
872 },
873 Self::BoolNeg(e, span_l, span_r) => match e.infer_type(v, ctx, state) {
874 DataType::Bool => DataType::Bool,
875 operand_type => error_op(
876 &DataType::Null,
877 &operand_type,
878 "!",
879 *span_l,
880 *span_r,
881 ctx.file_idx,
882 state.sources,
883 ),
884 },
885 Self::ArrayGetIndex(array, _, _) => match array.infer_type(v, ctx, state) {
886 DataType::Array(array_type) => array_type.map_or(DataType::Null, |t| *t),
887 DataType::String => DataType::String,
888 DataType::Unknown => DataType::Unknown,
889 _ => unsafe { unreachable_unchecked() },
890 },
891 Self::GetStructField(s, field, struct_span, field_span) => {
892 let s = s.infer_type(v, ctx, state);
893 if let DataType::Struct(s_id) = s {
894 state.structs[s_id as usize]
895 .fields
896 .iter()
897 .find(|x| &x.0 == field)
898 .unwrap_or_else(|| {
899 let s = &state.structs[s_id as usize];
900 error_struct_unknown_field(
901 ctx.file_idx,
902 *field_span,
903 field,
904 &s.name,
905 &s.fields,
906 state.sources,
907 )
908 })
909 .1
910 .clone()
911 } else {
912 error_invalid_type(
913 &DataType::Struct(0),
914 &s,
915 *struct_span,
916 None,
917 None,
918 ctx.file_idx,
919 state.sources,
920 );
921 }
922 }
923 Self::ArrayGetSlice(array, _, _, _) => match array.infer_type(v, ctx, state) {
924 DataType::Array(array_type) => DataType::Array(array_type),
925 DataType::String => DataType::String,
926 DataType::Unknown => DataType::Unknown,
927 _ => unsafe { unreachable_unchecked() },
928 },
929 Self::FunctionCall(args, namespace, span, _) => {
930 if namespace.len() >= 2
933 && let Some((enum_id, _)) =
934 crate::compiler::resolve_enum_variant(namespace, state)
935 {
936 return DataType::Enum(enum_id);
937 }
938 match namespace.last().unwrap().as_str() {
939 "print" | "write" | "append" | "delete" | "delete_dir" => DataType::Null,
940 "type" | "str" | "input" | "read" | "json_stringify" | "as_str" => {
941 DataType::String
942 }
943 "float" | "as_float" => DataType::Float,
944 "int" | "the_answer" | "as_int" => DataType::Int,
945 "bool" | "exists" | "as_bool" | "is_int" | "is_float" | "is_str"
946 | "is_bool" | "is_list" | "is_map" | "is_null" => DataType::Bool,
947 "range" => DataType::Array(Some(Box::from(DataType::Int))),
948 "argv" => DataType::Array(Some(Box::from(DataType::String))),
949 "as_list" => DataType::Array(None),
952 "as_map" => DataType::Map(Box::from((None, None))),
953 "json_parse" => DataType::Unknown,
954 function_name => {
955 if namespace.len() == 1
960 && let Some(DataType::Fn(fn_id)) = v
961 .iter()
962 .rfind(|var| var.name.as_str() == function_name)
963 .map(|var| var.var_type.clone())
964 {
965 let infered_arg_types = args
966 .iter()
967 .map(|x| x.infer_type(v, ctx, state))
968 .collect::<Vec<DataType>>();
969 return infer_user_fn_return_type(
970 fn_id as usize,
971 infered_arg_types,
972 function_name,
973 v,
974 ctx,
975 state,
976 );
977 }
978 if let Some(lib) = state.dyn_libs.iter().find(|l| l.name == namespace[0])
979 && let Some(FnSignature {
980 return_type: fn_return_type,
981 ..
982 }) = lib.fns.iter().find(|x| x.name == function_name)
983 {
984 return fn_return_type.clone();
985 }
986 let infered_arg_types = args
987 .iter()
988 .map(|x| x.infer_type(v, ctx, state))
989 .collect::<Vec<DataType>>();
990
991 let Some(fn_id) = state
992 .fns
993 .iter()
994 .rposition(|func| func.name == function_name)
995 else {
996 if let Some((enum_id, _)) =
1000 crate::compiler::resolve_enum_variant(namespace, state)
1001 {
1002 return DataType::Enum(enum_id);
1003 }
1004 if namespace.len() == 1 {
1005 error_unknown_function(
1006 function_name,
1007 *span,
1008 state.namespace,
1009 ctx.file_idx,
1010 state.sources,
1011 );
1012 } else {
1013 error_unknown_function_in_namespace(
1014 function_name,
1015 state.namespace,
1016 &namespace[..namespace.len() - 1],
1017 *span,
1018 ctx.file_idx,
1019 state.sources,
1020 );
1021 }
1022 };
1023
1024 infer_user_fn_return_type(
1025 fn_id,
1026 infered_arg_types,
1027 function_name,
1028 v,
1029 ctx,
1030 state,
1031 )
1032 }
1033 }
1034 }
1035 Self::ObjFunctionCall(obj, args, namespace, _, fn_span, _) => {
1036 let method = namespace.last().unwrap().as_str();
1037 let obj_type = obj.infer_type(v, ctx, state);
1038 if let DataType::Struct(struct_id) = obj_type {
1045 let struct_name = state.structs[struct_id as usize].name.clone();
1046 let mangled = mangle_method(&struct_name, method);
1047 if let Some(fn_id) = state.fns.iter().position(|f| f.name == mangled) {
1048 let mut arg_types: Vec<DataType> = Vec::with_capacity(args.len() + 1);
1049 arg_types.push(DataType::Struct(struct_id));
1050 for a in args {
1051 arg_types.push(a.infer_type(v, ctx, state));
1052 }
1053 return infer_user_fn_return_type(
1054 fn_id, arg_types, &mangled, v, ctx, state,
1055 );
1056 }
1057 crate::compiler::compiler_errors::error_no_such_method(
1060 method,
1061 &struct_name,
1062 *fn_span,
1063 ctx.file_idx,
1064 state.sources,
1065 );
1066 }
1067 if let DataType::Enum(enum_id) = obj_type {
1068 let enum_name = state.enums[enum_id as usize].name.clone();
1069 let mangled = mangle_method(&enum_name, method);
1070 if let Some(fn_id) = state.fns.iter().position(|f| f.name == mangled) {
1071 let mut arg_types: Vec<DataType> = Vec::with_capacity(args.len() + 1);
1072 arg_types.push(DataType::Enum(enum_id));
1073 for a in args {
1074 arg_types.push(a.infer_type(v, ctx, state));
1075 }
1076 return infer_user_fn_return_type(
1077 fn_id, arg_types, &mangled, v, ctx, state,
1078 );
1079 }
1080 crate::compiler::compiler_errors::error_no_such_method(
1081 method,
1082 &enum_name,
1083 *fn_span,
1084 ctx.file_idx,
1085 state.sources,
1086 );
1087 }
1088 if let Some(fn_id) = crate::compiler::methods::routed_list_method(
1092 method, &obj_type, args, v, ctx, state,
1093 ) {
1094 let mut arg_types: Vec<DataType> = Vec::with_capacity(args.len() + 1);
1095 arg_types.push(obj_type.clone());
1096 for a in args {
1097 arg_types.push(a.infer_type(v, ctx, state));
1098 }
1099 return infer_user_fn_return_type(fn_id, arg_types, method, v, ctx, state);
1100 }
1101 match method {
1102 "uppercase"
1103 | "lowercase"
1104 | "replace"
1105 | "trim"
1106 | "trim_sequence"
1107 | "trim_left"
1108 | "trim_right"
1109 | "trim_sequence_left"
1110 | "trim_sequence_right"
1111 | "join" => DataType::String,
1112 "starts_with" | "ends_with" | "contains" | "is_float" | "is_int" => {
1113 DataType::Bool
1114 }
1115 "len" | "find" => DataType::Int,
1116 "repeat" | "reverse" => {
1117 let obj_type = obj.infer_type(v, ctx, state);
1118 if obj_type == DataType::String {
1119 DataType::String
1120 } else if let DataType::Array(array_type) = obj_type {
1121 DataType::Array(array_type)
1122 } else {
1123 unsafe { unreachable_unchecked() }
1124 }
1125 }
1126 "push" | "sort" | "remove" | "insert" => DataType::Null,
1127 "sqrt" | "round" | "floor" => DataType::Float,
1128 "abs" => {
1129 let obj_type = obj.infer_type(v, ctx, state);
1130 if obj_type == DataType::Float {
1131 DataType::Float
1132 } else if obj_type == DataType::Int {
1133 DataType::Int
1134 } else {
1135 unsafe { unreachable_unchecked() }
1136 }
1137 }
1138 "split" => DataType::Array(Some(Box::from(DataType::String))),
1139 "partition" => {
1140 let obj_type = obj.infer_type(v, ctx, state);
1141 if let DataType::Array(array_type) = obj_type {
1142 DataType::Array(Some(Box::from(DataType::Array(array_type))))
1143 } else {
1144 unsafe { unreachable_unchecked() }
1145 }
1146 }
1147 "get" => {
1148 let obj_type = obj.infer_type(v, ctx, state);
1149 if let DataType::Map(m) = obj_type {
1150 m.1.unwrap_or(DataType::Unknown)
1151 } else {
1152 unsafe { unreachable_unchecked() }
1153 }
1154 }
1155 "keys" => {
1156 let obj_type = obj.infer_type(v, ctx, state);
1157 if let DataType::Map(m) = obj_type {
1158 DataType::Array(m.0.map(Box::new))
1159 } else {
1160 unsafe { unreachable_unchecked() }
1161 }
1162 }
1163 "values" => {
1164 let obj_type = obj.infer_type(v, ctx, state);
1165 if let DataType::Map(m) = obj_type {
1166 DataType::Array(m.1.map(Box::new))
1167 } else {
1168 unsafe { unreachable_unchecked() }
1169 }
1170 }
1171 _ => unsafe { unreachable_unchecked() },
1172 }
1173 }
1174 Self::InlineCondition(_, code, _) => {
1175 let mut types: Vec<DataType> = Vec::with_capacity(code.len());
1176 types.push(code[0].infer_type(v, ctx, state));
1177 for t in &code[0..] {
1178 if let Self::ElseIfBlock(_, code) = t {
1179 let infered = code[0].infer_type(v, ctx, state);
1180 if !types.contains(&infered) {
1181 types.push(infered);
1182 }
1183 } else if let Self::ElseBlock(code) = t {
1184 let infered = code[0].infer_type(v, ctx, state);
1185 if !types.contains(&infered) {
1186 types.push(infered);
1187 }
1188 }
1189 }
1190 DataType::Union(Box::from(types)).check_poly()
1191 }
1192 Self::NamespacedRef(path, span) => {
1193 if let Some((enum_id, _)) = crate::compiler::resolve_enum_variant(path, state) {
1194 DataType::Enum(enum_id)
1195 } else {
1196 crate::compiler::compiler_errors::error_enum(
1197 "Unknown enum variant",
1198 &format!("{} does not name an enum variant", path.join("::")),
1199 *span,
1200 ctx.file_idx,
1201 state.sources,
1202 );
1203 }
1204 }
1205 Self::Struct(namespace, _, span) => {
1206 let struct_name = &namespace[namespace.len() - 1];
1207 let namespace = &namespace[..(namespace.len() - 1)];
1208 DataType::Struct(
1209 state
1210 .namespace
1211 .find_struct(namespace, struct_name, *span, ctx.file_idx, state.sources)
1212 .unwrap_or_else(|| {
1213 error_unknown_struct(struct_name, *span, state.sources, ctx.file_idx);
1214 }) as u16,
1215 )
1216 }
1217 Self::AnonymousFunction(args, code, span) => {
1218 let fn_name =
1224 format_args!("{ANON_FN_PREFIX}{}:{}", span.start, span.end).to_smolstr();
1225 if let Some(id) = state.fns.iter().rposition(|f| f.name == fn_name) {
1226 return DataType::Fn(id as u16);
1227 }
1228 let returns_null = check_if_returns_void(code);
1229 let mut callees = Vec::new();
1230 collect_direct_fn_calls(code, &mut callees);
1231 let id = state.fns.len() as u16;
1232 state.fns.push(Function {
1233 name: fn_name,
1234 args: args.iter().map(|a| (a.clone(), None)).collect(),
1235 code: Rc::from(code.clone()),
1236 impls: Vec::new(),
1237 is_recursive: None,
1238 returns_null,
1239 src_file: ctx.file_idx,
1240 return_type_cache: Vec::new(),
1241 direct_calls: callees.into_boxed_slice(),
1242 name_span: *span,
1243 return_type: None,
1245 });
1246 state.fn_registers.push(Vec::new());
1247 DataType::Fn(id)
1248 }
1249 _ => unsafe { unreachable_unchecked() },
1250 }
1251 }
1252}