Skip to content

Commit

Permalink
checker, cgen: fix comptime issues with generic type (fix #22710, #22642
Browse files Browse the repository at this point in the history
) (#22751)
  • Loading branch information
felipensp authored Nov 5, 2024
1 parent bd6005e commit d9c3ac5
Show file tree
Hide file tree
Showing 22 changed files with 391 additions and 113 deletions.
7 changes: 4 additions & 3 deletions vlib/v/checker/assign.v
Original file line number Diff line number Diff line change
Expand Up @@ -399,7 +399,7 @@ fn (mut c Checker) assign_stmt(mut node ast.AssignStmt) {
&& right.or_expr.kind == .absent {
right_obj_var := right.obj as ast.Var
if right_obj_var.ct_type_var != .no_comptime {
ctyp := c.comptime.get_comptime_var_type(right)
ctyp := c.comptime.get_type(right)
if ctyp != ast.void_type {
left.obj.ct_type_var = right_obj_var.ct_type_var
left.obj.typ = ctyp
Expand All @@ -421,11 +421,12 @@ fn (mut c Checker) assign_stmt(mut node ast.AssignStmt) {
fn_ret_type := c.resolve_return_type(right)
if fn_ret_type != ast.void_type
&& c.table.final_sym(fn_ret_type).kind != .multi_return {
c.comptime.type_map['g.${left.name}.${left.obj.pos.pos}'] = if right.or_block.kind == .absent {
var_type := if right.or_block.kind == .absent {
fn_ret_type
} else {
fn_ret_type.clear_option_and_result()
}
c.comptime.type_map['g.${left.name}.${left.obj.pos.pos}'] = var_type
}
}
}
Expand Down Expand Up @@ -505,7 +506,7 @@ fn (mut c Checker) assign_stmt(mut node ast.AssignStmt) {
}

if right is ast.Ident && c.comptime.is_comptime_var(right) {
right_type = c.comptime.get_comptime_var_type(right)
right_type = c.comptime.get_type(right)
}
}
if mut left is ast.InfixExpr {
Expand Down
4 changes: 2 additions & 2 deletions vlib/v/checker/checker.v
Original file line number Diff line number Diff line change
Expand Up @@ -2928,7 +2928,7 @@ pub fn (mut c Checker) expr(mut node ast.Expr) ast.Type {

if c.comptime.inside_comptime_for && node.expr is ast.Ident {
if c.comptime.is_comptime_var(node.expr) {
node.expr_type = c.comptime.get_comptime_var_type(node.expr as ast.Ident)
node.expr_type = c.comptime.get_type(node.expr as ast.Ident)
} else if (node.expr as ast.Ident).name in c.comptime.type_map {
node.expr_type = c.comptime.type_map[(node.expr as ast.Ident).name]
}
Expand Down Expand Up @@ -3805,7 +3805,7 @@ fn (mut c Checker) ident(mut node ast.Ident) ast.Type {
if node.kind in [.constant, .global, .variable] {
info := node.info as ast.IdentVar
typ := if c.comptime.is_comptime_var(node) {
ctype := c.comptime.get_comptime_var_type(node)
ctype := c.comptime.get_type(node)
if ctype != ast.void_type {
ctype
} else {
Expand Down
4 changes: 2 additions & 2 deletions vlib/v/checker/comptime.v
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ fn (mut c Checker) comptime_call(mut node ast.ComptimeCall) ast.Type {
node.args[i].typ = c.expr(mut arg.expr)
}
c.stmts_ending_with_expression(mut node.or_block.stmts, c.expected_or_type)
return c.comptime.get_comptime_var_type(node)
return c.comptime.get_type(node)
}
if node.method_name == 'res' {
if !c.inside_defer {
Expand Down Expand Up @@ -790,7 +790,7 @@ fn (mut c Checker) comptime_if_cond(mut cond ast.Expr, pos token.Pos) ComptimeBr
if mut cond.left is ast.SelectorExpr && cond.right is ast.ComptimeType {
comptime_type := cond.right as ast.ComptimeType
if c.comptime.is_comptime_selector_type(cond.left) {
checked_type := c.comptime.get_comptime_var_type(cond.left)
checked_type := c.comptime.get_type(cond.left)
return if c.comptime.is_comptime_type(checked_type, comptime_type) {
.eval
} else {
Expand Down
15 changes: 9 additions & 6 deletions vlib/v/checker/fn.v
Original file line number Diff line number Diff line change
Expand Up @@ -1807,7 +1807,7 @@ fn (mut c Checker) resolve_comptime_args(func &ast.Fn, node_ ast.CallExpr, concr
if call_arg.expr is ast.Ident {
if call_arg.expr.obj is ast.Var {
if call_arg.expr.obj.ct_type_var !in [.generic_var, .generic_param, .no_comptime] {
mut ctyp := c.comptime.get_comptime_var_type(call_arg.expr)
mut ctyp := c.comptime.get_type(call_arg.expr)
if ctyp != ast.void_type {
arg_sym := c.table.sym(ctyp)
param_sym := c.table.final_sym(param_typ)
Expand All @@ -1830,7 +1830,7 @@ fn (mut c Checker) resolve_comptime_args(func &ast.Fn, node_ ast.CallExpr, concr
comptime_args[k] = ctyp
}
} else if call_arg.expr.obj.ct_type_var == .generic_param {
mut ctyp := c.comptime.get_comptime_var_type(call_arg.expr)
mut ctyp := c.comptime.get_type(call_arg.expr)
if ctyp != ast.void_type {
arg_sym := c.table.final_sym(call_arg.typ)
param_typ_sym := c.table.sym(param_typ)
Expand Down Expand Up @@ -1893,7 +1893,10 @@ fn (mut c Checker) resolve_comptime_args(func &ast.Fn, node_ ast.CallExpr, concr
}
}
} else if call_arg.expr.obj.ct_type_var == .generic_var {
mut ctyp := c.comptime.get_comptime_var_type(call_arg.expr)
mut ctyp := c.comptime.get_type(call_arg.expr)
if node_.args[i].expr.is_auto_deref_var() {
ctyp = ctyp.deref()
}
if ctyp.nr_muls() > 0 && param_typ.nr_muls() > 0 {
ctyp = ctyp.set_nr_muls(0)
}
Expand All @@ -1902,14 +1905,14 @@ fn (mut c Checker) resolve_comptime_args(func &ast.Fn, node_ ast.CallExpr, concr
}
} else if call_arg.expr is ast.PrefixExpr {
if call_arg.expr.right is ast.ComptimeSelector {
comptime_args[k] = c.comptime.get_comptime_var_type(call_arg.expr.right)
comptime_args[k] = c.comptime.get_type(call_arg.expr.right)
comptime_args[k] = comptime_args[k].deref()
if comptime_args[k].nr_muls() > 0 && param_typ.nr_muls() > 0 {
comptime_args[k] = comptime_args[k].set_nr_muls(0)
}
}
} else if call_arg.expr is ast.ComptimeSelector {
ct_value := c.comptime.get_comptime_var_type(call_arg.expr)
ct_value := c.comptime.get_type(call_arg.expr)
param_typ_sym := c.table.sym(param_typ)
if ct_value != ast.void_type {
arg_sym := c.table.final_sym(call_arg.typ)
Expand All @@ -1934,7 +1937,7 @@ fn (mut c Checker) resolve_comptime_args(func &ast.Fn, node_ ast.CallExpr, concr
}
}
} else if call_arg.expr is ast.ComptimeCall {
comptime_args[k] = c.comptime.get_comptime_var_type(call_arg.expr)
comptime_args[k] = c.comptime.get_type(call_arg.expr)
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion vlib/v/checker/for.v
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ fn (mut c Checker) for_in_stmt(mut node ast.ForInStmt) {
mut is_comptime := false
if (node.cond is ast.Ident && c.comptime.is_comptime_var(node.cond))
|| node.cond is ast.ComptimeSelector {
ctyp := c.comptime.get_comptime_var_type(node.cond)
ctyp := c.comptime.get_type(node.cond)
if ctyp != ast.void_type {
is_comptime = true
typ = ctyp
Expand Down
6 changes: 3 additions & 3 deletions vlib/v/checker/if.v
Original file line number Diff line number Diff line change
Expand Up @@ -557,7 +557,7 @@ fn (mut c Checker) smartcast_if_conds(mut node ast.Expr, mut scope ast.Scope, co
c.smartcast_if_conds(mut node.right, mut scope, control_expr)
} else if node.left is ast.Ident && node.op == .ne && node.right is ast.None {
if node.left is ast.Ident && c.comptime.get_ct_type_var(node.left) == .smartcast {
node.left_type = c.comptime.get_comptime_var_type(node.left)
node.left_type = c.comptime.get_type(node.left)
c.smartcast(mut node.left, node.left_type, node.left_type.clear_flag(.option), mut
scope, true)
} else {
Expand All @@ -566,7 +566,7 @@ fn (mut c Checker) smartcast_if_conds(mut node ast.Expr, mut scope ast.Scope, co
}
} else if node.op == .key_is {
if node.left is ast.Ident && c.comptime.is_comptime_var(node.left) {
node.left_type = c.comptime.get_comptime_var_type(node.left)
node.left_type = c.comptime.get_type(node.left)
} else {
node.left_type = c.expr(mut node.left)
}
Expand Down Expand Up @@ -650,7 +650,7 @@ fn (mut c Checker) smartcast_if_conds(mut node ast.Expr, mut scope ast.Scope, co
if first_cond.left is ast.Ident && first_cond.op == .eq && first_cond.right is ast.None {
if first_cond.left is ast.Ident
&& c.comptime.get_ct_type_var(first_cond.left) == .smartcast {
first_cond.left_type = c.comptime.get_comptime_var_type(first_cond.left)
first_cond.left_type = c.comptime.get_type(first_cond.left)
c.smartcast(mut first_cond.left, first_cond.left_type, first_cond.left_type.clear_flag(.option), mut
scope, true)
} else {
Expand Down
2 changes: 1 addition & 1 deletion vlib/v/checker/postfix.v
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,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 c.comptime.comptime_for_field_var != '' {
if c.comptime.is_comptime_var(node.expr) || node.expr is ast.ComptimeSelector {
node.typ = c.unwrap_generic(c.comptime.get_comptime_var_type(node.expr))
node.typ = c.unwrap_generic(c.comptime.get_type(node.expr))
if node.op == .question {
node.typ = node.typ.clear_flag(.option)
}
Expand Down
5 changes: 2 additions & 3 deletions vlib/v/checker/str.v
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ fn (mut c Checker) string_inter_lit(mut node ast.StringInterLiteral) ast.Type {
mut ftyp := c.expr(mut expr)
ftyp = c.check_expr_option_or_result_call(expr, ftyp)
if c.comptime.is_comptime_var(expr) {
ctyp := c.comptime.get_comptime_var_type(expr)
ctyp := c.comptime.get_type(expr)
if ctyp != ast.void_type {
ftyp = ctyp
}
Expand Down Expand Up @@ -79,8 +79,7 @@ fn (mut c Checker) string_inter_lit(mut node ast.StringInterLiteral) ast.Type {
c.error('no known default format for type `${c.table.get_type_name(ftyp)}`',
node.fmt_poss[i])
}
} else if c.comptime.is_comptime_var(expr)
&& c.comptime.get_comptime_var_type(expr) != ast.void_type {
} else if c.comptime.is_comptime_var(expr) && c.comptime.get_type(expr) != ast.void_type {
// still `_` placeholder for comptime variable without specifier
node.need_fmts[i] = false
} else {
Expand Down
36 changes: 31 additions & 5 deletions vlib/v/comptime/comptimeinfo.v
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,14 @@ pub fn (mut ct ComptimeInfo) get_comptime_selector_key_type(val ast.ComptimeSele
return ''
}

// is_comptime_expr checks if the node is related to a comptime expr
@[inline]
pub fn (mut ct ComptimeInfo) is_comptime_expr(node ast.Expr) bool {
return (node is ast.Ident && ct.get_ct_type_var(node) != .no_comptime)
|| (node is ast.IndexExpr && ct.is_comptime_expr(node.left))
|| node is ast.ComptimeSelector
}

// is_comptime_var checks if the node is related to a comptime variable
@[inline]
pub fn (mut ct ComptimeInfo) is_comptime_var(node ast.Expr) bool {
Expand All @@ -45,6 +53,8 @@ pub fn (mut ct ComptimeInfo) is_comptime_variant_var(node ast.Ident) bool {
pub fn (mut ct ComptimeInfo) get_ct_type_var(node ast.Expr) ast.ComptimeVarKind {
return if node is ast.Ident && node.obj is ast.Var {
(node.obj as ast.Var).ct_type_var
} else if node is ast.IndexExpr {
return ct.get_ct_type_var(node.left)
} else {
.no_comptime
}
Expand All @@ -56,9 +66,23 @@ pub fn (mut ct ComptimeInfo) is_generic_param_var(node ast.Expr) bool {
&& (node.obj as ast.Var).ct_type_var == .generic_param
}

// get_comptime_var_type retrieves the actual type from a comptime related ast node
// get_expr_type computes the ast node type regarding its or_expr
pub fn (mut ct ComptimeInfo) get_expr_type(node ast.Expr) ast.Type {
ctyp := ct.get_type(node)
match node {
ast.Ident {
if ctyp.has_flag(.option) && node.or_expr.kind != .absent {
return ctyp.clear_flag(.option)
}
}
else {}
}
return ctyp
}

// get_type retrieves the actual type from a comptime related ast node
@[inline]
pub fn (mut ct ComptimeInfo) get_comptime_var_type(node ast.Expr) ast.Type {
pub fn (mut ct ComptimeInfo) get_type(node ast.Expr) ast.Type {
if node is ast.Ident {
if node.obj is ast.Var {
return match node.obj.ct_type_var {
Expand Down Expand Up @@ -109,6 +133,8 @@ pub fn (mut ct ComptimeInfo) get_comptime_var_type(node ast.Expr) ast.Type {
return ast.void_type
}
return f.return_type
} else if node is ast.IndexExpr && ct.is_comptime_var(node.left) {
return ct.table.value_type(ct.resolver.unwrap_generic(ct.get_type(node.left)))
}
return ast.void_type
}
Expand Down Expand Up @@ -304,16 +330,16 @@ pub fn (mut ct ComptimeInfo) unwrap_generic_expr(expr ast.Expr, default_typ ast.
}
ast.InfixExpr {
if ct.is_comptime_var(expr.left) {
return ct.resolver.unwrap_generic(ct.get_comptime_var_type(expr.left))
return ct.resolver.unwrap_generic(ct.get_type(expr.left))
}
if ct.is_comptime_var(expr.right) {
return ct.resolver.unwrap_generic(ct.get_comptime_var_type(expr.right))
return ct.resolver.unwrap_generic(ct.get_type(expr.right))
}
return default_typ
}
ast.Ident {
return if ct.is_comptime_var(expr) {
ct.resolver.unwrap_generic(ct.get_comptime_var_type(expr))
ct.resolver.unwrap_generic(ct.get_type(expr))
} else {
default_typ
}
Expand Down
2 changes: 1 addition & 1 deletion vlib/v/gen/c/array.v
Original file line number Diff line number Diff line change
Expand Up @@ -564,7 +564,7 @@ fn (mut g Gen) gen_array_map(node ast.CallExpr) {
// value.map(Type(it)) when `value` is a comptime var
if expr.expr is ast.Ident && node.left is ast.Ident
&& g.comptime.is_comptime_var(node.left) {
ctyp := g.comptime.get_comptime_var_type(node.left)
ctyp := g.comptime.get_type(node.left)
if ctyp != ast.void_type {
expr.expr_type = g.table.value_type(ctyp)
}
Expand Down
16 changes: 14 additions & 2 deletions vlib/v/gen/c/assert.v
Original file line number Diff line number Diff line change
Expand Up @@ -151,12 +151,22 @@ fn (mut g Gen) gen_assert_metainfo(node ast.AssertStmt, kind AssertMetainfoKind)
g.writeln('\t${metaname}.op = ${expr_op_str};')
g.writeln('\t${metaname}.llabel = ${expr_left_str};')
g.writeln('\t${metaname}.rlabel = ${expr_right_str};')
left_type := if g.comptime.is_comptime_expr(node.expr.left) {
g.comptime.get_type(node.expr.left)
} else {
node.expr.left_type
}
right_type := if g.comptime.is_comptime_expr(node.expr.right) {
g.comptime.get_type(node.expr.right)
} else {
node.expr.right_type
}
if kind != .pass {
g.write('\t${metaname}.lvalue = ')
g.gen_assert_single_expr(node.expr.left, node.expr.left_type)
g.gen_assert_single_expr(node.expr.left, left_type)
g.writeln(';')
g.write('\t${metaname}.rvalue = ')
g.gen_assert_single_expr(node.expr.right, node.expr.right_type)
g.gen_assert_single_expr(node.expr.right, right_type)
g.writeln(';')
}
}
Expand Down Expand Up @@ -207,6 +217,8 @@ fn (mut g Gen) gen_assert_single_expr(expr ast.Expr, typ ast.Type) {
// vlib/builtin/map_test.v (a map of &int, set to &int(0)) fails
// without special casing ast.CastExpr here
g.write(ctoslit(expr_str))
} else if expr.right is ast.Ident {
g.write(ctoslit(expr_str))
} else {
g.gen_expr_to_string(expr, typ)
}
Expand Down
2 changes: 1 addition & 1 deletion vlib/v/gen/c/assign.v
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,7 @@ fn (mut g Gen) assign_stmt(node_ ast.AssignStmt) {
}
if mut left.obj is ast.Var {
if val is ast.Ident && g.comptime.is_comptime_var(val) {
ctyp := g.unwrap_generic(g.comptime.get_comptime_var_type(val))
ctyp := g.unwrap_generic(g.comptime.get_type(val))
if ctyp != ast.void_type {
var_type = ctyp
val_type = var_type
Expand Down
Loading

0 comments on commit d9c3ac5

Please sign in to comment.