From 1b9f15d60d32879c0659d8de82ed790ffc88e382 Mon Sep 17 00:00:00 2001 From: Felipe Pena Date: Fri, 17 Jan 2025 20:14:18 -0300 Subject: [PATCH] checker: cleanup used_features logic (#23502) --- vlib/v/ast/table.v | 1 - vlib/v/checker/checker.v | 57 ++-------- vlib/v/checker/comptime.v | 45 +------- vlib/v/checker/containers.v | 4 +- vlib/v/checker/fn.v | 65 ++--------- vlib/v/checker/infix.v | 5 +- vlib/v/checker/interface.v | 3 - vlib/v/checker/str.v | 12 +- vlib/v/checker/used_features.v | 199 +++++++++++++++++++++++++++++++++ 9 files changed, 223 insertions(+), 168 deletions(-) create mode 100644 vlib/v/checker/used_features.v diff --git a/vlib/v/ast/table.v b/vlib/v/ast/table.v index 64f8c93c98..c3ceff2b9c 100644 --- a/vlib/v/ast/table.v +++ b/vlib/v/ast/table.v @@ -10,7 +10,6 @@ import v.util @[heap; minify] pub struct UsedFeatures { pub mut: - interfaces bool // interface dump bool // dump() index bool // string[0] range_index bool // string[0..1] diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index b9ec682476..d64a823d57 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -1392,9 +1392,8 @@ fn (mut c Checker) check_expr_option_or_result_call(expr ast.Expr, ret_type ast. } fn (mut c Checker) check_or_expr(node ast.OrExpr, ret_type ast.Type, expr_return_type ast.Type, expr ast.Expr) { - if c.pref.skip_unused && !c.is_builtin_mod && node.kind != .absent && c.mod != 'strings' { - c.table.used_features.option_or_result = true - } + c.markused_option_or_result(!c.is_builtin_mod && node.kind != .absent && c.mod != 'strings') + if node.kind == .propagate_option { if c.table.cur_fn != unsafe { nil } && !c.table.cur_fn.return_type.has_flag(.option) && !c.table.cur_fn.is_main && !c.table.cur_fn.is_test && !c.inside_const { @@ -1794,16 +1793,12 @@ fn (mut c Checker) selector_expr(mut node ast.SelectorExpr) ast.Type { c.check_or_expr(node.or_block, unwrapped_typ, c.expected_or_type, node) c.expected_or_type = ast.void_type } - if c.pref.skip_unused && node.or_block.kind != .absent - && !c.table.used_features.option_or_result { - c.table.used_features.option_or_result = true - } + c.markused_option_or_result(node.or_block.kind != .absent + && !c.table.used_features.option_or_result) return field.typ } if mut method := c.table.sym(c.unwrap_generic(typ)).find_method_with_generic_parent(field_name) { - if c.pref.skip_unused && typ.has_flag(.generic) { - c.table.used_features.comptime_calls['${int(method.params[0].typ)}.${field_name}'] = true - } + c.markused_comptime_call(typ.has_flag(.generic), '${int(method.params[0].typ)}.${field_name}') if c.expected_type != 0 && c.expected_type != ast.none_type { fn_type := ast.new_type(c.table.find_or_register_fn_type(method, false, true)) // if the expected type includes the receiver, don't hide it behind a closure @@ -2383,15 +2378,7 @@ fn (mut c Checker) assert_stmt(mut node ast.AssertStmt) { 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 - } - } + c.markused_assertstmt_auto_str(mut node) 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', @@ -3051,17 +3038,7 @@ pub fn (mut c Checker) expr(mut node ast.Expr) ast.Type { 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 { - if !c.table.sym(c.unwrap_generic(node.expr_type)).has_method('str') { - c.table.used_features.auto_str = true - if node.expr_type.is_ptr() { - c.table.used_features.auto_str_ptr = true - } - } else { - c.table.used_features.print_types[node.expr_type.idx()] = true - } - c.table.used_features.print_types[ast.int_type_idx] = true - } + c.markused_dumpexpr(mut node) if c.comptime.inside_comptime_for && mut node.expr is ast.Ident { if node.expr.ct_expr { node.expr_type = c.type_resolver.get_type(node.expr as ast.Ident) @@ -3284,10 +3261,7 @@ pub fn (mut c Checker) expr(mut node ast.Expr) ast.Type { ast.StructInit { if node.unresolved { mut expr_ := c.table.resolve_init(node, c.unwrap_generic(node.typ)) - if c.pref.skip_unused && c.table.used_features.used_maps == 0 - && expr_ is ast.MapInit { - c.table.used_features.used_maps++ - } + c.markused_used_maps(c.table.used_features.used_maps == 0 && expr_ is ast.MapInit) return c.expr(mut expr_) } mut inited_fields := []string{} @@ -3374,16 +3348,7 @@ 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 c.pref.skip_unused && !c.is_builtin_mod { - if c.table.used_features.used_maps == 0 && mut final_to_sym.info is ast.SumType { - if final_to_sym.info.variants.any(c.table.final_sym(it).kind == .map) { - c.table.used_features.used_maps++ - } - } - if c.mod !in ['strings', 'math.bits'] && to_type.is_ptr() { - c.table.used_features.cast_ptr = true - } - } + c.markused_castexpr(mut node, to_type, mut final_to_sym) if to_type.has_flag(.result) { c.error('casting to Result type is forbidden', node.pos) } @@ -4003,9 +3968,7 @@ fn (mut c Checker) ident(mut node ast.Ident) ast.Type { c.error('`mut` is not allowed with `=` (use `:=` to declare a variable)', node.pos) } - if c.pref.skip_unused && !c.is_builtin_mod && node.language == .v && node.name.contains('.') { - c.table.used_features.external_types = true - } + c.markused_external_type(!c.is_builtin_mod && node.language == .v && node.name.contains('.')) if mut obj := node.scope.find(node.name) { match mut obj { ast.GlobalField { diff --git a/vlib/v/checker/comptime.v b/vlib/v/checker/comptime.v index 753b7406fd..2138ec271d 100644 --- a/vlib/v/checker/comptime.v +++ b/vlib/v/checker/comptime.v @@ -133,32 +133,7 @@ fn (mut c Checker) comptime_call(mut node ast.ComptimeCall) ast.Type { // check each arg expression node.args[i].typ = c.expr(mut arg.expr) } - if c.pref.skip_unused { - c.table.used_features.comptime_calls['${int(c.unwrap_generic(c.comptime.comptime_for_method.receiver_type))}.${c.comptime.comptime_for_method.name}'] = true - if c.inside_anon_fn { - // $method passed to anon fn, mark all methods as used - sym := c.table.sym(c.unwrap_generic(node.left_type)) - for m in sym.get_methods() { - c.table.used_features.comptime_calls['${int(c.unwrap_generic(m.receiver_type))}.${m.name}'] = true - if node.args.len > 0 && m.params.len > 0 { - last_param := m.params.last().typ - if (last_param.is_int() || last_param.is_bool()) - && c.table.final_sym(node.args.last().typ).kind == .array { - c.table.used_features.comptime_calls['${ast.string_type_idx}.${c.table.type_to_str(m.params.last().typ)}'] = true - } - } - } - } else { - m := c.comptime.comptime_for_method - if node.args.len > 0 && m.params.len > 0 { - last_param := m.params.last().typ - if (last_param.is_int() || last_param.is_bool()) - && c.table.final_sym(node.args.last().typ).kind == .array { - c.table.used_features.comptime_calls['${ast.string_type_idx}.${c.table.type_to_str(m.params.last().typ)}'] = true - } - } - } - } + c.markused_comptimecall(mut node) c.stmts_ending_with_expression(mut node.or_block.stmts, c.expected_or_type) return c.type_resolver.get_type(node) } @@ -223,9 +198,7 @@ fn (mut c Checker) comptime_call(mut node ast.ComptimeCall) ast.Type { c.error('could not find method `${method_name}`', node.method_pos) return ast.void_type } - if c.pref.skip_unused { - c.table.used_features.comptime_calls['${int(left_type)}.${method_name}'] = true - } + c.markused_comptime_call(true, '${int(left_type)}.${method_name}') node.result_type = f.return_type return f.return_type } @@ -312,19 +285,7 @@ fn (mut c Checker) comptime_for(mut node ast.ComptimeFor) { unwrapped_expr_type := c.unwrap_generic(field.typ) tsym := c.table.sym(unwrapped_expr_type) c.table.dumps[int(unwrapped_expr_type.clear_flags(.option, .result, .atomic_f))] = tsym.cname - if c.pref.skip_unused { - 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 { - c.table.used_features.used_maps++ - } else if final_sym.info is ast.SumType { - if final_sym.info.variants.any(c.table.final_sym(it).kind == .map) { - c.table.used_features.used_maps++ - } - } - } - } + c.markused_comptimefor(mut node, unwrapped_expr_type) if tsym.kind == .array_fixed { info := tsym.info as ast.ArrayFixed if !info.is_fn_ret { diff --git a/vlib/v/checker/containers.v b/vlib/v/checker/containers.v index 2de7d37d3f..2711e6773e 100644 --- a/vlib/v/checker/containers.v +++ b/vlib/v/checker/containers.v @@ -65,9 +65,7 @@ fn (mut c Checker) array_init(mut node ast.ArrayInit) ast.Type { } } ast.Map { - if c.pref.skip_unused && !c.is_builtin_mod { - c.table.used_features.arr_map = true - } + c.markused_array_method(!c.is_builtin_mod, 'map') } else {} } diff --git a/vlib/v/checker/fn.v b/vlib/v/checker/fn.v index 16491e737c..01b514f252 100644 --- a/vlib/v/checker/fn.v +++ b/vlib/v/checker/fn.v @@ -756,22 +756,10 @@ fn (mut c Checker) call_expr(mut node ast.CallExpr) ast.Type { 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.markused_option_or_result(!c.is_builtin_mod && c.mod != 'strings') } c.expected_or_type = old_expected_or_type - if c.pref.skip_unused && !c.is_builtin_mod && c.mod == 'main' - && !c.table.used_features.external_types { - if node.is_method { - if c.table.sym(node.left_type).is_builtin() { - c.table.used_features.external_types = true - } - } else if node.name.contains('.') { - c.table.used_features.external_types = true - } - } - + c.markused_call_expr(mut node) if !c.inside_const && c.table.cur_fn != unsafe { nil } && !c.table.cur_fn.is_main && !c.table.cur_fn.is_test { // TODO: use just `if node.or_block.kind == .propagate_result && !c.table.cur_fn.return_type.has_flag(.result) {` after the deprecation for ?!Type @@ -1422,20 +1410,7 @@ fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool) ast. if node.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) - 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 - } else { - if node.args[0].typ.has_option_or_result() { - c.table.used_features.option_or_result = true - } - c.table.used_features.print_types[node.args[0].typ.idx()] = true - } - if node.args[0].typ.is_ptr() { - c.table.used_features.auto_str_ptr = true - } - } + c.markused_fn_call(mut node) return func.return_type } // `return error(err)` -> `return err` @@ -1980,15 +1955,7 @@ 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 { - if !left_type.has_flag(.generic) && mut left_expr is ast.Ident { - if left_expr.obj is ast.Var && left_expr.obj.ct_type_var == .smartcast { - c.table.used_features.comptime_calls['${int(left_type)}.${node.name}'] = true - } - } else if left_type.has_flag(.generic) { - c.table.used_features.comptime_calls['${int(c.unwrap_generic(left_type))}.${node.name}'] = true - } - } + c.markused_method_call(mut node, mut left_expr, left_type) c.expected_type = left_type mut is_generic := left_type.has_flag(.generic) node.left_type = left_type @@ -2119,9 +2086,7 @@ fn (mut c Checker) method_call(mut node ast.CallExpr, mut continue_check &bool) if embed_types.len != 0 { is_method_from_embed = true node.from_embed_types = embed_types - if c.pref.skip_unused && node.left_type.has_flag(.generic) { - c.table.used_features.comptime_calls['${int(method.receiver_type)}.${method.name}'] = true - } + c.markused_comptime_call(node.left_type.has_flag(.generic), '${int(method.receiver_type)}.${method.name}') } } if final_left_sym.kind == .aggregate { @@ -2816,9 +2781,7 @@ 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 - } + c.markused_array_method(!c.is_builtin_mod, '') } else { has_decompose := node.args.any(it.expr is ast.ArrayDecompose) if has_decompose { @@ -3437,17 +3400,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 && !c.is_builtin_mod { - if method_name == 'first' { - c.table.used_features.arr_first = true - } - if method_name == 'last' { - c.table.used_features.arr_last = true - } - if method_name == 'pop' { - c.table.used_features.arr_pop = true - } - } + c.markused_array_method(!c.is_builtin_mod, method_name) if node.args.len != 0 { c.error('`.${method_name}()` does not have any arguments', arg0.pos) } @@ -3459,9 +3412,7 @@ 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.markused_array_method(!c.is_builtin_mod, method_name) 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/infix.v b/vlib/v/checker/infix.v index eb8abd6061..4466525eac 100644 --- a/vlib/v/checker/infix.v +++ b/vlib/v/checker/infix.v @@ -57,10 +57,7 @@ fn (mut c Checker) infix_expr(mut node ast.InfixExpr) ast.Type { } // `arr << if n > 0 { 10 } else { 11 }` set the right c.expected_type if node.op == .left_shift && c.table.sym(left_type).kind == .array { - if c.pref.skip_unused && !c.is_builtin_mod && c.mod != 'strings' { - c.table.used_features.index = true - c.table.used_features.arr_init = true - } + c.markused_infiexpr(!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/interface.v b/vlib/v/checker/interface.v index bf26665c1a..e546eceaa3 100644 --- a/vlib/v/checker/interface.v +++ b/vlib/v/checker/interface.v @@ -12,9 +12,6 @@ fn (mut c Checker) interface_decl(mut node ast.InterfaceDecl) { is_js := node.language == .js if mut decl_sym.info is ast.Interface { mut has_generic_types := false - if c.pref.skip_unused && decl_sym.mod == 'main' { - c.table.used_features.interfaces = true - } if node.embeds.len > 0 { all_embeds := c.expand_iface_embeds(node, 0, node.embeds) // eprintln('> node.name: $node.name | node.embeds.len: $node.embeds.len | all_embeds: $all_embeds.len') diff --git a/vlib/v/checker/str.v b/vlib/v/checker/str.v index e5cec6f149..a7ed0b1aeb 100644 --- a/vlib/v/checker/str.v +++ b/vlib/v/checker/str.v @@ -53,17 +53,7 @@ fn (mut c Checker) string_inter_lit(mut node ast.StringInterLiteral) ast.Type { c.error('expression returning type `char` cannot be used in string interpolation directly, print its address or cast it to an integer instead', expr.pos()) } - if c.pref.skip_unused && !c.is_builtin_mod { - if !c.table.sym(ftyp).has_method('str') { - c.table.used_features.auto_str = true - } else { - c.table.used_features.print_types[ftyp.idx()] = true - } - if ftyp.is_ptr() { - c.table.used_features.auto_str_ptr = true - } - c.table.used_features.interpolation = true - } + c.markused_string_inter_lit(mut node, ftyp) c.fail_if_unreadable(expr, ftyp, 'interpolation object') node.expr_types << ftyp ftyp_sym := c.table.sym(ftyp) diff --git a/vlib/v/checker/used_features.v b/vlib/v/checker/used_features.v new file mode 100644 index 0000000000..d024da99b9 --- /dev/null +++ b/vlib/v/checker/used_features.v @@ -0,0 +1,199 @@ +module checker + +import v.ast + +@[inline] +fn (mut c Checker) markused_option_or_result(check bool) { + if check { + c.table.used_features.option_or_result = true + } +} + +@[inline] +fn (mut c Checker) markused_comptime_call(check bool, key string) { + if check { + c.table.used_features.comptime_calls[key] = true + } +} + +fn (mut c Checker) markused_assertstmt_auto_str(mut node ast.AssertStmt) { + if !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 + return + } + if !c.table.sym(c.unwrap_generic(node.expr.right_type)).has_method('str') { + c.table.used_features.auto_str = true + } + } +} + +fn (mut c Checker) markused_dumpexpr(mut node ast.DumpExpr) { + if c.is_builtin_mod { + return + } + if !c.table.sym(c.unwrap_generic(node.expr_type)).has_method('str') { + c.table.used_features.auto_str = true + if node.expr_type.is_ptr() { + c.table.used_features.auto_str_ptr = true + } + } else { + c.table.used_features.print_types[node.expr_type.idx()] = true + } + c.table.used_features.print_types[ast.int_type_idx] = true +} + +@[inline] +fn (mut c Checker) markused_used_maps(check bool) { + if check { + c.table.used_features.used_maps++ + } +} + +fn (mut c Checker) markused_castexpr(mut node ast.CastExpr, to_type ast.Type, mut final_to_sym ast.TypeSymbol) { + if c.is_builtin_mod { + return + } + if c.table.used_features.used_maps == 0 && mut final_to_sym.info is ast.SumType { + if final_to_sym.info.variants.any(c.table.final_sym(it).kind == .map) { + 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_external_type(check bool) { + if check { + c.table.used_features.external_types = true + } +} + +fn (mut c Checker) markused_comptimecall(mut node ast.ComptimeCall) { + c.markused_comptime_call(true, '${int(c.unwrap_generic(c.comptime.comptime_for_method.receiver_type))}.${c.comptime.comptime_for_method.name}') + if c.inside_anon_fn { + // $method passed to anon fn, mark all methods as used + sym := c.table.sym(c.unwrap_generic(node.left_type)) + for m in sym.get_methods() { + c.table.used_features.comptime_calls['${int(c.unwrap_generic(m.receiver_type))}.${m.name}'] = true + if node.args.len > 0 && m.params.len > 0 { + last_param := m.params.last().typ + if (last_param.is_int() || last_param.is_bool()) + && c.table.final_sym(node.args.last().typ).kind == .array { + c.table.used_features.comptime_calls['${ast.string_type_idx}.${c.table.type_to_str(m.params.last().typ)}'] = true + } + } + } + } else { + m := c.comptime.comptime_for_method + if node.args.len > 0 && m.params.len > 0 { + last_param := m.params.last().typ + if (last_param.is_int() || last_param.is_bool()) + && c.table.final_sym(node.args.last().typ).kind == .array { + c.table.used_features.comptime_calls['${ast.string_type_idx}.${c.table.type_to_str(m.params.last().typ)}'] = true + } + } + } +} + +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 { + c.table.used_features.used_maps++ + } else if final_sym.info is ast.SumType { + if final_sym.info.variants.any(c.table.final_sym(it).kind == .map) { + c.table.used_features.used_maps++ + } + } + } +} + +fn (mut c Checker) markused_call_expr(mut node ast.CallExpr) { + if !c.is_builtin_mod && c.mod == 'main' && !c.table.used_features.external_types { + if node.is_method { + if c.table.sym(node.left_type).is_builtin() { + c.table.used_features.external_types = true + } + } else if node.name.contains('.') { + c.table.used_features.external_types = true + } + } +} + +fn (mut c Checker) markused_fn_call(mut node ast.CallExpr) { + if !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 + } else { + if node.args[0].typ.has_option_or_result() { + c.table.used_features.option_or_result = true + } + c.table.used_features.print_types[node.args[0].typ.idx()] = true + } + if node.args[0].typ.is_ptr() { + c.table.used_features.auto_str_ptr = true + } + } +} + +fn (mut c Checker) markused_method_call(mut node ast.CallExpr, mut left_expr ast.Expr, left_type ast.Type) { + if !left_type.has_flag(.generic) && mut left_expr is ast.Ident { + if left_expr.obj is ast.Var && left_expr.obj.ct_type_var == .smartcast { + c.table.used_features.comptime_calls['${int(left_type)}.${node.name}'] = true + } + } else if left_type.has_flag(.generic) { + c.table.used_features.comptime_calls['${int(c.unwrap_generic(left_type))}.${node.name}'] = true + } +} + +fn (mut c Checker) markused_string_inter_lit(mut node ast.StringInterLiteral, ftyp ast.Type) { + if c.is_builtin_mod { + return + } + if !c.table.sym(ftyp).has_method('str') { + c.table.used_features.auto_str = true + } else { + c.table.used_features.print_types[ftyp.idx()] = true + } + if ftyp.is_ptr() { + c.table.used_features.auto_str_ptr = true + } + c.table.used_features.interpolation = true +} + +fn (mut c Checker) markused_infiexpr(check bool) { + if check { + c.table.used_features.index = true + c.table.used_features.arr_init = true + } +} + +fn (mut c Checker) markused_array_method(check bool, method_name string) { + if !check { + return + } + match method_name { + '' { // array init + c.table.used_features.arr_init = true + } + 'first' { + c.table.used_features.arr_first = true + } + 'last' { + c.table.used_features.arr_last = true + } + 'pop' { + c.table.used_features.arr_pop = true + } + 'delete' { + c.table.used_features.arr_delete = true + } + 'map' { + c.table.used_features.arr_map = true + } + else {} + } +}