From 0d6e386d09a073f31a570726a368a2158f2a8163 Mon Sep 17 00:00:00 2001 From: Felipe Pena Date: Thu, 26 Dec 2024 18:06:21 -0300 Subject: [PATCH] checker, cgen: fix generic static method resolving on IfGuard (fix #23269) (fix #23270) (#23273) --- vlib/v/checker/if.v | 12 ++++++++++ vlib/v/checker/return.v | 5 ++++ vlib/v/gen/c/autofree.v | 3 +++ vlib/v/gen/c/fn.v | 7 +++++- vlib/v/gen/c/if.v | 8 ++++++- .../enum_from_generic_static_call_test.v | 23 +++++++++++++++++++ 6 files changed, 56 insertions(+), 2 deletions(-) create mode 100644 vlib/v/tests/enums/enum_from_generic_static_call_test.v diff --git a/vlib/v/checker/if.v b/vlib/v/checker/if.v index b4e7fbd33044b3..b20d72fe8de90f 100644 --- a/vlib/v/checker/if.v +++ b/vlib/v/checker/if.v @@ -93,6 +93,18 @@ fn (mut c Checker) if_expr(mut node ast.IfExpr) ast.Type { branch.scope.update_var_type(var.name, mr_info.types[vi]) } } + } else { + for _, var in branch.cond.vars { + if var.name == '_' { + continue + } + if w := branch.scope.find_var(var.name) { + if var.name !in branch.scope.objects { + branch.scope.objects[var.name] = w + } + branch.scope.update_var_type(var.name, branch.cond.expr_type.clear_option_and_result()) + } + } } } if node.is_comptime { // Skip checking if needed diff --git a/vlib/v/checker/return.v b/vlib/v/checker/return.v index dc80406f25ef98..d751df961a26bf 100644 --- a/vlib/v/checker/return.v +++ b/vlib/v/checker/return.v @@ -110,6 +110,11 @@ fn (mut c Checker) return_stmt(mut node ast.Return) { if expr.obj.ct_type_var != .no_comptime { typ = c.comptime.get_type_or_default(expr, typ) } + if mut expr.obj.expr is ast.IfGuardExpr { + if var := expr.scope.find_var(expr.name) { + typ = var.typ + } + } } } got_types << typ diff --git a/vlib/v/gen/c/autofree.v b/vlib/v/gen/c/autofree.v index bc5bbf1066d9a0..a7cd83891fffb3 100644 --- a/vlib/v/gen/c/autofree.v +++ b/vlib/v/gen/c/autofree.v @@ -95,6 +95,9 @@ fn (mut g Gen) autofree_scope_vars2(scope &ast.Scope, start_pos int, end_pos int // Do not free vars that were declared after this scope continue } + if obj.expr is ast.IfGuardExpr { + continue + } g.autofree_variable(obj) } else {} diff --git a/vlib/v/gen/c/fn.v b/vlib/v/gen/c/fn.v index 76f95a618650d3..b1dd98680c3499 100644 --- a/vlib/v/gen/c/fn.v +++ b/vlib/v/gen/c/fn.v @@ -2109,12 +2109,17 @@ fn (mut g Gen) fn_call(node ast.CallExpr) { } is_selector_call = true } + mut node_name := node.name // name to find on fn table mut name := node.name if node.is_static_method { // resolve static call T.name() if g.cur_fn != unsafe { nil } { _, name = g.table.convert_generic_static_type_name(node.name, g.cur_fn.generic_names, g.cur_concrete_types) + if node.concrete_types.len > 0 { + // Resolves T.from() to real symbol name to search on fn table + node_name = name + } } } is_print := name in ['print', 'println', 'eprint', 'eprintln', 'panic'] @@ -2210,7 +2215,7 @@ fn (mut g Gen) fn_call(node ast.CallExpr) { } } if !is_selector_call { - if func := g.table.find_fn(node.name) { + if func := g.table.find_fn(node_name) { mut concrete_types := node.concrete_types.map(g.unwrap_generic(it)) mut node_ := unsafe { node } comptime_args := g.resolve_comptime_args(func, mut node_, concrete_types) diff --git a/vlib/v/gen/c/if.v b/vlib/v/gen/c/if.v index d820b5f27b4856..bfb5175d5ba43f 100644 --- a/vlib/v/gen/c/if.v +++ b/vlib/v/gen/c/if.v @@ -253,7 +253,13 @@ fn (mut g Gen) if_expr(node ast.IfExpr) { if cond.expr !in [ast.IndexExpr, ast.PrefixExpr] { var_name := g.new_tmp_var() guard_vars[i] = var_name - g.writeln('${g.styp(g.unwrap_generic(cond.expr_type))} ${var_name};') + cond_expr_type := if cond.expr is ast.CallExpr && cond.expr.is_static_method + && cond.expr.left_type.has_flag(.generic) { + g.resolve_return_type(cond.expr) + } else { + cond.expr_type + } + g.writeln('${g.styp(g.unwrap_generic(cond_expr_type))} ${var_name};') } else { guard_vars[i] = '' } diff --git a/vlib/v/tests/enums/enum_from_generic_static_call_test.v b/vlib/v/tests/enums/enum_from_generic_static_call_test.v new file mode 100644 index 00000000000000..75d06be345c68b --- /dev/null +++ b/vlib/v/tests/enums/enum_from_generic_static_call_test.v @@ -0,0 +1,23 @@ +fn prompt_enum[T](s string) !T { + if x := T.from(s) { + return x + } + return error('fail') +} + +enum EnumA { + a + b + c +} + +enum EnumB { + x + y + z +} + +fn test_main() { + assert prompt_enum[EnumA]('a')! == EnumA.a + assert prompt_enum[EnumB]('x')! == EnumB.x +}