checker, cgen: fix comptime issues with generic type (fix #22710, #22642) (#22751)

This commit is contained in:
Felipe Pena 2024-11-05 11:23:51 -03:00 committed by GitHub
parent bd6005ed73
commit d9c3ac5ce6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
22 changed files with 391 additions and 113 deletions

View File

@ -399,7 +399,7 @@ fn (mut c Checker) assign_stmt(mut node ast.AssignStmt) {
&& right.or_expr.kind == .absent { && right.or_expr.kind == .absent {
right_obj_var := right.obj as ast.Var right_obj_var := right.obj as ast.Var
if right_obj_var.ct_type_var != .no_comptime { 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 { if ctyp != ast.void_type {
left.obj.ct_type_var = right_obj_var.ct_type_var left.obj.ct_type_var = right_obj_var.ct_type_var
left.obj.typ = ctyp left.obj.typ = ctyp
@ -421,11 +421,12 @@ fn (mut c Checker) assign_stmt(mut node ast.AssignStmt) {
fn_ret_type := c.resolve_return_type(right) fn_ret_type := c.resolve_return_type(right)
if fn_ret_type != ast.void_type if fn_ret_type != ast.void_type
&& c.table.final_sym(fn_ret_type).kind != .multi_return { && 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 fn_ret_type
} else { } else {
fn_ret_type.clear_option_and_result() fn_ret_type.clear_option_and_result()
} }
c.comptime.type_map['g.${left.name}.${left.obj.pos.pos}'] = var_type
} }
} }
} }
@ -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) { 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 { if mut left is ast.InfixExpr {

View File

@ -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.inside_comptime_for && node.expr is ast.Ident {
if c.comptime.is_comptime_var(node.expr) { 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 { } 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] node.expr_type = c.comptime.type_map[(node.expr as ast.Ident).name]
} }
@ -3805,7 +3805,7 @@ fn (mut c Checker) ident(mut node ast.Ident) ast.Type {
if node.kind in [.constant, .global, .variable] { if node.kind in [.constant, .global, .variable] {
info := node.info as ast.IdentVar info := node.info as ast.IdentVar
typ := if c.comptime.is_comptime_var(node) { 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 { if ctype != ast.void_type {
ctype ctype
} else { } else {

View File

@ -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) node.args[i].typ = c.expr(mut arg.expr)
} }
c.stmts_ending_with_expression(mut node.or_block.stmts, c.expected_or_type) 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 node.method_name == 'res' {
if !c.inside_defer { if !c.inside_defer {
@ -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 { if mut cond.left is ast.SelectorExpr && cond.right is ast.ComptimeType {
comptime_type := cond.right as ast.ComptimeType comptime_type := cond.right as ast.ComptimeType
if c.comptime.is_comptime_selector_type(cond.left) { 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) { return if c.comptime.is_comptime_type(checked_type, comptime_type) {
.eval .eval
} else { } else {

View File

@ -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 is ast.Ident {
if call_arg.expr.obj is ast.Var { if call_arg.expr.obj is ast.Var {
if call_arg.expr.obj.ct_type_var !in [.generic_var, .generic_param, .no_comptime] { 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 { if ctyp != ast.void_type {
arg_sym := c.table.sym(ctyp) arg_sym := c.table.sym(ctyp)
param_sym := c.table.final_sym(param_typ) param_sym := c.table.final_sym(param_typ)
@ -1830,7 +1830,7 @@ fn (mut c Checker) resolve_comptime_args(func &ast.Fn, node_ ast.CallExpr, concr
comptime_args[k] = ctyp comptime_args[k] = ctyp
} }
} else if call_arg.expr.obj.ct_type_var == .generic_param { } 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 { if ctyp != ast.void_type {
arg_sym := c.table.final_sym(call_arg.typ) arg_sym := c.table.final_sym(call_arg.typ)
param_typ_sym := c.table.sym(param_typ) param_typ_sym := c.table.sym(param_typ)
@ -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 { } 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 { if ctyp.nr_muls() > 0 && param_typ.nr_muls() > 0 {
ctyp = ctyp.set_nr_muls(0) ctyp = ctyp.set_nr_muls(0)
} }
@ -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 { } else if call_arg.expr is ast.PrefixExpr {
if call_arg.expr.right is ast.ComptimeSelector { 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() comptime_args[k] = comptime_args[k].deref()
if comptime_args[k].nr_muls() > 0 && param_typ.nr_muls() > 0 { if comptime_args[k].nr_muls() > 0 && param_typ.nr_muls() > 0 {
comptime_args[k] = comptime_args[k].set_nr_muls(0) comptime_args[k] = comptime_args[k].set_nr_muls(0)
} }
} }
} else if call_arg.expr is ast.ComptimeSelector { } 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) param_typ_sym := c.table.sym(param_typ)
if ct_value != ast.void_type { if ct_value != ast.void_type {
arg_sym := c.table.final_sym(call_arg.typ) arg_sym := c.table.final_sym(call_arg.typ)
@ -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 { } 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)
} }
} }
} }

View File

@ -80,7 +80,7 @@ fn (mut c Checker) for_in_stmt(mut node ast.ForInStmt) {
mut is_comptime := false mut is_comptime := false
if (node.cond is ast.Ident && c.comptime.is_comptime_var(node.cond)) if (node.cond is ast.Ident && c.comptime.is_comptime_var(node.cond))
|| node.cond is ast.ComptimeSelector { || 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 { if ctyp != ast.void_type {
is_comptime = true is_comptime = true
typ = ctyp typ = ctyp

View File

@ -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) 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 { } 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 { 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 c.smartcast(mut node.left, node.left_type, node.left_type.clear_flag(.option), mut
scope, true) scope, true)
} else { } else {
@ -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 { } else if node.op == .key_is {
if node.left is ast.Ident && c.comptime.is_comptime_var(node.left) { 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 { } else {
node.left_type = c.expr(mut node.left) node.left_type = c.expr(mut node.left)
} }
@ -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 && first_cond.op == .eq && first_cond.right is ast.None {
if first_cond.left is ast.Ident if first_cond.left is ast.Ident
&& c.comptime.get_ct_type_var(first_cond.left) == .smartcast { && 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 c.smartcast(mut first_cond.left, first_cond.left_type, first_cond.left_type.clear_flag(.option), mut
scope, true) scope, true)
} else { } else {

View File

@ -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 !(typ_sym.is_number() || ((c.inside_unsafe || c.pref.translated) && is_non_void_pointer)) {
if c.comptime.comptime_for_field_var != '' { if c.comptime.comptime_for_field_var != '' {
if c.comptime.is_comptime_var(node.expr) || node.expr is ast.ComptimeSelector { 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 { if node.op == .question {
node.typ = node.typ.clear_flag(.option) node.typ = node.typ.clear_flag(.option)
} }

View File

@ -47,7 +47,7 @@ fn (mut c Checker) string_inter_lit(mut node ast.StringInterLiteral) ast.Type {
mut ftyp := c.expr(mut expr) mut ftyp := c.expr(mut expr)
ftyp = c.check_expr_option_or_result_call(expr, ftyp) ftyp = c.check_expr_option_or_result_call(expr, ftyp)
if c.comptime.is_comptime_var(expr) { 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 { if ctyp != ast.void_type {
ftyp = ctyp ftyp = ctyp
} }
@ -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)}`', c.error('no known default format for type `${c.table.get_type_name(ftyp)}`',
node.fmt_poss[i]) node.fmt_poss[i])
} }
} else if c.comptime.is_comptime_var(expr) } else if c.comptime.is_comptime_var(expr) && c.comptime.get_type(expr) != ast.void_type {
&& c.comptime.get_comptime_var_type(expr) != ast.void_type {
// still `_` placeholder for comptime variable without specifier // still `_` placeholder for comptime variable without specifier
node.need_fmts[i] = false node.need_fmts[i] = false
} else { } else {

View File

@ -28,6 +28,14 @@ pub fn (mut ct ComptimeInfo) get_comptime_selector_key_type(val ast.ComptimeSele
return '' 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 // is_comptime_var checks if the node is related to a comptime variable
@[inline] @[inline]
pub fn (mut ct ComptimeInfo) is_comptime_var(node ast.Expr) bool { pub fn (mut ct ComptimeInfo) is_comptime_var(node ast.Expr) bool {
@ -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 { 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 { return if node is ast.Ident && node.obj is ast.Var {
(node.obj as ast.Var).ct_type_var (node.obj as ast.Var).ct_type_var
} else if node is ast.IndexExpr {
return ct.get_ct_type_var(node.left)
} else { } else {
.no_comptime .no_comptime
} }
@ -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 && (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] @[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 is ast.Ident {
if node.obj is ast.Var { if node.obj is ast.Var {
return match node.obj.ct_type_var { return match node.obj.ct_type_var {
@ -109,6 +133,8 @@ pub fn (mut ct ComptimeInfo) get_comptime_var_type(node ast.Expr) ast.Type {
return ast.void_type return ast.void_type
} }
return f.return_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 return ast.void_type
} }
@ -304,16 +330,16 @@ pub fn (mut ct ComptimeInfo) unwrap_generic_expr(expr ast.Expr, default_typ ast.
} }
ast.InfixExpr { ast.InfixExpr {
if ct.is_comptime_var(expr.left) { 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) { 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 return default_typ
} }
ast.Ident { ast.Ident {
return if ct.is_comptime_var(expr) { 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 { } else {
default_typ default_typ
} }

View File

@ -564,7 +564,7 @@ fn (mut g Gen) gen_array_map(node ast.CallExpr) {
// value.map(Type(it)) when `value` is a comptime var // value.map(Type(it)) when `value` is a comptime var
if expr.expr is ast.Ident && node.left is ast.Ident if expr.expr is ast.Ident && node.left is ast.Ident
&& g.comptime.is_comptime_var(node.left) { && 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 { if ctyp != ast.void_type {
expr.expr_type = g.table.value_type(ctyp) expr.expr_type = g.table.value_type(ctyp)
} }

View File

@ -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}.op = ${expr_op_str};')
g.writeln('\t${metaname}.llabel = ${expr_left_str};') g.writeln('\t${metaname}.llabel = ${expr_left_str};')
g.writeln('\t${metaname}.rlabel = ${expr_right_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 { if kind != .pass {
g.write('\t${metaname}.lvalue = ') 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.writeln(';')
g.write('\t${metaname}.rvalue = ') 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(';') g.writeln(';')
} }
} }
@ -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 // vlib/builtin/map_test.v (a map of &int, set to &int(0)) fails
// without special casing ast.CastExpr here // without special casing ast.CastExpr here
g.write(ctoslit(expr_str)) g.write(ctoslit(expr_str))
} else if expr.right is ast.Ident {
g.write(ctoslit(expr_str))
} else { } else {
g.gen_expr_to_string(expr, typ) g.gen_expr_to_string(expr, typ)
} }

View File

@ -259,7 +259,7 @@ fn (mut g Gen) assign_stmt(node_ ast.AssignStmt) {
} }
if mut left.obj is ast.Var { if mut left.obj is ast.Var {
if val is ast.Ident && g.comptime.is_comptime_var(val) { 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 { if ctyp != ast.void_type {
var_type = ctyp var_type = ctyp
val_type = var_type val_type = var_type

View File

@ -192,6 +192,7 @@ mut:
auto_fn_definitions []string // auto generated functions definition list auto_fn_definitions []string // auto generated functions definition list
sumtype_casting_fns []SumtypeCastingFn sumtype_casting_fns []SumtypeCastingFn
anon_fn_definitions []string // anon generated functions definition list anon_fn_definitions []string // anon generated functions definition list
anon_fns shared []string // remove duplicate anon generated functions
sumtype_definitions map[int]bool // `_TypeA_to_sumtype_TypeB()` fns that have been generated sumtype_definitions map[int]bool // `_TypeA_to_sumtype_TypeB()` fns that have been generated
trace_fn_definitions []string trace_fn_definitions []string
json_types []ast.Type // to avoid json gen duplicates json_types []ast.Type // to avoid json gen duplicates
@ -713,6 +714,7 @@ fn cgen_process_one_file_cb(mut p pool.PoolProcessor, idx int, wid int) &Gen {
waiter_fns: global_g.waiter_fns waiter_fns: global_g.waiter_fns
threaded_fns: global_g.threaded_fns threaded_fns: global_g.threaded_fns
str_fn_names: global_g.str_fn_names str_fn_names: global_g.str_fn_names
anon_fns: global_g.anon_fns
options_forward: global_g.options_forward options_forward: global_g.options_forward
results_forward: global_g.results_forward results_forward: global_g.results_forward
done_options: global_g.done_options done_options: global_g.done_options
@ -3895,6 +3897,7 @@ fn (mut g Gen) selector_expr(node ast.SelectorExpr) {
if node.expr_type == 0 { if node.expr_type == 0 {
g.checker_bug('unexpected SelectorExpr.expr_type = 0', node.pos) g.checker_bug('unexpected SelectorExpr.expr_type = 0', node.pos)
} }
sym := g.table.sym(g.unwrap_generic(node.expr_type)) sym := g.table.sym(g.unwrap_generic(node.expr_type))
field_name := if sym.language == .v { c_name(node.field_name) } else { node.field_name } field_name := if sym.language == .v { c_name(node.field_name) } else { node.field_name }
is_as_cast := node.expr is ast.AsCast is_as_cast := node.expr is ast.AsCast
@ -4033,53 +4036,13 @@ fn (mut g Gen) selector_expr(node ast.SelectorExpr) {
} }
receiver := m.params[0] receiver := m.params[0]
expr_styp := g.styp(g.unwrap_generic(node.expr_type).idx_type()) expr_styp := g.styp(g.unwrap_generic(node.expr_type).idx_type())
data_styp := g.styp(receiver.typ.idx_type())
mut sb := strings.new_builder(256)
name := '_V_closure_${expr_styp}_${m.name}_${node.pos.pos}' name := '_V_closure_${expr_styp}_${m.name}_${node.pos.pos}'
sb.write_string('${g.styp(m.return_type)} ${name}(') lock g.anon_fns {
for i in 1 .. m.params.len { if name !in g.anon_fns {
param := m.params[i] g.anon_fns << name
if i != 1 { g.gen_closure_fn(expr_styp, m, name)
sb.write_string(', ')
}
sb.write_string('${g.styp(param.typ)} a${i}')
}
sb.writeln(') {')
sb.writeln('\t${data_styp}* a0 = __CLOSURE_GET_DATA();')
if m.return_type != ast.void_type {
sb.write_string('\treturn ')
} else {
sb.write_string('\t')
}
mut method_name := m.name
rec_sym := g.table.sym(receiver.typ)
if rec_sym.info is ast.Struct {
if rec_sym.info.concrete_types.len > 0 {
method_name = g.generic_fn_name(rec_sym.info.concrete_types, m.name)
} }
} }
if rec_sym.info is ast.Interface {
left_cc_type := g.cc_type(g.table.unaliased_type(receiver.typ), false)
left_type_name := util.no_dots(left_cc_type)
sb.write_string('${c_name(left_type_name)}_name_table[a0->_typ]._method_${method_name}(')
} else {
sb.write_string('${expr_styp}_${method_name}(')
if !receiver.typ.is_ptr() {
sb.write_string('*')
}
}
for i in 0 .. m.params.len {
if i != 0 {
sb.write_string(', ')
}
sb.write_string('a${i}')
}
sb.writeln(');')
sb.writeln('}')
g.anon_fn_definitions << sb.str()
g.nr_closures++
g.write('__closure_create(${name}, ') g.write('__closure_create(${name}, ')
if !receiver.typ.is_ptr() { if !receiver.typ.is_ptr() {
g.write('memdup_uncollectable(') g.write('memdup_uncollectable(')
@ -4191,6 +4154,56 @@ fn (mut g Gen) selector_expr(node ast.SelectorExpr) {
} }
} }
fn (mut g Gen) gen_closure_fn(expr_styp string, m ast.Fn, name string) {
receiver := m.params[0]
data_styp := g.styp(receiver.typ.idx_type())
mut sb := strings.new_builder(256)
sb.write_string('${g.styp(m.return_type)} ${name}(')
for i in 1 .. m.params.len {
param := m.params[i]
if i != 1 {
sb.write_string(', ')
}
sb.write_string('${g.styp(param.typ)} a${i}')
}
sb.writeln(') {')
sb.writeln('\t${data_styp}* a0 = __CLOSURE_GET_DATA();')
if m.return_type != ast.void_type {
sb.write_string('\treturn ')
} else {
sb.write_string('\t')
}
mut method_name := m.name
rec_sym := g.table.sym(receiver.typ)
if rec_sym.info is ast.Struct {
if rec_sym.info.concrete_types.len > 0 {
method_name = g.generic_fn_name(rec_sym.info.concrete_types, m.name)
}
}
if rec_sym.info is ast.Interface {
left_cc_type := g.cc_type(g.table.unaliased_type(receiver.typ), false)
left_type_name := util.no_dots(left_cc_type)
sb.write_string('${c_name(left_type_name)}_name_table[a0->_typ]._method_${method_name}(')
} else {
sb.write_string('${expr_styp}_${method_name}(')
if !receiver.typ.is_ptr() {
sb.write_string('*')
}
}
for i in 0 .. m.params.len {
if i != 0 {
sb.write_string(', ')
}
sb.write_string('a${i}')
}
sb.writeln(');')
sb.writeln('}')
g.anon_fn_definitions << sb.str()
g.nr_closures++
}
fn (mut g Gen) write_selector_expr_embed_name(node ast.SelectorExpr, embed_types []ast.Type) { fn (mut g Gen) write_selector_expr_embed_name(node ast.SelectorExpr, embed_types []ast.Type) {
for i, embed in embed_types { for i, embed in embed_types {
embed_sym := g.table.sym(embed) embed_sym := g.table.sym(embed)
@ -4261,7 +4274,7 @@ fn (mut g Gen) debugger_stmt(node ast.DebuggerStmt) {
if obj is ast.Var && g.check_var_scope(obj, node.pos.pos) { if obj is ast.Var && g.check_var_scope(obj, node.pos.pos) {
keys.write_string('_SLIT("${obj.name}")') keys.write_string('_SLIT("${obj.name}")')
var_typ := if obj.ct_type_var != .no_comptime { var_typ := if obj.ct_type_var != .no_comptime {
g.comptime.get_comptime_var_type(ast.Ident{ obj: obj }) g.comptime.get_type(ast.Ident{ obj: obj })
} else if obj.smartcasts.len > 0 { } else if obj.smartcasts.len > 0 {
obj.smartcasts.last() obj.smartcasts.last()
} else { } else {
@ -4858,7 +4871,7 @@ fn (mut g Gen) ident(node ast.Ident) {
if node.obj is ast.Var { if node.obj is ast.Var {
if !g.is_assign_lhs if !g.is_assign_lhs
&& node.obj.ct_type_var !in [.smartcast, .generic_param, .no_comptime] { && node.obj.ct_type_var !in [.smartcast, .generic_param, .no_comptime] {
comptime_type := g.comptime.get_comptime_var_type(node) comptime_type := g.comptime.get_type(node)
if comptime_type.has_flag(.option) { if comptime_type.has_flag(.option) {
if (g.inside_opt_or_res || g.left_is_opt) && node.or_expr.kind == .absent { if (g.inside_opt_or_res || g.left_is_opt) && node.or_expr.kind == .absent {
if !g.is_assign_lhs && is_auto_heap { if !g.is_assign_lhs && is_auto_heap {
@ -4875,9 +4888,13 @@ fn (mut g Gen) ident(node ast.Ident) {
g.write('(*(${styp}*)${name}.data)') g.write('(*(${styp}*)${name}.data)')
} }
} }
} else {
if is_auto_heap {
g.write2('*', name)
} else { } else {
g.write(name) g.write(name)
} }
}
if node.or_expr.kind != .absent && !(g.inside_opt_or_res && g.inside_assign if node.or_expr.kind != .absent && !(g.inside_opt_or_res && g.inside_assign
&& !g.is_assign_lhs) { && !g.is_assign_lhs) {
stmt_str := g.go_before_last_stmt().trim_space() stmt_str := g.go_before_last_stmt().trim_space()
@ -4944,7 +4961,7 @@ fn (mut g Gen) ident(node ast.Ident) {
if node.obj.smartcasts.len > 0 { if node.obj.smartcasts.len > 0 {
obj_sym := g.table.sym(g.unwrap_generic(node.obj.typ)) obj_sym := g.table.sym(g.unwrap_generic(node.obj.typ))
if node.obj.ct_type_var == .smartcast { if node.obj.ct_type_var == .smartcast {
ctyp := g.unwrap_generic(g.comptime.get_comptime_var_type(node)) ctyp := g.unwrap_generic(g.comptime.get_type(node))
cur_variant_sym := g.table.sym(ctyp) cur_variant_sym := g.table.sym(ctyp)
variant_name := g.get_sumtype_variant_name(ctyp, cur_variant_sym) variant_name := g.get_sumtype_variant_name(ctyp, cur_variant_sym)
g.write('._${variant_name}') g.write('._${variant_name}')
@ -4980,7 +4997,7 @@ fn (mut g Gen) ident(node ast.Ident) {
is_option_unwrap := is_option && typ == node.obj.typ.clear_flag(.option) is_option_unwrap := is_option && typ == node.obj.typ.clear_flag(.option)
g.write('(') g.write('(')
if i == 0 && node.obj.is_unwrapped { if i == 0 && node.obj.is_unwrapped {
ctyp := g.unwrap_generic(g.comptime.get_comptime_var_type(node)) ctyp := g.unwrap_generic(g.comptime.get_type(node))
g.write('*(${g.base_type(ctyp)}*)(') g.write('*(${g.base_type(ctyp)}*)(')
} }
if obj_sym.kind == .sum_type && !is_auto_heap { if obj_sym.kind == .sum_type && !is_auto_heap {
@ -5036,7 +5053,7 @@ fn (mut g Gen) ident(node ast.Ident) {
} }
} }
if node.obj.ct_type_var == .smartcast { if node.obj.ct_type_var == .smartcast {
mut ctyp := g.unwrap_generic(g.comptime.get_comptime_var_type(node)) mut ctyp := g.unwrap_generic(g.comptime.get_type(node))
cur_variant_sym := g.table.sym(ctyp) cur_variant_sym := g.table.sym(ctyp)
if node.obj.is_unwrapped { if node.obj.is_unwrapped {
ctyp = ctyp.set_flag(.option) ctyp = ctyp.set_flag(.option)
@ -5111,9 +5128,8 @@ fn (mut g Gen) cast_expr(node ast.CastExpr) {
node_typ := g.unwrap_generic(node.typ) node_typ := g.unwrap_generic(node.typ)
mut expr_type := node.expr_type mut expr_type := node.expr_type
sym := g.table.sym(node_typ) sym := g.table.sym(node_typ)
if (node.expr is ast.Ident && g.comptime.is_comptime_var(node.expr)) if g.comptime.is_comptime_expr(node.expr) {
|| node.expr is ast.ComptimeSelector { expr_type = g.unwrap_generic(g.comptime.get_type(node.expr))
expr_type = g.unwrap_generic(g.comptime.get_comptime_var_type(node.expr))
} }
if sym.kind in [.sum_type, .interface] { if sym.kind in [.sum_type, .interface] {
if node.typ.has_flag(.option) && node.expr is ast.None { if node.typ.has_flag(.option) && node.expr is ast.None {

View File

@ -460,7 +460,7 @@ fn (mut g Gen) get_expr_type(cond ast.Expr) ast.Type {
match cond { match cond {
ast.Ident { ast.Ident {
return if g.comptime.is_comptime_var(cond) { return if g.comptime.is_comptime_var(cond) {
g.unwrap_generic(g.comptime.get_comptime_var_type(cond)) g.unwrap_generic(g.comptime.get_type(cond))
} else { } else {
g.unwrap_generic(cond.obj.typ) g.unwrap_generic(cond.obj.typ)
} }
@ -800,8 +800,8 @@ fn (mut g Gen) pop_comptime_info() {
} }
fn (mut g Gen) resolve_comptime_type(node ast.Expr, default_type ast.Type) ast.Type { fn (mut g Gen) resolve_comptime_type(node ast.Expr, default_type ast.Type) ast.Type {
if (node is ast.Ident && g.comptime.is_comptime_var(node)) || node is ast.ComptimeSelector { if g.comptime.is_comptime_expr(node) {
return g.comptime.get_comptime_var_type(node) return g.comptime.get_type(node)
} else if node is ast.SelectorExpr && node.expr_type != 0 { } else if node is ast.SelectorExpr && node.expr_type != 0 {
if node.expr is ast.Ident && g.comptime.is_comptime_selector_type(node) { if node.expr is ast.Ident && g.comptime.is_comptime_selector_type(node) {
return g.comptime.get_type_from_comptime_var(node.expr) return g.comptime.get_type_from_comptime_var(node.expr)
@ -1062,6 +1062,100 @@ fn (mut g Gen) comptime_for(node ast.ComptimeFor) {
g.writeln('}// \$for') g.writeln('}// \$for')
} }
// comptime_selector_type computes the selector type from an comptime var
fn (mut g Gen) comptime_selector_type(node ast.SelectorExpr) ast.Type {
if !(node.expr is ast.Ident && g.comptime.is_comptime_var(node.expr)) {
return node.expr_type
}
prevent_sum_type_unwrapping_once := g.prevent_sum_type_unwrapping_once
g.prevent_sum_type_unwrapping_once = false
mut typ := g.comptime.get_type(node.expr)
if node.expr.is_auto_deref_var() {
if node.expr is ast.Ident {
if node.expr.obj is ast.Var {
typ = node.expr.obj.typ
}
}
}
if g.comptime.inside_comptime_for && typ == g.enum_data_type && node.field_name == 'value' {
// for comp-time enum.values
return g.comptime.type_map['${g.comptime.comptime_for_enum_var}.typ']
}
field_name := node.field_name
sym := g.table.sym(typ)
final_sym := g.table.final_sym(typ)
if (typ.has_flag(.variadic) || final_sym.kind == .array_fixed) && field_name == 'len' {
return ast.int_type
}
if sym.kind == .chan {
if field_name == 'closed' {
return ast.bool_type
} else if field_name in ['len', 'cap'] {
return ast.u32_type
}
}
mut has_field := false
mut field := ast.StructField{}
if field_name.len > 0 && field_name[0].is_capital() && sym.info is ast.Struct
&& sym.language == .v {
// x.Foo.y => access the embedded struct
for embed in sym.info.embeds {
embed_sym := g.table.sym(embed)
if embed_sym.embed_name() == field_name {
return embed
}
}
} else {
if f := g.table.find_field(sym, field_name) {
has_field = true
field = f
} else {
// look for embedded field
has_field = true
g.table.find_field_from_embeds(sym, field_name) or { has_field = false }
}
if typ.has_flag(.generic) && !has_field {
gs := g.table.sym(g.unwrap_generic(typ))
if f := g.table.find_field(gs, field_name) {
has_field = true
field = f
} else {
// look for embedded field
has_field = true
g.table.find_field_from_embeds(gs, field_name) or { has_field = false }
}
}
}
if has_field {
field_sym := g.table.sym(field.typ)
if field_sym.kind in [.sum_type, .interface] {
if !prevent_sum_type_unwrapping_once {
if scope_field := node.scope.find_struct_field(node.expr.str(), typ, field_name) {
return scope_field.smartcasts.last()
}
}
}
return field.typ
}
if mut method := g.table.sym(g.unwrap_generic(typ)).find_method_with_generic_parent(field_name) {
method.params = method.params[1..]
method.name = ''
fn_type := ast.new_type(g.table.find_or_register_fn_type(method, false, true))
return fn_type
}
if sym.kind !in [.struct, .aggregate, .interface, .sum_type] {
if sym.kind != .placeholder {
unwrapped_sym := g.table.sym(g.unwrap_generic(typ))
if unwrapped_sym.kind == .array_fixed && node.field_name == 'len' {
return ast.int_type
}
}
}
return node.expr_type
}
fn (mut g Gen) comptime_if_to_ifdef(name string, is_comptime_option bool) !string { fn (mut g Gen) comptime_if_to_ifdef(name string, is_comptime_option bool) !string {
match name { match name {
// platforms/os-es: // platforms/os-es:

View File

@ -44,9 +44,13 @@ fn (mut g Gen) dump_expr(node ast.DumpExpr) {
} }
} }
} }
} else if node.expr is ast.Ident && g.comptime.inside_comptime_for } else if node.expr is ast.Ident && g.comptime.is_comptime_var(node.expr) {
&& g.comptime.is_comptime_var(node.expr) { expr_type = g.comptime.get_type(node.expr)
expr_type = g.comptime.get_comptime_var_type(node.expr) name = g.styp(g.unwrap_generic(expr_type.clear_flags(.shared_f, .result))).replace('*',
'')
} else if node.expr is ast.SelectorExpr && node.expr.expr is ast.Ident
&& g.comptime.is_comptime_var(node.expr.expr) {
expr_type = g.comptime_selector_type(node.expr)
name = g.styp(g.unwrap_generic(expr_type.clear_flags(.shared_f, .result))).replace('*', name = g.styp(g.unwrap_generic(expr_type.clear_flags(.shared_f, .result))).replace('*',
'') '')
} }

View File

@ -1294,7 +1294,7 @@ fn (mut g Gen) gen_to_str_method_call(node ast.CallExpr) bool {
} else if left_node is ast.Ident { } else if left_node is ast.Ident {
if left_node.obj is ast.Var { if left_node.obj is ast.Var {
if left_node.obj.ct_type_var != .no_comptime { if left_node.obj.ct_type_var != .no_comptime {
rec_type = g.comptime.get_comptime_var_type(left_node) rec_type = g.comptime.get_type(left_node)
g.gen_expr_to_string(left_node, rec_type) g.gen_expr_to_string(left_node, rec_type)
return true return true
} else if left_node.obj.smartcasts.len > 0 { } else if left_node.obj.smartcasts.len > 0 {
@ -1456,7 +1456,7 @@ fn (mut g Gen) resolve_comptime_args(func &ast.Fn, mut node_ ast.CallExpr, concr
if mut call_arg.expr.obj is ast.Var { if mut call_arg.expr.obj is ast.Var {
node_.args[i].typ = call_arg.expr.obj.typ node_.args[i].typ = call_arg.expr.obj.typ
if call_arg.expr.obj.ct_type_var !in [.generic_var, .generic_param, .no_comptime] { if call_arg.expr.obj.ct_type_var !in [.generic_var, .generic_param, .no_comptime] {
mut ctyp := g.comptime.get_comptime_var_type(call_arg.expr) mut ctyp := g.comptime.get_type(call_arg.expr)
if ctyp != ast.void_type { if ctyp != ast.void_type {
arg_sym := g.table.sym(ctyp) arg_sym := g.table.sym(ctyp)
param_sym := g.table.final_sym(param_typ) param_sym := g.table.final_sym(param_typ)
@ -1490,7 +1490,7 @@ fn (mut g Gen) resolve_comptime_args(func &ast.Fn, mut node_ ast.CallExpr, concr
comptime_args[k] = ctyp comptime_args[k] = ctyp
} }
} else if call_arg.expr.obj.ct_type_var == .generic_param { } else if call_arg.expr.obj.ct_type_var == .generic_param {
mut ctyp := g.comptime.get_comptime_var_type(call_arg.expr) mut ctyp := g.comptime.get_type(call_arg.expr)
if ctyp != ast.void_type { if ctyp != ast.void_type {
arg_sym := g.table.final_sym(call_arg.typ) arg_sym := g.table.final_sym(call_arg.typ)
param_typ_sym := g.table.sym(param_typ) param_typ_sym := g.table.sym(param_typ)
@ -1561,7 +1561,7 @@ fn (mut g Gen) resolve_comptime_args(func &ast.Fn, mut node_ ast.CallExpr, concr
} }
} else if mut call_arg.expr.right is ast.Ident { } else if mut call_arg.expr.right is ast.Ident {
if g.comptime.get_ct_type_var(call_arg.expr.right) != .generic_var { if g.comptime.get_ct_type_var(call_arg.expr.right) != .generic_var {
mut ctyp := g.comptime.get_comptime_var_type(call_arg.expr.right) mut ctyp := g.comptime.get_type(call_arg.expr.right)
if ctyp != ast.void_type { if ctyp != ast.void_type {
comptime_args[k] = ctyp comptime_args[k] = ctyp
if param_typ.nr_muls() > 0 && comptime_args[k].nr_muls() > 0 { if param_typ.nr_muls() > 0 && comptime_args[k].nr_muls() > 0 {
@ -1658,7 +1658,7 @@ fn (mut g Gen) unwrap_receiver_type(node ast.CallExpr) (ast.Type, &ast.TypeSymbo
if node.left.obj is ast.Var { if node.left.obj is ast.Var {
if node.left.obj.smartcasts.len > 0 { if node.left.obj.smartcasts.len > 0 {
if node.left.obj.ct_type_var == .smartcast { if node.left.obj.ct_type_var == .smartcast {
unwrapped_rec_type = g.unwrap_generic(g.comptime.get_comptime_var_type(node.left)) unwrapped_rec_type = g.unwrap_generic(g.comptime.get_type(node.left))
} else { } else {
unwrapped_rec_type = g.unwrap_generic(node.left.obj.smartcasts.last()) unwrapped_rec_type = g.unwrap_generic(node.left.obj.smartcasts.last())
cast_sym := g.table.sym(unwrapped_rec_type) cast_sym := g.table.sym(unwrapped_rec_type)
@ -2171,7 +2171,7 @@ fn (mut g Gen) fn_call(node ast.CallExpr) {
} }
mut typ := node.args[0].typ mut typ := node.args[0].typ
if g.comptime.is_comptime_var(node.args[0].expr) { if g.comptime.is_comptime_var(node.args[0].expr) {
ctyp := g.comptime.get_comptime_var_type(node.args[0].expr) ctyp := g.comptime.get_type(node.args[0].expr)
if ctyp != ast.void_type { if ctyp != ast.void_type {
typ = ctyp typ = ctyp
} }
@ -2223,7 +2223,7 @@ fn (mut g Gen) fn_call(node ast.CallExpr) {
if cast_sym.info is ast.Aggregate { if cast_sym.info is ast.Aggregate {
typ = cast_sym.info.types[g.aggregate_type_idx] typ = cast_sym.info.types[g.aggregate_type_idx]
} else if expr.obj.ct_type_var == .smartcast { } else if expr.obj.ct_type_var == .smartcast {
typ = g.unwrap_generic(g.comptime.get_comptime_var_type(expr)) typ = g.unwrap_generic(g.comptime.get_type(expr))
} }
} }
// handling println( var or { ... }) // handling println( var or { ... })
@ -2575,7 +2575,7 @@ fn (mut g Gen) call_args(node ast.CallExpr) {
if i < node.expected_arg_types.len && node.expected_arg_types[i].has_flag(.generic) if i < node.expected_arg_types.len && node.expected_arg_types[i].has_flag(.generic)
&& arg.expr.obj.ct_type_var !in [.generic_param, .no_comptime] { && arg.expr.obj.ct_type_var !in [.generic_param, .no_comptime] {
exp_option := node.expected_arg_types[i].has_flag(.option) exp_option := node.expected_arg_types[i].has_flag(.option)
expected_types[i] = g.unwrap_generic(g.comptime.get_comptime_var_type(arg.expr)) expected_types[i] = g.unwrap_generic(g.comptime.get_type(arg.expr))
if !exp_option { if !exp_option {
expected_types[i] = expected_types[i].clear_flag(.option) expected_types[i] = expected_types[i].clear_flag(.option)
} }
@ -2609,7 +2609,7 @@ fn (mut g Gen) call_args(node ast.CallExpr) {
} else if arg.expr is ast.ComptimeSelector && i < node.expected_arg_types.len } else if arg.expr is ast.ComptimeSelector && i < node.expected_arg_types.len
&& node.expected_arg_types[i].has_flag(.generic) { && node.expected_arg_types[i].has_flag(.generic) {
exp_option := node.expected_arg_types[i].has_flag(.option) exp_option := node.expected_arg_types[i].has_flag(.option)
expected_types[i] = g.unwrap_generic(g.comptime.get_comptime_var_type(arg.expr)) expected_types[i] = g.unwrap_generic(g.comptime.get_type(arg.expr))
if !exp_option { if !exp_option {
expected_types[i] = expected_types[i].clear_flag(.option) expected_types[i] = expected_types[i].clear_flag(.option)
} }
@ -2776,7 +2776,7 @@ fn (mut g Gen) keep_alive_call_postgen(node ast.CallExpr, tmp_cnt_save int) {
@[inline] @[inline]
fn (mut g Gen) ref_or_deref_arg(arg ast.CallArg, expected_type ast.Type, lang ast.Language, is_smartcast bool) { fn (mut g Gen) ref_or_deref_arg(arg ast.CallArg, expected_type ast.Type, lang ast.Language, is_smartcast bool) {
arg_typ := if arg.expr is ast.ComptimeSelector { arg_typ := if arg.expr is ast.ComptimeSelector {
g.unwrap_generic(g.comptime.get_comptime_var_type(arg.expr)) g.unwrap_generic(g.comptime.get_type(arg.expr))
} else { } else {
g.unwrap_generic(arg.typ) g.unwrap_generic(arg.typ)
} }

View File

@ -144,7 +144,7 @@ fn (mut g Gen) for_in_stmt(node_ ast.ForInStmt) {
if (node.cond is ast.Ident && g.comptime.is_comptime_var(node.cond)) if (node.cond is ast.Ident && g.comptime.is_comptime_var(node.cond))
|| node.cond is ast.ComptimeSelector { || node.cond is ast.ComptimeSelector {
mut unwrapped_typ := g.unwrap_generic(node.cond_type) mut unwrapped_typ := g.unwrap_generic(node.cond_type)
ctyp := g.comptime.get_comptime_var_type(node.cond) ctyp := g.comptime.get_type(node.cond)
if ctyp != ast.void_type { if ctyp != ast.void_type {
unwrapped_typ = g.unwrap_generic(ctyp) unwrapped_typ = g.unwrap_generic(ctyp)
is_comptime = true is_comptime = true
@ -223,7 +223,7 @@ fn (mut g Gen) for_in_stmt(node_ ast.ForInStmt) {
if is_comptime && g.comptime.is_comptime_var(node.cond) { if is_comptime && g.comptime.is_comptime_var(node.cond) {
mut unwrapped_typ := g.unwrap_generic(node.cond_type) mut unwrapped_typ := g.unwrap_generic(node.cond_type)
ctyp := g.unwrap_generic(g.comptime.get_comptime_var_type(node.cond)) ctyp := g.unwrap_generic(g.comptime.get_type(node.cond))
if ctyp != ast.void_type { if ctyp != ast.void_type {
unwrapped_typ = ctyp unwrapped_typ = ctyp
} }

View File

@ -96,13 +96,13 @@ fn (mut g Gen) infix_expr_arrow_op(node ast.InfixExpr) {
// infix_expr_eq_op generates code for `==` and `!=` // infix_expr_eq_op generates code for `==` and `!=`
fn (mut g Gen) infix_expr_eq_op(node ast.InfixExpr) { fn (mut g Gen) infix_expr_eq_op(node ast.InfixExpr) {
left_type := if node.left is ast.ComptimeSelector { left_type := if g.comptime.is_comptime_expr(node.left) {
g.comptime.get_comptime_var_type(node.left) g.comptime.get_expr_type(node.left)
} else { } else {
node.left_type node.left_type
} }
right_type := if node.right is ast.ComptimeSelector { right_type := if g.comptime.is_comptime_expr(node.right) {
g.comptime.get_comptime_var_type(node.right) g.comptime.get_expr_type(node.right)
} else { } else {
node.right_type node.right_type
} }
@ -796,7 +796,7 @@ fn (mut g Gen) infix_expr_in_optimization(left ast.Expr, left_type ast.Type, rig
// infix_expr_is_op generates code for `is` and `!is` // infix_expr_is_op generates code for `is` and `!is`
fn (mut g Gen) infix_expr_is_op(node ast.InfixExpr) { fn (mut g Gen) infix_expr_is_op(node ast.InfixExpr) {
mut left_sym := if g.comptime.is_comptime_var(node.left) { mut left_sym := if g.comptime.is_comptime_var(node.left) {
g.table.sym(g.unwrap_generic(g.comptime.get_comptime_var_type(node.left))) g.table.sym(g.unwrap_generic(g.comptime.get_type(node.left)))
} else { } else {
g.table.sym(node.left_type) g.table.sym(node.left_type)
} }

View File

@ -191,7 +191,7 @@ fn (mut g Gen) str_val(node ast.StringInterLiteral, i int, fmts []u8) {
mut exp_typ := typ mut exp_typ := typ
if expr is ast.Ident { if expr is ast.Ident {
if g.comptime.get_ct_type_var(expr) == .smartcast { if g.comptime.get_ct_type_var(expr) == .smartcast {
exp_typ = g.comptime.get_comptime_var_type(expr) exp_typ = g.comptime.get_type(expr)
} else if expr.obj is ast.Var { } else if expr.obj is ast.Var {
if expr.obj.smartcasts.len > 0 { if expr.obj.smartcasts.len > 0 {
exp_typ = g.unwrap_generic(expr.obj.smartcasts.last()) exp_typ = g.unwrap_generic(expr.obj.smartcasts.last())
@ -245,7 +245,7 @@ fn (mut g Gen) string_inter_literal(node ast.StringInterLiteral) {
mut fmts := node_.fmts.clone() mut fmts := node_.fmts.clone()
for i, mut expr in node_.exprs { for i, mut expr in node_.exprs {
if g.comptime.is_comptime_var(expr) { if g.comptime.is_comptime_var(expr) {
ctyp := g.comptime.get_comptime_var_type(expr) ctyp := g.comptime.get_type(expr)
if ctyp != ast.void_type { if ctyp != ast.void_type {
node_.expr_types[i] = ctyp node_.expr_types[i] = ctyp
if node_.fmts[i] == `_` { if node_.fmts[i] == `_` {

View File

@ -53,6 +53,7 @@ fn (mut g Gen) struct_init(node ast.StructInit) {
if mut sym.info is ast.Struct { if mut sym.info is ast.Struct {
is_anon = sym.info.is_anon is_anon = sym.info.is_anon
} }
is_generic_default := sym.kind !in [.struct, .array_fixed] && node.typ.has_flag(.generic) // T{}
is_array := sym.kind in [.array_fixed, .array] is_array := sym.kind in [.array_fixed, .array]
if sym.kind == .array_fixed { if sym.kind == .array_fixed {
arr_info := sym.array_fixed_info() arr_info := sym.array_fixed_info()
@ -63,7 +64,7 @@ fn (mut g Gen) struct_init(node ast.StructInit) {
// detect if we need type casting on msvc initialization // detect if we need type casting on msvc initialization
const_msvc_init := g.is_cc_msvc && g.inside_const && !g.inside_cast && g.inside_array_item const_msvc_init := g.is_cc_msvc && g.inside_const && !g.inside_cast && g.inside_array_item
if !g.inside_cinit && !is_anon && !is_array && !const_msvc_init { if !g.inside_cinit && !is_anon && !is_generic_default && !is_array && !const_msvc_init {
g.write('(') g.write('(')
defer { defer {
g.write(')') g.write(')')
@ -128,6 +129,8 @@ fn (mut g Gen) struct_init(node ast.StructInit) {
} }
} else if is_multiline { } else if is_multiline {
g.writeln('(${styp}){') g.writeln('(${styp}){')
} else if is_generic_default {
g.write(g.type_default(node.typ))
} else { } else {
g.write('(${styp}){') g.write('(${styp}){')
} }
@ -356,7 +359,7 @@ fn (mut g Gen) struct_init(node ast.StructInit) {
g.indent-- g.indent--
} }
if !initialized { if !initialized && !is_generic_default {
if nr_fields > 0 { if nr_fields > 0 {
g.write('0') g.write('0')
} else { } else {
@ -364,7 +367,7 @@ fn (mut g Gen) struct_init(node ast.StructInit) {
} }
} }
if !is_array_fixed_struct_init { if !is_array_fixed_struct_init && !is_generic_default {
g.write('}') g.write('}')
} }
if g.is_shared && !g.inside_opt_data && !g.is_arraymap_set { if g.is_shared && !g.inside_opt_data && !g.is_arraymap_set {

View File

@ -0,0 +1,56 @@
module main
struct Decoder {
json string
}
pub fn decode[T](val string) !T {
mut decoder := Decoder{
json: val
}
mut result := T{}
decoder.decode_value(mut &result)!
return result
}
fn (mut decoder Decoder) decode_value[T](mut val T) ! {
$if T.unaliased_typ is $array {
mut array_element := create_array_element(val)
decoder.decode_value(mut array_element)!
val << array_element
assert val.len == 1
assert val[0] == array_element
} $else $if T.unaliased_typ is $map {
mut map_value := create_map_value(val)
decoder.decode_value(mut map_value)!
val['key'] = map_value
assert val.len == 1
assert val['key'] == map_value
}
}
fn create_array_element[T](array []T) T {
return T{}
}
fn create_map_value[K, V](map_ map[K]V) V {
return V{}
}
fn test_main() {
assert decode[[]int]('[1, 2, 3]')! == [0]
assert decode[[]string]('["1", "2", "3"]')! == ['']
assert decode[map[string]int]('{"a": 1}')! == {
'key': 0
}
assert decode[map[string]string]('{"val": "2"}')! == {
'key': ''
}
}

View File

@ -0,0 +1,64 @@
module main
struct Decoder {
json string
}
pub fn decode[T](val string) !T {
mut decoder := Decoder{
json: val
}
mut result := T{}
decoder.decode_value(mut &result)!
return result
}
fn (mut decoder Decoder) decode_value[T](mut val T) ! {
$if T is $array {
mut array_element := create_array_element(val)
decoder.decode_value(mut array_element)!
println(array_element)
dump(array_element)
assert &array_element != unsafe { nil }
val << array_element
} $else $if T is $map {
mut map_value := create_map_value(val)
decoder.decode_value(mut map_value)!
println(map_value)
dump(map_value)
assert &map_value != unsafe { nil }
val['key'] = map_value
}
}
fn create_array_element[T](array []T) T {
a := T{}
dump(a)
dump(a.str)
assert a.str != unsafe { nil }
return a
}
fn create_map_value[K, V](map_ map[K]V) V {
a := V{}
dump(a)
dump(a.str)
assert a.str != unsafe { nil }
return a
}
fn test_main() {
assert decode[[]string]('["1", "2", "3"]')! == ['']
assert decode[[]int]('[1, 2, 3]')! == [0]
assert decode[map[string]string]('{"val": "2"}')! == {
'key': ''
}
assert decode[map[string]int]('{"a": 1}')! == {
'key': 0
}
}