parent
9d0a5942ac
commit
7178367de0
|
@ -534,6 +534,7 @@ pub mut:
|
|||
should_be_skipped bool // true for calls to `[if someflag?]` functions, when there is no `-d someflag`
|
||||
concrete_types []Type // concrete types, e.g. <int, string>
|
||||
concrete_list_pos token.Pos
|
||||
raw_concrete_types []Type
|
||||
free_receiver bool // true if the receiver expression needs to be freed
|
||||
scope &Scope
|
||||
from_embed_types []Type // holds the type of the embed that the method is called from
|
||||
|
|
|
@ -135,6 +135,8 @@ pub fn (mut c Checker) assign_stmt(mut node ast.AssignStmt) {
|
|||
}
|
||||
}
|
||||
}
|
||||
} else if right is ast.ComptimeSelector {
|
||||
right_type = c.comptime_fields_default_type
|
||||
}
|
||||
if is_decl {
|
||||
// check generic struct init and return unwrap generic struct type
|
||||
|
|
|
@ -82,6 +82,7 @@ pub mut:
|
|||
inside_defer bool // true inside `defer {}` blocks
|
||||
inside_fn_arg bool // `a`, `b` in `a.f(b)`
|
||||
inside_ct_attr bool // true inside `[if expr]`
|
||||
inside_comptime_for_field bool
|
||||
skip_flags bool // should `#flag` and `#include` be skipped
|
||||
fn_level int // 0 for the top level, 1 for `fn abc() {}`, 2 for a nested fn, etc
|
||||
ct_cond_stack []ast.Expr
|
||||
|
|
|
@ -109,11 +109,20 @@ fn (mut c Checker) comptime_for(node ast.ComptimeFor) {
|
|||
c.error('unknown type `$sym.name`', node.typ_pos)
|
||||
}
|
||||
if node.kind == .fields {
|
||||
if sym.kind == .struct_ {
|
||||
sym_info := sym.info as ast.Struct
|
||||
c.inside_comptime_for_field = true
|
||||
for field in sym_info.fields {
|
||||
c.comptime_fields_type[node.val_var] = node.typ
|
||||
c.comptime_fields_default_type = node.typ
|
||||
}
|
||||
c.comptime_fields_default_type = field.typ
|
||||
c.stmts(node.stmts)
|
||||
}
|
||||
c.inside_comptime_for_field = false
|
||||
}
|
||||
} else {
|
||||
c.stmts(node.stmts)
|
||||
}
|
||||
}
|
||||
|
||||
// comptime const eval
|
||||
fn (mut c Checker) eval_comptime_const_expr(expr ast.Expr, nlevel int) ?ast.ComptTimeConstValue {
|
||||
|
|
|
@ -428,6 +428,7 @@ pub fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool)
|
|||
}
|
||||
mut has_generic := false // foo<T>() instead of foo<int>()
|
||||
mut concrete_types := []ast.Type{}
|
||||
node.concrete_types = node.raw_concrete_types
|
||||
for concrete_type in node.concrete_types {
|
||||
if concrete_type.has_flag(.generic) {
|
||||
has_generic = true
|
||||
|
@ -777,6 +778,13 @@ pub fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool)
|
|||
|
||||
typ := c.check_expr_opt_call(call_arg.expr, c.expr(call_arg.expr))
|
||||
node.args[i].typ = typ
|
||||
if c.inside_comptime_for_field {
|
||||
if mut call_arg.expr is ast.Ident {
|
||||
if mut call_arg.expr.obj is ast.Var {
|
||||
node.args[i].typ = call_arg.expr.obj.typ
|
||||
}
|
||||
}
|
||||
}
|
||||
typ_sym := c.table.sym(typ)
|
||||
param_typ_sym := c.table.sym(param.typ)
|
||||
if func.is_variadic && typ.has_flag(.variadic) && node.args.len - 1 > i {
|
||||
|
@ -936,6 +944,9 @@ pub fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool)
|
|||
continue
|
||||
}
|
||||
c.check_expected_call_arg(utyp, unwrap_typ, node.language, call_arg) or {
|
||||
if c.comptime_fields_type.len > 0 {
|
||||
continue
|
||||
}
|
||||
c.error('$err.msg() in argument ${i + 1} to `$fn_name`', call_arg.pos)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,20 +18,6 @@ vlib/v/checker/tests/comptime_for.vv:4:12: error: unknown type `T`
|
|||
| ^
|
||||
5 | $if f.typ is Huh {}
|
||||
6 | $if f.typ is T {}
|
||||
vlib/v/checker/tests/comptime_for.vv:5:16: error: unknown type `Huh`
|
||||
3 | $for f in Huh.fields {}
|
||||
4 | $for f in T.fields {
|
||||
5 | $if f.typ is Huh {}
|
||||
| ~~~
|
||||
6 | $if f.typ is T {}
|
||||
7 | }
|
||||
vlib/v/checker/tests/comptime_for.vv:6:16: error: unknown type `T`
|
||||
4 | $for f in T.fields {
|
||||
5 | $if f.typ is Huh {}
|
||||
6 | $if f.typ is T {}
|
||||
| ^
|
||||
7 | }
|
||||
8 | _ = m
|
||||
vlib/v/checker/tests/comptime_for.vv:8:6: error: undefined ident: `m`
|
||||
6 | $if f.typ is T {}
|
||||
7 | }
|
||||
|
|
|
@ -20,4 +20,6 @@ struct S1 {
|
|||
i int
|
||||
}
|
||||
|
||||
fn main() {
|
||||
gf<S1>()
|
||||
}
|
||||
|
|
|
@ -117,6 +117,7 @@ mut:
|
|||
inside_or_block bool
|
||||
inside_call bool
|
||||
inside_for_c_stmt bool
|
||||
inside_comptime_for_field bool
|
||||
inside_cast_in_heap int // inside cast to interface type in heap (resolve recursive calls)
|
||||
inside_const bool
|
||||
inside_lambda bool
|
||||
|
|
|
@ -503,13 +503,16 @@ fn (mut g Gen) comptime_for(node ast.ComptimeFor) {
|
|||
}
|
||||
} else if node.kind == .fields {
|
||||
// TODO add fields
|
||||
if sym.info is ast.Struct {
|
||||
if sym.info.fields.len > 0 {
|
||||
if sym.kind == .struct_ {
|
||||
sym_info := sym.info as ast.Struct
|
||||
if sym_info.fields.len > 0 {
|
||||
g.writeln('\tFieldData $node.val_var = {0};')
|
||||
}
|
||||
for field in sym.info.fields {
|
||||
g.inside_comptime_for_field = true
|
||||
for field in sym_info.fields {
|
||||
g.comptime_for_field_var = node.val_var
|
||||
g.comptime_for_field_value = field
|
||||
g.comptime_for_field_type = field.typ
|
||||
g.writeln('/* field $i */ {')
|
||||
g.writeln('\t${node.val_var}.name = _SLIT("$field.name");')
|
||||
if field.attrs.len == 0 {
|
||||
|
@ -531,7 +534,9 @@ fn (mut g Gen) comptime_for(node ast.ComptimeFor) {
|
|||
g.stmts(node.stmts)
|
||||
i++
|
||||
g.writeln('}')
|
||||
g.comptime_for_field_type = 0
|
||||
}
|
||||
g.inside_comptime_for_field = false
|
||||
g.comptime_var_type_map.delete(node.val_var)
|
||||
}
|
||||
} else if node.kind == .attributes {
|
||||
|
|
|
@ -1120,6 +1120,16 @@ fn (mut g Gen) fn_call(node ast.CallExpr) {
|
|||
}
|
||||
is_selector_call = true
|
||||
}
|
||||
if g.inside_comptime_for_field {
|
||||
mut node_ := unsafe { node }
|
||||
for i, mut call_arg in node_.args {
|
||||
if mut call_arg.expr is ast.Ident {
|
||||
if mut call_arg.expr.obj is ast.Var {
|
||||
node_.args[i].typ = call_arg.expr.obj.typ
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
mut name := node.name
|
||||
is_print := name in ['print', 'println', 'eprint', 'eprintln', 'panic']
|
||||
print_method := name
|
||||
|
@ -1201,14 +1211,22 @@ fn (mut g Gen) fn_call(node ast.CallExpr) {
|
|||
}
|
||||
}
|
||||
if !is_selector_call {
|
||||
if func := g.table.find_fn(node.name) {
|
||||
if func.generic_names.len > 0 {
|
||||
if g.comptime_for_field_type != 0 && g.inside_comptime_for_field {
|
||||
name = g.generic_fn_name([g.comptime_for_field_type], name, false)
|
||||
} else {
|
||||
name = g.generic_fn_name(node.concrete_types, name, false)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// TODO2
|
||||
// cgen shouldn't modify ast nodes, this should be moved
|
||||
// g.generate_tmp_autofree_arg_vars(node, name)
|
||||
// Handle `print(x)`
|
||||
mut print_auto_str := false
|
||||
if is_print && (node.args[0].typ != ast.string_type || g.comptime_for_method.len > 0) { // && !free_tmp_arg_vars {
|
||||
if is_print && (node.args[0].typ != ast.string_type || g.comptime_for_method.len > 0) {
|
||||
mut typ := node.args[0].typ
|
||||
if typ == 0 {
|
||||
g.checker_bug('print arg.typ is 0', node.pos)
|
||||
|
|
|
@ -197,6 +197,16 @@ fn (mut g Gen) str_val(node ast.StringInterLiteral, i int) {
|
|||
|
||||
fn (mut g Gen) string_inter_literal(node ast.StringInterLiteral) {
|
||||
// fn (mut g Gen) str_int2(node ast.StringInterLiteral) {
|
||||
if g.inside_comptime_for_field {
|
||||
mut node_ := unsafe { node }
|
||||
for i, expr in node_.exprs {
|
||||
if mut expr is ast.Ident {
|
||||
if mut expr.obj is ast.Var {
|
||||
node_.expr_types[i] = expr.obj.typ
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
g.write(' str_intp($node.vals.len, ')
|
||||
g.write('_MOV((StrIntpData[]){')
|
||||
for i, val in node.vals {
|
||||
|
|
|
@ -92,6 +92,7 @@ pub fn (mut p Parser) call_expr(language ast.Language, mod string) ast.CallExpr
|
|||
language: language
|
||||
concrete_types: concrete_types
|
||||
concrete_list_pos: concrete_list_pos
|
||||
raw_concrete_types: concrete_types
|
||||
or_block: ast.OrExpr{
|
||||
stmts: or_stmts
|
||||
kind: or_kind
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
module main
|
||||
|
||||
// exploring `decode` options with nested structs
|
||||
|
||||
struct Parent {
|
||||
name string
|
||||
age int
|
||||
child Child
|
||||
}
|
||||
|
||||
struct Child {
|
||||
name string
|
||||
age int
|
||||
}
|
||||
|
||||
fn inspect<T>(t T) string {
|
||||
mut output_str := ''
|
||||
println('$T.name')
|
||||
$for field in T.fields {
|
||||
val := t.$(field.name)
|
||||
$if field.typ is string {
|
||||
println(' $field.name = $val')
|
||||
output_str += ' $field.name = $val\n'
|
||||
} $else $if field.typ is int {
|
||||
println(' $field.name = $val')
|
||||
output_str += ' $field.name = $val\n'
|
||||
} $else {
|
||||
str := inspect(val)
|
||||
output_str += str
|
||||
}
|
||||
}
|
||||
return output_str
|
||||
}
|
||||
|
||||
fn test_comptime_for_in_field_with_generic_fn() {
|
||||
p := Parent{
|
||||
name: 'parent'
|
||||
age: 30
|
||||
child: Child{
|
||||
name: 'child'
|
||||
age: 5
|
||||
}
|
||||
}
|
||||
ret := inspect(p)
|
||||
assert ret.contains('name = parent')
|
||||
assert ret.contains('age = 30')
|
||||
assert ret.contains('name = child')
|
||||
assert ret.contains('age = 5')
|
||||
}
|
|
@ -39,7 +39,7 @@ fn decode2<T>() T {
|
|||
x.$(field.name) = byte(-1)
|
||||
} $else $if field.typ is int {
|
||||
x.$(field.name) = int(-1)
|
||||
} $else {
|
||||
} $else $if field.typ is string {
|
||||
x.$(field.name) = 'hi'
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue