From 4201af8053bfbe4870581afd8de7a0bfd92ee800 Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Mon, 20 Apr 2026 23:24:37 +0300 Subject: [PATCH] all: fix several test failures with `-cc clang` - cgen: skip auto-heap deref for Ident from option/result unwrap (fixes variadic_interface_array_arg_test.v) - cgen: special-case sumtype-with-option-variant in ident smartcast loop (fixes option_sumtype_variant_test.v and option_unwrap_ifexpr_test.v) - infix: skip SLIT_EQ optimization for sumtype smartcast Ident - tests: update cheaders_manual_stdlib_decls_test for split __APPLE__ block - tests: update new_generics_regression_test expected counts - tests: drop double-quoting of already-quoted vexe in wasm test - vlib/x/sessions/veb_middleware: restore module deleted in vweb removal, required by session_app_test.v --- vlib/v/gen/c/cgen.v | 20 ++++++++++- .../gen/c/cheaders_manual_stdlib_decls_test.v | 3 +- vlib/v/gen/c/infix.v | 4 ++- .../v/generics/new_generics_regression_test.v | 5 ++- ...to_wasm_works_with_d_and_notd_files_test.v | 4 +-- .../sessions/veb_middleware/veb_middleware.v | 33 +++++++++++++++++++ 6 files changed, 61 insertions(+), 8 deletions(-) create mode 100644 vlib/x/sessions/veb_middleware/veb_middleware.v diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index 618e2aa5b..6a6266ed9 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -4080,7 +4080,7 @@ fn (mut g Gen) call_cfn_for_casting_expr(fname string, expr ast.Expr, exp ast.Ty needs_interface_value_copy := is_interface_cast && !preserve_interface_field_aliasing && !g.expected_arg_mut && !got_is_ptr && expr_is_lvalue force_auto_heap_value_deref = needs_interface_value_copy && expr is ast.Ident - && g.resolved_ident_is_auto_heap(expr) + && g.resolved_ident_is_auto_heap(expr) && !g.ident_unwraps_option_or_result(expr) if !is_cast_fixed_array_init && (is_comptime_variant || !expr_is_lvalue || (expr is ast.Ident && (expr.obj.is_simple_define_const() @@ -8135,6 +8135,24 @@ fn (mut g Gen) ident(node ast.Ident) { && !g.inside_selector_lhs && raw_smartcast_target_kind !in [.struct, .aggregate, .array, .array_fixed, .map, .interface, .sum_type, .function] if !prevent_sum_type_unwrapping_once { + // Special-case: sumtype variant is an Option type and we are + // past `if x != none` — emit the simple correct expression + // `*(INNER*)(name.__option_VARIANT->data)`. The general loop + // below produces malformed C for this case. + if obj_sym.kind == .sum_type && is_option && resolved_var.is_unwrapped + && !is_auto_heap && !resolved_var.orig_type.has_flag(.option) { + variant_typ := if resolved_var.ct_type_var == .smartcast { + g.unwrap_generic(g.type_resolver.get_type(node)).set_flag(.option) + } else { + smartcast_types[0] + } + variant_sym := g.table.sym(variant_typ) + variant_field := g.get_sumtype_variant_name(variant_typ, variant_sym) + inner_typ := variant_typ.clear_flag(.option) + inner_styp := g.styp(g.unwrap_generic(inner_typ)) + g.write('*(${inner_styp}*)(${name}._${variant_field}->data)') + return + } nested_unwrap := smartcast_types.len > 1 unwrap_sumtype := is_option && nested_unwrap && obj_sym.kind == .sum_type if unwrap_sumtype { diff --git a/vlib/v/gen/c/cheaders_manual_stdlib_decls_test.v b/vlib/v/gen/c/cheaders_manual_stdlib_decls_test.v index 15298e4c9..4359d7883 100644 --- a/vlib/v/gen/c/cheaders_manual_stdlib_decls_test.v +++ b/vlib/v/gen/c/cheaders_manual_stdlib_decls_test.v @@ -37,7 +37,8 @@ fn test_default_c_prelude_uses_manual_stdio_stdlib_string_and_stdarg_decls() { assert generated_c.contains('double atof(const char *str);'), generated_c assert generated_c.contains('extern FILE* stdout;'), generated_c assert generated_c.contains('#define stdout (__acrt_iob_func(1))'), generated_c - assert generated_c.contains('#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__)\ntypedef struct __sFILE FILE;\nextern FILE* __stdinp;\nextern FILE* __stdoutp;\nextern FILE* __stderrp;\n#define stdin __stdinp\n#define stdout __stdoutp\n#define stderr __stderrp'), generated_c + assert generated_c.contains('#if defined(__APPLE__) || defined(__FreeBSD__)\ntypedef struct __sFILE FILE;\nextern FILE* __stdinp;\nextern FILE* __stdoutp;\nextern FILE* __stderrp;\n#define stdin __stdinp\n#define stdout __stdoutp\n#define stderr __stderrp'), generated_c + assert generated_c.contains('#elif defined(__NetBSD__) || defined(__DragonFly__)\ntypedef struct __sFILE FILE;\nextern FILE* __stdinp;\nextern FILE* __stdoutp;\nextern FILE* __stderrp;\n#define stdin __stdinp\n#define stdout __stdoutp\n#define stderr __stderrp'), generated_c assert generated_c.contains('#elif defined(__OpenBSD__)\ntypedef struct __sFILE FILE;\nextern FILE* __stdin;\nextern FILE* __stdout;\nextern FILE* __stderr;\n#define stdin __stdin\n#define stdout __stdout\n#define stderr __stderr'), generated_c } diff --git a/vlib/v/gen/c/infix.v b/vlib/v/gen/c/infix.v index 3d1ab2485..00429bf90 100644 --- a/vlib/v/gen/c/infix.v +++ b/vlib/v/gen/c/infix.v @@ -211,7 +211,9 @@ fn (mut g Gen) infix_expr_eq_op(node ast.InfixExpr) { } else if (left.typ.idx() == ast.string_type_idx || (!has_defined_eq_operator && left.unaliased.idx() == ast.string_type_idx)) && node.right is ast.StringLiteral && (node.right.val == '' || (node.left is ast.SelectorExpr - || (node.left is ast.Ident && node.left.or_expr.kind == .absent))) { + || (node.left is ast.Ident && node.left.or_expr.kind == .absent + && !(node.left.obj is ast.Var && node.left.obj.ct_type_var == .smartcast + && g.table.sym(g.unwrap_generic(node.left.obj.orig_type)).kind == .sum_type)))) { if node.right.val == '' { // `str == ''` -> `str.len == 0` optimization g.write('(') diff --git a/vlib/v/generics/new_generics_regression_test.v b/vlib/v/generics/new_generics_regression_test.v index 3d79ebcf6..af096ec33 100644 --- a/vlib/v/generics/new_generics_regression_test.v +++ b/vlib/v/generics/new_generics_regression_test.v @@ -117,9 +117,9 @@ 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: 111 failed, 180 passed, 291 total.' +const expected_summsvc_generics = 'Summary for all V _test.v files: 110 failed, 182 passed, 292 total.' // The exact failure count varies slightly across compilers. -const expected_summary_generics = 'Summary for all V _test.v files: 109 failed, 182 passed, 291 total.' +const expected_summary_generics = 'Summary for all V _test.v files: 108 failed, 184 passed, 292 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: 21 passed, 21 total.' @@ -214,7 +214,6 @@ const failing_tests = [ 'vlib/v/tests/generics/generics_str_intp_test.v', 'vlib/v/tests/generics/generics_struct_anon_fn_type_test.v', 'vlib/v/tests/generics/generics_struct_free_test.v', - 'vlib/v/tests/generics/generics_struct_init_with_inconsistent_generic_types_7_test.v', 'vlib/v/tests/generics/generics_struct_inst_method_call_test.v', 'vlib/v/tests/generics/generics_struct_parent_has_str_to_string_test.v', 'vlib/v/tests/generics/generics_struct_to_string_test.v', diff --git a/vlib/v/tests/project_compiling_to_wasm/compilation_to_wasm_works_with_d_and_notd_files_test.v b/vlib/v/tests/project_compiling_to_wasm/compilation_to_wasm_works_with_d_and_notd_files_test.v index 653510dfe..cc4814135 100644 --- a/vlib/v/tests/project_compiling_to_wasm/compilation_to_wasm_works_with_d_and_notd_files_test.v +++ b/vlib/v/tests/project_compiling_to_wasm/compilation_to_wasm_works_with_d_and_notd_files_test.v @@ -22,7 +22,7 @@ fn test_normal() { } defer { println('done ${@FN}') } dump(vexe) - res := os.system('${os.quoted_path(vexe)} -o normal.exe ${os.quoted_path(project_folder)}') + res := os.system('${vexe} -o normal.exe ${os.quoted_path(project_folder)}') assert res == 0 dump(res) assert os.exists('normal.exe') @@ -41,7 +41,7 @@ fn test_emcc() { } dump(emcc) res := - os.system('${os.quoted_path(vexe)} -os wasm32_emscripten -o wasm_check.html ${os.quoted_path(project_folder)}') + os.system('${vexe} -os wasm32_emscripten -o wasm_check.html ${os.quoted_path(project_folder)}') assert res == 0 dump(res) assert os.exists('wasm_check.html') diff --git a/vlib/x/sessions/veb_middleware/veb_middleware.v b/vlib/x/sessions/veb_middleware/veb_middleware.v new file mode 100644 index 000000000..e1b64d775 --- /dev/null +++ b/vlib/x/sessions/veb_middleware/veb_middleware.v @@ -0,0 +1,33 @@ +module veb_middleware + +import x.sessions +import veb + +// create can be used to add session middleware to your veb app to ensure +// a valid session always exists. If a valid session exists the session data will +// be loaded into `session_data`, else a new session id will be generated. +// You have to pass the Context type as the generic type. +pub fn create[T, X](mut s sessions.Sessions[T]) veb.MiddlewareOptions[X] { + return veb.MiddlewareOptions[X]{ + handler: fn [mut s] [T, X](mut ctx X) bool { + // a session id is retrieved from the client, so it must be considered + // untrusted and has to be verified on every request + sid, valid := s.validate_session(ctx) + + if !valid { + if s.save_uninitialized { + // invalid session id, so create a new one + s.set_session_id(mut ctx) + } + return true + } + + ctx.CurrentSession.session_id = sid + if data := s.store.get(sid, s.max_age) { + ctx.CurrentSession.session_data = data + } + + return true + } + } +} -- 2.39.5