1
0
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:
Felipe Pena 2023-02-15 06:40:11 -03:00 committed by GitHub
parent 5a8c433548
commit 039c9b2550
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 88 additions and 62 deletions

View File

@ -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(',')

View File

@ -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 {

View File

@ -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
}
}
} }
} }
} }

View File

@ -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`

View File

@ -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

View File

@ -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 {

View File

@ -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)
} }
} }
} }

View File

@ -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
} }
} }

View File

@ -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 {

View File

@ -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

View File

@ -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)
} }

View File

@ -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())!