From 812fe9cbe124bf39a06f58a538c8c01f7402fb09 Mon Sep 17 00:00:00 2001 From: Zuhaitz Méndez Fernández de Aránguiz Date: Sat, 24 Jan 2026 12:14:48 +0000 Subject: Fix for #110 --- src/parser/parser_decl.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/parser/parser_decl.c') diff --git a/src/parser/parser_decl.c b/src/parser/parser_decl.c index 7e0cc5b..bd56350 100644 --- a/src/parser/parser_decl.c +++ b/src/parser/parser_decl.c @@ -562,17 +562,17 @@ ASTNode *parse_var_decl(ParserContext *ctx, Lexer *l) // Fallbacks for literals else if (init->type == NODE_EXPR_LITERAL) { - if (init->literal.type_kind == 0) + if (init->literal.type_kind == LITERAL_INT) { type = xstrdup("int"); type_obj = type_new(TYPE_INT); } - else if (init->literal.type_kind == 1) + else if (init->literal.type_kind == LITERAL_FLOAT) { type = xstrdup("float"); type_obj = type_new(TYPE_FLOAT); } - else if (init->literal.type_kind == 2) + else if (init->literal.type_kind == LITERAL_STRING) { type = xstrdup("string"); type_obj = type_new(TYPE_STRING); @@ -596,7 +596,7 @@ ASTNode *parse_var_decl(ParserContext *ctx, Lexer *l) add_symbol_with_token(ctx, name, type, type_obj, name_tok); // NEW: Capture Const Integer Values - if (init && init->type == NODE_EXPR_LITERAL && init->literal.type_kind == 0) + if (init && init->type == NODE_EXPR_LITERAL && init->literal.type_kind == LITERAL_INT) { Symbol *s = find_symbol_entry(ctx, name); // Helper to find the struct if (s) -- cgit v1.2.3 From 0bd7b99fbf813415b9a0217eaa2a4e8f6f74e1ea Mon Sep 17 00:00:00 2001 From: Zuhaitz Méndez Fernández de Aránguiz Date: Sun, 25 Jan 2026 13:44:24 +0000 Subject: Fix for #111 --- src/codegen/codegen.c | 26 ++++++++++++++++ src/parser/parser_decl.c | 30 +++++++++++++++++-- src/parser/parser_expr.c | 56 +++++++++++++++++++++++++++++------ src/parser/parser_struct.c | 56 +++++++++++++++++++++++++++++++---- tests/generics/test_generic_traits.zc | 42 ++++++++++++++++++++++++++ 5 files changed, 194 insertions(+), 16 deletions(-) create mode 100644 tests/generics/test_generic_traits.zc (limited to 'src/parser/parser_decl.c') diff --git a/src/codegen/codegen.c b/src/codegen/codegen.c index b375bbb..689c4dc 100644 --- a/src/codegen/codegen.c +++ b/src/codegen/codegen.c @@ -464,6 +464,32 @@ void codegen_expression(ParserContext *ctx, ASTNode *node, FILE *out) ref = ref->next; } + if (!resolved_method_suffix) + { + GenericImplTemplate *it = ctx->impl_templates; + while (it) + { + char *tname = NULL; + if (it->impl_node && it->impl_node->type == NODE_IMPL_TRAIT) + { + tname = it->impl_node->impl_trait.trait_name; + } + if (tname) + { + char trait_mangled[512]; + sprintf(trait_mangled, "%s__%s_%s", base, tname, method); + if (find_func(ctx, trait_mangled)) + { + char *suffix = xmalloc(strlen(tname) + strlen(method) + 2); + sprintf(suffix, "%s_%s", tname, method); + resolved_method_suffix = suffix; + break; + } + } + it = it->next; + } + } + if (resolved_method_suffix) { method = resolved_method_suffix; diff --git a/src/parser/parser_decl.c b/src/parser/parser_decl.c index bd56350..5d5af1e 100644 --- a/src/parser/parser_decl.c +++ b/src/parser/parser_decl.c @@ -207,17 +207,43 @@ char *patch_self_args(const char *args, const char *struct_name) { return NULL; } - char *new_args = xmalloc(strlen(args) + strlen(struct_name) + 10); + + // Sanitize struct name for C usage (Vec -> Vec_T) + char *safe_name = xmalloc(strlen(struct_name) + 1); + int j = 0; + for (int i = 0; struct_name[i]; i++) + { + if (struct_name[i] == '<') + { + safe_name[j++] = '_'; + } + else if (struct_name[i] == '>') + { + // skip + } + else if (struct_name[i] == ' ') + { + // skip + } + else + { + safe_name[j++] = struct_name[i]; + } + } + safe_name[j] = 0; + + char *new_args = xmalloc(strlen(args) + strlen(safe_name) + 10); // Check if it starts with "void* self" if (strncmp(args, "void* self", 10) == 0) { - sprintf(new_args, "%s* self%s", struct_name, args + 10); + sprintf(new_args, "%s* self%s", safe_name, args + 10); } else { strcpy(new_args, args); } + free(safe_name); return new_args; } // Helper for Value-Returning Defer diff --git a/src/parser/parser_expr.c b/src/parser/parser_expr.c index 07f133e..b07b544 100644 --- a/src/parser/parser_expr.c +++ b/src/parser/parser_expr.c @@ -1646,13 +1646,59 @@ ASTNode *parse_primary(ParserContext *ctx, Lexer *l) v = v->next; } } + int resolved = 0; if (is_variant) { sprintf(tmp, "%s_%.*s", acc, suffix.len, suffix.start); + resolved = 1; } else { - sprintf(tmp, "%s__%.*s", acc, suffix.len, suffix.start); + char inherent_name[256]; + sprintf(inherent_name, "%s__%.*s", acc, suffix.len, + suffix.start); + + if (find_func(ctx, inherent_name)) + { + strcpy(tmp, inherent_name); + resolved = 1; + } + else + { + GenericImplTemplate *it = ctx->impl_templates; + while (it) + { + if (strcmp(it->struct_name, gname) == 0) + { + char *tname = NULL; + if (it->impl_node && + it->impl_node->type == NODE_IMPL_TRAIT) + { + tname = it->impl_node->impl_trait + .trait_name; + } + if (tname) + { + char cand[512]; + sprintf(cand, "%s__%s_%.*s", acc, tname, + suffix.len, suffix.start); + + if (find_func(ctx, cand)) + { + strcpy(tmp, cand); + resolved = 1; + break; + } + } + } + it = it->next; + } + } + if (!resolved) + { + sprintf(tmp, "%s__%.*s", acc, suffix.len, + suffix.start); + } } handled_as_generic = 1; break; // Found and handled @@ -5588,14 +5634,6 @@ ASTNode *parse_arrow_lambda_single(ParserContext *ctx, Lexer *l, char *param_nam } t->inner = ret_val->type_info; } - else - { - if (param_name[0] == 'x') - { - fprintf(stderr, "DEBUG: Return type unknown/null! ret=%p kind=%d\n", - ret_val->type_info, ret_val->type_info ? ret_val->type_info->kind : -1); - } - } } // Update parameter types from symbol table (in case inference happened) diff --git a/src/parser/parser_struct.c b/src/parser/parser_struct.c index 3e5c73d..8eed017 100644 --- a/src/parser/parser_struct.c +++ b/src/parser/parser_struct.c @@ -187,6 +187,19 @@ ASTNode *parse_impl(ParserContext *ctx, Lexer *l) Token t2 = lexer_next(l); char *name2 = token_strdup(t2); + char *target_gen_param = NULL; + if (lexer_peek(l).type == TOK_LANGLE) + { + lexer_next(l); // eat < + Token gt = lexer_next(l); + target_gen_param = token_strdup(gt); + if (lexer_next(l).type != TOK_RANGLE) + { + zpanic_at(lexer_peek(l), "Expected > in impl struct generic"); + } + register_generic(ctx, target_gen_param); + } + register_impl(ctx, name1, name2); // RAII: Check for "Drop" trait implementation @@ -231,6 +244,18 @@ ASTNode *parse_impl(ParserContext *ctx, Lexer *l) lexer_next(l); // eat { ASTNode *h = 0, *tl = 0; + + char *full_target_name = name2; + if (target_gen_param) + { + full_target_name = xmalloc(strlen(name2) + strlen(target_gen_param) + 3); + sprintf(full_target_name, "%s<%s>", name2, target_gen_param); + } + else + { + full_target_name = xstrdup(name2); + } + while (1) { skip_comments(l); @@ -247,7 +272,9 @@ ASTNode *parse_impl(ParserContext *ctx, Lexer *l) sprintf(mangled, "%s__%s_%s", name2, name1, f->func.name); free(f->func.name); f->func.name = mangled; - char *na = patch_self_args(f->func.args, name2); + + // Use full_target_name (Vec) for self patching + char *na = patch_self_args(f->func.args, full_target_name); free(f->func.args); f->func.args = na; @@ -286,7 +313,8 @@ ASTNode *parse_impl(ParserContext *ctx, Lexer *l) sprintf(mangled, "%s__%s_%s", name2, name1, f->func.name); free(f->func.name); f->func.name = mangled; - char *na = patch_self_args(f->func.args, name2); + + char *na = patch_self_args(f->func.args, full_target_name); free(f->func.args); f->func.args = na; @@ -322,6 +350,16 @@ ASTNode *parse_impl(ParserContext *ctx, Lexer *l) lexer_next(l); } } + + if (target_gen_param) + { + free(full_target_name); + } + else + { + free(full_target_name); // It was strdup/ref. Wait, xstrdup needs free. + } + ctx->current_impl_struct = NULL; // Restore context ASTNode *n = ast_create(NODE_IMPL_TRAIT); n->impl_trait.trait_name = name1; @@ -331,11 +369,15 @@ ASTNode *parse_impl(ParserContext *ctx, Lexer *l) // If target struct is generic, register this impl as a template ASTNode *def = find_struct_def(ctx, name2); - if (def && ((def->type == NODE_STRUCT && def->strct.is_template) || - (def->type == NODE_ENUM && def->enm.is_template))) + if (target_gen_param || (def && ((def->type == NODE_STRUCT && def->strct.is_template) || + (def->type == NODE_ENUM && def->enm.is_template)))) { const char *gp = "T"; - if (def->type == NODE_STRUCT && def->strct.generic_param_count > 0) + if (target_gen_param) + { + gp = target_gen_param; + } + else if (def && def->type == NODE_STRUCT && def->strct.generic_param_count > 0) { gp = def->strct.generic_params[0]; } @@ -347,6 +389,10 @@ ASTNode *parse_impl(ParserContext *ctx, Lexer *l) { ctx->known_generics_count--; } + if (target_gen_param) + { + ctx->known_generics_count--; + } return n; } else diff --git a/tests/generics/test_generic_traits.zc b/tests/generics/test_generic_traits.zc new file mode 100644 index 0000000..8458ba0 --- /dev/null +++ b/tests/generics/test_generic_traits.zc @@ -0,0 +1,42 @@ + +trait MyClone { + fn my_clone(self) -> int; +} + +struct GBox { + val: T; +} + +impl MyClone for GBox { + fn my_clone(self) -> int { + return 1; + } +} + +test "generic_trait_method_resolution" { + var b = GBox{ val: 10 }; + var res = b.my_clone(); + assert(res == 1, "Generic trait method call failed"); +} + +trait ValueProvider { + fn get_value(self) -> int; +} + +struct Wrapper { + inner: T; +} + +impl ValueProvider for Wrapper { + fn get_value(self) -> int { + return 42; + } +} + +test "generic_trait_resolution_complex" { + var w = Wrapper{ inner: true }; + assert(w.get_value() == 42, "Wrapper trait call failed"); + + var w2 = Wrapper{ inner: 100 }; + assert(w2.get_value() == 42, "Wrapper trait call failed"); +} -- cgit v1.2.3