diff --git a/vlib/v/checker/fn.v b/vlib/v/checker/fn.v index d652a8ab2e..99cfe7b971 100644 --- a/vlib/v/checker/fn.v +++ b/vlib/v/checker/fn.v @@ -1502,18 +1502,20 @@ fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool) ast. return func.return_type } -fn (mut c Checker) get_comptime_args(func ast.Fn, node_ ast.CallExpr, concrete_types []ast.Type) map[int]ast.Type { +fn (mut c Checker) resolve_comptime_args(func ast.Fn, node_ ast.CallExpr, concrete_types []ast.Type) map[int]ast.Type { mut comptime_args := map[int]ast.Type{} has_dynamic_vars := (c.table.cur_fn != unsafe { nil } && c.table.cur_fn.generic_names.len > 0) || c.inside_comptime_for_field if has_dynamic_vars { offset := if func.is_method { 1 } else { 0 } + mut k := -1 for i, call_arg in node_.args { param := if func.is_variadic && i >= func.params.len - (offset + 1) { func.params.last() } else { func.params[offset + i] } + k++ if !param.typ.has_flag(.generic) { continue } @@ -1528,7 +1530,7 @@ fn (mut c Checker) get_comptime_args(func ast.Fn, node_ ast.CallExpr, concrete_t && c.table.final_sym(param_typ).kind == .array { ctyp = arg_sym.info.elem_type } - comptime_args[i] = ctyp + comptime_args[k] = ctyp } } else if call_arg.expr.obj.ct_type_var == .generic_param { mut ctyp := c.get_comptime_var_type(call_arg.expr) @@ -1538,11 +1540,11 @@ fn (mut c Checker) get_comptime_args(func ast.Fn, node_ ast.CallExpr, concrete_t if param_typ.has_flag(.variadic) { ctyp = ast.mktyp(ctyp) - comptime_args[i] = ctyp + comptime_args[k] = ctyp } else if arg_sym.info is ast.Array && param_typ.has_flag(.generic) && param_typ_sym.kind == .array { ctyp = c.get_generic_array_element_type(arg_sym.info) - comptime_args[i] = ctyp + comptime_args[k] = ctyp } else if arg_sym.kind in [.struct_, .interface_, .sum_type] { mut generic_types := []ast.Type{} match arg_sym.info { @@ -1560,15 +1562,19 @@ fn (mut c Checker) get_comptime_args(func ast.Fn, node_ ast.CallExpr, concrete_t if gt_name in generic_names && generic_types.len == concrete_types.len { idx := generic_names.index(gt_name) - comptime_args[i] = concrete_types[idx] + comptime_args[k] = concrete_types[idx] break } } } else if arg_sym.kind == .any { cparam_type_sym := c.table.sym(c.unwrap_generic(ctyp)) if param_typ_sym.kind == .array && cparam_type_sym.info is ast.Array { - ctyp = cparam_type_sym.info.elem_type - comptime_args[i] = ctyp + comptime_args[k] = cparam_type_sym.info.elem_type + } else if param_typ_sym.kind == .map + && cparam_type_sym.info is ast.Map { + comptime_args[k] = cparam_type_sym.info.key_type + comptime_args[k + 1] = cparam_type_sym.info.value_type + k++ } else { if node_.args[i].expr.is_auto_deref_var() { ctyp = ctyp.deref() @@ -1576,20 +1582,20 @@ fn (mut c Checker) get_comptime_args(func ast.Fn, node_ ast.CallExpr, concrete_t if ctyp.nr_muls() > 0 && param_typ.nr_muls() > 0 { ctyp = ctyp.set_nr_muls(0) } - comptime_args[i] = ctyp + comptime_args[k] = ctyp } } else { - comptime_args[i] = ctyp + comptime_args[k] = ctyp } } } } } else if call_arg.expr is ast.PrefixExpr { if call_arg.expr.right is ast.ComptimeSelector { - comptime_args[i] = c.get_comptime_var_type(call_arg.expr.right) - comptime_args[i] = comptime_args[i].deref() - if comptime_args[i].nr_muls() > 0 && param_typ.nr_muls() > 0 { - comptime_args[i] = comptime_args[i].set_nr_muls(0) + comptime_args[k] = c.get_comptime_var_type(call_arg.expr.right) + comptime_args[k] = comptime_args[k].deref() + if comptime_args[k].nr_muls() > 0 && param_typ.nr_muls() > 0 { + comptime_args[k] = comptime_args[k].set_nr_muls(0) } } } else if call_arg.expr is ast.ComptimeSelector { @@ -1598,13 +1604,13 @@ fn (mut c Checker) get_comptime_args(func ast.Fn, node_ ast.CallExpr, concrete_t if ct_value != ast.void_type { cparam_type_sym := c.table.sym(c.unwrap_generic(ct_value)) if param_typ_sym.kind == .array && cparam_type_sym.info is ast.Array { - comptime_args[i] = cparam_type_sym.info.elem_type + comptime_args[k] = cparam_type_sym.info.elem_type } else { - comptime_args[i] = ct_value + comptime_args[k] = ct_value } } } else if call_arg.expr is ast.ComptimeCall { - comptime_args[i] = c.get_comptime_var_type(call_arg.expr) + comptime_args[k] = c.get_comptime_var_type(call_arg.expr) } } } @@ -1628,7 +1634,7 @@ fn (mut c Checker) resolve_fn_generic_args(func ast.Fn, mut node ast.CallExpr) [ else {} } } - mut comptime_args := c.get_comptime_args(func, node, concrete_types) + mut comptime_args := c.resolve_comptime_args(func, node, concrete_types) if comptime_args.len > 0 { for k, v in comptime_args { if (rec_len + k) < concrete_types.len { diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index 4dbe661b24..558f566a1f 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -4631,7 +4631,7 @@ fn (mut g Gen) cast_expr(node ast.CastExpr) { && (sym.info as ast.Alias).parent_type !in [expr_type, ast.string_type]) { if sym.kind == .string && !node.typ.is_ptr() { cast_label = '*(string*)&' - } else { + } else if !(g.is_cc_msvc && g.typ(node.typ) == g.typ(expr_type)) { cast_label = '(${styp})' } } diff --git a/vlib/v/gen/c/fn.v b/vlib/v/gen/c/fn.v index d62411b9aa..a8847b07ce 100644 --- a/vlib/v/gen/c/fn.v +++ b/vlib/v/gen/c/fn.v @@ -1050,18 +1050,20 @@ fn (g Gen) get_generic_array_element_type(array ast.Array) ast.Type { return typ } -fn (mut g Gen) change_comptime_args(func ast.Fn, mut node_ ast.CallExpr, concrete_types []ast.Type) map[int]ast.Type { +fn (mut g Gen) resolve_comptime_args(func ast.Fn, mut node_ ast.CallExpr, concrete_types []ast.Type) map[int]ast.Type { mut comptime_args := map[int]ast.Type{} has_dynamic_vars := (g.cur_fn != unsafe { nil } && g.cur_fn.generic_names.len > 0) || g.inside_comptime_for_field if has_dynamic_vars { offset := if func.is_method { 1 } else { 0 } + mut k := -1 for i, mut call_arg in node_.args { param := if func.is_variadic && i >= func.params.len - (offset + 1) { func.params.last() } else { func.params[offset + i] } + k++ if !param.typ.has_flag(.generic) { continue } @@ -1089,7 +1091,7 @@ fn (mut g Gen) change_comptime_args(func ast.Fn, mut node_ ast.CallExpr, concret } } } - comptime_args[i] = ctyp + comptime_args[k] = ctyp } } else if call_arg.expr.obj.ct_type_var == .generic_param { mut ctyp := g.get_comptime_var_type(call_arg.expr) @@ -1098,11 +1100,11 @@ fn (mut g Gen) change_comptime_args(func ast.Fn, mut node_ ast.CallExpr, concret param_typ_sym := g.table.sym(param_typ) if param_typ.has_flag(.variadic) { ctyp = ast.mktyp(ctyp) - comptime_args[i] = ctyp + comptime_args[k] = ctyp } else if arg_sym.kind == .array && param_typ.has_flag(.generic) && param_typ_sym.kind == .array { ctyp = g.get_generic_array_element_type(arg_sym.info as ast.Array) - comptime_args[i] = ctyp + comptime_args[k] = ctyp } else if arg_sym.kind in [.struct_, .interface_, .sum_type] { mut generic_types := []ast.Type{} match arg_sym.info { @@ -1120,15 +1122,19 @@ fn (mut g Gen) change_comptime_args(func ast.Fn, mut node_ ast.CallExpr, concret if gt_name in generic_names && generic_types.len == concrete_types.len { idx := generic_names.index(gt_name) - comptime_args[i] = concrete_types[idx] + comptime_args[k] = concrete_types[idx] break } } } else if arg_sym.kind == .any { cparam_type_sym := g.table.sym(g.unwrap_generic(ctyp)) if param_typ_sym.kind == .array && cparam_type_sym.info is ast.Array { - ctyp = cparam_type_sym.info.elem_type - comptime_args[i] = ctyp + comptime_args[k] = cparam_type_sym.info.elem_type + } else if param_typ_sym.kind == .map + && cparam_type_sym.info is ast.Map { + comptime_args[k] = cparam_type_sym.info.key_type + comptime_args[k + 1] = cparam_type_sym.info.value_type + k++ } else { if node_.args[i].expr.is_auto_deref_var() { ctyp = ctyp.deref() @@ -1136,44 +1142,51 @@ fn (mut g Gen) change_comptime_args(func ast.Fn, mut node_ ast.CallExpr, concret if ctyp.nr_muls() > 0 && param_typ.nr_muls() > 0 { ctyp = ctyp.set_nr_muls(0) } - comptime_args[i] = ctyp + comptime_args[k] = ctyp } } else { - comptime_args[i] = ctyp + comptime_args[k] = ctyp } } } } } else if mut call_arg.expr is ast.PrefixExpr { if call_arg.expr.right is ast.ComptimeSelector { - comptime_args[i] = g.comptime_for_field_type - comptime_args[i] = comptime_args[i].deref() - if param_typ.nr_muls() > 0 && comptime_args[i].nr_muls() > 0 { - comptime_args[i] = comptime_args[i].set_nr_muls(0) + comptime_args[k] = g.comptime_for_field_type + comptime_args[k] = comptime_args[k].deref() + if param_typ.nr_muls() > 0 && comptime_args[k].nr_muls() > 0 { + comptime_args[k] = comptime_args[k].set_nr_muls(0) } } } else if mut call_arg.expr is ast.ComptimeSelector { - comptime_args[i] = g.comptime_for_field_type + comptime_args[k] = g.comptime_for_field_type arg_sym := g.table.final_sym(call_arg.typ) param_typ_sym := g.table.sym(param_typ) if arg_sym.kind == .array && param_typ.has_flag(.generic) && param_typ_sym.kind == .array { - comptime_args[i] = g.get_generic_array_element_type(arg_sym.info as ast.Array) + comptime_args[k] = g.get_generic_array_element_type(arg_sym.info as ast.Array) } if call_arg.expr.left.is_auto_deref_var() { - comptime_args[i] = comptime_args[i].deref() + comptime_args[k] = comptime_args[k].deref() } - if param_typ.nr_muls() > 0 && comptime_args[i].nr_muls() > 0 { - comptime_args[i] = comptime_args[i].set_nr_muls(0) + if param_typ.nr_muls() > 0 && comptime_args[k].nr_muls() > 0 { + comptime_args[k] = comptime_args[k].set_nr_muls(0) } } else if mut call_arg.expr is ast.ComptimeCall { if call_arg.expr.method_name == 'method' { sym := g.table.sym(g.unwrap_generic(call_arg.expr.left_type)) // `app.$method()` if m := sym.find_method(g.comptime_for_method) { - comptime_args[i] = m.return_type + comptime_args[k] = m.return_type } } + } else if mut call_arg.expr is ast.CastExpr { + cparam_type_sym := g.table.sym(g.unwrap_generic(call_arg.expr.typ)) + param_typ_sym := g.table.sym(param_typ) + if param_typ_sym.kind == .map && cparam_type_sym.info is ast.Map { + comptime_args[k] = cparam_type_sym.info.key_type + comptime_args[k + 1] = cparam_type_sym.info.value_type + } } } } @@ -1419,7 +1432,7 @@ fn (mut g Gen) method_call(node ast.CallExpr) { mut concrete_types := node.concrete_types.map(g.unwrap_generic(it)) if m := g.table.find_method(g.table.sym(node.left_type), node.name) { mut node_ := unsafe { node } - comptime_args := g.change_comptime_args(m, mut node_, concrete_types) + comptime_args := g.resolve_comptime_args(m, mut node_, concrete_types) for k, v in comptime_args { if (rec_len + k) < concrete_types.len { if !node.concrete_types[k].has_flag(.generic) { @@ -1711,7 +1724,7 @@ fn (mut g Gen) fn_call(node ast.CallExpr) { 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.change_comptime_args(func, mut node_, concrete_types) + comptime_args := g.resolve_comptime_args(func, mut node_, concrete_types) if concrete_types.len > 0 { for k, v in comptime_args { if k < concrete_types.len { diff --git a/vlib/v/tests/generic_comptime_map_test.v b/vlib/v/tests/generic_comptime_map_test.v new file mode 100644 index 0000000000..ada1ac59c0 --- /dev/null +++ b/vlib/v/tests/generic_comptime_map_test.v @@ -0,0 +1,27 @@ +module main + +fn generic[A](a A) { + expect_map_2_args(a, 1) + expect_map(A(a)) +} + +fn expect_map[K, V](a map[K]V) { + println(a) +} + +fn expect_map_2_args[K, V](a map[K]V, b int) { + assert b == 1 + println(b) +} + +fn test_main() { + a := { + 'a': 1 + } + b := { + 1: 'a' + } + generic(a) + generic(b) + assert true +}