From 4e9abd4e3add82fdd96f40f0618a381dd2d1e9d8 Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Thu, 23 Apr 2026 03:29:16 +0300 Subject: [PATCH] all: fix more tests --- vlib/v/checker/check_types.v | 15 ++++--- vlib/v/checker/comptime.v | 3 ++ vlib/v/checker/fn.v | 4 +- vlib/v/gen/c/fn.v | 12 ++---- vlib/v/gen/c/str.v | 9 ++--- vlib/v/markused/walker.v | 40 ++++++++++++++++++- .../builtin_maps/map_get_anon_fn_value_test.v | 6 ++- .../tests/sumtypes/alias_sumtype_match_test.v | 1 - 8 files changed, 65 insertions(+), 25 deletions(-) diff --git a/vlib/v/checker/check_types.v b/vlib/v/checker/check_types.v index 27d90cd1d..728423d30 100644 --- a/vlib/v/checker/check_types.v +++ b/vlib/v/checker/check_types.v @@ -1267,6 +1267,7 @@ fn (mut c Checker) infer_composite_generic_type(gt_name string, generic_typ ast. actual_type_args, actual_parent_idx := c.generic_type_args_and_parent_idx(concrete_typ) if expected_parent_idx != 0 && actual_parent_idx != 0 && expected_type_args.len > 0 && expected_type_args.len == actual_type_args.len { + mut parent_types_match := true if expected_parent_idx != actual_parent_idx { expected_parent_sym := c.table.sym(ast.idx_to_type(expected_parent_idx)) actual_parent_sym := c.table.sym(ast.idx_to_type(actual_parent_idx)) @@ -1283,14 +1284,16 @@ fn (mut c Checker) infer_composite_generic_type(gt_name string, generic_typ ast. if expected_parent_name != actual_parent_name && expected_parent_sym.parent_idx != actual_parent_idx && actual_parent_sym.parent_idx != expected_parent_idx { - return ast.void_type + parent_types_match = false } } - for i, expected_type_arg in expected_type_args { - inferred_type := c.infer_composite_generic_type(gt_name, expected_type_arg, - actual_type_args[i]) - if inferred_type != ast.void_type { - return inferred_type + if parent_types_match { + for i, expected_type_arg in expected_type_args { + inferred_type := c.infer_composite_generic_type(gt_name, expected_type_arg, + actual_type_args[i]) + if inferred_type != ast.void_type { + return inferred_type + } } } } diff --git a/vlib/v/checker/comptime.v b/vlib/v/checker/comptime.v index a792c526c..26c330fd8 100644 --- a/vlib/v/checker/comptime.v +++ b/vlib/v/checker/comptime.v @@ -70,6 +70,9 @@ fn (mut c Checker) check_comptime_method_call_args(mut node ast.ComptimeCall) { if c.comptime.comptime_for_method == unsafe { nil } { return } + if node.args.any(it.expr is ast.ArrayDecompose) { + return + } method := c.comptime.comptime_for_method if method.params.len == 0 { return diff --git a/vlib/v/checker/fn.v b/vlib/v/checker/fn.v index a8dbeb33c..6e4b843ce 100644 --- a/vlib/v/checker/fn.v +++ b/vlib/v/checker/fn.v @@ -2312,7 +2312,9 @@ fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool) ast. node.args[i].typ = arg_typ call_arg.typ = arg_typ if c.comptime.comptime_for_field_var != '' { - if mut call_arg.expr is ast.Ident && call_arg.expr.obj is ast.Var { + if mut call_arg.expr is ast.Ident + && call_arg.expr.name == c.comptime.comptime_for_field_var + && call_arg.expr.obj is ast.Var { node.args[i].typ = call_arg.expr.obj.typ } } diff --git a/vlib/v/gen/c/fn.v b/vlib/v/gen/c/fn.v index e719acd8e..8fed1cfc5 100644 --- a/vlib/v/gen/c/fn.v +++ b/vlib/v/gen/c/fn.v @@ -978,6 +978,9 @@ fn (mut g Gen) post_process_generic_fns_for_files(files []&ast.File) { g.fid = fid g.file = file for generic_fn in file.generic_fns { + if generic_fn.is_anon { + continue + } effective_generic_names := g.effective_fn_generic_names(*generic_fn) if effective_generic_names.len == 0 { continue @@ -1515,7 +1518,7 @@ fn (mut g Gen) c_fn_name(node &ast.FnDecl) string { name = name.replace_each(c_fn_name_escape_seq) } } - if node.is_anon && g.anon_fn.has_ct_var { + if node.is_anon && g.anon_fn != unsafe { nil } && g.anon_fn.has_ct_var { name = '${name}_${g.comptime.comptime_loop_id}' } if node.language == .c { @@ -1875,13 +1878,6 @@ fn (mut g Gen) fn_decl_params(params []ast.Param, scope &ast.Scope, is_variadic if g.pref.translated && g.file.is_translated && param.typ.has_flag(.variadic) { typ = g.table.sym(typ).array_info().elem_type.set_flag(.variadic) } - // `mut ?T` params are modeled as `?&T` internally, but the emitted C type - // must be pointer-to-option-of-T: `_option_T*`, not `_option_T_ptr*`. - if param.is_mut && param.orig_typ != 0 && param.orig_typ.has_flag(.option) - && !param.orig_typ.has_flag(.generic) && !param.orig_typ.is_ptr() - && typ.has_flag(.option) && typ.is_ptr() { - typ = g.unwrap_generic(param.orig_typ).set_flag(.option_mut_param_t) - } if param.is_mut && param.orig_typ != 0 && param.orig_typ.has_flag(.generic) && param.typ.has_flag(.generic) { mut surface_typ := g.unwrap_generic(param.orig_typ) diff --git a/vlib/v/gen/c/str.v b/vlib/v/gen/c/str.v index e900992d3..e392c89c0 100644 --- a/vlib/v/gen/c/str.v +++ b/vlib/v/gen/c/str.v @@ -71,10 +71,6 @@ fn option_mut_param_surface_type(expr ast.Expr) ast.Type { if typ == 0 || !typ.has_flag(.option) { return 0 } - inner := typ.clear_option_and_result() - if inner.is_ptr() { - return inner.deref().set_flag(.option) - } return typ } @@ -91,8 +87,9 @@ fn (mut g Gen) gen_expr_to_string(expr ast.Expr, etype ast.Type) { if is_shared { typ = typ.clear_flag(.shared_f).set_nr_muls(0) } - // option_mut_param_t is pointer-like even when nr_muls == 0 - is_ptr := typ.is_ptr() || typ.has_flag(.option_mut_param_t) + // `mut ?T` params are passed by pointer in C, but should still stringify as + // option values rather than as raw `&...` pointers. + is_ptr := typ.is_ptr() || (typ.has_flag(.option_mut_param_t) && !typ.has_flag(.option)) mut sym := g.table.sym(typ) // when type is non-option alias and doesn't has `str()`, print the aliased value if mut sym.info is ast.Alias && !sym.has_method('str') && !etype.has_flag(.option) { diff --git a/vlib/v/markused/walker.v b/vlib/v/markused/walker.v index db2a514f7..ec99cc928 100644 --- a/vlib/v/markused/walker.v +++ b/vlib/v/markused/walker.v @@ -577,7 +577,22 @@ pub fn (mut w Walker) mark_generic_fn_instances() { continue } base_fkey := generic_fn.fkey() - for concrete_types in w.table.fn_generic_types[base_fkey] { + mut concrete_type_sets := [][]ast.Type{} + if w.keep_all_fn_generic_types[base_fkey] { + concrete_type_sets = w.table.fn_generic_types[base_fkey].clone() + } else { + for concrete_types in w.used_fn_generic_types[base_fkey] { + if concrete_types !in concrete_type_sets { + concrete_type_sets << concrete_types.clone() + } + } + for concrete_types in w.walked_fn_generic_types[base_fkey] { + if concrete_types !in concrete_type_sets { + concrete_type_sets << concrete_types.clone() + } + } + } + for concrete_types in concrete_type_sets { if concrete_types.any(it.has_flag(.generic)) { continue } @@ -2952,6 +2967,29 @@ fn (mut w Walker) remove_unused_fn_generic_types() { } } } + // Phase 6: Prune non-method generic functions to the concrete type sets + // that were actually reached during the markused walk. + for fkey, _ in w.table.fn_generic_types { + if w.keep_all_fn_generic_types[fkey] { + continue + } + fn_decl := w.all_fns[fkey] or { continue } + if fn_decl.is_method { + continue + } + mut kept_types := [][]ast.Type{} + for concrete_type_list in w.used_fn_generic_types[fkey] { + if concrete_type_list !in kept_types { + kept_types << concrete_type_list.clone() + } + } + for concrete_type_list in w.walked_fn_generic_types[fkey] { + if concrete_type_list !in kept_types { + kept_types << concrete_type_list.clone() + } + } + w.table.fn_generic_types[fkey] = kept_types + } } fn (mut w Walker) mark_resource_dependencies() { diff --git a/vlib/v/tests/builtin_maps/map_get_anon_fn_value_test.v b/vlib/v/tests/builtin_maps/map_get_anon_fn_value_test.v index 24d6399e2..cc360acdd 100644 --- a/vlib/v/tests/builtin_maps/map_get_anon_fn_value_test.v +++ b/vlib/v/tests/builtin_maps/map_get_anon_fn_value_test.v @@ -66,6 +66,8 @@ fn test_cast_map_literal_with_closure_value() { return [tree.value + input] } - assert belt['bar']('foo') == ['he hefoo'] - assert belt2['bar']('fo') == ['he hefo'] + bar := belt['bar'] or { panic('missing `bar` in belt') } + bar2 := belt2['bar'] or { panic('missing `bar` in belt2') } + assert bar('foo') == ['he hefoo'] + assert bar2('fo') == ['he hefo'] } diff --git a/vlib/v/tests/sumtypes/alias_sumtype_match_test.v b/vlib/v/tests/sumtypes/alias_sumtype_match_test.v index f7e66db73..6dcf37cd4 100644 --- a/vlib/v/tests/sumtypes/alias_sumtype_match_test.v +++ b/vlib/v/tests/sumtypes/alias_sumtype_match_test.v @@ -41,7 +41,6 @@ fn test_match_on_sumtype_alias_parent_type_regression() { AliasMatchSome[AliasMatchParseRes] { match r.value { AliasMatchResult[[]AliasMatchToken, AliasMatchParseErr] {} - else {} } } AliasMatchNone[AliasMatchParseRes] { -- 2.39.5