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
|
||||
}
|
||||
|
||||
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)
|
||||
|
@ -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) {
|
||||
|
@ -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)
|
||||
|
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…
Reference in New Issue
Block a user