From 73aec0aa8344c81e4b790c561b2d60a1af437965 Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Wed, 15 Apr 2026 16:50:41 +0300 Subject: [PATCH] all: fix more tests --- vlib/flag/flag_to.v | 41 +++++++++++++++++++ vlib/sync/sync_darwin.c.v | 18 +++++++- vlib/sync/sync_default.c.v | 19 ++++++++- vlib/sync/sync_freebsd.c.v | 19 ++++++++- vlib/v/checker/assign.v | 4 +- vlib/v/checker/comptime.v | 4 +- vlib/v/gen/c/auto_eq_methods.v | 5 ++- vlib/v/gen/c/utils.v | 10 ++++- .../v/generics/new_generics_regression_test.v | 18 ++++---- 9 files changed, 121 insertions(+), 17 deletions(-) diff --git a/vlib/flag/flag_to.v b/vlib/flag/flag_to.v index b4351b022..37289b1e9 100644 --- a/vlib/flag/flag_to.v +++ b/vlib/flag/flag_to.v @@ -1813,3 +1813,44 @@ fn (mut fm FlagMapper) map_cmd_exe(flag_ctx FlagContext, field StructField) !boo } return false } + +// parsed_flags returns all parsed flags in order of position. +pub fn (fm FlagMapper) parsed_flags() []FlagData { + mut flags := []FlagData{} + for _, f in fm.field_map_flag { + flags << f + } + for _, arr in fm.array_field_map_flag { + for f in arr { + flags << f + } + } + flags.sort_with_compare(fn (a &FlagData, b &FlagData) int { + if a.pos != b.pos { + return if a.pos < b.pos { -1 } else { 1 } + } + return if a.name < b.name { + -1 + } else if a.name > b.name { + 1 + } else { + 0 + } + }) + return flags +} + +// handled_positions returns unique, sorted position indices from the input args +// that were consumed during parsing. +pub fn (fm FlagMapper) handled_positions() []int { + mut seen := map[int]bool{} + mut result := []int{} + for p in fm.handled_pos { + if p !in seen { + seen[p] = true + result << p + } + } + result.sort(a < b) + return result +} diff --git a/vlib/sync/sync_darwin.c.v b/vlib/sync/sync_darwin.c.v index 50c1353ac..e75d9c312 100644 --- a/vlib/sync/sync_darwin.c.v +++ b/vlib/sync/sync_darwin.c.v @@ -54,7 +54,8 @@ pub struct Mutex { @[heap] pub struct RwMutex { - mutex C.pthread_rwlock_t + mutex C.pthread_rwlock_t + inited u32 } struct RwMutexAttr { @@ -108,6 +109,19 @@ pub fn (mut m RwMutex) init() { // Give writer priority over readers C.pthread_rwlockattr_setkind_np(&a.attr, C.PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP) should_be_zero(C.pthread_rwlock_init(&m.mutex, &a.attr)) + C.atomic_store_u32(&m.inited, 1) +} + +fn (mut m RwMutex) lazy_init() { + if C.atomic_load_u32(&m.inited) == 0 { + mut expected := u32(0) + if C.atomic_compare_exchange_strong_u32(&m.inited, &expected, 1) { + a := RwMutexAttr{} + C.pthread_rwlockattr_init(&a.attr) + C.pthread_rwlockattr_setkind_np(&a.attr, C.PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP) + C.pthread_rwlock_init(&m.mutex, &a.attr) + } + } } // lock locks the mutex instance (`lock` is a keyword). @@ -145,6 +159,7 @@ pub fn (mut m Mutex) destroy() { // Note: RwMutex has separate read and write locks. @[inline] pub fn (mut m RwMutex) rlock() { + m.lazy_init() should_be_zero(C.pthread_rwlock_rdlock(&m.mutex)) } @@ -156,6 +171,7 @@ pub fn (mut m RwMutex) rlock() { // Note: RwMutex has separate read and write locks. @[inline] pub fn (mut m RwMutex) lock() { + m.lazy_init() should_be_zero(C.pthread_rwlock_wrlock(&m.mutex)) } diff --git a/vlib/sync/sync_default.c.v b/vlib/sync/sync_default.c.v index 32f441fdf..5140b1737 100644 --- a/vlib/sync/sync_default.c.v +++ b/vlib/sync/sync_default.c.v @@ -56,7 +56,8 @@ pub struct Mutex { @[heap] pub struct RwMutex { - mutex C.pthread_rwlock_t + mutex C.pthread_rwlock_t + inited u32 } struct RwMutexAttr { @@ -98,6 +99,20 @@ pub fn (mut m RwMutex) init() { C.pthread_rwlockattr_setkind_np(&a.attr, C.PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP) C.pthread_rwlock_init(&m.mutex, &a.attr) C.pthread_rwlockattr_destroy(&a.attr) // destroy the attr when done + C.atomic_store_u32(&m.inited, 1) +} + +fn (mut m RwMutex) lazy_init() { + if C.atomic_load_u32(&m.inited) == 0 { + mut expected := u32(0) + if C.atomic_compare_exchange_strong_u32(&m.inited, &expected, 1) { + a := RwMutexAttr{} + C.pthread_rwlockattr_init(&a.attr) + C.pthread_rwlockattr_setkind_np(&a.attr, C.PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP) + C.pthread_rwlock_init(&m.mutex, &a.attr) + C.pthread_rwlockattr_destroy(&a.attr) + } + } } // lock locks the mutex instance (`lock` is a keyword). @@ -135,6 +150,7 @@ pub fn (mut m Mutex) destroy() { // Note: RwMutex has separate read and write locks. @[inline] pub fn (mut m RwMutex) rlock() { + m.lazy_init() should_be_zero(C.pthread_rwlock_rdlock(&m.mutex)) } @@ -146,6 +162,7 @@ pub fn (mut m RwMutex) rlock() { // Note: RwMutex has separate read and write locks. @[inline] pub fn (mut m RwMutex) lock() { + m.lazy_init() should_be_zero(C.pthread_rwlock_wrlock(&m.mutex)) } diff --git a/vlib/sync/sync_freebsd.c.v b/vlib/sync/sync_freebsd.c.v index df384cb2e..0016ff335 100644 --- a/vlib/sync/sync_freebsd.c.v +++ b/vlib/sync/sync_freebsd.c.v @@ -54,7 +54,8 @@ pub struct Mutex { @[heap] pub struct RwMutex { - mutex &C.pthread_rwlock = unsafe { nil } + mutex &C.pthread_rwlock = unsafe { nil } + inited u32 } struct RwMutexAttr { @@ -96,6 +97,20 @@ pub fn (mut m RwMutex) init() { C.pthread_rwlockattr_setkind_np(&a.attr, C.PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP) C.pthread_rwlock_init(&m.mutex, &a.attr) C.pthread_rwlockattr_destroy(&a.attr) // destroy the attr when done + C.atomic_store_u32(&m.inited, 1) +} + +fn (mut m RwMutex) lazy_init() { + if C.atomic_load_u32(&m.inited) == 0 { + mut expected := u32(0) + if C.atomic_compare_exchange_strong_u32(&m.inited, &expected, 1) { + a := RwMutexAttr{} + C.pthread_rwlockattr_init(&a.attr) + C.pthread_rwlockattr_setkind_np(&a.attr, C.PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP) + C.pthread_rwlock_init(&m.mutex, &a.attr) + C.pthread_rwlockattr_destroy(&a.attr) + } + } } // lock locks the mutex instance (`lock` is a keyword). @@ -133,6 +148,7 @@ pub fn (mut m Mutex) destroy() { // Note: RwMutex has separate read and write locks. @[inline] pub fn (mut m RwMutex) rlock() { + m.lazy_init() should_be_zero(C.pthread_rwlock_rdlock(&m.mutex)) } @@ -144,6 +160,7 @@ pub fn (mut m RwMutex) rlock() { // Note: RwMutex has separate read and write locks. @[inline] pub fn (mut m RwMutex) lock() { + m.lazy_init() should_be_zero(C.pthread_rwlock_wrlock(&m.mutex)) } diff --git a/vlib/v/checker/assign.v b/vlib/v/checker/assign.v index e4c01f6ce..be250bbb4 100644 --- a/vlib/v/checker/assign.v +++ b/vlib/v/checker/assign.v @@ -300,7 +300,9 @@ fn (mut c Checker) assign_stmt(mut node ast.AssignStmt) { right_type = right_type.clear_flag(.option) } } else if right is ast.ComptimeSelector { - right_type = c.comptime.comptime_for_field_type + if !(right as ast.ComptimeSelector).is_method { + right_type = c.comptime.comptime_for_field_type + } } if is_decl || is_shared_re_assign { // check generic struct init and return unwrap generic struct type diff --git a/vlib/v/checker/comptime.v b/vlib/v/checker/comptime.v index a39b64bb9..5bfb79b62 100644 --- a/vlib/v/checker/comptime.v +++ b/vlib/v/checker/comptime.v @@ -326,8 +326,8 @@ fn (mut c Checker) comptime_selector_method_value(mut node ast.ComptimeSelector) node.is_method = true fn_type := c.type_resolver.get_comptime_selector_type(node, ast.void_type) node.typ = c.unwrap_generic(fn_type) - c.markused_comptime_call(node.left_type.has_flag(.generic), - '${int(method.params[0].typ)}.${method.name}') + c.mark_fn_decl_as_referenced(method.fkey()) + c.markused_comptime_call(true, '${int(method.params[0].typ)}.${method.name}') receiver := c.unwrap_generic(method.params[0].typ) if receiver.nr_muls() > 0 && !c.inside_unsafe { rec_sym := c.table.sym(receiver.set_nr_muls(0)) diff --git a/vlib/v/gen/c/auto_eq_methods.v b/vlib/v/gen/c/auto_eq_methods.v index 1c5e8f050..032000b77 100644 --- a/vlib/v/gen/c/auto_eq_methods.v +++ b/vlib/v/gen/c/auto_eq_methods.v @@ -469,8 +469,9 @@ fn (mut g Gen) gen_fixed_array_equality_fn(left_type ast.Type) string { g.definitions.writeln('${g.static_non_parallel}bool ${ptr_styp}_arr_eq(${arg_styp} a, ${arg_styp} b);') is_option := left_type.has_flag(.option) - left := if is_option { 'a.data' } else { 'a' } - right := if is_option { 'b.data' } else { 'b' } + inner_type := g.base_type(left_typ.typ.set_nr_muls(0)) + left := if is_option { '(*(${inner_type}*)a.data)' } else { 'a' } + right := if is_option { '(*(${inner_type}*)b.data)' } else { 'b' } mut fn_builder := strings.new_builder(512) fn_builder.writeln('${g.static_non_parallel}inline bool ${ptr_styp}_arr_eq(${arg_styp} a, ${arg_styp} b) {') diff --git a/vlib/v/gen/c/utils.v b/vlib/v/gen/c/utils.v index cb8c161a2..3f25205a5 100644 --- a/vlib/v/gen/c/utils.v +++ b/vlib/v/gen/c/utils.v @@ -946,7 +946,15 @@ fn (mut g Gen) resolved_expr_type(expr ast.Expr, default_typ ast.Type) ast.Type } } ast.ComptimeSelector { - if expr.typ_key != '' { + if expr.is_method { + ctyp := g.type_resolver.get_comptime_selector_type(expr, ast.void_type) + if ctyp != ast.void_type { + return g.unwrap_generic(ctyp) + } + if expr.typ != ast.void_type && expr.typ != 0 { + return g.unwrap_generic(expr.typ) + } + } else if expr.typ_key != '' { ctyp := g.type_resolver.get_ct_type_or_default(expr.typ_key, default_typ) if ctyp != ast.void_type { return g.unwrap_generic(ctyp) diff --git a/vlib/v/generics/new_generics_regression_test.v b/vlib/v/generics/new_generics_regression_test.v index 47781e7ce..266fb4ee2 100644 --- a/vlib/v/generics/new_generics_regression_test.v +++ b/vlib/v/generics/new_generics_regression_test.v @@ -117,16 +117,16 @@ fn run_new_generic_solver_tests(root_label string, test_cmd string, expected_sum println('') } -const expected_summsvc_generics = 'Summary for all V _test.v files: 106 failed, 174 passed, 280 total.' +const expected_summsvc_generics = 'Summary for all V _test.v files: 110 failed, 177 passed, 287 total.' // The exact failure count varies slightly across compilers: -// gcc/tcc: 104, clang: 105, msvc/windows-gcc: 106. -const expected_summary_generics = 'Summary for all V _test.v files: 104 failed, 176 passed, 280 total.' +// gcc/tcc: 108, clang: 109, msvc/windows-gcc: 110. +const expected_summary_generics = 'Summary for all V _test.v files: 108 failed, 179 passed, 287 total.' const expected_summsvc_vec = 'Summary for all V _test.v files: 3 failed, 3 total.' const expected_summary_vec = 'Summary for all V _test.v files: 3 failed, 3 total.' -const expected_summsvc_flag = 'Summary for all V _test.v files: 20 passed, 20 total.' -const expected_summary_flag = 'Summary for all V _test.v files: 20 passed, 20 total.' -const expected_summsvc_flag_clean = 'Summary for all V _test.v files: 20 passed, 20 total.' -const expected_summary_flag_clean = 'Summary for all V _test.v files: 20 passed, 20 total.' +const expected_summsvc_flag = 'Summary for all V _test.v files: 21 passed, 21 total.' +const expected_summary_flag = 'Summary for all V _test.v files: 21 passed, 21 total.' +const expected_summsvc_flag_clean = 'Summary for all V _test.v files: 21 passed, 21 total.' +const expected_summary_flag_clean = 'Summary for all V _test.v files: 21 passed, 21 total.' const failing_tests = [ 'vlib/v/tests/generics/checks_for_operator_overrides_should_happen_on_the_concrete_types_when_using_generics_test.v', 'vlib/v/tests/generics/default_type_with_ref_test.v', @@ -148,16 +148,17 @@ const failing_tests = [ 'vlib/v/tests/generics/generic_function_error_propagation_test.v', 'vlib/v/tests/generics/generic_interface_field_test.v', 'vlib/v/tests/generics/generic_interface_infer_test.v', + 'vlib/v/tests/generics/generic_interface_map_value_test.v', 'vlib/v/tests/generics/generic_interface_nested_generic_type_infer_test.v', 'vlib/v/tests/generics/generic_interface_test.v', 'vlib/v/tests/generics/generic_map_alias_test.v', 'vlib/v/tests/generics/generic_match_generic_interface_type_test.v', 'vlib/v/tests/generics/generic_method_with_variadic_generic_args_test.v', - 'vlib/v/tests/generics/generic_mut_pointer_param_test.v', 'vlib/v/tests/generics/generic_operator_overload_test.v', 'vlib/v/tests/generics/generic_receiver_embed_test.v', 'vlib/v/tests/generics/generic_recursive_fn_test.v', 'vlib/v/tests/generics/generic_resolve_test.v', + 'vlib/v/tests/generics/generic_return_array_generic_test.v', 'vlib/v/tests/generics/generic_return_test.v', 'vlib/v/tests/generics/generic_selector_field_test.v', 'vlib/v/tests/generics/generic_selector_indexexpr_test.v', @@ -219,6 +220,7 @@ const failing_tests = [ 'vlib/v/tests/generics/generics_struct_with_inconsistent_generic_types_1_test.v', 'vlib/v/tests/generics/generics_struct_with_non_generic_interface_test.v', 'vlib/v/tests/generics/generics_struct_with_option_fn_test.v', + 'vlib/v/tests/generics/generics_unused_specialized_fn_array_param_test.v', 'vlib/v/tests/generics/generics_with_anon_generics_fn_test.v', 'vlib/v/tests/generics/generics_with_assign_nested_generics_call_test.v', 'vlib/v/tests/generics/generics_with_embed_generics_method_call_test.v', -- 2.39.5