From 2f54c487608191fac1aacaa8577128771e31f9b0 Mon Sep 17 00:00:00 2001 From: CreeperFace <165158232+dy-tea@users.noreply.github.com> Date: Fri, 24 Oct 2025 20:49:38 +0100 Subject: [PATCH] checker: ensure ?Struct is not parsed as ??Struct when param is ?T (fix #25559) (#25564) --- vlib/v/checker/check_types.v | 11 +++++- .../option_unwrap_unwrap_or_generic_fn_test.v | 37 +++++++++++++++++++ 2 files changed, 47 insertions(+), 1 deletion(-) create mode 100644 vlib/v/tests/options/option_unwrap_unwrap_or_generic_fn_test.v diff --git a/vlib/v/checker/check_types.v b/vlib/v/checker/check_types.v index 31a8f349e..b11814728 100644 --- a/vlib/v/checker/check_types.v +++ b/vlib/v/checker/check_types.v @@ -1030,7 +1030,16 @@ fn (mut c Checker) infer_fn_generic_types(func &ast.Fn, mut node ast.CallExpr) { arg := node.args[arg_i] param_sym := c.table.sym(param.typ) - if param.typ.has_flag(.generic) && param_sym.name == gt_name { + if (param.typ.has_flag(.option) && arg.typ.has_flag(.option)) + || (param.typ.has_flag(.result) && arg.typ.has_flag(.result)) { + param_inner := param.typ.clear_option_and_result() + if param_inner.has_flag(.generic) && c.table.sym(param_inner).name == gt_name { + typ = arg.typ.clear_option_and_result() + if param_inner.nr_muls() > 0 && typ.nr_muls() > 0 { + typ = typ.set_nr_muls(0) + } + } + } else if param.typ.has_flag(.generic) && param_sym.name == gt_name { typ = ast.mktyp(arg.typ) if typ == ast.nil_type { typ = ast.voidptr_type diff --git a/vlib/v/tests/options/option_unwrap_unwrap_or_generic_fn_test.v b/vlib/v/tests/options/option_unwrap_unwrap_or_generic_fn_test.v new file mode 100644 index 000000000..acb1d6dba --- /dev/null +++ b/vlib/v/tests/options/option_unwrap_unwrap_or_generic_fn_test.v @@ -0,0 +1,37 @@ +fn unwrap[T](t ?T) T { + return t or { panic('none') } +} + +fn unwrap_or[T](t ?T, t_or T) T { + return t or { t_or } +} + +struct S1 { + value int +} + +struct S2 {} + +fn test_unwrap() { + s1 := ?S1{ + value: 42 + } + assert unwrap(s1).value == 42 + + // see #25566 + s2 := ?S2(S2{}) + assert unwrap(s2) == S2{} +} + +fn test_unwrap_or() { + s1 := ?S1{ + value: 42 + } + assert unwrap_or(s1, S1{ value: 12 }).value == 42 + + s1n := ?S1(none) + assert unwrap_or(s1n, S1{ value: 12 }).value == 12 + + s2 := ?S2{} + assert unwrap_or(s2, S2{}) == S2{} +} -- 2.39.5