diff --git a/vlib/v/depgraph/depgraph.v b/vlib/v/depgraph/depgraph.v index 7bb0aa12f1..e6da662b4a 100644 --- a/vlib/v/depgraph/depgraph.v +++ b/vlib/v/depgraph/depgraph.v @@ -9,14 +9,16 @@ import v.dotgraph struct DepGraphNode { pub mut: - name string - deps []string + name string + value i64 + deps []string } struct DepGraph { pub mut: acyclic bool nodes []DepGraphNode + values map[string]i64 } struct OrderedDepMap { @@ -43,7 +45,6 @@ pub fn (mut o OrderedDepMap) add(name string, deps []string) { for dep in deps { if dep !in d { d << dep - } else { } } o.set(name, d) @@ -95,6 +96,17 @@ pub fn (mut graph DepGraph) add(mod string, deps []string) { deps: deps.clone() } graph.nodes << new_node + graph.values[mod] = 0 +} + +pub fn (mut graph DepGraph) add_with_value(mod string, deps []string, value i64) { + new_node := DepGraphNode{ + name: mod + value: value + deps: deps.clone() + } + graph.nodes << new_node + graph.values[mod] = value } pub fn (graph &DepGraph) resolve() &DepGraph { @@ -119,14 +131,14 @@ pub fn (graph &DepGraph) resolve() &DepGraph { mut g := new_dep_graph() g.acyclic = false for name in node_deps.keys { - g.add(name, node_names.get(name)) + g.add_with_value(name, node_names.get(name), graph.values[name]) } return g } for name in ready_set { node_deps.delete(name) resolved_deps := node_names.get(name) - resolved.add(name, resolved_deps) + resolved.add_with_value(name, resolved_deps, graph.values[name]) } for name in node_deps.keys { node_deps.apply_diff(name, ready_set) diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index 0502aab411..2fe852f659 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -61,10 +61,6 @@ mut: hotcode_definitions strings.Builder // -live declarations & functions channel_definitions strings.Builder // channel related code comptime_definitions strings.Builder // custom defines, given by -d/-define flags on the CLI - global_inits map[string]strings.Builder // default initializers for globals (goes in _vinit()) - global_init strings.Builder // thread local of the above - inits map[string]strings.Builder // contents of `void _vinit/2{}` - init strings.Builder cleanup strings.Builder cleanups map[string]strings.Builder // contents of `void _vcleanup(){}` gowrappers strings.Builder // all go callsite wrappers @@ -79,6 +75,8 @@ mut: out_results strings.Builder // `result_xxxx` types json_forward_decls strings.Builder // json type forward decls sql_buf strings.Builder // for writing exprs to args via `sqlite3_bind_int()` etc + global_const_defs map[string]GlobalConstDef + sorted_global_const_names []string file &ast.File unique_file_path_hash u64 // a hash of file.path, used for making auxilary fn generation unique (like `compare_xyz`) fn_decl &ast.FnDecl // pointer to the FnDecl we are currently inside otherwise 0 @@ -215,6 +213,15 @@ mut: use_segfault_handler bool = true } +// global or const variable definition string +struct GlobalConstDef { + mod string // module name + def string // definition + init string // init later (in _vinit) + dep_names []string // the names of all the consts, that this const depends on + order int // -1 for simple defines, string literals, anonymous function names, extern declarations etc +} + pub fn gen(files []&ast.File, table &ast.Table, pref &pref.Preferences) string { // println('start cgen2') mut module_built := '' @@ -245,7 +252,6 @@ pub fn gen(files []&ast.File, table &ast.Table, pref &pref.Preferences) string { comptime_definitions: strings.new_builder(100) definitions: strings.new_builder(100) gowrappers: strings.new_builder(100) - stringliterals: strings.new_builder(100) auto_str_funcs: strings.new_builder(100) dump_funcs: strings.new_builder(100) pcs_declarations: strings.new_builder(100) @@ -266,7 +272,6 @@ pub fn gen(files []&ast.File, table &ast.Table, pref &pref.Preferences) string { timers: util.new_timers(should_print: timers_should_print, label: 'global_cgen') inner_loop: &ast.EmptyStmt{} field_data_type: ast.Type(table.find_type_idx('FieldData')) - init: strings.new_builder(100) is_cc_msvc: pref.ccompiler == 'msvc' use_segfault_handler: !('no_segfault_handler' in pref.compile_defines || pref.os == .wasm32) } @@ -278,8 +283,6 @@ pub fn gen(files []&ast.File, table &ast.Table, pref &pref.Preferences) string { global_g.timers.start('cgen init') for mod in global_g.table.modules { - global_g.inits[mod] = strings.new_builder(200) - global_g.global_inits[mod] = strings.new_builder(100) global_g.cleanups[mod] = strings.new_builder(100) } global_g.init() @@ -315,6 +318,9 @@ pub fn gen(files []&ast.File, table &ast.Table, pref &pref.Preferences) string { global_g.force_main_console = global_g.force_main_console || g.force_main_console // merge maps + for k, v in g.global_const_defs { + global_g.global_const_defs[k] = v + } for k, v in g.shareds { global_g.shareds[k] = v } @@ -342,8 +348,6 @@ pub fn gen(files []&ast.File, table &ast.Table, pref &pref.Preferences) string { global_g.sql_buf.write(g.sql_buf) or { panic(err) } global_g.cleanups[g.file.mod.name].write(g.cleanup) or { panic(err) } // strings.Builder.write never fails; it is like that in the source - global_g.inits[g.file.mod.name].write(g.init) or { panic(err) } - global_g.global_inits[g.file.mod.name].write(g.global_init) or { panic(err) } for str_type in g.str_types { global_g.str_types << str_type @@ -374,10 +378,7 @@ pub fn gen(files []&ast.File, table &ast.Table, pref &pref.Preferences) string { for file in files { global_g.file = file global_g.gen_file() - global_g.inits[file.mod.name].drain_builder(mut global_g.init, 100) global_g.cleanups[file.mod.name].drain_builder(mut global_g.cleanup, 100) - global_g.global_inits[file.mod.name].drain_builder(mut global_g.global_init, - 100) } global_g.timers.start('cgen unification') } @@ -399,6 +400,7 @@ pub fn gen(files []&ast.File, table &ast.Table, pref &pref.Preferences) string { global_g.gen_array_index_methods() global_g.gen_equality_fns() global_g.gen_free_methods() + global_g.sort_globals_consts() global_g.timers.show('cgen unification') mut g := global_g @@ -462,6 +464,12 @@ pub fn gen(files []&ast.File, table &ast.Table, pref &pref.Preferences) string { b.write_string(g.json_forward_decls.str()) b.writeln('\n// V definitions:') b.write_string(g.definitions.str()) + b.writeln('\n// V global/const definitions:') + for var_name in g.sorted_global_const_names { + if var := g.global_const_defs[var_name] { + b.writeln(var.def) + } + } interface_table := g.interface_table() if interface_table.len > 0 { b.writeln('\n// V interface table:') @@ -545,7 +553,6 @@ fn cgen_process_one_file_cb(p &pool.PoolProcessor, idx int, wid int) &Gen { alias_definitions: strings.new_builder(100) definitions: strings.new_builder(100) gowrappers: strings.new_builder(100) - stringliterals: strings.new_builder(100) auto_str_funcs: strings.new_builder(100) comptime_definitions: strings.new_builder(100) pcs_declarations: strings.new_builder(100) @@ -559,8 +566,6 @@ fn cgen_process_one_file_cb(p &pool.PoolProcessor, idx int, wid int) &Gen { json_forward_decls: strings.new_builder(100) enum_typedefs: strings.new_builder(100) sql_buf: strings.new_builder(100) - init: strings.new_builder(100) - global_init: strings.new_builder(0) cleanup: strings.new_builder(100) table: global_g.table pref: global_g.pref @@ -599,8 +604,6 @@ pub fn (mut g Gen) free_builders() { g.type_definitions.free() g.alias_definitions.free() g.definitions.free() - g.global_init.free() - g.init.free() g.cleanup.free() g.gowrappers.free() g.stringliterals.free() @@ -618,12 +621,6 @@ pub fn (mut g Gen) free_builders() { g.json_forward_decls.free() g.enum_typedefs.free() g.sql_buf.free() - for _, mut v in g.global_inits { - v.free() - } - for _, mut v in g.inits { - v.free() - } for _, mut v in g.cleanups { v.free() } @@ -707,14 +704,6 @@ pub fn (mut g Gen) init() { g.write_sorted_types() g.write_multi_return_types() g.definitions.writeln('// end of definitions #endif') - // - if !g.pref.no_builtin { - g.stringliterals.writeln('') - g.stringliterals.writeln('// >> string literal consts') - if g.pref.build_mode != .build_module { - g.stringliterals.writeln('void vinit_string_literals(void){') - } - } if g.pref.compile_defines_all.len > 0 { g.comptime_definitions.writeln('// V compile time defines by -d or -define flags:') g.comptime_definitions.writeln('// All custom defines : ' + @@ -796,13 +785,6 @@ pub fn (mut g Gen) init() { } pub fn (mut g Gen) finish() { - if !g.pref.no_builtin { - if g.pref.build_mode != .build_module { - g.stringliterals.writeln('}') - } - g.stringliterals.writeln('// << string literal consts') - g.stringliterals.writeln('') - } if g.pref.is_prof && g.pref.build_mode != .build_module { g.gen_vprint_profile_stats() } @@ -4383,6 +4365,44 @@ fn (mut g Gen) return_stmt(node ast.Return) { } } +fn (mut g Gen) dependent_var_names(expr ast.Expr) []string { + mut vars := []string{} + match expr { + ast.Ident { + if expr.kind in [.global, .constant] { + vars << util.no_dots(expr.name) + } + } + ast.ArrayInit { + for elem_expr in expr.exprs { + vars << g.dependent_var_names(elem_expr) + } + } + ast.StructInit { + for field in expr.fields { + vars << g.dependent_var_names(field.expr) + } + } + ast.InfixExpr { + vars << g.dependent_var_names(expr.left) + vars << g.dependent_var_names(expr.right) + } + ast.PostfixExpr { + vars << g.dependent_var_names(expr.expr) + } + ast.PrefixExpr { + vars << g.dependent_var_names(expr.right) + } + ast.CallExpr { + for arg in expr.args { + vars << g.dependent_var_names(arg.expr) + } + } + else {} + } + return vars +} + fn (mut g Gen) const_decl(node ast.ConstDecl) { g.inside_const = true defer { @@ -4409,21 +4429,23 @@ fn (mut g Gen) const_decl(node ast.ConstDecl) { ast.ArrayInit { if field.expr.is_fixed { styp := g.typ(field.expr.typ) - if g.pref.build_mode != .build_module { - val := g.expr_string(field.expr) - g.definitions.writeln('$styp $const_name = $val; // fixed array const') - } else { - g.definitions.writeln('$styp $const_name; // fixed array const') + val := g.expr_string(field.expr) + g.global_const_defs[util.no_dots(field.name)] = GlobalConstDef{ + mod: field.mod + def: '$styp $const_name = $val; // fixed array const' + dep_names: g.dependent_var_names(field_expr) } } else { g.const_decl_init_later(field.mod, name, field.expr, field.typ, false) } } ast.StringLiteral { - g.definitions.writeln('string $const_name; // a string literal, inited later') - if g.pref.build_mode != .build_module { - val := g.expr_string(field.expr) - g.stringliterals.writeln('\t$const_name = $val;') + val := g.expr_string(field.expr) + g.global_const_defs[util.no_dots(field.name)] = GlobalConstDef{ + mod: field.mod + def: 'string $const_name; // a string literal, inited later' + init: '\t$const_name = $val;' + order: -1 } } ast.CallExpr { @@ -4450,7 +4472,9 @@ fn (mut g Gen) const_decl(node ast.ConstDecl) { use_cache_mode := g.pref.build_mode == .build_module || g.pref.use_cache if !use_cache_mode { if ct_value := field.comptime_expr_value() { - if g.const_decl_precomputed(field.mod, name, ct_value, field.typ) { + if g.const_decl_precomputed(field.mod, name, field.name, ct_value, + field.typ) + { continue } } @@ -4458,7 +4482,7 @@ fn (mut g Gen) const_decl(node ast.ConstDecl) { if field.is_simple_define_const() { // "Simple" expressions are not going to need multiple statements, // only the ones which are inited later, so it's safe to use expr_string - g.const_decl_simple_define(field.name, g.expr_string(field_expr)) + g.const_decl_simple_define(field.mod, field.name, g.expr_string(field_expr)) } else { g.const_decl_init_later(field.mod, name, field.expr, field.typ, false) } @@ -4467,7 +4491,7 @@ fn (mut g Gen) const_decl(node ast.ConstDecl) { } } -fn (mut g Gen) const_decl_precomputed(mod string, name string, ct_value ast.ComptTimeConstValue, typ ast.Type) bool { +fn (mut g Gen) const_decl_precomputed(mod string, name string, field_name string, ct_value ast.ComptTimeConstValue, typ ast.Type) bool { mut styp := g.typ(typ) cname := if g.pref.translated && !g.is_builtin_mod { name } else { '_const_$name' } $if trace_const_precomputed ? { @@ -4475,13 +4499,13 @@ fn (mut g Gen) const_decl_precomputed(mod string, name string, ct_value ast.Comp } match ct_value { i8 { - g.const_decl_write_precomputed(styp, cname, ct_value.str()) + g.const_decl_write_precomputed(mod, styp, cname, field_name, ct_value.str()) } i16 { - g.const_decl_write_precomputed(styp, cname, ct_value.str()) + g.const_decl_write_precomputed(mod, styp, cname, field_name, ct_value.str()) } int { - g.const_decl_write_precomputed(styp, cname, ct_value.str()) + g.const_decl_write_precomputed(mod, styp, cname, field_name, ct_value.str()) } i64 { if typ == ast.i64_type { @@ -4493,32 +4517,32 @@ fn (mut g Gen) const_decl_precomputed(mod string, name string, ct_value ast.Comp // with -cstrict. Add checker errors for overflows instead, // so V can catch them earlier, instead of relying on the // C compiler for that. - g.const_decl_simple_define(name, ct_value.str()) + g.const_decl_simple_define(mod, name, ct_value.str()) return true } if typ == ast.u64_type { - g.const_decl_write_precomputed(styp, cname, ct_value.str() + 'U') + g.const_decl_write_precomputed(mod, styp, cname, field_name, ct_value.str() + 'U') } else { - g.const_decl_write_precomputed(styp, cname, ct_value.str()) + g.const_decl_write_precomputed(mod, styp, cname, field_name, ct_value.str()) } } u8 { - g.const_decl_write_precomputed(styp, cname, ct_value.str()) + g.const_decl_write_precomputed(mod, styp, cname, field_name, ct_value.str()) } u16 { - g.const_decl_write_precomputed(styp, cname, ct_value.str()) + g.const_decl_write_precomputed(mod, styp, cname, field_name, ct_value.str()) } u32 { - g.const_decl_write_precomputed(styp, cname, ct_value.str()) + g.const_decl_write_precomputed(mod, styp, cname, field_name, ct_value.str()) } u64 { - g.const_decl_write_precomputed(styp, cname, ct_value.str() + 'U') + g.const_decl_write_precomputed(mod, styp, cname, field_name, ct_value.str() + 'U') } f32 { - g.const_decl_write_precomputed(styp, cname, ct_value.str()) + g.const_decl_write_precomputed(mod, styp, cname, field_name, ct_value.str()) } f64 { - g.const_decl_write_precomputed(styp, cname, ct_value.str()) + g.const_decl_write_precomputed(mod, styp, cname, field_name, ct_value.str()) } rune { rune_code := u32(ct_value) @@ -4527,9 +4551,9 @@ fn (mut g Gen) const_decl_precomputed(mod string, name string, ct_value ast.Comp return false } escval := util.smart_quote(u8(rune_code).ascii_str(), false) - g.const_decl_write_precomputed(styp, cname, "'$escval'") + g.const_decl_write_precomputed(mod, styp, cname, field_name, "'$escval'") } else { - g.const_decl_write_precomputed(styp, cname, u32(ct_value).str()) + g.const_decl_write_precomputed(mod, styp, cname, field_name, u32(ct_value).str()) } } string { @@ -4538,8 +4562,12 @@ fn (mut g Gen) const_decl_precomputed(mod string, name string, ct_value ast.Comp // TODO: ^ the above for strings, cause: // `error C2099: initializer is not a constant` errors in MSVC, // so fall back to the delayed initialisation scheme: - g.definitions.writeln('$styp $cname; // str inited later') - g.init.writeln('\t$cname = _SLIT("$escaped_val");') + g.global_const_defs[util.no_dots(field_name)] = GlobalConstDef{ + mod: mod + def: '$styp $cname; // str inited later' + init: '\t$cname = _SLIT("$escaped_val");' + order: -1 + } if g.is_autofree { g.cleanups[mod].writeln('\tstring_free(&$cname);') } @@ -4551,11 +4579,14 @@ fn (mut g Gen) const_decl_precomputed(mod string, name string, ct_value ast.Comp return true } -fn (mut g Gen) const_decl_write_precomputed(styp string, cname string, ct_value string) { - g.definitions.writeln('$styp $cname = $ct_value; // precomputed') +fn (mut g Gen) const_decl_write_precomputed(mod string, styp string, cname string, field_name string, ct_value string) { + g.global_const_defs[util.no_dots(field_name)] = GlobalConstDef{ + mod: mod + def: '$styp $cname = $ct_value; // precomputed' + } } -fn (mut g Gen) const_decl_simple_define(name string, val string) { +fn (mut g Gen) const_decl_simple_define(mod string, name string, val string) { // Simple expressions should use a #define // so that we don't pollute the binary with unnecessary global vars // Do not do this when building a module, otherwise the consts @@ -4571,13 +4602,17 @@ fn (mut g Gen) const_decl_simple_define(name string, val string) { x = '_const_$x' } if g.pref.translated { - g.definitions.write_string('const int $x = ') + g.global_const_defs[util.no_dots(name)] = GlobalConstDef{ + mod: mod + def: 'const int $x = $val;' + order: -1 + } } else { - g.definitions.write_string('#define $x ') - } - g.definitions.writeln(val) - if g.pref.translated { - g.definitions.write_string(';') + g.global_const_defs[util.no_dots(name)] = GlobalConstDef{ + mod: mod + def: '#define $x $val' + order: -1 + } } } @@ -4586,22 +4621,27 @@ fn (mut g Gen) const_decl_init_later(mod string, name string, expr ast.Expr, typ // (C doesn't allow init expressions that can't be resolved at compile time). mut styp := g.typ(typ) cname := if g.pref.translated && !g.is_builtin_mod { name } else { '_const_$name' } - g.definitions.writeln('$styp $cname; // inited later') + mut init := strings.new_builder(100) if cname == '_const_os__args' { if g.pref.os == .windows { - g.init.writeln('\t_const_os__args = os__init_os_args_wide(___argc, (byteptr*)___argv);') + init.writeln('\t_const_os__args = os__init_os_args_wide(___argc, (byteptr*)___argv);') } else { - g.init.writeln('\t_const_os__args = os__init_os_args(___argc, (byte**)___argv);') + init.writeln('\t_const_os__args = os__init_os_args(___argc, (byte**)___argv);') } } else { if unwrap_option { - g.init.writeln('{') - g.init.writeln(g.expr_string_surround('\t$cname = *($styp*)', expr, '.data;')) - g.init.writeln('}') + init.writeln('{') + init.writeln(g.expr_string_surround('\t$cname = *($styp*)', expr, '.data;')) + init.writeln('}') } else { - g.init.writeln(g.expr_string_surround('\t$cname = ', expr, ';')) + init.writeln(g.expr_string_surround('\t$cname = ', expr, ';')) } } + g.global_const_defs[util.no_dots(name)] = GlobalConstDef{ + mod: mod + def: '$styp $cname; // inited later' + init: init.str() + } if g.is_autofree { sym := g.table.sym(typ) if styp.starts_with('Array_') { @@ -4654,40 +4694,57 @@ fn (mut g Gen) global_decl(node ast.GlobalDecl) { if field.has_expr && mut anon_fn_expr is ast.AnonFn { g.gen_anon_fn_decl(mut anon_fn_expr) fn_type_name := g.get_anon_fn_type_name(mut anon_fn_expr, field.name) - g.definitions.writeln('$fn_type_name = ${g.table.sym(field.typ).name}; // global2') + g.global_const_defs[util.no_dots(fn_type_name)] = GlobalConstDef{ + mod: node.mod + def: '$fn_type_name = ${g.table.sym(field.typ).name}; // global2' + order: -1 + } continue } + mut def_builder := strings.new_builder(100) + mut init := '' extern := if cextern { 'extern ' } else { '' } modifier := if field.is_volatile { ' volatile ' } else { '' } - g.definitions.write_string('$extern$visibility_kw$modifier$styp $attributes $field.name') + def_builder.write_string('$extern$visibility_kw$modifier$styp $attributes $field.name') if cextern { - g.definitions.writeln('; // global5') + def_builder.writeln('; // global5') + g.global_const_defs[util.no_dots(field.name)] = GlobalConstDef{ + mod: node.mod + def: def_builder.str() + order: -1 + } continue } if field.has_expr || cinit { if g.pref.translated { - g.definitions.write_string(' = ${g.expr_string(field.expr)}') + def_builder.write_string(' = ${g.expr_string(field.expr)}') } else if (field.expr.is_literal() && should_init) || cinit || (field.expr is ast.ArrayInit && (field.expr as ast.ArrayInit).is_fixed) { // Simple literals can be initialized right away in global scope in C. // e.g. `int myglobal = 10;` - g.definitions.write_string(' = ${g.expr_string(field.expr)}') + def_builder.write_string(' = ${g.expr_string(field.expr)}') } else { // More complex expressions need to be moved to `_vinit()` // e.g. `__global ( mygblobal = 'hello ' + world' )` - g.global_init.writeln('\t$field.name = ${g.expr_string(field.expr)}; // 3global') + init = '\t$field.name = ${g.expr_string(field.expr)}; // 3global' } } else if !g.pref.translated { // don't zero globals from C code default_initializer := g.type_default(field.typ) if default_initializer == '{0}' && should_init { - g.definitions.write_string(' = {0}') + def_builder.write_string(' = {0}') } else { if field.name !in ['as_cast_type_indexes', 'g_memory_block', 'global_allocator'] { - g.global_init.writeln('\t$field.name = *($styp*)&(($styp[]){${g.type_default(field.typ)}}[0]); // global') + init = '\t$field.name = *($styp*)&(($styp[]){${g.type_default(field.typ)}}[0]); // global' } } } - g.definitions.writeln('; // global4') + def_builder.writeln('; // global4') + g.global_const_defs[util.no_dots(field.name)] = GlobalConstDef{ + mod: node.mod + def: def_builder.str() + init: init + dep_names: g.dependent_var_names(field.expr) + } } } @@ -4769,17 +4826,21 @@ fn (mut g Gen) write_init_function() { // calling module init functions too, just in case they do fail... g.write('\tas_cast_type_indexes = ') g.writeln(g.as_cast_name_table()) - // g.writeln('\tbuiltin_init();') - g.writeln('\tvinit_string_literals();') - // + if g.nr_closures > 0 { g.writeln('\t_closure_mtx_init();') } for mod_name in g.table.modules { g.writeln('\t{ // Initializations for module $mod_name :') - g.write(g.inits[mod_name].str()) - g.write(g.global_inits[mod_name].str()) + // write globals and consts init later + for var_name in g.sorted_global_const_names { + if var := g.global_const_defs[var_name] { + if var.mod == mod_name && var.init.len > 0 { + g.writeln(var.init) + } + } + } init_fn_name := '${mod_name}.init' if initfn := g.table.find_fn(init_fn_name) { if initfn.return_type == ast.void_type && initfn.params.len == 0 { @@ -5059,6 +5120,22 @@ fn (mut g Gen) write_types(symbols []&ast.TypeSymbol) { } } +fn (mut g Gen) sort_globals_consts() { + g.sorted_global_const_names.clear() + mut dep_graph := depgraph.new_dep_graph() + for var_name, var_info in g.global_const_defs { + dep_graph.add_with_value(var_name, var_info.dep_names, var_info.order) + } + dep_graph_sorted := dep_graph.resolve() + for order in [-1, 0] { + for node in dep_graph_sorted.nodes { + if node.value == order { + g.sorted_global_const_names << node.name + } + } + } +} + // sort structs by dependant fields fn (mut g Gen) sort_structs(typesa []&ast.TypeSymbol) []&ast.TypeSymbol { util.timing_start(@METHOD) diff --git a/vlib/v/gen/c/json.v b/vlib/v/gen/c/json.v index e4720ac497..9a71c7a05d 100644 --- a/vlib/v/gen/c/json.v +++ b/vlib/v/gen/c/json.v @@ -152,7 +152,7 @@ $enc_fn_dec { dec.writeln('\topt_ok2(&res, ($option_name*)&ret, sizeof(res));') dec.writeln('\treturn ret;\n}') enc.writeln('\treturn o;\n}') - g.definitions.writeln(dec.str()) + g.gowrappers.writeln(dec.str()) g.gowrappers.writeln(enc.str()) } }