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:
parent
6adafbb6ea
commit
80cd9f820a
@ -3503,6 +3503,11 @@ fn (c &Checker) has_return(stmts []ast.Stmt) ?bool {
|
|||||||
return none
|
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 {
|
fn (mut c Checker) postfix_expr(mut node ast.PostfixExpr) ast.Type {
|
||||||
typ := c.unwrap_generic(c.expr(node.expr))
|
typ := c.unwrap_generic(c.expr(node.expr))
|
||||||
typ_sym := c.table.sym(typ)
|
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)
|
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 !(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)
|
typ_str := c.table.type_to_str(typ)
|
||||||
c.error('invalid operation: ${node.op.str()} (non-numeric type `${typ_str}`)',
|
c.error('invalid operation: ${node.op.str()} (non-numeric type `${typ_str}`)',
|
||||||
node.pos)
|
node.pos)
|
||||||
|
@ -1326,7 +1326,7 @@ fn (mut c Checker) method_call(mut node ast.CallExpr) ast.Type {
|
|||||||
} else {
|
} else {
|
||||||
'unknown method or field: `${left_sym.name}.${method_name}`'
|
'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())
|
c.error('option type cannot be called directly', node.left.pos())
|
||||||
return ast.void_type
|
return ast.void_type
|
||||||
} else if left_type.has_flag(.result) {
|
} else if left_type.has_flag(.result) {
|
||||||
|
@ -864,40 +864,41 @@ fn (mut g Gen) gen_to_str_method_call(node ast.CallExpr) bool {
|
|||||||
if rec_type.has_flag(.shared_f) {
|
if rec_type.has_flag(.shared_f) {
|
||||||
rec_type = rec_type.clear_flag(.shared_f).set_nr_muls(0)
|
rec_type = rec_type.clear_flag(.shared_f).set_nr_muls(0)
|
||||||
}
|
}
|
||||||
if node.left is ast.ComptimeSelector {
|
left_node := if node.left is ast.PostfixExpr { node.left.expr } else { node.left }
|
||||||
key_str := g.get_comptime_selector_key_type(node.left)
|
if left_node is ast.ComptimeSelector {
|
||||||
|
key_str := g.get_comptime_selector_key_type(left_node)
|
||||||
if key_str != '' {
|
if key_str != '' {
|
||||||
rec_type = g.comptime_var_type_map[key_str] or { rec_type }
|
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
|
return true
|
||||||
}
|
}
|
||||||
} else if node.left is ast.ComptimeCall {
|
} else if left_node is ast.ComptimeCall {
|
||||||
if node.left.method_name == 'method' {
|
if left_node.method_name == 'method' {
|
||||||
sym := g.table.sym(g.unwrap_generic(node.left.left_type))
|
sym := g.table.sym(g.unwrap_generic(left_node.left_type))
|
||||||
if m := sym.find_method(g.comptime_for_method) {
|
if m := sym.find_method(g.comptime_for_method) {
|
||||||
rec_type = m.return_type
|
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
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if node.left is ast.Ident {
|
} else if left_node is ast.Ident {
|
||||||
if node.left.obj is ast.Var {
|
if left_node.obj is ast.Var {
|
||||||
if g.comptime_var_type_map.len > 0 {
|
if g.comptime_var_type_map.len > 0 {
|
||||||
rec_type = node.left.obj.typ
|
rec_type = left_node.obj.typ
|
||||||
g.gen_expr_to_string(node.left, rec_type)
|
g.gen_expr_to_string(left_node, rec_type)
|
||||||
return true
|
return true
|
||||||
} else if node.left.obj.smartcasts.len > 0 {
|
} else if left_node.obj.smartcasts.len > 0 {
|
||||||
rec_type = g.unwrap_generic(node.left.obj.smartcasts.last())
|
rec_type = g.unwrap_generic(left_node.obj.smartcasts.last())
|
||||||
cast_sym := g.table.sym(rec_type)
|
cast_sym := g.table.sym(rec_type)
|
||||||
if cast_sym.info is ast.Aggregate {
|
if cast_sym.info is ast.Aggregate {
|
||||||
rec_type = cast_sym.info.types[g.aggregate_type_idx]
|
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
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if node.left is ast.None {
|
} else if left_node is ast.None {
|
||||||
g.gen_expr_to_string(node.left, ast.none_type)
|
g.gen_expr_to_string(left_node, ast.none_type)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
g.get_str_fn(rec_type)
|
g.get_str_fn(rec_type)
|
||||||
|
38
vlib/v/tests/call_to_str_on_option_test.v
Normal file
38
vlib/v/tests/call_to_str_on_option_test.v
Normal 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
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user