From 4225a346d65da8cc2f0ca7c056e19395be665649 Mon Sep 17 00:00:00 2001 From: Felipe Pena Date: Sun, 29 Dec 2024 16:48:41 -0300 Subject: [PATCH] checker,cgen: fix generic arr.map(var as T) support (fix #23284) (#23302) --- vlib/v/checker/assign.v | 8 +++++++- vlib/v/checker/fn.v | 3 ++- vlib/v/gen/c/array.v | 18 ++++++++++++++++-- vlib/v/gen/c/assign.v | 7 +++++++ vlib/v/gen/c/index.v | 3 ++- .../generics/generic_as_cast_on_map_test.v | 14 ++++++++++++++ vlib/v/type_resolver/generic_resolver.v | 7 +++++++ 7 files changed, 55 insertions(+), 5 deletions(-) create mode 100644 vlib/v/tests/generics/generic_as_cast_on_map_test.v diff --git a/vlib/v/checker/assign.v b/vlib/v/checker/assign.v index 5494e2eadf80a1..1dbd32b06c9b58 100644 --- a/vlib/v/checker/assign.v +++ b/vlib/v/checker/assign.v @@ -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 diff --git a/vlib/v/checker/fn.v b/vlib/v/checker/fn.v index e5c7a3001ab7fa..44b820d1fafb32 100644 --- a/vlib/v/checker/fn.v +++ b/vlib/v/checker/fn.v @@ -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) } } diff --git a/vlib/v/gen/c/array.v b/vlib/v/gen/c/array.v index ec672967a7f80c..1c92d673b226e6 100644 --- a/vlib/v/gen/c/array.v +++ b/vlib/v/gen/c/array.v @@ -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) @@ -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} = ') diff --git a/vlib/v/gen/c/assign.v b/vlib/v/gen/c/assign.v index 34420e0efe7ca3..7f9bc53f73ab2d 100644 --- a/vlib/v/gen/c/assign.v +++ b/vlib/v/gen/c/assign.v @@ -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 diff --git a/vlib/v/gen/c/index.v b/vlib/v/gen/c/index.v index 73fa24bb8767fb..28c6cdacf42bb7 100644 --- a/vlib/v/gen/c/index.v +++ b/vlib/v/gen/c/index.v @@ -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 { diff --git a/vlib/v/tests/generics/generic_as_cast_on_map_test.v b/vlib/v/tests/generics/generic_as_cast_on_map_test.v new file mode 100644 index 00000000000000..15393be045f806 --- /dev/null +++ b/vlib/v/tests/generics/generic_as_cast_on_map_test.v @@ -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) +} diff --git a/vlib/v/type_resolver/generic_resolver.v b/vlib/v/type_resolver/generic_resolver.v index f605f990e0f3a3..b34626b9561c6a 100644 --- a/vlib/v/type_resolver/generic_resolver.v +++ b/vlib/v/type_resolver/generic_resolver.v @@ -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 } @@ -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 }