checker: cleanup used_features logic (#23502)

This commit is contained in:
Felipe Pena 2025-01-17 20:14:18 -03:00 committed by GitHub
parent 496451ecbb
commit 1b9f15d60d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 223 additions and 168 deletions

View File

@ -10,7 +10,6 @@ import v.util
@[heap; minify] @[heap; minify]
pub struct UsedFeatures { pub struct UsedFeatures {
pub mut: pub mut:
interfaces bool // interface
dump bool // dump() dump bool // dump()
index bool // string[0] index bool // string[0]
range_index bool // string[0..1] range_index bool // string[0..1]

View File

@ -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) { 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.markused_option_or_result(!c.is_builtin_mod && node.kind != .absent && c.mod != 'strings')
c.table.used_features.option_or_result = true
}
if node.kind == .propagate_option { if node.kind == .propagate_option {
if c.table.cur_fn != unsafe { nil } && !c.table.cur_fn.return_type.has_flag(.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 { && !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.check_or_expr(node.or_block, unwrapped_typ, c.expected_or_type, node)
c.expected_or_type = ast.void_type c.expected_or_type = ast.void_type
} }
if c.pref.skip_unused && node.or_block.kind != .absent c.markused_option_or_result(node.or_block.kind != .absent
&& !c.table.used_features.option_or_result { && !c.table.used_features.option_or_result)
c.table.used_features.option_or_result = true
}
return field.typ return field.typ
} }
if mut method := c.table.sym(c.unwrap_generic(typ)).find_method_with_generic_parent(field_name) { 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.markused_comptime_call(typ.has_flag(.generic), '${int(method.params[0].typ)}.${field_name}')
c.table.used_features.comptime_calls['${int(method.params[0].typ)}.${field_name}'] = true
}
if c.expected_type != 0 && c.expected_type != ast.none_type { 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)) 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 // 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 cur_exp_typ := c.expected_type
c.expected_type = ast.bool_type c.expected_type = ast.bool_type
assert_type := c.check_expr_option_or_result_call(node.expr, c.expr(mut node.expr)) 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 c.markused_assertstmt_auto_str(mut node)
&& 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 { if assert_type != ast.bool_type_idx {
atype_name := c.table.sym(assert_type).name atype_name := c.table.sym(assert_type).name
c.error('assert can be used only with `bool` expressions, but found `${atype_name}` instead', 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.table.used_features.dump = true
c.expected_type = ast.string_type c.expected_type = ast.string_type
node.expr_type = c.expr(mut node.expr) node.expr_type = c.expr(mut node.expr)
if c.pref.skip_unused && !c.is_builtin_mod { c.markused_dumpexpr(mut node)
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
}
if c.comptime.inside_comptime_for && mut node.expr is ast.Ident { if c.comptime.inside_comptime_for && mut node.expr is ast.Ident {
if node.expr.ct_expr { if node.expr.ct_expr {
node.expr_type = c.type_resolver.get_type(node.expr as ast.Ident) 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 { ast.StructInit {
if node.unresolved { if node.unresolved {
mut expr_ := c.table.resolve_init(node, c.unwrap_generic(node.typ)) mut expr_ := c.table.resolve_init(node, c.unwrap_generic(node.typ))
if c.pref.skip_unused && c.table.used_features.used_maps == 0 c.markused_used_maps(c.table.used_features.used_maps == 0 && expr_ is ast.MapInit)
&& expr_ is ast.MapInit {
c.table.used_features.used_maps++
}
return c.expr(mut expr_) return c.expr(mut expr_)
} }
mut inited_fields := []string{} mut inited_fields := []string{}
@ -3374,16 +3348,7 @@ fn (mut c Checker) cast_expr(mut node ast.CastExpr) ast.Type {
to_type to_type
} }
final_to_is_ptr := to_type.is_ptr() || final_to_type.is_ptr() final_to_is_ptr := to_type.is_ptr() || final_to_type.is_ptr()
if c.pref.skip_unused && !c.is_builtin_mod { c.markused_castexpr(mut node, to_type, mut final_to_sym)
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
}
}
if to_type.has_flag(.result) { if to_type.has_flag(.result) {
c.error('casting to Result type is forbidden', node.pos) 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)', c.error('`mut` is not allowed with `=` (use `:=` to declare a variable)',
node.pos) node.pos)
} }
if c.pref.skip_unused && !c.is_builtin_mod && node.language == .v && node.name.contains('.') { c.markused_external_type(!c.is_builtin_mod && node.language == .v && node.name.contains('.'))
c.table.used_features.external_types = true
}
if mut obj := node.scope.find(node.name) { if mut obj := node.scope.find(node.name) {
match mut obj { match mut obj {
ast.GlobalField { ast.GlobalField {

View File

@ -133,32 +133,7 @@ fn (mut c Checker) comptime_call(mut node ast.ComptimeCall) ast.Type {
// check each arg expression // check each arg expression
node.args[i].typ = c.expr(mut arg.expr) node.args[i].typ = c.expr(mut arg.expr)
} }
if c.pref.skip_unused { c.markused_comptimecall(mut node)
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.stmts_ending_with_expression(mut node.or_block.stmts, c.expected_or_type) c.stmts_ending_with_expression(mut node.or_block.stmts, c.expected_or_type)
return c.type_resolver.get_type(node) 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) c.error('could not find method `${method_name}`', node.method_pos)
return ast.void_type return ast.void_type
} }
if c.pref.skip_unused { c.markused_comptime_call(true, '${int(left_type)}.${method_name}')
c.table.used_features.comptime_calls['${int(left_type)}.${method_name}'] = true
}
node.result_type = f.return_type node.result_type = f.return_type
return 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) unwrapped_expr_type := c.unwrap_generic(field.typ)
tsym := c.table.sym(unwrapped_expr_type) tsym := c.table.sym(unwrapped_expr_type)
c.table.dumps[int(unwrapped_expr_type.clear_flags(.option, .result, .atomic_f))] = tsym.cname c.table.dumps[int(unwrapped_expr_type.clear_flags(.option, .result, .atomic_f))] = tsym.cname
if c.pref.skip_unused { c.markused_comptimefor(mut node, unwrapped_expr_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++
}
}
}
}
if tsym.kind == .array_fixed { if tsym.kind == .array_fixed {
info := tsym.info as ast.ArrayFixed info := tsym.info as ast.ArrayFixed
if !info.is_fn_ret { if !info.is_fn_ret {

View File

@ -65,9 +65,7 @@ fn (mut c Checker) array_init(mut node ast.ArrayInit) ast.Type {
} }
} }
ast.Map { ast.Map {
if c.pref.skip_unused && !c.is_builtin_mod { c.markused_array_method(!c.is_builtin_mod, 'map')
c.table.used_features.arr_map = true
}
} }
else {} else {}
} }

View File

@ -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.check_or_expr(node.or_block, typ, c.expected_or_type, node)
c.inside_or_block_value = old_inside_or_block_value c.inside_or_block_value = old_inside_or_block_value
} else if node.or_block.kind == .propagate_option || node.or_block.kind == .propagate_result { } 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.markused_option_or_result(!c.is_builtin_mod && c.mod != 'strings')
c.table.used_features.option_or_result = true
}
} }
c.expected_or_type = old_expected_or_type c.expected_or_type = old_expected_or_type
if c.pref.skip_unused && !c.is_builtin_mod && c.mod == 'main' c.markused_call_expr(mut node)
&& !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
}
}
if !c.inside_const && c.table.cur_fn != unsafe { nil } && !c.table.cur_fn.is_main if !c.inside_const && c.table.cur_fn != unsafe { nil } && !c.table.cur_fn.is_main
&& !c.table.cur_fn.is_test { && !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 // 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 { if node.args.len > 0 && fn_name in print_everything_fns {
node.args[0].ct_expr = c.comptime.is_comptime(node.args[0].expr) node.args[0].ct_expr = c.comptime.is_comptime(node.args[0].expr)
c.builtin_args(mut node, fn_name, func) c.builtin_args(mut node, fn_name, func)
if c.pref.skip_unused && !c.is_builtin_mod && c.mod != 'math.bits' c.markused_fn_call(mut node)
&& 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
}
}
return func.return_type return func.return_type
} }
// `return error(err)` -> `return err` // `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 continue_check = false
return ast.void_type return ast.void_type
} }
if c.pref.skip_unused { c.markused_method_call(mut node, mut left_expr, left_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
}
}
c.expected_type = left_type c.expected_type = left_type
mut is_generic := left_type.has_flag(.generic) mut is_generic := left_type.has_flag(.generic)
node.left_type = left_type 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 { if embed_types.len != 0 {
is_method_from_embed = true is_method_from_embed = true
node.from_embed_types = embed_types node.from_embed_types = embed_types
if c.pref.skip_unused && node.left_type.has_flag(.generic) { c.markused_comptime_call(node.left_type.has_flag(.generic), '${int(method.receiver_type)}.${method.name}')
c.table.used_features.comptime_calls['${int(method.receiver_type)}.${method.name}'] = true
}
} }
} }
if final_left_sym.kind == .aggregate { 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 { if f.is_variadic {
min_required_params-- min_required_params--
if c.pref.skip_unused && !c.is_builtin_mod { c.markused_array_method(!c.is_builtin_mod, '')
c.table.used_features.arr_init = true
}
} else { } else {
has_decompose := node.args.any(it.expr is ast.ArrayDecompose) has_decompose := node.args.any(it.expr is ast.ArrayDecompose)
if has_decompose { 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 node.return_type = ast.int_type
} else if method_name in ['first', 'last', 'pop'] { } else if method_name in ['first', 'last', 'pop'] {
if c.pref.skip_unused && !c.is_builtin_mod { c.markused_array_method(!c.is_builtin_mod, method_name)
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
}
}
if node.args.len != 0 { if node.args.len != 0 {
c.error('`.${method_name}()` does not have any arguments', arg0.pos) 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 node.receiver_type = node.left_type
} }
} else if method_name == 'delete' { } else if method_name == 'delete' {
if c.pref.skip_unused && !c.is_builtin_mod { c.markused_array_method(!c.is_builtin_mod, method_name)
c.table.used_features.arr_delete = true
}
c.check_for_mut_receiver(mut node.left) c.check_for_mut_receiver(mut node.left)
unwrapped_left_sym := c.table.sym(unwrapped_left_type) unwrapped_left_sym := c.table.sym(unwrapped_left_type)
if method := c.table.find_method(unwrapped_left_sym, method_name) { if method := c.table.find_method(unwrapped_left_sym, method_name) {

View File

@ -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 // `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 node.op == .left_shift && c.table.sym(left_type).kind == .array {
if c.pref.skip_unused && !c.is_builtin_mod && c.mod != 'strings' { c.markused_infiexpr(!c.is_builtin_mod && c.mod != 'strings')
c.table.used_features.index = true
c.table.used_features.arr_init = true
}
if mut node.right is ast.IfExpr { if mut node.right is ast.IfExpr {
if node.right.is_expr && node.right.branches.len > 0 { if node.right.is_expr && node.right.branches.len > 0 {
mut last_stmt := node.right.branches[0].stmts.last() mut last_stmt := node.right.branches[0].stmts.last()

View File

@ -12,9 +12,6 @@ fn (mut c Checker) interface_decl(mut node ast.InterfaceDecl) {
is_js := node.language == .js is_js := node.language == .js
if mut decl_sym.info is ast.Interface { if mut decl_sym.info is ast.Interface {
mut has_generic_types := false 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 { if node.embeds.len > 0 {
all_embeds := c.expand_iface_embeds(node, 0, node.embeds) 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') // eprintln('> node.name: $node.name | node.embeds.len: $node.embeds.len | all_embeds: $all_embeds.len')

View File

@ -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', 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()) expr.pos())
} }
if c.pref.skip_unused && !c.is_builtin_mod { c.markused_string_inter_lit(mut node, ftyp)
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.fail_if_unreadable(expr, ftyp, 'interpolation object') c.fail_if_unreadable(expr, ftyp, 'interpolation object')
node.expr_types << ftyp node.expr_types << ftyp
ftyp_sym := c.table.sym(ftyp) ftyp_sym := c.table.sym(ftyp)

View File

@ -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 {}
}
}