From 216ef6b45a68f51e917cb4369e9c54af41cc2e0d Mon Sep 17 00:00:00 2001 From: Masashi Date: Tue, 16 Dec 2025 02:06:58 +0530 Subject: [PATCH 1/2] disappointment --- tests/generics_comprehensive.c | 60 ++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 tests/generics_comprehensive.c diff --git a/tests/generics_comprehensive.c b/tests/generics_comprehensive.c new file mode 100644 index 0000000..7c8a977 --- /dev/null +++ b/tests/generics_comprehensive.c @@ -0,0 +1,60 @@ +#include +#include +#include +#include + +struct Box_string { + struct T value; +}; + +struct Option_bool_union { + struct Option_bool_Some some; + struct Option_bool_None none; +}; + +struct Option_int_union { + struct Option_int_Some some; + struct Option_int_None none; +}; + +struct Option_int_None { +}; + +struct Option_int { + int discriminant; + struct Option_int_union data; +}; + +struct Option_int_Some { + struct T field_0; +}; + +struct Option_bool_None { +}; + +struct Option_bool { + int discriminant; + struct Option_bool_union data; +}; + +struct Option_bool_Some { + struct T field_0; +}; + +struct Box_int { + struct T value; +}; + +int test_containers(void); + + +int test_containers(void) { + struct Box box_int = (struct Box){ .value = 42 }; + struct Box box_string = (struct Box){ .value = "Fermented" }; + struct Option some_int = (Option){ .discriminant = 0, .data = { .some = (Option_Some{ .field_0 = 10 }) } }; + struct Option some_bool = (Option){ .discriminant = 0, .data = { .some = (Option_Some{ .field_0 = true }) } }; + struct T unwrapped = unwrap(some_int); + struct T unwraped_bool = unwrap(some_bool); + return (box_int.value + unwrapped); +} + From 62b78ddad27aeac9e7525d7320d7b15aea262c78 Mon Sep 17 00:00:00 2001 From: Masashi Date: Tue, 16 Dec 2025 02:46:45 +0530 Subject: [PATCH 2/2] hmm --- src/codegen/statements_transpiler.rs | 39 ++++++++++++----- src/codegen/transpiler.rs | 33 ++++++++++++--- src/typechecker.rs | 63 +++++++++++++++++++++++----- tests/traits.c | 19 +++++++++ 4 files changed, 128 insertions(+), 26 deletions(-) create mode 100644 tests/traits.c diff --git a/src/codegen/statements_transpiler.rs b/src/codegen/statements_transpiler.rs index bdd38de..a462fd8 100644 --- a/src/codegen/statements_transpiler.rs +++ b/src/codegen/statements_transpiler.rs @@ -1,5 +1,6 @@ use crate::ast::*; use crate::c_ir::*; +use crate::typechecker::Type; pub struct StatementsTranspiler; @@ -16,16 +17,32 @@ impl StatementsTranspiler { TypedExprKind::String(s) => Ok(CExpr::StringLit(s.clone())), TypedExprKind::Variable(name) => Ok(CExpr::Var(name.clone())), TypedExprKind::Call(func, args) => { - let func_expr = self.transpile_expr(func)?; - let func_name = match func_expr { - CExpr::Var(name) => name, - _ => return Err("Function calls must be on variables for now".to_string()), - }; - let c_args = args - .iter() - .map(|arg| self.transpile_expr(arg)) - .collect::, _>>()?; - Ok(CExpr::Call(func_name, c_args)) + if let TypedExprKind::Dot(obj, method) = &func.kind { + // Method call + let obj_type = &obj.ty; + let type_name = if let Type::Struct(name, _) = obj_type { + name + } else { + return Err("Method call on non-struct".to_string()); + }; + let func_name = format!("{}_{}", type_name, method); + let c_args = args + .iter() + .map(|arg| self.transpile_expr(arg)) + .collect::, _>>()?; + Ok(CExpr::Call(func_name, c_args)) + } else { + let func_expr = self.transpile_expr(func)?; + let func_name = match func_expr { + CExpr::Var(name) => name, + _ => return Err("Function calls must be on variables for now".to_string()), + }; + let c_args = args + .iter() + .map(|arg| self.transpile_expr(arg)) + .collect::, _>>()?; + Ok(CExpr::Call(func_name, c_args)) + } } TypedExprKind::BinOp(lhs, op, rhs) => { let c_lhs = self.transpile_expr(lhs)?; @@ -205,7 +222,7 @@ impl StatementsTranspiler { } Ok(c_stmts) } - _ => Ok(vec![self.transpile_stmt(expr)?]), + _ => Ok(vec![CStmt::Return(Some(self.transpile_expr(expr)?))]), } } diff --git a/src/codegen/transpiler.rs b/src/codegen/transpiler.rs index 1804cfe..c7392ef 100644 --- a/src/codegen/transpiler.rs +++ b/src/codegen/transpiler.rs @@ -88,6 +88,14 @@ impl Transpiler { func_decl.body = Some(Vec::new()); self.functions.push(func_decl); } + TypedASTNodeKind::Impl(imp) => { + for method in &imp.methods { + let mut func_decl = self.decl_transpiler.transpile_function(method)?; + func_decl.name = format!("{}_{}", imp.target, method.name); + func_decl.body = Some(Vec::new()); + self.functions.push(func_decl); + } + } TypedASTNodeKind::Extern(e) => { // For externs, we might need to add function prototypes // But for now, skip as they're handled differently @@ -101,12 +109,27 @@ impl Transpiler { fn transpile_function_bodies(&mut self, nodes: &[TypedASTNode]) -> Result<(), String> { for node in nodes { - if let TypedASTNodeKind::Function(f) = &node.kind { - // Find the corresponding function declaration - if let Some(func_decl) = self.functions.iter_mut().find(|fd| fd.name == f.name) { - let body_stmts = self.stmt_transpiler.expr_to_stmts(&f.body)?; - func_decl.body = Some(body_stmts); + match &node.kind { + TypedASTNodeKind::Function(f) => { + // Find the corresponding function declaration + if let Some(func_decl) = self.functions.iter_mut().find(|fd| fd.name == f.name) + { + let body_stmts = self.stmt_transpiler.expr_to_stmts(&f.body)?; + func_decl.body = Some(body_stmts); + } } + TypedASTNodeKind::Impl(imp) => { + for method in &imp.methods { + let method_name = format!("{}_{}", imp.target, method.name); + if let Some(func_decl) = + self.functions.iter_mut().find(|fd| fd.name == method_name) + { + let body_stmts = self.stmt_transpiler.expr_to_stmts(&method.body)?; + func_decl.body = Some(body_stmts); + } + } + } + _ => {} } } Ok(()) diff --git a/src/typechecker.rs b/src/typechecker.rs index 63ecda5..d21f70a 100644 --- a/src/typechecker.rs +++ b/src/typechecker.rs @@ -546,7 +546,15 @@ impl TypeChecker { ASTNodeKind::Impl(impl_def) => { let mut typed_methods = Vec::new(); for method in &impl_def.methods { - typed_methods.push(self.typecheck_function(method)?); + let mut method_clone = method.clone(); + if !method_clone.args.is_empty() + && method_clone.args[0].0 == "self" + && method_clone.args[0].1.is_none() + { + method_clone.args[0].1 = + Some(TypeAnnot::Cons(impl_def.target.clone(), vec![])); + } + typed_methods.push(self.typecheck_function(&method_clone)?); } return Ok(TypedASTNode { kind: TypedASTNodeKind::Impl(TypedImpl { @@ -832,12 +840,27 @@ impl TypeChecker { } ExprKind::Call(func_expr, args) => { - let typed_func = self.typecheck_expr(func_expr)?; - let mut typed_args = Vec::new(); - - for arg in args { - typed_args.push(self.typecheck_expr(arg)?); - } + let (typed_func, typed_args) = if let ExprKind::Dot(_, _) = &func_expr.kind { + // Method call: insert self as first argument + let typed_method = self.typecheck_expr(func_expr)?; + let typed_obj = if let TypedExprKind::Dot(obj, _) = &typed_method.kind { + obj.as_ref().clone() + } else { + unreachable!() + }; + let mut args_with_self = vec![typed_obj]; + for arg in args { + args_with_self.push(self.typecheck_expr(arg)?); + } + (typed_method, args_with_self) + } else { + let typed_func = self.typecheck_expr(func_expr)?; + let typed_args = args + .iter() + .map(|arg| self.typecheck_expr(arg)) + .collect::, _>>()?; + (typed_func, typed_args) + }; let return_type = match &typed_func.ty { Type::Function(param_types, ret) => { @@ -860,7 +883,10 @@ impl TypeChecker { expected.clone(), actual.ty.clone(), ), - span: args[i].span.clone(), + span: args + .get(i) + .map(|a| a.span.clone()) + .unwrap_or(expr.span.clone()), }); } } @@ -1064,17 +1090,34 @@ impl TypeChecker { Type::Struct(name, _) => { if let Some(type_info) = self.env.get_type(name) { if let TypeInfoKind::Struct(fields) = &type_info.kind { - fields + if let Some(field_ty) = fields .iter() .find(|(f, _)| f == field) .map(|(_, ty)| self.type_annot_to_type(ty)) - .ok_or_else(|| TypeError { + { + field_ty + } else { + // Check for methods in impls + let mut method_type = None; + for impl_info in &self.env.impls { + if impl_info.target == *name { + if let Some(func_type) = impl_info.methods.get(field) { + method_type = Some(Type::Function( + func_type.params.clone(), + Box::new(func_type.return_type.clone()), + )); + break; + } + } + } + method_type.ok_or_else(|| TypeError { kind: TypeErrorKind::UndefinedField( field.clone(), typed_obj.ty.clone(), ), span: expr.span.clone(), })? + } } else { return Err(TypeError { kind: TypeErrorKind::NotAStruct(typed_obj.ty.clone()), diff --git a/tests/traits.c b/tests/traits.c new file mode 100644 index 0000000..8cb9442 --- /dev/null +++ b/tests/traits.c @@ -0,0 +1,19 @@ +#include +#include +#include +#include + +struct Number { + int value; +}; + +char *Number_show(struct Number self); +int main(void); + +char *Number_show(struct Number self) { return "number"; } + +int main(void) { + struct Number number = (struct Number){.value = 40}; + Number_show(number); + return 0; +}