1use std::{
2 borrow::Cow,
3 collections::{HashMap, HashSet},
4 vec,
5};
6
7use rush_parser::{ast::*, Span};
8
9use crate::{ast::*, Diagnostic, DiagnosticLevel, ErrorKind};
10
11#[derive(Default, Debug)]
12pub struct Analyzer<'src> {
13 functions: HashMap<&'src str, Function<'src>>,
14 diagnostics: Vec<Diagnostic<'src>>,
15 builtin_functions: HashMap<&'static str, BuiltinFunction>,
16 scopes: Vec<HashMap<&'src str, Variable<'src>>>,
17 curr_func_name: &'src str,
18 used_builtins: HashSet<&'src str>,
20 loop_count: usize,
22 current_loop_is_terminated: bool,
24 source: &'src str,
26}
27
28#[derive(Debug)]
29struct Function<'src> {
30 pub ident: Spanned<'src, &'src str>,
31 pub params: Spanned<'src, Vec<Parameter<'src>>>,
32 pub return_type: Spanned<'src, Option<Type>>,
33 pub used: bool,
34}
35
36#[derive(Debug, Clone)]
37struct BuiltinFunction {
38 param_types: Vec<Type>,
39 return_type: Type,
40}
41
42impl BuiltinFunction {
43 fn new(param_types: Vec<Type>, return_type: Type) -> Self {
44 Self {
45 param_types,
46 return_type,
47 }
48 }
49}
50
51#[derive(Debug)]
52struct Variable<'src> {
53 pub type_: Type,
54 pub span: Span<'src>,
55 pub used: bool,
56 pub mutable: bool,
57 pub mutated: bool,
58}
59
60impl<'src> Analyzer<'src> {
61 pub fn new(source: &'src str) -> Self {
63 Self {
64 builtin_functions: HashMap::from([(
65 "exit",
66 BuiltinFunction::new(vec![Type::Int(0)], Type::Never),
67 )]),
68 source,
69 scopes: vec![HashMap::new()], ..Default::default()
71 }
72 }
73
74 fn hint(&mut self, message: impl Into<Cow<'static, str>>, span: Span<'src>) {
76 self.diagnostics.push(Diagnostic::new(
77 DiagnosticLevel::Hint,
78 message,
79 vec![],
80 span,
81 self.source,
82 ))
83 }
84
85 fn info(
87 &mut self,
88 message: impl Into<Cow<'static, str>>,
89 notes: Vec<Cow<'static, str>>,
90 span: Span<'src>,
91 ) {
92 self.diagnostics.push(Diagnostic::new(
93 DiagnosticLevel::Info,
94 message,
95 notes,
96 span,
97 self.source,
98 ))
99 }
100
101 fn warn(
103 &mut self,
104 message: impl Into<Cow<'static, str>>,
105 notes: Vec<Cow<'static, str>>,
106 span: Span<'src>,
107 ) {
108 self.diagnostics.push(Diagnostic::new(
109 DiagnosticLevel::Warning,
110 message,
111 notes,
112 span,
113 self.source,
114 ))
115 }
116
117 fn error(
119 &mut self,
120 kind: ErrorKind,
121 message: impl Into<Cow<'static, str>>,
122 notes: Vec<Cow<'static, str>>,
123 span: Span<'src>,
124 ) {
125 self.diagnostics.push(Diagnostic::new(
126 DiagnosticLevel::Error(kind),
127 message,
128 notes,
129 span,
130 self.source,
131 ))
132 }
133
134 pub fn analyze(
136 mut self,
137 program: Program<'src>,
138 ) -> Result<(AnalyzedProgram<'src>, Vec<Diagnostic>), Vec<Diagnostic>> {
139 for func in &program.functions {
141 if let Some(prev_def) = self.functions.get(func.name.inner) {
143 let prev_def_span = prev_def.ident.span;
144 self.error(
145 ErrorKind::Semantic,
146 format!("duplicate function definition `{}`", func.name.inner),
147 vec![],
148 func.name.span,
149 );
150 self.hint(
151 format!("function `{}` previously defined here", func.name.inner),
152 prev_def_span,
153 );
154 }
155 self.functions.insert(
156 func.name.inner,
157 Function {
158 ident: func.name.clone(),
159 params: func.params.clone(),
160 return_type: func.return_type.clone(),
161 used: false,
162 },
163 );
164 }
165
166 #[allow(clippy::needless_collect)]
169 let globals: Vec<AnalyzedLetStmt> = program
170 .globals
171 .into_iter()
172 .map(|node| self.global(node))
173 .collect();
174
175 let mut functions = vec![];
177 let mut main_fn = None;
178 for func in program.functions {
179 let func = self.function_definition(func);
180 match func.name {
181 "main" => {
182 main_fn = Some(func.block);
183 }
184 _ => functions.push(func),
185 }
186 }
187
188 let (unused_globals, non_mut_globals) = self.pop_scope();
190 let globals: Vec<AnalyzedLetStmt> = globals
191 .into_iter()
192 .map(|g| AnalyzedLetStmt {
193 used: !unused_globals.contains(&g.name),
194 mutable: g.mutable && !non_mut_globals.contains(&g.name),
195 ..g
196 })
197 .collect();
198
199 let unused_funcs: Vec<_> = self
201 .functions
202 .values()
203 .filter(|func| {
204 func.ident.inner != "main" && !func.ident.inner.starts_with('_') && !func.used
205 })
206 .map(|func| {
207 functions
209 .iter_mut()
210 .find(|func_def| func_def.name == func.ident.inner)
211 .expect("every unused function is defined")
212 .used = false;
213
214 func.ident.clone()
215 })
216 .collect();
217
218 for ident in unused_funcs {
220 self.warn(
221 format!("function `{}` is never called", ident.inner),
222 vec![format!(
223 "if this is intentional, change the name to `_{}` to hide this warning",
224 ident.inner,
225 )
226 .into()],
227 ident.span,
228 )
229 }
230
231 match main_fn {
232 Some(main_fn) => Ok((
233 AnalyzedProgram {
234 globals,
235 functions,
236 main_fn,
237 used_builtins: self.used_builtins,
238 },
239 self.diagnostics,
240 )),
241 None => {
242 self.error(
243 ErrorKind::Semantic,
244 "missing `main` function",
245 vec![
246 "the `main` function can be implemented like this: `fn main() { ... }`"
247 .into(),
248 ],
249 program.span.start.until(program.span.start),
251 );
252 Err(self.diagnostics)
253 }
254 }
255 }
256
257 fn push_scope(&mut self) {
258 self.scopes.push(HashMap::new());
259 }
260
261 fn pop_scope(&mut self) -> (Vec<&'src str>, Vec<&'src str>) {
266 let scope = self.scopes.pop().expect("is only called after a scope");
268
269 let mut unused = vec![];
270 let mut non_mut = vec![];
271
272 for (name, var) in scope {
274 if !name.starts_with('_') && !var.used {
276 unused.push(name);
277 self.warn(
278 format!("unused variable `{}`", name),
279 vec![format!(
280 "if this is intentional, change the name to `_{name}` to hide this warning"
281 )
282 .into()],
283 var.span,
284 );
285 } else if var.mutable && !var.mutated {
286 non_mut.push(name);
287 self.info(
288 format!("variable `{name}` does not need to be mutable"),
289 vec![],
290 var.span,
291 );
292 }
293 }
294
295 (unused, non_mut)
296 }
297
298 fn scope_mut(&mut self) -> &mut HashMap<&'src str, Variable<'src>> {
300 self.scopes.last_mut().expect("only called in scopes")
301 }
302
303 fn warn_unreachable(
304 &mut self,
305 unreachable_span: Span<'src>,
306 causing_span: Span<'src>,
307 expr: bool,
308 ) {
309 self.warn(
310 match expr {
311 true => "unreachable expression",
312 false => "unreachable statement",
313 },
314 vec![],
315 unreachable_span,
316 );
317 self.hint(
318 "any code following this expression is unreachable",
319 causing_span,
320 );
321 }
322
323 fn global(&mut self, node: LetStmt<'src>) -> AnalyzedLetStmt<'src> {
324 let expr_span = node.expr.span();
326 let expr = self.expression(node.expr);
327
328 if !expr.constant() {
330 self.error(
331 ErrorKind::Semantic,
332 "global initializer is not constant",
333 vec!["global variables must have a constant initializer".into()],
334 expr_span,
335 );
336 }
337
338 if let Some(declared) = &node.type_ {
340 if declared.inner != expr.result_type()
341 && !matches!(expr.result_type(), Type::Unknown | Type::Never)
342 {
343 self.error(
344 ErrorKind::Type,
345 format!(
346 "mismatched types: expected `{}`, found `{}`",
347 declared.inner,
348 expr.result_type(),
349 ),
350 vec![],
351 expr_span,
352 );
353 self.hint("expected due to this", declared.span);
354 }
355 }
356
357 if let Some(prev) = self.scopes[0].get(node.name.inner) {
359 let prev_span = prev.span;
360 self.error(
361 ErrorKind::Semantic,
362 format!("duplicate definition of global `{}`", node.name.inner),
363 vec![],
364 node.name.span,
365 );
366 self.hint(
367 format!("previous definition of global `{}` here", node.name.inner),
368 prev_span,
369 );
370 } else {
371 self.scopes[0].insert(
372 node.name.inner,
373 Variable {
374 type_: match expr.constant() {
377 true => node.type_.map_or(expr.result_type(), |type_| type_.inner),
378 false => Type::Unknown,
379 },
380 span: node.name.span,
381 used: false,
382 mutable: node.mutable,
383 mutated: false,
384 },
385 );
386 }
387
388 AnalyzedLetStmt {
389 name: node.name.inner,
390 expr,
391 mutable: node.mutable,
392 used: false,
393 }
394 }
395
396 fn function_definition(
397 &mut self,
398 node: FunctionDefinition<'src>,
399 ) -> AnalyzedFunctionDefinition<'src> {
400 self.curr_func_name = node.name.inner;
402
403 if node.name.inner == "main" {
404 if !node.params.inner.is_empty() {
406 self.error(
407 ErrorKind::Semantic,
408 format!(
409 "the `main` function must have 0 parameters, however {} {} defined",
410 node.params.inner.len(),
411 match node.params.inner.len() {
412 1 => "is",
413 _ => "are",
414 },
415 ),
416 vec!["remove the parameters: `fn main() { ... }`".into()],
417 node.params.span,
418 )
419 }
420
421 if let Some(return_type) = node.return_type.inner {
423 if return_type != Type::Unit {
424 self.error(
425 ErrorKind::Semantic,
426 format!(
427 "the `main` function's return type must be `()`, but is declared as `{}`",
428 return_type,
429 ),
430 vec!["remove the return type: `fn main() { ... }`".into()],
431 node.return_type.span,
432 )
433 }
434 }
435 }
436
437 if node.return_type.inner == Some(Type::Unit) {
439 self.info(
440 "unnecessary explicit unit return type",
441 vec![
442 "functions implicitly return `()` by default".into(),
443 format!(
444 "remove the explicit type: `fn {}(...) {{ ... }}`",
445 node.name.inner,
446 )
447 .into(),
448 ],
449 node.return_type.span,
450 );
451 }
452
453 self.push_scope();
455
456 let mut params = vec![];
458 let mut param_names = HashSet::new();
459
460 for param in node.params.inner {
462 if !param_names.insert(param.name.inner) && node.name.inner != "main" {
464 self.error(
465 ErrorKind::Semantic,
466 format!("duplicate parameter name `{}`", param.name.inner),
467 vec![],
468 param.name.span,
469 );
470 }
471 self.scope_mut().insert(
472 param.name.inner,
473 Variable {
474 type_: param.type_.inner,
475 span: param.name.span,
476 used: false,
477 mutable: param.mutable,
478 mutated: false,
479 },
480 );
481 params.push(AnalyzedParameter {
482 mutable: param.mutable,
483 name: param.name.inner,
484 type_: param.type_.inner,
485 });
486 }
487
488 let block_result_span = node.block.result_span();
490 let block = self.block(node.block, false);
491
492 if block.result_type != node.return_type.inner.unwrap_or(Type::Unit)
494 && !matches!(block.result_type, Type::Unknown | Type::Never)
496 {
497 self.error(
498 ErrorKind::Type,
499 format!(
500 "mismatched types: expected `{}`, found `{}`",
501 node.return_type.inner.unwrap_or(Type::Unit),
502 block.result_type,
503 ),
504 match node.return_type.inner.is_some() {
505 true => vec![],
506 false => vec![format!(
507 "specify a function return type like this: `fn {}(...) -> {} {{ ... }}`",
508 node.name.inner, block.result_type,
509 )
510 .into()],
511 },
512 block_result_span,
513 );
514 self.hint(
515 match node.return_type.inner.is_some() {
516 true => "function return type defined here",
517 false => "no explicit return type specified",
518 },
519 node.return_type.span,
520 );
521 }
522
523 self.pop_scope();
525
526 if params.len() > 6 {
528 self.warn(
529 "function takes more than 6 parameters".to_string(),
530 vec!["using more than 6 parameters will be slower on some backends".into()],
531 node.params.span,
532 )
533 }
534
535 AnalyzedFunctionDefinition {
536 used: true, name: node.name.inner,
538 params,
539 return_type: node.return_type.inner.unwrap_or(Type::Unit),
540 block,
541 }
542 }
543
544 fn block(&mut self, node: Block<'src>, new_scope: bool) -> AnalyzedBlock<'src> {
545 if new_scope {
546 self.push_scope();
547 }
548
549 let mut stmts = vec![];
550
551 let mut never_type_span = None;
552 let mut warned_unreachable = false;
553
554 for stmt in node.stmts {
555 if let Some(span) = never_type_span {
556 if !warned_unreachable {
557 self.warn("unreachable statement", vec![], stmt.span());
558 self.hint("any code following this statement is unreachable", span);
559 warned_unreachable = true;
560 }
561 }
562 let stmt_span = stmt.span();
563 if let Some(stmt) = self.statement(stmt) {
564 if stmt.result_type() == Type::Never {
565 never_type_span = Some(stmt_span);
566 }
567 stmts.push(stmt);
568 }
569 }
570
571 if let (Some(expr), Some(span), false) = (&node.expr, never_type_span, warned_unreachable) {
573 self.warn("unreachable expression", vec![], expr.span());
574 self.hint("any code following this statement is unreachable", span);
575 }
576
577 let expr = node.expr.map(|expr| self.expression(expr));
579
580 let result_type = match never_type_span {
582 Some(_) => Type::Never,
583 None => expr.as_ref().map_or(Type::Unit, |expr| expr.result_type()),
584 };
585
586 if new_scope {
587 self.pop_scope();
588 }
589
590 AnalyzedBlock {
591 result_type,
592 stmts,
593 expr,
594 }
595 }
596
597 fn statement(&mut self, node: Statement<'src>) -> Option<AnalyzedStatement<'src>> {
600 Some(match node {
601 Statement::Let(node) => self.let_stmt(node),
602 Statement::Return(node) => self.return_stmt(node),
603 Statement::Loop(node) => self.loop_stmt(node),
604 Statement::While(node) => return self.while_stmt(node),
605 Statement::For(node) => self.for_stmt(node),
606 Statement::Break(node) => self.break_stmt(node),
607 Statement::Continue(node) => self.continue_stmt(node),
608 Statement::Expr(node) => AnalyzedStatement::Expr(self.expression(node.expr)),
609 })
610 }
611
612 fn let_stmt(&mut self, node: LetStmt<'src>) -> AnalyzedStatement<'src> {
613 let expr_span = node.expr.span();
615
616 let expr = self.expression(node.expr);
618
619 if let Some(declared) = &node.type_ {
621 if declared.inner != expr.result_type()
622 && !matches!(expr.result_type(), Type::Unknown | Type::Never)
623 {
624 self.error(
625 ErrorKind::Type,
626 format!(
627 "mismatched types: expected `{}`, found `{}`",
628 declared.inner,
629 expr.result_type(),
630 ),
631 vec![],
632 expr_span,
633 );
634 self.hint("expected due to this", declared.span);
635 }
636 }
637
638 if expr.result_type() == Type::Never {
640 self.warn_unreachable(node.span, expr_span, false);
641 }
642
643 if let Some(old) = self.scope_mut().insert(
645 node.name.inner,
646 Variable {
647 type_: match node.type_.map_or(expr.result_type(), |type_| type_.inner) {
648 Type::Never => Type::Unknown,
650 type_ => type_,
651 },
652 span: node.name.span,
653 used: false,
654 mutable: node.mutable,
655 mutated: false,
656 },
657 ) {
658 if !old.used && !node.name.inner.starts_with('_') {
660 self.warn(
661 format!("unused variable `{}`", node.name.inner),
662 vec![format!(
663 "if this is intentional, change the name to `_{}` to hide this warning",
664 node.name.inner
665 )
666 .into()],
667 old.span,
668 );
669 self.hint(
670 format!("variable `{}` shadowed here", node.name.inner),
671 node.name.span,
672 );
673 } else if old.mutable && !old.mutated {
674 self.info(
675 format!("variable `{}` does not need to be mutable", node.name.inner),
676 vec![],
677 old.span,
678 );
679 }
680 }
681
682 AnalyzedStatement::Let(AnalyzedLetStmt {
683 name: node.name.inner,
684 expr,
685 mutable: node.mutable,
686 used: true,
687 })
688 }
689
690 fn return_stmt(&mut self, node: ReturnStmt<'src>) -> AnalyzedStatement<'src> {
691 let expr_span = node.expr.as_ref().map(|expr| expr.span());
693 let expr = node.expr.map(|expr| self.expression(expr));
694
695 let expr_type = expr.as_ref().map_or(Type::Unit, |expr| expr.result_type());
697
698 if expr_type == Type::Never {
699 self.warn_unreachable(
700 node.span,
701 expr_span.expect("the never type was caused by an expression"),
702 false,
703 );
704 }
705
706 let curr_fn = &self.functions[self.curr_func_name];
707
708 if curr_fn.return_type.inner.unwrap_or(Type::Unit) != expr_type
710 && !matches!(expr_type, Type::Unknown | Type::Never)
712 {
713 let fn_type_span = curr_fn.return_type.span;
714 let fn_type_explicit = curr_fn.return_type.inner.is_some();
715
716 self.error(
717 ErrorKind::Type,
718 format!(
719 "mismatched types: expected `{}`, found `{}`",
720 curr_fn.return_type.inner.unwrap_or(Type::Unit),
721 expr_type
722 ),
723 vec![],
724 node.span,
725 );
726 self.hint(
727 match fn_type_explicit {
728 true => "function return type defined here",
729 false => "no explicit return type specified",
730 },
731 fn_type_span,
732 );
733 }
734
735 AnalyzedStatement::Return(expr)
736 }
737
738 fn loop_stmt(&mut self, node: LoopStmt<'src>) -> AnalyzedStatement<'src> {
739 let old_loop_is_terminated = self.current_loop_is_terminated;
740
741 self.loop_count += 1;
742 let block_result_span = node.block.result_span();
743 let block = self.block(node.block, true);
744 self.loop_count -= 1;
745
746 if !matches!(block.result_type, Type::Unit | Type::Never | Type::Unknown) {
747 self.error(
748 ErrorKind::Type,
749 format!(
750 "loop-statement requires a block of type `()` or `!`, found `{}`",
751 block.result_type
752 ),
753 vec![],
754 block_result_span,
755 );
756 }
757
758 let never_terminates = !self.current_loop_is_terminated;
760 self.current_loop_is_terminated = old_loop_is_terminated;
761
762 AnalyzedStatement::Loop(AnalyzedLoopStmt {
763 block,
764 never_terminates,
765 })
766 }
767
768 fn while_stmt(&mut self, node: WhileStmt<'src>) -> Option<AnalyzedStatement<'src>> {
772 let mut condition_is_const_true = false;
773 let mut never_loops = false;
774
775 let cond_span = node.cond.span();
776 let cond = self.expression(node.cond);
777
778 if !matches!(
780 cond.result_type(),
781 Type::Bool(0) | Type::Never | Type::Unknown
782 ) {
783 self.error(
784 ErrorKind::Type,
785 format!(
786 "expected value of type `bool`, found `{}`",
787 cond.result_type()
788 ),
789 vec!["a condition must have the type `bool`".into()],
790 cond_span,
791 )
792 } else {
793 if cond.constant() {
795 let cond_val = match cond {
796 AnalyzedExpression::Bool(true) => {
797 condition_is_const_true = true;
798 true
799 }
800 AnalyzedExpression::Bool(false) => {
801 never_loops = true;
802 false
803 }
804 _ => unreachable!("type is checked above and expr is constant"),
805 };
806 self.warn(
807 format!("redundant while-statement: condition is always {cond_val}"),
808 match cond_val {
809 true => vec!["for unconditional loops, use a loop-statement".into()],
810 false => vec![
811 "since the condition is `false`, the loop will never iterate".into(),
812 ],
813 },
814 cond_span,
815 )
816 }
817 }
818
819 let old_loop_is_terminated = self.current_loop_is_terminated;
820
821 self.loop_count += 1;
822 let block_result_span = node.block.result_span();
823 let body_is_empty = node.block.stmts.is_empty() && node.block.expr.is_none();
824 let block = self.block(node.block, true);
825 self.loop_count -= 1;
826
827 if body_is_empty {
828 self.warn(
829 "empty loop body",
830 vec!["empty loop wastes CPU cycles".into()],
831 node.span,
832 )
833 }
834
835 if !matches!(block.result_type, Type::Unit | Type::Never | Type::Unknown) {
836 self.error(
837 ErrorKind::Type,
838 format!(
839 "while-statement requires a block of type `()` or `!`, found `{}`",
840 block.result_type
841 ),
842 vec![],
843 block_result_span,
844 );
845 }
846
847 let never_terminates = condition_is_const_true && !self.current_loop_is_terminated;
849 self.current_loop_is_terminated = old_loop_is_terminated;
850
851 match (never_loops, condition_is_const_true) {
852 (true, _) => None,
854 (false, true) => Some(AnalyzedStatement::Loop(AnalyzedLoopStmt {
856 block,
857 never_terminates,
858 })),
859 (false, false) => Some(AnalyzedStatement::While(AnalyzedWhileStmt {
861 cond,
862 block,
863 never_terminates,
864 })),
865 }
866 }
867
868 fn for_stmt(&mut self, node: ForStmt<'src>) -> AnalyzedStatement<'src> {
869 let mut never_terminates = false;
870
871 self.push_scope();
873
874 let initializer = self.expression(node.initializer);
876 self.scope_mut().insert(
877 node.ident.inner,
878 Variable {
879 type_: initializer.result_type(),
880 span: node.ident.span,
881 used: false,
882 mutable: true,
883 mutated: true,
885 },
886 );
887
888 let cond_span = node.cond.span();
890 let cond = self.expression(node.cond);
891
892 if !matches!(
893 cond.result_type(),
894 Type::Bool(0) | Type::Never | Type::Unknown
895 ) {
896 self.error(
897 ErrorKind::Type,
898 format!(
899 "expected value of type `bool`, found `{}`",
900 cond.result_type()
901 ),
902 vec!["a condition must have the type `bool`".into()],
903 cond_span,
904 )
905 } else {
906 if cond.constant() {
908 let cond_val = match cond {
909 AnalyzedExpression::Bool(true) => {
910 never_terminates = true;
911 true
912 }
913 AnalyzedExpression::Bool(false) => false,
914 _ => unreachable!("type is checked above and expr is constant"),
915 };
916 self.warn(
917 format!("redundant for-statement: condition is always {cond_val}",),
918 match cond_val {
919 true => vec!["for unconditional loops, use a loop-statement".into()],
920 false => vec![
921 "since the condition is `false`, the loop will never iterate".into(),
922 ],
923 },
924 cond_span,
925 )
926 }
927 }
928
929 let upd_span = node.update.span();
931 let update = self.expression(node.update);
932 if !matches!(
933 update.result_type(),
934 Type::Unit | Type::Never | Type::Unknown
935 ) {
936 self.error(
937 ErrorKind::Type,
938 format!(
939 "expected value of type `()`, found `{}`",
940 update.result_type()
941 ),
942 vec!["an update expression must have the type `()` or `!`".into()],
943 upd_span,
944 )
945 }
946
947 let old_loop_is_terminated = self.current_loop_is_terminated;
949
950 self.loop_count += 1;
951 let block_result_span = node.block.result_span();
952 let block = self.block(node.block, false);
953 self.pop_scope();
954 self.loop_count -= 1;
955
956 let never_terminates = never_terminates && !self.current_loop_is_terminated;
958 self.current_loop_is_terminated = old_loop_is_terminated;
959
960 if !matches!(block.result_type, Type::Unit | Type::Never | Type::Unknown) {
961 self.error(
962 ErrorKind::Type,
963 format!(
964 "for-statement requires a block of type `()` or `!`, found `{}`",
965 block.result_type
966 ),
967 vec![],
968 block_result_span,
969 );
970 }
971
972 AnalyzedStatement::For(AnalyzedForStmt {
973 ident: node.ident.inner,
974 initializer,
975 cond,
976 update,
977 block,
978 never_terminates,
979 })
980 }
981
982 fn break_stmt(&mut self, node: BreakStmt<'src>) -> AnalyzedStatement<'src> {
983 if self.loop_count == 0 {
984 self.error(
985 ErrorKind::Semantic,
986 "`break` outside of loop",
987 vec![],
988 node.span,
989 );
990 }
991 self.current_loop_is_terminated = true;
992 AnalyzedStatement::Break
993 }
994
995 fn continue_stmt(&mut self, node: ContinueStmt<'src>) -> AnalyzedStatement<'src> {
996 if self.loop_count == 0 {
997 self.error(
998 ErrorKind::Semantic,
999 "`continue` outside of loop",
1000 vec![],
1001 node.span,
1002 );
1003 }
1004 AnalyzedStatement::Continue
1005 }
1006
1007 fn expression(&mut self, node: Expression<'src>) -> AnalyzedExpression<'src> {
1008 let res = match node {
1009 Expression::Block(node) => self.block_expr(*node),
1010 Expression::If(node) => self.if_expr(*node),
1011 Expression::Int(node) => AnalyzedExpression::Int(node.inner),
1012 Expression::Float(node) => AnalyzedExpression::Float(node.inner),
1013 Expression::Bool(node) => AnalyzedExpression::Bool(node.inner),
1014 Expression::Char(node) => {
1015 if node.inner > 0x7f {
1016 self.error(
1017 ErrorKind::Type,
1018 "char literal out of range".to_string(),
1019 vec![
1020 format!("allowed range is `0x00..=0x7f`, got `0x{:x}`", node.inner)
1021 .into(),
1022 ],
1023 node.span,
1024 )
1025 }
1026 AnalyzedExpression::Char(node.inner)
1027 }
1028 Expression::Ident(node) => self.ident_expr(node),
1029 Expression::Prefix(node) => self.prefix_expr(*node),
1030 Expression::Infix(node) => self.infix_expr(*node),
1031 Expression::Assign(node) => self.assign_expr(*node),
1032 Expression::Call(node) => self.call_expr(*node),
1033 Expression::Cast(node) => self.cast_expr(*node),
1034 Expression::Grouped(node) => {
1035 let expr = self.expression(*node.inner);
1036 match expr.as_constant() {
1037 Some(expr) => expr,
1038 None => AnalyzedExpression::Grouped(expr.into()),
1039 }
1040 }
1041 };
1042
1043 if res.result_type() == Type::Never {
1045 self.current_loop_is_terminated = true;
1046 }
1047
1048 res
1049 }
1050
1051 fn block_expr(&mut self, node: Block<'src>) -> AnalyzedExpression<'src> {
1052 let block = self.block(node, true);
1053
1054 match Self::eval_block(&block) {
1055 Some(expr) => expr,
1056 None => AnalyzedExpression::Block(block.into()),
1057 }
1058 }
1059
1060 fn eval_block(block: &AnalyzedBlock<'src>) -> Option<AnalyzedExpression<'src>> {
1061 if block.stmts.iter().all(|stmt| stmt.constant()) {
1062 if let Some(expr) = block.expr.as_ref().and_then(|expr| expr.as_constant()) {
1063 return Some(expr);
1064 }
1065 }
1066 None
1067 }
1068
1069 fn if_expr(&mut self, node: IfExpr<'src>) -> AnalyzedExpression<'src> {
1070 let cond_span = node.cond.span();
1071 let cond = self.expression(node.cond);
1072
1073 if !matches!(
1075 cond.result_type(),
1076 Type::Bool(0) | Type::Never | Type::Unknown
1077 ) {
1078 self.error(
1079 ErrorKind::Type,
1080 format!(
1081 "expected value of type `bool`, found `{}`",
1082 cond.result_type()
1083 ),
1084 vec!["a condition must have the type `bool`".into()],
1085 cond_span,
1086 )
1087 } else {
1088 if cond.constant() {
1090 self.warn(
1091 format!(
1092 "redundant if-expression: condition is always {}",
1093 match cond {
1094 AnalyzedExpression::Bool(true) => "true",
1095 AnalyzedExpression::Bool(false) => "false",
1096 _ => unreachable!("type is checked above and expr is constant"),
1097 }
1098 ),
1099 vec![],
1100 cond_span,
1101 )
1102 }
1103 }
1104
1105 let then_result_span = node.then_block.result_span();
1107 let then_block = self.block(node.then_block, true);
1108
1109 let result_type;
1111 let else_block = match node.else_block {
1112 Some(else_block) => {
1113 let else_result_span = else_block.result_span();
1114 let else_block = self.block(else_block, true);
1115
1116 result_type = match (then_block.result_type, else_block.result_type) {
1118 (Type::Unknown, _) | (_, Type::Unknown) => Type::Unknown,
1120 (Type::Never, Type::Never) => Type::Never,
1122 (type_, Type::Never) | (Type::Never, type_) => type_,
1124 (then_type, else_type) if then_type == else_type => then_type,
1126 _ => {
1128 self.error(
1129 ErrorKind::Type,
1130 format!(
1131 "mismatched types: expected `{}`, found `{}`",
1132 then_block.result_type, else_block.result_type
1133 ),
1134 vec!["the `if` and `else` branches must result in the same type".into()],
1135 else_result_span,
1136 );
1137 self.hint("expected due to this", then_result_span);
1138 Type::Unknown
1139 }
1140 };
1141
1142 Some(else_block)
1143 }
1144 None => {
1145 result_type = match then_block.result_type {
1146 Type::Unknown => Type::Unknown,
1147 Type::Unit | Type::Never => Type::Unit,
1148 _ => {
1149 self.error(
1150 ErrorKind::Type,
1151 format!(
1152 "mismatched types: missing else branch with `{}` result type",
1153 then_block.result_type
1154 ),
1155 vec![format!("the `if` branch results in `{}`, therefore an else branch was expected", then_block.result_type).into()],
1156 node.span,
1157 );
1158 Type::Unknown
1159 }
1160 };
1161
1162 None
1163 }
1164 };
1165
1166 match (
1168 cond.as_constant(),
1169 Self::eval_block(&then_block),
1170 else_block.as_ref().and_then(Self::eval_block),
1171 ) {
1172 (Some(AnalyzedExpression::Bool(true)), Some(val), Some(_)) => return val,
1173 (Some(AnalyzedExpression::Bool(false)), Some(_), Some(val)) => return val,
1174 _ => {}
1175 }
1176
1177 AnalyzedExpression::If(
1178 AnalyzedIfExpr {
1179 result_type,
1180 cond,
1181 then_block,
1182 else_block,
1183 }
1184 .into(),
1185 )
1186 }
1187
1188 fn ident_expr(&mut self, node: Spanned<'src, &'src str>) -> AnalyzedExpression<'src> {
1191 for scope in self.scopes.iter_mut().rev() {
1192 if let Some(var) = scope.get_mut(node.inner) {
1193 var.used = true;
1194 return AnalyzedExpression::Ident(AnalyzedIdentExpr {
1195 result_type: var.type_,
1196 ident: node.inner,
1197 });
1198 };
1199 }
1200
1201 if !node.inner.is_empty() {
1203 self.error(
1204 ErrorKind::Reference,
1205 format!("use of undeclared variable `{}`", node.inner),
1206 vec![],
1207 node.span,
1208 );
1209 }
1210
1211 AnalyzedExpression::Ident(AnalyzedIdentExpr {
1212 result_type: Type::Unknown,
1213 ident: node.inner,
1214 })
1215 }
1216
1217 fn prefix_expr(&mut self, node: PrefixExpr<'src>) -> AnalyzedExpression<'src> {
1218 let expr_span = node.expr.span();
1219 let expr = self.expression(node.expr);
1220
1221 let result_type = match node.op {
1222 PrefixOp::Not => match expr.result_type() {
1223 Type::Bool(0) => Type::Bool(0),
1224 Type::Int(0) => Type::Int(0),
1225 Type::Unknown => Type::Unknown,
1226 Type::Never => {
1227 self.warn_unreachable(node.span, expr_span, true);
1228 Type::Never
1229 }
1230 _ => {
1231 self.error(
1232 ErrorKind::Type,
1233 format!(
1234 "prefix operator `!` does not allow values of type `{}`",
1235 expr.result_type()
1236 ),
1237 vec![],
1238 node.span,
1239 );
1240 Type::Unknown
1241 }
1242 },
1243 PrefixOp::Neg => match expr.result_type() {
1244 Type::Int(0) => Type::Int(0),
1245 Type::Float(0) => Type::Float(0),
1246 Type::Unknown => Type::Unknown,
1247 Type::Never => {
1248 self.warn_unreachable(node.span, expr_span, true);
1249 Type::Never
1250 }
1251 _ => {
1252 self.error(
1253 ErrorKind::Type,
1254 format!(
1255 "prefix operator `-` does not allow values of type `{}`",
1256 expr.result_type()
1257 ),
1258 vec![],
1259 node.span,
1260 );
1261 Type::Unknown
1262 }
1263 },
1264 PrefixOp::Ref => match &expr {
1265 AnalyzedExpression::Ident(ident) => match ident.result_type.add_ref() {
1266 Some(res) => {
1267 let mut var = self
1268 .scopes
1269 .iter_mut()
1270 .rev()
1271 .find_map(|s| s.get_mut(ident.ident))
1272 .expect("variable references are valid here");
1273
1274 var.mutated = true;
1276
1277 let var_span = var.span;
1279 if !var.mutable {
1280 self.error(
1281 ErrorKind::Semantic,
1282 format!("cannot reference immutable variable `{}`", ident.ident),
1283 vec!["only mutable variables can be referenced".into()],
1284 node.span,
1285 );
1286 self.hint("variable not declared as `mut`", var_span);
1287 }
1288
1289 res
1290 }
1291 None if ident.result_type == Type::Unknown => Type::Unknown,
1292 None => {
1293 self.error(
1294 ErrorKind::Type,
1295 format!("cannot reference a value of type `{}`", ident.result_type),
1296 vec![],
1297 node.span,
1298 );
1299 Type::Unknown
1300 }
1301 },
1302 _ => unreachable!("parser guarantees that only identifiers are referenced"),
1303 },
1304 PrefixOp::Deref => match &expr {
1305 AnalyzedExpression::Ident(ident) => match ident.result_type.sub_deref() {
1307 Some(res) => res,
1308 None => {
1309 self.error(
1310 ErrorKind::Type,
1311 format!("cannot dereference a value of type `{}`", ident.result_type),
1312 vec!["only pointers `*` can be dereferenced".into()],
1313 node.span,
1314 );
1315 dbg!(ident);
1316 Type::Unknown
1317 }
1318 },
1319 AnalyzedExpression::Prefix(expr) => match expr.result_type.sub_deref() {
1320 Some(res) => res,
1321 None => {
1322 self.error(
1323 ErrorKind::Type,
1324 format!("cannot dereference a value of type `{}`", expr.result_type),
1325 vec!["only pointers `*` can be dereferenced".into()],
1326 node.span,
1327 );
1328 Type::Unknown
1329 }
1330 },
1331 _ => unreachable!("can only dereference identifiers or prefix expressions"),
1332 },
1333 };
1334
1335 match (&expr, node.op) {
1337 (AnalyzedExpression::Int(num), PrefixOp::Not) => return AnalyzedExpression::Int(!num),
1338 (AnalyzedExpression::Int(num), PrefixOp::Neg) => {
1339 return AnalyzedExpression::Int(num.wrapping_neg())
1340 }
1341 (AnalyzedExpression::Float(num), PrefixOp::Neg) => {
1342 return AnalyzedExpression::Float(-num)
1343 }
1344 (AnalyzedExpression::Bool(bool), PrefixOp::Not) => {
1345 return AnalyzedExpression::Bool(!bool)
1346 }
1347 _ => {}
1348 }
1349
1350 AnalyzedExpression::Prefix(
1351 AnalyzedPrefixExpr {
1352 result_type,
1353 op: node.op,
1354 expr,
1355 }
1356 .into(),
1357 )
1358 }
1359
1360 fn infix_expr(&mut self, node: InfixExpr<'src>) -> AnalyzedExpression<'src> {
1361 let lhs_span = node.lhs.span();
1362 let rhs_span = node.rhs.span();
1363 let lhs = self.expression(node.lhs);
1364 let rhs = self.expression(node.rhs);
1365
1366 let allowed_types: &[Type];
1367 let mut override_result_type = None;
1368 let mut inherits_never_type = true;
1369 match node.op {
1370 InfixOp::Plus | InfixOp::Minus => {
1371 allowed_types = &[Type::Int(0), Type::Char(0), Type::Float(0)];
1372 }
1373 InfixOp::Mul | InfixOp::Div => {
1374 allowed_types = &[Type::Int(0), Type::Float(0)];
1375 }
1376 InfixOp::Lt | InfixOp::Gt | InfixOp::Lte | InfixOp::Gte => {
1377 allowed_types = &[Type::Int(0), Type::Char(0), Type::Float(0)];
1378 override_result_type = Some(Type::Bool(0));
1379 }
1380 InfixOp::Rem | InfixOp::Shl | InfixOp::Shr | InfixOp::Pow => {
1381 allowed_types = &[Type::Int(0)];
1382 }
1383 InfixOp::Eq | InfixOp::Neq => {
1384 allowed_types = &[Type::Int(0), Type::Float(0), Type::Bool(0), Type::Char(0)];
1385 override_result_type = Some(Type::Bool(0));
1386 }
1387 InfixOp::BitOr | InfixOp::BitAnd | InfixOp::BitXor => {
1388 allowed_types = &[Type::Int(0), Type::Bool(0)];
1389 }
1390 InfixOp::And | InfixOp::Or => {
1391 allowed_types = &[Type::Bool(0)];
1392 inherits_never_type = false;
1393 }
1394 }
1395
1396 let result_type = match (lhs.result_type(), rhs.result_type()) {
1397 (Type::Unknown, _) | (_, Type::Unknown) => Type::Unknown,
1398 (Type::Never, Type::Never) => {
1399 self.warn_unreachable(node.span, lhs_span, true);
1400 self.warn_unreachable(node.span, rhs_span, true);
1401 Type::Never
1402 }
1403 (Type::Never, _) if inherits_never_type => {
1404 self.warn_unreachable(node.span, lhs_span, true);
1405 Type::Never
1406 }
1407 (_, Type::Never) if inherits_never_type => {
1408 self.warn_unreachable(node.span, rhs_span, true);
1409 Type::Never
1410 }
1411 (Type::Never, _) => rhs.result_type(),
1412 (_, Type::Never) => lhs.result_type(),
1413 (left, right) if left == right && allowed_types.contains(&left) => {
1414 override_result_type.unwrap_or(left)
1415 }
1416 (left, right) if left != right => {
1417 self.error(
1418 ErrorKind::Type,
1419 format!(
1420 "infix expressions require equal types on both sides, got `{left}` and `{right}`"
1421 ),
1422 vec![],
1423 node.span,
1424 );
1425 Type::Unknown
1426 }
1427 (type_, _) => {
1428 self.error(
1429 ErrorKind::Type,
1430 format!(
1431 "infix operator `{}` does not allow values of type `{type_}`",
1432 node.op
1433 ),
1434 vec![],
1435 node.span,
1436 );
1437 Type::Unknown
1438 }
1439 };
1440
1441 match (&lhs, &rhs) {
1443 (AnalyzedExpression::Char(left), AnalyzedExpression::Char(right)) => match node.op {
1444 InfixOp::Plus => return AnalyzedExpression::Char(left.wrapping_add(*right) & 0x7f),
1445 InfixOp::Minus => {
1446 return AnalyzedExpression::Char(left.wrapping_sub(*right) & 0x7f)
1447 }
1448 InfixOp::Eq => return AnalyzedExpression::Bool(left == right),
1449 InfixOp::Neq => return AnalyzedExpression::Bool(left != right),
1450 InfixOp::Lt => return AnalyzedExpression::Bool(left < right),
1451 InfixOp::Lte => return AnalyzedExpression::Bool(left <= right),
1452 InfixOp::Gt => return AnalyzedExpression::Bool(left > right),
1453 InfixOp::Gte => return AnalyzedExpression::Bool(left >= right),
1454 _ => {}
1455 },
1456 (AnalyzedExpression::Int(left), AnalyzedExpression::Int(right)) => match node.op {
1457 InfixOp::Plus => return AnalyzedExpression::Int(left.wrapping_add(*right)),
1458 InfixOp::Minus => return AnalyzedExpression::Int(left.wrapping_sub(*right)),
1459 InfixOp::Mul => return AnalyzedExpression::Int(left.wrapping_mul(*right)),
1460 InfixOp::Div if *right == 0 => self.error(
1461 ErrorKind::Semantic,
1462 format!("cannot divide {left} by 0"),
1463 vec!["division by 0 is undefined".into()],
1464 node.span,
1465 ),
1466 InfixOp::Div => return AnalyzedExpression::Int(left.wrapping_div(*right)),
1467 InfixOp::Rem if *right == 0 => self.error(
1468 ErrorKind::Semantic,
1469 format!("cannot calculate remainder of {left} with a divisor of 0"),
1470 vec!["division by 0 is undefined".into()],
1471 node.span,
1472 ),
1473 InfixOp::Rem => return AnalyzedExpression::Int(left.wrapping_rem(*right)),
1474 InfixOp::Pow => {
1475 return AnalyzedExpression::Int(if *right < 0 {
1476 0
1477 } else {
1478 left.wrapping_pow(*right as u32)
1479 })
1480 }
1481 InfixOp::Eq => return AnalyzedExpression::Bool(left == right),
1482 InfixOp::Neq => return AnalyzedExpression::Bool(left != right),
1483 InfixOp::Lt => return AnalyzedExpression::Bool(left < right),
1484 InfixOp::Gt => return AnalyzedExpression::Bool(left > right),
1485 InfixOp::Lte => return AnalyzedExpression::Bool(left <= right),
1486 InfixOp::Gte => return AnalyzedExpression::Bool(left >= right),
1487 InfixOp::Shl | InfixOp::Shr => match *right {
1488 0..=63 => {
1489 return AnalyzedExpression::Int(match node.op == InfixOp::Shl {
1490 true => left << right,
1491 false => left >> right,
1492 })
1493 }
1494 _ => self.error(
1495 ErrorKind::Semantic,
1496 format!("cannot shift by {right}"),
1497 vec!["shifting by a number outside the range `0..=63` is undefined".into()],
1498 node.span,
1499 ),
1500 },
1501 InfixOp::BitOr => return AnalyzedExpression::Int(left | right),
1502 InfixOp::BitAnd => return AnalyzedExpression::Int(left & right),
1503 InfixOp::BitXor => return AnalyzedExpression::Int(left ^ right),
1504 _ => {}
1505 },
1506 (AnalyzedExpression::Float(left), AnalyzedExpression::Float(right)) => match node.op {
1507 InfixOp::Plus => return AnalyzedExpression::Float(left + right),
1508 InfixOp::Minus => return AnalyzedExpression::Float(left - right),
1509 InfixOp::Mul => return AnalyzedExpression::Float(left * right),
1510 InfixOp::Div => return AnalyzedExpression::Float(left / right),
1511 InfixOp::Eq => return AnalyzedExpression::Bool(left == right),
1512 InfixOp::Neq => return AnalyzedExpression::Bool(left != right),
1513 InfixOp::Lt => return AnalyzedExpression::Bool(left < right),
1514 InfixOp::Gt => return AnalyzedExpression::Bool(left > right),
1515 InfixOp::Lte => return AnalyzedExpression::Bool(left <= right),
1516 InfixOp::Gte => return AnalyzedExpression::Bool(left >= right),
1517 _ => {}
1518 },
1519 (AnalyzedExpression::Bool(left), AnalyzedExpression::Bool(right)) => match node.op {
1520 InfixOp::Eq => return AnalyzedExpression::Bool(left == right),
1521 InfixOp::Neq => return AnalyzedExpression::Bool(left != right),
1522 InfixOp::BitOr => return AnalyzedExpression::Bool(left | right),
1523 InfixOp::BitAnd => return AnalyzedExpression::Bool(left & right),
1524 InfixOp::BitXor => return AnalyzedExpression::Bool(left ^ right),
1525 InfixOp::And => return AnalyzedExpression::Bool(*left && *right),
1526 InfixOp::Or => return AnalyzedExpression::Bool(*left || *right),
1527 _ => {}
1528 },
1529 _ => {}
1530 }
1531
1532 AnalyzedExpression::Infix(
1533 AnalyzedInfixExpr {
1534 result_type,
1535 lhs,
1536 op: node.op,
1537 rhs,
1538 }
1539 .into(),
1540 )
1541 }
1542
1543 fn assign_type_error(&mut self, op: AssignOp, type_: Type, span: Span<'src>) -> Type {
1544 self.error(
1545 ErrorKind::Type,
1546 format!("assignment operator `{op}` does not allow values of type `{type_}`"),
1547 vec![],
1548 span,
1549 );
1550 Type::Unknown
1551 }
1552
1553 fn assign_expr(&mut self, node: AssignExpr<'src>) -> AnalyzedExpression<'src> {
1554 let var_type = match self
1555 .scopes
1556 .iter_mut()
1557 .rev()
1558 .find_map(|scope| scope.get_mut(node.assignee.inner))
1559 {
1560 Some(var) => {
1561 var.mutated = true;
1562 let mut type_ = var.type_;
1563 if !var.mutable && node.assignee_ptr_count == 0 {
1564 let span = var.span;
1565 self.error(
1566 ErrorKind::Semantic,
1567 format!(
1568 "cannot re-assign to immutable variable `{}`",
1569 node.assignee.inner
1570 ),
1571 vec![],
1572 node.span,
1573 );
1574 self.hint("variable not declared as `mut`", span);
1575 } else if node.assignee_ptr_count > 0 {
1576 var.used = true;
1578 }
1579
1580 for _ in 0..node.assignee_ptr_count {
1581 type_ = match type_.sub_deref() {
1582 Some(type_) => type_,
1583 None => {
1584 self.error(
1585 ErrorKind::Type,
1586 format!("cannot dereference a value of type `{type_}`"),
1587 vec!["only pointers `*` can be dereferenced".into()],
1588 node.assignee.span,
1589 );
1590 Type::Unknown
1591 }
1592 };
1593 }
1594
1595 type_
1596 }
1597 None => match self.functions.get(node.assignee.inner) {
1598 Some(_) => {
1599 self.error(
1600 ErrorKind::Type,
1601 "cannot assign to functions",
1602 vec![],
1603 node.assignee.span,
1604 );
1605 Type::Unknown
1606 }
1607 None if node.assignee.inner.is_empty() => Type::Unknown,
1608 None => {
1609 self.error(
1610 ErrorKind::Reference,
1611 format!("use of undeclared name `{}`", node.assignee.inner),
1612 vec![],
1613 node.assignee.span,
1614 );
1615 Type::Unknown
1616 }
1617 },
1618 };
1619
1620 let expr_span = node.expr.span();
1621 let expr = self.expression(node.expr);
1622 let result_type = match (node.op, var_type, expr.result_type()) {
1623 (_, Type::Unknown, _) | (_, _, Type::Unknown) => Type::Unknown,
1624 (_, _, Type::Never) => {
1625 self.warn_unreachable(node.span, expr_span, true);
1626 Type::Never
1627 }
1628 (_, left, right) if left != right => {
1629 self.error(
1630 ErrorKind::Type,
1631 format!("mismatched types: expected `{left}`, found `{right}`"),
1632 vec![],
1633 expr_span,
1634 );
1635 self.hint(
1636 format!("this variable has type `{left}`"),
1637 node.assignee.span,
1638 );
1639 Type::Unknown
1640 }
1641 (AssignOp::Plus | AssignOp::Minus, _, type_)
1642 if ![Type::Int(0), Type::Float(0), Type::Char(0)].contains(&type_) =>
1643 {
1644 self.assign_type_error(node.op, type_, expr_span)
1645 }
1646 (AssignOp::Mul | AssignOp::Div, _, type_)
1647 if ![Type::Int(0), Type::Float(0)].contains(&type_) =>
1648 {
1649 self.assign_type_error(node.op, type_, expr_span)
1650 }
1651 (AssignOp::Rem | AssignOp::Pow | AssignOp::Shl | AssignOp::Shr, _, type_)
1652 if type_ != Type::Int(0) =>
1653 {
1654 self.assign_type_error(node.op, type_, expr_span)
1655 }
1656 (AssignOp::BitOr | AssignOp::BitAnd | AssignOp::BitXor, _, type_)
1657 if ![Type::Int(0), Type::Bool(0)].contains(&type_) =>
1658 {
1659 self.assign_type_error(node.op, type_, expr_span)
1660 }
1661 (_, _, _) => Type::Unit,
1662 };
1663
1664 AnalyzedExpression::Assign(
1665 AnalyzedAssignExpr {
1666 result_type,
1667 assignee: node.assignee.inner,
1668 assignee_ptr_count: node.assignee_ptr_count,
1669 op: node.op,
1670 expr,
1671 }
1672 .into(),
1673 )
1674 }
1675
1676 fn call_expr(&mut self, node: CallExpr<'src>) -> AnalyzedExpression<'src> {
1677 let func = match (
1678 self.functions.get_mut(node.func.inner),
1679 self.builtin_functions.get(node.func.inner),
1680 ) {
1681 (Some(func), _) => {
1682 if self.curr_func_name != node.func.inner {
1684 func.used = true;
1685 }
1686 Some((
1687 func.return_type.inner.unwrap_or(Type::Unit),
1688 func.params.clone(),
1689 ))
1690 }
1691 (_, Some(builtin)) => {
1692 self.used_builtins.insert(node.func.inner);
1693 let builtin = builtin.clone();
1694 let (result_type, args) = if node.args.len() != builtin.param_types.len() {
1695 self.error(
1696 ErrorKind::Reference,
1697 format!(
1698 "function `{}` takes {} arguments, however {} were supplied",
1699 node.func.inner,
1700 builtin.param_types.len(),
1701 node.args.len()
1702 ),
1703 vec![],
1704 node.span,
1705 );
1706 (builtin.return_type, vec![])
1707 } else {
1708 let mut result_type = builtin.return_type;
1709 let args = node
1710 .args
1711 .into_iter()
1712 .zip(builtin.param_types)
1713 .map(|(arg, param_type)| {
1714 self.arg(arg, param_type, node.span, &mut result_type)
1715 })
1716 .collect();
1717 (result_type, args)
1718 };
1719
1720 return AnalyzedExpression::Call(
1721 AnalyzedCallExpr {
1722 result_type,
1723 func: node.func.inner,
1724 args,
1725 }
1726 .into(),
1727 );
1728 }
1729 (None, None) => {
1730 self.error(
1731 ErrorKind::Reference,
1732 format!("use of undeclared function `{}`", node.func.inner),
1733 vec![format!(
1734 "it can be declared like this: `fn {}(...) {{ ... }}`",
1735 node.func.inner
1736 )
1737 .into()],
1738 node.func.span,
1739 );
1740 None
1741 }
1742 };
1743 let (result_type, args) = match func {
1744 Some((func_type, func_params)) => {
1745 if node.args.len() != func_params.inner.len() {
1746 self.error(
1747 ErrorKind::Reference,
1748 format!(
1749 "function `{}` takes {} arguments, however {} were supplied",
1750 node.func.inner,
1751 func_params.inner.len(),
1752 node.args.len()
1753 ),
1754 vec![],
1755 node.span,
1756 );
1757 self.hint(
1758 format!(
1759 "function `{}` defined here with {} parameters",
1760 node.func.inner,
1761 func_params.inner.len()
1762 ),
1763 func_params.span,
1764 );
1765 (func_type, vec![])
1766 } else {
1767 let mut result_type = func_type;
1768 let args = node
1769 .args
1770 .into_iter()
1771 .zip(func_params.inner)
1772 .map(|(arg, param)| {
1773 self.arg(arg, param.type_.inner, node.span, &mut result_type)
1774 })
1775 .collect();
1776 (result_type, args)
1777 }
1778 }
1779 None => {
1780 let mut result_type = Type::Unknown;
1781 let args = node
1782 .args
1783 .into_iter()
1784 .map(|arg| {
1785 let arg = self.expression(arg);
1786 if arg.result_type() == Type::Never {
1787 result_type = Type::Never;
1788 }
1789 arg
1790 })
1791 .collect();
1792 (result_type, args)
1793 }
1794 };
1795
1796 AnalyzedExpression::Call(
1797 AnalyzedCallExpr {
1798 result_type,
1799 func: node.func.inner,
1800 args,
1801 }
1802 .into(),
1803 )
1804 }
1805
1806 fn arg(
1807 &mut self,
1808 arg: Expression<'src>,
1809 param_type: Type,
1810 call_span: Span<'src>,
1811 result_type: &mut Type,
1812 ) -> AnalyzedExpression<'src> {
1813 let arg_span = arg.span();
1814 let arg = self.expression(arg);
1815
1816 match (arg.result_type(), param_type) {
1817 (Type::Unknown, _) | (_, Type::Unknown) => {}
1818 (Type::Never, _) => {
1819 self.warn_unreachable(call_span, arg_span, true);
1820 *result_type = Type::Never;
1821 }
1822 (arg_type, param_type) if arg_type != param_type => self.error(
1823 ErrorKind::Type,
1824 format!("mismatched types: expected `{param_type}`, found `{arg_type}`"),
1825 vec![],
1826 arg_span,
1827 ),
1828 _ => {}
1829 }
1830
1831 arg
1832 }
1833
1834 fn cast_expr(&mut self, node: CastExpr<'src>) -> AnalyzedExpression<'src> {
1835 let expr_span = node.expr.span();
1836 let expr = self.expression(node.expr);
1837
1838 let result_type = match (expr.result_type(), node.type_.inner) {
1839 (Type::Unknown, _) => Type::Unknown,
1840 (Type::Never, _) => {
1841 self.warn_unreachable(node.span, expr_span, true);
1842 Type::Never
1843 }
1844 (left, right) if left == right => {
1845 self.info("unnecessary cast to same type", vec![], node.span);
1846 left
1847 }
1848 (
1849 Type::Int(0) | Type::Float(0) | Type::Bool(0) | Type::Char(0),
1850 Type::Int(0) | Type::Float(0) | Type::Bool(0) | Type::Char(0),
1851 ) => node.type_.inner,
1852 _ => {
1853 self.error(
1854 ErrorKind::Type,
1855 format!(
1856 "invalid cast: cannot cast type `{}` to `{}",
1857 expr.result_type(),
1858 node.type_.inner
1859 ),
1860 vec![],
1861 node.span,
1862 );
1863 Type::Unknown
1864 }
1865 };
1866
1867 match (expr, result_type) {
1869 (AnalyzedExpression::Int(val), Type::Int(0)) => AnalyzedExpression::Int(val),
1870 (AnalyzedExpression::Int(val), Type::Float(0)) => AnalyzedExpression::Float(val as f64),
1871 (AnalyzedExpression::Int(val), Type::Bool(0)) => AnalyzedExpression::Bool(val != 0),
1872 (AnalyzedExpression::Int(val), Type::Char(0)) => {
1873 AnalyzedExpression::Char(val.clamp(0, 127) as u8)
1874 }
1875 (AnalyzedExpression::Float(val), Type::Int(0)) => AnalyzedExpression::Int(val as i64),
1876 (AnalyzedExpression::Float(val), Type::Float(0)) => AnalyzedExpression::Float(val),
1877 (AnalyzedExpression::Float(val), Type::Bool(0)) => AnalyzedExpression::Bool(val != 0.0),
1878 (AnalyzedExpression::Float(val), Type::Char(0)) => {
1879 AnalyzedExpression::Char(val.clamp(0.0, 127.0) as u8)
1880 }
1881 (AnalyzedExpression::Bool(val), Type::Int(0)) => AnalyzedExpression::Int(val as i64),
1882 (AnalyzedExpression::Bool(val), Type::Float(0)) => {
1883 AnalyzedExpression::Float(val as u8 as f64)
1884 }
1885 (AnalyzedExpression::Bool(val), Type::Bool(0)) => AnalyzedExpression::Bool(val),
1886 (AnalyzedExpression::Bool(val), Type::Char(0)) => AnalyzedExpression::Char(val as u8),
1887 (AnalyzedExpression::Char(val), Type::Int(0)) => AnalyzedExpression::Int(val as i64),
1888 (AnalyzedExpression::Char(val), Type::Float(0)) => {
1889 AnalyzedExpression::Float(val as f64)
1890 }
1891 (AnalyzedExpression::Char(val), Type::Bool(0)) => AnalyzedExpression::Bool(val != 0),
1892 (AnalyzedExpression::Char(val), Type::Char(0)) => AnalyzedExpression::Char(val),
1893 (expr, result_type) => AnalyzedExpression::Cast(
1894 AnalyzedCastExpr {
1895 result_type,
1896 expr,
1897 type_: node.type_.inner,
1898 }
1899 .into(),
1900 ),
1901 }
1902 }
1903}
1904
1905#[cfg(test)]
1906mod tests {
1907 use super::*;
1908
1909 use rush_parser::{span, tree};
1910
1911 fn program_test(
1912 parsed_tree: Program<'static>,
1913 analyzed_tree: AnalyzedProgram<'static>,
1914 ) -> Result<(), Vec<Diagnostic<'static>>> {
1915 let (tree, diagnostics) = dbg!(Analyzer::new("").analyze(parsed_tree))?;
1916 assert!(!diagnostics
1917 .iter()
1918 .any(|diag| matches!(diag.level, DiagnosticLevel::Error(_))));
1919 assert_eq!(tree, analyzed_tree);
1920 Ok(())
1921 }
1922
1923 #[test]
1924 fn programs() -> Result<(), Vec<Diagnostic<'static>>> {
1925 program_test(
1927 tree! {
1928 (Program @ 0..61,
1929 functions: [
1930 (FunctionDefinition @ 0..61,
1931 name: ("add", @ 3..6),
1932 params @ 6..29: [
1933 (Parameter,
1934 mutable: false,
1935 name: ("left", @ 7..11),
1936 type: (Type::Int(0), @ 13..16)),
1937 (Parameter,
1938 mutable: false,
1939 name: ("right", @ 18..23),
1940 type: (Type::Int(0), @ 25..28))],
1941 return_type: (Some(Type::Int(0)), @ 33..36),
1942 block: (Block @ 37..61,
1943 stmts: [
1944 (ReturnStmt @ 39..59, (Some(InfixExpr @ 46..58,
1945 lhs: (Ident "left", @ 46..50),
1946 op: InfixOp::Plus,
1947 rhs: (Ident "right", @ 53..58))))],
1948 expr: (None))),
1949 (FunctionDefinition @ 62..74,
1950 name: ("main", @ 65..69),
1951 params @ 69..71: [],
1952 return_type: (None, @ 70..73),
1953 block: (Block @ 72..74,
1954 stmts: [],
1955 expr: (None)))],
1956 globals: [])
1957 },
1958 analyzed_tree! {
1959 (Program,
1960 globals: [],
1961 functions: [
1962 (FunctionDefinition,
1963 used: false,
1964 name: "add",
1965 params: [
1966 (Parameter,
1967 mutable: false,
1968 name: "left",
1969 type: Type::Int(0) ),
1970 (Parameter,
1971 mutable: false,
1972 name: "right",
1973 type: Type::Int(0) )],
1974 return_type: Type::Int(0),
1975 block: (Block -> Type::Never,
1976 stmts: [
1977 (ReturnStmt, (Some(InfixExpr -> Type::Int(0),
1978 lhs: (Ident -> Type::Int(0), "left"),
1979 op: InfixOp::Plus,
1980 rhs: (Ident -> Type::Int(0), "right"))))],
1981 expr: (None)))],
1982 main_fn: (Block -> Type::Unit,
1983 stmts: [],
1984 expr: (None)),
1985 used_builtins: [])
1986 },
1987 )?;
1988
1989 program_test(
1991 tree! {
1992 (Program @ 0..26,
1993 functions: [
1994 (FunctionDefinition @ 0..26,
1995 name: ("main", @ 3..7),
1996 params @ 7..9: [],
1997 return_type: (None, @ 8..11),
1998 block: (Block @ 10..26,
1999 stmts: [
2000 (ExprStmt @ 12..24, (CallExpr @ 12..23,
2001 func: ("exit", @ 12..16),
2002 args: [
2003 (InfixExpr @ 17..22,
2004 lhs: (Int 1, @ 17..18),
2005 op: InfixOp::Plus,
2006 rhs: (Int 2, @ 21..22))]))],
2007 expr: (None)))],
2008 globals: [])
2009 },
2010 analyzed_tree! {
2011 (Program,
2012 globals: [],
2013 functions: [],
2014 main_fn: (Block -> Type::Never,
2015 stmts: [
2016 (ExprStmt, (CallExpr -> Type::Never,
2017 func: "exit",
2018 args: [(Int 3)]))],
2019 expr: (None)),
2020 used_builtins: ["exit"])
2021 },
2022 )?;
2023
2024 Ok(())
2025 }
2026}