mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
cgen, checker: fix comptimeselector resolution + if comptime branching improvement + comptimeselector cleanup (#17302)
This commit is contained in:
parent
5a8c433548
commit
039c9b2550
@ -385,7 +385,7 @@ pub fn (x Expr) str() string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
ComptimeSelector {
|
ComptimeSelector {
|
||||||
return '${x.left}.$${x.field_expr}'
|
return '${x.left}.$(${x.field_expr})'
|
||||||
}
|
}
|
||||||
ConcatExpr {
|
ConcatExpr {
|
||||||
return x.vals.map(it.str()).join(',')
|
return x.vals.map(it.str()).join(',')
|
||||||
|
@ -296,6 +296,7 @@ fn (mut c Checker) assign_stmt(mut node ast.AssignStmt) {
|
|||||||
}
|
}
|
||||||
if right is ast.ComptimeSelector {
|
if right is ast.ComptimeSelector {
|
||||||
left.obj.is_comptime_field = true
|
left.obj.is_comptime_field = true
|
||||||
|
left.obj.typ = c.comptime_fields_default_type
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ast.GlobalField {
|
ast.GlobalField {
|
||||||
|
@ -873,19 +873,12 @@ fn (mut c Checker) infer_fn_generic_types(func ast.Fn, mut node ast.CallExpr) {
|
|||||||
typ = ast.new_type(idx).derive(arg.typ)
|
typ = ast.new_type(idx).derive(arg.typ)
|
||||||
} else if c.inside_comptime_for_field && sym.kind in [.struct_, .any]
|
} else if c.inside_comptime_for_field && sym.kind in [.struct_, .any]
|
||||||
&& arg.expr is ast.ComptimeSelector {
|
&& arg.expr is ast.ComptimeSelector {
|
||||||
compselector := arg.expr as ast.ComptimeSelector
|
comptime_typ := c.get_comptime_selector_type(arg.expr, ast.void_type)
|
||||||
if compselector.field_expr is ast.SelectorExpr {
|
if comptime_typ != ast.void_type {
|
||||||
selectorexpr := compselector.field_expr as ast.SelectorExpr
|
typ = comptime_typ
|
||||||
if selectorexpr.expr is ast.Ident {
|
if func.return_type.has_flag(.generic)
|
||||||
ident := selectorexpr.expr as ast.Ident
|
&& gt_name == c.table.type_to_str(func.return_type) {
|
||||||
if ident.name == c.comptime_for_field_var {
|
node.comptime_ret_val = true
|
||||||
typ = c.comptime_fields_default_type
|
|
||||||
|
|
||||||
if func.return_type.has_flag(.generic)
|
|
||||||
&& gt_name == c.table.type_to_str(func.return_type) {
|
|
||||||
node.comptime_ret_val = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2688,15 +2688,6 @@ pub fn (mut c Checker) expr(node_ ast.Expr) ast.Type {
|
|||||||
// return ast.void_type
|
// return ast.void_type
|
||||||
// }
|
// }
|
||||||
|
|
||||||
fn (mut c Checker) get_comptime_selector_type(node ast.ComptimeSelector, default_type ast.Type) ast.Type {
|
|
||||||
if node.field_expr is ast.SelectorExpr
|
|
||||||
&& c.check_comptime_is_field_selector(node.field_expr as ast.SelectorExpr)
|
|
||||||
&& (node.field_expr as ast.SelectorExpr).field_name == 'name' {
|
|
||||||
return c.comptime_fields_default_type
|
|
||||||
}
|
|
||||||
return default_type
|
|
||||||
}
|
|
||||||
|
|
||||||
fn (mut c Checker) cast_expr(mut node ast.CastExpr) ast.Type {
|
fn (mut c Checker) cast_expr(mut node ast.CastExpr) ast.Type {
|
||||||
// Given: `Outside( Inside(xyz) )`,
|
// Given: `Outside( Inside(xyz) )`,
|
||||||
// node.expr_type: `Inside`
|
// node.expr_type: `Inside`
|
||||||
|
@ -146,7 +146,7 @@ fn (mut c Checker) comptime_call(mut node ast.ComptimeCall) ast.Type {
|
|||||||
|
|
||||||
fn (mut c Checker) comptime_selector(mut node ast.ComptimeSelector) ast.Type {
|
fn (mut c Checker) comptime_selector(mut node ast.ComptimeSelector) ast.Type {
|
||||||
node.left_type = c.expr(node.left)
|
node.left_type = c.expr(node.left)
|
||||||
expr_type := c.unwrap_generic(c.expr(node.field_expr))
|
mut expr_type := c.unwrap_generic(c.expr(node.field_expr))
|
||||||
expr_sym := c.table.sym(expr_type)
|
expr_sym := c.table.sym(expr_type)
|
||||||
if expr_type != ast.string_type {
|
if expr_type != ast.string_type {
|
||||||
c.error('expected `string` instead of `${expr_sym.name}` (e.g. `field.name`)',
|
c.error('expected `string` instead of `${expr_sym.name}` (e.g. `field.name`)',
|
||||||
@ -158,6 +158,10 @@ fn (mut c Checker) comptime_selector(mut node ast.ComptimeSelector) ast.Type {
|
|||||||
c.error('compile time field access can only be used when iterating over `T.fields`',
|
c.error('compile time field access can only be used when iterating over `T.fields`',
|
||||||
left_pos)
|
left_pos)
|
||||||
}
|
}
|
||||||
|
expr_type = c.get_comptime_selector_type(node, ast.void_type)
|
||||||
|
if expr_type != ast.void_type {
|
||||||
|
return expr_type
|
||||||
|
}
|
||||||
expr_name := node.field_expr.expr.str()
|
expr_name := node.field_expr.expr.str()
|
||||||
if expr_name in c.comptime_fields_type {
|
if expr_name in c.comptime_fields_type {
|
||||||
return c.comptime_fields_type[expr_name]
|
return c.comptime_fields_type[expr_name]
|
||||||
@ -755,6 +759,18 @@ fn (mut c Checker) comptime_if_branch(cond ast.Expr, pos token.Pos) ComptimeBran
|
|||||||
return .unknown
|
return .unknown
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// get_comptime_selector_type retrieves the var.$(field.name) type when field_name is 'name' otherwise default_type is returned
|
||||||
|
[inline]
|
||||||
|
fn (mut c Checker) get_comptime_selector_type(node ast.ComptimeSelector, default_type ast.Type) ast.Type {
|
||||||
|
if node.field_expr is ast.SelectorExpr
|
||||||
|
&& c.check_comptime_is_field_selector(node.field_expr as ast.SelectorExpr)
|
||||||
|
&& (node.field_expr as ast.SelectorExpr).field_name == 'name' {
|
||||||
|
return c.unwrap_generic(c.comptime_fields_default_type)
|
||||||
|
}
|
||||||
|
return default_type
|
||||||
|
}
|
||||||
|
|
||||||
|
// check_comptime_is_field_selector checks if the SelectorExpr is related to $for variable
|
||||||
[inline]
|
[inline]
|
||||||
fn (mut c Checker) check_comptime_is_field_selector(node ast.SelectorExpr) bool {
|
fn (mut c Checker) check_comptime_is_field_selector(node ast.SelectorExpr) bool {
|
||||||
if c.inside_comptime_for_field && node.expr is ast.Ident {
|
if c.inside_comptime_for_field && node.expr is ast.Ident {
|
||||||
@ -763,6 +779,7 @@ fn (mut c Checker) check_comptime_is_field_selector(node ast.SelectorExpr) bool
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check_comptime_is_field_selector_bool checks if the SelectorExpr is related to field.is_* boolean fields
|
||||||
[inline]
|
[inline]
|
||||||
fn (mut c Checker) check_comptime_is_field_selector_bool(node ast.SelectorExpr) bool {
|
fn (mut c Checker) check_comptime_is_field_selector_bool(node ast.SelectorExpr) bool {
|
||||||
if c.check_comptime_is_field_selector(node) {
|
if c.check_comptime_is_field_selector(node) {
|
||||||
@ -772,6 +789,7 @@ fn (mut c Checker) check_comptime_is_field_selector_bool(node ast.SelectorExpr)
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// get_comptime_selector_bool_field evaluates the bool value for field.is_* fields
|
||||||
fn (mut c Checker) get_comptime_selector_bool_field(field_name string) bool {
|
fn (mut c Checker) get_comptime_selector_bool_field(field_name string) bool {
|
||||||
field := c.comptime_for_field_value
|
field := c.comptime_for_field_value
|
||||||
field_typ := c.comptime_fields_default_type
|
field_typ := c.comptime_fields_default_type
|
||||||
|
@ -37,15 +37,6 @@ fn (mut c Checker) for_c_stmt(node ast.ForCStmt) {
|
|||||||
c.in_for_count--
|
c.in_for_count--
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut c Checker) get_compselector_type_from_selector_name(node ast.ComptimeSelector) (bool, ast.Type) {
|
|
||||||
if c.inside_comptime_for_field && node.field_expr is ast.SelectorExpr
|
|
||||||
&& (node.field_expr as ast.SelectorExpr).expr.str() in c.comptime_fields_type
|
|
||||||
&& (node.field_expr as ast.SelectorExpr).field_name == 'name' {
|
|
||||||
return true, c.unwrap_generic(c.comptime_fields_default_type)
|
|
||||||
}
|
|
||||||
return false, ast.void_type
|
|
||||||
}
|
|
||||||
|
|
||||||
fn (mut c Checker) for_in_stmt(mut node ast.ForInStmt) {
|
fn (mut c Checker) for_in_stmt(mut node ast.ForInStmt) {
|
||||||
c.in_for_count++
|
c.in_for_count++
|
||||||
prev_loop_label := c.loop_label
|
prev_loop_label := c.loop_label
|
||||||
@ -97,10 +88,10 @@ fn (mut c Checker) for_in_stmt(mut node ast.ForInStmt) {
|
|||||||
node.val_is_ref = node.cond.op == .amp
|
node.val_is_ref = node.cond.op == .amp
|
||||||
}
|
}
|
||||||
ast.ComptimeSelector {
|
ast.ComptimeSelector {
|
||||||
found, selector_type := c.get_compselector_type_from_selector_name(node.cond)
|
comptime_typ := c.get_comptime_selector_type(node.cond, ast.void_type)
|
||||||
if found {
|
if comptime_typ != ast.void_type {
|
||||||
sym = c.table.final_sym(selector_type)
|
sym = c.table.final_sym(comptime_typ)
|
||||||
typ = selector_type
|
typ = comptime_typ
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ast.Ident {
|
ast.Ident {
|
||||||
|
@ -6,6 +6,22 @@ import v.ast
|
|||||||
import v.pref
|
import v.pref
|
||||||
import v.token
|
import v.token
|
||||||
|
|
||||||
|
fn (mut c Checker) check_compatible_types(left_type ast.Type, right ast.TypeNode) ComptimeBranchSkipState {
|
||||||
|
right_type := c.unwrap_generic(right.typ)
|
||||||
|
sym := c.table.sym(right_type)
|
||||||
|
|
||||||
|
if sym.kind == .interface_ {
|
||||||
|
checked_type := c.unwrap_generic(left_type)
|
||||||
|
return if c.table.does_type_implement_interface(checked_type, right_type) {
|
||||||
|
.eval
|
||||||
|
} else {
|
||||||
|
.skip
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return if left_type == right_type { .eval } else { .skip }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn (mut c Checker) if_expr(mut node ast.IfExpr) ast.Type {
|
fn (mut c Checker) if_expr(mut node ast.IfExpr) ast.Type {
|
||||||
if_kind := if node.is_comptime { '\$if' } else { 'if' }
|
if_kind := if node.is_comptime { '\$if' } else { 'if' }
|
||||||
mut node_is_expr := false
|
mut node_is_expr := false
|
||||||
@ -121,22 +137,25 @@ fn (mut c Checker) if_expr(mut node ast.IfExpr) ast.Type {
|
|||||||
comptime_field_name = left.expr.str()
|
comptime_field_name = left.expr.str()
|
||||||
c.comptime_fields_type[comptime_field_name] = got_type
|
c.comptime_fields_type[comptime_field_name] = got_type
|
||||||
is_comptime_type_is_expr = true
|
is_comptime_type_is_expr = true
|
||||||
} else if right is ast.TypeNode && left is ast.TypeNode
|
if comptime_field_name == c.comptime_for_field_var {
|
||||||
&& sym.kind == .interface_ {
|
left_type := c.unwrap_generic(c.comptime_fields_default_type)
|
||||||
is_comptime_type_is_expr = true
|
if left.field_name == 'typ' {
|
||||||
// is interface
|
skip_state = c.check_compatible_types(left_type, right as ast.TypeNode)
|
||||||
checked_type := c.unwrap_generic(left.typ)
|
} else if left.field_name == 'unaliased_typ' {
|
||||||
skip_state = if c.table.does_type_implement_interface(checked_type,
|
skip_state = c.check_compatible_types(c.table.unaliased_type(left_type),
|
||||||
got_type)
|
right as ast.TypeNode)
|
||||||
{
|
}
|
||||||
.eval
|
} else if c.check_comptime_is_field_selector_bool(left) {
|
||||||
} else {
|
skip_state = if c.get_comptime_selector_bool_field(left.field_name) {
|
||||||
.skip
|
.eval
|
||||||
|
} else {
|
||||||
|
.skip
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if left is ast.TypeNode {
|
} else if left is ast.TypeNode {
|
||||||
is_comptime_type_is_expr = true
|
is_comptime_type_is_expr = true
|
||||||
left_type := c.unwrap_generic(left.typ)
|
left_type := c.unwrap_generic(left.typ)
|
||||||
skip_state = if left_type == got_type { .eval } else { .skip }
|
skip_state = c.check_compatible_types(left_type, right as ast.TypeNode)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,9 +24,7 @@ fn (mut c Checker) postfix_expr(mut node ast.PostfixExpr) ast.Type {
|
|||||||
}
|
}
|
||||||
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.inside_comptime_for_field {
|
||||||
if c.is_comptime_var(node.expr) {
|
if c.is_comptime_var(node.expr) || node.expr is ast.ComptimeSelector {
|
||||||
return c.comptime_fields_default_type
|
|
||||||
} else if node.expr is ast.ComptimeSelector {
|
|
||||||
return c.comptime_fields_default_type
|
return c.comptime_fields_default_type
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -647,8 +647,7 @@ fn (mut c Checker) struct_init(mut node ast.StructInit, is_field_zero_struct_ini
|
|||||||
node.update_expr_type = update_type
|
node.update_expr_type = update_type
|
||||||
if node.update_expr is ast.ComptimeSelector {
|
if node.update_expr is ast.ComptimeSelector {
|
||||||
c.error('cannot use struct update syntax in compile time expressions', node.update_expr_pos)
|
c.error('cannot use struct update syntax in compile time expressions', node.update_expr_pos)
|
||||||
}
|
} else if c.table.final_sym(update_type).kind != .struct_ {
|
||||||
if c.table.final_sym(update_type).kind != .struct_ {
|
|
||||||
s := c.table.type_to_str(update_type)
|
s := c.table.type_to_str(update_type)
|
||||||
c.error('expected struct, found `${s}`', node.update_expr.pos())
|
c.error('expected struct, found `${s}`', node.update_expr.pos())
|
||||||
} else if update_type != node.typ {
|
} else if update_type != node.typ {
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
[vlib/v/checker/tests/comptime_dump_fields_var_test.vv:13] val.$field.name: c
|
[vlib/v/checker/tests/comptime_dump_fields_var_test.vv:13] val.$(field.name): c
|
||||||
[vlib/v/checker/tests/comptime_dump_fields_var_test.vv:13] val.$field.name: d
|
[vlib/v/checker/tests/comptime_dump_fields_var_test.vv:13] val.$(field.name): d
|
||||||
[vlib/v/checker/tests/comptime_dump_fields_var_test.vv:13] val.$field.name: 1
|
[vlib/v/checker/tests/comptime_dump_fields_var_test.vv:13] val.$(field.name): 1
|
||||||
[vlib/v/checker/tests/comptime_dump_fields_var_test.vv:13] val.$field.name: 0
|
[vlib/v/checker/tests/comptime_dump_fields_var_test.vv:13] val.$(field.name): 0
|
||||||
[vlib/v/checker/tests/comptime_dump_fields_var_test.vv:13] val.$field.name: struct {
|
[vlib/v/checker/tests/comptime_dump_fields_var_test.vv:13] val.$(field.name): struct {
|
||||||
i: 100
|
i: 100
|
||||||
}
|
}
|
||||||
ok
|
ok
|
||||||
|
@ -131,6 +131,7 @@ fn (mut g Gen) assign_stmt(node_ ast.AssignStmt) {
|
|||||||
key_str := g.get_comptime_selector_key_type(val)
|
key_str := g.get_comptime_selector_key_type(val)
|
||||||
if key_str != '' {
|
if key_str != '' {
|
||||||
var_type = g.comptime_var_type_map[key_str] or { var_type }
|
var_type = g.comptime_var_type_map[key_str] or { var_type }
|
||||||
|
val_type = var_type
|
||||||
left.obj.typ = var_type
|
left.obj.typ = var_type
|
||||||
is_comptime_var = true
|
is_comptime_var = true
|
||||||
}
|
}
|
||||||
@ -142,6 +143,17 @@ fn (mut g Gen) assign_stmt(node_ ast.AssignStmt) {
|
|||||||
}
|
}
|
||||||
is_auto_heap = left.obj.is_auto_heap
|
is_auto_heap = left.obj.is_auto_heap
|
||||||
}
|
}
|
||||||
|
} else if mut left is ast.ComptimeSelector {
|
||||||
|
key_str := g.get_comptime_selector_key_type(left)
|
||||||
|
if key_str != '' {
|
||||||
|
var_type = g.comptime_var_type_map[key_str] or { var_type }
|
||||||
|
}
|
||||||
|
if val is ast.ComptimeSelector {
|
||||||
|
key_str_right := g.get_comptime_selector_key_type(val)
|
||||||
|
if key_str_right != '' {
|
||||||
|
val_type = g.comptime_var_type_map[key_str_right] or { var_type }
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
mut styp := g.typ(var_type)
|
mut styp := g.typ(var_type)
|
||||||
mut is_fixed_array_init := false
|
mut is_fixed_array_init := false
|
||||||
@ -490,8 +502,12 @@ fn (mut g Gen) assign_stmt(node_ ast.AssignStmt) {
|
|||||||
} else if val_type.has_flag(.shared_f) {
|
} else if val_type.has_flag(.shared_f) {
|
||||||
g.expr_with_cast(val, val_type, var_type)
|
g.expr_with_cast(val, val_type, var_type)
|
||||||
} else if is_comptime_var && g.right_is_opt {
|
} else if is_comptime_var && g.right_is_opt {
|
||||||
tmp_var := g.new_tmp_var()
|
if var_type.has_flag(.option) && val is ast.ComptimeSelector {
|
||||||
g.expr_with_tmp_var(val, val_type, var_type, tmp_var)
|
g.expr(val)
|
||||||
|
} else {
|
||||||
|
tmp_var := g.new_tmp_var()
|
||||||
|
g.expr_with_tmp_var(val, val_type, var_type, tmp_var)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
g.expr(val)
|
g.expr(val)
|
||||||
}
|
}
|
||||||
|
@ -320,7 +320,7 @@ fn (e &Encoder) encode_struct[U](val U, level int, mut wr io.Writer) ! {
|
|||||||
$if field.unaliased_typ is string {
|
$if field.unaliased_typ is string {
|
||||||
e.encode_string(val.$(field.name).str(), mut wr)!
|
e.encode_string(val.$(field.name).str(), mut wr)!
|
||||||
} $else $if field.unaliased_typ is time.Time {
|
} $else $if field.unaliased_typ is time.Time {
|
||||||
parsed_time := val.$(field.name) as time.Time
|
parsed_time := time.parse(val.$(field.name).str()) or { time.Time{} }
|
||||||
e.encode_string(parsed_time.format_rfc3339(), mut wr)!
|
e.encode_string(parsed_time.format_rfc3339(), mut wr)!
|
||||||
} $else $if field.unaliased_typ in [bool, $Float, $Int] {
|
} $else $if field.unaliased_typ in [bool, $Float, $Int] {
|
||||||
wr.write(val.$(field.name).str().bytes())!
|
wr.write(val.$(field.name).str().bytes())!
|
||||||
|
Loading…
Reference in New Issue
Block a user