1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

checker,cgen: allow ?.str() on compile-time fields var (#16969)

This commit is contained in:
Felipe Pena 2023-01-14 10:04:13 -03:00 committed by GitHub
parent 6adafbb6ea
commit 80cd9f820a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 69 additions and 17 deletions

View File

@ -3503,6 +3503,11 @@ fn (c &Checker) has_return(stmts []ast.Stmt) ?bool {
return none
}
pub fn (mut c Checker) is_comptime_var(node ast.Expr) bool {
return c.inside_comptime_for_field && node is ast.Ident
&& (node as ast.Ident).info is ast.IdentVar && ((node as ast.Ident).obj as ast.Var).is_comptime_field
}
fn (mut c Checker) postfix_expr(mut node ast.PostfixExpr) ast.Type {
typ := c.unwrap_generic(c.expr(node.expr))
typ_sym := c.table.sym(typ)
@ -3511,6 +3516,14 @@ fn (mut c Checker) postfix_expr(mut node ast.PostfixExpr) ast.Type {
c.warn('pointer arithmetic is only allowed in `unsafe` blocks', node.pos)
}
if !(typ_sym.is_number() || ((c.inside_unsafe || c.pref.translated) && is_non_void_pointer)) {
if c.inside_comptime_for_field {
if c.is_comptime_var(node.expr) {
return c.comptime_fields_default_type
} else if node.expr is ast.ComptimeSelector {
return c.comptime_fields_default_type
}
}
typ_str := c.table.type_to_str(typ)
c.error('invalid operation: ${node.op.str()} (non-numeric type `${typ_str}`)',
node.pos)

View File

@ -1326,7 +1326,7 @@ fn (mut c Checker) method_call(mut node ast.CallExpr) ast.Type {
} else {
'unknown method or field: `${left_sym.name}.${method_name}`'
}
if left_type.has_flag(.option) {
if left_type.has_flag(.option) && method_name != 'str' {
c.error('option type cannot be called directly', node.left.pos())
return ast.void_type
} else if left_type.has_flag(.result) {

View File

@ -864,40 +864,41 @@ fn (mut g Gen) gen_to_str_method_call(node ast.CallExpr) bool {
if rec_type.has_flag(.shared_f) {
rec_type = rec_type.clear_flag(.shared_f).set_nr_muls(0)
}
if node.left is ast.ComptimeSelector {
key_str := g.get_comptime_selector_key_type(node.left)
left_node := if node.left is ast.PostfixExpr { node.left.expr } else { node.left }
if left_node is ast.ComptimeSelector {
key_str := g.get_comptime_selector_key_type(left_node)
if key_str != '' {
rec_type = g.comptime_var_type_map[key_str] or { rec_type }
g.gen_expr_to_string(node.left, rec_type)
g.gen_expr_to_string(left_node, rec_type)
return true
}
} else if node.left is ast.ComptimeCall {
if node.left.method_name == 'method' {
sym := g.table.sym(g.unwrap_generic(node.left.left_type))
} else if left_node is ast.ComptimeCall {
if left_node.method_name == 'method' {
sym := g.table.sym(g.unwrap_generic(left_node.left_type))
if m := sym.find_method(g.comptime_for_method) {
rec_type = m.return_type
g.gen_expr_to_string(node.left, rec_type)
g.gen_expr_to_string(left_node, rec_type)
return true
}
}
} else if node.left is ast.Ident {
if node.left.obj is ast.Var {
} else if left_node is ast.Ident {
if left_node.obj is ast.Var {
if g.comptime_var_type_map.len > 0 {
rec_type = node.left.obj.typ
g.gen_expr_to_string(node.left, rec_type)
rec_type = left_node.obj.typ
g.gen_expr_to_string(left_node, rec_type)
return true
} else if node.left.obj.smartcasts.len > 0 {
rec_type = g.unwrap_generic(node.left.obj.smartcasts.last())
} else if left_node.obj.smartcasts.len > 0 {
rec_type = g.unwrap_generic(left_node.obj.smartcasts.last())
cast_sym := g.table.sym(rec_type)
if cast_sym.info is ast.Aggregate {
rec_type = cast_sym.info.types[g.aggregate_type_idx]
}
g.gen_expr_to_string(node.left, rec_type)
g.gen_expr_to_string(left_node, rec_type)
return true
}
}
} else if node.left is ast.None {
g.gen_expr_to_string(node.left, ast.none_type)
} else if left_node is ast.None {
g.gen_expr_to_string(left_node, ast.none_type)
return true
}
g.get_str_fn(rec_type)

View File

@ -0,0 +1,38 @@
struct FixedStruct1 {
a int
b string
c ?int
d ?string
}
struct Encoder {}
fn test_main() {
fixed := FixedStruct1{123, '456', 789, '321'}
// this work well
println(fixed.a.str())
println(fixed.c?.str())
println(fixed.b.int())
println(fixed.d?.int())
e := Encoder{}
// this not work
e.encode_struct(fixed)
}
fn (e &Encoder) encode_struct[T](val T) {
mut count := 0
$for field in T.fields {
mut value := val.$(field.name)
$if field.is_option {
if field.name in ['c', 'd'] {
assert true
}
println('>> ${value ?.str()}')
println(val.$(field.name) ?.str())
count += 1
}
}
assert count == 2
}