mirror of
https://github.com/vlang/v.git
synced 2025-09-12 17:07:11 -04:00
cgen, checker: fix comptime map type resolution on generic arg (#20097)
This commit is contained in:
parent
7b44bb973d
commit
c121f56ffa
@ -1502,18 +1502,20 @@ fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool) ast.
|
|||||||
return func.return_type
|
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{}
|
mut comptime_args := map[int]ast.Type{}
|
||||||
has_dynamic_vars := (c.table.cur_fn != unsafe { nil } && c.table.cur_fn.generic_names.len > 0)
|
has_dynamic_vars := (c.table.cur_fn != unsafe { nil } && c.table.cur_fn.generic_names.len > 0)
|
||||||
|| c.inside_comptime_for_field
|
|| c.inside_comptime_for_field
|
||||||
if has_dynamic_vars {
|
if has_dynamic_vars {
|
||||||
offset := if func.is_method { 1 } else { 0 }
|
offset := if func.is_method { 1 } else { 0 }
|
||||||
|
mut k := -1
|
||||||
for i, call_arg in node_.args {
|
for i, call_arg in node_.args {
|
||||||
param := if func.is_variadic && i >= func.params.len - (offset + 1) {
|
param := if func.is_variadic && i >= func.params.len - (offset + 1) {
|
||||||
func.params.last()
|
func.params.last()
|
||||||
} else {
|
} else {
|
||||||
func.params[offset + i]
|
func.params[offset + i]
|
||||||
}
|
}
|
||||||
|
k++
|
||||||
if !param.typ.has_flag(.generic) {
|
if !param.typ.has_flag(.generic) {
|
||||||
continue
|
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 {
|
&& c.table.final_sym(param_typ).kind == .array {
|
||||||
ctyp = arg_sym.info.elem_type
|
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 {
|
} else if call_arg.expr.obj.ct_type_var == .generic_param {
|
||||||
mut ctyp := c.get_comptime_var_type(call_arg.expr)
|
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) {
|
if param_typ.has_flag(.variadic) {
|
||||||
ctyp = ast.mktyp(ctyp)
|
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)
|
} else if arg_sym.info is ast.Array && param_typ.has_flag(.generic)
|
||||||
&& param_typ_sym.kind == .array {
|
&& param_typ_sym.kind == .array {
|
||||||
ctyp = c.get_generic_array_element_type(arg_sym.info)
|
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] {
|
} else if arg_sym.kind in [.struct_, .interface_, .sum_type] {
|
||||||
mut generic_types := []ast.Type{}
|
mut generic_types := []ast.Type{}
|
||||||
match arg_sym.info {
|
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
|
if gt_name in generic_names
|
||||||
&& generic_types.len == concrete_types.len {
|
&& generic_types.len == concrete_types.len {
|
||||||
idx := generic_names.index(gt_name)
|
idx := generic_names.index(gt_name)
|
||||||
comptime_args[i] = concrete_types[idx]
|
comptime_args[k] = concrete_types[idx]
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if arg_sym.kind == .any {
|
} else if arg_sym.kind == .any {
|
||||||
cparam_type_sym := c.table.sym(c.unwrap_generic(ctyp))
|
cparam_type_sym := c.table.sym(c.unwrap_generic(ctyp))
|
||||||
if param_typ_sym.kind == .array && cparam_type_sym.info is ast.Array {
|
if param_typ_sym.kind == .array && cparam_type_sym.info is ast.Array {
|
||||||
ctyp = cparam_type_sym.info.elem_type
|
comptime_args[k] = cparam_type_sym.info.elem_type
|
||||||
comptime_args[i] = ctyp
|
} 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 {
|
} else {
|
||||||
if node_.args[i].expr.is_auto_deref_var() {
|
if node_.args[i].expr.is_auto_deref_var() {
|
||||||
ctyp = ctyp.deref()
|
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 {
|
if ctyp.nr_muls() > 0 && param_typ.nr_muls() > 0 {
|
||||||
ctyp = ctyp.set_nr_muls(0)
|
ctyp = ctyp.set_nr_muls(0)
|
||||||
}
|
}
|
||||||
comptime_args[i] = ctyp
|
comptime_args[k] = ctyp
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
comptime_args[i] = ctyp
|
comptime_args[k] = ctyp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if call_arg.expr is ast.PrefixExpr {
|
} else if call_arg.expr is ast.PrefixExpr {
|
||||||
if call_arg.expr.right is ast.ComptimeSelector {
|
if call_arg.expr.right is ast.ComptimeSelector {
|
||||||
comptime_args[i] = c.get_comptime_var_type(call_arg.expr.right)
|
comptime_args[k] = c.get_comptime_var_type(call_arg.expr.right)
|
||||||
comptime_args[i] = comptime_args[i].deref()
|
comptime_args[k] = comptime_args[k].deref()
|
||||||
if comptime_args[i].nr_muls() > 0 && param_typ.nr_muls() > 0 {
|
if comptime_args[k].nr_muls() > 0 && param_typ.nr_muls() > 0 {
|
||||||
comptime_args[i] = comptime_args[i].set_nr_muls(0)
|
comptime_args[k] = comptime_args[k].set_nr_muls(0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if call_arg.expr is ast.ComptimeSelector {
|
} 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 {
|
if ct_value != ast.void_type {
|
||||||
cparam_type_sym := c.table.sym(c.unwrap_generic(ct_value))
|
cparam_type_sym := c.table.sym(c.unwrap_generic(ct_value))
|
||||||
if param_typ_sym.kind == .array && cparam_type_sym.info is ast.Array {
|
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 {
|
} else {
|
||||||
comptime_args[i] = ct_value
|
comptime_args[k] = ct_value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if call_arg.expr is ast.ComptimeCall {
|
} 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 {}
|
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 {
|
if comptime_args.len > 0 {
|
||||||
for k, v in comptime_args {
|
for k, v in comptime_args {
|
||||||
if (rec_len + k) < concrete_types.len {
|
if (rec_len + k) < concrete_types.len {
|
||||||
|
@ -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]) {
|
&& (sym.info as ast.Alias).parent_type !in [expr_type, ast.string_type]) {
|
||||||
if sym.kind == .string && !node.typ.is_ptr() {
|
if sym.kind == .string && !node.typ.is_ptr() {
|
||||||
cast_label = '*(string*)&'
|
cast_label = '*(string*)&'
|
||||||
} else {
|
} else if !(g.is_cc_msvc && g.typ(node.typ) == g.typ(expr_type)) {
|
||||||
cast_label = '(${styp})'
|
cast_label = '(${styp})'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1050,18 +1050,20 @@ fn (g Gen) get_generic_array_element_type(array ast.Array) ast.Type {
|
|||||||
return typ
|
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{}
|
mut comptime_args := map[int]ast.Type{}
|
||||||
has_dynamic_vars := (g.cur_fn != unsafe { nil } && g.cur_fn.generic_names.len > 0)
|
has_dynamic_vars := (g.cur_fn != unsafe { nil } && g.cur_fn.generic_names.len > 0)
|
||||||
|| g.inside_comptime_for_field
|
|| g.inside_comptime_for_field
|
||||||
if has_dynamic_vars {
|
if has_dynamic_vars {
|
||||||
offset := if func.is_method { 1 } else { 0 }
|
offset := if func.is_method { 1 } else { 0 }
|
||||||
|
mut k := -1
|
||||||
for i, mut call_arg in node_.args {
|
for i, mut call_arg in node_.args {
|
||||||
param := if func.is_variadic && i >= func.params.len - (offset + 1) {
|
param := if func.is_variadic && i >= func.params.len - (offset + 1) {
|
||||||
func.params.last()
|
func.params.last()
|
||||||
} else {
|
} else {
|
||||||
func.params[offset + i]
|
func.params[offset + i]
|
||||||
}
|
}
|
||||||
|
k++
|
||||||
if !param.typ.has_flag(.generic) {
|
if !param.typ.has_flag(.generic) {
|
||||||
continue
|
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 {
|
} else if call_arg.expr.obj.ct_type_var == .generic_param {
|
||||||
mut ctyp := g.get_comptime_var_type(call_arg.expr)
|
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)
|
param_typ_sym := g.table.sym(param_typ)
|
||||||
if param_typ.has_flag(.variadic) {
|
if param_typ.has_flag(.variadic) {
|
||||||
ctyp = ast.mktyp(ctyp)
|
ctyp = ast.mktyp(ctyp)
|
||||||
comptime_args[i] = ctyp
|
comptime_args[k] = ctyp
|
||||||
} else if arg_sym.kind == .array && param_typ.has_flag(.generic)
|
} else if arg_sym.kind == .array && param_typ.has_flag(.generic)
|
||||||
&& param_typ_sym.kind == .array {
|
&& param_typ_sym.kind == .array {
|
||||||
ctyp = g.get_generic_array_element_type(arg_sym.info as ast.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] {
|
} else if arg_sym.kind in [.struct_, .interface_, .sum_type] {
|
||||||
mut generic_types := []ast.Type{}
|
mut generic_types := []ast.Type{}
|
||||||
match arg_sym.info {
|
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
|
if gt_name in generic_names
|
||||||
&& generic_types.len == concrete_types.len {
|
&& generic_types.len == concrete_types.len {
|
||||||
idx := generic_names.index(gt_name)
|
idx := generic_names.index(gt_name)
|
||||||
comptime_args[i] = concrete_types[idx]
|
comptime_args[k] = concrete_types[idx]
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if arg_sym.kind == .any {
|
} else if arg_sym.kind == .any {
|
||||||
cparam_type_sym := g.table.sym(g.unwrap_generic(ctyp))
|
cparam_type_sym := g.table.sym(g.unwrap_generic(ctyp))
|
||||||
if param_typ_sym.kind == .array && cparam_type_sym.info is ast.Array {
|
if param_typ_sym.kind == .array && cparam_type_sym.info is ast.Array {
|
||||||
ctyp = cparam_type_sym.info.elem_type
|
comptime_args[k] = cparam_type_sym.info.elem_type
|
||||||
comptime_args[i] = ctyp
|
} 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 {
|
} else {
|
||||||
if node_.args[i].expr.is_auto_deref_var() {
|
if node_.args[i].expr.is_auto_deref_var() {
|
||||||
ctyp = ctyp.deref()
|
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 {
|
if ctyp.nr_muls() > 0 && param_typ.nr_muls() > 0 {
|
||||||
ctyp = ctyp.set_nr_muls(0)
|
ctyp = ctyp.set_nr_muls(0)
|
||||||
}
|
}
|
||||||
comptime_args[i] = ctyp
|
comptime_args[k] = ctyp
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
comptime_args[i] = ctyp
|
comptime_args[k] = ctyp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if mut call_arg.expr is ast.PrefixExpr {
|
} else if mut call_arg.expr is ast.PrefixExpr {
|
||||||
if call_arg.expr.right is ast.ComptimeSelector {
|
if call_arg.expr.right is ast.ComptimeSelector {
|
||||||
comptime_args[i] = g.comptime_for_field_type
|
comptime_args[k] = g.comptime_for_field_type
|
||||||
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 {
|
if param_typ.nr_muls() > 0 && comptime_args[k].nr_muls() > 0 {
|
||||||
comptime_args[i] = comptime_args[i].set_nr_muls(0)
|
comptime_args[k] = comptime_args[k].set_nr_muls(0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if mut call_arg.expr is ast.ComptimeSelector {
|
} 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)
|
arg_sym := g.table.final_sym(call_arg.typ)
|
||||||
param_typ_sym := g.table.sym(param_typ)
|
param_typ_sym := g.table.sym(param_typ)
|
||||||
if arg_sym.kind == .array && param_typ.has_flag(.generic)
|
if arg_sym.kind == .array && param_typ.has_flag(.generic)
|
||||||
&& param_typ_sym.kind == .array {
|
&& 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() {
|
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 {
|
if param_typ.nr_muls() > 0 && comptime_args[k].nr_muls() > 0 {
|
||||||
comptime_args[i] = comptime_args[i].set_nr_muls(0)
|
comptime_args[k] = comptime_args[k].set_nr_muls(0)
|
||||||
}
|
}
|
||||||
} else if mut call_arg.expr is ast.ComptimeCall {
|
} else if mut call_arg.expr is ast.ComptimeCall {
|
||||||
if call_arg.expr.method_name == 'method' {
|
if call_arg.expr.method_name == 'method' {
|
||||||
sym := g.table.sym(g.unwrap_generic(call_arg.expr.left_type))
|
sym := g.table.sym(g.unwrap_generic(call_arg.expr.left_type))
|
||||||
// `app.$method()`
|
// `app.$method()`
|
||||||
if m := sym.find_method(g.comptime_for_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))
|
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) {
|
if m := g.table.find_method(g.table.sym(node.left_type), node.name) {
|
||||||
mut node_ := unsafe { node }
|
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 {
|
for k, v in comptime_args {
|
||||||
if (rec_len + k) < concrete_types.len {
|
if (rec_len + k) < concrete_types.len {
|
||||||
if !node.concrete_types[k].has_flag(.generic) {
|
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) {
|
if func := g.table.find_fn(node.name) {
|
||||||
mut concrete_types := node.concrete_types.map(g.unwrap_generic(it))
|
mut concrete_types := node.concrete_types.map(g.unwrap_generic(it))
|
||||||
mut node_ := unsafe { node }
|
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 {
|
if concrete_types.len > 0 {
|
||||||
for k, v in comptime_args {
|
for k, v in comptime_args {
|
||||||
if k < concrete_types.len {
|
if k < concrete_types.len {
|
||||||
|
27
vlib/v/tests/generic_comptime_map_test.v
Normal file
27
vlib/v/tests/generic_comptime_map_test.v
Normal file
@ -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
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user