Skip to content

Commit

Permalink
checker,cgen: fix generic arr.map(var as T) support (fix #23284) (#23302
Browse files Browse the repository at this point in the history
)
  • Loading branch information
felipensp authored Dec 29, 2024
1 parent 1607579 commit 4225a34
Show file tree
Hide file tree
Showing 7 changed files with 55 additions and 5 deletions.
8 changes: 7 additions & 1 deletion vlib/v/checker/assign.v
Original file line number Diff line number Diff line change
Expand Up @@ -404,7 +404,13 @@ fn (mut c Checker) assign_stmt(mut node ast.AssignStmt) {
left.obj.ct_type_var = .field_var
left.obj.typ = c.comptime.comptime_for_field_type
} else if mut right is ast.CallExpr {
if left.obj.ct_type_var in [.generic_var, .no_comptime]
if right.left_type != 0
&& c.table.type_kind(right.left_type) == .array
&& right.name == 'map' && right.args.len > 0
&& right.args[0].expr is ast.AsCast
&& right.args[0].expr.typ.has_flag(.generic) {
left.obj.ct_type_var = .generic_var
} else if left.obj.ct_type_var in [.generic_var, .no_comptime]
&& c.table.cur_fn != unsafe { nil }
&& c.table.cur_fn.generic_names.len != 0
&& !right.comptime_ret_val
Expand Down
3 changes: 2 additions & 1 deletion vlib/v/checker/fn.v
Original file line number Diff line number Diff line change
Expand Up @@ -3569,7 +3569,8 @@ fn (mut c Checker) array_builtin_method_call(mut node ast.CallExpr, left_type as
c.error('`.contains()` expected 1 argument, but got ${node.args.len}', node.pos)
} else if !left_sym.has_method('contains') {
arg_typ := c.expr(mut node.args[0].expr)
c.check_expected_call_arg(arg_typ, elem_typ, node.language, node.args[0]) or {
c.check_expected_call_arg(arg_typ, c.unwrap_generic(elem_typ), node.language,
node.args[0]) or {
c.error('${err.msg()} in argument 1 to `.contains()`', node.args[0].pos)
}
}
Expand Down
18 changes: 16 additions & 2 deletions vlib/v/gen/c/array.v
Original file line number Diff line number Diff line change
Expand Up @@ -474,8 +474,15 @@ fn (mut g Gen) gen_array_map(node ast.CallExpr) {
g.past_tmp_var_done(past)
}

ret_styp := g.styp(node.return_type)
ret_sym := g.table.final_sym(node.return_type)
return_type := if g.type_resolver.is_generic_expr(node.args[0].expr) {
ast.new_type(g.table.find_or_register_array(g.type_resolver.unwrap_generic_expr(node.args[0].expr,
node.return_type)))
} else {
node.return_type
}
ret_styp := g.styp(return_type)
ret_sym := g.table.final_sym(return_type)

left_is_array := g.table.final_sym(node.left_type).kind == .array
inp_sym := g.table.final_sym(node.receiver_type)

Expand Down Expand Up @@ -608,6 +615,13 @@ fn (mut g Gen) gen_array_map(node ast.CallExpr) {
g.expr(expr)
}
}
ast.AsCast {
if expr.typ.has_flag(.generic) {
ret_elem_styp = g.styp(g.unwrap_generic(expr.typ))
}
g.write('${ret_elem_styp} ${tmp_map_expr_result_name} = ')
g.expr(expr)
}
else {
if closure_var_decl != '' {
g.write('${closure_var_decl} = ')
Expand Down
7 changes: 7 additions & 0 deletions vlib/v/gen/c/assign.v
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,13 @@ fn (mut g Gen) assign_stmt(node_ ast.AssignStmt) {
val_type = var_type
left.obj.typ = var_type
g.assign_ct_type = var_type
} else if val.left_type != 0 && g.table.type_kind(val.left_type) == .array
&& val.name == 'map' && val.args.len > 0 && val.args[0].expr is ast.AsCast
&& val.args[0].expr.typ.has_flag(.generic) {
var_type = g.table.find_or_register_array(g.unwrap_generic((val.args[0].expr as ast.AsCast).typ))
val_type = var_type
left.obj.typ = var_type
g.assign_ct_type = var_type
}
}
is_auto_heap = left.obj.is_auto_heap
Expand Down
3 changes: 2 additions & 1 deletion vlib/v/gen/c/index.v
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ fn (mut g Gen) index_expr(node ast.IndexExpr) {
if node.index is ast.RangeExpr {
g.index_range_expr(node, node.index)
} else {
sym := g.table.final_sym(g.unwrap_generic(node.left_type))
left_type := g.unwrap_generic(g.type_resolver.get_type_or_default(node.left, node.left_type))
sym := g.table.final_sym(left_type)
if sym.kind == .array {
g.index_of_array(node, sym)
} else if sym.kind == .array_fixed {
Expand Down
14 changes: 14 additions & 0 deletions vlib/v/tests/generics/generic_as_cast_on_map_test.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
type Sumtype = string | int

fn generic_fn[T](x Sumtype) bool {
y := [x].map(it as T)
mut arr := []T{}
arr << x as T
dump(arr)
return arr.contains(y[0])
}

fn test_main() {
assert generic_fn[string]('hello')
assert generic_fn[int](123)
}
7 changes: 7 additions & 0 deletions vlib/v/type_resolver/generic_resolver.v
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ pub fn (mut ct TypeResolver) unwrap_generic_expr(expr ast.Expr, default_typ ast.
default_typ
}
}
ast.AsCast {
return ct.resolver.unwrap_generic(expr.typ)
}
else {
return default_typ
}
Expand Down Expand Up @@ -71,6 +74,10 @@ pub fn (t &TypeResolver) is_generic_expr(node ast.Expr) bool {
// generic_var.property
t.is_generic_param_var(node.expr)
}
ast.AsCast {
// var as T
node.typ.has_flag(.generic)
}
else {
false
}
Expand Down

0 comments on commit 4225a34

Please sign in to comment.