diff --git a/vlib/v/ast/table.v b/vlib/v/ast/table.v index f962fcfcc2..b3ece061e9 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..80679d0711 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,45 @@ 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 { + c.table.used_features.auto_str_arr = c.table.final_sym(arg_typ).kind == .array + } } } @@ -165,18 +175,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 c78b7061b5..02a883fb1d 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 e9ce833eec..c3fc346942 100644 --- a/vlib/v/markused/walker.v +++ b/vlib/v/markused/walker.v @@ -30,8 +30,9 @@ 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 @@ -60,6 +61,11 @@ mut: 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_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 { @@ -71,7 +77,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}|') } @@ -91,10 +97,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) } } @@ -482,7 +486,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 { @@ -508,10 +512,13 @@ fn (mut w Walker) expr(node_ ast.Expr) { w.expr(node.call_expr) } ast.IndexExpr { + if !w.uses_index && !w.is_direct_array_access { + w.uses_index = true + } 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,17 +536,22 @@ fn (mut w Walker) expr(node_ ast.Expr) { 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') + 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') + } } w.mark_by_sym(w.table.sym(sym.info.elem_type)) + } else if sym.info is ast.ArrayFixed { + w.uses_fixed_arr_int = true } 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 } else if sym.info is ast.Struct { w.mark_by_sym(sym) } else if sym.info is ast.SumType { @@ -583,6 +595,9 @@ 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.uses_append = true + } } ast.IfGuardExpr { w.expr(node.expr) @@ -814,18 +829,25 @@ pub fn (mut w Walker) fn_decl(mut node ast.FnDecl) { if node.no_body { return } + if node.is_method { + w.mark_by_type(node.receiver.typ) + } + 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-- } + defer { + w.level-- + } receiver_name := if node.is_method && node.receiver.typ != 0 { w.table.type_to_str(node.receiver.typ) + '.' } else { '' } - eprintln('>>>${' '.repeat(w.level)}${receiver_name}${node.name} [decl]') - } - if node.is_method { - w.mark_by_type(node.receiver.typ) + eprintln('>>>${' '.repeat(w.level)}${receiver_name}${node.name} [${@FN}]') } w.mark_fn_ret_and_params(node.return_type, node.params) w.mark_fn_as_used(fkey) @@ -936,17 +958,22 @@ pub fn (mut w Walker) call_expr(mut node ast.CallExpr) { 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 { + last_is_direct_array_access := w.is_direct_array_access + w.is_direct_array_access = stmt.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-- } - receiver_name := if node.receiver_type != 0 { - w.table.type_to_str(node.receiver_type) + '.' + receiver_name := if stmt.is_method && stmt.receiver.typ != 0 { + w.table.type_to_str(stmt.receiver.typ) + '.' } else { '' } - eprintln('>>>${' '.repeat(w.level)}${receiver_name}${node.name} [call]') + eprintln('>>>${' '.repeat(w.level)}${receiver_name}${node.name} [${@FN}]') } w.mark_fn_ret_and_params(stmt.return_type, stmt.params) w.stmts(stmt.stmts) @@ -964,17 +991,22 @@ pub fn (mut w Walker) fn_by_name(fn_name string) { return } stmt := w.all_fns[fn_name] or { return } + last_is_direct_array_access := w.is_direct_array_access + w.is_direct_array_access = stmt.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-- } - receiver_name := if fn_name.contains('.') && fn_name.all_before_last('.').int() > 0 { - w.table.type_to_str(fn_name.all_before_last('.').int()) + '.' + receiver_name := if stmt.is_method && stmt.receiver.typ != 0 { + w.table.type_to_str(stmt.receiver.typ) + '.' } else { '' } - eprintln('>>>${' '.repeat(w.level)}${receiver_name}${fn_name.all_after_last('.')} [by_name]') + eprintln('>>>${' '.repeat(w.level)}${receiver_name}${stmt.name} [${@FN}]') } w.mark_fn_as_used(fn_name) w.mark_fn_ret_and_params(stmt.return_type, stmt.params) @@ -1201,14 +1233,6 @@ 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') @@ -1274,12 +1298,16 @@ 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 { + 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') } if w.uses_spawn { w.fn_by_name('malloc') @@ -1294,6 +1322,33 @@ 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_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_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') + w.fn_by_name(string_idx_str + '.at_with_check') + w.fn_by_name(string_idx_str + '.substr') + } + if w.uses_fixed_arr_int { + w.fn_by_name('v_fixed_index') + } for typ, _ in w.table.used_features.print_types { w.mark_by_type(typ) } @@ -1316,6 +1371,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 { @@ -1354,9 +1411,28 @@ 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 + } + } + // 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 { @@ -1408,20 +1484,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 { @@ -1430,7 +1506,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() @@ -1450,7 +1526,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))