diff --git a/vlib/builtin/map.v b/vlib/builtin/map.v index 600ccaf1df..382bec968e 100644 --- a/vlib/builtin/map.v +++ b/vlib/builtin/map.v @@ -88,7 +88,7 @@ mut: values &u8 = unsafe { nil } } -@[inline; markused] +@[inline] fn new_dense_array(key_bytes int, value_bytes int) DenseArray { cap := 8 return DenseArray{ @@ -103,18 +103,18 @@ fn new_dense_array(key_bytes int, value_bytes int) DenseArray { } } -@[inline; markused] +@[inline] fn (d &DenseArray) key(i int) voidptr { return unsafe { voidptr(d.keys + i * d.key_bytes) } } // for cgen -@[inline; markused] +@[inline] fn (d &DenseArray) value(i int) voidptr { return unsafe { voidptr(d.values + i * d.value_bytes) } } -@[inline; markused] +@[inline] fn (d &DenseArray) has_index(i int) bool { return d.deletes == 0 || unsafe { d.all_deleted[i] } == 0 } @@ -259,7 +259,6 @@ fn map_free_string(pkey voidptr) { fn map_free_nop(_ voidptr) { } -@[markused] fn new_map(key_bytes int, value_bytes int, hash_fn MapHashFn, key_eq_fn MapEqFn, clone_fn MapCloneFn, free_fn MapFreeFn) map { metasize := int(sizeof(u32) * (init_capicity + extra_metas_inc)) // for now assume anything bigger than a pointer is a string diff --git a/vlib/v/ast/table.v b/vlib/v/ast/table.v index 2a3071f745..a2ea6ab185 100644 --- a/vlib/v/ast/table.v +++ b/vlib/v/ast/table.v @@ -12,10 +12,10 @@ pub struct UsedFeatures { pub mut: interfaces bool // interface dump bool // dump() - builtin_types bool // uses any builtin type index bool // string[0] range_index bool // string[0..1] cast_ptr bool // &u8(...) + asserts bool // assert expr as_cast bool // expr as Type anon_fn bool // fn () { } auto_str bool // auto str fns @@ -24,6 +24,11 @@ pub mut: arr_first bool // arr.first() arr_last bool // arr.last() arr_pop bool // arr.pop() + arr_delete bool // arr.delete() + arr_init bool // [1, 2, 3] + arr_map bool // []map[key]value + map_update bool // {...foo} + interpolation bool // '${foo} ${bar}' option_or_result bool // has panic call print_types map[int]bool // print() idx types used_fns map[string]bool // filled in by markused @@ -32,6 +37,7 @@ pub mut: used_veb_types []Type // veb context types, filled in by checker used_maps int // how many times maps were used, filled in by markused used_arrays int // how many times arrays were used, filled in by markused + used_modules map[string]bool // filled in checker // json bool // json is imported debugger bool // debugger is used comptime_calls map[string]bool // resolved $method() names diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 946fc60d45..45fa61920c 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -2302,11 +2302,20 @@ fn (mut c Checker) stmt(mut node ast.Stmt) { fn (mut c Checker) assert_stmt(mut node ast.AssertStmt) { if node.is_used { - c.table.used_features.auto_str = true + c.table.used_features.asserts = true } cur_exp_typ := c.expected_type c.expected_type = ast.bool_type assert_type := c.check_expr_option_or_result_call(node.expr, c.expr(mut node.expr)) + if c.pref.skip_unused && !c.table.used_features.auto_str && !c.is_builtin_mod + && mut node.expr is ast.InfixExpr { + if !c.table.sym(c.unwrap_generic(node.expr.left_type)).has_method('str') { + c.table.used_features.auto_str = true + } + if !c.table.sym(c.unwrap_generic(node.expr.right_type)).has_method('str') { + c.table.used_features.auto_str = true + } + } if assert_type != ast.bool_type_idx { atype_name := c.table.sym(assert_type).name c.error('assert can be used only with `bool` expressions, but found `${atype_name}` instead', @@ -2949,6 +2958,7 @@ 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) if c.pref.skip_unused && !c.is_builtin_mod { @@ -3268,7 +3278,8 @@ fn (mut c Checker) cast_expr(mut node ast.CastExpr) ast.Type { to_type } final_to_is_ptr := to_type.is_ptr() || final_to_type.is_ptr() - if to_type.is_ptr() { + if c.pref.skip_unused && !c.is_builtin_mod && c.mod !in ['strings', 'math.bits'] + && to_type.is_ptr() { c.table.used_features.cast_ptr = true } if to_type.has_flag(.result) { @@ -4763,9 +4774,11 @@ fn (mut c Checker) index_expr(mut node ast.IndexExpr) ast.Type { } else {} } - c.table.used_features.index = true - if node.index is ast.RangeExpr { - c.table.used_features.range_index = true + if !c.is_builtin_mod && c.mod !in ['strings', 'math.bits'] { + 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/containers.v b/vlib/v/checker/containers.v index 5013762716..b4765b8757 100644 --- a/vlib/v/checker/containers.v +++ b/vlib/v/checker/containers.v @@ -13,6 +13,9 @@ fn (mut c Checker) array_init(mut node ast.ArrayInit) ast.Type { } // `x := []string{}` (the type was set in the parser) if node.typ != ast.void_type { + if !c.is_builtin_mod && c.mod !in ['builtin', 'strings', 'strconv', 'math.bits'] { + c.table.used_features.arr_init = true + } if node.elem_type != 0 { elem_sym := c.table.sym(node.elem_type) @@ -61,6 +64,11 @@ fn (mut c Checker) array_init(mut node ast.ArrayInit) ast.Type { c.warn('byte is deprecated, use u8 instead', node.elem_type_pos) } } + ast.Map { + if c.pref.skip_unused && !c.is_builtin_mod { + c.table.used_features.arr_map = true + } + } else {} } } @@ -143,6 +151,9 @@ fn (mut c Checker) array_init(mut node ast.ArrayInit) ast.Type { } // `[1,2,3]` if node.exprs.len > 0 && node.elem_type == ast.void_type { + if !c.is_builtin_mod && c.mod !in ['builtin', 'strings', 'strconv', 'math.bits'] { + c.table.used_features.arr_init = true + } mut expected_value_type := ast.void_type mut expecting_interface_array := false mut expecting_sumtype_array := false @@ -495,6 +506,7 @@ fn (mut c Checker) map_init(mut node ast.MapInit) ast.Type { } if (node.keys.len > 0 && node.vals.len > 0) || node.has_update_expr { + c.table.used_features.map_update = true mut map_type := ast.void_type use_expected_type := c.expected_type != ast.void_type && !c.inside_const && c.table.sym(c.expected_type).kind == .map && !(c.inside_fn_arg diff --git a/vlib/v/checker/fn.v b/vlib/v/checker/fn.v index 04bcf09d21..5a55927752 100644 --- a/vlib/v/checker/fn.v +++ b/vlib/v/checker/fn.v @@ -751,8 +751,23 @@ fn (mut c Checker) call_expr(mut node ast.CallExpr) ast.Type { c.inside_or_block_value = true c.check_or_expr(node.or_block, typ, c.expected_or_type, node) c.inside_or_block_value = old_inside_or_block_value + } else if node.or_block.kind == .propagate_option || node.or_block.kind == .propagate_result { + if c.pref.skip_unused && !c.is_builtin_mod && c.mod != 'strings' { + c.table.used_features.option_or_result = true + } } c.expected_or_type = old_expected_or_type + if c.pref.skip_unused && !c.is_builtin_mod && c.mod == 'main' { + if node.is_method { + type_str := c.table.type_to_str(node.left_type) + if c.table.sym(node.left_type).is_builtin() + && type_str !in c.table.used_features.used_modules { + c.table.used_features.used_modules[type_str] = true + } + } else if node.name.contains('.') { + c.table.used_features.used_modules[node.name.all_before('.')] = true + } + } if !c.inside_const && c.table.cur_fn != unsafe { nil } && !c.table.cur_fn.is_main && !c.table.cur_fn.is_test { @@ -1401,7 +1416,8 @@ fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool) ast. // println / eprintln / panic can print anything if node.args.len > 0 && fn_name in print_everything_fns { c.builtin_args(mut node, fn_name, func) - if c.pref.skip_unused && !c.is_builtin_mod && node.args[0].expr !is ast.StringLiteral { + if c.pref.skip_unused && !c.is_builtin_mod && c.mod != 'math.bits' + && node.args[0].expr !is ast.StringLiteral { if !c.table.sym(c.unwrap_generic(node.args[0].typ)).has_method('str') { c.table.used_features.auto_str = true if node.args[0].typ.is_ptr() { @@ -2162,9 +2178,6 @@ fn (mut c Checker) method_call(mut node ast.CallExpr, mut continue_check &bool) continue_check = false return ast.void_type } - if c.pref.skip_unused && !c.is_builtin_mod && c.mod != 'strings' { - c.table.used_features.builtin_types = true - } c.expected_type = left_type mut is_generic := left_type.has_flag(.generic) node.left_type = left_type @@ -2949,6 +2962,9 @@ fn (mut c Checker) check_expected_arg_count(mut node ast.CallExpr, f &ast.Fn) ! } if f.is_variadic { min_required_params-- + if c.pref.skip_unused && !c.is_builtin_mod { + c.table.used_features.arr_init = true + } } else { has_decompose := node.args.any(it.expr is ast.ArrayDecompose) if has_decompose { @@ -3565,7 +3581,7 @@ fn (mut c Checker) array_builtin_method_call(mut node ast.CallExpr, left_type as } node.return_type = ast.int_type } else if method_name in ['first', 'last', 'pop'] { - if c.pref.skip_unused { + if c.pref.skip_unused && !c.is_builtin_mod { if method_name == 'first' { c.table.used_features.arr_first = true } @@ -3587,6 +3603,9 @@ fn (mut c Checker) array_builtin_method_call(mut node ast.CallExpr, left_type as node.receiver_type = node.left_type } } else if method_name == 'delete' { + if c.pref.skip_unused && !c.is_builtin_mod { + c.table.used_features.arr_delete = true + } c.check_for_mut_receiver(mut node.left) unwrapped_left_sym := c.table.sym(unwrapped_left_type) if method := c.table.find_method(unwrapped_left_sym, method_name) { diff --git a/vlib/v/checker/for.v b/vlib/v/checker/for.v index 5efa621845..51c6a89adb 100644 --- a/vlib/v/checker/for.v +++ b/vlib/v/checker/for.v @@ -190,6 +190,9 @@ fn (mut c Checker) for_in_stmt(mut node ast.ForInStmt) { 'declare a key and a value variable when ranging a map: `for key, val in map {`\n' + 'use `_` if you do not need the variable', node.pos) } + if !c.is_builtin_mod && c.mod != 'strings' { + c.table.used_features.used_maps++ + } if node.key_var.len > 0 { key_type := match sym.kind { .map { sym.map_info().key_type } diff --git a/vlib/v/checker/str.v b/vlib/v/checker/str.v index 769e8d61e3..551c67c6fe 100644 --- a/vlib/v/checker/str.v +++ b/vlib/v/checker/str.v @@ -62,6 +62,7 @@ fn (mut c Checker) string_inter_lit(mut node ast.StringInterLiteral) ast.Type { } else { c.table.used_features.print_types[ftyp.idx()] = true } + c.table.used_features.interpolation = true } c.fail_if_unreadable(expr, ftyp, 'interpolation object') node.expr_types << ftyp diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index 703d03af9a..e1829250ee 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -6660,7 +6660,7 @@ fn (mut g Gen) write_init_function() { g.write('\tas_cast_type_indexes = ') g.writeln(g.as_cast_name_table()) } - if !g.pref.is_shared && (!g.pref.skip_unused || g.table.used_features.builtin_types) { + if !g.pref.is_shared && (!g.pref.skip_unused || g.table.used_features.used_modules.len > 0) { // shared object does not need this g.writeln('\tbuiltin_init();') } diff --git a/vlib/v/markused/markused.v b/vlib/v/markused/markused.v index b587c47557..e0f99547fb 100644 --- a/vlib/v/markused/markused.v +++ b/vlib/v/markused/markused.v @@ -13,7 +13,6 @@ pub fn mark_used(mut table ast.Table, mut pref_ pref.Preferences, ast_files []&a defer { util.timing_measure(@METHOD) } - mut allow_noscan := true // Functions that must be generated and can't be skipped mut all_fn_root_names := []string{} if pref_.backend == .native { @@ -25,17 +24,19 @@ pub fn mark_used(mut table ast.Table, mut pref_ pref.Preferences, ast_files []&a string_idx_str := '${ast.string_type_idx}' array_idx_str := '${ast.array_type_idx}' map_idx_str := '${ast.map_type_idx}' + ref_map_idx_str := '${int(ast.map_type.ref())}' + ref_densearray_idx_str := '${int(table.find_type('DenseArray').ref())}' ref_array_idx_str := '${int(ast.array_type.ref())}' mut core_fns := [ 'main.main', 'init_global_allocator', // needed for linux_bare and wasm_bare 'v_realloc', // needed for _STR - 'malloc', - 'malloc_noscan', - 'vcalloc', - 'vcalloc_noscan', + //'malloc', + //'malloc_noscan', + //'vcalloc', + //'vcalloc_noscan', 'memdup', - 'vstrlen', + //'vstrlen', 'tos', 'tos2', 'error', @@ -45,26 +46,35 @@ pub fn mark_used(mut table ast.Table, mut pref_ pref.Preferences, ast_files []&a 'main.vtest_init', 'main.vtest_new_metainfo', 'main.vtest_new_filemetainfo', + 'println', ] $if debug_used_features ? { dump(table.used_features) } panic_deps := [ '__new_array_with_default', + '__new_array_with_default_noscan', 'str_intp', ref_array_idx_str + '.push', + ref_array_idx_str + '.push_noscan', string_idx_str + '.substr', array_idx_str + '.slice', array_idx_str + '.get', 'v_fixed_index', + charptr_idx_str + '.vstring_literal', ] - // real world apps - if table.used_features.builtin_types || table.used_features.as_cast - || table.used_features.auto_str { + if table.used_features.used_modules.len > 0 { core_fns << panic_deps + } + if table.used_features.as_cast || table.used_features.auto_str || pref_.is_shared { + core_fns << panic_deps + core_fns << 'isnil' core_fns << '__new_array' + core_fns << '__new_array_noscan' core_fns << '__new_array_with_multi_default' + core_fns << '__new_array_with_multi_default_noscan' core_fns << '__new_array_with_array_default' + core_fns << '__new_array_with_array_default_noscan' core_fns << 'new_array_from_c_array' // byteptr and charptr core_fns << byteptr_idx_str + '.vstring' @@ -73,65 +83,82 @@ pub fn mark_used(mut table ast.Table, mut pref_ pref.Preferences, ast_files []&a core_fns << charptr_idx_str + '.vstring' core_fns << charptr_idx_str + '.vstring_with_len' core_fns << charptr_idx_str + '.vstring_literal' - - if table.used_features.index { - 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 << ref_array_idx_str + '.set' - core_fns << map_idx_str + '.get' - core_fns << map_idx_str + '.set' - } - if table.used_features.range_index { - core_fns << string_idx_str + '.substr_with_check' - core_fns << string_idx_str + '.substr_ni' - core_fns << array_idx_str + '.slice_ni' - core_fns << array_idx_str + '.get_with_check' // used for `x := a[i] or {}` - core_fns << array_idx_str + '.clone_static_to_depth' - core_fns << array_idx_str + '.clone_to_depth' - } - if table.used_features.cast_ptr { - core_fns << 'ptr_str' // TODO: remove this. It is currently needed for the auto str methods for &u8, fn types, etc; See `./v -skip-unused vlib/builtin/int_test.v` - } - if table.used_features.auto_str { - core_fns << string_idx_str + '.repeat' - core_fns << 'tos3' - } - if table.used_features.auto_str_ptr { - core_fns << 'isnil' - } - if table.used_features.arr_prepend { - core_fns << ref_array_idx_str + '.prepend_many' - } - if table.used_features.arr_pop { - core_fns << ref_array_idx_str + '.pop' - } - if table.used_features.arr_first { - core_fns << array_idx_str + '.first' - } - if table.used_features.arr_last { - core_fns << array_idx_str + '.last' - } - } else { - // TODO: this *should not* depend on the used compiler, which is brittle, but only on info in the AST... - // hello world apps - if pref_.ccompiler_type != .tinyc && 'no_backtrace' !in pref_.compile_defines { - // with backtrace on gcc/clang more code needs be generated - allow_noscan = true - core_fns << panic_deps - } else { - allow_noscan = false - } + } + if table.used_features.index || pref_.is_shared { + 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 << 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' + core_fns << array_idx_str + '.slice_ni' + core_fns << array_idx_str + '.get_with_check' // used for `x := a[i] or {}` + core_fns << array_idx_str + '.clone_static_to_depth' + core_fns << array_idx_str + '.clone_to_depth' + } + if table.used_features.cast_ptr { + core_fns << 'ptr_str' // TODO: remove this. It is currently needed for the auto str methods for &u8, fn types, etc; See `./v -skip-unused vlib/builtin/int_test.v` + } + if table.used_features.auto_str { + core_fns << string_idx_str + '.repeat' + core_fns << 'tos3' + } + if table.used_features.auto_str_ptr { + core_fns << 'isnil' + } + if table.used_features.arr_prepend { + core_fns << ref_array_idx_str + '.prepend_many' + } + if table.used_features.arr_pop { + core_fns << ref_array_idx_str + '.pop' + } + if table.used_features.arr_first { + core_fns << array_idx_str + '.first' + } + if table.used_features.arr_last { + core_fns << array_idx_str + '.last' + } + if table.used_features.arr_delete { + core_fns << panic_deps + } + if pref_.ccompiler_type != .tinyc && 'no_backtrace' !in pref_.compile_defines { + // with backtrace on gcc/clang more code needs be generated + core_fns << panic_deps + } + if table.used_features.interpolation { + core_fns << panic_deps + } + if table.used_features.dump { + core_fns << panic_deps + builderptr_idx := int(table.find_type('strings.Builder').ref()) + core_fns << [ + '${builderptr_idx}.str', + '${builderptr_idx}.free', + '${builderptr_idx}.write_rune', + ] + } + if table.used_features.arr_init { + core_fns << '__new_array' + core_fns << 'new_array_from_c_array' + core_fns << 'new_array_from_c_array_noscan' + core_fns << '__new_array_with_multi_default' + core_fns << '__new_array_with_multi_default_noscan' + core_fns << '__new_array_with_array_default' } if table.used_features.option_or_result { core_fns << '_option_ok' core_fns << '_result_ok' - if !allow_noscan { - core_fns << panic_deps - allow_noscan = true - } + core_fns << charptr_idx_str + '.vstring_literal' + core_fns << panic_deps } if table.used_features.as_cast { core_fns << '__as_cast' @@ -139,9 +166,33 @@ pub fn mark_used(mut table ast.Table, mut pref_ pref.Preferences, ast_files []&a if table.used_features.anon_fn { core_fns << 'memdup_uncollectable' } + if table.used_features.arr_map { + core_fns << '__new_array_with_map_default' + core_fns << 'new_map_noscan_key' + core_fns << ref_map_idx_str + '.clone' + core_fns << ref_densearray_idx_str + '.clone' + core_fns << map_idx_str + '.clone' + table.used_features.used_maps++ + } + if table.used_features.map_update { + core_fns << 'new_map_update_init' + table.used_features.used_maps++ + } + if table.used_features.asserts { + core_fns << panic_deps + core_fns << '__print_assert_failure' + core_fns << 'isnil' + } + if pref_.trace_calls || pref_.trace_fns.len > 0 { + core_fns << panic_deps + core_fns << 'vgettid' + core_fns << 'C.gettid' + core_fns << 'v.trace_calls.on_c_main' + core_fns << 'v.trace_calls.current_time' + core_fns << 'v.trace_calls.on_call' + } all_fn_root_names << core_fns } - if pref_.is_bare { all_fn_root_names << [ 'strlen', @@ -154,16 +205,18 @@ pub fn mark_used(mut table ast.Table, mut pref_ pref.Preferences, ast_files []&a } is_noscan_whitelisted := pref_.gc_mode in [.boehm_full_opt, .boehm_incr_opt] - + has_noscan := all_fn_root_names.any(it.contains('noscan') + && it !in ['vcalloc_noscan', 'malloc_noscan']) for k, mut mfn in all_fns { $if trace_skip_unused_all_fns ? { println('k: ${k} | mfn: ${mfn.name}') } if k in table.used_features.comptime_calls { all_fn_root_names << k + continue } // _noscan functions/methods are selected when the `-gc boehm` is on: - if allow_noscan && is_noscan_whitelisted && mfn.name.ends_with('_noscan') { + if has_noscan && is_noscan_whitelisted && mfn.name.ends_with('_noscan') { all_fn_root_names << k continue } @@ -176,8 +229,7 @@ pub fn mark_used(mut table ast.Table, mut pref_ pref.Preferences, ast_files []&a all_fn_root_names << k continue } - if method_receiver_typename == '&strings.Builder' - && (table.used_features.builtin_types || table.used_features.auto_str) { + if method_receiver_typename == '&strings.Builder' && table.used_features.auto_str { // implicit string builders are generated in auto_eq_methods.v all_fn_root_names << k continue @@ -187,7 +239,7 @@ pub fn mark_used(mut table ast.Table, mut pref_ pref.Preferences, ast_files []&a if k.ends_with('.str') || k.ends_with('.auto_str') { if table.used_features.auto_str || table.used_features.print_types[mfn.receiver.typ.idx()] - || table.used_features.debugger { + || table.used_features.debugger || table.used_features.used_modules.len > 0 { all_fn_root_names << k } continue @@ -196,7 +248,7 @@ pub fn mark_used(mut table ast.Table, mut pref_ pref.Preferences, ast_files []&a all_fn_root_names << k continue } - if table.used_features.builtin_types && k.ends_with('.free') { + if table.used_features.used_modules.len > 0 && k.ends_with('.free') { all_fn_root_names << k continue } @@ -356,19 +408,13 @@ pub fn mark_used(mut table ast.Table, mut pref_ pref.Preferences, ast_files []&a all_globals: all_globals pref: pref_ ) - // println( all_fns.keys() ) - walker.mark_markused_fn_decls() // tagged with `@[markused]` - walker.mark_markused_consts() // tagged with `@[markused]` walker.mark_markused_globals() // tagged with `@[markused]` walker.mark_exported_fns() walker.mark_root_fns(all_fn_root_names) walker.mark_veb_actions() - if walker.n_asserts > 0 { - unsafe { walker.fn_decl(mut all_fns['__print_assert_failure']) } - } if table.used_features.used_maps > 0 { for k, mut mfn in all_fns { mut method_receiver_typename := '' @@ -465,6 +511,13 @@ fn all_fn_const_and_global(ast_files []&ast.File) (map[string]ast.FnDecl, map[st return all_fns, all_consts, all_globals } +fn mark_all_methods_used(mut table ast.Table, mut all_fn_root_names []string, typ ast.Type) { + sym := table.sym(typ) + for method in sym.methods { + all_fn_root_names << '${int(typ)}.${method.name}' + } +} + fn handle_vweb(mut table ast.Table, mut all_fn_root_names []string, result_name string, filter_name string, context_name string) { // handle vweb magic router methods: @@ -472,7 +525,7 @@ fn handle_vweb(mut table ast.Table, mut all_fn_root_names []string, result_name if result_type_idx != 0 { all_fn_root_names << filter_name typ_vweb_context := table.find_type(context_name).set_nr_muls(1) - all_fn_root_names << '${int(typ_vweb_context)}.html' + mark_all_methods_used(mut table, mut all_fn_root_names, typ_vweb_context) for vgt in table.used_features.used_veb_types { sym_app := table.sym(vgt) for m in sym_app.methods { diff --git a/vlib/v/markused/walker.v b/vlib/v/markused/walker.v index 56f855865e..32a98c25e5 100644 --- a/vlib/v/markused/walker.v +++ b/vlib/v/markused/walker.v @@ -299,6 +299,10 @@ fn (mut w Walker) expr(node_ ast.Expr) { w.fn_decl(mut node.decl) } ast.ArrayInit { + sym := w.table.final_sym(node.elem_type) + if sym.info is ast.Struct { + w.a_struct_info(sym.name, sym.info) + } w.expr(node.len_expr) w.expr(node.cap_expr) w.expr(node.init_expr) @@ -419,6 +423,7 @@ fn (mut w Walker) expr(node_ ast.Expr) { // println('>>> else, ast.Ident kind: $node.kind') } } + w.or_block(node.or_expr) } ast.LambdaExpr { w.expr(node.func) @@ -470,6 +475,7 @@ fn (mut w Walker) expr(node_ ast.Expr) { w.fn_by_name(method.fkey()) } } + w.or_block(node.or_block) } ast.SqlExpr { w.expr(node.db_expr) @@ -511,7 +517,14 @@ fn (mut w Walker) expr(node_ ast.Expr) { w.expr(node.orig) } ast.Comment {} - ast.EnumVal {} + ast.EnumVal { + if e := w.table.enum_decls[node.enum_name] { + filtered := e.fields.filter(it.name == node.val) + if filtered.len != 0 && filtered[0].expr !is ast.EmptyExpr { + w.expr(filtered[0].expr) + } + } + } ast.LockExpr { w.stmts(node.stmts) } @@ -557,6 +570,7 @@ pub fn (mut w Walker) a_struct_info(sname string, info ast.Struct) { pub fn (mut w Walker) fn_decl(mut node ast.FnDecl) { if node.language == .c { + w.mark_fn_as_used(node.fkey()) return } fkey := node.fkey() @@ -587,6 +601,17 @@ pub fn (mut w Walker) call_expr(mut node ast.CallExpr) { w.mark_aggregate_call_used(fn_name, types) } } + } else if left_sym.info is ast.Interface { + for typ in left_sym.info.types { + sym := w.table.sym(typ) + _, embed_types := w.table.find_method_from_embeds(sym, node.name) or { + ast.Fn{}, []ast.Type{} + } + if embed_types.len != 0 { + fn_embed := '${int(embed_types.last())}.${node.name}' + w.fn_by_name(fn_embed) + } + } } } w.expr(node.left) @@ -609,15 +634,19 @@ pub fn (mut w Walker) call_expr(mut node ast.CallExpr) { else {} } } + } else if node.is_fn_a_const { + const_fn_name := '${node.mod}.${fn_name}' + if const_fn_name in w.all_consts { + w.mark_const_as_used(const_fn_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`. fkey := '${int(node.receiver_concrete_type)}.${node.name}' - w.used_fns[fkey] = true + w.mark_fn_as_used(fkey) } stmt := w.all_fns[fn_name] or { return } if stmt.name == node.name {