mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
cgen,checker: fix method call with comptime var (#16844)
This commit is contained in:
parent
395ee2b464
commit
bd2b216ac7
@ -1578,9 +1578,17 @@ fn (mut c Checker) method_call(mut node ast.CallExpr) ast.Type {
|
||||
mut got_arg_typ := c.check_expr_opt_call(arg.expr, c.expr(arg.expr))
|
||||
node.args[i].typ = got_arg_typ
|
||||
if c.inside_comptime_for_field && method.params[param_idx].typ.has_flag(.generic) {
|
||||
c.table.register_fn_concrete_types(method.fkey(), [
|
||||
c.comptime_fields_default_type,
|
||||
])
|
||||
arg_sym := c.table.sym(c.comptime_fields_default_type)
|
||||
if arg_sym.kind == .array
|
||||
&& c.table.sym(method.params[param_idx].typ).kind == .array {
|
||||
c.table.register_fn_concrete_types(method.fkey(), [
|
||||
(arg_sym.info as ast.Array).elem_type,
|
||||
])
|
||||
} else {
|
||||
c.table.register_fn_concrete_types(method.fkey(), [
|
||||
c.comptime_fields_default_type,
|
||||
])
|
||||
}
|
||||
} else if c.inside_for_in_any_cond && method.params[param_idx].typ.has_flag(.generic) {
|
||||
c.table.register_fn_concrete_types(method.fkey(), [
|
||||
c.for_in_any_val_type,
|
||||
|
@ -769,6 +769,7 @@ fn (mut g Gen) method_call(node ast.CallExpr) {
|
||||
mut unwrapped_rec_type := node.receiver_type
|
||||
mut has_comptime_field := false
|
||||
mut for_in_any_var_type := ast.void_type
|
||||
mut comptime_args := []int{}
|
||||
if g.cur_fn != unsafe { nil } && g.cur_fn.generic_names.len > 0 { // in generic fn
|
||||
unwrapped_rec_type = g.unwrap_generic(node.receiver_type)
|
||||
} else { // in non-generic fn
|
||||
@ -795,10 +796,12 @@ fn (mut g Gen) method_call(node ast.CallExpr) {
|
||||
node_.args[i].typ = call_arg.expr.obj.typ
|
||||
if call_arg.expr.obj.is_comptime_field {
|
||||
has_comptime_field = true
|
||||
comptime_args << i
|
||||
}
|
||||
}
|
||||
} else if mut call_arg.expr is ast.ComptimeSelector {
|
||||
has_comptime_field = true
|
||||
comptime_args << i
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1130,7 +1133,20 @@ fn (mut g Gen) method_call(node ast.CallExpr) {
|
||||
}
|
||||
|
||||
if g.comptime_for_field_type != 0 && g.inside_comptime_for_field && has_comptime_field {
|
||||
name = g.generic_fn_name([g.comptime_for_field_type], name)
|
||||
mut concrete_types := node.concrete_types.map(g.unwrap_generic(it))
|
||||
arg_sym := g.table.sym(g.comptime_for_field_type)
|
||||
if m := g.table.find_method(g.table.sym(node.left_type), node.name) {
|
||||
for k in comptime_args {
|
||||
if m.generic_names.len > 0 && arg_sym.kind == .array
|
||||
&& m.params[k + 1].typ.has_flag(.generic)
|
||||
&& g.table.final_sym(m.params[k + 1].typ).kind == .array {
|
||||
concrete_types[k] = (arg_sym.info as ast.Array).elem_type
|
||||
} else {
|
||||
concrete_types[k] = g.comptime_for_field_type
|
||||
}
|
||||
}
|
||||
}
|
||||
name = g.generic_fn_name(concrete_types, name)
|
||||
} else if g.inside_for_in_any_cond && for_in_any_var_type != ast.void_type {
|
||||
name = g.generic_fn_name([for_in_any_var_type], name)
|
||||
} else {
|
||||
@ -1391,7 +1407,8 @@ fn (mut g Gen) fn_call(node ast.CallExpr) {
|
||||
mut concrete_types := node.concrete_types.map(g.unwrap_generic(it))
|
||||
arg_sym := g.table.sym(g.comptime_for_field_type)
|
||||
for k in comptime_args {
|
||||
if arg_sym.kind == .array {
|
||||
if arg_sym.kind == .array && func.params[k].typ.has_flag(.generic)
|
||||
&& g.table.sym(func.params[k].typ).kind == .array {
|
||||
concrete_types[k] = (arg_sym.info as ast.Array).elem_type
|
||||
} else {
|
||||
concrete_types[k] = g.comptime_for_field_type
|
||||
|
39
vlib/v/tests/method_call_var_comp_test.v
Normal file
39
vlib/v/tests/method_call_var_comp_test.v
Normal file
@ -0,0 +1,39 @@
|
||||
struct EmptyStruct {
|
||||
a int
|
||||
b []int
|
||||
}
|
||||
|
||||
struct Encoder {
|
||||
}
|
||||
|
||||
fn (e &Encoder) encode_array[T](val []T) []T {
|
||||
return val
|
||||
}
|
||||
|
||||
fn encode_struct[T](val T) []string {
|
||||
e := Encoder{}
|
||||
mut out := []string{}
|
||||
$if T is $Struct {
|
||||
$for field in T.fields {
|
||||
out << field.name
|
||||
out << field.is_array.str()
|
||||
|
||||
$if field.is_array {
|
||||
value := val.$(field.name)
|
||||
out << e.encode_array(value).str()
|
||||
out << e.encode_array([1, 2]).str()
|
||||
}
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
fn test_main() {
|
||||
out := encode_struct(EmptyStruct{3, [2, 1]})
|
||||
assert out[0] == 'a'
|
||||
assert out[1] == 'false'
|
||||
assert out[2] == 'b'
|
||||
assert out[3] == 'true'
|
||||
assert out[4] == '[2, 1]'
|
||||
assert out[5] == '[1, 2]'
|
||||
}
|
Loading…
Reference in New Issue
Block a user