From f834855cb5e88ab551424ff480ea13ece7c06598 Mon Sep 17 00:00:00 2001 From: Felipe Pena Date: Fri, 1 Aug 2025 15:15:55 -0300 Subject: [PATCH] markused: improve array resources tracking + remove all_fns loop for orm (#25007) --- vlib/v/ast/table.v | 5 +- vlib/v/checker/checker.v | 2 - vlib/v/checker/fn.v | 2 +- vlib/v/checker/infix.v | 1 - vlib/v/checker/used_features.v | 49 ++++-- vlib/v/gen/c/dumpexpr.v | 4 + vlib/v/markused/markused.v | 50 +----- vlib/v/markused/walker.v | 313 +++++++++++++++++++++------------ 8 files changed, 236 insertions(+), 190 deletions(-) diff --git a/vlib/v/ast/table.v b/vlib/v/ast/table.v index 967c25eeec..4b63800807 100644 --- a/vlib/v/ast/table.v +++ b/vlib/v/ast/table.v @@ -10,13 +10,12 @@ import v.util @[heap; minify] pub struct UsedFeatures { pub mut: - dump bool // dump() - index bool // string[0] + dump bool // filled in by markused range_index bool // string[0..1] - cast_ptr bool // &u8(...) anon_fn bool // fn () { } auto_str bool // auto str fns auto_str_ptr bool // auto str fns for ptr type + auto_str_arr bool // auto str fns for array arr_prepend bool // arr.prepend() arr_insert bool // arr.insert() arr_first bool // arr.first() diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 7129a46d4c..bda2d44f55 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -3069,7 +3069,6 @@ pub fn (mut c Checker) expr(mut node ast.Expr) ast.Type { return c.concat_expr(mut node) } ast.DumpExpr { - c.table.used_features.dump = true c.expected_type = ast.string_type node.expr_type = c.expr(mut node.expr) c.markused_dumpexpr(mut node) @@ -5014,7 +5013,6 @@ fn (mut c Checker) index_expr(mut node ast.IndexExpr) ast.Type { if node.index is ast.RangeExpr { c.table.used_features.range_index = true } - c.table.used_features.index = true } is_aggregate_arr := typ_sym.kind == .aggregate && (typ_sym.info as ast.Aggregate).types.filter(c.table.type_kind(it) !in [.array, .array_fixed, .string, .map]).len == 0 diff --git a/vlib/v/checker/fn.v b/vlib/v/checker/fn.v index 18996c05db..da4386d498 100644 --- a/vlib/v/checker/fn.v +++ b/vlib/v/checker/fn.v @@ -1441,7 +1441,7 @@ fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool) ast. if args_len > 0 && fn_name in print_everything_fns { node.args[0].ct_expr = c.comptime.is_comptime(node.args[0].expr) c.builtin_args(mut node, fn_name, func) - c.markused_fn_call(mut node) + c.markused_print_call(mut node) return func.return_type } // `return error(err)` -> `return err` diff --git a/vlib/v/checker/infix.v b/vlib/v/checker/infix.v index 24314b9a34..6378677a53 100644 --- a/vlib/v/checker/infix.v +++ b/vlib/v/checker/infix.v @@ -60,7 +60,6 @@ fn (mut c Checker) infix_expr(mut node ast.InfixExpr) ast.Type { if left_type.has_flag(.option) { c.error('cannot push to Option array that was not unwrapped first', node.left.pos()) } - c.markused_infixexpr(!c.is_builtin_mod && c.mod != 'strings') if mut node.right is ast.IfExpr { if node.right.is_expr && node.right.branches.len > 0 { mut last_stmt := node.right.branches[0].stmts.last() diff --git a/vlib/v/checker/used_features.v b/vlib/v/checker/used_features.v index 43139777e9..43b7e608cd 100644 --- a/vlib/v/checker/used_features.v +++ b/vlib/v/checker/used_features.v @@ -36,6 +36,9 @@ fn (mut c Checker) markused_dumpexpr(mut node ast.DumpExpr) { if node.expr_type.is_ptr() { c.table.used_features.auto_str_ptr = true } + if !c.table.used_features.auto_str_arr { + c.table.used_features.auto_str_arr = c.table.final_sym(unwrapped_type).kind == .array + } } else { c.table.used_features.print_types[node.expr_type.idx()] = true } @@ -58,9 +61,6 @@ fn (mut c Checker) markused_castexpr(mut node ast.CastExpr, to_type ast.Type, mu c.table.used_features.used_maps++ } } - if c.mod !in ['strings', 'math.bits'] && to_type.is_ptr() { - c.table.used_features.cast_ptr = true - } } fn (mut c Checker) markused_comptimecall(mut node ast.ComptimeCall) { @@ -91,7 +91,6 @@ fn (mut c Checker) markused_comptimecall(mut node ast.ComptimeCall) { } fn (mut c Checker) markused_comptimefor(mut node ast.ComptimeFor, unwrapped_expr_type ast.Type) { - c.table.used_features.dump = true if c.table.used_features.used_maps == 0 { final_sym := c.table.final_sym(unwrapped_expr_type) if final_sym.info is ast.Map { @@ -108,34 +107,50 @@ fn (mut c Checker) markused_call_expr(left_type ast.Type, mut node ast.CallExpr) if left_type != 0 && left_type.is_ptr() && !c.table.used_features.auto_str_ptr && node.name == 'str' { c.table.used_features.auto_str_ptr = true + if !c.table.used_features.auto_str_arr { + c.table.used_features.auto_str_arr = c.table.final_sym(left_type).kind == .array + } } } -fn (mut c Checker) markused_fn_call(mut node ast.CallExpr) { +fn (mut c Checker) markused_print_call(mut node ast.CallExpr) { if !c.is_builtin_mod && c.mod != 'math.bits' && node.args[0].expr !is ast.StringLiteral { + arg_typ := c.unwrap_generic(node.args[0].typ) if (node.args[0].expr is ast.CallExpr && node.args[0].expr.is_method && node.args[0].expr.name == 'str') - || !c.table.sym(c.unwrap_generic(node.args[0].typ)).has_method('str') { + || !c.table.sym(arg_typ).has_method('str') { c.table.used_features.auto_str = true } else { - if node.args[0].typ.has_option_or_result() { + if arg_typ.has_option_or_result() { c.table.used_features.print_options = true } - c.table.used_features.print_types[node.args[0].typ.idx()] = true + c.table.used_features.print_types[arg_typ.idx()] = true if !c.table.used_features.auto_str_ptr && node.args[0].expr is ast.Ident { var_obj := node.args[0].expr.obj if var_obj is ast.Var { - if var_obj.orig_type != 0 - && c.table.final_sym(var_obj.orig_type).kind == .interface { - c.table.used_features.auto_str_ptr = true + if var_obj.orig_type != 0 { + fsym := c.table.final_sym(var_obj.orig_type) + if fsym.kind == .interface { + c.table.used_features.auto_str_ptr = true + } else if fsym.kind == .array { + c.table.used_features.auto_str_arr = true + } return } } } } - if node.args[0].typ.is_ptr() { + if arg_typ.is_ptr() { c.table.used_features.auto_str_ptr = true } + if !c.table.used_features.auto_str_arr { + sym := c.table.final_sym(arg_typ) + if sym.kind == .array { + c.table.used_features.auto_str_arr = true + } else if sym.info is ast.Struct { + c.table.used_features.auto_str_arr = sym.info.fields.any(c.table.final_sym(it.typ).kind == .array) + } + } } } @@ -165,18 +180,14 @@ fn (mut c Checker) markused_string_inter_lit(mut node ast.StringInterLiteral, ft if ftyp.is_ptr() { c.table.used_features.auto_str_ptr = true } + if !c.table.used_features.auto_str_arr { + c.table.used_features.auto_str_arr = c.table.final_sym(ftyp).kind == .array + } if ftyp.has_option_or_result() { c.table.used_features.print_options = true } } -fn (mut c Checker) markused_infixexpr(check bool) { - if !check { - return - } - c.table.used_features.index = true -} - fn (mut c Checker) markused_array_method(check bool, method_name string) { if !check { return diff --git a/vlib/v/gen/c/dumpexpr.v b/vlib/v/gen/c/dumpexpr.v index 727948354a..b508b54d82 100644 --- a/vlib/v/gen/c/dumpexpr.v +++ b/vlib/v/gen/c/dumpexpr.v @@ -107,6 +107,10 @@ fn (mut g Gen) dump_expr_definitions() { } _, str_method_expects_ptr, _ := dump_sym.str_method_info() typ := ast.idx_to_type(dump_type) + if g.pref.skip_unused + && (!g.table.used_features.dump || typ.idx() !in g.table.used_features.used_syms) { + continue + } is_ptr := typ.is_ptr() deref, _ := deref_kind(str_method_expects_ptr, is_ptr, typ) to_string_fn_name := g.get_str_fn(typ.clear_flags(.shared_f, .result)) diff --git a/vlib/v/markused/markused.v b/vlib/v/markused/markused.v index f2b5fd6fe7..33c9477105 100644 --- a/vlib/v/markused/markused.v +++ b/vlib/v/markused/markused.v @@ -85,21 +85,6 @@ pub fn mark_used(mut table ast.Table, mut pref_ pref.Preferences, ast_files []&a core_fns << '__new_array_with_array_default_noscan' core_fns << 'new_array_from_c_array' } - if table.used_features.index || pref_.is_shared { - include_panic_deps = true - core_fns << string_idx_str + '.at_with_check' - core_fns << string_idx_str + '.clone' - core_fns << string_idx_str + '.clone_static' - core_fns << string_idx_str + '.at' - core_fns << array_idx_str + '.set' - core_fns << array_idx_str + '.get_with_check' // used for `x := a[i] or {}` - core_fns << ref_array_idx_str + '.set' - core_fns << map_idx_str + '.get' - core_fns << map_idx_str + '.set' - core_fns << '__new_array_noscan' - core_fns << ref_array_idx_str + '.push_noscan' - core_fns << ref_array_idx_str + '.push_many_noscan' - } if table.used_features.range_index || pref_.is_shared { core_fns << string_idx_str + '.substr_with_check' core_fns << string_idx_str + '.substr_ni' @@ -109,10 +94,6 @@ pub fn mark_used(mut table ast.Table, mut pref_ pref.Preferences, ast_files []&a core_fns << array_idx_str + '.clone_static_to_depth' core_fns << array_idx_str + '.clone_to_depth' } - if table.used_features.auto_str || table.used_features.dump { - core_fns << string_idx_str + '.repeat' - core_fns << 'tos3' - } if table.used_features.arr_prepend { core_fns << ref_array_idx_str + '.prepend_many' } @@ -121,6 +102,7 @@ pub fn mark_used(mut table ast.Table, mut pref_ pref.Preferences, ast_files []&a } if table.used_features.arr_pop { core_fns << ref_array_idx_str + '.pop' + core_fns << ref_array_idx_str + '.pop_noscan' } if table.used_features.arr_first { core_fns << array_idx_str + '.first' @@ -130,15 +112,7 @@ pub fn mark_used(mut table ast.Table, mut pref_ pref.Preferences, ast_files []&a } if table.used_features.arr_insert { core_fns << ref_array_idx_str + '.insert_many' - } - if table.used_features.dump { - include_panic_deps = true - builderptr_idx := int(table.find_type('strings.Builder').ref()).str() - core_fns << [ - builderptr_idx + '.str', - builderptr_idx + '.free', - builderptr_idx + '.write_rune', - ] + core_fns << ref_array_idx_str + '.insert_noscan' } if table.used_features.print_options { include_panic_deps = true @@ -285,26 +259,6 @@ pub fn mark_used(mut table ast.Table, mut pref_ pref.Preferences, ast_files []&a handle_vweb(mut table, mut all_fn_root_names, 'vweb.Result', 'vweb.filter', 'vweb.Context') handle_vweb(mut table, mut all_fn_root_names, 'x.vweb.Result', 'x.vweb.filter', 'x.vweb.Context') - // handle ORM drivers: - orm_connection_implementations := table.iface_types['orm.Connection'] or { []ast.Type{} } - if orm_connection_implementations.len > 0 { - for k, _ in all_fns { - if k.starts_with('orm.') { - all_fn_root_names << k - } - } - for orm_type in orm_connection_implementations { - typ := int(orm_type).str() - all_fn_root_names << typ + '.select' - all_fn_root_names << typ + '.insert' - all_fn_root_names << typ + '.update' - all_fn_root_names << typ + '.delete' - all_fn_root_names << typ + '.create' - all_fn_root_names << typ + '.drop' - all_fn_root_names << typ + '.last_id' - } - } - if 'debug_used_features' in pref_.compile_defines { eprintln('> debug_used_features: ${table.used_features}') } diff --git a/vlib/v/markused/walker.v b/vlib/v/markused/walker.v index 067e52fa38..dbea48f39b 100644 --- a/vlib/v/markused/walker.v +++ b/vlib/v/markused/walker.v @@ -31,36 +31,44 @@ mut: all_decltypes map[string]ast.TypeDecl all_structs map[string]ast.StructDecl - level int - is_builtin_mod bool + level int + is_builtin_mod bool + is_direct_array_access bool // dependencies finding flags - uses_atomic bool // has atomic - uses_array bool // has array - uses_channel bool // has chan dep - uses_lock bool // has mutex dep - uses_ct_fields bool // $for .fields - uses_ct_methods bool // $for .methods - uses_ct_params bool // $for .params - uses_ct_values bool // $for .values - uses_ct_variants bool // $for .variants - uses_ct_attribute bool // $for .attributes - uses_external_type bool - uses_err bool // err var - uses_asserts bool // assert - uses_map_update bool // has {...expr} - uses_debugger bool // has debugger; - uses_mem_align bool // @[aligned:N] for structs - uses_eq bool // has == op - uses_interp bool // string interpolation - uses_guard bool - uses_orm bool - uses_str map[ast.Type]bool // has .str() calls, and for which types - uses_free map[ast.Type]bool // has .free() calls, and for which types - uses_spawn bool - uses_dump bool - uses_memdup bool // sumtype cast and &Struct{} - uses_arr_void bool // auto arr methods + uses_atomic bool // has atomic + uses_array bool // has array + uses_channel bool // has chan dep + uses_lock bool // has mutex dep + uses_ct_fields bool // $for .fields + uses_ct_methods bool // $for .methods + uses_ct_params bool // $for .params + uses_ct_values bool // $for .values + uses_ct_variants bool // $for .variants + uses_ct_attribute bool // $for .attributes + uses_external_type bool + uses_err bool // err var + uses_asserts bool // assert + uses_map_update bool // has {...expr} + uses_debugger bool // has debugger; + uses_mem_align bool // @[aligned:N] for structs + uses_eq bool // has == op + uses_interp bool // string interpolation + uses_guard bool + uses_orm bool + uses_str map[ast.Type]bool // has .str() calls, and for which types + uses_free map[ast.Type]bool // has .free() calls, and for which types + uses_spawn bool + uses_dump bool + uses_memdup bool // sumtype cast and &Struct{} + uses_arr_void bool // auto arr methods + uses_index bool // var[k] + uses_str_index bool // string[k] + uses_str_index_check bool // string[k] or { } + uses_str_range bool // string[a..b] + uses_fixed_arr_int bool // fixed_arr[k] + uses_check_index bool // arr[key] or { } + uses_append bool // var << item } pub fn Walker.new(params Walker) &Walker { @@ -72,7 +80,7 @@ pub fn Walker.new(params Walker) &Walker { } @[inline] -pub fn (mut w Walker) mark_fn_as_used(fkey string) { +fn (mut w Walker) mark_fn_as_used(fkey string) { $if trace_skip_unused_marked ? { eprintln(' fn > |${fkey}|') } @@ -92,10 +100,8 @@ pub fn (mut w Walker) mark_builtin_map_method_as_used(method_name string) { pub fn (mut w Walker) mark_builtin_type_method_as_used(k string, rk string) { if mut cfn := w.all_fns[k] { w.fn_decl(mut cfn) - w.mark_fn_as_used(k) } else if mut cfn := w.all_fns[rk] { w.fn_decl(mut cfn) - w.mark_fn_as_used(rk) } } @@ -408,7 +414,9 @@ fn (mut w Walker) expr(node_ ast.Expr) { w.expr(node.cap_expr) w.expr(node.init_expr) w.exprs(node.exprs) - w.uses_array = true + if !w.uses_array && !w.is_direct_array_access { + w.uses_array = true + } } ast.Assoc { w.exprs(node.exprs) @@ -483,7 +491,7 @@ fn (mut w Walker) expr(node_ ast.Expr) { } ast.DumpExpr { w.expr(node.expr) - w.uses_dump = true + w.features.dump = true w.mark_by_type(node.expr_type) } ast.SpawnExpr { @@ -512,7 +520,7 @@ fn (mut w Walker) expr(node_ ast.Expr) { w.expr(node.left) w.expr(node.index) if node.or_expr.kind == .block { - w.uses_guard = true + w.uses_check_index = true } w.mark_by_type(node.typ) w.or_block(node.or_expr) @@ -529,22 +537,49 @@ fn (mut w Walker) expr(node_ ast.Expr) { w.mark_by_sym(w.table.sym(sym.info.key_type)) w.mark_by_sym(w.table.sym(sym.info.value_type)) w.features.used_maps++ - } else if sym.info is ast.Array { - if node.is_setter { - w.mark_builtin_array_method_as_used('set') - } else { - w.mark_builtin_array_method_as_used('get') + } else if sym.kind in [.array, .array_fixed, .any] { + if !w.is_direct_array_access || w.features.auto_str_arr { + if node.is_setter { + w.mark_builtin_array_method_as_used('set') + } else { + w.mark_builtin_array_method_as_used('get') + } + } + if sym.info is ast.Array { + w.mark_by_sym(w.table.sym(sym.info.elem_type)) + } else if sym.info is ast.ArrayFixed { + w.mark_by_sym(w.table.sym(sym.info.elem_type)) + } + if !w.uses_fixed_arr_int && sym.kind == .array_fixed { + w.uses_fixed_arr_int = true + } + if !w.uses_index && !w.is_direct_array_access { + w.uses_index = true } - w.mark_by_sym(w.table.sym(sym.info.elem_type)) } else if sym.kind == .string { if node.index is ast.RangeExpr { w.mark_builtin_array_method_as_used('slice') w.features.range_index = true } + w.uses_str_index = true + if !w.uses_str_index_check { + w.uses_str_index_check = node.or_expr.kind == .block + } + if !w.uses_str_range { + w.uses_str_range = node.index is ast.RangeExpr + } } else if sym.info is ast.Struct { w.mark_by_sym(sym) } else if sym.info is ast.SumType { w.mark_by_sym(sym) + } else if sym.kind == .any { + if !w.is_direct_array_access { + if node.is_setter { + w.mark_builtin_array_method_as_used('set') + } else { + w.mark_builtin_array_method_as_used('get') + } + } } } ast.InfixExpr { @@ -574,7 +609,8 @@ fn (mut w Walker) expr(node_ ast.Expr) { if right_sym.kind == .map { w.features.used_maps++ } - if !w.uses_arr_void && right_sym.kind in [.array, .array_fixed] { + if !w.uses_arr_void && !w.is_direct_array_access + && right_sym.kind in [.array, .array_fixed] { w.uses_arr_void = true } } else if node.op in [.key_is, .not_is] { @@ -584,11 +620,18 @@ fn (mut w Walker) expr(node_ ast.Expr) { if !w.uses_eq && node.op in [.eq, .ne] { w.uses_eq = true } + if !w.uses_append && node.op == .left_shift && !w.is_direct_array_access { + w.uses_append = true + } } ast.IfGuardExpr { w.expr(node.expr) w.mark_by_type(node.expr_type) w.uses_guard = true + if node.expr_type != 0 && !w.uses_str_index_check + && w.table.final_sym(node.expr_type).kind in [.u8, .string] { + w.uses_str_index_check = true + } } ast.IfExpr { w.expr(node.left) @@ -620,8 +663,7 @@ fn (mut w Walker) expr(node_ ast.Expr) { } else if node.name in w.all_globals { w.mark_global_as_used(node.name) } else { - if !w.uses_err && !w.is_builtin_mod && node.name == 'err' { - w.fn_by_name('${int(ast.error_type)}.str') + if !w.uses_err && node.name == 'err' { w.uses_err = true } w.fn_by_name(node.name) @@ -733,6 +775,9 @@ fn (mut w Walker) expr(node_ ast.Expr) { } sym := w.table.sym(node.typ) w.mark_by_sym(sym) + if !w.uses_memdup && sym.kind == .sum_type { + w.uses_memdup = true + } if node.has_update_expr { w.expr(node.update_expr) } @@ -811,10 +856,14 @@ pub fn (mut w Walker) fn_decl(mut node ast.FnDecl) { w.mark_fn_ret_and_params(node.return_type, node.params) return } + fkey := node.fkey() if w.used_fns[fkey] { return } + last_is_direct_array_access := w.is_direct_array_access + w.is_direct_array_access = node.is_direct_arr || w.pref.no_bounds_checking + defer { w.is_direct_array_access = last_is_direct_array_access } if w.trace_enabled { w.level++ defer { w.level-- } @@ -823,12 +872,13 @@ pub fn (mut w Walker) fn_decl(mut node ast.FnDecl) { } else { '' } - eprintln('>>>${' '.repeat(w.level)}${receiver_name}${node.name} [decl]') + eprintln('>>>${' '.repeat(w.level)}${receiver_name}${node.name}') } if node.is_closure { w.used_closures++ } if node.no_body { + w.mark_fn_as_used(fkey) return } if node.is_method { @@ -930,33 +980,18 @@ pub fn (mut w Walker) call_expr(mut node ast.CallExpr) { } else if node.is_fn_var { w.mark_global_as_used(node.name) } - w.mark_fn_as_used(fn_name) if node.is_method && node.receiver_type.has_flag(.generic) && node.receiver_concrete_type != 0 && !node.receiver_concrete_type.has_flag(.generic) { // if receiver is generic, then cgen requires `node.receiver_type` to be T. // We therefore need to get the concrete type from `node.receiver_concrete_type`. fn_name = '${int(node.receiver_concrete_type)}.${node.name}' receiver_typ = node.receiver_concrete_type - w.mark_fn_as_used(fn_name) } w.mark_by_type(node.return_type) - stmt := w.all_fns[fn_name] or { return } + mut stmt := w.all_fns[fn_name] or { return } if !stmt.should_be_skipped && stmt.name == node.name { if !node.is_method || receiver_typ == stmt.receiver.typ { - if w.trace_enabled { - w.level++ - defer { - w.level-- - } - receiver_name := if node.receiver_type != 0 { - w.table.type_to_str(node.receiver_type) + '.' - } else { - '' - } - eprintln('>>>${' '.repeat(w.level)}${receiver_name}${node.name} [call]') - } - w.mark_fn_ret_and_params(stmt.return_type, stmt.params) - w.stmts(stmt.stmts) + w.fn_decl(mut stmt) } if node.return_type.has_flag(.option) { w.used_option++ @@ -970,22 +1005,9 @@ pub fn (mut w Walker) fn_by_name(fn_name string) { if w.used_fns[fn_name] { return } - stmt := w.all_fns[fn_name] or { return } - if w.trace_enabled { - w.level++ - defer { - w.level-- - } - receiver_name := if fn_name.contains('.') && fn_name.all_before_last('.').int() > 0 { - w.table.type_to_str(fn_name.all_before_last('.').int()) + '.' - } else { - '' - } - eprintln('>>>${' '.repeat(w.level)}${receiver_name}${fn_name.all_after_last('.')} [by_name]') - } - w.mark_fn_as_used(fn_name) - w.mark_fn_ret_and_params(stmt.return_type, stmt.params) - w.stmts(stmt.stmts) + mut stmt := w.all_fns[fn_name] or { return } + w.fn_decl(mut stmt) + // w.stmts(stmt.stmts) } pub fn (mut w Walker) struct_fields(sfields []ast.StructField) { @@ -1095,7 +1117,9 @@ pub fn (mut w Walker) mark_by_sym(isym ast.TypeSymbol) { } } ast.ArrayFixed, ast.Array { - w.uses_array = true + if !w.uses_array && !w.is_direct_array_access { + w.uses_array = true + } w.mark_by_type(isym.info.elem_type) } ast.SumType { @@ -1208,18 +1232,24 @@ fn (mut w Walker) remove_unused_fn_generic_types() { } } -fn (mut w Walker) remove_unused_dump_type() { - for typ, _ in w.table.dumps { - if ast.Type(u32(typ)).idx() !in w.used_syms { - w.table.dumps.delete(typ) - } - } -} - fn (mut w Walker) mark_resource_dependencies() { if w.trace_enabled { eprintln('>>>>>>>>>> DEPS USAGE') } + if w.features.dump { + w.fn_by_name('eprint') + w.fn_by_name('eprintln') + builderptr_idx := int(w.table.find_type('strings.Builder').ref()).str() + w.fn_by_name(builderptr_idx + '.str') + w.fn_by_name(builderptr_idx + '.free') + w.fn_by_name(builderptr_idx + '.write_rune') + w.fn_by_name(builderptr_idx + '.write_string') + w.fn_by_name('strings.new_builder') + w.uses_free[ast.string_type] = true + } + // if w.uses_err { + // w.fn_by_name('${int(ast.error_type)}.str') + // } if w.uses_eq { w.fn_by_name('fast_string_eq') } @@ -1235,21 +1265,6 @@ fn (mut w Walker) mark_resource_dependencies() { if w.uses_lock { w.mark_by_sym_name('sync.RwMutex') } - if w.uses_array { - if w.pref.gc_mode in [.boehm_full_opt, .boehm_incr_opt] { - w.fn_by_name('__new_array_noscan') - w.fn_by_name('new_array_from_c_array_noscan') - w.fn_by_name('__new_array_with_multi_default_noscan') - w.fn_by_name('__new_array_with_array_default_noscan') - w.fn_by_name('__new_array_with_default_noscan') - } - w.fn_by_name('__new_array') - w.fn_by_name('new_array_from_c_array') - w.fn_by_name('__new_array_with_multi_default') - w.fn_by_name('__new_array_with_array_default') - w.fn_by_name('__new_array_with_default') - w.fn_by_name(int(ast.array_type.ref()).str() + '.set') - } if w.uses_orm { w.fn_by_name('__new_array_with_default_noscan') w.fn_by_name('new_array_from_c_array') @@ -1281,13 +1296,9 @@ fn (mut w Walker) mark_resource_dependencies() { if w.uses_mem_align { w.fn_by_name('memdup_align') } - if w.uses_guard { + if w.uses_guard || w.uses_check_index { w.fn_by_name('error') } - if w.uses_dump { - w.fn_by_name('eprint') - w.fn_by_name('eprintln') - } if w.uses_spawn { w.fn_by_name('malloc') w.fn_by_name('tos3') @@ -1301,6 +1312,28 @@ fn (mut w Walker) mark_resource_dependencies() { if w.uses_arr_void { w.mark_by_type(w.table.find_or_register_array(ast.voidptr_type)) } + if w.features.auto_str || w.uses_dump { + w.fn_by_name(ast.string_type_idx.str() + '.repeat') + w.fn_by_name('tos3') + } + if w.uses_index || w.pref.is_shared { + array_idx_str := ast.array_type_idx.str() + w.fn_by_name(array_idx_str + '.slice') + w.fn_by_name(array_idx_str + '.get') + if w.uses_guard || w.uses_check_index { + w.fn_by_name(array_idx_str + '.get_with_check') + } + } + if w.uses_str_index { + string_idx_str := ast.string_type_idx.str() + w.fn_by_name(string_idx_str + '.at') + if w.uses_str_index_check { + w.fn_by_name(string_idx_str + '.at_with_check') + } + if w.uses_str_range { + w.fn_by_name(string_idx_str + '.substr') + } + } for typ, _ in w.table.used_features.print_types { w.mark_by_type(typ) } @@ -1323,6 +1356,8 @@ fn (mut w Walker) mark_resource_dependencies() { mut map_fns := map[string]ast.FnDecl{} has_str_call := w.uses_interp || w.uses_asserts || w.uses_str.len > 0 || w.features.print_types.len > 0 + + orm_impls := w.table.iface_types['orm.Connection'] or { []ast.Type{} } for k, mut func in w.all_fns { if has_str_call && k.ends_with('.str') { if func.receiver.typ.idx() in w.used_syms { @@ -1334,8 +1369,8 @@ fn (mut w Walker) mark_resource_dependencies() { } continue } - if w.pref.autofree || (w.uses_free.len > 0 && k.ends_with('.free') - && func.receiver.typ.idx() in w.used_syms) { + if (w.pref.autofree || (w.uses_free.len > 0 && func.receiver.typ.idx() in w.used_syms)) + && k.ends_with('.free') { w.fn_by_name(k) continue } @@ -1361,10 +1396,57 @@ fn (mut w Walker) mark_resource_dependencies() { method_receiver_typename := w.table.type_to_str(func.receiver.typ) if method_receiver_typename in ['&map', '&mapnode', '&SortedMap', '&DenseArray'] { map_fns[k] = func + continue } } else if k.starts_with('map_') { map_fns[k] = func + continue } + if orm_impls.len > 0 && k.starts_with('orm.') { + w.fn_by_name(k) + continue + } + } + if w.uses_append { + ref_array_idx_str := int(ast.array_type.ref()).str() + w.fn_by_name(ref_array_idx_str + '.push') + w.fn_by_name(ref_array_idx_str + '.push_many_noscan') + w.fn_by_name(ref_array_idx_str + '.push_noscan') + } + if w.uses_array { + if w.pref.gc_mode in [.boehm_full_opt, .boehm_incr_opt] { + w.fn_by_name('__new_array_noscan') + w.fn_by_name('new_array_from_c_array_noscan') + w.fn_by_name('__new_array_with_multi_default_noscan') + w.fn_by_name('__new_array_with_array_default_noscan') + w.fn_by_name('__new_array_with_default_noscan') + } + w.fn_by_name('__new_array') + w.fn_by_name('new_array_from_c_array') + w.fn_by_name('__new_array_with_multi_default') + w.fn_by_name('__new_array_with_array_default') + w.fn_by_name('__new_array_with_default') + w.fn_by_name('__new_array_with_default_noscan') + w.fn_by_name(int(ast.array_type.ref()).str() + '.set') + } + if w.uses_fixed_arr_int { + w.fn_by_name('v_fixed_index') + } + // handle ORM drivers: + if orm_impls.len > 0 { + for orm_type in orm_impls { + typ := int(orm_type).str() + w.fn_by_name(typ + '.select') + w.fn_by_name(typ + '.insert') + w.fn_by_name(typ + '.update') + w.fn_by_name(typ + '.delete') + w.fn_by_name(typ + '.create') + w.fn_by_name(typ + '.drop') + w.fn_by_name(typ + '.last_id') + } + } + if w.features.used_maps == 0 && w.pref.autofree { + w.features.used_maps++ } if w.features.used_maps > 0 { w.fn_by_name('new_map') @@ -1415,20 +1497,20 @@ pub fn (mut w Walker) finalize(include_panic_deps bool) { w.mark_by_sym_name('VAssertMetaInfo') } if w.used_panic > 0 { - w.mark_fn_as_used('panic_option_not_set') - w.mark_fn_as_used('panic_result_not_set') + w.fn_by_name('panic_option_not_set') + w.fn_by_name('panic_result_not_set') } if w.used_none > 0 || w.table.used_features.auto_str { - w.mark_fn_as_used('_option_none') + w.fn_by_name('_option_none') w.mark_by_sym_name('_option') } if w.used_option > 0 { - w.mark_fn_as_used('_option_clone') - w.mark_fn_as_used('_option_ok') + w.fn_by_name('_option_clone') + w.fn_by_name('_option_ok') w.mark_by_sym_name('_option') } if w.used_result > 0 { - w.mark_fn_as_used('_result_ok') + w.fn_by_name('_result_ok') w.mark_by_sym_name('_result') } if (w.used_option + w.used_result + w.used_none) > 0 { @@ -1437,7 +1519,7 @@ pub fn (mut w Walker) finalize(include_panic_deps bool) { if include_panic_deps || w.uses_external_type || w.uses_asserts || w.uses_debugger || w.uses_interp { if w.trace_enabled { - eprintln('>>>>> PANIC DEPS ${include_panic_deps} | external_type=${w.uses_external_type} | asserts=${w.uses_asserts} | dbg=${w.uses_debugger}') + eprintln('>>>>> PANIC DEPS ${include_panic_deps} | external_type=${w.uses_external_type} | asserts=${w.uses_asserts} | dbg=${w.uses_debugger} interp=${w.uses_interp}') } ref_array_idx_str := int(ast.array_type.ref()).str() string_idx_str := ast.string_type_idx.str() @@ -1457,7 +1539,6 @@ pub fn (mut w Walker) finalize(include_panic_deps bool) { // remove unused symbols w.remove_unused_fn_generic_types() - w.remove_unused_dump_type() if w.trace_enabled { syms := w.used_syms.keys().map(w.table.type_to_str(it))