Skip to content

Commit

Permalink
checker, cgen: fix generic static method resolving on IfGuard (fix #2…
Browse files Browse the repository at this point in the history
  • Loading branch information
felipensp authored Dec 26, 2024
1 parent 18a1afe commit 0d6e386
Show file tree
Hide file tree
Showing 6 changed files with 56 additions and 2 deletions.
12 changes: 12 additions & 0 deletions vlib/v/checker/if.v
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
5 changes: 5 additions & 0 deletions vlib/v/checker/return.v
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 3 additions & 0 deletions vlib/v/gen/c/autofree.v
Original file line number Diff line number Diff line change
Expand Up @@ -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 {}
Expand Down
7 changes: 6 additions & 1 deletion vlib/v/gen/c/fn.v
Original file line number Diff line number Diff line change
Expand Up @@ -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']
Expand Down Expand Up @@ -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)
Expand Down
8 changes: 7 additions & 1 deletion vlib/v/gen/c/if.v
Original file line number Diff line number Diff line change
Expand Up @@ -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] = ''
}
Expand Down
23 changes: 23 additions & 0 deletions vlib/v/tests/enums/enum_from_generic_static_call_test.v
Original file line number Diff line number Diff line change
@@ -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
}

0 comments on commit 0d6e386

Please sign in to comment.