From 8c7a0de205bb72c72cf6a82eed638145ce2a9feb Mon Sep 17 00:00:00 2001 From: Hugo Freitas Silva Date: Mon, 8 Jun 2026 14:52:09 -0300 Subject: [PATCH 1/3] feat(analyser): improve semantic AST walk --- src/analyser/semantic.rs | 55 ++++++++++++++++++++++++++++++++-------- 1 file changed, 45 insertions(+), 10 deletions(-) diff --git a/src/analyser/semantic.rs b/src/analyser/semantic.rs index cd0fe95..f127c97 100644 --- a/src/analyser/semantic.rs +++ b/src/analyser/semantic.rs @@ -33,10 +33,19 @@ impl SemanticAnalyser { pub fn analyse_decl(&mut self, decl: &Decl) { match decl { Decl::GlobalVar(qty, name, init, span) => { + let resolved_qty = self.resolve_type(qty); if let Some(expr) = init { - self.analyse_expr(expr); + let init_ty = self.analyse_expr(expr); + if !types_compatible_for_assign(&resolved_qty.ty, &init_ty.ty) { + self.diagnostics.push(CompilerError::Semantic(SemanticError { + span: expr.span(), + kind: SemanticErrorKind::TypeMismatch { + expected: type_name(&resolved_qty.ty), + found: type_name(&init_ty.ty), + }, + })); + } } - let resolved_qty = self.resolve_type(qty); let symbol = Symbol { name: name.clone(), ty: resolved_qty.clone(), @@ -79,9 +88,20 @@ impl SemanticAnalyser { let resolved_qty = self.resolve_type(qty); self.sym.register_type_alias(name.clone(), resolved_qty); } - Decl::Function(return_type, _name, params, body, span) => { + Decl::Function(return_type, name, params, body, span) => { + let resolved_return_type = self.resolve_type(return_type); + let function_symbol = Symbol { + name: name.clone(), + ty: resolved_return_type.clone(), + mutable: false, + decl_span: span.clone(), + }; + if let Err(e) = self.sym.declare(function_symbol) { + self.diagnostics.push(e); + } + self.sym.enter_scope(); - let prev_ret = self.current_fn_ret.replace(self.resolve_type(return_type)); + let prev_ret = self.current_fn_ret.replace(resolved_return_type); for (qty, name) in params { let resolved_qty = self.resolve_type(qty); @@ -134,9 +154,25 @@ impl SemanticAnalyser { self.analyse_expr(expr); } Stmt::Return(expr, _) => { - if let Some(e) = expr { - self.analyse_expr(e); - // TODO(#87): checar compatibilidade com current_fn_ret + let ret_ty = expr + .as_ref() + .map(|e| self.analyse_expr(e)) + .unwrap_or_else(|| QualifierType { + ty: Type::Void, + is_const: false, + is_unsigned: false, + }); + + if let Some(expected_ret) = &self.current_fn_ret { + if !types_compatible_for_assign(&expected_ret.ty, &ret_ty.ty) { + self.diagnostics.push(CompilerError::Semantic(SemanticError { + span: expr.as_ref().map(|e| e.span()).unwrap_or_else(|| stmt.span()), + kind: SemanticErrorKind::TypeMismatch { + expected: type_name(&expected_ret.ty), + found: type_name(&ret_ty.ty), + }, + })); + } } } Stmt::If(cond, then, else_, _) => { @@ -255,12 +291,11 @@ impl SemanticAnalyser { } Expr::SizeofType(_, _) => uint_type(), Expr::Call(callee, args, _) => { - self.analyse_expr(callee); + let callee_ty = self.analyse_expr(callee); for a in args { self.analyse_expr(a); } - // TODO(#87): lookup do tipo de retorno da função - unknown_type() + callee_ty } Expr::Index(arr, idx, _) => { let arr_ty = self.analyse_expr(arr); From 392bcbd3a5383c700be6f6693fa3cc0d120dac94 Mon Sep 17 00:00:00 2001 From: Hugo Freitas Silva Date: Mon, 8 Jun 2026 14:52:14 -0300 Subject: [PATCH 2/3] test(analyser): add semantic regression cases --- src/tests/semantic_test.rs | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/src/tests/semantic_test.rs b/src/tests/semantic_test.rs index 73f0723..3bafcaf 100644 --- a/src/tests/semantic_test.rs +++ b/src/tests/semantic_test.rs @@ -137,6 +137,25 @@ mod tests { assert!(analyse(&prog).is_empty()); } + #[test] + fn global_initializer_type_mismatch_emits_error() { + let prog = Program { + decls: vec![Decl::GlobalVar( + qty(Type::Int), + "x".into(), + Some(Expr::Literal(Literal::String("hello".into()), span())), + span(), + )], + }; + + let errors = analyse(&prog); + assert!(errors.iter().any(|e| matches!( + e, + crate::common::errors::types::CompilerError::Semantic(se) + if matches!(&se.kind, SemanticErrorKind::TypeMismatch { .. }) + ))); + } + // ── múltiplos erros acumulados ──────────────────────────────────────────── #[test] @@ -328,6 +347,24 @@ mod tests { assert!(matches!(ty.ty, Type::Int)); } + #[test] + fn function_call_uses_registered_return_type() { + let prog = Program { + decls: vec![Decl::Function( + qty(Type::Int), + "main".into(), + vec![], + vec![Stmt::Return( + Some(Expr::Call(Box::new(ident("main")), vec![], span())), + span(), + )], + span(), + )], + }; + + assert!(analyse(&prog).is_empty()); + } + // ── Assign: verificação de compatibilidade de tipo ──────────────────────── #[test] From 23179503a2d2539f8996795d2300805caeaf0a69 Mon Sep 17 00:00:00 2001 From: Hugo Freitas Silva Date: Mon, 8 Jun 2026 15:01:17 -0300 Subject: [PATCH 3/3] fix(ci): formatting --- src/analyser/semantic.rs | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/src/analyser/semantic.rs b/src/analyser/semantic.rs index f127c97..c668a82 100644 --- a/src/analyser/semantic.rs +++ b/src/analyser/semantic.rs @@ -37,13 +37,14 @@ impl SemanticAnalyser { if let Some(expr) = init { let init_ty = self.analyse_expr(expr); if !types_compatible_for_assign(&resolved_qty.ty, &init_ty.ty) { - self.diagnostics.push(CompilerError::Semantic(SemanticError { - span: expr.span(), - kind: SemanticErrorKind::TypeMismatch { - expected: type_name(&resolved_qty.ty), - found: type_name(&init_ty.ty), - }, - })); + self.diagnostics + .push(CompilerError::Semantic(SemanticError { + span: expr.span(), + kind: SemanticErrorKind::TypeMismatch { + expected: type_name(&resolved_qty.ty), + found: type_name(&init_ty.ty), + }, + })); } } let symbol = Symbol { @@ -165,13 +166,17 @@ impl SemanticAnalyser { if let Some(expected_ret) = &self.current_fn_ret { if !types_compatible_for_assign(&expected_ret.ty, &ret_ty.ty) { - self.diagnostics.push(CompilerError::Semantic(SemanticError { - span: expr.as_ref().map(|e| e.span()).unwrap_or_else(|| stmt.span()), - kind: SemanticErrorKind::TypeMismatch { - expected: type_name(&expected_ret.ty), - found: type_name(&ret_ty.ty), - }, - })); + self.diagnostics + .push(CompilerError::Semantic(SemanticError { + span: expr + .as_ref() + .map(|e| e.span()) + .unwrap_or_else(|| stmt.span()), + kind: SemanticErrorKind::TypeMismatch { + expected: type_name(&expected_ret.ty), + found: type_name(&ret_ty.ty), + }, + })); } } }