From a309593f568cf6b5ccb02fcdb8892d9b88a5be93 Mon Sep 17 00:00:00 2001 From: Felipe Pena Date: Thu, 24 Jul 2025 12:25:41 -0300 Subject: [PATCH] markused: fix interface fields and chan usage (fix #24961) (#24962) --- vlib/v/gen/c/cgen.v | 37 +++++++++++++++++-- vlib/v/markused/markused.v | 9 +++-- vlib/v/markused/walker.v | 26 +++++++++---- .../skip_unused/interface_unused.run.out | 0 .../interface_unused.skip_unused.run.out | 0 vlib/v/tests/skip_unused/interface_unused.vv | 5 +++ 6 files changed, 63 insertions(+), 14 deletions(-) create mode 100644 vlib/v/tests/skip_unused/interface_unused.run.out create mode 100644 vlib/v/tests/skip_unused/interface_unused.skip_unused.run.out create mode 100644 vlib/v/tests/skip_unused/interface_unused.vv diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index e0a846fe30..6e884f1f57 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -1185,6 +1185,9 @@ pub fn (mut g Gen) write_typeof_functions() { if inter_info.is_generic { continue } + if g.pref.skip_unused && sym.idx !in g.table.used_features.used_syms { + continue + } g.definitions.writeln('${g.static_non_parallel}char * v_typeof_interface_${sym.cname}(int sidx);') if g.pref.parallel_cc { g.extern_out.writeln('extern char * v_typeof_interface_${sym.cname}(int sidx);') @@ -1620,6 +1623,13 @@ fn (mut g Gen) write_chan_pop_option_fns() { if opt_el_type in done { continue } + if g.pref.skip_unused { + if sym := g.table.find_sym(opt_el_type) { + if sym.idx !in g.table.used_features.used_syms { + continue + } + } + } done << opt_el_type g.channel_definitions.writeln(' static inline ${opt_el_type} __Option_${styp}_popval(${styp} ch) { @@ -1642,6 +1652,13 @@ fn (mut g Gen) write_chan_push_option_fns() { if styp in done { continue } + if g.pref.skip_unused { + if sym := g.table.find_sym(el_type) { + if sym.idx !in g.table.used_features.used_syms { + continue + } + } + } done << styp g.register_option(ast.void_type.set_flag(.option)) g.channel_definitions.writeln(' @@ -1744,10 +1761,14 @@ pub fn (mut g Gen) write_typedef_types() { } .chan { if sym.name != 'chan' { - g.type_definitions.writeln('typedef chan ${sym.cname};') chan_inf := sym.chan_info() chan_elem_type := chan_inf.elem_type - is_fixed_arr := g.table.sym(chan_elem_type).kind == .array_fixed + esym := g.table.sym(chan_elem_type) + if g.pref.skip_unused && esym.idx !in g.table.used_features.used_syms { + continue + } + g.type_definitions.writeln('typedef chan ${sym.cname};') + is_fixed_arr := esym.kind == .array_fixed if !chan_elem_type.has_flag(.generic) { el_stype := if is_fixed_arr { '_v_' } else { '' } + g.styp(chan_elem_type) val_arg_pop := if is_fixed_arr { '&val.ret_arr' } else { '&val' } @@ -1798,6 +1819,9 @@ static inline void __${sym.cname}_pushval(${sym.cname} ch, ${push_arg} val) { } } for sym in interface_non_generic_syms { + if g.pref.skip_unused && sym.idx !in g.table.used_features.used_syms { + continue + } g.write_interface_typesymbol_declaration(sym) } } @@ -6444,7 +6468,8 @@ fn (mut g Gen) write_debug_calls_typeof_functions() { continue } inter_info := sym.info as ast.Interface - if inter_info.is_generic { + if inter_info.is_generic + || (g.pref.skip_unused && sym.idx !in g.table.used_features.used_syms) { continue } g.writeln('\tv_typeof_interface_${sym.cname}(0);') @@ -6646,6 +6671,9 @@ fn (mut g Gen) write_builtin_types() { // everything except builtin will get sorted for builtin_name in ast.builtins { sym := g.table.sym_by_idx(g.table.type_idxs[builtin_name]) + if g.pref.skip_unused && sym.idx !in g.table.used_features.used_syms { + continue + } if sym.info is ast.Interface { g.write_interface_typedef(sym) if !sym.info.is_generic { @@ -7802,6 +7830,9 @@ fn (mut g Gen) interface_table() string { if inter_info.is_generic { continue } + if g.pref.skip_unused && isym.idx !in g.table.used_features.used_syms { + continue + } // interface_name is for example Speaker interface_name := isym.cname // generate a struct that references interface methods diff --git a/vlib/v/markused/markused.v b/vlib/v/markused/markused.v index 79385fbb4d..8a62690fdb 100644 --- a/vlib/v/markused/markused.v +++ b/vlib/v/markused/markused.v @@ -8,7 +8,7 @@ import v.pref // mark_used walks the AST, starting at main() and marks all used fns transitively. pub fn mark_used(mut table ast.Table, mut pref_ pref.Preferences, ast_files []&ast.File) { - mut all_fns, all_consts, all_globals, all_fields, all_decltypes := all_global_decl(ast_files) + mut all_fns, all_consts, all_globals, all_fields, all_decltypes, all_structs := all_global_decl(ast_files) util.timing_start('MARKUSED') defer { util.timing_measure('MARKUSED') @@ -447,6 +447,7 @@ pub fn mark_used(mut table ast.Table, mut pref_ pref.Preferences, ast_files []&a all_globals: all_globals all_fields: all_fields all_decltypes: all_decltypes + all_structs: all_structs pref: pref_ ) walker.mark_markused_consts() // tagged with `@[markused]` @@ -586,7 +587,7 @@ pub fn mark_used(mut table ast.Table, mut pref_ pref.Preferences, ast_files []&a } } -fn all_global_decl(ast_files []&ast.File) (map[string]ast.FnDecl, map[string]ast.ConstField, map[string]ast.GlobalField, map[string]ast.StructField, map[string]ast.Type) { +fn all_global_decl(ast_files []&ast.File) (map[string]ast.FnDecl, map[string]ast.ConstField, map[string]ast.GlobalField, map[string]ast.StructField, map[string]ast.Type, map[string]ast.StructDecl) { util.timing_start(@METHOD) defer { util.timing_measure(@METHOD) @@ -596,6 +597,7 @@ fn all_global_decl(ast_files []&ast.File) (map[string]ast.FnDecl, map[string]ast mut all_globals := map[string]ast.GlobalField{} mut all_fields := map[string]ast.StructField{} mut all_decltypes := map[string]ast.Type{} + mut all_structs := map[string]ast.StructDecl{} for i in 0 .. ast_files.len { for node in ast_files[i].stmts { match node { @@ -622,6 +624,7 @@ fn all_global_decl(ast_files []&ast.File) (map[string]ast.FnDecl, map[string]ast sfkey := sfield.sfkey() all_fields[sfkey] = sfield } + all_structs[node.name] = node } ast.TypeDecl { all_decltypes[node.name] = node.typ @@ -630,7 +633,7 @@ fn all_global_decl(ast_files []&ast.File) (map[string]ast.FnDecl, map[string]ast } } } - return all_fns, all_consts, all_globals, all_fields, all_decltypes + return all_fns, all_consts, all_globals, all_fields, all_decltypes, all_structs } fn mark_all_methods_used(mut table ast.Table, mut all_fn_root_names []string, typ ast.Type) { diff --git a/vlib/v/markused/walker.v b/vlib/v/markused/walker.v index 08e13545dd..02cd6f5e69 100644 --- a/vlib/v/markused/walker.v +++ b/vlib/v/markused/walker.v @@ -30,6 +30,7 @@ mut: all_globals map[string]ast.GlobalField all_fields map[string]ast.StructField all_decltypes map[string]ast.Type + all_structs map[string]ast.StructDecl } pub fn Walker.new(params Walker) &Walker { @@ -301,6 +302,9 @@ pub fn (mut w Walker) stmt(node_ ast.Stmt) { } } ast.StructDecl { + for typ in node.implements_types { + w.mark_by_type(typ.typ) + } w.struct_fields(node.fields) } ast.DeferStmt { @@ -921,8 +925,7 @@ pub fn (mut w Walker) mark_by_type(typ ast.Type) { if typ.has_flag(.generic) { return } - sym := w.table.sym(typ) - w.mark_by_sym(sym) + w.mark_by_sym(w.table.sym(typ)) } pub fn (mut w Walker) mark_by_sym(isym ast.TypeSymbol) { @@ -945,24 +948,28 @@ pub fn (mut w Walker) mark_by_sym(isym ast.TypeSymbol) { } } match fsym.info { - ast.Struct, ast.SumType, ast.FnType, ast.Alias, ast.Chan { - w.mark_by_sym(fsym) - } ast.Array, ast.ArrayFixed { w.features.used_arrays++ - w.mark_by_type(ifield.typ) + w.mark_by_sym(fsym) } ast.Map { w.features.used_maps++ - w.mark_by_type(ifield.typ) + w.mark_by_sym(fsym) + } + else { + w.mark_by_sym(fsym) } - else {} } } } for embed in isym.info.embeds { w.mark_by_type(embed) } + if decl := w.all_structs[isym.name] { + for iface_typ in decl.implements_types { + w.mark_by_type(iface_typ.typ) + } + } } ast.ArrayFixed, ast.Array { w.mark_by_type(isym.info.elem_type) @@ -1024,6 +1031,9 @@ pub fn (mut w Walker) mark_by_sym(isym ast.TypeSymbol) { if isym.info.parent_type != 0 { w.mark_by_type(isym.info.parent_type) } + for field in isym.info.fields { + w.mark_by_type(field.typ) + } for method in isym.methods { if method.receiver_type != 0 { w.mark_by_type(method.receiver_type) diff --git a/vlib/v/tests/skip_unused/interface_unused.run.out b/vlib/v/tests/skip_unused/interface_unused.run.out new file mode 100644 index 0000000000..e69de29bb2 diff --git a/vlib/v/tests/skip_unused/interface_unused.skip_unused.run.out b/vlib/v/tests/skip_unused/interface_unused.skip_unused.run.out new file mode 100644 index 0000000000..e69de29bb2 diff --git a/vlib/v/tests/skip_unused/interface_unused.vv b/vlib/v/tests/skip_unused/interface_unused.vv new file mode 100644 index 0000000000..2ccf4bea3e --- /dev/null +++ b/vlib/v/tests/skip_unused/interface_unused.vv @@ -0,0 +1,5 @@ +struct Foo {} + +interface Bar { + a Foo +}